@zerodev/wallet-react 0.0.1-alpha.14 → 0.0.1-alpha.15
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/CHANGELOG.md +8 -0
- package/dist/_cjs/actions.js +2 -1
- package/dist/_cjs/connector.js +4 -1
- package/dist/_cjs/oauth.js +6 -2
- package/dist/_esm/actions.js +2 -2
- package/dist/_esm/connector.js +4 -1
- package/dist/_esm/oauth.js +6 -2
- package/dist/_types/connector.d.ts.map +1 -1
- package/dist/_types/oauth.d.ts +2 -1
- package/dist/_types/oauth.d.ts.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/src/actions.test.ts +16 -8
- package/src/actions.ts +2 -2
- package/src/connector.ts +4 -1
- package/src/oauth.test.ts +45 -11
- package/src/oauth.ts +7 -6
- package/tsconfig.build.tsbuildinfo +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zerodev/wallet-react",
|
|
3
|
-
"version": "0.0.1-alpha.
|
|
3
|
+
"version": "0.0.1-alpha.15",
|
|
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.
|
|
33
|
+
"@zerodev/wallet-core": "0.0.1-alpha.14"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@types/react": "^19",
|
package/src/actions.test.ts
CHANGED
|
@@ -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
|
|
581
|
+
// Simulate the success callback being called with sessionId
|
|
582
582
|
mockListenForOAuthMessage.mockImplementation(
|
|
583
|
-
(
|
|
584
|
-
|
|
585
|
-
|
|
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
|
-
(
|
|
615
|
-
|
|
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
|
-
|
|
126
|
-
|
|
127
|
-
|
|
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
|
}
|