@zerodev/wallet-react 0.0.1-alpha.12 → 0.0.1-alpha.13

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zerodev/wallet-react",
3
- "version": "0.0.1-alpha.12",
3
+ "version": "0.0.1-alpha.13",
4
4
  "description": "React hooks for ZeroDev Wallet SDK",
5
5
  "sideEffects": false,
6
6
  "main": "./dist/_cjs/index.js",
@@ -30,7 +30,7 @@
30
30
  "wagmi": "^3.0.0",
31
31
  "zustand": "^5.0.3",
32
32
  "ox": "^0.3.0",
33
- "@zerodev/wallet-core": "0.0.1-alpha.11"
33
+ "@zerodev/wallet-core": "0.0.1-alpha.12"
34
34
  },
35
35
  "devDependencies": {
36
36
  "@types/react": "^19",
@@ -108,11 +108,10 @@ describe('React Actions', () => {
108
108
  const connector = createMockConnector(store)
109
109
  const config = createMockConfig(connector)
110
110
 
111
- await registerPasskey(config, { email: 'user@example.com' })
111
+ await registerPasskey(config, {})
112
112
 
113
113
  expect(wallet.auth).toHaveBeenCalledWith({
114
114
  type: 'passkey',
115
- email: 'user@example.com',
116
115
  mode: 'register',
117
116
  })
118
117
  })
@@ -125,7 +124,7 @@ describe('React Actions', () => {
125
124
  const connector = createMockConnector(store)
126
125
  const config = createMockConfig(connector)
127
126
 
128
- await registerPasskey(config, { email: 'user@example.com' })
127
+ await registerPasskey(config, {})
129
128
 
130
129
  expect(store.getState().setEoaAccount).toHaveBeenCalledWith({
131
130
  address: '0xdeadbeef',
@@ -143,7 +142,7 @@ describe('React Actions', () => {
143
142
  const connector = createMockConnector(store)
144
143
  const config = createMockConfig(connector)
145
144
 
146
- await registerPasskey(config, { email: 'user@example.com' })
145
+ await registerPasskey(config, {})
147
146
 
148
147
  expect(store.getState().setSession).toHaveBeenCalledWith(null)
149
148
  })
@@ -154,7 +153,7 @@ describe('React Actions', () => {
154
153
  const connector = createMockConnector(store)
155
154
  const config = createMockConfig(connector)
156
155
 
157
- await registerPasskey(config, { email: 'user@example.com' })
156
+ await registerPasskey(config, {})
158
157
 
159
158
  expect(wagmiConnect).toHaveBeenCalledWith(config, { connector })
160
159
  })
@@ -164,9 +163,9 @@ describe('React Actions', () => {
164
163
  const connector = createMockConnector(store)
165
164
  const config = createMockConfig(connector)
166
165
 
167
- await expect(
168
- registerPasskey(config, { email: 'user@example.com' }),
169
- ).rejects.toThrow('Wallet not initialized')
166
+ await expect(registerPasskey(config, {})).rejects.toThrow(
167
+ 'Wallet not initialized',
168
+ )
170
169
  })
171
170
 
172
171
  it('uses provided connector instead of finding one', async () => {
@@ -176,7 +175,6 @@ describe('React Actions', () => {
176
175
  const config = createMockConfig()
177
176
 
178
177
  await registerPasskey(config, {
179
- email: 'user@example.com',
180
178
  connector: customConnector,
181
179
  })
182
180
 
@@ -191,11 +189,10 @@ describe('React Actions', () => {
191
189
  const connector = createMockConnector(store)
192
190
  const config = createMockConfig(connector)
193
191
 
194
- await loginPasskey(config, { email: 'user@example.com' })
192
+ await loginPasskey(config, {})
195
193
 
196
194
  expect(wallet.auth).toHaveBeenCalledWith({
197
195
  type: 'passkey',
198
- email: 'user@example.com',
199
196
  mode: 'login',
200
197
  })
201
198
  })
@@ -208,7 +205,7 @@ describe('React Actions', () => {
208
205
  const connector = createMockConnector(store)
209
206
  const config = createMockConfig(connector)
210
207
 
211
- await loginPasskey(config, { email: 'user@example.com' })
208
+ await loginPasskey(config, {})
212
209
 
213
210
  expect(store.getState().setEoaAccount).toHaveBeenCalledWith({
214
211
  address: '0xabc',
@@ -224,7 +221,7 @@ describe('React Actions', () => {
224
221
  const connector = createMockConnector(store)
225
222
  const config = createMockConfig(connector)
226
223
 
227
- await loginPasskey(config, { email: 'user@example.com' })
224
+ await loginPasskey(config, {})
228
225
 
229
226
  expect(wagmiConnect).toHaveBeenCalledWith(config, { connector })
230
227
  })
@@ -234,9 +231,9 @@ describe('React Actions', () => {
234
231
  const connector = createMockConnector(store)
235
232
  const config = createMockConfig(connector)
236
233
 
237
- await expect(
238
- loginPasskey(config, { email: 'user@example.com' }),
239
- ).rejects.toThrow('Wallet not initialized')
234
+ await expect(loginPasskey(config, {})).rejects.toThrow(
235
+ 'Wallet not initialized',
236
+ )
240
237
  })
241
238
  })
242
239
 
@@ -887,9 +884,9 @@ describe('React Actions', () => {
887
884
  storage: null,
888
885
  } as unknown as Config
889
886
 
890
- await expect(
891
- registerPasskey(config, { email: 'user@example.com' }),
892
- ).rejects.toThrow('ZeroDev connector not found in Wagmi config')
887
+ await expect(registerPasskey(config, {})).rejects.toThrow(
888
+ 'ZeroDev connector not found in Wagmi config',
889
+ )
893
890
  })
894
891
  })
895
892
  })
package/src/actions.ts CHANGED
@@ -28,12 +28,11 @@ function getZeroDevConnector(config: Config): Connector {
28
28
  */
29
29
  export async function registerPasskey(
30
30
  config: Config,
31
- parameters: {
32
- email: string
31
+ parameters?: {
33
32
  connector?: Connector
34
33
  },
35
34
  ): Promise<void> {
36
- const connector = parameters.connector ?? getZeroDevConnector(config)
35
+ const connector = parameters?.connector ?? getZeroDevConnector(config)
37
36
 
38
37
  // @ts-expect-error - getStore is a custom method
39
38
  const store = await connector.getStore()
@@ -43,7 +42,6 @@ export async function registerPasskey(
43
42
 
44
43
  await wallet.auth({
45
44
  type: 'passkey',
46
- email: parameters.email,
47
45
  mode: 'register',
48
46
  })
49
47
 
@@ -60,8 +58,7 @@ export async function registerPasskey(
60
58
  }
61
59
 
62
60
  export declare namespace registerPasskey {
63
- type Parameters = {
64
- email: string
61
+ type Parameters = void | {
65
62
  connector?: Connector
66
63
  }
67
64
  type ReturnType = void
@@ -73,12 +70,11 @@ export declare namespace registerPasskey {
73
70
  */
74
71
  export async function loginPasskey(
75
72
  config: Config,
76
- parameters: {
77
- email: string
73
+ parameters?: {
78
74
  connector?: Connector
79
75
  },
80
76
  ): Promise<void> {
81
- const connector = parameters.connector ?? getZeroDevConnector(config)
77
+ const connector = parameters?.connector ?? getZeroDevConnector(config)
82
78
 
83
79
  // @ts-expect-error - getStore is a custom method
84
80
  const store = await connector.getStore()
@@ -88,7 +84,6 @@ export async function loginPasskey(
88
84
 
89
85
  await wallet.auth({
90
86
  type: 'passkey',
91
- email: parameters.email,
92
87
  mode: 'login',
93
88
  })
94
89
 
@@ -105,8 +100,7 @@ export async function loginPasskey(
105
100
  }
106
101
 
107
102
  export declare namespace loginPasskey {
108
- type Parameters = {
109
- email: string
103
+ type Parameters = void | {
110
104
  connector?: Connector
111
105
  }
112
106
  type ReturnType = void
@@ -376,6 +370,7 @@ export async function exportWallet(
376
370
  config: Config,
377
371
  parameters: {
378
372
  iframeContainerId: string
373
+ iframeStyles?: Record<string, string>
379
374
  connector?: Connector
380
375
  },
381
376
  ): Promise<void> {
@@ -399,6 +394,11 @@ export async function exportWallet(
399
394
  })
400
395
 
401
396
  const publicKey = await iframeStamper.init()
397
+
398
+ if (parameters.iframeStyles) {
399
+ await iframeStamper.applySettings({ styles: parameters.iframeStyles })
400
+ }
401
+
402
402
  const { exportBundle, organizationId } = await exportWalletSdk({
403
403
  wallet,
404
404
  targetPublicKey: publicKey,
@@ -416,6 +416,7 @@ export async function exportWallet(
416
416
  export declare namespace exportWallet {
417
417
  type Parameters = {
418
418
  iframeContainerId: string
419
+ iframeStyles?: Record<string, string>
419
420
  connector?: Connector
420
421
  }
421
422
  type ReturnType = void
@@ -429,6 +430,7 @@ export async function exportPrivateKey(
429
430
  config: Config,
430
431
  parameters: {
431
432
  iframeContainerId: string
433
+ iframeStyles?: Record<string, string>
432
434
  address?: string
433
435
  keyFormat?: 'Hexadecimal' | 'Solana'
434
436
  connector?: Connector
@@ -454,6 +456,11 @@ export async function exportPrivateKey(
454
456
  })
455
457
 
456
458
  const publicKey = await iframeStamper.init()
459
+
460
+ if (parameters.iframeStyles) {
461
+ await iframeStamper.applySettings({ styles: parameters.iframeStyles })
462
+ }
463
+
457
464
  const { exportBundle, organizationId } = await exportPrivateKeySdk({
458
465
  wallet,
459
466
  targetPublicKey: publicKey,
@@ -473,6 +480,7 @@ export async function exportPrivateKey(
473
480
  export declare namespace exportPrivateKey {
474
481
  type Parameters = {
475
482
  iframeContainerId: string
483
+ iframeStyles?: Record<string, string>
476
484
  address?: string
477
485
  keyFormat?: 'Hexadecimal' | 'Solana'
478
486
  connector?: Connector
@@ -480,3 +488,92 @@ export declare namespace exportPrivateKey {
480
488
  type ReturnType = void
481
489
  type ErrorType = Error
482
490
  }
491
+
492
+ /**
493
+ * Send magic link via email
494
+ */
495
+ export async function sendMagicLink(
496
+ config: Config,
497
+ parameters: {
498
+ email: string
499
+ redirectURL: string
500
+ connector?: Connector
501
+ },
502
+ ): Promise<{ otpId: string }> {
503
+ const connector = parameters.connector ?? getZeroDevConnector(config)
504
+
505
+ // @ts-expect-error - getStore is a custom method
506
+ const store = await connector.getStore()
507
+ const wallet = store.getState().wallet
508
+
509
+ if (!wallet) throw new Error('Wallet not initialized')
510
+
511
+ const result = await wallet.auth({
512
+ type: 'magicLink',
513
+ mode: 'send',
514
+ email: parameters.email,
515
+ redirectURL: parameters.redirectURL,
516
+ })
517
+
518
+ return {
519
+ otpId: result.otpId,
520
+ }
521
+ }
522
+
523
+ export declare namespace sendMagicLink {
524
+ type Parameters = {
525
+ email: string
526
+ redirectURL: string
527
+ connector?: Connector
528
+ }
529
+ type ReturnType = { otpId: string }
530
+ type ErrorType = Error
531
+ }
532
+
533
+ /**
534
+ * Verify magic link code
535
+ */
536
+ export async function verifyMagicLink(
537
+ config: Config,
538
+ parameters: {
539
+ otpId: string
540
+ code: string
541
+ connector?: Connector
542
+ },
543
+ ): Promise<void> {
544
+ const connector = parameters.connector ?? getZeroDevConnector(config)
545
+
546
+ // @ts-expect-error - getStore is a custom method
547
+ const store = await connector.getStore()
548
+ const wallet = store.getState().wallet
549
+
550
+ if (!wallet) throw new Error('Wallet not initialized')
551
+
552
+ await wallet.auth({
553
+ type: 'magicLink',
554
+ mode: 'verify',
555
+ otpId: parameters.otpId,
556
+ code: parameters.code,
557
+ })
558
+
559
+ const [session, eoaAccount] = await Promise.all([
560
+ wallet.getSession(),
561
+ wallet.toAccount(),
562
+ ])
563
+
564
+ store.getState().setEoaAccount(eoaAccount)
565
+ store.getState().setSession(session || null)
566
+
567
+ // Auto-connect to Wagmi
568
+ await wagmiConnect(config, { connector })
569
+ }
570
+
571
+ export declare namespace verifyMagicLink {
572
+ type Parameters = {
573
+ otpId: string
574
+ code: string
575
+ connector?: Connector
576
+ }
577
+ type ReturnType = void
578
+ type ErrorType = Error
579
+ }
@@ -26,8 +26,8 @@ export function useLoginPasskey<
26
26
 
27
27
  return useMutation({
28
28
  ...mutation,
29
- async mutationFn(variables: loginPasskey.Parameters) {
30
- return loginPasskey(config, variables)
29
+ async mutationFn(variables?: loginPasskey.Parameters) {
30
+ return loginPasskey(config, variables ?? undefined)
31
31
  },
32
32
  mutationKey: ['loginPasskey'],
33
33
  })
@@ -26,8 +26,8 @@ export function useRegisterPasskey<
26
26
 
27
27
  return useMutation({
28
28
  ...mutation,
29
- async mutationFn(variables: registerPasskey.Parameters) {
30
- return registerPasskey(config, variables)
29
+ async mutationFn(variables?: registerPasskey.Parameters) {
30
+ return registerPasskey(config, variables ?? undefined)
31
31
  },
32
32
  mutationKey: ['registerPasskey'],
33
33
  })
@@ -0,0 +1,57 @@
1
+ 'use client'
2
+
3
+ import {
4
+ type UseMutationOptions,
5
+ type UseMutationResult,
6
+ useMutation,
7
+ } from '@tanstack/react-query'
8
+ import { type Config, type ResolvedRegister, useConfig } from 'wagmi'
9
+ import { sendMagicLink } from '../actions.js'
10
+
11
+ type ConfigParameter<config extends Config = Config> = {
12
+ config?: Config | config | undefined
13
+ }
14
+
15
+ /**
16
+ * Hook to send a magic link via email
17
+ */
18
+ export function useSendMagicLink<
19
+ config extends Config = ResolvedRegister['config'],
20
+ context = unknown,
21
+ >(
22
+ parameters: useSendMagicLink.Parameters<config, context> = {},
23
+ ): useSendMagicLink.ReturnType<context> {
24
+ const { mutation } = parameters
25
+ const config = useConfig(parameters)
26
+
27
+ return useMutation({
28
+ ...mutation,
29
+ async mutationFn(variables: sendMagicLink.Parameters) {
30
+ return sendMagicLink(config, variables)
31
+ },
32
+ mutationKey: ['sendMagicLink'],
33
+ })
34
+ }
35
+
36
+ export declare namespace useSendMagicLink {
37
+ type Parameters<
38
+ config extends Config = Config,
39
+ context = unknown,
40
+ > = ConfigParameter<config> & {
41
+ mutation?:
42
+ | UseMutationOptions<
43
+ sendMagicLink.ReturnType,
44
+ sendMagicLink.ErrorType,
45
+ sendMagicLink.Parameters,
46
+ context
47
+ >
48
+ | undefined
49
+ }
50
+
51
+ type ReturnType<context = unknown> = UseMutationResult<
52
+ sendMagicLink.ReturnType,
53
+ sendMagicLink.ErrorType,
54
+ sendMagicLink.Parameters,
55
+ context
56
+ >
57
+ }
@@ -0,0 +1,57 @@
1
+ 'use client'
2
+
3
+ import {
4
+ type UseMutationOptions,
5
+ type UseMutationResult,
6
+ useMutation,
7
+ } from '@tanstack/react-query'
8
+ import { type Config, type ResolvedRegister, useConfig } from 'wagmi'
9
+ import { verifyMagicLink } from '../actions.js'
10
+
11
+ type ConfigParameter<config extends Config = Config> = {
12
+ config?: Config | config | undefined
13
+ }
14
+
15
+ /**
16
+ * Hook to verify a magic link code
17
+ */
18
+ export function useVerifyMagicLink<
19
+ config extends Config = ResolvedRegister['config'],
20
+ context = unknown,
21
+ >(
22
+ parameters: useVerifyMagicLink.Parameters<config, context> = {},
23
+ ): useVerifyMagicLink.ReturnType<context> {
24
+ const { mutation } = parameters
25
+ const config = useConfig(parameters)
26
+
27
+ return useMutation({
28
+ ...mutation,
29
+ async mutationFn(variables: verifyMagicLink.Parameters) {
30
+ return verifyMagicLink(config, variables)
31
+ },
32
+ mutationKey: ['verifyMagicLink'],
33
+ })
34
+ }
35
+
36
+ export declare namespace useVerifyMagicLink {
37
+ type Parameters<
38
+ config extends Config = Config,
39
+ context = unknown,
40
+ > = ConfigParameter<config> & {
41
+ mutation?:
42
+ | UseMutationOptions<
43
+ verifyMagicLink.ReturnType,
44
+ verifyMagicLink.ErrorType,
45
+ verifyMagicLink.Parameters,
46
+ context
47
+ >
48
+ | undefined
49
+ }
50
+
51
+ type ReturnType<context = unknown> = UseMutationResult<
52
+ verifyMagicLink.ReturnType,
53
+ verifyMagicLink.ErrorType,
54
+ verifyMagicLink.Parameters,
55
+ context
56
+ >
57
+ }
package/src/index.ts CHANGED
@@ -7,7 +7,9 @@ export { useGetUserEmail } from './hooks/useGetUserEmail.js'
7
7
  export { useLoginPasskey } from './hooks/useLoginPasskey.js'
8
8
  export { useRefreshSession } from './hooks/useRefreshSession.js'
9
9
  export { useRegisterPasskey } from './hooks/useRegisterPasskey.js'
10
+ export { useSendMagicLink } from './hooks/useSendMagicLink.js'
10
11
  export { useSendOTP } from './hooks/useSendOTP.js'
12
+ export { useVerifyMagicLink } from './hooks/useVerifyMagicLink.js'
11
13
  export { useVerifyOTP } from './hooks/useVerifyOTP.js'
12
14
  export type { OAuthMessageData, OAuthProvider } from './oauth.js'
13
15
  export {
package/src/provider.ts CHANGED
@@ -151,7 +151,8 @@ export function createProvider({
151
151
  throw new Error(`No kernel client for chain ${chainId}`)
152
152
  }
153
153
 
154
- // Send gasless transaction (always UserOp for EIP-7702)
154
+ // Transactions are sent as UserOperations under the hood (EIP-7702).
155
+ // Gasless if a paymaster is configured on the ZeroDev dashboard.
155
156
  const hash = await kernelClient.sendTransaction({
156
157
  calls: [
157
158
  {