@luxexchange/sessions 1.0.2 → 1.0.3
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/.depcheckrc +20 -0
- package/.eslintrc.js +21 -0
- package/README.md +1 -0
- package/env.d.ts +12 -0
- package/package.json +3 -4
- package/project.json +1 -7
- package/src/challenge-solvers/createChallengeSolverService.ts +2 -2
- package/src/challenge-solvers/createHashcashMockSolver.ts +2 -2
- package/src/challenge-solvers/createHashcashSolver.test.ts +6 -6
- package/src/challenge-solvers/createHashcashSolver.ts +18 -3
- package/src/challenge-solvers/createNoneMockSolver.ts +1 -1
- package/src/challenge-solvers/createTurnstileMockSolver.ts +2 -2
- package/src/challenge-solvers/createTurnstileSolver.ts +9 -5
- package/src/challenge-solvers/hashcash/core.native.ts +1 -1
- package/src/challenge-solvers/hashcash/core.test.ts +10 -10
- package/src/challenge-solvers/hashcash/core.ts +1 -1
- package/src/challenge-solvers/hashcash/createWorkerHashcashSolver.test.ts +4 -4
- package/src/challenge-solvers/hashcash/worker/createHashcashMultiWorkerChannel.native.ts +1 -1
- package/src/challenge-solvers/hashcash/worker/createHashcashMultiWorkerChannel.ts +1 -1
- package/src/challenge-solvers/hashcash/worker/createHashcashWorkerChannel.native.ts +1 -1
- package/src/challenge-solvers/hashcash/worker/createHashcashWorkerChannel.ts +1 -1
- package/src/challenge-solvers/hashcash/worker/hashcash.worker.ts +3 -3
- package/src/challenge-solvers/turnstileSolver.integration.test.ts +1 -1
- package/src/challengeFlow.integration.test.ts +41 -41
- package/src/device-id/createDeviceIdService.ts +1 -1
- package/src/index.ts +8 -6
- package/src/oauth-service/types.ts +1 -1
- package/src/session-initialization/createSessionInitializationService.ts +29 -38
- package/src/session-repository/createSessionClient.ts +1 -1
- package/src/session-repository/createSessionRepository.test.ts +2 -2
- package/src/session-repository/createSessionRepository.ts +11 -11
- package/src/session-repository/types.ts +1 -1
- package/src/session-service/createNoopSessionService.ts +2 -2
- package/src/session-service/createSessionService.test.ts +29 -29
- package/src/session-service/createSessionService.ts +4 -4
- package/src/session-service/types.ts +1 -1
- package/src/session-storage/createSessionStorage.ts +1 -1
- package/src/session.integration.test.ts +116 -80
- package/src/sessionLifecycle.integration.test.ts +22 -22
- package/src/test-utils/createLocalCookieTransport.ts +1 -1
- package/src/test-utils/createLocalHeaderTransport.ts +1 -1
- package/src/test-utils/mocks.ts +3 -3
- package/src/test-utils.ts +24 -24
- package/src/uniswap-identifier/createUniswapIdentifierService.ts +19 -0
- package/src/uniswap-identifier/types.ts +11 -0
- package/src/uniswap-identifier/uniswapIdentifierQuery.ts +20 -0
- package/tsconfig.json +10 -3
- package/tsconfig.lint.json +8 -0
- package/tsconfig.spec.json +8 -0
- package/vitest.config.ts +20 -0
- package/vitest.integration.config.ts +14 -0
- package/src/lux-identifier/createLuxIdentifierService.ts +0 -19
- package/src/lux-identifier/luxIdentifierQuery.ts +0 -20
- package/src/lux-identifier/types.ts +0 -11
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
SignoutResponse,
|
|
8
8
|
VerifyResponse,
|
|
9
9
|
VerifySuccess,
|
|
10
|
-
} from '@
|
|
10
|
+
} from '@luxamm/client-platform-service/dist/uniswap/platformservice/v1/sessionService_pb'
|
|
11
11
|
import { createChallengeSolverService } from '@luxexchange/sessions/src/challenge-solvers/createChallengeSolverService'
|
|
12
12
|
import type { ChallengeSolver } from '@luxexchange/sessions/src/challenge-solvers/types'
|
|
13
13
|
import type { PerformanceTracker } from '@luxexchange/sessions/src/performance/types'
|
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
createTestTransport,
|
|
24
24
|
InMemoryDeviceIdService,
|
|
25
25
|
InMemorySessionStorage,
|
|
26
|
-
|
|
26
|
+
InMemoryLxIdentifierService,
|
|
27
27
|
type MockEndpoints,
|
|
28
28
|
} from '@luxexchange/sessions/src/test-utils'
|
|
29
29
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
@@ -52,7 +52,7 @@ const mockTurnstileSolve = vi.fn()
|
|
|
52
52
|
describe('Challenge Flow Integration Tests', () => {
|
|
53
53
|
let sessionStorage: InMemorySessionStorage
|
|
54
54
|
let deviceIdService: InMemoryDeviceIdService
|
|
55
|
-
let
|
|
55
|
+
let lxIdentifierService: InMemoryLxIdentifierService
|
|
56
56
|
let sessionService: SessionService
|
|
57
57
|
let sessionInitializationService: SessionInitializationService
|
|
58
58
|
let mockEndpoints: MockEndpoints
|
|
@@ -61,18 +61,18 @@ describe('Challenge Flow Integration Tests', () => {
|
|
|
61
61
|
// Initialize in-memory storage
|
|
62
62
|
sessionStorage = new InMemorySessionStorage()
|
|
63
63
|
deviceIdService = new InMemoryDeviceIdService()
|
|
64
|
-
|
|
64
|
+
lxIdentifierService = new InMemoryLxIdentifierService()
|
|
65
65
|
|
|
66
66
|
// Set up mock endpoints with default responses
|
|
67
67
|
mockEndpoints = {
|
|
68
|
-
'/
|
|
68
|
+
'/uniswap.platformservice.v1.SessionService/InitSession': async (): Promise<InitSessionResponse> => {
|
|
69
69
|
return new InitSessionResponse({
|
|
70
70
|
sessionId: 'test-session-123',
|
|
71
71
|
needChallenge: true,
|
|
72
72
|
extra: {},
|
|
73
73
|
})
|
|
74
74
|
},
|
|
75
|
-
'/
|
|
75
|
+
'/uniswap.platformservice.v1.SessionService/Challenge': async (): Promise<ChallengeResponse> => {
|
|
76
76
|
return new ChallengeResponse({
|
|
77
77
|
challengeId: '02c241f3-8d45-4a88-842a-d364c30a6c44',
|
|
78
78
|
challengeType: ChallengeType.TURNSTILE,
|
|
@@ -81,16 +81,16 @@ describe('Challenge Flow Integration Tests', () => {
|
|
|
81
81
|
},
|
|
82
82
|
})
|
|
83
83
|
},
|
|
84
|
-
'/
|
|
84
|
+
'/uniswap.platformservice.v1.SessionService/Verify': async (): Promise<VerifyResponse> => {
|
|
85
85
|
return createSuccessVerifyResponse()
|
|
86
86
|
},
|
|
87
|
-
'/
|
|
87
|
+
'/uniswap.platformservice.v1.SessionService/DeleteSession': async (): Promise<DeleteSessionResponse> => {
|
|
88
88
|
return new DeleteSessionResponse({})
|
|
89
89
|
},
|
|
90
|
-
'/
|
|
90
|
+
'/uniswap.platformservice.v1.SessionService/GetChallengeTypes': async (): Promise<GetChallengeTypesResponse> => {
|
|
91
91
|
return new GetChallengeTypesResponse({ challengeTypes: [] })
|
|
92
92
|
},
|
|
93
|
-
'/
|
|
93
|
+
'/uniswap.platformservice.v1.SessionService/Signout': async (): Promise<SignoutResponse> => {
|
|
94
94
|
return new SignoutResponse({})
|
|
95
95
|
},
|
|
96
96
|
} as unknown as MockEndpoints
|
|
@@ -110,7 +110,7 @@ describe('Challenge Flow Integration Tests', () => {
|
|
|
110
110
|
sessionService = createSessionService({
|
|
111
111
|
sessionStorage,
|
|
112
112
|
deviceIdService,
|
|
113
|
-
|
|
113
|
+
lxIdentifierService,
|
|
114
114
|
sessionRepository,
|
|
115
115
|
})
|
|
116
116
|
|
|
@@ -149,7 +149,7 @@ describe('Challenge Flow Integration Tests', () => {
|
|
|
149
149
|
|
|
150
150
|
it('initializes a session with needChallenge: true and completes challenge flow', async () => {
|
|
151
151
|
// Update mock to return needChallenge: true
|
|
152
|
-
mockEndpoints['/
|
|
152
|
+
mockEndpoints['/uniswap.platformservice.v1.SessionService/InitSession'] =
|
|
153
153
|
async (): Promise<InitSessionResponse> => {
|
|
154
154
|
return new InitSessionResponse({
|
|
155
155
|
sessionId: '776973bd-bbc2-452b-9c35-1b72c475afbd',
|
|
@@ -164,8 +164,8 @@ describe('Challenge Flow Integration Tests', () => {
|
|
|
164
164
|
const verifyCalls: Array<{ request: any; headers: Record<string, string> }> = []
|
|
165
165
|
|
|
166
166
|
// Wrap handlers to track calls
|
|
167
|
-
const originalInit = mockEndpoints['/
|
|
168
|
-
mockEndpoints['/
|
|
167
|
+
const originalInit = mockEndpoints['/uniswap.platformservice.v1.SessionService/InitSession']
|
|
168
|
+
mockEndpoints['/uniswap.platformservice.v1.SessionService/InitSession'] = async (
|
|
169
169
|
request,
|
|
170
170
|
headers,
|
|
171
171
|
): Promise<InitSessionResponse> => {
|
|
@@ -173,8 +173,8 @@ describe('Challenge Flow Integration Tests', () => {
|
|
|
173
173
|
return originalInit(request, headers)
|
|
174
174
|
}
|
|
175
175
|
|
|
176
|
-
const originalChallenge = mockEndpoints['/
|
|
177
|
-
mockEndpoints['/
|
|
176
|
+
const originalChallenge = mockEndpoints['/uniswap.platformservice.v1.SessionService/Challenge']
|
|
177
|
+
mockEndpoints['/uniswap.platformservice.v1.SessionService/Challenge'] = async (
|
|
178
178
|
request,
|
|
179
179
|
headers,
|
|
180
180
|
): Promise<ChallengeResponse> => {
|
|
@@ -182,8 +182,8 @@ describe('Challenge Flow Integration Tests', () => {
|
|
|
182
182
|
return originalChallenge(request, headers)
|
|
183
183
|
}
|
|
184
184
|
|
|
185
|
-
const originalVerify = mockEndpoints['/
|
|
186
|
-
mockEndpoints['/
|
|
185
|
+
const originalVerify = mockEndpoints['/uniswap.platformservice.v1.SessionService/Verify']
|
|
186
|
+
mockEndpoints['/uniswap.platformservice.v1.SessionService/Verify'] = async (
|
|
187
187
|
request,
|
|
188
188
|
headers,
|
|
189
189
|
): Promise<VerifyResponse> => {
|
|
@@ -254,7 +254,7 @@ describe('Challenge Flow Integration Tests', () => {
|
|
|
254
254
|
|
|
255
255
|
// Track calls
|
|
256
256
|
let initCallCount = 0
|
|
257
|
-
mockEndpoints['/
|
|
257
|
+
mockEndpoints['/uniswap.platformservice.v1.SessionService/InitSession'] =
|
|
258
258
|
async (): Promise<InitSessionResponse> => {
|
|
259
259
|
initCallCount++
|
|
260
260
|
// Backend returns the same session ID (simulating session reuse)
|
|
@@ -279,7 +279,7 @@ describe('Challenge Flow Integration Tests', () => {
|
|
|
279
279
|
|
|
280
280
|
it('handles challenge retry when upgrade fails', async () => {
|
|
281
281
|
// Set up to require challenge
|
|
282
|
-
mockEndpoints['/
|
|
282
|
+
mockEndpoints['/uniswap.platformservice.v1.SessionService/InitSession'] =
|
|
283
283
|
async (): Promise<InitSessionResponse> => {
|
|
284
284
|
return new InitSessionResponse({
|
|
285
285
|
sessionId: 'retry-session-123',
|
|
@@ -290,7 +290,7 @@ describe('Challenge Flow Integration Tests', () => {
|
|
|
290
290
|
|
|
291
291
|
// Make first verify attempt fail with retry
|
|
292
292
|
let verifyAttempts = 0
|
|
293
|
-
mockEndpoints['/
|
|
293
|
+
mockEndpoints['/uniswap.platformservice.v1.SessionService/Verify'] = async (): Promise<VerifyResponse> => {
|
|
294
294
|
verifyAttempts++
|
|
295
295
|
if (verifyAttempts === 1) {
|
|
296
296
|
return new VerifyResponse({ retry: true })
|
|
@@ -300,8 +300,8 @@ describe('Challenge Flow Integration Tests', () => {
|
|
|
300
300
|
|
|
301
301
|
// Track challenge calls
|
|
302
302
|
const challengeCalls: any[] = []
|
|
303
|
-
const originalChallenge = mockEndpoints['/
|
|
304
|
-
mockEndpoints['/
|
|
303
|
+
const originalChallenge = mockEndpoints['/uniswap.platformservice.v1.SessionService/Challenge']
|
|
304
|
+
mockEndpoints['/uniswap.platformservice.v1.SessionService/Challenge'] = async (
|
|
305
305
|
request,
|
|
306
306
|
headers,
|
|
307
307
|
): Promise<ChallengeResponse> => {
|
|
@@ -323,7 +323,7 @@ describe('Challenge Flow Integration Tests', () => {
|
|
|
323
323
|
|
|
324
324
|
it('respects maximum retry limit for challenges', async () => {
|
|
325
325
|
// Set up to require challenge
|
|
326
|
-
mockEndpoints['/
|
|
326
|
+
mockEndpoints['/uniswap.platformservice.v1.SessionService/InitSession'] =
|
|
327
327
|
async (): Promise<InitSessionResponse> => {
|
|
328
328
|
return new InitSessionResponse({
|
|
329
329
|
sessionId: 'max-retry-session',
|
|
@@ -333,7 +333,7 @@ describe('Challenge Flow Integration Tests', () => {
|
|
|
333
333
|
}
|
|
334
334
|
|
|
335
335
|
// Always return retry: true
|
|
336
|
-
mockEndpoints['/
|
|
336
|
+
mockEndpoints['/uniswap.platformservice.v1.SessionService/Verify'] = async (): Promise<VerifyResponse> => {
|
|
337
337
|
return new VerifyResponse({ retry: true })
|
|
338
338
|
}
|
|
339
339
|
|
|
@@ -341,8 +341,8 @@ describe('Challenge Flow Integration Tests', () => {
|
|
|
341
341
|
const challengeCalls: any[] = []
|
|
342
342
|
const verifyCalls: any[] = []
|
|
343
343
|
|
|
344
|
-
const originalChallenge = mockEndpoints['/
|
|
345
|
-
mockEndpoints['/
|
|
344
|
+
const originalChallenge = mockEndpoints['/uniswap.platformservice.v1.SessionService/Challenge']
|
|
345
|
+
mockEndpoints['/uniswap.platformservice.v1.SessionService/Challenge'] = async (
|
|
346
346
|
request,
|
|
347
347
|
headers,
|
|
348
348
|
): Promise<ChallengeResponse> => {
|
|
@@ -350,8 +350,8 @@ describe('Challenge Flow Integration Tests', () => {
|
|
|
350
350
|
return originalChallenge(request, headers)
|
|
351
351
|
}
|
|
352
352
|
|
|
353
|
-
const originalVerify = mockEndpoints['/
|
|
354
|
-
mockEndpoints['/
|
|
353
|
+
const originalVerify = mockEndpoints['/uniswap.platformservice.v1.SessionService/Verify']
|
|
354
|
+
mockEndpoints['/uniswap.platformservice.v1.SessionService/Verify'] = async (
|
|
355
355
|
request,
|
|
356
356
|
headers,
|
|
357
357
|
): Promise<VerifyResponse> => {
|
|
@@ -374,8 +374,8 @@ describe('Challenge Flow Integration Tests', () => {
|
|
|
374
374
|
|
|
375
375
|
// Track challenge request to verify headers
|
|
376
376
|
let capturedHeaders: Record<string, string> = {}
|
|
377
|
-
const originalChallenge = mockEndpoints['/
|
|
378
|
-
mockEndpoints['/
|
|
377
|
+
const originalChallenge = mockEndpoints['/uniswap.platformservice.v1.SessionService/Challenge']
|
|
378
|
+
mockEndpoints['/uniswap.platformservice.v1.SessionService/Challenge'] = async (
|
|
379
379
|
request,
|
|
380
380
|
headers,
|
|
381
381
|
): Promise<ChallengeResponse> => {
|
|
@@ -397,8 +397,8 @@ describe('Challenge Flow Integration Tests', () => {
|
|
|
397
397
|
|
|
398
398
|
// Track challenge request to verify headers
|
|
399
399
|
let capturedHeaders: Record<string, string> = {}
|
|
400
|
-
const originalChallenge = mockEndpoints['/
|
|
401
|
-
mockEndpoints['/
|
|
400
|
+
const originalChallenge = mockEndpoints['/uniswap.platformservice.v1.SessionService/Challenge']
|
|
401
|
+
mockEndpoints['/uniswap.platformservice.v1.SessionService/Challenge'] = async (
|
|
402
402
|
request,
|
|
403
403
|
headers,
|
|
404
404
|
): Promise<ChallengeResponse> => {
|
|
@@ -416,7 +416,7 @@ describe('Challenge Flow Integration Tests', () => {
|
|
|
416
416
|
|
|
417
417
|
it('submits empty solution when solver throws, allowing verify-retry fallback', async () => {
|
|
418
418
|
// Set up to require challenge
|
|
419
|
-
mockEndpoints['/
|
|
419
|
+
mockEndpoints['/uniswap.platformservice.v1.SessionService/InitSession'] =
|
|
420
420
|
async (): Promise<InitSessionResponse> => {
|
|
421
421
|
return new InitSessionResponse({
|
|
422
422
|
sessionId: 'error-session-123',
|
|
@@ -430,7 +430,7 @@ describe('Challenge Flow Integration Tests', () => {
|
|
|
430
430
|
|
|
431
431
|
// Verify endpoint accepts empty solution (no retry needed for this test)
|
|
432
432
|
const verifyCalls: Array<{ request: any }> = []
|
|
433
|
-
mockEndpoints['/
|
|
433
|
+
mockEndpoints['/uniswap.platformservice.v1.SessionService/Verify'] = async (request): Promise<VerifyResponse> => {
|
|
434
434
|
verifyCalls.push({ request })
|
|
435
435
|
return createSuccessVerifyResponse()
|
|
436
436
|
}
|
|
@@ -462,7 +462,7 @@ describe('Challenge Flow Integration Tests', () => {
|
|
|
462
462
|
|
|
463
463
|
it('Turnstile solver fails → empty verify → retry → Hashcash succeeds end-to-end', async () => {
|
|
464
464
|
// Set up to require challenge
|
|
465
|
-
mockEndpoints['/
|
|
465
|
+
mockEndpoints['/uniswap.platformservice.v1.SessionService/InitSession'] =
|
|
466
466
|
async (): Promise<InitSessionResponse> => {
|
|
467
467
|
return new InitSessionResponse({
|
|
468
468
|
sessionId: 'fallback-e2e-session',
|
|
@@ -473,7 +473,7 @@ describe('Challenge Flow Integration Tests', () => {
|
|
|
473
473
|
|
|
474
474
|
// First challenge returns Turnstile, second returns Hashcash
|
|
475
475
|
let challengeRequestCount = 0
|
|
476
|
-
mockEndpoints['/
|
|
476
|
+
mockEndpoints['/uniswap.platformservice.v1.SessionService/Challenge'] = async (): Promise<ChallengeResponse> => {
|
|
477
477
|
challengeRequestCount++
|
|
478
478
|
if (challengeRequestCount === 1) {
|
|
479
479
|
return new ChallengeResponse({
|
|
@@ -495,7 +495,7 @@ describe('Challenge Flow Integration Tests', () => {
|
|
|
495
495
|
|
|
496
496
|
// First verify rejects empty solution, second succeeds
|
|
497
497
|
let verifyCount = 0
|
|
498
|
-
mockEndpoints['/
|
|
498
|
+
mockEndpoints['/uniswap.platformservice.v1.SessionService/Verify'] = async (): Promise<VerifyResponse> => {
|
|
499
499
|
verifyCount++
|
|
500
500
|
if (verifyCount === 1) {
|
|
501
501
|
return new VerifyResponse({ retry: true })
|
|
@@ -544,7 +544,7 @@ describe('Challenge Flow Integration Tests', () => {
|
|
|
544
544
|
|
|
545
545
|
it('falls back to Hashcash via verify-retry when mock Turnstile token is rejected', async () => {
|
|
546
546
|
// Set up to require challenge
|
|
547
|
-
mockEndpoints['/
|
|
547
|
+
mockEndpoints['/uniswap.platformservice.v1.SessionService/InitSession'] =
|
|
548
548
|
async (): Promise<InitSessionResponse> => {
|
|
549
549
|
return new InitSessionResponse({
|
|
550
550
|
sessionId: 'fallback-session-123',
|
|
@@ -556,7 +556,7 @@ describe('Challenge Flow Integration Tests', () => {
|
|
|
556
556
|
// First challenge returns Turnstile, second returns Hashcash
|
|
557
557
|
// (backend switches after failed verification)
|
|
558
558
|
let challengeRequestCount = 0
|
|
559
|
-
mockEndpoints['/
|
|
559
|
+
mockEndpoints['/uniswap.platformservice.v1.SessionService/Challenge'] = async (): Promise<ChallengeResponse> => {
|
|
560
560
|
challengeRequestCount++
|
|
561
561
|
if (challengeRequestCount === 1) {
|
|
562
562
|
return new ChallengeResponse({
|
|
@@ -578,7 +578,7 @@ describe('Challenge Flow Integration Tests', () => {
|
|
|
578
578
|
|
|
579
579
|
// First verify rejects mock token, second succeeds
|
|
580
580
|
let verifyCount = 0
|
|
581
|
-
mockEndpoints['/
|
|
581
|
+
mockEndpoints['/uniswap.platformservice.v1.SessionService/Verify'] = async (): Promise<VerifyResponse> => {
|
|
582
582
|
verifyCount++
|
|
583
583
|
if (verifyCount === 1) {
|
|
584
584
|
return new VerifyResponse({ retry: true })
|
package/src/index.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** biome-ignore-all assist/source/organizeImports: we want to manually group exports by category */
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* @
|
|
4
|
+
* @luxexchange/sessions
|
|
5
5
|
*
|
|
6
6
|
* This is the ONLY public entry point for the Sessions package.
|
|
7
7
|
* All exports must be explicitly listed here.
|
|
@@ -11,10 +11,10 @@
|
|
|
11
11
|
// Device ID
|
|
12
12
|
export { createDeviceIdService } from '@luxexchange/sessions/src/device-id/createDeviceIdService'
|
|
13
13
|
export type { DeviceIdService } from '@luxexchange/sessions/src/device-id/types'
|
|
14
|
-
//
|
|
15
|
-
export {
|
|
16
|
-
export {
|
|
17
|
-
export type {
|
|
14
|
+
// Uniswap Identifier
|
|
15
|
+
export { createLxIdentifierService } from '@luxexchange/sessions/src/uniswap-identifier/createLxIdentifierService'
|
|
16
|
+
export { lxIdentifierQuery } from '@luxexchange/sessions/src/uniswap-identifier/lxIdentifierQuery'
|
|
17
|
+
export type { LxIdentifierService } from '@luxexchange/sessions/src/uniswap-identifier/types'
|
|
18
18
|
// Session Repository
|
|
19
19
|
export { createSessionRepository } from '@luxexchange/sessions/src/session-repository/createSessionRepository'
|
|
20
20
|
export { ChallengeRejectedError } from '@luxexchange/sessions/src/session-repository/errors'
|
|
@@ -129,9 +129,11 @@ export { createNoopPerformanceTracker } from '@luxexchange/sessions/src/performa
|
|
|
129
129
|
export {
|
|
130
130
|
InMemorySessionStorage,
|
|
131
131
|
InMemoryDeviceIdService,
|
|
132
|
-
|
|
132
|
+
InMemoryLxIdentifierService,
|
|
133
133
|
} from '@luxexchange/sessions/src/test-utils'
|
|
134
134
|
export {
|
|
135
135
|
createCookieJar,
|
|
136
136
|
createLocalCookieTransport,
|
|
137
137
|
} from '@luxexchange/sessions/src/test-utils/createLocalCookieTransport'
|
|
138
|
+
|
|
139
|
+
export const luxIdentifierQuery = lxIdentifierQuery
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ChallengeType } from '@
|
|
1
|
+
import { ChallengeType } from '@luxamm/client-platform-service/dist/uniswap/platformservice/v1/sessionService_pb'
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Result from initiating an OAuth flow
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
NoSolverAvailableError,
|
|
6
6
|
} from '@luxexchange/sessions/src/session-initialization/sessionErrors'
|
|
7
7
|
import type { SessionService } from '@luxexchange/sessions/src/session-service/types'
|
|
8
|
-
import type { Logger } from '
|
|
8
|
+
import type { Logger } from 'utilities/src/logger/logger'
|
|
9
9
|
|
|
10
10
|
interface SessionInitResult {
|
|
11
11
|
sessionId: string | null
|
|
@@ -61,22 +61,23 @@ function createSessionInitializationService(ctx: {
|
|
|
61
61
|
/** Analytics callbacks for tracking session initialization lifecycle */
|
|
62
62
|
analytics?: SessionInitAnalytics
|
|
63
63
|
}): SessionInitializationService {
|
|
64
|
+
const log = ctx.getLogger?.()
|
|
65
|
+
|
|
64
66
|
async function handleChallengeFlow(attemptCount = 0, flowStartTime?: number): Promise<void> {
|
|
65
67
|
const startTime = flowStartTime ?? ctx.performanceTracker.now()
|
|
66
68
|
const maxRetries = ctx.maxChallengeRetries ?? 3
|
|
67
69
|
|
|
68
70
|
const challenge = await ctx.getSessionService().requestChallenge()
|
|
69
71
|
|
|
70
|
-
|
|
72
|
+
log?.debug('createSessionInitializationService', 'handleChallengeFlow', 'Requesting challenge', {
|
|
71
73
|
challenge,
|
|
72
74
|
})
|
|
73
75
|
|
|
74
76
|
// Report challenge received (only on first attempt)
|
|
75
77
|
if (attemptCount === 0) {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
})
|
|
78
|
+
const data = { challengeType: String(challenge.challengeType), challengeId: challenge.challengeId }
|
|
79
|
+
ctx.analytics?.onChallengeReceived?.(data)
|
|
80
|
+
log?.info('sessions', 'challengeReceived', 'Challenge received', data)
|
|
80
81
|
}
|
|
81
82
|
|
|
82
83
|
// get our solver for the challenge type
|
|
@@ -99,20 +100,16 @@ function createSessionInitializationService(ctx: {
|
|
|
99
100
|
challengeData: challenge.challengeData,
|
|
100
101
|
})
|
|
101
102
|
} catch (solverError) {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
{ error: solverError, challengeType: challenge.challengeType },
|
|
109
|
-
)
|
|
103
|
+
log?.warn(
|
|
104
|
+
'createSessionInitializationService',
|
|
105
|
+
'handleChallengeFlow',
|
|
106
|
+
'Solver failed, submitting placeholder solution to trigger fallback',
|
|
107
|
+
{ error: solverError, challengeType: challenge.challengeType },
|
|
108
|
+
)
|
|
110
109
|
solution = 'solver-failed'
|
|
111
110
|
}
|
|
112
111
|
|
|
113
|
-
|
|
114
|
-
.getLogger?.()
|
|
115
|
-
.debug('createSessionInitializationService', 'handleChallengeFlow', 'Solved challenge', { solution })
|
|
112
|
+
log?.debug('createSessionInitializationService', 'handleChallengeFlow', 'Solved challenge', { solution })
|
|
116
113
|
|
|
117
114
|
// Verify session with the solution
|
|
118
115
|
const result = await ctx.getSessionService().verifySession({
|
|
@@ -121,23 +118,18 @@ function createSessionInitializationService(ctx: {
|
|
|
121
118
|
challengeType: challenge.challengeType,
|
|
122
119
|
})
|
|
123
120
|
|
|
121
|
+
const verifyData = {
|
|
122
|
+
success: !result.retry,
|
|
123
|
+
attemptNumber: attemptCount + 1,
|
|
124
|
+
totalDurationMs: ctx.performanceTracker.now() - startTime,
|
|
125
|
+
}
|
|
126
|
+
ctx.analytics?.onVerifyCompleted?.(verifyData)
|
|
127
|
+
log?.info('sessions', 'verifyCompleted', 'Verify completed', verifyData)
|
|
128
|
+
|
|
124
129
|
if (!result.retry) {
|
|
125
|
-
// Verification was successful
|
|
126
|
-
ctx.analytics?.onVerifyCompleted?.({
|
|
127
|
-
success: true,
|
|
128
|
-
attemptNumber: attemptCount + 1,
|
|
129
|
-
totalDurationMs: ctx.performanceTracker.now() - startTime,
|
|
130
|
-
})
|
|
131
130
|
return
|
|
132
131
|
}
|
|
133
132
|
|
|
134
|
-
// Report retry (verification failed but will retry)
|
|
135
|
-
ctx.analytics?.onVerifyCompleted?.({
|
|
136
|
-
success: false,
|
|
137
|
-
attemptNumber: attemptCount + 1,
|
|
138
|
-
totalDurationMs: ctx.performanceTracker.now() - startTime,
|
|
139
|
-
})
|
|
140
|
-
|
|
141
133
|
// Handle server retry request
|
|
142
134
|
if (attemptCount >= maxRetries) {
|
|
143
135
|
throw new MaxChallengeRetriesError(maxRetries, attemptCount + 1)
|
|
@@ -157,22 +149,21 @@ function createSessionInitializationService(ctx: {
|
|
|
157
149
|
needChallenge = options.needChallenge
|
|
158
150
|
sessionId = undefined
|
|
159
151
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
})
|
|
152
|
+
const data = { needChallenge, durationMs: 0 }
|
|
153
|
+
ctx.analytics?.onInitCompleted?.(data)
|
|
154
|
+
log?.info('sessions', 'initCompleted', 'Session init completed', data)
|
|
164
155
|
} else {
|
|
165
156
|
// Discover from backend
|
|
166
157
|
ctx.analytics?.onInitStarted?.()
|
|
158
|
+
log?.info('sessions', 'initStarted', 'Session init started')
|
|
167
159
|
|
|
168
160
|
const initResponse = await ctx.getSessionService().initSession()
|
|
169
161
|
needChallenge = initResponse.needChallenge
|
|
170
162
|
sessionId = initResponse.sessionId
|
|
171
163
|
|
|
172
|
-
ctx.
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
})
|
|
164
|
+
const data = { needChallenge, durationMs: ctx.performanceTracker.now() - initStartTime }
|
|
165
|
+
ctx.analytics?.onInitCompleted?.(data)
|
|
166
|
+
log?.info('sessions', 'initCompleted', 'Session init completed', data)
|
|
176
167
|
}
|
|
177
168
|
|
|
178
169
|
// Handle challenge if required and enabled
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createPromiseClient, type PromiseClient, type Transport } from '@connectrpc/connect'
|
|
2
|
-
import { SessionService } from '@
|
|
2
|
+
import { SessionService } from '@luxamm/client-platform-service/dist/uniswap/platformservice/v1/sessionService_connect'
|
|
3
3
|
|
|
4
4
|
type SessionServiceClient = PromiseClient<typeof SessionService>
|
|
5
5
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { PromiseClient } from '@connectrpc/connect'
|
|
2
|
-
import type { SessionService } from '@
|
|
2
|
+
import type { SessionService } from '@luxamm/client-platform-service/dist/uniswap/platformservice/v1/sessionService_connect'
|
|
3
3
|
import {
|
|
4
4
|
ChallengeFailure,
|
|
5
5
|
ChallengeFailure_Reason,
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
GetChallengeTypesResponse,
|
|
8
8
|
InitSessionResponse,
|
|
9
9
|
SignoutResponse,
|
|
10
|
-
} from '@
|
|
10
|
+
} from '@luxamm/client-platform-service/dist/uniswap/platformservice/v1/sessionService_pb'
|
|
11
11
|
import { createSessionRepository } from '@luxexchange/sessions/src/session-repository/createSessionRepository'
|
|
12
12
|
import { ChallengeRejectedError } from '@luxexchange/sessions/src/session-repository/errors'
|
|
13
13
|
import { ChallengeType } from '@luxexchange/sessions/src/session-service/types'
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ChallengeFailure_Reason,
|
|
3
3
|
VerifyFailure_Reason,
|
|
4
|
-
} from '@
|
|
4
|
+
} from '@luxamm/client-platform-service/dist/uniswap/platformservice/v1/sessionService_pb'
|
|
5
5
|
import type { SessionServiceClient } from '@luxexchange/sessions/src/session-repository/createSessionClient'
|
|
6
6
|
import { ChallengeRejectedError } from '@luxexchange/sessions/src/session-repository/errors'
|
|
7
7
|
import type { SessionRepository, TypedChallengeData } from '@luxexchange/sessions/src/session-repository/types'
|
|
8
8
|
import { ChallengeFailureReason, VerifyFailureReason } from '@luxexchange/sessions/src/session-repository/types'
|
|
9
|
-
import type { Logger } from '
|
|
9
|
+
import type { Logger } from 'utilities/src/logger/logger'
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Creates a session repository that handles communication with the session service.
|
|
13
13
|
* This is the layer that makes actual API calls to the backend.
|
|
14
14
|
*
|
|
15
|
-
* TODO(proto): `VerifyResponse` in `@
|
|
15
|
+
* TODO(proto): `VerifyResponse` in `@luxamm/client-platform-service` still has a proto3
|
|
16
16
|
* issue where an empty `VerifySuccess` message gets silently dropped, leaving
|
|
17
17
|
* `outcome.case === undefined`. The `verifySession()` method works around this by using
|
|
18
18
|
* the `retry` flag as a discriminator.
|
|
@@ -23,7 +23,7 @@ import type { Logger } from '@luxfi/utilities/src/logger/logger'
|
|
|
23
23
|
function createSessionRepository(ctx: { client: SessionServiceClient; getLogger?: () => Logger }): SessionRepository {
|
|
24
24
|
const initSession: SessionRepository['initSession'] = async () => {
|
|
25
25
|
try {
|
|
26
|
-
const response = await ctx.client
|
|
26
|
+
const response = await ctx.client.initSession({})
|
|
27
27
|
|
|
28
28
|
return {
|
|
29
29
|
sessionId: response.sessionId,
|
|
@@ -39,7 +39,7 @@ function createSessionRepository(ctx: { client: SessionServiceClient; getLogger?
|
|
|
39
39
|
|
|
40
40
|
const challenge: SessionRepository['challenge'] = async (request) => {
|
|
41
41
|
try {
|
|
42
|
-
const response = await ctx.client
|
|
42
|
+
const response = await ctx.client.challenge({
|
|
43
43
|
challengeType: request.challengeType,
|
|
44
44
|
identifier: request.identifier,
|
|
45
45
|
})
|
|
@@ -140,7 +140,7 @@ function createSessionRepository(ctx: { client: SessionServiceClient; getLogger?
|
|
|
140
140
|
|
|
141
141
|
const verifySession: SessionRepository['verifySession'] = async (request) => {
|
|
142
142
|
try {
|
|
143
|
-
const response = await ctx.client
|
|
143
|
+
const response = await ctx.client.verify({
|
|
144
144
|
solution: request.solution,
|
|
145
145
|
challengeId: request.challengeId,
|
|
146
146
|
type: request.challengeType,
|
|
@@ -209,7 +209,7 @@ function createSessionRepository(ctx: { client: SessionServiceClient; getLogger?
|
|
|
209
209
|
const deleteSession: SessionRepository['deleteSession'] = async () => {
|
|
210
210
|
try {
|
|
211
211
|
// Proto renamed deleteSession to signout
|
|
212
|
-
await ctx.client
|
|
212
|
+
await ctx.client.signout({})
|
|
213
213
|
return {}
|
|
214
214
|
} catch (error) {
|
|
215
215
|
const errorMessage = error instanceof Error ? error.message : String(error)
|
|
@@ -219,10 +219,10 @@ function createSessionRepository(ctx: { client: SessionServiceClient; getLogger?
|
|
|
219
219
|
|
|
220
220
|
const getChallengeTypes: SessionRepository['getChallengeTypes'] = async () => {
|
|
221
221
|
try {
|
|
222
|
-
const response = await ctx.client
|
|
223
|
-
return response.challengeTypeConfig.map((
|
|
224
|
-
type:
|
|
225
|
-
config:
|
|
222
|
+
const response = await ctx.client.getChallengeTypes({})
|
|
223
|
+
return response.challengeTypeConfig.map((config) => ({
|
|
224
|
+
type: config.type,
|
|
225
|
+
config: config.config,
|
|
226
226
|
}))
|
|
227
227
|
} catch (error) {
|
|
228
228
|
const errorMessage = error instanceof Error ? error.message : String(error)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ChallengeType } from '@
|
|
1
|
+
import { ChallengeType } from '@luxamm/client-platform-service/dist/uniswap/platformservice/v1/sessionService_pb'
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Typed challenge data for Turnstile bot detection
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { ChallengeType } from '@
|
|
2
|
-
import type { SessionService } from '@
|
|
1
|
+
import { ChallengeType } from '@luxamm/client-platform-service/dist/uniswap/platformservice/v1/sessionService_pb'
|
|
2
|
+
import type { SessionService } from '@luxexchange/sessions/src/session-service/types'
|
|
3
3
|
|
|
4
4
|
function createNoopSessionService(): SessionService {
|
|
5
5
|
const initSession: SessionService['initSession'] = async () => ({ needChallenge: false, extra: {} })
|