@zerodev/wallet-react 0.0.1-alpha.6 → 0.0.1-alpha.8

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.6",
3
+ "version": "0.0.1-alpha.8",
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.6"
33
+ "@zerodev/wallet-core": "0.0.1-alpha.7"
34
34
  },
35
35
  "devDependencies": {
36
36
  "@types/react": "^19",
package/src/actions.ts CHANGED
@@ -7,10 +7,9 @@ import {
7
7
  } from '@zerodev/wallet-core'
8
8
  import type { OAuthProvider } from './oauth.js'
9
9
  import {
10
- buildOAuthUrl,
11
- generateOAuthNonce,
10
+ buildBackendOAuthUrl,
11
+ listenForOAuthMessage,
12
12
  openOAuthPopup,
13
- pollOAuthPopup,
14
13
  } from './oauth.js'
15
14
 
16
15
  /**
@@ -116,12 +115,12 @@ export declare namespace loginPasskey {
116
115
 
117
116
  /**
118
117
  * Authenticate with OAuth (opens popup)
118
+ * Uses backend OAuth flow where the backend handles PKCE and token exchange
119
119
  */
120
120
  export async function authenticateOAuth(
121
121
  config: Config,
122
122
  parameters: {
123
123
  provider: OAuthProvider
124
- clientId?: string
125
124
  connector?: Connector
126
125
  },
127
126
  ): Promise<void> {
@@ -134,38 +133,23 @@ export async function authenticateOAuth(
134
133
 
135
134
  if (!wallet) throw new Error('Wallet not initialized')
136
135
  if (!oauthConfig) {
137
- throw new Error(
138
- 'OAuth is not configured. Please provide oauthConfig to zeroDevWallet connector.',
139
- )
140
- }
141
-
142
- // Get client ID for the provider
143
- let clientId = parameters.clientId
144
- if (!clientId) {
145
- clientId = oauthConfig.googleClientId
146
- }
147
-
148
- if (!clientId) {
149
- throw new Error(`Client ID not configured for ${parameters.provider}`)
150
- }
151
-
152
- if (!oauthConfig.redirectUri) {
153
- throw new Error('OAuth redirect URI is not configured.')
136
+ throw new Error('Wallet not initialized. Please wait for connector setup.')
154
137
  }
155
138
 
156
- // Generate nonce from wallet public key
139
+ // Get wallet public key for the OAuth flow
157
140
  const publicKey = await wallet.getPublicKey()
158
141
  if (!publicKey) {
159
142
  throw new Error('Failed to get wallet public key')
160
143
  }
161
- const nonce = generateOAuthNonce(publicKey)
162
144
 
163
- // Build OAuth URL
164
- const oauthUrl = buildOAuthUrl({
145
+ // Build OAuth URL that redirects to backend
146
+ // Use current origin as redirect - SDK auto-detects callback on any page
147
+ const oauthUrl = buildBackendOAuthUrl({
165
148
  provider: parameters.provider,
166
- clientId,
167
- redirectUri: oauthConfig.redirectUri,
168
- nonce,
149
+ backendUrl: oauthConfig.backendUrl,
150
+ projectId: oauthConfig.projectId,
151
+ publicKey,
152
+ returnTo: `${window.location.origin}?oauth_success=true&oauth_provider=${parameters.provider}`,
169
153
  })
170
154
 
171
155
  // Open popup
@@ -175,18 +159,18 @@ export async function authenticateOAuth(
175
159
  throw new Error(`Failed to open ${parameters.provider} login window.`)
176
160
  }
177
161
 
178
- // Poll for OAuth completion
162
+ // Listen for OAuth completion via postMessage
179
163
  return new Promise<void>((resolve, reject) => {
180
- pollOAuthPopup(
164
+ const cleanup = listenForOAuthMessage(
181
165
  authWindow,
182
166
  window.location.origin,
183
- async (idToken) => {
167
+ async () => {
184
168
  try {
185
169
  // Complete OAuth authentication with wallet-core
170
+ // The backend has stored the OAuth session in a cookie
186
171
  await wallet.auth({
187
172
  type: 'oauth',
188
173
  provider: parameters.provider,
189
- credential: idToken,
190
174
  })
191
175
 
192
176
  const [session, eoaAccount] = await Promise.all([
@@ -205,7 +189,10 @@ export async function authenticateOAuth(
205
189
  reject(err)
206
190
  }
207
191
  },
208
- reject,
192
+ (error) => {
193
+ cleanup()
194
+ reject(error)
195
+ },
209
196
  )
210
197
  })
211
198
  }
@@ -213,7 +200,6 @@ export async function authenticateOAuth(
213
200
  export declare namespace authenticateOAuth {
214
201
  type Parameters = {
215
202
  provider: OAuthProvider
216
- clientId?: string
217
203
  connector?: Connector
218
204
  }
219
205
  type ReturnType = void
@@ -230,7 +216,7 @@ export async function sendOTP(
230
216
  emailCustomization?: { magicLinkTemplate?: string }
231
217
  connector?: Connector
232
218
  },
233
- ): Promise<{ otpId: string; subOrganizationId: string }> {
219
+ ): Promise<{ otpId: string }> {
234
220
  const connector = parameters.connector ?? getZeroDevConnector(config)
235
221
 
236
222
  // @ts-expect-error - getStore is a custom method
@@ -251,7 +237,6 @@ export async function sendOTP(
251
237
 
252
238
  return {
253
239
  otpId: result.otpId,
254
- subOrganizationId: result.subOrganizationId,
255
240
  }
256
241
  }
257
242
 
@@ -261,7 +246,7 @@ export declare namespace sendOTP {
261
246
  emailCustomization?: { magicLinkTemplate?: string }
262
247
  connector?: Connector
263
248
  }
264
- type ReturnType = { otpId: string; subOrganizationId: string }
249
+ type ReturnType = { otpId: string }
265
250
  type ErrorType = Error
266
251
  }
267
252
 
@@ -273,7 +258,6 @@ export async function verifyOTP(
273
258
  parameters: {
274
259
  code: string
275
260
  otpId: string
276
- subOrganizationId: string
277
261
  connector?: Connector
278
262
  },
279
263
  ): Promise<void> {
@@ -290,7 +274,6 @@ export async function verifyOTP(
290
274
  mode: 'verifyOtp',
291
275
  otpId: parameters.otpId,
292
276
  otpCode: parameters.code,
293
- subOrganizationId: parameters.subOrganizationId,
294
277
  })
295
278
 
296
279
  const [session, eoaAccount] = await Promise.all([
@@ -309,7 +292,6 @@ export declare namespace verifyOTP {
309
292
  type Parameters = {
310
293
  code: string
311
294
  otpId: string
312
- subOrganizationId: string
313
295
  connector?: Connector
314
296
  }
315
297
  type ReturnType = void
@@ -349,6 +331,43 @@ export declare namespace refreshSession {
349
331
  type ErrorType = Error
350
332
  }
351
333
 
334
+ /**
335
+ * Get user email
336
+ */
337
+ export async function getUserEmail(config: Config): Promise<{ email: string }> {
338
+ const connector = getZeroDevConnector(config)
339
+
340
+ // @ts-expect-error - getStore is a custom method
341
+ const store = await connector.getStore()
342
+ const wallet = store.getState().wallet
343
+
344
+ if (!wallet) throw new Error('Wallet not initialized')
345
+
346
+ const oauthConfig = store.getState().oauthConfig
347
+ if (!oauthConfig) {
348
+ throw new Error('Wallet not initialized. Please wait for connector setup.')
349
+ }
350
+
351
+ const session = store.getState().session
352
+ if (!session) {
353
+ throw new Error('No active session')
354
+ }
355
+
356
+ // Call the core SDK method
357
+ return await wallet.client.getUserEmail({
358
+ organizationId: session.organizationId,
359
+ projectId: oauthConfig.projectId,
360
+ })
361
+ }
362
+
363
+ export declare namespace getUserEmail {
364
+ type Parameters = {
365
+ connector?: Connector
366
+ }
367
+ type ReturnType = { email: string }
368
+ type ErrorType = Error
369
+ }
370
+
352
371
  /**
353
372
  * Export wallet
354
373
  */
package/src/connector.ts CHANGED
@@ -6,13 +6,71 @@ import {
6
6
  } from '@zerodev/sdk'
7
7
  import { getEntryPoint, KERNEL_V3_3 } from '@zerodev/sdk/constants'
8
8
  import type { StorageAdapter } from '@zerodev/wallet-core'
9
- import { createZeroDevWallet } from '@zerodev/wallet-core'
9
+ import { createZeroDevWallet, KMS_SERVER_URL } from '@zerodev/wallet-core'
10
10
  import { type Chain, createPublicClient, http } from 'viem'
11
- import type { OAuthConfig } from './oauth.js'
11
+ import { handleOAuthCallback, type OAuthProvider } from './oauth.js'
12
12
  import { createProvider } from './provider.js'
13
13
  import { createZeroDevWalletStore } from './store.js'
14
14
  import { getAAUrl } from './utils/aaUtils.js'
15
15
 
16
+ // OAuth URL parameter used to detect callback
17
+ const OAUTH_SUCCESS_PARAM = 'oauth_success'
18
+ const OAUTH_PROVIDER_PARAM = 'oauth_provider'
19
+
20
+ /**
21
+ * Detect OAuth callback from URL params and handle it.
22
+ * - If in popup: sends postMessage to opener and closes
23
+ * - If not in popup: completes auth directly
24
+ */
25
+ async function detectAndHandleOAuthCallback(
26
+ wallet: Awaited<ReturnType<typeof createZeroDevWallet>>,
27
+ store: ReturnType<typeof createZeroDevWalletStore>,
28
+ ): Promise<boolean> {
29
+ if (typeof window === 'undefined') return false
30
+
31
+ const params = new URLSearchParams(window.location.search)
32
+ const isOAuthCallback = params.get(OAUTH_SUCCESS_PARAM) === 'true'
33
+
34
+ if (!isOAuthCallback) return false
35
+
36
+ // If in popup, use the existing handler to notify opener
37
+ if (window.opener) {
38
+ handleOAuthCallback(OAUTH_SUCCESS_PARAM)
39
+ return true
40
+ }
41
+
42
+ // Not in popup - complete auth directly (redirect flow)
43
+ console.log('OAuth callback detected, completing authentication...')
44
+ const provider = (params.get(OAUTH_PROVIDER_PARAM) ||
45
+ 'google') as OAuthProvider
46
+
47
+ try {
48
+ await wallet.auth({ type: 'oauth', provider })
49
+
50
+ const [session, eoaAccount] = await Promise.all([
51
+ wallet.getSession(),
52
+ wallet.toAccount(),
53
+ ])
54
+
55
+ store.getState().setEoaAccount(eoaAccount)
56
+ store.getState().setSession(session || null)
57
+
58
+ // Clean up URL params
59
+ params.delete(OAUTH_SUCCESS_PARAM)
60
+ params.delete(OAUTH_PROVIDER_PARAM)
61
+ const newUrl = params.toString()
62
+ ? `${window.location.pathname}?${params.toString()}`
63
+ : window.location.pathname
64
+ window.history.replaceState({}, '', newUrl)
65
+
66
+ console.log('OAuth authentication completed')
67
+ return true
68
+ } catch (error) {
69
+ console.error('OAuth authentication failed:', error)
70
+ return false
71
+ }
72
+ }
73
+
16
74
  export type ZeroDevWalletConnectorParams = {
17
75
  projectId: string
18
76
  organizationId?: string
@@ -23,7 +81,6 @@ export type ZeroDevWalletConnectorParams = {
23
81
  sessionStorage?: StorageAdapter
24
82
  autoRefreshSession?: boolean
25
83
  sessionWarningThreshold?: number
26
- oauthConfig?: OAuthConfig
27
84
  }
28
85
 
29
86
  export function zeroDevWallet(
@@ -75,10 +132,11 @@ export function zeroDevWallet(
75
132
  store = createZeroDevWalletStore()
76
133
  store.getState().setWallet(wallet)
77
134
 
78
- // Store OAuth config if provided
79
- if (params.oauthConfig) {
80
- store.getState().setOAuthConfig(params.oauthConfig)
81
- }
135
+ // Store OAuth config - uses proxyBaseUrl and projectId from params
136
+ store.getState().setOAuthConfig({
137
+ backendUrl: params.proxyBaseUrl || `${KMS_SERVER_URL}/api/v1`,
138
+ projectId: params.projectId,
139
+ })
82
140
 
83
141
  // Create EIP-1193 provider
84
142
  provider = createProvider({
@@ -96,6 +154,9 @@ export function zeroDevWallet(
96
154
  store.getState().setSession(session)
97
155
  }
98
156
 
157
+ // Auto-detect OAuth callback (when popup redirects back with ?oauth_success=true)
158
+ await detectAndHandleOAuthCallback(wallet, store)
159
+
99
160
  console.log('ZeroDevWallet connector initialized')
100
161
  }
101
162
 
@@ -0,0 +1,52 @@
1
+ 'use client'
2
+
3
+ import {
4
+ type UseQueryOptions,
5
+ type UseQueryResult,
6
+ useQuery,
7
+ } from '@tanstack/react-query'
8
+ import { type Config, type ResolvedRegister, useConfig } from 'wagmi'
9
+ import { getUserEmail } from '../actions.js'
10
+
11
+ type ConfigParameter<config extends Config = Config> = {
12
+ config?: Config | config | undefined
13
+ }
14
+
15
+ /**
16
+ * Hook to fetch user email address
17
+ */
18
+ export function useGetUserEmail<
19
+ config extends Config = ResolvedRegister['config'],
20
+ >(parameters: useGetUserEmail.Parameters<config>): useGetUserEmail.ReturnType {
21
+ const { query } = parameters
22
+ const config = useConfig(parameters)
23
+
24
+ return useQuery({
25
+ ...query,
26
+ queryKey: ['getUserEmail'],
27
+ queryFn: async () => {
28
+ return getUserEmail(config)
29
+ },
30
+ enabled: Boolean(config),
31
+ })
32
+ }
33
+
34
+ export declare namespace useGetUserEmail {
35
+ type Parameters<config extends Config = Config> = ConfigParameter<config> & {
36
+ query?:
37
+ | Omit<
38
+ UseQueryOptions<
39
+ getUserEmail.ReturnType,
40
+ getUserEmail.ErrorType,
41
+ getUserEmail.ReturnType
42
+ >,
43
+ 'queryKey' | 'queryFn'
44
+ >
45
+ | undefined
46
+ }
47
+
48
+ type ReturnType = UseQueryResult<
49
+ getUserEmail.ReturnType,
50
+ getUserEmail.ErrorType
51
+ >
52
+ }
package/src/index.ts CHANGED
@@ -3,13 +3,19 @@ export { zeroDevWallet } from './connector.js'
3
3
  export { useAuthenticateOAuth } from './hooks/useAuthenticateOAuth.js'
4
4
  export { useExportPrivateKey } from './hooks/useExportPrivateKey.js'
5
5
  export { useExportWallet } from './hooks/useExportWallet.js'
6
+ export { useGetUserEmail } from './hooks/useGetUserEmail.js'
6
7
  export { useLoginPasskey } from './hooks/useLoginPasskey.js'
7
8
  export { useRefreshSession } from './hooks/useRefreshSession.js'
8
9
  export { useRegisterPasskey } from './hooks/useRegisterPasskey.js'
9
10
  export { useSendOTP } from './hooks/useSendOTP.js'
10
11
  export { useVerifyOTP } from './hooks/useVerifyOTP.js'
11
- export type { OAuthConfig, OAuthProvider } from './oauth.js'
12
- export { OAUTH_PROVIDERS } from './oauth.js'
12
+ export type { OAuthMessageData, OAuthProvider } from './oauth.js'
13
+ export {
14
+ buildBackendOAuthUrl,
15
+ handleOAuthCallback,
16
+ listenForOAuthMessage,
17
+ OAUTH_PROVIDERS,
18
+ } from './oauth.js'
13
19
  export type { ZeroDevProvider } from './provider.js'
14
20
  export type { ZeroDevWalletState } from './store.js'
15
21
  export { createZeroDevWalletStore } from './store.js'
package/src/oauth.ts CHANGED
@@ -7,56 +7,17 @@ export const OAUTH_PROVIDERS = {
7
7
  export type OAuthProvider =
8
8
  (typeof OAUTH_PROVIDERS)[keyof typeof OAUTH_PROVIDERS]
9
9
 
10
- export type OAuthConfig = {
11
- googleClientId?: string
12
- redirectUri: string
13
- }
14
-
15
- export type OAuthFlowParams = {
10
+ export type BackendOAuthFlowParams = {
16
11
  provider: OAuthProvider
17
- clientId: string
18
- redirectUri: string
19
- nonce: string
20
- state?: Record<string, string>
12
+ backendUrl: string
13
+ projectId: string
14
+ publicKey: string
15
+ returnTo: string
21
16
  }
22
17
 
23
- const GOOGLE_AUTH_URL = 'https://accounts.google.com/o/oauth2/v2/auth'
24
-
25
18
  const POPUP_WIDTH = 500
26
19
  const POPUP_HEIGHT = 600
27
20
 
28
- export function buildOAuthUrl(params: OAuthFlowParams): string {
29
- const { provider, clientId, redirectUri, nonce, state } = params
30
-
31
- if (provider !== OAUTH_PROVIDERS.GOOGLE) {
32
- throw new Error(`Unsupported OAuth provider: ${provider}`)
33
- }
34
-
35
- const authUrl = new URL(GOOGLE_AUTH_URL)
36
- authUrl.searchParams.set('client_id', clientId)
37
- authUrl.searchParams.set('redirect_uri', redirectUri)
38
- authUrl.searchParams.set('response_type', 'id_token')
39
- authUrl.searchParams.set('scope', 'openid email profile')
40
- authUrl.searchParams.set('nonce', nonce)
41
- authUrl.searchParams.set('prompt', 'select_account')
42
-
43
- let stateParam = `provider=${provider}`
44
- if (state) {
45
- const additionalState = Object.entries(state)
46
- .map(
47
- ([key, value]) =>
48
- `${encodeURIComponent(key)}=${encodeURIComponent(value)}`,
49
- )
50
- .join('&')
51
- if (additionalState) {
52
- stateParam += `&${additionalState}`
53
- }
54
- }
55
- authUrl.searchParams.set('state', stateParam)
56
-
57
- return authUrl.toString()
58
- }
59
-
60
21
  export function openOAuthPopup(url: string): Window | null {
61
22
  const width = POPUP_WIDTH
62
23
  const height = POPUP_HEIGHT
@@ -76,49 +37,107 @@ export function openOAuthPopup(url: string): Window | null {
76
37
  return authWindow
77
38
  }
78
39
 
79
- export function extractOAuthToken(url: string): string | null {
80
- const hashParams = new URLSearchParams(url.split('#')[1])
81
- let idToken = hashParams.get('id_token')
40
+ export function generateOAuthNonce(publicKey: string): string {
41
+ return sha256(publicKey as Hex).replace(/^0x/, '')
42
+ }
82
43
 
83
- if (!idToken) {
84
- const queryParams = new URLSearchParams(url.split('?')[1])
85
- idToken = queryParams.get('id_token')
44
+ /**
45
+ * Build OAuth URL that redirects to backend's OAuth endpoint
46
+ * The backend handles PKCE, client credentials, and token exchange
47
+ */
48
+ export function buildBackendOAuthUrl(params: BackendOAuthFlowParams): string {
49
+ const { provider, backendUrl, projectId, publicKey, returnTo } = params
50
+
51
+ if (provider !== OAUTH_PROVIDERS.GOOGLE) {
52
+ throw new Error(`Unsupported OAuth provider: ${provider}`)
86
53
  }
87
54
 
88
- return idToken
55
+ const oauthUrl = new URL(`${backendUrl}/oauth/google/login`)
56
+ oauthUrl.searchParams.set('project_id', projectId)
57
+ oauthUrl.searchParams.set('pub_key', publicKey.replace(/^0x/, ''))
58
+ oauthUrl.searchParams.set('return_to', returnTo)
59
+
60
+ return oauthUrl.toString()
89
61
  }
90
62
 
91
- export function pollOAuthPopup(
63
+ export type OAuthMessageData = {
64
+ type: 'oauth_success' | 'oauth_error'
65
+ error?: string
66
+ }
67
+
68
+ /**
69
+ * Listen for OAuth completion via postMessage from popup
70
+ * The popup sends a message when it detects a successful redirect
71
+ */
72
+ export function listenForOAuthMessage(
92
73
  authWindow: Window,
93
- originUrl: string,
94
- onSuccess: (token: string) => void,
74
+ expectedOrigin: string,
75
+ onSuccess: () => void,
95
76
  onError: (error: Error) => void,
96
- ): void {
97
- const interval = setInterval(() => {
98
- try {
99
- if (authWindow.closed) {
100
- clearInterval(interval)
101
- onError(new Error('Authentication window was closed'))
102
- return
103
- }
104
-
105
- const url = authWindow.location.href || ''
106
-
107
- if (url.startsWith(originUrl)) {
108
- const token = extractOAuthToken(url)
109
-
110
- if (token) {
111
- authWindow.close()
112
- clearInterval(interval)
113
- onSuccess(token)
114
- }
115
- }
116
- } catch {
117
- // Ignore cross-origin errors
77
+ ): () => void {
78
+ let cleaned = false
79
+
80
+ const handleMessage = (event: MessageEvent<OAuthMessageData>) => {
81
+ // Only trust messages from expected origin
82
+ if (event.origin !== expectedOrigin) return
83
+ if (!event.data || typeof event.data !== 'object') return
84
+
85
+ if (event.data.type === 'oauth_success') {
86
+ cleanup()
87
+ onSuccess()
88
+ } else if (event.data.type === 'oauth_error') {
89
+ cleanup()
90
+ onError(new Error(event.data.error || 'OAuth authentication failed'))
91
+ }
92
+ }
93
+
94
+ const checkWindowClosed = setInterval(() => {
95
+ if (authWindow.closed) {
96
+ cleanup()
97
+ onError(new Error('Authentication window was closed'))
118
98
  }
119
99
  }, 500)
100
+
101
+ const cleanup = () => {
102
+ if (cleaned) return
103
+ cleaned = true
104
+ window.removeEventListener('message', handleMessage)
105
+ clearInterval(checkWindowClosed)
106
+ }
107
+
108
+ window.addEventListener('message', handleMessage)
109
+
110
+ return cleanup
120
111
  }
121
112
 
122
- export function generateOAuthNonce(publicKey: string): string {
123
- return sha256(publicKey as Hex).replace(/^0x/, '')
113
+ /**
114
+ * Handle OAuth callback on the return page
115
+ * Call this on the page that receives the OAuth redirect
116
+ * It sends a postMessage to the opener and closes the window
117
+ */
118
+ export function handleOAuthCallback(successParam = 'oauth_success'): boolean {
119
+ const urlParams = new URLSearchParams(window.location.search)
120
+ const isSuccess = urlParams.get(successParam) === 'true'
121
+ const error = urlParams.get('error')
122
+
123
+ if (window.opener) {
124
+ if (isSuccess) {
125
+ window.opener.postMessage(
126
+ { type: 'oauth_success' } satisfies OAuthMessageData,
127
+ window.location.origin,
128
+ )
129
+ window.close()
130
+ return true
131
+ }
132
+ if (error) {
133
+ window.opener.postMessage(
134
+ { type: 'oauth_error', error } satisfies OAuthMessageData,
135
+ window.location.origin,
136
+ )
137
+ window.close()
138
+ return false
139
+ }
140
+ }
141
+
142
+ return false
124
143
  }
package/src/store.ts CHANGED
@@ -10,7 +10,12 @@ import type { LocalAccount } from 'viem'
10
10
  import type { SmartAccount } from 'viem/account-abstraction'
11
11
  import { create } from 'zustand'
12
12
  import { persist, subscribeWithSelector } from 'zustand/middleware'
13
- import type { OAuthConfig } from './oauth.js'
13
+
14
+ // Internal OAuth config stored in the state (derived from connector params)
15
+ type InternalOAuthConfig = {
16
+ backendUrl: string
17
+ projectId: string
18
+ }
14
19
 
15
20
  export type ZeroDevWalletState = {
16
21
  // Core
@@ -26,8 +31,8 @@ export type ZeroDevWalletState = {
26
31
  // Session expiry
27
32
  isExpiring: boolean
28
33
 
29
- // OAuth config (optional)
30
- oauthConfig: OAuthConfig | null
34
+ // OAuth config (derived from connector params)
35
+ oauthConfig: InternalOAuthConfig | null
31
36
 
32
37
  // Actions
33
38
  setWallet: (wallet: ZeroDevWalletSDK) => void
@@ -40,7 +45,7 @@ export type ZeroDevWalletState = {
40
45
  setSession: (session: ZeroDevWalletSession | null) => void
41
46
  setActiveChainId: (chainId: number | null) => void
42
47
  setIsExpiring: (isExpiring: boolean) => void
43
- setOAuthConfig: (config: OAuthConfig | null) => void
48
+ setOAuthConfig: (config: InternalOAuthConfig | null) => void
44
49
  clear: () => void
45
50
  }
46
51