@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
@@ -1,20 +1,16 @@
1
1
  import {
2
2
  PostMessageMethod,
3
3
  PostMessageType
4
- } from "../chunk-VVL65GIB.mjs";
4
+ } from "../chunk-JU5MWLXH.mjs";
5
5
  import {
6
6
  arrayLikeToBytes,
7
7
  authState,
8
8
  broadcastEthereumRaw,
9
9
  broadcastSolanaSigned,
10
10
  bs58ToBytes,
11
- clearParentAssertCache,
12
- readParentAssertCache,
13
11
  serializeEthereumTransaction,
14
- toB64url,
15
- withClearOnFailure,
16
- writeParentAssertCache
17
- } from "../chunk-CDT4MC7S.mjs";
12
+ toB64url
13
+ } from "../chunk-I56GRKAG.mjs";
18
14
  import "../chunk-GQKIA37O.mjs";
19
15
 
20
16
  // src/sdk/parent-passkey-assert.ts
@@ -22,13 +18,8 @@ var assertPasskeyInParent = async ({
22
18
  transport,
23
19
  passkey,
24
20
  publishableKey,
25
- requireFreshAssertion = false,
26
21
  validateCredentialInAllowList = false
27
22
  }) => {
28
- if (!requireFreshAssertion) {
29
- const cached = readParentAssertCache();
30
- if (cached) return cached;
31
- }
32
23
  const dekInfo = await transport.send(
33
24
  PostMessageType.AUTH,
34
25
  PostMessageMethod.GET_DEK_INFO,
@@ -52,12 +43,10 @@ var assertPasskeyInParent = async ({
52
43
  if (validateCredentialInAllowList && !allowList.includes(credential.rawIdB64url)) {
53
44
  throw new Error("unknown_passkey_for_this_account");
54
45
  }
55
- const result = {
46
+ return {
56
47
  userHandleB64url: credential.userHandleB64url,
57
48
  credentialIdB64url: credential.rawIdB64url
58
49
  };
59
- writeParentAssertCache(result);
60
- return result;
61
50
  };
62
51
 
63
52
  // src/sdk/get-presence-token.ts
@@ -89,19 +78,79 @@ var getPresenceToken = async ({
89
78
  };
90
79
  };
91
80
 
81
+ // src/sdk/get-internal-presence-tokens.ts
82
+ var getInternalPresenceTokens = async ({
83
+ transport,
84
+ passkey,
85
+ publishableKey,
86
+ relyingPartyOrigin,
87
+ scopes,
88
+ scopeCounts
89
+ }) => {
90
+ const { token, optionsJSON } = await transport.send(
91
+ PostMessageType.AUTH,
92
+ PostMessageMethod.PASSKEY_PRESENCE_BEGIN,
93
+ { publishableKey, relyingPartyOrigin }
94
+ );
95
+ const { response, userHandleB64url, credentialIdB64url } = await passkey.assertForInternalPresence({ optionsJSON });
96
+ const verifyPayload = {
97
+ publishableKey,
98
+ relyingPartyOrigin,
99
+ token,
100
+ response,
101
+ purpose: "internal"
102
+ };
103
+ if (scopes && scopes.length > 0) verifyPayload.scopes = scopes;
104
+ if (scopeCounts && Object.keys(scopeCounts).length > 0) {
105
+ verifyPayload.scope_counts = scopeCounts;
106
+ }
107
+ const verify = await transport.send(
108
+ PostMessageType.AUTH,
109
+ PostMessageMethod.PASSKEY_PRESENCE_VERIFY,
110
+ verifyPayload
111
+ );
112
+ const out = {};
113
+ for (const [scope, t] of Object.entries(verify.tokens ?? {})) {
114
+ out[scope] = { token: t.token, expiresAt: t.expires_at };
115
+ }
116
+ const outBatches = {};
117
+ for (const [scope, batch] of Object.entries(verify.token_batches ?? {})) {
118
+ outBatches[scope] = batch.map((t) => ({
119
+ token: t.token,
120
+ expiresAt: t.expires_at
121
+ }));
122
+ }
123
+ return {
124
+ tokens: out,
125
+ tokenBatches: outBatches,
126
+ userHandleB64url,
127
+ credentialIdB64url
128
+ };
129
+ };
130
+ var flattenPresenceTokens = (result) => {
131
+ const out = {};
132
+ for (const [scope, t] of Object.entries(result.tokens)) {
133
+ out[scope] = t.token;
134
+ }
135
+ return out;
136
+ };
137
+
92
138
  // src/sdk/headless-ethereum.ts
139
+ var SCOPES_SIGN = ["keyshare_read", "sign"];
93
140
  var getHeadlessEthereumMethods = ({
94
141
  transport,
95
142
  passkey,
96
- publishableKey
143
+ publishableKey,
144
+ relyingPartyOrigin
97
145
  }) => ({
98
- signEthereumMessageHeadless: async (params) => withClearOnFailure(async () => {
146
+ signEthereumMessageHeadless: async (params) => {
99
147
  if (!transport.isReady()) throw new Error("SDK not ready");
100
- const { userHandleB64url, credentialIdB64url } = await assertPasskeyInParent({
148
+ const { userHandleB64url, credentialIdB64url, tokens } = await getInternalPresenceTokens({
101
149
  transport,
102
150
  passkey,
103
151
  publishableKey,
104
- requireFreshAssertion: params.requireFreshAssertion
152
+ relyingPartyOrigin,
153
+ scopes: SCOPES_SIGN
105
154
  });
106
155
  return transport.send(
107
156
  PostMessageType.WALLET,
@@ -112,17 +161,23 @@ var getHeadlessEthereumMethods = ({
112
161
  wallet: params.wallet,
113
162
  uiOptions: params.options?.uiOptions,
114
163
  userHandleB64url,
115
- credentialIdB64url
164
+ credentialIdB64url,
165
+ presenceTokens: flattenPresenceTokens({
166
+ tokens,
167
+ userHandleB64url,
168
+ credentialIdB64url
169
+ })
116
170
  }
117
171
  );
118
- }),
119
- signEthereumTransactionHeadless: async (params) => withClearOnFailure(async () => {
172
+ },
173
+ signEthereumTransactionHeadless: async (params) => {
120
174
  if (!transport.isReady()) throw new Error("SDK not ready");
121
- const { userHandleB64url, credentialIdB64url } = await assertPasskeyInParent({
175
+ const { userHandleB64url, credentialIdB64url, tokens } = await getInternalPresenceTokens({
122
176
  transport,
123
177
  passkey,
124
178
  publishableKey,
125
- requireFreshAssertion: params.requireFreshAssertion
179
+ relyingPartyOrigin,
180
+ scopes: SCOPES_SIGN
126
181
  });
127
182
  return transport.send(
128
183
  PostMessageType.WALLET,
@@ -134,17 +189,23 @@ var getHeadlessEthereumMethods = ({
134
189
  wallet: params.wallet,
135
190
  options: params.options,
136
191
  userHandleB64url,
137
- credentialIdB64url
192
+ credentialIdB64url,
193
+ presenceTokens: flattenPresenceTokens({
194
+ tokens,
195
+ userHandleB64url,
196
+ credentialIdB64url
197
+ })
138
198
  }
139
199
  );
140
- }),
141
- signEthereumTypedDataHeadless: async (params) => withClearOnFailure(async () => {
200
+ },
201
+ signEthereumTypedDataHeadless: async (params) => {
142
202
  if (!transport.isReady()) throw new Error("SDK not ready");
143
- const { userHandleB64url, credentialIdB64url } = await assertPasskeyInParent({
203
+ const { userHandleB64url, credentialIdB64url, tokens } = await getInternalPresenceTokens({
144
204
  transport,
145
205
  passkey,
146
206
  publishableKey,
147
- requireFreshAssertion: params.requireFreshAssertion
207
+ relyingPartyOrigin,
208
+ scopes: SCOPES_SIGN
148
209
  });
149
210
  return transport.send(
150
211
  PostMessageType.WALLET,
@@ -158,17 +219,23 @@ var getHeadlessEthereumMethods = ({
158
219
  wallet: params.wallet,
159
220
  options: params.options,
160
221
  userHandleB64url,
161
- credentialIdB64url
222
+ credentialIdB64url,
223
+ presenceTokens: flattenPresenceTokens({
224
+ tokens,
225
+ userHandleB64url,
226
+ credentialIdB64url
227
+ })
162
228
  }
163
229
  );
164
- }),
165
- signEthereumHashHeadless: async (params) => withClearOnFailure(async () => {
230
+ },
231
+ signEthereumHashHeadless: async (params) => {
166
232
  if (!transport.isReady()) throw new Error("SDK not ready");
167
- const { userHandleB64url, credentialIdB64url } = await assertPasskeyInParent({
233
+ const { userHandleB64url, credentialIdB64url, tokens } = await getInternalPresenceTokens({
168
234
  transport,
169
235
  passkey,
170
236
  publishableKey,
171
- requireFreshAssertion: params.requireFreshAssertion
237
+ relyingPartyOrigin,
238
+ scopes: SCOPES_SIGN
172
239
  });
173
240
  return transport.send(
174
241
  PostMessageType.WALLET,
@@ -179,17 +246,23 @@ var getHeadlessEthereumMethods = ({
179
246
  wallet: params.wallet,
180
247
  options: params.options,
181
248
  userHandleB64url,
182
- credentialIdB64url
249
+ credentialIdB64url,
250
+ presenceTokens: flattenPresenceTokens({
251
+ tokens,
252
+ userHandleB64url,
253
+ credentialIdB64url
254
+ })
183
255
  }
184
256
  );
185
- }),
186
- signEthereum7702AuthorizationHeadless: async (params) => withClearOnFailure(async () => {
257
+ },
258
+ signEthereum7702AuthorizationHeadless: async (params) => {
187
259
  if (!transport.isReady()) throw new Error("SDK not ready");
188
- const { userHandleB64url, credentialIdB64url } = await assertPasskeyInParent({
260
+ const { userHandleB64url, credentialIdB64url, tokens } = await getInternalPresenceTokens({
189
261
  transport,
190
262
  passkey,
191
263
  publishableKey,
192
- requireFreshAssertion: params.requireFreshAssertion
264
+ relyingPartyOrigin,
265
+ scopes: SCOPES_SIGN
193
266
  });
194
267
  return transport.send(
195
268
  PostMessageType.WALLET,
@@ -203,17 +276,23 @@ var getHeadlessEthereumMethods = ({
203
276
  wallet: params.wallet,
204
277
  options: params.options,
205
278
  userHandleB64url,
206
- credentialIdB64url
279
+ credentialIdB64url,
280
+ presenceTokens: flattenPresenceTokens({
281
+ tokens,
282
+ userHandleB64url,
283
+ credentialIdB64url
284
+ })
207
285
  }
208
286
  );
209
- }),
210
- sendEthereumTransactionHeadless: async (params) => withClearOnFailure(async () => {
287
+ },
288
+ sendEthereumTransactionHeadless: async (params) => {
211
289
  if (!transport.isReady()) throw new Error("SDK not ready");
212
- const { userHandleB64url, credentialIdB64url } = await assertPasskeyInParent({
290
+ const { userHandleB64url, credentialIdB64url, tokens } = await getInternalPresenceTokens({
213
291
  transport,
214
292
  passkey,
215
293
  publishableKey,
216
- requireFreshAssertion: params.requireFreshAssertion
294
+ relyingPartyOrigin,
295
+ scopes: SCOPES_SIGN
217
296
  });
218
297
  const serializedTransaction = await serializeEthereumTransaction(
219
298
  params.transaction
@@ -227,7 +306,12 @@ var getHeadlessEthereumMethods = ({
227
306
  wallet: params.wallet,
228
307
  options: params.options,
229
308
  userHandleB64url,
230
- credentialIdB64url
309
+ credentialIdB64url,
310
+ presenceTokens: flattenPresenceTokens({
311
+ tokens,
312
+ userHandleB64url,
313
+ credentialIdB64url
314
+ })
231
315
  }
232
316
  );
233
317
  if (!signed.serializedSigned) {
@@ -240,7 +324,7 @@ var getHeadlessEthereumMethods = ({
240
324
  signed.serializedSigned
241
325
  );
242
326
  return { hash };
243
- }),
327
+ },
244
328
  getEthereumBalance: async (params) => {
245
329
  if (!transport.isReady()) throw new Error("SDK not ready");
246
330
  return transport.send(
@@ -276,18 +360,21 @@ var getHeadlessEthereumMethods = ({
276
360
  });
277
361
 
278
362
  // src/sdk/headless-solana.ts
363
+ var SCOPES_SIGN2 = ["keyshare_read", "sign"];
279
364
  var getHeadlessSolanaMethods = ({
280
365
  transport,
281
366
  passkey,
282
- publishableKey
367
+ publishableKey,
368
+ relyingPartyOrigin
283
369
  }) => ({
284
- signSolanaMessageHeadless: async (params) => withClearOnFailure(async () => {
370
+ signSolanaMessageHeadless: async (params) => {
285
371
  if (!transport.isReady()) throw new Error("SDK not ready");
286
- const { userHandleB64url, credentialIdB64url } = await assertPasskeyInParent({
372
+ const { userHandleB64url, credentialIdB64url, tokens } = await getInternalPresenceTokens({
287
373
  transport,
288
374
  passkey,
289
375
  publishableKey,
290
- requireFreshAssertion: params.requireFreshAssertion
376
+ relyingPartyOrigin,
377
+ scopes: SCOPES_SIGN2
291
378
  });
292
379
  const { signature } = await transport.send(
293
380
  PostMessageType.WALLET,
@@ -298,18 +385,24 @@ var getHeadlessSolanaMethods = ({
298
385
  wallet: params.wallet,
299
386
  uiOptions: params.options?.uiOptions,
300
387
  userHandleB64url,
301
- credentialIdB64url
388
+ credentialIdB64url,
389
+ presenceTokens: flattenPresenceTokens({
390
+ tokens,
391
+ userHandleB64url,
392
+ credentialIdB64url
393
+ })
302
394
  }
303
395
  );
304
396
  return { signature: arrayLikeToBytes(signature) };
305
- }),
306
- signSolanaTransactionHeadless: async (params) => withClearOnFailure(async () => {
397
+ },
398
+ signSolanaTransactionHeadless: async (params) => {
307
399
  if (!transport.isReady()) throw new Error("SDK not ready");
308
- const { userHandleB64url, credentialIdB64url } = await assertPasskeyInParent({
400
+ const { userHandleB64url, credentialIdB64url, tokens } = await getInternalPresenceTokens({
309
401
  transport,
310
402
  passkey,
311
403
  publishableKey,
312
- requireFreshAssertion: params.requireFreshAssertion
404
+ relyingPartyOrigin,
405
+ scopes: SCOPES_SIGN2
313
406
  });
314
407
  const { signedTransaction } = await transport.send(
315
408
  PostMessageType.WALLET,
@@ -320,18 +413,24 @@ var getHeadlessSolanaMethods = ({
320
413
  wallet: params.wallet,
321
414
  options: params.options,
322
415
  userHandleB64url,
323
- credentialIdB64url
416
+ credentialIdB64url,
417
+ presenceTokens: flattenPresenceTokens({
418
+ tokens,
419
+ userHandleB64url,
420
+ credentialIdB64url
421
+ })
324
422
  }
325
423
  );
326
424
  return { signedTransaction: await bs58ToBytes(signedTransaction) };
327
- }),
328
- sendSolanaTransactionHeadless: async (params) => withClearOnFailure(async () => {
425
+ },
426
+ sendSolanaTransactionHeadless: async (params) => {
329
427
  if (!transport.isReady()) throw new Error("SDK not ready");
330
- const { userHandleB64url, credentialIdB64url } = await assertPasskeyInParent({
428
+ const { userHandleB64url, credentialIdB64url, tokens } = await getInternalPresenceTokens({
331
429
  transport,
332
430
  passkey,
333
431
  publishableKey,
334
- requireFreshAssertion: params.requireFreshAssertion
432
+ relyingPartyOrigin,
433
+ scopes: SCOPES_SIGN2
335
434
  });
336
435
  const { signedTransaction } = await transport.send(
337
436
  PostMessageType.WALLET,
@@ -342,7 +441,12 @@ var getHeadlessSolanaMethods = ({
342
441
  wallet: params.wallet,
343
442
  options: params.options,
344
443
  userHandleB64url,
345
- credentialIdB64url
444
+ credentialIdB64url,
445
+ presenceTokens: flattenPresenceTokens({
446
+ tokens,
447
+ userHandleB64url,
448
+ credentialIdB64url
449
+ })
346
450
  }
347
451
  );
348
452
  const broadcastSignature = await broadcastSolanaSigned(
@@ -350,7 +454,7 @@ var getHeadlessSolanaMethods = ({
350
454
  signedTransaction
351
455
  );
352
456
  return { signature: await bs58ToBytes(broadcastSignature) };
353
- }),
457
+ },
354
458
  getSolanaBalance: async (params) => {
355
459
  if (!transport.isReady()) throw new Error("SDK not ready");
356
460
  return transport.send(
@@ -462,11 +566,17 @@ var getHeadlessAuthenticationMethods = ({
462
566
  });
463
567
 
464
568
  // src/sdk/headless-general.ts
569
+ var SCOPES_CREATE_WALLET = ["dek_bootstrap", "keyshare_write"];
570
+ var SCOPES_IMPORT_KEY = ["dek_bootstrap", "keyshare_write"];
571
+ var SCOPES_REMOVE_PASSKEY = ["passkey_remove"];
572
+ var SCOPES_PROVISION_EPHEMERAL_SIGNER = ["keyshare_read"];
573
+ var SCOPES_REVOKE_EPHEMERAL_SIGNER = ["ephemeral_signer_revoke"];
465
574
  var getHeadlessGeneralMethods = ({
466
575
  transport,
467
576
  passkey,
468
577
  storage,
469
578
  publishableKey,
579
+ relyingPartyOrigin,
470
580
  setIsAuthenticated,
471
581
  setUser
472
582
  }) => ({
@@ -476,18 +586,38 @@ var getHeadlessGeneralMethods = ({
476
586
  { publishableKey }
477
587
  ),
478
588
  removePasskey: async (credentialIdB64url) => {
589
+ const {
590
+ tokens,
591
+ userHandleB64url,
592
+ credentialIdB64url: assertedCredId
593
+ } = await getInternalPresenceTokens({
594
+ transport,
595
+ passkey,
596
+ publishableKey,
597
+ relyingPartyOrigin,
598
+ scopes: SCOPES_REMOVE_PASSKEY
599
+ });
479
600
  await transport.send(
480
601
  PostMessageType.AUTH,
481
602
  PostMessageMethod.REMOVE_PASSKEY,
482
- { publishableKey, credentialIdB64url }
603
+ {
604
+ publishableKey,
605
+ credentialIdB64url,
606
+ presenceTokens: flattenPresenceTokens({
607
+ tokens,
608
+ userHandleB64url,
609
+ credentialIdB64url: assertedCredId
610
+ })
611
+ }
483
612
  );
484
613
  },
485
- createWallet: (walletType, options) => withClearOnFailure(async () => {
486
- const { userHandleB64url, credentialIdB64url } = await assertPasskeyInParent({
614
+ createWallet: async (walletType, options) => {
615
+ const { userHandleB64url, credentialIdB64url, tokens } = await getInternalPresenceTokens({
487
616
  transport,
488
617
  passkey,
489
618
  publishableKey,
490
- requireFreshAssertion: options?.requireFreshAssertion
619
+ relyingPartyOrigin,
620
+ scopes: SCOPES_CREATE_WALLET
491
621
  });
492
622
  const wallet = await transport.send(
493
623
  PostMessageType.WALLET,
@@ -497,17 +627,23 @@ var getHeadlessGeneralMethods = ({
497
627
  publishableKey,
498
628
  options,
499
629
  userHandleB64url,
500
- credentialIdB64url
630
+ credentialIdB64url,
631
+ presenceTokens: flattenPresenceTokens({
632
+ tokens,
633
+ userHandleB64url,
634
+ credentialIdB64url
635
+ })
501
636
  }
502
637
  );
503
638
  return { wallet };
504
- }),
505
- importKey: (walletType, key, options) => withClearOnFailure(async () => {
506
- const { userHandleB64url, credentialIdB64url } = await assertPasskeyInParent({
639
+ },
640
+ importKey: async (walletType, key) => {
641
+ const { userHandleB64url, credentialIdB64url, tokens } = await getInternalPresenceTokens({
507
642
  transport,
508
643
  passkey,
509
644
  publishableKey,
510
- requireFreshAssertion: options?.requireFreshAssertion
645
+ relyingPartyOrigin,
646
+ scopes: SCOPES_IMPORT_KEY
511
647
  });
512
648
  const wallet = await transport.send(
513
649
  PostMessageType.WALLET,
@@ -517,11 +653,93 @@ var getHeadlessGeneralMethods = ({
517
653
  publishableKey,
518
654
  key,
519
655
  userHandleB64url,
520
- credentialIdB64url
656
+ credentialIdB64url,
657
+ presenceTokens: flattenPresenceTokens({
658
+ tokens,
659
+ userHandleB64url,
660
+ credentialIdB64url
661
+ })
521
662
  }
522
663
  );
523
664
  return { wallet };
524
- }),
665
+ },
666
+ provisionEphemeralSigner: async (params) => {
667
+ const walletCount = params.walletIds.length;
668
+ if (walletCount === 0) {
669
+ throw new Error(
670
+ "provisionEphemeralSigner: at least one walletId required"
671
+ );
672
+ }
673
+ const { userHandleB64url, credentialIdB64url, tokenBatches } = await getInternalPresenceTokens({
674
+ transport,
675
+ passkey,
676
+ publishableKey,
677
+ relyingPartyOrigin,
678
+ scopeCounts: { [SCOPES_PROVISION_EPHEMERAL_SIGNER[0]]: walletCount }
679
+ });
680
+ const keyshareReadBatch = (tokenBatches[SCOPES_PROVISION_EPHEMERAL_SIGNER[0]] ?? []).map((t) => t.token);
681
+ if (keyshareReadBatch.length !== walletCount) {
682
+ throw new Error(
683
+ `provisionEphemeralSigner: server returned ${keyshareReadBatch.length} tokens, expected ${walletCount}`
684
+ );
685
+ }
686
+ return transport.send(
687
+ PostMessageType.WALLET,
688
+ PostMessageMethod.PROVISION_EPHEMERAL_SIGNER,
689
+ {
690
+ publishableKey,
691
+ userHandleB64url,
692
+ credentialIdB64url,
693
+ // One keyshare_read token per wallet, parallel to params.walletIds
694
+ // (iframe consumes them positionally after wallet resolution).
695
+ presenceTokenBatches: {
696
+ [SCOPES_PROVISION_EPHEMERAL_SIGNER[0]]: keyshareReadBatch
697
+ },
698
+ walletIds: params.walletIds,
699
+ expiresAt: params.expiresAt?.toISOString(),
700
+ label: params.label
701
+ }
702
+ );
703
+ },
704
+ // Read-only: list the user's active (non-revoked) provisioned agents
705
+ // for the current app. No WebAuthn ceremony needed — the wallet
706
+ // session JWT is enough since this exposes only metadata (api_pub,
707
+ // key_ids, expiry) and not the private agent material.
708
+ listEphemeralSigners: async () => {
709
+ return transport.send(
710
+ PostMessageType.WALLET,
711
+ PostMessageMethod.LIST_EPHEMERAL_SIGNERS,
712
+ { publishableKey }
713
+ );
714
+ },
715
+ // Soft-revoke a signer (and forward the revoke to SES). Requires a
716
+ // fresh WebAuthn-bound presence token: ephemeral_signer_revoke scope. Wallet JWT
717
+ // alone isn't enough because revoke is destructive (DoS-grade) — the
718
+ // presence proof confirms it's really the user driving it.
719
+ revokeEphemeralSigner: async (params) => {
720
+ const { userHandleB64url, credentialIdB64url, tokens } = await getInternalPresenceTokens({
721
+ transport,
722
+ passkey,
723
+ publishableKey,
724
+ relyingPartyOrigin,
725
+ scopes: SCOPES_REVOKE_EPHEMERAL_SIGNER
726
+ });
727
+ await transport.send(
728
+ PostMessageType.WALLET,
729
+ PostMessageMethod.REVOKE_EPHEMERAL_SIGNER,
730
+ {
731
+ publishableKey,
732
+ apiPubHex: params.apiPubHex,
733
+ userHandleB64url,
734
+ credentialIdB64url,
735
+ presenceTokens: flattenPresenceTokens({
736
+ tokens,
737
+ userHandleB64url,
738
+ credentialIdB64url
739
+ })
740
+ }
741
+ );
742
+ },
525
743
  getWallets: async (walletType) => {
526
744
  const { wallets } = await transport.send(
527
745
  PostMessageType.WALLET,
@@ -538,11 +756,9 @@ var getHeadlessGeneralMethods = ({
538
756
  // silently extend session lifetime.
539
757
  getSessionTokens: async () => {
540
758
  try {
541
- const session = await transport.send(
542
- PostMessageType.AUTH,
543
- PostMessageMethod.GET_CURRENT_SESSION,
544
- { publishableKey }
545
- );
759
+ const session = await transport.send(PostMessageType.AUTH, PostMessageMethod.GET_CURRENT_SESSION, {
760
+ publishableKey
761
+ });
546
762
  return session ? {
547
763
  accessToken: session.accessToken,
548
764
  identityToken: session.identityToken,
@@ -561,7 +777,6 @@ var getHeadlessGeneralMethods = ({
561
777
  await transport.send(PostMessageType.AUTH, PostMessageMethod.LOGOUT, {
562
778
  publishableKey
563
779
  });
564
- clearParentAssertCache();
565
780
  await storage.remove("id_token");
566
781
  if (setIsAuthenticated) setIsAuthenticated(false);
567
782
  if (setUser) setUser(null);
@@ -607,11 +822,156 @@ var getHeadlessGeneralMethods = ({
607
822
  }
608
823
  }
609
824
  });
825
+
826
+ // src/sdk/ephemeral-signer-sign.ts
827
+ import { ed25519 } from "@noble/curves/ed25519";
828
+ import { bytesToHex, hexToBytes } from "@noble/hashes/utils";
829
+ function normalizeBase(url) {
830
+ return url.replace(/\/+$/, "");
831
+ }
832
+ var EphemeralSignerSignError = class extends Error {
833
+ constructor(message, status, body) {
834
+ super(message);
835
+ this.status = status;
836
+ this.body = body;
837
+ this.name = "EphemeralSignerSignError";
838
+ }
839
+ };
840
+ var bindingsCache = /* @__PURE__ */ new Map();
841
+ async function resolveBinding(input) {
842
+ const cached = bindingsCache.get(input.apiPubHex);
843
+ if (cached) {
844
+ const hit2 = cached.find((b) => b.walletId === input.walletId);
845
+ if (hit2) return hit2;
846
+ }
847
+ const issuedAt = (/* @__PURE__ */ new Date()).toISOString();
848
+ const signedBodyBytes = new TextEncoder().encode(
849
+ JSON.stringify({ issued_at: issuedAt })
850
+ );
851
+ const apiPrivBytes = hexToBytes(input.apiPrivHex);
852
+ const agentSig = ed25519.sign(signedBodyBytes, apiPrivBytes);
853
+ const url = `${normalizeBase(input.baseUrl)}/v0/wallets/ephemeral-signers/me/wallets`;
854
+ const fetchFn = input.fetchImpl ?? fetch;
855
+ let response;
856
+ try {
857
+ response = await fetchFn(url, {
858
+ method: "POST",
859
+ headers: {
860
+ "Content-Type": "application/json",
861
+ Authorization: `PublicToken ${input.publishableKey}`
862
+ },
863
+ body: JSON.stringify({
864
+ api_pub: input.apiPubHex,
865
+ signed_body: bytesToHex(signedBodyBytes),
866
+ agent_signature: bytesToHex(agentSig)
867
+ })
868
+ });
869
+ } catch (e) {
870
+ throw new EphemeralSignerSignError(
871
+ `wallet binding fetch failed: ${e instanceof Error ? e.message : String(e)}`
872
+ );
873
+ }
874
+ if (!response.ok) {
875
+ const body = await response.text().catch(() => "");
876
+ throw new EphemeralSignerSignError(
877
+ `wallet binding fetch failed: ${response.status}`,
878
+ response.status,
879
+ body
880
+ );
881
+ }
882
+ const json = await response.json();
883
+ const bindings = json.wallets.map((w) => ({
884
+ walletId: w.wallet_id,
885
+ keyId: w.key_id,
886
+ derivationPath: w.derivation_path
887
+ }));
888
+ bindingsCache.set(input.apiPubHex, bindings);
889
+ const hit = bindings.find((b) => b.walletId === input.walletId);
890
+ if (!hit) {
891
+ throw new EphemeralSignerSignError(
892
+ `walletId ${input.walletId} is not authorized for this agent`
893
+ );
894
+ }
895
+ return hit;
896
+ }
897
+ async function signWithEphemeralSigner(input) {
898
+ if (!/^[0-9a-f]{64}$/i.test(input.apiPubHex)) {
899
+ throw new EphemeralSignerSignError(
900
+ "apiPubHex must be 64 lowercase hex chars (32-byte Ed25519 pubkey)"
901
+ );
902
+ }
903
+ if (!/^[0-9a-f]{64}$/i.test(input.apiPrivHex)) {
904
+ throw new EphemeralSignerSignError(
905
+ "apiPrivHex must be 64 lowercase hex chars (32-byte Ed25519 privkey)"
906
+ );
907
+ }
908
+ if (!input.walletId) {
909
+ throw new EphemeralSignerSignError("walletId is required");
910
+ }
911
+ if (!input.rawSigningPayloadHex || !/^[0-9a-f]+$/i.test(input.rawSigningPayloadHex)) {
912
+ throw new EphemeralSignerSignError(
913
+ "rawSigningPayloadHex must be a non-empty lowercase hex string"
914
+ );
915
+ }
916
+ if (!input.publishableKey) {
917
+ throw new EphemeralSignerSignError(
918
+ "publishableKey is required \u2014 wallets backend gates /ephemeral-signers/* with RequirePublicToken"
919
+ );
920
+ }
921
+ const binding = await resolveBinding(input);
922
+ const issuedAt = (input.issuedAt ?? /* @__PURE__ */ new Date()).toISOString();
923
+ const signedPayload = {
924
+ raw_signing_payload: input.rawSigningPayloadHex,
925
+ key_id: binding.keyId,
926
+ derivation_path: binding.derivationPath,
927
+ issued_at: issuedAt
928
+ };
929
+ const signedBodyBytes = new TextEncoder().encode(
930
+ JSON.stringify(signedPayload)
931
+ );
932
+ const apiPrivBytes = hexToBytes(input.apiPrivHex);
933
+ const agentSig = ed25519.sign(signedBodyBytes, apiPrivBytes);
934
+ const requestBody = {
935
+ api_pub: input.apiPubHex,
936
+ signed_body: bytesToHex(signedBodyBytes),
937
+ agent_signature: bytesToHex(agentSig)
938
+ };
939
+ const url = `${normalizeBase(input.baseUrl)}/v0/wallets/ephemeral-signers/sign`;
940
+ const fetchFn = input.fetchImpl ?? fetch;
941
+ let response;
942
+ try {
943
+ response = await fetchFn(url, {
944
+ method: "POST",
945
+ headers: {
946
+ "Content-Type": "application/json",
947
+ Authorization: `PublicToken ${input.publishableKey}`
948
+ },
949
+ body: JSON.stringify(requestBody)
950
+ });
951
+ } catch (e) {
952
+ throw new EphemeralSignerSignError(
953
+ `transport failure: ${e instanceof Error ? e.message : String(e)}`
954
+ );
955
+ }
956
+ if (!response.ok) {
957
+ const body = await response.text().catch(() => "");
958
+ throw new EphemeralSignerSignError(
959
+ `ephemeral signer sign failed: ${response.status}`,
960
+ response.status,
961
+ body
962
+ );
963
+ }
964
+ return await response.json();
965
+ }
610
966
  export {
967
+ EphemeralSignerSignError,
611
968
  assertPasskeyInParent,
969
+ flattenPresenceTokens,
612
970
  getHeadlessAuthenticationMethods,
613
971
  getHeadlessEthereumMethods,
614
972
  getHeadlessGeneralMethods,
615
973
  getHeadlessSolanaMethods,
616
- getPresenceToken
974
+ getInternalPresenceTokens,
975
+ getPresenceToken,
976
+ signWithEphemeralSigner
617
977
  };