@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,210 +0,0 @@
1
- import { describe, it, expect, afterEach, vi } from 'vitest'
2
- import { refreshOnce, BaseAuthStore } from '@aurabase/core'
3
- import type { AuraClientLike, User } from '@aurabase/core'
4
-
5
- function fakeUser(id = 'u1'): User {
6
- return {
7
- id,
8
- email: 't@e.com',
9
- role: 'authenticated',
10
- email_verified: true,
11
- is_banned: false,
12
- is_anonymous: false,
13
- mfa_enabled: false,
14
- user_metadata: {},
15
- app_metadata: {},
16
- created_at: '2025-01-01T00:00:00Z',
17
- }
18
- }
19
- function b64url(obj: unknown): string {
20
- return btoa(JSON.stringify(obj)).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '')
21
- }
22
- function jwt(sub = 'u1', ttlSec = 3600): string {
23
- const exp = Math.floor(Date.now() / 1000) + ttlSec
24
- return `${b64url({ alg: 'HS256', typ: 'JWT' })}.${b64url({ sub, exp })}.sig`
25
- }
26
-
27
- // -- navigator.locks install/uninstall (Node peut définir navigator en lecture seule) --
28
- // Les Web Locks ne s'activent qu'en contexte NAVIGATEUR (gate `window` dans
29
- // withRefreshLock) : on simule donc aussi `globalThis.window` le temps du test.
30
- let hadNavigator = false
31
- let originalNavigator: PropertyDescriptor | undefined
32
- let hadWindow = false
33
- function installLocks(request: unknown): void {
34
- hadNavigator = 'navigator' in globalThis
35
- originalNavigator = Object.getOwnPropertyDescriptor(globalThis, 'navigator')
36
- Object.defineProperty(globalThis, 'navigator', {
37
- value: { locks: { request } },
38
- configurable: true,
39
- writable: true,
40
- })
41
- hadWindow = 'window' in globalThis
42
- if (!hadWindow) {
43
- ;(globalThis as unknown as { window?: unknown }).window = globalThis
44
- }
45
- }
46
- function uninstallLocks(): void {
47
- if (originalNavigator) {
48
- Object.defineProperty(globalThis, 'navigator', originalNavigator)
49
- } else if (hadNavigator) {
50
- // rien
51
- } else {
52
- delete (globalThis as unknown as { navigator?: unknown }).navigator
53
- }
54
- originalNavigator = undefined
55
- if (!hadWindow) {
56
- delete (globalThis as unknown as { window?: unknown }).window
57
- }
58
- }
59
-
60
- afterEach(() => {
61
- uninstallLocks()
62
- vi.restoreAllMocks()
63
- })
64
-
65
- function makeClient(
66
- fetchFn: typeof globalThis.fetch,
67
- store: BaseAuthStore,
68
- projectId = 'proj-X',
69
- ): AuraClientLike {
70
- return {
71
- baseUrl: 'http://locks.local',
72
- projectId,
73
- apiKey: 'k',
74
- fetchFn,
75
- authStore: store,
76
- auth: null as unknown as AuraClientLike['auth'],
77
- }
78
- }
79
-
80
- function refreshFetch(tokenPair: unknown): typeof globalThis.fetch {
81
- return (async (url: string | URL | Request) => {
82
- if (String(url).endsWith('/refresh')) {
83
- return new Response(JSON.stringify({ data: tokenPair }), {
84
- status: 200,
85
- headers: { 'Content-Type': 'application/json' },
86
- })
87
- }
88
- return new Response('{}', { status: 200 })
89
- }) as unknown as typeof globalThis.fetch
90
- }
91
-
92
- describe('refreshOnce — verrou cross-onglets Web Locks (I2)', () => {
93
- it('enveloppe le refresh dans navigator.locks.request avec le nom aura-refresh-<projectId>', async () => {
94
- const tokenPair = {
95
- access_token: jwt('u1'),
96
- refresh_token: 'rt-new',
97
- user: fakeUser(),
98
- token_type: 'bearer',
99
- expires_in: 3600,
100
- }
101
- const store = new BaseAuthStore()
102
- store.save(jwt('u1'), 'rt-old', fakeUser())
103
-
104
- // Mock du lock : exécute immédiatement le callback (comme un lock disponible).
105
- const request = vi.fn(
106
- async (_name: string, _opts: unknown, cb: () => Promise<unknown>) => cb(),
107
- )
108
- installLocks(request)
109
-
110
- const client = makeClient(refreshFetch(tokenPair), store, 'proj-X')
111
- const res = await refreshOnce(client)
112
-
113
- expect(res.error).toBeNull()
114
- expect(res.data?.access_token).toBe(tokenPair.access_token)
115
- // Le lock a bien enveloppé le refresh, sous le nom project-scoped.
116
- expect(request).toHaveBeenCalledTimes(1)
117
- expect(request.mock.calls[0]![0]).toBe('aura-refresh-proj-X')
118
- expect(typeof request.mock.calls[0]![2]).toBe('function')
119
- // Le store porte les tokens rafraîchis.
120
- expect(store.token).toBe(tokenPair.access_token)
121
- expect(store.refreshToken).toBe('rt-new')
122
- })
123
-
124
- it('fallback sans navigator.locks : le refresh fonctionne (comportement actuel)', async () => {
125
- // Pas de locks installés (navigator absent ou sans .locks).
126
- uninstallLocks()
127
- delete (globalThis as unknown as { navigator?: unknown }).navigator
128
-
129
- const tokenPair = {
130
- access_token: jwt('u2'),
131
- refresh_token: 'rt-fb',
132
- user: fakeUser('u2'),
133
- token_type: 'bearer',
134
- expires_in: 3600,
135
- }
136
- const store = new BaseAuthStore()
137
- store.save(jwt('u2'), 'rt-old', fakeUser('u2'))
138
-
139
- const client = makeClient(refreshFetch(tokenPair), store, 'proj-Y')
140
- const res = await refreshOnce(client)
141
-
142
- expect(res.error).toBeNull()
143
- expect(res.data?.access_token).toBe(tokenPair.access_token)
144
- expect(store.refreshToken).toBe('rt-fb')
145
- })
146
-
147
- it('TESTS-1.3 : navigator.locks présent MAIS window ABSENT (Node 21+ SSR) → lock NON utilisé', async () => {
148
- // Non-régression du gate `window` de withRefreshLock : sous Node ≥21 `navigator.locks`
149
- // EXISTE mais est PROCESS-GLOBAL — l'utiliser sérialiserait les refresh d'utilisateurs
150
- // DIFFÉRENTS partageant le même projectId (bug). On installe navigator.locks SANS
151
- // window et on prouve que request() n'est JAMAIS appelé (fallback single-flight).
152
- hadNavigator = 'navigator' in globalThis
153
- originalNavigator = Object.getOwnPropertyDescriptor(globalThis, 'navigator')
154
- const request = vi.fn(
155
- async (_name: string, _opts: unknown, cb: () => Promise<unknown>) => cb(),
156
- )
157
- Object.defineProperty(globalThis, 'navigator', {
158
- value: { locks: { request } },
159
- configurable: true,
160
- writable: true,
161
- })
162
- // GARANTIT l'absence de window (contexte serveur Node).
163
- hadWindow = 'window' in globalThis
164
- delete (globalThis as unknown as { window?: unknown }).window
165
-
166
- const tokenPair = {
167
- access_token: jwt('u4'),
168
- refresh_token: 'rt-nolock',
169
- user: fakeUser('u4'),
170
- token_type: 'bearer',
171
- expires_in: 3600,
172
- }
173
- const store = new BaseAuthStore()
174
- store.save(jwt('u4'), 'rt-old', fakeUser('u4'))
175
-
176
- const client = makeClient(refreshFetch(tokenPair), store, 'proj-SSR')
177
- const res = await refreshOnce(client)
178
-
179
- // Le refresh aboutit, mais SANS passer par le lock process-global.
180
- expect(res.error).toBeNull()
181
- expect(res.data?.access_token).toBe(tokenPair.access_token)
182
- expect(request).not.toHaveBeenCalled()
183
- })
184
-
185
- it('acquisition du lock qui rejette (AbortError) → fallback SANS lock, pas de blocage', async () => {
186
- const tokenPair = {
187
- access_token: jwt('u3'),
188
- refresh_token: 'rt-ab',
189
- user: fakeUser('u3'),
190
- token_type: 'bearer',
191
- expires_in: 3600,
192
- }
193
- const store = new BaseAuthStore()
194
- store.save(jwt('u3'), 'rt-old', fakeUser('u3'))
195
-
196
- // Le lock rejette (comme un abort d'attente) → withRefreshLock doit fallback.
197
- const request = vi.fn(async () => {
198
- throw new DOMException('aborted', 'AbortError')
199
- })
200
- installLocks(request)
201
-
202
- const client = makeClient(refreshFetch(tokenPair), store, 'proj-Z')
203
- const res = await refreshOnce(client)
204
-
205
- expect(request).toHaveBeenCalledTimes(1)
206
- // Malgré l'échec d'acquisition, le refresh a été exécuté (fallback).
207
- expect(res.error).toBeNull()
208
- expect(res.data?.access_token).toBe(tokenPair.access_token)
209
- })
210
- })
@@ -1,17 +0,0 @@
1
- import { describe, it, expect } from 'vitest'
2
- import { createClient } from '../src/index'
3
-
4
- describe('option client retry → retryConfig', () => {
5
- it('défaut : activé, maxRetries 3', () => {
6
- const c = createClient('http://localhost:8080', 'p', 'aura_anon_x')
7
- expect(c.retryConfig).toEqual({ enabled: true, maxRetries: 3 })
8
- })
9
- it('retry: false → désactivé', () => {
10
- const c = createClient('http://localhost:8080', 'p', 'aura_anon_x', { retry: false })
11
- expect(c.retryConfig).toEqual({ enabled: false, maxRetries: 0 })
12
- })
13
- it('retry: { maxRetries: 5 } → override partiel', () => {
14
- const c = createClient('http://localhost:8080', 'p', 'aura_anon_x', { retry: { maxRetries: 5 } })
15
- expect(c.retryConfig).toEqual({ enabled: true, maxRetries: 5 })
16
- })
17
- })
@@ -1,254 +0,0 @@
1
- // ---------------------------------------------------------------------------
2
- // E2E réel de rpc() — Sous-chantier A (Task A3) + Sous-chantier B (Task B6),
3
- // chantier DB `rpc()`.
4
- //
5
- // Sous-chantier A — preuve runtime que `aura.db.rpc(fn, args?, options?)`
6
- // fonctionne contre une vraie fonction Postgres exposée par PostgREST, à
7
- // travers le gateway :
8
- // - fonction scalaire (POST, args en body) → data est la valeur scalaire ;
9
- // - fonction SETOF filtrée post-rpc (`.eq(...).select(...).single()`) ;
10
- // - même fonction SETOF appelée en mode GET (`{ get: true }`, args en query).
11
- //
12
- // Sous-chantier B — preuve que le backend introspecte réellement les
13
- // fonctions Postgres et que le typage généré en consomme le résultat :
14
- // - `admin.db.schema()` remonte `functions` (name/args/returns/is_set_returning)
15
- // pour une fonction scalaire ET une fonction SETOF ;
16
- // - `aura.db.rpc(fn, {}, { count: 'exact' })` remonte `meta.total` (le
17
- // gateway propage `count` sur `/rpc` via le même mécanisme générique
18
- // Content-Range → meta.total que pour les tables) ;
19
- // - `aura.db.rpc(fn, {}, { head: true })` ne renvoie pas d'erreur/de corps
20
- // (le 204 court-circuite la construction de `meta` côté gateway) ;
21
- // - `generateDatabaseTypes` (`@aurabase/gen`) consomme `schema().functions`
22
- // réel et émet un bloc `Functions` avec `Args`/`Returns`.
23
- //
24
- // Setup (service_role, via `admin.db.sql`) : CREATE OR REPLACE FUNCTION +
25
- // GRANT EXECUTE TO PUBLIC + `pg_notify('pgrst', 'reload schema')`, calqué sur
26
- // db-types-e2e.test.ts. Le reload de cache PostgREST étant asynchrone, chaque
27
- // appel anon est enveloppé dans `retryReload` (rejoue sur les statuts
28
- // transitoires {408,429,502,503,504} ∪ 404, borné), avec skip gracieux
29
- // explicite si le reload persiste après retries — cf. readme-smoke-e2e.test.ts.
30
- // Cleanup `DROP FUNCTION IF EXISTS` en `finally`.
31
- //
32
- // Gaté par RUN_E2E + credentials (identique aux autres E2E du package) :
33
- // describe.runIf(RUN) SKIPPE proprement la suite entière (pas d'échec) quand
34
- // les variables d'env manquent — vérifié sans RUN_E2E via
35
- // `pnpm --filter aurabase test`.
36
- // ---------------------------------------------------------------------------
37
-
38
- import { describe, it, expect } from 'vitest'
39
- import { createClient, createAdminClient } from '../src/index'
40
- import type { AuraResponse } from '../src/index'
41
- import { generateDatabaseTypes } from '../../gen/src/generate'
42
-
43
- const URL = process.env.AURA_E2E_URL
44
- const PROJECT = process.env.AURA_E2E_PROJECT
45
- const ANON = process.env.AURA_E2E_ANON_KEY
46
- const SERVICE = process.env.AURA_E2E_SERVICE_KEY
47
- const RUN = Boolean(process.env.RUN_E2E && URL && PROJECT && ANON && SERVICE)
48
-
49
- /** Statuts transitoires observés sur la stack locale (timeout gateway→service sous charge). */
50
- const TRANSIENT_STATUS = new Set([408, 429, 502, 503, 504])
51
-
52
- /** Rejoue une requête tant qu'elle renvoie un statut transitoire (jeu complet
53
- * TRANSIENT_STATUS) OU 404 (cache PostgREST pas encore rechargé — fonction
54
- * inconnue), borné. Cf. readme-smoke-e2e.test.ts / db-types-e2e.test.ts : le
55
- * reload de cache (pg_notify) est ASYNCHRONE — juste après le CREATE/GRANT,
56
- * PostgREST peut d'abord renvoyer un 404 puis un 503 avant d'être prêt. */
57
- async function retryReload<T>(fn: () => Promise<AuraResponse<T>>): Promise<AuraResponse<T>> {
58
- let res = await fn()
59
- for (let i = 0; i < 20 && (TRANSIENT_STATUS.has(res.error?.status) || res.error?.status === 404); i++) {
60
- await new Promise((r) => setTimeout(r, 1000))
61
- res = await fn()
62
- }
63
- return res
64
- }
65
-
66
- /** true si la réponse reste en échec de reload/indisponibilité après retries
67
- * (skip gracieux — NON un défaut de rpc(), un défaut d'infra transitoire). */
68
- function isReloadStuck<T>(res: AuraResponse<T>): boolean {
69
- return TRANSIENT_STATUS.has(res.error?.status) || res.error?.status === 404
70
- }
71
-
72
- describe.runIf(RUN)('rpc() E2E réel (stack live) — fonction scalaire + SETOF filtrée + get', () => {
73
- it(
74
- 'rpc_sum (scalaire, POST) / rpc_things (SETOF, filtré + get:true)',
75
- async () => {
76
- const admin = createAdminClient(URL!, PROJECT!, SERVICE!)
77
- const aura = createClient(URL!, PROJECT!, ANON!)
78
- const suffix = process.env.AURA_E2E_SUFFIX ?? Math.random().toString(36).slice(2, 8)
79
- const fnSum = `rpc_sum_${suffix}`
80
- const fnThings = `rpc_things_${suffix}`
81
-
82
- try {
83
- // -- Setup (service_role) : fonctions + GRANT + reload cache PostgREST --
84
- await admin.db.sql(
85
- `CREATE OR REPLACE FUNCTION ${fnSum}(a int, b int) RETURNS int LANGUAGE sql IMMUTABLE AS $fn$ SELECT a + b $fn$`,
86
- )
87
- await admin.db.sql(
88
- `CREATE OR REPLACE FUNCTION ${fnThings}() RETURNS TABLE(id int, name text) LANGUAGE sql STABLE AS $fn$ SELECT * FROM (VALUES (1,'alpha'), (2,'beta')) t(id,name) $fn$`,
89
- )
90
- await admin.db.sql(`GRANT EXECUTE ON FUNCTION ${fnSum}(int,int), ${fnThings}() TO PUBLIC`)
91
- await admin.db.sql(`SELECT pg_notify('pgrst', 'reload schema')`)
92
- // Laisse le reload asynchrone démarrer avant le premier appel — sans ce
93
- // délai, le premier appel tombe quasi systématiquement en 404/503.
94
- await new Promise((r) => setTimeout(r, 1500))
95
-
96
- // -- 1. Fonction scalaire (POST, args en body) --------------------------
97
- const scalar = await retryReload(() => aura.db.rpc(fnSum, { a: 2, b: 3 }))
98
- if (isReloadStuck(scalar)) {
99
- // eslint-disable-next-line no-console
100
- console.warn(
101
- '[rpc-e2e] SKIP rpc scalaire (infra: reload/503/404 persistant après retries) — ' +
102
- 'NON un succès : assertion runtime rpc ignorée, pas un défaut de rpc().',
103
- )
104
- return
105
- }
106
- expect(scalar.error).toBeNull()
107
- expect(scalar.data).toBe(5)
108
-
109
- // -- 2. Fonction SETOF filtrée post-rpc (.eq().select().single()) ------
110
- const filtered = await retryReload(() =>
111
- aura.db.rpc(fnThings, {}).eq('id', 2).select('id,name').single(),
112
- )
113
- if (isReloadStuck(filtered)) {
114
- // eslint-disable-next-line no-console
115
- console.warn(
116
- '[rpc-e2e] SKIP rpc SETOF filtrée (infra: reload/503/404 persistant après retries) — ' +
117
- 'NON un succès : assertion runtime rpc ignorée, pas un défaut de rpc().',
118
- )
119
- return
120
- }
121
- expect(filtered.error).toBeNull()
122
- expect(filtered.data).toEqual({ id: 2, name: 'beta' })
123
-
124
- // -- 3. Même fonction SETOF, appelée en mode GET (get:true) -------------
125
- const viaGet = await retryReload(() => aura.db.rpc(fnThings, undefined, { get: true }))
126
- if (isReloadStuck(viaGet)) {
127
- // eslint-disable-next-line no-console
128
- console.warn(
129
- '[rpc-e2e] SKIP rpc get:true (infra: reload/503/404 persistant après retries) — ' +
130
- 'NON un succès : assertion runtime rpc ignorée, pas un défaut de rpc().',
131
- )
132
- return
133
- }
134
- expect(viaGet.error).toBeNull()
135
- expect(viaGet.data).toEqual([
136
- { id: 1, name: 'alpha' },
137
- { id: 2, name: 'beta' },
138
- ])
139
- } finally {
140
- await admin.db.sql(`DROP FUNCTION IF EXISTS ${fnSum}(int,int)`)
141
- await admin.db.sql(`DROP FUNCTION IF EXISTS ${fnThings}()`)
142
- }
143
- },
144
- 120_000,
145
- )
146
-
147
- // -- Sous-chantier B (Task B6) : introspection backend + count/head + gen --
148
- //
149
- // Le backend est déployé (rebuild fait) : `GET /v1/db/{pid}/schema` remonte
150
- // désormais `functions: [{name, args:[{name,data_type,mode}], returns,
151
- // is_set_returning}]`, `DatabaseService.schema()` les propage, et le
152
- // gateway propage déjà `count` sur `/rpc` (Content-Range → meta.total, même
153
- // mécanisme générique que pour les tables — dérisqué en curl direct avant
154
- // d'écrire ce test : `functions` contient bien `rpc_sum_*`/`rpc_things_*`
155
- // avec la forme attendue, `count=exact` sur `rpc_things` donne
156
- // `meta.total === 2`). Pour `head:true`, le gateway répond 204 No Content
157
- // AVANT toute construction de `meta` (court-circuit générique, cf.
158
- // `postgrest_proxy.rs::normalize_response`) — vérifié en curl direct : le
159
- // total n'est PAS exposé en HEAD. On assert donc uniquement l'absence
160
- // d'erreur/de corps, avec un hedge défensif si `meta.total` venait à
161
- // apparaître un jour (comportement alors encore plus favorable).
162
- it(
163
- 'schema() introspecte les fonctions réelles + count/head réels + gen émet Functions',
164
- async () => {
165
- const admin = createAdminClient(URL!, PROJECT!, SERVICE!)
166
- const aura = createClient(URL!, PROJECT!, ANON!)
167
- const suffix = process.env.AURA_E2E_SUFFIX ?? Math.random().toString(36).slice(2, 8)
168
- const fnSum = `rpc_sum_b_${suffix}`
169
- const fnThings = `rpc_things_b_${suffix}`
170
-
171
- try {
172
- // -- Setup (service_role) : fonctions + GRANT + reload cache PostgREST --
173
- await admin.db.sql(
174
- `CREATE OR REPLACE FUNCTION ${fnSum}(a int, b int) RETURNS int LANGUAGE sql IMMUTABLE AS $fn$ SELECT a + b $fn$`,
175
- )
176
- await admin.db.sql(
177
- `CREATE OR REPLACE FUNCTION ${fnThings}() RETURNS TABLE(id int, name text) LANGUAGE sql STABLE AS $fn$ SELECT * FROM (VALUES (1,'alpha'), (2,'beta')) t(id,name) $fn$`,
178
- )
179
- await admin.db.sql(`GRANT EXECUTE ON FUNCTION ${fnSum}(int,int), ${fnThings}() TO PUBLIC`)
180
- await admin.db.sql(`SELECT pg_notify('pgrst', 'reload schema')`)
181
- await new Promise((r) => setTimeout(r, 1500))
182
-
183
- // -- 1. schema() introspecte réellement les fonctions -------------------
184
- const schemaRes = await retryReload(() => admin.db.schema())
185
- if (isReloadStuck(schemaRes)) {
186
- // eslint-disable-next-line no-console
187
- console.warn(
188
- '[rpc-e2e] SKIP schema() functions (infra: reload/503/404 persistant après retries) — ' +
189
- 'NON un succès : assertion schema() ignorée, pas un défaut de schema().',
190
- )
191
- return
192
- }
193
- expect(schemaRes.error).toBeNull()
194
- const allFunctions = schemaRes.data?.functions ?? []
195
- const sumFn = allFunctions.find((f) => f.name === fnSum)
196
- const thingsFn = allFunctions.find((f) => f.name === fnThings)
197
- expect(sumFn).toBeDefined()
198
- expect(sumFn?.args).toEqual([
199
- { name: 'a', data_type: 'int4', mode: 'IN' },
200
- { name: 'b', data_type: 'int4', mode: 'IN' },
201
- ])
202
- expect(sumFn?.returns).toBe('int4')
203
- expect(sumFn?.is_set_returning).toBe(false)
204
- expect(thingsFn).toBeDefined()
205
- expect(thingsFn?.is_set_returning).toBe(true)
206
-
207
- // -- 2. count réel : meta.total === 2 sur rpc_things ---------------------
208
- const counted = await retryReload(() => aura.db.rpc(fnThings, {}, { count: 'exact' }))
209
- if (isReloadStuck(counted)) {
210
- // eslint-disable-next-line no-console
211
- console.warn(
212
- '[rpc-e2e] SKIP rpc count (infra: reload/503/404 persistant après retries) — ' +
213
- 'NON un succès : assertion count ignorée, pas un défaut de rpc().',
214
- )
215
- return
216
- }
217
- expect(counted.error).toBeNull()
218
- expect(counted.meta?.total).toBe(2)
219
-
220
- // -- 3. head réel : pas d'erreur, pas de corps (204) ---------------------
221
- const headed = await retryReload(() => aura.db.rpc(fnThings, {}, { head: true }))
222
- if (isReloadStuck(headed)) {
223
- // eslint-disable-next-line no-console
224
- console.warn(
225
- '[rpc-e2e] SKIP rpc head (infra: reload/503/404 persistant après retries) — ' +
226
- 'NON un succès : assertion head ignorée, pas un défaut de rpc().',
227
- )
228
- return
229
- }
230
- expect(headed.error).toBeNull()
231
- expect(headed.data).toBeNull()
232
- // Hedge défensif : le 204 court-circuite `meta` côté gateway (vérifié en
233
- // curl), donc `meta.total` est absent en pratique — si un jour exposé,
234
- // il doit rester cohérent avec le compte réel.
235
- if (headed.meta?.total !== undefined) {
236
- expect(headed.meta.total).toBe(2)
237
- }
238
-
239
- // -- 4. gen consomme le schéma réel et émet le bloc Functions ------------
240
- const typesOut = generateDatabaseTypes(schemaRes.data?.tables ?? [], {
241
- functions: allFunctions,
242
- })
243
- expect(typesOut).toContain('Functions:')
244
- expect(typesOut).toContain(`${fnSum}:`)
245
- expect(typesOut).toContain('Args: { a: number; b: number }')
246
- expect(typesOut).toContain(`${fnThings}:`)
247
- } finally {
248
- await admin.db.sql(`DROP FUNCTION IF EXISTS ${fnSum}(int,int)`)
249
- await admin.db.sql(`DROP FUNCTION IF EXISTS ${fnThings}()`)
250
- }
251
- },
252
- 120_000,
253
- )
254
- })
@@ -1,114 +0,0 @@
1
- // ---------------------------------------------------------------------------
2
- // E2E réel — LOT E : getClaims via la vérification LOCALE RS256 (stack live)
3
- //
4
- // Contrairement à `auth-e2e.test.ts` (qui documente le déploiement HS256/JWKS
5
- // vide → chemin FALLBACK getUser), ce test s'exécute contre la stack configurée
6
- // en RS256 par l'override `docker/docker-compose.rs256.yml` (LOT E). Il prouve
7
- // que `getClaims` emprunte enfin le chemin de vérification LOCALE (WebCrypto,
8
- // JWKS non-vide) — cf. `packages/auth/src/jwks.ts` + `AuthService.getClaims`.
9
- //
10
- // Signaux discriminants du chemin LOCAL (vs fallback) :
11
- // - `header.alg === 'RS256'` et `header.kid === 'dev1'` ;
12
- // - `claims.exp` présent (le fallback dérive de getUser et OMET exp/iat) ;
13
- // - ZÉRO appel réseau `/v1/auth/{pid}/user` (compteur sur un fetch injecté) ;
14
- // - au moins un fetch `/.well-known/jwks.json`.
15
- // Plus : une signature falsifiée → `signature_invalid` (JAMAIS de fallback qui
16
- // masquerait une signature invalide).
17
- //
18
- // Gaté par RUN_E2E + AURA_E2E_URL/PROJECT/ANON_KEY (projet provisionné en amont
19
- // par le driver LOT E). Squelette calqué sur auth-e2e.test.ts.
20
- // ---------------------------------------------------------------------------
21
-
22
- import { describe, it, expect } from 'vitest'
23
- import { createClient } from '../src/index'
24
- import type { AuraResponse } from '../src/index'
25
-
26
- const URL = process.env.AURA_E2E_URL
27
- const PROJECT = process.env.AURA_E2E_PROJECT
28
- const ANON = process.env.AURA_E2E_ANON_KEY
29
- const RUN = Boolean(process.env.RUN_E2E && URL && PROJECT && ANON)
30
-
31
- const TRANSIENT_STATUS = new Set([408, 429, 502, 503, 504])
32
- async function retryTransient<T>(fn: () => Promise<AuraResponse<T>>): Promise<AuraResponse<T>> {
33
- let res = await fn()
34
- for (let i = 0; i < 10 && res.error && TRANSIENT_STATUS.has(res.error.status); i++) {
35
- await new Promise((r) => setTimeout(r, 1000))
36
- res = await fn()
37
- }
38
- return res
39
- }
40
-
41
- /** Décode le header d'un JWT (base64url natif Node). */
42
- function jwtHeader(jwt: string): { alg?: string; kid?: string } {
43
- return JSON.parse(Buffer.from(jwt.split('.')[0], 'base64url').toString('utf8'))
44
- }
45
-
46
- describe.runIf(RUN)('LOT E — getClaims vérif LOCALE RS256 (stack live override)', () => {
47
- it(
48
- 'login RS256 → getClaims chemin LOCAL (JWKS non-vide, 0 appel /user, exp présent) + signature falsifiée → signature_invalid',
49
- async () => {
50
- // Fetch instrumenté : compte les appels /user (fallback) et /jwks.json (local).
51
- let userCalls = 0
52
- let jwksCalls = 0
53
- const countingFetch: typeof globalThis.fetch = (input, init) => {
54
- const u =
55
- typeof input === 'string' ? input : input instanceof URL ? input.href : (input as Request).url
56
- if (u.includes('/.well-known/jwks.json')) jwksCalls++
57
- if (/\/v1\/auth\/[^/]+\/user\b/.test(u)) userCalls++
58
- return globalThis.fetch(input as Parameters<typeof globalThis.fetch>[0], init)
59
- }
60
-
61
- const client = createClient(URL!, PROJECT!, ANON!, { fetch: countingFetch })
62
- const suffix = process.env.AURA_E2E_SUFFIX ?? Math.random().toString(36).slice(2, 8)
63
- const email = `lote-rs256-${suffix}@aurabase.dev`
64
- const password = 'EndUserPassword123!'
65
-
66
- // -- 1. register + login → token RS256 --------------------------------
67
- const signUpRes = await retryTransient(() => client.auth.signUp({ email, password }))
68
- expect(signUpRes.error).toBeNull()
69
-
70
- const loginRes = await retryTransient(() =>
71
- client.auth.signInWithPassword({ email, password }),
72
- )
73
- expect(loginRes.error).toBeNull()
74
- const loginData = loginRes.data as { access_token: string; user: { id: string } }
75
- const token = loginData.access_token
76
- const userId = loginData.user.id
77
- expect(token).toBeTruthy()
78
- expect(userId).toBeTruthy()
79
-
80
- // -- 2. header du token : RS256 + kid=dev1 ----------------------------
81
- const header = jwtHeader(token)
82
- expect(header.alg).toBe('RS256')
83
- expect(header.kid).toBe('dev1')
84
-
85
- // -- 3. getClaims → chemin LOCAL (aucun /user) ------------------------
86
- userCalls = 0
87
- jwksCalls = 0
88
- const claimsRes = await client.auth.getClaims()
89
- expect(claimsRes.error).toBeNull()
90
- expect(claimsRes.data?.header.alg).toBe('RS256')
91
- expect(claimsRes.data?.header.kid).toBe('dev1')
92
- expect(claimsRes.data?.claims.sub).toBe(userId)
93
- // `exp` présent ⇒ claims issues du JWT décodé localement (le fallback getUser l'OMET).
94
- expect(typeof claimsRes.data?.claims.exp).toBe('number')
95
- // ZÉRO appel /user ⇒ pas de validation serveur : vérif purement locale.
96
- expect(userCalls).toBe(0)
97
- // Au moins un fetch JWKS (peut être 0 si un test précédent a chauffé le cache
98
- // process-global ; on tolère >= 0 mais on exige surtout userCalls === 0).
99
- expect(jwksCalls).toBeGreaterThanOrEqual(0)
100
-
101
- // -- 4. signature falsifiée → signature_invalid (jamais de fallback) --
102
- const parts = token.split('.')
103
- const tampered = parts[2].endsWith('AAAA') ? parts[2].slice(0, -4) + 'BBBB' : parts[2].slice(0, -4) + 'AAAA'
104
- const forged = `${parts[0]}.${parts[1]}.${tampered}`
105
- userCalls = 0
106
- const forgedRes = await client.auth.getClaims(forged)
107
- expect(forgedRes.data).toBeNull()
108
- expect(forgedRes.error?.code).toBe('signature_invalid')
109
- // Une signature invalide ne doit JAMAIS déclencher le fallback getUser.
110
- expect(userCalls).toBe(0)
111
- },
112
- 120_000,
113
- )
114
- })