@rocicorp/zero 1.11.0-canary.3 → 1.11.0-canary.30

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 (988) hide show
  1. package/out/analyze-query/src/analyze-cli.js +4 -4
  2. package/out/analyze-query/src/analyze-cli.js.map +1 -1
  3. package/out/analyze-query/src/bin-analyze.js +13 -12
  4. package/out/analyze-query/src/bin-analyze.js.map +1 -1
  5. package/out/analyze-query/src/bin-transform.js +1 -1
  6. package/out/analyze-query/src/bin-transform.js.map +1 -1
  7. package/out/ast-to-zql/src/ast-to-zql.d.ts +8 -1
  8. package/out/ast-to-zql/src/ast-to-zql.d.ts.map +1 -1
  9. package/out/ast-to-zql/src/ast-to-zql.js +25 -25
  10. package/out/ast-to-zql/src/ast-to-zql.js.map +1 -1
  11. package/out/otel/src/log-options.d.ts +16 -0
  12. package/out/otel/src/log-options.d.ts.map +1 -1
  13. package/out/otel/src/log-options.js +60 -6
  14. package/out/otel/src/log-options.js.map +1 -1
  15. package/out/replicache/src/bg-interval.d.ts +2 -1
  16. package/out/replicache/src/bg-interval.d.ts.map +1 -1
  17. package/out/replicache/src/bg-interval.js +13 -4
  18. package/out/replicache/src/bg-interval.js.map +1 -1
  19. package/out/replicache/src/btree/node.d.ts.map +1 -1
  20. package/out/replicache/src/btree/node.js +3 -6
  21. package/out/replicache/src/btree/node.js.map +1 -1
  22. package/out/replicache/src/dag/gc.d.ts.map +1 -1
  23. package/out/replicache/src/dag/gc.js +8 -11
  24. package/out/replicache/src/dag/gc.js.map +1 -1
  25. package/out/replicache/src/dag/invalid-ref-count-error.d.ts +12 -0
  26. package/out/replicache/src/dag/invalid-ref-count-error.d.ts.map +1 -0
  27. package/out/replicache/src/dag/invalid-ref-count-error.js +19 -0
  28. package/out/replicache/src/dag/invalid-ref-count-error.js.map +1 -0
  29. package/out/replicache/src/dag/lazy-store.d.ts +17 -4
  30. package/out/replicache/src/dag/lazy-store.d.ts.map +1 -1
  31. package/out/replicache/src/dag/lazy-store.js +35 -9
  32. package/out/replicache/src/dag/lazy-store.js.map +1 -1
  33. package/out/replicache/src/dag/store-impl.d.ts +12 -2
  34. package/out/replicache/src/dag/store-impl.d.ts.map +1 -1
  35. package/out/replicache/src/dag/store-impl.js +29 -9
  36. package/out/replicache/src/dag/store-impl.js.map +1 -1
  37. package/out/replicache/src/db/rebase.d.ts +14 -2
  38. package/out/replicache/src/db/rebase.d.ts.map +1 -1
  39. package/out/replicache/src/db/rebase.js +27 -5
  40. package/out/replicache/src/db/rebase.js.map +1 -1
  41. package/out/replicache/src/get-kv-store-provider.d.ts +1 -1
  42. package/out/replicache/src/get-kv-store-provider.d.ts.map +1 -1
  43. package/out/replicache/src/get-kv-store-provider.js +4 -4
  44. package/out/replicache/src/get-kv-store-provider.js.map +1 -1
  45. package/out/replicache/src/kv/expo-sqlite/store.d.ts.map +1 -1
  46. package/out/replicache/src/kv/expo-sqlite/store.js +28 -5
  47. package/out/replicache/src/kv/expo-sqlite/store.js.map +1 -1
  48. package/out/replicache/src/kv/idb-store.d.ts +18 -0
  49. package/out/replicache/src/kv/idb-store.d.ts.map +1 -1
  50. package/out/replicache/src/kv/idb-store.js +30 -2
  51. package/out/replicache/src/kv/idb-store.js.map +1 -1
  52. package/out/replicache/src/kv/mem-fallback-store.d.ts +54 -0
  53. package/out/replicache/src/kv/mem-fallback-store.d.ts.map +1 -0
  54. package/out/replicache/src/kv/mem-fallback-store.js +177 -0
  55. package/out/replicache/src/kv/mem-fallback-store.js.map +1 -0
  56. package/out/replicache/src/kv/mem-store.d.ts +1 -0
  57. package/out/replicache/src/kv/mem-store.d.ts.map +1 -1
  58. package/out/replicache/src/kv/mem-store.js +3 -0
  59. package/out/replicache/src/kv/mem-store.js.map +1 -1
  60. package/out/replicache/src/kv/op-sqlite/store.d.ts.map +1 -1
  61. package/out/replicache/src/kv/op-sqlite/store.js +4 -4
  62. package/out/replicache/src/kv/op-sqlite/store.js.map +1 -1
  63. package/out/replicache/src/kv/sqlite-store.d.ts +22 -1
  64. package/out/replicache/src/kv/sqlite-store.d.ts.map +1 -1
  65. package/out/replicache/src/kv/sqlite-store.js +159 -14
  66. package/out/replicache/src/kv/sqlite-store.js.map +1 -1
  67. package/out/replicache/src/kv/store.d.ts +6 -0
  68. package/out/replicache/src/kv/store.d.ts.map +1 -1
  69. package/out/replicache/src/new-client-channel.js.map +1 -1
  70. package/out/replicache/src/persist/client-gc.d.ts +2 -1
  71. package/out/replicache/src/persist/client-gc.d.ts.map +1 -1
  72. package/out/replicache/src/persist/client-gc.js +2 -2
  73. package/out/replicache/src/persist/client-gc.js.map +1 -1
  74. package/out/replicache/src/persist/client-group-gc.d.ts +2 -1
  75. package/out/replicache/src/persist/client-group-gc.d.ts.map +1 -1
  76. package/out/replicache/src/persist/client-group-gc.js +2 -2
  77. package/out/replicache/src/persist/client-group-gc.js.map +1 -1
  78. package/out/replicache/src/persist/clients.d.ts +2 -2
  79. package/out/replicache/src/persist/collect-idb-databases.d.ts +28 -8
  80. package/out/replicache/src/persist/collect-idb-databases.d.ts.map +1 -1
  81. package/out/replicache/src/persist/collect-idb-databases.js +97 -20
  82. package/out/replicache/src/persist/collect-idb-databases.js.map +1 -1
  83. package/out/replicache/src/persist/heartbeat.d.ts +2 -1
  84. package/out/replicache/src/persist/heartbeat.d.ts.map +1 -1
  85. package/out/replicache/src/persist/heartbeat.js +2 -2
  86. package/out/replicache/src/persist/heartbeat.js.map +1 -1
  87. package/out/replicache/src/persist/idb-databases-store-db-name.js +1 -1
  88. package/out/replicache/src/persist/idb-databases-store-db-name.js.map +1 -1
  89. package/out/replicache/src/persist/persist.d.ts.map +1 -1
  90. package/out/replicache/src/persist/persist.js +18 -8
  91. package/out/replicache/src/persist/persist.js.map +1 -1
  92. package/out/replicache/src/persist/refresh.js +6 -2
  93. package/out/replicache/src/persist/refresh.js.map +1 -1
  94. package/out/replicache/src/replicache-impl.d.ts +85 -3
  95. package/out/replicache/src/replicache-impl.d.ts.map +1 -1
  96. package/out/replicache/src/replicache-impl.js +321 -29
  97. package/out/replicache/src/replicache-impl.js.map +1 -1
  98. package/out/replicache/src/replicache-options.d.ts +9 -0
  99. package/out/replicache/src/replicache-options.d.ts.map +1 -1
  100. package/out/replicache/src/storage-failure.d.ts +37 -0
  101. package/out/replicache/src/storage-failure.d.ts.map +1 -0
  102. package/out/replicache/src/storage-failure.js +31 -0
  103. package/out/replicache/src/storage-failure.js.map +1 -0
  104. package/out/shared/src/arrays.d.ts +5 -0
  105. package/out/shared/src/arrays.d.ts.map +1 -1
  106. package/out/shared/src/arrays.js +8 -10
  107. package/out/shared/src/arrays.js.map +1 -1
  108. package/out/shared/src/base64.d.ts +19 -0
  109. package/out/shared/src/base64.d.ts.map +1 -0
  110. package/out/shared/src/base64.js +40 -0
  111. package/out/shared/src/base64.js.map +1 -0
  112. package/out/shared/src/centroid.d.ts +0 -1
  113. package/out/shared/src/centroid.d.ts.map +1 -1
  114. package/out/shared/src/centroid.js +1 -4
  115. package/out/shared/src/centroid.js.map +1 -1
  116. package/out/shared/src/error.d.ts +11 -0
  117. package/out/shared/src/error.d.ts.map +1 -1
  118. package/out/shared/src/error.js +35 -1
  119. package/out/shared/src/error.js.map +1 -1
  120. package/out/shared/src/hash.d.ts.map +1 -1
  121. package/out/shared/src/hash.js +32 -7
  122. package/out/shared/src/hash.js.map +1 -1
  123. package/out/shared/src/iterables.d.ts +2 -0
  124. package/out/shared/src/iterables.d.ts.map +1 -1
  125. package/out/shared/src/iterables.js +18 -1
  126. package/out/shared/src/iterables.js.map +1 -1
  127. package/out/shared/src/map.d.ts +24 -2
  128. package/out/shared/src/map.d.ts.map +1 -1
  129. package/out/shared/src/map.js +18 -4
  130. package/out/shared/src/map.js.map +1 -1
  131. package/out/shared/src/options-types.d.ts +2 -2
  132. package/out/shared/src/options.d.ts.map +1 -1
  133. package/out/shared/src/options.js +10 -7
  134. package/out/shared/src/options.js.map +1 -1
  135. package/out/shared/src/packed-boolean-map.d.ts +7 -0
  136. package/out/shared/src/packed-boolean-map.d.ts.map +1 -0
  137. package/out/shared/src/packed-boolean-map.js +36 -0
  138. package/out/shared/src/packed-boolean-map.js.map +1 -0
  139. package/out/shared/src/random-values.js +12 -1
  140. package/out/shared/src/random-values.js.map +1 -1
  141. package/out/shared/src/ring-buffer.d.ts +10 -0
  142. package/out/shared/src/ring-buffer.d.ts.map +1 -1
  143. package/out/shared/src/ring-buffer.js +26 -1
  144. package/out/shared/src/ring-buffer.js.map +1 -1
  145. package/out/shared/src/tdigest.d.ts +10 -0
  146. package/out/shared/src/tdigest.d.ts.map +1 -1
  147. package/out/shared/src/tdigest.js +147 -63
  148. package/out/shared/src/tdigest.js.map +1 -1
  149. package/out/shared/src/valita.d.ts +13 -0
  150. package/out/shared/src/valita.d.ts.map +1 -1
  151. package/out/shared/src/valita.js +23 -23
  152. package/out/shared/src/valita.js.map +1 -1
  153. package/out/z2s/src/compiler.d.ts.map +1 -1
  154. package/out/z2s/src/compiler.js +10 -6
  155. package/out/z2s/src/compiler.js.map +1 -1
  156. package/out/z2s/src/sql.d.ts.map +1 -1
  157. package/out/z2s/src/sql.js +9 -5
  158. package/out/z2s/src/sql.js.map +1 -1
  159. package/out/zero/package.js +4 -5
  160. package/out/zero/package.js.map +1 -1
  161. package/out/zero/src/zero.js +2 -1
  162. package/out/zero-cache/src/auth/write-authorizer.d.ts.map +1 -1
  163. package/out/zero-cache/src/auth/write-authorizer.js +1 -0
  164. package/out/zero-cache/src/auth/write-authorizer.js.map +1 -1
  165. package/out/zero-cache/src/config/normalize.d.ts +1 -0
  166. package/out/zero-cache/src/config/normalize.d.ts.map +1 -1
  167. package/out/zero-cache/src/config/normalize.js +46 -4
  168. package/out/zero-cache/src/config/normalize.js.map +1 -1
  169. package/out/zero-cache/src/config/zero-config.d.ts +116 -24
  170. package/out/zero-cache/src/config/zero-config.d.ts.map +1 -1
  171. package/out/zero-cache/src/config/zero-config.js +409 -157
  172. package/out/zero-cache/src/config/zero-config.js.map +1 -1
  173. package/out/zero-cache/src/custom/fetch.d.ts +1 -1
  174. package/out/zero-cache/src/custom/fetch.d.ts.map +1 -1
  175. package/out/zero-cache/src/custom/fetch.js.map +1 -1
  176. package/out/zero-cache/src/db/lite-tables.d.ts.map +1 -1
  177. package/out/zero-cache/src/db/lite-tables.js +3 -4
  178. package/out/zero-cache/src/db/lite-tables.js.map +1 -1
  179. package/out/zero-cache/src/db/migration-lite.d.ts.map +1 -1
  180. package/out/zero-cache/src/db/migration-lite.js +5 -3
  181. package/out/zero-cache/src/db/migration-lite.js.map +1 -1
  182. package/out/zero-cache/src/observability/events.js +4 -1
  183. package/out/zero-cache/src/observability/events.js.map +1 -1
  184. package/out/zero-cache/src/observability/log-throttle.d.ts +44 -0
  185. package/out/zero-cache/src/observability/log-throttle.d.ts.map +1 -0
  186. package/out/zero-cache/src/observability/log-throttle.js +76 -0
  187. package/out/zero-cache/src/observability/log-throttle.js.map +1 -0
  188. package/out/zero-cache/src/observability/metrics.d.ts.map +1 -1
  189. package/out/zero-cache/src/observability/metrics.js +2 -7
  190. package/out/zero-cache/src/observability/metrics.js.map +1 -1
  191. package/out/zero-cache/src/scripts/permissions.d.ts +16 -0
  192. package/out/zero-cache/src/scripts/permissions.d.ts.map +1 -1
  193. package/out/zero-cache/src/scripts/permissions.js +3 -3
  194. package/out/zero-cache/src/scripts/permissions.js.map +1 -1
  195. package/out/zero-cache/src/server/change-streamer.d.ts.map +1 -1
  196. package/out/zero-cache/src/server/change-streamer.js +117 -77
  197. package/out/zero-cache/src/server/change-streamer.js.map +1 -1
  198. package/out/zero-cache/src/server/inspector-delegate.d.ts +28 -2
  199. package/out/zero-cache/src/server/inspector-delegate.d.ts.map +1 -1
  200. package/out/zero-cache/src/server/inspector-delegate.js +37 -17
  201. package/out/zero-cache/src/server/inspector-delegate.js.map +1 -1
  202. package/out/zero-cache/src/server/main.d.ts.map +1 -1
  203. package/out/zero-cache/src/server/main.js +8 -1
  204. package/out/zero-cache/src/server/main.js.map +1 -1
  205. package/out/zero-cache/src/server/mutator.js +2 -0
  206. package/out/zero-cache/src/server/mutator.js.map +1 -1
  207. package/out/zero-cache/src/server/reaper.d.ts.map +1 -1
  208. package/out/zero-cache/src/server/reaper.js +2 -0
  209. package/out/zero-cache/src/server/reaper.js.map +1 -1
  210. package/out/zero-cache/src/server/replicator.d.ts +3 -0
  211. package/out/zero-cache/src/server/replicator.d.ts.map +1 -1
  212. package/out/zero-cache/src/server/replicator.js +95 -21
  213. package/out/zero-cache/src/server/replicator.js.map +1 -1
  214. package/out/zero-cache/src/server/runner/zero-dispatcher.d.ts.map +1 -1
  215. package/out/zero-cache/src/server/runner/zero-dispatcher.js +5 -0
  216. package/out/zero-cache/src/server/runner/zero-dispatcher.js.map +1 -1
  217. package/out/zero-cache/src/server/syncer-assigner.d.ts +14 -0
  218. package/out/zero-cache/src/server/syncer-assigner.d.ts.map +1 -0
  219. package/out/zero-cache/src/server/syncer-assigner.js +72 -0
  220. package/out/zero-cache/src/server/syncer-assigner.js.map +1 -0
  221. package/out/zero-cache/src/server/syncer.d.ts.map +1 -1
  222. package/out/zero-cache/src/server/syncer.js +24 -2
  223. package/out/zero-cache/src/server/syncer.js.map +1 -1
  224. package/out/zero-cache/src/server/worker-dispatcher.d.ts.map +1 -1
  225. package/out/zero-cache/src/server/worker-dispatcher.js +21 -4
  226. package/out/zero-cache/src/server/worker-dispatcher.js.map +1 -1
  227. package/out/zero-cache/src/services/analyze.d.ts.map +1 -1
  228. package/out/zero-cache/src/services/analyze.js +11 -9
  229. package/out/zero-cache/src/services/analyze.js.map +1 -1
  230. package/out/zero-cache/src/services/change-source/common/backfill-manager.d.ts.map +1 -1
  231. package/out/zero-cache/src/services/change-source/common/backfill-manager.js +198 -24
  232. package/out/zero-cache/src/services/change-source/common/backfill-manager.js.map +1 -1
  233. package/out/zero-cache/src/services/change-source/common/change-stream-multiplexer.d.ts.map +1 -1
  234. package/out/zero-cache/src/services/change-source/common/change-stream-multiplexer.js +16 -4
  235. package/out/zero-cache/src/services/change-source/common/change-stream-multiplexer.js.map +1 -1
  236. package/out/zero-cache/src/services/change-source/common/init-cleanup.d.ts +24 -0
  237. package/out/zero-cache/src/services/change-source/common/init-cleanup.d.ts.map +1 -0
  238. package/out/zero-cache/src/services/change-source/common/init-cleanup.js +44 -0
  239. package/out/zero-cache/src/services/change-source/common/init-cleanup.js.map +1 -0
  240. package/out/zero-cache/src/services/change-source/common/replica-restore.d.ts +92 -2
  241. package/out/zero-cache/src/services/change-source/common/replica-restore.d.ts.map +1 -1
  242. package/out/zero-cache/src/services/change-source/common/replica-restore.js +27 -10
  243. package/out/zero-cache/src/services/change-source/common/replica-restore.js.map +1 -1
  244. package/out/zero-cache/src/services/change-source/common/replica-schema.d.ts +1 -0
  245. package/out/zero-cache/src/services/change-source/common/replica-schema.d.ts.map +1 -1
  246. package/out/zero-cache/src/services/change-source/common/replica-schema.js +15 -3
  247. package/out/zero-cache/src/services/change-source/common/replica-schema.js.map +1 -1
  248. package/out/zero-cache/src/services/change-source/custom/change-source.d.ts +1 -1
  249. package/out/zero-cache/src/services/change-source/custom/change-source.d.ts.map +1 -1
  250. package/out/zero-cache/src/services/change-source/custom/change-source.js +7 -3
  251. package/out/zero-cache/src/services/change-source/custom/change-source.js.map +1 -1
  252. package/out/zero-cache/src/services/change-source/pg/backfill-stream.d.ts +9 -0
  253. package/out/zero-cache/src/services/change-source/pg/backfill-stream.d.ts.map +1 -1
  254. package/out/zero-cache/src/services/change-source/pg/backfill-stream.js +206 -19
  255. package/out/zero-cache/src/services/change-source/pg/backfill-stream.js.map +1 -1
  256. package/out/zero-cache/src/services/change-source/pg/change-source-init.d.ts +55 -0
  257. package/out/zero-cache/src/services/change-source/pg/change-source-init.d.ts.map +1 -0
  258. package/out/zero-cache/src/services/change-source/pg/change-source-init.js +305 -0
  259. package/out/zero-cache/src/services/change-source/pg/change-source-init.js.map +1 -0
  260. package/out/zero-cache/src/services/change-source/pg/change-source.d.ts +31 -18
  261. package/out/zero-cache/src/services/change-source/pg/change-source.d.ts.map +1 -1
  262. package/out/zero-cache/src/services/change-source/pg/change-source.js +130 -157
  263. package/out/zero-cache/src/services/change-source/pg/change-source.js.map +1 -1
  264. package/out/zero-cache/src/services/change-source/pg/initial-sync.d.ts +38 -2
  265. package/out/zero-cache/src/services/change-source/pg/initial-sync.d.ts.map +1 -1
  266. package/out/zero-cache/src/services/change-source/pg/initial-sync.js +55 -21
  267. package/out/zero-cache/src/services/change-source/pg/initial-sync.js.map +1 -1
  268. package/out/zero-cache/src/services/change-source/pg/logical-replication/stream.d.ts +31 -0
  269. package/out/zero-cache/src/services/change-source/pg/logical-replication/stream.d.ts.map +1 -1
  270. package/out/zero-cache/src/services/change-source/pg/logical-replication/stream.js +102 -3
  271. package/out/zero-cache/src/services/change-source/pg/logical-replication/stream.js.map +1 -1
  272. package/out/zero-cache/src/services/change-source/pg/replication-slot-cleanup-monitor.d.ts +16 -0
  273. package/out/zero-cache/src/services/change-source/pg/replication-slot-cleanup-monitor.d.ts.map +1 -0
  274. package/out/zero-cache/src/services/change-source/pg/replication-slot-cleanup-monitor.js +113 -0
  275. package/out/zero-cache/src/services/change-source/pg/replication-slot-cleanup-monitor.js.map +1 -0
  276. package/out/zero-cache/src/services/change-source/pg/replication-slots.d.ts +40 -15
  277. package/out/zero-cache/src/services/change-source/pg/replication-slots.d.ts.map +1 -1
  278. package/out/zero-cache/src/services/change-source/pg/replication-slots.js +149 -27
  279. package/out/zero-cache/src/services/change-source/pg/replication-slots.js.map +1 -1
  280. package/out/zero-cache/src/services/change-source/pg/schema/index-predicate.d.ts.map +1 -1
  281. package/out/zero-cache/src/services/change-source/pg/schema/index-predicate.js +68 -8
  282. package/out/zero-cache/src/services/change-source/pg/schema/index-predicate.js.map +1 -1
  283. package/out/zero-cache/src/services/change-source/pg/schema/init.d.ts.map +1 -1
  284. package/out/zero-cache/src/services/change-source/pg/schema/init.js +32 -1
  285. package/out/zero-cache/src/services/change-source/pg/schema/init.js.map +1 -1
  286. package/out/zero-cache/src/services/change-source/pg/schema/replica-stage-enum.d.ts +10 -0
  287. package/out/zero-cache/src/services/change-source/pg/schema/replica-stage-enum.d.ts.map +1 -0
  288. package/out/zero-cache/src/services/change-source/pg/schema/replica-stage-enum.js +6 -0
  289. package/out/zero-cache/src/services/change-source/pg/schema/replica-stage-enum.js.map +1 -0
  290. package/out/zero-cache/src/services/change-source/pg/schema/shard.d.ts +50 -27
  291. package/out/zero-cache/src/services/change-source/pg/schema/shard.d.ts.map +1 -1
  292. package/out/zero-cache/src/services/change-source/pg/schema/shard.js +98 -34
  293. package/out/zero-cache/src/services/change-source/pg/schema/shard.js.map +1 -1
  294. package/out/zero-cache/src/services/change-source/protocol/backfill-progress.d.ts +68 -0
  295. package/out/zero-cache/src/services/change-source/protocol/backfill-progress.d.ts.map +1 -0
  296. package/out/zero-cache/src/services/change-source/protocol/backfill-progress.js +141 -0
  297. package/out/zero-cache/src/services/change-source/protocol/backfill-progress.js.map +1 -0
  298. package/out/zero-cache/src/services/change-source/protocol/current/data.d.ts +45 -2
  299. package/out/zero-cache/src/services/change-source/protocol/current/data.d.ts.map +1 -1
  300. package/out/zero-cache/src/services/change-source/protocol/current/data.js +10 -1
  301. package/out/zero-cache/src/services/change-source/protocol/current/data.js.map +1 -1
  302. package/out/zero-cache/src/services/change-source/protocol/current/downstream.d.ts +60 -3
  303. package/out/zero-cache/src/services/change-source/protocol/current/downstream.d.ts.map +1 -1
  304. package/out/zero-cache/src/services/change-source/protocol/current/upstream.d.ts +23 -10
  305. package/out/zero-cache/src/services/change-source/protocol/current/upstream.d.ts.map +1 -1
  306. package/out/zero-cache/src/services/change-source/protocol/current/upstream.js +17 -7
  307. package/out/zero-cache/src/services/change-source/protocol/current/upstream.js.map +1 -1
  308. package/out/zero-cache/src/services/change-source/protocol/current.js +2 -1
  309. package/out/zero-cache/src/services/change-streamer/backfill-state-tracker.d.ts +72 -0
  310. package/out/zero-cache/src/services/change-streamer/backfill-state-tracker.d.ts.map +1 -0
  311. package/out/zero-cache/src/services/change-streamer/backfill-state-tracker.js +162 -0
  312. package/out/zero-cache/src/services/change-streamer/backfill-state-tracker.js.map +1 -0
  313. package/out/zero-cache/src/services/change-streamer/backfill-state.d.ts +50 -0
  314. package/out/zero-cache/src/services/change-streamer/backfill-state.d.ts.map +1 -0
  315. package/out/zero-cache/src/services/change-streamer/backfill-state.js +268 -0
  316. package/out/zero-cache/src/services/change-streamer/backfill-state.js.map +1 -0
  317. package/out/zero-cache/src/services/change-streamer/backup-cleanup-monitor-factory.d.ts.map +1 -1
  318. package/out/zero-cache/src/services/change-streamer/backup-cleanup-monitor-factory.js +6 -17
  319. package/out/zero-cache/src/services/change-streamer/backup-cleanup-monitor-factory.js.map +1 -1
  320. package/out/zero-cache/src/services/change-streamer/backup-monitor.d.ts.map +1 -1
  321. package/out/zero-cache/src/services/change-streamer/backup-monitor.js +59 -8
  322. package/out/zero-cache/src/services/change-streamer/backup-monitor.js.map +1 -1
  323. package/out/zero-cache/src/services/change-streamer/broadcast.d.ts +8 -2
  324. package/out/zero-cache/src/services/change-streamer/broadcast.d.ts.map +1 -1
  325. package/out/zero-cache/src/services/change-streamer/broadcast.js +24 -4
  326. package/out/zero-cache/src/services/change-streamer/broadcast.js.map +1 -1
  327. package/out/zero-cache/src/services/change-streamer/change-log-codec.d.ts +19 -4
  328. package/out/zero-cache/src/services/change-streamer/change-log-codec.d.ts.map +1 -1
  329. package/out/zero-cache/src/services/change-streamer/change-log-codec.js +28 -8
  330. package/out/zero-cache/src/services/change-streamer/change-log-codec.js.map +1 -1
  331. package/out/zero-cache/src/services/change-streamer/change-log-initializer.d.ts +17 -0
  332. package/out/zero-cache/src/services/change-streamer/change-log-initializer.d.ts.map +1 -1
  333. package/out/zero-cache/src/services/change-streamer/change-log-initializer.js +44 -1
  334. package/out/zero-cache/src/services/change-streamer/change-log-initializer.js.map +1 -1
  335. package/out/zero-cache/src/services/change-streamer/change-streamer-http.d.ts +48 -6
  336. package/out/zero-cache/src/services/change-streamer/change-streamer-http.d.ts.map +1 -1
  337. package/out/zero-cache/src/services/change-streamer/change-streamer-http.js +131 -34
  338. package/out/zero-cache/src/services/change-streamer/change-streamer-http.js.map +1 -1
  339. package/out/zero-cache/src/services/change-streamer/change-streamer-service.d.ts +22 -0
  340. package/out/zero-cache/src/services/change-streamer/change-streamer-service.d.ts.map +1 -1
  341. package/out/zero-cache/src/services/change-streamer/change-streamer-service.js +149 -78
  342. package/out/zero-cache/src/services/change-streamer/change-streamer-service.js.map +1 -1
  343. package/out/zero-cache/src/services/change-streamer/change-streamer.d.ts +38 -16
  344. package/out/zero-cache/src/services/change-streamer/change-streamer.d.ts.map +1 -1
  345. package/out/zero-cache/src/services/change-streamer/change-streamer.js.map +1 -1
  346. package/out/zero-cache/src/services/change-streamer/forwarder.d.ts +3 -3
  347. package/out/zero-cache/src/services/change-streamer/forwarder.d.ts.map +1 -1
  348. package/out/zero-cache/src/services/change-streamer/forwarder.js +36 -5
  349. package/out/zero-cache/src/services/change-streamer/forwarder.js.map +1 -1
  350. package/out/zero-cache/src/services/change-streamer/litestream-sync-requester.d.ts +53 -0
  351. package/out/zero-cache/src/services/change-streamer/litestream-sync-requester.d.ts.map +1 -0
  352. package/out/zero-cache/src/services/change-streamer/litestream-sync-requester.js +156 -0
  353. package/out/zero-cache/src/services/change-streamer/litestream-sync-requester.js.map +1 -0
  354. package/out/zero-cache/src/services/change-streamer/schema/tables.d.ts +58 -1
  355. package/out/zero-cache/src/services/change-streamer/schema/tables.d.ts.map +1 -1
  356. package/out/zero-cache/src/services/change-streamer/schema/tables.js +107 -16
  357. package/out/zero-cache/src/services/change-streamer/schema/tables.js.map +1 -1
  358. package/out/zero-cache/src/services/change-streamer/snapshot-message.d.ts +92 -0
  359. package/out/zero-cache/src/services/change-streamer/snapshot-message.d.ts.map +1 -0
  360. package/out/zero-cache/src/services/change-streamer/snapshot-message.js +42 -0
  361. package/out/zero-cache/src/services/change-streamer/snapshot-message.js.map +1 -0
  362. package/out/zero-cache/src/services/change-streamer/snapshot-reservations.d.ts +1 -1
  363. package/out/zero-cache/src/services/change-streamer/snapshot-reservations.d.ts.map +1 -1
  364. package/out/zero-cache/src/services/change-streamer/snapshot-reservations.js +16 -4
  365. package/out/zero-cache/src/services/change-streamer/snapshot-reservations.js.map +1 -1
  366. package/out/zero-cache/src/services/change-streamer/snapshot.d.ts +7 -69
  367. package/out/zero-cache/src/services/change-streamer/snapshot.d.ts.map +1 -1
  368. package/out/zero-cache/src/services/change-streamer/snapshot.js +21 -53
  369. package/out/zero-cache/src/services/change-streamer/snapshot.js.map +1 -1
  370. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-writer.d.ts +6 -1
  371. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-writer.d.ts.map +1 -1
  372. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-writer.js +27 -9
  373. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-writer.js.map +1 -1
  374. package/out/zero-cache/src/services/change-streamer/storer.d.ts +95 -4
  375. package/out/zero-cache/src/services/change-streamer/storer.d.ts.map +1 -1
  376. package/out/zero-cache/src/services/change-streamer/storer.js +293 -83
  377. package/out/zero-cache/src/services/change-streamer/storer.js.map +1 -1
  378. package/out/zero-cache/src/services/change-streamer/subscribe.d.ts +446 -0
  379. package/out/zero-cache/src/services/change-streamer/subscribe.d.ts.map +1 -0
  380. package/out/zero-cache/src/services/change-streamer/subscribe.js +76 -0
  381. package/out/zero-cache/src/services/change-streamer/subscribe.js.map +1 -0
  382. package/out/zero-cache/src/services/change-streamer/subscriber.d.ts +58 -1
  383. package/out/zero-cache/src/services/change-streamer/subscriber.d.ts.map +1 -1
  384. package/out/zero-cache/src/services/change-streamer/subscriber.js +123 -12
  385. package/out/zero-cache/src/services/change-streamer/subscriber.js.map +1 -1
  386. package/out/zero-cache/src/services/change-streamer/upstream-acker.d.ts +19 -1
  387. package/out/zero-cache/src/services/change-streamer/upstream-acker.d.ts.map +1 -1
  388. package/out/zero-cache/src/services/change-streamer/upstream-acker.js +23 -3
  389. package/out/zero-cache/src/services/change-streamer/upstream-acker.js.map +1 -1
  390. package/out/zero-cache/src/services/http-service.d.ts +1 -1
  391. package/out/zero-cache/src/services/http-service.d.ts.map +1 -1
  392. package/out/zero-cache/src/services/http-service.js.map +1 -1
  393. package/out/zero-cache/src/services/life-cycle.d.ts.map +1 -1
  394. package/out/zero-cache/src/services/life-cycle.js +3 -1
  395. package/out/zero-cache/src/services/life-cycle.js.map +1 -1
  396. package/out/zero-cache/src/services/litestream/commands.d.ts +34 -3
  397. package/out/zero-cache/src/services/litestream/commands.d.ts.map +1 -1
  398. package/out/zero-cache/src/services/litestream/commands.js +121 -35
  399. package/out/zero-cache/src/services/litestream/commands.js.map +1 -1
  400. package/out/zero-cache/src/services/litestream/config-v5.yml +6 -7
  401. package/out/zero-cache/src/services/litestream/litestream-checkpointer.js +51 -24
  402. package/out/zero-cache/src/services/litestream/litestream-checkpointer.js.map +1 -1
  403. package/out/zero-cache/src/services/litestream/litestream-controller.d.ts +10 -2
  404. package/out/zero-cache/src/services/litestream/litestream-controller.d.ts.map +1 -1
  405. package/out/zero-cache/src/services/litestream/litestream-controller.js +3 -2
  406. package/out/zero-cache/src/services/litestream/litestream-controller.js.map +1 -1
  407. package/out/zero-cache/src/services/litestream/restore-progress.d.ts +24 -0
  408. package/out/zero-cache/src/services/litestream/restore-progress.d.ts.map +1 -0
  409. package/out/zero-cache/src/services/litestream/restore-progress.js +91 -0
  410. package/out/zero-cache/src/services/litestream/restore-progress.js.map +1 -0
  411. package/out/zero-cache/src/services/litestream/wal-keeper.d.ts +33 -0
  412. package/out/zero-cache/src/services/litestream/wal-keeper.d.ts.map +1 -0
  413. package/out/zero-cache/src/services/litestream/wal-keeper.js +49 -0
  414. package/out/zero-cache/src/services/litestream/wal-keeper.js.map +1 -0
  415. package/out/zero-cache/src/services/mutagen/mutagen.d.ts +5 -0
  416. package/out/zero-cache/src/services/mutagen/mutagen.d.ts.map +1 -1
  417. package/out/zero-cache/src/services/mutagen/mutagen.js +7 -1
  418. package/out/zero-cache/src/services/mutagen/mutagen.js.map +1 -1
  419. package/out/zero-cache/src/services/mutagen/pusher.d.ts.map +1 -1
  420. package/out/zero-cache/src/services/mutagen/pusher.js +5 -6
  421. package/out/zero-cache/src/services/mutagen/pusher.js.map +1 -1
  422. package/out/zero-cache/src/services/plannerz.d.ts +163 -0
  423. package/out/zero-cache/src/services/plannerz.d.ts.map +1 -0
  424. package/out/zero-cache/src/services/plannerz.js +267 -0
  425. package/out/zero-cache/src/services/plannerz.js.map +1 -0
  426. package/out/zero-cache/src/services/profz.d.ts +30 -0
  427. package/out/zero-cache/src/services/profz.d.ts.map +1 -0
  428. package/out/zero-cache/src/services/profz.js +163 -0
  429. package/out/zero-cache/src/services/profz.js.map +1 -0
  430. package/out/zero-cache/src/services/replicator/change-log-cookies.js +1 -1
  431. package/out/zero-cache/src/services/replicator/change-log-cookies.js.map +1 -1
  432. package/out/zero-cache/src/services/replicator/change-log-stream-writer.d.ts +5 -4
  433. package/out/zero-cache/src/services/replicator/change-log-stream-writer.d.ts.map +1 -1
  434. package/out/zero-cache/src/services/replicator/change-log-stream-writer.js +20 -22
  435. package/out/zero-cache/src/services/replicator/change-log-stream-writer.js.map +1 -1
  436. package/out/zero-cache/src/services/replicator/change-processor.d.ts.map +1 -1
  437. package/out/zero-cache/src/services/replicator/change-processor.js +51 -5
  438. package/out/zero-cache/src/services/replicator/change-processor.js.map +1 -1
  439. package/out/zero-cache/src/services/replicator/incremental-sync.d.ts +5 -2
  440. package/out/zero-cache/src/services/replicator/incremental-sync.d.ts.map +1 -1
  441. package/out/zero-cache/src/services/replicator/incremental-sync.js +54 -21
  442. package/out/zero-cache/src/services/replicator/incremental-sync.js.map +1 -1
  443. package/out/zero-cache/src/services/replicator/replication-status.d.ts +35 -1
  444. package/out/zero-cache/src/services/replicator/replication-status.d.ts.map +1 -1
  445. package/out/zero-cache/src/services/replicator/replication-status.js +99 -8
  446. package/out/zero-cache/src/services/replicator/replication-status.js.map +1 -1
  447. package/out/zero-cache/src/services/replicator/replicator.d.ts +4 -1
  448. package/out/zero-cache/src/services/replicator/replicator.d.ts.map +1 -1
  449. package/out/zero-cache/src/services/replicator/replicator.js +5 -2
  450. package/out/zero-cache/src/services/replicator/replicator.js.map +1 -1
  451. package/out/zero-cache/src/services/replicator/reporter/recorder.d.ts +16 -1
  452. package/out/zero-cache/src/services/replicator/reporter/recorder.d.ts.map +1 -1
  453. package/out/zero-cache/src/services/replicator/reporter/recorder.js +70 -27
  454. package/out/zero-cache/src/services/replicator/reporter/recorder.js.map +1 -1
  455. package/out/zero-cache/src/services/replicator/schema/backfilling.d.ts +23 -2
  456. package/out/zero-cache/src/services/replicator/schema/backfilling.d.ts.map +1 -1
  457. package/out/zero-cache/src/services/replicator/schema/backfilling.js +54 -2
  458. package/out/zero-cache/src/services/replicator/schema/backfilling.js.map +1 -1
  459. package/out/zero-cache/src/services/replicator/sqlite-change-log-observability.d.ts +6 -6
  460. package/out/zero-cache/src/services/replicator/sqlite-change-log-observability.d.ts.map +1 -1
  461. package/out/zero-cache/src/services/replicator/sqlite-change-log-observability.js +19 -14
  462. package/out/zero-cache/src/services/replicator/sqlite-change-log-observability.js.map +1 -1
  463. package/out/zero-cache/src/services/replicator/write-worker-client.d.ts +11 -3
  464. package/out/zero-cache/src/services/replicator/write-worker-client.d.ts.map +1 -1
  465. package/out/zero-cache/src/services/replicator/write-worker-client.js.map +1 -1
  466. package/out/zero-cache/src/services/replicator/write-worker.js +5 -1
  467. package/out/zero-cache/src/services/replicator/write-worker.js.map +1 -1
  468. package/out/zero-cache/src/services/run-ast.d.ts +12 -0
  469. package/out/zero-cache/src/services/run-ast.d.ts.map +1 -1
  470. package/out/zero-cache/src/services/run-ast.js +42 -22
  471. package/out/zero-cache/src/services/run-ast.js.map +1 -1
  472. package/out/zero-cache/src/services/runner.d.ts +2 -1
  473. package/out/zero-cache/src/services/runner.d.ts.map +1 -1
  474. package/out/zero-cache/src/services/runner.js +10 -2
  475. package/out/zero-cache/src/services/runner.js.map +1 -1
  476. package/out/zero-cache/src/services/statz.d.ts +4 -0
  477. package/out/zero-cache/src/services/statz.d.ts.map +1 -1
  478. package/out/zero-cache/src/services/statz.js +22 -5
  479. package/out/zero-cache/src/services/statz.js.map +1 -1
  480. package/out/zero-cache/src/services/view-syncer/advancement-metrics.d.ts +26 -0
  481. package/out/zero-cache/src/services/view-syncer/advancement-metrics.d.ts.map +1 -0
  482. package/out/zero-cache/src/services/view-syncer/advancement-metrics.js +26 -0
  483. package/out/zero-cache/src/services/view-syncer/advancement-metrics.js.map +1 -0
  484. package/out/zero-cache/src/services/view-syncer/client-handler.d.ts +19 -2
  485. package/out/zero-cache/src/services/view-syncer/client-handler.d.ts.map +1 -1
  486. package/out/zero-cache/src/services/view-syncer/client-handler.js +42 -30
  487. package/out/zero-cache/src/services/view-syncer/client-handler.js.map +1 -1
  488. package/out/zero-cache/src/services/view-syncer/connection-context-manager.d.ts +2 -1
  489. package/out/zero-cache/src/services/view-syncer/connection-context-manager.d.ts.map +1 -1
  490. package/out/zero-cache/src/services/view-syncer/connection-context-manager.js +1 -0
  491. package/out/zero-cache/src/services/view-syncer/connection-context-manager.js.map +1 -1
  492. package/out/zero-cache/src/services/view-syncer/cvr-store.d.ts +27 -2
  493. package/out/zero-cache/src/services/view-syncer/cvr-store.d.ts.map +1 -1
  494. package/out/zero-cache/src/services/view-syncer/cvr-store.js +85 -20
  495. package/out/zero-cache/src/services/view-syncer/cvr-store.js.map +1 -1
  496. package/out/zero-cache/src/services/view-syncer/cvr.d.ts +76 -11
  497. package/out/zero-cache/src/services/view-syncer/cvr.d.ts.map +1 -1
  498. package/out/zero-cache/src/services/view-syncer/cvr.js +214 -40
  499. package/out/zero-cache/src/services/view-syncer/cvr.js.map +1 -1
  500. package/out/zero-cache/src/services/view-syncer/deferred-writes-budget.d.ts +81 -0
  501. package/out/zero-cache/src/services/view-syncer/deferred-writes-budget.d.ts.map +1 -0
  502. package/out/zero-cache/src/services/view-syncer/deferred-writes-budget.js +128 -0
  503. package/out/zero-cache/src/services/view-syncer/deferred-writes-budget.js.map +1 -0
  504. package/out/zero-cache/src/services/view-syncer/drain-coordinator.d.ts +14 -1
  505. package/out/zero-cache/src/services/view-syncer/drain-coordinator.d.ts.map +1 -1
  506. package/out/zero-cache/src/services/view-syncer/drain-coordinator.js +30 -4
  507. package/out/zero-cache/src/services/view-syncer/drain-coordinator.js.map +1 -1
  508. package/out/zero-cache/src/services/view-syncer/hydration-budget.d.ts +33 -0
  509. package/out/zero-cache/src/services/view-syncer/hydration-budget.d.ts.map +1 -0
  510. package/out/zero-cache/src/services/view-syncer/hydration-budget.js +62 -0
  511. package/out/zero-cache/src/services/view-syncer/hydration-budget.js.map +1 -0
  512. package/out/zero-cache/src/services/view-syncer/hydration-circuit-breaker.d.ts +51 -0
  513. package/out/zero-cache/src/services/view-syncer/hydration-circuit-breaker.d.ts.map +1 -0
  514. package/out/zero-cache/src/services/view-syncer/hydration-circuit-breaker.js +78 -0
  515. package/out/zero-cache/src/services/view-syncer/hydration-circuit-breaker.js.map +1 -0
  516. package/out/zero-cache/src/services/view-syncer/inspect-handler.d.ts +10 -1
  517. package/out/zero-cache/src/services/view-syncer/inspect-handler.d.ts.map +1 -1
  518. package/out/zero-cache/src/services/view-syncer/inspect-handler.js +18 -4
  519. package/out/zero-cache/src/services/view-syncer/inspect-handler.js.map +1 -1
  520. package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts +80 -6
  521. package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts.map +1 -1
  522. package/out/zero-cache/src/services/view-syncer/pipeline-driver.js +658 -195
  523. package/out/zero-cache/src/services/view-syncer/pipeline-driver.js.map +1 -1
  524. package/out/zero-cache/src/services/view-syncer/plan-warnings.d.ts +7 -0
  525. package/out/zero-cache/src/services/view-syncer/plan-warnings.d.ts.map +1 -0
  526. package/out/zero-cache/src/services/view-syncer/plan-warnings.js +35 -0
  527. package/out/zero-cache/src/services/view-syncer/plan-warnings.js.map +1 -0
  528. package/out/zero-cache/src/services/view-syncer/query-covering.d.ts.map +1 -1
  529. package/out/zero-cache/src/services/view-syncer/query-covering.js +2 -6
  530. package/out/zero-cache/src/services/view-syncer/query-covering.js.map +1 -1
  531. package/out/zero-cache/src/services/view-syncer/query-shape.d.ts +25 -0
  532. package/out/zero-cache/src/services/view-syncer/query-shape.d.ts.map +1 -0
  533. package/out/zero-cache/src/services/view-syncer/query-shape.js +28 -0
  534. package/out/zero-cache/src/services/view-syncer/query-shape.js.map +1 -0
  535. package/out/zero-cache/src/services/view-syncer/query-stats.d.ts +82 -0
  536. package/out/zero-cache/src/services/view-syncer/query-stats.d.ts.map +1 -0
  537. package/out/zero-cache/src/services/view-syncer/query-stats.js +214 -0
  538. package/out/zero-cache/src/services/view-syncer/query-stats.js.map +1 -0
  539. package/out/zero-cache/src/services/view-syncer/schema/types.d.ts +2 -107
  540. package/out/zero-cache/src/services/view-syncer/schema/types.d.ts.map +1 -1
  541. package/out/zero-cache/src/services/view-syncer/schema/types.js +5 -20
  542. package/out/zero-cache/src/services/view-syncer/schema/types.js.map +1 -1
  543. package/out/zero-cache/src/services/view-syncer/snapshot-row-cache.d.ts +95 -0
  544. package/out/zero-cache/src/services/view-syncer/snapshot-row-cache.d.ts.map +1 -0
  545. package/out/zero-cache/src/services/view-syncer/snapshot-row-cache.js +155 -0
  546. package/out/zero-cache/src/services/view-syncer/snapshot-row-cache.js.map +1 -0
  547. package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts +96 -14
  548. package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts.map +1 -1
  549. package/out/zero-cache/src/services/view-syncer/snapshotter.js +214 -30
  550. package/out/zero-cache/src/services/view-syncer/snapshotter.js.map +1 -1
  551. package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts +11 -1
  552. package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts.map +1 -1
  553. package/out/zero-cache/src/services/view-syncer/view-syncer.js +566 -107
  554. package/out/zero-cache/src/services/view-syncer/view-syncer.js.map +1 -1
  555. package/out/zero-cache/src/types/pg-data-type.d.ts +2 -0
  556. package/out/zero-cache/src/types/pg-data-type.d.ts.map +1 -1
  557. package/out/zero-cache/src/types/pg-data-type.js +6 -1
  558. package/out/zero-cache/src/types/pg-data-type.js.map +1 -1
  559. package/out/zero-cache/src/types/pg.d.ts.map +1 -1
  560. package/out/zero-cache/src/types/pg.js +1 -1
  561. package/out/zero-cache/src/types/pg.js.map +1 -1
  562. package/out/zero-cache/src/types/processes.d.ts +39 -0
  563. package/out/zero-cache/src/types/processes.d.ts.map +1 -1
  564. package/out/zero-cache/src/types/processes.js +43 -4
  565. package/out/zero-cache/src/types/processes.js.map +1 -1
  566. package/out/zero-cache/src/types/profiler.d.ts +12 -0
  567. package/out/zero-cache/src/types/profiler.d.ts.map +1 -1
  568. package/out/zero-cache/src/types/profiler.js +46 -1
  569. package/out/zero-cache/src/types/profiler.js.map +1 -1
  570. package/out/zero-cache/src/types/row-key.d.ts +1 -15
  571. package/out/zero-cache/src/types/row-key.d.ts.map +1 -1
  572. package/out/zero-cache/src/types/row-key.js +6 -8
  573. package/out/zero-cache/src/types/row-key.js.map +1 -1
  574. package/out/zero-cache/src/types/streams.d.ts +49 -7
  575. package/out/zero-cache/src/types/streams.d.ts.map +1 -1
  576. package/out/zero-cache/src/types/streams.js +190 -58
  577. package/out/zero-cache/src/types/streams.js.map +1 -1
  578. package/out/zero-cache/src/types/subscription.d.ts +15 -0
  579. package/out/zero-cache/src/types/subscription.d.ts.map +1 -1
  580. package/out/zero-cache/src/types/subscription.js +123 -31
  581. package/out/zero-cache/src/types/subscription.js.map +1 -1
  582. package/out/zero-cache/src/types/websocket-handoff.d.ts +1 -1
  583. package/out/zero-cache/src/types/websocket-handoff.d.ts.map +1 -1
  584. package/out/zero-cache/src/types/websocket-handoff.js +18 -9
  585. package/out/zero-cache/src/types/websocket-handoff.js.map +1 -1
  586. package/out/zero-cache/src/types/ws.d.ts.map +1 -1
  587. package/out/zero-cache/src/types/ws.js +1 -16
  588. package/out/zero-cache/src/types/ws.js.map +1 -1
  589. package/out/zero-cache/src/workers/connect-params.d.ts +18 -1
  590. package/out/zero-cache/src/workers/connect-params.d.ts.map +1 -1
  591. package/out/zero-cache/src/workers/connect-params.js +25 -1
  592. package/out/zero-cache/src/workers/connect-params.js.map +1 -1
  593. package/out/zero-cache/src/workers/connection.d.ts +4 -4
  594. package/out/zero-cache/src/workers/connection.d.ts.map +1 -1
  595. package/out/zero-cache/src/workers/connection.js +8 -8
  596. package/out/zero-cache/src/workers/connection.js.map +1 -1
  597. package/out/zero-cache/src/workers/replicator.d.ts.map +1 -1
  598. package/out/zero-cache/src/workers/replicator.js +15 -7
  599. package/out/zero-cache/src/workers/replicator.js.map +1 -1
  600. package/out/zero-cache/src/workers/syncer-ws-message-handler.d.ts.map +1 -1
  601. package/out/zero-cache/src/workers/syncer-ws-message-handler.js +21 -16
  602. package/out/zero-cache/src/workers/syncer-ws-message-handler.js.map +1 -1
  603. package/out/zero-cache/src/workers/syncer.d.ts.map +1 -1
  604. package/out/zero-cache/src/workers/syncer.js +55 -4
  605. package/out/zero-cache/src/workers/syncer.js.map +1 -1
  606. package/out/zero-client/src/client/active-clients-manager.d.ts.map +1 -1
  607. package/out/zero-client/src/client/active-clients-manager.js +4 -1
  608. package/out/zero-client/src/client/active-clients-manager.js.map +1 -1
  609. package/out/zero-client/src/client/connection-manager.d.ts +20 -0
  610. package/out/zero-client/src/client/connection-manager.d.ts.map +1 -1
  611. package/out/zero-client/src/client/connection-manager.js +77 -13
  612. package/out/zero-client/src/client/connection-manager.js.map +1 -1
  613. package/out/zero-client/src/client/connection-status-enum.d.ts +2 -0
  614. package/out/zero-client/src/client/connection-status-enum.d.ts.map +1 -1
  615. package/out/zero-client/src/client/connection-status-enum.js +3 -1
  616. package/out/zero-client/src/client/connection-status-enum.js.map +1 -1
  617. package/out/zero-client/src/client/connection.d.ts +6 -0
  618. package/out/zero-client/src/client/connection.d.ts.map +1 -1
  619. package/out/zero-client/src/client/connection.js +2 -1
  620. package/out/zero-client/src/client/connection.js.map +1 -1
  621. package/out/zero-client/src/client/context.d.ts +23 -13
  622. package/out/zero-client/src/client/context.d.ts.map +1 -1
  623. package/out/zero-client/src/client/context.js +94 -26
  624. package/out/zero-client/src/client/context.js.map +1 -1
  625. package/out/zero-client/src/client/crud-impl.d.ts.map +1 -1
  626. package/out/zero-client/src/client/crud-impl.js +1 -1
  627. package/out/zero-client/src/client/crud-impl.js.map +1 -1
  628. package/out/zero-client/src/client/custom.d.ts +5 -4
  629. package/out/zero-client/src/client/custom.d.ts.map +1 -1
  630. package/out/zero-client/src/client/custom.js +3 -3
  631. package/out/zero-client/src/client/custom.js.map +1 -1
  632. package/out/zero-client/src/client/inspector/lazy-inspector.js +1 -1
  633. package/out/zero-client/src/client/ivm-branch.d.ts.map +1 -1
  634. package/out/zero-client/src/client/ivm-branch.js +20 -3
  635. package/out/zero-client/src/client/ivm-branch.js.map +1 -1
  636. package/out/zero-client/src/client/keys.d.ts.map +1 -1
  637. package/out/zero-client/src/client/keys.js +19 -1
  638. package/out/zero-client/src/client/keys.js.map +1 -1
  639. package/out/zero-client/src/client/make-mutate-property.d.ts +1 -1
  640. package/out/zero-client/src/client/make-mutate-property.d.ts.map +1 -1
  641. package/out/zero-client/src/client/make-mutate-property.js.map +1 -1
  642. package/out/zero-client/src/client/make-replicache-mutators.d.ts.map +1 -1
  643. package/out/zero-client/src/client/make-replicache-mutators.js +1 -1
  644. package/out/zero-client/src/client/make-replicache-mutators.js.map +1 -1
  645. package/out/zero-client/src/client/mutation-tracker.d.ts +2 -2
  646. package/out/zero-client/src/client/mutation-tracker.d.ts.map +1 -1
  647. package/out/zero-client/src/client/mutation-tracker.js +3 -7
  648. package/out/zero-client/src/client/mutation-tracker.js.map +1 -1
  649. package/out/zero-client/src/client/mutator-proxy.d.ts.map +1 -1
  650. package/out/zero-client/src/client/mutator-proxy.js +9 -4
  651. package/out/zero-client/src/client/mutator-proxy.js.map +1 -1
  652. package/out/zero-client/src/client/options.d.ts +33 -0
  653. package/out/zero-client/src/client/options.d.ts.map +1 -1
  654. package/out/zero-client/src/client/options.js.map +1 -1
  655. package/out/zero-client/src/client/query-manager.d.ts +9 -0
  656. package/out/zero-client/src/client/query-manager.d.ts.map +1 -1
  657. package/out/zero-client/src/client/query-manager.js +47 -14
  658. package/out/zero-client/src/client/query-manager.js.map +1 -1
  659. package/out/zero-client/src/client/reload-error-handler.js +2 -2
  660. package/out/zero-client/src/client/reload-error-handler.js.map +1 -1
  661. package/out/zero-client/src/client/version.js +1 -1
  662. package/out/zero-client/src/client/zero-rep.d.ts +1 -0
  663. package/out/zero-client/src/client/zero-rep.d.ts.map +1 -1
  664. package/out/zero-client/src/client/zero-rep.js +8 -6
  665. package/out/zero-client/src/client/zero-rep.js.map +1 -1
  666. package/out/zero-client/src/client/zero.d.ts +18 -3
  667. package/out/zero-client/src/client/zero.d.ts.map +1 -1
  668. package/out/zero-client/src/client/zero.js +89 -50
  669. package/out/zero-client/src/client/zero.js.map +1 -1
  670. package/out/zero-client/src/mod.d.ts +2 -1
  671. package/out/zero-client/src/mod.d.ts.map +1 -1
  672. package/out/zero-client/src/mod.js +1 -0
  673. package/out/zero-client/src/types/query-result.d.ts +2 -0
  674. package/out/zero-client/src/types/query-result.d.ts.map +1 -1
  675. package/out/zero-events/src/status.d.ts +64 -0
  676. package/out/zero-events/src/status.d.ts.map +1 -1
  677. package/out/zero-protocol/src/analyze-query-result.d.ts +5 -0
  678. package/out/zero-protocol/src/analyze-query-result.d.ts.map +1 -1
  679. package/out/zero-protocol/src/analyze-query-result.js.map +1 -1
  680. package/out/zero-protocol/src/ast.d.ts.map +1 -1
  681. package/out/zero-protocol/src/ast.js +13 -14
  682. package/out/zero-protocol/src/ast.js.map +1 -1
  683. package/out/zero-protocol/src/connect.d.ts +16 -0
  684. package/out/zero-protocol/src/connect.d.ts.map +1 -1
  685. package/out/zero-protocol/src/connect.js +27 -1
  686. package/out/zero-protocol/src/connect.js.map +1 -1
  687. package/out/zero-protocol/src/down.d.ts +31 -31
  688. package/out/zero-protocol/src/feature-flag-enum.d.ts +14 -0
  689. package/out/zero-protocol/src/feature-flag-enum.d.ts.map +1 -0
  690. package/out/zero-protocol/src/feature-flag-enum.js +10 -0
  691. package/out/zero-protocol/src/feature-flag-enum.js.map +1 -0
  692. package/out/zero-protocol/src/feature-flag.d.ts +5 -0
  693. package/out/zero-protocol/src/feature-flag.d.ts.map +1 -0
  694. package/out/zero-protocol/src/inspect-down.d.ts +16 -16
  695. package/out/zero-protocol/src/poke.d.ts +17 -10
  696. package/out/zero-protocol/src/poke.d.ts.map +1 -1
  697. package/out/zero-protocol/src/poke.js +3 -2
  698. package/out/zero-protocol/src/poke.js.map +1 -1
  699. package/out/zero-protocol/src/protocol-version.d.ts +30 -6
  700. package/out/zero-protocol/src/protocol-version.d.ts.map +1 -1
  701. package/out/zero-protocol/src/protocol-version.js +1 -1
  702. package/out/zero-protocol/src/protocol-version.js.map +1 -1
  703. package/out/zero-protocol/src/query-hash.d.ts.map +1 -1
  704. package/out/zero-protocol/src/query-hash.js +2 -5
  705. package/out/zero-protocol/src/query-hash.js.map +1 -1
  706. package/out/zero-react/src/use-query.d.ts +5 -4
  707. package/out/zero-react/src/use-query.d.ts.map +1 -1
  708. package/out/zero-react/src/use-query.js +74 -7
  709. package/out/zero-react/src/use-query.js.map +1 -1
  710. package/out/zero-react/src/zero.js +1 -0
  711. package/out/zero-server/src/adapters/drizzle.d.ts +2 -1
  712. package/out/zero-server/src/adapters/drizzle.d.ts.map +1 -1
  713. package/out/zero-server/src/adapters/drizzle.js +12 -7
  714. package/out/zero-server/src/adapters/drizzle.js.map +1 -1
  715. package/out/zero-server/src/adapters/kysely.d.ts +2 -1
  716. package/out/zero-server/src/adapters/kysely.d.ts.map +1 -1
  717. package/out/zero-server/src/adapters/kysely.js +8 -2
  718. package/out/zero-server/src/adapters/kysely.js.map +1 -1
  719. package/out/zero-server/src/adapters/pg.d.ts +5 -1
  720. package/out/zero-server/src/adapters/pg.d.ts.map +1 -1
  721. package/out/zero-server/src/adapters/pg.js +28 -7
  722. package/out/zero-server/src/adapters/pg.js.map +1 -1
  723. package/out/zero-server/src/adapters/postgresjs.d.ts +1 -0
  724. package/out/zero-server/src/adapters/postgresjs.d.ts.map +1 -1
  725. package/out/zero-server/src/adapters/postgresjs.js +7 -1
  726. package/out/zero-server/src/adapters/postgresjs.js.map +1 -1
  727. package/out/zero-server/src/adapters/prisma.d.ts +3 -2
  728. package/out/zero-server/src/adapters/prisma.d.ts.map +1 -1
  729. package/out/zero-server/src/adapters/prisma.js +8 -2
  730. package/out/zero-server/src/adapters/prisma.js.map +1 -1
  731. package/out/zero-server/src/closable-db-transaction.d.ts +16 -0
  732. package/out/zero-server/src/closable-db-transaction.d.ts.map +1 -0
  733. package/out/zero-server/src/closable-db-transaction.js +31 -0
  734. package/out/zero-server/src/closable-db-transaction.js.map +1 -0
  735. package/out/zero-server/src/custom.d.ts +10 -4
  736. package/out/zero-server/src/custom.d.ts.map +1 -1
  737. package/out/zero-server/src/custom.js +15 -6
  738. package/out/zero-server/src/custom.js.map +1 -1
  739. package/out/zero-server/src/logging.d.ts +2 -2
  740. package/out/zero-server/src/logging.d.ts.map +1 -1
  741. package/out/zero-server/src/logging.js +2 -2
  742. package/out/zero-server/src/logging.js.map +1 -1
  743. package/out/zero-server/src/mod.d.ts +1 -1
  744. package/out/zero-server/src/mod.d.ts.map +1 -1
  745. package/out/zero-server/src/pg-query-executor.d.ts +2 -2
  746. package/out/zero-server/src/pg-query-executor.d.ts.map +1 -1
  747. package/out/zero-server/src/pg-query-executor.js +2 -2
  748. package/out/zero-server/src/pg-query-executor.js.map +1 -1
  749. package/out/zero-server/src/process-mutations.d.ts +25 -4
  750. package/out/zero-server/src/process-mutations.d.ts.map +1 -1
  751. package/out/zero-server/src/process-mutations.js +103 -52
  752. package/out/zero-server/src/process-mutations.js.map +1 -1
  753. package/out/zero-server/src/push-processor.d.ts +8 -2
  754. package/out/zero-server/src/push-processor.d.ts.map +1 -1
  755. package/out/zero-server/src/push-processor.js +12 -4
  756. package/out/zero-server/src/push-processor.js.map +1 -1
  757. package/out/zero-server/src/schema.d.ts +2 -2
  758. package/out/zero-server/src/schema.d.ts.map +1 -1
  759. package/out/zero-server/src/schema.js +3 -2
  760. package/out/zero-server/src/schema.js.map +1 -1
  761. package/out/zero-server/src/zql-database.d.ts +21 -1
  762. package/out/zero-server/src/zql-database.d.ts.map +1 -1
  763. package/out/zero-server/src/zql-database.js +61 -24
  764. package/out/zero-server/src/zql-database.js.map +1 -1
  765. package/out/zero-solid/src/solid-view.d.ts +17 -0
  766. package/out/zero-solid/src/solid-view.d.ts.map +1 -1
  767. package/out/zero-solid/src/solid-view.js +39 -1
  768. package/out/zero-solid/src/solid-view.js.map +1 -1
  769. package/out/zero-solid/src/use-query.js +1 -2
  770. package/out/zero-solid/src/use-query.js.map +1 -1
  771. package/out/zero-solid/src/zero.js +1 -0
  772. package/out/zql/src/builder/builder.d.ts +25 -0
  773. package/out/zql/src/builder/builder.d.ts.map +1 -1
  774. package/out/zql/src/builder/builder.js +69 -19
  775. package/out/zql/src/builder/builder.js.map +1 -1
  776. package/out/zql/src/builder/correlated-predicate-pushdown.d.ts +43 -0
  777. package/out/zql/src/builder/correlated-predicate-pushdown.d.ts.map +1 -0
  778. package/out/zql/src/builder/correlated-predicate-pushdown.js +161 -0
  779. package/out/zql/src/builder/correlated-predicate-pushdown.js.map +1 -0
  780. package/out/zql/src/builder/debug-delegate.d.ts +6 -1
  781. package/out/zql/src/builder/debug-delegate.d.ts.map +1 -1
  782. package/out/zql/src/builder/debug-delegate.js +14 -2
  783. package/out/zql/src/builder/debug-delegate.js.map +1 -1
  784. package/out/zql/src/ivm/array-view.d.ts +29 -0
  785. package/out/zql/src/ivm/array-view.d.ts.map +1 -1
  786. package/out/zql/src/ivm/array-view.js +74 -16
  787. package/out/zql/src/ivm/array-view.js.map +1 -1
  788. package/out/zql/src/ivm/cap.d.ts +2 -1
  789. package/out/zql/src/ivm/cap.d.ts.map +1 -1
  790. package/out/zql/src/ivm/cap.js +14 -4
  791. package/out/zql/src/ivm/cap.js.map +1 -1
  792. package/out/zql/src/ivm/data.d.ts.map +1 -1
  793. package/out/zql/src/ivm/data.js +8 -3
  794. package/out/zql/src/ivm/data.js.map +1 -1
  795. package/out/zql/src/ivm/deferred-input.d.ts.map +1 -1
  796. package/out/zql/src/ivm/deferred-input.js +3 -2
  797. package/out/zql/src/ivm/deferred-input.js.map +1 -1
  798. package/out/zql/src/ivm/exists.d.ts +3 -1
  799. package/out/zql/src/ivm/exists.d.ts.map +1 -1
  800. package/out/zql/src/ivm/exists.js +4 -1
  801. package/out/zql/src/ivm/exists.js.map +1 -1
  802. package/out/zql/src/ivm/fan-in.d.ts +6 -2
  803. package/out/zql/src/ivm/fan-in.d.ts.map +1 -1
  804. package/out/zql/src/ivm/fan-in.js +13 -5
  805. package/out/zql/src/ivm/fan-in.js.map +1 -1
  806. package/out/zql/src/ivm/fan-out.d.ts +5 -2
  807. package/out/zql/src/ivm/fan-out.d.ts.map +1 -1
  808. package/out/zql/src/ivm/fan-out.js +4 -0
  809. package/out/zql/src/ivm/fan-out.js.map +1 -1
  810. package/out/zql/src/ivm/filter-operators.d.ts +8 -6
  811. package/out/zql/src/ivm/filter-operators.d.ts.map +1 -1
  812. package/out/zql/src/ivm/filter-operators.js +19 -8
  813. package/out/zql/src/ivm/filter-operators.js.map +1 -1
  814. package/out/zql/src/ivm/filter.d.ts +5 -2
  815. package/out/zql/src/ivm/filter.d.ts.map +1 -1
  816. package/out/zql/src/ivm/filter.js +10 -4
  817. package/out/zql/src/ivm/filter.js.map +1 -1
  818. package/out/zql/src/ivm/flipped-join.d.ts +9 -4
  819. package/out/zql/src/ivm/flipped-join.d.ts.map +1 -1
  820. package/out/zql/src/ivm/flipped-join.js +97 -46
  821. package/out/zql/src/ivm/flipped-join.js.map +1 -1
  822. package/out/zql/src/ivm/join-index-tap.d.ts +33 -0
  823. package/out/zql/src/ivm/join-index-tap.d.ts.map +1 -0
  824. package/out/zql/src/ivm/join-index-tap.js +70 -0
  825. package/out/zql/src/ivm/join-index-tap.js.map +1 -0
  826. package/out/zql/src/ivm/join-index.d.ts +35 -0
  827. package/out/zql/src/ivm/join-index.d.ts.map +1 -0
  828. package/out/zql/src/ivm/join-index.js +141 -0
  829. package/out/zql/src/ivm/join-index.js.map +1 -0
  830. package/out/zql/src/ivm/join-utils.d.ts +6 -0
  831. package/out/zql/src/ivm/join-utils.d.ts.map +1 -1
  832. package/out/zql/src/ivm/join-utils.js +22 -1
  833. package/out/zql/src/ivm/join-utils.js.map +1 -1
  834. package/out/zql/src/ivm/join.d.ts +19 -1
  835. package/out/zql/src/ivm/join.d.ts.map +1 -1
  836. package/out/zql/src/ivm/join.js +107 -15
  837. package/out/zql/src/ivm/join.js.map +1 -1
  838. package/out/zql/src/ivm/maybe-split-and-push-edit-change.d.ts +1 -1
  839. package/out/zql/src/ivm/maybe-split-and-push-edit-change.d.ts.map +1 -1
  840. package/out/zql/src/ivm/maybe-split-and-push-edit-change.js +6 -4
  841. package/out/zql/src/ivm/maybe-split-and-push-edit-change.js.map +1 -1
  842. package/out/zql/src/ivm/memory-source.d.ts +29 -4
  843. package/out/zql/src/ivm/memory-source.d.ts.map +1 -1
  844. package/out/zql/src/ivm/memory-source.js +70 -34
  845. package/out/zql/src/ivm/memory-source.js.map +1 -1
  846. package/out/zql/src/ivm/memory-storage.d.ts +1 -0
  847. package/out/zql/src/ivm/memory-storage.d.ts.map +1 -1
  848. package/out/zql/src/ivm/memory-storage.js +1 -0
  849. package/out/zql/src/ivm/memory-storage.js.map +1 -1
  850. package/out/zql/src/ivm/operator.d.ts +45 -10
  851. package/out/zql/src/ivm/operator.d.ts.map +1 -1
  852. package/out/zql/src/ivm/operator.js +9 -4
  853. package/out/zql/src/ivm/operator.js.map +1 -1
  854. package/out/zql/src/ivm/push-accumulated.d.ts +6 -1
  855. package/out/zql/src/ivm/push-accumulated.d.ts.map +1 -1
  856. package/out/zql/src/ivm/push-accumulated.js +47 -2
  857. package/out/zql/src/ivm/push-accumulated.js.map +1 -1
  858. package/out/zql/src/ivm/skip.d.ts +2 -1
  859. package/out/zql/src/ivm/skip.d.ts.map +1 -1
  860. package/out/zql/src/ivm/skip.js +3 -0
  861. package/out/zql/src/ivm/skip.js.map +1 -1
  862. package/out/zql/src/ivm/take-gate.d.ts +57 -0
  863. package/out/zql/src/ivm/take-gate.d.ts.map +1 -0
  864. package/out/zql/src/ivm/take-gate.js +106 -0
  865. package/out/zql/src/ivm/take-gate.js.map +1 -0
  866. package/out/zql/src/ivm/take.d.ts +8 -2
  867. package/out/zql/src/ivm/take.d.ts.map +1 -1
  868. package/out/zql/src/ivm/take.js +139 -103
  869. package/out/zql/src/ivm/take.js.map +1 -1
  870. package/out/zql/src/ivm/union-fan-in.d.ts +3 -0
  871. package/out/zql/src/ivm/union-fan-in.d.ts.map +1 -1
  872. package/out/zql/src/ivm/union-fan-in.js +63 -10
  873. package/out/zql/src/ivm/union-fan-in.js.map +1 -1
  874. package/out/zql/src/ivm/union-fan-out.d.ts +2 -1
  875. package/out/zql/src/ivm/union-fan-out.d.ts.map +1 -1
  876. package/out/zql/src/ivm/union-fan-out.js +5 -0
  877. package/out/zql/src/ivm/union-fan-out.js.map +1 -1
  878. package/out/zql/src/ivm/view-apply-change.d.ts.map +1 -1
  879. package/out/zql/src/ivm/view-apply-change.js +9 -4
  880. package/out/zql/src/ivm/view-apply-change.js.map +1 -1
  881. package/out/zql/src/ivm/view.d.ts +15 -0
  882. package/out/zql/src/ivm/view.d.ts.map +1 -1
  883. package/out/zql/src/mutate/custom.d.ts +53 -1
  884. package/out/zql/src/mutate/custom.d.ts.map +1 -1
  885. package/out/zql/src/mutate/custom.js.map +1 -1
  886. package/out/zql/src/mutate/mutator-registry.d.ts.map +1 -1
  887. package/out/zql/src/mutate/mutator-registry.js +3 -3
  888. package/out/zql/src/mutate/mutator-registry.js.map +1 -1
  889. package/out/zql/src/mutate/mutator.d.ts +2 -2
  890. package/out/zql/src/mutate/mutator.d.ts.map +1 -1
  891. package/out/zql/src/mutate/mutator.js.map +1 -1
  892. package/out/zql/src/planner/planner-builder.d.ts +23 -3
  893. package/out/zql/src/planner/planner-builder.d.ts.map +1 -1
  894. package/out/zql/src/planner/planner-builder.js +34 -17
  895. package/out/zql/src/planner/planner-builder.js.map +1 -1
  896. package/out/zql/src/planner/planner-connection.d.ts +58 -2
  897. package/out/zql/src/planner/planner-connection.d.ts.map +1 -1
  898. package/out/zql/src/planner/planner-connection.js +103 -11
  899. package/out/zql/src/planner/planner-connection.js.map +1 -1
  900. package/out/zql/src/planner/planner-debug.d.ts.map +1 -1
  901. package/out/zql/src/planner/planner-debug.js +3 -8
  902. package/out/zql/src/planner/planner-debug.js.map +1 -1
  903. package/out/zql/src/planner/planner-graph.d.ts +10 -0
  904. package/out/zql/src/planner/planner-graph.d.ts.map +1 -1
  905. package/out/zql/src/planner/planner-graph.js +14 -0
  906. package/out/zql/src/planner/planner-graph.js.map +1 -1
  907. package/out/zql/src/planner/planner-source.d.ts +2 -2
  908. package/out/zql/src/planner/planner-source.d.ts.map +1 -1
  909. package/out/zql/src/planner/planner-source.js +2 -2
  910. package/out/zql/src/planner/planner-source.js.map +1 -1
  911. package/out/zql/src/planner/planner-warnings.d.ts +83 -0
  912. package/out/zql/src/planner/planner-warnings.d.ts.map +1 -0
  913. package/out/zql/src/planner/planner-warnings.js +78 -0
  914. package/out/zql/src/planner/planner-warnings.js.map +1 -0
  915. package/out/zql/src/query/measure-push-operator.d.ts +9 -2
  916. package/out/zql/src/query/measure-push-operator.d.ts.map +1 -1
  917. package/out/zql/src/query/measure-push-operator.js +52 -5
  918. package/out/zql/src/query/measure-push-operator.js.map +1 -1
  919. package/out/zql/src/query/query-delegate-base.d.ts +4 -2
  920. package/out/zql/src/query/query-delegate-base.d.ts.map +1 -1
  921. package/out/zql/src/query/query-delegate-base.js +66 -33
  922. package/out/zql/src/query/query-delegate-base.js.map +1 -1
  923. package/out/zql/src/query/query-delegate.d.ts +33 -6
  924. package/out/zql/src/query/query-delegate.d.ts.map +1 -1
  925. package/out/zql/src/query/query-impl.d.ts +1 -0
  926. package/out/zql/src/query/query-impl.d.ts.map +1 -1
  927. package/out/zql/src/query/query-impl.js +6 -23
  928. package/out/zql/src/query/query-impl.js.map +1 -1
  929. package/out/zql/src/query/query-transitions.d.ts.map +1 -1
  930. package/out/zql/src/query/query-transitions.js +2 -5
  931. package/out/zql/src/query/query-transitions.js.map +1 -1
  932. package/out/zql/src/query/query.d.ts +22 -5
  933. package/out/zql/src/query/query.d.ts.map +1 -1
  934. package/out/zql/src/query/runnable-query-impl.d.ts +1 -0
  935. package/out/zql/src/query/runnable-query-impl.d.ts.map +1 -1
  936. package/out/zql/src/query/runnable-query-impl.js +2 -10
  937. package/out/zql/src/query/runnable-query-impl.js.map +1 -1
  938. package/out/zql/src/query/typed-view.d.ts +1 -1
  939. package/out/zql/src/query/typed-view.d.ts.map +1 -1
  940. package/out/zqlite/src/database-storage.d.ts.map +1 -1
  941. package/out/zqlite/src/database-storage.js +9 -1
  942. package/out/zqlite/src/database-storage.js.map +1 -1
  943. package/out/zqlite/src/db.d.ts +9 -1
  944. package/out/zqlite/src/db.d.ts.map +1 -1
  945. package/out/zqlite/src/db.js +62 -30
  946. package/out/zqlite/src/db.js.map +1 -1
  947. package/out/zqlite/src/index-usage.d.ts +19 -0
  948. package/out/zqlite/src/index-usage.d.ts.map +1 -0
  949. package/out/zqlite/src/index-usage.js +49 -0
  950. package/out/zqlite/src/index-usage.js.map +1 -0
  951. package/out/zqlite/src/pending-delta.d.ts +110 -0
  952. package/out/zqlite/src/pending-delta.d.ts.map +1 -0
  953. package/out/zqlite/src/pending-delta.js +278 -0
  954. package/out/zqlite/src/pending-delta.js.map +1 -0
  955. package/out/zqlite/src/query-builder.d.ts +17 -1
  956. package/out/zqlite/src/query-builder.d.ts.map +1 -1
  957. package/out/zqlite/src/query-builder.js +111 -20
  958. package/out/zqlite/src/query-builder.js.map +1 -1
  959. package/out/zqlite/src/query-delegate.d.ts.map +1 -1
  960. package/out/zqlite/src/query-delegate.js +10 -7
  961. package/out/zqlite/src/query-delegate.js.map +1 -1
  962. package/out/zqlite/src/resolve-scalar-subqueries.d.ts +3 -1
  963. package/out/zqlite/src/resolve-scalar-subqueries.d.ts.map +1 -1
  964. package/out/zqlite/src/resolve-scalar-subqueries.js +1 -0
  965. package/out/zqlite/src/resolve-scalar-subqueries.js.map +1 -1
  966. package/out/zqlite/src/sqlite-cost-model.d.ts.map +1 -1
  967. package/out/zqlite/src/sqlite-cost-model.js +52 -1
  968. package/out/zqlite/src/sqlite-cost-model.js.map +1 -1
  969. package/out/zqlite/src/sqlite-stat-fanout.d.ts.map +1 -1
  970. package/out/zqlite/src/sqlite-stat-fanout.js +5 -31
  971. package/out/zqlite/src/sqlite-stat-fanout.js.map +1 -1
  972. package/out/zqlite/src/sqlite-stat4-sample.d.ts +37 -0
  973. package/out/zqlite/src/sqlite-stat4-sample.d.ts.map +1 -0
  974. package/out/zqlite/src/sqlite-stat4-sample.js +61 -0
  975. package/out/zqlite/src/sqlite-stat4-sample.js.map +1 -0
  976. package/out/zqlite/src/table-source.d.ts +87 -2
  977. package/out/zqlite/src/table-source.d.ts.map +1 -1
  978. package/out/zqlite/src/table-source.js +276 -42
  979. package/out/zqlite/src/table-source.js.map +1 -1
  980. package/package.json +4 -5
  981. package/out/replicache/src/kv/idb-store-with-mem-fallback.d.ts +0 -25
  982. package/out/replicache/src/kv/idb-store-with-mem-fallback.d.ts.map +0 -1
  983. package/out/replicache/src/kv/idb-store-with-mem-fallback.js +0 -83
  984. package/out/replicache/src/kv/idb-store-with-mem-fallback.js.map +0 -1
  985. package/out/zero-cache/src/services/change-streamer/vfs-watermark-poller.d.ts +0 -29
  986. package/out/zero-cache/src/services/change-streamer/vfs-watermark-poller.d.ts.map +0 -1
  987. package/out/zero-cache/src/services/change-streamer/vfs-watermark-poller.js +0 -154
  988. package/out/zero-cache/src/services/change-streamer/vfs-watermark-poller.js.map +0 -1
@@ -1,11 +1,15 @@
1
1
  import { assert } from "../../../../../shared/src/asserts.js";
2
2
  import { parse } from "../../../../../shared/src/valita.js";
3
+ import { must } from "../../../../../shared/src/must.js";
4
+ import { randomCharacters } from "../../../../../shared/src/random-values.js";
3
5
  import { equals } from "../../../../../shared/src/set-utils.js";
6
+ import { id } from "../../../types/sql.js";
4
7
  import { connectPgClient, pgClient } from "../../../types/pg.js";
5
8
  import { toStateVersionString } from "./lsn.js";
6
9
  import { READONLY } from "../../../db/mode-enum.js";
7
10
  import { getPublicationInfo } from "./schema/published.js";
8
11
  import { Queue } from "../../../../../shared/src/queue.js";
12
+ import { resumePoint } from "../protocol/backfill-progress.js";
9
13
  import { SchemaIncompatibilityError } from "../common/backfill-manager.js";
10
14
  import { BinaryCopyParser, hasBinaryDecoder, makeBinaryDecoder, textCastDecoder } from "../../../db/pg-copy-binary.js";
11
15
  import { TsvParser } from "../../../db/pg-copy.js";
@@ -17,6 +21,52 @@ import { makeBinarySelectExprs, makeDownloadStatements } from "./initial-sync.js
17
21
  import postgres from "postgres";
18
22
  import { PG_UNDEFINED_COLUMN, PG_UNDEFINED_TABLE } from "@drdgvhbh/postgres-error-codes";
19
23
  //#region ../zero-cache/src/services/change-source/pg/backfill-stream.ts
24
+ /**
25
+ * Encodes a `ctid` text representation, e.g. `(123,4)`, as a
26
+ * fixed-width string that sorts lexicographically in `ctid` order.
27
+ */
28
+ var CTID_RE = /^\((\d+),(\d+)\)$/;
29
+ var CTID_MARK_RE = /^(\d{10})\.(\d{5})$/;
30
+ function ctidToProgressMark(ctid) {
31
+ const match = CTID_RE.exec(ctid);
32
+ assert(match, () => `invalid ctid: ${ctid}`);
33
+ return `${match[1].padStart(10, "0")}.${match[2].padStart(5, "0")}`;
34
+ }
35
+ /** The inverse of {@link ctidToProgressMark}, as a `tid` literal. */
36
+ function progressMarkToCtid(mark) {
37
+ const match = CTID_MARK_RE.exec(mark);
38
+ assert(match, () => `invalid ctid progress mark: ${mark}`);
39
+ return `(${Number(match[1])},${Number(match[2])})`;
40
+ }
41
+ function progressMarks(previous, current) {
42
+ return previous ? {
43
+ previous,
44
+ current
45
+ } : { current };
46
+ }
47
+ /** The `ctid` of each row is appended as the last column of the download. */
48
+ var CTID_SELECT = "ctid::text";
49
+ /**
50
+ * Settings that ensure that the COPY scans the table in physical (i.e.
51
+ * `ctid`) order, which is necessary for the progress marks of a resumable
52
+ * backfill to be meaningful. (Monotonicity is nonetheless verified as rows
53
+ * are streamed.)
54
+ *
55
+ * * Synchronized seqscans can start in the middle of the table.
56
+ * * Parallel scans interleave the rows of different workers.
57
+ * * Index scans follow index order. (A publication row filter could
58
+ * otherwise be satisfied with an index.)
59
+ */
60
+ var PHYSICAL_ORDER_SETTINGS = [
61
+ "synchronize_seqscans = off",
62
+ "max_parallel_workers_per_gather = 0",
63
+ "enable_indexscan = off",
64
+ "enable_indexonlyscan = off",
65
+ "enable_bitmapscan = off"
66
+ ];
67
+ function rowCountMark(rows) {
68
+ return String(rows).padStart(16, "0");
69
+ }
20
70
  var POSTGRES_COPY_CHUNK_SIZE = 64 * 1024;
21
71
  var SAMPLE_OR_LIMIT_RE = /\sTABLESAMPLE\s+BERNOULLI\b|\sLIMIT\s+\d/i;
22
72
  /**
@@ -27,7 +77,7 @@ var SAMPLE_OR_LIMIT_RE = /\sTABLESAMPLE\s+BERNOULLI\b|\sLIMIT\s+\d/i;
27
77
  */
28
78
  async function* streamBackfill(lc, upstreamURI, { slot, publications }, bf, opts = {}) {
29
79
  lc = lc.withContext("component", "backfill").withContext("table", bf.table.name);
30
- const { flushThresholdBytes = POSTGRES_COPY_CHUNK_SIZE, textCopy = false } = opts;
80
+ const { flushThresholdBytes = POSTGRES_COPY_CHUNK_SIZE, textCopy = false, afterSnapshotForTesting } = opts;
31
81
  const db = await connectPgClient(lc, upstreamURI, "backfill-stream", {
32
82
  ["max_lifetime"]: 1440 * 60,
33
83
  liveness: "keepalive"
@@ -36,23 +86,26 @@ async function* streamBackfill(lc, upstreamURI, { slot, publications }, bf, opts
36
86
  let watermark;
37
87
  try {
38
88
  ({tx, watermark} = await createSnapshotTransaction(lc, upstreamURI, db, slot));
39
- const { tableSpec, backfill } = await validateSchema(tx, publications, bf, watermark);
89
+ await afterSnapshotForTesting?.();
90
+ const { tableSpec, backfill, progress } = await validateSchema(lc, tx, publications, bf, watermark);
40
91
  const { relation, columns } = backfill;
41
92
  const cols = [...relation.rowKey.columns, ...columns];
42
- const stmts = makeDownloadStatements(tableSpec, cols);
93
+ const order = progress.resumable && progress.start ? { after: `ctid > '${progressMarkToCtid(progress.start.progressMark)}'::tid` } : void 0;
94
+ const stmts = makeDownloadStatements(tableSpec, cols, void 0, void 0, [...cols.map((col) => id(col)), CTID_SELECT], order);
95
+ if (progress.start) lc.info?.(`resuming backfill from ${progress.start.progressMark} (timeline ${progress.timeline})`);
43
96
  if (textCopy) {
44
97
  const types = await getTypeParsers(db, { returnJsonAsString: true });
45
- yield* stream(lc, tx, backfill, stmts, `COPY (${stmts.select}) TO STDOUT`, new TsvParser(), cols.map((col) => {
98
+ yield* stream(lc, tx, backfill, progress, stmts, `COPY (${stmts.select}) TO STDOUT`, new TsvParser(), cols.map((col) => {
46
99
  const parser = types.getTypeParser(tableSpec.columns[col].typeOID);
47
100
  return (text) => parser(text);
48
- }), flushThresholdBytes);
101
+ }), (text) => text, flushThresholdBytes);
49
102
  } else {
50
- const binaryStmts = makeDownloadStatements(tableSpec, cols, void 0, void 0, makeBinarySelectExprs(tableSpec, cols));
51
- yield* stream(lc, tx, backfill, stmts, `COPY (${binaryStmts.select}) TO STDOUT WITH (FORMAT binary)`, new BinaryCopyParser(), cols.map((col) => {
103
+ const binaryStmts = makeDownloadStatements(tableSpec, cols, void 0, void 0, [...makeBinarySelectExprs(tableSpec, cols), CTID_SELECT], order);
104
+ yield* stream(lc, tx, backfill, progress, stmts, `COPY (${binaryStmts.select}) TO STDOUT WITH (FORMAT binary)`, new BinaryCopyParser(), cols.map((col) => {
52
105
  const spec = tableSpec.columns[col];
53
106
  const decoder = hasBinaryDecoder(spec) ? makeBinaryDecoder(spec) : textCastDecoder;
54
107
  return (buf) => decoder(buf);
55
- }), flushThresholdBytes);
108
+ }), (buf) => buf.toString("utf8"), flushThresholdBytes);
56
109
  }
57
110
  } catch (e) {
58
111
  if (e instanceof postgres.PostgresError && (e.code === PG_UNDEFINED_TABLE || e.code === PG_UNDEFINED_COLUMN)) throw new SchemaIncompatibilityError(bf, String(e), { cause: e });
@@ -62,7 +115,7 @@ async function* streamBackfill(lc, upstreamURI, { slot, publications }, bf, opts
62
115
  db.end().catch((e) => lc.warn?.(`error closing backfill connection`, e));
63
116
  }
64
117
  }
65
- async function* stream(lc, tx, backfill, { getTotalRows, getTotalBytes }, copyCommand, parser, decoders, flushThresholdBytes) {
118
+ async function* stream(lc, tx, backfill, { timeline, resumable, start: startMark }, { getTotalRows, getTotalBytes }, copyCommand, parser, decoders, ctidDecoder, flushThresholdBytes) {
66
119
  assert(!SAMPLE_OR_LIMIT_RE.test(copyCommand), `backfill COPY must not sample or limit: ${copyCommand}`);
67
120
  const start = performance.now();
68
121
  const [rows, bytes] = await tx.processReadTask((sql) => Promise.all([sql.unsafe(getTotalRows), sql.unsafe(getTotalBytes)]));
@@ -76,6 +129,7 @@ async function* stream(lc, tx, backfill, { getTotalRows, getTotalBytes }, copyCo
76
129
  const chunks = new Queue();
77
130
  const acks = new Queue();
78
131
  const copyDone = tx.processReadTask(async (sql) => {
132
+ for (const setting of PHYSICAL_ORDER_SETTINGS) await sql.unsafe(`SET LOCAL ${setting}`);
79
133
  const readable = await sql.unsafe(copyCommand).readable();
80
134
  for await (const chunk of readable) {
81
135
  chunks.enqueue(chunk);
@@ -91,14 +145,26 @@ async function* stream(lc, tx, backfill, { getTotalRows, getTotalBytes }, copyCo
91
145
  const logFlushed = () => {
92
146
  lc.debug?.(`Flushed ${rowValues.length} rows, ${bufferedBytes} bytes (total: rows=${status.rows}, msgs=${totalMsgs}, bytes=${totalBytes})`);
93
147
  };
148
+ let current = startMark;
149
+ let previous = startMark;
150
+ const markOf = (progressMark) => ({
151
+ progressMark,
152
+ timeline
153
+ });
154
+ const numCols = decoders.length + 1;
94
155
  let row = Array.from({ length: decoders.length });
95
156
  let col = 0;
96
157
  for (;;) {
97
158
  const chunk = await chunks.dequeue();
98
159
  if (chunk === "done") break;
99
160
  for (const field of parser.parse(chunk)) {
100
- row[col] = field === null ? null : decoders[col](field);
101
- if (++col === decoders.length) {
161
+ if (col < decoders.length) row[col] = field === null ? null : decoders[col](field);
162
+ else {
163
+ const mark = resumable ? ctidToProgressMark(ctidDecoder(field)) : rowCountMark(status.rows + 1);
164
+ if (current !== void 0 && mark <= current.progressMark) throw new Error(`backfill rows are not in ctid order (${mark} after ${current.progressMark})`);
165
+ current = markOf(mark);
166
+ }
167
+ if (++col === numCols) {
102
168
  rowValues.push(row);
103
169
  status.rows++;
104
170
  row = Array.from({ length: decoders.length });
@@ -107,16 +173,18 @@ async function* stream(lc, tx, backfill, { getTotalRows, getTotalBytes }, copyCo
107
173
  }
108
174
  bufferedBytes += chunk.byteLength;
109
175
  totalBytes += chunk.byteLength;
110
- if (bufferedBytes >= flushThresholdBytes) {
176
+ if (bufferedBytes >= flushThresholdBytes && rowValues.length > 0) {
111
177
  yield {
112
178
  message: {
113
179
  tag: "backfill",
114
180
  ...backfill,
115
181
  rowValues,
116
- status
182
+ status,
183
+ progressMarks: progressMarks(previous, must(current))
117
184
  },
118
185
  byteSize: bufferedBytes
119
186
  };
187
+ previous = current;
120
188
  totalMsgs++;
121
189
  logFlushed();
122
190
  rowValues = [];
@@ -131,10 +199,12 @@ async function* stream(lc, tx, backfill, { getTotalRows, getTotalBytes }, copyCo
131
199
  tag: "backfill",
132
200
  ...backfill,
133
201
  rowValues,
134
- status
202
+ status,
203
+ progressMarks: progressMarks(previous, must(current))
135
204
  },
136
205
  byteSize: bufferedBytes
137
206
  };
207
+ previous = current;
138
208
  totalMsgs++;
139
209
  logFlushed();
140
210
  }
@@ -142,7 +212,8 @@ async function* stream(lc, tx, backfill, { getTotalRows, getTotalBytes }, copyCo
142
212
  message: {
143
213
  tag: "backfill-completed",
144
214
  ...backfill,
145
- status
215
+ status,
216
+ progressMarks: previous ? { previous } : {}
146
217
  },
147
218
  byteSize: 0
148
219
  };
@@ -167,7 +238,8 @@ async function createSnapshotTransaction(lc, upstreamURI, db, slotNamePrefix) {
167
238
  try {
168
239
  const { snapshot_name: snapshot, consistent_point: lsn } = await createReplicationSlot(lc, replicationSession, {
169
240
  slotName,
170
- temporary: true
241
+ temporary: true,
242
+ diagnosticsDB: db
171
243
  });
172
244
  const { init, imported } = importSnapshot(snapshot);
173
245
  const tx = new TransactionPool(lc, {
@@ -185,7 +257,7 @@ async function createSnapshotTransaction(lc, upstreamURI, db, slotNamePrefix) {
185
257
  await replicationSession.end();
186
258
  }
187
259
  }
188
- function validateSchema(tx, publications, bf, watermark) {
260
+ function validateSchema(lc, tx, publications, bf, watermark) {
189
261
  return tx.processReadTask(async (sql) => {
190
262
  const { tables } = await getPublicationInfo(sql, publications);
191
263
  const spec = tables.find((spec) => spec.schema === bf.table.schema && spec.name === bf.table.name);
@@ -194,7 +266,7 @@ function validateSchema(tx, publications, bf, watermark) {
194
266
  if (spec.schemaOID !== tableMeta.schemaOID) throw new SchemaIncompatibilityError(bf, `Schema no longer corresponds to the original schema`);
195
267
  if (spec.oid !== tableMeta.relationOID) throw new SchemaIncompatibilityError(bf, `Table no longer corresponds to the original table`);
196
268
  if (!equals(new Set(Object.keys(tableMeta.rowKey)), new Set(spec.replicaIdentityColumns))) throw new SchemaIncompatibilityError(bf, "Row key (e.g. PRIMARY KEY or INDEX) has changed");
197
- const allCols = [...Object.entries(tableMeta.rowKey), ...Object.entries(bf.columns)];
269
+ const allCols = [...Object.entries(tableMeta.rowKey), ...Object.entries(bf.columns).map(([col, { id }]) => [col, id])];
198
270
  for (const [col, val] of allCols) {
199
271
  const colSpec = spec.columns[col];
200
272
  if (!colSpec) throw new SchemaIncompatibilityError(bf, `Column ${col} has been renamed or dropped`);
@@ -210,10 +282,125 @@ function validateSchema(tx, publications, bf, watermark) {
210
282
  },
211
283
  columns: Object.keys(bf.columns).filter((col) => !(col in tableMeta.rowKey)),
212
284
  watermark
213
- }
285
+ },
286
+ progress: await getProgress(lc, sql, spec.oid, bf)
214
287
  };
215
288
  });
216
289
  }
290
+ /**
291
+ * Determines the timeline of the table's progress marks (as of the snapshot),
292
+ * and whether the backfill can be resumed from the requested progress.
293
+ *
294
+ * The table is locked (in ACCESS SHARE mode, as the COPY would, for the rest
295
+ * of the transaction) so that its storage cannot be rewritten (by `VACUUM
296
+ * FULL`, `CLUSTER`, `TRUNCATE`, or a rewriting `ALTER TABLE`, all of which
297
+ * require ACCESS EXCLUSIVE) between reading the timeline and the COPY. Note
298
+ * that `pg_relation_filenode()` reflects the table's current storage (only
299
+ * refreshed upon acquiring a lock), whereas `pg_class.relfilenode` is read at
300
+ * the transaction snapshot. If they differ, the storage was rewritten after the
301
+ * snapshot, and the COPY would scan the new storage with the old snapshot,
302
+ * which is not MVCC-safe for all rewrites (e.g. the table appears empty after
303
+ * a rewriting `ALTER TABLE`). The backfill is then retried at a new snapshot.
304
+ */
305
+ async function getProgress(lc, sql, relationOID, bf) {
306
+ const table = `${id(bf.table.schema)}.${id(bf.table.name)}`;
307
+ await sql.unsafe(`LOCK TABLE ${table} IN ACCESS SHARE MODE`);
308
+ const [{ lockedOID, relkind, snapshotFilenode, filenode }] = await sql`
309
+ SELECT to_regclass(${table})::oid::int8 AS "lockedOID",
310
+ relkind,
311
+ relfilenode::text AS "snapshotFilenode",
312
+ pg_relation_filenode(oid)::text AS filenode
313
+ FROM pg_class WHERE oid = ${relationOID}`;
314
+ if (Number(lockedOID) !== relationOID) throw new SchemaIncompatibilityError(bf, `Table has been renamed or replaced`);
315
+ if (relkind !== "r" || filenode === null) return {
316
+ timeline: `${relkind}:${randomCharacters(12)}`,
317
+ resumable: false,
318
+ start: void 0
319
+ };
320
+ if (filenode !== snapshotFilenode) throw new Error(`${bf.table.schema}.${bf.table.name} was rewritten after the backfill snapshot (relfilenode ${snapshotFilenode} => ${filenode})`);
321
+ const timeline = filenode;
322
+ const requested = resumePoint(bf);
323
+ if (requested && requested.timeline !== timeline) {
324
+ lc.info?.(`restarting backfill from scratch: the requested progress is on timeline ${requested.timeline} but the table is on ${timeline}`);
325
+ return {
326
+ timeline,
327
+ resumable: true,
328
+ start: void 0
329
+ };
330
+ }
331
+ if (requested && !await canResume(sql, relationOID, bf)) {
332
+ lc.info?.(`restarting backfill from scratch: the table has TOASTed values and backfilling columns [${Object.keys(bf.columns).join(",")}] are TOAST-able`);
333
+ return {
334
+ timeline,
335
+ resumable: true,
336
+ start: void 0
337
+ };
338
+ }
339
+ return {
340
+ timeline,
341
+ resumable: true,
342
+ start: requested
343
+ };
344
+ }
345
+ /**
346
+ * Whether resuming a backfill (in a new snapshot) is guaranteed to deliver
347
+ * the values of every row that the preceding snapshot(s) had not reached.
348
+ *
349
+ * Within a single snapshot, every row is scanned exactly once, since the
350
+ * version visible to the snapshot stays in place while it is held. Across
351
+ * snapshots, however, a row that had not yet been reached (i.e. beyond the
352
+ * resume mark `M`) can be updated between the snapshots, with its new
353
+ * version placed at or before `M` (a non-HOT update into free space in an
354
+ * earlier page, or a HOT update into a lower line pointer of `M`'s page).
355
+ * Neither snapshot then scans the row, and it is only delivered by the
356
+ * replication stream. The stream's UPDATE contains the full row, _except_
357
+ * for unchanged values stored out-of-line in TOAST, which pgoutput omits
358
+ * (unless the table has REPLICA IDENTITY FULL). A backfilling column with
359
+ * such a value would be published without it.
360
+ *
361
+ * Resuming is therefore only done if no backfilling column can be TOASTed
362
+ * (i.e. all have `attstorage = 'p'`, as for fixed-width types), or if the
363
+ * table has no TOAST data. The latter is safe because an omitted value must
364
+ * still be in the TOAST relation at the new snapshot (unless its row has since
365
+ * been deleted, which the replication stream does deliver), and conservative
366
+ * because the TOAST relation does not shrink to empty without a heap rewrite,
367
+ * which changes the timeline.
368
+ *
369
+ * Potential optimization for TOAST-able backfills: have the resumed run also
370
+ * deliver the rows at or before `M` that were modified since the snapshot of
371
+ * the run that started the backfill from scratch. That run's snapshot `xmin`
372
+ * (`T_origin`, as an xid8) would be encoded in the timeline, i.e.
373
+ * `timeline = "<relfilenode>:<T_origin>"`, and carried over (rather than
374
+ * replaced) by resumed runs, so that:
375
+ * * Within a chain of runs, every row version with `xmin < T_origin` stayed
376
+ * in place across all of the runs' snapshots and was therefore scanned
377
+ * exactly once, and all other rows are re-delivered by the resumed run
378
+ * (`ctid > M OR xmin >= T_origin`).
379
+ * * Continuations from a different chain (i.e. with a newer `T_origin`) are
380
+ * not accepted by subscribers, and requests from different chains are
381
+ * merged into a backfill from scratch, as the timelines differ. Note that
382
+ * using the _latest_ `T` would be incorrect: rows that moved before `M`
383
+ * between the earlier snapshots would never be re-delivered.
384
+ * The resumed run would scan the whole table (but only deliver the modified
385
+ * rows), comparing the 32-bit `xmin` with `T_origin` modulo 2^32, which
386
+ * requires falling back to a backfill from scratch once the current xid is
387
+ * 2^31 or more past `T_origin` (i.e. wraparound). This also relies on the
388
+ * `xmin` system column returning the raw xmin of frozen tuples, which should
389
+ * be verified.
390
+ */
391
+ async function canResume(sql, relationOID, bf) {
392
+ const [{ toastable, toasted }] = await sql`
393
+ SELECT
394
+ EXISTS (
395
+ SELECT 1 FROM pg_attribute
396
+ WHERE attrelid = ${relationOID}
397
+ AND attname IN ${sql(Object.keys(bf.columns))}
398
+ AND attstorage <> 'p'
399
+ ) AS toastable,
400
+ reltoastrelid <> 0 AND pg_relation_size(reltoastrelid) > 0 AS toasted
401
+ FROM pg_class WHERE oid = ${relationOID}`;
402
+ return !toastable || !toasted;
403
+ }
217
404
  //#endregion
218
405
  export { streamBackfill };
219
406
 
@@ -1 +1 @@
1
- {"version":3,"file":"backfill-stream.js","names":[],"sources":["../../../../../../../zero-cache/src/services/change-source/pg/backfill-stream.ts"],"sourcesContent":["import {\n PG_UNDEFINED_COLUMN,\n PG_UNDEFINED_TABLE,\n} from '@drdgvhbh/postgres-error-codes';\nimport type {LogContext} from '@rocicorp/logger';\nimport postgres from 'postgres';\nimport {assert} from '../../../../../shared/src/asserts.ts';\nimport {Queue} from '../../../../../shared/src/queue.ts';\nimport {equals} from '../../../../../shared/src/set-utils.ts';\nimport * as v from '../../../../../shared/src/valita.ts';\nimport {READONLY} from '../../../db/mode-enum.ts';\nimport {\n BinaryCopyParser,\n hasBinaryDecoder,\n makeBinaryDecoder,\n textCastDecoder,\n} from '../../../db/pg-copy-binary.ts';\nimport {TsvParser} from '../../../db/pg-copy.ts';\nimport {getTypeParsers} from '../../../db/pg-type-parser.ts';\nimport type {PublishedTableSpec} from '../../../db/specs.ts';\nimport {importSnapshot, TransactionPool} from '../../../db/transaction-pool.ts';\nimport {connectPgClient, pgClient, type PostgresDB} from '../../../types/pg.ts';\nimport {\n SchemaIncompatibilityError,\n type BackfillMessage,\n} from '../common/backfill-manager.ts';\nimport type {\n BackfillCompleted,\n BackfillRequest,\n DownloadStatus,\n JSONValue,\n} from '../protocol/current.ts';\nimport {\n columnMetadataSchema,\n tableMetadataSchema,\n} from './backfill-metadata.ts';\nimport {\n makeBinarySelectExprs,\n makeDownloadStatements,\n type DownloadStatements,\n} from './initial-sync.ts';\nimport {toStateVersionString} from './lsn.ts';\nimport {createReplicationSlot} from './replication-slots.ts';\nimport {getPublicationInfo} from './schema/published.ts';\nimport type {Replica} from './schema/shard.ts';\n\ntype BackfillParams = Omit<BackfillCompleted, 'tag'>;\n\ntype StreamOptions = {\n /**\n * The number of bytes at which to flush a batch of rows in a\n * backfill message. Defaults to Node's getDefaultHighWatermark().\n */\n flushThresholdBytes?: number | undefined;\n\n /**\n * Use text-format COPY instead of binary COPY.\n * Binary is faster and handles all types (unknown types are cast to\n * `::text` in the SELECT). This flag exists as an escape hatch to\n * revert to the old code path if needed.\n */\n textCopy?: boolean | undefined;\n};\n\n// The size of chunks that Postgres sends on COPY stream.\n// This happens to match NodeJS's getDefaultHighWatermark()\n// (for Node v20+).\nconst POSTGRES_COPY_CHUNK_SIZE = 64 * 1024;\n\n// Matches the exact clauses emitted by makeDownloadStatements; quoted\n// identifiers like \"limit\" won't match because they lack the surrounding\n// whitespace.\nconst SAMPLE_OR_LIMIT_RE = /\\sTABLESAMPLE\\s+BERNOULLI\\b|\\sLIMIT\\s+\\d/i;\n\n/**\n * Streams a series of `backfill` messages (ending with `backfill-complete`)\n * at a set watermark (i.e. LSN). The data is retrieved via a COPY stream\n * made at a transaction snapshot corresponding to specific LSN, obtained by\n * creating a short-lived replication slot.\n */\nexport async function* streamBackfill(\n lc: LogContext,\n upstreamURI: string,\n {slot, publications}: Pick<Replica, 'slot' | 'publications'>,\n bf: BackfillRequest,\n opts: StreamOptions = {},\n): AsyncGenerator<BackfillMessage> {\n lc = lc\n .withContext('component', 'backfill')\n .withContext('table', bf.table.name);\n\n const {flushThresholdBytes = POSTGRES_COPY_CHUNK_SIZE, textCopy = false} =\n opts;\n const db = await connectPgClient(lc, upstreamURI, 'backfill-stream', {\n // The COPY is a single stream that must outlive the entire table download,\n // so allow a very long (24h) connection lifetime.\n ['max_lifetime']: 24 * 60 * 60,\n // A backfill COPY is a background process that can be preempted by\n // upstream replication changes, potentially requiring it to sit idle for\n // long stretches. Use TCP keepalive to detect dead connections instead\n // of the inactivity watchdog, which could kill connnections that are\n // taking a back seat for upstream replication changes.\n liveness: 'keepalive',\n });\n let tx: TransactionPool | undefined;\n let watermark: string;\n try {\n ({tx, watermark} = await createSnapshotTransaction(\n lc,\n upstreamURI,\n db,\n slot,\n ));\n const {tableSpec, backfill} = await validateSchema(\n tx,\n publications,\n bf,\n watermark,\n );\n\n // Note: validateSchema ensures that the rowKey and columns are disjoint\n const {relation, columns} = backfill;\n const cols = [...relation.rowKey.columns, ...columns];\n const stmts = makeDownloadStatements(tableSpec, cols);\n\n if (textCopy) {\n const types = await getTypeParsers(db, {returnJsonAsString: true});\n yield* stream(\n lc,\n tx,\n backfill,\n stmts,\n `COPY (${stmts.select}) TO STDOUT`,\n new TsvParser(),\n cols.map(col => {\n const parser = types.getTypeParser(tableSpec.columns[col].typeOID);\n return (text: string) => parser(text) as JSONValue;\n }),\n flushThresholdBytes,\n );\n } else {\n const binaryStmts = makeDownloadStatements(\n tableSpec,\n cols,\n undefined,\n undefined,\n makeBinarySelectExprs(tableSpec, cols),\n );\n\n yield* stream(\n lc,\n tx,\n backfill,\n stmts,\n `COPY (${binaryStmts.select}) TO STDOUT WITH (FORMAT binary)`,\n new BinaryCopyParser(),\n cols.map(col => {\n const spec = tableSpec.columns[col];\n const decoder = hasBinaryDecoder(spec)\n ? makeBinaryDecoder(spec)\n : textCastDecoder;\n return (buf: Buffer) => decoder(buf) as unknown as JSONValue;\n }),\n flushThresholdBytes,\n );\n }\n } catch (e) {\n // Although we make the best effort to validate the schema at the\n // transaction snapshot, certain forms of `ALTER TABLE` are not\n // MVCC safe and not \"frozen\" in the snapshot:\n //\n // https://www.postgresql.org/docs/current/mvcc-caveats.html\n //\n // Handle these errors as schema incompatibility errors rather than\n // unknown runtime errors.\n if (\n e instanceof postgres.PostgresError &&\n (e.code === PG_UNDEFINED_TABLE || e.code === PG_UNDEFINED_COLUMN)\n ) {\n throw new SchemaIncompatibilityError(bf, String(e), {cause: e});\n }\n throw e;\n } finally {\n tx?.setDone();\n // Workaround postgres.js hanging at the end of some COPY commands:\n // https://github.com/porsager/postgres/issues/499\n void db.end().catch(e => lc.warn?.(`error closing backfill connection`, e));\n }\n}\n\nasync function* stream<T>(\n lc: LogContext,\n tx: TransactionPool,\n backfill: BackfillParams,\n {\n getTotalRows,\n getTotalBytes,\n }: Pick<DownloadStatements, 'getTotalRows' | 'getTotalBytes'>,\n copyCommand: string,\n parser: {parse(chunk: Buffer): Iterable<T | null>},\n decoders: ((field: T) => JSONValue)[],\n flushThresholdBytes: number,\n): AsyncGenerator<BackfillMessage> {\n // Backfill must read every row: TABLESAMPLE / LIMIT are reserved for shadow\n // sync and must never appear in a backfill COPY.\n assert(\n !SAMPLE_OR_LIMIT_RE.test(copyCommand),\n `backfill COPY must not sample or limit: ${copyCommand}`,\n );\n const start = performance.now();\n const [rows, bytes] = await tx.processReadTask(sql =>\n Promise.all([\n sql.unsafe<{totalRows: bigint}[]>(getTotalRows),\n sql.unsafe<{totalBytes: bigint}[]>(getTotalBytes),\n ]),\n );\n const status: DownloadStatus = {\n rows: 0,\n totalRows: Number(rows[0].totalRows),\n totalBytes: Number(bytes[0].totalBytes),\n };\n\n let elapsed = (performance.now() - start).toFixed(3);\n lc.info?.(\n `Computed total rows and bytes for: ${copyCommand} (${elapsed} ms)`,\n {\n status,\n },\n );\n\n // Drain the COPY stream from *within* a single read task so that the\n // TransactionPool worker holds the transaction for the entire duration of\n // the COPY, rather than incorrectly considering the worker \"idle\" and\n // attempting to send keepalives on it.\n //\n // Chunks are bridged out to this generator via a Queue, with a corresponding\n // acks Queue providing strict one-chunk-at-a-time backpressure. This is\n // necessary because it is not possible to \"yield\" from within the read task.\n const chunks = new Queue<Buffer | 'done'>();\n const acks = new Queue<void>();\n\n const copyDone = tx.processReadTask(async sql => {\n const readable = await sql.unsafe(copyCommand).readable();\n for await (const chunk of readable) {\n chunks.enqueue(chunk as Buffer);\n await acks.dequeue(); // wait for this generator to consume the chunk\n }\n chunks.enqueue('done');\n });\n copyDone.catch(e => chunks.enqueueRejection(e));\n\n let totalBytes = 0;\n let totalMsgs = 0;\n let rowValues: JSONValue[][] = [];\n let bufferedBytes = 0;\n\n const logFlushed = () => {\n lc.debug?.(\n `Flushed ${rowValues.length} rows, ${bufferedBytes} bytes ` +\n `(total: rows=${status.rows}, msgs=${totalMsgs}, bytes=${totalBytes})`,\n );\n };\n\n // Tracks the row being parsed.\n let row: JSONValue[] = Array.from({length: decoders.length});\n let col = 0;\n\n for (;;) {\n const chunk = await chunks.dequeue();\n if (chunk === 'done') {\n break;\n }\n for (const field of parser.parse(chunk)) {\n row[col] = field === null ? null : decoders[col](field);\n\n if (++col === decoders.length) {\n rowValues.push(row);\n status.rows++;\n row = Array.from({length: decoders.length});\n col = 0;\n }\n }\n bufferedBytes += chunk.byteLength;\n totalBytes += chunk.byteLength;\n\n if (bufferedBytes >= flushThresholdBytes) {\n yield {\n message: {tag: 'backfill', ...backfill, rowValues, status},\n byteSize: bufferedBytes,\n };\n totalMsgs++;\n logFlushed();\n rowValues = [];\n bufferedBytes = 0;\n }\n\n // Signal the read task to pull the next chunk (one-chunk backpressure).\n acks.enqueue();\n }\n\n // Surface any error from the COPY read task (and confirm clean completion).\n await copyDone;\n\n // Flush the last batch of rows.\n if (rowValues.length > 0) {\n yield {\n message: {tag: 'backfill', ...backfill, rowValues, status},\n byteSize: bufferedBytes,\n };\n totalMsgs++;\n logFlushed();\n }\n\n yield {\n message: {tag: 'backfill-completed', ...backfill, status},\n byteSize: 0,\n };\n elapsed = (performance.now() - start).toFixed(3);\n lc.info?.(\n `Finished streaming ${status.rows} rows, ${totalMsgs} msgs, ${totalBytes} bytes ` +\n `(${elapsed} ms)`,\n );\n}\n\n/**\n * Creates (and drops) a replication slot in order to obtain a snapshot\n * that corresponds with a specific LSN. Sets the snapshot on the\n * TransactionPool and returns the watermark corresponding to the LSN.\n *\n * (Note that PG's other LSN-related functions are not scoped to a\n * transaction; this is the only way to get set a transaction at a specific\n * LSN.)\n */\nasync function createSnapshotTransaction(\n lc: LogContext,\n upstreamURI: string,\n db: PostgresDB,\n slotNamePrefix: string,\n) {\n const replicationSession = pgClient(\n lc,\n upstreamURI,\n 'backfill-replication-session',\n {\n ['fetch_types']: false, // Necessary for the streaming protocol\n connection: {replication: 'database'}, // https://www.postgresql.org/docs/current/protocol-replication.html\n },\n );\n const slotName = `${slotNamePrefix}_bf_${Date.now()}`;\n try {\n const {snapshot_name: snapshot, consistent_point: lsn} =\n await createReplicationSlot(lc, replicationSession, {\n slotName,\n temporary: true, // deletes the slot when the replicationSession ends\n });\n\n const {init, imported} = importSnapshot(snapshot);\n const tx = new TransactionPool(lc, {mode: READONLY, init}).run(db);\n await imported.dequeue();\n\n const watermark = toStateVersionString(lsn);\n lc.info?.(`Opened snapshot transaction at LSN ${lsn} (${watermark})`);\n return {tx, watermark};\n } finally {\n await replicationSession.end();\n }\n}\n\nfunction validateSchema(\n tx: TransactionPool,\n publications: string[],\n bf: BackfillRequest,\n watermark: string,\n): Promise<{\n tableSpec: PublishedTableSpec;\n backfill: BackfillParams;\n}> {\n return tx.processReadTask(async sql => {\n const {tables} = await getPublicationInfo(sql, publications);\n const spec = tables.find(\n spec => spec.schema === bf.table.schema && spec.name === bf.table.name,\n );\n if (!spec) {\n throw new SchemaIncompatibilityError(\n bf,\n `Table has been renamed or dropped`,\n );\n }\n const tableMeta = v.parse(bf.table.metadata, tableMetadataSchema);\n if (spec.schemaOID !== tableMeta.schemaOID) {\n throw new SchemaIncompatibilityError(\n bf,\n `Schema no longer corresponds to the original schema`,\n );\n }\n if (spec.oid !== tableMeta.relationOID) {\n throw new SchemaIncompatibilityError(\n bf,\n `Table no longer corresponds to the original table`,\n );\n }\n if (\n !equals(\n new Set(Object.keys(tableMeta.rowKey)),\n new Set(spec.replicaIdentityColumns),\n )\n ) {\n throw new SchemaIncompatibilityError(\n bf,\n 'Row key (e.g. PRIMARY KEY or INDEX) has changed',\n );\n }\n const allCols = [\n ...Object.entries(tableMeta.rowKey),\n ...Object.entries(bf.columns),\n ];\n for (const [col, val] of allCols) {\n const colSpec = spec.columns[col];\n if (!colSpec) {\n throw new SchemaIncompatibilityError(\n bf,\n `Column ${col} has been renamed or dropped`,\n );\n }\n const colMeta = v.parse(val, columnMetadataSchema);\n if (colMeta.attNum !== colSpec.pos) {\n throw new SchemaIncompatibilityError(\n bf,\n `Column ${col} no longer corresponds to the original column`,\n );\n }\n }\n const backfill: BackfillParams = {\n relation: {\n schema: bf.table.schema,\n name: bf.table.name,\n rowKey: {columns: Object.keys(tableMeta.rowKey)},\n },\n columns: Object.keys(bf.columns).filter(\n col => !(col in tableMeta.rowKey),\n ),\n watermark,\n };\n return {tableSpec: spec, backfill};\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"backfill-stream.js","names":[],"sources":["../../../../../../../zero-cache/src/services/change-source/pg/backfill-stream.ts"],"sourcesContent":["import {\n PG_UNDEFINED_COLUMN,\n PG_UNDEFINED_TABLE,\n} from '@drdgvhbh/postgres-error-codes';\nimport type {LogContext} from '@rocicorp/logger';\nimport postgres from 'postgres';\nimport {assert} from '../../../../../shared/src/asserts.ts';\nimport {must} from '../../../../../shared/src/must.ts';\nimport {Queue} from '../../../../../shared/src/queue.ts';\nimport {randomCharacters} from '../../../../../shared/src/random-values.ts';\nimport {equals} from '../../../../../shared/src/set-utils.ts';\nimport * as v from '../../../../../shared/src/valita.ts';\nimport {READONLY} from '../../../db/mode-enum.ts';\nimport {\n BinaryCopyParser,\n hasBinaryDecoder,\n makeBinaryDecoder,\n textCastDecoder,\n} from '../../../db/pg-copy-binary.ts';\nimport {TsvParser} from '../../../db/pg-copy.ts';\nimport {getTypeParsers} from '../../../db/pg-type-parser.ts';\nimport type {PublishedTableSpec} from '../../../db/specs.ts';\nimport {importSnapshot, TransactionPool} from '../../../db/transaction-pool.ts';\nimport {connectPgClient, pgClient, type PostgresDB} from '../../../types/pg.ts';\nimport {id} from '../../../types/sql.ts';\nimport {\n SchemaIncompatibilityError,\n type BackfillMessage,\n} from '../common/backfill-manager.ts';\nimport {resumePoint} from '../protocol/backfill-progress.ts';\nimport type {\n BackfillCompleted,\n BackfillProgressMark,\n BackfillRequest,\n DownloadStatus,\n JSONValue,\n} from '../protocol/current.ts';\nimport {\n columnMetadataSchema,\n tableMetadataSchema,\n} from './backfill-metadata.ts';\nimport {\n makeBinarySelectExprs,\n makeDownloadStatements,\n type DownloadStatements,\n} from './initial-sync.ts';\nimport {toStateVersionString} from './lsn.ts';\nimport {createReplicationSlot} from './replication-slots.ts';\nimport {getPublicationInfo} from './schema/published.ts';\nimport type {Replica} from './schema/shard.ts';\n\ntype BackfillParams = Omit<BackfillCompleted, 'tag' | 'progressMarks'>;\n\n/**\n * Determines how the progress of a backfill is marked, and from where it is\n * resumed.\n */\ntype Progress = {\n /**\n * The timeline of the progress marks. For plain tables, this is the table's\n * `relfilenode`, which identifies the physical \"generation\" of the table's\n * data (changed by heap rewrites like `VACUUM FULL`, `CLUSTER`, or\n * `TRUNCATE`), within which `ctid`s are comparable.\n */\n timeline: string;\n\n /**\n * Whether the progress marks are resumable `ctid`s. Tables without\n * (their own) storage, such as partitioned tables, are not resumable and\n * are instead marked with the number of rows streamed, on a timeline that\n * is unique to the run.\n */\n resumable: boolean;\n\n /** The mark from which the backfill resumes, if any. */\n start: BackfillProgressMark | undefined;\n};\n\n/**\n * Encodes a `ctid` text representation, e.g. `(123,4)`, as a\n * fixed-width string that sorts lexicographically in `ctid` order.\n */\nconst CTID_RE = /^\\((\\d+),(\\d+)\\)$/;\nconst CTID_MARK_RE = /^(\\d{10})\\.(\\d{5})$/;\n\nexport function ctidToProgressMark(ctid: string): string {\n const match = CTID_RE.exec(ctid);\n assert(match, () => `invalid ctid: ${ctid}`);\n return `${match[1].padStart(10, '0')}.${match[2].padStart(5, '0')}`;\n}\n\n/** The inverse of {@link ctidToProgressMark}, as a `tid` literal. */\nexport function progressMarkToCtid(mark: string): string {\n const match = CTID_MARK_RE.exec(mark);\n assert(match, () => `invalid ctid progress mark: ${mark}`);\n return `(${Number(match[1])},${Number(match[2])})`;\n}\n\nfunction progressMarks(\n previous: BackfillProgressMark | undefined,\n current: BackfillProgressMark,\n) {\n return previous ? {previous, current} : {current};\n}\n\n/** The `ctid` of each row is appended as the last column of the download. */\nconst CTID_SELECT = 'ctid::text';\n\n/**\n * Settings that ensure that the COPY scans the table in physical (i.e.\n * `ctid`) order, which is necessary for the progress marks of a resumable\n * backfill to be meaningful. (Monotonicity is nonetheless verified as rows\n * are streamed.)\n *\n * * Synchronized seqscans can start in the middle of the table.\n * * Parallel scans interleave the rows of different workers.\n * * Index scans follow index order. (A publication row filter could\n * otherwise be satisfied with an index.)\n */\nconst PHYSICAL_ORDER_SETTINGS = [\n 'synchronize_seqscans = off',\n 'max_parallel_workers_per_gather = 0',\n 'enable_indexscan = off',\n 'enable_indexonlyscan = off',\n 'enable_bitmapscan = off',\n];\n\nfunction rowCountMark(rows: number): string {\n return String(rows).padStart(16, '0');\n}\n\ntype StreamOptions = {\n /**\n * The number of bytes at which to flush a batch of rows in a\n * backfill message. Defaults to Node's getDefaultHighWatermark().\n */\n flushThresholdBytes?: number | undefined;\n\n /**\n * Use text-format COPY instead of binary COPY.\n * Binary is faster and handles all types (unknown types are cast to\n * `::text` in the SELECT). This flag exists as an escape hatch to\n * revert to the old code path if needed.\n */\n textCopy?: boolean | undefined;\n\n /**\n * @visibleForTesting\n * Called after the snapshot transaction is opened, before the table is\n * locked, e.g. to run a concurrent heap rewrite in between.\n */\n afterSnapshotForTesting?: (() => Promise<void>) | undefined;\n};\n\n// The size of chunks that Postgres sends on COPY stream.\n// This happens to match NodeJS's getDefaultHighWatermark()\n// (for Node v20+).\nconst POSTGRES_COPY_CHUNK_SIZE = 64 * 1024;\n\n// Matches the exact clauses emitted by makeDownloadStatements; quoted\n// identifiers like \"limit\" won't match because they lack the surrounding\n// whitespace.\nconst SAMPLE_OR_LIMIT_RE = /\\sTABLESAMPLE\\s+BERNOULLI\\b|\\sLIMIT\\s+\\d/i;\n\n/**\n * Streams a series of `backfill` messages (ending with `backfill-complete`)\n * at a set watermark (i.e. LSN). The data is retrieved via a COPY stream\n * made at a transaction snapshot corresponding to specific LSN, obtained by\n * creating a short-lived replication slot.\n */\nexport async function* streamBackfill(\n lc: LogContext,\n upstreamURI: string,\n {slot, publications}: Pick<Replica, 'slot' | 'publications'>,\n bf: BackfillRequest,\n opts: StreamOptions = {},\n): AsyncGenerator<BackfillMessage> {\n lc = lc\n .withContext('component', 'backfill')\n .withContext('table', bf.table.name);\n\n const {\n flushThresholdBytes = POSTGRES_COPY_CHUNK_SIZE,\n textCopy = false,\n afterSnapshotForTesting,\n } = opts;\n const db = await connectPgClient(lc, upstreamURI, 'backfill-stream', {\n // The COPY is a single stream that must outlive the entire table download,\n // so allow a very long (24h) connection lifetime.\n ['max_lifetime']: 24 * 60 * 60,\n // A backfill COPY is a background process that can be preempted by\n // upstream replication changes, potentially requiring it to sit idle for\n // long stretches. Use TCP keepalive to detect dead connections instead\n // of the inactivity watchdog, which could kill connnections that are\n // taking a back seat for upstream replication changes.\n liveness: 'keepalive',\n });\n let tx: TransactionPool | undefined;\n let watermark: string;\n try {\n ({tx, watermark} = await createSnapshotTransaction(\n lc,\n upstreamURI,\n db,\n slot,\n ));\n await afterSnapshotForTesting?.();\n const {tableSpec, backfill, progress} = await validateSchema(\n lc,\n tx,\n publications,\n bf,\n watermark,\n );\n\n // Note: validateSchema ensures that the rowKey and columns are disjoint\n const {relation, columns} = backfill;\n const cols = [...relation.rowKey.columns, ...columns];\n // Resumable backfills are streamed in physical (i.e. ctid) order, which\n // is the natural order of a sequential or TID range scan (as enforced by\n // the settings in `stream()`). An ORDER BY is not used, as Postgres does\n // not consider either scan to be ordered, and would unnecessarily sort\n // the table.\n const order =\n progress.resumable && progress.start\n ? {\n after: /*sql*/ `ctid > '${progressMarkToCtid(progress.start.progressMark)}'::tid`,\n }\n : undefined;\n const stmts = makeDownloadStatements(\n tableSpec,\n cols,\n undefined,\n undefined,\n [...cols.map(col => id(col)), CTID_SELECT],\n order,\n );\n if (progress.start) {\n lc.info?.(\n `resuming backfill from ${progress.start.progressMark} ` +\n `(timeline ${progress.timeline})`,\n );\n }\n\n if (textCopy) {\n const types = await getTypeParsers(db, {returnJsonAsString: true});\n yield* stream(\n lc,\n tx,\n backfill,\n progress,\n stmts,\n `COPY (${stmts.select}) TO STDOUT`,\n new TsvParser(),\n cols.map(col => {\n const parser = types.getTypeParser(tableSpec.columns[col].typeOID);\n return (text: string) => parser(text) as JSONValue;\n }),\n (text: string) => text,\n flushThresholdBytes,\n );\n } else {\n const binaryStmts = makeDownloadStatements(\n tableSpec,\n cols,\n undefined,\n undefined,\n [...makeBinarySelectExprs(tableSpec, cols), CTID_SELECT],\n order,\n );\n\n yield* stream(\n lc,\n tx,\n backfill,\n progress,\n stmts,\n `COPY (${binaryStmts.select}) TO STDOUT WITH (FORMAT binary)`,\n new BinaryCopyParser(),\n cols.map(col => {\n const spec = tableSpec.columns[col];\n const decoder = hasBinaryDecoder(spec)\n ? makeBinaryDecoder(spec)\n : textCastDecoder;\n return (buf: Buffer) => decoder(buf) as unknown as JSONValue;\n }),\n (buf: Buffer) => buf.toString('utf8'), // ctid::text\n flushThresholdBytes,\n );\n }\n } catch (e) {\n // Although we make the best effort to validate the schema at the\n // transaction snapshot, certain forms of `ALTER TABLE` are not\n // MVCC safe and not \"frozen\" in the snapshot:\n //\n // https://www.postgresql.org/docs/current/mvcc-caveats.html\n //\n // Handle these errors as schema incompatibility errors rather than\n // unknown runtime errors.\n if (\n e instanceof postgres.PostgresError &&\n (e.code === PG_UNDEFINED_TABLE || e.code === PG_UNDEFINED_COLUMN)\n ) {\n throw new SchemaIncompatibilityError(bf, String(e), {cause: e});\n }\n throw e;\n } finally {\n tx?.setDone();\n // Workaround postgres.js hanging at the end of some COPY commands:\n // https://github.com/porsager/postgres/issues/499\n void db.end().catch(e => lc.warn?.(`error closing backfill connection`, e));\n }\n}\n\nasync function* stream<T>(\n lc: LogContext,\n tx: TransactionPool,\n backfill: BackfillParams,\n {timeline, resumable, start: startMark}: Progress,\n {\n getTotalRows,\n getTotalBytes,\n }: Pick<DownloadStatements, 'getTotalRows' | 'getTotalBytes'>,\n copyCommand: string,\n parser: {parse(chunk: Buffer): Iterable<T | null>},\n decoders: ((field: T) => JSONValue)[],\n ctidDecoder: (field: T) => string,\n flushThresholdBytes: number,\n): AsyncGenerator<BackfillMessage> {\n // Backfill must read every row: TABLESAMPLE / LIMIT are reserved for shadow\n // sync and must never appear in a backfill COPY.\n assert(\n !SAMPLE_OR_LIMIT_RE.test(copyCommand),\n `backfill COPY must not sample or limit: ${copyCommand}`,\n );\n const start = performance.now();\n const [rows, bytes] = await tx.processReadTask(sql =>\n Promise.all([\n sql.unsafe<{totalRows: bigint}[]>(getTotalRows),\n sql.unsafe<{totalBytes: bigint}[]>(getTotalBytes),\n ]),\n );\n const status: DownloadStatus = {\n rows: 0,\n totalRows: Number(rows[0].totalRows),\n totalBytes: Number(bytes[0].totalBytes),\n };\n\n let elapsed = (performance.now() - start).toFixed(3);\n lc.info?.(\n `Computed total rows and bytes for: ${copyCommand} (${elapsed} ms)`,\n {\n status,\n },\n );\n\n // Drain the COPY stream from *within* a single read task so that the\n // TransactionPool worker holds the transaction for the entire duration of\n // the COPY, rather than incorrectly considering the worker \"idle\" and\n // attempting to send keepalives on it.\n //\n // Chunks are bridged out to this generator via a Queue, with a corresponding\n // acks Queue providing strict one-chunk-at-a-time backpressure. This is\n // necessary because it is not possible to \"yield\" from within the read task.\n const chunks = new Queue<Buffer | 'done'>();\n const acks = new Queue<void>();\n\n const copyDone = tx.processReadTask(async sql => {\n // SET LOCAL applies to the (snapshot) transaction of this read task.\n for (const setting of PHYSICAL_ORDER_SETTINGS) {\n await sql.unsafe(`SET LOCAL ${setting}`);\n }\n const readable = await sql.unsafe(copyCommand).readable();\n for await (const chunk of readable) {\n chunks.enqueue(chunk as Buffer);\n await acks.dequeue(); // wait for this generator to consume the chunk\n }\n chunks.enqueue('done');\n });\n copyDone.catch(e => chunks.enqueueRejection(e));\n\n let totalBytes = 0;\n let totalMsgs = 0;\n let rowValues: JSONValue[][] = [];\n let bufferedBytes = 0;\n\n const logFlushed = () => {\n lc.debug?.(\n `Flushed ${rowValues.length} rows, ${bufferedBytes} bytes ` +\n `(total: rows=${status.rows}, msgs=${totalMsgs}, bytes=${totalBytes})`,\n );\n };\n\n // The mark of the last row that was streamed, and that of the last row of\n // the previous message.\n let current: BackfillProgressMark | undefined = startMark;\n let previous: BackfillProgressMark | undefined = startMark;\n const markOf = (progressMark: string) => ({progressMark, timeline});\n\n // The number of columns of each row, followed by the ctid.\n const numCols = decoders.length + 1;\n\n // Tracks the row being parsed.\n let row: JSONValue[] = Array.from({length: decoders.length});\n let col = 0;\n\n for (;;) {\n const chunk = await chunks.dequeue();\n if (chunk === 'done') {\n break;\n }\n for (const field of parser.parse(chunk)) {\n if (col < decoders.length) {\n row[col] = field === null ? null : decoders[col](field);\n } else {\n const mark = resumable\n ? ctidToProgressMark(ctidDecoder(field as T))\n : rowCountMark(status.rows + 1);\n if (current !== undefined && mark <= current.progressMark) {\n // This should not happen given the PHYSICAL_ORDER_SETTINGS, but\n // the correctness of the progress marks depends on it.\n throw new Error(\n `backfill rows are not in ctid order ` +\n `(${mark} after ${current.progressMark})`,\n );\n }\n current = markOf(mark);\n }\n\n if (++col === numCols) {\n rowValues.push(row);\n status.rows++;\n row = Array.from({length: decoders.length});\n col = 0;\n }\n }\n bufferedBytes += chunk.byteLength;\n totalBytes += chunk.byteLength;\n\n if (bufferedBytes >= flushThresholdBytes && rowValues.length > 0) {\n yield {\n message: {\n tag: 'backfill',\n ...backfill,\n rowValues,\n status,\n progressMarks: progressMarks(previous, must(current)),\n },\n byteSize: bufferedBytes,\n };\n previous = current;\n totalMsgs++;\n logFlushed();\n rowValues = [];\n bufferedBytes = 0;\n }\n\n // Signal the read task to pull the next chunk (one-chunk backpressure).\n acks.enqueue();\n }\n\n // Surface any error from the COPY read task (and confirm clean completion).\n await copyDone;\n\n // Flush the last batch of rows.\n if (rowValues.length > 0) {\n yield {\n message: {\n tag: 'backfill',\n ...backfill,\n rowValues,\n status,\n progressMarks: progressMarks(previous, must(current)),\n },\n byteSize: bufferedBytes,\n };\n previous = current;\n totalMsgs++;\n logFlushed();\n }\n\n yield {\n message: {\n tag: 'backfill-completed',\n ...backfill,\n status,\n // `previous` is only unset for a backfill from scratch with no rows.\n progressMarks: previous ? {previous} : {},\n },\n byteSize: 0,\n };\n elapsed = (performance.now() - start).toFixed(3);\n lc.info?.(\n `Finished streaming ${status.rows} rows, ${totalMsgs} msgs, ${totalBytes} bytes ` +\n `(${elapsed} ms)`,\n );\n}\n\n/**\n * Creates (and drops) a replication slot in order to obtain a snapshot\n * that corresponds with a specific LSN. Sets the snapshot on the\n * TransactionPool and returns the watermark corresponding to the LSN.\n *\n * (Note that PG's other LSN-related functions are not scoped to a\n * transaction; this is the only way to get set a transaction at a specific\n * LSN.)\n */\nasync function createSnapshotTransaction(\n lc: LogContext,\n upstreamURI: string,\n db: PostgresDB,\n slotNamePrefix: string,\n) {\n const replicationSession = pgClient(\n lc,\n upstreamURI,\n 'backfill-replication-session',\n {\n ['fetch_types']: false, // Necessary for the streaming protocol\n connection: {replication: 'database'}, // https://www.postgresql.org/docs/current/protocol-replication.html\n },\n );\n const slotName = `${slotNamePrefix}_bf_${Date.now()}`;\n try {\n const {snapshot_name: snapshot, consistent_point: lsn} =\n await createReplicationSlot(lc, replicationSession, {\n slotName,\n temporary: true, // deletes the slot when the replicationSession ends\n diagnosticsDB: db,\n });\n\n const {init, imported} = importSnapshot(snapshot);\n const tx = new TransactionPool(lc, {mode: READONLY, init}).run(db);\n await imported.dequeue();\n\n const watermark = toStateVersionString(lsn);\n lc.info?.(`Opened snapshot transaction at LSN ${lsn} (${watermark})`);\n return {tx, watermark};\n } finally {\n await replicationSession.end();\n }\n}\n\nfunction validateSchema(\n lc: LogContext,\n tx: TransactionPool,\n publications: string[],\n bf: BackfillRequest,\n watermark: string,\n): Promise<{\n tableSpec: PublishedTableSpec;\n backfill: BackfillParams;\n progress: Progress;\n}> {\n return tx.processReadTask(async sql => {\n const {tables} = await getPublicationInfo(sql, publications);\n const spec = tables.find(\n spec => spec.schema === bf.table.schema && spec.name === bf.table.name,\n );\n if (!spec) {\n throw new SchemaIncompatibilityError(\n bf,\n `Table has been renamed or dropped`,\n );\n }\n const tableMeta = v.parse(bf.table.metadata, tableMetadataSchema);\n if (spec.schemaOID !== tableMeta.schemaOID) {\n throw new SchemaIncompatibilityError(\n bf,\n `Schema no longer corresponds to the original schema`,\n );\n }\n if (spec.oid !== tableMeta.relationOID) {\n throw new SchemaIncompatibilityError(\n bf,\n `Table no longer corresponds to the original table`,\n );\n }\n if (\n !equals(\n new Set(Object.keys(tableMeta.rowKey)),\n new Set(spec.replicaIdentityColumns),\n )\n ) {\n throw new SchemaIncompatibilityError(\n bf,\n 'Row key (e.g. PRIMARY KEY or INDEX) has changed',\n );\n }\n const allCols = [\n ...Object.entries(tableMeta.rowKey),\n ...Object.entries(bf.columns).map(([col, {id}]) => [col, id] as const),\n ];\n for (const [col, val] of allCols) {\n const colSpec = spec.columns[col];\n if (!colSpec) {\n throw new SchemaIncompatibilityError(\n bf,\n `Column ${col} has been renamed or dropped`,\n );\n }\n const colMeta = v.parse(val, columnMetadataSchema);\n if (colMeta.attNum !== colSpec.pos) {\n throw new SchemaIncompatibilityError(\n bf,\n `Column ${col} no longer corresponds to the original column`,\n );\n }\n }\n const backfill: BackfillParams = {\n relation: {\n schema: bf.table.schema,\n name: bf.table.name,\n rowKey: {columns: Object.keys(tableMeta.rowKey)},\n },\n columns: Object.keys(bf.columns).filter(\n col => !(col in tableMeta.rowKey),\n ),\n watermark,\n };\n const progress = await getProgress(lc, sql, spec.oid, bf);\n return {tableSpec: spec, backfill, progress};\n });\n}\n\n/**\n * Determines the timeline of the table's progress marks (as of the snapshot),\n * and whether the backfill can be resumed from the requested progress.\n *\n * The table is locked (in ACCESS SHARE mode, as the COPY would, for the rest\n * of the transaction) so that its storage cannot be rewritten (by `VACUUM\n * FULL`, `CLUSTER`, `TRUNCATE`, or a rewriting `ALTER TABLE`, all of which\n * require ACCESS EXCLUSIVE) between reading the timeline and the COPY. Note\n * that `pg_relation_filenode()` reflects the table's current storage (only\n * refreshed upon acquiring a lock), whereas `pg_class.relfilenode` is read at\n * the transaction snapshot. If they differ, the storage was rewritten after the\n * snapshot, and the COPY would scan the new storage with the old snapshot,\n * which is not MVCC-safe for all rewrites (e.g. the table appears empty after\n * a rewriting `ALTER TABLE`). The backfill is then retried at a new snapshot.\n */\nasync function getProgress(\n lc: LogContext,\n sql: postgres.Sql,\n relationOID: number,\n bf: BackfillRequest,\n): Promise<Progress> {\n const table = `${id(bf.table.schema)}.${id(bf.table.name)}`;\n await sql.unsafe(`LOCK TABLE ${table} IN ACCESS SHARE MODE`);\n const [{lockedOID, relkind, snapshotFilenode, filenode}] = await sql<\n {\n lockedOID: number | null;\n relkind: string;\n snapshotFilenode: string;\n filenode: string | null;\n }[]\n >`\n SELECT to_regclass(${table})::oid::int8 AS \"lockedOID\",\n relkind,\n relfilenode::text AS \"snapshotFilenode\",\n pg_relation_filenode(oid)::text AS filenode\n FROM pg_class WHERE oid = ${relationOID}`;\n if (Number(lockedOID) !== relationOID) {\n // The (current) table with the name is not the one at the snapshot.\n throw new SchemaIncompatibilityError(\n bf,\n `Table has been renamed or replaced`,\n );\n }\n if (relkind !== 'r' || filenode === null) {\n // Not a plain table (e.g. a partitioned table), for which ctids are not\n // unique. Such backfills are not resumable, which is achieved by using a\n // timeline that is unique to the run.\n return {\n timeline: `${relkind}:${randomCharacters(12)}`,\n resumable: false,\n start: undefined,\n };\n }\n if (filenode !== snapshotFilenode) {\n throw new Error(\n `${bf.table.schema}.${bf.table.name} was rewritten after the backfill ` +\n `snapshot (relfilenode ${snapshotFilenode} => ${filenode})`,\n );\n }\n const timeline = filenode;\n const requested = resumePoint(bf);\n if (requested && requested.timeline !== timeline) {\n lc.info?.(\n `restarting backfill from scratch: the requested progress is on ` +\n `timeline ${requested.timeline} but the table is on ${timeline}`,\n );\n return {timeline, resumable: true, start: undefined};\n }\n if (requested && !(await canResume(sql, relationOID, bf))) {\n lc.info?.(\n `restarting backfill from scratch: the table has TOASTed values ` +\n `and backfilling columns [${Object.keys(bf.columns).join(',')}] ` +\n `are TOAST-able`,\n );\n return {timeline, resumable: true, start: undefined};\n }\n return {timeline, resumable: true, start: requested};\n}\n\n/**\n * Whether resuming a backfill (in a new snapshot) is guaranteed to deliver\n * the values of every row that the preceding snapshot(s) had not reached.\n *\n * Within a single snapshot, every row is scanned exactly once, since the\n * version visible to the snapshot stays in place while it is held. Across\n * snapshots, however, a row that had not yet been reached (i.e. beyond the\n * resume mark `M`) can be updated between the snapshots, with its new\n * version placed at or before `M` (a non-HOT update into free space in an\n * earlier page, or a HOT update into a lower line pointer of `M`'s page).\n * Neither snapshot then scans the row, and it is only delivered by the\n * replication stream. The stream's UPDATE contains the full row, _except_\n * for unchanged values stored out-of-line in TOAST, which pgoutput omits\n * (unless the table has REPLICA IDENTITY FULL). A backfilling column with\n * such a value would be published without it.\n *\n * Resuming is therefore only done if no backfilling column can be TOASTed\n * (i.e. all have `attstorage = 'p'`, as for fixed-width types), or if the\n * table has no TOAST data. The latter is safe because an omitted value must\n * still be in the TOAST relation at the new snapshot (unless its row has since\n * been deleted, which the replication stream does deliver), and conservative\n * because the TOAST relation does not shrink to empty without a heap rewrite,\n * which changes the timeline.\n *\n * Potential optimization for TOAST-able backfills: have the resumed run also\n * deliver the rows at or before `M` that were modified since the snapshot of\n * the run that started the backfill from scratch. That run's snapshot `xmin`\n * (`T_origin`, as an xid8) would be encoded in the timeline, i.e.\n * `timeline = \"<relfilenode>:<T_origin>\"`, and carried over (rather than\n * replaced) by resumed runs, so that:\n * * Within a chain of runs, every row version with `xmin < T_origin` stayed\n * in place across all of the runs' snapshots and was therefore scanned\n * exactly once, and all other rows are re-delivered by the resumed run\n * (`ctid > M OR xmin >= T_origin`).\n * * Continuations from a different chain (i.e. with a newer `T_origin`) are\n * not accepted by subscribers, and requests from different chains are\n * merged into a backfill from scratch, as the timelines differ. Note that\n * using the _latest_ `T` would be incorrect: rows that moved before `M`\n * between the earlier snapshots would never be re-delivered.\n * The resumed run would scan the whole table (but only deliver the modified\n * rows), comparing the 32-bit `xmin` with `T_origin` modulo 2^32, which\n * requires falling back to a backfill from scratch once the current xid is\n * 2^31 or more past `T_origin` (i.e. wraparound). This also relies on the\n * `xmin` system column returning the raw xmin of frozen tuples, which should\n * be verified.\n */\nasync function canResume(\n sql: postgres.Sql,\n relationOID: number,\n bf: BackfillRequest,\n): Promise<boolean> {\n const [{toastable, toasted}] = await sql<\n {toastable: boolean; toasted: boolean}[]\n >`\n SELECT\n EXISTS (\n SELECT 1 FROM pg_attribute\n WHERE attrelid = ${relationOID}\n AND attname IN ${sql(Object.keys(bf.columns))}\n AND attstorage <> 'p'\n ) AS toastable,\n reltoastrelid <> 0 AND pg_relation_size(reltoastrelid) > 0 AS toasted\n FROM pg_class WHERE oid = ${relationOID}`;\n return !toastable || !toasted;\n}\n"],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ import type { Readable } from 'node:stream';
2
+ import type { LogContext } from '@rocicorp/logger';
3
+ import { type PostgresDB } from '../../../types/pg.ts';
4
+ import { type ShardConfig, type ShardID } from '../../../types/shards.ts';
5
+ import { type ConstrainingPurgeLock, type InitializeResult, type RestoreOptions } from '../common/replica-restore.ts';
6
+ import { type InitialSyncOptions, type ReplicaOptions, type ServerContext } from './initial-sync.ts';
7
+ import { type LSN } from './lsn.ts';
8
+ import { type ReplicaState } from './schema/shard.ts';
9
+ export type InitializeOptions = ReplicaOptions & {
10
+ slotPerReplica: boolean | undefined;
11
+ inactiveReplicaGracePeriodMs: number;
12
+ };
13
+ /**
14
+ * Initializes a Postgres change source, including the initial sync of the
15
+ * replica, before streaming changes from the corresponding logical replication
16
+ * stream.
17
+ */
18
+ export declare function initializePostgresChangeSource(lc: LogContext, upstreamURI: string, shard: ShardConfig, replicaDbFile: string, syncOptions: InitialSyncOptions, context: ServerContext, lagReportIntervalMs?: number, restoreOptions?: RestoreOptions, { epoch, slotPerReplica, backupV5, inactiveReplicaGracePeriodMs, }?: InitializeOptions, streamInboundTimeoutMs?: number | undefined): Promise<InitializeResult>;
19
+ /**
20
+ * The watermark below which the replication stream cannot (correctly) be
21
+ * started, i.e. from which it would skip transactions that the change log
22
+ * does not contain. It reflects the order in which each mode stores a
23
+ * transaction and then acks it to the slot, such that a correctly initialized
24
+ * stream always starts at or past it:
25
+ *
26
+ * * After an initial sync, the replica's watermark, which is the position
27
+ * at which the new slot was created, and the change log is (re)initialized
28
+ * at it.
29
+ * * With a slot per replica (RMv1.5 and RMv2), the minimum of the restored
30
+ * replica's watermark and the slot's position. Transactions are only acked
31
+ * once backed up (so a skipped interval ends at or before the replica), and
32
+ * if the change log is behind the slot it is re-initialized from the
33
+ * replica. Note that the slot can be past the replica (acked for keepalives,
34
+ * with nothing skipped), and the replica past the change log (forwarded
35
+ * before being stored, and streamed again from the slot), but the stream
36
+ * never starts below both. (With RMv1.5's purge lock, the change log's head
37
+ * is at or past the slot, so it does not lower the minimum.)
38
+ * * With a shared slot (RMv1), the change log's head when it was purge
39
+ * locked, as the stream resumes from the head, which only advances. The
40
+ * slot is not a reference: its owner acks it until it is taken over. Without
41
+ * a purge lock (i.e. an empty change log), there is no floor.
42
+ */
43
+ export declare function minStartWatermark(replicaWatermark: string, initialSynced: boolean, slotWatermark: string | undefined, purgeLock: ConstrainingPurgeLock | null): string | undefined;
44
+ export declare function getSourceAndDestinationReplicas(lc: LogContext, sql: PostgresDB, shard: ShardID, epoch: number, slotFailover: boolean, gracePeriodMs: number, pollIntervalMs?: number): Promise<{
45
+ restoreFrom: ReplicaState;
46
+ replicateTo: ReplicaState;
47
+ /** The position of the slot from which replication resumes. */
48
+ slotLSN: LSN;
49
+ /**
50
+ * The session holding the destination slot active until it is taken
51
+ * over by the PostgresChangeSource. Destroying it releases the slot.
52
+ */
53
+ slotSession: Readable;
54
+ } | undefined>;
55
+ //# sourceMappingURL=change-source-init.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"change-source-init.d.ts","sourceRoot":"","sources":["../../../../../../../zero-cache/src/services/change-source/pg/change-source-init.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,aAAa,CAAC;AAC1C,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAQjD,OAAO,EAAkB,KAAK,UAAU,EAAC,MAAM,sBAAsB,CAAC;AACtE,OAAO,EAAC,KAAK,WAAW,EAAE,KAAK,OAAO,EAAC,MAAM,0BAA0B,CAAC;AAOxE,OAAO,EAEL,KAAK,qBAAqB,EAC1B,KAAK,gBAAgB,EACrB,KAAK,cAAc,EAEpB,MAAM,8BAA8B,CAAC;AAGtC,OAAO,EAEL,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAiC,KAAK,GAAG,EAAC,MAAM,UAAU,CAAC;AASlE,OAAO,EAOL,KAAK,YAAY,EAClB,MAAM,mBAAmB,CAAC;AAE3B,MAAM,MAAM,iBAAiB,GAAG,cAAc,GAAG;IAG/C,cAAc,EAAE,OAAO,GAAG,SAAS,CAAC;IAEpC,4BAA4B,EAAE,MAAM,CAAC;CACtC,CAAC;AAEF;;;;GAIG;AACH,wBAAsB,8BAA8B,CAClD,EAAE,EAAE,UAAU,EACd,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,WAAW,EAClB,aAAa,EAAE,MAAM,EACrB,WAAW,EAAE,kBAAkB,EAC/B,OAAO,EAAE,aAAa,EACtB,mBAAmB,SAAI,EACvB,cAAc,GAAE,cAAmB,EACnC,EACE,KAAK,EACL,cAAc,EACd,QAAQ,EACR,4BAA4B,GAC7B,GAAE,iBAKF,EACD,sBAAsB,CAAC,EAAE,MAAM,GAAG,SAAS,GAC1C,OAAO,CAAC,gBAAgB,CAAC,CA6I3B;AAkKD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,wBAAgB,iBAAiB,CAC/B,gBAAgB,EAAE,MAAM,EACxB,aAAa,EAAE,OAAO,EACtB,aAAa,EAAE,MAAM,GAAG,SAAS,EACjC,SAAS,EAAE,qBAAqB,GAAG,IAAI,GACtC,MAAM,GAAG,SAAS,CAQpB;AAsBD,wBAAsB,+BAA+B,CACnD,EAAE,EAAE,UAAU,EACd,GAAG,EAAE,UAAU,EACf,KAAK,EAAE,OAAO,EACd,KAAK,EAAE,MAAM,EACb,YAAY,EAAE,OAAO,EACrB,aAAa,EAAE,MAAM,EACrB,cAAc,SAA2B,GACxC,OAAO,CACN;IACE,WAAW,EAAE,YAAY,CAAC;IAC1B,WAAW,EAAE,YAAY,CAAC;IAC1B,+DAA+D;IAC/D,OAAO,EAAE,GAAG,CAAC;IACb;;;OAGG;IACH,WAAW,EAAE,QAAQ,CAAC;CACvB,GACD,SAAS,CACZ,CA4LA"}