@capxul/sdk 2.7.0 → 2.8.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,15 +1,32 @@
1
- import { A as toPartyId, B as Errors, G as failureFingerprint, H as CHAIN_UPSTREAMS, K as isFailureMode, M as toPayrollRunId, P as toRoleKey, R as CapxulError, S as toCurrencyCode, U as FAILURE_MODES$1, V as isCapxulError, W as chainCauseProperties, b as toChainId, c as BYTES32_RE, d as WEI_RE, f as ZERO_BYTES32, h as toAddress, j as toPayrollGroupId, k as toOrgId, l as EVM_ADDRESS_RE$1, m as toAccountId, n as BrowserAuthCacheAdapter, s as APP_ID_RE, t as InMemoryAuthCacheAdapter, u as SUPPORTED_CURRENCY_CODES, v as toAuthUserId, w as toEmail, x as toCountryCode, y as toBudgetId, z as EXPECTED_OPERATION_OUTCOMES } from "./InMemoryAuthCacheAdapter-B6PHyzCN.mjs";
1
+ import { A as toPartyId, B as Errors, G as decodeChainCause, H as CHAIN_UPSTREAMS, J as revertSummaryText, K as failureFingerprint, L as CAPXUL_ERROR_CODES, M as toPayrollRunId, P as toRoleKey, R as CapxulError, S as toCurrencyCode, U as FAILURE_MODES$1, V as isCapxulError, W as chainCauseProperties, b as toChainId, c as BYTES32_RE, d as WEI_RE, f as ZERO_BYTES32, h as toAddress, j as toPayrollGroupId, k as toOrgId, l as EVM_ADDRESS_RE$1, m as toAccountId, n as BrowserAuthCacheAdapter, q as isFailureMode, s as APP_ID_RE, t as InMemoryAuthCacheAdapter, u as SUPPORTED_CURRENCY_CODES, v as toAuthUserId, w as toEmail, x as toCountryCode, y as toBudgetId, z as EXPECTED_OPERATION_OUTCOMES } from "./InMemoryAuthCacheAdapter-BrEN-men.mjs";
2
2
  import { concat, encodeAbiParameters, encodeFunctionData, encodePacked, formatUnits, getContractAddress, keccak256, padHex, parseUnits, recoverAddress, stringToHex, toBytes, toEventSelector, toFunctionSelector, toFunctionSignature } from "viem";
3
3
  import { Context, Data, Deferred, Duration, Effect, Exit, Fiber, Layer, Queue, Ref, Result, Schema, SchemaGetter, Scope } from "effect";
4
4
  import { makeFunctionReference } from "convex/server";
5
5
  //#region src/domain/identity/model.ts
6
6
  const WRONG = { refused: "WRONG_STATE" };
7
7
  /** org-lifecycle.ts:173-184, lifted verbatim. */
8
+ /**
9
+ * Causes that do not change on a retry: the same request reverts, is refused,
10
+ * or fails the same pre-flight again. A retry re-enters the same lane and
11
+ * fails the same way (the GS205 loop of 2026-09-02).
12
+ */
13
+ const DEFINITIVE_PROVIDER_MODES = /* @__PURE__ */ new Set([
14
+ "auth-origin-mismatch",
15
+ "app-env-allowlist",
16
+ "no-secure-context",
17
+ "signer-not-ready",
18
+ "revert",
19
+ "insufficient-balance",
20
+ "insufficient-allowance",
21
+ "rejected",
22
+ "unauthorized"
23
+ ]);
8
24
  const isRetryable = (failure) => {
9
25
  if (failure.code === "CANCELLED" || failure.code === "SIGNER_REJECTED") return true;
10
26
  if (failure.code === "PROVIDER_ERROR") {
11
- const mode = failure.mode;
12
- return mode !== "auth-origin-mismatch" && mode !== "app-env-allowlist" && mode !== "no-secure-context";
27
+ const chainRetryable = failure.error?.chain?.retryable;
28
+ if (chainRetryable !== void 0) return chainRetryable;
29
+ return !DEFINITIVE_PROVIDER_MODES.has(failure.mode);
13
30
  }
14
31
  return failure.code === "NETWORK_ERROR" || failure.code === "UNKNOWN";
15
32
  };
@@ -3028,6 +3045,50 @@ function isSafeField(field, value) {
3028
3045
  return value.length > 0 && value.length <= rule.maxLength && value === value.trim() && !value.includes("://") && !containsSensitiveMaterial(value) && rule.pattern.test(value);
3029
3046
  }
3030
3047
  //#endregion
3048
+ //#region src/internal/invocation-observation.ts
3049
+ const INVOCATION_OBSERVATION = Symbol("capxul.invocation-observation");
3050
+ const FAILURE_INVOCATION_SNAPSHOT = Symbol("capxul.failure-invocation-snapshot");
3051
+ /** @internal Attach one immutable, non-wire invocation snapshot to an SDK-owned object. */
3052
+ function attachInvocationObservation(target, source) {
3053
+ const snapshot = Object.freeze(source.context === void 0 ? { active: source.active } : {
3054
+ active: source.active,
3055
+ context: Object.freeze({ ...source.context })
3056
+ });
3057
+ Object.defineProperty(target, INVOCATION_OBSERVATION, {
3058
+ configurable: false,
3059
+ enumerable: false,
3060
+ value: snapshot,
3061
+ writable: false
3062
+ });
3063
+ return target;
3064
+ }
3065
+ /** @internal Read the snapshot without exposing its symbol or adding a wire field. */
3066
+ function readInvocationObservation(source) {
3067
+ if (typeof source !== "object" || source === null) return void 0;
3068
+ return source[INVOCATION_OBSERVATION];
3069
+ }
3070
+ /** @internal Carry a snapshot across an SDK adapter projection without resolving again. */
3071
+ function copyInvocationObservation(source, target) {
3072
+ const snapshot = readInvocationObservation(source);
3073
+ return snapshot === void 0 ? target : attachInvocationObservation(target, snapshot);
3074
+ }
3075
+ /** @internal Carry the public call-start delivery decision with its failure envelope. */
3076
+ function markFailureInvocationSnapshot(failure, snapshot) {
3077
+ Object.defineProperty(failure, FAILURE_INVOCATION_SNAPSHOT, {
3078
+ configurable: false,
3079
+ enumerable: false,
3080
+ value: Object.freeze(snapshot),
3081
+ writable: false
3082
+ });
3083
+ return failure;
3084
+ }
3085
+ /** @internal Read the call-start delivery decision; undefined means a direct adapter call. */
3086
+ function readFailureInvocationSnapshot(failure) {
3087
+ if (typeof failure !== "object" || failure === null) return void 0;
3088
+ const snapshot = failure[FAILURE_INVOCATION_SNAPSHOT];
3089
+ return typeof snapshot === "object" && snapshot !== null && "active" in snapshot ? snapshot : void 0;
3090
+ }
3091
+ //#endregion
3031
3092
  //#region src/surface/_shared/provisioning-telemetry.ts
3032
3093
  async function emitProvisioningTelemetry(telemetry, smartAccount) {
3033
3094
  if (telemetry === void 0) return;
@@ -3105,9 +3166,29 @@ function* causeChain(cause) {
3105
3166
  current = current.cause;
3106
3167
  }
3107
3168
  }
3169
+ const SIGNER_NOT_READY_CODES = /* @__PURE__ */ new Set(["MISSING_SIGNER", "NOT_CONFIGURED"]);
3170
+ function isOpenfortSignerNotReadyCode(value) {
3171
+ return typeof value === "string" && SIGNER_NOT_READY_CODES.has(value);
3172
+ }
3173
+ /** Return the exact Openfort code that requires an embedded-signer rebuild. */
3174
+ function openfortSignerNotReadyCode(cause) {
3175
+ for (const link of causeChain(cause)) {
3176
+ const error = link;
3177
+ for (const value of [
3178
+ error.error,
3179
+ error.code,
3180
+ error.details?.provider_error_code
3181
+ ]) if (isOpenfortSignerNotReadyCode(value)) return value;
3182
+ }
3183
+ }
3184
+ /** Openfort's typed signal that its embedded signer state must be rebuilt. */
3185
+ function isSignerNotReadySignal(cause) {
3186
+ return openfortSignerNotReadyCode(cause) !== void 0;
3187
+ }
3108
3188
  /** Fold a signer throw into the public error contract. */
3109
3189
  function signerFailure(source, operation, cause) {
3110
3190
  let failureMode;
3191
+ const providerErrorCode = source === "openfort-embedded" ? openfortSignerNotReadyCode(cause) : void 0;
3111
3192
  for (const link of causeChain(cause)) {
3112
3193
  if (link instanceof CapxulError && link.code === "SIGNER_REJECTED") return link;
3113
3194
  failureMode = getFailureMode(link) ?? failureMode;
@@ -3116,8 +3197,15 @@ function signerFailure(source, operation, cause) {
3116
3197
  source,
3117
3198
  cause
3118
3199
  });
3200
+ if (providerErrorCode !== void 0) failureMode = "signer-not-ready";
3119
3201
  }
3120
- return Errors.providerError("signer", operation, cause, failureMode === void 0 ? void 0 : { failure_mode: failureMode });
3202
+ return Errors.providerError("signer", operation, cause, failureMode === void 0 && providerErrorCode === void 0 ? void 0 : {
3203
+ ...failureMode === void 0 ? {} : { failure_mode: failureMode },
3204
+ ...providerErrorCode === void 0 ? {} : { details: {
3205
+ provider_error_source: "openfort",
3206
+ provider_error_code: providerErrorCode
3207
+ } }
3208
+ });
3121
3209
  }
3122
3210
  /**
3123
3211
  * Browser `CapxulSigner` backed by an injected EIP-1193 wallet (MetaMask, etc.).
@@ -3169,50 +3257,6 @@ async function recoverRawDigestSigner(input) {
3169
3257
  }
3170
3258
  }
3171
3259
  //#endregion
3172
- //#region src/internal/invocation-observation.ts
3173
- const INVOCATION_OBSERVATION = Symbol("capxul.invocation-observation");
3174
- const FAILURE_INVOCATION_SNAPSHOT = Symbol("capxul.failure-invocation-snapshot");
3175
- /** @internal Attach one immutable, non-wire invocation snapshot to an SDK-owned object. */
3176
- function attachInvocationObservation(target, source) {
3177
- const snapshot = Object.freeze(source.context === void 0 ? { active: source.active } : {
3178
- active: source.active,
3179
- context: Object.freeze({ ...source.context })
3180
- });
3181
- Object.defineProperty(target, INVOCATION_OBSERVATION, {
3182
- configurable: false,
3183
- enumerable: false,
3184
- value: snapshot,
3185
- writable: false
3186
- });
3187
- return target;
3188
- }
3189
- /** @internal Read the snapshot without exposing its symbol or adding a wire field. */
3190
- function readInvocationObservation(source) {
3191
- if (typeof source !== "object" || source === null) return void 0;
3192
- return source[INVOCATION_OBSERVATION];
3193
- }
3194
- /** @internal Carry a snapshot across an SDK adapter projection without resolving again. */
3195
- function copyInvocationObservation(source, target) {
3196
- const snapshot = readInvocationObservation(source);
3197
- return snapshot === void 0 ? target : attachInvocationObservation(target, snapshot);
3198
- }
3199
- /** @internal Carry the public call-start delivery decision with its failure envelope. */
3200
- function markFailureInvocationSnapshot(failure, snapshot) {
3201
- Object.defineProperty(failure, FAILURE_INVOCATION_SNAPSHOT, {
3202
- configurable: false,
3203
- enumerable: false,
3204
- value: Object.freeze(snapshot),
3205
- writable: false
3206
- });
3207
- return failure;
3208
- }
3209
- /** @internal Read the call-start delivery decision; undefined means a direct adapter call. */
3210
- function readFailureInvocationSnapshot(failure) {
3211
- if (typeof failure !== "object" || failure === null) return void 0;
3212
- const snapshot = failure[FAILURE_INVOCATION_SNAPSHOT];
3213
- return typeof snapshot === "object" && snapshot !== null && "active" in snapshot ? snapshot : void 0;
3214
- }
3215
- //#endregion
3216
3260
  //#region src/domain/machine/telemetry.ts
3217
3261
  const definedEntries = (values) => Object.fromEntries(Object.entries(values).filter((entry) => entry[1] !== void 0));
3218
3262
  const SAFE_ENGINEERING_ID = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
@@ -3674,21 +3718,27 @@ async function runIdentityFacade(verb, controls, run, runPromise = Effect.runPro
3674
3718
  async function runPortEffect(effect, controls, operation = "port", runPromise = Effect.runPromise) {
3675
3719
  const deadlineDelay = controls?.deadlineMs === void 0 ? void 0 : Math.max(0, controls.deadlineMs - Date.now());
3676
3720
  const timeoutMs = controls?.timeoutMs === void 0 ? deadlineDelay : deadlineDelay === void 0 ? controls.timeoutMs : Math.min(controls.timeoutMs, deadlineDelay);
3677
- const observed = (timeoutMs === void 0 ? effect : effect.pipe(Effect.timeoutOrElse({
3721
+ return runCapxulEffect((timeoutMs === void 0 ? effect : effect.pipe(Effect.timeoutOrElse({
3678
3722
  duration: `${timeoutMs} millis`,
3679
3723
  orElse: () => Effect.fail({ publicError: Errors.providerTimeout("sdk", operation, timeoutMs) })
3680
- }))).pipe(Effect.tap(() => Effect.annotateCurrentSpan({ outcome: "succeeded" })), Effect.tapError((failure) => {
3681
- const mode = failure.publicError.details?.failure_mode;
3724
+ }))).pipe(Effect.mapError((failure) => failure.publicError)), controls, operation, runPromise);
3725
+ }
3726
+ /** Observe a public Effect that already uses the canonical CapxulError channel. */
3727
+ async function runCapxulEffect(effect, controls, operation = "port", runPromise = Effect.runPromise) {
3728
+ const invocation = readInvocationObservation(controls);
3729
+ const correlationId = safeEngineeringIdentifier(controls?.correlation_id ?? invocation?.context?.correlationId);
3730
+ const observed = effect.pipe(Effect.tap(() => Effect.annotateCurrentSpan({ outcome: "succeeded" })), Effect.tapError((error) => {
3731
+ const mode = error.mode ?? error.details?.failure_mode;
3682
3732
  return Effect.annotateCurrentSpan({
3683
- outcome: portFailureOutcome(failure.publicError.code),
3684
- failure_code: failure.publicError.code,
3733
+ outcome: portFailureOutcome(error.code),
3734
+ failure_code: error.code,
3685
3735
  ...typeof mode === "string" ? { mode } : {}
3686
3736
  });
3687
3737
  }), Effect.tapDefect(() => Effect.annotateCurrentSpan({
3688
3738
  outcome: "failed",
3689
3739
  failure_code: "UNKNOWN"
3690
- })), Effect.withSpan(`identity.port.${operation}`));
3691
- return runIfActive(controls?.signal, operation, () => withInvocationParentSpan(observed, controls), runPromise);
3740
+ })), Effect.withSpan(`identity.port.${operation}`), Effect.annotateSpans(correlationId === void 0 ? {} : { correlation_id: correlationId }));
3741
+ return runIfActive(controls?.signal, operation, () => withInvocationParentSpan(observed, controls).pipe(Effect.mapError((publicError) => ({ publicError }))), runPromise);
3692
3742
  }
3693
3743
  /** Map machine-internal failure state onto the public SDK error vocabulary. */
3694
3744
  function publicIdentityFailure(failure) {
@@ -4403,7 +4453,7 @@ function makeAccountMethods(deps) {
4403
4453
  value: provisioningPhase(deps.actor.snapshot())
4404
4454
  };
4405
4455
  };
4406
- const resolveLifecycle = async () => {
4456
+ const resolveLifecycle = async (controls) => {
4407
4457
  const phase = provisioningPhase(deps.actor.snapshot());
4408
4458
  const status = await getStatus();
4409
4459
  if (!status.ok) return accountFailureResult(status.error);
@@ -4411,7 +4461,7 @@ function makeAccountMethods(deps) {
4411
4461
  if (status.value.status !== "notAuthenticated" && (phase.status === "ready" || isRequirementMet(status.value, requirement))) {
4412
4462
  const accountReadPort = deps.accountReadPort;
4413
4463
  if (accountReadPort === void 0) return accountFailureResult(Errors.invalidInput("account", "accountReadPort is required to resolve ready lifecycle"));
4414
- const account = await runPortEffect(accountReadPort.readBalance({ chainId: toChainId(deps.chainId) }));
4464
+ const account = await runPortEffect(accountReadPort.readBalance(copyInvocationObservation(controls, { chainId: toChainId(deps.chainId) })), controls, "accounts.read", deps.runPromise);
4415
4465
  if (!account.ok) return accountFailureResult(account.error);
4416
4466
  accountId = String(account.value.id);
4417
4467
  }
@@ -4425,8 +4475,9 @@ function makeAccountMethods(deps) {
4425
4475
  })
4426
4476
  };
4427
4477
  };
4428
- const getLifecycle = () => resolveLifecycle();
4478
+ const getLifecycle = () => resolveLifecycle(deps.invocationControls?.());
4429
4479
  const retrySetup = async () => {
4480
+ const controls = deps.invocationControls?.();
4430
4481
  const resetSession = deps.signer?.resetSession;
4431
4482
  if (typeof resetSession === "function") try {
4432
4483
  resetSession.call(deps.signer);
@@ -4435,7 +4486,7 @@ function makeAccountMethods(deps) {
4435
4486
  }
4436
4487
  const retried = await drive({ _tag: "RetryAccount" });
4437
4488
  if (!retried.ok) return accountFailureResult(retried.error);
4438
- return resolveLifecycle();
4489
+ return resolveLifecycle(controls);
4439
4490
  };
4440
4491
  return {
4441
4492
  methods: {
@@ -4495,146 +4546,45 @@ const moneyExecutionContract = {
4495
4546
  };
4496
4547
  //#endregion
4497
4548
  //#region package.json
4498
- var version = "2.7.0";
4549
+ var version = "2.8.2";
4499
4550
  //#endregion
4500
- //#region src/telemetry/stack-frame-parser.ts
4501
- /**
4502
- * Regex for V8/Chrome stack trace frame lines.
4503
- * Matches:
4504
- * `at functionName (url:line:col)`
4505
- * `at url:line:col`
4506
- * `at async functionName (url:line:col)`
4507
- * `at new ClassName (url:line:col)`
4508
- */
4509
- const V8_FRAME_RE = /^\s*at\s+(?:(.+?)\s+\()?(?:(.+?)(?::(\d+):(\d+))?|(.+?))\)?\s*$/;
4510
- function isNonUrlName(name) {
4511
- return name === "<anonymous>" || name.startsWith("eval") || name.startsWith("new ") || name.startsWith("async ");
4512
- }
4513
- /**
4514
- * Parse a V8/Chrome-style stack trace string into PostHog `ExceptionFrame` objects.
4515
- * Returns an empty array when `error.stack` is absent or empty.
4516
- *
4517
- * Handles:
4518
- * - Standard `at functionName (url:line:col)`
4519
- * - Bare `at url:line:col` (no function name)
4520
- * - `at async functionName (url:line:col)`
4521
- * - `at new ClassName (url:line:col)`
4522
- * - Native frames: `at Array.forEach (<anonymous>)`
4523
- */
4524
- function parseV8StackFrames(error) {
4525
- const stack = error.stack;
4526
- if (stack === void 0 || stack === null || stack === "") return [];
4527
- const lines = stack.split("\n");
4528
- const frames = [];
4529
- for (const line of lines) {
4530
- const trimmed = line.trim();
4531
- if (!trimmed.startsWith("at ")) continue;
4532
- const match = V8_FRAME_RE.exec(trimmed);
4533
- if (match === null) continue;
4534
- if (match[1] !== void 0) frames.push({
4535
- function: match[1],
4536
- filename: match[2],
4537
- lineno: match[3] !== void 0 ? Number(match[3]) : null,
4538
- colno: match[4] !== void 0 ? Number(match[4]) : null
4539
- });
4540
- else if (match[2] !== void 0 && !isNonUrlName(match[2])) frames.push({
4541
- function: "<anonymous>",
4542
- filename: match[2],
4543
- lineno: match[3] !== void 0 ? Number(match[3]) : null,
4544
- colno: match[4] !== void 0 ? Number(match[4]) : null
4545
- });
4546
- else frames.push({
4547
- function: match[1] ?? match[2] ?? match[5] ?? "<anonymous>",
4548
- filename: match[2] ?? match[5] ?? "<anonymous>",
4549
- lineno: match[3] !== void 0 ? Number(match[3]) : null,
4550
- colno: match[4] !== void 0 ? Number(match[4]) : null
4551
- });
4552
- }
4553
- return frames;
4551
+ //#region src/telemetry/exception-projection.ts
4552
+ /** Fixed fallback for failures that have no safe message. */
4553
+ const EXCEPTION_MESSAGE = "Capxul SDK operation failed";
4554
+ const SDK_VERSION = version;
4555
+ /** The one PostHog Error Tracking projection for every SDK exception emitter. */
4556
+ function projectSdkException(input) {
4557
+ const operation = normalizeExceptionOperation(input.operation);
4558
+ const errorKind = normalizeExceptionErrorKind(input.errorKind);
4559
+ const mode = isFailureMode(input.failureMode) ? input.failureMode : void 0;
4560
+ const message = input.message ?? "Capxul SDK operation failed";
4561
+ const where = input.chainUpstream === void 0 ? "" : ` on ${input.chainUpstream}${input.chainMethod === void 0 ? "" : ` during ${input.chainMethod}`}`;
4562
+ return {
4563
+ ...input.properties,
4564
+ sdk_version: input.sdkVersion,
4565
+ operation,
4566
+ error_kind: errorKind,
4567
+ handled: true,
4568
+ $exception_type: errorKind,
4569
+ $exception_message: message,
4570
+ $exception_level: "error",
4571
+ $exception_fingerprint: failureFingerprint(errorKind, mode, operation),
4572
+ $issue_name: `${errorKind}${mode === void 0 ? "" : `: ${mode}`}${where} (${operation})`,
4573
+ $issue_description: input.issueDescription ?? message,
4574
+ $exception_list: input.exceptionList
4575
+ };
4554
4576
  }
4555
- /** Fixed, leak-safe frame used when the error carries no parseable stack. */
4556
- const SDK_BOUNDARY_FILENAME = "capxul-sdk-observation://boundary";
4557
- /**
4558
- * Build PostHog's `$exception_list` (always a single entry). Error Tracking
4559
- * groups on `type`, so it is ALWAYS present (the CapxulError code) — the
4560
- * previous `[{ frames }]` shape omitted it and PostHog dropped the event as
4561
- * "missing field `type`". When the error has no parseable stack, a synthetic
4562
- * boundary frame stands in so the event still ingests as a real Issue (#1031).
4563
- */
4564
- function buildExceptionList(input) {
4565
- const frames = input.frames.length > 0 ? input.frames : [{
4566
- filename: SDK_BOUNDARY_FILENAME,
4567
- function: input.operation ?? "unknown",
4568
- lineno: 1,
4569
- colno: 1
4570
- }];
4571
- return [{
4572
- type: input.type,
4573
- value: input.value,
4574
- mechanism: {
4575
- handled: true,
4576
- type: "capxul_sdk_boundary"
4577
- },
4578
- stacktrace: { frames }
4579
- }];
4577
+ function normalizeExceptionOperation(value) {
4578
+ return typeof value === "string" && /^[A-Za-z0-9_][A-Za-z0-9_.-]{0,255}$/u.test(value) ? value : "unknown";
4580
4579
  }
4581
- //#endregion
4582
- //#region src/telemetry/capture-exception.ts
4583
- /** Fixed, leak-safe message — the raw error message may carry PII and never ships. */
4584
- const EXCEPTION_MESSAGE = "Capxul SDK operation failed";
4585
- /**
4586
- * Capture an error as a `$exception` event through the telemetry port,
4587
- * formatted for PostHog Error Tracking.
4588
- *
4589
- * Parses stack traces into `$exception_list` format, extracts structured
4590
- * metadata from CapxulError objects, and supplements with context props.
4591
- * Fire-and-forget: telemetry defects are silently swallowed.
4592
- * Returns `Effect<void, never>` for use in Effect pipelines; the underlying
4593
- * adapter work is synchronous, so callers outside Effect contexts can
4594
- * use `Effect.runSync`.
4595
- */
4596
- function captureException(telemetry, error, context) {
4597
- return Effect.catchDefect(Effect.sync(() => {
4598
- const frames = error instanceof Error ? parseV8StackFrames(error) : [];
4599
- const capxulError = isCapxulError(error) ? error : null;
4600
- const errorCode = capxulError?.code ?? context?.capxul_error_code ?? "UNKNOWN";
4601
- const props = {
4602
- capxul_error_code: errorCode,
4603
- $exception_type: errorCode,
4604
- $exception_message: EXCEPTION_MESSAGE,
4605
- $exception_list: buildExceptionList({
4606
- type: errorCode,
4607
- value: EXCEPTION_MESSAGE,
4608
- ...context?.operation === void 0 ? {} : { operation: context.operation },
4609
- frames
4610
- }),
4611
- layer: capxulError?.layer ?? context?.layer,
4612
- operation: context?.operation,
4613
- provider: context?.provider,
4614
- failure_mode: resolveFailureMode(error, context?.failure_mode)
4615
- };
4616
- if (capxulError?.details !== void 0) props.details = JSON.stringify(capxulError.details);
4617
- for (const key of Object.keys(props)) if (props[key] === void 0) delete props[key];
4618
- return telemetry.emit({
4619
- name: "$exception",
4620
- props
4621
- });
4622
- }).pipe(Effect.flatten), () => Effect.void);
4580
+ function normalizeExceptionErrorKind(value) {
4581
+ return safeExceptionLabel(value) ?? "UNKNOWN";
4623
4582
  }
4624
- /**
4625
- * Synchronous fire-and-forget capture. Runs the Effect inline with
4626
- * `Effect.runSync` so callers outside an Effect context can report errors
4627
- * without awaiting. Core SDK public methods use the assembled observation
4628
- * boundary instead.
4629
- */
4630
- function captureExceptionSync(telemetry, error, context) {
4631
- try {
4632
- Effect.runSync(captureException(telemetry, error, context));
4633
- } catch {}
4583
+ function safeExceptionLabel(value) {
4584
+ return typeof value === "string" && /^[A-Za-z][A-Za-z0-9_.-]{0,63}$/u.test(value) ? value : void 0;
4634
4585
  }
4635
4586
  //#endregion
4636
4587
  //#region src/observation.ts
4637
- const SDK_VERSION = version;
4638
4588
  /** Stable PostHog event used for typed failures that are expected product outcomes. */
4639
4589
  const CAPXUL_SDK_EXPECTED_OUTCOME_EVENT = "capxul_sdk_expected_outcome";
4640
4590
  /**
@@ -4660,13 +4610,13 @@ function postHogFailureObservation(policy, fixedSnapshot) {
4660
4610
  }));
4661
4611
  return;
4662
4612
  }
4663
- policy.deliver(() => policy.client.capture("$exception", postHogExceptionProperties(safeFailure, properties)));
4613
+ policy.deliver(() => policy.client.capture("$exception", projectFailureException(safeFailure, properties)));
4664
4614
  };
4665
4615
  const captureException = (failure) => {
4666
4616
  const prepared = prepare(failure);
4667
4617
  if (prepared === void 0 || policy.client === null || policy.client === void 0) return;
4668
4618
  const [safeFailure, properties] = prepared;
4669
- policy.deliver(() => policy.client.capture("$exception", postHogExceptionProperties(safeFailure, properties)));
4619
+ policy.deliver(() => policy.client.capture("$exception", projectFailureException(safeFailure, properties)));
4670
4620
  };
4671
4621
  return {
4672
4622
  resolveContext: () => {
@@ -4877,19 +4827,20 @@ function postHogProperties(failure, context) {
4877
4827
  ...observationContextProps(merged)
4878
4828
  };
4879
4829
  }
4880
- function postHogExceptionProperties(failure, properties) {
4830
+ function projectFailureException(failure, properties) {
4881
4831
  const filename = `capxul-sdk-observation://boundary/${failure.operation}`;
4882
4832
  const message = failure.message ?? "Capxul SDK operation failed";
4883
- const mode = failure.detail?.failure_mode;
4884
- return {
4885
- ...properties,
4886
- $exception_type: failure.errorKind,
4887
- $exception_message: message,
4888
- $exception_level: "error",
4889
- $exception_fingerprint: failureFingerprint(failure.errorKind, isFailureMode(mode) ? mode : void 0, failure.operation),
4890
- $issue_name: issueName(failure, isFailureMode(mode) ? mode : void 0),
4891
- $issue_description: failure.detail?.chain_provider_message ?? message,
4892
- $exception_list: [{
4833
+ return projectSdkException({
4834
+ properties,
4835
+ sdkVersion: failure.sdkVersion,
4836
+ operation: failure.operation,
4837
+ errorKind: failure.errorKind,
4838
+ failureMode: failure.detail?.failure_mode,
4839
+ message,
4840
+ issueDescription: issueDescription(failure, message),
4841
+ ...failure.detail?.chain_upstream === void 0 ? {} : { chainUpstream: failure.detail.chain_upstream },
4842
+ ...failure.detail?.chain_method === void 0 ? {} : { chainMethod: failure.detail.chain_method },
4843
+ exceptionList: [{
4893
4844
  type: failure.errorKind,
4894
4845
  value: message,
4895
4846
  mechanism: {
@@ -4910,14 +4861,23 @@ function postHogExceptionProperties(failure, properties) {
4910
4861
  },
4911
4862
  ...failure.stack === void 0 ? {} : { stack: failure.stack }
4912
4863
  }]
4913
- };
4864
+ });
4914
4865
  }
4915
- function issueName(failure, mode) {
4916
- const upstream = failure.detail?.chain_upstream;
4917
- const method = failure.detail?.chain_method;
4918
- const cause = mode === void 0 ? "" : `: ${mode}`;
4919
- const where = typeof upstream !== "string" ? "" : ` on ${upstream}${typeof method === "string" ? ` during ${method}` : ""}`;
4920
- return `${failure.errorKind}${cause}${where} (${failure.operation})`;
4866
+ /**
4867
+ * The decoded revert leads the description: the provider's own message masks
4868
+ * the raw revert data (`reason: [REDACTED]`), and the name plus arguments
4869
+ * (`Error(message=GS205)`) is what tells one revert from another.
4870
+ */
4871
+ function issueDescription(failure, message) {
4872
+ const detail = failure.detail;
4873
+ const providerMessage = detail?.chain_provider_message;
4874
+ if (detail?.chain_revert_name === void 0) return providerMessage ?? message;
4875
+ const revert = revertSummaryText({
4876
+ name: detail.chain_revert_name === "unknown" ? null : detail.chain_revert_name,
4877
+ selector: detail.chain_revert_selector ?? "0x",
4878
+ args: detail.chain_revert_args ?? {}
4879
+ });
4880
+ return providerMessage === void 0 ? revert : `${revert}; ${providerMessage}`;
4921
4881
  }
4922
4882
  const MAX_EVIDENCE_TEXT = 4e3;
4923
4883
  const MAX_CAUSE_DEPTH = 8;
@@ -5022,18 +4982,45 @@ function sanitizeFailureObservation(failure) {
5022
4982
  * Shared by the failure boundary and the `bootstrap_failed` product event.
5023
4983
  */
5024
4984
  function failureDetail(cause) {
5025
- if (!isCapxulError(cause)) return void 0;
5026
- const details = cause.details;
4985
+ const error = observationError(cause);
4986
+ if (error === void 0) return void 0;
4987
+ const details = error.details;
5027
4988
  const source = typeof details === "object" && details !== null ? details : {};
5028
4989
  return sanitizeFailureDetail({
5029
4990
  provider: source.provider,
5030
4991
  provider_operation: source.operation,
5031
- failure_mode: cause.mode ?? source.failure_mode,
4992
+ provider_error_source: source.provider_error_source,
4993
+ provider_error_code: source.provider_error_code,
4994
+ target_host: source.target_host,
4995
+ failure_mode: error.mode ?? source.failure_mode,
5032
4996
  reason: source.reason,
5033
4997
  http_status: source.httpStatus,
5034
- ...cause.chain === void 0 ? {} : chainCauseProperties(cause.chain)
4998
+ connection_id: source.connection_id,
4999
+ connection_count: source.connection_count,
5000
+ connection_retries: source.connection_retries,
5001
+ close_code: source.close_code,
5002
+ close_was_clean: source.close_was_clean,
5003
+ close_reason_present: source.close_reason_present,
5004
+ document_visibility: source.document_visibility,
5005
+ navigator_online: source.navigator_online,
5006
+ last_browser_event: source.last_browser_event,
5007
+ ms_since_browser_event: source.ms_since_browser_event,
5008
+ ...error.chain === void 0 ? {} : chainCauseProperties(error.chain)
5035
5009
  });
5036
5010
  }
5011
+ const CAPXUL_ERROR_CODE_SET = new Set(CAPXUL_ERROR_CODES);
5012
+ function observationError(cause) {
5013
+ if (isCapxulError(cause)) return cause;
5014
+ if (typeof cause !== "object" || cause === null) return void 0;
5015
+ const candidate = cause;
5016
+ if (typeof candidate.code !== "string" || !CAPXUL_ERROR_CODE_SET.has(candidate.code) || typeof candidate.message !== "string") return;
5017
+ const chain = decodeChainCause(candidate.chain);
5018
+ return {
5019
+ ...candidate.details === void 0 ? {} : { details: candidate.details },
5020
+ ...candidate.mode === void 0 ? {} : { mode: candidate.mode },
5021
+ ...chain === null ? {} : { chain }
5022
+ };
5023
+ }
5037
5024
  /** The chain-cause half of {@link sanitizeFailureDetail}: same bounds, same masking. */
5038
5025
  function sanitizeChainDetail(source, detail) {
5039
5026
  for (const key of [
@@ -5045,17 +5032,19 @@ function sanitizeChainDetail(source, detail) {
5045
5032
  const value = source[key];
5046
5033
  if (typeof value === "string" && ENUMERATED_DETAIL_RE.test(value)) detail[key] = value;
5047
5034
  }
5035
+ sanitizeProviderErrorDetail(source, detail);
5048
5036
  const status = source.http_status;
5049
5037
  if (typeof status === "number" && Number.isInteger(status) && status >= 100 && status <= 599) detail.http_status = status;
5050
5038
  for (const key of [
5051
5039
  "chain_upstream",
5052
5040
  "chain_method",
5053
- "chain_revert_name",
5054
- "chain_revert_selector"
5041
+ "chain_revert_name"
5055
5042
  ]) {
5056
5043
  const value = source[key];
5057
5044
  if (typeof value === "string" && ENUMERATED_DETAIL_RE.test(value)) detail[key] = value;
5058
5045
  }
5046
+ const selector = source.chain_revert_selector;
5047
+ if (typeof selector === "string" && REVERT_SELECTOR_RE.test(selector)) detail.chain_revert_selector = selector;
5059
5048
  if (typeof source.chain_retryable === "boolean") detail.chain_retryable = source.chain_retryable;
5060
5049
  const chainHttpStatus = source.chain_http_status;
5061
5050
  if (typeof chainHttpStatus === "number" && Number.isInteger(chainHttpStatus) && chainHttpStatus >= 100 && chainHttpStatus <= 599) detail.chain_http_status = chainHttpStatus;
@@ -5072,15 +5061,53 @@ function sanitizeChainDetail(source, detail) {
5072
5061
  const providerMessage = evidenceText(source.chain_provider_message);
5073
5062
  if (providerMessage !== void 0) detail.chain_provider_message = providerMessage;
5074
5063
  }
5064
+ function sanitizeProviderErrorDetail(source, detail) {
5065
+ if (source.provider_error_source !== "openfort") return;
5066
+ detail.provider_error_source = "openfort";
5067
+ if (isOpenfortSignerNotReadyCode(source.provider_error_code)) detail.provider_error_code = source.provider_error_code;
5068
+ }
5069
+ function sanitizeConnectionDetail(source, detail) {
5070
+ const targetHost = source.target_host;
5071
+ if (typeof targetHost === "string" && TARGET_HOST_RE.test(targetHost)) detail.target_host = targetHost;
5072
+ for (const key of [
5073
+ "connection_id",
5074
+ "document_visibility",
5075
+ "last_browser_event"
5076
+ ]) {
5077
+ const value = source[key];
5078
+ if (typeof value === "string" && ENUMERATED_DETAIL_RE.test(value)) detail[key] = value;
5079
+ }
5080
+ for (const key of [
5081
+ "connection_count",
5082
+ "connection_retries",
5083
+ "close_code",
5084
+ "ms_since_browser_event"
5085
+ ]) {
5086
+ const value = source[key];
5087
+ if (typeof value === "number" && Number.isSafeInteger(value) && value >= 0 && (key !== "close_code" || value <= 4999)) detail[key] = value;
5088
+ }
5089
+ for (const key of [
5090
+ "close_was_clean",
5091
+ "close_reason_present",
5092
+ "navigator_online"
5093
+ ]) {
5094
+ const value = source[key];
5095
+ if (typeof value === "boolean") detail[key] = value;
5096
+ }
5097
+ }
5075
5098
  function sanitizeFailureDetail(input) {
5076
5099
  if (typeof input !== "object" || input === null) return void 0;
5077
5100
  const source = input;
5078
5101
  const detail = {};
5102
+ sanitizeConnectionDetail(source, detail);
5079
5103
  sanitizeChainDetail(source, detail);
5080
5104
  return Object.keys(detail).length === 0 ? void 0 : detail;
5081
5105
  }
5082
5106
  /** Enumerated codes only (`convex`, `no-secure-context`, `bootstrap-encode`); free text fails. */
5083
5107
  const ENUMERATED_DETAIL_RE = /^[A-Za-z][A-Za-z0-9_.-]{0,63}$/u;
5108
+ const TARGET_HOST_RE = /^[A-Za-z0-9.[\]:-]{1,253}$/u;
5109
+ /** A four-byte revert selector, or the bare `0x` of an empty revert. */
5110
+ const REVERT_SELECTOR_RE = /^0x(?:[0-9a-fA-F]{8})?$/u;
5084
5111
  function normalizeSdkVersion(value) {
5085
5112
  return typeof value === "string" && /^[A-Za-z0-9][A-Za-z0-9.+_-]{0,127}$/u.test(value) ? value : "unknown";
5086
5113
  }
@@ -6242,13 +6269,14 @@ var ClockPortTag = class extends Context.Service()("@capxul/sdk/ports/ClockPort"
6242
6269
  //#endregion
6243
6270
  //#region src/ports/convex-call.ts
6244
6271
  var ConvexCallError = class extends Data.TaggedError("ConvexCallError") {};
6245
- function convexCallErrorFromCapxul(operation, error) {
6272
+ function convexCallErrorFromCapxul(operation, error, transport) {
6246
6273
  return new ConvexCallError({
6247
6274
  operation,
6248
6275
  publicCode: error.code,
6249
6276
  publicError: error,
6250
6277
  cause: error,
6251
- ...error.details === void 0 ? {} : { details: error.details }
6278
+ ...error.details === void 0 ? {} : { details: error.details },
6279
+ ...transport === void 0 ? {} : { transport }
6252
6280
  });
6253
6281
  }
6254
6282
  var ConvexCallPortTag = class extends Context.Service()("@capxul/sdk/ports/ConvexCallPort") {};
@@ -6289,31 +6317,56 @@ function wireChainId(chainId) {
6289
6317
  return chainId;
6290
6318
  }
6291
6319
  //#endregion
6292
- //#region src/ports/account-read.ts
6293
- var AccountReadError = class extends Data.TaggedError("AccountReadError") {};
6294
- function accountReadErrorFromCapxul(operation, error, cause = error) {
6295
- return new AccountReadError({
6296
- operation,
6297
- publicCode: error.code,
6298
- publicError: error,
6299
- cause,
6300
- ...error.details === void 0 ? {} : { details: error.details }
6301
- });
6320
+ //#region src/telemetry/invocation.ts
6321
+ const PRODUCT_INVOCATION = Symbol("capxul.product-telemetry-invocation");
6322
+ function bindProductTelemetryInvocation(telemetry, source) {
6323
+ return telemetry[PRODUCT_INVOCATION]?.(source) ?? telemetry;
6302
6324
  }
6303
- var AccountReadPortTag = class extends Context.Service()("@capxul/sdk/ports/AccountReadPort") {};
6304
6325
  //#endregion
6305
- //#region src/ports/smart-account.ts
6306
- var SmartAccountError = class extends Data.TaggedError("SmartAccountError") {};
6307
- function smartAccountErrorFromCapxul(operation, error, cause = error) {
6308
- return new SmartAccountError({
6309
- operation,
6310
- publicCode: error.code,
6311
- publicError: error,
6312
- cause,
6313
- ...error.details === void 0 ? {} : { details: error.details }
6326
+ //#region src/adapters/convex-call/retry-idempotent-read.ts
6327
+ const MAX_RETRIES = 2;
6328
+ function isConnectionLoss(error) {
6329
+ return error.publicCode === "NETWORK_ERROR" && error.publicError.mode === "upstream-down" && error.publicError.details?.reason === "connection-lost-in-flight";
6330
+ }
6331
+ function retryIdempotentRead(effect, operation, telemetry, invocationSource) {
6332
+ return Effect.suspend(() => {
6333
+ let attempt = 0;
6334
+ const invocationTelemetry = telemetry === void 0 ? void 0 : bindProductTelemetryInvocation(telemetry, invocationSource);
6335
+ return effect.pipe(Effect.tapError((error) => {
6336
+ if (!isConnectionLoss(error) || attempt >= MAX_RETRIES) return Effect.void;
6337
+ attempt += 1;
6338
+ const eventFields = {
6339
+ operation,
6340
+ failure_mode: "upstream-down",
6341
+ reason: "connection-lost-in-flight",
6342
+ attempt,
6343
+ delay_ms: 0,
6344
+ ...error.transport === void 0 ? {} : {
6345
+ connection_id: error.transport.connection_id,
6346
+ connection_count: error.transport.connection_count
6347
+ }
6348
+ };
6349
+ const transport = error.transport;
6350
+ const connection = transport === void 0 ? void 0 : omitTransportKind(transport);
6351
+ const log = Effect.logInfo("capxul.operation.retried").pipe(Effect.annotateLogs(connection === void 0 ? eventFields : {
6352
+ ...eventFields,
6353
+ ...connection
6354
+ }), Effect.catchCause(() => Effect.void));
6355
+ if (invocationTelemetry === void 0) return log;
6356
+ return log.pipe(Effect.andThen(invocationTelemetry.emit({
6357
+ name: "operation_retried",
6358
+ props: eventFields
6359
+ })), Effect.catchCause(() => Effect.void));
6360
+ }), Effect.retry({
6361
+ times: MAX_RETRIES,
6362
+ while: isConnectionLoss
6363
+ }));
6314
6364
  });
6315
6365
  }
6316
- var SmartAccountPortTag = class extends Context.Service()("@capxul/sdk/ports/SmartAccountPort") {};
6366
+ function omitTransportKind(transport) {
6367
+ const { kind: _kind, ...connection } = transport;
6368
+ return connection;
6369
+ }
6317
6370
  //#endregion
6318
6371
  //#region ../observability/src/index.ts
6319
6372
  const PII = Schema.String.pipe(Schema.brand("PII"));
@@ -6465,7 +6518,10 @@ const BootstrapFailedProps = Schema.Struct({
6465
6518
  applicationId: OptionalAppId,
6466
6519
  durationMs: OptionalDurationMs,
6467
6520
  origin: OptionalString,
6468
- reason: OptionalString
6521
+ provider: OptionalString,
6522
+ provider_operation: OptionalString,
6523
+ reason: OptionalString,
6524
+ target_host: OptionalString
6469
6525
  });
6470
6526
  const AccountBalanceReadProps = Schema.Struct({
6471
6527
  ...TelemetryEnvelopeProps,
@@ -6530,6 +6586,9 @@ const OperationRetriedProps = Schema.Struct({
6530
6586
  ...TelemetryEnvelopeProps,
6531
6587
  operation: Schema.String,
6532
6588
  failure_mode: FailureModeSchema,
6589
+ reason: Schema.optional(Schema.Literal("connection-lost-in-flight")),
6590
+ connection_id: OptionalString,
6591
+ connection_count: Schema.optional(Schema.Number),
6533
6592
  attempt: Schema.Number,
6534
6593
  delay_ms: DurationMsSchema
6535
6594
  });
@@ -6706,7 +6765,9 @@ const PaymentVerificationRetryProps = Schema.Struct({
6706
6765
  command_id: Schema.String,
6707
6766
  attempt: Schema.Number,
6708
6767
  reason_code: Schema.String,
6709
- chain_id: Schema.Number
6768
+ chain_id: Schema.Number,
6769
+ delay_ms: DurationMsSchema,
6770
+ outcome: Schema.Literals(["scheduled", "unresolved"])
6710
6771
  });
6711
6772
  const DepositInitiatedProps = Schema.Struct({ ...TelemetryEnvelopeProps });
6712
6773
  const DepositSettledProps = Schema.Struct({
@@ -6947,7 +7008,7 @@ function redactTelemetryEvent(event, options = {}) {
6947
7008
  }
6948
7009
  function redactTelemetryProps(name, props, options = {}) {
6949
7010
  if (props === void 0) return void 0;
6950
- const clone = cloneProps$1(props);
7011
+ const clone = cloneProps(props);
6951
7012
  if (options.rawMode === true) return clone;
6952
7013
  for (const key of PII_PROP_KEYS_BY_EVENT[name] ?? []) redactProperty(clone, key);
6953
7014
  return clone;
@@ -6962,17 +7023,17 @@ function redactProperty(props, key) {
6962
7023
  const value = props[key];
6963
7024
  if (typeof value === "string") props[key] = sha256Hex(value).slice(0, 12);
6964
7025
  }
6965
- function cloneProps$1(props) {
7026
+ function cloneProps(props) {
6966
7027
  const cloned = {};
6967
- for (const [key, value] of Object.entries(props)) cloned[key] = cloneTelemetryValue$1(value);
7028
+ for (const [key, value] of Object.entries(props)) cloned[key] = cloneTelemetryValue(value);
6968
7029
  return cloned;
6969
7030
  }
6970
- function cloneTelemetryValue$1(value) {
6971
- if (Array.isArray(value)) return value.map(cloneTelemetryValue$1);
7031
+ function cloneTelemetryValue(value) {
7032
+ if (Array.isArray(value)) return value.map(cloneTelemetryValue);
6972
7033
  if (value === null || typeof value !== "object") return value;
6973
7034
  if (Object.getPrototypeOf(value) !== Object.prototype) return value;
6974
7035
  const cloned = {};
6975
- for (const [key, nested] of Object.entries(value)) cloned[key] = cloneTelemetryValue$1(nested);
7036
+ for (const [key, nested] of Object.entries(value)) cloned[key] = cloneTelemetryValue(nested);
6976
7037
  return cloned;
6977
7038
  }
6978
7039
  const SHA256_INITIAL_HASH = [
@@ -7130,89 +7191,31 @@ function rotr(value, bits) {
7130
7191
  //#region src/ports/telemetry.ts
7131
7192
  var TelemetryPortTag = class extends Context.Service()("@capxul/sdk/ports/TelemetryPort") {};
7132
7193
  //#endregion
7133
- //#region src/adapters/telemetry/PostHogTelemetryAdapter.ts
7134
- var PostHogTelemetryAdapter = class {
7135
- #capture;
7136
- #identify;
7137
- #group;
7138
- #reset;
7139
- constructor(deps) {
7140
- this.#capture = deps.capture;
7141
- this.#identify = deps.identify ?? (() => void 0);
7142
- this.#group = deps.group ?? (() => void 0);
7143
- this.#reset = deps.reset ?? (() => void 0);
7144
- }
7145
- emit(event) {
7146
- return this.#run(() => this.#capture(event.name, redactTelemetryProps(event.name, cloneProps(event.props)), event), "emit", event.name);
7147
- }
7148
- identify(input) {
7149
- return this.#run(() => this.#identify(cloneIdentifyInput(input)), "identify");
7150
- }
7151
- group(input) {
7152
- return this.#run(() => this.#group(cloneGroupInput(input)), "group");
7153
- }
7154
- reset() {
7155
- return this.#run(() => this.#reset(), "reset");
7156
- }
7157
- #run(operation, operationName, eventName) {
7158
- const diagnose = Effect.logWarning("product.telemetry.transport.dropped").pipe(Effect.annotateLogs({
7159
- operation: operationName,
7160
- ...eventName === void 0 ? {} : { product_event: eventName }
7161
- }), Effect.catchCause(() => Effect.void));
7162
- return Effect.suspend(() => {
7163
- let pending;
7164
- try {
7165
- pending = operation();
7166
- } catch {
7167
- return diagnose;
7168
- }
7169
- if (pending === void 0) return Effect.void;
7170
- const transport = Effect.tryPromise({
7171
- try: () => pending,
7172
- catch: () => void 0
7173
- }).pipe(Effect.catch(() => diagnose));
7174
- return Effect.forkDetach(transport, { startImmediately: true }).pipe(Effect.asVoid);
7175
- });
7176
- }
7177
- };
7178
- function PostHogTelemetryLayer(deps) {
7179
- return Layer.succeed(TelemetryPortTag, new PostHogTelemetryAdapter(deps));
7180
- }
7181
- function cloneIdentifyInput(input) {
7182
- const traits = input.traits === void 0 ? void 0 : cloneProps(input.traits);
7183
- const properties = input.properties === void 0 ? void 0 : cloneProps(input.properties);
7184
- return {
7185
- distinctId: input.distinctId,
7186
- ...input.anonDistinctId === void 0 ? {} : { anonDistinctId: input.anonDistinctId },
7187
- ...traits === void 0 ? {} : { traits },
7188
- ...properties === void 0 ? {} : { properties }
7189
- };
7190
- }
7191
- function cloneGroupInput(input) {
7192
- const properties = input.properties === void 0 ? void 0 : cloneProps(input.properties);
7193
- return properties === void 0 ? {
7194
- groupType: input.groupType,
7195
- groupKey: input.groupKey
7196
- } : {
7197
- groupType: input.groupType,
7198
- groupKey: input.groupKey,
7199
- properties
7200
- };
7201
- }
7202
- function cloneProps(props) {
7203
- if (props === void 0) return void 0;
7204
- const cloned = {};
7205
- for (const [key, value] of Object.entries(props)) cloned[key] = cloneTelemetryValue(value);
7206
- return cloned;
7194
+ //#region src/ports/account-read.ts
7195
+ var AccountReadError = class extends Data.TaggedError("AccountReadError") {};
7196
+ function accountReadErrorFromCapxul(operation, error, cause = error) {
7197
+ return new AccountReadError({
7198
+ operation,
7199
+ publicCode: error.code,
7200
+ publicError: error,
7201
+ cause,
7202
+ ...error.details === void 0 ? {} : { details: error.details }
7203
+ });
7207
7204
  }
7208
- function cloneTelemetryValue(value) {
7209
- if (Array.isArray(value)) return value.map(cloneTelemetryValue);
7210
- if (value === null || typeof value !== "object") return value;
7211
- if (Object.getPrototypeOf(value) !== Object.prototype) return value;
7212
- const cloned = {};
7213
- for (const [key, nested] of Object.entries(value)) cloned[key] = cloneTelemetryValue(nested);
7214
- return cloned;
7205
+ var AccountReadPortTag = class extends Context.Service()("@capxul/sdk/ports/AccountReadPort") {};
7206
+ //#endregion
7207
+ //#region src/ports/smart-account.ts
7208
+ var SmartAccountError = class extends Data.TaggedError("SmartAccountError") {};
7209
+ function smartAccountErrorFromCapxul(operation, error, cause = error) {
7210
+ return new SmartAccountError({
7211
+ operation,
7212
+ publicCode: error.code,
7213
+ publicError: error,
7214
+ cause,
7215
+ ...error.details === void 0 ? {} : { details: error.details }
7216
+ });
7215
7217
  }
7218
+ var SmartAccountPortTag = class extends Context.Service()("@capxul/sdk/ports/SmartAccountPort") {};
7216
7219
  //#endregion
7217
7220
  //#region src/flows/identity.ts
7218
7221
  const IDENTITY_SLOT = {
@@ -8132,7 +8135,7 @@ function accountsDepsLayer(deps) {
8132
8135
  }
8133
8136
  const readAccountProgram = Effect.gen(function* () {
8134
8137
  const deps = yield* AccountsDepsTag;
8135
- return yield* deps.accountReadPort.readBalance({ chainId: deps.chainId }).pipe(Effect.tapError((error) => Effect.promise(() => emitAccountBalanceFailed(deps.telemetry, error.publicError))), Effect.mapError((error) => error.publicError));
8138
+ return yield* deps.accountReadPort.readBalance(copyInvocationObservation(deps.invocationSource, { chainId: deps.chainId })).pipe(Effect.tapError((error) => Effect.promise(() => emitAccountBalanceFailed(deps.telemetry, error.publicError))), Effect.mapError((error) => error.publicError));
8136
8139
  });
8137
8140
  function fundFromFaucetProgram(amount) {
8138
8141
  return Effect.gen(function* () {
@@ -8162,7 +8165,11 @@ function makeAccountsMethods(deps) {
8162
8165
  ok: false,
8163
8166
  error: Errors.cancelled({ operation: "accounts.read" })
8164
8167
  };
8165
- return toCapxulResult(readAccountProgram, accountsDepsLayer(deps));
8168
+ const controls = deps.invocationControls?.(options) ?? options;
8169
+ return runCapxulEffect(readAccountProgram.pipe(Effect.provide(accountsDepsLayer({
8170
+ ...deps,
8171
+ ...controls === void 0 ? {} : { invocationSource: controls }
8172
+ }))), controls, "accounts.read", deps.runPromise);
8166
8173
  },
8167
8174
  async fund(amount, options) {
8168
8175
  if (options?.signal?.aborted) return {
@@ -8927,7 +8934,7 @@ function emitCreationFunnelTail(telemetry, org, chainId) {
8927
8934
  function readTreasuryProgram(orgId) {
8928
8935
  return Effect.gen(function* () {
8929
8936
  const deps = yield* OrgDepsTag;
8930
- if (deps.orgPort !== void 0) return yield* deps.orgPort.readTreasury({ orgId }).pipe(Effect.mapError((error) => error.publicError));
8937
+ if (deps.orgPort !== void 0) return yield* deps.orgPort.readTreasury(copyInvocationObservation(deps.invocationSource, { orgId })).pipe(Effect.mapError((error) => error.publicError));
8931
8938
  return zeroTreasury(orgId);
8932
8939
  });
8933
8940
  }
@@ -9011,7 +9018,7 @@ function detectAndAcceptPendingInvitationsProgram() {
9011
9018
  function listOrgsProgram() {
9012
9019
  return Effect.gen(function* () {
9013
9020
  const deps = yield* OrgDepsTag;
9014
- if (deps.orgPort !== void 0) return yield* deps.orgPort.listOrgs({}).pipe(Effect.mapError((error) => error.publicError));
9021
+ if (deps.orgPort !== void 0) return yield* deps.orgPort.listOrgs(copyInvocationObservation(deps.invocationSource, {})).pipe(Effect.mapError((error) => error.publicError));
9015
9022
  return [];
9016
9023
  });
9017
9024
  }
@@ -9099,11 +9106,28 @@ function isRetryableOrganizationSetupFailure(error) {
9099
9106
  * state. The closed-over `orgId` is its only entity reference.
9100
9107
  */
9101
9108
  function makeOrgMethods(deps) {
9102
- const layer = orgDepsLayer({
9109
+ const orgDeps = {
9103
9110
  ...deps.orgPort === void 0 ? {} : { orgPort: deps.orgPort },
9104
9111
  ...deps.chainId === void 0 ? {} : { chainId: deps.chainId },
9105
9112
  ...deps.telemetry === void 0 ? {} : { telemetry: deps.telemetry }
9106
- });
9113
+ };
9114
+ const layer = orgDepsLayer(orgDeps);
9115
+ const treasury = (orgId, controls) => {
9116
+ return runCapxulEffect(readTreasuryProgram(orgId).pipe(Effect.provide(orgDepsLayer({
9117
+ ...orgDeps,
9118
+ ...controls === void 0 ? {} : { invocationSource: controls }
9119
+ }))), controls, "org.treasury", deps.runPromise);
9120
+ };
9121
+ const listOrganizations = (controls) => {
9122
+ if (controls?.signal?.aborted) return Promise.resolve({
9123
+ ok: false,
9124
+ error: Errors.cancelled({ operation: "org.orgs" })
9125
+ });
9126
+ return runCapxulEffect(listOrgsProgram().pipe(Effect.provide(orgDepsLayer({
9127
+ ...orgDeps,
9128
+ ...controls === void 0 ? {} : { invocationSource: controls }
9129
+ }))), controls, "org.orgs", deps.runPromise);
9130
+ };
9107
9131
  return {
9108
9132
  createOrg(input, options) {
9109
9133
  if (options?.signal?.aborted) return Promise.resolve({
@@ -9112,13 +9136,7 @@ function makeOrgMethods(deps) {
9112
9136
  });
9113
9137
  return toCapxulResult(createOrgProgram(input), layer);
9114
9138
  },
9115
- orgs: Object.assign((options) => {
9116
- if (options?.signal?.aborted) return Promise.resolve({
9117
- ok: false,
9118
- error: Errors.cancelled({ operation: "org.orgs" })
9119
- });
9120
- return toCapxulResult(listOrgsProgram(), layer);
9121
- }, { detectAndAcceptPendingInvitations(options) {
9139
+ orgs: Object.assign((options) => listOrganizations(deps.invocationControls?.(options) ?? options), { detectAndAcceptPendingInvitations(options) {
9122
9140
  if (options?.signal?.aborted) return Promise.resolve({
9123
9141
  ok: false,
9124
9142
  error: Errors.cancelled({ operation: "orgs.detectAndAcceptPendingInvitations" })
@@ -9190,19 +9208,20 @@ function makeOrgMethods(deps) {
9190
9208
  ok: false,
9191
9209
  error: Errors.cancelled({ operation: "org.treasury" })
9192
9210
  });
9193
- return toCapxulResult(readTreasuryProgram(orgId), layer);
9211
+ return treasury(orgId, deps.invocationControls?.(options) ?? options);
9194
9212
  },
9195
9213
  account: { async get(options) {
9196
9214
  if (options?.signal?.aborted) return {
9197
9215
  ok: false,
9198
9216
  error: Errors.cancelled({ operation: "org.account.get" })
9199
9217
  };
9200
- const treasury = await toCapxulResult(readTreasuryProgram(orgId), layer);
9201
- if (!treasury.ok) return {
9218
+ const controls = deps.invocationControls?.(options) ?? options;
9219
+ const treasuryResult = await treasury(orgId, controls);
9220
+ if (!treasuryResult.ok) return {
9202
9221
  ok: false,
9203
- error: treasury.error
9222
+ error: treasuryResult.error
9204
9223
  };
9205
- const orgList = await toCapxulResult(listOrgsProgram(), layer);
9224
+ const orgList = await listOrganizations(controls);
9206
9225
  if (!orgList.ok) return {
9207
9226
  ok: false,
9208
9227
  error: orgList.error
@@ -9211,10 +9230,10 @@ function makeOrgMethods(deps) {
9211
9230
  return {
9212
9231
  ok: true,
9213
9232
  value: {
9214
- id: treasury.value.id,
9233
+ id: treasuryResult.value.id,
9215
9234
  address: org?.safeAddress ?? null,
9216
- balance: treasury.value.balance,
9217
- available: treasury.value.available
9235
+ balance: treasuryResult.value.balance,
9236
+ available: treasuryResult.value.available
9218
9237
  }
9219
9238
  };
9220
9239
  } },
@@ -9366,13 +9385,16 @@ function compareDecimal(first, second) {
9366
9385
  //#region src/surface/holdings.ts
9367
9386
  function makeHoldingsMethods(deps) {
9368
9387
  const functions = deps.functions ?? holdingsContract;
9369
- const read = (operation, actor, signal, pick) => runIfActive(signal, operation, () => deps.convexCall.action(functions.current, actor?.kind === "organization" ? { actor: {
9370
- kind: "organization",
9371
- orgId: actor.organizationId
9372
- } } : {}).pipe(Effect.map(pick)));
9388
+ const read = (operation, actor, options, pick) => {
9389
+ const controls = deps.invocationControls?.(options) ?? options;
9390
+ return runCapxulEffect(retryIdempotentRead(deps.convexCall.action(functions.current, copyInvocationObservation(controls, actor?.kind === "organization" ? { actor: {
9391
+ kind: "organization",
9392
+ orgId: actor.organizationId
9393
+ } } : {})), operation, deps.telemetry, controls).pipe(Effect.map(pick), Effect.mapError((error) => error.publicError)), controls, operation, deps.runPromise);
9394
+ };
9373
9395
  return {
9374
- current: (input, options) => read("holdings.current", input?.actor, options?.signal, (snapshot) => snapshot),
9375
- primary: (input, options) => read("holdings.primary", input?.actor, options?.signal, (snapshot) => primaryHolding(snapshot.rows))
9396
+ current: (input, options) => read("holdings.current", input?.actor, options, (snapshot) => snapshot),
9397
+ primary: (input, options) => read("holdings.primary", input?.actor, options, (snapshot) => primaryHolding(snapshot.rows))
9376
9398
  };
9377
9399
  }
9378
9400
  //#endregion
@@ -9383,78 +9405,6 @@ function detectAuthCacheAdapter() {
9383
9405
  return new InMemoryAuthCacheAdapter();
9384
9406
  }
9385
9407
  //#endregion
9386
- //#region src/telemetry/from-posthog.ts
9387
- const PRODUCT_INVOCATION = Symbol("capxul.product-telemetry-invocation");
9388
- /** @internal Bind paired emit/identify/reset work to one call-start snapshot. */
9389
- function bindProductTelemetryInvocation(telemetry, source) {
9390
- return telemetry[PRODUCT_INVOCATION]?.(source) ?? telemetry;
9391
- }
9392
- /**
9393
- * Drop props that must never cross to a host-owned external sink. Today that is
9394
- * the `$exception` `details` blob: `captureException` serializes
9395
- * `CapxulError.details` (e.g. `{ asset, available, required }`, `{ name }`,
9396
- * `{ accountId }` — errors.ts) into it, and the shared redactor has no
9397
- * `$exception` rule, so it is stripped here at the boundary (infra#1037). The
9398
- * safe fields (error code, operation, failure_mode, the fixed leak-safe message,
9399
- * stack frames) are preserved.
9400
- */
9401
- function stripHostUnsafeProps(props) {
9402
- if (props === void 0) return void 0;
9403
- const { details: _details, ...safe } = props;
9404
- return safe;
9405
- }
9406
- /**
9407
- * The subset of a posthog-js client the seam calls. `identify` / `group` /
9408
- * `reset` are optional — a host that only wants event capture can omit them.
9409
- */
9410
- /**
9411
- * Adapt the host's already-initialized posthog-like client into a
9412
- * `TelemetryPort` for the `telemetry` prop / input. This port SUPPLANTS the
9413
- * SDK's no-op default telemetry sink (`production.ts` binds it via
9414
- * `Layer.succeed`, not `compose` — there is no client-side success relay to
9415
- * compose with); it is additive to Capxul's backend first-party record and
9416
- * never owns the client.
9417
- */
9418
- function postHogProductTelemetry(policy, fixedSnapshot) {
9419
- const telemetry = new PostHogTelemetryAdapter({
9420
- capture: (name, props, source) => {
9421
- const snapshot = readInvocationObservation(source) ?? fixedSnapshot ?? policy.snapshot();
9422
- if (!snapshot.active || policy.client === null || policy.client === void 0) return;
9423
- const event = stampTelemetryEnvelope({
9424
- name,
9425
- props
9426
- }, {
9427
- capxul_env: policy.capxulEnv,
9428
- producer: "sdk"
9429
- });
9430
- policy.deliver(() => policy.client.capture(name, {
9431
- ...stripHostUnsafeProps(event.props),
9432
- ...observationContextProps(snapshot.context)
9433
- }));
9434
- },
9435
- identify: (input) => {
9436
- if (!(fixedSnapshot ?? policy.snapshot()).active || policy.client?.identify === void 0) return;
9437
- policy.deliver(() => policy.client.identify(input.distinctId, {
9438
- ...input.traits,
9439
- ...input.properties
9440
- }));
9441
- },
9442
- group: (input) => {
9443
- if (!(fixedSnapshot ?? policy.snapshot()).active || policy.client?.group === void 0) return;
9444
- policy.deliver(() => policy.client.group(input.groupType, input.groupKey, input.properties === void 0 ? void 0 : { ...input.properties }));
9445
- },
9446
- reset: () => {
9447
- if (!(fixedSnapshot ?? policy.snapshot()).active || policy.client?.reset === void 0) return;
9448
- policy.deliver(() => policy.client.reset());
9449
- }
9450
- });
9451
- Object.defineProperty(telemetry, PRODUCT_INVOCATION, {
9452
- enumerable: false,
9453
- value: (source) => postHogProductTelemetry(policy, readInvocationObservation(source) ?? fixedSnapshot ?? policy.snapshot())
9454
- });
9455
- return telemetry;
9456
- }
9457
- //#endregion
9458
9408
  //#region src/telemetry/identity-product.ts
9459
9409
  const NONE = null;
9460
9410
  const IDENTITY_EVENT_TAG_SET = new Set(IDENTITY_EVENT_TAGS);
@@ -9651,6 +9601,8 @@ function assembleCapxulClient(input) {
9651
9601
  accountReadPort: input.ports.accountRead,
9652
9602
  profileMethods: financialOps.me,
9653
9603
  convexCall: input.ports.convexCall,
9604
+ runPromise: effectRunner.runPromise,
9605
+ invocationControls: (controls) => withHostObservationControls(observation.hostObservationSnapshot, controls),
9654
9606
  ...input.signer === void 0 ? {} : { signer: input.signer }
9655
9607
  });
9656
9608
  kickProvisioning = accountBundle.kickProvisioning;
@@ -9688,16 +9640,25 @@ function assembleCapxulClient(input) {
9688
9640
  });
9689
9641
  const system = makeSystemMethods({ convexCall: input.ports.convexCall });
9690
9642
  const media = makeMediaMethods({ convexCall: input.ports.convexCall });
9691
- const holdings = makeHoldingsMethods({ convexCall: input.ports.convexCall });
9643
+ const holdings = makeHoldingsMethods({
9644
+ convexCall: input.ports.convexCall,
9645
+ telemetry: input.ports.telemetry,
9646
+ runPromise: effectRunner.runPromise,
9647
+ invocationControls: (controls) => withHostObservationControls(observation.hostObservationSnapshot, controls)
9648
+ });
9692
9649
  const accounts = makeAccountsMethods({
9693
9650
  accountReadPort: input.ports.accountRead,
9694
9651
  chainId: input.bootstrap.chainId,
9695
- telemetry: input.ports.telemetry
9652
+ telemetry: input.ports.telemetry,
9653
+ runPromise: effectRunner.runPromise,
9654
+ invocationControls: (controls) => withHostObservationControls(observation.hostObservationSnapshot, controls)
9696
9655
  });
9697
9656
  const orgMethods = makeOrgMethods({
9698
9657
  actor,
9699
9658
  chainId: input.bootstrap.chainId,
9700
9659
  telemetry: input.ports.telemetry,
9660
+ runPromise: effectRunner.runPromise,
9661
+ invocationControls: (controls) => withHostObservationControls(observation.hostObservationSnapshot, controls),
9701
9662
  requestKeyScope: `${input.bootstrap.convexUrl}:${String(input.bootstrap.chainId)}`,
9702
9663
  ...selectedOrgPort === void 0 ? {} : { orgPort: selectedOrgPort },
9703
9664
  convexCall: input.ports.convexCall,
@@ -9834,11 +9795,7 @@ function transitionError(record) {
9834
9795
  }
9835
9796
  function withHostObservation(actor, snapshot) {
9836
9797
  if (snapshot === void 0) return actor;
9837
- const controls = (input) => {
9838
- const captured = snapshot();
9839
- const copied = { ...input };
9840
- return captured === void 0 ? copied : attachInvocationObservation(copied, captured);
9841
- };
9798
+ const controls = (input) => withHostObservationControls(snapshot, input);
9842
9799
  return {
9843
9800
  ...actor,
9844
9801
  ask: (event, input) => actor.ask(event, controls(input)),
@@ -9846,5 +9803,10 @@ function withHostObservation(actor, snapshot) {
9846
9803
  restoreAuthSession: (session, input) => actor.restoreAuthSession(session, controls(input))
9847
9804
  };
9848
9805
  }
9806
+ function withHostObservationControls(snapshot, input) {
9807
+ const copied = { ...input };
9808
+ const captured = snapshot?.();
9809
+ return captured === void 0 ? copied : attachInvocationObservation(copied, captured);
9810
+ }
9849
9811
  //#endregion
9850
- export { deriveCapxulSafeAddress as $, postHogFailureObservation as A, injectedWalletSigner as B, fingerprintPaymentIntent as C, failureEvidenceProps as D, failureDetail as E, isSettingUpLifecycle as F, PAYMENT_DIRECTIONS as G, OBSERVATION_CONTEXT_HEADER as H, formatTraceparent as I, BootstrapEnvelope as J, PAYMENT_STATUSES as K, copyInvocationObservation as L, captureExceptionSync as M, version as N, observationContextProps as O, fromWei as P, BASE_SEPOLIA_CHAIN_ID as Q, readInvocationObservation as R, AuthClientPortTag as S, CAPXUL_SDK_EXPECTED_OUTCOME_EVENT as T, encodeObservationContextHeader as U, signerFailure as V, sanitizeObservationContext as W, CAPXUL_PAYMENTS_V2_ADDRESS as X, EngineeringTelemetryBootstrapPolicy as Y, normalizeBindingEmail as Z, ClockPortTag as _, TelemetryPortTag as a, authClientPortFromPromiseAdapter as b, smartAccountErrorFromCapxul as c, wireChainId as d, destination as et, IdentityPortTag as f, ClockError as g, convexCallErrorFromCapxul as h, PostHogTelemetryLayer as i, captureException as j, observeFailedResult as k, AccountReadPortTag as l, ConvexCallPortTag as m, postHogProductTelemetry as n, isRestoring as nt, redactTelemetryEvent as o, identityErrorFromCapxul as p, CAPXUL_FUNCTIONS as q, detectAuthCacheAdapter as r, SmartAccountPortTag as s, assembleCapxulClient as t, isClaimed as tt, accountReadErrorFromCapxul as u, BootstrapPortTag as v, toWei as w, AuthClientError as x, bootstrapErrorFromCapxul as y, causeChain as z };
9812
+ export { sanitizeObservationContext as $, observationContextProps as A, fromWei as B, AuthClientError as C, CAPXUL_SDK_EXPECTED_OUTCOME_EVENT as D, toWei as E, normalizeExceptionErrorKind as F, isSignerNotReadySignal as G, formatTraceparent as H, normalizeExceptionOperation as I, resolveFailureMode as J, openfortSignerNotReadyCode as K, projectSdkException as L, postHogFailureObservation as M, EXCEPTION_MESSAGE as N, failureDetail as O, SDK_VERSION as P, encodeObservationContextHeader as Q, safeExceptionLabel as R, authClientPortFromPromiseAdapter as S, fingerprintPaymentIntent as T, causeChain as U, isSettingUpLifecycle as V, injectedWalletSigner as W, readInvocationObservation as X, copyInvocationObservation as Y, OBSERVATION_CONTEXT_HEADER as Z, convexCallErrorFromCapxul as _, AccountReadPortTag as a, CAPXUL_PAYMENTS_V2_ADDRESS as at, BootstrapPortTag as b, redactTelemetryEvent as c, deriveCapxulSafeAddress as ct, retryIdempotentRead as d, isRestoring as dt, PAYMENT_DIRECTIONS as et, PRODUCT_INVOCATION as f, ConvexCallPortTag as g, identityErrorFromCapxul as h, smartAccountErrorFromCapxul as i, EngineeringTelemetryBootstrapPolicy as it, observeFailedResult as j, failureEvidenceProps as k, redactTelemetryProps as l, destination as lt, IdentityPortTag as m, detectAuthCacheAdapter as n, CAPXUL_FUNCTIONS as nt, accountReadErrorFromCapxul as o, normalizeBindingEmail as ot, wireChainId as p, signerFailure as q, SmartAccountPortTag as r, BootstrapEnvelope as rt, TelemetryPortTag as s, BASE_SEPOLIA_CHAIN_ID as st, assembleCapxulClient as t, PAYMENT_STATUSES as tt, stampTelemetryEnvelope as u, isClaimed as ut, ClockError as v, AuthClientPortTag as w, bootstrapErrorFromCapxul as x, ClockPortTag as y, version as z };