@moon-x/core 0.4.0 → 0.6.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 (38) hide show
  1. package/dist/{chunk-6LTEG7VN.mjs → chunk-I56GRKAG.mjs} +19 -0
  2. package/dist/{chunk-VVL65GIB.mjs → chunk-JU5MWLXH.mjs} +14 -0
  3. package/dist/index.d.mts +2 -3
  4. package/dist/index.d.ts +2 -3
  5. package/dist/index.js +14 -0
  6. package/dist/index.mjs +1 -1
  7. package/dist/{interfaces-pNTEOKaK.d.ts → interfaces-BWxOajnD.d.mts} +17 -2
  8. package/dist/{interfaces-cdKh3sLA.d.mts → interfaces-BZ5GMWS9.d.ts} +17 -2
  9. package/dist/lib/index.d.mts +32 -2
  10. package/dist/lib/index.d.ts +32 -2
  11. package/dist/lib/index.js +21 -0
  12. package/dist/lib/index.mjs +5 -1
  13. package/dist/{post-message-CmgAfkOS.d.mts → post-message-Z6cLf0mS.d.mts} +3 -0
  14. package/dist/{post-message-CmgAfkOS.d.ts → post-message-Z6cLf0mS.d.ts} +3 -0
  15. package/dist/react/ethereum.d.mts +0 -1
  16. package/dist/react/ethereum.d.ts +0 -1
  17. package/dist/react/index.d.mts +41 -3
  18. package/dist/react/index.d.ts +41 -3
  19. package/dist/react/index.js +138 -12
  20. package/dist/react/index.mjs +137 -12
  21. package/dist/react/solana.d.mts +0 -1
  22. package/dist/react/solana.d.ts +0 -1
  23. package/dist/sdk/index.d.mts +68 -14
  24. package/dist/sdk/index.d.ts +68 -14
  25. package/dist/sdk/index.js +280 -20
  26. package/dist/sdk/index.mjs +264 -21
  27. package/dist/types/index.d.mts +135 -3
  28. package/dist/types/index.d.ts +135 -3
  29. package/dist/utils/index.d.mts +1 -1
  30. package/dist/utils/index.d.ts +1 -1
  31. package/dist/utils/index.js +14 -0
  32. package/dist/utils/index.mjs +1 -1
  33. package/dist/web/index.d.mts +2 -2
  34. package/dist/web/index.d.ts +2 -2
  35. package/dist/web/index.mjs +1 -1
  36. package/package.json +3 -1
  37. package/dist/chain-C9dvKXUY.d.mts +0 -48
  38. package/dist/chain-C9dvKXUY.d.ts +0 -48
@@ -1,9 +1,8 @@
1
- import { T as Transport, P as PasskeyAssertor, K as KvStorage } from '../interfaces-pNTEOKaK.js';
2
- export { O as OAuthOpener, a as PlatformImpls, W as WebAuthnAssertionResponse, b as WebAuthnRequestOptions } from '../interfaces-pNTEOKaK.js';
1
+ import { T as Transport, P as PasskeyAssertor, R as RelyingPartyOriginInput, K as KvStorage } from '../interfaces-BZ5GMWS9.js';
2
+ export { O as OAuthOpener, a as PlatformImpls, W as WebAuthnAssertionResponse, b as WebAuthnRequestOptions, r as resolveRelyingPartyOrigin } from '../interfaces-BZ5GMWS9.js';
3
3
  import { C as CachedAssertion } from '../passkey-cache-WnDFQ-v4.js';
4
- import { EthereumSignMessageParams, EthereumSignMessageResult, EthereumSignTransactionParams, EthereumSignTransactionResult, EthereumSignTypedDataParams, EthereumSignTypedDataResult, EthereumSignHashParams, EthereumSignHashResult, EthereumSign7702AuthorizationParams, EthereumSign7702AuthorizationResult, EthereumSendTransactionParams, EthereumSendTransactionResult, EthereumGetBalanceParams, EthereumGetBalanceResult, EthereumGetTokenAccountsByOwnerParams, EthereumGetTokenAccountsByOwnerResult, SolanaSignMessageParams, SolanaSignMessageResult, SolanaSignTransactionParams, SolanaSignTransactionResult, SolanaSendTransactionParams, SolanaSendTransactionResult, SolanaGetBalanceParams, SolanaGetBalanceResult, SolanaGetTokenAccountsByOwnerParams, SolanaGetTokenAccountsByOwnerResult, SendEmailOtpResponse, PublicWallet } from '../types/index.js';
5
- import '../post-message-CmgAfkOS.js';
6
- import '../chain-C9dvKXUY.js';
4
+ import { EthereumSignMessageParams, EthereumSignMessageResult, EthereumSignTransactionParams, EthereumSignTransactionResult, EthereumSignTypedDataParams, EthereumSignTypedDataResult, EthereumSignHashParams, EthereumSignHashResult, EthereumSign7702AuthorizationParams, EthereumSign7702AuthorizationResult, EthereumSendTransactionParams, EthereumSendTransactionResult, EthereumGetBalanceParams, EthereumGetBalanceResult, EthereumGetTokenAccountsByOwnerParams, EthereumGetTokenAccountsByOwnerResult, SolanaSignMessageParams, SolanaSignMessageResult, SolanaSignTransactionParams, SolanaSignTransactionResult, SolanaSendTransactionParams, SolanaSendTransactionResult, SolanaGetBalanceParams, SolanaGetBalanceResult, SolanaGetTokenAccountsByOwnerParams, SolanaGetTokenAccountsByOwnerResult, SendEmailOtpResponse, PublicWallet, ProvisionEphemeralSignerParams, ProvisionEphemeralSignerResult, ListEphemeralSignersResult, RevokeEphemeralSignerParams } from '../types/index.js';
5
+ import '../post-message-Z6cLf0mS.js';
7
6
 
8
7
  type AssertPasskeyInParentResult = CachedAssertion;
9
8
  declare const assertPasskeyInParent: ({ transport, passkey, publishableKey, validateCredentialInAllowList, }: {
@@ -21,7 +20,7 @@ declare const getPresenceToken: ({ transport, passkey, publishableKey, relyingPa
21
20
  transport: Transport;
22
21
  passkey: PasskeyAssertor;
23
22
  publishableKey: string;
24
- relyingPartyOrigin: string;
23
+ relyingPartyOrigin: RelyingPartyOriginInput;
25
24
  }) => Promise<GetPresenceTokenResult>;
26
25
 
27
26
  interface ScopedPresenceToken {
@@ -30,23 +29,25 @@ interface ScopedPresenceToken {
30
29
  }
31
30
  interface GetInternalPresenceTokensResult {
32
31
  tokens: Record<string, ScopedPresenceToken>;
32
+ tokenBatches: Record<string, ScopedPresenceToken[]>;
33
33
  userHandleB64url: string;
34
34
  credentialIdB64url: string;
35
35
  }
36
- declare const getInternalPresenceTokens: ({ transport, passkey, publishableKey, relyingPartyOrigin, scopes, }: {
36
+ declare const getInternalPresenceTokens: ({ transport, passkey, publishableKey, relyingPartyOrigin, scopes, scopeCounts, }: {
37
37
  transport: Transport;
38
38
  passkey: PasskeyAssertor;
39
39
  publishableKey: string;
40
- relyingPartyOrigin: string;
41
- scopes: string[];
40
+ relyingPartyOrigin: RelyingPartyOriginInput;
41
+ scopes?: string[];
42
+ scopeCounts?: Record<string, number>;
42
43
  }) => Promise<GetInternalPresenceTokensResult>;
43
- declare const flattenPresenceTokens: (result: GetInternalPresenceTokensResult) => Record<string, string>;
44
+ declare const flattenPresenceTokens: (result: Pick<GetInternalPresenceTokensResult, "tokens"> & Partial<GetInternalPresenceTokensResult>) => Record<string, string>;
44
45
 
45
46
  declare const getHeadlessEthereumMethods: ({ transport, passkey, publishableKey, relyingPartyOrigin, }: {
46
47
  transport: Transport;
47
48
  passkey: PasskeyAssertor;
48
49
  publishableKey: string;
49
- relyingPartyOrigin: string;
50
+ relyingPartyOrigin: RelyingPartyOriginInput;
50
51
  }) => {
51
52
  signEthereumMessageHeadless: (params: EthereumSignMessageParams) => Promise<EthereumSignMessageResult>;
52
53
  signEthereumTransactionHeadless: (params: EthereumSignTransactionParams) => Promise<EthereumSignTransactionResult>;
@@ -68,7 +69,7 @@ declare const getHeadlessSolanaMethods: ({ transport, passkey, publishableKey, r
68
69
  transport: Transport;
69
70
  passkey: PasskeyAssertor;
70
71
  publishableKey: string;
71
- relyingPartyOrigin: string;
72
+ relyingPartyOrigin: RelyingPartyOriginInput;
72
73
  }) => {
73
74
  signSolanaMessageHeadless: (params: SolanaSignMessageParams) => Promise<SolanaSignMessageResult>;
74
75
  signSolanaTransactionHeadless: (params: SolanaSignTransactionParams) => Promise<SolanaSignTransactionResult>;
@@ -122,7 +123,7 @@ declare const getHeadlessGeneralMethods: ({ transport, passkey, storage, publish
122
123
  passkey: PasskeyAssertor;
123
124
  storage: KvStorage;
124
125
  publishableKey: string;
125
- relyingPartyOrigin: string;
126
+ relyingPartyOrigin: RelyingPartyOriginInput;
126
127
  setIsAuthenticated?: (isAuth: boolean) => void;
127
128
  setUser?: (user: unknown | null) => void;
128
129
  }) => {
@@ -137,6 +138,9 @@ declare const getHeadlessGeneralMethods: ({ transport, passkey, storage, publish
137
138
  importKey: (walletType: "solana" | "ethereum", key: string) => Promise<{
138
139
  wallet: PublicWallet;
139
140
  }>;
141
+ provisionEphemeralSigner: (params: ProvisionEphemeralSignerParams) => Promise<ProvisionEphemeralSignerResult>;
142
+ listEphemeralSigners: () => Promise<ListEphemeralSignersResult>;
143
+ revokeEphemeralSigner: (params: RevokeEphemeralSignerParams) => Promise<void>;
140
144
  getWallets: (walletType: "solana" | "ethereum") => Promise<{
141
145
  wallets: unknown[];
142
146
  walletType: string;
@@ -154,4 +158,54 @@ declare const getHeadlessGeneralMethods: ({ transport, passkey, storage, publish
154
158
  getUser: () => Promise<unknown>;
155
159
  };
156
160
 
157
- export { type AssertPasskeyInParentResult, type GetInternalPresenceTokensResult, type GetPresenceTokenResult, KvStorage, type LoginWithCodeParams, PasskeyAssertor, type ScopedPresenceToken, type SendCodeParams, Transport, type VerifyOAuthParams, assertPasskeyInParent, flattenPresenceTokens, getHeadlessAuthenticationMethods, getHeadlessEthereumMethods, getHeadlessGeneralMethods, getHeadlessSolanaMethods, getInternalPresenceTokens, getPresenceToken };
161
+ interface EphemeralSignerSignInput {
162
+ /** Lowercase-hex 32-byte Ed25519 agent public key (no 0x prefix). */
163
+ apiPubHex: string;
164
+ /** Lowercase-hex 32-byte Ed25519 agent private key (no 0x prefix). */
165
+ apiPrivHex: string;
166
+ /**
167
+ * Wallet UUID (from `user.wallets[i].id`) the agent should sign on
168
+ * behalf of. Must be one of the wallets the agent was provisioned
169
+ * for. The SDK resolves this internally to the wallet's MPC `key_id`
170
+ * + stored `derivation_path` — integrators never see those values.
171
+ */
172
+ walletId: string;
173
+ /**
174
+ * Lowercase-hex digest to sign — keccak256 of the message/tx for
175
+ * ECDSA, raw bytes for Ed25519. No 0x prefix.
176
+ */
177
+ rawSigningPayloadHex: string;
178
+ /** Defaults to now. SES rejects timestamps further than ±5 min from its clock. */
179
+ issuedAt?: Date;
180
+ /** Wallets backend base URL (no trailing slash). */
181
+ baseUrl: string;
182
+ /**
183
+ * MoonX publishable key (`moon_pk_…`). The wallets backend's
184
+ * /ephemeral-signers/* router group is gated by RequirePublicToken — every
185
+ * call needs an `Authorization: PublicToken <publishableKey>` header.
186
+ */
187
+ publishableKey: string;
188
+ /** Optional fetch override — e.g. for Next.js route handlers or test stubs. */
189
+ fetchImpl?: typeof fetch;
190
+ }
191
+ interface EphemeralSignerSignResult {
192
+ scheme: "ecdsa_secp256k1" | "eddsa_ed25519";
193
+ signature: {
194
+ /** ECDSA only. Lowercase-hex 32-byte r. */
195
+ r?: string;
196
+ /** ECDSA only. Lowercase-hex 32-byte s. */
197
+ s?: string;
198
+ /** ECDSA only. 0..3. */
199
+ recovery_id?: number;
200
+ /** Ed25519 only. Lowercase-hex 64-byte signature. */
201
+ signature?: string;
202
+ };
203
+ }
204
+ declare class EphemeralSignerSignError extends Error {
205
+ readonly status?: number | undefined;
206
+ readonly body?: string | undefined;
207
+ constructor(message: string, status?: number | undefined, body?: string | undefined);
208
+ }
209
+ declare function signWithEphemeralSigner(input: EphemeralSignerSignInput): Promise<EphemeralSignerSignResult>;
210
+
211
+ export { type AssertPasskeyInParentResult, EphemeralSignerSignError, type EphemeralSignerSignInput, type EphemeralSignerSignResult, type GetInternalPresenceTokensResult, type GetPresenceTokenResult, KvStorage, type LoginWithCodeParams, PasskeyAssertor, RelyingPartyOriginInput, type ScopedPresenceToken, type SendCodeParams, Transport, type VerifyOAuthParams, assertPasskeyInParent, flattenPresenceTokens, getHeadlessAuthenticationMethods, getHeadlessEthereumMethods, getHeadlessGeneralMethods, getHeadlessSolanaMethods, getInternalPresenceTokens, getPresenceToken, signWithEphemeralSigner };
package/dist/sdk/index.js CHANGED
@@ -30,6 +30,7 @@ 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,
34
35
  flattenPresenceTokens: () => flattenPresenceTokens,
35
36
  getHeadlessAuthenticationMethods: () => getHeadlessAuthenticationMethods,
@@ -37,10 +38,15 @@ __export(sdk_exports, {
37
38
  getHeadlessGeneralMethods: () => getHeadlessGeneralMethods,
38
39
  getHeadlessSolanaMethods: () => getHeadlessSolanaMethods,
39
40
  getInternalPresenceTokens: () => getInternalPresenceTokens,
40
- getPresenceToken: () => getPresenceToken
41
+ getPresenceToken: () => getPresenceToken,
42
+ resolveRelyingPartyOrigin: () => resolveRelyingPartyOrigin,
43
+ signWithEphemeralSigner: () => signWithEphemeralSigner
41
44
  });
42
45
  module.exports = __toCommonJS(sdk_exports);
43
46
 
47
+ // src/sdk/interfaces.ts
48
+ var resolveRelyingPartyOrigin = async (input) => typeof input === "function" ? input() : input;
49
+
44
50
  // src/lib/auth/authentication-state.ts
45
51
  var AuthenticationState = class {
46
52
  constructor() {
@@ -244,6 +250,20 @@ var PostMessageMethod = {
244
250
  // dispatcher boring.
245
251
  SIGN_HASH: "SIGN_HASH",
246
252
  SIGN_7702_AUTHORIZATION: "SIGN_7702_AUTHORIZATION",
253
+ // Provision a SES (Secure Ephemeral Signer) over one or more of the
254
+ // user's MPC wallets. Iframe verifies the Nitro attestation, decrypts
255
+ // the selected keyshares, HPKE-seals them to the verified enclave
256
+ // pubkey, and returns a freshly-generated Ed25519 signer keypair.
257
+ // MoonX never persists the private key — the parent must hand it to
258
+ // the user immediately.
259
+ PROVISION_EPHEMERAL_SIGNER: "PROVISION_EPHEMERAL_SIGNER",
260
+ // List the user's active provisioned ephemeral signers from the
261
+ // wallets backend. Read-only; doesn't touch SES or the enclave.
262
+ LIST_EPHEMERAL_SIGNERS: "LIST_EPHEMERAL_SIGNERS",
263
+ // Soft-revoke a previously-provisioned ephemeral signer. The wallets
264
+ // backend updates revoked_at locally and forwards the revoke to SES
265
+ // so the enclave drops the policy.
266
+ REVOKE_EPHEMERAL_SIGNER: "REVOKE_EPHEMERAL_SIGNER",
247
267
  VERIFY_EMAIL_OTP: "VERIFY_EMAIL_OTP",
248
268
  VERIFY_OAUTH: "VERIFY_OAUTH",
249
269
  START_OAUTH: "START_OAUTH",
@@ -329,10 +349,11 @@ var getPresenceToken = async ({
329
349
  publishableKey,
330
350
  relyingPartyOrigin
331
351
  }) => {
352
+ const rpOrigin = await resolveRelyingPartyOrigin(relyingPartyOrigin);
332
353
  const { token, optionsJSON } = await transport.send(
333
354
  PostMessageType.AUTH,
334
355
  PostMessageMethod.PASSKEY_PRESENCE_BEGIN,
335
- { publishableKey, relyingPartyOrigin }
356
+ { publishableKey, relyingPartyOrigin: rpOrigin }
336
357
  );
337
358
  const response = await passkey.assertForServer({ optionsJSON });
338
359
  const verify = await transport.send(
@@ -340,7 +361,7 @@ var getPresenceToken = async ({
340
361
  PostMessageMethod.PASSKEY_PRESENCE_VERIFY,
341
362
  {
342
363
  publishableKey,
343
- relyingPartyOrigin,
364
+ relyingPartyOrigin: rpOrigin,
344
365
  token,
345
366
  response
346
367
  }
@@ -357,32 +378,46 @@ var getInternalPresenceTokens = async ({
357
378
  passkey,
358
379
  publishableKey,
359
380
  relyingPartyOrigin,
360
- scopes
381
+ scopes,
382
+ scopeCounts
361
383
  }) => {
384
+ const rpOrigin = await resolveRelyingPartyOrigin(relyingPartyOrigin);
362
385
  const { token, optionsJSON } = await transport.send(
363
386
  PostMessageType.AUTH,
364
387
  PostMessageMethod.PASSKEY_PRESENCE_BEGIN,
365
- { publishableKey, relyingPartyOrigin }
388
+ { publishableKey, relyingPartyOrigin: rpOrigin }
366
389
  );
367
390
  const { response, userHandleB64url, credentialIdB64url } = await passkey.assertForInternalPresence({ optionsJSON });
391
+ const verifyPayload = {
392
+ publishableKey,
393
+ relyingPartyOrigin: rpOrigin,
394
+ token,
395
+ response,
396
+ purpose: "internal"
397
+ };
398
+ if (scopes && scopes.length > 0) verifyPayload.scopes = scopes;
399
+ if (scopeCounts && Object.keys(scopeCounts).length > 0) {
400
+ verifyPayload.scope_counts = scopeCounts;
401
+ }
368
402
  const verify = await transport.send(
369
403
  PostMessageType.AUTH,
370
404
  PostMessageMethod.PASSKEY_PRESENCE_VERIFY,
371
- {
372
- publishableKey,
373
- relyingPartyOrigin,
374
- token,
375
- response,
376
- purpose: "internal",
377
- scopes
378
- }
405
+ verifyPayload
379
406
  );
380
407
  const out = {};
381
408
  for (const [scope, t] of Object.entries(verify.tokens ?? {})) {
382
409
  out[scope] = { token: t.token, expiresAt: t.expires_at };
383
410
  }
411
+ const outBatches = {};
412
+ for (const [scope, batch] of Object.entries(verify.token_batches ?? {})) {
413
+ outBatches[scope] = batch.map((t) => ({
414
+ token: t.token,
415
+ expiresAt: t.expires_at
416
+ }));
417
+ }
384
418
  return {
385
419
  tokens: out,
420
+ tokenBatches: outBatches,
386
421
  userHandleB64url,
387
422
  credentialIdB64url
388
423
  };
@@ -829,6 +864,8 @@ var getHeadlessAuthenticationMethods = ({
829
864
  var SCOPES_CREATE_WALLET = ["dek_bootstrap", "keyshare_write"];
830
865
  var SCOPES_IMPORT_KEY = ["dek_bootstrap", "keyshare_write"];
831
866
  var SCOPES_REMOVE_PASSKEY = ["passkey_remove"];
867
+ var SCOPES_PROVISION_EPHEMERAL_SIGNER = ["keyshare_read"];
868
+ var SCOPES_REVOKE_EPHEMERAL_SIGNER = ["ephemeral_signer_revoke"];
832
869
  var getHeadlessGeneralMethods = ({
833
870
  transport,
834
871
  passkey,
@@ -844,7 +881,11 @@ var getHeadlessGeneralMethods = ({
844
881
  { publishableKey }
845
882
  ),
846
883
  removePasskey: async (credentialIdB64url) => {
847
- const { tokens, userHandleB64url, credentialIdB64url: assertedCredId } = await getInternalPresenceTokens({
884
+ const {
885
+ tokens,
886
+ userHandleB64url,
887
+ credentialIdB64url: assertedCredId
888
+ } = await getInternalPresenceTokens({
848
889
  transport,
849
890
  passkey,
850
891
  publishableKey,
@@ -917,6 +958,83 @@ var getHeadlessGeneralMethods = ({
917
958
  );
918
959
  return { wallet };
919
960
  },
961
+ provisionEphemeralSigner: async (params) => {
962
+ const walletCount = params.walletIds.length;
963
+ if (walletCount === 0) {
964
+ throw new Error(
965
+ "provisionEphemeralSigner: at least one walletId required"
966
+ );
967
+ }
968
+ const { userHandleB64url, credentialIdB64url, tokenBatches } = await getInternalPresenceTokens({
969
+ transport,
970
+ passkey,
971
+ publishableKey,
972
+ relyingPartyOrigin,
973
+ scopeCounts: { [SCOPES_PROVISION_EPHEMERAL_SIGNER[0]]: walletCount }
974
+ });
975
+ const keyshareReadBatch = (tokenBatches[SCOPES_PROVISION_EPHEMERAL_SIGNER[0]] ?? []).map((t) => t.token);
976
+ if (keyshareReadBatch.length !== walletCount) {
977
+ throw new Error(
978
+ `provisionEphemeralSigner: server returned ${keyshareReadBatch.length} tokens, expected ${walletCount}`
979
+ );
980
+ }
981
+ return transport.send(
982
+ PostMessageType.WALLET,
983
+ PostMessageMethod.PROVISION_EPHEMERAL_SIGNER,
984
+ {
985
+ publishableKey,
986
+ userHandleB64url,
987
+ credentialIdB64url,
988
+ // One keyshare_read token per wallet, parallel to params.walletIds
989
+ // (iframe consumes them positionally after wallet resolution).
990
+ presenceTokenBatches: {
991
+ [SCOPES_PROVISION_EPHEMERAL_SIGNER[0]]: keyshareReadBatch
992
+ },
993
+ walletIds: params.walletIds,
994
+ expiresAt: params.expiresAt?.toISOString(),
995
+ label: params.label
996
+ }
997
+ );
998
+ },
999
+ // Read-only: list the user's active (non-revoked) provisioned agents
1000
+ // for the current app. No WebAuthn ceremony needed — the wallet
1001
+ // session JWT is enough since this exposes only metadata (api_pub,
1002
+ // key_ids, expiry) and not the private agent material.
1003
+ listEphemeralSigners: async () => {
1004
+ return transport.send(
1005
+ PostMessageType.WALLET,
1006
+ PostMessageMethod.LIST_EPHEMERAL_SIGNERS,
1007
+ { publishableKey }
1008
+ );
1009
+ },
1010
+ // Soft-revoke a signer (and forward the revoke to SES). Requires a
1011
+ // fresh WebAuthn-bound presence token: ephemeral_signer_revoke scope. Wallet JWT
1012
+ // alone isn't enough because revoke is destructive (DoS-grade) — the
1013
+ // presence proof confirms it's really the user driving it.
1014
+ revokeEphemeralSigner: async (params) => {
1015
+ const { userHandleB64url, credentialIdB64url, tokens } = await getInternalPresenceTokens({
1016
+ transport,
1017
+ passkey,
1018
+ publishableKey,
1019
+ relyingPartyOrigin,
1020
+ scopes: SCOPES_REVOKE_EPHEMERAL_SIGNER
1021
+ });
1022
+ await transport.send(
1023
+ PostMessageType.WALLET,
1024
+ PostMessageMethod.REVOKE_EPHEMERAL_SIGNER,
1025
+ {
1026
+ publishableKey,
1027
+ apiPubHex: params.apiPubHex,
1028
+ userHandleB64url,
1029
+ credentialIdB64url,
1030
+ presenceTokens: flattenPresenceTokens({
1031
+ tokens,
1032
+ userHandleB64url,
1033
+ credentialIdB64url
1034
+ })
1035
+ }
1036
+ );
1037
+ },
920
1038
  getWallets: async (walletType) => {
921
1039
  const { wallets } = await transport.send(
922
1040
  PostMessageType.WALLET,
@@ -933,11 +1051,9 @@ var getHeadlessGeneralMethods = ({
933
1051
  // silently extend session lifetime.
934
1052
  getSessionTokens: async () => {
935
1053
  try {
936
- const session = await transport.send(
937
- PostMessageType.AUTH,
938
- PostMessageMethod.GET_CURRENT_SESSION,
939
- { publishableKey }
940
- );
1054
+ const session = await transport.send(PostMessageType.AUTH, PostMessageMethod.GET_CURRENT_SESSION, {
1055
+ publishableKey
1056
+ });
941
1057
  return session ? {
942
1058
  accessToken: session.accessToken,
943
1059
  identityToken: session.identityToken,
@@ -1001,8 +1117,150 @@ var getHeadlessGeneralMethods = ({
1001
1117
  }
1002
1118
  }
1003
1119
  });
1120
+
1121
+ // src/sdk/ephemeral-signer-sign.ts
1122
+ var import_ed25519 = require("@noble/curves/ed25519");
1123
+ var import_utils = require("@noble/hashes/utils");
1124
+ function normalizeBase(url) {
1125
+ return url.replace(/\/+$/, "");
1126
+ }
1127
+ var EphemeralSignerSignError = class extends Error {
1128
+ constructor(message, status, body) {
1129
+ super(message);
1130
+ this.status = status;
1131
+ this.body = body;
1132
+ this.name = "EphemeralSignerSignError";
1133
+ }
1134
+ };
1135
+ var bindingsCache = /* @__PURE__ */ new Map();
1136
+ async function resolveBinding(input) {
1137
+ const cached = bindingsCache.get(input.apiPubHex);
1138
+ if (cached) {
1139
+ const hit2 = cached.find((b) => b.walletId === input.walletId);
1140
+ if (hit2) return hit2;
1141
+ }
1142
+ const issuedAt = (/* @__PURE__ */ new Date()).toISOString();
1143
+ const signedBodyBytes = new TextEncoder().encode(
1144
+ JSON.stringify({ issued_at: issuedAt })
1145
+ );
1146
+ const apiPrivBytes = (0, import_utils.hexToBytes)(input.apiPrivHex);
1147
+ const agentSig = import_ed25519.ed25519.sign(signedBodyBytes, apiPrivBytes);
1148
+ const url = `${normalizeBase(input.baseUrl)}/v0/wallets/ephemeral-signers/me/wallets`;
1149
+ const fetchFn = input.fetchImpl ?? fetch;
1150
+ let response;
1151
+ try {
1152
+ response = await fetchFn(url, {
1153
+ method: "POST",
1154
+ headers: {
1155
+ "Content-Type": "application/json",
1156
+ Authorization: `PublicToken ${input.publishableKey}`
1157
+ },
1158
+ body: JSON.stringify({
1159
+ api_pub: input.apiPubHex,
1160
+ signed_body: (0, import_utils.bytesToHex)(signedBodyBytes),
1161
+ agent_signature: (0, import_utils.bytesToHex)(agentSig)
1162
+ })
1163
+ });
1164
+ } catch (e) {
1165
+ throw new EphemeralSignerSignError(
1166
+ `wallet binding fetch failed: ${e instanceof Error ? e.message : String(e)}`
1167
+ );
1168
+ }
1169
+ if (!response.ok) {
1170
+ const body = await response.text().catch(() => "");
1171
+ throw new EphemeralSignerSignError(
1172
+ `wallet binding fetch failed: ${response.status}`,
1173
+ response.status,
1174
+ body
1175
+ );
1176
+ }
1177
+ const json = await response.json();
1178
+ const bindings = json.wallets.map((w) => ({
1179
+ walletId: w.wallet_id,
1180
+ keyId: w.key_id,
1181
+ derivationPath: w.derivation_path
1182
+ }));
1183
+ bindingsCache.set(input.apiPubHex, bindings);
1184
+ const hit = bindings.find((b) => b.walletId === input.walletId);
1185
+ if (!hit) {
1186
+ throw new EphemeralSignerSignError(
1187
+ `walletId ${input.walletId} is not authorized for this agent`
1188
+ );
1189
+ }
1190
+ return hit;
1191
+ }
1192
+ async function signWithEphemeralSigner(input) {
1193
+ if (!/^[0-9a-f]{64}$/i.test(input.apiPubHex)) {
1194
+ throw new EphemeralSignerSignError(
1195
+ "apiPubHex must be 64 lowercase hex chars (32-byte Ed25519 pubkey)"
1196
+ );
1197
+ }
1198
+ if (!/^[0-9a-f]{64}$/i.test(input.apiPrivHex)) {
1199
+ throw new EphemeralSignerSignError(
1200
+ "apiPrivHex must be 64 lowercase hex chars (32-byte Ed25519 privkey)"
1201
+ );
1202
+ }
1203
+ if (!input.walletId) {
1204
+ throw new EphemeralSignerSignError("walletId is required");
1205
+ }
1206
+ if (!input.rawSigningPayloadHex || !/^[0-9a-f]+$/i.test(input.rawSigningPayloadHex)) {
1207
+ throw new EphemeralSignerSignError(
1208
+ "rawSigningPayloadHex must be a non-empty lowercase hex string"
1209
+ );
1210
+ }
1211
+ if (!input.publishableKey) {
1212
+ throw new EphemeralSignerSignError(
1213
+ "publishableKey is required \u2014 wallets backend gates /ephemeral-signers/* with RequirePublicToken"
1214
+ );
1215
+ }
1216
+ const binding = await resolveBinding(input);
1217
+ const issuedAt = (input.issuedAt ?? /* @__PURE__ */ new Date()).toISOString();
1218
+ const signedPayload = {
1219
+ raw_signing_payload: input.rawSigningPayloadHex,
1220
+ key_id: binding.keyId,
1221
+ derivation_path: binding.derivationPath,
1222
+ issued_at: issuedAt
1223
+ };
1224
+ const signedBodyBytes = new TextEncoder().encode(
1225
+ JSON.stringify(signedPayload)
1226
+ );
1227
+ const apiPrivBytes = (0, import_utils.hexToBytes)(input.apiPrivHex);
1228
+ const agentSig = import_ed25519.ed25519.sign(signedBodyBytes, apiPrivBytes);
1229
+ const requestBody = {
1230
+ api_pub: input.apiPubHex,
1231
+ signed_body: (0, import_utils.bytesToHex)(signedBodyBytes),
1232
+ agent_signature: (0, import_utils.bytesToHex)(agentSig)
1233
+ };
1234
+ const url = `${normalizeBase(input.baseUrl)}/v0/wallets/ephemeral-signers/sign`;
1235
+ const fetchFn = input.fetchImpl ?? fetch;
1236
+ let response;
1237
+ try {
1238
+ response = await fetchFn(url, {
1239
+ method: "POST",
1240
+ headers: {
1241
+ "Content-Type": "application/json",
1242
+ Authorization: `PublicToken ${input.publishableKey}`
1243
+ },
1244
+ body: JSON.stringify(requestBody)
1245
+ });
1246
+ } catch (e) {
1247
+ throw new EphemeralSignerSignError(
1248
+ `transport failure: ${e instanceof Error ? e.message : String(e)}`
1249
+ );
1250
+ }
1251
+ if (!response.ok) {
1252
+ const body = await response.text().catch(() => "");
1253
+ throw new EphemeralSignerSignError(
1254
+ `ephemeral signer sign failed: ${response.status}`,
1255
+ response.status,
1256
+ body
1257
+ );
1258
+ }
1259
+ return await response.json();
1260
+ }
1004
1261
  // Annotate the CommonJS export names for ESM import in node:
1005
1262
  0 && (module.exports = {
1263
+ EphemeralSignerSignError,
1006
1264
  assertPasskeyInParent,
1007
1265
  flattenPresenceTokens,
1008
1266
  getHeadlessAuthenticationMethods,
@@ -1010,5 +1268,7 @@ var getHeadlessGeneralMethods = ({
1010
1268
  getHeadlessGeneralMethods,
1011
1269
  getHeadlessSolanaMethods,
1012
1270
  getInternalPresenceTokens,
1013
- getPresenceToken
1271
+ getPresenceToken,
1272
+ resolveRelyingPartyOrigin,
1273
+ signWithEphemeralSigner
1014
1274
  });