@aurabase/aurabase-js 0.3.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 (344) hide show
  1. package/.changeset/config.json +11 -0
  2. package/CHANGELOG.md +30 -0
  3. package/LICENSE +21 -0
  4. package/README.md +833 -0
  5. package/package.json +90 -0
  6. package/packages/ai/LICENSE +21 -0
  7. package/packages/ai/README.md +106 -0
  8. package/packages/ai/dist/index.cjs +229 -0
  9. package/packages/ai/dist/index.d.cts +139 -0
  10. package/packages/ai/dist/index.d.ts +139 -0
  11. package/packages/ai/dist/index.js +226 -0
  12. package/packages/ai/node_modules/.bin/esbuild +19 -0
  13. package/packages/ai/node_modules/.bin/tsc +22 -0
  14. package/packages/ai/node_modules/.bin/tsserver +22 -0
  15. package/packages/ai/node_modules/.bin/tsup +22 -0
  16. package/packages/ai/node_modules/.bin/tsup-node +22 -0
  17. package/packages/ai/node_modules/.bin/vite +22 -0
  18. package/packages/ai/node_modules/.bin/vitest +22 -0
  19. package/packages/ai/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
  20. package/packages/ai/package.json +61 -0
  21. package/packages/ai/src/AiService.ts +226 -0
  22. package/packages/ai/src/index.ts +18 -0
  23. package/packages/ai/src/sse.ts +141 -0
  24. package/packages/ai/src/types.ts +30 -0
  25. package/packages/ai/tests/chat-stream.test.ts +151 -0
  26. package/packages/ai/tests/rag-namespaces.test.ts +54 -0
  27. package/packages/ai/tests/sse.test.ts +69 -0
  28. package/packages/ai/tsconfig.json +5 -0
  29. package/packages/ai/tsup.config.ts +11 -0
  30. package/packages/aurabase/LICENSE +21 -0
  31. package/packages/aurabase/README.md +64 -0
  32. package/packages/aurabase/dist/AuraClient-DAtDbfPB.d.cts +77 -0
  33. package/packages/aurabase/dist/AuraClient-DAtDbfPB.d.ts +77 -0
  34. package/packages/aurabase/dist/index.cjs +237 -0
  35. package/packages/aurabase/dist/index.d.cts +46 -0
  36. package/packages/aurabase/dist/index.d.ts +46 -0
  37. package/packages/aurabase/dist/index.js +177 -0
  38. package/packages/aurabase/dist/ssr.cjs +224 -0
  39. package/packages/aurabase/dist/ssr.d.cts +65 -0
  40. package/packages/aurabase/dist/ssr.d.ts +65 -0
  41. package/packages/aurabase/dist/ssr.js +214 -0
  42. package/packages/aurabase/node_modules/.bin/esbuild +19 -0
  43. package/packages/aurabase/node_modules/.bin/tsc +22 -0
  44. package/packages/aurabase/node_modules/.bin/tsserver +22 -0
  45. package/packages/aurabase/node_modules/.bin/tsup +22 -0
  46. package/packages/aurabase/node_modules/.bin/tsup-node +22 -0
  47. package/packages/aurabase/node_modules/.bin/vite +22 -0
  48. package/packages/aurabase/node_modules/.bin/vitest +22 -0
  49. package/packages/aurabase/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
  50. package/packages/aurabase/package.json +80 -0
  51. package/packages/aurabase/src/AuraClient.ts +237 -0
  52. package/packages/aurabase/src/index.ts +152 -0
  53. package/packages/aurabase/src/ssr.ts +156 -0
  54. package/packages/aurabase/tests/ai-streaming-rag-e2e.test.ts +82 -0
  55. package/packages/aurabase/tests/ai.test.ts +111 -0
  56. package/packages/aurabase/tests/auth-admin.test.ts +515 -0
  57. package/packages/aurabase/tests/auth-e2e.test.ts +135 -0
  58. package/packages/aurabase/tests/auth-hardening.test.ts +206 -0
  59. package/packages/aurabase/tests/auth.test.ts +947 -0
  60. package/packages/aurabase/tests/database.test.ts +230 -0
  61. package/packages/aurabase/tests/db-types-e2e.test.ts +217 -0
  62. package/packages/aurabase/tests/dispose.test.ts +23 -0
  63. package/packages/aurabase/tests/foreign-token.e2e.test.ts +129 -0
  64. package/packages/aurabase/tests/functions.test.ts +107 -0
  65. package/packages/aurabase/tests/integration.test.ts +413 -0
  66. package/packages/aurabase/tests/live-production-validation.js +241 -0
  67. package/packages/aurabase/tests/live-sdk-production-validation.js +293 -0
  68. package/packages/aurabase/tests/mocks.ts +139 -0
  69. package/packages/aurabase/tests/notifications.test.ts +314 -0
  70. package/packages/aurabase/tests/observability-backup.test.ts +186 -0
  71. package/packages/aurabase/tests/observability-hook.test.ts +130 -0
  72. package/packages/aurabase/tests/production-robustness.test.ts +268 -0
  73. package/packages/aurabase/tests/public-api-surface.test.ts +53 -0
  74. package/packages/aurabase/tests/query-builder.test.ts +329 -0
  75. package/packages/aurabase/tests/readme-smoke-e2e.test.ts +231 -0
  76. package/packages/aurabase/tests/realtime-filter-e2e.test.ts +344 -0
  77. package/packages/aurabase/tests/refresh-locks.test.ts +210 -0
  78. package/packages/aurabase/tests/retry-option.test.ts +17 -0
  79. package/packages/aurabase/tests/rpc-e2e.test.ts +254 -0
  80. package/packages/aurabase/tests/rs256-local-e2e.test.ts +114 -0
  81. package/packages/aurabase/tests/rt-alias-public-e2e.test.ts +235 -0
  82. package/packages/aurabase/tests/rt-http-broadcast-e2e.test.ts +124 -0
  83. package/packages/aurabase/tests/service-role-guard.test.ts +99 -0
  84. package/packages/aurabase/tests/ssr.test.ts +91 -0
  85. package/packages/aurabase/tests/storage-backend-e2e.test.ts +481 -0
  86. package/packages/aurabase/tests/storage-sdk-parity-e2e.test.ts +104 -0
  87. package/packages/aurabase/tests/storage-transform-e2e.test.ts +684 -0
  88. package/packages/aurabase/tests/storage.test.ts +55 -0
  89. package/packages/aurabase/tests/types/client-generic.test-d.ts +79 -0
  90. package/packages/aurabase/tests/types/docs-snippets.test-d.ts +571 -0
  91. package/packages/aurabase/tests/types/error-code.test-d.ts +53 -0
  92. package/packages/aurabase/tsconfig.json +5 -0
  93. package/packages/aurabase/tsconfig.test-d.json +5 -0
  94. package/packages/aurabase/tsup.config.ts +11 -0
  95. package/packages/aurabase/vitest.config.ts +16 -0
  96. package/packages/aurabase/vitest.e2e.config.ts +9 -0
  97. package/packages/auth/LICENSE +21 -0
  98. package/packages/auth/README.md +215 -0
  99. package/packages/auth/dist/index.cjs +1175 -0
  100. package/packages/auth/dist/index.d.cts +397 -0
  101. package/packages/auth/dist/index.d.ts +397 -0
  102. package/packages/auth/dist/index.js +1170 -0
  103. package/packages/auth/node_modules/.bin/esbuild +19 -0
  104. package/packages/auth/node_modules/.bin/tsc +22 -0
  105. package/packages/auth/node_modules/.bin/tsserver +22 -0
  106. package/packages/auth/node_modules/.bin/tsup +22 -0
  107. package/packages/auth/node_modules/.bin/tsup-node +22 -0
  108. package/packages/auth/node_modules/.bin/vite +22 -0
  109. package/packages/auth/node_modules/.bin/vitest +22 -0
  110. package/packages/auth/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
  111. package/packages/auth/package.json +61 -0
  112. package/packages/auth/src/AuthAdminService.ts +149 -0
  113. package/packages/auth/src/AuthService.ts +1166 -0
  114. package/packages/auth/src/SessionManager.ts +92 -0
  115. package/packages/auth/src/index.ts +17 -0
  116. package/packages/auth/src/jwks.ts +337 -0
  117. package/packages/auth/src/pkce.ts +27 -0
  118. package/packages/auth/src/types.ts +89 -0
  119. package/packages/auth/tests/auth-lifecycle.test.ts +149 -0
  120. package/packages/auth/tests/detect-session.test.ts +361 -0
  121. package/packages/auth/tests/getclaims.test.ts +780 -0
  122. package/packages/auth/tests/is-mfa-challenge.test.ts +27 -0
  123. package/packages/auth/tests/password-recovery.test.ts +124 -0
  124. package/packages/auth/tests/pkce.test.ts +192 -0
  125. package/packages/auth/tests/session-manager.test.ts +103 -0
  126. package/packages/auth/tests/set-session.test.ts +139 -0
  127. package/packages/auth/tests/verify-otp.test.ts +153 -0
  128. package/packages/auth/tsconfig.json +5 -0
  129. package/packages/auth/tsup.config.ts +11 -0
  130. package/packages/core/LICENSE +21 -0
  131. package/packages/core/README.md +132 -0
  132. package/packages/core/dist/index.cjs +695 -0
  133. package/packages/core/dist/index.d.cts +1137 -0
  134. package/packages/core/dist/index.d.ts +1137 -0
  135. package/packages/core/dist/index.js +673 -0
  136. package/packages/core/node_modules/.bin/esbuild +22 -0
  137. package/packages/core/node_modules/.bin/tsc +22 -0
  138. package/packages/core/node_modules/.bin/tsserver +22 -0
  139. package/packages/core/node_modules/.bin/tsup +22 -0
  140. package/packages/core/node_modules/.bin/tsup-node +22 -0
  141. package/packages/core/node_modules/.bin/vite +22 -0
  142. package/packages/core/node_modules/.bin/vitest +22 -0
  143. package/packages/core/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
  144. package/packages/core/package.json +57 -0
  145. package/packages/core/src/AuraError.ts +89 -0
  146. package/packages/core/src/BaseService.ts +44 -0
  147. package/packages/core/src/client.ts +34 -0
  148. package/packages/core/src/cookie-utils.ts +42 -0
  149. package/packages/core/src/fetch.ts +435 -0
  150. package/packages/core/src/index.ts +22 -0
  151. package/packages/core/src/retry.ts +63 -0
  152. package/packages/core/src/serialize.ts +6 -0
  153. package/packages/core/src/stores/BaseAuthStore.ts +164 -0
  154. package/packages/core/src/stores/LocalAuthStore.ts +199 -0
  155. package/packages/core/src/types.ts +1042 -0
  156. package/packages/core/tests/auth-store.test.ts +300 -0
  157. package/packages/core/tests/error-code.test.ts +61 -0
  158. package/packages/core/tests/error.test.ts +24 -0
  159. package/packages/core/tests/fetch.test.ts +286 -0
  160. package/packages/core/tests/mocks.ts +139 -0
  161. package/packages/core/tests/observability.test.ts +86 -0
  162. package/packages/core/tests/refresh-hardening.test.ts +164 -0
  163. package/packages/core/tests/refresh-observability.test.ts +111 -0
  164. package/packages/core/tests/retry.test.ts +106 -0
  165. package/packages/core/tests/serialize.test.ts +12 -0
  166. package/packages/core/tests/timeout.test.ts +79 -0
  167. package/packages/core/tsconfig.json +5 -0
  168. package/packages/core/tsup.config.ts +11 -0
  169. package/packages/db/LICENSE +21 -0
  170. package/packages/db/README.md +152 -0
  171. package/packages/db/VENDORED.md +93 -0
  172. package/packages/db/dist/index.cjs +544 -0
  173. package/packages/db/dist/index.d.cts +1111 -0
  174. package/packages/db/dist/index.d.ts +1111 -0
  175. package/packages/db/dist/index.js +541 -0
  176. package/packages/db/node_modules/.bin/esbuild +19 -0
  177. package/packages/db/node_modules/.bin/tsc +22 -0
  178. package/packages/db/node_modules/.bin/tsserver +22 -0
  179. package/packages/db/node_modules/.bin/tsup +22 -0
  180. package/packages/db/node_modules/.bin/tsup-node +22 -0
  181. package/packages/db/node_modules/.bin/vite +22 -0
  182. package/packages/db/node_modules/.bin/vitest +22 -0
  183. package/packages/db/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
  184. package/packages/db/package.json +62 -0
  185. package/packages/db/src/DatabaseService.ts +170 -0
  186. package/packages/db/src/QueryBuilder.ts +830 -0
  187. package/packages/db/src/index.ts +2 -0
  188. package/packages/db/src/pgrst-types/common/common.ts +86 -0
  189. package/packages/db/src/pgrst-types/common/rpc.ts +151 -0
  190. package/packages/db/src/pgrst-types/feature-flags.ts +20 -0
  191. package/packages/db/src/pgrst-types/types.ts +134 -0
  192. package/packages/db/src/select-query-parser/parser.ts +479 -0
  193. package/packages/db/src/select-query-parser/result.ts +553 -0
  194. package/packages/db/src/select-query-parser/types.ts +132 -0
  195. package/packages/db/src/select-query-parser/utils.ts +707 -0
  196. package/packages/db/tests/filters.test.ts +81 -0
  197. package/packages/db/tests/mutations-filtered.e2e.test.ts +132 -0
  198. package/packages/db/tests/mutations-filtered.test.ts +188 -0
  199. package/packages/db/tests/order.test.ts +45 -0
  200. package/packages/db/tests/rpc.test.ts +41 -0
  201. package/packages/db/tests/scale/build-large-schema.ts +94 -0
  202. package/packages/db/tests/scale/scale-compile.test.ts +167 -0
  203. package/packages/db/tests/schema.test.ts +77 -0
  204. package/packages/db/tests/single-accept.e2e.test.ts +123 -0
  205. package/packages/db/tests/single.test.ts +211 -0
  206. package/packages/db/tests/types/filters.test-d.ts +52 -0
  207. package/packages/db/tests/types/fixtures.ts +40 -0
  208. package/packages/db/tests/types/from-views.test-d.ts +18 -0
  209. package/packages/db/tests/types/mutations.test-d.ts +23 -0
  210. package/packages/db/tests/types/rpc.test-d.ts +60 -0
  211. package/packages/db/tests/types/schema-shape.test-d.ts +8 -0
  212. package/packages/db/tests/types/select-inference.test-d.ts +38 -0
  213. package/packages/db/tests/vendored/fixtures.ts +83 -0
  214. package/packages/db/tests/vendored/get-result.test-d.ts +75 -0
  215. package/packages/db/tsconfig.json +5 -0
  216. package/packages/db/tsconfig.test-d.json +5 -0
  217. package/packages/db/tsup.config.ts +11 -0
  218. package/packages/db/vitest.config.ts +8 -0
  219. package/packages/functions/LICENSE +21 -0
  220. package/packages/functions/README.md +96 -0
  221. package/packages/functions/dist/index.cjs +173 -0
  222. package/packages/functions/dist/index.d.cts +81 -0
  223. package/packages/functions/dist/index.d.ts +81 -0
  224. package/packages/functions/dist/index.js +168 -0
  225. package/packages/functions/node_modules/.bin/esbuild +19 -0
  226. package/packages/functions/node_modules/.bin/tsc +22 -0
  227. package/packages/functions/node_modules/.bin/tsserver +22 -0
  228. package/packages/functions/node_modules/.bin/tsup +22 -0
  229. package/packages/functions/node_modules/.bin/tsup-node +22 -0
  230. package/packages/functions/node_modules/.bin/vite +22 -0
  231. package/packages/functions/node_modules/.bin/vitest +22 -0
  232. package/packages/functions/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
  233. package/packages/functions/package.json +60 -0
  234. package/packages/functions/src/FunctionsService.ts +188 -0
  235. package/packages/functions/src/errors.ts +70 -0
  236. package/packages/functions/src/index.ts +6 -0
  237. package/packages/functions/tests/invoke.test.ts +97 -0
  238. package/packages/functions/tests/response-type-errors.test.ts +135 -0
  239. package/packages/functions/tsconfig.json +5 -0
  240. package/packages/functions/tsup.config.ts +11 -0
  241. package/packages/gen/LICENSE +21 -0
  242. package/packages/gen/README.md +84 -0
  243. package/packages/gen/dist/cli.cjs +334 -0
  244. package/packages/gen/dist/cli.d.cts +1 -0
  245. package/packages/gen/dist/cli.d.ts +1 -0
  246. package/packages/gen/dist/cli.js +332 -0
  247. package/packages/gen/dist/index.cjs +257 -0
  248. package/packages/gen/dist/index.d.cts +12 -0
  249. package/packages/gen/dist/index.d.ts +12 -0
  250. package/packages/gen/dist/index.js +255 -0
  251. package/packages/gen/node_modules/.bin/esbuild +19 -0
  252. package/packages/gen/node_modules/.bin/tsc +22 -0
  253. package/packages/gen/node_modules/.bin/tsserver +22 -0
  254. package/packages/gen/node_modules/.bin/tsup +22 -0
  255. package/packages/gen/node_modules/.bin/tsup-node +22 -0
  256. package/packages/gen/node_modules/.bin/vite +22 -0
  257. package/packages/gen/node_modules/.bin/vitest +22 -0
  258. package/packages/gen/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
  259. package/packages/gen/package.json +66 -0
  260. package/packages/gen/src/cli.ts +67 -0
  261. package/packages/gen/src/generate.ts +0 -0
  262. package/packages/gen/src/index.ts +2 -0
  263. package/packages/gen/tests/compile.test.ts +213 -0
  264. package/packages/gen/tests/e2e.test.ts +130 -0
  265. package/packages/gen/tests/generate.test.ts +396 -0
  266. package/packages/gen/tsconfig.json +5 -0
  267. package/packages/gen/tsup.config.ts +11 -0
  268. package/packages/notifications/LICENSE +21 -0
  269. package/packages/notifications/README.md +134 -0
  270. package/packages/notifications/dist/index.cjs +128 -0
  271. package/packages/notifications/dist/index.d.cts +81 -0
  272. package/packages/notifications/dist/index.d.ts +81 -0
  273. package/packages/notifications/dist/index.js +125 -0
  274. package/packages/notifications/node_modules/.bin/esbuild +19 -0
  275. package/packages/notifications/node_modules/.bin/tsc +22 -0
  276. package/packages/notifications/node_modules/.bin/tsserver +22 -0
  277. package/packages/notifications/node_modules/.bin/tsup +22 -0
  278. package/packages/notifications/node_modules/.bin/tsup-node +22 -0
  279. package/packages/notifications/node_modules/.bin/vite +22 -0
  280. package/packages/notifications/node_modules/.bin/vitest +22 -0
  281. package/packages/notifications/package.json +60 -0
  282. package/packages/notifications/src/NotificationsService.ts +230 -0
  283. package/packages/notifications/src/index.ts +19 -0
  284. package/packages/notifications/tsconfig.json +5 -0
  285. package/packages/notifications/tsup.config.ts +11 -0
  286. package/packages/realtime/LICENSE +21 -0
  287. package/packages/realtime/README.md +183 -0
  288. package/packages/realtime/dist/index.cjs +977 -0
  289. package/packages/realtime/dist/index.d.cts +259 -0
  290. package/packages/realtime/dist/index.d.ts +259 -0
  291. package/packages/realtime/dist/index.js +973 -0
  292. package/packages/realtime/node_modules/.bin/esbuild +19 -0
  293. package/packages/realtime/node_modules/.bin/tsc +22 -0
  294. package/packages/realtime/node_modules/.bin/tsserver +22 -0
  295. package/packages/realtime/node_modules/.bin/tsup +22 -0
  296. package/packages/realtime/node_modules/.bin/tsup-node +22 -0
  297. package/packages/realtime/node_modules/.bin/vite +22 -0
  298. package/packages/realtime/node_modules/.bin/vitest +22 -0
  299. package/packages/realtime/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
  300. package/packages/realtime/package.json +60 -0
  301. package/packages/realtime/src/AuraChannel.ts +485 -0
  302. package/packages/realtime/src/HeartbeatManager.ts +73 -0
  303. package/packages/realtime/src/RealtimeService.ts +505 -0
  304. package/packages/realtime/src/columnFilter.ts +301 -0
  305. package/packages/realtime/src/index.ts +4 -0
  306. package/packages/realtime/tests/ack-routing.test.ts +81 -0
  307. package/packages/realtime/tests/column-filter.test.ts +144 -0
  308. package/packages/realtime/tests/dispatch.test.ts +191 -0
  309. package/packages/realtime/tests/heartbeat.test.ts +67 -0
  310. package/packages/realtime/tests/http-broadcast.test.ts +68 -0
  311. package/packages/realtime/tests/realtime-token.test.ts +43 -0
  312. package/packages/realtime/tests/reconnect-race.test.ts +149 -0
  313. package/packages/realtime/tests/ref-id.test.ts +34 -0
  314. package/packages/realtime/tests/set-auth.test.ts +70 -0
  315. package/packages/realtime/tsconfig.json +5 -0
  316. package/packages/realtime/tsup.config.ts +11 -0
  317. package/packages/storage/LICENSE +21 -0
  318. package/packages/storage/README.md +141 -0
  319. package/packages/storage/dist/index.cjs +333 -0
  320. package/packages/storage/dist/index.d.cts +185 -0
  321. package/packages/storage/dist/index.d.ts +185 -0
  322. package/packages/storage/dist/index.js +329 -0
  323. package/packages/storage/node_modules/.bin/esbuild +19 -0
  324. package/packages/storage/node_modules/.bin/tsc +22 -0
  325. package/packages/storage/node_modules/.bin/tsserver +22 -0
  326. package/packages/storage/node_modules/.bin/tsup +22 -0
  327. package/packages/storage/node_modules/.bin/tsup-node +22 -0
  328. package/packages/storage/node_modules/.bin/vite +22 -0
  329. package/packages/storage/node_modules/.bin/vitest +22 -0
  330. package/packages/storage/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
  331. package/packages/storage/package.json +60 -0
  332. package/packages/storage/src/DownloadBuilder.ts +60 -0
  333. package/packages/storage/src/StorageService.ts +323 -0
  334. package/packages/storage/src/index.ts +2 -0
  335. package/packages/storage/src/path.ts +35 -0
  336. package/packages/storage/src/transform.ts +15 -0
  337. package/packages/storage/tests/download.test.ts +64 -0
  338. package/packages/storage/tests/parity.test.ts +154 -0
  339. package/packages/storage/tests/path.test.ts +87 -0
  340. package/packages/storage/tests/transform.test.ts +79 -0
  341. package/packages/storage/tsconfig.json +5 -0
  342. package/packages/storage/tsup.config.ts +11 -0
  343. package/pnpm-workspace.yaml +24 -0
  344. package/tsconfig.base.json +15 -0
@@ -0,0 +1,188 @@
1
+ import { BaseService, AuraError, isTokenExpired, refreshOnce, isAbortError } from '@aurabase/core'
2
+ import type { AuraResponse, CronJob, FunctionDef, Job } from '@aurabase/core'
3
+ import type { AuraClientLike } from '@aurabase/core'
4
+ import { FunctionsRelayError, toFunctionsError } from './errors'
5
+
6
+ /** Type de réponse attendu de l'invocation (parité `@supabase/functions-js`). */
7
+ export type FunctionsResponseType = 'json' | 'text' | 'blob' | 'arrayBuffer'
8
+
9
+ export class FunctionsService extends BaseService {
10
+ constructor(client: AuraClientLike) {
11
+ super(client)
12
+ }
13
+
14
+ private get prefix(): string {
15
+ return `/v1/functions/${this.client.projectId}`
16
+ }
17
+
18
+ // -- Function invocation ----------------------------------------------------
19
+
20
+ /**
21
+ * Invoque une edge function.
22
+ *
23
+ * `responseType` (parité `@supabase/functions-js`, défaut `'json'`) :
24
+ * - `'json'` : chemin PIPELINE inchangé (refresh proactif centralisé, injection
25
+ * apikey/Authorization, dé-wrapping `{data,meta}`, retryConfig). Non-régression.
26
+ * - `'text' | 'blob' | 'arrayBuffer'` : chemin TRANSPORT BRUT `client.fetchFn`
27
+ * (patron `StorageService`, SANS toucher `core/fetch.ts`) — refresh proactif
28
+ * manuel, pose de `Authorization`/`apikey`, puis `res.text()/blob()/arrayBuffer()`
29
+ * sans dé-wrapping (le corps HTTP est renvoyé tel quel).
30
+ *
31
+ * Erreurs typées (parité) : une réponse HTTP non-2xx → `FunctionsHttpError`, une
32
+ * panne de relais/infra (réseau, 502/503/504) → `FunctionsRelayError` ; les deux
33
+ * sous-classent `AuraError` (rétrocompat `isAuraError`/champ `error`). `timeout`/
34
+ * `signal` continuent de produire le code `timeout`.
35
+ */
36
+ async invoke<T = unknown>(
37
+ slug: string,
38
+ options?: {
39
+ body?: unknown
40
+ method?: string
41
+ path?: string
42
+ headers?: Record<string, string>
43
+ signal?: AbortSignal
44
+ timeout?: number
45
+ responseType?: FunctionsResponseType
46
+ },
47
+ ): Promise<AuraResponse<T>> {
48
+ const controller = new AbortController()
49
+ let timeoutId: ReturnType<typeof setTimeout> | undefined
50
+ const userSignal = options?.signal
51
+ const onAbort = () => controller.abort()
52
+ if (options?.timeout) timeoutId = setTimeout(() => controller.abort(), options.timeout)
53
+ if (userSignal) {
54
+ // Un signal déjà avorté à l'entrée doit couper immédiatement (addEventListener ne
55
+ // rejouerait pas un 'abort' déjà émis).
56
+ if (userSignal.aborted) controller.abort()
57
+ else userSignal.addEventListener('abort', onAbort, { once: true })
58
+ }
59
+ // Nettoyage exécuté en succès ET en erreur — évite de fuir le listener quand l'appelant
60
+ // réutilise un même AbortSignal longue-durée sur plusieurs invoke().
61
+ const cleanup = () => {
62
+ if (timeoutId) clearTimeout(timeoutId)
63
+ if (userSignal) userSignal.removeEventListener('abort', onAbort)
64
+ }
65
+
66
+ const envelope = { method: options?.method, path: options?.path, headers: options?.headers, body: options?.body }
67
+ const responseType = options?.responseType ?? 'json'
68
+ const timeoutError = (): AuraResponse<T> => ({
69
+ data: null,
70
+ error: new AuraError(0, {
71
+ error: { code: 'timeout', message: 'Function invocation aborted or timed out' },
72
+ }),
73
+ })
74
+
75
+ try {
76
+ if (responseType === 'json') {
77
+ // Passe par le pipeline unifié (fetchWithAuth via BaseService.request) : refresh
78
+ // proactif à marge CENTRALISÉE, injection apikey/Authorization, dé-wrapping
79
+ // `{data,meta}` et respect de `retryConfig`. Un POST n'est jamais rejoué.
80
+ const res = await this.request<T>('POST', `${this.prefix}/${slug}/invoke`, envelope, {
81
+ signal: controller.signal,
82
+ })
83
+ if (res.error && controller.signal.aborted) return timeoutError()
84
+ // Taxonomie d'erreurs : mappe une erreur HTTP vers FunctionsHttpError/RelayError.
85
+ if (res.error) return { data: null, error: toFunctionsError(res.error) }
86
+ return res
87
+ }
88
+
89
+ // ── Chemin transport BRUT (text/blob/arrayBuffer) ──────────────────────
90
+ const client = this.client
91
+ const store = client.authStore
92
+ if (store.token && store.refreshToken && isTokenExpired(store.token, 30)) {
93
+ await refreshOnce(client)
94
+ }
95
+ const headers: Record<string, string> = {
96
+ 'Content-Type': 'application/json',
97
+ // Négocie le mode passthrough côté backend : réponse HTTP BRUTE (statut réel de la
98
+ // fonction + content-type réel + corps brut) au lieu de l'enveloppe `{data,meta}`.
99
+ // Indispensable pour que `res.text()/blob()/arrayBuffer()` reçoive le corps de la
100
+ // fonction (et non l'enveloppe JSON) et que `res.status` porte le statut fonction.
101
+ 'X-Aurabase-Invoke-Mode': 'raw',
102
+ }
103
+ if (store.token) headers['Authorization'] = `Bearer ${store.token}`
104
+ if (client.apiKey) headers['apikey'] = client.apiKey
105
+
106
+ const res = await client.fetchFn(this.url(`${this.prefix}/${slug}/invoke`), {
107
+ method: 'POST',
108
+ headers,
109
+ body: JSON.stringify(envelope),
110
+ signal: controller.signal,
111
+ })
112
+ if (!res.ok) {
113
+ let parsed: { error?: { code?: string; message?: string }; message?: string } | null = null
114
+ try {
115
+ parsed = (await res.json()) as typeof parsed
116
+ } catch {
117
+ // corps non-JSON → AuraError générique sur le status
118
+ }
119
+ return { data: null, error: toFunctionsError(new AuraError(res.status, parsed)) }
120
+ }
121
+ let data: unknown
122
+ if (responseType === 'text') data = await res.text()
123
+ else if (responseType === 'blob') data = await res.blob()
124
+ else data = await res.arrayBuffer()
125
+ return { data: data as T, error: null }
126
+ } catch (err) {
127
+ // Annulation/timeout : conserve le code `timeout` (non-régression).
128
+ if (controller.signal.aborted || isAbortError(err)) return timeoutError()
129
+ // Toute autre exception (panne réseau : fonction injoignable) → relais.
130
+ return {
131
+ data: null,
132
+ error: new FunctionsRelayError(0, {
133
+ error: { code: 'network_error', message: err instanceof Error ? err.message : 'Function relay error' },
134
+ }),
135
+ }
136
+ } finally {
137
+ cleanup()
138
+ }
139
+ }
140
+
141
+ // -- Function CRUD ----------------------------------------------------------
142
+
143
+ async list(): Promise<AuraResponse<FunctionDef[]>> {
144
+ return this.request('GET', `${this.prefix}`)
145
+ }
146
+
147
+ async get(id: string): Promise<AuraResponse<FunctionDef>> {
148
+ return this.request('GET', `${this.prefix}/${id}`)
149
+ }
150
+
151
+ // -- Jobs -------------------------------------------------------------------
152
+
153
+ async listJobs(options?: { status?: string; limit?: number }): Promise<AuraResponse<Job[]>> {
154
+ const params = new URLSearchParams()
155
+ if (options?.status) params.set('status', options.status)
156
+ if (options?.limit !== undefined) params.set('limit', String(options.limit))
157
+ const qs = params.toString() ? `?${params.toString()}` : ''
158
+ return this.request('GET', `${this.prefix}/jobs${qs}`)
159
+ }
160
+
161
+ async getJob(jobId: string): Promise<AuraResponse<Job>> {
162
+ return this.request('GET', `${this.prefix}/jobs/${jobId}`)
163
+ }
164
+
165
+ // -- Cron -------------------------------------------------------------------
166
+
167
+ async listCronJobs(): Promise<AuraResponse<CronJob[]>> {
168
+ return this.request('GET', `${this.prefix}/cron`)
169
+ }
170
+
171
+ async createCronJob(
172
+ name: string,
173
+ schedule: string,
174
+ functionName: string,
175
+ options?: { payload?: unknown },
176
+ ): Promise<AuraResponse<CronJob>> {
177
+ return this.request('POST', `${this.prefix}/cron`, {
178
+ name,
179
+ schedule,
180
+ function_name: functionName,
181
+ payload: options?.payload,
182
+ })
183
+ }
184
+
185
+ async deleteCronJob(name: string): Promise<AuraResponse<null>> {
186
+ return this.request('DELETE', `${this.prefix}/cron/${name}`)
187
+ }
188
+ }
@@ -0,0 +1,70 @@
1
+ import { AuraError } from '@aurabase/core'
2
+
3
+ /**
4
+ * Statuts HTTP considérés comme des pannes de RELAIS/infra (passerelle, cold
5
+ * start, service indisponible) plutôt que des erreurs applicatives de la fonction.
6
+ * `0` = échec réseau (aucune réponse HTTP).
7
+ */
8
+ const RELAY_STATUSES = new Set([502, 503, 504])
9
+
10
+ export function isRelayStatus(status: number): boolean {
11
+ return status === 0 || RELAY_STATUSES.has(status)
12
+ }
13
+
14
+ /**
15
+ * Erreur HTTP APPLICATIVE renvoyée par l'invocation d'une edge function
16
+ * (réponse HTTP non-2xx). Parité `FunctionsHttpError` de `@supabase/functions-js`.
17
+ * Sous-classe `AuraError` → `isAuraError()` reste vrai, `status` porte le code HTTP.
18
+ * `context` conserve le corps déjà lu (JSON/texte) pour inspection.
19
+ */
20
+ export class FunctionsHttpError extends AuraError {
21
+ readonly context: unknown
22
+
23
+ constructor(
24
+ status: number,
25
+ body?: { error?: { code?: string; message?: string }; message?: string } | null,
26
+ context?: unknown,
27
+ ) {
28
+ super(status, body)
29
+ this.name = 'FunctionsHttpError'
30
+ this.context = context
31
+ Object.setPrototypeOf(this, FunctionsHttpError.prototype)
32
+ }
33
+ }
34
+
35
+ /**
36
+ * Erreur de RELAIS/infra : fonction injoignable (échec réseau), 502/503/504 de la
37
+ * passerelle, cold start échoué, corps non exploitable. Parité `FunctionsRelayError`
38
+ * de `@supabase/functions-js`. Sous-classe `AuraError`.
39
+ */
40
+ export class FunctionsRelayError extends AuraError {
41
+ readonly context: unknown
42
+
43
+ constructor(
44
+ status: number,
45
+ body?: { error?: { code?: string; message?: string }; message?: string } | null,
46
+ context?: unknown,
47
+ ) {
48
+ super(status, body)
49
+ this.name = 'FunctionsRelayError'
50
+ this.context = context
51
+ Object.setPrototypeOf(this, FunctionsRelayError.prototype)
52
+ }
53
+ }
54
+
55
+ /**
56
+ * Convertit une `AuraError` générique (produite par le pipeline ou un `!res.ok`)
57
+ * en la sous-classe Functions appropriée, selon le statut HTTP :
58
+ * - relais (0/502/503/504) → `FunctionsRelayError` ;
59
+ * - toute autre erreur HTTP → `FunctionsHttpError`.
60
+ * Préserve le corps original (`details`) → code/message conservés.
61
+ */
62
+ export function toFunctionsError(err: AuraError, context?: unknown): AuraError {
63
+ const body =
64
+ err.details != null
65
+ ? (err.details as { error?: { code?: string; message?: string }; message?: string })
66
+ : { error: { code: err.code, message: err.message } }
67
+ return isRelayStatus(err.status)
68
+ ? new FunctionsRelayError(err.status, body, context ?? err.details)
69
+ : new FunctionsHttpError(err.status, body, context ?? err.details)
70
+ }
@@ -0,0 +1,6 @@
1
+ export { FunctionsService } from './FunctionsService'
2
+ export type { FunctionsResponseType } from './FunctionsService'
3
+ export { FunctionsHttpError, FunctionsRelayError, isRelayStatus } from './errors'
4
+
5
+ // Types publics (utilisables en consommant `@aurabase/functions` seul).
6
+ export type { AuraResponse, FunctionDef, Job, CronJob } from '@aurabase/core'
@@ -0,0 +1,97 @@
1
+ import { describe, it, expect, vi, afterEach } from 'vitest'
2
+ import { FunctionsService } from '../src/FunctionsService'
3
+ import { BaseAuthStore } from '@aurabase/core'
4
+ import type { AuraClientLike } from '@aurabase/core'
5
+
6
+ afterEach(() => vi.useRealTimers())
7
+
8
+ function b64url(o: unknown) { return btoa(JSON.stringify(o)).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '') }
9
+ function expiredJwt() { return `${b64url({ alg: 'HS256' })}.${b64url({ exp: Math.floor(Date.now() / 1000) - 60 })}.s` }
10
+ function validJwt() { return `${b64url({ alg: 'HS256' })}.${b64url({ exp: Math.floor(Date.now() / 1000) + 3600 })}.s` }
11
+ function fakeUser() { return { id: 'u', email: null, role: 'authenticated', email_verified: true, is_banned: false, is_anonymous: false, mfa_enabled: false, user_metadata: {}, app_metadata: {}, created_at: '2025-01-01T00:00:00Z' } }
12
+
13
+ function make(responder: (url: string, init: RequestInit) => Response | Promise<Response>, store = new BaseAuthStore()) {
14
+ const calls: string[] = []
15
+ const client: AuraClientLike = {
16
+ baseUrl: 'http://x', projectId: 'p', apiKey: 'k', authStore: store,
17
+ fetchFn: (async (url: string, init: RequestInit) => { calls.push(String(url)); return responder(String(url), init) }) as unknown as typeof globalThis.fetch,
18
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
19
+ auth: { refreshSession: async () => ({ data: null, error: null }) as any },
20
+ }
21
+ return { fns: new FunctionsService(client), calls }
22
+ }
23
+ const json = (o: unknown, s = 200) => new Response(JSON.stringify(o), { status: s, headers: { 'Content-Type': 'application/json' } })
24
+
25
+ describe('functions.invoke — dé-wrap enveloppe + timeout', () => {
26
+ it('dé-wrappe l’enveloppe ApiResponse {data, meta}', async () => {
27
+ const { fns } = make(() => json({ data: { status: 200, body: { ok: true } }, meta: null }))
28
+ const { data, error } = await fns.invoke('hello')
29
+ expect(error).toBeNull()
30
+ expect(data).toEqual({ status: 200, body: { ok: true } }) // contenu, pas l'enveloppe
31
+ })
32
+ it('réponse sans enveloppe → renvoyée telle quelle (fallback data ?? parsed)', async () => {
33
+ const { fns } = make(() => json({ ok: true }))
34
+ const { data } = await fns.invoke('hello')
35
+ expect(data).toEqual({ ok: true })
36
+ })
37
+ it('propage meta', async () => {
38
+ const { fns } = make(() => json({ data: { x: 1 }, meta: { total: 5 } }))
39
+ const { meta } = await fns.invoke('hello')
40
+ expect(meta).toEqual({ total: 5 })
41
+ })
42
+ it('signal déjà avorté à l’entrée → coupe la requête (controller interne aborté)', async () => {
43
+ const ac = new AbortController()
44
+ ac.abort()
45
+ // Le responder rejette UNIQUEMENT si le signal reçu est déjà aborté → prouve le pré-abort.
46
+ const { fns } = make((_url, init) =>
47
+ init.signal?.aborted
48
+ ? Promise.reject(Object.assign(new Error('aborted'), { name: 'AbortError' }))
49
+ : Promise.resolve(json({ data: { ok: 1 } })),
50
+ )
51
+ const { error } = await fns.invoke('hello', { signal: ac.signal })
52
+ expect(error?.code).toBe('timeout') // aborté, pas résolu
53
+ })
54
+ it('!ok → erreur status', async () => {
55
+ const { fns } = make(() => json({ error: { code: 'boom', message: 'x' } }, 500))
56
+ const { error } = await fns.invoke('hello')
57
+ expect(error?.status).toBe(500)
58
+ })
59
+ it('timeout → error code timeout', async () => {
60
+ vi.useFakeTimers()
61
+ const { fns } = make((_url, init) => new Promise<Response>((_res, rej) => {
62
+ init.signal?.addEventListener('abort', () => rej(Object.assign(new Error('aborted'), { name: 'AbortError' })))
63
+ }))
64
+ const p = fns.invoke('slow', { timeout: 100 })
65
+ await vi.advanceTimersByTimeAsync(100)
66
+ const { error } = await p
67
+ expect(error?.code).toBe('timeout')
68
+ })
69
+ it('passe par le pipeline unifié : injecte apikey/Authorization et ne rejoue PAS un POST (503)', async () => {
70
+ const store = new BaseAuthStore()
71
+ store.save(validJwt(), 'rt', fakeUser())
72
+ let count = 0
73
+ const seen: Record<string, string> = {}
74
+ const { fns } = make((_url, init) => {
75
+ count++
76
+ Object.assign(seen, init.headers as Record<string, string>)
77
+ return json({ error: { code: 'unavailable', message: 'x' } }, 503)
78
+ }, store)
79
+ const { error } = await fns.invoke('hello')
80
+ expect(count).toBe(1) // POST non-idempotent → jamais rejoué même sur 503
81
+ expect(error?.status).toBe(503)
82
+ expect(seen['apikey']).toBe('k')
83
+ expect(seen['Authorization']).toBe(`Bearer ${store.token}`)
84
+ })
85
+
86
+ it('refresh proactif si token expiré', async () => {
87
+ const store = new BaseAuthStore()
88
+ store.save(expiredJwt(), 'rt', fakeUser())
89
+ const { fns, calls } = make((url) => {
90
+ if (url.includes('/v1/auth/')) return json({ access_token: validJwt(), refresh_token: 'rt2', token_type: 'bearer', expires_in: 3600, user: fakeUser() })
91
+ return json({ ok: 1 })
92
+ }, store)
93
+ await fns.invoke('hello')
94
+ expect(calls[0]).toContain('/v1/auth/p/refresh')
95
+ expect(calls[1]).toContain('/hello/invoke')
96
+ })
97
+ })
@@ -0,0 +1,135 @@
1
+ import { describe, it, expect } from 'vitest'
2
+ import { FunctionsService } from '../src/FunctionsService'
3
+ import { FunctionsHttpError, FunctionsRelayError } from '../src/errors'
4
+ import { BaseAuthStore, isAuraError } from '@aurabase/core'
5
+ import type { AuraClientLike } from '@aurabase/core'
6
+
7
+ function make(responder: (url: string, init: RequestInit) => Response | Promise<Response>, store = new BaseAuthStore()) {
8
+ const calls: Array<{ url: string; init: RequestInit }> = []
9
+ const client: AuraClientLike = {
10
+ baseUrl: 'http://x', projectId: 'p', apiKey: 'k', authStore: store,
11
+ fetchFn: (async (url: string, init: RequestInit) => { calls.push({ url: String(url), init }); return responder(String(url), init) }) as unknown as typeof globalThis.fetch,
12
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
13
+ auth: { refreshSession: async () => ({ data: null, error: null }) as any },
14
+ }
15
+ return { fns: new FunctionsService(client), calls }
16
+ }
17
+ const json = (o: unknown, s = 200) => new Response(JSON.stringify(o), { status: s, headers: { 'Content-Type': 'application/json' } })
18
+
19
+ describe('functions.invoke — responseType', () => {
20
+ it("défaut = json : dé-wrappe l'enveloppe (non-régression)", async () => {
21
+ const { fns } = make(() => json({ data: { ok: true } }))
22
+ const { data, error } = await fns.invoke('hello')
23
+ expect(error).toBeNull()
24
+ expect(data).toEqual({ ok: true })
25
+ })
26
+
27
+ it("responseType 'text' → data est la chaîne brute (pas de dé-wrapping)", async () => {
28
+ const { fns } = make(() => new Response('bonjour brut', { status: 200, headers: { 'Content-Type': 'text/plain' } }))
29
+ const { data, error } = await fns.invoke<string>('hello', { responseType: 'text' })
30
+ expect(error).toBeNull()
31
+ expect(data).toBe('bonjour brut')
32
+ })
33
+
34
+ it("responseType 'blob' → data est un Blob", async () => {
35
+ const { fns } = make(() => new Response(new Blob([new Uint8Array([1, 2, 3])]), { status: 200 }))
36
+ const { data, error } = await fns.invoke<Blob>('hello', { responseType: 'blob' })
37
+ expect(error).toBeNull()
38
+ expect(data).toBeInstanceOf(Blob)
39
+ })
40
+
41
+ it("responseType 'arrayBuffer' → data est un ArrayBuffer", async () => {
42
+ const { fns } = make(() => new Response(new Uint8Array([1, 2, 3]), { status: 200 }))
43
+ const { data, error } = await fns.invoke<ArrayBuffer>('hello', { responseType: 'arrayBuffer' })
44
+ expect(error).toBeNull()
45
+ expect(data).toBeInstanceOf(ArrayBuffer)
46
+ expect(new Uint8Array(data as ArrayBuffer)).toEqual(new Uint8Array([1, 2, 3]))
47
+ })
48
+
49
+ it("chemin brut : POST vers /invoke avec apikey + Authorization", async () => {
50
+ const store = new BaseAuthStore()
51
+ const jwt = `${btoa(JSON.stringify({ alg: 'HS256' }))}.${btoa(JSON.stringify({ exp: Math.floor(Date.now() / 1000) + 3600 }))}.s`.replace(/=+/g, '')
52
+ store.save(jwt, 'rt', { id: 'u', email: null, role: 'authenticated', email_verified: true, is_banned: false, is_anonymous: false, mfa_enabled: false, user_metadata: {}, app_metadata: {}, created_at: '2025-01-01T00:00:00Z' })
53
+ const { fns, calls } = make(() => new Response('x', { status: 200 }), store)
54
+ await fns.invoke('hello', { responseType: 'text' })
55
+ expect(calls[0]!.url).toBe('http://x/v1/functions/p/hello/invoke')
56
+ expect(calls[0]!.init.method).toBe('POST')
57
+ const h = calls[0]!.init.headers as Record<string, string>
58
+ expect(h['apikey']).toBe('k')
59
+ expect(h['Authorization']).toBe(`Bearer ${store.token}`)
60
+ // Négocie le mode passthrough backend (réponse brute, pas l'enveloppe).
61
+ expect(h['X-Aurabase-Invoke-Mode']).toBe('raw')
62
+ })
63
+
64
+ it("chemin json (défaut) : n'envoie PAS X-Aurabase-Invoke-Mode (enveloppe, non-régression)", async () => {
65
+ const { fns, calls } = make(() => json({ data: { ok: true } }))
66
+ await fns.invoke('hello')
67
+ const h = (calls[0]!.init.headers ?? {}) as Record<string, string>
68
+ expect(h['X-Aurabase-Invoke-Mode']).toBeUndefined()
69
+ })
70
+ })
71
+
72
+ describe('functions.invoke — erreurs typées', () => {
73
+ it('4xx applicatif (json) → FunctionsHttpError, status correct, isAuraError', async () => {
74
+ const { fns } = make(() => json({ error: { code: 'bad', message: 'nope' } }, 400))
75
+ const { data, error } = await fns.invoke('hello')
76
+ expect(data).toBeNull()
77
+ expect(error).toBeInstanceOf(FunctionsHttpError)
78
+ expect(error?.status).toBe(400)
79
+ expect(isAuraError(error)).toBe(true)
80
+ })
81
+
82
+ it('4xx applicatif (chemin brut text) → FunctionsHttpError', async () => {
83
+ const { fns } = make(() => new Response('nope', { status: 422, headers: { 'Content-Type': 'text/plain' } }))
84
+ const { error } = await fns.invoke('hello', { responseType: 'text' })
85
+ expect(error).toBeInstanceOf(FunctionsHttpError)
86
+ expect(error?.status).toBe(422)
87
+ })
88
+
89
+ it('503 relais → FunctionsRelayError', async () => {
90
+ const { fns } = make(() => json({ error: { code: 'unavailable', message: 'x' } }, 503))
91
+ const { error } = await fns.invoke('hello')
92
+ expect(error).toBeInstanceOf(FunctionsRelayError)
93
+ expect(error?.status).toBe(503)
94
+ })
95
+
96
+ it('502 relais (chemin brut) → FunctionsRelayError', async () => {
97
+ const { fns } = make(() => new Response('bad gateway', { status: 502 }))
98
+ const { error } = await fns.invoke('hello', { responseType: 'text' })
99
+ expect(error).toBeInstanceOf(FunctionsRelayError)
100
+ expect(error?.status).toBe(502)
101
+ })
102
+
103
+ it('panne réseau (chemin brut) → FunctionsRelayError', async () => {
104
+ const { fns } = make(() => Promise.reject(new TypeError('fetch failed')))
105
+ const { error } = await fns.invoke('hello', { responseType: 'text' })
106
+ expect(error).toBeInstanceOf(FunctionsRelayError)
107
+ expect(error?.status).toBe(0)
108
+ })
109
+
110
+ it('timeout → code timeout (non-régression, PAS une FunctionsError)', async () => {
111
+ const ac = new AbortController()
112
+ ac.abort()
113
+ const { fns } = make((_url, init) =>
114
+ init.signal?.aborted
115
+ ? Promise.reject(Object.assign(new Error('aborted'), { name: 'AbortError' }))
116
+ : Promise.resolve(json({ data: { ok: 1 } })),
117
+ )
118
+ const { error } = await fns.invoke('hello', { signal: ac.signal })
119
+ expect(error?.code).toBe('timeout')
120
+ expect(error).not.toBeInstanceOf(FunctionsHttpError)
121
+ expect(error).not.toBeInstanceOf(FunctionsRelayError)
122
+ })
123
+
124
+ it("timeout sur chemin brut (text) → code timeout", async () => {
125
+ const ac = new AbortController()
126
+ ac.abort()
127
+ const { fns } = make((_url, init) =>
128
+ init.signal?.aborted
129
+ ? Promise.reject(Object.assign(new Error('aborted'), { name: 'AbortError' }))
130
+ : Promise.resolve(new Response('x', { status: 200 })),
131
+ )
132
+ const { error } = await fns.invoke('hello', { responseType: 'text', signal: ac.signal })
133
+ expect(error?.code).toBe('timeout')
134
+ })
135
+ })
@@ -0,0 +1,5 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "compilerOptions": { "outDir": "dist", "rootDir": "src" },
4
+ "include": ["src"]
5
+ }
@@ -0,0 +1,11 @@
1
+ import { defineConfig } from 'tsup'
2
+
3
+ export default defineConfig({
4
+ entry: ['src/index.ts'],
5
+ format: ['cjs', 'esm'],
6
+ dts: true,
7
+ splitting: false,
8
+ clean: true,
9
+ treeshake: true,
10
+ minify: false,
11
+ })
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Aurabase
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,84 @@
1
+ # @aurabase/gen
2
+
3
+ Générateur de types TypeScript `Database` pour le SDK Aurabase : introspecte le schéma d'un projet et produit un fichier de types compatible avec l'inférence de `@aurabase/db` (parité `Database` façon Supabase).
4
+
5
+ ![npm](https://img.shields.io/npm/v/@aurabase/gen) ![license](https://img.shields.io/badge/license-MIT-blue)
6
+
7
+ > Pre-release — pas encore publié sur npm.
8
+
9
+ Fait partie de l'écosystème du SDK **[aurabase](../aurabase)**, mais publié et installé **séparément** : contrairement aux autres packages `@aurabase/*`, le méta-package `aurabase` ne dépend pas de `@aurabase/gen` — c'est un outil de développement (CLI de génération de types), pas une dépendance runtime de votre application.
10
+
11
+ ## Installation
12
+
13
+ ```bash
14
+ npm i -D @aurabase/gen
15
+ ```
16
+
17
+ > S'installe typiquement en devDependency (ou s'exécute via `npx` sans installation) : c'est un outil exécuté ponctuellement (local ou CI) pour régénérer un fichier `.ts`, pas un module importé par votre application en production.
18
+
19
+ ## Usage
20
+
21
+ ### CLI `aurabase-gen`
22
+
23
+ ```bash
24
+ npx aurabase-gen --url http://localhost:8080 --project my-project --key aura_anon_xxx --out database.types.ts
25
+ ```
26
+
27
+ Options complètes :
28
+
29
+ ```
30
+ aurabase-gen --url <baseUrl> --project <id> [--key <apiKey>] [--out database.types.ts] [--schema public] [--type-name Database]
31
+ ```
32
+
33
+ Sans `--out`, la sortie est écrite sur `stdout` plutôt que dans un fichier.
34
+
35
+ ### Utilisation programmatique
36
+
37
+ ```ts
38
+ import { generateDatabaseTypes } from '@aurabase/gen'
39
+ import type { SchemaTable } from '@aurabase/core'
40
+
41
+ const tables: SchemaTable[] = [
42
+ {
43
+ name: 'posts',
44
+ primary_key: 'id',
45
+ columns: [
46
+ { name: 'id', col_type: 'uuid', nullable: false, unique: true, default_val: 'gen_random_uuid()', references: null },
47
+ { name: 'title', col_type: 'text', nullable: false, unique: false, default_val: null, references: null },
48
+ ],
49
+ indexes: [],
50
+ rls_enabled: false,
51
+ realtime_enabled: false,
52
+ },
53
+ ]
54
+
55
+ const source = generateDatabaseTypes(tables, { schemaName: 'public', typeName: 'Database' })
56
+ ```
57
+
58
+ ### Workflow complet (typage bout-en-bout avec `@aurabase/db`)
59
+
60
+ ```bash
61
+ npx aurabase-gen --url http://localhost:8080 --project my-project --key aura_anon_xxx --out database.types.ts
62
+ ```
63
+
64
+ ```ts
65
+ import { createClient } from 'aurabase'
66
+ import type { Database } from './database.types' // fichier généré à l'étape précédente
67
+
68
+ const aura = createClient<Database>('http://localhost:8080', 'my-project', 'aura_anon_xxx')
69
+
70
+ // select()/insert()/update() sont désormais inférés depuis les colonnes réelles de `posts`.
71
+ const { data } = await aura.db.from('posts').select('id,title').eq('id', 'post-id').single()
72
+ ```
73
+
74
+ ## Limitations
75
+
76
+ - `Views`, `Functions`, `Enums` et `CompositeTypes` sont toujours générés vides (`Record<string, never>`) — seules les `Tables` sont introspectées et typées.
77
+ - Un seul schéma à la fois (`--schema`, défaut `public`) : pas de génération multi-schémas en une seule invocation.
78
+ - Dépend de l'endpoint `/schema` exposé par `aura.db.schema()` côté backend — un projet ou une clé sans droit de lecture du schéma ne peut pas générer de types (erreur explicite, pas de repli silencieux).
79
+ - Pas de détection de types enum Postgres dédiés : un `col_type` non reconnu retombe sur `unknown`.
80
+ - Le fichier généré est un instantané : il ne se met pas à jour automatiquement quand le schéma change côté backend (pas de mode watch).
81
+
82
+ ## Documentation
83
+
84
+ Référence complète du SDK (tous les services, types partagés, SSR) : [README racine](../../README.md).