@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,505 +0,0 @@
1
- import type { AuraClientLike, AuraResponse } from '@aurabase/core'
2
- import type { ServerMessage, ChannelConfig, BroadcastAckMessage } from '@aurabase/core'
3
- import { fetchWithAuth } from '@aurabase/core'
4
- import { AuraChannel } from './AuraChannel'
5
- import { HeartbeatManager } from './HeartbeatManager'
6
-
7
- /** Connection state machine */
8
- export type ConnectionState = 'disconnected' | 'connecting' | 'connected' | 'reconnecting'
9
-
10
- /**
11
- * Realtime service — manages a single WebSocket connection and multiplexes
12
- * channels on top of it. Supabase-compatible API.
13
- *
14
- * @example
15
- * ```ts
16
- * const aura = createClient('http://localhost:8080', 'my-project')
17
- *
18
- * const channel = aura.realtime.channel('room-1')
19
- * .on('postgres_changes', { event: 'INSERT', schema: 'public', table: 'messages' }, (payload) => {
20
- * console.log('New message:', payload)
21
- * })
22
- * .on('broadcast', { event: 'cursor-pos' }, (payload) => {
23
- * console.log('Cursor:', payload)
24
- * })
25
- * .subscribe((status) => {
26
- * if (status === 'SUBSCRIBED') {
27
- * channel.send({ type: 'broadcast', event: 'cursor-pos', payload: { x: 100, y: 200 } })
28
- * }
29
- * })
30
- * ```
31
- */
32
- export class RealtimeService {
33
- private readonly client: AuraClientLike
34
- private _ws: WebSocket | null = null
35
- private _channels = new Map<string, AuraChannel>()
36
- private _state: ConnectionState = 'disconnected'
37
- private _stateListeners = new Set<(state: ConnectionState) => void>()
38
-
39
- // ─── Reconnection state ──────────────────────────────────────────────
40
- private _autoReconnect = true
41
- private _reconnectAttempts = 0
42
- private _maxReconnectAttempts = Infinity
43
- private _reconnectTimer: ReturnType<typeof setTimeout> | null = null
44
- private _intentionalClose = false
45
- private _heartbeat = new HeartbeatManager()
46
- private _tokenRefreshTimer: ReturnType<typeof setTimeout> | null = null
47
- /** Dernier access_token propagé au serveur — évite les pushs redondants (propagation différentielle). */
48
- private _lastSentToken: string | null = null
49
-
50
- /** Backoff delays in ms: 1s, 2s, 4s, 8s, 16s, 30s (cap) */
51
- private static readonly BACKOFF_MS = [1000, 2000, 4000, 8000, 16000, 30000]
52
-
53
- constructor(client: AuraClientLike) {
54
- this.client = client
55
- }
56
-
57
- /** Current connection state. */
58
- get connectionState(): ConnectionState {
59
- return this._state
60
- }
61
-
62
- /** Listen for connection state changes. */
63
- onStateChange(callback: (state: ConnectionState) => void): () => void {
64
- this._stateListeners.add(callback)
65
- return () => this._stateListeners.delete(callback)
66
- }
67
-
68
- private _setState(state: ConnectionState): void {
69
- this._state = state
70
- for (const cb of this._stateListeners) {
71
- try { cb(state) } catch { /* ignore */ }
72
- }
73
- }
74
-
75
- // ─── WebSocket URL ──────────────────────────────────────────────────────
76
-
77
- private get _wsUrl(): string {
78
- const base = this.client.baseUrl.replace(/^http/, 'ws')
79
- return `${base}/v1/realtime/ws`
80
- }
81
-
82
- // ─── Connection management ──────────────────────────────────────────────
83
-
84
- /** Ensure the WebSocket connection is open. */
85
- connect(): void {
86
- if (this._ws && (this._ws.readyState === WebSocket.OPEN || this._ws.readyState === WebSocket.CONNECTING)) {
87
- return
88
- }
89
-
90
- // Toute nouvelle tentative de connexion repart d'un état « non-intentionnel » :
91
- // évite qu'un flag `_intentionalClose` laissé à true (car le onclose de
92
- // l'ancien socket est désormais court-circuité par la garde anti-race) ne
93
- // fasse traiter une future coupure inattendue comme volontaire.
94
- this._intentionalClose = false
95
-
96
- this._setState('connecting')
97
-
98
- const token = this.client.authStore.token
99
- const params = new URLSearchParams()
100
- if (token) params.set('token', token)
101
- // Clé API en query param (les navigateurs ne permettent pas de headers custom sur WebSocket)
102
- if (this.client.apiKey) params.set('apikey', this.client.apiKey)
103
-
104
- const url = `${this._wsUrl}?${params.toString()}`
105
- // On capture `ws` dans les closures des handlers : un ancien socket dont
106
- // l'événement `onclose`/`onopen` se déclenche de façon asynchrone APRÈS
107
- // qu'un nouveau socket ait été créé ne doit pas écraser la connexion
108
- // courante (race « stale onclose »). Chaque handler se garde donc par
109
- // `if (ws !== this._ws) return`.
110
- const ws = new WebSocket(url)
111
- this._ws = ws
112
-
113
- ws.onopen = () => {
114
- // Socket périmé (superseded par un connect()/reconnexion) ⇒ on le ferme
115
- // proprement et on n'active rien dessus.
116
- if (ws !== this._ws) {
117
- try { ws.close() } catch { /* ignore */ }
118
- return
119
- }
120
- this._reconnectAttempts = 0
121
- this._setState('connected')
122
-
123
- // Démarrer le heartbeat proactif (anti-throttle navigateur)
124
- this._heartbeat.start(() => this._send(JSON.stringify({ type: 'ping' })), 25000)
125
-
126
- // Planifier le refresh proactif du token (à 80% du TTL)
127
- this._scheduleTokenRefresh()
128
-
129
- // Bind send function and re-subscribe all pending channels
130
- for (const channel of this._channels.values()) {
131
- channel._bindSend((data) => this._send(data))
132
- if (channel.isSubscribed) {
133
- channel._doSubscribe()
134
- }
135
- }
136
- }
137
-
138
- ws.onmessage = (evt) => {
139
- // Ignore les messages d'un socket périmé.
140
- if (ws !== this._ws) return
141
- try {
142
- const raw = typeof evt.data === 'string' ? evt.data : ''
143
- const msg: ServerMessage = JSON.parse(raw)
144
- this._dispatch(msg)
145
- } catch (e) {
146
- if (typeof console !== 'undefined') {
147
- console.warn('[aura-realtime] Failed to parse WS message:', evt.data, e)
148
- }
149
- }
150
- }
151
-
152
- ws.onclose = () => {
153
- // Garde anti-race : si ce socket n'est plus le socket courant (une
154
- // nouvelle connexion l'a remplacé, ou disconnect() a déjà nettoyé),
155
- // son `onclose` tardif ne doit PAS toucher l'état partagé.
156
- if (ws !== this._ws) return
157
- this._ws = null
158
- // Nouvelle connexion (après reconnexion auto) ⇒ le token devra être renvoyé.
159
- this._lastSentToken = null
160
- this._heartbeat.stop()
161
- if (this._intentionalClose) {
162
- this._setState('disconnected')
163
- this._intentionalClose = false
164
- } else if (this._autoReconnect) {
165
- this._scheduleReconnect()
166
- } else {
167
- this._setState('disconnected')
168
- }
169
- }
170
-
171
- ws.onerror = (evt) => {
172
- if (ws !== this._ws) return
173
- if (typeof console !== 'undefined') {
174
- console.warn('[aura-realtime] WebSocket error', evt)
175
- }
176
- }
177
- }
178
-
179
- /** Send raw data through the WebSocket. */
180
- private _send(data: string): void {
181
- if (this._ws && this._ws.readyState === WebSocket.OPEN) {
182
- this._ws.send(data)
183
- }
184
- }
185
-
186
- /** Refresh the JWT token on an existing connection (no disconnect). */
187
- refreshToken(token: string): void {
188
- if (token === this._lastSentToken) {
189
- this._scheduleTokenRefresh()
190
- return
191
- }
192
- this._lastSentToken = token
193
- this._send(JSON.stringify({ type: 'access_token', token }))
194
- this._scheduleTokenRefresh()
195
- }
196
-
197
- /**
198
- * Définit/rafraîchit explicitement le token utilisé pour l'autorisation des
199
- * canaux privés et broadcast (parité `@supabase/realtime-js` `setAuth`).
200
- *
201
- * - Avec `token` : utilise ce token. Sinon, reprend `client.authStore.token`.
202
- * - Propage via le pipeline existant `refreshToken` (push
203
- * `{ type:'access_token', token }` sur une connexion ouverte, dédupliqué via
204
- * `_lastSentToken`). N'ouvre ni ne ferme aucune connexion WS.
205
- * - Hors-ligne : `connect()` lit `client.authStore.token` au moment de l'open,
206
- * donc `setAuth()` doit être appelé avec un token présent dans le store (ou
207
- * après authentification) pour prendre effet sur une future connexion.
208
- *
209
- * À appeler AVANT de s'abonner à un canal privé (`channel(name,{private:true})`).
210
- *
211
- * @example
212
- * ```ts
213
- * aura.realtime.setAuth(session.access_token)
214
- * const ch = aura.realtime.channel('secret', { private: true }).subscribe()
215
- * ```
216
- */
217
- setAuth(token?: string): void {
218
- const resolved = token ?? this.client.authStore.token
219
- if (resolved == null) return
220
- this.refreshToken(resolved)
221
- }
222
-
223
- /**
224
- * Envoie un broadcast par HTTP (REST), sans connexion WebSocket ouverte
225
- * (parité `@supabase/realtime-js`). Utile côté serveur/edge.
226
- *
227
- * POST `/v1/realtime/{projectId}/broadcast` avec le contrat du handler backend
228
- * (`broadcast.rs`) : `{ channel, payload }`, `channel` préfixé par le projet,
229
- * `event` replié dans `payload` (aligné sur le broadcast WS).
230
- *
231
- * @param channel Nom du canal (préfixé projet automatiquement si absent).
232
- * @param event Nom de l'événement broadcast.
233
- * @param payload Données de l'événement.
234
- * @returns `AuraResponse<null>` — `error` non nul en cas de 4xx/rate-limit.
235
- *
236
- * @example
237
- * ```ts
238
- * await aura.realtime.httpBroadcast('room-1', 'cursor', { x: 10, y: 20 })
239
- * ```
240
- */
241
- httpBroadcast(
242
- channel: string,
243
- event: string,
244
- payload: Record<string, unknown> = {},
245
- ): Promise<AuraResponse<null>> {
246
- const prefix = `${this.client.projectId}:`
247
- const fullChannel = channel.startsWith(prefix) ? channel : `${prefix}${channel}`
248
- const body = {
249
- channel: fullChannel,
250
- payload: { event, ...payload },
251
- }
252
- return fetchWithAuth<null>(
253
- `${this.client.baseUrl}/v1/realtime/${this.client.projectId}/broadcast`,
254
- { method: 'POST', body },
255
- this.client,
256
- )
257
- }
258
-
259
- /**
260
- * Schedule proactive token refresh at 80% of the JWT TTL.
261
- * Prevents token expiration during an active WebSocket session.
262
- */
263
- private _scheduleTokenRefresh(): void {
264
- if (this._tokenRefreshTimer) {
265
- clearTimeout(this._tokenRefreshTimer)
266
- this._tokenRefreshTimer = null
267
- }
268
- const token = this.client.authStore.token
269
- if (!token) return
270
- try {
271
- const payload = JSON.parse(atob(token.split('.')[1]))
272
- const exp = payload.exp * 1000
273
- const ttl = exp - Date.now()
274
- if (ttl <= 0) return
275
- // Refresh at 80% of the remaining TTL
276
- const refreshIn = ttl * 0.8
277
- this._tokenRefreshTimer = setTimeout(async () => {
278
- this._tokenRefreshTimer = null
279
- try {
280
- const res = await this.client.auth.refreshSession()
281
- if (res.data) {
282
- this.refreshToken(res.data.access_token)
283
- }
284
- } catch {
285
- // Refresh failed — the server will eventually disconnect on token expiry
286
- }
287
- }, refreshIn)
288
- } catch {
289
- // JWT decode failed — skip proactive refresh
290
- }
291
- }
292
-
293
- /** Schedule a reconnection attempt with exponential backoff + jitter. */
294
- private _scheduleReconnect(): void {
295
- // Clear any existing timer to avoid double-reconnect
296
- if (this._reconnectTimer) {
297
- clearTimeout(this._reconnectTimer)
298
- this._reconnectTimer = null
299
- }
300
-
301
- if (this._reconnectAttempts >= this._maxReconnectAttempts) {
302
- this._setState('disconnected')
303
- return
304
- }
305
-
306
- this._reconnectAttempts++
307
- this._setState('reconnecting')
308
-
309
- const idx = Math.min(this._reconnectAttempts - 1, RealtimeService.BACKOFF_MS.length - 1)
310
- const baseDelay = RealtimeService.BACKOFF_MS[idx]
311
- const jitter = Math.random() * baseDelay * 0.25
312
- const delay = baseDelay + jitter
313
-
314
- this._reconnectTimer = setTimeout(() => {
315
- this._reconnectTimer = null
316
- this.connect()
317
- }, delay)
318
- }
319
-
320
- /** Enable/disable auto-reconnect (enabled by default). */
321
- setAutoReconnect(enabled: boolean, maxAttempts?: number): void {
322
- this._autoReconnect = enabled
323
- if (maxAttempts !== undefined) this._maxReconnectAttempts = maxAttempts
324
- }
325
-
326
- /** Disconnect the WebSocket and clean up all channels. */
327
- disconnect(): void {
328
- this._intentionalClose = true
329
- this._heartbeat.stop()
330
- if (this._tokenRefreshTimer) {
331
- clearTimeout(this._tokenRefreshTimer)
332
- this._tokenRefreshTimer = null
333
- }
334
- if (this._reconnectTimer) {
335
- clearTimeout(this._reconnectTimer)
336
- this._reconnectTimer = null
337
- }
338
- this._reconnectAttempts = 0
339
- for (const channel of this._channels.values()) {
340
- channel.unsubscribe()
341
- }
342
- this._channels.clear()
343
- if (this._ws) {
344
- this._ws.close()
345
- this._ws = null
346
- }
347
- this._setState('disconnected')
348
- this._lastSentToken = null
349
- }
350
-
351
- // ─── Channel factory ────────────────────────────────────────────────────
352
-
353
- /**
354
- * Create or retrieve a channel by name.
355
- * Returns an `AuraChannel` with chainable `.on()` / `.subscribe()` API.
356
- *
357
- * @example
358
- * ```ts
359
- * const channel = aura.realtime.channel('room-1')
360
- * ```
361
- */
362
- channel(name: string, options?: ChannelConfig): AuraChannel {
363
- const existing = this._channels.get(name)
364
- if (existing) return existing
365
-
366
- const ch = new AuraChannel(name, this.client.projectId, options)
367
- this._channels.set(name, ch)
368
-
369
- // Établit la connexion WS si nécessaire (idempotent — connect() vérifie
370
- // déjà readyState avant d'ouvrir un nouveau socket).
371
- this.connect()
372
-
373
- // If already connected, bind immediately
374
- if (this._ws && this._ws.readyState === WebSocket.OPEN) {
375
- ch._bindSend((data) => this._send(data))
376
- }
377
-
378
- return ch
379
- }
380
-
381
- /** Remove a channel. */
382
- removeChannel(name: string): void {
383
- const ch = this._channels.get(name)
384
- if (ch) {
385
- ch.unsubscribe()
386
- this._channels.delete(name)
387
- }
388
- }
389
-
390
- /** List active channels. */
391
- getChannels(): AuraChannel[] {
392
- return Array.from(this._channels.values())
393
- }
394
-
395
- /** Remove all channels and subscriptions. */
396
- removeAllChannels(): void {
397
- for (const ch of this._channels.values()) {
398
- ch.unsubscribe()
399
- }
400
- this._channels.clear()
401
- }
402
-
403
- // ─── Message dispatch ───────────────────────────────────────────────────
404
-
405
- /** Route incoming server messages to the correct channel. */
406
- private _dispatch(msg: ServerMessage): void {
407
- // Extract channel name — present in subscribed, presence_state, OR topic in event messages
408
- // ServerMessage::Event uses 'topic' (serde flatten de RealtimeEvent), pas 'channel'
409
- const channelFull = 'channel' in msg
410
- ? (msg as { channel?: string }).channel
411
- : 'topic' in msg
412
- ? (msg as { topic?: string }).topic
413
- : undefined
414
-
415
- if (channelFull) {
416
- // Strip project prefix to find channel
417
- const prefix = `${this.client.projectId}:`
418
- const name = channelFull.startsWith(prefix) ? channelFull.slice(prefix.length) : channelFull
419
- const ch = this._channels.get(name)
420
- if (ch) {
421
- ch._onMessage(msg)
422
- return
423
- }
424
-
425
- // Try matching by full name (for CDC channels like proj:db:schema.table)
426
- // The channel might have been created with a short name but CDC sends full topic
427
- for (const [, channel] of this._channels) {
428
- if (channel.fullName === channelFull || channelFull.startsWith(channel.fullName + ':')) {
429
- channel._onMessage(msg)
430
- return
431
- }
432
- }
433
- }
434
-
435
- // Messages without channel (pong, token_refreshed, global errors)
436
- if (msg.type === 'token_refreshed') {
437
- // Global token refresh ACK — no action needed
438
- return
439
- }
440
-
441
- if (msg.type === 'pong') {
442
- // Keepalive — no action needed
443
- return
444
- }
445
-
446
- if (msg.type === 'broadcast_ack') {
447
- // Router l'ACK vers le SEUL channel émetteur. Le `ref_id` est préfixé par
448
- // le `fullName` du channel (`{fullName}:r{n}`, cf. AuraChannel._nextRef) :
449
- // on récupère le suffixe `:r{n}` via lastIndexOf (robuste à un nom de
450
- // channel contenant lui-même « :r ») et on résout par `fullName`.
451
- const ack = msg as BroadcastAckMessage
452
- const refId = ack.ref_id ?? ack.message_id
453
- if (refId) {
454
- const marker = refId.lastIndexOf(':r')
455
- if (marker > 0) {
456
- const fullName = refId.slice(0, marker)
457
- for (const ch of this._channels.values()) {
458
- if (ch.fullName === fullName) {
459
- ch._onMessage(msg)
460
- return
461
- }
462
- }
463
- }
464
- }
465
- // Fallback prudent : `ref_id` non résoluble (préfixe inattendu ou
466
- // `message_id` brut sans « :r ») → dispatch à tous pour ne pas perdre
467
- // l'ACK. Chaque channel n'agit que sur un `ref_id`/`message_id` présent
468
- // dans ses `_pendingAcks`, donc aucun faux positif.
469
- for (const ch of this._channels.values()) {
470
- ch._onMessage(msg)
471
- }
472
- return
473
- }
474
-
475
- // Broadcast to all channels for unroutable messages
476
- if (msg.type === 'error') {
477
- for (const ch of this._channels.values()) {
478
- ch._onMessage(msg)
479
- }
480
- }
481
- }
482
-
483
- // ─── Backward compatibility ─────────────────────────────────────────────
484
-
485
- /**
486
- * Simple callback-based subscription (legacy API).
487
- * Prefer using `.channel().on().subscribe()` instead.
488
- *
489
- * @deprecated Use `channel().on().subscribe()` instead.
490
- */
491
- on<T = Record<string, unknown>>(
492
- channelName: string,
493
- callback: (event: any) => void,
494
- ): { unsubscribe: () => void } {
495
- this.connect()
496
-
497
- const ch = this.channel(channelName)
498
- ch.on('postgres_changes', { event: '*' }, callback)
499
- ch.subscribe()
500
-
501
- return {
502
- unsubscribe: () => this.removeChannel(channelName),
503
- }
504
- }
505
- }