@syncular/server 0.0.6-96 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (601) hide show
  1. package/README.md +1 -2
  2. package/dist/auth-leases.d.ts +85 -0
  3. package/dist/auth-leases.d.ts.map +1 -0
  4. package/dist/auth-leases.js +368 -0
  5. package/dist/auth-leases.js.map +1 -0
  6. package/dist/better-sqlite3.d.ts +22 -0
  7. package/dist/better-sqlite3.d.ts.map +1 -0
  8. package/dist/better-sqlite3.js +16 -0
  9. package/dist/better-sqlite3.js.map +1 -0
  10. package/dist/blobs/access.d.ts +35 -0
  11. package/dist/blobs/access.d.ts.map +1 -0
  12. package/dist/blobs/access.js +149 -0
  13. package/dist/blobs/access.js.map +1 -0
  14. package/dist/blobs/adapters/database.d.ts +26 -9
  15. package/dist/blobs/adapters/database.d.ts.map +1 -1
  16. package/dist/blobs/adapters/database.js +68 -23
  17. package/dist/blobs/adapters/database.js.map +1 -1
  18. package/dist/blobs/index.d.ts +1 -0
  19. package/dist/blobs/index.d.ts.map +1 -1
  20. package/dist/blobs/index.js +5 -4
  21. package/dist/blobs/index.js.map +1 -1
  22. package/dist/blobs/manager.d.ts +69 -44
  23. package/dist/blobs/manager.d.ts.map +1 -1
  24. package/dist/blobs/manager.js +250 -65
  25. package/dist/blobs/manager.js.map +1 -1
  26. package/dist/blobs/migrate.d.ts.map +1 -1
  27. package/dist/blobs/migrate.js +16 -8
  28. package/dist/blobs/migrate.js.map +1 -1
  29. package/dist/blobs/types.d.ts +4 -0
  30. package/dist/blobs/types.d.ts.map +1 -1
  31. package/dist/bun-sqlite.d.ts +19 -0
  32. package/dist/bun-sqlite.d.ts.map +1 -0
  33. package/dist/bun-sqlite.js +19 -0
  34. package/dist/bun-sqlite.js.map +1 -0
  35. package/dist/clients.d.ts +1 -0
  36. package/dist/clients.d.ts.map +1 -1
  37. package/dist/clients.js.map +1 -1
  38. package/dist/cloudflare/durable-object.d.ts +93 -0
  39. package/dist/cloudflare/durable-object.d.ts.map +1 -0
  40. package/dist/cloudflare/durable-object.js +210 -0
  41. package/dist/cloudflare/durable-object.js.map +1 -0
  42. package/dist/cloudflare/index.d.ts +22 -0
  43. package/dist/cloudflare/index.d.ts.map +1 -0
  44. package/dist/cloudflare/index.js +22 -0
  45. package/dist/cloudflare/index.js.map +1 -0
  46. package/dist/cloudflare/r2.d.ts +180 -0
  47. package/dist/cloudflare/r2.d.ts.map +1 -0
  48. package/dist/cloudflare/r2.js +258 -0
  49. package/dist/cloudflare/r2.js.map +1 -0
  50. package/dist/cloudflare/scope-cache.d.ts +54 -0
  51. package/dist/cloudflare/scope-cache.d.ts.map +1 -0
  52. package/dist/cloudflare/scope-cache.js +223 -0
  53. package/dist/cloudflare/scope-cache.js.map +1 -0
  54. package/dist/cloudflare/sentry.d.ts +47 -0
  55. package/dist/cloudflare/sentry.d.ts.map +1 -0
  56. package/dist/cloudflare/sentry.js +163 -0
  57. package/dist/cloudflare/sentry.js.map +1 -0
  58. package/dist/cloudflare/worker.d.ts +46 -0
  59. package/dist/cloudflare/worker.d.ts.map +1 -0
  60. package/dist/cloudflare/worker.js +63 -0
  61. package/dist/cloudflare/worker.js.map +1 -0
  62. package/dist/commit-integrity.d.ts +38 -0
  63. package/dist/commit-integrity.d.ts.map +1 -0
  64. package/dist/commit-integrity.js +260 -0
  65. package/dist/commit-integrity.js.map +1 -0
  66. package/dist/compaction.js.map +1 -1
  67. package/dist/crdt-yjs/index.d.ts +99 -0
  68. package/dist/crdt-yjs/index.d.ts.map +1 -0
  69. package/dist/crdt-yjs/index.js +629 -0
  70. package/dist/crdt-yjs/index.js.map +1 -0
  71. package/dist/d1.d.ts +13 -0
  72. package/dist/d1.d.ts.map +1 -0
  73. package/dist/d1.js +14 -0
  74. package/dist/d1.js.map +1 -0
  75. package/dist/dialect/base.d.ts +11 -1
  76. package/dist/dialect/base.d.ts.map +1 -1
  77. package/dist/dialect/base.js +43 -6
  78. package/dist/dialect/base.js.map +1 -1
  79. package/dist/dialect/helpers.d.ts +6 -0
  80. package/dist/dialect/helpers.d.ts.map +1 -1
  81. package/dist/dialect/helpers.js +24 -0
  82. package/dist/dialect/helpers.js.map +1 -1
  83. package/dist/dialect/index.js +3 -3
  84. package/dist/dialect/types.d.ts +40 -0
  85. package/dist/dialect/types.d.ts.map +1 -1
  86. package/dist/encrypted-crdt.d.ts +67 -0
  87. package/dist/encrypted-crdt.d.ts.map +1 -0
  88. package/dist/encrypted-crdt.js +426 -0
  89. package/dist/encrypted-crdt.js.map +1 -0
  90. package/dist/errors.d.ts +10 -0
  91. package/dist/errors.d.ts.map +1 -0
  92. package/dist/errors.js +13 -0
  93. package/dist/errors.js.map +1 -0
  94. package/dist/filesystem/index.d.ts +44 -0
  95. package/dist/filesystem/index.d.ts.map +1 -0
  96. package/dist/filesystem/index.js +164 -0
  97. package/dist/filesystem/index.js.map +1 -0
  98. package/dist/handlers/collection.d.ts +11 -3
  99. package/dist/handlers/collection.d.ts.map +1 -1
  100. package/dist/handlers/collection.js +34 -56
  101. package/dist/handlers/collection.js.map +1 -1
  102. package/dist/handlers/create-handler.d.ts +31 -7
  103. package/dist/handlers/create-handler.d.ts.map +1 -1
  104. package/dist/handlers/create-handler.js +332 -115
  105. package/dist/handlers/create-handler.js.map +1 -1
  106. package/dist/handlers/index.js +3 -3
  107. package/dist/handlers/types.d.ts +86 -1
  108. package/dist/handlers/types.d.ts.map +1 -1
  109. package/dist/helpers/conflict.js.map +1 -1
  110. package/dist/helpers/emitted-change.js.map +1 -1
  111. package/dist/helpers/index.d.ts +2 -0
  112. package/dist/helpers/index.d.ts.map +1 -1
  113. package/dist/helpers/index.js +6 -4
  114. package/dist/helpers/index.js.map +1 -1
  115. package/dist/helpers/paginate.js.map +1 -1
  116. package/dist/helpers/scope-authorization.d.ts +7 -0
  117. package/dist/helpers/scope-authorization.d.ts.map +1 -0
  118. package/dist/helpers/scope-authorization.js +19 -0
  119. package/dist/helpers/scope-authorization.js.map +1 -0
  120. package/dist/helpers/scope-commit-index.d.ts +12 -0
  121. package/dist/helpers/scope-commit-index.d.ts.map +1 -0
  122. package/dist/helpers/scope-commit-index.js +35 -0
  123. package/dist/helpers/scope-commit-index.js.map +1 -0
  124. package/dist/helpers/scope-strings.js.map +1 -1
  125. package/dist/hono/api-key-auth.d.ts +49 -0
  126. package/dist/hono/api-key-auth.d.ts.map +1 -0
  127. package/dist/hono/api-key-auth.js +108 -0
  128. package/dist/hono/api-key-auth.js.map +1 -0
  129. package/dist/hono/audit-redaction.d.ts +20 -0
  130. package/dist/hono/audit-redaction.d.ts.map +1 -0
  131. package/dist/hono/audit-redaction.js +85 -0
  132. package/dist/hono/audit-redaction.js.map +1 -0
  133. package/dist/hono/blobs.d.ts +75 -0
  134. package/dist/hono/blobs.d.ts.map +1 -0
  135. package/dist/hono/blobs.js +586 -0
  136. package/dist/hono/blobs.js.map +1 -0
  137. package/dist/hono/console/gateway.d.ts +42 -0
  138. package/dist/hono/console/gateway.d.ts.map +1 -0
  139. package/dist/hono/console/gateway.js +2158 -0
  140. package/dist/hono/console/gateway.js.map +1 -0
  141. package/dist/hono/console/live-auth.d.ts +7 -0
  142. package/dist/hono/console/live-auth.d.ts.map +1 -0
  143. package/dist/hono/console/live-auth.js +39 -0
  144. package/dist/hono/console/live-auth.js.map +1 -0
  145. package/dist/hono/console/route-descriptor.d.ts +6 -0
  146. package/dist/hono/console/route-descriptor.d.ts.map +1 -0
  147. package/dist/hono/console/route-descriptor.js +16 -0
  148. package/dist/hono/console/route-descriptor.js.map +1 -0
  149. package/dist/hono/console/routes/api-keys.d.ts +8 -0
  150. package/dist/hono/console/routes/api-keys.d.ts.map +1 -0
  151. package/dist/hono/console/routes/api-keys.js +575 -0
  152. package/dist/hono/console/routes/api-keys.js.map +1 -0
  153. package/dist/hono/console/routes/clients.d.ts +8 -0
  154. package/dist/hono/console/routes/clients.d.ts.map +1 -0
  155. package/dist/hono/console/routes/clients.js +322 -0
  156. package/dist/hono/console/routes/clients.js.map +1 -0
  157. package/dist/hono/console/routes/commits.d.ts +8 -0
  158. package/dist/hono/console/routes/commits.d.ts.map +1 -0
  159. package/dist/hono/console/routes/commits.js +882 -0
  160. package/dist/hono/console/routes/commits.js.map +1 -0
  161. package/dist/hono/console/routes/context.d.ts +188 -0
  162. package/dist/hono/console/routes/context.d.ts.map +1 -0
  163. package/dist/hono/console/routes/context.js +633 -0
  164. package/dist/hono/console/routes/context.js.map +1 -0
  165. package/dist/hono/console/routes/events.d.ts +8 -0
  166. package/dist/hono/console/routes/events.d.ts.map +1 -0
  167. package/dist/hono/console/routes/events.js +501 -0
  168. package/dist/hono/console/routes/events.js.map +1 -0
  169. package/dist/hono/console/routes/maintenance.d.ts +8 -0
  170. package/dist/hono/console/routes/maintenance.d.ts.map +1 -0
  171. package/dist/hono/console/routes/maintenance.js +341 -0
  172. package/dist/hono/console/routes/maintenance.js.map +1 -0
  173. package/dist/hono/console/routes/shared.d.ts +174 -0
  174. package/dist/hono/console/routes/shared.d.ts.map +1 -0
  175. package/dist/hono/console/routes/shared.js +583 -0
  176. package/dist/hono/console/routes/shared.js.map +1 -0
  177. package/dist/hono/console/routes/stats.d.ts +8 -0
  178. package/dist/hono/console/routes/stats.d.ts.map +1 -0
  179. package/dist/hono/console/routes/stats.js +295 -0
  180. package/dist/hono/console/routes/stats.js.map +1 -0
  181. package/dist/hono/console/routes/storage.d.ts +8 -0
  182. package/dist/hono/console/routes/storage.d.ts.map +1 -0
  183. package/dist/hono/console/routes/storage.js +121 -0
  184. package/dist/hono/console/routes/storage.js.map +1 -0
  185. package/dist/hono/console/routes.d.ts +36 -0
  186. package/dist/hono/console/routes.d.ts.map +1 -0
  187. package/dist/hono/console/routes.js +112 -0
  188. package/dist/hono/console/routes.js.map +1 -0
  189. package/dist/hono/console/schema-errors.d.ts +2 -0
  190. package/dist/hono/console/schema-errors.d.ts.map +1 -0
  191. package/dist/hono/console/schema-errors.js +17 -0
  192. package/dist/hono/console/schema-errors.js.map +1 -0
  193. package/dist/hono/console/schemas.d.ts +1515 -0
  194. package/dist/hono/console/schemas.d.ts.map +1 -0
  195. package/dist/hono/console/schemas.js +661 -0
  196. package/dist/hono/console/schemas.js.map +1 -0
  197. package/dist/hono/console/types.d.ts +213 -0
  198. package/dist/hono/console/types.d.ts.map +1 -0
  199. package/dist/hono/console/types.js +2 -0
  200. package/dist/hono/console/types.js.map +1 -0
  201. package/dist/hono/console/ui.d.ts +38 -0
  202. package/dist/hono/console/ui.d.ts.map +1 -0
  203. package/dist/hono/console/ui.js +43 -0
  204. package/dist/hono/console/ui.js.map +1 -0
  205. package/dist/hono/create-server.d.ts +71 -0
  206. package/dist/hono/create-server.d.ts.map +1 -0
  207. package/dist/hono/create-server.js +121 -0
  208. package/dist/hono/create-server.js.map +1 -0
  209. package/dist/hono/errors.d.ts +13 -0
  210. package/dist/hono/errors.d.ts.map +1 -0
  211. package/dist/hono/errors.js +21 -0
  212. package/dist/hono/errors.js.map +1 -0
  213. package/dist/hono/index.d.ts +20 -0
  214. package/dist/hono/index.d.ts.map +1 -0
  215. package/dist/hono/index.js +31 -0
  216. package/dist/hono/index.js.map +1 -0
  217. package/dist/hono/openapi.d.ts +72 -0
  218. package/dist/hono/openapi.d.ts.map +1 -0
  219. package/dist/hono/openapi.js +99 -0
  220. package/dist/hono/openapi.js.map +1 -0
  221. package/dist/hono/proxy/connection-manager.d.ts +78 -0
  222. package/dist/hono/proxy/connection-manager.d.ts.map +1 -0
  223. package/dist/hono/proxy/connection-manager.js +251 -0
  224. package/dist/hono/proxy/connection-manager.js.map +1 -0
  225. package/dist/hono/proxy/index.d.ts +8 -0
  226. package/dist/hono/proxy/index.d.ts.map +1 -0
  227. package/dist/hono/proxy/index.js +8 -0
  228. package/dist/hono/proxy/index.js.map +1 -0
  229. package/dist/hono/proxy/routes.d.ts +86 -0
  230. package/dist/hono/proxy/routes.d.ts.map +1 -0
  231. package/dist/hono/proxy/routes.js +183 -0
  232. package/dist/hono/proxy/routes.js.map +1 -0
  233. package/dist/hono/rate-limit.d.ts +101 -0
  234. package/dist/hono/rate-limit.d.ts.map +1 -0
  235. package/dist/hono/rate-limit.js +184 -0
  236. package/dist/hono/rate-limit.js.map +1 -0
  237. package/dist/hono/realtime-sync-packs.d.ts +43 -0
  238. package/dist/hono/realtime-sync-packs.d.ts.map +1 -0
  239. package/dist/hono/realtime-sync-packs.js +219 -0
  240. package/dist/hono/realtime-sync-packs.js.map +1 -0
  241. package/dist/hono/routes/audit.d.ts +12 -0
  242. package/dist/hono/routes/audit.d.ts.map +1 -0
  243. package/dist/hono/routes/audit.js +385 -0
  244. package/dist/hono/routes/audit.js.map +1 -0
  245. package/dist/hono/routes/auth-leases.d.ts +8 -0
  246. package/dist/hono/routes/auth-leases.d.ts.map +1 -0
  247. package/dist/hono/routes/auth-leases.js +88 -0
  248. package/dist/hono/routes/auth-leases.js.map +1 -0
  249. package/dist/hono/routes/combined.d.ts +8 -0
  250. package/dist/hono/routes/combined.d.ts.map +1 -0
  251. package/dist/hono/routes/combined.js +392 -0
  252. package/dist/hono/routes/combined.js.map +1 -0
  253. package/dist/hono/routes/context.d.ts +314 -0
  254. package/dist/hono/routes/context.d.ts.map +1 -0
  255. package/dist/hono/routes/context.js +1147 -0
  256. package/dist/hono/routes/context.js.map +1 -0
  257. package/dist/hono/routes/health.d.ts +8 -0
  258. package/dist/hono/routes/health.d.ts.map +1 -0
  259. package/dist/hono/routes/health.js +16 -0
  260. package/dist/hono/routes/health.js.map +1 -0
  261. package/dist/hono/routes/realtime.d.ts +9 -0
  262. package/dist/hono/routes/realtime.d.ts.map +1 -0
  263. package/dist/hono/routes/realtime.js +626 -0
  264. package/dist/hono/routes/realtime.js.map +1 -0
  265. package/dist/hono/routes/shared.d.ts +689 -0
  266. package/dist/hono/routes/shared.d.ts.map +1 -0
  267. package/dist/hono/routes/shared.js +972 -0
  268. package/dist/hono/routes/shared.js.map +1 -0
  269. package/dist/hono/routes/snapshots.d.ts +10 -0
  270. package/dist/hono/routes/snapshots.d.ts.map +1 -0
  271. package/dist/hono/routes/snapshots.js +281 -0
  272. package/dist/hono/routes/snapshots.js.map +1 -0
  273. package/dist/hono/routes.d.ts +19 -0
  274. package/dist/hono/routes.d.ts.map +1 -0
  275. package/dist/hono/routes.js +37 -0
  276. package/dist/hono/routes.js.map +1 -0
  277. package/dist/hono/validation.d.ts +5 -0
  278. package/dist/hono/validation.d.ts.map +1 -0
  279. package/dist/hono/validation.js +47 -0
  280. package/dist/hono/validation.js.map +1 -0
  281. package/dist/hono/websocket-origin.d.ts +9 -0
  282. package/dist/hono/websocket-origin.d.ts.map +1 -0
  283. package/dist/hono/websocket-origin.js +96 -0
  284. package/dist/hono/websocket-origin.js.map +1 -0
  285. package/dist/hono/ws.d.ts +341 -0
  286. package/dist/hono/ws.d.ts.map +1 -0
  287. package/dist/hono/ws.js +711 -0
  288. package/dist/hono/ws.js.map +1 -0
  289. package/dist/index.d.ts +6 -0
  290. package/dist/index.d.ts.map +1 -1
  291. package/dist/index.js +24 -18
  292. package/dist/index.js.map +1 -1
  293. package/dist/libsql.d.ts +29 -0
  294. package/dist/libsql.d.ts.map +1 -0
  295. package/dist/libsql.js +25 -0
  296. package/dist/libsql.js.map +1 -0
  297. package/dist/migrate.js.map +1 -1
  298. package/dist/neon.d.ts +21 -0
  299. package/dist/neon.d.ts.map +1 -0
  300. package/dist/neon.js +22 -0
  301. package/dist/neon.js.map +1 -0
  302. package/dist/notify.d.ts +30 -0
  303. package/dist/notify.d.ts.map +1 -1
  304. package/dist/notify.js +160 -41
  305. package/dist/notify.js.map +1 -1
  306. package/dist/pglite.d.ts +37 -0
  307. package/dist/pglite.d.ts.map +1 -0
  308. package/dist/pglite.js +37 -0
  309. package/dist/pglite.js.map +1 -0
  310. package/dist/plugins/index.d.ts +2 -0
  311. package/dist/plugins/index.d.ts.map +1 -0
  312. package/dist/plugins/index.js +2 -0
  313. package/dist/plugins/index.js.map +1 -0
  314. package/dist/plugins/types.d.ts +73 -0
  315. package/dist/plugins/types.d.ts.map +1 -0
  316. package/dist/plugins/types.js +30 -0
  317. package/dist/plugins/types.js.map +1 -0
  318. package/dist/postgres/index.d.ts +68 -0
  319. package/dist/postgres/index.d.ts.map +1 -0
  320. package/dist/postgres/index.js +924 -0
  321. package/dist/postgres/index.js.map +1 -0
  322. package/dist/proxy/collection.d.ts +0 -2
  323. package/dist/proxy/collection.d.ts.map +1 -1
  324. package/dist/proxy/collection.js +2 -17
  325. package/dist/proxy/collection.js.map +1 -1
  326. package/dist/proxy/handler.d.ts +1 -1
  327. package/dist/proxy/handler.d.ts.map +1 -1
  328. package/dist/proxy/handler.js +3 -4
  329. package/dist/proxy/handler.js.map +1 -1
  330. package/dist/proxy/index.d.ts +1 -1
  331. package/dist/proxy/index.d.ts.map +1 -1
  332. package/dist/proxy/index.js +3 -3
  333. package/dist/proxy/index.js.map +1 -1
  334. package/dist/proxy/mutation-detector.js.map +1 -1
  335. package/dist/proxy/oplog.d.ts.map +1 -1
  336. package/dist/proxy/oplog.js +32 -8
  337. package/dist/proxy/oplog.js.map +1 -1
  338. package/dist/prune.d.ts +8 -1
  339. package/dist/prune.d.ts.map +1 -1
  340. package/dist/prune.js +68 -28
  341. package/dist/prune.js.map +1 -1
  342. package/dist/pull.d.ts +31 -0
  343. package/dist/pull.d.ts.map +1 -1
  344. package/dist/pull.js +1014 -474
  345. package/dist/pull.js.map +1 -1
  346. package/dist/push.d.ts +36 -2
  347. package/dist/push.d.ts.map +1 -1
  348. package/dist/push.js +603 -358
  349. package/dist/push.js.map +1 -1
  350. package/dist/realtime/in-memory.js.map +1 -1
  351. package/dist/realtime/index.d.ts +2 -1
  352. package/dist/realtime/index.d.ts.map +1 -1
  353. package/dist/realtime/index.js +2 -1
  354. package/dist/realtime/index.js.map +1 -1
  355. package/dist/realtime/types.d.ts +12 -0
  356. package/dist/realtime/types.d.ts.map +1 -1
  357. package/dist/realtime/types.js +13 -1
  358. package/dist/realtime/types.js.map +1 -1
  359. package/dist/relay/client-role/forward-engine.d.ts +63 -0
  360. package/dist/relay/client-role/forward-engine.d.ts.map +1 -0
  361. package/dist/relay/client-role/forward-engine.js +267 -0
  362. package/dist/relay/client-role/forward-engine.js.map +1 -0
  363. package/dist/relay/client-role/index.d.ts +9 -0
  364. package/dist/relay/client-role/index.d.ts.map +1 -0
  365. package/dist/relay/client-role/index.js +9 -0
  366. package/dist/relay/client-role/index.js.map +1 -0
  367. package/dist/relay/client-role/pull-engine.d.ts +72 -0
  368. package/dist/relay/client-role/pull-engine.d.ts.map +1 -0
  369. package/dist/relay/client-role/pull-engine.js +249 -0
  370. package/dist/relay/client-role/pull-engine.js.map +1 -0
  371. package/dist/relay/client-role/sequence-mapper.d.ts +65 -0
  372. package/dist/relay/client-role/sequence-mapper.d.ts.map +1 -0
  373. package/dist/relay/client-role/sequence-mapper.js +161 -0
  374. package/dist/relay/client-role/sequence-mapper.js.map +1 -0
  375. package/dist/relay/evaluation/relay-paths.d.ts +41 -0
  376. package/dist/relay/evaluation/relay-paths.d.ts.map +1 -0
  377. package/dist/relay/evaluation/relay-paths.js +504 -0
  378. package/dist/relay/evaluation/relay-paths.js.map +1 -0
  379. package/dist/relay/evaluation/rust-boundary.d.ts +47 -0
  380. package/dist/relay/evaluation/rust-boundary.d.ts.map +1 -0
  381. package/dist/relay/evaluation/rust-boundary.js +220 -0
  382. package/dist/relay/evaluation/rust-boundary.js.map +1 -0
  383. package/dist/relay/index.d.ts +37 -0
  384. package/dist/relay/index.d.ts.map +1 -0
  385. package/dist/relay/index.js +44 -0
  386. package/dist/relay/index.js.map +1 -0
  387. package/dist/relay/migrate.d.ts +18 -0
  388. package/dist/relay/migrate.d.ts.map +1 -0
  389. package/dist/relay/migrate.js +99 -0
  390. package/dist/relay/migrate.js.map +1 -0
  391. package/dist/relay/mode-manager.d.ts +60 -0
  392. package/dist/relay/mode-manager.d.ts.map +1 -0
  393. package/dist/relay/mode-manager.js +114 -0
  394. package/dist/relay/mode-manager.js.map +1 -0
  395. package/dist/relay/realtime.d.ts +90 -0
  396. package/dist/relay/realtime.d.ts.map +1 -0
  397. package/dist/relay/realtime.js +147 -0
  398. package/dist/relay/realtime.js.map +1 -0
  399. package/dist/relay/relay.d.ts +190 -0
  400. package/dist/relay/relay.d.ts.map +1 -0
  401. package/dist/relay/relay.js +320 -0
  402. package/dist/relay/relay.js.map +1 -0
  403. package/dist/relay/schema.d.ts +158 -0
  404. package/dist/relay/schema.d.ts.map +1 -0
  405. package/dist/relay/schema.js +7 -0
  406. package/dist/relay/schema.js.map +1 -0
  407. package/dist/relay/server-role/index.d.ts +56 -0
  408. package/dist/relay/server-role/index.d.ts.map +1 -0
  409. package/dist/relay/server-role/index.js +193 -0
  410. package/dist/relay/server-role/index.js.map +1 -0
  411. package/dist/relay/server-role/pull.d.ts +27 -0
  412. package/dist/relay/server-role/pull.d.ts.map +1 -0
  413. package/dist/relay/server-role/pull.js +24 -0
  414. package/dist/relay/server-role/pull.js.map +1 -0
  415. package/dist/relay/server-role/push.d.ts +29 -0
  416. package/dist/relay/server-role/push.d.ts.map +1 -0
  417. package/dist/relay/server-role/push.js +122 -0
  418. package/dist/relay/server-role/push.js.map +1 -0
  419. package/dist/s3/index.d.ts +83 -0
  420. package/dist/s3/index.d.ts.map +1 -0
  421. package/dist/s3/index.js +223 -0
  422. package/dist/s3/index.js.map +1 -0
  423. package/dist/schema.d.ts +137 -1
  424. package/dist/schema.d.ts.map +1 -1
  425. package/dist/schema.js +1 -0
  426. package/dist/schema.js.map +1 -1
  427. package/dist/service-worker/index.d.ts +114 -0
  428. package/dist/service-worker/index.d.ts.map +1 -0
  429. package/dist/service-worker/index.js +487 -0
  430. package/dist/service-worker/index.js.map +1 -0
  431. package/dist/snapshot-artifacts/sqlite-bun.d.ts +15 -0
  432. package/dist/snapshot-artifacts/sqlite-bun.d.ts.map +1 -0
  433. package/dist/snapshot-artifacts/sqlite-bun.js +128 -0
  434. package/dist/snapshot-artifacts/sqlite-bun.js.map +1 -0
  435. package/dist/snapshot-artifacts.d.ts +206 -0
  436. package/dist/snapshot-artifacts.d.ts.map +1 -0
  437. package/dist/snapshot-artifacts.js +545 -0
  438. package/dist/snapshot-artifacts.js.map +1 -0
  439. package/dist/snapshot-chunks/db-metadata.d.ts +18 -0
  440. package/dist/snapshot-chunks/db-metadata.d.ts.map +1 -1
  441. package/dist/snapshot-chunks/db-metadata.js +91 -63
  442. package/dist/snapshot-chunks/db-metadata.js.map +1 -1
  443. package/dist/snapshot-chunks/index.js +2 -2
  444. package/dist/snapshot-chunks/types.d.ts +2 -0
  445. package/dist/snapshot-chunks/types.d.ts.map +1 -1
  446. package/dist/snapshot-chunks.d.ts +33 -3
  447. package/dist/snapshot-chunks.d.ts.map +1 -1
  448. package/dist/snapshot-chunks.js +136 -55
  449. package/dist/snapshot-chunks.js.map +1 -1
  450. package/dist/sqlite/index.d.ts +53 -0
  451. package/dist/sqlite/index.d.ts.map +1 -0
  452. package/dist/sqlite/index.js +795 -0
  453. package/dist/sqlite/index.js.map +1 -0
  454. package/dist/sqlite3.d.ts +22 -0
  455. package/dist/sqlite3.d.ts.map +1 -0
  456. package/dist/sqlite3.js +99 -0
  457. package/dist/sqlite3.js.map +1 -0
  458. package/dist/stats.d.ts +8 -0
  459. package/dist/stats.d.ts.map +1 -1
  460. package/dist/stats.js +45 -13
  461. package/dist/stats.js.map +1 -1
  462. package/dist/subscriptions/cache.d.ts +3 -0
  463. package/dist/subscriptions/cache.d.ts.map +1 -1
  464. package/dist/subscriptions/cache.js +44 -0
  465. package/dist/subscriptions/cache.js.map +1 -1
  466. package/dist/subscriptions/index.js +2 -2
  467. package/dist/subscriptions/resolve.d.ts +3 -1
  468. package/dist/subscriptions/resolve.d.ts.map +1 -1
  469. package/dist/subscriptions/resolve.js +91 -52
  470. package/dist/subscriptions/resolve.js.map +1 -1
  471. package/dist/sync.d.ts +3 -0
  472. package/dist/sync.d.ts.map +1 -1
  473. package/dist/sync.js +9 -5
  474. package/dist/sync.js.map +1 -1
  475. package/package.json +297 -8
  476. package/src/auth-leases.ts +649 -0
  477. package/src/better-sqlite3.ts +35 -0
  478. package/src/blobs/access.ts +244 -0
  479. package/src/blobs/adapters/database.ts +125 -43
  480. package/src/blobs/index.ts +1 -0
  481. package/src/blobs/manager.ts +366 -65
  482. package/src/blobs/migrate.ts +16 -8
  483. package/src/blobs/types.ts +4 -0
  484. package/src/bun-sqlite-ambient.d.ts +19 -0
  485. package/src/bun-sqlite.ts +27 -0
  486. package/src/clients.ts +1 -0
  487. package/src/cloudflare/durable-object.ts +289 -0
  488. package/src/cloudflare/index.ts +22 -0
  489. package/src/cloudflare/r2.ts +526 -0
  490. package/src/cloudflare/scope-cache.ts +341 -0
  491. package/src/cloudflare/sentry.ts +230 -0
  492. package/src/cloudflare/worker.ts +77 -0
  493. package/src/commit-integrity.ts +371 -0
  494. package/src/crdt-yjs/index.ts +931 -0
  495. package/src/d1.ts +16 -0
  496. package/src/dialect/base.ts +71 -5
  497. package/src/dialect/helpers.ts +31 -0
  498. package/src/dialect/types.ts +47 -0
  499. package/src/encrypted-crdt.ts +786 -0
  500. package/src/errors.ts +22 -0
  501. package/src/filesystem/index.ts +262 -0
  502. package/src/handlers/collection.ts +78 -78
  503. package/src/handlers/create-handler.ts +540 -147
  504. package/src/handlers/types.ts +116 -0
  505. package/src/helpers/index.ts +2 -0
  506. package/src/helpers/scope-authorization.ts +27 -0
  507. package/src/helpers/scope-commit-index.ts +52 -0
  508. package/src/hono/api-key-auth.ts +177 -0
  509. package/src/hono/audit-redaction.ts +135 -0
  510. package/src/hono/blobs.ts +851 -0
  511. package/src/hono/console/gateway.ts +3046 -0
  512. package/src/hono/console/live-auth.ts +46 -0
  513. package/src/hono/console/route-descriptor.ts +22 -0
  514. package/src/hono/console/routes/api-keys.ts +721 -0
  515. package/src/hono/console/routes/clients.ts +447 -0
  516. package/src/hono/console/routes/commits.ts +1137 -0
  517. package/src/hono/console/routes/context.ts +956 -0
  518. package/src/hono/console/routes/events.ts +669 -0
  519. package/src/hono/console/routes/maintenance.ts +461 -0
  520. package/src/hono/console/routes/shared.ts +816 -0
  521. package/src/hono/console/routes/stats.ts +392 -0
  522. package/src/hono/console/routes/storage.ts +159 -0
  523. package/src/hono/console/routes.ts +146 -0
  524. package/src/hono/console/schema-errors.ts +23 -0
  525. package/src/hono/console/schemas.ts +914 -0
  526. package/src/hono/console/types.ts +223 -0
  527. package/src/hono/console/ui.ts +100 -0
  528. package/src/hono/create-server.ts +230 -0
  529. package/src/hono/errors.ts +50 -0
  530. package/src/hono/index.ts +54 -0
  531. package/src/hono/openapi.ts +139 -0
  532. package/src/hono/proxy/connection-manager.ts +340 -0
  533. package/src/hono/proxy/index.ts +8 -0
  534. package/src/hono/proxy/routes.ts +272 -0
  535. package/src/hono/rate-limit.ts +319 -0
  536. package/src/hono/realtime-sync-packs.ts +354 -0
  537. package/src/hono/routes/audit.ts +499 -0
  538. package/src/hono/routes/auth-leases.ts +119 -0
  539. package/src/hono/routes/combined.ts +583 -0
  540. package/src/hono/routes/context.ts +1629 -0
  541. package/src/hono/routes/health.ts +26 -0
  542. package/src/hono/routes/realtime.ts +808 -0
  543. package/src/hono/routes/shared.ts +1626 -0
  544. package/src/hono/routes/snapshots.ts +345 -0
  545. package/src/hono/routes.ts +68 -0
  546. package/src/hono/validation.ts +81 -0
  547. package/src/hono/websocket-origin.ts +131 -0
  548. package/src/hono/ws.ts +1134 -0
  549. package/src/index.ts +6 -0
  550. package/src/libsql.ts +51 -0
  551. package/src/neon.ts +28 -0
  552. package/src/notify.ts +224 -44
  553. package/src/pglite.ts +68 -0
  554. package/src/plugins/index.ts +1 -0
  555. package/src/plugins/types.ts +144 -0
  556. package/src/postgres/index.ts +1291 -0
  557. package/src/proxy/collection.ts +5 -27
  558. package/src/proxy/handler.ts +2 -2
  559. package/src/proxy/index.ts +0 -2
  560. package/src/proxy/oplog.ts +41 -10
  561. package/src/prune.ts +137 -36
  562. package/src/pull.ts +1504 -591
  563. package/src/push.ts +881 -443
  564. package/src/realtime/index.ts +2 -0
  565. package/src/realtime/types.ts +35 -0
  566. package/src/relay/bun-types.d.ts +50 -0
  567. package/src/relay/client-role/forward-engine.ts +355 -0
  568. package/src/relay/client-role/index.ts +9 -0
  569. package/src/relay/client-role/pull-engine.ts +329 -0
  570. package/src/relay/client-role/sequence-mapper.ts +201 -0
  571. package/src/relay/evaluation/relay-paths.ts +699 -0
  572. package/src/relay/evaluation/rust-boundary.ts +464 -0
  573. package/src/relay/index.ts +50 -0
  574. package/src/relay/migrate.ts +113 -0
  575. package/src/relay/mode-manager.ts +142 -0
  576. package/src/relay/realtime.ts +207 -0
  577. package/src/relay/relay.ts +431 -0
  578. package/src/relay/schema.ts +171 -0
  579. package/src/relay/server-role/index.ts +338 -0
  580. package/src/relay/server-role/pull.ts +43 -0
  581. package/src/relay/server-role/push.ts +164 -0
  582. package/src/s3/index.ts +346 -0
  583. package/src/schema.ts +141 -1
  584. package/src/service-worker/index.ts +773 -0
  585. package/src/snapshot-artifacts/sqlite-bun.ts +168 -0
  586. package/src/snapshot-artifacts.ts +896 -0
  587. package/src/snapshot-chunks/db-metadata.ts +131 -72
  588. package/src/snapshot-chunks/types.ts +2 -0
  589. package/src/snapshot-chunks.ts +194 -70
  590. package/src/sqlite/index.ts +1064 -0
  591. package/src/sqlite3.ts +137 -0
  592. package/src/stats.ts +76 -13
  593. package/src/subscriptions/cache.ts +58 -0
  594. package/src/subscriptions/resolve.ts +99 -58
  595. package/src/sync.ts +16 -6
  596. package/src/blobs/adapters/database.test.ts +0 -67
  597. package/src/notify.test.ts +0 -520
  598. package/src/proxy/handler.test.ts +0 -126
  599. package/src/proxy/mutation-detector.test.ts +0 -71
  600. package/src/snapshot-chunks/db-metadata.test.ts +0 -172
  601. package/src/subscriptions/resolve.test.ts +0 -180
@@ -3,7 +3,8 @@
3
3
  */
4
4
 
5
5
  import type {
6
- ScopePattern,
6
+ BinarySnapshotColumn,
7
+ BinarySnapshotRowsEncoder,
7
8
  ScopeValues,
8
9
  ScopeValuesFromPatterns,
9
10
  ScopeDefinition as SimpleScopeDefinition,
@@ -15,8 +16,9 @@ import {
15
16
  applyCodecsToDbRow,
16
17
  type ColumnCodecDialect,
17
18
  type ColumnCodecSource,
18
- extractScopeVars,
19
- normalizeScopes,
19
+ createSingleVariableScopeMetadata,
20
+ createTableColumnCodecsResolver,
21
+ type SyncularErrorCode,
20
22
  toTableColumnCodecs,
21
23
  } from '@syncular/core';
22
24
  import type {
@@ -32,9 +34,12 @@ import type {
32
34
  UpdateResult,
33
35
  } from 'kysely';
34
36
  import { sql } from 'kysely';
37
+ import { coerceNumber } from '../dialect/helpers';
38
+ import { rowScopesAllowed } from '../helpers/scope-authorization';
35
39
  import type { SyncCoreDb } from '../schema';
36
40
  import type {
37
41
  ApplyOperationResult,
42
+ BatchApplyOperationInput,
38
43
  EmittedChange,
39
44
  ServerApplyOperationContext,
40
45
  ServerContext,
@@ -48,14 +53,10 @@ import type {
48
53
  */
49
54
  type AuthorizeResult =
50
55
  | true
51
- | { error: string; code: string; retriable?: boolean };
56
+ | { error: string; code: SyncularErrorCode; retriable?: boolean };
52
57
 
53
- function classifyConstraintViolationCode(message: string): string {
54
- const normalized = message.toLowerCase();
55
- if (normalized.includes('not null')) return 'NOT_NULL_CONSTRAINT';
56
- if (normalized.includes('unique')) return 'UNIQUE_CONSTRAINT';
57
- if (normalized.includes('foreign key')) return 'FOREIGN_KEY_CONSTRAINT';
58
- return 'CONSTRAINT_VIOLATION';
58
+ function classifyConstraintViolationCode(_message: string): SyncularErrorCode {
59
+ return 'sync.constraint_violation';
59
60
  }
60
61
 
61
62
  function isConstraintViolationError(message: string): boolean {
@@ -76,10 +77,36 @@ function isMissingColumnReferenceError(message: string): boolean {
76
77
  );
77
78
  }
78
79
 
79
- /**
80
- * Scope definition for a column - maps scope variable to column name.
81
- */
82
- export type ScopeColumnMap = Record<string, string>;
80
+ function readSafeVersionColumn(
81
+ row: Record<string, unknown>,
82
+ versionColumn: string,
83
+ defaultValue: number
84
+ ): number {
85
+ const value = row[versionColumn];
86
+ if (value === null || value === undefined) return defaultValue;
87
+ const version = coerceNumber(value);
88
+ if (version === null || !Number.isSafeInteger(version)) {
89
+ throw new Error(`Version column "${versionColumn}" must be a safe integer`);
90
+ }
91
+ return version;
92
+ }
93
+
94
+ function normalizeOutboundVersionColumn<Row>(
95
+ row: Row,
96
+ versionColumn: string,
97
+ version: number
98
+ ): Row {
99
+ if (row === null || typeof row !== 'object' || Array.isArray(row)) {
100
+ return row;
101
+ }
102
+ if (!Object.hasOwn(row, versionColumn)) {
103
+ return row;
104
+ }
105
+ return {
106
+ ...(row as Record<string, unknown>),
107
+ [versionColumn]: version,
108
+ } as Row;
109
+ }
83
110
 
84
111
  /**
85
112
  * Options for creating a declarative server handler.
@@ -124,6 +151,37 @@ export interface CreateServerHandlerOptions<
124
151
  /** TTL for cached snapshot chunks in ms */
125
152
  snapshotChunkTtlMs?: number;
126
153
 
154
+ /**
155
+ * Stable binary snapshot column metadata used by binary bootstrap chunks.
156
+ */
157
+ snapshotBinaryColumns?: readonly BinarySnapshotColumn[];
158
+
159
+ /**
160
+ * Version-aware binary snapshot column metadata. Returning null intentionally
161
+ * disables fallback to current metadata.
162
+ */
163
+ snapshotBinaryColumnsForVersion?: (
164
+ schemaVersion: number
165
+ ) => readonly BinarySnapshotColumn[] | null | undefined;
166
+
167
+ /**
168
+ * Optional generated binary snapshot encoder used by binary bootstrap chunks.
169
+ */
170
+ snapshotBinaryEncoder?: BinarySnapshotRowsEncoder<
171
+ Selectable<ClientDB[TableName]>
172
+ >;
173
+
174
+ /**
175
+ * Version-aware generated binary snapshot encoder. Returning null
176
+ * intentionally disables fallback to the current encoder.
177
+ */
178
+ snapshotBinaryEncoderForVersion?: (
179
+ schemaVersion: number
180
+ ) =>
181
+ | BinarySnapshotRowsEncoder<Selectable<ClientDB[TableName]>>
182
+ | null
183
+ | undefined;
184
+
127
185
  /**
128
186
  * Resolve allowed scope values for the current actor.
129
187
  * Called per request to determine what the actor can access.
@@ -187,6 +245,17 @@ export interface CreateServerHandlerOptions<
187
245
  */
188
246
  applyOperation?: ServerTableHandler<ServerDB, Auth>['applyOperation'];
189
247
 
248
+ /**
249
+ * Hint for savepoint optimization on single-op commits.
250
+ *
251
+ * `true` means a rejected single operation never leaves durable writes
252
+ * before returning the rejection result.
253
+ *
254
+ * Defaults to `true` for the built-in applyOperation implementation and
255
+ * `false` when a custom applyOperation is provided.
256
+ */
257
+ canRejectSingleOperationWithoutSavepoint?: boolean;
258
+
190
259
  /**
191
260
  * Custom scope extraction from row (for complex scope logic).
192
261
  */
@@ -254,6 +323,10 @@ export function createServerHandler<
254
323
  versionColumn = 'server_version',
255
324
  dependsOn,
256
325
  snapshotChunkTtlMs,
326
+ snapshotBinaryColumns,
327
+ snapshotBinaryColumnsForVersion,
328
+ snapshotBinaryEncoder,
329
+ snapshotBinaryEncoderForVersion,
257
330
  resolveScopes,
258
331
  transformInbound,
259
332
  transformOutbound,
@@ -262,42 +335,19 @@ export function createServerHandler<
262
335
  authorize,
263
336
  extractScopes: customExtractScopes,
264
337
  } = options;
265
- const codecCache = new Map<string, ReturnType<typeof toTableColumnCodecs>>();
266
- const resolveTableCodecs = (row: Record<string, unknown>) => {
267
- if (!codecs) return {};
268
- const columns = Object.keys(row);
269
- if (columns.length === 0) return {};
270
- const cacheKey = columns.slice().sort().join('\u0000');
271
- const cached = codecCache.get(cacheKey);
272
- if (cached) return cached;
273
- const resolved = toTableColumnCodecs(table, codecs, columns, {
274
- dialect: codecDialect,
275
- });
276
- codecCache.set(cacheKey, resolved);
277
- return resolved;
278
- };
279
-
280
- // Normalize scopes to pattern map and extract patterns/columns
281
- const scopeColumnMap = normalizeScopes(scopeDefs);
282
- const scopePatterns = Object.keys(scopeColumnMap) as ScopePattern[];
283
- const scopeColumns: ScopeColumnMap = {};
284
-
285
- for (const [pattern, columnName] of Object.entries(scopeColumnMap)) {
286
- const vars = extractScopeVars(pattern);
287
- if (vars.length !== 1) {
288
- throw new Error(
289
- `Scope pattern "${pattern}" must contain exactly one placeholder (got ${vars.length}).`
290
- );
291
- }
292
- const varName = vars[0]!;
293
- const existing = scopeColumns[varName];
294
- if (existing && existing !== columnName) {
295
- throw new Error(
296
- `Scope variable "${varName}" is mapped to multiple columns: "${existing}" and "${columnName}".`
297
- );
298
- }
299
- scopeColumns[varName] = columnName;
300
- }
338
+ const resolveRowCodecs = createTableColumnCodecsResolver(codecs, {
339
+ dialect: codecDialect,
340
+ });
341
+ const primaryKeyColumn = primaryKey as keyof ServerDB[TableName] & string;
342
+ const qualifiedVersionRef = `${table}.${versionColumn}`;
343
+ const resolveTableCodecs = (row: Record<string, unknown>) =>
344
+ resolveRowCodecs(table, row);
345
+ const usePassthroughInbound = !transformInbound && codecs == null;
346
+
347
+ const { scopePatterns, scopeColumnsByVariable: scopeColumns } =
348
+ createSingleVariableScopeMetadata(scopeDefs);
349
+ const scopeColumnEntries = Object.entries(scopeColumns);
350
+ const requiredScopeKeys = Object.keys(scopeColumns);
301
351
 
302
352
  // Default extractScopes from scope columns
303
353
  const defaultExtractScopes = (row: Record<string, unknown>): StoredScopes => {
@@ -321,12 +371,101 @@ export function createServerHandler<
321
371
  const resolved = await resolveScopes(ctx);
322
372
  const normalized: ScopeValues = {};
323
373
  for (const [scopeKey, scopeValue] of Object.entries(resolved)) {
324
- if (typeof scopeValue === 'string' || Array.isArray(scopeValue)) {
374
+ // null/undefined means "no access for this scope" and is skipped.
375
+ if (scopeValue === null || scopeValue === undefined) continue;
376
+ if (typeof scopeValue === 'string') {
377
+ normalized[scopeKey] = scopeValue;
378
+ continue;
379
+ }
380
+ if (Array.isArray(scopeValue)) {
381
+ const invalidIndex = scopeValue.findIndex(
382
+ (entry) => typeof entry !== 'string'
383
+ );
384
+ if (invalidIndex !== -1) {
385
+ throw new Error(
386
+ `resolveScopes() for table "${table}" returned a non-string entry ` +
387
+ `(${typeof scopeValue[invalidIndex]}) at index ${invalidIndex} of scope "${scopeKey}". ` +
388
+ 'Scope values must be strings or string arrays.'
389
+ );
390
+ }
325
391
  normalized[scopeKey] = scopeValue;
392
+ continue;
326
393
  }
394
+ throw new Error(
395
+ `resolveScopes() for table "${table}" returned an invalid value ` +
396
+ `(${typeof scopeValue}) for scope "${scopeKey}". ` +
397
+ 'Scope values must be strings or string arrays.'
398
+ );
327
399
  }
328
400
  return normalized;
329
401
  };
402
+ const writeScopeCache = new WeakMap<
403
+ ServerApplyOperationContext<ServerDB, Auth>,
404
+ Promise<ScopeValues>
405
+ >();
406
+
407
+ const resolveWriteScopes = (
408
+ ctx: ServerApplyOperationContext<ServerDB, Auth>
409
+ ): Promise<ScopeValues> => {
410
+ const cached = writeScopeCache.get(ctx);
411
+ if (cached) return cached;
412
+ const loaded = resolveScopesImpl(ctx);
413
+ writeScopeCache.set(ctx, loaded);
414
+ return loaded;
415
+ };
416
+
417
+ const authorizeRowScopes = async (
418
+ ctx: ServerApplyOperationContext<ServerDB, Auth>,
419
+ row: Record<string, unknown>
420
+ ): Promise<AuthorizeResult> => {
421
+ if (requiredScopeKeys.length === 0) return true;
422
+
423
+ let allowedScopes: ScopeValues;
424
+ try {
425
+ allowedScopes = await resolveWriteScopes(ctx);
426
+ } catch (resolveErr) {
427
+ console.error(
428
+ `[resolveScopes] Failed for table ${table} during write authorization:`,
429
+ resolveErr
430
+ );
431
+ return {
432
+ error: 'Forbidden',
433
+ code: 'sync.forbidden',
434
+ retriable: false,
435
+ };
436
+ }
437
+
438
+ const rowScopes = extractScopesImpl(row);
439
+ if (
440
+ rowScopesAllowed({
441
+ rowScopes,
442
+ allowedScopes,
443
+ requiredScopeKeys,
444
+ })
445
+ ) {
446
+ return true;
447
+ }
448
+
449
+ return {
450
+ error: 'Forbidden',
451
+ code: 'sync.forbidden',
452
+ retriable: false,
453
+ };
454
+ };
455
+
456
+ const rejectionResult = (
457
+ opIndex: number,
458
+ rejection: Exclude<AuthorizeResult, true>
459
+ ): ApplyOperationResult => ({
460
+ result: {
461
+ opIndex,
462
+ status: 'error',
463
+ error: rejection.error,
464
+ code: rejection.code,
465
+ retriable: rejection.retriable ?? false,
466
+ },
467
+ emittedChanges: [],
468
+ });
330
469
 
331
470
  const applyOutboundTransform = (
332
471
  row: Selectable<ServerDB[TableName]>
@@ -348,6 +487,10 @@ export function createServerHandler<
348
487
  row: Record<string, unknown>,
349
488
  schemaVersion: number | undefined
350
489
  ): Updateable<ServerDB[TableName]> => {
490
+ if (usePassthroughInbound) {
491
+ return row as Updateable<ServerDB[TableName]>;
492
+ }
493
+
351
494
  if (transformInbound) {
352
495
  return transformInbound(row as Selectable<ClientDB[TableName]>, {
353
496
  schemaVersion,
@@ -371,29 +514,29 @@ export function createServerHandler<
371
514
  const { ref } = trx.dynamic;
372
515
  const scopeValues = ctx.scopeValues;
373
516
 
374
- const pageSize = Math.max(1, Math.min(10_000, ctx.limit));
517
+ const pageSize = Math.max(1, ctx.limit);
375
518
 
376
- // Build dynamic WHERE conditions
377
- const whereConditions: Array<{ column: string; values: string[] }> = [];
378
- for (const [varName, columnName] of Object.entries(scopeColumns)) {
379
- const values = scopeValues[varName];
380
- if (values === undefined) continue;
381
- const normalized = Array.isArray(values) ? values : [values];
382
- if (normalized.length === 0) continue;
383
- whereConditions.push({ column: columnName, values: normalized });
384
- }
519
+ let q = trx.selectFrom(table) as SelectQueryBuilder<
520
+ ServerDB,
521
+ keyof ServerDB & string,
522
+ Record<string, unknown>
523
+ >;
385
524
 
386
- let q = trx.selectFrom(table).selectAll() as SelectQueryBuilder<
525
+ q = q.selectAll() as SelectQueryBuilder<
387
526
  ServerDB,
388
527
  keyof ServerDB & string,
389
528
  Record<string, unknown>
390
529
  >;
391
530
 
392
- for (const cond of whereConditions) {
393
- if (cond.values.length === 1) {
394
- q = q.where(ref<string>(cond.column), '=', cond.values[0]);
531
+ for (const [varName, columnName] of scopeColumnEntries) {
532
+ const values = scopeValues[varName];
533
+ if (values === undefined) continue;
534
+ const normalized = Array.isArray(values) ? values : [values];
535
+ if (normalized.length === 0) continue;
536
+ if (normalized.length === 1) {
537
+ q = q.where(ref<string>(columnName), '=', normalized[0]);
395
538
  } else {
396
- q = q.where(ref<string>(cond.column), 'in', cond.values);
539
+ q = q.where(ref<string>(columnName), 'in', normalized);
397
540
  }
398
541
  }
399
542
 
@@ -417,10 +560,30 @@ export function createServerHandler<
417
560
  | undefined)
418
561
  : null;
419
562
 
420
- // Transform outbound if provided
421
- const outputRows = pageRows.map((r) =>
422
- applyOutboundTransform(r as Selectable<ServerDB[TableName]>)
423
- );
563
+ let outputRows: unknown[];
564
+ if (transformOutbound) {
565
+ outputRows = pageRows.map((r) =>
566
+ applyOutboundTransform(r as Selectable<ServerDB[TableName]>)
567
+ );
568
+ } else {
569
+ const firstRow = pageRows[0] as Record<string, unknown> | undefined;
570
+ const tableCodecs = firstRow
571
+ ? toTableColumnCodecs(table, codecs, Object.keys(firstRow), {
572
+ dialect: codecDialect,
573
+ })
574
+ : {};
575
+ if (Object.keys(tableCodecs).length === 0) {
576
+ outputRows = pageRows;
577
+ } else {
578
+ outputRows = pageRows.map((r) =>
579
+ applyCodecsFromDbRow(
580
+ r as Record<string, unknown>,
581
+ tableCodecs,
582
+ codecDialect
583
+ )
584
+ );
585
+ }
586
+ }
424
587
 
425
588
  return {
426
589
  rows: outputRows,
@@ -445,8 +608,8 @@ export function createServerHandler<
445
608
  result: {
446
609
  opIndex,
447
610
  status: 'error',
448
- error: `UNKNOWN_TABLE:${op.table}`,
449
- code: 'UNKNOWN_TABLE',
611
+ error: `Unknown table: ${op.table}`,
612
+ code: 'sync.unknown_table',
450
613
  retriable: false,
451
614
  },
452
615
  emittedChanges: [],
@@ -472,6 +635,25 @@ export function createServerHandler<
472
635
 
473
636
  // Handle delete
474
637
  if (op.op === 'delete') {
638
+ const existingRow = (await (
639
+ trx.selectFrom(table).selectAll() as SelectQueryBuilder<
640
+ ServerDB,
641
+ keyof ServerDB & string,
642
+ Record<string, unknown>
643
+ >
644
+ )
645
+ .where(ref<string>(primaryKey), '=', op.row_id)
646
+ .executeTakeFirst()) as Record<string, unknown> | undefined;
647
+
648
+ if (!existingRow) {
649
+ return { result: { opIndex, status: 'applied' }, emittedChanges: [] };
650
+ }
651
+
652
+ const scopeAuth = await authorizeRowScopes(ctx, existingRow);
653
+ if (scopeAuth !== true) {
654
+ return rejectionResult(opIndex, scopeAuth);
655
+ }
656
+
475
657
  const deleted = await (
476
658
  trx.deleteFrom(table) as DeleteQueryBuilder<
477
659
  ServerDB,
@@ -484,9 +666,8 @@ export function createServerHandler<
484
666
  .executeTakeFirst();
485
667
 
486
668
  const deletedRow = deleted as Record<string, unknown> | undefined;
487
- if (!deletedRow) {
669
+ if (!deletedRow)
488
670
  return { result: { opIndex, status: 'applied' }, emittedChanges: [] };
489
- }
490
671
 
491
672
  // Extract scopes from existing row for the delete emission
492
673
  const scopes = extractScopesImpl(deletedRow);
@@ -513,6 +694,29 @@ export function createServerHandler<
513
694
  ? (rawPayload as Record<string, unknown>)
514
695
  : {};
515
696
  const payload = applyInboundTransform(payloadRecord, ctx.schemaVersion);
697
+ const rowForInsertScopeCheck: Record<string, unknown> = {
698
+ ...payload,
699
+ [primaryKey]: op.row_id,
700
+ [versionColumn]: 1,
701
+ };
702
+
703
+ const existingRowBeforeWrite = (await (
704
+ trx.selectFrom(table).selectAll() as SelectQueryBuilder<
705
+ ServerDB,
706
+ keyof ServerDB & string,
707
+ Record<string, unknown>
708
+ >
709
+ )
710
+ .where(ref<string>(primaryKey), '=', op.row_id)
711
+ .executeTakeFirst()) as Record<string, unknown> | undefined;
712
+
713
+ const rowScopeAuth = await authorizeRowScopes(
714
+ ctx,
715
+ existingRowBeforeWrite ?? rowForInsertScopeCheck
716
+ );
717
+ if (rowScopeAuth !== true) {
718
+ return rejectionResult(opIndex, rowScopeAuth);
719
+ }
516
720
 
517
721
  let updated: Record<string, unknown> | undefined;
518
722
  let constraintError: { message: string; code: string } | null = null;
@@ -544,7 +748,7 @@ export function createServerHandler<
544
748
  .executeTakeFirst()) as Record<string, unknown> | undefined;
545
749
 
546
750
  if (!updated) {
547
- const conflictRow = await (
751
+ let conflictRow = await (
548
752
  trx.selectFrom(table).selectAll() as SelectQueryBuilder<
549
753
  ServerDB,
550
754
  keyof ServerDB & string,
@@ -554,100 +758,118 @@ export function createServerHandler<
554
758
  .where(ref<string>(primaryKey), '=', op.row_id)
555
759
  .executeTakeFirst();
556
760
 
557
- if (!conflictRow) {
761
+ if (!conflictRow && expectedVersion === 0) {
762
+ const insertValues: Record<string, unknown> = {
763
+ ...payload,
764
+ [primaryKey]: op.row_id,
765
+ [versionColumn]: 1,
766
+ };
767
+
768
+ try {
769
+ updated = (await (
770
+ trx.insertInto(table) as InsertQueryBuilder<
771
+ ServerDB,
772
+ TableName,
773
+ InsertResult
774
+ >
775
+ )
776
+ .values(insertValues as Insertable<ServerDB[TableName]>)
777
+ .returningAll()
778
+ .executeTakeFirst()) as Record<string, unknown> | undefined;
779
+ } catch (err) {
780
+ const message = err instanceof Error ? err.message : String(err);
781
+ if (!isConstraintViolationError(message)) {
782
+ throw err;
783
+ }
784
+ conflictRow = await (
785
+ trx.selectFrom(table).selectAll() as SelectQueryBuilder<
786
+ ServerDB,
787
+ keyof ServerDB & string,
788
+ Record<string, unknown>
789
+ >
790
+ )
791
+ .where(ref<string>(primaryKey), '=', op.row_id)
792
+ .executeTakeFirst();
793
+ }
794
+ }
795
+
796
+ if (!updated && !conflictRow) {
558
797
  return {
559
798
  result: {
560
799
  opIndex,
561
800
  status: 'error',
562
- error: 'ROW_NOT_FOUND_FOR_BASE_VERSION',
563
- code: 'ROW_MISSING',
801
+ error: 'Row not found for base version',
802
+ code: 'sync.row_missing',
564
803
  retriable: false,
565
804
  },
566
805
  emittedChanges: [],
567
806
  };
568
807
  }
569
808
 
570
- const existingVersion =
571
- (conflictRow[versionColumn] as number | undefined) ?? 0;
572
- return {
573
- result: {
574
- opIndex,
575
- status: 'conflict',
576
- message: `Version conflict: server=${existingVersion}, base=${expectedVersion}`,
577
- server_version: existingVersion,
578
- server_row: applyOutboundTransform(
579
- conflictRow as Selectable<ServerDB[TableName]>
580
- ),
581
- },
582
- emittedChanges: [],
583
- };
809
+ if (!updated && conflictRow) {
810
+ const conflictScopeAuth = await authorizeRowScopes(
811
+ ctx,
812
+ conflictRow
813
+ );
814
+ if (conflictScopeAuth !== true) {
815
+ return rejectionResult(opIndex, conflictScopeAuth);
816
+ }
817
+
818
+ const existingVersion = readSafeVersionColumn(
819
+ conflictRow,
820
+ versionColumn,
821
+ 0
822
+ );
823
+ return {
824
+ result: {
825
+ opIndex,
826
+ status: 'conflict',
827
+ message: `Version conflict: server=${existingVersion}, base=${expectedVersion}`,
828
+ code: 'sync.version_conflict',
829
+ server_version: existingVersion,
830
+ server_row: normalizeOutboundVersionColumn(
831
+ applyOutboundTransform(
832
+ conflictRow as Selectable<ServerDB[TableName]>
833
+ ),
834
+ versionColumn,
835
+ existingVersion
836
+ ),
837
+ },
838
+ emittedChanges: [],
839
+ };
840
+ }
584
841
  }
585
842
  } else {
586
843
  const updateSet: Record<string, unknown> = {
587
844
  ...payload,
588
- [versionColumn]: sql`${sql.ref(versionColumn)} + 1`,
845
+ [versionColumn]: sql`${sql.ref(qualifiedVersionRef)} + 1`,
589
846
  };
590
847
  delete updateSet[primaryKey];
591
848
  for (const col of Object.values(scopeColumns)) {
592
849
  delete updateSet[col];
593
850
  }
594
851
 
852
+ const insertValues: Record<string, unknown> = {
853
+ ...payload,
854
+ [primaryKey]: op.row_id,
855
+ [versionColumn]: 1,
856
+ };
857
+
595
858
  updated = (await (
596
- trx.updateTable(table) as UpdateQueryBuilder<
859
+ trx.insertInto(table) as InsertQueryBuilder<
597
860
  ServerDB,
598
861
  TableName,
599
- TableName,
600
- UpdateResult
862
+ InsertResult
601
863
  >
602
864
  )
603
- .set(updateSet as UpdateSetObject)
604
- .where(ref<string>(primaryKey), '=', op.row_id)
865
+ .values(insertValues as Insertable<ServerDB[TableName]>)
866
+ .onConflict((oc) =>
867
+ oc
868
+ .column(primaryKeyColumn)
869
+ .doUpdateSet(updateSet as UpdateSetObject)
870
+ )
605
871
  .returningAll()
606
872
  .executeTakeFirst()) as Record<string, unknown> | undefined;
607
-
608
- if (!updated) {
609
- const insertValues: Record<string, unknown> = {
610
- ...payload,
611
- [primaryKey]: op.row_id,
612
- [versionColumn]: 1,
613
- };
614
-
615
- try {
616
- updated = (await (
617
- trx.insertInto(table) as InsertQueryBuilder<
618
- ServerDB,
619
- TableName,
620
- InsertResult
621
- >
622
- )
623
- .values(insertValues as Insertable<ServerDB[TableName]>)
624
- .returningAll()
625
- .executeTakeFirst()) as Record<string, unknown> | undefined;
626
- } catch (err) {
627
- const message = err instanceof Error ? err.message : String(err);
628
- if (!isConstraintViolationError(message)) {
629
- throw err;
630
- }
631
- updated = (await (
632
- trx.updateTable(table) as UpdateQueryBuilder<
633
- ServerDB,
634
- TableName,
635
- TableName,
636
- UpdateResult
637
- >
638
- )
639
- .set(updateSet as UpdateSetObject)
640
- .where(ref<string>(primaryKey), '=', op.row_id)
641
- .returningAll()
642
- .executeTakeFirst()) as Record<string, unknown> | undefined;
643
- if (!updated) {
644
- constraintError = {
645
- message,
646
- code: classifyConstraintViolationCode(message),
647
- };
648
- }
649
- }
650
- }
651
873
  }
652
874
  } catch (err) {
653
875
  const message = err instanceof Error ? err.message : String(err);
@@ -666,8 +888,8 @@ export function createServerHandler<
666
888
  result: {
667
889
  opIndex,
668
890
  status: 'error',
669
- error: 'ROW_NOT_FOUND_FOR_BASE_VERSION',
670
- code: 'ROW_MISSING',
891
+ error: 'Row not found for base version',
892
+ code: 'sync.row_missing',
671
893
  retriable: false,
672
894
  },
673
895
  emittedChanges: [],
@@ -703,14 +925,16 @@ export function createServerHandler<
703
925
  }
704
926
 
705
927
  const updatedRow = updated;
706
- const rowVersion = (updatedRow[versionColumn] as number) ?? 1;
928
+ const rowVersion = readSafeVersionColumn(updatedRow, versionColumn, 1);
707
929
 
708
930
  // Extract scopes from updated row
709
931
  const scopes = extractScopesImpl(updatedRow);
710
932
 
711
933
  // Transform outbound for emitted change
712
- const rowJson = applyOutboundTransform(
713
- updated as Selectable<ServerDB[TableName]>
934
+ const rowJson = normalizeOutboundVersionColumn(
935
+ applyOutboundTransform(updated as Selectable<ServerDB[TableName]>),
936
+ versionColumn,
937
+ rowVersion
714
938
  );
715
939
 
716
940
  const emitted: EmittedChange = {
@@ -728,14 +952,183 @@ export function createServerHandler<
728
952
  };
729
953
  };
730
954
 
955
+ const defaultApplyOperationBatch = async (
956
+ ctx: ServerApplyOperationContext<ServerDB, Auth>,
957
+ operations: BatchApplyOperationInput[]
958
+ ): Promise<ApplyOperationResult[]> => {
959
+ if (operations.length === 0) return [];
960
+
961
+ const runSequentialFallback = async (): Promise<ApplyOperationResult[]> => {
962
+ const sequential: ApplyOperationResult[] = [];
963
+ for (const entry of operations) {
964
+ const applied = await defaultApplyOperation(
965
+ ctx,
966
+ entry.op,
967
+ entry.opIndex
968
+ );
969
+ sequential.push(applied);
970
+ if (applied.result.status !== 'applied') {
971
+ break;
972
+ }
973
+ }
974
+ return sequential;
975
+ };
976
+
977
+ if (operations.length === 1 || authorize || requiredScopeKeys.length > 0) {
978
+ return runSequentialFallback();
979
+ }
980
+
981
+ const trx = ctx.trx;
982
+ const prepared: Array<{
983
+ entry: BatchApplyOperationInput;
984
+ payload: Record<string, unknown>;
985
+ insertValues: Record<string, unknown>;
986
+ }> = [];
987
+ const seenRowIds = new Set<string>();
988
+ const payloadKeySignatures = new Set<string>();
989
+
990
+ for (const entry of operations) {
991
+ const op = entry.op;
992
+ if (op.table !== table || op.op !== 'upsert' || op.base_version != null) {
993
+ return runSequentialFallback();
994
+ }
995
+ if (seenRowIds.has(op.row_id)) {
996
+ return runSequentialFallback();
997
+ }
998
+ seenRowIds.add(op.row_id);
999
+
1000
+ const rawPayload = op.payload ?? {};
1001
+ const payloadRecord =
1002
+ rawPayload !== null && typeof rawPayload === 'object'
1003
+ ? (rawPayload as Record<string, unknown>)
1004
+ : {};
1005
+ const payload = applyInboundTransform(
1006
+ payloadRecord,
1007
+ ctx.schemaVersion
1008
+ ) as Record<string, unknown>;
1009
+
1010
+ payloadKeySignatures.add(Object.keys(payload).sort().join('\u0000'));
1011
+
1012
+ const insertValues: Record<string, unknown> = {
1013
+ ...payload,
1014
+ [primaryKey]: op.row_id,
1015
+ [versionColumn]: 1,
1016
+ };
1017
+
1018
+ prepared.push({
1019
+ entry,
1020
+ payload,
1021
+ insertValues,
1022
+ });
1023
+ }
1024
+
1025
+ if (prepared.length <= 1 || payloadKeySignatures.size !== 1) {
1026
+ return runSequentialFallback();
1027
+ }
1028
+
1029
+ const basePayload = prepared[0]!.payload;
1030
+ const updateSet: Record<string, unknown> = {
1031
+ ...basePayload,
1032
+ [versionColumn]: sql`${sql.ref(qualifiedVersionRef)} + 1`,
1033
+ };
1034
+ delete updateSet[primaryKey];
1035
+ for (const col of Object.values(scopeColumns)) {
1036
+ delete updateSet[col];
1037
+ }
1038
+
1039
+ try {
1040
+ const updatedRows = (await (
1041
+ trx.insertInto(table) as InsertQueryBuilder<
1042
+ ServerDB,
1043
+ TableName,
1044
+ InsertResult
1045
+ >
1046
+ )
1047
+ .values(
1048
+ prepared.map(
1049
+ (item) => item.insertValues as Insertable<ServerDB[TableName]>
1050
+ )
1051
+ )
1052
+ .onConflict((oc) =>
1053
+ oc.column(primaryKeyColumn).doUpdateSet(updateSet as UpdateSetObject)
1054
+ )
1055
+ .returningAll()
1056
+ .execute()) as Record<string, unknown>[];
1057
+
1058
+ const updatedById = new Map<string, Record<string, unknown>>();
1059
+ for (const row of updatedRows) {
1060
+ const rowIdValue = row[primaryKey];
1061
+ if (rowIdValue === null || rowIdValue === undefined) continue;
1062
+ updatedById.set(String(rowIdValue), row);
1063
+ }
1064
+
1065
+ const results: ApplyOperationResult[] = [];
1066
+ for (const item of prepared) {
1067
+ const rowId = item.entry.op.row_id;
1068
+ const updated = updatedById.get(rowId);
1069
+ if (!updated) {
1070
+ return runSequentialFallback();
1071
+ }
1072
+
1073
+ const rowVersion = readSafeVersionColumn(updated, versionColumn, 1);
1074
+ const scopes = extractScopesImpl(updated);
1075
+ const rowJson = normalizeOutboundVersionColumn(
1076
+ applyOutboundTransform(updated as Selectable<ServerDB[TableName]>),
1077
+ versionColumn,
1078
+ rowVersion
1079
+ );
1080
+
1081
+ results.push({
1082
+ result: { opIndex: item.entry.opIndex, status: 'applied' },
1083
+ emittedChanges: [
1084
+ {
1085
+ table,
1086
+ row_id: rowId,
1087
+ op: 'upsert',
1088
+ row_json: rowJson,
1089
+ row_version: rowVersion,
1090
+ scopes,
1091
+ },
1092
+ ],
1093
+ });
1094
+ }
1095
+
1096
+ return results;
1097
+ } catch (err) {
1098
+ const message = err instanceof Error ? err.message : String(err);
1099
+ if (isConstraintViolationError(message)) {
1100
+ return runSequentialFallback();
1101
+ }
1102
+ throw err;
1103
+ }
1104
+ };
1105
+
731
1106
  return {
732
1107
  table,
1108
+ primaryKeyColumn,
733
1109
  scopePatterns,
734
1110
  dependsOn,
735
1111
  snapshotChunkTtlMs,
1112
+ snapshotBinaryColumns,
1113
+ snapshotBinaryColumnsForVersion,
1114
+ snapshotBinaryEncoder: snapshotBinaryEncoder as
1115
+ | BinarySnapshotRowsEncoder
1116
+ | undefined,
1117
+ snapshotBinaryEncoderForVersion: snapshotBinaryEncoderForVersion as
1118
+ | ((
1119
+ schemaVersion: number
1120
+ ) => BinarySnapshotRowsEncoder | null | undefined)
1121
+ | undefined,
1122
+ canRejectSingleOperationWithoutSavepoint:
1123
+ options.canRejectSingleOperationWithoutSavepoint ??
1124
+ options.applyOperation === undefined,
736
1125
  resolveScopes: resolveScopesImpl,
737
1126
  extractScopes: extractScopesImpl,
738
1127
  snapshot: options.snapshot ?? defaultSnapshot,
739
1128
  applyOperation: options.applyOperation ?? defaultApplyOperation,
1129
+ applyOperationBatch:
1130
+ options.applyOperation === undefined
1131
+ ? defaultApplyOperationBatch
1132
+ : undefined,
740
1133
  };
741
1134
  }