@rocicorp/zero 1.12.0-canary.0 → 1.12.0-canary.10

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 (1387) hide show
  1. package/out/_virtual/{_@oxc-project_runtime@0.130.0/helpers → _@oxc-project_runtime@0.154.0/helpers/esm}/usingCtx.js +2 -2
  2. package/out/analyze-query/src/analyze-cli.d.ts.map +1 -1
  3. package/out/analyze-query/src/analyze-cli.js +4 -2
  4. package/out/analyze-query/src/analyze-cli.js.map +1 -1
  5. package/out/analyze-query/src/bin-transform.js +4 -3
  6. package/out/analyze-query/src/bin-transform.js.map +1 -1
  7. package/out/analyze-query/src/zql-chain.d.ts +23 -0
  8. package/out/analyze-query/src/zql-chain.d.ts.map +1 -0
  9. package/out/analyze-query/src/zql-chain.js +162 -0
  10. package/out/analyze-query/src/zql-chain.js.map +1 -0
  11. package/out/ast-to-zql/src/ast-to-zql.js.map +1 -1
  12. package/out/ast-to-zql/src/bin.js +4 -3
  13. package/out/ast-to-zql/src/bin.js.map +1 -1
  14. package/out/ast-to-zql/src/format.js.map +1 -1
  15. package/out/datadog/src/datadog-log-sink.js +5 -4
  16. package/out/datadog/src/datadog-log-sink.js.map +1 -1
  17. package/out/otel/src/log-options.js.map +1 -1
  18. package/out/replicache/src/btree/node.d.ts +0 -2
  19. package/out/replicache/src/btree/node.d.ts.map +1 -1
  20. package/out/replicache/src/btree/node.js +14 -12
  21. package/out/replicache/src/btree/node.js.map +1 -1
  22. package/out/replicache/src/btree/read.js +4 -2
  23. package/out/replicache/src/btree/read.js.map +1 -1
  24. package/out/replicache/src/btree/splice.js.map +1 -1
  25. package/out/replicache/src/btree/write.js +9 -5
  26. package/out/replicache/src/btree/write.js.map +1 -1
  27. package/out/replicache/src/config.js +1 -2
  28. package/out/replicache/src/connection-loop.d.ts.map +1 -1
  29. package/out/replicache/src/connection-loop.js +1 -1
  30. package/out/replicache/src/connection-loop.js.map +1 -1
  31. package/out/replicache/src/dag/chunk.js +1 -1
  32. package/out/replicache/src/dag/gc.js.map +1 -1
  33. package/out/replicache/src/dag/lazy-store.js +8 -7
  34. package/out/replicache/src/dag/lazy-store.js.map +1 -1
  35. package/out/replicache/src/dag/store-impl.js +1 -1
  36. package/out/replicache/src/dag/store-impl.js.map +1 -1
  37. package/out/replicache/src/dag/visitor.js.map +1 -1
  38. package/out/replicache/src/db/commit.d.ts +0 -1
  39. package/out/replicache/src/db/commit.d.ts.map +1 -1
  40. package/out/replicache/src/db/commit.js +5 -3
  41. package/out/replicache/src/db/commit.js.map +1 -1
  42. package/out/replicache/src/db/read.js +1 -1
  43. package/out/replicache/src/db/read.js.map +1 -1
  44. package/out/replicache/src/db/rebase.js.map +1 -1
  45. package/out/replicache/src/db/write.d.ts +0 -2
  46. package/out/replicache/src/db/write.d.ts.map +1 -1
  47. package/out/replicache/src/db/write.js +5 -2
  48. package/out/replicache/src/db/write.js.map +1 -1
  49. package/out/replicache/src/deleted-clients.d.ts +0 -2
  50. package/out/replicache/src/deleted-clients.d.ts.map +1 -1
  51. package/out/replicache/src/deleted-clients.js +5 -3
  52. package/out/replicache/src/deleted-clients.js.map +1 -1
  53. package/out/replicache/src/expo-sqlite.js +1 -2
  54. package/out/replicache/src/frozen-json.d.ts +0 -1
  55. package/out/replicache/src/frozen-json.d.ts.map +1 -1
  56. package/out/replicache/src/frozen-json.js +1 -1
  57. package/out/replicache/src/frozen-json.js.map +1 -1
  58. package/out/replicache/src/get-default-puller.js +1 -1
  59. package/out/replicache/src/hash.js +1 -1
  60. package/out/replicache/src/hash.js.map +1 -1
  61. package/out/replicache/src/impl.js +1 -2
  62. package/out/replicache/src/index-defs.d.ts +0 -2
  63. package/out/replicache/src/index-defs.d.ts.map +1 -1
  64. package/out/replicache/src/index-defs.js +5 -3
  65. package/out/replicache/src/index-defs.js.map +1 -1
  66. package/out/replicache/src/kv/expo-sqlite/store.d.ts +0 -1
  67. package/out/replicache/src/kv/expo-sqlite/store.d.ts.map +1 -1
  68. package/out/replicache/src/kv/expo-sqlite/store.js.map +1 -1
  69. package/out/replicache/src/kv/idb-store.js +2 -2
  70. package/out/replicache/src/kv/idb-store.js.map +1 -1
  71. package/out/replicache/src/kv/mem-fallback-store.js +1 -1
  72. package/out/replicache/src/kv/mem-fallback-store.js.map +1 -1
  73. package/out/replicache/src/kv/mem-store.js.map +1 -1
  74. package/out/replicache/src/kv/op-sqlite/store.js.map +1 -1
  75. package/out/replicache/src/kv/op-sqlite/types.js.map +1 -1
  76. package/out/replicache/src/kv/read-impl.js.map +1 -1
  77. package/out/replicache/src/kv/sqlite-store.d.ts.map +1 -1
  78. package/out/replicache/src/kv/sqlite-store.js +8 -4
  79. package/out/replicache/src/kv/sqlite-store.js.map +1 -1
  80. package/out/replicache/src/kv/throw-if-closed.d.ts +0 -3
  81. package/out/replicache/src/kv/throw-if-closed.d.ts.map +1 -1
  82. package/out/replicache/src/kv/throw-if-closed.js.map +1 -1
  83. package/out/replicache/src/kv/write-impl-base.js +4 -1
  84. package/out/replicache/src/kv/write-impl-base.js.map +1 -1
  85. package/out/replicache/src/kv/write-impl.js.map +1 -1
  86. package/out/replicache/src/log-options.js +2 -1
  87. package/out/replicache/src/log-options.js.map +1 -1
  88. package/out/replicache/src/make-idb-name.js +1 -1
  89. package/out/replicache/src/new-client-channel.js +9 -7
  90. package/out/replicache/src/new-client-channel.js.map +1 -1
  91. package/out/replicache/src/on-persist-channel.js +1 -1
  92. package/out/replicache/src/on-persist-channel.js.map +1 -1
  93. package/out/replicache/src/op-sqlite.js +1 -2
  94. package/out/replicache/src/pending-mutations.js +2 -1
  95. package/out/replicache/src/pending-mutations.js.map +1 -1
  96. package/out/replicache/src/persist/client-gc.js +2 -2
  97. package/out/replicache/src/persist/client-gc.js.map +1 -1
  98. package/out/replicache/src/persist/client-group-gc.d.ts +0 -7
  99. package/out/replicache/src/persist/client-group-gc.d.ts.map +1 -1
  100. package/out/replicache/src/persist/client-group-gc.js +1 -1
  101. package/out/replicache/src/persist/client-group-gc.js.map +1 -1
  102. package/out/replicache/src/persist/client-groups.js +1 -1
  103. package/out/replicache/src/persist/client-groups.js.map +1 -1
  104. package/out/replicache/src/persist/clients.js +1 -1
  105. package/out/replicache/src/persist/clients.js.map +1 -1
  106. package/out/replicache/src/persist/collect-idb-databases.js +5 -4
  107. package/out/replicache/src/persist/collect-idb-databases.js.map +1 -1
  108. package/out/replicache/src/persist/gather-mem-only-visitor.js.map +1 -1
  109. package/out/replicache/src/persist/gather-not-cached-visitor.js.map +1 -1
  110. package/out/replicache/src/persist/heartbeat.js +2 -2
  111. package/out/replicache/src/persist/heartbeat.js.map +1 -1
  112. package/out/replicache/src/persist/idb-databases-store.js +1 -1
  113. package/out/replicache/src/persist/idb-databases-store.js.map +1 -1
  114. package/out/replicache/src/persist/make-client-id.js +1 -1
  115. package/out/replicache/src/persist/make-client-id.js.map +1 -1
  116. package/out/replicache/src/persist/persist.js +3 -2
  117. package/out/replicache/src/persist/persist.js.map +1 -1
  118. package/out/replicache/src/persist/refresh.js +8 -5
  119. package/out/replicache/src/persist/refresh.js.map +1 -1
  120. package/out/replicache/src/process-scheduler.js +1 -1
  121. package/out/replicache/src/process-scheduler.js.map +1 -1
  122. package/out/replicache/src/replicache-impl.d.ts +2 -7
  123. package/out/replicache/src/replicache-impl.d.ts.map +1 -1
  124. package/out/replicache/src/replicache-impl.js +21 -18
  125. package/out/replicache/src/replicache-impl.js.map +1 -1
  126. package/out/replicache/src/scan-iterator.js.map +1 -1
  127. package/out/replicache/src/scan-options.js +7 -6
  128. package/out/replicache/src/scan-options.js.map +1 -1
  129. package/out/replicache/src/sqlite.js +1 -2
  130. package/out/replicache/src/subscriptions.js +1 -1
  131. package/out/replicache/src/subscriptions.js.map +1 -1
  132. package/out/replicache/src/sync/diff.js +3 -1
  133. package/out/replicache/src/sync/diff.js.map +1 -1
  134. package/out/replicache/src/sync/ids.js.map +1 -1
  135. package/out/replicache/src/sync/patch.d.ts +0 -5
  136. package/out/replicache/src/sync/patch.d.ts.map +1 -1
  137. package/out/replicache/src/sync/patch.js +2 -4
  138. package/out/replicache/src/sync/patch.js.map +1 -1
  139. package/out/replicache/src/sync/pull.d.ts +0 -1
  140. package/out/replicache/src/sync/pull.d.ts.map +1 -1
  141. package/out/replicache/src/sync/pull.js +3 -1
  142. package/out/replicache/src/sync/pull.js.map +1 -1
  143. package/out/replicache/src/sync/push.d.ts +2 -1
  144. package/out/replicache/src/sync/push.d.ts.map +1 -1
  145. package/out/replicache/src/sync/push.js.map +1 -1
  146. package/out/replicache/src/sync/request-id.js +1 -1
  147. package/out/replicache/src/sync/request-id.js.map +1 -1
  148. package/out/replicache/src/transactions.js +1 -1
  149. package/out/replicache/src/transactions.js.map +1 -1
  150. package/out/replicache/src/types.d.ts +2 -1
  151. package/out/replicache/src/types.d.ts.map +1 -1
  152. package/out/shared/src/arrays.js +4 -1
  153. package/out/shared/src/arrays.js.map +1 -1
  154. package/out/shared/src/asserts.d.ts +0 -5
  155. package/out/shared/src/asserts.d.ts.map +1 -1
  156. package/out/shared/src/asserts.js.map +1 -1
  157. package/out/shared/src/bigint-json.d.ts +9 -0
  158. package/out/shared/src/bigint-json.d.ts.map +1 -1
  159. package/out/shared/src/bigint-json.js +27 -2
  160. package/out/shared/src/bigint-json.js.map +1 -1
  161. package/out/shared/src/broadcast-channel.js +1 -1
  162. package/out/shared/src/browser-env.d.ts +0 -17
  163. package/out/shared/src/browser-env.d.ts.map +1 -1
  164. package/out/shared/src/browser-env.js.map +1 -1
  165. package/out/shared/src/btree-set.js +11 -8
  166. package/out/shared/src/btree-set.js.map +1 -1
  167. package/out/shared/src/cache.js.map +1 -1
  168. package/out/shared/src/config.js +1 -1
  169. package/out/shared/src/custom-key-map.js.map +1 -1
  170. package/out/shared/src/custom-key-set.js.map +1 -1
  171. package/out/shared/src/deep-clone.d.ts +0 -1
  172. package/out/shared/src/deep-clone.d.ts.map +1 -1
  173. package/out/shared/src/deep-clone.js.map +1 -1
  174. package/out/shared/src/document-visible.js +1 -1
  175. package/out/shared/src/document-visible.js.map +1 -1
  176. package/out/shared/src/dotenv.js.map +1 -1
  177. package/out/shared/src/error.js +1 -1
  178. package/out/shared/src/error.js.map +1 -1
  179. package/out/shared/src/expand.d.ts +0 -3
  180. package/out/shared/src/expand.d.ts.map +1 -1
  181. package/out/shared/src/hash.js +2 -2
  182. package/out/shared/src/hash.js.map +1 -1
  183. package/out/shared/src/immutable.d.ts +1 -1
  184. package/out/shared/src/immutable.d.ts.map +1 -1
  185. package/out/shared/src/iterables.d.ts +0 -1
  186. package/out/shared/src/iterables.d.ts.map +1 -1
  187. package/out/shared/src/iterables.js.map +1 -1
  188. package/out/shared/src/json-schema.js.map +1 -1
  189. package/out/shared/src/json.js.map +1 -1
  190. package/out/shared/src/logging-test-utils.js.map +1 -1
  191. package/out/shared/src/logging.js +1 -1
  192. package/out/shared/src/logging.js.map +1 -1
  193. package/out/shared/src/navigator.js +1 -1
  194. package/out/shared/src/options-types.d.ts +1 -1
  195. package/out/shared/src/options-types.d.ts.map +1 -1
  196. package/out/shared/src/options.d.ts +2 -3
  197. package/out/shared/src/options.d.ts.map +1 -1
  198. package/out/shared/src/options.js +8 -11
  199. package/out/shared/src/options.js.map +1 -1
  200. package/out/shared/src/promise-race.js +1 -1
  201. package/out/shared/src/promise-race.js.map +1 -1
  202. package/out/shared/src/queue.js +1 -1
  203. package/out/shared/src/queue.js.map +1 -1
  204. package/out/shared/src/record-proxy.js.map +1 -1
  205. package/out/shared/src/resolved-promises.d.ts +0 -4
  206. package/out/shared/src/resolved-promises.d.ts.map +1 -1
  207. package/out/shared/src/resolved-promises.js +0 -1
  208. package/out/shared/src/resolved-promises.js.map +1 -1
  209. package/out/shared/src/resolver.d.ts +9 -0
  210. package/out/shared/src/resolver.d.ts.map +1 -0
  211. package/out/shared/src/resolver.js +6 -0
  212. package/out/shared/src/resolver.js.map +1 -0
  213. package/out/shared/src/ring-buffer.js.map +1 -1
  214. package/out/shared/src/size-of-value.js +7 -10
  215. package/out/shared/src/size-of-value.js.map +1 -1
  216. package/out/shared/src/sleep.js +1 -1
  217. package/out/shared/src/sleep.js.map +1 -1
  218. package/out/shared/src/sorted-entries.js.map +1 -1
  219. package/out/shared/src/tdigest-schema.js.map +1 -1
  220. package/out/shared/src/tdigest.d.ts +0 -1
  221. package/out/shared/src/tdigest.d.ts.map +1 -1
  222. package/out/shared/src/tdigest.js.map +1 -1
  223. package/out/shared/src/valita.js +1 -1
  224. package/out/shared/src/valita.js.map +1 -1
  225. package/out/z2s/src/compiler.js +5 -7
  226. package/out/z2s/src/compiler.js.map +1 -1
  227. package/out/z2s/src/sql.d.ts +1 -5
  228. package/out/z2s/src/sql.d.ts.map +1 -1
  229. package/out/z2s/src/sql.js +1 -1
  230. package/out/z2s/src/sql.js.map +1 -1
  231. package/out/zero/package.js +210 -189
  232. package/out/zero/package.js.map +1 -1
  233. package/out/zero/src/adapters/drizzle.js +1 -2
  234. package/out/zero/src/adapters/kysely.js +1 -2
  235. package/out/zero/src/adapters/pg.js +1 -2
  236. package/out/zero/src/adapters/postgresjs.js +1 -2
  237. package/out/zero/src/adapters/prisma.js +1 -2
  238. package/out/zero/src/analyze.js +1 -2
  239. package/out/zero/src/change-protocol/v0.js +1 -2
  240. package/out/zero/src/expo-sqlite.js +1 -2
  241. package/out/zero/src/op-sqlite.js +1 -2
  242. package/out/zero/src/react-native.js.map +1 -1
  243. package/out/zero/src/sqlite.js +1 -2
  244. package/out/zero/src/zero-cache-dev.js +11 -10
  245. package/out/zero/src/zero-cache-dev.js.map +1 -1
  246. package/out/zero/src/zero-out.js +2 -1
  247. package/out/zero/src/zero-out.js.map +1 -1
  248. package/out/zero-cache/src/auth/auth.js +1 -1
  249. package/out/zero-cache/src/auth/auth.js.map +1 -1
  250. package/out/zero-cache/src/auth/jwt.js +4 -1
  251. package/out/zero-cache/src/auth/jwt.js.map +1 -1
  252. package/out/zero-cache/src/auth/load-permissions.js +1 -1
  253. package/out/zero-cache/src/auth/load-permissions.js.map +1 -1
  254. package/out/zero-cache/src/auth/read-authorizer.js +3 -2
  255. package/out/zero-cache/src/auth/read-authorizer.js.map +1 -1
  256. package/out/zero-cache/src/auth/write-authorizer.js +15 -19
  257. package/out/zero-cache/src/auth/write-authorizer.js.map +1 -1
  258. package/out/zero-cache/src/config/network.js +1 -1
  259. package/out/zero-cache/src/config/network.js.map +1 -1
  260. package/out/zero-cache/src/config/server-context.js.map +1 -1
  261. package/out/zero-cache/src/config/zero-config.d.ts +19 -11
  262. package/out/zero-cache/src/config/zero-config.d.ts.map +1 -1
  263. package/out/zero-cache/src/config/zero-config.js +47 -10
  264. package/out/zero-cache/src/config/zero-config.js.map +1 -1
  265. package/out/zero-cache/src/custom/fetch.js +1 -1
  266. package/out/zero-cache/src/custom/fetch.js.map +1 -1
  267. package/out/zero-cache/src/custom-queries/transform-query.js.map +1 -1
  268. package/out/zero-cache/src/db/create.js.map +1 -1
  269. package/out/zero-cache/src/db/index-predicate.js.map +1 -1
  270. package/out/zero-cache/src/db/lite-tables.d.ts +2 -2
  271. package/out/zero-cache/src/db/lite-tables.d.ts.map +1 -1
  272. package/out/zero-cache/src/db/lite-tables.js.map +1 -1
  273. package/out/zero-cache/src/db/migration-lite.js +1 -1
  274. package/out/zero-cache/src/db/migration-lite.js.map +1 -1
  275. package/out/zero-cache/src/db/migration.js +5 -3
  276. package/out/zero-cache/src/db/migration.js.map +1 -1
  277. package/out/zero-cache/src/db/pg-copy-binary.js +4 -3
  278. package/out/zero-cache/src/db/pg-copy-binary.js.map +1 -1
  279. package/out/zero-cache/src/db/pg-copy.js +0 -1
  280. package/out/zero-cache/src/db/pg-copy.js.map +1 -1
  281. package/out/zero-cache/src/db/pg-to-lite.js +1 -1
  282. package/out/zero-cache/src/db/pg-to-lite.js.map +1 -1
  283. package/out/zero-cache/src/db/pg-type-parser.js.map +1 -1
  284. package/out/zero-cache/src/db/run-transaction.js.map +1 -1
  285. package/out/zero-cache/src/db/specs.d.ts +3 -4
  286. package/out/zero-cache/src/db/specs.d.ts.map +1 -1
  287. package/out/zero-cache/src/db/specs.js +1 -1
  288. package/out/zero-cache/src/db/specs.js.map +1 -1
  289. package/out/zero-cache/src/db/sqlite-corruption.js.map +1 -1
  290. package/out/zero-cache/src/db/statements.d.ts.map +1 -1
  291. package/out/zero-cache/src/db/statements.js +9 -2
  292. package/out/zero-cache/src/db/statements.js.map +1 -1
  293. package/out/zero-cache/src/db/transaction-pool.js +6 -4
  294. package/out/zero-cache/src/db/transaction-pool.js.map +1 -1
  295. package/out/zero-cache/src/db/warmup.js.map +1 -1
  296. package/out/zero-cache/src/observability/events.js +1 -1
  297. package/out/zero-cache/src/observability/events.js.map +1 -1
  298. package/out/zero-cache/src/observability/log-throttle.js.map +1 -1
  299. package/out/zero-cache/src/observability/metrics.js.map +1 -1
  300. package/out/zero-cache/src/scripts/decommission.js +1 -1
  301. package/out/zero-cache/src/scripts/deploy-permissions.js +5 -3
  302. package/out/zero-cache/src/scripts/deploy-permissions.js.map +1 -1
  303. package/out/zero-cache/src/scripts/permissions.js.map +1 -1
  304. package/out/zero-cache/src/server/anonymous-otel-start.js +2 -1
  305. package/out/zero-cache/src/server/anonymous-otel-start.js.map +1 -1
  306. package/out/zero-cache/src/server/change-streamer.js +49 -16
  307. package/out/zero-cache/src/server/change-streamer.js.map +1 -1
  308. package/out/zero-cache/src/server/inspector-delegate.js.map +1 -1
  309. package/out/zero-cache/src/server/logging.js +1 -1
  310. package/out/zero-cache/src/server/logging.js.map +1 -1
  311. package/out/zero-cache/src/server/main.js +2 -2
  312. package/out/zero-cache/src/server/main.js.map +1 -1
  313. package/out/zero-cache/src/server/otel-log-sink.js.map +1 -1
  314. package/out/zero-cache/src/server/otel-start.js.map +1 -1
  315. package/out/zero-cache/src/server/reaper.js +2 -2
  316. package/out/zero-cache/src/server/reaper.js.map +1 -1
  317. package/out/zero-cache/src/server/replicator.js +1 -1
  318. package/out/zero-cache/src/server/replicator.js.map +1 -1
  319. package/out/zero-cache/src/server/runner/run-worker.d.ts.map +1 -1
  320. package/out/zero-cache/src/server/runner/run-worker.js +4 -3
  321. package/out/zero-cache/src/server/runner/run-worker.js.map +1 -1
  322. package/out/zero-cache/src/server/runner/runtime.js +2 -1
  323. package/out/zero-cache/src/server/runner/runtime.js.map +1 -1
  324. package/out/zero-cache/src/server/runner/zero-dispatcher.d.ts +9 -1
  325. package/out/zero-cache/src/server/runner/zero-dispatcher.d.ts.map +1 -1
  326. package/out/zero-cache/src/server/runner/zero-dispatcher.js +29 -2
  327. package/out/zero-cache/src/server/runner/zero-dispatcher.js.map +1 -1
  328. package/out/zero-cache/src/server/shadow-syncer.js +1 -1
  329. package/out/zero-cache/src/server/shadow-syncer.js.map +1 -1
  330. package/out/zero-cache/src/server/slot-keeper.js.map +1 -1
  331. package/out/zero-cache/src/server/syncer-assigner.js.map +1 -1
  332. package/out/zero-cache/src/server/syncer.js +10 -5
  333. package/out/zero-cache/src/server/syncer.js.map +1 -1
  334. package/out/zero-cache/src/server/worker-dispatcher.js +1 -1
  335. package/out/zero-cache/src/server/worker-dispatcher.js.map +1 -1
  336. package/out/zero-cache/src/server/worker-urls.js.map +1 -1
  337. package/out/zero-cache/src/services/analyze.js +2 -2
  338. package/out/zero-cache/src/services/analyze.js.map +1 -1
  339. package/out/zero-cache/src/services/change-source/common/backfill-manager.js +3 -3
  340. package/out/zero-cache/src/services/change-source/common/backfill-manager.js.map +1 -1
  341. package/out/zero-cache/src/services/change-source/common/change-stream-multiplexer.js +1 -1
  342. package/out/zero-cache/src/services/change-source/common/change-stream-multiplexer.js.map +1 -1
  343. package/out/zero-cache/src/services/change-source/common/init-cleanup.js.map +1 -1
  344. package/out/zero-cache/src/services/change-source/common/replica-restore.js.map +1 -1
  345. package/out/zero-cache/src/services/change-source/common/replica-schema.js +4 -4
  346. package/out/zero-cache/src/services/change-source/common/replica-schema.js.map +1 -1
  347. package/out/zero-cache/src/services/change-source/custom/change-source.js +1 -1
  348. package/out/zero-cache/src/services/change-source/custom/change-source.js.map +1 -1
  349. package/out/zero-cache/src/services/change-source/pg/backfill-metadata.js.map +1 -1
  350. package/out/zero-cache/src/services/change-source/pg/backfill-stream.js +4 -4
  351. package/out/zero-cache/src/services/change-source/pg/backfill-stream.js.map +1 -1
  352. package/out/zero-cache/src/services/change-source/pg/change-source-init.js +52 -27
  353. package/out/zero-cache/src/services/change-source/pg/change-source-init.js.map +1 -1
  354. package/out/zero-cache/src/services/change-source/pg/change-source.js +70 -15
  355. package/out/zero-cache/src/services/change-source/pg/change-source.js.map +1 -1
  356. package/out/zero-cache/src/services/change-source/pg/decommission.js +2 -1
  357. package/out/zero-cache/src/services/change-source/pg/decommission.js.map +1 -1
  358. package/out/zero-cache/src/services/change-source/pg/fork-request.js +54 -0
  359. package/out/zero-cache/src/services/change-source/pg/fork-request.js.map +1 -0
  360. package/out/zero-cache/src/services/change-source/pg/initial-sync.js +9 -7
  361. package/out/zero-cache/src/services/change-source/pg/initial-sync.js.map +1 -1
  362. package/out/zero-cache/src/services/change-source/pg/logical-replication/binary-reader.js.map +1 -1
  363. package/out/zero-cache/src/services/change-source/pg/logical-replication/pgoutput-parser.js.map +1 -1
  364. package/out/zero-cache/src/services/change-source/pg/logical-replication/stream.js +5 -4
  365. package/out/zero-cache/src/services/change-source/pg/logical-replication/stream.js.map +1 -1
  366. package/out/zero-cache/src/services/change-source/pg/lsn.d.ts +0 -2
  367. package/out/zero-cache/src/services/change-source/pg/lsn.d.ts.map +1 -1
  368. package/out/zero-cache/src/services/change-source/pg/lsn.js.map +1 -1
  369. package/out/zero-cache/src/services/change-source/pg/replication-slot-cleanup-monitor.js +2 -2
  370. package/out/zero-cache/src/services/change-source/pg/replication-slot-cleanup-monitor.js.map +1 -1
  371. package/out/zero-cache/src/services/change-source/pg/replication-slot-health.js +1 -1
  372. package/out/zero-cache/src/services/change-source/pg/replication-slot-health.js.map +1 -1
  373. package/out/zero-cache/src/services/change-source/pg/replication-slots.js +9 -3
  374. package/out/zero-cache/src/services/change-source/pg/replication-slots.js.map +1 -1
  375. package/out/zero-cache/src/services/change-source/pg/schema/ddl.d.ts +0 -12
  376. package/out/zero-cache/src/services/change-source/pg/schema/ddl.d.ts.map +1 -1
  377. package/out/zero-cache/src/services/change-source/pg/schema/ddl.js +6 -4
  378. package/out/zero-cache/src/services/change-source/pg/schema/ddl.js.map +1 -1
  379. package/out/zero-cache/src/services/change-source/pg/schema/index-predicate.d.ts +1 -1
  380. package/out/zero-cache/src/services/change-source/pg/schema/index-predicate.d.ts.map +1 -1
  381. package/out/zero-cache/src/services/change-source/pg/schema/index-predicate.js +13 -12
  382. package/out/zero-cache/src/services/change-source/pg/schema/index-predicate.js.map +1 -1
  383. package/out/zero-cache/src/services/change-source/pg/schema/init.js +1 -1
  384. package/out/zero-cache/src/services/change-source/pg/schema/init.js.map +1 -1
  385. package/out/zero-cache/src/services/change-source/pg/schema/published.js +2 -2
  386. package/out/zero-cache/src/services/change-source/pg/schema/published.js.map +1 -1
  387. package/out/zero-cache/src/services/change-source/pg/schema/replica-stage-enum.js.map +1 -1
  388. package/out/zero-cache/src/services/change-source/pg/schema/shard.js +10 -7
  389. package/out/zero-cache/src/services/change-source/pg/schema/shard.js.map +1 -1
  390. package/out/zero-cache/src/services/change-source/pg/schema/validation.d.ts +0 -1
  391. package/out/zero-cache/src/services/change-source/pg/schema/validation.d.ts.map +1 -1
  392. package/out/zero-cache/src/services/change-source/pg/schema/validation.js +1 -1
  393. package/out/zero-cache/src/services/change-source/pg/schema/validation.js.map +1 -1
  394. package/out/zero-cache/src/services/change-source/protocol/backfill-progress.js +1 -1
  395. package/out/zero-cache/src/services/change-source/protocol/backfill-progress.js.map +1 -1
  396. package/out/zero-cache/src/services/change-source/protocol/current/control.js.map +1 -1
  397. package/out/zero-cache/src/services/change-source/protocol/current/data.js.map +1 -1
  398. package/out/zero-cache/src/services/change-source/protocol/current/downstream.d.ts +1 -0
  399. package/out/zero-cache/src/services/change-source/protocol/current/downstream.d.ts.map +1 -1
  400. package/out/zero-cache/src/services/change-source/protocol/current/downstream.js.map +1 -1
  401. package/out/zero-cache/src/services/change-source/protocol/current/status.d.ts +3 -0
  402. package/out/zero-cache/src/services/change-source/protocol/current/status.d.ts.map +1 -1
  403. package/out/zero-cache/src/services/change-source/protocol/current/status.js +2 -1
  404. package/out/zero-cache/src/services/change-source/protocol/current/status.js.map +1 -1
  405. package/out/zero-cache/src/services/change-source/protocol/current/upstream.d.ts +1 -0
  406. package/out/zero-cache/src/services/change-source/protocol/current/upstream.d.ts.map +1 -1
  407. package/out/zero-cache/src/services/change-source/protocol/current/upstream.js.map +1 -1
  408. package/out/zero-cache/src/services/change-source/protocol/current.js +1 -1
  409. package/out/zero-cache/src/services/change-source/protocol/mod.js +1 -2
  410. package/out/zero-cache/src/services/change-streamer/backfill-state-tracker.js.map +1 -1
  411. package/out/zero-cache/src/services/change-streamer/backfill-state.js +1 -1
  412. package/out/zero-cache/src/services/change-streamer/backfill-state.js.map +1 -1
  413. package/out/zero-cache/src/services/change-streamer/backup-cleanup-monitor-factory.js +6 -6
  414. package/out/zero-cache/src/services/change-streamer/backup-cleanup-monitor-factory.js.map +1 -1
  415. package/out/zero-cache/src/services/change-streamer/backup-monitor.js +56 -21
  416. package/out/zero-cache/src/services/change-streamer/backup-monitor.js.map +1 -1
  417. package/out/zero-cache/src/services/change-streamer/broadcast.js +2 -2
  418. package/out/zero-cache/src/services/change-streamer/broadcast.js.map +1 -1
  419. package/out/zero-cache/src/services/change-streamer/change-log-codec.js +2 -3
  420. package/out/zero-cache/src/services/change-streamer/change-log-codec.js.map +1 -1
  421. package/out/zero-cache/src/services/change-streamer/change-log-initializer.js +3 -3
  422. package/out/zero-cache/src/services/change-streamer/change-log-initializer.js.map +1 -1
  423. package/out/zero-cache/src/services/change-streamer/change-log-transaction-hash.js.map +1 -1
  424. package/out/zero-cache/src/services/change-streamer/change-streamer-http.js +8 -4
  425. package/out/zero-cache/src/services/change-streamer/change-streamer-http.js.map +1 -1
  426. package/out/zero-cache/src/services/change-streamer/change-streamer-service.js +85 -59
  427. package/out/zero-cache/src/services/change-streamer/change-streamer-service.js.map +1 -1
  428. package/out/zero-cache/src/services/change-streamer/change-streamer.js.map +1 -1
  429. package/out/zero-cache/src/services/change-streamer/drain-tracker.js +1 -1
  430. package/out/zero-cache/src/services/change-streamer/drain-tracker.js.map +1 -1
  431. package/out/zero-cache/src/services/change-streamer/forwarder.js +11 -10
  432. package/out/zero-cache/src/services/change-streamer/forwarder.js.map +1 -1
  433. package/out/zero-cache/src/services/change-streamer/litestream-sync-requester.js +81 -12
  434. package/out/zero-cache/src/services/change-streamer/litestream-sync-requester.js.map +1 -1
  435. package/out/zero-cache/src/services/change-streamer/litestream3-prometheus-poller.js +4 -4
  436. package/out/zero-cache/src/services/change-streamer/litestream3-prometheus-poller.js.map +1 -1
  437. package/out/zero-cache/src/services/change-streamer/replica-poller.js +2 -2
  438. package/out/zero-cache/src/services/change-streamer/replica-poller.js.map +1 -1
  439. package/out/zero-cache/src/services/change-streamer/restore-admission.js +12 -1
  440. package/out/zero-cache/src/services/change-streamer/restore-admission.js.map +1 -1
  441. package/out/zero-cache/src/services/change-streamer/schema/init.js +1 -1
  442. package/out/zero-cache/src/services/change-streamer/schema/init.js.map +1 -1
  443. package/out/zero-cache/src/services/change-streamer/schema/tables.js +1 -1
  444. package/out/zero-cache/src/services/change-streamer/schema/tables.js.map +1 -1
  445. package/out/zero-cache/src/services/change-streamer/server-start-metrics.js +42 -0
  446. package/out/zero-cache/src/services/change-streamer/server-start-metrics.js.map +1 -0
  447. package/out/zero-cache/src/services/change-streamer/snapshot-message.js +1 -2
  448. package/out/zero-cache/src/services/change-streamer/snapshot-message.js.map +1 -1
  449. package/out/zero-cache/src/services/change-streamer/snapshot-reservations.js.map +1 -1
  450. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-catchup.js +2 -2
  451. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-catchup.js.map +1 -1
  452. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-comparator.js +2 -2
  453. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-comparator.js.map +1 -1
  454. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-purge-scheduler.js.map +1 -1
  455. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-read-router.js.map +1 -1
  456. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-reader.js +4 -6
  457. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-reader.js.map +1 -1
  458. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-writer.js +3 -5
  459. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-writer.js.map +1 -1
  460. package/out/zero-cache/src/services/change-streamer/storer.js +4 -4
  461. package/out/zero-cache/src/services/change-streamer/storer.js.map +1 -1
  462. package/out/zero-cache/src/services/change-streamer/subscribe.js.map +1 -1
  463. package/out/zero-cache/src/services/change-streamer/subscriber.js +8 -7
  464. package/out/zero-cache/src/services/change-streamer/subscriber.js.map +1 -1
  465. package/out/zero-cache/src/services/change-streamer/upstream-acker.js +0 -1
  466. package/out/zero-cache/src/services/change-streamer/upstream-acker.js.map +1 -1
  467. package/out/zero-cache/src/services/heapz.js +2 -1
  468. package/out/zero-cache/src/services/heapz.js.map +1 -1
  469. package/out/zero-cache/src/services/http-service.d.ts +2 -2
  470. package/out/zero-cache/src/services/http-service.d.ts.map +1 -1
  471. package/out/zero-cache/src/services/http-service.js +6 -4
  472. package/out/zero-cache/src/services/http-service.js.map +1 -1
  473. package/out/zero-cache/src/services/life-cycle.js +3 -3
  474. package/out/zero-cache/src/services/life-cycle.js.map +1 -1
  475. package/out/zero-cache/src/services/limiter/sliding-window-limiter.js +4 -2
  476. package/out/zero-cache/src/services/limiter/sliding-window-limiter.js.map +1 -1
  477. package/out/zero-cache/src/services/litestream/commands.js +4 -4
  478. package/out/zero-cache/src/services/litestream/commands.js.map +1 -1
  479. package/out/zero-cache/src/services/litestream/litestream-checkpointer.js +2 -2
  480. package/out/zero-cache/src/services/litestream/litestream-checkpointer.js.map +1 -1
  481. package/out/zero-cache/src/services/litestream/litestream-controller.js.map +1 -1
  482. package/out/zero-cache/src/services/litestream/metrics.js.map +1 -1
  483. package/out/zero-cache/src/services/litestream/restore-progress.js.map +1 -1
  484. package/out/zero-cache/src/services/mutagen/mutagen.js +3 -4
  485. package/out/zero-cache/src/services/mutagen/mutagen.js.map +1 -1
  486. package/out/zero-cache/src/services/mutagen/pusher.js +61 -17
  487. package/out/zero-cache/src/services/mutagen/pusher.js.map +1 -1
  488. package/out/zero-cache/src/services/plannerz.d.ts +4 -12
  489. package/out/zero-cache/src/services/plannerz.d.ts.map +1 -1
  490. package/out/zero-cache/src/services/plannerz.js +6 -7
  491. package/out/zero-cache/src/services/plannerz.js.map +1 -1
  492. package/out/zero-cache/src/services/profz.js +5 -3
  493. package/out/zero-cache/src/services/profz.js.map +1 -1
  494. package/out/zero-cache/src/services/replicator/change-log-cookies.js.map +1 -1
  495. package/out/zero-cache/src/services/replicator/change-log-db.js +4 -3
  496. package/out/zero-cache/src/services/replicator/change-log-db.js.map +1 -1
  497. package/out/zero-cache/src/services/replicator/change-log-stream-writer.js.map +1 -1
  498. package/out/zero-cache/src/services/replicator/change-processor.js.map +1 -1
  499. package/out/zero-cache/src/services/replicator/drain-handler.js +1 -1
  500. package/out/zero-cache/src/services/replicator/drain-handler.js.map +1 -1
  501. package/out/zero-cache/src/services/replicator/incremental-sync.js +4 -4
  502. package/out/zero-cache/src/services/replicator/incremental-sync.js.map +1 -1
  503. package/out/zero-cache/src/services/replicator/notifier.js.map +1 -1
  504. package/out/zero-cache/src/services/replicator/replication-status.js +4 -3
  505. package/out/zero-cache/src/services/replicator/replication-status.js.map +1 -1
  506. package/out/zero-cache/src/services/replicator/replicator.js.map +1 -1
  507. package/out/zero-cache/src/services/replicator/reporter/recorder.js +2 -2
  508. package/out/zero-cache/src/services/replicator/reporter/recorder.js.map +1 -1
  509. package/out/zero-cache/src/services/replicator/reporter/report-schema.d.ts +2 -11
  510. package/out/zero-cache/src/services/replicator/reporter/report-schema.d.ts.map +1 -1
  511. package/out/zero-cache/src/services/replicator/reporter/report-schema.js.map +1 -1
  512. package/out/zero-cache/src/services/replicator/schema/backfilling.js +2 -2
  513. package/out/zero-cache/src/services/replicator/schema/backfilling.js.map +1 -1
  514. package/out/zero-cache/src/services/replicator/schema/change-log.d.ts +19 -17
  515. package/out/zero-cache/src/services/replicator/schema/change-log.d.ts.map +1 -1
  516. package/out/zero-cache/src/services/replicator/schema/change-log.js +31 -15
  517. package/out/zero-cache/src/services/replicator/schema/change-log.js.map +1 -1
  518. package/out/zero-cache/src/services/replicator/schema/column-metadata.d.ts +0 -7
  519. package/out/zero-cache/src/services/replicator/schema/column-metadata.d.ts.map +1 -1
  520. package/out/zero-cache/src/services/replicator/schema/column-metadata.js +1 -1
  521. package/out/zero-cache/src/services/replicator/schema/column-metadata.js.map +1 -1
  522. package/out/zero-cache/src/services/replicator/schema/replication-state.js +10 -7
  523. package/out/zero-cache/src/services/replicator/schema/replication-state.js.map +1 -1
  524. package/out/zero-cache/src/services/replicator/schema/table-metadata.js.map +1 -1
  525. package/out/zero-cache/src/services/replicator/sqlite-change-log-observability.js +1 -1
  526. package/out/zero-cache/src/services/replicator/sqlite-change-log-observability.js.map +1 -1
  527. package/out/zero-cache/src/services/replicator/sqlite-change-log-purger.js +1 -1
  528. package/out/zero-cache/src/services/replicator/sqlite-change-log-purger.js.map +1 -1
  529. package/out/zero-cache/src/services/replicator/write-worker-client.js +2 -2
  530. package/out/zero-cache/src/services/replicator/write-worker-client.js.map +1 -1
  531. package/out/zero-cache/src/services/replicator/write-worker.js +3 -3
  532. package/out/zero-cache/src/services/replicator/write-worker.js.map +1 -1
  533. package/out/zero-cache/src/services/run-ast.js +1 -1
  534. package/out/zero-cache/src/services/run-ast.js.map +1 -1
  535. package/out/zero-cache/src/services/runner.js.map +1 -1
  536. package/out/zero-cache/src/services/running-state.js +1 -1
  537. package/out/zero-cache/src/services/running-state.js.map +1 -1
  538. package/out/zero-cache/src/services/shadow-sync/shadow-sync-service.js.map +1 -1
  539. package/out/zero-cache/src/services/statz.d.ts.map +1 -1
  540. package/out/zero-cache/src/services/statz.js +5 -4
  541. package/out/zero-cache/src/services/statz.js.map +1 -1
  542. package/out/zero-cache/src/services/view-syncer/active-users-gauge.js +2 -2
  543. package/out/zero-cache/src/services/view-syncer/active-users-gauge.js.map +1 -1
  544. package/out/zero-cache/src/services/view-syncer/advancement-metrics.js.map +1 -1
  545. package/out/zero-cache/src/services/view-syncer/batch-pacer.js.map +1 -1
  546. package/out/zero-cache/src/services/view-syncer/client-handler.js +71 -24
  547. package/out/zero-cache/src/services/view-syncer/client-handler.js.map +1 -1
  548. package/out/zero-cache/src/services/view-syncer/client-schema.js +46 -6
  549. package/out/zero-cache/src/services/view-syncer/client-schema.js.map +1 -1
  550. package/out/zero-cache/src/services/view-syncer/connection-context-manager.js.map +1 -1
  551. package/out/zero-cache/src/services/view-syncer/cvr-purger.js +2 -2
  552. package/out/zero-cache/src/services/view-syncer/cvr-purger.js.map +1 -1
  553. package/out/zero-cache/src/services/view-syncer/cvr-store.js +12 -7
  554. package/out/zero-cache/src/services/view-syncer/cvr-store.js.map +1 -1
  555. package/out/zero-cache/src/services/view-syncer/cvr.js +12 -4
  556. package/out/zero-cache/src/services/view-syncer/cvr.js.map +1 -1
  557. package/out/zero-cache/src/services/view-syncer/deferred-writes-budget.js +1 -1
  558. package/out/zero-cache/src/services/view-syncer/deferred-writes-budget.js.map +1 -1
  559. package/out/zero-cache/src/services/view-syncer/drain-coordinator.js +2 -2
  560. package/out/zero-cache/src/services/view-syncer/drain-coordinator.js.map +1 -1
  561. package/out/zero-cache/src/services/view-syncer/e2e-serving-lag.js.map +1 -1
  562. package/out/zero-cache/src/services/view-syncer/hydration-budget.js.map +1 -1
  563. package/out/zero-cache/src/services/view-syncer/hydration-circuit-breaker.js +2 -2
  564. package/out/zero-cache/src/services/view-syncer/hydration-circuit-breaker.js.map +1 -1
  565. package/out/zero-cache/src/services/view-syncer/inspect-handler.js +6 -4
  566. package/out/zero-cache/src/services/view-syncer/inspect-handler.js.map +1 -1
  567. package/out/zero-cache/src/services/view-syncer/pipeline-driver.js +13 -10
  568. package/out/zero-cache/src/services/view-syncer/pipeline-driver.js.map +1 -1
  569. package/out/zero-cache/src/services/view-syncer/plan-warnings.js.map +1 -1
  570. package/out/zero-cache/src/services/view-syncer/push-cost.js.map +1 -1
  571. package/out/zero-cache/src/services/view-syncer/push-cutoff.js.map +1 -1
  572. package/out/zero-cache/src/services/view-syncer/query-covering.js.map +1 -1
  573. package/out/zero-cache/src/services/view-syncer/query-shape.js.map +1 -1
  574. package/out/zero-cache/src/services/view-syncer/query-stats.js +1 -1
  575. package/out/zero-cache/src/services/view-syncer/query-stats.js.map +1 -1
  576. package/out/zero-cache/src/services/view-syncer/row-record-cache.js +2 -2
  577. package/out/zero-cache/src/services/view-syncer/row-record-cache.js.map +1 -1
  578. package/out/zero-cache/src/services/view-syncer/schema/cvr.js.map +1 -1
  579. package/out/zero-cache/src/services/view-syncer/schema/types.js +2 -16
  580. package/out/zero-cache/src/services/view-syncer/schema/types.js.map +1 -1
  581. package/out/zero-cache/src/services/view-syncer/snapshot-row-cache.js +7 -1
  582. package/out/zero-cache/src/services/view-syncer/snapshot-row-cache.js.map +1 -1
  583. package/out/zero-cache/src/services/view-syncer/snapshotter.js +12 -8
  584. package/out/zero-cache/src/services/view-syncer/snapshotter.js.map +1 -1
  585. package/out/zero-cache/src/services/view-syncer/ttl-clock.js.map +1 -1
  586. package/out/zero-cache/src/services/view-syncer/view-syncer.js +52 -28
  587. package/out/zero-cache/src/services/view-syncer/view-syncer.js.map +1 -1
  588. package/out/zero-cache/src/types/error-with-level.js.map +1 -1
  589. package/out/zero-cache/src/types/lexi-version.js.map +1 -1
  590. package/out/zero-cache/src/types/lite.d.ts +0 -1
  591. package/out/zero-cache/src/types/lite.d.ts.map +1 -1
  592. package/out/zero-cache/src/types/lite.js +1 -1
  593. package/out/zero-cache/src/types/lite.js.map +1 -1
  594. package/out/zero-cache/src/types/pg-data-type.js +1 -1
  595. package/out/zero-cache/src/types/pg-data-type.js.map +1 -1
  596. package/out/zero-cache/src/types/pg-types.d.ts +0 -40
  597. package/out/zero-cache/src/types/pg-types.d.ts.map +1 -1
  598. package/out/zero-cache/src/types/pg-types.js.map +1 -1
  599. package/out/zero-cache/src/types/pg.js +6 -4
  600. package/out/zero-cache/src/types/pg.js.map +1 -1
  601. package/out/zero-cache/src/types/poke-chunk.d.ts +0 -1
  602. package/out/zero-cache/src/types/poke-chunk.d.ts.map +1 -1
  603. package/out/zero-cache/src/types/poke-chunk.js +1 -1
  604. package/out/zero-cache/src/types/poke-chunk.js.map +1 -1
  605. package/out/zero-cache/src/types/processes.js +1 -1
  606. package/out/zero-cache/src/types/processes.js.map +1 -1
  607. package/out/zero-cache/src/types/profiler.js +1 -1
  608. package/out/zero-cache/src/types/profiler.js.map +1 -1
  609. package/out/zero-cache/src/types/row-key.d.ts +0 -5
  610. package/out/zero-cache/src/types/row-key.d.ts.map +1 -1
  611. package/out/zero-cache/src/types/row-key.js.map +1 -1
  612. package/out/zero-cache/src/types/sql.js.map +1 -1
  613. package/out/zero-cache/src/types/streams.d.ts.map +1 -1
  614. package/out/zero-cache/src/types/streams.js +11 -10
  615. package/out/zero-cache/src/types/streams.js.map +1 -1
  616. package/out/zero-cache/src/types/strings.js.map +1 -1
  617. package/out/zero-cache/src/types/subscription.js +1 -1
  618. package/out/zero-cache/src/types/subscription.js.map +1 -1
  619. package/out/zero-cache/src/types/timeout.js +1 -1
  620. package/out/zero-cache/src/types/websocket-handoff.d.ts +4 -7
  621. package/out/zero-cache/src/types/websocket-handoff.d.ts.map +1 -1
  622. package/out/zero-cache/src/types/websocket-handoff.js +16 -2
  623. package/out/zero-cache/src/types/websocket-handoff.js.map +1 -1
  624. package/out/zero-cache/src/types/ws.d.ts +2 -1
  625. package/out/zero-cache/src/types/ws.d.ts.map +1 -1
  626. package/out/zero-cache/src/types/ws.js.map +1 -1
  627. package/out/zero-cache/src/workers/connection.d.ts +1 -2
  628. package/out/zero-cache/src/workers/connection.d.ts.map +1 -1
  629. package/out/zero-cache/src/workers/connection.js +5 -3
  630. package/out/zero-cache/src/workers/connection.js.map +1 -1
  631. package/out/zero-cache/src/workers/mutator.js +1 -1
  632. package/out/zero-cache/src/workers/mutator.js.map +1 -1
  633. package/out/zero-cache/src/workers/rehome.d.ts +15 -0
  634. package/out/zero-cache/src/workers/rehome.d.ts.map +1 -0
  635. package/out/zero-cache/src/workers/rehome.js +36 -0
  636. package/out/zero-cache/src/workers/rehome.js.map +1 -0
  637. package/out/zero-cache/src/workers/replicator.js +5 -4
  638. package/out/zero-cache/src/workers/replicator.js.map +1 -1
  639. package/out/zero-cache/src/workers/syncer-ws-message-handler.js +9 -1
  640. package/out/zero-cache/src/workers/syncer-ws-message-handler.js.map +1 -1
  641. package/out/zero-cache/src/workers/syncer.js +30 -5
  642. package/out/zero-cache/src/workers/syncer.js.map +1 -1
  643. package/out/zero-client/src/client/active-clients-manager.d.ts.map +1 -1
  644. package/out/zero-client/src/client/active-clients-manager.js +2 -2
  645. package/out/zero-client/src/client/active-clients-manager.js.map +1 -1
  646. package/out/zero-client/src/client/bindings.js +11 -11
  647. package/out/zero-client/src/client/connection-manager.js +1 -1
  648. package/out/zero-client/src/client/connection-manager.js.map +1 -1
  649. package/out/zero-client/src/client/connection.js +1 -1
  650. package/out/zero-client/src/client/connection.js.map +1 -1
  651. package/out/zero-client/src/client/context.js.map +1 -1
  652. package/out/zero-client/src/client/crud-impl.js +1 -1
  653. package/out/zero-client/src/client/crud-impl.js.map +1 -1
  654. package/out/zero-client/src/client/crud.d.ts +2 -8
  655. package/out/zero-client/src/client/crud.d.ts.map +1 -1
  656. package/out/zero-client/src/client/crud.js.map +1 -1
  657. package/out/zero-client/src/client/custom.d.ts +0 -2
  658. package/out/zero-client/src/client/custom.d.ts.map +1 -1
  659. package/out/zero-client/src/client/custom.js.map +1 -1
  660. package/out/zero-client/src/client/delete-clients-manager.js.map +1 -1
  661. package/out/zero-client/src/client/enable-analytics.d.ts +0 -1
  662. package/out/zero-client/src/client/enable-analytics.d.ts.map +1 -1
  663. package/out/zero-client/src/client/enable-analytics.js +1 -0
  664. package/out/zero-client/src/client/enable-analytics.js.map +1 -1
  665. package/out/zero-client/src/client/error.d.ts +4 -5
  666. package/out/zero-client/src/client/error.d.ts.map +1 -1
  667. package/out/zero-client/src/client/error.js.map +1 -1
  668. package/out/zero-client/src/client/inspector/client-group.js.map +1 -1
  669. package/out/zero-client/src/client/inspector/client.js.map +1 -1
  670. package/out/zero-client/src/client/inspector/html-dialog-prompt.js +1 -1
  671. package/out/zero-client/src/client/inspector/html-dialog-prompt.js.map +1 -1
  672. package/out/zero-client/src/client/inspector/inspector.js.map +1 -1
  673. package/out/zero-client/src/client/inspector/lazy-inspector.js.map +1 -1
  674. package/out/zero-client/src/client/inspector/query.js.map +1 -1
  675. package/out/zero-client/src/client/ivm-branch.js +1 -3
  676. package/out/zero-client/src/client/ivm-branch.js.map +1 -1
  677. package/out/zero-client/src/client/keys.d.ts +0 -1
  678. package/out/zero-client/src/client/keys.d.ts.map +1 -1
  679. package/out/zero-client/src/client/keys.js +6 -3
  680. package/out/zero-client/src/client/keys.js.map +1 -1
  681. package/out/zero-client/src/client/log-options.js.map +1 -1
  682. package/out/zero-client/src/client/make-replicache-mutators.js +5 -3
  683. package/out/zero-client/src/client/make-replicache-mutators.js.map +1 -1
  684. package/out/zero-client/src/client/metrics.js +3 -5
  685. package/out/zero-client/src/client/metrics.js.map +1 -1
  686. package/out/zero-client/src/client/mutation-tracker.d.ts.map +1 -1
  687. package/out/zero-client/src/client/mutation-tracker.js +1 -1
  688. package/out/zero-client/src/client/mutation-tracker.js.map +1 -1
  689. package/out/zero-client/src/client/mutator-proxy.js.map +1 -1
  690. package/out/zero-client/src/client/options.d.ts +0 -4
  691. package/out/zero-client/src/client/options.d.ts.map +1 -1
  692. package/out/zero-client/src/client/options.js.map +1 -1
  693. package/out/zero-client/src/client/query-manager.js +2 -2
  694. package/out/zero-client/src/client/query-manager.js.map +1 -1
  695. package/out/zero-client/src/client/reload-error-handler.js +4 -3
  696. package/out/zero-client/src/client/reload-error-handler.js.map +1 -1
  697. package/out/zero-client/src/client/replicache-types.d.ts +3 -2
  698. package/out/zero-client/src/client/replicache-types.d.ts.map +1 -1
  699. package/out/zero-client/src/client/version.js +1 -1
  700. package/out/zero-client/src/client/zero-poke-handler.d.ts +1 -2
  701. package/out/zero-client/src/client/zero-poke-handler.d.ts.map +1 -1
  702. package/out/zero-client/src/client/zero-poke-handler.js +1 -1
  703. package/out/zero-client/src/client/zero-poke-handler.js.map +1 -1
  704. package/out/zero-client/src/client/zero-rep.js.map +1 -1
  705. package/out/zero-client/src/client/zero.d.ts +1 -5
  706. package/out/zero-client/src/client/zero.d.ts.map +1 -1
  707. package/out/zero-client/src/client/zero.js +20 -12
  708. package/out/zero-client/src/client/zero.js.map +1 -1
  709. package/out/zero-client/src/mod.js +23 -23
  710. package/out/zero-client/src/types/client-state.d.ts +0 -6
  711. package/out/zero-client/src/types/client-state.d.ts.map +1 -1
  712. package/out/zero-client/src/util/nanoid.js.map +1 -1
  713. package/out/zero-permissions/src/permissions.d.ts +1 -12
  714. package/out/zero-permissions/src/permissions.d.ts.map +1 -1
  715. package/out/zero-permissions/src/permissions.js +3 -3
  716. package/out/zero-permissions/src/permissions.js.map +1 -1
  717. package/out/zero-pg/src/mod.js +9 -9
  718. package/out/zero-protocol/src/analyze-query-result.js +1 -1
  719. package/out/zero-protocol/src/analyze-query-result.js.map +1 -1
  720. package/out/zero-protocol/src/application-error.js.map +1 -1
  721. package/out/zero-protocol/src/ast.d.ts +0 -4
  722. package/out/zero-protocol/src/ast.d.ts.map +1 -1
  723. package/out/zero-protocol/src/ast.js +21 -11
  724. package/out/zero-protocol/src/ast.js.map +1 -1
  725. package/out/zero-protocol/src/change-desired-queries.d.ts +0 -20
  726. package/out/zero-protocol/src/change-desired-queries.d.ts.map +1 -1
  727. package/out/zero-protocol/src/change-desired-queries.js.map +1 -1
  728. package/out/zero-protocol/src/client-schema.d.ts +2 -5
  729. package/out/zero-protocol/src/client-schema.d.ts.map +1 -1
  730. package/out/zero-protocol/src/client-schema.js.map +1 -1
  731. package/out/zero-protocol/src/close-connection.d.ts +0 -8
  732. package/out/zero-protocol/src/close-connection.d.ts.map +1 -1
  733. package/out/zero-protocol/src/close-connection.js.map +1 -1
  734. package/out/zero-protocol/src/connect.d.ts +0 -12
  735. package/out/zero-protocol/src/connect.d.ts.map +1 -1
  736. package/out/zero-protocol/src/connect.js.map +1 -1
  737. package/out/zero-protocol/src/custom-queries.d.ts +3 -17
  738. package/out/zero-protocol/src/custom-queries.d.ts.map +1 -1
  739. package/out/zero-protocol/src/custom-queries.js.map +1 -1
  740. package/out/zero-protocol/src/data.d.ts +0 -1
  741. package/out/zero-protocol/src/data.d.ts.map +1 -1
  742. package/out/zero-protocol/src/data.js +3 -1
  743. package/out/zero-protocol/src/data.js.map +1 -1
  744. package/out/zero-protocol/src/delete-clients.js.map +1 -1
  745. package/out/zero-protocol/src/down.d.ts +2 -2
  746. package/out/zero-protocol/src/down.js.map +1 -1
  747. package/out/zero-protocol/src/error.js.map +1 -1
  748. package/out/zero-protocol/src/inspect-down.d.ts +82 -84
  749. package/out/zero-protocol/src/inspect-down.d.ts.map +1 -1
  750. package/out/zero-protocol/src/inspect-down.js.map +1 -1
  751. package/out/zero-protocol/src/inspect-up.d.ts +0 -28
  752. package/out/zero-protocol/src/inspect-up.d.ts.map +1 -1
  753. package/out/zero-protocol/src/inspect-up.js.map +1 -1
  754. package/out/zero-protocol/src/mutate-server.d.ts +0 -21
  755. package/out/zero-protocol/src/mutate-server.d.ts.map +1 -1
  756. package/out/zero-protocol/src/mutate-server.js.map +1 -1
  757. package/out/zero-protocol/src/mutation-id.js.map +1 -1
  758. package/out/zero-protocol/src/mutation-type-enum.d.ts +0 -1
  759. package/out/zero-protocol/src/mutation-type-enum.d.ts.map +1 -1
  760. package/out/zero-protocol/src/mutation-type-enum.js.map +1 -1
  761. package/out/zero-protocol/src/mutation.d.ts +2 -4
  762. package/out/zero-protocol/src/mutation.d.ts.map +1 -1
  763. package/out/zero-protocol/src/mutation.js.map +1 -1
  764. package/out/zero-protocol/src/mutations-patch.d.ts +0 -33
  765. package/out/zero-protocol/src/mutations-patch.d.ts.map +1 -1
  766. package/out/zero-protocol/src/mutations-patch.js.map +1 -1
  767. package/out/zero-protocol/src/ping.d.ts +0 -2
  768. package/out/zero-protocol/src/ping.d.ts.map +1 -1
  769. package/out/zero-protocol/src/ping.js.map +1 -1
  770. package/out/zero-protocol/src/poke.d.ts +3 -2
  771. package/out/zero-protocol/src/poke.d.ts.map +1 -1
  772. package/out/zero-protocol/src/poke.js +1 -1
  773. package/out/zero-protocol/src/poke.js.map +1 -1
  774. package/out/zero-protocol/src/pong.d.ts +0 -2
  775. package/out/zero-protocol/src/pong.d.ts.map +1 -1
  776. package/out/zero-protocol/src/pong.js.map +1 -1
  777. package/out/zero-protocol/src/primary-key.js.map +1 -1
  778. package/out/zero-protocol/src/protocol-version.js +1 -0
  779. package/out/zero-protocol/src/protocol-version.js.map +1 -1
  780. package/out/zero-protocol/src/pull.d.ts +2 -7
  781. package/out/zero-protocol/src/pull.d.ts.map +1 -1
  782. package/out/zero-protocol/src/pull.js.map +1 -1
  783. package/out/zero-protocol/src/push.d.ts +1 -3
  784. package/out/zero-protocol/src/push.d.ts.map +1 -1
  785. package/out/zero-protocol/src/push.js.map +1 -1
  786. package/out/zero-protocol/src/queries-patch.d.ts +0 -16
  787. package/out/zero-protocol/src/queries-patch.d.ts.map +1 -1
  788. package/out/zero-protocol/src/queries-patch.js +1 -1
  789. package/out/zero-protocol/src/queries-patch.js.map +1 -1
  790. package/out/zero-protocol/src/query-hash-visitor.js.map +1 -1
  791. package/out/zero-protocol/src/query-hash.js +2 -2
  792. package/out/zero-protocol/src/query-server.d.ts +2 -41
  793. package/out/zero-protocol/src/query-server.d.ts.map +1 -1
  794. package/out/zero-protocol/src/query-server.js.map +1 -1
  795. package/out/zero-protocol/src/row-patch.js.map +1 -1
  796. package/out/zero-protocol/src/up.d.ts +60 -60
  797. package/out/zero-protocol/src/up.js +1 -1
  798. package/out/zero-protocol/src/up.js.map +1 -1
  799. package/out/zero-protocol/src/update-auth.js.map +1 -1
  800. package/out/zero-protocol/src/version.d.ts +0 -1
  801. package/out/zero-protocol/src/version.d.ts.map +1 -1
  802. package/out/zero-protocol/src/version.js.map +1 -1
  803. package/out/zero-react/src/bindings.js +11 -11
  804. package/out/zero-react/src/mod.js +5 -5
  805. package/out/zero-react/src/use-query.js +2 -2
  806. package/out/zero-react/src/use-query.js.map +1 -1
  807. package/out/zero-react/src/zero-provider.d.ts +1 -1
  808. package/out/zero-react/src/zero-provider.d.ts.map +1 -1
  809. package/out/zero-react/src/zero-provider.js +2 -1
  810. package/out/zero-react/src/zero-provider.js.map +1 -1
  811. package/out/zero-react/src/zero.js +23 -23
  812. package/out/zero-schema/src/builder/relationship-builder.d.ts +0 -2
  813. package/out/zero-schema/src/builder/relationship-builder.d.ts.map +1 -1
  814. package/out/zero-schema/src/builder/relationship-builder.js.map +1 -1
  815. package/out/zero-schema/src/builder/schema-builder.js +3 -2
  816. package/out/zero-schema/src/builder/schema-builder.js.map +1 -1
  817. package/out/zero-schema/src/builder/table-builder.d.ts +1 -1
  818. package/out/zero-schema/src/builder/table-builder.d.ts.map +1 -1
  819. package/out/zero-schema/src/builder/table-builder.js +1 -1
  820. package/out/zero-schema/src/builder/table-builder.js.map +1 -1
  821. package/out/zero-schema/src/compiled-permissions.js.map +1 -1
  822. package/out/zero-schema/src/name-mapper.js +7 -5
  823. package/out/zero-schema/src/name-mapper.js.map +1 -1
  824. package/out/zero-schema/src/schema-config.d.ts +0 -1
  825. package/out/zero-schema/src/schema-config.d.ts.map +1 -1
  826. package/out/zero-schema/src/schema-config.js +1 -1
  827. package/out/zero-schema/src/schema-config.js.map +1 -1
  828. package/out/zero-schema/src/table-schema.d.ts +3 -11
  829. package/out/zero-schema/src/table-schema.d.ts.map +1 -1
  830. package/out/zero-server/src/adapters/drizzle.js.map +1 -1
  831. package/out/zero-server/src/adapters/kysely.js.map +1 -1
  832. package/out/zero-server/src/adapters/pg.js.map +1 -1
  833. package/out/zero-server/src/adapters/postgresjs.js.map +1 -1
  834. package/out/zero-server/src/adapters/prisma.js.map +1 -1
  835. package/out/zero-server/src/closable-db-transaction.js.map +1 -1
  836. package/out/zero-server/src/custom.js +1 -1
  837. package/out/zero-server/src/custom.js.map +1 -1
  838. package/out/zero-server/src/mod.js +8 -8
  839. package/out/zero-server/src/process-mutations.js.map +1 -1
  840. package/out/zero-server/src/push-processor.js.map +1 -1
  841. package/out/zero-server/src/queries/process-queries.d.ts +2 -4
  842. package/out/zero-server/src/queries/process-queries.d.ts.map +1 -1
  843. package/out/zero-server/src/queries/process-queries.js +2 -1
  844. package/out/zero-server/src/queries/process-queries.js.map +1 -1
  845. package/out/zero-server/src/schema.js +7 -7
  846. package/out/zero-server/src/schema.js.map +1 -1
  847. package/out/zero-server/src/zql-database.js.map +1 -1
  848. package/out/zero-solid/src/bindings.js +11 -11
  849. package/out/zero-solid/src/mod.js +5 -5
  850. package/out/zero-solid/src/solid-view.d.ts +0 -2
  851. package/out/zero-solid/src/solid-view.d.ts.map +1 -1
  852. package/out/zero-solid/src/solid-view.js +1 -1
  853. package/out/zero-solid/src/solid-view.js.map +1 -1
  854. package/out/zero-solid/src/use-connection-state.js +2 -1
  855. package/out/zero-solid/src/use-connection-state.js.map +1 -1
  856. package/out/zero-solid/src/use-query.js.map +1 -1
  857. package/out/zero-solid/src/use-zero-online.js +2 -1
  858. package/out/zero-solid/src/use-zero-online.js.map +1 -1
  859. package/out/zero-solid/src/use-zero.js +3 -2
  860. package/out/zero-solid/src/use-zero.js.map +1 -1
  861. package/out/zero-solid/src/zero.js +23 -23
  862. package/out/zero-types/src/name-mapper.d.ts +2 -1
  863. package/out/zero-types/src/name-mapper.d.ts.map +1 -1
  864. package/out/zero-types/src/name-mapper.js.map +1 -1
  865. package/out/zero-types/src/schema-value.d.ts +3 -2
  866. package/out/zero-types/src/schema-value.d.ts.map +1 -1
  867. package/out/zero-types/src/schema.d.ts +1 -1
  868. package/out/zero-types/src/schema.d.ts.map +1 -1
  869. package/out/zql/src/builder/builder.d.ts +1 -11
  870. package/out/zql/src/builder/builder.d.ts.map +1 -1
  871. package/out/zql/src/builder/builder.js +15 -13
  872. package/out/zql/src/builder/builder.js.map +1 -1
  873. package/out/zql/src/builder/correlated-predicate-pushdown.js.map +1 -1
  874. package/out/zql/src/builder/debug-delegate.js.map +1 -1
  875. package/out/zql/src/builder/filter.d.ts +0 -1
  876. package/out/zql/src/builder/filter.d.ts.map +1 -1
  877. package/out/zql/src/builder/filter.js.map +1 -1
  878. package/out/zql/src/builder/like.js +0 -1
  879. package/out/zql/src/builder/like.js.map +1 -1
  880. package/out/zql/src/error.d.ts +0 -5
  881. package/out/zql/src/error.d.ts.map +1 -1
  882. package/out/zql/src/error.js.map +1 -1
  883. package/out/zql/src/ivm/array-view.js.map +1 -1
  884. package/out/zql/src/ivm/cap.d.ts +1 -1
  885. package/out/zql/src/ivm/cap.d.ts.map +1 -1
  886. package/out/zql/src/ivm/cap.js +12 -4
  887. package/out/zql/src/ivm/cap.js.map +1 -1
  888. package/out/zql/src/ivm/constraint.d.ts +0 -7
  889. package/out/zql/src/ivm/constraint.d.ts.map +1 -1
  890. package/out/zql/src/ivm/constraint.js +1 -1
  891. package/out/zql/src/ivm/constraint.js.map +1 -1
  892. package/out/zql/src/ivm/data.d.ts +15 -2
  893. package/out/zql/src/ivm/data.d.ts.map +1 -1
  894. package/out/zql/src/ivm/data.js +15 -1
  895. package/out/zql/src/ivm/data.js.map +1 -1
  896. package/out/zql/src/ivm/deferred-input.js.map +1 -1
  897. package/out/zql/src/ivm/exists.d.ts.map +1 -1
  898. package/out/zql/src/ivm/exists.js +32 -22
  899. package/out/zql/src/ivm/exists.js.map +1 -1
  900. package/out/zql/src/ivm/fan-in.js.map +1 -1
  901. package/out/zql/src/ivm/fan-out.js.map +1 -1
  902. package/out/zql/src/ivm/filter-operators.d.ts +5 -0
  903. package/out/zql/src/ivm/filter-operators.d.ts.map +1 -1
  904. package/out/zql/src/ivm/filter-operators.js +1 -1
  905. package/out/zql/src/ivm/filter-operators.js.map +1 -1
  906. package/out/zql/src/ivm/filter-push.js.map +1 -1
  907. package/out/zql/src/ivm/filter.js.map +1 -1
  908. package/out/zql/src/ivm/flipped-join.js +1 -3
  909. package/out/zql/src/ivm/flipped-join.js.map +1 -1
  910. package/out/zql/src/ivm/join-index-tap.js.map +1 -1
  911. package/out/zql/src/ivm/join-index.js.map +1 -1
  912. package/out/zql/src/ivm/join-utils.js +11 -13
  913. package/out/zql/src/ivm/join-utils.js.map +1 -1
  914. package/out/zql/src/ivm/join.d.ts.map +1 -1
  915. package/out/zql/src/ivm/join.js +6 -3
  916. package/out/zql/src/ivm/join.js.map +1 -1
  917. package/out/zql/src/ivm/maybe-split-and-push-edit-change.js.map +1 -1
  918. package/out/zql/src/ivm/memory-source.d.ts +1 -2
  919. package/out/zql/src/ivm/memory-source.d.ts.map +1 -1
  920. package/out/zql/src/ivm/memory-source.js +27 -23
  921. package/out/zql/src/ivm/memory-source.js.map +1 -1
  922. package/out/zql/src/ivm/memory-storage.js.map +1 -1
  923. package/out/zql/src/ivm/operator.d.ts +6 -0
  924. package/out/zql/src/ivm/operator.d.ts.map +1 -1
  925. package/out/zql/src/ivm/operator.js +2 -2
  926. package/out/zql/src/ivm/operator.js.map +1 -1
  927. package/out/zql/src/ivm/push-accumulated.js +0 -1
  928. package/out/zql/src/ivm/push-accumulated.js.map +1 -1
  929. package/out/zql/src/ivm/skip-yields.js.map +1 -1
  930. package/out/zql/src/ivm/skip.js.map +1 -1
  931. package/out/zql/src/ivm/stream.d.ts +0 -1
  932. package/out/zql/src/ivm/stream.d.ts.map +1 -1
  933. package/out/zql/src/ivm/stream.js.map +1 -1
  934. package/out/zql/src/ivm/take-gate.js.map +1 -1
  935. package/out/zql/src/ivm/take.d.ts.map +1 -1
  936. package/out/zql/src/ivm/take.js +7 -8
  937. package/out/zql/src/ivm/take.js.map +1 -1
  938. package/out/zql/src/ivm/union-fan-in.d.ts +0 -1
  939. package/out/zql/src/ivm/union-fan-in.d.ts.map +1 -1
  940. package/out/zql/src/ivm/union-fan-in.js.map +1 -1
  941. package/out/zql/src/ivm/union-fan-out.js.map +1 -1
  942. package/out/zql/src/ivm/view-apply-change.d.ts +5 -35
  943. package/out/zql/src/ivm/view-apply-change.d.ts.map +1 -1
  944. package/out/zql/src/ivm/view-apply-change.js.map +1 -1
  945. package/out/zql/src/mutate/crud.d.ts +1 -3
  946. package/out/zql/src/mutate/crud.d.ts.map +1 -1
  947. package/out/zql/src/mutate/crud.js +2 -1
  948. package/out/zql/src/mutate/crud.js.map +1 -1
  949. package/out/zql/src/mutate/mutator-registry.d.ts +1 -1
  950. package/out/zql/src/mutate/mutator-registry.d.ts.map +1 -1
  951. package/out/zql/src/mutate/mutator-registry.js.map +1 -1
  952. package/out/zql/src/mutate/mutator.d.ts +1 -1
  953. package/out/zql/src/mutate/mutator.d.ts.map +1 -1
  954. package/out/zql/src/mutate/mutator.js.map +1 -1
  955. package/out/zql/src/planner/planner-builder.js +1 -1
  956. package/out/zql/src/planner/planner-builder.js.map +1 -1
  957. package/out/zql/src/planner/planner-connection.js.map +1 -1
  958. package/out/zql/src/planner/planner-debug.d.ts +10 -9
  959. package/out/zql/src/planner/planner-debug.d.ts.map +1 -1
  960. package/out/zql/src/planner/planner-debug.js.map +1 -1
  961. package/out/zql/src/planner/planner-fan-in.js.map +1 -1
  962. package/out/zql/src/planner/planner-fan-out.js.map +1 -1
  963. package/out/zql/src/planner/planner-filter.js.map +1 -1
  964. package/out/zql/src/planner/planner-graph.js +1 -5
  965. package/out/zql/src/planner/planner-graph.js.map +1 -1
  966. package/out/zql/src/planner/planner-join.js +1 -1
  967. package/out/zql/src/planner/planner-join.js.map +1 -1
  968. package/out/zql/src/planner/planner-node.d.ts +0 -1
  969. package/out/zql/src/planner/planner-node.d.ts.map +1 -1
  970. package/out/zql/src/planner/planner-node.js.map +1 -1
  971. package/out/zql/src/planner/planner-source.js.map +1 -1
  972. package/out/zql/src/planner/planner-terminus.js.map +1 -1
  973. package/out/zql/src/planner/planner-warnings.d.ts +3 -3
  974. package/out/zql/src/planner/planner-warnings.d.ts.map +1 -1
  975. package/out/zql/src/planner/planner-warnings.js.map +1 -1
  976. package/out/zql/src/query/create-builder.js +2 -1
  977. package/out/zql/src/query/create-builder.js.map +1 -1
  978. package/out/zql/src/query/expression.d.ts +0 -22
  979. package/out/zql/src/query/expression.d.ts.map +1 -1
  980. package/out/zql/src/query/expression.js +1 -1
  981. package/out/zql/src/query/expression.js.map +1 -1
  982. package/out/zql/src/query/measure-push-operator.js.map +1 -1
  983. package/out/zql/src/query/named.js +2 -1
  984. package/out/zql/src/query/named.js.map +1 -1
  985. package/out/zql/src/query/query-delegate-base.d.ts +0 -7
  986. package/out/zql/src/query/query-delegate-base.d.ts.map +1 -1
  987. package/out/zql/src/query/query-delegate-base.js +1 -1
  988. package/out/zql/src/query/query-delegate-base.js.map +1 -1
  989. package/out/zql/src/query/query-delegate.d.ts +1 -4
  990. package/out/zql/src/query/query-delegate.d.ts.map +1 -1
  991. package/out/zql/src/query/query-impl.js +3 -2
  992. package/out/zql/src/query/query-impl.js.map +1 -1
  993. package/out/zql/src/query/query-internals.d.ts +0 -3
  994. package/out/zql/src/query/query-internals.d.ts.map +1 -1
  995. package/out/zql/src/query/query-internals.js.map +1 -1
  996. package/out/zql/src/query/query-registry.d.ts +5 -5
  997. package/out/zql/src/query/query-registry.d.ts.map +1 -1
  998. package/out/zql/src/query/query-registry.js +1 -1
  999. package/out/zql/src/query/query-registry.js.map +1 -1
  1000. package/out/zql/src/query/query-transitions.js +1 -1
  1001. package/out/zql/src/query/query-transitions.js.map +1 -1
  1002. package/out/zql/src/query/query.d.ts +2 -13
  1003. package/out/zql/src/query/query.d.ts.map +1 -1
  1004. package/out/zql/src/query/runnable-query-impl.d.ts +1 -19
  1005. package/out/zql/src/query/runnable-query-impl.d.ts.map +1 -1
  1006. package/out/zql/src/query/runnable-query-impl.js +2 -1
  1007. package/out/zql/src/query/runnable-query-impl.js.map +1 -1
  1008. package/out/zql/src/query/static-query.js.map +1 -1
  1009. package/out/zql/src/query/ttl.d.ts +2 -3
  1010. package/out/zql/src/query/ttl.d.ts.map +1 -1
  1011. package/out/zql/src/query/ttl.js +8 -8
  1012. package/out/zql/src/query/ttl.js.map +1 -1
  1013. package/out/zql/src/query/validate-input.js.map +1 -1
  1014. package/out/zqlite/src/database-storage.js +195 -26
  1015. package/out/zqlite/src/database-storage.js.map +1 -1
  1016. package/out/zqlite/src/db.d.ts +47 -1
  1017. package/out/zqlite/src/db.d.ts.map +1 -1
  1018. package/out/zqlite/src/db.js +121 -21
  1019. package/out/zqlite/src/db.js.map +1 -1
  1020. package/out/zqlite/src/explain-queries.js.map +1 -1
  1021. package/out/zqlite/src/fetch-sql.d.ts +27 -0
  1022. package/out/zqlite/src/fetch-sql.d.ts.map +1 -0
  1023. package/out/zqlite/src/fetch-sql.js +112 -0
  1024. package/out/zqlite/src/fetch-sql.js.map +1 -0
  1025. package/out/zqlite/src/index-usage.js.map +1 -1
  1026. package/out/zqlite/src/internal/sql-inline.js.map +1 -1
  1027. package/out/zqlite/src/internal/sql.js.map +1 -1
  1028. package/out/zqlite/src/internal/statement-cache.d.ts +7 -0
  1029. package/out/zqlite/src/internal/statement-cache.d.ts.map +1 -1
  1030. package/out/zqlite/src/internal/statement-cache.js +11 -4
  1031. package/out/zqlite/src/internal/statement-cache.js.map +1 -1
  1032. package/out/zqlite/src/mod.js +5 -5
  1033. package/out/zqlite/src/pending-delta.js.map +1 -1
  1034. package/out/zqlite/src/query-builder.d.ts +11 -3
  1035. package/out/zqlite/src/query-builder.d.ts.map +1 -1
  1036. package/out/zqlite/src/query-builder.js +22 -7
  1037. package/out/zqlite/src/query-builder.js.map +1 -1
  1038. package/out/zqlite/src/query-delegate.js.map +1 -1
  1039. package/out/zqlite/src/resolve-scalar-subqueries.js +2 -5
  1040. package/out/zqlite/src/resolve-scalar-subqueries.js.map +1 -1
  1041. package/out/zqlite/src/sqlite-cost-model.js +3 -2
  1042. package/out/zqlite/src/sqlite-cost-model.js.map +1 -1
  1043. package/out/zqlite/src/sqlite-stat-fanout.js.map +1 -1
  1044. package/out/zqlite/src/table-source.d.ts +20 -3
  1045. package/out/zqlite/src/table-source.d.ts.map +1 -1
  1046. package/out/zqlite/src/table-source.js +74 -40
  1047. package/out/zqlite/src/table-source.js.map +1 -1
  1048. package/package.json +39 -39
  1049. package/out/analyze-query/src/bin-analyze.d.ts +0 -2
  1050. package/out/analyze-query/src/bin-analyze.d.ts.map +0 -1
  1051. package/out/analyze-query/src/bin-analyze.js +0 -283
  1052. package/out/analyze-query/src/bin-analyze.js.map +0 -1
  1053. package/out/otel/src/maybe-time.d.ts +0 -3
  1054. package/out/otel/src/maybe-time.d.ts.map +0 -1
  1055. package/out/otel/src/maybe-time.js +0 -15
  1056. package/out/otel/src/maybe-time.js.map +0 -1
  1057. package/out/shared/src/cache.d.ts +0 -22
  1058. package/out/shared/src/cache.d.ts.map +0 -1
  1059. package/out/shared/src/custom-key-map.d.ts +0 -26
  1060. package/out/shared/src/custom-key-map.d.ts.map +0 -1
  1061. package/out/shared/src/custom-key-set.d.ts +0 -25
  1062. package/out/shared/src/custom-key-set.d.ts.map +0 -1
  1063. package/out/shared/src/logging-test-utils.d.ts +0 -12
  1064. package/out/shared/src/logging-test-utils.d.ts.map +0 -1
  1065. package/out/shared/src/sorted-entries.d.ts +0 -2
  1066. package/out/shared/src/sorted-entries.d.ts.map +0 -1
  1067. package/out/zero/src/analyze-query.d.ts +0 -3
  1068. package/out/zero/src/analyze-query.d.ts.map +0 -1
  1069. package/out/zero/src/analyze-query.js +0 -3
  1070. package/out/zero/src/server/change-streamer.d.ts +0 -2
  1071. package/out/zero/src/server/change-streamer.d.ts.map +0 -1
  1072. package/out/zero/src/server/main.d.ts +0 -2
  1073. package/out/zero/src/server/main.d.ts.map +0 -1
  1074. package/out/zero/src/server/reaper.d.ts +0 -2
  1075. package/out/zero/src/server/reaper.d.ts.map +0 -1
  1076. package/out/zero/src/server/replicator.d.ts +0 -2
  1077. package/out/zero/src/server/replicator.d.ts.map +0 -1
  1078. package/out/zero/src/server/syncer.d.ts +0 -2
  1079. package/out/zero/src/server/syncer.d.ts.map +0 -1
  1080. package/out/zero-cache/src/auth/jwt.d.ts +0 -12
  1081. package/out/zero-cache/src/auth/jwt.d.ts.map +0 -1
  1082. package/out/zero-cache/src/auth/load-permissions.d.ts +0 -17
  1083. package/out/zero-cache/src/auth/load-permissions.d.ts.map +0 -1
  1084. package/out/zero-cache/src/auth/write-authorizer.d.ts +0 -28
  1085. package/out/zero-cache/src/auth/write-authorizer.d.ts.map +0 -1
  1086. package/out/zero-cache/src/config/server-context.d.ts +0 -16
  1087. package/out/zero-cache/src/config/server-context.d.ts.map +0 -1
  1088. package/out/zero-cache/src/custom/fetch.d.ts +0 -38
  1089. package/out/zero-cache/src/custom/fetch.d.ts.map +0 -1
  1090. package/out/zero-cache/src/custom/metrics.d.ts +0 -31
  1091. package/out/zero-cache/src/custom/metrics.d.ts.map +0 -1
  1092. package/out/zero-cache/src/custom-queries/transform-query.d.ts +0 -68
  1093. package/out/zero-cache/src/custom-queries/transform-query.d.ts.map +0 -1
  1094. package/out/zero-cache/src/db/create.d.ts +0 -12
  1095. package/out/zero-cache/src/db/create.d.ts.map +0 -1
  1096. package/out/zero-cache/src/db/delete-lite-db.d.ts +0 -2
  1097. package/out/zero-cache/src/db/delete-lite-db.d.ts.map +0 -1
  1098. package/out/zero-cache/src/db/index-predicate.d.ts +0 -4
  1099. package/out/zero-cache/src/db/index-predicate.d.ts.map +0 -1
  1100. package/out/zero-cache/src/db/migration-lite.d.ts +0 -78
  1101. package/out/zero-cache/src/db/migration-lite.d.ts.map +0 -1
  1102. package/out/zero-cache/src/db/migration.d.ts +0 -80
  1103. package/out/zero-cache/src/db/migration.d.ts.map +0 -1
  1104. package/out/zero-cache/src/db/pg-copy-binary.d.ts +0 -101
  1105. package/out/zero-cache/src/db/pg-copy-binary.d.ts.map +0 -1
  1106. package/out/zero-cache/src/db/pg-copy.d.ts +0 -30
  1107. package/out/zero-cache/src/db/pg-copy.d.ts.map +0 -1
  1108. package/out/zero-cache/src/db/pg-type-parser.d.ts +0 -15
  1109. package/out/zero-cache/src/db/pg-type-parser.d.ts.map +0 -1
  1110. package/out/zero-cache/src/db/transaction-pool.d.ts +0 -205
  1111. package/out/zero-cache/src/db/transaction-pool.d.ts.map +0 -1
  1112. package/out/zero-cache/src/db/warmup.d.ts +0 -4
  1113. package/out/zero-cache/src/db/warmup.d.ts.map +0 -1
  1114. package/out/zero-cache/src/observability/events.d.ts +0 -15
  1115. package/out/zero-cache/src/observability/events.d.ts.map +0 -1
  1116. package/out/zero-cache/src/observability/log-throttle.d.ts +0 -44
  1117. package/out/zero-cache/src/observability/log-throttle.d.ts.map +0 -1
  1118. package/out/zero-cache/src/server/anonymous-otel-start.d.ts +0 -21
  1119. package/out/zero-cache/src/server/anonymous-otel-start.d.ts.map +0 -1
  1120. package/out/zero-cache/src/server/change-streamer.d.ts +0 -3
  1121. package/out/zero-cache/src/server/change-streamer.d.ts.map +0 -1
  1122. package/out/zero-cache/src/server/inspector-delegate.d.ts +0 -71
  1123. package/out/zero-cache/src/server/inspector-delegate.d.ts.map +0 -1
  1124. package/out/zero-cache/src/server/main.d.ts +0 -3
  1125. package/out/zero-cache/src/server/main.d.ts.map +0 -1
  1126. package/out/zero-cache/src/server/otel-diag-logger.d.ts +0 -16
  1127. package/out/zero-cache/src/server/otel-diag-logger.d.ts.map +0 -1
  1128. package/out/zero-cache/src/server/otel-start.d.ts +0 -3
  1129. package/out/zero-cache/src/server/otel-start.d.ts.map +0 -1
  1130. package/out/zero-cache/src/server/priority-op.d.ts +0 -8
  1131. package/out/zero-cache/src/server/priority-op.d.ts.map +0 -1
  1132. package/out/zero-cache/src/server/reaper.d.ts +0 -3
  1133. package/out/zero-cache/src/server/reaper.d.ts.map +0 -1
  1134. package/out/zero-cache/src/server/replicator.d.ts +0 -10
  1135. package/out/zero-cache/src/server/replicator.d.ts.map +0 -1
  1136. package/out/zero-cache/src/server/slot-keeper.d.ts +0 -26
  1137. package/out/zero-cache/src/server/slot-keeper.d.ts.map +0 -1
  1138. package/out/zero-cache/src/server/syncer.d.ts +0 -3
  1139. package/out/zero-cache/src/server/syncer.d.ts.map +0 -1
  1140. package/out/zero-cache/src/services/analyze.d.ts +0 -9
  1141. package/out/zero-cache/src/services/analyze.d.ts.map +0 -1
  1142. package/out/zero-cache/src/services/change-source/change-source.d.ts +0 -32
  1143. package/out/zero-cache/src/services/change-source/change-source.d.ts.map +0 -1
  1144. package/out/zero-cache/src/services/change-source/common/backfill-manager.d.ts +0 -57
  1145. package/out/zero-cache/src/services/change-source/common/backfill-manager.d.ts.map +0 -1
  1146. package/out/zero-cache/src/services/change-source/common/change-stream-multiplexer.d.ts +0 -55
  1147. package/out/zero-cache/src/services/change-source/common/change-stream-multiplexer.d.ts.map +0 -1
  1148. package/out/zero-cache/src/services/change-source/common/init-cleanup.d.ts +0 -24
  1149. package/out/zero-cache/src/services/change-source/common/init-cleanup.d.ts.map +0 -1
  1150. package/out/zero-cache/src/services/change-source/common/replica-restore.d.ts +0 -115
  1151. package/out/zero-cache/src/services/change-source/common/replica-restore.d.ts.map +0 -1
  1152. package/out/zero-cache/src/services/change-source/common/replica-schema.d.ts +0 -14
  1153. package/out/zero-cache/src/services/change-source/common/replica-schema.d.ts.map +0 -1
  1154. package/out/zero-cache/src/services/change-source/custom/change-source.d.ts +0 -25
  1155. package/out/zero-cache/src/services/change-source/custom/change-source.d.ts.map +0 -1
  1156. package/out/zero-cache/src/services/change-source/pg/backfill-metadata.d.ts +0 -14
  1157. package/out/zero-cache/src/services/change-source/pg/backfill-metadata.d.ts.map +0 -1
  1158. package/out/zero-cache/src/services/change-source/pg/backfill-stream.d.ts +0 -36
  1159. package/out/zero-cache/src/services/change-source/pg/backfill-stream.d.ts.map +0 -1
  1160. package/out/zero-cache/src/services/change-source/pg/change-source-init.d.ts +0 -65
  1161. package/out/zero-cache/src/services/change-source/pg/change-source-init.d.ts.map +0 -1
  1162. package/out/zero-cache/src/services/change-source/pg/change-source.d.ts +0 -115
  1163. package/out/zero-cache/src/services/change-source/pg/change-source.d.ts.map +0 -1
  1164. package/out/zero-cache/src/services/change-source/pg/initial-sync.d.ts +0 -155
  1165. package/out/zero-cache/src/services/change-source/pg/initial-sync.d.ts.map +0 -1
  1166. package/out/zero-cache/src/services/change-source/pg/logical-replication/binary-reader.d.ts +0 -17
  1167. package/out/zero-cache/src/services/change-source/pg/logical-replication/binary-reader.d.ts.map +0 -1
  1168. package/out/zero-cache/src/services/change-source/pg/logical-replication/pgoutput-parser.d.ts +0 -28
  1169. package/out/zero-cache/src/services/change-source/pg/logical-replication/pgoutput-parser.d.ts.map +0 -1
  1170. package/out/zero-cache/src/services/change-source/pg/logical-replication/pgoutput.types.d.ts +0 -76
  1171. package/out/zero-cache/src/services/change-source/pg/logical-replication/pgoutput.types.d.ts.map +0 -1
  1172. package/out/zero-cache/src/services/change-source/pg/logical-replication/stream.d.ts +0 -169
  1173. package/out/zero-cache/src/services/change-source/pg/logical-replication/stream.d.ts.map +0 -1
  1174. package/out/zero-cache/src/services/change-source/pg/replication-slot-cleanup-monitor.d.ts +0 -16
  1175. package/out/zero-cache/src/services/change-source/pg/replication-slot-cleanup-monitor.d.ts.map +0 -1
  1176. package/out/zero-cache/src/services/change-source/pg/replication-slot-health.d.ts +0 -15
  1177. package/out/zero-cache/src/services/change-source/pg/replication-slot-health.d.ts.map +0 -1
  1178. package/out/zero-cache/src/services/change-source/pg/replication-slots.d.ts +0 -127
  1179. package/out/zero-cache/src/services/change-source/pg/replication-slots.d.ts.map +0 -1
  1180. package/out/zero-cache/src/services/change-source/pg/schema/init.d.ts +0 -9
  1181. package/out/zero-cache/src/services/change-source/pg/schema/init.d.ts.map +0 -1
  1182. package/out/zero-cache/src/services/change-source/protocol/backfill-progress.d.ts +0 -68
  1183. package/out/zero-cache/src/services/change-source/protocol/backfill-progress.d.ts.map +0 -1
  1184. package/out/zero-cache/src/services/change-streamer/backfill-state-tracker.d.ts +0 -72
  1185. package/out/zero-cache/src/services/change-streamer/backfill-state-tracker.d.ts.map +0 -1
  1186. package/out/zero-cache/src/services/change-streamer/backfill-state.d.ts +0 -50
  1187. package/out/zero-cache/src/services/change-streamer/backfill-state.d.ts.map +0 -1
  1188. package/out/zero-cache/src/services/change-streamer/backup-cleanup-monitor-factory.d.ts +0 -14
  1189. package/out/zero-cache/src/services/change-streamer/backup-cleanup-monitor-factory.d.ts.map +0 -1
  1190. package/out/zero-cache/src/services/change-streamer/backup-monitor.d.ts +0 -18
  1191. package/out/zero-cache/src/services/change-streamer/backup-monitor.d.ts.map +0 -1
  1192. package/out/zero-cache/src/services/change-streamer/broadcast.d.ts +0 -98
  1193. package/out/zero-cache/src/services/change-streamer/broadcast.d.ts.map +0 -1
  1194. package/out/zero-cache/src/services/change-streamer/change-log-codec.d.ts +0 -34
  1195. package/out/zero-cache/src/services/change-streamer/change-log-codec.d.ts.map +0 -1
  1196. package/out/zero-cache/src/services/change-streamer/change-log-compare-digest.d.ts +0 -34
  1197. package/out/zero-cache/src/services/change-streamer/change-log-compare-digest.d.ts.map +0 -1
  1198. package/out/zero-cache/src/services/change-streamer/change-log-initializer.d.ts +0 -158
  1199. package/out/zero-cache/src/services/change-streamer/change-log-initializer.d.ts.map +0 -1
  1200. package/out/zero-cache/src/services/change-streamer/change-log-transaction-hash.d.ts +0 -19
  1201. package/out/zero-cache/src/services/change-streamer/change-log-transaction-hash.d.ts.map +0 -1
  1202. package/out/zero-cache/src/services/change-streamer/change-streamer-http.d.ts +0 -78
  1203. package/out/zero-cache/src/services/change-streamer/change-streamer-http.d.ts.map +0 -1
  1204. package/out/zero-cache/src/services/change-streamer/change-streamer-service.d.ts +0 -139
  1205. package/out/zero-cache/src/services/change-streamer/change-streamer-service.d.ts.map +0 -1
  1206. package/out/zero-cache/src/services/change-streamer/change-streamer.d.ts +0 -586
  1207. package/out/zero-cache/src/services/change-streamer/change-streamer.d.ts.map +0 -1
  1208. package/out/zero-cache/src/services/change-streamer/drain-tracker.d.ts +0 -24
  1209. package/out/zero-cache/src/services/change-streamer/drain-tracker.d.ts.map +0 -1
  1210. package/out/zero-cache/src/services/change-streamer/error-type-enum.d.ts +0 -15
  1211. package/out/zero-cache/src/services/change-streamer/error-type-enum.d.ts.map +0 -1
  1212. package/out/zero-cache/src/services/change-streamer/forwarder.d.ts +0 -49
  1213. package/out/zero-cache/src/services/change-streamer/forwarder.d.ts.map +0 -1
  1214. package/out/zero-cache/src/services/change-streamer/litestream-sync-requester.d.ts +0 -53
  1215. package/out/zero-cache/src/services/change-streamer/litestream-sync-requester.d.ts.map +0 -1
  1216. package/out/zero-cache/src/services/change-streamer/litestream3-prometheus-poller.d.ts +0 -88
  1217. package/out/zero-cache/src/services/change-streamer/litestream3-prometheus-poller.d.ts.map +0 -1
  1218. package/out/zero-cache/src/services/change-streamer/replica-poller.d.ts +0 -15
  1219. package/out/zero-cache/src/services/change-streamer/replica-poller.d.ts.map +0 -1
  1220. package/out/zero-cache/src/services/change-streamer/restore-admission.d.ts +0 -243
  1221. package/out/zero-cache/src/services/change-streamer/restore-admission.d.ts.map +0 -1
  1222. package/out/zero-cache/src/services/change-streamer/schema/init.d.ts +0 -6
  1223. package/out/zero-cache/src/services/change-streamer/schema/init.d.ts.map +0 -1
  1224. package/out/zero-cache/src/services/change-streamer/schema/tables.d.ts +0 -152
  1225. package/out/zero-cache/src/services/change-streamer/schema/tables.d.ts.map +0 -1
  1226. package/out/zero-cache/src/services/change-streamer/shard-sampling.d.ts +0 -11
  1227. package/out/zero-cache/src/services/change-streamer/shard-sampling.d.ts.map +0 -1
  1228. package/out/zero-cache/src/services/change-streamer/snapshot-message.d.ts +0 -92
  1229. package/out/zero-cache/src/services/change-streamer/snapshot-message.d.ts.map +0 -1
  1230. package/out/zero-cache/src/services/change-streamer/snapshot-reservations.d.ts +0 -36
  1231. package/out/zero-cache/src/services/change-streamer/snapshot-reservations.d.ts.map +0 -1
  1232. package/out/zero-cache/src/services/change-streamer/snapshot.d.ts +0 -22
  1233. package/out/zero-cache/src/services/change-streamer/snapshot.d.ts.map +0 -1
  1234. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-catchup.d.ts +0 -99
  1235. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-catchup.d.ts.map +0 -1
  1236. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-comparator.d.ts +0 -83
  1237. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-comparator.d.ts.map +0 -1
  1238. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-purge-scheduler.d.ts +0 -121
  1239. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-purge-scheduler.d.ts.map +0 -1
  1240. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-read-router.d.ts +0 -73
  1241. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-read-router.d.ts.map +0 -1
  1242. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-reader.d.ts +0 -62
  1243. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-reader.d.ts.map +0 -1
  1244. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-writer.d.ts +0 -114
  1245. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-writer.d.ts.map +0 -1
  1246. package/out/zero-cache/src/services/change-streamer/storer.d.ts +0 -276
  1247. package/out/zero-cache/src/services/change-streamer/storer.d.ts.map +0 -1
  1248. package/out/zero-cache/src/services/change-streamer/subscribe.d.ts +0 -485
  1249. package/out/zero-cache/src/services/change-streamer/subscribe.d.ts.map +0 -1
  1250. package/out/zero-cache/src/services/change-streamer/subscriber.d.ts +0 -194
  1251. package/out/zero-cache/src/services/change-streamer/subscriber.d.ts.map +0 -1
  1252. package/out/zero-cache/src/services/change-streamer/upstream-acker.d.ts +0 -52
  1253. package/out/zero-cache/src/services/change-streamer/upstream-acker.d.ts.map +0 -1
  1254. package/out/zero-cache/src/services/limiter/sliding-window-limiter.d.ts +0 -57
  1255. package/out/zero-cache/src/services/limiter/sliding-window-limiter.d.ts.map +0 -1
  1256. package/out/zero-cache/src/services/litestream/commands.d.ts +0 -77
  1257. package/out/zero-cache/src/services/litestream/commands.d.ts.map +0 -1
  1258. package/out/zero-cache/src/services/litestream/litestream-controller.d.ts +0 -78
  1259. package/out/zero-cache/src/services/litestream/litestream-controller.d.ts.map +0 -1
  1260. package/out/zero-cache/src/services/litestream/metrics.d.ts +0 -31
  1261. package/out/zero-cache/src/services/litestream/metrics.d.ts.map +0 -1
  1262. package/out/zero-cache/src/services/litestream/restore-progress.d.ts +0 -24
  1263. package/out/zero-cache/src/services/litestream/restore-progress.d.ts.map +0 -1
  1264. package/out/zero-cache/src/services/mutagen/mutagen.d.ts +0 -40
  1265. package/out/zero-cache/src/services/mutagen/mutagen.d.ts.map +0 -1
  1266. package/out/zero-cache/src/services/mutagen/pusher.d.ts +0 -63
  1267. package/out/zero-cache/src/services/mutagen/pusher.d.ts.map +0 -1
  1268. package/out/zero-cache/src/services/replicator/change-log-db.d.ts +0 -368
  1269. package/out/zero-cache/src/services/replicator/change-log-db.d.ts.map +0 -1
  1270. package/out/zero-cache/src/services/replicator/change-log-stream-writer.d.ts +0 -56
  1271. package/out/zero-cache/src/services/replicator/change-log-stream-writer.d.ts.map +0 -1
  1272. package/out/zero-cache/src/services/replicator/change-processor.d.ts +0 -37
  1273. package/out/zero-cache/src/services/replicator/change-processor.d.ts.map +0 -1
  1274. package/out/zero-cache/src/services/replicator/drain-handler.d.ts +0 -82
  1275. package/out/zero-cache/src/services/replicator/drain-handler.d.ts.map +0 -1
  1276. package/out/zero-cache/src/services/replicator/incremental-sync.d.ts +0 -25
  1277. package/out/zero-cache/src/services/replicator/incremental-sync.d.ts.map +0 -1
  1278. package/out/zero-cache/src/services/replicator/notifier.d.ts +0 -9
  1279. package/out/zero-cache/src/services/replicator/notifier.d.ts.map +0 -1
  1280. package/out/zero-cache/src/services/replicator/replication-status.d.ts +0 -71
  1281. package/out/zero-cache/src/services/replicator/replication-status.d.ts.map +0 -1
  1282. package/out/zero-cache/src/services/replicator/replicator.d.ts +0 -86
  1283. package/out/zero-cache/src/services/replicator/replicator.d.ts.map +0 -1
  1284. package/out/zero-cache/src/services/replicator/reporter/recorder.d.ts +0 -55
  1285. package/out/zero-cache/src/services/replicator/reporter/recorder.d.ts.map +0 -1
  1286. package/out/zero-cache/src/services/replicator/sqlite-change-log-observability.d.ts +0 -132
  1287. package/out/zero-cache/src/services/replicator/sqlite-change-log-observability.d.ts.map +0 -1
  1288. package/out/zero-cache/src/services/replicator/sqlite-change-log-purger.d.ts +0 -120
  1289. package/out/zero-cache/src/services/replicator/sqlite-change-log-purger.d.ts.map +0 -1
  1290. package/out/zero-cache/src/services/replicator/write-worker-client.d.ts +0 -111
  1291. package/out/zero-cache/src/services/replicator/write-worker-client.d.ts.map +0 -1
  1292. package/out/zero-cache/src/services/run-ast.d.ts +0 -39
  1293. package/out/zero-cache/src/services/run-ast.d.ts.map +0 -1
  1294. package/out/zero-cache/src/services/runner.d.ts +0 -19
  1295. package/out/zero-cache/src/services/runner.d.ts.map +0 -1
  1296. package/out/zero-cache/src/services/view-syncer/active-users-gauge.d.ts +0 -17
  1297. package/out/zero-cache/src/services/view-syncer/active-users-gauge.d.ts.map +0 -1
  1298. package/out/zero-cache/src/services/view-syncer/advancement-metrics.d.ts +0 -26
  1299. package/out/zero-cache/src/services/view-syncer/advancement-metrics.d.ts.map +0 -1
  1300. package/out/zero-cache/src/services/view-syncer/batch-pacer.d.ts +0 -79
  1301. package/out/zero-cache/src/services/view-syncer/batch-pacer.d.ts.map +0 -1
  1302. package/out/zero-cache/src/services/view-syncer/client-handler.d.ts +0 -79
  1303. package/out/zero-cache/src/services/view-syncer/client-handler.d.ts.map +0 -1
  1304. package/out/zero-cache/src/services/view-syncer/client-schema.d.ts +0 -5
  1305. package/out/zero-cache/src/services/view-syncer/client-schema.d.ts.map +0 -1
  1306. package/out/zero-cache/src/services/view-syncer/connection-context-manager.d.ts +0 -184
  1307. package/out/zero-cache/src/services/view-syncer/connection-context-manager.d.ts.map +0 -1
  1308. package/out/zero-cache/src/services/view-syncer/cvr-purger.d.ts +0 -22
  1309. package/out/zero-cache/src/services/view-syncer/cvr-purger.d.ts.map +0 -1
  1310. package/out/zero-cache/src/services/view-syncer/cvr-store.d.ts +0 -128
  1311. package/out/zero-cache/src/services/view-syncer/cvr-store.d.ts.map +0 -1
  1312. package/out/zero-cache/src/services/view-syncer/cvr.d.ts +0 -294
  1313. package/out/zero-cache/src/services/view-syncer/cvr.d.ts.map +0 -1
  1314. package/out/zero-cache/src/services/view-syncer/deferred-writes-budget.d.ts +0 -81
  1315. package/out/zero-cache/src/services/view-syncer/deferred-writes-budget.d.ts.map +0 -1
  1316. package/out/zero-cache/src/services/view-syncer/drain-coordinator.d.ts +0 -45
  1317. package/out/zero-cache/src/services/view-syncer/drain-coordinator.d.ts.map +0 -1
  1318. package/out/zero-cache/src/services/view-syncer/e2e-serving-lag.d.ts +0 -53
  1319. package/out/zero-cache/src/services/view-syncer/e2e-serving-lag.d.ts.map +0 -1
  1320. package/out/zero-cache/src/services/view-syncer/hydration-budget.d.ts +0 -33
  1321. package/out/zero-cache/src/services/view-syncer/hydration-budget.d.ts.map +0 -1
  1322. package/out/zero-cache/src/services/view-syncer/hydration-circuit-breaker.d.ts +0 -51
  1323. package/out/zero-cache/src/services/view-syncer/hydration-circuit-breaker.d.ts.map +0 -1
  1324. package/out/zero-cache/src/services/view-syncer/inspect-handler.d.ts +0 -34
  1325. package/out/zero-cache/src/services/view-syncer/inspect-handler.d.ts.map +0 -1
  1326. package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts +0 -296
  1327. package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts.map +0 -1
  1328. package/out/zero-cache/src/services/view-syncer/plan-warnings.d.ts +0 -7
  1329. package/out/zero-cache/src/services/view-syncer/plan-warnings.d.ts.map +0 -1
  1330. package/out/zero-cache/src/services/view-syncer/push-cost.d.ts +0 -132
  1331. package/out/zero-cache/src/services/view-syncer/push-cost.d.ts.map +0 -1
  1332. package/out/zero-cache/src/services/view-syncer/push-cutoff.d.ts +0 -55
  1333. package/out/zero-cache/src/services/view-syncer/push-cutoff.d.ts.map +0 -1
  1334. package/out/zero-cache/src/services/view-syncer/query-covering.d.ts +0 -28
  1335. package/out/zero-cache/src/services/view-syncer/query-covering.d.ts.map +0 -1
  1336. package/out/zero-cache/src/services/view-syncer/query-shape.d.ts +0 -25
  1337. package/out/zero-cache/src/services/view-syncer/query-shape.d.ts.map +0 -1
  1338. package/out/zero-cache/src/services/view-syncer/query-stats.d.ts +0 -89
  1339. package/out/zero-cache/src/services/view-syncer/query-stats.d.ts.map +0 -1
  1340. package/out/zero-cache/src/services/view-syncer/row-record-cache.d.ts +0 -90
  1341. package/out/zero-cache/src/services/view-syncer/row-record-cache.d.ts.map +0 -1
  1342. package/out/zero-cache/src/services/view-syncer/row-set-signature.d.ts +0 -17
  1343. package/out/zero-cache/src/services/view-syncer/row-set-signature.d.ts.map +0 -1
  1344. package/out/zero-cache/src/services/view-syncer/schema/cvr.d.ts +0 -86
  1345. package/out/zero-cache/src/services/view-syncer/schema/cvr.d.ts.map +0 -1
  1346. package/out/zero-cache/src/services/view-syncer/schema/init.d.ts +0 -5
  1347. package/out/zero-cache/src/services/view-syncer/schema/init.d.ts.map +0 -1
  1348. package/out/zero-cache/src/services/view-syncer/schema/types.d.ts +0 -563
  1349. package/out/zero-cache/src/services/view-syncer/schema/types.d.ts.map +0 -1
  1350. package/out/zero-cache/src/services/view-syncer/snapshot-row-cache.d.ts +0 -95
  1351. package/out/zero-cache/src/services/view-syncer/snapshot-row-cache.d.ts.map +0 -1
  1352. package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts +0 -412
  1353. package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts.map +0 -1
  1354. package/out/zero-cache/src/services/view-syncer/tracer.d.ts +0 -2
  1355. package/out/zero-cache/src/services/view-syncer/tracer.d.ts.map +0 -1
  1356. package/out/zero-cache/src/services/view-syncer/ttl-clock.d.ts +0 -10
  1357. package/out/zero-cache/src/services/view-syncer/ttl-clock.d.ts.map +0 -1
  1358. package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts +0 -133
  1359. package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts.map +0 -1
  1360. package/out/zero-cache/src/types/pg-patch.d.ts +0 -21
  1361. package/out/zero-cache/src/types/pg-patch.d.ts.map +0 -1
  1362. package/out/zero-cache/src/types/pg-versions.d.ts +0 -3
  1363. package/out/zero-cache/src/types/pg-versions.d.ts.map +0 -1
  1364. package/out/zero-cache/src/workers/replicator.d.ts +0 -57
  1365. package/out/zero-cache/src/workers/replicator.d.ts.map +0 -1
  1366. package/out/zero-cache/src/workers/syncer-ws-message-handler.d.ts +0 -14
  1367. package/out/zero-cache/src/workers/syncer-ws-message-handler.d.ts.map +0 -1
  1368. package/out/zero-cache/src/workers/syncer.d.ts +0 -67
  1369. package/out/zero-cache/src/workers/syncer.d.ts.map +0 -1
  1370. package/out/zero-events/src/index.d.ts +0 -27
  1371. package/out/zero-events/src/index.d.ts.map +0 -1
  1372. package/out/zero-events/src/json.d.ts +0 -20
  1373. package/out/zero-events/src/json.d.ts.map +0 -1
  1374. package/out/zero-events/src/status.d.ts +0 -144
  1375. package/out/zero-events/src/status.d.ts.map +0 -1
  1376. package/out/zqlite/src/database-storage.d.ts +0 -24
  1377. package/out/zqlite/src/database-storage.d.ts.map +0 -1
  1378. package/out/zqlite/src/explain-queries.d.ts +0 -4
  1379. package/out/zqlite/src/explain-queries.d.ts.map +0 -1
  1380. package/out/zqlite/src/internal/sql-inline.d.ts +0 -13
  1381. package/out/zqlite/src/internal/sql-inline.d.ts.map +0 -1
  1382. package/out/zqlite/src/resolve-scalar-subqueries.d.ts +0 -72
  1383. package/out/zqlite/src/resolve-scalar-subqueries.d.ts.map +0 -1
  1384. package/out/zqlite/src/sqlite-cost-model.d.ts +0 -17
  1385. package/out/zqlite/src/sqlite-cost-model.d.ts.map +0 -1
  1386. package/out/zqlite/src/sqlite-stat-fanout.d.ts +0 -121
  1387. package/out/zqlite/src/sqlite-stat-fanout.d.ts.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"change-processor.js","names":["#db","#changeLog","#tableMetadata","#backfilling","#mode","#failService","#tableSpecs","#failure","#currentTx","#fail","#processMessage","#beginTransaction","#lc","#startMs","#version","#jsonFormat","#columnMetadata","#reloadTableSpecs","#tableSpec","#upsert","#getKey","#logSetOp","#logDeleteOp","#delete","#logTruncateOp","#logResetOp","#bumpVersions","#pos","#numChangeLogEntries","#schemaChanged","#trackBackfillProgress","#completedBackfill"],"sources":["../../../../../../zero-cache/src/services/replicator/change-processor.ts"],"sourcesContent":["import {constants as bufferConstants} from 'node:buffer';\nimport type {LogContext} from '@rocicorp/logger';\nimport {SqliteError} from '@rocicorp/zero-sqlite3';\nimport {AbortError} from '../../../../shared/src/abort-error.ts';\nimport {assert, unreachable} from '../../../../shared/src/asserts.ts';\nimport {stringify} from '../../../../shared/src/bigint-json.ts';\nimport {deepEqual} from '../../../../shared/src/json.ts';\nimport {must} from '../../../../shared/src/must.ts';\nimport {mapEntries} from '../../../../shared/src/objects.ts';\nimport type {DownloadStatus} from '../../../../zero-events/src/status.ts';\nimport {\n createLiteIndexStatement,\n createLiteTableStatement,\n liteColumnDef,\n} from '../../db/create.ts';\nimport {\n computeZqlSpecs,\n listTables,\n type LiteTableSpecWithReplicationStatus,\n} from '../../db/lite-tables.ts';\nimport {\n isArrayColumn,\n isEnumColumn,\n mapPostgresToLite,\n mapPostgresToLiteColumn,\n mapPostgresToLiteIndex,\n} from '../../db/pg-to-lite.ts';\nimport type {ColumnSpec} from '../../db/specs.ts';\nimport type {StatementRunner} from '../../db/statements.ts';\nimport type {LexiVersion} from '../../types/lexi-version.ts';\nimport {\n JSON_PARSED,\n liteRow,\n type JSONFormat,\n type LiteRow,\n type LiteRowKey,\n type LiteValueType,\n} from '../../types/lite.ts';\nimport {liteTableName} from '../../types/names.ts';\nimport {id} from '../../types/sql.ts';\nimport {\n acceptBackfill,\n type AcceptResult,\n} from '../change-source/protocol/backfill-progress.ts';\nimport type {\n BackfillCompleted,\n BackfillProgressMark,\n Change,\n ColumnAdd,\n ColumnDrop,\n ColumnUpdate,\n Identifier,\n IndexCreate,\n IndexDrop,\n MessageBackfill,\n MessageCommit,\n MessageDelete,\n MessageInsert,\n MessageRelation,\n MessageTruncate,\n MessageUpdate,\n TableCreate,\n TableDrop,\n TableRename,\n TableUpdateMetadata,\n} from '../change-source/protocol/current/data.ts';\nimport type {ChangeStreamData} from '../change-source/protocol/current/downstream.ts';\nimport type {ReplicatorMode} from './replicator.ts';\nimport {BackfillingTracker} from './schema/backfilling.ts';\nimport {ChangeLog, DEL_OP, SET_OP} from './schema/change-log.ts';\nimport {ColumnMetadataStore} from './schema/column-metadata.ts';\nimport {\n ZERO_VERSION_COLUMN_NAME,\n updateReplicationWatermark,\n} from './schema/replication-state.ts';\nimport {TableMetadataTracker} from './schema/table-metadata.ts';\n\nexport type ChangeProcessorMode = ReplicatorMode | 'initial-sync';\n\nconst BIND_VALUE_TOO_BIG_ERROR =\n 'The bound string, buffer, or bigint is too big';\nconst MAX_SQLITE_BIND_BYTES = Math.min(\n bufferConstants.MAX_LENGTH,\n bufferConstants.MAX_STRING_LENGTH,\n);\n\nexport type CommitResult = {\n watermark: string;\n completedBackfill: DownloadStatus | undefined;\n schemaUpdated: boolean;\n changeLogUpdated: boolean;\n /**\n * Millisecond epoch at which the transaction committed upstream, if the\n * ChangeSource reported one. Propagated to ViewSyncers as the origin\n * timestamp of the end-to-end serving lag measurement.\n */\n upstreamCommitTimeMs?: number | undefined;\n};\n\n/**\n * The ChangeProcessor partitions the stream of messages into transactions\n * by creating a {@link TransactionProcessor} when a transaction begins, and dispatching\n * messages to it until the commit is received.\n *\n * From https://www.postgresql.org/docs/current/protocol-logical-replication.html#PROTOCOL-LOGICAL-MESSAGES-FLOW :\n *\n * \"The logical replication protocol sends individual transactions one by one.\n * This means that all messages between a pair of Begin and Commit messages\n * belong to the same transaction.\"\n */\nexport class ChangeProcessor {\n readonly #db: StatementRunner;\n readonly #changeLog: ChangeLog;\n readonly #tableMetadata: TableMetadataTracker;\n readonly #backfilling: BackfillingTracker;\n readonly #mode: ChangeProcessorMode;\n readonly #failService: (lc: LogContext, err: unknown) => void;\n\n // The TransactionProcessor lazily loads table specs into this Map,\n // and reloads them after a schema change. It is cached here to avoid\n // reading them from the DB on every transaction.\n readonly #tableSpecs = new Map<string, LiteTableSpecWithReplicationStatus>();\n\n #currentTx: TransactionProcessor | null = null;\n\n #failure: Error | undefined;\n\n constructor(\n db: StatementRunner,\n mode: ChangeProcessorMode,\n failService: (lc: LogContext, err: unknown) => void,\n ) {\n this.#db = db;\n this.#changeLog = new ChangeLog(db.db);\n this.#tableMetadata = new TableMetadataTracker(db.db);\n this.#backfilling = new BackfillingTracker(db.db);\n this.#mode = mode;\n this.#failService = failService;\n }\n\n #fail(lc: LogContext, err: unknown) {\n if (!this.#failure) {\n let failureError = err;\n const rollbackErrors = [attempt(() => this.#currentTx?.abort(lc))].filter(\n e => e !== undefined,\n );\n\n if (rollbackErrors.length) {\n const combinedError = new Error(\n `Message processing failed and rollback also failed: operation error = ${String(err)}; rollback error = ${rollbackErrors.map(String).join('; ')}`,\n );\n combinedError.cause = err;\n failureError = combinedError;\n }\n\n this.#failure = ensureError(failureError);\n\n if (!(this.#failure instanceof AbortError)) {\n // Propagate the failure up to the service.\n lc.error?.('Message Processing failed:', this.#failure);\n this.#failService(lc, this.#failure);\n }\n }\n }\n\n abort(lc: LogContext) {\n this.#fail(lc, new AbortError());\n }\n\n /** @return If a transaction was committed. */\n processMessage(\n lc: LogContext,\n downstream: ChangeStreamData,\n ): CommitResult | null {\n const [type, message] = downstream;\n if (this.#failure) {\n lc.debug?.(`Dropping ${message.tag}`);\n return null;\n }\n try {\n const watermark =\n type === 'begin'\n ? downstream[2].commitWatermark\n : type === 'commit'\n ? downstream[2].watermark\n : undefined;\n return this.#processMessage(lc, message, watermark);\n } catch (e) {\n this.#fail(lc, e);\n }\n return null;\n }\n\n #beginTransaction(\n lc: LogContext,\n commitVersion: string,\n jsonFormat: JSONFormat,\n ): TransactionProcessor {\n const start = Date.now();\n\n // litestream can technically hold the lock for an arbitrary amount of time\n // when checkpointing a large commit. Crashing on the busy-timeout in this\n // scenario will either produce a corrupt backup or otherwise prevent\n // replication from proceeding.\n //\n // Instead, retry the lock acquisition indefinitely. If this masks\n // an unknown deadlock situation, manual intervention will be necessary.\n for (let i = 0; ; i++) {\n try {\n return new TransactionProcessor(\n lc,\n this.#db,\n this.#mode,\n this.#changeLog,\n this.#tableMetadata,\n this.#backfilling,\n this.#tableSpecs,\n commitVersion,\n jsonFormat,\n );\n } catch (e) {\n if (e instanceof SqliteError && e.code === 'SQLITE_BUSY') {\n lc.warn?.(\n `SQLITE_BUSY for ${Date.now() - start} ms (attempt ${i + 1}). ` +\n `This is only expected if litestream is performing a large ` +\n `checkpoint.`,\n e,\n );\n continue;\n }\n throw e;\n }\n }\n }\n\n /** @return If a transaction was committed. */\n #processMessage(\n lc: LogContext,\n msg: Change,\n watermark: string | undefined,\n ): CommitResult | null {\n if (msg.tag === 'begin') {\n if (this.#currentTx) {\n throw new Error(`Already in a transaction ${stringify(msg)}`);\n }\n this.#currentTx = this.#beginTransaction(\n lc,\n must(watermark),\n msg.json ?? JSON_PARSED,\n );\n return null;\n }\n\n // For non-begin messages, there should be a #currentTx set.\n const tx = this.#currentTx;\n if (!tx) {\n throw new Error(\n `Received message outside of transaction: ${stringify(msg)}`,\n );\n }\n\n if (msg.tag === 'commit') {\n assert(watermark, 'watermark is required for commit messages');\n const result = tx.processCommit(msg, watermark);\n // Clear only after a successful commit so #fail can roll back a commit\n // path that throws before SQLite has committed.\n this.#currentTx = null;\n return result;\n }\n\n if (msg.tag === 'rollback') {\n tx.abort(lc);\n this.#currentTx = null;\n return null;\n }\n\n switch (msg.tag) {\n case 'insert':\n tx.processInsert(msg);\n break;\n case 'update':\n tx.processUpdate(msg);\n break;\n case 'delete':\n tx.processDelete(msg);\n break;\n case 'truncate':\n tx.processTruncate(msg);\n break;\n case 'create-table':\n tx.processCreateTable(msg);\n break;\n case 'rename-table':\n tx.processRenameTable(msg);\n break;\n case 'update-table-metadata':\n tx.processTableMetadata(msg);\n break;\n case 'add-column':\n tx.processAddColumn(msg);\n break;\n case 'update-column':\n tx.processUpdateColumn(msg);\n break;\n case 'drop-column':\n tx.processDropColumn(msg);\n break;\n case 'drop-table':\n tx.processDropTable(msg);\n break;\n case 'create-index':\n tx.processCreateIndex(msg);\n break;\n case 'drop-index':\n tx.processDropIndex(msg);\n break;\n case 'backfill':\n tx.processBackfill(msg);\n break;\n case 'backfill-completed':\n tx.processBackfillCompleted(msg);\n break;\n default:\n unreachable(msg);\n }\n\n return null;\n }\n}\n\n/**\n * The {@link TransactionProcessor} handles the sequence of messages from\n * upstream, from `BEGIN` to `COMMIT` and executes the corresponding mutations\n * on the {@link postgres.TransactionSql} on the replica.\n *\n * When applying row contents to the replica, the `_0_version` column is added / updated,\n * and a corresponding entry in the `ChangeLog` is added. The version value is derived\n * from the watermark of the preceding transaction (stored as the `nextStateVersion` in the\n * `ReplicationState` table).\n *\n * Side note: For non-streaming Postgres transactions, the commitEndLsn (and thus\n * commit watermark) is available in the `begin` message, so it could theoretically\n * be used for the row version of changes within the transaction. However, the\n * commitEndLsn is not available in the streaming (in-progress) transaction\n * protocol, and may not be available for CDC streams of other upstream types.\n * Therefore, the zero replication protocol is designed to not require the commit\n * watermark when a transaction begins.\n *\n * Also of interest is the fact that all INSERT Messages are logically applied as\n * UPSERTs. See {@link processInsert} for the underlying motivation.\n */\nclass TransactionProcessor {\n readonly #lc: LogContext;\n readonly #startMs: number;\n readonly #db: StatementRunner;\n readonly #mode: ChangeProcessorMode;\n readonly #version: LexiVersion;\n readonly #changeLog: ChangeLog;\n readonly #tableMetadata: TableMetadataTracker;\n readonly #backfilling: BackfillingTracker;\n readonly #tableSpecs: Map<string, LiteTableSpecWithReplicationStatus>;\n readonly #jsonFormat: JSONFormat;\n readonly #columnMetadata: ColumnMetadataStore;\n\n #pos = 0;\n #schemaChanged = false;\n #numChangeLogEntries = 0;\n\n constructor(\n lc: LogContext,\n db: StatementRunner,\n mode: ChangeProcessorMode,\n changeLog: ChangeLog,\n tableMetadata: TableMetadataTracker,\n backfilling: BackfillingTracker,\n tableSpecs: Map<string, LiteTableSpecWithReplicationStatus>,\n commitVersion: LexiVersion,\n jsonFormat: JSONFormat,\n ) {\n this.#startMs = Date.now();\n this.#mode = mode;\n this.#jsonFormat = jsonFormat;\n\n switch (mode) {\n case 'serving':\n // This is the only transaction that commits to the serving replica.\n // Snapshotters use BEGIN CONCURRENT for private changes that are\n // always rolled back, while BEGIN IMMEDIATE lets this writer spill\n // dirty pages during large transactions.\n db.beginImmediate();\n break;\n case 'backup':\n // For the backup-replicator (i.e. replication-manager), there are no View Syncers\n // and thus BEGIN CONCURRENT is not necessary. In fact, BEGIN CONCURRENT can cause\n // deadlocks with forced wal-checkpoints (which `litestream replicate` performs),\n // so it is important to use vanilla transactions in this configuration.\n db.beginImmediate();\n break;\n case 'initial-sync':\n // When the ChangeProcessor is used for initial-sync, the calling code\n // handles the transaction boundaries.\n break;\n default:\n unreachable();\n }\n this.#db = db;\n this.#version = commitVersion;\n this.#lc = lc.withContext('version', commitVersion);\n this.#changeLog = changeLog;\n this.#tableMetadata = tableMetadata;\n this.#backfilling = backfilling;\n this.#tableSpecs = tableSpecs;\n // The column_metadata table is guaranteed to exist since the\n // replica-schema.ts migration to v8.\n this.#columnMetadata = must(ColumnMetadataStore.getInstance(db.db));\n\n if (this.#tableSpecs.size === 0) {\n this.#reloadTableSpecs();\n }\n }\n\n #reloadTableSpecs() {\n this.#tableSpecs.clear();\n // zqlSpecs include the primary key derived from unique indexes\n const zqlSpecs = computeZqlSpecs(this.#lc, this.#db.db, {\n includeBackfillingColumns: true,\n });\n for (let spec of listTables(this.#db.db)) {\n if (!spec.primaryKey) {\n spec = {\n ...spec,\n primaryKey: [\n ...(zqlSpecs.get(spec.name)?.tableSpec.primaryKey ?? []),\n ],\n };\n }\n this.#tableSpecs.set(spec.name, spec);\n }\n }\n\n #tableSpec(name: string) {\n return must(this.#tableSpecs.get(name), `Unknown table ${name}`);\n }\n\n #getKey(\n {row, numCols}: {row: LiteRow; numCols: number},\n {relation}: {relation: MessageRelation},\n ): LiteRowKey {\n const keyColumns =\n relation.rowKey.type !== 'full'\n ? relation.rowKey.columns // already a suitable key\n : this.#tableSpec(liteTableName(relation)).primaryKey;\n if (!keyColumns?.length) {\n throw new Error(\n `Cannot replicate table \"${relation.name}\" without a PRIMARY KEY or UNIQUE INDEX`,\n );\n }\n // For the common case (replica identity default), the row is already the\n // key for deletes and updates, in which case a new object can be avoided.\n if (numCols === keyColumns.length) {\n return row;\n }\n const key: Record<string, LiteValueType> = {};\n for (const col of keyColumns) {\n key[col] = row[col];\n }\n return key;\n }\n\n processInsert(insert: MessageInsert) {\n const table = liteTableName(insert.relation);\n const tableSpec = this.#tableSpec(table);\n const newRow = liteRow(insert.new, tableSpec, this.#jsonFormat);\n\n this.#upsert(table, {\n ...newRow.row,\n [ZERO_VERSION_COLUMN_NAME]: this.#version,\n });\n\n if (insert.relation.rowKey.columns.length === 0) {\n // INSERTs can be replicated for rows without a PRIMARY KEY or a\n // UNIQUE INDEX. These are written to the replica but not recorded\n // in the changeLog, because these rows cannot participate in IVM.\n //\n // (Once the table schema has been corrected to include a key, the\n // associated schema change will reset pipelines and data can be\n // loaded via hydration.)\n return;\n }\n const key = this.#getKey(newRow, insert);\n this.#logSetOp(table, key, getBackfilledColumns(newRow.row, tableSpec));\n }\n\n #upsert(table: string, row: LiteRow) {\n const columns = Object.keys(row).map(c => id(c));\n this.#db.run(\n `\n INSERT OR REPLACE INTO ${id(table)} (${columns.join(',')})\n VALUES (${Array.from({length: columns.length}).fill('?').join(',')})\n `,\n Object.values(row),\n );\n }\n\n // Updates by default are applied as UPDATE commands to support partial\n // row specifications from the change source. In particular, this is needed\n // to handle updates for which unchanged TOASTed values are not sent:\n //\n // https://www.postgresql.org/docs/current/protocol-logicalrep-message-formats.html#PROTOCOL-LOGICALREP-MESSAGE-FORMATS-TUPLEDATA\n //\n // However, in certain cases an UPDATE may be received for a row that\n // was not initially synced, such as when, an existing table is added\n // to the app's publication.\n //\n // In order to facilitate \"resumptive\" replication, the logic falls back to\n // an INSERT if the update did not change any rows.\n processUpdate(update: MessageUpdate) {\n const table = liteTableName(update.relation);\n const tableSpec = this.#tableSpec(table);\n const newRow = liteRow(update.new, tableSpec, this.#jsonFormat);\n const row = {...newRow.row, [ZERO_VERSION_COLUMN_NAME]: this.#version};\n\n // update.key is set with the old values if the key has changed.\n const oldKey = update.key\n ? this.#getKey(\n liteRow(update.key, this.#tableSpec(table), this.#jsonFormat),\n update,\n )\n : null;\n const newKey = this.#getKey(newRow, update);\n\n if (oldKey) {\n this.#logDeleteOp(table, oldKey, tableSpec.backfilling);\n }\n this.#logSetOp(table, newKey, getBackfilledColumns(newRow.row, tableSpec));\n\n const currKey = oldKey ?? newKey;\n const conds = Object.keys(currKey).map(col => `${id(col)}=?`);\n const setExprs = Object.keys(row).map(col => `${id(col)}=?`);\n\n try {\n const {changes} = this.#db.run(\n `\n UPDATE ${id(table)}\n SET ${setExprs.join(',')}\n WHERE ${conds.join(' AND ')}\n `,\n [...Object.values(row), ...Object.values(currKey)],\n );\n\n // If the UPDATE did not affect any rows, perform an UPSERT of the\n // new row for resumptive replication.\n if (changes === 0) {\n this.#upsert(table, row);\n }\n } catch (e) {\n if (\n !(e instanceof RangeError) ||\n e.message !== BIND_VALUE_TOO_BIG_ERROR\n ) {\n throw e;\n }\n\n const binding = [...Object.entries(row), ...Object.entries(currKey)]\n .map(\n ([column, value]) =>\n [column, oversizedValueDescription(value)] as const,\n )\n .find(([, description]) => description);\n const relationOid =\n 'relationOid' in update.relation &&\n typeof update.relation.relationOid === 'number'\n ? ` relationOid=${update.relation.relationOid}`\n : '';\n const error = new Error(\n `Oversized SQLite update binding: tx=${this.#version}${relationOid} table=${update.relation.schema}.${update.relation.name} column=${binding?.[0] ?? 'unknown'}${binding?.[1] ? ` ${binding[1]}` : ''}`,\n {cause: e},\n );\n error.name = 'OversizedUpdateBindingError';\n throw error;\n }\n }\n\n processDelete(del: MessageDelete) {\n const table = liteTableName(del.relation);\n const tableSpec = this.#tableSpec(table);\n const rowKey = this.#getKey(\n liteRow(del.key, tableSpec, this.#jsonFormat),\n del,\n );\n\n this.#delete(table, rowKey);\n this.#logDeleteOp(table, rowKey, tableSpec.backfilling);\n }\n\n #delete(table: string, rowKey: LiteRowKey) {\n const conds = Object.keys(rowKey).map(col => `${id(col)}=?`);\n this.#db.run(\n `DELETE FROM ${id(table)} WHERE ${conds.join(' AND ')}`,\n Object.values(rowKey),\n );\n }\n\n processTruncate(truncate: MessageTruncate) {\n for (const relation of truncate.relations) {\n const table = liteTableName(relation);\n // Update replica data.\n this.#db.run(`DELETE FROM ${id(table)}`);\n\n // Update change log.\n this.#logTruncateOp(table);\n }\n }\n\n processCreateTable(create: TableCreate) {\n if (create.metadata) {\n this.#tableMetadata.setUpstreamMetadata(create.spec, create.metadata);\n }\n this.#backfilling.apply(create);\n const table = mapPostgresToLite(create.spec);\n this.#db.db.exec(createLiteTableStatement(table));\n\n // Write to metadata table\n for (const [colName, colSpec] of Object.entries(create.spec.columns)) {\n this.#columnMetadata.insert(\n table.name,\n colName,\n colSpec,\n create.backfill?.[colName],\n );\n }\n\n this.#logResetOp(table.name);\n this.#lc.info?.(create.tag, table.name);\n }\n\n processTableMetadata(msg: TableUpdateMetadata) {\n this.#tableMetadata.setUpstreamMetadata(msg.table, msg.new);\n // Inert today: the fold's only op for this tag is `upsert-metadata`, which\n // the line above is the replica's interpreter of. Called anyway so that\n // every site that hands a schema change to one cookie tracker hands it to\n // both -- an exception here would be a schema change the shared fold has an\n // opinion about and this store never sees, which is the drift the fold\n // exists to make impossible.\n this.#backfilling.apply(msg);\n }\n\n processRenameTable(rename: TableRename) {\n this.#tableMetadata.rename(rename.old, rename.new);\n this.#backfilling.apply(rename);\n\n const oldName = liteTableName(rename.old);\n const newName = liteTableName(rename.new);\n this.#db.db.exec(`ALTER TABLE ${id(oldName)} RENAME TO ${id(newName)}`);\n\n // Rename in metadata table\n this.#columnMetadata.renameTable(oldName, newName);\n\n this.#bumpVersions(rename.new);\n this.#logResetOp(oldName);\n this.#lc.info?.(rename.tag, oldName, newName);\n }\n\n processAddColumn(msg: ColumnAdd) {\n if (msg.tableMetadata) {\n this.#tableMetadata.setUpstreamMetadata(msg.table, msg.tableMetadata);\n }\n this.#backfilling.apply(msg);\n const table = liteTableName(msg.table);\n const {name} = msg.column;\n const spec = mapPostgresToLiteColumn(table, msg.column);\n this.#db.db.exec(\n `ALTER TABLE ${id(table)} ADD ${id(name)} ${liteColumnDef(spec)}`,\n );\n\n // Write to metadata table\n this.#columnMetadata.insert(table, name, msg.column.spec, msg.backfill);\n\n if (msg.backfill) {\n this.#reloadTableSpecs();\n } else {\n // Make the new column visible immediately if it's not being backfilled.\n // Otherwise, the version bump will happen with the backfill is complete.\n this.#bumpVersions(msg.table);\n }\n this.#lc.info?.(msg.tag, table, msg.column);\n }\n\n processUpdateColumn(msg: ColumnUpdate) {\n // A no-op unless this is a rename, which is the only part of a column\n // update that moves the backfill cookie.\n this.#backfilling.apply(msg);\n\n const table = liteTableName(msg.table);\n let oldName = msg.old.name;\n const newName = msg.new.name;\n\n const storageTypesDiffer = differentStorageTypes(\n msg.old.spec,\n msg.new.spec,\n );\n\n // If neither the column name nor the SQLite data type changes, only the\n // upstream metadata needs to be updated. This includes changes such as a\n // varchar character limit and nullability, which SQLite does not enforce\n // but a freshly built replica still records.\n if (oldName === newName && !storageTypesDiffer) {\n this.#columnMetadata.update(\n table,\n msg.old.name,\n msg.new.name,\n msg.new.spec,\n );\n if (Boolean(msg.old.spec.notNull) !== Boolean(msg.new.spec.notNull)) {\n this.#bumpVersions(msg.table);\n }\n this.#lc.info?.(msg.tag, 'updated metadata only', msg.old, msg.new);\n return;\n }\n // Storage type changes require a new column so that SQLite uses the new\n // representation for existing and future values.\n if (storageTypesDiffer) {\n // update-column can ignore defaults because it does not change the values\n // in existing rows.\n //\n // https://www.postgresql.org/docs/current/sql-altertable.html#SQL-ALTERTABLE-DESC-SET-DROP-DEFAULT\n //\n // \"The new default value will only apply in subsequent INSERT or UPDATE\n // commands; it does not cause rows already in the table to change.\"\n //\n // This allows support for _changing_ column defaults to any expression,\n // since it does not affect what the replica needs to do.\n const newLiteSpec = mapPostgresToLiteColumn(\n table,\n msg.new,\n 'ignore-default',\n );\n if (oldName !== newName) {\n // Rename the column in place first so that SQLite rewrites every\n // reference to it in the table's index definitions, including the\n // WHERE clauses of partial indexes.\n this.#db.db.exec(\n `ALTER TABLE ${id(table)} RENAME ${id(oldName)} TO ${id(newName)}`,\n );\n oldName = newName;\n }\n const tableSpec = must(\n listTables(this.#db.db, false, false).find(\n tableSpec => tableSpec.name === table,\n ),\n );\n // Recreating the table drops its indexes, so capture their DDL to\n // replay afterwards. Auto-indexes (PRIMARY KEY) have no DDL and are\n // recreated by the CREATE TABLE statement itself.\n const indexDDL = this.#db.db\n .prepare(\n `SELECT sql FROM sqlite_master\n WHERE type = 'index' AND tbl_name = ? AND sql IS NOT NULL\n ORDER BY rowid`,\n )\n .all<{sql: string}>(table)\n .map(({sql}) => sql);\n const tmpTable = `tmp.${table}`;\n const columns = Object.keys(tableSpec.columns);\n const stmts = [\n createLiteTableStatement({\n ...tableSpec,\n name: tmpTable,\n columns: mapEntries(tableSpec.columns, (column, spec) => [\n column,\n column === newName ? {...newLiteSpec, pos: spec.pos} : spec,\n ]),\n }),\n `INSERT INTO ${id(tmpTable)} (${columns.map(id).join(',')})\n SELECT ${columns.map(id).join(',')} FROM ${id(table)};`,\n `DROP TABLE ${id(table)};`,\n `ALTER TABLE ${id(tmpTable)} RENAME TO ${id(table)};`,\n ...indexDDL.map(sql => `${sql};`),\n ];\n this.#db.db.exec(stmts.join(''));\n }\n if (oldName !== newName) {\n this.#db.db.exec(\n `ALTER TABLE ${id(table)} RENAME ${id(oldName)} TO ${id(newName)}`,\n );\n }\n\n // Update metadata table\n this.#columnMetadata.update(\n table,\n msg.old.name,\n msg.new.name,\n msg.new.spec,\n );\n\n this.#bumpVersions(msg.table);\n this.#lc.info?.(msg.tag, table, msg.new);\n }\n\n processDropColumn(msg: ColumnDrop) {\n const table = liteTableName(msg.table);\n const {column} = msg;\n this.#db.db.exec(`ALTER TABLE ${id(table)} DROP ${id(column)}`);\n\n // Delete from metadata table\n this.#columnMetadata.deleteColumn(table, column);\n this.#backfilling.apply(msg);\n\n this.#bumpVersions(msg.table);\n this.#lc.info?.(msg.tag, table, column);\n }\n\n processDropTable(drop: TableDrop) {\n this.#tableMetadata.drop(drop.id);\n this.#backfilling.apply(drop);\n\n const name = liteTableName(drop.id);\n this.#db.db.exec(`DROP TABLE IF EXISTS ${id(name)}`);\n\n // Delete from metadata table\n this.#columnMetadata.deleteTable(name);\n\n this.#logResetOp(name);\n this.#lc.info?.(drop.tag, name);\n }\n\n processCreateIndex(create: IndexCreate) {\n const index = mapPostgresToLiteIndex(create.spec);\n this.#db.db.exec(createLiteIndexStatement(index));\n\n // indexes affect tables visibility (e.g. sync-ability is gated on\n // having a unique index), so reset pipelines to refresh table schemas.\n this.#logResetOp(index.tableName);\n this.#lc.info?.(create.tag, index.name);\n }\n\n processDropIndex(drop: IndexDrop) {\n const name = liteTableName(drop.id);\n const indexExisted = this.#db.db\n .prepare(\n `SELECT tbl_name as tableName FROM sqlite_master WHERE type = 'index' AND name = ?`,\n )\n .get(name) as {tableName: string} | undefined;\n\n this.#db.db.exec(`DROP INDEX IF EXISTS ${id(name)}`);\n\n if (indexExisted) {\n // indexes affect tables visibility (e.g. sync-ability is gated on\n // having a unique index), so reset pipelines to refresh table schemas.\n this.#logResetOp(indexExisted.tableName);\n }\n this.#lc.info?.(drop.tag, name);\n }\n\n #bumpVersions(table: Identifier) {\n this.#tableMetadata.setMinRowVersion(table, this.#version);\n this.#logResetOp(liteTableName(table));\n }\n\n /**\n * @param backfilledColumns `backfilling` columns for which values were set\n */\n #logSetOp(\n table: string,\n key: LiteRowKey,\n backfilledColumns: string[] | undefined,\n ) {\n // The \"serving\" replicator always writes to the change-log (for IVM).\n // The \"backup\" replicator only needs to write to the change log\n // when writing columns that are being backfilled.\n if (this.#mode === 'serving' || backfilledColumns !== undefined) {\n this.#changeLog.logSetOp(\n this.#version,\n this.#pos++,\n table,\n key,\n backfilledColumns,\n );\n this.#numChangeLogEntries++;\n }\n }\n\n #logDeleteOp(table: string, key: LiteRowKey, backfilling?: string[]) {\n // The \"serving\" replicator always writes to the change-log (for IVM).\n // The \"backup\" replicator only needs to write to the change log\n // when writing columns that are being backfilled.\n if (this.#mode === 'serving' || backfilling?.length) {\n this.#changeLog.logDeleteOp(this.#version, this.#pos++, table, key);\n this.#numChangeLogEntries++;\n }\n }\n\n #logTruncateOp(table: string) {\n if (this.#mode === 'serving') {\n this.#changeLog.logTruncateOp(this.#version, table);\n this.#numChangeLogEntries++;\n }\n }\n\n #logResetOp(table: string) {\n this.#schemaChanged = true;\n if (this.#mode === 'serving') {\n this.#changeLog.logResetOp(this.#version, table);\n this.#numChangeLogEntries++;\n }\n this.#reloadTableSpecs();\n }\n\n processBackfill({\n relation,\n watermark,\n columns,\n rowValues,\n progressMarks,\n }: MessageBackfill) {\n const tableName = liteTableName(relation);\n const tableSpec = must(this.#tableSpecs.get(tableName));\n const rowKeyCols = relation.rowKey.columns;\n const cols = [...rowKeyCols, ...columns];\n\n // Only columns that are still being backfilled on _this_ replica are\n // written, and of those, only the columns for which this message is\n // contiguous with the data received so far (whose progress is advanced).\n //\n // * Once a column has been published (backfill completed), its values\n // strictly follow the replication timeline, so a subsequent backfill must\n // never overwrite them. This guards against a redundant backfill, e.g.\n // when the view-syncer (re)connects to a replication-manager that is\n // (re)running a backfill this replica already completed.\n // * Data for non-contiguous (ignored) columns is necessarily re-delivered\n // (by a resumed or from-scratch run) before the column can be published,\n // so writing it would be wasted I/O.\n const {accepted, ignored} = this.#trackBackfillProgress(\n relation,\n cols,\n own => acceptBackfill(own, progressMarks),\n );\n if (accepted.length === 0) {\n this.#lc.debug?.(\n ignored.length\n ? `skipping backfill of ${rowValues.length} rows into ` +\n `${tableName}: not contiguous with the progress of columns ` +\n `[${ignored.join(',')}]`\n : `skipping redundant backfill of ${rowValues.length} rows into ` +\n `${tableName} (all columns already published)`,\n progressMarks,\n );\n return;\n }\n if (ignored.length) {\n this.#lc.debug?.(\n `backfill of ${tableName} is not contiguous with the progress ` +\n `of columns [${ignored.join(',')}]`,\n progressMarks,\n );\n }\n const acceptedSet = new Set(accepted);\n\n // Common parts of the INSERT sql statement.\n const insertColsStr = [...cols, ZERO_VERSION_COLUMN_NAME].map(id).join(',');\n const qMarks = Array.from({length: cols.length + 1})\n .fill('?')\n .join(',');\n const rowKeyColsStr = rowKeyCols.map(id).join(',');\n\n let backfilled = 0;\n let skipped = 0;\n for (const v of rowValues) {\n const row = liteRow(\n Object.fromEntries(cols.map((c, i) => [c, v[i]])),\n tableSpec,\n this.#jsonFormat,\n );\n const rowKey = this.#getKey(row, {relation});\n const rowOp = this.#changeLog.getLatestRowOp(tableName, rowKey);\n if (rowOp?.op === DEL_OP && rowOp.stateVersion > watermark) {\n skipped++;\n continue; // the row was deleted after the backfill snapshot\n }\n // Restrict the DO UPDATE columns to those still being backfilled. Never\n // update an already backfilled (i.e. published) column.\n const updates = (\n rowOp?.op === SET_OP\n ? cols.filter(\n c => (rowOp.backfillingColumnVersions[c] ?? '') <= watermark,\n )\n : cols\n ).filter(c => acceptedSet.has(c));\n if (updates.length === 0) {\n // row already has newer values for all accepted backfilling columns.\n skipped++;\n continue;\n }\n const updateStmts = updates.map(col => `${id(col)}=excluded.${id(col)}`);\n this.#db.run(\n /*sql*/ `\n INSERT INTO ${id(tableName)} (${insertColsStr}) VALUES (${qMarks})\n ON CONFLICT (${rowKeyColsStr})\n DO UPDATE SET ${updateStmts.join(',')};\n `,\n ...Object.values(row.row),\n watermark, // the _0_version for new rows (i.e. table backfill)\n );\n backfilled++;\n }\n\n this.#lc.debug?.(\n `backfilled ${backfilled} rows (skipped ${skipped}) into ${tableName}`,\n );\n }\n\n #completedBackfill: DownloadStatus | undefined;\n\n /**\n * Applies `accept` to the tracked progress of each of the `cols` that are\n * still backfilling on this replica, updating the progress of the accepted\n * ones. Columns that are not backfilling (e.g. already published) are\n * neither accepted nor ignored.\n */\n #trackBackfillProgress(\n relation: Identifier,\n cols: readonly string[],\n accept: (progress: BackfillProgressMark | undefined) => AcceptResult,\n ): {accepted: string[]; ignored: string[]} {\n const tracked = this.#backfilling.getProgress(relation);\n const accepted: string[] = [];\n const ignored: string[] = [];\n for (const col of cols) {\n if (!tracked.has(col)) {\n continue; // not backfilling\n }\n const progress = tracked.get(col);\n const result = accept(progress);\n if (!result.accept) {\n ignored.push(col);\n continue;\n }\n accepted.push(col);\n if (!deepEqual(result.progress, progress)) {\n this.#backfilling.setProgress(relation, col, result.progress);\n }\n }\n return {accepted, ignored};\n }\n\n processBackfillCompleted(msg: BackfillCompleted) {\n const {relation, columns, status, progressMarks} = msg;\n const tableName = liteTableName(relation);\n const rowKeyCols = relation.rowKey.columns;\n\n // Only complete the columns whose backfill progress is contiguous with\n // the completed backfill. The others remain backfilling (and will be\n // re-requested by the change-streamer).\n const {accepted, ignored} = this.#trackBackfillProgress(\n relation,\n [...rowKeyCols, ...columns],\n own =>\n acceptBackfill(\n own,\n progressMarks ? {previous: progressMarks.previous} : undefined,\n ),\n );\n if (ignored.length) {\n this.#lc.info?.(\n `ignoring backfill-completed of ${tableName} for columns ` +\n `[${ignored.join(',')}], which have not received all of the data`,\n progressMarks,\n );\n }\n\n // If none of the columns are still backfilling on this replica, they were\n // already published (e.g. a redundant backfill from a replication-manager\n // re-running a backfill this replica already completed). Bumping versions\n // again would spuriously reset pipelines and re-report completion, so treat\n // the completion as a no-op.\n if (accepted.length === 0) {\n if (ignored.length === 0) {\n this.#lc.debug?.(\n `skipping redundant backfill-completed for ${tableName} ` +\n `(all columns already published)`,\n );\n }\n return;\n }\n const ignoredSet = new Set(ignored);\n const cols = [\n ...rowKeyCols.filter(c => !ignoredSet.has(c)),\n ...columns.filter(c => !ignoredSet.has(c)),\n ];\n\n const columnMetadata = must(ColumnMetadataStore.getInstance(this.#db.db));\n for (const col of cols) {\n columnMetadata.clearBackfilling(tableName, col);\n }\n this.#backfilling.complete(relation, cols);\n // Given that new columns are being exposed for every row in the table, bump the\n // row version for all rows.\n this.#bumpVersions(relation);\n if (status) {\n this.#completedBackfill = {table: tableName, columns: cols, ...status};\n }\n this.#lc.info?.(`finished backfilling ${tableName}`);\n\n // Note that there is no need to clear the backfillingColumnVersions values\n // in the changeLog. It could theoretically be done for clarity but:\n // (1) it could be non-trivial in terms of latency introduced and\n // (2) the data must be preserved if _other_ columns are in the process\n // of being backfilled\n //\n // Thus, for speed and simplicity, the values are left as is. (Note that\n // subsequent replicated changes to those rows will clear the values if\n // no backfills are in progress).\n }\n\n processCommit(commit: MessageCommit, watermark: string): CommitResult {\n if (watermark !== this.#version) {\n throw new Error(\n `'commit' version ${watermark} does not match 'begin' version ${\n this.#version\n }: ${stringify(commit)}`,\n );\n }\n updateReplicationWatermark(this.#db, watermark);\n\n if (this.#schemaChanged) {\n const start = Date.now();\n this.#db.db.pragma('optimize');\n this.#lc.info?.(\n `PRAGMA optimized after schema change (${Date.now() - start} ms)`,\n );\n }\n\n if (this.#mode !== 'initial-sync') {\n this.#db.commit();\n }\n\n const elapsedMs = Date.now() - this.#startMs;\n this.#lc.debug?.(`Committed tx@${this.#version} (${elapsedMs} ms)`);\n\n return {\n watermark,\n completedBackfill: this.#completedBackfill,\n schemaUpdated: this.#schemaChanged,\n changeLogUpdated: this.#numChangeLogEntries > 0,\n upstreamCommitTimeMs: commit.commitTimeMs,\n };\n }\n\n abort(lc: LogContext) {\n lc.info?.(`aborting transaction ${this.#version}`);\n this.#db.rollback();\n // A schema change in the transaction reloaded the table specs, which now\n // describe the schema that the rollback undid. Clearing them makes the\n // next transaction reload them from the database.\n this.#tableSpecs.clear();\n }\n}\n\nfunction differentStorageTypes(\n oldSpec: ColumnSpec,\n newSpec: ColumnSpec,\n): boolean {\n return (\n oldSpec.dataType !== newSpec.dataType ||\n isEnumColumn(oldSpec) !== isEnumColumn(newSpec) ||\n isArrayColumn(oldSpec) !== isArrayColumn(newSpec)\n );\n}\n\nfunction getBackfilledColumns(\n row: LiteRow,\n {backfilling}: LiteTableSpecWithReplicationStatus,\n): string[] | undefined {\n if (!backfilling?.length) {\n return undefined; // common case\n }\n return backfilling.filter(col => col in row);\n}\n\nfunction oversizedValueDescription(value: LiteValueType): string | undefined {\n if (typeof value === 'bigint') {\n return BigInt.asIntN(64, value) !== value\n ? 'valueType=bigint fitsInt64=false'\n : undefined;\n }\n\n const sizeBytes =\n typeof value === 'string'\n ? Buffer.byteLength(value)\n : value instanceof Uint8Array\n ? value.byteLength\n : undefined;\n if (sizeBytes !== undefined && sizeBytes > MAX_SQLITE_BIND_BYTES) {\n const valueType = typeof value === 'string' ? 'string' : 'buffer';\n return `valueType=${valueType} sizeBytes=${sizeBytes} limitBytes=${MAX_SQLITE_BIND_BYTES}`;\n }\n\n return undefined;\n}\n\n/** Runs `fn`, returning its error rather than throwing it. */\nfunction attempt(fn: () => void): unknown {\n try {\n fn();\n return undefined;\n } catch (e) {\n return e ?? new Error('rollback failed');\n }\n}\n\nfunction ensureError(err: unknown): Error {\n if (err instanceof Error) {\n return err;\n }\n const error = new Error();\n error.cause = err;\n return error;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"change-processor.js","names":["bufferConstants"],"sources":["../../../../../../zero-cache/src/services/replicator/change-processor.ts"],"sourcesContent":["import {constants as bufferConstants} from 'node:buffer';\nimport type {LogContext} from '@rocicorp/logger';\nimport {SqliteError} from '@rocicorp/zero-sqlite3';\nimport {AbortError} from '../../../../shared/src/abort-error.ts';\nimport {assert, unreachable} from '../../../../shared/src/asserts.ts';\nimport {stringify} from '../../../../shared/src/bigint-json.ts';\nimport {deepEqual} from '../../../../shared/src/json.ts';\nimport {must} from '../../../../shared/src/must.ts';\nimport {mapEntries} from '../../../../shared/src/objects.ts';\nimport type {DownloadStatus} from '../../../../zero-events/src/status.ts';\nimport {\n createLiteIndexStatement,\n createLiteTableStatement,\n liteColumnDef,\n} from '../../db/create.ts';\nimport {\n computeZqlSpecs,\n listTables,\n type LiteTableSpecWithReplicationStatus,\n} from '../../db/lite-tables.ts';\nimport {\n isArrayColumn,\n isEnumColumn,\n mapPostgresToLite,\n mapPostgresToLiteColumn,\n mapPostgresToLiteIndex,\n} from '../../db/pg-to-lite.ts';\nimport type {ColumnSpec} from '../../db/specs.ts';\nimport type {StatementRunner} from '../../db/statements.ts';\nimport type {LexiVersion} from '../../types/lexi-version.ts';\nimport {\n JSON_PARSED,\n liteRow,\n type JSONFormat,\n type LiteRow,\n type LiteRowKey,\n type LiteValueType,\n} from '../../types/lite.ts';\nimport {liteTableName} from '../../types/names.ts';\nimport {id} from '../../types/sql.ts';\nimport {\n acceptBackfill,\n type AcceptResult,\n} from '../change-source/protocol/backfill-progress.ts';\nimport type {\n BackfillCompleted,\n BackfillProgressMark,\n Change,\n ColumnAdd,\n ColumnDrop,\n ColumnUpdate,\n Identifier,\n IndexCreate,\n IndexDrop,\n MessageBackfill,\n MessageCommit,\n MessageDelete,\n MessageInsert,\n MessageRelation,\n MessageTruncate,\n MessageUpdate,\n TableCreate,\n TableDrop,\n TableRename,\n TableUpdateMetadata,\n} from '../change-source/protocol/current/data.ts';\nimport type {ChangeStreamData} from '../change-source/protocol/current/downstream.ts';\nimport type {ReplicatorMode} from './replicator.ts';\nimport {BackfillingTracker} from './schema/backfilling.ts';\nimport {ChangeLog, DEL_OP, SET_OP} from './schema/change-log.ts';\nimport {ColumnMetadataStore} from './schema/column-metadata.ts';\nimport {\n ZERO_VERSION_COLUMN_NAME,\n updateReplicationWatermark,\n} from './schema/replication-state.ts';\nimport {TableMetadataTracker} from './schema/table-metadata.ts';\n\nexport type ChangeProcessorMode = ReplicatorMode | 'initial-sync';\n\nconst BIND_VALUE_TOO_BIG_ERROR =\n 'The bound string, buffer, or bigint is too big';\nconst MAX_SQLITE_BIND_BYTES = Math.min(\n bufferConstants.MAX_LENGTH,\n bufferConstants.MAX_STRING_LENGTH,\n);\n\nexport type CommitResult = {\n watermark: string;\n completedBackfill: DownloadStatus | undefined;\n schemaUpdated: boolean;\n changeLogUpdated: boolean;\n /**\n * Millisecond epoch at which the transaction committed upstream, if the\n * ChangeSource reported one. Propagated to ViewSyncers as the origin\n * timestamp of the end-to-end serving lag measurement.\n */\n upstreamCommitTimeMs?: number | undefined;\n};\n\n/**\n * The ChangeProcessor partitions the stream of messages into transactions\n * by creating a {@link TransactionProcessor} when a transaction begins, and dispatching\n * messages to it until the commit is received.\n *\n * From https://www.postgresql.org/docs/current/protocol-logical-replication.html#PROTOCOL-LOGICAL-MESSAGES-FLOW :\n *\n * \"The logical replication protocol sends individual transactions one by one.\n * This means that all messages between a pair of Begin and Commit messages\n * belong to the same transaction.\"\n */\nexport class ChangeProcessor {\n readonly #db: StatementRunner;\n readonly #changeLog: ChangeLog;\n readonly #tableMetadata: TableMetadataTracker;\n readonly #backfilling: BackfillingTracker;\n readonly #mode: ChangeProcessorMode;\n readonly #failService: (lc: LogContext, err: unknown) => void;\n\n // The TransactionProcessor lazily loads table specs into this Map,\n // and reloads them after a schema change. It is cached here to avoid\n // reading them from the DB on every transaction.\n readonly #tableSpecs = new Map<string, LiteTableSpecWithReplicationStatus>();\n\n #currentTx: TransactionProcessor | null = null;\n\n #failure: Error | undefined;\n\n constructor(\n db: StatementRunner,\n mode: ChangeProcessorMode,\n failService: (lc: LogContext, err: unknown) => void,\n ) {\n this.#db = db;\n this.#changeLog = new ChangeLog(db.db);\n this.#tableMetadata = new TableMetadataTracker(db.db);\n this.#backfilling = new BackfillingTracker(db.db);\n this.#mode = mode;\n this.#failService = failService;\n }\n\n #fail(lc: LogContext, err: unknown) {\n if (!this.#failure) {\n let failureError = err;\n const rollbackErrors = [attempt(() => this.#currentTx?.abort(lc))].filter(\n e => e !== undefined,\n );\n\n if (rollbackErrors.length) {\n const combinedError = new Error(\n `Message processing failed and rollback also failed: operation error = ${String(err)}; rollback error = ${rollbackErrors.map(String).join('; ')}`,\n );\n combinedError.cause = err;\n failureError = combinedError;\n }\n\n this.#failure = ensureError(failureError);\n\n if (!(this.#failure instanceof AbortError)) {\n // Propagate the failure up to the service.\n lc.error?.('Message Processing failed:', this.#failure);\n this.#failService(lc, this.#failure);\n }\n }\n }\n\n abort(lc: LogContext) {\n this.#fail(lc, new AbortError());\n }\n\n /** @return If a transaction was committed. */\n processMessage(\n lc: LogContext,\n downstream: ChangeStreamData,\n ): CommitResult | null {\n const [type, message] = downstream;\n if (this.#failure) {\n lc.debug?.(`Dropping ${message.tag}`);\n return null;\n }\n try {\n const watermark =\n type === 'begin'\n ? downstream[2].commitWatermark\n : type === 'commit'\n ? downstream[2].watermark\n : undefined;\n return this.#processMessage(lc, message, watermark);\n } catch (e) {\n this.#fail(lc, e);\n }\n return null;\n }\n\n #beginTransaction(\n lc: LogContext,\n commitVersion: string,\n jsonFormat: JSONFormat,\n ): TransactionProcessor {\n const start = Date.now();\n\n // litestream can technically hold the lock for an arbitrary amount of time\n // when checkpointing a large commit. Crashing on the busy-timeout in this\n // scenario will either produce a corrupt backup or otherwise prevent\n // replication from proceeding.\n //\n // Instead, retry the lock acquisition indefinitely. If this masks\n // an unknown deadlock situation, manual intervention will be necessary.\n for (let i = 0; ; i++) {\n try {\n return new TransactionProcessor(\n lc,\n this.#db,\n this.#mode,\n this.#changeLog,\n this.#tableMetadata,\n this.#backfilling,\n this.#tableSpecs,\n commitVersion,\n jsonFormat,\n );\n } catch (e) {\n if (e instanceof SqliteError && e.code === 'SQLITE_BUSY') {\n lc.warn?.(\n `SQLITE_BUSY for ${Date.now() - start} ms (attempt ${i + 1}). ` +\n `This is only expected if litestream is performing a large ` +\n `checkpoint.`,\n e,\n );\n continue;\n }\n throw e;\n }\n }\n }\n\n /** @return If a transaction was committed. */\n #processMessage(\n lc: LogContext,\n msg: Change,\n watermark: string | undefined,\n ): CommitResult | null {\n if (msg.tag === 'begin') {\n if (this.#currentTx) {\n throw new Error(`Already in a transaction ${stringify(msg)}`);\n }\n this.#currentTx = this.#beginTransaction(\n lc,\n must(watermark),\n msg.json ?? JSON_PARSED,\n );\n return null;\n }\n\n // For non-begin messages, there should be a #currentTx set.\n const tx = this.#currentTx;\n if (!tx) {\n throw new Error(\n `Received message outside of transaction: ${stringify(msg)}`,\n );\n }\n\n if (msg.tag === 'commit') {\n assert(watermark, 'watermark is required for commit messages');\n const result = tx.processCommit(msg, watermark);\n // Clear only after a successful commit so #fail can roll back a commit\n // path that throws before SQLite has committed.\n this.#currentTx = null;\n return result;\n }\n\n if (msg.tag === 'rollback') {\n tx.abort(lc);\n this.#currentTx = null;\n return null;\n }\n\n switch (msg.tag) {\n case 'insert':\n tx.processInsert(msg);\n break;\n case 'update':\n tx.processUpdate(msg);\n break;\n case 'delete':\n tx.processDelete(msg);\n break;\n case 'truncate':\n tx.processTruncate(msg);\n break;\n case 'create-table':\n tx.processCreateTable(msg);\n break;\n case 'rename-table':\n tx.processRenameTable(msg);\n break;\n case 'update-table-metadata':\n tx.processTableMetadata(msg);\n break;\n case 'add-column':\n tx.processAddColumn(msg);\n break;\n case 'update-column':\n tx.processUpdateColumn(msg);\n break;\n case 'drop-column':\n tx.processDropColumn(msg);\n break;\n case 'drop-table':\n tx.processDropTable(msg);\n break;\n case 'create-index':\n tx.processCreateIndex(msg);\n break;\n case 'drop-index':\n tx.processDropIndex(msg);\n break;\n case 'backfill':\n tx.processBackfill(msg);\n break;\n case 'backfill-completed':\n tx.processBackfillCompleted(msg);\n break;\n default:\n unreachable(msg);\n }\n\n return null;\n }\n}\n\n/**\n * The {@link TransactionProcessor} handles the sequence of messages from\n * upstream, from `BEGIN` to `COMMIT` and executes the corresponding mutations\n * on the {@link postgres.TransactionSql} on the replica.\n *\n * When applying row contents to the replica, the `_0_version` column is added / updated,\n * and a corresponding entry in the `ChangeLog` is added. The version value is derived\n * from the watermark of the preceding transaction (stored as the `nextStateVersion` in the\n * `ReplicationState` table).\n *\n * Side note: For non-streaming Postgres transactions, the commitEndLsn (and thus\n * commit watermark) is available in the `begin` message, so it could theoretically\n * be used for the row version of changes within the transaction. However, the\n * commitEndLsn is not available in the streaming (in-progress) transaction\n * protocol, and may not be available for CDC streams of other upstream types.\n * Therefore, the zero replication protocol is designed to not require the commit\n * watermark when a transaction begins.\n *\n * Also of interest is the fact that all INSERT Messages are logically applied as\n * UPSERTs. See {@link processInsert} for the underlying motivation.\n */\nclass TransactionProcessor {\n readonly #lc: LogContext;\n readonly #startMs: number;\n readonly #db: StatementRunner;\n readonly #mode: ChangeProcessorMode;\n readonly #version: LexiVersion;\n readonly #changeLog: ChangeLog;\n readonly #tableMetadata: TableMetadataTracker;\n readonly #backfilling: BackfillingTracker;\n readonly #tableSpecs: Map<string, LiteTableSpecWithReplicationStatus>;\n readonly #jsonFormat: JSONFormat;\n readonly #columnMetadata: ColumnMetadataStore;\n\n #pos = 0;\n #schemaChanged = false;\n #numChangeLogEntries = 0;\n\n constructor(\n lc: LogContext,\n db: StatementRunner,\n mode: ChangeProcessorMode,\n changeLog: ChangeLog,\n tableMetadata: TableMetadataTracker,\n backfilling: BackfillingTracker,\n tableSpecs: Map<string, LiteTableSpecWithReplicationStatus>,\n commitVersion: LexiVersion,\n jsonFormat: JSONFormat,\n ) {\n this.#startMs = Date.now();\n this.#mode = mode;\n this.#jsonFormat = jsonFormat;\n\n switch (mode) {\n case 'serving':\n // This is the only transaction that commits to the serving replica.\n // Snapshotters use BEGIN CONCURRENT for private changes that are\n // always rolled back, while BEGIN IMMEDIATE lets this writer spill\n // dirty pages during large transactions.\n db.beginImmediate();\n break;\n case 'backup':\n // For the backup-replicator (i.e. replication-manager), there are no View Syncers\n // and thus BEGIN CONCURRENT is not necessary. In fact, BEGIN CONCURRENT can cause\n // deadlocks with forced wal-checkpoints (which `litestream replicate` performs),\n // so it is important to use vanilla transactions in this configuration.\n db.beginImmediate();\n break;\n case 'initial-sync':\n // When the ChangeProcessor is used for initial-sync, the calling code\n // handles the transaction boundaries.\n break;\n default:\n unreachable();\n }\n this.#db = db;\n this.#version = commitVersion;\n this.#lc = lc.withContext('version', commitVersion);\n this.#changeLog = changeLog;\n this.#tableMetadata = tableMetadata;\n this.#backfilling = backfilling;\n this.#tableSpecs = tableSpecs;\n // The column_metadata table is guaranteed to exist since the\n // replica-schema.ts migration to v8.\n this.#columnMetadata = must(ColumnMetadataStore.getInstance(db.db));\n\n if (this.#tableSpecs.size === 0) {\n this.#reloadTableSpecs();\n }\n }\n\n #reloadTableSpecs() {\n this.#tableSpecs.clear();\n // zqlSpecs include the primary key derived from unique indexes\n const zqlSpecs = computeZqlSpecs(this.#lc, this.#db.db, {\n includeBackfillingColumns: true,\n });\n for (let spec of listTables(this.#db.db)) {\n if (!spec.primaryKey) {\n spec = {\n ...spec,\n primaryKey: [\n ...(zqlSpecs.get(spec.name)?.tableSpec.primaryKey ?? []),\n ],\n };\n }\n this.#tableSpecs.set(spec.name, spec);\n }\n }\n\n #tableSpec(name: string) {\n return must(this.#tableSpecs.get(name), `Unknown table ${name}`);\n }\n\n #getKey(\n {row, numCols}: {row: LiteRow; numCols: number},\n {relation}: {relation: MessageRelation},\n ): LiteRowKey {\n const keyColumns =\n relation.rowKey.type !== 'full'\n ? relation.rowKey.columns // already a suitable key\n : this.#tableSpec(liteTableName(relation)).primaryKey;\n if (!keyColumns?.length) {\n throw new Error(\n `Cannot replicate table \"${relation.name}\" without a PRIMARY KEY or UNIQUE INDEX`,\n );\n }\n // For the common case (replica identity default), the row is already the\n // key for deletes and updates, in which case a new object can be avoided.\n if (numCols === keyColumns.length) {\n return row;\n }\n const key: Record<string, LiteValueType> = {};\n for (const col of keyColumns) {\n key[col] = row[col];\n }\n return key;\n }\n\n processInsert(insert: MessageInsert) {\n const table = liteTableName(insert.relation);\n const tableSpec = this.#tableSpec(table);\n const newRow = liteRow(insert.new, tableSpec, this.#jsonFormat);\n\n this.#upsert(table, {\n ...newRow.row,\n [ZERO_VERSION_COLUMN_NAME]: this.#version,\n });\n\n if (insert.relation.rowKey.columns.length === 0) {\n // INSERTs can be replicated for rows without a PRIMARY KEY or a\n // UNIQUE INDEX. These are written to the replica but not recorded\n // in the changeLog, because these rows cannot participate in IVM.\n //\n // (Once the table schema has been corrected to include a key, the\n // associated schema change will reset pipelines and data can be\n // loaded via hydration.)\n return;\n }\n const key = this.#getKey(newRow, insert);\n this.#logSetOp(table, key, getBackfilledColumns(newRow.row, tableSpec));\n }\n\n #upsert(table: string, row: LiteRow) {\n const columns = Object.keys(row).map(c => id(c));\n this.#db.run(\n `\n INSERT OR REPLACE INTO ${id(table)} (${columns.join(',')})\n VALUES (${Array.from({length: columns.length}).fill('?').join(',')})\n `,\n Object.values(row),\n );\n }\n\n // Updates by default are applied as UPDATE commands to support partial\n // row specifications from the change source. In particular, this is needed\n // to handle updates for which unchanged TOASTed values are not sent:\n //\n // https://www.postgresql.org/docs/current/protocol-logicalrep-message-formats.html#PROTOCOL-LOGICALREP-MESSAGE-FORMATS-TUPLEDATA\n //\n // However, in certain cases an UPDATE may be received for a row that\n // was not initially synced, such as when, an existing table is added\n // to the app's publication.\n //\n // In order to facilitate \"resumptive\" replication, the logic falls back to\n // an INSERT if the update did not change any rows.\n processUpdate(update: MessageUpdate) {\n const table = liteTableName(update.relation);\n const tableSpec = this.#tableSpec(table);\n const newRow = liteRow(update.new, tableSpec, this.#jsonFormat);\n const row = {...newRow.row, [ZERO_VERSION_COLUMN_NAME]: this.#version};\n\n // update.key is set with the old values if the key has changed.\n const oldKey = update.key\n ? this.#getKey(\n liteRow(update.key, this.#tableSpec(table), this.#jsonFormat),\n update,\n )\n : null;\n const newKey = this.#getKey(newRow, update);\n\n if (oldKey) {\n this.#logDeleteOp(table, oldKey, tableSpec.backfilling);\n }\n this.#logSetOp(table, newKey, getBackfilledColumns(newRow.row, tableSpec));\n\n const currKey = oldKey ?? newKey;\n const conds = Object.keys(currKey).map(col => `${id(col)}=?`);\n const setExprs = Object.keys(row).map(col => `${id(col)}=?`);\n\n try {\n const {changes} = this.#db.run(\n `\n UPDATE ${id(table)}\n SET ${setExprs.join(',')}\n WHERE ${conds.join(' AND ')}\n `,\n [...Object.values(row), ...Object.values(currKey)],\n );\n\n // If the UPDATE did not affect any rows, perform an UPSERT of the\n // new row for resumptive replication.\n if (changes === 0) {\n this.#upsert(table, row);\n }\n } catch (e) {\n if (\n !(e instanceof RangeError) ||\n e.message !== BIND_VALUE_TOO_BIG_ERROR\n ) {\n throw e;\n }\n\n const binding = [...Object.entries(row), ...Object.entries(currKey)]\n .map(\n ([column, value]) =>\n [column, oversizedValueDescription(value)] as const,\n )\n .find(([, description]) => description);\n const relationOid =\n 'relationOid' in update.relation &&\n typeof update.relation.relationOid === 'number'\n ? ` relationOid=${update.relation.relationOid}`\n : '';\n const error = new Error(\n `Oversized SQLite update binding: tx=${this.#version}${relationOid} table=${update.relation.schema}.${update.relation.name} column=${binding?.[0] ?? 'unknown'}${binding?.[1] ? ` ${binding[1]}` : ''}`,\n {cause: e},\n );\n error.name = 'OversizedUpdateBindingError';\n throw error;\n }\n }\n\n processDelete(del: MessageDelete) {\n const table = liteTableName(del.relation);\n const tableSpec = this.#tableSpec(table);\n const rowKey = this.#getKey(\n liteRow(del.key, tableSpec, this.#jsonFormat),\n del,\n );\n\n this.#delete(table, rowKey);\n this.#logDeleteOp(table, rowKey, tableSpec.backfilling);\n }\n\n #delete(table: string, rowKey: LiteRowKey) {\n const conds = Object.keys(rowKey).map(col => `${id(col)}=?`);\n this.#db.run(\n `DELETE FROM ${id(table)} WHERE ${conds.join(' AND ')}`,\n Object.values(rowKey),\n );\n }\n\n processTruncate(truncate: MessageTruncate) {\n for (const relation of truncate.relations) {\n const table = liteTableName(relation);\n // Update replica data.\n this.#db.run(`DELETE FROM ${id(table)}`);\n\n // Update change log.\n this.#logTruncateOp(table);\n }\n }\n\n processCreateTable(create: TableCreate) {\n if (create.metadata) {\n this.#tableMetadata.setUpstreamMetadata(create.spec, create.metadata);\n }\n this.#backfilling.apply(create);\n const table = mapPostgresToLite(create.spec);\n this.#db.db.exec(createLiteTableStatement(table));\n\n // Write to metadata table\n for (const [colName, colSpec] of Object.entries(create.spec.columns)) {\n this.#columnMetadata.insert(\n table.name,\n colName,\n colSpec,\n create.backfill?.[colName],\n );\n }\n\n this.#logResetOp(table.name);\n this.#lc.info?.(create.tag, table.name);\n }\n\n processTableMetadata(msg: TableUpdateMetadata) {\n this.#tableMetadata.setUpstreamMetadata(msg.table, msg.new);\n // Inert today: the fold's only op for this tag is `upsert-metadata`, which\n // the line above is the replica's interpreter of. Called anyway so that\n // every site that hands a schema change to one cookie tracker hands it to\n // both -- an exception here would be a schema change the shared fold has an\n // opinion about and this store never sees, which is the drift the fold\n // exists to make impossible.\n this.#backfilling.apply(msg);\n }\n\n processRenameTable(rename: TableRename) {\n this.#tableMetadata.rename(rename.old, rename.new);\n this.#backfilling.apply(rename);\n\n const oldName = liteTableName(rename.old);\n const newName = liteTableName(rename.new);\n this.#db.db.exec(`ALTER TABLE ${id(oldName)} RENAME TO ${id(newName)}`);\n\n // Rename in metadata table\n this.#columnMetadata.renameTable(oldName, newName);\n\n this.#bumpVersions(rename.new);\n this.#logResetOp(oldName);\n this.#lc.info?.(rename.tag, oldName, newName);\n }\n\n processAddColumn(msg: ColumnAdd) {\n if (msg.tableMetadata) {\n this.#tableMetadata.setUpstreamMetadata(msg.table, msg.tableMetadata);\n }\n this.#backfilling.apply(msg);\n const table = liteTableName(msg.table);\n const {name} = msg.column;\n const spec = mapPostgresToLiteColumn(table, msg.column);\n this.#db.db.exec(\n `ALTER TABLE ${id(table)} ADD ${id(name)} ${liteColumnDef(spec)}`,\n );\n\n // Write to metadata table\n this.#columnMetadata.insert(table, name, msg.column.spec, msg.backfill);\n\n if (msg.backfill) {\n this.#reloadTableSpecs();\n } else {\n // Make the new column visible immediately if it's not being backfilled.\n // Otherwise, the version bump will happen with the backfill is complete.\n this.#bumpVersions(msg.table);\n }\n this.#lc.info?.(msg.tag, table, msg.column);\n }\n\n processUpdateColumn(msg: ColumnUpdate) {\n // A no-op unless this is a rename, which is the only part of a column\n // update that moves the backfill cookie.\n this.#backfilling.apply(msg);\n\n const table = liteTableName(msg.table);\n let oldName = msg.old.name;\n const newName = msg.new.name;\n\n const storageTypesDiffer = differentStorageTypes(\n msg.old.spec,\n msg.new.spec,\n );\n\n // If neither the column name nor the SQLite data type changes, only the\n // upstream metadata needs to be updated. This includes changes such as a\n // varchar character limit and nullability, which SQLite does not enforce\n // but a freshly built replica still records.\n if (oldName === newName && !storageTypesDiffer) {\n this.#columnMetadata.update(\n table,\n msg.old.name,\n msg.new.name,\n msg.new.spec,\n );\n if (Boolean(msg.old.spec.notNull) !== Boolean(msg.new.spec.notNull)) {\n this.#bumpVersions(msg.table);\n }\n this.#lc.info?.(msg.tag, 'updated metadata only', msg.old, msg.new);\n return;\n }\n // Storage type changes require a new column so that SQLite uses the new\n // representation for existing and future values.\n if (storageTypesDiffer) {\n // update-column can ignore defaults because it does not change the values\n // in existing rows.\n //\n // https://www.postgresql.org/docs/current/sql-altertable.html#SQL-ALTERTABLE-DESC-SET-DROP-DEFAULT\n //\n // \"The new default value will only apply in subsequent INSERT or UPDATE\n // commands; it does not cause rows already in the table to change.\"\n //\n // This allows support for _changing_ column defaults to any expression,\n // since it does not affect what the replica needs to do.\n const newLiteSpec = mapPostgresToLiteColumn(\n table,\n msg.new,\n 'ignore-default',\n );\n if (oldName !== newName) {\n // Rename the column in place first so that SQLite rewrites every\n // reference to it in the table's index definitions, including the\n // WHERE clauses of partial indexes.\n this.#db.db.exec(\n `ALTER TABLE ${id(table)} RENAME ${id(oldName)} TO ${id(newName)}`,\n );\n oldName = newName;\n }\n const tableSpec = must(\n listTables(this.#db.db, false, false).find(\n tableSpec => tableSpec.name === table,\n ),\n );\n // Recreating the table drops its indexes, so capture their DDL to\n // replay afterwards. Auto-indexes (PRIMARY KEY) have no DDL and are\n // recreated by the CREATE TABLE statement itself.\n const indexDDL = this.#db.db\n .prepare(\n `SELECT sql FROM sqlite_master\n WHERE type = 'index' AND tbl_name = ? AND sql IS NOT NULL\n ORDER BY rowid`,\n )\n .all<{sql: string}>(table)\n .map(({sql}) => sql);\n const tmpTable = `tmp.${table}`;\n const columns = Object.keys(tableSpec.columns);\n const stmts = [\n createLiteTableStatement({\n ...tableSpec,\n name: tmpTable,\n columns: mapEntries(tableSpec.columns, (column, spec) => [\n column,\n column === newName ? {...newLiteSpec, pos: spec.pos} : spec,\n ]),\n }),\n `INSERT INTO ${id(tmpTable)} (${columns.map(id).join(',')})\n SELECT ${columns.map(id).join(',')} FROM ${id(table)};`,\n `DROP TABLE ${id(table)};`,\n `ALTER TABLE ${id(tmpTable)} RENAME TO ${id(table)};`,\n ...indexDDL.map(sql => `${sql};`),\n ];\n this.#db.db.exec(stmts.join(''));\n }\n if (oldName !== newName) {\n this.#db.db.exec(\n `ALTER TABLE ${id(table)} RENAME ${id(oldName)} TO ${id(newName)}`,\n );\n }\n\n // Update metadata table\n this.#columnMetadata.update(\n table,\n msg.old.name,\n msg.new.name,\n msg.new.spec,\n );\n\n this.#bumpVersions(msg.table);\n this.#lc.info?.(msg.tag, table, msg.new);\n }\n\n processDropColumn(msg: ColumnDrop) {\n const table = liteTableName(msg.table);\n const {column} = msg;\n this.#db.db.exec(`ALTER TABLE ${id(table)} DROP ${id(column)}`);\n\n // Delete from metadata table\n this.#columnMetadata.deleteColumn(table, column);\n this.#backfilling.apply(msg);\n\n this.#bumpVersions(msg.table);\n this.#lc.info?.(msg.tag, table, column);\n }\n\n processDropTable(drop: TableDrop) {\n this.#tableMetadata.drop(drop.id);\n this.#backfilling.apply(drop);\n\n const name = liteTableName(drop.id);\n this.#db.db.exec(`DROP TABLE IF EXISTS ${id(name)}`);\n\n // Delete from metadata table\n this.#columnMetadata.deleteTable(name);\n\n this.#logResetOp(name);\n this.#lc.info?.(drop.tag, name);\n }\n\n processCreateIndex(create: IndexCreate) {\n const index = mapPostgresToLiteIndex(create.spec);\n this.#db.db.exec(createLiteIndexStatement(index));\n\n // indexes affect tables visibility (e.g. sync-ability is gated on\n // having a unique index), so reset pipelines to refresh table schemas.\n this.#logResetOp(index.tableName);\n this.#lc.info?.(create.tag, index.name);\n }\n\n processDropIndex(drop: IndexDrop) {\n const name = liteTableName(drop.id);\n const indexExisted = this.#db.db\n .prepare(\n `SELECT tbl_name as tableName FROM sqlite_master WHERE type = 'index' AND name = ?`,\n )\n .get(name) as {tableName: string} | undefined;\n\n this.#db.db.exec(`DROP INDEX IF EXISTS ${id(name)}`);\n\n if (indexExisted) {\n // indexes affect tables visibility (e.g. sync-ability is gated on\n // having a unique index), so reset pipelines to refresh table schemas.\n this.#logResetOp(indexExisted.tableName);\n }\n this.#lc.info?.(drop.tag, name);\n }\n\n #bumpVersions(table: Identifier) {\n this.#tableMetadata.setMinRowVersion(table, this.#version);\n this.#logResetOp(liteTableName(table));\n }\n\n /**\n * @param backfilledColumns `backfilling` columns for which values were set\n */\n #logSetOp(\n table: string,\n key: LiteRowKey,\n backfilledColumns: string[] | undefined,\n ) {\n // The \"serving\" replicator always writes to the change-log (for IVM).\n // The \"backup\" replicator only needs to write to the change log\n // when writing columns that are being backfilled.\n if (this.#mode === 'serving' || backfilledColumns !== undefined) {\n this.#changeLog.logSetOp(\n this.#version,\n this.#pos++,\n table,\n key,\n backfilledColumns,\n );\n this.#numChangeLogEntries++;\n }\n }\n\n #logDeleteOp(table: string, key: LiteRowKey, backfilling?: string[]) {\n // The \"serving\" replicator always writes to the change-log (for IVM).\n // The \"backup\" replicator only needs to write to the change log\n // when writing columns that are being backfilled.\n if (this.#mode === 'serving' || backfilling?.length) {\n this.#changeLog.logDeleteOp(this.#version, this.#pos++, table, key);\n this.#numChangeLogEntries++;\n }\n }\n\n #logTruncateOp(table: string) {\n if (this.#mode === 'serving') {\n this.#changeLog.logTruncateOp(this.#version, table);\n this.#numChangeLogEntries++;\n }\n }\n\n #logResetOp(table: string) {\n this.#schemaChanged = true;\n if (this.#mode === 'serving') {\n this.#changeLog.logResetOp(this.#version, table);\n this.#numChangeLogEntries++;\n }\n this.#reloadTableSpecs();\n }\n\n processBackfill({\n relation,\n watermark,\n columns,\n rowValues,\n progressMarks,\n }: MessageBackfill) {\n const tableName = liteTableName(relation);\n const tableSpec = must(this.#tableSpecs.get(tableName));\n const rowKeyCols = relation.rowKey.columns;\n const cols = [...rowKeyCols, ...columns];\n\n // Only columns that are still being backfilled on _this_ replica are\n // written, and of those, only the columns for which this message is\n // contiguous with the data received so far (whose progress is advanced).\n //\n // * Once a column has been published (backfill completed), its values\n // strictly follow the replication timeline, so a subsequent backfill must\n // never overwrite them. This guards against a redundant backfill, e.g.\n // when the view-syncer (re)connects to a replication-manager that is\n // (re)running a backfill this replica already completed.\n // * Data for non-contiguous (ignored) columns is necessarily re-delivered\n // (by a resumed or from-scratch run) before the column can be published,\n // so writing it would be wasted I/O.\n const {accepted, ignored} = this.#trackBackfillProgress(\n relation,\n cols,\n own => acceptBackfill(own, progressMarks),\n );\n if (accepted.length === 0) {\n this.#lc.debug?.(\n ignored.length\n ? `skipping backfill of ${rowValues.length} rows into ` +\n `${tableName}: not contiguous with the progress of columns ` +\n `[${ignored.join(',')}]`\n : `skipping redundant backfill of ${rowValues.length} rows into ` +\n `${tableName} (all columns already published)`,\n progressMarks,\n );\n return;\n }\n if (ignored.length) {\n this.#lc.debug?.(\n `backfill of ${tableName} is not contiguous with the progress ` +\n `of columns [${ignored.join(',')}]`,\n progressMarks,\n );\n }\n const acceptedSet = new Set(accepted);\n\n // Common parts of the INSERT sql statement.\n const insertColsStr = [...cols, ZERO_VERSION_COLUMN_NAME].map(id).join(',');\n const qMarks = Array.from({length: cols.length + 1})\n .fill('?')\n .join(',');\n const rowKeyColsStr = rowKeyCols.map(id).join(',');\n\n let backfilled = 0;\n let skipped = 0;\n for (const v of rowValues) {\n const row = liteRow(\n Object.fromEntries(cols.map((c, i) => [c, v[i]])),\n tableSpec,\n this.#jsonFormat,\n );\n const rowKey = this.#getKey(row, {relation});\n const rowOp = this.#changeLog.getLatestRowOp(tableName, rowKey);\n if (rowOp?.op === DEL_OP && rowOp.stateVersion > watermark) {\n skipped++;\n continue; // the row was deleted after the backfill snapshot\n }\n // Restrict the DO UPDATE columns to those still being backfilled. Never\n // update an already backfilled (i.e. published) column.\n const updates = (\n rowOp?.op === SET_OP\n ? cols.filter(\n c => (rowOp.backfillingColumnVersions[c] ?? '') <= watermark,\n )\n : cols\n ).filter(c => acceptedSet.has(c));\n if (updates.length === 0) {\n // row already has newer values for all accepted backfilling columns.\n skipped++;\n continue;\n }\n const updateStmts = updates.map(col => `${id(col)}=excluded.${id(col)}`);\n this.#db.run(\n /*sql*/ `\n INSERT INTO ${id(tableName)} (${insertColsStr}) VALUES (${qMarks})\n ON CONFLICT (${rowKeyColsStr})\n DO UPDATE SET ${updateStmts.join(',')};\n `,\n ...Object.values(row.row),\n watermark, // the _0_version for new rows (i.e. table backfill)\n );\n backfilled++;\n }\n\n this.#lc.debug?.(\n `backfilled ${backfilled} rows (skipped ${skipped}) into ${tableName}`,\n );\n }\n\n #completedBackfill: DownloadStatus | undefined;\n\n /**\n * Applies `accept` to the tracked progress of each of the `cols` that are\n * still backfilling on this replica, updating the progress of the accepted\n * ones. Columns that are not backfilling (e.g. already published) are\n * neither accepted nor ignored.\n */\n #trackBackfillProgress(\n relation: Identifier,\n cols: readonly string[],\n accept: (progress: BackfillProgressMark | undefined) => AcceptResult,\n ): {accepted: string[]; ignored: string[]} {\n const tracked = this.#backfilling.getProgress(relation);\n const accepted: string[] = [];\n const ignored: string[] = [];\n for (const col of cols) {\n if (!tracked.has(col)) {\n continue; // not backfilling\n }\n const progress = tracked.get(col);\n const result = accept(progress);\n if (!result.accept) {\n ignored.push(col);\n continue;\n }\n accepted.push(col);\n if (!deepEqual(result.progress, progress)) {\n this.#backfilling.setProgress(relation, col, result.progress);\n }\n }\n return {accepted, ignored};\n }\n\n processBackfillCompleted(msg: BackfillCompleted) {\n const {relation, columns, status, progressMarks} = msg;\n const tableName = liteTableName(relation);\n const rowKeyCols = relation.rowKey.columns;\n\n // Only complete the columns whose backfill progress is contiguous with\n // the completed backfill. The others remain backfilling (and will be\n // re-requested by the change-streamer).\n const {accepted, ignored} = this.#trackBackfillProgress(\n relation,\n [...rowKeyCols, ...columns],\n own =>\n acceptBackfill(\n own,\n progressMarks ? {previous: progressMarks.previous} : undefined,\n ),\n );\n if (ignored.length) {\n this.#lc.info?.(\n `ignoring backfill-completed of ${tableName} for columns ` +\n `[${ignored.join(',')}], which have not received all of the data`,\n progressMarks,\n );\n }\n\n // If none of the columns are still backfilling on this replica, they were\n // already published (e.g. a redundant backfill from a replication-manager\n // re-running a backfill this replica already completed). Bumping versions\n // again would spuriously reset pipelines and re-report completion, so treat\n // the completion as a no-op.\n if (accepted.length === 0) {\n if (ignored.length === 0) {\n this.#lc.debug?.(\n `skipping redundant backfill-completed for ${tableName} ` +\n `(all columns already published)`,\n );\n }\n return;\n }\n const ignoredSet = new Set(ignored);\n const cols = [\n ...rowKeyCols.filter(c => !ignoredSet.has(c)),\n ...columns.filter(c => !ignoredSet.has(c)),\n ];\n\n const columnMetadata = must(ColumnMetadataStore.getInstance(this.#db.db));\n for (const col of cols) {\n columnMetadata.clearBackfilling(tableName, col);\n }\n this.#backfilling.complete(relation, cols);\n // Given that new columns are being exposed for every row in the table, bump the\n // row version for all rows.\n this.#bumpVersions(relation);\n if (status) {\n this.#completedBackfill = {table: tableName, columns: cols, ...status};\n }\n this.#lc.info?.(`finished backfilling ${tableName}`);\n\n // Note that there is no need to clear the backfillingColumnVersions values\n // in the changeLog. It could theoretically be done for clarity but:\n // (1) it could be non-trivial in terms of latency introduced and\n // (2) the data must be preserved if _other_ columns are in the process\n // of being backfilled\n //\n // Thus, for speed and simplicity, the values are left as is. (Note that\n // subsequent replicated changes to those rows will clear the values if\n // no backfills are in progress).\n }\n\n processCommit(commit: MessageCommit, watermark: string): CommitResult {\n if (watermark !== this.#version) {\n throw new Error(\n `'commit' version ${watermark} does not match 'begin' version ${\n this.#version\n }: ${stringify(commit)}`,\n );\n }\n updateReplicationWatermark(this.#db, watermark);\n\n if (this.#schemaChanged) {\n const start = Date.now();\n this.#db.db.pragma('optimize');\n this.#lc.info?.(\n `PRAGMA optimized after schema change (${Date.now() - start} ms)`,\n );\n }\n\n if (this.#mode !== 'initial-sync') {\n this.#db.commit();\n }\n\n const elapsedMs = Date.now() - this.#startMs;\n this.#lc.debug?.(`Committed tx@${this.#version} (${elapsedMs} ms)`);\n\n return {\n watermark,\n completedBackfill: this.#completedBackfill,\n schemaUpdated: this.#schemaChanged,\n changeLogUpdated: this.#numChangeLogEntries > 0,\n upstreamCommitTimeMs: commit.commitTimeMs,\n };\n }\n\n abort(lc: LogContext) {\n lc.info?.(`aborting transaction ${this.#version}`);\n this.#db.rollback();\n // A schema change in the transaction reloaded the table specs, which now\n // describe the schema that the rollback undid. Clearing them makes the\n // next transaction reload them from the database.\n this.#tableSpecs.clear();\n }\n}\n\nfunction differentStorageTypes(\n oldSpec: ColumnSpec,\n newSpec: ColumnSpec,\n): boolean {\n return (\n oldSpec.dataType !== newSpec.dataType ||\n isEnumColumn(oldSpec) !== isEnumColumn(newSpec) ||\n isArrayColumn(oldSpec) !== isArrayColumn(newSpec)\n );\n}\n\nfunction getBackfilledColumns(\n row: LiteRow,\n {backfilling}: LiteTableSpecWithReplicationStatus,\n): string[] | undefined {\n if (!backfilling?.length) {\n return undefined; // common case\n }\n return backfilling.filter(col => col in row);\n}\n\nfunction oversizedValueDescription(value: LiteValueType): string | undefined {\n if (typeof value === 'bigint') {\n return BigInt.asIntN(64, value) !== value\n ? 'valueType=bigint fitsInt64=false'\n : undefined;\n }\n\n const sizeBytes =\n typeof value === 'string'\n ? Buffer.byteLength(value)\n : value instanceof Uint8Array\n ? value.byteLength\n : undefined;\n if (sizeBytes !== undefined && sizeBytes > MAX_SQLITE_BIND_BYTES) {\n const valueType = typeof value === 'string' ? 'string' : 'buffer';\n return `valueType=${valueType} sizeBytes=${sizeBytes} limitBytes=${MAX_SQLITE_BIND_BYTES}`;\n }\n\n return undefined;\n}\n\n/** Runs `fn`, returning its error rather than throwing it. */\nfunction attempt(fn: () => void): unknown {\n try {\n fn();\n return undefined;\n } catch (e) {\n return e ?? new Error('rollback failed');\n }\n}\n\nfunction ensureError(err: unknown): Error {\n if (err instanceof Error) {\n return err;\n }\n const error = new Error();\n error.cause = err;\n return error;\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
+ import { resolver } from "../../../../shared/src/resolver.js";
1
2
  import { readHead } from "../../types/streams.js";
2
- import { resolver } from "@rocicorp/resolver";
3
3
  //#region ../zero-cache/src/services/replicator/drain-handler.ts
4
4
  var DEFAULT_SWITCHOVER_TIMEOUT_MS = 1e4;
5
5
  var MIN_SWITCHOVER_RETRY_DELAY_MS = 1e3;
@@ -1 +1 @@
1
- {"version":3,"file":"drain-handler.js","names":["#lc","#changeStreamer","#state","#options","#committedContext","#restoreGranted","#draining","#isActive","#switchover","#next","#attempt","#holdForRestore"],"sources":["../../../../../../zero-cache/src/services/replicator/drain-handler.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {resolver} from '@rocicorp/resolver';\nimport {readHead, type Sized, type Source} from '../../types/streams.ts';\nimport type {\n ChangeStreamer,\n Status,\n SubscriberContext,\n} from '../change-streamer/change-streamer.ts';\nimport type {SubscribeDownstream} from '../change-streamer/subscribe.ts';\nimport type {RunningState} from '../running-state.ts';\n\n// Bounds the time to wait for a switchover subscription to be established\n// and to receive its first message.\nconst DEFAULT_SWITCHOVER_TIMEOUT_MS = 10_000;\nconst MIN_SWITCHOVER_RETRY_DELAY_MS = 1_000;\nconst MAX_SWITCHOVER_RETRY_DELAY_MS = 30_000;\n\n/**\n * Bounds the time to search for another replication-manager to switch over\n * to, after which the current subscription is closed so that the draining\n * replication-manager can shut down (e.g. when it is the only one). The time\n * during which a subscription is held by another replication-manager (i.e.\n * waiting for permission to restore) does not count towards it.\n *\n * This is well below the default termination grace period of container\n * runners (30 seconds in Kubernetes and ECS), so that the draining\n * replication-manager can shut down cleanly when there is no other.\n */\nconst DEFAULT_SWITCHOVER_SEARCH_TIMEOUT_MS = 20_000;\n\nexport type SwitchoverOptions = {\n /**\n * Called when a replication-manager with a newer replica version grants\n * permission to restore its replica. This should initiate a graceful\n * restart of the server (during which the current subscription continues\n * to be served).\n */\n onRestoreGranted: () => void;\n\n /**\n * The replica file, from which the state of the last committed\n * transaction is read for switchover subscriptions.\n */\n replicaFile: string;\n\n /** For testing. */\n timeoutMs?: number | undefined;\n\n /** For testing. */\n searchTimeoutMs?: number | undefined;\n};\n\nexport type Downstream = Source<Sized<SubscribeDownstream>>;\n\ntype AttemptOutcome =\n | 'switched'\n | 'restoring'\n // The subscription was held for restore, but closed before a grant.\n | 'released'\n | 'retry';\n\n/**\n * Handles the switchover of a serving replica's subscription from a draining\n * replication-manager to another one, without interrupting the current\n * subscription.\n *\n * Upon {@link onChangeStreamerDrain}, the handler repeatedly (with backoff)\n * opens a new `switchover` subscription, at the watermark of the replica's\n * last committed transaction, to whichever replication-manager the\n * connection is routed to. The first message on the new subscription\n * determines the outcome:\n * * `status`: The subscription was accepted (i.e. the replica is compatible).\n * The current subscription is cancelled (aborting any transaction in\n * progress), and the new one is made available via\n * {@link getNextConnection}. Note that the new subscription may start with\n * transactions that were committed from the current subscription in the\n * meantime, which the consumer must skip.\n * * `status` with `restore: queued`: The replication-manager has a newer\n * replica version, and is holding the subscription until it grants\n * permission to restore. The held subscription is monitored for the grant.\n * * `status` with `restore: granted`: Permission to restore is granted, and\n * {@link SwitchoverOptions.onRestoreGranted} is called. The granted\n * subscription is kept open until the process exits, so that the\n * replication-manager can track the grant until the restore begins.\n * * Anything else (e.g. an error, or a `draining` replication-manager):\n * The switchover is retried later.\n *\n * If no other replication-manager accepts or holds a switchover subscription\n * within {@link DEFAULT_SWITCHOVER_SEARCH_TIMEOUT_MS} (e.g. because the\n * draining one is the only one), the current subscription is closed so that\n * the draining replication-manager can shut down, and the consumer reconnects\n * on its own.\n *\n * The current subscription continues to be consumed throughout. A\n * switchover is scoped to the subscription from which it switches: If that\n * subscription ends first (e.g. the replication-manager shuts down), the\n * switchover is abandoned, including any held (but not granted)\n * subscription, as the consumer reconnects on its own.\n */\nexport class DrainHandler {\n readonly #lc: LogContext;\n readonly #changeStreamer: ChangeStreamer;\n readonly #state: RunningState;\n readonly #options: SwitchoverOptions;\n readonly #committedContext: () => SubscriberContext;\n\n // The subscription currently being switched from.\n #draining: Downstream | undefined;\n #restoreGranted = false;\n #next: Downstream | undefined;\n\n /**\n * @param committedContext Returns the subscriber context as of the\n * replica's last committed transaction.\n */\n constructor(\n lc: LogContext,\n changeStreamer: ChangeStreamer,\n state: RunningState,\n options: SwitchoverOptions,\n committedContext: () => SubscriberContext,\n ) {\n this.#lc = lc.withContext('component', 'drain-handler');\n this.#changeStreamer = changeStreamer;\n this.#state = state;\n this.#options = options;\n this.#committedContext = committedContext;\n }\n\n /**\n * Called when the change-streamer of the `current` subscription is\n * draining.\n */\n onChangeStreamerDrain(current: Downstream) {\n if (\n this.#restoreGranted ||\n this.#draining === current ||\n !this.#isActive(current)\n ) {\n return;\n }\n this.#draining = current;\n this.#lc.info?.(\n `replication-manager is draining. switching over to another`,\n );\n void this.#switchover(current);\n }\n\n get hasNextConnection(): boolean {\n return this.#next !== undefined;\n }\n\n /**\n * Returns (and clears) the subscription that replaces the (now cancelled)\n * current one, if a switchover succeeded.\n */\n getNextConnection(): Downstream | undefined {\n const next = this.#next;\n this.#next = undefined;\n return next;\n }\n\n #isActive(current: Downstream) {\n return !current.signal.aborted && this.#state.shouldRun();\n }\n\n async #switchover(current: Downstream) {\n const searchTimeoutMs =\n this.#options.searchTimeoutMs ?? DEFAULT_SWITCHOVER_SEARCH_TIMEOUT_MS;\n let failures = 0;\n let searchStart = Date.now();\n while (this.#isActive(current)) {\n const outcome = await this.#attempt(current);\n if (outcome === 'switched' || outcome === 'restoring') {\n return;\n }\n if (outcome === 'released') {\n // Time spent held by another replication-manager does not count\n // towards the search.\n failures = 0;\n searchStart = Date.now();\n }\n const remaining = searchStart + searchTimeoutMs - Date.now();\n if (remaining > 0) {\n const delay = Math.min(\n MIN_SWITCHOVER_RETRY_DELAY_MS * 2 ** failures++,\n MAX_SWITCHOVER_RETRY_DELAY_MS,\n );\n await this.#state.sleep(Math.min(delay, remaining));\n continue;\n }\n // The search has timed out.\n if (this.#isActive(current)) {\n this.#lc.warn?.(\n `no other replication-manager found within ${searchTimeoutMs} ms. ` +\n `disconnecting from the draining replication-manager`,\n );\n current.cancel();\n }\n return;\n }\n }\n\n async #attempt(current: Downstream): Promise<AttemptOutcome> {\n const lc = this.#lc;\n const timeoutMs = this.#options.timeoutMs ?? DEFAULT_SWITCHOVER_TIMEOUT_MS;\n let candidate: Downstream | undefined;\n let timer: ReturnType<typeof setTimeout> | undefined;\n let timedOut = false;\n try {\n const ctx = this.#committedContext();\n lc.info?.(`attempting switchover at ${ctx.watermark}`);\n const timeout = new Promise<never>((_, reject) => {\n timer = setTimeout(() => {\n timedOut = true;\n reject(new Error(`timed out after ${timeoutMs} ms`));\n }, timeoutMs);\n });\n const subscribing = this.#changeStreamer.subscribe({\n ...ctx,\n switchover: true,\n });\n // Clean up a connection that is established after a timeout.\n void subscribing.then(\n sub => (timedOut ? sub.cancel() : undefined),\n () => {},\n );\n candidate = await Promise.race([subscribing, timeout]);\n const {head, rest} = readHead(candidate);\n const first = await Promise.race([head.next(), timeout]);\n const msg = first.done ? undefined : first.value.data;\n\n if (!this.#isActive(current)) {\n // e.g. The current subscription failed in the meantime.\n } else if (msg?.[0] === 'status') {\n const {restore, draining} = msg[1];\n if (restore) {\n const granted = await this.#holdForRestore(current, rest, restore);\n if (granted) {\n return 'restoring';\n }\n lc.info?.(`held switchover subscription closed. will retry`);\n return 'released';\n }\n if (!draining) {\n lc.info?.(`switched over to a new subscription at ${ctx.watermark}`);\n this.#next = rest;\n current.cancel();\n return 'switched';\n }\n }\n lc.warn?.(`switchover rejected. continuing current subscription`, msg);\n } catch (e) {\n lc.warn?.(`switchover failed. continuing current subscription`, e);\n } finally {\n clearTimeout(timer);\n }\n candidate?.cancel();\n return 'retry';\n }\n\n /**\n * Keeps the held (or granted) subscription open, and initiates a graceful\n * restart when permission to restore is granted. A held subscription that\n * has yet to be granted is cancelled if the `current` subscription ends.\n *\n * @returns `true` once permission is granted, or `false` if the held\n * subscription closes before then.\n */\n #holdForRestore(\n current: Downstream,\n held: Downstream,\n restore: NonNullable<Status['restore']>,\n ): Promise<boolean> {\n const lc = this.#lc;\n const result = resolver<boolean>();\n const unregister = this.#state.cancelOnStop(held);\n const onCurrentEnded = () => {\n if (!this.#restoreGranted) {\n lc.info?.(`abandoning held switchover subscription`);\n held.cancel();\n }\n };\n current.signal.addEventListener('abort', onCurrentEnded, {once: true});\n\n const onRestore = (r: NonNullable<Status['restore']>) => {\n if (r.state === 'queued') {\n lc.info?.(\n `waiting for permission to restore a new replica (position ${r.position})`,\n );\n } else if (!this.#restoreGranted) {\n lc.info?.(\n `granted permission to restore a new replica. restarting gracefully`,\n );\n this.#restoreGranted = true;\n this.#options.onRestoreGranted();\n result.resolve(true);\n }\n };\n onRestore(restore);\n void (async () => {\n try {\n // Note: The loop must not be exited early, as that would close the\n // connection.\n for await (const {data: msg} of held) {\n if (msg[0] === 'status' && msg[1].restore) {\n onRestore(msg[1].restore);\n }\n }\n } catch (e) {\n lc.warn?.(`held switchover subscription failed`, e);\n } finally {\n unregister();\n current.signal.removeEventListener('abort', onCurrentEnded);\n result.resolve(false);\n }\n })();\n return result.promise;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"drain-handler.js","names":[],"sources":["../../../../../../zero-cache/src/services/replicator/drain-handler.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {resolver} from '../../../../shared/src/resolver.ts';\nimport {readHead, type Sized, type Source} from '../../types/streams.ts';\nimport type {\n ChangeStreamer,\n Status,\n SubscriberContext,\n} from '../change-streamer/change-streamer.ts';\nimport type {SubscribeDownstream} from '../change-streamer/subscribe.ts';\nimport type {RunningState} from '../running-state.ts';\n\n// Bounds the time to wait for a switchover subscription to be established\n// and to receive its first message.\nconst DEFAULT_SWITCHOVER_TIMEOUT_MS = 10_000;\nconst MIN_SWITCHOVER_RETRY_DELAY_MS = 1_000;\nconst MAX_SWITCHOVER_RETRY_DELAY_MS = 30_000;\n\n/**\n * Bounds the time to search for another replication-manager to switch over\n * to, after which the current subscription is closed so that the draining\n * replication-manager can shut down (e.g. when it is the only one). The time\n * during which a subscription is held by another replication-manager (i.e.\n * waiting for permission to restore) does not count towards it.\n *\n * This is well below the default termination grace period of container\n * runners (30 seconds in Kubernetes and ECS), so that the draining\n * replication-manager can shut down cleanly when there is no other.\n */\nconst DEFAULT_SWITCHOVER_SEARCH_TIMEOUT_MS = 20_000;\n\nexport type SwitchoverOptions = {\n /**\n * Called when a replication-manager with a newer replica version grants\n * permission to restore its replica. This should initiate a graceful\n * restart of the server (during which the current subscription continues\n * to be served).\n */\n onRestoreGranted: () => void;\n\n /**\n * The replica file, from which the state of the last committed\n * transaction is read for switchover subscriptions.\n */\n replicaFile: string;\n\n /** For testing. */\n timeoutMs?: number | undefined;\n\n /** For testing. */\n searchTimeoutMs?: number | undefined;\n};\n\nexport type Downstream = Source<Sized<SubscribeDownstream>>;\n\ntype AttemptOutcome =\n | 'switched'\n | 'restoring'\n // The subscription was held for restore, but closed before a grant.\n | 'released'\n | 'retry';\n\n/**\n * Handles the switchover of a serving replica's subscription from a draining\n * replication-manager to another one, without interrupting the current\n * subscription.\n *\n * Upon {@link onChangeStreamerDrain}, the handler repeatedly (with backoff)\n * opens a new `switchover` subscription, at the watermark of the replica's\n * last committed transaction, to whichever replication-manager the\n * connection is routed to. The first message on the new subscription\n * determines the outcome:\n * * `status`: The subscription was accepted (i.e. the replica is compatible).\n * The current subscription is cancelled (aborting any transaction in\n * progress), and the new one is made available via\n * {@link getNextConnection}. Note that the new subscription may start with\n * transactions that were committed from the current subscription in the\n * meantime, which the consumer must skip.\n * * `status` with `restore: queued`: The replication-manager has a newer\n * replica version, and is holding the subscription until it grants\n * permission to restore. The held subscription is monitored for the grant.\n * * `status` with `restore: granted`: Permission to restore is granted, and\n * {@link SwitchoverOptions.onRestoreGranted} is called. The granted\n * subscription is kept open until the process exits, so that the\n * replication-manager can track the grant until the restore begins.\n * * Anything else (e.g. an error, or a `draining` replication-manager):\n * The switchover is retried later.\n *\n * If no other replication-manager accepts or holds a switchover subscription\n * within {@link DEFAULT_SWITCHOVER_SEARCH_TIMEOUT_MS} (e.g. because the\n * draining one is the only one), the current subscription is closed so that\n * the draining replication-manager can shut down, and the consumer reconnects\n * on its own.\n *\n * The current subscription continues to be consumed throughout. A\n * switchover is scoped to the subscription from which it switches: If that\n * subscription ends first (e.g. the replication-manager shuts down), the\n * switchover is abandoned, including any held (but not granted)\n * subscription, as the consumer reconnects on its own.\n */\nexport class DrainHandler {\n readonly #lc: LogContext;\n readonly #changeStreamer: ChangeStreamer;\n readonly #state: RunningState;\n readonly #options: SwitchoverOptions;\n readonly #committedContext: () => SubscriberContext;\n\n // The subscription currently being switched from.\n #draining: Downstream | undefined;\n #restoreGranted = false;\n #next: Downstream | undefined;\n\n /**\n * @param committedContext Returns the subscriber context as of the\n * replica's last committed transaction.\n */\n constructor(\n lc: LogContext,\n changeStreamer: ChangeStreamer,\n state: RunningState,\n options: SwitchoverOptions,\n committedContext: () => SubscriberContext,\n ) {\n this.#lc = lc.withContext('component', 'drain-handler');\n this.#changeStreamer = changeStreamer;\n this.#state = state;\n this.#options = options;\n this.#committedContext = committedContext;\n }\n\n /**\n * Called when the change-streamer of the `current` subscription is\n * draining.\n */\n onChangeStreamerDrain(current: Downstream) {\n if (\n this.#restoreGranted ||\n this.#draining === current ||\n !this.#isActive(current)\n ) {\n return;\n }\n this.#draining = current;\n this.#lc.info?.(\n `replication-manager is draining. switching over to another`,\n );\n void this.#switchover(current);\n }\n\n get hasNextConnection(): boolean {\n return this.#next !== undefined;\n }\n\n /**\n * Returns (and clears) the subscription that replaces the (now cancelled)\n * current one, if a switchover succeeded.\n */\n getNextConnection(): Downstream | undefined {\n const next = this.#next;\n this.#next = undefined;\n return next;\n }\n\n #isActive(current: Downstream) {\n return !current.signal.aborted && this.#state.shouldRun();\n }\n\n async #switchover(current: Downstream) {\n const searchTimeoutMs =\n this.#options.searchTimeoutMs ?? DEFAULT_SWITCHOVER_SEARCH_TIMEOUT_MS;\n let failures = 0;\n let searchStart = Date.now();\n while (this.#isActive(current)) {\n const outcome = await this.#attempt(current);\n if (outcome === 'switched' || outcome === 'restoring') {\n return;\n }\n if (outcome === 'released') {\n // Time spent held by another replication-manager does not count\n // towards the search.\n failures = 0;\n searchStart = Date.now();\n }\n const remaining = searchStart + searchTimeoutMs - Date.now();\n if (remaining > 0) {\n const delay = Math.min(\n MIN_SWITCHOVER_RETRY_DELAY_MS * 2 ** failures++,\n MAX_SWITCHOVER_RETRY_DELAY_MS,\n );\n await this.#state.sleep(Math.min(delay, remaining));\n continue;\n }\n // The search has timed out.\n if (this.#isActive(current)) {\n this.#lc.warn?.(\n `no other replication-manager found within ${searchTimeoutMs} ms. ` +\n `disconnecting from the draining replication-manager`,\n );\n current.cancel();\n }\n return;\n }\n }\n\n async #attempt(current: Downstream): Promise<AttemptOutcome> {\n const lc = this.#lc;\n const timeoutMs = this.#options.timeoutMs ?? DEFAULT_SWITCHOVER_TIMEOUT_MS;\n let candidate: Downstream | undefined;\n let timer: ReturnType<typeof setTimeout> | undefined;\n let timedOut = false;\n try {\n const ctx = this.#committedContext();\n lc.info?.(`attempting switchover at ${ctx.watermark}`);\n const timeout = new Promise<never>((_, reject) => {\n timer = setTimeout(() => {\n timedOut = true;\n reject(new Error(`timed out after ${timeoutMs} ms`));\n }, timeoutMs);\n });\n const subscribing = this.#changeStreamer.subscribe({\n ...ctx,\n switchover: true,\n });\n // Clean up a connection that is established after a timeout.\n void subscribing.then(\n sub => (timedOut ? sub.cancel() : undefined),\n () => {},\n );\n candidate = await Promise.race([subscribing, timeout]);\n const {head, rest} = readHead(candidate);\n const first = await Promise.race([head.next(), timeout]);\n const msg = first.done ? undefined : first.value.data;\n\n if (!this.#isActive(current)) {\n // e.g. The current subscription failed in the meantime.\n } else if (msg?.[0] === 'status') {\n const {restore, draining} = msg[1];\n if (restore) {\n const granted = await this.#holdForRestore(current, rest, restore);\n if (granted) {\n return 'restoring';\n }\n lc.info?.(`held switchover subscription closed. will retry`);\n return 'released';\n }\n if (!draining) {\n lc.info?.(`switched over to a new subscription at ${ctx.watermark}`);\n this.#next = rest;\n current.cancel();\n return 'switched';\n }\n }\n lc.warn?.(`switchover rejected. continuing current subscription`, msg);\n } catch (e) {\n lc.warn?.(`switchover failed. continuing current subscription`, e);\n } finally {\n clearTimeout(timer);\n }\n candidate?.cancel();\n return 'retry';\n }\n\n /**\n * Keeps the held (or granted) subscription open, and initiates a graceful\n * restart when permission to restore is granted. A held subscription that\n * has yet to be granted is cancelled if the `current` subscription ends.\n *\n * @returns `true` once permission is granted, or `false` if the held\n * subscription closes before then.\n */\n #holdForRestore(\n current: Downstream,\n held: Downstream,\n restore: NonNullable<Status['restore']>,\n ): Promise<boolean> {\n const lc = this.#lc;\n const result = resolver<boolean>();\n const unregister = this.#state.cancelOnStop(held);\n const onCurrentEnded = () => {\n if (!this.#restoreGranted) {\n lc.info?.(`abandoning held switchover subscription`);\n held.cancel();\n }\n };\n current.signal.addEventListener('abort', onCurrentEnded, {once: true});\n\n const onRestore = (r: NonNullable<Status['restore']>) => {\n if (r.state === 'queued') {\n lc.info?.(\n `waiting for permission to restore a new replica (position ${r.position})`,\n );\n } else if (!this.#restoreGranted) {\n lc.info?.(\n `granted permission to restore a new replica. restarting gracefully`,\n );\n this.#restoreGranted = true;\n this.#options.onRestoreGranted();\n result.resolve(true);\n }\n };\n onRestore(restore);\n void (async () => {\n try {\n // Note: The loop must not be exited early, as that would close the\n // connection.\n for await (const {data: msg} of held) {\n if (msg[0] === 'status' && msg[1].restore) {\n onRestore(msg[1].restore);\n }\n }\n } catch (e) {\n lc.warn?.(`held switchover subscription failed`, e);\n } finally {\n unregister();\n current.signal.removeEventListener('abort', onCurrentEnded);\n result.resolve(false);\n }\n })();\n return result.promise;\n }\n}\n"],"mappings":"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"}
@@ -1,11 +1,11 @@
1
1
  import { AbortError } from "../../../../shared/src/abort-error.js";
2
2
  import { Database } from "../../../../zqlite/src/db.js";
3
- import { mapPostgresToLiteIndex } from "../../db/pg-to-lite.js";
4
3
  import { getOrCreateCounter } from "../../observability/metrics.js";
4
+ import { RunningState } from "../running-state.js";
5
+ import { mapPostgresToLiteIndex } from "../../db/pg-to-lite.js";
6
+ import { StatementRunner } from "../../db/statements.js";
5
7
  import { readReplicaBackfills } from "./schema/backfilling.js";
6
8
  import { getSubscriptionState } from "./schema/replication-state.js";
7
- import { StatementRunner } from "../../db/statements.js";
8
- import { RunningState } from "../running-state.js";
9
9
  import { IndexingProgress } from "./replication-status.js";
10
10
  import { errorTypeToReadableName } from "../change-streamer/change-streamer.js";
11
11
  import { Notifier } from "./notifier.js";
@@ -13,7 +13,7 @@ import { DrainHandler } from "./drain-handler.js";
13
13
  import { ReplicationReportRecorder } from "./reporter/recorder.js";
14
14
  //#region ../zero-cache/src/services/replicator/incremental-sync.ts
15
15
  var MAX_WORKER_BATCH_MESSAGES = 256;
16
- var MAX_WORKER_BATCH_SIZE = 1024 * 1024;
16
+ var MAX_WORKER_BATCH_SIZE = 1048576;
17
17
  var MAX_OLDER_REPLICA_VERSION_REJECTIONS = 20;
18
18
  /**
19
19
  * The {@link IncrementalSyncer} manages a logical replication stream from upstream,
@@ -1 +1 @@
1
- {"version":3,"file":"incremental-sync.js","names":["#lc","#taskID","#id","#changeStreamer","#worker","#mode","#statusPublisher","#notifier","#reporter","#drainHandler","#state","#replicationEvents","#initialConnection","#committedContext","#subscriberContext","#handleResult","#olderReplicaVersionRejections"],"sources":["../../../../../../zero-cache/src/services/replicator/incremental-sync.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {AbortError} from '../../../../shared/src/abort-error.ts';\nimport type {Enum} from '../../../../shared/src/enum.ts';\nimport {Database} from '../../../../zqlite/src/db.ts';\nimport {mapPostgresToLiteIndex} from '../../db/pg-to-lite.ts';\nimport {StatementRunner} from '../../db/statements.ts';\nimport {getOrCreateCounter} from '../../observability/metrics.ts';\nimport type {Source} from '../../types/streams.ts';\nimport type {DownloadStatus} from '../change-source/protocol/current.ts';\nimport type {ChangeStreamData} from '../change-source/protocol/current/downstream.ts';\nimport type {ReservationFollowup} from '../change-streamer/change-streamer-http.ts';\nimport {\n errorTypeToReadableName,\n PROTOCOL_VERSION,\n type ChangeStreamer,\n type SubscriberContext,\n} from '../change-streamer/change-streamer.ts';\nimport type * as ErrorType from '../change-streamer/error-type-enum.ts';\nimport {WrongReplicaVersion} from '../change-streamer/error-type-enum.ts';\nimport type {SubscribeDownstream} from '../change-streamer/subscribe.ts';\nimport {RunningState} from '../running-state.ts';\nimport type {CommitResult} from './change-processor.ts';\nimport {\n DrainHandler,\n type Downstream,\n type SwitchoverOptions,\n} from './drain-handler.ts';\nimport {Notifier} from './notifier.ts';\nimport {\n IndexingProgress,\n type ReplicationStatusPublisher,\n} from './replication-status.ts';\nimport type {ReplicaState, ReplicatorMode} from './replicator.ts';\nimport {\n ReplicationReportRecorder,\n type ReplicationLagReadinessOptions,\n} from './reporter/recorder.ts';\nimport type {ReplicationReport} from './reporter/report-schema.ts';\nimport {readReplicaBackfills} from './schema/backfilling.ts';\nimport {getSubscriptionState} from './schema/replication-state.ts';\nimport type {WriteWorkerClient} from './write-worker-client.ts';\n\ntype ErrorType = Enum<typeof ErrorType>;\n\nconst MAX_WORKER_BATCH_MESSAGES = 256;\nconst MAX_WORKER_BATCH_SIZE = 1024 * 1024;\n\n// The number of times to reconnect after being rejected by a\n// replication-manager with an older replica version (e.g. one that has yet\n// to be replaced by a resync), before accepting the rejection and restarting\n// (e.g. if the upstream was legitimately replaced by one with a lower replica\n// version).\nconst MAX_OLDER_REPLICA_VERSION_REJECTIONS = 20;\n\n/**\n * The {@link IncrementalSyncer} manages a logical replication stream from upstream,\n * handling application lifecycle events (start, stop) and retrying the\n * connection with exponential backoff. The actual handling of the logical\n * replication messages is done by the {@link ChangeProcessor}, which runs\n * in a worker thread via the {@link WriteWorkerClient}.\n */\nexport class IncrementalSyncer {\n readonly #lc: LogContext;\n readonly #taskID: string;\n readonly #id: string;\n readonly #changeStreamer: ChangeStreamer;\n readonly #worker: WriteWorkerClient;\n readonly #mode: ReplicatorMode;\n readonly #statusPublisher: ReplicationStatusPublisher | null;\n readonly #notifier: Notifier;\n readonly #reporter: ReplicationReportRecorder;\n // Consumed (and cleared) by the first subscribe() in run()'s loop; every\n // subsequent (re)connection goes through #changeStreamer.subscribe().\n #initialConnection: ReservationFollowup | undefined;\n\n // Only set for serving replicas that switch over between\n // replication-managers.\n readonly #drainHandler: DrainHandler | undefined;\n #olderReplicaVersionRejections = 0;\n\n readonly #state = new RunningState('IncrementalSyncer');\n\n readonly #replicationEvents = getOrCreateCounter(\n 'replication',\n 'events',\n 'Number of replication events processed',\n );\n\n constructor(\n lc: LogContext,\n taskID: string,\n id: string,\n changeStreamer: ChangeStreamer,\n worker: WriteWorkerClient,\n mode: ReplicatorMode,\n statusPublisher: ReplicationStatusPublisher | null,\n replicationLagReadinessOptions: ReplicationLagReadinessOptions = {},\n initialConnection?: ReservationFollowup,\n switchover?: SwitchoverOptions,\n ) {\n this.#lc = lc;\n this.#taskID = taskID;\n this.#id = id;\n this.#changeStreamer = changeStreamer;\n this.#worker = worker;\n this.#mode = mode;\n this.#statusPublisher = statusPublisher;\n this.#notifier = new Notifier();\n this.#reporter = new ReplicationReportRecorder(\n lc,\n replicationLagReadinessOptions,\n );\n this.#initialConnection = initialConnection;\n // Only serving replicas switch over between replication-managers. In\n // particular, the in-RM backup-replicator never does.\n this.#drainHandler =\n mode === 'serving' && switchover\n ? new DrainHandler(lc, changeStreamer, this.#state, switchover, () =>\n this.#committedContext(switchover.replicaFile),\n )\n : undefined;\n }\n\n ready(): Promise<void> {\n return this.#reporter.ready();\n }\n\n async run() {\n const lc = this.#lc;\n let workerError: Error | undefined;\n this.#worker.onError(err => {\n workerError ??= err;\n this.#state.stop(lc, err);\n });\n lc.info?.(`Starting IncrementalSyncer`);\n const {watermark: initialWatermark} =\n await this.#worker.getSubscriptionState();\n\n // Notify any waiting subscribers that the replica is ready to be read.\n // This initial notification intentionally omits replicaReadyTimeMs because\n // it represents already-current state, not newly-unserved work.\n void this.#notifier.notifySubscribers({\n state: 'version-ready',\n watermark: initialWatermark,\n });\n\n while (this.#state.shouldRun()) {\n const {replicaVersion, watermark, backfills} =\n await this.#worker.getSubscriptionState();\n\n let downstream: Downstream | undefined;\n let unregister = () => {};\n let err: unknown | undefined;\n\n try {\n const ctx = this.#subscriberContext(\n replicaVersion,\n watermark,\n backfills,\n );\n // A successful switchover has already established the subscription\n // on a new connection.\n const switched = this.#drainHandler?.getNextConnection();\n // The first connection reuses the still-open reservation connection\n // (if any) from the backup restore, so the replication-manager that\n // reserved the change log is the one that serves the subscription.\n // Every reconnect after that opens a fresh connection.\n const initialConnection = this.#initialConnection;\n this.#initialConnection = undefined;\n downstream =\n switched ??\n (initialConnection\n ? await initialConnection.subscribe(ctx)\n : await this.#changeStreamer.subscribe(ctx));\n unregister = this.#state.cancelOnStop(downstream);\n this.#statusPublisher\n ?.publish(lc, 'Replicating', `Replicating from ${watermark}`)\n .watchGrowth(lc);\n\n let backfill:\n | {status: DownloadStatus; table: string; columns: string[]}\n | undefined;\n let writeBatch: ChangeStreamData[] = [];\n let writeBatchSize = 0;\n let inTransaction = false;\n // Indexes created in the current run of consecutive index creations.\n let indexing: IndexingProgress | undefined;\n\n const publishBackfillStatus = (table: string) =>\n this.#statusPublisher?.publish(\n lc,\n 'Replicating',\n `Backfilling ${table} table`,\n 3000,\n () =>\n backfill\n ? {\n downloadStatus: [\n {\n ...backfill.status,\n table: backfill.table,\n columns: backfill.columns,\n },\n ],\n }\n : {},\n );\n\n const flushWrites = async () => {\n if (writeBatch.length === 0) {\n return;\n }\n const batch = writeBatch;\n writeBatch = [];\n writeBatchSize = 0;\n\n const result = await this.#worker.processMessages(batch);\n this.#handleResult(lc, result);\n if (result?.completedBackfill) {\n backfill = undefined;\n }\n };\n\n // Whether the current transaction is being skipped.\n let skipping = false;\n\n // A subscription established by a switchover starts at the\n // watermark at which it was requested, and may thus include\n // transactions that were since committed from the previous\n // subscription.\n const shouldSkip = (message: SubscribeDownstream) => {\n const type = message[0];\n if (type === 'begin' && message[2].commitWatermark <= watermark) {\n lc.debug?.(\n `skipping committed transaction ${message[2].commitWatermark}`,\n );\n skipping = true;\n }\n if (\n skipping &&\n (type === 'begin' ||\n type === 'data' ||\n type === 'commit' ||\n type === 'rollback')\n ) {\n skipping = type !== 'commit' && type !== 'rollback';\n return true;\n }\n return false;\n };\n\n for await (const {data: message, size} of downstream) {\n if (shouldSkip(message)) {\n continue;\n }\n // Only reset backoff after receiving an actual message.\n this.#state.resetBackoff();\n\n this.#replicationEvents.add(1);\n switch (message[0]) {\n case 'reserved':\n lc.warn?.(`unexpected snapshot reservation message received`, {\n message: message[0],\n });\n break;\n case 'status': {\n const {lagReport, draining} = message[1];\n this.#olderReplicaVersionRejections = 0;\n if (draining) {\n this.#drainHandler?.onChangeStreamerDrain(downstream);\n }\n if (lagReport) {\n const report: ReplicationReport = {\n nextSendTimeMs: lagReport.nextSendTimeMs,\n };\n if (lagReport.lastTimings) {\n report.lastTimings = {\n ...lagReport.lastTimings,\n replicateTimeMs: Date.now(),\n };\n }\n this.#reporter.record(report);\n }\n break;\n }\n case 'error': {\n const {\n type,\n message: msg,\n replicaVersion: rmVersion,\n } = message[1];\n if (\n type === WrongReplicaVersion &&\n rmVersion !== undefined &&\n rmVersion < replicaVersion &&\n this.#olderReplicaVersionRejections++ <\n MAX_OLDER_REPLICA_VERSION_REJECTIONS\n ) {\n // The replication-manager is behind this replica (e.g. it\n // has yet to be replaced by a resync). Rather than restoring\n // its older replica, reconnect (with backoff), which may\n // reach a different replication-manager.\n lc.warn?.(\n `replication-manager is at an older replica version ` +\n `(${rmVersion}) than ${replicaVersion}. reconnecting`,\n );\n break;\n }\n // Signal from the replication-manager that the view-syncer must\n // shut down and restore a new backup from litestream.\n this.stop(\n lc,\n // Note: The AbortError indicates a clean / intentional shutdown.\n new AbortError(\n `${errorTypeToReadableName(type as ErrorType)}: ${msg}`,\n ),\n );\n break;\n }\n default: {\n const msg = message[1];\n if (msg.tag === 'backfill' && msg.status) {\n const {status, relation} = msg;\n const first = !backfill;\n backfill = {\n status, // Update the current status\n table: relation.name,\n columns: [...relation.rowKey.columns, ...msg.columns],\n };\n if (first) {\n // Start publishing the status every 3 seconds.\n publishBackfillStatus(relation.name);\n }\n }\n\n if (msg.tag === 'create-index' && this.#statusPublisher) {\n // Creating an index on an existing table can take a long\n // time. Flush preceding changes so that the index creation\n // is processed (and timed) on its own.\n await flushWrites();\n const index = mapPostgresToLiteIndex(msg.spec);\n indexing ??= new IndexingProgress();\n indexing.start(index);\n this.#statusPublisher.publish(\n lc,\n 'Replicating',\n `Creating index ${index.name} on ${index.tableName}`,\n 3000,\n indexing.state,\n );\n // Exclude the time spent publishing the status.\n indexing.restartTimer();\n writeBatch.push(message as ChangeStreamData);\n writeBatchSize += size;\n await flushWrites();\n const elapsed = indexing.finish();\n lc.info?.(\n `Created index ${index.name} (${elapsed.toFixed(3)} ms)`,\n );\n this.#statusPublisher.publish(\n lc,\n 'Replicating',\n `Created index ${index.name} on ${index.tableName}`,\n 0,\n indexing.state,\n );\n if (backfill) {\n // Resume reporting the progress of the ongoing backfill.\n publishBackfillStatus(backfill.table);\n }\n break;\n }\n indexing = undefined;\n\n const type = message[0];\n const invalidTransactionSequence =\n type === 'begin' ? inTransaction : !inTransaction;\n if (type === 'begin') {\n inTransaction = true;\n } else if (type === 'commit' || type === 'rollback') {\n inTransaction = false;\n }\n\n writeBatch.push(message as ChangeStreamData);\n writeBatchSize += size;\n if (\n // Waiting here ensures that consuming the commit, which ACKs\n // it upstream, only happens after the SQLite commit finishes.\n type === 'commit' ||\n type === 'rollback' ||\n // Promptly surface malformed transaction sequences instead\n // of leaving a partial batch waiting for another message.\n invalidTransactionSequence ||\n writeBatch.length >= MAX_WORKER_BATCH_MESSAGES ||\n writeBatchSize >= MAX_WORKER_BATCH_SIZE\n ) {\n await flushWrites();\n }\n break;\n }\n }\n }\n this.#worker.abort();\n } catch (e) {\n err = e;\n this.#worker.abort();\n } finally {\n downstream?.cancel();\n unregister();\n this.#statusPublisher?.stop();\n }\n if (err === undefined && this.#drainHandler?.hasNextConnection) {\n continue; // Switched over to a new subscription; no backoff.\n }\n this.#drainHandler?.getNextConnection()?.cancel();\n await this.#state.backoff(lc, err);\n }\n lc.info?.('IncrementalSyncer stopped');\n if (workerError) {\n throw workerError;\n }\n }\n\n #handleResult(lc: LogContext, result: CommitResult | null) {\n if (!result) {\n return;\n }\n if (result.completedBackfill) {\n // Publish the final status\n const status = result.completedBackfill;\n this.#statusPublisher?.publish(\n lc,\n 'Replicating',\n `Backfilled ${status.table} table`,\n 0,\n () => ({downloadStatus: [status]}),\n );\n } else if (result.schemaUpdated) {\n this.#statusPublisher?.publish(lc, 'Replicating', 'Schema updated');\n }\n if (result.watermark && result.changeLogUpdated) {\n void this.#notifier.notifySubscribers({\n state: 'version-ready',\n watermark: result.watermark,\n replicaReadyTimeMs: Date.now(),\n upstreamCommitTimeMs: result.upstreamCommitTimeMs,\n });\n }\n }\n\n subscribe(): Source<ReplicaState> {\n return this.#notifier.subscribe();\n }\n\n #subscriberContext(\n replicaVersion: string,\n watermark: string,\n backfills: SubscriberContext['backfills'],\n ): SubscriberContext {\n return {\n protocolVersion: PROTOCOL_VERSION,\n taskID: this.#taskID,\n id: this.#id,\n mode: this.#mode,\n watermark,\n replicaVersion,\n backfills,\n ...(this.#drainHandler ? {drainable: true} : {}),\n };\n }\n\n /**\n * Returns the subscriber context as of the last committed transaction,\n * read from the replica file (i.e. not from the write worker, whose\n * connection may be in the middle of a transaction).\n */\n #committedContext(replicaFile: string): SubscriberContext {\n const db = new Database(this.#lc, replicaFile, {readonly: true});\n try {\n const {replicaVersion, watermark, backfills} = db.transaction(() => ({\n ...getSubscriptionState(new StatementRunner(db)),\n backfills: readReplicaBackfills(db),\n }));\n return this.#subscriberContext(replicaVersion, watermark, backfills);\n } finally {\n db.close();\n }\n }\n\n stop(lc: LogContext, err?: unknown) {\n this.#state.stop(lc, err);\n // Abort any polling loop that the write worker may be in.\n this.#worker.abort();\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"incremental-sync.js","names":[],"sources":["../../../../../../zero-cache/src/services/replicator/incremental-sync.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {AbortError} from '../../../../shared/src/abort-error.ts';\nimport type {Enum} from '../../../../shared/src/enum.ts';\nimport {Database} from '../../../../zqlite/src/db.ts';\nimport {mapPostgresToLiteIndex} from '../../db/pg-to-lite.ts';\nimport {StatementRunner} from '../../db/statements.ts';\nimport {getOrCreateCounter} from '../../observability/metrics.ts';\nimport type {Source} from '../../types/streams.ts';\nimport type {DownloadStatus} from '../change-source/protocol/current.ts';\nimport type {ChangeStreamData} from '../change-source/protocol/current/downstream.ts';\nimport type {ReservationFollowup} from '../change-streamer/change-streamer-http.ts';\nimport {\n errorTypeToReadableName,\n PROTOCOL_VERSION,\n type ChangeStreamer,\n type SubscriberContext,\n} from '../change-streamer/change-streamer.ts';\nimport type * as ErrorType from '../change-streamer/error-type-enum.ts';\nimport {WrongReplicaVersion} from '../change-streamer/error-type-enum.ts';\nimport type {SubscribeDownstream} from '../change-streamer/subscribe.ts';\nimport {RunningState} from '../running-state.ts';\nimport type {CommitResult} from './change-processor.ts';\nimport {\n DrainHandler,\n type Downstream,\n type SwitchoverOptions,\n} from './drain-handler.ts';\nimport {Notifier} from './notifier.ts';\nimport {\n IndexingProgress,\n type ReplicationStatusPublisher,\n} from './replication-status.ts';\nimport type {ReplicaState, ReplicatorMode} from './replicator.ts';\nimport {\n ReplicationReportRecorder,\n type ReplicationLagReadinessOptions,\n} from './reporter/recorder.ts';\nimport type {ReplicationReport} from './reporter/report-schema.ts';\nimport {readReplicaBackfills} from './schema/backfilling.ts';\nimport {getSubscriptionState} from './schema/replication-state.ts';\nimport type {WriteWorkerClient} from './write-worker-client.ts';\n\ntype ErrorType = Enum<typeof ErrorType>;\n\nconst MAX_WORKER_BATCH_MESSAGES = 256;\nconst MAX_WORKER_BATCH_SIZE = 1024 * 1024;\n\n// The number of times to reconnect after being rejected by a\n// replication-manager with an older replica version (e.g. one that has yet\n// to be replaced by a resync), before accepting the rejection and restarting\n// (e.g. if the upstream was legitimately replaced by one with a lower replica\n// version).\nconst MAX_OLDER_REPLICA_VERSION_REJECTIONS = 20;\n\n/**\n * The {@link IncrementalSyncer} manages a logical replication stream from upstream,\n * handling application lifecycle events (start, stop) and retrying the\n * connection with exponential backoff. The actual handling of the logical\n * replication messages is done by the {@link ChangeProcessor}, which runs\n * in a worker thread via the {@link WriteWorkerClient}.\n */\nexport class IncrementalSyncer {\n readonly #lc: LogContext;\n readonly #taskID: string;\n readonly #id: string;\n readonly #changeStreamer: ChangeStreamer;\n readonly #worker: WriteWorkerClient;\n readonly #mode: ReplicatorMode;\n readonly #statusPublisher: ReplicationStatusPublisher | null;\n readonly #notifier: Notifier;\n readonly #reporter: ReplicationReportRecorder;\n // Consumed (and cleared) by the first subscribe() in run()'s loop; every\n // subsequent (re)connection goes through #changeStreamer.subscribe().\n #initialConnection: ReservationFollowup | undefined;\n\n // Only set for serving replicas that switch over between\n // replication-managers.\n readonly #drainHandler: DrainHandler | undefined;\n #olderReplicaVersionRejections = 0;\n\n readonly #state = new RunningState('IncrementalSyncer');\n\n readonly #replicationEvents = getOrCreateCounter(\n 'replication',\n 'events',\n 'Number of replication events processed',\n );\n\n constructor(\n lc: LogContext,\n taskID: string,\n id: string,\n changeStreamer: ChangeStreamer,\n worker: WriteWorkerClient,\n mode: ReplicatorMode,\n statusPublisher: ReplicationStatusPublisher | null,\n replicationLagReadinessOptions: ReplicationLagReadinessOptions = {},\n initialConnection?: ReservationFollowup,\n switchover?: SwitchoverOptions,\n ) {\n this.#lc = lc;\n this.#taskID = taskID;\n this.#id = id;\n this.#changeStreamer = changeStreamer;\n this.#worker = worker;\n this.#mode = mode;\n this.#statusPublisher = statusPublisher;\n this.#notifier = new Notifier();\n this.#reporter = new ReplicationReportRecorder(\n lc,\n replicationLagReadinessOptions,\n );\n this.#initialConnection = initialConnection;\n // Only serving replicas switch over between replication-managers. In\n // particular, the in-RM backup-replicator never does.\n this.#drainHandler =\n mode === 'serving' && switchover\n ? new DrainHandler(lc, changeStreamer, this.#state, switchover, () =>\n this.#committedContext(switchover.replicaFile),\n )\n : undefined;\n }\n\n ready(): Promise<void> {\n return this.#reporter.ready();\n }\n\n async run() {\n const lc = this.#lc;\n let workerError: Error | undefined;\n this.#worker.onError(err => {\n workerError ??= err;\n this.#state.stop(lc, err);\n });\n lc.info?.(`Starting IncrementalSyncer`);\n const {watermark: initialWatermark} =\n await this.#worker.getSubscriptionState();\n\n // Notify any waiting subscribers that the replica is ready to be read.\n // This initial notification intentionally omits replicaReadyTimeMs because\n // it represents already-current state, not newly-unserved work.\n void this.#notifier.notifySubscribers({\n state: 'version-ready',\n watermark: initialWatermark,\n });\n\n while (this.#state.shouldRun()) {\n const {replicaVersion, watermark, backfills} =\n await this.#worker.getSubscriptionState();\n\n let downstream: Downstream | undefined;\n let unregister = () => {};\n let err: unknown | undefined;\n\n try {\n const ctx = this.#subscriberContext(\n replicaVersion,\n watermark,\n backfills,\n );\n // A successful switchover has already established the subscription\n // on a new connection.\n const switched = this.#drainHandler?.getNextConnection();\n // The first connection reuses the still-open reservation connection\n // (if any) from the backup restore, so the replication-manager that\n // reserved the change log is the one that serves the subscription.\n // Every reconnect after that opens a fresh connection.\n const initialConnection = this.#initialConnection;\n this.#initialConnection = undefined;\n downstream =\n switched ??\n (initialConnection\n ? await initialConnection.subscribe(ctx)\n : await this.#changeStreamer.subscribe(ctx));\n unregister = this.#state.cancelOnStop(downstream);\n this.#statusPublisher\n ?.publish(lc, 'Replicating', `Replicating from ${watermark}`)\n .watchGrowth(lc);\n\n let backfill:\n | {status: DownloadStatus; table: string; columns: string[]}\n | undefined;\n let writeBatch: ChangeStreamData[] = [];\n let writeBatchSize = 0;\n let inTransaction = false;\n // Indexes created in the current run of consecutive index creations.\n let indexing: IndexingProgress | undefined;\n\n const publishBackfillStatus = (table: string) =>\n this.#statusPublisher?.publish(\n lc,\n 'Replicating',\n `Backfilling ${table} table`,\n 3000,\n () =>\n backfill\n ? {\n downloadStatus: [\n {\n ...backfill.status,\n table: backfill.table,\n columns: backfill.columns,\n },\n ],\n }\n : {},\n );\n\n const flushWrites = async () => {\n if (writeBatch.length === 0) {\n return;\n }\n const batch = writeBatch;\n writeBatch = [];\n writeBatchSize = 0;\n\n const result = await this.#worker.processMessages(batch);\n this.#handleResult(lc, result);\n if (result?.completedBackfill) {\n backfill = undefined;\n }\n };\n\n // Whether the current transaction is being skipped.\n let skipping = false;\n\n // A subscription established by a switchover starts at the\n // watermark at which it was requested, and may thus include\n // transactions that were since committed from the previous\n // subscription.\n const shouldSkip = (message: SubscribeDownstream) => {\n const type = message[0];\n if (type === 'begin' && message[2].commitWatermark <= watermark) {\n lc.debug?.(\n `skipping committed transaction ${message[2].commitWatermark}`,\n );\n skipping = true;\n }\n if (\n skipping &&\n (type === 'begin' ||\n type === 'data' ||\n type === 'commit' ||\n type === 'rollback')\n ) {\n skipping = type !== 'commit' && type !== 'rollback';\n return true;\n }\n return false;\n };\n\n for await (const {data: message, size} of downstream) {\n if (shouldSkip(message)) {\n continue;\n }\n // Only reset backoff after receiving an actual message.\n this.#state.resetBackoff();\n\n this.#replicationEvents.add(1);\n switch (message[0]) {\n case 'reserved':\n lc.warn?.(`unexpected snapshot reservation message received`, {\n message: message[0],\n });\n break;\n case 'status': {\n const {lagReport, draining} = message[1];\n this.#olderReplicaVersionRejections = 0;\n if (draining) {\n this.#drainHandler?.onChangeStreamerDrain(downstream);\n }\n if (lagReport) {\n const report: ReplicationReport = {\n nextSendTimeMs: lagReport.nextSendTimeMs,\n };\n if (lagReport.lastTimings) {\n report.lastTimings = {\n ...lagReport.lastTimings,\n replicateTimeMs: Date.now(),\n };\n }\n this.#reporter.record(report);\n }\n break;\n }\n case 'error': {\n const {\n type,\n message: msg,\n replicaVersion: rmVersion,\n } = message[1];\n if (\n type === WrongReplicaVersion &&\n rmVersion !== undefined &&\n rmVersion < replicaVersion &&\n this.#olderReplicaVersionRejections++ <\n MAX_OLDER_REPLICA_VERSION_REJECTIONS\n ) {\n // The replication-manager is behind this replica (e.g. it\n // has yet to be replaced by a resync). Rather than restoring\n // its older replica, reconnect (with backoff), which may\n // reach a different replication-manager.\n lc.warn?.(\n `replication-manager is at an older replica version ` +\n `(${rmVersion}) than ${replicaVersion}. reconnecting`,\n );\n break;\n }\n // Signal from the replication-manager that the view-syncer must\n // shut down and restore a new backup from litestream.\n this.stop(\n lc,\n // Note: The AbortError indicates a clean / intentional shutdown.\n new AbortError(\n `${errorTypeToReadableName(type as ErrorType)}: ${msg}`,\n ),\n );\n break;\n }\n default: {\n const msg = message[1];\n if (msg.tag === 'backfill' && msg.status) {\n const {status, relation} = msg;\n const first = !backfill;\n backfill = {\n status, // Update the current status\n table: relation.name,\n columns: [...relation.rowKey.columns, ...msg.columns],\n };\n if (first) {\n // Start publishing the status every 3 seconds.\n publishBackfillStatus(relation.name);\n }\n }\n\n if (msg.tag === 'create-index' && this.#statusPublisher) {\n // Creating an index on an existing table can take a long\n // time. Flush preceding changes so that the index creation\n // is processed (and timed) on its own.\n await flushWrites();\n const index = mapPostgresToLiteIndex(msg.spec);\n indexing ??= new IndexingProgress();\n indexing.start(index);\n this.#statusPublisher.publish(\n lc,\n 'Replicating',\n `Creating index ${index.name} on ${index.tableName}`,\n 3000,\n indexing.state,\n );\n // Exclude the time spent publishing the status.\n indexing.restartTimer();\n writeBatch.push(message as ChangeStreamData);\n writeBatchSize += size;\n await flushWrites();\n const elapsed = indexing.finish();\n lc.info?.(\n `Created index ${index.name} (${elapsed.toFixed(3)} ms)`,\n );\n this.#statusPublisher.publish(\n lc,\n 'Replicating',\n `Created index ${index.name} on ${index.tableName}`,\n 0,\n indexing.state,\n );\n if (backfill) {\n // Resume reporting the progress of the ongoing backfill.\n publishBackfillStatus(backfill.table);\n }\n break;\n }\n indexing = undefined;\n\n const type = message[0];\n const invalidTransactionSequence =\n type === 'begin' ? inTransaction : !inTransaction;\n if (type === 'begin') {\n inTransaction = true;\n } else if (type === 'commit' || type === 'rollback') {\n inTransaction = false;\n }\n\n writeBatch.push(message as ChangeStreamData);\n writeBatchSize += size;\n if (\n // Waiting here ensures that consuming the commit, which ACKs\n // it upstream, only happens after the SQLite commit finishes.\n type === 'commit' ||\n type === 'rollback' ||\n // Promptly surface malformed transaction sequences instead\n // of leaving a partial batch waiting for another message.\n invalidTransactionSequence ||\n writeBatch.length >= MAX_WORKER_BATCH_MESSAGES ||\n writeBatchSize >= MAX_WORKER_BATCH_SIZE\n ) {\n await flushWrites();\n }\n break;\n }\n }\n }\n this.#worker.abort();\n } catch (e) {\n err = e;\n this.#worker.abort();\n } finally {\n downstream?.cancel();\n unregister();\n this.#statusPublisher?.stop();\n }\n if (err === undefined && this.#drainHandler?.hasNextConnection) {\n continue; // Switched over to a new subscription; no backoff.\n }\n this.#drainHandler?.getNextConnection()?.cancel();\n await this.#state.backoff(lc, err);\n }\n lc.info?.('IncrementalSyncer stopped');\n if (workerError) {\n throw workerError;\n }\n }\n\n #handleResult(lc: LogContext, result: CommitResult | null) {\n if (!result) {\n return;\n }\n if (result.completedBackfill) {\n // Publish the final status\n const status = result.completedBackfill;\n this.#statusPublisher?.publish(\n lc,\n 'Replicating',\n `Backfilled ${status.table} table`,\n 0,\n () => ({downloadStatus: [status]}),\n );\n } else if (result.schemaUpdated) {\n this.#statusPublisher?.publish(lc, 'Replicating', 'Schema updated');\n }\n if (result.watermark && result.changeLogUpdated) {\n void this.#notifier.notifySubscribers({\n state: 'version-ready',\n watermark: result.watermark,\n replicaReadyTimeMs: Date.now(),\n upstreamCommitTimeMs: result.upstreamCommitTimeMs,\n });\n }\n }\n\n subscribe(): Source<ReplicaState> {\n return this.#notifier.subscribe();\n }\n\n #subscriberContext(\n replicaVersion: string,\n watermark: string,\n backfills: SubscriberContext['backfills'],\n ): SubscriberContext {\n return {\n protocolVersion: PROTOCOL_VERSION,\n taskID: this.#taskID,\n id: this.#id,\n mode: this.#mode,\n watermark,\n replicaVersion,\n backfills,\n ...(this.#drainHandler ? {drainable: true} : {}),\n };\n }\n\n /**\n * Returns the subscriber context as of the last committed transaction,\n * read from the replica file (i.e. not from the write worker, whose\n * connection may be in the middle of a transaction).\n */\n #committedContext(replicaFile: string): SubscriberContext {\n const db = new Database(this.#lc, replicaFile, {readonly: true});\n try {\n const {replicaVersion, watermark, backfills} = db.transaction(() => ({\n ...getSubscriptionState(new StatementRunner(db)),\n backfills: readReplicaBackfills(db),\n }));\n return this.#subscriberContext(replicaVersion, watermark, backfills);\n } finally {\n db.close();\n }\n }\n\n stop(lc: LogContext, err?: unknown) {\n this.#state.stop(lc, err);\n // Abort any polling loop that the write worker may be in.\n this.#worker.abort();\n }\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"notifier.js","names":["#eventEmitter","#lastStateReceived","#newSubscription"],"sources":["../../../../../../zero-cache/src/services/replicator/notifier.ts"],"sourcesContent":["import {EventEmitter} from 'eventemitter3';\nimport {\n type PendingResult,\n type Result,\n Subscription,\n} from '../../types/subscription.ts';\nimport type {ReplicaState, ReplicaStateNotifier} from './replicator.ts';\n\n/**\n * Handles the semantics of {@link ReplicatorVersionNotifier.subscribe()}\n * notifications, namely:\n *\n * * New subscribers are notified immediately with the latest received\n * ReplicaState.\n *\n * * Non-latest notifications are discarded if the subscriber is too\n * busy to consume them.\n *\n * By encapsulating the state for the first behavior (essentially, whether\n * the first notification has been sent by the Replicator), Notifier objects\n * can be chained to simplify fanout from Replicator to View Syncers.\n *\n * In particular, each Syncer Thread can manage a single Subscription to\n * the Replicator across a MessageChannel, which it uses for its own Notifier\n * instance to manage subscriptions from View Syncers within its thread. This\n * way a Replicator only deals with sending notifications to a bounded set\n * of MessageChannel-based subscribers (Syncer Threads), while the dynamic\n * subscribe and unsubscribe traffic from View Syncers remains within each\n * Syncer Thread.\n */\nfunction oldest(\n curr: number | undefined,\n prev: number | undefined,\n): number | undefined {\n if (curr === undefined) {\n return prev;\n }\n if (prev === undefined) {\n return curr;\n }\n return Math.min(curr, prev);\n}\n\nexport class Notifier implements ReplicaStateNotifier {\n readonly #eventEmitter = new EventEmitter();\n #lastStateReceived: ReplicaState | undefined;\n\n get latestState(): ReplicaState | undefined {\n return this.#lastStateReceived;\n }\n\n #newSubscription() {\n const notify = (state: ReplicaState) => subscription.push(state);\n const subscription = Subscription.create<ReplicaState>({\n // A coalesced notification stands in for every notification it\n // subsumed, so both timestamps keep the *oldest* value: they measure how\n // long work has been outstanding, and the subsumed watermarks are still\n // unserved.\n coalesce: (curr, prev) => ({\n ...curr,\n replicaReadyTimeMs: oldest(\n curr.replicaReadyTimeMs,\n prev.replicaReadyTimeMs,\n ),\n upstreamCommitTimeMs: oldest(\n curr.upstreamCommitTimeMs,\n prev.upstreamCommitTimeMs,\n ),\n }),\n cleanup: () => this.#eventEmitter.off('version', notify),\n });\n return {notify, subscription};\n }\n\n subscribe(): Subscription<ReplicaState> {\n const {notify, subscription} = this.#newSubscription();\n this.#eventEmitter.on('version', notify);\n if (this.#lastStateReceived) {\n // Per Replicator.subscribe() semantics, the current state of the\n // replica, if known, is immediately sent on subscribe.\n notify(this.#lastStateReceived);\n }\n return subscription;\n }\n\n notifySubscribers(\n state: ReplicaState = {state: 'version-ready'},\n ): Promise<Result>[] {\n this.#lastStateReceived = state;\n return this.#eventEmitter\n .listeners('version')\n .map(notify => notify(state) as unknown as PendingResult)\n .map(pending => pending.result);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AA8BA,SAAS,OACP,MACA,MACoB;CACpB,IAAI,SAAS,KAAA,GACX,OAAO;CAET,IAAI,SAAS,KAAA,GACX,OAAO;CAET,OAAO,KAAK,IAAI,MAAM,IAAI;AAC5B;AAEA,IAAa,WAAb,MAAsD;CACpD,gBAAyB,IAAI,aAAa;CAC1C;CAEA,IAAI,cAAwC;EAC1C,OAAO,KAAKC;CACd;CAEA,mBAAmB;EACjB,MAAM,UAAU,UAAwB,aAAa,KAAK,KAAK;EAC/D,MAAM,eAAe,aAAa,OAAqB;GAKrD,WAAW,MAAM,UAAU;IACzB,GAAG;IACH,oBAAoB,OAClB,KAAK,oBACL,KAAK,kBACP;IACA,sBAAsB,OACpB,KAAK,sBACL,KAAK,oBACP;GACF;GACA,eAAe,KAAKD,cAAc,IAAI,WAAW,MAAM;EACzD,CAAC;EACD,OAAO;GAAC;GAAQ;EAAY;CAC9B;CAEA,YAAwC;EACtC,MAAM,EAAC,QAAQ,iBAAgB,KAAKE,iBAAiB;EACrD,KAAKF,cAAc,GAAG,WAAW,MAAM;EACvC,IAAI,KAAKC,oBAGP,OAAO,KAAKA,kBAAkB;EAEhC,OAAO;CACT;CAEA,kBACE,QAAsB,EAAC,OAAO,gBAAe,GAC1B;EACnB,KAAKA,qBAAqB;EAC1B,OAAO,KAAKD,cACT,UAAU,SAAS,EACnB,KAAI,WAAU,OAAO,KAAK,CAA6B,EACvD,KAAI,YAAW,QAAQ,MAAM;CAClC;AACF"}
1
+ {"version":3,"file":"notifier.js","names":[],"sources":["../../../../../../zero-cache/src/services/replicator/notifier.ts"],"sourcesContent":["import {EventEmitter} from 'eventemitter3';\nimport {\n type PendingResult,\n type Result,\n Subscription,\n} from '../../types/subscription.ts';\nimport type {ReplicaState, ReplicaStateNotifier} from './replicator.ts';\n\n/**\n * Handles the semantics of {@link ReplicatorVersionNotifier.subscribe()}\n * notifications, namely:\n *\n * * New subscribers are notified immediately with the latest received\n * ReplicaState.\n *\n * * Non-latest notifications are discarded if the subscriber is too\n * busy to consume them.\n *\n * By encapsulating the state for the first behavior (essentially, whether\n * the first notification has been sent by the Replicator), Notifier objects\n * can be chained to simplify fanout from Replicator to View Syncers.\n *\n * In particular, each Syncer Thread can manage a single Subscription to\n * the Replicator across a MessageChannel, which it uses for its own Notifier\n * instance to manage subscriptions from View Syncers within its thread. This\n * way a Replicator only deals with sending notifications to a bounded set\n * of MessageChannel-based subscribers (Syncer Threads), while the dynamic\n * subscribe and unsubscribe traffic from View Syncers remains within each\n * Syncer Thread.\n */\nfunction oldest(\n curr: number | undefined,\n prev: number | undefined,\n): number | undefined {\n if (curr === undefined) {\n return prev;\n }\n if (prev === undefined) {\n return curr;\n }\n return Math.min(curr, prev);\n}\n\nexport class Notifier implements ReplicaStateNotifier {\n readonly #eventEmitter = new EventEmitter();\n #lastStateReceived: ReplicaState | undefined;\n\n get latestState(): ReplicaState | undefined {\n return this.#lastStateReceived;\n }\n\n #newSubscription() {\n const notify = (state: ReplicaState) => subscription.push(state);\n const subscription = Subscription.create<ReplicaState>({\n // A coalesced notification stands in for every notification it\n // subsumed, so both timestamps keep the *oldest* value: they measure how\n // long work has been outstanding, and the subsumed watermarks are still\n // unserved.\n coalesce: (curr, prev) => ({\n ...curr,\n replicaReadyTimeMs: oldest(\n curr.replicaReadyTimeMs,\n prev.replicaReadyTimeMs,\n ),\n upstreamCommitTimeMs: oldest(\n curr.upstreamCommitTimeMs,\n prev.upstreamCommitTimeMs,\n ),\n }),\n cleanup: () => this.#eventEmitter.off('version', notify),\n });\n return {notify, subscription};\n }\n\n subscribe(): Subscription<ReplicaState> {\n const {notify, subscription} = this.#newSubscription();\n this.#eventEmitter.on('version', notify);\n if (this.#lastStateReceived) {\n // Per Replicator.subscribe() semantics, the current state of the\n // replica, if known, is immediately sent on subscribe.\n notify(this.#lastStateReceived);\n }\n return subscription;\n }\n\n notifySubscribers(\n state: ReplicaState = {state: 'version-ready'},\n ): Promise<Result>[] {\n this.#lastStateReceived = state;\n return this.#eventEmitter\n .listeners('version')\n .map(notify => notify(state) as unknown as PendingResult)\n .map(pending => pending.result);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AA8BA,SAAS,OACP,MACA,MACoB;CACpB,IAAI,SAAS,KAAA,GACX,OAAO;CAET,IAAI,SAAS,KAAA,GACX,OAAO;CAET,OAAO,KAAK,IAAI,MAAM,IAAI;AAC5B;AAEA,IAAa,WAAb,MAAsD;CACpD,gBAAyB,IAAI,aAAa;CAC1C;CAEA,IAAI,cAAwC;EAC1C,OAAO,KAAK;CACd;CAEA,mBAAmB;EACjB,MAAM,UAAU,UAAwB,aAAa,KAAK,KAAK;EAC/D,MAAM,eAAe,aAAa,OAAqB;GAKrD,WAAW,MAAM,UAAU;IACzB,GAAG;IACH,oBAAoB,OAClB,KAAK,oBACL,KAAK,kBACP;IACA,sBAAsB,OACpB,KAAK,sBACL,KAAK,oBACP;GACF;GACA,eAAe,KAAK,cAAc,IAAI,WAAW,MAAM;EACzD,CAAC;EACD,OAAO;GAAC;GAAQ;EAAY;CAC9B;CAEA,YAAwC;EACtC,MAAM,EAAC,QAAQ,iBAAgB,KAAK,iBAAiB;EACrD,KAAK,cAAc,GAAG,WAAW,MAAM;EACvC,IAAI,KAAK,oBAGP,OAAO,KAAK,kBAAkB;EAEhC,OAAO;CACT;CAEA,kBACE,QAAsB,EAAC,OAAO,gBAAe,GAC1B;EACnB,KAAK,qBAAqB;EAC1B,OAAO,KAAK,cACT,UAAU,SAAS,CAAC,CACpB,KAAI,WAAU,OAAO,KAAK,CAA6B,CAAC,CACxD,KAAI,YAAW,QAAQ,MAAM;CAClC;AACF"}
@@ -191,7 +191,7 @@ var IndexingProgress = class {
191
191
  }
192
192
  };
193
193
  async function publishReplicationError(lc, stage, description, errorDetails, now = /* @__PURE__ */ new Date()) {
194
- await publishCriticalEvent(lc, {
194
+ const event = {
195
195
  type: "zero/events/status/replication/v1",
196
196
  component: "replication",
197
197
  status: "ERROR",
@@ -199,7 +199,8 @@ async function publishReplicationError(lc, stage, description, errorDetails, now
199
199
  description,
200
200
  errorDetails,
201
201
  time: now.toISOString()
202
- });
202
+ };
203
+ await publishCriticalEvent(lc, event);
203
204
  }
204
205
  function replicationStatusError(lc, stage, e, db, now = /* @__PURE__ */ new Date()) {
205
206
  const event = replicationStatusEvent(lc, db, stage, "ERROR", String(e), now);
@@ -271,6 +272,6 @@ function getReplicaSize(db) {
271
272
  return pageCount * pageSize;
272
273
  }
273
274
  //#endregion
274
- export { IndexingProgress, ReplicationStatusPublisher, publishReplicationError, replicationStatusError };
275
+ export { IndexingProgress, ReplicationStatusPublisher, publishReplicationError, replicationStatusError, replicationStatusEvent };
275
276
 
276
277
  //# sourceMappingURL=replication-status.js.map