@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
package/src/sqlite3.ts ADDED
@@ -0,0 +1,137 @@
1
+ /**
2
+ * @syncular/server/sqlite3 - node-sqlite3 dialect for sync
3
+ *
4
+ * Provides a Kysely dialect for the callback-based `sqlite3` npm package.
5
+ * SQLite-compatible — use with @syncular/server/sqlite.
6
+ */
7
+
8
+ import type {
9
+ CompiledQuery,
10
+ DatabaseConnection,
11
+ Dialect,
12
+ QueryResult,
13
+ } from 'kysely';
14
+ import { BaseSqliteDialect, BaseSqliteDriver } from 'kysely-generic-sqlite';
15
+ import sqlite3 from 'sqlite3';
16
+
17
+ export interface Sqlite3PathOptions {
18
+ /** Path to SQLite database file, or ':memory:' for in-memory */
19
+ path: string;
20
+ }
21
+
22
+ export interface Sqlite3InstanceOptions {
23
+ /** An existing sqlite3.Database instance */
24
+ database: sqlite3.Database;
25
+ }
26
+
27
+ export type Sqlite3Options = Sqlite3PathOptions | Sqlite3InstanceOptions;
28
+
29
+ /**
30
+ * Create the sqlite3 dialect directly.
31
+ */
32
+ export function createSqlite3Dialect(options: Sqlite3Options): Dialect {
33
+ return new BaseSqliteDialect(() => new Sqlite3Driver(options));
34
+ }
35
+
36
+ class Sqlite3Driver extends BaseSqliteDriver {
37
+ #db: sqlite3.Database | undefined;
38
+
39
+ constructor(options: Sqlite3Options) {
40
+ super(async () => {
41
+ this.#db = await resolveSqlite3Database(options);
42
+ this.conn = new Sqlite3Connection(this.#db);
43
+ });
44
+ }
45
+
46
+ async destroy(): Promise<void> {
47
+ const db = this.#db;
48
+ this.#db = undefined;
49
+ if (!db) return;
50
+
51
+ await new Promise<void>((resolve, reject) => {
52
+ db.close((err) => {
53
+ if (err) {
54
+ reject(err);
55
+ return;
56
+ }
57
+ resolve();
58
+ });
59
+ });
60
+ }
61
+ }
62
+
63
+ async function resolveSqlite3Database(
64
+ options: Sqlite3Options
65
+ ): Promise<sqlite3.Database> {
66
+ if ('database' in options) {
67
+ return options.database;
68
+ }
69
+
70
+ return new Promise<sqlite3.Database>((resolve, reject) => {
71
+ const db = new sqlite3.Database(options.path, (err) => {
72
+ if (err) {
73
+ reject(err);
74
+ return;
75
+ }
76
+ resolve(db);
77
+ });
78
+ });
79
+ }
80
+
81
+ class Sqlite3Connection implements DatabaseConnection {
82
+ readonly #db: sqlite3.Database;
83
+
84
+ constructor(db: sqlite3.Database) {
85
+ this.#db = db;
86
+ }
87
+
88
+ async executeQuery<R>(compiledQuery: CompiledQuery): Promise<QueryResult<R>> {
89
+ const { sql, parameters } = compiledQuery;
90
+ const params = [...parameters];
91
+
92
+ const hasReturning = /\breturning\b/i.test(sql);
93
+ const isSelectLike = /^\s*(select|pragma|explain|with)\b/i.test(sql);
94
+ const isInsert = /^\s*(insert|replace)\b/i.test(sql);
95
+
96
+ if (isSelectLike || hasReturning) {
97
+ return new Promise<QueryResult<R>>((resolve, reject) => {
98
+ this.#db.all(sql, params, (err: Error | null, rows: R[]) => {
99
+ if (err) {
100
+ reject(err);
101
+ return;
102
+ }
103
+
104
+ const normalizedRows = rows ?? [];
105
+ resolve({
106
+ rows: normalizedRows,
107
+ ...(hasReturning
108
+ ? { numAffectedRows: BigInt(normalizedRows.length) }
109
+ : {}),
110
+ });
111
+ });
112
+ });
113
+ }
114
+
115
+ return new Promise<QueryResult<R>>((resolve, reject) => {
116
+ this.#db.run(sql, params, function onRun(err: Error | null) {
117
+ if (err) {
118
+ reject(err);
119
+ return;
120
+ }
121
+
122
+ resolve({
123
+ rows: [],
124
+ numAffectedRows: BigInt(this.changes),
125
+ ...(isInsert ? { insertId: BigInt(this.lastID) } : {}),
126
+ });
127
+ });
128
+ });
129
+ }
130
+
131
+ streamQuery<R>(
132
+ _compiledQuery: CompiledQuery,
133
+ _chunkSize?: number
134
+ ): AsyncIterableIterator<QueryResult<R>> {
135
+ throw new Error('sqlite3 driver does not support streaming');
136
+ }
137
+ }
package/src/stats.ts CHANGED
@@ -4,23 +4,12 @@
4
4
 
5
5
  import type { Kysely, SelectQueryBuilder, SqlBool } from 'kysely';
6
6
  import { sql } from 'kysely';
7
+ import { coerceNumber } from './dialect/helpers';
7
8
  import type { SyncCoreDb } from './schema';
8
9
 
9
10
  // biome-ignore lint/complexity/noBannedTypes: Kysely uses `{}` as the initial "no selected columns yet" marker.
10
11
  type EmptySelection = {};
11
12
 
12
- function coerceNumber(value: unknown): number | null {
13
- if (value === null || value === undefined) return null;
14
- if (typeof value === 'number') return Number.isFinite(value) ? value : null;
15
- if (typeof value === 'bigint')
16
- return Number.isFinite(Number(value)) ? Number(value) : null;
17
- if (typeof value === 'string') {
18
- const n = Number(value);
19
- return Number.isFinite(n) ? n : null;
20
- }
21
- return null;
22
- }
23
-
24
13
  export interface SyncStats {
25
14
  commitCount: number;
26
15
  changeCount: number;
@@ -30,6 +19,35 @@ export interface SyncStats {
30
19
  activeClientCount: number;
31
20
  minActiveClientCursor: number | null;
32
21
  maxActiveClientCursor: number | null;
22
+ snapshotChunkCount: number;
23
+ snapshotChunkBytes: number;
24
+ expiredSnapshotChunkCount: number;
25
+ expiredSnapshotChunkBytes: number;
26
+ snapshotArtifactCount: number;
27
+ snapshotArtifactBytes: number;
28
+ expiredSnapshotArtifactCount: number;
29
+ expiredSnapshotArtifactBytes: number;
30
+ }
31
+
32
+ interface CachePressureRow {
33
+ total_count: unknown;
34
+ total_bytes: unknown;
35
+ expired_count: unknown;
36
+ expired_bytes: unknown;
37
+ }
38
+
39
+ function mapCachePressure(row: CachePressureRow | undefined): {
40
+ count: number;
41
+ bytes: number;
42
+ expiredCount: number;
43
+ expiredBytes: number;
44
+ } {
45
+ return {
46
+ count: coerceNumber(row?.total_count) ?? 0,
47
+ bytes: coerceNumber(row?.total_bytes) ?? 0,
48
+ expiredCount: coerceNumber(row?.expired_count) ?? 0,
49
+ expiredBytes: coerceNumber(row?.expired_bytes) ?? 0,
50
+ };
33
51
  }
34
52
 
35
53
  export async function readSyncStats<DB extends SyncCoreDb>(
@@ -41,6 +59,7 @@ export async function readSyncStats<DB extends SyncCoreDb>(
41
59
 
42
60
  const activeWindowMs = options.activeWindowMs ?? 14 * 24 * 60 * 60 * 1000;
43
61
  const cutoffIso = new Date(Date.now() - activeWindowMs).toISOString();
62
+ const nowIso = new Date().toISOString();
44
63
  const partitionId = options.partitionId;
45
64
 
46
65
  let commitQuery = (
@@ -97,13 +116,49 @@ export async function readSyncStats<DB extends SyncCoreDb>(
97
116
  );
98
117
  }
99
118
 
100
- const [commitRow, changeRow, clientRow, activeClientRow] = await Promise.all([
119
+ const partitionFilter = partitionId
120
+ ? sql`where partition_id = ${partitionId}`
121
+ : sql``;
122
+
123
+ const [
124
+ commitRow,
125
+ changeRow,
126
+ clientRow,
127
+ activeClientRow,
128
+ chunkPressureRow,
129
+ artifactPressureRow,
130
+ ] = await Promise.all([
101
131
  commitQuery.executeTakeFirst(),
102
132
  changeQuery.executeTakeFirst(),
103
133
  clientQuery.executeTakeFirst(),
104
134
  activeClientQuery.executeTakeFirst(),
135
+ sql<CachePressureRow>`
136
+ select
137
+ count(*) as total_count,
138
+ coalesce(sum(byte_length), 0) as total_bytes,
139
+ coalesce(sum(case when expires_at <= ${nowIso} then 1 else 0 end), 0) as expired_count,
140
+ coalesce(sum(case when expires_at <= ${nowIso} then byte_length else 0 end), 0) as expired_bytes
141
+ from ${sql.table('sync_snapshot_chunks')}
142
+ ${partitionFilter}
143
+ `
144
+ .execute(db)
145
+ .then((result) => result.rows[0]),
146
+ sql<CachePressureRow>`
147
+ select
148
+ count(*) as total_count,
149
+ coalesce(sum(byte_length), 0) as total_bytes,
150
+ coalesce(sum(case when expires_at <= ${nowIso} then 1 else 0 end), 0) as expired_count,
151
+ coalesce(sum(case when expires_at <= ${nowIso} then byte_length else 0 end), 0) as expired_bytes
152
+ from ${sql.table('sync_snapshot_artifacts')}
153
+ ${partitionFilter}
154
+ `
155
+ .execute(db)
156
+ .then((result) => result.rows[0]),
105
157
  ]);
106
158
 
159
+ const chunkPressure = mapCachePressure(chunkPressureRow);
160
+ const artifactPressure = mapCachePressure(artifactPressureRow);
161
+
107
162
  return {
108
163
  commitCount: coerceNumber(commitRow?.commitCount) ?? 0,
109
164
  changeCount: coerceNumber(changeRow?.changeCount) ?? 0,
@@ -113,5 +168,13 @@ export async function readSyncStats<DB extends SyncCoreDb>(
113
168
  activeClientCount: coerceNumber(activeClientRow?.activeClientCount) ?? 0,
114
169
  minActiveClientCursor: coerceNumber(activeClientRow?.minActiveClientCursor),
115
170
  maxActiveClientCursor: coerceNumber(activeClientRow?.maxActiveClientCursor),
171
+ snapshotChunkCount: chunkPressure.count,
172
+ snapshotChunkBytes: chunkPressure.bytes,
173
+ expiredSnapshotChunkCount: chunkPressure.expiredCount,
174
+ expiredSnapshotChunkBytes: chunkPressure.expiredBytes,
175
+ snapshotArtifactCount: artifactPressure.count,
176
+ snapshotArtifactBytes: artifactPressure.bytes,
177
+ expiredSnapshotArtifactCount: artifactPressure.expiredCount,
178
+ expiredSnapshotArtifactBytes: artifactPressure.expiredBytes,
116
179
  };
117
180
  }
@@ -37,6 +37,11 @@ export interface ScopeCacheBackend {
37
37
  get<DB extends SyncCoreDb, Auth extends SyncServerAuth>(
38
38
  args: ScopeCacheContext<DB, Auth>
39
39
  ): Promise<ScopeValues | null>;
40
+ getOrResolve?<DB extends SyncCoreDb, Auth extends SyncServerAuth>(
41
+ args: ScopeCacheContext<DB, Auth> & {
42
+ load: () => Promise<ScopeValues | null>;
43
+ }
44
+ ): Promise<ScopeValues | null>;
40
45
  set<DB extends SyncCoreDb, Auth extends SyncServerAuth>(
41
46
  args: ScopeCacheSetContext<DB, Auth>
42
47
  ): Promise<void>;
@@ -117,6 +122,10 @@ export function createMemoryScopeCache(
117
122
  options?.maxEntries ?? DEFAULT_MEMORY_SCOPE_CACHE_MAX_ENTRIES;
118
123
  const now = options?.now ?? Date.now;
119
124
  const buckets = new WeakMap<object, Map<string, MemoryScopeCacheEntry>>();
125
+ const inflightByDb = new WeakMap<
126
+ object,
127
+ Map<string, Promise<ScopeValues | null>>
128
+ >();
120
129
 
121
130
  function getBucket(db: object): Map<string, MemoryScopeCacheEntry> {
122
131
  const existing = buckets.get(db);
@@ -128,6 +137,18 @@ export function createMemoryScopeCache(
128
137
  return created;
129
138
  }
130
139
 
140
+ function getInflightBucket(
141
+ db: object
142
+ ): Map<string, Promise<ScopeValues | null>> {
143
+ const existing = inflightByDb.get(db);
144
+ if (existing) {
145
+ return existing;
146
+ }
147
+ const created = new Map<string, Promise<ScopeValues | null>>();
148
+ inflightByDb.set(db, created);
149
+ return created;
150
+ }
151
+
131
152
  function evictOldest(bucket: Map<string, MemoryScopeCacheEntry>): void {
132
153
  while (bucket.size > maxEntries) {
133
154
  const oldestKey = bucket.keys().next().value;
@@ -155,6 +176,43 @@ export function createMemoryScopeCache(
155
176
 
156
177
  return cloneScopeValues(entry.scopes);
157
178
  },
179
+ async getOrResolve(args) {
180
+ const cached = await this.get(args);
181
+ if (cached !== null) {
182
+ return cached;
183
+ }
184
+
185
+ const inflightBucket = getInflightBucket(args.db);
186
+ const inflight = inflightBucket.get(args.cacheKey);
187
+ if (inflight) {
188
+ const resolved = await inflight;
189
+ return resolved ? cloneScopeValues(resolved) : null;
190
+ }
191
+
192
+ const pending = args
193
+ .load()
194
+ .then(async (resolved) => {
195
+ if (resolved !== null && ttlMs > 0) {
196
+ const bucket = getBucket(args.db);
197
+ if (bucket.has(args.cacheKey)) {
198
+ bucket.delete(args.cacheKey);
199
+ }
200
+ bucket.set(args.cacheKey, {
201
+ scopes: cloneScopeValues(resolved),
202
+ expiresAt: now() + ttlMs,
203
+ });
204
+ evictOldest(bucket);
205
+ }
206
+ return resolved;
207
+ })
208
+ .finally(() => {
209
+ inflightBucket.delete(args.cacheKey);
210
+ });
211
+
212
+ inflightBucket.set(args.cacheKey, pending);
213
+ const resolved = await pending;
214
+ return resolved ? cloneScopeValues(resolved) : null;
215
+ },
158
216
  async set(args) {
159
217
  const bucket = getBucket(args.db);
160
218
  if (ttlMs <= 0) {
@@ -1,13 +1,10 @@
1
1
  import {
2
- extractScopeVars,
2
+ collectScopeVars,
3
3
  type ScopeValues,
4
4
  type SyncSubscriptionRequest,
5
5
  } from '@syncular/core';
6
6
  import type { Kysely } from 'kysely';
7
- import {
8
- getServerHandler,
9
- type ServerHandlerCollection,
10
- } from '../handlers/collection';
7
+ import type { ServerHandlerCollection } from '../handlers/collection';
11
8
  import type { SyncServerAuth } from '../handlers/types';
12
9
  import type { SyncCoreDb } from '../schema';
13
10
  import { createDefaultScopeCacheKey, type ScopeCacheBackend } from './cache';
@@ -29,6 +26,8 @@ export interface ResolvedSubscription {
29
26
  params: Record<string, unknown> | undefined;
30
27
  cursor: number;
31
28
  bootstrapState?: SyncSubscriptionRequest['bootstrapState'];
29
+ verifiedRoot?: string;
30
+ crdtStateVectors: SyncSubscriptionRequest['crdtStateVectors'];
32
31
  status: 'active' | 'revoked';
33
32
  }
34
33
 
@@ -92,19 +91,6 @@ function scopesEmpty(scopes: ScopeValues): boolean {
92
91
  return true;
93
92
  }
94
93
 
95
- /**
96
- * Collect valid scope keys from handler scope patterns.
97
- */
98
- function collectScopeKeys(scopePatterns: readonly string[]): Set<string> {
99
- const keys = new Set<string>();
100
- for (const pattern of scopePatterns) {
101
- for (const key of extractScopeVars(pattern)) {
102
- keys.add(key);
103
- }
104
- }
105
- return keys;
106
- }
107
-
108
94
  function validateScopeKeys(args: {
109
95
  scopeValues: ScopeValues;
110
96
  validScopeKeys: Set<string>;
@@ -166,14 +152,14 @@ export async function resolveEffectiveScopesForSubscriptions<
166
152
  );
167
153
  }
168
154
 
169
- const handler = getServerHandler(args.handlers, sub.table);
155
+ const handler = args.handlers.byTable.get(sub.table);
170
156
  if (!handler) {
171
157
  throw new InvalidSubscriptionScopeError(
172
158
  `Unknown table: ${sub.table} for subscription ${sub.id}`
173
159
  );
174
160
  }
175
161
 
176
- const validScopeKeys = collectScopeKeys(handler.scopePatterns);
162
+ const validScopeKeys = collectScopeVars(handler.scopePatterns);
177
163
  const requested = sub.scopes ?? {};
178
164
  validateScopeKeys({
179
165
  scopeValues: requested,
@@ -193,72 +179,101 @@ export async function resolveEffectiveScopesForSubscriptions<
193
179
  if (requestScopeCache.has(scopeCacheKey)) {
194
180
  allowed = requestScopeCache.get(scopeCacheKey) ?? null;
195
181
  } else {
196
- allowed = null;
197
- let sharedCacheHit = false;
182
+ let resolveFailed = false;
198
183
 
199
- if (args.scopeCache) {
184
+ const loadAllowedScopes = async (): Promise<ScopeValues> => {
200
185
  try {
201
- const cachedAllowed = await args.scopeCache.get({
186
+ return await handler.resolveScopes({
202
187
  db: args.db,
188
+ actorId: args.auth.actorId,
203
189
  auth: args.auth,
204
- table: sub.table,
205
- cacheKey: scopeCacheKey,
206
190
  });
207
- if (cachedAllowed !== null) {
208
- allowed = cachedAllowed;
209
- sharedCacheHit = true;
210
- }
211
- } catch (cacheErr) {
191
+ } catch (resolveErr) {
192
+ resolveFailed = true;
212
193
  console.error(
213
- `[scopeCache.get] Failed for table ${sub.table}, subscription ${sub.id}:`,
214
- cacheErr
194
+ `[resolveScopes] Failed for table ${sub.table}, subscription ${sub.id}:`,
195
+ resolveErr
215
196
  );
197
+ throw resolveErr;
216
198
  }
217
- }
199
+ };
218
200
 
219
- if (!sharedCacheHit) {
201
+ if (args.scopeCache?.getOrResolve) {
220
202
  try {
221
- allowed = await handler.resolveScopes({
203
+ allowed = await args.scopeCache.getOrResolve({
222
204
  db: args.db,
223
- actorId: args.auth.actorId,
224
205
  auth: args.auth,
225
- });
226
- } catch (resolveErr) {
227
- // Scope resolution failed - mark subscription as revoked
228
- // rather than failing the entire pull
229
- console.error(
230
- `[resolveScopes] Failed for table ${sub.table}, subscription ${sub.id}:`,
231
- resolveErr
232
- );
233
- requestScopeCache.set(scopeCacheKey, null);
234
- out.push({
235
- id: sub.id,
236
206
  table: sub.table,
237
- scopes: {},
238
- params: sub.params,
239
- cursor: sub.cursor,
240
- bootstrapState: sub.bootstrapState ?? null,
241
- status: 'revoked',
207
+ cacheKey: scopeCacheKey,
208
+ load: loadAllowedScopes,
242
209
  });
243
- continue;
210
+ } catch {
211
+ allowed = null;
244
212
  }
213
+ } else {
214
+ allowed = null;
215
+ let sharedCacheHit = false;
245
216
 
246
- if (args.scopeCache && allowed !== null) {
217
+ if (args.scopeCache) {
247
218
  try {
248
- await args.scopeCache.set({
219
+ const cachedAllowed = await args.scopeCache.get({
249
220
  db: args.db,
250
221
  auth: args.auth,
251
222
  table: sub.table,
252
223
  cacheKey: scopeCacheKey,
253
- scopes: allowed,
254
224
  });
225
+ if (cachedAllowed !== null) {
226
+ allowed = cachedAllowed;
227
+ sharedCacheHit = true;
228
+ }
255
229
  } catch (cacheErr) {
256
230
  console.error(
257
- `[scopeCache.set] Failed for table ${sub.table}, subscription ${sub.id}:`,
231
+ `[scopeCache.get] Failed for table ${sub.table}, subscription ${sub.id}:`,
258
232
  cacheErr
259
233
  );
260
234
  }
261
235
  }
236
+
237
+ if (!sharedCacheHit) {
238
+ try {
239
+ allowed = await loadAllowedScopes();
240
+ } catch {
241
+ allowed = null;
242
+ }
243
+
244
+ if (args.scopeCache && allowed !== null) {
245
+ try {
246
+ await args.scopeCache.set({
247
+ db: args.db,
248
+ auth: args.auth,
249
+ table: sub.table,
250
+ cacheKey: scopeCacheKey,
251
+ scopes: allowed,
252
+ });
253
+ } catch (cacheErr) {
254
+ console.error(
255
+ `[scopeCache.set] Failed for table ${sub.table}, subscription ${sub.id}:`,
256
+ cacheErr
257
+ );
258
+ }
259
+ }
260
+ }
261
+ }
262
+
263
+ if (resolveFailed) {
264
+ requestScopeCache.set(scopeCacheKey, null);
265
+ out.push({
266
+ id: sub.id,
267
+ table: sub.table,
268
+ scopes: {},
269
+ params: sub.params,
270
+ cursor: sub.cursor,
271
+ bootstrapState: sub.bootstrapState ?? null,
272
+ verifiedRoot: sub.verifiedRoot,
273
+ crdtStateVectors: sub.crdtStateVectors,
274
+ status: 'revoked',
275
+ });
276
+ continue;
262
277
  }
263
278
 
264
279
  requestScopeCache.set(scopeCacheKey, allowed);
@@ -272,6 +287,8 @@ export async function resolveEffectiveScopesForSubscriptions<
272
287
  params: sub.params,
273
288
  cursor: sub.cursor,
274
289
  bootstrapState: sub.bootstrapState ?? null,
290
+ verifiedRoot: sub.verifiedRoot,
291
+ crdtStateVectors: sub.crdtStateVectors,
275
292
  status: 'revoked',
276
293
  });
277
294
  continue;
@@ -288,6 +305,26 @@ export async function resolveEffectiveScopesForSubscriptions<
288
305
  // Intersect with requested scopes
289
306
  const effective = intersectScopes(requested, allowed);
290
307
 
308
+ // If a requested scope key lost all access after intersection,
309
+ // treat the subscription as revoked to avoid partially-scoped leaks.
310
+ const missingRequestedKey = Object.keys(requested).some(
311
+ (key) => !Object.hasOwn(effective, key)
312
+ );
313
+ if (missingRequestedKey) {
314
+ out.push({
315
+ id: sub.id,
316
+ table: sub.table,
317
+ scopes: {},
318
+ params: sub.params,
319
+ cursor: sub.cursor,
320
+ bootstrapState: sub.bootstrapState ?? null,
321
+ verifiedRoot: sub.verifiedRoot,
322
+ crdtStateVectors: sub.crdtStateVectors,
323
+ status: 'revoked',
324
+ });
325
+ continue;
326
+ }
327
+
291
328
  if (scopesEmpty(effective)) {
292
329
  out.push({
293
330
  id: sub.id,
@@ -296,6 +333,8 @@ export async function resolveEffectiveScopesForSubscriptions<
296
333
  params: sub.params,
297
334
  cursor: sub.cursor,
298
335
  bootstrapState: sub.bootstrapState ?? null,
336
+ verifiedRoot: sub.verifiedRoot,
337
+ crdtStateVectors: sub.crdtStateVectors,
299
338
  status: 'revoked',
300
339
  });
301
340
  continue;
@@ -308,6 +347,8 @@ export async function resolveEffectiveScopesForSubscriptions<
308
347
  params: sub.params,
309
348
  cursor: sub.cursor,
310
349
  bootstrapState: sub.bootstrapState ?? null,
350
+ verifiedRoot: sub.verifiedRoot,
351
+ crdtStateVectors: sub.crdtStateVectors,
311
352
  status: 'active',
312
353
  });
313
354
  }
package/src/sync.ts CHANGED
@@ -3,11 +3,13 @@ import type {
3
3
  ColumnCodecSource,
4
4
  ScopeDefinition,
5
5
  } from '@syncular/core';
6
+ import { registerTableOrThrow } from '@syncular/core';
6
7
  import {
7
8
  type CreateServerHandlerOptions,
8
9
  createServerHandler,
9
10
  } from './handlers';
10
11
  import type { ServerTableHandler, SyncServerAuth } from './handlers/types';
12
+ import type { SyncServerPushPlugin } from './plugins/types';
11
13
  import type { SyncCoreDb } from './schema';
12
14
 
13
15
  type SharedTableName<ServerDB, ClientDB> = keyof ServerDB &
@@ -31,6 +33,7 @@ export interface ServerSyncConfig<
31
33
  > {
32
34
  authenticate: (request: Request) => Promise<Auth | null> | Auth | null;
33
35
  handlers: ServerTableHandler<ServerDB, Auth>[];
36
+ plugins?: SyncServerPushPlugin<ServerDB, Auth>[];
34
37
  }
35
38
 
36
39
  export interface DefineServerSyncOptions<Auth extends SyncServerAuth> {
@@ -54,6 +57,8 @@ export interface ServerSyncBuilder<
54
57
  ScopeDefs
55
58
  >
56
59
  ): this;
60
+
61
+ addPushPlugin(plugin: SyncServerPushPlugin<ServerDB, Auth>): this;
57
62
  }
58
63
 
59
64
  export function defineServerSync<
@@ -65,11 +70,13 @@ export function defineServerSync<
65
70
  options: DefineServerSyncOptions<Auth>
66
71
  ): ServerSyncBuilder<ServerDB, ClientDB, ScopeDefs, Auth> {
67
72
  const handlers: ServerTableHandler<ServerDB, Auth>[] = [];
73
+ const plugins: SyncServerPushPlugin<ServerDB, Auth>[] = [];
68
74
  const registeredTables = new Set<string>();
69
75
 
70
76
  const sync: ServerSyncBuilder<ServerDB, ClientDB, ScopeDefs, Auth> = {
71
77
  authenticate: options.authenticate,
72
78
  handlers,
79
+ plugins,
73
80
  addHandler<TableName extends SharedTableName<ServerDB, ClientDB>>(
74
81
  handlerOptions: ServerSyncHandlerOptionsForTable<
75
82
  ServerDB,
@@ -79,11 +86,11 @@ export function defineServerSync<
79
86
  ScopeDefs
80
87
  >
81
88
  ) {
82
- if (registeredTables.has(handlerOptions.table)) {
83
- throw new Error(
84
- `Server table handler already registered: ${handlerOptions.table}`
85
- );
86
- }
89
+ registerTableOrThrow(
90
+ registeredTables,
91
+ handlerOptions.table,
92
+ (table) => `Server table handler already registered: ${table}`
93
+ );
87
94
 
88
95
  handlers.push(
89
96
  createServerHandler({
@@ -92,7 +99,10 @@ export function defineServerSync<
92
99
  codecDialect: options.codecDialect,
93
100
  })
94
101
  );
95
- registeredTables.add(handlerOptions.table);
102
+ return sync;
103
+ },
104
+ addPushPlugin(plugin: SyncServerPushPlugin<ServerDB, Auth>) {
105
+ plugins.push(plugin);
96
106
  return sync;
97
107
  },
98
108
  };