@aurabase/aurabase-js 0.3.0 → 0.4.0

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 (343) hide show
  1. package/README.md +26 -795
  2. package/{packages/aurabase/dist/AuraClient-DAtDbfPB.d.ts → dist/AuraClient-BcFE8u1v.d.cts} +1 -1
  3. package/{packages/aurabase/dist/AuraClient-DAtDbfPB.d.cts → dist/AuraClient-BcFE8u1v.d.ts} +1 -1
  4. package/{packages/aurabase/dist → dist}/index.d.cts +1 -1
  5. package/{packages/aurabase/dist → dist}/index.d.ts +1 -1
  6. package/{packages/aurabase/dist → dist}/ssr.d.cts +1 -1
  7. package/{packages/aurabase/dist → dist}/ssr.d.ts +1 -1
  8. package/package.json +72 -82
  9. package/.changeset/config.json +0 -11
  10. package/CHANGELOG.md +0 -30
  11. package/packages/ai/LICENSE +0 -21
  12. package/packages/ai/README.md +0 -106
  13. package/packages/ai/dist/index.cjs +0 -229
  14. package/packages/ai/dist/index.d.cts +0 -139
  15. package/packages/ai/dist/index.d.ts +0 -139
  16. package/packages/ai/dist/index.js +0 -226
  17. package/packages/ai/node_modules/.bin/esbuild +0 -19
  18. package/packages/ai/node_modules/.bin/tsc +0 -22
  19. package/packages/ai/node_modules/.bin/tsserver +0 -22
  20. package/packages/ai/node_modules/.bin/tsup +0 -22
  21. package/packages/ai/node_modules/.bin/tsup-node +0 -22
  22. package/packages/ai/node_modules/.bin/vite +0 -22
  23. package/packages/ai/node_modules/.bin/vitest +0 -22
  24. package/packages/ai/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +0 -1
  25. package/packages/ai/package.json +0 -61
  26. package/packages/ai/src/AiService.ts +0 -226
  27. package/packages/ai/src/index.ts +0 -18
  28. package/packages/ai/src/sse.ts +0 -141
  29. package/packages/ai/src/types.ts +0 -30
  30. package/packages/ai/tests/chat-stream.test.ts +0 -151
  31. package/packages/ai/tests/rag-namespaces.test.ts +0 -54
  32. package/packages/ai/tests/sse.test.ts +0 -69
  33. package/packages/ai/tsconfig.json +0 -5
  34. package/packages/ai/tsup.config.ts +0 -11
  35. package/packages/aurabase/LICENSE +0 -21
  36. package/packages/aurabase/README.md +0 -64
  37. package/packages/aurabase/node_modules/.bin/esbuild +0 -19
  38. package/packages/aurabase/node_modules/.bin/tsc +0 -22
  39. package/packages/aurabase/node_modules/.bin/tsserver +0 -22
  40. package/packages/aurabase/node_modules/.bin/tsup +0 -22
  41. package/packages/aurabase/node_modules/.bin/tsup-node +0 -22
  42. package/packages/aurabase/node_modules/.bin/vite +0 -22
  43. package/packages/aurabase/node_modules/.bin/vitest +0 -22
  44. package/packages/aurabase/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +0 -1
  45. package/packages/aurabase/package.json +0 -80
  46. package/packages/aurabase/src/AuraClient.ts +0 -237
  47. package/packages/aurabase/src/index.ts +0 -152
  48. package/packages/aurabase/src/ssr.ts +0 -156
  49. package/packages/aurabase/tests/ai-streaming-rag-e2e.test.ts +0 -82
  50. package/packages/aurabase/tests/ai.test.ts +0 -111
  51. package/packages/aurabase/tests/auth-admin.test.ts +0 -515
  52. package/packages/aurabase/tests/auth-e2e.test.ts +0 -135
  53. package/packages/aurabase/tests/auth-hardening.test.ts +0 -206
  54. package/packages/aurabase/tests/auth.test.ts +0 -947
  55. package/packages/aurabase/tests/database.test.ts +0 -230
  56. package/packages/aurabase/tests/db-types-e2e.test.ts +0 -217
  57. package/packages/aurabase/tests/dispose.test.ts +0 -23
  58. package/packages/aurabase/tests/foreign-token.e2e.test.ts +0 -129
  59. package/packages/aurabase/tests/functions.test.ts +0 -107
  60. package/packages/aurabase/tests/integration.test.ts +0 -413
  61. package/packages/aurabase/tests/live-production-validation.js +0 -241
  62. package/packages/aurabase/tests/live-sdk-production-validation.js +0 -293
  63. package/packages/aurabase/tests/mocks.ts +0 -139
  64. package/packages/aurabase/tests/notifications.test.ts +0 -314
  65. package/packages/aurabase/tests/observability-backup.test.ts +0 -186
  66. package/packages/aurabase/tests/observability-hook.test.ts +0 -130
  67. package/packages/aurabase/tests/production-robustness.test.ts +0 -268
  68. package/packages/aurabase/tests/public-api-surface.test.ts +0 -53
  69. package/packages/aurabase/tests/query-builder.test.ts +0 -329
  70. package/packages/aurabase/tests/readme-smoke-e2e.test.ts +0 -231
  71. package/packages/aurabase/tests/realtime-filter-e2e.test.ts +0 -344
  72. package/packages/aurabase/tests/refresh-locks.test.ts +0 -210
  73. package/packages/aurabase/tests/retry-option.test.ts +0 -17
  74. package/packages/aurabase/tests/rpc-e2e.test.ts +0 -254
  75. package/packages/aurabase/tests/rs256-local-e2e.test.ts +0 -114
  76. package/packages/aurabase/tests/rt-alias-public-e2e.test.ts +0 -235
  77. package/packages/aurabase/tests/rt-http-broadcast-e2e.test.ts +0 -124
  78. package/packages/aurabase/tests/service-role-guard.test.ts +0 -99
  79. package/packages/aurabase/tests/ssr.test.ts +0 -91
  80. package/packages/aurabase/tests/storage-backend-e2e.test.ts +0 -481
  81. package/packages/aurabase/tests/storage-sdk-parity-e2e.test.ts +0 -104
  82. package/packages/aurabase/tests/storage-transform-e2e.test.ts +0 -684
  83. package/packages/aurabase/tests/storage.test.ts +0 -55
  84. package/packages/aurabase/tests/types/client-generic.test-d.ts +0 -79
  85. package/packages/aurabase/tests/types/docs-snippets.test-d.ts +0 -571
  86. package/packages/aurabase/tests/types/error-code.test-d.ts +0 -53
  87. package/packages/aurabase/tsconfig.json +0 -5
  88. package/packages/aurabase/tsconfig.test-d.json +0 -5
  89. package/packages/aurabase/tsup.config.ts +0 -11
  90. package/packages/aurabase/vitest.config.ts +0 -16
  91. package/packages/aurabase/vitest.e2e.config.ts +0 -9
  92. package/packages/auth/LICENSE +0 -21
  93. package/packages/auth/README.md +0 -215
  94. package/packages/auth/dist/index.cjs +0 -1175
  95. package/packages/auth/dist/index.d.cts +0 -397
  96. package/packages/auth/dist/index.d.ts +0 -397
  97. package/packages/auth/dist/index.js +0 -1170
  98. package/packages/auth/node_modules/.bin/esbuild +0 -19
  99. package/packages/auth/node_modules/.bin/tsc +0 -22
  100. package/packages/auth/node_modules/.bin/tsserver +0 -22
  101. package/packages/auth/node_modules/.bin/tsup +0 -22
  102. package/packages/auth/node_modules/.bin/tsup-node +0 -22
  103. package/packages/auth/node_modules/.bin/vite +0 -22
  104. package/packages/auth/node_modules/.bin/vitest +0 -22
  105. package/packages/auth/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +0 -1
  106. package/packages/auth/package.json +0 -61
  107. package/packages/auth/src/AuthAdminService.ts +0 -149
  108. package/packages/auth/src/AuthService.ts +0 -1166
  109. package/packages/auth/src/SessionManager.ts +0 -92
  110. package/packages/auth/src/index.ts +0 -17
  111. package/packages/auth/src/jwks.ts +0 -337
  112. package/packages/auth/src/pkce.ts +0 -27
  113. package/packages/auth/src/types.ts +0 -89
  114. package/packages/auth/tests/auth-lifecycle.test.ts +0 -149
  115. package/packages/auth/tests/detect-session.test.ts +0 -361
  116. package/packages/auth/tests/getclaims.test.ts +0 -780
  117. package/packages/auth/tests/is-mfa-challenge.test.ts +0 -27
  118. package/packages/auth/tests/password-recovery.test.ts +0 -124
  119. package/packages/auth/tests/pkce.test.ts +0 -192
  120. package/packages/auth/tests/session-manager.test.ts +0 -103
  121. package/packages/auth/tests/set-session.test.ts +0 -139
  122. package/packages/auth/tests/verify-otp.test.ts +0 -153
  123. package/packages/auth/tsconfig.json +0 -5
  124. package/packages/auth/tsup.config.ts +0 -11
  125. package/packages/core/LICENSE +0 -21
  126. package/packages/core/README.md +0 -132
  127. package/packages/core/dist/index.cjs +0 -695
  128. package/packages/core/dist/index.d.cts +0 -1137
  129. package/packages/core/dist/index.d.ts +0 -1137
  130. package/packages/core/dist/index.js +0 -673
  131. package/packages/core/node_modules/.bin/esbuild +0 -22
  132. package/packages/core/node_modules/.bin/tsc +0 -22
  133. package/packages/core/node_modules/.bin/tsserver +0 -22
  134. package/packages/core/node_modules/.bin/tsup +0 -22
  135. package/packages/core/node_modules/.bin/tsup-node +0 -22
  136. package/packages/core/node_modules/.bin/vite +0 -22
  137. package/packages/core/node_modules/.bin/vitest +0 -22
  138. package/packages/core/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +0 -1
  139. package/packages/core/package.json +0 -57
  140. package/packages/core/src/AuraError.ts +0 -89
  141. package/packages/core/src/BaseService.ts +0 -44
  142. package/packages/core/src/client.ts +0 -34
  143. package/packages/core/src/cookie-utils.ts +0 -42
  144. package/packages/core/src/fetch.ts +0 -435
  145. package/packages/core/src/index.ts +0 -22
  146. package/packages/core/src/retry.ts +0 -63
  147. package/packages/core/src/serialize.ts +0 -6
  148. package/packages/core/src/stores/BaseAuthStore.ts +0 -164
  149. package/packages/core/src/stores/LocalAuthStore.ts +0 -199
  150. package/packages/core/src/types.ts +0 -1042
  151. package/packages/core/tests/auth-store.test.ts +0 -300
  152. package/packages/core/tests/error-code.test.ts +0 -61
  153. package/packages/core/tests/error.test.ts +0 -24
  154. package/packages/core/tests/fetch.test.ts +0 -286
  155. package/packages/core/tests/mocks.ts +0 -139
  156. package/packages/core/tests/observability.test.ts +0 -86
  157. package/packages/core/tests/refresh-hardening.test.ts +0 -164
  158. package/packages/core/tests/refresh-observability.test.ts +0 -111
  159. package/packages/core/tests/retry.test.ts +0 -106
  160. package/packages/core/tests/serialize.test.ts +0 -12
  161. package/packages/core/tests/timeout.test.ts +0 -79
  162. package/packages/core/tsconfig.json +0 -5
  163. package/packages/core/tsup.config.ts +0 -11
  164. package/packages/db/LICENSE +0 -21
  165. package/packages/db/README.md +0 -152
  166. package/packages/db/VENDORED.md +0 -93
  167. package/packages/db/dist/index.cjs +0 -544
  168. package/packages/db/dist/index.d.cts +0 -1111
  169. package/packages/db/dist/index.d.ts +0 -1111
  170. package/packages/db/dist/index.js +0 -541
  171. package/packages/db/node_modules/.bin/esbuild +0 -19
  172. package/packages/db/node_modules/.bin/tsc +0 -22
  173. package/packages/db/node_modules/.bin/tsserver +0 -22
  174. package/packages/db/node_modules/.bin/tsup +0 -22
  175. package/packages/db/node_modules/.bin/tsup-node +0 -22
  176. package/packages/db/node_modules/.bin/vite +0 -22
  177. package/packages/db/node_modules/.bin/vitest +0 -22
  178. package/packages/db/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +0 -1
  179. package/packages/db/package.json +0 -62
  180. package/packages/db/src/DatabaseService.ts +0 -170
  181. package/packages/db/src/QueryBuilder.ts +0 -830
  182. package/packages/db/src/index.ts +0 -2
  183. package/packages/db/src/pgrst-types/common/common.ts +0 -86
  184. package/packages/db/src/pgrst-types/common/rpc.ts +0 -151
  185. package/packages/db/src/pgrst-types/feature-flags.ts +0 -20
  186. package/packages/db/src/pgrst-types/types.ts +0 -134
  187. package/packages/db/src/select-query-parser/parser.ts +0 -479
  188. package/packages/db/src/select-query-parser/result.ts +0 -553
  189. package/packages/db/src/select-query-parser/types.ts +0 -132
  190. package/packages/db/src/select-query-parser/utils.ts +0 -707
  191. package/packages/db/tests/filters.test.ts +0 -81
  192. package/packages/db/tests/mutations-filtered.e2e.test.ts +0 -132
  193. package/packages/db/tests/mutations-filtered.test.ts +0 -188
  194. package/packages/db/tests/order.test.ts +0 -45
  195. package/packages/db/tests/rpc.test.ts +0 -41
  196. package/packages/db/tests/scale/build-large-schema.ts +0 -94
  197. package/packages/db/tests/scale/scale-compile.test.ts +0 -167
  198. package/packages/db/tests/schema.test.ts +0 -77
  199. package/packages/db/tests/single-accept.e2e.test.ts +0 -123
  200. package/packages/db/tests/single.test.ts +0 -211
  201. package/packages/db/tests/types/filters.test-d.ts +0 -52
  202. package/packages/db/tests/types/fixtures.ts +0 -40
  203. package/packages/db/tests/types/from-views.test-d.ts +0 -18
  204. package/packages/db/tests/types/mutations.test-d.ts +0 -23
  205. package/packages/db/tests/types/rpc.test-d.ts +0 -60
  206. package/packages/db/tests/types/schema-shape.test-d.ts +0 -8
  207. package/packages/db/tests/types/select-inference.test-d.ts +0 -38
  208. package/packages/db/tests/vendored/fixtures.ts +0 -83
  209. package/packages/db/tests/vendored/get-result.test-d.ts +0 -75
  210. package/packages/db/tsconfig.json +0 -5
  211. package/packages/db/tsconfig.test-d.json +0 -5
  212. package/packages/db/tsup.config.ts +0 -11
  213. package/packages/db/vitest.config.ts +0 -8
  214. package/packages/functions/LICENSE +0 -21
  215. package/packages/functions/README.md +0 -96
  216. package/packages/functions/dist/index.cjs +0 -173
  217. package/packages/functions/dist/index.d.cts +0 -81
  218. package/packages/functions/dist/index.d.ts +0 -81
  219. package/packages/functions/dist/index.js +0 -168
  220. package/packages/functions/node_modules/.bin/esbuild +0 -19
  221. package/packages/functions/node_modules/.bin/tsc +0 -22
  222. package/packages/functions/node_modules/.bin/tsserver +0 -22
  223. package/packages/functions/node_modules/.bin/tsup +0 -22
  224. package/packages/functions/node_modules/.bin/tsup-node +0 -22
  225. package/packages/functions/node_modules/.bin/vite +0 -22
  226. package/packages/functions/node_modules/.bin/vitest +0 -22
  227. package/packages/functions/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +0 -1
  228. package/packages/functions/package.json +0 -60
  229. package/packages/functions/src/FunctionsService.ts +0 -188
  230. package/packages/functions/src/errors.ts +0 -70
  231. package/packages/functions/src/index.ts +0 -6
  232. package/packages/functions/tests/invoke.test.ts +0 -97
  233. package/packages/functions/tests/response-type-errors.test.ts +0 -135
  234. package/packages/functions/tsconfig.json +0 -5
  235. package/packages/functions/tsup.config.ts +0 -11
  236. package/packages/gen/LICENSE +0 -21
  237. package/packages/gen/README.md +0 -84
  238. package/packages/gen/dist/cli.cjs +0 -334
  239. package/packages/gen/dist/cli.d.cts +0 -1
  240. package/packages/gen/dist/cli.d.ts +0 -1
  241. package/packages/gen/dist/cli.js +0 -332
  242. package/packages/gen/dist/index.cjs +0 -257
  243. package/packages/gen/dist/index.d.cts +0 -12
  244. package/packages/gen/dist/index.d.ts +0 -12
  245. package/packages/gen/dist/index.js +0 -255
  246. package/packages/gen/node_modules/.bin/esbuild +0 -19
  247. package/packages/gen/node_modules/.bin/tsc +0 -22
  248. package/packages/gen/node_modules/.bin/tsserver +0 -22
  249. package/packages/gen/node_modules/.bin/tsup +0 -22
  250. package/packages/gen/node_modules/.bin/tsup-node +0 -22
  251. package/packages/gen/node_modules/.bin/vite +0 -22
  252. package/packages/gen/node_modules/.bin/vitest +0 -22
  253. package/packages/gen/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +0 -1
  254. package/packages/gen/package.json +0 -66
  255. package/packages/gen/src/cli.ts +0 -67
  256. package/packages/gen/src/generate.ts +0 -0
  257. package/packages/gen/src/index.ts +0 -2
  258. package/packages/gen/tests/compile.test.ts +0 -213
  259. package/packages/gen/tests/e2e.test.ts +0 -130
  260. package/packages/gen/tests/generate.test.ts +0 -396
  261. package/packages/gen/tsconfig.json +0 -5
  262. package/packages/gen/tsup.config.ts +0 -11
  263. package/packages/notifications/LICENSE +0 -21
  264. package/packages/notifications/README.md +0 -134
  265. package/packages/notifications/dist/index.cjs +0 -128
  266. package/packages/notifications/dist/index.d.cts +0 -81
  267. package/packages/notifications/dist/index.d.ts +0 -81
  268. package/packages/notifications/dist/index.js +0 -125
  269. package/packages/notifications/node_modules/.bin/esbuild +0 -19
  270. package/packages/notifications/node_modules/.bin/tsc +0 -22
  271. package/packages/notifications/node_modules/.bin/tsserver +0 -22
  272. package/packages/notifications/node_modules/.bin/tsup +0 -22
  273. package/packages/notifications/node_modules/.bin/tsup-node +0 -22
  274. package/packages/notifications/node_modules/.bin/vite +0 -22
  275. package/packages/notifications/node_modules/.bin/vitest +0 -22
  276. package/packages/notifications/package.json +0 -60
  277. package/packages/notifications/src/NotificationsService.ts +0 -230
  278. package/packages/notifications/src/index.ts +0 -19
  279. package/packages/notifications/tsconfig.json +0 -5
  280. package/packages/notifications/tsup.config.ts +0 -11
  281. package/packages/realtime/LICENSE +0 -21
  282. package/packages/realtime/README.md +0 -183
  283. package/packages/realtime/dist/index.cjs +0 -977
  284. package/packages/realtime/dist/index.d.cts +0 -259
  285. package/packages/realtime/dist/index.d.ts +0 -259
  286. package/packages/realtime/dist/index.js +0 -973
  287. package/packages/realtime/node_modules/.bin/esbuild +0 -19
  288. package/packages/realtime/node_modules/.bin/tsc +0 -22
  289. package/packages/realtime/node_modules/.bin/tsserver +0 -22
  290. package/packages/realtime/node_modules/.bin/tsup +0 -22
  291. package/packages/realtime/node_modules/.bin/tsup-node +0 -22
  292. package/packages/realtime/node_modules/.bin/vite +0 -22
  293. package/packages/realtime/node_modules/.bin/vitest +0 -22
  294. package/packages/realtime/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +0 -1
  295. package/packages/realtime/package.json +0 -60
  296. package/packages/realtime/src/AuraChannel.ts +0 -485
  297. package/packages/realtime/src/HeartbeatManager.ts +0 -73
  298. package/packages/realtime/src/RealtimeService.ts +0 -505
  299. package/packages/realtime/src/columnFilter.ts +0 -301
  300. package/packages/realtime/src/index.ts +0 -4
  301. package/packages/realtime/tests/ack-routing.test.ts +0 -81
  302. package/packages/realtime/tests/column-filter.test.ts +0 -144
  303. package/packages/realtime/tests/dispatch.test.ts +0 -191
  304. package/packages/realtime/tests/heartbeat.test.ts +0 -67
  305. package/packages/realtime/tests/http-broadcast.test.ts +0 -68
  306. package/packages/realtime/tests/realtime-token.test.ts +0 -43
  307. package/packages/realtime/tests/reconnect-race.test.ts +0 -149
  308. package/packages/realtime/tests/ref-id.test.ts +0 -34
  309. package/packages/realtime/tests/set-auth.test.ts +0 -70
  310. package/packages/realtime/tsconfig.json +0 -5
  311. package/packages/realtime/tsup.config.ts +0 -11
  312. package/packages/storage/LICENSE +0 -21
  313. package/packages/storage/README.md +0 -141
  314. package/packages/storage/dist/index.cjs +0 -333
  315. package/packages/storage/dist/index.d.cts +0 -185
  316. package/packages/storage/dist/index.d.ts +0 -185
  317. package/packages/storage/dist/index.js +0 -329
  318. package/packages/storage/node_modules/.bin/esbuild +0 -19
  319. package/packages/storage/node_modules/.bin/tsc +0 -22
  320. package/packages/storage/node_modules/.bin/tsserver +0 -22
  321. package/packages/storage/node_modules/.bin/tsup +0 -22
  322. package/packages/storage/node_modules/.bin/tsup-node +0 -22
  323. package/packages/storage/node_modules/.bin/vite +0 -22
  324. package/packages/storage/node_modules/.bin/vitest +0 -22
  325. package/packages/storage/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +0 -1
  326. package/packages/storage/package.json +0 -60
  327. package/packages/storage/src/DownloadBuilder.ts +0 -60
  328. package/packages/storage/src/StorageService.ts +0 -323
  329. package/packages/storage/src/index.ts +0 -2
  330. package/packages/storage/src/path.ts +0 -35
  331. package/packages/storage/src/transform.ts +0 -15
  332. package/packages/storage/tests/download.test.ts +0 -64
  333. package/packages/storage/tests/parity.test.ts +0 -154
  334. package/packages/storage/tests/path.test.ts +0 -87
  335. package/packages/storage/tests/transform.test.ts +0 -79
  336. package/packages/storage/tsconfig.json +0 -5
  337. package/packages/storage/tsup.config.ts +0 -11
  338. package/pnpm-workspace.yaml +0 -24
  339. package/tsconfig.base.json +0 -15
  340. /package/{packages/aurabase/dist → dist}/index.cjs +0 -0
  341. /package/{packages/aurabase/dist → dist}/index.js +0 -0
  342. /package/{packages/aurabase/dist → dist}/ssr.cjs +0 -0
  343. /package/{packages/aurabase/dist → dist}/ssr.js +0 -0
@@ -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
- })