@zerodev/wallet-core 0.0.1-alpha.22 → 0.0.1-alpha.24

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 (73) hide show
  1. package/README.md +2 -29
  2. package/dist/_cjs/actions/auth/authenticateWithEmail.js +1 -2
  3. package/dist/_cjs/actions/auth/authenticateWithEmail.js.map +1 -1
  4. package/dist/_cjs/actions/auth/getAuthenticators.js +3 -6
  5. package/dist/_cjs/actions/auth/getAuthenticators.js.map +1 -1
  6. package/dist/_cjs/actions/auth/index.js.map +1 -1
  7. package/dist/_cjs/actions/auth/loginWithStamp.js +0 -1
  8. package/dist/_cjs/actions/auth/loginWithStamp.js.map +1 -1
  9. package/dist/_cjs/actions/auth/registerWithOTP.js +1 -7
  10. package/dist/_cjs/actions/auth/registerWithOTP.js.map +1 -1
  11. package/dist/_cjs/actions/auth/registerWithPasskey.js.map +1 -1
  12. package/dist/_cjs/actions/index.js.map +1 -1
  13. package/dist/_cjs/actions/wallet/getUserWallet.js +3 -5
  14. package/dist/_cjs/actions/wallet/getUserWallet.js.map +1 -1
  15. package/dist/_cjs/client/transports/rest.js +33 -21
  16. package/dist/_cjs/client/transports/rest.js.map +1 -1
  17. package/dist/_cjs/core/createZeroDevWalletCore.js +3 -11
  18. package/dist/_cjs/core/createZeroDevWalletCore.js.map +1 -1
  19. package/dist/_cjs/index.js.map +1 -1
  20. package/dist/_cjs/index.native.js.map +1 -1
  21. package/dist/_esm/actions/auth/authenticateWithEmail.js +1 -2
  22. package/dist/_esm/actions/auth/authenticateWithEmail.js.map +1 -1
  23. package/dist/_esm/actions/auth/getAuthenticators.js +6 -6
  24. package/dist/_esm/actions/auth/getAuthenticators.js.map +1 -1
  25. package/dist/_esm/actions/auth/index.js.map +1 -1
  26. package/dist/_esm/actions/auth/loginWithStamp.js +4 -1
  27. package/dist/_esm/actions/auth/loginWithStamp.js.map +1 -1
  28. package/dist/_esm/actions/auth/registerWithOTP.js +5 -7
  29. package/dist/_esm/actions/auth/registerWithOTP.js.map +1 -1
  30. package/dist/_esm/actions/auth/registerWithPasskey.js.map +1 -1
  31. package/dist/_esm/actions/index.js.map +1 -1
  32. package/dist/_esm/actions/wallet/getUserWallet.js +5 -5
  33. package/dist/_esm/actions/wallet/getUserWallet.js.map +1 -1
  34. package/dist/_esm/client/transports/rest.js +37 -22
  35. package/dist/_esm/client/transports/rest.js.map +1 -1
  36. package/dist/_esm/core/createZeroDevWalletCore.js +15 -11
  37. package/dist/_esm/core/createZeroDevWalletCore.js.map +1 -1
  38. package/dist/_esm/index.js.map +1 -1
  39. package/dist/_esm/index.native.js.map +1 -1
  40. package/dist/_types/actions/auth/authenticateWithEmail.d.ts +0 -6
  41. package/dist/_types/actions/auth/authenticateWithEmail.d.ts.map +1 -1
  42. package/dist/_types/actions/auth/index.d.ts +2 -2
  43. package/dist/_types/actions/auth/index.d.ts.map +1 -1
  44. package/dist/_types/actions/auth/loginWithStamp.d.ts +0 -4
  45. package/dist/_types/actions/auth/loginWithStamp.d.ts.map +1 -1
  46. package/dist/_types/actions/auth/registerWithOTP.d.ts +4 -11
  47. package/dist/_types/actions/auth/registerWithOTP.d.ts.map +1 -1
  48. package/dist/_types/actions/auth/registerWithPasskey.d.ts +0 -4
  49. package/dist/_types/actions/auth/registerWithPasskey.d.ts.map +1 -1
  50. package/dist/_types/actions/index.d.ts +1 -1
  51. package/dist/_types/actions/index.d.ts.map +1 -1
  52. package/dist/_types/client/transports/rest.d.ts +8 -1
  53. package/dist/_types/client/transports/rest.d.ts.map +1 -1
  54. package/dist/_types/core/createZeroDevWalletCore.d.ts +0 -6
  55. package/dist/_types/core/createZeroDevWalletCore.d.ts.map +1 -1
  56. package/dist/_types/index.d.ts +1 -1
  57. package/dist/_types/index.d.ts.map +1 -1
  58. package/dist/_types/index.native.d.ts +1 -1
  59. package/dist/_types/index.native.d.ts.map +1 -1
  60. package/dist/tsconfig.build.tsbuildinfo +1 -1
  61. package/package.json +1 -1
  62. package/src/actions/auth/authenticateWithEmail.ts +1 -9
  63. package/src/actions/auth/getAuthenticators.ts +6 -6
  64. package/src/actions/auth/index.ts +0 -2
  65. package/src/actions/auth/loginWithStamp.ts +4 -6
  66. package/src/actions/auth/registerWithOTP.ts +5 -28
  67. package/src/actions/auth/registerWithPasskey.ts +0 -5
  68. package/src/actions/index.ts +0 -1
  69. package/src/actions/wallet/getUserWallet.ts +5 -5
  70. package/src/client/transports/rest.ts +45 -23
  71. package/src/core/createZeroDevWalletCore.ts +15 -22
  72. package/src/index.native.ts +0 -1
  73. package/src/index.ts +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zerodev/wallet-core",
3
- "version": "0.0.1-alpha.22",
3
+ "version": "0.0.1-alpha.24",
4
4
  "description": "ZeroDev Wallet SDK built on Turnkey",
5
5
  "sideEffects": false,
6
6
  "main": "./dist/_cjs/index.js",
@@ -1,10 +1,5 @@
1
1
  import type { Client } from '../../client/types.js'
2
2
 
3
- export type EmailCustomization = {
4
- /** A template for the URL to be used in a magic link button, e.g. `https://dapp.xyz/%s`. The auth bundle will be interpolated into the `%s`. */
5
- magicLinkTemplate?: string
6
- }
7
-
8
3
  export type AuthenticateWithEmailParameters = {
9
4
  /** The email address to authenticate */
10
5
  email: string
@@ -12,8 +7,6 @@ export type AuthenticateWithEmailParameters = {
12
7
  projectId: string
13
8
  /** Target public key for authentication */
14
9
  targetPublicKey: string
15
- /** Optional email customization settings */
16
- emailCustomization?: EmailCustomization
17
10
  }
18
11
 
19
12
  export type AuthenticateWithEmailReturnType = {
@@ -37,14 +30,13 @@ export async function authenticateWithEmail(
37
30
  client: Client,
38
31
  params: AuthenticateWithEmailParameters,
39
32
  ): Promise<AuthenticateWithEmailReturnType> {
40
- const { email, projectId, targetPublicKey, emailCustomization } = params
33
+ const { email, projectId, targetPublicKey } = params
41
34
 
42
35
  return await client.request({
43
36
  path: `${projectId}/auth/email-magic`,
44
37
  method: 'POST',
45
38
  body: {
46
39
  email,
47
- emailCustomization,
48
40
  targetPublicKey,
49
41
  projectId,
50
42
  },
@@ -72,18 +72,18 @@ export async function getAuthenticators(
72
72
  client: Client,
73
73
  params: GetAuthenticatorsParameters,
74
74
  ): Promise<GetAuthenticatorsReturnType> {
75
- const { subOrganizationId, projectId, token } = params
75
+ const { projectId, token } = params
76
76
 
77
+ // GET behind StampCheckUser: the backend resolves the user from the stamped
78
+ // credential (+ session JWT), so no body / sub-org is sent. The stamp signs
79
+ // the X-Timestamp value (see transport `stampPostion: 'timestamp'`).
77
80
  return await client.request({
78
81
  path: `${projectId}/authenticators`,
79
- method: 'POST',
80
- body: {
81
- subOrganizationId,
82
- },
82
+ method: 'GET',
83
83
  headers: {
84
84
  Authorization: `Bearer ${token}`,
85
85
  },
86
86
  stamp: true,
87
- stampPostion: 'headers',
87
+ stampPostion: 'timestamp',
88
88
  })
89
89
  }
@@ -2,7 +2,6 @@ export {
2
2
  type AuthenticateWithEmailParameters,
3
3
  type AuthenticateWithEmailReturnType,
4
4
  authenticateWithEmail,
5
- type EmailCustomization,
6
5
  } from './authenticateWithEmail.js'
7
6
 
8
7
  export {
@@ -44,7 +43,6 @@ export {
44
43
  loginWithStamp,
45
44
  } from './loginWithStamp.js'
46
45
  export {
47
- type OtpCodeCustomization,
48
46
  type OtpContact,
49
47
  type RegisterWithOTPParameters,
50
48
  type RegisterWithOTPReturnType,
@@ -3,11 +3,6 @@ import type { Client } from '../../client/types.js'
3
3
  import type { Stamp } from '../../stampers/types.js'
4
4
  import type { StamperType } from '../../types/session.js'
5
5
 
6
- export type EmailCustomization = {
7
- /** A template for the URL to be used in a magic link button, e.g. `https://dapp.xyz/%s`. The auth bundle will be interpolated into the `%s`. */
8
- magicLinkTemplate?: string
9
- }
10
-
11
6
  export type LoginWithStampParameters = {
12
7
  /** The project ID for the request */
13
8
  projectId: string
@@ -70,8 +65,11 @@ export async function loginWithStamp(
70
65
  return client.request({
71
66
  path: `${projectId}/auth/login/stamp`,
72
67
  method: 'POST',
68
+ // The sub-org id is intentionally not sent: the backend derives it from
69
+ // the stamped credential. `organizationId` (the parent org) is only
70
+ // signed into `stampPayload` above so the stamp matches the body the
71
+ // backend relays to Turnkey — it is not part of the wire request.
73
72
  body: {
74
- subOrganizationId: organizationId,
75
73
  targetPublicKey,
76
74
  timestamp: timestampIso,
77
75
  stamp,
@@ -1,5 +1,4 @@
1
1
  import type { Client } from '../../client/types.js'
2
- import type { EmailCustomization } from './authenticateWithEmail.js'
3
2
 
4
3
  export type OtpContact = {
5
4
  /** The OTP delivery type (currently only 'email' is supported) */
@@ -8,13 +7,6 @@ export type OtpContact = {
8
7
  contact: string
9
8
  }
10
9
 
11
- export type OtpCodeCustomization = {
12
- /** The length of the OTP code (must be between 6 and 9 inclusive) */
13
- length: 6 | 7 | 8 | 9
14
- /** Whether the OTP code should be alphanumeric */
15
- alphanumeric: boolean
16
- }
17
-
18
10
  export type RegisterWithOTPParameters = {
19
11
  /** The email address to register */
20
12
  email: string
@@ -22,10 +14,6 @@ export type RegisterWithOTPParameters = {
22
14
  contact: OtpContact
23
15
  /** The project ID for the request */
24
16
  projectId: string
25
- /** Optional email customization settings */
26
- emailCustomization?: EmailCustomization
27
- /** Optional OTP code customization settings */
28
- otpCodeCustomization?: OtpCodeCustomization
29
17
  }
30
18
 
31
19
  export type RegisterWithOTPReturnType = {
@@ -43,6 +31,10 @@ export type RegisterWithOTPReturnType = {
43
31
  * Initiates OTP (One-Time Password) authentication
44
32
  * This will send an OTP code to the specified contact method
45
33
  *
34
+ * OTP code length/format and, when enabled, the magic-link URL template are
35
+ * configured per-project on the backend (`wallet.otp_configs`). The client no
36
+ * longer sends customization fields — they are ignored server-side.
37
+ *
46
38
  * @param client - The ZeroDev Wallet client
47
39
  * @param params - The parameters for OTP initiation
48
40
  * @returns The result including otpId needed for verification
@@ -65,20 +57,7 @@ export async function registerWithOTP(
65
57
  client: Client,
66
58
  params: RegisterWithOTPParameters,
67
59
  ): Promise<RegisterWithOTPReturnType> {
68
- const {
69
- email,
70
- contact,
71
- projectId,
72
- emailCustomization,
73
- otpCodeCustomization,
74
- } = params
75
-
76
- if (
77
- otpCodeCustomization &&
78
- (otpCodeCustomization.length < 6 || otpCodeCustomization.length > 9)
79
- ) {
80
- throw new Error('OTP code length must be between 6 and 9')
81
- }
60
+ const { email, contact, projectId } = params
82
61
 
83
62
  return await client.request({
84
63
  path: `${projectId}/auth/init/otp`,
@@ -86,8 +65,6 @@ export async function registerWithOTP(
86
65
  body: {
87
66
  email,
88
67
  contact,
89
- emailCustomization,
90
- otpCodeCustomization,
91
68
  },
92
69
  })
93
70
  }
@@ -1,10 +1,5 @@
1
1
  import type { Client } from '../../client/types.js'
2
2
 
3
- export type EmailCustomization = {
4
- /** A template for the URL to be used in a magic link button, e.g. `https://dapp.xyz/%s`. The auth bundle will be interpolated into the `%s`. */
5
- magicLinkTemplate?: string
6
- }
7
-
8
3
  export type RegisterWithPasskeyParameters = {
9
4
  /** The project ID for the request */
10
5
  projectId: string
@@ -8,7 +8,6 @@ export {
8
8
  authenticateWithEmail,
9
9
  authenticateWithOAuth,
10
10
  type EmailContact,
11
- type EmailCustomization,
12
11
  type GetAuthenticatorsParameters,
13
12
  type GetAuthenticatorsReturnType,
14
13
  type GetAuthProxyConfigIdReturnType,
@@ -37,17 +37,17 @@ export async function getUserWallet(
37
37
  client: Client,
38
38
  params: GetUserWalletParameters,
39
39
  ): Promise<GetUserWalletReturnType> {
40
- const { organizationId, projectId, token } = params
40
+ const { projectId, token } = params
41
41
 
42
+ // GET behind StampCheckUser: user is resolved from the stamped credential
43
+ // (+ session JWT); no body sent. The stamp signs the X-Timestamp value.
42
44
  return await client.request({
43
45
  path: `${projectId}/user-wallet`,
44
- body: {
45
- organizationId,
46
- },
46
+ method: 'GET',
47
47
  headers: {
48
48
  Authorization: `Bearer ${token}`,
49
49
  },
50
50
  stamp: true,
51
- stampPostion: 'headers',
51
+ stampPostion: 'timestamp',
52
52
  })
53
53
  }
@@ -10,7 +10,14 @@ export type RestRequestArgs = {
10
10
  headers?: Record<string, string>
11
11
  stamp?: boolean
12
12
  stampWith?: StamperType
13
- stampPostion?: 'body' | 'headers'
13
+ /**
14
+ * Where the stamp goes / what it signs:
15
+ * - `body`/`headers`: sign the canonicalized request body (POST endpoints).
16
+ * - `timestamp`: GET endpoints behind StampCheckUser — sign the current
17
+ * unix-millis string, send it as the `X-Timestamp` header plus the stamp
18
+ * header. No request body. Matches the backend's `FormatTimestamp`.
19
+ */
20
+ stampPostion?: 'body' | 'headers' | 'timestamp'
14
21
  /** Include credentials (cookies) in the request */
15
22
  credentials?: RequestCredentials
16
23
  }
@@ -49,8 +56,8 @@ export function rest(url: string, cfg: RestTransportConfig): RestTransport {
49
56
 
50
57
  try {
51
58
  let requestBody = args.body
52
- let requestHeaders = {
53
- ...(cfg.fetchOptions?.headers ?? {}),
59
+ let requestHeaders: Record<string, string> = {
60
+ ...((cfg.fetchOptions?.headers as Record<string, string>) ?? {}),
54
61
  ...(args.headers ?? {}),
55
62
  'content-type': 'application/json',
56
63
  }
@@ -65,32 +72,47 @@ export function rest(url: string, cfg: RestTransportConfig): RestTransport {
65
72
  } else {
66
73
  stamper = cfg.apiKeyStamper
67
74
  }
68
- const { body, apiUrl } = args.body
69
- const bodyString = canonicalizeEx(body ?? args.body)
70
- const stamp = await stamper.stamp(bodyString)
71
75
 
72
- // Restructure request body to match backend expectation
73
- if (args.stampPostion === 'headers') {
76
+ // Timestamped stamp for GET endpoints behind StampCheckUser: the
77
+ // signed body is the unix-millis string itself (the backend rebuilds
78
+ // it from the X-Timestamp header via FormatTimestamp). No request body.
79
+ if (args.stampPostion === 'timestamp') {
80
+ const ts = Date.now().toString()
81
+ const stamp = await stamper.stamp(ts)
74
82
  requestHeaders = {
75
83
  ...requestHeaders,
84
+ 'X-Timestamp': ts,
76
85
  [stamp.stampHeaderName]: stamp.stampHeaderValue,
77
86
  }
78
- } else if (body) {
79
- requestBody = {
80
- body: bodyString,
81
- stamp: {
82
- stampHeaderName: stamp.stampHeaderName,
83
- stampHeaderValue: stamp.stampHeaderValue,
84
- },
85
- apiUrl: apiUrl,
86
- }
87
+ requestBody = undefined
87
88
  } else {
88
- requestBody = {
89
- ...args.body,
90
- stamp: {
91
- stampHeaderName: stamp.stampHeaderName,
92
- stampHeaderValue: stamp.stampHeaderValue,
93
- },
89
+ const { body, apiUrl } = args.body
90
+ const bodyString = canonicalizeEx(body ?? args.body)
91
+ const stamp = await stamper.stamp(bodyString)
92
+
93
+ // Restructure request body to match backend expectation
94
+ if (args.stampPostion === 'headers') {
95
+ requestHeaders = {
96
+ ...requestHeaders,
97
+ [stamp.stampHeaderName]: stamp.stampHeaderValue,
98
+ }
99
+ } else if (body) {
100
+ requestBody = {
101
+ body: bodyString,
102
+ stamp: {
103
+ stampHeaderName: stamp.stampHeaderName,
104
+ stampHeaderValue: stamp.stampHeaderValue,
105
+ },
106
+ apiUrl: apiUrl,
107
+ }
108
+ } else {
109
+ requestBody = {
110
+ ...args.body,
111
+ stamp: {
112
+ stampHeaderName: stamp.stampHeaderName,
113
+ stampHeaderValue: stamp.stampHeaderValue,
114
+ },
115
+ }
94
116
  }
95
117
  }
96
118
  }
@@ -1,8 +1,4 @@
1
1
  import type { LocalAccount } from 'viem/accounts'
2
- import type {
3
- EmailCustomization,
4
- OtpCodeCustomization,
5
- } from '../actions/auth/index.js'
6
2
  import { toViemAccount } from '../adapters/viem.js'
7
3
  import {
8
4
  type CreateTransportOptions,
@@ -37,8 +33,6 @@ export interface ZeroDevWalletConfigCore {
37
33
  fetchOptions?: CreateTransportOptions['fetchOptions']
38
34
  }
39
35
 
40
- // Re-export EmailCustomization for convenience
41
- export type { EmailCustomization } from '../actions/auth/index.js'
42
36
  export type { StorageAdapter, StorageManager } from '../storage/manager.js'
43
37
  // Re-export new session types
44
38
  export type { StamperType, ZeroDevWalletSession } from '../types/session.js'
@@ -61,8 +55,6 @@ export type AuthParams =
61
55
  type: 'email' | 'sms'
62
56
  contact: string
63
57
  }
64
- emailCustomization?: EmailCustomization
65
- otpCodeCustomization?: OtpCodeCustomization
66
58
  }
67
59
  | {
68
60
  type: 'otp'
@@ -79,8 +71,6 @@ export type AuthParams =
79
71
  type: 'magicLink'
80
72
  mode: 'send'
81
73
  email: string
82
- redirectURL: string
83
- otpCodeCustomization?: OtpCodeCustomization
84
74
  }
85
75
  | {
86
76
  type: 'magicLink'
@@ -190,7 +180,11 @@ export async function createZeroDevWalletCore(
190
180
  const data = await client.loginWithStamp({
191
181
  targetPublicKey: compressedPublicKeyHex,
192
182
  projectId,
193
- organizationId: activeSession.organizationId,
183
+ // Stamp-login is signed against the Turnkey parent org; the backend
184
+ // resolves the sub-org from the stamped credential. Signing the
185
+ // sub-org here makes the relayed payload's org mismatch the
186
+ // signature → Turnkey SIGNATURE_INVALID.
187
+ organizationId,
194
188
  stampWith: 'apiKey',
195
189
  })
196
190
  await client.apiKeyStamper.commitKeyRotation()
@@ -270,7 +264,9 @@ export async function createZeroDevWalletCore(
270
264
  const loginData = await client.loginWithStamp({
271
265
  projectId,
272
266
  targetPublicKey: compressedPublicKeyHex,
273
- organizationId: data.subOrganizationId,
267
+ // Sign against the parent org (see refreshSession note) — the
268
+ // backend derives the sub-org from the stamped credential.
269
+ organizationId,
274
270
  })
275
271
  await client.apiKeyStamper.commitKeyRotation()
276
272
  const parsedSession = parseSession(loginData.session)
@@ -302,6 +298,9 @@ export async function createZeroDevWalletCore(
302
298
  const loginData = await client.loginWithStamp({
303
299
  targetPublicKey: generatedPublicKey,
304
300
  projectId,
301
+ // Sign against the parent org, not the user's sub-org (see the
302
+ // refreshSession note). The backend derives the sub-org from the
303
+ // stamped passkey credential.
305
304
  organizationId,
306
305
  stampWith: 'passkey',
307
306
  })
@@ -329,17 +328,14 @@ export async function createZeroDevWalletCore(
329
328
  let otpParams: Extract<AuthParams, { type: 'otp' }>
330
329
  if (params.type === 'magicLink') {
331
330
  if (params.mode === 'send') {
331
+ // Magic-link vs plain-OTP delivery and the link URL template are
332
+ // configured per-project on the backend (`wallet.otp_configs`);
333
+ // the client just initiates OTP and the backend decides.
332
334
  otpParams = {
333
335
  type: 'otp',
334
336
  mode: 'sendOtp',
335
337
  email: params.email,
336
338
  contact: { type: 'email', contact: params.email },
337
- emailCustomization: {
338
- magicLinkTemplate: `${params.redirectURL}${params.redirectURL.includes('?') ? '&' : '?'}code=%s`,
339
- },
340
- ...(params.otpCodeCustomization && {
341
- otpCodeCustomization: params.otpCodeCustomization,
342
- }),
343
339
  }
344
340
  } else {
345
341
  otpParams = {
@@ -355,15 +351,12 @@ export async function createZeroDevWalletCore(
355
351
  }
356
352
 
357
353
  if (otpParams.mode === 'sendOtp') {
358
- const { email, contact, emailCustomization, otpCodeCustomization } =
359
- otpParams
354
+ const { email, contact } = otpParams
360
355
 
361
356
  const data = await client.registerWithOTP({
362
357
  email,
363
358
  contact,
364
359
  projectId,
365
- ...(emailCustomization && { emailCustomization }),
366
- ...(otpCodeCustomization && { otpCodeCustomization }),
367
360
  })
368
361
 
369
362
  return data
@@ -19,7 +19,6 @@ export type {
19
19
  AuthenticateWithOAuthParameters,
20
20
  AuthenticateWithOAuthReturnType,
21
21
  EmailContact,
22
- EmailCustomization,
23
22
  GetAuthenticatorsParameters,
24
23
  GetAuthenticatorsReturnType,
25
24
  GetUserWalletParameters,
package/src/index.ts CHANGED
@@ -15,7 +15,6 @@ export type {
15
15
  AuthenticateWithOAuthParameters,
16
16
  AuthenticateWithOAuthReturnType,
17
17
  EmailContact,
18
- EmailCustomization,
19
18
  GetAuthenticatorsParameters,
20
19
  GetAuthenticatorsReturnType,
21
20
  // Wallet types