@zerodev/wallet-react 0.0.1-alpha.14 → 0.0.1-alpha.16

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.14",
3
+ "version": "0.0.1-alpha.16",
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.13"
33
+ "@zerodev/wallet-core": "0.0.1-alpha.15"
34
34
  },
35
35
  "devDependencies": {
36
36
  "@types/react": "^19",
@@ -569,7 +569,7 @@ describe('React Actions', () => {
569
569
  })
570
570
  })
571
571
 
572
- it('completes full OAuth success flow', async () => {
572
+ it('completes full OAuth success flow with sessionId', async () => {
573
573
  const wallet = createMockWallet()
574
574
  wallet.getSession.mockResolvedValue({ id: 'oauth-session' })
575
575
  wallet.toAccount.mockResolvedValue({ address: '0xoauth' })
@@ -578,11 +578,14 @@ describe('React Actions', () => {
578
578
  const config = createMockConfig(connector)
579
579
 
580
580
  mockOpenOAuthPopup.mockReturnValue({ closed: false } as Window)
581
- // Simulate the success callback being called immediately
581
+ // Simulate the success callback being called with sessionId
582
582
  mockListenForOAuthMessage.mockImplementation(
583
- (_win: Window, _origin: string, onSuccess: () => void) => {
584
- // Call onSuccess asynchronously to simulate real behavior
585
- setTimeout(() => onSuccess(), 0)
583
+ (
584
+ _win: Window,
585
+ _origin: string,
586
+ onSuccess: (sessionId: string) => void,
587
+ ) => {
588
+ setTimeout(() => onSuccess('test-session-id'), 0)
586
589
  return () => {}
587
590
  },
588
591
  )
@@ -592,6 +595,7 @@ describe('React Actions', () => {
592
595
  expect(wallet.auth).toHaveBeenCalledWith({
593
596
  type: 'oauth',
594
597
  provider: 'google',
598
+ sessionId: 'test-session-id',
595
599
  })
596
600
  expect(store.getState().setEoaAccount).toHaveBeenCalledWith({
597
601
  address: '0xoauth',
@@ -611,8 +615,12 @@ describe('React Actions', () => {
611
615
 
612
616
  mockOpenOAuthPopup.mockReturnValue({ closed: false } as Window)
613
617
  mockListenForOAuthMessage.mockImplementation(
614
- (_win: Window, _origin: string, onSuccess: () => void) => {
615
- setTimeout(() => onSuccess(), 0)
618
+ (
619
+ _win: Window,
620
+ _origin: string,
621
+ onSuccess: (sessionId: string) => void,
622
+ ) => {
623
+ setTimeout(() => onSuccess('session-id'), 0)
616
624
  return () => {}
617
625
  },
618
626
  )
@@ -633,7 +641,7 @@ describe('React Actions', () => {
633
641
  (
634
642
  _win: Window,
635
643
  _origin: string,
636
- _onSuccess: () => void,
644
+ _onSuccess: (sessionId: string) => void,
637
645
  onError: (error: Error) => void,
638
646
  ) => {
639
647
  setTimeout(() => onError(new Error('Window closed')), 0)
package/src/actions.ts CHANGED
@@ -158,13 +158,13 @@ export async function authenticateOAuth(
158
158
  const cleanup = listenForOAuthMessage(
159
159
  authWindow,
160
160
  window.location.origin,
161
- async () => {
161
+ async (sessionId) => {
162
162
  try {
163
163
  // Complete OAuth authentication with wallet-core
164
- // The backend has stored the OAuth session in a cookie
165
164
  await wallet.auth({
166
165
  type: 'oauth',
167
166
  provider: parameters.provider,
167
+ sessionId,
168
168
  })
169
169
 
170
170
  const [session, eoaAccount] = await Promise.all([
package/src/connector.ts CHANGED
@@ -16,6 +16,7 @@ import { getAAUrl } from './utils/aaUtils.js'
16
16
  // OAuth URL parameter used to detect callback
17
17
  const OAUTH_SUCCESS_PARAM = 'oauth_success'
18
18
  const OAUTH_PROVIDER_PARAM = 'oauth_provider'
19
+ const OAUTH_SESSION_ID_PARAM = 'session_id'
19
20
 
20
21
  /**
21
22
  * Detect OAuth callback from URL params and handle it.
@@ -43,9 +44,10 @@ async function detectAndHandleOAuthCallback(
43
44
  console.log('OAuth callback detected, completing authentication...')
44
45
  const provider = (params.get(OAUTH_PROVIDER_PARAM) ||
45
46
  'google') as OAuthProvider
47
+ const sessionId = params.get(OAUTH_SESSION_ID_PARAM) || ''
46
48
 
47
49
  try {
48
- await wallet.auth({ type: 'oauth', provider })
50
+ await wallet.auth({ type: 'oauth', provider, sessionId })
49
51
 
50
52
  const [session, eoaAccount] = await Promise.all([
51
53
  wallet.getSession(),
@@ -58,6 +60,7 @@ async function detectAndHandleOAuthCallback(
58
60
  // Clean up URL params
59
61
  params.delete(OAUTH_SUCCESS_PARAM)
60
62
  params.delete(OAUTH_PROVIDER_PARAM)
63
+ params.delete(OAUTH_SESSION_ID_PARAM)
61
64
  const newUrl = params.toString()
62
65
  ? `${window.location.pathname}?${params.toString()}`
63
66
  : window.location.pathname
package/src/oauth.test.ts CHANGED
@@ -188,15 +188,35 @@ describe('OAuth utilities', () => {
188
188
  vi.useRealTimers()
189
189
  })
190
190
 
191
- it('calls onSuccess when oauth_success message received', () => {
191
+ it('calls onSuccess with sessionId when oauth_success message received', () => {
192
192
  const cleanup = listenForOAuthMessage(
193
193
  mockWindow as Window,
194
194
  'https://app.example.com',
195
- onSuccessMock as () => void,
195
+ onSuccessMock as (sessionId: string) => void,
196
+ onErrorMock as (error: Error) => void,
197
+ )
198
+
199
+ // Simulate receiving a message with sessionId
200
+ const event = new MessageEvent('message', {
201
+ data: { type: 'oauth_success', sessionId: 'test-session-123' },
202
+ origin: 'https://app.example.com',
203
+ })
204
+ window.dispatchEvent(event)
205
+
206
+ expect(onSuccessMock).toHaveBeenCalledOnce()
207
+ expect(onSuccessMock).toHaveBeenCalledWith('test-session-123')
208
+ expect(onErrorMock).not.toHaveBeenCalled()
209
+ cleanup()
210
+ })
211
+
212
+ it('calls onSuccess with empty string when sessionId is missing', () => {
213
+ const cleanup = listenForOAuthMessage(
214
+ mockWindow as Window,
215
+ 'https://app.example.com',
216
+ onSuccessMock as (sessionId: string) => void,
196
217
  onErrorMock as (error: Error) => void,
197
218
  )
198
219
 
199
- // Simulate receiving a message
200
220
  const event = new MessageEvent('message', {
201
221
  data: { type: 'oauth_success' },
202
222
  origin: 'https://app.example.com',
@@ -204,6 +224,7 @@ describe('OAuth utilities', () => {
204
224
  window.dispatchEvent(event)
205
225
 
206
226
  expect(onSuccessMock).toHaveBeenCalledOnce()
227
+ expect(onSuccessMock).toHaveBeenCalledWith('')
207
228
  expect(onErrorMock).not.toHaveBeenCalled()
208
229
  cleanup()
209
230
  })
@@ -212,7 +233,7 @@ describe('OAuth utilities', () => {
212
233
  const cleanup = listenForOAuthMessage(
213
234
  mockWindow as Window,
214
235
  'https://app.example.com',
215
- onSuccessMock as () => void,
236
+ onSuccessMock as (sessionId: string) => void,
216
237
  onErrorMock as (error: Error) => void,
217
238
  )
218
239
 
@@ -232,7 +253,7 @@ describe('OAuth utilities', () => {
232
253
  const cleanup = listenForOAuthMessage(
233
254
  mockWindow as Window,
234
255
  'https://app.example.com',
235
- onSuccessMock as () => void,
256
+ onSuccessMock as (sessionId: string) => void,
236
257
  onErrorMock as (error: Error) => void,
237
258
  )
238
259
 
@@ -251,7 +272,7 @@ describe('OAuth utilities', () => {
251
272
  const cleanup = listenForOAuthMessage(
252
273
  mockWindow as Window,
253
274
  'https://app.example.com',
254
- onSuccessMock as () => void,
275
+ onSuccessMock as (sessionId: string) => void,
255
276
  onErrorMock as (error: Error) => void,
256
277
  )
257
278
 
@@ -268,7 +289,7 @@ describe('OAuth utilities', () => {
268
289
  const cleanup = listenForOAuthMessage(
269
290
  mockWindow as Window,
270
291
  'https://app.example.com',
271
- onSuccessMock as () => void,
292
+ onSuccessMock as (sessionId: string) => void,
272
293
  onErrorMock as (error: Error) => void,
273
294
  )
274
295
 
@@ -288,7 +309,7 @@ describe('OAuth utilities', () => {
288
309
  const cleanup = listenForOAuthMessage(
289
310
  mockWindow as Window,
290
311
  'https://app.example.com',
291
- onSuccessMock as () => void,
312
+ onSuccessMock as (sessionId: string) => void,
292
313
  onErrorMock as (error: Error) => void,
293
314
  )
294
315
 
@@ -323,7 +344,7 @@ describe('OAuth utilities', () => {
323
344
  const cleanup = listenForOAuthMessage(
324
345
  mockWindow as Window,
325
346
  'https://app.example.com',
326
- onSuccessMock as () => void,
347
+ onSuccessMock as (sessionId: string) => void,
327
348
  onErrorMock as (error: Error) => void,
328
349
  )
329
350
 
@@ -345,7 +366,7 @@ describe('OAuth utilities', () => {
345
366
  const cleanup = listenForOAuthMessage(
346
367
  mockWindow as Window,
347
368
  'https://app.example.com',
348
- onSuccessMock as () => void,
369
+ onSuccessMock as (sessionId: string) => void,
349
370
  onErrorMock as (error: Error) => void,
350
371
  )
351
372
 
@@ -391,7 +412,20 @@ describe('OAuth utilities', () => {
391
412
  window.close = originalClose
392
413
  })
393
414
 
394
- it('returns true and posts success message on oauth_success=true', () => {
415
+ it('returns true and posts success message with sessionId on oauth_success=true', () => {
416
+ window.location.search = '?oauth_success=true&session_id=abc123'
417
+
418
+ const result = handleOAuthCallback()
419
+
420
+ expect(result).toBe(true)
421
+ expect(window.opener?.postMessage).toHaveBeenCalledWith(
422
+ { type: 'oauth_success', sessionId: 'abc123' },
423
+ 'https://app.example.com',
424
+ )
425
+ expect(window.close).toHaveBeenCalled()
426
+ })
427
+
428
+ it('posts success message without sessionId when session_id param is missing', () => {
395
429
  window.location.search = '?oauth_success=true'
396
430
 
397
431
  const result = handleOAuthCallback()
package/src/oauth.ts CHANGED
@@ -62,6 +62,7 @@ export function buildBackendOAuthUrl(params: BackendOAuthFlowParams): string {
62
62
 
63
63
  export type OAuthMessageData = {
64
64
  type: 'oauth_success' | 'oauth_error'
65
+ sessionId?: string
65
66
  error?: string
66
67
  }
67
68
 
@@ -72,7 +73,7 @@ export type OAuthMessageData = {
72
73
  export function listenForOAuthMessage(
73
74
  authWindow: Window,
74
75
  expectedOrigin: string,
75
- onSuccess: () => void,
76
+ onSuccess: (sessionId: string) => void,
76
77
  onError: (error: Error) => void,
77
78
  ): () => void {
78
79
  let cleaned = false
@@ -84,7 +85,7 @@ export function listenForOAuthMessage(
84
85
 
85
86
  if (event.data.type === 'oauth_success') {
86
87
  cleanup()
87
- onSuccess()
88
+ onSuccess(event.data.sessionId || '')
88
89
  } else if (event.data.type === 'oauth_error') {
89
90
  cleanup()
90
91
  onError(new Error(event.data.error || 'OAuth authentication failed'))
@@ -119,13 +120,13 @@ export function handleOAuthCallback(successParam = 'oauth_success'): boolean {
119
120
  const urlParams = new URLSearchParams(window.location.search)
120
121
  const isSuccess = urlParams.get(successParam) === 'true'
121
122
  const error = urlParams.get('error')
123
+ const sessionId = urlParams.get('session_id') ?? undefined
122
124
 
123
125
  if (window.opener) {
124
126
  if (isSuccess) {
125
- window.opener.postMessage(
126
- { type: 'oauth_success' } satisfies OAuthMessageData,
127
- window.location.origin,
128
- )
127
+ const message: OAuthMessageData = { type: 'oauth_success' }
128
+ if (sessionId) message.sessionId = sessionId
129
+ window.opener.postMessage(message, window.location.origin)
129
130
  window.close()
130
131
  return true
131
132
  }
package/src/provider.ts CHANGED
@@ -187,7 +187,9 @@ export function createProvider({
187
187
 
188
188
  if (!account) throw new Error('Not authenticated')
189
189
 
190
- return await account.signMessage({ message })
190
+ return await account.signMessage({
191
+ message: { raw: message as `0x${string}` },
192
+ })
191
193
  }
192
194
 
193
195
  case 'eth_signTypedData_v4': {