@rhinestone/1auth 0.7.6 → 0.8.1

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.
Files changed (43) hide show
  1. package/dist/chunk-IX45E5LE.mjs +6135 -0
  2. package/dist/chunk-IX45E5LE.mjs.map +1 -0
  3. package/dist/chunk-ZDW2LY6H.mjs +116 -0
  4. package/dist/chunk-ZDW2LY6H.mjs.map +1 -0
  5. package/dist/{client-Dn6mL7BZ.d.ts → client-B0vb_deA.d.mts} +26 -14
  6. package/dist/{client-C8QSA1th.d.mts → client-CPt1hn4_.d.ts} +26 -14
  7. package/dist/errors-Blx9IVF_.d.mts +16 -0
  8. package/dist/errors-Cg605N0t.d.ts +16 -0
  9. package/dist/headless.d.mts +5 -10
  10. package/dist/headless.d.ts +5 -10
  11. package/dist/headless.js +74 -24
  12. package/dist/headless.js.map +1 -1
  13. package/dist/headless.mjs +74 -24
  14. package/dist/headless.mjs.map +1 -1
  15. package/dist/index.d.mts +8 -7
  16. package/dist/index.d.ts +8 -7
  17. package/dist/index.js +678 -220
  18. package/dist/index.js.map +1 -1
  19. package/dist/index.mjs +68 -5271
  20. package/dist/index.mjs.map +1 -1
  21. package/dist/{provider-CJv38fIK.d.mts → provider-CNDrBzGs.d.mts} +2 -2
  22. package/dist/{provider-BsVmPgkQ.d.ts → provider-DwZPA2N1.d.ts} +2 -2
  23. package/dist/react.d.mts +3 -2
  24. package/dist/react.d.ts +3 -2
  25. package/dist/react.js +61 -1
  26. package/dist/react.js.map +1 -1
  27. package/dist/react.mjs +6 -1
  28. package/dist/react.mjs.map +1 -1
  29. package/dist/server.d.mts +2 -2
  30. package/dist/server.d.ts +2 -2
  31. package/dist/{types-Dzm5lZK-.d.mts → types-BN6cCuAd.d.mts} +88 -69
  32. package/dist/{types-Dzm5lZK-.d.ts → types-BN6cCuAd.d.ts} +88 -69
  33. package/dist/{verify-0VXQpQBJ.d.mts → verify-CEzkfM92.d.mts} +1 -1
  34. package/dist/{verify-9UgxLSdo.d.ts → verify-DhEkGnym.d.ts} +1 -1
  35. package/dist/wagmi.d.mts +3 -3
  36. package/dist/wagmi.d.ts +3 -3
  37. package/dist/wagmi.js +116 -26
  38. package/dist/wagmi.js.map +1 -1
  39. package/dist/wagmi.mjs +3 -1
  40. package/dist/wagmi.mjs.map +1 -1
  41. package/package.json +1 -1
  42. package/dist/chunk-E4YZS7FZ.mjs +0 -565
  43. package/dist/chunk-E4YZS7FZ.mjs.map +0 -1
package/dist/index.js CHANGED
@@ -34,6 +34,8 @@ __export(index_exports, {
34
34
  BatchQueueWidget: () => BatchQueueWidget,
35
35
  ETHEREUM_MESSAGE_PREFIX: () => ETHEREUM_MESSAGE_PREFIX,
36
36
  OneAuthClient: () => OneAuthClient,
37
+ OneAuthError: () => OneAuthError,
38
+ SIGNING_ERROR_CODES: () => SIGNING_ERROR_CODES,
37
39
  createCrossChainPermission: () => createCrossChainPermission,
38
40
  createOneAuthConnection: () => createOneAuthConnection,
39
41
  createOneAuthProvider: () => createOneAuthProvider,
@@ -55,6 +57,7 @@ __export(index_exports, {
55
57
  getTokenSymbol: () => getTokenSymbol,
56
58
  hashCalls: () => hashCalls,
57
59
  hashMessage: () => hashMessage,
60
+ isSigningErrorCode: () => isSigningErrorCode,
58
61
  isTestnet: () => isTestnet,
59
62
  isTokenAddressSupported: () => isTokenAddressSupported,
60
63
  resolveTokenAddress: () => resolveTokenAddress,
@@ -338,6 +341,111 @@ async function tokenFetchError(label, response) {
338
341
  );
339
342
  }
340
343
 
344
+ // src/types.ts
345
+ var SIGNING_ERROR_CODES = [
346
+ "USER_REJECTED",
347
+ "EXPIRED",
348
+ "INVALID_REQUEST",
349
+ "NETWORK_ERROR",
350
+ "POPUP_BLOCKED",
351
+ "SIGNING_FAILED",
352
+ "UNKNOWN"
353
+ ];
354
+ function isSigningErrorCode(value) {
355
+ return typeof value === "string" && SIGNING_ERROR_CODES.includes(value);
356
+ }
357
+
358
+ // src/errors.ts
359
+ function isPlainRecord(value) {
360
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
361
+ const prototype = Object.getPrototypeOf(value);
362
+ return prototype === Object.prototype || prototype === null;
363
+ }
364
+ function normalizeCandidateError(value) {
365
+ if (!isPlainRecord(value)) return void 0;
366
+ const candidate = {};
367
+ if (typeof value.code === "string") candidate.code = value.code;
368
+ if (typeof value.message === "string") candidate.message = value.message;
369
+ const details = normalizeOneAuthErrorDetails(value.details);
370
+ if (details) candidate.details = details;
371
+ return Object.keys(candidate).length > 0 ? candidate : void 0;
372
+ }
373
+ function normalizeOneAuthErrorDetails(value) {
374
+ if (typeof value === "string") return { reason: value };
375
+ if (Array.isArray(value)) {
376
+ const candidateErrors = value.map(normalizeCandidateError).filter((candidate) => candidate !== void 0);
377
+ return candidateErrors.length > 0 ? { candidateErrors } : void 0;
378
+ }
379
+ if (!isPlainRecord(value)) return void 0;
380
+ const details = {};
381
+ if (typeof value.providerCode === "string") details.providerCode = value.providerCode;
382
+ if (typeof value.traceId === "string") details.traceId = value.traceId;
383
+ if (typeof value.statusCode === "number" && Number.isFinite(value.statusCode)) {
384
+ details.statusCode = value.statusCode;
385
+ }
386
+ if (typeof value.errorType === "string") details.errorType = value.errorType;
387
+ if (Array.isArray(value.simulationUrls)) {
388
+ const simulationUrls = value.simulationUrls.filter(
389
+ (url) => typeof url === "string"
390
+ );
391
+ if (simulationUrls.length > 0) details.simulationUrls = simulationUrls;
392
+ }
393
+ if (typeof value.reason === "string") details.reason = value.reason;
394
+ if (Array.isArray(value.candidateErrors)) {
395
+ const candidateErrors = value.candidateErrors.map(normalizeCandidateError).filter((candidate) => candidate !== void 0);
396
+ if (candidateErrors.length > 0) details.candidateErrors = candidateErrors;
397
+ }
398
+ return Object.keys(details).length > 0 ? details : void 0;
399
+ }
400
+ function parseSigningResultError(value, fallbackCode = "SIGNING_FAILED", fallbackMessage = "Signing failed") {
401
+ if (!isPlainRecord(value)) return { code: fallbackCode, message: fallbackMessage };
402
+ const code = isSigningErrorCode(value.code) ? value.code : value.code === void 0 ? fallbackCode : "UNKNOWN";
403
+ return {
404
+ code,
405
+ message: typeof value.message === "string" ? value.message : fallbackMessage,
406
+ details: normalizeOneAuthErrorDetails(value.details)
407
+ };
408
+ }
409
+ var OneAuthError = class extends Error {
410
+ constructor(code, message, details) {
411
+ super(message);
412
+ this.name = "OneAuthError";
413
+ this.code = code;
414
+ this.details = details;
415
+ }
416
+ };
417
+ function toOneAuthError(error, fallbackMessage, fallbackCode = "UNKNOWN") {
418
+ return new OneAuthError(
419
+ error?.code || fallbackCode,
420
+ error?.message || fallbackMessage,
421
+ normalizeOneAuthErrorDetails(error?.details)
422
+ );
423
+ }
424
+ function executeErrorCode(errorData) {
425
+ if (!errorData || typeof errorData !== "object" || !("code" in errorData)) {
426
+ return "EXECUTE_FAILED";
427
+ }
428
+ return errorData.code === "INVALID_SIGNATURE" ? "INVALID_SIGNATURE" : "EXECUTE_FAILED";
429
+ }
430
+ function executeErrorDetails(debug) {
431
+ if (!debug || typeof debug !== "object") return void 0;
432
+ const details = {};
433
+ if ("code" in debug && typeof debug.code === "string") details.providerCode = debug.code;
434
+ if ("traceId" in debug && typeof debug.traceId === "string") details.traceId = debug.traceId;
435
+ if ("statusCode" in debug && typeof debug.statusCode === "number") {
436
+ details.statusCode = debug.statusCode;
437
+ }
438
+ if ("errorType" in debug && typeof debug.errorType === "string") {
439
+ details.errorType = debug.errorType;
440
+ }
441
+ if ("simulationUrls" in debug && Array.isArray(debug.simulationUrls)) {
442
+ details.simulationUrls = debug.simulationUrls.filter(
443
+ (url) => typeof url === "string"
444
+ );
445
+ }
446
+ return Object.keys(details).length > 0 ? details : void 0;
447
+ }
448
+
341
449
  // ../loading-tokens/src/index.ts
342
450
  var SPINNER_SIZE = 82;
343
451
  var SPINNER_STROKE = 2.4118;
@@ -375,6 +483,10 @@ var LOADING_TITLE = "Loading...";
375
483
  var LOADING_SUBTITLE = "This will only take a few moments, do not close the window.";
376
484
 
377
485
  // src/client.ts
486
+ function requireSigningPasskeyCredentials(value) {
487
+ if (!value) return void 0;
488
+ return typeof value.keyId === "number" ? value : void 0;
489
+ }
378
490
  var POPUP_WIDTH = LOADING_MODAL_WIDTH;
379
491
  var POPUP_HEIGHT = 600;
380
492
  var DEFAULT_EMBED_WIDTH = `${LOADING_MODAL_WIDTH}px`;
@@ -512,6 +624,16 @@ function normalizeGrantTargetChains(options) {
512
624
  function normalizeGrantSourceChains(options) {
513
625
  return Array.from(new Set(options.sourceChains ?? []));
514
626
  }
627
+ var sessionForgetHandlers = /* @__PURE__ */ new WeakMap();
628
+ function registerSessionForgetHandler(client, handler) {
629
+ const handlers = sessionForgetHandlers.get(client) ?? /* @__PURE__ */ new Set();
630
+ handlers.add(handler);
631
+ sessionForgetHandlers.set(client, handlers);
632
+ return () => {
633
+ handlers.delete(handler);
634
+ if (handlers.size === 0) sessionForgetHandlers.delete(client);
635
+ };
636
+ }
515
637
  var OneAuthClient = class {
516
638
  /**
517
639
  * Create a new OneAuthClient.
@@ -550,6 +672,7 @@ var OneAuthClient = class {
550
672
  this.config = { ...config, providerUrl, dialogUrl };
551
673
  this.theme = this.config.theme || {};
552
674
  this.sponsorship = normalizeSponsorship(config.sponsorship);
675
+ this.installDisconnectListener();
553
676
  if (typeof document !== "undefined") {
554
677
  this.injectPreconnect(providerUrl);
555
678
  if (dialogUrl !== providerUrl) {
@@ -571,6 +694,26 @@ var OneAuthClient = class {
571
694
  });
572
695
  this.emitTelemetry("client.init", initOperation, { outcome: "started" });
573
696
  }
697
+ /** Clear the default cache plus every provider bound to this client. */
698
+ forgetApplicationSessions() {
699
+ if (typeof window !== "undefined") localStorage.removeItem("1auth-user");
700
+ for (const handler of sessionForgetHandlers.get(this) ?? []) handler();
701
+ try {
702
+ this.config.onDisconnect?.();
703
+ } catch {
704
+ }
705
+ }
706
+ /** Forget embedder-side sessions from any trusted dialog transport. */
707
+ installDisconnectListener() {
708
+ if (typeof window === "undefined" || typeof document === "undefined" || typeof window.addEventListener !== "function") return;
709
+ const dialogOrigin = this.getDialogOrigin();
710
+ window.addEventListener("message", (event) => {
711
+ if (event.origin !== dialogOrigin) return;
712
+ if (event.data?.type === "PASSKEY_DISCONNECT") {
713
+ this.forgetApplicationSessions();
714
+ }
715
+ });
716
+ }
574
717
  /**
575
718
  * Update the sponsorship configuration at runtime. Pass `undefined` to
576
719
  * disable sponsorship.
@@ -702,13 +845,16 @@ var OneAuthClient = class {
702
845
  ...operation.trace?.spanId ? { spanId: operation.trace.spanId } : {}
703
846
  };
704
847
  }
848
+ /** Resolve the public funding policy while preserving the legacy user-paid alias. */
849
+ resolveSponsorshipMode(options) {
850
+ return options.sponsorshipMode ?? (options.sponsor === false ? "disabled" : "required");
851
+ }
705
852
  /**
706
853
  * Determine whether this signing call should request invisible dialog mode.
707
854
  * Resolution order: per-call option wins over the constructor config, which
708
855
  * wins over the platform-wide {@link DEFAULT_BLIND_SIGNING}. This lets an app
709
856
  * flip the global default for itself while still overriding individual
710
- * high-risk calls — e.g. default-blind but force the review UI for a large
711
- * transfer, or default-visible but blind-sign selected low-risk signatures.
857
+ * high-risk calls.
712
858
  */
713
859
  shouldRequestBlindSigning(options) {
714
860
  return options?.blind_signing ?? this.config.blind_signing ?? DEFAULT_BLIND_SIGNING;
@@ -741,12 +887,12 @@ var OneAuthClient = class {
741
887
  }
742
888
  }
743
889
  /**
744
- * Fetch one extension token per intent, aligned with `sponsorFlags`.
745
- * Returns an empty array when no intent is sponsored. Fired after
746
- * `/prepare` so each token can be bound to its quote's `intentOp`, and
747
- * overlaps the dialog / WebAuthn ceremony for no added serial latency.
890
+ * Fetch one extension token per canonical sponsorship intent input, aligned
891
+ * with `sponsorFlags`. Sponsored prepare uses the same token for the final
892
+ * quote and later submission, so route construction and execution share one
893
+ * digest-bound authorization.
748
894
  */
749
- async fetchExtensionTokens(intentOps, sponsorFlags) {
895
+ async fetchExtensionTokens(sponsorshipIntentInputs, sponsorFlags) {
750
896
  if (!this.sponsorship) {
751
897
  return { ok: false, message: MISSING_APP_CREDENTIALS_MESSAGE };
752
898
  }
@@ -755,8 +901,8 @@ var OneAuthClient = class {
755
901
  try {
756
902
  const sponsorship = this.sponsorship;
757
903
  const tokens = await Promise.all(
758
- intentOps.map(
759
- (op, i) => sponsorFlags[i] ? sponsorship.getExtensionToken(op) : Promise.resolve("")
904
+ sponsorshipIntentInputs.map(
905
+ (input, i) => sponsorFlags[i] ? sponsorship.getExtensionToken(input) : Promise.resolve("")
760
906
  )
761
907
  );
762
908
  return { ok: true, extensionTokens: tokens };
@@ -1765,11 +1911,13 @@ var OneAuthClient = class {
1765
1911
  async sendIntent(options) {
1766
1912
  const { accountAddress, targetChain } = options;
1767
1913
  const calls = capCallLabels(options.calls);
1768
- const sponsor = options.sponsor !== false;
1914
+ const sponsorshipMode = this.resolveSponsorshipMode(options);
1915
+ const sponsor = sponsorshipMode !== "disabled";
1769
1916
  const telemetry = this.createTelemetryOperation("intent", {
1770
1917
  targetChain: targetChain ?? null,
1771
1918
  callsCount: calls?.length ?? 0,
1772
1919
  sponsor,
1920
+ sponsorshipMode,
1773
1921
  blindSigning: this.shouldRequestBlindSigning(options)
1774
1922
  });
1775
1923
  if (getStoredSignerType() === "eoa") {
@@ -1972,43 +2120,129 @@ var OneAuthClient = class {
1972
2120
  });
1973
2121
  const prepareStartedAt = Date.now();
1974
2122
  let prepareDurationMs;
1975
- const runPrepare = () => this.prepareIntent(requestBody, telemetry).then((r) => {
1976
- earlyPrepareResult = r;
2123
+ const runPrepare = async () => {
2124
+ let result;
2125
+ if (sponsorshipMode === "disabled") {
2126
+ result = await this.prepareIntent(
2127
+ { ...requestBody, quoteMode: "final", sponsorshipMode: "self-funded" },
2128
+ telemetry
2129
+ );
2130
+ } else {
2131
+ const draft = await this.prepareSponsorshipDraft(
2132
+ { ...requestBody, sponsorshipMode: "required" },
2133
+ telemetry
2134
+ );
2135
+ if (!draft.success) {
2136
+ result = draft;
2137
+ } else {
2138
+ const extensionTokensStartedAt = Date.now();
2139
+ const quoteGrantResult = await this.fetchExtensionTokens(
2140
+ [JSON.stringify(draft.sponsorshipIntentInput)],
2141
+ [true]
2142
+ );
2143
+ extensionTokensDurationMs = Date.now() - extensionTokensStartedAt;
2144
+ if (!quoteGrantResult.ok) {
2145
+ if (sponsorshipMode === "preferred") {
2146
+ extensionTokensPromise = Promise.resolve({ ok: true, extensionTokens: [] });
2147
+ result = await this.prepareIntent(
2148
+ { ...requestBody, quoteMode: "final", sponsorshipMode: "self-funded" },
2149
+ telemetry
2150
+ );
2151
+ } else {
2152
+ result = {
2153
+ success: false,
2154
+ error: {
2155
+ code: "SPONSORSHIP_FETCH_FAILED",
2156
+ message: quoteGrantResult.message
2157
+ }
2158
+ };
2159
+ }
2160
+ } else {
2161
+ const prepareFinalQuote = (quoteGrant) => this.prepareIntent(
2162
+ {
2163
+ ...requestBody,
2164
+ quoteMode: "final",
2165
+ sponsorshipMode: "required",
2166
+ auth: {
2167
+ accessToken,
2168
+ extensionToken: quoteGrant
2169
+ }
2170
+ },
2171
+ telemetry
2172
+ );
2173
+ let quoteIsSponsored = true;
2174
+ result = await prepareFinalQuote(quoteGrantResult.extensionTokens[0]);
2175
+ if (!result.success) {
2176
+ const replacementQuoteGrant = await this.fetchExtensionTokens(
2177
+ [JSON.stringify(draft.sponsorshipIntentInput)],
2178
+ [true]
2179
+ );
2180
+ if (replacementQuoteGrant.ok) {
2181
+ result = await prepareFinalQuote(replacementQuoteGrant.extensionTokens[0]);
2182
+ }
2183
+ }
2184
+ if (!result.success && sponsorshipMode === "preferred") {
2185
+ extensionTokensPromise = Promise.resolve({ ok: true, extensionTokens: [] });
2186
+ quoteIsSponsored = false;
2187
+ result = await this.prepareIntent(
2188
+ { ...requestBody, quoteMode: "final", sponsorshipMode: "self-funded" },
2189
+ telemetry
2190
+ );
2191
+ }
2192
+ if (result.success && quoteIsSponsored) {
2193
+ const executionGrantResult = await this.fetchExtensionTokens(
2194
+ [result.data.intentOp],
2195
+ [true]
2196
+ );
2197
+ extensionTokensDurationMs = Date.now() - extensionTokensStartedAt;
2198
+ if (!executionGrantResult.ok) {
2199
+ if (sponsorshipMode === "preferred") {
2200
+ extensionTokensPromise = Promise.resolve({ ok: true, extensionTokens: [] });
2201
+ quoteIsSponsored = false;
2202
+ result = await this.prepareIntent(
2203
+ { ...requestBody, quoteMode: "final", sponsorshipMode: "self-funded" },
2204
+ telemetry
2205
+ );
2206
+ } else {
2207
+ result = {
2208
+ success: false,
2209
+ error: {
2210
+ code: "SPONSORSHIP_FETCH_FAILED",
2211
+ message: executionGrantResult.message
2212
+ }
2213
+ };
2214
+ }
2215
+ } else {
2216
+ extensionTokensPromise = Promise.resolve(executionGrantResult);
2217
+ }
2218
+ }
2219
+ }
2220
+ }
2221
+ }
2222
+ earlyPrepareResult = result;
1977
2223
  prepareDurationMs = Date.now() - prepareStartedAt;
1978
- if (r.success) {
1979
- this.emitTelemetry("intent.prepare.succeeded", telemetry, {
2224
+ this.emitTelemetry(
2225
+ result.success ? "intent.prepare.succeeded" : "intent.prepare.failed",
2226
+ telemetry,
2227
+ result.success ? {
1980
2228
  outcome: "success",
1981
2229
  targetChain,
1982
2230
  status: "quoted",
1983
- attributes: {
1984
- accessTokenDurationMs,
1985
- dialogReadyDurationMs,
1986
- prepareDurationMs
1987
- }
1988
- });
1989
- const extensionTokensStartedAt = Date.now();
1990
- extensionTokensPromise = this.fetchExtensionTokens(
1991
- [r.data.intentOp],
1992
- [sponsor]
1993
- ).then((result) => {
1994
- extensionTokensDurationMs = Date.now() - extensionTokensStartedAt;
1995
- return result;
1996
- });
1997
- } else {
1998
- this.emitTelemetry("intent.prepare.failed", telemetry, {
2231
+ attributes: { accessTokenDurationMs, dialogReadyDurationMs, prepareDurationMs }
2232
+ } : {
1999
2233
  outcome: "failure",
2000
2234
  targetChain,
2001
- ...describeTelemetryError(r.error),
2235
+ ...describeTelemetryError(result.error),
2002
2236
  attributes: {
2003
2237
  accessTokenDurationMs,
2004
2238
  dialogReadyDurationMs,
2005
2239
  prepareDurationMs,
2006
2240
  loadingPhase: "prepare"
2007
2241
  }
2008
- });
2009
- }
2010
- return r;
2011
- });
2242
+ }
2243
+ );
2244
+ return result;
2245
+ };
2012
2246
  const preparePromise = accessTokenFailure ? Promise.resolve({
2013
2247
  success: false,
2014
2248
  error: accessTokenFailure
@@ -2029,6 +2263,7 @@ var OneAuthClient = class {
2029
2263
  }
2030
2264
  accessToken = retryTokenResult.accessToken;
2031
2265
  requestBody.auth = { accessToken };
2266
+ extensionTokensPromise = Promise.resolve({ ok: true, extensionTokens: [] });
2032
2267
  return runPrepare();
2033
2268
  };
2034
2269
  const readyOrClose = await Promise.race([
@@ -2082,27 +2317,18 @@ var OneAuthClient = class {
2082
2317
  try {
2083
2318
  const refreshedTokenResult = await this.fetchAccessToken();
2084
2319
  const refreshToken = refreshedTokenResult.ok ? refreshedTokenResult.accessToken : accessToken;
2085
- const refreshResponse = await fetch(`${this.config.providerUrl}/api/intent/prepare`, {
2086
- method: "POST",
2087
- headers: { "Content-Type": "application/json", ...this.telemetryHeaders(telemetry) },
2088
- body: JSON.stringify({ ...requestBody, auth: { accessToken: refreshToken } }),
2089
- credentials: "include"
2090
- });
2091
- if (!refreshResponse.ok) {
2092
- console.error("[SDK] Quote refresh failed:", await refreshResponse.text());
2320
+ accessToken = refreshToken;
2321
+ requestBody.auth = { accessToken: refreshToken };
2322
+ extensionTokensPromise = Promise.resolve({ ok: true, extensionTokens: [] });
2323
+ const refreshedResult = await runPrepare();
2324
+ if (!refreshedResult.success) {
2325
+ console.error("[SDK] Quote refresh failed:", refreshedResult.error.message);
2093
2326
  return null;
2094
2327
  }
2095
- const refreshedData = await refreshResponse.json();
2096
- const refreshedExtensionPromise = this.fetchExtensionTokens(
2097
- [refreshedData.intentOp],
2098
- [sponsor]
2099
- );
2100
- const extensionResult = await refreshedExtensionPromise;
2328
+ const refreshedData = refreshedResult.data;
2329
+ const extensionResult = await extensionTokensPromise;
2101
2330
  if (!extensionResult.ok) {
2102
- console.error(
2103
- "[SDK] Extension token refresh failed:",
2104
- extensionResult.message
2105
- );
2331
+ console.error("[SDK] Extension token refresh failed:", extensionResult.message);
2106
2332
  return null;
2107
2333
  }
2108
2334
  const refreshedAuth = {
@@ -2110,9 +2336,7 @@ var OneAuthClient = class {
2110
2336
  extensionTokens: extensionResult.extensionTokens
2111
2337
  };
2112
2338
  prepareResponse = refreshedData;
2113
- accessToken = refreshToken;
2114
- requestBody.auth = { accessToken: refreshToken };
2115
- extensionTokensPromise = refreshedExtensionPromise;
2339
+ extensionTokensPromise = Promise.resolve(extensionResult);
2116
2340
  currentInitPayload = {
2117
2341
  ...currentInitPayload,
2118
2342
  transaction: refreshedData.transaction,
@@ -2131,7 +2355,10 @@ var OneAuthClient = class {
2131
2355
  intentOp: refreshedData.intentOp,
2132
2356
  expiresAt: refreshedData.expiresAt,
2133
2357
  challenge: refreshedData.challenge,
2134
- originMessages: refreshedData.originMessages,
2358
+ originMessages: refreshedData.originMessages?.map((message) => ({
2359
+ chainId: message.chainId,
2360
+ hash: message.messageHash
2361
+ })),
2135
2362
  transaction: refreshedData.transaction,
2136
2363
  digestResult: refreshedData.digestResult,
2137
2364
  binding: refreshedData.binding,
@@ -2505,8 +2732,7 @@ var OneAuthClient = class {
2505
2732
  binding: prepareResponse.binding,
2506
2733
  // Signature from dialog
2507
2734
  signature: signingResult.signature,
2508
- passkey: signingResult.passkey,
2509
- // Include passkey info for signature encoding
2735
+ passkey: requireSigningPasskeyCredentials(signingResult.passkey),
2510
2736
  // App JWT — `accessToken` is always present. `extensionToken` is
2511
2737
  // only included when sponsorship was requested (sponsor !== false).
2512
2738
  auth: {
@@ -2524,7 +2750,7 @@ var OneAuthClient = class {
2524
2750
  this.emitTelemetry("intent.execute.failed", telemetry, {
2525
2751
  outcome: "failure",
2526
2752
  targetChain: prepareResponse.targetChain,
2527
- errorCode: "EXECUTE_FAILED",
2753
+ errorCode: executeErrorCode(errorData),
2528
2754
  errorMessage: errorData.error || "Failed to execute intent"
2529
2755
  });
2530
2756
  return {
@@ -2533,8 +2759,9 @@ var OneAuthClient = class {
2533
2759
  // No intentId - execute failed before creation
2534
2760
  status: "failed",
2535
2761
  error: {
2536
- code: "EXECUTE_FAILED",
2537
- message: errorData.error || "Failed to execute intent"
2762
+ code: executeErrorCode(errorData),
2763
+ message: errorData.error || "Failed to execute intent",
2764
+ details: executeErrorDetails(errorData.debug)
2538
2765
  }
2539
2766
  };
2540
2767
  }
@@ -2791,7 +3018,7 @@ var OneAuthClient = class {
2791
3018
  error: "No sponsorship configured on OneAuthClient. Every user intent must carry the app's JWT \u2014 configure `sponsorship` on the client."
2792
3019
  };
2793
3020
  }
2794
- const sponsorFlags = options.intents.map((intent) => intent.sponsor !== false);
3021
+ const sponsorshipModes = options.intents.map((intent) => this.resolveSponsorshipMode(intent));
2795
3022
  const accessTokenResult = await this.fetchAccessToken();
2796
3023
  if (!accessTokenResult.ok) {
2797
3024
  this.emitTelemetry("batch.prepare.failed", telemetry, {
@@ -2803,8 +3030,7 @@ var OneAuthClient = class {
2803
3030
  success: false,
2804
3031
  results: [],
2805
3032
  successCount: 0,
2806
- failureCount: 0,
2807
- error: accessTokenResult.message
3033
+ failureCount: 0
2808
3034
  };
2809
3035
  }
2810
3036
  let accessToken = accessTokenResult.accessToken;
@@ -2846,13 +3072,12 @@ var OneAuthClient = class {
2846
3072
  });
2847
3073
  const dialogOrigin = this.getDialogOrigin();
2848
3074
  let earlyBatchResult = null;
2849
- let batchExtensionTokensPromise = Promise.resolve({ ok: true, extensionTokens: [] });
2850
3075
  this.emitTelemetry("batch.prepare.started", telemetry, {
2851
3076
  outcome: "started",
2852
3077
  intentCount: options.intents.length,
2853
3078
  targetChains: serializedIntents.map((intent) => intent.targetChain)
2854
3079
  });
2855
- const preparePromise = this.prepareBatchIntent(requestBody, telemetry).then((r) => {
3080
+ const preparePromise = this.prepareBatchWithFunding(requestBody, sponsorshipModes, telemetry).then((r) => {
2856
3081
  earlyBatchResult = r;
2857
3082
  if (r.success) {
2858
3083
  this.emitTelemetry("batch.prepare.succeeded", telemetry, {
@@ -2860,10 +3085,6 @@ var OneAuthClient = class {
2860
3085
  intentCount: r.data.intents.length,
2861
3086
  targetChains: serializedIntents.map((intent) => intent.targetChain)
2862
3087
  });
2863
- batchExtensionTokensPromise = this.fetchExtensionTokens(
2864
- r.data.intents.map((intent) => intent.intentOp),
2865
- sponsorFlags
2866
- );
2867
3088
  } else {
2868
3089
  this.emitTelemetry("batch.prepare.failed", telemetry, {
2869
3090
  outcome: "failure",
@@ -2912,17 +3133,6 @@ var OneAuthClient = class {
2912
3133
  error: prepareResult.error
2913
3134
  };
2914
3135
  };
2915
- const handleSponsorshipFailure = async (message) => {
2916
- this.sendPrepareError(iframe, message);
2917
- await this.waitForDialogCloseUnlessBlind(blindSigning, dialog, cleanup);
2918
- return {
2919
- success: false,
2920
- results: [],
2921
- successCount: 0,
2922
- failureCount: 0,
2923
- error: `Sponsorship token fetch failed: ${message}`
2924
- };
2925
- };
2926
3136
  let prepareResponse;
2927
3137
  if (earlyBatchResult) {
2928
3138
  const prepareResult = earlyBatchResult;
@@ -2930,13 +3140,9 @@ var OneAuthClient = class {
2930
3140
  return handleBatchPrepareFailure(prepareResult);
2931
3141
  }
2932
3142
  prepareResponse = prepareResult.data;
2933
- const batchExtensionResult = await batchExtensionTokensPromise;
2934
- if (!batchExtensionResult.ok) {
2935
- return handleSponsorshipFailure(batchExtensionResult.message);
2936
- }
2937
3143
  const batchSponsorshipTokens = {
2938
3144
  accessToken,
2939
- extensionTokens: batchExtensionResult.extensionTokens
3145
+ extensionTokens: prepareResult.extensionTokens
2940
3146
  };
2941
3147
  currentBatchPayload = {
2942
3148
  mode: "iframe",
@@ -2972,13 +3178,9 @@ var OneAuthClient = class {
2972
3178
  return handleBatchPrepareFailure(prepareResult);
2973
3179
  }
2974
3180
  prepareResponse = prepareResult.data;
2975
- const batchExtensionResult = await batchExtensionTokensPromise;
2976
- if (!batchExtensionResult.ok) {
2977
- return handleSponsorshipFailure(batchExtensionResult.message);
2978
- }
2979
3181
  const batchSponsorshipTokens = {
2980
3182
  accessToken,
2981
- extensionTokens: batchExtensionResult.extensionTokens
3183
+ extensionTokens: prepareResult.extensionTokens
2982
3184
  };
2983
3185
  currentBatchPayload = {
2984
3186
  mode: "iframe",
@@ -3013,41 +3215,40 @@ var OneAuthClient = class {
3013
3215
  const handleMessage = async (event) => {
3014
3216
  if (event.origin !== dialogOrigin) return;
3015
3217
  const message = event.data;
3218
+ if (message?.type === "PASSKEY_DISCONNECT") {
3219
+ window.removeEventListener("message", handleMessage);
3220
+ cleanup();
3221
+ this.emitTelemetry("dialog.cancelled", telemetry, {
3222
+ outcome: "cancelled",
3223
+ errorCode: "USER_REJECTED",
3224
+ errorMessage: "Session disconnected"
3225
+ });
3226
+ resolve({
3227
+ success: false,
3228
+ results: [],
3229
+ successCount: 0,
3230
+ failureCount: 0
3231
+ });
3232
+ return;
3233
+ }
3016
3234
  if (message?.type === "PASSKEY_REFRESH_QUOTE") {
3017
3235
  try {
3018
3236
  const refreshedTokenResult = await this.fetchAccessToken();
3019
3237
  const refreshToken = refreshedTokenResult.ok ? refreshedTokenResult.accessToken : accessToken;
3020
- const refreshResponse = await fetch(`${this.config.providerUrl}/api/intent/batch-prepare`, {
3021
- method: "POST",
3022
- headers: { "Content-Type": "application/json", ...this.telemetryHeaders(telemetry) },
3023
- body: JSON.stringify({ ...requestBody, auth: { accessToken: refreshToken } })
3024
- });
3025
- if (refreshResponse.ok) {
3026
- const refreshed = await refreshResponse.json();
3027
- const refreshedExtensionPromise = this.fetchExtensionTokens(
3028
- refreshed.intents.map((intent) => intent.intentOp),
3029
- sponsorFlags
3030
- );
3031
- const extensionResult = await refreshedExtensionPromise;
3032
- if (!extensionResult.ok) {
3033
- console.error(
3034
- "[SDK] Batch extension token refresh failed:",
3035
- extensionResult.message
3036
- );
3037
- iframe.contentWindow?.postMessage({
3038
- type: "PASSKEY_REFRESH_ERROR",
3039
- error: "Failed to refresh batch quotes"
3040
- }, dialogOrigin);
3041
- return;
3042
- }
3238
+ const refreshResult = await this.prepareBatchWithFunding(
3239
+ { ...requestBody, auth: { accessToken: refreshToken } },
3240
+ sponsorshipModes,
3241
+ telemetry
3242
+ );
3243
+ if (refreshResult.success) {
3244
+ const refreshed = refreshResult.data;
3043
3245
  const refreshedAuth = {
3044
3246
  accessToken: refreshToken,
3045
- extensionTokens: extensionResult.extensionTokens
3247
+ extensionTokens: refreshResult.extensionTokens
3046
3248
  };
3047
3249
  prepareResponse = refreshed;
3048
3250
  accessToken = refreshToken;
3049
3251
  requestBody.auth = { accessToken: refreshToken };
3050
- batchExtensionTokensPromise = refreshedExtensionPromise;
3051
3252
  currentBatchPayload = {
3052
3253
  ...currentBatchPayload,
3053
3254
  batchIntents: refreshed.intents,
@@ -3194,6 +3395,15 @@ var OneAuthClient = class {
3194
3395
  if (event.origin !== dialogOrigin) return;
3195
3396
  const message = event.data;
3196
3397
  const payload = message?.data;
3398
+ if (message?.type === "PASSKEY_DISCONNECT") {
3399
+ window.removeEventListener("message", handleMessage);
3400
+ cleanup();
3401
+ resolve({
3402
+ success: false,
3403
+ error: { code: "USER_REJECTED", message: "Session disconnected" }
3404
+ });
3405
+ return;
3406
+ }
3197
3407
  if (message?.type === "PASSKEY_SIGNING_RESULT" && payload?.requestId === requestId) {
3198
3408
  window.removeEventListener("message", handleMessage);
3199
3409
  if (message.success && payload.signature) {
@@ -3207,10 +3417,7 @@ var OneAuthClient = class {
3207
3417
  } else {
3208
3418
  resolve({
3209
3419
  success: false,
3210
- error: message.error || {
3211
- code: "SIGNING_FAILED",
3212
- message: "Signing failed"
3213
- }
3420
+ error: parseSigningResultError(message.error)
3214
3421
  });
3215
3422
  }
3216
3423
  } else if (message?.type === "PASSKEY_CLOSE" && event.source === iframe.contentWindow) {
@@ -3257,6 +3464,15 @@ var OneAuthClient = class {
3257
3464
  if (event.origin !== dialogOrigin) return;
3258
3465
  const message = event.data;
3259
3466
  const payload = message?.data;
3467
+ if (message?.type === "PASSKEY_DISCONNECT") {
3468
+ window.removeEventListener("message", handleMessage);
3469
+ cleanup();
3470
+ resolve({
3471
+ success: false,
3472
+ error: { code: "USER_REJECTED", message: "Session disconnected" }
3473
+ });
3474
+ return;
3475
+ }
3260
3476
  if (message?.type === "PASSKEY_SIGNING_RESULT") {
3261
3477
  window.removeEventListener("message", handleMessage);
3262
3478
  if (message.success && payload?.intentId) {
@@ -3275,10 +3491,7 @@ var OneAuthClient = class {
3275
3491
  cleanup();
3276
3492
  resolve({
3277
3493
  success: false,
3278
- error: message.error || {
3279
- code: "SIGNING_FAILED",
3280
- message: "Signing failed"
3281
- }
3494
+ error: parseSigningResultError(message.error)
3282
3495
  });
3283
3496
  }
3284
3497
  } else if (message?.type === "PASSKEY_CLOSE" && event.source === iframe.contentWindow) {
@@ -3324,6 +3537,15 @@ var OneAuthClient = class {
3324
3537
  const handleMessage = async (event) => {
3325
3538
  if (event.origin !== dialogOrigin) return;
3326
3539
  const message = event.data;
3540
+ if (message?.type === "PASSKEY_DISCONNECT") {
3541
+ window.removeEventListener("message", handleMessage);
3542
+ cleanup();
3543
+ resolve({
3544
+ success: false,
3545
+ error: { code: "USER_REJECTED", message: "Session disconnected" }
3546
+ });
3547
+ return;
3548
+ }
3327
3549
  if (message?.type === "PASSKEY_REFRESH_QUOTE") {
3328
3550
  const refreshedData = await onRefresh();
3329
3551
  if (refreshedData) {
@@ -3358,10 +3580,7 @@ var OneAuthClient = class {
3358
3580
  cleanup();
3359
3581
  resolve({
3360
3582
  success: false,
3361
- error: message.error || {
3362
- code: "SIGNING_FAILED",
3363
- message: "Signing failed"
3364
- }
3583
+ error: parseSigningResultError(message.error)
3365
3584
  });
3366
3585
  }
3367
3586
  } else if (message?.type === "PASSKEY_CLOSE" && event.source === iframe.contentWindow) {
@@ -3530,7 +3749,8 @@ var OneAuthClient = class {
3530
3749
  async prewarm() {
3531
3750
  if (typeof document === "undefined") return false;
3532
3751
  if (this.prewarmState) return this.prewarmState.ready;
3533
- const warmUrl = `${this.getDialogUrl()}/dialog/warm`;
3752
+ const warmParams = new URLSearchParams({ parentOrigin: window.location.origin });
3753
+ const warmUrl = `${this.getDialogUrl()}/dialog/warm?${warmParams.toString()}`;
3534
3754
  const iframe = document.createElement("iframe");
3535
3755
  iframe.setAttribute("aria-hidden", "true");
3536
3756
  iframe.setAttribute("tabindex", "-1");
@@ -3652,6 +3872,47 @@ var OneAuthClient = class {
3652
3872
  * @returns On success: `{ success: true, data: PrepareIntentResponse, tier }`.
3653
3873
  * On failure: `{ success: false, error: { code, message, details? } }`.
3654
3874
  */
3875
+ /**
3876
+ * Request a non-sponsored draft solely to obtain the SDK-canonical intent
3877
+ * input that the embedding app must authorize. The passkey service returns
3878
+ * no signable quote or user data in this phase.
3879
+ */
3880
+ async prepareSponsorshipDraft(requestBody, telemetry) {
3881
+ try {
3882
+ const response = await fetch(`${this.config.providerUrl}/api/intent/prepare`, {
3883
+ method: "POST",
3884
+ headers: { "Content-Type": "application/json", ...this.telemetryHeaders(telemetry) },
3885
+ body: JSON.stringify({ ...requestBody, quoteMode: "draft" })
3886
+ });
3887
+ if (!response.ok) {
3888
+ const errorData = await response.json().catch(() => ({}));
3889
+ return {
3890
+ success: false,
3891
+ error: {
3892
+ code: "PREPARE_FAILED",
3893
+ message: errorData.error || "Failed to prepare sponsorship draft",
3894
+ details: errorData.details ?? errorData.candidateErrors ?? errorData
3895
+ }
3896
+ };
3897
+ }
3898
+ const data = await response.json();
3899
+ if (data.sponsorshipIntentInput === void 0) {
3900
+ return {
3901
+ success: false,
3902
+ error: { code: "PREPARE_FAILED", message: "Prepare response missing sponsorship intent input" }
3903
+ };
3904
+ }
3905
+ return { success: true, sponsorshipIntentInput: data.sponsorshipIntentInput };
3906
+ } catch (error) {
3907
+ return {
3908
+ success: false,
3909
+ error: {
3910
+ code: "NETWORK_ERROR",
3911
+ message: error instanceof Error ? error.message : "Network error"
3912
+ }
3913
+ };
3914
+ }
3915
+ }
3655
3916
  async prepareIntent(requestBody, telemetry) {
3656
3917
  try {
3657
3918
  const response = await fetch(`${this.config.providerUrl}/api/intent/prepare`, {
@@ -3670,7 +3931,9 @@ var OneAuthClient = class {
3670
3931
  error: {
3671
3932
  code: errorMessage.includes("User not found") ? "USER_NOT_FOUND" : "PREPARE_FAILED",
3672
3933
  message: errorMessage,
3673
- details: errorData.details ?? errorData.candidateErrors ?? errorData
3934
+ details: normalizeOneAuthErrorDetails(
3935
+ errorData.details ?? (errorData.candidateErrors === void 0 ? errorData : { candidateErrors: errorData.candidateErrors })
3936
+ )
3674
3937
  }
3675
3938
  };
3676
3939
  }
@@ -3703,6 +3966,134 @@ var OneAuthClient = class {
3703
3966
  * @returns On success: `{ success: true, data: PrepareBatchIntentResponse, tier }`.
3704
3967
  * On failure: `{ success: false, error, failedIntents? }`.
3705
3968
  */
3969
+ /**
3970
+ * Draft, authorize, and authoritatively quote a batch without losing caller indices.
3971
+ * Preferred sponsorship failures are retried only by an explicit full-batch
3972
+ * self-funded re-quote so every returned intent shares one fresh merkle root.
3973
+ */
3974
+ async prepareBatchWithFunding(requestBody, sponsorshipModes, telemetry) {
3975
+ const draftFundingModes = sponsorshipModes.map(
3976
+ (mode) => mode === "disabled" ? "self-funded" : "required"
3977
+ );
3978
+ const draftResult = await this.prepareBatchDraft(
3979
+ { ...requestBody, quoteMode: "draft", fundingModes: draftFundingModes },
3980
+ telemetry
3981
+ );
3982
+ if (!draftResult.success) return draftResult;
3983
+ const draftFailedIntents = draftResult.data.failedIntents ?? [];
3984
+ const draftSuccessfulIndices = new Set(
3985
+ Object.keys(draftResult.data.sponsorshipIntentInputs).map(Number)
3986
+ );
3987
+ if (draftSuccessfulIndices.size === 0) {
3988
+ return {
3989
+ success: false,
3990
+ error: "All intents failed to get sponsorship drafts",
3991
+ failedIntents: draftFailedIntents
3992
+ };
3993
+ }
3994
+ const finalIntents = requestBody.intents.flatMap((intent, index) => draftSuccessfulIndices.has(index) ? [{ ...intent, originalIndex: index }] : []);
3995
+ const grantsByIndex = {};
3996
+ const finalFundingModes = [...draftFundingModes];
3997
+ const sponsoredIndices = Object.keys(draftResult.data.sponsorshipIntentInputs).map(Number).filter((index) => sponsorshipModes[index] !== "disabled");
3998
+ const grantResults = await Promise.allSettled(
3999
+ sponsoredIndices.map(async (index) => ({
4000
+ index,
4001
+ token: await this.sponsorship.getExtensionToken(
4002
+ JSON.stringify(draftResult.data.sponsorshipIntentInputs[String(index)])
4003
+ )
4004
+ }))
4005
+ );
4006
+ for (let i = 0; i < grantResults.length; i++) {
4007
+ const result = grantResults[i];
4008
+ const index = sponsoredIndices[i];
4009
+ if (result.status === "fulfilled") {
4010
+ grantsByIndex[String(index)] = result.value.token;
4011
+ } else if (sponsorshipModes[index] === "preferred") {
4012
+ finalFundingModes[index] = "self-funded";
4013
+ } else {
4014
+ return { success: false, error: `Sponsorship token fetch failed for required intent ${index}` };
4015
+ }
4016
+ }
4017
+ const runFinal = (fundingModes) => this.prepareBatchIntent({
4018
+ ...requestBody,
4019
+ intents: finalIntents,
4020
+ quoteMode: "final",
4021
+ fundingModes,
4022
+ quoteExtensionTokens: grantsByIndex
4023
+ }, telemetry);
4024
+ let finalResult = await runFinal(finalFundingModes);
4025
+ const preferredSponsoredFailures = finalResult.success ? (finalResult.data.failedIntents ?? []).map((failure) => failure.index) : (finalResult.failedIntents ?? []).map((failure) => failure.index);
4026
+ const preferredFallbackIndices = preferredSponsoredFailures.filter(
4027
+ (index) => sponsorshipModes[index] === "preferred" && finalFundingModes[index] === "required"
4028
+ );
4029
+ if (preferredFallbackIndices.length > 0) {
4030
+ for (const index of preferredFallbackIndices) {
4031
+ finalFundingModes[index] = "self-funded";
4032
+ delete grantsByIndex[String(index)];
4033
+ }
4034
+ finalResult = await runFinal(finalFundingModes);
4035
+ }
4036
+ if (!finalResult.success) return finalResult;
4037
+ if (draftFailedIntents.length > 0) {
4038
+ const draftFailedIndices = new Set(
4039
+ draftFailedIntents.map((failure) => failure.index)
4040
+ );
4041
+ finalResult = {
4042
+ ...finalResult,
4043
+ data: {
4044
+ ...finalResult.data,
4045
+ failedIntents: [
4046
+ ...draftFailedIntents,
4047
+ ...(finalResult.data.failedIntents ?? []).filter(
4048
+ (failure) => !draftFailedIndices.has(failure.index)
4049
+ )
4050
+ ]
4051
+ }
4052
+ };
4053
+ }
4054
+ const sponsoredPreparedIntents = finalResult.data.intents.filter(
4055
+ (intent) => finalFundingModes[intent.index] === "required"
4056
+ );
4057
+ const executionGrantResults = await Promise.allSettled(
4058
+ sponsoredPreparedIntents.map(async (intent) => ({
4059
+ index: intent.index,
4060
+ token: await this.sponsorship.getExtensionToken(intent.intentOp)
4061
+ }))
4062
+ );
4063
+ const executionGrantsByIndex = {};
4064
+ for (let i = 0; i < executionGrantResults.length; i++) {
4065
+ const result = executionGrantResults[i];
4066
+ const index = sponsoredPreparedIntents[i].index;
4067
+ if (result.status === "fulfilled") {
4068
+ executionGrantsByIndex[String(index)] = result.value.token;
4069
+ } else {
4070
+ return { success: false, error: `Execution sponsorship token fetch failed for intent ${index}` };
4071
+ }
4072
+ }
4073
+ return {
4074
+ ...finalResult,
4075
+ extensionTokens: finalResult.data.intents.map(
4076
+ (intent) => finalFundingModes[intent.index] === "required" ? executionGrantsByIndex[String(intent.index)] ?? "" : ""
4077
+ )
4078
+ };
4079
+ }
4080
+ /** Request canonical batch sponsorship inputs without returning signable data. */
4081
+ async prepareBatchDraft(requestBody, telemetry) {
4082
+ try {
4083
+ const response = await fetch(`${this.config.providerUrl}/api/intent/batch-prepare`, {
4084
+ method: "POST",
4085
+ headers: { "Content-Type": "application/json", ...this.telemetryHeaders(telemetry) },
4086
+ body: JSON.stringify(requestBody)
4087
+ });
4088
+ if (!response.ok) {
4089
+ const errorData = await response.json().catch(() => ({}));
4090
+ return { success: false, error: errorData.error || "Failed to prepare batch sponsorship draft", failedIntents: errorData.failedIntents };
4091
+ }
4092
+ return { success: true, data: await response.json(), tier: response.headers.get("X-Origin-Tier") };
4093
+ } catch {
4094
+ return { success: false, error: "Network error" };
4095
+ }
4096
+ }
3706
4097
  async prepareBatchIntent(requestBody, telemetry) {
3707
4098
  try {
3708
4099
  const response = await fetch(`${this.config.providerUrl}/api/intent/batch-prepare`, {
@@ -4460,7 +4851,7 @@ var OneAuthClient = class {
4460
4851
  resolve({
4461
4852
  success: false,
4462
4853
  requestId,
4463
- error: message.error
4854
+ error: parseSigningResultError(message.error)
4464
4855
  });
4465
4856
  }
4466
4857
  }
@@ -4485,7 +4876,7 @@ var OneAuthClient = class {
4485
4876
  success: false,
4486
4877
  requestId: requestId || void 0,
4487
4878
  error: {
4488
- code: error,
4879
+ code: parseSigningResultError({ code: error }).code,
4489
4880
  message: errorMessage || "Unknown error"
4490
4881
  }
4491
4882
  };
@@ -4511,26 +4902,6 @@ var OneAuthClient = class {
4511
4902
  }
4512
4903
  return this.fetchSigningResult(requestId);
4513
4904
  }
4514
- /**
4515
- * Fetch passkeys for a user from the auth provider.
4516
- *
4517
- * The account address is the sole identity; the backend `resolveUserWhere`
4518
- * accepts an address as a globally-unique path identifier.
4519
- */
4520
- async getPasskeys(accountAddress) {
4521
- const response = await fetch(
4522
- `${this.config.providerUrl}/api/users/${encodeURIComponent(accountAddress)}/passkeys`,
4523
- {
4524
- headers: this.config.clientId ? { "x-client-id": this.config.clientId } : {}
4525
- }
4526
- );
4527
- if (!response.ok) {
4528
- const errorData = await response.json().catch(() => ({}));
4529
- throw new Error(errorData.error || errorData.message || "Failed to fetch passkeys");
4530
- }
4531
- const data = await response.json();
4532
- return data.passkeys;
4533
- }
4534
4905
  /**
4535
4906
  * Register a signing request with the passkey service and receive a
4536
4907
  * short-lived `requestId`.
@@ -4917,9 +5288,6 @@ var OneAuthClient = class {
4917
5288
  } else if (event.data?.type === "PASSKEY_READY" && !revealed && readyFailsafe === void 0) {
4918
5289
  readyFailsafe = setTimeout(revealIframe, 1e3);
4919
5290
  }
4920
- if (event.data?.type === "PASSKEY_DISCONNECT") {
4921
- localStorage.removeItem("1auth-user");
4922
- }
4923
5291
  };
4924
5292
  window.addEventListener("message", handleMessage);
4925
5293
  const iframeUrl = new URL(url, window.location.href);
@@ -4951,6 +5319,27 @@ var OneAuthClient = class {
4951
5319
  iframe.style.opacity = "1";
4952
5320
  overlay.style.display = "none";
4953
5321
  };
5322
+ const RESTORE_FRAME_BUDGET = 18;
5323
+ const holdScroll = (target) => {
5324
+ let frames = 0;
5325
+ const tick = () => {
5326
+ if (window.scrollY !== target) {
5327
+ window.scrollTo({ top: target, left: window.scrollX, behavior: "auto" });
5328
+ }
5329
+ if (++frames < RESTORE_FRAME_BUDGET) requestAnimationFrame(tick);
5330
+ };
5331
+ tick();
5332
+ };
5333
+ let scrollBeforeBlur = null;
5334
+ const onHostBlur = () => {
5335
+ if (dialog.open) scrollBeforeBlur = window.scrollY;
5336
+ };
5337
+ const onHostFocus = () => {
5338
+ if (!dialog.open || scrollBeforeBlur === null) return;
5339
+ holdScroll(scrollBeforeBlur);
5340
+ };
5341
+ window.addEventListener("blur", onHostBlur);
5342
+ window.addEventListener("focus", onHostFocus);
4954
5343
  if (options?.hidden) {
4955
5344
  dialog.show();
4956
5345
  } else {
@@ -4965,7 +5354,10 @@ var OneAuthClient = class {
4965
5354
  inertObserver.disconnect();
4966
5355
  viewportInfoCleanup();
4967
5356
  window.removeEventListener("message", handleMessage);
5357
+ window.removeEventListener("blur", onHostBlur);
5358
+ window.removeEventListener("focus", onHostFocus);
4968
5359
  document.removeEventListener("keydown", handleEscape);
5360
+ const scrollAtClose = !options?.hidden && dialog.open ? window.scrollY : null;
4969
5361
  dialog.close();
4970
5362
  if (dialog.parentNode) {
4971
5363
  for (const sibling of Array.from(dialog.parentNode.children)) {
@@ -4975,9 +5367,13 @@ var OneAuthClient = class {
4975
5367
  }
4976
5368
  }
4977
5369
  dialog.remove();
5370
+ if (scrollAtClose !== null) holdScroll(scrollAtClose);
4978
5371
  };
4979
5372
  const cleanup = options?.persistent ? () => {
4980
- if (dialog.open) dialog.close();
5373
+ if (!dialog.open) return;
5374
+ const scrollAtClose = options?.hidden ? null : window.scrollY;
5375
+ dialog.close();
5376
+ if (scrollAtClose !== null) holdScroll(scrollAtClose);
4981
5377
  } : destroy;
4982
5378
  return { dialog, iframe, cleanup, destroy, reveal };
4983
5379
  }
@@ -5075,57 +5471,73 @@ var OneAuthClient = class {
5075
5471
  */
5076
5472
  waitForPopupAuthResponse(url) {
5077
5473
  const dialogOrigin = this.getDialogOrigin();
5474
+ const modalNonce = generateModalNonce();
5078
5475
  const popup = this.openPopup(url);
5079
- return new Promise((resolve) => {
5080
- const pollTimer = setInterval(() => {
5081
- if (popup?.closed) {
5082
- clearInterval(pollTimer);
5083
- window.removeEventListener("message", handleMessage);
5084
- resolve({
5085
- success: false,
5086
- error: {
5087
- code: "USER_CANCELLED",
5088
- message: "Authentication was cancelled"
5089
- }
5090
- });
5476
+ if (!popup) {
5477
+ return Promise.resolve({
5478
+ success: false,
5479
+ error: {
5480
+ code: "USER_CANCELLED",
5481
+ message: "Authentication was cancelled"
5091
5482
  }
5092
- }, 500);
5483
+ });
5484
+ }
5485
+ return new Promise((resolve) => {
5486
+ let settled = false;
5093
5487
  const handleMessage = (event) => {
5094
- if (event.origin !== dialogOrigin) return;
5488
+ if (event.origin !== dialogOrigin || event.source !== popup) return;
5095
5489
  const data = event.data;
5490
+ if (data?.type === "PASSKEY_READY") {
5491
+ popup.postMessage({
5492
+ type: "PASSKEY_INIT",
5493
+ mode: "popup",
5494
+ fullViewport: true,
5495
+ modalNonce
5496
+ }, dialogOrigin);
5497
+ return;
5498
+ }
5096
5499
  if (data?.type === "PASSKEY_LOGIN_RESULT") {
5097
- clearInterval(pollTimer);
5098
- window.removeEventListener("message", handleMessage);
5099
- popup?.close();
5100
- if (data.success) {
5101
- resolve({
5500
+ finish(
5501
+ data.success ? {
5102
5502
  success: true,
5103
5503
  user: {
5104
5504
  id: data.data?.user?.id,
5105
5505
  address: data.data?.address
5106
5506
  },
5107
5507
  signerType: data.data?.signerType ?? "passkey"
5108
- });
5109
- } else {
5110
- resolve({
5111
- success: false,
5112
- error: data.error
5113
- });
5114
- }
5508
+ } : { success: false, error: data.error },
5509
+ true
5510
+ );
5115
5511
  } else if (data?.type === "PASSKEY_CLOSE") {
5116
- clearInterval(pollTimer);
5117
- window.removeEventListener("message", handleMessage);
5118
- popup?.close();
5119
- resolve({
5512
+ finish({
5120
5513
  success: false,
5121
5514
  error: {
5122
5515
  code: "USER_CANCELLED",
5123
5516
  message: "Authentication was cancelled"
5124
5517
  }
5125
- });
5518
+ }, true);
5126
5519
  }
5127
5520
  };
5521
+ const finish = (result, closePopup) => {
5522
+ if (settled) return;
5523
+ settled = true;
5524
+ clearInterval(pollTimer);
5525
+ window.removeEventListener("message", handleMessage);
5526
+ if (closePopup) popup.close();
5527
+ resolve(result);
5528
+ };
5128
5529
  window.addEventListener("message", handleMessage);
5530
+ const pollTimer = setInterval(() => {
5531
+ if (popup.closed) {
5532
+ finish({
5533
+ success: false,
5534
+ error: {
5535
+ code: "USER_CANCELLED",
5536
+ message: "Authentication was cancelled"
5537
+ }
5538
+ }, false);
5539
+ }
5540
+ }, 500);
5129
5541
  });
5130
5542
  }
5131
5543
  /**
@@ -5331,6 +5743,16 @@ var OneAuthClient = class {
5331
5743
  if (event.origin !== dialogOrigin) return;
5332
5744
  const message = event.data;
5333
5745
  const payload = message?.data;
5746
+ if (message?.type === "PASSKEY_DISCONNECT") {
5747
+ window.removeEventListener("message", handleMessage);
5748
+ cleanup();
5749
+ resolve({
5750
+ success: false,
5751
+ requestId,
5752
+ error: { code: "USER_REJECTED", message: "Session disconnected" }
5753
+ });
5754
+ return;
5755
+ }
5334
5756
  if (message?.type === "PASSKEY_SIGNING_RESULT" && payload?.requestId === requestId) {
5335
5757
  window.removeEventListener("message", handleMessage);
5336
5758
  cleanup();
@@ -5344,7 +5766,7 @@ var OneAuthClient = class {
5344
5766
  resolve({
5345
5767
  success: false,
5346
5768
  requestId,
5347
- error: message.error
5769
+ error: parseSigningResultError(message.error)
5348
5770
  });
5349
5771
  }
5350
5772
  } else if (message?.type === "PASSKEY_CLOSE") {
@@ -5401,6 +5823,17 @@ var OneAuthClient = class {
5401
5823
  }
5402
5824
  const message = event.data;
5403
5825
  const payload = message?.data;
5826
+ if (message?.type === "PASSKEY_DISCONNECT") {
5827
+ clearInterval(checkClosed);
5828
+ window.removeEventListener("message", handleMessage);
5829
+ popup.close();
5830
+ resolve({
5831
+ success: false,
5832
+ requestId,
5833
+ error: { code: "USER_REJECTED", message: "Session disconnected" }
5834
+ });
5835
+ return;
5836
+ }
5404
5837
  if (message?.type === "PASSKEY_SIGNING_RESULT" && payload?.requestId === requestId) {
5405
5838
  clearInterval(checkClosed);
5406
5839
  window.removeEventListener("message", handleMessage);
@@ -5415,7 +5848,7 @@ var OneAuthClient = class {
5415
5848
  resolve({
5416
5849
  success: false,
5417
5850
  requestId,
5418
- error: message.error
5851
+ error: parseSigningResultError(message.error)
5419
5852
  });
5420
5853
  }
5421
5854
  }
@@ -5459,13 +5892,16 @@ var OneAuthClient = class {
5459
5892
  signature: data.signature
5460
5893
  };
5461
5894
  }
5462
- const errorCode = data.error?.code || "UNKNOWN";
5895
+ const error = parseSigningResultError(
5896
+ data.error,
5897
+ data.status === "EXPIRED" ? "EXPIRED" : "UNKNOWN",
5898
+ `Request status: ${data.status}`
5899
+ );
5463
5900
  return {
5464
5901
  success: false,
5465
5902
  requestId,
5466
5903
  error: {
5467
- code: errorCode,
5468
- message: data.error?.message || `Request status: ${data.status}`
5904
+ ...error
5469
5905
  }
5470
5906
  };
5471
5907
  }
@@ -5633,6 +6069,13 @@ function createOneAuthProvider(options) {
5633
6069
  if (typeof window === "undefined") return;
5634
6070
  localStorage.removeItem(storageKey);
5635
6071
  };
6072
+ const forgetSession = () => {
6073
+ sessionOverride = void 0;
6074
+ clearStoredUser();
6075
+ emit("accountsChanged", []);
6076
+ emit("disconnect");
6077
+ };
6078
+ if (client) registerSessionForgetHandler(client, forgetSession);
5636
6079
  const connect = async () => {
5637
6080
  const stored = getStoredUser();
5638
6081
  if (stored) {
@@ -5653,17 +6096,11 @@ function createOneAuthProvider(options) {
5653
6096
  return [address];
5654
6097
  };
5655
6098
  const disconnect = async () => {
5656
- sessionOverride = void 0;
5657
- clearStoredUser();
5658
- emit("accountsChanged", []);
5659
- emit("disconnect");
6099
+ forgetSession();
5660
6100
  };
5661
6101
  const setSession = (session) => {
5662
6102
  if (!session) {
5663
- sessionOverride = void 0;
5664
- clearStoredUser();
5665
- emit("accountsChanged", []);
5666
- emit("disconnect");
6103
+ forgetSession();
5667
6104
  return;
5668
6105
  }
5669
6106
  sessionOverride = {
@@ -5786,8 +6223,11 @@ function createOneAuthProvider(options) {
5786
6223
  accountAddress: user.address,
5787
6224
  message
5788
6225
  });
5789
- if (!result.success || !result.signature) {
5790
- throw new Error(result.error?.message || "Signing failed");
6226
+ if (!result.success) {
6227
+ throw toOneAuthError(result.error, "Signing failed", "SIGNING_FAILED");
6228
+ }
6229
+ if (!result.signature) {
6230
+ throw toOneAuthError(void 0, "No signature received", "SIGNING_FAILED");
5791
6231
  }
5792
6232
  return encodeWebAuthnSignature(result.signature);
5793
6233
  };
@@ -5804,8 +6244,11 @@ function createOneAuthProvider(options) {
5804
6244
  primaryType: data.primaryType,
5805
6245
  message: data.message
5806
6246
  });
5807
- if (!result.success || !result.signature) {
5808
- throw new Error(result.error?.message || "Signing failed");
6247
+ if (!result.success) {
6248
+ throw toOneAuthError(result.error, "Signing failed", "SIGNING_FAILED");
6249
+ }
6250
+ if (!result.signature) {
6251
+ throw toOneAuthError(void 0, "No signature received", "SIGNING_FAILED");
5809
6252
  }
5810
6253
  return encodeWebAuthnSignature(result.signature);
5811
6254
  };
@@ -5827,7 +6270,7 @@ function createOneAuthProvider(options) {
5827
6270
  hashIntervalMs: options.hashIntervalMs
5828
6271
  });
5829
6272
  if (!result.success) {
5830
- throw new Error(result.error?.message || "Transaction failed");
6273
+ throw toOneAuthError(result.error, "Transaction failed", "INTENT_FAILED");
5831
6274
  }
5832
6275
  return result.intentId;
5833
6276
  };
@@ -6253,8 +6696,11 @@ function createPasskeyAccount(client, params) {
6253
6696
  accountAddress: address,
6254
6697
  message: normalizeMessage(message)
6255
6698
  });
6256
- if (!result.success || !result.signature) {
6257
- throw new Error(result.error?.message || "Signing failed");
6699
+ if (!result.success) {
6700
+ throw toOneAuthError(result.error, "Signing failed", "SIGNING_FAILED");
6701
+ }
6702
+ if (!result.signature) {
6703
+ throw toOneAuthError(void 0, "No signature received", "SIGNING_FAILED");
6258
6704
  }
6259
6705
  return encodeWebAuthnSignature(result.signature);
6260
6706
  },
@@ -6291,8 +6737,11 @@ function createPasskeyAccount(client, params) {
6291
6737
  primaryType: typedData.primaryType,
6292
6738
  message: typedData.message
6293
6739
  });
6294
- if (!result.success || !result.signature) {
6295
- throw new Error(result.error?.message || "Signing failed");
6740
+ if (!result.success) {
6741
+ throw toOneAuthError(result.error, "Signing failed", "SIGNING_FAILED");
6742
+ }
6743
+ if (!result.signature) {
6744
+ throw toOneAuthError(void 0, "No signature received", "SIGNING_FAILED");
6296
6745
  }
6297
6746
  return encodeWebAuthnSignature(result.signature);
6298
6747
  }
@@ -6330,10 +6779,10 @@ function createPasskeyWalletClient(config) {
6330
6779
  description: "Sign message"
6331
6780
  });
6332
6781
  if (!result.success) {
6333
- throw new Error(result.error?.message || "Signing failed");
6782
+ throw toOneAuthError(result.error, "Signing failed", "SIGNING_FAILED");
6334
6783
  }
6335
6784
  if (!result.signature) {
6336
- throw new Error("No signature received");
6785
+ throw toOneAuthError(void 0, "No signature received", "SIGNING_FAILED");
6337
6786
  }
6338
6787
  return encodeWebAuthnSignature(result.signature);
6339
6788
  };
@@ -6353,10 +6802,10 @@ function createPasskeyWalletClient(config) {
6353
6802
  transaction: buildTransactionReview(calls)
6354
6803
  });
6355
6804
  if (!result.success) {
6356
- throw new Error(result.error?.message || "Signing failed");
6805
+ throw toOneAuthError(result.error, "Signing failed", "SIGNING_FAILED");
6357
6806
  }
6358
6807
  if (!result.signature) {
6359
- throw new Error("No signature received");
6808
+ throw toOneAuthError(void 0, "No signature received", "SIGNING_FAILED");
6360
6809
  }
6361
6810
  return encodeWebAuthnSignature(result.signature);
6362
6811
  };
@@ -6377,10 +6826,10 @@ function createPasskeyWalletClient(config) {
6377
6826
  }
6378
6827
  });
6379
6828
  if (!result.success) {
6380
- throw new Error(result.error?.message || "Signing failed");
6829
+ throw toOneAuthError(result.error, "Signing failed", "SIGNING_FAILED");
6381
6830
  }
6382
6831
  if (!result.signature) {
6383
- throw new Error("No signature received");
6832
+ throw toOneAuthError(void 0, "No signature received", "SIGNING_FAILED");
6384
6833
  }
6385
6834
  return encodeWebAuthnSignature(result.signature);
6386
6835
  };
@@ -6432,8 +6881,11 @@ function createPasskeyWalletClient(config) {
6432
6881
  hashTimeoutMs: config.hashTimeoutMs,
6433
6882
  hashIntervalMs: config.hashIntervalMs
6434
6883
  });
6435
- if (!result.success || !result.transactionHash) {
6436
- throw new Error(result.error?.message || "Transaction failed");
6884
+ if (!result.success) {
6885
+ throw toOneAuthError(result.error, "Transaction failed", "INTENT_FAILED");
6886
+ }
6887
+ if (!result.transactionHash) {
6888
+ throw toOneAuthError(void 0, "No transaction hash received", "HASH_UNAVAILABLE");
6437
6889
  }
6438
6890
  return result.transactionHash;
6439
6891
  },
@@ -6452,8 +6904,11 @@ function createPasskeyWalletClient(config) {
6452
6904
  hashTimeoutMs: config.hashTimeoutMs,
6453
6905
  hashIntervalMs: config.hashIntervalMs
6454
6906
  });
6455
- if (!result.success || !result.transactionHash) {
6456
- throw new Error(result.error?.message || "Transaction failed");
6907
+ if (!result.success) {
6908
+ throw toOneAuthError(result.error, "Transaction failed", "INTENT_FAILED");
6909
+ }
6910
+ if (!result.transactionHash) {
6911
+ throw toOneAuthError(void 0, "No transaction hash received", "HASH_UNAVAILABLE");
6457
6912
  }
6458
6913
  return result.transactionHash;
6459
6914
  }
@@ -6932,6 +7387,8 @@ function verifyMessageHash(message, signedHash) {
6932
7387
  BatchQueueWidget,
6933
7388
  ETHEREUM_MESSAGE_PREFIX,
6934
7389
  OneAuthClient,
7390
+ OneAuthError,
7391
+ SIGNING_ERROR_CODES,
6935
7392
  createCrossChainPermission,
6936
7393
  createOneAuthConnection,
6937
7394
  createOneAuthProvider,
@@ -6953,6 +7410,7 @@ function verifyMessageHash(message, signedHash) {
6953
7410
  getTokenSymbol,
6954
7411
  hashCalls,
6955
7412
  hashMessage,
7413
+ isSigningErrorCode,
6956
7414
  isTestnet,
6957
7415
  isTokenAddressSupported,
6958
7416
  resolveTokenAddress,