@rhinestone/1auth 0.1.2 → 0.4.0
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-TACK3LJN.mjs → chunk-X73ALCGW.mjs} +46 -20
- package/dist/chunk-X73ALCGW.mjs.map +1 -0
- package/dist/{client-DyYGKWj3.d.mts → client-DKuPEx83.d.mts} +164 -9
- package/dist/{client-DyYGKWj3.d.ts → client-DKuPEx83.d.ts} +164 -9
- package/dist/index.d.mts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +515 -125
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +471 -107
- package/dist/index.mjs.map +1 -1
- package/dist/{provider-Ctr7HQHR.d.mts → provider-CmJarV7y.d.mts} +2 -2
- package/dist/{provider-CNTZPPFz.d.ts → provider-Dj5l4bWn.d.ts} +2 -2
- package/dist/react.d.mts +1 -1
- package/dist/react.d.ts +1 -1
- package/dist/react.js +16 -9
- package/dist/react.js.map +1 -1
- package/dist/react.mjs +16 -9
- package/dist/react.mjs.map +1 -1
- package/dist/wagmi.d.mts +2 -2
- package/dist/wagmi.d.ts +2 -2
- package/dist/wagmi.js +45 -19
- package/dist/wagmi.js.map +1 -1
- package/dist/wagmi.mjs +1 -1
- package/package.json +7 -6
- package/dist/chunk-TACK3LJN.mjs.map +0 -1
package/dist/index.mjs
CHANGED
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
isTestnet,
|
|
20
20
|
isTokenAddressSupported,
|
|
21
21
|
resolveTokenAddress
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-X73ALCGW.mjs";
|
|
23
23
|
|
|
24
24
|
// src/client.ts
|
|
25
25
|
import { parseUnits, hashTypedData } from "viem";
|
|
@@ -27,7 +27,7 @@ var POPUP_WIDTH = 450;
|
|
|
27
27
|
var POPUP_HEIGHT = 600;
|
|
28
28
|
var DEFAULT_EMBED_WIDTH = "400px";
|
|
29
29
|
var DEFAULT_EMBED_HEIGHT = "500px";
|
|
30
|
-
var MODAL_WIDTH =
|
|
30
|
+
var MODAL_WIDTH = 340;
|
|
31
31
|
var DEFAULT_PROVIDER_URL = "https://passkey.1auth.box";
|
|
32
32
|
var OneAuthClient = class {
|
|
33
33
|
constructor(config) {
|
|
@@ -35,6 +35,12 @@ var OneAuthClient = class {
|
|
|
35
35
|
const dialogUrl = config.dialogUrl || providerUrl;
|
|
36
36
|
this.config = { ...config, providerUrl, dialogUrl };
|
|
37
37
|
this.theme = this.config.theme || {};
|
|
38
|
+
if (typeof document !== "undefined") {
|
|
39
|
+
this.injectPreconnect(providerUrl);
|
|
40
|
+
if (dialogUrl !== providerUrl) {
|
|
41
|
+
this.injectPreconnect(dialogUrl);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
38
44
|
}
|
|
39
45
|
/**
|
|
40
46
|
* Update the theme configuration at runtime
|
|
@@ -189,6 +195,133 @@ var OneAuthClient = class {
|
|
|
189
195
|
}
|
|
190
196
|
return this.waitForConnectResponse(dialog, iframe, cleanup);
|
|
191
197
|
}
|
|
198
|
+
/**
|
|
199
|
+
* Check if a user has already granted consent for the requested fields.
|
|
200
|
+
* This is a read-only check — no dialog is shown.
|
|
201
|
+
*
|
|
202
|
+
* @example
|
|
203
|
+
* ```typescript
|
|
204
|
+
* const result = await client.checkConsent({
|
|
205
|
+
* username: "alice",
|
|
206
|
+
* fields: ["email"],
|
|
207
|
+
* });
|
|
208
|
+
* if (result.hasConsent) {
|
|
209
|
+
* console.log(result.data?.email);
|
|
210
|
+
* }
|
|
211
|
+
* ```
|
|
212
|
+
*/
|
|
213
|
+
async checkConsent(options) {
|
|
214
|
+
const clientId = options.clientId ?? this.config.clientId;
|
|
215
|
+
if (!clientId) {
|
|
216
|
+
return {
|
|
217
|
+
hasConsent: false
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
const username = options.username ?? options.accountAddress;
|
|
221
|
+
if (!username) {
|
|
222
|
+
return {
|
|
223
|
+
hasConsent: false
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
try {
|
|
227
|
+
const res = await fetch(`${this.config.providerUrl || "https://passkey.1auth.box"}/api/consent`, {
|
|
228
|
+
method: "POST",
|
|
229
|
+
headers: {
|
|
230
|
+
"Content-Type": "application/json",
|
|
231
|
+
...clientId ? { "x-client-id": clientId } : {}
|
|
232
|
+
},
|
|
233
|
+
body: JSON.stringify({
|
|
234
|
+
username,
|
|
235
|
+
requestedFields: options.fields,
|
|
236
|
+
clientId
|
|
237
|
+
})
|
|
238
|
+
});
|
|
239
|
+
if (!res.ok) {
|
|
240
|
+
return { hasConsent: false };
|
|
241
|
+
}
|
|
242
|
+
const data = await res.json();
|
|
243
|
+
return {
|
|
244
|
+
hasConsent: data.hasConsent ?? false,
|
|
245
|
+
data: data.data,
|
|
246
|
+
grantedAt: data.grantedAt
|
|
247
|
+
};
|
|
248
|
+
} catch {
|
|
249
|
+
return { hasConsent: false };
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Request consent from the user to share their data.
|
|
254
|
+
*
|
|
255
|
+
* First checks if consent was already granted (returns cached data immediately).
|
|
256
|
+
* If not, opens the consent dialog where the user can review and approve sharing.
|
|
257
|
+
*
|
|
258
|
+
* @example
|
|
259
|
+
* ```typescript
|
|
260
|
+
* const result = await client.requestConsent({
|
|
261
|
+
* username: "alice",
|
|
262
|
+
* fields: ["email", "deviceNames"],
|
|
263
|
+
* });
|
|
264
|
+
* if (result.success) {
|
|
265
|
+
* console.log(result.data?.email);
|
|
266
|
+
* console.log(result.cached); // true if no dialog was shown
|
|
267
|
+
* }
|
|
268
|
+
* ```
|
|
269
|
+
*/
|
|
270
|
+
async requestConsent(options) {
|
|
271
|
+
const clientId = options.clientId ?? this.config.clientId;
|
|
272
|
+
if (!clientId) {
|
|
273
|
+
return {
|
|
274
|
+
success: false,
|
|
275
|
+
error: { code: "INVALID_REQUEST", message: "clientId is required (set in config or options)" }
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
const username = options.username ?? options.accountAddress;
|
|
279
|
+
if (!username) {
|
|
280
|
+
return {
|
|
281
|
+
success: false,
|
|
282
|
+
error: { code: "INVALID_REQUEST", message: "username or accountAddress is required" }
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
if (!options.fields || options.fields.length === 0) {
|
|
286
|
+
return {
|
|
287
|
+
success: false,
|
|
288
|
+
error: { code: "INVALID_REQUEST", message: "At least one field is required" }
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
const existing = await this.checkConsent({ ...options, clientId });
|
|
292
|
+
if (existing.hasConsent && existing.data) {
|
|
293
|
+
return {
|
|
294
|
+
success: true,
|
|
295
|
+
data: existing.data,
|
|
296
|
+
grantedAt: existing.grantedAt,
|
|
297
|
+
cached: true
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
const dialogUrl = this.getDialogUrl();
|
|
301
|
+
const params = new URLSearchParams({
|
|
302
|
+
mode: "iframe",
|
|
303
|
+
username,
|
|
304
|
+
clientId,
|
|
305
|
+
fields: options.fields.join(",")
|
|
306
|
+
});
|
|
307
|
+
const themeParams = this.getThemeParams(options.theme);
|
|
308
|
+
if (themeParams) {
|
|
309
|
+
const themeParsed = new URLSearchParams(themeParams);
|
|
310
|
+
themeParsed.forEach((value, key) => params.set(key, value));
|
|
311
|
+
}
|
|
312
|
+
const url = `${dialogUrl}/dialog/consent?${params.toString()}`;
|
|
313
|
+
const { dialog, iframe, cleanup } = this.createModalDialog(url);
|
|
314
|
+
const ready = await this.waitForDialogReady(dialog, iframe, cleanup, {
|
|
315
|
+
mode: "iframe"
|
|
316
|
+
});
|
|
317
|
+
if (!ready) {
|
|
318
|
+
return {
|
|
319
|
+
success: false,
|
|
320
|
+
error: { code: "USER_CANCELLED", message: "User closed the dialog" }
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
return this.waitForConsentResponse(dialog, iframe, cleanup);
|
|
324
|
+
}
|
|
192
325
|
/**
|
|
193
326
|
* Authenticate a user with an optional challenge to sign.
|
|
194
327
|
*
|
|
@@ -316,7 +449,8 @@ var OneAuthClient = class {
|
|
|
316
449
|
}
|
|
317
450
|
};
|
|
318
451
|
}
|
|
319
|
-
|
|
452
|
+
const accountAddress = signedIntent?.accountAddress || options.accountAddress;
|
|
453
|
+
if (!username && !accountAddress) {
|
|
320
454
|
return {
|
|
321
455
|
success: false,
|
|
322
456
|
intentId: "",
|
|
@@ -345,6 +479,7 @@ var OneAuthClient = class {
|
|
|
345
479
|
let prepareResponse;
|
|
346
480
|
const requestBody = signedIntent || {
|
|
347
481
|
username: options.username,
|
|
482
|
+
accountAddress: options.accountAddress,
|
|
348
483
|
targetChain: options.targetChain,
|
|
349
484
|
calls: options.calls,
|
|
350
485
|
tokenRequests: serializedTokenRequests,
|
|
@@ -352,48 +487,35 @@ var OneAuthClient = class {
|
|
|
352
487
|
sourceChainId: options.sourceChainId,
|
|
353
488
|
...this.config.clientId && { clientId: this.config.clientId }
|
|
354
489
|
};
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
const errorData = await response.json().catch(() => ({}));
|
|
365
|
-
const errorMessage = errorData.error || "Failed to prepare intent";
|
|
366
|
-
if (errorMessage.includes("User not found")) {
|
|
367
|
-
localStorage.removeItem("1auth-user");
|
|
368
|
-
}
|
|
369
|
-
return {
|
|
370
|
-
success: false,
|
|
371
|
-
intentId: "",
|
|
372
|
-
status: "failed",
|
|
373
|
-
error: {
|
|
374
|
-
code: errorMessage.includes("User not found") ? "USER_NOT_FOUND" : "PREPARE_FAILED",
|
|
375
|
-
message: errorMessage
|
|
376
|
-
}
|
|
377
|
-
};
|
|
378
|
-
}
|
|
379
|
-
prepareResponse = await response.json();
|
|
380
|
-
} catch (error) {
|
|
490
|
+
const dialogUrl = this.getDialogUrl();
|
|
491
|
+
const themeParams = this.getThemeParams();
|
|
492
|
+
const signingUrl = `${dialogUrl}/dialog/sign?mode=iframe${themeParams ? `&${themeParams}` : ""}`;
|
|
493
|
+
const { dialog, iframe, cleanup } = this.createModalDialog(signingUrl);
|
|
494
|
+
const [prepareResult, dialogResult] = await Promise.all([
|
|
495
|
+
this.prepareIntent(requestBody),
|
|
496
|
+
this.waitForDialogReadyDeferred(dialog, iframe, cleanup)
|
|
497
|
+
]);
|
|
498
|
+
if (!dialogResult.ready) {
|
|
381
499
|
return {
|
|
382
500
|
success: false,
|
|
383
501
|
intentId: "",
|
|
384
502
|
status: "failed",
|
|
385
|
-
error: {
|
|
386
|
-
code: "NETWORK_ERROR",
|
|
387
|
-
message: error instanceof Error ? error.message : "Network error"
|
|
388
|
-
}
|
|
503
|
+
error: { code: "USER_CANCELLED", message: "User closed the dialog" }
|
|
389
504
|
};
|
|
390
505
|
}
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
506
|
+
if (!prepareResult.success) {
|
|
507
|
+
this.sendPrepareError(iframe, prepareResult.error.message);
|
|
508
|
+
await this.waitForDialogClose(dialog, cleanup);
|
|
509
|
+
return {
|
|
510
|
+
success: false,
|
|
511
|
+
intentId: "",
|
|
512
|
+
status: "failed",
|
|
513
|
+
error: prepareResult.error
|
|
514
|
+
};
|
|
515
|
+
}
|
|
516
|
+
prepareResponse = prepareResult.data;
|
|
395
517
|
const dialogOrigin = this.getDialogOrigin();
|
|
396
|
-
const
|
|
518
|
+
const initPayload = {
|
|
397
519
|
mode: "iframe",
|
|
398
520
|
calls,
|
|
399
521
|
chainId: targetChain,
|
|
@@ -405,16 +527,21 @@ var OneAuthClient = class {
|
|
|
405
527
|
tokenRequests: serializedTokenRequests,
|
|
406
528
|
expiresAt: prepareResponse.expiresAt,
|
|
407
529
|
userId: prepareResponse.userId,
|
|
408
|
-
intentOp: prepareResponse.intentOp
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
530
|
+
intentOp: prepareResponse.intentOp,
|
|
531
|
+
digestResult: prepareResponse.digestResult,
|
|
532
|
+
tier: prepareResult.tier
|
|
533
|
+
};
|
|
534
|
+
dialogResult.sendInit(initPayload);
|
|
535
|
+
const handleReReady = (event) => {
|
|
536
|
+
if (event.origin !== dialogOrigin) return;
|
|
537
|
+
if (event.data?.type === "PASSKEY_READY") {
|
|
538
|
+
iframe.contentWindow?.postMessage(
|
|
539
|
+
{ type: "PASSKEY_INIT", ...initPayload },
|
|
540
|
+
dialogOrigin
|
|
541
|
+
);
|
|
542
|
+
}
|
|
543
|
+
};
|
|
544
|
+
window.addEventListener("message", handleReReady);
|
|
418
545
|
const signingResult = await this.waitForSigningWithRefresh(
|
|
419
546
|
dialog,
|
|
420
547
|
iframe,
|
|
@@ -441,7 +568,8 @@ var OneAuthClient = class {
|
|
|
441
568
|
expiresAt: refreshedData.expiresAt,
|
|
442
569
|
challenge: refreshedData.challenge,
|
|
443
570
|
originMessages: refreshedData.originMessages,
|
|
444
|
-
transaction: refreshedData.transaction
|
|
571
|
+
transaction: refreshedData.transaction,
|
|
572
|
+
digestResult: refreshedData.digestResult
|
|
445
573
|
};
|
|
446
574
|
} catch (error) {
|
|
447
575
|
console.error("[SDK] Quote refresh error:", error);
|
|
@@ -449,6 +577,7 @@ var OneAuthClient = class {
|
|
|
449
577
|
}
|
|
450
578
|
}
|
|
451
579
|
);
|
|
580
|
+
window.removeEventListener("message", handleReReady);
|
|
452
581
|
if (!signingResult.success) {
|
|
453
582
|
return {
|
|
454
583
|
success: false,
|
|
@@ -480,6 +609,7 @@ var OneAuthClient = class {
|
|
|
480
609
|
targetChain: prepareResponse.targetChain,
|
|
481
610
|
calls: prepareResponse.calls,
|
|
482
611
|
expiresAt: prepareResponse.expiresAt,
|
|
612
|
+
digestResult: prepareResponse.digestResult,
|
|
483
613
|
// Signature from dialog
|
|
484
614
|
signature: signingResult.signature,
|
|
485
615
|
passkey: signingResult.passkey
|
|
@@ -521,10 +651,21 @@ var OneAuthClient = class {
|
|
|
521
651
|
let finalTxHash = executeResponse.transactionHash;
|
|
522
652
|
if (finalStatus === "pending") {
|
|
523
653
|
this.sendTransactionStatus(iframe, "pending");
|
|
654
|
+
let userClosedEarly = false;
|
|
655
|
+
const dialogOrigin2 = this.getDialogOrigin();
|
|
656
|
+
const earlyCloseHandler = (event) => {
|
|
657
|
+
if (event.origin !== dialogOrigin2) return;
|
|
658
|
+
if (event.data?.type === "PASSKEY_CLOSE") {
|
|
659
|
+
userClosedEarly = true;
|
|
660
|
+
cleanup();
|
|
661
|
+
}
|
|
662
|
+
};
|
|
663
|
+
window.addEventListener("message", earlyCloseHandler);
|
|
524
664
|
const maxAttempts = 120;
|
|
525
665
|
const pollIntervalMs = 1500;
|
|
526
666
|
let lastStatus = "pending";
|
|
527
667
|
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
668
|
+
if (userClosedEarly) break;
|
|
528
669
|
try {
|
|
529
670
|
const statusResponse = await fetch(
|
|
530
671
|
`${this.config.providerUrl}/api/intent/status/${executeResponse.intentId}`,
|
|
@@ -559,6 +700,21 @@ var OneAuthClient = class {
|
|
|
559
700
|
}
|
|
560
701
|
await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
|
|
561
702
|
}
|
|
703
|
+
window.removeEventListener("message", earlyCloseHandler);
|
|
704
|
+
if (userClosedEarly) {
|
|
705
|
+
cleanup();
|
|
706
|
+
return {
|
|
707
|
+
success: false,
|
|
708
|
+
intentId: executeResponse.intentId,
|
|
709
|
+
status: finalStatus,
|
|
710
|
+
transactionHash: finalTxHash,
|
|
711
|
+
operationId: executeResponse.operationId,
|
|
712
|
+
error: {
|
|
713
|
+
code: "USER_CANCELLED",
|
|
714
|
+
message: "User closed the dialog"
|
|
715
|
+
}
|
|
716
|
+
};
|
|
717
|
+
}
|
|
562
718
|
}
|
|
563
719
|
const closeOn = options.closeOn || "preconfirmed";
|
|
564
720
|
const successStatuses = {
|
|
@@ -569,8 +725,9 @@ var OneAuthClient = class {
|
|
|
569
725
|
};
|
|
570
726
|
const isSuccessStatus = successStatuses[closeOn]?.includes(finalStatus) ?? false;
|
|
571
727
|
const displayStatus = isSuccessStatus ? "confirmed" : finalStatus;
|
|
728
|
+
const closePromise = this.waitForDialogClose(dialog, cleanup);
|
|
572
729
|
this.sendTransactionStatus(iframe, displayStatus, finalTxHash);
|
|
573
|
-
await
|
|
730
|
+
await closePromise;
|
|
574
731
|
if (options.waitForHash && !finalTxHash) {
|
|
575
732
|
const hash = await this.waitForTransactionHash(executeResponse.intentId, {
|
|
576
733
|
timeoutMs: options.hashTimeoutMs,
|
|
@@ -631,7 +788,7 @@ var OneAuthClient = class {
|
|
|
631
788
|
* ```
|
|
632
789
|
*/
|
|
633
790
|
async sendBatchIntent(options) {
|
|
634
|
-
if (!options.username) {
|
|
791
|
+
if (!options.username && !options.accountAddress) {
|
|
635
792
|
return {
|
|
636
793
|
success: false,
|
|
637
794
|
results: [],
|
|
@@ -655,35 +812,24 @@ var OneAuthClient = class {
|
|
|
655
812
|
amount: r.amount.toString()
|
|
656
813
|
})),
|
|
657
814
|
sourceAssets: intent.sourceAssets,
|
|
658
|
-
sourceChainId: intent.sourceChainId
|
|
815
|
+
sourceChainId: intent.sourceChainId,
|
|
816
|
+
moduleInstall: intent.moduleInstall
|
|
659
817
|
}));
|
|
660
818
|
const requestBody = {
|
|
661
|
-
username: options.username,
|
|
819
|
+
...options.username && { username: options.username },
|
|
820
|
+
...options.accountAddress && { accountAddress: options.accountAddress },
|
|
662
821
|
intents: serializedIntents,
|
|
663
822
|
...this.config.clientId && { clientId: this.config.clientId }
|
|
664
823
|
};
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
const errorMessage = errorData.error || "Failed to prepare batch intent";
|
|
675
|
-
if (errorMessage.includes("User not found")) {
|
|
676
|
-
localStorage.removeItem("1auth-user");
|
|
677
|
-
}
|
|
678
|
-
return {
|
|
679
|
-
success: false,
|
|
680
|
-
results: [],
|
|
681
|
-
successCount: 0,
|
|
682
|
-
failureCount: 0
|
|
683
|
-
};
|
|
684
|
-
}
|
|
685
|
-
prepareResponse = await response.json();
|
|
686
|
-
} catch {
|
|
824
|
+
const dialogUrl = this.getDialogUrl();
|
|
825
|
+
const themeParams = this.getThemeParams();
|
|
826
|
+
const signingUrl = `${dialogUrl}/dialog/sign?mode=iframe${themeParams ? `&${themeParams}` : ""}`;
|
|
827
|
+
const { dialog, iframe, cleanup } = this.createModalDialog(signingUrl);
|
|
828
|
+
const [prepareResult, dialogResult] = await Promise.all([
|
|
829
|
+
this.prepareBatchIntent(requestBody),
|
|
830
|
+
this.waitForDialogReadyDeferred(dialog, iframe, cleanup)
|
|
831
|
+
]);
|
|
832
|
+
if (!dialogResult.ready) {
|
|
687
833
|
return {
|
|
688
834
|
success: false,
|
|
689
835
|
results: [],
|
|
@@ -691,29 +837,50 @@ var OneAuthClient = class {
|
|
|
691
837
|
failureCount: 0
|
|
692
838
|
};
|
|
693
839
|
}
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
840
|
+
if (!prepareResult.success) {
|
|
841
|
+
const failedIntents = prepareResult.failedIntents;
|
|
842
|
+
const failureResults = failedIntents?.map((f) => ({
|
|
843
|
+
index: f.index,
|
|
844
|
+
success: false,
|
|
845
|
+
intentId: "",
|
|
846
|
+
status: "failed",
|
|
847
|
+
error: { message: f.error, code: "PREPARE_FAILED" }
|
|
848
|
+
})) ?? [];
|
|
849
|
+
this.sendPrepareError(iframe, prepareResult.error);
|
|
850
|
+
await this.waitForDialogClose(dialog, cleanup);
|
|
851
|
+
return {
|
|
852
|
+
success: false,
|
|
853
|
+
results: failureResults,
|
|
854
|
+
successCount: 0,
|
|
855
|
+
failureCount: failureResults.length,
|
|
856
|
+
error: prepareResult.error
|
|
857
|
+
};
|
|
858
|
+
}
|
|
859
|
+
let prepareResponse = prepareResult.data;
|
|
698
860
|
const dialogOrigin = this.getDialogOrigin();
|
|
699
|
-
const
|
|
861
|
+
const batchInitPayload = {
|
|
700
862
|
mode: "iframe",
|
|
701
863
|
batchMode: true,
|
|
702
864
|
batchIntents: prepareResponse.intents,
|
|
865
|
+
batchFailedIntents: prepareResponse.failedIntents,
|
|
703
866
|
challenge: prepareResponse.challenge,
|
|
704
867
|
username: options.username,
|
|
705
868
|
accountAddress: prepareResponse.accountAddress,
|
|
706
869
|
userId: prepareResponse.userId,
|
|
707
|
-
expiresAt: prepareResponse.expiresAt
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
870
|
+
expiresAt: prepareResponse.expiresAt,
|
|
871
|
+
tier: prepareResult.tier
|
|
872
|
+
};
|
|
873
|
+
dialogResult.sendInit(batchInitPayload);
|
|
874
|
+
const handleBatchReReady = (event) => {
|
|
875
|
+
if (event.origin !== dialogOrigin) return;
|
|
876
|
+
if (event.data?.type === "PASSKEY_READY") {
|
|
877
|
+
iframe.contentWindow?.postMessage(
|
|
878
|
+
{ type: "PASSKEY_INIT", ...batchInitPayload },
|
|
879
|
+
dialogOrigin
|
|
880
|
+
);
|
|
881
|
+
}
|
|
882
|
+
};
|
|
883
|
+
window.addEventListener("message", handleBatchReReady);
|
|
717
884
|
const batchResult = await new Promise((resolve) => {
|
|
718
885
|
const handleMessage = async (event) => {
|
|
719
886
|
if (event.origin !== dialogOrigin) return;
|
|
@@ -760,13 +927,21 @@ var OneAuthClient = class {
|
|
|
760
927
|
status: r.status === "FAILED" ? "failed" : "pending",
|
|
761
928
|
error: r.error ? { code: "EXECUTE_FAILED", message: r.error } : void 0
|
|
762
929
|
}));
|
|
763
|
-
const
|
|
930
|
+
const prepareFailures = (prepareResponse.failedIntents ?? []).map((f) => ({
|
|
931
|
+
index: f.index,
|
|
932
|
+
success: false,
|
|
933
|
+
intentId: "",
|
|
934
|
+
status: "failed",
|
|
935
|
+
error: { code: "PREPARE_FAILED", message: f.error }
|
|
936
|
+
}));
|
|
937
|
+
const allResults = [...results, ...prepareFailures].sort((a, b) => a.index - b.index);
|
|
938
|
+
const successCount = allResults.filter((r) => r.success).length;
|
|
764
939
|
await this.waitForDialogClose(dialog, cleanup);
|
|
765
940
|
resolve({
|
|
766
|
-
success: successCount ===
|
|
767
|
-
results,
|
|
941
|
+
success: successCount === allResults.length,
|
|
942
|
+
results: allResults,
|
|
768
943
|
successCount,
|
|
769
|
-
failureCount:
|
|
944
|
+
failureCount: allResults.length - successCount
|
|
770
945
|
});
|
|
771
946
|
} else {
|
|
772
947
|
cleanup();
|
|
@@ -791,6 +966,7 @@ var OneAuthClient = class {
|
|
|
791
966
|
};
|
|
792
967
|
window.addEventListener("message", handleMessage);
|
|
793
968
|
});
|
|
969
|
+
window.removeEventListener("message", handleBatchReReady);
|
|
794
970
|
return batchResult;
|
|
795
971
|
}
|
|
796
972
|
/**
|
|
@@ -994,6 +1170,143 @@ var OneAuthClient = class {
|
|
|
994
1170
|
dialog.addEventListener("close", handleClose);
|
|
995
1171
|
});
|
|
996
1172
|
}
|
|
1173
|
+
/**
|
|
1174
|
+
* Inject a preconnect link tag to pre-warm DNS + TLS for a given URL.
|
|
1175
|
+
*/
|
|
1176
|
+
injectPreconnect(url) {
|
|
1177
|
+
try {
|
|
1178
|
+
const origin = new URL(url).origin;
|
|
1179
|
+
if (document.querySelector(`link[rel="preconnect"][href="${origin}"]`)) return;
|
|
1180
|
+
const link = document.createElement("link");
|
|
1181
|
+
link.rel = "preconnect";
|
|
1182
|
+
link.href = origin;
|
|
1183
|
+
link.crossOrigin = "anonymous";
|
|
1184
|
+
document.head.appendChild(link);
|
|
1185
|
+
} catch {
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
1188
|
+
/**
|
|
1189
|
+
* Wait for the dialog iframe to signal ready without sending init data.
|
|
1190
|
+
* Returns a sendInit function the caller uses once prepare data is available.
|
|
1191
|
+
*/
|
|
1192
|
+
waitForDialogReadyDeferred(dialog, iframe, cleanup) {
|
|
1193
|
+
const dialogOrigin = this.getDialogOrigin();
|
|
1194
|
+
return new Promise((resolve) => {
|
|
1195
|
+
let settled = false;
|
|
1196
|
+
const teardown = () => {
|
|
1197
|
+
if (settled) return;
|
|
1198
|
+
settled = true;
|
|
1199
|
+
clearTimeout(readyTimeout);
|
|
1200
|
+
window.removeEventListener("message", handleMessage);
|
|
1201
|
+
dialog.removeEventListener("close", handleClose);
|
|
1202
|
+
};
|
|
1203
|
+
const handleMessage = (event) => {
|
|
1204
|
+
if (event.origin !== dialogOrigin) return;
|
|
1205
|
+
if (event.data?.type === "PASSKEY_READY") {
|
|
1206
|
+
teardown();
|
|
1207
|
+
resolve({
|
|
1208
|
+
ready: true,
|
|
1209
|
+
sendInit: (initMessage) => {
|
|
1210
|
+
iframe.contentWindow?.postMessage(
|
|
1211
|
+
{ type: "PASSKEY_INIT", ...initMessage },
|
|
1212
|
+
dialogOrigin
|
|
1213
|
+
);
|
|
1214
|
+
}
|
|
1215
|
+
});
|
|
1216
|
+
} else if (event.data?.type === "PASSKEY_CLOSE") {
|
|
1217
|
+
teardown();
|
|
1218
|
+
cleanup();
|
|
1219
|
+
resolve({ ready: false });
|
|
1220
|
+
}
|
|
1221
|
+
};
|
|
1222
|
+
const handleClose = () => {
|
|
1223
|
+
teardown();
|
|
1224
|
+
resolve({ ready: false });
|
|
1225
|
+
};
|
|
1226
|
+
const readyTimeout = setTimeout(() => {
|
|
1227
|
+
teardown();
|
|
1228
|
+
cleanup();
|
|
1229
|
+
resolve({ ready: false });
|
|
1230
|
+
}, 1e4);
|
|
1231
|
+
window.addEventListener("message", handleMessage);
|
|
1232
|
+
dialog.addEventListener("close", handleClose);
|
|
1233
|
+
});
|
|
1234
|
+
}
|
|
1235
|
+
/**
|
|
1236
|
+
* Prepare an intent by calling the orchestrator for a quote.
|
|
1237
|
+
* Returns the prepare response and the origin tier from the response header.
|
|
1238
|
+
*/
|
|
1239
|
+
async prepareIntent(requestBody) {
|
|
1240
|
+
try {
|
|
1241
|
+
const response = await fetch(`${this.config.providerUrl}/api/intent/prepare`, {
|
|
1242
|
+
method: "POST",
|
|
1243
|
+
headers: { "Content-Type": "application/json" },
|
|
1244
|
+
body: JSON.stringify(requestBody)
|
|
1245
|
+
});
|
|
1246
|
+
if (!response.ok) {
|
|
1247
|
+
const errorData = await response.json().catch(() => ({}));
|
|
1248
|
+
const errorMessage = errorData.error || "Failed to prepare intent";
|
|
1249
|
+
if (errorMessage.includes("User not found")) {
|
|
1250
|
+
localStorage.removeItem("1auth-user");
|
|
1251
|
+
}
|
|
1252
|
+
return {
|
|
1253
|
+
success: false,
|
|
1254
|
+
error: {
|
|
1255
|
+
code: errorMessage.includes("User not found") ? "USER_NOT_FOUND" : "PREPARE_FAILED",
|
|
1256
|
+
message: errorMessage
|
|
1257
|
+
}
|
|
1258
|
+
};
|
|
1259
|
+
}
|
|
1260
|
+
const tier = response.headers.get("X-Origin-Tier");
|
|
1261
|
+
return { success: true, data: await response.json(), tier };
|
|
1262
|
+
} catch (error) {
|
|
1263
|
+
return {
|
|
1264
|
+
success: false,
|
|
1265
|
+
error: {
|
|
1266
|
+
code: "NETWORK_ERROR",
|
|
1267
|
+
message: error instanceof Error ? error.message : "Network error"
|
|
1268
|
+
}
|
|
1269
|
+
};
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
1272
|
+
/**
|
|
1273
|
+
* Prepare a batch intent by calling the orchestrator for quotes on all intents.
|
|
1274
|
+
*/
|
|
1275
|
+
async prepareBatchIntent(requestBody) {
|
|
1276
|
+
try {
|
|
1277
|
+
const response = await fetch(`${this.config.providerUrl}/api/intent/batch-prepare`, {
|
|
1278
|
+
method: "POST",
|
|
1279
|
+
headers: { "Content-Type": "application/json" },
|
|
1280
|
+
body: JSON.stringify(requestBody)
|
|
1281
|
+
});
|
|
1282
|
+
if (!response.ok) {
|
|
1283
|
+
const errorData = await response.json().catch(() => ({}));
|
|
1284
|
+
const errorMessage = errorData.error || "Failed to prepare batch intent";
|
|
1285
|
+
if (errorMessage.includes("User not found")) {
|
|
1286
|
+
localStorage.removeItem("1auth-user");
|
|
1287
|
+
}
|
|
1288
|
+
return {
|
|
1289
|
+
success: false,
|
|
1290
|
+
error: errorMessage,
|
|
1291
|
+
failedIntents: errorData.failedIntents
|
|
1292
|
+
};
|
|
1293
|
+
}
|
|
1294
|
+
const tier = response.headers.get("X-Origin-Tier");
|
|
1295
|
+
return { success: true, data: await response.json(), tier };
|
|
1296
|
+
} catch {
|
|
1297
|
+
return { success: false, error: "Network error" };
|
|
1298
|
+
}
|
|
1299
|
+
}
|
|
1300
|
+
/**
|
|
1301
|
+
* Send a prepare error message to the dialog iframe.
|
|
1302
|
+
*/
|
|
1303
|
+
sendPrepareError(iframe, error) {
|
|
1304
|
+
const dialogOrigin = this.getDialogOrigin();
|
|
1305
|
+
iframe.contentWindow?.postMessage(
|
|
1306
|
+
{ type: "PASSKEY_PREPARE_ERROR", error },
|
|
1307
|
+
dialogOrigin
|
|
1308
|
+
);
|
|
1309
|
+
}
|
|
997
1310
|
/**
|
|
998
1311
|
* Poll for intent status
|
|
999
1312
|
*
|
|
@@ -1305,6 +1618,7 @@ var OneAuthClient = class {
|
|
|
1305
1618
|
message: options.message,
|
|
1306
1619
|
challenge: options.challenge || options.message,
|
|
1307
1620
|
username: options.username,
|
|
1621
|
+
accountAddress: options.accountAddress,
|
|
1308
1622
|
description: options.description,
|
|
1309
1623
|
metadata: options.metadata
|
|
1310
1624
|
});
|
|
@@ -1396,6 +1710,7 @@ var OneAuthClient = class {
|
|
|
1396
1710
|
},
|
|
1397
1711
|
challenge: signedHash,
|
|
1398
1712
|
username: options.username,
|
|
1713
|
+
accountAddress: options.accountAddress,
|
|
1399
1714
|
description: options.description
|
|
1400
1715
|
});
|
|
1401
1716
|
if (!ready) {
|
|
@@ -1469,7 +1784,7 @@ var OneAuthClient = class {
|
|
|
1469
1784
|
iframe.style.borderRadius = "12px";
|
|
1470
1785
|
iframe.style.boxShadow = "0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)";
|
|
1471
1786
|
iframe.id = `passkey-embed-${requestId}`;
|
|
1472
|
-
iframe.allow = "publickey-credentials-get *; publickey-credentials-create
|
|
1787
|
+
iframe.allow = "publickey-credentials-get *; publickey-credentials-create *; identity-credentials-get";
|
|
1473
1788
|
iframe.onload = () => {
|
|
1474
1789
|
options.onReady?.();
|
|
1475
1790
|
};
|
|
@@ -1617,6 +1932,7 @@ var OneAuthClient = class {
|
|
|
1617
1932
|
const teardown = () => {
|
|
1618
1933
|
if (settled) return;
|
|
1619
1934
|
settled = true;
|
|
1935
|
+
clearTimeout(readyTimeout);
|
|
1620
1936
|
window.removeEventListener("message", handleMessage);
|
|
1621
1937
|
dialog.removeEventListener("close", handleClose);
|
|
1622
1938
|
};
|
|
@@ -1639,6 +1955,11 @@ var OneAuthClient = class {
|
|
|
1639
1955
|
teardown();
|
|
1640
1956
|
resolve(false);
|
|
1641
1957
|
};
|
|
1958
|
+
const readyTimeout = setTimeout(() => {
|
|
1959
|
+
teardown();
|
|
1960
|
+
cleanup();
|
|
1961
|
+
resolve(false);
|
|
1962
|
+
}, 1e4);
|
|
1642
1963
|
window.addEventListener("message", handleMessage);
|
|
1643
1964
|
dialog.addEventListener("close", handleClose);
|
|
1644
1965
|
});
|
|
@@ -1679,7 +2000,9 @@ var OneAuthClient = class {
|
|
|
1679
2000
|
border-radius: 14px;
|
|
1680
2001
|
border: none;
|
|
1681
2002
|
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.12), 0 2px 8px rgba(0, 0, 0, 0.08);
|
|
1682
|
-
transition:
|
|
2003
|
+
transition: height 0.15s ease-out;
|
|
2004
|
+
max-height: calc(100vh - 100px);
|
|
2005
|
+
max-height: calc(100dvh - 100px);
|
|
1683
2006
|
}
|
|
1684
2007
|
|
|
1685
2008
|
@media (min-width: 769px) {
|
|
@@ -1741,14 +2064,10 @@ var OneAuthClient = class {
|
|
|
1741
2064
|
const iframe = document.createElement("iframe");
|
|
1742
2065
|
iframe.setAttribute(
|
|
1743
2066
|
"allow",
|
|
1744
|
-
"publickey-credentials-get *; publickey-credentials-create *; clipboard-write"
|
|
2067
|
+
"publickey-credentials-get *; publickey-credentials-create *; clipboard-write; identity-credentials-get"
|
|
1745
2068
|
);
|
|
1746
2069
|
iframe.setAttribute("aria-label", "Passkey Authentication");
|
|
1747
2070
|
iframe.setAttribute("tabindex", "0");
|
|
1748
|
-
iframe.setAttribute(
|
|
1749
|
-
"sandbox",
|
|
1750
|
-
"allow-forms allow-scripts allow-same-origin allow-popups allow-popups-to-escape-sandbox"
|
|
1751
|
-
);
|
|
1752
2071
|
iframe.setAttribute("src", url);
|
|
1753
2072
|
iframe.setAttribute("title", "Passkey");
|
|
1754
2073
|
iframe.style.border = "none";
|
|
@@ -1758,10 +2077,8 @@ var OneAuthClient = class {
|
|
|
1758
2077
|
const handleMessage = (event) => {
|
|
1759
2078
|
if (event.origin !== hostUrl.origin) return;
|
|
1760
2079
|
if (event.data?.type === "PASSKEY_RESIZE") {
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
iframe.style.width = `${event.data.width}px`;
|
|
1764
|
-
}
|
|
2080
|
+
const maxHeight = window.innerHeight - 100;
|
|
2081
|
+
iframe.style.height = `${Math.min(event.data.height, maxHeight)}px`;
|
|
1765
2082
|
} else if (event.data?.type === "PASSKEY_DISCONNECT") {
|
|
1766
2083
|
localStorage.removeItem("1auth-user");
|
|
1767
2084
|
}
|
|
@@ -1779,7 +2096,10 @@ var OneAuthClient = class {
|
|
|
1779
2096
|
}
|
|
1780
2097
|
});
|
|
1781
2098
|
dialog.showModal();
|
|
2099
|
+
let cleanedUp = false;
|
|
1782
2100
|
const cleanup = () => {
|
|
2101
|
+
if (cleanedUp) return;
|
|
2102
|
+
cleanedUp = true;
|
|
1783
2103
|
window.removeEventListener("message", handleMessage);
|
|
1784
2104
|
document.removeEventListener("keydown", handleEscape);
|
|
1785
2105
|
dialog.close();
|
|
@@ -1812,6 +2132,7 @@ var OneAuthClient = class {
|
|
|
1812
2132
|
resolve({
|
|
1813
2133
|
success: true,
|
|
1814
2134
|
username: data.data?.username,
|
|
2135
|
+
address: data.data?.address,
|
|
1815
2136
|
user: data.data?.user
|
|
1816
2137
|
});
|
|
1817
2138
|
} else {
|
|
@@ -1826,7 +2147,8 @@ var OneAuthClient = class {
|
|
|
1826
2147
|
if (data.success) {
|
|
1827
2148
|
resolve({
|
|
1828
2149
|
success: true,
|
|
1829
|
-
username: data.data?.username
|
|
2150
|
+
username: data.data?.username,
|
|
2151
|
+
address: data.data?.address
|
|
1830
2152
|
});
|
|
1831
2153
|
} else {
|
|
1832
2154
|
resolve({
|
|
@@ -1886,6 +2208,7 @@ var OneAuthClient = class {
|
|
|
1886
2208
|
resolve({
|
|
1887
2209
|
success: true,
|
|
1888
2210
|
username: data.data?.username,
|
|
2211
|
+
address: data.data?.address,
|
|
1889
2212
|
user: data.data?.user
|
|
1890
2213
|
});
|
|
1891
2214
|
} else {
|
|
@@ -1901,7 +2224,8 @@ var OneAuthClient = class {
|
|
|
1901
2224
|
if (data.success) {
|
|
1902
2225
|
resolve({
|
|
1903
2226
|
success: true,
|
|
1904
|
-
username: data.data?.username
|
|
2227
|
+
username: data.data?.username,
|
|
2228
|
+
address: data.data?.address
|
|
1905
2229
|
});
|
|
1906
2230
|
} else {
|
|
1907
2231
|
resolve({
|
|
@@ -1977,6 +2301,7 @@ var OneAuthClient = class {
|
|
|
1977
2301
|
resolve({
|
|
1978
2302
|
success: true,
|
|
1979
2303
|
username: data.data?.username,
|
|
2304
|
+
address: data.data?.address,
|
|
1980
2305
|
autoConnected: data.data?.autoConnected
|
|
1981
2306
|
});
|
|
1982
2307
|
} else {
|
|
@@ -2002,6 +2327,45 @@ var OneAuthClient = class {
|
|
|
2002
2327
|
window.addEventListener("message", handleMessage);
|
|
2003
2328
|
});
|
|
2004
2329
|
}
|
|
2330
|
+
waitForConsentResponse(_dialog, _iframe, cleanup) {
|
|
2331
|
+
const dialogOrigin = this.getDialogOrigin();
|
|
2332
|
+
return new Promise((resolve) => {
|
|
2333
|
+
const handleMessage = (event) => {
|
|
2334
|
+
if (event.origin !== dialogOrigin) return;
|
|
2335
|
+
const data = event.data;
|
|
2336
|
+
if (data?.type === "PASSKEY_CONSENT_RESULT") {
|
|
2337
|
+
window.removeEventListener("message", handleMessage);
|
|
2338
|
+
cleanup();
|
|
2339
|
+
if (data.success) {
|
|
2340
|
+
resolve({
|
|
2341
|
+
success: true,
|
|
2342
|
+
data: data.data,
|
|
2343
|
+
grantedAt: data.data?.grantedAt
|
|
2344
|
+
});
|
|
2345
|
+
} else {
|
|
2346
|
+
resolve({
|
|
2347
|
+
success: false,
|
|
2348
|
+
error: data.error ?? {
|
|
2349
|
+
code: "USER_REJECTED",
|
|
2350
|
+
message: "User denied the consent request"
|
|
2351
|
+
}
|
|
2352
|
+
});
|
|
2353
|
+
}
|
|
2354
|
+
} else if (data?.type === "PASSKEY_CLOSE") {
|
|
2355
|
+
window.removeEventListener("message", handleMessage);
|
|
2356
|
+
cleanup();
|
|
2357
|
+
resolve({
|
|
2358
|
+
success: false,
|
|
2359
|
+
error: {
|
|
2360
|
+
code: "USER_CANCELLED",
|
|
2361
|
+
message: "User closed the dialog"
|
|
2362
|
+
}
|
|
2363
|
+
});
|
|
2364
|
+
}
|
|
2365
|
+
};
|
|
2366
|
+
window.addEventListener("message", handleMessage);
|
|
2367
|
+
});
|
|
2368
|
+
}
|
|
2005
2369
|
waitForModalSigningResponse(requestId, _dialog, _iframe, cleanup) {
|
|
2006
2370
|
const dialogOrigin = this.getDialogOrigin();
|
|
2007
2371
|
return new Promise((resolve) => {
|