@syncular/server 0.0.6-95 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (601) hide show
  1. package/README.md +1 -2
  2. package/dist/auth-leases.d.ts +85 -0
  3. package/dist/auth-leases.d.ts.map +1 -0
  4. package/dist/auth-leases.js +368 -0
  5. package/dist/auth-leases.js.map +1 -0
  6. package/dist/better-sqlite3.d.ts +22 -0
  7. package/dist/better-sqlite3.d.ts.map +1 -0
  8. package/dist/better-sqlite3.js +16 -0
  9. package/dist/better-sqlite3.js.map +1 -0
  10. package/dist/blobs/access.d.ts +35 -0
  11. package/dist/blobs/access.d.ts.map +1 -0
  12. package/dist/blobs/access.js +149 -0
  13. package/dist/blobs/access.js.map +1 -0
  14. package/dist/blobs/adapters/database.d.ts +26 -9
  15. package/dist/blobs/adapters/database.d.ts.map +1 -1
  16. package/dist/blobs/adapters/database.js +68 -23
  17. package/dist/blobs/adapters/database.js.map +1 -1
  18. package/dist/blobs/index.d.ts +1 -0
  19. package/dist/blobs/index.d.ts.map +1 -1
  20. package/dist/blobs/index.js +5 -4
  21. package/dist/blobs/index.js.map +1 -1
  22. package/dist/blobs/manager.d.ts +69 -44
  23. package/dist/blobs/manager.d.ts.map +1 -1
  24. package/dist/blobs/manager.js +250 -65
  25. package/dist/blobs/manager.js.map +1 -1
  26. package/dist/blobs/migrate.d.ts.map +1 -1
  27. package/dist/blobs/migrate.js +16 -8
  28. package/dist/blobs/migrate.js.map +1 -1
  29. package/dist/blobs/types.d.ts +4 -0
  30. package/dist/blobs/types.d.ts.map +1 -1
  31. package/dist/bun-sqlite.d.ts +19 -0
  32. package/dist/bun-sqlite.d.ts.map +1 -0
  33. package/dist/bun-sqlite.js +19 -0
  34. package/dist/bun-sqlite.js.map +1 -0
  35. package/dist/clients.d.ts +1 -0
  36. package/dist/clients.d.ts.map +1 -1
  37. package/dist/clients.js.map +1 -1
  38. package/dist/cloudflare/durable-object.d.ts +93 -0
  39. package/dist/cloudflare/durable-object.d.ts.map +1 -0
  40. package/dist/cloudflare/durable-object.js +210 -0
  41. package/dist/cloudflare/durable-object.js.map +1 -0
  42. package/dist/cloudflare/index.d.ts +22 -0
  43. package/dist/cloudflare/index.d.ts.map +1 -0
  44. package/dist/cloudflare/index.js +22 -0
  45. package/dist/cloudflare/index.js.map +1 -0
  46. package/dist/cloudflare/r2.d.ts +180 -0
  47. package/dist/cloudflare/r2.d.ts.map +1 -0
  48. package/dist/cloudflare/r2.js +258 -0
  49. package/dist/cloudflare/r2.js.map +1 -0
  50. package/dist/cloudflare/scope-cache.d.ts +54 -0
  51. package/dist/cloudflare/scope-cache.d.ts.map +1 -0
  52. package/dist/cloudflare/scope-cache.js +223 -0
  53. package/dist/cloudflare/scope-cache.js.map +1 -0
  54. package/dist/cloudflare/sentry.d.ts +47 -0
  55. package/dist/cloudflare/sentry.d.ts.map +1 -0
  56. package/dist/cloudflare/sentry.js +163 -0
  57. package/dist/cloudflare/sentry.js.map +1 -0
  58. package/dist/cloudflare/worker.d.ts +46 -0
  59. package/dist/cloudflare/worker.d.ts.map +1 -0
  60. package/dist/cloudflare/worker.js +63 -0
  61. package/dist/cloudflare/worker.js.map +1 -0
  62. package/dist/commit-integrity.d.ts +38 -0
  63. package/dist/commit-integrity.d.ts.map +1 -0
  64. package/dist/commit-integrity.js +260 -0
  65. package/dist/commit-integrity.js.map +1 -0
  66. package/dist/compaction.js.map +1 -1
  67. package/dist/crdt-yjs/index.d.ts +99 -0
  68. package/dist/crdt-yjs/index.d.ts.map +1 -0
  69. package/dist/crdt-yjs/index.js +629 -0
  70. package/dist/crdt-yjs/index.js.map +1 -0
  71. package/dist/d1.d.ts +13 -0
  72. package/dist/d1.d.ts.map +1 -0
  73. package/dist/d1.js +14 -0
  74. package/dist/d1.js.map +1 -0
  75. package/dist/dialect/base.d.ts +11 -1
  76. package/dist/dialect/base.d.ts.map +1 -1
  77. package/dist/dialect/base.js +43 -6
  78. package/dist/dialect/base.js.map +1 -1
  79. package/dist/dialect/helpers.d.ts +6 -0
  80. package/dist/dialect/helpers.d.ts.map +1 -1
  81. package/dist/dialect/helpers.js +24 -0
  82. package/dist/dialect/helpers.js.map +1 -1
  83. package/dist/dialect/index.js +3 -3
  84. package/dist/dialect/types.d.ts +40 -0
  85. package/dist/dialect/types.d.ts.map +1 -1
  86. package/dist/encrypted-crdt.d.ts +67 -0
  87. package/dist/encrypted-crdt.d.ts.map +1 -0
  88. package/dist/encrypted-crdt.js +426 -0
  89. package/dist/encrypted-crdt.js.map +1 -0
  90. package/dist/errors.d.ts +10 -0
  91. package/dist/errors.d.ts.map +1 -0
  92. package/dist/errors.js +13 -0
  93. package/dist/errors.js.map +1 -0
  94. package/dist/filesystem/index.d.ts +44 -0
  95. package/dist/filesystem/index.d.ts.map +1 -0
  96. package/dist/filesystem/index.js +164 -0
  97. package/dist/filesystem/index.js.map +1 -0
  98. package/dist/handlers/collection.d.ts +11 -3
  99. package/dist/handlers/collection.d.ts.map +1 -1
  100. package/dist/handlers/collection.js +34 -56
  101. package/dist/handlers/collection.js.map +1 -1
  102. package/dist/handlers/create-handler.d.ts +31 -7
  103. package/dist/handlers/create-handler.d.ts.map +1 -1
  104. package/dist/handlers/create-handler.js +332 -115
  105. package/dist/handlers/create-handler.js.map +1 -1
  106. package/dist/handlers/index.js +3 -3
  107. package/dist/handlers/types.d.ts +86 -1
  108. package/dist/handlers/types.d.ts.map +1 -1
  109. package/dist/helpers/conflict.js.map +1 -1
  110. package/dist/helpers/emitted-change.js.map +1 -1
  111. package/dist/helpers/index.d.ts +2 -0
  112. package/dist/helpers/index.d.ts.map +1 -1
  113. package/dist/helpers/index.js +6 -4
  114. package/dist/helpers/index.js.map +1 -1
  115. package/dist/helpers/paginate.js.map +1 -1
  116. package/dist/helpers/scope-authorization.d.ts +7 -0
  117. package/dist/helpers/scope-authorization.d.ts.map +1 -0
  118. package/dist/helpers/scope-authorization.js +19 -0
  119. package/dist/helpers/scope-authorization.js.map +1 -0
  120. package/dist/helpers/scope-commit-index.d.ts +12 -0
  121. package/dist/helpers/scope-commit-index.d.ts.map +1 -0
  122. package/dist/helpers/scope-commit-index.js +35 -0
  123. package/dist/helpers/scope-commit-index.js.map +1 -0
  124. package/dist/helpers/scope-strings.js.map +1 -1
  125. package/dist/hono/api-key-auth.d.ts +49 -0
  126. package/dist/hono/api-key-auth.d.ts.map +1 -0
  127. package/dist/hono/api-key-auth.js +108 -0
  128. package/dist/hono/api-key-auth.js.map +1 -0
  129. package/dist/hono/audit-redaction.d.ts +20 -0
  130. package/dist/hono/audit-redaction.d.ts.map +1 -0
  131. package/dist/hono/audit-redaction.js +85 -0
  132. package/dist/hono/audit-redaction.js.map +1 -0
  133. package/dist/hono/blobs.d.ts +75 -0
  134. package/dist/hono/blobs.d.ts.map +1 -0
  135. package/dist/hono/blobs.js +586 -0
  136. package/dist/hono/blobs.js.map +1 -0
  137. package/dist/hono/console/gateway.d.ts +42 -0
  138. package/dist/hono/console/gateway.d.ts.map +1 -0
  139. package/dist/hono/console/gateway.js +2158 -0
  140. package/dist/hono/console/gateway.js.map +1 -0
  141. package/dist/hono/console/live-auth.d.ts +7 -0
  142. package/dist/hono/console/live-auth.d.ts.map +1 -0
  143. package/dist/hono/console/live-auth.js +39 -0
  144. package/dist/hono/console/live-auth.js.map +1 -0
  145. package/dist/hono/console/route-descriptor.d.ts +6 -0
  146. package/dist/hono/console/route-descriptor.d.ts.map +1 -0
  147. package/dist/hono/console/route-descriptor.js +16 -0
  148. package/dist/hono/console/route-descriptor.js.map +1 -0
  149. package/dist/hono/console/routes/api-keys.d.ts +8 -0
  150. package/dist/hono/console/routes/api-keys.d.ts.map +1 -0
  151. package/dist/hono/console/routes/api-keys.js +575 -0
  152. package/dist/hono/console/routes/api-keys.js.map +1 -0
  153. package/dist/hono/console/routes/clients.d.ts +8 -0
  154. package/dist/hono/console/routes/clients.d.ts.map +1 -0
  155. package/dist/hono/console/routes/clients.js +322 -0
  156. package/dist/hono/console/routes/clients.js.map +1 -0
  157. package/dist/hono/console/routes/commits.d.ts +8 -0
  158. package/dist/hono/console/routes/commits.d.ts.map +1 -0
  159. package/dist/hono/console/routes/commits.js +882 -0
  160. package/dist/hono/console/routes/commits.js.map +1 -0
  161. package/dist/hono/console/routes/context.d.ts +188 -0
  162. package/dist/hono/console/routes/context.d.ts.map +1 -0
  163. package/dist/hono/console/routes/context.js +633 -0
  164. package/dist/hono/console/routes/context.js.map +1 -0
  165. package/dist/hono/console/routes/events.d.ts +8 -0
  166. package/dist/hono/console/routes/events.d.ts.map +1 -0
  167. package/dist/hono/console/routes/events.js +501 -0
  168. package/dist/hono/console/routes/events.js.map +1 -0
  169. package/dist/hono/console/routes/maintenance.d.ts +8 -0
  170. package/dist/hono/console/routes/maintenance.d.ts.map +1 -0
  171. package/dist/hono/console/routes/maintenance.js +341 -0
  172. package/dist/hono/console/routes/maintenance.js.map +1 -0
  173. package/dist/hono/console/routes/shared.d.ts +174 -0
  174. package/dist/hono/console/routes/shared.d.ts.map +1 -0
  175. package/dist/hono/console/routes/shared.js +583 -0
  176. package/dist/hono/console/routes/shared.js.map +1 -0
  177. package/dist/hono/console/routes/stats.d.ts +8 -0
  178. package/dist/hono/console/routes/stats.d.ts.map +1 -0
  179. package/dist/hono/console/routes/stats.js +295 -0
  180. package/dist/hono/console/routes/stats.js.map +1 -0
  181. package/dist/hono/console/routes/storage.d.ts +8 -0
  182. package/dist/hono/console/routes/storage.d.ts.map +1 -0
  183. package/dist/hono/console/routes/storage.js +121 -0
  184. package/dist/hono/console/routes/storage.js.map +1 -0
  185. package/dist/hono/console/routes.d.ts +36 -0
  186. package/dist/hono/console/routes.d.ts.map +1 -0
  187. package/dist/hono/console/routes.js +112 -0
  188. package/dist/hono/console/routes.js.map +1 -0
  189. package/dist/hono/console/schema-errors.d.ts +2 -0
  190. package/dist/hono/console/schema-errors.d.ts.map +1 -0
  191. package/dist/hono/console/schema-errors.js +17 -0
  192. package/dist/hono/console/schema-errors.js.map +1 -0
  193. package/dist/hono/console/schemas.d.ts +1515 -0
  194. package/dist/hono/console/schemas.d.ts.map +1 -0
  195. package/dist/hono/console/schemas.js +661 -0
  196. package/dist/hono/console/schemas.js.map +1 -0
  197. package/dist/hono/console/types.d.ts +213 -0
  198. package/dist/hono/console/types.d.ts.map +1 -0
  199. package/dist/hono/console/types.js +2 -0
  200. package/dist/hono/console/types.js.map +1 -0
  201. package/dist/hono/console/ui.d.ts +38 -0
  202. package/dist/hono/console/ui.d.ts.map +1 -0
  203. package/dist/hono/console/ui.js +43 -0
  204. package/dist/hono/console/ui.js.map +1 -0
  205. package/dist/hono/create-server.d.ts +71 -0
  206. package/dist/hono/create-server.d.ts.map +1 -0
  207. package/dist/hono/create-server.js +121 -0
  208. package/dist/hono/create-server.js.map +1 -0
  209. package/dist/hono/errors.d.ts +13 -0
  210. package/dist/hono/errors.d.ts.map +1 -0
  211. package/dist/hono/errors.js +21 -0
  212. package/dist/hono/errors.js.map +1 -0
  213. package/dist/hono/index.d.ts +20 -0
  214. package/dist/hono/index.d.ts.map +1 -0
  215. package/dist/hono/index.js +31 -0
  216. package/dist/hono/index.js.map +1 -0
  217. package/dist/hono/openapi.d.ts +72 -0
  218. package/dist/hono/openapi.d.ts.map +1 -0
  219. package/dist/hono/openapi.js +99 -0
  220. package/dist/hono/openapi.js.map +1 -0
  221. package/dist/hono/proxy/connection-manager.d.ts +78 -0
  222. package/dist/hono/proxy/connection-manager.d.ts.map +1 -0
  223. package/dist/hono/proxy/connection-manager.js +251 -0
  224. package/dist/hono/proxy/connection-manager.js.map +1 -0
  225. package/dist/hono/proxy/index.d.ts +8 -0
  226. package/dist/hono/proxy/index.d.ts.map +1 -0
  227. package/dist/hono/proxy/index.js +8 -0
  228. package/dist/hono/proxy/index.js.map +1 -0
  229. package/dist/hono/proxy/routes.d.ts +86 -0
  230. package/dist/hono/proxy/routes.d.ts.map +1 -0
  231. package/dist/hono/proxy/routes.js +183 -0
  232. package/dist/hono/proxy/routes.js.map +1 -0
  233. package/dist/hono/rate-limit.d.ts +101 -0
  234. package/dist/hono/rate-limit.d.ts.map +1 -0
  235. package/dist/hono/rate-limit.js +184 -0
  236. package/dist/hono/rate-limit.js.map +1 -0
  237. package/dist/hono/realtime-sync-packs.d.ts +43 -0
  238. package/dist/hono/realtime-sync-packs.d.ts.map +1 -0
  239. package/dist/hono/realtime-sync-packs.js +219 -0
  240. package/dist/hono/realtime-sync-packs.js.map +1 -0
  241. package/dist/hono/routes/audit.d.ts +12 -0
  242. package/dist/hono/routes/audit.d.ts.map +1 -0
  243. package/dist/hono/routes/audit.js +385 -0
  244. package/dist/hono/routes/audit.js.map +1 -0
  245. package/dist/hono/routes/auth-leases.d.ts +8 -0
  246. package/dist/hono/routes/auth-leases.d.ts.map +1 -0
  247. package/dist/hono/routes/auth-leases.js +88 -0
  248. package/dist/hono/routes/auth-leases.js.map +1 -0
  249. package/dist/hono/routes/combined.d.ts +8 -0
  250. package/dist/hono/routes/combined.d.ts.map +1 -0
  251. package/dist/hono/routes/combined.js +392 -0
  252. package/dist/hono/routes/combined.js.map +1 -0
  253. package/dist/hono/routes/context.d.ts +314 -0
  254. package/dist/hono/routes/context.d.ts.map +1 -0
  255. package/dist/hono/routes/context.js +1147 -0
  256. package/dist/hono/routes/context.js.map +1 -0
  257. package/dist/hono/routes/health.d.ts +8 -0
  258. package/dist/hono/routes/health.d.ts.map +1 -0
  259. package/dist/hono/routes/health.js +16 -0
  260. package/dist/hono/routes/health.js.map +1 -0
  261. package/dist/hono/routes/realtime.d.ts +9 -0
  262. package/dist/hono/routes/realtime.d.ts.map +1 -0
  263. package/dist/hono/routes/realtime.js +626 -0
  264. package/dist/hono/routes/realtime.js.map +1 -0
  265. package/dist/hono/routes/shared.d.ts +689 -0
  266. package/dist/hono/routes/shared.d.ts.map +1 -0
  267. package/dist/hono/routes/shared.js +972 -0
  268. package/dist/hono/routes/shared.js.map +1 -0
  269. package/dist/hono/routes/snapshots.d.ts +10 -0
  270. package/dist/hono/routes/snapshots.d.ts.map +1 -0
  271. package/dist/hono/routes/snapshots.js +281 -0
  272. package/dist/hono/routes/snapshots.js.map +1 -0
  273. package/dist/hono/routes.d.ts +19 -0
  274. package/dist/hono/routes.d.ts.map +1 -0
  275. package/dist/hono/routes.js +37 -0
  276. package/dist/hono/routes.js.map +1 -0
  277. package/dist/hono/validation.d.ts +5 -0
  278. package/dist/hono/validation.d.ts.map +1 -0
  279. package/dist/hono/validation.js +47 -0
  280. package/dist/hono/validation.js.map +1 -0
  281. package/dist/hono/websocket-origin.d.ts +9 -0
  282. package/dist/hono/websocket-origin.d.ts.map +1 -0
  283. package/dist/hono/websocket-origin.js +96 -0
  284. package/dist/hono/websocket-origin.js.map +1 -0
  285. package/dist/hono/ws.d.ts +341 -0
  286. package/dist/hono/ws.d.ts.map +1 -0
  287. package/dist/hono/ws.js +711 -0
  288. package/dist/hono/ws.js.map +1 -0
  289. package/dist/index.d.ts +6 -0
  290. package/dist/index.d.ts.map +1 -1
  291. package/dist/index.js +24 -18
  292. package/dist/index.js.map +1 -1
  293. package/dist/libsql.d.ts +29 -0
  294. package/dist/libsql.d.ts.map +1 -0
  295. package/dist/libsql.js +25 -0
  296. package/dist/libsql.js.map +1 -0
  297. package/dist/migrate.js.map +1 -1
  298. package/dist/neon.d.ts +21 -0
  299. package/dist/neon.d.ts.map +1 -0
  300. package/dist/neon.js +22 -0
  301. package/dist/neon.js.map +1 -0
  302. package/dist/notify.d.ts +30 -0
  303. package/dist/notify.d.ts.map +1 -1
  304. package/dist/notify.js +160 -41
  305. package/dist/notify.js.map +1 -1
  306. package/dist/pglite.d.ts +37 -0
  307. package/dist/pglite.d.ts.map +1 -0
  308. package/dist/pglite.js +37 -0
  309. package/dist/pglite.js.map +1 -0
  310. package/dist/plugins/index.d.ts +2 -0
  311. package/dist/plugins/index.d.ts.map +1 -0
  312. package/dist/plugins/index.js +2 -0
  313. package/dist/plugins/index.js.map +1 -0
  314. package/dist/plugins/types.d.ts +73 -0
  315. package/dist/plugins/types.d.ts.map +1 -0
  316. package/dist/plugins/types.js +30 -0
  317. package/dist/plugins/types.js.map +1 -0
  318. package/dist/postgres/index.d.ts +68 -0
  319. package/dist/postgres/index.d.ts.map +1 -0
  320. package/dist/postgres/index.js +924 -0
  321. package/dist/postgres/index.js.map +1 -0
  322. package/dist/proxy/collection.d.ts +0 -2
  323. package/dist/proxy/collection.d.ts.map +1 -1
  324. package/dist/proxy/collection.js +2 -17
  325. package/dist/proxy/collection.js.map +1 -1
  326. package/dist/proxy/handler.d.ts +1 -1
  327. package/dist/proxy/handler.d.ts.map +1 -1
  328. package/dist/proxy/handler.js +3 -4
  329. package/dist/proxy/handler.js.map +1 -1
  330. package/dist/proxy/index.d.ts +1 -1
  331. package/dist/proxy/index.d.ts.map +1 -1
  332. package/dist/proxy/index.js +3 -3
  333. package/dist/proxy/index.js.map +1 -1
  334. package/dist/proxy/mutation-detector.js.map +1 -1
  335. package/dist/proxy/oplog.d.ts.map +1 -1
  336. package/dist/proxy/oplog.js +32 -8
  337. package/dist/proxy/oplog.js.map +1 -1
  338. package/dist/prune.d.ts +8 -1
  339. package/dist/prune.d.ts.map +1 -1
  340. package/dist/prune.js +68 -28
  341. package/dist/prune.js.map +1 -1
  342. package/dist/pull.d.ts +31 -0
  343. package/dist/pull.d.ts.map +1 -1
  344. package/dist/pull.js +1014 -474
  345. package/dist/pull.js.map +1 -1
  346. package/dist/push.d.ts +36 -2
  347. package/dist/push.d.ts.map +1 -1
  348. package/dist/push.js +603 -358
  349. package/dist/push.js.map +1 -1
  350. package/dist/realtime/in-memory.js.map +1 -1
  351. package/dist/realtime/index.d.ts +2 -1
  352. package/dist/realtime/index.d.ts.map +1 -1
  353. package/dist/realtime/index.js +2 -1
  354. package/dist/realtime/index.js.map +1 -1
  355. package/dist/realtime/types.d.ts +12 -0
  356. package/dist/realtime/types.d.ts.map +1 -1
  357. package/dist/realtime/types.js +13 -1
  358. package/dist/realtime/types.js.map +1 -1
  359. package/dist/relay/client-role/forward-engine.d.ts +63 -0
  360. package/dist/relay/client-role/forward-engine.d.ts.map +1 -0
  361. package/dist/relay/client-role/forward-engine.js +267 -0
  362. package/dist/relay/client-role/forward-engine.js.map +1 -0
  363. package/dist/relay/client-role/index.d.ts +9 -0
  364. package/dist/relay/client-role/index.d.ts.map +1 -0
  365. package/dist/relay/client-role/index.js +9 -0
  366. package/dist/relay/client-role/index.js.map +1 -0
  367. package/dist/relay/client-role/pull-engine.d.ts +72 -0
  368. package/dist/relay/client-role/pull-engine.d.ts.map +1 -0
  369. package/dist/relay/client-role/pull-engine.js +249 -0
  370. package/dist/relay/client-role/pull-engine.js.map +1 -0
  371. package/dist/relay/client-role/sequence-mapper.d.ts +65 -0
  372. package/dist/relay/client-role/sequence-mapper.d.ts.map +1 -0
  373. package/dist/relay/client-role/sequence-mapper.js +161 -0
  374. package/dist/relay/client-role/sequence-mapper.js.map +1 -0
  375. package/dist/relay/evaluation/relay-paths.d.ts +41 -0
  376. package/dist/relay/evaluation/relay-paths.d.ts.map +1 -0
  377. package/dist/relay/evaluation/relay-paths.js +504 -0
  378. package/dist/relay/evaluation/relay-paths.js.map +1 -0
  379. package/dist/relay/evaluation/rust-boundary.d.ts +47 -0
  380. package/dist/relay/evaluation/rust-boundary.d.ts.map +1 -0
  381. package/dist/relay/evaluation/rust-boundary.js +220 -0
  382. package/dist/relay/evaluation/rust-boundary.js.map +1 -0
  383. package/dist/relay/index.d.ts +37 -0
  384. package/dist/relay/index.d.ts.map +1 -0
  385. package/dist/relay/index.js +44 -0
  386. package/dist/relay/index.js.map +1 -0
  387. package/dist/relay/migrate.d.ts +18 -0
  388. package/dist/relay/migrate.d.ts.map +1 -0
  389. package/dist/relay/migrate.js +99 -0
  390. package/dist/relay/migrate.js.map +1 -0
  391. package/dist/relay/mode-manager.d.ts +60 -0
  392. package/dist/relay/mode-manager.d.ts.map +1 -0
  393. package/dist/relay/mode-manager.js +114 -0
  394. package/dist/relay/mode-manager.js.map +1 -0
  395. package/dist/relay/realtime.d.ts +90 -0
  396. package/dist/relay/realtime.d.ts.map +1 -0
  397. package/dist/relay/realtime.js +147 -0
  398. package/dist/relay/realtime.js.map +1 -0
  399. package/dist/relay/relay.d.ts +190 -0
  400. package/dist/relay/relay.d.ts.map +1 -0
  401. package/dist/relay/relay.js +320 -0
  402. package/dist/relay/relay.js.map +1 -0
  403. package/dist/relay/schema.d.ts +158 -0
  404. package/dist/relay/schema.d.ts.map +1 -0
  405. package/dist/relay/schema.js +7 -0
  406. package/dist/relay/schema.js.map +1 -0
  407. package/dist/relay/server-role/index.d.ts +56 -0
  408. package/dist/relay/server-role/index.d.ts.map +1 -0
  409. package/dist/relay/server-role/index.js +193 -0
  410. package/dist/relay/server-role/index.js.map +1 -0
  411. package/dist/relay/server-role/pull.d.ts +27 -0
  412. package/dist/relay/server-role/pull.d.ts.map +1 -0
  413. package/dist/relay/server-role/pull.js +24 -0
  414. package/dist/relay/server-role/pull.js.map +1 -0
  415. package/dist/relay/server-role/push.d.ts +29 -0
  416. package/dist/relay/server-role/push.d.ts.map +1 -0
  417. package/dist/relay/server-role/push.js +122 -0
  418. package/dist/relay/server-role/push.js.map +1 -0
  419. package/dist/s3/index.d.ts +83 -0
  420. package/dist/s3/index.d.ts.map +1 -0
  421. package/dist/s3/index.js +223 -0
  422. package/dist/s3/index.js.map +1 -0
  423. package/dist/schema.d.ts +137 -1
  424. package/dist/schema.d.ts.map +1 -1
  425. package/dist/schema.js +1 -0
  426. package/dist/schema.js.map +1 -1
  427. package/dist/service-worker/index.d.ts +114 -0
  428. package/dist/service-worker/index.d.ts.map +1 -0
  429. package/dist/service-worker/index.js +487 -0
  430. package/dist/service-worker/index.js.map +1 -0
  431. package/dist/snapshot-artifacts/sqlite-bun.d.ts +15 -0
  432. package/dist/snapshot-artifacts/sqlite-bun.d.ts.map +1 -0
  433. package/dist/snapshot-artifacts/sqlite-bun.js +128 -0
  434. package/dist/snapshot-artifacts/sqlite-bun.js.map +1 -0
  435. package/dist/snapshot-artifacts.d.ts +206 -0
  436. package/dist/snapshot-artifacts.d.ts.map +1 -0
  437. package/dist/snapshot-artifacts.js +545 -0
  438. package/dist/snapshot-artifacts.js.map +1 -0
  439. package/dist/snapshot-chunks/db-metadata.d.ts +18 -0
  440. package/dist/snapshot-chunks/db-metadata.d.ts.map +1 -1
  441. package/dist/snapshot-chunks/db-metadata.js +91 -63
  442. package/dist/snapshot-chunks/db-metadata.js.map +1 -1
  443. package/dist/snapshot-chunks/index.js +2 -2
  444. package/dist/snapshot-chunks/types.d.ts +2 -0
  445. package/dist/snapshot-chunks/types.d.ts.map +1 -1
  446. package/dist/snapshot-chunks.d.ts +33 -3
  447. package/dist/snapshot-chunks.d.ts.map +1 -1
  448. package/dist/snapshot-chunks.js +136 -55
  449. package/dist/snapshot-chunks.js.map +1 -1
  450. package/dist/sqlite/index.d.ts +53 -0
  451. package/dist/sqlite/index.d.ts.map +1 -0
  452. package/dist/sqlite/index.js +795 -0
  453. package/dist/sqlite/index.js.map +1 -0
  454. package/dist/sqlite3.d.ts +22 -0
  455. package/dist/sqlite3.d.ts.map +1 -0
  456. package/dist/sqlite3.js +99 -0
  457. package/dist/sqlite3.js.map +1 -0
  458. package/dist/stats.d.ts +8 -0
  459. package/dist/stats.d.ts.map +1 -1
  460. package/dist/stats.js +45 -13
  461. package/dist/stats.js.map +1 -1
  462. package/dist/subscriptions/cache.d.ts +3 -0
  463. package/dist/subscriptions/cache.d.ts.map +1 -1
  464. package/dist/subscriptions/cache.js +44 -0
  465. package/dist/subscriptions/cache.js.map +1 -1
  466. package/dist/subscriptions/index.js +2 -2
  467. package/dist/subscriptions/resolve.d.ts +3 -1
  468. package/dist/subscriptions/resolve.d.ts.map +1 -1
  469. package/dist/subscriptions/resolve.js +91 -52
  470. package/dist/subscriptions/resolve.js.map +1 -1
  471. package/dist/sync.d.ts +3 -0
  472. package/dist/sync.d.ts.map +1 -1
  473. package/dist/sync.js +9 -5
  474. package/dist/sync.js.map +1 -1
  475. package/package.json +297 -8
  476. package/src/auth-leases.ts +649 -0
  477. package/src/better-sqlite3.ts +35 -0
  478. package/src/blobs/access.ts +244 -0
  479. package/src/blobs/adapters/database.ts +125 -43
  480. package/src/blobs/index.ts +1 -0
  481. package/src/blobs/manager.ts +366 -65
  482. package/src/blobs/migrate.ts +16 -8
  483. package/src/blobs/types.ts +4 -0
  484. package/src/bun-sqlite-ambient.d.ts +19 -0
  485. package/src/bun-sqlite.ts +27 -0
  486. package/src/clients.ts +1 -0
  487. package/src/cloudflare/durable-object.ts +289 -0
  488. package/src/cloudflare/index.ts +22 -0
  489. package/src/cloudflare/r2.ts +526 -0
  490. package/src/cloudflare/scope-cache.ts +341 -0
  491. package/src/cloudflare/sentry.ts +230 -0
  492. package/src/cloudflare/worker.ts +77 -0
  493. package/src/commit-integrity.ts +371 -0
  494. package/src/crdt-yjs/index.ts +931 -0
  495. package/src/d1.ts +16 -0
  496. package/src/dialect/base.ts +71 -5
  497. package/src/dialect/helpers.ts +31 -0
  498. package/src/dialect/types.ts +47 -0
  499. package/src/encrypted-crdt.ts +786 -0
  500. package/src/errors.ts +22 -0
  501. package/src/filesystem/index.ts +262 -0
  502. package/src/handlers/collection.ts +78 -78
  503. package/src/handlers/create-handler.ts +540 -147
  504. package/src/handlers/types.ts +116 -0
  505. package/src/helpers/index.ts +2 -0
  506. package/src/helpers/scope-authorization.ts +27 -0
  507. package/src/helpers/scope-commit-index.ts +52 -0
  508. package/src/hono/api-key-auth.ts +177 -0
  509. package/src/hono/audit-redaction.ts +135 -0
  510. package/src/hono/blobs.ts +851 -0
  511. package/src/hono/console/gateway.ts +3046 -0
  512. package/src/hono/console/live-auth.ts +46 -0
  513. package/src/hono/console/route-descriptor.ts +22 -0
  514. package/src/hono/console/routes/api-keys.ts +721 -0
  515. package/src/hono/console/routes/clients.ts +447 -0
  516. package/src/hono/console/routes/commits.ts +1137 -0
  517. package/src/hono/console/routes/context.ts +956 -0
  518. package/src/hono/console/routes/events.ts +669 -0
  519. package/src/hono/console/routes/maintenance.ts +461 -0
  520. package/src/hono/console/routes/shared.ts +816 -0
  521. package/src/hono/console/routes/stats.ts +392 -0
  522. package/src/hono/console/routes/storage.ts +159 -0
  523. package/src/hono/console/routes.ts +146 -0
  524. package/src/hono/console/schema-errors.ts +23 -0
  525. package/src/hono/console/schemas.ts +914 -0
  526. package/src/hono/console/types.ts +223 -0
  527. package/src/hono/console/ui.ts +100 -0
  528. package/src/hono/create-server.ts +230 -0
  529. package/src/hono/errors.ts +50 -0
  530. package/src/hono/index.ts +54 -0
  531. package/src/hono/openapi.ts +139 -0
  532. package/src/hono/proxy/connection-manager.ts +340 -0
  533. package/src/hono/proxy/index.ts +8 -0
  534. package/src/hono/proxy/routes.ts +272 -0
  535. package/src/hono/rate-limit.ts +319 -0
  536. package/src/hono/realtime-sync-packs.ts +354 -0
  537. package/src/hono/routes/audit.ts +499 -0
  538. package/src/hono/routes/auth-leases.ts +119 -0
  539. package/src/hono/routes/combined.ts +583 -0
  540. package/src/hono/routes/context.ts +1629 -0
  541. package/src/hono/routes/health.ts +26 -0
  542. package/src/hono/routes/realtime.ts +808 -0
  543. package/src/hono/routes/shared.ts +1626 -0
  544. package/src/hono/routes/snapshots.ts +345 -0
  545. package/src/hono/routes.ts +68 -0
  546. package/src/hono/validation.ts +81 -0
  547. package/src/hono/websocket-origin.ts +131 -0
  548. package/src/hono/ws.ts +1134 -0
  549. package/src/index.ts +6 -0
  550. package/src/libsql.ts +51 -0
  551. package/src/neon.ts +28 -0
  552. package/src/notify.ts +224 -44
  553. package/src/pglite.ts +68 -0
  554. package/src/plugins/index.ts +1 -0
  555. package/src/plugins/types.ts +144 -0
  556. package/src/postgres/index.ts +1291 -0
  557. package/src/proxy/collection.ts +5 -27
  558. package/src/proxy/handler.ts +2 -2
  559. package/src/proxy/index.ts +0 -2
  560. package/src/proxy/oplog.ts +41 -10
  561. package/src/prune.ts +137 -36
  562. package/src/pull.ts +1504 -591
  563. package/src/push.ts +881 -443
  564. package/src/realtime/index.ts +2 -0
  565. package/src/realtime/types.ts +35 -0
  566. package/src/relay/bun-types.d.ts +50 -0
  567. package/src/relay/client-role/forward-engine.ts +355 -0
  568. package/src/relay/client-role/index.ts +9 -0
  569. package/src/relay/client-role/pull-engine.ts +329 -0
  570. package/src/relay/client-role/sequence-mapper.ts +201 -0
  571. package/src/relay/evaluation/relay-paths.ts +699 -0
  572. package/src/relay/evaluation/rust-boundary.ts +464 -0
  573. package/src/relay/index.ts +50 -0
  574. package/src/relay/migrate.ts +113 -0
  575. package/src/relay/mode-manager.ts +142 -0
  576. package/src/relay/realtime.ts +207 -0
  577. package/src/relay/relay.ts +431 -0
  578. package/src/relay/schema.ts +171 -0
  579. package/src/relay/server-role/index.ts +338 -0
  580. package/src/relay/server-role/pull.ts +43 -0
  581. package/src/relay/server-role/push.ts +164 -0
  582. package/src/s3/index.ts +346 -0
  583. package/src/schema.ts +141 -1
  584. package/src/service-worker/index.ts +773 -0
  585. package/src/snapshot-artifacts/sqlite-bun.ts +168 -0
  586. package/src/snapshot-artifacts.ts +896 -0
  587. package/src/snapshot-chunks/db-metadata.ts +131 -72
  588. package/src/snapshot-chunks/types.ts +2 -0
  589. package/src/snapshot-chunks.ts +194 -70
  590. package/src/sqlite/index.ts +1064 -0
  591. package/src/sqlite3.ts +137 -0
  592. package/src/stats.ts +76 -13
  593. package/src/subscriptions/cache.ts +58 -0
  594. package/src/subscriptions/resolve.ts +99 -58
  595. package/src/sync.ts +16 -6
  596. package/src/blobs/adapters/database.test.ts +0 -67
  597. package/src/notify.test.ts +0 -520
  598. package/src/proxy/handler.test.ts +0 -126
  599. package/src/proxy/mutation-detector.test.ts +0 -71
  600. package/src/snapshot-chunks/db-metadata.test.ts +0 -172
  601. package/src/subscriptions/resolve.test.ts +0 -180
@@ -0,0 +1,1137 @@
1
+ /**
2
+ * @syncular/server/hono - Console timeline, commit, and row-history routes.
3
+ *
4
+ * Extracted from console/routes.ts without behavior changes.
5
+ */
6
+
7
+ import { ErrorResponseSchema, type ScopeValues } from '@syncular/core';
8
+ import { coerceNumber, type SyncCoreDb } from '@syncular/server';
9
+ import { resolver } from 'hono-openapi';
10
+ import type { Kysely } from 'kysely';
11
+ import { summarizeAuditChange } from '../../audit-redaction';
12
+ import { consoleValidator as zValidator } from '../../validation';
13
+ import { describeConsoleRoute } from '../route-descriptor';
14
+ import {
15
+ type ConsoleChange,
16
+ type ConsoleCommitDetail,
17
+ ConsoleCommitDetailSchema,
18
+ type ConsoleCommitListItem,
19
+ ConsoleCommitListItemSchema,
20
+ type ConsoleDebugExportCommit,
21
+ type ConsoleDebugExportResponse,
22
+ ConsoleDebugExportResponseSchema,
23
+ type ConsolePaginatedResponse,
24
+ ConsolePaginatedResponseSchema,
25
+ ConsolePartitionedPaginationQuerySchema,
26
+ type ConsoleRowHistoryResponse,
27
+ ConsoleRowHistoryResponseSchema,
28
+ type ConsoleRowInvestigationClient,
29
+ type ConsoleRowInvestigationFinding,
30
+ type ConsoleRowInvestigationResponse,
31
+ ConsoleRowInvestigationResponseSchema,
32
+ type ConsoleTimelineItem,
33
+ ConsoleTimelineItemSchema,
34
+ ConsoleTimelineQuerySchema,
35
+ } from '../schemas';
36
+ import type { ConsoleRoutesContext } from './context';
37
+ import {
38
+ assessScopeEligibility,
39
+ commitDetailQuerySchema,
40
+ commitSeqParamSchema,
41
+ consoleNotFound,
42
+ debugExportQuerySchema,
43
+ includesSearchTerm,
44
+ parseDate,
45
+ parseJsonStringArray,
46
+ rowHistoryParamSchema,
47
+ rowHistoryQuerySchema,
48
+ rowInvestigationQuerySchema,
49
+ summarizeRealtimeEvidence,
50
+ summarizeRequestEvidence,
51
+ summarizeSnapshotEvidence,
52
+ summarizeSubscriptionEvidence,
53
+ } from './shared';
54
+
55
+ export function registerCommitRoutes(ctx: ConsoleRoutesContext): void {
56
+ const {
57
+ routes,
58
+ options,
59
+ db,
60
+ timelineScanMaxRows,
61
+ requestEventSelectColumns,
62
+ mapRequestEvent,
63
+ mapDebugExportEvent,
64
+ readRedactedCommitChanges,
65
+ } = ctx;
66
+
67
+ // -------------------------------------------------------------------------
68
+ // GET /timeline
69
+ // -------------------------------------------------------------------------
70
+
71
+ routes.get(
72
+ '/timeline',
73
+ describeConsoleRoute({
74
+ summary: 'List timeline items',
75
+ responses: {
76
+ 200: {
77
+ description: 'Paginated merged timeline',
78
+ content: {
79
+ 'application/json': {
80
+ schema: resolver(
81
+ ConsolePaginatedResponseSchema(ConsoleTimelineItemSchema)
82
+ ),
83
+ },
84
+ },
85
+ },
86
+ 401: {
87
+ description: 'Unauthenticated',
88
+ content: {
89
+ 'application/json': { schema: resolver(ErrorResponseSchema) },
90
+ },
91
+ },
92
+ },
93
+ }),
94
+ zValidator('query', ConsoleTimelineQuerySchema),
95
+ async (c) => {
96
+ const {
97
+ limit,
98
+ offset,
99
+ view,
100
+ partitionId,
101
+ eventType,
102
+ actorId,
103
+ clientId,
104
+ requestId,
105
+ traceId,
106
+ syncAttemptId,
107
+ table,
108
+ outcome,
109
+ search,
110
+ from,
111
+ to,
112
+ } = c.req.valid('query');
113
+ const resolvedTraceId = traceId ?? syncAttemptId;
114
+
115
+ const items: ConsoleTimelineItem[] = [];
116
+ const normalizedSearchTerm = search?.trim().toLowerCase() || null;
117
+ const normalizedTable = table?.trim() || null;
118
+ const timelineSourceScanLimit =
119
+ timelineScanMaxRows > 0 ? timelineScanMaxRows : null;
120
+ let timelineTruncated = false;
121
+
122
+ if (
123
+ view !== 'events' &&
124
+ !eventType &&
125
+ !outcome &&
126
+ !requestId &&
127
+ !resolvedTraceId
128
+ ) {
129
+ let commitsQuery = db
130
+ .selectFrom('sync_commits')
131
+ .select([
132
+ 'commit_seq',
133
+ 'actor_id',
134
+ 'client_id',
135
+ 'client_commit_id',
136
+ 'created_at',
137
+ 'change_count',
138
+ 'affected_tables',
139
+ ]);
140
+
141
+ if (partitionId) {
142
+ commitsQuery = commitsQuery.where('partition_id', '=', partitionId);
143
+ }
144
+ if (actorId) {
145
+ commitsQuery = commitsQuery.where('actor_id', '=', actorId);
146
+ }
147
+ if (clientId) {
148
+ commitsQuery = commitsQuery.where('client_id', '=', clientId);
149
+ }
150
+ if (from) {
151
+ commitsQuery = commitsQuery.where('created_at', '>=', from);
152
+ }
153
+ if (to) {
154
+ commitsQuery = commitsQuery.where('created_at', '<=', to);
155
+ }
156
+
157
+ let commitsQueryWithOrdering = commitsQuery.orderBy(
158
+ 'created_at',
159
+ 'desc'
160
+ );
161
+ if (timelineSourceScanLimit !== null) {
162
+ commitsQueryWithOrdering = commitsQueryWithOrdering.limit(
163
+ timelineSourceScanLimit + 1
164
+ );
165
+ }
166
+
167
+ const commitRows = await commitsQueryWithOrdering.execute();
168
+ const scannedCommitRows =
169
+ timelineSourceScanLimit === null
170
+ ? commitRows
171
+ : commitRows.slice(0, timelineSourceScanLimit);
172
+ if (
173
+ timelineSourceScanLimit !== null &&
174
+ commitRows.length > timelineSourceScanLimit
175
+ ) {
176
+ timelineTruncated = true;
177
+ }
178
+
179
+ for (const row of scannedCommitRows) {
180
+ const commit: ConsoleCommitListItem = {
181
+ commitSeq: coerceNumber(row.commit_seq) ?? 0,
182
+ actorId: row.actor_id ?? '',
183
+ clientId: row.client_id ?? '',
184
+ clientCommitId: row.client_commit_id ?? '',
185
+ createdAt: row.created_at ?? '',
186
+ changeCount: coerceNumber(row.change_count) ?? 0,
187
+ affectedTables: options.dialect.dbToArray(row.affected_tables),
188
+ };
189
+
190
+ items.push({
191
+ type: 'commit',
192
+ timestamp: commit.createdAt,
193
+ commit,
194
+ event: null,
195
+ });
196
+ }
197
+ }
198
+
199
+ if (view !== 'commits') {
200
+ let eventsQuery = db
201
+ .selectFrom('sync_request_events')
202
+ .select(requestEventSelectColumns);
203
+
204
+ if (partitionId) {
205
+ eventsQuery = eventsQuery.where('partition_id', '=', partitionId);
206
+ }
207
+ if (eventType) {
208
+ eventsQuery = eventsQuery.where('event_type', '=', eventType);
209
+ }
210
+ if (actorId) {
211
+ eventsQuery = eventsQuery.where('actor_id', '=', actorId);
212
+ }
213
+ if (clientId) {
214
+ eventsQuery = eventsQuery.where('client_id', '=', clientId);
215
+ }
216
+ if (requestId) {
217
+ eventsQuery = eventsQuery.where('request_id', '=', requestId);
218
+ }
219
+ if (resolvedTraceId) {
220
+ eventsQuery = eventsQuery.where('trace_id', '=', resolvedTraceId);
221
+ }
222
+ if (outcome) {
223
+ eventsQuery = eventsQuery.where('outcome', '=', outcome);
224
+ }
225
+ if (from) {
226
+ eventsQuery = eventsQuery.where('created_at', '>=', from);
227
+ }
228
+ if (to) {
229
+ eventsQuery = eventsQuery.where('created_at', '<=', to);
230
+ }
231
+
232
+ let eventsQueryWithOrdering = eventsQuery.orderBy('created_at', 'desc');
233
+ if (timelineSourceScanLimit !== null) {
234
+ eventsQueryWithOrdering = eventsQueryWithOrdering.limit(
235
+ timelineSourceScanLimit + 1
236
+ );
237
+ }
238
+
239
+ const eventRows = await eventsQueryWithOrdering.execute();
240
+ const scannedEventRows =
241
+ timelineSourceScanLimit === null
242
+ ? eventRows
243
+ : eventRows.slice(0, timelineSourceScanLimit);
244
+ if (
245
+ timelineSourceScanLimit !== null &&
246
+ eventRows.length > timelineSourceScanLimit
247
+ ) {
248
+ timelineTruncated = true;
249
+ }
250
+
251
+ for (const row of scannedEventRows) {
252
+ const event = mapRequestEvent(row);
253
+
254
+ items.push({
255
+ type: 'event',
256
+ timestamp: event.createdAt,
257
+ commit: null,
258
+ event,
259
+ });
260
+ }
261
+ }
262
+
263
+ const filteredItems = items.filter((item) => {
264
+ if (item.type === 'commit') {
265
+ const commit = item.commit;
266
+ if (!commit) return false;
267
+
268
+ if (
269
+ normalizedTable &&
270
+ !(commit.affectedTables ?? []).includes(normalizedTable)
271
+ ) {
272
+ return false;
273
+ }
274
+
275
+ if (!normalizedSearchTerm) return true;
276
+
277
+ const searchableCommitFields = [
278
+ String(commit.commitSeq),
279
+ commit.actorId,
280
+ commit.clientId,
281
+ commit.clientCommitId,
282
+ ...(commit.affectedTables ?? []),
283
+ ];
284
+
285
+ return searchableCommitFields.some((field) =>
286
+ includesSearchTerm(field, normalizedSearchTerm)
287
+ );
288
+ }
289
+
290
+ const event = item.event;
291
+ if (!event) return false;
292
+
293
+ if (
294
+ normalizedTable &&
295
+ !(event.tables ?? []).includes(normalizedTable)
296
+ ) {
297
+ return false;
298
+ }
299
+
300
+ if (!normalizedSearchTerm) return true;
301
+
302
+ const searchableEventFields = [
303
+ String(event.eventId),
304
+ event.requestId,
305
+ event.traceId ?? '',
306
+ event.actorId,
307
+ event.clientId,
308
+ event.outcome,
309
+ event.responseStatus,
310
+ event.errorCode ?? '',
311
+ event.errorMessage ?? '',
312
+ ...(event.tables ?? []),
313
+ ];
314
+
315
+ return searchableEventFields.some((field) =>
316
+ includesSearchTerm(field, normalizedSearchTerm)
317
+ );
318
+ });
319
+
320
+ filteredItems.sort(
321
+ (a, b) => (parseDate(b.timestamp) ?? 0) - (parseDate(a.timestamp) ?? 0)
322
+ );
323
+
324
+ const total = filteredItems.length;
325
+ const pagedItems = filteredItems.slice(offset, offset + limit);
326
+
327
+ const response: ConsolePaginatedResponse<ConsoleTimelineItem> = {
328
+ items: pagedItems,
329
+ total,
330
+ offset,
331
+ limit,
332
+ };
333
+
334
+ c.header('X-Total-Count', String(total));
335
+ if (timelineTruncated) {
336
+ c.header('X-Timeline-Truncated', 'true');
337
+ if (timelineSourceScanLimit !== null) {
338
+ c.header('X-Timeline-Scan-Limit', String(timelineSourceScanLimit));
339
+ }
340
+ }
341
+ return c.json(response, 200);
342
+ }
343
+ );
344
+
345
+ // -------------------------------------------------------------------------
346
+ // GET /commits
347
+ // -------------------------------------------------------------------------
348
+
349
+ routes.get(
350
+ '/commits',
351
+ describeConsoleRoute({
352
+ summary: 'List commits',
353
+ responses: {
354
+ 200: {
355
+ description: 'Paginated commit list',
356
+ content: {
357
+ 'application/json': {
358
+ schema: resolver(
359
+ ConsolePaginatedResponseSchema(ConsoleCommitListItemSchema)
360
+ ),
361
+ },
362
+ },
363
+ },
364
+ 401: {
365
+ description: 'Unauthenticated',
366
+ content: {
367
+ 'application/json': { schema: resolver(ErrorResponseSchema) },
368
+ },
369
+ },
370
+ },
371
+ }),
372
+ zValidator('query', ConsolePartitionedPaginationQuerySchema),
373
+ async (c) => {
374
+ const { limit, offset, partitionId } = c.req.valid('query');
375
+
376
+ let query = db
377
+ .selectFrom('sync_commits')
378
+ .select([
379
+ 'commit_seq',
380
+ 'actor_id',
381
+ 'client_id',
382
+ 'client_commit_id',
383
+ 'created_at',
384
+ 'change_count',
385
+ 'affected_tables',
386
+ ]);
387
+
388
+ let countQuery = db
389
+ .selectFrom('sync_commits')
390
+ .select(({ fn }) => fn.countAll().as('total'));
391
+
392
+ if (partitionId) {
393
+ query = query.where('partition_id', '=', partitionId);
394
+ countQuery = countQuery.where('partition_id', '=', partitionId);
395
+ }
396
+
397
+ const [rows, countRow] = await Promise.all([
398
+ query
399
+ .orderBy('commit_seq', 'desc')
400
+ .limit(limit)
401
+ .offset(offset)
402
+ .execute(),
403
+ countQuery.executeTakeFirst(),
404
+ ]);
405
+
406
+ const items: ConsoleCommitListItem[] = rows.map((row) => ({
407
+ commitSeq: coerceNumber(row.commit_seq) ?? 0,
408
+ actorId: row.actor_id ?? '',
409
+ clientId: row.client_id ?? '',
410
+ clientCommitId: row.client_commit_id ?? '',
411
+ createdAt: row.created_at ?? '',
412
+ changeCount: coerceNumber(row.change_count) ?? 0,
413
+ affectedTables: options.dialect.dbToArray(row.affected_tables),
414
+ }));
415
+
416
+ const total = coerceNumber(countRow?.total) ?? 0;
417
+
418
+ const response: ConsolePaginatedResponse<ConsoleCommitListItem> = {
419
+ items,
420
+ total,
421
+ offset,
422
+ limit,
423
+ };
424
+
425
+ c.header('X-Total-Count', String(total));
426
+ return c.json(response, 200);
427
+ }
428
+ );
429
+
430
+ // -------------------------------------------------------------------------
431
+ // GET /commits/:seq
432
+ // -------------------------------------------------------------------------
433
+
434
+ routes.get(
435
+ '/commits/:seq',
436
+ describeConsoleRoute({
437
+ summary: 'Get commit details',
438
+ responses: {
439
+ 200: {
440
+ description: 'Commit with changes',
441
+ content: {
442
+ 'application/json': { schema: resolver(ConsoleCommitDetailSchema) },
443
+ },
444
+ },
445
+ 400: {
446
+ description: 'Invalid request',
447
+ content: {
448
+ 'application/json': { schema: resolver(ErrorResponseSchema) },
449
+ },
450
+ },
451
+ 401: {
452
+ description: 'Unauthenticated',
453
+ content: {
454
+ 'application/json': { schema: resolver(ErrorResponseSchema) },
455
+ },
456
+ },
457
+ 404: {
458
+ description: 'Not found',
459
+ content: {
460
+ 'application/json': { schema: resolver(ErrorResponseSchema) },
461
+ },
462
+ },
463
+ },
464
+ }),
465
+ zValidator('param', commitSeqParamSchema),
466
+ zValidator('query', commitDetailQuerySchema),
467
+ async (c) => {
468
+ const { seq } = c.req.valid('param');
469
+ const { partitionId } = c.req.valid('query');
470
+
471
+ let commitQuery = db
472
+ .selectFrom('sync_commits')
473
+ .select([
474
+ 'commit_seq',
475
+ 'actor_id',
476
+ 'client_id',
477
+ 'client_commit_id',
478
+ 'created_at',
479
+ 'change_count',
480
+ 'affected_tables',
481
+ ])
482
+ .where('commit_seq', '=', seq);
483
+
484
+ if (partitionId) {
485
+ commitQuery = commitQuery.where('partition_id', '=', partitionId);
486
+ }
487
+
488
+ const commitRow = await commitQuery.executeTakeFirst();
489
+
490
+ if (!commitRow) {
491
+ return consoleNotFound(c);
492
+ }
493
+
494
+ let changesQuery = db
495
+ .selectFrom('sync_changes')
496
+ .select([
497
+ 'change_id',
498
+ 'table',
499
+ 'row_id',
500
+ 'op',
501
+ 'row_json',
502
+ 'row_version',
503
+ 'scopes',
504
+ ])
505
+ .where('commit_seq', '=', seq);
506
+
507
+ if (partitionId) {
508
+ changesQuery = changesQuery.where('partition_id', '=', partitionId);
509
+ }
510
+
511
+ const changeRows = await changesQuery
512
+ .orderBy('change_id', 'asc')
513
+ .execute();
514
+
515
+ const changes: ConsoleChange[] = changeRows.map((row) => {
516
+ const op = row.op === 'delete' ? 'delete' : 'upsert';
517
+ return {
518
+ ...summarizeAuditChange({
519
+ table: row.table ?? '',
520
+ op,
521
+ rowJson: row.row_json,
522
+ scopes: row.scopes,
523
+ }),
524
+ changeId: coerceNumber(row.change_id) ?? 0,
525
+ table: row.table ?? '',
526
+ rowId: row.row_id ?? '',
527
+ op,
528
+ rowVersion: coerceNumber(row.row_version),
529
+ };
530
+ });
531
+
532
+ const commit: ConsoleCommitDetail = {
533
+ commitSeq: coerceNumber(commitRow.commit_seq) ?? 0,
534
+ actorId: commitRow.actor_id ?? '',
535
+ clientId: commitRow.client_id ?? '',
536
+ clientCommitId: commitRow.client_commit_id ?? '',
537
+ createdAt: commitRow.created_at ?? '',
538
+ changeCount: coerceNumber(commitRow.change_count) ?? 0,
539
+ affectedTables: parseJsonStringArray(commitRow.affected_tables),
540
+ changes,
541
+ };
542
+
543
+ return c.json(commit, 200);
544
+ }
545
+ );
546
+
547
+ // -------------------------------------------------------------------------
548
+ // GET /row-history/:table/:rowId
549
+ // -------------------------------------------------------------------------
550
+
551
+ routes.get(
552
+ '/row-history/:table/:rowId',
553
+ describeConsoleRoute({
554
+ summary: 'Get redacted row history',
555
+ responses: {
556
+ 200: {
557
+ description: 'Redacted row history with request-event links',
558
+ content: {
559
+ 'application/json': {
560
+ schema: resolver(ConsoleRowHistoryResponseSchema),
561
+ },
562
+ },
563
+ },
564
+ 400: {
565
+ description: 'Invalid request',
566
+ content: {
567
+ 'application/json': { schema: resolver(ErrorResponseSchema) },
568
+ },
569
+ },
570
+ 401: {
571
+ description: 'Unauthenticated',
572
+ content: {
573
+ 'application/json': { schema: resolver(ErrorResponseSchema) },
574
+ },
575
+ },
576
+ 404: {
577
+ description: 'Not found',
578
+ content: {
579
+ 'application/json': { schema: resolver(ErrorResponseSchema) },
580
+ },
581
+ },
582
+ },
583
+ }),
584
+ zValidator('param', rowHistoryParamSchema),
585
+ zValidator('query', rowHistoryQuerySchema),
586
+ async (c) => {
587
+ const { table, rowId } = c.req.valid('param');
588
+ const {
589
+ partitionId: requestedPartitionId,
590
+ limit,
591
+ beforeCommitSeq,
592
+ afterCommitSeq,
593
+ } = c.req.valid('query');
594
+ const partitionId = requestedPartitionId ?? 'default';
595
+
596
+ const rows = await options.dialect.readAuditRowHistory(
597
+ options.db as unknown as Kysely<SyncCoreDb>,
598
+ {
599
+ partitionId,
600
+ table,
601
+ rowId,
602
+ scopes: {},
603
+ limit,
604
+ beforeCommitSeq,
605
+ afterCommitSeq,
606
+ }
607
+ );
608
+ if (rows.length === 0) {
609
+ return consoleNotFound(c);
610
+ }
611
+
612
+ const hasMore = rows.length > limit;
613
+ const selectedRows = hasMore ? rows.slice(0, limit) : rows;
614
+ const nextCursor = hasMore
615
+ ? Number(selectedRows[selectedRows.length - 1]?.commit_seq ?? 0)
616
+ : null;
617
+ const commitSeqs = Array.from(
618
+ new Set(selectedRows.map((row) => Number(row.commit_seq)))
619
+ );
620
+
621
+ const eventRows =
622
+ commitSeqs.length > 0
623
+ ? await db
624
+ .selectFrom('sync_request_events')
625
+ .select(['event_id', 'commit_seq', 'request_id', 'trace_id'])
626
+ .where('partition_id', '=', partitionId)
627
+ .where('commit_seq', 'in', commitSeqs)
628
+ .orderBy('event_id', 'asc')
629
+ .execute()
630
+ : [];
631
+ const eventLinksByCommitSeq = new Map<
632
+ number,
633
+ {
634
+ eventIds: Set<number>;
635
+ requestIds: Set<string>;
636
+ traceIds: Set<string>;
637
+ }
638
+ >();
639
+ for (const row of eventRows) {
640
+ const commitSeq = coerceNumber(row.commit_seq);
641
+ if (commitSeq === null) continue;
642
+ const links = eventLinksByCommitSeq.get(commitSeq) ?? {
643
+ eventIds: new Set<number>(),
644
+ requestIds: new Set<string>(),
645
+ traceIds: new Set<string>(),
646
+ };
647
+ const eventId = coerceNumber(row.event_id);
648
+ if (eventId !== null) links.eventIds.add(eventId);
649
+ if (row.request_id) links.requestIds.add(row.request_id);
650
+ if (row.trace_id) links.traceIds.add(row.trace_id);
651
+ eventLinksByCommitSeq.set(commitSeq, links);
652
+ }
653
+
654
+ const response: ConsoleRowHistoryResponse = {
655
+ table,
656
+ rowId,
657
+ partitionId,
658
+ history: selectedRows.map((row) => {
659
+ const commitSeq = Number(row.commit_seq);
660
+ const links = eventLinksByCommitSeq.get(commitSeq);
661
+ const summary = summarizeAuditChange({
662
+ table: row.table,
663
+ op: row.op,
664
+ rowJson: row.row_json,
665
+ scopes: row.scopes,
666
+ });
667
+ return {
668
+ commitSeq,
669
+ actorId: row.actor_id,
670
+ clientId: row.client_id,
671
+ clientCommitId: row.client_commit_id,
672
+ createdAt: row.created_at,
673
+ changeId: Number(row.change_id),
674
+ table: row.table,
675
+ rowId: row.row_id,
676
+ op: row.op,
677
+ rowVersion:
678
+ row.row_version === null ? null : Number(row.row_version),
679
+ ...summary,
680
+ requestEventIds: links ? Array.from(links.eventIds) : [],
681
+ requestIds: links ? Array.from(links.requestIds) : [],
682
+ traceIds: links ? Array.from(links.traceIds) : [],
683
+ };
684
+ }),
685
+ nextCursor,
686
+ };
687
+
688
+ return c.json(response, 200);
689
+ }
690
+ );
691
+
692
+ // -------------------------------------------------------------------------
693
+ // GET /row-investigation/:table/:rowId
694
+ // -------------------------------------------------------------------------
695
+
696
+ routes.get(
697
+ '/row-investigation/:table/:rowId',
698
+ describeConsoleRoute({
699
+ summary: 'Investigate row visibility',
700
+ responses: {
701
+ 200: {
702
+ description: 'Redacted row investigation with client/event hints',
703
+ content: {
704
+ 'application/json': {
705
+ schema: resolver(ConsoleRowInvestigationResponseSchema),
706
+ },
707
+ },
708
+ },
709
+ 400: {
710
+ description: 'Invalid request',
711
+ content: {
712
+ 'application/json': { schema: resolver(ErrorResponseSchema) },
713
+ },
714
+ },
715
+ 401: {
716
+ description: 'Unauthenticated',
717
+ content: {
718
+ 'application/json': { schema: resolver(ErrorResponseSchema) },
719
+ },
720
+ },
721
+ },
722
+ }),
723
+ zValidator('param', rowHistoryParamSchema),
724
+ zValidator('query', rowInvestigationQuerySchema),
725
+ async (c) => {
726
+ const { table, rowId } = c.req.valid('param');
727
+ const {
728
+ partitionId: requestedPartitionId,
729
+ clientId,
730
+ limit,
731
+ beforeCommitSeq,
732
+ afterCommitSeq,
733
+ } = c.req.valid('query');
734
+ const partitionId = requestedPartitionId ?? 'default';
735
+
736
+ const rows = await options.dialect.readAuditRowHistory(
737
+ options.db as unknown as Kysely<SyncCoreDb>,
738
+ {
739
+ partitionId,
740
+ table,
741
+ rowId,
742
+ scopes: {},
743
+ limit,
744
+ beforeCommitSeq,
745
+ afterCommitSeq,
746
+ }
747
+ );
748
+
749
+ const hasMore = rows.length > limit;
750
+ const selectedRows = hasMore ? rows.slice(0, limit) : rows;
751
+ const nextCursor = hasMore
752
+ ? Number(selectedRows[selectedRows.length - 1]?.commit_seq ?? 0)
753
+ : null;
754
+ const commitSeqs = Array.from(
755
+ new Set(selectedRows.map((row) => Number(row.commit_seq)))
756
+ );
757
+
758
+ const eventLinkRows =
759
+ commitSeqs.length > 0
760
+ ? await db
761
+ .selectFrom('sync_request_events')
762
+ .select(['event_id', 'commit_seq', 'request_id', 'trace_id'])
763
+ .where('partition_id', '=', partitionId)
764
+ .where('commit_seq', 'in', commitSeqs)
765
+ .orderBy('event_id', 'asc')
766
+ .execute()
767
+ : [];
768
+ const eventLinksByCommitSeq = new Map<
769
+ number,
770
+ {
771
+ eventIds: Set<number>;
772
+ requestIds: Set<string>;
773
+ traceIds: Set<string>;
774
+ }
775
+ >();
776
+ for (const row of eventLinkRows) {
777
+ const commitSeq = coerceNumber(row.commit_seq);
778
+ if (commitSeq === null) continue;
779
+ const links = eventLinksByCommitSeq.get(commitSeq) ?? {
780
+ eventIds: new Set<number>(),
781
+ requestIds: new Set<string>(),
782
+ traceIds: new Set<string>(),
783
+ };
784
+ const eventId = coerceNumber(row.event_id);
785
+ if (eventId !== null) links.eventIds.add(eventId);
786
+ if (row.request_id) links.requestIds.add(row.request_id);
787
+ if (row.trace_id) links.traceIds.add(row.trace_id);
788
+ eventLinksByCommitSeq.set(commitSeq, links);
789
+ }
790
+
791
+ const history = selectedRows.map((row) => {
792
+ const commitSeq = Number(row.commit_seq);
793
+ const links = eventLinksByCommitSeq.get(commitSeq);
794
+ const summary = summarizeAuditChange({
795
+ table: row.table,
796
+ op: row.op,
797
+ rowJson: row.row_json,
798
+ scopes: row.scopes,
799
+ });
800
+ return {
801
+ commitSeq,
802
+ actorId: row.actor_id,
803
+ clientId: row.client_id,
804
+ clientCommitId: row.client_commit_id,
805
+ createdAt: row.created_at,
806
+ changeId: Number(row.change_id),
807
+ table: row.table,
808
+ rowId: row.row_id,
809
+ op: row.op,
810
+ rowVersion: row.row_version === null ? null : Number(row.row_version),
811
+ ...summary,
812
+ requestEventIds: links ? Array.from(links.eventIds) : [],
813
+ requestIds: links ? Array.from(links.requestIds) : [],
814
+ traceIds: links ? Array.from(links.traceIds) : [],
815
+ };
816
+ });
817
+
818
+ const latestRow = selectedRows[0] ?? null;
819
+ const latestCommitSeq = latestRow
820
+ ? (coerceNumber(latestRow.commit_seq) ?? 0)
821
+ : null;
822
+ const latestOp =
823
+ latestRow?.op === 'delete' || latestRow?.op === 'upsert'
824
+ ? latestRow.op
825
+ : null;
826
+
827
+ const clientRow = clientId
828
+ ? await db
829
+ .selectFrom('sync_client_cursors')
830
+ .select([
831
+ 'client_id',
832
+ 'actor_id',
833
+ 'cursor',
834
+ 'effective_scopes',
835
+ 'updated_at',
836
+ ])
837
+ .where('partition_id', '=', partitionId)
838
+ .where('client_id', '=', clientId)
839
+ .executeTakeFirst()
840
+ : null;
841
+
842
+ const eventRows = await db
843
+ .selectFrom('sync_request_events')
844
+ .select(requestEventSelectColumns)
845
+ .where('partition_id', '=', partitionId)
846
+ .$if(Boolean(clientId), (query) =>
847
+ query.where('client_id', '=', clientId ?? '')
848
+ )
849
+ .orderBy('created_at', 'desc')
850
+ .limit(Math.min(Math.max(limit * 5, 25), 200))
851
+ .execute();
852
+ const relevantEvents = eventRows
853
+ .map((row) => mapRequestEvent(row))
854
+ .filter((event) => (event.tables ?? []).includes(table))
855
+ .slice(0, limit);
856
+ const subscriptionEvidence =
857
+ summarizeSubscriptionEvidence(relevantEvents);
858
+ const requestEvidence = summarizeRequestEvidence(relevantEvents);
859
+ const snapshotEvidence = summarizeSnapshotEvidence(relevantEvents);
860
+ const realtimeRows = clientId
861
+ ? await db
862
+ .selectFrom('sync_realtime_events')
863
+ .select([
864
+ 'event_id',
865
+ 'event_type',
866
+ 'reason',
867
+ 'cursor',
868
+ 'latest_cursor',
869
+ ])
870
+ .where('partition_id', '=', partitionId)
871
+ .where('client_id', '=', clientId)
872
+ .orderBy('created_at', 'desc')
873
+ .limit(Math.min(Math.max(limit * 5, 25), 200))
874
+ .execute()
875
+ : [];
876
+ const realtimeEvidence = summarizeRealtimeEvidence(realtimeRows);
877
+
878
+ const latestClientEvent = relevantEvents.find(
879
+ (event) => !clientId || event.clientId === clientId
880
+ );
881
+ const clientScopes = clientRow
882
+ ? (options.dialect.dbToScopes(
883
+ clientRow.effective_scopes
884
+ ) as ScopeValues)
885
+ : null;
886
+ const latestRowScopes = latestRow
887
+ ? options.dialect.dbToScopes(latestRow.scopes)
888
+ : null;
889
+ const client: ConsoleRowInvestigationClient | null = clientRow
890
+ ? {
891
+ clientId: clientRow.client_id ?? '',
892
+ actorId: clientRow.actor_id ?? '',
893
+ cursor: coerceNumber(clientRow.cursor) ?? 0,
894
+ effectiveScopeKeys: Object.keys(clientScopes ?? {}).sort(),
895
+ updatedAt: clientRow.updated_at ?? '',
896
+ lastRequestAt: latestClientEvent?.createdAt ?? null,
897
+ lastRequestType: latestClientEvent?.eventType ?? null,
898
+ lastRequestOutcome: latestClientEvent?.outcome ?? null,
899
+ }
900
+ : null;
901
+
902
+ const scopeEligibility = assessScopeEligibility({
903
+ rowScopes: latestRowScopes,
904
+ clientScopes,
905
+ });
906
+ const findings: ConsoleRowInvestigationFinding[] = [];
907
+ if (!latestRow) {
908
+ findings.push({
909
+ severity: 'warning',
910
+ code: 'row.not_found',
911
+ message:
912
+ 'No audit entry exists for this table and row in the selected partition.',
913
+ });
914
+ }
915
+ if (!clientId) {
916
+ findings.push({
917
+ severity: 'info',
918
+ code: 'client.not_selected',
919
+ message:
920
+ 'Provide a client id to check cursor position and scope eligibility.',
921
+ });
922
+ } else if (!client) {
923
+ findings.push({
924
+ severity: 'warning',
925
+ code: 'client.not_found',
926
+ message:
927
+ 'No client cursor exists for this client in the selected partition.',
928
+ });
929
+ }
930
+ if (latestOp === 'delete') {
931
+ findings.push({
932
+ severity: 'warning',
933
+ code: 'row.deleted',
934
+ message: 'The latest recorded operation for this row is a delete.',
935
+ });
936
+ }
937
+ if (
938
+ client &&
939
+ latestCommitSeq !== null &&
940
+ client.cursor < latestCommitSeq
941
+ ) {
942
+ findings.push({
943
+ severity: 'warning',
944
+ code: 'client.cursor_behind',
945
+ message:
946
+ 'The client cursor is behind the latest row commit, so the row may not have been pulled yet.',
947
+ });
948
+ }
949
+ if (scopeEligibility.status === 'not_eligible') {
950
+ findings.push({
951
+ severity: 'warning',
952
+ code: 'scope.not_eligible',
953
+ message:
954
+ 'The client effective scopes do not cover the latest row scopes.',
955
+ });
956
+ }
957
+ if (relevantEvents.length === 0) {
958
+ findings.push({
959
+ severity: 'info',
960
+ code: 'events.none_for_table',
961
+ message:
962
+ 'No recent request events mention this table for the selected filters.',
963
+ });
964
+ } else if (subscriptionEvidence.status === 'revoked') {
965
+ findings.push({
966
+ severity: 'warning',
967
+ code: 'subscription.revoked',
968
+ message:
969
+ 'A relevant pull event reported at least one revoked subscription.',
970
+ });
971
+ } else if (subscriptionEvidence.status === 'unknown') {
972
+ findings.push({
973
+ severity: 'info',
974
+ code: 'subscription.not_recorded',
975
+ message:
976
+ 'Relevant events exist, but none include subscription-count evidence.',
977
+ });
978
+ } else if (subscriptionEvidence.status === 'not_observed') {
979
+ findings.push({
980
+ severity: 'warning',
981
+ code: 'subscription.not_observed',
982
+ message:
983
+ 'Relevant pull events did not report an active subscription for this table.',
984
+ });
985
+ }
986
+ if (latestClientEvent && latestClientEvent.responseStatus !== 'success') {
987
+ findings.push({
988
+ severity: 'warning',
989
+ code: 'events.latest_not_success',
990
+ message:
991
+ 'The latest relevant request event did not complete successfully.',
992
+ });
993
+ }
994
+
995
+ const response: ConsoleRowInvestigationResponse = {
996
+ table,
997
+ rowId,
998
+ partitionId,
999
+ clientId: clientId ?? null,
1000
+ rowKnown: history.length > 0,
1001
+ latestCommitSeq,
1002
+ latestOp,
1003
+ client,
1004
+ scopeEligibility,
1005
+ subscriptionEvidence,
1006
+ requestEvidence,
1007
+ snapshotEvidence,
1008
+ realtimeEvidence,
1009
+ history,
1010
+ relevantEvents,
1011
+ findings,
1012
+ nextCursor,
1013
+ };
1014
+
1015
+ return c.json(response, 200);
1016
+ }
1017
+ );
1018
+
1019
+ // -------------------------------------------------------------------------
1020
+ // GET /debug/export
1021
+ // -------------------------------------------------------------------------
1022
+
1023
+ routes.get(
1024
+ '/debug/export',
1025
+ describeConsoleRoute({
1026
+ summary: 'Export a redacted debug bundle',
1027
+ responses: {
1028
+ 200: {
1029
+ description: 'Size-bounded redacted debug export',
1030
+ content: {
1031
+ 'application/json': {
1032
+ schema: resolver(ConsoleDebugExportResponseSchema),
1033
+ },
1034
+ },
1035
+ },
1036
+ 400: {
1037
+ description: 'Invalid request',
1038
+ content: {
1039
+ 'application/json': { schema: resolver(ErrorResponseSchema) },
1040
+ },
1041
+ },
1042
+ 401: {
1043
+ description: 'Unauthenticated',
1044
+ content: {
1045
+ 'application/json': { schema: resolver(ErrorResponseSchema) },
1046
+ },
1047
+ },
1048
+ },
1049
+ }),
1050
+ zValidator('query', debugExportQuerySchema),
1051
+ async (c) => {
1052
+ const {
1053
+ partitionId: requestedPartitionId,
1054
+ limitCommits,
1055
+ limitEvents,
1056
+ } = c.req.valid('query');
1057
+ const { from, to } = c.req.valid('query');
1058
+ const partitionId = requestedPartitionId ?? 'default';
1059
+
1060
+ let commitsQuery = db
1061
+ .selectFrom('sync_commits')
1062
+ .select([
1063
+ 'commit_seq',
1064
+ 'actor_id',
1065
+ 'client_id',
1066
+ 'client_commit_id',
1067
+ 'created_at',
1068
+ 'change_count',
1069
+ 'affected_tables',
1070
+ ])
1071
+ .where('partition_id', '=', partitionId);
1072
+ if (from) commitsQuery = commitsQuery.where('created_at', '>=', from);
1073
+ if (to) commitsQuery = commitsQuery.where('created_at', '<=', to);
1074
+
1075
+ let eventsQuery = db
1076
+ .selectFrom('sync_request_events')
1077
+ .select(requestEventSelectColumns)
1078
+ .where('partition_id', '=', partitionId);
1079
+ if (from) eventsQuery = eventsQuery.where('created_at', '>=', from);
1080
+ if (to) eventsQuery = eventsQuery.where('created_at', '<=', to);
1081
+
1082
+ const [commitRows, eventRows] = await Promise.all([
1083
+ commitsQuery
1084
+ .orderBy('commit_seq', 'desc')
1085
+ .limit(limitCommits + 1)
1086
+ .execute(),
1087
+ eventsQuery
1088
+ .orderBy('created_at', 'desc')
1089
+ .limit(limitEvents + 1)
1090
+ .execute(),
1091
+ ]);
1092
+
1093
+ const selectedCommitRows = commitRows.slice(0, limitCommits);
1094
+ const selectedEventRows = eventRows.slice(0, limitEvents);
1095
+ const commitSeqs = selectedCommitRows
1096
+ .map((row) => coerceNumber(row.commit_seq))
1097
+ .filter((seq): seq is number => seq !== null);
1098
+ const changesByCommitSeq = await readRedactedCommitChanges(
1099
+ partitionId,
1100
+ commitSeqs
1101
+ );
1102
+
1103
+ const commits: ConsoleDebugExportCommit[] = selectedCommitRows.map(
1104
+ (row) => {
1105
+ const commitSeq = coerceNumber(row.commit_seq) ?? 0;
1106
+ return {
1107
+ commitSeq,
1108
+ actorId: row.actor_id ?? '',
1109
+ clientId: row.client_id ?? '',
1110
+ clientCommitId: row.client_commit_id ?? '',
1111
+ createdAt: row.created_at ?? '',
1112
+ changeCount: coerceNumber(row.change_count) ?? 0,
1113
+ affectedTables: options.dialect.dbToArray(row.affected_tables),
1114
+ changes: changesByCommitSeq.get(commitSeq) ?? [],
1115
+ };
1116
+ }
1117
+ );
1118
+
1119
+ const response: ConsoleDebugExportResponse = {
1120
+ generatedAt: new Date().toISOString(),
1121
+ partitionId,
1122
+ limits: {
1123
+ commits: limitCommits,
1124
+ requestEvents: limitEvents,
1125
+ },
1126
+ truncated: {
1127
+ commits: commitRows.length > limitCommits,
1128
+ requestEvents: eventRows.length > limitEvents,
1129
+ },
1130
+ commits,
1131
+ requestEvents: selectedEventRows.map(mapDebugExportEvent),
1132
+ };
1133
+
1134
+ return c.json(response, 200);
1135
+ }
1136
+ );
1137
+ }