@rhinestone/1auth 0.6.4 → 0.6.7
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/{chunk-IP2FG4WQ.mjs → chunk-SXISYG2P.mjs} +10 -24
- package/dist/chunk-SXISYG2P.mjs.map +1 -0
- package/dist/{client-hZxAAhcl.d.mts → client-BrMrhetG.d.mts} +407 -71
- package/dist/{client-hZxAAhcl.d.ts → client-BrMrhetG.d.ts} +407 -71
- package/dist/index.d.mts +114 -9
- package/dist/index.d.ts +114 -9
- package/dist/index.js +434 -122
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +426 -100
- package/dist/index.mjs.map +1 -1
- package/dist/provider-CDl9wYEc.d.mts +88 -0
- package/dist/provider-Dgv533YQ.d.ts +88 -0
- package/dist/react.d.mts +33 -15
- package/dist/react.d.ts +33 -15
- package/dist/react.js +6 -23
- package/dist/react.js.map +1 -1
- package/dist/react.mjs +6 -23
- package/dist/react.mjs.map +1 -1
- package/dist/wagmi.d.mts +39 -3
- package/dist/wagmi.d.ts +39 -3
- package/dist/wagmi.js +107 -25
- package/dist/wagmi.js.map +1 -1
- package/dist/wagmi.mjs +99 -3
- package/dist/wagmi.mjs.map +1 -1
- package/package.json +1 -6
- package/dist/chunk-IP2FG4WQ.mjs.map +0 -1
- package/dist/provider-A89sCgGr.d.ts +0 -27
- package/dist/provider-B9GKBMC5.d.mts +0 -27
- package/dist/server.d.mts +0 -44
- package/dist/server.d.ts +0 -44
- package/dist/server.js +0 -145
- package/dist/server.js.map +0 -1
- package/dist/server.mjs +0 -119
- package/dist/server.mjs.map +0 -1
package/dist/index.mjs
CHANGED
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
isTestnet,
|
|
19
19
|
isTokenAddressSupported,
|
|
20
20
|
resolveTokenAddress
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-SXISYG2P.mjs";
|
|
22
22
|
|
|
23
23
|
// src/client.ts
|
|
24
24
|
import { parseUnits, hashTypedData } from "viem";
|
|
@@ -28,6 +28,17 @@ var DEFAULT_EMBED_WIDTH = "400px";
|
|
|
28
28
|
var DEFAULT_EMBED_HEIGHT = "500px";
|
|
29
29
|
var DEFAULT_PROVIDER_URL = "https://passkey.1auth.box";
|
|
30
30
|
var OneAuthClient = class {
|
|
31
|
+
/**
|
|
32
|
+
* Create a new OneAuthClient.
|
|
33
|
+
*
|
|
34
|
+
* Normalizes the config (filling in default URLs), then immediately injects
|
|
35
|
+
* `<link rel="preconnect">` tags for the passkey domain so that DNS lookup
|
|
36
|
+
* and TLS handshake start before the first dialog is opened, shaving
|
|
37
|
+
* noticeable latency from the first user interaction.
|
|
38
|
+
*
|
|
39
|
+
* @param config - Client configuration including optional providerUrl, dialogUrl,
|
|
40
|
+
* clientId, theme, and redirect settings.
|
|
41
|
+
*/
|
|
31
42
|
constructor(config) {
|
|
32
43
|
const providerUrl = config.providerUrl || DEFAULT_PROVIDER_URL;
|
|
33
44
|
const dialogUrl = config.dialogUrl || providerUrl;
|
|
@@ -47,7 +58,16 @@ var OneAuthClient = class {
|
|
|
47
58
|
this.theme = theme;
|
|
48
59
|
}
|
|
49
60
|
/**
|
|
50
|
-
*
|
|
61
|
+
* Serialize the active theme into URL query parameters for the dialog.
|
|
62
|
+
*
|
|
63
|
+
* Merges the instance-level theme (set via constructor or `setTheme`) with any
|
|
64
|
+
* per-call override, so callers can temporarily change the appearance for a
|
|
65
|
+
* single dialog invocation without mutating shared state.
|
|
66
|
+
*
|
|
67
|
+
* @param overrideTheme - One-shot theme values that take precedence over the
|
|
68
|
+
* instance theme for this call only.
|
|
69
|
+
* @returns A URL-encoded query string (e.g. `"theme=dark&accent=%230090ff"`),
|
|
70
|
+
* or an empty string if no theme properties are set.
|
|
51
71
|
*/
|
|
52
72
|
getThemeParams(overrideTheme) {
|
|
53
73
|
const theme = { ...this.theme, ...overrideTheme };
|
|
@@ -61,15 +81,30 @@ var OneAuthClient = class {
|
|
|
61
81
|
return params.toString();
|
|
62
82
|
}
|
|
63
83
|
/**
|
|
64
|
-
*
|
|
65
|
-
*
|
|
84
|
+
* Resolve the URL of the dialog app (the Vite/Next.js frontend that renders
|
|
85
|
+
* the WebAuthn UI inside the iframe).
|
|
86
|
+
*
|
|
87
|
+
* `dialogUrl` is a separate config option to support split deployments where
|
|
88
|
+
* the API server and the dialog frontend run at different origins. Falls back
|
|
89
|
+
* to `providerUrl` when not explicitly configured — the common case.
|
|
90
|
+
*
|
|
91
|
+
* @returns The base URL used when constructing all dialog endpoint paths.
|
|
66
92
|
*/
|
|
67
93
|
getDialogUrl() {
|
|
68
94
|
return this.config.dialogUrl || this.config.providerUrl;
|
|
69
95
|
}
|
|
70
96
|
/**
|
|
71
|
-
*
|
|
72
|
-
*
|
|
97
|
+
* Extract the trusted origin used to validate incoming postMessage events.
|
|
98
|
+
*
|
|
99
|
+
* All `window.addEventListener("message", ...)` handlers in this class check
|
|
100
|
+
* `event.origin` against this value to prevent cross-origin spoofing. Wraps
|
|
101
|
+
* `getDialogUrl()` in a `new URL()` parse so that paths and query strings are
|
|
102
|
+
* stripped — only the scheme + host + port are compared.
|
|
103
|
+
*
|
|
104
|
+
* Falls back to the raw dialog URL string if URL parsing fails (e.g. during
|
|
105
|
+
* unit tests with non-standard URL formats).
|
|
106
|
+
*
|
|
107
|
+
* @returns The scheme + host + optional port of the dialog app (e.g. `"https://passkey.1auth.box"`).
|
|
73
108
|
*/
|
|
74
109
|
getDialogOrigin() {
|
|
75
110
|
const dialogUrl = this.getDialogUrl();
|
|
@@ -91,6 +126,24 @@ var OneAuthClient = class {
|
|
|
91
126
|
getClientId() {
|
|
92
127
|
return this.config.clientId;
|
|
93
128
|
}
|
|
129
|
+
/**
|
|
130
|
+
* Poll the intent status endpoint until a transaction hash appears or the
|
|
131
|
+
* intent reaches a terminal failure state.
|
|
132
|
+
*
|
|
133
|
+
* This is used after `sendIntent` resolves (with `waitForHash: true`) to
|
|
134
|
+
* continue waiting for the on-chain hash even after the dialog has been
|
|
135
|
+
* dismissed. It is intentionally separate from the in-dialog polling loop so
|
|
136
|
+
* callers that don't need the hash can skip it entirely.
|
|
137
|
+
*
|
|
138
|
+
* Errors during individual poll attempts are swallowed so that transient
|
|
139
|
+
* network issues don't abort the wait prematurely.
|
|
140
|
+
*
|
|
141
|
+
* @param intentId - The Rhinestone intent ID returned by the execute endpoint.
|
|
142
|
+
* @param options.timeoutMs - Maximum wait time in milliseconds (default 120 000).
|
|
143
|
+
* @param options.intervalMs - Time between polls in milliseconds (default 2 000).
|
|
144
|
+
* @returns The transaction hash string, or `undefined` if the deadline was
|
|
145
|
+
* reached or the intent failed/expired before a hash was produced.
|
|
146
|
+
*/
|
|
94
147
|
async waitForTransactionHash(intentId, options = {}) {
|
|
95
148
|
const timeoutMs = options.timeoutMs ?? 12e4;
|
|
96
149
|
const intervalMs = options.intervalMs ?? 2e3;
|
|
@@ -496,25 +549,7 @@ var OneAuthClient = class {
|
|
|
496
549
|
* ```
|
|
497
550
|
*/
|
|
498
551
|
async sendIntent(options) {
|
|
499
|
-
const
|
|
500
|
-
...options.signedIntent,
|
|
501
|
-
merchantId: options.signedIntent.merchantId || options.signedIntent.developerId
|
|
502
|
-
} : void 0;
|
|
503
|
-
const username = signedIntent?.username || options.username;
|
|
504
|
-
const targetChain = signedIntent?.targetChain || options.targetChain;
|
|
505
|
-
const calls = signedIntent?.calls || options.calls;
|
|
506
|
-
if (signedIntent && !signedIntent.merchantId) {
|
|
507
|
-
return {
|
|
508
|
-
success: false,
|
|
509
|
-
intentId: "",
|
|
510
|
-
status: "failed",
|
|
511
|
-
error: {
|
|
512
|
-
code: "INVALID_OPTIONS",
|
|
513
|
-
message: "Signed intent requires developerId (clientId)"
|
|
514
|
-
}
|
|
515
|
-
};
|
|
516
|
-
}
|
|
517
|
-
const accountAddress = signedIntent?.accountAddress || options.accountAddress;
|
|
552
|
+
const { username, accountAddress, targetChain, calls } = options;
|
|
518
553
|
if (!username && !accountAddress) {
|
|
519
554
|
return {
|
|
520
555
|
success: false,
|
|
@@ -522,7 +557,7 @@ var OneAuthClient = class {
|
|
|
522
557
|
status: "failed",
|
|
523
558
|
error: {
|
|
524
559
|
code: "INVALID_OPTIONS",
|
|
525
|
-
message: "Either username
|
|
560
|
+
message: "Either username or accountAddress is required"
|
|
526
561
|
}
|
|
527
562
|
};
|
|
528
563
|
}
|
|
@@ -533,7 +568,7 @@ var OneAuthClient = class {
|
|
|
533
568
|
status: "failed",
|
|
534
569
|
error: {
|
|
535
570
|
code: "INVALID_OPTIONS",
|
|
536
|
-
message: "targetChain and calls are required
|
|
571
|
+
message: "targetChain and calls are required"
|
|
537
572
|
}
|
|
538
573
|
};
|
|
539
574
|
}
|
|
@@ -542,11 +577,11 @@ var OneAuthClient = class {
|
|
|
542
577
|
amount: r.amount.toString()
|
|
543
578
|
}));
|
|
544
579
|
let prepareResponse;
|
|
545
|
-
const requestBody =
|
|
546
|
-
username
|
|
547
|
-
accountAddress
|
|
548
|
-
targetChain
|
|
549
|
-
calls
|
|
580
|
+
const requestBody = {
|
|
581
|
+
username,
|
|
582
|
+
accountAddress,
|
|
583
|
+
targetChain,
|
|
584
|
+
calls,
|
|
550
585
|
tokenRequests: serializedTokenRequests,
|
|
551
586
|
sourceAssets: options.sourceAssets,
|
|
552
587
|
sourceChainId: options.sourceChainId,
|
|
@@ -662,7 +697,6 @@ var OneAuthClient = class {
|
|
|
662
697
|
dialogOrigin,
|
|
663
698
|
// Refresh callback - called when dialog requests a quote refresh
|
|
664
699
|
async () => {
|
|
665
|
-
console.log("[SDK] Dialog requested quote refresh, re-preparing intent");
|
|
666
700
|
try {
|
|
667
701
|
const refreshResponse = await fetch(`${this.config.providerUrl}/api/intent/prepare`, {
|
|
668
702
|
method: "POST",
|
|
@@ -1044,7 +1078,6 @@ var OneAuthClient = class {
|
|
|
1044
1078
|
if (event.origin !== dialogOrigin) return;
|
|
1045
1079
|
const message = event.data;
|
|
1046
1080
|
if (message?.type === "PASSKEY_REFRESH_QUOTE") {
|
|
1047
|
-
console.log("[SDK] Batch dialog requested quote refresh, re-preparing all intents");
|
|
1048
1081
|
try {
|
|
1049
1082
|
const refreshResponse = await fetch(`${this.config.providerUrl}/api/intent/batch-prepare`, {
|
|
1050
1083
|
method: "POST",
|
|
@@ -1142,7 +1175,22 @@ var OneAuthClient = class {
|
|
|
1142
1175
|
);
|
|
1143
1176
|
}
|
|
1144
1177
|
/**
|
|
1145
|
-
*
|
|
1178
|
+
* Listen for a signing result that belongs to a specific `requestId`.
|
|
1179
|
+
*
|
|
1180
|
+
* Used by legacy server-side signing request flows (popup/embed/modal) where
|
|
1181
|
+
* the dialog was pre-loaded with a signing request created via the API. The
|
|
1182
|
+
* `requestId` filter is needed because multiple dialogs may be open or there
|
|
1183
|
+
* may be stale messages from a previous dialog in the queue.
|
|
1184
|
+
*
|
|
1185
|
+
* Resolves on `PASSKEY_SIGNING_RESULT` matching `requestId`, or on
|
|
1186
|
+
* `PASSKEY_CLOSE` (user dismissed the dialog).
|
|
1187
|
+
*
|
|
1188
|
+
* @param requestId - The signing request ID to match against incoming messages.
|
|
1189
|
+
* @param dialog - The `<dialog>` element (opened before this call) used to
|
|
1190
|
+
* `showModal()` so the dialog becomes interactive.
|
|
1191
|
+
* @param _iframe - Unused; kept for signature consistency with other wait helpers.
|
|
1192
|
+
* @param cleanup - Idempotent teardown function that closes and removes the dialog.
|
|
1193
|
+
* @returns A `SigningResult` discriminated union.
|
|
1146
1194
|
*/
|
|
1147
1195
|
waitForIntentSigningResponse(requestId, dialog, _iframe, cleanup) {
|
|
1148
1196
|
const dialogOrigin = this.getDialogOrigin();
|
|
@@ -1187,18 +1235,30 @@ var OneAuthClient = class {
|
|
|
1187
1235
|
});
|
|
1188
1236
|
}
|
|
1189
1237
|
/**
|
|
1190
|
-
*
|
|
1238
|
+
* Listen for a signing result from the currently open modal dialog.
|
|
1239
|
+
*
|
|
1240
|
+
* Unlike `waitForIntentSigningResponse`, this variant does not filter by
|
|
1241
|
+
* `requestId` because the inline intent flow (sendIntent / signMessage /
|
|
1242
|
+
* signTypedData) owns the dialog exclusively — there is no risk of collisions
|
|
1243
|
+
* from other dialogs.
|
|
1244
|
+
*
|
|
1245
|
+
* Handles two result shapes:
|
|
1246
|
+
* - New "secure flow": dialog executed the intent server-side and returns
|
|
1247
|
+
* only an `intentId` (no signature exposed to the SDK).
|
|
1248
|
+
* - Legacy flow: dialog returns a raw `WebAuthnSignature` for the SDK to
|
|
1249
|
+
* forward to the execute endpoint.
|
|
1250
|
+
*
|
|
1251
|
+
* @param dialog - The `<dialog>` element wrapping the signing iframe.
|
|
1252
|
+
* @param _iframe - Unused; kept for signature consistency with other wait helpers.
|
|
1253
|
+
* @param cleanup - Idempotent teardown that closes and removes the dialog.
|
|
1254
|
+
* @returns A `SigningResult` extended with an optional `signedHash` field
|
|
1255
|
+
* populated when the dialog performs message signing.
|
|
1191
1256
|
*/
|
|
1192
1257
|
waitForSigningResponse(dialog, _iframe, cleanup) {
|
|
1193
1258
|
const dialogOrigin = this.getDialogOrigin();
|
|
1194
|
-
console.log("[SDK] waitForSigningResponse, expecting origin:", dialogOrigin);
|
|
1195
1259
|
return new Promise((resolve) => {
|
|
1196
1260
|
const handleMessage = (event) => {
|
|
1197
|
-
|
|
1198
|
-
if (event.origin !== dialogOrigin) {
|
|
1199
|
-
console.log("[SDK] Origin mismatch, ignoring. Expected:", dialogOrigin, "Got:", event.origin);
|
|
1200
|
-
return;
|
|
1201
|
-
}
|
|
1261
|
+
if (event.origin !== dialogOrigin) return;
|
|
1202
1262
|
const message = event.data;
|
|
1203
1263
|
const payload = message?.data;
|
|
1204
1264
|
if (message?.type === "PASSKEY_SIGNING_RESULT") {
|
|
@@ -1240,17 +1300,34 @@ var OneAuthClient = class {
|
|
|
1240
1300
|
});
|
|
1241
1301
|
}
|
|
1242
1302
|
/**
|
|
1243
|
-
*
|
|
1244
|
-
*
|
|
1303
|
+
* Listen for a signing result while also handling quote-refresh requests.
|
|
1304
|
+
*
|
|
1305
|
+
* Quotes from the Rhinestone orchestrator have a short TTL (typically ~60 s).
|
|
1306
|
+
* When the user takes too long to review and the quote expires, the dialog
|
|
1307
|
+
* sends `PASSKEY_REFRESH_QUOTE`. This method intercepts that message, calls
|
|
1308
|
+
* the provided `onRefresh` callback to fetch a new quote, and replies with
|
|
1309
|
+
* either `PASSKEY_REFRESH_COMPLETE` (success) or `PASSKEY_REFRESH_ERROR`
|
|
1310
|
+
* (failure) — allowing the dialog to stay open and show the updated fees
|
|
1311
|
+
* without requiring a full restart.
|
|
1312
|
+
*
|
|
1313
|
+
* Once the user confirms or rejects, the promise resolves with the signing
|
|
1314
|
+
* result exactly as `waitForSigningResponse` would.
|
|
1315
|
+
*
|
|
1316
|
+
* @param dialog - The `<dialog>` element wrapping the signing iframe.
|
|
1317
|
+
* @param iframe - The iframe element; used to post refresh messages back.
|
|
1318
|
+
* @param cleanup - Idempotent teardown that closes and removes the dialog.
|
|
1319
|
+
* @param dialogOrigin - Trusted origin for message validation (passed in to
|
|
1320
|
+
* avoid redundant `getDialogOrigin()` calls from the hot path).
|
|
1321
|
+
* @param onRefresh - Async callback that fetches a fresh quote and returns the
|
|
1322
|
+
* updated intent fields, or `null` if the refresh failed.
|
|
1323
|
+
* @returns A `SigningResult` extended with an optional `signedHash`.
|
|
1245
1324
|
*/
|
|
1246
1325
|
waitForSigningWithRefresh(dialog, iframe, cleanup, dialogOrigin, onRefresh) {
|
|
1247
|
-
console.log("[SDK] waitForSigningWithRefresh, expecting origin:", dialogOrigin);
|
|
1248
1326
|
return new Promise((resolve) => {
|
|
1249
1327
|
const handleMessage = async (event) => {
|
|
1250
1328
|
if (event.origin !== dialogOrigin) return;
|
|
1251
1329
|
const message = event.data;
|
|
1252
1330
|
if (message?.type === "PASSKEY_REFRESH_QUOTE") {
|
|
1253
|
-
console.log("[SDK] Received quote refresh request from dialog");
|
|
1254
1331
|
const refreshedData = await onRefresh();
|
|
1255
1332
|
if (refreshedData) {
|
|
1256
1333
|
iframe.contentWindow?.postMessage({
|
|
@@ -1305,7 +1382,20 @@ var OneAuthClient = class {
|
|
|
1305
1382
|
});
|
|
1306
1383
|
}
|
|
1307
1384
|
/**
|
|
1308
|
-
* Wait for the dialog to be closed
|
|
1385
|
+
* Wait for the dialog to be explicitly closed by the user or the iframe.
|
|
1386
|
+
*
|
|
1387
|
+
* Resolves on either:
|
|
1388
|
+
* - `PASSKEY_CLOSE` postMessage from the iframe (user clicked the X button
|
|
1389
|
+
* or the dialog programmatically closed itself after showing a result).
|
|
1390
|
+
* - The native `<dialog> close` event (escape key or `dialog.close()` call).
|
|
1391
|
+
*
|
|
1392
|
+
* Calling `cleanup()` before awaiting this is safe — both resolution paths
|
|
1393
|
+
* call `cleanup()` internally but it is idempotent. The primary use case is
|
|
1394
|
+
* keeping the dialog open while the SDK polls for a transaction hash, then
|
|
1395
|
+
* showing the final success/error state before letting the user dismiss.
|
|
1396
|
+
*
|
|
1397
|
+
* @param dialog - The `<dialog>` element to watch.
|
|
1398
|
+
* @param cleanup - Idempotent teardown that closes and removes the dialog.
|
|
1309
1399
|
*/
|
|
1310
1400
|
waitForDialogClose(dialog, cleanup) {
|
|
1311
1401
|
const dialogOrigin = this.getDialogOrigin();
|
|
@@ -1329,7 +1419,17 @@ var OneAuthClient = class {
|
|
|
1329
1419
|
});
|
|
1330
1420
|
}
|
|
1331
1421
|
/**
|
|
1332
|
-
* Inject a preconnect
|
|
1422
|
+
* Inject a `<link rel="preconnect">` tag for the given URL's origin.
|
|
1423
|
+
*
|
|
1424
|
+
* Browsers use preconnect hints to resolve DNS, perform the TCP handshake,
|
|
1425
|
+
* and negotiate TLS before a resource is actually requested, reducing
|
|
1426
|
+
* time-to-first-byte when the dialog iframe loads. The tag is deduplicated —
|
|
1427
|
+
* if one already exists for the same origin it will not be added again.
|
|
1428
|
+
*
|
|
1429
|
+
* Only called in browser environments (guarded by `typeof document` in the
|
|
1430
|
+
* constructor). Invalid URLs are silently ignored.
|
|
1431
|
+
*
|
|
1432
|
+
* @param url - Any URL whose origin should be preconnected to.
|
|
1333
1433
|
*/
|
|
1334
1434
|
injectPreconnect(url) {
|
|
1335
1435
|
try {
|
|
@@ -1344,8 +1444,24 @@ var OneAuthClient = class {
|
|
|
1344
1444
|
}
|
|
1345
1445
|
}
|
|
1346
1446
|
/**
|
|
1347
|
-
* Wait for the dialog iframe to signal ready
|
|
1348
|
-
*
|
|
1447
|
+
* Wait for the dialog iframe to signal ready, but defer sending `PASSKEY_INIT`
|
|
1448
|
+
* until the caller decides the time is right.
|
|
1449
|
+
*
|
|
1450
|
+
* This is the deferred variant of `waitForDialogReady`, used by flows that run
|
|
1451
|
+
* the dialog and a background API call in parallel (the "two-phase" approach).
|
|
1452
|
+
* Rather than blocking until both the iframe is ready AND the API call is done,
|
|
1453
|
+
* this method resolves as soon as `PASSKEY_READY` arrives and returns a
|
|
1454
|
+
* `sendInit` callback. The caller invokes `sendInit` once prepare data is
|
|
1455
|
+
* available, which may happen before or after the iframe is ready.
|
|
1456
|
+
*
|
|
1457
|
+
* Timeout: if the iframe never signals ready within 10 seconds (e.g. network
|
|
1458
|
+
* error, origin mismatch), resolves with `{ ready: false }` and calls cleanup.
|
|
1459
|
+
*
|
|
1460
|
+
* @param dialog - The `<dialog>` element wrapping the iframe.
|
|
1461
|
+
* @param iframe - The iframe element that will receive `PASSKEY_INIT`.
|
|
1462
|
+
* @param cleanup - Idempotent teardown that closes and removes the dialog.
|
|
1463
|
+
* @returns `{ ready: true, sendInit }` when the iframe is ready, or
|
|
1464
|
+
* `{ ready: false }` if the dialog was closed or timed out first.
|
|
1349
1465
|
*/
|
|
1350
1466
|
waitForDialogReadyDeferred(dialog, iframe, cleanup) {
|
|
1351
1467
|
const dialogOrigin = this.getDialogOrigin();
|
|
@@ -1391,8 +1507,23 @@ var OneAuthClient = class {
|
|
|
1391
1507
|
});
|
|
1392
1508
|
}
|
|
1393
1509
|
/**
|
|
1394
|
-
*
|
|
1395
|
-
*
|
|
1510
|
+
* Call the passkey service to obtain a Rhinestone orchestrator quote for an
|
|
1511
|
+
* intent (a single target-chain transaction or swap).
|
|
1512
|
+
*
|
|
1513
|
+
* The service contacts the Rhinestone orchestrator, which returns a signed
|
|
1514
|
+
* `intentOp` structure containing the quote, fees, and a WebAuthn challenge
|
|
1515
|
+
* the user must sign to authorize execution.
|
|
1516
|
+
*
|
|
1517
|
+
* The `X-Origin-Tier` response header is forwarded to the dialog so it can
|
|
1518
|
+
* display tier-specific UI (e.g. "Free" vs "Premium" badge).
|
|
1519
|
+
*
|
|
1520
|
+
* Side effect: if the server returns "User not found", the cached user entry
|
|
1521
|
+
* is removed from `localStorage` to force re-authentication.
|
|
1522
|
+
*
|
|
1523
|
+
* @param requestBody - Serialized intent options (bigint amounts converted to
|
|
1524
|
+
* strings before this call).
|
|
1525
|
+
* @returns On success: `{ success: true, data: PrepareIntentResponse, tier }`.
|
|
1526
|
+
* On failure: `{ success: false, error: { code, message } }`.
|
|
1396
1527
|
*/
|
|
1397
1528
|
async prepareIntent(requestBody) {
|
|
1398
1529
|
try {
|
|
@@ -1428,7 +1559,21 @@ var OneAuthClient = class {
|
|
|
1428
1559
|
}
|
|
1429
1560
|
}
|
|
1430
1561
|
/**
|
|
1431
|
-
*
|
|
1562
|
+
* Call the passkey service to obtain orchestrator quotes for all intents in a
|
|
1563
|
+
* batch, returning a single shared WebAuthn challenge.
|
|
1564
|
+
*
|
|
1565
|
+
* The service prepares each intent independently and assembles a merkle tree
|
|
1566
|
+
* whose root becomes the challenge. Signing that root once authorizes every
|
|
1567
|
+
* intent in the batch. Partially-failed batches are supported: the response
|
|
1568
|
+
* includes both `intents` (succeeded) and `failedIntents` (per-intent errors),
|
|
1569
|
+
* so the dialog can still show the successful subset for signing.
|
|
1570
|
+
*
|
|
1571
|
+
* Side effect: same "User not found" localStorage cleanup as `prepareIntent`.
|
|
1572
|
+
*
|
|
1573
|
+
* @param requestBody - Serialized batch options (bigint amounts converted to
|
|
1574
|
+
* strings before this call).
|
|
1575
|
+
* @returns On success: `{ success: true, data: PrepareBatchIntentResponse, tier }`.
|
|
1576
|
+
* On failure: `{ success: false, error, failedIntents? }`.
|
|
1432
1577
|
*/
|
|
1433
1578
|
async prepareBatchIntent(requestBody) {
|
|
1434
1579
|
try {
|
|
@@ -1456,7 +1601,15 @@ var OneAuthClient = class {
|
|
|
1456
1601
|
}
|
|
1457
1602
|
}
|
|
1458
1603
|
/**
|
|
1459
|
-
*
|
|
1604
|
+
* Forward a prepare-phase error to the dialog iframe so it can display a
|
|
1605
|
+
* human-readable failure message instead of hanging on the loading state.
|
|
1606
|
+
*
|
|
1607
|
+
* The dialog listens for `PASSKEY_PREPARE_ERROR` and transitions to an error
|
|
1608
|
+
* view. The user can then dismiss the dialog, at which point
|
|
1609
|
+
* `waitForDialogClose` resolves and the SDK returns the error to the caller.
|
|
1610
|
+
*
|
|
1611
|
+
* @param iframe - The iframe element to post the error to.
|
|
1612
|
+
* @param error - Human-readable error message from the prepare response.
|
|
1460
1613
|
*/
|
|
1461
1614
|
sendPrepareError(iframe, error) {
|
|
1462
1615
|
const dialogOrigin = this.getDialogOrigin();
|
|
@@ -1639,13 +1792,6 @@ var OneAuthClient = class {
|
|
|
1639
1792
|
};
|
|
1640
1793
|
}
|
|
1641
1794
|
const toTokenAddress = toTokenResult.address;
|
|
1642
|
-
console.log("[SDK sendSwap] Token resolution:", {
|
|
1643
|
-
fromToken: options.fromToken ?? "Any",
|
|
1644
|
-
fromTokenAddress: fromTokenAddress ?? "orchestrator picks",
|
|
1645
|
-
toToken: options.toToken,
|
|
1646
|
-
toTokenAddress,
|
|
1647
|
-
targetChain: options.targetChain
|
|
1648
|
-
});
|
|
1649
1795
|
const formatTokenLabel = (token, fallback) => {
|
|
1650
1796
|
if (!token.startsWith("0x")) {
|
|
1651
1797
|
return token;
|
|
@@ -1674,16 +1820,10 @@ var OneAuthClient = class {
|
|
|
1674
1820
|
const match = getSupportedTokens(chainId).find(
|
|
1675
1821
|
(t) => t.symbol.toUpperCase() === symbol.toUpperCase()
|
|
1676
1822
|
);
|
|
1677
|
-
if (match)
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
}
|
|
1681
|
-
const decimals = getTokenDecimals(symbol, chainId);
|
|
1682
|
-
console.log(`[SDK] getTokenDecimals(${symbol}, ${chainId}) = ${decimals}`);
|
|
1683
|
-
return decimals;
|
|
1684
|
-
} catch (e) {
|
|
1823
|
+
if (match) return match.decimals;
|
|
1824
|
+
return getTokenDecimals(symbol, chainId);
|
|
1825
|
+
} catch {
|
|
1685
1826
|
const upperSymbol = symbol.toUpperCase();
|
|
1686
|
-
console.warn(`[SDK] getTokenDecimals failed for ${symbol}, using fallback`, e);
|
|
1687
1827
|
return KNOWN_DECIMALS[upperSymbol] ?? 18;
|
|
1688
1828
|
}
|
|
1689
1829
|
};
|
|
@@ -1693,13 +1833,6 @@ var OneAuthClient = class {
|
|
|
1693
1833
|
token: toTokenAddress,
|
|
1694
1834
|
amount: parseUnits(options.amount, toDecimals)
|
|
1695
1835
|
}];
|
|
1696
|
-
console.log("[SDK sendSwap] Building intent:", {
|
|
1697
|
-
isBridge,
|
|
1698
|
-
isFromNativeEth,
|
|
1699
|
-
isToNativeEth,
|
|
1700
|
-
toDecimals,
|
|
1701
|
-
tokenRequests
|
|
1702
|
-
});
|
|
1703
1836
|
const result = await this.sendIntent({
|
|
1704
1837
|
username: options.username,
|
|
1705
1838
|
targetChain: options.targetChain,
|
|
@@ -1960,6 +2093,20 @@ var OneAuthClient = class {
|
|
|
1960
2093
|
const iframe = this.createEmbed(request.requestId, embedOptions);
|
|
1961
2094
|
return this.waitForEmbedResponse(request.requestId, iframe, embedOptions);
|
|
1962
2095
|
}
|
|
2096
|
+
/**
|
|
2097
|
+
* Create and append a signing iframe to a caller-supplied container element.
|
|
2098
|
+
*
|
|
2099
|
+
* Used by the `signWithEmbed` flow where the integrator wants the signing UI
|
|
2100
|
+
* to appear inline on their page rather than in a modal overlay. The iframe
|
|
2101
|
+
* loads a pre-created signing request URL and fires `options.onReady` once
|
|
2102
|
+
* the page has loaded.
|
|
2103
|
+
*
|
|
2104
|
+
* @param requestId - The signing request ID; used to construct the iframe src
|
|
2105
|
+
* and give it a stable DOM id for later removal via `removeEmbed`.
|
|
2106
|
+
* @param options - Embed configuration including the container element,
|
|
2107
|
+
* optional dimensions, and lifecycle callbacks.
|
|
2108
|
+
* @returns The created `<iframe>` element (already appended to the container).
|
|
2109
|
+
*/
|
|
1963
2110
|
createEmbed(requestId, options) {
|
|
1964
2111
|
const dialogUrl = this.getDialogUrl();
|
|
1965
2112
|
const iframe = document.createElement("iframe");
|
|
@@ -1977,6 +2124,19 @@ var OneAuthClient = class {
|
|
|
1977
2124
|
options.container.appendChild(iframe);
|
|
1978
2125
|
return iframe;
|
|
1979
2126
|
}
|
|
2127
|
+
/**
|
|
2128
|
+
* Listen for a signing result from an embedded (inline) signing iframe.
|
|
2129
|
+
*
|
|
2130
|
+
* Matches incoming `PASSKEY_SIGNING_RESULT` messages against `requestId`
|
|
2131
|
+
* to avoid reacting to messages from other iframes on the page. On resolution
|
|
2132
|
+
* (success or failure), the iframe is removed from the DOM and
|
|
2133
|
+
* `embedOptions.onClose` is invoked.
|
|
2134
|
+
*
|
|
2135
|
+
* @param requestId - The signing request ID to match against incoming messages.
|
|
2136
|
+
* @param iframe - The embedded signing iframe.
|
|
2137
|
+
* @param embedOptions - Embed configuration; `onClose` is called after cleanup.
|
|
2138
|
+
* @returns A `SigningResult` discriminated union.
|
|
2139
|
+
*/
|
|
1980
2140
|
waitForEmbedResponse(requestId, iframe, embedOptions) {
|
|
1981
2141
|
const dialogOrigin = this.getDialogOrigin();
|
|
1982
2142
|
return new Promise((resolve) => {
|
|
@@ -2071,6 +2231,22 @@ var OneAuthClient = class {
|
|
|
2071
2231
|
const data = await response.json();
|
|
2072
2232
|
return data.passkeys;
|
|
2073
2233
|
}
|
|
2234
|
+
/**
|
|
2235
|
+
* Register a signing request with the passkey service and receive a
|
|
2236
|
+
* short-lived `requestId`.
|
|
2237
|
+
*
|
|
2238
|
+
* Used by the legacy popup, redirect, and embed flows. The passkey service
|
|
2239
|
+
* stores the challenge and metadata server-side so the dialog page can fetch
|
|
2240
|
+
* them by `requestId` without relying on URL parameters alone. This avoids
|
|
2241
|
+
* exposing potentially large challenge payloads in query strings.
|
|
2242
|
+
*
|
|
2243
|
+
* @param options - The signing options (challenge, username, description, etc.).
|
|
2244
|
+
* @param mode - How the dialog will be opened (`"popup"`, `"redirect"`, or `"embed"`).
|
|
2245
|
+
* @param redirectUrl - Only required for `"redirect"` mode; the URL the dialog
|
|
2246
|
+
* will navigate back to after signing.
|
|
2247
|
+
* @returns The created signing request with its unique `requestId`.
|
|
2248
|
+
* @throws If the API call fails.
|
|
2249
|
+
*/
|
|
2074
2250
|
async createSigningRequest(options, mode, redirectUrl) {
|
|
2075
2251
|
const response = await fetch(
|
|
2076
2252
|
`${this.config.providerUrl}/api/sign/request`,
|
|
@@ -2097,6 +2273,17 @@ var OneAuthClient = class {
|
|
|
2097
2273
|
}
|
|
2098
2274
|
return response.json();
|
|
2099
2275
|
}
|
|
2276
|
+
/**
|
|
2277
|
+
* Open a centered popup window for the signing or auth dialog.
|
|
2278
|
+
*
|
|
2279
|
+
* Positions the popup near the top of the current window (50px from the top)
|
|
2280
|
+
* and horizontally centered relative to the browser window. Uses `popup=true`
|
|
2281
|
+
* to request a minimal chrome popup (no address bar) on browsers that support
|
|
2282
|
+
* the Window Management API.
|
|
2283
|
+
*
|
|
2284
|
+
* @param url - The full URL to open in the popup.
|
|
2285
|
+
* @returns The popup `Window` reference, or `null` if the browser blocked it.
|
|
2286
|
+
*/
|
|
2100
2287
|
openPopup(url) {
|
|
2101
2288
|
const left = window.screenX + (window.outerWidth - POPUP_WIDTH) / 2;
|
|
2102
2289
|
const top = window.screenY + 50;
|
|
@@ -2107,9 +2294,24 @@ var OneAuthClient = class {
|
|
|
2107
2294
|
);
|
|
2108
2295
|
}
|
|
2109
2296
|
/**
|
|
2110
|
-
* Wait for the dialog iframe to signal ready, then send init data.
|
|
2111
|
-
*
|
|
2112
|
-
*
|
|
2297
|
+
* Wait for the dialog iframe to signal ready, then immediately send init data.
|
|
2298
|
+
*
|
|
2299
|
+
* This is the synchronous-init variant: `initMessage` is available at call
|
|
2300
|
+
* time, so it can be posted as soon as `PASSKEY_READY` arrives. Use
|
|
2301
|
+
* `waitForDialogReadyDeferred` when init data depends on an in-flight API call.
|
|
2302
|
+
*
|
|
2303
|
+
* Also handles early close (X button, escape key, backdrop click) during the
|
|
2304
|
+
* ready phase so those paths resolve cleanly without leaking event listeners.
|
|
2305
|
+
*
|
|
2306
|
+
* Timeout: resolves `false` after 10 seconds if the iframe never signals ready
|
|
2307
|
+
* (e.g. origin mismatch or network error loading the dialog app).
|
|
2308
|
+
*
|
|
2309
|
+
* @param dialog - The `<dialog>` element wrapping the iframe.
|
|
2310
|
+
* @param iframe - The iframe element that will receive `PASSKEY_INIT`.
|
|
2311
|
+
* @param cleanup - Idempotent teardown that closes and removes the dialog.
|
|
2312
|
+
* @param initMessage - The `PASSKEY_INIT` payload to send when ready.
|
|
2313
|
+
* @returns `true` if the dialog is ready and init was sent; `false` if the
|
|
2314
|
+
* dialog was closed or timed out before becoming ready.
|
|
2113
2315
|
*/
|
|
2114
2316
|
waitForDialogReady(dialog, iframe, cleanup, initMessage) {
|
|
2115
2317
|
const dialogOrigin = this.getDialogOrigin();
|
|
@@ -2152,10 +2354,33 @@ var OneAuthClient = class {
|
|
|
2152
2354
|
});
|
|
2153
2355
|
}
|
|
2154
2356
|
/**
|
|
2155
|
-
* Create a
|
|
2156
|
-
*
|
|
2157
|
-
*
|
|
2158
|
-
*
|
|
2357
|
+
* Create and open a full-viewport `<dialog>` containing a passkey iframe.
|
|
2358
|
+
*
|
|
2359
|
+
* The SDK owns only the transparent outer shell; all visible UI (backdrop,
|
|
2360
|
+
* card, animations, close button) is rendered by the passkey app inside the
|
|
2361
|
+
* iframe. This approach means design changes can be shipped server-side
|
|
2362
|
+
* without updating SDK consumers.
|
|
2363
|
+
*
|
|
2364
|
+
* Lifecycle:
|
|
2365
|
+
* 1. A themed "Loading…" overlay is injected and shown immediately while the
|
|
2366
|
+
* iframe loads, matching the exact visual structure of the passkey app's
|
|
2367
|
+
* TitleBar + IndeterminateLoader so the transition is seamless.
|
|
2368
|
+
* 2. When the iframe sends `PASSKEY_RENDERED`, the overlay fades out and
|
|
2369
|
+
* the iframe becomes fully visible.
|
|
2370
|
+
* 3. The returned `cleanup` function tears down all event listeners,
|
|
2371
|
+
* disconnects the MutationObserver, closes the `<dialog>`, and removes
|
|
2372
|
+
* it from the DOM. It is idempotent — safe to call multiple times.
|
|
2373
|
+
*
|
|
2374
|
+
* Browser quirks handled:
|
|
2375
|
+
* - The 1Password extension sets `inert` on the `<dialog>`, making it
|
|
2376
|
+
* non-interactive. A MutationObserver removes the attribute immediately.
|
|
2377
|
+
* - Password managers may also set `inert` on dialog siblings; cleanup
|
|
2378
|
+
* restores those as well.
|
|
2379
|
+
* - The iframe sandbox includes `allow-popups-to-escape-sandbox` so that
|
|
2380
|
+
* 1Password's popup UI can render outside the sandboxed context.
|
|
2381
|
+
*
|
|
2382
|
+
* @param url - The full URL (including query params) to load in the iframe.
|
|
2383
|
+
* @returns References to the dialog, iframe, and a cleanup function.
|
|
2159
2384
|
*/
|
|
2160
2385
|
createModalDialog(url) {
|
|
2161
2386
|
const dialogUrl = this.getDialogUrl();
|
|
@@ -2353,6 +2578,24 @@ var OneAuthClient = class {
|
|
|
2353
2578
|
};
|
|
2354
2579
|
return { dialog, iframe, cleanup };
|
|
2355
2580
|
}
|
|
2581
|
+
/**
|
|
2582
|
+
* Listen for the auth result from the modal dialog.
|
|
2583
|
+
*
|
|
2584
|
+
* Waits for `PASSKEY_READY` before processing any other messages to avoid
|
|
2585
|
+
* acting on stale `PASSKEY_CLOSE` events that may still be in the event queue
|
|
2586
|
+
* from a previously closed dialog.
|
|
2587
|
+
*
|
|
2588
|
+
* Also handles the `PASSKEY_RETRY_POPUP` message: sent by the dialog when a
|
|
2589
|
+
* password manager (e.g. Bitwarden) intercepts the WebAuthn call inside the
|
|
2590
|
+
* iframe. In that case the SDK seamlessly re-opens a standalone popup window,
|
|
2591
|
+
* where WebAuthn works without cross-origin iframe restrictions, and waits
|
|
2592
|
+
* for the result from there instead.
|
|
2593
|
+
*
|
|
2594
|
+
* @param _dialog - Unused; kept for signature consistency.
|
|
2595
|
+
* @param iframe - The iframe element; used to send `PASSKEY_INIT` on ready.
|
|
2596
|
+
* @param cleanup - Idempotent teardown for the modal dialog.
|
|
2597
|
+
* @returns An `AuthResult` discriminated union.
|
|
2598
|
+
*/
|
|
2356
2599
|
waitForModalAuthResponse(_dialog, iframe, cleanup) {
|
|
2357
2600
|
const dialogOrigin = this.getDialogOrigin();
|
|
2358
2601
|
return new Promise((resolve) => {
|
|
@@ -2469,6 +2712,20 @@ var OneAuthClient = class {
|
|
|
2469
2712
|
window.addEventListener("message", handleMessage);
|
|
2470
2713
|
});
|
|
2471
2714
|
}
|
|
2715
|
+
/**
|
|
2716
|
+
* Listen for the authenticate result from the modal dialog.
|
|
2717
|
+
*
|
|
2718
|
+
* The authenticate flow combines sign-in/sign-up with optional off-chain
|
|
2719
|
+
* challenge signing. The dialog sends `PASSKEY_AUTHENTICATE_RESULT` on
|
|
2720
|
+
* completion with both user details and, if a challenge was requested, the
|
|
2721
|
+
* WebAuthn signature and the hashed challenge value for server-side
|
|
2722
|
+
* verification.
|
|
2723
|
+
*
|
|
2724
|
+
* @param _dialog - Unused; kept for signature consistency.
|
|
2725
|
+
* @param _iframe - Unused; kept for signature consistency.
|
|
2726
|
+
* @param cleanup - Idempotent teardown for the modal dialog.
|
|
2727
|
+
* @returns An `AuthenticateResult` discriminated union.
|
|
2728
|
+
*/
|
|
2472
2729
|
waitForAuthenticateResponse(_dialog, _iframe, cleanup) {
|
|
2473
2730
|
const dialogOrigin = this.getDialogOrigin();
|
|
2474
2731
|
return new Promise((resolve) => {
|
|
@@ -2512,6 +2769,22 @@ var OneAuthClient = class {
|
|
|
2512
2769
|
window.addEventListener("message", handleMessage);
|
|
2513
2770
|
});
|
|
2514
2771
|
}
|
|
2772
|
+
/**
|
|
2773
|
+
* Listen for the connect result from the connect dialog.
|
|
2774
|
+
*
|
|
2775
|
+
* The connect flow is a lightweight "are you still you?" confirmation that
|
|
2776
|
+
* does not require a new passkey ceremony. On success, the dialog returns the
|
|
2777
|
+
* user's username, address, and an `autoConnected` flag indicating whether the
|
|
2778
|
+
* user had previously enabled auto-connect (in which case no UI was shown).
|
|
2779
|
+
*
|
|
2780
|
+
* On failure with `action: "switch"`, the caller should redirect to the full
|
|
2781
|
+
* auth flow because the user has no cached session to confirm.
|
|
2782
|
+
*
|
|
2783
|
+
* @param _dialog - Unused; kept for signature consistency.
|
|
2784
|
+
* @param _iframe - Unused; kept for signature consistency.
|
|
2785
|
+
* @param cleanup - Idempotent teardown for the modal dialog.
|
|
2786
|
+
* @returns A `ConnectResult` discriminated union.
|
|
2787
|
+
*/
|
|
2515
2788
|
waitForConnectResponse(_dialog, _iframe, cleanup) {
|
|
2516
2789
|
const dialogOrigin = this.getDialogOrigin();
|
|
2517
2790
|
return new Promise((resolve) => {
|
|
@@ -2553,6 +2826,23 @@ var OneAuthClient = class {
|
|
|
2553
2826
|
window.addEventListener("message", handleMessage);
|
|
2554
2827
|
});
|
|
2555
2828
|
}
|
|
2829
|
+
/**
|
|
2830
|
+
* Listen for the consent result from the consent dialog.
|
|
2831
|
+
*
|
|
2832
|
+
* The consent dialog shows the user which data fields an app is requesting
|
|
2833
|
+
* access to and lets them approve or deny. On approval, `data` contains the
|
|
2834
|
+
* consented field values (e.g. email address, device names) and `grantedAt`
|
|
2835
|
+
* records when consent was given.
|
|
2836
|
+
*
|
|
2837
|
+
* A `PASSKEY_CLOSE` without a prior `PASSKEY_CONSENT_RESULT` is treated as an
|
|
2838
|
+
* explicit user cancellation (distinct from denial, though both yield
|
|
2839
|
+
* `success: false`).
|
|
2840
|
+
*
|
|
2841
|
+
* @param _dialog - Unused; kept for signature consistency.
|
|
2842
|
+
* @param _iframe - Unused; kept for signature consistency.
|
|
2843
|
+
* @param cleanup - Idempotent teardown for the modal dialog.
|
|
2844
|
+
* @returns A `RequestConsentResult` discriminated union.
|
|
2845
|
+
*/
|
|
2556
2846
|
waitForConsentResponse(_dialog, _iframe, cleanup) {
|
|
2557
2847
|
const dialogOrigin = this.getDialogOrigin();
|
|
2558
2848
|
return new Promise((resolve) => {
|
|
@@ -2592,6 +2882,20 @@ var OneAuthClient = class {
|
|
|
2592
2882
|
window.addEventListener("message", handleMessage);
|
|
2593
2883
|
});
|
|
2594
2884
|
}
|
|
2885
|
+
/**
|
|
2886
|
+
* Listen for a signing result from a server-request-based modal dialog.
|
|
2887
|
+
*
|
|
2888
|
+
* Similar to `waitForIntentSigningResponse` but intended for the older
|
|
2889
|
+
* `signWithModal` path that pre-creates a signing request via the API (rather
|
|
2890
|
+
* than inlining all data in `PASSKEY_INIT`). Filters by `requestId` to handle
|
|
2891
|
+
* the case where stale messages from a previous dialog may still be in flight.
|
|
2892
|
+
*
|
|
2893
|
+
* @param requestId - The signing request ID to match against incoming messages.
|
|
2894
|
+
* @param _dialog - Unused; kept for signature consistency.
|
|
2895
|
+
* @param _iframe - Unused; kept for signature consistency.
|
|
2896
|
+
* @param cleanup - Idempotent teardown that closes and removes the dialog.
|
|
2897
|
+
* @returns A `SigningResult` discriminated union.
|
|
2898
|
+
*/
|
|
2595
2899
|
waitForModalSigningResponse(requestId, _dialog, _iframe, cleanup) {
|
|
2596
2900
|
const dialogOrigin = this.getDialogOrigin();
|
|
2597
2901
|
return new Promise((resolve) => {
|
|
@@ -2631,6 +2935,21 @@ var OneAuthClient = class {
|
|
|
2631
2935
|
window.addEventListener("message", handleMessage);
|
|
2632
2936
|
});
|
|
2633
2937
|
}
|
|
2938
|
+
/**
|
|
2939
|
+
* Listen for a signing result from a popup window.
|
|
2940
|
+
*
|
|
2941
|
+
* Polls for popup closure every 500 ms as a fallback to detect when the user
|
|
2942
|
+
* closes the popup without completing the signing flow (no `PASSKEY_CLOSE`
|
|
2943
|
+
* message is fired in that case because the popup's unload event cannot
|
|
2944
|
+
* reliably postMessage to the opener on all browsers).
|
|
2945
|
+
*
|
|
2946
|
+
* On success or cancellation, the popup is programmatically closed and the
|
|
2947
|
+
* interval is cleared.
|
|
2948
|
+
*
|
|
2949
|
+
* @param requestId - The signing request ID to match against incoming messages.
|
|
2950
|
+
* @param popup - The popup `Window` reference returned by `openPopup`.
|
|
2951
|
+
* @returns A `SigningResult` discriminated union.
|
|
2952
|
+
*/
|
|
2634
2953
|
waitForPopupResponse(requestId, popup) {
|
|
2635
2954
|
const dialogOrigin = this.getDialogOrigin();
|
|
2636
2955
|
return new Promise((resolve) => {
|
|
@@ -2676,6 +2995,17 @@ var OneAuthClient = class {
|
|
|
2676
2995
|
window.addEventListener("message", handleMessage);
|
|
2677
2996
|
});
|
|
2678
2997
|
}
|
|
2998
|
+
/**
|
|
2999
|
+
* Fetch the completed signing result from the passkey service by request ID.
|
|
3000
|
+
*
|
|
3001
|
+
* Used by the redirect flow: after the passkey service redirects back to
|
|
3002
|
+
* `redirectUrl`, the integrator calls `handleRedirectCallback()`, which
|
|
3003
|
+
* extracts `requestId` from the URL query params and delegates here to
|
|
3004
|
+
* retrieve the full signature from the server.
|
|
3005
|
+
*
|
|
3006
|
+
* @param requestId - The signing request ID from the redirect callback URL.
|
|
3007
|
+
* @returns A `SigningResult` discriminated union.
|
|
3008
|
+
*/
|
|
2679
3009
|
async fetchSigningResult(requestId) {
|
|
2680
3010
|
const response = await fetch(
|
|
2681
3011
|
`${this.config.providerUrl}/api/sign/request/${requestId}`,
|
|
@@ -2760,6 +3090,7 @@ function createPasskeyAccount(client, params) {
|
|
|
2760
3090
|
const domain = {
|
|
2761
3091
|
name: domainInput.name,
|
|
2762
3092
|
version: domainInput.version,
|
|
3093
|
+
// viem uses bigint for chainId in typed data; the passkey service expects number
|
|
2763
3094
|
chainId: typeof domainInput.chainId === "bigint" ? Number(domainInput.chainId) : domainInput.chainId,
|
|
2764
3095
|
verifyingContract: domainInput.verifyingContract,
|
|
2765
3096
|
salt: domainInput.salt
|
|
@@ -2798,6 +3129,7 @@ import {
|
|
|
2798
3129
|
} from "viem";
|
|
2799
3130
|
import { toAccount as toAccount2 } from "viem/accounts";
|
|
2800
3131
|
function createPasskeyWalletClient(config) {
|
|
3132
|
+
const resolvedUsername = config.username ?? config.accountAddress;
|
|
2801
3133
|
const provider = new OneAuthClient({
|
|
2802
3134
|
providerUrl: config.providerUrl,
|
|
2803
3135
|
clientId: config.clientId,
|
|
@@ -2807,7 +3139,7 @@ function createPasskeyWalletClient(config) {
|
|
|
2807
3139
|
const hash = hashMessage(message);
|
|
2808
3140
|
const result = await provider.signWithModal({
|
|
2809
3141
|
challenge: hash,
|
|
2810
|
-
username:
|
|
3142
|
+
username: resolvedUsername,
|
|
2811
3143
|
description: "Sign message",
|
|
2812
3144
|
transaction: {
|
|
2813
3145
|
actions: [
|
|
@@ -2838,7 +3170,7 @@ function createPasskeyWalletClient(config) {
|
|
|
2838
3170
|
const hash = hashCalls(calls);
|
|
2839
3171
|
const result = await provider.signWithModal({
|
|
2840
3172
|
challenge: hash,
|
|
2841
|
-
username:
|
|
3173
|
+
username: resolvedUsername,
|
|
2842
3174
|
description: "Sign transaction",
|
|
2843
3175
|
transaction: buildTransactionReview(calls)
|
|
2844
3176
|
});
|
|
@@ -2854,7 +3186,7 @@ function createPasskeyWalletClient(config) {
|
|
|
2854
3186
|
const hash = hashTypedData2(typedData);
|
|
2855
3187
|
const result = await provider.signWithModal({
|
|
2856
3188
|
challenge: hash,
|
|
2857
|
-
username:
|
|
3189
|
+
username: resolvedUsername,
|
|
2858
3190
|
description: "Sign typed data",
|
|
2859
3191
|
transaction: {
|
|
2860
3192
|
actions: [
|
|
@@ -2874,7 +3206,7 @@ function createPasskeyWalletClient(config) {
|
|
|
2874
3206
|
}
|
|
2875
3207
|
return encodeWebAuthnSignature(result.signature);
|
|
2876
3208
|
};
|
|
2877
|
-
const buildIntentPayload = async (calls, targetChainOverride) => {
|
|
3209
|
+
const buildIntentPayload = async (calls, targetChainOverride, extra) => {
|
|
2878
3210
|
const targetChain = targetChainOverride ?? config.chain.id;
|
|
2879
3211
|
const intentCalls = calls.map((call) => ({
|
|
2880
3212
|
to: call.to,
|
|
@@ -2883,17 +3215,9 @@ function createPasskeyWalletClient(config) {
|
|
|
2883
3215
|
label: call.label,
|
|
2884
3216
|
sublabel: call.sublabel
|
|
2885
3217
|
}));
|
|
2886
|
-
if (config.signIntent) {
|
|
2887
|
-
const signedIntent = await config.signIntent({
|
|
2888
|
-
username: config.username,
|
|
2889
|
-
accountAddress: config.accountAddress,
|
|
2890
|
-
targetChain,
|
|
2891
|
-
calls: intentCalls
|
|
2892
|
-
});
|
|
2893
|
-
return { signedIntent };
|
|
2894
|
-
}
|
|
2895
3218
|
return {
|
|
2896
|
-
username:
|
|
3219
|
+
username: resolvedUsername,
|
|
3220
|
+
accountAddress: config.accountAddress,
|
|
2897
3221
|
targetChain,
|
|
2898
3222
|
calls: intentCalls
|
|
2899
3223
|
};
|
|
@@ -2940,12 +3264,14 @@ function createPasskeyWalletClient(config) {
|
|
|
2940
3264
|
* Send multiple calls as a single batched transaction
|
|
2941
3265
|
*/
|
|
2942
3266
|
async sendCalls(params) {
|
|
2943
|
-
const { calls, chainId: targetChain, tokenRequests } = params;
|
|
3267
|
+
const { calls, chainId: targetChain, tokenRequests, sourceAssets, sourceChainId } = params;
|
|
2944
3268
|
const closeOn = config.waitForHash ?? true ? "completed" : "preconfirmed";
|
|
2945
|
-
const intentPayload = await buildIntentPayload(calls, targetChain);
|
|
3269
|
+
const intentPayload = await buildIntentPayload(calls, targetChain, { tokenRequests, sourceAssets });
|
|
2946
3270
|
const result = await provider.sendIntent({
|
|
2947
3271
|
...intentPayload,
|
|
2948
3272
|
tokenRequests,
|
|
3273
|
+
sourceAssets,
|
|
3274
|
+
sourceChainId,
|
|
2949
3275
|
closeOn,
|
|
2950
3276
|
waitForHash: config.waitForHash ?? true,
|
|
2951
3277
|
hashTimeoutMs: config.hashTimeoutMs,
|