@syncular/server 0.0.6-96 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (597) 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 +1 -0
  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 +42 -5
  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/types.d.ts +40 -0
  84. package/dist/dialect/types.d.ts.map +1 -1
  85. package/dist/encrypted-crdt.d.ts +67 -0
  86. package/dist/encrypted-crdt.d.ts.map +1 -0
  87. package/dist/encrypted-crdt.js +426 -0
  88. package/dist/encrypted-crdt.js.map +1 -0
  89. package/dist/errors.d.ts +10 -0
  90. package/dist/errors.d.ts.map +1 -0
  91. package/dist/errors.js +13 -0
  92. package/dist/errors.js.map +1 -0
  93. package/dist/filesystem/index.d.ts +44 -0
  94. package/dist/filesystem/index.d.ts.map +1 -0
  95. package/dist/filesystem/index.js +164 -0
  96. package/dist/filesystem/index.js.map +1 -0
  97. package/dist/handlers/collection.d.ts +11 -3
  98. package/dist/handlers/collection.d.ts.map +1 -1
  99. package/dist/handlers/collection.js +34 -56
  100. package/dist/handlers/collection.js.map +1 -1
  101. package/dist/handlers/create-handler.d.ts +31 -7
  102. package/dist/handlers/create-handler.d.ts.map +1 -1
  103. package/dist/handlers/create-handler.js +332 -115
  104. package/dist/handlers/create-handler.js.map +1 -1
  105. package/dist/handlers/types.d.ts +86 -1
  106. package/dist/handlers/types.d.ts.map +1 -1
  107. package/dist/helpers/conflict.js.map +1 -1
  108. package/dist/helpers/emitted-change.js.map +1 -1
  109. package/dist/helpers/index.d.ts +2 -0
  110. package/dist/helpers/index.d.ts.map +1 -1
  111. package/dist/helpers/index.js +2 -0
  112. package/dist/helpers/index.js.map +1 -1
  113. package/dist/helpers/paginate.js.map +1 -1
  114. package/dist/helpers/scope-authorization.d.ts +7 -0
  115. package/dist/helpers/scope-authorization.d.ts.map +1 -0
  116. package/dist/helpers/scope-authorization.js +19 -0
  117. package/dist/helpers/scope-authorization.js.map +1 -0
  118. package/dist/helpers/scope-commit-index.d.ts +12 -0
  119. package/dist/helpers/scope-commit-index.d.ts.map +1 -0
  120. package/dist/helpers/scope-commit-index.js +35 -0
  121. package/dist/helpers/scope-commit-index.js.map +1 -0
  122. package/dist/helpers/scope-strings.js.map +1 -1
  123. package/dist/hono/api-key-auth.d.ts +49 -0
  124. package/dist/hono/api-key-auth.d.ts.map +1 -0
  125. package/dist/hono/api-key-auth.js +108 -0
  126. package/dist/hono/api-key-auth.js.map +1 -0
  127. package/dist/hono/audit-redaction.d.ts +20 -0
  128. package/dist/hono/audit-redaction.d.ts.map +1 -0
  129. package/dist/hono/audit-redaction.js +85 -0
  130. package/dist/hono/audit-redaction.js.map +1 -0
  131. package/dist/hono/blobs.d.ts +75 -0
  132. package/dist/hono/blobs.d.ts.map +1 -0
  133. package/dist/hono/blobs.js +586 -0
  134. package/dist/hono/blobs.js.map +1 -0
  135. package/dist/hono/console/gateway.d.ts +42 -0
  136. package/dist/hono/console/gateway.d.ts.map +1 -0
  137. package/dist/hono/console/gateway.js +2158 -0
  138. package/dist/hono/console/gateway.js.map +1 -0
  139. package/dist/hono/console/live-auth.d.ts +7 -0
  140. package/dist/hono/console/live-auth.d.ts.map +1 -0
  141. package/dist/hono/console/live-auth.js +39 -0
  142. package/dist/hono/console/live-auth.js.map +1 -0
  143. package/dist/hono/console/route-descriptor.d.ts +6 -0
  144. package/dist/hono/console/route-descriptor.d.ts.map +1 -0
  145. package/dist/hono/console/route-descriptor.js +16 -0
  146. package/dist/hono/console/route-descriptor.js.map +1 -0
  147. package/dist/hono/console/routes/api-keys.d.ts +8 -0
  148. package/dist/hono/console/routes/api-keys.d.ts.map +1 -0
  149. package/dist/hono/console/routes/api-keys.js +575 -0
  150. package/dist/hono/console/routes/api-keys.js.map +1 -0
  151. package/dist/hono/console/routes/clients.d.ts +8 -0
  152. package/dist/hono/console/routes/clients.d.ts.map +1 -0
  153. package/dist/hono/console/routes/clients.js +322 -0
  154. package/dist/hono/console/routes/clients.js.map +1 -0
  155. package/dist/hono/console/routes/commits.d.ts +8 -0
  156. package/dist/hono/console/routes/commits.d.ts.map +1 -0
  157. package/dist/hono/console/routes/commits.js +882 -0
  158. package/dist/hono/console/routes/commits.js.map +1 -0
  159. package/dist/hono/console/routes/context.d.ts +188 -0
  160. package/dist/hono/console/routes/context.d.ts.map +1 -0
  161. package/dist/hono/console/routes/context.js +633 -0
  162. package/dist/hono/console/routes/context.js.map +1 -0
  163. package/dist/hono/console/routes/events.d.ts +8 -0
  164. package/dist/hono/console/routes/events.d.ts.map +1 -0
  165. package/dist/hono/console/routes/events.js +501 -0
  166. package/dist/hono/console/routes/events.js.map +1 -0
  167. package/dist/hono/console/routes/maintenance.d.ts +8 -0
  168. package/dist/hono/console/routes/maintenance.d.ts.map +1 -0
  169. package/dist/hono/console/routes/maintenance.js +341 -0
  170. package/dist/hono/console/routes/maintenance.js.map +1 -0
  171. package/dist/hono/console/routes/shared.d.ts +174 -0
  172. package/dist/hono/console/routes/shared.d.ts.map +1 -0
  173. package/dist/hono/console/routes/shared.js +583 -0
  174. package/dist/hono/console/routes/shared.js.map +1 -0
  175. package/dist/hono/console/routes/stats.d.ts +8 -0
  176. package/dist/hono/console/routes/stats.d.ts.map +1 -0
  177. package/dist/hono/console/routes/stats.js +295 -0
  178. package/dist/hono/console/routes/stats.js.map +1 -0
  179. package/dist/hono/console/routes/storage.d.ts +8 -0
  180. package/dist/hono/console/routes/storage.d.ts.map +1 -0
  181. package/dist/hono/console/routes/storage.js +121 -0
  182. package/dist/hono/console/routes/storage.js.map +1 -0
  183. package/dist/hono/console/routes.d.ts +36 -0
  184. package/dist/hono/console/routes.d.ts.map +1 -0
  185. package/dist/hono/console/routes.js +112 -0
  186. package/dist/hono/console/routes.js.map +1 -0
  187. package/dist/hono/console/schema-errors.d.ts +2 -0
  188. package/dist/hono/console/schema-errors.d.ts.map +1 -0
  189. package/dist/hono/console/schema-errors.js +17 -0
  190. package/dist/hono/console/schema-errors.js.map +1 -0
  191. package/dist/hono/console/schemas.d.ts +1515 -0
  192. package/dist/hono/console/schemas.d.ts.map +1 -0
  193. package/dist/hono/console/schemas.js +661 -0
  194. package/dist/hono/console/schemas.js.map +1 -0
  195. package/dist/hono/console/types.d.ts +213 -0
  196. package/dist/hono/console/types.d.ts.map +1 -0
  197. package/dist/hono/console/types.js +2 -0
  198. package/dist/hono/console/types.js.map +1 -0
  199. package/dist/hono/console/ui.d.ts +38 -0
  200. package/dist/hono/console/ui.d.ts.map +1 -0
  201. package/dist/hono/console/ui.js +43 -0
  202. package/dist/hono/console/ui.js.map +1 -0
  203. package/dist/hono/create-server.d.ts +71 -0
  204. package/dist/hono/create-server.d.ts.map +1 -0
  205. package/dist/hono/create-server.js +121 -0
  206. package/dist/hono/create-server.js.map +1 -0
  207. package/dist/hono/errors.d.ts +13 -0
  208. package/dist/hono/errors.d.ts.map +1 -0
  209. package/dist/hono/errors.js +21 -0
  210. package/dist/hono/errors.js.map +1 -0
  211. package/dist/hono/index.d.ts +20 -0
  212. package/dist/hono/index.d.ts.map +1 -0
  213. package/dist/hono/index.js +31 -0
  214. package/dist/hono/index.js.map +1 -0
  215. package/dist/hono/openapi.d.ts +72 -0
  216. package/dist/hono/openapi.d.ts.map +1 -0
  217. package/dist/hono/openapi.js +99 -0
  218. package/dist/hono/openapi.js.map +1 -0
  219. package/dist/hono/proxy/connection-manager.d.ts +78 -0
  220. package/dist/hono/proxy/connection-manager.d.ts.map +1 -0
  221. package/dist/hono/proxy/connection-manager.js +251 -0
  222. package/dist/hono/proxy/connection-manager.js.map +1 -0
  223. package/dist/hono/proxy/index.d.ts +8 -0
  224. package/dist/hono/proxy/index.d.ts.map +1 -0
  225. package/dist/hono/proxy/index.js +8 -0
  226. package/dist/hono/proxy/index.js.map +1 -0
  227. package/dist/hono/proxy/routes.d.ts +86 -0
  228. package/dist/hono/proxy/routes.d.ts.map +1 -0
  229. package/dist/hono/proxy/routes.js +183 -0
  230. package/dist/hono/proxy/routes.js.map +1 -0
  231. package/dist/hono/rate-limit.d.ts +101 -0
  232. package/dist/hono/rate-limit.d.ts.map +1 -0
  233. package/dist/hono/rate-limit.js +184 -0
  234. package/dist/hono/rate-limit.js.map +1 -0
  235. package/dist/hono/realtime-sync-packs.d.ts +43 -0
  236. package/dist/hono/realtime-sync-packs.d.ts.map +1 -0
  237. package/dist/hono/realtime-sync-packs.js +219 -0
  238. package/dist/hono/realtime-sync-packs.js.map +1 -0
  239. package/dist/hono/routes/audit.d.ts +12 -0
  240. package/dist/hono/routes/audit.d.ts.map +1 -0
  241. package/dist/hono/routes/audit.js +385 -0
  242. package/dist/hono/routes/audit.js.map +1 -0
  243. package/dist/hono/routes/auth-leases.d.ts +8 -0
  244. package/dist/hono/routes/auth-leases.d.ts.map +1 -0
  245. package/dist/hono/routes/auth-leases.js +88 -0
  246. package/dist/hono/routes/auth-leases.js.map +1 -0
  247. package/dist/hono/routes/combined.d.ts +8 -0
  248. package/dist/hono/routes/combined.d.ts.map +1 -0
  249. package/dist/hono/routes/combined.js +392 -0
  250. package/dist/hono/routes/combined.js.map +1 -0
  251. package/dist/hono/routes/context.d.ts +314 -0
  252. package/dist/hono/routes/context.d.ts.map +1 -0
  253. package/dist/hono/routes/context.js +1147 -0
  254. package/dist/hono/routes/context.js.map +1 -0
  255. package/dist/hono/routes/health.d.ts +8 -0
  256. package/dist/hono/routes/health.d.ts.map +1 -0
  257. package/dist/hono/routes/health.js +16 -0
  258. package/dist/hono/routes/health.js.map +1 -0
  259. package/dist/hono/routes/realtime.d.ts +9 -0
  260. package/dist/hono/routes/realtime.d.ts.map +1 -0
  261. package/dist/hono/routes/realtime.js +626 -0
  262. package/dist/hono/routes/realtime.js.map +1 -0
  263. package/dist/hono/routes/shared.d.ts +689 -0
  264. package/dist/hono/routes/shared.d.ts.map +1 -0
  265. package/dist/hono/routes/shared.js +972 -0
  266. package/dist/hono/routes/shared.js.map +1 -0
  267. package/dist/hono/routes/snapshots.d.ts +10 -0
  268. package/dist/hono/routes/snapshots.d.ts.map +1 -0
  269. package/dist/hono/routes/snapshots.js +281 -0
  270. package/dist/hono/routes/snapshots.js.map +1 -0
  271. package/dist/hono/routes.d.ts +19 -0
  272. package/dist/hono/routes.d.ts.map +1 -0
  273. package/dist/hono/routes.js +37 -0
  274. package/dist/hono/routes.js.map +1 -0
  275. package/dist/hono/validation.d.ts +5 -0
  276. package/dist/hono/validation.d.ts.map +1 -0
  277. package/dist/hono/validation.js +47 -0
  278. package/dist/hono/validation.js.map +1 -0
  279. package/dist/hono/websocket-origin.d.ts +9 -0
  280. package/dist/hono/websocket-origin.d.ts.map +1 -0
  281. package/dist/hono/websocket-origin.js +96 -0
  282. package/dist/hono/websocket-origin.js.map +1 -0
  283. package/dist/hono/ws.d.ts +341 -0
  284. package/dist/hono/ws.d.ts.map +1 -0
  285. package/dist/hono/ws.js +711 -0
  286. package/dist/hono/ws.js.map +1 -0
  287. package/dist/index.d.ts +6 -0
  288. package/dist/index.d.ts.map +1 -1
  289. package/dist/index.js +6 -0
  290. package/dist/index.js.map +1 -1
  291. package/dist/libsql.d.ts +29 -0
  292. package/dist/libsql.d.ts.map +1 -0
  293. package/dist/libsql.js +25 -0
  294. package/dist/libsql.js.map +1 -0
  295. package/dist/migrate.js.map +1 -1
  296. package/dist/neon.d.ts +21 -0
  297. package/dist/neon.d.ts.map +1 -0
  298. package/dist/neon.js +22 -0
  299. package/dist/neon.js.map +1 -0
  300. package/dist/notify.d.ts +30 -0
  301. package/dist/notify.d.ts.map +1 -1
  302. package/dist/notify.js +160 -41
  303. package/dist/notify.js.map +1 -1
  304. package/dist/pglite.d.ts +37 -0
  305. package/dist/pglite.d.ts.map +1 -0
  306. package/dist/pglite.js +37 -0
  307. package/dist/pglite.js.map +1 -0
  308. package/dist/plugins/index.d.ts +2 -0
  309. package/dist/plugins/index.d.ts.map +1 -0
  310. package/dist/plugins/index.js +2 -0
  311. package/dist/plugins/index.js.map +1 -0
  312. package/dist/plugins/types.d.ts +73 -0
  313. package/dist/plugins/types.d.ts.map +1 -0
  314. package/dist/plugins/types.js +30 -0
  315. package/dist/plugins/types.js.map +1 -0
  316. package/dist/postgres/index.d.ts +68 -0
  317. package/dist/postgres/index.d.ts.map +1 -0
  318. package/dist/postgres/index.js +924 -0
  319. package/dist/postgres/index.js.map +1 -0
  320. package/dist/proxy/collection.d.ts +0 -2
  321. package/dist/proxy/collection.d.ts.map +1 -1
  322. package/dist/proxy/collection.js +2 -17
  323. package/dist/proxy/collection.js.map +1 -1
  324. package/dist/proxy/handler.d.ts +1 -1
  325. package/dist/proxy/handler.d.ts.map +1 -1
  326. package/dist/proxy/handler.js +1 -2
  327. package/dist/proxy/handler.js.map +1 -1
  328. package/dist/proxy/index.d.ts +1 -1
  329. package/dist/proxy/index.d.ts.map +1 -1
  330. package/dist/proxy/index.js +1 -1
  331. package/dist/proxy/index.js.map +1 -1
  332. package/dist/proxy/mutation-detector.js.map +1 -1
  333. package/dist/proxy/oplog.d.ts.map +1 -1
  334. package/dist/proxy/oplog.js +32 -8
  335. package/dist/proxy/oplog.js.map +1 -1
  336. package/dist/prune.d.ts +8 -1
  337. package/dist/prune.d.ts.map +1 -1
  338. package/dist/prune.js +68 -28
  339. package/dist/prune.js.map +1 -1
  340. package/dist/pull.d.ts +31 -0
  341. package/dist/pull.d.ts.map +1 -1
  342. package/dist/pull.js +1011 -471
  343. package/dist/pull.js.map +1 -1
  344. package/dist/push.d.ts +36 -2
  345. package/dist/push.d.ts.map +1 -1
  346. package/dist/push.js +603 -358
  347. package/dist/push.js.map +1 -1
  348. package/dist/realtime/in-memory.js.map +1 -1
  349. package/dist/realtime/index.d.ts +2 -1
  350. package/dist/realtime/index.d.ts.map +1 -1
  351. package/dist/realtime/index.js +1 -0
  352. package/dist/realtime/index.js.map +1 -1
  353. package/dist/realtime/types.d.ts +12 -0
  354. package/dist/realtime/types.d.ts.map +1 -1
  355. package/dist/realtime/types.js +13 -1
  356. package/dist/realtime/types.js.map +1 -1
  357. package/dist/relay/client-role/forward-engine.d.ts +63 -0
  358. package/dist/relay/client-role/forward-engine.d.ts.map +1 -0
  359. package/dist/relay/client-role/forward-engine.js +267 -0
  360. package/dist/relay/client-role/forward-engine.js.map +1 -0
  361. package/dist/relay/client-role/index.d.ts +9 -0
  362. package/dist/relay/client-role/index.d.ts.map +1 -0
  363. package/dist/relay/client-role/index.js +9 -0
  364. package/dist/relay/client-role/index.js.map +1 -0
  365. package/dist/relay/client-role/pull-engine.d.ts +72 -0
  366. package/dist/relay/client-role/pull-engine.d.ts.map +1 -0
  367. package/dist/relay/client-role/pull-engine.js +249 -0
  368. package/dist/relay/client-role/pull-engine.js.map +1 -0
  369. package/dist/relay/client-role/sequence-mapper.d.ts +65 -0
  370. package/dist/relay/client-role/sequence-mapper.d.ts.map +1 -0
  371. package/dist/relay/client-role/sequence-mapper.js +161 -0
  372. package/dist/relay/client-role/sequence-mapper.js.map +1 -0
  373. package/dist/relay/evaluation/relay-paths.d.ts +41 -0
  374. package/dist/relay/evaluation/relay-paths.d.ts.map +1 -0
  375. package/dist/relay/evaluation/relay-paths.js +504 -0
  376. package/dist/relay/evaluation/relay-paths.js.map +1 -0
  377. package/dist/relay/evaluation/rust-boundary.d.ts +47 -0
  378. package/dist/relay/evaluation/rust-boundary.d.ts.map +1 -0
  379. package/dist/relay/evaluation/rust-boundary.js +220 -0
  380. package/dist/relay/evaluation/rust-boundary.js.map +1 -0
  381. package/dist/relay/index.d.ts +37 -0
  382. package/dist/relay/index.d.ts.map +1 -0
  383. package/dist/relay/index.js +44 -0
  384. package/dist/relay/index.js.map +1 -0
  385. package/dist/relay/migrate.d.ts +18 -0
  386. package/dist/relay/migrate.d.ts.map +1 -0
  387. package/dist/relay/migrate.js +99 -0
  388. package/dist/relay/migrate.js.map +1 -0
  389. package/dist/relay/mode-manager.d.ts +60 -0
  390. package/dist/relay/mode-manager.d.ts.map +1 -0
  391. package/dist/relay/mode-manager.js +114 -0
  392. package/dist/relay/mode-manager.js.map +1 -0
  393. package/dist/relay/realtime.d.ts +90 -0
  394. package/dist/relay/realtime.d.ts.map +1 -0
  395. package/dist/relay/realtime.js +147 -0
  396. package/dist/relay/realtime.js.map +1 -0
  397. package/dist/relay/relay.d.ts +190 -0
  398. package/dist/relay/relay.d.ts.map +1 -0
  399. package/dist/relay/relay.js +320 -0
  400. package/dist/relay/relay.js.map +1 -0
  401. package/dist/relay/schema.d.ts +158 -0
  402. package/dist/relay/schema.d.ts.map +1 -0
  403. package/dist/relay/schema.js +7 -0
  404. package/dist/relay/schema.js.map +1 -0
  405. package/dist/relay/server-role/index.d.ts +56 -0
  406. package/dist/relay/server-role/index.d.ts.map +1 -0
  407. package/dist/relay/server-role/index.js +193 -0
  408. package/dist/relay/server-role/index.js.map +1 -0
  409. package/dist/relay/server-role/pull.d.ts +27 -0
  410. package/dist/relay/server-role/pull.d.ts.map +1 -0
  411. package/dist/relay/server-role/pull.js +24 -0
  412. package/dist/relay/server-role/pull.js.map +1 -0
  413. package/dist/relay/server-role/push.d.ts +29 -0
  414. package/dist/relay/server-role/push.d.ts.map +1 -0
  415. package/dist/relay/server-role/push.js +122 -0
  416. package/dist/relay/server-role/push.js.map +1 -0
  417. package/dist/s3/index.d.ts +83 -0
  418. package/dist/s3/index.d.ts.map +1 -0
  419. package/dist/s3/index.js +223 -0
  420. package/dist/s3/index.js.map +1 -0
  421. package/dist/schema.d.ts +137 -1
  422. package/dist/schema.d.ts.map +1 -1
  423. package/dist/schema.js +1 -0
  424. package/dist/schema.js.map +1 -1
  425. package/dist/service-worker/index.d.ts +114 -0
  426. package/dist/service-worker/index.d.ts.map +1 -0
  427. package/dist/service-worker/index.js +487 -0
  428. package/dist/service-worker/index.js.map +1 -0
  429. package/dist/snapshot-artifacts/sqlite-bun.d.ts +15 -0
  430. package/dist/snapshot-artifacts/sqlite-bun.d.ts.map +1 -0
  431. package/dist/snapshot-artifacts/sqlite-bun.js +128 -0
  432. package/dist/snapshot-artifacts/sqlite-bun.js.map +1 -0
  433. package/dist/snapshot-artifacts.d.ts +206 -0
  434. package/dist/snapshot-artifacts.d.ts.map +1 -0
  435. package/dist/snapshot-artifacts.js +545 -0
  436. package/dist/snapshot-artifacts.js.map +1 -0
  437. package/dist/snapshot-chunks/db-metadata.d.ts +18 -0
  438. package/dist/snapshot-chunks/db-metadata.d.ts.map +1 -1
  439. package/dist/snapshot-chunks/db-metadata.js +91 -63
  440. package/dist/snapshot-chunks/db-metadata.js.map +1 -1
  441. package/dist/snapshot-chunks/types.d.ts +2 -0
  442. package/dist/snapshot-chunks/types.d.ts.map +1 -1
  443. package/dist/snapshot-chunks.d.ts +33 -3
  444. package/dist/snapshot-chunks.d.ts.map +1 -1
  445. package/dist/snapshot-chunks.js +136 -55
  446. package/dist/snapshot-chunks.js.map +1 -1
  447. package/dist/sqlite/index.d.ts +53 -0
  448. package/dist/sqlite/index.d.ts.map +1 -0
  449. package/dist/sqlite/index.js +795 -0
  450. package/dist/sqlite/index.js.map +1 -0
  451. package/dist/sqlite3.d.ts +22 -0
  452. package/dist/sqlite3.d.ts.map +1 -0
  453. package/dist/sqlite3.js +99 -0
  454. package/dist/sqlite3.js.map +1 -0
  455. package/dist/stats.d.ts +8 -0
  456. package/dist/stats.d.ts.map +1 -1
  457. package/dist/stats.js +45 -13
  458. package/dist/stats.js.map +1 -1
  459. package/dist/subscriptions/cache.d.ts +3 -0
  460. package/dist/subscriptions/cache.d.ts.map +1 -1
  461. package/dist/subscriptions/cache.js +44 -0
  462. package/dist/subscriptions/cache.js.map +1 -1
  463. package/dist/subscriptions/resolve.d.ts +3 -1
  464. package/dist/subscriptions/resolve.d.ts.map +1 -1
  465. package/dist/subscriptions/resolve.js +90 -51
  466. package/dist/subscriptions/resolve.js.map +1 -1
  467. package/dist/sync.d.ts +3 -0
  468. package/dist/sync.d.ts.map +1 -1
  469. package/dist/sync.js +8 -4
  470. package/dist/sync.js.map +1 -1
  471. package/package.json +296 -7
  472. package/src/auth-leases.ts +649 -0
  473. package/src/better-sqlite3.ts +35 -0
  474. package/src/blobs/access.ts +244 -0
  475. package/src/blobs/adapters/database.ts +125 -43
  476. package/src/blobs/index.ts +1 -0
  477. package/src/blobs/manager.ts +366 -65
  478. package/src/blobs/migrate.ts +16 -8
  479. package/src/blobs/types.ts +4 -0
  480. package/src/bun-sqlite-ambient.d.ts +19 -0
  481. package/src/bun-sqlite.ts +27 -0
  482. package/src/clients.ts +1 -0
  483. package/src/cloudflare/durable-object.ts +289 -0
  484. package/src/cloudflare/index.ts +22 -0
  485. package/src/cloudflare/r2.ts +526 -0
  486. package/src/cloudflare/scope-cache.ts +341 -0
  487. package/src/cloudflare/sentry.ts +230 -0
  488. package/src/cloudflare/worker.ts +77 -0
  489. package/src/commit-integrity.ts +371 -0
  490. package/src/crdt-yjs/index.ts +931 -0
  491. package/src/d1.ts +16 -0
  492. package/src/dialect/base.ts +71 -5
  493. package/src/dialect/helpers.ts +31 -0
  494. package/src/dialect/types.ts +47 -0
  495. package/src/encrypted-crdt.ts +786 -0
  496. package/src/errors.ts +22 -0
  497. package/src/filesystem/index.ts +262 -0
  498. package/src/handlers/collection.ts +78 -78
  499. package/src/handlers/create-handler.ts +540 -147
  500. package/src/handlers/types.ts +116 -0
  501. package/src/helpers/index.ts +2 -0
  502. package/src/helpers/scope-authorization.ts +27 -0
  503. package/src/helpers/scope-commit-index.ts +52 -0
  504. package/src/hono/api-key-auth.ts +177 -0
  505. package/src/hono/audit-redaction.ts +135 -0
  506. package/src/hono/blobs.ts +851 -0
  507. package/src/hono/console/gateway.ts +3046 -0
  508. package/src/hono/console/live-auth.ts +46 -0
  509. package/src/hono/console/route-descriptor.ts +22 -0
  510. package/src/hono/console/routes/api-keys.ts +721 -0
  511. package/src/hono/console/routes/clients.ts +447 -0
  512. package/src/hono/console/routes/commits.ts +1137 -0
  513. package/src/hono/console/routes/context.ts +956 -0
  514. package/src/hono/console/routes/events.ts +669 -0
  515. package/src/hono/console/routes/maintenance.ts +461 -0
  516. package/src/hono/console/routes/shared.ts +816 -0
  517. package/src/hono/console/routes/stats.ts +392 -0
  518. package/src/hono/console/routes/storage.ts +159 -0
  519. package/src/hono/console/routes.ts +146 -0
  520. package/src/hono/console/schema-errors.ts +23 -0
  521. package/src/hono/console/schemas.ts +914 -0
  522. package/src/hono/console/types.ts +223 -0
  523. package/src/hono/console/ui.ts +100 -0
  524. package/src/hono/create-server.ts +230 -0
  525. package/src/hono/errors.ts +50 -0
  526. package/src/hono/index.ts +54 -0
  527. package/src/hono/openapi.ts +139 -0
  528. package/src/hono/proxy/connection-manager.ts +340 -0
  529. package/src/hono/proxy/index.ts +8 -0
  530. package/src/hono/proxy/routes.ts +272 -0
  531. package/src/hono/rate-limit.ts +319 -0
  532. package/src/hono/realtime-sync-packs.ts +354 -0
  533. package/src/hono/routes/audit.ts +499 -0
  534. package/src/hono/routes/auth-leases.ts +119 -0
  535. package/src/hono/routes/combined.ts +583 -0
  536. package/src/hono/routes/context.ts +1629 -0
  537. package/src/hono/routes/health.ts +26 -0
  538. package/src/hono/routes/realtime.ts +808 -0
  539. package/src/hono/routes/shared.ts +1626 -0
  540. package/src/hono/routes/snapshots.ts +345 -0
  541. package/src/hono/routes.ts +68 -0
  542. package/src/hono/validation.ts +81 -0
  543. package/src/hono/websocket-origin.ts +131 -0
  544. package/src/hono/ws.ts +1134 -0
  545. package/src/index.ts +6 -0
  546. package/src/libsql.ts +51 -0
  547. package/src/neon.ts +28 -0
  548. package/src/notify.ts +224 -44
  549. package/src/pglite.ts +68 -0
  550. package/src/plugins/index.ts +1 -0
  551. package/src/plugins/types.ts +144 -0
  552. package/src/postgres/index.ts +1291 -0
  553. package/src/proxy/collection.ts +5 -27
  554. package/src/proxy/handler.ts +2 -2
  555. package/src/proxy/index.ts +0 -2
  556. package/src/proxy/oplog.ts +41 -10
  557. package/src/prune.ts +137 -36
  558. package/src/pull.ts +1504 -591
  559. package/src/push.ts +881 -443
  560. package/src/realtime/index.ts +2 -0
  561. package/src/realtime/types.ts +35 -0
  562. package/src/relay/bun-types.d.ts +50 -0
  563. package/src/relay/client-role/forward-engine.ts +355 -0
  564. package/src/relay/client-role/index.ts +9 -0
  565. package/src/relay/client-role/pull-engine.ts +329 -0
  566. package/src/relay/client-role/sequence-mapper.ts +201 -0
  567. package/src/relay/evaluation/relay-paths.ts +699 -0
  568. package/src/relay/evaluation/rust-boundary.ts +464 -0
  569. package/src/relay/index.ts +50 -0
  570. package/src/relay/migrate.ts +113 -0
  571. package/src/relay/mode-manager.ts +142 -0
  572. package/src/relay/realtime.ts +207 -0
  573. package/src/relay/relay.ts +431 -0
  574. package/src/relay/schema.ts +171 -0
  575. package/src/relay/server-role/index.ts +338 -0
  576. package/src/relay/server-role/pull.ts +43 -0
  577. package/src/relay/server-role/push.ts +164 -0
  578. package/src/s3/index.ts +346 -0
  579. package/src/schema.ts +141 -1
  580. package/src/service-worker/index.ts +773 -0
  581. package/src/snapshot-artifacts/sqlite-bun.ts +168 -0
  582. package/src/snapshot-artifacts.ts +896 -0
  583. package/src/snapshot-chunks/db-metadata.ts +131 -72
  584. package/src/snapshot-chunks/types.ts +2 -0
  585. package/src/snapshot-chunks.ts +194 -70
  586. package/src/sqlite/index.ts +1064 -0
  587. package/src/sqlite3.ts +137 -0
  588. package/src/stats.ts +76 -13
  589. package/src/subscriptions/cache.ts +58 -0
  590. package/src/subscriptions/resolve.ts +99 -58
  591. package/src/sync.ts +16 -6
  592. package/src/blobs/adapters/database.test.ts +0 -67
  593. package/src/notify.test.ts +0 -520
  594. package/src/proxy/handler.test.ts +0 -126
  595. package/src/proxy/mutation-detector.test.ts +0 -71
  596. package/src/snapshot-chunks/db-metadata.test.ts +0 -172
  597. package/src/subscriptions/resolve.test.ts +0 -180
@@ -0,0 +1,1147 @@
1
+ /**
2
+ * Shared per-instance context for the sync route modules.
3
+ *
4
+ * createSyncRoutesContext() contains the entire setup block of the former
5
+ * monolithic createSyncRoutes() factory (Hono app creation, CORS + rate-limit
6
+ * middleware, handler registry, websocket manager, realtime broadcaster
7
+ * bridge, console request-event recording, and the shared push/pull
8
+ * execution pipeline). Route modules destructure what they need from the
9
+ * returned context object.
10
+ */
11
+ import { captureSyncException, collectScopeVars, countSyncMetric, createSyncTimer, logSyncEvent, SYNC_AUTH_LEASE_CODE_INVALID, SYNC_AUTH_LEASE_CODE_MISSING, } from '@syncular/core';
12
+ import { coerceNumber, createServerHandlerCollection, createSyncRealtimeShardKey, maybeCompactChanges, maybePruneSync, pushCommit, pushCommitBatch, rowScopesAllowed, validateAuthLeaseOperation, verifyAuthLeaseToken, } from '@syncular/server';
13
+ import { Hono } from 'hono';
14
+ import { sql } from 'kysely';
15
+ import { summarizeAuditChange } from '../audit-redaction.js';
16
+ import { isBenignConsoleSchemaError } from '../console/schema-errors.js';
17
+ import { syncError, syncLimitExceeded } from '../errors.js';
18
+ import { createRateLimiter, DEFAULT_SYNC_RATE_LIMITS, } from '../rate-limit.js';
19
+ import { notifyWebSocketConnectionsWithSyncPacks } from '../realtime-sync-packs.js';
20
+ import { WebSocketConnectionManager, } from '../ws.js';
21
+ import { applyPartitionToScopeKeys, applySyncCorsHeaders, createOpaqueId, createSyncCorsOriginDeniedResponse, DEFAULT_MAX_SNAPSHOT_ARTIFACT_RESPONSE_BYTES, DEFAULT_MAX_SNAPSHOT_CHUNK_RESPONSE_BYTES, DEFAULT_MAX_SYNC_BINARY_PACK_BYTES, DEFAULT_MAX_SYNC_REQUEST_JSON_BYTES, DEFAULT_REQUEST_PAYLOAD_SNAPSHOT_MAX_BYTES, emitConsoleLiveEvent, encodePayloadSnapshot, firstPushErrorCode, isAuthLeaseRefreshRetriable, isMissingRequestEventsTableError, isSyncJsonBodyLimitError, normalizeRequestEventType, normalizeResponseStatus, normalizeSyncCorsConfig, parseScopesSummary, parseStoredAuditScopes, readClientIdHint, readCommitScopeKeys, readOptionalPositiveInteger, readOriginHeader, readPositiveInteger, readRequestBodyBytesWithLimit, readRequestContentLength, readRequestId, readTraceContext, readTransportPath, realtimeUnsubscribeMap, scopeValuesToScopeKeys, selectRequiredAuditScopes, syncValidationError, wsConnectionManagerMap, } from './shared.js';
22
+ export function createSyncRoutesContext(options) {
23
+ const routes = new Hono();
24
+ const config = options.sync ?? {};
25
+ const authLeaseRoutesConfig = options.authLeases;
26
+ routes.onError((error, c) => {
27
+ captureSyncException(error, {
28
+ event: 'sync.route.unhandled',
29
+ method: c.req.method,
30
+ path: c.req.path,
31
+ });
32
+ return c.text('Internal Server Error', 500);
33
+ });
34
+ const corsConfig = normalizeSyncCorsConfig(config.cors);
35
+ if (corsConfig) {
36
+ routes.use('*', async (c, next) => {
37
+ const origin = readOriginHeader(c);
38
+ const allowedOrigin = await corsConfig.resolveOrigin(origin, c);
39
+ if (origin && !allowedOrigin) {
40
+ return createSyncCorsOriginDeniedResponse(origin);
41
+ }
42
+ const resolvedOrigin = allowedOrigin ?? '*';
43
+ if (c.req.method === 'OPTIONS') {
44
+ const headers = new Headers();
45
+ applySyncCorsHeaders({
46
+ headers,
47
+ allowedOrigin: resolvedOrigin,
48
+ allowCredentials: corsConfig.allowCredentials,
49
+ allowHeaders: corsConfig.allowHeaders,
50
+ exposeHeaders: corsConfig.exposeHeaders,
51
+ allowMethods: corsConfig.allowMethods,
52
+ maxAgeSeconds: corsConfig.maxAgeSeconds,
53
+ });
54
+ return new Response(null, { status: 204, headers });
55
+ }
56
+ await next();
57
+ applySyncCorsHeaders({
58
+ headers: c.res.headers,
59
+ allowedOrigin: resolvedOrigin,
60
+ allowCredentials: corsConfig.allowCredentials,
61
+ allowHeaders: corsConfig.allowHeaders,
62
+ exposeHeaders: corsConfig.exposeHeaders,
63
+ allowMethods: corsConfig.allowMethods,
64
+ maxAgeSeconds: corsConfig.maxAgeSeconds,
65
+ });
66
+ return c.res;
67
+ });
68
+ }
69
+ const handlerRegistry = createServerHandlerCollection(options.handlers, {
70
+ snapshotBinary: options.snapshotBinary,
71
+ });
72
+ const binarySyncPackChangeRowEncoders = Object.fromEntries(handlerRegistry.handlers.flatMap((handler) => handler.snapshotBinaryEncoder
73
+ ? [[handler.table, handler.snapshotBinaryEncoder]]
74
+ : []));
75
+ const maxPullLimitCommits = config.maxPullLimitCommits ?? 1000;
76
+ const maxSubscriptionsPerPull = config.maxSubscriptionsPerPull ?? 200;
77
+ const maxPullLimitSnapshotRows = config.maxPullLimitSnapshotRows ?? 50000;
78
+ const maxPullMaxSnapshotPages = config.maxPullMaxSnapshotPages ?? 50;
79
+ const maxOperationsPerPush = config.maxOperationsPerPush ?? 200;
80
+ const maxSyncRequestJsonBytes = readPositiveInteger(config.maxSyncRequestJsonBytes, DEFAULT_MAX_SYNC_REQUEST_JSON_BYTES);
81
+ const maxSyncBinaryPackBytes = readPositiveInteger(config.maxSyncBinaryPackBytes, DEFAULT_MAX_SYNC_BINARY_PACK_BYTES);
82
+ const maxSnapshotChunkResponseBytes = readPositiveInteger(config.maxSnapshotChunkResponseBytes, DEFAULT_MAX_SNAPSHOT_CHUNK_RESPONSE_BYTES);
83
+ const maxSnapshotArtifactResponseBytes = readPositiveInteger(config.maxSnapshotArtifactResponseBytes, DEFAULT_MAX_SNAPSHOT_ARTIFACT_RESPONSE_BYTES);
84
+ const requiredSchemaVersion = readOptionalPositiveInteger(config.requiredSchemaVersion);
85
+ const latestSchemaVersion = readOptionalPositiveInteger(config.latestSchemaVersion);
86
+ const requestPayloadSnapshots = config.requestPayloadSnapshots;
87
+ const requestPayloadSnapshotsEnabled = requestPayloadSnapshots?.enabled ??
88
+ requestPayloadSnapshots?.maxBytes !== undefined;
89
+ const pruneConfig = config.prune;
90
+ const compactConfig = config.compact;
91
+ const pruneMinIntervalMs = readPositiveInteger(pruneConfig?.minIntervalMs, 5 * 60 * 1000);
92
+ const compactMinIntervalMs = readPositiveInteger(compactConfig?.minIntervalMs, 30 * 60 * 1000);
93
+ const compactOptions = compactConfig?.options;
94
+ const consoleLiveEmitter = options.consoleLiveEmitter;
95
+ const shouldEmitConsoleLiveEvents = consoleLiveEmitter !== undefined;
96
+ const shouldRecordRequestEvents = shouldEmitConsoleLiveEvents;
97
+ const shouldCaptureRequestPayloadSnapshots = shouldRecordRequestEvents && requestPayloadSnapshotsEnabled;
98
+ const requestPayloadSnapshotMaxBytes = readPositiveInteger(requestPayloadSnapshots?.maxBytes, DEFAULT_REQUEST_PAYLOAD_SNAPSHOT_MAX_BYTES);
99
+ const consoleSchemaReadyBase = shouldRecordRequestEvents
100
+ ? (options.consoleSchemaReady ??
101
+ options.dialect.ensureConsoleSchema?.(options.db) ??
102
+ Promise.resolve())
103
+ : Promise.resolve();
104
+ const consoleSchemaReady = consoleSchemaReadyBase.catch((error) => {
105
+ if (isBenignConsoleSchemaError(error)) {
106
+ return;
107
+ }
108
+ logSyncEvent({
109
+ event: 'sync.console_schema_ready_failed',
110
+ error: error instanceof Error ? error.message : String(error),
111
+ });
112
+ throw error;
113
+ });
114
+ const authCache = new WeakMap();
115
+ const getAuth = (c) => {
116
+ const cached = authCache.get(c);
117
+ if (cached)
118
+ return cached;
119
+ const pending = options.authenticate(c);
120
+ authCache.set(c, pending);
121
+ return pending;
122
+ };
123
+ const createAuditScopeResolver = (auth) => {
124
+ const auditScopesByTable = new Map();
125
+ return async (table) => {
126
+ const cached = auditScopesByTable.get(table);
127
+ if (cached)
128
+ return cached;
129
+ const pending = (async () => {
130
+ const handler = handlerRegistry.byTable.get(table);
131
+ if (!handler)
132
+ return null;
133
+ let allowedScopes;
134
+ try {
135
+ allowedScopes = await handler.resolveScopes({
136
+ db: options.db,
137
+ actorId: auth.actorId,
138
+ auth,
139
+ });
140
+ }
141
+ catch {
142
+ return null;
143
+ }
144
+ const scopes = selectRequiredAuditScopes(handler.scopePatterns, allowedScopes);
145
+ if (!scopes)
146
+ return null;
147
+ return {
148
+ scopes,
149
+ requiredScopeKeys: Array.from(collectScopeVars(handler.scopePatterns)),
150
+ };
151
+ })();
152
+ auditScopesByTable.set(table, pending);
153
+ return pending;
154
+ };
155
+ };
156
+ const readVisibleAuditChanges = async (args) => {
157
+ const uniqueCommitSeqs = Array.from(new Set(args.commitSeqs));
158
+ if (uniqueCommitSeqs.length === 0)
159
+ return new Map();
160
+ const changesResult = await sql `
161
+ select
162
+ ${sql.ref('commit_seq')} as ${sql.ref('commit_seq')},
163
+ ${sql.ref('change_id')} as ${sql.ref('change_id')},
164
+ ${sql.ref('table')} as ${sql.ref('table')},
165
+ ${sql.ref('row_id')} as ${sql.ref('row_id')},
166
+ ${sql.ref('op')} as ${sql.ref('op')},
167
+ ${sql.ref('row_json')} as ${sql.ref('row_json')},
168
+ ${sql.ref('row_version')} as ${sql.ref('row_version')},
169
+ ${sql.ref('scopes')} as ${sql.ref('scopes')}
170
+ from ${sql.table('sync_changes')}
171
+ where ${sql.ref('partition_id')} = ${args.partitionId}
172
+ and ${sql.ref('commit_seq')} in (${sql.join(uniqueCommitSeqs)})
173
+ order by ${sql.ref('commit_seq')} asc, ${sql.ref('change_id')} asc
174
+ `.execute(options.db);
175
+ const resolveAuditScopesForTable = createAuditScopeResolver(args.auth);
176
+ const changesByCommitSeq = new Map();
177
+ for (const change of changesResult.rows) {
178
+ const scopeConfig = await resolveAuditScopesForTable(change.table);
179
+ if (!scopeConfig)
180
+ continue;
181
+ const rowScopes = parseStoredAuditScopes(change.scopes);
182
+ if (!rowScopesAllowed({
183
+ rowScopes,
184
+ allowedScopes: scopeConfig.scopes,
185
+ requiredScopeKeys: scopeConfig.requiredScopeKeys,
186
+ })) {
187
+ continue;
188
+ }
189
+ const commitSeq = Number(change.commit_seq);
190
+ const summary = summarizeAuditChange({
191
+ table: change.table,
192
+ op: change.op,
193
+ rowJson: change.row_json,
194
+ scopes: change.scopes,
195
+ });
196
+ const changes = changesByCommitSeq.get(commitSeq) ?? [];
197
+ changes.push({
198
+ changeId: Number(change.change_id),
199
+ table: change.table,
200
+ rowId: change.row_id,
201
+ op: change.op,
202
+ rowVersion: change.row_version === null ? null : Number(change.row_version),
203
+ ...summary,
204
+ });
205
+ changesByCommitSeq.set(commitSeq, changes);
206
+ }
207
+ return changesByCommitSeq;
208
+ };
209
+ const readAuditDebugRequestEvents = async (args) => {
210
+ const whereClauses = [
211
+ sql `partition_id = ${args.partitionId}`,
212
+ sql `actor_id = ${args.auth.actorId}`,
213
+ ];
214
+ if (args.from) {
215
+ whereClauses.push(sql `created_at >= ${args.from}`);
216
+ }
217
+ if (args.to) {
218
+ whereClauses.push(sql `created_at <= ${args.to}`);
219
+ }
220
+ try {
221
+ const result = await sql `
222
+ select
223
+ event_id,
224
+ partition_id,
225
+ request_id,
226
+ trace_id,
227
+ span_id,
228
+ event_type,
229
+ sync_path,
230
+ transport_path,
231
+ actor_id,
232
+ client_id,
233
+ status_code,
234
+ outcome,
235
+ response_status,
236
+ error_code,
237
+ duration_ms,
238
+ commit_seq,
239
+ operation_count,
240
+ row_count,
241
+ subscription_count,
242
+ scopes_summary,
243
+ tables,
244
+ created_at
245
+ from ${sql.table('sync_request_events')}
246
+ where ${sql.join(whereClauses, sql ` and `)}
247
+ order by created_at desc
248
+ limit ${args.limit + 1}
249
+ `.execute(options.db);
250
+ const selectedRows = result.rows.slice(0, args.limit);
251
+ return {
252
+ truncated: result.rows.length > args.limit,
253
+ events: selectedRows.map((row) => ({
254
+ eventId: coerceNumber(row.event_id) ?? 0,
255
+ partitionId: row.partition_id ?? args.partitionId,
256
+ requestId: row.request_id ?? '',
257
+ traceId: row.trace_id ?? null,
258
+ spanId: row.span_id ?? null,
259
+ eventType: normalizeRequestEventType(row.event_type),
260
+ syncPath: row.sync_path === 'ws-push' ? 'ws-push' : 'http-combined',
261
+ transportPath: row.transport_path === 'relay' ? 'relay' : 'direct',
262
+ actorId: row.actor_id ?? '',
263
+ clientId: row.client_id ?? '',
264
+ statusCode: coerceNumber(row.status_code) ?? 0,
265
+ outcome: row.outcome ?? '',
266
+ responseStatus: row.response_status ?? 'unknown',
267
+ errorCode: row.error_code ?? null,
268
+ durationMs: coerceNumber(row.duration_ms) ?? 0,
269
+ commitSeq: coerceNumber(row.commit_seq),
270
+ operationCount: coerceNumber(row.operation_count),
271
+ rowCount: coerceNumber(row.row_count),
272
+ subscriptionCount: coerceNumber(row.subscription_count),
273
+ scopesSummary: parseScopesSummary(row.scopes_summary),
274
+ tables: options.dialect.dbToArray(row.tables),
275
+ createdAt: row.created_at ?? '',
276
+ })),
277
+ };
278
+ }
279
+ catch (error) {
280
+ if (isMissingRequestEventsTableError(error)) {
281
+ return { events: [], truncated: false };
282
+ }
283
+ throw error;
284
+ }
285
+ };
286
+ const validateAuthLeaseCommit = authLeaseRoutesConfig && authLeaseRoutesConfig.enabled !== false
287
+ ? async ({ trx, request, auth }) => {
288
+ const authLease = request.authLease;
289
+ if (!authLease)
290
+ return null;
291
+ if (!authLease.leaseToken) {
292
+ return {
293
+ opIndex: 0,
294
+ status: 'error',
295
+ error: 'Auth lease token is missing',
296
+ code: SYNC_AUTH_LEASE_CODE_MISSING,
297
+ retriable: true,
298
+ };
299
+ }
300
+ const verification = await verifyAuthLeaseToken({
301
+ token: authLease.leaseToken,
302
+ publicKey: authLeaseRoutesConfig.publicKey,
303
+ nowMs: authLeaseRoutesConfig.nowMs?.(),
304
+ expectedIssuer: authLeaseRoutesConfig.issuer,
305
+ expectedAudience: authLeaseRoutesConfig.audience,
306
+ expectedSchemaVersion: request.schemaVersion,
307
+ });
308
+ if (!verification.ok) {
309
+ return {
310
+ opIndex: 0,
311
+ status: 'error',
312
+ error: verification.message,
313
+ code: verification.code,
314
+ retriable: isAuthLeaseRefreshRetriable(verification.code),
315
+ };
316
+ }
317
+ const verifiedPayload = verification.payload;
318
+ if (verifiedPayload.actorId !== auth.actorId ||
319
+ verifiedPayload.leaseId !== authLease.leaseId) {
320
+ return {
321
+ opIndex: 0,
322
+ status: 'error',
323
+ error: 'Auth lease does not match the current replay context',
324
+ code: SYNC_AUTH_LEASE_CODE_INVALID,
325
+ retriable: true,
326
+ };
327
+ }
328
+ for (let opIndex = 0; opIndex < request.operations.length; opIndex += 1) {
329
+ const operation = request.operations[opIndex];
330
+ const handler = handlerRegistry.byTable.get(operation.table);
331
+ if (!handler) {
332
+ return {
333
+ opIndex,
334
+ status: 'error',
335
+ error: 'Auth lease operation table is not registered',
336
+ code: SYNC_AUTH_LEASE_CODE_INVALID,
337
+ retriable: false,
338
+ };
339
+ }
340
+ const operationError = await validateAuthLeaseOperation({
341
+ db: trx,
342
+ auth,
343
+ handler,
344
+ payload: verifiedPayload,
345
+ operation,
346
+ opIndex,
347
+ });
348
+ if (operationError)
349
+ return operationError;
350
+ }
351
+ return null;
352
+ }
353
+ : undefined;
354
+ const syncJsonBodyCache = new WeakMap();
355
+ const readLimitedSyncJsonBody = (c) => {
356
+ const cached = syncJsonBodyCache.get(c.req.raw);
357
+ if (cached)
358
+ return cached;
359
+ const pending = (async () => {
360
+ const declaredLength = readRequestContentLength(c);
361
+ if (declaredLength === 'invalid') {
362
+ return {
363
+ ok: false,
364
+ response: syncError(c, 400, 'sync.invalid_request', 'Invalid Content-Length'),
365
+ };
366
+ }
367
+ if (typeof declaredLength === 'number' &&
368
+ declaredLength > maxSyncRequestJsonBytes) {
369
+ return {
370
+ ok: false,
371
+ response: syncLimitExceeded(c, {
372
+ limit: 'maxSyncRequestJsonBytes',
373
+ observed: declaredLength,
374
+ max: maxSyncRequestJsonBytes,
375
+ }),
376
+ failure: {
377
+ statusCode: 413,
378
+ errorCode: 'runtime.limit_exceeded',
379
+ errorMessage: 'maxSyncRequestJsonBytes exceeded',
380
+ },
381
+ };
382
+ }
383
+ let bytes;
384
+ try {
385
+ bytes = await readRequestBodyBytesWithLimit(c.req.raw, {
386
+ maxBytes: maxSyncRequestJsonBytes,
387
+ limit: 'maxSyncRequestJsonBytes',
388
+ });
389
+ }
390
+ catch (error) {
391
+ if (isSyncJsonBodyLimitError(error)) {
392
+ return {
393
+ ok: false,
394
+ response: syncLimitExceeded(c, {
395
+ limit: error.limit,
396
+ observed: error.observed,
397
+ max: error.max,
398
+ }),
399
+ failure: {
400
+ statusCode: 413,
401
+ errorCode: 'runtime.limit_exceeded',
402
+ errorMessage: `${error.limit} exceeded`,
403
+ },
404
+ };
405
+ }
406
+ throw error;
407
+ }
408
+ try {
409
+ const text = new TextDecoder().decode(bytes);
410
+ return { ok: true, value: JSON.parse(text) };
411
+ }
412
+ catch {
413
+ return {
414
+ ok: false,
415
+ response: syncValidationError(c, 'json', [
416
+ { message: 'Invalid JSON body.', path: [] },
417
+ ]),
418
+ };
419
+ }
420
+ })();
421
+ syncJsonBodyCache.set(c.req.raw, pending);
422
+ return pending;
423
+ };
424
+ // -------------------------------------------------------------------------
425
+ // Optional WebSocket manager (scope-key based wake-ups)
426
+ // -------------------------------------------------------------------------
427
+ const websocketConfig = config.websocket;
428
+ if (websocketConfig?.enabled && !websocketConfig.upgradeWebSocket) {
429
+ throw new Error('sync.websocket.enabled requires sync.websocket.upgradeWebSocket');
430
+ }
431
+ const wsConnectionManager = websocketConfig?.enabled
432
+ ? (options.wsConnectionManager ??
433
+ new WebSocketConnectionManager({
434
+ heartbeatIntervalMs: websocketConfig.heartbeatIntervalMs ?? 30_000,
435
+ maxInFlightSyncsPerConnection: websocketConfig.maxInFlightSyncsPerConnection ?? 64,
436
+ maxSyncPackBytes: websocketConfig.maxSyncPackBytes,
437
+ replayWindowSize: websocketConfig.replayWindowSize ?? 64,
438
+ }))
439
+ : null;
440
+ if (wsConnectionManager) {
441
+ wsConnectionManagerMap.set(routes, wsConnectionManager);
442
+ }
443
+ // -------------------------------------------------------------------------
444
+ // Multi-instance realtime broadcaster (optional)
445
+ // -------------------------------------------------------------------------
446
+ const realtimeBroadcaster = config.realtime?.broadcaster ?? null;
447
+ const instanceId = config.realtime?.instanceId ??
448
+ (typeof crypto !== 'undefined' && 'randomUUID' in crypto
449
+ ? crypto.randomUUID()
450
+ : `${Date.now()}-${Math.random().toString(16).slice(2)}`);
451
+ const loggedAsyncFailureKeys = new Set();
452
+ const logAsyncFailureOnce = (key, event) => {
453
+ if (loggedAsyncFailureKeys.has(key))
454
+ return;
455
+ loggedAsyncFailureKeys.add(key);
456
+ logSyncEvent(event);
457
+ };
458
+ if (compactConfig && !compactOptions) {
459
+ logSyncEvent({
460
+ event: 'sync.compact_auto_disabled',
461
+ reason: 'missing_options',
462
+ });
463
+ }
464
+ const triggerAutoMaintenance = (ctx) => {
465
+ if (!pruneConfig && !compactConfig)
466
+ return;
467
+ void (async () => {
468
+ if (pruneConfig) {
469
+ try {
470
+ const deleted = await maybePruneSync(options.db, {
471
+ minIntervalMs: pruneMinIntervalMs,
472
+ options: pruneConfig.options,
473
+ });
474
+ if (deleted > 0) {
475
+ logSyncEvent({
476
+ event: 'sync.prune_auto',
477
+ userId: ctx.actorId,
478
+ clientId: ctx.clientId,
479
+ partitionId: ctx.partitionId,
480
+ deletedCount: deleted,
481
+ });
482
+ }
483
+ }
484
+ catch (error) {
485
+ logAsyncFailureOnce('sync.prune_auto_failed', {
486
+ event: 'sync.prune_auto_failed',
487
+ userId: ctx.actorId,
488
+ clientId: ctx.clientId,
489
+ partitionId: ctx.partitionId,
490
+ error: error instanceof Error ? error.message : String(error),
491
+ });
492
+ }
493
+ }
494
+ if (compactConfig && compactOptions) {
495
+ try {
496
+ const deleted = await maybeCompactChanges(options.db, {
497
+ dialect: options.dialect,
498
+ minIntervalMs: compactMinIntervalMs,
499
+ options: compactOptions,
500
+ });
501
+ if (deleted > 0) {
502
+ logSyncEvent({
503
+ event: 'sync.compact_auto',
504
+ userId: ctx.actorId,
505
+ clientId: ctx.clientId,
506
+ partitionId: ctx.partitionId,
507
+ deletedCount: deleted,
508
+ });
509
+ }
510
+ }
511
+ catch (error) {
512
+ logAsyncFailureOnce('sync.compact_auto_failed', {
513
+ event: 'sync.compact_auto_failed',
514
+ userId: ctx.actorId,
515
+ clientId: ctx.clientId,
516
+ partitionId: ctx.partitionId,
517
+ error: error instanceof Error ? error.message : String(error),
518
+ });
519
+ }
520
+ }
521
+ })();
522
+ };
523
+ if (wsConnectionManager && realtimeBroadcaster) {
524
+ const unsubscribe = realtimeBroadcaster.subscribe((event) => {
525
+ void handleRealtimeEvent(event).catch((error) => {
526
+ logAsyncFailureOnce('sync.realtime.broadcast_delivery_failed', {
527
+ event: 'sync.realtime.broadcast_delivery_failed',
528
+ error: error instanceof Error ? error.message : String(error),
529
+ sourceEventType: event.type,
530
+ });
531
+ });
532
+ });
533
+ realtimeUnsubscribeMap.set(routes, unsubscribe);
534
+ }
535
+ const recordRequestEvent = async (event) => {
536
+ let payloadRef = event.payloadRef ?? null;
537
+ if (event.payloadSnapshot) {
538
+ const nextPayloadRef = payloadRef ?? createOpaqueId('payload');
539
+ const nowIso = new Date().toISOString();
540
+ try {
541
+ await sql `
542
+ INSERT INTO sync_request_payloads (
543
+ payload_ref, partition_id, request_payload, response_payload, created_at
544
+ ) VALUES (
545
+ ${nextPayloadRef}, ${event.partitionId},
546
+ ${encodePayloadSnapshot(event.payloadSnapshot.request, requestPayloadSnapshotMaxBytes)},
547
+ ${encodePayloadSnapshot(event.payloadSnapshot.response, requestPayloadSnapshotMaxBytes)},
548
+ ${nowIso}
549
+ )
550
+ ON CONFLICT (payload_ref) DO UPDATE SET
551
+ partition_id = EXCLUDED.partition_id,
552
+ request_payload = EXCLUDED.request_payload,
553
+ response_payload = EXCLUDED.response_payload,
554
+ created_at = EXCLUDED.created_at
555
+ `.execute(options.db);
556
+ payloadRef = nextPayloadRef;
557
+ }
558
+ catch (error) {
559
+ payloadRef = null;
560
+ logAsyncFailureOnce('sync.request_payload_record_failed', {
561
+ event: 'sync.request_payload_record_failed',
562
+ userId: event.actorId,
563
+ clientId: event.clientId,
564
+ requestEventType: event.eventType,
565
+ error: error instanceof Error ? error.message : String(error),
566
+ });
567
+ }
568
+ }
569
+ const tablesValue = options.dialect.arrayToDb(event.tables ?? []);
570
+ const scopesSummaryValue = event.scopesSummary
571
+ ? JSON.stringify(event.scopesSummary)
572
+ : null;
573
+ const responseSummaryValue = event.responseSummary
574
+ ? JSON.stringify(event.responseSummary)
575
+ : null;
576
+ await sql `
577
+ INSERT INTO sync_request_events (
578
+ partition_id, request_id, trace_id, span_id,
579
+ event_type, sync_path, actor_id, client_id, transport_path,
580
+ status_code, outcome, response_status, error_code,
581
+ duration_ms, commit_seq, operation_count, row_count, subscription_count,
582
+ scopes_summary, response_summary, tables, error_message, payload_ref
583
+ ) VALUES (
584
+ ${event.partitionId}, ${event.requestId}, ${event.traceId ?? null},
585
+ ${event.spanId ?? null}, ${event.eventType}, ${event.syncPath},
586
+ ${event.actorId}, ${event.clientId}, ${event.transportPath},
587
+ ${event.statusCode}, ${event.outcome}, ${event.responseStatus},
588
+ ${event.errorCode ?? null}, ${event.durationMs}, ${event.commitSeq ?? null},
589
+ ${event.operationCount ?? null}, ${event.rowCount ?? null},
590
+ ${event.subscriptionCount ?? null}, ${scopesSummaryValue},
591
+ ${responseSummaryValue}, ${tablesValue}, ${event.errorMessage ?? null},
592
+ ${payloadRef}
593
+ )
594
+ `.execute(options.db);
595
+ };
596
+ const recordRequestEventInBackground = (event) => {
597
+ if (!shouldRecordRequestEvents)
598
+ return;
599
+ const resolvedEvent = typeof event === 'function' ? event() : event;
600
+ void consoleSchemaReady
601
+ .then(() => recordRequestEvent(resolvedEvent))
602
+ .catch((error) => {
603
+ logAsyncFailureOnce('sync.request_event_record_failed', {
604
+ event: 'sync.request_event_record_failed',
605
+ userId: resolvedEvent.actorId,
606
+ clientId: resolvedEvent.clientId,
607
+ requestEventType: resolvedEvent.eventType,
608
+ error: error instanceof Error ? error.message : String(error),
609
+ });
610
+ });
611
+ };
612
+ const recordRealtimeEvent = async (event) => {
613
+ await sql `
614
+ INSERT INTO sync_realtime_events (
615
+ partition_id, actor_id, client_id, transport_path, event_type, reason,
616
+ cursor, latest_cursor, commit_seq, scope_count, skipped_count,
617
+ sync_pack_encoding
618
+ ) VALUES (
619
+ ${event.partitionId}, ${event.actorId}, ${event.clientId},
620
+ ${event.transportPath}, ${event.eventType}, ${event.reason ?? null},
621
+ ${event.cursor ?? null}, ${event.latestCursor ?? null},
622
+ ${event.commitSeq ?? null}, ${event.scopeCount ?? null},
623
+ ${event.skippedCount ?? null}, ${event.syncPackEncoding ?? null}
624
+ )
625
+ `.execute(options.db);
626
+ };
627
+ const recordRealtimeEventInBackground = (event) => {
628
+ if (!shouldRecordRequestEvents)
629
+ return;
630
+ const resolvedEvent = typeof event === 'function' ? event() : event;
631
+ void consoleSchemaReady
632
+ .then(() => recordRealtimeEvent(resolvedEvent))
633
+ .catch((error) => {
634
+ logAsyncFailureOnce('sync.realtime_event_record_failed', {
635
+ event: 'sync.realtime_event_record_failed',
636
+ userId: resolvedEvent.actorId,
637
+ clientId: resolvedEvent.clientId,
638
+ realtimeEventType: resolvedEvent.eventType,
639
+ error: error instanceof Error ? error.message : String(error),
640
+ });
641
+ });
642
+ };
643
+ const recordHttpCombinedFailure = (args) => {
644
+ recordRequestEventInBackground(() => ({
645
+ partitionId: args.partitionId,
646
+ requestId: args.requestId,
647
+ traceId: args.traceContext.traceId,
648
+ spanId: args.traceContext.spanId,
649
+ eventType: args.eventType,
650
+ syncPath: 'http-combined',
651
+ actorId: args.actorId,
652
+ clientId: args.clientId,
653
+ transportPath: args.transportPath,
654
+ statusCode: args.statusCode,
655
+ outcome: args.outcome,
656
+ responseStatus: normalizeResponseStatus(args.statusCode, args.outcome),
657
+ durationMs: args.durationMs,
658
+ errorCode: args.errorCode,
659
+ errorMessage: args.errorMessage,
660
+ operationCount: args.operationCount ?? null,
661
+ rowCount: args.rowCount ?? null,
662
+ subscriptionCount: args.subscriptionCount ?? null,
663
+ scopesSummary: args.scopesSummary ?? null,
664
+ responseSummary: args.responseSummary ?? null,
665
+ payloadSnapshot: args.payloadSnapshot ?? null,
666
+ }));
667
+ emitConsoleLiveEvent(consoleLiveEmitter, args.eventType, () => ({
668
+ partitionId: args.partitionId,
669
+ requestId: args.requestId,
670
+ traceId: args.traceContext.traceId,
671
+ spanId: args.traceContext.spanId,
672
+ actorId: args.actorId,
673
+ clientId: args.clientId,
674
+ transportPath: args.transportPath,
675
+ syncPath: 'http-combined',
676
+ outcome: args.outcome,
677
+ statusCode: args.statusCode,
678
+ durationMs: args.durationMs,
679
+ operationCount: args.operationCount ?? null,
680
+ rowCount: args.rowCount ?? null,
681
+ subscriptionCount: args.subscriptionCount ?? null,
682
+ errorCode: args.errorCode,
683
+ errorMessage: args.errorMessage,
684
+ }));
685
+ };
686
+ const recordHttpCombinedReadFailure = async (c, failure) => {
687
+ if (!shouldRecordRequestEvents && !shouldEmitConsoleLiveEvents)
688
+ return;
689
+ const auth = await getAuth(c).catch(() => null);
690
+ if (!auth)
691
+ return;
692
+ recordHttpCombinedFailure({
693
+ partitionId: auth.partitionId ?? 'default',
694
+ requestId: readRequestId(c),
695
+ traceContext: readTraceContext(c),
696
+ actorId: auth.actorId,
697
+ clientId: readClientIdHint(c),
698
+ transportPath: readTransportPath(c),
699
+ eventType: 'sync',
700
+ statusCode: failure.statusCode,
701
+ outcome: failure.statusCode >= 500 ? 'error' : 'rejected',
702
+ durationMs: 0,
703
+ errorCode: failure.errorCode,
704
+ errorMessage: failure.errorMessage,
705
+ });
706
+ };
707
+ async function notifyRealtimeForAppliedPushes(ctx, pushedCommits) {
708
+ if (!wsConnectionManager && !realtimeBroadcaster) {
709
+ return;
710
+ }
711
+ let latestCommitSeq = 0;
712
+ const scopeKeys = new Set();
713
+ const emittedCommits = [];
714
+ for (const pushed of pushedCommits) {
715
+ if (pushed.response.ok !== true ||
716
+ pushed.response.status !== 'applied' ||
717
+ typeof pushed.response.commitSeq !== 'number') {
718
+ continue;
719
+ }
720
+ latestCommitSeq = Math.max(latestCommitSeq, pushed.response.commitSeq);
721
+ for (const scopeKey of applyPartitionToScopeKeys(ctx.partitionId, pushed.scopeKeys)) {
722
+ scopeKeys.add(scopeKey);
723
+ }
724
+ if (pushed.emittedChanges.length > 0) {
725
+ emittedCommits.push({
726
+ commitSeq: pushed.response.commitSeq,
727
+ createdAt: pushed.commitCreatedAt ?? new Date().toISOString(),
728
+ actorId: pushed.commitActorId ?? ctx.auth.actorId,
729
+ changes: [...pushed.emittedChanges],
730
+ });
731
+ }
732
+ }
733
+ if (latestCommitSeq <= 0 || scopeKeys.size === 0) {
734
+ return;
735
+ }
736
+ const combinedScopeKeys = Array.from(scopeKeys);
737
+ if (wsConnectionManager) {
738
+ await notifyWebSocketConnectionsWithSyncPacks({
739
+ manager: wsConnectionManager,
740
+ partitionId: ctx.partitionId,
741
+ scopeKeys: combinedScopeKeys,
742
+ cursor: latestCommitSeq,
743
+ commits: emittedCommits,
744
+ changeRowEncoders: binarySyncPackChangeRowEncoders,
745
+ excludeClientIds: [ctx.clientId],
746
+ onPackUnavailable: (event) => {
747
+ logSyncEvent({
748
+ event: 'sync.realtime.binary_pack_unavailable',
749
+ userId: ctx.auth.actorId,
750
+ clientId: ctx.clientId,
751
+ reason: event.reason,
752
+ subscriptionCount: event.subscriptionCount,
753
+ emittedCommitCount: event.emittedCommitCount,
754
+ });
755
+ },
756
+ onPackEncodeFailed: (event) => {
757
+ logAsyncFailureOnce('sync.realtime.binary_pack_encode_failed', {
758
+ event: 'sync.realtime.binary_pack_encode_failed',
759
+ userId: ctx.auth.actorId,
760
+ clientId: ctx.clientId,
761
+ error: event.error instanceof Error
762
+ ? event.error.message
763
+ : String(event.error),
764
+ });
765
+ },
766
+ });
767
+ }
768
+ if (realtimeBroadcaster) {
769
+ realtimeBroadcaster
770
+ .publish({
771
+ type: 'commit',
772
+ commitSeq: latestCommitSeq,
773
+ shardKey: createSyncRealtimeShardKey({
774
+ partitionId: ctx.partitionId,
775
+ }),
776
+ partitionId: ctx.partitionId,
777
+ scopeKeys: combinedScopeKeys,
778
+ sourceInstanceId: instanceId,
779
+ })
780
+ .catch((error) => {
781
+ logAsyncFailureOnce('sync.realtime.broadcast_publish_failed', {
782
+ event: 'sync.realtime.broadcast_publish_failed',
783
+ userId: ctx.auth.actorId,
784
+ clientId: ctx.clientId,
785
+ error: error instanceof Error ? error.message : String(error),
786
+ });
787
+ });
788
+ }
789
+ }
790
+ function buildRealtimeSubscriptionsForPull(args) {
791
+ const requestById = new Map(args.requestSubscriptions.map((subscription) => [
792
+ subscription.id,
793
+ subscription,
794
+ ]));
795
+ const subscriptions = [];
796
+ for (const response of args.responseSubscriptions) {
797
+ if (response.status !== 'active')
798
+ continue;
799
+ const request = requestById.get(response.id);
800
+ const scopeKeys = applyPartitionToScopeKeys(args.partitionId, scopeValuesToScopeKeys(response.scopes));
801
+ if (scopeKeys.length === 0)
802
+ continue;
803
+ subscriptions.push({
804
+ id: response.id,
805
+ table: request?.table ?? response.id,
806
+ scopes: response.scopes,
807
+ scopeKeys,
808
+ cursor: response.nextCursor,
809
+ verifiedRoot: response.integrity?.commitChainRoot ?? request?.verifiedRoot ?? null,
810
+ });
811
+ }
812
+ return subscriptions;
813
+ }
814
+ function serializeRealtimeSubscriptions(subscriptions) {
815
+ return subscriptions.map((subscription) => ({
816
+ id: subscription.id,
817
+ table: subscription.table,
818
+ scopes: subscription.scopes,
819
+ cursor: subscription.cursor,
820
+ verifiedRoot: subscription.verifiedRoot ?? null,
821
+ }));
822
+ }
823
+ function recordPushExecutionSideEffects(ctx, summary) {
824
+ recordRequestEventInBackground(() => ({
825
+ partitionId: ctx.partitionId,
826
+ requestId: ctx.requestId,
827
+ traceId: ctx.traceContext.traceId,
828
+ spanId: ctx.traceContext.spanId,
829
+ eventType: 'push',
830
+ syncPath: ctx.syncPath,
831
+ actorId: ctx.auth.actorId,
832
+ clientId: ctx.clientId,
833
+ transportPath: ctx.transportPath,
834
+ statusCode: 200,
835
+ outcome: summary.outcome,
836
+ responseStatus: normalizeResponseStatus(200, summary.outcome),
837
+ durationMs: summary.durationMs,
838
+ errorCode: firstPushErrorCode(summary.results),
839
+ commitSeq: summary.commitSeq,
840
+ operationCount: summary.operationCount,
841
+ tables: summary.tables,
842
+ payloadSnapshot: summary.payloadSnapshot,
843
+ }));
844
+ emitConsoleLiveEvent(consoleLiveEmitter, 'push', () => ({
845
+ partitionId: ctx.partitionId,
846
+ requestId: ctx.requestId,
847
+ traceId: ctx.traceContext.traceId,
848
+ spanId: ctx.traceContext.spanId,
849
+ actorId: ctx.auth.actorId,
850
+ clientId: ctx.clientId,
851
+ transportPath: ctx.transportPath,
852
+ syncPath: ctx.syncPath,
853
+ outcome: summary.outcome,
854
+ statusCode: 200,
855
+ durationMs: summary.durationMs,
856
+ commitSeq: summary.commitSeq,
857
+ operationCount: summary.operationCount,
858
+ tables: summary.tables,
859
+ }));
860
+ }
861
+ function maybeCountPushConflicts(ctx, results, enabled) {
862
+ if (enabled !== true) {
863
+ return;
864
+ }
865
+ const detectedConflicts = results.reduce((count, result) => count + (result.status === 'conflict' ? 1 : 0), 0);
866
+ if (detectedConflicts <= 0) {
867
+ return;
868
+ }
869
+ countSyncMetric('sync.conflicts.detected', detectedConflicts, {
870
+ attributes: {
871
+ syncPath: ctx.syncPath,
872
+ transportPath: ctx.transportPath,
873
+ },
874
+ });
875
+ }
876
+ function emitCommitLiveEvents(ctx, pushedCommits) {
877
+ for (const pushed of pushedCommits) {
878
+ if (pushed.response.ok !== true ||
879
+ pushed.response.status !== 'applied' ||
880
+ typeof pushed.response.commitSeq !== 'number') {
881
+ continue;
882
+ }
883
+ emitConsoleLiveEvent(consoleLiveEmitter, 'commit', () => ({
884
+ partitionId: ctx.partitionId,
885
+ commitSeq: pushed.response.commitSeq,
886
+ actorId: ctx.auth.actorId,
887
+ clientId: ctx.clientId,
888
+ affectedTables: pushed.affectedTables,
889
+ }));
890
+ }
891
+ }
892
+ async function executePushCommitBatchWithSideEffects(ctx, pushBodies, execOptions = {}) {
893
+ const timer = createSyncTimer();
894
+ const totalOperationCount = pushBodies.reduce((count, pushBody) => count + (pushBody.operations?.length ?? 0), 0);
895
+ const executedPushes = await pushCommitBatch({
896
+ db: options.db,
897
+ dialect: options.dialect,
898
+ handlers: handlerRegistry,
899
+ plugins: options.plugins,
900
+ auth: ctx.auth,
901
+ validateCommit: validateAuthLeaseCommit,
902
+ suppressTelemetry: true,
903
+ requests: pushBodies.map((pushBody) => ({
904
+ clientId: ctx.clientId,
905
+ clientCommitId: pushBody.clientCommitId,
906
+ operations: pushBody.operations,
907
+ schemaVersion: pushBody.schemaVersion,
908
+ authLease: pushBody.authLease,
909
+ })),
910
+ });
911
+ const affectedTables = new Set();
912
+ for (const pushed of executedPushes) {
913
+ for (const table of pushed.affectedTables) {
914
+ affectedTables.add(table);
915
+ }
916
+ }
917
+ const pushDurationMs = timer();
918
+ const latestCommitSeq = executedPushes.reduce((latest, pushed) => {
919
+ if (typeof pushed.response.commitSeq === 'number') {
920
+ return Math.max(latest, pushed.response.commitSeq);
921
+ }
922
+ return latest;
923
+ }, 0);
924
+ const aggregateStatus = executedPushes.every((pushed) => pushed.response.status === 'cached')
925
+ ? 'cached'
926
+ : executedPushes.every((pushed) => pushed.response.status === 'applied' ||
927
+ pushed.response.status === 'cached')
928
+ ? 'applied'
929
+ : 'rejected';
930
+ const aggregatedResults = executedPushes.flatMap((pushed) => pushed.response.results);
931
+ logSyncEvent({
932
+ event: 'sync.push',
933
+ userId: ctx.auth.actorId,
934
+ durationMs: pushDurationMs,
935
+ operationCount: totalOperationCount,
936
+ status: aggregateStatus,
937
+ commitSeq: latestCommitSeq > 0 ? latestCommitSeq : undefined,
938
+ });
939
+ recordPushExecutionSideEffects(ctx, {
940
+ durationMs: pushDurationMs,
941
+ outcome: aggregateStatus,
942
+ commitSeq: latestCommitSeq > 0 ? latestCommitSeq : null,
943
+ operationCount: totalOperationCount,
944
+ tables: Array.from(affectedTables),
945
+ results: aggregatedResults,
946
+ payloadSnapshot: shouldCaptureRequestPayloadSnapshots
947
+ ? {
948
+ request: {
949
+ clientId: ctx.clientId,
950
+ commits: pushBodies.map((pushBody) => ({
951
+ clientCommitId: pushBody.clientCommitId,
952
+ schemaVersion: pushBody.schemaVersion,
953
+ authLease: pushBody.authLease,
954
+ operations: pushBody.operations,
955
+ })),
956
+ },
957
+ response: {
958
+ ok: true,
959
+ commits: executedPushes.map((pushed, index) => ({
960
+ clientCommitId: pushBodies[index]?.clientCommitId ?? '',
961
+ ...pushed.response,
962
+ })),
963
+ },
964
+ }
965
+ : null,
966
+ });
967
+ maybeCountPushConflicts(ctx, aggregatedResults, execOptions.countConflictsMetric);
968
+ await notifyRealtimeForAppliedPushes(ctx, executedPushes);
969
+ emitCommitLiveEvents(ctx, executedPushes);
970
+ return executedPushes;
971
+ }
972
+ async function executePushCommitWithSideEffects(ctx, pushBody, execOptions = {}) {
973
+ const timer = createSyncTimer();
974
+ const pushOps = pushBody.operations ?? [];
975
+ const pushed = await pushCommit({
976
+ db: options.db,
977
+ dialect: options.dialect,
978
+ handlers: handlerRegistry,
979
+ plugins: options.plugins,
980
+ auth: ctx.auth,
981
+ validateCommit: validateAuthLeaseCommit,
982
+ request: {
983
+ clientId: ctx.clientId,
984
+ clientCommitId: pushBody.clientCommitId,
985
+ operations: pushBody.operations,
986
+ schemaVersion: pushBody.schemaVersion,
987
+ authLease: pushBody.authLease,
988
+ },
989
+ });
990
+ const pushDurationMs = timer();
991
+ logSyncEvent({
992
+ event: 'sync.push',
993
+ userId: ctx.auth.actorId,
994
+ durationMs: pushDurationMs,
995
+ operationCount: pushOps.length,
996
+ status: pushed.response.status,
997
+ commitSeq: pushed.response.commitSeq,
998
+ });
999
+ recordPushExecutionSideEffects(ctx, {
1000
+ durationMs: pushDurationMs,
1001
+ outcome: pushed.response.status,
1002
+ commitSeq: pushed.response.commitSeq ?? null,
1003
+ operationCount: pushOps.length,
1004
+ tables: pushed.affectedTables,
1005
+ results: pushed.response.results,
1006
+ payloadSnapshot: shouldCaptureRequestPayloadSnapshots
1007
+ ? {
1008
+ request: {
1009
+ clientId: ctx.clientId,
1010
+ clientCommitId: pushBody.clientCommitId,
1011
+ schemaVersion: pushBody.schemaVersion,
1012
+ authLease: pushBody.authLease,
1013
+ operations: pushBody.operations,
1014
+ },
1015
+ response: pushed.response,
1016
+ }
1017
+ : null,
1018
+ });
1019
+ maybeCountPushConflicts(ctx, pushed.response.results, execOptions.countConflictsMetric);
1020
+ if (execOptions.deferRealtimeNotifications !== true) {
1021
+ await notifyRealtimeForAppliedPushes(ctx, [pushed]);
1022
+ }
1023
+ emitCommitLiveEvents(ctx, [pushed]);
1024
+ return pushed;
1025
+ }
1026
+ // -------------------------------------------------------------------------
1027
+ // Rate limiting (optional)
1028
+ // -------------------------------------------------------------------------
1029
+ const rateLimitConfig = config.rateLimit;
1030
+ if (rateLimitConfig !== false) {
1031
+ const pullRateLimit = rateLimitConfig?.pull ?? DEFAULT_SYNC_RATE_LIMITS.pull;
1032
+ const pushRateLimit = rateLimitConfig?.push ?? DEFAULT_SYNC_RATE_LIMITS.push;
1033
+ const createAuthBasedRateLimiter = (limitConfig) => {
1034
+ if (limitConfig === false || !limitConfig)
1035
+ return null;
1036
+ return createRateLimiter({
1037
+ ...limitConfig,
1038
+ keyGenerator: async (c) => {
1039
+ const auth = await getAuth(c);
1040
+ return auth?.actorId ?? null;
1041
+ },
1042
+ });
1043
+ };
1044
+ const pullLimiter = createAuthBasedRateLimiter(pullRateLimit);
1045
+ const pushLimiter = createAuthBasedRateLimiter(pushRateLimit);
1046
+ const syncRateLimiter = async (c, next) => {
1047
+ if (!pullLimiter && !pushLimiter)
1048
+ return next();
1049
+ let shouldApplyPull = pullLimiter !== null;
1050
+ let shouldApplyPush = pushLimiter !== null;
1051
+ if (pullLimiter && pushLimiter && c.req.method === 'POST') {
1052
+ const parsed = await readLimitedSyncJsonBody(c);
1053
+ if (!parsed.ok) {
1054
+ if (parsed.failure) {
1055
+ await recordHttpCombinedReadFailure(c, parsed.failure);
1056
+ }
1057
+ return parsed.response;
1058
+ }
1059
+ if (parsed.value !== null && typeof parsed.value === 'object') {
1060
+ shouldApplyPull = Reflect.get(parsed.value, 'pull') !== undefined;
1061
+ shouldApplyPush = Reflect.get(parsed.value, 'push') !== undefined;
1062
+ }
1063
+ }
1064
+ if (pullLimiter && shouldApplyPull && pushLimiter && shouldApplyPush) {
1065
+ return pullLimiter(c, async () => {
1066
+ const pushResult = await pushLimiter(c, next);
1067
+ if (pushResult instanceof Response) {
1068
+ c.res = pushResult;
1069
+ }
1070
+ });
1071
+ }
1072
+ if (pullLimiter && shouldApplyPull) {
1073
+ return pullLimiter(c, next);
1074
+ }
1075
+ if (pushLimiter && shouldApplyPush) {
1076
+ return pushLimiter(c, next);
1077
+ }
1078
+ return next();
1079
+ };
1080
+ routes.use('/', syncRateLimiter);
1081
+ }
1082
+ async function handleRealtimeEvent(event) {
1083
+ if (!wsConnectionManager)
1084
+ return;
1085
+ if (event.type !== 'commit')
1086
+ return;
1087
+ if (event.sourceInstanceId && event.sourceInstanceId === instanceId)
1088
+ return;
1089
+ const commitSeq = event.commitSeq;
1090
+ const partitionId = event.partitionId ?? 'default';
1091
+ const scopeKeys = event.scopeKeys && event.scopeKeys.length > 0
1092
+ ? event.scopeKeys
1093
+ : await readCommitScopeKeys(options.db, commitSeq, partitionId);
1094
+ if (scopeKeys.length === 0)
1095
+ return;
1096
+ wsConnectionManager.notifyScopeKeys(scopeKeys, commitSeq);
1097
+ }
1098
+ return {
1099
+ routes,
1100
+ config,
1101
+ options,
1102
+ authLeaseRoutesConfig,
1103
+ corsConfig,
1104
+ handlerRegistry,
1105
+ binarySyncPackChangeRowEncoders,
1106
+ maxPullLimitCommits,
1107
+ maxSubscriptionsPerPull,
1108
+ maxPullLimitSnapshotRows,
1109
+ maxPullMaxSnapshotPages,
1110
+ maxOperationsPerPush,
1111
+ maxSyncRequestJsonBytes,
1112
+ maxSyncBinaryPackBytes,
1113
+ maxSnapshotChunkResponseBytes,
1114
+ maxSnapshotArtifactResponseBytes,
1115
+ requiredSchemaVersion,
1116
+ latestSchemaVersion,
1117
+ consoleLiveEmitter,
1118
+ shouldEmitConsoleLiveEvents,
1119
+ shouldRecordRequestEvents,
1120
+ shouldCaptureRequestPayloadSnapshots,
1121
+ getAuth,
1122
+ createAuditScopeResolver,
1123
+ readVisibleAuditChanges,
1124
+ readAuditDebugRequestEvents,
1125
+ validateAuthLeaseCommit,
1126
+ readLimitedSyncJsonBody,
1127
+ websocketConfig,
1128
+ wsConnectionManager,
1129
+ realtimeBroadcaster,
1130
+ instanceId,
1131
+ logAsyncFailureOnce,
1132
+ triggerAutoMaintenance,
1133
+ recordRequestEventInBackground,
1134
+ recordRealtimeEventInBackground,
1135
+ recordHttpCombinedFailure,
1136
+ recordHttpCombinedReadFailure,
1137
+ notifyRealtimeForAppliedPushes,
1138
+ buildRealtimeSubscriptionsForPull,
1139
+ serializeRealtimeSubscriptions,
1140
+ recordPushExecutionSideEffects,
1141
+ maybeCountPushConflicts,
1142
+ emitCommitLiveEvents,
1143
+ executePushCommitBatchWithSideEffects,
1144
+ executePushCommitWithSideEffects,
1145
+ };
1146
+ }
1147
+ //# sourceMappingURL=context.js.map