@rhinestone/1auth 0.1.2 → 0.5.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-N4BLW5UR.mjs} +49 -25
- package/dist/chunk-N4BLW5UR.mjs.map +1 -0
- package/dist/{client-DyYGKWj3.d.mts → client-Di8SBnPO.d.mts} +242 -85
- package/dist/{client-DyYGKWj3.d.ts → client-Di8SBnPO.d.ts} +242 -85
- package/dist/index.d.mts +5 -9
- package/dist/index.d.ts +5 -9
- package/dist/index.js +559 -178
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +513 -155
- package/dist/index.mjs.map +1 -1
- package/dist/{provider-CNTZPPFz.d.ts → provider-8anOtc87.d.mts} +2 -8
- package/dist/{provider-Ctr7HQHR.d.mts → provider-CFnLQt5m.d.ts} +2 -8
- 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/server.d.mts +2 -5
- package/dist/server.d.ts +2 -5
- package/dist/server.js +2 -2
- package/dist/server.js.map +1 -1
- package/dist/server.mjs +2 -2
- package/dist/server.mjs.map +1 -1
- package/dist/wagmi.d.mts +2 -2
- package/dist/wagmi.d.ts +2 -2
- package/dist/wagmi.js +48 -23
- package/dist/wagmi.js.map +1 -1
- package/dist/wagmi.mjs +3 -3
- package/dist/wagmi.mjs.map +1 -1
- package/package.json +7 -6
- package/dist/chunk-TACK3LJN.mjs.map +0 -1
package/dist/index.js
CHANGED
|
@@ -34,11 +34,8 @@ __export(index_exports, {
|
|
|
34
34
|
BatchQueueWidget: () => BatchQueueWidget,
|
|
35
35
|
ETHEREUM_MESSAGE_PREFIX: () => ETHEREUM_MESSAGE_PREFIX,
|
|
36
36
|
OneAuthClient: () => OneAuthClient,
|
|
37
|
-
PASSKEY_MESSAGE_PREFIX: () => PASSKEY_MESSAGE_PREFIX,
|
|
38
|
-
PasskeyProviderClient: () => OneAuthClient,
|
|
39
37
|
createOneAuthProvider: () => createOneAuthProvider,
|
|
40
38
|
createPasskeyAccount: () => createPasskeyAccount,
|
|
41
|
-
createPasskeyProvider: () => createPasskeyProvider,
|
|
42
39
|
createPasskeyWalletClient: () => createPasskeyWalletClient,
|
|
43
40
|
encodeWebAuthnSignature: () => encodeWebAuthnSignature,
|
|
44
41
|
getAllSupportedChainsAndTokens: () => getAllSupportedChainsAndTokens,
|
|
@@ -71,12 +68,15 @@ var import_viem = require("viem");
|
|
|
71
68
|
var viemChains = __toESM(require("viem/chains"));
|
|
72
69
|
var import_sdk = require("@rhinestone/sdk");
|
|
73
70
|
var env = typeof process !== "undefined" ? process.env : {};
|
|
74
|
-
var
|
|
75
|
-
|
|
76
|
-
);
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
)
|
|
71
|
+
var VIEM_CHAIN_BY_ID = /* @__PURE__ */ new Map();
|
|
72
|
+
for (const value of Object.values(viemChains)) {
|
|
73
|
+
if (typeof value !== "object" || value === null || !("id" in value) || !("name" in value)) continue;
|
|
74
|
+
const chain = value;
|
|
75
|
+
const existing = VIEM_CHAIN_BY_ID.get(chain.id);
|
|
76
|
+
if (!existing || existing.testnet && !chain.testnet) {
|
|
77
|
+
VIEM_CHAIN_BY_ID.set(chain.id, chain);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
80
|
var SUPPORTED_CHAIN_IDS = new Set(
|
|
81
81
|
(0, import_sdk.getAllSupportedChainsAndTokens)().map((entry) => entry.chainId)
|
|
82
82
|
);
|
|
@@ -197,7 +197,7 @@ var POPUP_WIDTH = 450;
|
|
|
197
197
|
var POPUP_HEIGHT = 600;
|
|
198
198
|
var DEFAULT_EMBED_WIDTH = "400px";
|
|
199
199
|
var DEFAULT_EMBED_HEIGHT = "500px";
|
|
200
|
-
var MODAL_WIDTH =
|
|
200
|
+
var MODAL_WIDTH = 340;
|
|
201
201
|
var DEFAULT_PROVIDER_URL = "https://passkey.1auth.box";
|
|
202
202
|
var OneAuthClient = class {
|
|
203
203
|
constructor(config) {
|
|
@@ -205,6 +205,12 @@ var OneAuthClient = class {
|
|
|
205
205
|
const dialogUrl = config.dialogUrl || providerUrl;
|
|
206
206
|
this.config = { ...config, providerUrl, dialogUrl };
|
|
207
207
|
this.theme = this.config.theme || {};
|
|
208
|
+
if (typeof document !== "undefined") {
|
|
209
|
+
this.injectPreconnect(providerUrl);
|
|
210
|
+
if (dialogUrl !== providerUrl) {
|
|
211
|
+
this.injectPreconnect(dialogUrl);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
208
214
|
}
|
|
209
215
|
/**
|
|
210
216
|
* Update the theme configuration at runtime
|
|
@@ -285,7 +291,28 @@ var OneAuthClient = class {
|
|
|
285
291
|
return void 0;
|
|
286
292
|
}
|
|
287
293
|
/**
|
|
288
|
-
* Open the
|
|
294
|
+
* Open the authentication modal (sign in + sign up).
|
|
295
|
+
*
|
|
296
|
+
* Handles both new user registration and returning user login in a single
|
|
297
|
+
* call — the modal shows the appropriate flow based on whether the user
|
|
298
|
+
* has a passkey registered.
|
|
299
|
+
*
|
|
300
|
+
* @param options.username - Pre-fill the username field
|
|
301
|
+
* @param options.theme - Override the theme for this modal invocation
|
|
302
|
+
* @param options.oauthEnabled - Set to false to hide OAuth sign-in buttons
|
|
303
|
+
* @returns {@link AuthResult} with user details and typed address
|
|
304
|
+
*
|
|
305
|
+
* @example
|
|
306
|
+
* ```typescript
|
|
307
|
+
* const result = await client.authWithModal();
|
|
308
|
+
*
|
|
309
|
+
* if (result.success) {
|
|
310
|
+
* console.log('Signed in as:', result.user?.username);
|
|
311
|
+
* console.log('Address:', result.user?.address); // typed `0x${string}`
|
|
312
|
+
* } else if (result.error?.code === 'USER_CANCELLED') {
|
|
313
|
+
* // User closed the modal
|
|
314
|
+
* }
|
|
315
|
+
* ```
|
|
289
316
|
*/
|
|
290
317
|
async authWithModal(options) {
|
|
291
318
|
const dialogUrl = this.getDialogUrl();
|
|
@@ -325,7 +352,7 @@ var OneAuthClient = class {
|
|
|
325
352
|
* const result = await client.connectWithModal();
|
|
326
353
|
*
|
|
327
354
|
* if (result.success) {
|
|
328
|
-
* console.log('Connected as:', result.username);
|
|
355
|
+
* console.log('Connected as:', result.user?.username);
|
|
329
356
|
* } else if (result.action === 'switch') {
|
|
330
357
|
* // User needs to sign in first
|
|
331
358
|
* const authResult = await client.authWithModal();
|
|
@@ -359,6 +386,133 @@ var OneAuthClient = class {
|
|
|
359
386
|
}
|
|
360
387
|
return this.waitForConnectResponse(dialog, iframe, cleanup);
|
|
361
388
|
}
|
|
389
|
+
/**
|
|
390
|
+
* Check if a user has already granted consent for the requested fields.
|
|
391
|
+
* This is a read-only check — no dialog is shown.
|
|
392
|
+
*
|
|
393
|
+
* @example
|
|
394
|
+
* ```typescript
|
|
395
|
+
* const result = await client.checkConsent({
|
|
396
|
+
* username: "alice",
|
|
397
|
+
* fields: ["email"],
|
|
398
|
+
* });
|
|
399
|
+
* if (result.hasConsent) {
|
|
400
|
+
* console.log(result.data?.email);
|
|
401
|
+
* }
|
|
402
|
+
* ```
|
|
403
|
+
*/
|
|
404
|
+
async checkConsent(options) {
|
|
405
|
+
const clientId = options.clientId ?? this.config.clientId;
|
|
406
|
+
if (!clientId) {
|
|
407
|
+
return {
|
|
408
|
+
hasConsent: false
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
const username = options.username ?? options.accountAddress;
|
|
412
|
+
if (!username) {
|
|
413
|
+
return {
|
|
414
|
+
hasConsent: false
|
|
415
|
+
};
|
|
416
|
+
}
|
|
417
|
+
try {
|
|
418
|
+
const res = await fetch(`${this.config.providerUrl || "https://passkey.1auth.box"}/api/consent`, {
|
|
419
|
+
method: "POST",
|
|
420
|
+
headers: {
|
|
421
|
+
"Content-Type": "application/json",
|
|
422
|
+
...clientId ? { "x-client-id": clientId } : {}
|
|
423
|
+
},
|
|
424
|
+
body: JSON.stringify({
|
|
425
|
+
username,
|
|
426
|
+
requestedFields: options.fields,
|
|
427
|
+
clientId
|
|
428
|
+
})
|
|
429
|
+
});
|
|
430
|
+
if (!res.ok) {
|
|
431
|
+
return { hasConsent: false };
|
|
432
|
+
}
|
|
433
|
+
const data = await res.json();
|
|
434
|
+
return {
|
|
435
|
+
hasConsent: data.hasConsent ?? false,
|
|
436
|
+
data: data.data,
|
|
437
|
+
grantedAt: data.grantedAt
|
|
438
|
+
};
|
|
439
|
+
} catch {
|
|
440
|
+
return { hasConsent: false };
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
/**
|
|
444
|
+
* Request consent from the user to share their data.
|
|
445
|
+
*
|
|
446
|
+
* First checks if consent was already granted (returns cached data immediately).
|
|
447
|
+
* If not, opens the consent dialog where the user can review and approve sharing.
|
|
448
|
+
*
|
|
449
|
+
* @example
|
|
450
|
+
* ```typescript
|
|
451
|
+
* const result = await client.requestConsent({
|
|
452
|
+
* username: "alice",
|
|
453
|
+
* fields: ["email", "deviceNames"],
|
|
454
|
+
* });
|
|
455
|
+
* if (result.success) {
|
|
456
|
+
* console.log(result.data?.email);
|
|
457
|
+
* console.log(result.cached); // true if no dialog was shown
|
|
458
|
+
* }
|
|
459
|
+
* ```
|
|
460
|
+
*/
|
|
461
|
+
async requestConsent(options) {
|
|
462
|
+
const clientId = options.clientId ?? this.config.clientId;
|
|
463
|
+
if (!clientId) {
|
|
464
|
+
return {
|
|
465
|
+
success: false,
|
|
466
|
+
error: { code: "INVALID_REQUEST", message: "clientId is required (set in config or options)" }
|
|
467
|
+
};
|
|
468
|
+
}
|
|
469
|
+
const username = options.username ?? options.accountAddress;
|
|
470
|
+
if (!username) {
|
|
471
|
+
return {
|
|
472
|
+
success: false,
|
|
473
|
+
error: { code: "INVALID_REQUEST", message: "username or accountAddress is required" }
|
|
474
|
+
};
|
|
475
|
+
}
|
|
476
|
+
if (!options.fields || options.fields.length === 0) {
|
|
477
|
+
return {
|
|
478
|
+
success: false,
|
|
479
|
+
error: { code: "INVALID_REQUEST", message: "At least one field is required" }
|
|
480
|
+
};
|
|
481
|
+
}
|
|
482
|
+
const existing = await this.checkConsent({ ...options, clientId });
|
|
483
|
+
if (existing.hasConsent && existing.data) {
|
|
484
|
+
return {
|
|
485
|
+
success: true,
|
|
486
|
+
data: existing.data,
|
|
487
|
+
grantedAt: existing.grantedAt,
|
|
488
|
+
cached: true
|
|
489
|
+
};
|
|
490
|
+
}
|
|
491
|
+
const dialogUrl = this.getDialogUrl();
|
|
492
|
+
const params = new URLSearchParams({
|
|
493
|
+
mode: "iframe",
|
|
494
|
+
username,
|
|
495
|
+
clientId,
|
|
496
|
+
fields: options.fields.join(",")
|
|
497
|
+
});
|
|
498
|
+
const themeParams = this.getThemeParams(options.theme);
|
|
499
|
+
if (themeParams) {
|
|
500
|
+
const themeParsed = new URLSearchParams(themeParams);
|
|
501
|
+
themeParsed.forEach((value, key) => params.set(key, value));
|
|
502
|
+
}
|
|
503
|
+
const url = `${dialogUrl}/dialog/consent?${params.toString()}`;
|
|
504
|
+
const { dialog, iframe, cleanup } = this.createModalDialog(url);
|
|
505
|
+
const ready = await this.waitForDialogReady(dialog, iframe, cleanup, {
|
|
506
|
+
mode: "iframe"
|
|
507
|
+
});
|
|
508
|
+
if (!ready) {
|
|
509
|
+
return {
|
|
510
|
+
success: false,
|
|
511
|
+
error: { code: "USER_CANCELLED", message: "User closed the dialog" }
|
|
512
|
+
};
|
|
513
|
+
}
|
|
514
|
+
return this.waitForConsentResponse(dialog, iframe, cleanup);
|
|
515
|
+
}
|
|
362
516
|
/**
|
|
363
517
|
* Authenticate a user with an optional challenge to sign.
|
|
364
518
|
*
|
|
@@ -376,17 +530,16 @@ var OneAuthClient = class {
|
|
|
376
530
|
*
|
|
377
531
|
* @example
|
|
378
532
|
* ```typescript
|
|
379
|
-
* // Authenticate with a login challenge
|
|
380
533
|
* const result = await client.authenticate({
|
|
381
534
|
* challenge: `Login to MyApp\nTimestamp: ${Date.now()}\nNonce: ${crypto.randomUUID()}`
|
|
382
535
|
* });
|
|
383
536
|
*
|
|
384
|
-
* if (result.success && result.
|
|
537
|
+
* if (result.success && result.challenge) {
|
|
385
538
|
* // Verify signature server-side
|
|
386
539
|
* const isValid = await verifyOnServer(
|
|
387
|
-
* result.username,
|
|
388
|
-
* result.signature,
|
|
389
|
-
* result.signedHash
|
|
540
|
+
* result.user?.username,
|
|
541
|
+
* result.challenge.signature,
|
|
542
|
+
* result.challenge.signedHash
|
|
390
543
|
* );
|
|
391
544
|
* }
|
|
392
545
|
* ```
|
|
@@ -486,7 +639,8 @@ var OneAuthClient = class {
|
|
|
486
639
|
}
|
|
487
640
|
};
|
|
488
641
|
}
|
|
489
|
-
|
|
642
|
+
const accountAddress = signedIntent?.accountAddress || options.accountAddress;
|
|
643
|
+
if (!username && !accountAddress) {
|
|
490
644
|
return {
|
|
491
645
|
success: false,
|
|
492
646
|
intentId: "",
|
|
@@ -515,6 +669,7 @@ var OneAuthClient = class {
|
|
|
515
669
|
let prepareResponse;
|
|
516
670
|
const requestBody = signedIntent || {
|
|
517
671
|
username: options.username,
|
|
672
|
+
accountAddress: options.accountAddress,
|
|
518
673
|
targetChain: options.targetChain,
|
|
519
674
|
calls: options.calls,
|
|
520
675
|
tokenRequests: serializedTokenRequests,
|
|
@@ -522,48 +677,35 @@ var OneAuthClient = class {
|
|
|
522
677
|
sourceChainId: options.sourceChainId,
|
|
523
678
|
...this.config.clientId && { clientId: this.config.clientId }
|
|
524
679
|
};
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
const errorData = await response.json().catch(() => ({}));
|
|
535
|
-
const errorMessage = errorData.error || "Failed to prepare intent";
|
|
536
|
-
if (errorMessage.includes("User not found")) {
|
|
537
|
-
localStorage.removeItem("1auth-user");
|
|
538
|
-
}
|
|
539
|
-
return {
|
|
540
|
-
success: false,
|
|
541
|
-
intentId: "",
|
|
542
|
-
status: "failed",
|
|
543
|
-
error: {
|
|
544
|
-
code: errorMessage.includes("User not found") ? "USER_NOT_FOUND" : "PREPARE_FAILED",
|
|
545
|
-
message: errorMessage
|
|
546
|
-
}
|
|
547
|
-
};
|
|
548
|
-
}
|
|
549
|
-
prepareResponse = await response.json();
|
|
550
|
-
} catch (error) {
|
|
680
|
+
const dialogUrl = this.getDialogUrl();
|
|
681
|
+
const themeParams = this.getThemeParams();
|
|
682
|
+
const signingUrl = `${dialogUrl}/dialog/sign?mode=iframe${themeParams ? `&${themeParams}` : ""}`;
|
|
683
|
+
const { dialog, iframe, cleanup } = this.createModalDialog(signingUrl);
|
|
684
|
+
const [prepareResult, dialogResult] = await Promise.all([
|
|
685
|
+
this.prepareIntent(requestBody),
|
|
686
|
+
this.waitForDialogReadyDeferred(dialog, iframe, cleanup)
|
|
687
|
+
]);
|
|
688
|
+
if (!dialogResult.ready) {
|
|
551
689
|
return {
|
|
552
690
|
success: false,
|
|
553
691
|
intentId: "",
|
|
554
692
|
status: "failed",
|
|
555
|
-
error: {
|
|
556
|
-
code: "NETWORK_ERROR",
|
|
557
|
-
message: error instanceof Error ? error.message : "Network error"
|
|
558
|
-
}
|
|
693
|
+
error: { code: "USER_CANCELLED", message: "User closed the dialog" }
|
|
559
694
|
};
|
|
560
695
|
}
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
696
|
+
if (!prepareResult.success) {
|
|
697
|
+
this.sendPrepareError(iframe, prepareResult.error.message);
|
|
698
|
+
await this.waitForDialogClose(dialog, cleanup);
|
|
699
|
+
return {
|
|
700
|
+
success: false,
|
|
701
|
+
intentId: "",
|
|
702
|
+
status: "failed",
|
|
703
|
+
error: prepareResult.error
|
|
704
|
+
};
|
|
705
|
+
}
|
|
706
|
+
prepareResponse = prepareResult.data;
|
|
565
707
|
const dialogOrigin = this.getDialogOrigin();
|
|
566
|
-
const
|
|
708
|
+
const initPayload = {
|
|
567
709
|
mode: "iframe",
|
|
568
710
|
calls,
|
|
569
711
|
chainId: targetChain,
|
|
@@ -575,16 +717,21 @@ var OneAuthClient = class {
|
|
|
575
717
|
tokenRequests: serializedTokenRequests,
|
|
576
718
|
expiresAt: prepareResponse.expiresAt,
|
|
577
719
|
userId: prepareResponse.userId,
|
|
578
|
-
intentOp: prepareResponse.intentOp
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
720
|
+
intentOp: prepareResponse.intentOp,
|
|
721
|
+
digestResult: prepareResponse.digestResult,
|
|
722
|
+
tier: prepareResult.tier
|
|
723
|
+
};
|
|
724
|
+
dialogResult.sendInit(initPayload);
|
|
725
|
+
const handleReReady = (event) => {
|
|
726
|
+
if (event.origin !== dialogOrigin) return;
|
|
727
|
+
if (event.data?.type === "PASSKEY_READY") {
|
|
728
|
+
iframe.contentWindow?.postMessage(
|
|
729
|
+
{ type: "PASSKEY_INIT", ...initPayload },
|
|
730
|
+
dialogOrigin
|
|
731
|
+
);
|
|
732
|
+
}
|
|
733
|
+
};
|
|
734
|
+
window.addEventListener("message", handleReReady);
|
|
588
735
|
const signingResult = await this.waitForSigningWithRefresh(
|
|
589
736
|
dialog,
|
|
590
737
|
iframe,
|
|
@@ -611,7 +758,8 @@ var OneAuthClient = class {
|
|
|
611
758
|
expiresAt: refreshedData.expiresAt,
|
|
612
759
|
challenge: refreshedData.challenge,
|
|
613
760
|
originMessages: refreshedData.originMessages,
|
|
614
|
-
transaction: refreshedData.transaction
|
|
761
|
+
transaction: refreshedData.transaction,
|
|
762
|
+
digestResult: refreshedData.digestResult
|
|
615
763
|
};
|
|
616
764
|
} catch (error) {
|
|
617
765
|
console.error("[SDK] Quote refresh error:", error);
|
|
@@ -619,6 +767,7 @@ var OneAuthClient = class {
|
|
|
619
767
|
}
|
|
620
768
|
}
|
|
621
769
|
);
|
|
770
|
+
window.removeEventListener("message", handleReReady);
|
|
622
771
|
if (!signingResult.success) {
|
|
623
772
|
return {
|
|
624
773
|
success: false,
|
|
@@ -650,6 +799,7 @@ var OneAuthClient = class {
|
|
|
650
799
|
targetChain: prepareResponse.targetChain,
|
|
651
800
|
calls: prepareResponse.calls,
|
|
652
801
|
expiresAt: prepareResponse.expiresAt,
|
|
802
|
+
digestResult: prepareResponse.digestResult,
|
|
653
803
|
// Signature from dialog
|
|
654
804
|
signature: signingResult.signature,
|
|
655
805
|
passkey: signingResult.passkey
|
|
@@ -691,10 +841,21 @@ var OneAuthClient = class {
|
|
|
691
841
|
let finalTxHash = executeResponse.transactionHash;
|
|
692
842
|
if (finalStatus === "pending") {
|
|
693
843
|
this.sendTransactionStatus(iframe, "pending");
|
|
844
|
+
let userClosedEarly = false;
|
|
845
|
+
const dialogOrigin2 = this.getDialogOrigin();
|
|
846
|
+
const earlyCloseHandler = (event) => {
|
|
847
|
+
if (event.origin !== dialogOrigin2) return;
|
|
848
|
+
if (event.data?.type === "PASSKEY_CLOSE") {
|
|
849
|
+
userClosedEarly = true;
|
|
850
|
+
cleanup();
|
|
851
|
+
}
|
|
852
|
+
};
|
|
853
|
+
window.addEventListener("message", earlyCloseHandler);
|
|
694
854
|
const maxAttempts = 120;
|
|
695
855
|
const pollIntervalMs = 1500;
|
|
696
856
|
let lastStatus = "pending";
|
|
697
857
|
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
858
|
+
if (userClosedEarly) break;
|
|
698
859
|
try {
|
|
699
860
|
const statusResponse = await fetch(
|
|
700
861
|
`${this.config.providerUrl}/api/intent/status/${executeResponse.intentId}`,
|
|
@@ -729,6 +890,21 @@ var OneAuthClient = class {
|
|
|
729
890
|
}
|
|
730
891
|
await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
|
|
731
892
|
}
|
|
893
|
+
window.removeEventListener("message", earlyCloseHandler);
|
|
894
|
+
if (userClosedEarly) {
|
|
895
|
+
cleanup();
|
|
896
|
+
return {
|
|
897
|
+
success: false,
|
|
898
|
+
intentId: executeResponse.intentId,
|
|
899
|
+
status: finalStatus,
|
|
900
|
+
transactionHash: finalTxHash,
|
|
901
|
+
operationId: executeResponse.operationId,
|
|
902
|
+
error: {
|
|
903
|
+
code: "USER_CANCELLED",
|
|
904
|
+
message: "User closed the dialog"
|
|
905
|
+
}
|
|
906
|
+
};
|
|
907
|
+
}
|
|
732
908
|
}
|
|
733
909
|
const closeOn = options.closeOn || "preconfirmed";
|
|
734
910
|
const successStatuses = {
|
|
@@ -739,8 +915,9 @@ var OneAuthClient = class {
|
|
|
739
915
|
};
|
|
740
916
|
const isSuccessStatus = successStatuses[closeOn]?.includes(finalStatus) ?? false;
|
|
741
917
|
const displayStatus = isSuccessStatus ? "confirmed" : finalStatus;
|
|
918
|
+
const closePromise = this.waitForDialogClose(dialog, cleanup);
|
|
742
919
|
this.sendTransactionStatus(iframe, displayStatus, finalTxHash);
|
|
743
|
-
await
|
|
920
|
+
await closePromise;
|
|
744
921
|
if (options.waitForHash && !finalTxHash) {
|
|
745
922
|
const hash = await this.waitForTransactionHash(executeResponse.intentId, {
|
|
746
923
|
timeoutMs: options.hashTimeoutMs,
|
|
@@ -801,7 +978,7 @@ var OneAuthClient = class {
|
|
|
801
978
|
* ```
|
|
802
979
|
*/
|
|
803
980
|
async sendBatchIntent(options) {
|
|
804
|
-
if (!options.username) {
|
|
981
|
+
if (!options.username && !options.accountAddress) {
|
|
805
982
|
return {
|
|
806
983
|
success: false,
|
|
807
984
|
results: [],
|
|
@@ -825,35 +1002,24 @@ var OneAuthClient = class {
|
|
|
825
1002
|
amount: r.amount.toString()
|
|
826
1003
|
})),
|
|
827
1004
|
sourceAssets: intent.sourceAssets,
|
|
828
|
-
sourceChainId: intent.sourceChainId
|
|
1005
|
+
sourceChainId: intent.sourceChainId,
|
|
1006
|
+
moduleInstall: intent.moduleInstall
|
|
829
1007
|
}));
|
|
830
1008
|
const requestBody = {
|
|
831
|
-
username: options.username,
|
|
1009
|
+
...options.username && { username: options.username },
|
|
1010
|
+
...options.accountAddress && { accountAddress: options.accountAddress },
|
|
832
1011
|
intents: serializedIntents,
|
|
833
1012
|
...this.config.clientId && { clientId: this.config.clientId }
|
|
834
1013
|
};
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
const errorMessage = errorData.error || "Failed to prepare batch intent";
|
|
845
|
-
if (errorMessage.includes("User not found")) {
|
|
846
|
-
localStorage.removeItem("1auth-user");
|
|
847
|
-
}
|
|
848
|
-
return {
|
|
849
|
-
success: false,
|
|
850
|
-
results: [],
|
|
851
|
-
successCount: 0,
|
|
852
|
-
failureCount: 0
|
|
853
|
-
};
|
|
854
|
-
}
|
|
855
|
-
prepareResponse = await response.json();
|
|
856
|
-
} catch {
|
|
1014
|
+
const dialogUrl = this.getDialogUrl();
|
|
1015
|
+
const themeParams = this.getThemeParams();
|
|
1016
|
+
const signingUrl = `${dialogUrl}/dialog/sign?mode=iframe${themeParams ? `&${themeParams}` : ""}`;
|
|
1017
|
+
const { dialog, iframe, cleanup } = this.createModalDialog(signingUrl);
|
|
1018
|
+
const [prepareResult, dialogResult] = await Promise.all([
|
|
1019
|
+
this.prepareBatchIntent(requestBody),
|
|
1020
|
+
this.waitForDialogReadyDeferred(dialog, iframe, cleanup)
|
|
1021
|
+
]);
|
|
1022
|
+
if (!dialogResult.ready) {
|
|
857
1023
|
return {
|
|
858
1024
|
success: false,
|
|
859
1025
|
results: [],
|
|
@@ -861,29 +1027,50 @@ var OneAuthClient = class {
|
|
|
861
1027
|
failureCount: 0
|
|
862
1028
|
};
|
|
863
1029
|
}
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
1030
|
+
if (!prepareResult.success) {
|
|
1031
|
+
const failedIntents = prepareResult.failedIntents;
|
|
1032
|
+
const failureResults = failedIntents?.map((f) => ({
|
|
1033
|
+
index: f.index,
|
|
1034
|
+
success: false,
|
|
1035
|
+
intentId: "",
|
|
1036
|
+
status: "failed",
|
|
1037
|
+
error: { message: f.error, code: "PREPARE_FAILED" }
|
|
1038
|
+
})) ?? [];
|
|
1039
|
+
this.sendPrepareError(iframe, prepareResult.error);
|
|
1040
|
+
await this.waitForDialogClose(dialog, cleanup);
|
|
1041
|
+
return {
|
|
1042
|
+
success: false,
|
|
1043
|
+
results: failureResults,
|
|
1044
|
+
successCount: 0,
|
|
1045
|
+
failureCount: failureResults.length,
|
|
1046
|
+
error: prepareResult.error
|
|
1047
|
+
};
|
|
1048
|
+
}
|
|
1049
|
+
let prepareResponse = prepareResult.data;
|
|
868
1050
|
const dialogOrigin = this.getDialogOrigin();
|
|
869
|
-
const
|
|
1051
|
+
const batchInitPayload = {
|
|
870
1052
|
mode: "iframe",
|
|
871
1053
|
batchMode: true,
|
|
872
1054
|
batchIntents: prepareResponse.intents,
|
|
1055
|
+
batchFailedIntents: prepareResponse.failedIntents,
|
|
873
1056
|
challenge: prepareResponse.challenge,
|
|
874
1057
|
username: options.username,
|
|
875
1058
|
accountAddress: prepareResponse.accountAddress,
|
|
876
1059
|
userId: prepareResponse.userId,
|
|
877
|
-
expiresAt: prepareResponse.expiresAt
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
1060
|
+
expiresAt: prepareResponse.expiresAt,
|
|
1061
|
+
tier: prepareResult.tier
|
|
1062
|
+
};
|
|
1063
|
+
dialogResult.sendInit(batchInitPayload);
|
|
1064
|
+
const handleBatchReReady = (event) => {
|
|
1065
|
+
if (event.origin !== dialogOrigin) return;
|
|
1066
|
+
if (event.data?.type === "PASSKEY_READY") {
|
|
1067
|
+
iframe.contentWindow?.postMessage(
|
|
1068
|
+
{ type: "PASSKEY_INIT", ...batchInitPayload },
|
|
1069
|
+
dialogOrigin
|
|
1070
|
+
);
|
|
1071
|
+
}
|
|
1072
|
+
};
|
|
1073
|
+
window.addEventListener("message", handleBatchReReady);
|
|
887
1074
|
const batchResult = await new Promise((resolve) => {
|
|
888
1075
|
const handleMessage = async (event) => {
|
|
889
1076
|
if (event.origin !== dialogOrigin) return;
|
|
@@ -930,13 +1117,21 @@ var OneAuthClient = class {
|
|
|
930
1117
|
status: r.status === "FAILED" ? "failed" : "pending",
|
|
931
1118
|
error: r.error ? { code: "EXECUTE_FAILED", message: r.error } : void 0
|
|
932
1119
|
}));
|
|
933
|
-
const
|
|
1120
|
+
const prepareFailures = (prepareResponse.failedIntents ?? []).map((f) => ({
|
|
1121
|
+
index: f.index,
|
|
1122
|
+
success: false,
|
|
1123
|
+
intentId: "",
|
|
1124
|
+
status: "failed",
|
|
1125
|
+
error: { code: "PREPARE_FAILED", message: f.error }
|
|
1126
|
+
}));
|
|
1127
|
+
const allResults = [...results, ...prepareFailures].sort((a, b) => a.index - b.index);
|
|
1128
|
+
const successCount = allResults.filter((r) => r.success).length;
|
|
934
1129
|
await this.waitForDialogClose(dialog, cleanup);
|
|
935
1130
|
resolve({
|
|
936
|
-
success: successCount ===
|
|
937
|
-
results,
|
|
1131
|
+
success: successCount === allResults.length,
|
|
1132
|
+
results: allResults,
|
|
938
1133
|
successCount,
|
|
939
|
-
failureCount:
|
|
1134
|
+
failureCount: allResults.length - successCount
|
|
940
1135
|
});
|
|
941
1136
|
} else {
|
|
942
1137
|
cleanup();
|
|
@@ -961,6 +1156,7 @@ var OneAuthClient = class {
|
|
|
961
1156
|
};
|
|
962
1157
|
window.addEventListener("message", handleMessage);
|
|
963
1158
|
});
|
|
1159
|
+
window.removeEventListener("message", handleBatchReReady);
|
|
964
1160
|
return batchResult;
|
|
965
1161
|
}
|
|
966
1162
|
/**
|
|
@@ -1164,6 +1360,143 @@ var OneAuthClient = class {
|
|
|
1164
1360
|
dialog.addEventListener("close", handleClose);
|
|
1165
1361
|
});
|
|
1166
1362
|
}
|
|
1363
|
+
/**
|
|
1364
|
+
* Inject a preconnect link tag to pre-warm DNS + TLS for a given URL.
|
|
1365
|
+
*/
|
|
1366
|
+
injectPreconnect(url) {
|
|
1367
|
+
try {
|
|
1368
|
+
const origin = new URL(url).origin;
|
|
1369
|
+
if (document.querySelector(`link[rel="preconnect"][href="${origin}"]`)) return;
|
|
1370
|
+
const link = document.createElement("link");
|
|
1371
|
+
link.rel = "preconnect";
|
|
1372
|
+
link.href = origin;
|
|
1373
|
+
link.crossOrigin = "anonymous";
|
|
1374
|
+
document.head.appendChild(link);
|
|
1375
|
+
} catch {
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
/**
|
|
1379
|
+
* Wait for the dialog iframe to signal ready without sending init data.
|
|
1380
|
+
* Returns a sendInit function the caller uses once prepare data is available.
|
|
1381
|
+
*/
|
|
1382
|
+
waitForDialogReadyDeferred(dialog, iframe, cleanup) {
|
|
1383
|
+
const dialogOrigin = this.getDialogOrigin();
|
|
1384
|
+
return new Promise((resolve) => {
|
|
1385
|
+
let settled = false;
|
|
1386
|
+
const teardown = () => {
|
|
1387
|
+
if (settled) return;
|
|
1388
|
+
settled = true;
|
|
1389
|
+
clearTimeout(readyTimeout);
|
|
1390
|
+
window.removeEventListener("message", handleMessage);
|
|
1391
|
+
dialog.removeEventListener("close", handleClose);
|
|
1392
|
+
};
|
|
1393
|
+
const handleMessage = (event) => {
|
|
1394
|
+
if (event.origin !== dialogOrigin) return;
|
|
1395
|
+
if (event.data?.type === "PASSKEY_READY") {
|
|
1396
|
+
teardown();
|
|
1397
|
+
resolve({
|
|
1398
|
+
ready: true,
|
|
1399
|
+
sendInit: (initMessage) => {
|
|
1400
|
+
iframe.contentWindow?.postMessage(
|
|
1401
|
+
{ type: "PASSKEY_INIT", ...initMessage },
|
|
1402
|
+
dialogOrigin
|
|
1403
|
+
);
|
|
1404
|
+
}
|
|
1405
|
+
});
|
|
1406
|
+
} else if (event.data?.type === "PASSKEY_CLOSE") {
|
|
1407
|
+
teardown();
|
|
1408
|
+
cleanup();
|
|
1409
|
+
resolve({ ready: false });
|
|
1410
|
+
}
|
|
1411
|
+
};
|
|
1412
|
+
const handleClose = () => {
|
|
1413
|
+
teardown();
|
|
1414
|
+
resolve({ ready: false });
|
|
1415
|
+
};
|
|
1416
|
+
const readyTimeout = setTimeout(() => {
|
|
1417
|
+
teardown();
|
|
1418
|
+
cleanup();
|
|
1419
|
+
resolve({ ready: false });
|
|
1420
|
+
}, 1e4);
|
|
1421
|
+
window.addEventListener("message", handleMessage);
|
|
1422
|
+
dialog.addEventListener("close", handleClose);
|
|
1423
|
+
});
|
|
1424
|
+
}
|
|
1425
|
+
/**
|
|
1426
|
+
* Prepare an intent by calling the orchestrator for a quote.
|
|
1427
|
+
* Returns the prepare response and the origin tier from the response header.
|
|
1428
|
+
*/
|
|
1429
|
+
async prepareIntent(requestBody) {
|
|
1430
|
+
try {
|
|
1431
|
+
const response = await fetch(`${this.config.providerUrl}/api/intent/prepare`, {
|
|
1432
|
+
method: "POST",
|
|
1433
|
+
headers: { "Content-Type": "application/json" },
|
|
1434
|
+
body: JSON.stringify(requestBody)
|
|
1435
|
+
});
|
|
1436
|
+
if (!response.ok) {
|
|
1437
|
+
const errorData = await response.json().catch(() => ({}));
|
|
1438
|
+
const errorMessage = errorData.error || "Failed to prepare intent";
|
|
1439
|
+
if (errorMessage.includes("User not found")) {
|
|
1440
|
+
localStorage.removeItem("1auth-user");
|
|
1441
|
+
}
|
|
1442
|
+
return {
|
|
1443
|
+
success: false,
|
|
1444
|
+
error: {
|
|
1445
|
+
code: errorMessage.includes("User not found") ? "USER_NOT_FOUND" : "PREPARE_FAILED",
|
|
1446
|
+
message: errorMessage
|
|
1447
|
+
}
|
|
1448
|
+
};
|
|
1449
|
+
}
|
|
1450
|
+
const tier = response.headers.get("X-Origin-Tier");
|
|
1451
|
+
return { success: true, data: await response.json(), tier };
|
|
1452
|
+
} catch (error) {
|
|
1453
|
+
return {
|
|
1454
|
+
success: false,
|
|
1455
|
+
error: {
|
|
1456
|
+
code: "NETWORK_ERROR",
|
|
1457
|
+
message: error instanceof Error ? error.message : "Network error"
|
|
1458
|
+
}
|
|
1459
|
+
};
|
|
1460
|
+
}
|
|
1461
|
+
}
|
|
1462
|
+
/**
|
|
1463
|
+
* Prepare a batch intent by calling the orchestrator for quotes on all intents.
|
|
1464
|
+
*/
|
|
1465
|
+
async prepareBatchIntent(requestBody) {
|
|
1466
|
+
try {
|
|
1467
|
+
const response = await fetch(`${this.config.providerUrl}/api/intent/batch-prepare`, {
|
|
1468
|
+
method: "POST",
|
|
1469
|
+
headers: { "Content-Type": "application/json" },
|
|
1470
|
+
body: JSON.stringify(requestBody)
|
|
1471
|
+
});
|
|
1472
|
+
if (!response.ok) {
|
|
1473
|
+
const errorData = await response.json().catch(() => ({}));
|
|
1474
|
+
const errorMessage = errorData.error || "Failed to prepare batch intent";
|
|
1475
|
+
if (errorMessage.includes("User not found")) {
|
|
1476
|
+
localStorage.removeItem("1auth-user");
|
|
1477
|
+
}
|
|
1478
|
+
return {
|
|
1479
|
+
success: false,
|
|
1480
|
+
error: errorMessage,
|
|
1481
|
+
failedIntents: errorData.failedIntents
|
|
1482
|
+
};
|
|
1483
|
+
}
|
|
1484
|
+
const tier = response.headers.get("X-Origin-Tier");
|
|
1485
|
+
return { success: true, data: await response.json(), tier };
|
|
1486
|
+
} catch {
|
|
1487
|
+
return { success: false, error: "Network error" };
|
|
1488
|
+
}
|
|
1489
|
+
}
|
|
1490
|
+
/**
|
|
1491
|
+
* Send a prepare error message to the dialog iframe.
|
|
1492
|
+
*/
|
|
1493
|
+
sendPrepareError(iframe, error) {
|
|
1494
|
+
const dialogOrigin = this.getDialogOrigin();
|
|
1495
|
+
iframe.contentWindow?.postMessage(
|
|
1496
|
+
{ type: "PASSKEY_PREPARE_ERROR", error },
|
|
1497
|
+
dialogOrigin
|
|
1498
|
+
);
|
|
1499
|
+
}
|
|
1167
1500
|
/**
|
|
1168
1501
|
* Poll for intent status
|
|
1169
1502
|
*
|
|
@@ -1475,6 +1808,7 @@ var OneAuthClient = class {
|
|
|
1475
1808
|
message: options.message,
|
|
1476
1809
|
challenge: options.challenge || options.message,
|
|
1477
1810
|
username: options.username,
|
|
1811
|
+
accountAddress: options.accountAddress,
|
|
1478
1812
|
description: options.description,
|
|
1479
1813
|
metadata: options.metadata
|
|
1480
1814
|
});
|
|
@@ -1566,6 +1900,7 @@ var OneAuthClient = class {
|
|
|
1566
1900
|
},
|
|
1567
1901
|
challenge: signedHash,
|
|
1568
1902
|
username: options.username,
|
|
1903
|
+
accountAddress: options.accountAddress,
|
|
1569
1904
|
description: options.description
|
|
1570
1905
|
});
|
|
1571
1906
|
if (!ready) {
|
|
@@ -1639,7 +1974,7 @@ var OneAuthClient = class {
|
|
|
1639
1974
|
iframe.style.borderRadius = "12px";
|
|
1640
1975
|
iframe.style.boxShadow = "0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)";
|
|
1641
1976
|
iframe.id = `passkey-embed-${requestId}`;
|
|
1642
|
-
iframe.allow = "publickey-credentials-get *; publickey-credentials-create
|
|
1977
|
+
iframe.allow = "publickey-credentials-get *; publickey-credentials-create *; identity-credentials-get";
|
|
1643
1978
|
iframe.onload = () => {
|
|
1644
1979
|
options.onReady?.();
|
|
1645
1980
|
};
|
|
@@ -1787,6 +2122,7 @@ var OneAuthClient = class {
|
|
|
1787
2122
|
const teardown = () => {
|
|
1788
2123
|
if (settled) return;
|
|
1789
2124
|
settled = true;
|
|
2125
|
+
clearTimeout(readyTimeout);
|
|
1790
2126
|
window.removeEventListener("message", handleMessage);
|
|
1791
2127
|
dialog.removeEventListener("close", handleClose);
|
|
1792
2128
|
};
|
|
@@ -1809,6 +2145,11 @@ var OneAuthClient = class {
|
|
|
1809
2145
|
teardown();
|
|
1810
2146
|
resolve(false);
|
|
1811
2147
|
};
|
|
2148
|
+
const readyTimeout = setTimeout(() => {
|
|
2149
|
+
teardown();
|
|
2150
|
+
cleanup();
|
|
2151
|
+
resolve(false);
|
|
2152
|
+
}, 1e4);
|
|
1812
2153
|
window.addEventListener("message", handleMessage);
|
|
1813
2154
|
dialog.addEventListener("close", handleClose);
|
|
1814
2155
|
});
|
|
@@ -1849,7 +2190,9 @@ var OneAuthClient = class {
|
|
|
1849
2190
|
border-radius: 14px;
|
|
1850
2191
|
border: none;
|
|
1851
2192
|
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.12), 0 2px 8px rgba(0, 0, 0, 0.08);
|
|
1852
|
-
transition:
|
|
2193
|
+
transition: height 0.15s ease-out;
|
|
2194
|
+
max-height: calc(100vh - 100px);
|
|
2195
|
+
max-height: calc(100dvh - 100px);
|
|
1853
2196
|
}
|
|
1854
2197
|
|
|
1855
2198
|
@media (min-width: 769px) {
|
|
@@ -1911,14 +2254,10 @@ var OneAuthClient = class {
|
|
|
1911
2254
|
const iframe = document.createElement("iframe");
|
|
1912
2255
|
iframe.setAttribute(
|
|
1913
2256
|
"allow",
|
|
1914
|
-
"publickey-credentials-get *; publickey-credentials-create *; clipboard-write"
|
|
2257
|
+
"publickey-credentials-get *; publickey-credentials-create *; clipboard-write; identity-credentials-get"
|
|
1915
2258
|
);
|
|
1916
2259
|
iframe.setAttribute("aria-label", "Passkey Authentication");
|
|
1917
2260
|
iframe.setAttribute("tabindex", "0");
|
|
1918
|
-
iframe.setAttribute(
|
|
1919
|
-
"sandbox",
|
|
1920
|
-
"allow-forms allow-scripts allow-same-origin allow-popups allow-popups-to-escape-sandbox"
|
|
1921
|
-
);
|
|
1922
2261
|
iframe.setAttribute("src", url);
|
|
1923
2262
|
iframe.setAttribute("title", "Passkey");
|
|
1924
2263
|
iframe.style.border = "none";
|
|
@@ -1928,10 +2267,8 @@ var OneAuthClient = class {
|
|
|
1928
2267
|
const handleMessage = (event) => {
|
|
1929
2268
|
if (event.origin !== hostUrl.origin) return;
|
|
1930
2269
|
if (event.data?.type === "PASSKEY_RESIZE") {
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
iframe.style.width = `${event.data.width}px`;
|
|
1934
|
-
}
|
|
2270
|
+
const maxHeight = window.innerHeight - 100;
|
|
2271
|
+
iframe.style.height = `${Math.min(event.data.height, maxHeight)}px`;
|
|
1935
2272
|
} else if (event.data?.type === "PASSKEY_DISCONNECT") {
|
|
1936
2273
|
localStorage.removeItem("1auth-user");
|
|
1937
2274
|
}
|
|
@@ -1949,7 +2286,10 @@ var OneAuthClient = class {
|
|
|
1949
2286
|
}
|
|
1950
2287
|
});
|
|
1951
2288
|
dialog.showModal();
|
|
2289
|
+
let cleanedUp = false;
|
|
1952
2290
|
const cleanup = () => {
|
|
2291
|
+
if (cleanedUp) return;
|
|
2292
|
+
cleanedUp = true;
|
|
1953
2293
|
window.removeEventListener("message", handleMessage);
|
|
1954
2294
|
document.removeEventListener("keydown", handleEscape);
|
|
1955
2295
|
dialog.close();
|
|
@@ -1981,22 +2321,11 @@ var OneAuthClient = class {
|
|
|
1981
2321
|
if (data.success) {
|
|
1982
2322
|
resolve({
|
|
1983
2323
|
success: true,
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
success: false,
|
|
1990
|
-
error: data.error
|
|
1991
|
-
});
|
|
1992
|
-
}
|
|
1993
|
-
} else if (data?.type === "PASSKEY_REGISTER_RESULT") {
|
|
1994
|
-
window.removeEventListener("message", handleMessage);
|
|
1995
|
-
cleanup();
|
|
1996
|
-
if (data.success) {
|
|
1997
|
-
resolve({
|
|
1998
|
-
success: true,
|
|
1999
|
-
username: data.data?.username
|
|
2324
|
+
user: {
|
|
2325
|
+
id: data.data?.user?.id,
|
|
2326
|
+
username: data.data?.username,
|
|
2327
|
+
address: data.data?.address
|
|
2328
|
+
}
|
|
2000
2329
|
});
|
|
2001
2330
|
} else {
|
|
2002
2331
|
resolve({
|
|
@@ -2055,8 +2384,11 @@ var OneAuthClient = class {
|
|
|
2055
2384
|
if (data.success) {
|
|
2056
2385
|
resolve({
|
|
2057
2386
|
success: true,
|
|
2058
|
-
|
|
2059
|
-
|
|
2387
|
+
user: {
|
|
2388
|
+
id: data.data?.user?.id,
|
|
2389
|
+
username: data.data?.username,
|
|
2390
|
+
address: data.data?.address
|
|
2391
|
+
}
|
|
2060
2392
|
});
|
|
2061
2393
|
} else {
|
|
2062
2394
|
resolve({
|
|
@@ -2064,14 +2396,43 @@ var OneAuthClient = class {
|
|
|
2064
2396
|
error: data.error
|
|
2065
2397
|
});
|
|
2066
2398
|
}
|
|
2067
|
-
} else if (data?.type === "
|
|
2399
|
+
} else if (data?.type === "PASSKEY_CLOSE") {
|
|
2068
2400
|
clearInterval(pollTimer);
|
|
2069
2401
|
window.removeEventListener("message", handleMessage);
|
|
2070
2402
|
popup?.close();
|
|
2403
|
+
resolve({
|
|
2404
|
+
success: false,
|
|
2405
|
+
error: {
|
|
2406
|
+
code: "USER_CANCELLED",
|
|
2407
|
+
message: "Authentication was cancelled"
|
|
2408
|
+
}
|
|
2409
|
+
});
|
|
2410
|
+
}
|
|
2411
|
+
};
|
|
2412
|
+
window.addEventListener("message", handleMessage);
|
|
2413
|
+
});
|
|
2414
|
+
}
|
|
2415
|
+
waitForAuthenticateResponse(_dialog, _iframe, cleanup) {
|
|
2416
|
+
const dialogOrigin = this.getDialogOrigin();
|
|
2417
|
+
return new Promise((resolve) => {
|
|
2418
|
+
const handleMessage = (event) => {
|
|
2419
|
+
if (event.origin !== dialogOrigin) return;
|
|
2420
|
+
const data = event.data;
|
|
2421
|
+
if (data?.type === "PASSKEY_AUTHENTICATE_RESULT") {
|
|
2422
|
+
window.removeEventListener("message", handleMessage);
|
|
2423
|
+
cleanup();
|
|
2071
2424
|
if (data.success) {
|
|
2072
2425
|
resolve({
|
|
2073
2426
|
success: true,
|
|
2074
|
-
|
|
2427
|
+
user: {
|
|
2428
|
+
id: data.data?.user?.id,
|
|
2429
|
+
username: data.data?.username,
|
|
2430
|
+
address: data.data?.accountAddress
|
|
2431
|
+
},
|
|
2432
|
+
challenge: data.data?.signature ? {
|
|
2433
|
+
signature: data.data.signature,
|
|
2434
|
+
signedHash: data.data.signedHash
|
|
2435
|
+
} : void 0
|
|
2075
2436
|
});
|
|
2076
2437
|
} else {
|
|
2077
2438
|
resolve({
|
|
@@ -2080,9 +2441,8 @@ var OneAuthClient = class {
|
|
|
2080
2441
|
});
|
|
2081
2442
|
}
|
|
2082
2443
|
} else if (data?.type === "PASSKEY_CLOSE") {
|
|
2083
|
-
clearInterval(pollTimer);
|
|
2084
2444
|
window.removeEventListener("message", handleMessage);
|
|
2085
|
-
|
|
2445
|
+
cleanup();
|
|
2086
2446
|
resolve({
|
|
2087
2447
|
success: false,
|
|
2088
2448
|
error: {
|
|
@@ -2095,27 +2455,28 @@ var OneAuthClient = class {
|
|
|
2095
2455
|
window.addEventListener("message", handleMessage);
|
|
2096
2456
|
});
|
|
2097
2457
|
}
|
|
2098
|
-
|
|
2458
|
+
waitForConnectResponse(_dialog, _iframe, cleanup) {
|
|
2099
2459
|
const dialogOrigin = this.getDialogOrigin();
|
|
2100
2460
|
return new Promise((resolve) => {
|
|
2101
2461
|
const handleMessage = (event) => {
|
|
2102
2462
|
if (event.origin !== dialogOrigin) return;
|
|
2103
2463
|
const data = event.data;
|
|
2104
|
-
if (data?.type === "
|
|
2464
|
+
if (data?.type === "PASSKEY_CONNECT_RESULT") {
|
|
2105
2465
|
window.removeEventListener("message", handleMessage);
|
|
2106
2466
|
cleanup();
|
|
2107
2467
|
if (data.success) {
|
|
2108
2468
|
resolve({
|
|
2109
2469
|
success: true,
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2470
|
+
user: {
|
|
2471
|
+
username: data.data?.username,
|
|
2472
|
+
address: data.data?.address
|
|
2473
|
+
},
|
|
2474
|
+
autoConnected: data.data?.autoConnected
|
|
2115
2475
|
});
|
|
2116
2476
|
} else {
|
|
2117
2477
|
resolve({
|
|
2118
2478
|
success: false,
|
|
2479
|
+
action: data.data?.action,
|
|
2119
2480
|
error: data.error
|
|
2120
2481
|
});
|
|
2121
2482
|
}
|
|
@@ -2124,9 +2485,10 @@ var OneAuthClient = class {
|
|
|
2124
2485
|
cleanup();
|
|
2125
2486
|
resolve({
|
|
2126
2487
|
success: false,
|
|
2488
|
+
action: "cancel",
|
|
2127
2489
|
error: {
|
|
2128
2490
|
code: "USER_CANCELLED",
|
|
2129
|
-
message: "
|
|
2491
|
+
message: "Connection was cancelled"
|
|
2130
2492
|
}
|
|
2131
2493
|
});
|
|
2132
2494
|
}
|
|
@@ -2134,26 +2496,28 @@ var OneAuthClient = class {
|
|
|
2134
2496
|
window.addEventListener("message", handleMessage);
|
|
2135
2497
|
});
|
|
2136
2498
|
}
|
|
2137
|
-
|
|
2499
|
+
waitForConsentResponse(_dialog, _iframe, cleanup) {
|
|
2138
2500
|
const dialogOrigin = this.getDialogOrigin();
|
|
2139
2501
|
return new Promise((resolve) => {
|
|
2140
2502
|
const handleMessage = (event) => {
|
|
2141
2503
|
if (event.origin !== dialogOrigin) return;
|
|
2142
2504
|
const data = event.data;
|
|
2143
|
-
if (data?.type === "
|
|
2505
|
+
if (data?.type === "PASSKEY_CONSENT_RESULT") {
|
|
2144
2506
|
window.removeEventListener("message", handleMessage);
|
|
2145
2507
|
cleanup();
|
|
2146
2508
|
if (data.success) {
|
|
2147
2509
|
resolve({
|
|
2148
2510
|
success: true,
|
|
2149
|
-
|
|
2150
|
-
|
|
2511
|
+
data: data.data,
|
|
2512
|
+
grantedAt: data.data?.grantedAt
|
|
2151
2513
|
});
|
|
2152
2514
|
} else {
|
|
2153
2515
|
resolve({
|
|
2154
2516
|
success: false,
|
|
2155
|
-
|
|
2156
|
-
|
|
2517
|
+
error: data.error ?? {
|
|
2518
|
+
code: "USER_REJECTED",
|
|
2519
|
+
message: "User denied the consent request"
|
|
2520
|
+
}
|
|
2157
2521
|
});
|
|
2158
2522
|
}
|
|
2159
2523
|
} else if (data?.type === "PASSKEY_CLOSE") {
|
|
@@ -2161,10 +2525,9 @@ var OneAuthClient = class {
|
|
|
2161
2525
|
cleanup();
|
|
2162
2526
|
resolve({
|
|
2163
2527
|
success: false,
|
|
2164
|
-
action: "cancel",
|
|
2165
2528
|
error: {
|
|
2166
2529
|
code: "USER_CANCELLED",
|
|
2167
|
-
message: "
|
|
2530
|
+
message: "User closed the dialog"
|
|
2168
2531
|
}
|
|
2169
2532
|
});
|
|
2170
2533
|
}
|
|
@@ -2380,7 +2743,7 @@ function createOneAuthProvider(options) {
|
|
|
2380
2743
|
const raw = localStorage.getItem(storageKey);
|
|
2381
2744
|
if (!raw) return null;
|
|
2382
2745
|
const parsed = JSON.parse(raw);
|
|
2383
|
-
if (!parsed?.
|
|
2746
|
+
if (!parsed?.address) return null;
|
|
2384
2747
|
return parsed;
|
|
2385
2748
|
} catch {
|
|
2386
2749
|
return null;
|
|
@@ -2416,18 +2779,26 @@ function createOneAuthProvider(options) {
|
|
|
2416
2779
|
}
|
|
2417
2780
|
const connectResult = await client.connectWithModal();
|
|
2418
2781
|
let username;
|
|
2419
|
-
|
|
2420
|
-
|
|
2782
|
+
let address;
|
|
2783
|
+
if (connectResult.success) {
|
|
2784
|
+
username = connectResult.user?.username;
|
|
2785
|
+
address = connectResult.user?.address;
|
|
2421
2786
|
} else if (connectResult.action === "switch") {
|
|
2422
2787
|
const authResult = await client.authWithModal();
|
|
2423
|
-
if (!authResult.success
|
|
2788
|
+
if (!authResult.success) {
|
|
2424
2789
|
throw new Error(authResult.error?.message || "Authentication failed");
|
|
2425
2790
|
}
|
|
2426
|
-
username = authResult.username;
|
|
2791
|
+
username = authResult.user?.username;
|
|
2792
|
+
address = authResult.user?.address;
|
|
2427
2793
|
} else {
|
|
2428
2794
|
throw new Error(connectResult.error?.message || "Connection cancelled");
|
|
2429
2795
|
}
|
|
2430
|
-
|
|
2796
|
+
if (!address && username) {
|
|
2797
|
+
address = await resolveAccountAddress(username);
|
|
2798
|
+
}
|
|
2799
|
+
if (!address) {
|
|
2800
|
+
throw new Error("No account address available");
|
|
2801
|
+
}
|
|
2431
2802
|
setStoredUser({ username, address });
|
|
2432
2803
|
emit("accountsChanged", [address]);
|
|
2433
2804
|
emit("connect", { chainId: (0, import_viem4.numberToHex)(chainId) });
|
|
@@ -2442,11 +2813,11 @@ function createOneAuthProvider(options) {
|
|
|
2442
2813
|
const stored = getStoredUser();
|
|
2443
2814
|
if (stored) return stored;
|
|
2444
2815
|
const [address] = await connect();
|
|
2445
|
-
|
|
2446
|
-
if (!username || !address) {
|
|
2816
|
+
if (!address) {
|
|
2447
2817
|
throw new Error("Failed to resolve user session");
|
|
2448
2818
|
}
|
|
2449
|
-
|
|
2819
|
+
const user = getStoredUser();
|
|
2820
|
+
return user || { address };
|
|
2450
2821
|
};
|
|
2451
2822
|
const parseChainId = (value) => {
|
|
2452
2823
|
if (typeof value === "number") return value;
|
|
@@ -2504,9 +2875,13 @@ function createOneAuthProvider(options) {
|
|
|
2504
2875
|
}
|
|
2505
2876
|
};
|
|
2506
2877
|
const signMessage = async (message) => {
|
|
2507
|
-
const
|
|
2878
|
+
const user = await ensureUser();
|
|
2879
|
+
if (!user.username && !user.address) {
|
|
2880
|
+
throw new Error("Username or address required for signing.");
|
|
2881
|
+
}
|
|
2508
2882
|
const result = await client.signMessage({
|
|
2509
|
-
username,
|
|
2883
|
+
username: user.username,
|
|
2884
|
+
accountAddress: user.address,
|
|
2510
2885
|
message
|
|
2511
2886
|
});
|
|
2512
2887
|
if (!result.success || !result.signature) {
|
|
@@ -2515,10 +2890,14 @@ function createOneAuthProvider(options) {
|
|
|
2515
2890
|
return encodeWebAuthnSignature(result.signature);
|
|
2516
2891
|
};
|
|
2517
2892
|
const signTypedData = async (typedData) => {
|
|
2518
|
-
const
|
|
2893
|
+
const user = await ensureUser();
|
|
2894
|
+
if (!user.username && !user.address) {
|
|
2895
|
+
throw new Error("Username or address required for signing.");
|
|
2896
|
+
}
|
|
2519
2897
|
const data = typeof typedData === "string" ? JSON.parse(typedData) : typedData;
|
|
2520
2898
|
const result = await client.signTypedData({
|
|
2521
|
-
username,
|
|
2899
|
+
username: user.username,
|
|
2900
|
+
accountAddress: user.address,
|
|
2522
2901
|
domain: data.domain,
|
|
2523
2902
|
types: data.types,
|
|
2524
2903
|
primaryType: data.primaryType,
|
|
@@ -2533,11 +2912,15 @@ function createOneAuthProvider(options) {
|
|
|
2533
2912
|
if (!options.signIntent) {
|
|
2534
2913
|
return {
|
|
2535
2914
|
username: payload.username,
|
|
2915
|
+
accountAddress: payload.accountAddress,
|
|
2536
2916
|
targetChain: payload.targetChain,
|
|
2537
2917
|
calls: payload.calls,
|
|
2538
2918
|
tokenRequests: payload.tokenRequests
|
|
2539
2919
|
};
|
|
2540
2920
|
}
|
|
2921
|
+
if (!payload.username) {
|
|
2922
|
+
throw new Error("Username required for signed intents. Set a username first.");
|
|
2923
|
+
}
|
|
2541
2924
|
const signedIntent = await options.signIntent({
|
|
2542
2925
|
username: payload.username,
|
|
2543
2926
|
accountAddress: payload.accountAddress,
|
|
@@ -2663,10 +3046,13 @@ function createOneAuthProvider(options) {
|
|
|
2663
3046
|
return capabilities;
|
|
2664
3047
|
}
|
|
2665
3048
|
case "wallet_getAssets": {
|
|
2666
|
-
const
|
|
3049
|
+
const user = await ensureUser();
|
|
3050
|
+
if (!user.username) {
|
|
3051
|
+
throw new Error("Username required to fetch assets. Set a username first.");
|
|
3052
|
+
}
|
|
2667
3053
|
const clientId = client.getClientId();
|
|
2668
3054
|
const response = await fetch(
|
|
2669
|
-
`${client.getProviderUrl()}/api/users/${encodeURIComponent(username)}/portfolio`,
|
|
3055
|
+
`${client.getProviderUrl()}/api/users/${encodeURIComponent(user.username)}/portfolio`,
|
|
2670
3056
|
{
|
|
2671
3057
|
headers: clientId ? { "x-client-id": clientId } : {}
|
|
2672
3058
|
}
|
|
@@ -2776,7 +3162,6 @@ function createOneAuthProvider(options) {
|
|
|
2776
3162
|
disconnect
|
|
2777
3163
|
};
|
|
2778
3164
|
}
|
|
2779
|
-
var createPasskeyProvider = createOneAuthProvider;
|
|
2780
3165
|
|
|
2781
3166
|
// src/account.ts
|
|
2782
3167
|
var import_viem5 = require("viem");
|
|
@@ -3447,7 +3832,6 @@ function BatchQueueWidget({ onSignAll }) {
|
|
|
3447
3832
|
// src/verify.ts
|
|
3448
3833
|
var import_viem7 = require("viem");
|
|
3449
3834
|
var ETHEREUM_MESSAGE_PREFIX = "Ethereum Signed Message:\n";
|
|
3450
|
-
var PASSKEY_MESSAGE_PREFIX = ETHEREUM_MESSAGE_PREFIX;
|
|
3451
3835
|
function hashMessage2(message) {
|
|
3452
3836
|
const prefixed = ETHEREUM_MESSAGE_PREFIX + message.length.toString() + message;
|
|
3453
3837
|
return (0, import_viem7.keccak256)((0, import_viem7.toBytes)(prefixed));
|
|
@@ -3463,11 +3847,8 @@ function verifyMessageHash(message, signedHash) {
|
|
|
3463
3847
|
BatchQueueWidget,
|
|
3464
3848
|
ETHEREUM_MESSAGE_PREFIX,
|
|
3465
3849
|
OneAuthClient,
|
|
3466
|
-
PASSKEY_MESSAGE_PREFIX,
|
|
3467
|
-
PasskeyProviderClient,
|
|
3468
3850
|
createOneAuthProvider,
|
|
3469
3851
|
createPasskeyAccount,
|
|
3470
|
-
createPasskeyProvider,
|
|
3471
3852
|
createPasskeyWalletClient,
|
|
3472
3853
|
encodeWebAuthnSignature,
|
|
3473
3854
|
getAllSupportedChainsAndTokens,
|