@capxul/sdk 4.2.0-rc.10 → 4.2.0-rc.11

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.
@@ -985,6 +985,10 @@ function toChainId(raw) {
985
985
  if (typeof raw !== "number" || !Number.isSafeInteger(raw) || raw <= 0) throw Errors.invalidInput("chainId", invalidValueReason("must be a positive safe integer", raw));
986
986
  return raw;
987
987
  }
988
+ function toWeiAmount(raw) {
989
+ if (typeof raw !== "string" || !WEI_RE.test(raw)) throw Errors.invalidInput("weiAmount", invalidValueReason("must be a non-negative integer string", raw));
990
+ return raw;
991
+ }
988
992
  function toCountryCode(raw) {
989
993
  if (typeof raw !== "string") throw Errors.invalidInput("countryCode", "must be a string");
990
994
  const upper = raw.toUpperCase();
@@ -2468,4 +2472,4 @@ function readExchange(body) {
2468
2472
  };
2469
2473
  }
2470
2474
  //#endregion
2471
- export { toRoleKey as $, currencySymbolFor as A, toCurrencyCode as B, ASSET_ID_RE as C, redactSecrets as Ct, WEI_RE as D, SUPPORTED_CURRENCY_CODES as E, toAssetId as F, toHandle as G, toEmail as H, toAuthUserId as I, toOrgId as J, toJwtToken as K, toBudgetId as L, toAddress as M, toAllowedOrigin as N, ZERO_BYTES32 as O, toAppId as P, toPublishableKey as Q, toChainId as R, APP_ID_RE as S, isCredentialField as St, EVM_ADDRESS_RE as T, toEpochMs as U, toDurationMs as V, toEpochSeconds as W, toPayrollGroupId as X, toPartyId as Y, toPayrollRunId as Z, normalizeBindingEmail as _, failureFingerprint as _t, parseAuthSession as a, decodeConvexError as at, configuredMoneyAssetById as b, revertSummaryText as bt, AuthCachePortTag as c, EXPECTED_OPERATION_OUTCOMES as ct, authClientPortFromPromiseAdapter as d, CHAIN_UPSTREAMS as dt, toSessionToken as et, AuthClientError as f, FAILURE_MODES as ft, CAPXUL_PAYMENTS_V2_ADDRESS as g, decodeChainCause as gt, orgRoleKeyForLabel as h, chainEvidenceLabel as ht, BrowserAuthCacheAdapter as i, HANDLE_RE as it, toAccountId as j, assetIdFor as k, SystemClockLayer as l, Errors as lt, ADMIN_ROLE_LABEL as m, chainCauseProperties as mt, readClockNow as n, toTxHash as nt, parseCachedJwt as o, CAPXUL_ERROR_CODES as ot, AuthClientPortTag as p, boundedResponseHeaders as pt, toKycTier as q, InMemoryAuthCacheAdapter as r, validateHandle as rt, AuthCacheError as s, CapxulError as st, oauthBearerAuthClient as t, toTesterKind as tt, ClockPortTag as u, isCapxulError as ut, BASE_SEPOLIA_CHAIN_ID as v, isChainUpstream as vt, BYTES32_RE as w, redactUrlSecrets as wt, ACCOUNT_ID_RE as x, containsSensitiveMaterial as xt, deriveCapxulSafeAddress as y, isFailureMode as yt, toCountryCode as z };
2475
+ export { toRoleKey as $, currencySymbolFor as A, toCurrencyCode as B, ASSET_ID_RE as C, isCredentialField as Ct, WEI_RE as D, SUPPORTED_CURRENCY_CODES as E, toAssetId as F, toHandle as G, toEmail as H, toAuthUserId as I, toOrgId as J, toJwtToken as K, toBudgetId as L, toAddress as M, toAllowedOrigin as N, ZERO_BYTES32 as O, toAppId as P, toPublishableKey as Q, toChainId as R, APP_ID_RE as S, containsSensitiveMaterial as St, EVM_ADDRESS_RE as T, redactUrlSecrets as Tt, toEpochMs as U, toDurationMs as V, toEpochSeconds as W, toPayrollGroupId as X, toPartyId as Y, toPayrollRunId as Z, normalizeBindingEmail as _, decodeChainCause as _t, parseAuthSession as a, HANDLE_RE as at, configuredMoneyAssetById as b, isFailureMode as bt, AuthCachePortTag as c, CapxulError as ct, authClientPortFromPromiseAdapter as d, isCapxulError as dt, toSessionToken as et, AuthClientError as f, CHAIN_UPSTREAMS as ft, CAPXUL_PAYMENTS_V2_ADDRESS as g, chainEvidenceLabel as gt, orgRoleKeyForLabel as h, chainCauseProperties as ht, BrowserAuthCacheAdapter as i, validateHandle as it, toAccountId as j, assetIdFor as k, SystemClockLayer as l, EXPECTED_OPERATION_OUTCOMES as lt, ADMIN_ROLE_LABEL as m, boundedResponseHeaders as mt, readClockNow as n, toTxHash as nt, parseCachedJwt as o, decodeConvexError as ot, AuthClientPortTag as p, FAILURE_MODES as pt, toKycTier as q, InMemoryAuthCacheAdapter as r, toWeiAmount as rt, AuthCacheError as s, CAPXUL_ERROR_CODES as st, oauthBearerAuthClient as t, toTesterKind as tt, ClockPortTag as u, Errors as ut, BASE_SEPOLIA_CHAIN_ID as v, failureFingerprint as vt, BYTES32_RE as w, redactSecrets as wt, ACCOUNT_ID_RE as x, revertSummaryText as xt, deriveCapxulSafeAddress as y, isChainUpstream as yt, toCountryCode as z };
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "source": {
3
- "commit": "a7e55e5f1c2af5567a8b285a4ef70b8b5a3289f6",
4
- "tree": "91bf1b080c0006fe30131711c13c843afd627158",
3
+ "commit": "12a590f10914e8b056ce54732e6f484f36e060f3",
4
+ "tree": "90adc6656be3c1fb0a6e18170877d46081fa2538",
5
5
  "branch": "codex/programme-rc",
6
6
  "repository": "https://github.com/Xelmar-tech/infrastructure",
7
7
  "lockfileSha256": "5870f53b72706d103220c1bcf733cb4fb71196aea32a9cfbdc277d73cc959264"
8
8
  },
9
9
  "name": "@capxul/sdk",
10
- "version": "4.2.0-rc.10"
10
+ "version": "4.2.0-rc.11"
11
11
  }
package/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { $ as PayrollGroupId, B as ChainId, Ct as ChainCause, D as Account, Dt as RevertSummary, E as CAPXUL_PAYMENTS_V2_ADDRESS, Et as FailureMode, F as AssetId, G as EVM_ADDRESS_RE, H as CurrencyCode, I as AuthSession, J as Handle, L as AuthUserId, O as AccountId, P as AssetAmount, St as CHAIN_UPSTREAMS, Tt as FAILURE_MODES, V as CountryCode, X as OrgId, Y as Money, Z as PartyId, _ as Session, _t as CapxulErrorCode, a as Eip1193RequestProvider, at as RoleKey, c as injectedWalletSigner, ct as TesterKind, d as AccountRequirement, dt as toAddress, et as PayrollRunId, f as Eip1193Provider, ft as toCountryCode, g as Profile, gt as CapxulError, h as CapxulResult, ht as CAPXUL_ERROR_CODES, i as CapxulSigner, k as Address, l as AccountProvider, m as localPrivateKeyAccountProvider, mt as toPartyId, o as SignerStatus, p as eip1193AccountProvider, pt as toHandle, r as CapxulDigestSigner, s as SignerStatusStore, u as AccountProviderSource, v as SmartAccount, vt as CapxulErrorDetails, wt as ChainUpstream, xt as isCapxulError, yt as Errors, z as BudgetId } from "./OAuthBearerAuthClient-C-ip-z8M.mjs";
2
- import { $ as OrganizationPaymentBatchInput, $n as RequestStatus, $t as Destination, A as OrgScopedMethods, An as Ref, At as AddressBookAddInput, B as AuthorizeRunOptions, Bn as SmartAccountMethods, Bt as ActivityFilter, C as CurrentUserMethods, Cn as PaymentMoney, Ct as AccountMethods, D as MemberStatus, Dn as PaymentsMethods, Dt as ActorRequest, E as InviteMemberInput, En as PaymentType, Et as ActorRelationshipMethods, F as ResendInviteTokenInput, Fn as AccountLifecycle, Ft as InboxItem, G as PayrollGroupsMethods, Gn as ActorRef, Gt as ActivityPage, H as PayrollGroup, Hn as OrgLifecycle, Ht as ActivityKind, I as RoleDefinition, In as AccountSetupStep, It as InboxMethods, J as PayrollRun, Jn as SubmittedPermissionExecution, Jt as ActivitySummary, K as PayrollMethods, Kn as CurrentHoldings, Kt as ActivityRange, L as RoleSpendCap, Ln as isSettingUpLifecycle, Lt as ActivityAnnotation, M as OrgView, Mn as TargetReference, Mt as AddressBookLabelInput, N as OrganizationAccount, Nn as TargetsMethods, Nt as AddressBookMethods, O as MemberView, On as PaymentsPayInput, Ot as ActorRequestIssueInput, P as OrganizationAuditLogItem, Pn as fingerprintPaymentIntent, Pt as InboxApproveInput, Q as PayrollTermsUnit, Qn as PaymentStatus$1, Qt as DepositInstructions, R as RoleView, Rn as CompleteProfileInput, Rt as ActivityAnnotationInput, S as CurrentUserContext, Sn as PaymentDocumentsMethods, St as ReadyAccountLifecycle, T as DetectPendingOrgInvitationsResult, Tn as PaymentTiming, Tt as ActorProfileMethods, U as PayrollGroupInput, Un as OrgSetupStep, Ut as ActivityListParams, V as PayrollEngagementTerms, Vn as AuthMethods, Vt as ActivityItem, W as PayrollGroupMember, Wn as PayoutAddress, Wt as ActivityMethods, X as PayrollRunStatus, Xn as PAYMENT_DIRECTIONS, Xt as ActivitySummaryTotal, Y as PayrollRunItemInput, Yn as InboxStatus, Yt as ActivitySummaryParams, Z as PayrollRuns, Zn as PAYMENT_STATUSES, Zt as ActorReference, _ as HoldingsMethods, _n as PaymentDirection, _t as OnboardingMethods, a as ObservationContext, an as DestinationRemoveInput, ar as IdentityEvent, at as PermissionCreateInput, b as SystemHealth, bn as PaymentDocumentRender, bt as PersonOnboarding, c as HostObservability, cn as MeMethods, cr as Readiness, ct as PermissionReplaceInput, d as postHogObservability, dn as OfframpMethods, dr as isClaimed, dt as Budget, en as DestinationAddInput, et as OrganizationPaymentInput, f as CapxulClient, fn as OfframpQuote, fr as isRestoring, ft as OrgMe, g as IdentityRuntimeSendResult, gn as PaymentActivityEvidence, gt as CompletedPersonProfile, h as IdentityRuntime, hn as Payment, ht as AccountsMethods, i as ObservationAdapter, in as DestinationRail, ir as Destination$1, it as PermissionChangeInput, j as OrgTemplate, jn as ResolvedTarget, jt as AddressBookEntry, k as OrgMethods, kn as RecipientResolution, kt as ActorRequestsMethods, l as PostHogObservabilityClient, ln as MeProfile, lr as StateLabel, lt as PermissionRevokeInput, m as IdentityProfileDetails, mn as OfframpStatus, mr as InvocationControls, mt as OrgMeOptions, nn as DestinationListInput, nt as OrganizationPaymentsMethods, o as ObservationDelivery, on as DestinationsMethods, or as IdentityState, ot as PermissionMethods, p as CreateCapxulClientInput, pn as OfframpQuoteInput, pr as IdentityTransition, pt as OrgMeMethod, q as PayrollOptions, qn as Permission, qt as ActivityReference, r as CAPXUL_SDK_EXPECTED_OUTCOME_EVENT, rn as DestinationPayload, rr as TelemetryPort, rt as PermissionAssignInput, s as SdkFailureObservation, sn as FinancialOpsMethods, sr as OrgLane, st as PermissionOptions, t as CapxulClientInput, tn as DestinationKind, tt as OrganizationPaymentItemInput, u as PostHogObservabilityOptions, un as MovementActivityEvidence, ur as destination, ut as PermissionReadResult, v as Holding, vn as PaymentDocumentKind, vt as OrganizationOnboarding, w as CreateOrgInput, wn as PaymentStatus, wt as ActorProfile, x as MediaMethods, xn as PaymentDocumentVerification, xt as PersonOnboardingInput, y as SystemMethods, yn as PaymentDocumentRef, yt as OrganizationOnboardingInput, z as AuthorizeRunInput, zn as IdentityMethods, zt as ActivityDetail } from "./production-Du4Vc7YD.mjs";
2
+ import { $ as OrganizationPaymentBatchInput, $n as RequestStatus, $t as Destination, A as OrgScopedMethods, An as Ref, At as AddressBookAddInput, B as AuthorizeRunOptions, Bn as SmartAccountMethods, Bt as ActivityFilter, C as CurrentUserMethods, Cn as PaymentMoney, Ct as AccountMethods, D as MemberStatus, Dn as PaymentsMethods, Dt as ActorRequest, E as InviteMemberInput, En as PaymentType, Et as ActorRelationshipMethods, F as ResendInviteTokenInput, Fn as AccountLifecycle, Ft as InboxItem, G as PayrollGroupsMethods, Gn as ActorRef, Gt as ActivityPage, H as PayrollGroup, Hn as OrgLifecycle, Ht as ActivityKind, I as RoleDefinition, In as AccountSetupStep, It as InboxMethods, J as PayrollRun, Jn as SubmittedPermissionExecution, Jt as ActivitySummary, K as PayrollMethods, Kn as CurrentHoldings, Kt as ActivityRange, L as RoleSpendCap, Ln as isSettingUpLifecycle, Lt as ActivityAnnotation, M as OrgView, Mn as TargetReference, Mt as AddressBookLabelInput, N as OrganizationAccount, Nn as TargetsMethods, Nt as AddressBookMethods, O as MemberView, On as PaymentsPayInput, Ot as ActorRequestIssueInput, P as OrganizationAuditLogItem, Pn as fingerprintPaymentIntent, Pt as InboxApproveInput, Q as PayrollTermsUnit, Qn as PaymentStatus$1, Qt as DepositInstructions, R as RoleView, Rn as CompleteProfileInput, Rt as ActivityAnnotationInput, S as CurrentUserContext, Sn as PaymentDocumentsMethods, St as ReadyAccountLifecycle, T as DetectPendingOrgInvitationsResult, Tn as PaymentTiming, Tt as ActorProfileMethods, U as PayrollGroupInput, Un as OrgSetupStep, Ut as ActivityListParams, V as PayrollEngagementTerms, Vn as AuthMethods, Vt as ActivityItem, W as PayrollGroupMember, Wn as PayoutAddress, Wt as ActivityMethods, X as PayrollRunStatus, Xn as PAYMENT_DIRECTIONS, Xt as ActivitySummaryTotal, Y as PayrollRunItemInput, Yn as InboxStatus, Yt as ActivitySummaryParams, Z as PayrollRuns, Zn as PAYMENT_STATUSES, Zt as ActorReference, _ as HoldingsMethods, _n as PaymentDirection, _t as OnboardingMethods, a as ObservationContext, an as DestinationRemoveInput, ar as IdentityEvent, at as PermissionCreateInput, b as SystemHealth, bn as PaymentDocumentRender, bt as PersonOnboarding, c as HostObservability, cn as MeMethods, cr as Readiness, ct as PermissionReplaceInput, d as postHogObservability, dn as OfframpMethods, dr as isClaimed, dt as Budget, en as DestinationAddInput, et as OrganizationPaymentInput, f as CapxulClient, fn as OfframpQuote, fr as isRestoring, ft as OrgMe, g as IdentityRuntimeSendResult, gn as PaymentActivityEvidence, gt as CompletedPersonProfile, h as IdentityRuntime, hn as Payment, ht as AccountsMethods, i as ObservationAdapter, in as DestinationRail, ir as Destination$1, it as PermissionChangeInput, j as OrgTemplate, jn as ResolvedTarget, jt as AddressBookEntry, k as OrgMethods, kn as RecipientResolution, kt as ActorRequestsMethods, l as PostHogObservabilityClient, ln as MeProfile, lr as StateLabel, lt as PermissionRevokeInput, m as IdentityProfileDetails, mn as OfframpStatus, mr as InvocationControls, mt as OrgMeOptions, nn as DestinationListInput, nt as OrganizationPaymentsMethods, o as ObservationDelivery, on as DestinationsMethods, or as IdentityState, ot as PermissionMethods, p as CreateCapxulClientInput, pn as OfframpQuoteInput, pr as IdentityTransition, pt as OrgMeMethod, q as PayrollOptions, qn as Permission, qt as ActivityReference, r as CAPXUL_SDK_EXPECTED_OUTCOME_EVENT, rn as DestinationPayload, rr as TelemetryPort, rt as PermissionAssignInput, s as SdkFailureObservation, sn as FinancialOpsMethods, sr as OrgLane, st as PermissionOptions, t as CapxulClientInput, tn as DestinationKind, tt as OrganizationPaymentItemInput, u as PostHogObservabilityOptions, un as MovementActivityEvidence, ur as destination, ut as PermissionReadResult, v as Holding, vn as PaymentDocumentKind, vt as OrganizationOnboarding, w as CreateOrgInput, wn as PaymentStatus, wt as ActorProfile, x as MediaMethods, xn as PaymentDocumentVerification, xt as PersonOnboardingInput, y as SystemMethods, yn as PaymentDocumentRef, yt as OrganizationOnboardingInput, z as AuthorizeRunInput, zn as IdentityMethods, zt as ActivityDetail } from "./production-A1zW1JPt.mjs";
3
3
  import { Hex } from "viem";
4
4
  import { Effect, Layer } from "effect";
5
5
  //#region ../errors/src/index.d.ts
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
- import { A as signerFailure, B as isRestoring, C as normalizeExceptionErrorKind, E as safeExceptionLabel, F as CAPXUL_OPERATIONS, I as isCapxulOperation, L as normalizeCapxulOperation, M as PAYMENT_DIRECTIONS, N as PAYMENT_STATUSES, O as isSettingUpLifecycle, R as destination, S as SDK_VERSION, T as projectSdkException, _ as fingerprintPaymentIntent, b as failureDetail, d as embeddedSigner, f as openfortEmbeddedSigner, g as devPrivateKeySigner, h as deriveDevPrivateKey, j as resolveFailureMode, k as injectedWalletSigner, m as openfortEmbeddedWalletPort, p as openfortEmbeddedSignerFromWallet, r as postHogObservability, t as createCapxulClient$1, w as normalizeExceptionOperation, x as EXCEPTION_MESSAGE, y as CAPXUL_SDK_EXPECTED_OUTCOME_EVENT, z as isClaimed } from "./production-BndbwuVx.mjs";
2
- import { A as currencySymbolFor, B as toCurrencyCode, G as toHandle, M as toAddress, T as EVM_ADDRESS_RE, Y as toPartyId, b as configuredMoneyAssetById, dt as CHAIN_UPSTREAMS, ft as FAILURE_MODES, g as CAPXUL_PAYMENTS_V2_ADDRESS, it as HANDLE_RE, k as assetIdFor, lt as Errors, ot as CAPXUL_ERROR_CODES, st as CapxulError, ut as isCapxulError, z as toCountryCode } from "./OAuthBearerAuthClient-IB2W1Fzj.mjs";
1
+ import { A as signerFailure, B as isRestoring, C as normalizeExceptionErrorKind, E as safeExceptionLabel, F as CAPXUL_OPERATIONS, I as isCapxulOperation, L as normalizeCapxulOperation, M as PAYMENT_DIRECTIONS, N as PAYMENT_STATUSES, O as isSettingUpLifecycle, R as destination, S as SDK_VERSION, T as projectSdkException, _ as fingerprintPaymentIntent, b as failureDetail, d as embeddedSigner, f as openfortEmbeddedSigner, g as devPrivateKeySigner, h as deriveDevPrivateKey, j as resolveFailureMode, k as injectedWalletSigner, m as openfortEmbeddedWalletPort, p as openfortEmbeddedSignerFromWallet, r as postHogObservability, t as createCapxulClient$1, w as normalizeExceptionOperation, x as EXCEPTION_MESSAGE, y as CAPXUL_SDK_EXPECTED_OUTCOME_EVENT, z as isClaimed } from "./production-7jr-KUvX.mjs";
2
+ import { A as currencySymbolFor, B as toCurrencyCode, G as toHandle, M as toAddress, T as EVM_ADDRESS_RE, Y as toPartyId, at as HANDLE_RE, b as configuredMoneyAssetById, ct as CapxulError, dt as isCapxulError, ft as CHAIN_UPSTREAMS, g as CAPXUL_PAYMENTS_V2_ADDRESS, k as assetIdFor, pt as FAILURE_MODES, st as CAPXUL_ERROR_CODES, ut as Errors, z as toCountryCode } from "./OAuthBearerAuthClient-CbU_W9Sp.mjs";
3
3
  import { formatUnits } from "viem";
4
4
  import { Effect } from "effect";
5
5
  import { privateKeyToAccount } from "viem/accounts";
@@ -1,4 +1,4 @@
1
- import { M as toAddress, a as parseAuthSession, c as AuthCachePortTag, i as BrowserAuthCacheAdapter, o as parseCachedJwt, r as InMemoryAuthCacheAdapter, s as AuthCacheError, t as oauthBearerAuthClient } from "../OAuthBearerAuthClient-IB2W1Fzj.mjs";
1
+ import { M as toAddress, a as parseAuthSession, c as AuthCachePortTag, i as BrowserAuthCacheAdapter, o as parseCachedJwt, r as InMemoryAuthCacheAdapter, s as AuthCacheError, t as oauthBearerAuthClient } from "../OAuthBearerAuthClient-CbU_W9Sp.mjs";
2
2
  import { Effect, FileSystem, Layer, Path } from "effect";
3
3
  import { privateKeyToAccount } from "viem/accounts";
4
4
  import * as os from "node:os";
@@ -1,4 +1,4 @@
1
- import { $ as toRoleKey, B as toCurrencyCode, C as ASSET_ID_RE, Ct as redactSecrets, D as WEI_RE, E as SUPPORTED_CURRENCY_CODES, F as toAssetId, G as toHandle, H as toEmail, I as toAuthUserId, J as toOrgId, K as toJwtToken, L as toBudgetId, M as toAddress, N as toAllowedOrigin, O as ZERO_BYTES32, Q as toPublishableKey, R as toChainId, S as APP_ID_RE, St as isCredentialField, T as EVM_ADDRESS_RE$1, U as toEpochMs, V as toDurationMs, W as toEpochSeconds, X as toPayrollGroupId, Y as toPartyId, Z as toPayrollRunId, _ as normalizeBindingEmail, _t as failureFingerprint, at as decodeConvexError, bt as revertSummaryText, c as AuthCachePortTag, ct as EXPECTED_OPERATION_OUTCOMES, d as authClientPortFromPromiseAdapter, dt as CHAIN_UPSTREAMS, et as toSessionToken, f as AuthClientError, ft as FAILURE_MODES$1, gt as decodeChainCause, h as orgRoleKeyForLabel, ht as chainEvidenceLabel, i as BrowserAuthCacheAdapter, j as toAccountId, l as SystemClockLayer, lt as Errors, m as ADMIN_ROLE_LABEL, mt as chainCauseProperties, nt as toTxHash, ot as CAPXUL_ERROR_CODES, p as AuthClientPortTag, pt as boundedResponseHeaders, q as toKycTier, r as InMemoryAuthCacheAdapter, rt as validateHandle, st as CapxulError, tt as toTesterKind, u as ClockPortTag, ut as isCapxulError, v as BASE_SEPOLIA_CHAIN_ID, vt as isChainUpstream, w as BYTES32_RE, wt as redactUrlSecrets, x as ACCOUNT_ID_RE, xt as containsSensitiveMaterial, y as deriveCapxulSafeAddress, yt as isFailureMode, z as toCountryCode } from "./OAuthBearerAuthClient-IB2W1Fzj.mjs";
1
+ import { $ as toRoleKey, B as toCurrencyCode, C as ASSET_ID_RE, Ct as isCredentialField, D as WEI_RE, E as SUPPORTED_CURRENCY_CODES, F as toAssetId, G as toHandle, H as toEmail, I as toAuthUserId, J as toOrgId, K as toJwtToken, L as toBudgetId, M as toAddress, N as toAllowedOrigin, O as ZERO_BYTES32, Q as toPublishableKey, R as toChainId, S as APP_ID_RE, St as containsSensitiveMaterial, T as EVM_ADDRESS_RE$1, Tt as redactUrlSecrets, U as toEpochMs, V as toDurationMs, W as toEpochSeconds, X as toPayrollGroupId, Y as toPartyId, Z as toPayrollRunId, _ as normalizeBindingEmail, _t as decodeChainCause, b as configuredMoneyAssetById, bt as isFailureMode, c as AuthCachePortTag, ct as CapxulError, d as authClientPortFromPromiseAdapter, dt as isCapxulError, et as toSessionToken, f as AuthClientError, ft as CHAIN_UPSTREAMS, gt as chainEvidenceLabel, h as orgRoleKeyForLabel, ht as chainCauseProperties, i as BrowserAuthCacheAdapter, it as validateHandle, j as toAccountId, l as SystemClockLayer, lt as EXPECTED_OPERATION_OUTCOMES, m as ADMIN_ROLE_LABEL, mt as boundedResponseHeaders, nt as toTxHash, ot as decodeConvexError, p as AuthClientPortTag, pt as FAILURE_MODES$1, q as toKycTier, r as InMemoryAuthCacheAdapter, rt as toWeiAmount, st as CAPXUL_ERROR_CODES, tt as toTesterKind, u as ClockPortTag, ut as Errors, v as BASE_SEPOLIA_CHAIN_ID, vt as failureFingerprint, w as BYTES32_RE, wt as redactSecrets, x as ACCOUNT_ID_RE, xt as revertSummaryText, y as deriveCapxulSafeAddress, yt as isChainUpstream, z as toCountryCode } from "./OAuthBearerAuthClient-CbU_W9Sp.mjs";
2
2
  import { formatUnits, keccak256, parseUnits, recoverAddress, stringToHex, toBytes } from "viem";
3
3
  import { Cause, Clock, Context, Data, Deferred, Duration, Effect, Exit, Fiber, FiberSet, Layer, Option, Queue, Ref, Result, Schedule, Schema, SchemaGetter, SchemaIssue, SchemaParser, Scope, Stream, Tracer } from "effect";
4
4
  import { getFunctionName, makeFunctionReference } from "convex/server";
@@ -1363,7 +1363,27 @@ const PermissionMirrorVerificationProps = Schema.Struct({
1363
1363
  "conflicting_replay",
1364
1364
  "revision_mismatch"
1365
1365
  ])),
1366
- command_id: OptionalString
1366
+ command_id: OptionalString,
1367
+ /**
1368
+ * #1961 R03. The authorized stored row names the Permission it changed; the
1369
+ * verified receipt names the chain facts that prove it. Every field is
1370
+ * optional because a pending or provider-failed verification has neither an
1371
+ * application result nor a receipt to report.
1372
+ */
1373
+ permission_id: OptionalString,
1374
+ permission_assignment_id: OptionalString,
1375
+ permission_operation: Schema.optional(Schema.Literals([
1376
+ "create",
1377
+ "change",
1378
+ "assign",
1379
+ "revoke",
1380
+ "replace"
1381
+ ])),
1382
+ revision: Schema.optional(Schema.Number),
1383
+ user_op_hash: OptionalString,
1384
+ transaction_hash: OptionalString,
1385
+ block_number: Schema.optional(Schema.Number),
1386
+ log_index: Schema.optional(Schema.Number)
1367
1387
  });
1368
1388
  const MovementScanWindowProps = Schema.Struct({
1369
1389
  ...TelemetryEnvelopeProps,
@@ -2295,6 +2315,7 @@ const CAPXUL_FUNCTIONS = {
2295
2315
  list: "movement/activity:list",
2296
2316
  summary: "movement/activity:summary"
2297
2317
  },
2318
+ "movement/annotations": { overlay: "movement/annotations:overlay" },
2298
2319
  "moneyExecution/actions": {
2299
2320
  abandonPaymentExecution: "moneyExecution/actions:abandonPaymentExecution",
2300
2321
  preparePermissionExecution: "moneyExecution/actions:preparePermissionExecution",
@@ -2893,7 +2914,19 @@ const StoredPermissionCommandSchema = Schema.Struct({
2893
2914
  roleKey: RoleKeySchema,
2894
2915
  allowanceKey: Schema.NullOr(AllowanceKeySchema),
2895
2916
  memberSafe: Schema.NullOr(SafeAddressSchema),
2896
- expectedAuthorityEvents: Schema.Array(Bytes32Schema)
2917
+ expectedAuthorityEvents: Schema.Array(Bytes32Schema),
2918
+ /**
2919
+ * #1961 R03. The authenticated user who created the command, and the browser
2920
+ * linkage captured with it. Delayed verification and bounded retries read
2921
+ * this snapshot instead of the current viewer, so one command keeps one
2922
+ * origin. Both are absent on commands created before this contract.
2923
+ *
2924
+ * The context stays `unknown` on purpose: `sanitizeObservationContext` owns
2925
+ * the field allowlist, and every reader passes the stored value through it
2926
+ * rather than repeating those rules here.
2927
+ */
2928
+ originatingAuthUserId: Schema.optional(Schema.String),
2929
+ originatingObservationContext: Schema.optional(Schema.Unknown)
2897
2930
  });
2898
2931
  Schema.Struct({
2899
2932
  command: StoredPermissionCommandSchema,
@@ -5666,6 +5699,7 @@ const financialOpsContract = {
5666
5699
  activitySummary: makeFunctionReference(CAPXUL_FUNCTIONS["movement/activity"].summary),
5667
5700
  activityGet: makeFunctionReference(CAPXUL_FUNCTIONS["movement/activity"].get),
5668
5701
  activityAnnotate: makeFunctionReference(CAPXUL_FUNCTIONS["movement/activity"].annotate),
5702
+ activityOverlay: makeFunctionReference(CAPXUL_FUNCTIONS["movement/annotations"].overlay),
5669
5703
  verifyPaymentDocument: makeFunctionReference(CAPXUL_FUNCTIONS["financialOps/queries"].verifyPaymentDocument),
5670
5704
  renderStoredDocument: makeFunctionReference(CAPXUL_FUNCTIONS["financialOps/queries"].renderStoredDocument)
5671
5705
  };
@@ -5682,8 +5716,357 @@ const moneyExecutionContract = {
5682
5716
  submitPaymentCommandExecution: makeFunctionReference(CAPXUL_FUNCTIONS["moneyExecution/paymentCommandActions"].submitPaymentCommandExecution)
5683
5717
  };
5684
5718
  //#endregion
5719
+ //#region src/ports/indexer-read.ts
5720
+ /** The indexer's own page bound. Exceeding it is a caller defect, not a refusal. */
5721
+ const INDEXER_MAX_LIMIT = 1e3;
5722
+ const LOWER_CASE_ADDRESS = /^0x[0-9a-f]{40}$/;
5723
+ /**
5724
+ * Refuse a page the indexer would refuse, before any implementation spends a
5725
+ * round trip on it. Every implementation calls this, so a consumer test written
5726
+ * against the hermetic adapter cannot pass on input production rejects. Throws
5727
+ * a `CapxulError`; callers convert it to an `IndexerReadError`.
5728
+ */
5729
+ function assertIndexerPage(input) {
5730
+ const safe = String(input.safe).toLowerCase();
5731
+ if (!LOWER_CASE_ADDRESS.test(safe)) throw Errors.invalidInput("safe", "must be a lower-case EVM address");
5732
+ if (!Number.isSafeInteger(input.limit) || input.limit < 1 || input.limit > 1e3) throw Errors.invalidInput("limit", `must be an integer from 1 to ${INDEXER_MAX_LIMIT}`);
5733
+ const offset = input.offset ?? 0;
5734
+ if (!Number.isSafeInteger(offset) || offset < 0) throw Errors.invalidInput("offset", "must be a non-negative integer");
5735
+ return safe;
5736
+ }
5737
+ var IndexerReadError = class extends Data.TaggedError("IndexerReadError") {};
5738
+ function indexerReadErrorFromCapxul(operation, error, cause = error) {
5739
+ return new IndexerReadError({
5740
+ operation,
5741
+ publicCode: error.code,
5742
+ publicError: error,
5743
+ cause,
5744
+ ...error.details === void 0 ? {} : { details: error.details }
5745
+ });
5746
+ }
5747
+ Context.Service()("@capxul/sdk/ports/IndexerReadPort");
5748
+ //#endregion
5749
+ //#region src/surface/activity-stitch.ts
5750
+ /** Epoch milliseconds of the block that carried the row. */
5751
+ function blockMillis(row) {
5752
+ return Number(row.timestamp) * 1e3;
5753
+ }
5754
+ /** `0x1234…abcd` — the counterparty of an unclaimed transfer is an address. */
5755
+ function shortAddressLabel(address) {
5756
+ return address.length <= 12 ? address : `${address.slice(0, 6)}…${address.slice(-4)}`;
5757
+ }
5758
+ function directionFor(safe, transfer) {
5759
+ const from = transfer.from.toLowerCase();
5760
+ const to = transfer.to.toLowerCase();
5761
+ if (from === safe && to === safe) return "self";
5762
+ return to === safe ? "in" : "out";
5763
+ }
5764
+ /**
5765
+ * The Transfer a protocol Payment moved is the same money as its `payment`
5766
+ * row. One actor sees one item for it, so the Transfer is claimed and does not
5767
+ * become a second row. Another transfer in the same transaction that this
5768
+ * payment did not move stays unclaimed and keeps its own row.
5769
+ */
5770
+ function claimedTransferIds(transfers, payments) {
5771
+ const claimed = /* @__PURE__ */ new Set();
5772
+ for (const payment of payments) {
5773
+ const match = transfers.find((transfer) => !claimed.has(transfer.id) && transfer.txHash === payment.txHash && transfer.token.toLowerCase() === payment.token.toLowerCase() && transfer.amount === payment.amount && transfer.to.toLowerCase() === payment.recipient.toLowerCase());
5774
+ if (match !== void 0) claimed.add(match.id);
5775
+ }
5776
+ return claimed;
5777
+ }
5778
+ function withAnnotation(item, annotation) {
5779
+ return annotation?.counterpartyLabel === void 0 ? item : {
5780
+ ...item,
5781
+ counterpartyLabel: annotation.counterpartyLabel
5782
+ };
5783
+ }
5784
+ /**
5785
+ * Confirmation comes from the chain, never from Convex.
5786
+ *
5787
+ * A Ponder row for this Payment's settlement means settled, and its receipt is
5788
+ * the indexed transaction. No Ponder row and a Convex row that still says
5789
+ * settled means the block that carried it was dropped: the row goes back to
5790
+ * `settling` and its annotation, which keys on the Payment id, is untouched.
5791
+ */
5792
+ function confirmPayment(intent, chain, hasSettlement) {
5793
+ if (chain !== void 0) return {
5794
+ ...intent,
5795
+ status: "settled",
5796
+ receipt: {
5797
+ chainId: chain.chainId,
5798
+ transactionHash: chain.txHash
5799
+ },
5800
+ updatedAt: blockMillis(chain)
5801
+ };
5802
+ if (hasSettlement && intent.status === "settled") return {
5803
+ ...intent,
5804
+ status: "settling",
5805
+ receipt: null
5806
+ };
5807
+ return intent;
5808
+ }
5809
+ /**
5810
+ * One unclaimed Transfer as an Activity row, or `null` when this SDK cannot
5811
+ * denominate its asset. The indexer serves only configured assets, so a row
5812
+ * the registry does not know means the SDK and that deployment disagree; it is
5813
+ * dropped rather than shown with a guessed currency.
5814
+ */
5815
+ function transferItem(safe, transfer, annotation) {
5816
+ const asset = configuredMoneyAssetById(transfer.assetId);
5817
+ if (asset === null) return null;
5818
+ const direction = directionFor(safe, transfer);
5819
+ const counterparty = direction === "in" ? transfer.from : transfer.to;
5820
+ const at = blockMillis(transfer);
5821
+ return withAnnotation({
5822
+ kind: "movement",
5823
+ id: transfer.id,
5824
+ classification: "movement_only_outflow",
5825
+ amount: {
5826
+ currency: asset.peg ?? asset.symbol,
5827
+ value: formatUnits(transfer.amount, asset.decimals),
5828
+ decimals: asset.decimals
5829
+ },
5830
+ direction,
5831
+ counterpartyLabel: shortAddressLabel(counterparty),
5832
+ receipt: {
5833
+ chainId: transfer.chainId,
5834
+ transactionHash: transfer.txHash
5835
+ },
5836
+ createdAt: at,
5837
+ updatedAt: at
5838
+ }, annotation);
5839
+ }
5840
+ /** Newest first. A Payment precedes a Movement at one instant, as the ledger reader orders them. */
5841
+ function compareItems(left, right) {
5842
+ if (right.createdAt !== left.createdAt) return right.createdAt - left.createdAt;
5843
+ if (left.kind !== right.kind) return left.kind === "payment" ? -1 : 1;
5844
+ if (left.id === right.id) return 0;
5845
+ return left.id < right.id ? 1 : -1;
5846
+ }
5847
+ function stitchActivity(input) {
5848
+ const safe = input.safe.toLowerCase();
5849
+ const chainBySettlement = /* @__PURE__ */ new Map();
5850
+ for (const row of input.payments) chainBySettlement.set(row.settlementId.toLowerCase(), row);
5851
+ const chainByPaymentId = /* @__PURE__ */ new Map();
5852
+ const settledPaymentIds = /* @__PURE__ */ new Set();
5853
+ for (const link of input.links) {
5854
+ settledPaymentIds.add(link.paymentId);
5855
+ const row = chainBySettlement.get(link.settlementId.toLowerCase());
5856
+ if (row !== void 0) chainByPaymentId.set(link.paymentId, row);
5857
+ }
5858
+ const annotations = /* @__PURE__ */ new Map();
5859
+ for (const annotation of input.annotations) annotations.set(`${annotation.reference.kind}:${annotation.reference.id}`, annotation);
5860
+ const items = [];
5861
+ const claiming = [];
5862
+ for (const intent of input.intents) {
5863
+ if (intent.kind !== "payment") continue;
5864
+ const chain = chainByPaymentId.get(intent.id);
5865
+ if (chain !== void 0) claiming.push(chain);
5866
+ items.push(withAnnotation(confirmPayment(intent, chain, settledPaymentIds.has(intent.id)), annotations.get(`payment:${intent.id}`)));
5867
+ }
5868
+ const claimed = claimedTransferIds(input.transfers, claiming);
5869
+ for (const transfer of input.transfers) {
5870
+ if (claimed.has(transfer.id)) continue;
5871
+ const item = transferItem(safe, transfer, annotations.get(`movement:${transfer.id}`));
5872
+ if (item !== null) items.push(item);
5873
+ }
5874
+ return items.sort(compareItems);
5875
+ }
5876
+ /** The reference ids one stitched page needs its Convex overlay for. */
5877
+ function overlayReferences(items) {
5878
+ return items.map((item) => ({
5879
+ kind: item.kind,
5880
+ id: item.id
5881
+ }));
5882
+ }
5883
+ /**
5884
+ * Money in, money out and the pending share, one bucket per currency and
5885
+ * precision. Two assets that peg to the same currency at different precision
5886
+ * stay distinct buckets: their raw units are not interchangeable.
5887
+ */
5888
+ function summarizeItems(items) {
5889
+ const buckets = /* @__PURE__ */ new Map();
5890
+ for (const item of items) {
5891
+ const key = `${item.amount.currency}:${String(item.amount.decimals)}`;
5892
+ const bucket = buckets.get(key) ?? {
5893
+ currency: item.amount.currency,
5894
+ decimals: item.amount.decimals,
5895
+ in: 0n,
5896
+ out: 0n,
5897
+ pendingIn: 0n
5898
+ };
5899
+ const raw = rawUnits(item.amount.value, item.amount.decimals);
5900
+ if (item.direction === "in") {
5901
+ bucket.in += raw;
5902
+ if (item.kind === "payment" && item.status !== "settled") bucket.pendingIn += raw;
5903
+ } else if (item.direction === "out") bucket.out += raw;
5904
+ buckets.set(key, bucket);
5905
+ }
5906
+ return [...buckets.values()].map((bucket) => ({
5907
+ currency: bucket.currency,
5908
+ decimals: bucket.decimals,
5909
+ in: bucket.in.toString(),
5910
+ out: bucket.out.toString(),
5911
+ net: (bucket.in - bucket.out).toString(),
5912
+ pendingIn: bucket.pendingIn.toString()
5913
+ }));
5914
+ }
5915
+ /** The inverse of `formatUnits`, kept exact: `"1.25"` at 6 decimals is `1250000n`. */
5916
+ function rawUnits(value, decimals) {
5917
+ const negative = value.startsWith("-");
5918
+ const [whole = "0", fraction = ""] = (negative ? value.slice(1) : value).split(".");
5919
+ const raw = BigInt(`${whole}${fraction.padEnd(decimals, "0").slice(0, decimals)}`);
5920
+ return negative ? -raw : raw;
5921
+ }
5922
+ //#endregion
5923
+ //#region src/surface/activity-read.ts
5924
+ /** How many Convex intent rows one page reads for its labels and pending rows. */
5925
+ const INTENT_WINDOW = 100;
5926
+ /** The window a summary aggregates over. The indexer's own page bound. */
5927
+ const SUMMARY_WINDOW = INDEXER_MAX_LIMIT;
5928
+ function parseCursor(value) {
5929
+ if (value === void 0) return 0;
5930
+ try {
5931
+ const parsed = JSON.parse(value);
5932
+ return Number.isSafeInteger(parsed.offset) && parsed.offset >= 0 ? parsed.offset : 0;
5933
+ } catch {
5934
+ return 0;
5935
+ }
5936
+ }
5937
+ function inRange(item, range) {
5938
+ if (range?.from !== void 0 && item.createdAt < range.from) return false;
5939
+ return range?.to === void 0 || item.createdAt <= range.to;
5940
+ }
5941
+ /** The caller's filter applied to the merged page. The join owns the order. */
5942
+ function matchesFilter(item, filter) {
5943
+ if (filter === void 0) return true;
5944
+ if (filter.kind !== void 0 && item.kind !== filter.kind) return false;
5945
+ if (filter.direction !== void 0 && item.direction !== filter.direction) return false;
5946
+ if (filter.status === void 0) return true;
5947
+ return item.kind === "payment" && filter.status.includes(item.status);
5948
+ }
5949
+ function overlay(deps, actor, controls, input) {
5950
+ return deps.convexCall.query(deps.functions.activityOverlay, copyInvocationObservation(controls, { input: {
5951
+ ...actor === void 0 ? {} : { actor },
5952
+ ...input.references === void 0 ? {} : { references: input.references },
5953
+ ...input.settlementIds === void 0 ? {} : { settlementIds: input.settlementIds }
5954
+ } }));
5955
+ }
5956
+ function convexPage(deps, actor, controls, input) {
5957
+ return deps.convexCall.query(deps.functions.activityList, copyInvocationObservation(controls, { input: {
5958
+ ...actor === void 0 ? {} : { actor },
5959
+ ...input.cursor === void 0 ? {} : { cursor: input.cursor },
5960
+ ...input.limit === void 0 ? {} : { limit: input.limit },
5961
+ ...input.range === void 0 ? {} : { range: input.range }
5962
+ } }));
5963
+ }
5964
+ /** Both indexed tables for one Safe, or `null` when the indexer cannot answer. */
5965
+ function chainRows(deps, safe, limit) {
5966
+ const page = {
5967
+ safe,
5968
+ limit: Math.min(limit, INDEXER_MAX_LIMIT)
5969
+ };
5970
+ return Effect.all([deps.indexer.read("transfer", page), deps.indexer.read("payment", page)], { concurrency: 2 }).pipe(Effect.map(([transfers, payments]) => ({
5971
+ transfers,
5972
+ payments
5973
+ })), Effect.catch(() => Effect.succeed(null)));
5974
+ }
5975
+ /** The stitched, filtered rows of one window, newest first. */
5976
+ function stitchedWindow(deps, actor, controls, window, params) {
5977
+ return Effect.gen(function* () {
5978
+ const scope = yield* overlay(deps, actor, controls, {});
5979
+ const convex = yield* convexPage(deps, actor, controls, {
5980
+ limit: INTENT_WINDOW,
5981
+ ...params.range === void 0 ? {} : { range: params.range }
5982
+ });
5983
+ const rows = scope.safe === null ? null : yield* chainRows(deps, scope.safe, window);
5984
+ if (rows === null || scope.safe === null) return {
5985
+ items: convex.items.filter((item) => matchesFilter(item, params.filter)),
5986
+ stitched: false
5987
+ };
5988
+ const decoration = yield* overlay(deps, actor, controls, {
5989
+ references: [...overlayReferences(convex.items), ...rows.transfers.map((row) => ({
5990
+ kind: "movement",
5991
+ id: row.id
5992
+ }))],
5993
+ settlementIds: rows.payments.map((row) => row.settlementId)
5994
+ });
5995
+ return {
5996
+ items: stitchActivity({
5997
+ safe: scope.safe,
5998
+ transfers: rows.transfers,
5999
+ payments: rows.payments,
6000
+ intents: convex.items,
6001
+ links: decoration.links,
6002
+ annotations: decoration.annotations
6003
+ }).filter((item) => inRange(item, params.range) && matchesFilter(item, params.filter)),
6004
+ stitched: true
6005
+ };
6006
+ });
6007
+ }
6008
+ function readActivityPage(deps, actor, controls, params) {
6009
+ const limit = params?.limit ?? 25;
6010
+ const offset = parseCursor(params?.cursor);
6011
+ return stitchedWindow(deps, actor, controls, offset + limit + 1, {
6012
+ ...params?.range === void 0 ? {} : { range: params.range },
6013
+ ...params?.filter === void 0 ? {} : { filter: params.filter }
6014
+ }).pipe(Effect.map(({ items, stitched }) => {
6015
+ const observedAt = Date.now();
6016
+ if (!stitched) return {
6017
+ items: items.slice(0, limit),
6018
+ cursor: null,
6019
+ checkpoint: observedAt,
6020
+ observedAt
6021
+ };
6022
+ return {
6023
+ items: items.slice(offset, offset + limit),
6024
+ cursor: items.length > offset + limit ? JSON.stringify({ offset: offset + limit }) : null,
6025
+ checkpoint: observedAt,
6026
+ observedAt
6027
+ };
6028
+ }));
6029
+ }
6030
+ function readActivitySummary(deps, actor, controls, params) {
6031
+ return stitchedWindow(deps, actor, controls, SUMMARY_WINDOW, params?.window === void 0 ? {} : { range: params.window }).pipe(Effect.map(({ items }) => ({
6032
+ window: {
6033
+ from: params?.window?.from ?? null,
6034
+ to: params?.window?.to ?? null
6035
+ },
6036
+ totals: summarizeItems(items),
6037
+ count: items.length,
6038
+ observedAt: Date.now()
6039
+ })));
6040
+ }
6041
+ /**
6042
+ * Tell the caller when the indexed page for this Safe changed.
6043
+ *
6044
+ * The transport is the indexer's one SSE connection, wired in the Ponder
6045
+ * adapter under `activity.subscribe`. A reactive snapshot is not a product
6046
+ * event, so nothing here emits telemetry: the adapter reports a teardown, and
6047
+ * the caller re-reads.
6048
+ */
6049
+ function subscribeActivity(deps, actor, controls, onChange) {
6050
+ return Effect.gen(function* () {
6051
+ const scope = yield* overlay(deps, actor, controls, {});
6052
+ if (scope.safe === null) return () => {};
6053
+ const page = {
6054
+ safe: scope.safe,
6055
+ limit: INTENT_WINDOW
6056
+ };
6057
+ let delivered = false;
6058
+ const notify = () => {
6059
+ if (delivered) onChange();
6060
+ delivered = true;
6061
+ };
6062
+ return yield* deps.indexer.subscribe("transfer", page, (snapshot) => {
6063
+ if (snapshot.status === "ok") notify();
6064
+ });
6065
+ });
6066
+ }
6067
+ //#endregion
5685
6068
  //#region package.json
5686
- var version = "4.2.0-rc.10";
6069
+ var version = "4.2.0-rc.11";
5687
6070
  //#endregion
5688
6071
  //#region src/telemetry/exception-projection.ts
5689
6072
  /** Fixed fallback for failures that have no safe message. */
@@ -5881,10 +6264,15 @@ function observeFailedResult(result, adapter, operation, origin) {
5881
6264
  * A reactive stream is torn down after its call already returned, so nothing
5882
6265
  * downstream observes it. `captureException` is the right kind: the caller did
5883
6266
  * not ask for the end, so it is not an expected product outcome.
6267
+ *
6268
+ * A caller that DID ask for the end — the session it authenticated with
6269
+ * expired, and the service closed the stream on purpose — passes
6270
+ * `kind: "operation"` instead, so the refusal lands in the expected-outcome
6271
+ * stream its code already declares.
5884
6272
  */
5885
- function observeStreamFailure(adapter, operation, cause) {
6273
+ function observeStreamFailure(adapter, operation, cause, kind = "exception") {
5886
6274
  if (adapter === void 0) return;
5887
- report(adapter, "exception", operation, cause, resolveAdapterSnapshot(adapter));
6275
+ report(adapter, kind, operation, cause, resolveAdapterSnapshot(adapter));
5888
6276
  }
5889
6277
  /**
5890
6278
  * One failure, one event. The identity machine reports a failed transition
@@ -6989,6 +7377,11 @@ function paymentExecutionIntent(input) {
6989
7377
  }
6990
7378
  function makeFinancialOpsMethods(deps) {
6991
7379
  const fns = deps.functions ?? financialOpsContract;
7380
+ const indexerDeps = deps.indexerRead === void 0 ? void 0 : {
7381
+ indexer: deps.indexerRead,
7382
+ convexCall: deps.convexCall,
7383
+ functions: fns
7384
+ };
6992
7385
  const executionFns = deps.moneyExecutionFunctions ?? moneyExecutionContract;
6993
7386
  const requestKeyScope = deps.requestKeyScope ?? randomPaymentRequestKey();
6994
7387
  const inFlightPersonalPayments = /* @__PURE__ */ new Map();
@@ -7219,22 +7612,26 @@ function makeFinancialOpsMethods(deps) {
7219
7612
  }
7220
7613
  },
7221
7614
  activity: {
7615
+ subscribe: (onChange, params, options) => {
7616
+ const controls = deps.invocationControls?.(options) ?? options;
7617
+ return runPortEffect(captureActivityInput(() => Effect.succeed(activityActorField(params?.actor).actor)).pipe(Effect.flatMap((actor) => indexerDeps === void 0 ? Effect.succeed(() => {}) : Effect.suspend(() => subscribeActivity(indexerDeps, actor, controls, onChange)).pipe(Effect.tap(() => observeActivityScope(actor))))), controls, CAPXUL_OPERATIONS.activity.subscribe, deps.runPromise);
7618
+ },
7222
7619
  list: (params, options) => {
7223
7620
  const controls = deps.invocationControls?.(options) ?? options;
7224
- return runPortEffect(captureActivityInput(() => Effect.succeed(activityActorField(params?.actor).actor)).pipe(Effect.flatMap((actor) => Effect.suspend(() => deps.convexCall.query(fns.activityList, copyInvocationObservation(controls, { input: {
7621
+ return runPortEffect(captureActivityInput(() => Effect.succeed(activityActorField(params?.actor).actor)).pipe(Effect.flatMap((actor) => Effect.suspend(() => indexerDeps === void 0 ? deps.convexCall.query(fns.activityList, copyInvocationObservation(controls, { input: {
7225
7622
  ...actor === void 0 ? {} : { actor },
7226
7623
  ...params?.cursor === void 0 ? {} : { cursor: params.cursor },
7227
7624
  ...params?.limit === void 0 ? {} : { limit: params.limit },
7228
7625
  ...params?.range === void 0 ? {} : { range: params.range },
7229
7626
  ...params?.filter === void 0 ? {} : { filter: params.filter }
7230
- } }))).pipe(Effect.tap(() => observeActivityScope(actor))))), controls, CAPXUL_OPERATIONS.activity.list, deps.runPromise);
7627
+ } })) : readActivityPage(indexerDeps, actor, controls, params)).pipe(Effect.tap(() => observeActivityScope(actor))))), controls, CAPXUL_OPERATIONS.activity.list, deps.runPromise);
7231
7628
  },
7232
7629
  summary: (params, options) => {
7233
7630
  const controls = deps.invocationControls?.(options) ?? options;
7234
- return runPortEffect(captureActivityInput(() => Effect.succeed(activityActorField(params?.actor).actor)).pipe(Effect.flatMap((actor) => Effect.suspend(() => deps.convexCall.query(fns.activitySummary, copyInvocationObservation(controls, { input: {
7631
+ return runPortEffect(captureActivityInput(() => Effect.succeed(activityActorField(params?.actor).actor)).pipe(Effect.flatMap((actor) => Effect.suspend(() => indexerDeps === void 0 ? deps.convexCall.query(fns.activitySummary, copyInvocationObservation(controls, { input: {
7235
7632
  ...actor === void 0 ? {} : { actor },
7236
7633
  ...params?.window === void 0 ? {} : { window: params.window }
7237
- } }))).pipe(Effect.tap(() => observeActivityScope(actor))))), controls, CAPXUL_OPERATIONS.activity.summary, deps.runPromise);
7634
+ } })) : readActivitySummary(indexerDeps, actor, controls, params)).pipe(Effect.tap(() => observeActivityScope(actor))))), controls, CAPXUL_OPERATIONS.activity.summary, deps.runPromise);
7238
7635
  },
7239
7636
  get: (reference, options) => {
7240
7637
  const controls = deps.invocationControls?.(options) ?? options;
@@ -9041,6 +9438,9 @@ const OBSERVED_CONVEX_ACTIONS = /* @__PURE__ */ new Set([
9041
9438
  "org/actions:resumeBootstrapSubmission",
9042
9439
  "org/actions:confirmBootstrap",
9043
9440
  "org/actions:readTreasury",
9441
+ "moneyExecution/actions:preparePermissionExecution",
9442
+ "moneyExecution/actions:submitPermissionExecution",
9443
+ "permission/actions:verify",
9044
9444
  "moneyExecution/actions:preparePaymentExecution",
9045
9445
  "moneyExecution/actions:abandonPaymentExecution",
9046
9446
  "moneyExecution/actions:submitPaymentExecution",
@@ -9065,6 +9465,9 @@ const OBSERVED_CONVEX_QUERIES = /* @__PURE__ */ new Set([
9065
9465
  "payroll/queries:groups",
9066
9466
  "payroll/queries:terms",
9067
9467
  "financialOps/queries:resolveRecipient",
9468
+ "org/queries:me",
9469
+ "permission/queries:read",
9470
+ "permission/queries:authorize",
9068
9471
  "identity/queries:loadByAuthUserId",
9069
9472
  "smartAccount/queries:loadByAuthUserId",
9070
9473
  "org/lifecycle:load"
@@ -9083,6 +9486,7 @@ const OBSERVED_CONVEX_MUTATIONS = /* @__PURE__ */ new Set([
9083
9486
  "financialOps/requestsInbox:decline",
9084
9487
  "payroll/mutations:saveGroup",
9085
9488
  "payroll/mutations:removeGroup",
9489
+ "permission/mutations:command",
9086
9490
  "identity/mutations:create",
9087
9491
  "identity/mutations:update",
9088
9492
  "identity/mutations:completeOnboarding",
@@ -12139,8 +12543,33 @@ function toOrgMe(wire) {
12139
12543
  observedAt: wire.observedAt
12140
12544
  };
12141
12545
  }
12546
+ /**
12547
+ * The read runs through the canonical observed runner, so `org.me` owns one
12548
+ * `capxul_sdk_operation` record and one span like every other public method.
12549
+ *
12550
+ * The call-start invocation snapshot travels on the query arguments: the
12551
+ * Convex adapter reads it there and sends the browser linkage with the call,
12552
+ * so an account switch mid-flight cannot re-resolve the actor. A successful
12553
+ * read proves participation in this Organization, so the owning span carries
12554
+ * the verified Organization and the two authority booleans the backend
12555
+ * actually enforces. Labels and Budget caps stay off the record.
12556
+ */
12142
12557
  function makeOrgMeMethod(deps, orgId) {
12143
- return (options) => runIfActive(options?.signal, CAPXUL_OPERATIONS.org.me, () => Effect.map(deps.convexCall.query(orgReadContract.me, { orgId }), toOrgMe));
12558
+ return (options) => {
12559
+ const controls = deps.invocationControls?.(options) ?? options;
12560
+ return runCapxulEffect(Effect.gen(function* () {
12561
+ const wire = yield* deps.convexCall.query(orgReadContract.me, copyInvocationObservation(controls, { orgId })).pipe(Effect.mapError((failure) => failure.publicError));
12562
+ yield* Effect.annotateCurrentSpan({
12563
+ verified_organization_id: orgId,
12564
+ scope_kind: "organization",
12565
+ can_manage_people: wire.capabilities.canManagePeople,
12566
+ can_spend: wire.capabilities.canSpend,
12567
+ budget_count: wire.budgets.length,
12568
+ observed_at: wire.observedAt
12569
+ }).pipe(Effect.catchCause(() => Effect.void));
12570
+ return toOrgMe(wire);
12571
+ }), controls, CAPXUL_OPERATIONS.org.me, deps.runPromise);
12572
+ };
12144
12573
  }
12145
12574
  //#endregion
12146
12575
  //#region src/contract/permission.ts
@@ -12160,16 +12589,24 @@ function isAborted(signal) {
12160
12589
  */
12161
12590
  function observed(deps, operation, options, run) {
12162
12591
  const controls = deps.invocationControls?.(options) ?? options;
12592
+ let verifiedOrganizationId;
12163
12593
  return runCapxulEffect(Effect.gen(function* () {
12164
12594
  if (controls?.signal?.aborted === true) return yield* Effect.fail(Errors.cancelled({ operation }));
12595
+ const parent = yield* Effect.currentSpan.pipe(Effect.orDie);
12596
+ const captured = carryInvocationParentSpan(controls, parent);
12165
12597
  const result = yield* Effect.tryPromise({
12166
- try: () => run(controls?.signal),
12598
+ try: () => run(controls?.signal, captured, (orgId) => {
12599
+ verifiedOrganizationId = orgId;
12600
+ }),
12167
12601
  catch: (cause) => cause instanceof CapxulError ? cause : Errors.unknown(cause)
12168
12602
  });
12169
12603
  return yield* result.ok ? Effect.succeed(result.value) : Effect.fail(result.error);
12170
- }), observationOnlyControls(controls), operation, deps.runPromise);
12604
+ }).pipe(Effect.ensuring(Effect.suspend(() => verifiedOrganizationId === void 0 ? Effect.void : Effect.annotateCurrentSpan({
12605
+ verified_organization_id: verifiedOrganizationId,
12606
+ scope_kind: "organization"
12607
+ })).pipe(Effect.catchCause(() => Effect.void)))), observationOnlyControls(controls), operation, deps.runPromise);
12171
12608
  }
12172
- async function execute(deps, orgId, command, signal) {
12609
+ async function execute(deps, orgId, command, signal, controls, verifiedOrganization) {
12173
12610
  if (isAborted(signal)) return {
12174
12611
  ok: false,
12175
12612
  error: Errors.cancelled({ operation: "permissions" })
@@ -12193,17 +12630,18 @@ async function execute(deps, orgId, command, signal) {
12193
12630
  };
12194
12631
  }
12195
12632
  const executionFns = deps.executionFunctions ?? moneyExecutionContract;
12196
- const prepared = await runIfActive(signal, CAPXUL_OPERATIONS.permissions.prepareExecution, () => deps.convexCall.action(executionFns.preparePermissionExecution, { input: {
12633
+ const prepared = await runIfActive(signal, CAPXUL_OPERATIONS.permissions.prepareExecution, () => withInvocationParentSpan(Effect.suspend(() => deps.convexCall.action(executionFns.preparePermissionExecution, copyInvocationObservation(controls, { input: {
12197
12634
  orgId,
12198
12635
  signerAddress,
12199
12636
  command
12200
- } }));
12637
+ } }))), controls), deps.runPromise);
12201
12638
  if (!prepared.ok) return prepared;
12202
12639
  const expectedSafe = deriveCapxulSafeAddress({ email: session.email });
12203
12640
  if (prepared.value.chainId !== deps.chainId || prepared.value.signerAddress.toLowerCase() !== signerAddress.toLowerCase() || prepared.value.userOpSenderSafe.toLowerCase() !== expectedSafe.toLowerCase() || prepared.value.operation !== command.operation || prepared.value.orgId !== orgId || canonicalJson(prepared.value.command) !== canonicalJson(command)) return {
12204
12641
  ok: false,
12205
12642
  error: Errors.invalidInput("permission", "prepared authority mismatch")
12206
12643
  };
12644
+ verifiedOrganization(prepared.value.orgId);
12207
12645
  if (isAborted(signal)) return {
12208
12646
  ok: false,
12209
12647
  error: Errors.cancelled({ operation: "permissions" })
@@ -12221,38 +12659,40 @@ async function execute(deps, orgId, command, signal) {
12221
12659
  ok: false,
12222
12660
  error: Errors.cancelled({ operation: "permissions" })
12223
12661
  };
12224
- return runIfActive(void 0, CAPXUL_OPERATIONS.permissions.submitExecution, () => deps.convexCall.action(executionFns.submitPermissionExecution, { input: {
12662
+ return runIfActive(void 0, CAPXUL_OPERATIONS.permissions.submitExecution, () => withInvocationParentSpan(Effect.suspend(() => deps.convexCall.action(executionFns.submitPermissionExecution, copyInvocationObservation(controls, { input: {
12225
12663
  executionId: prepared.value.executionId,
12226
12664
  signature
12227
- } }));
12665
+ } }))), controls), deps.runPromise);
12228
12666
  }
12229
12667
  function makePermissionMethods(deps, orgId) {
12230
12668
  const reads = deps.permissionFunctions ?? permissionContract;
12231
12669
  const ops = CAPXUL_OPERATIONS.org.permissions;
12670
+ const read = (signal, operation, controls) => runIfActive(signal, operation, () => withInvocationParentSpan(Effect.suspend(() => deps.convexCall.query(reads.read, copyInvocationObservation(controls, { orgId }))), controls), deps.runPromise);
12671
+ const command = (operation, build, options) => observed(deps, operation, options, (signal, captured, verifiedOrganization) => execute(deps, orgId, build(), signal, captured, verifiedOrganization));
12232
12672
  return {
12233
- create: (input, options) => observed(deps, ops.create, options, (signal) => execute(deps, orgId, {
12673
+ create: (input, options) => command(ops.create, () => ({
12234
12674
  operation: "create",
12235
12675
  ...input
12236
- }, signal)),
12237
- change: (input, options) => observed(deps, ops.change, options, (signal) => execute(deps, orgId, {
12676
+ }), options),
12677
+ change: (input, options) => command(ops.change, () => ({
12238
12678
  operation: "change",
12239
12679
  ...input
12240
- }, signal)),
12241
- assign: (input, options) => observed(deps, ops.assign, options, (signal) => execute(deps, orgId, {
12680
+ }), options),
12681
+ assign: (input, options) => command(ops.assign, () => ({
12242
12682
  operation: "assign",
12243
12683
  ...input
12244
- }, signal)),
12245
- revoke: (input, options) => observed(deps, ops.revoke, options, (signal) => execute(deps, orgId, {
12684
+ }), options),
12685
+ revoke: (input, options) => command(ops.revoke, () => ({
12246
12686
  operation: "revoke",
12247
12687
  ...input
12248
- }, signal)),
12249
- replace: (input, options) => observed(deps, ops.replace, options, (signal) => execute(deps, orgId, {
12688
+ }), options),
12689
+ replace: (input, options) => command(ops.replace, () => ({
12250
12690
  operation: "replace",
12251
12691
  ...input
12252
- }, signal)),
12253
- list: (options) => observed(deps, ops.list, options, (signal) => runIfActive(signal, CAPXUL_OPERATIONS.permissions.list, () => deps.convexCall.query(reads.read, { orgId }))),
12254
- get: (permissionId, options) => observed(deps, ops.get, options, async (signal) => {
12255
- const listed = await runIfActive(signal, CAPXUL_OPERATIONS.permissions.get, () => deps.convexCall.query(reads.read, { orgId }));
12692
+ }), options),
12693
+ list: (options) => observed(deps, ops.list, options, (signal, captured) => read(signal, CAPXUL_OPERATIONS.permissions.list, captured)),
12694
+ get: (permissionId, options) => observed(deps, ops.get, options, async (signal, captured) => {
12695
+ const listed = await read(signal, CAPXUL_OPERATIONS.permissions.get, captured);
12256
12696
  if (!listed.ok) return listed;
12257
12697
  return {
12258
12698
  ok: true,
@@ -13123,7 +13563,10 @@ function makeOrgMethods(deps) {
13123
13563
  },
13124
13564
  ...convexCall === void 0 ? {} : { convexCall }
13125
13565
  }),
13126
- me: convexCall === void 0 ? orgMeUnavailable : makeOrgMeMethod({ convexCall }, String(orgId)),
13566
+ me: convexCall === void 0 ? orgMeUnavailable : makeOrgMeMethod({
13567
+ convexCall,
13568
+ ...observedRunnerDeps(deps)
13569
+ }, String(orgId)),
13127
13570
  async getLifecycle(options) {
13128
13571
  if (options?.signal?.aborted) return {
13129
13572
  ok: false,
@@ -13360,14 +13803,65 @@ function compareDecimal(first, second) {
13360
13803
  }
13361
13804
  //#endregion
13362
13805
  //#region src/surface/holdings.ts
13806
+ /** SPEC Freshness: past this block age the read is labelled stale. Nothing refuses. */
13807
+ const FRESHNESS_LIMIT_SECONDS = 60;
13808
+ /**
13809
+ * The Ponder balance view for one Safe as `CurrentHoldings`.
13810
+ *
13811
+ * The view is the signed sum of every indexed transfer, so the balance IS what
13812
+ * the chain said — there is no snapshot to go stale behind it. `observedAt` is
13813
+ * the indexed block's own timestamp, which is what the last-good label reads,
13814
+ * and `stale` is that block's age. A stopped indexer therefore shows an old
13815
+ * "as of" and the stale flag; it never turns the read into a refusal.
13816
+ */
13817
+ function indexerHoldings(indexer, convexCall, overlay, actor, controls) {
13818
+ return Effect.gen(function* () {
13819
+ const scope = yield* convexCall.query(overlay, copyInvocationObservation(controls, actor?.kind === "organization" ? { input: { actor: {
13820
+ kind: "organization",
13821
+ orgId: actor.organizationId
13822
+ } } } : { input: {} }));
13823
+ if (scope.safe === null) return null;
13824
+ const balances = yield* indexer.read("balance", {
13825
+ safe: toAddress(scope.safe),
13826
+ limit: INDEXER_MAX_LIMIT
13827
+ });
13828
+ const status = yield* indexer.status.pipe(Effect.catch(() => Effect.succeed([])));
13829
+ const rows = [];
13830
+ for (const balance of balances) {
13831
+ const asset = configuredMoneyAssetById(balance.assetId);
13832
+ if (asset === null || balance.amount < 0n) continue;
13833
+ rows.push({
13834
+ assetKind: "erc20",
13835
+ tokenAddress: toAddress(asset.tokenAddress),
13836
+ symbol: asset.symbol,
13837
+ decimals: asset.decimals,
13838
+ rawBalance: toWeiAmount(balance.amount.toString())
13839
+ });
13840
+ }
13841
+ const chainId = balances[0]?.chainId ?? status[0]?.chainId;
13842
+ if (chainId === void 0) return null;
13843
+ const head = status.find((entry) => entry.chainId === chainId);
13844
+ const nowSeconds = Math.floor(Date.now() / 1e3);
13845
+ const headSeconds = head === void 0 ? void 0 : Number(head.blockTimestamp);
13846
+ return {
13847
+ actor: scope.actor,
13848
+ chainId: toChainId(chainId),
13849
+ observedAt: headSeconds === void 0 ? Date.now() : headSeconds * 1e3,
13850
+ stale: headSeconds === void 0 || nowSeconds - headSeconds > FRESHNESS_LIMIT_SECONDS,
13851
+ rows
13852
+ };
13853
+ }).pipe(Effect.catch(() => Effect.succeed(null)));
13854
+ }
13363
13855
  function makeHoldingsMethods(deps) {
13364
13856
  const functions = deps.functions ?? holdingsContract;
13857
+ const overlay = (deps.financialOpsFunctions ?? financialOpsContract).activityOverlay;
13365
13858
  const read = (operation, actor, options, pick) => {
13366
13859
  const controls = deps.invocationControls?.(options) ?? options;
13367
- return runCapxulEffect(retryIdempotentRead(deps.convexCall.action(functions.current, copyInvocationObservation(controls, actor?.kind === "organization" ? { actor: {
13860
+ const convexSnapshot = retryIdempotentRead(deps.convexCall.action(functions.current, copyInvocationObservation(controls, actor?.kind === "organization" ? { actor: {
13368
13861
  kind: "organization",
13369
13862
  orgId: actor.organizationId
13370
- } } : {})), operation, deps.telemetry, controls).pipe(Effect.map(pick), Effect.mapError((error) => error.publicError)), controls, operation, deps.runPromise);
13863
+ } } : {})), operation, deps.telemetry, controls).pipe(Effect.mapError((error) => error.publicError));
13864
+ return runCapxulEffect((deps.indexerRead === void 0 ? convexSnapshot : indexerHoldings(deps.indexerRead, deps.convexCall, overlay, actor, controls).pipe(Effect.flatMap((current) => current === null ? convexSnapshot : Effect.succeed(current)))).pipe(Effect.map(pick)), controls, operation, deps.runPromise);
13371
13865
  };
13372
13866
  return {
13373
13867
  current: (input, options) => read(CAPXUL_OPERATIONS.holdings.current, input?.actor, options, (snapshot) => snapshot),
@@ -13393,8 +13887,8 @@ const APPLIED_ACTION_BY_EVENT = {
13393
13887
  RestoreSession: "none",
13394
13888
  ResumeOtpEntry: "none",
13395
13889
  Reset: "none",
13396
- SessionRestored: "none",
13397
- SessionAbsent: "none",
13890
+ SessionRestored: "restoration",
13891
+ SessionAbsent: "restoration",
13398
13892
  EnsureAccount: "none",
13399
13893
  ClaimAccount: "none",
13400
13894
  RetryAccount: "none",
@@ -13406,8 +13900,8 @@ const APPLIED_ACTION_BY_EVENT = {
13406
13900
  OtpFailed: "failed",
13407
13901
  Verified: "verified",
13408
13902
  VerifyFailed: "failed",
13409
- SessionRead: "none",
13410
- SessionReadFailed: "none",
13903
+ SessionRead: "restoration",
13904
+ SessionReadFailed: "restoration",
13411
13905
  SignedOut: "signed-out",
13412
13906
  SignOutFailed: "failed",
13413
13907
  AccountAt: "none",
@@ -13433,6 +13927,49 @@ const authFailure = (record, reason, mode) => ({
13433
13927
  ...linkage(record)
13434
13928
  }
13435
13929
  });
13930
+ /**
13931
+ * The label of the restore window every client boots into. A settled session
13932
+ * fact that left this label is the restoration result (#1962 R04); the same
13933
+ * facts from a signed-out or authenticated state are the routine session probe
13934
+ * that `getSession()` runs, and a probe is not a restoration attempt.
13935
+ */
13936
+ const RESTORE_WINDOW = "restoring";
13937
+ /**
13938
+ * Which result the window settled on. `SessionRestored` and `SessionAbsent` are
13939
+ * the cache door and say it themselves. `ReadSession` is also valid inside the
13940
+ * window — `getSession()` drives it on a cache miss and its `SessionRead`
13941
+ * completion settles the window — so that one event reports both halves and the
13942
+ * state it produced is what separates them.
13943
+ */
13944
+ const restorationOutcome = (event, state) => {
13945
+ switch (event) {
13946
+ case "SessionRestored": return "restored";
13947
+ case "SessionAbsent": return "absent";
13948
+ case "SessionReadFailed": return "failed";
13949
+ case "SessionRead":
13950
+ if (state.phase === "authenticated") return "restored";
13951
+ return state.phase === "signed_out" ? "absent" : void 0;
13952
+ default: return;
13953
+ }
13954
+ };
13955
+ /**
13956
+ * The restore window's one result, or nothing when this settled session fact
13957
+ * belongs to a probe rather than to the window.
13958
+ */
13959
+ const restorationObservation = (record, state) => {
13960
+ if (record.slot !== "identity:session" || record.from !== RESTORE_WINDOW) return NONE;
13961
+ const outcome = restorationOutcome(record.event, state);
13962
+ if (outcome === void 0) return NONE;
13963
+ return {
13964
+ name: "access_recovery_completed",
13965
+ props: {
13966
+ recovery: "session_restoration",
13967
+ outcome,
13968
+ ...outcome === "failed" && state.phase === "faulted" ? { reason_code: state.failure.code } : {},
13969
+ ...linkage(record)
13970
+ }
13971
+ };
13972
+ };
13436
13973
  const REFUSAL_EVENTS = /* @__PURE__ */ new Set([
13437
13974
  "ClaimAccount",
13438
13975
  "RetryAccount",
@@ -13477,6 +14014,7 @@ function mapIdentityProductObservation(record, state) {
13477
14014
  name: "auth_signed_out",
13478
14015
  props: linkage(record)
13479
14016
  };
14017
+ case "restoration": return restorationObservation(record, state);
13480
14018
  }
13481
14019
  }
13482
14020
  const ignoreTransportFailure = (operation, operationName, eventName) => Effect.suspend(operation).pipe(Effect.catchCause(() => Effect.logWarning("identity.product.telemetry.dropped").pipe(Effect.annotateLogs({
@@ -13488,7 +14026,7 @@ function executeIdentityProductObservation(telemetry, record, state) {
13488
14026
  if (mapped === null) return Effect.void;
13489
14027
  copyInvocationObservation(record, mapped);
13490
14028
  const invocationTelemetry = bindProductTelemetryInvocation(telemetry, mapped);
13491
- const after = () => mapped.name === "auth_verified" && state.phase === "authenticated" ? invocationTelemetry.identify({
14029
+ const after = () => state.phase === "authenticated" && (mapped.name === "auth_verified" || mapped.name === "access_recovery_completed") ? invocationTelemetry.identify({
13492
14030
  distinctId: state.session.authUserId,
13493
14031
  traits: { email_domain: emailDomain(state.session.email) }
13494
14032
  }) : mapped.name === "auth_signed_out" ? invocationTelemetry.reset() : Effect.void;
@@ -13533,6 +14071,51 @@ function startSignerReadinessOnClaim(actor, signer) {
13533
14071
  browserSigner.ensureWalletReady?.().catch(() => {});
13534
14072
  });
13535
14073
  }
14074
+ /**
14075
+ * Report the result of each signer readiness cycle (#1962 R04).
14076
+ *
14077
+ * The readiness store already carries the cycle boundary this needs, so no
14078
+ * public signer hook, second identity subscriber, or render counter is added.
14079
+ * `ensureOpenfortWalletReady` writes `recovering` synchronously when it starts
14080
+ * a cycle, and only the cycle that is still the current one writes `ready` or
14081
+ * `unavailable` (`create-openfort-browser-signer.ts:501-521`). Callers that
14082
+ * join a live cycle share that single write, and a `resetSession` writes
14083
+ * `unknown` first, so a cycle that a reset or an account replacement outran
14084
+ * reports nothing.
14085
+ *
14086
+ * The host context is bound when the cycle starts, so a person who signs out
14087
+ * and back in while a cycle runs cannot relabel the result that began under
14088
+ * the previous person. A signer with no readiness cycle — a node or dev key,
14089
+ * and a headless client whose requirement never opens the account lane —
14090
+ * writes no status and reports nothing.
14091
+ */
14092
+ function observeSignerReadinessCycles(signer, telemetry, hostObservationSnapshot, runPromise) {
14093
+ const statusStore = signer?.statusStore;
14094
+ if (statusStore === void 0 || telemetry === void 0) return () => {};
14095
+ let running = false;
14096
+ let startContext;
14097
+ return statusStore.subscribe((status) => {
14098
+ if (status === "recovering") {
14099
+ running = true;
14100
+ startContext = hostObservationSnapshot?.();
14101
+ return;
14102
+ }
14103
+ const cycleContext = startContext;
14104
+ const completesCycle = running;
14105
+ running = false;
14106
+ startContext = void 0;
14107
+ if (!completesCycle || status !== "ready" && status !== "unavailable") return;
14108
+ const event = {
14109
+ name: "access_recovery_completed",
14110
+ props: {
14111
+ recovery: "signer_readiness",
14112
+ outcome: status
14113
+ }
14114
+ };
14115
+ if (cycleContext !== void 0) attachInvocationObservation(event, cycleContext);
14116
+ runPromise(Effect.suspend(() => bindProductTelemetryInvocation(telemetry, event).emit(event)).pipe(Effect.catchCause(() => Effect.void))).catch(() => {});
14117
+ });
14118
+ }
13536
14119
  function assembleCapxulClient(input) {
13537
14120
  const observation = input;
13538
14121
  const authCache = input.authCache ?? detectAuthCacheAdapter();
@@ -13562,12 +14145,14 @@ function assembleCapxulClient(input) {
13562
14145
  }, failureObservation, normalizeCapxulOperation(`identity.${record.event}`), "machine");
13563
14146
  });
13564
14147
  const unsubscribeSignerReadiness = startSignerReadinessOnClaim(actor, input.signer);
14148
+ const unsubscribeReadinessObservation = observeSignerReadinessCycles(input.signer, input.ports.telemetry, observation.hostObservationSnapshot, effectRunner.runPromise);
13565
14149
  let stopPromise = null;
13566
14150
  const stopActor = () => {
13567
14151
  if (stopPromise === null) {
13568
14152
  unsubscribeProductTelemetry();
13569
14153
  unsubscribeFailureObservation();
13570
14154
  unsubscribeSignerReadiness();
14155
+ unsubscribeReadinessObservation();
13571
14156
  stopPromise = effectRunner.runPromise(Scope.close(scope, Exit.void));
13572
14157
  }
13573
14158
  return stopPromise;
@@ -13584,7 +14169,8 @@ function assembleCapxulClient(input) {
13584
14169
  convexCall: input.ports.convexCall,
13585
14170
  ...input.signer === void 0 ? {} : { signer: input.signer },
13586
14171
  telemetry: input.ports.telemetry,
13587
- requestKeyScope: `${input.bootstrap.convexUrl}:${String(input.bootstrap.chainId)}`
14172
+ requestKeyScope: `${input.bootstrap.convexUrl}:${String(input.bootstrap.chainId)}`,
14173
+ ...input.ports.indexerRead === void 0 ? {} : { indexerRead: input.ports.indexerRead }
13588
14174
  });
13589
14175
  const accountBundle = makeAccountMethods({
13590
14176
  actor,
@@ -13655,7 +14241,8 @@ function assembleCapxulClient(input) {
13655
14241
  convexCall: input.ports.convexCall,
13656
14242
  telemetry: input.ports.telemetry,
13657
14243
  runPromise: effectRunner.runPromise,
13658
- invocationControls: (controls) => withHostObservationControls(observation.hostObservationSnapshot, controls, actor.authSession()?.authUserId)
14244
+ invocationControls: (controls) => withHostObservationControls(observation.hostObservationSnapshot, controls, actor.authSession()?.authUserId),
14245
+ ...input.ports.indexerRead === void 0 ? {} : { indexerRead: input.ports.indexerRead }
13659
14246
  });
13660
14247
  const accounts = makeAccountsMethods({
13661
14248
  accountReadPort: input.ports.accountRead,
@@ -13983,36 +14570,6 @@ function isPromiseLike(value) {
13983
14570
  return (typeof value === "object" && value !== null || typeof value === "function") && "then" in value;
13984
14571
  }
13985
14572
  //#endregion
13986
- //#region src/ports/indexer-read.ts
13987
- /** The indexer's own page bound. Exceeding it is a caller defect, not a refusal. */
13988
- const INDEXER_MAX_LIMIT = 1e3;
13989
- const LOWER_CASE_ADDRESS = /^0x[0-9a-f]{40}$/;
13990
- /**
13991
- * Refuse a page the indexer would refuse, before any implementation spends a
13992
- * round trip on it. Every implementation calls this, so a consumer test written
13993
- * against the hermetic adapter cannot pass on input production rejects. Throws
13994
- * a `CapxulError`; callers convert it to an `IndexerReadError`.
13995
- */
13996
- function assertIndexerPage(input) {
13997
- const safe = String(input.safe).toLowerCase();
13998
- if (!LOWER_CASE_ADDRESS.test(safe)) throw Errors.invalidInput("safe", "must be a lower-case EVM address");
13999
- if (!Number.isSafeInteger(input.limit) || input.limit < 1 || input.limit > 1e3) throw Errors.invalidInput("limit", `must be an integer from 1 to ${INDEXER_MAX_LIMIT}`);
14000
- const offset = input.offset ?? 0;
14001
- if (!Number.isSafeInteger(offset) || offset < 0) throw Errors.invalidInput("offset", "must be a non-negative integer");
14002
- return safe;
14003
- }
14004
- var IndexerReadError = class extends Data.TaggedError("IndexerReadError") {};
14005
- function indexerReadErrorFromCapxul(operation, error, cause = error) {
14006
- return new IndexerReadError({
14007
- operation,
14008
- publicCode: error.code,
14009
- publicError: error,
14010
- cause,
14011
- ...error.details === void 0 ? {} : { details: error.details }
14012
- });
14013
- }
14014
- Context.Service()("@capxul/sdk/ports/IndexerReadPort");
14015
- //#endregion
14016
14573
  //#region src/adapters/ponder/decode.ts
14017
14574
  /**
14018
14575
  * Decode the indexer's rows at the trust boundary.
@@ -14318,7 +14875,7 @@ var PonderIndexerAdapter = class {
14318
14875
  }
14319
14876
  if (stopped()) return;
14320
14877
  const error = failure ?? Errors.capabilityUnavailable("indexer", operation);
14321
- observeStreamFailure(this.#observation, CAPXUL_OPERATIONS.activity.subscribe, error);
14878
+ observeStreamFailure(this.#observation, CAPXUL_OPERATIONS.activity.subscribe, error, error.code === "NOT_AUTHENTICATED" ? "operation" : "exception");
14322
14879
  callback({
14323
14880
  status: "error",
14324
14881
  error
@@ -14955,6 +15512,7 @@ function idempotentClose(close) {
14955
15512
  * and Convex see one session with one scope.
14956
15513
  */
14957
15514
  function productionIndexerReadPort(input, ports, observation) {
15515
+ if (input.activityReadSource === "convex") return void 0;
14958
15516
  if (input.indexerUrl === void 0 || input.indexerUrl === "") return void 0;
14959
15517
  return new PonderIndexerAdapter({
14960
15518
  baseUrl: normalizeHttpUrl("indexerUrl", input.indexerUrl),
@@ -1679,6 +1679,17 @@ interface ActivityAnnotationInput {
1679
1679
  * are unaffected.
1680
1680
  */
1681
1681
  interface ActivityMethods {
1682
+ /**
1683
+ * Tell the caller when the indexed page for this actor's Safe changed, over
1684
+ * the indexer's one live connection. The callback carries no rows: it is the
1685
+ * signal to re-read `list` or `summary`. Without an indexer this resolves a
1686
+ * no-op teardown, so a caller needs no branch.
1687
+ *
1688
+ * @internal-use — substrate reactive transport, like `ConvexCallPort.subscribe`.
1689
+ */
1690
+ subscribe(onChange: () => void, params?: {
1691
+ readonly actor?: ActorReference;
1692
+ }, options?: InvocationControls): Promise<CapxulResult<() => void>>;
1682
1693
  list(params?: ActivityListParams, options?: InvocationControls): Promise<CapxulResult<ActivityPage>>;
1683
1694
  summary(params?: ActivitySummaryParams, options?: InvocationControls): Promise<CapxulResult<ActivitySummary>>;
1684
1695
  get(reference: ActivityReference, options?: InvocationControls & {
@@ -1,5 +1,5 @@
1
1
  import { h as CapxulResult } from "../OAuthBearerAuthClient-C-ip-z8M.mjs";
2
- import { er as TelemetryEvent, f as CapxulClient, i as ObservationAdapter, n as ProductionSignerControls, nr as TelemetryIdentifyInput, pr as IdentityTransition, t as CapxulClientInput, tr as TelemetryGroupInput } from "../production-Du4Vc7YD.mjs";
2
+ import { er as TelemetryEvent, f as CapxulClient, i as ObservationAdapter, n as ProductionSignerControls, nr as TelemetryIdentifyInput, pr as IdentityTransition, t as CapxulClientInput, tr as TelemetryGroupInput } from "../production-A1zW1JPt.mjs";
3
3
  import { Effect, Layer } from "effect";
4
4
  //#region src/testing/production-client.d.ts
5
5
  /** Create the one production client with per-client controls at its signing boundaries. */
@@ -1,5 +1,5 @@
1
- import { D as fromWei, P as redactTelemetryEvent, a as smartAccountErrorFromCapxul, c as identityErrorFromCapxul, i as assembleCapxulClient, l as convexCallErrorFromCapxul, n as createCapxulClientWithSignerControls, o as accountReadErrorFromCapxul, s as wireChainId, u as bootstrapErrorFromCapxul, v as toWei } from "../production-BndbwuVx.mjs";
2
- import { G as toHandle, H as toEmail, I as toAuthUserId, K as toJwtToken, M as toAddress, N as toAllowedOrigin, P as toAppId, Q as toPublishableKey, R as toChainId, U as toEpochMs, V as toDurationMs, W as toEpochSeconds, d as authClientPortFromPromiseAdapter, et as toSessionToken, j as toAccountId, lt as Errors, n as readClockNow, q as toKycTier, r as InMemoryAuthCacheAdapter, rt as validateHandle, st as CapxulError, y as deriveCapxulSafeAddress, z as toCountryCode } from "../OAuthBearerAuthClient-IB2W1Fzj.mjs";
1
+ import { D as fromWei, P as redactTelemetryEvent, a as smartAccountErrorFromCapxul, c as identityErrorFromCapxul, i as assembleCapxulClient, l as convexCallErrorFromCapxul, n as createCapxulClientWithSignerControls, o as accountReadErrorFromCapxul, s as wireChainId, u as bootstrapErrorFromCapxul, v as toWei } from "../production-7jr-KUvX.mjs";
2
+ import { G as toHandle, H as toEmail, I as toAuthUserId, K as toJwtToken, M as toAddress, N as toAllowedOrigin, P as toAppId, Q as toPublishableKey, R as toChainId, U as toEpochMs, V as toDurationMs, W as toEpochSeconds, ct as CapxulError, d as authClientPortFromPromiseAdapter, et as toSessionToken, it as validateHandle, j as toAccountId, n as readClockNow, q as toKycTier, r as InMemoryAuthCacheAdapter, ut as Errors, y as deriveCapxulSafeAddress, z as toCountryCode } from "../OAuthBearerAuthClient-CbU_W9Sp.mjs";
3
3
  import { keccak256 } from "viem";
4
4
  import { Effect, Result, Semaphore } from "effect";
5
5
  import { getFunctionName } from "convex/server";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capxul/sdk",
3
- "version": "4.2.0-rc.10",
3
+ "version": "4.2.0-rc.11",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/Xelmar-tech/infrastructure.git",
@@ -47,12 +47,12 @@
47
47
  "vite": "npm:@voidzero-dev/vite-plus-core@0.3.0",
48
48
  "vite-plus": "0.3.0",
49
49
  "vitest": "4.1.11",
50
- "@capxul/errors": "0.3.0",
51
- "@capxul/typescript-config": "0.0.0",
52
- "@capxul/observability": "4.2.0-rc.10",
53
- "@capxul/wire": "0.7.0",
50
+ "@capxul/config": "0.3.0",
51
+ "@capxul/observability": "4.2.0-rc.11",
54
52
  "@capxul/types": "0.3.0",
55
- "@capxul/config": "0.3.0"
53
+ "@capxul/typescript-config": "0.0.0",
54
+ "@capxul/errors": "0.3.0",
55
+ "@capxul/wire": "0.7.0"
56
56
  },
57
57
  "_permissionlessPinReason": "permissionless.toSafeSmartAccount is pinned to 0.3.4 for live Safe deployment E2E. Counterfactual address fixtures captured 2026-05-17 in packages/backend/convex/_shared/__tests__/counterfactual.test.ts and packages/config/tests/safe.test.ts must be re-verified before upgrading.",
58
58
  "scripts": {