@syncular/server 0.0.6-95 → 0.1.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 (601) hide show
  1. package/README.md +1 -2
  2. package/dist/auth-leases.d.ts +85 -0
  3. package/dist/auth-leases.d.ts.map +1 -0
  4. package/dist/auth-leases.js +368 -0
  5. package/dist/auth-leases.js.map +1 -0
  6. package/dist/better-sqlite3.d.ts +22 -0
  7. package/dist/better-sqlite3.d.ts.map +1 -0
  8. package/dist/better-sqlite3.js +16 -0
  9. package/dist/better-sqlite3.js.map +1 -0
  10. package/dist/blobs/access.d.ts +35 -0
  11. package/dist/blobs/access.d.ts.map +1 -0
  12. package/dist/blobs/access.js +149 -0
  13. package/dist/blobs/access.js.map +1 -0
  14. package/dist/blobs/adapters/database.d.ts +26 -9
  15. package/dist/blobs/adapters/database.d.ts.map +1 -1
  16. package/dist/blobs/adapters/database.js +68 -23
  17. package/dist/blobs/adapters/database.js.map +1 -1
  18. package/dist/blobs/index.d.ts +1 -0
  19. package/dist/blobs/index.d.ts.map +1 -1
  20. package/dist/blobs/index.js +5 -4
  21. package/dist/blobs/index.js.map +1 -1
  22. package/dist/blobs/manager.d.ts +69 -44
  23. package/dist/blobs/manager.d.ts.map +1 -1
  24. package/dist/blobs/manager.js +250 -65
  25. package/dist/blobs/manager.js.map +1 -1
  26. package/dist/blobs/migrate.d.ts.map +1 -1
  27. package/dist/blobs/migrate.js +16 -8
  28. package/dist/blobs/migrate.js.map +1 -1
  29. package/dist/blobs/types.d.ts +4 -0
  30. package/dist/blobs/types.d.ts.map +1 -1
  31. package/dist/bun-sqlite.d.ts +19 -0
  32. package/dist/bun-sqlite.d.ts.map +1 -0
  33. package/dist/bun-sqlite.js +19 -0
  34. package/dist/bun-sqlite.js.map +1 -0
  35. package/dist/clients.d.ts +1 -0
  36. package/dist/clients.d.ts.map +1 -1
  37. package/dist/clients.js.map +1 -1
  38. package/dist/cloudflare/durable-object.d.ts +93 -0
  39. package/dist/cloudflare/durable-object.d.ts.map +1 -0
  40. package/dist/cloudflare/durable-object.js +210 -0
  41. package/dist/cloudflare/durable-object.js.map +1 -0
  42. package/dist/cloudflare/index.d.ts +22 -0
  43. package/dist/cloudflare/index.d.ts.map +1 -0
  44. package/dist/cloudflare/index.js +22 -0
  45. package/dist/cloudflare/index.js.map +1 -0
  46. package/dist/cloudflare/r2.d.ts +180 -0
  47. package/dist/cloudflare/r2.d.ts.map +1 -0
  48. package/dist/cloudflare/r2.js +258 -0
  49. package/dist/cloudflare/r2.js.map +1 -0
  50. package/dist/cloudflare/scope-cache.d.ts +54 -0
  51. package/dist/cloudflare/scope-cache.d.ts.map +1 -0
  52. package/dist/cloudflare/scope-cache.js +223 -0
  53. package/dist/cloudflare/scope-cache.js.map +1 -0
  54. package/dist/cloudflare/sentry.d.ts +47 -0
  55. package/dist/cloudflare/sentry.d.ts.map +1 -0
  56. package/dist/cloudflare/sentry.js +163 -0
  57. package/dist/cloudflare/sentry.js.map +1 -0
  58. package/dist/cloudflare/worker.d.ts +46 -0
  59. package/dist/cloudflare/worker.d.ts.map +1 -0
  60. package/dist/cloudflare/worker.js +63 -0
  61. package/dist/cloudflare/worker.js.map +1 -0
  62. package/dist/commit-integrity.d.ts +38 -0
  63. package/dist/commit-integrity.d.ts.map +1 -0
  64. package/dist/commit-integrity.js +260 -0
  65. package/dist/commit-integrity.js.map +1 -0
  66. package/dist/compaction.js.map +1 -1
  67. package/dist/crdt-yjs/index.d.ts +99 -0
  68. package/dist/crdt-yjs/index.d.ts.map +1 -0
  69. package/dist/crdt-yjs/index.js +629 -0
  70. package/dist/crdt-yjs/index.js.map +1 -0
  71. package/dist/d1.d.ts +13 -0
  72. package/dist/d1.d.ts.map +1 -0
  73. package/dist/d1.js +14 -0
  74. package/dist/d1.js.map +1 -0
  75. package/dist/dialect/base.d.ts +11 -1
  76. package/dist/dialect/base.d.ts.map +1 -1
  77. package/dist/dialect/base.js +43 -6
  78. package/dist/dialect/base.js.map +1 -1
  79. package/dist/dialect/helpers.d.ts +6 -0
  80. package/dist/dialect/helpers.d.ts.map +1 -1
  81. package/dist/dialect/helpers.js +24 -0
  82. package/dist/dialect/helpers.js.map +1 -1
  83. package/dist/dialect/index.js +3 -3
  84. package/dist/dialect/types.d.ts +40 -0
  85. package/dist/dialect/types.d.ts.map +1 -1
  86. package/dist/encrypted-crdt.d.ts +67 -0
  87. package/dist/encrypted-crdt.d.ts.map +1 -0
  88. package/dist/encrypted-crdt.js +426 -0
  89. package/dist/encrypted-crdt.js.map +1 -0
  90. package/dist/errors.d.ts +10 -0
  91. package/dist/errors.d.ts.map +1 -0
  92. package/dist/errors.js +13 -0
  93. package/dist/errors.js.map +1 -0
  94. package/dist/filesystem/index.d.ts +44 -0
  95. package/dist/filesystem/index.d.ts.map +1 -0
  96. package/dist/filesystem/index.js +164 -0
  97. package/dist/filesystem/index.js.map +1 -0
  98. package/dist/handlers/collection.d.ts +11 -3
  99. package/dist/handlers/collection.d.ts.map +1 -1
  100. package/dist/handlers/collection.js +34 -56
  101. package/dist/handlers/collection.js.map +1 -1
  102. package/dist/handlers/create-handler.d.ts +31 -7
  103. package/dist/handlers/create-handler.d.ts.map +1 -1
  104. package/dist/handlers/create-handler.js +332 -115
  105. package/dist/handlers/create-handler.js.map +1 -1
  106. package/dist/handlers/index.js +3 -3
  107. package/dist/handlers/types.d.ts +86 -1
  108. package/dist/handlers/types.d.ts.map +1 -1
  109. package/dist/helpers/conflict.js.map +1 -1
  110. package/dist/helpers/emitted-change.js.map +1 -1
  111. package/dist/helpers/index.d.ts +2 -0
  112. package/dist/helpers/index.d.ts.map +1 -1
  113. package/dist/helpers/index.js +6 -4
  114. package/dist/helpers/index.js.map +1 -1
  115. package/dist/helpers/paginate.js.map +1 -1
  116. package/dist/helpers/scope-authorization.d.ts +7 -0
  117. package/dist/helpers/scope-authorization.d.ts.map +1 -0
  118. package/dist/helpers/scope-authorization.js +19 -0
  119. package/dist/helpers/scope-authorization.js.map +1 -0
  120. package/dist/helpers/scope-commit-index.d.ts +12 -0
  121. package/dist/helpers/scope-commit-index.d.ts.map +1 -0
  122. package/dist/helpers/scope-commit-index.js +35 -0
  123. package/dist/helpers/scope-commit-index.js.map +1 -0
  124. package/dist/helpers/scope-strings.js.map +1 -1
  125. package/dist/hono/api-key-auth.d.ts +49 -0
  126. package/dist/hono/api-key-auth.d.ts.map +1 -0
  127. package/dist/hono/api-key-auth.js +108 -0
  128. package/dist/hono/api-key-auth.js.map +1 -0
  129. package/dist/hono/audit-redaction.d.ts +20 -0
  130. package/dist/hono/audit-redaction.d.ts.map +1 -0
  131. package/dist/hono/audit-redaction.js +85 -0
  132. package/dist/hono/audit-redaction.js.map +1 -0
  133. package/dist/hono/blobs.d.ts +75 -0
  134. package/dist/hono/blobs.d.ts.map +1 -0
  135. package/dist/hono/blobs.js +586 -0
  136. package/dist/hono/blobs.js.map +1 -0
  137. package/dist/hono/console/gateway.d.ts +42 -0
  138. package/dist/hono/console/gateway.d.ts.map +1 -0
  139. package/dist/hono/console/gateway.js +2158 -0
  140. package/dist/hono/console/gateway.js.map +1 -0
  141. package/dist/hono/console/live-auth.d.ts +7 -0
  142. package/dist/hono/console/live-auth.d.ts.map +1 -0
  143. package/dist/hono/console/live-auth.js +39 -0
  144. package/dist/hono/console/live-auth.js.map +1 -0
  145. package/dist/hono/console/route-descriptor.d.ts +6 -0
  146. package/dist/hono/console/route-descriptor.d.ts.map +1 -0
  147. package/dist/hono/console/route-descriptor.js +16 -0
  148. package/dist/hono/console/route-descriptor.js.map +1 -0
  149. package/dist/hono/console/routes/api-keys.d.ts +8 -0
  150. package/dist/hono/console/routes/api-keys.d.ts.map +1 -0
  151. package/dist/hono/console/routes/api-keys.js +575 -0
  152. package/dist/hono/console/routes/api-keys.js.map +1 -0
  153. package/dist/hono/console/routes/clients.d.ts +8 -0
  154. package/dist/hono/console/routes/clients.d.ts.map +1 -0
  155. package/dist/hono/console/routes/clients.js +322 -0
  156. package/dist/hono/console/routes/clients.js.map +1 -0
  157. package/dist/hono/console/routes/commits.d.ts +8 -0
  158. package/dist/hono/console/routes/commits.d.ts.map +1 -0
  159. package/dist/hono/console/routes/commits.js +882 -0
  160. package/dist/hono/console/routes/commits.js.map +1 -0
  161. package/dist/hono/console/routes/context.d.ts +188 -0
  162. package/dist/hono/console/routes/context.d.ts.map +1 -0
  163. package/dist/hono/console/routes/context.js +633 -0
  164. package/dist/hono/console/routes/context.js.map +1 -0
  165. package/dist/hono/console/routes/events.d.ts +8 -0
  166. package/dist/hono/console/routes/events.d.ts.map +1 -0
  167. package/dist/hono/console/routes/events.js +501 -0
  168. package/dist/hono/console/routes/events.js.map +1 -0
  169. package/dist/hono/console/routes/maintenance.d.ts +8 -0
  170. package/dist/hono/console/routes/maintenance.d.ts.map +1 -0
  171. package/dist/hono/console/routes/maintenance.js +341 -0
  172. package/dist/hono/console/routes/maintenance.js.map +1 -0
  173. package/dist/hono/console/routes/shared.d.ts +174 -0
  174. package/dist/hono/console/routes/shared.d.ts.map +1 -0
  175. package/dist/hono/console/routes/shared.js +583 -0
  176. package/dist/hono/console/routes/shared.js.map +1 -0
  177. package/dist/hono/console/routes/stats.d.ts +8 -0
  178. package/dist/hono/console/routes/stats.d.ts.map +1 -0
  179. package/dist/hono/console/routes/stats.js +295 -0
  180. package/dist/hono/console/routes/stats.js.map +1 -0
  181. package/dist/hono/console/routes/storage.d.ts +8 -0
  182. package/dist/hono/console/routes/storage.d.ts.map +1 -0
  183. package/dist/hono/console/routes/storage.js +121 -0
  184. package/dist/hono/console/routes/storage.js.map +1 -0
  185. package/dist/hono/console/routes.d.ts +36 -0
  186. package/dist/hono/console/routes.d.ts.map +1 -0
  187. package/dist/hono/console/routes.js +112 -0
  188. package/dist/hono/console/routes.js.map +1 -0
  189. package/dist/hono/console/schema-errors.d.ts +2 -0
  190. package/dist/hono/console/schema-errors.d.ts.map +1 -0
  191. package/dist/hono/console/schema-errors.js +17 -0
  192. package/dist/hono/console/schema-errors.js.map +1 -0
  193. package/dist/hono/console/schemas.d.ts +1515 -0
  194. package/dist/hono/console/schemas.d.ts.map +1 -0
  195. package/dist/hono/console/schemas.js +661 -0
  196. package/dist/hono/console/schemas.js.map +1 -0
  197. package/dist/hono/console/types.d.ts +213 -0
  198. package/dist/hono/console/types.d.ts.map +1 -0
  199. package/dist/hono/console/types.js +2 -0
  200. package/dist/hono/console/types.js.map +1 -0
  201. package/dist/hono/console/ui.d.ts +38 -0
  202. package/dist/hono/console/ui.d.ts.map +1 -0
  203. package/dist/hono/console/ui.js +43 -0
  204. package/dist/hono/console/ui.js.map +1 -0
  205. package/dist/hono/create-server.d.ts +71 -0
  206. package/dist/hono/create-server.d.ts.map +1 -0
  207. package/dist/hono/create-server.js +121 -0
  208. package/dist/hono/create-server.js.map +1 -0
  209. package/dist/hono/errors.d.ts +13 -0
  210. package/dist/hono/errors.d.ts.map +1 -0
  211. package/dist/hono/errors.js +21 -0
  212. package/dist/hono/errors.js.map +1 -0
  213. package/dist/hono/index.d.ts +20 -0
  214. package/dist/hono/index.d.ts.map +1 -0
  215. package/dist/hono/index.js +31 -0
  216. package/dist/hono/index.js.map +1 -0
  217. package/dist/hono/openapi.d.ts +72 -0
  218. package/dist/hono/openapi.d.ts.map +1 -0
  219. package/dist/hono/openapi.js +99 -0
  220. package/dist/hono/openapi.js.map +1 -0
  221. package/dist/hono/proxy/connection-manager.d.ts +78 -0
  222. package/dist/hono/proxy/connection-manager.d.ts.map +1 -0
  223. package/dist/hono/proxy/connection-manager.js +251 -0
  224. package/dist/hono/proxy/connection-manager.js.map +1 -0
  225. package/dist/hono/proxy/index.d.ts +8 -0
  226. package/dist/hono/proxy/index.d.ts.map +1 -0
  227. package/dist/hono/proxy/index.js +8 -0
  228. package/dist/hono/proxy/index.js.map +1 -0
  229. package/dist/hono/proxy/routes.d.ts +86 -0
  230. package/dist/hono/proxy/routes.d.ts.map +1 -0
  231. package/dist/hono/proxy/routes.js +183 -0
  232. package/dist/hono/proxy/routes.js.map +1 -0
  233. package/dist/hono/rate-limit.d.ts +101 -0
  234. package/dist/hono/rate-limit.d.ts.map +1 -0
  235. package/dist/hono/rate-limit.js +184 -0
  236. package/dist/hono/rate-limit.js.map +1 -0
  237. package/dist/hono/realtime-sync-packs.d.ts +43 -0
  238. package/dist/hono/realtime-sync-packs.d.ts.map +1 -0
  239. package/dist/hono/realtime-sync-packs.js +219 -0
  240. package/dist/hono/realtime-sync-packs.js.map +1 -0
  241. package/dist/hono/routes/audit.d.ts +12 -0
  242. package/dist/hono/routes/audit.d.ts.map +1 -0
  243. package/dist/hono/routes/audit.js +385 -0
  244. package/dist/hono/routes/audit.js.map +1 -0
  245. package/dist/hono/routes/auth-leases.d.ts +8 -0
  246. package/dist/hono/routes/auth-leases.d.ts.map +1 -0
  247. package/dist/hono/routes/auth-leases.js +88 -0
  248. package/dist/hono/routes/auth-leases.js.map +1 -0
  249. package/dist/hono/routes/combined.d.ts +8 -0
  250. package/dist/hono/routes/combined.d.ts.map +1 -0
  251. package/dist/hono/routes/combined.js +392 -0
  252. package/dist/hono/routes/combined.js.map +1 -0
  253. package/dist/hono/routes/context.d.ts +314 -0
  254. package/dist/hono/routes/context.d.ts.map +1 -0
  255. package/dist/hono/routes/context.js +1147 -0
  256. package/dist/hono/routes/context.js.map +1 -0
  257. package/dist/hono/routes/health.d.ts +8 -0
  258. package/dist/hono/routes/health.d.ts.map +1 -0
  259. package/dist/hono/routes/health.js +16 -0
  260. package/dist/hono/routes/health.js.map +1 -0
  261. package/dist/hono/routes/realtime.d.ts +9 -0
  262. package/dist/hono/routes/realtime.d.ts.map +1 -0
  263. package/dist/hono/routes/realtime.js +626 -0
  264. package/dist/hono/routes/realtime.js.map +1 -0
  265. package/dist/hono/routes/shared.d.ts +689 -0
  266. package/dist/hono/routes/shared.d.ts.map +1 -0
  267. package/dist/hono/routes/shared.js +972 -0
  268. package/dist/hono/routes/shared.js.map +1 -0
  269. package/dist/hono/routes/snapshots.d.ts +10 -0
  270. package/dist/hono/routes/snapshots.d.ts.map +1 -0
  271. package/dist/hono/routes/snapshots.js +281 -0
  272. package/dist/hono/routes/snapshots.js.map +1 -0
  273. package/dist/hono/routes.d.ts +19 -0
  274. package/dist/hono/routes.d.ts.map +1 -0
  275. package/dist/hono/routes.js +37 -0
  276. package/dist/hono/routes.js.map +1 -0
  277. package/dist/hono/validation.d.ts +5 -0
  278. package/dist/hono/validation.d.ts.map +1 -0
  279. package/dist/hono/validation.js +47 -0
  280. package/dist/hono/validation.js.map +1 -0
  281. package/dist/hono/websocket-origin.d.ts +9 -0
  282. package/dist/hono/websocket-origin.d.ts.map +1 -0
  283. package/dist/hono/websocket-origin.js +96 -0
  284. package/dist/hono/websocket-origin.js.map +1 -0
  285. package/dist/hono/ws.d.ts +341 -0
  286. package/dist/hono/ws.d.ts.map +1 -0
  287. package/dist/hono/ws.js +711 -0
  288. package/dist/hono/ws.js.map +1 -0
  289. package/dist/index.d.ts +6 -0
  290. package/dist/index.d.ts.map +1 -1
  291. package/dist/index.js +24 -18
  292. package/dist/index.js.map +1 -1
  293. package/dist/libsql.d.ts +29 -0
  294. package/dist/libsql.d.ts.map +1 -0
  295. package/dist/libsql.js +25 -0
  296. package/dist/libsql.js.map +1 -0
  297. package/dist/migrate.js.map +1 -1
  298. package/dist/neon.d.ts +21 -0
  299. package/dist/neon.d.ts.map +1 -0
  300. package/dist/neon.js +22 -0
  301. package/dist/neon.js.map +1 -0
  302. package/dist/notify.d.ts +30 -0
  303. package/dist/notify.d.ts.map +1 -1
  304. package/dist/notify.js +160 -41
  305. package/dist/notify.js.map +1 -1
  306. package/dist/pglite.d.ts +37 -0
  307. package/dist/pglite.d.ts.map +1 -0
  308. package/dist/pglite.js +37 -0
  309. package/dist/pglite.js.map +1 -0
  310. package/dist/plugins/index.d.ts +2 -0
  311. package/dist/plugins/index.d.ts.map +1 -0
  312. package/dist/plugins/index.js +2 -0
  313. package/dist/plugins/index.js.map +1 -0
  314. package/dist/plugins/types.d.ts +73 -0
  315. package/dist/plugins/types.d.ts.map +1 -0
  316. package/dist/plugins/types.js +30 -0
  317. package/dist/plugins/types.js.map +1 -0
  318. package/dist/postgres/index.d.ts +68 -0
  319. package/dist/postgres/index.d.ts.map +1 -0
  320. package/dist/postgres/index.js +924 -0
  321. package/dist/postgres/index.js.map +1 -0
  322. package/dist/proxy/collection.d.ts +0 -2
  323. package/dist/proxy/collection.d.ts.map +1 -1
  324. package/dist/proxy/collection.js +2 -17
  325. package/dist/proxy/collection.js.map +1 -1
  326. package/dist/proxy/handler.d.ts +1 -1
  327. package/dist/proxy/handler.d.ts.map +1 -1
  328. package/dist/proxy/handler.js +3 -4
  329. package/dist/proxy/handler.js.map +1 -1
  330. package/dist/proxy/index.d.ts +1 -1
  331. package/dist/proxy/index.d.ts.map +1 -1
  332. package/dist/proxy/index.js +3 -3
  333. package/dist/proxy/index.js.map +1 -1
  334. package/dist/proxy/mutation-detector.js.map +1 -1
  335. package/dist/proxy/oplog.d.ts.map +1 -1
  336. package/dist/proxy/oplog.js +32 -8
  337. package/dist/proxy/oplog.js.map +1 -1
  338. package/dist/prune.d.ts +8 -1
  339. package/dist/prune.d.ts.map +1 -1
  340. package/dist/prune.js +68 -28
  341. package/dist/prune.js.map +1 -1
  342. package/dist/pull.d.ts +31 -0
  343. package/dist/pull.d.ts.map +1 -1
  344. package/dist/pull.js +1014 -474
  345. package/dist/pull.js.map +1 -1
  346. package/dist/push.d.ts +36 -2
  347. package/dist/push.d.ts.map +1 -1
  348. package/dist/push.js +603 -358
  349. package/dist/push.js.map +1 -1
  350. package/dist/realtime/in-memory.js.map +1 -1
  351. package/dist/realtime/index.d.ts +2 -1
  352. package/dist/realtime/index.d.ts.map +1 -1
  353. package/dist/realtime/index.js +2 -1
  354. package/dist/realtime/index.js.map +1 -1
  355. package/dist/realtime/types.d.ts +12 -0
  356. package/dist/realtime/types.d.ts.map +1 -1
  357. package/dist/realtime/types.js +13 -1
  358. package/dist/realtime/types.js.map +1 -1
  359. package/dist/relay/client-role/forward-engine.d.ts +63 -0
  360. package/dist/relay/client-role/forward-engine.d.ts.map +1 -0
  361. package/dist/relay/client-role/forward-engine.js +267 -0
  362. package/dist/relay/client-role/forward-engine.js.map +1 -0
  363. package/dist/relay/client-role/index.d.ts +9 -0
  364. package/dist/relay/client-role/index.d.ts.map +1 -0
  365. package/dist/relay/client-role/index.js +9 -0
  366. package/dist/relay/client-role/index.js.map +1 -0
  367. package/dist/relay/client-role/pull-engine.d.ts +72 -0
  368. package/dist/relay/client-role/pull-engine.d.ts.map +1 -0
  369. package/dist/relay/client-role/pull-engine.js +249 -0
  370. package/dist/relay/client-role/pull-engine.js.map +1 -0
  371. package/dist/relay/client-role/sequence-mapper.d.ts +65 -0
  372. package/dist/relay/client-role/sequence-mapper.d.ts.map +1 -0
  373. package/dist/relay/client-role/sequence-mapper.js +161 -0
  374. package/dist/relay/client-role/sequence-mapper.js.map +1 -0
  375. package/dist/relay/evaluation/relay-paths.d.ts +41 -0
  376. package/dist/relay/evaluation/relay-paths.d.ts.map +1 -0
  377. package/dist/relay/evaluation/relay-paths.js +504 -0
  378. package/dist/relay/evaluation/relay-paths.js.map +1 -0
  379. package/dist/relay/evaluation/rust-boundary.d.ts +47 -0
  380. package/dist/relay/evaluation/rust-boundary.d.ts.map +1 -0
  381. package/dist/relay/evaluation/rust-boundary.js +220 -0
  382. package/dist/relay/evaluation/rust-boundary.js.map +1 -0
  383. package/dist/relay/index.d.ts +37 -0
  384. package/dist/relay/index.d.ts.map +1 -0
  385. package/dist/relay/index.js +44 -0
  386. package/dist/relay/index.js.map +1 -0
  387. package/dist/relay/migrate.d.ts +18 -0
  388. package/dist/relay/migrate.d.ts.map +1 -0
  389. package/dist/relay/migrate.js +99 -0
  390. package/dist/relay/migrate.js.map +1 -0
  391. package/dist/relay/mode-manager.d.ts +60 -0
  392. package/dist/relay/mode-manager.d.ts.map +1 -0
  393. package/dist/relay/mode-manager.js +114 -0
  394. package/dist/relay/mode-manager.js.map +1 -0
  395. package/dist/relay/realtime.d.ts +90 -0
  396. package/dist/relay/realtime.d.ts.map +1 -0
  397. package/dist/relay/realtime.js +147 -0
  398. package/dist/relay/realtime.js.map +1 -0
  399. package/dist/relay/relay.d.ts +190 -0
  400. package/dist/relay/relay.d.ts.map +1 -0
  401. package/dist/relay/relay.js +320 -0
  402. package/dist/relay/relay.js.map +1 -0
  403. package/dist/relay/schema.d.ts +158 -0
  404. package/dist/relay/schema.d.ts.map +1 -0
  405. package/dist/relay/schema.js +7 -0
  406. package/dist/relay/schema.js.map +1 -0
  407. package/dist/relay/server-role/index.d.ts +56 -0
  408. package/dist/relay/server-role/index.d.ts.map +1 -0
  409. package/dist/relay/server-role/index.js +193 -0
  410. package/dist/relay/server-role/index.js.map +1 -0
  411. package/dist/relay/server-role/pull.d.ts +27 -0
  412. package/dist/relay/server-role/pull.d.ts.map +1 -0
  413. package/dist/relay/server-role/pull.js +24 -0
  414. package/dist/relay/server-role/pull.js.map +1 -0
  415. package/dist/relay/server-role/push.d.ts +29 -0
  416. package/dist/relay/server-role/push.d.ts.map +1 -0
  417. package/dist/relay/server-role/push.js +122 -0
  418. package/dist/relay/server-role/push.js.map +1 -0
  419. package/dist/s3/index.d.ts +83 -0
  420. package/dist/s3/index.d.ts.map +1 -0
  421. package/dist/s3/index.js +223 -0
  422. package/dist/s3/index.js.map +1 -0
  423. package/dist/schema.d.ts +137 -1
  424. package/dist/schema.d.ts.map +1 -1
  425. package/dist/schema.js +1 -0
  426. package/dist/schema.js.map +1 -1
  427. package/dist/service-worker/index.d.ts +114 -0
  428. package/dist/service-worker/index.d.ts.map +1 -0
  429. package/dist/service-worker/index.js +487 -0
  430. package/dist/service-worker/index.js.map +1 -0
  431. package/dist/snapshot-artifacts/sqlite-bun.d.ts +15 -0
  432. package/dist/snapshot-artifacts/sqlite-bun.d.ts.map +1 -0
  433. package/dist/snapshot-artifacts/sqlite-bun.js +128 -0
  434. package/dist/snapshot-artifacts/sqlite-bun.js.map +1 -0
  435. package/dist/snapshot-artifacts.d.ts +206 -0
  436. package/dist/snapshot-artifacts.d.ts.map +1 -0
  437. package/dist/snapshot-artifacts.js +545 -0
  438. package/dist/snapshot-artifacts.js.map +1 -0
  439. package/dist/snapshot-chunks/db-metadata.d.ts +18 -0
  440. package/dist/snapshot-chunks/db-metadata.d.ts.map +1 -1
  441. package/dist/snapshot-chunks/db-metadata.js +91 -63
  442. package/dist/snapshot-chunks/db-metadata.js.map +1 -1
  443. package/dist/snapshot-chunks/index.js +2 -2
  444. package/dist/snapshot-chunks/types.d.ts +2 -0
  445. package/dist/snapshot-chunks/types.d.ts.map +1 -1
  446. package/dist/snapshot-chunks.d.ts +33 -3
  447. package/dist/snapshot-chunks.d.ts.map +1 -1
  448. package/dist/snapshot-chunks.js +136 -55
  449. package/dist/snapshot-chunks.js.map +1 -1
  450. package/dist/sqlite/index.d.ts +53 -0
  451. package/dist/sqlite/index.d.ts.map +1 -0
  452. package/dist/sqlite/index.js +795 -0
  453. package/dist/sqlite/index.js.map +1 -0
  454. package/dist/sqlite3.d.ts +22 -0
  455. package/dist/sqlite3.d.ts.map +1 -0
  456. package/dist/sqlite3.js +99 -0
  457. package/dist/sqlite3.js.map +1 -0
  458. package/dist/stats.d.ts +8 -0
  459. package/dist/stats.d.ts.map +1 -1
  460. package/dist/stats.js +45 -13
  461. package/dist/stats.js.map +1 -1
  462. package/dist/subscriptions/cache.d.ts +3 -0
  463. package/dist/subscriptions/cache.d.ts.map +1 -1
  464. package/dist/subscriptions/cache.js +44 -0
  465. package/dist/subscriptions/cache.js.map +1 -1
  466. package/dist/subscriptions/index.js +2 -2
  467. package/dist/subscriptions/resolve.d.ts +3 -1
  468. package/dist/subscriptions/resolve.d.ts.map +1 -1
  469. package/dist/subscriptions/resolve.js +91 -52
  470. package/dist/subscriptions/resolve.js.map +1 -1
  471. package/dist/sync.d.ts +3 -0
  472. package/dist/sync.d.ts.map +1 -1
  473. package/dist/sync.js +9 -5
  474. package/dist/sync.js.map +1 -1
  475. package/package.json +297 -8
  476. package/src/auth-leases.ts +649 -0
  477. package/src/better-sqlite3.ts +35 -0
  478. package/src/blobs/access.ts +244 -0
  479. package/src/blobs/adapters/database.ts +125 -43
  480. package/src/blobs/index.ts +1 -0
  481. package/src/blobs/manager.ts +366 -65
  482. package/src/blobs/migrate.ts +16 -8
  483. package/src/blobs/types.ts +4 -0
  484. package/src/bun-sqlite-ambient.d.ts +19 -0
  485. package/src/bun-sqlite.ts +27 -0
  486. package/src/clients.ts +1 -0
  487. package/src/cloudflare/durable-object.ts +289 -0
  488. package/src/cloudflare/index.ts +22 -0
  489. package/src/cloudflare/r2.ts +526 -0
  490. package/src/cloudflare/scope-cache.ts +341 -0
  491. package/src/cloudflare/sentry.ts +230 -0
  492. package/src/cloudflare/worker.ts +77 -0
  493. package/src/commit-integrity.ts +371 -0
  494. package/src/crdt-yjs/index.ts +931 -0
  495. package/src/d1.ts +16 -0
  496. package/src/dialect/base.ts +71 -5
  497. package/src/dialect/helpers.ts +31 -0
  498. package/src/dialect/types.ts +47 -0
  499. package/src/encrypted-crdt.ts +786 -0
  500. package/src/errors.ts +22 -0
  501. package/src/filesystem/index.ts +262 -0
  502. package/src/handlers/collection.ts +78 -78
  503. package/src/handlers/create-handler.ts +540 -147
  504. package/src/handlers/types.ts +116 -0
  505. package/src/helpers/index.ts +2 -0
  506. package/src/helpers/scope-authorization.ts +27 -0
  507. package/src/helpers/scope-commit-index.ts +52 -0
  508. package/src/hono/api-key-auth.ts +177 -0
  509. package/src/hono/audit-redaction.ts +135 -0
  510. package/src/hono/blobs.ts +851 -0
  511. package/src/hono/console/gateway.ts +3046 -0
  512. package/src/hono/console/live-auth.ts +46 -0
  513. package/src/hono/console/route-descriptor.ts +22 -0
  514. package/src/hono/console/routes/api-keys.ts +721 -0
  515. package/src/hono/console/routes/clients.ts +447 -0
  516. package/src/hono/console/routes/commits.ts +1137 -0
  517. package/src/hono/console/routes/context.ts +956 -0
  518. package/src/hono/console/routes/events.ts +669 -0
  519. package/src/hono/console/routes/maintenance.ts +461 -0
  520. package/src/hono/console/routes/shared.ts +816 -0
  521. package/src/hono/console/routes/stats.ts +392 -0
  522. package/src/hono/console/routes/storage.ts +159 -0
  523. package/src/hono/console/routes.ts +146 -0
  524. package/src/hono/console/schema-errors.ts +23 -0
  525. package/src/hono/console/schemas.ts +914 -0
  526. package/src/hono/console/types.ts +223 -0
  527. package/src/hono/console/ui.ts +100 -0
  528. package/src/hono/create-server.ts +230 -0
  529. package/src/hono/errors.ts +50 -0
  530. package/src/hono/index.ts +54 -0
  531. package/src/hono/openapi.ts +139 -0
  532. package/src/hono/proxy/connection-manager.ts +340 -0
  533. package/src/hono/proxy/index.ts +8 -0
  534. package/src/hono/proxy/routes.ts +272 -0
  535. package/src/hono/rate-limit.ts +319 -0
  536. package/src/hono/realtime-sync-packs.ts +354 -0
  537. package/src/hono/routes/audit.ts +499 -0
  538. package/src/hono/routes/auth-leases.ts +119 -0
  539. package/src/hono/routes/combined.ts +583 -0
  540. package/src/hono/routes/context.ts +1629 -0
  541. package/src/hono/routes/health.ts +26 -0
  542. package/src/hono/routes/realtime.ts +808 -0
  543. package/src/hono/routes/shared.ts +1626 -0
  544. package/src/hono/routes/snapshots.ts +345 -0
  545. package/src/hono/routes.ts +68 -0
  546. package/src/hono/validation.ts +81 -0
  547. package/src/hono/websocket-origin.ts +131 -0
  548. package/src/hono/ws.ts +1134 -0
  549. package/src/index.ts +6 -0
  550. package/src/libsql.ts +51 -0
  551. package/src/neon.ts +28 -0
  552. package/src/notify.ts +224 -44
  553. package/src/pglite.ts +68 -0
  554. package/src/plugins/index.ts +1 -0
  555. package/src/plugins/types.ts +144 -0
  556. package/src/postgres/index.ts +1291 -0
  557. package/src/proxy/collection.ts +5 -27
  558. package/src/proxy/handler.ts +2 -2
  559. package/src/proxy/index.ts +0 -2
  560. package/src/proxy/oplog.ts +41 -10
  561. package/src/prune.ts +137 -36
  562. package/src/pull.ts +1504 -591
  563. package/src/push.ts +881 -443
  564. package/src/realtime/index.ts +2 -0
  565. package/src/realtime/types.ts +35 -0
  566. package/src/relay/bun-types.d.ts +50 -0
  567. package/src/relay/client-role/forward-engine.ts +355 -0
  568. package/src/relay/client-role/index.ts +9 -0
  569. package/src/relay/client-role/pull-engine.ts +329 -0
  570. package/src/relay/client-role/sequence-mapper.ts +201 -0
  571. package/src/relay/evaluation/relay-paths.ts +699 -0
  572. package/src/relay/evaluation/rust-boundary.ts +464 -0
  573. package/src/relay/index.ts +50 -0
  574. package/src/relay/migrate.ts +113 -0
  575. package/src/relay/mode-manager.ts +142 -0
  576. package/src/relay/realtime.ts +207 -0
  577. package/src/relay/relay.ts +431 -0
  578. package/src/relay/schema.ts +171 -0
  579. package/src/relay/server-role/index.ts +338 -0
  580. package/src/relay/server-role/pull.ts +43 -0
  581. package/src/relay/server-role/push.ts +164 -0
  582. package/src/s3/index.ts +346 -0
  583. package/src/schema.ts +141 -1
  584. package/src/service-worker/index.ts +773 -0
  585. package/src/snapshot-artifacts/sqlite-bun.ts +168 -0
  586. package/src/snapshot-artifacts.ts +896 -0
  587. package/src/snapshot-chunks/db-metadata.ts +131 -72
  588. package/src/snapshot-chunks/types.ts +2 -0
  589. package/src/snapshot-chunks.ts +194 -70
  590. package/src/sqlite/index.ts +1064 -0
  591. package/src/sqlite3.ts +137 -0
  592. package/src/stats.ts +76 -13
  593. package/src/subscriptions/cache.ts +58 -0
  594. package/src/subscriptions/resolve.ts +99 -58
  595. package/src/sync.ts +16 -6
  596. package/src/blobs/adapters/database.test.ts +0 -67
  597. package/src/notify.test.ts +0 -520
  598. package/src/proxy/handler.test.ts +0 -126
  599. package/src/proxy/mutation-detector.test.ts +0 -71
  600. package/src/snapshot-chunks/db-metadata.test.ts +0 -172
  601. package/src/subscriptions/resolve.test.ts +0 -180
@@ -0,0 +1,931 @@
1
+ import {
2
+ type ApplyOperationResult,
3
+ ServerPushPluginPriority,
4
+ type SyncChange,
5
+ type SyncCrdtStateVectorHint,
6
+ type SyncServerPlugin,
7
+ } from '@syncular/server';
8
+ import { sql } from 'kysely';
9
+ import * as Y from 'yjs';
10
+
11
+ export const YJS_PAYLOAD_KEY = '__yjs';
12
+
13
+ const BASE64_PATTERN =
14
+ /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/;
15
+
16
+ export type YjsFieldKind = 'text' | 'xml-fragment' | 'prosemirror';
17
+
18
+ export interface YjsServerFieldRule {
19
+ table: string;
20
+ field: string;
21
+ /**
22
+ * Column that stores canonical serialized Yjs state.
23
+ * Example: "content_yjs_state"
24
+ */
25
+ stateColumn: string;
26
+ /**
27
+ * Container key inside the Yjs document. Defaults to `field`.
28
+ */
29
+ containerKey?: string;
30
+ /**
31
+ * Snapshot row id column. Defaults to `id`.
32
+ */
33
+ rowIdField?: string;
34
+ /**
35
+ * CRDT container type.
36
+ */
37
+ kind?: YjsFieldKind;
38
+ }
39
+
40
+ interface ResolvedYjsServerFieldRule extends YjsServerFieldRule {
41
+ containerKey: string;
42
+ rowIdField: string;
43
+ kind: YjsFieldKind;
44
+ }
45
+
46
+ export interface YjsServerUpdateEnvelope {
47
+ updateId: string;
48
+ updateBase64: string;
49
+ requiresStateVectorBase64?: string;
50
+ }
51
+
52
+ export type YjsServerUpdateInput =
53
+ | YjsServerUpdateEnvelope
54
+ | readonly YjsServerUpdateEnvelope[];
55
+
56
+ export interface YjsServerPayloadEnvelope {
57
+ [field: string]: YjsServerUpdateInput;
58
+ }
59
+
60
+ export interface BuildYjsTextUpdateArgs {
61
+ previousStateBase64?: string | Uint8Array | null;
62
+ nextText: string;
63
+ containerKey?: string;
64
+ updateId?: string;
65
+ }
66
+
67
+ export interface BuildYjsTextUpdateResult {
68
+ update: YjsServerUpdateEnvelope;
69
+ nextStateBase64: string;
70
+ nextText: string;
71
+ }
72
+
73
+ export interface ApplyYjsTextUpdatesArgs {
74
+ previousStateBase64?: string | Uint8Array | null;
75
+ updates: readonly YjsServerUpdateEnvelope[];
76
+ containerKey?: string;
77
+ }
78
+
79
+ export interface ApplyYjsTextUpdatesResult {
80
+ nextStateBase64: string;
81
+ text: string;
82
+ }
83
+
84
+ export interface CreateYjsServerModuleOptions {
85
+ name?: string;
86
+ rules: readonly YjsServerFieldRule[];
87
+ envelopeKey?: string;
88
+ /**
89
+ * Throw when envelope payload references fields without matching rules.
90
+ * @default true
91
+ */
92
+ strict?: boolean;
93
+ /**
94
+ * Remove the Yjs envelope key from processed payload/rows.
95
+ * @default true
96
+ */
97
+ stripEnvelope?: boolean;
98
+ }
99
+
100
+ export interface CreateYjsServerPushPluginOptions
101
+ extends CreateYjsServerModuleOptions {
102
+ priority?: number;
103
+ }
104
+
105
+ type RuleIndex = Map<string, Map<string, ResolvedYjsServerFieldRule>>;
106
+
107
+ export interface YjsServerApplyPayloadArgs {
108
+ table: string;
109
+ rowId: string;
110
+ payload: Record<string, unknown>;
111
+ existingRow?: Record<string, unknown> | null;
112
+ }
113
+
114
+ export interface YjsServerMaterializeRowArgs {
115
+ table: string;
116
+ row: Record<string, unknown>;
117
+ }
118
+
119
+ export type YjsServerStateVectorHint = SyncCrdtStateVectorHint;
120
+
121
+ export interface YjsServerTransformPullChangesArgs {
122
+ table: string;
123
+ changes: readonly SyncChange[];
124
+ crdtStateVectors: readonly YjsServerStateVectorHint[];
125
+ }
126
+
127
+ export interface YjsServerModule {
128
+ name: string;
129
+ rules: readonly YjsServerFieldRule[];
130
+ envelopeKey: string;
131
+ applyPayload(
132
+ args: YjsServerApplyPayloadArgs
133
+ ): Promise<Record<string, unknown>>;
134
+ materializeRow(
135
+ args: YjsServerMaterializeRowArgs
136
+ ): Promise<Record<string, unknown>>;
137
+ transformPullChanges(
138
+ args: YjsServerTransformPullChangesArgs
139
+ ): Promise<readonly SyncChange[]>;
140
+ }
141
+
142
+ function isRecord(value: unknown): value is Record<string, unknown> {
143
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
144
+ }
145
+
146
+ function readString(value: unknown): string | null {
147
+ return typeof value === 'string' && value.length > 0 ? value : null;
148
+ }
149
+
150
+ function bytesToBase64(bytes: Uint8Array): string {
151
+ if (typeof Buffer !== 'undefined') {
152
+ return Buffer.from(bytes).toString('base64');
153
+ }
154
+
155
+ let binary = '';
156
+ for (const byte of bytes) {
157
+ binary += String.fromCharCode(byte);
158
+ }
159
+ return btoa(binary);
160
+ }
161
+
162
+ function tryReadBase64TextFromBytes(bytes: Uint8Array): string | null {
163
+ if (bytes.length === 0) return null;
164
+ try {
165
+ const decoded = new TextDecoder().decode(bytes).trim();
166
+ if (!decoded || !BASE64_PATTERN.test(decoded)) return null;
167
+ return decoded;
168
+ } catch {
169
+ return null;
170
+ }
171
+ }
172
+
173
+ function base64ToBytes(base64: string): Uint8Array {
174
+ if (!BASE64_PATTERN.test(base64)) {
175
+ throw new Error('Invalid base64 string');
176
+ }
177
+
178
+ if (typeof Buffer !== 'undefined') {
179
+ return new Uint8Array(Buffer.from(base64, 'base64'));
180
+ }
181
+
182
+ const binary = atob(base64);
183
+ const out = new Uint8Array(binary.length);
184
+ for (let i = 0; i < binary.length; i++) {
185
+ out[i] = binary.charCodeAt(i);
186
+ }
187
+ return out;
188
+ }
189
+
190
+ function stateValueToBytes(value: unknown): Uint8Array | null {
191
+ if (value instanceof Uint8Array) {
192
+ const encoded = tryReadBase64TextFromBytes(value);
193
+ if (encoded) return base64ToBytes(encoded);
194
+ return value;
195
+ }
196
+ const str = readString(value);
197
+ if (!str) return null;
198
+ return base64ToBytes(str);
199
+ }
200
+
201
+ function stateValueToBase64(value: unknown): string | null {
202
+ const str = readString(value);
203
+ if (str) return str;
204
+ if (value instanceof Uint8Array) {
205
+ const encoded = tryReadBase64TextFromBytes(value);
206
+ if (encoded) return encoded;
207
+ return bytesToBase64(value);
208
+ }
209
+ return null;
210
+ }
211
+
212
+ function createDocFromState(stateValue: unknown): Y.Doc {
213
+ const doc = new Y.Doc();
214
+ const bytes = stateValueToBytes(stateValue);
215
+ if (bytes && bytes.length > 0) {
216
+ Y.applyUpdate(doc, bytes);
217
+ }
218
+ return doc;
219
+ }
220
+
221
+ function exportSnapshotBase64(doc: Y.Doc): string {
222
+ return bytesToBase64(Y.encodeStateAsUpdate(doc));
223
+ }
224
+
225
+ function exportUpdateFromStateVectorBase64(
226
+ stateValue: unknown,
227
+ stateVectorBase64: string
228
+ ): string | null {
229
+ const stateBytes = stateValueToBytes(stateValue);
230
+ if (!stateBytes || stateBytes.length === 0) return null;
231
+ const stateVector = base64ToBytes(stateVectorBase64);
232
+ const doc = new Y.Doc();
233
+ try {
234
+ Y.applyUpdate(doc, stateBytes);
235
+ return bytesToBase64(Y.encodeStateAsUpdate(doc, stateVector));
236
+ } finally {
237
+ doc.destroy();
238
+ }
239
+ }
240
+
241
+ function ensureTextContainer(doc: Y.Doc, containerKey: string): string {
242
+ return doc.getText(containerKey).toString();
243
+ }
244
+
245
+ function ensureXmlFragmentContainer(doc: Y.Doc, containerKey: string): string {
246
+ return doc.getXmlFragment(containerKey).toString();
247
+ }
248
+
249
+ function replaceText(doc: Y.Doc, containerKey: string, nextText: string): void {
250
+ const text = doc.getText(containerKey);
251
+ const currentLength = text.length;
252
+ doc.transact(() => {
253
+ if (currentLength > 0) {
254
+ text.delete(0, currentLength);
255
+ }
256
+ if (nextText.length > 0) {
257
+ text.insert(0, nextText);
258
+ }
259
+ });
260
+ }
261
+
262
+ function patchText(doc: Y.Doc, containerKey: string, nextText: string): void {
263
+ const text = doc.getText(containerKey);
264
+ const currentText = text.toString();
265
+ if (currentText === nextText) return;
266
+
267
+ const minLength = Math.min(currentText.length, nextText.length);
268
+ let prefixLength = 0;
269
+ while (
270
+ prefixLength < minLength &&
271
+ currentText.charCodeAt(prefixLength) === nextText.charCodeAt(prefixLength)
272
+ ) {
273
+ prefixLength += 1;
274
+ }
275
+
276
+ let currentSuffixStart = currentText.length;
277
+ let nextSuffixStart = nextText.length;
278
+ while (
279
+ currentSuffixStart > prefixLength &&
280
+ nextSuffixStart > prefixLength &&
281
+ currentText.charCodeAt(currentSuffixStart - 1) ===
282
+ nextText.charCodeAt(nextSuffixStart - 1)
283
+ ) {
284
+ currentSuffixStart -= 1;
285
+ nextSuffixStart -= 1;
286
+ }
287
+
288
+ const deleteLength = currentSuffixStart - prefixLength;
289
+ const insertSegment = nextText.slice(prefixLength, nextSuffixStart);
290
+
291
+ doc.transact(() => {
292
+ if (deleteLength > 0) {
293
+ text.delete(prefixLength, deleteLength);
294
+ }
295
+ if (insertSegment.length > 0) {
296
+ text.insert(prefixLength, insertSegment);
297
+ }
298
+ });
299
+ }
300
+
301
+ function materializeRuleValue(
302
+ doc: Y.Doc,
303
+ rule: ResolvedYjsServerFieldRule
304
+ ): unknown {
305
+ if (rule.kind === 'text') {
306
+ return ensureTextContainer(doc, rule.containerKey);
307
+ }
308
+ return ensureXmlFragmentContainer(doc, rule.containerKey);
309
+ }
310
+
311
+ function seedRuleValueFromPayload(
312
+ doc: Y.Doc,
313
+ rule: ResolvedYjsServerFieldRule,
314
+ source: Record<string, unknown>
315
+ ): void {
316
+ if (rule.kind !== 'text') return;
317
+ const initialText = readString(source[rule.field]);
318
+ if (initialText) {
319
+ replaceText(doc, rule.containerKey, initialText);
320
+ }
321
+ }
322
+
323
+ function createUpdateId(): string {
324
+ const randomUUID = globalThis.crypto?.randomUUID;
325
+ if (typeof randomUUID === 'function') {
326
+ return randomUUID.call(globalThis.crypto);
327
+ }
328
+ const ts = Date.now().toString(36);
329
+ const rnd = Math.random().toString(36).slice(2, 12);
330
+ return `yjs-${ts}-${rnd}`;
331
+ }
332
+
333
+ function buildRuleIndex(rules: readonly YjsServerFieldRule[]): {
334
+ index: RuleIndex;
335
+ normalizedRules: readonly ResolvedYjsServerFieldRule[];
336
+ } {
337
+ const index: RuleIndex = new Map();
338
+ const normalizedRules: ResolvedYjsServerFieldRule[] = [];
339
+ const seen = new Set<string>();
340
+
341
+ for (const rule of rules) {
342
+ if (!rule.table.trim()) {
343
+ throw new Error('YjsServerFieldRule.table cannot be empty');
344
+ }
345
+ if (!rule.field.trim()) {
346
+ throw new Error('YjsServerFieldRule.field cannot be empty');
347
+ }
348
+ if (!rule.stateColumn.trim()) {
349
+ throw new Error('YjsServerFieldRule.stateColumn cannot be empty');
350
+ }
351
+
352
+ const key = `${rule.table}\u001f${rule.field}`;
353
+ if (seen.has(key)) {
354
+ throw new Error(
355
+ `Duplicate Yjs server rule for table "${rule.table}", field "${rule.field}"`
356
+ );
357
+ }
358
+ seen.add(key);
359
+
360
+ const resolved: ResolvedYjsServerFieldRule = {
361
+ ...rule,
362
+ containerKey: rule.containerKey ?? rule.field,
363
+ rowIdField: rule.rowIdField ?? 'id',
364
+ kind: rule.kind ?? 'text',
365
+ };
366
+ normalizedRules.push(resolved);
367
+
368
+ const tableRules = index.get(resolved.table) ?? new Map();
369
+ tableRules.set(resolved.field, resolved);
370
+ index.set(resolved.table, tableRules);
371
+ }
372
+
373
+ return { index, normalizedRules };
374
+ }
375
+
376
+ function normalizeUpdateEnvelope(
377
+ value: unknown,
378
+ context: string
379
+ ): YjsServerUpdateEnvelope {
380
+ if (!isRecord(value)) {
381
+ throw new Error(`${context} must be an object`);
382
+ }
383
+ const updateId = readString(value.updateId);
384
+ const updateBase64 = readString(value.updateBase64);
385
+ if (!updateId) {
386
+ throw new Error(`${context}.updateId must be a non-empty string`);
387
+ }
388
+ if (!updateBase64) {
389
+ throw new Error(
390
+ `${context}.updateBase64 must be a non-empty base64 string`
391
+ );
392
+ }
393
+ const requiresStateVectorBase64 = readString(value.requiresStateVectorBase64);
394
+ return {
395
+ updateId,
396
+ updateBase64,
397
+ ...(requiresStateVectorBase64 ? { requiresStateVectorBase64 } : {}),
398
+ };
399
+ }
400
+
401
+ function normalizeUpdateEnvelopes(
402
+ value: unknown,
403
+ context: string
404
+ ): YjsServerUpdateEnvelope[] {
405
+ if (Array.isArray(value)) {
406
+ return value.map((entry, i) =>
407
+ normalizeUpdateEnvelope(entry, `${context}[${i}]`)
408
+ );
409
+ }
410
+ return [normalizeUpdateEnvelope(value, context)];
411
+ }
412
+
413
+ /*async function applyYjsTextUpdates(
414
+ args: ApplyYjsTextUpdatesArgs
415
+ ): Promise<ApplyYjsTextUpdatesResult> {
416
+ const containerKey = args.containerKey ?? 'text';
417
+ const doc = createDocFromState(args.previousStateBase64);
418
+ try {
419
+ for (const update of args.updates) {
420
+ Y.applyUpdate(doc, base64ToBytes(update.updateBase64));
421
+ }
422
+ const text = ensureTextContainer(doc, containerKey);
423
+ const nextStateBase64 = exportSnapshotBase64(doc);
424
+ return { nextStateBase64, text };
425
+ } finally {
426
+ doc.destroy();
427
+ }
428
+ }*/
429
+
430
+ export async function buildYjsTextUpdate(
431
+ args: BuildYjsTextUpdateArgs
432
+ ): Promise<BuildYjsTextUpdateResult> {
433
+ const containerKey = args.containerKey ?? 'text';
434
+ const doc = createDocFromState(args.previousStateBase64);
435
+ try {
436
+ const from = Y.encodeStateVector(doc);
437
+ patchText(doc, containerKey, args.nextText);
438
+ const update = bytesToBase64(Y.encodeStateAsUpdate(doc, from));
439
+ const nextText = ensureTextContainer(doc, containerKey);
440
+ const nextStateBase64 = exportSnapshotBase64(doc);
441
+
442
+ return {
443
+ update: {
444
+ updateId: args.updateId ?? createUpdateId(),
445
+ updateBase64: update,
446
+ },
447
+ nextStateBase64,
448
+ nextText,
449
+ };
450
+ } finally {
451
+ doc.destroy();
452
+ }
453
+ }
454
+
455
+ async function materializeRowFromState(args: {
456
+ table: string;
457
+ row: Record<string, unknown>;
458
+ index: RuleIndex;
459
+ envelopeKey: string;
460
+ stripEnvelope: boolean;
461
+ }): Promise<Record<string, unknown>> {
462
+ const tableRules = args.index.get(args.table);
463
+ if (!tableRules) {
464
+ if (args.stripEnvelope && args.envelopeKey in args.row) {
465
+ const next = { ...args.row };
466
+ delete next[args.envelopeKey];
467
+ return next;
468
+ }
469
+ return args.row;
470
+ }
471
+
472
+ let nextRow: Record<string, unknown> | null = null;
473
+ const ensureRow = (): Record<string, unknown> => {
474
+ if (nextRow) return nextRow;
475
+ nextRow = { ...args.row };
476
+ return nextRow;
477
+ };
478
+
479
+ for (const rule of tableRules.values()) {
480
+ const source = nextRow ?? args.row;
481
+ const stateBase64 = stateValueToBase64(source[rule.stateColumn]);
482
+ if (!stateBase64) continue;
483
+
484
+ const doc = createDocFromState(stateBase64);
485
+ try {
486
+ const nextValue = materializeRuleValue(doc, rule);
487
+ if (source[rule.field] !== nextValue) {
488
+ ensureRow()[rule.field] = nextValue;
489
+ }
490
+ } finally {
491
+ doc.destroy();
492
+ }
493
+ }
494
+
495
+ if (args.stripEnvelope) {
496
+ const source = nextRow ?? args.row;
497
+ if (args.envelopeKey in source) {
498
+ const target = ensureRow();
499
+ delete target[args.envelopeKey];
500
+ }
501
+ }
502
+
503
+ return nextRow ?? args.row;
504
+ }
505
+
506
+ async function applyYjsEnvelopeToPayload(args: {
507
+ table: string;
508
+ payload: Record<string, unknown>;
509
+ existingRow?: Record<string, unknown> | null;
510
+ index: RuleIndex;
511
+ envelopeKey: string;
512
+ stripEnvelope: boolean;
513
+ strict: boolean;
514
+ }): Promise<Record<string, unknown>> {
515
+ const tableRules = args.index.get(args.table);
516
+ const rawEnvelope = args.payload[args.envelopeKey];
517
+
518
+ if (!tableRules) {
519
+ if (rawEnvelope !== undefined && args.strict) {
520
+ throw new Error(
521
+ `Yjs envelope provided for table "${args.table}" without matching rules`
522
+ );
523
+ }
524
+ if (args.stripEnvelope && rawEnvelope !== undefined) {
525
+ const next = { ...args.payload };
526
+ delete next[args.envelopeKey];
527
+ return next;
528
+ }
529
+ return args.payload;
530
+ }
531
+
532
+ const sourceEnvelope = rawEnvelope;
533
+ if (sourceEnvelope !== undefined && !isRecord(sourceEnvelope)) {
534
+ throw new Error(
535
+ `Yjs payload key "${args.envelopeKey}" must be an object for table "${args.table}"`
536
+ );
537
+ }
538
+
539
+ const basePayload =
540
+ sourceEnvelope && args.existingRow
541
+ ? { ...args.existingRow, ...args.payload }
542
+ : args.payload;
543
+ let nextPayload: Record<string, unknown> | null =
544
+ basePayload === args.payload ? null : basePayload;
545
+ const ensurePayload = (): Record<string, unknown> => {
546
+ if (nextPayload) return nextPayload;
547
+ nextPayload = { ...basePayload };
548
+ return nextPayload;
549
+ };
550
+
551
+ if (sourceEnvelope) {
552
+ for (const [field, rawUpdateInput] of Object.entries(sourceEnvelope)) {
553
+ const rule = tableRules.get(field);
554
+ if (!rule) {
555
+ if (args.strict) {
556
+ throw new Error(
557
+ `No Yjs rule found for envelope field "${field}" on table "${args.table}"`
558
+ );
559
+ }
560
+ continue;
561
+ }
562
+
563
+ const updates = normalizeUpdateEnvelopes(
564
+ rawUpdateInput,
565
+ `yjs.${args.table}.${field}`
566
+ );
567
+
568
+ const source = nextPayload ?? basePayload;
569
+ const existingSource = args.existingRow ?? null;
570
+ const baseState =
571
+ (existingSource
572
+ ? stateValueToBase64(existingSource[rule.stateColumn])
573
+ : null) ??
574
+ stateValueToBase64(source[rule.stateColumn]) ??
575
+ null;
576
+
577
+ const requiredBase = updates.find(
578
+ (update) => update.requiresStateVectorBase64
579
+ )?.requiresStateVectorBase64;
580
+ if (!baseState && requiredBase) {
581
+ throw new Error(
582
+ `Yjs diff envelope for table "${args.table}" field "${field}" requires local base state vector ${requiredBase}, but no local state is available; full snapshot resync required`
583
+ );
584
+ }
585
+
586
+ const doc = createDocFromState(baseState);
587
+ try {
588
+ if (!baseState) {
589
+ seedRuleValueFromPayload(doc, rule, source);
590
+ }
591
+
592
+ for (const update of updates) {
593
+ if (update.requiresStateVectorBase64) {
594
+ const actualStateVectorBase64 = bytesToBase64(
595
+ Y.encodeStateVector(doc)
596
+ );
597
+ if (actualStateVectorBase64 !== update.requiresStateVectorBase64) {
598
+ throw new Error(
599
+ `Yjs update ${update.updateId} requires base state vector ${update.requiresStateVectorBase64}, but current state vector is ${actualStateVectorBase64}; full snapshot resync required`
600
+ );
601
+ }
602
+ }
603
+ Y.applyUpdate(doc, base64ToBytes(update.updateBase64));
604
+ }
605
+
606
+ const nextValue = materializeRuleValue(doc, rule);
607
+ const nextStateBase64 = exportSnapshotBase64(doc);
608
+ const target = ensurePayload();
609
+ target[rule.field] = nextValue;
610
+ target[rule.stateColumn] = nextStateBase64;
611
+ } finally {
612
+ doc.destroy();
613
+ }
614
+ }
615
+ }
616
+
617
+ if (args.stripEnvelope) {
618
+ const source = nextPayload ?? basePayload;
619
+ if (args.envelopeKey in source) {
620
+ const target = ensurePayload();
621
+ delete target[args.envelopeKey];
622
+ }
623
+ }
624
+
625
+ return nextPayload ?? args.payload;
626
+ }
627
+
628
+ function createHintKey(rowId: string, field: string, stateColumn: string) {
629
+ return `${rowId}\u001f${field}\u001f${stateColumn}`;
630
+ }
631
+
632
+ function indexStateVectorHints(
633
+ hints: readonly YjsServerStateVectorHint[]
634
+ ): Map<string, YjsServerStateVectorHint> {
635
+ const indexed = new Map<string, YjsServerStateVectorHint>();
636
+ for (const hint of hints) {
637
+ if (hint.syncMode !== 'server-merge') continue;
638
+ indexed.set(createHintKey(hint.rowId, hint.field, hint.stateColumn), hint);
639
+ }
640
+ return indexed;
641
+ }
642
+
643
+ function transformPullChangeWithStateVectorHints(args: {
644
+ table: string;
645
+ change: SyncChange;
646
+ index: RuleIndex;
647
+ hintsByKey: ReadonlyMap<string, YjsServerStateVectorHint>;
648
+ envelopeKey: string;
649
+ }): SyncChange {
650
+ if (args.change.op !== 'upsert' || !isRecord(args.change.row_json)) {
651
+ return args.change;
652
+ }
653
+
654
+ const tableRules = args.index.get(args.table);
655
+ if (!tableRules) return args.change;
656
+
657
+ const row = args.change.row_json;
658
+ let nextRow: Record<string, unknown> | null = null;
659
+ let envelope: YjsServerPayloadEnvelope | undefined;
660
+
661
+ const ensureRow = (): Record<string, unknown> => {
662
+ if (nextRow) return nextRow;
663
+ nextRow = { ...row };
664
+ return nextRow;
665
+ };
666
+
667
+ const ensureEnvelope = (): YjsServerPayloadEnvelope => {
668
+ if (envelope) return envelope;
669
+ const target = ensureRow();
670
+ const existingEnvelope = target[args.envelopeKey];
671
+ envelope = {};
672
+ if (isRecord(existingEnvelope)) {
673
+ for (const [field, updateInput] of Object.entries(existingEnvelope)) {
674
+ envelope[field] = updateInput as YjsServerUpdateInput;
675
+ }
676
+ }
677
+ target[args.envelopeKey] = envelope;
678
+ return envelope;
679
+ };
680
+
681
+ for (const rule of tableRules.values()) {
682
+ const hint = args.hintsByKey.get(
683
+ createHintKey(args.change.row_id, rule.field, rule.stateColumn)
684
+ );
685
+ if (!hint) continue;
686
+
687
+ const serverState = row[rule.stateColumn];
688
+ const updateBase64 = exportUpdateFromStateVectorBase64(
689
+ serverState,
690
+ hint.stateVectorBase64
691
+ );
692
+ if (!updateBase64) continue;
693
+
694
+ const target = ensureRow();
695
+ delete target[rule.field];
696
+ delete target[rule.stateColumn];
697
+ ensureEnvelope()[rule.field] = {
698
+ updateId: `server:${args.table}:${args.change.row_id}:${rule.field}:${hint.updatedAt}`,
699
+ updateBase64,
700
+ requiresStateVectorBase64: hint.stateVectorBase64,
701
+ };
702
+ }
703
+
704
+ if (!nextRow) return args.change;
705
+ return {
706
+ ...args.change,
707
+ row_json: nextRow,
708
+ };
709
+ }
710
+
711
+ async function transformPullChangesWithStateVectorHints(args: {
712
+ table: string;
713
+ changes: readonly SyncChange[];
714
+ index: RuleIndex;
715
+ envelopeKey: string;
716
+ crdtStateVectors: readonly YjsServerStateVectorHint[];
717
+ }): Promise<readonly SyncChange[]> {
718
+ const tableRules = args.index.get(args.table);
719
+ if (!tableRules || args.crdtStateVectors.length === 0) {
720
+ return args.changes;
721
+ }
722
+ const hintsByKey = indexStateVectorHints(args.crdtStateVectors);
723
+ if (hintsByKey.size === 0) return args.changes;
724
+
725
+ let changed = false;
726
+ const nextChanges = args.changes.map((change) => {
727
+ const nextChange = transformPullChangeWithStateVectorHints({
728
+ table: args.table,
729
+ change,
730
+ index: args.index,
731
+ hintsByKey,
732
+ envelopeKey: args.envelopeKey,
733
+ });
734
+ if (nextChange !== change) changed = true;
735
+ return nextChange;
736
+ });
737
+
738
+ return changed ? nextChanges : args.changes;
739
+ }
740
+
741
+ export function createYjsServerModule(
742
+ options: CreateYjsServerModuleOptions
743
+ ): YjsServerModule {
744
+ if (options.rules.length === 0) {
745
+ throw new Error(
746
+ 'createYjsServerModule requires at least one table/field rule'
747
+ );
748
+ }
749
+
750
+ const envelopeKey = options.envelopeKey ?? YJS_PAYLOAD_KEY;
751
+ const strict = options.strict ?? true;
752
+ const stripEnvelope = options.stripEnvelope ?? true;
753
+ const { index } = buildRuleIndex(options.rules);
754
+
755
+ return {
756
+ name: options.name ?? 'crdt-yjs-server',
757
+ rules: options.rules,
758
+ envelopeKey,
759
+
760
+ async applyPayload(args): Promise<Record<string, unknown>> {
761
+ return await applyYjsEnvelopeToPayload({
762
+ table: args.table,
763
+ payload: args.payload,
764
+ existingRow: args.existingRow,
765
+ index,
766
+ envelopeKey,
767
+ stripEnvelope,
768
+ strict,
769
+ });
770
+ },
771
+
772
+ async materializeRow(args): Promise<Record<string, unknown>> {
773
+ return await materializeRowFromState({
774
+ table: args.table,
775
+ row: args.row,
776
+ index,
777
+ envelopeKey,
778
+ stripEnvelope,
779
+ });
780
+ },
781
+
782
+ async transformPullChanges(args): Promise<readonly SyncChange[]> {
783
+ return await transformPullChangesWithStateVectorHints({
784
+ table: args.table,
785
+ changes: args.changes,
786
+ crdtStateVectors: args.crdtStateVectors,
787
+ index,
788
+ envelopeKey,
789
+ });
790
+ },
791
+ };
792
+ }
793
+
794
+ function buildTableRowIdFieldIndex(
795
+ rules: readonly YjsServerFieldRule[]
796
+ ): Map<string, string> {
797
+ const tableRowIdFields = new Map<string, string>();
798
+
799
+ for (const rule of rules) {
800
+ const rowIdField = rule.rowIdField ?? 'id';
801
+ const existing = tableRowIdFields.get(rule.table);
802
+ if (existing && existing !== rowIdField) {
803
+ throw new Error(
804
+ `Yjs rules for table "${rule.table}" must use a single rowIdField`
805
+ );
806
+ }
807
+ tableRowIdFields.set(rule.table, rowIdField);
808
+ }
809
+
810
+ return tableRowIdFields;
811
+ }
812
+
813
+ async function materializeAppliedResult(
814
+ yjsModule: YjsServerModule,
815
+ opTable: string,
816
+ applied: ApplyOperationResult
817
+ ): Promise<ApplyOperationResult> {
818
+ let nextResult: ApplyOperationResult['result'] = applied.result;
819
+ let resultChanged = false;
820
+
821
+ if (nextResult.status === 'conflict' && isRecord(nextResult.server_row)) {
822
+ const materializedServerRow = await yjsModule.materializeRow({
823
+ table: opTable,
824
+ row: nextResult.server_row,
825
+ });
826
+ if (materializedServerRow !== nextResult.server_row) {
827
+ nextResult = {
828
+ ...nextResult,
829
+ server_row: materializedServerRow,
830
+ };
831
+ resultChanged = true;
832
+ }
833
+ }
834
+
835
+ let emittedChanged = false;
836
+ const nextEmitted: ApplyOperationResult['emittedChanges'] = [];
837
+ for (const emitted of applied.emittedChanges) {
838
+ if (emitted.op !== 'upsert' || !isRecord(emitted.row_json)) {
839
+ nextEmitted.push(emitted);
840
+ continue;
841
+ }
842
+
843
+ const materializedRow = await yjsModule.materializeRow({
844
+ table: emitted.table,
845
+ row: emitted.row_json,
846
+ });
847
+ if (materializedRow !== emitted.row_json) {
848
+ emittedChanged = true;
849
+ nextEmitted.push({
850
+ ...emitted,
851
+ row_json: materializedRow,
852
+ });
853
+ continue;
854
+ }
855
+
856
+ nextEmitted.push(emitted);
857
+ }
858
+
859
+ if (!resultChanged && !emittedChanged) {
860
+ return applied;
861
+ }
862
+
863
+ return {
864
+ result: nextResult,
865
+ emittedChanges: emittedChanged ? nextEmitted : applied.emittedChanges,
866
+ };
867
+ }
868
+
869
+ export function createYjsServerPushPlugin(
870
+ options: CreateYjsServerPushPluginOptions
871
+ ): SyncServerPlugin {
872
+ const yjsModule = createYjsServerModule(options);
873
+ const tableRowIdFields = buildTableRowIdFieldIndex(options.rules);
874
+
875
+ return {
876
+ name: options.name ?? yjsModule.name,
877
+ priority: options.priority ?? ServerPushPluginPriority.CRDT,
878
+
879
+ async beforeApplyOperation(args) {
880
+ const op = args.op;
881
+ if (op.op !== 'upsert' || !isRecord(op.payload)) {
882
+ return op;
883
+ }
884
+
885
+ const rowIdField = tableRowIdFields.get(op.table);
886
+ let existingRow: Record<string, unknown> | null = null;
887
+
888
+ if (rowIdField) {
889
+ const loadedRows = await sql<Record<string, unknown>>`
890
+ select *
891
+ from ${sql.table(op.table)}
892
+ where ${sql.ref(rowIdField)} = ${sql.val(op.row_id)}
893
+ limit ${sql.val(1)}
894
+ `.execute(args.ctx.trx);
895
+ const loadedRow = loadedRows.rows[0];
896
+ if (loadedRow && isRecord(loadedRow)) {
897
+ existingRow = loadedRow;
898
+ }
899
+ }
900
+
901
+ const nextPayload = await yjsModule.applyPayload({
902
+ table: op.table,
903
+ rowId: op.row_id,
904
+ payload: op.payload,
905
+ existingRow,
906
+ });
907
+
908
+ if (nextPayload === op.payload) return op;
909
+ return {
910
+ ...op,
911
+ payload: nextPayload,
912
+ };
913
+ },
914
+
915
+ async afterApplyOperation(args) {
916
+ return await materializeAppliedResult(
917
+ yjsModule,
918
+ args.op.table,
919
+ args.applied
920
+ );
921
+ },
922
+
923
+ async transformPullChanges(args) {
924
+ return await yjsModule.transformPullChanges({
925
+ table: args.subscription.table,
926
+ changes: args.changes,
927
+ crdtStateVectors: args.subscription.crdtStateVectors,
928
+ });
929
+ },
930
+ };
931
+ }