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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { A as toSessionToken, C as toEpochSeconds, D as toPublishableKey, E as toOrgId, F as Errors, I as isCapxulError, M as decodeConvexError, N as CapxulError, O as toPublishableKeyId, P as EXPECTED_OPERATION_OUTCOMES, S as toEpochMs, T as toKycTier, _ as toChainId, b as toDurationMs, c as BYTES32_RE, d as toAccountId, f as toAddress, g as toAuthUserId, h as toAppId, j as toSubAccountId, k as toRoleKey, l as EVM_ADDRESS_RE$1, m as toAnonymousDistinctId, n as BrowserAuthCacheAdapter, o as AuthCachePortTag, p as toAllowedOrigin, s as APP_ID_RE, t as InMemoryAuthCacheAdapter, u as SUPPORTED_CURRENCY_CODES, v as toCountryCode, w as toJwtToken, x as toEmail, y as toCurrencyCode } from "./InMemoryAuthCacheAdapter-BuVZpnSx.mjs";
1
+ import { A as toSessionToken, C as toEpochSeconds, D as toPublishableKey, E as toOrgId, F as Errors, I as isCapxulError, M as decodeConvexError, N as CapxulError, O as toPublishableKeyId, P as EXPECTED_OPERATION_OUTCOMES, S as toEpochMs, T as toKycTier, _ as toChainId, b as toDurationMs, c as BYTES32_RE, d as toAccountId, f as toAddress, g as toAuthUserId, h as toAppId, j as toSubAccountId, k as toRoleKey, l as EVM_ADDRESS_RE$1, m as toAnonymousDistinctId, n as BrowserAuthCacheAdapter, o as AuthCachePortTag, p as toAllowedOrigin, s as APP_ID_RE, t as InMemoryAuthCacheAdapter, u as SUPPORTED_CURRENCY_CODES, v as toCountryCode, w as toJwtToken, x as toEmail, y as toCurrencyCode } from "./InMemoryAuthCacheAdapter-CHYpYyk5.mjs";
2
2
  import { concat, formatUnits, keccak256, padHex, parseUnits, recoverAddress, stringToHex, toBytes, toEventSelector, toFunctionSelector } from "viem";
3
3
  import { Context, Data, Deferred, Duration, Effect, Either, Exit, Layer, Ref, Request, Scope } from "effect";
4
4
  import { getFunctionName, makeFunctionReference } from "convex/server";
@@ -249,13 +249,31 @@ function parseV8StackFrames(error) {
249
249
  }
250
250
  return frames;
251
251
  }
252
+ /** Fixed, leak-safe frame used when the error carries no parseable stack. */
253
+ const SDK_BOUNDARY_FILENAME = "capxul-sdk-observation://boundary";
252
254
  /**
253
- * Build PostHog's `$exception_list` format from a list of frames.
254
- * Returns `[{ frames: [...] }]` or `undefined` if the frames list is empty.
255
+ * Build PostHog's `$exception_list` (always a single entry). Error Tracking
256
+ * groups on `type`, so it is ALWAYS present (the CapxulError code) the
257
+ * previous `[{ frames }]` shape omitted it and PostHog dropped the event as
258
+ * "missing field `type`". When the error has no parseable stack, a synthetic
259
+ * boundary frame stands in so the event still ingests as a real Issue (#1031).
255
260
  */
256
- function buildExceptionList(frames) {
257
- if (frames.length === 0) return void 0;
258
- return [{ frames }];
261
+ function buildExceptionList(input) {
262
+ const frames = input.frames.length > 0 ? input.frames : [{
263
+ filename: SDK_BOUNDARY_FILENAME,
264
+ function: input.operation ?? "unknown",
265
+ lineno: 1,
266
+ colno: 1
267
+ }];
268
+ return [{
269
+ type: input.type,
270
+ value: input.value,
271
+ mechanism: {
272
+ handled: true,
273
+ type: "capxul_sdk_boundary"
274
+ },
275
+ stacktrace: { frames }
276
+ }];
259
277
  }
260
278
  //#endregion
261
279
  //#region src/telemetry/get-failure-mode.ts
@@ -306,6 +324,8 @@ function resolveFailureMode(error, contextFailureMode) {
306
324
  }
307
325
  //#endregion
308
326
  //#region src/telemetry/capture-exception.ts
327
+ /** Fixed, leak-safe message — the raw error message may carry PII and never ships. */
328
+ const EXCEPTION_MESSAGE = "Capxul SDK operation failed";
309
329
  /**
310
330
  * Capture an error as a `$exception` event through the telemetry port,
311
331
  * formatted for PostHog Error Tracking.
@@ -319,16 +339,24 @@ function resolveFailureMode(error, contextFailureMode) {
319
339
  */
320
340
  function captureException(telemetry, error, context) {
321
341
  return Effect.catchAllDefect(Effect.sync(() => {
322
- const exceptionList = buildExceptionList(error instanceof Error ? parseV8StackFrames(error) : []);
342
+ const frames = error instanceof Error ? parseV8StackFrames(error) : [];
323
343
  const capxulError = isCapxulError(error) ? error : null;
344
+ const errorCode = capxulError?.code ?? context?.capxul_error_code ?? "UNKNOWN";
324
345
  const props = {
325
- capxul_error_code: capxulError?.code ?? context?.capxul_error_code ?? "UNKNOWN",
346
+ capxul_error_code: errorCode,
347
+ $exception_type: errorCode,
348
+ $exception_message: EXCEPTION_MESSAGE,
349
+ $exception_list: buildExceptionList({
350
+ type: errorCode,
351
+ value: EXCEPTION_MESSAGE,
352
+ ...context?.operation === void 0 ? {} : { operation: context.operation },
353
+ frames
354
+ }),
326
355
  layer: capxulError?.layer ?? context?.layer,
327
356
  operation: context?.operation,
328
357
  provider: context?.provider,
329
358
  failure_mode: resolveFailureMode(error, context?.failure_mode)
330
359
  };
331
- if (exceptionList !== void 0) props.$exception_list = exceptionList;
332
360
  if (capxulError?.details !== void 0) props.details = JSON.stringify(capxulError.details);
333
361
  for (const key of Object.keys(props)) if (props[key] === void 0) delete props[key];
334
362
  return telemetry.emit({
@@ -1258,10 +1286,10 @@ function makeAccountMethods(deps) {
1258
1286
  value: await lane.retryProvisioning()
1259
1287
  };
1260
1288
  };
1261
- const reportAndReturn = (error) => {
1289
+ const reportAndReturn = (error, operation = "getLifecycle") => {
1262
1290
  if (deps.telemetry) captureExceptionSync(deps.telemetry, error, {
1263
1291
  layer: "account",
1264
- operation: "getLifecycle"
1292
+ operation
1265
1293
  });
1266
1294
  return {
1267
1295
  ok: false,
@@ -1292,6 +1320,12 @@ function makeAccountMethods(deps) {
1292
1320
  };
1293
1321
  const getLifecycle = () => resolveLifecycle();
1294
1322
  const retrySetup = async () => {
1323
+ const resetSession = deps.signer?.resetSession;
1324
+ if (typeof resetSession === "function") try {
1325
+ resetSession.call(deps.signer);
1326
+ } catch (cause) {
1327
+ return reportAndReturn(cause instanceof CapxulError ? cause : Errors.providerError("openfort", "resetSession", cause, { failure_mode: "unknown" }), "retrySetup");
1328
+ }
1295
1329
  await lane.retryProvisioning();
1296
1330
  return resolveLifecycle();
1297
1331
  };
@@ -1618,7 +1652,7 @@ async function recoverRawDigestSigner(input) {
1618
1652
  }
1619
1653
  //#endregion
1620
1654
  //#region package.json
1621
- var version = "1.0.0-alpha.18";
1655
+ var version = "1.0.0-alpha.20";
1622
1656
  //#endregion
1623
1657
  //#region src/ports/auth-client.ts
1624
1658
  var AuthClientError = class extends Data.TaggedError("AuthClientError") {};
@@ -3386,24 +3420,6 @@ const envFields = {
3386
3420
  "required": false,
3387
3421
  "example": "development"
3388
3422
  },
3389
- AUTH_DEV_OTP: {
3390
- "runtime": "server",
3391
- "kind": "nonempty",
3392
- "required": false,
3393
- "example": "000000"
3394
- },
3395
- SENTRY_DSN: {
3396
- "runtime": "server",
3397
- "kind": "url",
3398
- "required": false,
3399
- "example": "https://public@example.ingest.sentry.io/1"
3400
- },
3401
- POSTHOG_API_KEY: {
3402
- "runtime": "server",
3403
- "kind": "nonempty",
3404
- "required": false,
3405
- "example": "phx_test"
3406
- },
3407
3423
  POSTHOG_PROJECT_TOKEN: {
3408
3424
  "runtime": "server",
3409
3425
  "kind": "nonempty",
@@ -3434,24 +3450,12 @@ const envFields = {
3434
3450
  "required": false,
3435
3451
  "example": "12345"
3436
3452
  },
3437
- POSTHOG_ENV_ID: {
3438
- "runtime": "server",
3439
- "kind": "nonempty",
3440
- "required": false,
3441
- "example": "12345"
3442
- },
3443
3453
  SENDER_EMAIL: {
3444
3454
  "runtime": "server",
3445
3455
  "kind": "email",
3446
3456
  "required": false,
3447
3457
  "example": "noreply@capxul.test"
3448
3458
  },
3449
- SHIELD_API_URL: {
3450
- "runtime": "server",
3451
- "kind": "url",
3452
- "required": false,
3453
- "example": "https://api.shield.test"
3454
- },
3455
3459
  ALCHEMY_API_KEY: {
3456
3460
  "runtime": "server",
3457
3461
  "kind": "nonempty",
@@ -3470,24 +3474,6 @@ const envFields = {
3470
3474
  "required": true,
3471
3475
  "example": "alchemy_hmac"
3472
3476
  },
3473
- ALCHEMY_AUTH_TOKEN: {
3474
- "runtime": "server",
3475
- "kind": "nonempty",
3476
- "required": false,
3477
- "example": "alchemy_auth"
3478
- },
3479
- ALCHEMY_WEBHOOK_ID: {
3480
- "runtime": "server",
3481
- "kind": "nonempty",
3482
- "required": false,
3483
- "example": "wh_123"
3484
- },
3485
- GOLDSKY_WEBHOOK_SECRET: {
3486
- "runtime": "server",
3487
- "kind": "nonempty",
3488
- "required": false,
3489
- "example": "goldsky_secret"
3490
- },
3491
3477
  DEPLOYER_PRIVATE_KEY: {
3492
3478
  "runtime": "server",
3493
3479
  "kind": "privateKey",
@@ -4207,6 +4193,7 @@ const DEFAULT_FUNCTIONS$1 = {
4207
4193
  prepareFounderAccount: makeFunctionReference("org/actions:prepareFounderAccount"),
4208
4194
  prepareBootstrap: makeFunctionReference("org/actions:prepareBootstrap"),
4209
4195
  submitBootstrap: makeFunctionReference("org/actions:submitBootstrap"),
4196
+ resumeBootstrapSubmission: makeFunctionReference("org/actions:resumeBootstrapSubmission"),
4210
4197
  confirmBootstrap: makeFunctionReference("org/actions:confirmBootstrap"),
4211
4198
  recordFailure: makeFunctionReference("org/lifecycle:recordFailure"),
4212
4199
  load: makeFunctionReference("org/lifecycle:load"),
@@ -4268,14 +4255,22 @@ var ConvexOrganizationSetupAdapter = class {
4268
4255
  if (!submitted.ok) return submitted;
4269
4256
  return parseLifecycle("submitBootstrap", submitted.value);
4270
4257
  }
4258
+ resumeSubmittedBootstrap(input) {
4259
+ return this.#lifecycleAction("resumeBootstrapSubmission", input, () => this.#convex.action(this.#fns.resumeBootstrapSubmission, { orgId: input.orgId }));
4260
+ }
4271
4261
  confirmSubmittedBootstrap(input) {
4272
4262
  return this.#lifecycleAction("confirmBootstrap", input, () => this.#convex.action(this.#fns.confirmBootstrap, { orgId: input.orgId }));
4273
4263
  }
4274
4264
  async recordFailure(input) {
4265
+ const errorProvider = input.error.details?.provider;
4266
+ const errorOperation = input.error.details?.operation;
4275
4267
  const result = await runCall("recordFailure", this.#convex.mutation(this.#fns.recordFailure, {
4276
4268
  orgId: input.orgId,
4277
- at: input.at,
4278
4269
  errorCode: input.error.code,
4270
+ ...typeof errorProvider === "string" && typeof errorOperation === "string" ? {
4271
+ errorProvider,
4272
+ errorOperation
4273
+ } : {},
4279
4274
  retryable: input.retryable
4280
4275
  }));
4281
4276
  return result.ok ? parseLifecycle("recordFailure", result.value) : result;
@@ -4289,8 +4284,15 @@ var ConvexOrganizationSetupAdapter = class {
4289
4284
  async retry(input) {
4290
4285
  const cancelled = cancellation(input.signal);
4291
4286
  if (cancelled !== void 0) return cancelled;
4287
+ const current = await this.loadLifecycle({ orgId: input.orgId });
4288
+ if (!current.ok) return current;
4289
+ if (current.value.status === "failed" && current.value.retryable && (current.value.at === "awaitingFounderAuthorization" || current.value.at === "submittingBootstrap")) {
4290
+ const reset = resetSignerSession(this.#signer);
4291
+ if (!reset.ok) return reset;
4292
+ }
4292
4293
  const result = await runCall("retry", this.#convex.mutation(this.#fns.retry, { orgId: input.orgId }));
4293
- return result.ok ? parseLifecycle("retry", result.value) : result;
4294
+ if (!result.ok) return result;
4295
+ return parseLifecycle("retry", result.value);
4294
4296
  }
4295
4297
  async #lifecycleAction(operation, input, call) {
4296
4298
  const cancelled = cancellation(input.signal);
@@ -4302,6 +4304,22 @@ var ConvexOrganizationSetupAdapter = class {
4302
4304
  return parseLifecycle(operation, result.value);
4303
4305
  }
4304
4306
  };
4307
+ function resetSignerSession(signer) {
4308
+ const resetSession = signer.resetSession;
4309
+ if (typeof resetSession !== "function") return {
4310
+ ok: true,
4311
+ value: void 0
4312
+ };
4313
+ try {
4314
+ resetSession.call(signer);
4315
+ return {
4316
+ ok: true,
4317
+ value: void 0
4318
+ };
4319
+ } catch (cause) {
4320
+ return fail$2(cause instanceof CapxulError ? cause : Errors.providerError("openfort", "resetSession", cause, { failure_mode: "unknown" }));
4321
+ }
4322
+ }
4305
4323
  async function runCall(operation, effect) {
4306
4324
  try {
4307
4325
  const result = await Effect.runPromise(Effect.either(effect));
@@ -4328,7 +4346,7 @@ async function signerResult(operation, run) {
4328
4346
  value: await run()
4329
4347
  };
4330
4348
  } catch (cause) {
4331
- return fail$2(Errors.providerError("organization-signer", operation, cause));
4349
+ return fail$2(cause instanceof CapxulError ? cause : Errors.providerError("organization-signer", operation, cause));
4332
4350
  }
4333
4351
  }
4334
4352
  function validatePreparedAuthorities(prepared, signerAddress) {
@@ -5249,7 +5267,22 @@ function transportErrorFromThrown(operation, request, cause) {
5249
5267
  return transportErrorFromCapxul(operation, request, cause instanceof Error ? Errors.providerError("transport", request.name, cause) : Errors.providerError("transport", request.name, new Error(String(cause))), cause);
5250
5268
  }
5251
5269
  //#endregion
5270
+ //#region src/adapters/diagnostic/ConsoleDiagnosticAdapter.ts
5271
+ const DEFAULT_ACCOUNT_SETUP_LOG_PREFIX = "[capxul:account-setup]";
5272
+ var ConsoleDiagnosticAdapter = class {
5273
+ prefix;
5274
+ constructor(prefix = DEFAULT_ACCOUNT_SETUP_LOG_PREFIX) {
5275
+ this.prefix = prefix;
5276
+ }
5277
+ trace(scope, detail) {
5278
+ globalThis.console?.debug?.(`${this.prefix} ${scope}`, detail);
5279
+ }
5280
+ };
5281
+ //#endregion
5252
5282
  //#region src/openfort/create-openfort-browser-signer.ts
5283
+ function openfortProviderError(operation, cause) {
5284
+ return cause instanceof CapxulError ? cause : Errors.providerError("openfort", operation, cause, { failure_mode: "unknown" });
5285
+ }
5253
5286
  /**
5254
5287
  * True when the browser cannot perform Web Crypto — sandboxed iframes, headless
5255
5288
  * agent browsers, or non-HTTPS origins. OpenFort's embedded-wallet `configure`
@@ -5318,21 +5351,39 @@ function createOpenfortBrowserSignerFromBootstrap(bootstrap, options = {}) {
5318
5351
  return `${authBaseUrl}/encryption-session`;
5319
5352
  }
5320
5353
  async function fetchBetterAuthAccessToken() {
5321
- const response = await fetch(betterAuthSessionUrl(), { credentials: "include" });
5322
- if (!response.ok) {
5354
+ try {
5355
+ const response = await fetch(betterAuthSessionUrl(), { credentials: "include" });
5356
+ if (!response.ok) {
5357
+ diagnostic?.trace("openfort.token", {
5358
+ ok: false,
5359
+ tokenPresent: false,
5360
+ httpStatus: response.status,
5361
+ failure_mode: "unknown"
5362
+ });
5363
+ return null;
5364
+ }
5365
+ const token = (await response.json()).session?.token?.trim();
5366
+ if (token === void 0 || token.length === 0) {
5367
+ diagnostic?.trace("openfort.token", {
5368
+ ok: false,
5369
+ tokenPresent: false,
5370
+ failure_mode: "unknown"
5371
+ });
5372
+ return null;
5373
+ }
5323
5374
  diagnostic?.trace("openfort.token", {
5375
+ ok: true,
5376
+ tokenPresent: true
5377
+ });
5378
+ return token;
5379
+ } catch (cause) {
5380
+ diagnostic?.trace("openfort.token", {
5381
+ ok: false,
5324
5382
  tokenPresent: false,
5325
- httpStatus: response.status
5383
+ failure_mode: "unknown"
5326
5384
  });
5327
- return null;
5328
- }
5329
- const token = (await response.json()).session?.token?.trim();
5330
- if (token === void 0 || token.length === 0) {
5331
- diagnostic?.trace("openfort.token", { tokenPresent: false });
5332
- return null;
5385
+ throw openfortProviderError("token", cause);
5333
5386
  }
5334
- diagnostic?.trace("openfort.token", { tokenPresent: true });
5335
- return token;
5336
5387
  }
5337
5388
  const openfort = new Openfort({
5338
5389
  baseConfiguration: { publishableKey: bootstrap.openfortPublishableKey },
@@ -5348,25 +5399,60 @@ function createOpenfortBrowserSignerFromBootstrap(bootstrap, options = {}) {
5348
5399
  if (isInsecureBrowserContext()) failNoSecureContext();
5349
5400
  await openfort.waitForInitialization();
5350
5401
  const accessToken = await fetchBetterAuthAccessToken();
5351
- if (accessToken === null) throw Errors.notAuthenticated();
5352
- const encryptionResponse = await fetch(encryptionSessionUrl(), {
5353
- method: "POST",
5354
- credentials: "include",
5355
- headers: {
5356
- Authorization: `Bearer ${accessToken}`,
5357
- "Content-Type": "application/json"
5358
- },
5359
- body: JSON.stringify({})
5360
- });
5361
- diagnostic?.trace("openfort.encryptionSession", { httpStatus: encryptionResponse.status });
5402
+ if (accessToken === null) throw openfortProviderError("token", /* @__PURE__ */ new Error("Better Auth access token unavailable for Openfort"));
5403
+ let encryptionResponse;
5404
+ try {
5405
+ encryptionResponse = await fetch(encryptionSessionUrl(), {
5406
+ method: "POST",
5407
+ credentials: "include",
5408
+ headers: {
5409
+ Authorization: `Bearer ${accessToken}`,
5410
+ "Content-Type": "application/json"
5411
+ },
5412
+ body: JSON.stringify({})
5413
+ });
5414
+ } catch (cause) {
5415
+ diagnostic?.trace("openfort.encryptionSession", {
5416
+ ok: false,
5417
+ failure_mode: "unknown"
5418
+ });
5419
+ throw openfortProviderError("encryptionSession", cause);
5420
+ }
5362
5421
  if (!encryptionResponse.ok) {
5363
- const detail = await encryptionResponse.text();
5364
- throw Errors.providerError("openfort", "encryptionSession", /* @__PURE__ */ new Error(`Openfort encryption session failed (${encryptionResponse.status}): ${detail.slice(0, 200)}`));
5422
+ diagnostic?.trace("openfort.encryptionSession", {
5423
+ ok: false,
5424
+ httpStatus: encryptionResponse.status,
5425
+ failure_mode: "unknown"
5426
+ });
5427
+ throw Errors.providerError("openfort", "encryptionSession", /* @__PURE__ */ new Error(`Openfort encryption session failed (${encryptionResponse.status})`), { failure_mode: "unknown" });
5428
+ }
5429
+ let encryptionBody;
5430
+ try {
5431
+ encryptionBody = await encryptionResponse.json();
5432
+ if (typeof encryptionBody.sessionId !== "string" || encryptionBody.sessionId.length === 0) throw new Error("Openfort encryption session response missing sessionId");
5433
+ } catch (cause) {
5434
+ diagnostic?.trace("openfort.encryptionSession", {
5435
+ ok: false,
5436
+ httpStatus: encryptionResponse.status,
5437
+ failure_mode: "unknown"
5438
+ });
5439
+ throw openfortProviderError("encryptionSession", cause);
5440
+ }
5441
+ diagnostic?.trace("openfort.encryptionSession", {
5442
+ ok: true,
5443
+ httpStatus: encryptionResponse.status
5444
+ });
5445
+ let embeddedState;
5446
+ try {
5447
+ embeddedState = await openfort.embeddedWallet.getEmbeddedState();
5448
+ diagnostic?.trace("openfort.embeddedState", { state: embeddedState });
5449
+ } catch (cause) {
5450
+ diagnostic?.trace("openfort.embeddedState", {
5451
+ ok: false,
5452
+ failure_mode: "unknown"
5453
+ });
5454
+ throw openfortProviderError("embeddedState", cause);
5365
5455
  }
5366
- const encryptionBody = await encryptionResponse.json();
5367
- if (typeof encryptionBody.sessionId !== "string" || encryptionBody.sessionId.length === 0) throw Errors.providerError("openfort", "encryptionSession", /* @__PURE__ */ new Error("Openfort encryption session response missing sessionId"));
5368
- const embeddedState = await openfort.embeddedWallet.getEmbeddedState();
5369
- diagnostic?.trace("openfort.embeddedState", { state: embeddedState });
5370
5456
  if (embeddedState !== EmbeddedState.READY) {
5371
5457
  clearStaleOpenfortBrowserStorage(bootstrap.openfortPublishableKey);
5372
5458
  diagnostic?.trace("openfort.storageCleared", { beforeConfigure: true });
@@ -5383,9 +5469,9 @@ function createOpenfortBrowserSignerFromBootstrap(bootstrap, options = {}) {
5383
5469
  } catch (cause) {
5384
5470
  diagnostic?.trace("openfort.configure", {
5385
5471
  ok: false,
5386
- message: cause instanceof Error ? cause.message : String(cause)
5472
+ failure_mode: "unknown"
5387
5473
  });
5388
- throw cause;
5474
+ throw openfortProviderError("configure", cause);
5389
5475
  }
5390
5476
  }
5391
5477
  try {
@@ -5394,9 +5480,9 @@ function createOpenfortBrowserSignerFromBootstrap(bootstrap, options = {}) {
5394
5480
  } catch (cause) {
5395
5481
  diagnostic?.trace("openfort.get", {
5396
5482
  ok: false,
5397
- message: cause instanceof Error ? cause.message : String(cause)
5483
+ failure_mode: "unknown"
5398
5484
  });
5399
- throw cause;
5485
+ throw openfortProviderError("get", cause);
5400
5486
  }
5401
5487
  })();
5402
5488
  }
@@ -5415,6 +5501,19 @@ function createOpenfortBrowserSignerFromBootstrap(bootstrap, options = {}) {
5415
5501
  });
5416
5502
  return {
5417
5503
  ...signer,
5504
+ getAddress: async () => {
5505
+ try {
5506
+ const address = await signer.getAddress();
5507
+ diagnostic?.trace("openfort.address", { ok: true });
5508
+ return address;
5509
+ } catch (cause) {
5510
+ diagnostic?.trace("openfort.address", {
5511
+ ok: false,
5512
+ failure_mode: "unknown"
5513
+ });
5514
+ throw openfortProviderError("getAddress", cause);
5515
+ }
5516
+ },
5418
5517
  resetSession: () => {
5419
5518
  walletReadyPromise = null;
5420
5519
  clearStaleOpenfortBrowserStorage(bootstrap.openfortPublishableKey);
@@ -6540,10 +6639,6 @@ function makeCurrentUserMethods(deps) {
6540
6639
  deps.smartAccount.loadCurrent(options),
6541
6640
  deps.orgs(options)
6542
6641
  ]);
6543
- if (!account.ok) return {
6544
- ok: false,
6545
- error: account.error
6546
- };
6547
6642
  if (!smartAccount.ok) return {
6548
6643
  ok: false,
6549
6644
  error: smartAccount.error
@@ -6552,6 +6647,10 @@ function makeCurrentUserMethods(deps) {
6552
6647
  ok: false,
6553
6648
  error: organizations.error
6554
6649
  };
6650
+ if (!account.ok && account.error.code !== "SMART_ACCOUNT_MISSING") return {
6651
+ ok: false,
6652
+ error: account.error
6653
+ };
6555
6654
  return {
6556
6655
  ok: true,
6557
6656
  value: {
@@ -6562,10 +6661,10 @@ function makeCurrentUserMethods(deps) {
6562
6661
  handle: null,
6563
6662
  paymentLink: null
6564
6663
  },
6565
- personalAccount: {
6664
+ personalAccount: account.ok ? {
6566
6665
  id: account.value.id,
6567
6666
  address: smartAccount.value?.smartAccountAddress ?? null
6568
- },
6667
+ } : null,
6569
6668
  organizations: organizations.value.map((organization) => ({
6570
6669
  id: organization.id,
6571
6670
  name: organization.name,
@@ -7921,16 +8020,17 @@ async function advanceOrganizationSetup(setup, orgId, initial, signal) {
7921
8020
  value: lifecycle
7922
8021
  };
7923
8022
  const currentStep = lifecycle.step;
7924
- if (signal?.aborted) {
7925
- const cancelled = Errors.cancelled({ operation: "organization.setup" });
7926
- return recordRetryableCancellation(setup, orgId, lifecycle.step, cancelled);
7927
- }
8023
+ if (signal?.aborted) return recordSetupFailure(setup, orgId, Errors.cancelled({ operation: "organization.setup" }), true);
7928
8024
  const stepInput = {
7929
8025
  orgId,
7930
8026
  ...signal === void 0 ? {} : { signal }
7931
8027
  };
7932
- const next = lifecycle.step === "preparingFounderAccount" ? await setup.prepareFounderAccount(stepInput) : lifecycle.step === "awaitingFounderAuthorization" || lifecycle.step === "submittingBootstrap" ? await setup.authorizeAndSubmitBootstrap(stepInput) : await setup.confirmSubmittedBootstrap(stepInput);
7933
- if (!next.ok) return next.error.code === "CANCELLED" ? recordRetryableCancellation(setup, orgId, lifecycle.step, next.error) : next;
8028
+ const next = lifecycle.step === "preparingFounderAccount" ? await setup.prepareFounderAccount(stepInput) : lifecycle.step === "awaitingFounderAuthorization" ? await setup.authorizeAndSubmitBootstrap(stepInput) : lifecycle.step === "submittingBootstrap" ? await setup.resumeSubmittedBootstrap(stepInput) : await setup.confirmSubmittedBootstrap(stepInput);
8029
+ if (!next.ok) {
8030
+ if (next.error.code === "CANCELLED") return recordSetupFailure(setup, orgId, next.error, true);
8031
+ if (next.error.code === "PROVIDER_ERROR") return recordSetupFailure(setup, orgId, next.error, isRetryableProviderFailure(next.error));
8032
+ return next;
8033
+ }
7934
8034
  const scopedNext = validateOrganizationLifecycleScope(orgId, next.value);
7935
8035
  if (!scopedNext.ok) return scopedNext;
7936
8036
  lifecycle = scopedNext.value;
@@ -7953,17 +8053,20 @@ async function advanceOrganizationSetup(setup, orgId, initial, signal) {
7953
8053
  ]
7954
8054
  }));
7955
8055
  }
7956
- async function recordRetryableCancellation(setup, orgId, at, cancelled) {
8056
+ async function recordSetupFailure(setup, orgId, error, retryable) {
7957
8057
  const recorded = await setup.recordFailure({
7958
8058
  orgId,
7959
- at,
7960
- error: cancelled,
7961
- retryable: true
8059
+ error,
8060
+ retryable
7962
8061
  });
7963
8062
  if (!recorded.ok) return recorded;
7964
8063
  const scopedRecorded = validateOrganizationLifecycleScope(orgId, recorded.value);
7965
8064
  if (!scopedRecorded.ok) return scopedRecorded;
7966
- return fail$1(cancelled);
8065
+ return fail$1(error);
8066
+ }
8067
+ function isRetryableProviderFailure(error) {
8068
+ const mode = error.details?.failure_mode;
8069
+ return mode !== "auth-origin-mismatch" && mode !== "app-env-allowlist" && mode !== "no-secure-context";
7967
8070
  }
7968
8071
  //#endregion
7969
8072
  //#region src/client/org.ts
@@ -8314,7 +8417,18 @@ async function runCompleteOrganizationOnboarding(ops, input, options) {
8314
8417
  });
8315
8418
  if (!started.ok) return fail(started.error);
8316
8419
  const lifecycle = await advanceOrganizationSetup(setup, started.value.orgId, started.value.lifecycle, options?.signal);
8317
- if (!lifecycle.ok) return lifecycle;
8420
+ if (!lifecycle.ok) {
8421
+ const error = lifecycle.error;
8422
+ return fail(new CapxulError(error.code, error.message, {
8423
+ cause: error.cause,
8424
+ details: {
8425
+ ...error.details,
8426
+ orgId: started.value.orgId
8427
+ },
8428
+ ...error.correlationId === void 0 ? {} : { correlationId: error.correlationId },
8429
+ ...error.layer === void 0 ? {} : { layer: error.layer }
8430
+ }));
8431
+ }
8318
8432
  return {
8319
8433
  ok: true,
8320
8434
  value: {
@@ -8438,6 +8552,7 @@ function detectAuthCacheAdapter() {
8438
8552
  }
8439
8553
  //#endregion
8440
8554
  //#region src/client/create-capxul-client.ts
8555
+ const GET_ORGANIZATION_SETUP_PROOF_RECEIPT = makeFunctionReference("org/lifecycle:getProofReceipt");
8441
8556
  function assembleCapxulClient(input) {
8442
8557
  const authCache = input.authCache ?? detectAuthCacheAdapter();
8443
8558
  const layer = Layer.mergeAll(Layer.succeed(AuthClientPortTag, input.ports.authClient), Layer.succeed(ClockPortTag, input.ports.clock), Layer.succeed(TelemetryPortTag, input.ports.telemetry));
@@ -8561,6 +8676,7 @@ function assembleCapxulClient(input) {
8561
8676
  },
8562
8677
  bootstrap: input.bootstrap,
8563
8678
  accounts: { fund: accounts.fund },
8679
+ organizationSetup: { getProofReceipt: (orgId) => runPortEffect(input.ports.convexCall.query(GET_ORGANIZATION_SETUP_PROOF_RECEIPT, { orgId })) },
8564
8680
  telemetry: input.ports.telemetry
8565
8681
  }
8566
8682
  };
@@ -8762,24 +8878,34 @@ function ignoreDeliveryFailure(delivery) {
8762
8878
  Promise.resolve(delivery).catch(() => void 0);
8763
8879
  } catch {}
8764
8880
  }
8881
+ /**
8882
+ * Map an ALREADY-sanitized observation context to the snake_case PostHog
8883
+ * property keys. Shared by the failure boundary here and the host
8884
+ * success-telemetry seam (`telemetry/from-posthog.ts`) so both attach identical
8885
+ * correlation fields from one definition.
8886
+ */
8887
+ function observationContextProps(context) {
8888
+ const props = {};
8889
+ if (context?.application !== void 0) props.application = context.application;
8890
+ if (context?.release !== void 0) props.release = context.release;
8891
+ if (context?.sessionId !== void 0) props.session_id = context.sessionId;
8892
+ if (context?.organizationId !== void 0) props.organization_id = context.organizationId;
8893
+ if (context?.correlationId !== void 0) props.correlation_id = context.correlationId;
8894
+ if (context?.anonymousId !== void 0) props.anonymous_id = context.anonymousId;
8895
+ return props;
8896
+ }
8765
8897
  function postHogProperties(failure, context) {
8766
- const properties = {
8767
- sdk_version: failure.sdkVersion,
8768
- operation: failure.operation,
8769
- error_kind: failure.errorKind,
8770
- handled: true
8771
- };
8772
8898
  const merged = sanitizeObservationContext({
8773
8899
  ...context,
8774
8900
  ...failure.context
8775
8901
  });
8776
- if (merged?.application !== void 0) properties.application = merged.application;
8777
- if (merged?.release !== void 0) properties.release = merged.release;
8778
- if (merged?.sessionId !== void 0) properties.session_id = merged.sessionId;
8779
- if (merged?.organizationId !== void 0) properties.organization_id = merged.organizationId;
8780
- if (merged?.correlationId !== void 0) properties.correlation_id = merged.correlationId;
8781
- if (merged?.anonymousId !== void 0) properties.anonymous_id = merged.anonymousId;
8782
- return properties;
8902
+ return {
8903
+ sdk_version: failure.sdkVersion,
8904
+ operation: failure.operation,
8905
+ error_kind: failure.errorKind,
8906
+ handled: true,
8907
+ ...observationContextProps(merged)
8908
+ };
8783
8909
  }
8784
8910
  function resolveContext(context) {
8785
8911
  return sanitizeObservationContext(resolveRawContext(context));
@@ -8830,7 +8956,7 @@ function normalizeErrorKind(value) {
8830
8956
  return typeof value === "string" && /^[A-Za-z][A-Za-z0-9_.-]{0,63}$/u.test(value) ? value : "Error";
8831
8957
  }
8832
8958
  function syntheticException(operation, kind) {
8833
- const error = /* @__PURE__ */ new Error("Capxul SDK operation failed");
8959
+ const error = /* @__PURE__ */ new Error(EXCEPTION_MESSAGE);
8834
8960
  error.name = kind;
8835
8961
  error.stack = `${kind}: ${error.message}\n at CapxulSdkBoundary.${operation} (capxul-sdk-observation://boundary/${operation}:1:1)`;
8836
8962
  return error;
@@ -9176,6 +9302,9 @@ async function createCapxulClient$1(input) {
9176
9302
  if (signer === void 0 && runtime === "browser") signer = createOpenfortBrowserSignerFromBootstrap({
9177
9303
  ...adapters.value.bootstrap,
9178
9304
  authBaseUrl: resolvedAuthBaseUrl
9305
+ }, {
9306
+ diagnostic: new ConsoleDiagnosticAdapter(),
9307
+ telemetry: adapters.value.ports.telemetry
9179
9308
  });
9180
9309
  const client = wireOpenfortSignerLifecycle(assembleCapxulClient({
9181
9310
  ports: adapters.value.ports,
@@ -9390,6 +9519,73 @@ async function createCapxulClient(input) {
9390
9519
  return createCapxulClient$1(input);
9391
9520
  }
9392
9521
  //#endregion
9393
- export { CAPXUL_SDK_EXPECTED_OUTCOME_EVENT, CapxulError, captureException, captureExceptionSync, createCapxulClient, deriveDevPrivateKey, devPrivateKeySigner, eip1193AccountProvider, embeddedSigner, fromPostHog, injectedWalletSigner, isCapxulError, isSettingUpLifecycle, localPrivateKeyAccountProvider, openfortEmbeddedSigner, openfortEmbeddedSignerFromWallet, openfortEmbeddedWalletPort };
9522
+ //#region src/telemetry/from-posthog.ts
9523
+ /**
9524
+ * Drop props that must never cross to a host-owned external sink. Today that is
9525
+ * the `$exception` `details` blob: `captureException` serializes
9526
+ * `CapxulError.details` (e.g. `{ asset, available, required }`, `{ name }`,
9527
+ * `{ accountId }` — errors.ts) into it, and the shared redactor has no
9528
+ * `$exception` rule, so it is stripped here at the boundary (infra#1037). The
9529
+ * safe fields (error code, operation, failure_mode, the fixed leak-safe message,
9530
+ * stack frames) are preserved.
9531
+ */
9532
+ function stripHostUnsafeProps(props) {
9533
+ if (props === void 0) return void 0;
9534
+ const { details: _details, ...safe } = props;
9535
+ return safe;
9536
+ }
9537
+ /**
9538
+ * Adapt the host's already-initialized posthog-like client into a
9539
+ * `TelemetryPort` for the `telemetry` prop / input. This port SUPPLANTS the
9540
+ * SDK's no-op default telemetry sink (`production.ts` binds it via
9541
+ * `Layer.succeed`, not `compose` — there is no client-side success relay to
9542
+ * compose with); it is additive to Capxul's backend first-party record and
9543
+ * never owns the client.
9544
+ */
9545
+ function telemetryFromPostHog(client, options = {}) {
9546
+ const active = () => {
9547
+ if (client === null || client === void 0) return false;
9548
+ try {
9549
+ return typeof options.enabled === "function" ? options.enabled() : options.enabled ?? true;
9550
+ } catch {
9551
+ return false;
9552
+ }
9553
+ };
9554
+ const contextProps = () => {
9555
+ let raw;
9556
+ try {
9557
+ raw = typeof options.context === "function" ? options.context() : options.context;
9558
+ } catch {
9559
+ return {};
9560
+ }
9561
+ return observationContextProps(sanitizeObservationContext(raw));
9562
+ };
9563
+ return new PostHogTelemetryAdapter({
9564
+ capture: (name, props) => {
9565
+ if (!active() || client === null || client === void 0) return;
9566
+ client.capture(name, {
9567
+ ...stripHostUnsafeProps(props),
9568
+ ...contextProps()
9569
+ });
9570
+ },
9571
+ identify: (input) => {
9572
+ if (!active() || client?.identify === void 0) return;
9573
+ client.identify(input.distinctId, {
9574
+ ...input.traits,
9575
+ ...input.properties
9576
+ });
9577
+ },
9578
+ group: (input) => {
9579
+ if (!active() || client?.group === void 0) return;
9580
+ client.group(input.groupType, input.groupKey, input.properties === void 0 ? void 0 : { ...input.properties });
9581
+ },
9582
+ reset: () => {
9583
+ if (!active() || client?.reset === void 0) return;
9584
+ client.reset();
9585
+ }
9586
+ });
9587
+ }
9588
+ //#endregion
9589
+ export { CAPXUL_SDK_EXPECTED_OUTCOME_EVENT, CapxulError, captureException, captureExceptionSync, createCapxulClient, deriveDevPrivateKey, devPrivateKeySigner, eip1193AccountProvider, embeddedSigner, fromPostHog, injectedWalletSigner, isCapxulError, isSettingUpLifecycle, localPrivateKeyAccountProvider, openfortEmbeddedSigner, openfortEmbeddedSignerFromWallet, openfortEmbeddedWalletPort, telemetryFromPostHog };
9394
9590
 
9395
9591
  //# sourceMappingURL=index.mjs.map