@syncular/server 0.0.6-96 → 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,786 @@
1
+ import type {
2
+ BinarySnapshotColumn,
3
+ BinarySnapshotRowsEncoder,
4
+ ScopePattern,
5
+ ScopeValues,
6
+ StoredScopes,
7
+ SyncOperation,
8
+ SyncularErrorCode,
9
+ } from '@syncular/core';
10
+ import { BinarySnapshotTableWriter, collectScopeVars } from '@syncular/core';
11
+ import { sql } from 'kysely';
12
+ import { parseScopes } from './dialect/helpers';
13
+ import type { DbExecutor } from './dialect/types';
14
+ import type {
15
+ ApplyOperationResult,
16
+ EmittedChange,
17
+ ServerApplyOperationContext,
18
+ ServerSnapshotContext,
19
+ ServerTableHandler,
20
+ SyncServerAuth,
21
+ } from './handlers/types';
22
+ import { rowScopesAllowed } from './helpers/scope-authorization';
23
+ import type { SyncCoreDb } from './schema';
24
+
25
+ export const SYNC_CRDT_UPDATES_TABLE = 'sync_crdt_updates';
26
+ export const SYNC_CRDT_CHECKPOINTS_TABLE = 'sync_crdt_checkpoints';
27
+
28
+ type SystemTableName =
29
+ | typeof SYNC_CRDT_UPDATES_TABLE
30
+ | typeof SYNC_CRDT_CHECKPOINTS_TABLE;
31
+
32
+ type RequiredStringField =
33
+ | 'stream_id'
34
+ | 'app_table'
35
+ | 'row_id'
36
+ | 'field_name'
37
+ | 'key_id'
38
+ | 'ciphertext';
39
+
40
+ export interface EncryptedCrdtSystemHandlersOptions<
41
+ DB extends SyncCoreDb = SyncCoreDb,
42
+ Auth extends SyncServerAuth = SyncServerAuth,
43
+ > {
44
+ scopePatterns?: ScopePattern[];
45
+ resolveScopes: (ctx: {
46
+ db: DbExecutor<DB>;
47
+ actorId: string;
48
+ auth: Auth;
49
+ }) => Promise<ScopeValues> | ScopeValues;
50
+ authorizeUpdate?: (args: {
51
+ ctx: ServerApplyOperationContext<DB, Auth>;
52
+ row: EncryptedCrdtUpdateRow;
53
+ }) => Promise<boolean> | boolean;
54
+ authorizeCheckpoint?: (args: {
55
+ ctx: ServerApplyOperationContext<DB, Auth>;
56
+ row: EncryptedCrdtCheckpointRow;
57
+ }) => Promise<boolean> | boolean;
58
+ }
59
+
60
+ export interface EncryptedCrdtUpdateRow {
61
+ partition_id: string;
62
+ stream_id: string;
63
+ app_table: string;
64
+ row_id: string;
65
+ field_name: string;
66
+ update_id: string;
67
+ actor_id: string | null;
68
+ client_id: string | null;
69
+ key_id: string;
70
+ ciphertext: string;
71
+ scopes: StoredScopes;
72
+ }
73
+
74
+ export interface EncryptedCrdtCheckpointRow {
75
+ partition_id: string;
76
+ stream_id: string;
77
+ app_table: string;
78
+ row_id: string;
79
+ field_name: string;
80
+ checkpoint_id: string;
81
+ covers_seq: number;
82
+ actor_id: string | null;
83
+ client_id: string | null;
84
+ key_id: string;
85
+ ciphertext: string;
86
+ scopes: StoredScopes;
87
+ }
88
+
89
+ export interface EncryptedCrdtPruneOptions {
90
+ partitionId?: string;
91
+ streamId?: string;
92
+ pruneCoveredUpdates?: boolean;
93
+ maxCheckpointsPerStream?: number;
94
+ }
95
+
96
+ export interface EncryptedCrdtPruneReport {
97
+ updatesDeleted: number;
98
+ checkpointsDeleted: number;
99
+ }
100
+
101
+ const CRDT_UPDATE_BINARY_COLUMNS = [
102
+ { name: 'seq', type: 'integer' },
103
+ { name: 'partition_id', type: 'string' },
104
+ { name: 'stream_id', type: 'string' },
105
+ { name: 'app_table', type: 'string' },
106
+ { name: 'row_id', type: 'string' },
107
+ { name: 'field_name', type: 'string' },
108
+ { name: 'update_id', type: 'string' },
109
+ { name: 'actor_id', type: 'string', nullable: true },
110
+ { name: 'client_id', type: 'string', nullable: true },
111
+ { name: 'key_id', type: 'string' },
112
+ { name: 'ciphertext', type: 'string' },
113
+ { name: 'scopes', type: 'json' },
114
+ ] satisfies readonly BinarySnapshotColumn[];
115
+
116
+ const CRDT_CHECKPOINT_BINARY_COLUMNS = [
117
+ { name: 'seq', type: 'integer' },
118
+ { name: 'partition_id', type: 'string' },
119
+ { name: 'stream_id', type: 'string' },
120
+ { name: 'app_table', type: 'string' },
121
+ { name: 'row_id', type: 'string' },
122
+ { name: 'field_name', type: 'string' },
123
+ { name: 'checkpoint_id', type: 'string' },
124
+ { name: 'covers_seq', type: 'integer' },
125
+ { name: 'actor_id', type: 'string', nullable: true },
126
+ { name: 'client_id', type: 'string', nullable: true },
127
+ { name: 'key_id', type: 'string' },
128
+ { name: 'ciphertext', type: 'string' },
129
+ { name: 'scopes', type: 'json' },
130
+ ] satisfies readonly BinarySnapshotColumn[];
131
+
132
+ const CRDT_UPDATE_BINARY_ENCODER: BinarySnapshotRowsEncoder = (rows) =>
133
+ encodeEncryptedCrdtUpdateRows(rows);
134
+
135
+ const CRDT_CHECKPOINT_BINARY_ENCODER: BinarySnapshotRowsEncoder = (rows) =>
136
+ encodeEncryptedCrdtCheckpointRows(rows);
137
+
138
+ function createSystemRowScopeAuthorizer<
139
+ DB extends SyncCoreDb,
140
+ Auth extends SyncServerAuth,
141
+ >(options: EncryptedCrdtSystemHandlersOptions<DB, Auth>) {
142
+ const requiredScopeKeys = Array.from(
143
+ collectScopeVars(options.scopePatterns ?? [])
144
+ );
145
+
146
+ return async (
147
+ ctx: ServerApplyOperationContext<DB, Auth>,
148
+ rowScopes: StoredScopes
149
+ ): Promise<boolean> => {
150
+ if (requiredScopeKeys.length === 0) return true;
151
+
152
+ let allowedScopes: ScopeValues;
153
+ try {
154
+ allowedScopes = await options.resolveScopes({
155
+ db: ctx.db,
156
+ actorId: ctx.actorId,
157
+ auth: ctx.auth,
158
+ });
159
+ } catch {
160
+ return false;
161
+ }
162
+
163
+ return rowScopesAllowed({
164
+ rowScopes,
165
+ allowedScopes,
166
+ requiredScopeKeys,
167
+ });
168
+ };
169
+ }
170
+
171
+ export function encryptedCrdtStreamId(args: {
172
+ table: string;
173
+ rowId: string;
174
+ field: string;
175
+ }): string {
176
+ return `${escapeStreamPart(args.table)}:${escapeStreamPart(args.rowId)}:${escapeStreamPart(args.field)}`;
177
+ }
178
+
179
+ export function createEncryptedCrdtSystemHandlers<
180
+ DB extends SyncCoreDb = SyncCoreDb,
181
+ Auth extends SyncServerAuth = SyncServerAuth,
182
+ >(
183
+ options: EncryptedCrdtSystemHandlersOptions<DB, Auth>
184
+ ): ServerTableHandler<DB, Auth>[] {
185
+ return [
186
+ createEncryptedCrdtUpdateHandler(options),
187
+ createEncryptedCrdtCheckpointHandler(options),
188
+ ];
189
+ }
190
+
191
+ export async function pruneEncryptedCrdtSystemRows<DB extends SyncCoreDb>(
192
+ db: DbExecutor<DB>,
193
+ options: EncryptedCrdtPruneOptions = {}
194
+ ): Promise<EncryptedCrdtPruneReport> {
195
+ const partitionId = options.partitionId ?? 'default';
196
+ const streamFilter = options.streamId
197
+ ? sql`and stream_id = ${options.streamId}`
198
+ : sql``;
199
+ const updateStreamFilter = options.streamId
200
+ ? sql`and sync_crdt_updates.stream_id = ${options.streamId}`
201
+ : sql``;
202
+ const checkpointStreamFilter = options.streamId
203
+ ? sql`and sync_crdt_checkpoints.stream_id = ${options.streamId}`
204
+ : sql``;
205
+
206
+ let updatesDeleted = 0;
207
+ if (options.pruneCoveredUpdates !== false) {
208
+ const deleted = await sql`
209
+ delete from sync_crdt_updates
210
+ where partition_id = ${partitionId}
211
+ ${updateStreamFilter}
212
+ and exists (
213
+ select 1
214
+ from sync_crdt_checkpoints
215
+ where sync_crdt_checkpoints.partition_id = sync_crdt_updates.partition_id
216
+ and sync_crdt_checkpoints.stream_id = sync_crdt_updates.stream_id
217
+ and sync_crdt_checkpoints.key_id = sync_crdt_updates.key_id
218
+ and sync_crdt_checkpoints.covers_seq >= sync_crdt_updates.seq
219
+ )
220
+ `.execute(db);
221
+ updatesDeleted = affectedRows(deleted);
222
+ }
223
+
224
+ let checkpointsDeleted = 0;
225
+ if (options.maxCheckpointsPerStream != null) {
226
+ if (
227
+ !Number.isInteger(options.maxCheckpointsPerStream) ||
228
+ options.maxCheckpointsPerStream < 1
229
+ ) {
230
+ throw new Error('maxCheckpointsPerStream must be an integer >= 1');
231
+ }
232
+ const deleted = await sql`
233
+ delete from sync_crdt_checkpoints
234
+ where checkpoint_id in (
235
+ select checkpoint_id
236
+ from (
237
+ select
238
+ checkpoint_id,
239
+ row_number() over (
240
+ partition by partition_id, stream_id, key_id
241
+ order by covers_seq desc, seq desc
242
+ ) as checkpoint_rank
243
+ from sync_crdt_checkpoints
244
+ where partition_id = ${partitionId}
245
+ ${streamFilter}
246
+ ) ranked
247
+ where checkpoint_rank > ${options.maxCheckpointsPerStream}
248
+ )
249
+ and partition_id = ${partitionId}
250
+ ${checkpointStreamFilter}
251
+ `.execute(db);
252
+ checkpointsDeleted = affectedRows(deleted);
253
+ }
254
+
255
+ return { updatesDeleted, checkpointsDeleted };
256
+ }
257
+
258
+ function createEncryptedCrdtUpdateHandler<
259
+ DB extends SyncCoreDb,
260
+ Auth extends SyncServerAuth,
261
+ >(
262
+ options: EncryptedCrdtSystemHandlersOptions<DB, Auth>
263
+ ): ServerTableHandler<DB, Auth> {
264
+ const authorizeRowScopes = createSystemRowScopeAuthorizer(options);
265
+
266
+ return {
267
+ table: SYNC_CRDT_UPDATES_TABLE,
268
+ primaryKeyColumn: 'update_id',
269
+ snapshotBinaryColumns: CRDT_UPDATE_BINARY_COLUMNS,
270
+ snapshotBinaryEncoder: CRDT_UPDATE_BINARY_ENCODER,
271
+ scopePatterns: options.scopePatterns ?? [],
272
+ resolveScopes: async (ctx) => options.resolveScopes(ctx),
273
+ extractScopes: (row) => parseScopes(row.scopes),
274
+ snapshot: (ctx, _params) =>
275
+ snapshotSystemTable(ctx, SYNC_CRDT_UPDATES_TABLE, 'update_id'),
276
+ async applyOperation(ctx, op, opIndex) {
277
+ if (op.table !== SYNC_CRDT_UPDATES_TABLE) {
278
+ return errorResult(
279
+ opIndex,
280
+ `Unknown table: ${op.table}`,
281
+ 'sync.unknown_table'
282
+ );
283
+ }
284
+ if (op.op !== 'upsert') {
285
+ return errorResult(
286
+ opIndex,
287
+ 'Encrypted CRDT updates are append-only',
288
+ 'sync.unsupported_operation'
289
+ );
290
+ }
291
+
292
+ const payload = payloadRecord(op);
293
+ const row = updateRowFromPayload(ctx, op, payload);
294
+ if (!(await authorizeRowScopes(ctx, row.scopes))) {
295
+ return errorResult(opIndex, 'Forbidden', 'sync.forbidden');
296
+ }
297
+ if (options.authorizeUpdate) {
298
+ const allowed = await options.authorizeUpdate({ ctx, row });
299
+ if (!allowed) {
300
+ return errorResult(opIndex, 'Forbidden', 'sync.forbidden');
301
+ }
302
+ }
303
+
304
+ const inserted = await insertSystemRow(
305
+ ctx.trx,
306
+ SYNC_CRDT_UPDATES_TABLE,
307
+ 'update_id',
308
+ row.update_id,
309
+ { ...row }
310
+ );
311
+ if (!inserted) {
312
+ return { result: { opIndex, status: 'applied' }, emittedChanges: [] };
313
+ }
314
+
315
+ return appliedResult(opIndex, SYNC_CRDT_UPDATES_TABLE, row.update_id, {
316
+ ...row,
317
+ seq: inserted.seq,
318
+ });
319
+ },
320
+ };
321
+ }
322
+
323
+ function createEncryptedCrdtCheckpointHandler<
324
+ DB extends SyncCoreDb,
325
+ Auth extends SyncServerAuth,
326
+ >(
327
+ options: EncryptedCrdtSystemHandlersOptions<DB, Auth>
328
+ ): ServerTableHandler<DB, Auth> {
329
+ const authorizeRowScopes = createSystemRowScopeAuthorizer(options);
330
+
331
+ return {
332
+ table: SYNC_CRDT_CHECKPOINTS_TABLE,
333
+ primaryKeyColumn: 'checkpoint_id',
334
+ snapshotBinaryColumns: CRDT_CHECKPOINT_BINARY_COLUMNS,
335
+ snapshotBinaryEncoder: CRDT_CHECKPOINT_BINARY_ENCODER,
336
+ scopePatterns: options.scopePatterns ?? [],
337
+ resolveScopes: async (ctx) => options.resolveScopes(ctx),
338
+ extractScopes: (row) => parseScopes(row.scopes),
339
+ snapshot: (ctx, _params) =>
340
+ snapshotSystemTable(ctx, SYNC_CRDT_CHECKPOINTS_TABLE, 'checkpoint_id'),
341
+ async applyOperation(ctx, op, opIndex) {
342
+ if (op.table !== SYNC_CRDT_CHECKPOINTS_TABLE) {
343
+ return errorResult(
344
+ opIndex,
345
+ `Unknown table: ${op.table}`,
346
+ 'sync.unknown_table'
347
+ );
348
+ }
349
+ if (op.op !== 'upsert') {
350
+ return errorResult(
351
+ opIndex,
352
+ 'Encrypted CRDT checkpoints are append-only',
353
+ 'sync.unsupported_operation'
354
+ );
355
+ }
356
+
357
+ const payload = payloadRecord(op);
358
+ const row = checkpointRowFromPayload(ctx, op, payload);
359
+ if (!(await authorizeRowScopes(ctx, row.scopes))) {
360
+ return errorResult(opIndex, 'Forbidden', 'sync.forbidden');
361
+ }
362
+ if (options.authorizeCheckpoint) {
363
+ const allowed = await options.authorizeCheckpoint({ ctx, row });
364
+ if (!allowed) {
365
+ return errorResult(opIndex, 'Forbidden', 'sync.forbidden');
366
+ }
367
+ }
368
+
369
+ const inserted = await insertSystemRow(
370
+ ctx.trx,
371
+ SYNC_CRDT_CHECKPOINTS_TABLE,
372
+ 'checkpoint_id',
373
+ row.checkpoint_id,
374
+ { ...row }
375
+ );
376
+ if (!inserted) {
377
+ return { result: { opIndex, status: 'applied' }, emittedChanges: [] };
378
+ }
379
+
380
+ return appliedResult(
381
+ opIndex,
382
+ SYNC_CRDT_CHECKPOINTS_TABLE,
383
+ row.checkpoint_id,
384
+ { ...row, seq: inserted.seq }
385
+ );
386
+ },
387
+ };
388
+ }
389
+
390
+ async function snapshotSystemTable<
391
+ DB extends SyncCoreDb,
392
+ Auth extends SyncServerAuth,
393
+ >(
394
+ ctx: ServerSnapshotContext<DB, string, Auth>,
395
+ table: SystemTableName,
396
+ cursorColumn: 'update_id' | 'checkpoint_id'
397
+ ): Promise<{ rows: unknown[]; nextCursor: string | null }> {
398
+ const partitionId = ctx.auth.partitionId ?? 'default';
399
+ const cursor = ctx.cursor;
400
+ const rows = await sql<Record<string, unknown>>`
401
+ select *
402
+ from ${sql.table(table)}
403
+ where partition_id = ${partitionId}
404
+ and (${cursor} is null or ${sql.ref(cursorColumn)} > ${cursor})
405
+ order by ${sql.ref(cursorColumn)} asc
406
+ limit ${ctx.limit + 1}
407
+ `.execute(ctx.db);
408
+
409
+ const matched = rows.rows
410
+ .filter((row) => scopesMatch(parseScopes(row.scopes), ctx.scopeValues))
411
+ .slice(0, ctx.limit);
412
+
413
+ return {
414
+ rows: matched.map(normalizeSystemRowForProtocol),
415
+ nextCursor:
416
+ matched.length === ctx.limit
417
+ ? String(matched[matched.length - 1]?.[cursorColumn] ?? '')
418
+ : null,
419
+ };
420
+ }
421
+
422
+ async function insertSystemRow<DB extends SyncCoreDb>(
423
+ trx: DbExecutor<DB>,
424
+ table: SystemTableName,
425
+ identityColumn: 'update_id' | 'checkpoint_id',
426
+ identity: string,
427
+ row: Record<string, unknown>
428
+ ): Promise<{ seq: number } | null> {
429
+ const insertable = {
430
+ ...row,
431
+ scopes: JSON.stringify(scopesField(row.scopes)),
432
+ };
433
+ const result = await (trx.insertInto(table) as never as any)
434
+ .values(insertable)
435
+ .onConflict((oc: any) =>
436
+ oc.columns(['partition_id', identityColumn]).doNothing()
437
+ )
438
+ .returning(['seq', identityColumn])
439
+ .executeTakeFirst();
440
+ if (result) return { seq: Number(result.seq) };
441
+
442
+ const existing = await sql<{ identity: string }>`
443
+ select ${sql.ref(identityColumn)} as identity
444
+ from ${sql.table(table)}
445
+ where partition_id = ${String(row.partition_id)}
446
+ and ${sql.ref(identityColumn)} = ${identity}
447
+ limit 1
448
+ `.execute(trx);
449
+ if (existing.rows.length > 0) return null;
450
+ throw new Error(`Encrypted CRDT insert did not return ${identityColumn}`);
451
+ }
452
+
453
+ function updateRowFromPayload<
454
+ DB extends SyncCoreDb,
455
+ Auth extends SyncServerAuth,
456
+ >(
457
+ ctx: ServerApplyOperationContext<DB, Auth>,
458
+ op: SyncOperation,
459
+ payload: Record<string, unknown>
460
+ ): EncryptedCrdtUpdateRow {
461
+ return {
462
+ partition_id: ctx.auth.partitionId ?? 'default',
463
+ stream_id: stringField(payload, 'stream_id'),
464
+ app_table: stringField(payload, 'app_table'),
465
+ row_id: stringField(payload, 'row_id'),
466
+ field_name: stringField(payload, 'field_name'),
467
+ update_id: stringField(payload, 'update_id', op.row_id),
468
+ actor_id: ctx.actorId,
469
+ client_id: ctx.clientId,
470
+ key_id: stringField(payload, 'key_id'),
471
+ ciphertext: stringField(payload, 'ciphertext'),
472
+ scopes: scopesField(payload.scopes),
473
+ };
474
+ }
475
+
476
+ function checkpointRowFromPayload<
477
+ DB extends SyncCoreDb,
478
+ Auth extends SyncServerAuth,
479
+ >(
480
+ ctx: ServerApplyOperationContext<DB, Auth>,
481
+ op: SyncOperation,
482
+ payload: Record<string, unknown>
483
+ ): EncryptedCrdtCheckpointRow {
484
+ const coversSeq = Number(payload.covers_seq);
485
+ if (!Number.isInteger(coversSeq) || coversSeq < 0) {
486
+ throw new Error(
487
+ 'Encrypted CRDT checkpoint covers_seq must be a non-negative integer'
488
+ );
489
+ }
490
+ return {
491
+ partition_id: ctx.auth.partitionId ?? 'default',
492
+ stream_id: stringField(payload, 'stream_id'),
493
+ app_table: stringField(payload, 'app_table'),
494
+ row_id: stringField(payload, 'row_id'),
495
+ field_name: stringField(payload, 'field_name'),
496
+ checkpoint_id: stringField(payload, 'checkpoint_id', op.row_id),
497
+ covers_seq: coversSeq,
498
+ actor_id: ctx.actorId,
499
+ client_id: ctx.clientId,
500
+ key_id: stringField(payload, 'key_id'),
501
+ ciphertext: stringField(payload, 'ciphertext'),
502
+ scopes: scopesField(payload.scopes),
503
+ };
504
+ }
505
+
506
+ function appliedResult(
507
+ opIndex: number,
508
+ table: SystemTableName,
509
+ rowId: string,
510
+ row: Record<string, unknown>
511
+ ): ApplyOperationResult {
512
+ const emitted: EmittedChange = {
513
+ table,
514
+ row_id: rowId,
515
+ op: 'upsert',
516
+ row_json: normalizeSystemRowForProtocol(row),
517
+ row_version: numberOrNull(row.seq),
518
+ scopes: scopesField(row.scopes),
519
+ };
520
+ return {
521
+ result: { opIndex, status: 'applied' },
522
+ emittedChanges: [emitted],
523
+ };
524
+ }
525
+
526
+ function errorResult(
527
+ opIndex: number,
528
+ error: string,
529
+ code: SyncularErrorCode
530
+ ): ApplyOperationResult {
531
+ return {
532
+ result: { opIndex, status: 'error', error, code, retriable: false },
533
+ emittedChanges: [],
534
+ };
535
+ }
536
+
537
+ function payloadRecord(op: SyncOperation): Record<string, unknown> {
538
+ if (
539
+ !op.payload ||
540
+ typeof op.payload !== 'object' ||
541
+ Array.isArray(op.payload)
542
+ ) {
543
+ throw new Error('Encrypted CRDT operation payload must be an object');
544
+ }
545
+ return op.payload as Record<string, unknown>;
546
+ }
547
+
548
+ function stringField(
549
+ payload: Record<string, unknown>,
550
+ field: RequiredStringField | 'update_id' | 'checkpoint_id',
551
+ fallback?: string
552
+ ): string {
553
+ const value = payload[field] ?? fallback;
554
+ if (typeof value !== 'string' || value.length === 0) {
555
+ throw new Error(
556
+ `Encrypted CRDT payload field ${field} must be a non-empty string`
557
+ );
558
+ }
559
+ return value;
560
+ }
561
+
562
+ function scopesField(value: unknown): StoredScopes {
563
+ const parsed = parseScopes(value);
564
+ return parsed;
565
+ }
566
+
567
+ function scopesMatch(
568
+ stored: StoredScopes,
569
+ requested: Record<string, unknown>
570
+ ): boolean {
571
+ for (const [key, value] of Object.entries(requested)) {
572
+ if (Array.isArray(value)) {
573
+ if (value.length === 0 || !value.includes(stored[key])) return false;
574
+ continue;
575
+ }
576
+ if (stored[key] !== value) return false;
577
+ }
578
+ return true;
579
+ }
580
+
581
+ function normalizeSystemRowForProtocol(
582
+ row: Record<string, unknown>
583
+ ): Record<string, unknown> {
584
+ return {
585
+ ...row,
586
+ scopes: scopesField(row.scopes),
587
+ seq: numberOrNull(row.seq),
588
+ };
589
+ }
590
+
591
+ function numberOrNull(value: unknown): number | null {
592
+ const number = Number(value);
593
+ return Number.isFinite(number) ? number : null;
594
+ }
595
+
596
+ function affectedRows(result: {
597
+ numAffectedRows?: bigint | number | string;
598
+ }): number {
599
+ return Number(result.numAffectedRows ?? 0);
600
+ }
601
+
602
+ function encodeEncryptedCrdtUpdateRows(rows: readonly unknown[]): Uint8Array {
603
+ const writer = new BinarySnapshotTableWriter(
604
+ SYNC_CRDT_UPDATES_TABLE,
605
+ CRDT_UPDATE_BINARY_COLUMNS,
606
+ rows.length
607
+ );
608
+ for (const value of rows) {
609
+ const row = recordRow(value);
610
+ writer.beginRow();
611
+ writer.writeInteger(
612
+ rowInteger(row, 'seq'),
613
+ 'binary snapshot sync_crdt_updates.seq'
614
+ );
615
+ writer.writeString(
616
+ rowString(row, 'partition_id'),
617
+ 'binary snapshot sync_crdt_updates.partition_id'
618
+ );
619
+ writer.writeString(
620
+ rowString(row, 'stream_id'),
621
+ 'binary snapshot sync_crdt_updates.stream_id'
622
+ );
623
+ writer.writeString(
624
+ rowString(row, 'app_table'),
625
+ 'binary snapshot sync_crdt_updates.app_table'
626
+ );
627
+ writer.writeString(
628
+ rowString(row, 'row_id'),
629
+ 'binary snapshot sync_crdt_updates.row_id'
630
+ );
631
+ writer.writeString(
632
+ rowString(row, 'field_name'),
633
+ 'binary snapshot sync_crdt_updates.field_name'
634
+ );
635
+ writer.writeString(
636
+ rowString(row, 'update_id'),
637
+ 'binary snapshot sync_crdt_updates.update_id'
638
+ );
639
+ writeNullableString(
640
+ writer,
641
+ 7,
642
+ row.actor_id,
643
+ 'binary snapshot sync_crdt_updates.actor_id'
644
+ );
645
+ writeNullableString(
646
+ writer,
647
+ 8,
648
+ row.client_id,
649
+ 'binary snapshot sync_crdt_updates.client_id'
650
+ );
651
+ writer.writeString(
652
+ rowString(row, 'key_id'),
653
+ 'binary snapshot sync_crdt_updates.key_id'
654
+ );
655
+ writer.writeString(
656
+ rowString(row, 'ciphertext'),
657
+ 'binary snapshot sync_crdt_updates.ciphertext'
658
+ );
659
+ writer.writeJson(
660
+ scopesField(row.scopes),
661
+ 'binary snapshot sync_crdt_updates.scopes'
662
+ );
663
+ }
664
+ return writer.finish();
665
+ }
666
+
667
+ function encodeEncryptedCrdtCheckpointRows(
668
+ rows: readonly unknown[]
669
+ ): Uint8Array {
670
+ const writer = new BinarySnapshotTableWriter(
671
+ SYNC_CRDT_CHECKPOINTS_TABLE,
672
+ CRDT_CHECKPOINT_BINARY_COLUMNS,
673
+ rows.length
674
+ );
675
+ for (const value of rows) {
676
+ const row = recordRow(value);
677
+ writer.beginRow();
678
+ writer.writeInteger(
679
+ rowInteger(row, 'seq'),
680
+ 'binary snapshot sync_crdt_checkpoints.seq'
681
+ );
682
+ writer.writeString(
683
+ rowString(row, 'partition_id'),
684
+ 'binary snapshot sync_crdt_checkpoints.partition_id'
685
+ );
686
+ writer.writeString(
687
+ rowString(row, 'stream_id'),
688
+ 'binary snapshot sync_crdt_checkpoints.stream_id'
689
+ );
690
+ writer.writeString(
691
+ rowString(row, 'app_table'),
692
+ 'binary snapshot sync_crdt_checkpoints.app_table'
693
+ );
694
+ writer.writeString(
695
+ rowString(row, 'row_id'),
696
+ 'binary snapshot sync_crdt_checkpoints.row_id'
697
+ );
698
+ writer.writeString(
699
+ rowString(row, 'field_name'),
700
+ 'binary snapshot sync_crdt_checkpoints.field_name'
701
+ );
702
+ writer.writeString(
703
+ rowString(row, 'checkpoint_id'),
704
+ 'binary snapshot sync_crdt_checkpoints.checkpoint_id'
705
+ );
706
+ writer.writeInteger(
707
+ rowInteger(row, 'covers_seq'),
708
+ 'binary snapshot sync_crdt_checkpoints.covers_seq'
709
+ );
710
+ writeNullableString(
711
+ writer,
712
+ 8,
713
+ row.actor_id,
714
+ 'binary snapshot sync_crdt_checkpoints.actor_id'
715
+ );
716
+ writeNullableString(
717
+ writer,
718
+ 9,
719
+ row.client_id,
720
+ 'binary snapshot sync_crdt_checkpoints.client_id'
721
+ );
722
+ writer.writeString(
723
+ rowString(row, 'key_id'),
724
+ 'binary snapshot sync_crdt_checkpoints.key_id'
725
+ );
726
+ writer.writeString(
727
+ rowString(row, 'ciphertext'),
728
+ 'binary snapshot sync_crdt_checkpoints.ciphertext'
729
+ );
730
+ writer.writeJson(
731
+ scopesField(row.scopes),
732
+ 'binary snapshot sync_crdt_checkpoints.scopes'
733
+ );
734
+ }
735
+ return writer.finish();
736
+ }
737
+
738
+ function recordRow(value: unknown): Record<string, unknown> {
739
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
740
+ throw new Error('Encrypted CRDT binary rows must be objects');
741
+ }
742
+ return value as Record<string, unknown>;
743
+ }
744
+
745
+ function rowString(row: Record<string, unknown>, field: string): string {
746
+ const value = row[field];
747
+ if (typeof value !== 'string' || value.length === 0) {
748
+ throw new Error(
749
+ `Encrypted CRDT binary row field ${field} must be a non-empty string`
750
+ );
751
+ }
752
+ return value;
753
+ }
754
+
755
+ function rowInteger(
756
+ row: Record<string, unknown>,
757
+ field: string
758
+ ): number | bigint {
759
+ const value = row[field];
760
+ if (typeof value === 'bigint') return value;
761
+ if (typeof value === 'number' && Number.isSafeInteger(value)) return value;
762
+ if (typeof value === 'string' && /^-?\d+$/.test(value)) return BigInt(value);
763
+ throw new Error(
764
+ `Encrypted CRDT binary row field ${field} must be an integer`
765
+ );
766
+ }
767
+
768
+ function writeNullableString(
769
+ writer: BinarySnapshotTableWriter,
770
+ columnIndex: number,
771
+ value: unknown,
772
+ label: string
773
+ ): void {
774
+ if (value == null) {
775
+ writer.writeNull(columnIndex);
776
+ return;
777
+ }
778
+ if (typeof value !== 'string') {
779
+ throw new Error(`${label} expected string`);
780
+ }
781
+ writer.writeString(value, label);
782
+ }
783
+
784
+ function escapeStreamPart(value: string): string {
785
+ return encodeURIComponent(value);
786
+ }