@capxul/sdk 4.1.4 → 4.2.0-rc.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,12 @@
1
- import { $ as CapxulError, A as toAuthUserId, C as WEI_RE, D as toAddress, E as toAccountId, G as toPayrollRunId, H as toOrgId, I as toEmail, M as toChainId, N as toCountryCode, P as toCurrencyCode, Q as CAPXUL_ERROR_CODES, S as SUPPORTED_CURRENCY_CODES, U as toPartyId, W as toPayrollGroupId, _ as deriveCapxulSafeAddress, at as boundedResponseHeaders, b as BYTES32_RE, ct as decodeChainCause, dt as isFailureMode, et as EXPECTED_OPERATION_OUTCOMES, ft as revertSummaryText, it as FAILURE_MODES$1, j as toBudgetId, lt as failureFingerprint, mt as redactSecrets, n as InMemoryAuthCacheAdapter, nt as isCapxulError, ot as chainCauseProperties, p as orgRoleKeyForLabel, pt as containsSensitiveMaterial, q as toRoleKey, r as BrowserAuthCacheAdapter, rt as CHAIN_UPSTREAMS, st as chainEvidenceLabel, tt as Errors, ut as isChainUpstream, v as validateHandle, w as ZERO_BYTES32, x as EVM_ADDRESS_RE$1, y as APP_ID_RE } from "./clock-C2AUlq1V.mjs";
2
- import { Cause, Clock, Context, Data, Deferred, Duration, Effect, Exit, Fiber, Layer, Queue, Ref, Result, Schema, SchemaGetter, SchemaParser, Scope } from "effect";
3
- import { formatUnits, keccak256, parseUnits, recoverAddress, toBytes } from "viem";
4
- import { makeFunctionReference } from "convex/server";
1
+ import { $ as toTesterKind, A as toAccountId, B as toEmail, C as BYTES32_RE, D as ZERO_BYTES32, E as WEI_RE, F as toBudgetId, G as toKycTier, H as toEpochSeconds, I as toChainId, J as toPayrollGroupId, K as toOrgId, L as toCountryCode, M as toAllowedOrigin, P as toAuthUserId, Q as toSessionToken, R as toCurrencyCode, S as ASSET_ID_RE, T as SUPPORTED_CURRENCY_CODES, U as toHandle, V as toEpochMs, W as toJwtToken, X as toPublishableKey, Y as toPayrollRunId, Z as toRoleKey, _ as BASE_SEPOLIA_CHAIN_ID, _t as revertSummaryText, at as EXPECTED_OPERATION_OUTCOMES, b as ACCOUNT_ID_RE, bt as redactSecrets, c as AuthCachePortTag, ct as CHAIN_UPSTREAMS, d as authClientPortFromPromiseAdapter, dt as chainCauseProperties, et as validateHandle, f as AuthClientError, ft as chainEvidenceLabel, g as normalizeBindingEmail, gt as isFailureMode, ht as isChainUpstream, i as BrowserAuthCacheAdapter, it as CapxulError, j as toAddress, l as SystemClockLayer, lt as FAILURE_MODES$1, m as orgRoleKeyForLabel, mt as failureFingerprint, nt as decodeConvexError, ot as Errors, p as AuthClientPortTag, pt as decodeChainCause, q as toPartyId, r as InMemoryAuthCacheAdapter, rt as CAPXUL_ERROR_CODES, st as isCapxulError, u as ClockPortTag, ut as boundedResponseHeaders, v as deriveCapxulSafeAddress, vt as containsSensitiveMaterial, w as EVM_ADDRESS_RE$1, x as APP_ID_RE, xt as redactUrlSecrets, yt as isCredentialField, z as toDurationMs } from "./OAuthBearerAuthClient-BrbXrndM.mjs";
2
+ import { formatUnits, keccak256, parseUnits, recoverAddress, stringToHex, toBytes } from "viem";
3
+ import { Cause, Clock, Context, Data, Deferred, Duration, Effect, Exit, Fiber, FiberSet, Layer, Option, Queue, Ref, Result, Schedule, Schema, SchemaGetter, SchemaIssue, SchemaParser, Scope, Stream, Tracer } from "effect";
4
+ import { getFunctionName, makeFunctionReference } from "convex/server";
5
+ import { privateKeyToAccount } from "viem/accounts";
6
+ import { FetchHttpClient, Headers, HttpClient } from "effect/unstable/http";
7
+ import { OtlpExporter, OtlpLogger, OtlpSerialization, OtlpTracer } from "effect/unstable/observability";
8
+ import { ConvexClient } from "convex/browser";
9
+ import { AccountTypeEnum, ChainTypeEnum, EmbeddedState, Openfort, RecoveryMethod, ThirdPartyOAuthProvider } from "@openfort/openfort-js";
5
10
  //#region src/domain/identity/model.ts
6
11
  const WRONG = { refused: "WRONG_STATE" };
7
12
  /** org-lifecycle.ts:173-184, lifted verbatim. */
@@ -811,11 +816,11 @@ const PublishableKeyIdSchema = Schema.String.pipe(Schema.refine((value) => value
811
816
  const TxHashSchema$1 = Schema.String.pipe(Schema.refine((value) => BYTES32_RE.test(value), { message: "must be 0x + 64 hex chars" }));
812
817
  const ACCOUNT_ID_TELEMETRY_RE = /^account_[0-9A-Za-z]+$/;
813
818
  const WEI_AMOUNT_TELEMETRY_RE = /^[0-9]+$/;
814
- const AccountIdSchema = Schema.String.pipe(Schema.refine((value) => ACCOUNT_ID_TELEMETRY_RE.test(value), { message: "must be account_ plus an alphanumeric id" }));
819
+ const AccountIdSchema$1 = Schema.String.pipe(Schema.refine((value) => ACCOUNT_ID_TELEMETRY_RE.test(value), { message: "must be account_ plus an alphanumeric id" }));
815
820
  const WeiAmountSchema$1 = Schema.String.pipe(Schema.refine((value) => WEI_AMOUNT_TELEMETRY_RE.test(value), { message: "must be a non-negative integer string" }));
816
821
  const CurrencyCodeSchema$1 = Schema.String.pipe(Schema.refine((value) => value.length > 0, { message: "must be a non-empty currency code" }));
817
822
  const BalanceBucketSchema = Schema.Literals(["zero", "nonzero"]);
818
- const OptionalAccountId = Schema.optional(AccountIdSchema);
823
+ const OptionalAccountId = Schema.optional(AccountIdSchema$1);
819
824
  const OptionalWeiAmount = Schema.optional(WeiAmountSchema$1);
820
825
  const OptionalCurrencyCode = Schema.optional(CurrencyCodeSchema$1);
821
826
  const OptionalBalanceBucket = Schema.optional(BalanceBucketSchema);
@@ -1709,7 +1714,7 @@ function redactTelemetryEvent(event, options = {}) {
1709
1714
  }
1710
1715
  function redactTelemetryProps(name, props, options = {}) {
1711
1716
  if (props === void 0) return void 0;
1712
- const clone = cloneProps(props);
1717
+ const clone = cloneProps$1(props);
1713
1718
  if (options.rawMode === true) return clone;
1714
1719
  for (const key of PII_PROP_KEYS_BY_EVENT[name] ?? []) redactProperty(clone, key);
1715
1720
  return clone;
@@ -1724,17 +1729,17 @@ function redactProperty(props, key) {
1724
1729
  const value = props[key];
1725
1730
  if (typeof value === "string") props[key] = sha256Hex(value).slice(0, 12);
1726
1731
  }
1727
- function cloneProps(props) {
1732
+ function cloneProps$1(props) {
1728
1733
  const cloned = {};
1729
- for (const [key, value] of Object.entries(props)) cloned[key] = cloneTelemetryValue(value);
1734
+ for (const [key, value] of Object.entries(props)) cloned[key] = cloneTelemetryValue$1(value);
1730
1735
  return cloned;
1731
1736
  }
1732
- function cloneTelemetryValue(value) {
1733
- if (Array.isArray(value)) return value.map(cloneTelemetryValue);
1737
+ function cloneTelemetryValue$1(value) {
1738
+ if (Array.isArray(value)) return value.map(cloneTelemetryValue$1);
1734
1739
  if (value === null || typeof value !== "object") return value;
1735
1740
  if (Object.getPrototypeOf(value) !== Object.prototype) return value;
1736
1741
  const cloned = {};
1737
- for (const [key, nested] of Object.entries(value)) cloned[key] = cloneTelemetryValue(nested);
1742
+ for (const [key, nested] of Object.entries(value)) cloned[key] = cloneTelemetryValue$1(nested);
1738
1743
  return cloned;
1739
1744
  }
1740
1745
  const SHA256_INITIAL_HASH = [
@@ -1899,6 +1904,11 @@ const bytes32BrandSchema = (name) => lowercasedString.pipe(Schema.refine((value)
1899
1904
  /** Lowercase, 0x-prefixed bytes32 evidence without a public brand. */
1900
1905
  const Bytes32Schema = bytes32BrandSchema("value");
1901
1906
  const AddressSchema = addressSchema("address");
1907
+ const AccountIdSchema = Schema.String.pipe(Schema.refine((value) => ACCOUNT_ID_RE.test(value), { message: "must be account_ plus an alphanumeric id" }));
1908
+ const AssetIdSchema = Schema.String.pipe(Schema.refine((value) => {
1909
+ const match = ASSET_ID_RE.exec(value);
1910
+ return match !== null && match[0] === value && Number.isSafeInteger(Number(match[1])) && Number(match[1]) > 0 && match[2] !== "0x0000000000000000000000000000000000000000";
1911
+ }, { message: "must be a canonical ERC-20 AssetId" }));
1902
1912
  const SafeAddressSchema = addressSchema("safe address");
1903
1913
  const ModuleAddressSchema = addressSchema("module address");
1904
1914
  const TxHashSchema = bytes32BrandSchema("transaction hash");
@@ -3539,6 +3549,212 @@ Schema.Struct({
3539
3549
  decimals: nonNegativeInteger("decimals"),
3540
3550
  effectiveFrom: nonNegativeInteger("effectiveFrom")
3541
3551
  });
3552
+ //#endregion
3553
+ //#region ../wire/src/payment-document-v2.ts
3554
+ const uint8 = Schema.Number.check(Schema.makeFilter((n) => Number.isInteger(n) && n >= 0 && n <= 255));
3555
+ const uint64 = Schema.Number.check(Schema.makeFilter((n) => Number.isSafeInteger(n) && n >= 0));
3556
+ const minorUnits$1 = Schema.String.check(Schema.makeFilter((s) => s.length <= 78 && s.trim() === s && /^(0|[1-9][0-9]*)$/.test(s) && BigInt(s) < 2n ** 256n));
3557
+ const reference = Schema.String.check(Schema.makeFilter((s) => s.length > 0));
3558
+ /** Public asset quantities use decimal major units. Registry validation resolves their scale. */
3559
+ const AssetAmountSchema = Schema.Struct({
3560
+ asset: AssetIdSchema,
3561
+ value: Schema.String.check(Schema.makeFilter((s) => s.length <= 512 && s.trim() === s && /^(0|[1-9][0-9]*)(\.[0-9]+)?$/.test(s))),
3562
+ currency: Schema.optional(Schema.Never),
3563
+ decimals: Schema.optional(Schema.Never)
3564
+ });
3565
+ const requestedMoney = Schema.Struct({
3566
+ ...FinancialOpsMoney.fields,
3567
+ asset: Schema.optional(Schema.Never)
3568
+ }).check(Schema.makeFilter((amount) => amount.decimals <= 255 && amount.value.length <= 512 && amount.value.trim() === amount.value && (amount.value.split(".")[1]?.length ?? 0) <= amount.decimals, { message: "money must use exact decimal precision" }));
3569
+ Schema.Union([Schema.Struct({
3570
+ kind: Schema.Literal("money"),
3571
+ amount: requestedMoney
3572
+ }), Schema.Struct({
3573
+ kind: Schema.Literal("asset"),
3574
+ amount: AssetAmountSchema
3575
+ })]);
3576
+ Schema.Union([Schema.Struct({
3577
+ kind: Schema.Literal("money"),
3578
+ account: AccountIdSchema,
3579
+ currency: CurrencyCodeSchema,
3580
+ asset: Schema.optional(Schema.Never)
3581
+ }), Schema.Struct({
3582
+ kind: Schema.Literal("asset"),
3583
+ account: AccountIdSchema,
3584
+ asset: AssetIdSchema,
3585
+ currency: Schema.optional(Schema.Never)
3586
+ })]);
3587
+ Schema.Union([Schema.Struct({
3588
+ kind: Schema.Literal("money"),
3589
+ account: AccountIdSchema,
3590
+ amount: requestedMoney
3591
+ }), Schema.Struct({
3592
+ kind: Schema.Literal("asset"),
3593
+ account: AccountIdSchema,
3594
+ amount: AssetAmountSchema
3595
+ })]);
3596
+ /** Inactive fields are required and empty. They never carry an alternative denomination. */
3597
+ const AmountV2Schema = Schema.Union([Schema.Struct({
3598
+ denomination: Schema.Literal(0),
3599
+ currency: CurrencyCodeSchema,
3600
+ asset: Schema.Literal(""),
3601
+ minorUnits: minorUnits$1,
3602
+ decimals: uint8
3603
+ }), Schema.Struct({
3604
+ denomination: Schema.Literal(1),
3605
+ currency: Schema.Literal(""),
3606
+ asset: AssetIdSchema,
3607
+ minorUnits: minorUnits$1,
3608
+ decimals: uint8
3609
+ })]);
3610
+ const targetFields$1 = {
3611
+ target: reference,
3612
+ targetRevision: uint64
3613
+ };
3614
+ const payoutFields = {
3615
+ rail: Schema.Literals(["chainrails", "lightspark"]),
3616
+ purposeKind: Schema.Literals([
3617
+ 0,
3618
+ 1,
3619
+ 2,
3620
+ 3
3621
+ ]),
3622
+ payerRef: reference,
3623
+ fundingAccount: reference,
3624
+ ...targetFields$1,
3625
+ requestId: Schema.String,
3626
+ obligationHash: DocumentHashSchema,
3627
+ send: AmountV2Schema,
3628
+ receive: AmountV2Schema,
3629
+ feesHash: NonzeroDocumentHashSchema,
3630
+ releaseHash: NonzeroDocumentHashSchema
3631
+ };
3632
+ Schema.Struct(payoutFields);
3633
+ const InvoiceV2 = Schema.Struct({
3634
+ kind: Schema.Literal(1),
3635
+ invoiceNumber: Schema.String,
3636
+ payerRef: reference,
3637
+ payeeRef: reference,
3638
+ amount: AmountV2Schema,
3639
+ ...targetFields$1,
3640
+ issuedAt: uint64,
3641
+ dueAt: uint64,
3642
+ lineItemsHash: DocumentHashSchema
3643
+ });
3644
+ const PayslipV2 = Schema.Struct({
3645
+ kind: Schema.Literal(2),
3646
+ employerRef: reference,
3647
+ employeeRef: reference,
3648
+ period: Schema.String,
3649
+ gross: AmountV2Schema,
3650
+ net: AmountV2Schema,
3651
+ ...targetFields$1,
3652
+ issuedAt: uint64
3653
+ }).check(Schema.makeFilter((m) => m.gross.denomination === m.net.denomination && m.gross.currency === m.net.currency && m.gross.asset === m.net.asset && m.gross.decimals === m.net.decimals && BigInt(m.net.minorUnits) <= BigInt(m.gross.minorUnits), { message: "gross and net must use one denomination; net cannot exceed gross" }));
3654
+ const ReceiptV2 = Schema.Struct({
3655
+ kind: Schema.Literal(3),
3656
+ reference: Schema.String,
3657
+ amount: AmountV2Schema,
3658
+ ...targetFields$1,
3659
+ obligationHash: DocumentHashSchema,
3660
+ dealHash: NonzeroDocumentHashSchema,
3661
+ paidAt: uint64,
3662
+ note: Schema.String
3663
+ });
3664
+ const PayoutV2 = Schema.Struct({
3665
+ kind: Schema.Literal(4),
3666
+ quoteId: reference,
3667
+ ...payoutFields,
3668
+ expiresAt: uint64,
3669
+ issuedAt: uint64
3670
+ }).check(Schema.makeFilter((m) => m.issuedAt <= m.expiresAt, { message: "issuance must not follow the acceptance deadline" }));
3671
+ const common = {
3672
+ protocol: Schema.Literal("capxul.payment-document"),
3673
+ version: Schema.Literal(2),
3674
+ domain: Schema.Struct({
3675
+ name: Schema.Literal("CapxulPayments"),
3676
+ version: Schema.Literal("2"),
3677
+ chainId: ChainIdSchema,
3678
+ verifyingContract: Schema.Literal(PAYMENT_DOCUMENT_VERIFYING_CONTRACT)
3679
+ })
3680
+ };
3681
+ Schema.Union([
3682
+ Schema.Struct({
3683
+ ...common,
3684
+ primaryType: Schema.Literal("Invoice"),
3685
+ message: InvoiceV2
3686
+ }),
3687
+ Schema.Struct({
3688
+ ...common,
3689
+ primaryType: Schema.Literal("Payslip"),
3690
+ message: PayslipV2
3691
+ }),
3692
+ Schema.Struct({
3693
+ ...common,
3694
+ primaryType: Schema.Literal("Receipt"),
3695
+ message: ReceiptV2
3696
+ }),
3697
+ Schema.Struct({
3698
+ ...common,
3699
+ primaryType: Schema.Literal("Payout"),
3700
+ message: PayoutV2
3701
+ })
3702
+ ]);
3703
+ const targetFields = [{
3704
+ name: "target",
3705
+ type: "string"
3706
+ }, {
3707
+ name: "targetRevision",
3708
+ type: "uint64"
3709
+ }];
3710
+ const termsFields = [
3711
+ {
3712
+ name: "rail",
3713
+ type: "string"
3714
+ },
3715
+ {
3716
+ name: "purposeKind",
3717
+ type: "uint16"
3718
+ },
3719
+ {
3720
+ name: "payerRef",
3721
+ type: "string"
3722
+ },
3723
+ {
3724
+ name: "fundingAccount",
3725
+ type: "string"
3726
+ },
3727
+ ...targetFields,
3728
+ {
3729
+ name: "requestId",
3730
+ type: "string"
3731
+ },
3732
+ {
3733
+ name: "obligationHash",
3734
+ type: "bytes32"
3735
+ },
3736
+ {
3737
+ name: "send",
3738
+ type: "AmountV2"
3739
+ },
3740
+ {
3741
+ name: "receive",
3742
+ type: "AmountV2"
3743
+ },
3744
+ {
3745
+ name: "feesHash",
3746
+ type: "bytes32"
3747
+ },
3748
+ {
3749
+ name: "releaseHash",
3750
+ type: "bytes32"
3751
+ }
3752
+ ];
3753
+ [...targetFields], [...targetFields], [...targetFields], [...termsFields];
3754
+ Schema.Array(Schema.Struct({
3755
+ code: Schema.Literals(["rail", "capxul"]),
3756
+ amount: AmountV2Schema
3757
+ }));
3542
3758
  `
3543
3759
  .capxul-doc{--ink:#1d1d1f;--muted:#6e6e73;--line:#e7e7ea;--accent:#0a7d4b;--bg:#fff;
3544
3760
  font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Inter,system-ui,sans-serif;
@@ -3751,9 +3967,9 @@ function resolveFailureMode(error, contextFailureMode) {
3751
3967
  }
3752
3968
  //#endregion
3753
3969
  //#region src/signer.ts
3754
- const EVM_ADDRESS_HEX = /^0x[0-9a-fA-F]{40}$/;
3755
- const ECDSA_SIGNATURE_HEX = /^0x[0-9a-fA-F]{130}$/;
3756
- const SAFE_OP_DIGEST_HEX = /^0x[0-9a-fA-F]{64}$/;
3970
+ const EVM_ADDRESS_HEX$1 = /^0x[0-9a-fA-F]{40}$/;
3971
+ const ECDSA_SIGNATURE_HEX$1 = /^0x[0-9a-fA-F]{130}$/;
3972
+ const SAFE_OP_DIGEST_HEX$1 = /^0x[0-9a-fA-F]{64}$/;
3757
3973
  /**
3758
3974
  * The readiness store a signer reports when it runs no readiness cycle. It
3759
3975
  * fails CLOSED: a node key signer or an injected wallet never claims `ready`,
@@ -3829,14 +4045,14 @@ function injectedWalletSigner(provider) {
3829
4045
  const accounts = await provider.request({ method: "eth_requestAccounts" });
3830
4046
  const first = Array.isArray(accounts) ? accounts[0] : void 0;
3831
4047
  if (typeof first !== "string") throw new Error("injectedWalletSigner: wallet returned no accounts");
3832
- if (!EVM_ADDRESS_HEX.test(first)) throw new Error("injectedWalletSigner: wallet returned invalid address format");
4048
+ if (!EVM_ADDRESS_HEX$1.test(first)) throw new Error("injectedWalletSigner: wallet returned invalid address format");
3833
4049
  return toAddress(first);
3834
4050
  };
3835
4051
  return {
3836
4052
  source: "injected-eip1193",
3837
4053
  getAddress: resolveAddress,
3838
4054
  async signUserOpHash(hash) {
3839
- if (!SAFE_OP_DIGEST_HEX.test(hash)) throw new Error("injectedWalletSigner: SafeOp digest must be a 0x-prefixed 32-byte hex");
4055
+ if (!SAFE_OP_DIGEST_HEX$1.test(hash)) throw new Error("injectedWalletSigner: SafeOp digest must be a 0x-prefixed 32-byte hex");
3840
4056
  const address = await resolveAddress();
3841
4057
  let signature;
3842
4058
  try {
@@ -3849,8 +4065,8 @@ function injectedWalletSigner(provider) {
3849
4065
  throw new Error(`injectedWalletSigner: eth_sign failed; enable raw-hash signing for deployment (${detail})`, { cause });
3850
4066
  }
3851
4067
  if (typeof signature !== "string") throw new Error("injectedWalletSigner: wallet returned a non-string signature");
3852
- if (!ECDSA_SIGNATURE_HEX.test(signature)) throw new Error("injectedWalletSigner: wallet returned invalid signature format");
3853
- if ((await recoverRawDigestSigner({
4068
+ if (!ECDSA_SIGNATURE_HEX$1.test(signature)) throw new Error("injectedWalletSigner: wallet returned invalid signature format");
4069
+ if ((await recoverRawDigestSigner$1({
3854
4070
  hash,
3855
4071
  signature
3856
4072
  })).toLowerCase() !== address.toLowerCase()) throw new Error("injectedWalletSigner: wallet signature did not recover the selected account for the raw SafeOp digest; use a raw-hash-capable wallet or @capxul/sdk/node localPrivateKeySigner for deployed flows");
@@ -3858,7 +4074,7 @@ function injectedWalletSigner(provider) {
3858
4074
  }
3859
4075
  };
3860
4076
  }
3861
- async function recoverRawDigestSigner(input) {
4077
+ async function recoverRawDigestSigner$1(input) {
3862
4078
  try {
3863
4079
  return toAddress(await recoverAddress(input));
3864
4080
  } catch (cause) {
@@ -4612,7 +4828,14 @@ function fromWei(rawBalance, decimals, currency) {
4612
4828
  //#region src/surface/contacts.ts
4613
4829
  function makeActorRelationshipMethods(deps) {
4614
4830
  const domain = deps.actor.kind === "account" ? "account" : "org";
4615
- const actor = deps.actor;
4831
+ const actor = deps.actor.kind === "account" ? { kind: "account" } : {
4832
+ kind: "org",
4833
+ orgId: deps.actor.orgId
4834
+ };
4835
+ const observeContactScope = Effect.annotateCurrentSpan({
4836
+ scope_kind: actor.kind === "org" ? "organization" : "account",
4837
+ ...actor.kind === "org" ? { verified_organization_id: actor.orgId } : {}
4838
+ });
4616
4839
  const convexCall = deps.convexCall;
4617
4840
  const profileGetOperation = domain === "account" ? CAPXUL_OPERATIONS.account.profile.get : CAPXUL_OPERATIONS.org.profile.get;
4618
4841
  const profileDepositInstructionsOperation = domain === "account" ? CAPXUL_OPERATIONS.account.profile.depositInstructions : CAPXUL_OPERATIONS.org.profile.depositInstructions;
@@ -4625,14 +4848,14 @@ function makeActorRelationshipMethods(deps) {
4625
4848
  return runPortEffect(mapReply(CAPXUL_OPERATIONS.addressBook.list, Effect.suspend(() => convexCall.query(fns.addressBookList, copyInvocationObservation(controls, {
4626
4849
  actor,
4627
4850
  ...input?.includeHidden === void 0 ? {} : { includeHidden: input.includeHidden }
4628
- }))), (entries) => entries.map(mapAddressBookEntry)), controls, CAPXUL_OPERATIONS.addressBook.list, deps.runPromise);
4851
+ }))), (entries) => entries.map(mapAddressBookEntry)).pipe(Effect.tap(() => observeContactScope)), controls, CAPXUL_OPERATIONS.addressBook.list, deps.runPromise);
4629
4852
  },
4630
4853
  get: (entryId, options) => {
4631
4854
  const controls = deps.invocationControls?.(options) ?? options;
4632
4855
  return runPortEffect(mapReply(CAPXUL_OPERATIONS.addressBook.get, Effect.suspend(() => convexCall.query(fns.addressBookGet, copyInvocationObservation(controls, {
4633
4856
  actor,
4634
4857
  partyId: entryId
4635
- }))), (entry) => entry === null ? null : mapAddressBookEntry(entry)), controls, CAPXUL_OPERATIONS.addressBook.get, deps.runPromise);
4858
+ }))), (entry) => entry === null ? null : mapAddressBookEntry(entry)).pipe(Effect.tap(() => observeContactScope)), controls, CAPXUL_OPERATIONS.addressBook.get, deps.runPromise);
4636
4859
  },
4637
4860
  add: (input, options) => {
4638
4861
  const controls = deps.invocationControls?.(options) ?? options;
@@ -4642,21 +4865,21 @@ function makeActorRelationshipMethods(deps) {
4642
4865
  actor,
4643
4866
  ref: ref.value,
4644
4867
  ...input.label === void 0 ? {} : { label: input.label }
4645
- }))), mapAddressBookEntry), controls, CAPXUL_OPERATIONS.addressBook.add, deps.runPromise);
4868
+ }))), mapAddressBookEntry).pipe(Effect.tap(() => observeContactScope)), controls, CAPXUL_OPERATIONS.addressBook.add, deps.runPromise);
4646
4869
  },
4647
4870
  hide: (entryId, options) => {
4648
4871
  const controls = deps.invocationControls?.(options) ?? options;
4649
4872
  return runPortEffect(mapReply(CAPXUL_OPERATIONS.addressBook.hide, Effect.suspend(() => convexCall.mutation(fns.addressBookHide, copyInvocationObservation(controls, {
4650
4873
  actor,
4651
4874
  partyId: entryId
4652
- }))), mapAddressBookEntry), controls, CAPXUL_OPERATIONS.addressBook.hide, deps.runPromise);
4875
+ }))), mapAddressBookEntry).pipe(Effect.tap(() => observeContactScope)), controls, CAPXUL_OPERATIONS.addressBook.hide, deps.runPromise);
4653
4876
  },
4654
4877
  unhide: (entryId, options) => {
4655
4878
  const controls = deps.invocationControls?.(options) ?? options;
4656
4879
  return runPortEffect(mapReply(CAPXUL_OPERATIONS.addressBook.unhide, Effect.suspend(() => convexCall.mutation(fns.addressBookUnhide, copyInvocationObservation(controls, {
4657
4880
  actor,
4658
4881
  partyId: entryId
4659
- }))), mapAddressBookEntry), controls, CAPXUL_OPERATIONS.addressBook.unhide, deps.runPromise);
4882
+ }))), mapAddressBookEntry).pipe(Effect.tap(() => observeContactScope)), controls, CAPXUL_OPERATIONS.addressBook.unhide, deps.runPromise);
4660
4883
  },
4661
4884
  label: (input, options) => {
4662
4885
  const controls = deps.invocationControls?.(options) ?? options;
@@ -4664,7 +4887,7 @@ function makeActorRelationshipMethods(deps) {
4664
4887
  actor,
4665
4888
  partyId: input.entryId,
4666
4889
  label: input.label
4667
- }))), mapAddressBookEntry), controls, CAPXUL_OPERATIONS.addressBook.label, deps.runPromise);
4890
+ }))), mapAddressBookEntry).pipe(Effect.tap(() => observeContactScope)), controls, CAPXUL_OPERATIONS.addressBook.label, deps.runPromise);
4668
4891
  }
4669
4892
  },
4670
4893
  requests: {
@@ -5228,12 +5451,12 @@ const moneyExecutionContract = {
5228
5451
  };
5229
5452
  //#endregion
5230
5453
  //#region package.json
5231
- var version = "4.1.4";
5454
+ var version = "4.2.0-rc.2";
5232
5455
  //#endregion
5233
5456
  //#region src/telemetry/exception-projection.ts
5234
5457
  /** Fixed fallback for failures that have no safe message. */
5235
5458
  const EXCEPTION_MESSAGE = "Capxul SDK operation failed";
5236
- const SDK_VERSION = version;
5459
+ const SDK_VERSION$1 = version;
5237
5460
  /** The one PostHog Error Tracking projection for every SDK exception emitter. */
5238
5461
  function projectSdkException(input) {
5239
5462
  const operation = normalizeExceptionOperation(input.operation);
@@ -5380,7 +5603,7 @@ function observeSdkClient(client, adapter, snapshot) {
5380
5603
  report(adapter, "exception", operation, cause, invocation);
5381
5604
  throw cause;
5382
5605
  }
5383
- if (isPromiseLike(output)) return Promise.resolve(output).then((result) => processOutput(result, path, invocation), (cause) => {
5606
+ if (isPromiseLike$1(output)) return Promise.resolve(output).then((result) => processOutput(result, path, invocation), (cause) => {
5384
5607
  report(adapter, "exception", operation, cause, invocation);
5385
5608
  throw cause;
5386
5609
  });
@@ -5454,7 +5677,7 @@ function report(adapter, kind, operation, cause, invocation, origin, authoritati
5454
5677
  const evidence = failureEvidence(cause);
5455
5678
  const failure = markFailureInvocationSnapshot({
5456
5679
  exception: syntheticException(operationName, kindName, evidence.message, evidence.stack),
5457
- sdkVersion: SDK_VERSION,
5680
+ sdkVersion: SDK_VERSION$1,
5458
5681
  operation: operationName,
5459
5682
  errorKind: kindName,
5460
5683
  ...context === void 0 ? {} : { context },
@@ -5492,7 +5715,7 @@ function resolveAdapterContext(adapter) {
5492
5715
  }
5493
5716
  }
5494
5717
  function ignoreDeliveryFailure(delivery) {
5495
- if (!isPromiseLike(delivery)) return;
5718
+ if (!isPromiseLike$1(delivery)) return;
5496
5719
  try {
5497
5720
  Promise.resolve(delivery).catch(() => void 0);
5498
5721
  } catch {}
@@ -5591,8 +5814,6 @@ function evidenceText(value) {
5591
5814
  if (typeof value !== "string" || value.length === 0) return void 0;
5592
5815
  return redactSecrets(value).slice(0, MAX_EVIDENCE_TEXT);
5593
5816
  }
5594
- /** A field whose NAME says credential is masked whatever its value looks like. */
5595
- const CREDENTIAL_FIELD_NAME = /(?:otp|pass(?:word|wd|phrase)?|token|secret|credential|api[_-]?key|private[_-]?key|authorization|cookie|session)/iu;
5596
5817
  /** Copy a details object into a JSON-safe shape with every string masked. */
5597
5818
  function evidenceValue(value, depth = 0) {
5598
5819
  if (typeof value === "string") return evidenceText(value);
@@ -5603,7 +5824,7 @@ function evidenceValue(value, depth = 0) {
5603
5824
  if (Array.isArray(value)) return value.slice(0, 50).map((item) => evidenceValue(item, depth + 1));
5604
5825
  const copy = {};
5605
5826
  for (const [key, nested] of Object.entries(value)) {
5606
- if (CREDENTIAL_FIELD_NAME.test(key)) {
5827
+ if (isCredentialField(key)) {
5607
5828
  copy[key] = "[REDACTED]";
5608
5829
  continue;
5609
5830
  }
@@ -5873,7 +6094,7 @@ function syntheticException(operation, kind, message = EXCEPTION_MESSAGE, stack)
5873
6094
  error.stack = `${kind}: ${error.message}\n at CapxulSdkBoundary.${operation} (capxul-sdk-observation://boundary/${operation}:1:1)` + (stack === void 0 ? "" : `\nCaused by: ${stack}`);
5874
6095
  return error;
5875
6096
  }
5876
- function isPromiseLike(value) {
6097
+ function isPromiseLike$1(value) {
5877
6098
  return (typeof value === "object" || typeof value === "function") && value !== null && typeof value.then === "function";
5878
6099
  }
5879
6100
  function isPlainObject(value) {
@@ -6235,6 +6456,27 @@ function activityActorField(actor) {
6235
6456
  } };
6236
6457
  }
6237
6458
  }
6459
+ /** Capture scope now; let the observed result boundary handle a malformed caller value. */
6460
+ function captureActivityInput(prepare) {
6461
+ try {
6462
+ return prepare();
6463
+ } catch (cause) {
6464
+ return Effect.die(cause);
6465
+ }
6466
+ }
6467
+ function observeActivityScope(actor) {
6468
+ const organizationId = actor?.kind === "organization" || actor?.kind === "org" ? safeEngineeringIdentifier(actor.orgId) : void 0;
6469
+ return Effect.annotateCurrentSpan({
6470
+ scope_kind: actor?.kind === "organization" || actor?.kind === "org" ? "organization" : "account",
6471
+ ...organizationId === void 0 ? {} : { verified_organization_id: organizationId }
6472
+ });
6473
+ }
6474
+ function decodeActivityViewer(value) {
6475
+ const viewer = Option.getOrUndefined(Schema.decodeUnknownOption(ActorRefSchema)(value));
6476
+ if (viewer === void 0) return void 0;
6477
+ const id = viewer.kind === "organization" ? viewer.orgId : viewer.accountId;
6478
+ return safeEngineeringIdentifier(id) === void 0 ? void 0 : viewer;
6479
+ }
6238
6480
  /** An absent actor and a `personal` actor both name the signed-in Account. */
6239
6481
  function actorScopeKey(actor) {
6240
6482
  return actor === void 0 || actor.kind === "personal" ? "personal" : `org:${actor.organizationId}`;
@@ -6429,8 +6671,9 @@ async function waitForPaymentSubmission(submission, signal, operation, onCancel
6429
6671
  });
6430
6672
  });
6431
6673
  }
6432
- function normalizeActivityDetail(detail) {
6433
- if (detail === null) return null;
6674
+ function normalizeActivityDetail(response) {
6675
+ if (response === null) return null;
6676
+ const { viewer: _viewer, ...detail } = response;
6434
6677
  if (detail.kind === "payment") {
6435
6678
  if (detail.evidence === null) return detail;
6436
6679
  return {
@@ -6707,39 +6950,58 @@ function makeFinancialOpsMethods(deps) {
6707
6950
  activity: {
6708
6951
  list: (params, options) => {
6709
6952
  const controls = deps.invocationControls?.(options) ?? options;
6710
- return runPortEffect(Effect.suspend(() => deps.convexCall.query(fns.activityList, copyInvocationObservation(controls, { input: {
6711
- ...activityActorField(params?.actor),
6953
+ return runPortEffect(captureActivityInput(() => Effect.succeed(activityActorField(params?.actor).actor)).pipe(Effect.flatMap((actor) => Effect.suspend(() => deps.convexCall.query(fns.activityList, copyInvocationObservation(controls, { input: {
6954
+ ...actor === void 0 ? {} : { actor },
6712
6955
  ...params?.cursor === void 0 ? {} : { cursor: params.cursor },
6713
6956
  ...params?.limit === void 0 ? {} : { limit: params.limit },
6714
6957
  ...params?.range === void 0 ? {} : { range: params.range },
6715
6958
  ...params?.filter === void 0 ? {} : { filter: params.filter }
6716
- } }))), controls, CAPXUL_OPERATIONS.activity.list, deps.runPromise);
6959
+ } }))).pipe(Effect.tap(() => observeActivityScope(actor))))), controls, CAPXUL_OPERATIONS.activity.list, deps.runPromise);
6717
6960
  },
6718
6961
  summary: (params, options) => {
6719
6962
  const controls = deps.invocationControls?.(options) ?? options;
6720
- return runPortEffect(Effect.suspend(() => deps.convexCall.query(fns.activitySummary, copyInvocationObservation(controls, { input: {
6721
- ...activityActorField(params?.actor),
6963
+ return runPortEffect(captureActivityInput(() => Effect.succeed(activityActorField(params?.actor).actor)).pipe(Effect.flatMap((actor) => Effect.suspend(() => deps.convexCall.query(fns.activitySummary, copyInvocationObservation(controls, { input: {
6964
+ ...actor === void 0 ? {} : { actor },
6722
6965
  ...params?.window === void 0 ? {} : { window: params.window }
6723
- } }))), controls, CAPXUL_OPERATIONS.activity.summary, deps.runPromise);
6966
+ } }))).pipe(Effect.tap(() => observeActivityScope(actor))))), controls, CAPXUL_OPERATIONS.activity.summary, deps.runPromise);
6724
6967
  },
6725
6968
  get: (reference, options) => {
6726
6969
  const controls = deps.invocationControls?.(options) ?? options;
6727
- const actor = actorReferenceToBackend(options?.actor);
6728
- return runPortEffect(Effect.suspend(() => deps.convexCall.query(fns.activityGet, copyInvocationObservation(controls, {
6970
+ const requestedActor = actorReferenceToBackend(options?.actor);
6971
+ return runPortEffect(captureActivityInput(() => {
6972
+ const scope = requestedActor === void 0 ? void 0 : requestedActor.kind === "org" ? {
6973
+ kind: "org",
6974
+ orgId: requestedActor.orgId
6975
+ } : { kind: "account" };
6976
+ return Effect.succeed({
6977
+ actor: scope,
6978
+ referenceActor: reference.kind === "payment" ? activityActorField(reference.actor).actor : void 0
6979
+ });
6980
+ }).pipe(Effect.flatMap(({ actor, referenceActor }) => Effect.suspend(() => deps.convexCall.query(fns.activityGet, copyInvocationObservation(controls, {
6729
6981
  input: {
6730
6982
  kind: reference.kind,
6731
6983
  id: reference.id,
6732
- ...reference.kind === "payment" ? activityActorField(reference.actor) : {}
6984
+ ...referenceActor === void 0 ? {} : { actor: referenceActor }
6733
6985
  },
6734
6986
  ...actor === void 0 ? {} : { actor }
6735
- }))).pipe(Effect.map(normalizeActivityDetail)), controls, CAPXUL_OPERATIONS.activity.get, deps.runPromise);
6987
+ }))).pipe(Effect.flatMap((response) => {
6988
+ const detail = normalizeActivityDetail(response);
6989
+ if (response === null) return Effect.succeed(detail);
6990
+ const viewer = response.viewer === void 0 ? actor ?? referenceActor : decodeActivityViewer(response.viewer);
6991
+ return viewer === void 0 ? Effect.succeed(detail) : observeActivityScope(viewer).pipe(Effect.as(detail));
6992
+ })))), controls, CAPXUL_OPERATIONS.activity.get, deps.runPromise);
6736
6993
  },
6737
6994
  annotate: (input, options) => {
6738
6995
  const controls = deps.invocationControls?.(options) ?? options;
6739
- if (input.actor !== void 0 && input.reference.kind === "payment" && input.reference.actor !== void 0 && !sameActor(input.actor, input.reference.actor)) return runCapxulEffect(Effect.fail(Errors.invalidInput("reference.actor", "must match the annotation actor")), controls, CAPXUL_OPERATIONS.activity.annotate, deps.runPromise);
6740
- const referenceActor = input.reference.kind === "payment" ? activityActorField(input.reference.actor).actor : void 0;
6741
- return runPortEffect(Effect.suspend(() => deps.convexCall.mutation(fns.activityAnnotate, copyInvocationObservation(controls, { input: {
6742
- ...activityActorField(input.actor),
6996
+ return runPortEffect(captureActivityInput(() => {
6997
+ const actor = activityActorField(input.actor).actor;
6998
+ if (input.actor !== void 0 && input.reference.kind === "payment" && input.reference.actor !== void 0 && !sameActor(input.actor, input.reference.actor)) return Effect.fail({ publicError: Errors.invalidInput("reference.actor", "must match the annotation actor") });
6999
+ return Effect.succeed({
7000
+ actor,
7001
+ referenceActor: input.reference.kind === "payment" ? activityActorField(input.reference.actor).actor : void 0
7002
+ });
7003
+ }).pipe(Effect.flatMap(({ actor, referenceActor }) => Effect.suspend(() => deps.convexCall.mutation(fns.activityAnnotate, copyInvocationObservation(controls, { input: {
7004
+ ...actor === void 0 ? {} : { actor },
6743
7005
  reference: input.reference.kind === "payment" && referenceActor !== void 0 ? {
6744
7006
  kind: "payment",
6745
7007
  id: input.reference.id,
@@ -6751,7 +7013,10 @@ function makeFinancialOpsMethods(deps) {
6751
7013
  ...input.counterpartyLabel === void 0 ? {} : { counterpartyLabel: input.counterpartyLabel },
6752
7014
  ...input.accountingCategory === void 0 ? {} : { accountingCategory: input.accountingCategory },
6753
7015
  ...input.memo === void 0 ? {} : { memo: input.memo }
6754
- } }))), controls, CAPXUL_OPERATIONS.activity.annotate, deps.runPromise);
7016
+ } }))).pipe(Effect.tap((annotation) => {
7017
+ const scope = decodeActivityViewer(annotation.actor);
7018
+ return scope === void 0 ? Effect.void : observeActivityScope(scope);
7019
+ })))), controls, CAPXUL_OPERATIONS.activity.annotate, deps.runPromise);
6755
7020
  }
6756
7021
  },
6757
7022
  offramp: {
@@ -7045,148 +7310,2974 @@ function mapOk(result, f) {
7045
7310
  }
7046
7311
  }
7047
7312
  //#endregion
7048
- //#region src/ports/bootstrap.ts
7049
- var BootstrapError = class extends Data.TaggedError("BootstrapError") {};
7050
- function bootstrapErrorFromCapxul(kind, error) {
7051
- return new BootstrapError({
7052
- operation: "resolve",
7053
- kind,
7054
- publicCode: error.code,
7055
- cause: error,
7056
- ...kind === "notAuthenticated" || error.details === void 0 ? {} : { details: error.details }
7057
- });
7058
- }
7059
- var BootstrapPortTag = class extends Context.Service()("@capxul/sdk/ports/BootstrapPort") {};
7060
- //#endregion
7061
- //#region src/ports/convex-call.ts
7062
- var ConvexCallError = class extends Data.TaggedError("ConvexCallError") {};
7063
- function convexCallErrorFromCapxul(operation, error, transport) {
7064
- return new ConvexCallError({
7065
- operation,
7066
- publicCode: error.code,
7067
- publicError: error,
7068
- cause: error,
7069
- ...error.details === void 0 ? {} : { details: error.details },
7070
- ...transport === void 0 ? {} : { transport }
7071
- });
7072
- }
7073
- var ConvexCallPortTag = class extends Context.Service()("@capxul/sdk/ports/ConvexCallPort") {};
7074
- //#endregion
7075
- //#region src/ports/identity.ts
7076
- var IdentityError = class extends Data.TaggedError("IdentityError") {};
7077
- function identityErrorFromCapxul(operation, error, cause = error) {
7078
- return new IdentityError({
7079
- operation,
7080
- publicCode: error.code,
7081
- publicError: error,
7082
- cause,
7083
- ...error.details === void 0 ? {} : { details: error.details }
7084
- });
7085
- }
7086
- var IdentityPortTag = class extends Context.Service()("@capxul/sdk/ports/IdentityPort") {};
7087
- //#endregion
7088
- //#region src/adapters/_shared/wire.ts
7313
+ //#region src/dev-signer.ts
7314
+ const SESSION_KEY = "capxul.session";
7089
7315
  /**
7090
- * Documented brand-erasure helpers for the wire boundary.
7091
- *
7092
- * Branded primitives (`Address`, `ChainId`) carry compile-time tags that
7093
- * vanish at runtime. When sending values across a wire Convex function
7094
- * args, viem's template-literal-typed parameters, raw JSON we have to
7095
- * remove the brand at the type level so the wire-side type system accepts
7096
- * the value.
7316
+ * Chains a `local-private-key` signer may sign on. Base Sepolia only, and this
7317
+ * list does not grow without an ADR: the keys are deterministic throwaways
7318
+ * derived from a shared seed (see `deriveDevPrivateKey`), so anyone holding
7319
+ * the seed holds every account. A dev key on a value-bearing chain is a
7320
+ * custody incident, not a config mistake.
7321
+ */
7322
+ const DEV_KEY_ALLOWED_CHAIN_IDS = [BASE_SEPOLIA_CHAIN_ID];
7323
+ /**
7324
+ * Testnet fence for the dev-key signing lane (#1149, folds #1065; ADR-0018 P9
7325
+ * human/Openfort vs agent/dev-key split). Call it wherever a signer first
7326
+ * meets a resolved chain; it refuses before the signer can be used.
7097
7327
  *
7098
- * Using these helpers (rather than ad-hoc `as number` / `as \`0x${string}\``
7099
- * casts) localizes every de-branding site. If we ever need to centralize
7100
- * validation (e.g. "must not de-brand a placeholder address"), the change
7101
- * lands here once instead of grep-and-replace across every adapter.
7328
+ * Only `local-private-key` signers are fenced — Openfort-embedded and injected
7329
+ * wallets carry their own custody and are the sanctioned human paths.
7102
7330
  */
7331
+ function assertDevKeySignerIsTestnetOnly(signer, chainId) {
7332
+ if (signer?.source !== "local-private-key") return {
7333
+ ok: true,
7334
+ value: void 0
7335
+ };
7336
+ if (DEV_KEY_ALLOWED_CHAIN_IDS.includes(chainId)) return {
7337
+ ok: true,
7338
+ value: void 0
7339
+ };
7340
+ return {
7341
+ ok: false,
7342
+ error: Errors.invalidInput("signer", `dev-key signer is testnet-only: chain ${chainId} is not allowed (expected ${DEV_KEY_ALLOWED_CHAIN_IDS.join(", ")})`)
7343
+ };
7344
+ }
7345
+ /** Deterministic dev private key for an email under a seed. Exported for probes. */
7346
+ function deriveDevPrivateKey(seed, email) {
7347
+ return keccak256(stringToHex(seed + normalizeBindingEmail(email)));
7348
+ }
7349
+ function readSessionEmail(storage) {
7350
+ const resolved = storage ?? globalThis.window?.localStorage;
7351
+ if (resolved === void 0) throw new Error("devPrivateKeySigner: no browser localStorage available and no explicit email supplied");
7352
+ const raw = resolved.getItem(SESSION_KEY);
7353
+ if (raw === null) throw new Error("devPrivateKeySigner: no cached session yet — sign in before the account lane uses the signer");
7354
+ let email;
7355
+ try {
7356
+ email = JSON.parse(raw).email;
7357
+ } catch {
7358
+ throw new Error("devPrivateKeySigner: cached session is not valid JSON");
7359
+ }
7360
+ if (typeof email !== "string" || email.length === 0) throw new Error("devPrivateKeySigner: cached session has no email");
7361
+ return email;
7362
+ }
7103
7363
  /**
7104
- * De-brand a `ChainId` for the wire. The runtime representation is already
7105
- * `number` the cast removes the compile-time brand only.
7364
+ * Browser-safe dev signer. Lazy: the email (and so the key) is resolved at
7365
+ * each `getAddress()` / `signUserOpHash()` from the cached session, so the
7366
+ * same signer instance follows whichever user is signed in.
7106
7367
  */
7107
- function wireChainId(chainId) {
7108
- return chainId;
7368
+ function devPrivateKeySigner(input) {
7369
+ if (input.seed.trim().length === 0) throw new Error("devPrivateKeySigner: seed must be non-empty");
7370
+ const accounts = /* @__PURE__ */ new Map();
7371
+ const resolveAccount = () => {
7372
+ const email = normalizeBindingEmail(input.email ?? readSessionEmail(input.storage));
7373
+ const cached = accounts.get(email);
7374
+ if (cached !== void 0) return cached;
7375
+ const account = privateKeyToAccount(deriveDevPrivateKey(input.seed, email));
7376
+ accounts.set(email, account);
7377
+ return account;
7378
+ };
7379
+ return {
7380
+ source: "local-private-key",
7381
+ async getAddress() {
7382
+ return toAddress(resolveAccount().address);
7383
+ },
7384
+ async signUserOpHash(hash) {
7385
+ return resolveAccount().sign({ hash });
7386
+ }
7387
+ };
7109
7388
  }
7110
7389
  //#endregion
7111
- //#region src/telemetry/invocation.ts
7112
- const PRODUCT_INVOCATION = Symbol("capxul.product-telemetry-invocation");
7113
- function bindProductTelemetryInvocation(telemetry, source) {
7114
- return telemetry[PRODUCT_INVOCATION]?.(source) ?? telemetry;
7390
+ //#region src/ports/embedded-wallet.ts
7391
+ function openfortEmbeddedWalletPort(input) {
7392
+ return {
7393
+ async getAddress() {
7394
+ if (input.ensureReady !== void 0) await input.ensureReady();
7395
+ return (await input.embeddedWallet.get()).address;
7396
+ },
7397
+ async signRawDigest(hash) {
7398
+ if (input.ensureReady !== void 0) await input.ensureReady();
7399
+ return await input.embeddedWallet.signMessage(hash, {
7400
+ hashMessage: false,
7401
+ arrayifyMessage: false
7402
+ });
7403
+ }
7404
+ };
7115
7405
  }
7116
7406
  //#endregion
7117
- //#region src/adapters/convex-call/retry-idempotent-read.ts
7118
- const MAX_RETRIES = 2;
7119
- function isConnectionLoss(error) {
7120
- return error.publicCode === "NETWORK_ERROR" && error.publicError.mode === "upstream-down" && error.publicError.details?.reason === "connection-lost-in-flight";
7121
- }
7122
- function retryIdempotentRead(effect, operation, telemetry, invocationSource) {
7123
- return Effect.suspend(() => {
7124
- let attempt = 0;
7125
- const invocationTelemetry = telemetry === void 0 ? void 0 : bindProductTelemetryInvocation(telemetry, invocationSource);
7126
- return effect.pipe(Effect.tapError((error) => {
7127
- if (!isConnectionLoss(error) || attempt >= MAX_RETRIES) return Effect.void;
7128
- attempt += 1;
7129
- const eventFields = {
7130
- operation,
7131
- failure_mode: "upstream-down",
7132
- reason: "connection-lost-in-flight",
7133
- attempt,
7134
- delay_ms: 0,
7135
- ...error.transport === void 0 ? {} : {
7136
- connection_id: error.transport.connection_id,
7137
- connection_count: error.transport.connection_count
7138
- }
7139
- };
7140
- const transport = error.transport;
7141
- const connection = transport === void 0 ? void 0 : omitTransportKind(transport);
7142
- const log = Effect.logInfo("capxul.operation.retried").pipe(Effect.annotateLogs(connection === void 0 ? eventFields : {
7143
- ...eventFields,
7144
- ...connection
7145
- }), Effect.catchCause(() => Effect.void));
7146
- if (invocationTelemetry === void 0) return log;
7147
- return log.pipe(Effect.andThen(invocationTelemetry.emit({
7148
- name: "operation_retried",
7149
- props: eventFields
7150
- })), Effect.catchCause(() => Effect.void));
7151
- }), Effect.retry({
7152
- times: MAX_RETRIES,
7153
- while: isConnectionLoss
7154
- }));
7155
- });
7407
+ //#region src/openfort-embedded-signer.ts
7408
+ const EVM_ADDRESS_HEX = /^0x[0-9a-fA-F]{40}$/;
7409
+ const ECDSA_SIGNATURE_HEX = /^0x[0-9a-fA-F]{130}$/;
7410
+ const SAFE_OP_DIGEST_HEX = /^0x[0-9a-fA-F]{64}$/;
7411
+ /** Browser helper: wrap an initialized Openfort `embeddedWallet` API. */
7412
+ function openfortEmbeddedSignerFromWallet(input) {
7413
+ return openfortEmbeddedSigner({ wallet: openfortEmbeddedWalletPort({
7414
+ embeddedWallet: input.embeddedWallet,
7415
+ ...input.ensureWalletReady === void 0 ? {} : { ensureReady: input.ensureWalletReady }
7416
+ }) });
7417
+ }
7418
+ function openfortEmbeddedSigner(input) {
7419
+ let cachedAddress = null;
7420
+ let addressInFlight = null;
7421
+ let cacheEpoch = 0;
7422
+ const resetAddressCache = () => {
7423
+ cacheEpoch += 1;
7424
+ cachedAddress = null;
7425
+ addressInFlight = null;
7426
+ };
7427
+ const resolveAddress = async () => {
7428
+ if (cachedAddress !== null) return cachedAddress;
7429
+ if (addressInFlight !== null) return addressInFlight;
7430
+ const epoch = cacheEpoch;
7431
+ addressInFlight = (async () => {
7432
+ try {
7433
+ const raw = await input.wallet.getAddress();
7434
+ if (!EVM_ADDRESS_HEX.test(raw)) throw new Error("openfortEmbeddedSigner: embedded wallet returned invalid address format");
7435
+ const address = toAddress(raw);
7436
+ if (epoch === cacheEpoch) cachedAddress = address;
7437
+ return address;
7438
+ } finally {
7439
+ if (epoch === cacheEpoch) addressInFlight = null;
7440
+ }
7441
+ })();
7442
+ return addressInFlight;
7443
+ };
7444
+ return {
7445
+ source: "openfort-embedded",
7446
+ getAddress: resolveAddress,
7447
+ resetAddressCache,
7448
+ async signUserOpHash(hash) {
7449
+ if (!SAFE_OP_DIGEST_HEX.test(hash)) throw new Error("openfortEmbeddedSigner: SafeOp digest must be a 0x-prefixed 32-byte hex");
7450
+ const address = await resolveAddress();
7451
+ let signature;
7452
+ try {
7453
+ signature = await input.wallet.signRawDigest(hash);
7454
+ } catch (cause) {
7455
+ const detail = cause instanceof Error ? cause.message : String(cause);
7456
+ throw new Error(`openfortEmbeddedSigner: raw digest signing failed; ensure the embedded wallet is configured (${detail})`, { cause });
7457
+ }
7458
+ if (!ECDSA_SIGNATURE_HEX.test(signature)) throw new Error("openfortEmbeddedSigner: embedded wallet returned invalid signature format");
7459
+ if ((await recoverRawDigestSigner({
7460
+ hash,
7461
+ signature
7462
+ })).toLowerCase() !== address.toLowerCase()) throw new Error("openfortEmbeddedSigner: signature did not recover the embedded wallet address for the raw SafeOp digest");
7463
+ return signature;
7464
+ }
7465
+ };
7156
7466
  }
7157
- function omitTransportKind(transport) {
7158
- const { kind: _kind, ...connection } = transport;
7159
- return connection;
7467
+ /**
7468
+ * Canonical name for the embedded-wallet `CapxulSigner` constructor
7469
+ * (backend-orchestrated-deploy.md). The embedded-wallet (passkey / Openfort)
7470
+ * member of the named constructor trio `localPrivateKeySigner` /
7471
+ * `injectedWalletSigner` / `embeddedSigner`. Takes the provider-agnostic
7472
+ * `OpenfortEmbeddedWalletPort` (getAddress + signRawDigest); the Openfort-API
7473
+ * convenience wrapper is `openfortEmbeddedSignerFromWallet`.
7474
+ */
7475
+ const embeddedSigner = openfortEmbeddedSigner;
7476
+ async function recoverRawDigestSigner(input) {
7477
+ try {
7478
+ return toAddress(await recoverAddress(input));
7479
+ } catch (cause) {
7480
+ const detail = cause instanceof Error ? cause.message : String(cause);
7481
+ throw new Error(`openfortEmbeddedSigner: could not verify raw SafeOp digest signature (${detail})`, { cause });
7482
+ }
7160
7483
  }
7161
7484
  //#endregion
7162
- //#region src/ports/telemetry.ts
7163
- var TelemetryPortTag = class extends Context.Service()("@capxul/sdk/ports/TelemetryPort") {};
7164
- //#endregion
7165
- //#region src/ports/account-read.ts
7166
- var AccountReadError = class extends Data.TaggedError("AccountReadError") {};
7167
- function accountReadErrorFromCapxul(operation, error, cause = error) {
7168
- return new AccountReadError({
7169
- operation,
7170
- publicCode: error.code,
7171
- publicError: error,
7485
+ //#region ../observability/src/engineering.ts
7486
+ const ENGINEERING_CAPXUL_ENVS = [
7487
+ "development",
7488
+ "staging",
7489
+ "production",
7490
+ "local"
7491
+ ];
7492
+ const traceHeaderFilter = (_name) => true;
7493
+ const credentialHeaderPattern = Object.assign(/./u, { test: (name) => isCredentialField(name, "header") });
7494
+ const postHogOtlpEndpoints = (host) => {
7495
+ const base = host.replace(/\/+$/, "");
7496
+ return {
7497
+ logs: `${base}/i/v1/logs`,
7498
+ traces: `${base}/i/v1/traces`
7499
+ };
7500
+ };
7501
+ const ENGINEERING_CAPXUL_ENV_SET = new Set(ENGINEERING_CAPXUL_ENVS);
7502
+ const ENGINEERING_PRODUCERS = /* @__PURE__ */ new Set(["browser", "server"]);
7503
+ const PUBLIC_POSTHOG_AUTHORIZATION = /^Bearer phc_[A-Za-z0-9_-]{1,191}$/u;
7504
+ const SAFE_RESOURCE_VALUE = /^[A-Za-z0-9][A-Za-z0-9._+@/-]{0,127}$/u;
7505
+ const validateEngineeringTelemetryConfig = (config) => {
7506
+ let url;
7507
+ try {
7508
+ url = new URL(config.host);
7509
+ } catch {
7510
+ throw new TypeError("engineering telemetry host must be an absolute HTTPS URL");
7511
+ }
7512
+ if (url.protocol !== "https:" || url.username.length > 0 || url.password.length > 0 || url.pathname !== "/" || url.search.length > 0 || url.hash.length > 0 || !(url.hostname === "posthog.com" || url.hostname.endsWith(".posthog.com"))) throw new TypeError("engineering telemetry host must be a credential-free HTTPS origin");
7513
+ if (!ENGINEERING_CAPXUL_ENV_SET.has(config.capxulEnv)) throw new TypeError("engineering telemetry capxulEnv is not canonical");
7514
+ if (!ENGINEERING_PRODUCERS.has(config.producer)) throw new TypeError("engineering telemetry producer is not canonical");
7515
+ if (!SAFE_RESOURCE_VALUE.test(config.sdkVersion)) throw new TypeError("engineering telemetry sdkVersion must be a bounded safe value");
7516
+ if (config.serviceName !== void 0 && !SAFE_RESOURCE_VALUE.test(config.serviceName)) throw new TypeError("engineering telemetry serviceName must be a bounded safe value");
7517
+ const headerEntries = Object.entries(config.headers);
7518
+ if (headerEntries.length !== 1 || headerEntries[0]?.[0].toLowerCase() !== "authorization" || !PUBLIC_POSTHOG_AUTHORIZATION.test(headerEntries[0]?.[1] ?? "")) throw new TypeError("engineering telemetry headers must contain exactly one public PostHog authorization token");
7519
+ return {
7520
+ ...config,
7521
+ host: url.origin,
7522
+ headers: Object.freeze({ authorization: headerEntries[0][1] })
7523
+ };
7524
+ };
7525
+ const failureText = (failure, key, limit, source) => {
7526
+ if (failure === null || typeof failure !== "object") return void 0;
7527
+ try {
7528
+ let owner = failure;
7529
+ let descriptor;
7530
+ for (let depth = 0; owner !== null && depth < 4; depth += 1) {
7531
+ descriptor = Object.getOwnPropertyDescriptor(owner, key);
7532
+ if (descriptor !== void 0 || key !== "name") break;
7533
+ owner = Object.getPrototypeOf(owner);
7534
+ }
7535
+ const value = descriptor?.value;
7536
+ return typeof value === "string" || key === "code" && typeof value === "number" ? redactSecrets(String(value), source).slice(0, limit) : void 0;
7537
+ } catch {
7538
+ return;
7539
+ }
7540
+ };
7541
+ const exportFailure = (failure, source) => {
7542
+ const message = failureText(failure, "message", 2048, source) ?? (typeof failure === "string" ? redactSecrets(failure, source).slice(0, 2048) : "Engineering operation failed");
7543
+ const code = failureText(failure, "code", 128);
7544
+ const error = new Error((code === void 0 ? message : `${message} [code=${code}]`).slice(0, 2048));
7545
+ error.name = failureText(failure, "_tag", 128) ?? failureText(failure, "name", 128) ?? "Error";
7546
+ error.stack = failureText(failure, "stack", 8192, source) ?? `${error.name}: ${error.message}`;
7547
+ return error;
7548
+ };
7549
+ const exportFailureExit = (cause, source) => Exit.failCause(Cause.fromReasons(cause.reasons.filter((reason) => !Cause.isInterruptReason(reason)).slice(0, 8).map((reason) => Cause.isFailReason(reason) ? Cause.makeFailReason(exportFailure(reason.error, source)) : Cause.makeDieReason(exportFailure(reason.defect, source)))));
7550
+ const BROWSER_KEEPALIVE_BYTES = 65536;
7551
+ let unfinishedBrowserExportBytes = 0;
7552
+ const hasBrowserDocument = () => typeof window !== "undefined" && typeof document !== "undefined";
7553
+ const browserExportClient = (client) => HttpClient.transform(client, (response, request) => Effect.acquireUseRelease(Effect.sync(() => {
7554
+ const bytes = "contentLength" in request.body ? request.body.contentLength : void 0;
7555
+ if (request.body._tag === "Stream" || request.body._tag === "FormData" || bytes === void 0 || !Number.isSafeInteger(bytes) || bytes < 0 || unfinishedBrowserExportBytes + bytes > BROWSER_KEEPALIVE_BYTES) return;
7556
+ unfinishedBrowserExportBytes += bytes;
7557
+ return bytes;
7558
+ }), (bytes) => response.pipe(Effect.provideService(FetchHttpClient.RequestInit, { keepalive: bytes !== void 0 }), Effect.tap((result) => bytes === void 0 ? Effect.void : Stream.runDrain(result.stream).pipe(Effect.catch((error) => error.reason._tag === "EmptyBodyError" ? Effect.void : Effect.fail(error))))), (bytes) => Effect.sync(() => {
7559
+ if (bytes !== void 0) unfinishedBrowserExportBytes -= bytes;
7560
+ })));
7561
+ const spanUpstream = (span) => {
7562
+ let current = span;
7563
+ while (current?._tag === "Span") {
7564
+ const upstream = current.attributes.get("chain.upstream");
7565
+ if (upstream === "alchemy" || upstream === "infura") return upstream;
7566
+ current = current.parent._tag === "Some" ? current.parent.value : void 0;
7567
+ }
7568
+ };
7569
+ /** Preserve domain exits while preventing the OTLP serializer from seeing raw causes. */
7570
+ const makeLeakSafeEngineeringTracer = (delegate) => Tracer.make({
7571
+ span(options) {
7572
+ const span = delegate.span(options);
7573
+ const wrapped = Object.create(span);
7574
+ Object.defineProperty(wrapped, "attribute", { value: (name, value) => {
7575
+ const source = spanUpstream(span);
7576
+ const header = /^http\.(?:request|response)\.header\.(.+)$/u.exec(name)?.[1];
7577
+ if (header !== void 0 && isCredentialField(header, "header")) span.attribute(name, "[REDACTED]");
7578
+ else if (typeof value === "string" && name === "url.query") span.attribute(name, redactUrlSecrets(`?${value}`).slice(1, 2049));
7579
+ else if (typeof value === "string" && name === "url.path") {
7580
+ const fullUrl = span.attributes.get("url.full");
7581
+ const path = typeof fullUrl === "string" ? /^https?:\/\/[^/]+([^?#]*)/u.exec(fullUrl)?.[1] ?? value : value;
7582
+ span.attribute(name, redactUrlSecrets(path, source).slice(0, 2048));
7583
+ } else if (typeof value === "string" && (name === "url.full" || header === "location" || header === "referer" || header === "referrer")) span.attribute(name, redactUrlSecrets(value, source).slice(0, 2048));
7584
+ else if (header !== void 0 && typeof value === "string") span.attribute(name, redactSecrets(value, source).slice(0, 2048));
7585
+ else span.attribute(name, value);
7586
+ } });
7587
+ Object.defineProperty(wrapped, "end", {
7588
+ configurable: false,
7589
+ enumerable: false,
7590
+ value: (endTime, exit) => {
7591
+ if (Exit.isFailure(exit) && !Cause.hasInterruptsOnly(exit.cause)) {
7592
+ const first = exit.cause.reasons.find((reason) => !Cause.isInterruptReason(reason));
7593
+ const code = failureText(first === void 0 ? void 0 : Cause.isFailReason(first) ? first.error : first.defect, "code", 128);
7594
+ if (code !== void 0) span.attribute("error.code", code);
7595
+ span.end(endTime, exportFailureExit(exit.cause, spanUpstream(span)));
7596
+ } else span.end(endTime, exit);
7597
+ },
7598
+ writable: false
7599
+ });
7600
+ return wrapped;
7601
+ },
7602
+ ...delegate.context === void 0 ? {} : { context: delegate.context.bind(delegate) }
7603
+ });
7604
+ /** Shared browser/server OTLP layer. OtlpLogger merges with incumbent loggers once. */
7605
+ const makeEngineeringTelemetryLayer = (config) => {
7606
+ const validated = validateEngineeringTelemetryConfig(config);
7607
+ const endpoints = postHogOtlpEndpoints(validated.host);
7608
+ const resource = {
7609
+ serviceName: validated.serviceName ?? "capxul-sdk",
7610
+ serviceVersion: validated.sdkVersion,
7611
+ attributes: {
7612
+ capxul_env: validated.capxulEnv,
7613
+ producer: validated.producer,
7614
+ sdk_version: validated.sdkVersion
7615
+ }
7616
+ };
7617
+ const tracing = Layer.effect(Tracer.Tracer, OtlpTracer.make({
7618
+ url: endpoints.traces,
7619
+ headers: validated.headers,
7620
+ resource
7621
+ }).pipe(Effect.map(makeLeakSafeEngineeringTracer))).pipe(Layer.provideMerge(OtlpExporter.layerFlusher));
7622
+ const logging = OtlpLogger.layer({
7623
+ url: endpoints.logs,
7624
+ headers: validated.headers,
7625
+ resource,
7626
+ mergeWithExisting: true
7627
+ });
7628
+ const headerPolicy = Layer.merge(Layer.succeed(HttpClient.TracerHeaderFilter, traceHeaderFilter), Layer.succeed(Headers.CurrentRedactedNames, [credentialHeaderPattern]));
7629
+ const browserLifecycle = Layer.effectDiscard(Effect.gen(function* () {
7630
+ if (validated.producer !== "browser" || !hasBrowserDocument()) return;
7631
+ const browserWindow = window;
7632
+ const browserDocument = document;
7633
+ const flusher = yield* OtlpExporter.Flusher;
7634
+ const run = yield* FiberSet.makeRuntime();
7635
+ const flush = () => {
7636
+ run(flusher.flush);
7637
+ };
7638
+ const visibilityChanged = () => {
7639
+ if (browserDocument.visibilityState === "hidden") flush();
7640
+ };
7641
+ yield* Effect.acquireRelease(Effect.sync(() => {
7642
+ browserDocument.addEventListener("visibilitychange", visibilityChanged);
7643
+ browserWindow.addEventListener("pagehide", flush);
7644
+ }), () => Effect.sync(() => {
7645
+ browserDocument.removeEventListener("visibilitychange", visibilityChanged);
7646
+ browserWindow.removeEventListener("pagehide", flush);
7647
+ }));
7648
+ }));
7649
+ const transport = Layer.effect(HttpClient.HttpClient, Effect.map(HttpClient.HttpClient, (client) => validated.producer === "browser" && hasBrowserDocument() ? browserExportClient(client) : client)).pipe(Layer.provide(FetchHttpClient.layer));
7650
+ return browserLifecycle.pipe(Layer.provideMerge(Layer.mergeAll(tracing, logging, headerPolicy)), Layer.provide(OtlpSerialization.layerJson), Layer.provide(transport));
7651
+ };
7652
+ //#endregion
7653
+ //#region src/adapters/auth-client/resolve-auth-url.ts
7654
+ /** Join bootstrap `authBaseUrl` with a BetterAuth route without duplicating `/api/auth`. */
7655
+ function resolveAuthClientUrl(authBaseUrl, path) {
7656
+ const base = authBaseUrl.replace(/\/$/, "");
7657
+ if (base.endsWith("/api/auth") && path.startsWith("/api/auth")) return `${base}${path.slice(9)}`;
7658
+ return `${base}${path}`;
7659
+ }
7660
+ //#endregion
7661
+ //#region src/internal/observation-http.ts
7662
+ /** Resolve one bounded pre-auth snapshot for an outbound SDK HTTP request. */
7663
+ function observationRequestHeaders(adapter, source) {
7664
+ if (adapter === void 0) return {};
7665
+ try {
7666
+ const invocation = readInvocationObservation(source);
7667
+ if (invocation !== void 0 && !invocation.active) return {};
7668
+ const encoded = encodeObservationContextHeader(invocation === void 0 ? adapter.resolveContext?.() : invocation.context);
7669
+ return encoded === void 0 ? {} : { [OBSERVATION_CONTEXT_HEADER]: encoded };
7670
+ } catch {
7671
+ return {};
7672
+ }
7673
+ }
7674
+ //#endregion
7675
+ //#region src/adapters/auth-client/BetterAuthBrowserAdapter.ts
7676
+ function withSignal$1(init, signal) {
7677
+ return signal === void 0 ? init : {
7678
+ ...init,
7679
+ signal
7680
+ };
7681
+ }
7682
+ const DEFAULT_JWT_LIFETIME_S$1 = 900;
7683
+ function decodeJwtExp$1(jwt) {
7684
+ const parts = jwt.split(".");
7685
+ if (parts.length < 2 || parts[1] === void 0) return Math.floor(Date.now() / 1e3) + DEFAULT_JWT_LIFETIME_S$1;
7686
+ try {
7687
+ const raw = parts[1].replace(/\s+/g, "");
7688
+ const pad = "=".repeat((4 - raw.length % 4) % 4);
7689
+ const decoded = atob(raw.replace(/-/g, "+").replace(/_/g, "/") + pad);
7690
+ const payload = JSON.parse(decoded);
7691
+ if (typeof payload.exp === "number" && Number.isFinite(payload.exp) && payload.exp > 0) return payload.exp;
7692
+ } catch {}
7693
+ return Math.floor(Date.now() / 1e3) + DEFAULT_JWT_LIFETIME_S$1;
7694
+ }
7695
+ function authSessionFromBetterAuth$1(token, user) {
7696
+ return {
7697
+ authUserId: toAuthUserId(user.id),
7698
+ email: toEmail(user.email),
7699
+ token: toSessionToken(token),
7700
+ expiresAt: toEpochMs(Date.now() + 6048e5)
7701
+ };
7702
+ }
7703
+ async function safeJson$1(res) {
7704
+ const raw = await res.text();
7705
+ if (raw.length === 0 || raw === "null") return null;
7706
+ try {
7707
+ return JSON.parse(raw);
7708
+ } catch {
7709
+ return null;
7710
+ }
7711
+ }
7712
+ function mapBetterAuthError(operation, body) {
7713
+ if (typeof body === "object" && body !== null) {
7714
+ const errBody = body;
7715
+ const code = typeof errBody.code === "string" ? errBody.code : "";
7716
+ if (code === "OTP_EXPIRED") return Errors.otpExpired();
7717
+ if (code === "INVALID_OTP") return Errors.invalidInput("otp", errBody.message ?? "invalid OTP");
7718
+ if (code === "VALIDATION_ERROR" || code === "INVALID_EMAIL") return Errors.invalidInput("email", errBody.message ?? "invalid email");
7719
+ }
7720
+ return Errors.providerError("better-auth", operation, new Error(String(body)));
7721
+ }
7722
+ function isAbortError$1(err, signal) {
7723
+ return signal?.aborted === true || err instanceof Error && err.name === "AbortError" || typeof DOMException !== "undefined" && err instanceof DOMException && err.name === "AbortError";
7724
+ }
7725
+ function mapFetchError$1(operation, err, signal) {
7726
+ if (isAbortError$1(err, signal)) return Errors.cancelled({ operation });
7727
+ return Errors.networkError(operation, err instanceof Error ? err : new Error(String(err)));
7728
+ }
7729
+ var BetterAuthBrowserAdapter = class {
7730
+ authBaseUrl;
7731
+ fetchImpl;
7732
+ observation;
7733
+ constructor(deps) {
7734
+ this.authBaseUrl = deps.authBaseUrl.replace(/\/$/, "");
7735
+ this.observation = deps.observation;
7736
+ this.fetchImpl = deps.fetch ?? ((input, init) => globalThis.fetch(input, init));
7737
+ }
7738
+ url(path) {
7739
+ return resolveAuthClientUrl(this.authBaseUrl, path);
7740
+ }
7741
+ async canSendOtp(_input, options) {
7742
+ if (options?.signal?.aborted) return {
7743
+ ok: false,
7744
+ error: Errors.cancelled({ operation: "canSendOtp" })
7745
+ };
7746
+ return {
7747
+ ok: true,
7748
+ value: {
7749
+ allowed: true,
7750
+ cooldownMs: toDurationMs(0)
7751
+ }
7752
+ };
7753
+ }
7754
+ async sendOtp(input, options) {
7755
+ if (options?.signal?.aborted) return {
7756
+ ok: false,
7757
+ error: Errors.cancelled({ operation: "sendOtp" })
7758
+ };
7759
+ try {
7760
+ const res = await this.fetchImpl(this.url("/api/auth/email-otp/send-verification-otp"), withSignal$1({
7761
+ method: "POST",
7762
+ headers: {
7763
+ "Content-Type": "application/json",
7764
+ ...observationRequestHeaders(this.observation, input)
7765
+ },
7766
+ body: JSON.stringify({
7767
+ email: input.email,
7768
+ type: "sign-in"
7769
+ }),
7770
+ credentials: "include"
7771
+ }, options?.signal));
7772
+ if (options?.signal?.aborted) return {
7773
+ ok: false,
7774
+ error: Errors.cancelled({ operation: "sendOtp" })
7775
+ };
7776
+ if (res.ok) return {
7777
+ ok: true,
7778
+ value: void 0
7779
+ };
7780
+ if (res.status === 429) return {
7781
+ ok: false,
7782
+ error: Errors.rateLimited({ resource: "better-auth/sendOtp" })
7783
+ };
7784
+ const body = await safeJson$1(res);
7785
+ if (typeof body === "object" && body !== null) {
7786
+ const errBody = body;
7787
+ if (errBody.code === "INVALID_EMAIL" || errBody.code === "VALIDATION_ERROR") return {
7788
+ ok: false,
7789
+ error: Errors.invalidInput("email", errBody.message ?? "invalid email")
7790
+ };
7791
+ }
7792
+ return {
7793
+ ok: false,
7794
+ error: Errors.providerError("better-auth", "sendOtp", /* @__PURE__ */ new Error(`HTTP ${res.status}`))
7795
+ };
7796
+ } catch (err) {
7797
+ return {
7798
+ ok: false,
7799
+ error: mapFetchError$1("sendOtp", err, options?.signal)
7800
+ };
7801
+ }
7802
+ }
7803
+ async verifyOtp(input, options) {
7804
+ if (options?.signal?.aborted) return {
7805
+ ok: false,
7806
+ error: Errors.cancelled({ operation: "verifyOtp" })
7807
+ };
7808
+ try {
7809
+ const res = await this.fetchImpl(this.url("/api/auth/sign-in/email-otp"), withSignal$1({
7810
+ method: "POST",
7811
+ headers: { "Content-Type": "application/json" },
7812
+ body: JSON.stringify({
7813
+ email: input.email,
7814
+ otp: input.otp
7815
+ }),
7816
+ credentials: "include"
7817
+ }, options?.signal));
7818
+ if (options?.signal?.aborted) return {
7819
+ ok: false,
7820
+ error: Errors.cancelled({ operation: "verifyOtp" })
7821
+ };
7822
+ const body = await safeJson$1(res);
7823
+ if (res.ok) {
7824
+ if (typeof body === "object" && body !== null) {
7825
+ const okBody = body;
7826
+ if (typeof okBody.token === "string" && typeof okBody.user === "object" && okBody.user !== null) return {
7827
+ ok: true,
7828
+ value: authSessionFromBetterAuth$1(okBody.token, okBody.user)
7829
+ };
7830
+ }
7831
+ return {
7832
+ ok: false,
7833
+ error: Errors.providerError("better-auth", "verifyOtp", /* @__PURE__ */ new Error("unexpected 200 body"))
7834
+ };
7835
+ }
7836
+ return {
7837
+ ok: false,
7838
+ error: mapBetterAuthError("verifyOtp", body)
7839
+ };
7840
+ } catch (err) {
7841
+ return {
7842
+ ok: false,
7843
+ error: mapFetchError$1("verifyOtp", err, options?.signal)
7844
+ };
7845
+ }
7846
+ }
7847
+ async getSession(options) {
7848
+ if (options?.signal?.aborted) return {
7849
+ ok: false,
7850
+ error: Errors.cancelled({ operation: "getSession" })
7851
+ };
7852
+ try {
7853
+ const res = await this.fetchImpl(this.url("/api/auth/get-session"), withSignal$1({
7854
+ method: "GET",
7855
+ credentials: "include"
7856
+ }, options?.signal));
7857
+ if (options?.signal?.aborted) return {
7858
+ ok: false,
7859
+ error: Errors.cancelled({ operation: "getSession" })
7860
+ };
7861
+ if (!res.ok) return {
7862
+ ok: false,
7863
+ error: Errors.providerError("better-auth", "getSession", /* @__PURE__ */ new Error(`HTTP ${res.status}`))
7864
+ };
7865
+ const body = await safeJson$1(res);
7866
+ if (body === null) return {
7867
+ ok: true,
7868
+ value: null
7869
+ };
7870
+ if (typeof body === "object" && body !== null) {
7871
+ const okBody = body;
7872
+ if (typeof okBody.user === "object" && okBody.user !== null) return {
7873
+ ok: true,
7874
+ value: authSessionFromBetterAuth$1(okBody.session?.token ?? okBody.session?.id ?? "session", okBody.user)
7875
+ };
7876
+ }
7877
+ return {
7878
+ ok: true,
7879
+ value: null
7880
+ };
7881
+ } catch (err) {
7882
+ return {
7883
+ ok: false,
7884
+ error: mapFetchError$1("getSession", err, options?.signal)
7885
+ };
7886
+ }
7887
+ }
7888
+ async signOut(options) {
7889
+ if (options?.signal?.aborted) return {
7890
+ ok: false,
7891
+ error: Errors.cancelled({ operation: "signOut" })
7892
+ };
7893
+ try {
7894
+ const res = await this.fetchImpl(this.url("/api/auth/sign-out"), withSignal$1({
7895
+ method: "POST",
7896
+ headers: { "Content-Type": "application/json" },
7897
+ body: "{}",
7898
+ credentials: "include"
7899
+ }, options?.signal));
7900
+ if (options?.signal?.aborted) return {
7901
+ ok: false,
7902
+ error: Errors.cancelled({ operation: "signOut" })
7903
+ };
7904
+ if (res.ok) return {
7905
+ ok: true,
7906
+ value: void 0
7907
+ };
7908
+ return {
7909
+ ok: false,
7910
+ error: Errors.providerError("better-auth", "signOut", /* @__PURE__ */ new Error(`HTTP ${res.status}`))
7911
+ };
7912
+ } catch (err) {
7913
+ return {
7914
+ ok: false,
7915
+ error: mapFetchError$1("signOut", err, options?.signal)
7916
+ };
7917
+ }
7918
+ }
7919
+ async getConvexJwt(options) {
7920
+ if (options?.signal?.aborted) return {
7921
+ ok: false,
7922
+ error: Errors.cancelled({ operation: "getConvexJwt" })
7923
+ };
7924
+ try {
7925
+ const res = await this.fetchImpl(this.url("/api/auth/convex/token"), withSignal$1({
7926
+ method: "GET",
7927
+ credentials: "include"
7928
+ }, options?.signal));
7929
+ if (options?.signal?.aborted) return {
7930
+ ok: false,
7931
+ error: Errors.cancelled({ operation: "getConvexJwt" })
7932
+ };
7933
+ if (res.status === 401) return {
7934
+ ok: false,
7935
+ error: Errors.notAuthenticated()
7936
+ };
7937
+ if (!res.ok) return {
7938
+ ok: false,
7939
+ error: Errors.providerError("better-auth", "getConvexJwt", /* @__PURE__ */ new Error(`HTTP ${res.status}`))
7940
+ };
7941
+ const body = await safeJson$1(res);
7942
+ if (typeof body === "object" && body !== null) {
7943
+ const okBody = body;
7944
+ if (typeof okBody.token === "string" && okBody.token.length > 0) return {
7945
+ ok: true,
7946
+ value: {
7947
+ token: toJwtToken(okBody.token),
7948
+ expEpochSeconds: toEpochSeconds(decodeJwtExp$1(okBody.token))
7949
+ }
7950
+ };
7951
+ }
7952
+ return {
7953
+ ok: false,
7954
+ error: Errors.providerError("better-auth", "getConvexJwt", /* @__PURE__ */ new Error("unexpected body"))
7955
+ };
7956
+ } catch (err) {
7957
+ return {
7958
+ ok: false,
7959
+ error: mapFetchError$1("getConvexJwt", err, options?.signal)
7960
+ };
7961
+ }
7962
+ }
7963
+ };
7964
+ function BetterAuthBrowserLayer(deps) {
7965
+ return Layer.succeed(AuthClientPortTag, authClientPortFromPromiseAdapter(new BetterAuthBrowserAdapter(deps)));
7966
+ }
7967
+ //#endregion
7968
+ //#region src/adapters/auth-client/cookie-jar.ts
7969
+ function parseSetCookie(raw) {
7970
+ const parts = raw.split(";").map((p) => p.trim());
7971
+ if (parts.length === 0 || parts[0] === void 0) return null;
7972
+ const nameValue = parts[0];
7973
+ const eq = nameValue.indexOf("=");
7974
+ if (eq < 0) return null;
7975
+ const name = nameValue.slice(0, eq).trim();
7976
+ const value = nameValue.slice(eq + 1).trim();
7977
+ if (name.length === 0) return null;
7978
+ let maxAgeSeconds = null;
7979
+ let expiresEpochMs = null;
7980
+ let path = null;
7981
+ let httpOnly = false;
7982
+ let secure = false;
7983
+ let sameSite = null;
7984
+ for (let i = 1; i < parts.length; i++) {
7985
+ const part = parts[i];
7986
+ if (part === void 0) continue;
7987
+ const partEq = part.indexOf("=");
7988
+ const key = (partEq < 0 ? part : part.slice(0, partEq)).trim().toLowerCase();
7989
+ const val = partEq < 0 ? "" : part.slice(partEq + 1).trim();
7990
+ if (key === "max-age") {
7991
+ const n = Number(val);
7992
+ if (Number.isFinite(n)) maxAgeSeconds = n;
7993
+ } else if (key === "expires") {
7994
+ const t = Date.parse(val);
7995
+ if (Number.isFinite(t)) expiresEpochMs = t;
7996
+ } else if (key === "path") path = val;
7997
+ else if (key === "httponly") httpOnly = true;
7998
+ else if (key === "secure") secure = true;
7999
+ else if (key === "samesite") {
8000
+ const lc = val.toLowerCase();
8001
+ if (lc === "strict" || lc === "lax" || lc === "none") sameSite = lc;
8002
+ }
8003
+ }
8004
+ return {
8005
+ name,
8006
+ value,
8007
+ maxAgeSeconds,
8008
+ expiresEpochMs,
8009
+ path,
8010
+ httpOnly,
8011
+ secure,
8012
+ sameSite
8013
+ };
8014
+ }
8015
+ function isExpired(cookie, nowEpochMs) {
8016
+ if (cookie.maxAgeSeconds !== null) {
8017
+ if (cookie.maxAgeSeconds <= 0) return true;
8018
+ return nowEpochMs >= cookie.storedAtEpochMs + cookie.maxAgeSeconds * 1e3;
8019
+ }
8020
+ if (cookie.expiresEpochMs !== null) return nowEpochMs >= cookie.expiresEpochMs;
8021
+ return false;
8022
+ }
8023
+ var CookieJar = class {
8024
+ store = /* @__PURE__ */ new Map();
8025
+ set(host, setCookieHeaders) {
8026
+ let perHost = this.store.get(host);
8027
+ const now = Date.now();
8028
+ for (const raw of setCookieHeaders) {
8029
+ const parsed = parseSetCookie(raw);
8030
+ if (parsed === null) continue;
8031
+ if (perHost === void 0) {
8032
+ perHost = /* @__PURE__ */ new Map();
8033
+ this.store.set(host, perHost);
8034
+ }
8035
+ if (parsed.maxAgeSeconds !== null && parsed.maxAgeSeconds <= 0) {
8036
+ perHost.delete(parsed.name);
8037
+ continue;
8038
+ }
8039
+ perHost.set(parsed.name, {
8040
+ ...parsed,
8041
+ storedAtEpochMs: now
8042
+ });
8043
+ }
8044
+ if (perHost !== void 0 && perHost.size === 0) this.store.delete(host);
8045
+ }
8046
+ getCookieHeader(host) {
8047
+ const perHost = this.store.get(host);
8048
+ if (perHost === void 0 || perHost.size === 0) return null;
8049
+ const now = Date.now();
8050
+ const live = [];
8051
+ for (const [name, cookie] of perHost.entries()) {
8052
+ if (isExpired(cookie, now)) {
8053
+ perHost.delete(name);
8054
+ continue;
8055
+ }
8056
+ live.push(`${name}=${cookie.value}`);
8057
+ }
8058
+ if (live.length === 0) {
8059
+ this.store.delete(host);
8060
+ return null;
8061
+ }
8062
+ return live.join("; ");
8063
+ }
8064
+ };
8065
+ //#endregion
8066
+ //#region src/adapters/auth-client/BetterAuthNodeAdapter.ts
8067
+ function withSignal(init, signal) {
8068
+ return signal === void 0 ? init : {
8069
+ ...init,
8070
+ signal
8071
+ };
8072
+ }
8073
+ const DEFAULT_JWT_LIFETIME_S = 900;
8074
+ function decodeJwtExp(jwt) {
8075
+ const parts = jwt.split(".");
8076
+ if (parts.length < 2 || parts[1] === void 0) return Math.floor(Date.now() / 1e3) + DEFAULT_JWT_LIFETIME_S;
8077
+ try {
8078
+ const raw = parts[1].replace(/\s+/g, "");
8079
+ const pad = "=".repeat((4 - raw.length % 4) % 4);
8080
+ const decoded = Buffer.from(raw.replace(/-/g, "+").replace(/_/g, "/") + pad, "base64").toString("utf-8");
8081
+ const payload = JSON.parse(decoded);
8082
+ if (typeof payload.exp === "number" && Number.isFinite(payload.exp) && payload.exp > 0) return payload.exp;
8083
+ } catch {}
8084
+ return Math.floor(Date.now() / 1e3) + DEFAULT_JWT_LIFETIME_S;
8085
+ }
8086
+ function authSessionFromBetterAuth(token, user) {
8087
+ return {
8088
+ authUserId: toAuthUserId(user.id),
8089
+ email: toEmail(user.email),
8090
+ token: toSessionToken(token),
8091
+ expiresAt: toEpochMs(Date.now() + 6048e5)
8092
+ };
8093
+ }
8094
+ async function safeJson(res) {
8095
+ const raw = await res.text();
8096
+ if (raw.length === 0 || raw === "null") return null;
8097
+ try {
8098
+ return JSON.parse(raw);
8099
+ } catch {
8100
+ return null;
8101
+ }
8102
+ }
8103
+ function hostFromBaseUrl(baseUrl) {
8104
+ try {
8105
+ return new URL(baseUrl).host;
8106
+ } catch {
8107
+ return baseUrl;
8108
+ }
8109
+ }
8110
+ function originFromBaseUrl(baseUrl) {
8111
+ try {
8112
+ return new URL(baseUrl).origin;
8113
+ } catch {
8114
+ return;
8115
+ }
8116
+ }
8117
+ function setCookiesFromResponse(jar, host, res) {
8118
+ const ext = res.headers;
8119
+ let setCookies = [];
8120
+ if (typeof ext.getSetCookie === "function") setCookies = ext.getSetCookie();
8121
+ else res.headers.forEach((value, key) => {
8122
+ if (key.toLowerCase() === "set-cookie") setCookies.push(value);
8123
+ });
8124
+ if (setCookies.length > 0) jar.set(host, setCookies);
8125
+ }
8126
+ function isAbortError(err, signal) {
8127
+ return signal?.aborted === true || err instanceof Error && err.name === "AbortError" || typeof DOMException !== "undefined" && err instanceof DOMException && err.name === "AbortError";
8128
+ }
8129
+ function mapFetchError(operation, err, signal) {
8130
+ if (isAbortError(err, signal)) return Errors.cancelled({ operation });
8131
+ return Errors.networkError(operation, err instanceof Error ? err : new Error(String(err)));
8132
+ }
8133
+ var BetterAuthNodeAdapter = class {
8134
+ authBaseUrl;
8135
+ host;
8136
+ origin;
8137
+ cookieJar;
8138
+ fetchImpl;
8139
+ observation;
8140
+ constructor(deps) {
8141
+ this.authBaseUrl = deps.authBaseUrl.replace(/\/$/, "");
8142
+ this.host = hostFromBaseUrl(this.authBaseUrl);
8143
+ this.origin = deps.origin?.replace(/\/$/, "");
8144
+ this.cookieJar = deps.cookieJar ?? new CookieJar();
8145
+ this.fetchImpl = deps.fetch ?? fetch;
8146
+ this.observation = deps.observation;
8147
+ }
8148
+ url(path) {
8149
+ return resolveAuthClientUrl(this.authBaseUrl, path);
8150
+ }
8151
+ headersWithCookie(extra = {}) {
8152
+ const cookie = this.cookieJar.getCookieHeader(this.host);
8153
+ return cookie !== null ? {
8154
+ ...extra,
8155
+ cookie
8156
+ } : { ...extra };
8157
+ }
8158
+ async canSendOtp(_input, options) {
8159
+ if (options?.signal?.aborted) return {
8160
+ ok: false,
8161
+ error: Errors.cancelled({ operation: "canSendOtp" })
8162
+ };
8163
+ return {
8164
+ ok: true,
8165
+ value: {
8166
+ allowed: true,
8167
+ cooldownMs: toDurationMs(0)
8168
+ }
8169
+ };
8170
+ }
8171
+ async sendOtp(input, options) {
8172
+ if (options?.signal?.aborted) return {
8173
+ ok: false,
8174
+ error: Errors.cancelled({ operation: "sendOtp" })
8175
+ };
8176
+ try {
8177
+ const res = await this.fetchImpl(this.url("/api/auth/email-otp/send-verification-otp"), withSignal({
8178
+ method: "POST",
8179
+ headers: {
8180
+ "content-type": "application/json",
8181
+ ...this.origin ? { origin: this.origin } : {},
8182
+ ...observationRequestHeaders(this.observation, input)
8183
+ },
8184
+ body: JSON.stringify({
8185
+ email: input.email,
8186
+ type: "sign-in"
8187
+ })
8188
+ }, options?.signal));
8189
+ if (options?.signal?.aborted) return {
8190
+ ok: false,
8191
+ error: Errors.cancelled({ operation: "sendOtp" })
8192
+ };
8193
+ if (res.ok) return {
8194
+ ok: true,
8195
+ value: void 0
8196
+ };
8197
+ if (res.status === 429) return {
8198
+ ok: false,
8199
+ error: Errors.rateLimited({ resource: "better-auth/sendOtp" })
8200
+ };
8201
+ const body = await safeJson(res);
8202
+ if (typeof body === "object" && body !== null) {
8203
+ const errBody = body;
8204
+ if (errBody.code === "INVALID_EMAIL" || errBody.code === "VALIDATION_ERROR") return {
8205
+ ok: false,
8206
+ error: Errors.invalidInput("email", errBody.message ?? "invalid email")
8207
+ };
8208
+ }
8209
+ return {
8210
+ ok: false,
8211
+ error: Errors.providerError("better-auth", "sendOtp", /* @__PURE__ */ new Error(`HTTP ${res.status}`))
8212
+ };
8213
+ } catch (err) {
8214
+ return {
8215
+ ok: false,
8216
+ error: mapFetchError("sendOtp", err, options?.signal)
8217
+ };
8218
+ }
8219
+ }
8220
+ async verifyOtp(input, options) {
8221
+ if (options?.signal?.aborted) return {
8222
+ ok: false,
8223
+ error: Errors.cancelled({ operation: "verifyOtp" })
8224
+ };
8225
+ try {
8226
+ const res = await this.fetchImpl(this.url("/api/auth/sign-in/email-otp"), withSignal({
8227
+ method: "POST",
8228
+ headers: {
8229
+ "content-type": "application/json",
8230
+ ...this.origin ? { origin: this.origin } : {}
8231
+ },
8232
+ body: JSON.stringify({
8233
+ email: input.email,
8234
+ otp: input.otp
8235
+ })
8236
+ }, options?.signal));
8237
+ if (options?.signal?.aborted) return {
8238
+ ok: false,
8239
+ error: Errors.cancelled({ operation: "verifyOtp" })
8240
+ };
8241
+ setCookiesFromResponse(this.cookieJar, this.host, res);
8242
+ const body = await safeJson(res);
8243
+ if (res.ok && typeof body === "object" && body !== null) {
8244
+ const okBody = body;
8245
+ if (typeof okBody.token === "string" && typeof okBody.user === "object" && okBody.user !== null) return {
8246
+ ok: true,
8247
+ value: authSessionFromBetterAuth(okBody.token, okBody.user)
8248
+ };
8249
+ }
8250
+ if (!res.ok) {
8251
+ if (typeof body === "object" && body !== null) {
8252
+ const errBody = body;
8253
+ if (errBody.code === "OTP_EXPIRED") return {
8254
+ ok: false,
8255
+ error: Errors.otpExpired()
8256
+ };
8257
+ if (errBody.code === "INVALID_OTP") return {
8258
+ ok: false,
8259
+ error: Errors.invalidInput("otp", errBody.message ?? "invalid OTP")
8260
+ };
8261
+ }
8262
+ }
8263
+ return {
8264
+ ok: false,
8265
+ error: Errors.providerError("better-auth", "verifyOtp", /* @__PURE__ */ new Error(`HTTP ${res.status}`))
8266
+ };
8267
+ } catch (err) {
8268
+ return {
8269
+ ok: false,
8270
+ error: mapFetchError("verifyOtp", err, options?.signal)
8271
+ };
8272
+ }
8273
+ }
8274
+ async getSession(options) {
8275
+ if (options?.signal?.aborted) return {
8276
+ ok: false,
8277
+ error: Errors.cancelled({ operation: "getSession" })
8278
+ };
8279
+ try {
8280
+ const res = await this.fetchImpl(this.url("/api/auth/get-session"), withSignal({
8281
+ method: "GET",
8282
+ headers: this.headersWithCookie()
8283
+ }, options?.signal));
8284
+ if (options?.signal?.aborted) return {
8285
+ ok: false,
8286
+ error: Errors.cancelled({ operation: "getSession" })
8287
+ };
8288
+ if (!res.ok) return {
8289
+ ok: false,
8290
+ error: Errors.providerError("better-auth", "getSession", /* @__PURE__ */ new Error(`HTTP ${res.status}`))
8291
+ };
8292
+ const body = await safeJson(res);
8293
+ if (body === null) return {
8294
+ ok: true,
8295
+ value: null
8296
+ };
8297
+ if (typeof body === "object" && body !== null) {
8298
+ const okBody = body;
8299
+ if (typeof okBody.user === "object" && okBody.user !== null) return {
8300
+ ok: true,
8301
+ value: authSessionFromBetterAuth(okBody.session?.token ?? okBody.session?.id ?? "session", okBody.user)
8302
+ };
8303
+ }
8304
+ return {
8305
+ ok: true,
8306
+ value: null
8307
+ };
8308
+ } catch (err) {
8309
+ return {
8310
+ ok: false,
8311
+ error: mapFetchError("getSession", err, options?.signal)
8312
+ };
8313
+ }
8314
+ }
8315
+ async signOut(options) {
8316
+ if (options?.signal?.aborted) return {
8317
+ ok: false,
8318
+ error: Errors.cancelled({ operation: "signOut" })
8319
+ };
8320
+ try {
8321
+ const signOutOrigin = originFromBaseUrl(this.authBaseUrl) ?? this.origin;
8322
+ const res = await this.fetchImpl(this.url("/api/auth/sign-out"), withSignal({
8323
+ method: "POST",
8324
+ headers: this.headersWithCookie({
8325
+ "content-type": "application/json",
8326
+ ...signOutOrigin ? { origin: signOutOrigin } : {}
8327
+ }),
8328
+ body: "{}"
8329
+ }, options?.signal));
8330
+ if (options?.signal?.aborted) return {
8331
+ ok: false,
8332
+ error: Errors.cancelled({ operation: "signOut" })
8333
+ };
8334
+ setCookiesFromResponse(this.cookieJar, this.host, res);
8335
+ if (res.ok) return {
8336
+ ok: true,
8337
+ value: void 0
8338
+ };
8339
+ return {
8340
+ ok: false,
8341
+ error: Errors.providerError("better-auth", "signOut", /* @__PURE__ */ new Error(`HTTP ${res.status}`))
8342
+ };
8343
+ } catch (err) {
8344
+ return {
8345
+ ok: false,
8346
+ error: mapFetchError("signOut", err, options?.signal)
8347
+ };
8348
+ }
8349
+ }
8350
+ async getConvexJwt(options) {
8351
+ if (options?.signal?.aborted) return {
8352
+ ok: false,
8353
+ error: Errors.cancelled({ operation: "getConvexJwt" })
8354
+ };
8355
+ try {
8356
+ const res = await this.fetchImpl(this.url("/api/auth/convex/token"), withSignal({
8357
+ method: "GET",
8358
+ headers: this.headersWithCookie()
8359
+ }, options?.signal));
8360
+ if (options?.signal?.aborted) return {
8361
+ ok: false,
8362
+ error: Errors.cancelled({ operation: "getConvexJwt" })
8363
+ };
8364
+ if (res.status === 401) return {
8365
+ ok: false,
8366
+ error: Errors.notAuthenticated()
8367
+ };
8368
+ if (!res.ok) return {
8369
+ ok: false,
8370
+ error: Errors.providerError("better-auth", "getConvexJwt", /* @__PURE__ */ new Error(`HTTP ${res.status}`))
8371
+ };
8372
+ const body = await safeJson(res);
8373
+ if (typeof body === "object" && body !== null) {
8374
+ const okBody = body;
8375
+ if (typeof okBody.token === "string" && okBody.token.length > 0) return {
8376
+ ok: true,
8377
+ value: {
8378
+ token: toJwtToken(okBody.token),
8379
+ expEpochSeconds: toEpochSeconds(decodeJwtExp(okBody.token))
8380
+ }
8381
+ };
8382
+ }
8383
+ return {
8384
+ ok: false,
8385
+ error: Errors.providerError("better-auth", "getConvexJwt", /* @__PURE__ */ new Error("unexpected body"))
8386
+ };
8387
+ } catch (err) {
8388
+ return {
8389
+ ok: false,
8390
+ error: mapFetchError("getConvexJwt", err, options?.signal)
8391
+ };
8392
+ }
8393
+ }
8394
+ };
8395
+ function BetterAuthNodeLayer(deps) {
8396
+ return Layer.succeed(AuthClientPortTag, authClientPortFromPromiseAdapter(new BetterAuthNodeAdapter(deps)));
8397
+ }
8398
+ //#endregion
8399
+ //#region src/ports/bootstrap.ts
8400
+ var BootstrapError = class extends Data.TaggedError("BootstrapError") {};
8401
+ function bootstrapErrorFromCapxul(kind, error) {
8402
+ return new BootstrapError({
8403
+ operation: "resolve",
8404
+ kind,
8405
+ publicCode: error.code,
8406
+ cause: error,
8407
+ ...kind === "notAuthenticated" || error.details === void 0 ? {} : { details: error.details }
8408
+ });
8409
+ }
8410
+ var BootstrapPortTag = class extends Context.Service()("@capxul/sdk/ports/BootstrapPort") {};
8411
+ //#endregion
8412
+ //#region src/adapters/bootstrap/HttpBootstrapAdapter.ts
8413
+ const DEFAULT_RETRY = {
8414
+ attempts: 2,
8415
+ baseDelayMs: 400
8416
+ };
8417
+ /** Request-side statuses a proxy or backend returns while momentarily unable to serve. */
8418
+ const TRANSIENT_HTTP_STATUSES = /* @__PURE__ */ new Set([
8419
+ 408,
8420
+ 425,
8421
+ 429
8422
+ ]);
8423
+ /** Every 5xx is a server-side condition worth one more try; the client sent nothing wrong. */
8424
+ function isTransientHttpStatus(status) {
8425
+ return status >= 500 || TRANSIENT_HTTP_STATUSES.has(status);
8426
+ }
8427
+ /**
8428
+ * A transient HTTP status is worth one more try. The bootstrap call crosses
8429
+ * the host's own proxy before it reaches Convex, and every observed failure
8430
+ * of that hop cleared on a retry seconds later. A network rejection (offline,
8431
+ * DNS, CORS) is not retried: it does not clear in a second, and the caller
8432
+ * surfaces it as `NETWORK_ERROR` at once. Auth and input rejections are
8433
+ * deterministic and never retried.
8434
+ */
8435
+ function isTransientBootstrapFailure(error) {
8436
+ if (error.kind !== "provider") return false;
8437
+ const status = error.details?.httpStatus;
8438
+ return typeof status === "number" && isTransientHttpStatus(status);
8439
+ }
8440
+ async function safeText(res) {
8441
+ try {
8442
+ return await res.text();
8443
+ } catch {
8444
+ return "";
8445
+ }
8446
+ }
8447
+ var HttpBootstrapAdapter = class {
8448
+ bootstrapBaseUrl;
8449
+ bootstrapHost;
8450
+ fetchImpl;
8451
+ observation;
8452
+ retry;
8453
+ constructor(deps) {
8454
+ this.bootstrapBaseUrl = deps.bootstrapBaseUrl.replace(/\/$/, "");
8455
+ this.bootstrapHost = hostOf(this.bootstrapBaseUrl);
8456
+ this.observation = deps.observation;
8457
+ this.retry = deps.retry ?? DEFAULT_RETRY;
8458
+ this.fetchImpl = deps.fetch ?? ((input, init) => globalThis.fetch(input, init));
8459
+ }
8460
+ resolve(input) {
8461
+ return this.attempt(input).pipe(Effect.retry({
8462
+ times: this.retry.attempts,
8463
+ while: isTransientBootstrapFailure,
8464
+ schedule: Schedule.exponential(Duration.millis(this.retry.baseDelayMs))
8465
+ }));
8466
+ }
8467
+ attempt(input) {
8468
+ return Effect.tryPromise({
8469
+ try: () => {
8470
+ const headers = {
8471
+ "content-type": "application/json",
8472
+ ...input.origin === void 0 ? {} : { origin: input.origin },
8473
+ ...observationRequestHeaders(this.observation)
8474
+ };
8475
+ return this.fetchImpl(`${this.bootstrapBaseUrl}/v1/client/bootstrap`, {
8476
+ method: "POST",
8477
+ headers,
8478
+ body: JSON.stringify({ publishableKey: input.publishableKey })
8479
+ });
8480
+ },
8481
+ catch: (cause) => bootstrapErrorFromCapxul("network", Errors.networkError("bootstrap", cause, {
8482
+ provider: "bootstrap",
8483
+ failure_mode: "upstream-down",
8484
+ ...this.bootstrapHost === void 0 ? {} : { target_host: this.bootstrapHost }
8485
+ }))
8486
+ }).pipe(Effect.flatMap((res) => this.mapResponse(res)));
8487
+ }
8488
+ mapResponse(res) {
8489
+ if (res.ok) return Effect.tryPromise({
8490
+ try: async () => {
8491
+ const body = await res.json();
8492
+ const state = typeof body === "object" && body !== null && "state" in body && typeof body.state === "object" && body.state !== null ? body.state : void 0;
8493
+ const rawEngineeringTelemetry = state?.engineeringTelemetry;
8494
+ const baseBody = state === void 0 || rawEngineeringTelemetry === void 0 ? body : {
8495
+ ...body,
8496
+ state: Object.fromEntries(Object.entries(state).filter(([key]) => key !== "engineeringTelemetry"))
8497
+ };
8498
+ const decoded = SchemaParser.decodeUnknownResult(BootstrapEnvelope)(baseBody);
8499
+ if (Result.isFailure(decoded)) throw Errors.invalidInput("bootstrapEnvelope", SchemaIssue.makeFormatterDefault()(decoded.failure));
8500
+ const { state: decodedState } = decoded.success;
8501
+ const decodedEngineeringTelemetry = rawEngineeringTelemetry === void 0 ? void 0 : SchemaParser.decodeUnknownResult(EngineeringTelemetryBootstrapPolicy)(rawEngineeringTelemetry, { onExcessProperty: "error" });
8502
+ return {
8503
+ applicationId: decodedState.applicationId,
8504
+ chainId: decodedState.chainId,
8505
+ sessionToken: decodedState.sessionToken,
8506
+ issuedAt: decodedState.issuedAt,
8507
+ expiresIn: decodedState.expiresIn,
8508
+ authBaseUrl: normalizeRuntimeUrl("authBaseUrl", decodedState.authBaseUrl),
8509
+ convexUrl: normalizeRuntimeUrl("convexUrl", decodedState.convexUrl),
8510
+ siteBaseUrl: normalizeRuntimeUrl("siteBaseUrl", decodedState.siteBaseUrl),
8511
+ openfortPublishableKey: decodedState.openfortPublishableKey,
8512
+ shieldPublishableKey: decodedState.shieldPublishableKey,
8513
+ ...decodedEngineeringTelemetry !== void 0 && Result.isSuccess(decodedEngineeringTelemetry) ? { engineeringTelemetry: decodedEngineeringTelemetry.success } : {}
8514
+ };
8515
+ },
8516
+ catch: (cause) => {
8517
+ if (cause instanceof CapxulError && cause.code === "INVALID_INPUT") return bootstrapErrorFromCapxul("invalidInput", cause);
8518
+ return bootstrapErrorFromCapxul("malformedBody", Errors.providerError("convex", "bootstrap", cause instanceof Error ? cause : new Error(String(cause))));
8519
+ }
8520
+ });
8521
+ return Effect.promise(() => safeText(res)).pipe(Effect.flatMap((body) => {
8522
+ if (res.status === 401 || body.startsWith("NOT_AUTHENTICATED")) return Effect.fail(bootstrapErrorFromCapxul("notAuthenticated", Errors.notAuthenticated()));
8523
+ if (res.status === 400 || body.startsWith("INVALID_INPUT")) return Effect.fail(bootstrapErrorFromCapxul("invalidInput", Errors.invalidInput("publishableKey", "rejected by bootstrap")));
8524
+ const responseBody = body.slice(0, 300);
8525
+ const edgeError = res.headers?.get?.("x-vercel-error") ?? void 0;
8526
+ const edgeRequestId = res.headers?.get?.("x-vercel-id") ?? void 0;
8527
+ return Effect.fail(bootstrapErrorFromCapxul("provider", Errors.providerError("convex", "bootstrap", /* @__PURE__ */ new Error(`HTTP ${res.status}${edgeError === void 0 ? "" : ` ${edgeError}`}`), {
8528
+ httpStatus: res.status,
8529
+ details: {
8530
+ ...responseBody.length === 0 ? {} : { responseBody },
8531
+ ...edgeError === void 0 ? {} : { edgeError },
8532
+ ...edgeRequestId === void 0 ? {} : { edgeRequestId }
8533
+ }
8534
+ })));
8535
+ }));
8536
+ }
8537
+ };
8538
+ function HttpBootstrapLayer(deps) {
8539
+ return Layer.succeed(BootstrapPortTag, new HttpBootstrapAdapter(deps));
8540
+ }
8541
+ function hostOf(url) {
8542
+ try {
8543
+ return new URL(url).hostname;
8544
+ } catch {
8545
+ return;
8546
+ }
8547
+ }
8548
+ function normalizeRuntimeUrl(field, raw) {
8549
+ let parsed;
8550
+ try {
8551
+ parsed = new URL(raw);
8552
+ } catch {
8553
+ throw Errors.invalidInput(field, "must be an http or https URL");
8554
+ }
8555
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") throw Errors.invalidInput(field, "must be an http or https URL");
8556
+ return parsed.toString().replace(/\/$/, "");
8557
+ }
8558
+ //#endregion
8559
+ //#region src/ports/convex-call.ts
8560
+ var ConvexCallError = class extends Data.TaggedError("ConvexCallError") {};
8561
+ function convexCallErrorFromCapxul(operation, error, transport) {
8562
+ return new ConvexCallError({
8563
+ operation,
8564
+ publicCode: error.code,
8565
+ publicError: error,
8566
+ cause: error,
8567
+ ...error.details === void 0 ? {} : { details: error.details },
8568
+ ...transport === void 0 ? {} : { transport }
8569
+ });
8570
+ }
8571
+ var ConvexCallPortTag = class extends Context.Service()("@capxul/sdk/ports/ConvexCallPort") {};
8572
+ //#endregion
8573
+ //#region src/adapters/convex-call/convex-connection-monitor.ts
8574
+ var ConvexConnectionMonitor = class {
8575
+ #connectionId = makeConnectionId();
8576
+ #browser = new BrowserLifecycleMonitor();
8577
+ #lastClose;
8578
+ observedWebSocketConstructor() {
8579
+ const NativeWebSocket = globalThis.WebSocket;
8580
+ if (typeof globalThis.window === "undefined" || NativeWebSocket === void 0) return void 0;
8581
+ return new Proxy(NativeWebSocket, { construct: (Target, args) => {
8582
+ const socket = Reflect.construct(Target, args);
8583
+ socket.addEventListener("close", (event) => {
8584
+ this.#lastClose = this.#browser.socketClose(event);
8585
+ });
8586
+ return socket;
8587
+ } });
8588
+ }
8589
+ close() {
8590
+ this.#browser.close();
8591
+ }
8592
+ observe(client, observer) {
8593
+ const subscribe = client.subscribeToConnectionState?.bind(client);
8594
+ if (subscribe === void 0) return () => this.#browser.close();
8595
+ let previous;
8596
+ const unsubscribe = subscribe((next) => {
8597
+ const diagnostics = this.#diagnostics(previous, next);
8598
+ previous = next;
8599
+ for (const diagnostic of diagnostics) emitDiagnostic(observer, diagnostic);
8600
+ });
8601
+ if (previous === void 0) {
8602
+ const current = safeConnectionState(client);
8603
+ if (current !== void 0) {
8604
+ previous = current;
8605
+ for (const diagnostic of this.#diagnostics(void 0, current)) emitDiagnostic(observer, diagnostic);
8606
+ }
8607
+ }
8608
+ let closed = false;
8609
+ return () => {
8610
+ if (closed) return;
8611
+ closed = true;
8612
+ try {
8613
+ unsubscribe();
8614
+ } finally {
8615
+ this.#browser.close();
8616
+ }
8617
+ };
8618
+ }
8619
+ reconnectEvidence(start, end) {
8620
+ if (!connectionRestarted(start, end)) return void 0;
8621
+ return {
8622
+ kind: "connection-lost-in-flight",
8623
+ connection_id: this.#connectionId,
8624
+ start_connection_count: start.connectionCount,
8625
+ connection_count: end.connectionCount,
8626
+ ...end.connectionRetries === void 0 ? {} : { connection_retries: end.connectionRetries },
8627
+ ...closeFields(this.#lastClose)
8628
+ };
8629
+ }
8630
+ #diagnostics(previous, next) {
8631
+ const transitions = connectionTransitions(previous, next);
8632
+ if (transitions.length === 0) return [];
8633
+ const oldest = next.timeOfOldestInflightRequest;
8634
+ const oldestInflightMs = oldest instanceof Date && Number.isFinite(oldest.getTime()) ? Math.max(0, Date.now() - oldest.getTime()) : void 0;
8635
+ return transitions.map((transition) => ({
8636
+ connection_id: this.#connectionId,
8637
+ transition,
8638
+ previous_connected: previous?.isWebSocketConnected ?? false,
8639
+ connected: next.isWebSocketConnected,
8640
+ ...next.hasEverConnected === void 0 ? {} : { has_ever_connected: next.hasEverConnected },
8641
+ connection_count: next.connectionCount,
8642
+ ...next.connectionRetries === void 0 ? {} : { connection_retries: next.connectionRetries },
8643
+ ...next.hasInflightRequests === void 0 ? {} : { has_inflight_requests: next.hasInflightRequests },
8644
+ ...next.inflightActions === void 0 ? {} : { inflight_actions: next.inflightActions },
8645
+ ...next.inflightMutations === void 0 ? {} : { inflight_mutations: next.inflightMutations },
8646
+ ...oldestInflightMs === void 0 ? {} : { oldest_inflight_ms: oldestInflightMs },
8647
+ ...closeFields(this.#lastClose)
8648
+ }));
8649
+ }
8650
+ };
8651
+ function connectionRestarted(start, end) {
8652
+ if (start === void 0 || end === void 0) return false;
8653
+ const opensBeforeCancellation = start.isWebSocketConnected ? 1 : 2;
8654
+ return end.connectionCount >= start.connectionCount + opensBeforeCancellation;
8655
+ }
8656
+ function connectionTransitions(previous, next) {
8657
+ if (previous === void 0) {
8658
+ if (next.isWebSocketConnected) return (next.connectionRetries ?? 0) > 0 ? ["retrying", "connected"] : ["connected"];
8659
+ return (next.connectionRetries ?? 0) > 0 ? ["disconnected", "retrying"] : [];
8660
+ }
8661
+ const transitions = [];
8662
+ if (previous.isWebSocketConnected !== next.isWebSocketConnected) transitions.push(next.isWebSocketConnected ? "connected" : "disconnected");
8663
+ if ((next.connectionRetries ?? 0) > (previous.connectionRetries ?? 0)) transitions.push("retrying");
8664
+ return transitions;
8665
+ }
8666
+ function emitDiagnostic(observer, diagnostic) {
8667
+ try {
8668
+ observer(diagnostic);
8669
+ } catch {}
8670
+ }
8671
+ function safeConnectionState(client) {
8672
+ try {
8673
+ return client.connectionState?.();
8674
+ } catch {
8675
+ return;
8676
+ }
8677
+ }
8678
+ function closeFields(close) {
8679
+ if (close === void 0) return {};
8680
+ return {
8681
+ close_code: close.code,
8682
+ close_was_clean: close.wasClean,
8683
+ close_reason_present: close.reasonPresent,
8684
+ ...close.documentVisibility === void 0 ? {} : { document_visibility: close.documentVisibility },
8685
+ ...close.navigatorOnline === void 0 ? {} : { navigator_online: close.navigatorOnline },
8686
+ ...close.browserEvent === void 0 ? {} : { last_browser_event: close.browserEvent },
8687
+ ...close.msSinceBrowserEvent === void 0 ? {} : { ms_since_browser_event: close.msSinceBrowserEvent }
8688
+ };
8689
+ }
8690
+ var BrowserLifecycleMonitor = class {
8691
+ #listeners = [];
8692
+ #last = {};
8693
+ constructor() {
8694
+ const windowTarget = eventTarget(globalThis.window);
8695
+ const documentTarget = eventTarget(globalThis.document);
8696
+ if (windowTarget === void 0 || documentTarget === void 0) return;
8697
+ this.#listen(documentTarget, "visibilitychange", () => {
8698
+ this.#record(globalThis.document?.visibilityState === "hidden" ? "visibility-hidden" : "visibility-visible");
8699
+ });
8700
+ this.#listen(windowTarget, "pagehide", () => this.#record("pagehide"));
8701
+ this.#listen(windowTarget, "pageshow", () => this.#record("pageshow"));
8702
+ this.#listen(windowTarget, "online", () => this.#record("online"));
8703
+ this.#listen(windowTarget, "offline", () => this.#record("offline"));
8704
+ }
8705
+ socketClose(event) {
8706
+ const now = Date.now();
8707
+ return {
8708
+ code: event.code,
8709
+ wasClean: event.wasClean,
8710
+ reasonPresent: event.reason.length > 0,
8711
+ ...this.#last.event === void 0 ? {} : { browserEvent: this.#last.event },
8712
+ ...this.#last.at === void 0 ? {} : { msSinceBrowserEvent: Math.max(0, now - this.#last.at) },
8713
+ ...globalThis.document?.visibilityState === void 0 ? {} : { documentVisibility: globalThis.document.visibilityState },
8714
+ ...globalThis.navigator?.onLine === void 0 ? {} : { navigatorOnline: globalThis.navigator.onLine }
8715
+ };
8716
+ }
8717
+ close() {
8718
+ for (const [target, name, listener] of this.#listeners) target.removeEventListener(name, listener);
8719
+ this.#listeners.length = 0;
8720
+ }
8721
+ #listen(target, name, listener) {
8722
+ target.addEventListener(name, listener);
8723
+ this.#listeners.push([
8724
+ target,
8725
+ name,
8726
+ listener
8727
+ ]);
8728
+ }
8729
+ #record(event) {
8730
+ this.#last = {
8731
+ event,
8732
+ at: Date.now()
8733
+ };
8734
+ }
8735
+ };
8736
+ function eventTarget(value) {
8737
+ if (typeof value !== "object" || value === null || !("addEventListener" in value) || typeof value.addEventListener !== "function" || !("removeEventListener" in value) || typeof value.removeEventListener !== "function") return;
8738
+ return value;
8739
+ }
8740
+ let fallbackConnectionId = 0;
8741
+ function makeConnectionId() {
8742
+ try {
8743
+ return `convex_${globalThis.crypto.randomUUID()}`;
8744
+ } catch {
8745
+ fallbackConnectionId += 1;
8746
+ return `convex_${Date.now().toString(36)}_${fallbackConnectionId.toString(36)}`;
8747
+ }
8748
+ }
8749
+ //#endregion
8750
+ //#region src/adapters/convex-call/ConvexCallAdapter.ts
8751
+ /** Exact floor-first allowlist; every additional handler must migrate its validator first. */
8752
+ const OBSERVED_CONVEX_ACTIONS = /* @__PURE__ */ new Set([
8753
+ "payroll/actions:authorizeRun",
8754
+ "account/actions:readBalance",
8755
+ "holdings/actions:current",
8756
+ "smartAccount/actions:claim",
8757
+ "org/actions:prepareFounderAccount",
8758
+ "org/actions:prepareBootstrap",
8759
+ "org/actions:submitBootstrap",
8760
+ "org/actions:resumeBootstrapSubmission",
8761
+ "org/actions:confirmBootstrap",
8762
+ "org/actions:readTreasury",
8763
+ "moneyExecution/actions:preparePaymentExecution",
8764
+ "moneyExecution/actions:abandonPaymentExecution",
8765
+ "moneyExecution/actions:submitPaymentExecution",
8766
+ "moneyExecution/paymentCommandActions:preparePaymentLifecycleExecution",
8767
+ "moneyExecution/paymentCommandActions:prepareOrganizationPaymentExecution",
8768
+ "moneyExecution/paymentCommandActions:submitPaymentCommandExecution"
8769
+ ]);
8770
+ const OBSERVED_CONVEX_QUERIES = /* @__PURE__ */ new Set([
8771
+ "movement/activity:list",
8772
+ "movement/activity:summary",
8773
+ "movement/activity:get",
8774
+ "financialOps/queries:depositInstructions",
8775
+ "financialOps/destinations:list",
8776
+ "financialOps/queries:verifyPaymentDocument",
8777
+ "financialOps/queries:renderStoredDocument",
8778
+ "financialOps/addressBook:list",
8779
+ "financialOps/addressBook:get",
8780
+ "financialOps/requestsInbox:list",
8781
+ "financialOps/requestsInbox:get",
8782
+ "financialOps/requestsInbox:inboxList",
8783
+ "payroll/queries:runs",
8784
+ "payroll/queries:groups",
8785
+ "payroll/queries:terms",
8786
+ "financialOps/queries:resolveRecipient",
8787
+ "identity/queries:loadByAuthUserId",
8788
+ "smartAccount/queries:loadByAuthUserId",
8789
+ "org/lifecycle:load"
8790
+ ]);
8791
+ const OBSERVED_CONVEX_MUTATIONS = /* @__PURE__ */ new Set([
8792
+ "movement/activity:annotate",
8793
+ "financialOps/destinations:add",
8794
+ "financialOps/destinations:remove",
8795
+ "financialOps/addressBook:add",
8796
+ "financialOps/addressBook:hide",
8797
+ "financialOps/addressBook:unhide",
8798
+ "financialOps/addressBook:label",
8799
+ "financialOps/requestsInbox:issue",
8800
+ "financialOps/requestsInbox:cancel",
8801
+ "financialOps/requestsInbox:approve",
8802
+ "financialOps/requestsInbox:decline",
8803
+ "payroll/mutations:saveGroup",
8804
+ "payroll/mutations:removeGroup",
8805
+ "identity/mutations:create",
8806
+ "identity/mutations:update",
8807
+ "identity/mutations:completeOnboarding",
8808
+ "smartAccount/mutations:provision",
8809
+ "org/lifecycle:startOrResume",
8810
+ "org/lifecycle:recordFailure",
8811
+ "org/lifecycle:retry"
8812
+ ]);
8813
+ var ConvexCallAdapter = class {
8814
+ #client;
8815
+ #tokenProvider;
8816
+ #applicationId;
8817
+ #observation;
8818
+ #connectionMonitor;
8819
+ constructor(deps) {
8820
+ this.#connectionMonitor = new ConvexConnectionMonitor();
8821
+ const webSocketConstructor = this.#connectionMonitor.observedWebSocketConstructor();
8822
+ this.#client = deps.client ?? new ConvexClient(deps.convexUrl, webSocketConstructor === void 0 ? {} : { webSocketConstructor });
8823
+ this.#tokenProvider = deps.tokenProvider;
8824
+ this.#applicationId = deps.applicationId;
8825
+ this.#observation = deps.observation;
8826
+ if (this.#tokenProvider) this.#client.setAuth(this.#tokenProvider);
8827
+ }
8828
+ refreshAuth() {
8829
+ if (this.#tokenProvider) this.#client.setAuth(this.#tokenProvider);
8830
+ }
8831
+ observeConnection(observer) {
8832
+ return this.#connectionMonitor.observe(this.#client, observer);
8833
+ }
8834
+ query(fn, args) {
8835
+ const path = getFunctionName(fn);
8836
+ return Effect.serviceOption(Tracer.ParentSpan).pipe(Effect.flatMap((parent) => {
8837
+ const traceparent = parent._tag === "Some" ? formatTraceparent(parent.value) : void 0;
8838
+ return Effect.tryPromise({
8839
+ try: () => this.#client.query(fn, this.#observedArgs(OBSERVED_CONVEX_QUERIES, path, args, traceparent)),
8840
+ catch: (cause) => mapToConvexCallError(path, cause)
8841
+ });
8842
+ }));
8843
+ }
8844
+ mutation(fn, args) {
8845
+ const path = getFunctionName(fn);
8846
+ return Effect.serviceOption(Tracer.ParentSpan).pipe(Effect.flatMap((parent) => {
8847
+ const traceparent = parent._tag === "Some" ? formatTraceparent(parent.value) : void 0;
8848
+ return Effect.tryPromise({
8849
+ try: () => this.#client.mutation(fn, this.#observedArgs(OBSERVED_CONVEX_MUTATIONS, path, args, traceparent)),
8850
+ catch: (cause) => mapToConvexCallError(path, cause)
8851
+ });
8852
+ }));
8853
+ }
8854
+ action(fn, args) {
8855
+ const path = getFunctionName(fn);
8856
+ return Effect.serviceOption(Tracer.ParentSpan).pipe(Effect.flatMap((parent) => {
8857
+ const traceparent = parent._tag === "Some" ? formatTraceparent(parent.value) : void 0;
8858
+ const connectionAtStart = connectionState(this.#client);
8859
+ return Effect.tryPromise({
8860
+ try: () => this.#client.action(fn, this.#observedArgs(OBSERVED_CONVEX_ACTIONS, path, args, traceparent)),
8861
+ catch: (cause) => {
8862
+ const transport = this.#connectionMonitor.reconnectEvidence(connectionAtStart, connectionState(this.#client));
8863
+ return mapToConvexCallError(path, cause, transport);
8864
+ }
8865
+ }).pipe(Effect.tapError((error) => logActionTransportFailure(path, error)));
8866
+ }));
8867
+ }
8868
+ #observedArgs(allowlist, path, args, traceparent) {
8869
+ if (!allowlist.has(path)) return args;
8870
+ const carriedContext = sanitizeObservationContext(args.observationContext);
8871
+ let hostContext;
8872
+ const invocationSnapshot = readInvocationObservation(args);
8873
+ if (invocationSnapshot !== void 0) hostContext = invocationSnapshot.active ? invocationSnapshot.context : void 0;
8874
+ else {
8875
+ const resolveContext = this.#observation?.resolveContext;
8876
+ if (resolveContext !== void 0) try {
8877
+ hostContext = resolveContext();
8878
+ } catch {
8879
+ hostContext = void 0;
8880
+ }
8881
+ }
8882
+ if (hostContext === void 0 && carriedContext === void 0 && traceparent === void 0) return args;
8883
+ hostContext = sanitizeObservationContext({
8884
+ ...hostContext,
8885
+ ...carriedContext,
8886
+ ...this.#applicationId === void 0 ? {} : { applicationId: this.#applicationId },
8887
+ ...traceparent === void 0 ? {} : { traceparent }
8888
+ });
8889
+ if (hostContext === void 0) return args;
8890
+ return {
8891
+ ...args,
8892
+ observationContext: hostContext
8893
+ };
8894
+ }
8895
+ subscribe(fn, args, callback) {
8896
+ return Effect.try({
8897
+ try: () => {
8898
+ const path = getFunctionName(fn);
8899
+ const unsubscribe = this.#client.onUpdate(fn, args, (value) => callback({
8900
+ status: "ok",
8901
+ value
8902
+ }), (err) => callback({
8903
+ status: "error",
8904
+ error: mapToCapxulError(path, err)
8905
+ }));
8906
+ let active = true;
8907
+ return () => {
8908
+ if (!active) return;
8909
+ active = false;
8910
+ unsubscribe();
8911
+ };
8912
+ },
8913
+ catch: (cause) => mapToConvexCallError(getFunctionName(fn), cause)
8914
+ }).pipe(Effect.tap(() => Effect.sync(() => {
8915
+ callback({ status: "loading" });
8916
+ })));
8917
+ }
8918
+ async close() {
8919
+ this.#connectionMonitor.close();
8920
+ await this.#client.close();
8921
+ }
8922
+ };
8923
+ function ConvexCallLayer(deps) {
8924
+ return Layer.effect(ConvexCallPortTag, Effect.acquireRelease(Effect.sync(() => new ConvexCallAdapter(deps)), (adapter) => Effect.promise(() => adapter.close()).pipe(Effect.orDie)));
8925
+ }
8926
+ function mapToCapxulError(operation, err, transport) {
8927
+ const decoded = decodeConvexError(err);
8928
+ if (decoded !== null) return decoded;
8929
+ if (err instanceof CapxulError) return err;
8930
+ if (transport !== void 0) {
8931
+ const { kind: _kind, start_connection_count: _start, ...connection } = transport;
8932
+ return Errors.networkError(operation, err, {
8933
+ provider: "convex",
8934
+ failure_mode: "upstream-down",
8935
+ reason: "connection-lost-in-flight",
8936
+ ...connection
8937
+ });
8938
+ }
8939
+ if (err instanceof Error) {
8940
+ if (isTransportError(err)) return Errors.networkError(operation, err, { provider: "convex" });
8941
+ return Errors.providerError("convex", operation, err);
8942
+ }
8943
+ return Errors.providerError("convex", operation, new Error(String(err)));
8944
+ }
8945
+ function mapToConvexCallError(operation, err, transport) {
8946
+ return convexCallErrorFromCapxul(operation, mapToCapxulError(operation, err, transport), transport);
8947
+ }
8948
+ function connectionState(client) {
8949
+ try {
8950
+ const state = client.connectionState?.();
8951
+ return typeof state?.connectionCount === "number" ? state : void 0;
8952
+ } catch {
8953
+ return;
8954
+ }
8955
+ }
8956
+ function logActionTransportFailure(operation, error) {
8957
+ if (error.transport === void 0) return Effect.void;
8958
+ const { kind, ...connection } = error.transport;
8959
+ return Effect.logWarning("convex.action.connection_lost").pipe(Effect.annotateLogs({
8960
+ operation,
8961
+ failure_mode: "upstream-down",
8962
+ reason: kind,
8963
+ ...connection
8964
+ }), Effect.catchCause(() => Effect.void));
8965
+ }
8966
+ const TRANSPORT_ERROR_CODES = /* @__PURE__ */ new Set([
8967
+ "EAI_AGAIN",
8968
+ "ECONNREFUSED",
8969
+ "ECONNRESET",
8970
+ "ENOTFOUND",
8971
+ "EPIPE",
8972
+ "ETIMEDOUT",
8973
+ "UND_ERR_CONNECT_TIMEOUT",
8974
+ "UND_ERR_HEADERS_TIMEOUT",
8975
+ "UND_ERR_SOCKET"
8976
+ ]);
8977
+ function isTransportError(err) {
8978
+ const seen = /* @__PURE__ */ new Set();
8979
+ let current = err;
8980
+ while (current !== void 0 && !seen.has(current)) {
8981
+ seen.add(current);
8982
+ const code = current.code;
8983
+ if (current.name === "FetchError" || current.name === "NetworkError" || typeof code === "string" && TRANSPORT_ERROR_CODES.has(code)) return true;
8984
+ current = current.cause instanceof Error ? current.cause : void 0;
8985
+ }
8986
+ return false;
8987
+ }
8988
+ //#endregion
8989
+ //#region src/ports/identity.ts
8990
+ /** The chain families a payout address may name (#1955). */
8991
+ const PAYOUT_CHAINS = [
8992
+ "evm",
8993
+ "solana",
8994
+ "starknet"
8995
+ ];
8996
+ var IdentityError = class extends Data.TaggedError("IdentityError") {};
8997
+ function identityErrorFromCapxul(operation, error, cause = error) {
8998
+ return new IdentityError({
8999
+ operation,
9000
+ publicCode: error.code,
9001
+ publicError: error,
9002
+ cause,
9003
+ ...error.details === void 0 ? {} : { details: error.details }
9004
+ });
9005
+ }
9006
+ var IdentityPortTag = class extends Context.Service()("@capxul/sdk/ports/IdentityPort") {};
9007
+ //#endregion
9008
+ //#region src/adapters/identity/ConvexIdentityAdapter.ts
9009
+ const identityLoadByAuthUserIdQuery = makeFunctionReference(CAPXUL_FUNCTIONS["identity/queries"].loadByAuthUserId);
9010
+ const identityCreateMutation = makeFunctionReference(CAPXUL_FUNCTIONS["identity/mutations"].create);
9011
+ const identityUpdateMutation = makeFunctionReference(CAPXUL_FUNCTIONS["identity/mutations"].update);
9012
+ const identityCompleteOnboardingMutation = makeFunctionReference(CAPXUL_FUNCTIONS["identity/mutations"].completeOnboarding);
9013
+ var ConvexIdentityAdapter = class {
9014
+ #convex;
9015
+ constructor(deps) {
9016
+ this.#convex = deps.convex;
9017
+ }
9018
+ loadByAuthUserId(authUserId) {
9019
+ return this.#convex.query(identityLoadByAuthUserIdQuery, { authUserId }).pipe(Effect.mapError((error) => identityErrorFromCapxul("loadByAuthUserId", error.publicError, error)), Effect.flatMap((row) => Effect.try({
9020
+ try: () => row === null ? null : brandProfile(row),
9021
+ catch: (cause) => identityErrorFromUnknown("loadByAuthUserId", cause)
9022
+ })), Effect.catchDefect((cause) => Effect.fail(identityErrorFromUnknown("loadByAuthUserId", cause))));
9023
+ }
9024
+ create(input) {
9025
+ return this.#convex.mutation(identityCreateMutation, input).pipe(Effect.mapError((error) => identityErrorFromCapxul("create", error.publicError, error)), Effect.flatMap((row) => Effect.try({
9026
+ try: () => brandProfile(row),
9027
+ catch: (cause) => identityErrorFromUnknown("create", cause)
9028
+ })), Effect.catchDefect((cause) => Effect.fail(identityErrorFromUnknown("create", cause))));
9029
+ }
9030
+ update(input) {
9031
+ return this.#convex.mutation(identityUpdateMutation, input).pipe(Effect.mapError((error) => identityErrorFromCapxul("update", error.publicError, error)), Effect.flatMap((row) => Effect.try({
9032
+ try: () => brandProfile(row),
9033
+ catch: (cause) => identityErrorFromUnknown("update", cause)
9034
+ })), Effect.catchDefect((cause) => Effect.fail(identityErrorFromUnknown("update", cause))));
9035
+ }
9036
+ completeOnboarding(input) {
9037
+ return this.#convex.mutation(identityCompleteOnboardingMutation, input).pipe(Effect.mapError((error) => identityErrorFromCapxul("completeOnboarding", error.publicError, error)), Effect.flatMap((row) => Effect.try({
9038
+ try: () => brandProfile(row),
9039
+ catch: (cause) => identityErrorFromUnknown("completeOnboarding", cause)
9040
+ })), Effect.catchDefect((cause) => Effect.fail(identityErrorFromUnknown("completeOnboarding", cause))));
9041
+ }
9042
+ };
9043
+ function ConvexIdentityLayer() {
9044
+ return Layer.effect(IdentityPortTag, Effect.map(ConvexCallPortTag, (convex) => new ConvexIdentityAdapter({ convex })));
9045
+ }
9046
+ function brandProfile(raw) {
9047
+ return {
9048
+ authUserId: toAuthUserId(raw.authUserId),
9049
+ ...raw.testerKind === void 0 ? {} : { testerKind: toTesterKind(raw.testerKind) },
9050
+ email: toEmail(raw.email),
9051
+ displayName: raw.displayName,
9052
+ country: raw.country === null ? null : toCountryCode(raw.country),
9053
+ onboarded: raw.onboarded ?? false,
9054
+ withdrawalAddress: raw.withdrawalAddress === null || raw.withdrawalAddress === void 0 ? null : toAddress(raw.withdrawalAddress),
9055
+ handle: raw.handle === null || raw.handle === void 0 ? null : toHandle(raw.handle),
9056
+ imageUrl: raw.imageUrl ?? null,
9057
+ kycTier: toKycTier(raw.kycTier),
9058
+ createdAt: toEpochMs(raw.createdAt),
9059
+ updatedAt: toEpochMs(raw.updatedAt)
9060
+ };
9061
+ }
9062
+ function identityErrorFromUnknown(operation, cause) {
9063
+ if (cause instanceof CapxulError) return identityErrorFromCapxul(operation, cause);
9064
+ return identityErrorFromCapxul(operation, Errors.providerError("convex", operation, cause), cause);
9065
+ }
9066
+ //#endregion
9067
+ //#region src/adapters/_shared/wire.ts
9068
+ /**
9069
+ * Documented brand-erasure helpers for the wire boundary.
9070
+ *
9071
+ * Branded primitives (`Address`, `ChainId`) carry compile-time tags that
9072
+ * vanish at runtime. When sending values across a wire — Convex function
9073
+ * args, viem's template-literal-typed parameters, raw JSON — we have to
9074
+ * remove the brand at the type level so the wire-side type system accepts
9075
+ * the value.
9076
+ *
9077
+ * Using these helpers (rather than ad-hoc `as number` / `as \`0x${string}\``
9078
+ * casts) localizes every de-branding site. If we ever need to centralize
9079
+ * validation (e.g. "must not de-brand a placeholder address"), the change
9080
+ * lands here once instead of grep-and-replace across every adapter.
9081
+ */
9082
+ /**
9083
+ * De-brand a `ChainId` for the wire. The runtime representation is already
9084
+ * `number` — the cast removes the compile-time brand only.
9085
+ */
9086
+ function wireChainId(chainId) {
9087
+ return chainId;
9088
+ }
9089
+ //#endregion
9090
+ //#region src/telemetry/invocation.ts
9091
+ const PRODUCT_INVOCATION = Symbol("capxul.product-telemetry-invocation");
9092
+ function bindProductTelemetryInvocation(telemetry, source) {
9093
+ return telemetry[PRODUCT_INVOCATION]?.(source) ?? telemetry;
9094
+ }
9095
+ //#endregion
9096
+ //#region src/adapters/convex-call/retry-idempotent-read.ts
9097
+ const MAX_RETRIES = 2;
9098
+ function isConnectionLoss(error) {
9099
+ return error.publicCode === "NETWORK_ERROR" && error.publicError.mode === "upstream-down" && error.publicError.details?.reason === "connection-lost-in-flight";
9100
+ }
9101
+ function retryIdempotentRead(effect, operation, telemetry, invocationSource) {
9102
+ return Effect.suspend(() => {
9103
+ let attempt = 0;
9104
+ const invocationTelemetry = telemetry === void 0 ? void 0 : bindProductTelemetryInvocation(telemetry, invocationSource);
9105
+ return effect.pipe(Effect.tapError((error) => {
9106
+ if (!isConnectionLoss(error) || attempt >= MAX_RETRIES) return Effect.void;
9107
+ attempt += 1;
9108
+ const eventFields = {
9109
+ operation,
9110
+ failure_mode: "upstream-down",
9111
+ reason: "connection-lost-in-flight",
9112
+ attempt,
9113
+ delay_ms: 0,
9114
+ ...error.transport === void 0 ? {} : {
9115
+ connection_id: error.transport.connection_id,
9116
+ connection_count: error.transport.connection_count
9117
+ }
9118
+ };
9119
+ const transport = error.transport;
9120
+ const connection = transport === void 0 ? void 0 : omitTransportKind(transport);
9121
+ const log = Effect.logInfo("capxul.operation.retried").pipe(Effect.annotateLogs(connection === void 0 ? eventFields : {
9122
+ ...eventFields,
9123
+ ...connection
9124
+ }), Effect.catchCause(() => Effect.void));
9125
+ if (invocationTelemetry === void 0) return log;
9126
+ return log.pipe(Effect.andThen(invocationTelemetry.emit({
9127
+ name: "operation_retried",
9128
+ props: eventFields
9129
+ })), Effect.catchCause(() => Effect.void));
9130
+ }), Effect.retry({
9131
+ times: MAX_RETRIES,
9132
+ while: isConnectionLoss
9133
+ }));
9134
+ });
9135
+ }
9136
+ function omitTransportKind(transport) {
9137
+ const { kind: _kind, ...connection } = transport;
9138
+ return connection;
9139
+ }
9140
+ //#endregion
9141
+ //#region src/ports/telemetry.ts
9142
+ var TelemetryPortTag = class extends Context.Service()("@capxul/sdk/ports/TelemetryPort") {};
9143
+ //#endregion
9144
+ //#region src/ports/account-read.ts
9145
+ var AccountReadError = class extends Data.TaggedError("AccountReadError") {};
9146
+ function accountReadErrorFromCapxul(operation, error, cause = error) {
9147
+ return new AccountReadError({
9148
+ operation,
9149
+ publicCode: error.code,
9150
+ publicError: error,
9151
+ cause,
9152
+ ...error.details === void 0 ? {} : { details: error.details }
9153
+ });
9154
+ }
9155
+ var AccountReadPortTag = class extends Context.Service()("@capxul/sdk/ports/AccountReadPort") {};
9156
+ //#endregion
9157
+ //#region src/adapters/account-read/ConvexAccountAdapter.ts
9158
+ const DEFAULT_FUNCTIONS$3 = {
9159
+ readBalance: makeFunctionReference(CAPXUL_FUNCTIONS["account/actions"].readBalance),
9160
+ faucetMint: makeFunctionReference(CAPXUL_FUNCTIONS["account/actions"].faucetMint)
9161
+ };
9162
+ var ConvexAccountAdapter = class {
9163
+ #convex;
9164
+ #fns;
9165
+ #telemetry;
9166
+ constructor(deps) {
9167
+ this.#convex = deps.convex;
9168
+ this.#fns = deps.functions ?? DEFAULT_FUNCTIONS$3;
9169
+ this.#telemetry = deps.telemetry;
9170
+ }
9171
+ readBalance(input) {
9172
+ return retryIdempotentRead(this.#convex.action(this.#fns.readBalance, copyInvocationObservation(input, { chainId: wireChainId(input.chainId) })), CAPXUL_OPERATIONS.accounts.read, this.#telemetry, input).pipe(Effect.mapError((error) => accountReadErrorFromCapxul("readBalance", error.publicError, error)), Effect.flatMap((wire) => brandAccountEffect("readBalance", wire)), Effect.catchDefect((cause) => Effect.fail(accountReadErrorFromUnknown("readBalance", cause))));
9173
+ }
9174
+ fundFromFaucet(input) {
9175
+ const operation = "fundFromFaucet";
9176
+ return Effect.suspend(() => {
9177
+ const rawAmount = toWei(input.amount);
9178
+ return this.#convex.action(this.#fns.faucetMint, {
9179
+ chainId: wireChainId(input.chainId),
9180
+ rawAmount
9181
+ });
9182
+ }).pipe(Effect.mapError((error) => accountReadErrorFromCapxul(operation, error.publicError, error)), Effect.map((wire) => ({ txHash: wire.txHash })), Effect.catchDefect((cause) => Effect.fail(accountReadErrorFromUnknown(operation, cause))));
9183
+ }
9184
+ };
9185
+ function ConvexAccountLayer() {
9186
+ return Layer.effect(AccountReadPortTag, Effect.all([ConvexCallPortTag, TelemetryPortTag]).pipe(Effect.map(([convex, telemetry]) => new ConvexAccountAdapter({
9187
+ convex,
9188
+ telemetry
9189
+ }))));
9190
+ }
9191
+ function brandAccountEffect(operation, wire) {
9192
+ return Effect.try({
9193
+ try: () => brandAccount(wire),
9194
+ catch: (cause) => accountReadErrorFromUnknown(operation, cause)
9195
+ });
9196
+ }
9197
+ function brandAccount(wire) {
9198
+ const balance = fromWei(wire.rawBalance, wire.decimals, wire.currency);
9199
+ const available = fromWei(wire.rawAvailableBalance ?? wire.rawBalance, wire.decimals, wire.currency);
9200
+ return {
9201
+ id: toAccountId(wire.accountId),
9202
+ balance,
9203
+ available
9204
+ };
9205
+ }
9206
+ function accountReadErrorFromUnknown(operation, cause) {
9207
+ if (cause instanceof CapxulError) return accountReadErrorFromCapxul(operation, cause);
9208
+ return accountReadErrorFromCapxul(operation, Errors.providerError("convex", operation, cause), cause);
9209
+ }
9210
+ //#endregion
9211
+ //#region src/ports/smart-account.ts
9212
+ var SmartAccountError = class extends Data.TaggedError("SmartAccountError") {};
9213
+ function smartAccountErrorFromCapxul(operation, error, cause = error) {
9214
+ return new SmartAccountError({
9215
+ operation,
9216
+ publicCode: error.code,
9217
+ publicError: error,
9218
+ cause,
9219
+ ...error.details === void 0 ? {} : { details: error.details }
9220
+ });
9221
+ }
9222
+ var SmartAccountPortTag = class extends Context.Service()("@capxul/sdk/ports/SmartAccountPort") {};
9223
+ //#endregion
9224
+ //#region src/adapters/smart-account/ConvexSmartAccountAdapter.ts
9225
+ const DEFAULT_FUNCTIONS$2 = {
9226
+ loadByAuthUserId: makeFunctionReference(CAPXUL_FUNCTIONS["smartAccount/queries"].loadByAuthUserId),
9227
+ loadBySmartAccountAddress: makeFunctionReference(CAPXUL_FUNCTIONS["smartAccount/queries"].loadBySmartAccountAddress),
9228
+ provision: makeFunctionReference(CAPXUL_FUNCTIONS["smartAccount/mutations"].provision),
9229
+ confirmDeployment: makeFunctionReference(CAPXUL_FUNCTIONS["smartAccount/actions"].confirmDeployment),
9230
+ claim: makeFunctionReference(CAPXUL_FUNCTIONS["smartAccount/actions"].claim)
9231
+ };
9232
+ var ConvexSmartAccountAdapter = class {
9233
+ #convex;
9234
+ #fns;
9235
+ constructor(deps) {
9236
+ this.#convex = deps.convex;
9237
+ this.#fns = deps.functions ?? DEFAULT_FUNCTIONS$2;
9238
+ }
9239
+ loadByAuthUserId(authUserId) {
9240
+ return this.#convex.query(this.#fns.loadByAuthUserId, { authUserId }).pipe(Effect.mapError((error) => smartAccountErrorFromCapxul("loadByAuthUserId", error.publicError, error)), Effect.flatMap((row) => brandSmartAccountEffect("loadByAuthUserId", row)), Effect.catchDefect((cause) => Effect.fail(smartAccountErrorFromUnknown("loadByAuthUserId", cause))));
9241
+ }
9242
+ loadBySmartAccountAddress(address) {
9243
+ return this.#convex.query(this.#fns.loadBySmartAccountAddress, { address }).pipe(Effect.mapError((error) => smartAccountErrorFromCapxul("loadBySmartAccountAddress", error.publicError, error)), Effect.flatMap((row) => brandSmartAccountEffect("loadBySmartAccountAddress", row)), Effect.catchDefect((cause) => Effect.fail(smartAccountErrorFromUnknown("loadBySmartAccountAddress", cause))));
9244
+ }
9245
+ provision(input) {
9246
+ return this.#convex.mutation(this.#fns.provision, { chainId: wireChainId(input.chainId) }).pipe(Effect.mapError((error) => smartAccountErrorFromCapxul("provision", error.publicError, error)), Effect.flatMap((row) => Effect.try({
9247
+ try: () => brandProvisionedSmartAccount(input.authUserId, row),
9248
+ catch: (cause) => smartAccountErrorFromUnknown("provision", cause)
9249
+ })), Effect.catchDefect((cause) => Effect.fail(smartAccountErrorFromUnknown("provision", cause))));
9250
+ }
9251
+ confirmDeployment(input) {
9252
+ const evidence = {
9253
+ chainId: wireChainId(input.evidence.chainId),
9254
+ signerAddress: input.evidence.signerAddress,
9255
+ safeAddress: input.evidence.safeAddress,
9256
+ ...input.evidence.userOpHash === void 0 ? {} : { userOpHash: input.evidence.userOpHash },
9257
+ ...input.evidence.txHash === void 0 ? {} : { txHash: input.evidence.txHash },
9258
+ ...input.evidence.blockNumber === void 0 ? {} : { blockNumber: input.evidence.blockNumber }
9259
+ };
9260
+ return this.#convex.action(this.#fns.confirmDeployment, {
9261
+ chainId: wireChainId(input.chainId),
9262
+ safeAddress: input.safeAddress,
9263
+ evidence
9264
+ }).pipe(Effect.mapError((error) => smartAccountErrorFromCapxul("confirmDeployment", error.publicError, error)), Effect.flatMap((row) => Effect.try({
9265
+ try: () => brandProvisionedSmartAccount(input.authUserId, row),
9266
+ catch: (cause) => smartAccountErrorFromUnknown("confirmDeployment", cause)
9267
+ })), Effect.catchDefect((cause) => Effect.fail(smartAccountErrorFromUnknown("confirmDeployment", cause))));
9268
+ }
9269
+ claim(input) {
9270
+ return this.#convex.action(this.#fns.claim, copyInvocationObservation(input, {
9271
+ chainId: wireChainId(input.chainId),
9272
+ signerAddress: input.signerAddress
9273
+ })).pipe(Effect.mapError((error) => smartAccountErrorFromCapxul("claim", error.publicError, error)), Effect.flatMap((row) => Effect.try({
9274
+ try: () => brandProvisionedSmartAccount(input.authUserId, row),
9275
+ catch: (cause) => smartAccountErrorFromUnknown("claim", cause)
9276
+ })), Effect.catchDefect((cause) => Effect.fail(smartAccountErrorFromUnknown("claim", cause))));
9277
+ }
9278
+ };
9279
+ function ConvexSmartAccountLayer() {
9280
+ return Layer.effect(SmartAccountPortTag, Effect.map(ConvexCallPortTag, (convex) => new ConvexSmartAccountAdapter({ convex })));
9281
+ }
9282
+ function brandSmartAccountEffect(operation, wire) {
9283
+ return Effect.try({
9284
+ try: () => wire === null ? null : brandNonNullSmartAccount(wire),
9285
+ catch: (cause) => smartAccountErrorFromUnknown(operation, cause)
9286
+ });
9287
+ }
9288
+ function brandNonNullSmartAccount(wire) {
9289
+ return {
9290
+ authUserId: toAuthUserId(wire.authUserId),
9291
+ signerAddress: wire.signerAddress === null ? null : toAddress(wire.signerAddress),
9292
+ smartAccountAddress: toAddress(wire.smartAccountAddress),
9293
+ chainId: toChainId(wire.chainId),
9294
+ deployedAt: wire.deployedAt === null ? null : toEpochMs(wire.deployedAt),
9295
+ claimedAt: wire.claimedAt === null ? null : toEpochMs(wire.claimedAt),
9296
+ createdAt: toEpochMs(wire.createdAt)
9297
+ };
9298
+ }
9299
+ function brandProvisionedSmartAccount(requestedAuthUserId, wire) {
9300
+ if (wire.authUserId !== String(requestedAuthUserId)) throw Errors.notAuthenticated();
9301
+ return brandNonNullSmartAccount(wire);
9302
+ }
9303
+ function smartAccountErrorFromUnknown(operation, cause) {
9304
+ if (cause instanceof CapxulError) return smartAccountErrorFromCapxul(operation, cause);
9305
+ return smartAccountErrorFromCapxul(operation, Errors.providerError("convex", operation, cause), cause);
9306
+ }
9307
+ //#endregion
9308
+ //#region src/ports/org.ts
9309
+ var OrgError = class extends Data.TaggedError("OrgError") {};
9310
+ function orgErrorFromCapxul(operation, error, cause = error) {
9311
+ return new OrgError({
9312
+ operation,
9313
+ publicCode: error.code,
9314
+ publicError: error,
7172
9315
  cause,
7173
9316
  ...error.details === void 0 ? {} : { details: error.details }
7174
9317
  });
7175
9318
  }
7176
- var AccountReadPortTag = class extends Context.Service()("@capxul/sdk/ports/AccountReadPort") {};
9319
+ var OrgPortTag = class extends Context.Service()("@capxul/sdk/ports/OrgPort") {};
9320
+ //#endregion
9321
+ //#region src/adapters/org/parse.ts
9322
+ /**
9323
+ * Map a `WireOrg` + its (separately read) treasury `Account` into the branded
9324
+ * `OrgView`. The viewer role is projected by the authenticated backend read;
9325
+ * it must never be inferred from Organization ownership. Brands at the read
9326
+ * edge: `orgId`, `safeAddress`.
9327
+ */
9328
+ function brandOrgView(wire, treasury, viewerRole) {
9329
+ return {
9330
+ id: toOrgId(wire.orgId),
9331
+ ...wire.creationSource === void 0 ? {} : { creationSource: toTesterKind(wire.creationSource) },
9332
+ name: wire.name,
9333
+ handle: wire.handle,
9334
+ safeAddress: toAddress(wire.safeAddress.toLowerCase()),
9335
+ role: viewerRole,
9336
+ treasury,
9337
+ bio: wire.bio ?? null,
9338
+ size: wire.size ?? null,
9339
+ logoUrl: wire.logoUrl ?? null
9340
+ };
9341
+ }
9342
+ /**
9343
+ * Build the Org treasury `Account` from the raw on-chain `balanceOf` integer
9344
+ * (the D3 RPC read). `available === balance` for a treasury with no envelope
9345
+ * partition yet (a fresh Org reads back $0).
9346
+ */
9347
+ function brandOrgTreasury(input) {
9348
+ return {
9349
+ id: toAccountId(`account_${orgIdBody(input.orgId)}`),
9350
+ balance: input.money,
9351
+ available: input.money
9352
+ };
9353
+ }
9354
+ function brandOrgRole(wire) {
9355
+ return {
9356
+ orgId: toOrgId(wire.orgId),
9357
+ label: wire.label,
9358
+ roleKey: toRoleKey(wire.roleKey),
9359
+ definition: parseRoleDefinition(wire.definitionJson)
9360
+ };
9361
+ }
9362
+ function brandOrgMember(wire) {
9363
+ return {
9364
+ orgId: toOrgId(wire.orgId),
9365
+ email: toEmail(wire.email),
9366
+ name: wire.name,
9367
+ personalSafeAddress: wire.personalSafeAddress === null ? null : toAddress(wire.personalSafeAddress),
9368
+ role: wire.role,
9369
+ roleKey: wire.roleKey === null ? null : toRoleKey(wire.roleKey),
9370
+ status: wire.status,
9371
+ grantTxHash: wire.grantTxHash,
9372
+ revokeTxHash: wire.revokeTxHash
9373
+ };
9374
+ }
9375
+ function parseRoleDefinition(json) {
9376
+ let raw;
9377
+ try {
9378
+ const parsed = JSON.parse(json);
9379
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) throw new Error("expected object");
9380
+ raw = parsed;
9381
+ } catch (err) {
9382
+ throw new Error(`Invalid role definition: malformed JSON - ${err instanceof Error ? err.message : String(err)}`, { cause: err });
9383
+ }
9384
+ if (typeof raw.label !== "string" || raw.label.trim().length === 0) throw new Error("Invalid role definition: missing label");
9385
+ return {
9386
+ label: raw.label,
9387
+ ...raw.spend === void 0 ? {} : { spend: {
9388
+ ...raw.spend.perTx === void 0 ? {} : { perTx: parseRoleMoney(raw.spend.perTx, "perTx") },
9389
+ ...raw.spend.perDay === void 0 ? {} : { perDay: parseRoleMoney(raw.spend.perDay, "perDay") },
9390
+ ...raw.spend.toRecipients === void 0 ? {} : { toRecipients: parseRoleRecipients(raw.spend.toRecipients) }
9391
+ } },
9392
+ ...typeof raw.canSpend === "boolean" ? { canSpend: raw.canSpend } : {},
9393
+ ...typeof raw.canManageMembers === "boolean" ? { canManageMembers: raw.canManageMembers } : {},
9394
+ ...typeof raw.canManageRoles === "boolean" ? { canManageRoles: raw.canManageRoles } : {}
9395
+ };
9396
+ }
9397
+ function parseRoleMoney(raw, field) {
9398
+ if (typeof raw.currency !== "string" || typeof raw.value !== "string" || !/^\d+$/.test(raw.value) || raw.decimals !== 6) throw new Error(`Invalid role money: ${field}`);
9399
+ return {
9400
+ currency: toCurrencyCode(raw.currency),
9401
+ value: raw.value,
9402
+ decimals: raw.decimals
9403
+ };
9404
+ }
9405
+ function parseRoleRecipients(raw) {
9406
+ if (raw === "anyone") return "anyone";
9407
+ if (!Array.isArray(raw)) throw new Error("Invalid role definition: toRecipients must be \"anyone\" or an array");
9408
+ return raw.map((recipient) => {
9409
+ if (typeof recipient !== "string") throw new Error("Invalid role definition: toRecipients must be \"anyone\" or an array");
9410
+ return toAddress(recipient);
9411
+ });
9412
+ }
9413
+ /** Strip the `org_` prefix + non-alphanumerics so the body re-seeds `account_`. */
9414
+ function orgIdBody(orgId) {
9415
+ const underscore = orgId.indexOf("_");
9416
+ const cleaned = (underscore < 0 ? orgId : orgId.slice(underscore + 1)).replace(/[^0-9A-Za-z]/g, "");
9417
+ return cleaned.length > 0 ? cleaned : "0";
9418
+ }
9419
+ //#endregion
9420
+ //#region src/adapters/org/ConvexOrganizationAdapter.ts
9421
+ const DEFAULT_FUNCTIONS$1 = {
9422
+ listAll: makeFunctionReference(CAPXUL_FUNCTIONS["org/queries"].listAll),
9423
+ listRoles: makeFunctionReference(CAPXUL_FUNCTIONS["org/queries"].listRolesByOrgId),
9424
+ listMembers: makeFunctionReference(CAPXUL_FUNCTIONS["org/queries"].listMembersByOrgId),
9425
+ readTreasury: makeFunctionReference(CAPXUL_FUNCTIONS["org/actions"].readTreasury),
9426
+ inviteMember: makeFunctionReference(CAPXUL_FUNCTIONS["org/actions"].inviteMember),
9427
+ resendInvite: makeFunctionReference(CAPXUL_FUNCTIONS["org/mutations"].resendInviteToken),
9428
+ detectInvitations: makeFunctionReference(CAPXUL_FUNCTIONS["org/actions"].detectAndAcceptPendingInvitations)
9429
+ };
9430
+ /**
9431
+ * Standard production Organization read adapter. It intentionally has no
9432
+ * deployer/RPC/test configuration: authenticated Convex actions own live chain
9433
+ * reads, while the lifecycle adapter owns the single sponsored bootstrap.
9434
+ */
9435
+ var ConvexOrganizationAdapter = class {
9436
+ #convex;
9437
+ #fns;
9438
+ #telemetry;
9439
+ constructor(input) {
9440
+ this.#convex = input.convex;
9441
+ this.#fns = input.functions ?? DEFAULT_FUNCTIONS$1;
9442
+ this.#telemetry = input.telemetry;
9443
+ }
9444
+ createOrg(_input) {
9445
+ return Effect.fail(orgErrorFromCapxul("createOrg", Errors.notImplemented("organizationSetup", "use onboarding.completeOrganization")));
9446
+ }
9447
+ listOrgs(input) {
9448
+ return this.#convex.query(this.#fns.listAll, copyInvocationObservation(input, {})).pipe(Effect.mapError((error) => orgErrorFromCapxul("listOrgs", error.publicError, error)), Effect.flatMap((wires) => Effect.forEach(wires, (wire) => this.#readTreasuryWire(copyInvocationObservation(input, { orgId: toOrgId(wire.orgId) })).pipe(Effect.map((treasury) => {
9449
+ const viewerRole = wire.viewerRole.trim();
9450
+ if (viewerRole.length === 0) throw Errors.wrongState({
9451
+ method: "listOrgs",
9452
+ currentState: "viewerRoleMissing",
9453
+ validStates: ["activeViewerRole"]
9454
+ });
9455
+ return brandOrgView(wire, treasury, viewerRole);
9456
+ })))), Effect.catchDefect((cause) => Effect.fail(toOrgError("listOrgs", cause))));
9457
+ }
9458
+ readTreasury(input) {
9459
+ return this.#readTreasuryWire(input).pipe(Effect.catchDefect((cause) => Effect.fail(toOrgError("readTreasury", cause))));
9460
+ }
9461
+ listRoles(input) {
9462
+ return this.#convex.query(this.#fns.listRoles, { orgId: input.orgId }).pipe(Effect.mapError((error) => orgErrorFromCapxul("listRoles", error.publicError, error)), Effect.flatMap((rows) => rows.length === 0 ? Effect.fail(partialOrgTruth("listRoles", "activeRoleMissing")) : Effect.succeed(rows.map(brandOrgRole))), Effect.catchDefect((cause) => Effect.fail(toOrgError("listRoles", cause))));
9463
+ }
9464
+ listMembers(input) {
9465
+ return this.#convex.query(this.#fns.listMembers, { orgId: input.orgId }).pipe(Effect.mapError((error) => orgErrorFromCapxul("listMembers", error.publicError, error)), Effect.flatMap((rows) => rows.length === 0 ? Effect.fail(partialOrgTruth("listMembers", "activeMemberMissing")) : Effect.succeed(rows.map(brandOrgMember))), Effect.catchDefect((cause) => Effect.fail(toOrgError("listMembers", cause))));
9466
+ }
9467
+ pendingMembers(input) {
9468
+ return this.listMembers(input).pipe(Effect.map((members) => members.filter((member) => member.status === "pending" || member.status === "pending_safe" || member.status === "pending_grant")));
9469
+ }
9470
+ inviteMember(input) {
9471
+ return this.#convex.action(this.#fns.inviteMember, {
9472
+ orgId: input.orgId,
9473
+ email: input.input.email,
9474
+ role: input.input.role
9475
+ }).pipe(Effect.mapError((error) => orgErrorFromCapxul("inviteMember", error.publicError, error)), Effect.map(brandOrgMember), Effect.catchDefect((cause) => Effect.fail(toOrgError("inviteMember", cause))));
9476
+ }
9477
+ resendInviteToken(input) {
9478
+ return this.#convex.mutation(this.#fns.resendInvite, {
9479
+ orgId: input.orgId,
9480
+ email: input.email
9481
+ }).pipe(Effect.mapError((error) => orgErrorFromCapxul("resendInviteToken", error.publicError, error)), Effect.map(brandOrgMember), Effect.catchDefect((cause) => Effect.fail(toOrgError("resendInviteToken", cause))));
9482
+ }
9483
+ detectAndAcceptPendingInvitations(_input) {
9484
+ return this.#convex.action(this.#fns.detectInvitations, {}).pipe(Effect.mapError((error) => orgErrorFromCapxul("detectAndAcceptPendingInvitations", error.publicError, error)), Effect.map((result) => ({ matched: result.matched.map(toOrgId) })), Effect.catchDefect((cause) => Effect.fail(toOrgError("detectAndAcceptPendingInvitations", cause))));
9485
+ }
9486
+ #readTreasuryWire(input) {
9487
+ const orgId = String(input.orgId);
9488
+ return retryIdempotentRead(this.#convex.action(this.#fns.readTreasury, copyInvocationObservation(input, { orgId })), CAPXUL_OPERATIONS.org.treasury, this.#telemetry, input).pipe(Effect.mapError((error) => orgErrorFromCapxul("readTreasury", error.publicError, error)), Effect.map((wire) => {
9489
+ if (wire.orgId !== orgId) throw Errors.invalidInput("orgId", "Organization treasury scope does not match");
9490
+ const balance = fromWei(wire.rawBalance, wire.decimals, wire.currency);
9491
+ const available = fromWei(wire.rawAvailableBalance, wire.decimals, wire.currency);
9492
+ return {
9493
+ ...brandOrgTreasury({
9494
+ orgId: wire.orgId,
9495
+ money: balance
9496
+ }),
9497
+ available
9498
+ };
9499
+ }));
9500
+ }
9501
+ };
9502
+ function toOrgError(operation, cause) {
9503
+ if (cause instanceof CapxulError) return orgErrorFromCapxul(operation, cause);
9504
+ return orgErrorFromCapxul(operation, Errors.providerError("convex", operation, cause), cause);
9505
+ }
9506
+ function partialOrgTruth(operation, currentState) {
9507
+ return orgErrorFromCapxul(operation, Errors.wrongState({
9508
+ method: operation,
9509
+ currentState,
9510
+ validStates: ["completeProductionOrganizationTruth"]
9511
+ }));
9512
+ }
9513
+ //#endregion
9514
+ //#region src/adapters/org/ConvexOrganizationSetupAdapter.ts
9515
+ const DEFAULT_FUNCTIONS = {
9516
+ startOrResume: makeFunctionReference(CAPXUL_FUNCTIONS["org/lifecycle"].startOrResume),
9517
+ prepareFounderAccount: makeFunctionReference(CAPXUL_FUNCTIONS["org/actions"].prepareFounderAccount),
9518
+ prepareBootstrap: makeFunctionReference(CAPXUL_FUNCTIONS["org/actions"].prepareBootstrap),
9519
+ submitBootstrap: makeFunctionReference(CAPXUL_FUNCTIONS["org/actions"].submitBootstrap),
9520
+ resumeBootstrapSubmission: makeFunctionReference(CAPXUL_FUNCTIONS["org/actions"].resumeBootstrapSubmission),
9521
+ confirmBootstrap: makeFunctionReference(CAPXUL_FUNCTIONS["org/actions"].confirmBootstrap),
9522
+ recordFailure: makeFunctionReference(CAPXUL_FUNCTIONS["org/lifecycle"].recordFailure),
9523
+ load: makeFunctionReference(CAPXUL_FUNCTIONS["org/lifecycle"].load),
9524
+ retry: makeFunctionReference(CAPXUL_FUNCTIONS["org/lifecycle"].retry)
9525
+ };
9526
+ /** Durable Organization setup capability composed by the standard client. */
9527
+ var ConvexOrganizationSetupAdapter = class {
9528
+ #convex;
9529
+ #signer;
9530
+ #chainId;
9531
+ #fns;
9532
+ constructor(input) {
9533
+ this.#convex = input.convex;
9534
+ this.#signer = input.signer;
9535
+ this.#chainId = input.chainId;
9536
+ this.#fns = input.functions ?? DEFAULT_FUNCTIONS;
9537
+ }
9538
+ async startOrResume(input) {
9539
+ const result = await runCall("startOrResume", this.#convex.mutation(this.#fns.startOrResume, copyInvocationObservation(input, {
9540
+ ...input,
9541
+ chainId: this.#chainId
9542
+ })));
9543
+ if (!result.ok) return result;
9544
+ const lifecycle = parseLifecycle("startOrResume", result.value.lifecycle);
9545
+ if (!lifecycle.ok) return lifecycle;
9546
+ const orgId = parseOrgId("startOrResume", result.value.orgId);
9547
+ if (!orgId.ok) return orgId;
9548
+ if (String(orgId.value) !== String(lifecycle.value.orgId)) return fail$1(Errors.invalidInput("orgId", "Organization lifecycle scope does not match"));
9549
+ return {
9550
+ ok: true,
9551
+ value: {
9552
+ orgId: orgId.value,
9553
+ lifecycle: lifecycle.value
9554
+ }
9555
+ };
9556
+ }
9557
+ prepareFounderAccount(input) {
9558
+ return this.#lifecycleAction("prepareFounderAccount", input, () => this.#convex.action(this.#fns.prepareFounderAccount, copyInvocationObservation(input, {
9559
+ orgId: input.orgId,
9560
+ ...input.observationContext === void 0 ? {} : { observationContext: input.observationContext }
9561
+ })));
9562
+ }
9563
+ async authorizeAndSubmitBootstrap(input) {
9564
+ const cancelled = cancellation(input.signal);
9565
+ if (cancelled !== void 0) return cancelled;
9566
+ const signerAddress = await signerResult(this.#signer.source, "getAddress", () => this.#signer.getAddress());
9567
+ if (!signerAddress.ok) return signerAddress;
9568
+ const prepared = await runCall("prepareBootstrap", this.#convex.action(this.#fns.prepareBootstrap, copyInvocationObservation(input, {
9569
+ orgId: input.orgId,
9570
+ signerAddress: signerAddress.value,
9571
+ ...input.observationContext === void 0 ? {} : { observationContext: input.observationContext }
9572
+ })));
9573
+ if (!prepared.ok) return prepared;
9574
+ const authority = validatePreparedAuthorities(prepared.value, signerAddress.value);
9575
+ if (!authority.ok) return authority;
9576
+ const cancelledAfterPrepare = cancellation(input.signal);
9577
+ if (cancelledAfterPrepare !== void 0) return cancelledAfterPrepare;
9578
+ const signature = await signerResult(this.#signer.source, "signUserOpHash", () => this.#signer.signUserOpHash(prepared.value.digest));
9579
+ if (!signature.ok) return signature;
9580
+ const cancelledAfterSign = cancellation(input.signal);
9581
+ if (cancelledAfterSign !== void 0) return cancelledAfterSign;
9582
+ const submitted = await runCall("submitBootstrap", this.#convex.action(this.#fns.submitBootstrap, copyInvocationObservation(input, {
9583
+ orgId: input.orgId,
9584
+ signerAddress: signerAddress.value,
9585
+ signature: signature.value,
9586
+ userOp: prepared.value.userOp,
9587
+ ...input.observationContext === void 0 ? {} : { observationContext: input.observationContext }
9588
+ })));
9589
+ if (!submitted.ok) return submitted;
9590
+ return parseLifecycle("submitBootstrap", submitted.value);
9591
+ }
9592
+ resumeSubmittedBootstrap(input) {
9593
+ return this.#lifecycleAction("resumeBootstrapSubmission", input, () => this.#convex.action(this.#fns.resumeBootstrapSubmission, copyInvocationObservation(input, {
9594
+ orgId: input.orgId,
9595
+ ...input.observationContext === void 0 ? {} : { observationContext: input.observationContext }
9596
+ })));
9597
+ }
9598
+ confirmSubmittedBootstrap(input) {
9599
+ return this.#lifecycleAction("confirmBootstrap", input, () => this.#convex.action(this.#fns.confirmBootstrap, copyInvocationObservation(input, {
9600
+ orgId: input.orgId,
9601
+ ...input.observationContext === void 0 ? {} : { observationContext: input.observationContext },
9602
+ ...input.retryDelayMs === void 0 ? {} : { retryDelayMs: input.retryDelayMs }
9603
+ })));
9604
+ }
9605
+ async recordFailure(input) {
9606
+ const errorProvider = input.error.details?.provider;
9607
+ const errorOperation = input.error.details?.operation;
9608
+ const result = await runCall("recordFailure", this.#convex.mutation(this.#fns.recordFailure, copyInvocationObservation(input, {
9609
+ orgId: input.orgId,
9610
+ errorCode: input.error.code,
9611
+ ...typeof errorProvider === "string" && typeof errorOperation === "string" ? {
9612
+ errorProvider,
9613
+ errorOperation
9614
+ } : {},
9615
+ retryable: input.retryable,
9616
+ ...input.observationContext === void 0 ? {} : { observationContext: input.observationContext }
9617
+ })));
9618
+ return result.ok ? parseLifecycle("recordFailure", result.value) : result;
9619
+ }
9620
+ async loadLifecycle(input) {
9621
+ const result = await runCall("loadLifecycle", this.#convex.query(this.#fns.load, input));
9622
+ if (!result.ok) return result;
9623
+ if (result.value === null) return fail$1(Errors.invalidInput("orgId", "Organization lifecycle was not found"));
9624
+ return parseLifecycle("loadLifecycle", result.value);
9625
+ }
9626
+ async retry(input) {
9627
+ const cancelled = cancellation(input.signal);
9628
+ if (cancelled !== void 0) return cancelled;
9629
+ const current = await this.loadLifecycle({
9630
+ orgId: input.orgId,
9631
+ ...input.observationContext === void 0 ? {} : { observationContext: input.observationContext }
9632
+ });
9633
+ if (!current.ok) return current;
9634
+ if (current.value.status === "failed" && current.value.retryable && (current.value.at === "awaitingFounderAuthorization" || current.value.at === "submittingBootstrap")) {
9635
+ const reset = resetSignerSession(this.#signer);
9636
+ if (!reset.ok) return reset;
9637
+ }
9638
+ const result = await runCall("retry", this.#convex.mutation(this.#fns.retry, copyInvocationObservation(input, {
9639
+ orgId: input.orgId,
9640
+ ...input.observationContext === void 0 ? {} : { observationContext: input.observationContext }
9641
+ })));
9642
+ if (!result.ok) return result;
9643
+ return parseLifecycle("retry", result.value);
9644
+ }
9645
+ async #lifecycleAction(operation, input, call) {
9646
+ const cancelled = cancellation(input.signal);
9647
+ if (cancelled !== void 0) return cancelled;
9648
+ const result = await runCall(operation, call());
9649
+ if (!result.ok) return result;
9650
+ const cancelledAfter = cancellation(input.signal);
9651
+ if (cancelledAfter !== void 0) return cancelledAfter;
9652
+ return parseLifecycle(operation, result.value);
9653
+ }
9654
+ };
9655
+ function resetSignerSession(signer) {
9656
+ const resetSession = signer.resetSession;
9657
+ if (typeof resetSession !== "function") return {
9658
+ ok: true,
9659
+ value: void 0
9660
+ };
9661
+ try {
9662
+ resetSession.call(signer);
9663
+ return {
9664
+ ok: true,
9665
+ value: void 0
9666
+ };
9667
+ } catch (cause) {
9668
+ return fail$1(signerFailure(signer.source, "resetSession", cause));
9669
+ }
9670
+ }
9671
+ async function runCall(operation, effect) {
9672
+ try {
9673
+ const result = await Effect.runPromise(Effect.result(effect));
9674
+ return Result.isSuccess(result) ? {
9675
+ ok: true,
9676
+ value: result.success
9677
+ } : fail$1(publicError(operation, result.failure));
9678
+ } catch (cause) {
9679
+ return fail$1(publicError(operation, cause));
9680
+ }
9681
+ }
9682
+ function publicError(operation, cause) {
9683
+ if (cause instanceof CapxulError) return cause;
9684
+ if (typeof cause === "object" && cause !== null) {
9685
+ const carried = cause.publicError;
9686
+ if (carried instanceof CapxulError) return carried;
9687
+ }
9688
+ return Errors.providerError("convex-organization", operation, cause);
9689
+ }
9690
+ async function signerResult(source, operation, run) {
9691
+ try {
9692
+ return {
9693
+ ok: true,
9694
+ value: await run()
9695
+ };
9696
+ } catch (cause) {
9697
+ return fail$1(signerFailure(source, operation, cause));
9698
+ }
9699
+ }
9700
+ function validatePreparedAuthorities(prepared, signerAddress) {
9701
+ const signer = signerAddress.toLowerCase();
9702
+ const preparedSigner = prepared.signerAddress.toLowerCase();
9703
+ const founder = prepared.founderPersonalAccount.toLowerCase();
9704
+ const organization = prepared.organizationAccountAddress.toLowerCase();
9705
+ const sender = prepared.userOp.sender.toLowerCase();
9706
+ if (preparedSigner !== signer) return fail$1(Errors.invalidInput("signerAddress", "Prepared signer does not match configured signer"));
9707
+ if (founder === signer || organization === signer || organization === founder) return fail$1(Errors.invalidInput("organizationAuthority", "Signer EOA, founder Account, and Organization Account must be distinct"));
9708
+ if (sender !== founder) return fail$1(Errors.invalidInput("userOp.sender", "Bootstrap sender must be the founder Account"));
9709
+ if (!/^0x[0-9a-fA-F]{64}$/u.test(prepared.digest)) return fail$1(Errors.invalidInput("digest", "Prepared bootstrap digest must be 32-byte hex"));
9710
+ return {
9711
+ ok: true,
9712
+ value: void 0
9713
+ };
9714
+ }
9715
+ function parseLifecycle(operation, wire) {
9716
+ const orgId = parseOrgId(operation, wire.orgId);
9717
+ if (!orgId.ok) return orgId;
9718
+ if (wire.status === "loading") return {
9719
+ ok: true,
9720
+ value: {
9721
+ status: "loading",
9722
+ orgId: orgId.value
9723
+ }
9724
+ };
9725
+ if (wire.status === "ready") return {
9726
+ ok: true,
9727
+ value: {
9728
+ status: "ready",
9729
+ orgId: orgId.value,
9730
+ canTransact: true
9731
+ }
9732
+ };
9733
+ if (wire.status === "failed") {
9734
+ if (!isSetupStep(wire.at)) return fail$1(Errors.invalidInput("lifecycle.at", "Unknown setup step"));
9735
+ return {
9736
+ ok: true,
9737
+ value: {
9738
+ status: "failed",
9739
+ orgId: orgId.value,
9740
+ at: wire.at,
9741
+ error: new CapxulError(wire.error.code, wire.error.message),
9742
+ retryable: wire.retryable
9743
+ }
9744
+ };
9745
+ }
9746
+ if (!isSetupStep(wire.step)) return fail$1(Errors.invalidInput("lifecycle.step", `Unknown setup step from ${operation}`));
9747
+ return {
9748
+ ok: true,
9749
+ value: {
9750
+ status: "settingUp",
9751
+ orgId: orgId.value,
9752
+ step: wire.step
9753
+ }
9754
+ };
9755
+ }
9756
+ function parseOrgId(operation, value) {
9757
+ try {
9758
+ return {
9759
+ ok: true,
9760
+ value: toOrgId(value)
9761
+ };
9762
+ } catch (cause) {
9763
+ return fail$1(Errors.providerError("convex-organization", operation, cause));
9764
+ }
9765
+ }
9766
+ function isSetupStep(value) {
9767
+ return value === "preparingFounderAccount" || value === "awaitingFounderAuthorization" || value === "submittingBootstrap" || value === "confirmingBootstrap";
9768
+ }
9769
+ function cancellation(signal) {
9770
+ return signal?.aborted ? fail$1(Errors.cancelled({ operation: CAPXUL_OPERATIONS.organization.setup })) : void 0;
9771
+ }
9772
+ function fail$1(error) {
9773
+ return {
9774
+ ok: false,
9775
+ error
9776
+ };
9777
+ }
7177
9778
  //#endregion
7178
- //#region src/ports/smart-account.ts
7179
- var SmartAccountError = class extends Data.TaggedError("SmartAccountError") {};
7180
- function smartAccountErrorFromCapxul(operation, error, cause = error) {
7181
- return new SmartAccountError({
7182
- operation,
7183
- publicCode: error.code,
7184
- publicError: error,
7185
- cause,
7186
- ...error.details === void 0 ? {} : { details: error.details }
9779
+ //#region src/adapters/telemetry/PostHogTelemetryAdapter.ts
9780
+ var PostHogTelemetryAdapter = class {
9781
+ #capture;
9782
+ #identify;
9783
+ #group;
9784
+ #reset;
9785
+ constructor(deps) {
9786
+ this.#capture = deps.capture;
9787
+ this.#identify = deps.identify ?? (() => void 0);
9788
+ this.#group = deps.group ?? (() => void 0);
9789
+ this.#reset = deps.reset ?? (() => void 0);
9790
+ }
9791
+ emit(event) {
9792
+ return this.#run(() => this.#capture(event.name, redactTelemetryProps(event.name, cloneProps(event.props)), event), "emit", event.name);
9793
+ }
9794
+ identify(input) {
9795
+ return this.#run(() => this.#identify(cloneIdentifyInput(input)), "identify");
9796
+ }
9797
+ group(input) {
9798
+ return this.#run(() => this.#group(cloneGroupInput(input)), "group");
9799
+ }
9800
+ reset() {
9801
+ return this.#run(() => this.#reset(), "reset");
9802
+ }
9803
+ #run(operation, operationName, eventName) {
9804
+ const diagnose = Effect.logWarning("product.telemetry.transport.dropped").pipe(Effect.annotateLogs({
9805
+ operation: operationName,
9806
+ ...eventName === void 0 ? {} : { product_event: eventName }
9807
+ }), Effect.catchCause(() => Effect.void));
9808
+ return Effect.suspend(() => {
9809
+ let pending;
9810
+ try {
9811
+ pending = operation();
9812
+ } catch {
9813
+ return diagnose;
9814
+ }
9815
+ if (pending === void 0) return Effect.void;
9816
+ const transport = Effect.tryPromise({
9817
+ try: () => pending,
9818
+ catch: () => void 0
9819
+ }).pipe(Effect.catch(() => diagnose));
9820
+ return Effect.forkDetach(transport, { startImmediately: true }).pipe(Effect.asVoid);
9821
+ });
9822
+ }
9823
+ };
9824
+ function PostHogTelemetryLayer(deps) {
9825
+ return Layer.succeed(TelemetryPortTag, new PostHogTelemetryAdapter(deps));
9826
+ }
9827
+ function cloneIdentifyInput(input) {
9828
+ const traits = input.traits === void 0 ? void 0 : cloneProps(input.traits);
9829
+ const properties = input.properties === void 0 ? void 0 : cloneProps(input.properties);
9830
+ return {
9831
+ distinctId: input.distinctId,
9832
+ ...input.anonDistinctId === void 0 ? {} : { anonDistinctId: input.anonDistinctId },
9833
+ ...traits === void 0 ? {} : { traits },
9834
+ ...properties === void 0 ? {} : { properties }
9835
+ };
9836
+ }
9837
+ function cloneGroupInput(input) {
9838
+ const properties = input.properties === void 0 ? void 0 : cloneProps(input.properties);
9839
+ return properties === void 0 ? {
9840
+ groupType: input.groupType,
9841
+ groupKey: input.groupKey
9842
+ } : {
9843
+ groupType: input.groupType,
9844
+ groupKey: input.groupKey,
9845
+ properties
9846
+ };
9847
+ }
9848
+ function cloneProps(props) {
9849
+ if (props === void 0) return void 0;
9850
+ const cloned = {};
9851
+ for (const [key, value] of Object.entries(props)) cloned[key] = cloneTelemetryValue(value);
9852
+ return cloned;
9853
+ }
9854
+ function cloneTelemetryValue(value) {
9855
+ if (Array.isArray(value)) return value.map(cloneTelemetryValue);
9856
+ if (value === null || typeof value !== "object") return value;
9857
+ if (Object.getPrototypeOf(value) !== Object.prototype) return value;
9858
+ const cloned = {};
9859
+ for (const [key, nested] of Object.entries(value)) cloned[key] = cloneTelemetryValue(nested);
9860
+ return cloned;
9861
+ }
9862
+ //#endregion
9863
+ //#region src/adapters/diagnostic/ConsoleDiagnosticAdapter.ts
9864
+ const DEFAULT_ACCOUNT_SETUP_LOG_PREFIX = "[capxul:account-setup]";
9865
+ var ConsoleDiagnosticAdapter = class {
9866
+ prefix;
9867
+ constructor(prefix = DEFAULT_ACCOUNT_SETUP_LOG_PREFIX) {
9868
+ this.prefix = prefix;
9869
+ }
9870
+ trace(scope, detail) {
9871
+ globalThis.console?.debug?.(`${this.prefix} ${scope}`, detail);
9872
+ }
9873
+ };
9874
+ //#endregion
9875
+ //#region src/openfort/create-openfort-browser-signer.ts
9876
+ function httpStatusOf(link) {
9877
+ const carrier = link;
9878
+ if (typeof carrier.response?.status === "number") return carrier.response.status;
9879
+ if (typeof carrier.statusCode === "number") return carrier.statusCode;
9880
+ if (typeof carrier.status === "number") return carrier.status;
9881
+ }
9882
+ function isUnauthorizedCause(cause) {
9883
+ for (const link of causeChain(cause)) if (httpStatusOf(link) === 401) return true;
9884
+ return false;
9885
+ }
9886
+ function openfortProviderError(operation, cause) {
9887
+ if (cause instanceof CapxulError) return cause;
9888
+ const failure_mode = operation === "configure" && isUnauthorizedCause(cause) ? "unauthorized" : "unknown";
9889
+ return Errors.providerError("openfort", operation, cause, { failure_mode });
9890
+ }
9891
+ function openfortFailureMode(error) {
9892
+ return error.mode ?? "unknown";
9893
+ }
9894
+ /** Build a named PROVIDER_ERROR. The assembled Core SDK boundary reports it. */
9895
+ function failOpenfort(operation, failure_mode, cause) {
9896
+ return Errors.providerError("openfort", operation, cause, { failure_mode });
9897
+ }
9898
+ /**
9899
+ * True when the browser cannot perform Web Crypto — sandboxed iframes, headless
9900
+ * agent browsers, or non-HTTPS origins. OpenFort's embedded-wallet `configure`
9901
+ * silently produces no address in this state, so we detect it up front and name
9902
+ * it `no-secure-context` instead of letting it decay into `unknown`.
9903
+ */
9904
+ function isInsecureBrowserContext() {
9905
+ return globalThis.isSecureContext === false || globalThis.crypto?.subtle === void 0;
9906
+ }
9907
+ /** Openfort SDK storage keys (`@openfort/openfort-js` StorageKeys). */
9908
+ const OPENFORT_BROWSER_STORAGE_KEYS = [
9909
+ "openfort.authentication",
9910
+ "openfort.account",
9911
+ "openfort.session",
9912
+ "openfort.configuration"
9913
+ ];
9914
+ /**
9915
+ * Matches `@openfort/openfort-js` ScopedStorage.createScope — chars 8–15 of the
9916
+ * publishable key, prefixed onto each StorageKeys entry in localStorage.
9917
+ */
9918
+ function openfortBrowserStorageScope(publishableKey) {
9919
+ const trimmed = publishableKey.trim();
9920
+ if (trimmed.length < 16) return;
9921
+ return trimmed.substring(8, 16);
9922
+ }
9923
+ /**
9924
+ * Drop cached Openfort auth/account state so third-party login re-runs for the
9925
+ * current Better Auth session. The SDK skips `authenticateThirdParty` when a
9926
+ * stale `userId` is already in storage, which yields 401 on `v2/accounts`.
9927
+ */
9928
+ function clearStaleOpenfortBrowserStorage(publishableKey) {
9929
+ if (typeof localStorage === "undefined") return;
9930
+ const scope = openfortBrowserStorageScope(publishableKey);
9931
+ if (scope === void 0) return;
9932
+ for (const key of OPENFORT_BROWSER_STORAGE_KEYS) localStorage.removeItem(`${scope}.${key}`);
9933
+ }
9934
+ /**
9935
+ * The Openfort error code that names the stale-user class (#1435).
9936
+ * `getThirdPartyAuthToken` skips `authenticateThirdParty` while a `userId` sits
9937
+ * in scoped storage. A purged `userId` therefore pins every later call to a 401
9938
+ * that `extractApiError` reports as `USER_NOT_FOUND`.
9939
+ *
9940
+ * The set holds one member on purpose. Session-expiry codes (`SESSION_EXPIRED`,
9941
+ * `NOT_LOGGED_IN`, `INVALID_TOKEN`, `REFRESH_TOKEN_ERROR`) are a different
9942
+ * cause, and a bare 401 is a different cause again: `app-env-allowlist` is a
9943
+ * 401 by definition (`packages/errors/src/errors.ts:80-81`). Healing those and
9944
+ * tagging them `stale-openfort-cache` would delete the triage signal the tag
9945
+ * exists to carry.
9946
+ */
9947
+ const STALE_USER_ERROR_CODES = /* @__PURE__ */ new Set(["USER_NOT_FOUND"]);
9948
+ /**
9949
+ * The one predicate that opens the heal. It reads the Openfort error code and
9950
+ * never the message text (ADR-0023 R4). It walks the cause chain the way
9951
+ * `isTransportError` walks it in the Convex transport adapter.
9952
+ *
9953
+ * Known ceiling (#1435): a 401 that carries no recognized code is NOT healed.
9954
+ * `extractApiError` keeps the status only on `AuthenticationError`, so such a
9955
+ * payload is reachable. Add the code a live payload shows; do not add a message
9956
+ * match, because that trades one bug class for an ADR-0023 R4 violation.
9957
+ */
9958
+ function isStaleUserSignal(cause) {
9959
+ for (const link of causeChain(cause)) {
9960
+ const error = link;
9961
+ if (typeof error.error === "string" && STALE_USER_ERROR_CODES.has(error.error) || typeof error.code === "string" && STALE_USER_ERROR_CODES.has(error.code)) return true;
9962
+ }
9963
+ return false;
9964
+ }
9965
+ function createOpenfortBrowserSignerFromBootstrap(bootstrap, options = {}) {
9966
+ const diagnostic = options.diagnostic;
9967
+ const authBaseUrl = normalizeBetterAuthBaseUrl(bootstrap.authBaseUrl);
9968
+ let currentStatus = "unknown";
9969
+ const statusListeners = /* @__PURE__ */ new Set();
9970
+ function setStatus(next) {
9971
+ if (currentStatus === next) return;
9972
+ currentStatus = next;
9973
+ for (const listener of statusListeners) try {
9974
+ listener(next);
9975
+ } catch {
9976
+ statusListeners.delete(listener);
9977
+ diagnostic?.trace("openfort.signerStatusListener", {
9978
+ ok: false,
9979
+ failure_mode: "unknown"
9980
+ });
9981
+ }
9982
+ }
9983
+ const statusStore = {
9984
+ status: () => currentStatus,
9985
+ subscribe: (listener) => {
9986
+ statusListeners.add(listener);
9987
+ return () => {
9988
+ statusListeners.delete(listener);
9989
+ };
9990
+ }
9991
+ };
9992
+ /**
9993
+ * Closes the black hole: when the browser has no Web Crypto, OpenFort's
9994
+ * `configure` would resolve to no address and the failure would be reported
9995
+ * as `unknown`. Detect it before any network or wallet work. Tag it
9996
+ * `no-secure-context` on a PROVIDER_ERROR scoped to `configure`. Add a
9997
+ * DiagnosticPort breadcrumb. The assembled Core SDK boundary reports it.
9998
+ */
9999
+ function failNoSecureContext() {
10000
+ diagnostic?.trace("openfort.configure", {
10001
+ ok: false,
10002
+ failure_mode: "no-secure-context"
10003
+ });
10004
+ throw failOpenfort("configure", "no-secure-context", /* @__PURE__ */ new Error("Web Crypto unavailable: browser is not a secure context"));
10005
+ }
10006
+ function betterAuthSessionUrl() {
10007
+ return `${authBaseUrl}/get-session`;
10008
+ }
10009
+ function encryptionSessionUrl() {
10010
+ return `${authBaseUrl}/encryption-session`;
10011
+ }
10012
+ async function fetchBetterAuthAccessToken() {
10013
+ try {
10014
+ const response = await fetch(betterAuthSessionUrl(), { credentials: "include" });
10015
+ if (!response.ok) {
10016
+ diagnostic?.trace("openfort.token", {
10017
+ ok: false,
10018
+ tokenPresent: false,
10019
+ httpStatus: response.status,
10020
+ failure_mode: "unknown"
10021
+ });
10022
+ return null;
10023
+ }
10024
+ const token = (await response.json()).session?.token?.trim();
10025
+ if (token === void 0 || token.length === 0) {
10026
+ diagnostic?.trace("openfort.token", {
10027
+ ok: false,
10028
+ tokenPresent: false,
10029
+ failure_mode: "unknown"
10030
+ });
10031
+ return null;
10032
+ }
10033
+ diagnostic?.trace("openfort.token", {
10034
+ ok: true,
10035
+ tokenPresent: true
10036
+ });
10037
+ return token;
10038
+ } catch (cause) {
10039
+ diagnostic?.trace("openfort.token", {
10040
+ ok: false,
10041
+ tokenPresent: false,
10042
+ failure_mode: "unknown"
10043
+ });
10044
+ throw openfortProviderError("token", cause);
10045
+ }
10046
+ }
10047
+ const openfort = new Openfort({
10048
+ baseConfiguration: { publishableKey: bootstrap.openfortPublishableKey },
10049
+ shieldConfiguration: { shieldPublishableKey: bootstrap.shieldPublishableKey },
10050
+ thirdPartyAuth: {
10051
+ provider: ThirdPartyOAuthProvider.BETTER_AUTH,
10052
+ getAccessToken: fetchBetterAuthAccessToken
10053
+ }
10054
+ });
10055
+ async function configureEmbeddedWallet(encryptionSession) {
10056
+ await openfort.embeddedWallet.configure({
10057
+ accountType: AccountTypeEnum.EOA,
10058
+ chainType: ChainTypeEnum.EVM,
10059
+ recoveryParams: {
10060
+ recoveryMethod: RecoveryMethod.AUTOMATIC,
10061
+ encryptionSession
10062
+ }
10063
+ });
10064
+ }
10065
+ /**
10066
+ * ONE heal cycle on the stale-user rejection (#1435). Clear the scoped
10067
+ * storage that pins the dead `userId`, run the existing configure path — it
10068
+ * re-runs third-party auth against the live Better Auth session now that no
10069
+ * `userId` is cached — and retry the read once. Exactly one cycle: a second
10070
+ * rejection is terminal and carries `failure_mode: "stale-openfort-cache"`.
10071
+ * The caller stays in `recovering` throughout; only the outcome moves it.
10072
+ */
10073
+ async function healStaleOpenfortCache(encryptionSession) {
10074
+ try {
10075
+ clearStaleOpenfortBrowserStorage(bootstrap.openfortPublishableKey);
10076
+ diagnostic?.trace("openfort.storageCleared", { beforeConfigure: false });
10077
+ await configureEmbeddedWallet(encryptionSession);
10078
+ await openfort.embeddedWallet.get();
10079
+ } catch (cause) {
10080
+ diagnostic?.trace("openfort.staleCacheHeal", {
10081
+ ok: false,
10082
+ failure_mode: "stale-openfort-cache"
10083
+ });
10084
+ throw failOpenfort("get", "stale-openfort-cache", cause);
10085
+ }
10086
+ diagnostic?.trace("openfort.staleCacheHeal", { ok: true });
10087
+ }
10088
+ let walletReadyPromise = null;
10089
+ function startWalletReady() {
10090
+ return (async () => {
10091
+ if (isInsecureBrowserContext()) failNoSecureContext();
10092
+ await openfort.waitForInitialization();
10093
+ const accessToken = await fetchBetterAuthAccessToken();
10094
+ if (accessToken === null) throw openfortProviderError("token", /* @__PURE__ */ new Error("Better Auth access token unavailable for Openfort"));
10095
+ let encryptionResponse;
10096
+ try {
10097
+ encryptionResponse = await fetch(encryptionSessionUrl(), {
10098
+ method: "POST",
10099
+ credentials: "include",
10100
+ headers: {
10101
+ Authorization: `Bearer ${accessToken}`,
10102
+ "Content-Type": "application/json"
10103
+ },
10104
+ body: JSON.stringify({})
10105
+ });
10106
+ } catch (cause) {
10107
+ diagnostic?.trace("openfort.encryptionSession", {
10108
+ ok: false,
10109
+ failure_mode: "unknown"
10110
+ });
10111
+ throw openfortProviderError("encryptionSession", cause);
10112
+ }
10113
+ if (!encryptionResponse.ok) {
10114
+ diagnostic?.trace("openfort.encryptionSession", {
10115
+ ok: false,
10116
+ httpStatus: encryptionResponse.status,
10117
+ failure_mode: "unknown"
10118
+ });
10119
+ throw Errors.providerError("openfort", "encryptionSession", /* @__PURE__ */ new Error(`Openfort encryption session failed (${encryptionResponse.status})`), { failure_mode: "unknown" });
10120
+ }
10121
+ let encryptionBody;
10122
+ try {
10123
+ encryptionBody = await encryptionResponse.json();
10124
+ if (typeof encryptionBody.sessionId !== "string" || encryptionBody.sessionId.length === 0) throw new Error("Openfort encryption session response missing sessionId");
10125
+ } catch (cause) {
10126
+ diagnostic?.trace("openfort.encryptionSession", {
10127
+ ok: false,
10128
+ httpStatus: encryptionResponse.status,
10129
+ failure_mode: "unknown"
10130
+ });
10131
+ throw openfortProviderError("encryptionSession", cause);
10132
+ }
10133
+ diagnostic?.trace("openfort.encryptionSession", {
10134
+ ok: true,
10135
+ httpStatus: encryptionResponse.status
10136
+ });
10137
+ let embeddedState;
10138
+ try {
10139
+ embeddedState = await openfort.embeddedWallet.getEmbeddedState();
10140
+ diagnostic?.trace("openfort.embeddedState", { state: embeddedState });
10141
+ } catch (cause) {
10142
+ diagnostic?.trace("openfort.embeddedState", {
10143
+ ok: false,
10144
+ failure_mode: "unknown"
10145
+ });
10146
+ throw openfortProviderError("embeddedState", cause);
10147
+ }
10148
+ if (embeddedState !== EmbeddedState.READY) {
10149
+ clearStaleOpenfortBrowserStorage(bootstrap.openfortPublishableKey);
10150
+ diagnostic?.trace("openfort.storageCleared", { beforeConfigure: true });
10151
+ try {
10152
+ await configureEmbeddedWallet(encryptionBody.sessionId);
10153
+ diagnostic?.trace("openfort.configure", { ok: true });
10154
+ } catch (cause) {
10155
+ const error = openfortProviderError("configure", cause);
10156
+ diagnostic?.trace("openfort.configure", {
10157
+ ok: false,
10158
+ failure_mode: openfortFailureMode(error)
10159
+ });
10160
+ throw error;
10161
+ }
10162
+ }
10163
+ try {
10164
+ await openfort.embeddedWallet.get();
10165
+ diagnostic?.trace("openfort.get", { ok: true });
10166
+ } catch (cause) {
10167
+ if (!isStaleUserSignal(cause)) {
10168
+ diagnostic?.trace("openfort.get", {
10169
+ ok: false,
10170
+ failure_mode: "unknown"
10171
+ });
10172
+ throw openfortProviderError("get", cause);
10173
+ }
10174
+ diagnostic?.trace("openfort.get", {
10175
+ ok: false,
10176
+ failure_mode: "stale-openfort-cache"
10177
+ });
10178
+ await healStaleOpenfortCache(encryptionBody.sessionId);
10179
+ }
10180
+ })();
10181
+ }
10182
+ async function ensureOpenfortWalletReady() {
10183
+ let joined = walletReadyPromise;
10184
+ if (joined === null) {
10185
+ joined = startWalletReady();
10186
+ walletReadyPromise = joined;
10187
+ setStatus("recovering");
10188
+ }
10189
+ try {
10190
+ await joined;
10191
+ if (walletReadyPromise === joined) setStatus("ready");
10192
+ } catch (cause) {
10193
+ if (walletReadyPromise === joined) {
10194
+ walletReadyPromise = null;
10195
+ setStatus("unavailable");
10196
+ }
10197
+ throw cause;
10198
+ }
10199
+ }
10200
+ const signer = openfortEmbeddedSignerFromWallet({
10201
+ embeddedWallet: openfort.embeddedWallet,
10202
+ ensureWalletReady: ensureOpenfortWalletReady
7187
10203
  });
10204
+ const controlledSign = options.signUserOpHash;
10205
+ const signEmbeddedHash = controlledSign === void 0 ? signer.signUserOpHash : (hash) => controlledSign(hash, signer.signUserOpHash);
10206
+ const resetReadiness = () => {
10207
+ walletReadyPromise = null;
10208
+ clearStaleOpenfortBrowserStorage(bootstrap.openfortPublishableKey);
10209
+ signer.resetAddressCache();
10210
+ setStatus("unknown");
10211
+ };
10212
+ const signUserOpHash = async (hash) => {
10213
+ try {
10214
+ return await signEmbeddedHash(hash);
10215
+ } catch (cause) {
10216
+ const providerErrorCode = openfortSignerNotReadyCode(cause);
10217
+ if (providerErrorCode === void 0) throw cause;
10218
+ diagnostic?.trace("openfort.signerRecovery", {
10219
+ outcome: "started",
10220
+ attempt: 1,
10221
+ failure_mode: "signer-not-ready"
10222
+ });
10223
+ resetReadiness();
10224
+ try {
10225
+ await ensureOpenfortWalletReady();
10226
+ const signature = await signEmbeddedHash(hash);
10227
+ diagnostic?.trace("openfort.signerRecovery", {
10228
+ outcome: "succeeded",
10229
+ attempt: 1,
10230
+ failure_mode: "signer-not-ready"
10231
+ });
10232
+ return signature;
10233
+ } catch (retryCause) {
10234
+ const retryFailure = signerFailure("openfort-embedded", "signUserOpHash", retryCause);
10235
+ if (retryFailure.code === "SIGNER_REJECTED") throw retryFailure;
10236
+ if (isSignerNotReadySignal(retryCause)) {
10237
+ walletReadyPromise = null;
10238
+ signer.resetAddressCache();
10239
+ setStatus("unavailable");
10240
+ }
10241
+ diagnostic?.trace("openfort.signerRecovery", {
10242
+ outcome: "failed",
10243
+ attempt: 1,
10244
+ failure_mode: isSignerNotReadySignal(retryCause) ? "signer-not-ready" : "unknown"
10245
+ });
10246
+ throw Errors.providerError("openfort", "signerRecovery", retryCause, {
10247
+ failure_mode: "signer-not-ready",
10248
+ details: {
10249
+ provider_error_source: "openfort",
10250
+ provider_error_code: providerErrorCode
10251
+ }
10252
+ });
10253
+ }
10254
+ }
10255
+ };
10256
+ return {
10257
+ ...signer,
10258
+ signUserOpHash,
10259
+ statusStore,
10260
+ ensureWalletReady: ensureOpenfortWalletReady,
10261
+ getAddress: async () => {
10262
+ try {
10263
+ const address = await signer.getAddress();
10264
+ diagnostic?.trace("openfort.address", { ok: true });
10265
+ return address;
10266
+ } catch (cause) {
10267
+ diagnostic?.trace("openfort.address", {
10268
+ ok: false,
10269
+ failure_mode: "unknown"
10270
+ });
10271
+ throw openfortProviderError("getAddress", cause);
10272
+ }
10273
+ },
10274
+ resetSession: resetReadiness
10275
+ };
10276
+ }
10277
+ function normalizeBetterAuthBaseUrl(raw) {
10278
+ const trimmed = raw.replace(/\/$/, "");
10279
+ return trimmed.endsWith("/api/auth") ? trimmed : `${trimmed}/api/auth`;
7188
10280
  }
7189
- var SmartAccountPortTag = class extends Context.Service()("@capxul/sdk/ports/SmartAccountPort") {};
7190
10281
  //#endregion
7191
10282
  //#region src/flows/identity.ts
7192
10283
  const IDENTITY_SLOT = {
@@ -8075,8 +11166,52 @@ const loadIdentityProgram = Effect.gen(function* () {
8075
11166
  if (authUserId === void 0) return null;
8076
11167
  return yield* deps.identityPort.loadByAuthUserId(authUserId).pipe(Effect.catchDefect((cause) => Effect.fail(identityErrorFromCapxul("loadByAuthUserId", cause instanceof CapxulError ? cause : Errors.unknown(cause), cause))), Effect.mapError((failure) => failure.publicError));
8077
11168
  });
8078
- //#endregion
8079
- //#region src/surface/identity.ts
11169
+ /**
11170
+ * THE ONE boundary grammar for those optional fields. Both `completeProfile`
11171
+ * entry points — the method bundle here and the identity runtime in
11172
+ * `create-capxul-client.ts` — run it, so a malformed value is refused the same
11173
+ * way at each and never reaches the port.
11174
+ */
11175
+ function checkProfileCarriage(profile) {
11176
+ const carriage = {};
11177
+ if (profile.imageStorageId !== void 0) {
11178
+ if (typeof profile.imageStorageId !== "string" || profile.imageStorageId.trim().length === 0) return {
11179
+ ok: false,
11180
+ field: "imageStorageId",
11181
+ message: "must be a non-empty storage id"
11182
+ };
11183
+ carriage.imageStorageId = profile.imageStorageId.trim();
11184
+ }
11185
+ if (profile.payoutAddresses !== void 0) {
11186
+ if (!Array.isArray(profile.payoutAddresses)) return {
11187
+ ok: false,
11188
+ field: "payoutAddresses",
11189
+ message: "must be an array"
11190
+ };
11191
+ if (profile.payoutAddresses.length > 10) return {
11192
+ ok: false,
11193
+ field: "payoutAddresses",
11194
+ message: `must carry at most 10 addresses`
11195
+ };
11196
+ const entries = [];
11197
+ for (const entry of profile.payoutAddresses) {
11198
+ if (typeof entry !== "object" || entry === null || !PAYOUT_CHAINS.some((chain) => chain === entry.chain) || typeof entry.address !== "string" || entry.address.trim().length === 0) return {
11199
+ ok: false,
11200
+ field: "payoutAddresses",
11201
+ message: `each entry needs a chain of ${PAYOUT_CHAINS.join(", ")} and an address`
11202
+ };
11203
+ entries.push({
11204
+ chain: entry.chain,
11205
+ address: entry.address.trim()
11206
+ });
11207
+ }
11208
+ carriage.payoutAddresses = entries;
11209
+ }
11210
+ return {
11211
+ ok: true,
11212
+ carriage
11213
+ };
11214
+ }
8080
11215
  function makeIdentityMethods(deps) {
8081
11216
  const convexCall = deps.convexCall;
8082
11217
  return {
@@ -8115,6 +11250,11 @@ function makeIdentityMethods(deps) {
8115
11250
  error: Errors.invalidInput("country", "unsupported country")
8116
11251
  };
8117
11252
  }
11253
+ const carried = checkProfileCarriage(profile);
11254
+ if (!carried.ok) return {
11255
+ ok: false,
11256
+ error: Errors.invalidInput(carried.field, carried.message)
11257
+ };
8118
11258
  const session = deps.actor?.authSession();
8119
11259
  if (session === void 0 || session === null) return {
8120
11260
  ok: false,
@@ -8125,7 +11265,8 @@ function makeIdentityMethods(deps) {
8125
11265
  email: session.email,
8126
11266
  displayName,
8127
11267
  country,
8128
- handle
11268
+ handle,
11269
+ ...carried.carriage
8129
11270
  }), options, CAPXUL_OPERATIONS.identity.completeProfile);
8130
11271
  },
8131
11272
  async handleAvailable(handle, options) {
@@ -8222,14 +11363,66 @@ function organizationWrongState(currentState, validStates) {
8222
11363
  function requestCancelled(options) {
8223
11364
  return options?.signal?.aborted === true;
8224
11365
  }
11366
+ function accountInFlight(state) {
11367
+ return state.phase === "authenticated" && (state.account.at === "deriving" || state.account.at === "claiming");
11368
+ }
11369
+ function settledAccount(deps, options) {
11370
+ return new Promise((resolve) => {
11371
+ let done = false;
11372
+ let unsubscribe = null;
11373
+ const onAbort = () => finish({
11374
+ ok: false,
11375
+ error: Errors.cancelled({ operation: CAPXUL_OPERATIONS.onboarding.completeOrganization })
11376
+ });
11377
+ const finish = (result) => {
11378
+ if (done) return;
11379
+ done = true;
11380
+ unsubscribe?.();
11381
+ options?.signal?.removeEventListener("abort", onAbort);
11382
+ resolve(result);
11383
+ };
11384
+ if (options?.signal?.aborted) {
11385
+ onAbort();
11386
+ return;
11387
+ }
11388
+ options?.signal?.addEventListener("abort", onAbort, { once: true });
11389
+ const stop = deps.subscribeIdentity((state) => {
11390
+ if (!accountInFlight(state)) finish({
11391
+ ok: true,
11392
+ value: state
11393
+ });
11394
+ });
11395
+ if (done) {
11396
+ stop();
11397
+ return;
11398
+ }
11399
+ unsubscribe = stop;
11400
+ const current = deps.snapshotIdentity();
11401
+ if (!accountInFlight(current)) finish({
11402
+ ok: true,
11403
+ value: current
11404
+ });
11405
+ });
11406
+ }
8225
11407
  async function reachClaimedAccount(deps, options) {
8226
11408
  let state = deps.snapshotIdentity();
11409
+ if (accountInFlight(state)) {
11410
+ const settled = await settledAccount(deps, options);
11411
+ if (!settled.ok) return settled;
11412
+ state = settled.value;
11413
+ }
8227
11414
  if (state.phase !== "authenticated" || state.account.at === "unknown") {
8228
11415
  const ensured = await deps.sendIdentity({ _tag: "EnsureAccount" }, options);
8229
11416
  if (!ensured.ok) return ensured;
8230
11417
  state = ensured.value;
8231
11418
  }
8232
11419
  if (state.phase !== "authenticated") return organizationWrongState(state.phase, ["authenticated:claimed"]);
11420
+ if (accountInFlight(state)) {
11421
+ const settled = await settledAccount(deps, options);
11422
+ if (!settled.ok) return settled;
11423
+ state = settled.value;
11424
+ if (state.phase !== "authenticated") return organizationWrongState(state.phase, ["authenticated:claimed"]);
11425
+ }
8233
11426
  if (state.account.at !== "claimed") {
8234
11427
  const event = state.account.at === "failed" ? { _tag: "RetryAccount" } : state.account.at === "counterfactual" ? { _tag: "ClaimAccount" } : { _tag: "EnsureAccount" };
8235
11428
  const claimed = await deps.sendIdentity(event, options);
@@ -10029,6 +13222,7 @@ function assembleCapxulClient(input) {
10029
13222
  ensureAccount: account._internal.ensureReady,
10030
13223
  getLifecycle: account.getLifecycle,
10031
13224
  snapshotIdentity: actor.snapshot,
13225
+ subscribeIdentity: actor.subscribe,
10032
13226
  sendIdentity: (event, options) => runCapxulEffect(askIdentity(actor, event, options), options, CAPXUL_OPERATIONS._internal.identity.send, effectRunner.runPromise)
10033
13227
  });
10034
13228
  const system = makeSystemMethods({ convexCall: input.ports.convexCall });
@@ -10111,6 +13305,11 @@ function assembleCapxulClient(input) {
10111
13305
  ok: false,
10112
13306
  reason: "INVALID_INPUT"
10113
13307
  };
13308
+ const carried = checkProfileCarriage(profile);
13309
+ if (!carried.ok) return {
13310
+ ok: false,
13311
+ reason: "INVALID_INPUT"
13312
+ };
10114
13313
  const session = actor.authSession();
10115
13314
  if (session === null) return {
10116
13315
  ok: false,
@@ -10121,7 +13320,8 @@ function assembleCapxulClient(input) {
10121
13320
  email: session.email,
10122
13321
  displayName,
10123
13322
  country,
10124
- handle
13323
+ handle,
13324
+ ...carried.carriage
10125
13325
  }), controls, CAPXUL_OPERATIONS.identity.completeProfile, effectRunner.runPromise);
10126
13326
  return result.ok ? { ok: true } : {
10127
13327
  ok: false,
@@ -10220,4 +13420,721 @@ function withHostObservationControls(snapshot, input, actorId) {
10220
13420
  });
10221
13421
  }
10222
13422
  //#endregion
10223
- export { stampTelemetryEnvelope as $, safeExceptionLabel as A, resolveFailureMode as B, observeFailedResult as C, normalizeExceptionErrorKind as D, SDK_VERSION as E, causeChain as F, sanitizeObservationContext as G, readInvocationObservation as H, injectedWalletSigner as I, CAPXUL_FUNCTIONS as J, PAYMENT_DIRECTIONS as K, isSignerNotReadySignal as L, fromWei as M, isSettingUpLifecycle as N, normalizeExceptionOperation as O, formatTraceparent as P, redactTelemetryProps as Q, openfortSignerNotReadyCode as R, observationContextProps as S, EXCEPTION_MESSAGE as T, OBSERVATION_CONTEXT_HEADER as U, copyInvocationObservation as V, encodeObservationContextHeader as W, EngineeringTelemetryBootstrapPolicy as X, BootstrapEnvelope as Y, redactTelemetryEvent as Z, fingerprintPaymentIntent as _, AccountReadPortTag as a, isRestoring as at, failureDetail as b, retryIdempotentRead as c, IdentityPortTag as d, CAPXUL_OPERATIONS as et, identityErrorFromCapxul as f, bootstrapErrorFromCapxul as g, BootstrapPortTag as h, smartAccountErrorFromCapxul as i, isClaimed as it, version as j, projectSdkException as k, PRODUCT_INVOCATION as l, convexCallErrorFromCapxul as m, detectAuthCacheAdapter as n, normalizeCapxulOperation as nt, accountReadErrorFromCapxul as o, ConvexCallPortTag as p, PAYMENT_STATUSES as q, SmartAccountPortTag as r, destination as rt, TelemetryPortTag as s, assembleCapxulClient as t, isCapxulOperation as tt, wireChainId as u, toWei as v, postHogFailureObservation as w, failureEvidenceProps as x, CAPXUL_SDK_EXPECTED_OUTCOME_EVENT as y, signerFailure as z };
13423
+ //#region src/telemetry/from-posthog.ts
13424
+ /**
13425
+ * Drop props that must never cross to a host-owned external sink. Today that is
13426
+ * the `$exception` `details` blob: `captureException` serializes
13427
+ * `CapxulError.details` (e.g. `{ asset, available, required }`, `{ name }`,
13428
+ * `{ accountId }` — errors.ts) into it, and the shared redactor has no
13429
+ * `$exception` rule, so it is stripped here at the boundary (infra#1037). The
13430
+ * safe fields (error code, operation, failure_mode, the fixed leak-safe message,
13431
+ * stack frames) are preserved.
13432
+ */
13433
+ function stripHostUnsafeProps(props) {
13434
+ if (props === void 0) return void 0;
13435
+ const { details: _details, ...safe } = props;
13436
+ return safe;
13437
+ }
13438
+ /**
13439
+ * The subset of a posthog-js client the seam calls. `identify` / `group` /
13440
+ * `reset` are optional — a host that only wants event capture can omit them.
13441
+ */
13442
+ /**
13443
+ * Adapt the host's already-initialized posthog-like client into a
13444
+ * `TelemetryPort` for the `telemetry` prop / input. This port SUPPLANTS the
13445
+ * SDK's no-op default telemetry sink (`production.ts` binds it via
13446
+ * `Layer.succeed`, not `compose` — there is no client-side success relay to
13447
+ * compose with); it is additive to Capxul's backend first-party record and
13448
+ * never owns the client.
13449
+ */
13450
+ function postHogProductTelemetry(policy, fixedSnapshot) {
13451
+ const telemetry = new PostHogTelemetryAdapter({
13452
+ capture: (name, props, source) => {
13453
+ const snapshot = readInvocationObservation(source) ?? fixedSnapshot ?? policy.snapshot();
13454
+ if (!snapshot.active || policy.client === null || policy.client === void 0) return;
13455
+ const event = stampTelemetryEnvelope({
13456
+ name,
13457
+ props
13458
+ }, {
13459
+ capxul_env: policy.capxulEnv,
13460
+ producer: "sdk"
13461
+ });
13462
+ policy.deliver(() => policy.client.capture(name, {
13463
+ ...stripHostUnsafeProps(event.props),
13464
+ ...observationContextProps(snapshot.context)
13465
+ }));
13466
+ },
13467
+ identify: (input) => {
13468
+ if (!(fixedSnapshot ?? policy.snapshot()).active || policy.client?.identify === void 0) return;
13469
+ policy.deliver(() => policy.client.identify(input.distinctId, {
13470
+ ...input.traits,
13471
+ ...input.properties
13472
+ }));
13473
+ },
13474
+ group: (input) => {
13475
+ if (!(fixedSnapshot ?? policy.snapshot()).active || policy.client?.group === void 0) return;
13476
+ policy.deliver(() => policy.client.group(input.groupType, input.groupKey, input.properties === void 0 ? void 0 : { ...input.properties }));
13477
+ },
13478
+ reset: () => {
13479
+ if (!(fixedSnapshot ?? policy.snapshot()).active || policy.client?.reset === void 0) return;
13480
+ policy.deliver(() => policy.client.reset());
13481
+ }
13482
+ });
13483
+ Object.defineProperty(telemetry, PRODUCT_INVOCATION, {
13484
+ enumerable: false,
13485
+ value: (source) => postHogProductTelemetry(policy, readInvocationObservation(source) ?? fixedSnapshot ?? policy.snapshot())
13486
+ });
13487
+ return telemetry;
13488
+ }
13489
+ //#endregion
13490
+ //#region src/host-observability.ts
13491
+ const HOST_INVOCATION = Symbol("capxul.host-observability-invocation");
13492
+ /** Build the SDK's one host module around an already-initialized PostHog client. */
13493
+ function postHogObservability(client, options = {}) {
13494
+ const inactive = Object.freeze({
13495
+ active: false,
13496
+ contextProps: Object.freeze({})
13497
+ });
13498
+ const snapshot = () => {
13499
+ if (client === null || client === void 0) return inactive;
13500
+ try {
13501
+ if (!(typeof options.enabled === "function" ? options.enabled() : options.enabled ?? true)) return inactive;
13502
+ const sanitized = sanitizeObservationContext(typeof options.context === "function" ? options.context() : options.context);
13503
+ const context = sanitized === void 0 ? void 0 : Object.freeze({ ...sanitized });
13504
+ return Object.freeze({
13505
+ active: true,
13506
+ ...context === void 0 ? {} : { context },
13507
+ contextProps: Object.freeze(observationContextProps(context))
13508
+ });
13509
+ } catch {
13510
+ return inactive;
13511
+ }
13512
+ };
13513
+ const policy = {
13514
+ client,
13515
+ capxulEnv: options.capxulEnv ?? "unknown",
13516
+ snapshot,
13517
+ deliver: (capture) => {
13518
+ try {
13519
+ const delivery = capture();
13520
+ if (isPromiseLike(delivery)) Promise.resolve(delivery).catch(() => void 0);
13521
+ } catch {}
13522
+ }
13523
+ };
13524
+ const module = {
13525
+ failures: postHogFailureObservation(policy),
13526
+ product: postHogProductTelemetry(policy)
13527
+ };
13528
+ Object.defineProperty(module, HOST_INVOCATION, {
13529
+ enumerable: false,
13530
+ value: {
13531
+ bind: () => {
13532
+ const invocation = snapshot();
13533
+ return {
13534
+ failures: postHogFailureObservation(policy, invocation),
13535
+ product: postHogProductTelemetry(policy, invocation)
13536
+ };
13537
+ },
13538
+ snapshot
13539
+ }
13540
+ });
13541
+ return module;
13542
+ }
13543
+ /** @internal Bind both projections to one call-start decision/context snapshot. */
13544
+ function bindHostObservabilityInvocation(observability) {
13545
+ return observability?.[HOST_INVOCATION]?.bind() ?? observability;
13546
+ }
13547
+ /** @internal Read one call-start snapshot for actor/transition carriage. */
13548
+ function snapshotHostObservability(observability) {
13549
+ const snapshot = observability?.[HOST_INVOCATION]?.snapshot();
13550
+ return snapshot === void 0 ? void 0 : {
13551
+ active: snapshot.active,
13552
+ ...snapshot.context === void 0 ? {} : { context: snapshot.context }
13553
+ };
13554
+ }
13555
+ function isPromiseLike(value) {
13556
+ return (typeof value === "object" && value !== null || typeof value === "function") && "then" in value;
13557
+ }
13558
+ const SDK_VERSION = version;
13559
+ /**
13560
+ * Project the built graph into the flat `FlowPorts` record the method bundles
13561
+ * still take. It is a VIEW of `ProductionAdapters.context`, taken from the
13562
+ * graph and never instead of it — the graph stays alive in the scope and is
13563
+ * handed to every caller.
13564
+ */
13565
+ const collectProductionFlowPorts = Effect.gen(function* () {
13566
+ const authClient = yield* AuthClientPortTag;
13567
+ const authCache = yield* AuthCachePortTag;
13568
+ const bootstrap = yield* BootstrapPortTag;
13569
+ const clock = yield* ClockPortTag;
13570
+ const convexCall = yield* ConvexCallPortTag;
13571
+ return {
13572
+ authClient,
13573
+ authCache,
13574
+ identity: yield* IdentityPortTag,
13575
+ smartAccount: yield* SmartAccountPortTag,
13576
+ accountRead: yield* AccountReadPortTag,
13577
+ bootstrap,
13578
+ clock,
13579
+ telemetry: yield* TelemetryPortTag,
13580
+ convexCall
13581
+ };
13582
+ });
13583
+ function makeProductionAdapterLayerEntries(input) {
13584
+ const refreshConvexAuthRef = {
13585
+ current: null,
13586
+ pending: false
13587
+ };
13588
+ return [
13589
+ {
13590
+ name: "bootstrap",
13591
+ layer: productionBootstrapPortLayer(input.bootstrap)
13592
+ },
13593
+ {
13594
+ name: "authClient",
13595
+ layer: productionAuthClientLayer(input, refreshConvexAuthRef, input.resetSignerSession)
13596
+ },
13597
+ {
13598
+ name: "authCache",
13599
+ layer: productionAuthCacheLayer(input)
13600
+ },
13601
+ {
13602
+ name: "identity",
13603
+ layer: ConvexIdentityLayer()
13604
+ },
13605
+ {
13606
+ name: "smartAccount",
13607
+ layer: ConvexSmartAccountLayer()
13608
+ },
13609
+ {
13610
+ name: "accountRead",
13611
+ layer: ConvexAccountLayer()
13612
+ },
13613
+ {
13614
+ name: "clock",
13615
+ layer: SystemClockLayer()
13616
+ },
13617
+ {
13618
+ name: "telemetry",
13619
+ layer: input.telemetry === void 0 ? PostHogTelemetryLayer({ capture: () => void 0 }) : Layer.succeed(TelemetryPortTag, input.telemetry)
13620
+ },
13621
+ {
13622
+ name: "convexCall",
13623
+ layer: productionConvexCallLayer(input, refreshConvexAuthRef)
13624
+ },
13625
+ {
13626
+ name: "org",
13627
+ layer: Layer.effect(OrgPortTag, Effect.all([ConvexCallPortTag, TelemetryPortTag]).pipe(Effect.map(([convex, telemetry]) => new ConvexOrganizationAdapter({
13628
+ convex,
13629
+ telemetry
13630
+ }))))
13631
+ }
13632
+ ];
13633
+ }
13634
+ function mergeProductionAdapterLayers(entries) {
13635
+ const byName = /* @__PURE__ */ new Map();
13636
+ for (const entry of entries) byName.set(entry.name, entry.layer);
13637
+ const authClientLayer = byName.get("authClient");
13638
+ const convexCallLayer = byName.get("convexCall");
13639
+ const telemetryLayer = byName.get("telemetry");
13640
+ const convexCallReadyLayer = convexCallLayer === void 0 || authClientLayer === void 0 ? convexCallLayer : convexCallLayer.pipe(Layer.provide(authClientLayer));
13641
+ const observedConvexCallLayer = convexCallReadyLayer === void 0 ? telemetryLayer : telemetryLayer === void 0 ? convexCallReadyLayer : Layer.merge(convexCallReadyLayer, telemetryLayer);
13642
+ return entries.map((entry) => {
13643
+ const layer = byName.get(entry.name) ?? entry.layer;
13644
+ if (entry.name === "convexCall") return convexCallReadyLayer ?? layer;
13645
+ if (entry.name === "accountRead" || entry.name === "org") return observedConvexCallLayer === void 0 ? layer : layer.pipe(Layer.provide(observedConvexCallLayer));
13646
+ if (isConvexDependentLayer(entry.name)) return convexCallReadyLayer === void 0 ? layer : layer.pipe(Layer.provide(convexCallReadyLayer));
13647
+ return layer;
13648
+ }).reduce((current, layer) => Layer.merge(current, layer), Layer.empty);
13649
+ }
13650
+ function isConvexDependentLayer(name) {
13651
+ return name === "identity" || name === "smartAccount" || name === "accountRead" || name === "org";
13652
+ }
13653
+ function productionBootstrapPortLayer(bootstrap) {
13654
+ return Layer.succeed(BootstrapPortTag, bootstrap);
13655
+ }
13656
+ function productionAuthClientLayer(input, refreshConvexAuthRef, resetSignerSessionRef) {
13657
+ return (input.authClient !== void 0 ? Layer.succeed(AuthClientPortTag, input.authClient) : input.runtime === "browser" ? BetterAuthBrowserLayer({
13658
+ authBaseUrl: input.runtimeUrls.authBaseUrl,
13659
+ ...input.fetch === void 0 ? {} : { fetch: input.fetch },
13660
+ ...input.observation === void 0 ? {} : { observation: input.observation }
13661
+ }) : BetterAuthNodeLayer({
13662
+ authBaseUrl: input.runtimeUrls.authBaseUrl,
13663
+ ...input.origin === void 0 ? {} : { origin: input.origin },
13664
+ ...input.fetch === void 0 ? {} : { fetch: input.fetch },
13665
+ ...input.observation === void 0 ? {} : { observation: input.observation }
13666
+ })).pipe(Layer.flatMap((context) => {
13667
+ const refreshed = refreshConvexAuthOnSession(Context.get(context, AuthClientPortTag), () => {
13668
+ const refresh = refreshConvexAuthRef.current;
13669
+ if (refresh === null) {
13670
+ refreshConvexAuthRef.pending = true;
13671
+ return;
13672
+ }
13673
+ refresh();
13674
+ });
13675
+ return Layer.succeedContext(Context.make(AuthClientPortTag, resetSignerSessionRef === void 0 ? refreshed : resetSignerSessionOnSignOut(refreshed, resetSignerSessionRef)));
13676
+ }));
13677
+ }
13678
+ function productionAuthCacheLayer(input) {
13679
+ return Layer.succeed(AuthCachePortTag, input.authCache ?? detectAuthCacheAdapter());
13680
+ }
13681
+ function productionConvexCallLayer(input, refreshConvexAuthRef) {
13682
+ return Layer.unwrap(Effect.map(AuthClientPortTag, (authClient) => ConvexCallLayer({
13683
+ convexUrl: input.runtimeUrls.convexUrl,
13684
+ ...input.applicationId === void 0 ? {} : { applicationId: input.applicationId },
13685
+ ...input.observation === void 0 ? {} : { observation: input.observation },
13686
+ ...input.convexClient === void 0 ? {} : { client: input.convexClient },
13687
+ tokenProvider: async ({ forceRefreshToken }) => {
13688
+ const tokenResult = await Effect.runPromise(Effect.result(authClient.getConvexJwt({
13689
+ forceRefresh: forceRefreshToken,
13690
+ ...input.signal === void 0 ? {} : { signal: input.signal }
13691
+ })));
13692
+ if (Result.isFailure(tokenResult)) return null;
13693
+ return String(tokenResult.success.token);
13694
+ }
13695
+ }).pipe(Layer.flatMap((context) => {
13696
+ const convexCall = Context.get(context, ConvexCallPortTag);
13697
+ if (isRefreshableConvexCallPort(convexCall)) {
13698
+ refreshConvexAuthRef.current = () => convexCall.refreshAuth();
13699
+ if (refreshConvexAuthRef.pending) {
13700
+ refreshConvexAuthRef.pending = false;
13701
+ refreshConvexAuthRef.current();
13702
+ }
13703
+ }
13704
+ return Layer.succeedContext(context);
13705
+ }))));
13706
+ }
13707
+ function isRefreshableConvexCallPort(convexCall) {
13708
+ return "refreshAuth" in convexCall && typeof convexCall.refreshAuth === "function";
13709
+ }
13710
+ function resolveProductionObservability(input) {
13711
+ const observation = input.observability?.failures ?? input.observation;
13712
+ const telemetry = input.observability?.product ?? input.telemetry;
13713
+ const invocationObservability = input.invocationObservability;
13714
+ return {
13715
+ observation,
13716
+ telemetry,
13717
+ invocationObservation: invocationObservability?.failures ?? observation,
13718
+ invocationTelemetry: invocationObservability?.product ?? telemetry
13719
+ };
13720
+ }
13721
+ async function createProductionAdapters(input) {
13722
+ const { observation, telemetry, invocationObservation, invocationTelemetry } = resolveProductionObservability(input);
13723
+ const resolvedInput = resolveInput(input);
13724
+ if (!resolvedInput.ok) return resolvedInput;
13725
+ const scope = await Effect.runPromise(Scope.make());
13726
+ const closeScope = idempotentClose(() => Effect.runPromise(Scope.close(scope, Exit.void)));
13727
+ const bootstrapLayer = HttpBootstrapLayer({
13728
+ bootstrapBaseUrl: resolvedInput.value.bootstrapBaseUrl,
13729
+ ...input.fetch === void 0 ? {} : { fetch: input.fetch },
13730
+ ...invocationObservation === void 0 ? {} : { observation: invocationObservation }
13731
+ });
13732
+ try {
13733
+ const bootstrapContext = await Effect.runPromise(Layer.buildWithScope(bootstrapLayer, scope));
13734
+ const bootstrap = Context.get(bootstrapContext, BootstrapPortTag);
13735
+ const bootstrapResult = await runBootstrap(bootstrap.resolve({
13736
+ publishableKey: resolvedInput.value.publishableKey,
13737
+ ...resolvedInput.value.origin === void 0 ? {} : { origin: resolvedInput.value.origin }
13738
+ }));
13739
+ if (!bootstrapResult.ok) {
13740
+ await emitBootstrapTelemetry(invocationTelemetry, {
13741
+ name: "bootstrap_failed",
13742
+ props: {
13743
+ ...bootstrapTelemetryEnvelope(input, resolvedInput.value),
13744
+ reason: bootstrapResult.error.code,
13745
+ ...failureDetail(bootstrapResult.error),
13746
+ ...failureEvidenceProps(bootstrapResult.error)
13747
+ }
13748
+ });
13749
+ await closeScope().catch(() => void 0);
13750
+ return bootstrapResult;
13751
+ }
13752
+ const chainFence = assertDevKeySignerIsTestnetOnly(input.signer, bootstrapResult.value.chainId);
13753
+ if (!chainFence.ok) {
13754
+ await closeScope().catch(() => void 0);
13755
+ return chainFence;
13756
+ }
13757
+ const runtimeUrlsResult = resolveRuntimeUrls(bootstrapResult.value, resolvedInput.value.runtime, input.authBaseUrl);
13758
+ if (!runtimeUrlsResult.ok) {
13759
+ await emitBootstrapTelemetry(invocationTelemetry, {
13760
+ name: "bootstrap_failed",
13761
+ props: {
13762
+ ...bootstrapTelemetryEnvelope(input, resolvedInput.value),
13763
+ applicationId: bootstrapResult.value.applicationId,
13764
+ reason: runtimeUrlsResult.error.code
13765
+ }
13766
+ });
13767
+ await closeScope().catch(() => void 0);
13768
+ return runtimeUrlsResult;
13769
+ }
13770
+ const runtimeUrls = runtimeUrlsResult;
13771
+ await emitBootstrapTelemetry(invocationTelemetry, {
13772
+ name: "bootstrap_resolved",
13773
+ props: {
13774
+ ...bootstrapTelemetryEnvelope(input, resolvedInput.value),
13775
+ applicationId: bootstrapResult.value.applicationId
13776
+ }
13777
+ });
13778
+ let injectedClient;
13779
+ const convexClientFactory = input.convexClientFactory;
13780
+ if (convexClientFactory !== void 0) try {
13781
+ injectedClient = convexClientFactory(runtimeUrls.value.convexUrl);
13782
+ } catch (cause) {
13783
+ await closeScope().catch(() => void 0);
13784
+ return {
13785
+ ok: false,
13786
+ error: toPublicError(cause, "createProductionAdapters")
13787
+ };
13788
+ }
13789
+ const portsLayer = mergeProductionAdapterLayers(makeProductionAdapterLayerEntries({
13790
+ bootstrap,
13791
+ runtime: resolvedInput.value.runtime,
13792
+ ...resolvedInput.value.origin === void 0 ? {} : { origin: resolvedInput.value.origin },
13793
+ runtimeUrls: runtimeUrls.value,
13794
+ chainId: bootstrapResult.value.chainId,
13795
+ applicationId: bootstrapResult.value.applicationId,
13796
+ ...observation === void 0 ? {} : { observation },
13797
+ ...input.authCache === void 0 ? {} : { authCache: input.authCache },
13798
+ ...input.authClient === void 0 ? {} : { authClient: input.authClient },
13799
+ ...telemetry === void 0 ? {} : { telemetry },
13800
+ ...injectedClient === void 0 ? {} : { convexClient: injectedClient },
13801
+ ...input.fetch === void 0 ? {} : { fetch: input.fetch },
13802
+ ...input.signal === void 0 ? {} : { signal: input.signal },
13803
+ ...input.resetSignerSession === void 0 ? {} : { resetSignerSession: input.resetSignerSession }
13804
+ }));
13805
+ const applicationLayer = Layer.merge(portsLayer, optionalEngineeringTelemetryLayer(bootstrapResult.value.engineeringTelemetry, resolvedInput.value.runtime));
13806
+ const context = await Effect.runPromise(Layer.buildWithScope(applicationLayer, scope));
13807
+ const ports = await Effect.runPromise(collectProductionFlowPorts.pipe(Effect.provide(context)));
13808
+ const stopConnectionObservation = observeProductionConvexConnection(ports.convexCall, context);
13809
+ const close = idempotentClose(async () => {
13810
+ try {
13811
+ stopConnectionObservation();
13812
+ } finally {
13813
+ await closeScope();
13814
+ }
13815
+ });
13816
+ return {
13817
+ ok: true,
13818
+ value: {
13819
+ context,
13820
+ ports,
13821
+ bootstrap: bootstrapResult.value,
13822
+ close
13823
+ }
13824
+ };
13825
+ } catch (cause) {
13826
+ await closeScope().catch(() => void 0);
13827
+ return {
13828
+ ok: false,
13829
+ error: toPublicError(cause, "createProductionAdapters")
13830
+ };
13831
+ }
13832
+ }
13833
+ function observeProductionConvexConnection(convexCall, context) {
13834
+ if (!("observeConnection" in convexCall) || typeof convexCall.observeConnection !== "function") return () => {};
13835
+ const runPromise = Effect.runPromiseWith(context);
13836
+ try {
13837
+ return convexCall.observeConnection((diagnostic) => {
13838
+ const message = diagnostic.transition === "connected" ? Effect.logInfo("convex.connection.changed") : Effect.logWarning("convex.connection.changed");
13839
+ runPromise(message.pipe(Effect.annotateLogs(diagnostic), Effect.catchCause(() => Effect.void))).catch(() => void 0);
13840
+ });
13841
+ } catch {
13842
+ return () => {};
13843
+ }
13844
+ }
13845
+ function optionalEngineeringTelemetryLayer(policy, runtime) {
13846
+ if (policy === void 0) return Layer.empty;
13847
+ try {
13848
+ return makeEngineeringTelemetryLayer({
13849
+ host: policy.host,
13850
+ headers: { authorization: `Bearer ${policy.projectToken}` },
13851
+ capxulEnv: policy.capxulEnv,
13852
+ producer: runtime === "browser" ? "browser" : "server",
13853
+ sdkVersion: SDK_VERSION
13854
+ });
13855
+ } catch {
13856
+ return Layer.empty;
13857
+ }
13858
+ }
13859
+ function refreshConvexAuthOnSession(authClient, refresh) {
13860
+ return {
13861
+ ...authClient,
13862
+ verifyOtp: (input, options) => authClient.verifyOtp(input, options).pipe(Effect.tap(() => Effect.sync(refresh))),
13863
+ signOut: (options) => authClient.signOut(options).pipe(Effect.tap(() => Effect.sync(refresh)))
13864
+ };
13865
+ }
13866
+ /**
13867
+ * Signer-session reset, as a port wrapper INSIDE the Layer graph (blueprint §2:
13868
+ * "wrappers become Layers, not post-hoc spreads/Proxies").
13869
+ *
13870
+ * This was a spread over the assembled client — `{...client, auth: {...,
13871
+ * signOut}}` — applied after composition finished, so the reset lived on one
13872
+ * particular object rather than on the auth seam itself. Here it wraps
13873
+ * `AuthClientPort.signOut`, so it holds for every route to a sign-out.
13874
+ *
13875
+ * Capture the sign-out exit before reset. This preserves the old `try/finally`
13876
+ * order and keeps a reset failure in the typed error channel.
13877
+ */
13878
+ function resetSignerSessionOnSignOut(authClient, resetRef) {
13879
+ return {
13880
+ ...authClient,
13881
+ signOut: (options) => Effect.gen(function* () {
13882
+ const exit = yield* Effect.exit(authClient.signOut(options));
13883
+ yield* Effect.try({
13884
+ try: () => resetRef.current?.(),
13885
+ catch: (cause) => new AuthClientError({
13886
+ operation: "signOut",
13887
+ kind: "signer",
13888
+ cause
13889
+ })
13890
+ });
13891
+ return yield* exit;
13892
+ })
13893
+ };
13894
+ }
13895
+ async function createCapxulClient(input) {
13896
+ return createCapxulClientWithSignerControls(input, {});
13897
+ }
13898
+ function withSignerControl(signer, control) {
13899
+ if (signer === void 0 || control === void 0) return signer;
13900
+ return {
13901
+ source: signer.source,
13902
+ getAddress: () => signer.getAddress(),
13903
+ signUserOpHash: (hash) => control(hash, signer),
13904
+ ...signer.statusStore === void 0 ? {} : { statusStore: signer.statusStore },
13905
+ ...signer.ensureWalletReady === void 0 ? {} : { ensureWalletReady: signer.ensureWalletReady.bind(signer) },
13906
+ ..."resetSession" in signer ? { resetSession: () => signer.resetSession() } : {}
13907
+ };
13908
+ }
13909
+ /** Shared production composition. The normal factory passes no controls. */
13910
+ async function createCapxulClientWithSignerControls(input, controls) {
13911
+ const invocationObservability = bindHostObservabilityInvocation(input.observability);
13912
+ const observation = invocationObservability?.failures ?? input.observation;
13913
+ const validation = validateCreateCapxulClientInput(input);
13914
+ if (!validation.ok) return observeFailedResult(validation, observation, "createCapxulClient");
13915
+ const resetSignerSession = { current: null };
13916
+ const adapters = await createProductionAdapters({
13917
+ ...input,
13918
+ resetSignerSession,
13919
+ ...invocationObservability === void 0 ? {} : { invocationObservability }
13920
+ });
13921
+ if (!adapters.ok) return observeFailedResult(adapters, observation, "createCapxulClient");
13922
+ try {
13923
+ const runtime = input.runtime ?? detectRuntime();
13924
+ const resolvedAuthBaseUrl = resolveBrowserAuthBaseUrl({
13925
+ bootstrapAuthBaseUrl: adapters.value.bootstrap.authBaseUrl,
13926
+ runtime,
13927
+ ...input.authBaseUrl === void 0 ? {} : { override: input.authBaseUrl }
13928
+ });
13929
+ let signer = input.signer;
13930
+ if (signer === void 0 && runtime === "browser") signer = createOpenfortBrowserSignerFromBootstrap({
13931
+ ...adapters.value.bootstrap,
13932
+ authBaseUrl: resolvedAuthBaseUrl
13933
+ }, {
13934
+ diagnostic: new ConsoleDiagnosticAdapter(),
13935
+ signUserOpHash: controls.signEmbeddedUserOpHash
13936
+ });
13937
+ signer = withSignerControl(signer, controls.signUserOpHash);
13938
+ if (signer !== void 0 && "resetSession" in signer) {
13939
+ const { resetSession, source } = signer;
13940
+ resetSignerSession.current = () => {
13941
+ try {
13942
+ resetSession();
13943
+ } catch (cause) {
13944
+ throw signerFailure(source, "resetSession", cause);
13945
+ }
13946
+ };
13947
+ }
13948
+ const client = assembleCapxulClient({
13949
+ ports: adapters.value.ports,
13950
+ bootstrap: adapters.value.bootstrap,
13951
+ authCache: adapters.value.ports.authCache,
13952
+ requirement: input.requirement ?? "none",
13953
+ ...signer === void 0 ? {} : { signer },
13954
+ orgPort: Context.get(adapters.value.context, OrgPortTag),
13955
+ ...signer === void 0 ? {} : { organizationSetup: new ConvexOrganizationSetupAdapter({
13956
+ convex: adapters.value.ports.convexCall,
13957
+ signer,
13958
+ chainId: adapters.value.bootstrap.chainId
13959
+ }) },
13960
+ ...input.signal === void 0 ? {} : { signal: input.signal },
13961
+ ...input.otpTtlMs === void 0 ? {} : { otpTtlMs: input.otpTtlMs },
13962
+ invokeTimeoutMs: input.invokeTimeoutMs ?? 3e4,
13963
+ ...input.observability?.failures === void 0 && input.observation === void 0 ? {} : { failureObservation: input.observability?.failures ?? input.observation },
13964
+ ...input.observability === void 0 ? {} : { hostObservationSnapshot: () => snapshotHostObservability(input.observability) },
13965
+ effectRunner: {
13966
+ runSync: Effect.runSyncWith(adapters.value.context),
13967
+ runPromise: Effect.runPromiseWith(adapters.value.context)
13968
+ }
13969
+ });
13970
+ const upstreamClose = adapters.value.close;
13971
+ const close = idempotentClose(async () => {
13972
+ try {
13973
+ if (signer !== void 0 && "resetSession" in signer) try {
13974
+ signer.resetSession();
13975
+ } catch (cause) {
13976
+ throw signerFailure(signer.source, "resetSession", cause);
13977
+ }
13978
+ } finally {
13979
+ await Promise.all([client._internal.close?.(), upstreamClose()]);
13980
+ }
13981
+ });
13982
+ return {
13983
+ ok: true,
13984
+ value: {
13985
+ ...client,
13986
+ _internal: {
13987
+ ...client._internal,
13988
+ close
13989
+ }
13990
+ }
13991
+ };
13992
+ } catch (cause) {
13993
+ await adapters.value.close().catch(() => void 0);
13994
+ return observeFailedResult({
13995
+ ok: false,
13996
+ error: toPublicError(cause, "createCapxulClient")
13997
+ }, observation, "createCapxulClient");
13998
+ }
13999
+ }
14000
+ function validateCreateCapxulClientInput(input) {
14001
+ const runtime = input.runtime ?? detectRuntime();
14002
+ if ((input.requirement ?? "none") === "deployed" && input.signer === void 0 && runtime !== "browser") return {
14003
+ ok: false,
14004
+ error: Errors.invalidInput("signer", "required when requirement is \"deployed\"")
14005
+ };
14006
+ return {
14007
+ ok: true,
14008
+ value: void 0
14009
+ };
14010
+ }
14011
+ function resolveInput(input) {
14012
+ try {
14013
+ const runtime = input.runtime ?? detectRuntime();
14014
+ const publishableKey = toPublishableKey(input.publishableKey);
14015
+ const origin = input.origin === void 0 ? runtime === "browser" ? toAllowedOrigin(derivedBrowserOrigin(runtime)) : void 0 : toAllowedOrigin(input.origin);
14016
+ return {
14017
+ ok: true,
14018
+ value: {
14019
+ publishableKey,
14020
+ ...origin === void 0 ? {} : { origin },
14021
+ bootstrapBaseUrl: normalizeHttpUrl("bootstrapBaseUrl", input.bootstrapBaseUrl ?? (runtime === "browser" ? derivedBrowserOrigin(runtime) : "https://api.capxul.com")),
14022
+ runtime
14023
+ }
14024
+ };
14025
+ } catch (cause) {
14026
+ return {
14027
+ ok: false,
14028
+ error: toPublicError(cause, "createProductionAdapters")
14029
+ };
14030
+ }
14031
+ }
14032
+ function detectRuntime() {
14033
+ const globalAny = globalThis;
14034
+ return globalAny.window !== void 0 || globalAny.document !== void 0 ? "browser" : "node";
14035
+ }
14036
+ function derivedBrowserOrigin(runtime) {
14037
+ if (runtime !== "browser") throw Errors.invalidInput("origin", "required outside browser runtime");
14038
+ const globalAny = globalThis;
14039
+ if (typeof globalAny.location?.origin === "string" && globalAny.location.origin.length > 0) return globalAny.location.origin;
14040
+ throw Errors.invalidInput("origin", "required when browser location is unavailable");
14041
+ }
14042
+ /**
14043
+ * Browser local dev serves `/api/auth` via the Vite proxy on `window.location.origin`
14044
+ * while bootstrap returns the remote Convex site host. Openfort wallet setup reads
14045
+ * Better Auth cookies from `get-session` — those only attach on the same origin the
14046
+ * OTP flow used, so rewrite when hosts differ.
14047
+ */
14048
+ function resolveBrowserAuthBaseUrl(input) {
14049
+ if (input.override !== void 0) return normalizeHttpUrl("authBaseUrl", input.override);
14050
+ const bootstrapUrl = normalizeHttpUrl("authBaseUrl", input.bootstrapAuthBaseUrl);
14051
+ if (input.runtime !== "browser") return bootstrapUrl;
14052
+ try {
14053
+ const localAuthBase = normalizeHttpUrl("authBaseUrl", `${derivedBrowserOrigin(input.runtime)}/api/auth`);
14054
+ const remoteAuthBase = bootstrapUrl.endsWith("/api/auth") ? bootstrapUrl : `${bootstrapUrl}/api/auth`;
14055
+ if (new URL(remoteAuthBase).host !== new URL(localAuthBase).host) return localAuthBase;
14056
+ return bootstrapUrl;
14057
+ } catch {
14058
+ return bootstrapUrl;
14059
+ }
14060
+ }
14061
+ function resolveRuntimeUrls(bootstrap, runtime, authBaseUrlOverride) {
14062
+ try {
14063
+ return {
14064
+ ok: true,
14065
+ value: {
14066
+ authBaseUrl: resolveBrowserAuthBaseUrl({
14067
+ bootstrapAuthBaseUrl: bootstrap.authBaseUrl,
14068
+ runtime,
14069
+ ...authBaseUrlOverride === void 0 ? {} : { override: authBaseUrlOverride }
14070
+ }),
14071
+ convexUrl: normalizeHttpUrl("convexUrl", bootstrap.convexUrl)
14072
+ }
14073
+ };
14074
+ } catch (cause) {
14075
+ return {
14076
+ ok: false,
14077
+ error: toPublicError(cause, "createProductionAdapters")
14078
+ };
14079
+ }
14080
+ }
14081
+ async function runBootstrap(effect) {
14082
+ const result = await Effect.runPromise(Effect.result(effect));
14083
+ if (Result.isSuccess(result)) return {
14084
+ ok: true,
14085
+ value: result.success
14086
+ };
14087
+ return {
14088
+ ok: false,
14089
+ error: toPublicError(result.failure, "bootstrap.resolve")
14090
+ };
14091
+ }
14092
+ /**
14093
+ * Bootstrap-event props. `runtime` used to be called `capxulEnv`, which was a
14094
+ * name collision, not a value: it carried "browser"/"node", never an
14095
+ * environment. ADR-0020 A1 makes `capxul_env` the environment discriminator
14096
+ * every synced artifact filters on, so this field was renamed to what it
14097
+ * actually is. `sdk_version` follows the canon envelope spelling.
14098
+ */
14099
+ function bootstrapTelemetryEnvelope(input, resolvedInput) {
14100
+ return {
14101
+ runtime: resolvedInput.runtime,
14102
+ env: input.requirement ?? "none",
14103
+ ...resolvedInput.origin === void 0 ? {} : { origin: resolvedInput.origin },
14104
+ sdk_version: SDK_VERSION
14105
+ };
14106
+ }
14107
+ async function emitBootstrapTelemetry(telemetry, event) {
14108
+ if (telemetry === void 0) return;
14109
+ await Effect.runPromise(telemetry.emit(event).pipe(Effect.catchDefect(() => Effect.void)));
14110
+ }
14111
+ function normalizeHttpUrl(field, raw) {
14112
+ let parsed;
14113
+ try {
14114
+ parsed = new URL(raw);
14115
+ } catch {
14116
+ throw Errors.invalidInput(field, "must be an http or https URL");
14117
+ }
14118
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") throw Errors.invalidInput(field, "must be an http or https URL");
14119
+ return parsed.toString().replace(/\/$/, "");
14120
+ }
14121
+ function toPublicError(cause, operation) {
14122
+ if (cause instanceof CapxulError) return cause;
14123
+ if (typeof cause === "object" && cause !== null) {
14124
+ const publicError = cause.publicError;
14125
+ if (publicError instanceof CapxulError) return publicError;
14126
+ const nestedCause = cause.cause;
14127
+ if (nestedCause instanceof CapxulError) return nestedCause;
14128
+ }
14129
+ return Errors.providerError("sdk-production-adapters", operation, cause);
14130
+ }
14131
+ function idempotentClose(close) {
14132
+ let closed = false;
14133
+ return async () => {
14134
+ if (closed) return;
14135
+ closed = true;
14136
+ await close();
14137
+ };
14138
+ }
14139
+ //#endregion
14140
+ export { signerFailure as A, isRestoring as B, normalizeExceptionErrorKind as C, fromWei as D, safeExceptionLabel as E, CAPXUL_OPERATIONS as F, isCapxulOperation as I, normalizeCapxulOperation as L, PAYMENT_DIRECTIONS as M, PAYMENT_STATUSES as N, isSettingUpLifecycle as O, redactTelemetryEvent as P, destination as R, SDK_VERSION$1 as S, projectSdkException as T, fingerprintPaymentIntent as _, smartAccountErrorFromCapxul as a, failureDetail as b, identityErrorFromCapxul as c, embeddedSigner as d, openfortEmbeddedSigner as f, devPrivateKeySigner as g, deriveDevPrivateKey as h, assembleCapxulClient as i, resolveFailureMode as j, injectedWalletSigner as k, convexCallErrorFromCapxul as l, openfortEmbeddedWalletPort as m, createCapxulClientWithSignerControls as n, accountReadErrorFromCapxul as o, openfortEmbeddedSignerFromWallet as p, postHogObservability as r, wireChainId as s, createCapxulClient as t, bootstrapErrorFromCapxul as u, toWei as v, normalizeExceptionOperation as w, EXCEPTION_MESSAGE as x, CAPXUL_SDK_EXPECTED_OUTCOME_EVENT as y, isClaimed as z };