@syncular/server 0.1.3 → 0.2.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 (758) hide show
  1. package/README.md +773 -13
  2. package/dist/admin.d.ts +136 -0
  3. package/dist/admin.js +168 -0
  4. package/dist/blob-handlers.d.ts +69 -0
  5. package/dist/blob-handlers.js +245 -0
  6. package/dist/blob-store.d.ts +111 -0
  7. package/dist/blob-store.js +0 -0
  8. package/dist/content-encoding.d.ts +27 -0
  9. package/dist/content-encoding.js +69 -0
  10. package/dist/context.d.ts +151 -0
  11. package/dist/context.js +21 -0
  12. package/dist/crdt-merger.d.ts +28 -0
  13. package/dist/crdt-merger.js +11 -0
  14. package/dist/d1-storage.d.ts +50 -0
  15. package/dist/d1-storage.js +0 -0
  16. package/dist/errors.d.ts +35 -9
  17. package/dist/errors.js +220 -11
  18. package/dist/events-ring.d.ts +55 -0
  19. package/dist/events-ring.js +96 -0
  20. package/dist/events.d.ts +231 -0
  21. package/dist/events.js +22 -0
  22. package/dist/frame-bytes.d.ts +20 -0
  23. package/dist/frame-bytes.js +75 -0
  24. package/dist/handler.d.ts +9 -0
  25. package/dist/handler.js +490 -0
  26. package/dist/index.d.ts +42 -33
  27. package/dist/index.js +45 -27
  28. package/dist/lease-store.d.ts +50 -0
  29. package/dist/lease-store.js +0 -0
  30. package/dist/pg-executor-pglite.d.ts +27 -0
  31. package/dist/pg-executor-pglite.js +33 -0
  32. package/dist/pg-executor.d.ts +67 -0
  33. package/dist/pg-executor.js +56 -0
  34. package/dist/postgres-fanout.d.ts +83 -0
  35. package/dist/postgres-fanout.js +71 -0
  36. package/dist/postgres-storage.d.ts +69 -0
  37. package/dist/postgres-storage.js +766 -0
  38. package/dist/prune.d.ts +24 -39
  39. package/dist/prune.js +44 -146
  40. package/dist/pull.d.ts +42 -67
  41. package/dist/pull.js +387 -1187
  42. package/dist/push.d.ts +31 -66
  43. package/dist/push.js +406 -655
  44. package/dist/realtime.d.ts +197 -0
  45. package/dist/realtime.js +848 -0
  46. package/dist/relational-rows.d.ts +229 -0
  47. package/dist/relational-rows.js +514 -0
  48. package/dist/s3-blob-store.d.ts +142 -0
  49. package/dist/s3-blob-store.js +458 -0
  50. package/dist/s3-segment-store.d.ts +95 -0
  51. package/dist/s3-segment-store.js +380 -0
  52. package/dist/schema.d.ts +82 -286
  53. package/dist/schema.js +133 -9
  54. package/dist/scopes.d.ts +48 -0
  55. package/dist/scopes.js +98 -0
  56. package/dist/segment-download.d.ts +14 -0
  57. package/dist/segment-download.js +125 -0
  58. package/dist/segment-store.d.ts +81 -0
  59. package/dist/segment-store.js +63 -0
  60. package/dist/signed-url.d.ts +139 -0
  61. package/dist/signed-url.js +143 -0
  62. package/dist/sigv4.d.ts +97 -0
  63. package/dist/sigv4.js +161 -0
  64. package/dist/sqlite-blob-store.d.ts +22 -0
  65. package/dist/sqlite-blob-store.js +86 -0
  66. package/dist/sqlite-dialect.d.ts +101 -0
  67. package/dist/sqlite-dialect.js +250 -0
  68. package/dist/sqlite-image.d.ts +27 -0
  69. package/dist/sqlite-image.js +83 -0
  70. package/dist/sqlite-lease-store.d.ts +21 -0
  71. package/dist/sqlite-lease-store.js +94 -0
  72. package/dist/sqlite-segment-store.d.ts +25 -0
  73. package/dist/sqlite-segment-store.js +115 -0
  74. package/dist/sqlite-storage.d.ts +47 -0
  75. package/dist/sqlite-storage.js +477 -0
  76. package/dist/storage.d.ts +252 -0
  77. package/dist/storage.js +1 -0
  78. package/dist/validate.d.ts +83 -0
  79. package/dist/validate.js +44 -0
  80. package/package.json +17 -325
  81. package/src/admin.ts +312 -0
  82. package/src/blob-handlers.ts +340 -0
  83. package/src/blob-store.ts +0 -0
  84. package/src/content-encoding.ts +94 -0
  85. package/src/context.ts +176 -0
  86. package/src/crdt-merger.ts +33 -0
  87. package/src/d1-storage.ts +0 -0
  88. package/src/errors.ts +241 -19
  89. package/src/events-ring.ts +116 -0
  90. package/src/events.ts +291 -0
  91. package/src/frame-bytes.ts +94 -0
  92. package/src/handler.ts +678 -0
  93. package/src/index.ts +44 -27
  94. package/src/lease-store.ts +0 -0
  95. package/src/pg-executor-pglite.ts +63 -0
  96. package/src/pg-executor.ts +87 -0
  97. package/src/postgres-fanout.ts +143 -0
  98. package/src/postgres-storage.ts +1182 -0
  99. package/src/prune.ts +63 -289
  100. package/src/pull.ts +505 -1805
  101. package/src/push.ts +623 -1006
  102. package/src/realtime.ts +1082 -0
  103. package/src/relational-rows.ts +633 -0
  104. package/src/s3-blob-store.ts +616 -0
  105. package/src/s3-segment-store.ts +519 -0
  106. package/src/schema.ts +242 -281
  107. package/src/scopes.ts +127 -0
  108. package/src/segment-download.ts +169 -0
  109. package/src/segment-store.ts +154 -0
  110. package/src/signed-url.ts +308 -0
  111. package/src/sigv4.ts +267 -0
  112. package/src/sqlite-blob-store.ts +125 -0
  113. package/src/sqlite-dialect.ts +337 -0
  114. package/src/sqlite-image.ts +124 -0
  115. package/src/sqlite-lease-store.ts +144 -0
  116. package/src/sqlite-segment-store.ts +204 -0
  117. package/src/sqlite-storage.ts +792 -0
  118. package/src/storage.ts +316 -0
  119. package/src/validate.ts +123 -0
  120. package/dist/auth-leases.d.ts +0 -85
  121. package/dist/auth-leases.d.ts.map +0 -1
  122. package/dist/auth-leases.js +0 -368
  123. package/dist/auth-leases.js.map +0 -1
  124. package/dist/better-sqlite3.d.ts +0 -22
  125. package/dist/better-sqlite3.d.ts.map +0 -1
  126. package/dist/better-sqlite3.js +0 -16
  127. package/dist/better-sqlite3.js.map +0 -1
  128. package/dist/blobs/access.d.ts +0 -35
  129. package/dist/blobs/access.d.ts.map +0 -1
  130. package/dist/blobs/access.js +0 -149
  131. package/dist/blobs/access.js.map +0 -1
  132. package/dist/blobs/adapters/database.d.ts +0 -100
  133. package/dist/blobs/adapters/database.d.ts.map +0 -1
  134. package/dist/blobs/adapters/database.js +0 -247
  135. package/dist/blobs/adapters/database.js.map +0 -1
  136. package/dist/blobs/index.d.ts +0 -9
  137. package/dist/blobs/index.d.ts.map +0 -1
  138. package/dist/blobs/index.js +0 -9
  139. package/dist/blobs/index.js.map +0 -1
  140. package/dist/blobs/manager.d.ts +0 -220
  141. package/dist/blobs/manager.d.ts.map +0 -1
  142. package/dist/blobs/manager.js +0 -625
  143. package/dist/blobs/manager.js.map +0 -1
  144. package/dist/blobs/migrate.d.ts +0 -27
  145. package/dist/blobs/migrate.d.ts.map +0 -1
  146. package/dist/blobs/migrate.js +0 -127
  147. package/dist/blobs/migrate.js.map +0 -1
  148. package/dist/blobs/types.d.ts +0 -58
  149. package/dist/blobs/types.d.ts.map +0 -1
  150. package/dist/blobs/types.js +0 -5
  151. package/dist/blobs/types.js.map +0 -1
  152. package/dist/bun-sqlite.d.ts +0 -19
  153. package/dist/bun-sqlite.d.ts.map +0 -1
  154. package/dist/bun-sqlite.js +0 -19
  155. package/dist/bun-sqlite.js.map +0 -1
  156. package/dist/clients.d.ts +0 -15
  157. package/dist/clients.d.ts.map +0 -1
  158. package/dist/clients.js +0 -7
  159. package/dist/clients.js.map +0 -1
  160. package/dist/cloudflare/durable-object.d.ts +0 -93
  161. package/dist/cloudflare/durable-object.d.ts.map +0 -1
  162. package/dist/cloudflare/durable-object.js +0 -210
  163. package/dist/cloudflare/durable-object.js.map +0 -1
  164. package/dist/cloudflare/index.d.ts +0 -22
  165. package/dist/cloudflare/index.d.ts.map +0 -1
  166. package/dist/cloudflare/index.js +0 -22
  167. package/dist/cloudflare/index.js.map +0 -1
  168. package/dist/cloudflare/r2.d.ts +0 -180
  169. package/dist/cloudflare/r2.d.ts.map +0 -1
  170. package/dist/cloudflare/r2.js +0 -258
  171. package/dist/cloudflare/r2.js.map +0 -1
  172. package/dist/cloudflare/scope-cache.d.ts +0 -54
  173. package/dist/cloudflare/scope-cache.d.ts.map +0 -1
  174. package/dist/cloudflare/scope-cache.js +0 -223
  175. package/dist/cloudflare/scope-cache.js.map +0 -1
  176. package/dist/cloudflare/sentry.d.ts +0 -47
  177. package/dist/cloudflare/sentry.d.ts.map +0 -1
  178. package/dist/cloudflare/sentry.js +0 -163
  179. package/dist/cloudflare/sentry.js.map +0 -1
  180. package/dist/cloudflare/worker.d.ts +0 -46
  181. package/dist/cloudflare/worker.d.ts.map +0 -1
  182. package/dist/cloudflare/worker.js +0 -63
  183. package/dist/cloudflare/worker.js.map +0 -1
  184. package/dist/commit-integrity.d.ts +0 -38
  185. package/dist/commit-integrity.d.ts.map +0 -1
  186. package/dist/commit-integrity.js +0 -260
  187. package/dist/commit-integrity.js.map +0 -1
  188. package/dist/compaction.d.ts +0 -27
  189. package/dist/compaction.d.ts.map +0 -1
  190. package/dist/compaction.js +0 -49
  191. package/dist/compaction.js.map +0 -1
  192. package/dist/crdt-yjs/index.d.ts +0 -99
  193. package/dist/crdt-yjs/index.d.ts.map +0 -1
  194. package/dist/crdt-yjs/index.js +0 -629
  195. package/dist/crdt-yjs/index.js.map +0 -1
  196. package/dist/d1.d.ts +0 -13
  197. package/dist/d1.d.ts.map +0 -1
  198. package/dist/d1.js +0 -14
  199. package/dist/d1.js.map +0 -1
  200. package/dist/dialect/base.d.ts +0 -93
  201. package/dist/dialect/base.d.ts.map +0 -1
  202. package/dist/dialect/base.js +0 -181
  203. package/dist/dialect/base.js.map +0 -1
  204. package/dist/dialect/helpers.d.ts +0 -16
  205. package/dist/dialect/helpers.d.ts.map +0 -1
  206. package/dist/dialect/helpers.js +0 -83
  207. package/dist/dialect/helpers.js.map +0 -1
  208. package/dist/dialect/index.d.ts +0 -7
  209. package/dist/dialect/index.d.ts.map +0 -1
  210. package/dist/dialect/index.js +0 -7
  211. package/dist/dialect/index.js.map +0 -1
  212. package/dist/dialect/types.d.ts +0 -187
  213. package/dist/dialect/types.d.ts.map +0 -1
  214. package/dist/dialect/types.js +0 -8
  215. package/dist/dialect/types.js.map +0 -1
  216. package/dist/encrypted-crdt.d.ts +0 -67
  217. package/dist/encrypted-crdt.d.ts.map +0 -1
  218. package/dist/encrypted-crdt.js +0 -426
  219. package/dist/encrypted-crdt.js.map +0 -1
  220. package/dist/errors.d.ts.map +0 -1
  221. package/dist/errors.js.map +0 -1
  222. package/dist/filesystem/index.d.ts +0 -44
  223. package/dist/filesystem/index.d.ts.map +0 -1
  224. package/dist/filesystem/index.js +0 -164
  225. package/dist/filesystem/index.js.map +0 -1
  226. package/dist/handlers/collection.d.ts +0 -20
  227. package/dist/handlers/collection.d.ts.map +0 -1
  228. package/dist/handlers/collection.js +0 -42
  229. package/dist/handlers/collection.js.map +0 -1
  230. package/dist/handlers/create-handler.d.ts +0 -156
  231. package/dist/handlers/create-handler.d.ts.map +0 -1
  232. package/dist/handlers/create-handler.js +0 -626
  233. package/dist/handlers/create-handler.js.map +0 -1
  234. package/dist/handlers/index.d.ts +0 -4
  235. package/dist/handlers/index.d.ts.map +0 -1
  236. package/dist/handlers/index.js +0 -4
  237. package/dist/handlers/index.js.map +0 -1
  238. package/dist/handlers/types.d.ts +0 -295
  239. package/dist/handlers/types.d.ts.map +0 -1
  240. package/dist/handlers/types.js +0 -2
  241. package/dist/handlers/types.js.map +0 -1
  242. package/dist/helpers/conflict.d.ts +0 -52
  243. package/dist/helpers/conflict.d.ts.map +0 -1
  244. package/dist/helpers/conflict.js +0 -49
  245. package/dist/helpers/conflict.js.map +0 -1
  246. package/dist/helpers/emitted-change.d.ts +0 -56
  247. package/dist/helpers/emitted-change.d.ts.map +0 -1
  248. package/dist/helpers/emitted-change.js +0 -46
  249. package/dist/helpers/emitted-change.js.map +0 -1
  250. package/dist/helpers/index.d.ts +0 -12
  251. package/dist/helpers/index.d.ts.map +0 -1
  252. package/dist/helpers/index.js +0 -12
  253. package/dist/helpers/index.js.map +0 -1
  254. package/dist/helpers/paginate.d.ts +0 -49
  255. package/dist/helpers/paginate.d.ts.map +0 -1
  256. package/dist/helpers/paginate.js +0 -54
  257. package/dist/helpers/paginate.js.map +0 -1
  258. package/dist/helpers/scope-authorization.d.ts +0 -7
  259. package/dist/helpers/scope-authorization.d.ts.map +0 -1
  260. package/dist/helpers/scope-authorization.js +0 -19
  261. package/dist/helpers/scope-authorization.js.map +0 -1
  262. package/dist/helpers/scope-commit-index.d.ts +0 -12
  263. package/dist/helpers/scope-commit-index.d.ts.map +0 -1
  264. package/dist/helpers/scope-commit-index.js +0 -35
  265. package/dist/helpers/scope-commit-index.js.map +0 -1
  266. package/dist/helpers/scope-strings.d.ts +0 -74
  267. package/dist/helpers/scope-strings.d.ts.map +0 -1
  268. package/dist/helpers/scope-strings.js +0 -82
  269. package/dist/helpers/scope-strings.js.map +0 -1
  270. package/dist/hono/api-key-auth.d.ts +0 -49
  271. package/dist/hono/api-key-auth.d.ts.map +0 -1
  272. package/dist/hono/api-key-auth.js +0 -108
  273. package/dist/hono/api-key-auth.js.map +0 -1
  274. package/dist/hono/audit-redaction.d.ts +0 -20
  275. package/dist/hono/audit-redaction.d.ts.map +0 -1
  276. package/dist/hono/audit-redaction.js +0 -85
  277. package/dist/hono/audit-redaction.js.map +0 -1
  278. package/dist/hono/blobs.d.ts +0 -75
  279. package/dist/hono/blobs.d.ts.map +0 -1
  280. package/dist/hono/blobs.js +0 -586
  281. package/dist/hono/blobs.js.map +0 -1
  282. package/dist/hono/console/gateway.d.ts +0 -42
  283. package/dist/hono/console/gateway.d.ts.map +0 -1
  284. package/dist/hono/console/gateway.js +0 -2158
  285. package/dist/hono/console/gateway.js.map +0 -1
  286. package/dist/hono/console/live-auth.d.ts +0 -7
  287. package/dist/hono/console/live-auth.d.ts.map +0 -1
  288. package/dist/hono/console/live-auth.js +0 -39
  289. package/dist/hono/console/live-auth.js.map +0 -1
  290. package/dist/hono/console/route-descriptor.d.ts +0 -6
  291. package/dist/hono/console/route-descriptor.d.ts.map +0 -1
  292. package/dist/hono/console/route-descriptor.js +0 -16
  293. package/dist/hono/console/route-descriptor.js.map +0 -1
  294. package/dist/hono/console/routes/api-keys.d.ts +0 -8
  295. package/dist/hono/console/routes/api-keys.d.ts.map +0 -1
  296. package/dist/hono/console/routes/api-keys.js +0 -575
  297. package/dist/hono/console/routes/api-keys.js.map +0 -1
  298. package/dist/hono/console/routes/clients.d.ts +0 -8
  299. package/dist/hono/console/routes/clients.d.ts.map +0 -1
  300. package/dist/hono/console/routes/clients.js +0 -322
  301. package/dist/hono/console/routes/clients.js.map +0 -1
  302. package/dist/hono/console/routes/commits.d.ts +0 -8
  303. package/dist/hono/console/routes/commits.d.ts.map +0 -1
  304. package/dist/hono/console/routes/commits.js +0 -882
  305. package/dist/hono/console/routes/commits.js.map +0 -1
  306. package/dist/hono/console/routes/context.d.ts +0 -188
  307. package/dist/hono/console/routes/context.d.ts.map +0 -1
  308. package/dist/hono/console/routes/context.js +0 -633
  309. package/dist/hono/console/routes/context.js.map +0 -1
  310. package/dist/hono/console/routes/events.d.ts +0 -8
  311. package/dist/hono/console/routes/events.d.ts.map +0 -1
  312. package/dist/hono/console/routes/events.js +0 -501
  313. package/dist/hono/console/routes/events.js.map +0 -1
  314. package/dist/hono/console/routes/maintenance.d.ts +0 -8
  315. package/dist/hono/console/routes/maintenance.d.ts.map +0 -1
  316. package/dist/hono/console/routes/maintenance.js +0 -341
  317. package/dist/hono/console/routes/maintenance.js.map +0 -1
  318. package/dist/hono/console/routes/shared.d.ts +0 -174
  319. package/dist/hono/console/routes/shared.d.ts.map +0 -1
  320. package/dist/hono/console/routes/shared.js +0 -583
  321. package/dist/hono/console/routes/shared.js.map +0 -1
  322. package/dist/hono/console/routes/stats.d.ts +0 -8
  323. package/dist/hono/console/routes/stats.d.ts.map +0 -1
  324. package/dist/hono/console/routes/stats.js +0 -295
  325. package/dist/hono/console/routes/stats.js.map +0 -1
  326. package/dist/hono/console/routes/storage.d.ts +0 -8
  327. package/dist/hono/console/routes/storage.d.ts.map +0 -1
  328. package/dist/hono/console/routes/storage.js +0 -121
  329. package/dist/hono/console/routes/storage.js.map +0 -1
  330. package/dist/hono/console/routes.d.ts +0 -36
  331. package/dist/hono/console/routes.d.ts.map +0 -1
  332. package/dist/hono/console/routes.js +0 -112
  333. package/dist/hono/console/routes.js.map +0 -1
  334. package/dist/hono/console/schema-errors.d.ts +0 -2
  335. package/dist/hono/console/schema-errors.d.ts.map +0 -1
  336. package/dist/hono/console/schema-errors.js +0 -17
  337. package/dist/hono/console/schema-errors.js.map +0 -1
  338. package/dist/hono/console/schemas.d.ts +0 -1515
  339. package/dist/hono/console/schemas.d.ts.map +0 -1
  340. package/dist/hono/console/schemas.js +0 -661
  341. package/dist/hono/console/schemas.js.map +0 -1
  342. package/dist/hono/console/types.d.ts +0 -213
  343. package/dist/hono/console/types.d.ts.map +0 -1
  344. package/dist/hono/console/types.js +0 -2
  345. package/dist/hono/console/types.js.map +0 -1
  346. package/dist/hono/console/ui.d.ts +0 -38
  347. package/dist/hono/console/ui.d.ts.map +0 -1
  348. package/dist/hono/console/ui.js +0 -43
  349. package/dist/hono/console/ui.js.map +0 -1
  350. package/dist/hono/create-server.d.ts +0 -71
  351. package/dist/hono/create-server.d.ts.map +0 -1
  352. package/dist/hono/create-server.js +0 -121
  353. package/dist/hono/create-server.js.map +0 -1
  354. package/dist/hono/errors.d.ts +0 -13
  355. package/dist/hono/errors.d.ts.map +0 -1
  356. package/dist/hono/errors.js +0 -21
  357. package/dist/hono/errors.js.map +0 -1
  358. package/dist/hono/index.d.ts +0 -20
  359. package/dist/hono/index.d.ts.map +0 -1
  360. package/dist/hono/index.js +0 -31
  361. package/dist/hono/index.js.map +0 -1
  362. package/dist/hono/openapi.d.ts +0 -72
  363. package/dist/hono/openapi.d.ts.map +0 -1
  364. package/dist/hono/openapi.js +0 -99
  365. package/dist/hono/openapi.js.map +0 -1
  366. package/dist/hono/proxy/connection-manager.d.ts +0 -78
  367. package/dist/hono/proxy/connection-manager.d.ts.map +0 -1
  368. package/dist/hono/proxy/connection-manager.js +0 -251
  369. package/dist/hono/proxy/connection-manager.js.map +0 -1
  370. package/dist/hono/proxy/index.d.ts +0 -8
  371. package/dist/hono/proxy/index.d.ts.map +0 -1
  372. package/dist/hono/proxy/index.js +0 -8
  373. package/dist/hono/proxy/index.js.map +0 -1
  374. package/dist/hono/proxy/routes.d.ts +0 -86
  375. package/dist/hono/proxy/routes.d.ts.map +0 -1
  376. package/dist/hono/proxy/routes.js +0 -183
  377. package/dist/hono/proxy/routes.js.map +0 -1
  378. package/dist/hono/rate-limit.d.ts +0 -101
  379. package/dist/hono/rate-limit.d.ts.map +0 -1
  380. package/dist/hono/rate-limit.js +0 -184
  381. package/dist/hono/rate-limit.js.map +0 -1
  382. package/dist/hono/realtime-sync-packs.d.ts +0 -43
  383. package/dist/hono/realtime-sync-packs.d.ts.map +0 -1
  384. package/dist/hono/realtime-sync-packs.js +0 -219
  385. package/dist/hono/realtime-sync-packs.js.map +0 -1
  386. package/dist/hono/routes/audit.d.ts +0 -12
  387. package/dist/hono/routes/audit.d.ts.map +0 -1
  388. package/dist/hono/routes/audit.js +0 -385
  389. package/dist/hono/routes/audit.js.map +0 -1
  390. package/dist/hono/routes/auth-leases.d.ts +0 -8
  391. package/dist/hono/routes/auth-leases.d.ts.map +0 -1
  392. package/dist/hono/routes/auth-leases.js +0 -88
  393. package/dist/hono/routes/auth-leases.js.map +0 -1
  394. package/dist/hono/routes/combined.d.ts +0 -8
  395. package/dist/hono/routes/combined.d.ts.map +0 -1
  396. package/dist/hono/routes/combined.js +0 -392
  397. package/dist/hono/routes/combined.js.map +0 -1
  398. package/dist/hono/routes/context.d.ts +0 -314
  399. package/dist/hono/routes/context.d.ts.map +0 -1
  400. package/dist/hono/routes/context.js +0 -1147
  401. package/dist/hono/routes/context.js.map +0 -1
  402. package/dist/hono/routes/health.d.ts +0 -8
  403. package/dist/hono/routes/health.d.ts.map +0 -1
  404. package/dist/hono/routes/health.js +0 -16
  405. package/dist/hono/routes/health.js.map +0 -1
  406. package/dist/hono/routes/realtime.d.ts +0 -9
  407. package/dist/hono/routes/realtime.d.ts.map +0 -1
  408. package/dist/hono/routes/realtime.js +0 -626
  409. package/dist/hono/routes/realtime.js.map +0 -1
  410. package/dist/hono/routes/shared.d.ts +0 -689
  411. package/dist/hono/routes/shared.d.ts.map +0 -1
  412. package/dist/hono/routes/shared.js +0 -972
  413. package/dist/hono/routes/shared.js.map +0 -1
  414. package/dist/hono/routes/snapshots.d.ts +0 -10
  415. package/dist/hono/routes/snapshots.d.ts.map +0 -1
  416. package/dist/hono/routes/snapshots.js +0 -281
  417. package/dist/hono/routes/snapshots.js.map +0 -1
  418. package/dist/hono/routes.d.ts +0 -19
  419. package/dist/hono/routes.d.ts.map +0 -1
  420. package/dist/hono/routes.js +0 -37
  421. package/dist/hono/routes.js.map +0 -1
  422. package/dist/hono/validation.d.ts +0 -5
  423. package/dist/hono/validation.d.ts.map +0 -1
  424. package/dist/hono/validation.js +0 -47
  425. package/dist/hono/validation.js.map +0 -1
  426. package/dist/hono/websocket-origin.d.ts +0 -9
  427. package/dist/hono/websocket-origin.d.ts.map +0 -1
  428. package/dist/hono/websocket-origin.js +0 -96
  429. package/dist/hono/websocket-origin.js.map +0 -1
  430. package/dist/hono/ws.d.ts +0 -341
  431. package/dist/hono/ws.d.ts.map +0 -1
  432. package/dist/hono/ws.js +0 -711
  433. package/dist/hono/ws.js.map +0 -1
  434. package/dist/index.d.ts.map +0 -1
  435. package/dist/index.js.map +0 -1
  436. package/dist/libsql.d.ts +0 -29
  437. package/dist/libsql.d.ts.map +0 -1
  438. package/dist/libsql.js +0 -25
  439. package/dist/libsql.js.map +0 -1
  440. package/dist/migrate.d.ts +0 -14
  441. package/dist/migrate.d.ts.map +0 -1
  442. package/dist/migrate.js +0 -13
  443. package/dist/migrate.js.map +0 -1
  444. package/dist/neon.d.ts +0 -21
  445. package/dist/neon.d.ts.map +0 -1
  446. package/dist/neon.js +0 -22
  447. package/dist/neon.js.map +0 -1
  448. package/dist/notify.d.ts +0 -77
  449. package/dist/notify.d.ts.map +0 -1
  450. package/dist/notify.js +0 -233
  451. package/dist/notify.js.map +0 -1
  452. package/dist/pglite.d.ts +0 -37
  453. package/dist/pglite.d.ts.map +0 -1
  454. package/dist/pglite.js +0 -37
  455. package/dist/pglite.js.map +0 -1
  456. package/dist/plugins/index.d.ts +0 -2
  457. package/dist/plugins/index.d.ts.map +0 -1
  458. package/dist/plugins/index.js +0 -2
  459. package/dist/plugins/index.js.map +0 -1
  460. package/dist/plugins/types.d.ts +0 -73
  461. package/dist/plugins/types.d.ts.map +0 -1
  462. package/dist/plugins/types.js +0 -30
  463. package/dist/plugins/types.js.map +0 -1
  464. package/dist/postgres/index.d.ts +0 -68
  465. package/dist/postgres/index.d.ts.map +0 -1
  466. package/dist/postgres/index.js +0 -924
  467. package/dist/postgres/index.js.map +0 -1
  468. package/dist/proxy/collection.d.ts +0 -7
  469. package/dist/proxy/collection.d.ts.map +0 -1
  470. package/dist/proxy/collection.js +0 -6
  471. package/dist/proxy/collection.js.map +0 -1
  472. package/dist/proxy/handler.d.ts +0 -42
  473. package/dist/proxy/handler.d.ts.map +0 -1
  474. package/dist/proxy/handler.js +0 -102
  475. package/dist/proxy/handler.js.map +0 -1
  476. package/dist/proxy/index.d.ts +0 -9
  477. package/dist/proxy/index.d.ts.map +0 -1
  478. package/dist/proxy/index.js +0 -14
  479. package/dist/proxy/index.js.map +0 -1
  480. package/dist/proxy/mutation-detector.d.ts +0 -35
  481. package/dist/proxy/mutation-detector.d.ts.map +0 -1
  482. package/dist/proxy/mutation-detector.js +0 -246
  483. package/dist/proxy/mutation-detector.js.map +0 -1
  484. package/dist/proxy/oplog.d.ts +0 -30
  485. package/dist/proxy/oplog.d.ts.map +0 -1
  486. package/dist/proxy/oplog.js +0 -137
  487. package/dist/proxy/oplog.js.map +0 -1
  488. package/dist/proxy/types.d.ts +0 -44
  489. package/dist/proxy/types.d.ts.map +0 -1
  490. package/dist/proxy/types.js +0 -7
  491. package/dist/proxy/types.js.map +0 -1
  492. package/dist/prune.d.ts.map +0 -1
  493. package/dist/prune.js.map +0 -1
  494. package/dist/pull.d.ts.map +0 -1
  495. package/dist/pull.js.map +0 -1
  496. package/dist/push.d.ts.map +0 -1
  497. package/dist/push.js.map +0 -1
  498. package/dist/realtime/in-memory.d.ts +0 -13
  499. package/dist/realtime/in-memory.d.ts.map +0 -1
  500. package/dist/realtime/in-memory.js +0 -28
  501. package/dist/realtime/in-memory.js.map +0 -1
  502. package/dist/realtime/index.d.ts +0 -4
  503. package/dist/realtime/index.d.ts.map +0 -1
  504. package/dist/realtime/index.js +0 -3
  505. package/dist/realtime/index.js.map +0 -1
  506. package/dist/realtime/types.d.ts +0 -62
  507. package/dist/realtime/types.d.ts.map +0 -1
  508. package/dist/realtime/types.js +0 -19
  509. package/dist/realtime/types.js.map +0 -1
  510. package/dist/relay/client-role/forward-engine.d.ts +0 -63
  511. package/dist/relay/client-role/forward-engine.d.ts.map +0 -1
  512. package/dist/relay/client-role/forward-engine.js +0 -267
  513. package/dist/relay/client-role/forward-engine.js.map +0 -1
  514. package/dist/relay/client-role/index.d.ts +0 -9
  515. package/dist/relay/client-role/index.d.ts.map +0 -1
  516. package/dist/relay/client-role/index.js +0 -9
  517. package/dist/relay/client-role/index.js.map +0 -1
  518. package/dist/relay/client-role/pull-engine.d.ts +0 -72
  519. package/dist/relay/client-role/pull-engine.d.ts.map +0 -1
  520. package/dist/relay/client-role/pull-engine.js +0 -249
  521. package/dist/relay/client-role/pull-engine.js.map +0 -1
  522. package/dist/relay/client-role/sequence-mapper.d.ts +0 -65
  523. package/dist/relay/client-role/sequence-mapper.d.ts.map +0 -1
  524. package/dist/relay/client-role/sequence-mapper.js +0 -161
  525. package/dist/relay/client-role/sequence-mapper.js.map +0 -1
  526. package/dist/relay/evaluation/relay-paths.d.ts +0 -41
  527. package/dist/relay/evaluation/relay-paths.d.ts.map +0 -1
  528. package/dist/relay/evaluation/relay-paths.js +0 -504
  529. package/dist/relay/evaluation/relay-paths.js.map +0 -1
  530. package/dist/relay/evaluation/rust-boundary.d.ts +0 -47
  531. package/dist/relay/evaluation/rust-boundary.d.ts.map +0 -1
  532. package/dist/relay/evaluation/rust-boundary.js +0 -220
  533. package/dist/relay/evaluation/rust-boundary.js.map +0 -1
  534. package/dist/relay/index.d.ts +0 -37
  535. package/dist/relay/index.d.ts.map +0 -1
  536. package/dist/relay/index.js +0 -44
  537. package/dist/relay/index.js.map +0 -1
  538. package/dist/relay/migrate.d.ts +0 -18
  539. package/dist/relay/migrate.d.ts.map +0 -1
  540. package/dist/relay/migrate.js +0 -99
  541. package/dist/relay/migrate.js.map +0 -1
  542. package/dist/relay/mode-manager.d.ts +0 -60
  543. package/dist/relay/mode-manager.d.ts.map +0 -1
  544. package/dist/relay/mode-manager.js +0 -114
  545. package/dist/relay/mode-manager.js.map +0 -1
  546. package/dist/relay/realtime.d.ts +0 -90
  547. package/dist/relay/realtime.d.ts.map +0 -1
  548. package/dist/relay/realtime.js +0 -147
  549. package/dist/relay/realtime.js.map +0 -1
  550. package/dist/relay/relay.d.ts +0 -190
  551. package/dist/relay/relay.d.ts.map +0 -1
  552. package/dist/relay/relay.js +0 -320
  553. package/dist/relay/relay.js.map +0 -1
  554. package/dist/relay/schema.d.ts +0 -158
  555. package/dist/relay/schema.d.ts.map +0 -1
  556. package/dist/relay/schema.js +0 -7
  557. package/dist/relay/schema.js.map +0 -1
  558. package/dist/relay/server-role/index.d.ts +0 -56
  559. package/dist/relay/server-role/index.d.ts.map +0 -1
  560. package/dist/relay/server-role/index.js +0 -193
  561. package/dist/relay/server-role/index.js.map +0 -1
  562. package/dist/relay/server-role/pull.d.ts +0 -27
  563. package/dist/relay/server-role/pull.d.ts.map +0 -1
  564. package/dist/relay/server-role/pull.js +0 -24
  565. package/dist/relay/server-role/pull.js.map +0 -1
  566. package/dist/relay/server-role/push.d.ts +0 -29
  567. package/dist/relay/server-role/push.d.ts.map +0 -1
  568. package/dist/relay/server-role/push.js +0 -122
  569. package/dist/relay/server-role/push.js.map +0 -1
  570. package/dist/s3/index.d.ts +0 -83
  571. package/dist/s3/index.d.ts.map +0 -1
  572. package/dist/s3/index.js +0 -223
  573. package/dist/s3/index.js.map +0 -1
  574. package/dist/schema.d.ts.map +0 -1
  575. package/dist/schema.js.map +0 -1
  576. package/dist/service-worker/index.d.ts +0 -114
  577. package/dist/service-worker/index.d.ts.map +0 -1
  578. package/dist/service-worker/index.js +0 -487
  579. package/dist/service-worker/index.js.map +0 -1
  580. package/dist/snapshot-artifacts/sqlite-bun.d.ts +0 -15
  581. package/dist/snapshot-artifacts/sqlite-bun.d.ts.map +0 -1
  582. package/dist/snapshot-artifacts/sqlite-bun.js +0 -128
  583. package/dist/snapshot-artifacts/sqlite-bun.js.map +0 -1
  584. package/dist/snapshot-artifacts.d.ts +0 -206
  585. package/dist/snapshot-artifacts.d.ts.map +0 -1
  586. package/dist/snapshot-artifacts.js +0 -545
  587. package/dist/snapshot-artifacts.js.map +0 -1
  588. package/dist/snapshot-chunks/db-metadata.d.ts +0 -56
  589. package/dist/snapshot-chunks/db-metadata.d.ts.map +0 -1
  590. package/dist/snapshot-chunks/db-metadata.js +0 -360
  591. package/dist/snapshot-chunks/db-metadata.js.map +0 -1
  592. package/dist/snapshot-chunks/index.d.ts +0 -8
  593. package/dist/snapshot-chunks/index.d.ts.map +0 -1
  594. package/dist/snapshot-chunks/index.js +0 -8
  595. package/dist/snapshot-chunks/index.js.map +0 -1
  596. package/dist/snapshot-chunks/types.d.ts +0 -80
  597. package/dist/snapshot-chunks/types.d.ts.map +0 -1
  598. package/dist/snapshot-chunks/types.js +0 -8
  599. package/dist/snapshot-chunks/types.js.map +0 -1
  600. package/dist/snapshot-chunks.d.ts +0 -90
  601. package/dist/snapshot-chunks.d.ts.map +0 -1
  602. package/dist/snapshot-chunks.js +0 -304
  603. package/dist/snapshot-chunks.js.map +0 -1
  604. package/dist/sqlite/index.d.ts +0 -53
  605. package/dist/sqlite/index.d.ts.map +0 -1
  606. package/dist/sqlite/index.js +0 -795
  607. package/dist/sqlite/index.js.map +0 -1
  608. package/dist/sqlite3.d.ts +0 -22
  609. package/dist/sqlite3.d.ts.map +0 -1
  610. package/dist/sqlite3.js +0 -99
  611. package/dist/sqlite3.js.map +0 -1
  612. package/dist/stats.d.ts +0 -28
  613. package/dist/stats.d.ts.map +0 -1
  614. package/dist/stats.js +0 -93
  615. package/dist/stats.js.map +0 -1
  616. package/dist/subscriptions/cache.d.ts +0 -58
  617. package/dist/subscriptions/cache.d.ts.map +0 -1
  618. package/dist/subscriptions/cache.js +0 -250
  619. package/dist/subscriptions/cache.js.map +0 -1
  620. package/dist/subscriptions/index.d.ts +0 -3
  621. package/dist/subscriptions/index.d.ts.map +0 -1
  622. package/dist/subscriptions/index.js +0 -3
  623. package/dist/subscriptions/index.js.map +0 -1
  624. package/dist/subscriptions/resolve.d.ts +0 -40
  625. package/dist/subscriptions/resolve.d.ts.map +0 -1
  626. package/dist/subscriptions/resolve.js +0 -275
  627. package/dist/subscriptions/resolve.js.map +0 -1
  628. package/dist/sync.d.ts +0 -24
  629. package/dist/sync.d.ts.map +0 -1
  630. package/dist/sync.js +0 -27
  631. package/dist/sync.js.map +0 -1
  632. package/src/auth-leases.ts +0 -649
  633. package/src/better-sqlite3.ts +0 -35
  634. package/src/blobs/access.ts +0 -244
  635. package/src/blobs/adapters/database.ts +0 -397
  636. package/src/blobs/index.ts +0 -9
  637. package/src/blobs/manager.ts +0 -901
  638. package/src/blobs/migrate.ts +0 -158
  639. package/src/blobs/types.ts +0 -74
  640. package/src/bun-sqlite-ambient.d.ts +0 -19
  641. package/src/bun-sqlite.ts +0 -27
  642. package/src/clients.ts +0 -22
  643. package/src/cloudflare/durable-object.ts +0 -289
  644. package/src/cloudflare/index.ts +0 -22
  645. package/src/cloudflare/r2.ts +0 -526
  646. package/src/cloudflare/scope-cache.ts +0 -341
  647. package/src/cloudflare/sentry.ts +0 -230
  648. package/src/cloudflare/worker.ts +0 -77
  649. package/src/commit-integrity.ts +0 -371
  650. package/src/compaction.ts +0 -77
  651. package/src/crdt-yjs/index.ts +0 -931
  652. package/src/d1.ts +0 -16
  653. package/src/dialect/base.ts +0 -360
  654. package/src/dialect/helpers.ts +0 -92
  655. package/src/dialect/index.ts +0 -7
  656. package/src/dialect/types.ts +0 -247
  657. package/src/encrypted-crdt.ts +0 -786
  658. package/src/filesystem/index.ts +0 -262
  659. package/src/handlers/collection.ts +0 -121
  660. package/src/handlers/create-handler.ts +0 -1134
  661. package/src/handlers/index.ts +0 -3
  662. package/src/handlers/types.ts +0 -403
  663. package/src/helpers/conflict.ts +0 -64
  664. package/src/helpers/emitted-change.ts +0 -69
  665. package/src/helpers/index.ts +0 -12
  666. package/src/helpers/paginate.ts +0 -82
  667. package/src/helpers/scope-authorization.ts +0 -27
  668. package/src/helpers/scope-commit-index.ts +0 -52
  669. package/src/helpers/scope-strings.ts +0 -101
  670. package/src/hono/api-key-auth.ts +0 -177
  671. package/src/hono/audit-redaction.ts +0 -135
  672. package/src/hono/blobs.ts +0 -851
  673. package/src/hono/console/gateway.ts +0 -3046
  674. package/src/hono/console/live-auth.ts +0 -46
  675. package/src/hono/console/route-descriptor.ts +0 -22
  676. package/src/hono/console/routes/api-keys.ts +0 -721
  677. package/src/hono/console/routes/clients.ts +0 -447
  678. package/src/hono/console/routes/commits.ts +0 -1137
  679. package/src/hono/console/routes/context.ts +0 -956
  680. package/src/hono/console/routes/events.ts +0 -669
  681. package/src/hono/console/routes/maintenance.ts +0 -461
  682. package/src/hono/console/routes/shared.ts +0 -816
  683. package/src/hono/console/routes/stats.ts +0 -392
  684. package/src/hono/console/routes/storage.ts +0 -159
  685. package/src/hono/console/routes.ts +0 -146
  686. package/src/hono/console/schema-errors.ts +0 -23
  687. package/src/hono/console/schemas.ts +0 -914
  688. package/src/hono/console/types.ts +0 -223
  689. package/src/hono/console/ui.ts +0 -100
  690. package/src/hono/create-server.ts +0 -230
  691. package/src/hono/errors.ts +0 -50
  692. package/src/hono/index.ts +0 -54
  693. package/src/hono/openapi.ts +0 -139
  694. package/src/hono/proxy/connection-manager.ts +0 -340
  695. package/src/hono/proxy/index.ts +0 -8
  696. package/src/hono/proxy/routes.ts +0 -272
  697. package/src/hono/rate-limit.ts +0 -319
  698. package/src/hono/realtime-sync-packs.ts +0 -354
  699. package/src/hono/routes/audit.ts +0 -499
  700. package/src/hono/routes/auth-leases.ts +0 -119
  701. package/src/hono/routes/combined.ts +0 -583
  702. package/src/hono/routes/context.ts +0 -1629
  703. package/src/hono/routes/health.ts +0 -26
  704. package/src/hono/routes/realtime.ts +0 -808
  705. package/src/hono/routes/shared.ts +0 -1626
  706. package/src/hono/routes/snapshots.ts +0 -345
  707. package/src/hono/routes.ts +0 -68
  708. package/src/hono/validation.ts +0 -81
  709. package/src/hono/websocket-origin.ts +0 -131
  710. package/src/hono/ws.ts +0 -1134
  711. package/src/libsql.ts +0 -51
  712. package/src/migrate.ts +0 -20
  713. package/src/neon.ts +0 -28
  714. package/src/notify.ts +0 -341
  715. package/src/pglite.ts +0 -68
  716. package/src/plugins/index.ts +0 -1
  717. package/src/plugins/types.ts +0 -144
  718. package/src/postgres/index.ts +0 -1291
  719. package/src/proxy/collection.ts +0 -17
  720. package/src/proxy/handler.ts +0 -159
  721. package/src/proxy/index.ts +0 -21
  722. package/src/proxy/mutation-detector.ts +0 -281
  723. package/src/proxy/oplog.ts +0 -181
  724. package/src/proxy/types.ts +0 -46
  725. package/src/realtime/in-memory.ts +0 -33
  726. package/src/realtime/index.ts +0 -7
  727. package/src/realtime/types.ts +0 -90
  728. package/src/relay/bun-types.d.ts +0 -50
  729. package/src/relay/client-role/forward-engine.ts +0 -355
  730. package/src/relay/client-role/index.ts +0 -9
  731. package/src/relay/client-role/pull-engine.ts +0 -329
  732. package/src/relay/client-role/sequence-mapper.ts +0 -201
  733. package/src/relay/evaluation/relay-paths.ts +0 -699
  734. package/src/relay/evaluation/rust-boundary.ts +0 -464
  735. package/src/relay/index.ts +0 -50
  736. package/src/relay/migrate.ts +0 -113
  737. package/src/relay/mode-manager.ts +0 -142
  738. package/src/relay/realtime.ts +0 -207
  739. package/src/relay/relay.ts +0 -431
  740. package/src/relay/schema.ts +0 -171
  741. package/src/relay/server-role/index.ts +0 -338
  742. package/src/relay/server-role/pull.ts +0 -43
  743. package/src/relay/server-role/push.ts +0 -164
  744. package/src/s3/index.ts +0 -346
  745. package/src/service-worker/index.ts +0 -773
  746. package/src/snapshot-artifacts/sqlite-bun.ts +0 -168
  747. package/src/snapshot-artifacts.ts +0 -896
  748. package/src/snapshot-chunks/db-metadata.ts +0 -537
  749. package/src/snapshot-chunks/index.ts +0 -8
  750. package/src/snapshot-chunks/types.ts +0 -105
  751. package/src/snapshot-chunks.ts +0 -453
  752. package/src/sqlite/index.ts +0 -1064
  753. package/src/sqlite3.ts +0 -137
  754. package/src/stats.ts +0 -180
  755. package/src/subscriptions/cache.ts +0 -376
  756. package/src/subscriptions/index.ts +0 -2
  757. package/src/subscriptions/resolve.ts +0 -357
  758. package/src/sync.ts +0 -111
@@ -0,0 +1,519 @@
1
+ /**
2
+ * S3-compatible segment store (SPEC.md §5.1 cache semantics, §5.4
3
+ * delegated presign) — AWS S3, Cloudflare R2, MinIO. Zero dependencies:
4
+ * hand-rolled SigV4 over `fetch` (sigv4.ts).
5
+ *
6
+ * Key layout (deterministic — every lookup is a GET/HEAD, never a LIST):
7
+ *
8
+ * {keyPrefix}seg/sha256/{hex}
9
+ * The segment bytes, verbatim (the object body MUST be exactly the
10
+ * content-addressed bytes so presigned GETs serve them directly and
11
+ * the client's §5.1 hash check passes). The full `SegmentRecord`
12
+ * (minus bytes) rides along as object user metadata
13
+ * `x-amz-meta-syncular-record` = base64url(JSON), so `get` is a
14
+ * single GET.
15
+ *
16
+ * {keyPrefix}find/{sha256Hex(canonical reuse key)}.json
17
+ * Whole-table reuse pointer (§5.3): written only when
18
+ * `rowCursor === null`, body = the record JSON. The reuse key is the
19
+ * canonical JSON array `[partition, table, schemaVersion, mediaType,
20
+ * scopeDigest, asOfCommitSeq]`, so `find` is one GET (plus a HEAD to
21
+ * confirm the segment object itself still exists — lifecycle GC may
22
+ * remove objects independently of pointers).
23
+ *
24
+ * TTL mapping: expiry is **store-side and authoritative** — `expiresAtMs`
25
+ * (put-time + `ttlMs`, default 24 h) is recorded in the object metadata
26
+ * and the pointer; `get` returns expired records so §5.5 can answer
27
+ * `sync.segment_expired`, and `find` filters them out itself. S3 lifecycle
28
+ * expiration is garbage collection only: configure it comfortably ABOVE
29
+ * `ttlMs` (e.g. 2 days for the 24 h default) so clients normally see the
30
+ * precise, retryable `sync.segment_expired` and hit `sync.not_found` only
31
+ * long after. Never set lifecycle below `ttlMs`.
32
+ */
33
+ import type {
34
+ SegmentFindKey,
35
+ SegmentMetadata,
36
+ SegmentRecord,
37
+ SegmentStore,
38
+ SegmentStoreStats,
39
+ } from './segment-store';
40
+ import { segmentIdFor } from './segment-store';
41
+ import type { DelegatedPresignConfig, SegmentUrlIssue } from './signed-url';
42
+ import {
43
+ EMPTY_PAYLOAD_SHA256,
44
+ presignUrl,
45
+ type SigV4Credentials,
46
+ sha256Hex,
47
+ signRequest,
48
+ } from './sigv4';
49
+
50
+ export interface S3SegmentStoreConfig {
51
+ /**
52
+ * Endpoint origin, no bucket, no trailing slash:
53
+ * AWS `https://s3.<region>.amazonaws.com`,
54
+ * R2 `https://<account-id>.r2.cloudflarestorage.com`,
55
+ * MinIO `http://127.0.0.1:9000`. Requests are path-style
56
+ * (`{endpoint}/{bucket}/{key}`), which all three accept.
57
+ */
58
+ readonly endpoint: string;
59
+ /** AWS region; R2 uses `auto`. */
60
+ readonly region: string;
61
+ readonly bucket: string;
62
+ readonly accessKeyId: string;
63
+ readonly secretAccessKey: string;
64
+ /** Optional STS session token. */
65
+ readonly sessionToken?: string;
66
+ /** Key namespace inside the bucket, e.g. `syncular/`. Default: none. */
67
+ readonly keyPrefix?: string;
68
+ /** Segment TTL (§5.1 cache semantics). Default 24 h. */
69
+ readonly ttlMs?: number;
70
+ }
71
+
72
+ const DEFAULT_TTL_MS = 24 * 60 * 60 * 1000;
73
+ const SEGMENT_ID_PATTERN = /^sha256:[0-9a-f]{64}$/;
74
+ const RECORD_META_HEADER = 'x-amz-meta-syncular-record';
75
+
76
+ /**
77
+ * Stats accumulator (§ "S3 stats" in the README). The store keeps a small
78
+ * counter object under a fixed key, updated read-modify-write on `put`. It
79
+ * exists because a LIST-free store (every lookup is a GET/HEAD) has no cheap
80
+ * way to count objects on demand — so `stats()` reads the accumulator instead
81
+ * of enumerating the bucket.
82
+ *
83
+ * The write is guarded by an ETag compare-and-swap (`If-Match`, or
84
+ * `If-None-Match: *` to create): the loop re-reads and retries on a `412`
85
+ * precondition failure, so concurrent writers do not silently clobber each
86
+ * other's increment. The counters are still APPROXIMATE — a crash between the
87
+ * segment PUT and the accumulator CAS, or a writer against a backend that
88
+ * ignores conditional headers, can drift them — so the admin surface labels
89
+ * S3 stats `approximate: true`. They are a health gauge, not an invoice.
90
+ */
91
+ const STATS_KEY_SUFFIX = 'stats/segments.json';
92
+ const STATS_CAS_ATTEMPTS = 16;
93
+
94
+ interface StatsAccumulator {
95
+ count: number;
96
+ bytes: number;
97
+ rowsSegments: number;
98
+ sqliteSegments: number;
99
+ }
100
+
101
+ function emptyStats(): StatsAccumulator {
102
+ return { count: 0, bytes: 0, rowsSegments: 0, sqliteSegments: 0 };
103
+ }
104
+
105
+ function parseStatsJson(json: string): StatsAccumulator {
106
+ const parsed = JSON.parse(json) as Partial<StatsAccumulator>;
107
+ return {
108
+ count: Number(parsed.count ?? 0),
109
+ bytes: Number(parsed.bytes ?? 0),
110
+ rowsSegments: Number(parsed.rowsSegments ?? 0),
111
+ sqliteSegments: Number(parsed.sqliteSegments ?? 0),
112
+ };
113
+ }
114
+
115
+ // Runtime-neutral base64url (TODO §4.2): `Buffer` is not present on
116
+ // Cloudflare Workers without `nodejs_compat`, so the object-metadata record
117
+ // header is (de)coded with `btoa`/`atob`, available in every runtime.
118
+ function utf8ToBase64url(text: string): string {
119
+ let binary = '';
120
+ for (const byte of new TextEncoder().encode(text)) {
121
+ binary += String.fromCharCode(byte);
122
+ }
123
+ return btoa(binary)
124
+ .replaceAll('+', '-')
125
+ .replaceAll('/', '_')
126
+ .replace(/=+$/, '');
127
+ }
128
+
129
+ function base64urlToUtf8(value: string): string {
130
+ const binary = atob(value.replaceAll('-', '+').replaceAll('_', '/'));
131
+ const bytes = new Uint8Array(binary.length);
132
+ for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
133
+ return new TextDecoder().decode(bytes);
134
+ }
135
+
136
+ function recordToJson(record: SegmentRecord): string {
137
+ return JSON.stringify(record);
138
+ }
139
+
140
+ function isMediaType(value: unknown): value is 'rows' | 'sqlite' {
141
+ return value === 'rows' || value === 'sqlite';
142
+ }
143
+
144
+ function parseRecordJson(json: string, source: string): SegmentRecord {
145
+ let parsed: unknown;
146
+ try {
147
+ parsed = JSON.parse(json);
148
+ } catch {
149
+ throw new Error(`S3SegmentStore: corrupt record JSON in ${source}`);
150
+ }
151
+ if (typeof parsed !== 'object' || parsed === null) {
152
+ throw new Error(`S3SegmentStore: corrupt record in ${source}`);
153
+ }
154
+ const r = parsed as Record<string, unknown>;
155
+ const strings = ['segmentId', 'partition', 'table', 'scopeDigest'] as const;
156
+ const numbers = [
157
+ 'schemaVersion',
158
+ 'asOfCommitSeq',
159
+ 'rowCount',
160
+ 'byteLength',
161
+ 'createdAtMs',
162
+ 'expiresAtMs',
163
+ ] as const;
164
+ for (const field of strings) {
165
+ if (typeof r[field] !== 'string') {
166
+ throw new Error(`S3SegmentStore: bad record field ${field} in ${source}`);
167
+ }
168
+ }
169
+ for (const field of numbers) {
170
+ if (typeof r[field] !== 'number') {
171
+ throw new Error(`S3SegmentStore: bad record field ${field} in ${source}`);
172
+ }
173
+ }
174
+ if (!isMediaType(r.mediaType)) {
175
+ throw new Error(`S3SegmentStore: bad record mediaType in ${source}`);
176
+ }
177
+ const cursorOk = (v: unknown): v is string | null =>
178
+ v === null || typeof v === 'string';
179
+ if (!cursorOk(r.rowCursor) || !cursorOk(r.nextRowCursor)) {
180
+ throw new Error(`S3SegmentStore: bad record cursor in ${source}`);
181
+ }
182
+ return {
183
+ segmentId: r.segmentId as string,
184
+ partition: r.partition as string,
185
+ table: r.table as string,
186
+ schemaVersion: r.schemaVersion as number,
187
+ mediaType: r.mediaType,
188
+ scopeDigest: r.scopeDigest as string,
189
+ asOfCommitSeq: r.asOfCommitSeq as number,
190
+ rowCount: r.rowCount as number,
191
+ rowCursor: r.rowCursor,
192
+ nextRowCursor: r.nextRowCursor,
193
+ byteLength: r.byteLength as number,
194
+ createdAtMs: r.createdAtMs as number,
195
+ expiresAtMs: r.expiresAtMs as number,
196
+ };
197
+ }
198
+
199
+ export class S3SegmentStore implements SegmentStore {
200
+ readonly #config: S3SegmentStoreConfig;
201
+ readonly #credentials: SigV4Credentials;
202
+ readonly #ttlMs: number;
203
+ readonly #prefix: string;
204
+
205
+ constructor(config: S3SegmentStoreConfig) {
206
+ this.#config = config;
207
+ this.#credentials = {
208
+ accessKeyId: config.accessKeyId,
209
+ secretAccessKey: config.secretAccessKey,
210
+ ...(config.sessionToken !== undefined
211
+ ? { sessionToken: config.sessionToken }
212
+ : {}),
213
+ };
214
+ this.#ttlMs = config.ttlMs ?? DEFAULT_TTL_MS;
215
+ this.#prefix = config.keyPrefix ?? '';
216
+ }
217
+
218
+ /** `{keyPrefix}seg/sha256/{hex}` — the §5.4 "key embeds the segmentId". */
219
+ objectKeyFor(segmentId: string): string {
220
+ return `${this.#prefix}seg/${segmentId.replace(':', '/')}`;
221
+ }
222
+
223
+ async #findKeyFor(key: SegmentFindKey): Promise<string> {
224
+ const canonical = JSON.stringify([
225
+ key.partition,
226
+ key.table,
227
+ key.schemaVersion,
228
+ key.mediaType,
229
+ key.scopeDigest,
230
+ key.asOfCommitSeq,
231
+ ]);
232
+ return `${this.#prefix}find/${await sha256Hex(canonical)}.json`;
233
+ }
234
+
235
+ #statsKey(): string {
236
+ return `${this.#prefix}${STATS_KEY_SUFFIX}`;
237
+ }
238
+
239
+ #urlFor(key: string): URL {
240
+ const endpoint = this.#config.endpoint.replace(/\/+$/, '');
241
+ return new URL(`${endpoint}/${this.#config.bucket}/${key}`);
242
+ }
243
+
244
+ async #request(
245
+ method: 'GET' | 'HEAD' | 'PUT' | 'DELETE',
246
+ key: string,
247
+ options?: {
248
+ readonly body?: Uint8Array;
249
+ readonly headers?: Readonly<Record<string, string>>;
250
+ },
251
+ ): Promise<Response | undefined> {
252
+ const url = this.#urlFor(key);
253
+ const body = options?.body;
254
+ const headers = await signRequest({
255
+ method,
256
+ url,
257
+ region: this.#config.region,
258
+ credentials: this.#credentials,
259
+ nowMs: Date.now(),
260
+ payloadHash:
261
+ body === undefined ? EMPTY_PAYLOAD_SHA256 : await sha256Hex(body),
262
+ ...(options?.headers !== undefined ? { headers: options.headers } : {}),
263
+ });
264
+ const response = await fetch(url, {
265
+ method,
266
+ headers,
267
+ ...(body !== undefined ? { body: body as BodyInit } : {}),
268
+ });
269
+ if (response.status === 404) {
270
+ await response.arrayBuffer();
271
+ return undefined;
272
+ }
273
+ if (!response.ok) {
274
+ const detail = (await response.text()).slice(0, 300);
275
+ throw new Error(
276
+ `S3SegmentStore: ${method} ${key} failed with ${response.status}: ${detail}`,
277
+ );
278
+ }
279
+ return response;
280
+ }
281
+
282
+ /** Read the stats accumulator + its ETag (for the CAS write), or none. */
283
+ async #readStats(): Promise<{
284
+ stats: StatsAccumulator;
285
+ etag: string | undefined;
286
+ }> {
287
+ const response = await this.#request('GET', this.#statsKey());
288
+ if (response === undefined) {
289
+ return { stats: emptyStats(), etag: undefined };
290
+ }
291
+ const etag = response.headers.get('etag') ?? undefined;
292
+ const stats = parseStatsJson(await response.text());
293
+ return { stats, etag };
294
+ }
295
+
296
+ /**
297
+ * Conditionally write the stats accumulator. `etag` present ⇒ `If-Match`
298
+ * (update the object we read); absent ⇒ `If-None-Match: *` (create only).
299
+ * Returns `false` on a `412` precondition failure so the caller retries.
300
+ */
301
+ async #writeStatsCas(
302
+ stats: StatsAccumulator,
303
+ etag: string | undefined,
304
+ ): Promise<boolean> {
305
+ const url = this.#urlFor(this.#statsKey());
306
+ const body = new TextEncoder().encode(JSON.stringify(stats));
307
+ const conditional: Record<string, string> =
308
+ etag === undefined ? { 'if-none-match': '*' } : { 'if-match': etag };
309
+ const headers = await signRequest({
310
+ method: 'PUT',
311
+ url,
312
+ region: this.#config.region,
313
+ credentials: this.#credentials,
314
+ nowMs: Date.now(),
315
+ payloadHash: await sha256Hex(body),
316
+ headers: { 'content-type': 'application/json', ...conditional },
317
+ });
318
+ const response = await fetch(url, {
319
+ method: 'PUT',
320
+ headers,
321
+ body: body as BodyInit,
322
+ });
323
+ if (response.status === 412) {
324
+ await response.arrayBuffer();
325
+ return false;
326
+ }
327
+ if (!response.ok) {
328
+ const detail = (await response.text()).slice(0, 300);
329
+ throw new Error(
330
+ `S3SegmentStore: stats PUT failed with ${response.status}: ${detail}`,
331
+ );
332
+ }
333
+ await response.arrayBuffer();
334
+ return true;
335
+ }
336
+
337
+ /**
338
+ * Fold `delta` into the stats accumulator under an ETag compare-and-swap
339
+ * retry loop. Best-effort: exhausting the retry budget leaves the counters
340
+ * drifted (they are documented APPROXIMATE) rather than failing the `put`
341
+ * that already stored the bytes.
342
+ */
343
+ async #bumpStats(delta: StatsAccumulator): Promise<void> {
344
+ for (let attempt = 0; attempt < STATS_CAS_ATTEMPTS; attempt++) {
345
+ const { stats, etag } = await this.#readStats();
346
+ const next: StatsAccumulator = {
347
+ count: stats.count + delta.count,
348
+ bytes: stats.bytes + delta.bytes,
349
+ rowsSegments: stats.rowsSegments + delta.rowsSegments,
350
+ sqliteSegments: stats.sqliteSegments + delta.sqliteSegments,
351
+ };
352
+ if (await this.#writeStatsCas(next, etag)) return;
353
+ }
354
+ // Lost the CAS race `STATS_CAS_ATTEMPTS` times running — leave the
355
+ // counters as-is. `stats()` stays APPROXIMATE by contract.
356
+ }
357
+
358
+ async put(
359
+ metadata: SegmentMetadata,
360
+ bytes: Uint8Array,
361
+ nowMs: number,
362
+ ): Promise<SegmentRecord> {
363
+ const segmentId = await segmentIdFor(bytes);
364
+ const record: SegmentRecord = {
365
+ ...metadata,
366
+ segmentId,
367
+ byteLength: bytes.length,
368
+ createdAtMs: nowMs,
369
+ expiresAtMs: nowMs + this.#ttlMs,
370
+ };
371
+ const recordJson = recordToJson(record);
372
+ // Detect an idempotent re-put (same content-address ⇒ same key) so the
373
+ // stats accumulator counts each distinct segment once, not once per PUT.
374
+ const objectKey = this.objectKeyFor(segmentId);
375
+ const preexisting = await this.#request('HEAD', objectKey);
376
+ await preexisting?.arrayBuffer();
377
+ const isNew = preexisting === undefined;
378
+ const response = await this.#request('PUT', objectKey, {
379
+ body: bytes,
380
+ headers: {
381
+ 'content-type': 'application/octet-stream',
382
+ [RECORD_META_HEADER]: utf8ToBase64url(recordJson),
383
+ },
384
+ });
385
+ await response?.arrayBuffer();
386
+ if (isNew) {
387
+ await this.#bumpStats({
388
+ count: 1,
389
+ bytes: bytes.length,
390
+ rowsSegments: metadata.mediaType === 'rows' ? 1 : 0,
391
+ sqliteSegments: metadata.mediaType === 'sqlite' ? 1 : 0,
392
+ });
393
+ }
394
+ if (metadata.rowCursor === null) {
395
+ const pointer = await this.#request(
396
+ 'PUT',
397
+ await this.#findKeyFor(metadata),
398
+ {
399
+ body: new TextEncoder().encode(recordJson),
400
+ headers: { 'content-type': 'application/json' },
401
+ },
402
+ );
403
+ await pointer?.arrayBuffer();
404
+ }
405
+ return record;
406
+ }
407
+
408
+ async get(
409
+ segmentId: string,
410
+ ): Promise<{ record: SegmentRecord; bytes: Uint8Array } | undefined> {
411
+ if (!SEGMENT_ID_PATTERN.test(segmentId)) return undefined;
412
+ const response = await this.#request('GET', this.objectKeyFor(segmentId));
413
+ if (response === undefined) return undefined;
414
+ const bytes = new Uint8Array(await response.arrayBuffer());
415
+ const meta = response.headers.get(RECORD_META_HEADER);
416
+ if (meta === null) {
417
+ throw new Error(
418
+ `S3SegmentStore: object for ${segmentId} lacks ${RECORD_META_HEADER}`,
419
+ );
420
+ }
421
+ const record = parseRecordJson(base64urlToUtf8(meta), segmentId);
422
+ return { record, bytes };
423
+ }
424
+
425
+ async find(
426
+ key: SegmentFindKey,
427
+ nowMs: number,
428
+ ): Promise<SegmentRecord | undefined> {
429
+ const response = await this.#request('GET', await this.#findKeyFor(key));
430
+ if (response === undefined) return undefined;
431
+ const record = parseRecordJson(await response.text(), 'reuse pointer');
432
+ if (
433
+ record.partition !== key.partition ||
434
+ record.table !== key.table ||
435
+ record.schemaVersion !== key.schemaVersion ||
436
+ record.mediaType !== key.mediaType ||
437
+ record.scopeDigest !== key.scopeDigest ||
438
+ record.asOfCommitSeq !== key.asOfCommitSeq ||
439
+ record.rowCursor !== null
440
+ ) {
441
+ return undefined;
442
+ }
443
+ if (record.expiresAtMs <= nowMs) return undefined;
444
+ // Lifecycle GC may have removed the object while the pointer survived.
445
+ const head = await this.#request(
446
+ 'HEAD',
447
+ this.objectKeyFor(record.segmentId),
448
+ );
449
+ if (head === undefined) return undefined;
450
+ await head.arrayBuffer();
451
+ return record;
452
+ }
453
+
454
+ /**
455
+ * Store-wide counters from the pointer-object accumulator (never a LIST).
456
+ * Marked `approximate: true`: the counters are maintained by a best-effort
457
+ * ETag-CAS read-modify-write on `put`, so a crash between the segment PUT
458
+ * and the accumulator write, or lifecycle GC that deletes objects the
459
+ * accumulator still counts, can drift them. Exact within a single writer;
460
+ * a health gauge under concurrency. See the README "S3 stats".
461
+ */
462
+ async stats(): Promise<SegmentStoreStats> {
463
+ const { stats } = await this.#readStats();
464
+ return {
465
+ count: stats.count,
466
+ bytes: stats.bytes,
467
+ rowsSegments: stats.rowsSegments,
468
+ sqliteSegments: stats.sqliteSegments,
469
+ approximate: true,
470
+ };
471
+ }
472
+
473
+ /**
474
+ * SigV4 presigned GET for a segment object (§5.4 delegated presign).
475
+ * The signed key embeds the `segmentId` (equivalence rule) and
476
+ * `urlExpiresAtMs` is the provider-enforced expiry
477
+ * (`X-Amz-Date + X-Amz-Expires`). TTL SHOULD be ≤ 15 minutes (§5.4);
478
+ * default 900 s.
479
+ */
480
+ async presignSegmentGet(
481
+ segmentId: string,
482
+ options?: { readonly ttlSeconds?: number; readonly nowMs?: number },
483
+ ): Promise<SegmentUrlIssue> {
484
+ if (!SEGMENT_ID_PATTERN.test(segmentId)) {
485
+ throw new Error(`S3SegmentStore: malformed segmentId ${segmentId}`);
486
+ }
487
+ const ttlSeconds = options?.ttlSeconds ?? 900;
488
+ const nowMs = options?.nowMs ?? Date.now();
489
+ const url = await presignUrl({
490
+ url: this.#urlFor(this.objectKeyFor(segmentId)),
491
+ region: this.#config.region,
492
+ credentials: this.#credentials,
493
+ nowMs,
494
+ expiresSeconds: ttlSeconds,
495
+ });
496
+ return {
497
+ url: url.toString(),
498
+ urlExpiresAtMs: (Math.floor(nowMs / 1000) + ttlSeconds) * 1000,
499
+ };
500
+ }
501
+ }
502
+
503
+ /**
504
+ * Wire an `S3SegmentStore` into `SyncServerConfig.signedUrls` as the §5.4
505
+ * delegated-presign scheme:
506
+ * `signedUrls: s3PresignedUrls(store, { ttlSeconds: 900 })`.
507
+ */
508
+ export function s3PresignedUrls(
509
+ store: S3SegmentStore,
510
+ options?: { readonly ttlSeconds?: number },
511
+ ): DelegatedPresignConfig {
512
+ return {
513
+ ...(options?.ttlSeconds !== undefined
514
+ ? { ttlSeconds: options.ttlSeconds }
515
+ : {}),
516
+ presign: ({ segmentId, ttlSeconds, nowMs }) =>
517
+ store.presignSegmentGet(segmentId, { ttlSeconds, nowMs }),
518
+ };
519
+ }