@capxul/sdk 1.0.0-alpha.19 → 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({
@@ -1624,7 +1652,7 @@ async function recoverRawDigestSigner(input) {
1624
1652
  }
1625
1653
  //#endregion
1626
1654
  //#region package.json
1627
- var version = "1.0.0-alpha.19";
1655
+ var version = "1.0.0-alpha.20";
1628
1656
  //#endregion
1629
1657
  //#region src/ports/auth-client.ts
1630
1658
  var AuthClientError = class extends Data.TaggedError("AuthClientError") {};
@@ -5239,6 +5267,18 @@ function transportErrorFromThrown(operation, request, cause) {
5239
5267
  return transportErrorFromCapxul(operation, request, cause instanceof Error ? Errors.providerError("transport", request.name, cause) : Errors.providerError("transport", request.name, new Error(String(cause))), cause);
5240
5268
  }
5241
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
5242
5282
  //#region src/openfort/create-openfort-browser-signer.ts
5243
5283
  function openfortProviderError(operation, cause) {
5244
5284
  return cause instanceof CapxulError ? cause : Errors.providerError("openfort", operation, cause, { failure_mode: "unknown" });
@@ -6599,10 +6639,6 @@ function makeCurrentUserMethods(deps) {
6599
6639
  deps.smartAccount.loadCurrent(options),
6600
6640
  deps.orgs(options)
6601
6641
  ]);
6602
- if (!account.ok) return {
6603
- ok: false,
6604
- error: account.error
6605
- };
6606
6642
  if (!smartAccount.ok) return {
6607
6643
  ok: false,
6608
6644
  error: smartAccount.error
@@ -6611,6 +6647,10 @@ function makeCurrentUserMethods(deps) {
6611
6647
  ok: false,
6612
6648
  error: organizations.error
6613
6649
  };
6650
+ if (!account.ok && account.error.code !== "SMART_ACCOUNT_MISSING") return {
6651
+ ok: false,
6652
+ error: account.error
6653
+ };
6614
6654
  return {
6615
6655
  ok: true,
6616
6656
  value: {
@@ -6621,10 +6661,10 @@ function makeCurrentUserMethods(deps) {
6621
6661
  handle: null,
6622
6662
  paymentLink: null
6623
6663
  },
6624
- personalAccount: {
6664
+ personalAccount: account.ok ? {
6625
6665
  id: account.value.id,
6626
6666
  address: smartAccount.value?.smartAccountAddress ?? null
6627
- },
6667
+ } : null,
6628
6668
  organizations: organizations.value.map((organization) => ({
6629
6669
  id: organization.id,
6630
6670
  name: organization.name,
@@ -8838,24 +8878,34 @@ function ignoreDeliveryFailure(delivery) {
8838
8878
  Promise.resolve(delivery).catch(() => void 0);
8839
8879
  } catch {}
8840
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
+ }
8841
8897
  function postHogProperties(failure, context) {
8842
- const properties = {
8843
- sdk_version: failure.sdkVersion,
8844
- operation: failure.operation,
8845
- error_kind: failure.errorKind,
8846
- handled: true
8847
- };
8848
8898
  const merged = sanitizeObservationContext({
8849
8899
  ...context,
8850
8900
  ...failure.context
8851
8901
  });
8852
- if (merged?.application !== void 0) properties.application = merged.application;
8853
- if (merged?.release !== void 0) properties.release = merged.release;
8854
- if (merged?.sessionId !== void 0) properties.session_id = merged.sessionId;
8855
- if (merged?.organizationId !== void 0) properties.organization_id = merged.organizationId;
8856
- if (merged?.correlationId !== void 0) properties.correlation_id = merged.correlationId;
8857
- if (merged?.anonymousId !== void 0) properties.anonymous_id = merged.anonymousId;
8858
- 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
+ };
8859
8909
  }
8860
8910
  function resolveContext(context) {
8861
8911
  return sanitizeObservationContext(resolveRawContext(context));
@@ -8906,7 +8956,7 @@ function normalizeErrorKind(value) {
8906
8956
  return typeof value === "string" && /^[A-Za-z][A-Za-z0-9_.-]{0,63}$/u.test(value) ? value : "Error";
8907
8957
  }
8908
8958
  function syntheticException(operation, kind) {
8909
- const error = /* @__PURE__ */ new Error("Capxul SDK operation failed");
8959
+ const error = /* @__PURE__ */ new Error(EXCEPTION_MESSAGE);
8910
8960
  error.name = kind;
8911
8961
  error.stack = `${kind}: ${error.message}\n at CapxulSdkBoundary.${operation} (capxul-sdk-observation://boundary/${operation}:1:1)`;
8912
8962
  return error;
@@ -9252,6 +9302,9 @@ async function createCapxulClient$1(input) {
9252
9302
  if (signer === void 0 && runtime === "browser") signer = createOpenfortBrowserSignerFromBootstrap({
9253
9303
  ...adapters.value.bootstrap,
9254
9304
  authBaseUrl: resolvedAuthBaseUrl
9305
+ }, {
9306
+ diagnostic: new ConsoleDiagnosticAdapter(),
9307
+ telemetry: adapters.value.ports.telemetry
9255
9308
  });
9256
9309
  const client = wireOpenfortSignerLifecycle(assembleCapxulClient({
9257
9310
  ports: adapters.value.ports,
@@ -9466,6 +9519,73 @@ async function createCapxulClient(input) {
9466
9519
  return createCapxulClient$1(input);
9467
9520
  }
9468
9521
  //#endregion
9469
- 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 };
9470
9590
 
9471
9591
  //# sourceMappingURL=index.mjs.map