@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.
Files changed (258) hide show
  1. package/package.json +4 -4
  2. package/packages/ai/node_modules/.bin/esbuild +0 -19
  3. package/packages/ai/node_modules/.bin/tsc +0 -22
  4. package/packages/ai/node_modules/.bin/tsserver +0 -22
  5. package/packages/ai/node_modules/.bin/tsup +0 -22
  6. package/packages/ai/node_modules/.bin/tsup-node +0 -22
  7. package/packages/ai/node_modules/.bin/vite +0 -22
  8. package/packages/ai/node_modules/.bin/vitest +0 -22
  9. package/packages/ai/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +0 -1
  10. package/packages/ai/src/AiService.ts +0 -226
  11. package/packages/ai/src/index.ts +0 -18
  12. package/packages/ai/src/sse.ts +0 -141
  13. package/packages/ai/src/types.ts +0 -30
  14. package/packages/ai/tests/chat-stream.test.ts +0 -151
  15. package/packages/ai/tests/rag-namespaces.test.ts +0 -54
  16. package/packages/ai/tests/sse.test.ts +0 -69
  17. package/packages/ai/tsconfig.json +0 -5
  18. package/packages/ai/tsup.config.ts +0 -11
  19. package/packages/aurabase/node_modules/.bin/esbuild +0 -19
  20. package/packages/aurabase/node_modules/.bin/tsc +0 -22
  21. package/packages/aurabase/node_modules/.bin/tsserver +0 -22
  22. package/packages/aurabase/node_modules/.bin/tsup +0 -22
  23. package/packages/aurabase/node_modules/.bin/tsup-node +0 -22
  24. package/packages/aurabase/node_modules/.bin/vite +0 -22
  25. package/packages/aurabase/node_modules/.bin/vitest +0 -22
  26. package/packages/aurabase/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +0 -1
  27. package/packages/aurabase/src/AuraClient.ts +0 -237
  28. package/packages/aurabase/src/index.ts +0 -152
  29. package/packages/aurabase/src/ssr.ts +0 -156
  30. package/packages/aurabase/tests/ai-streaming-rag-e2e.test.ts +0 -82
  31. package/packages/aurabase/tests/ai.test.ts +0 -111
  32. package/packages/aurabase/tests/auth-admin.test.ts +0 -515
  33. package/packages/aurabase/tests/auth-e2e.test.ts +0 -135
  34. package/packages/aurabase/tests/auth-hardening.test.ts +0 -206
  35. package/packages/aurabase/tests/auth.test.ts +0 -947
  36. package/packages/aurabase/tests/database.test.ts +0 -230
  37. package/packages/aurabase/tests/db-types-e2e.test.ts +0 -217
  38. package/packages/aurabase/tests/dispose.test.ts +0 -23
  39. package/packages/aurabase/tests/foreign-token.e2e.test.ts +0 -129
  40. package/packages/aurabase/tests/functions.test.ts +0 -107
  41. package/packages/aurabase/tests/integration.test.ts +0 -413
  42. package/packages/aurabase/tests/live-production-validation.js +0 -241
  43. package/packages/aurabase/tests/live-sdk-production-validation.js +0 -293
  44. package/packages/aurabase/tests/mocks.ts +0 -139
  45. package/packages/aurabase/tests/notifications.test.ts +0 -314
  46. package/packages/aurabase/tests/observability-backup.test.ts +0 -186
  47. package/packages/aurabase/tests/observability-hook.test.ts +0 -130
  48. package/packages/aurabase/tests/production-robustness.test.ts +0 -268
  49. package/packages/aurabase/tests/public-api-surface.test.ts +0 -53
  50. package/packages/aurabase/tests/query-builder.test.ts +0 -329
  51. package/packages/aurabase/tests/readme-smoke-e2e.test.ts +0 -231
  52. package/packages/aurabase/tests/realtime-filter-e2e.test.ts +0 -344
  53. package/packages/aurabase/tests/refresh-locks.test.ts +0 -210
  54. package/packages/aurabase/tests/retry-option.test.ts +0 -17
  55. package/packages/aurabase/tests/rpc-e2e.test.ts +0 -254
  56. package/packages/aurabase/tests/rs256-local-e2e.test.ts +0 -114
  57. package/packages/aurabase/tests/rt-alias-public-e2e.test.ts +0 -235
  58. package/packages/aurabase/tests/rt-http-broadcast-e2e.test.ts +0 -124
  59. package/packages/aurabase/tests/service-role-guard.test.ts +0 -99
  60. package/packages/aurabase/tests/ssr.test.ts +0 -91
  61. package/packages/aurabase/tests/storage-backend-e2e.test.ts +0 -481
  62. package/packages/aurabase/tests/storage-sdk-parity-e2e.test.ts +0 -104
  63. package/packages/aurabase/tests/storage-transform-e2e.test.ts +0 -684
  64. package/packages/aurabase/tests/storage.test.ts +0 -55
  65. package/packages/aurabase/tests/types/client-generic.test-d.ts +0 -79
  66. package/packages/aurabase/tests/types/docs-snippets.test-d.ts +0 -571
  67. package/packages/aurabase/tests/types/error-code.test-d.ts +0 -53
  68. package/packages/aurabase/tsconfig.json +0 -5
  69. package/packages/aurabase/tsconfig.test-d.json +0 -5
  70. package/packages/aurabase/tsup.config.ts +0 -11
  71. package/packages/aurabase/vitest.config.ts +0 -16
  72. package/packages/auth/node_modules/.bin/esbuild +0 -19
  73. package/packages/auth/node_modules/.bin/tsc +0 -22
  74. package/packages/auth/node_modules/.bin/tsserver +0 -22
  75. package/packages/auth/node_modules/.bin/tsup +0 -22
  76. package/packages/auth/node_modules/.bin/tsup-node +0 -22
  77. package/packages/auth/node_modules/.bin/vite +0 -22
  78. package/packages/auth/node_modules/.bin/vitest +0 -22
  79. package/packages/auth/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +0 -1
  80. package/packages/auth/src/AuthAdminService.ts +0 -149
  81. package/packages/auth/src/AuthService.ts +0 -1166
  82. package/packages/auth/src/SessionManager.ts +0 -92
  83. package/packages/auth/src/index.ts +0 -17
  84. package/packages/auth/src/jwks.ts +0 -337
  85. package/packages/auth/src/pkce.ts +0 -27
  86. package/packages/auth/src/types.ts +0 -89
  87. package/packages/auth/tests/auth-lifecycle.test.ts +0 -149
  88. package/packages/auth/tests/detect-session.test.ts +0 -361
  89. package/packages/auth/tests/getclaims.test.ts +0 -780
  90. package/packages/auth/tests/is-mfa-challenge.test.ts +0 -27
  91. package/packages/auth/tests/password-recovery.test.ts +0 -124
  92. package/packages/auth/tests/pkce.test.ts +0 -192
  93. package/packages/auth/tests/session-manager.test.ts +0 -103
  94. package/packages/auth/tests/set-session.test.ts +0 -139
  95. package/packages/auth/tests/verify-otp.test.ts +0 -153
  96. package/packages/auth/tsconfig.json +0 -5
  97. package/packages/auth/tsup.config.ts +0 -11
  98. package/packages/core/node_modules/.bin/esbuild +0 -22
  99. package/packages/core/node_modules/.bin/tsc +0 -22
  100. package/packages/core/node_modules/.bin/tsserver +0 -22
  101. package/packages/core/node_modules/.bin/tsup +0 -22
  102. package/packages/core/node_modules/.bin/tsup-node +0 -22
  103. package/packages/core/node_modules/.bin/vite +0 -22
  104. package/packages/core/node_modules/.bin/vitest +0 -22
  105. package/packages/core/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +0 -1
  106. package/packages/core/src/AuraError.ts +0 -89
  107. package/packages/core/src/BaseService.ts +0 -44
  108. package/packages/core/src/client.ts +0 -34
  109. package/packages/core/src/cookie-utils.ts +0 -42
  110. package/packages/core/src/fetch.ts +0 -435
  111. package/packages/core/src/index.ts +0 -22
  112. package/packages/core/src/retry.ts +0 -63
  113. package/packages/core/src/serialize.ts +0 -6
  114. package/packages/core/src/stores/BaseAuthStore.ts +0 -164
  115. package/packages/core/src/stores/LocalAuthStore.ts +0 -199
  116. package/packages/core/src/types.ts +0 -1042
  117. package/packages/core/tests/auth-store.test.ts +0 -300
  118. package/packages/core/tests/error-code.test.ts +0 -61
  119. package/packages/core/tests/error.test.ts +0 -24
  120. package/packages/core/tests/fetch.test.ts +0 -286
  121. package/packages/core/tests/mocks.ts +0 -139
  122. package/packages/core/tests/observability.test.ts +0 -86
  123. package/packages/core/tests/refresh-hardening.test.ts +0 -164
  124. package/packages/core/tests/refresh-observability.test.ts +0 -111
  125. package/packages/core/tests/retry.test.ts +0 -106
  126. package/packages/core/tests/serialize.test.ts +0 -12
  127. package/packages/core/tests/timeout.test.ts +0 -79
  128. package/packages/core/tsconfig.json +0 -5
  129. package/packages/core/tsup.config.ts +0 -11
  130. package/packages/db/node_modules/.bin/esbuild +0 -19
  131. package/packages/db/node_modules/.bin/tsc +0 -22
  132. package/packages/db/node_modules/.bin/tsserver +0 -22
  133. package/packages/db/node_modules/.bin/tsup +0 -22
  134. package/packages/db/node_modules/.bin/tsup-node +0 -22
  135. package/packages/db/node_modules/.bin/vite +0 -22
  136. package/packages/db/node_modules/.bin/vitest +0 -22
  137. package/packages/db/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +0 -1
  138. package/packages/db/src/DatabaseService.ts +0 -170
  139. package/packages/db/src/QueryBuilder.ts +0 -830
  140. package/packages/db/src/index.ts +0 -2
  141. package/packages/db/src/pgrst-types/common/common.ts +0 -86
  142. package/packages/db/src/pgrst-types/common/rpc.ts +0 -151
  143. package/packages/db/src/pgrst-types/feature-flags.ts +0 -20
  144. package/packages/db/src/pgrst-types/types.ts +0 -134
  145. package/packages/db/src/select-query-parser/parser.ts +0 -479
  146. package/packages/db/src/select-query-parser/result.ts +0 -553
  147. package/packages/db/src/select-query-parser/types.ts +0 -132
  148. package/packages/db/src/select-query-parser/utils.ts +0 -707
  149. package/packages/db/tests/filters.test.ts +0 -81
  150. package/packages/db/tests/mutations-filtered.e2e.test.ts +0 -132
  151. package/packages/db/tests/mutations-filtered.test.ts +0 -188
  152. package/packages/db/tests/order.test.ts +0 -45
  153. package/packages/db/tests/rpc.test.ts +0 -41
  154. package/packages/db/tests/scale/build-large-schema.ts +0 -94
  155. package/packages/db/tests/scale/scale-compile.test.ts +0 -167
  156. package/packages/db/tests/schema.test.ts +0 -77
  157. package/packages/db/tests/single-accept.e2e.test.ts +0 -123
  158. package/packages/db/tests/single.test.ts +0 -211
  159. package/packages/db/tests/types/filters.test-d.ts +0 -52
  160. package/packages/db/tests/types/fixtures.ts +0 -40
  161. package/packages/db/tests/types/from-views.test-d.ts +0 -18
  162. package/packages/db/tests/types/mutations.test-d.ts +0 -23
  163. package/packages/db/tests/types/rpc.test-d.ts +0 -60
  164. package/packages/db/tests/types/schema-shape.test-d.ts +0 -8
  165. package/packages/db/tests/types/select-inference.test-d.ts +0 -38
  166. package/packages/db/tests/vendored/fixtures.ts +0 -83
  167. package/packages/db/tests/vendored/get-result.test-d.ts +0 -75
  168. package/packages/db/tsconfig.json +0 -5
  169. package/packages/db/tsconfig.test-d.json +0 -5
  170. package/packages/db/tsup.config.ts +0 -11
  171. package/packages/db/vitest.config.ts +0 -8
  172. package/packages/functions/node_modules/.bin/esbuild +0 -19
  173. package/packages/functions/node_modules/.bin/tsc +0 -22
  174. package/packages/functions/node_modules/.bin/tsserver +0 -22
  175. package/packages/functions/node_modules/.bin/tsup +0 -22
  176. package/packages/functions/node_modules/.bin/tsup-node +0 -22
  177. package/packages/functions/node_modules/.bin/vite +0 -22
  178. package/packages/functions/node_modules/.bin/vitest +0 -22
  179. package/packages/functions/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +0 -1
  180. package/packages/functions/src/FunctionsService.ts +0 -188
  181. package/packages/functions/src/errors.ts +0 -70
  182. package/packages/functions/src/index.ts +0 -6
  183. package/packages/functions/tests/invoke.test.ts +0 -97
  184. package/packages/functions/tests/response-type-errors.test.ts +0 -135
  185. package/packages/functions/tsconfig.json +0 -5
  186. package/packages/functions/tsup.config.ts +0 -11
  187. package/packages/gen/node_modules/.bin/esbuild +0 -19
  188. package/packages/gen/node_modules/.bin/tsc +0 -22
  189. package/packages/gen/node_modules/.bin/tsserver +0 -22
  190. package/packages/gen/node_modules/.bin/tsup +0 -22
  191. package/packages/gen/node_modules/.bin/tsup-node +0 -22
  192. package/packages/gen/node_modules/.bin/vite +0 -22
  193. package/packages/gen/node_modules/.bin/vitest +0 -22
  194. package/packages/gen/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +0 -1
  195. package/packages/gen/src/cli.ts +0 -67
  196. package/packages/gen/src/generate.ts +0 -0
  197. package/packages/gen/src/index.ts +0 -2
  198. package/packages/gen/tests/compile.test.ts +0 -213
  199. package/packages/gen/tests/e2e.test.ts +0 -130
  200. package/packages/gen/tests/generate.test.ts +0 -396
  201. package/packages/gen/tsconfig.json +0 -5
  202. package/packages/gen/tsup.config.ts +0 -11
  203. package/packages/notifications/node_modules/.bin/esbuild +0 -19
  204. package/packages/notifications/node_modules/.bin/tsc +0 -22
  205. package/packages/notifications/node_modules/.bin/tsserver +0 -22
  206. package/packages/notifications/node_modules/.bin/tsup +0 -22
  207. package/packages/notifications/node_modules/.bin/tsup-node +0 -22
  208. package/packages/notifications/node_modules/.bin/vite +0 -22
  209. package/packages/notifications/node_modules/.bin/vitest +0 -22
  210. package/packages/notifications/src/NotificationsService.ts +0 -230
  211. package/packages/notifications/src/index.ts +0 -19
  212. package/packages/notifications/tsconfig.json +0 -5
  213. package/packages/notifications/tsup.config.ts +0 -11
  214. package/packages/realtime/node_modules/.bin/esbuild +0 -19
  215. package/packages/realtime/node_modules/.bin/tsc +0 -22
  216. package/packages/realtime/node_modules/.bin/tsserver +0 -22
  217. package/packages/realtime/node_modules/.bin/tsup +0 -22
  218. package/packages/realtime/node_modules/.bin/tsup-node +0 -22
  219. package/packages/realtime/node_modules/.bin/vite +0 -22
  220. package/packages/realtime/node_modules/.bin/vitest +0 -22
  221. package/packages/realtime/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +0 -1
  222. package/packages/realtime/src/AuraChannel.ts +0 -485
  223. package/packages/realtime/src/HeartbeatManager.ts +0 -73
  224. package/packages/realtime/src/RealtimeService.ts +0 -505
  225. package/packages/realtime/src/columnFilter.ts +0 -301
  226. package/packages/realtime/src/index.ts +0 -4
  227. package/packages/realtime/tests/ack-routing.test.ts +0 -81
  228. package/packages/realtime/tests/column-filter.test.ts +0 -144
  229. package/packages/realtime/tests/dispatch.test.ts +0 -191
  230. package/packages/realtime/tests/heartbeat.test.ts +0 -67
  231. package/packages/realtime/tests/http-broadcast.test.ts +0 -68
  232. package/packages/realtime/tests/realtime-token.test.ts +0 -43
  233. package/packages/realtime/tests/reconnect-race.test.ts +0 -149
  234. package/packages/realtime/tests/ref-id.test.ts +0 -34
  235. package/packages/realtime/tests/set-auth.test.ts +0 -70
  236. package/packages/realtime/tsconfig.json +0 -5
  237. package/packages/realtime/tsup.config.ts +0 -11
  238. package/packages/storage/node_modules/.bin/esbuild +0 -19
  239. package/packages/storage/node_modules/.bin/tsc +0 -22
  240. package/packages/storage/node_modules/.bin/tsserver +0 -22
  241. package/packages/storage/node_modules/.bin/tsup +0 -22
  242. package/packages/storage/node_modules/.bin/tsup-node +0 -22
  243. package/packages/storage/node_modules/.bin/vite +0 -22
  244. package/packages/storage/node_modules/.bin/vitest +0 -22
  245. package/packages/storage/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +0 -1
  246. package/packages/storage/src/DownloadBuilder.ts +0 -60
  247. package/packages/storage/src/StorageService.ts +0 -323
  248. package/packages/storage/src/index.ts +0 -2
  249. package/packages/storage/src/path.ts +0 -35
  250. package/packages/storage/src/transform.ts +0 -15
  251. package/packages/storage/tests/download.test.ts +0 -64
  252. package/packages/storage/tests/parity.test.ts +0 -154
  253. package/packages/storage/tests/path.test.ts +0 -87
  254. package/packages/storage/tests/transform.test.ts +0 -79
  255. package/packages/storage/tsconfig.json +0 -5
  256. package/packages/storage/tsup.config.ts +0 -11
  257. package/pnpm-workspace.yaml +0 -24
  258. package/tsconfig.base.json +0 -15
@@ -1,481 +0,0 @@
1
- // ---------------------------------------------------------------------------
2
- // E2E réel (stack live) — Lot storage-backend : valide les 4 correctifs backend.
3
- // Réf. specs : docs/superpowers/specs/2026-07-13-storage-*-design.md
4
- //
5
- // Les méthodes SDK correspondantes (updateBucket, uploadToSignedUrl, copy/move
6
- // cross-bucket) ne sont pas encore ajoutées (lot storage-sdk) → on teste le
7
- // BACKEND via fetch REST direct (routes confirmées dans aura-storage/src/main.rs),
8
- // avec la même mécanique de skip gracieux que storage-transform-e2e.test.ts.
9
- //
10
- // Scénarios :
11
- // 1. img-transform-default : défaut déterministe = activé (plus de bascule
12
- // autorisé→Forbidden à l'ouverture des settings).
13
- // 2. signed-upload-url : mint service_role → PUT signé fonctionnel (valide
14
- // aussi l'assomption gateway : PUT signé sans apikey passe le data-plane) ;
15
- // PUT sans sig → 401 ; mint anon → 403 (sécurité #1) ; mint _derivatives → 403.
16
- // 3. cache-hardening : x-aura-cache MISS→HIT + ETag stable ; overwrite source
17
- // → nouveau rendu (clé versionnée etag) ; upload ?folder=_derivatives → 400.
18
- // 4. cross-bucket : copy/move a→b (bucket destination distinct) ; dst inconnu → 404.
19
- //
20
- // Gaté par RUN_E2E + credentials.
21
- // ---------------------------------------------------------------------------
22
-
23
- import { describe, it, expect } from 'vitest'
24
- import { deflateSync } from 'node:zlib'
25
- import { createAdminClient, createClient } from '../src/index'
26
- import type { AuraResponse } from '../src/index'
27
-
28
- const URL = process.env.AURA_E2E_URL
29
- const PROJECT = process.env.AURA_E2E_PROJECT
30
- const ANON = process.env.AURA_E2E_ANON_KEY
31
- const SERVICE = process.env.AURA_E2E_SERVICE_KEY
32
- const RUN = Boolean(process.env.RUN_E2E && URL && PROJECT && ANON && SERVICE)
33
-
34
- const TRANSIENT_STATUS = new Set([408, 429, 502, 503, 504])
35
-
36
- async function retryTransient<T>(fn: () => PromiseLike<AuraResponse<T>>): Promise<AuraResponse<T>> {
37
- let res = await fn()
38
- for (let i = 0; i < 10 && res.error && TRANSIENT_STATUS.has(res.error.status); i++) {
39
- await new Promise((r) => setTimeout(r, 1000))
40
- res = await fn()
41
- }
42
- return res
43
- }
44
-
45
- async function retryFetch(fn: () => Promise<Response>): Promise<Response> {
46
- let res = await fn()
47
- for (let i = 0; i < 10 && TRANSIENT_STATUS.has(res.status); i++) {
48
- await new Promise((r) => setTimeout(r, 1000))
49
- res = await fn()
50
- }
51
- return res
52
- }
53
-
54
- // ── Générateur PNG minimal (repris de storage-transform-e2e.test.ts) ──────────
55
- const CRC_TABLE: Uint32Array = (() => {
56
- const table = new Uint32Array(256)
57
- for (let n = 0; n < 256; n++) {
58
- let c = n
59
- for (let k = 0; k < 8; k++) c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1
60
- table[n] = c >>> 0
61
- }
62
- return table
63
- })()
64
- function crc32(bytes: Uint8Array): number {
65
- let c = 0xffffffff
66
- for (let i = 0; i < bytes.length; i++) c = CRC_TABLE[(c ^ bytes[i]) & 0xff] ^ (c >>> 8)
67
- return (c ^ 0xffffffff) >>> 0
68
- }
69
- function u32be(n: number): Uint8Array {
70
- return new Uint8Array([(n >>> 24) & 0xff, (n >>> 16) & 0xff, (n >>> 8) & 0xff, n & 0xff])
71
- }
72
- function concatBytes(...parts: Uint8Array[]): Uint8Array {
73
- const total = parts.reduce((s, p) => s + p.length, 0)
74
- const out = new Uint8Array(total)
75
- let off = 0
76
- for (const p of parts) {
77
- out.set(p, off)
78
- off += p.length
79
- }
80
- return out
81
- }
82
- function pngChunk(type: string, data: Uint8Array): Uint8Array {
83
- const typeBytes = new Uint8Array(type.split('').map((c) => c.charCodeAt(0)))
84
- return concatBytes(u32be(data.length), typeBytes, data, u32be(crc32(concatBytes(typeBytes, data))))
85
- }
86
- function makePng(width: number, height: number, seedInit = 0x12345678): Uint8Array {
87
- const SIGNATURE = new Uint8Array([137, 80, 78, 71, 13, 10, 26, 10])
88
- const ihdr = pngChunk('IHDR', concatBytes(u32be(width), u32be(height), new Uint8Array([8, 2, 0, 0, 0])))
89
- const stride = 1 + width * 3
90
- const raw = new Uint8Array(stride * height)
91
- let seed = seedInit
92
- const nextByte = () => {
93
- seed = (seed * 1103515245 + 12345) & 0x7fffffff
94
- return (seed >>> 16) & 0xff
95
- }
96
- for (let y = 0; y < height; y++) {
97
- const rowStart = y * stride
98
- raw[rowStart] = 0
99
- for (let x = 0; x < width; x++) {
100
- const px = rowStart + 1 + x * 3
101
- raw[px] = nextByte()
102
- raw[px + 1] = nextByte()
103
- raw[px + 2] = nextByte()
104
- }
105
- }
106
- const compressed = deflateSync(raw)
107
- const idat = pngChunk('IDAT', new Uint8Array(compressed.buffer, compressed.byteOffset, compressed.byteLength))
108
- return concatBytes(SIGNATURE, ihdr, idat, pngChunk('IEND', new Uint8Array(0)))
109
- }
110
- function readPngWidth(bytes: Uint8Array): number {
111
- return ((bytes[16] << 24) | (bytes[17] << 16) | (bytes[18] << 8) | bytes[19]) >>> 0
112
- }
113
-
114
- /** Lit `{ data: { url } }` OU `{ url }` selon l'enveloppe ApiResponse. */
115
- function extractUrl(json: unknown): string | undefined {
116
- const j = json as { data?: { url?: string }; url?: string }
117
- return j?.data?.url ?? j?.url
118
- }
119
-
120
- describe.runIf(RUN)('storage-backend E2E réel (stack live)', () => {
121
- const suffix = () => process.env.AURA_E2E_SUFFIX ?? Math.random().toString(36).slice(2, 8)
122
- const H_SERVICE = { apikey: SERVICE! } as Record<string, string>
123
-
124
- // ── 1. img-transform-default : défaut déterministe activé ───────────────────
125
- it(
126
- 'img_transform_enabled par défaut = activé : ouvrir les settings ne bascule pas transform en Forbidden',
127
- async () => {
128
- const admin = createAdminClient(URL!, PROJECT!, SERVICE!)
129
- const bucket = `e2e-imgdef-${suffix()}`
130
- let created = false
131
- let uploadedKey = 'img.png'
132
- try {
133
- const createRes = await retryTransient(() =>
134
- admin.storage.createBucket(bucket, { public: false, allowedMimeTypes: ['image/png'] }),
135
- )
136
- if (createRes.error && TRANSIENT_STATUS.has(createRes.error.status)) {
137
- console.warn(`[storage-backend-e2e] SKIP img-default (createBucket ${createRes.error.status}).`)
138
- return
139
- }
140
- expect(createRes.error).toBeNull()
141
- created = true
142
-
143
- const uploadRes = await admin.storage.upload(bucket, 'img.png', new Blob([makePng(120, 120)], { type: 'image/png' }), {
144
- contentType: 'image/png',
145
- })
146
- expect(uploadRes.error).toBeNull()
147
- uploadedKey = uploadRes.data?.key ?? 'img.png'
148
-
149
- // GET /settings crée la ligne (avec le fix : DEFAULT true + INSERT explicite true).
150
- const settingsRes = await retryFetch(() =>
151
- fetch(`${admin.baseUrl}/v1/storage/${admin.projectId}/settings`, { headers: H_SERVICE }),
152
- )
153
- if (!settingsRes.ok) {
154
- console.warn(`[storage-backend-e2e] SKIP img-default (GET settings ${settingsRes.status}).`)
155
- return
156
- }
157
- const settingsJson = (await settingsRes.json()) as { data?: Record<string, unknown> }
158
- const flag = (settingsJson.data ?? (settingsJson as Record<string, unknown>))['img_transform_enabled']
159
- // Cœur du fix : après création de la ligne, le défaut est `true` (déterministe), donc pas
160
- // de bascule autorisé→refusé. Sur le projet E2E partagé, un test concurrent peut avoir
161
- // mis false explicitement → on n'assène l'assertion stricte que si le flag n'est pas false.
162
- if (flag === false) {
163
- console.warn('[storage-backend-e2e] img_transform_enabled=false (override explicite concurrent) — assertion défaut ignorée.')
164
- } else {
165
- expect(flag).toBe(true)
166
- }
167
-
168
- // Et une transformation doit réussir (autorisée), après avoir touché les settings.
169
- const dl = await retryTransient(() => admin.storage.download(bucket, uploadedKey, { transform: { width: 40 } }))
170
- if (dl.error && TRANSIENT_STATUS.has(dl.error.status)) {
171
- console.warn(`[storage-backend-e2e] SKIP img-default (download transform ${dl.error.status}).`)
172
- return
173
- }
174
- if (flag !== false) {
175
- expect(dl.error).toBeNull()
176
- const buf = new Uint8Array(await dl.data!.arrayBuffer())
177
- expect(readPngWidth(buf)).toBe(40)
178
- }
179
- } finally {
180
- if (created) {
181
- try {
182
- await admin.storage.remove(bucket, [uploadedKey])
183
- } catch {
184
- /* best-effort */
185
- }
186
- try {
187
- await admin.storage.deleteBucket(bucket)
188
- } catch {
189
- /* best-effort */
190
- }
191
- }
192
- }
193
- },
194
- 120_000,
195
- )
196
-
197
- // ── 2. signed-upload-url : PUT signé + garde-fous sécurité ──────────────────
198
- it(
199
- 'upload par URL signée : mint service_role → PUT fonctionnel ; PUT sans sig → 401 ; mint anon → 403 ; mint _derivatives → 403',
200
- async () => {
201
- const admin = createAdminClient(URL!, PROJECT!, SERVICE!)
202
- const bucket = `e2e-signup-${suffix()}`
203
- const key = `direct-${suffix()}.txt`
204
- let created = false
205
- try {
206
- const createRes = await retryTransient(() =>
207
- admin.storage.createBucket(bucket, { public: false, allowedMimeTypes: ['text/plain'] }),
208
- )
209
- if (createRes.error && TRANSIENT_STATUS.has(createRes.error.status)) {
210
- console.warn(`[storage-backend-e2e] SKIP signed-upload (createBucket ${createRes.error.status}).`)
211
- return
212
- }
213
- expect(createRes.error).toBeNull()
214
- created = true
215
-
216
- const mintUrl = `${admin.baseUrl}/v1/storage/${admin.projectId}/${bucket}/upload-url?key=${encodeURIComponent(key)}`
217
-
218
- // (a) Mint avec ANON (non service_role) → 403 (finding #1).
219
- const anonMint = await retryFetch(() => fetch(mintUrl, { headers: { apikey: ANON! } }))
220
- if (!TRANSIENT_STATUS.has(anonMint.status)) {
221
- expect(anonMint.status).toBe(403)
222
- }
223
-
224
- // (b) Mint pour une clé sous _derivatives/ (service_role) → 403.
225
- const derivMint = await retryFetch(() =>
226
- fetch(
227
- `${admin.baseUrl}/v1/storage/${admin.projectId}/${bucket}/upload-url?key=${encodeURIComponent('_derivatives/x/y.txt')}`,
228
- { headers: H_SERVICE },
229
- ),
230
- )
231
- if (!TRANSIENT_STATUS.has(derivMint.status)) {
232
- expect(derivMint.status).toBe(403)
233
- }
234
-
235
- // (c) Mint service_role → URL signée.
236
- const mintRes = await retryFetch(() => fetch(mintUrl, { headers: H_SERVICE }))
237
- if (TRANSIENT_STATUS.has(mintRes.status)) {
238
- console.warn(`[storage-backend-e2e] SKIP signed-upload (mint ${mintRes.status}).`)
239
- return
240
- }
241
- expect(mintRes.ok).toBe(true)
242
- const signedUrl = extractUrl(await mintRes.json())
243
- expect(signedUrl).toBeTruthy()
244
-
245
- // (d) PUT du corps vers l'URL signée (SANS apikey) → 200. Valide l'assomption gateway.
246
- const payload = `bonjour-${suffix()}`
247
- const putRes = await retryFetch(() =>
248
- fetch(signedUrl!, { method: 'PUT', headers: { 'content-type': 'text/plain' }, body: payload }),
249
- )
250
- if (TRANSIENT_STATUS.has(putRes.status)) {
251
- console.warn(`[storage-backend-e2e] SKIP signed-upload (PUT ${putRes.status}).`)
252
- return
253
- }
254
- expect(
255
- putRes.ok,
256
- `PUT vers l'URL signée a échoué (${putRes.status}) — si 401/403 sans transitoire, la gateway ` +
257
- `data-plane bloque le PUT signé non-authentifié (assomption gateway à corriger côté aura-gateway).`,
258
- ).toBe(true)
259
-
260
- // (e) Contenu relu identique.
261
- const dl = await retryTransient(() => admin.storage.download(bucket, key))
262
- if (!(dl.error && TRANSIENT_STATUS.has(dl.error.status))) {
263
- expect(dl.error).toBeNull()
264
- expect(await dl.data!.text()).toBe(payload)
265
- }
266
-
267
- // (f) PUT sur le chemin objet SANS ?sig= → 401.
268
- const noSig = await retryFetch(() =>
269
- fetch(`${admin.baseUrl}/v1/storage/${admin.projectId}/${bucket}/${encodeURIComponent(key)}`, {
270
- method: 'PUT',
271
- headers: { 'content-type': 'text/plain', apikey: SERVICE! },
272
- body: 'x',
273
- }),
274
- )
275
- if (!TRANSIENT_STATUS.has(noSig.status)) {
276
- expect(noSig.status).toBe(401)
277
- }
278
- } finally {
279
- if (created) {
280
- try {
281
- await admin.storage.remove(bucket, [key])
282
- } catch {
283
- /* best-effort */
284
- }
285
- try {
286
- await admin.storage.deleteBucket(bucket)
287
- } catch {
288
- /* best-effort */
289
- }
290
- }
291
- }
292
- },
293
- 120_000,
294
- )
295
-
296
- // ── 3. cache-hardening : ETag stable + overwrite + rejet _derivatives ───────
297
- it(
298
- 'cache dérivés : MISS→HIT même ETag ; overwrite source → nouveau rendu ; upload ?folder=_derivatives → 400',
299
- async () => {
300
- const admin = createAdminClient(URL!, PROJECT!, SERVICE!)
301
- const bucket = `e2e-cache-${suffix()}`
302
- let created = false
303
- let uploadedKey = 'img.png'
304
- try {
305
- const createRes = await retryTransient(() =>
306
- admin.storage.createBucket(bucket, { public: false, allowedMimeTypes: ['image/png'] }),
307
- )
308
- if (createRes.error && TRANSIENT_STATUS.has(createRes.error.status)) {
309
- console.warn(`[storage-backend-e2e] SKIP cache (createBucket ${createRes.error.status}).`)
310
- return
311
- }
312
- expect(createRes.error).toBeNull()
313
- created = true
314
-
315
- const up = await admin.storage.upload(bucket, 'img.png', new Blob([makePng(150, 150, 0x1111)], { type: 'image/png' }), {
316
- contentType: 'image/png',
317
- upsert: true,
318
- })
319
- expect(up.error).toBeNull()
320
- uploadedKey = up.data?.key ?? 'img.png'
321
-
322
- const signedRes = await retryTransient(() => admin.storage.createSignedUrl(bucket, uploadedKey, 600, { transform: { width: 45 } }))
323
- if (signedRes.error && TRANSIENT_STATUS.has(signedRes.error.status)) {
324
- console.warn(`[storage-backend-e2e] SKIP cache (signedUrl ${signedRes.error.status}).`)
325
- return
326
- }
327
- expect(signedRes.error).toBeNull()
328
- const derivUrl = signedRes.data!.url
329
-
330
- const f1 = await retryFetch(() => fetch(derivUrl))
331
- if (TRANSIENT_STATUS.has(f1.status)) {
332
- console.warn(`[storage-backend-e2e] SKIP cache (fetch1 ${f1.status}).`)
333
- return
334
- }
335
- expect(f1.ok).toBe(true)
336
- const etag1 = f1.headers.get('etag')
337
- const cache1 = f1.headers.get('x-aura-cache')
338
- await f1.arrayBuffer()
339
-
340
- if (cache1 === 'MISS' && etag1) {
341
- const f2 = await retryFetch(() => fetch(derivUrl))
342
- if (!TRANSIENT_STATUS.has(f2.status)) {
343
- expect(f2.headers.get('x-aura-cache')).toBe('HIT')
344
- // ETag stable entre MISS et HIT (sous-finding c).
345
- expect(f2.headers.get('etag')).toBe(etag1)
346
- await f2.arrayBuffer()
347
- }
348
- } else {
349
- console.warn(`[storage-backend-e2e] cache header x-aura-cache=${cache1} (non 'MISS') — assertion HIT/ETag ignorée.`)
350
- }
351
-
352
- // Sous-finding (d) : le préfixe réservé _derivatives/ n'est écrivable que via un handler
353
- // qui exploite `?folder=`. upload_file (POST .../{bucket}) IGNORE `?folder=` (sa clé = le
354
- // nom de fichier, l'objet n'atterrit jamais sous _derivatives/) — le VRAI vecteur est
355
- // init_multipart, qui construit la clé `{folder}/{uuid}`. On teste donc celui-là.
356
- const folderRes = await retryFetch(() =>
357
- fetch(
358
- `${admin.baseUrl}/v1/storage/${admin.projectId}/${bucket}/multipart/init?filename=x.png&folder=${encodeURIComponent('_derivatives')}`,
359
- { method: 'POST', headers: H_SERVICE },
360
- ),
361
- )
362
- if (!TRANSIENT_STATUS.has(folderRes.status)) {
363
- expect(
364
- folderRes.status,
365
- `init_multipart ?folder=_derivatives devrait être rejeté (400), reçu ${folderRes.status}`,
366
- ).toBe(400)
367
- }
368
- } finally {
369
- if (created) {
370
- try {
371
- await admin.storage.remove(bucket, [uploadedKey])
372
- } catch {
373
- /* best-effort */
374
- }
375
- try {
376
- await admin.storage.deleteBucket(bucket)
377
- } catch {
378
- /* best-effort */
379
- }
380
- }
381
- }
382
- },
383
- 120_000,
384
- )
385
-
386
- // ── 4. cross-bucket copy/move ───────────────────────────────────────────────
387
- it(
388
- 'copy/move vers un bucket destination distinct ; dst_bucket inconnu → 404',
389
- async () => {
390
- const admin = createAdminClient(URL!, PROJECT!, SERVICE!)
391
- const s = suffix()
392
- const bucketA = `e2e-xb-a-${s}`
393
- const bucketB = `e2e-xb-b-${s}`
394
- let createdA = false
395
- let createdB = false
396
- let keyX = 'x.txt'
397
- let keyY = 'y.txt'
398
- try {
399
- for (const [b, set] of [[bucketA, (v: boolean) => (createdA = v)], [bucketB, (v: boolean) => (createdB = v)]] as const) {
400
- const r = await retryTransient(() => admin.storage.createBucket(b, { public: false, allowedMimeTypes: ['text/plain'] }))
401
- if (r.error && TRANSIENT_STATUS.has(r.error.status)) {
402
- console.warn(`[storage-backend-e2e] SKIP cross-bucket (createBucket ${b} ${r.error.status}).`)
403
- return
404
- }
405
- expect(r.error).toBeNull()
406
- set(true)
407
- }
408
-
409
- const upX = await admin.storage.upload(bucketA, 'x.txt', new Blob(['contenu-x'], { type: 'text/plain' }), { contentType: 'text/plain' })
410
- expect(upX.error).toBeNull()
411
- keyX = upX.data?.key ?? 'x.txt'
412
- const upY = await admin.storage.upload(bucketA, 'y.txt', new Blob(['contenu-y'], { type: 'text/plain' }), { contentType: 'text/plain' })
413
- expect(upY.error).toBeNull()
414
- keyY = upY.data?.key ?? 'y.txt'
415
-
416
- // COPY a→b : objet créé dans b, source intacte.
417
- const copyRes = await retryFetch(() =>
418
- fetch(`${admin.baseUrl}/v1/storage/${admin.projectId}/${bucketA}/copy`, {
419
- method: 'POST',
420
- headers: { ...H_SERVICE, 'content-type': 'application/json' },
421
- body: JSON.stringify({ src_key: keyX, dst_key: 'copied.txt', dst_bucket: bucketB }),
422
- }),
423
- )
424
- if (TRANSIENT_STATUS.has(copyRes.status)) {
425
- console.warn(`[storage-backend-e2e] SKIP cross-bucket (copy ${copyRes.status}).`)
426
- return
427
- }
428
- expect(copyRes.ok, `copy a→b devrait réussir, reçu ${copyRes.status}`).toBe(true)
429
- const dlCopied = await retryTransient(() => admin.storage.download(bucketB, 'copied.txt'))
430
- if (!(dlCopied.error && TRANSIENT_STATUS.has(dlCopied.error.status))) {
431
- expect(dlCopied.error).toBeNull()
432
- expect(await dlCopied.data!.text()).toBe('contenu-x')
433
- }
434
- const dlSrc = await retryTransient(() => admin.storage.download(bucketA, keyX))
435
- if (!(dlSrc.error && TRANSIENT_STATUS.has(dlSrc.error.status))) {
436
- expect(dlSrc.error, 'la source doit rester intacte après copy').toBeNull()
437
- }
438
-
439
- // MOVE a→b : objet dans b, absent de a.
440
- const moveRes = await retryFetch(() =>
441
- fetch(`${admin.baseUrl}/v1/storage/${admin.projectId}/${bucketA}/move`, {
442
- method: 'POST',
443
- headers: { ...H_SERVICE, 'content-type': 'application/json' },
444
- body: JSON.stringify({ src_key: keyY, dst_key: 'moved.txt', dst_bucket: bucketB }),
445
- }),
446
- )
447
- if (!TRANSIENT_STATUS.has(moveRes.status)) {
448
- expect(moveRes.ok, `move a→b devrait réussir, reçu ${moveRes.status}`).toBe(true)
449
- const dlMoved = await retryTransient(() => admin.storage.download(bucketB, 'moved.txt'))
450
- if (!(dlMoved.error && TRANSIENT_STATUS.has(dlMoved.error.status))) {
451
- expect(dlMoved.error).toBeNull()
452
- expect(await dlMoved.data!.text()).toBe('contenu-y')
453
- }
454
- }
455
-
456
- // dst_bucket inexistant → 404.
457
- const badRes = await retryFetch(() =>
458
- fetch(`${admin.baseUrl}/v1/storage/${admin.projectId}/${bucketA}/copy`, {
459
- method: 'POST',
460
- headers: { ...H_SERVICE, 'content-type': 'application/json' },
461
- body: JSON.stringify({ src_key: keyX, dst_key: 'z.txt', dst_bucket: `nope-${s}` }),
462
- }),
463
- )
464
- if (!TRANSIENT_STATUS.has(badRes.status)) {
465
- expect(badRes.status, 'copy vers un bucket inconnu doit renvoyer 404').toBe(404)
466
- }
467
- } finally {
468
- for (const [b, wasCreated] of [[bucketA, createdA], [bucketB, createdB]] as const) {
469
- if (wasCreated) {
470
- try {
471
- await admin.storage.deleteBucket(b)
472
- } catch {
473
- /* best-effort */
474
- }
475
- }
476
- }
477
- }
478
- },
479
- 120_000,
480
- )
481
- })
@@ -1,104 +0,0 @@
1
- // ---------------------------------------------------------------------------
2
- // E2E réel (stack live) — Lot sdk-storage-gen / `storage-sdk-parity-quickwins`.
3
- // Réf. : docs/superpowers/specs/2026-07-13-storage-sdk-parity-quickwins-design.md
4
- //
5
- // Vérifie updateBucket (PATCH partiel), option upload `metadata` (relue via
6
- // getMetadata), createSignedUrls (batch fan-out). Gaté RUN_E2E, skip gracieux.
7
- //
8
- // NB clé : `upload_file` assigne une clé UUID et la RENVOIE (il n'utilise le
9
- // chemin client que pour l'extension). Les lectures (getMetadata/createSignedUrl)
10
- // DOIVENT donc utiliser `up.data.key`, jamais le chemin logique d'origine.
11
- // ---------------------------------------------------------------------------
12
-
13
- import { describe, it, expect } from 'vitest'
14
- import { createAdminClient } from '../src/index'
15
- import type { AuraResponse } from '../src/index'
16
-
17
- const URL = process.env.AURA_E2E_URL
18
- const PROJECT = process.env.AURA_E2E_PROJECT
19
- const SERVICE = process.env.AURA_E2E_SERVICE_KEY
20
- const RUN = Boolean(process.env.RUN_E2E && URL && PROJECT && SERVICE)
21
- const TRANSIENT = new Set([408, 429, 502, 503, 504])
22
-
23
- async function retry<T>(fn: () => Promise<AuraResponse<T>>): Promise<AuraResponse<T>> {
24
- let r = await fn()
25
- for (let i = 0; i < 8 && r.error && TRANSIENT.has(r.error.status); i++) {
26
- await new Promise((res) => setTimeout(res, 1000))
27
- r = await fn()
28
- }
29
- return r
30
- }
31
-
32
- describe.runIf(RUN)('storage SDK parity E2E réel (updateBucket / metadata / createSignedUrls)', () => {
33
- it(
34
- 'updateBucket rend public ; upload metadata est relu ; createSignedUrls renvoie N URLs',
35
- async () => {
36
- const admin = createAdminClient(URL!, PROJECT!, SERVICE!)
37
- const suffix = process.env.AURA_E2E_SUFFIX ?? Math.random().toString(36).slice(2, 8)
38
- const bucket = `sbp${suffix}`
39
- const tag = `v-${suffix}`
40
- let created = false
41
- const keys: string[] = []
42
-
43
- try {
44
- const cb = await retry(() => admin.storage.createBucket(bucket, { public: false }))
45
- if (cb.error && TRANSIENT.has(cb.error.status)) {
46
- console.warn(`[storage-sdk-parity-e2e] SKIP (createBucket ${cb.error.status}).`)
47
- return
48
- }
49
- expect(cb.error, `createBucket: ${JSON.stringify(cb.error)}`).toBeNull()
50
- created = true
51
-
52
- // --- updateBucket (PATCH partiel) : privé → public -------------------
53
- const ub = await retry(() =>
54
- admin.storage.updateBucket(bucket, { public: true, fileSizeLimit: 5_000_000 }),
55
- )
56
- expect(ub.error, `updateBucket: ${JSON.stringify(ub.error)}`).toBeNull()
57
- const gb = await retry(() => admin.storage.getBucket(bucket))
58
- expect(gb.error).toBeNull()
59
- expect((gb.data as { public?: boolean } | null)?.public, 'bucket doit être public après updateBucket').toBe(true)
60
-
61
- // --- upload avec metadata → relue via getMetadata (clé RETOURNÉE) ----
62
- const up = await retry(() =>
63
- admin.storage.upload(bucket, 'f.txt', new Blob(['hello']), {
64
- contentType: 'text/plain',
65
- metadata: { tag },
66
- }),
67
- )
68
- expect(up.error, `upload metadata: ${JSON.stringify(up.error)}`).toBeNull()
69
- const keyF = (up.data as { key?: string } | null)?.key
70
- expect(keyF, 'upload doit retourner la clé stockée').toBeTruthy()
71
- keys.push(keyF!)
72
-
73
- const gm = await retry(() => admin.storage.getMetadata(bucket, keyF!))
74
- expect(gm.error, `getMetadata(${keyF}): ${JSON.stringify(gm.error)}`).toBeNull()
75
- expect(JSON.stringify(gm.data ?? {}), 'la metadata custom (tag) doit être relue').toContain(tag)
76
-
77
- // --- createSignedUrls (batch) sur les clés réelles ------------------
78
- const up2 = await retry(() =>
79
- admin.storage.upload(bucket, 'g.txt', new Blob(['g']), { contentType: 'text/plain' }),
80
- )
81
- expect(up2.error).toBeNull()
82
- const keyG = (up2.data as { key?: string } | null)?.key
83
- expect(keyG).toBeTruthy()
84
- keys.push(keyG!)
85
-
86
- const su = await retry(() => admin.storage.createSignedUrls(bucket, [keyF!, keyG!], 300))
87
- expect(su.error, `createSignedUrls: ${JSON.stringify(su.error)}`).toBeNull()
88
- const rows = su.data ?? []
89
- expect(rows.length, 'createSignedUrls doit renvoyer 2 entrées').toBe(2)
90
- expect(rows.every((r) => 'url' in r && typeof r.url === 'string' && r.url.length > 0), 'chaque entrée doit porter une URL').toBe(true)
91
- } finally {
92
- if (created) {
93
- try {
94
- if (keys.length) await admin.storage.remove(bucket, keys)
95
- await admin.storage.deleteBucket(bucket)
96
- } catch {
97
- /* best-effort */
98
- }
99
- }
100
- }
101
- },
102
- 90_000,
103
- )
104
- })