@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,268 +0,0 @@
1
- import { describe, it, expect, beforeAll, afterAll } from 'vitest'
2
- import { createClient } from '../src/index'
3
-
4
- const GATEWAY_URL = 'http://localhost:8080'
5
- const MGMT_URL = 'http://localhost:8090'
6
-
7
- describe('Tests de robustesse de production E2E (Multi-tenant, Transactions, Injection, Concurrence)', () => {
8
- let devToken: string
9
- let projectId: string
10
- let anonKey: string
11
- let serviceKey: string
12
-
13
- const runId = Math.random().toString(36).substring(2, 10)
14
- const devEmail = `robustness-dev-${runId}@aurabase.dev`
15
- const devPassword = 'RobustPasswordE2E123!'
16
- const projectName = `robustness-proj-${runId}`
17
-
18
- const endUserEmail = `enduser-${runId}@example.com`
19
- const endUserPassword = 'EndUserPassword123!'
20
-
21
- beforeAll(async () => {
22
- // 1. Enregistrement développeur
23
- const regRes = await fetch(`${MGMT_URL}/v1/control/accounts/register`, {
24
- method: 'POST',
25
- headers: { 'Content-Type': 'application/json' },
26
- body: JSON.stringify({ email: devEmail, password: devPassword }),
27
- })
28
- expect(regRes.status).toBe(200)
29
- const regData = await regRes.json()
30
- devToken = regData.data.access_token
31
-
32
- // 2. Création organisation
33
- const orgRes = await fetch(`${MGMT_URL}/v1/control/orgs`, {
34
- method: 'POST',
35
- headers: {
36
- 'Authorization': `Bearer ${devToken}`,
37
- 'Content-Type': 'application/json',
38
- },
39
- body: JSON.stringify({ name: 'Robustness Org', slug: `robust-org-${runId}` }),
40
- })
41
- expect(orgRes.status).toBeLessThan(300)
42
- const orgData = await orgRes.json()
43
- const orgId = orgData.id
44
-
45
- // 3. Création projet
46
- const projRes = await fetch(`${MGMT_URL}/v1/control/orgs/${orgId}/projects`, {
47
- method: 'POST',
48
- headers: {
49
- 'Authorization': `Bearer ${devToken}`,
50
- 'Content-Type': 'application/json',
51
- },
52
- body: JSON.stringify({ name: projectName, engine: 'postgres', region: 'eu-west-1' }),
53
- })
54
- expect(projRes.status).toBe(202)
55
- const projData = await projRes.json()
56
- projectId = projData.id
57
-
58
- // Attente du provisioning
59
- let active = false
60
- for (let i = 0; i < 50; i++) {
61
- const statusRes = await fetch(`${MGMT_URL}/v1/control/projects/${projectId}`, {
62
- headers: { 'Authorization': `Bearer ${devToken}` },
63
- })
64
- const statusData = await statusRes.json()
65
- if (statusData && statusData.status === 'active') {
66
- active = true
67
- break
68
- }
69
- await new Promise((resolve) => setTimeout(resolve, 1500))
70
- }
71
- expect(active).toBe(true)
72
-
73
- // Récupération clés API (avec retry)
74
- let keysRes: Response | null = null
75
- for (let i = 0; i < 15; i++) {
76
- keysRes = await fetch(`${MGMT_URL}/v1/control/projects/${projectId}/initial-keys`, {
77
- headers: { 'Authorization': `Bearer ${devToken}` },
78
- })
79
- if (keysRes.status === 200) {
80
- break
81
- }
82
- await new Promise((resolve) => setTimeout(resolve, 1000))
83
- }
84
- expect(keysRes).not.toBeNull()
85
- expect(keysRes!.status).toBe(200)
86
- const keysData = await keysRes!.json()
87
- const keys = keysData.data || keysData
88
- anonKey = keys.find((k: any) => k.scope === 'anon').key
89
- serviceKey = keys.find((k: any) => k.scope === 'service_role').key
90
-
91
- // 4. Création de la table 'tasks' avec RLS active
92
- const tableDef = {
93
- name: 'tasks',
94
- columns: [
95
- {
96
- name: 'id',
97
- col_type: 'uuid',
98
- nullable: false,
99
- unique: true,
100
- default_val: 'gen_random_uuid()',
101
- references: null
102
- },
103
- {
104
- name: 'title',
105
- col_type: 'text',
106
- nullable: false,
107
- unique: false,
108
- default_val: null,
109
- references: null
110
- },
111
- {
112
- name: 'owner_id',
113
- col_type: 'text',
114
- nullable: false,
115
- unique: false,
116
- default_val: null,
117
- references: null
118
- }
119
- ],
120
- primary_key: 'id',
121
- indexes: [],
122
- rls_enabled: true,
123
- realtime_enabled: true
124
- }
125
-
126
- const tableRes = await fetch(`${MGMT_URL}/v1/db/${projectId}/schema/tables`, {
127
- method: 'POST',
128
- headers: {
129
- 'Authorization': `Bearer ${devToken}`,
130
- 'Content-Type': 'application/json',
131
- },
132
- body: JSON.stringify(tableDef),
133
- })
134
- expect(tableRes.status).toBe(200)
135
-
136
- // Attendre l'indexation PostgREST
137
- let ready = false
138
- for (let i = 0; i < 30; i++) {
139
- const probeRes = await fetch(`${GATEWAY_URL}/v1/db/${projectId}/tasks`, {
140
- headers: { 'apikey': anonKey },
141
- })
142
- if (probeRes.status === 200) {
143
- ready = true
144
- break
145
- }
146
- await new Promise((resolve) => setTimeout(resolve, 1500))
147
- }
148
- expect(ready).toBe(true)
149
-
150
- // Attendre 3 secondes que PostgREST stabilise son cache après les DDL de setup
151
- await new Promise((resolve) => setTimeout(resolve, 3000))
152
- }, 60000)
153
-
154
- afterAll(async () => {
155
- // Suppression propre
156
- if (projectId && devToken) {
157
- const delRes = await fetch(`${MGMT_URL}/v1/control/projects/${projectId}`, {
158
- method: 'DELETE',
159
- headers: { 'Authorization': `Bearer ${devToken}` },
160
- })
161
- expect(delRes.status).toBe(204)
162
- }
163
- })
164
-
165
- it('devrait exécuter des requêtes avec EXPLAIN ANALYZE', async () => {
166
- const client = createClient(GATEWAY_URL, projectId, serviceKey, {
167
- auth: { persistSession: false },
168
- })
169
-
170
- const explainRes = await client.db.sql<any[]>('EXPLAIN ANALYZE SELECT * FROM tasks')
171
- expect(explainRes.error).toBeNull()
172
- expect(explainRes.data).toBeDefined()
173
- expect(explainRes.data!.length).toBeGreaterThan(0)
174
-
175
- // Vérifier la présence d'éléments typiques d'un plan d'exécution
176
- const planText = JSON.stringify(explainRes.data)
177
- expect(planText).toMatch(/Plan|Scan/i)
178
- })
179
-
180
- it('devrait empêcher le contournement d\'isolation multi-tenant (Lecture inter-schéma)', async () => {
181
- const client = createClient(GATEWAY_URL, projectId, serviceKey, {
182
- auth: { persistSession: false },
183
- })
184
-
185
- // Tenter de lire un schéma d'un autre tenant inexistant ou existant (ex: project_autre_tenant)
186
- // Devrait être rejeté avec une erreur 400 (BAD REQUEST) par Axum avant d'exécuter le SQL
187
- const foreignSchemaRes = await client.db.sql('SELECT * FROM project_00000000_0000_0000_0000_000000000000.tasks')
188
- expect(foreignSchemaRes.error).not.toBeNull()
189
- expect(foreignSchemaRes.error?.code).toBe('BAD_REQUEST')
190
- expect(foreignSchemaRes.error?.message).toContain('interdite')
191
- })
192
-
193
- it('devrait garantir la sécurité face aux injections SQL', async () => {
194
- const client = createClient(GATEWAY_URL, projectId, serviceKey, {
195
- auth: { persistSession: false },
196
- })
197
-
198
- // Tentative d'injection SQL via filtre
199
- const maliciosQueryRes = await client.db
200
- .from('tasks')
201
- .eq('title', "'; DROP TABLE tasks; --")
202
- .select('*')
203
-
204
- expect(maliciosQueryRes.error).toBeNull() // Sûr grâce à la paramétrisation PostgREST
205
-
206
- // Vérifier que la table 'tasks' existe toujours
207
- const probeRes = await client.db.from('tasks').select('*')
208
- expect(probeRes.error).toBeNull()
209
- })
210
-
211
- it('devrait exécuter des requêtes concurrentes saines (saturation de charge)', async () => {
212
- const client = createClient(GATEWAY_URL, projectId, serviceKey, {
213
- auth: { persistSession: false },
214
- })
215
-
216
- const requests = Array.from({ length: 50 }).map((_, idx) =>
217
- client.db.from('tasks').insert({
218
- title: `Tâche concurrente ${idx}`,
219
- owner_id: `owner_${idx}`,
220
- })
221
- )
222
-
223
- const startTime = performance.now()
224
- const results = await Promise.all(requests)
225
- const duration = performance.now() - startTime
226
-
227
- console.log(`[PERF] 50 requêtes concurrentes d'insertion exécutées en ${duration.toFixed(1)}ms`)
228
-
229
- // Vérifier que toutes les requêtes ont réussi
230
- for (const r of results) {
231
- expect(r.error).toBeNull()
232
- }
233
-
234
- // Vérifier que 50 lignes ont bien été insérées
235
- const selectRes = await client.db.from('tasks').select('*')
236
- expect(selectRes.data?.length).toBe(50)
237
- })
238
-
239
- it('devrait gérer proprement les transactions SQL brutes (Commit & Rollback)', async () => {
240
- const client = createClient(GATEWAY_URL, projectId, serviceKey, {
241
- auth: { persistSession: false },
242
- })
243
-
244
- // 1. Test du ROLLBACK : exécuter BEGIN, INSERT et ROLLBACK dans un seul bloc multi-statement
245
- const txRollbackRes = await client.db.sql(
246
- `BEGIN;
247
- INSERT INTO tasks (title, owner_id) VALUES ('Task Tx Rollback', 'owner_tx');
248
- ROLLBACK;`
249
- )
250
- expect(txRollbackRes.error).toBeNull()
251
-
252
- // La ligne ne doit pas exister dans la base
253
- const selectPostRollback = await client.db.from('tasks').eq('title', 'Task Tx Rollback')
254
- expect(selectPostRollback.data?.length).toBe(0)
255
-
256
- // 2. Test du COMMIT : exécuter BEGIN, INSERT et COMMIT dans un seul bloc
257
- const txCommitRes = await client.db.sql(
258
- `BEGIN;
259
- INSERT INTO tasks (title, owner_id) VALUES ('Task Tx Commit', 'owner_tx');
260
- COMMIT;`
261
- )
262
- expect(txCommitRes.error).toBeNull()
263
-
264
- // La ligne doit exister
265
- const selectPostCommit = await client.db.from('tasks').eq('title', 'Task Tx Commit')
266
- expect(selectPostCommit.data?.length).toBe(1)
267
- })
268
- })
@@ -1,53 +0,0 @@
1
- import { describe, it, expect } from 'vitest'
2
- import * as root from '../src/index'
3
- import * as ssr from '../src/ssr'
4
-
5
- describe('surface publique du meta-package aurabase', () => {
6
- it('exporte exactement les symboles runtime attendus depuis la racine', () => {
7
- const actual = Object.keys(root).sort()
8
- const expected = [
9
- 'AiService',
10
- 'AuraChannel',
11
- 'AuraClient',
12
- 'AuraError',
13
- 'AuthAdminService',
14
- 'AuthService',
15
- 'BaseAuthStore',
16
- 'DatabaseService',
17
- 'FunctionsService',
18
- 'LocalAuthStore',
19
- 'NotificationsService',
20
- 'NotificationsAdminService',
21
- 'QueryBuilder',
22
- 'RealtimeService',
23
- 'StorageService',
24
- 'createAdminClient',
25
- 'createClient',
26
- 'isAuraError',
27
- 'isMfaChallenge',
28
- ].sort()
29
- expect(actual).toEqual(expected)
30
- })
31
-
32
- it('createClient fabrique un AuraClient fonctionnel', () => {
33
- const client = root.createClient('http://localhost:8080', 'proj-1', 'aura_anon_x')
34
- expect(client).toBeInstanceOf(root.AuraClient)
35
- expect(client.baseUrl).toBe('http://localhost:8080')
36
- expect(client.projectId).toBe('proj-1')
37
- // sous-clients accessibles
38
- expect(client.auth).toBeInstanceOf(root.AuthService)
39
- expect(client.db).toBeInstanceOf(root.DatabaseService)
40
- expect(client.storage).toBeInstanceOf(root.StorageService)
41
- expect(client.functions).toBeInstanceOf(root.FunctionsService)
42
- expect(client.ai).toBeInstanceOf(root.AiService)
43
- expect(client.notifications).toBeInstanceOf(root.NotificationsService)
44
- expect(client.realtime).toBeInstanceOf(root.RealtimeService)
45
- })
46
-
47
- it('exporte les helpers SSR', () => {
48
- const actual = Object.keys(ssr).sort()
49
- expect(actual).toEqual(
50
- ['createBrowserClient', 'createServerClient', 'parseCookieHeader', 'serializeCookieHeader'].sort(),
51
- )
52
- })
53
- })
@@ -1,329 +0,0 @@
1
- // ---------------------------------------------------------------------------
2
- // QueryBuilder tests -- verify query string compilation for all operators
3
- // ---------------------------------------------------------------------------
4
-
5
- import { describe, it, expect, beforeEach, afterEach } from 'vitest'
6
- import { AuraClient } from '../src/AuraClient'
7
- import { QueryBuilder } from '@aurabase/db'
8
- import { FetchMock, fakeTokenPair } from './mocks'
9
-
10
- const BASE = 'http://localhost:8080'
11
- const PROJECT = 'test-project'
12
-
13
- let fetchMock: FetchMock
14
- let client: AuraClient
15
-
16
- beforeEach(() => {
17
- fetchMock = new FetchMock()
18
- fetchMock.init()
19
- client = new AuraClient(BASE, PROJECT, {
20
- auth: { persistSession: false },
21
- })
22
- // Pre-populate auth so fetchWithAuth does not try to refresh
23
- const tp = fakeTokenPair()
24
- client.authStore.save(tp.access_token, tp.refresh_token, tp.user)
25
- })
26
-
27
- afterEach(() => {
28
- fetchMock.restore()
29
- fetchMock.clearMocks()
30
- })
31
-
32
- /** Helper: build a QueryBuilder for a table and return its query string. */
33
- function qs(configure: (qb: QueryBuilder) => void): string {
34
- const qb = new QueryBuilder(client, `/v1/db/${PROJECT}/posts`)
35
- configure(qb)
36
- return qb.buildQueryString()
37
- }
38
-
39
- // ---------------------------------------------------------------------------
40
- // Filter operators
41
- // ---------------------------------------------------------------------------
42
-
43
- describe('QueryBuilder filters', () => {
44
- it('eq produces col=eq.val', () => {
45
- const q = qs((qb) => qb.eq('status', 'active'))
46
- expect(q).toContain('status=eq.active')
47
- })
48
-
49
- it('neq produces col=neq.val', () => {
50
- const q = qs((qb) => qb.neq('status', 'deleted'))
51
- expect(q).toContain('status=neq.deleted')
52
- })
53
-
54
- it('gt produces col=gt.val', () => {
55
- const q = qs((qb) => qb.gt('age', 18))
56
- expect(q).toContain('age=gt.18')
57
- })
58
-
59
- it('gte produces col=gte.val', () => {
60
- const q = qs((qb) => qb.gte('score', 90))
61
- expect(q).toContain('score=gte.90')
62
- })
63
-
64
- it('lt produces col=lt.val', () => {
65
- const q = qs((qb) => qb.lt('price', 100))
66
- expect(q).toContain('price=lt.100')
67
- })
68
-
69
- it('lte produces col=lte.val', () => {
70
- const q = qs((qb) => qb.lte('price', 50))
71
- expect(q).toContain('price=lte.50')
72
- })
73
-
74
- it('in produces col=in.(a,b,c)', () => {
75
- const q = qs((qb) => qb.in('id', [1, 2, 3]))
76
- expect(q).toContain('id=in.%281%2C2%2C3%29')
77
- // Decoded: id=in.(1,2,3)
78
- expect(decodeURIComponent(q)).toContain('id=in.(1,2,3)')
79
- })
80
-
81
- it('like produces col=like.pattern', () => {
82
- const q = qs((qb) => qb.like('name', '%john%'))
83
- expect(decodeURIComponent(q)).toContain('name=like.%john%')
84
- })
85
-
86
- it('ilike produces col=ilike.pattern', () => {
87
- const q = qs((qb) => qb.ilike('name', '%JOHN%'))
88
- expect(decodeURIComponent(q)).toContain('name=ilike.%JOHN%')
89
- })
90
-
91
- it('is(col, null) produces col=is.null', () => {
92
- const q = qs((qb) => qb.is('deleted_at', 'null'))
93
- expect(q).toContain('deleted_at=is.null')
94
- })
95
-
96
- it('is(col, not_null) produces col=is.not_null', () => {
97
- const q = qs((qb) => qb.is('email', 'not_null'))
98
- expect(q).toContain('email=is.not_null')
99
- })
100
- })
101
-
102
- // ---------------------------------------------------------------------------
103
- // OR groups
104
- // ---------------------------------------------------------------------------
105
-
106
- describe('QueryBuilder or()', () => {
107
- it('produces or=(col1.eq.val1,col2.gt.val2)', () => {
108
- const q = qs((qb) =>
109
- qb.or([
110
- { column: 'status', op: 'eq', value: 'active' },
111
- { column: 'priority', op: 'gt', value: 5 },
112
- ]),
113
- )
114
- const decoded = decodeURIComponent(q)
115
- expect(decoded).toContain('or=(status.eq.active,priority.gt.5)')
116
- })
117
-
118
- it('supports in operator inside or group', () => {
119
- const q = qs((qb) =>
120
- qb.or([{ column: 'id', op: 'in', value: [1, 2] }]),
121
- )
122
- const decoded = decodeURIComponent(q)
123
- expect(decoded).toContain('or=(id.in.(1,2))')
124
- })
125
- })
126
-
127
- // ---------------------------------------------------------------------------
128
- // Select
129
- // ---------------------------------------------------------------------------
130
-
131
- describe('QueryBuilder select()', () => {
132
- it('select("id, title") compiles to select=id,title', () => {
133
- const q = qs((qb) => qb.select('id, title'))
134
- const decoded = decodeURIComponent(q)
135
- expect(decoded).toContain('select=id,title')
136
- })
137
-
138
- it('select(["id","title"]) works the same', () => {
139
- const q = qs((qb) => qb.select(['id', 'title']))
140
- const decoded = decodeURIComponent(q)
141
- expect(decoded).toContain('select=id,title')
142
- })
143
-
144
- it('select("*") omits the select param', () => {
145
- const q = qs((qb) => qb.select('*'))
146
- expect(q).not.toContain('select=')
147
- })
148
- })
149
-
150
- // ---------------------------------------------------------------------------
151
- // Order / Pagination
152
- // ---------------------------------------------------------------------------
153
-
154
- describe('QueryBuilder order / limit / offset', () => {
155
- it('order("created_at", "desc") produces sort_by + sort_order', () => {
156
- const q = qs((qb) => qb.order('created_at', 'desc'))
157
- const decoded = decodeURIComponent(q)
158
- expect(decoded).toContain('sort_by=created_at')
159
- expect(decoded).toContain('sort_order=desc')
160
- })
161
-
162
- it('limit(10).offset(20) produces limit=10&offset=20', () => {
163
- const q = qs((qb) => qb.limit(10).offset(20))
164
- const decoded = decodeURIComponent(q)
165
- expect(decoded).toContain('limit=10')
166
- expect(decoded).toContain('offset=20')
167
- })
168
- })
169
-
170
- // ---------------------------------------------------------------------------
171
- // Count
172
- // ---------------------------------------------------------------------------
173
-
174
- describe('QueryBuilder count()', () => {
175
- it('count("exact") adds count=exact', () => {
176
- const q = qs((qb) => qb.count('exact'))
177
- expect(q).toContain('count=exact')
178
- })
179
-
180
- it('count("estimated") adds count=estimated', () => {
181
- const q = qs((qb) => qb.count('estimated'))
182
- expect(q).toContain('count=estimated')
183
- })
184
- })
185
-
186
- // ---------------------------------------------------------------------------
187
- // single() and throwOnError()
188
- // ---------------------------------------------------------------------------
189
-
190
- describe('QueryBuilder single()', () => {
191
- it('sets limit to 1 and unwraps the first element', async () => {
192
- const rows = [{ id: '1', title: 'Hello' }]
193
- fetchMock.on({
194
- method: 'GET',
195
- url: /\/posts\?/,
196
- replyCode: 200,
197
- replyBody: { data: rows },
198
- })
199
-
200
- const res = await client.db.from('posts').eq('id', '1').single()
201
-
202
- expect(res.data).toEqual({ id: '1', title: 'Hello' })
203
- })
204
-
205
- it('returns null when array is empty', async () => {
206
- fetchMock.on({
207
- method: 'GET',
208
- url: /\/posts\?/,
209
- replyCode: 200,
210
- replyBody: { data: [] },
211
- })
212
-
213
- const res = await client.db.from('posts').eq('id', 'nonexistent').single()
214
-
215
- expect(res.data).toBeNull()
216
- })
217
- })
218
-
219
- describe('QueryBuilder throwOnError()', () => {
220
- it('throws an error when response has error', async () => {
221
- fetchMock.on({
222
- method: 'GET',
223
- url: /\/posts/,
224
- replyCode: 500,
225
- replyBody: { error: { code: 'internal', message: 'DB down' } },
226
- })
227
-
228
- await expect(
229
- client.db.from('posts').throwOnError(),
230
- ).rejects.toThrow('DB down')
231
- })
232
- })
233
-
234
- // ---------------------------------------------------------------------------
235
- // Chained combinations
236
- // ---------------------------------------------------------------------------
237
-
238
- describe('QueryBuilder chained combinations', () => {
239
- it('combines select + filters + order + pagination', () => {
240
- const q = qs((qb) =>
241
- qb
242
- .select('id, title, created_at')
243
- .eq('published', true)
244
- .gt('views', 100)
245
- .order('created_at', 'desc')
246
- .limit(10)
247
- .offset(0),
248
- )
249
- const decoded = decodeURIComponent(q)
250
- expect(decoded).toContain('select=id,title,created_at')
251
- expect(decoded).toContain('published=eq.true')
252
- expect(decoded).toContain('views=gt.100')
253
- expect(decoded).toContain('sort_by=created_at')
254
- expect(decoded).toContain('sort_order=desc')
255
- expect(decoded).toContain('limit=10')
256
- expect(decoded).toContain('offset=0')
257
- })
258
-
259
- it('combines multiple filters with or group', () => {
260
- const q = qs((qb) =>
261
- qb
262
- .eq('type', 'post')
263
- .or([
264
- { column: 'status', op: 'eq', value: 'published' },
265
- { column: 'status', op: 'eq', value: 'draft' },
266
- ]),
267
- )
268
- const decoded = decodeURIComponent(q)
269
- expect(decoded).toContain('type=eq.post')
270
- expect(decoded).toContain('or=(status.eq.published,status.eq.draft)')
271
- })
272
- })
273
-
274
- // ---------------------------------------------------------------------------
275
- // Resource Embedding (PostgREST parity)
276
- // ---------------------------------------------------------------------------
277
-
278
- describe('QueryBuilder resource embedding', () => {
279
- it('select with embed passes raw string to ?select=', () => {
280
- const q = qs((qb) => qb.select('*,customer:customers(name,email)'))
281
- const decoded = decodeURIComponent(q)
282
- expect(decoded).toContain('select=*,customer:customers(name,email)')
283
- })
284
-
285
- it('select with one-to-many embed', () => {
286
- const q = qs((qb) => qb.select('last_name,films(title,year)'))
287
- const decoded = decodeURIComponent(q)
288
- expect(decoded).toContain('select=last_name,films(title,year)')
289
- })
290
-
291
- it('select with FK hint', () => {
292
- const q = qs((qb) =>
293
- qb.select('*,billing:addresses!billing_address_id(name),shipping:addresses!shipping_address_id(name)'),
294
- )
295
- const decoded = decodeURIComponent(q)
296
- expect(decoded).toContain('billing:addresses!billing_address_id(name)')
297
- expect(decoded).toContain('shipping:addresses!shipping_address_id(name)')
298
- })
299
-
300
- it('select with nested embedding', () => {
301
- const q = qs((qb) => qb.select('first_name,roles(character,films(title))'))
302
- const decoded = decodeURIComponent(q)
303
- expect(decoded).toContain('select=first_name,roles(character,films(title))')
304
- })
305
-
306
- it('select with embed + filters + pagination', () => {
307
- const q = qs((qb) =>
308
- qb
309
- .select('*,customer:customers(name)')
310
- .eq('status', 'active')
311
- .limit(10),
312
- )
313
- const decoded = decodeURIComponent(q)
314
- expect(decoded).toContain('select=*,customer:customers(name)')
315
- expect(decoded).toContain('status=eq.active')
316
- expect(decoded).toContain('limit=10')
317
- })
318
-
319
- it('select star returns no select param', () => {
320
- const q = qs((qb) => qb.select('*'))
321
- expect(q).toBe('') // no params = select all
322
- })
323
-
324
- it('select with array still joins with comma', () => {
325
- const q = qs((qb) => qb.select(['id', 'name', 'email']))
326
- const decoded = decodeURIComponent(q)
327
- expect(decoded).toContain('select=id,name,email')
328
- })
329
- })