@zerodev/wallet-react 0.0.1-alpha.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 (88) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/dist/_cjs/actions.js +193 -0
  3. package/dist/_cjs/connector.js +221 -0
  4. package/dist/_cjs/constants.js +4 -0
  5. package/dist/_cjs/hooks/useAuthenticateOAuth.js +18 -0
  6. package/dist/_cjs/hooks/useExportWallet.js +18 -0
  7. package/dist/_cjs/hooks/useLoginPasskey.js +18 -0
  8. package/dist/_cjs/hooks/useRefreshSession.js +18 -0
  9. package/dist/_cjs/hooks/useRegisterPasskey.js +18 -0
  10. package/dist/_cjs/hooks/useSendOTP.js +18 -0
  11. package/dist/_cjs/hooks/useVerifyOTP.js +18 -0
  12. package/dist/_cjs/index.js +23 -0
  13. package/dist/_cjs/oauth.js +84 -0
  14. package/dist/_cjs/package.json +1 -0
  15. package/dist/_cjs/provider.js +163 -0
  16. package/dist/_cjs/store.js +51 -0
  17. package/dist/_cjs/utils/aaUtils.js +7 -0
  18. package/dist/_cjs/utils/timers.js +50 -0
  19. package/dist/_esm/actions.js +225 -0
  20. package/dist/_esm/connector.js +248 -0
  21. package/dist/_esm/constants.js +1 -0
  22. package/dist/_esm/hooks/useAuthenticateOAuth.js +18 -0
  23. package/dist/_esm/hooks/useExportWallet.js +18 -0
  24. package/dist/_esm/hooks/useLoginPasskey.js +18 -0
  25. package/dist/_esm/hooks/useRefreshSession.js +18 -0
  26. package/dist/_esm/hooks/useRegisterPasskey.js +18 -0
  27. package/dist/_esm/hooks/useSendOTP.js +18 -0
  28. package/dist/_esm/hooks/useVerifyOTP.js +18 -0
  29. package/dist/_esm/index.js +10 -0
  30. package/dist/_esm/oauth.js +77 -0
  31. package/dist/_esm/package.json +1 -0
  32. package/dist/_esm/provider.js +169 -0
  33. package/dist/_esm/store.js +51 -0
  34. package/dist/_esm/utils/aaUtils.js +4 -0
  35. package/dist/_esm/utils/timers.js +55 -0
  36. package/dist/_types/actions.d.ts +124 -0
  37. package/dist/_types/actions.d.ts.map +1 -0
  38. package/dist/_types/connector.d.ts +18 -0
  39. package/dist/_types/connector.d.ts.map +1 -0
  40. package/dist/_types/constants.d.ts +2 -0
  41. package/dist/_types/constants.d.ts.map +1 -0
  42. package/dist/_types/hooks/useAuthenticateOAuth.d.ts +18 -0
  43. package/dist/_types/hooks/useAuthenticateOAuth.d.ts.map +1 -0
  44. package/dist/_types/hooks/useExportWallet.d.ts +18 -0
  45. package/dist/_types/hooks/useExportWallet.d.ts.map +1 -0
  46. package/dist/_types/hooks/useLoginPasskey.d.ts +18 -0
  47. package/dist/_types/hooks/useLoginPasskey.d.ts.map +1 -0
  48. package/dist/_types/hooks/useRefreshSession.d.ts +18 -0
  49. package/dist/_types/hooks/useRefreshSession.d.ts.map +1 -0
  50. package/dist/_types/hooks/useRegisterPasskey.d.ts +18 -0
  51. package/dist/_types/hooks/useRegisterPasskey.d.ts.map +1 -0
  52. package/dist/_types/hooks/useSendOTP.d.ts +18 -0
  53. package/dist/_types/hooks/useSendOTP.d.ts.map +1 -0
  54. package/dist/_types/hooks/useVerifyOTP.d.ts +18 -0
  55. package/dist/_types/hooks/useVerifyOTP.d.ts.map +1 -0
  56. package/dist/_types/index.d.ts +15 -0
  57. package/dist/_types/index.d.ts.map +1 -0
  58. package/dist/_types/oauth.d.ts +21 -0
  59. package/dist/_types/oauth.d.ts.map +1 -0
  60. package/dist/_types/provider.d.ts +19 -0
  61. package/dist/_types/provider.d.ts.map +1 -0
  62. package/dist/_types/store.d.ts +52 -0
  63. package/dist/_types/store.d.ts.map +1 -0
  64. package/dist/_types/utils/aaUtils.d.ts +2 -0
  65. package/dist/_types/utils/aaUtils.d.ts.map +1 -0
  66. package/dist/_types/utils/timers.d.ts +22 -0
  67. package/dist/_types/utils/timers.d.ts.map +1 -0
  68. package/dist/tsconfig.build.tsbuildinfo +1 -0
  69. package/package.json +48 -0
  70. package/package.json.type +1 -0
  71. package/src/actions.ts +402 -0
  72. package/src/connector.ts +336 -0
  73. package/src/constants.ts +1 -0
  74. package/src/hooks/useAuthenticateOAuth.ts +57 -0
  75. package/src/hooks/useExportWallet.ts +57 -0
  76. package/src/hooks/useLoginPasskey.ts +57 -0
  77. package/src/hooks/useRefreshSession.ts +57 -0
  78. package/src/hooks/useRegisterPasskey.ts +57 -0
  79. package/src/hooks/useSendOTP.ts +57 -0
  80. package/src/hooks/useVerifyOTP.ts +57 -0
  81. package/src/index.ts +14 -0
  82. package/src/oauth.ts +124 -0
  83. package/src/provider.ts +235 -0
  84. package/src/store.ts +113 -0
  85. package/src/utils/aaUtils.ts +5 -0
  86. package/src/utils/timers.ts +80 -0
  87. package/tsconfig.build.json +10 -0
  88. package/tsconfig.build.tsbuildinfo +1 -0
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "@zerodev/wallet-react",
3
+ "version": "0.0.1-alpha.0",
4
+ "description": "React hooks for ZeroDev Wallet SDK",
5
+ "sideEffects": false,
6
+ "main": "./dist/_cjs/index.js",
7
+ "module": "./dist/_esm/index.js",
8
+ "types": "./dist/_types/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/_types/index.d.ts",
12
+ "import": "./dist/_esm/index.js",
13
+ "require": "./dist/_cjs/index.js"
14
+ }
15
+ },
16
+ "keywords": [
17
+ "react",
18
+ "hooks",
19
+ "wallet",
20
+ "zerodev",
21
+ "web3"
22
+ ],
23
+ "license": "MIT",
24
+ "peerDependencies": {
25
+ "@tanstack/react-query": "^5.0.0",
26
+ "@zerodev/sdk": "5.5.4",
27
+ "@wagmi/core": "^2.22.0",
28
+ "react": "^18.0.0 || ^19.0.0",
29
+ "viem": "^2.38.0",
30
+ "wagmi": "^3.0.0",
31
+ "zustand": "^5.0.3",
32
+ "ox": "^0.3.0",
33
+ "@zerodev/wallet-core": "0.0.1-alpha.4"
34
+ },
35
+ "devDependencies": {
36
+ "@types/react": "^19",
37
+ "typescript": "5.9.3"
38
+ },
39
+ "scripts": {
40
+ "build": "pnpm run clean && pnpm run build:cjs && pnpm run build:esm && pnpm run build:types",
41
+ "build:cjs": "tsc --project ./tsconfig.build.json --module commonjs --moduleResolution node --outDir ./dist/_cjs --removeComments --verbatimModuleSyntax false && printf '{\"type\":\"commonjs\"}' > ./dist/_cjs/package.json",
42
+ "build:esm": "tsc --project ./tsconfig.build.json --outDir ./dist/_esm && printf '{\"type\": \"module\",\"sideEffects\":false}' > ./dist/_esm/package.json",
43
+ "build:types": "tsc --project ./tsconfig.build.json --outDir ./dist/_types --emitDeclarationOnly --declaration --declarationMap",
44
+ "dev": "tsc --watch",
45
+ "typecheck": "tsc --noEmit --project ./tsconfig.build.json",
46
+ "clean": "rm -rf dist"
47
+ }
48
+ }
@@ -0,0 +1 @@
1
+ module
package/src/actions.ts ADDED
@@ -0,0 +1,402 @@
1
+ import type { Config, Connector } from '@wagmi/core'
2
+ import { connect as wagmiConnect } from '@wagmi/core/actions'
3
+ import type { OAuthProvider } from './oauth.js'
4
+ import {
5
+ buildOAuthUrl,
6
+ generateOAuthNonce,
7
+ openOAuthPopup,
8
+ pollOAuthPopup,
9
+ } from './oauth.js'
10
+
11
+ /**
12
+ * Get ZeroDev connector from config
13
+ */
14
+ function getZeroDevConnector(config: Config): Connector {
15
+ const connector = config.connectors.find((c) => c.id === 'zerodev-wallet')
16
+ if (!connector) {
17
+ throw new Error('ZeroDev connector not found in Wagmi config')
18
+ }
19
+ return connector
20
+ }
21
+
22
+ /**
23
+ * Register with passkey
24
+ */
25
+ export async function registerPasskey(
26
+ config: Config,
27
+ parameters: {
28
+ email: string
29
+ connector?: Connector
30
+ },
31
+ ): Promise<void> {
32
+ const connector = parameters.connector ?? getZeroDevConnector(config)
33
+
34
+ // @ts-expect-error - getStore is a custom method
35
+ const store = await connector.getStore()
36
+ const wallet = store.getState().wallet
37
+
38
+ if (!wallet) throw new Error('Wallet not initialized')
39
+
40
+ await wallet.auth({
41
+ type: 'passkey',
42
+ email: parameters.email,
43
+ mode: 'register',
44
+ })
45
+
46
+ const [session, eoaAccount] = await Promise.all([
47
+ wallet.getSession(),
48
+ wallet.toAccount(),
49
+ ])
50
+
51
+ store.getState().setEoaAccount(eoaAccount)
52
+ store.getState().setSession(session || null)
53
+
54
+ // Auto-connect to Wagmi
55
+ await wagmiConnect(config, { connector })
56
+ }
57
+
58
+ export declare namespace registerPasskey {
59
+ type Parameters = {
60
+ email: string
61
+ connector?: Connector
62
+ }
63
+ type ReturnType = void
64
+ type ErrorType = Error
65
+ }
66
+
67
+ /**
68
+ * Login with passkey
69
+ */
70
+ export async function loginPasskey(
71
+ config: Config,
72
+ parameters: {
73
+ email: string
74
+ connector?: Connector
75
+ },
76
+ ): Promise<void> {
77
+ const connector = parameters.connector ?? getZeroDevConnector(config)
78
+
79
+ // @ts-expect-error - getStore is a custom method
80
+ const store = await connector.getStore()
81
+ const wallet = store.getState().wallet
82
+
83
+ if (!wallet) throw new Error('Wallet not initialized')
84
+
85
+ await wallet.auth({
86
+ type: 'passkey',
87
+ email: parameters.email,
88
+ mode: 'login',
89
+ })
90
+
91
+ const [session, eoaAccount] = await Promise.all([
92
+ wallet.getSession(),
93
+ wallet.toAccount(),
94
+ ])
95
+
96
+ store.getState().setEoaAccount(eoaAccount)
97
+ store.getState().setSession(session || null)
98
+
99
+ // Auto-connect to Wagmi
100
+ await wagmiConnect(config, { connector })
101
+ }
102
+
103
+ export declare namespace loginPasskey {
104
+ type Parameters = {
105
+ email: string
106
+ connector?: Connector
107
+ }
108
+ type ReturnType = void
109
+ type ErrorType = Error
110
+ }
111
+
112
+ /**
113
+ * Authenticate with OAuth (opens popup)
114
+ */
115
+ export async function authenticateOAuth(
116
+ config: Config,
117
+ parameters: {
118
+ provider: OAuthProvider
119
+ clientId?: string
120
+ connector?: Connector
121
+ },
122
+ ): Promise<void> {
123
+ const connector = parameters.connector ?? getZeroDevConnector(config)
124
+
125
+ // @ts-expect-error - getStore is a custom method
126
+ const store = await connector.getStore()
127
+ const wallet = store.getState().wallet
128
+ const oauthConfig = store.getState().oauthConfig
129
+
130
+ if (!wallet) throw new Error('Wallet not initialized')
131
+ if (!oauthConfig) {
132
+ throw new Error(
133
+ 'OAuth is not configured. Please provide oauthConfig to zeroDevWallet connector.',
134
+ )
135
+ }
136
+
137
+ // Get client ID for the provider
138
+ let clientId = parameters.clientId
139
+ if (!clientId) {
140
+ clientId = oauthConfig.googleClientId
141
+ }
142
+
143
+ if (!clientId) {
144
+ throw new Error(`Client ID not configured for ${parameters.provider}`)
145
+ }
146
+
147
+ if (!oauthConfig.redirectUri) {
148
+ throw new Error('OAuth redirect URI is not configured.')
149
+ }
150
+
151
+ // Generate nonce from wallet public key
152
+ const publicKey = await wallet.getPublicKey()
153
+ if (!publicKey) {
154
+ throw new Error('Failed to get wallet public key')
155
+ }
156
+ const nonce = generateOAuthNonce(publicKey)
157
+
158
+ // Build OAuth URL
159
+ const oauthUrl = buildOAuthUrl({
160
+ provider: parameters.provider,
161
+ clientId,
162
+ redirectUri: oauthConfig.redirectUri,
163
+ nonce,
164
+ })
165
+
166
+ // Open popup
167
+ const authWindow = openOAuthPopup(oauthUrl)
168
+
169
+ if (!authWindow) {
170
+ throw new Error(`Failed to open ${parameters.provider} login window.`)
171
+ }
172
+
173
+ // Poll for OAuth completion
174
+ return new Promise<void>((resolve, reject) => {
175
+ pollOAuthPopup(
176
+ authWindow,
177
+ window.location.origin,
178
+ async (idToken) => {
179
+ try {
180
+ // Complete OAuth authentication with wallet-core
181
+ await wallet.auth({
182
+ type: 'oauth',
183
+ provider: parameters.provider,
184
+ credential: idToken,
185
+ })
186
+
187
+ const [session, eoaAccount] = await Promise.all([
188
+ wallet.getSession(),
189
+ wallet.toAccount(),
190
+ ])
191
+
192
+ store.getState().setEoaAccount(eoaAccount)
193
+ store.getState().setSession(session || null)
194
+
195
+ // Auto-connect to Wagmi
196
+ await wagmiConnect(config, { connector })
197
+
198
+ resolve()
199
+ } catch (err) {
200
+ reject(err)
201
+ }
202
+ },
203
+ reject,
204
+ )
205
+ })
206
+ }
207
+
208
+ export declare namespace authenticateOAuth {
209
+ type Parameters = {
210
+ provider: OAuthProvider
211
+ clientId?: string
212
+ connector?: Connector
213
+ }
214
+ type ReturnType = void
215
+ type ErrorType = Error
216
+ }
217
+
218
+ /**
219
+ * Send OTP via email
220
+ */
221
+ export async function sendOTP(
222
+ config: Config,
223
+ parameters: {
224
+ email: string
225
+ emailCustomization?: { magicLinkTemplate?: string }
226
+ connector?: Connector
227
+ },
228
+ ): Promise<{ otpId: string; subOrganizationId: string }> {
229
+ const connector = parameters.connector ?? getZeroDevConnector(config)
230
+
231
+ // @ts-expect-error - getStore is a custom method
232
+ const store = await connector.getStore()
233
+ const wallet = store.getState().wallet
234
+
235
+ if (!wallet) throw new Error('Wallet not initialized')
236
+
237
+ const result = await wallet.auth({
238
+ type: 'otp',
239
+ mode: 'sendOtp',
240
+ email: parameters.email,
241
+ contact: { type: 'email', contact: parameters.email },
242
+ ...(parameters.emailCustomization && {
243
+ emailCustomization: parameters.emailCustomization,
244
+ }),
245
+ })
246
+
247
+ return {
248
+ otpId: result.otpId,
249
+ subOrganizationId: result.subOrganizationId,
250
+ }
251
+ }
252
+
253
+ export declare namespace sendOTP {
254
+ type Parameters = {
255
+ email: string
256
+ emailCustomization?: { magicLinkTemplate?: string }
257
+ connector?: Connector
258
+ }
259
+ type ReturnType = { otpId: string; subOrganizationId: string }
260
+ type ErrorType = Error
261
+ }
262
+
263
+ /**
264
+ * Verify OTP code
265
+ */
266
+ export async function verifyOTP(
267
+ config: Config,
268
+ parameters: {
269
+ code: string
270
+ otpId: string
271
+ subOrganizationId: string
272
+ connector?: Connector
273
+ },
274
+ ): Promise<void> {
275
+ const connector = parameters.connector ?? getZeroDevConnector(config)
276
+
277
+ // @ts-expect-error - getStore is a custom method
278
+ const store = await connector.getStore()
279
+ const wallet = store.getState().wallet
280
+
281
+ if (!wallet) throw new Error('Wallet not initialized')
282
+
283
+ await wallet.auth({
284
+ type: 'otp',
285
+ mode: 'verifyOtp',
286
+ otpId: parameters.otpId,
287
+ otpCode: parameters.code,
288
+ subOrganizationId: parameters.subOrganizationId,
289
+ })
290
+
291
+ const [session, eoaAccount] = await Promise.all([
292
+ wallet.getSession(),
293
+ wallet.toAccount(),
294
+ ])
295
+
296
+ store.getState().setEoaAccount(eoaAccount)
297
+ store.getState().setSession(session || null)
298
+
299
+ // Auto-connect to Wagmi
300
+ await wagmiConnect(config, { connector })
301
+ }
302
+
303
+ export declare namespace verifyOTP {
304
+ type Parameters = {
305
+ code: string
306
+ otpId: string
307
+ subOrganizationId: string
308
+ connector?: Connector
309
+ }
310
+ type ReturnType = void
311
+ type ErrorType = Error
312
+ }
313
+
314
+ /**
315
+ * Refresh session
316
+ */
317
+ export async function refreshSession(
318
+ config: Config,
319
+ parameters: {
320
+ connector?: Connector
321
+ } = {},
322
+ ): Promise<unknown> {
323
+ const connector = parameters.connector ?? getZeroDevConnector(config)
324
+
325
+ // @ts-expect-error - getStore is a custom method
326
+ const store = await connector.getStore()
327
+ const wallet = store.getState().wallet
328
+ const currentSession = store.getState().session
329
+
330
+ if (!wallet || !currentSession) {
331
+ throw new Error('No active session to refresh')
332
+ }
333
+
334
+ const newSession = await wallet.refreshSession(currentSession.id)
335
+ store.getState().setSession(newSession || null)
336
+ return newSession
337
+ }
338
+
339
+ export declare namespace refreshSession {
340
+ type Parameters = {
341
+ connector?: Connector
342
+ }
343
+ type ReturnType = unknown
344
+ type ErrorType = Error
345
+ }
346
+
347
+ /**
348
+ * Export wallet
349
+ */
350
+ export async function exportWallet(
351
+ config: Config,
352
+ parameters: {
353
+ iframeContainerId: string
354
+ connector?: Connector
355
+ },
356
+ ): Promise<void> {
357
+ const connector = parameters.connector ?? getZeroDevConnector(config)
358
+
359
+ // @ts-expect-error - getStore is a custom method
360
+ const store = await connector.getStore()
361
+ const wallet = store.getState().wallet
362
+
363
+ if (!wallet) throw new Error('Wallet not initialized')
364
+
365
+ const { exportWallet: exportWalletSdk, createIframeStamper } = await import(
366
+ '@zerodev/wallet-core'
367
+ )
368
+
369
+ const iframeContainer = document.getElementById(parameters.iframeContainerId)
370
+ if (!iframeContainer) {
371
+ throw new Error('Iframe container not found')
372
+ }
373
+
374
+ const iframeStamper = await createIframeStamper({
375
+ iframeUrl: 'https://export.turnkey.com',
376
+ iframeContainer,
377
+ iframeElementId: 'export-wallet-iframe',
378
+ })
379
+
380
+ const publicKey = await iframeStamper.init()
381
+ const { exportBundle, organizationId } = await exportWalletSdk({
382
+ wallet,
383
+ targetPublicKey: publicKey,
384
+ })
385
+
386
+ const success = await iframeStamper.injectWalletExportBundle(
387
+ exportBundle,
388
+ organizationId,
389
+ )
390
+ if (success !== true) {
391
+ throw new Error('Failed to inject export bundle')
392
+ }
393
+ }
394
+
395
+ export declare namespace exportWallet {
396
+ type Parameters = {
397
+ iframeContainerId: string
398
+ connector?: Connector
399
+ }
400
+ type ReturnType = void
401
+ type ErrorType = Error
402
+ }