@capxul/sdk 1.0.0-alpha.16 → 1.0.0-alpha.18

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.
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
- import { A as toSessionToken, C as toEpochSeconds, D as toPublishableKey, E as toOrgId, F as isCapxulError, M as decodeConvexError, N as CapxulError, O as toPublishableKeyId, P as Errors, S as toEpochMs, T as toKycTier, _ as toChainId, b as toDurationMs, c as BYTES32_RE, d as toAccountId, f as toAddress, g as toAuthUserId, h as toAppId, j as toSubAccountId, k as toRoleKey, l as EVM_ADDRESS_RE$1, m as toAnonymousDistinctId, n as BrowserAuthCacheAdapter, o as AuthCachePortTag, p as toAllowedOrigin, s as APP_ID_RE, t as InMemoryAuthCacheAdapter, u as SUPPORTED_CURRENCY_CODES, v as toCountryCode, w as toJwtToken, x as toEmail, y as toCurrencyCode } from "./InMemoryAuthCacheAdapter-v5W-XB5M.mjs";
2
- import { formatUnits, keccak256, padHex, parseUnits, recoverAddress, stringToHex, toBytes } from "viem";
1
+ import { A as toSessionToken, C as toEpochSeconds, D as toPublishableKey, E as toOrgId, F as Errors, I as isCapxulError, M as decodeConvexError, N as CapxulError, O as toPublishableKeyId, P as EXPECTED_OPERATION_OUTCOMES, S as toEpochMs, T as toKycTier, _ as toChainId, b as toDurationMs, c as BYTES32_RE, d as toAccountId, f as toAddress, g as toAuthUserId, h as toAppId, j as toSubAccountId, k as toRoleKey, l as EVM_ADDRESS_RE$1, m as toAnonymousDistinctId, n as BrowserAuthCacheAdapter, o as AuthCachePortTag, p as toAllowedOrigin, s as APP_ID_RE, t as InMemoryAuthCacheAdapter, u as SUPPORTED_CURRENCY_CODES, v as toCountryCode, w as toJwtToken, x as toEmail, y as toCurrencyCode } from "./InMemoryAuthCacheAdapter-BuVZpnSx.mjs";
2
+ import { concat, formatUnits, keccak256, padHex, parseUnits, recoverAddress, stringToHex, toBytes, toEventSelector, toFunctionSelector } from "viem";
3
3
  import { Context, Data, Deferred, Duration, Effect, Either, Exit, Layer, Ref, Request, Scope } from "effect";
4
4
  import { getFunctionName, makeFunctionReference } from "convex/server";
5
5
  import { privateKeyToAccount } from "viem/accounts";
@@ -12,6 +12,10 @@ import { Machine } from "@effect/experimental";
12
12
  const USDX_ADDRESS_BASE_SEPOLIA = "0xf09fcbb6df9f8f918e58f9c8ab15a76ade862b77";
13
13
  USDX_ADDRESS_BASE_SEPOLIA.toLowerCase();
14
14
  //#endregion
15
+ //#region ../config/src/org-payments.ts
16
+ /** Zodiac MultiSendCallOnly module on Base Sepolia. */
17
+ const MULTI_SEND_CALL_ONLY = "0x9641d764fc13c8b624c04430c7356c1c7c8102e2";
18
+ //#endregion
15
19
  //#region ../config/src/safe.ts
16
20
  const BASE_SEPOLIA_CHAIN_ID = 84532;
17
21
  /**
@@ -175,6 +179,20 @@ padHex(stringToHex("FM_DAILY"), {
175
179
  size: 32,
176
180
  dir: "right"
177
181
  });
182
+ padHex(concat([MULTI_SEND_CALL_ONLY, "0x8d80ff0a"]), {
183
+ dir: "right",
184
+ size: 32
185
+ });
186
+ new Map([
187
+ ["assignRoles(address,bytes32[],bool[])", "AssignRoles(address,bytes32[],bool[])"],
188
+ ["allowTarget(bytes32,address,uint8)", "AllowTarget(bytes32,address,uint8)"],
189
+ ["scopeTarget(bytes32,address)", "ScopeTarget(bytes32,address)"],
190
+ ["revokeTarget(bytes32,address)", "RevokeTarget(bytes32,address)"],
191
+ ["allowFunction(bytes32,address,bytes4,uint8)", "AllowFunction(bytes32,address,bytes4,uint8)"],
192
+ ["scopeFunction(bytes32,address,bytes4,(uint8,uint8,uint8,bytes)[],uint8)", "ScopeFunction(bytes32,address,bytes4,(uint8,uint8,uint8,bytes)[],uint8)"],
193
+ ["revokeFunction(bytes32,address,bytes4)", "RevokeFunction(bytes32,address,bytes4)"],
194
+ ["setAllowance(bytes32,uint128,uint128,uint128,uint64,uint64)", "SetAllowance(bytes32,uint128,uint128,uint128,uint64,uint64)"]
195
+ ].map(([functionSignature, eventSignature]) => [toFunctionSelector(functionSignature), toEventSelector(eventSignature)]));
178
196
  //#endregion
179
197
  //#region src/telemetry/stack-frame-parser.ts
180
198
  /**
@@ -1600,7 +1618,7 @@ async function recoverRawDigestSigner(input) {
1600
1618
  }
1601
1619
  //#endregion
1602
1620
  //#region package.json
1603
- var version = "1.0.0-alpha.16";
1621
+ var version = "1.0.0-alpha.18";
1604
1622
  //#endregion
1605
1623
  //#region src/ports/auth-client.ts
1606
1624
  var AuthClientError = class extends Data.TaggedError("AuthClientError") {};
@@ -1646,6 +1664,94 @@ function resolveAuthClientUrl(authBaseUrl, path) {
1646
1664
  return `${base}${path}`;
1647
1665
  }
1648
1666
  //#endregion
1667
+ //#region ../wire/src/secret-material.ts
1668
+ const SENSITIVE_MATERIAL_PATTERNS = [
1669
+ /0x[a-fA-F0-9]{40,}/u,
1670
+ /(?:^|[^a-fA-F0-9])[a-fA-F0-9]{64}(?:$|[^a-fA-F0-9])/u,
1671
+ /eyJ[A-Za-z0-9_-]*\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/u,
1672
+ /(?:(?:sk|pk|rk)_(?:live|test)|(?:phc|phx|ghp|gho|ghu|ghs|ghr|whsec)_|github_pat_|xox[baprs]-|AKIA[0-9A-Z]{16}|AIza)[A-Za-z0-9_-]*/iu
1673
+ ];
1674
+ /**
1675
+ * Reject: does the value carry any known secret material? Best effort — callers
1676
+ * drop the whole value on a match; a false negative is a leak, a false positive
1677
+ * merely omits an observation field.
1678
+ */
1679
+ function containsSensitiveMaterial(value) {
1680
+ return SENSITIVE_MATERIAL_PATTERNS.some((pattern) => pattern.test(value));
1681
+ }
1682
+ //#endregion
1683
+ //#region ../wire/src/observation-context.ts
1684
+ /** Single bounded HTTP carrier used before a Convex action envelope exists. */
1685
+ const OBSERVATION_CONTEXT_HEADER = "x-capxul-observation-context";
1686
+ const FIELD_RULES = {
1687
+ application: {
1688
+ maxLength: 64,
1689
+ pattern: /^[A-Za-z0-9][A-Za-z0-9._-]*$/u
1690
+ },
1691
+ applicationId: {
1692
+ maxLength: 30,
1693
+ pattern: APP_ID_RE
1694
+ },
1695
+ release: {
1696
+ maxLength: 128,
1697
+ pattern: /^[A-Za-z0-9][A-Za-z0-9._+@:/-]*$/u
1698
+ },
1699
+ sessionId: {
1700
+ maxLength: 128,
1701
+ pattern: /^[A-Za-z0-9][A-Za-z0-9._:-]*$/u
1702
+ },
1703
+ organizationId: {
1704
+ maxLength: 128,
1705
+ pattern: /^[A-Za-z0-9][A-Za-z0-9._:-]*$/u
1706
+ },
1707
+ correlationId: {
1708
+ maxLength: 128,
1709
+ pattern: /^[A-Za-z0-9][A-Za-z0-9._:-]*$/u
1710
+ },
1711
+ anonymousId: {
1712
+ maxLength: 128,
1713
+ pattern: /^anon_[A-Za-z0-9-]+$/u
1714
+ }
1715
+ };
1716
+ /**
1717
+ * Copy only the canonical allowlist and silently omit malformed/sensitive
1718
+ * values. Observation metadata is best effort and may never reject a domain
1719
+ * operation.
1720
+ */
1721
+ function sanitizeObservationContext(input) {
1722
+ if (typeof input !== "object" || input === null || Array.isArray(input)) return void 0;
1723
+ const source = input;
1724
+ const sanitized = {};
1725
+ for (const field of Object.keys(FIELD_RULES)) {
1726
+ const value = source[field];
1727
+ if (!isSafeField(field, value)) continue;
1728
+ sanitized[field] = value;
1729
+ }
1730
+ return Object.keys(sanitized).length === 0 ? void 0 : sanitized;
1731
+ }
1732
+ /** Encode only the sanitized allowlist; absence stays absence. */
1733
+ function encodeObservationContextHeader(input) {
1734
+ const sanitized = sanitizeObservationContext(input);
1735
+ return sanitized === void 0 ? void 0 : JSON.stringify(sanitized);
1736
+ }
1737
+ function isSafeField(field, value) {
1738
+ if (typeof value !== "string") return false;
1739
+ const rule = FIELD_RULES[field];
1740
+ return value.length > 0 && value.length <= rule.maxLength && value === value.trim() && !value.includes("://") && !containsSensitiveMaterial(value) && rule.pattern.test(value);
1741
+ }
1742
+ //#endregion
1743
+ //#region src/internal/observation-http.ts
1744
+ /** Resolve one bounded pre-auth snapshot for an outbound SDK HTTP request. */
1745
+ function observationRequestHeaders(adapter) {
1746
+ if (adapter === void 0) return {};
1747
+ try {
1748
+ const encoded = encodeObservationContextHeader(adapter.resolveContext?.());
1749
+ return encoded === void 0 ? {} : { [OBSERVATION_CONTEXT_HEADER]: encoded };
1750
+ } catch {
1751
+ return {};
1752
+ }
1753
+ }
1754
+ //#endregion
1649
1755
  //#region src/adapters/auth-client/BetterAuthBrowserAdapter.ts
1650
1756
  function withSignal$1(init, signal) {
1651
1757
  return signal === void 0 ? init : {
@@ -1703,8 +1809,10 @@ function mapFetchError$1(operation, err, signal) {
1703
1809
  var BetterAuthBrowserAdapter = class {
1704
1810
  authBaseUrl;
1705
1811
  fetchImpl;
1812
+ observation;
1706
1813
  constructor(deps) {
1707
1814
  this.authBaseUrl = deps.authBaseUrl.replace(/\/$/, "");
1815
+ this.observation = deps.observation;
1708
1816
  this.fetchImpl = deps.fetch ?? ((input, init) => globalThis.fetch(input, init));
1709
1817
  }
1710
1818
  url(path) {
@@ -1731,7 +1839,10 @@ var BetterAuthBrowserAdapter = class {
1731
1839
  try {
1732
1840
  const res = await this.fetchImpl(this.url("/api/auth/email-otp/send-verification-otp"), withSignal$1({
1733
1841
  method: "POST",
1734
- headers: { "Content-Type": "application/json" },
1842
+ headers: {
1843
+ "Content-Type": "application/json",
1844
+ ...observationRequestHeaders(this.observation)
1845
+ },
1735
1846
  body: JSON.stringify({
1736
1847
  email: input.email,
1737
1848
  type: "sign-in"
@@ -2105,12 +2216,14 @@ var BetterAuthNodeAdapter = class {
2105
2216
  origin;
2106
2217
  cookieJar;
2107
2218
  fetchImpl;
2219
+ observation;
2108
2220
  constructor(deps) {
2109
2221
  this.authBaseUrl = deps.authBaseUrl.replace(/\/$/, "");
2110
2222
  this.host = hostFromBaseUrl(this.authBaseUrl);
2111
2223
  this.origin = deps.origin?.replace(/\/$/, "");
2112
2224
  this.cookieJar = deps.cookieJar ?? new CookieJar();
2113
2225
  this.fetchImpl = deps.fetch ?? fetch;
2226
+ this.observation = deps.observation;
2114
2227
  }
2115
2228
  url(path) {
2116
2229
  return resolveAuthClientUrl(this.authBaseUrl, path);
@@ -2145,7 +2258,8 @@ var BetterAuthNodeAdapter = class {
2145
2258
  method: "POST",
2146
2259
  headers: {
2147
2260
  "content-type": "application/json",
2148
- ...this.origin ? { origin: this.origin } : {}
2261
+ ...this.origin ? { origin: this.origin } : {},
2262
+ ...observationRequestHeaders(this.observation)
2149
2263
  },
2150
2264
  body: JSON.stringify({
2151
2265
  email: input.email,
@@ -2646,7 +2760,7 @@ const PaymentSource = Schema.Union(Schema.Struct({
2646
2760
  * `hashLineItems` (payment-document-hash.ts) into the Invoice `lineItemsHash`,
2647
2761
  * and Σ(quantity × unitMinor) MUST equal the invoice `amount`. The hash binds
2648
2762
  * the documentHash to the exact items; the sum-check makes the items add up to
2649
- * the amount due. See the payment-document spec (canon/mcp/financial-ops.md).
2763
+ * the amount due. See the financial-operations contract in `packages/wire/CONTEXT.md`.
2650
2764
  */
2651
2765
  const LineItem = Schema.Struct({
2652
2766
  description: Schema.String,
@@ -2757,8 +2871,10 @@ async function safeText(res) {
2757
2871
  var HttpBootstrapAdapter = class {
2758
2872
  bootstrapBaseUrl;
2759
2873
  fetchImpl;
2874
+ observation;
2760
2875
  constructor(deps) {
2761
2876
  this.bootstrapBaseUrl = deps.bootstrapBaseUrl.replace(/\/$/, "");
2877
+ this.observation = deps.observation;
2762
2878
  this.fetchImpl = deps.fetch ?? ((input, init) => globalThis.fetch(input, init));
2763
2879
  }
2764
2880
  resolve(input) {
@@ -2766,7 +2882,8 @@ var HttpBootstrapAdapter = class {
2766
2882
  try: () => {
2767
2883
  const headers = {
2768
2884
  "content-type": "application/json",
2769
- ...input.origin === void 0 ? {} : { origin: input.origin }
2885
+ ...input.origin === void 0 ? {} : { origin: input.origin },
2886
+ ...observationRequestHeaders(this.observation)
2770
2887
  };
2771
2888
  return this.fetchImpl(`${this.bootstrapBaseUrl}/v1/client/bootstrap`, {
2772
2889
  method: "POST",
@@ -2860,13 +2977,58 @@ function convexCallErrorFromCapxul(operation, error) {
2860
2977
  }
2861
2978
  var ConvexCallPortTag = class extends Context.Tag("@capxul/sdk/ports/ConvexCallPort")() {};
2862
2979
  //#endregion
2980
+ //#region src/internal/invocation-observation.ts
2981
+ const INVOCATION_OBSERVATION = Symbol("capxul.invocation-observation");
2982
+ const FAILURE_INVOCATION_SNAPSHOT = Symbol("capxul.failure-invocation-snapshot");
2983
+ /** @internal Attach one immutable, non-wire invocation snapshot to an SDK-owned object. */
2984
+ function attachInvocationObservation(target, context) {
2985
+ const snapshot = Object.freeze(context === void 0 ? {} : { context: Object.freeze({ ...context }) });
2986
+ Object.defineProperty(target, INVOCATION_OBSERVATION, {
2987
+ configurable: false,
2988
+ enumerable: false,
2989
+ value: snapshot,
2990
+ writable: false
2991
+ });
2992
+ return target;
2993
+ }
2994
+ /** @internal Read the snapshot without exposing its symbol or adding a wire field. */
2995
+ function readInvocationObservation(source) {
2996
+ if (typeof source !== "object" || source === null) return void 0;
2997
+ return source[INVOCATION_OBSERVATION];
2998
+ }
2999
+ /** @internal Carry a snapshot across an SDK adapter projection without resolving again. */
3000
+ function copyInvocationObservation(source, target) {
3001
+ const snapshot = readInvocationObservation(source);
3002
+ return snapshot === void 0 ? target : attachInvocationObservation(target, snapshot.context);
3003
+ }
3004
+ /** @internal Mark a failure envelope as already resolved at the public invocation boundary. */
3005
+ function markFailureInvocationSnapshot(failure) {
3006
+ Object.defineProperty(failure, FAILURE_INVOCATION_SNAPSHOT, {
3007
+ configurable: false,
3008
+ enumerable: false,
3009
+ value: true,
3010
+ writable: false
3011
+ });
3012
+ return failure;
3013
+ }
3014
+ /** @internal Distinguish public-boundary failures from direct adapter calls. */
3015
+ function hasFailureInvocationSnapshot(failure) {
3016
+ return typeof failure === "object" && failure !== null && failure[FAILURE_INVOCATION_SNAPSHOT] === true;
3017
+ }
3018
+ //#endregion
2863
3019
  //#region src/adapters/convex-call/ConvexCallAdapter.ts
3020
+ /** Exact floor-first allowlist; every additional handler must migrate its validator first. */
3021
+ const OBSERVED_CONVEX_ACTIONS = new Set(["subAccount/actions:transfer"]);
2864
3022
  var ConvexCallAdapter = class {
2865
3023
  #client;
2866
3024
  #tokenProvider;
3025
+ #applicationId;
3026
+ #observation;
2867
3027
  constructor(deps) {
2868
3028
  this.#client = deps.client ?? new ConvexClient(deps.convexUrl);
2869
3029
  this.#tokenProvider = deps.tokenProvider;
3030
+ this.#applicationId = deps.applicationId;
3031
+ this.#observation = deps.observation;
2870
3032
  if (this.#tokenProvider) this.#client.setAuth(this.#tokenProvider);
2871
3033
  }
2872
3034
  refreshAuth() {
@@ -2885,10 +3047,36 @@ var ConvexCallAdapter = class {
2885
3047
  });
2886
3048
  }
2887
3049
  action(fn, args) {
3050
+ const path = getFunctionName(fn);
2888
3051
  return Effect.tryPromise({
2889
- try: () => this.#client.action(fn, args),
2890
- catch: (cause) => mapToConvexCallError(getFunctionName(fn), cause)
3052
+ try: () => this.#client.action(fn, this.#observedActionArgs(path, args)),
3053
+ catch: (cause) => mapToConvexCallError(path, cause)
3054
+ });
3055
+ }
3056
+ #observedActionArgs(path, args) {
3057
+ if (!OBSERVED_CONVEX_ACTIONS.has(path)) return args;
3058
+ let hostContext;
3059
+ const invocationSnapshot = readInvocationObservation(args);
3060
+ if (invocationSnapshot !== void 0) hostContext = invocationSnapshot.context;
3061
+ else {
3062
+ const resolveContext = this.#observation?.resolveContext;
3063
+ if (resolveContext === void 0) return args;
3064
+ try {
3065
+ hostContext = resolveContext();
3066
+ } catch {
3067
+ return args;
3068
+ }
3069
+ }
3070
+ if (hostContext === void 0) return args;
3071
+ hostContext = sanitizeObservationContext({
3072
+ ...hostContext,
3073
+ ...this.#applicationId === void 0 ? {} : { applicationId: this.#applicationId }
2891
3074
  });
3075
+ if (hostContext === void 0) return args;
3076
+ return {
3077
+ ...args,
3078
+ observationContext: hostContext
3079
+ };
2892
3080
  }
2893
3081
  subscribe(fn, args, callback) {
2894
3082
  return Effect.try({
@@ -3556,7 +3744,7 @@ function fromWei(rawBalance, decimals, currency) {
3556
3744
  }
3557
3745
  //#endregion
3558
3746
  //#region src/adapters/account-read/ConvexAccountAdapter.ts
3559
- const DEFAULT_FUNCTIONS$3 = {
3747
+ const DEFAULT_FUNCTIONS$5 = {
3560
3748
  readBalance: makeFunctionReference("account/actions:readBalance"),
3561
3749
  faucetMint: makeFunctionReference("account/actions:faucetMint")
3562
3750
  };
@@ -3565,7 +3753,7 @@ var ConvexAccountAdapter = class {
3565
3753
  #fns;
3566
3754
  constructor(deps) {
3567
3755
  this.#convex = deps.convex;
3568
- this.#fns = deps.functions ?? DEFAULT_FUNCTIONS$3;
3756
+ this.#fns = deps.functions ?? DEFAULT_FUNCTIONS$5;
3569
3757
  }
3570
3758
  readBalance(input) {
3571
3759
  return this.#convex.action(this.#fns.readBalance, { chainId: wireChainId(input.chainId) }).pipe(Effect.mapError((error) => accountReadErrorFromCapxul("readBalance", error.publicError, error)), Effect.flatMap((wire) => brandAccountEffect("readBalance", wire)), Effect.catchAllDefect((cause) => Effect.fail(accountReadErrorFromUnknown("readBalance", cause))));
@@ -3618,7 +3806,7 @@ function subAccountErrorFromCapxul(operation, error, cause = error) {
3618
3806
  var SubAccountPortTag = class extends Context.Tag("@capxul/sdk/ports/SubAccountPort")() {};
3619
3807
  //#endregion
3620
3808
  //#region src/adapters/sub-account/ConvexSubAccountAdapter.ts
3621
- const DEFAULT_FUNCTIONS$2 = {
3809
+ const DEFAULT_FUNCTIONS$4 = {
3622
3810
  create: makeFunctionReference("subAccount/mutations:create"),
3623
3811
  get: makeFunctionReference("subAccount/queries:get"),
3624
3812
  list: makeFunctionReference("subAccount/queries:list"),
@@ -3633,7 +3821,7 @@ var ConvexSubAccountAdapter = class {
3633
3821
  constructor(deps) {
3634
3822
  this.#convex = deps.convex;
3635
3823
  this.#chainId = deps.chainId;
3636
- this.#fns = deps.functions ?? DEFAULT_FUNCTIONS$2;
3824
+ this.#fns = deps.functions ?? DEFAULT_FUNCTIONS$4;
3637
3825
  }
3638
3826
  create(input) {
3639
3827
  return this.#runMutation("create", this.#fns.create, {
@@ -3661,12 +3849,12 @@ var ConvexSubAccountAdapter = class {
3661
3849
  const operation = "transfer";
3662
3850
  return Effect.suspend(() => {
3663
3851
  const rawAmount = toWei(input.amount);
3664
- return this.#convex.action(this.#fns.transfer, {
3852
+ return this.#convex.action(this.#fns.transfer, copyInvocationObservation(input, {
3665
3853
  chainId: this.#chainId,
3666
3854
  from: input.from,
3667
3855
  to: input.to,
3668
3856
  rawAmount
3669
- });
3857
+ }));
3670
3858
  }).pipe(Effect.mapError((error) => subAccountErrorFromCapxul(operation, error.publicError, error)), Effect.map((wire) => brandTransferResult(wire)), Effect.catchAllDefect((cause) => Effect.fail(subAccountErrorFromUnknown(operation, cause))));
3671
3859
  }
3672
3860
  #runMutation(operation, ref, args) {
@@ -3717,7 +3905,7 @@ function smartAccountErrorFromCapxul(operation, error, cause = error) {
3717
3905
  var SmartAccountPortTag = class extends Context.Tag("@capxul/sdk/ports/SmartAccountPort")() {};
3718
3906
  //#endregion
3719
3907
  //#region src/adapters/smart-account/ConvexSmartAccountAdapter.ts
3720
- const DEFAULT_FUNCTIONS$1 = {
3908
+ const DEFAULT_FUNCTIONS$3 = {
3721
3909
  loadByAuthUserId: makeFunctionReference("smartAccount/queries:loadByAuthUserId"),
3722
3910
  loadBySmartAccountAddress: makeFunctionReference("smartAccount/queries:loadBySmartAccountAddress"),
3723
3911
  provision: makeFunctionReference("smartAccount/mutations:provision"),
@@ -3729,7 +3917,7 @@ var ConvexSmartAccountAdapter = class {
3729
3917
  #fns;
3730
3918
  constructor(deps) {
3731
3919
  this.#convex = deps.convex;
3732
- this.#fns = deps.functions ?? DEFAULT_FUNCTIONS$1;
3920
+ this.#fns = deps.functions ?? DEFAULT_FUNCTIONS$3;
3733
3921
  }
3734
3922
  loadByAuthUserId(authUserId) {
3735
3923
  return this.#convex.query(this.#fns.loadByAuthUserId, { authUserId }).pipe(Effect.mapError((error) => smartAccountErrorFromCapxul("loadByAuthUserId", error.publicError, error)), Effect.flatMap((row) => brandSmartAccountEffect("loadByAuthUserId", row)), Effect.catchAllDefect((cause) => Effect.fail(smartAccountErrorFromUnknown("loadByAuthUserId", cause))));
@@ -3804,6 +3992,424 @@ function smartAccountErrorFromUnknown(operation, cause) {
3804
3992
  toAddress("0xa6b71e26c5e0845f74c812102ca7114b6a896ab2");
3805
3993
  keccak256("0x");
3806
3994
  //#endregion
3995
+ //#region src/ports/org.ts
3996
+ var OrgError = class extends Data.TaggedError("OrgError") {};
3997
+ function orgErrorFromCapxul(operation, error, cause = error) {
3998
+ return new OrgError({
3999
+ operation,
4000
+ publicCode: error.code,
4001
+ publicError: error,
4002
+ cause,
4003
+ ...error.details === void 0 ? {} : { details: error.details }
4004
+ });
4005
+ }
4006
+ Context.Tag("@capxul/sdk/ports/OrgPort")();
4007
+ Context.Tag("@capxul/sdk/ports/OrgRolesDeploymentPort")();
4008
+ Context.Tag("@capxul/sdk/ports/OrgSpendPort")();
4009
+ //#endregion
4010
+ //#region src/adapters/org/parse.ts
4011
+ /**
4012
+ * Map a `WireOrg` + its (separately read) treasury `Account` into the branded
4013
+ * `OrgView`. The viewer role is projected by the authenticated backend read;
4014
+ * it must never be inferred from Organization ownership. Brands at the read
4015
+ * edge: `orgId`, `safeAddress`.
4016
+ */
4017
+ function brandOrgView(wire, treasury, viewerRole) {
4018
+ return {
4019
+ id: toOrgId(wire.orgId),
4020
+ name: wire.name,
4021
+ handle: wire.slug,
4022
+ safeAddress: toAddress(wire.safeAddress.toLowerCase()),
4023
+ role: viewerRole,
4024
+ treasury
4025
+ };
4026
+ }
4027
+ /**
4028
+ * Build the Org treasury `Account` from the raw on-chain `balanceOf` integer
4029
+ * (the D3 RPC read). `available === balance` for a treasury with no envelope
4030
+ * partition yet (a fresh Org reads back $0).
4031
+ */
4032
+ function brandOrgTreasury(input) {
4033
+ return {
4034
+ id: toAccountId(`account_${orgIdBody(input.orgId)}`),
4035
+ balance: input.money,
4036
+ available: input.money
4037
+ };
4038
+ }
4039
+ function brandOrgRole(wire) {
4040
+ return {
4041
+ orgId: toOrgId(wire.orgId),
4042
+ label: wire.label,
4043
+ roleKey: toRoleKey(wire.roleKey),
4044
+ definition: parseRoleDefinition(wire.definitionJson)
4045
+ };
4046
+ }
4047
+ function brandOrgMember(wire) {
4048
+ return {
4049
+ orgId: toOrgId(wire.orgId),
4050
+ email: toEmail(wire.email),
4051
+ name: wire.name,
4052
+ personalSafeAddress: wire.personalSafeAddress === null ? null : toAddress(wire.personalSafeAddress),
4053
+ role: wire.role,
4054
+ roleKey: wire.roleKey === null ? null : toRoleKey(wire.roleKey),
4055
+ status: wire.status,
4056
+ grantTxHash: wire.grantTxHash,
4057
+ revokeTxHash: wire.revokeTxHash
4058
+ };
4059
+ }
4060
+ function parseRoleDefinition(json) {
4061
+ let raw;
4062
+ try {
4063
+ const parsed = JSON.parse(json);
4064
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) throw new Error("expected object");
4065
+ raw = parsed;
4066
+ } catch (err) {
4067
+ throw new Error(`Invalid role definition: malformed JSON - ${err instanceof Error ? err.message : String(err)}`, { cause: err });
4068
+ }
4069
+ if (typeof raw.label !== "string" || raw.label.trim().length === 0) throw new Error("Invalid role definition: missing label");
4070
+ return {
4071
+ label: raw.label,
4072
+ ...raw.spend === void 0 ? {} : { spend: {
4073
+ ...raw.spend.perTx === void 0 ? {} : { perTx: parseRoleMoney(raw.spend.perTx, "perTx") },
4074
+ ...raw.spend.perDay === void 0 ? {} : { perDay: parseRoleMoney(raw.spend.perDay, "perDay") },
4075
+ ...raw.spend.toRecipients === void 0 ? {} : { toRecipients: parseRoleRecipients(raw.spend.toRecipients) }
4076
+ } },
4077
+ ...raw.subAccounts === void 0 ? {} : { subAccounts: parseRoleSubAccounts(raw.subAccounts) },
4078
+ ...typeof raw.canManageMembers === "boolean" ? { canManageMembers: raw.canManageMembers } : {},
4079
+ ...typeof raw.canManageRoles === "boolean" ? { canManageRoles: raw.canManageRoles } : {}
4080
+ };
4081
+ }
4082
+ function parseRoleMoney(raw, field) {
4083
+ if (typeof raw.currency !== "string" || typeof raw.value !== "string" || !/^\d+$/.test(raw.value) || raw.decimals !== 6) throw new Error(`Invalid role money: ${field}`);
4084
+ return {
4085
+ currency: toCurrencyCode(raw.currency),
4086
+ value: raw.value,
4087
+ decimals: raw.decimals
4088
+ };
4089
+ }
4090
+ function parseRoleRecipients(raw) {
4091
+ if (raw === "anyone") return "anyone";
4092
+ if (!Array.isArray(raw)) throw new Error("Invalid role definition: toRecipients must be \"anyone\" or an array");
4093
+ return raw.map((recipient) => {
4094
+ if (typeof recipient !== "string") throw new Error("Invalid role definition: toRecipients must be \"anyone\" or an array");
4095
+ return toAddress(recipient);
4096
+ });
4097
+ }
4098
+ function parseRoleSubAccounts(raw) {
4099
+ if (raw.scope === "all") return { scope: "all" };
4100
+ if (!Array.isArray(raw.scope)) throw new Error("Invalid role definition: subAccounts.scope must be \"all\" or an array");
4101
+ return { scope: raw.scope.map((subAccountId) => {
4102
+ if (typeof subAccountId !== "string") throw new Error("Invalid role definition: subAccounts.scope must be \"all\" or an array");
4103
+ return toSubAccountId(subAccountId);
4104
+ }) };
4105
+ }
4106
+ /** Strip the `org_` prefix + non-alphanumerics so the body re-seeds `account_`. */
4107
+ function orgIdBody(orgId) {
4108
+ const underscore = orgId.indexOf("_");
4109
+ const cleaned = (underscore < 0 ? orgId : orgId.slice(underscore + 1)).replace(/[^0-9A-Za-z]/g, "");
4110
+ return cleaned.length > 0 ? cleaned : "0";
4111
+ }
4112
+ //#endregion
4113
+ //#region src/adapters/org/ConvexOrganizationAdapter.ts
4114
+ const DEFAULT_FUNCTIONS$2 = {
4115
+ listAll: makeFunctionReference("org/queries:listAll"),
4116
+ listRoles: makeFunctionReference("org/queries:listRolesByOrgId"),
4117
+ listMembers: makeFunctionReference("org/queries:listMembersByOrgId"),
4118
+ readTreasury: makeFunctionReference("org/actions:readTreasury"),
4119
+ inviteMember: makeFunctionReference("org/actions:inviteMember"),
4120
+ resendInvite: makeFunctionReference("org/mutations:resendInviteToken"),
4121
+ detectInvitations: makeFunctionReference("org/actions:detectAndAcceptPendingInvitations")
4122
+ };
4123
+ /**
4124
+ * Standard production Organization read adapter. It intentionally has no
4125
+ * deployer/RPC/test configuration: authenticated Convex actions own live chain
4126
+ * reads, while the lifecycle adapter owns the single sponsored bootstrap.
4127
+ */
4128
+ var ConvexOrganizationAdapter = class {
4129
+ #convex;
4130
+ #fns;
4131
+ constructor(input) {
4132
+ this.#convex = input.convex;
4133
+ this.#fns = input.functions ?? DEFAULT_FUNCTIONS$2;
4134
+ }
4135
+ createOrg(_input) {
4136
+ return Effect.fail(orgErrorFromCapxul("createOrg", Errors.notImplemented("organizationSetup", "use onboarding.completeOrganization")));
4137
+ }
4138
+ listOrgs(_input) {
4139
+ return this.#convex.query(this.#fns.listAll, {}).pipe(Effect.mapError((error) => orgErrorFromCapxul("listOrgs", error.publicError, error)), Effect.flatMap((wires) => Effect.forEach(wires, (wire) => this.#readTreasuryWire(wire.orgId).pipe(Effect.map((treasury) => {
4140
+ const viewerRole = wire.viewerRole.trim();
4141
+ if (viewerRole.length === 0) throw Errors.wrongState({
4142
+ method: "listOrgs",
4143
+ currentState: "viewerRoleMissing",
4144
+ validStates: ["activeViewerRole"]
4145
+ });
4146
+ return brandOrgView(wire, treasury, viewerRole);
4147
+ })))), Effect.catchAllDefect((cause) => Effect.fail(toOrgError("listOrgs", cause))));
4148
+ }
4149
+ readTreasury(input) {
4150
+ return this.#readTreasuryWire(String(input.orgId)).pipe(Effect.catchAllDefect((cause) => Effect.fail(toOrgError("readTreasury", cause))));
4151
+ }
4152
+ listRoles(input) {
4153
+ 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.catchAllDefect((cause) => Effect.fail(toOrgError("listRoles", cause))));
4154
+ }
4155
+ listMembers(input) {
4156
+ 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.catchAllDefect((cause) => Effect.fail(toOrgError("listMembers", cause))));
4157
+ }
4158
+ pendingMembers(input) {
4159
+ return this.listMembers(input).pipe(Effect.map((members) => members.filter((member) => member.status === "pending" || member.status === "pending_safe" || member.status === "pending_grant")));
4160
+ }
4161
+ inviteMember(input) {
4162
+ return this.#convex.action(this.#fns.inviteMember, {
4163
+ orgId: input.orgId,
4164
+ email: input.input.email,
4165
+ role: input.input.role
4166
+ }).pipe(Effect.mapError((error) => orgErrorFromCapxul("inviteMember", error.publicError, error)), Effect.map(brandOrgMember), Effect.catchAllDefect((cause) => Effect.fail(toOrgError("inviteMember", cause))));
4167
+ }
4168
+ resendInviteToken(input) {
4169
+ return this.#convex.mutation(this.#fns.resendInvite, {
4170
+ orgId: input.orgId,
4171
+ email: input.email
4172
+ }).pipe(Effect.mapError((error) => orgErrorFromCapxul("resendInviteToken", error.publicError, error)), Effect.map(brandOrgMember), Effect.catchAllDefect((cause) => Effect.fail(toOrgError("resendInviteToken", cause))));
4173
+ }
4174
+ detectAndAcceptPendingInvitations(_input) {
4175
+ 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.catchAllDefect((cause) => Effect.fail(toOrgError("detectAndAcceptPendingInvitations", cause))));
4176
+ }
4177
+ #readTreasuryWire(orgId) {
4178
+ return this.#convex.action(this.#fns.readTreasury, { orgId }).pipe(Effect.mapError((error) => orgErrorFromCapxul("readTreasury", error.publicError, error)), Effect.map((wire) => {
4179
+ if (wire.orgId !== orgId) throw Errors.invalidInput("orgId", "Organization treasury scope does not match");
4180
+ const balance = fromWei(wire.rawBalance, wire.decimals, wire.currency);
4181
+ const available = fromWei(wire.rawAvailableBalance, wire.decimals, wire.currency);
4182
+ return {
4183
+ ...brandOrgTreasury({
4184
+ orgId: wire.orgId,
4185
+ money: balance
4186
+ }),
4187
+ available
4188
+ };
4189
+ }));
4190
+ }
4191
+ };
4192
+ function toOrgError(operation, cause) {
4193
+ if (cause instanceof CapxulError) return orgErrorFromCapxul(operation, cause);
4194
+ return orgErrorFromCapxul(operation, Errors.providerError("convex", operation, cause), cause);
4195
+ }
4196
+ function partialOrgTruth(operation, currentState) {
4197
+ return orgErrorFromCapxul(operation, Errors.wrongState({
4198
+ method: operation,
4199
+ currentState,
4200
+ validStates: ["completeProductionOrganizationTruth"]
4201
+ }));
4202
+ }
4203
+ //#endregion
4204
+ //#region src/adapters/org/ConvexOrganizationSetupAdapter.ts
4205
+ const DEFAULT_FUNCTIONS$1 = {
4206
+ startOrResume: makeFunctionReference("org/lifecycle:startOrResume"),
4207
+ prepareFounderAccount: makeFunctionReference("org/actions:prepareFounderAccount"),
4208
+ prepareBootstrap: makeFunctionReference("org/actions:prepareBootstrap"),
4209
+ submitBootstrap: makeFunctionReference("org/actions:submitBootstrap"),
4210
+ confirmBootstrap: makeFunctionReference("org/actions:confirmBootstrap"),
4211
+ recordFailure: makeFunctionReference("org/lifecycle:recordFailure"),
4212
+ load: makeFunctionReference("org/lifecycle:load"),
4213
+ retry: makeFunctionReference("org/lifecycle:retry")
4214
+ };
4215
+ /** Durable Organization setup capability composed by the standard client. */
4216
+ var ConvexOrganizationSetupAdapter = class {
4217
+ #convex;
4218
+ #signer;
4219
+ #fns;
4220
+ constructor(input) {
4221
+ this.#convex = input.convex;
4222
+ this.#signer = input.signer;
4223
+ this.#fns = input.functions ?? DEFAULT_FUNCTIONS$1;
4224
+ }
4225
+ async startOrResume(input) {
4226
+ const result = await runCall("startOrResume", this.#convex.mutation(this.#fns.startOrResume, input));
4227
+ if (!result.ok) return result;
4228
+ const lifecycle = parseLifecycle("startOrResume", result.value.lifecycle);
4229
+ if (!lifecycle.ok) return lifecycle;
4230
+ const orgId = parseOrgId("startOrResume", result.value.orgId);
4231
+ if (!orgId.ok) return orgId;
4232
+ if (String(orgId.value) !== String(lifecycle.value.orgId)) return fail$2(Errors.invalidInput("orgId", "Organization lifecycle scope does not match"));
4233
+ return {
4234
+ ok: true,
4235
+ value: {
4236
+ orgId: orgId.value,
4237
+ lifecycle: lifecycle.value
4238
+ }
4239
+ };
4240
+ }
4241
+ prepareFounderAccount(input) {
4242
+ return this.#lifecycleAction("prepareFounderAccount", input, () => this.#convex.action(this.#fns.prepareFounderAccount, { orgId: input.orgId }));
4243
+ }
4244
+ async authorizeAndSubmitBootstrap(input) {
4245
+ const cancelled = cancellation(input.signal);
4246
+ if (cancelled !== void 0) return cancelled;
4247
+ const signerAddress = await signerResult("getAddress", () => this.#signer.getAddress());
4248
+ if (!signerAddress.ok) return signerAddress;
4249
+ const prepared = await runCall("prepareBootstrap", this.#convex.action(this.#fns.prepareBootstrap, {
4250
+ orgId: input.orgId,
4251
+ signerAddress: signerAddress.value
4252
+ }));
4253
+ if (!prepared.ok) return prepared;
4254
+ const authority = validatePreparedAuthorities(prepared.value, signerAddress.value);
4255
+ if (!authority.ok) return authority;
4256
+ const cancelledAfterPrepare = cancellation(input.signal);
4257
+ if (cancelledAfterPrepare !== void 0) return cancelledAfterPrepare;
4258
+ const signature = await signerResult("signUserOpHash", () => this.#signer.signUserOpHash(prepared.value.digest));
4259
+ if (!signature.ok) return signature;
4260
+ const cancelledAfterSign = cancellation(input.signal);
4261
+ if (cancelledAfterSign !== void 0) return cancelledAfterSign;
4262
+ const submitted = await runCall("submitBootstrap", this.#convex.action(this.#fns.submitBootstrap, {
4263
+ orgId: input.orgId,
4264
+ signerAddress: signerAddress.value,
4265
+ signature: signature.value,
4266
+ userOp: prepared.value.userOp
4267
+ }));
4268
+ if (!submitted.ok) return submitted;
4269
+ return parseLifecycle("submitBootstrap", submitted.value);
4270
+ }
4271
+ confirmSubmittedBootstrap(input) {
4272
+ return this.#lifecycleAction("confirmBootstrap", input, () => this.#convex.action(this.#fns.confirmBootstrap, { orgId: input.orgId }));
4273
+ }
4274
+ async recordFailure(input) {
4275
+ const result = await runCall("recordFailure", this.#convex.mutation(this.#fns.recordFailure, {
4276
+ orgId: input.orgId,
4277
+ at: input.at,
4278
+ errorCode: input.error.code,
4279
+ retryable: input.retryable
4280
+ }));
4281
+ return result.ok ? parseLifecycle("recordFailure", result.value) : result;
4282
+ }
4283
+ async loadLifecycle(input) {
4284
+ const result = await runCall("loadLifecycle", this.#convex.query(this.#fns.load, input));
4285
+ if (!result.ok) return result;
4286
+ if (result.value === null) return fail$2(Errors.invalidInput("orgId", "Organization lifecycle was not found"));
4287
+ return parseLifecycle("loadLifecycle", result.value);
4288
+ }
4289
+ async retry(input) {
4290
+ const cancelled = cancellation(input.signal);
4291
+ if (cancelled !== void 0) return cancelled;
4292
+ const result = await runCall("retry", this.#convex.mutation(this.#fns.retry, { orgId: input.orgId }));
4293
+ return result.ok ? parseLifecycle("retry", result.value) : result;
4294
+ }
4295
+ async #lifecycleAction(operation, input, call) {
4296
+ const cancelled = cancellation(input.signal);
4297
+ if (cancelled !== void 0) return cancelled;
4298
+ const result = await runCall(operation, call());
4299
+ if (!result.ok) return result;
4300
+ const cancelledAfter = cancellation(input.signal);
4301
+ if (cancelledAfter !== void 0) return cancelledAfter;
4302
+ return parseLifecycle(operation, result.value);
4303
+ }
4304
+ };
4305
+ async function runCall(operation, effect) {
4306
+ try {
4307
+ const result = await Effect.runPromise(Effect.either(effect));
4308
+ return Either.isRight(result) ? {
4309
+ ok: true,
4310
+ value: result.right
4311
+ } : fail$2(publicError(operation, result.left));
4312
+ } catch (cause) {
4313
+ return fail$2(publicError(operation, cause));
4314
+ }
4315
+ }
4316
+ function publicError(operation, cause) {
4317
+ if (cause instanceof CapxulError) return cause;
4318
+ if (typeof cause === "object" && cause !== null) {
4319
+ const carried = cause.publicError;
4320
+ if (carried instanceof CapxulError) return carried;
4321
+ }
4322
+ return Errors.providerError("convex-organization", operation, cause);
4323
+ }
4324
+ async function signerResult(operation, run) {
4325
+ try {
4326
+ return {
4327
+ ok: true,
4328
+ value: await run()
4329
+ };
4330
+ } catch (cause) {
4331
+ return fail$2(Errors.providerError("organization-signer", operation, cause));
4332
+ }
4333
+ }
4334
+ function validatePreparedAuthorities(prepared, signerAddress) {
4335
+ const signer = signerAddress.toLowerCase();
4336
+ const preparedSigner = prepared.signerAddress.toLowerCase();
4337
+ const founder = prepared.founderPersonalAccount.toLowerCase();
4338
+ const organization = prepared.organizationAccountAddress.toLowerCase();
4339
+ const sender = prepared.userOp.sender.toLowerCase();
4340
+ if (preparedSigner !== signer) return fail$2(Errors.invalidInput("signerAddress", "Prepared signer does not match configured signer"));
4341
+ if (founder === signer || organization === signer || organization === founder) return fail$2(Errors.invalidInput("organizationAuthority", "Signer EOA, founder Account, and Organization Account must be distinct"));
4342
+ if (sender !== founder) return fail$2(Errors.invalidInput("userOp.sender", "Bootstrap sender must be the founder Account"));
4343
+ if (!/^0x[0-9a-fA-F]{64}$/u.test(prepared.digest)) return fail$2(Errors.invalidInput("digest", "Prepared bootstrap digest must be 32-byte hex"));
4344
+ return {
4345
+ ok: true,
4346
+ value: void 0
4347
+ };
4348
+ }
4349
+ function parseLifecycle(operation, wire) {
4350
+ const orgId = parseOrgId(operation, wire.orgId);
4351
+ if (!orgId.ok) return orgId;
4352
+ if (wire.status === "loading") return {
4353
+ ok: true,
4354
+ value: {
4355
+ status: "loading",
4356
+ orgId: orgId.value
4357
+ }
4358
+ };
4359
+ if (wire.status === "ready") return {
4360
+ ok: true,
4361
+ value: {
4362
+ status: "ready",
4363
+ orgId: orgId.value,
4364
+ canTransact: true
4365
+ }
4366
+ };
4367
+ if (wire.status === "failed") {
4368
+ if (!isSetupStep(wire.at)) return fail$2(Errors.invalidInput("lifecycle.at", "Unknown setup step"));
4369
+ return {
4370
+ ok: true,
4371
+ value: {
4372
+ status: "failed",
4373
+ orgId: orgId.value,
4374
+ at: wire.at,
4375
+ error: new CapxulError(wire.error.code, wire.error.message),
4376
+ retryable: wire.retryable
4377
+ }
4378
+ };
4379
+ }
4380
+ if (!isSetupStep(wire.step)) return fail$2(Errors.invalidInput("lifecycle.step", `Unknown setup step from ${operation}`));
4381
+ return {
4382
+ ok: true,
4383
+ value: {
4384
+ status: "settingUp",
4385
+ orgId: orgId.value,
4386
+ step: wire.step
4387
+ }
4388
+ };
4389
+ }
4390
+ function parseOrgId(operation, value) {
4391
+ try {
4392
+ return {
4393
+ ok: true,
4394
+ value: toOrgId(value)
4395
+ };
4396
+ } catch (cause) {
4397
+ return fail$2(Errors.providerError("convex-organization", operation, cause));
4398
+ }
4399
+ }
4400
+ function isSetupStep(value) {
4401
+ return value === "preparingFounderAccount" || value === "awaitingFounderAuthorization" || value === "submittingBootstrap" || value === "confirmingBootstrap";
4402
+ }
4403
+ function cancellation(signal) {
4404
+ return signal?.aborted ? fail$2(Errors.cancelled({ operation: "organization.setup" })) : void 0;
4405
+ }
4406
+ function fail$2(error) {
4407
+ return {
4408
+ ok: false,
4409
+ error
4410
+ };
4411
+ }
4412
+ //#endregion
3807
4413
  //#region ../observability/src/index.ts
3808
4414
  const PII = Schema.String.pipe(Schema.brand("PII"));
3809
4415
  const OptionalString = Schema.optional(Schema.String);
@@ -3963,6 +4569,10 @@ const TransferRequestedProps = Schema.Struct({
3963
4569
  amount: OptionalWeiAmount,
3964
4570
  direction: OptionalTransferDirection
3965
4571
  });
4572
+ const TransferBackendReceivedProps = Schema.Struct({
4573
+ ...TelemetryEnvelopeProps,
4574
+ direction: OptionalTransferDirection
4575
+ });
3966
4576
  const TransferConfirmedProps = Schema.Struct({
3967
4577
  ...TelemetryEnvelopeProps,
3968
4578
  amount: OptionalWeiAmount,
@@ -4179,6 +4789,10 @@ Schema.Struct({
4179
4789
  name: Schema.Literal("transfer_requested"),
4180
4790
  props: Schema.optional(TransferRequestedProps)
4181
4791
  });
4792
+ Schema.Struct({
4793
+ name: Schema.Literal("transfer_backend_received"),
4794
+ props: Schema.optional(TransferBackendReceivedProps)
4795
+ });
4182
4796
  Schema.Struct({
4183
4797
  name: Schema.Literal("transfer_confirmed"),
4184
4798
  props: Schema.optional(TransferConfirmedProps)
@@ -7282,6 +7896,76 @@ function listOrgsProgram() {
7282
7896
  });
7283
7897
  }
7284
7898
  //#endregion
7899
+ //#region src/client/org-lifecycle.ts
7900
+ function fail$1(error) {
7901
+ return {
7902
+ ok: false,
7903
+ error
7904
+ };
7905
+ }
7906
+ function validateOrganizationLifecycleScope(orgId, lifecycle) {
7907
+ if (String(lifecycle.orgId) !== String(orgId)) return fail$1(Errors.invalidInput("orgId", "Organization lifecycle scope does not match"));
7908
+ return {
7909
+ ok: true,
7910
+ value: lifecycle
7911
+ };
7912
+ }
7913
+ /** Advance only the steps still required by one durable Organization lane. */
7914
+ async function advanceOrganizationSetup(setup, orgId, initial, signal) {
7915
+ const scopedInitial = validateOrganizationLifecycleScope(orgId, initial);
7916
+ if (!scopedInitial.ok) return scopedInitial;
7917
+ let lifecycle = scopedInitial.value;
7918
+ for (let transition = 0; transition < 3; transition += 1) {
7919
+ if (lifecycle.status !== "settingUp") return {
7920
+ ok: true,
7921
+ value: lifecycle
7922
+ };
7923
+ const currentStep = lifecycle.step;
7924
+ if (signal?.aborted) {
7925
+ const cancelled = Errors.cancelled({ operation: "organization.setup" });
7926
+ return recordRetryableCancellation(setup, orgId, lifecycle.step, cancelled);
7927
+ }
7928
+ const stepInput = {
7929
+ orgId,
7930
+ ...signal === void 0 ? {} : { signal }
7931
+ };
7932
+ const next = lifecycle.step === "preparingFounderAccount" ? await setup.prepareFounderAccount(stepInput) : lifecycle.step === "awaitingFounderAuthorization" || lifecycle.step === "submittingBootstrap" ? await setup.authorizeAndSubmitBootstrap(stepInput) : await setup.confirmSubmittedBootstrap(stepInput);
7933
+ if (!next.ok) return next.error.code === "CANCELLED" ? recordRetryableCancellation(setup, orgId, lifecycle.step, next.error) : next;
7934
+ const scopedNext = validateOrganizationLifecycleScope(orgId, next.value);
7935
+ if (!scopedNext.ok) return scopedNext;
7936
+ lifecycle = scopedNext.value;
7937
+ if (currentStep === "confirmingBootstrap") return {
7938
+ ok: true,
7939
+ value: lifecycle
7940
+ };
7941
+ }
7942
+ if (lifecycle.status !== "settingUp" || lifecycle.step === "confirmingBootstrap") return {
7943
+ ok: true,
7944
+ value: lifecycle
7945
+ };
7946
+ return fail$1(Errors.wrongState({
7947
+ method: "organization.setup",
7948
+ currentState: lifecycle.step,
7949
+ validStates: [
7950
+ "confirmingBootstrap",
7951
+ "ready",
7952
+ "failed"
7953
+ ]
7954
+ }));
7955
+ }
7956
+ async function recordRetryableCancellation(setup, orgId, at, cancelled) {
7957
+ const recorded = await setup.recordFailure({
7958
+ orgId,
7959
+ at,
7960
+ error: cancelled,
7961
+ retryable: true
7962
+ });
7963
+ if (!recorded.ok) return recorded;
7964
+ const scopedRecorded = validateOrganizationLifecycleScope(orgId, recorded.value);
7965
+ if (!scopedRecorded.ok) return scopedRecorded;
7966
+ return fail$1(cancelled);
7967
+ }
7968
+ //#endregion
7285
7969
  //#region src/client/org.ts
7286
7970
  /**
7287
7971
  * Org method surface (canon §C2/§C3, D13). S1 (#274) wires `createOrg` /
@@ -7330,6 +8014,36 @@ function makeOrgMethods(deps) {
7330
8014
  },
7331
8015
  ...convexCall === void 0 ? {} : { convexCall }
7332
8016
  }),
8017
+ async getLifecycle(options) {
8018
+ if (options?.signal?.aborted) return {
8019
+ ok: false,
8020
+ error: Errors.cancelled({ operation: "org.getLifecycle" })
8021
+ };
8022
+ if (deps.organizationSetup === void 0) return {
8023
+ ok: false,
8024
+ error: Errors.notImplemented("organizationSetup", "getLifecycle")
8025
+ };
8026
+ const loaded = await deps.organizationSetup.loadLifecycle({ orgId });
8027
+ if (!loaded.ok) return loaded;
8028
+ return validateOrganizationLifecycleScope(orgId, loaded.value);
8029
+ },
8030
+ async retrySetup(options) {
8031
+ if (options?.signal?.aborted) return {
8032
+ ok: false,
8033
+ error: Errors.cancelled({ operation: "org.retrySetup" })
8034
+ };
8035
+ const setup = deps.organizationSetup;
8036
+ if (setup === void 0) return {
8037
+ ok: false,
8038
+ error: Errors.notImplemented("organizationSetup", "retrySetup")
8039
+ };
8040
+ const retried = await setup.retry({
8041
+ orgId,
8042
+ ...options?.signal === void 0 ? {} : { signal: options.signal }
8043
+ });
8044
+ if (!retried.ok) return retried;
8045
+ return advanceOrganizationSetup(setup, orgId, retried.value, options?.signal);
8046
+ },
7333
8047
  profile: {
7334
8048
  get(_options) {
7335
8049
  if (_options?.signal?.aborted) return Promise.resolve({
@@ -7363,12 +8077,12 @@ function makeOrgMethods(deps) {
7363
8077
  ok: false,
7364
8078
  error: treasury.error
7365
8079
  };
7366
- const orgs = await toCapxulResult(listOrgsProgram(), layer);
7367
- if (!orgs.ok) return {
8080
+ const orgList = await toCapxulResult(listOrgsProgram(), layer);
8081
+ if (!orgList.ok) return {
7368
8082
  ok: false,
7369
- error: orgs.error
8083
+ error: orgList.error
7370
8084
  };
7371
- const org = orgs.value.find((candidate) => candidate.id === orgId);
8085
+ const org = orgList.value.find((candidate) => candidate.id === orgId);
7372
8086
  return {
7373
8087
  ok: true,
7374
8088
  value: {
@@ -7556,7 +8270,6 @@ function normalizePaymentTiming(payment) {
7556
8270
  }
7557
8271
  //#endregion
7558
8272
  //#region src/flows/onboarding.ts
7559
- const DEFAULT_ORG_TEMPLATE = "Startup";
7560
8273
  async function runCompletePersonalOnboarding(ops, input) {
7561
8274
  const validated = validatePersonalInput(input);
7562
8275
  if (!validated.ok) return validated;
@@ -7580,11 +8293,13 @@ async function runCompletePersonalOnboarding(ops, input) {
7580
8293
  value: { lifecycle: lifecycle.value }
7581
8294
  };
7582
8295
  }
7583
- async function runCompleteOrganizationOnboarding(ops, input) {
8296
+ async function runCompleteOrganizationOnboarding(ops, input, options) {
7584
8297
  const validated = validateOrganizationInput(input);
7585
8298
  if (!validated.ok) return validated;
7586
8299
  const session = await ops.currentSession();
7587
8300
  if (session === null) return fail(Errors.notAuthenticated());
8301
+ const setup = ops.organizationSetup;
8302
+ if (setup === void 0) return fail(Errors.notImplemented("organizationSetup", "completeOrganization"));
7588
8303
  const written = await ops.completeIdentityOnboarding({
7589
8304
  authUserId: session.authUserId,
7590
8305
  email: session.email,
@@ -7592,22 +8307,18 @@ async function runCompleteOrganizationOnboarding(ops, input) {
7592
8307
  country: validated.value.country
7593
8308
  });
7594
8309
  if (!written.ok) return fail(written.error);
7595
- const provisioned = await ops.triggerProvisioning();
7596
- if (!provisioned.ok) return fail(provisioned.error);
7597
- const org = await ops.createOrg({
8310
+ const started = await setup.startOrResume({
7598
8311
  name: validated.value.organizationName,
7599
8312
  handle: validated.value.handle,
7600
- template: DEFAULT_ORG_TEMPLATE,
7601
8313
  country: validated.value.country
7602
8314
  });
7603
- if (!org.ok) return fail(org.error);
7604
- ops.kickProvisioning();
7605
- const lifecycle = await ops.readLifecycle();
7606
- if (!lifecycle.ok) return fail(lifecycle.error);
8315
+ if (!started.ok) return fail(started.error);
8316
+ const lifecycle = await advanceOrganizationSetup(setup, started.value.orgId, started.value.lifecycle, options?.signal);
8317
+ if (!lifecycle.ok) return lifecycle;
7607
8318
  return {
7608
8319
  ok: true,
7609
8320
  value: {
7610
- org: org.value,
8321
+ orgId: started.value.orgId,
7611
8322
  lifecycle: lifecycle.value
7612
8323
  }
7613
8324
  };
@@ -7698,8 +8409,7 @@ function fail(error) {
7698
8409
  * Onboarding method surface. The thin namespace over the `flows/onboarding.ts`
7699
8410
  * choreography: it adds the `signal`-abort pre-check and delegates to the run
7700
8411
  * functions. The `OnboardingOps` seam is supplied by `assembleCapxulClient`
7701
- * (real ops over the account lane + createOrg + IdentityPort) or by tests
7702
- * (in-memory double).
8412
+ * (real identity/Account ops plus Organization setup capability) or by tests.
7703
8413
  */
7704
8414
  function makeOnboardingMethods(ops) {
7705
8415
  return {
@@ -7715,7 +8425,7 @@ function makeOnboardingMethods(ops) {
7715
8425
  ok: false,
7716
8426
  error: Errors.cancelled({ operation: "onboarding.completeOrganization" })
7717
8427
  });
7718
- return runCompleteOrganizationOnboarding(ops, input);
8428
+ return runCompleteOrganizationOnboarding(ops, input, options);
7719
8429
  }
7720
8430
  };
7721
8431
  }
@@ -7794,7 +8504,8 @@ function assembleCapxulClient(input) {
7794
8504
  ...selectedOrgPort === void 0 ? {} : { orgPort: selectedOrgPort },
7795
8505
  ...input.orgRolesDeploymentPort === void 0 ? {} : { orgRolesDeploymentPort: input.orgRolesDeploymentPort },
7796
8506
  ...input.orgSpendPort === void 0 ? {} : { orgSpendPort: input.orgSpendPort },
7797
- convexCall: input.ports.convexCall
8507
+ convexCall: input.ports.convexCall,
8508
+ ...input.organizationSetup === void 0 ? {} : { organizationSetup: input.organizationSetup }
7798
8509
  });
7799
8510
  if (selectedOrgPort !== void 0) detectPendingOrgInvitations = async () => {
7800
8511
  await orgMethods.orgs.detectAndAcceptPendingInvitations();
@@ -7817,7 +8528,7 @@ function assembleCapxulClient(input) {
7817
8528
  triggerProvisioning: () => account._internal.provision(),
7818
8529
  kickProvisioning: () => kickProvisioning?.(),
7819
8530
  readLifecycle: () => account.getLifecycle(),
7820
- createOrg: (createOrgInput) => orgMethods.createOrg(createOrgInput)
8531
+ ...input.organizationSetup === void 0 ? {} : { organizationSetup: input.organizationSetup }
7821
8532
  });
7822
8533
  return {
7823
8534
  auth,
@@ -7859,45 +8570,6 @@ function assembleCapxulClient(input) {
7859
8570
  const SDK_VERSION$1 = version;
7860
8571
  /** Stable PostHog event used for typed failures that are expected product outcomes. */
7861
8572
  const CAPXUL_SDK_EXPECTED_OUTCOME_EVENT = "capxul_sdk_expected_outcome";
7862
- const EXPECTED_OPERATION_OUTCOMES = new Set([
7863
- "INVALID_INPUT",
7864
- "NOT_AUTHENTICATED",
7865
- "CANCELLED",
7866
- "SIGNER_REJECTED",
7867
- "VERIFICATION_REQUIRED",
7868
- "INSUFFICIENT_BALANCE",
7869
- "INVALID_RECIPIENT",
7870
- "ROLE_PERMISSION_DENIED",
7871
- "RATE_LIMITED",
7872
- "OTP_EXPIRED",
7873
- "WRONG_STATE"
7874
- ]);
7875
- const CONTEXT_PROPERTY_RULES = {
7876
- application: {
7877
- maxLength: 64,
7878
- pattern: /^[A-Za-z0-9][A-Za-z0-9._-]*$/u
7879
- },
7880
- release: {
7881
- maxLength: 128,
7882
- pattern: /^[A-Za-z0-9][A-Za-z0-9._+@:/-]*$/u
7883
- },
7884
- session_id: {
7885
- maxLength: 128,
7886
- pattern: /^[A-Za-z0-9][A-Za-z0-9._:-]*$/u
7887
- },
7888
- organization_id: {
7889
- maxLength: 128,
7890
- pattern: /^[A-Za-z0-9][A-Za-z0-9._:-]*$/u
7891
- },
7892
- correlation_id: {
7893
- maxLength: 128,
7894
- pattern: /^[A-Za-z0-9][A-Za-z0-9._:-]*$/u
7895
- }
7896
- };
7897
- const EMBEDDED_WALLET_MATERIAL = /0x[a-fA-F0-9]{40,}/u;
7898
- const RAW_PRIVATE_KEY_MATERIAL = /(?:^|[^a-fA-F0-9])[a-fA-F0-9]{64}(?:$|[^a-fA-F0-9])/u;
7899
- const COMPACT_JWT = /eyJ[A-Za-z0-9_-]*\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/u;
7900
- const KNOWN_CREDENTIAL_PREFIX = /(?:(?:sk|pk|rk)_(?:live|test)|(?:phc|phx|ghp|gho|ghu|ghs|ghr|whsec)_|github_pat_|xox[baprs]-|AKIA[0-9A-Z]{16}|AIza)[A-Za-z0-9_-]*/iu;
7901
8573
  /**
7902
8574
  * Adapt the host's already-initialized PostHog-like client. This function does
7903
8575
  * not import, initialize, configure, or own PostHog.
@@ -7907,7 +8579,7 @@ function fromPostHog(client, options = {}) {
7907
8579
  if (!isEnabled(options.enabled)) return;
7908
8580
  if (client === null || client === void 0) return;
7909
8581
  const safeFailure = sanitizeFailureObservation(failure);
7910
- return [safeFailure, postHogProperties(safeFailure, resolveContext(options.context))];
8582
+ return [safeFailure, postHogProperties(safeFailure, hasFailureInvocationSnapshot(failure) ? void 0 : resolveContext(options.context))];
7911
8583
  };
7912
8584
  const captureOperationFailure = (failure) => {
7913
8585
  const prepared = prepare(failure);
@@ -7932,6 +8604,10 @@ function fromPostHog(client, options = {}) {
7932
8604
  deliver(() => client.captureException(safeFailure.exception, properties));
7933
8605
  };
7934
8606
  return {
8607
+ resolveContext: () => {
8608
+ if (!isEnabled(options.enabled) || client === null || client === void 0) return void 0;
8609
+ return resolveRawContext(options.context) ?? {};
8610
+ },
7935
8611
  captureOperationFailure,
7936
8612
  captureException
7937
8613
  };
@@ -7944,6 +8620,34 @@ function deliver(capture) {
7944
8620
  ignoreDeliveryFailure(capture());
7945
8621
  } catch {}
7946
8622
  }
8623
+ /**
8624
+ * Fan one SDK failure out to several adapters (issue #877). The SDK's own
8625
+ * first-party relay and an optional host-provided adapter both observe the same
8626
+ * failure. Order matters for `resolveContext`: the FIRST adapter that returns a
8627
+ * context wins, so pass the host adapter first to keep its call-start snapshot.
8628
+ * Each capture is isolated — a throwing adapter never blocks its peers or the
8629
+ * SDK. Returns `undefined` when no adapters are present (zero observation work).
8630
+ */
8631
+ function composeObservationAdapters(...adapters) {
8632
+ const present = adapters.filter((adapter) => adapter !== void 0);
8633
+ if (present.length === 0) return void 0;
8634
+ if (present.length === 1) return present[0];
8635
+ const fanOut = (select) => {
8636
+ for (const adapter of present) try {
8637
+ ignoreDeliveryFailure(select(adapter));
8638
+ } catch {}
8639
+ };
8640
+ return {
8641
+ resolveContext: () => {
8642
+ for (const adapter of present) try {
8643
+ const context = adapter.resolveContext?.();
8644
+ if (context !== void 0) return context;
8645
+ } catch {}
8646
+ },
8647
+ captureOperationFailure: (failure) => fanOut((adapter) => adapter.captureOperationFailure(failure)),
8648
+ captureException: (failure) => fanOut((adapter) => adapter.captureException(failure))
8649
+ };
8650
+ }
7947
8651
  /** @internal Decorates public client method bundles at the owning SDK boundary. */
7948
8652
  function observeSdkClient(client, adapter) {
7949
8653
  if (adapter === void 0) return client;
@@ -7982,18 +8686,20 @@ function observeSdkClient(client, adapter) {
7982
8686
  if (cached !== void 0) return cached;
7983
8687
  const wrapped = new Proxy(callable, {
7984
8688
  apply(currentTarget, _thisArg, args) {
8689
+ const invocationContext = resolveAdapterContext(adapter);
8690
+ const invocationArgs = carryInvocationContext(operation, args, invocationContext);
7985
8691
  let output;
7986
8692
  try {
7987
- output = Reflect.apply(currentTarget, owner, args);
8693
+ output = Reflect.apply(currentTarget, owner, invocationArgs);
7988
8694
  } catch (cause) {
7989
- report(adapter, "exception", operation, cause);
8695
+ report(adapter, "exception", operation, cause, invocationContext);
7990
8696
  throw cause;
7991
8697
  }
7992
- if (isPromiseLike(output)) return Promise.resolve(output).then((result) => processOutput(result, path), (cause) => {
7993
- report(adapter, "exception", operation, cause);
8698
+ if (isPromiseLike(output)) return Promise.resolve(output).then((result) => processOutput(result, path, invocationContext), (cause) => {
8699
+ report(adapter, "exception", operation, cause, invocationContext);
7994
8700
  throw cause;
7995
8701
  });
7996
- return processOutput(output, path);
8702
+ return processOutput(output, path, invocationContext);
7997
8703
  },
7998
8704
  get(currentTarget, property) {
7999
8705
  const attached = Reflect.get(currentTarget, property, currentTarget);
@@ -8006,9 +8712,9 @@ function observeSdkClient(client, adapter) {
8006
8712
  }
8007
8713
  return isPlainObject(value) ? wrapObject(value, path) : value;
8008
8714
  };
8009
- const processOutput = (output, path) => {
8715
+ const processOutput = (output, path, invocationContext) => {
8010
8716
  if (isFailedResult(output)) {
8011
- report(adapter, "operation", path.join("."), output.error);
8717
+ report(adapter, "operation", path.join("."), output.error, invocationContext);
8012
8718
  return output;
8013
8719
  }
8014
8720
  if (isCapxulResult(output)) return output;
@@ -8016,24 +8722,40 @@ function observeSdkClient(client, adapter) {
8016
8722
  };
8017
8723
  return wrapObject(client, []);
8018
8724
  }
8725
+ function carryInvocationContext(operation, args, context) {
8726
+ if (operation !== "subAccounts.transfer" || !isPlainObject(args[0])) return args;
8727
+ return [attachInvocationObservation({ ...args[0] }, context), ...args.slice(1)];
8728
+ }
8019
8729
  /** @internal Reports a factory-level typed failure without changing its identity. */
8020
8730
  function observeFailedResult(result, adapter, operation) {
8021
- if (adapter !== void 0 && isFailedResult(result)) report(adapter, "operation", operation, result.error);
8731
+ if (adapter !== void 0 && isFailedResult(result)) report(adapter, "operation", operation, result.error, resolveAdapterContext(adapter));
8022
8732
  return result;
8023
8733
  }
8024
- function report(adapter, kind, operation, cause) {
8734
+ function report(adapter, kind, operation, cause, invocationContext) {
8025
8735
  const operationName = normalizeOperation(operation);
8026
8736
  const kindName = normalizeErrorKind(errorKind(cause));
8027
- const failure = {
8737
+ const context = sanitizeObservationContext({
8738
+ ...invocationContext,
8739
+ ...isCapxulError(cause) && cause.correlationId !== void 0 ? { correlationId: cause.correlationId } : {}
8740
+ });
8741
+ const failure = markFailureInvocationSnapshot({
8028
8742
  exception: syntheticException(operationName, kindName),
8029
8743
  sdkVersion: SDK_VERSION$1,
8030
8744
  operation: operationName,
8031
- errorKind: kindName
8032
- };
8745
+ errorKind: kindName,
8746
+ ...context === void 0 ? {} : { context }
8747
+ });
8033
8748
  try {
8034
8749
  ignoreDeliveryFailure(kind === "operation" ? adapter.captureOperationFailure(failure) : adapter.captureException(failure));
8035
8750
  } catch {}
8036
8751
  }
8752
+ function resolveAdapterContext(adapter) {
8753
+ try {
8754
+ return adapter.resolveContext?.();
8755
+ } catch {
8756
+ return;
8757
+ }
8758
+ }
8037
8759
  function ignoreDeliveryFailure(delivery) {
8038
8760
  if (!isPromiseLike(delivery)) return;
8039
8761
  try {
@@ -8047,23 +8769,23 @@ function postHogProperties(failure, context) {
8047
8769
  error_kind: failure.errorKind,
8048
8770
  handled: true
8049
8771
  };
8050
- assignSafeContext(properties, "application", context?.application);
8051
- assignSafeContext(properties, "release", context?.release);
8052
- assignSafeContext(properties, "session_id", context?.sessionId);
8053
- assignSafeContext(properties, "organization_id", context?.organizationId);
8054
- assignSafeContext(properties, "correlation_id", context?.correlationId);
8772
+ const merged = sanitizeObservationContext({
8773
+ ...context,
8774
+ ...failure.context
8775
+ });
8776
+ if (merged?.application !== void 0) properties.application = merged.application;
8777
+ if (merged?.release !== void 0) properties.release = merged.release;
8778
+ if (merged?.sessionId !== void 0) properties.session_id = merged.sessionId;
8779
+ if (merged?.organizationId !== void 0) properties.organization_id = merged.organizationId;
8780
+ if (merged?.correlationId !== void 0) properties.correlation_id = merged.correlationId;
8781
+ if (merged?.anonymousId !== void 0) properties.anonymous_id = merged.anonymousId;
8055
8782
  return properties;
8056
8783
  }
8057
- function assignSafeContext(properties, key, value) {
8058
- if (typeof value !== "string") return;
8059
- const rule = CONTEXT_PROPERTY_RULES[key];
8060
- if (value.length === 0 || value.length > rule.maxLength || value !== value.trim() || value.includes("://") || containsSensitiveContext(value) || !rule.pattern.test(value)) return;
8061
- properties[key] = value;
8062
- }
8063
- function containsSensitiveContext(value) {
8064
- return EMBEDDED_WALLET_MATERIAL.test(value) || RAW_PRIVATE_KEY_MATERIAL.test(value) || COMPACT_JWT.test(value) || KNOWN_CREDENTIAL_PREFIX.test(value);
8065
- }
8066
8784
  function resolveContext(context) {
8785
+ return sanitizeObservationContext(resolveRawContext(context));
8786
+ }
8787
+ /** Resolve the host context closure without sanitizing — the call-start snapshot. */
8788
+ function resolveRawContext(context) {
8067
8789
  try {
8068
8790
  return typeof context === "function" ? context() : context;
8069
8791
  } catch {
@@ -8089,11 +8811,13 @@ function errorKind(cause) {
8089
8811
  function sanitizeFailureObservation(failure) {
8090
8812
  const operation = normalizeOperation(failure.operation);
8091
8813
  const kind = normalizeErrorKind(failure.errorKind);
8814
+ const context = sanitizeObservationContext(failure.context);
8092
8815
  return {
8093
8816
  exception: syntheticException(operation, kind),
8094
8817
  sdkVersion: normalizeSdkVersion(failure.sdkVersion),
8095
8818
  operation,
8096
- errorKind: kind
8819
+ errorKind: kind,
8820
+ ...context === void 0 ? {} : { context }
8097
8821
  };
8098
8822
  }
8099
8823
  function normalizeSdkVersion(value) {
@@ -8125,6 +8849,43 @@ function isCapxulResult(value) {
8125
8849
  function isFailedResult(value) {
8126
8850
  return isCapxulResult(value) && value.ok === false && "error" in value;
8127
8851
  }
8852
+ //#endregion
8853
+ //#region src/observation-relay.ts
8854
+ /**
8855
+ * Build the SDK-owned first-party relay adapter. Both capture entry points send
8856
+ * the same redacted envelope fire-and-forget; delivery is fully isolated from
8857
+ * the SDK's `CapxulResult` and can never throw into the caller.
8858
+ */
8859
+ function createCapxulFirstPartyRelay(options) {
8860
+ const fetchImpl = options.fetch ?? resolveGlobalFetch();
8861
+ const send = (failure) => {
8862
+ if (fetchImpl === void 0) return;
8863
+ try {
8864
+ const headers = { "content-type": "application/json" };
8865
+ const encodedContext = encodeObservationContextHeader(failure.context);
8866
+ if (encodedContext !== void 0) headers[OBSERVATION_CONTEXT_HEADER] = encodedContext;
8867
+ const body = JSON.stringify({
8868
+ operation: failure.operation,
8869
+ error_kind: failure.errorKind,
8870
+ sdk_version: failure.sdkVersion
8871
+ });
8872
+ Promise.resolve(fetchImpl(options.ingestUrl, {
8873
+ method: "POST",
8874
+ headers,
8875
+ body,
8876
+ keepalive: true
8877
+ })).catch(() => void 0);
8878
+ } catch {}
8879
+ };
8880
+ return {
8881
+ captureOperationFailure: send,
8882
+ captureException: send
8883
+ };
8884
+ }
8885
+ function resolveGlobalFetch() {
8886
+ const candidate = globalThis.fetch;
8887
+ return typeof candidate === "function" ? candidate : void 0;
8888
+ }
8128
8889
  const SDK_VERSION = version;
8129
8890
  const collectProductionFlowPorts = Effect.gen(function* () {
8130
8891
  const authClient = yield* AuthClientPortTag;
@@ -8232,11 +8993,13 @@ function productionBootstrapPortLayer(bootstrap) {
8232
8993
  function productionAuthClientLayer(input, refreshConvexAuthRef) {
8233
8994
  return (input.runtime === "browser" ? BetterAuthBrowserLayer({
8234
8995
  authBaseUrl: input.runtimeUrls.authBaseUrl,
8235
- ...input.fetch === void 0 ? {} : { fetch: input.fetch }
8996
+ ...input.fetch === void 0 ? {} : { fetch: input.fetch },
8997
+ ...input.observation === void 0 ? {} : { observation: input.observation }
8236
8998
  }) : BetterAuthNodeLayer({
8237
8999
  authBaseUrl: input.runtimeUrls.authBaseUrl,
8238
9000
  ...input.origin === void 0 ? {} : { origin: input.origin },
8239
- ...input.fetch === void 0 ? {} : { fetch: input.fetch }
9001
+ ...input.fetch === void 0 ? {} : { fetch: input.fetch },
9002
+ ...input.observation === void 0 ? {} : { observation: input.observation }
8240
9003
  })).pipe(Layer.map((context) => {
8241
9004
  const authClient = Context.get(context, AuthClientPortTag);
8242
9005
  return Context.make(AuthClientPortTag, refreshConvexAuthOnSession(authClient, () => {
@@ -8255,6 +9018,8 @@ function productionAuthCacheLayer(input) {
8255
9018
  function productionConvexCallLayer(input, refreshConvexAuthRef) {
8256
9019
  return Layer.unwrapEffect(Effect.map(AuthClientPortTag, (authClient) => ConvexCallLayer({
8257
9020
  convexUrl: input.runtimeUrls.convexUrl,
9021
+ ...input.applicationId === void 0 ? {} : { applicationId: input.applicationId },
9022
+ ...input.observation === void 0 ? {} : { observation: input.observation },
8258
9023
  ...input.convexClient === void 0 ? {} : { client: input.convexClient },
8259
9024
  tokenProvider: async ({ forceRefreshToken }) => {
8260
9025
  const tokenResult = await Effect.runPromise(Effect.either(authClient.getConvexJwt({
@@ -8286,7 +9051,8 @@ async function createProductionAdapters(input) {
8286
9051
  const closeScope = idempotentClose(() => Effect.runPromise(Scope.close(scope, Exit.void)));
8287
9052
  const bootstrapLayer = HttpBootstrapLayer({
8288
9053
  bootstrapBaseUrl: resolvedInput.value.bootstrapBaseUrl,
8289
- ...input.fetch === void 0 ? {} : { fetch: input.fetch }
9054
+ ...input.fetch === void 0 ? {} : { fetch: input.fetch },
9055
+ ...input.observation === void 0 ? {} : { observation: input.observation }
8290
9056
  });
8291
9057
  try {
8292
9058
  const bootstrapContext = await Effect.runPromise(Layer.buildWithScope(bootstrapLayer, scope));
@@ -8344,6 +9110,8 @@ async function createProductionAdapters(input) {
8344
9110
  ...resolvedInput.value.origin === void 0 ? {} : { origin: resolvedInput.value.origin },
8345
9111
  runtimeUrls: runtimeUrls.value,
8346
9112
  chainId: bootstrapResult.value.chainId,
9113
+ applicationId: bootstrapResult.value.applicationId,
9114
+ ...input.observation === void 0 ? {} : { observation: input.observation },
8347
9115
  ...input.authCache === void 0 ? {} : { authCache: input.authCache },
8348
9116
  ...input.telemetry === void 0 ? {} : { telemetry: input.telemetry },
8349
9117
  ...injectedClient === void 0 ? {} : { convexClient: injectedClient },
@@ -8405,7 +9173,7 @@ async function createCapxulClient$1(input) {
8405
9173
  ...input.authBaseUrl === void 0 ? {} : { override: input.authBaseUrl }
8406
9174
  });
8407
9175
  let signer = input.signer;
8408
- if (signer === void 0 && (input.requirement ?? "none") === "deployed" && runtime === "browser") signer = createOpenfortBrowserSignerFromBootstrap({
9176
+ if (signer === void 0 && runtime === "browser") signer = createOpenfortBrowserSignerFromBootstrap({
8409
9177
  ...adapters.value.bootstrap,
8410
9178
  authBaseUrl: resolvedAuthBaseUrl
8411
9179
  });
@@ -8415,23 +9183,33 @@ async function createCapxulClient$1(input) {
8415
9183
  authCache: adapters.value.ports.authCache,
8416
9184
  requirement: input.requirement ?? "none",
8417
9185
  ...signer === void 0 ? {} : { signer },
9186
+ orgPort: new ConvexOrganizationAdapter({ convex: adapters.value.ports.convexCall }),
9187
+ ...signer === void 0 ? {} : { organizationSetup: new ConvexOrganizationSetupAdapter({
9188
+ convex: adapters.value.ports.convexCall,
9189
+ signer
9190
+ }) },
8418
9191
  ...input.signal === void 0 ? {} : { signal: input.signal },
8419
9192
  ...input.otpTtlMs === void 0 ? {} : { otpTtlMs: input.otpTtlMs },
8420
9193
  invokeTimeoutMs: input.invokeTimeoutMs ?? 3e4
8421
9194
  }), signer);
8422
9195
  const upstreamClose = adapters.value.close;
9196
+ const value = {
9197
+ ...client,
9198
+ _internal: {
9199
+ ...client._internal,
9200
+ close: async () => {
9201
+ if ("resetSession" in (signer ?? {})) signer.resetSession();
9202
+ await upstreamClose();
9203
+ }
9204
+ }
9205
+ };
9206
+ const relay = runtime === "browser" ? createCapxulFirstPartyRelay({
9207
+ ingestUrl: deriveObserveIngestUrl(adapters.value.bootstrap),
9208
+ ...input.fetch === void 0 ? {} : { fetch: input.fetch }
9209
+ }) : void 0;
8423
9210
  return {
8424
9211
  ok: true,
8425
- value: observeSdkClient({
8426
- ...client,
8427
- _internal: {
8428
- ...client._internal,
8429
- close: async () => {
8430
- if ("resetSession" in (signer ?? {})) signer.resetSession();
8431
- await upstreamClose();
8432
- }
8433
- }
8434
- }, input.observation)
9212
+ value: observeSdkClient(value, composeObservationAdapters(input.observation, relay))
8435
9213
  };
8436
9214
  } catch (cause) {
8437
9215
  await adapters.value.close().catch(() => void 0);
@@ -8473,6 +9251,38 @@ function resolveInput(input) {
8473
9251
  };
8474
9252
  }
8475
9253
  }
9254
+ /**
9255
+ * Address of the Capxul client-relay ingest endpoint (Pipe 1, issue #877). The
9256
+ * HTTP router that serves `/v1/client/observe` lives on the deployment's
9257
+ * `.convex.site` host, while the bootstrap-resolved `convexUrl` is the sibling
9258
+ * `.convex.cloud` (WebSocket/query) host — the same deterministic pairing
9259
+ * `mintQuickstartKey` inverts. For any standard Convex deployment (including
9260
+ * production) rewriting the suffix targets the router directly with no host
9261
+ * proxy, so it is the primary rule.
9262
+ *
9263
+ * `siteBaseUrl` is deliberately NOT the primary source: it is an app-configured
9264
+ * field that defaults to a placeholder (`https://capxul.local`, see
9265
+ * `credentials/applications.ts`) for registered applications, so trusting it
9266
+ * outright would POST to a dead host for the common case. It is only consulted
9267
+ * as a fallback for a custom-domain `convexUrl` (no deterministic `.convex.site`
9268
+ * sibling) when it carries a real, non-placeholder origin.
9269
+ */
9270
+ function deriveObserveIngestUrl(bootstrap) {
9271
+ const convexUrl = bootstrap.convexUrl.replace(/\/+$/, "");
9272
+ if (convexUrl.endsWith(".convex.cloud")) return `${convexUrl.replace(/\.convex\.cloud$/, ".convex.site")}/v1/client/observe`;
9273
+ return `${(usableSiteOrigin(bootstrap.siteBaseUrl) ?? convexUrl).replace(/\/+$/, "")}/v1/client/observe`;
9274
+ }
9275
+ /** A configured `siteBaseUrl` usable as a router host, or `undefined` if it is the placeholder. */
9276
+ function usableSiteOrigin(siteBaseUrl) {
9277
+ try {
9278
+ const url = new URL(siteBaseUrl);
9279
+ if (url.protocol !== "http:" && url.protocol !== "https:") return void 0;
9280
+ if (url.hostname === "capxul.local") return void 0;
9281
+ return url.origin;
9282
+ } catch {
9283
+ return;
9284
+ }
9285
+ }
8476
9286
  function detectRuntime() {
8477
9287
  const globalAny = globalThis;
8478
9288
  return globalAny.window !== void 0 || globalAny.document !== void 0 ? "browser" : "node";