@aurabase/aurabase-js 0.3.0 → 0.3.1
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 +4 -4
- package/packages/ai/node_modules/.bin/esbuild +0 -19
- package/packages/ai/node_modules/.bin/tsc +0 -22
- package/packages/ai/node_modules/.bin/tsserver +0 -22
- package/packages/ai/node_modules/.bin/tsup +0 -22
- package/packages/ai/node_modules/.bin/tsup-node +0 -22
- package/packages/ai/node_modules/.bin/vite +0 -22
- package/packages/ai/node_modules/.bin/vitest +0 -22
- package/packages/ai/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +0 -1
- package/packages/ai/src/AiService.ts +0 -226
- package/packages/ai/src/index.ts +0 -18
- package/packages/ai/src/sse.ts +0 -141
- package/packages/ai/src/types.ts +0 -30
- package/packages/ai/tests/chat-stream.test.ts +0 -151
- package/packages/ai/tests/rag-namespaces.test.ts +0 -54
- package/packages/ai/tests/sse.test.ts +0 -69
- package/packages/ai/tsconfig.json +0 -5
- package/packages/ai/tsup.config.ts +0 -11
- package/packages/aurabase/node_modules/.bin/esbuild +0 -19
- package/packages/aurabase/node_modules/.bin/tsc +0 -22
- package/packages/aurabase/node_modules/.bin/tsserver +0 -22
- package/packages/aurabase/node_modules/.bin/tsup +0 -22
- package/packages/aurabase/node_modules/.bin/tsup-node +0 -22
- package/packages/aurabase/node_modules/.bin/vite +0 -22
- package/packages/aurabase/node_modules/.bin/vitest +0 -22
- package/packages/aurabase/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +0 -1
- package/packages/aurabase/src/AuraClient.ts +0 -237
- package/packages/aurabase/src/index.ts +0 -152
- package/packages/aurabase/src/ssr.ts +0 -156
- package/packages/aurabase/tests/ai-streaming-rag-e2e.test.ts +0 -82
- package/packages/aurabase/tests/ai.test.ts +0 -111
- package/packages/aurabase/tests/auth-admin.test.ts +0 -515
- package/packages/aurabase/tests/auth-e2e.test.ts +0 -135
- package/packages/aurabase/tests/auth-hardening.test.ts +0 -206
- package/packages/aurabase/tests/auth.test.ts +0 -947
- package/packages/aurabase/tests/database.test.ts +0 -230
- package/packages/aurabase/tests/db-types-e2e.test.ts +0 -217
- package/packages/aurabase/tests/dispose.test.ts +0 -23
- package/packages/aurabase/tests/foreign-token.e2e.test.ts +0 -129
- package/packages/aurabase/tests/functions.test.ts +0 -107
- package/packages/aurabase/tests/integration.test.ts +0 -413
- package/packages/aurabase/tests/live-production-validation.js +0 -241
- package/packages/aurabase/tests/live-sdk-production-validation.js +0 -293
- package/packages/aurabase/tests/mocks.ts +0 -139
- package/packages/aurabase/tests/notifications.test.ts +0 -314
- package/packages/aurabase/tests/observability-backup.test.ts +0 -186
- package/packages/aurabase/tests/observability-hook.test.ts +0 -130
- package/packages/aurabase/tests/production-robustness.test.ts +0 -268
- package/packages/aurabase/tests/public-api-surface.test.ts +0 -53
- package/packages/aurabase/tests/query-builder.test.ts +0 -329
- package/packages/aurabase/tests/readme-smoke-e2e.test.ts +0 -231
- package/packages/aurabase/tests/realtime-filter-e2e.test.ts +0 -344
- package/packages/aurabase/tests/refresh-locks.test.ts +0 -210
- package/packages/aurabase/tests/retry-option.test.ts +0 -17
- package/packages/aurabase/tests/rpc-e2e.test.ts +0 -254
- package/packages/aurabase/tests/rs256-local-e2e.test.ts +0 -114
- package/packages/aurabase/tests/rt-alias-public-e2e.test.ts +0 -235
- package/packages/aurabase/tests/rt-http-broadcast-e2e.test.ts +0 -124
- package/packages/aurabase/tests/service-role-guard.test.ts +0 -99
- package/packages/aurabase/tests/ssr.test.ts +0 -91
- package/packages/aurabase/tests/storage-backend-e2e.test.ts +0 -481
- package/packages/aurabase/tests/storage-sdk-parity-e2e.test.ts +0 -104
- package/packages/aurabase/tests/storage-transform-e2e.test.ts +0 -684
- package/packages/aurabase/tests/storage.test.ts +0 -55
- package/packages/aurabase/tests/types/client-generic.test-d.ts +0 -79
- package/packages/aurabase/tests/types/docs-snippets.test-d.ts +0 -571
- package/packages/aurabase/tests/types/error-code.test-d.ts +0 -53
- package/packages/aurabase/tsconfig.json +0 -5
- package/packages/aurabase/tsconfig.test-d.json +0 -5
- package/packages/aurabase/tsup.config.ts +0 -11
- package/packages/aurabase/vitest.config.ts +0 -16
- package/packages/auth/node_modules/.bin/esbuild +0 -19
- package/packages/auth/node_modules/.bin/tsc +0 -22
- package/packages/auth/node_modules/.bin/tsserver +0 -22
- package/packages/auth/node_modules/.bin/tsup +0 -22
- package/packages/auth/node_modules/.bin/tsup-node +0 -22
- package/packages/auth/node_modules/.bin/vite +0 -22
- package/packages/auth/node_modules/.bin/vitest +0 -22
- package/packages/auth/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +0 -1
- package/packages/auth/src/AuthAdminService.ts +0 -149
- package/packages/auth/src/AuthService.ts +0 -1166
- package/packages/auth/src/SessionManager.ts +0 -92
- package/packages/auth/src/index.ts +0 -17
- package/packages/auth/src/jwks.ts +0 -337
- package/packages/auth/src/pkce.ts +0 -27
- package/packages/auth/src/types.ts +0 -89
- package/packages/auth/tests/auth-lifecycle.test.ts +0 -149
- package/packages/auth/tests/detect-session.test.ts +0 -361
- package/packages/auth/tests/getclaims.test.ts +0 -780
- package/packages/auth/tests/is-mfa-challenge.test.ts +0 -27
- package/packages/auth/tests/password-recovery.test.ts +0 -124
- package/packages/auth/tests/pkce.test.ts +0 -192
- package/packages/auth/tests/session-manager.test.ts +0 -103
- package/packages/auth/tests/set-session.test.ts +0 -139
- package/packages/auth/tests/verify-otp.test.ts +0 -153
- package/packages/auth/tsconfig.json +0 -5
- package/packages/auth/tsup.config.ts +0 -11
- package/packages/core/node_modules/.bin/esbuild +0 -22
- package/packages/core/node_modules/.bin/tsc +0 -22
- package/packages/core/node_modules/.bin/tsserver +0 -22
- package/packages/core/node_modules/.bin/tsup +0 -22
- package/packages/core/node_modules/.bin/tsup-node +0 -22
- package/packages/core/node_modules/.bin/vite +0 -22
- package/packages/core/node_modules/.bin/vitest +0 -22
- package/packages/core/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +0 -1
- package/packages/core/src/AuraError.ts +0 -89
- package/packages/core/src/BaseService.ts +0 -44
- package/packages/core/src/client.ts +0 -34
- package/packages/core/src/cookie-utils.ts +0 -42
- package/packages/core/src/fetch.ts +0 -435
- package/packages/core/src/index.ts +0 -22
- package/packages/core/src/retry.ts +0 -63
- package/packages/core/src/serialize.ts +0 -6
- package/packages/core/src/stores/BaseAuthStore.ts +0 -164
- package/packages/core/src/stores/LocalAuthStore.ts +0 -199
- package/packages/core/src/types.ts +0 -1042
- package/packages/core/tests/auth-store.test.ts +0 -300
- package/packages/core/tests/error-code.test.ts +0 -61
- package/packages/core/tests/error.test.ts +0 -24
- package/packages/core/tests/fetch.test.ts +0 -286
- package/packages/core/tests/mocks.ts +0 -139
- package/packages/core/tests/observability.test.ts +0 -86
- package/packages/core/tests/refresh-hardening.test.ts +0 -164
- package/packages/core/tests/refresh-observability.test.ts +0 -111
- package/packages/core/tests/retry.test.ts +0 -106
- package/packages/core/tests/serialize.test.ts +0 -12
- package/packages/core/tests/timeout.test.ts +0 -79
- package/packages/core/tsconfig.json +0 -5
- package/packages/core/tsup.config.ts +0 -11
- package/packages/db/node_modules/.bin/esbuild +0 -19
- package/packages/db/node_modules/.bin/tsc +0 -22
- package/packages/db/node_modules/.bin/tsserver +0 -22
- package/packages/db/node_modules/.bin/tsup +0 -22
- package/packages/db/node_modules/.bin/tsup-node +0 -22
- package/packages/db/node_modules/.bin/vite +0 -22
- package/packages/db/node_modules/.bin/vitest +0 -22
- package/packages/db/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +0 -1
- package/packages/db/src/DatabaseService.ts +0 -170
- package/packages/db/src/QueryBuilder.ts +0 -830
- package/packages/db/src/index.ts +0 -2
- package/packages/db/src/pgrst-types/common/common.ts +0 -86
- package/packages/db/src/pgrst-types/common/rpc.ts +0 -151
- package/packages/db/src/pgrst-types/feature-flags.ts +0 -20
- package/packages/db/src/pgrst-types/types.ts +0 -134
- package/packages/db/src/select-query-parser/parser.ts +0 -479
- package/packages/db/src/select-query-parser/result.ts +0 -553
- package/packages/db/src/select-query-parser/types.ts +0 -132
- package/packages/db/src/select-query-parser/utils.ts +0 -707
- package/packages/db/tests/filters.test.ts +0 -81
- package/packages/db/tests/mutations-filtered.e2e.test.ts +0 -132
- package/packages/db/tests/mutations-filtered.test.ts +0 -188
- package/packages/db/tests/order.test.ts +0 -45
- package/packages/db/tests/rpc.test.ts +0 -41
- package/packages/db/tests/scale/build-large-schema.ts +0 -94
- package/packages/db/tests/scale/scale-compile.test.ts +0 -167
- package/packages/db/tests/schema.test.ts +0 -77
- package/packages/db/tests/single-accept.e2e.test.ts +0 -123
- package/packages/db/tests/single.test.ts +0 -211
- package/packages/db/tests/types/filters.test-d.ts +0 -52
- package/packages/db/tests/types/fixtures.ts +0 -40
- package/packages/db/tests/types/from-views.test-d.ts +0 -18
- package/packages/db/tests/types/mutations.test-d.ts +0 -23
- package/packages/db/tests/types/rpc.test-d.ts +0 -60
- package/packages/db/tests/types/schema-shape.test-d.ts +0 -8
- package/packages/db/tests/types/select-inference.test-d.ts +0 -38
- package/packages/db/tests/vendored/fixtures.ts +0 -83
- package/packages/db/tests/vendored/get-result.test-d.ts +0 -75
- package/packages/db/tsconfig.json +0 -5
- package/packages/db/tsconfig.test-d.json +0 -5
- package/packages/db/tsup.config.ts +0 -11
- package/packages/db/vitest.config.ts +0 -8
- package/packages/functions/node_modules/.bin/esbuild +0 -19
- package/packages/functions/node_modules/.bin/tsc +0 -22
- package/packages/functions/node_modules/.bin/tsserver +0 -22
- package/packages/functions/node_modules/.bin/tsup +0 -22
- package/packages/functions/node_modules/.bin/tsup-node +0 -22
- package/packages/functions/node_modules/.bin/vite +0 -22
- package/packages/functions/node_modules/.bin/vitest +0 -22
- package/packages/functions/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +0 -1
- package/packages/functions/src/FunctionsService.ts +0 -188
- package/packages/functions/src/errors.ts +0 -70
- package/packages/functions/src/index.ts +0 -6
- package/packages/functions/tests/invoke.test.ts +0 -97
- package/packages/functions/tests/response-type-errors.test.ts +0 -135
- package/packages/functions/tsconfig.json +0 -5
- package/packages/functions/tsup.config.ts +0 -11
- package/packages/gen/node_modules/.bin/esbuild +0 -19
- package/packages/gen/node_modules/.bin/tsc +0 -22
- package/packages/gen/node_modules/.bin/tsserver +0 -22
- package/packages/gen/node_modules/.bin/tsup +0 -22
- package/packages/gen/node_modules/.bin/tsup-node +0 -22
- package/packages/gen/node_modules/.bin/vite +0 -22
- package/packages/gen/node_modules/.bin/vitest +0 -22
- package/packages/gen/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +0 -1
- package/packages/gen/src/cli.ts +0 -67
- package/packages/gen/src/generate.ts +0 -0
- package/packages/gen/src/index.ts +0 -2
- package/packages/gen/tests/compile.test.ts +0 -213
- package/packages/gen/tests/e2e.test.ts +0 -130
- package/packages/gen/tests/generate.test.ts +0 -396
- package/packages/gen/tsconfig.json +0 -5
- package/packages/gen/tsup.config.ts +0 -11
- package/packages/notifications/node_modules/.bin/esbuild +0 -19
- package/packages/notifications/node_modules/.bin/tsc +0 -22
- package/packages/notifications/node_modules/.bin/tsserver +0 -22
- package/packages/notifications/node_modules/.bin/tsup +0 -22
- package/packages/notifications/node_modules/.bin/tsup-node +0 -22
- package/packages/notifications/node_modules/.bin/vite +0 -22
- package/packages/notifications/node_modules/.bin/vitest +0 -22
- package/packages/notifications/src/NotificationsService.ts +0 -230
- package/packages/notifications/src/index.ts +0 -19
- package/packages/notifications/tsconfig.json +0 -5
- package/packages/notifications/tsup.config.ts +0 -11
- package/packages/realtime/node_modules/.bin/esbuild +0 -19
- package/packages/realtime/node_modules/.bin/tsc +0 -22
- package/packages/realtime/node_modules/.bin/tsserver +0 -22
- package/packages/realtime/node_modules/.bin/tsup +0 -22
- package/packages/realtime/node_modules/.bin/tsup-node +0 -22
- package/packages/realtime/node_modules/.bin/vite +0 -22
- package/packages/realtime/node_modules/.bin/vitest +0 -22
- package/packages/realtime/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +0 -1
- package/packages/realtime/src/AuraChannel.ts +0 -485
- package/packages/realtime/src/HeartbeatManager.ts +0 -73
- package/packages/realtime/src/RealtimeService.ts +0 -505
- package/packages/realtime/src/columnFilter.ts +0 -301
- package/packages/realtime/src/index.ts +0 -4
- package/packages/realtime/tests/ack-routing.test.ts +0 -81
- package/packages/realtime/tests/column-filter.test.ts +0 -144
- package/packages/realtime/tests/dispatch.test.ts +0 -191
- package/packages/realtime/tests/heartbeat.test.ts +0 -67
- package/packages/realtime/tests/http-broadcast.test.ts +0 -68
- package/packages/realtime/tests/realtime-token.test.ts +0 -43
- package/packages/realtime/tests/reconnect-race.test.ts +0 -149
- package/packages/realtime/tests/ref-id.test.ts +0 -34
- package/packages/realtime/tests/set-auth.test.ts +0 -70
- package/packages/realtime/tsconfig.json +0 -5
- package/packages/realtime/tsup.config.ts +0 -11
- package/packages/storage/node_modules/.bin/esbuild +0 -19
- package/packages/storage/node_modules/.bin/tsc +0 -22
- package/packages/storage/node_modules/.bin/tsserver +0 -22
- package/packages/storage/node_modules/.bin/tsup +0 -22
- package/packages/storage/node_modules/.bin/tsup-node +0 -22
- package/packages/storage/node_modules/.bin/vite +0 -22
- package/packages/storage/node_modules/.bin/vitest +0 -22
- package/packages/storage/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +0 -1
- package/packages/storage/src/DownloadBuilder.ts +0 -60
- package/packages/storage/src/StorageService.ts +0 -323
- package/packages/storage/src/index.ts +0 -2
- package/packages/storage/src/path.ts +0 -35
- package/packages/storage/src/transform.ts +0 -15
- package/packages/storage/tests/download.test.ts +0 -64
- package/packages/storage/tests/parity.test.ts +0 -154
- package/packages/storage/tests/path.test.ts +0 -87
- package/packages/storage/tests/transform.test.ts +0 -79
- package/packages/storage/tsconfig.json +0 -5
- package/packages/storage/tsup.config.ts +0 -11
- package/pnpm-workspace.yaml +0 -24
- package/tsconfig.base.json +0 -15
|
@@ -1,300 +0,0 @@
|
|
|
1
|
-
// ---------------------------------------------------------------------------
|
|
2
|
-
// BaseAuthStore + LocalAuthStore tests
|
|
3
|
-
// ---------------------------------------------------------------------------
|
|
4
|
-
|
|
5
|
-
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'
|
|
6
|
-
import { BaseAuthStore, isTokenExpired } from '../src/stores/BaseAuthStore'
|
|
7
|
-
import { LocalAuthStore } from '../src/stores/LocalAuthStore'
|
|
8
|
-
import { fakeUser, fakeJwt, validJwt, expiredJwt } from './mocks'
|
|
9
|
-
|
|
10
|
-
// ---------------------------------------------------------------------------
|
|
11
|
-
// BaseAuthStore
|
|
12
|
-
// ---------------------------------------------------------------------------
|
|
13
|
-
|
|
14
|
-
describe('BaseAuthStore', () => {
|
|
15
|
-
let store: BaseAuthStore
|
|
16
|
-
|
|
17
|
-
beforeEach(() => {
|
|
18
|
-
store = new BaseAuthStore()
|
|
19
|
-
})
|
|
20
|
-
|
|
21
|
-
it('starts with null token/user', () => {
|
|
22
|
-
expect(store.token).toBeNull()
|
|
23
|
-
expect(store.refreshToken).toBeNull()
|
|
24
|
-
expect(store.user).toBeNull()
|
|
25
|
-
})
|
|
26
|
-
|
|
27
|
-
it('save() stores token, refreshToken and user', () => {
|
|
28
|
-
const user = fakeUser()
|
|
29
|
-
store.save('tok_1', 'rt_1', user)
|
|
30
|
-
|
|
31
|
-
expect(store.token).toBe('tok_1')
|
|
32
|
-
expect(store.refreshToken).toBe('rt_1')
|
|
33
|
-
expect(store.user).toEqual(user)
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
it('clear() resets to null', () => {
|
|
37
|
-
store.save('tok_1', 'rt_1', fakeUser())
|
|
38
|
-
store.clear()
|
|
39
|
-
|
|
40
|
-
expect(store.token).toBeNull()
|
|
41
|
-
expect(store.refreshToken).toBeNull()
|
|
42
|
-
expect(store.user).toBeNull()
|
|
43
|
-
})
|
|
44
|
-
|
|
45
|
-
it('onChange fires callback on save and clear', () => {
|
|
46
|
-
const events: Array<{ token: string | null; user: unknown }> = []
|
|
47
|
-
store.onChange((token, user) => {
|
|
48
|
-
events.push({ token, user })
|
|
49
|
-
})
|
|
50
|
-
|
|
51
|
-
const user = fakeUser()
|
|
52
|
-
store.save('tok_1', 'rt_1', user)
|
|
53
|
-
store.clear()
|
|
54
|
-
|
|
55
|
-
expect(events).toHaveLength(2)
|
|
56
|
-
expect(events[0].token).toBe('tok_1')
|
|
57
|
-
expect(events[1].token).toBeNull()
|
|
58
|
-
})
|
|
59
|
-
|
|
60
|
-
it('unsubscribe stops receiving events', () => {
|
|
61
|
-
const events: string[] = []
|
|
62
|
-
const unsub = store.onChange((token) => {
|
|
63
|
-
events.push(token ?? 'null')
|
|
64
|
-
})
|
|
65
|
-
|
|
66
|
-
store.save('tok_1', 'rt_1', fakeUser())
|
|
67
|
-
expect(events).toHaveLength(1)
|
|
68
|
-
|
|
69
|
-
unsub()
|
|
70
|
-
store.save('tok_2', 'rt_2', fakeUser())
|
|
71
|
-
// Should still be 1 since we unsubscribed
|
|
72
|
-
expect(events).toHaveLength(1)
|
|
73
|
-
})
|
|
74
|
-
|
|
75
|
-
it('isValid returns true for a non-expired JWT', () => {
|
|
76
|
-
store.save(validJwt(), 'rt', fakeUser())
|
|
77
|
-
expect(store.isValid).toBe(true)
|
|
78
|
-
})
|
|
79
|
-
|
|
80
|
-
it('isValid returns false for an expired JWT', () => {
|
|
81
|
-
store.save(expiredJwt(), 'rt', fakeUser())
|
|
82
|
-
expect(store.isValid).toBe(false)
|
|
83
|
-
})
|
|
84
|
-
|
|
85
|
-
it('isValid returns false when no token is set', () => {
|
|
86
|
-
expect(store.isValid).toBe(false)
|
|
87
|
-
})
|
|
88
|
-
|
|
89
|
-
it('subscriber errors do not break the store', () => {
|
|
90
|
-
store.onChange(() => {
|
|
91
|
-
throw new Error('subscriber boom')
|
|
92
|
-
})
|
|
93
|
-
const events: string[] = []
|
|
94
|
-
store.onChange((token) => events.push(token ?? 'null'))
|
|
95
|
-
|
|
96
|
-
// Should not throw
|
|
97
|
-
store.save('tok_1', 'rt_1', fakeUser())
|
|
98
|
-
expect(events).toHaveLength(1)
|
|
99
|
-
expect(events[0]).toBe('tok_1')
|
|
100
|
-
})
|
|
101
|
-
})
|
|
102
|
-
|
|
103
|
-
// ---------------------------------------------------------------------------
|
|
104
|
-
// isTokenExpired
|
|
105
|
-
// ---------------------------------------------------------------------------
|
|
106
|
-
|
|
107
|
-
describe('isTokenExpired', () => {
|
|
108
|
-
it('returns false for a future-exp token', () => {
|
|
109
|
-
const future = fakeJwt(Math.floor(Date.now() / 1000) + 3600)
|
|
110
|
-
expect(isTokenExpired(future)).toBe(false)
|
|
111
|
-
})
|
|
112
|
-
|
|
113
|
-
it('returns true for a past-exp token', () => {
|
|
114
|
-
const past = fakeJwt(Math.floor(Date.now() / 1000) - 60)
|
|
115
|
-
expect(isTokenExpired(past)).toBe(true)
|
|
116
|
-
})
|
|
117
|
-
|
|
118
|
-
it('respects margin parameter', () => {
|
|
119
|
-
// Token expires in 10 seconds, but margin is 30 -- should be "expired"
|
|
120
|
-
const almostExpired = fakeJwt(Math.floor(Date.now() / 1000) + 10)
|
|
121
|
-
expect(isTokenExpired(almostExpired, 30)).toBe(true)
|
|
122
|
-
})
|
|
123
|
-
|
|
124
|
-
it('returns true for malformed tokens', () => {
|
|
125
|
-
expect(isTokenExpired('not-a-jwt')).toBe(true)
|
|
126
|
-
expect(isTokenExpired('')).toBe(true)
|
|
127
|
-
expect(isTokenExpired('a.b')).toBe(true)
|
|
128
|
-
})
|
|
129
|
-
})
|
|
130
|
-
|
|
131
|
-
// ---------------------------------------------------------------------------
|
|
132
|
-
// LocalAuthStore (mocked localStorage)
|
|
133
|
-
// ---------------------------------------------------------------------------
|
|
134
|
-
|
|
135
|
-
describe('LocalAuthStore', () => {
|
|
136
|
-
let mockStorage: Record<string, string>
|
|
137
|
-
|
|
138
|
-
beforeEach(() => {
|
|
139
|
-
mockStorage = {}
|
|
140
|
-
// Mock localStorage
|
|
141
|
-
const storage = {
|
|
142
|
-
getItem: vi.fn((key: string) => mockStorage[key] ?? null),
|
|
143
|
-
setItem: vi.fn((key: string, value: string) => {
|
|
144
|
-
mockStorage[key] = value
|
|
145
|
-
}),
|
|
146
|
-
removeItem: vi.fn((key: string) => {
|
|
147
|
-
delete mockStorage[key]
|
|
148
|
-
}),
|
|
149
|
-
clear: vi.fn(() => {
|
|
150
|
-
mockStorage = {}
|
|
151
|
-
}),
|
|
152
|
-
get length() {
|
|
153
|
-
return Object.keys(mockStorage).length
|
|
154
|
-
},
|
|
155
|
-
key: vi.fn((index: number) => Object.keys(mockStorage)[index] ?? null),
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
Object.defineProperty(globalThis, 'localStorage', {
|
|
159
|
-
value: storage,
|
|
160
|
-
writable: true,
|
|
161
|
-
configurable: true,
|
|
162
|
-
})
|
|
163
|
-
})
|
|
164
|
-
|
|
165
|
-
afterEach(() => {
|
|
166
|
-
// Clean up
|
|
167
|
-
delete (globalThis as any).localStorage
|
|
168
|
-
})
|
|
169
|
-
|
|
170
|
-
it('persists to localStorage on save', () => {
|
|
171
|
-
const store = new LocalAuthStore()
|
|
172
|
-
store.save('tok_1', 'rt_1', fakeUser())
|
|
173
|
-
|
|
174
|
-
const raw = mockStorage['aurabase_auth']
|
|
175
|
-
expect(raw).toBeDefined()
|
|
176
|
-
const parsed = JSON.parse(raw)
|
|
177
|
-
expect(parsed.token).toBe('tok_1')
|
|
178
|
-
expect(parsed.refreshToken).toBe('rt_1')
|
|
179
|
-
expect(parsed.user.id).toBe('user-1')
|
|
180
|
-
})
|
|
181
|
-
|
|
182
|
-
it('clears localStorage on clear()', () => {
|
|
183
|
-
const store = new LocalAuthStore()
|
|
184
|
-
store.save('tok_1', 'rt_1', fakeUser())
|
|
185
|
-
expect(mockStorage['aurabase_auth']).toBeDefined()
|
|
186
|
-
|
|
187
|
-
store.clear()
|
|
188
|
-
expect(mockStorage['aurabase_auth']).toBeUndefined()
|
|
189
|
-
})
|
|
190
|
-
|
|
191
|
-
it('loads from localStorage on construction', () => {
|
|
192
|
-
// Pre-populate storage
|
|
193
|
-
mockStorage['aurabase_auth'] = JSON.stringify({
|
|
194
|
-
token: 'tok_pre',
|
|
195
|
-
refreshToken: 'rt_pre',
|
|
196
|
-
user: fakeUser({ email: 'stored@example.com' }),
|
|
197
|
-
})
|
|
198
|
-
|
|
199
|
-
const store = new LocalAuthStore()
|
|
200
|
-
|
|
201
|
-
expect(store.token).toBe('tok_pre')
|
|
202
|
-
expect(store.refreshToken).toBe('rt_pre')
|
|
203
|
-
expect(store.user?.email).toBe('stored@example.com')
|
|
204
|
-
})
|
|
205
|
-
|
|
206
|
-
it('uses custom key', () => {
|
|
207
|
-
const store = new LocalAuthStore('custom_key')
|
|
208
|
-
store.save('tok_1', 'rt_1', fakeUser())
|
|
209
|
-
|
|
210
|
-
expect(mockStorage['custom_key']).toBeDefined()
|
|
211
|
-
expect(mockStorage['aurabase_auth']).toBeUndefined()
|
|
212
|
-
})
|
|
213
|
-
|
|
214
|
-
it('handles corrupted localStorage gracefully', () => {
|
|
215
|
-
mockStorage['aurabase_auth'] = 'not valid json {'
|
|
216
|
-
|
|
217
|
-
// Should not throw
|
|
218
|
-
const store = new LocalAuthStore()
|
|
219
|
-
expect(store.token).toBeNull()
|
|
220
|
-
})
|
|
221
|
-
|
|
222
|
-
it('exportToCookie produces valid Set-Cookie string', () => {
|
|
223
|
-
const store = new LocalAuthStore()
|
|
224
|
-
store.save('tok_1', 'rt_1', fakeUser())
|
|
225
|
-
|
|
226
|
-
const cookie = store.exportToCookie({
|
|
227
|
-
path: '/',
|
|
228
|
-
secure: true,
|
|
229
|
-
sameSite: 'Lax',
|
|
230
|
-
maxAge: 86400,
|
|
231
|
-
})
|
|
232
|
-
|
|
233
|
-
expect(cookie).toContain('aurabase_auth=')
|
|
234
|
-
expect(cookie).toContain('Path=/')
|
|
235
|
-
expect(cookie).toContain('Secure')
|
|
236
|
-
expect(cookie).toContain('SameSite=Lax')
|
|
237
|
-
expect(cookie).toContain('Max-Age=86400')
|
|
238
|
-
})
|
|
239
|
-
|
|
240
|
-
it('LOT 3 (I8) : setItem qui throw (quota) émet storage-blocked sans casser save()', () => {
|
|
241
|
-
const store = new LocalAuthStore()
|
|
242
|
-
const events: Array<{ kind: string; op?: string }> = []
|
|
243
|
-
store.setObservabilityHook((e) => events.push(e as { kind: string; op?: string }), false)
|
|
244
|
-
|
|
245
|
-
const original = (globalThis as any).localStorage.setItem
|
|
246
|
-
;(globalThis as any).localStorage.setItem = vi.fn(() => {
|
|
247
|
-
throw new Error('QuotaExceededError')
|
|
248
|
-
})
|
|
249
|
-
|
|
250
|
-
// save() ne throw jamais malgré le localStorage bloqué.
|
|
251
|
-
expect(() => store.save('tok_1', 'rt_1', fakeUser())).not.toThrow()
|
|
252
|
-
expect(store.token).toBe('tok_1') // état en mémoire toujours à jour
|
|
253
|
-
|
|
254
|
-
// save() persiste via `_persist()` (op 'persist'), pas via le `setItem` public
|
|
255
|
-
// override (réservé au stockage clé/valeur générique — PKCE `code_verifier`).
|
|
256
|
-
expect(events).toContainEqual({ kind: 'storage-blocked', op: 'persist' })
|
|
257
|
-
|
|
258
|
-
;(globalThis as any).localStorage.setItem = original
|
|
259
|
-
})
|
|
260
|
-
|
|
261
|
-
it('LOT 3 (I8) : setItem (générique, ex. PKCE) qui throw émet storage-blocked op:"setItem"', () => {
|
|
262
|
-
const store = new LocalAuthStore()
|
|
263
|
-
const events: Array<{ kind: string; op?: string }> = []
|
|
264
|
-
store.setObservabilityHook((e) => events.push(e as { kind: string; op?: string }), false)
|
|
265
|
-
|
|
266
|
-
const original = (globalThis as any).localStorage.setItem
|
|
267
|
-
;(globalThis as any).localStorage.setItem = vi.fn(() => {
|
|
268
|
-
throw new Error('QuotaExceededError')
|
|
269
|
-
})
|
|
270
|
-
|
|
271
|
-
expect(() => store.setItem('some-key', 'some-value')).not.toThrow()
|
|
272
|
-
expect(events).toContainEqual({ kind: 'storage-blocked', op: 'setItem' })
|
|
273
|
-
|
|
274
|
-
;(globalThis as any).localStorage.setItem = original
|
|
275
|
-
})
|
|
276
|
-
|
|
277
|
-
it('LOT 3 (I8) : sans hook câblé, aucun throw / no-op silencieux', () => {
|
|
278
|
-
const store = new LocalAuthStore()
|
|
279
|
-
;(globalThis as any).localStorage.setItem = vi.fn(() => {
|
|
280
|
-
throw new Error('blocked')
|
|
281
|
-
})
|
|
282
|
-
expect(() => store.save('tok_1', 'rt_1', fakeUser())).not.toThrow()
|
|
283
|
-
})
|
|
284
|
-
|
|
285
|
-
it('loadFromCookie restores auth state', () => {
|
|
286
|
-
const store = new LocalAuthStore()
|
|
287
|
-
const data = {
|
|
288
|
-
token: 'tok_cookie',
|
|
289
|
-
refreshToken: 'rt_cookie',
|
|
290
|
-
user: fakeUser({ email: 'cookie@example.com' }),
|
|
291
|
-
}
|
|
292
|
-
const cookieString = `other=val; aurabase_auth=${encodeURIComponent(JSON.stringify(data))}; foo=bar`
|
|
293
|
-
|
|
294
|
-
store.loadFromCookie(cookieString)
|
|
295
|
-
|
|
296
|
-
expect(store.token).toBe('tok_cookie')
|
|
297
|
-
expect(store.refreshToken).toBe('rt_cookie')
|
|
298
|
-
expect(store.user?.email).toBe('cookie@example.com')
|
|
299
|
-
})
|
|
300
|
-
})
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
// ---------------------------------------------------------------------------
|
|
2
|
-
// AuraErrorCode (LOT 3, finding I4) -- taxonomie d'erreurs typée
|
|
3
|
-
// ---------------------------------------------------------------------------
|
|
4
|
-
|
|
5
|
-
// NOTE : le test type-level proprement dit (vérifié par `tsc`, pas seulement par
|
|
6
|
-
// vitest qui transpile/strip les types) vit dans
|
|
7
|
-
// `packages/aurabase/tests/types/error-code.test-d.ts` (chaîné à `pnpm --filter
|
|
8
|
-
// aurabase test` via `tsconfig.test-d.json`). Ici : couverture RUNTIME uniquement.
|
|
9
|
-
import { describe, it, expect } from 'vitest'
|
|
10
|
-
import { AuraError, type AuraErrorCode } from '../src/AuraError'
|
|
11
|
-
|
|
12
|
-
describe('AuraErrorCode', () => {
|
|
13
|
-
it('un code connu (littéral de l’union) est accepté et préservé au runtime', () => {
|
|
14
|
-
const e = new AuraError(0, { error: { code: 'timeout', message: 'x' } })
|
|
15
|
-
expect(e.code).toBe('timeout')
|
|
16
|
-
// Sanity : assignable à AuraErrorCode sans cast (autocomplétion sur les littéraux connus).
|
|
17
|
-
const code: AuraErrorCode = e.code
|
|
18
|
-
expect(code).toBe('timeout')
|
|
19
|
-
})
|
|
20
|
-
|
|
21
|
-
it('reste ouvert à un code backend arbitraire non listé (pattern LiteralUnion)', () => {
|
|
22
|
-
const e = new AuraError(422, { error: { code: 'some_backend_specific_code', message: 'x' } })
|
|
23
|
-
expect(e.code).toBe('some_backend_specific_code')
|
|
24
|
-
const code: AuraErrorCode = e.code
|
|
25
|
-
expect(code).toBe('some_backend_specific_code')
|
|
26
|
-
})
|
|
27
|
-
|
|
28
|
-
it('fallback http_<status> quand aucun code n’est fourni par le backend', () => {
|
|
29
|
-
const e = new AuraError(503)
|
|
30
|
-
expect(e.code).toBe('http_503')
|
|
31
|
-
})
|
|
32
|
-
|
|
33
|
-
it('couvre tous les codes SDK-side connus (échantillon représentatif)', () => {
|
|
34
|
-
const knownCodes: AuraErrorCode[] = [
|
|
35
|
-
'no_session',
|
|
36
|
-
'timeout',
|
|
37
|
-
'network_error',
|
|
38
|
-
'invalid_response',
|
|
39
|
-
'refresh_discarded',
|
|
40
|
-
'unverifiable_token',
|
|
41
|
-
'no_code_verifier',
|
|
42
|
-
'pkce_generation_failed',
|
|
43
|
-
'missing_email',
|
|
44
|
-
'jwks_fetch_failed',
|
|
45
|
-
'signature_invalid',
|
|
46
|
-
'token_expired',
|
|
47
|
-
'token_not_yet_valid',
|
|
48
|
-
'invalid_jwt',
|
|
49
|
-
'unsupported_alg',
|
|
50
|
-
'no_matching_key',
|
|
51
|
-
'invalid_issuer',
|
|
52
|
-
'invalid_audience',
|
|
53
|
-
'invalid_path',
|
|
54
|
-
'PGRST116',
|
|
55
|
-
]
|
|
56
|
-
for (const code of knownCodes) {
|
|
57
|
-
const e = new AuraError(0, { error: { code, message: 'x' } })
|
|
58
|
-
expect(e.code).toBe(code)
|
|
59
|
-
}
|
|
60
|
-
})
|
|
61
|
-
})
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest'
|
|
2
|
-
import { AuraError, isAuraError } from '../src/AuraError'
|
|
3
|
-
|
|
4
|
-
describe('AuraError / isAuraError', () => {
|
|
5
|
-
it('reconnaît une vraie instance et expose les helpers', () => {
|
|
6
|
-
const e = new AuraError(429, { error: { code: 'rate_limited', message: 'slow down' } })
|
|
7
|
-
expect(isAuraError(e)).toBe(true)
|
|
8
|
-
expect(e.isRateLimited).toBe(true)
|
|
9
|
-
expect(e.status).toBe(429)
|
|
10
|
-
})
|
|
11
|
-
it('les instances portent le marqueur __isAuraError (détection cross-realm réelle)', () => {
|
|
12
|
-
// Le correctif : une vraie instance doit exposer le marqueur au runtime,
|
|
13
|
-
// pour être détectée même quand `instanceof` échoue (autre bundle/realm).
|
|
14
|
-
expect((new AuraError(500) as unknown as Record<string, unknown>).__isAuraError).toBe(true)
|
|
15
|
-
})
|
|
16
|
-
it('reconnaît un objet marqué __isAuraError (cross-realm simulé)', () => {
|
|
17
|
-
expect(isAuraError({ __isAuraError: true })).toBe(true)
|
|
18
|
-
})
|
|
19
|
-
it('rejette un objet quelconque', () => {
|
|
20
|
-
expect(isAuraError({})).toBe(false)
|
|
21
|
-
expect(isAuraError(null)).toBe(false)
|
|
22
|
-
expect(isAuraError(new Error('x'))).toBe(false)
|
|
23
|
-
})
|
|
24
|
-
})
|
|
@@ -1,286 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi, afterEach } from 'vitest'
|
|
2
|
-
import { fetchWithAuth, type FetchInit } from '../src/fetch'
|
|
3
|
-
import { BaseAuthStore } from '../src/stores/BaseAuthStore'
|
|
4
|
-
import type { AuraClientLike } from '../src/client'
|
|
5
|
-
import type { AuraObservabilityEvent } from '../src/types'
|
|
6
|
-
|
|
7
|
-
// fetch séquentiel : renvoie les réponses dans l'ordre, compte les appels.
|
|
8
|
-
function seqFetch(
|
|
9
|
-
responses: Array<{ status: number; body?: unknown; headers?: Record<string, string>; throw?: unknown }>,
|
|
10
|
-
) {
|
|
11
|
-
const calls: Array<{ url: string; init: RequestInit }> = []
|
|
12
|
-
let i = 0
|
|
13
|
-
const fn = async (url: string, init: RequestInit): Promise<Response> => {
|
|
14
|
-
calls.push({ url, init })
|
|
15
|
-
const r = responses[Math.min(i, responses.length - 1)]
|
|
16
|
-
i++
|
|
17
|
-
if (r.throw) throw r.throw
|
|
18
|
-
return new Response(r.body !== undefined ? JSON.stringify(r.body) : null, {
|
|
19
|
-
status: r.status,
|
|
20
|
-
headers: { 'Content-Type': 'application/json', ...r.headers },
|
|
21
|
-
})
|
|
22
|
-
}
|
|
23
|
-
return { fn, calls }
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function makeClient(
|
|
27
|
-
fetchFn: typeof globalThis.fetch,
|
|
28
|
-
retryConfig?: { enabled: boolean; maxRetries: number },
|
|
29
|
-
onEvent?: (e: AuraObservabilityEvent) => void,
|
|
30
|
-
): AuraClientLike {
|
|
31
|
-
return {
|
|
32
|
-
baseUrl: 'http://localhost:8080',
|
|
33
|
-
projectId: 'proj-1',
|
|
34
|
-
apiKey: 'aura_anon_x',
|
|
35
|
-
fetchFn,
|
|
36
|
-
authStore: new BaseAuthStore(),
|
|
37
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
38
|
-
auth: { refreshSession: async () => ({ data: null, error: null }) as any },
|
|
39
|
-
...(retryConfig ? { retryConfig } : {}),
|
|
40
|
-
...(onEvent ? { onEvent } : {}),
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
afterEach(() => vi.useRealTimers())
|
|
45
|
-
|
|
46
|
-
describe('fetchWithAuth — minor 6b : corps JSON non-objet (null/primitif) sans throw', () => {
|
|
47
|
-
it('200 avec corps primitif (number) → data = valeur, pas de throw ni perte', async () => {
|
|
48
|
-
const { fn } = seqFetch([{ status: 200, body: 42 }])
|
|
49
|
-
const client = makeClient(fn as unknown as typeof globalThis.fetch)
|
|
50
|
-
const res = await fetchWithAuth<number>('http://x/y', { method: 'GET' }, client)
|
|
51
|
-
expect(res.error).toBeNull()
|
|
52
|
-
expect(res.data).toBe(42)
|
|
53
|
-
})
|
|
54
|
-
|
|
55
|
-
it('200 avec corps JSON `null` → data = null, error = null (pas de `in` sur null)', async () => {
|
|
56
|
-
const { fn } = seqFetch([{ status: 200, body: null }])
|
|
57
|
-
const client = makeClient(fn as unknown as typeof globalThis.fetch)
|
|
58
|
-
const res = await fetchWithAuth<unknown>('http://x/y', { method: 'GET' }, client)
|
|
59
|
-
expect(res.error).toBeNull()
|
|
60
|
-
expect(res.data).toBeNull()
|
|
61
|
-
})
|
|
62
|
-
|
|
63
|
-
it('200 avec corps tableau (pas d’enveloppe) → data = tableau tel quel', async () => {
|
|
64
|
-
const { fn } = seqFetch([{ status: 200, body: [1, 2, 3] }])
|
|
65
|
-
const client = makeClient(fn as unknown as typeof globalThis.fetch)
|
|
66
|
-
const res = await fetchWithAuth<number[]>('http://x/y', { method: 'GET' }, client)
|
|
67
|
-
expect(res.error).toBeNull()
|
|
68
|
-
expect(res.data).toEqual([1, 2, 3])
|
|
69
|
-
})
|
|
70
|
-
})
|
|
71
|
-
|
|
72
|
-
describe('fetchWithAuth — retry transitoire', () => {
|
|
73
|
-
it('GET 503 puis 200 → retry puis succès', async () => {
|
|
74
|
-
vi.useFakeTimers()
|
|
75
|
-
const { fn, calls } = seqFetch([{ status: 503 }, { status: 200, body: { ok: true } }])
|
|
76
|
-
const client = makeClient(fn as unknown as typeof globalThis.fetch)
|
|
77
|
-
const p = fetchWithAuth<{ ok: boolean }>('http://x/y', { method: 'GET' }, client)
|
|
78
|
-
await vi.advanceTimersByTimeAsync(600)
|
|
79
|
-
const res = await p
|
|
80
|
-
expect(res.error).toBeNull()
|
|
81
|
-
expect(res.data).toEqual({ ok: true })
|
|
82
|
-
expect(calls.length).toBe(2)
|
|
83
|
-
expect(calls[1].init.headers).toMatchObject({ 'X-Retry-Count': '1' })
|
|
84
|
-
})
|
|
85
|
-
|
|
86
|
-
it('GET erreur réseau puis 200 → retry puis succès', async () => {
|
|
87
|
-
vi.useFakeTimers()
|
|
88
|
-
const { fn, calls } = seqFetch([{ status: 0, throw: new Error('ECONNRESET') }, { status: 200, body: { ok: 1 } }])
|
|
89
|
-
const client = makeClient(fn as unknown as typeof globalThis.fetch)
|
|
90
|
-
const p = fetchWithAuth('http://x/y', { method: 'GET' }, client)
|
|
91
|
-
await vi.advanceTimersByTimeAsync(600)
|
|
92
|
-
const res = await p
|
|
93
|
-
expect(res.error).toBeNull()
|
|
94
|
-
expect(calls.length).toBe(2)
|
|
95
|
-
})
|
|
96
|
-
|
|
97
|
-
it('POST 503 → PAS de retry', async () => {
|
|
98
|
-
const { fn, calls } = seqFetch([{ status: 503, body: { error: { code: 'x', message: 'down' } } }])
|
|
99
|
-
const client = makeClient(fn as unknown as typeof globalThis.fetch)
|
|
100
|
-
const res = await fetchWithAuth('http://x/y', { method: 'POST', body: { a: 1 } }, client)
|
|
101
|
-
expect(res.error?.status).toBe(503)
|
|
102
|
-
expect(calls.length).toBe(1)
|
|
103
|
-
})
|
|
104
|
-
|
|
105
|
-
it('GET 503 en boucle → borné à maxRetries (3) puis erreur', async () => {
|
|
106
|
-
vi.useFakeTimers()
|
|
107
|
-
const { fn, calls } = seqFetch([{ status: 503 }])
|
|
108
|
-
const client = makeClient(fn as unknown as typeof globalThis.fetch)
|
|
109
|
-
const p = fetchWithAuth('http://x/y', { method: 'GET' }, client)
|
|
110
|
-
await vi.advanceTimersByTimeAsync(60000)
|
|
111
|
-
const res = await p
|
|
112
|
-
expect(res.error?.status).toBe(503)
|
|
113
|
-
expect(calls.length).toBe(4) // 1 + 3 retries
|
|
114
|
-
})
|
|
115
|
-
|
|
116
|
-
it('Retry-After prioritaire sur le backoff', async () => {
|
|
117
|
-
vi.useFakeTimers()
|
|
118
|
-
const { fn, calls } = seqFetch([
|
|
119
|
-
{ status: 503, headers: { 'Retry-After': '2' } },
|
|
120
|
-
{ status: 200, body: { ok: true } },
|
|
121
|
-
])
|
|
122
|
-
const client = makeClient(fn as unknown as typeof globalThis.fetch)
|
|
123
|
-
const p = fetchWithAuth('http://x/y', { method: 'GET' }, client)
|
|
124
|
-
await vi.advanceTimersByTimeAsync(600) // > backoff max (500) mais < 2000
|
|
125
|
-
expect(calls.length).toBe(1)
|
|
126
|
-
await vi.advanceTimersByTimeAsync(1500) // total 2100 > 2000
|
|
127
|
-
await p
|
|
128
|
-
expect(calls.length).toBe(2)
|
|
129
|
-
})
|
|
130
|
-
|
|
131
|
-
it('AbortError → aucun retry', async () => {
|
|
132
|
-
const { fn, calls } = seqFetch([
|
|
133
|
-
{ status: 0, throw: Object.assign(new Error('aborted'), { name: 'AbortError' }) },
|
|
134
|
-
])
|
|
135
|
-
const client = makeClient(fn as unknown as typeof globalThis.fetch)
|
|
136
|
-
const res = await fetchWithAuth('http://x/y', { method: 'GET' }, client)
|
|
137
|
-
expect(res.error?.code).toBe('network_error')
|
|
138
|
-
expect(calls.length).toBe(1)
|
|
139
|
-
})
|
|
140
|
-
|
|
141
|
-
it('retry désactivé (client) → aucun retry sur 503', async () => {
|
|
142
|
-
const { fn, calls } = seqFetch([{ status: 503, body: {} }])
|
|
143
|
-
const client = makeClient(fn as unknown as typeof globalThis.fetch, { enabled: false, maxRetries: 0 })
|
|
144
|
-
const res = await fetchWithAuth('http://x/y', { method: 'GET' }, client)
|
|
145
|
-
expect(res.error?.status).toBe(503)
|
|
146
|
-
expect(calls.length).toBe(1)
|
|
147
|
-
})
|
|
148
|
-
|
|
149
|
-
it('skipRetry par requête → aucun retry', async () => {
|
|
150
|
-
const { fn, calls } = seqFetch([{ status: 503, body: {} }])
|
|
151
|
-
const client = makeClient(fn as unknown as typeof globalThis.fetch)
|
|
152
|
-
const init: FetchInit = { method: 'GET', skipRetry: true }
|
|
153
|
-
const res = await fetchWithAuth('http://x/y', init, client)
|
|
154
|
-
expect(res.error?.status).toBe(503)
|
|
155
|
-
expect(calls.length).toBe(1)
|
|
156
|
-
})
|
|
157
|
-
|
|
158
|
-
it('LOT 3 (I5) : `{data:null,meta:null}` (enveloppe vide honnête) → res.data === null (pas l’enveloppe)', async () => {
|
|
159
|
-
const { fn } = seqFetch([{ status: 200, body: { data: null, meta: null } }])
|
|
160
|
-
const client = makeClient(fn as unknown as typeof globalThis.fetch)
|
|
161
|
-
const res = await fetchWithAuth('http://x/y', { method: 'POST', body: {} }, client)
|
|
162
|
-
expect(res.error).toBeNull()
|
|
163
|
-
expect(res.data).toBeNull()
|
|
164
|
-
})
|
|
165
|
-
|
|
166
|
-
it('LOT 3 (I5) : corps SANS clé `data` (legacy non enveloppé) → res.data === le corps entier', async () => {
|
|
167
|
-
const { fn } = seqFetch([{ status: 200, body: { message: 'ok', extra: 1 } }])
|
|
168
|
-
const client = makeClient(fn as unknown as typeof globalThis.fetch)
|
|
169
|
-
const res = await fetchWithAuth('http://x/y', { method: 'GET' }, client)
|
|
170
|
-
expect(res.error).toBeNull()
|
|
171
|
-
expect(res.data).toEqual({ message: 'ok', extra: 1 })
|
|
172
|
-
})
|
|
173
|
-
|
|
174
|
-
it('corps avec bigint → sérialisé en string', async () => {
|
|
175
|
-
const { fn, calls } = seqFetch([{ status: 200, body: { ok: true } }])
|
|
176
|
-
const client = makeClient(fn as unknown as typeof globalThis.fetch)
|
|
177
|
-
await fetchWithAuth('http://x/y', { method: 'POST', body: { id: 7n } }, client)
|
|
178
|
-
expect(calls[0].init.body).toBe('{"id":"7"}')
|
|
179
|
-
})
|
|
180
|
-
|
|
181
|
-
it('LOT 3 (I8) : GET 503 puis 200 → onEvent reçoit {kind:"retry", attempt:1, status:503, url}', async () => {
|
|
182
|
-
vi.useFakeTimers()
|
|
183
|
-
const events: AuraObservabilityEvent[] = []
|
|
184
|
-
const { fn } = seqFetch([{ status: 503 }, { status: 200, body: { ok: true } }])
|
|
185
|
-
const client = makeClient(fn as unknown as typeof globalThis.fetch, undefined, (e) => events.push(e))
|
|
186
|
-
const p = fetchWithAuth('http://x/y', { method: 'GET' }, client)
|
|
187
|
-
await vi.advanceTimersByTimeAsync(600)
|
|
188
|
-
await p
|
|
189
|
-
expect(events).toContainEqual({ kind: 'retry', attempt: 1, status: 503, url: 'http://x/y' })
|
|
190
|
-
})
|
|
191
|
-
|
|
192
|
-
it('LOT 3 (I8) : erreur réseau puis 200 → onEvent reçoit {kind:"retry", attempt:1, url} (sans status)', async () => {
|
|
193
|
-
vi.useFakeTimers()
|
|
194
|
-
const events: AuraObservabilityEvent[] = []
|
|
195
|
-
const { fn } = seqFetch([{ status: 0, throw: new Error('ECONNRESET') }, { status: 200, body: { ok: 1 } }])
|
|
196
|
-
const client = makeClient(fn as unknown as typeof globalThis.fetch, undefined, (e) => events.push(e))
|
|
197
|
-
const p = fetchWithAuth('http://x/y', { method: 'GET' }, client)
|
|
198
|
-
await vi.advanceTimersByTimeAsync(600)
|
|
199
|
-
await p
|
|
200
|
-
expect(events).toContainEqual({ kind: 'retry', attempt: 1, url: 'http://x/y' })
|
|
201
|
-
})
|
|
202
|
-
|
|
203
|
-
it('LOT 3 (I8) : plusieurs retries → un événement par tentative, attempt croissant', async () => {
|
|
204
|
-
vi.useFakeTimers()
|
|
205
|
-
const events: AuraObservabilityEvent[] = []
|
|
206
|
-
const { fn } = seqFetch([{ status: 503 }, { status: 503 }, { status: 200, body: { ok: true } }])
|
|
207
|
-
const client = makeClient(fn as unknown as typeof globalThis.fetch, undefined, (e) => events.push(e))
|
|
208
|
-
const p = fetchWithAuth('http://x/y', { method: 'GET' }, client)
|
|
209
|
-
await vi.advanceTimersByTimeAsync(60000)
|
|
210
|
-
await p
|
|
211
|
-
const retries = events.filter((e) => e.kind === 'retry')
|
|
212
|
-
expect(retries.map((e) => (e as { attempt: number }).attempt)).toEqual([1, 2])
|
|
213
|
-
})
|
|
214
|
-
|
|
215
|
-
it('LOT 3 (I8) : onEvent absent → aucun throw, comportement inchangé', async () => {
|
|
216
|
-
vi.useFakeTimers()
|
|
217
|
-
const { fn, calls } = seqFetch([{ status: 503 }, { status: 200, body: { ok: true } }])
|
|
218
|
-
const client = makeClient(fn as unknown as typeof globalThis.fetch)
|
|
219
|
-
const p = fetchWithAuth('http://x/y', { method: 'GET' }, client)
|
|
220
|
-
await vi.advanceTimersByTimeAsync(600)
|
|
221
|
-
const res = await p
|
|
222
|
-
expect(res.error).toBeNull()
|
|
223
|
-
expect(calls.length).toBe(2)
|
|
224
|
-
})
|
|
225
|
-
|
|
226
|
-
it('LOT 3 (I8) : un onEvent qui throw ne casse pas la requête', async () => {
|
|
227
|
-
vi.useFakeTimers()
|
|
228
|
-
const { fn } = seqFetch([{ status: 503 }, { status: 200, body: { ok: true } }])
|
|
229
|
-
const client = makeClient(fn as unknown as typeof globalThis.fetch, undefined, () => {
|
|
230
|
-
throw new Error('consumer onEvent boom')
|
|
231
|
-
})
|
|
232
|
-
const p = fetchWithAuth('http://x/y', { method: 'GET' }, client)
|
|
233
|
-
await vi.advanceTimersByTimeAsync(600)
|
|
234
|
-
const res = await p
|
|
235
|
-
expect(res.error).toBeNull()
|
|
236
|
-
expect(res.data).toEqual({ ok: true })
|
|
237
|
-
})
|
|
238
|
-
|
|
239
|
-
it('LOT D : authToken override gagne sur store.token (Authorization = Bearer authToken)', async () => {
|
|
240
|
-
const { fn, calls } = seqFetch([{ status: 200, body: { ok: true } }])
|
|
241
|
-
const client = makeClient(fn as unknown as typeof globalThis.fetch)
|
|
242
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
243
|
-
client.authStore.save('store-token', 'refresh', { id: 'u_store' } as any)
|
|
244
|
-
const init: FetchInit = { method: 'GET', authToken: 'foreign-token', skipAuthRefresh: true }
|
|
245
|
-
await fetchWithAuth('http://x/y', init, client)
|
|
246
|
-
const headers = calls[0].init.headers as Record<string, string>
|
|
247
|
-
expect(headers['Authorization']).toBe('Bearer foreign-token')
|
|
248
|
-
// apikey toujours envoyé (parité Supabase), inchangé.
|
|
249
|
-
expect(headers['apikey']).toBe('aura_anon_x')
|
|
250
|
-
})
|
|
251
|
-
|
|
252
|
-
it('LOT D : sans authToken → store.token (comportement inchangé)', async () => {
|
|
253
|
-
const { fn, calls } = seqFetch([{ status: 200, body: { ok: true } }])
|
|
254
|
-
const client = makeClient(fn as unknown as typeof globalThis.fetch)
|
|
255
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
256
|
-
client.authStore.save('store-token', 'refresh', { id: 'u_store' } as any)
|
|
257
|
-
const init: FetchInit = { method: 'GET', skipAuthRefresh: true }
|
|
258
|
-
await fetchWithAuth('http://x/y', init, client)
|
|
259
|
-
const headers = calls[0].init.headers as Record<string, string>
|
|
260
|
-
expect(headers['Authorization']).toBe('Bearer store-token')
|
|
261
|
-
})
|
|
262
|
-
|
|
263
|
-
it('LOT D : authToken sans session (store vide) → Authorization = Bearer authToken', async () => {
|
|
264
|
-
const { fn, calls } = seqFetch([{ status: 200, body: { ok: true } }])
|
|
265
|
-
const client = makeClient(fn as unknown as typeof globalThis.fetch)
|
|
266
|
-
const init: FetchInit = { method: 'GET', authToken: 'foreign-token', skipAuthRefresh: true }
|
|
267
|
-
await fetchWithAuth('http://x/y', init, client)
|
|
268
|
-
const headers = calls[0].init.headers as Record<string, string>
|
|
269
|
-
expect(headers['Authorization']).toBe('Bearer foreign-token')
|
|
270
|
-
})
|
|
271
|
-
|
|
272
|
-
it('Retry-After énorme (86400) est plafonné à 60000ms', async () => {
|
|
273
|
-
vi.useFakeTimers()
|
|
274
|
-
const { fn, calls } = seqFetch([
|
|
275
|
-
{ status: 503, headers: { 'Retry-After': '86400' } },
|
|
276
|
-
{ status: 200, body: { ok: true } },
|
|
277
|
-
])
|
|
278
|
-
const client = makeClient(fn as unknown as typeof globalThis.fetch)
|
|
279
|
-
const p = fetchWithAuth('http://x/y', { method: 'GET' }, client)
|
|
280
|
-
await vi.advanceTimersByTimeAsync(59_999)
|
|
281
|
-
expect(calls.length).toBe(1) // pas encore rejoué
|
|
282
|
-
await vi.advanceTimersByTimeAsync(1) // total 60000 → plafond atteint
|
|
283
|
-
await p
|
|
284
|
-
expect(calls.length).toBe(2)
|
|
285
|
-
})
|
|
286
|
-
})
|