@zerodev/wallet-core 0.0.1-alpha.18 → 0.0.1-alpha.19

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 (128) hide show
  1. package/dist/_cjs/actions/auth/getOAuthLoginUrl.js +18 -0
  2. package/dist/_cjs/actions/auth/getOAuthLoginUrl.js.map +1 -0
  3. package/dist/_cjs/actions/auth/getWhoami.js +2 -2
  4. package/dist/_cjs/actions/auth/getWhoami.js.map +1 -1
  5. package/dist/_cjs/actions/auth/index.js +3 -1
  6. package/dist/_cjs/actions/auth/index.js.map +1 -1
  7. package/dist/_cjs/actions/auth/loginWithStamp.js +5 -5
  8. package/dist/_cjs/actions/auth/loginWithStamp.js.map +1 -1
  9. package/dist/_cjs/actions/index.js +2 -1
  10. package/dist/_cjs/actions/index.js.map +1 -1
  11. package/dist/_cjs/actions/wallet/signingUtils.js +2 -2
  12. package/dist/_cjs/actions/wallet/signingUtils.js.map +1 -1
  13. package/dist/_cjs/client/createClient.js +5 -5
  14. package/dist/_cjs/client/createClient.js.map +1 -1
  15. package/dist/_cjs/client/decorators/client.js +1 -0
  16. package/dist/_cjs/client/decorators/client.js.map +1 -1
  17. package/dist/_cjs/client/transports/createTransport.js +5 -5
  18. package/dist/_cjs/client/transports/createTransport.js.map +1 -1
  19. package/dist/_cjs/client/transports/rest.js +5 -5
  20. package/dist/_cjs/client/transports/rest.js.map +1 -1
  21. package/dist/_cjs/core/createZeroDevWallet.js +29 -61
  22. package/dist/_cjs/core/createZeroDevWallet.js.map +1 -1
  23. package/dist/_cjs/index.js.map +1 -1
  24. package/dist/_cjs/stampers/indexedDbStamper.js +17 -2
  25. package/dist/_cjs/stampers/indexedDbStamper.js.map +1 -1
  26. package/dist/_cjs/stampers/webauthnStamper.js +23 -3
  27. package/dist/_cjs/stampers/webauthnStamper.js.map +1 -1
  28. package/dist/_cjs/utils/exportPrivateKey.js +1 -1
  29. package/dist/_cjs/utils/exportPrivateKey.js.map +1 -1
  30. package/dist/_cjs/utils/exportWallet.js +2 -6
  31. package/dist/_cjs/utils/exportWallet.js.map +1 -1
  32. package/dist/_cjs/utils/hpke.js +4 -15
  33. package/dist/_cjs/utils/hpke.js.map +1 -1
  34. package/dist/_cjs/utils/utils.js +5 -6
  35. package/dist/_cjs/utils/utils.js.map +1 -1
  36. package/dist/_esm/actions/auth/getOAuthLoginUrl.js +23 -0
  37. package/dist/_esm/actions/auth/getOAuthLoginUrl.js.map +1 -0
  38. package/dist/_esm/actions/auth/getWhoami.js +2 -2
  39. package/dist/_esm/actions/auth/getWhoami.js.map +1 -1
  40. package/dist/_esm/actions/auth/index.js +1 -0
  41. package/dist/_esm/actions/auth/index.js.map +1 -1
  42. package/dist/_esm/actions/auth/loginWithStamp.js +5 -5
  43. package/dist/_esm/actions/auth/loginWithStamp.js.map +1 -1
  44. package/dist/_esm/actions/index.js +1 -1
  45. package/dist/_esm/actions/index.js.map +1 -1
  46. package/dist/_esm/actions/wallet/signingUtils.js +2 -2
  47. package/dist/_esm/actions/wallet/signingUtils.js.map +1 -1
  48. package/dist/_esm/client/createClient.js +5 -5
  49. package/dist/_esm/client/createClient.js.map +1 -1
  50. package/dist/_esm/client/decorators/client.js +2 -1
  51. package/dist/_esm/client/decorators/client.js.map +1 -1
  52. package/dist/_esm/client/transports/createTransport.js +5 -5
  53. package/dist/_esm/client/transports/createTransport.js.map +1 -1
  54. package/dist/_esm/client/transports/rest.js +5 -5
  55. package/dist/_esm/client/transports/rest.js.map +1 -1
  56. package/dist/_esm/core/createZeroDevWallet.js +30 -62
  57. package/dist/_esm/core/createZeroDevWallet.js.map +1 -1
  58. package/dist/_esm/index.js.map +1 -1
  59. package/dist/_esm/stampers/indexedDbStamper.js +17 -2
  60. package/dist/_esm/stampers/indexedDbStamper.js.map +1 -1
  61. package/dist/_esm/stampers/webauthnStamper.js +23 -4
  62. package/dist/_esm/stampers/webauthnStamper.js.map +1 -1
  63. package/dist/_esm/utils/exportPrivateKey.js +1 -1
  64. package/dist/_esm/utils/exportPrivateKey.js.map +1 -1
  65. package/dist/_esm/utils/exportWallet.js +2 -6
  66. package/dist/_esm/utils/exportWallet.js.map +1 -1
  67. package/dist/_esm/utils/hpke.js +6 -22
  68. package/dist/_esm/utils/hpke.js.map +1 -1
  69. package/dist/_esm/utils/utils.js +5 -6
  70. package/dist/_esm/utils/utils.js.map +1 -1
  71. package/dist/_types/actions/auth/getOAuthLoginUrl.d.ts +30 -0
  72. package/dist/_types/actions/auth/getOAuthLoginUrl.d.ts.map +1 -0
  73. package/dist/_types/actions/auth/index.d.ts +1 -0
  74. package/dist/_types/actions/auth/index.d.ts.map +1 -1
  75. package/dist/_types/actions/auth/loginWithStamp.d.ts +2 -1
  76. package/dist/_types/actions/auth/loginWithStamp.d.ts.map +1 -1
  77. package/dist/_types/actions/index.d.ts +1 -1
  78. package/dist/_types/actions/index.d.ts.map +1 -1
  79. package/dist/_types/client/decorators/client.d.ts +7 -1
  80. package/dist/_types/client/decorators/client.d.ts.map +1 -1
  81. package/dist/_types/client/transports/rest.d.ts +5 -4
  82. package/dist/_types/client/transports/rest.d.ts.map +1 -1
  83. package/dist/_types/client/types.d.ts +9 -9
  84. package/dist/_types/client/types.d.ts.map +1 -1
  85. package/dist/_types/core/createZeroDevWallet.d.ts +3 -0
  86. package/dist/_types/core/createZeroDevWallet.d.ts.map +1 -1
  87. package/dist/_types/index.d.ts +1 -1
  88. package/dist/_types/index.d.ts.map +1 -1
  89. package/dist/_types/stampers/index.d.ts +1 -1
  90. package/dist/_types/stampers/index.d.ts.map +1 -1
  91. package/dist/_types/stampers/indexedDbStamper.d.ts +2 -2
  92. package/dist/_types/stampers/indexedDbStamper.d.ts.map +1 -1
  93. package/dist/_types/stampers/types.d.ts +31 -5
  94. package/dist/_types/stampers/types.d.ts.map +1 -1
  95. package/dist/_types/stampers/webauthnStamper.d.ts +2 -2
  96. package/dist/_types/stampers/webauthnStamper.d.ts.map +1 -1
  97. package/dist/_types/types/session.d.ts +2 -3
  98. package/dist/_types/types/session.d.ts.map +1 -1
  99. package/dist/_types/utils/buildClientSignature.d.ts +3 -3
  100. package/dist/_types/utils/buildClientSignature.d.ts.map +1 -1
  101. package/dist/_types/utils/exportWallet.d.ts.map +1 -1
  102. package/dist/_types/utils/hpke.d.ts.map +1 -1
  103. package/dist/_types/utils/utils.d.ts.map +1 -1
  104. package/dist/tsconfig.build.tsbuildinfo +1 -1
  105. package/package.json +2 -1
  106. package/src/actions/auth/getOAuthLoginUrl.ts +48 -0
  107. package/src/actions/auth/getWhoami.ts +2 -2
  108. package/src/actions/auth/index.ts +5 -0
  109. package/src/actions/auth/loginWithStamp.ts +7 -6
  110. package/src/actions/index.ts +3 -0
  111. package/src/actions/wallet/signingUtils.ts +2 -2
  112. package/src/client/createClient.ts +6 -6
  113. package/src/client/decorators/client.ts +13 -0
  114. package/src/client/transports/createTransport.ts +5 -5
  115. package/src/client/transports/rest.ts +11 -10
  116. package/src/client/types.ts +9 -9
  117. package/src/core/createZeroDevWallet.ts +35 -77
  118. package/src/index.ts +5 -2
  119. package/src/stampers/index.ts +2 -2
  120. package/src/stampers/indexedDbStamper.ts +24 -4
  121. package/src/stampers/types.ts +33 -5
  122. package/src/stampers/webauthnStamper.ts +27 -6
  123. package/src/types/session.ts +2 -3
  124. package/src/utils/buildClientSignature.ts +3 -3
  125. package/src/utils/exportPrivateKey.ts +1 -1
  126. package/src/utils/exportWallet.ts +2 -6
  127. package/src/utils/hpke.ts +7 -33
  128. package/src/utils/utils.ts +5 -6
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zerodev/wallet-core",
3
- "version": "0.0.1-alpha.18",
3
+ "version": "0.0.1-alpha.19",
4
4
  "description": "ZeroDev Wallet SDK built on Turnkey",
5
5
  "main": "./dist/_cjs/index.js",
6
6
  "module": "./dist/_esm/index.js",
@@ -49,6 +49,7 @@
49
49
  ],
50
50
  "license": "MIT",
51
51
  "dependencies": {
52
+ "@noble/ciphers": "^2.2.0",
52
53
  "@noble/curves": "^2.2.0",
53
54
  "@noble/hashes": "^2.2.0",
54
55
  "@turnkey/http": "^3.12.1",
@@ -0,0 +1,48 @@
1
+ import type { Client } from '../../client/types.js'
2
+
3
+ export type GetOAuthLoginUrlParameters = {
4
+ /** OAuth provider — currently only `'google'` is supported. */
5
+ provider: 'google'
6
+ /** The project ID for the request. */
7
+ projectId: string
8
+ /**
9
+ * The session public key (compressed P-256 hex, lowercase, with or
10
+ * without `0x` prefix). The backend embeds `sha256(utf8(hex))` as the
11
+ * OIDC `nonce` so the SDK can verify the URL was minted for this key.
12
+ */
13
+ publicKey: string
14
+ /**
15
+ * Where the popup should land after the OAuth round-trip
16
+ * (e.g. `https://app.example.com/dashboard?oauth_success=true`).
17
+ * Must be on the project's whitelist.
18
+ */
19
+ returnTo: string
20
+ }
21
+
22
+ export type GetOAuthLoginUrlReturnType = string
23
+
24
+ /**
25
+ * Fetches the Google OAuth authorization URL from the backend.
26
+ *
27
+ * The SDK must verify the returned URL's `nonce` against
28
+ * `sha256(utf8(publicKey))` (and the host is `accounts.google.com`)
29
+ * before opening it in a popup — the backend is not a trusted party.
30
+ * See audit finding TOB-KMS-1.
31
+ */
32
+ export async function getOAuthLoginUrl(
33
+ client: Client,
34
+ params: GetOAuthLoginUrlParameters,
35
+ ): Promise<GetOAuthLoginUrlReturnType> {
36
+ if (params.provider !== 'google') {
37
+ throw new Error(`Unsupported OAuth provider: ${params.provider}`)
38
+ }
39
+ const query = new URLSearchParams({
40
+ project_id: params.projectId,
41
+ pub_key: params.publicKey.replace(/^0x/, '').toLowerCase(),
42
+ return_to: params.returnTo,
43
+ })
44
+ return await client.request<string>({
45
+ path: `oauth/google/login-url?${query.toString()}`,
46
+ method: 'GET',
47
+ })
48
+ }
@@ -51,7 +51,7 @@ export async function getWhoami(
51
51
  // Step 1: Inner stamp over the payload (for Turnkey verification)
52
52
  const innerBody = { organizationId }
53
53
  const innerBodyString = canonicalizeEx(innerBody)
54
- const innerStamp = await client.indexedDbStamper.stamp(innerBodyString)
54
+ const innerStamp = await client.apiKeyStamper.stamp(innerBodyString)
55
55
 
56
56
  // Step 2: Build full body with inner stamp embedded
57
57
  const fullBody = {
@@ -64,7 +64,7 @@ export async function getWhoami(
64
64
 
65
65
  // Step 3: Outer stamp over full body (for KMS middleware)
66
66
  const fullBodyString = canonicalizeEx(fullBody)
67
- const outerStamp = await client.indexedDbStamper.stamp(fullBodyString)
67
+ const outerStamp = await client.apiKeyStamper.stamp(fullBodyString)
68
68
 
69
69
  return await client.request({
70
70
  path: `${projectId}/whoami`,
@@ -23,6 +23,11 @@ export {
23
23
  type GetAuthProxyConfigIdReturnType,
24
24
  getAuthProxyConfigId,
25
25
  } from './getAuthProxyConfigId.js'
26
+ export {
27
+ type GetOAuthLoginUrlParameters,
28
+ type GetOAuthLoginUrlReturnType,
29
+ getOAuthLoginUrl,
30
+ } from './getOAuthLoginUrl.js'
26
31
  export {
27
32
  type GetWhoamiParameters,
28
33
  type GetWhoamiReturnType,
@@ -1,6 +1,7 @@
1
1
  import { canonicalizeEx } from 'json-canonicalize'
2
2
  import type { Client } from '../../client/types.js'
3
3
  import type { Stamp } from '../../stampers/types.js'
4
+ import type { StamperType } from '../../types/session.js'
4
5
 
5
6
  export type EmailCustomization = {
6
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`. */
@@ -15,7 +16,7 @@ export type LoginWithStampParameters = {
15
16
  /** The encoded public key for the request */
16
17
  targetPublicKey: string
17
18
  /** The stamper type for the request */
18
- stampWith?: 'indexedDb' | 'webauthn'
19
+ stampWith?: StamperType
19
20
  }
20
21
 
21
22
  export type LoginWithStampReturnType = {
@@ -58,12 +59,12 @@ export async function loginWithStamp(
58
59
  type: 'ACTIVITY_TYPE_STAMP_LOGIN',
59
60
  })
60
61
  let stamp: Stamp
61
- if (stampWith === 'indexedDb') {
62
- stamp = await client.indexedDbStamper.stamp(stampPayload)
63
- } else if (stampWith === 'webauthn') {
64
- stamp = await client.webauthnStamper.stamp(stampPayload)
62
+ if (stampWith === 'apiKey') {
63
+ stamp = await client.apiKeyStamper.stamp(stampPayload)
64
+ } else if (stampWith === 'passkey') {
65
+ stamp = await client.passkeyStamper.stamp(stampPayload)
65
66
  } else {
66
- stamp = await client.indexedDbStamper.stamp(stampPayload)
67
+ stamp = await client.apiKeyStamper.stamp(stampPayload)
67
68
  }
68
69
 
69
70
  return client.request({
@@ -12,10 +12,13 @@ export {
12
12
  type GetAuthenticatorsParameters,
13
13
  type GetAuthenticatorsReturnType,
14
14
  type GetAuthProxyConfigIdReturnType,
15
+ type GetOAuthLoginUrlParameters,
16
+ type GetOAuthLoginUrlReturnType,
15
17
  type GetWhoamiParameters,
16
18
  type GetWhoamiReturnType,
17
19
  getAuthenticators,
18
20
  getAuthProxyConfigId,
21
+ getOAuthLoginUrl,
19
22
  getWhoami,
20
23
  type LoginWithOTPParameters,
21
24
  type LoginWithOTPReturnType,
@@ -47,7 +47,7 @@ export async function sendSigningRequest(
47
47
 
48
48
  // Inner stamp over the Turnkey payload (for Turnkey verification)
49
49
  const innerBodyString = canonicalizeEx(turnkeyPayload)
50
- const innerStamp = await client.indexedDbStamper.stamp(innerBodyString)
50
+ const innerStamp = await client.apiKeyStamper.stamp(innerBodyString)
51
51
 
52
52
  // Build full body with inner stamp embedded
53
53
  const fullBody = {
@@ -61,7 +61,7 @@ export async function sendSigningRequest(
61
61
 
62
62
  // Outer stamp over full body (for KMS middleware)
63
63
  const fullBodyString = canonicalizeEx(fullBody)
64
- const outerStamp = await client.indexedDbStamper.stamp(fullBodyString)
64
+ const outerStamp = await client.apiKeyStamper.stamp(fullBodyString)
65
65
 
66
66
  const { signature } = await client.request({
67
67
  path: `${projectId}/${path}`,
@@ -16,8 +16,8 @@ export function createBaseClient<
16
16
  >(config: ClientConfig): Client<extended> {
17
17
  const {
18
18
  transport,
19
- indexedDbStamper,
20
- webauthnStamper,
19
+ apiKeyStamper,
20
+ passkeyStamper,
21
21
  organizationId,
22
22
  key = 'zeroDevWallet',
23
23
  name = 'ZeroDev Wallet Client',
@@ -29,8 +29,8 @@ export function createBaseClient<
29
29
  request,
30
30
  value,
31
31
  } = transport({
32
- indexedDbStamper,
33
- webauthnStamper,
32
+ apiKeyStamper,
33
+ passkeyStamper,
34
34
  })
35
35
  const transportInstance = { ...transportConfig, ...value }
36
36
 
@@ -39,8 +39,8 @@ export function createBaseClient<
39
39
  const client = {
40
40
  transport: transportInstance,
41
41
  request,
42
- indexedDbStamper,
43
- webauthnStamper,
42
+ apiKeyStamper,
43
+ passkeyStamper,
44
44
  organizationId,
45
45
  key,
46
46
  name,
@@ -13,12 +13,15 @@ import {
13
13
  type GetAuthenticatorsParameters,
14
14
  type GetAuthenticatorsReturnType,
15
15
  type GetAuthProxyConfigIdReturnType,
16
+ type GetOAuthLoginUrlParameters,
17
+ type GetOAuthLoginUrlReturnType,
16
18
  type GetUserWalletParameters,
17
19
  type GetUserWalletReturnType,
18
20
  type GetWhoamiParameters,
19
21
  type GetWhoamiReturnType,
20
22
  getAuthenticators,
21
23
  getAuthProxyConfigId,
24
+ getOAuthLoginUrl,
22
25
  getUserWallet,
23
26
  getWhoami,
24
27
  type LoginWithOTPParameters,
@@ -153,6 +156,15 @@ export type ZeroDevWalletActions = {
153
156
  * Gets the auth proxy config ID from the backend
154
157
  */
155
158
  getAuthProxyConfigId: () => Promise<GetAuthProxyConfigIdReturnType>
159
+
160
+ /**
161
+ * Fetches the Google OAuth authorization URL from the backend.
162
+ * The caller must verify the URL's `nonce` against `sha256(utf8(publicKey))`
163
+ * before opening it (audit finding TOB-KMS-1).
164
+ */
165
+ getOAuthLoginUrl: (
166
+ params: GetOAuthLoginUrlParameters,
167
+ ) => Promise<GetOAuthLoginUrlReturnType>
156
168
  }
157
169
 
158
170
  /**
@@ -197,5 +209,6 @@ export function zeroDevWalletActions(client: Client): ZeroDevWalletActions {
197
209
  registerWithOTP: (params) => registerWithOTP(client, params),
198
210
  loginWithOTP: (params) => loginWithOTP(client, params),
199
211
  getAuthProxyConfigId: () => getAuthProxyConfigId(client),
212
+ getOAuthLoginUrl: (params) => getOAuthLoginUrl(client, params),
200
213
  }
201
214
  }
@@ -26,14 +26,14 @@ export function zeroDevWalletTransport(
26
26
  name = 'ZeroDev Wallet Transport',
27
27
  } = options
28
28
 
29
- return ({ indexedDbStamper, webauthnStamper }) => {
29
+ return ({ apiKeyStamper, passkeyStamper }) => {
30
30
  // Create REST transport with stamper
31
31
  const transport = rest(baseUrl, {
32
32
  timeoutMs,
33
33
  key,
34
34
  name,
35
- indexedDbStamper,
36
- webauthnStamper,
35
+ apiKeyStamper,
36
+ passkeyStamper,
37
37
  })
38
38
 
39
39
  return {
@@ -46,8 +46,8 @@ export function zeroDevWalletTransport(
46
46
  },
47
47
  request: transport.request,
48
48
  value: {
49
- indexedDbStamper,
50
- webauthnStamper,
49
+ apiKeyStamper,
50
+ passkeyStamper,
51
51
  },
52
52
  }
53
53
  }
@@ -1,6 +1,7 @@
1
1
  import { canonicalizeEx } from 'json-canonicalize'
2
2
  import { RestRequestError, RestTimeoutError } from '../../errors/request.js'
3
- import type { IndexedDbStamper, WebauthnStamper } from '../../stampers/types.js'
3
+ import type { ApiKeyStamper, PasskeyStamper } from '../../stampers/types.js'
4
+ import type { StamperType } from '../../types/session.js'
4
5
 
5
6
  export type RestRequestArgs = {
6
7
  path: string
@@ -8,7 +9,7 @@ export type RestRequestArgs = {
8
9
  body?: any
9
10
  headers?: Record<string, string>
10
11
  stamp?: boolean
11
- stampWith?: 'indexedDb' | 'webAuthn'
12
+ stampWith?: StamperType
12
13
  stampPostion?: 'body' | 'headers'
13
14
  /** Include credentials (cookies) in the request */
14
15
  credentials?: RequestCredentials
@@ -32,8 +33,8 @@ export type RestTransportConfig = {
32
33
  timeoutMs?: number
33
34
  key?: string
34
35
  name?: string
35
- indexedDbStamper: IndexedDbStamper
36
- webauthnStamper: WebauthnStamper
36
+ apiKeyStamper: ApiKeyStamper
37
+ passkeyStamper: PasskeyStamper
37
38
  }
38
39
 
39
40
  export function rest(url: string, cfg: RestTransportConfig): RestTransport {
@@ -56,13 +57,13 @@ export function rest(url: string, cfg: RestTransportConfig): RestTransport {
56
57
 
57
58
  // Handle stamping if requested
58
59
  if (args.stamp) {
59
- let stamper: IndexedDbStamper | WebauthnStamper
60
- if (args.stampWith === 'indexedDb') {
61
- stamper = cfg.indexedDbStamper
62
- } else if (args.stampWith === 'webAuthn') {
63
- stamper = cfg.webauthnStamper
60
+ let stamper: ApiKeyStamper | PasskeyStamper
61
+ if (args.stampWith === 'apiKey') {
62
+ stamper = cfg.apiKeyStamper
63
+ } else if (args.stampWith === 'passkey') {
64
+ stamper = cfg.passkeyStamper
64
65
  } else {
65
- stamper = cfg.indexedDbStamper
66
+ stamper = cfg.apiKeyStamper
66
67
  }
67
68
  const { body, apiUrl } = args.body
68
69
  const bodyString = canonicalizeEx(body ?? args.body)
@@ -1,4 +1,4 @@
1
- import type { IndexedDbStamper, WebauthnStamper } from '../stampers/types.js'
1
+ import type { ApiKeyStamper, PasskeyStamper } from '../stampers/types.js'
2
2
  import type { RestRequestFn } from './transports/rest.js'
3
3
 
4
4
  export type TransportConfig = {
@@ -17,8 +17,8 @@ export type TransportConfig = {
17
17
  }
18
18
 
19
19
  export type Transport = (options: {
20
- indexedDbStamper: IndexedDbStamper
21
- webauthnStamper: WebauthnStamper
20
+ apiKeyStamper: ApiKeyStamper
21
+ passkeyStamper: PasskeyStamper
22
22
  }) => {
23
23
  config: TransportConfig
24
24
  request: RestRequestFn
@@ -27,8 +27,8 @@ export type Transport = (options: {
27
27
 
28
28
  export type ClientConfig = {
29
29
  transport: Transport
30
- indexedDbStamper: IndexedDbStamper
31
- webauthnStamper: WebauthnStamper
30
+ apiKeyStamper: ApiKeyStamper
31
+ passkeyStamper: PasskeyStamper
32
32
  organizationId?: string
33
33
  key?: string
34
34
  name?: string
@@ -39,10 +39,10 @@ export type Client<extended extends Extended | undefined = undefined> = {
39
39
  transport: TransportConfig & Record<string, unknown>
40
40
  /** Request function from transport */
41
41
  request: RestRequestFn
42
- /** IndexedDB Stamper for authenticated requests */
43
- indexedDbStamper: IndexedDbStamper
44
- /** WebAuthn Stamper for authenticated requests */
45
- webauthnStamper: WebauthnStamper
42
+ /** API Key Stamper for authenticated requests */
43
+ apiKeyStamper: ApiKeyStamper
44
+ /** Passkey Stamper for authenticated requests */
45
+ passkeyStamper: PasskeyStamper
46
46
  /** Organization ID */
47
47
  organizationId?: string
48
48
  /** A key for the client */
@@ -1,4 +1,3 @@
1
- import { getWebAuthnAttestation } from '@turnkey/http'
2
1
  import type { LocalAccount } from 'viem/accounts'
3
2
  import type {
4
3
  EmailCustomization,
@@ -17,6 +16,7 @@ import {
17
16
  KMS_SERVER_URL,
18
17
  } from '../constants.js'
19
18
  import { createIndexedDbStamper } from '../stampers/indexedDbStamper.js'
19
+ import type { ApiKeyStamper, PasskeyStamper } from '../stampers/types.js'
20
20
  import { createWebauthnStamper } from '../stampers/webauthnStamper.js'
21
21
  import { createWebStorageAdapter } from '../storage/adapters.js'
22
22
  import {
@@ -26,19 +26,15 @@ import {
26
26
  import { SessionType, type ZeroDevWalletSession } from '../types/session.js'
27
27
  import { buildClientSignature } from '../utils/buildClientSignature.js'
28
28
  import { encryptOtpAttempt } from '../utils/encryptOtpAttempt.js'
29
- import {
30
- base64UrlEncode,
31
- generateCompressedPublicKeyFromKeyPair,
32
- generateRandomBuffer,
33
- humanReadableDateTime,
34
- parseSession,
35
- } from '../utils/utils.js'
29
+ import { humanReadableDateTime, parseSession } from '../utils/utils.js'
36
30
  export interface ZeroDevWalletConfig {
37
31
  organizationId?: string
38
32
  proxyBaseUrl?: string
39
33
  projectId: string
40
34
  sessionStorage?: StorageAdapter
41
35
  rpId?: string
36
+ apiKeyStamper?: ApiKeyStamper
37
+ passkeyStamper?: PasskeyStamper
42
38
  }
43
39
 
44
40
  // Re-export EmailCustomization for convenience
@@ -134,13 +130,14 @@ export async function createZeroDevWallet(
134
130
  sessionStorage || createWebStorageAdapter(),
135
131
  )
136
132
 
137
- const indexedDbStamper = await createIndexedDbStamper()
133
+ const apiKeyStamper = config.apiKeyStamper ?? (await createIndexedDbStamper())
138
134
 
139
- const webauthnStamper = await createWebauthnStamper({ rpId })
135
+ const passkeyStamper =
136
+ config.passkeyStamper ?? (await createWebauthnStamper({ rpId }))
140
137
 
141
138
  const client = createClient({
142
- indexedDbStamper,
143
- webauthnStamper,
139
+ apiKeyStamper,
140
+ passkeyStamper,
144
141
  transport: zeroDevWalletTransport({
145
142
  baseUrl: config.proxyBaseUrl || `${KMS_SERVER_URL}/api/v1`,
146
143
  }),
@@ -151,8 +148,8 @@ export async function createZeroDevWallet(
151
148
  return {
152
149
  client,
153
150
  async getPublicKey() {
154
- await client.indexedDbStamper.resetKeyPair()
155
- const compressedPublicKey = await client.indexedDbStamper.getPublicKey()
151
+ await client.apiKeyStamper.resetKeyPair()
152
+ const compressedPublicKey = await client.apiKeyStamper.getPublicKey()
156
153
  return compressedPublicKey
157
154
  },
158
155
 
@@ -191,30 +188,22 @@ export async function createZeroDevWallet(
191
188
  if (!activeSession) {
192
189
  throw new Error('No active session')
193
190
  }
194
- if (activeSession.stamperType === 'indexedDb') {
195
- const newKeyPair = await crypto.subtle.generateKey(
196
- {
197
- name: 'ECDSA',
198
- namedCurve: 'P-256',
199
- },
200
- false,
201
- ['sign', 'verify'],
202
- )
191
+ if (activeSession.stamperType === 'apiKey') {
203
192
  const compressedPublicKeyHex =
204
- await generateCompressedPublicKeyFromKeyPair(newKeyPair)
193
+ await client.apiKeyStamper.prepareKeyRotation()
205
194
  const data = await client.loginWithStamp({
206
195
  targetPublicKey: compressedPublicKeyHex,
207
196
  projectId,
208
197
  organizationId: activeSession.organizationId,
209
- stampWith: 'indexedDb',
198
+ stampWith: 'apiKey',
210
199
  })
211
- await client.indexedDbStamper.resetKeyPair(newKeyPair)
200
+ await client.apiKeyStamper.commitKeyRotation()
212
201
  const parsedSession = parseSession(data.session)
213
202
  const session: ZeroDevWalletSession = {
214
203
  id: `session_indexedDb_${Date.now()}`,
215
204
  userId: parsedSession.userId,
216
205
  organizationId: parsedSession.organizationId,
217
- stamperType: 'indexedDb',
206
+ stamperType: 'apiKey',
218
207
  sessionType: SessionType.READ_WRITE,
219
208
  token: data.session,
220
209
  expiry: parsedSession.expiry,
@@ -240,17 +229,15 @@ export async function createZeroDevWallet(
240
229
  if (data.session) {
241
230
  // Parse the JWT to get session data
242
231
  const parsedSession = parseSession(data.session)
243
- const publicKey = await client.indexedDbStamper.getPublicKey()
244
232
  const session: ZeroDevWalletSession = {
245
233
  id: `session_oauth_${Date.now()}`,
246
234
  userId: parsedSession.userId,
247
235
  organizationId: parsedSession.organizationId,
248
- stamperType: 'indexedDb',
236
+ stamperType: 'apiKey',
249
237
  sessionType: parsedSession.sessionType || SessionType.READ_WRITE,
250
238
  token: data.session,
251
239
  expiry: parsedSession.expiry,
252
240
  createdAt: Date.now(),
253
- publicKey: publicKey || '',
254
241
  }
255
242
  await sessionStorageManager.storeSession(session, session.id)
256
243
  }
@@ -263,62 +250,35 @@ export async function createZeroDevWallet(
263
250
  'mode' in params &&
264
251
  params.mode === 'register'
265
252
  ) {
266
- await client.indexedDbStamper.resetKeyPair()
267
- const tempPublicKey = await client.indexedDbStamper.getPublicKey()
253
+ await client.apiKeyStamper.resetKeyPair()
254
+ const tempPublicKey = await client.apiKeyStamper.getPublicKey()
268
255
  if (!tempPublicKey) {
269
256
  throw new Error('Failed to get public key')
270
257
  }
271
- const challenge = generateRandomBuffer()
272
- const encodedChallenge = base64UrlEncode(challenge)
273
- const authenticatorUserId = generateRandomBuffer()
274
258
  const name = `ZeroDevWallet-${humanReadableDateTime()}`
275
- const attestation = await getWebAuthnAttestation({
276
- publicKey: {
259
+ const { attestation, encodedChallenge } =
260
+ await passkeyStamper.register({
277
261
  rp: { id: rpId, name: '' },
278
- challenge,
279
- pubKeyCredParams: [
280
- {
281
- type: 'public-key',
282
- alg: -7,
283
- },
284
- {
285
- type: 'public-key',
286
- alg: -257,
287
- },
288
- ],
289
- user: {
290
- id: authenticatorUserId,
291
- name,
292
- displayName: name,
293
- },
294
- },
295
- })
262
+ userName: name,
263
+ })
296
264
  const data = await client.registerWithPasskey({
297
265
  attestation,
298
266
  challenge: encodedChallenge,
299
267
  projectId,
300
268
  encodedPublicKey: tempPublicKey,
301
269
  })
302
- const newKeyPair = await crypto.subtle.generateKey(
303
- {
304
- name: 'ECDSA',
305
- namedCurve: 'P-256',
306
- },
307
- false,
308
- ['sign', 'verify'],
309
- )
310
270
  const compressedPublicKeyHex =
311
- await generateCompressedPublicKeyFromKeyPair(newKeyPair)
271
+ await client.apiKeyStamper.prepareKeyRotation()
312
272
  const loginData = await client.loginWithStamp({
313
273
  projectId,
314
274
  targetPublicKey: compressedPublicKeyHex,
315
275
  organizationId: data.subOrganizationId,
316
276
  })
317
- await client.indexedDbStamper.resetKeyPair(newKeyPair)
277
+ await client.apiKeyStamper.commitKeyRotation()
318
278
  const parsedSession = parseSession(loginData.session)
319
279
  const session: ZeroDevWalletSession = {
320
280
  id: `session_indexedDb_${Date.now()}`,
321
- stamperType: 'indexedDb',
281
+ stamperType: 'apiKey',
322
282
  createdAt: Date.now(),
323
283
  sessionType: SessionType.READ_WRITE,
324
284
  userId: parsedSession.userId,
@@ -336,9 +296,8 @@ export async function createZeroDevWallet(
336
296
  'mode' in params &&
337
297
  params.mode === 'login'
338
298
  ) {
339
- await client.indexedDbStamper.resetKeyPair()
340
- const generatedPublicKey =
341
- await client.indexedDbStamper.getPublicKey()
299
+ await client.apiKeyStamper.resetKeyPair()
300
+ const generatedPublicKey = await client.apiKeyStamper.getPublicKey()
342
301
  if (!generatedPublicKey) {
343
302
  throw new Error('Failed to get public key')
344
303
  }
@@ -346,12 +305,12 @@ export async function createZeroDevWallet(
346
305
  targetPublicKey: generatedPublicKey,
347
306
  projectId,
348
307
  organizationId,
349
- stampWith: 'webauthn',
308
+ stampWith: 'passkey',
350
309
  })
351
310
  const parsedSession = parseSession(loginData.session)
352
311
  const session: ZeroDevWalletSession = {
353
312
  id: `session_indexedDb_${Date.now()}`,
354
- stamperType: 'indexedDb',
313
+ stamperType: 'apiKey',
355
314
  createdAt: Date.now(),
356
315
  sessionType: SessionType.READ_WRITE,
357
316
  userId: parsedSession.userId,
@@ -416,8 +375,8 @@ export async function createZeroDevWallet(
416
375
  const { otpId, otpCode, otpEncryptionTargetBundle } = otpParams
417
376
 
418
377
  // Step 1: Generate new key pair
419
- await client.indexedDbStamper.resetKeyPair()
420
- const targetPublicKey = await client.indexedDbStamper.getPublicKey()
378
+ await client.apiKeyStamper.resetKeyPair()
379
+ const targetPublicKey = await client.apiKeyStamper.getPublicKey()
421
380
 
422
381
  if (!targetPublicKey) {
423
382
  throw new Error('Failed to get public key')
@@ -449,7 +408,7 @@ export async function createZeroDevWallet(
449
408
  const clientSignature = await buildClientSignature({
450
409
  verificationToken,
451
410
  publicKey: targetPublicKey,
452
- stamper: client.indexedDbStamper,
411
+ stamper: client.apiKeyStamper,
453
412
  })
454
413
 
455
414
  // Step 4: Login via backend (not Auth Proxy!)
@@ -466,13 +425,12 @@ export async function createZeroDevWallet(
466
425
  id: `session_otp_${Date.now()}`,
467
426
  userId: parsedSession.userId,
468
427
  organizationId: parsedSession.organizationId,
469
- stamperType: 'indexedDb',
428
+ stamperType: 'apiKey',
470
429
  sessionType:
471
430
  parsedSession.sessionType || SessionType.READ_WRITE,
472
431
  token: data.session,
473
432
  expiry: parsedSession.expiry,
474
433
  createdAt: Date.now(),
475
- publicKey: targetPublicKey,
476
434
  }
477
435
  await sessionStorageManager.storeSession(session, session.id)
478
436
  }
@@ -488,7 +446,7 @@ export async function createZeroDevWallet(
488
446
 
489
447
  async logout() {
490
448
  await sessionStorageManager.clearAllSessions()
491
- await client.indexedDbStamper.resetKeyPair()
449
+ await client.apiKeyStamper.resetKeyPair()
492
450
  return true
493
451
  },
494
452
 
package/src/index.ts CHANGED
@@ -80,9 +80,12 @@ export {
80
80
  createWebauthnStamper,
81
81
  } from './stampers/index.js'
82
82
  export type {
83
+ ApiKeyStamper,
84
+ Attestation,
83
85
  IframeStamper,
84
- IndexedDbStamper,
85
- WebauthnStamper,
86
+ PasskeyRegistrationOptions,
87
+ PasskeyRegistrationResult,
88
+ PasskeyStamper,
86
89
  } from './stampers/types.js'
87
90
  // Storage
88
91
  export type { StorageAdapter, StorageManager } from './storage/manager.js'
@@ -1,8 +1,8 @@
1
1
  export { createIframeStamper } from './iframeStamper.js'
2
2
  export { createIndexedDbStamper } from './indexedDbStamper.js'
3
3
  export type {
4
+ ApiKeyStamper,
4
5
  IframeStamper,
5
- IndexedDbStamper,
6
- WebauthnStamper,
6
+ PasskeyStamper,
7
7
  } from './types.js'
8
8
  export { createWebauthnStamper } from './webauthnStamper.js'