@syncular/server 0.1.3 → 0.2.1

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 (758) hide show
  1. package/README.md +773 -13
  2. package/dist/admin.d.ts +136 -0
  3. package/dist/admin.js +168 -0
  4. package/dist/blob-handlers.d.ts +69 -0
  5. package/dist/blob-handlers.js +245 -0
  6. package/dist/blob-store.d.ts +111 -0
  7. package/dist/blob-store.js +0 -0
  8. package/dist/content-encoding.d.ts +27 -0
  9. package/dist/content-encoding.js +69 -0
  10. package/dist/context.d.ts +151 -0
  11. package/dist/context.js +21 -0
  12. package/dist/crdt-merger.d.ts +28 -0
  13. package/dist/crdt-merger.js +11 -0
  14. package/dist/d1-storage.d.ts +50 -0
  15. package/dist/d1-storage.js +0 -0
  16. package/dist/errors.d.ts +35 -9
  17. package/dist/errors.js +220 -11
  18. package/dist/events-ring.d.ts +55 -0
  19. package/dist/events-ring.js +96 -0
  20. package/dist/events.d.ts +231 -0
  21. package/dist/events.js +22 -0
  22. package/dist/frame-bytes.d.ts +20 -0
  23. package/dist/frame-bytes.js +75 -0
  24. package/dist/handler.d.ts +9 -0
  25. package/dist/handler.js +490 -0
  26. package/dist/index.d.ts +42 -33
  27. package/dist/index.js +45 -27
  28. package/dist/lease-store.d.ts +50 -0
  29. package/dist/lease-store.js +0 -0
  30. package/dist/pg-executor-pglite.d.ts +27 -0
  31. package/dist/pg-executor-pglite.js +33 -0
  32. package/dist/pg-executor.d.ts +67 -0
  33. package/dist/pg-executor.js +56 -0
  34. package/dist/postgres-fanout.d.ts +83 -0
  35. package/dist/postgres-fanout.js +71 -0
  36. package/dist/postgres-storage.d.ts +69 -0
  37. package/dist/postgres-storage.js +766 -0
  38. package/dist/prune.d.ts +24 -39
  39. package/dist/prune.js +44 -146
  40. package/dist/pull.d.ts +42 -67
  41. package/dist/pull.js +387 -1187
  42. package/dist/push.d.ts +31 -66
  43. package/dist/push.js +406 -655
  44. package/dist/realtime.d.ts +197 -0
  45. package/dist/realtime.js +848 -0
  46. package/dist/relational-rows.d.ts +229 -0
  47. package/dist/relational-rows.js +514 -0
  48. package/dist/s3-blob-store.d.ts +142 -0
  49. package/dist/s3-blob-store.js +458 -0
  50. package/dist/s3-segment-store.d.ts +95 -0
  51. package/dist/s3-segment-store.js +380 -0
  52. package/dist/schema.d.ts +82 -286
  53. package/dist/schema.js +133 -9
  54. package/dist/scopes.d.ts +48 -0
  55. package/dist/scopes.js +98 -0
  56. package/dist/segment-download.d.ts +14 -0
  57. package/dist/segment-download.js +125 -0
  58. package/dist/segment-store.d.ts +81 -0
  59. package/dist/segment-store.js +63 -0
  60. package/dist/signed-url.d.ts +139 -0
  61. package/dist/signed-url.js +143 -0
  62. package/dist/sigv4.d.ts +97 -0
  63. package/dist/sigv4.js +161 -0
  64. package/dist/sqlite-blob-store.d.ts +22 -0
  65. package/dist/sqlite-blob-store.js +86 -0
  66. package/dist/sqlite-dialect.d.ts +101 -0
  67. package/dist/sqlite-dialect.js +250 -0
  68. package/dist/sqlite-image.d.ts +27 -0
  69. package/dist/sqlite-image.js +83 -0
  70. package/dist/sqlite-lease-store.d.ts +21 -0
  71. package/dist/sqlite-lease-store.js +94 -0
  72. package/dist/sqlite-segment-store.d.ts +25 -0
  73. package/dist/sqlite-segment-store.js +115 -0
  74. package/dist/sqlite-storage.d.ts +47 -0
  75. package/dist/sqlite-storage.js +477 -0
  76. package/dist/storage.d.ts +252 -0
  77. package/dist/storage.js +1 -0
  78. package/dist/validate.d.ts +83 -0
  79. package/dist/validate.js +44 -0
  80. package/package.json +17 -325
  81. package/src/admin.ts +312 -0
  82. package/src/blob-handlers.ts +340 -0
  83. package/src/blob-store.ts +0 -0
  84. package/src/content-encoding.ts +94 -0
  85. package/src/context.ts +176 -0
  86. package/src/crdt-merger.ts +33 -0
  87. package/src/d1-storage.ts +0 -0
  88. package/src/errors.ts +241 -19
  89. package/src/events-ring.ts +116 -0
  90. package/src/events.ts +291 -0
  91. package/src/frame-bytes.ts +94 -0
  92. package/src/handler.ts +678 -0
  93. package/src/index.ts +44 -27
  94. package/src/lease-store.ts +0 -0
  95. package/src/pg-executor-pglite.ts +63 -0
  96. package/src/pg-executor.ts +87 -0
  97. package/src/postgres-fanout.ts +143 -0
  98. package/src/postgres-storage.ts +1182 -0
  99. package/src/prune.ts +63 -289
  100. package/src/pull.ts +505 -1805
  101. package/src/push.ts +623 -1006
  102. package/src/realtime.ts +1082 -0
  103. package/src/relational-rows.ts +633 -0
  104. package/src/s3-blob-store.ts +616 -0
  105. package/src/s3-segment-store.ts +519 -0
  106. package/src/schema.ts +242 -281
  107. package/src/scopes.ts +127 -0
  108. package/src/segment-download.ts +169 -0
  109. package/src/segment-store.ts +154 -0
  110. package/src/signed-url.ts +308 -0
  111. package/src/sigv4.ts +267 -0
  112. package/src/sqlite-blob-store.ts +125 -0
  113. package/src/sqlite-dialect.ts +337 -0
  114. package/src/sqlite-image.ts +124 -0
  115. package/src/sqlite-lease-store.ts +144 -0
  116. package/src/sqlite-segment-store.ts +204 -0
  117. package/src/sqlite-storage.ts +792 -0
  118. package/src/storage.ts +316 -0
  119. package/src/validate.ts +123 -0
  120. package/dist/auth-leases.d.ts +0 -85
  121. package/dist/auth-leases.d.ts.map +0 -1
  122. package/dist/auth-leases.js +0 -368
  123. package/dist/auth-leases.js.map +0 -1
  124. package/dist/better-sqlite3.d.ts +0 -22
  125. package/dist/better-sqlite3.d.ts.map +0 -1
  126. package/dist/better-sqlite3.js +0 -16
  127. package/dist/better-sqlite3.js.map +0 -1
  128. package/dist/blobs/access.d.ts +0 -35
  129. package/dist/blobs/access.d.ts.map +0 -1
  130. package/dist/blobs/access.js +0 -149
  131. package/dist/blobs/access.js.map +0 -1
  132. package/dist/blobs/adapters/database.d.ts +0 -100
  133. package/dist/blobs/adapters/database.d.ts.map +0 -1
  134. package/dist/blobs/adapters/database.js +0 -247
  135. package/dist/blobs/adapters/database.js.map +0 -1
  136. package/dist/blobs/index.d.ts +0 -9
  137. package/dist/blobs/index.d.ts.map +0 -1
  138. package/dist/blobs/index.js +0 -9
  139. package/dist/blobs/index.js.map +0 -1
  140. package/dist/blobs/manager.d.ts +0 -220
  141. package/dist/blobs/manager.d.ts.map +0 -1
  142. package/dist/blobs/manager.js +0 -625
  143. package/dist/blobs/manager.js.map +0 -1
  144. package/dist/blobs/migrate.d.ts +0 -27
  145. package/dist/blobs/migrate.d.ts.map +0 -1
  146. package/dist/blobs/migrate.js +0 -127
  147. package/dist/blobs/migrate.js.map +0 -1
  148. package/dist/blobs/types.d.ts +0 -58
  149. package/dist/blobs/types.d.ts.map +0 -1
  150. package/dist/blobs/types.js +0 -5
  151. package/dist/blobs/types.js.map +0 -1
  152. package/dist/bun-sqlite.d.ts +0 -19
  153. package/dist/bun-sqlite.d.ts.map +0 -1
  154. package/dist/bun-sqlite.js +0 -19
  155. package/dist/bun-sqlite.js.map +0 -1
  156. package/dist/clients.d.ts +0 -15
  157. package/dist/clients.d.ts.map +0 -1
  158. package/dist/clients.js +0 -7
  159. package/dist/clients.js.map +0 -1
  160. package/dist/cloudflare/durable-object.d.ts +0 -93
  161. package/dist/cloudflare/durable-object.d.ts.map +0 -1
  162. package/dist/cloudflare/durable-object.js +0 -210
  163. package/dist/cloudflare/durable-object.js.map +0 -1
  164. package/dist/cloudflare/index.d.ts +0 -22
  165. package/dist/cloudflare/index.d.ts.map +0 -1
  166. package/dist/cloudflare/index.js +0 -22
  167. package/dist/cloudflare/index.js.map +0 -1
  168. package/dist/cloudflare/r2.d.ts +0 -180
  169. package/dist/cloudflare/r2.d.ts.map +0 -1
  170. package/dist/cloudflare/r2.js +0 -258
  171. package/dist/cloudflare/r2.js.map +0 -1
  172. package/dist/cloudflare/scope-cache.d.ts +0 -54
  173. package/dist/cloudflare/scope-cache.d.ts.map +0 -1
  174. package/dist/cloudflare/scope-cache.js +0 -223
  175. package/dist/cloudflare/scope-cache.js.map +0 -1
  176. package/dist/cloudflare/sentry.d.ts +0 -47
  177. package/dist/cloudflare/sentry.d.ts.map +0 -1
  178. package/dist/cloudflare/sentry.js +0 -163
  179. package/dist/cloudflare/sentry.js.map +0 -1
  180. package/dist/cloudflare/worker.d.ts +0 -46
  181. package/dist/cloudflare/worker.d.ts.map +0 -1
  182. package/dist/cloudflare/worker.js +0 -63
  183. package/dist/cloudflare/worker.js.map +0 -1
  184. package/dist/commit-integrity.d.ts +0 -38
  185. package/dist/commit-integrity.d.ts.map +0 -1
  186. package/dist/commit-integrity.js +0 -260
  187. package/dist/commit-integrity.js.map +0 -1
  188. package/dist/compaction.d.ts +0 -27
  189. package/dist/compaction.d.ts.map +0 -1
  190. package/dist/compaction.js +0 -49
  191. package/dist/compaction.js.map +0 -1
  192. package/dist/crdt-yjs/index.d.ts +0 -99
  193. package/dist/crdt-yjs/index.d.ts.map +0 -1
  194. package/dist/crdt-yjs/index.js +0 -629
  195. package/dist/crdt-yjs/index.js.map +0 -1
  196. package/dist/d1.d.ts +0 -13
  197. package/dist/d1.d.ts.map +0 -1
  198. package/dist/d1.js +0 -14
  199. package/dist/d1.js.map +0 -1
  200. package/dist/dialect/base.d.ts +0 -93
  201. package/dist/dialect/base.d.ts.map +0 -1
  202. package/dist/dialect/base.js +0 -181
  203. package/dist/dialect/base.js.map +0 -1
  204. package/dist/dialect/helpers.d.ts +0 -16
  205. package/dist/dialect/helpers.d.ts.map +0 -1
  206. package/dist/dialect/helpers.js +0 -83
  207. package/dist/dialect/helpers.js.map +0 -1
  208. package/dist/dialect/index.d.ts +0 -7
  209. package/dist/dialect/index.d.ts.map +0 -1
  210. package/dist/dialect/index.js +0 -7
  211. package/dist/dialect/index.js.map +0 -1
  212. package/dist/dialect/types.d.ts +0 -187
  213. package/dist/dialect/types.d.ts.map +0 -1
  214. package/dist/dialect/types.js +0 -8
  215. package/dist/dialect/types.js.map +0 -1
  216. package/dist/encrypted-crdt.d.ts +0 -67
  217. package/dist/encrypted-crdt.d.ts.map +0 -1
  218. package/dist/encrypted-crdt.js +0 -426
  219. package/dist/encrypted-crdt.js.map +0 -1
  220. package/dist/errors.d.ts.map +0 -1
  221. package/dist/errors.js.map +0 -1
  222. package/dist/filesystem/index.d.ts +0 -44
  223. package/dist/filesystem/index.d.ts.map +0 -1
  224. package/dist/filesystem/index.js +0 -164
  225. package/dist/filesystem/index.js.map +0 -1
  226. package/dist/handlers/collection.d.ts +0 -20
  227. package/dist/handlers/collection.d.ts.map +0 -1
  228. package/dist/handlers/collection.js +0 -42
  229. package/dist/handlers/collection.js.map +0 -1
  230. package/dist/handlers/create-handler.d.ts +0 -156
  231. package/dist/handlers/create-handler.d.ts.map +0 -1
  232. package/dist/handlers/create-handler.js +0 -626
  233. package/dist/handlers/create-handler.js.map +0 -1
  234. package/dist/handlers/index.d.ts +0 -4
  235. package/dist/handlers/index.d.ts.map +0 -1
  236. package/dist/handlers/index.js +0 -4
  237. package/dist/handlers/index.js.map +0 -1
  238. package/dist/handlers/types.d.ts +0 -295
  239. package/dist/handlers/types.d.ts.map +0 -1
  240. package/dist/handlers/types.js +0 -2
  241. package/dist/handlers/types.js.map +0 -1
  242. package/dist/helpers/conflict.d.ts +0 -52
  243. package/dist/helpers/conflict.d.ts.map +0 -1
  244. package/dist/helpers/conflict.js +0 -49
  245. package/dist/helpers/conflict.js.map +0 -1
  246. package/dist/helpers/emitted-change.d.ts +0 -56
  247. package/dist/helpers/emitted-change.d.ts.map +0 -1
  248. package/dist/helpers/emitted-change.js +0 -46
  249. package/dist/helpers/emitted-change.js.map +0 -1
  250. package/dist/helpers/index.d.ts +0 -12
  251. package/dist/helpers/index.d.ts.map +0 -1
  252. package/dist/helpers/index.js +0 -12
  253. package/dist/helpers/index.js.map +0 -1
  254. package/dist/helpers/paginate.d.ts +0 -49
  255. package/dist/helpers/paginate.d.ts.map +0 -1
  256. package/dist/helpers/paginate.js +0 -54
  257. package/dist/helpers/paginate.js.map +0 -1
  258. package/dist/helpers/scope-authorization.d.ts +0 -7
  259. package/dist/helpers/scope-authorization.d.ts.map +0 -1
  260. package/dist/helpers/scope-authorization.js +0 -19
  261. package/dist/helpers/scope-authorization.js.map +0 -1
  262. package/dist/helpers/scope-commit-index.d.ts +0 -12
  263. package/dist/helpers/scope-commit-index.d.ts.map +0 -1
  264. package/dist/helpers/scope-commit-index.js +0 -35
  265. package/dist/helpers/scope-commit-index.js.map +0 -1
  266. package/dist/helpers/scope-strings.d.ts +0 -74
  267. package/dist/helpers/scope-strings.d.ts.map +0 -1
  268. package/dist/helpers/scope-strings.js +0 -82
  269. package/dist/helpers/scope-strings.js.map +0 -1
  270. package/dist/hono/api-key-auth.d.ts +0 -49
  271. package/dist/hono/api-key-auth.d.ts.map +0 -1
  272. package/dist/hono/api-key-auth.js +0 -108
  273. package/dist/hono/api-key-auth.js.map +0 -1
  274. package/dist/hono/audit-redaction.d.ts +0 -20
  275. package/dist/hono/audit-redaction.d.ts.map +0 -1
  276. package/dist/hono/audit-redaction.js +0 -85
  277. package/dist/hono/audit-redaction.js.map +0 -1
  278. package/dist/hono/blobs.d.ts +0 -75
  279. package/dist/hono/blobs.d.ts.map +0 -1
  280. package/dist/hono/blobs.js +0 -586
  281. package/dist/hono/blobs.js.map +0 -1
  282. package/dist/hono/console/gateway.d.ts +0 -42
  283. package/dist/hono/console/gateway.d.ts.map +0 -1
  284. package/dist/hono/console/gateway.js +0 -2158
  285. package/dist/hono/console/gateway.js.map +0 -1
  286. package/dist/hono/console/live-auth.d.ts +0 -7
  287. package/dist/hono/console/live-auth.d.ts.map +0 -1
  288. package/dist/hono/console/live-auth.js +0 -39
  289. package/dist/hono/console/live-auth.js.map +0 -1
  290. package/dist/hono/console/route-descriptor.d.ts +0 -6
  291. package/dist/hono/console/route-descriptor.d.ts.map +0 -1
  292. package/dist/hono/console/route-descriptor.js +0 -16
  293. package/dist/hono/console/route-descriptor.js.map +0 -1
  294. package/dist/hono/console/routes/api-keys.d.ts +0 -8
  295. package/dist/hono/console/routes/api-keys.d.ts.map +0 -1
  296. package/dist/hono/console/routes/api-keys.js +0 -575
  297. package/dist/hono/console/routes/api-keys.js.map +0 -1
  298. package/dist/hono/console/routes/clients.d.ts +0 -8
  299. package/dist/hono/console/routes/clients.d.ts.map +0 -1
  300. package/dist/hono/console/routes/clients.js +0 -322
  301. package/dist/hono/console/routes/clients.js.map +0 -1
  302. package/dist/hono/console/routes/commits.d.ts +0 -8
  303. package/dist/hono/console/routes/commits.d.ts.map +0 -1
  304. package/dist/hono/console/routes/commits.js +0 -882
  305. package/dist/hono/console/routes/commits.js.map +0 -1
  306. package/dist/hono/console/routes/context.d.ts +0 -188
  307. package/dist/hono/console/routes/context.d.ts.map +0 -1
  308. package/dist/hono/console/routes/context.js +0 -633
  309. package/dist/hono/console/routes/context.js.map +0 -1
  310. package/dist/hono/console/routes/events.d.ts +0 -8
  311. package/dist/hono/console/routes/events.d.ts.map +0 -1
  312. package/dist/hono/console/routes/events.js +0 -501
  313. package/dist/hono/console/routes/events.js.map +0 -1
  314. package/dist/hono/console/routes/maintenance.d.ts +0 -8
  315. package/dist/hono/console/routes/maintenance.d.ts.map +0 -1
  316. package/dist/hono/console/routes/maintenance.js +0 -341
  317. package/dist/hono/console/routes/maintenance.js.map +0 -1
  318. package/dist/hono/console/routes/shared.d.ts +0 -174
  319. package/dist/hono/console/routes/shared.d.ts.map +0 -1
  320. package/dist/hono/console/routes/shared.js +0 -583
  321. package/dist/hono/console/routes/shared.js.map +0 -1
  322. package/dist/hono/console/routes/stats.d.ts +0 -8
  323. package/dist/hono/console/routes/stats.d.ts.map +0 -1
  324. package/dist/hono/console/routes/stats.js +0 -295
  325. package/dist/hono/console/routes/stats.js.map +0 -1
  326. package/dist/hono/console/routes/storage.d.ts +0 -8
  327. package/dist/hono/console/routes/storage.d.ts.map +0 -1
  328. package/dist/hono/console/routes/storage.js +0 -121
  329. package/dist/hono/console/routes/storage.js.map +0 -1
  330. package/dist/hono/console/routes.d.ts +0 -36
  331. package/dist/hono/console/routes.d.ts.map +0 -1
  332. package/dist/hono/console/routes.js +0 -112
  333. package/dist/hono/console/routes.js.map +0 -1
  334. package/dist/hono/console/schema-errors.d.ts +0 -2
  335. package/dist/hono/console/schema-errors.d.ts.map +0 -1
  336. package/dist/hono/console/schema-errors.js +0 -17
  337. package/dist/hono/console/schema-errors.js.map +0 -1
  338. package/dist/hono/console/schemas.d.ts +0 -1515
  339. package/dist/hono/console/schemas.d.ts.map +0 -1
  340. package/dist/hono/console/schemas.js +0 -661
  341. package/dist/hono/console/schemas.js.map +0 -1
  342. package/dist/hono/console/types.d.ts +0 -213
  343. package/dist/hono/console/types.d.ts.map +0 -1
  344. package/dist/hono/console/types.js +0 -2
  345. package/dist/hono/console/types.js.map +0 -1
  346. package/dist/hono/console/ui.d.ts +0 -38
  347. package/dist/hono/console/ui.d.ts.map +0 -1
  348. package/dist/hono/console/ui.js +0 -43
  349. package/dist/hono/console/ui.js.map +0 -1
  350. package/dist/hono/create-server.d.ts +0 -71
  351. package/dist/hono/create-server.d.ts.map +0 -1
  352. package/dist/hono/create-server.js +0 -121
  353. package/dist/hono/create-server.js.map +0 -1
  354. package/dist/hono/errors.d.ts +0 -13
  355. package/dist/hono/errors.d.ts.map +0 -1
  356. package/dist/hono/errors.js +0 -21
  357. package/dist/hono/errors.js.map +0 -1
  358. package/dist/hono/index.d.ts +0 -20
  359. package/dist/hono/index.d.ts.map +0 -1
  360. package/dist/hono/index.js +0 -31
  361. package/dist/hono/index.js.map +0 -1
  362. package/dist/hono/openapi.d.ts +0 -72
  363. package/dist/hono/openapi.d.ts.map +0 -1
  364. package/dist/hono/openapi.js +0 -99
  365. package/dist/hono/openapi.js.map +0 -1
  366. package/dist/hono/proxy/connection-manager.d.ts +0 -78
  367. package/dist/hono/proxy/connection-manager.d.ts.map +0 -1
  368. package/dist/hono/proxy/connection-manager.js +0 -251
  369. package/dist/hono/proxy/connection-manager.js.map +0 -1
  370. package/dist/hono/proxy/index.d.ts +0 -8
  371. package/dist/hono/proxy/index.d.ts.map +0 -1
  372. package/dist/hono/proxy/index.js +0 -8
  373. package/dist/hono/proxy/index.js.map +0 -1
  374. package/dist/hono/proxy/routes.d.ts +0 -86
  375. package/dist/hono/proxy/routes.d.ts.map +0 -1
  376. package/dist/hono/proxy/routes.js +0 -183
  377. package/dist/hono/proxy/routes.js.map +0 -1
  378. package/dist/hono/rate-limit.d.ts +0 -101
  379. package/dist/hono/rate-limit.d.ts.map +0 -1
  380. package/dist/hono/rate-limit.js +0 -184
  381. package/dist/hono/rate-limit.js.map +0 -1
  382. package/dist/hono/realtime-sync-packs.d.ts +0 -43
  383. package/dist/hono/realtime-sync-packs.d.ts.map +0 -1
  384. package/dist/hono/realtime-sync-packs.js +0 -219
  385. package/dist/hono/realtime-sync-packs.js.map +0 -1
  386. package/dist/hono/routes/audit.d.ts +0 -12
  387. package/dist/hono/routes/audit.d.ts.map +0 -1
  388. package/dist/hono/routes/audit.js +0 -385
  389. package/dist/hono/routes/audit.js.map +0 -1
  390. package/dist/hono/routes/auth-leases.d.ts +0 -8
  391. package/dist/hono/routes/auth-leases.d.ts.map +0 -1
  392. package/dist/hono/routes/auth-leases.js +0 -88
  393. package/dist/hono/routes/auth-leases.js.map +0 -1
  394. package/dist/hono/routes/combined.d.ts +0 -8
  395. package/dist/hono/routes/combined.d.ts.map +0 -1
  396. package/dist/hono/routes/combined.js +0 -392
  397. package/dist/hono/routes/combined.js.map +0 -1
  398. package/dist/hono/routes/context.d.ts +0 -314
  399. package/dist/hono/routes/context.d.ts.map +0 -1
  400. package/dist/hono/routes/context.js +0 -1147
  401. package/dist/hono/routes/context.js.map +0 -1
  402. package/dist/hono/routes/health.d.ts +0 -8
  403. package/dist/hono/routes/health.d.ts.map +0 -1
  404. package/dist/hono/routes/health.js +0 -16
  405. package/dist/hono/routes/health.js.map +0 -1
  406. package/dist/hono/routes/realtime.d.ts +0 -9
  407. package/dist/hono/routes/realtime.d.ts.map +0 -1
  408. package/dist/hono/routes/realtime.js +0 -626
  409. package/dist/hono/routes/realtime.js.map +0 -1
  410. package/dist/hono/routes/shared.d.ts +0 -689
  411. package/dist/hono/routes/shared.d.ts.map +0 -1
  412. package/dist/hono/routes/shared.js +0 -972
  413. package/dist/hono/routes/shared.js.map +0 -1
  414. package/dist/hono/routes/snapshots.d.ts +0 -10
  415. package/dist/hono/routes/snapshots.d.ts.map +0 -1
  416. package/dist/hono/routes/snapshots.js +0 -281
  417. package/dist/hono/routes/snapshots.js.map +0 -1
  418. package/dist/hono/routes.d.ts +0 -19
  419. package/dist/hono/routes.d.ts.map +0 -1
  420. package/dist/hono/routes.js +0 -37
  421. package/dist/hono/routes.js.map +0 -1
  422. package/dist/hono/validation.d.ts +0 -5
  423. package/dist/hono/validation.d.ts.map +0 -1
  424. package/dist/hono/validation.js +0 -47
  425. package/dist/hono/validation.js.map +0 -1
  426. package/dist/hono/websocket-origin.d.ts +0 -9
  427. package/dist/hono/websocket-origin.d.ts.map +0 -1
  428. package/dist/hono/websocket-origin.js +0 -96
  429. package/dist/hono/websocket-origin.js.map +0 -1
  430. package/dist/hono/ws.d.ts +0 -341
  431. package/dist/hono/ws.d.ts.map +0 -1
  432. package/dist/hono/ws.js +0 -711
  433. package/dist/hono/ws.js.map +0 -1
  434. package/dist/index.d.ts.map +0 -1
  435. package/dist/index.js.map +0 -1
  436. package/dist/libsql.d.ts +0 -29
  437. package/dist/libsql.d.ts.map +0 -1
  438. package/dist/libsql.js +0 -25
  439. package/dist/libsql.js.map +0 -1
  440. package/dist/migrate.d.ts +0 -14
  441. package/dist/migrate.d.ts.map +0 -1
  442. package/dist/migrate.js +0 -13
  443. package/dist/migrate.js.map +0 -1
  444. package/dist/neon.d.ts +0 -21
  445. package/dist/neon.d.ts.map +0 -1
  446. package/dist/neon.js +0 -22
  447. package/dist/neon.js.map +0 -1
  448. package/dist/notify.d.ts +0 -77
  449. package/dist/notify.d.ts.map +0 -1
  450. package/dist/notify.js +0 -233
  451. package/dist/notify.js.map +0 -1
  452. package/dist/pglite.d.ts +0 -37
  453. package/dist/pglite.d.ts.map +0 -1
  454. package/dist/pglite.js +0 -37
  455. package/dist/pglite.js.map +0 -1
  456. package/dist/plugins/index.d.ts +0 -2
  457. package/dist/plugins/index.d.ts.map +0 -1
  458. package/dist/plugins/index.js +0 -2
  459. package/dist/plugins/index.js.map +0 -1
  460. package/dist/plugins/types.d.ts +0 -73
  461. package/dist/plugins/types.d.ts.map +0 -1
  462. package/dist/plugins/types.js +0 -30
  463. package/dist/plugins/types.js.map +0 -1
  464. package/dist/postgres/index.d.ts +0 -68
  465. package/dist/postgres/index.d.ts.map +0 -1
  466. package/dist/postgres/index.js +0 -924
  467. package/dist/postgres/index.js.map +0 -1
  468. package/dist/proxy/collection.d.ts +0 -7
  469. package/dist/proxy/collection.d.ts.map +0 -1
  470. package/dist/proxy/collection.js +0 -6
  471. package/dist/proxy/collection.js.map +0 -1
  472. package/dist/proxy/handler.d.ts +0 -42
  473. package/dist/proxy/handler.d.ts.map +0 -1
  474. package/dist/proxy/handler.js +0 -102
  475. package/dist/proxy/handler.js.map +0 -1
  476. package/dist/proxy/index.d.ts +0 -9
  477. package/dist/proxy/index.d.ts.map +0 -1
  478. package/dist/proxy/index.js +0 -14
  479. package/dist/proxy/index.js.map +0 -1
  480. package/dist/proxy/mutation-detector.d.ts +0 -35
  481. package/dist/proxy/mutation-detector.d.ts.map +0 -1
  482. package/dist/proxy/mutation-detector.js +0 -246
  483. package/dist/proxy/mutation-detector.js.map +0 -1
  484. package/dist/proxy/oplog.d.ts +0 -30
  485. package/dist/proxy/oplog.d.ts.map +0 -1
  486. package/dist/proxy/oplog.js +0 -137
  487. package/dist/proxy/oplog.js.map +0 -1
  488. package/dist/proxy/types.d.ts +0 -44
  489. package/dist/proxy/types.d.ts.map +0 -1
  490. package/dist/proxy/types.js +0 -7
  491. package/dist/proxy/types.js.map +0 -1
  492. package/dist/prune.d.ts.map +0 -1
  493. package/dist/prune.js.map +0 -1
  494. package/dist/pull.d.ts.map +0 -1
  495. package/dist/pull.js.map +0 -1
  496. package/dist/push.d.ts.map +0 -1
  497. package/dist/push.js.map +0 -1
  498. package/dist/realtime/in-memory.d.ts +0 -13
  499. package/dist/realtime/in-memory.d.ts.map +0 -1
  500. package/dist/realtime/in-memory.js +0 -28
  501. package/dist/realtime/in-memory.js.map +0 -1
  502. package/dist/realtime/index.d.ts +0 -4
  503. package/dist/realtime/index.d.ts.map +0 -1
  504. package/dist/realtime/index.js +0 -3
  505. package/dist/realtime/index.js.map +0 -1
  506. package/dist/realtime/types.d.ts +0 -62
  507. package/dist/realtime/types.d.ts.map +0 -1
  508. package/dist/realtime/types.js +0 -19
  509. package/dist/realtime/types.js.map +0 -1
  510. package/dist/relay/client-role/forward-engine.d.ts +0 -63
  511. package/dist/relay/client-role/forward-engine.d.ts.map +0 -1
  512. package/dist/relay/client-role/forward-engine.js +0 -267
  513. package/dist/relay/client-role/forward-engine.js.map +0 -1
  514. package/dist/relay/client-role/index.d.ts +0 -9
  515. package/dist/relay/client-role/index.d.ts.map +0 -1
  516. package/dist/relay/client-role/index.js +0 -9
  517. package/dist/relay/client-role/index.js.map +0 -1
  518. package/dist/relay/client-role/pull-engine.d.ts +0 -72
  519. package/dist/relay/client-role/pull-engine.d.ts.map +0 -1
  520. package/dist/relay/client-role/pull-engine.js +0 -249
  521. package/dist/relay/client-role/pull-engine.js.map +0 -1
  522. package/dist/relay/client-role/sequence-mapper.d.ts +0 -65
  523. package/dist/relay/client-role/sequence-mapper.d.ts.map +0 -1
  524. package/dist/relay/client-role/sequence-mapper.js +0 -161
  525. package/dist/relay/client-role/sequence-mapper.js.map +0 -1
  526. package/dist/relay/evaluation/relay-paths.d.ts +0 -41
  527. package/dist/relay/evaluation/relay-paths.d.ts.map +0 -1
  528. package/dist/relay/evaluation/relay-paths.js +0 -504
  529. package/dist/relay/evaluation/relay-paths.js.map +0 -1
  530. package/dist/relay/evaluation/rust-boundary.d.ts +0 -47
  531. package/dist/relay/evaluation/rust-boundary.d.ts.map +0 -1
  532. package/dist/relay/evaluation/rust-boundary.js +0 -220
  533. package/dist/relay/evaluation/rust-boundary.js.map +0 -1
  534. package/dist/relay/index.d.ts +0 -37
  535. package/dist/relay/index.d.ts.map +0 -1
  536. package/dist/relay/index.js +0 -44
  537. package/dist/relay/index.js.map +0 -1
  538. package/dist/relay/migrate.d.ts +0 -18
  539. package/dist/relay/migrate.d.ts.map +0 -1
  540. package/dist/relay/migrate.js +0 -99
  541. package/dist/relay/migrate.js.map +0 -1
  542. package/dist/relay/mode-manager.d.ts +0 -60
  543. package/dist/relay/mode-manager.d.ts.map +0 -1
  544. package/dist/relay/mode-manager.js +0 -114
  545. package/dist/relay/mode-manager.js.map +0 -1
  546. package/dist/relay/realtime.d.ts +0 -90
  547. package/dist/relay/realtime.d.ts.map +0 -1
  548. package/dist/relay/realtime.js +0 -147
  549. package/dist/relay/realtime.js.map +0 -1
  550. package/dist/relay/relay.d.ts +0 -190
  551. package/dist/relay/relay.d.ts.map +0 -1
  552. package/dist/relay/relay.js +0 -320
  553. package/dist/relay/relay.js.map +0 -1
  554. package/dist/relay/schema.d.ts +0 -158
  555. package/dist/relay/schema.d.ts.map +0 -1
  556. package/dist/relay/schema.js +0 -7
  557. package/dist/relay/schema.js.map +0 -1
  558. package/dist/relay/server-role/index.d.ts +0 -56
  559. package/dist/relay/server-role/index.d.ts.map +0 -1
  560. package/dist/relay/server-role/index.js +0 -193
  561. package/dist/relay/server-role/index.js.map +0 -1
  562. package/dist/relay/server-role/pull.d.ts +0 -27
  563. package/dist/relay/server-role/pull.d.ts.map +0 -1
  564. package/dist/relay/server-role/pull.js +0 -24
  565. package/dist/relay/server-role/pull.js.map +0 -1
  566. package/dist/relay/server-role/push.d.ts +0 -29
  567. package/dist/relay/server-role/push.d.ts.map +0 -1
  568. package/dist/relay/server-role/push.js +0 -122
  569. package/dist/relay/server-role/push.js.map +0 -1
  570. package/dist/s3/index.d.ts +0 -83
  571. package/dist/s3/index.d.ts.map +0 -1
  572. package/dist/s3/index.js +0 -223
  573. package/dist/s3/index.js.map +0 -1
  574. package/dist/schema.d.ts.map +0 -1
  575. package/dist/schema.js.map +0 -1
  576. package/dist/service-worker/index.d.ts +0 -114
  577. package/dist/service-worker/index.d.ts.map +0 -1
  578. package/dist/service-worker/index.js +0 -487
  579. package/dist/service-worker/index.js.map +0 -1
  580. package/dist/snapshot-artifacts/sqlite-bun.d.ts +0 -15
  581. package/dist/snapshot-artifacts/sqlite-bun.d.ts.map +0 -1
  582. package/dist/snapshot-artifacts/sqlite-bun.js +0 -128
  583. package/dist/snapshot-artifacts/sqlite-bun.js.map +0 -1
  584. package/dist/snapshot-artifacts.d.ts +0 -206
  585. package/dist/snapshot-artifacts.d.ts.map +0 -1
  586. package/dist/snapshot-artifacts.js +0 -545
  587. package/dist/snapshot-artifacts.js.map +0 -1
  588. package/dist/snapshot-chunks/db-metadata.d.ts +0 -56
  589. package/dist/snapshot-chunks/db-metadata.d.ts.map +0 -1
  590. package/dist/snapshot-chunks/db-metadata.js +0 -360
  591. package/dist/snapshot-chunks/db-metadata.js.map +0 -1
  592. package/dist/snapshot-chunks/index.d.ts +0 -8
  593. package/dist/snapshot-chunks/index.d.ts.map +0 -1
  594. package/dist/snapshot-chunks/index.js +0 -8
  595. package/dist/snapshot-chunks/index.js.map +0 -1
  596. package/dist/snapshot-chunks/types.d.ts +0 -80
  597. package/dist/snapshot-chunks/types.d.ts.map +0 -1
  598. package/dist/snapshot-chunks/types.js +0 -8
  599. package/dist/snapshot-chunks/types.js.map +0 -1
  600. package/dist/snapshot-chunks.d.ts +0 -90
  601. package/dist/snapshot-chunks.d.ts.map +0 -1
  602. package/dist/snapshot-chunks.js +0 -304
  603. package/dist/snapshot-chunks.js.map +0 -1
  604. package/dist/sqlite/index.d.ts +0 -53
  605. package/dist/sqlite/index.d.ts.map +0 -1
  606. package/dist/sqlite/index.js +0 -795
  607. package/dist/sqlite/index.js.map +0 -1
  608. package/dist/sqlite3.d.ts +0 -22
  609. package/dist/sqlite3.d.ts.map +0 -1
  610. package/dist/sqlite3.js +0 -99
  611. package/dist/sqlite3.js.map +0 -1
  612. package/dist/stats.d.ts +0 -28
  613. package/dist/stats.d.ts.map +0 -1
  614. package/dist/stats.js +0 -93
  615. package/dist/stats.js.map +0 -1
  616. package/dist/subscriptions/cache.d.ts +0 -58
  617. package/dist/subscriptions/cache.d.ts.map +0 -1
  618. package/dist/subscriptions/cache.js +0 -250
  619. package/dist/subscriptions/cache.js.map +0 -1
  620. package/dist/subscriptions/index.d.ts +0 -3
  621. package/dist/subscriptions/index.d.ts.map +0 -1
  622. package/dist/subscriptions/index.js +0 -3
  623. package/dist/subscriptions/index.js.map +0 -1
  624. package/dist/subscriptions/resolve.d.ts +0 -40
  625. package/dist/subscriptions/resolve.d.ts.map +0 -1
  626. package/dist/subscriptions/resolve.js +0 -275
  627. package/dist/subscriptions/resolve.js.map +0 -1
  628. package/dist/sync.d.ts +0 -24
  629. package/dist/sync.d.ts.map +0 -1
  630. package/dist/sync.js +0 -27
  631. package/dist/sync.js.map +0 -1
  632. package/src/auth-leases.ts +0 -649
  633. package/src/better-sqlite3.ts +0 -35
  634. package/src/blobs/access.ts +0 -244
  635. package/src/blobs/adapters/database.ts +0 -397
  636. package/src/blobs/index.ts +0 -9
  637. package/src/blobs/manager.ts +0 -901
  638. package/src/blobs/migrate.ts +0 -158
  639. package/src/blobs/types.ts +0 -74
  640. package/src/bun-sqlite-ambient.d.ts +0 -19
  641. package/src/bun-sqlite.ts +0 -27
  642. package/src/clients.ts +0 -22
  643. package/src/cloudflare/durable-object.ts +0 -289
  644. package/src/cloudflare/index.ts +0 -22
  645. package/src/cloudflare/r2.ts +0 -526
  646. package/src/cloudflare/scope-cache.ts +0 -341
  647. package/src/cloudflare/sentry.ts +0 -230
  648. package/src/cloudflare/worker.ts +0 -77
  649. package/src/commit-integrity.ts +0 -371
  650. package/src/compaction.ts +0 -77
  651. package/src/crdt-yjs/index.ts +0 -931
  652. package/src/d1.ts +0 -16
  653. package/src/dialect/base.ts +0 -360
  654. package/src/dialect/helpers.ts +0 -92
  655. package/src/dialect/index.ts +0 -7
  656. package/src/dialect/types.ts +0 -247
  657. package/src/encrypted-crdt.ts +0 -786
  658. package/src/filesystem/index.ts +0 -262
  659. package/src/handlers/collection.ts +0 -121
  660. package/src/handlers/create-handler.ts +0 -1134
  661. package/src/handlers/index.ts +0 -3
  662. package/src/handlers/types.ts +0 -403
  663. package/src/helpers/conflict.ts +0 -64
  664. package/src/helpers/emitted-change.ts +0 -69
  665. package/src/helpers/index.ts +0 -12
  666. package/src/helpers/paginate.ts +0 -82
  667. package/src/helpers/scope-authorization.ts +0 -27
  668. package/src/helpers/scope-commit-index.ts +0 -52
  669. package/src/helpers/scope-strings.ts +0 -101
  670. package/src/hono/api-key-auth.ts +0 -177
  671. package/src/hono/audit-redaction.ts +0 -135
  672. package/src/hono/blobs.ts +0 -851
  673. package/src/hono/console/gateway.ts +0 -3046
  674. package/src/hono/console/live-auth.ts +0 -46
  675. package/src/hono/console/route-descriptor.ts +0 -22
  676. package/src/hono/console/routes/api-keys.ts +0 -721
  677. package/src/hono/console/routes/clients.ts +0 -447
  678. package/src/hono/console/routes/commits.ts +0 -1137
  679. package/src/hono/console/routes/context.ts +0 -956
  680. package/src/hono/console/routes/events.ts +0 -669
  681. package/src/hono/console/routes/maintenance.ts +0 -461
  682. package/src/hono/console/routes/shared.ts +0 -816
  683. package/src/hono/console/routes/stats.ts +0 -392
  684. package/src/hono/console/routes/storage.ts +0 -159
  685. package/src/hono/console/routes.ts +0 -146
  686. package/src/hono/console/schema-errors.ts +0 -23
  687. package/src/hono/console/schemas.ts +0 -914
  688. package/src/hono/console/types.ts +0 -223
  689. package/src/hono/console/ui.ts +0 -100
  690. package/src/hono/create-server.ts +0 -230
  691. package/src/hono/errors.ts +0 -50
  692. package/src/hono/index.ts +0 -54
  693. package/src/hono/openapi.ts +0 -139
  694. package/src/hono/proxy/connection-manager.ts +0 -340
  695. package/src/hono/proxy/index.ts +0 -8
  696. package/src/hono/proxy/routes.ts +0 -272
  697. package/src/hono/rate-limit.ts +0 -319
  698. package/src/hono/realtime-sync-packs.ts +0 -354
  699. package/src/hono/routes/audit.ts +0 -499
  700. package/src/hono/routes/auth-leases.ts +0 -119
  701. package/src/hono/routes/combined.ts +0 -583
  702. package/src/hono/routes/context.ts +0 -1629
  703. package/src/hono/routes/health.ts +0 -26
  704. package/src/hono/routes/realtime.ts +0 -808
  705. package/src/hono/routes/shared.ts +0 -1626
  706. package/src/hono/routes/snapshots.ts +0 -345
  707. package/src/hono/routes.ts +0 -68
  708. package/src/hono/validation.ts +0 -81
  709. package/src/hono/websocket-origin.ts +0 -131
  710. package/src/hono/ws.ts +0 -1134
  711. package/src/libsql.ts +0 -51
  712. package/src/migrate.ts +0 -20
  713. package/src/neon.ts +0 -28
  714. package/src/notify.ts +0 -341
  715. package/src/pglite.ts +0 -68
  716. package/src/plugins/index.ts +0 -1
  717. package/src/plugins/types.ts +0 -144
  718. package/src/postgres/index.ts +0 -1291
  719. package/src/proxy/collection.ts +0 -17
  720. package/src/proxy/handler.ts +0 -159
  721. package/src/proxy/index.ts +0 -21
  722. package/src/proxy/mutation-detector.ts +0 -281
  723. package/src/proxy/oplog.ts +0 -181
  724. package/src/proxy/types.ts +0 -46
  725. package/src/realtime/in-memory.ts +0 -33
  726. package/src/realtime/index.ts +0 -7
  727. package/src/realtime/types.ts +0 -90
  728. package/src/relay/bun-types.d.ts +0 -50
  729. package/src/relay/client-role/forward-engine.ts +0 -355
  730. package/src/relay/client-role/index.ts +0 -9
  731. package/src/relay/client-role/pull-engine.ts +0 -329
  732. package/src/relay/client-role/sequence-mapper.ts +0 -201
  733. package/src/relay/evaluation/relay-paths.ts +0 -699
  734. package/src/relay/evaluation/rust-boundary.ts +0 -464
  735. package/src/relay/index.ts +0 -50
  736. package/src/relay/migrate.ts +0 -113
  737. package/src/relay/mode-manager.ts +0 -142
  738. package/src/relay/realtime.ts +0 -207
  739. package/src/relay/relay.ts +0 -431
  740. package/src/relay/schema.ts +0 -171
  741. package/src/relay/server-role/index.ts +0 -338
  742. package/src/relay/server-role/pull.ts +0 -43
  743. package/src/relay/server-role/push.ts +0 -164
  744. package/src/s3/index.ts +0 -346
  745. package/src/service-worker/index.ts +0 -773
  746. package/src/snapshot-artifacts/sqlite-bun.ts +0 -168
  747. package/src/snapshot-artifacts.ts +0 -896
  748. package/src/snapshot-chunks/db-metadata.ts +0 -537
  749. package/src/snapshot-chunks/index.ts +0 -8
  750. package/src/snapshot-chunks/types.ts +0 -105
  751. package/src/snapshot-chunks.ts +0 -453
  752. package/src/sqlite/index.ts +0 -1064
  753. package/src/sqlite3.ts +0 -137
  754. package/src/stats.ts +0 -180
  755. package/src/subscriptions/cache.ts +0 -376
  756. package/src/subscriptions/index.ts +0 -2
  757. package/src/subscriptions/resolve.ts +0 -357
  758. package/src/sync.ts +0 -111
package/src/hono/ws.ts DELETED
@@ -1,1134 +0,0 @@
1
- /**
2
- * @syncular/server/hono - WebSocket helpers for realtime sync wake-ups
3
- *
4
- * WebSockets deliver binary sync-pack deltas or explicit pull-required wake-ups.
5
- * Also supports presence tracking for collaborative features.
6
- */
7
-
8
- import { RealtimeConnectionRegistry } from '@syncular/core';
9
- import type { WSContext } from 'hono/ws';
10
-
11
- /**
12
- * Presence entry for a client connected to a scope
13
- */
14
- export interface PresenceEntry {
15
- clientId: string;
16
- actorId: string;
17
- joinedAt: number;
18
- metadata?: Record<string, unknown>;
19
- }
20
-
21
- export function createWebSocketConnectionOwnerKey(args: {
22
- partitionId: string;
23
- actorId: string;
24
- clientId: string;
25
- }): string {
26
- return JSON.stringify([args.partitionId, args.actorId, args.clientId]);
27
- }
28
-
29
- /**
30
- * Push response data sent back to the client over WS
31
- */
32
- export interface WsPushResponseData {
33
- requestId: string;
34
- ok: boolean;
35
- status: string;
36
- commitSeq?: number;
37
- results: Array<{ opIndex: number; status: string; [k: string]: unknown }>;
38
- }
39
-
40
- export type WebSocketSyncPackEncoding = 'binary-sync-pack-v1';
41
-
42
- export interface WsHelloData {
43
- protocolVersion: 1;
44
- sessionId: string;
45
- shardKey: string;
46
- actorId: string;
47
- clientId: string;
48
- transportPath: 'direct' | 'relay';
49
- syncPackEncoding: WebSocketSyncPackEncoding | null;
50
- cursor: number;
51
- latestCursor: number;
52
- scopeCount: number;
53
- requiresSync: boolean;
54
- }
55
-
56
- export type WebSocketSyncReason =
57
- | 'payload-too-large'
58
- | 'reconnect-catchup'
59
- | 'resync-required'
60
- | 'server-wakeup';
61
-
62
- export const DEFAULT_WS_SYNC_PACK_MAX_BYTES = 64 * 1024;
63
-
64
- export interface WebSocketSyncMetadata {
65
- reason?: WebSocketSyncReason;
66
- requiresPull?: boolean;
67
- droppedCount?: number;
68
- payloadBytes?: number;
69
- }
70
-
71
- interface WebSocketReplayRecord {
72
- scopeKeys: string[];
73
- cursor: number;
74
- syncPack?: Uint8Array;
75
- payloadBytes?: number;
76
- syncPackForConnection?: (
77
- connection: WebSocketConnection
78
- ) => Uint8Array | undefined;
79
- hasSharedPayload: boolean;
80
- }
81
-
82
- export interface WebSocketRealtimeSubscription {
83
- id: string;
84
- table: string;
85
- scopes: Record<string, string | string[]>;
86
- scopeKeys: string[];
87
- cursor: number;
88
- verifiedRoot?: string | null;
89
- }
90
-
91
- /**
92
- * WebSocket event data for sync notifications
93
- */
94
- export interface SyncWebSocketEvent {
95
- /** Event type */
96
- event:
97
- | 'hello'
98
- | 'sync'
99
- | 'heartbeat'
100
- | 'error'
101
- | 'presence'
102
- | 'push-response';
103
- /** Data payload */
104
- data: {
105
- /** Realtime protocol version (for hello events) */
106
- protocolVersion?: number;
107
- /** Server-generated websocket session id (for hello events) */
108
- sessionId?: string;
109
- /** Stable sequencer/fanout shard key (for hello events) */
110
- shardKey?: string;
111
- /** New cursor position (for sync events) */
112
- cursor?: number;
113
- /** Latest server cursor known when the session was accepted */
114
- latestCursor?: number;
115
- /** Number of effective scope keys attached to this connection */
116
- scopeCount?: number;
117
- /** Whether the client should run catch-up sync */
118
- requiresSync?: boolean;
119
- /** Whether this notification intentionally requires HTTP pull recovery */
120
- requiresPull?: boolean;
121
- /** Number of realtime payload notifications skipped while waiting for ACK */
122
- droppedCount?: number;
123
- /** Why the server sent this sync notification */
124
- reason?: WebSocketSyncReason;
125
- /** Negotiated binary sync-pack encoding, if any */
126
- syncPackEncoding?: WebSocketSyncPackEncoding | null;
127
- /** Client/device id (for hello events) */
128
- clientId?: string;
129
- /** Transport path used by this connection */
130
- transportPath?: 'direct' | 'relay';
131
- /** Error message (for error events) */
132
- error?: string;
133
- /** Presence data (for presence events) */
134
- presence?: {
135
- action: 'join' | 'leave' | 'update' | 'snapshot';
136
- scopeKey: string;
137
- ownerKey?: string;
138
- clientId?: string;
139
- actorId?: string;
140
- metadata?: Record<string, unknown>;
141
- entries?: PresenceEntry[];
142
- };
143
- /** Push response data (for push-response events) */
144
- requestId?: string;
145
- ok?: boolean;
146
- status?: string;
147
- commitSeq?: number;
148
- results?: Array<{ opIndex: number; status: string; [k: string]: unknown }>;
149
- /** Timestamp */
150
- timestamp: number;
151
- };
152
- }
153
-
154
- /**
155
- * WebSocket connection controller for managing active connections
156
- */
157
- export interface WebSocketConnection {
158
- /** Send session/capability handshake metadata */
159
- sendHello(data: WsHelloData): void;
160
- /** Send a sync wake-up notification. */
161
- sendSync(cursor: number, metadata?: WebSocketSyncMetadata): void;
162
- /** Send an encoded binary sync-pack delta */
163
- sendSyncPack(bytes: Uint8Array): void;
164
- /** Send a heartbeat */
165
- sendHeartbeat(): void;
166
- /** Send a presence event */
167
- sendPresence(data: {
168
- action: 'join' | 'leave' | 'update' | 'snapshot';
169
- scopeKey: string;
170
- ownerKey?: string;
171
- clientId?: string;
172
- actorId?: string;
173
- metadata?: Record<string, unknown>;
174
- entries?: PresenceEntry[];
175
- }): void;
176
- /** Send a push response back to the client */
177
- sendPushResponse(data: WsPushResponseData): void;
178
- /** Send an error and close */
179
- sendError(message: string): void;
180
- /** Close the connection */
181
- close(code?: number, reason?: string): void;
182
- /** Whether the connection is still open */
183
- isOpen: boolean;
184
- /** Actor ID for this connection */
185
- actorId: string;
186
- /** Client/device identifier for this connection */
187
- clientId: string;
188
- /** Stable owner identity for this connection */
189
- ownerKey: string;
190
- /** Transport path used by this connection. */
191
- transportPath: 'direct' | 'relay';
192
- /** Optional binary sync-pack encoding negotiated by the client. */
193
- syncPackEncoding?: WebSocketSyncPackEncoding | null;
194
- }
195
-
196
- function safeSend(ws: WSContext, message: string | ArrayBuffer): boolean {
197
- try {
198
- ws.send(message);
199
- return true;
200
- } catch {
201
- return false;
202
- }
203
- }
204
-
205
- export function createRealtimeSessionId(): string {
206
- const randomUuid = globalThis.crypto?.randomUUID?.();
207
- if (randomUuid) return randomUuid;
208
- return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;
209
- }
210
-
211
- export function createWebSocketConnection(
212
- ws: WSContext,
213
- args: {
214
- actorId: string;
215
- clientId: string;
216
- ownerKey: string;
217
- transportPath: 'direct' | 'relay';
218
- syncPackEncoding?: WebSocketSyncPackEncoding | null;
219
- }
220
- ): WebSocketConnection {
221
- let closed = false;
222
-
223
- const connection: WebSocketConnection = {
224
- get isOpen() {
225
- if (closed) return false;
226
- return ws.readyState === 1;
227
- },
228
- actorId: args.actorId,
229
- clientId: args.clientId,
230
- ownerKey: args.ownerKey,
231
- transportPath: args.transportPath,
232
- syncPackEncoding: args.syncPackEncoding ?? null,
233
- sendHello(data: WsHelloData) {
234
- if (!connection.isOpen) return;
235
- const ok = safeSend(
236
- ws,
237
- JSON.stringify({
238
- event: 'hello',
239
- data: { ...data, timestamp: Date.now() },
240
- })
241
- );
242
- if (!ok) closed = true;
243
- },
244
- sendSync(cursor: number, metadata?: WebSocketSyncMetadata) {
245
- if (!connection.isOpen) return;
246
- const payload: Record<string, unknown> = {
247
- cursor,
248
- timestamp: Date.now(),
249
- };
250
- if (metadata?.reason) {
251
- payload.reason = metadata.reason;
252
- }
253
- if (metadata?.requiresPull) {
254
- payload.requiresPull = true;
255
- }
256
- if (metadata?.droppedCount !== undefined) {
257
- payload.droppedCount = metadata.droppedCount;
258
- }
259
- if (metadata?.payloadBytes !== undefined) {
260
- payload.payloadBytes = metadata.payloadBytes;
261
- }
262
- const ok = safeSend(ws, JSON.stringify({ event: 'sync', data: payload }));
263
- if (!ok) closed = true;
264
- },
265
- sendSyncPack(bytes: Uint8Array) {
266
- if (!connection.isOpen) return;
267
- const body = bytes.buffer.slice(
268
- bytes.byteOffset,
269
- bytes.byteOffset + bytes.byteLength
270
- ) as ArrayBuffer;
271
- const ok = safeSend(ws, body);
272
- if (!ok) closed = true;
273
- },
274
- sendHeartbeat() {
275
- if (!connection.isOpen) return;
276
- const ok = safeSend(
277
- ws,
278
- JSON.stringify({ event: 'heartbeat', data: { timestamp: Date.now() } })
279
- );
280
- if (!ok) closed = true;
281
- },
282
- sendPresence(data: {
283
- action: 'join' | 'leave' | 'update' | 'snapshot';
284
- scopeKey: string;
285
- ownerKey?: string;
286
- clientId?: string;
287
- actorId?: string;
288
- metadata?: Record<string, unknown>;
289
- entries?: PresenceEntry[];
290
- }) {
291
- if (!connection.isOpen) return;
292
- const ok = safeSend(
293
- ws,
294
- JSON.stringify({
295
- event: 'presence',
296
- data: { presence: data, timestamp: Date.now() },
297
- })
298
- );
299
- if (!ok) closed = true;
300
- },
301
- sendPushResponse(data: WsPushResponseData) {
302
- if (!connection.isOpen) return;
303
- const ok = safeSend(
304
- ws,
305
- JSON.stringify({
306
- event: 'push-response',
307
- data: { ...data, timestamp: Date.now() },
308
- })
309
- );
310
- if (!ok) closed = true;
311
- },
312
- sendError(message: string) {
313
- if (connection.isOpen) {
314
- safeSend(
315
- ws,
316
- JSON.stringify({
317
- event: 'error',
318
- data: { error: message, timestamp: Date.now() },
319
- })
320
- );
321
- }
322
- connection.close(1011, 'server error');
323
- },
324
- close(code?: number, reason?: string) {
325
- if (closed) return;
326
- closed = true;
327
- try {
328
- ws.close(code, reason);
329
- } catch {
330
- // ignore
331
- }
332
- },
333
- };
334
-
335
- return connection;
336
- }
337
-
338
- /**
339
- * Connection manager for tracking active WebSocket connections.
340
- * Scope-key based notifications and presence tracking.
341
- */
342
- export class WebSocketConnectionManager {
343
- private readonly registry: RealtimeConnectionRegistry<WebSocketConnection>;
344
- private readonly replayWindowSize: number;
345
- private readonly maxSyncPackBytes: number;
346
- private readonly replayRecords: WebSocketReplayRecord[] = [];
347
- private readonly subscriptionsByOwnerKey = new Map<
348
- string,
349
- WebSocketRealtimeSubscription[]
350
- >();
351
- private replayDroppedThroughCursor = -1;
352
- private readonly flowStateByConnection = new WeakMap<
353
- WebSocketConnection,
354
- {
355
- lastAckedCursor: number;
356
- lastSentCursor: number;
357
- inFlightCursors: number[];
358
- resyncRequired: boolean;
359
- droppedCount: number;
360
- }
361
- >();
362
- private readonly maxInFlightSyncsPerConnection: number;
363
-
364
- /**
365
- * In-memory presence tracking by scope key.
366
- * Map<scopeKey, Map<ownerKey, PresenceEntry>>
367
- */
368
- private presenceByScopeKey = new Map<string, Map<string, PresenceEntry>>();
369
-
370
- /**
371
- * Callback for presence changes - allows integration with SyncRealtimeBroadcaster
372
- */
373
- onPresenceChange?: (event: {
374
- action: 'join' | 'leave' | 'update';
375
- scopeKey: string;
376
- ownerKey: string;
377
- clientId: string;
378
- actorId: string;
379
- metadata?: Record<string, unknown>;
380
- }) => void;
381
-
382
- constructor(options?: {
383
- heartbeatIntervalMs?: number;
384
- maxInFlightSyncsPerConnection?: number;
385
- maxSyncPackBytes?: number;
386
- replayWindowSize?: number;
387
- onPresenceChange?: WebSocketConnectionManager['onPresenceChange'];
388
- }) {
389
- this.onPresenceChange = options?.onPresenceChange;
390
- this.maxInFlightSyncsPerConnection =
391
- options?.maxInFlightSyncsPerConnection ?? 64;
392
- this.maxSyncPackBytes = normalizeMaxSyncPackBytes(
393
- options?.maxSyncPackBytes
394
- );
395
- this.replayWindowSize = normalizeReplayWindowSize(
396
- options?.replayWindowSize
397
- );
398
- this.registry = new RealtimeConnectionRegistry({
399
- heartbeatIntervalMs: options?.heartbeatIntervalMs,
400
- onOwnerDisconnected: (ownerKey) => {
401
- this.cleanupOwnerPresence(ownerKey);
402
- },
403
- });
404
- }
405
-
406
- recordAck(connection: WebSocketConnection, cursor: number): void {
407
- if (!Number.isSafeInteger(cursor) || cursor < 0) return;
408
- const state = this.getFlowState(connection);
409
- if (cursor <= state.lastAckedCursor) return;
410
- state.lastAckedCursor = cursor;
411
- state.inFlightCursors = state.inFlightCursors.filter(
412
- (inFlightCursor) => inFlightCursor > cursor
413
- );
414
- if (cursor >= state.lastSentCursor) {
415
- state.inFlightCursors = [];
416
- state.resyncRequired = false;
417
- state.droppedCount = 0;
418
- }
419
- }
420
-
421
- /**
422
- * Register a connection for a client.
423
- * Returns a cleanup function to unregister.
424
- */
425
- register(
426
- connection: WebSocketConnection,
427
- initialScopeKeys: string[] = []
428
- ): () => void {
429
- return this.registry.register(connection, initialScopeKeys);
430
- }
431
-
432
- /**
433
- * Update the effective scopes for an already-connected client.
434
- * If the client has no active connections, this is a no-op.
435
- */
436
- updateConnectionScopeKeys(ownerKey: string, scopeKeys: string[]): void {
437
- this.registry.updateOwnerScopeKeys(ownerKey, scopeKeys);
438
- }
439
-
440
- /**
441
- * Update the active pull subscriptions for an owner. Realtime binary deltas
442
- * use these records to emit the same per-subscription integrity contract as
443
- * HTTP pull responses.
444
- */
445
- updateConnectionSubscriptions(
446
- ownerKey: string,
447
- subscriptions: WebSocketRealtimeSubscription[]
448
- ): void {
449
- if (subscriptions.length === 0) {
450
- this.subscriptionsByOwnerKey.delete(ownerKey);
451
- this.registry.updateOwnerScopeKeys(ownerKey, []);
452
- return;
453
- }
454
-
455
- this.subscriptionsByOwnerKey.set(
456
- ownerKey,
457
- subscriptions.map((subscription) => ({
458
- ...subscription,
459
- scopeKeys: [...subscription.scopeKeys],
460
- }))
461
- );
462
- this.registry.updateOwnerScopeKeys(
463
- ownerKey,
464
- uniqueScopeKeys(
465
- subscriptions.flatMap((subscription) => subscription.scopeKeys)
466
- )
467
- );
468
- }
469
-
470
- updateConnectionSubscriptionRoots(
471
- ownerKey: string,
472
- updates: Array<{
473
- subscriptionId: string;
474
- cursor: number;
475
- verifiedRoot: string;
476
- }>
477
- ): void {
478
- if (updates.length === 0) return;
479
- const subscriptions = this.subscriptionsByOwnerKey.get(ownerKey);
480
- if (!subscriptions || subscriptions.length === 0) return;
481
-
482
- const updatesBySubscription = new Map(
483
- updates.map((update) => [update.subscriptionId, update])
484
- );
485
- let changed = false;
486
- const next = subscriptions.map((subscription) => {
487
- const update = updatesBySubscription.get(subscription.id);
488
- if (!update) return subscription;
489
- changed = true;
490
- return {
491
- ...subscription,
492
- cursor: Math.max(subscription.cursor, update.cursor),
493
- verifiedRoot: update.verifiedRoot,
494
- };
495
- });
496
- if (changed) {
497
- this.subscriptionsByOwnerKey.set(ownerKey, next);
498
- }
499
- }
500
-
501
- getConnectionSubscriptions(
502
- ownerKey: string
503
- ): readonly WebSocketRealtimeSubscription[] {
504
- return this.subscriptionsByOwnerKey.get(ownerKey) ?? [];
505
- }
506
-
507
- getConnectionsForScopeKeys(
508
- scopeKeys: Iterable<string>,
509
- options?: { excludeClientIds?: readonly string[] }
510
- ): WebSocketConnection[] {
511
- const connections: WebSocketConnection[] = [];
512
- this.registry.forEachConnectionInScopeKeys(
513
- scopeKeys,
514
- (connection) => connections.push(connection),
515
- options
516
- );
517
- return connections;
518
- }
519
-
520
- /**
521
- * Check whether a client is currently authorized/subscribed for a scope key.
522
- */
523
- isConnectionSubscribedToScopeKey(
524
- ownerKey: string,
525
- scopeKey: string
526
- ): boolean {
527
- return this.registry.isOwnerSubscribedToScopeKey(ownerKey, scopeKey);
528
- }
529
-
530
- getConnectionScopeKeys(ownerKey: string): readonly string[] {
531
- return this.registry.getScopeKeysForOwner(ownerKey);
532
- }
533
-
534
- /**
535
- * Replay recent websocket delta notifications for a reconnecting client.
536
- * Returns false when the requested cursor range is no longer fully in memory,
537
- * so the caller can send an explicit pull-required recovery frame.
538
- */
539
- replayScopeKeys(
540
- connection: WebSocketConnection,
541
- scopeKeys: string[],
542
- fromCursor: number,
543
- latestCursor: number
544
- ): boolean {
545
- if (
546
- !Number.isSafeInteger(fromCursor) ||
547
- !Number.isSafeInteger(latestCursor)
548
- ) {
549
- return false;
550
- }
551
- if (latestCursor <= fromCursor) {
552
- return true;
553
- }
554
- if (scopeKeys.length === 0 || this.replayRecords.length === 0) {
555
- return false;
556
- }
557
- if (fromCursor < this.replayDroppedThroughCursor) {
558
- return false;
559
- }
560
-
561
- const scopeKeySet = new Set(scopeKeys);
562
- const records = this.replayRecords.filter(
563
- (record) =>
564
- record.cursor > fromCursor &&
565
- record.cursor <= latestCursor &&
566
- record.scopeKeys.some((scopeKey) => scopeKeySet.has(scopeKey))
567
- );
568
- if (records.length === 0) {
569
- return false;
570
- }
571
-
572
- const lastRecordCursor = records.reduce(
573
- (cursor, record) => Math.max(cursor, record.cursor),
574
- fromCursor
575
- );
576
- if (lastRecordCursor < latestCursor) {
577
- return false;
578
- }
579
-
580
- for (const record of records) {
581
- this.deliverSyncRecordToConnection(connection, record);
582
- }
583
- return true;
584
- }
585
-
586
- // =========================================================================
587
- // Presence Tracking
588
- // =========================================================================
589
-
590
- /**
591
- * Join presence for a scope key.
592
- * Called when a client wants to be visible to others in a scope.
593
- */
594
- joinPresence(
595
- ownerKey: string,
596
- scopeKey: string,
597
- metadata?: Record<string, unknown>
598
- ): boolean {
599
- const conns = this.registry.getConnectionsForOwner(ownerKey);
600
- if (!conns || conns.size === 0) return false;
601
- if (!this.isConnectionSubscribedToScopeKey(ownerKey, scopeKey))
602
- return false;
603
-
604
- const conn = conns.values().next().value;
605
- if (!conn) return false;
606
- const { actorId, clientId } = conn;
607
-
608
- let scopePresence = this.presenceByScopeKey.get(scopeKey);
609
- if (!scopePresence) {
610
- scopePresence = new Map();
611
- this.presenceByScopeKey.set(scopeKey, scopePresence);
612
- }
613
-
614
- const entry: PresenceEntry = {
615
- clientId,
616
- actorId,
617
- joinedAt: Date.now(),
618
- metadata,
619
- };
620
- scopePresence.set(ownerKey, entry);
621
-
622
- this.broadcastPresenceEvent(scopeKey, {
623
- action: 'join',
624
- scopeKey,
625
- ownerKey,
626
- clientId,
627
- actorId,
628
- metadata,
629
- });
630
-
631
- this.onPresenceChange?.({
632
- action: 'join',
633
- scopeKey,
634
- ownerKey,
635
- clientId,
636
- actorId,
637
- metadata,
638
- });
639
-
640
- return true;
641
- }
642
-
643
- /**
644
- * Leave presence for a scope key.
645
- * Called when a client no longer wants to be visible in a scope.
646
- */
647
- leavePresence(ownerKey: string, scopeKey: string): boolean {
648
- const scopePresence = this.presenceByScopeKey.get(scopeKey);
649
- if (!scopePresence) return false;
650
-
651
- const entry = scopePresence.get(ownerKey);
652
- if (!entry) return false;
653
-
654
- scopePresence.delete(ownerKey);
655
- if (scopePresence.size === 0) {
656
- this.presenceByScopeKey.delete(scopeKey);
657
- }
658
-
659
- this.broadcastPresenceEvent(scopeKey, {
660
- action: 'leave',
661
- scopeKey,
662
- ownerKey,
663
- clientId: entry.clientId,
664
- actorId: entry.actorId,
665
- });
666
-
667
- this.onPresenceChange?.({
668
- action: 'leave',
669
- scopeKey,
670
- ownerKey,
671
- clientId: entry.clientId,
672
- actorId: entry.actorId,
673
- });
674
-
675
- return true;
676
- }
677
-
678
- /**
679
- * Update presence metadata for a client in a scope.
680
- * Used to update what entity a user is viewing/editing.
681
- */
682
- updatePresenceMetadata(
683
- ownerKey: string,
684
- scopeKey: string,
685
- metadata: Record<string, unknown>
686
- ): boolean {
687
- if (!this.isConnectionSubscribedToScopeKey(ownerKey, scopeKey))
688
- return false;
689
- const scopePresence = this.presenceByScopeKey.get(scopeKey);
690
- if (!scopePresence) return false;
691
-
692
- const entry = scopePresence.get(ownerKey);
693
- if (!entry) return false;
694
-
695
- entry.metadata = metadata;
696
-
697
- this.broadcastPresenceEvent(scopeKey, {
698
- action: 'update',
699
- scopeKey,
700
- ownerKey,
701
- clientId: entry.clientId,
702
- actorId: entry.actorId,
703
- metadata,
704
- });
705
-
706
- this.onPresenceChange?.({
707
- action: 'update',
708
- scopeKey,
709
- ownerKey,
710
- clientId: entry.clientId,
711
- actorId: entry.actorId,
712
- metadata,
713
- });
714
-
715
- return true;
716
- }
717
-
718
- /**
719
- * Get presence entries for a scope key.
720
- */
721
- getPresence(scopeKey: string): PresenceEntry[] {
722
- const scopePresence = this.presenceByScopeKey.get(scopeKey);
723
- if (!scopePresence) return [];
724
- return Array.from(scopePresence.values());
725
- }
726
-
727
- /**
728
- * Get presence for multiple scopes.
729
- */
730
- getPresenceMultiple(scopeKeys: string[]): Record<string, PresenceEntry[]> {
731
- const result: Record<string, PresenceEntry[]> = {};
732
- for (const scopeKey of scopeKeys) {
733
- result[scopeKey] = this.getPresence(scopeKey);
734
- }
735
- return result;
736
- }
737
-
738
- /**
739
- * Send current presence snapshot to a specific connection.
740
- * Called when a client first subscribes to presence for a scope.
741
- */
742
- sendPresenceSnapshot(
743
- connection: WebSocketConnection,
744
- scopeKey: string
745
- ): void {
746
- const entries = this.getPresence(scopeKey);
747
- connection.sendPresence({
748
- action: 'snapshot',
749
- scopeKey,
750
- entries,
751
- });
752
- }
753
-
754
- /**
755
- * Handle a presence event from another server instance (via broadcaster).
756
- * Updates local state and notifies local clients.
757
- */
758
- handleRemotePresenceEvent(event: {
759
- action: 'join' | 'leave' | 'update';
760
- scopeKey: string;
761
- ownerKey?: string;
762
- clientId: string;
763
- actorId: string;
764
- metadata?: Record<string, unknown>;
765
- }): void {
766
- const {
767
- action,
768
- scopeKey,
769
- clientId,
770
- actorId,
771
- metadata,
772
- ownerKey = createWebSocketConnectionOwnerKey({
773
- partitionId: scopeKey.split(':', 1)[0] ?? 'default',
774
- actorId,
775
- clientId,
776
- }),
777
- } = event;
778
-
779
- let scopePresence = this.presenceByScopeKey.get(scopeKey);
780
-
781
- switch (action) {
782
- case 'join': {
783
- if (!scopePresence) {
784
- scopePresence = new Map();
785
- this.presenceByScopeKey.set(scopeKey, scopePresence);
786
- }
787
- scopePresence.set(ownerKey, {
788
- clientId,
789
- actorId,
790
- joinedAt: Date.now(),
791
- metadata,
792
- });
793
- break;
794
- }
795
- case 'leave': {
796
- if (scopePresence) {
797
- scopePresence.delete(ownerKey);
798
- if (scopePresence.size === 0) {
799
- this.presenceByScopeKey.delete(scopeKey);
800
- }
801
- }
802
- break;
803
- }
804
- case 'update': {
805
- if (scopePresence) {
806
- const entry = scopePresence.get(ownerKey);
807
- if (entry) {
808
- entry.metadata = metadata;
809
- }
810
- }
811
- break;
812
- }
813
- }
814
-
815
- // Notify local clients
816
- this.broadcastPresenceEvent(scopeKey, event);
817
- }
818
-
819
- /**
820
- * Broadcast a presence event to all clients subscribed to a scope key.
821
- */
822
- private broadcastPresenceEvent(
823
- scopeKey: string,
824
- event: {
825
- action: 'join' | 'leave' | 'update';
826
- scopeKey: string;
827
- ownerKey?: string;
828
- clientId?: string;
829
- actorId?: string;
830
- metadata?: Record<string, unknown>;
831
- }
832
- ): void {
833
- this.registry.forEachConnectionInScopeKeys(
834
- [scopeKey],
835
- (conn) => {
836
- conn.sendPresence(event);
837
- },
838
- {
839
- excludeClientIds: event.clientId ? [event.clientId] : undefined,
840
- }
841
- );
842
- }
843
-
844
- /**
845
- * Clean up presence when an owner fully disconnects (all connections closed).
846
- */
847
- private cleanupOwnerPresence(ownerKey: string): void {
848
- for (const [scopeKey, scopePresence] of this.presenceByScopeKey) {
849
- const entry = scopePresence.get(ownerKey);
850
- if (!entry) continue;
851
-
852
- scopePresence.delete(ownerKey);
853
- if (scopePresence.size === 0) {
854
- this.presenceByScopeKey.delete(scopeKey);
855
- }
856
-
857
- this.broadcastPresenceEvent(scopeKey, {
858
- action: 'leave',
859
- scopeKey,
860
- ownerKey,
861
- clientId: entry.clientId,
862
- actorId: entry.actorId,
863
- });
864
-
865
- this.onPresenceChange?.({
866
- action: 'leave',
867
- scopeKey,
868
- ownerKey,
869
- clientId: entry.clientId,
870
- actorId: entry.actorId,
871
- });
872
- }
873
- }
874
-
875
- // =========================================================================
876
- // Sync Notifications
877
- // =========================================================================
878
-
879
- /**
880
- * Notify clients that new data is available for the given scopes.
881
- * Dedupes connections that match multiple scopes.
882
- */
883
- notifyScopeKeys(
884
- scopeKeys: string[],
885
- cursor: number,
886
- opts?: {
887
- excludeClientIds?: string[];
888
- syncPack?: Uint8Array;
889
- syncPackForConnection?: (
890
- connection: WebSocketConnection
891
- ) => Uint8Array | undefined;
892
- }
893
- ): void {
894
- const websocketSyncPack =
895
- opts?.syncPack && opts.syncPack.byteLength <= this.maxSyncPackBytes
896
- ? opts.syncPack
897
- : undefined;
898
- const replayRecord: WebSocketReplayRecord = {
899
- scopeKeys: [...scopeKeys],
900
- cursor,
901
- syncPack: websocketSyncPack,
902
- payloadBytes: opts?.syncPack?.byteLength,
903
- syncPackForConnection: opts?.syncPackForConnection,
904
- hasSharedPayload:
905
- opts?.syncPack !== undefined ||
906
- opts?.syncPackForConnection !== undefined,
907
- };
908
- this.rememberReplayRecord(replayRecord);
909
-
910
- this.registry.forEachConnectionInScopeKeys(
911
- scopeKeys,
912
- (conn) => {
913
- this.deliverSyncRecordToConnection(conn, replayRecord);
914
- },
915
- { excludeClientIds: opts?.excludeClientIds }
916
- );
917
- }
918
-
919
- /**
920
- * Notify all connected clients of a new cursor position.
921
- * Used for external data changes that affect all clients regardless of scope.
922
- */
923
- notifyAllClients(cursor: number): void {
924
- this.registry.forEachConnection((conn) => {
925
- if (this.shouldSendResyncRequired(conn, cursor)) {
926
- this.sendResyncRequired(conn, cursor);
927
- return;
928
- }
929
- this.markSyncSent(conn, cursor);
930
- conn.sendSync(cursor, {
931
- reason: 'server-wakeup',
932
- requiresPull: true,
933
- });
934
- });
935
- }
936
-
937
- /**
938
- * Get the number of active connections for a client.
939
- */
940
- getConnectionCount(clientId: string): number {
941
- return this.registry.getConnectionCount(clientId);
942
- }
943
-
944
- /**
945
- * Get the number of active connections for one owner identity.
946
- */
947
- getScopedConnectionCount(ownerKey: string): number {
948
- return this.registry.getScopedConnectionCount(ownerKey);
949
- }
950
-
951
- /**
952
- * Get the current transport path for a client if connected.
953
- */
954
- getClientTransportPath(clientId: string): 'direct' | 'relay' | null {
955
- const conns = this.registry.getConnectionsForClient(clientId);
956
- if (!conns || conns.size === 0) {
957
- return null;
958
- }
959
-
960
- for (const conn of conns) {
961
- if (conn.transportPath === 'relay') {
962
- return 'relay';
963
- }
964
- }
965
-
966
- return 'direct';
967
- }
968
-
969
- /**
970
- * Get total number of active connections.
971
- */
972
- getTotalConnections(): number {
973
- return this.registry.getTotalConnections();
974
- }
975
-
976
- /**
977
- * Close all connections for a client.
978
- */
979
- closeClientConnections(clientId: string): void {
980
- this.registry.closeClientConnections(clientId, 1000, 'client closed');
981
- }
982
-
983
- /**
984
- * Close all connections.
985
- */
986
- closeAll(): void {
987
- this.registry.closeAll(1000, 'server shutdown');
988
- this.presenceByScopeKey.clear();
989
- }
990
-
991
- private getFlowState(connection: WebSocketConnection): {
992
- lastAckedCursor: number;
993
- lastSentCursor: number;
994
- inFlightCursors: number[];
995
- resyncRequired: boolean;
996
- droppedCount: number;
997
- } {
998
- let state = this.flowStateByConnection.get(connection);
999
- if (!state) {
1000
- state = {
1001
- lastAckedCursor: -1,
1002
- lastSentCursor: -1,
1003
- inFlightCursors: [],
1004
- resyncRequired: false,
1005
- droppedCount: 0,
1006
- };
1007
- this.flowStateByConnection.set(connection, state);
1008
- }
1009
- return state;
1010
- }
1011
-
1012
- private shouldSendResyncRequired(
1013
- connection: WebSocketConnection,
1014
- cursor: number
1015
- ): boolean {
1016
- if (
1017
- this.maxInFlightSyncsPerConnection <= 0 ||
1018
- !Number.isSafeInteger(cursor) ||
1019
- cursor < 0
1020
- ) {
1021
- return false;
1022
- }
1023
- const state = this.getFlowState(connection);
1024
- if (cursor <= state.lastAckedCursor) return false;
1025
- return (
1026
- state.resyncRequired ||
1027
- state.inFlightCursors.length >= this.maxInFlightSyncsPerConnection
1028
- );
1029
- }
1030
-
1031
- private markSyncSent(connection: WebSocketConnection, cursor: number): void {
1032
- if (
1033
- this.maxInFlightSyncsPerConnection <= 0 ||
1034
- !Number.isSafeInteger(cursor) ||
1035
- cursor < 0
1036
- ) {
1037
- return;
1038
- }
1039
- const state = this.getFlowState(connection);
1040
- if (cursor <= state.lastAckedCursor) return;
1041
- state.lastSentCursor = Math.max(state.lastSentCursor, cursor);
1042
- if (!state.inFlightCursors.includes(cursor)) {
1043
- state.inFlightCursors.push(cursor);
1044
- }
1045
- }
1046
-
1047
- private sendResyncRequired(
1048
- connection: WebSocketConnection,
1049
- cursor: number
1050
- ): void {
1051
- const state = this.getFlowState(connection);
1052
- state.resyncRequired = true;
1053
- state.lastSentCursor = Math.max(state.lastSentCursor, cursor);
1054
- state.droppedCount += 1;
1055
- connection.sendSync(cursor, {
1056
- reason: 'resync-required',
1057
- requiresPull: true,
1058
- droppedCount: state.droppedCount,
1059
- });
1060
- }
1061
-
1062
- private rememberReplayRecord(record: WebSocketReplayRecord): void {
1063
- if (
1064
- this.replayWindowSize <= 0 ||
1065
- record.scopeKeys.length === 0 ||
1066
- !Number.isSafeInteger(record.cursor) ||
1067
- record.cursor < 0
1068
- ) {
1069
- return;
1070
- }
1071
- this.replayRecords.push(record);
1072
- while (this.replayRecords.length > this.replayWindowSize) {
1073
- const dropped = this.replayRecords.shift();
1074
- if (dropped) {
1075
- this.replayDroppedThroughCursor = Math.max(
1076
- this.replayDroppedThroughCursor,
1077
- dropped.cursor
1078
- );
1079
- }
1080
- }
1081
- }
1082
-
1083
- private deliverSyncRecordToConnection(
1084
- connection: WebSocketConnection,
1085
- record: WebSocketReplayRecord
1086
- ): void {
1087
- if (this.shouldSendResyncRequired(connection, record.cursor)) {
1088
- this.sendResyncRequired(connection, record.cursor);
1089
- return;
1090
- }
1091
-
1092
- const connectionSyncPack =
1093
- record.syncPackForConnection?.(connection) ?? record.syncPack;
1094
- if (
1095
- connectionSyncPack &&
1096
- connectionSyncPack.byteLength <= this.maxSyncPackBytes &&
1097
- connection.syncPackEncoding === 'binary-sync-pack-v1'
1098
- ) {
1099
- this.markSyncSent(connection, record.cursor);
1100
- connection.sendSyncPack(connectionSyncPack);
1101
- return;
1102
- }
1103
-
1104
- this.markSyncSent(connection, record.cursor);
1105
- connection.sendSync(record.cursor, {
1106
- reason:
1107
- connectionSyncPack || record.payloadBytes !== undefined
1108
- ? 'payload-too-large'
1109
- : 'server-wakeup',
1110
- requiresPull: true,
1111
- payloadBytes: connectionSyncPack?.byteLength ?? record.payloadBytes,
1112
- });
1113
- }
1114
- }
1115
-
1116
- function normalizeMaxSyncPackBytes(value: number | undefined): number {
1117
- if (value === undefined) return DEFAULT_WS_SYNC_PACK_MAX_BYTES;
1118
- if (!Number.isFinite(value)) return DEFAULT_WS_SYNC_PACK_MAX_BYTES;
1119
- return Math.max(0, Math.floor(value));
1120
- }
1121
-
1122
- function normalizeReplayWindowSize(value: number | undefined): number {
1123
- if (value === undefined) return 64;
1124
- if (!Number.isFinite(value)) return 64;
1125
- return Math.max(0, Math.floor(value));
1126
- }
1127
-
1128
- function uniqueScopeKeys(scopeKeys: Iterable<string>): string[] {
1129
- const unique = new Set<string>();
1130
- for (const scopeKey of scopeKeys) {
1131
- if (scopeKey) unique.add(scopeKey);
1132
- }
1133
- return Array.from(unique);
1134
- }