@moon-x/core 0.3.0 → 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.
Files changed (44) hide show
  1. package/README.md +1 -1
  2. package/dist/{chunk-CDT4MC7S.mjs → chunk-I56GRKAG.mjs} +19 -39
  3. package/dist/{chunk-VVL65GIB.mjs → chunk-JU5MWLXH.mjs} +14 -0
  4. package/dist/index.d.mts +2 -3
  5. package/dist/index.d.ts +2 -3
  6. package/dist/index.js +14 -0
  7. package/dist/index.mjs +1 -1
  8. package/dist/{interfaces-Bm7fGOAI.d.ts → interfaces-1vfik3Ef.d.ts} +24 -1
  9. package/dist/{interfaces-CYtJHALV.d.mts → interfaces-BdIeMGGD.d.mts} +24 -1
  10. package/dist/lib/index.d.mts +33 -3
  11. package/dist/lib/index.d.ts +33 -3
  12. package/dist/lib/index.js +23 -47
  13. package/dist/lib/index.mjs +7 -15
  14. package/dist/passkey-cache-WnDFQ-v4.d.mts +26 -0
  15. package/dist/passkey-cache-WnDFQ-v4.d.ts +26 -0
  16. package/dist/{post-message-CmgAfkOS.d.mts → post-message-Z6cLf0mS.d.mts} +3 -0
  17. package/dist/{post-message-CmgAfkOS.d.ts → post-message-Z6cLf0mS.d.ts} +3 -0
  18. package/dist/react/ethereum.d.mts +0 -1
  19. package/dist/react/ethereum.d.ts +0 -1
  20. package/dist/react/index.d.mts +41 -3
  21. package/dist/react/index.d.ts +41 -3
  22. package/dist/react/index.js +138 -12
  23. package/dist/react/index.mjs +137 -12
  24. package/dist/react/solana.d.mts +0 -1
  25. package/dist/react/solana.d.ts +0 -1
  26. package/dist/sdk/index.d.mts +87 -16
  27. package/dist/sdk/index.d.ts +87 -16
  28. package/dist/sdk/index.js +456 -102
  29. package/dist/sdk/index.mjs +440 -80
  30. package/dist/types/index.d.mts +135 -12
  31. package/dist/types/index.d.ts +135 -12
  32. package/dist/utils/index.d.mts +1 -1
  33. package/dist/utils/index.d.ts +1 -1
  34. package/dist/utils/index.js +14 -0
  35. package/dist/utils/index.mjs +1 -1
  36. package/dist/web/index.d.mts +2 -2
  37. package/dist/web/index.d.ts +2 -2
  38. package/dist/web/index.js +29 -0
  39. package/dist/web/index.mjs +30 -1
  40. package/package.json +3 -1
  41. package/dist/chain-C9dvKXUY.d.mts +0 -48
  42. package/dist/chain-C9dvKXUY.d.ts +0 -48
  43. package/dist/passkey-cache-B9PT3AWX.d.mts +0 -47
  44. package/dist/passkey-cache-B9PT3AWX.d.ts +0 -47
package/dist/sdk/index.js CHANGED
@@ -30,12 +30,16 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/sdk/index.ts
31
31
  var sdk_exports = {};
32
32
  __export(sdk_exports, {
33
+ EphemeralSignerSignError: () => EphemeralSignerSignError,
33
34
  assertPasskeyInParent: () => assertPasskeyInParent,
35
+ flattenPresenceTokens: () => flattenPresenceTokens,
34
36
  getHeadlessAuthenticationMethods: () => getHeadlessAuthenticationMethods,
35
37
  getHeadlessEthereumMethods: () => getHeadlessEthereumMethods,
36
38
  getHeadlessGeneralMethods: () => getHeadlessGeneralMethods,
37
39
  getHeadlessSolanaMethods: () => getHeadlessSolanaMethods,
38
- getPresenceToken: () => getPresenceToken
40
+ getInternalPresenceTokens: () => getInternalPresenceTokens,
41
+ getPresenceToken: () => getPresenceToken,
42
+ signWithEphemeralSigner: () => signWithEphemeralSigner
39
43
  });
40
44
  module.exports = __toCommonJS(sdk_exports);
41
45
 
@@ -66,34 +70,6 @@ var toB64url = (bytes) => {
66
70
  return btoa(str).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
67
71
  };
68
72
 
69
- // src/lib/passkey/passkey-cache.ts
70
- var cacheTtlMs = 0;
71
- var cache = null;
72
- var clearParentAssertCache = () => {
73
- cache = null;
74
- };
75
- var readParentAssertCache = () => {
76
- if (cacheTtlMs <= 0) return null;
77
- if (!cache) return null;
78
- if (Date.now() - cache.ts >= cacheTtlMs) return null;
79
- return {
80
- userHandleB64url: cache.userHandleB64url,
81
- credentialIdB64url: cache.credentialIdB64url
82
- };
83
- };
84
- var writeParentAssertCache = (entry) => {
85
- if (cacheTtlMs <= 0) return;
86
- cache = { ...entry, ts: Date.now() };
87
- };
88
- var withClearOnFailure = async (fn) => {
89
- try {
90
- return await fn();
91
- } catch (error) {
92
- clearParentAssertCache();
93
- throw error;
94
- }
95
- };
96
-
97
73
  // src/lib/ethereum/chains.ts
98
74
  var import_viem = require("viem");
99
75
 
@@ -270,6 +246,20 @@ var PostMessageMethod = {
270
246
  // dispatcher boring.
271
247
  SIGN_HASH: "SIGN_HASH",
272
248
  SIGN_7702_AUTHORIZATION: "SIGN_7702_AUTHORIZATION",
249
+ // Provision a SES (Secure Ephemeral Signer) over one or more of the
250
+ // user's MPC wallets. Iframe verifies the Nitro attestation, decrypts
251
+ // the selected keyshares, HPKE-seals them to the verified enclave
252
+ // pubkey, and returns a freshly-generated Ed25519 signer keypair.
253
+ // MoonX never persists the private key — the parent must hand it to
254
+ // the user immediately.
255
+ PROVISION_EPHEMERAL_SIGNER: "PROVISION_EPHEMERAL_SIGNER",
256
+ // List the user's active provisioned ephemeral signers from the
257
+ // wallets backend. Read-only; doesn't touch SES or the enclave.
258
+ LIST_EPHEMERAL_SIGNERS: "LIST_EPHEMERAL_SIGNERS",
259
+ // Soft-revoke a previously-provisioned ephemeral signer. The wallets
260
+ // backend updates revoked_at locally and forwards the revoke to SES
261
+ // so the enclave drops the policy.
262
+ REVOKE_EPHEMERAL_SIGNER: "REVOKE_EPHEMERAL_SIGNER",
273
263
  VERIFY_EMAIL_OTP: "VERIFY_EMAIL_OTP",
274
264
  VERIFY_OAUTH: "VERIFY_OAUTH",
275
265
  START_OAUTH: "START_OAUTH",
@@ -317,13 +307,8 @@ var assertPasskeyInParent = async ({
317
307
  transport,
318
308
  passkey,
319
309
  publishableKey,
320
- requireFreshAssertion = false,
321
310
  validateCredentialInAllowList = false
322
311
  }) => {
323
- if (!requireFreshAssertion) {
324
- const cached = readParentAssertCache();
325
- if (cached) return cached;
326
- }
327
312
  const dekInfo = await transport.send(
328
313
  PostMessageType.AUTH,
329
314
  PostMessageMethod.GET_DEK_INFO,
@@ -347,12 +332,10 @@ var assertPasskeyInParent = async ({
347
332
  if (validateCredentialInAllowList && !allowList.includes(credential.rawIdB64url)) {
348
333
  throw new Error("unknown_passkey_for_this_account");
349
334
  }
350
- const result = {
335
+ return {
351
336
  userHandleB64url: credential.userHandleB64url,
352
337
  credentialIdB64url: credential.rawIdB64url
353
338
  };
354
- writeParentAssertCache(result);
355
- return result;
356
339
  };
357
340
 
358
341
  // src/sdk/get-presence-token.ts
@@ -384,19 +367,79 @@ var getPresenceToken = async ({
384
367
  };
385
368
  };
386
369
 
370
+ // src/sdk/get-internal-presence-tokens.ts
371
+ var getInternalPresenceTokens = async ({
372
+ transport,
373
+ passkey,
374
+ publishableKey,
375
+ relyingPartyOrigin,
376
+ scopes,
377
+ scopeCounts
378
+ }) => {
379
+ const { token, optionsJSON } = await transport.send(
380
+ PostMessageType.AUTH,
381
+ PostMessageMethod.PASSKEY_PRESENCE_BEGIN,
382
+ { publishableKey, relyingPartyOrigin }
383
+ );
384
+ const { response, userHandleB64url, credentialIdB64url } = await passkey.assertForInternalPresence({ optionsJSON });
385
+ const verifyPayload = {
386
+ publishableKey,
387
+ relyingPartyOrigin,
388
+ token,
389
+ response,
390
+ purpose: "internal"
391
+ };
392
+ if (scopes && scopes.length > 0) verifyPayload.scopes = scopes;
393
+ if (scopeCounts && Object.keys(scopeCounts).length > 0) {
394
+ verifyPayload.scope_counts = scopeCounts;
395
+ }
396
+ const verify = await transport.send(
397
+ PostMessageType.AUTH,
398
+ PostMessageMethod.PASSKEY_PRESENCE_VERIFY,
399
+ verifyPayload
400
+ );
401
+ const out = {};
402
+ for (const [scope, t] of Object.entries(verify.tokens ?? {})) {
403
+ out[scope] = { token: t.token, expiresAt: t.expires_at };
404
+ }
405
+ const outBatches = {};
406
+ for (const [scope, batch] of Object.entries(verify.token_batches ?? {})) {
407
+ outBatches[scope] = batch.map((t) => ({
408
+ token: t.token,
409
+ expiresAt: t.expires_at
410
+ }));
411
+ }
412
+ return {
413
+ tokens: out,
414
+ tokenBatches: outBatches,
415
+ userHandleB64url,
416
+ credentialIdB64url
417
+ };
418
+ };
419
+ var flattenPresenceTokens = (result) => {
420
+ const out = {};
421
+ for (const [scope, t] of Object.entries(result.tokens)) {
422
+ out[scope] = t.token;
423
+ }
424
+ return out;
425
+ };
426
+
387
427
  // src/sdk/headless-ethereum.ts
428
+ var SCOPES_SIGN = ["keyshare_read", "sign"];
388
429
  var getHeadlessEthereumMethods = ({
389
430
  transport,
390
431
  passkey,
391
- publishableKey
432
+ publishableKey,
433
+ relyingPartyOrigin
392
434
  }) => ({
393
- signEthereumMessageHeadless: async (params) => withClearOnFailure(async () => {
435
+ signEthereumMessageHeadless: async (params) => {
394
436
  if (!transport.isReady()) throw new Error("SDK not ready");
395
- const { userHandleB64url, credentialIdB64url } = await assertPasskeyInParent({
437
+ const { userHandleB64url, credentialIdB64url, tokens } = await getInternalPresenceTokens({
396
438
  transport,
397
439
  passkey,
398
440
  publishableKey,
399
- requireFreshAssertion: params.requireFreshAssertion
441
+ relyingPartyOrigin,
442
+ scopes: SCOPES_SIGN
400
443
  });
401
444
  return transport.send(
402
445
  PostMessageType.WALLET,
@@ -407,17 +450,23 @@ var getHeadlessEthereumMethods = ({
407
450
  wallet: params.wallet,
408
451
  uiOptions: params.options?.uiOptions,
409
452
  userHandleB64url,
410
- credentialIdB64url
453
+ credentialIdB64url,
454
+ presenceTokens: flattenPresenceTokens({
455
+ tokens,
456
+ userHandleB64url,
457
+ credentialIdB64url
458
+ })
411
459
  }
412
460
  );
413
- }),
414
- signEthereumTransactionHeadless: async (params) => withClearOnFailure(async () => {
461
+ },
462
+ signEthereumTransactionHeadless: async (params) => {
415
463
  if (!transport.isReady()) throw new Error("SDK not ready");
416
- const { userHandleB64url, credentialIdB64url } = await assertPasskeyInParent({
464
+ const { userHandleB64url, credentialIdB64url, tokens } = await getInternalPresenceTokens({
417
465
  transport,
418
466
  passkey,
419
467
  publishableKey,
420
- requireFreshAssertion: params.requireFreshAssertion
468
+ relyingPartyOrigin,
469
+ scopes: SCOPES_SIGN
421
470
  });
422
471
  return transport.send(
423
472
  PostMessageType.WALLET,
@@ -429,17 +478,23 @@ var getHeadlessEthereumMethods = ({
429
478
  wallet: params.wallet,
430
479
  options: params.options,
431
480
  userHandleB64url,
432
- credentialIdB64url
481
+ credentialIdB64url,
482
+ presenceTokens: flattenPresenceTokens({
483
+ tokens,
484
+ userHandleB64url,
485
+ credentialIdB64url
486
+ })
433
487
  }
434
488
  );
435
- }),
436
- signEthereumTypedDataHeadless: async (params) => withClearOnFailure(async () => {
489
+ },
490
+ signEthereumTypedDataHeadless: async (params) => {
437
491
  if (!transport.isReady()) throw new Error("SDK not ready");
438
- const { userHandleB64url, credentialIdB64url } = await assertPasskeyInParent({
492
+ const { userHandleB64url, credentialIdB64url, tokens } = await getInternalPresenceTokens({
439
493
  transport,
440
494
  passkey,
441
495
  publishableKey,
442
- requireFreshAssertion: params.requireFreshAssertion
496
+ relyingPartyOrigin,
497
+ scopes: SCOPES_SIGN
443
498
  });
444
499
  return transport.send(
445
500
  PostMessageType.WALLET,
@@ -453,17 +508,23 @@ var getHeadlessEthereumMethods = ({
453
508
  wallet: params.wallet,
454
509
  options: params.options,
455
510
  userHandleB64url,
456
- credentialIdB64url
511
+ credentialIdB64url,
512
+ presenceTokens: flattenPresenceTokens({
513
+ tokens,
514
+ userHandleB64url,
515
+ credentialIdB64url
516
+ })
457
517
  }
458
518
  );
459
- }),
460
- signEthereumHashHeadless: async (params) => withClearOnFailure(async () => {
519
+ },
520
+ signEthereumHashHeadless: async (params) => {
461
521
  if (!transport.isReady()) throw new Error("SDK not ready");
462
- const { userHandleB64url, credentialIdB64url } = await assertPasskeyInParent({
522
+ const { userHandleB64url, credentialIdB64url, tokens } = await getInternalPresenceTokens({
463
523
  transport,
464
524
  passkey,
465
525
  publishableKey,
466
- requireFreshAssertion: params.requireFreshAssertion
526
+ relyingPartyOrigin,
527
+ scopes: SCOPES_SIGN
467
528
  });
468
529
  return transport.send(
469
530
  PostMessageType.WALLET,
@@ -474,17 +535,23 @@ var getHeadlessEthereumMethods = ({
474
535
  wallet: params.wallet,
475
536
  options: params.options,
476
537
  userHandleB64url,
477
- credentialIdB64url
538
+ credentialIdB64url,
539
+ presenceTokens: flattenPresenceTokens({
540
+ tokens,
541
+ userHandleB64url,
542
+ credentialIdB64url
543
+ })
478
544
  }
479
545
  );
480
- }),
481
- signEthereum7702AuthorizationHeadless: async (params) => withClearOnFailure(async () => {
546
+ },
547
+ signEthereum7702AuthorizationHeadless: async (params) => {
482
548
  if (!transport.isReady()) throw new Error("SDK not ready");
483
- const { userHandleB64url, credentialIdB64url } = await assertPasskeyInParent({
549
+ const { userHandleB64url, credentialIdB64url, tokens } = await getInternalPresenceTokens({
484
550
  transport,
485
551
  passkey,
486
552
  publishableKey,
487
- requireFreshAssertion: params.requireFreshAssertion
553
+ relyingPartyOrigin,
554
+ scopes: SCOPES_SIGN
488
555
  });
489
556
  return transport.send(
490
557
  PostMessageType.WALLET,
@@ -498,17 +565,23 @@ var getHeadlessEthereumMethods = ({
498
565
  wallet: params.wallet,
499
566
  options: params.options,
500
567
  userHandleB64url,
501
- credentialIdB64url
568
+ credentialIdB64url,
569
+ presenceTokens: flattenPresenceTokens({
570
+ tokens,
571
+ userHandleB64url,
572
+ credentialIdB64url
573
+ })
502
574
  }
503
575
  );
504
- }),
505
- sendEthereumTransactionHeadless: async (params) => withClearOnFailure(async () => {
576
+ },
577
+ sendEthereumTransactionHeadless: async (params) => {
506
578
  if (!transport.isReady()) throw new Error("SDK not ready");
507
- const { userHandleB64url, credentialIdB64url } = await assertPasskeyInParent({
579
+ const { userHandleB64url, credentialIdB64url, tokens } = await getInternalPresenceTokens({
508
580
  transport,
509
581
  passkey,
510
582
  publishableKey,
511
- requireFreshAssertion: params.requireFreshAssertion
583
+ relyingPartyOrigin,
584
+ scopes: SCOPES_SIGN
512
585
  });
513
586
  const serializedTransaction = await serializeEthereumTransaction(
514
587
  params.transaction
@@ -522,7 +595,12 @@ var getHeadlessEthereumMethods = ({
522
595
  wallet: params.wallet,
523
596
  options: params.options,
524
597
  userHandleB64url,
525
- credentialIdB64url
598
+ credentialIdB64url,
599
+ presenceTokens: flattenPresenceTokens({
600
+ tokens,
601
+ userHandleB64url,
602
+ credentialIdB64url
603
+ })
526
604
  }
527
605
  );
528
606
  if (!signed.serializedSigned) {
@@ -535,7 +613,7 @@ var getHeadlessEthereumMethods = ({
535
613
  signed.serializedSigned
536
614
  );
537
615
  return { hash };
538
- }),
616
+ },
539
617
  getEthereumBalance: async (params) => {
540
618
  if (!transport.isReady()) throw new Error("SDK not ready");
541
619
  return transport.send(
@@ -571,18 +649,21 @@ var getHeadlessEthereumMethods = ({
571
649
  });
572
650
 
573
651
  // src/sdk/headless-solana.ts
652
+ var SCOPES_SIGN2 = ["keyshare_read", "sign"];
574
653
  var getHeadlessSolanaMethods = ({
575
654
  transport,
576
655
  passkey,
577
- publishableKey
656
+ publishableKey,
657
+ relyingPartyOrigin
578
658
  }) => ({
579
- signSolanaMessageHeadless: async (params) => withClearOnFailure(async () => {
659
+ signSolanaMessageHeadless: async (params) => {
580
660
  if (!transport.isReady()) throw new Error("SDK not ready");
581
- const { userHandleB64url, credentialIdB64url } = await assertPasskeyInParent({
661
+ const { userHandleB64url, credentialIdB64url, tokens } = await getInternalPresenceTokens({
582
662
  transport,
583
663
  passkey,
584
664
  publishableKey,
585
- requireFreshAssertion: params.requireFreshAssertion
665
+ relyingPartyOrigin,
666
+ scopes: SCOPES_SIGN2
586
667
  });
587
668
  const { signature } = await transport.send(
588
669
  PostMessageType.WALLET,
@@ -593,18 +674,24 @@ var getHeadlessSolanaMethods = ({
593
674
  wallet: params.wallet,
594
675
  uiOptions: params.options?.uiOptions,
595
676
  userHandleB64url,
596
- credentialIdB64url
677
+ credentialIdB64url,
678
+ presenceTokens: flattenPresenceTokens({
679
+ tokens,
680
+ userHandleB64url,
681
+ credentialIdB64url
682
+ })
597
683
  }
598
684
  );
599
685
  return { signature: arrayLikeToBytes(signature) };
600
- }),
601
- signSolanaTransactionHeadless: async (params) => withClearOnFailure(async () => {
686
+ },
687
+ signSolanaTransactionHeadless: async (params) => {
602
688
  if (!transport.isReady()) throw new Error("SDK not ready");
603
- const { userHandleB64url, credentialIdB64url } = await assertPasskeyInParent({
689
+ const { userHandleB64url, credentialIdB64url, tokens } = await getInternalPresenceTokens({
604
690
  transport,
605
691
  passkey,
606
692
  publishableKey,
607
- requireFreshAssertion: params.requireFreshAssertion
693
+ relyingPartyOrigin,
694
+ scopes: SCOPES_SIGN2
608
695
  });
609
696
  const { signedTransaction } = await transport.send(
610
697
  PostMessageType.WALLET,
@@ -615,18 +702,24 @@ var getHeadlessSolanaMethods = ({
615
702
  wallet: params.wallet,
616
703
  options: params.options,
617
704
  userHandleB64url,
618
- credentialIdB64url
705
+ credentialIdB64url,
706
+ presenceTokens: flattenPresenceTokens({
707
+ tokens,
708
+ userHandleB64url,
709
+ credentialIdB64url
710
+ })
619
711
  }
620
712
  );
621
713
  return { signedTransaction: await bs58ToBytes(signedTransaction) };
622
- }),
623
- sendSolanaTransactionHeadless: async (params) => withClearOnFailure(async () => {
714
+ },
715
+ sendSolanaTransactionHeadless: async (params) => {
624
716
  if (!transport.isReady()) throw new Error("SDK not ready");
625
- const { userHandleB64url, credentialIdB64url } = await assertPasskeyInParent({
717
+ const { userHandleB64url, credentialIdB64url, tokens } = await getInternalPresenceTokens({
626
718
  transport,
627
719
  passkey,
628
720
  publishableKey,
629
- requireFreshAssertion: params.requireFreshAssertion
721
+ relyingPartyOrigin,
722
+ scopes: SCOPES_SIGN2
630
723
  });
631
724
  const { signedTransaction } = await transport.send(
632
725
  PostMessageType.WALLET,
@@ -637,7 +730,12 @@ var getHeadlessSolanaMethods = ({
637
730
  wallet: params.wallet,
638
731
  options: params.options,
639
732
  userHandleB64url,
640
- credentialIdB64url
733
+ credentialIdB64url,
734
+ presenceTokens: flattenPresenceTokens({
735
+ tokens,
736
+ userHandleB64url,
737
+ credentialIdB64url
738
+ })
641
739
  }
642
740
  );
643
741
  const broadcastSignature = await broadcastSolanaSigned(
@@ -645,7 +743,7 @@ var getHeadlessSolanaMethods = ({
645
743
  signedTransaction
646
744
  );
647
745
  return { signature: await bs58ToBytes(broadcastSignature) };
648
- }),
746
+ },
649
747
  getSolanaBalance: async (params) => {
650
748
  if (!transport.isReady()) throw new Error("SDK not ready");
651
749
  return transport.send(
@@ -757,11 +855,17 @@ var getHeadlessAuthenticationMethods = ({
757
855
  });
758
856
 
759
857
  // src/sdk/headless-general.ts
858
+ var SCOPES_CREATE_WALLET = ["dek_bootstrap", "keyshare_write"];
859
+ var SCOPES_IMPORT_KEY = ["dek_bootstrap", "keyshare_write"];
860
+ var SCOPES_REMOVE_PASSKEY = ["passkey_remove"];
861
+ var SCOPES_PROVISION_EPHEMERAL_SIGNER = ["keyshare_read"];
862
+ var SCOPES_REVOKE_EPHEMERAL_SIGNER = ["ephemeral_signer_revoke"];
760
863
  var getHeadlessGeneralMethods = ({
761
864
  transport,
762
865
  passkey,
763
866
  storage,
764
867
  publishableKey,
868
+ relyingPartyOrigin,
765
869
  setIsAuthenticated,
766
870
  setUser
767
871
  }) => ({
@@ -771,18 +875,38 @@ var getHeadlessGeneralMethods = ({
771
875
  { publishableKey }
772
876
  ),
773
877
  removePasskey: async (credentialIdB64url) => {
878
+ const {
879
+ tokens,
880
+ userHandleB64url,
881
+ credentialIdB64url: assertedCredId
882
+ } = await getInternalPresenceTokens({
883
+ transport,
884
+ passkey,
885
+ publishableKey,
886
+ relyingPartyOrigin,
887
+ scopes: SCOPES_REMOVE_PASSKEY
888
+ });
774
889
  await transport.send(
775
890
  PostMessageType.AUTH,
776
891
  PostMessageMethod.REMOVE_PASSKEY,
777
- { publishableKey, credentialIdB64url }
892
+ {
893
+ publishableKey,
894
+ credentialIdB64url,
895
+ presenceTokens: flattenPresenceTokens({
896
+ tokens,
897
+ userHandleB64url,
898
+ credentialIdB64url: assertedCredId
899
+ })
900
+ }
778
901
  );
779
902
  },
780
- createWallet: (walletType, options) => withClearOnFailure(async () => {
781
- const { userHandleB64url, credentialIdB64url } = await assertPasskeyInParent({
903
+ createWallet: async (walletType, options) => {
904
+ const { userHandleB64url, credentialIdB64url, tokens } = await getInternalPresenceTokens({
782
905
  transport,
783
906
  passkey,
784
907
  publishableKey,
785
- requireFreshAssertion: options?.requireFreshAssertion
908
+ relyingPartyOrigin,
909
+ scopes: SCOPES_CREATE_WALLET
786
910
  });
787
911
  const wallet = await transport.send(
788
912
  PostMessageType.WALLET,
@@ -792,17 +916,23 @@ var getHeadlessGeneralMethods = ({
792
916
  publishableKey,
793
917
  options,
794
918
  userHandleB64url,
795
- credentialIdB64url
919
+ credentialIdB64url,
920
+ presenceTokens: flattenPresenceTokens({
921
+ tokens,
922
+ userHandleB64url,
923
+ credentialIdB64url
924
+ })
796
925
  }
797
926
  );
798
927
  return { wallet };
799
- }),
800
- importKey: (walletType, key, options) => withClearOnFailure(async () => {
801
- const { userHandleB64url, credentialIdB64url } = await assertPasskeyInParent({
928
+ },
929
+ importKey: async (walletType, key) => {
930
+ const { userHandleB64url, credentialIdB64url, tokens } = await getInternalPresenceTokens({
802
931
  transport,
803
932
  passkey,
804
933
  publishableKey,
805
- requireFreshAssertion: options?.requireFreshAssertion
934
+ relyingPartyOrigin,
935
+ scopes: SCOPES_IMPORT_KEY
806
936
  });
807
937
  const wallet = await transport.send(
808
938
  PostMessageType.WALLET,
@@ -812,11 +942,93 @@ var getHeadlessGeneralMethods = ({
812
942
  publishableKey,
813
943
  key,
814
944
  userHandleB64url,
815
- credentialIdB64url
945
+ credentialIdB64url,
946
+ presenceTokens: flattenPresenceTokens({
947
+ tokens,
948
+ userHandleB64url,
949
+ credentialIdB64url
950
+ })
816
951
  }
817
952
  );
818
953
  return { wallet };
819
- }),
954
+ },
955
+ provisionEphemeralSigner: async (params) => {
956
+ const walletCount = params.walletIds.length;
957
+ if (walletCount === 0) {
958
+ throw new Error(
959
+ "provisionEphemeralSigner: at least one walletId required"
960
+ );
961
+ }
962
+ const { userHandleB64url, credentialIdB64url, tokenBatches } = await getInternalPresenceTokens({
963
+ transport,
964
+ passkey,
965
+ publishableKey,
966
+ relyingPartyOrigin,
967
+ scopeCounts: { [SCOPES_PROVISION_EPHEMERAL_SIGNER[0]]: walletCount }
968
+ });
969
+ const keyshareReadBatch = (tokenBatches[SCOPES_PROVISION_EPHEMERAL_SIGNER[0]] ?? []).map((t) => t.token);
970
+ if (keyshareReadBatch.length !== walletCount) {
971
+ throw new Error(
972
+ `provisionEphemeralSigner: server returned ${keyshareReadBatch.length} tokens, expected ${walletCount}`
973
+ );
974
+ }
975
+ return transport.send(
976
+ PostMessageType.WALLET,
977
+ PostMessageMethod.PROVISION_EPHEMERAL_SIGNER,
978
+ {
979
+ publishableKey,
980
+ userHandleB64url,
981
+ credentialIdB64url,
982
+ // One keyshare_read token per wallet, parallel to params.walletIds
983
+ // (iframe consumes them positionally after wallet resolution).
984
+ presenceTokenBatches: {
985
+ [SCOPES_PROVISION_EPHEMERAL_SIGNER[0]]: keyshareReadBatch
986
+ },
987
+ walletIds: params.walletIds,
988
+ expiresAt: params.expiresAt?.toISOString(),
989
+ label: params.label
990
+ }
991
+ );
992
+ },
993
+ // Read-only: list the user's active (non-revoked) provisioned agents
994
+ // for the current app. No WebAuthn ceremony needed — the wallet
995
+ // session JWT is enough since this exposes only metadata (api_pub,
996
+ // key_ids, expiry) and not the private agent material.
997
+ listEphemeralSigners: async () => {
998
+ return transport.send(
999
+ PostMessageType.WALLET,
1000
+ PostMessageMethod.LIST_EPHEMERAL_SIGNERS,
1001
+ { publishableKey }
1002
+ );
1003
+ },
1004
+ // Soft-revoke a signer (and forward the revoke to SES). Requires a
1005
+ // fresh WebAuthn-bound presence token: ephemeral_signer_revoke scope. Wallet JWT
1006
+ // alone isn't enough because revoke is destructive (DoS-grade) — the
1007
+ // presence proof confirms it's really the user driving it.
1008
+ revokeEphemeralSigner: async (params) => {
1009
+ const { userHandleB64url, credentialIdB64url, tokens } = await getInternalPresenceTokens({
1010
+ transport,
1011
+ passkey,
1012
+ publishableKey,
1013
+ relyingPartyOrigin,
1014
+ scopes: SCOPES_REVOKE_EPHEMERAL_SIGNER
1015
+ });
1016
+ await transport.send(
1017
+ PostMessageType.WALLET,
1018
+ PostMessageMethod.REVOKE_EPHEMERAL_SIGNER,
1019
+ {
1020
+ publishableKey,
1021
+ apiPubHex: params.apiPubHex,
1022
+ userHandleB64url,
1023
+ credentialIdB64url,
1024
+ presenceTokens: flattenPresenceTokens({
1025
+ tokens,
1026
+ userHandleB64url,
1027
+ credentialIdB64url
1028
+ })
1029
+ }
1030
+ );
1031
+ },
820
1032
  getWallets: async (walletType) => {
821
1033
  const { wallets } = await transport.send(
822
1034
  PostMessageType.WALLET,
@@ -833,11 +1045,9 @@ var getHeadlessGeneralMethods = ({
833
1045
  // silently extend session lifetime.
834
1046
  getSessionTokens: async () => {
835
1047
  try {
836
- const session = await transport.send(
837
- PostMessageType.AUTH,
838
- PostMessageMethod.GET_CURRENT_SESSION,
839
- { publishableKey }
840
- );
1048
+ const session = await transport.send(PostMessageType.AUTH, PostMessageMethod.GET_CURRENT_SESSION, {
1049
+ publishableKey
1050
+ });
841
1051
  return session ? {
842
1052
  accessToken: session.accessToken,
843
1053
  identityToken: session.identityToken,
@@ -856,7 +1066,6 @@ var getHeadlessGeneralMethods = ({
856
1066
  await transport.send(PostMessageType.AUTH, PostMessageMethod.LOGOUT, {
857
1067
  publishableKey
858
1068
  });
859
- clearParentAssertCache();
860
1069
  await storage.remove("id_token");
861
1070
  if (setIsAuthenticated) setIsAuthenticated(false);
862
1071
  if (setUser) setUser(null);
@@ -902,12 +1111,157 @@ var getHeadlessGeneralMethods = ({
902
1111
  }
903
1112
  }
904
1113
  });
1114
+
1115
+ // src/sdk/ephemeral-signer-sign.ts
1116
+ var import_ed25519 = require("@noble/curves/ed25519");
1117
+ var import_utils = require("@noble/hashes/utils");
1118
+ function normalizeBase(url) {
1119
+ return url.replace(/\/+$/, "");
1120
+ }
1121
+ var EphemeralSignerSignError = class extends Error {
1122
+ constructor(message, status, body) {
1123
+ super(message);
1124
+ this.status = status;
1125
+ this.body = body;
1126
+ this.name = "EphemeralSignerSignError";
1127
+ }
1128
+ };
1129
+ var bindingsCache = /* @__PURE__ */ new Map();
1130
+ async function resolveBinding(input) {
1131
+ const cached = bindingsCache.get(input.apiPubHex);
1132
+ if (cached) {
1133
+ const hit2 = cached.find((b) => b.walletId === input.walletId);
1134
+ if (hit2) return hit2;
1135
+ }
1136
+ const issuedAt = (/* @__PURE__ */ new Date()).toISOString();
1137
+ const signedBodyBytes = new TextEncoder().encode(
1138
+ JSON.stringify({ issued_at: issuedAt })
1139
+ );
1140
+ const apiPrivBytes = (0, import_utils.hexToBytes)(input.apiPrivHex);
1141
+ const agentSig = import_ed25519.ed25519.sign(signedBodyBytes, apiPrivBytes);
1142
+ const url = `${normalizeBase(input.baseUrl)}/v0/wallets/ephemeral-signers/me/wallets`;
1143
+ const fetchFn = input.fetchImpl ?? fetch;
1144
+ let response;
1145
+ try {
1146
+ response = await fetchFn(url, {
1147
+ method: "POST",
1148
+ headers: {
1149
+ "Content-Type": "application/json",
1150
+ Authorization: `PublicToken ${input.publishableKey}`
1151
+ },
1152
+ body: JSON.stringify({
1153
+ api_pub: input.apiPubHex,
1154
+ signed_body: (0, import_utils.bytesToHex)(signedBodyBytes),
1155
+ agent_signature: (0, import_utils.bytesToHex)(agentSig)
1156
+ })
1157
+ });
1158
+ } catch (e) {
1159
+ throw new EphemeralSignerSignError(
1160
+ `wallet binding fetch failed: ${e instanceof Error ? e.message : String(e)}`
1161
+ );
1162
+ }
1163
+ if (!response.ok) {
1164
+ const body = await response.text().catch(() => "");
1165
+ throw new EphemeralSignerSignError(
1166
+ `wallet binding fetch failed: ${response.status}`,
1167
+ response.status,
1168
+ body
1169
+ );
1170
+ }
1171
+ const json = await response.json();
1172
+ const bindings = json.wallets.map((w) => ({
1173
+ walletId: w.wallet_id,
1174
+ keyId: w.key_id,
1175
+ derivationPath: w.derivation_path
1176
+ }));
1177
+ bindingsCache.set(input.apiPubHex, bindings);
1178
+ const hit = bindings.find((b) => b.walletId === input.walletId);
1179
+ if (!hit) {
1180
+ throw new EphemeralSignerSignError(
1181
+ `walletId ${input.walletId} is not authorized for this agent`
1182
+ );
1183
+ }
1184
+ return hit;
1185
+ }
1186
+ async function signWithEphemeralSigner(input) {
1187
+ if (!/^[0-9a-f]{64}$/i.test(input.apiPubHex)) {
1188
+ throw new EphemeralSignerSignError(
1189
+ "apiPubHex must be 64 lowercase hex chars (32-byte Ed25519 pubkey)"
1190
+ );
1191
+ }
1192
+ if (!/^[0-9a-f]{64}$/i.test(input.apiPrivHex)) {
1193
+ throw new EphemeralSignerSignError(
1194
+ "apiPrivHex must be 64 lowercase hex chars (32-byte Ed25519 privkey)"
1195
+ );
1196
+ }
1197
+ if (!input.walletId) {
1198
+ throw new EphemeralSignerSignError("walletId is required");
1199
+ }
1200
+ if (!input.rawSigningPayloadHex || !/^[0-9a-f]+$/i.test(input.rawSigningPayloadHex)) {
1201
+ throw new EphemeralSignerSignError(
1202
+ "rawSigningPayloadHex must be a non-empty lowercase hex string"
1203
+ );
1204
+ }
1205
+ if (!input.publishableKey) {
1206
+ throw new EphemeralSignerSignError(
1207
+ "publishableKey is required \u2014 wallets backend gates /ephemeral-signers/* with RequirePublicToken"
1208
+ );
1209
+ }
1210
+ const binding = await resolveBinding(input);
1211
+ const issuedAt = (input.issuedAt ?? /* @__PURE__ */ new Date()).toISOString();
1212
+ const signedPayload = {
1213
+ raw_signing_payload: input.rawSigningPayloadHex,
1214
+ key_id: binding.keyId,
1215
+ derivation_path: binding.derivationPath,
1216
+ issued_at: issuedAt
1217
+ };
1218
+ const signedBodyBytes = new TextEncoder().encode(
1219
+ JSON.stringify(signedPayload)
1220
+ );
1221
+ const apiPrivBytes = (0, import_utils.hexToBytes)(input.apiPrivHex);
1222
+ const agentSig = import_ed25519.ed25519.sign(signedBodyBytes, apiPrivBytes);
1223
+ const requestBody = {
1224
+ api_pub: input.apiPubHex,
1225
+ signed_body: (0, import_utils.bytesToHex)(signedBodyBytes),
1226
+ agent_signature: (0, import_utils.bytesToHex)(agentSig)
1227
+ };
1228
+ const url = `${normalizeBase(input.baseUrl)}/v0/wallets/ephemeral-signers/sign`;
1229
+ const fetchFn = input.fetchImpl ?? fetch;
1230
+ let response;
1231
+ try {
1232
+ response = await fetchFn(url, {
1233
+ method: "POST",
1234
+ headers: {
1235
+ "Content-Type": "application/json",
1236
+ Authorization: `PublicToken ${input.publishableKey}`
1237
+ },
1238
+ body: JSON.stringify(requestBody)
1239
+ });
1240
+ } catch (e) {
1241
+ throw new EphemeralSignerSignError(
1242
+ `transport failure: ${e instanceof Error ? e.message : String(e)}`
1243
+ );
1244
+ }
1245
+ if (!response.ok) {
1246
+ const body = await response.text().catch(() => "");
1247
+ throw new EphemeralSignerSignError(
1248
+ `ephemeral signer sign failed: ${response.status}`,
1249
+ response.status,
1250
+ body
1251
+ );
1252
+ }
1253
+ return await response.json();
1254
+ }
905
1255
  // Annotate the CommonJS export names for ESM import in node:
906
1256
  0 && (module.exports = {
1257
+ EphemeralSignerSignError,
907
1258
  assertPasskeyInParent,
1259
+ flattenPresenceTokens,
908
1260
  getHeadlessAuthenticationMethods,
909
1261
  getHeadlessEthereumMethods,
910
1262
  getHeadlessGeneralMethods,
911
1263
  getHeadlessSolanaMethods,
912
- getPresenceToken
1264
+ getInternalPresenceTokens,
1265
+ getPresenceToken,
1266
+ signWithEphemeralSigner
913
1267
  });