@rocicorp/zero 1.11.0-canary.2 → 1.11.0-canary.21

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 (832) hide show
  1. package/out/analyze-query/src/bin-analyze.js +9 -8
  2. package/out/analyze-query/src/bin-analyze.js.map +1 -1
  3. package/out/ast-to-zql/src/ast-to-zql.d.ts +8 -1
  4. package/out/ast-to-zql/src/ast-to-zql.d.ts.map +1 -1
  5. package/out/ast-to-zql/src/ast-to-zql.js +25 -25
  6. package/out/ast-to-zql/src/ast-to-zql.js.map +1 -1
  7. package/out/otel/src/log-options.d.ts +16 -0
  8. package/out/otel/src/log-options.d.ts.map +1 -1
  9. package/out/otel/src/log-options.js +54 -1
  10. package/out/otel/src/log-options.js.map +1 -1
  11. package/out/replicache/src/bg-interval.d.ts +2 -1
  12. package/out/replicache/src/bg-interval.d.ts.map +1 -1
  13. package/out/replicache/src/bg-interval.js +13 -4
  14. package/out/replicache/src/bg-interval.js.map +1 -1
  15. package/out/replicache/src/btree/node.d.ts.map +1 -1
  16. package/out/replicache/src/btree/node.js +3 -6
  17. package/out/replicache/src/btree/node.js.map +1 -1
  18. package/out/replicache/src/dag/gc.d.ts.map +1 -1
  19. package/out/replicache/src/dag/gc.js +8 -11
  20. package/out/replicache/src/dag/gc.js.map +1 -1
  21. package/out/replicache/src/dag/invalid-ref-count-error.d.ts +12 -0
  22. package/out/replicache/src/dag/invalid-ref-count-error.d.ts.map +1 -0
  23. package/out/replicache/src/dag/invalid-ref-count-error.js +19 -0
  24. package/out/replicache/src/dag/invalid-ref-count-error.js.map +1 -0
  25. package/out/replicache/src/dag/lazy-store.d.ts +17 -4
  26. package/out/replicache/src/dag/lazy-store.d.ts.map +1 -1
  27. package/out/replicache/src/dag/lazy-store.js +35 -9
  28. package/out/replicache/src/dag/lazy-store.js.map +1 -1
  29. package/out/replicache/src/dag/store-impl.d.ts +12 -2
  30. package/out/replicache/src/dag/store-impl.d.ts.map +1 -1
  31. package/out/replicache/src/dag/store-impl.js +29 -9
  32. package/out/replicache/src/dag/store-impl.js.map +1 -1
  33. package/out/replicache/src/db/rebase.d.ts +14 -2
  34. package/out/replicache/src/db/rebase.d.ts.map +1 -1
  35. package/out/replicache/src/db/rebase.js +27 -5
  36. package/out/replicache/src/db/rebase.js.map +1 -1
  37. package/out/replicache/src/get-kv-store-provider.d.ts +1 -1
  38. package/out/replicache/src/get-kv-store-provider.d.ts.map +1 -1
  39. package/out/replicache/src/get-kv-store-provider.js +4 -4
  40. package/out/replicache/src/get-kv-store-provider.js.map +1 -1
  41. package/out/replicache/src/kv/expo-sqlite/store.d.ts.map +1 -1
  42. package/out/replicache/src/kv/expo-sqlite/store.js +28 -5
  43. package/out/replicache/src/kv/expo-sqlite/store.js.map +1 -1
  44. package/out/replicache/src/kv/idb-store.d.ts +18 -0
  45. package/out/replicache/src/kv/idb-store.d.ts.map +1 -1
  46. package/out/replicache/src/kv/idb-store.js +30 -2
  47. package/out/replicache/src/kv/idb-store.js.map +1 -1
  48. package/out/replicache/src/kv/mem-fallback-store.d.ts +54 -0
  49. package/out/replicache/src/kv/mem-fallback-store.d.ts.map +1 -0
  50. package/out/replicache/src/kv/mem-fallback-store.js +177 -0
  51. package/out/replicache/src/kv/mem-fallback-store.js.map +1 -0
  52. package/out/replicache/src/kv/mem-store.d.ts +1 -0
  53. package/out/replicache/src/kv/mem-store.d.ts.map +1 -1
  54. package/out/replicache/src/kv/mem-store.js +3 -0
  55. package/out/replicache/src/kv/mem-store.js.map +1 -1
  56. package/out/replicache/src/kv/op-sqlite/store.d.ts.map +1 -1
  57. package/out/replicache/src/kv/op-sqlite/store.js +4 -4
  58. package/out/replicache/src/kv/op-sqlite/store.js.map +1 -1
  59. package/out/replicache/src/kv/sqlite-store.d.ts +22 -1
  60. package/out/replicache/src/kv/sqlite-store.d.ts.map +1 -1
  61. package/out/replicache/src/kv/sqlite-store.js +159 -14
  62. package/out/replicache/src/kv/sqlite-store.js.map +1 -1
  63. package/out/replicache/src/kv/store.d.ts +6 -0
  64. package/out/replicache/src/kv/store.d.ts.map +1 -1
  65. package/out/replicache/src/new-client-channel.js.map +1 -1
  66. package/out/replicache/src/persist/client-gc.d.ts +2 -1
  67. package/out/replicache/src/persist/client-gc.d.ts.map +1 -1
  68. package/out/replicache/src/persist/client-gc.js +2 -2
  69. package/out/replicache/src/persist/client-gc.js.map +1 -1
  70. package/out/replicache/src/persist/client-group-gc.d.ts +2 -1
  71. package/out/replicache/src/persist/client-group-gc.d.ts.map +1 -1
  72. package/out/replicache/src/persist/client-group-gc.js +2 -2
  73. package/out/replicache/src/persist/client-group-gc.js.map +1 -1
  74. package/out/replicache/src/persist/collect-idb-databases.d.ts +28 -8
  75. package/out/replicache/src/persist/collect-idb-databases.d.ts.map +1 -1
  76. package/out/replicache/src/persist/collect-idb-databases.js +97 -20
  77. package/out/replicache/src/persist/collect-idb-databases.js.map +1 -1
  78. package/out/replicache/src/persist/heartbeat.d.ts +2 -1
  79. package/out/replicache/src/persist/heartbeat.d.ts.map +1 -1
  80. package/out/replicache/src/persist/heartbeat.js +2 -2
  81. package/out/replicache/src/persist/heartbeat.js.map +1 -1
  82. package/out/replicache/src/persist/idb-databases-store-db-name.js +1 -1
  83. package/out/replicache/src/persist/idb-databases-store-db-name.js.map +1 -1
  84. package/out/replicache/src/persist/persist.d.ts.map +1 -1
  85. package/out/replicache/src/persist/persist.js +18 -8
  86. package/out/replicache/src/persist/persist.js.map +1 -1
  87. package/out/replicache/src/persist/refresh.js +6 -2
  88. package/out/replicache/src/persist/refresh.js.map +1 -1
  89. package/out/replicache/src/replicache-impl.d.ts +85 -3
  90. package/out/replicache/src/replicache-impl.d.ts.map +1 -1
  91. package/out/replicache/src/replicache-impl.js +321 -29
  92. package/out/replicache/src/replicache-impl.js.map +1 -1
  93. package/out/replicache/src/replicache-options.d.ts +9 -0
  94. package/out/replicache/src/replicache-options.d.ts.map +1 -1
  95. package/out/replicache/src/storage-failure.d.ts +37 -0
  96. package/out/replicache/src/storage-failure.d.ts.map +1 -0
  97. package/out/replicache/src/storage-failure.js +31 -0
  98. package/out/replicache/src/storage-failure.js.map +1 -0
  99. package/out/shared/src/arrays.d.ts +5 -0
  100. package/out/shared/src/arrays.d.ts.map +1 -1
  101. package/out/shared/src/arrays.js +8 -10
  102. package/out/shared/src/arrays.js.map +1 -1
  103. package/out/shared/src/error.d.ts +11 -0
  104. package/out/shared/src/error.d.ts.map +1 -1
  105. package/out/shared/src/error.js +35 -1
  106. package/out/shared/src/error.js.map +1 -1
  107. package/out/shared/src/iterables.d.ts +2 -0
  108. package/out/shared/src/iterables.d.ts.map +1 -1
  109. package/out/shared/src/iterables.js +18 -1
  110. package/out/shared/src/iterables.js.map +1 -1
  111. package/out/shared/src/map.d.ts +24 -2
  112. package/out/shared/src/map.d.ts.map +1 -1
  113. package/out/shared/src/map.js +18 -4
  114. package/out/shared/src/map.js.map +1 -1
  115. package/out/shared/src/random-values.js +12 -1
  116. package/out/shared/src/random-values.js.map +1 -1
  117. package/out/shared/src/ring-buffer.d.ts +10 -0
  118. package/out/shared/src/ring-buffer.d.ts.map +1 -1
  119. package/out/shared/src/ring-buffer.js +26 -1
  120. package/out/shared/src/ring-buffer.js.map +1 -1
  121. package/out/z2s/src/compiler.js +1 -1
  122. package/out/z2s/src/sql.d.ts.map +1 -1
  123. package/out/z2s/src/sql.js +2 -2
  124. package/out/z2s/src/sql.js.map +1 -1
  125. package/out/zero/package.js +3 -4
  126. package/out/zero/package.js.map +1 -1
  127. package/out/zero/src/zero.js +2 -1
  128. package/out/zero-cache/src/auth/write-authorizer.d.ts.map +1 -1
  129. package/out/zero-cache/src/auth/write-authorizer.js +1 -0
  130. package/out/zero-cache/src/auth/write-authorizer.js.map +1 -1
  131. package/out/zero-cache/src/config/normalize.d.ts.map +1 -1
  132. package/out/zero-cache/src/config/normalize.js +26 -2
  133. package/out/zero-cache/src/config/normalize.js.map +1 -1
  134. package/out/zero-cache/src/config/zero-config.d.ts +102 -6
  135. package/out/zero-cache/src/config/zero-config.d.ts.map +1 -1
  136. package/out/zero-cache/src/config/zero-config.js +254 -57
  137. package/out/zero-cache/src/config/zero-config.js.map +1 -1
  138. package/out/zero-cache/src/db/lite-tables.d.ts.map +1 -1
  139. package/out/zero-cache/src/db/lite-tables.js +3 -4
  140. package/out/zero-cache/src/db/lite-tables.js.map +1 -1
  141. package/out/zero-cache/src/observability/events.js +4 -1
  142. package/out/zero-cache/src/observability/events.js.map +1 -1
  143. package/out/zero-cache/src/observability/log-throttle.d.ts +44 -0
  144. package/out/zero-cache/src/observability/log-throttle.d.ts.map +1 -0
  145. package/out/zero-cache/src/observability/log-throttle.js +76 -0
  146. package/out/zero-cache/src/observability/log-throttle.js.map +1 -0
  147. package/out/zero-cache/src/observability/metrics.d.ts.map +1 -1
  148. package/out/zero-cache/src/observability/metrics.js +2 -7
  149. package/out/zero-cache/src/observability/metrics.js.map +1 -1
  150. package/out/zero-cache/src/scripts/permissions.d.ts +16 -0
  151. package/out/zero-cache/src/scripts/permissions.d.ts.map +1 -1
  152. package/out/zero-cache/src/server/change-streamer.d.ts.map +1 -1
  153. package/out/zero-cache/src/server/change-streamer.js +27 -10
  154. package/out/zero-cache/src/server/change-streamer.js.map +1 -1
  155. package/out/zero-cache/src/server/inspector-delegate.d.ts +28 -2
  156. package/out/zero-cache/src/server/inspector-delegate.d.ts.map +1 -1
  157. package/out/zero-cache/src/server/inspector-delegate.js +37 -17
  158. package/out/zero-cache/src/server/inspector-delegate.js.map +1 -1
  159. package/out/zero-cache/src/server/main.d.ts.map +1 -1
  160. package/out/zero-cache/src/server/main.js +8 -1
  161. package/out/zero-cache/src/server/main.js.map +1 -1
  162. package/out/zero-cache/src/server/mutator.js +2 -0
  163. package/out/zero-cache/src/server/mutator.js.map +1 -1
  164. package/out/zero-cache/src/server/reaper.d.ts.map +1 -1
  165. package/out/zero-cache/src/server/reaper.js +2 -0
  166. package/out/zero-cache/src/server/reaper.js.map +1 -1
  167. package/out/zero-cache/src/server/replicator.d.ts +3 -0
  168. package/out/zero-cache/src/server/replicator.d.ts.map +1 -1
  169. package/out/zero-cache/src/server/replicator.js +79 -15
  170. package/out/zero-cache/src/server/replicator.js.map +1 -1
  171. package/out/zero-cache/src/server/runner/zero-dispatcher.d.ts.map +1 -1
  172. package/out/zero-cache/src/server/runner/zero-dispatcher.js +5 -0
  173. package/out/zero-cache/src/server/runner/zero-dispatcher.js.map +1 -1
  174. package/out/zero-cache/src/server/syncer-assigner.d.ts +14 -0
  175. package/out/zero-cache/src/server/syncer-assigner.d.ts.map +1 -0
  176. package/out/zero-cache/src/server/syncer-assigner.js +72 -0
  177. package/out/zero-cache/src/server/syncer-assigner.js.map +1 -0
  178. package/out/zero-cache/src/server/syncer.d.ts.map +1 -1
  179. package/out/zero-cache/src/server/syncer.js +24 -2
  180. package/out/zero-cache/src/server/syncer.js.map +1 -1
  181. package/out/zero-cache/src/server/worker-dispatcher.d.ts.map +1 -1
  182. package/out/zero-cache/src/server/worker-dispatcher.js +21 -4
  183. package/out/zero-cache/src/server/worker-dispatcher.js.map +1 -1
  184. package/out/zero-cache/src/services/analyze.d.ts.map +1 -1
  185. package/out/zero-cache/src/services/analyze.js +11 -9
  186. package/out/zero-cache/src/services/analyze.js.map +1 -1
  187. package/out/zero-cache/src/services/change-source/common/backfill-manager.d.ts.map +1 -1
  188. package/out/zero-cache/src/services/change-source/common/backfill-manager.js +198 -24
  189. package/out/zero-cache/src/services/change-source/common/backfill-manager.js.map +1 -1
  190. package/out/zero-cache/src/services/change-source/common/change-stream-multiplexer.d.ts.map +1 -1
  191. package/out/zero-cache/src/services/change-source/common/change-stream-multiplexer.js +15 -3
  192. package/out/zero-cache/src/services/change-source/common/change-stream-multiplexer.js.map +1 -1
  193. package/out/zero-cache/src/services/change-source/common/replica-schema.d.ts +1 -0
  194. package/out/zero-cache/src/services/change-source/common/replica-schema.d.ts.map +1 -1
  195. package/out/zero-cache/src/services/change-source/common/replica-schema.js +15 -3
  196. package/out/zero-cache/src/services/change-source/common/replica-schema.js.map +1 -1
  197. package/out/zero-cache/src/services/change-source/pg/backfill-stream.d.ts +9 -0
  198. package/out/zero-cache/src/services/change-source/pg/backfill-stream.d.ts.map +1 -1
  199. package/out/zero-cache/src/services/change-source/pg/backfill-stream.js +204 -18
  200. package/out/zero-cache/src/services/change-source/pg/backfill-stream.js.map +1 -1
  201. package/out/zero-cache/src/services/change-source/pg/change-source-init.d.ts +25 -0
  202. package/out/zero-cache/src/services/change-source/pg/change-source-init.d.ts.map +1 -0
  203. package/out/zero-cache/src/services/change-source/pg/change-source-init.js +202 -0
  204. package/out/zero-cache/src/services/change-source/pg/change-source-init.js.map +1 -0
  205. package/out/zero-cache/src/services/change-source/pg/change-source.d.ts +14 -16
  206. package/out/zero-cache/src/services/change-source/pg/change-source.d.ts.map +1 -1
  207. package/out/zero-cache/src/services/change-source/pg/change-source.js +64 -143
  208. package/out/zero-cache/src/services/change-source/pg/change-source.js.map +1 -1
  209. package/out/zero-cache/src/services/change-source/pg/initial-sync.d.ts +37 -2
  210. package/out/zero-cache/src/services/change-source/pg/initial-sync.d.ts.map +1 -1
  211. package/out/zero-cache/src/services/change-source/pg/initial-sync.js +53 -21
  212. package/out/zero-cache/src/services/change-source/pg/initial-sync.js.map +1 -1
  213. package/out/zero-cache/src/services/change-source/pg/replication-slot-cleanup-monitor.d.ts +16 -0
  214. package/out/zero-cache/src/services/change-source/pg/replication-slot-cleanup-monitor.d.ts.map +1 -0
  215. package/out/zero-cache/src/services/change-source/pg/replication-slot-cleanup-monitor.js +113 -0
  216. package/out/zero-cache/src/services/change-source/pg/replication-slot-cleanup-monitor.js.map +1 -0
  217. package/out/zero-cache/src/services/change-source/pg/replication-slots.d.ts +21 -15
  218. package/out/zero-cache/src/services/change-source/pg/replication-slots.d.ts.map +1 -1
  219. package/out/zero-cache/src/services/change-source/pg/replication-slots.js +86 -23
  220. package/out/zero-cache/src/services/change-source/pg/replication-slots.js.map +1 -1
  221. package/out/zero-cache/src/services/change-source/pg/schema/index-predicate.d.ts.map +1 -1
  222. package/out/zero-cache/src/services/change-source/pg/schema/index-predicate.js +68 -8
  223. package/out/zero-cache/src/services/change-source/pg/schema/index-predicate.js.map +1 -1
  224. package/out/zero-cache/src/services/change-source/pg/schema/init.d.ts.map +1 -1
  225. package/out/zero-cache/src/services/change-source/pg/schema/init.js +32 -1
  226. package/out/zero-cache/src/services/change-source/pg/schema/init.js.map +1 -1
  227. package/out/zero-cache/src/services/change-source/pg/schema/replica-stage-enum.d.ts +10 -0
  228. package/out/zero-cache/src/services/change-source/pg/schema/replica-stage-enum.d.ts.map +1 -0
  229. package/out/zero-cache/src/services/change-source/pg/schema/replica-stage-enum.js +6 -0
  230. package/out/zero-cache/src/services/change-source/pg/schema/replica-stage-enum.js.map +1 -0
  231. package/out/zero-cache/src/services/change-source/pg/schema/shard.d.ts +50 -27
  232. package/out/zero-cache/src/services/change-source/pg/schema/shard.d.ts.map +1 -1
  233. package/out/zero-cache/src/services/change-source/pg/schema/shard.js +100 -34
  234. package/out/zero-cache/src/services/change-source/pg/schema/shard.js.map +1 -1
  235. package/out/zero-cache/src/services/change-source/protocol/backfill-progress.d.ts +68 -0
  236. package/out/zero-cache/src/services/change-source/protocol/backfill-progress.d.ts.map +1 -0
  237. package/out/zero-cache/src/services/change-source/protocol/backfill-progress.js +141 -0
  238. package/out/zero-cache/src/services/change-source/protocol/backfill-progress.js.map +1 -0
  239. package/out/zero-cache/src/services/change-source/protocol/current/data.d.ts +43 -0
  240. package/out/zero-cache/src/services/change-source/protocol/current/data.d.ts.map +1 -1
  241. package/out/zero-cache/src/services/change-source/protocol/current/data.js +10 -1
  242. package/out/zero-cache/src/services/change-source/protocol/current/data.js.map +1 -1
  243. package/out/zero-cache/src/services/change-source/protocol/current/downstream.d.ts +57 -0
  244. package/out/zero-cache/src/services/change-source/protocol/current/downstream.d.ts.map +1 -1
  245. package/out/zero-cache/src/services/change-source/protocol/current/upstream.d.ts +20 -6
  246. package/out/zero-cache/src/services/change-source/protocol/current/upstream.d.ts.map +1 -1
  247. package/out/zero-cache/src/services/change-source/protocol/current/upstream.js +17 -7
  248. package/out/zero-cache/src/services/change-source/protocol/current/upstream.js.map +1 -1
  249. package/out/zero-cache/src/services/change-source/protocol/current.js +2 -1
  250. package/out/zero-cache/src/services/change-streamer/backfill-state-tracker.d.ts +66 -0
  251. package/out/zero-cache/src/services/change-streamer/backfill-state-tracker.d.ts.map +1 -0
  252. package/out/zero-cache/src/services/change-streamer/backfill-state-tracker.js +154 -0
  253. package/out/zero-cache/src/services/change-streamer/backfill-state-tracker.js.map +1 -0
  254. package/out/zero-cache/src/services/change-streamer/backfill-state.d.ts +50 -0
  255. package/out/zero-cache/src/services/change-streamer/backfill-state.d.ts.map +1 -0
  256. package/out/zero-cache/src/services/change-streamer/backfill-state.js +268 -0
  257. package/out/zero-cache/src/services/change-streamer/backfill-state.js.map +1 -0
  258. package/out/zero-cache/src/services/change-streamer/backup-cleanup-monitor-factory.d.ts.map +1 -1
  259. package/out/zero-cache/src/services/change-streamer/backup-cleanup-monitor-factory.js +2 -0
  260. package/out/zero-cache/src/services/change-streamer/backup-cleanup-monitor-factory.js.map +1 -1
  261. package/out/zero-cache/src/services/change-streamer/backup-monitor.d.ts.map +1 -1
  262. package/out/zero-cache/src/services/change-streamer/backup-monitor.js +58 -7
  263. package/out/zero-cache/src/services/change-streamer/backup-monitor.js.map +1 -1
  264. package/out/zero-cache/src/services/change-streamer/broadcast.d.ts +8 -2
  265. package/out/zero-cache/src/services/change-streamer/broadcast.d.ts.map +1 -1
  266. package/out/zero-cache/src/services/change-streamer/broadcast.js +24 -4
  267. package/out/zero-cache/src/services/change-streamer/broadcast.js.map +1 -1
  268. package/out/zero-cache/src/services/change-streamer/change-log-codec.d.ts +19 -4
  269. package/out/zero-cache/src/services/change-streamer/change-log-codec.d.ts.map +1 -1
  270. package/out/zero-cache/src/services/change-streamer/change-log-codec.js +28 -8
  271. package/out/zero-cache/src/services/change-streamer/change-log-codec.js.map +1 -1
  272. package/out/zero-cache/src/services/change-streamer/change-streamer-http.d.ts +48 -6
  273. package/out/zero-cache/src/services/change-streamer/change-streamer-http.d.ts.map +1 -1
  274. package/out/zero-cache/src/services/change-streamer/change-streamer-http.js +130 -34
  275. package/out/zero-cache/src/services/change-streamer/change-streamer-http.js.map +1 -1
  276. package/out/zero-cache/src/services/change-streamer/change-streamer-service.d.ts +11 -0
  277. package/out/zero-cache/src/services/change-streamer/change-streamer-service.d.ts.map +1 -1
  278. package/out/zero-cache/src/services/change-streamer/change-streamer-service.js +118 -68
  279. package/out/zero-cache/src/services/change-streamer/change-streamer-service.js.map +1 -1
  280. package/out/zero-cache/src/services/change-streamer/change-streamer.d.ts +37 -15
  281. package/out/zero-cache/src/services/change-streamer/change-streamer.d.ts.map +1 -1
  282. package/out/zero-cache/src/services/change-streamer/change-streamer.js.map +1 -1
  283. package/out/zero-cache/src/services/change-streamer/forwarder.d.ts +3 -3
  284. package/out/zero-cache/src/services/change-streamer/forwarder.d.ts.map +1 -1
  285. package/out/zero-cache/src/services/change-streamer/forwarder.js +36 -5
  286. package/out/zero-cache/src/services/change-streamer/forwarder.js.map +1 -1
  287. package/out/zero-cache/src/services/change-streamer/litestream-sync-requester.d.ts +51 -0
  288. package/out/zero-cache/src/services/change-streamer/litestream-sync-requester.d.ts.map +1 -0
  289. package/out/zero-cache/src/services/change-streamer/litestream-sync-requester.js +132 -0
  290. package/out/zero-cache/src/services/change-streamer/litestream-sync-requester.js.map +1 -0
  291. package/out/zero-cache/src/services/change-streamer/schema/tables.d.ts +1 -1
  292. package/out/zero-cache/src/services/change-streamer/schema/tables.d.ts.map +1 -1
  293. package/out/zero-cache/src/services/change-streamer/schema/tables.js +19 -8
  294. package/out/zero-cache/src/services/change-streamer/schema/tables.js.map +1 -1
  295. package/out/zero-cache/src/services/change-streamer/snapshot-message.d.ts +92 -0
  296. package/out/zero-cache/src/services/change-streamer/snapshot-message.d.ts.map +1 -0
  297. package/out/zero-cache/src/services/change-streamer/snapshot-message.js +42 -0
  298. package/out/zero-cache/src/services/change-streamer/snapshot-message.js.map +1 -0
  299. package/out/zero-cache/src/services/change-streamer/snapshot-reservations.d.ts +1 -1
  300. package/out/zero-cache/src/services/change-streamer/snapshot-reservations.d.ts.map +1 -1
  301. package/out/zero-cache/src/services/change-streamer/snapshot-reservations.js +16 -4
  302. package/out/zero-cache/src/services/change-streamer/snapshot-reservations.js.map +1 -1
  303. package/out/zero-cache/src/services/change-streamer/snapshot.d.ts +7 -69
  304. package/out/zero-cache/src/services/change-streamer/snapshot.d.ts.map +1 -1
  305. package/out/zero-cache/src/services/change-streamer/snapshot.js +21 -53
  306. package/out/zero-cache/src/services/change-streamer/snapshot.js.map +1 -1
  307. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-writer.d.ts +6 -1
  308. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-writer.d.ts.map +1 -1
  309. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-writer.js +27 -9
  310. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-writer.js.map +1 -1
  311. package/out/zero-cache/src/services/change-streamer/storer.d.ts +2 -2
  312. package/out/zero-cache/src/services/change-streamer/storer.d.ts.map +1 -1
  313. package/out/zero-cache/src/services/change-streamer/storer.js +9 -6
  314. package/out/zero-cache/src/services/change-streamer/storer.js.map +1 -1
  315. package/out/zero-cache/src/services/change-streamer/subscribe.d.ts +446 -0
  316. package/out/zero-cache/src/services/change-streamer/subscribe.d.ts.map +1 -0
  317. package/out/zero-cache/src/services/change-streamer/subscribe.js +76 -0
  318. package/out/zero-cache/src/services/change-streamer/subscribe.js.map +1 -0
  319. package/out/zero-cache/src/services/change-streamer/subscriber.d.ts +33 -1
  320. package/out/zero-cache/src/services/change-streamer/subscriber.d.ts.map +1 -1
  321. package/out/zero-cache/src/services/change-streamer/subscriber.js +76 -0
  322. package/out/zero-cache/src/services/change-streamer/subscriber.js.map +1 -1
  323. package/out/zero-cache/src/services/change-streamer/upstream-acker.d.ts +17 -1
  324. package/out/zero-cache/src/services/change-streamer/upstream-acker.d.ts.map +1 -1
  325. package/out/zero-cache/src/services/change-streamer/upstream-acker.js +19 -3
  326. package/out/zero-cache/src/services/change-streamer/upstream-acker.js.map +1 -1
  327. package/out/zero-cache/src/services/change-streamer/vfs-watermark-poller.d.ts +5 -0
  328. package/out/zero-cache/src/services/change-streamer/vfs-watermark-poller.d.ts.map +1 -1
  329. package/out/zero-cache/src/services/change-streamer/vfs-watermark-poller.js +35 -5
  330. package/out/zero-cache/src/services/change-streamer/vfs-watermark-poller.js.map +1 -1
  331. package/out/zero-cache/src/services/life-cycle.d.ts.map +1 -1
  332. package/out/zero-cache/src/services/life-cycle.js +3 -1
  333. package/out/zero-cache/src/services/life-cycle.js.map +1 -1
  334. package/out/zero-cache/src/services/litestream/commands.d.ts +15 -3
  335. package/out/zero-cache/src/services/litestream/commands.d.ts.map +1 -1
  336. package/out/zero-cache/src/services/litestream/commands.js +24 -7
  337. package/out/zero-cache/src/services/litestream/commands.js.map +1 -1
  338. package/out/zero-cache/src/services/litestream/config-v5.yml +11 -4
  339. package/out/zero-cache/src/services/litestream/litestream-checkpointer.js +51 -24
  340. package/out/zero-cache/src/services/litestream/litestream-checkpointer.js.map +1 -1
  341. package/out/zero-cache/src/services/litestream/litestream-controller.d.ts +10 -2
  342. package/out/zero-cache/src/services/litestream/litestream-controller.d.ts.map +1 -1
  343. package/out/zero-cache/src/services/litestream/litestream-controller.js +3 -2
  344. package/out/zero-cache/src/services/litestream/litestream-controller.js.map +1 -1
  345. package/out/zero-cache/src/services/litestream/restore-progress.d.ts +24 -0
  346. package/out/zero-cache/src/services/litestream/restore-progress.d.ts.map +1 -0
  347. package/out/zero-cache/src/services/litestream/restore-progress.js +91 -0
  348. package/out/zero-cache/src/services/litestream/restore-progress.js.map +1 -0
  349. package/out/zero-cache/src/services/mutagen/mutagen.d.ts +5 -0
  350. package/out/zero-cache/src/services/mutagen/mutagen.d.ts.map +1 -1
  351. package/out/zero-cache/src/services/mutagen/mutagen.js +7 -1
  352. package/out/zero-cache/src/services/mutagen/mutagen.js.map +1 -1
  353. package/out/zero-cache/src/services/mutagen/pusher.d.ts.map +1 -1
  354. package/out/zero-cache/src/services/mutagen/pusher.js +5 -6
  355. package/out/zero-cache/src/services/mutagen/pusher.js.map +1 -1
  356. package/out/zero-cache/src/services/plannerz.d.ts +163 -0
  357. package/out/zero-cache/src/services/plannerz.d.ts.map +1 -0
  358. package/out/zero-cache/src/services/plannerz.js +267 -0
  359. package/out/zero-cache/src/services/plannerz.js.map +1 -0
  360. package/out/zero-cache/src/services/profz.d.ts +30 -0
  361. package/out/zero-cache/src/services/profz.d.ts.map +1 -0
  362. package/out/zero-cache/src/services/profz.js +145 -0
  363. package/out/zero-cache/src/services/profz.js.map +1 -0
  364. package/out/zero-cache/src/services/replicator/change-log-cookies.js +1 -1
  365. package/out/zero-cache/src/services/replicator/change-log-cookies.js.map +1 -1
  366. package/out/zero-cache/src/services/replicator/change-log-stream-writer.d.ts +5 -4
  367. package/out/zero-cache/src/services/replicator/change-log-stream-writer.d.ts.map +1 -1
  368. package/out/zero-cache/src/services/replicator/change-log-stream-writer.js +20 -22
  369. package/out/zero-cache/src/services/replicator/change-log-stream-writer.js.map +1 -1
  370. package/out/zero-cache/src/services/replicator/change-processor.d.ts.map +1 -1
  371. package/out/zero-cache/src/services/replicator/change-processor.js +49 -5
  372. package/out/zero-cache/src/services/replicator/change-processor.js.map +1 -1
  373. package/out/zero-cache/src/services/replicator/incremental-sync.d.ts +3 -2
  374. package/out/zero-cache/src/services/replicator/incremental-sync.d.ts.map +1 -1
  375. package/out/zero-cache/src/services/replicator/incremental-sync.js +50 -20
  376. package/out/zero-cache/src/services/replicator/incremental-sync.js.map +1 -1
  377. package/out/zero-cache/src/services/replicator/replication-status.d.ts +35 -1
  378. package/out/zero-cache/src/services/replicator/replication-status.d.ts.map +1 -1
  379. package/out/zero-cache/src/services/replicator/replication-status.js +96 -6
  380. package/out/zero-cache/src/services/replicator/replication-status.js.map +1 -1
  381. package/out/zero-cache/src/services/replicator/replicator.d.ts +2 -1
  382. package/out/zero-cache/src/services/replicator/replicator.d.ts.map +1 -1
  383. package/out/zero-cache/src/services/replicator/replicator.js +2 -2
  384. package/out/zero-cache/src/services/replicator/replicator.js.map +1 -1
  385. package/out/zero-cache/src/services/replicator/schema/backfilling.d.ts +23 -2
  386. package/out/zero-cache/src/services/replicator/schema/backfilling.d.ts.map +1 -1
  387. package/out/zero-cache/src/services/replicator/schema/backfilling.js +54 -2
  388. package/out/zero-cache/src/services/replicator/schema/backfilling.js.map +1 -1
  389. package/out/zero-cache/src/services/replicator/sqlite-change-log-observability.d.ts +6 -6
  390. package/out/zero-cache/src/services/replicator/sqlite-change-log-observability.d.ts.map +1 -1
  391. package/out/zero-cache/src/services/replicator/sqlite-change-log-observability.js +19 -14
  392. package/out/zero-cache/src/services/replicator/sqlite-change-log-observability.js.map +1 -1
  393. package/out/zero-cache/src/services/replicator/write-worker-client.d.ts +11 -3
  394. package/out/zero-cache/src/services/replicator/write-worker-client.d.ts.map +1 -1
  395. package/out/zero-cache/src/services/replicator/write-worker-client.js.map +1 -1
  396. package/out/zero-cache/src/services/replicator/write-worker.js +5 -1
  397. package/out/zero-cache/src/services/replicator/write-worker.js.map +1 -1
  398. package/out/zero-cache/src/services/run-ast.d.ts +12 -0
  399. package/out/zero-cache/src/services/run-ast.d.ts.map +1 -1
  400. package/out/zero-cache/src/services/run-ast.js +26 -14
  401. package/out/zero-cache/src/services/run-ast.js.map +1 -1
  402. package/out/zero-cache/src/services/runner.d.ts +2 -1
  403. package/out/zero-cache/src/services/runner.d.ts.map +1 -1
  404. package/out/zero-cache/src/services/runner.js +10 -2
  405. package/out/zero-cache/src/services/runner.js.map +1 -1
  406. package/out/zero-cache/src/services/statz.d.ts +4 -0
  407. package/out/zero-cache/src/services/statz.d.ts.map +1 -1
  408. package/out/zero-cache/src/services/statz.js +22 -5
  409. package/out/zero-cache/src/services/statz.js.map +1 -1
  410. package/out/zero-cache/src/services/view-syncer/client-handler.d.ts +19 -2
  411. package/out/zero-cache/src/services/view-syncer/client-handler.d.ts.map +1 -1
  412. package/out/zero-cache/src/services/view-syncer/client-handler.js +42 -30
  413. package/out/zero-cache/src/services/view-syncer/client-handler.js.map +1 -1
  414. package/out/zero-cache/src/services/view-syncer/cvr-store.d.ts +19 -1
  415. package/out/zero-cache/src/services/view-syncer/cvr-store.d.ts.map +1 -1
  416. package/out/zero-cache/src/services/view-syncer/cvr-store.js +34 -11
  417. package/out/zero-cache/src/services/view-syncer/cvr-store.js.map +1 -1
  418. package/out/zero-cache/src/services/view-syncer/cvr.d.ts +51 -2
  419. package/out/zero-cache/src/services/view-syncer/cvr.d.ts.map +1 -1
  420. package/out/zero-cache/src/services/view-syncer/cvr.js +142 -6
  421. package/out/zero-cache/src/services/view-syncer/cvr.js.map +1 -1
  422. package/out/zero-cache/src/services/view-syncer/deferred-writes-budget.d.ts +81 -0
  423. package/out/zero-cache/src/services/view-syncer/deferred-writes-budget.d.ts.map +1 -0
  424. package/out/zero-cache/src/services/view-syncer/deferred-writes-budget.js +128 -0
  425. package/out/zero-cache/src/services/view-syncer/deferred-writes-budget.js.map +1 -0
  426. package/out/zero-cache/src/services/view-syncer/drain-coordinator.d.ts +14 -1
  427. package/out/zero-cache/src/services/view-syncer/drain-coordinator.d.ts.map +1 -1
  428. package/out/zero-cache/src/services/view-syncer/drain-coordinator.js +30 -4
  429. package/out/zero-cache/src/services/view-syncer/drain-coordinator.js.map +1 -1
  430. package/out/zero-cache/src/services/view-syncer/hydration-budget.d.ts +33 -0
  431. package/out/zero-cache/src/services/view-syncer/hydration-budget.d.ts.map +1 -0
  432. package/out/zero-cache/src/services/view-syncer/hydration-budget.js +62 -0
  433. package/out/zero-cache/src/services/view-syncer/hydration-budget.js.map +1 -0
  434. package/out/zero-cache/src/services/view-syncer/hydration-circuit-breaker.d.ts +51 -0
  435. package/out/zero-cache/src/services/view-syncer/hydration-circuit-breaker.d.ts.map +1 -0
  436. package/out/zero-cache/src/services/view-syncer/hydration-circuit-breaker.js +78 -0
  437. package/out/zero-cache/src/services/view-syncer/hydration-circuit-breaker.js.map +1 -0
  438. package/out/zero-cache/src/services/view-syncer/inspect-handler.d.ts +1 -1
  439. package/out/zero-cache/src/services/view-syncer/inspect-handler.d.ts.map +1 -1
  440. package/out/zero-cache/src/services/view-syncer/inspect-handler.js +3 -3
  441. package/out/zero-cache/src/services/view-syncer/inspect-handler.js.map +1 -1
  442. package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts +50 -2
  443. package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts.map +1 -1
  444. package/out/zero-cache/src/services/view-syncer/pipeline-driver.js +466 -62
  445. package/out/zero-cache/src/services/view-syncer/pipeline-driver.js.map +1 -1
  446. package/out/zero-cache/src/services/view-syncer/plan-warnings.d.ts +7 -0
  447. package/out/zero-cache/src/services/view-syncer/plan-warnings.d.ts.map +1 -0
  448. package/out/zero-cache/src/services/view-syncer/plan-warnings.js +35 -0
  449. package/out/zero-cache/src/services/view-syncer/plan-warnings.js.map +1 -0
  450. package/out/zero-cache/src/services/view-syncer/query-covering.d.ts.map +1 -1
  451. package/out/zero-cache/src/services/view-syncer/query-covering.js +2 -6
  452. package/out/zero-cache/src/services/view-syncer/query-covering.js.map +1 -1
  453. package/out/zero-cache/src/services/view-syncer/query-shape.d.ts +25 -0
  454. package/out/zero-cache/src/services/view-syncer/query-shape.d.ts.map +1 -0
  455. package/out/zero-cache/src/services/view-syncer/query-shape.js +28 -0
  456. package/out/zero-cache/src/services/view-syncer/query-shape.js.map +1 -0
  457. package/out/zero-cache/src/services/view-syncer/query-stats.d.ts +77 -0
  458. package/out/zero-cache/src/services/view-syncer/query-stats.d.ts.map +1 -0
  459. package/out/zero-cache/src/services/view-syncer/query-stats.js +206 -0
  460. package/out/zero-cache/src/services/view-syncer/query-stats.js.map +1 -0
  461. package/out/zero-cache/src/services/view-syncer/snapshot-row-cache.d.ts +95 -0
  462. package/out/zero-cache/src/services/view-syncer/snapshot-row-cache.d.ts.map +1 -0
  463. package/out/zero-cache/src/services/view-syncer/snapshot-row-cache.js +155 -0
  464. package/out/zero-cache/src/services/view-syncer/snapshot-row-cache.js.map +1 -0
  465. package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts +78 -4
  466. package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts.map +1 -1
  467. package/out/zero-cache/src/services/view-syncer/snapshotter.js +158 -28
  468. package/out/zero-cache/src/services/view-syncer/snapshotter.js.map +1 -1
  469. package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts +11 -1
  470. package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts.map +1 -1
  471. package/out/zero-cache/src/services/view-syncer/view-syncer.js +587 -103
  472. package/out/zero-cache/src/services/view-syncer/view-syncer.js.map +1 -1
  473. package/out/zero-cache/src/types/processes.d.ts +39 -0
  474. package/out/zero-cache/src/types/processes.d.ts.map +1 -1
  475. package/out/zero-cache/src/types/processes.js +43 -4
  476. package/out/zero-cache/src/types/processes.js.map +1 -1
  477. package/out/zero-cache/src/types/profiler.d.ts +12 -0
  478. package/out/zero-cache/src/types/profiler.d.ts.map +1 -1
  479. package/out/zero-cache/src/types/profiler.js +46 -1
  480. package/out/zero-cache/src/types/profiler.js.map +1 -1
  481. package/out/zero-cache/src/types/row-key.d.ts.map +1 -1
  482. package/out/zero-cache/src/types/row-key.js +5 -5
  483. package/out/zero-cache/src/types/row-key.js.map +1 -1
  484. package/out/zero-cache/src/types/streams.d.ts +49 -7
  485. package/out/zero-cache/src/types/streams.d.ts.map +1 -1
  486. package/out/zero-cache/src/types/streams.js +190 -58
  487. package/out/zero-cache/src/types/streams.js.map +1 -1
  488. package/out/zero-cache/src/types/subscription.d.ts +15 -0
  489. package/out/zero-cache/src/types/subscription.d.ts.map +1 -1
  490. package/out/zero-cache/src/types/subscription.js +123 -31
  491. package/out/zero-cache/src/types/subscription.js.map +1 -1
  492. package/out/zero-cache/src/types/websocket-handoff.d.ts +1 -1
  493. package/out/zero-cache/src/types/websocket-handoff.d.ts.map +1 -1
  494. package/out/zero-cache/src/types/websocket-handoff.js +18 -9
  495. package/out/zero-cache/src/types/websocket-handoff.js.map +1 -1
  496. package/out/zero-cache/src/types/ws.d.ts.map +1 -1
  497. package/out/zero-cache/src/types/ws.js +1 -16
  498. package/out/zero-cache/src/types/ws.js.map +1 -1
  499. package/out/zero-cache/src/workers/connect-params.d.ts +1 -0
  500. package/out/zero-cache/src/workers/connect-params.d.ts.map +1 -1
  501. package/out/zero-cache/src/workers/connect-params.js.map +1 -1
  502. package/out/zero-cache/src/workers/syncer-ws-message-handler.d.ts.map +1 -1
  503. package/out/zero-cache/src/workers/syncer-ws-message-handler.js +21 -16
  504. package/out/zero-cache/src/workers/syncer-ws-message-handler.js.map +1 -1
  505. package/out/zero-cache/src/workers/syncer.d.ts.map +1 -1
  506. package/out/zero-cache/src/workers/syncer.js +55 -4
  507. package/out/zero-cache/src/workers/syncer.js.map +1 -1
  508. package/out/zero-client/src/client/active-clients-manager.d.ts.map +1 -1
  509. package/out/zero-client/src/client/active-clients-manager.js +4 -1
  510. package/out/zero-client/src/client/active-clients-manager.js.map +1 -1
  511. package/out/zero-client/src/client/connection-manager.d.ts +20 -0
  512. package/out/zero-client/src/client/connection-manager.d.ts.map +1 -1
  513. package/out/zero-client/src/client/connection-manager.js +77 -13
  514. package/out/zero-client/src/client/connection-manager.js.map +1 -1
  515. package/out/zero-client/src/client/connection-status-enum.d.ts +2 -0
  516. package/out/zero-client/src/client/connection-status-enum.d.ts.map +1 -1
  517. package/out/zero-client/src/client/connection-status-enum.js +3 -1
  518. package/out/zero-client/src/client/connection-status-enum.js.map +1 -1
  519. package/out/zero-client/src/client/connection.d.ts +6 -0
  520. package/out/zero-client/src/client/connection.d.ts.map +1 -1
  521. package/out/zero-client/src/client/connection.js +2 -1
  522. package/out/zero-client/src/client/connection.js.map +1 -1
  523. package/out/zero-client/src/client/context.d.ts +22 -12
  524. package/out/zero-client/src/client/context.d.ts.map +1 -1
  525. package/out/zero-client/src/client/context.js +92 -25
  526. package/out/zero-client/src/client/context.js.map +1 -1
  527. package/out/zero-client/src/client/custom.js +2 -2
  528. package/out/zero-client/src/client/custom.js.map +1 -1
  529. package/out/zero-client/src/client/error.js +1 -1
  530. package/out/zero-client/src/client/ivm-branch.d.ts.map +1 -1
  531. package/out/zero-client/src/client/ivm-branch.js +20 -3
  532. package/out/zero-client/src/client/ivm-branch.js.map +1 -1
  533. package/out/zero-client/src/client/mutator-proxy.d.ts.map +1 -1
  534. package/out/zero-client/src/client/mutator-proxy.js +5 -2
  535. package/out/zero-client/src/client/mutator-proxy.js.map +1 -1
  536. package/out/zero-client/src/client/options.d.ts +33 -0
  537. package/out/zero-client/src/client/options.d.ts.map +1 -1
  538. package/out/zero-client/src/client/options.js.map +1 -1
  539. package/out/zero-client/src/client/query-manager.d.ts.map +1 -1
  540. package/out/zero-client/src/client/query-manager.js +44 -11
  541. package/out/zero-client/src/client/query-manager.js.map +1 -1
  542. package/out/zero-client/src/client/version.js +1 -1
  543. package/out/zero-client/src/client/zero-rep.d.ts +1 -0
  544. package/out/zero-client/src/client/zero-rep.d.ts.map +1 -1
  545. package/out/zero-client/src/client/zero-rep.js +8 -6
  546. package/out/zero-client/src/client/zero-rep.js.map +1 -1
  547. package/out/zero-client/src/client/zero.d.ts +18 -3
  548. package/out/zero-client/src/client/zero.d.ts.map +1 -1
  549. package/out/zero-client/src/client/zero.js +84 -47
  550. package/out/zero-client/src/client/zero.js.map +1 -1
  551. package/out/zero-client/src/mod.d.ts +1 -0
  552. package/out/zero-client/src/mod.d.ts.map +1 -1
  553. package/out/zero-client/src/mod.js +1 -0
  554. package/out/zero-client/src/types/query-result.d.ts +2 -0
  555. package/out/zero-client/src/types/query-result.d.ts.map +1 -1
  556. package/out/zero-events/src/status.d.ts +58 -0
  557. package/out/zero-events/src/status.d.ts.map +1 -1
  558. package/out/zero-protocol/src/ast.d.ts.map +1 -1
  559. package/out/zero-protocol/src/ast.js +13 -14
  560. package/out/zero-protocol/src/ast.js.map +1 -1
  561. package/out/zero-protocol/src/down.d.ts +29 -29
  562. package/out/zero-protocol/src/query-hash.d.ts.map +1 -1
  563. package/out/zero-protocol/src/query-hash.js +2 -5
  564. package/out/zero-protocol/src/query-hash.js.map +1 -1
  565. package/out/zero-react/src/use-query.d.ts +5 -4
  566. package/out/zero-react/src/use-query.d.ts.map +1 -1
  567. package/out/zero-react/src/use-query.js +62 -4
  568. package/out/zero-react/src/use-query.js.map +1 -1
  569. package/out/zero-react/src/zero.js +1 -0
  570. package/out/zero-server/src/adapters/drizzle.d.ts +2 -1
  571. package/out/zero-server/src/adapters/drizzle.d.ts.map +1 -1
  572. package/out/zero-server/src/adapters/drizzle.js +12 -7
  573. package/out/zero-server/src/adapters/drizzle.js.map +1 -1
  574. package/out/zero-server/src/adapters/kysely.d.ts +2 -1
  575. package/out/zero-server/src/adapters/kysely.d.ts.map +1 -1
  576. package/out/zero-server/src/adapters/kysely.js +8 -2
  577. package/out/zero-server/src/adapters/kysely.js.map +1 -1
  578. package/out/zero-server/src/adapters/pg.d.ts +1 -0
  579. package/out/zero-server/src/adapters/pg.d.ts.map +1 -1
  580. package/out/zero-server/src/adapters/pg.js +8 -2
  581. package/out/zero-server/src/adapters/pg.js.map +1 -1
  582. package/out/zero-server/src/adapters/postgresjs.d.ts +1 -0
  583. package/out/zero-server/src/adapters/postgresjs.d.ts.map +1 -1
  584. package/out/zero-server/src/adapters/postgresjs.js +7 -1
  585. package/out/zero-server/src/adapters/postgresjs.js.map +1 -1
  586. package/out/zero-server/src/adapters/prisma.d.ts +3 -2
  587. package/out/zero-server/src/adapters/prisma.d.ts.map +1 -1
  588. package/out/zero-server/src/adapters/prisma.js +8 -2
  589. package/out/zero-server/src/adapters/prisma.js.map +1 -1
  590. package/out/zero-server/src/custom.d.ts +5 -1
  591. package/out/zero-server/src/custom.d.ts.map +1 -1
  592. package/out/zero-server/src/custom.js +6 -3
  593. package/out/zero-server/src/custom.js.map +1 -1
  594. package/out/zero-server/src/logging.d.ts +2 -2
  595. package/out/zero-server/src/logging.d.ts.map +1 -1
  596. package/out/zero-server/src/logging.js +2 -2
  597. package/out/zero-server/src/logging.js.map +1 -1
  598. package/out/zero-server/src/mod.d.ts +1 -1
  599. package/out/zero-server/src/mod.d.ts.map +1 -1
  600. package/out/zero-server/src/pg-query-executor.d.ts +2 -2
  601. package/out/zero-server/src/pg-query-executor.d.ts.map +1 -1
  602. package/out/zero-server/src/pg-query-executor.js +2 -2
  603. package/out/zero-server/src/pg-query-executor.js.map +1 -1
  604. package/out/zero-server/src/process-mutations.d.ts +12 -3
  605. package/out/zero-server/src/process-mutations.d.ts.map +1 -1
  606. package/out/zero-server/src/process-mutations.js +13 -8
  607. package/out/zero-server/src/process-mutations.js.map +1 -1
  608. package/out/zero-server/src/push-processor.d.ts +8 -2
  609. package/out/zero-server/src/push-processor.d.ts.map +1 -1
  610. package/out/zero-server/src/push-processor.js +12 -4
  611. package/out/zero-server/src/push-processor.js.map +1 -1
  612. package/out/zero-server/src/schema.d.ts +2 -2
  613. package/out/zero-server/src/schema.d.ts.map +1 -1
  614. package/out/zero-server/src/schema.js +2 -2
  615. package/out/zero-server/src/schema.js.map +1 -1
  616. package/out/zero-server/src/zql-database.d.ts +21 -1
  617. package/out/zero-server/src/zql-database.d.ts.map +1 -1
  618. package/out/zero-server/src/zql-database.js +33 -2
  619. package/out/zero-server/src/zql-database.js.map +1 -1
  620. package/out/zero-solid/src/solid-view.d.ts +17 -0
  621. package/out/zero-solid/src/solid-view.d.ts.map +1 -1
  622. package/out/zero-solid/src/solid-view.js +39 -1
  623. package/out/zero-solid/src/solid-view.js.map +1 -1
  624. package/out/zero-solid/src/use-query.js +1 -2
  625. package/out/zero-solid/src/use-query.js.map +1 -1
  626. package/out/zero-solid/src/zero.js +1 -0
  627. package/out/zql/src/builder/builder.d.ts +25 -0
  628. package/out/zql/src/builder/builder.d.ts.map +1 -1
  629. package/out/zql/src/builder/builder.js +69 -19
  630. package/out/zql/src/builder/builder.js.map +1 -1
  631. package/out/zql/src/builder/correlated-predicate-pushdown.d.ts +43 -0
  632. package/out/zql/src/builder/correlated-predicate-pushdown.d.ts.map +1 -0
  633. package/out/zql/src/builder/correlated-predicate-pushdown.js +161 -0
  634. package/out/zql/src/builder/correlated-predicate-pushdown.js.map +1 -0
  635. package/out/zql/src/builder/debug-delegate.d.ts +6 -1
  636. package/out/zql/src/builder/debug-delegate.d.ts.map +1 -1
  637. package/out/zql/src/builder/debug-delegate.js +14 -2
  638. package/out/zql/src/builder/debug-delegate.js.map +1 -1
  639. package/out/zql/src/ivm/array-view.d.ts +29 -0
  640. package/out/zql/src/ivm/array-view.d.ts.map +1 -1
  641. package/out/zql/src/ivm/array-view.js +58 -9
  642. package/out/zql/src/ivm/array-view.js.map +1 -1
  643. package/out/zql/src/ivm/cap.d.ts +2 -1
  644. package/out/zql/src/ivm/cap.d.ts.map +1 -1
  645. package/out/zql/src/ivm/cap.js +14 -4
  646. package/out/zql/src/ivm/cap.js.map +1 -1
  647. package/out/zql/src/ivm/connection-index.d.ts +68 -0
  648. package/out/zql/src/ivm/connection-index.d.ts.map +1 -0
  649. package/out/zql/src/ivm/connection-index.js +149 -0
  650. package/out/zql/src/ivm/connection-index.js.map +1 -0
  651. package/out/zql/src/ivm/data.d.ts.map +1 -1
  652. package/out/zql/src/ivm/data.js +8 -3
  653. package/out/zql/src/ivm/data.js.map +1 -1
  654. package/out/zql/src/ivm/deferred-input.d.ts.map +1 -1
  655. package/out/zql/src/ivm/deferred-input.js +3 -2
  656. package/out/zql/src/ivm/deferred-input.js.map +1 -1
  657. package/out/zql/src/ivm/exists.d.ts +3 -1
  658. package/out/zql/src/ivm/exists.d.ts.map +1 -1
  659. package/out/zql/src/ivm/exists.js +4 -1
  660. package/out/zql/src/ivm/exists.js.map +1 -1
  661. package/out/zql/src/ivm/fan-in.d.ts +6 -2
  662. package/out/zql/src/ivm/fan-in.d.ts.map +1 -1
  663. package/out/zql/src/ivm/fan-in.js +13 -5
  664. package/out/zql/src/ivm/fan-in.js.map +1 -1
  665. package/out/zql/src/ivm/fan-out.d.ts +5 -2
  666. package/out/zql/src/ivm/fan-out.d.ts.map +1 -1
  667. package/out/zql/src/ivm/fan-out.js +4 -0
  668. package/out/zql/src/ivm/fan-out.js.map +1 -1
  669. package/out/zql/src/ivm/filter-operators.d.ts +8 -6
  670. package/out/zql/src/ivm/filter-operators.d.ts.map +1 -1
  671. package/out/zql/src/ivm/filter-operators.js +19 -8
  672. package/out/zql/src/ivm/filter-operators.js.map +1 -1
  673. package/out/zql/src/ivm/filter.d.ts +5 -2
  674. package/out/zql/src/ivm/filter.d.ts.map +1 -1
  675. package/out/zql/src/ivm/filter.js +10 -4
  676. package/out/zql/src/ivm/filter.js.map +1 -1
  677. package/out/zql/src/ivm/flipped-join.d.ts +9 -4
  678. package/out/zql/src/ivm/flipped-join.d.ts.map +1 -1
  679. package/out/zql/src/ivm/flipped-join.js +97 -46
  680. package/out/zql/src/ivm/flipped-join.js.map +1 -1
  681. package/out/zql/src/ivm/join-index-tap.d.ts +33 -0
  682. package/out/zql/src/ivm/join-index-tap.d.ts.map +1 -0
  683. package/out/zql/src/ivm/join-index-tap.js +70 -0
  684. package/out/zql/src/ivm/join-index-tap.js.map +1 -0
  685. package/out/zql/src/ivm/join-index.d.ts +35 -0
  686. package/out/zql/src/ivm/join-index.d.ts.map +1 -0
  687. package/out/zql/src/ivm/join-index.js +141 -0
  688. package/out/zql/src/ivm/join-index.js.map +1 -0
  689. package/out/zql/src/ivm/join-utils.d.ts +6 -0
  690. package/out/zql/src/ivm/join-utils.d.ts.map +1 -1
  691. package/out/zql/src/ivm/join-utils.js +22 -1
  692. package/out/zql/src/ivm/join-utils.js.map +1 -1
  693. package/out/zql/src/ivm/join.d.ts +19 -1
  694. package/out/zql/src/ivm/join.d.ts.map +1 -1
  695. package/out/zql/src/ivm/join.js +107 -15
  696. package/out/zql/src/ivm/join.js.map +1 -1
  697. package/out/zql/src/ivm/maybe-split-and-push-edit-change.d.ts +1 -1
  698. package/out/zql/src/ivm/maybe-split-and-push-edit-change.d.ts.map +1 -1
  699. package/out/zql/src/ivm/maybe-split-and-push-edit-change.js +6 -4
  700. package/out/zql/src/ivm/maybe-split-and-push-edit-change.js.map +1 -1
  701. package/out/zql/src/ivm/memory-source.d.ts +28 -3
  702. package/out/zql/src/ivm/memory-source.d.ts.map +1 -1
  703. package/out/zql/src/ivm/memory-source.js +69 -33
  704. package/out/zql/src/ivm/memory-source.js.map +1 -1
  705. package/out/zql/src/ivm/memory-storage.d.ts +1 -0
  706. package/out/zql/src/ivm/memory-storage.d.ts.map +1 -1
  707. package/out/zql/src/ivm/memory-storage.js +1 -0
  708. package/out/zql/src/ivm/memory-storage.js.map +1 -1
  709. package/out/zql/src/ivm/operator.d.ts +45 -10
  710. package/out/zql/src/ivm/operator.d.ts.map +1 -1
  711. package/out/zql/src/ivm/operator.js +9 -4
  712. package/out/zql/src/ivm/operator.js.map +1 -1
  713. package/out/zql/src/ivm/push-accumulated.d.ts +6 -1
  714. package/out/zql/src/ivm/push-accumulated.d.ts.map +1 -1
  715. package/out/zql/src/ivm/push-accumulated.js +47 -2
  716. package/out/zql/src/ivm/push-accumulated.js.map +1 -1
  717. package/out/zql/src/ivm/skip.d.ts +2 -1
  718. package/out/zql/src/ivm/skip.d.ts.map +1 -1
  719. package/out/zql/src/ivm/skip.js +3 -0
  720. package/out/zql/src/ivm/skip.js.map +1 -1
  721. package/out/zql/src/ivm/take-gate.d.ts +57 -0
  722. package/out/zql/src/ivm/take-gate.d.ts.map +1 -0
  723. package/out/zql/src/ivm/take-gate.js +106 -0
  724. package/out/zql/src/ivm/take-gate.js.map +1 -0
  725. package/out/zql/src/ivm/take.d.ts +8 -2
  726. package/out/zql/src/ivm/take.d.ts.map +1 -1
  727. package/out/zql/src/ivm/take.js +139 -103
  728. package/out/zql/src/ivm/take.js.map +1 -1
  729. package/out/zql/src/ivm/union-fan-in.d.ts +3 -0
  730. package/out/zql/src/ivm/union-fan-in.d.ts.map +1 -1
  731. package/out/zql/src/ivm/union-fan-in.js +63 -10
  732. package/out/zql/src/ivm/union-fan-in.js.map +1 -1
  733. package/out/zql/src/ivm/union-fan-out.d.ts +2 -1
  734. package/out/zql/src/ivm/union-fan-out.d.ts.map +1 -1
  735. package/out/zql/src/ivm/union-fan-out.js +5 -0
  736. package/out/zql/src/ivm/union-fan-out.js.map +1 -1
  737. package/out/zql/src/ivm/view-apply-change.d.ts.map +1 -1
  738. package/out/zql/src/ivm/view-apply-change.js +9 -4
  739. package/out/zql/src/ivm/view-apply-change.js.map +1 -1
  740. package/out/zql/src/ivm/view.d.ts +15 -0
  741. package/out/zql/src/ivm/view.d.ts.map +1 -1
  742. package/out/zql/src/mutate/custom.d.ts +24 -1
  743. package/out/zql/src/mutate/custom.d.ts.map +1 -1
  744. package/out/zql/src/mutate/custom.js.map +1 -1
  745. package/out/zql/src/mutate/mutator-registry.d.ts.map +1 -1
  746. package/out/zql/src/mutate/mutator-registry.js +2 -2
  747. package/out/zql/src/mutate/mutator-registry.js.map +1 -1
  748. package/out/zql/src/planner/planner-builder.d.ts +23 -3
  749. package/out/zql/src/planner/planner-builder.d.ts.map +1 -1
  750. package/out/zql/src/planner/planner-builder.js +34 -17
  751. package/out/zql/src/planner/planner-builder.js.map +1 -1
  752. package/out/zql/src/planner/planner-connection.d.ts +58 -2
  753. package/out/zql/src/planner/planner-connection.d.ts.map +1 -1
  754. package/out/zql/src/planner/planner-connection.js +103 -11
  755. package/out/zql/src/planner/planner-connection.js.map +1 -1
  756. package/out/zql/src/planner/planner-debug.d.ts.map +1 -1
  757. package/out/zql/src/planner/planner-debug.js +3 -8
  758. package/out/zql/src/planner/planner-debug.js.map +1 -1
  759. package/out/zql/src/planner/planner-graph.d.ts +10 -0
  760. package/out/zql/src/planner/planner-graph.d.ts.map +1 -1
  761. package/out/zql/src/planner/planner-graph.js +14 -0
  762. package/out/zql/src/planner/planner-graph.js.map +1 -1
  763. package/out/zql/src/planner/planner-source.d.ts +2 -2
  764. package/out/zql/src/planner/planner-source.d.ts.map +1 -1
  765. package/out/zql/src/planner/planner-source.js +2 -2
  766. package/out/zql/src/planner/planner-source.js.map +1 -1
  767. package/out/zql/src/planner/planner-warnings.d.ts +83 -0
  768. package/out/zql/src/planner/planner-warnings.d.ts.map +1 -0
  769. package/out/zql/src/planner/planner-warnings.js +78 -0
  770. package/out/zql/src/planner/planner-warnings.js.map +1 -0
  771. package/out/zql/src/query/measure-push-operator.d.ts +2 -1
  772. package/out/zql/src/query/measure-push-operator.d.ts.map +1 -1
  773. package/out/zql/src/query/measure-push-operator.js +33 -4
  774. package/out/zql/src/query/measure-push-operator.js.map +1 -1
  775. package/out/zql/src/query/query-delegate-base.d.ts +4 -2
  776. package/out/zql/src/query/query-delegate-base.d.ts.map +1 -1
  777. package/out/zql/src/query/query-delegate-base.js +66 -33
  778. package/out/zql/src/query/query-delegate-base.js.map +1 -1
  779. package/out/zql/src/query/query-delegate.d.ts +33 -6
  780. package/out/zql/src/query/query-delegate.d.ts.map +1 -1
  781. package/out/zql/src/query/query-impl.d.ts +1 -0
  782. package/out/zql/src/query/query-impl.d.ts.map +1 -1
  783. package/out/zql/src/query/query-impl.js +6 -23
  784. package/out/zql/src/query/query-impl.js.map +1 -1
  785. package/out/zql/src/query/query-transitions.d.ts.map +1 -1
  786. package/out/zql/src/query/query-transitions.js +2 -5
  787. package/out/zql/src/query/query-transitions.js.map +1 -1
  788. package/out/zql/src/query/query.d.ts +11 -2
  789. package/out/zql/src/query/query.d.ts.map +1 -1
  790. package/out/zql/src/query/runnable-query-impl.d.ts +1 -0
  791. package/out/zql/src/query/runnable-query-impl.d.ts.map +1 -1
  792. package/out/zql/src/query/runnable-query-impl.js +2 -10
  793. package/out/zql/src/query/runnable-query-impl.js.map +1 -1
  794. package/out/zql/src/query/typed-view.d.ts +1 -1
  795. package/out/zql/src/query/typed-view.d.ts.map +1 -1
  796. package/out/zqlite/src/database-storage.d.ts.map +1 -1
  797. package/out/zqlite/src/database-storage.js +9 -1
  798. package/out/zqlite/src/database-storage.js.map +1 -1
  799. package/out/zqlite/src/db.d.ts +9 -1
  800. package/out/zqlite/src/db.d.ts.map +1 -1
  801. package/out/zqlite/src/db.js +31 -27
  802. package/out/zqlite/src/db.js.map +1 -1
  803. package/out/zqlite/src/pending-delta.d.ts +110 -0
  804. package/out/zqlite/src/pending-delta.d.ts.map +1 -0
  805. package/out/zqlite/src/pending-delta.js +278 -0
  806. package/out/zqlite/src/pending-delta.js.map +1 -0
  807. package/out/zqlite/src/query-builder.d.ts +17 -1
  808. package/out/zqlite/src/query-builder.d.ts.map +1 -1
  809. package/out/zqlite/src/query-builder.js +111 -20
  810. package/out/zqlite/src/query-builder.js.map +1 -1
  811. package/out/zqlite/src/query-delegate.d.ts.map +1 -1
  812. package/out/zqlite/src/query-delegate.js +10 -7
  813. package/out/zqlite/src/query-delegate.js.map +1 -1
  814. package/out/zqlite/src/sqlite-cost-model.d.ts.map +1 -1
  815. package/out/zqlite/src/sqlite-cost-model.js +52 -1
  816. package/out/zqlite/src/sqlite-cost-model.js.map +1 -1
  817. package/out/zqlite/src/sqlite-stat-fanout.d.ts.map +1 -1
  818. package/out/zqlite/src/sqlite-stat-fanout.js +5 -31
  819. package/out/zqlite/src/sqlite-stat-fanout.js.map +1 -1
  820. package/out/zqlite/src/sqlite-stat4-sample.d.ts +37 -0
  821. package/out/zqlite/src/sqlite-stat4-sample.d.ts.map +1 -0
  822. package/out/zqlite/src/sqlite-stat4-sample.js +61 -0
  823. package/out/zqlite/src/sqlite-stat4-sample.js.map +1 -0
  824. package/out/zqlite/src/table-source.d.ts +82 -2
  825. package/out/zqlite/src/table-source.d.ts.map +1 -1
  826. package/out/zqlite/src/table-source.js +261 -38
  827. package/out/zqlite/src/table-source.js.map +1 -1
  828. package/package.json +3 -4
  829. package/out/replicache/src/kv/idb-store-with-mem-fallback.d.ts +0 -25
  830. package/out/replicache/src/kv/idb-store-with-mem-fallback.d.ts.map +0 -1
  831. package/out/replicache/src/kv/idb-store-with-mem-fallback.js +0 -83
  832. package/out/replicache/src/kv/idb-store-with-mem-fallback.js.map +0 -1
@@ -1,4 +1,6 @@
1
1
  import { assert, unreachable } from "../../../../shared/src/asserts.js";
2
+ import { getOrInsertComputed } from "../../../../shared/src/map.js";
3
+ import { newArray } from "../../../../shared/src/arrays.js";
2
4
  import { must } from "../../../../shared/src/must.js";
3
5
  import { h64 } from "../../../../shared/src/hash.js";
4
6
  import { Internal, InvalidConnectionRequest, InvalidConnectionRequestBaseCookie, Rehome } from "../../../../zero-protocol/src/error-kind-enum.js";
@@ -10,12 +12,14 @@ import { manualSpan, startAsyncSpan, startSpan } from "../../../../otel/src/span
10
12
  import { ZERO_VERSION_COLUMN_NAME } from "../replicator/schema/constants.js";
11
13
  import { transformAndHashQuery } from "../../auth/read-authorizer.js";
12
14
  import { randInt } from "../../../../shared/src/rand.js";
13
- import { getOrCreateCounter, getOrCreateLatencyHistogram, getOrCreateNativeHistogram, getOrCreateUpDownCounter } from "../../observability/metrics.js";
15
+ import { LogThrottle } from "../../observability/log-throttle.js";
16
+ import { getOrCreateCounter, getOrCreateLatencyHistogram, getOrCreateNativeHistogram, getOrCreateUpDownCounter, getOrCreateValueHistogram } from "../../observability/metrics.js";
14
17
  import { rowIDString } from "../../types/row-key.js";
15
18
  import "../replicator/schema/replication-state.js";
19
+ import { planWarningMessage } from "./plan-warnings.js";
20
+ import { queryShape } from "./query-shape.js";
16
21
  import { parseSignature } from "./row-set-signature.js";
17
22
  import { ResetPipelinesSignal } from "./snapshotter.js";
18
- import "./pipeline-driver.js";
19
23
  import { Subscription } from "../../types/subscription.js";
20
24
  import { CustomKeyMap } from "../../../../shared/src/custom-key-map.js";
21
25
  import { ttlClockAsNumber, ttlClockFromNumber } from "./ttl-clock.js";
@@ -25,8 +29,10 @@ import { isAuthErrorBody } from "../../auth/auth.js";
25
29
  import { ClientHandler, startPoke } from "./client-handler.js";
26
30
  import { tracer } from "./tracer.js";
27
31
  import { CVRStore, ClientNotFoundError } from "./cvr-store.js";
28
- import { CVRConfigDrivenUpdater, CVRQueryDrivenUpdater, nextEvictionTime } from "./cvr.js";
32
+ import { CVRConfigDrivenUpdater, CVRQueryDrivenUpdater, classifyQueriesForHydration, nextEvictionTime } from "./cvr.js";
29
33
  import { E2EServingLagTracker } from "./e2e-serving-lag.js";
34
+ import { HydrationBudget } from "./hydration-budget.js";
35
+ import { HydrationCircuitBreaker } from "./hydration-circuit-breaker.js";
30
36
  import { handleInspect } from "./inspect-handler.js";
31
37
  import { QueryCoveringIndex } from "./query-covering.js";
32
38
  import { resolver } from "@rocicorp/resolver";
@@ -50,6 +56,7 @@ function shutdownBeforeInitializationError() {
50
56
  * use a timer to update the ttlClock every minute.
51
57
  */
52
58
  var TTL_CLOCK_INTERVAL = 6e4;
59
+ var slowHydrationLogThrottle = new LogThrottle({ windowMs: 5 * 6e4 });
53
60
  var ViewSyncerService = class {
54
61
  id;
55
62
  createdAtMs = Date.now();
@@ -61,6 +68,7 @@ var ViewSyncerService = class {
61
68
  #drainCoordinator;
62
69
  #keepaliveMs;
63
70
  #slowHydrateThreshold;
71
+ #hydrationCircuitBreaker;
64
72
  #lastConnectTime = Date.now();
65
73
  /**
66
74
  * The TTL clock is used to determine the time at which queries are considered
@@ -88,14 +96,37 @@ var ViewSyncerService = class {
88
96
  #lock = new Lock();
89
97
  #cvrStore;
90
98
  #stopped = resolver();
99
+ /**
100
+ * Set when {@link #cleanup} begins. Lock tasks that were in flight when the
101
+ * view-syncer was stopped may still complete after the timers have been
102
+ * cleared; this flag prevents them from scheduling new timers, which would
103
+ * otherwise outlive the service (and retain everything it references).
104
+ */
105
+ #shuttingDown = false;
91
106
  #initialized = resolver();
92
107
  #cvr;
93
- #pipelinesSynced = false;
108
+ /**
109
+ * Indicates whether the query pipelines have completed initial catch-up and
110
+ * hydration with the CVR snapshot, and are ready for steady-state operation.
111
+ *
112
+ * - When `false`: The syncer is in its initial catch-up phase. The replica
113
+ * advances without diffs until it reaches `cvr.version.stateVersion`,
114
+ * after which `#maybeHydratePipelines` hydrates queries.
115
+ * - When `true`: Pipelines are fully populated and in steady-state; replica
116
+ * changes advance incrementally via `#advancePipelines`, and client query
117
+ * updates are processed via `#syncQueryPipelineSet`.
118
+ *
119
+ * Resets to `false` if `#advancePipelines` returns a `ResetPipelinesSignal`
120
+ * and pipelines must be reset and rehydrated, or if a reloaded CVR is ahead
121
+ * of the pipelines (see `#resetPipelinesIfBehindCVR`).
122
+ */
123
+ #pipelinesHydrated = false;
94
124
  #servedVersion = null;
95
125
  #e2eServingLagTracker = new E2EServingLagTracker();
96
126
  #expiredQueriesTimer = 0;
97
127
  #authMaintenanceTimer = 0;
98
128
  #setTimeout;
129
+ #now;
99
130
  #customQueryTransformer;
100
131
  #queryReplacements = /* @__PURE__ */ new Map();
101
132
  #activeClients = getOrCreateUpDownCounter("sync", "active-clients", "Number of active sync clients");
@@ -122,10 +153,64 @@ var ViewSyncerService = class {
122
153
  #pipelineResets = getOrCreateCounter("sync", "pipeline-resets", "Number of pipeline resets");
123
154
  #rowSetSignatureDrifts = getOrCreateCounter("sync", "query.row-set-signature-drifts", "Number of times re-hydration of an unchanged query produced a different row-set signature than what is stored in the CVR (forcing a configVersion bump and full re-execution). Expected to be near-zero in steady state; persistent non-zero values indicate non-deterministic query execution (e.g. Cap operator picking different N-row subsets).");
124
155
  #sameHashRehydrationVersionBumps = getOrCreateCounter("sync", "query.same-hash-rehydrations-forced-bump", "Number of times query-set reconciliation forced a configVersion bump for already-gotten same-transformation-hash query rehydration because trackQueries would not otherwise bump. Expected to be near-zero; non-zero values indicate pipeline/CVR row-set drift reached query-set reconciliation.");
156
+ #hydrationBudgetExhaustions = getOrCreateCounter("sync", "hydration_budget_exhaustions", {
157
+ description: "Number of hydration passes that exhaust their budget.",
158
+ unit: "{pass}"
159
+ });
160
+ #hydrationBudgetEvictions = getOrCreateCounter("sync", "hydration_budget_evictions", {
161
+ description: "Number of inactive queries removed after hydration budget exhaustion.",
162
+ unit: "{query}"
163
+ });
164
+ #hydrationBudgetElapsed = getOrCreateValueHistogram("sync", "hydration_budget_elapsed", {
165
+ description: "Elapsed milliseconds when optional query hydration stopped.",
166
+ unit: "ms",
167
+ bucketBoundaries: [
168
+ 1,
169
+ 2,
170
+ 5,
171
+ 10,
172
+ 20,
173
+ 50,
174
+ 100,
175
+ 200,
176
+ 500,
177
+ 1e3,
178
+ 5e3
179
+ ]
180
+ });
181
+ #hydrationBudgetOvershoot = getOrCreateValueHistogram("sync", "hydration_budget_overshoot", {
182
+ description: "Milliseconds elapsed beyond the configured hydration budget.",
183
+ unit: "ms",
184
+ bucketBoundaries: [
185
+ 0,
186
+ 1,
187
+ 2,
188
+ 5,
189
+ 10,
190
+ 20,
191
+ 50,
192
+ 100,
193
+ 200,
194
+ 500,
195
+ 1e3
196
+ ]
197
+ });
198
+ #queryEvictions = getOrCreateCounter("sync", "query_evictions", {
199
+ description: "Number of queries evicted from the CVR ahead of their removal by the client, grouped by reason. Inactive queries are evicted by ttl and hydration-budget; hydration-timeout and hydration-circuit-breaker evict active queries as well.",
200
+ unit: "{query}"
201
+ });
202
+ #hydrationTimeouts = getOrCreateCounter("sync", "hydration_timeouts", {
203
+ description: "Number of query hydrations aborted for exceeding the query hydration timeout.",
204
+ unit: "{query}"
205
+ });
206
+ #hydrationCircuitBreakerRejections = getOrCreateCounter("sync", "hydration_circuit_breaker_rejections", {
207
+ description: "Number of queries rejected without hydration because their hydration circuit breaker was open.",
208
+ unit: "{query}"
209
+ });
125
210
  #inspectorDelegate;
126
211
  #config;
127
212
  #runPriorityOp;
128
- constructor(config, lc, shard, taskID, clientGroupID, cvrDb, pipelineDriver, versionChanges, drainCoordinator, slowHydrateThreshold, inspectorDelegate, connContextManager, customQueryTransformer, runPriorityOp, keepaliveMs = DEFAULT_KEEPALIVE_MS, setTimeoutFn = setTimeout.bind(globalThis)) {
213
+ constructor(config, lc, shard, taskID, clientGroupID, cvrDb, pipelineDriver, versionChanges, drainCoordinator, slowHydrateThreshold, inspectorDelegate, connContextManager, customQueryTransformer, runPriorityOp, keepaliveMs = DEFAULT_KEEPALIVE_MS, setTimeoutFn = setTimeout.bind(globalThis), now = performance.now.bind(performance)) {
129
214
  this.#config = config;
130
215
  this.id = clientGroupID;
131
216
  this.connContextManager = connContextManager;
@@ -140,6 +225,8 @@ var ViewSyncerService = class {
140
225
  this.#customQueryTransformer = customQueryTransformer;
141
226
  this.#cvrStore = new CVRStore(lc, cvrDb, shard, taskID, clientGroupID, () => this.#stateChanges.cancel());
142
227
  this.#setTimeout = setTimeoutFn;
228
+ this.#now = now;
229
+ this.#hydrationCircuitBreaker = new HydrationCircuitBreaker(config.viewSyncerQueryHydrationTimeoutMs ?? 0, void 0, now);
143
230
  this.#runPriorityOp = runPriorityOp;
144
231
  this.keepalive();
145
232
  }
@@ -166,11 +253,13 @@ var ViewSyncerService = class {
166
253
  this.#stateChanges.cancel();
167
254
  return;
168
255
  }
256
+ let reloaded = false;
169
257
  if (!this.#cvr) {
170
258
  this.#lc.debug?.("loading cvr");
171
259
  this.#cvr = await this.#runPriorityOp(lc, "loading cvr", () => this.#cvrStore.load(lc, this.#lastConnectTime));
172
260
  this.#ttlClock = this.#cvr.ttlClock;
173
261
  this.#ttlClockBase = Date.now();
262
+ reloaded = true;
174
263
  } else {
175
264
  const now = Date.now();
176
265
  this.#cvr = {
@@ -179,6 +268,10 @@ var ViewSyncerService = class {
179
268
  };
180
269
  }
181
270
  try {
271
+ if (reloaded && this.#resetPipelinesIfBehindCVR(lc, this.#cvr)) {
272
+ const connCtx = this.connContextManager.getBackgroundConnectionContext();
273
+ if (connCtx) await this.#maybeHydratePipelines(lc, this.#cvr, connCtx);
274
+ }
182
275
  await fn(lc, this.#cvr);
183
276
  } catch (e) {
184
277
  this.#cvr = void 0;
@@ -188,11 +281,47 @@ var ViewSyncerService = class {
188
281
  }
189
282
  });
190
283
  }
284
+ /**
285
+ * The CVR is reloaded after an error clears the cached copy. By then another
286
+ * view-syncer may have taken over the client group and flushed the CVR at a
287
+ * version ahead of this instance's hydrated pipelines (e.g. its replica was
288
+ * further ahead). The pipelines can no longer be diffed against the CVR, so
289
+ * reset them and let `#maybeHydratePipelines` rehydrate once the replica has
290
+ * caught up to the CVR.
291
+ *
292
+ * A CVR behind the pipelines is expected (advancements that do not change
293
+ * the CVR are not flushed) and is handled by the normal update path.
294
+ *
295
+ * Returns whether the pipelines were reset.
296
+ *
297
+ * Must be called from within the #lock.
298
+ */
299
+ #resetPipelinesIfBehindCVR(lc, cvr) {
300
+ if (!this.#pipelinesHydrated) return false;
301
+ const pipelineVersion = this.#pipelines.currentVersion();
302
+ if (pipelineVersion >= cvr.version.stateVersion) return false;
303
+ lc.info?.(`resetting pipelines: pipelines@${pipelineVersion} are behind reloaded cvr@${versionString(cvr.version)}`);
304
+ this.#pipelineResets.add(1, { reason: "behind-cvr" });
305
+ this.#pipelinesHydrated = false;
306
+ this.connContextManager.setSharedRetransformReady(false);
307
+ this.#pipelines.reset(must(cvr.clientSchema, "cvr.clientSchema missing after initialization"));
308
+ return true;
309
+ }
191
310
  readyState() {
192
- return Promise.race([this.#initialized.promise, this.#drainCoordinator.draining]);
311
+ return new Promise((resolve, reject) => {
312
+ const unsubscribe = this.#drainCoordinator.onDraining(() => resolve("draining"));
313
+ this.#initialized.promise.then((state) => {
314
+ unsubscribe();
315
+ resolve(state);
316
+ }, (err) => {
317
+ unsubscribe();
318
+ reject(err);
319
+ });
320
+ });
193
321
  }
194
322
  async run() {
195
323
  try {
324
+ this.#scheduleShutdown(this.#keepaliveMs);
196
325
  if (await this.readyState() === "draining") {
197
326
  this.#lc.debug?.(`draining view-syncer ${this.id} before running`);
198
327
  this.stop();
@@ -213,26 +342,29 @@ var ViewSyncerService = class {
213
342
  lc.info?.(`resetting CVR: ${message}`);
214
343
  throw new ClientNotFoundError(message);
215
344
  }
216
- if (this.#pipelinesSynced) {
345
+ let previousQueries;
346
+ if (this.#pipelinesHydrated) {
217
347
  const result = await this.#advancePipelines(lc, cvr);
218
348
  if (result === "success") return;
219
349
  lc.info?.(`resetting pipelines: ${result.message}`);
220
350
  this.#pipelineResets.add(1, { reason: result.reason });
351
+ switch (result.reason) {
352
+ case "advancement-timeout":
353
+ case "scalar-subquery":
354
+ case "truncation":
355
+ case "schema-change":
356
+ if (!Object.values(cvr.queries).some((q) => q.type === "client")) previousQueries = new Map(this.#pipelines.queries());
357
+ break;
358
+ case "permissions-change": break;
359
+ default: unreachable(result.reason);
360
+ }
221
361
  this.#pipelines.reset(clientSchema);
222
- this.#pipelinesSynced = false;
362
+ this.#pipelinesHydrated = false;
223
363
  this.connContextManager.setSharedRetransformReady(false);
224
364
  }
225
- const version = this.#pipelines.advanceWithoutDiff();
226
- const cvrVer = versionString(cvr.version);
227
- if (version < cvr.version.stateVersion) {
228
- lc.debug?.(`replica@${version} is behind cvr@${cvrVer}`);
229
- return;
230
- }
231
- lc.info?.(`init pipelines@${version} (cvr@${cvrVer})`);
232
- const driftedQueryIDs = await this.#hydrateUnchangedQueries(lc, cvr);
233
- await this.#syncQueryPipelineSet(lc, cvr, "missing", void 0, driftedQueryIDs);
234
- this.#pipelinesSynced = true;
235
- this.connContextManager.setSharedRetransformReady(true);
365
+ const backgroundConnCtx = this.connContextManager.getBackgroundConnectionContext();
366
+ if (backgroundConnCtx) await this.#maybeHydratePipelines(lc, cvr, backgroundConnCtx, previousQueries);
367
+ else lc.info?.("No validated background connection; deferring pipeline init");
236
368
  });
237
369
  }
238
370
  if (this.#drainCoordinator.shouldDrain()) this.#drainCoordinator.drainNextIn(this.#totalHydrationTimeMs());
@@ -246,11 +378,66 @@ var ViewSyncerService = class {
246
378
  this.#stopped.resolve();
247
379
  }
248
380
  }
381
+ /**
382
+ * Ensures that query pipelines are hydrated and ready for steady-state
383
+ * operation.
384
+ *
385
+ * Preconditions:
386
+ * 1. Must be called from within the `#lock`.
387
+ * 2. The caller must provide an active, validated `ConnectionContext` for
388
+ * evaluating custom query transforms and permissions.
389
+ *
390
+ * Readiness prerequisites:
391
+ * - The underlying `QueryPipelineDriver` must be initialized with the schema
392
+ * (i.e. `this.#pipelines.initialized()` is true).
393
+ * - The SQLite replica must have caught up to at least the CVR's
394
+ * `stateVersion` (`version >= cvr.version.stateVersion`).
395
+ *
396
+ * If either prerequisite is not met, this method returns early as a no-op,
397
+ * waiting for the replica to catch up or the driver to initialize.
398
+ *
399
+ * Once ready:
400
+ * - Hydrates unchanged queries from the CVR snapshot without full row diffing.
401
+ * - Syncs missing, errored, or drifted queries via `#syncQueryPipelineSet`.
402
+ * - Sets `#pipelinesHydrated = true` and enables shared retransformations.
403
+ */
404
+ async #maybeHydratePipelines(lc, cvr, connCtx, previousQueries) {
405
+ if (!this.#pipelines.initialized()) return;
406
+ let version;
407
+ try {
408
+ version = this.#pipelines.advanceWithoutDiff();
409
+ } catch (e) {
410
+ if (!(e instanceof ResetPipelinesSignal)) throw e;
411
+ lc.info?.(`resetting pipelines: ${e.message}`);
412
+ this.#pipelineResets.add(1, { reason: e.reason });
413
+ this.#pipelines.reset(must(cvr.clientSchema, "cvr.clientSchema missing after initialization"));
414
+ version = this.#pipelines.currentVersion();
415
+ }
416
+ const cvrVer = versionString(cvr.version);
417
+ if (version < cvr.version.stateVersion) {
418
+ lc.debug?.(`replica@${version} is behind cvr@${cvrVer}`);
419
+ return;
420
+ }
421
+ lc.info?.(`init pipelines@${version} (cvr@${cvrVer})`);
422
+ const hydrationBudget = new HydrationBudget(this.#config.viewSyncerHydrationBudgetMs ?? 0, this.#now);
423
+ const hydrationPassStats = {
424
+ activeHydratedQueries: 0,
425
+ inactiveHydratedQueries: 0
426
+ };
427
+ const driftedQueryIDs = await this.#hydrateUnchangedQueries(lc, cvr, connCtx, hydrationPassStats, hydrationBudget, previousQueries);
428
+ await this.#syncQueryPipelineSet(lc, cvr, "missing", connCtx, driftedQueryIDs, hydrationBudget, hydrationPassStats, previousQueries);
429
+ this.#pipelinesHydrated = true;
430
+ this.connContextManager.setSharedRetransformReady(true);
431
+ }
249
432
  #removeExpiredQueries = async (lc, cvr) => {
250
433
  if (hasExpiredQueries(cvr)) {
251
434
  lc = lc.withContext("method", "#removeExpiredQueries");
252
435
  lc.debug?.("Queries have expired");
253
- if (this.#pipelinesSynced) await this.#syncQueryPipelineSet(lc, cvr, "missing", void 0);
436
+ if (this.#pipelinesHydrated) {
437
+ const connCtx = this.connContextManager.getBackgroundConnectionContext();
438
+ if (connCtx) await this.#syncQueryPipelineSet(lc, cvr, "missing", connCtx);
439
+ else lc.info?.("No validated background connection to remove expired queries; deferring");
440
+ }
254
441
  }
255
442
  this.#scheduleExpireEviction(lc, cvr);
256
443
  };
@@ -332,7 +519,14 @@ var ViewSyncerService = class {
332
519
  return true;
333
520
  }
334
521
  #shutdownTimer = null;
522
+ #stopShutdownTimer() {
523
+ if (this.#shutdownTimer !== null) {
524
+ clearTimeout(this.#shutdownTimer);
525
+ this.#shutdownTimer = null;
526
+ }
527
+ }
335
528
  #scheduleShutdown(delayMs = 0) {
529
+ if (this.#shuttingDown) return;
336
530
  this.#shutdownTimer ??= this.#setTimeout(() => {
337
531
  this.#shutdownTimer = null;
338
532
  this.#runInLockWithCVR(() => {}).catch((e) => this.#stateChanges.fail(e));
@@ -379,6 +573,7 @@ var ViewSyncerService = class {
379
573
  */
380
574
  #scheduleAuthMaintenance(lc) {
381
575
  this.#stopAuthMaintenanceTimer();
576
+ if (this.#shuttingDown) return;
382
577
  const plan = this.connContextManager.planMaintenance();
383
578
  if (plan.earliestDeadlineAt === void 0) {
384
579
  lc.debug?.("No auth maintenance wakeup scheduled");
@@ -466,7 +661,7 @@ var ViewSyncerService = class {
466
661
  }
467
662
  lc.debug?.("Auth changed, re-validating and re-transforming queries");
468
663
  const connCtx = this.connContextManager.mustGetConnectionContext(selector);
469
- if (!this.#pipelinesSynced) {
664
+ if (!this.#pipelinesHydrated) {
470
665
  if (!await this.#validateConnection(connCtx)) return;
471
666
  }
472
667
  return await this.#handleConfigUpdate(lc, clientID, {}, cvr, "all", void 0, connCtx);
@@ -484,17 +679,41 @@ var ViewSyncerService = class {
484
679
  this.#ttlClockBase = now;
485
680
  return ttlClock;
486
681
  }
487
- #flushUpdater(lc, updater) {
682
+ /**
683
+ * @param patchesPoked Whether patches computed against the updater's CVR
684
+ * have already been poked to clients. If so, the CVR is checked to be
685
+ * current even when the flush has nothing to write: another
686
+ * view-syncer may have already committed identical rows at a newer
687
+ * version, which would otherwise leave this one poking from a stale
688
+ * CVR whose version it cannot advance.
689
+ */
690
+ #flushUpdater(lc, updater, patchesPoked = false) {
488
691
  return startAsyncSpan(tracer, "vs.#flushUpdater", () => this.#runPriorityOp(lc, "flushing cvr", async () => {
489
692
  const now = Date.now();
490
693
  const ttlClock = this.#getTTLClock(now);
491
- const { cvr, flushed } = await updater.flush(lc, this.#lastConnectTime, now, ttlClock);
694
+ const { cvr, flushed } = await updater.flush(lc, this.#lastConnectTime, now, ttlClock, patchesPoked);
492
695
  if (flushed) this.#startTTLClockInterval(lc);
493
696
  return cvr;
494
697
  }));
495
698
  }
699
+ /**
700
+ * Flushes an updater whose changes have already been poked. If the flush
701
+ * fails (e.g. the CVR was concurrently modified), the poke is cancelled
702
+ * before the error propagates. The error may only fail the client that
703
+ * initiated the operation, and any other client left mid-poke would fail
704
+ * its next pokeStart.
705
+ */
706
+ async #flushPoked(lc, updater, pokers) {
707
+ try {
708
+ return await this.#flushUpdater(lc, updater, pokers.patchesSent);
709
+ } catch (e) {
710
+ await pokers.cancel();
711
+ throw e;
712
+ }
713
+ }
496
714
  #startTTLClockInterval(lc) {
497
715
  this.#stopTTLClockInterval();
716
+ if (this.#shuttingDown) return;
498
717
  this.#ttlClockInterval = this.#setTimeout(() => {
499
718
  this.#updateTTLClockInCVRWithoutLock(lc);
500
719
  this.#startTTLClockInterval(lc);
@@ -523,12 +742,13 @@ var ViewSyncerService = class {
523
742
  if (cmpVersions(cvr.version, this.#cvr.version) < 0) {
524
743
  const newCVR = this.#cvr;
525
744
  await startAsyncSpan(tracer, "vs.#updateCVRConfig.pokeClients", async () => {
526
- const pokers = startPoke(this.#getClients(cvr.version), newCVR.version);
745
+ const pokers = startPoke(lc, this.#getClients(cvr.version), newCVR.version);
527
746
  for (const patch of patches) await pokers.addPatch(patch);
528
747
  await pokers.end(newCVR.version);
529
748
  });
530
749
  }
531
- if (this.#pipelinesSynced) await this.#syncQueryPipelineSet(lc, this.#cvr, customQueryTransformMode, connCtx);
750
+ if (!this.#pipelinesHydrated) await this.#maybeHydratePipelines(lc, this.#cvr, connCtx);
751
+ else await this.#syncQueryPipelineSet(lc, this.#cvr, customQueryTransformMode, connCtx);
532
752
  return this.#cvr;
533
753
  }
534
754
  /**
@@ -624,6 +844,7 @@ var ViewSyncerService = class {
624
844
  #scheduleExpireEviction(lc, cvr) {
625
845
  const { ttlClock } = cvr;
626
846
  this.#stopExpireTimer();
847
+ if (this.#shuttingDown) return;
627
848
  const next = nextEvictionTime(cvr);
628
849
  if (next === void 0) {
629
850
  lc.debug?.("no inactive queries with ttl");
@@ -651,7 +872,7 @@ var ViewSyncerService = class {
651
872
  *
652
873
  * This must be called from within the #lock.
653
874
  */
654
- async #hydrateUnchangedQueries(lc, cvr) {
875
+ async #hydrateUnchangedQueries(lc, cvr, connCtx, hydrationPassStats, hydrationBudget, previousQueries) {
655
876
  assert(this.#pipelines.initialized(), "pipelines must be initialized");
656
877
  const dbVersion = this.#pipelines.currentVersion();
657
878
  const cvrVersion = cvr.version;
@@ -660,33 +881,34 @@ var ViewSyncerService = class {
660
881
  return /* @__PURE__ */ new Set();
661
882
  }
662
883
  const gotQueries = Object.entries(cvr.queries).filter(([_, state]) => state.transformationHash !== void 0);
884
+ const { required: requiredGotQueries } = classifyQueriesForHydration(gotQueries.map(([, query]) => query));
663
885
  const customQueries = /* @__PURE__ */ new Map();
664
886
  const otherQueries = [];
665
- let inactivatedCount = 0;
666
- for (const [, query] of gotQueries) {
667
- if (query.type !== "internal" && Object.values(query.clientState).every(({ inactivatedAt }) => inactivatedAt !== void 0)) {
668
- inactivatedCount++;
669
- continue;
670
- }
671
- if (query.type === "custom") customQueries.set(query.id, query);
672
- else otherQueries.push(query);
673
- }
887
+ const inactivatedCount = gotQueries.length - requiredGotQueries.length;
674
888
  const transformedQueries = [];
889
+ for (const query of requiredGotQueries) if (query.type === "custom") {
890
+ const previous = previousQueries?.get(query.id);
891
+ if (previous && previous.transformationHash === query.transformationHash) transformedQueries.push({
892
+ id: query.id,
893
+ transformationHash: previous.transformationHash,
894
+ transformedAst: previous.originalAst ?? previous.transformedAst
895
+ });
896
+ else customQueries.set(query.id, query);
897
+ } else otherQueries.push(query);
675
898
  let customErrorCount = 0;
676
899
  let customHashMismatchCount = 0;
677
900
  let otherHashMismatchCount = 0;
678
901
  if (customQueries.size > 0 && !this.#customQueryTransformer) lc.warn?.("Custom/named queries were requested but no `ZERO_QUERY_URL` is configured for Zero Cache.");
679
- const backgroundContext = this.connContextManager.mustGetBackgroundConnectionContext();
680
902
  const customQueryTransformer = this.#customQueryTransformer;
681
903
  if (customQueryTransformer && customQueries.size > 0) {
682
- const transformedCustomQueries = await this.#runPriorityOp(lc, "#hydrateUnchangedQueries transforming custom queries", () => customQueryTransformer.transform(backgroundContext, customQueries.values()));
683
- if (transformedCustomQueries.kind === "success" && !transformedCustomQueries.cached) this.connContextManager.validateConnection(backgroundContext, backgroundContext.revision, transformedCustomQueries.validation);
904
+ const transformedCustomQueries = await hydrationBudget.excluding(() => this.#runPriorityOp(lc, "#hydrateUnchangedQueries transforming custom queries", () => customQueryTransformer.transform(connCtx, customQueries.values())));
905
+ if (transformedCustomQueries.kind === "success" && !transformedCustomQueries.cached) this.connContextManager.validateConnection(connCtx, connCtx.revision, transformedCustomQueries.validation);
684
906
  if (Array.isArray(transformedCustomQueries.result)) for (const q of transformedCustomQueries.result) if ("error" in q) customErrorCount++;
685
907
  else if (q.transformationHash !== customQueries.get(q.id)?.transformationHash) customHashMismatchCount++;
686
908
  else transformedQueries.push(q);
687
909
  }
688
910
  for (const q of otherQueries) {
689
- const transformed = transformAndHashQuery(lc, q.id, q.ast, must(this.#pipelines.currentPermissions()).permissions ?? { tables: {} }, backgroundContext.auth?.type === "jwt" ? backgroundContext.auth : void 0, q.type === "internal");
911
+ const transformed = transformAndHashQuery(lc, q.id, q.ast, must(this.#pipelines.currentPermissions()).permissions ?? { tables: {} }, connCtx.auth?.type === "jwt" ? connCtx.auth : void 0, q.type === "internal");
690
912
  if (transformed.transformationHash === q.transformationHash) transformedQueries.push(transformed);
691
913
  else otherHashMismatchCount++;
692
914
  }
@@ -699,6 +921,10 @@ var ViewSyncerService = class {
699
921
  for (const { id: queryID, transformationHash, transformedAst } of transformedQueries) {
700
922
  const query = cvr.queries[queryID];
701
923
  const queryName = query.type === "custom" ? query.name : void 0;
924
+ if (query.type !== "internal" && this.#hydrationCircuitBreaker.isOpen(transformationHash)) {
925
+ lc.info?.(`skipping hydration of ${queryID}: hydration circuit breaker open`);
926
+ continue;
927
+ }
702
928
  const covered = queryCoveringIndex ? this.#findQueryCoverageShadowHit(queryCoveringIndex, queryID, transformationHash, transformedAst, queryName) : void 0;
703
929
  totalHydratedQueries++;
704
930
  if (covered) {
@@ -707,20 +933,43 @@ var ViewSyncerService = class {
707
933
  }
708
934
  const timer = new TimeSliceTimer(lc);
709
935
  let count = 0;
936
+ let timedOut = false;
710
937
  await startAsyncSpan(tracer, "vs.#hydrateUnchangedQueries.addQuery", async (span) => {
711
938
  span.setAttribute("queryHash", queryID);
712
939
  span.setAttribute("transformationHash", transformationHash);
713
940
  span.setAttribute("table", transformedAst.table);
714
941
  if (queryName !== void 0) span.setAttribute("queryName", queryName);
715
- for (const change of this.#pipelines.addQuery(transformationHash, queryID, transformedAst, await timer.start(), queryName, "unchanged-query-rehydrate")) if (change === "yield") await timer.yieldProcess("yield in hydrateUnchangedQueries");
716
- else count++;
942
+ for (const change of this.#pipelines.addQuery(transformationHash, queryID, transformedAst, await timer.start(), queryName, "unchanged-query-rehydrate")) if (change === "yield") {
943
+ if (query.type !== "internal" && this.#hydrationCircuitBreaker.exceeded(timer.totalElapsed())) {
944
+ timedOut = true;
945
+ await timer.yieldProcess("yield in hydrateUnchangedQueries");
946
+ break;
947
+ }
948
+ await timer.yieldProcess("yield in hydrateUnchangedQueries");
949
+ } else count++;
717
950
  });
718
951
  const elapsed = timer.totalElapsed();
952
+ if (timedOut) {
953
+ this.#recordHydrationTimeout(lc, {
954
+ id: queryID,
955
+ ast: transformedAst,
956
+ transformationHash,
957
+ name: queryName
958
+ }, elapsed, count);
959
+ continue;
960
+ }
961
+ hydrationPassStats.activeHydratedQueries++;
719
962
  this.#hydrations.add(1);
720
963
  this.#hydrationTime.recordMs(elapsed);
721
- this.#addQueryMaterializationServerMetric(transformationHash, elapsed);
722
- this.#inspectorDelegate.addQuery(transformationHash, transformedAst);
964
+ this.#addQueryMaterializationServerMetric(queryID, elapsed);
965
+ this.#inspectorDelegate.addQuery(queryID, transformedAst);
723
966
  lc.debug?.(`hydrated ${count} rows for ${queryID} (${elapsed} ms)`);
967
+ if (elapsed > this.#slowHydrateThreshold) this.#logSlowHydration(lc, {
968
+ id: queryID,
969
+ ast: transformedAst,
970
+ transformationHash,
971
+ name: queryName
972
+ }, elapsed);
724
973
  let drifted = false;
725
974
  const storedSigHex = cvr.queries[queryID]?.rowSetSignature;
726
975
  if (storedSigHex !== void 0 && storedSigHex !== null) {
@@ -780,11 +1029,7 @@ var ViewSyncerService = class {
780
1029
  return;
781
1030
  }
782
1031
  const appErrorGroups = /* @__PURE__ */ new Map();
783
- for (const err of errorOrErrors) for (const clientId of getAffectedClientIDs([err.id])) {
784
- const group = appErrorGroups.get(clientId) ?? [];
785
- group.push(err);
786
- appErrorGroups.set(clientId, group);
787
- }
1032
+ for (const err of errorOrErrors) for (const clientId of getAffectedClientIDs([err.id])) getOrInsertComputed(appErrorGroups, clientId, newArray).push(err);
788
1033
  for (const [clientId, errors] of appErrorGroups) this.#clients.get(clientId)?.sendQueryTransformApplicationErrors(errors);
789
1034
  }
790
1035
  #addQueryMaterializationServerMetric(queryID, elapsed) {
@@ -820,7 +1065,10 @@ var ViewSyncerService = class {
820
1065
  *
821
1066
  * This must be called from within the #lock.
822
1067
  */
823
- #syncQueryPipelineSet(lc, cvr, customQueryTransformMode, connCtx, driftedQueryIDs = /* @__PURE__ */ new Set()) {
1068
+ #syncQueryPipelineSet(lc, cvr, customQueryTransformMode, connCtx, driftedQueryIDs = /* @__PURE__ */ new Set(), hydrationBudget = new HydrationBudget(this.#config.viewSyncerHydrationBudgetMs ?? 0, this.#now), hydrationPassStats = {
1069
+ activeHydratedQueries: 0,
1070
+ inactiveHydratedQueries: 0
1071
+ }, previousQueries) {
824
1072
  return startAsyncSpan(tracer, "vs.#syncQueryPipelineSet", async (span) => {
825
1073
  const start = performance.now();
826
1074
  span.setAttribute("clientGroupID", this.id);
@@ -829,38 +1077,45 @@ var ViewSyncerService = class {
829
1077
  const now = Date.now();
830
1078
  const ttlClock = this.#getTTLClock(now);
831
1079
  const cvrQueryEntires = Object.entries(cvr.queries);
832
- const customQueries = /* @__PURE__ */ new Map();
833
- const otherQueries = [];
834
1080
  const transformedQueries = [];
835
- const resolvedConnCtx = connCtx ?? this.connContextManager.mustGetBackgroundConnectionContext();
836
- for (const [id, query] of cvrQueryEntires) if (query.type === "custom") {
837
- assert(id === query.id, "custom query id mismatch");
838
- customQueries.set(id, query);
839
- } else otherQueries.push({
840
- id,
841
- query
842
- });
843
- for (const { id, query: origQuery } of otherQueries) {
844
- assert(id === origQuery.id, "query id mismatch");
845
- const transformed = transformAndHashQuery(lc, origQuery.id, origQuery.ast, must(this.#pipelines.currentPermissions()).permissions ?? { tables: {} }, resolvedConnCtx.auth?.type === "jwt" ? resolvedConnCtx.auth : void 0, origQuery.type === "internal");
846
- transformedQueries.push({
847
- id,
848
- origQuery,
849
- transformed
850
- });
851
- }
852
- if (customQueries.size > 0 && !this.#customQueryTransformer) lc.warn?.("Custom/named queries were requested but no `ZERO_QUERY_URL` is configured for Zero Cache.");
853
- let erroredQueryIDs;
854
- const customQueriesToTransform = customQueryTransformMode === "all" ? [...customQueries.values()] : customQueryTransformMode && [...customQueries.values()].filter((q) => !this.#pipelines.queries().has(q.id));
1081
+ const naturallyExpiredQueryIDs = new Set(cvrQueryEntires.map(([, query]) => query).filter((query) => expired(ttlClock, query)).map((query) => query.id));
1082
+ if (naturallyExpiredQueryIDs.size > 0) this.#queryEvictions.add(naturallyExpiredQueryIDs.size, { reason: "ttl" });
1083
+ const hydrationCandidates = cvrQueryEntires.map(([, query]) => query).filter((query) => !naturallyExpiredQueryIDs.has(query.id));
1084
+ const { required, optional } = classifyQueriesForHydration(hydrationCandidates);
1085
+ const requiredQueryIDs = new Set(required.map((query) => query.id));
1086
+ const optionalToHydrate = hydrationBudget.limitMs === 0 ? optional : optional.filter((query) => query.patchVersion !== void 0);
1087
+ if (!this.#customQueryTransformer && hydrationCandidates.some((query) => query.type === "custom")) lc.warn?.("Custom/named queries were requested but no `ZERO_QUERY_URL` is configured for Zero Cache.");
855
1088
  const customQueryTransformer = this.#customQueryTransformer;
856
- if (customQueryTransformer && customQueriesToTransform.length > 0) {
1089
+ const erroredQueryIDs = [];
1090
+ let transformedCustomQueryCount = 0;
1091
+ const transformOtherQueries = (queries) => {
1092
+ for (const origQuery of queries) {
1093
+ if (origQuery.type === "custom") continue;
1094
+ const transformed = transformAndHashQuery(lc, origQuery.id, origQuery.ast, must(this.#pipelines.currentPermissions()).permissions ?? { tables: {} }, connCtx.auth?.type === "jwt" ? connCtx.auth : void 0, origQuery.type === "internal");
1095
+ transformedQueries.push({
1096
+ id: origQuery.id,
1097
+ origQuery,
1098
+ transformed
1099
+ });
1100
+ }
1101
+ };
1102
+ const shouldTransformCustomQuery = (query) => {
1103
+ if (customQueryTransformMode === "all") return true;
1104
+ if (this.#pipelines.queries().has(query.id)) return false;
1105
+ const previous = previousQueries?.get(query.id);
1106
+ if (previous && previous.transformationHash === query.transformationHash) return false;
1107
+ return true;
1108
+ };
1109
+ const transformCustomQueries = async (queries) => {
1110
+ if (!customQueryTransformer || queries.length === 0) return;
1111
+ transformedCustomQueryCount += queries.length;
857
1112
  const transformStart = performance.now();
858
1113
  let transformedCustomQueries;
859
1114
  try {
860
- transformedCustomQueries = await this.#runPriorityOp(lc, "#syncQueryPipelineSet transforming custom queries", () => customQueryTransformer.transform(resolvedConnCtx, customQueriesToTransform));
1115
+ transformedCustomQueries = await hydrationBudget.excluding(() => this.#runPriorityOp(lc, "#syncQueryPipelineSet transforming custom queries", () => customQueryTransformer.transform(connCtx, queries)));
861
1116
  if (transformedCustomQueries.kind === "failed") throw new ProtocolErrorWithLevel(transformedCustomQueries.result, "warn");
862
1117
  else {
863
- if (!transformedCustomQueries.cached) this.connContextManager.validateConnection(resolvedConnCtx, resolvedConnCtx.revision, transformedCustomQueries.validation);
1118
+ if (!transformedCustomQueries.cached) this.connContextManager.validateConnection(connCtx, connCtx.revision, transformedCustomQueries.validation);
864
1119
  this.#queryTransformations.add(1, { result: "success" });
865
1120
  }
866
1121
  } catch (e) {
@@ -871,8 +1126,9 @@ var ViewSyncerService = class {
871
1126
  this.#queryTransformationTime.recordMs(transformDuration);
872
1127
  }
873
1128
  const successfullyTransformedCustomQueries = /* @__PURE__ */ new Map();
874
- erroredQueryIDs = this.#processTransformedCustomQueries(lc, transformedCustomQueries.result, (q) => {
875
- const origQuery = customQueries.get(q.id);
1129
+ const customQueryMap = new Map(queries.map((query) => [query.id, query]));
1130
+ erroredQueryIDs.push(...this.#processTransformedCustomQueries(lc, transformedCustomQueries.result, (q) => {
1131
+ const origQuery = customQueryMap.get(q.id);
876
1132
  if (origQuery) {
877
1133
  successfullyTransformedCustomQueries.set(q.id, q);
878
1134
  transformedQueries.push({
@@ -881,7 +1137,7 @@ var ViewSyncerService = class {
881
1137
  transformed: q
882
1138
  });
883
1139
  }
884
- }, customQueries);
1140
+ }, customQueryMap));
885
1141
  for (const [queryID, newTransform] of successfullyTransformedCustomQueries) {
886
1142
  const existingTransformHash = cvr.queries[queryID]?.transformationHash;
887
1143
  if (existingTransformHash) {
@@ -894,21 +1150,55 @@ var ViewSyncerService = class {
894
1150
  } else this.#queryTransformationNoOps.add(1);
895
1151
  }
896
1152
  }
1153
+ };
1154
+ const queriesToTransform = [...required, ...optionalToHydrate];
1155
+ transformOtherQueries(queriesToTransform);
1156
+ if (customQueryTransformMode === "missing" && previousQueries) {
1157
+ for (const query of queriesToTransform) if (query.type === "custom" && !this.#pipelines.queries().has(query.id)) {
1158
+ const previous = previousQueries.get(query.id);
1159
+ if (previous && previous.transformationHash === query.transformationHash) {
1160
+ this.#queryTransformationNoOps.add(1);
1161
+ transformedQueries.push({
1162
+ id: query.id,
1163
+ origQuery: query,
1164
+ transformed: {
1165
+ id: query.id,
1166
+ transformationHash: previous.transformationHash,
1167
+ transformedAst: previous.originalAst ?? previous.transformedAst
1168
+ }
1169
+ });
1170
+ }
1171
+ }
897
1172
  }
898
- const removeQueriesQueryIds = new Set([...Object.values(cvr.queries).filter((q) => expired(ttlClock, q)).map((q) => q.id), ...erroredQueryIDs || []]);
1173
+ await transformCustomQueries(queriesToTransform.filter((query) => query.type === "custom" && shouldTransformCustomQuery(query)));
1174
+ const circuitBrokenQueries = transformedQueries.filter(({ id, origQuery, transformed }) => origQuery.type !== "internal" && this.#pipelines.queries().get(id)?.transformationHash !== transformed.transformationHash && this.#hydrationCircuitBreaker.isOpen(transformed.transformationHash)).map(({ id, origQuery, transformed }) => ({
1175
+ id,
1176
+ transformationHash: transformed.transformationHash,
1177
+ name: origQuery.type === "custom" ? origQuery.name : void 0
1178
+ }));
1179
+ if (circuitBrokenQueries.length > 0) this.#rejectCircuitBrokenQueries(lc, cvr, circuitBrokenQueries);
1180
+ const removeQueriesQueryIds = new Set([
1181
+ ...naturallyExpiredQueryIDs,
1182
+ ...erroredQueryIDs,
1183
+ ...circuitBrokenQueries.map(({ id }) => id)
1184
+ ]);
899
1185
  const addQueries = transformedQueries.map(({ id, origQuery, transformed }) => ({
900
1186
  id,
901
1187
  ast: transformed.transformedAst,
902
1188
  transformationHash: transformed.transformationHash,
903
1189
  name: origQuery.type === "custom" ? origQuery.name : void 0
904
1190
  })).filter((q) => !removeQueriesQueryIds.has(q.id) && this.#pipelines.queries().get(q.id)?.transformationHash !== q.transformationHash);
905
- lc.info?.(`syncQueryPipelineSet: ${cvrQueryEntires.length} CVR queries, ${customQueriesToTransform.length} custom re-transformed, ${erroredQueryIDs?.length ?? 0} errored, ${removeQueriesQueryIds.size} to remove, ${addQueries.length} to add`);
1191
+ const hydrationOrder = new Map([...required, ...optional].map((query, index) => [query.id, index]));
1192
+ addQueries.sort((a, b) => must(hydrationOrder.get(a.id)) - must(hydrationOrder.get(b.id)));
1193
+ const requiredAddQueries = addQueries.filter((query) => requiredQueryIDs.has(query.id));
1194
+ const optionalAddQueries = addQueries.filter((query) => !requiredQueryIDs.has(query.id));
1195
+ lc.info?.(`syncQueryPipelineSet: ${cvrQueryEntires.length} CVR queries, ${transformedCustomQueryCount} custom re-transformed, ${erroredQueryIDs.length} errored, ${circuitBrokenQueries.length} circuit-broken, ${removeQueriesQueryIds.size} to remove, ${addQueries.length} to add`);
906
1196
  for (const q of addQueries) {
907
1197
  const orig = cvr.queries[q.id];
908
1198
  lc.debug?.("ViewSyncer adding query", q.ast, "transformed from", orig.type === "custom" ? orig.name : orig.ast);
909
1199
  }
910
1200
  if (addQueries.length > 0 || removeQueriesQueryIds.size > 0) {
911
- await this.#addAndRemoveQueries(lc, cvr, addQueries, Array.from(removeQueriesQueryIds, (id) => ({ id })), driftedQueryIDs);
1201
+ await this.#addAndRemoveQueries(lc, cvr, requiredAddQueries, optionalAddQueries, Array.from(removeQueriesQueryIds, (id) => ({ id })), hydrationBudget, hydrationPassStats, driftedQueryIDs);
912
1202
  if (addQueries.length > 0) this.#viewSyncerHydration.recordMs(performance.now() - start);
913
1203
  } else await this.#catchupClients(lc, cvr);
914
1204
  });
@@ -941,8 +1231,128 @@ var ViewSyncerService = class {
941
1231
  record.count++;
942
1232
  if (record.count >= THRASH_THRESHOLD) this.#lc.warn?.(`Query thrashing detected for query ${queryID}. ${record.count} replacements in 60s. This may indicate clients with different auth contexts connecting to the same client group.`);
943
1233
  }
944
- #addAndRemoveQueries(lc, cvr, addQueries, removeQueries, driftedQueryIDs = /* @__PURE__ */ new Set()) {
1234
+ /**
1235
+ * Records that hydrating `query` was aborted for exceeding the query
1236
+ * hydration timeout, and opens its circuit breaker.
1237
+ */
1238
+ #recordHydrationTimeout(lc, query, elapsedMs, rowCount) {
1239
+ this.#hydrationCircuitBreaker.trip(query.transformationHash);
1240
+ this.#hydrationTimeouts.add(1);
1241
+ if (!lc.warn) return;
1242
+ const shape = queryShape(query.ast);
1243
+ lc.warn("Query hydration aborted for exceeding the hydration timeout", {
1244
+ clientGroupID: this.id,
1245
+ queryHash: query.id,
1246
+ transformationHash: query.transformationHash,
1247
+ ...query.name !== void 0 && { queryName: query.name },
1248
+ queryShape: shape.hash,
1249
+ hydrationTimeoutMs: this.#hydrationCircuitBreaker.timeoutMs,
1250
+ hydrationElapsedMs: elapsedMs,
1251
+ ...rowCount !== void 0 && { hydrationRowCount: rowCount },
1252
+ circuitBreakerOpenMs: this.#hydrationCircuitBreaker.openMs,
1253
+ zql: shape.zql
1254
+ });
1255
+ }
1256
+ /**
1257
+ * Logs a hydration that exceeded the slow hydration threshold.
1258
+ *
1259
+ * The query is logged as its {@link queryShape}, with literal values
1260
+ * redacted, and each shape is logged at most once per
1261
+ * {@link SLOW_HYDRATION_LOG_WINDOW_MS}. The next log of a shape reports how
1262
+ * many slow hydrations of it were suppressed in the meantime.
1263
+ */
1264
+ #logSlowHydration(lc, query, elapsedMs) {
1265
+ if (!lc.warn) return;
1266
+ const stats = this.#pipelines.hydrationStats(query.id);
1267
+ const shape = stats?.shape ?? queryShape(query.ast);
1268
+ const suppressed = slowHydrationLogThrottle.admit(`${query.name ?? ""}:${shape.hash}`);
1269
+ if (suppressed === void 0) return;
1270
+ lc.warn("Slow query materialization", {
1271
+ zeroEvent: "query-slow-hydration",
1272
+ clientGroupID: this.id,
1273
+ queryHash: query.id,
1274
+ transformationHash: query.transformationHash,
1275
+ ...query.name !== void 0 && { queryName: query.name },
1276
+ queryShape: shape.hash,
1277
+ hydrationTimeMs: elapsedMs,
1278
+ ...stats && {
1279
+ hydrationRowCount: stats.rowCount,
1280
+ hydrationRowsRead: stats.rowsRead
1281
+ },
1282
+ ...stats !== void 0 && stats.planWarnings.length > 0 && { planWarnings: stats.planWarnings.map(planWarningMessage) },
1283
+ ...suppressed > 0 && { suppressedSinceLastLog: suppressed },
1284
+ zql: shape.zql
1285
+ });
1286
+ }
1287
+ /** Records that `query` was rejected without hydration by its open breaker. */
1288
+ #recordCircuitBreakerRejection(lc, query) {
1289
+ this.#hydrationCircuitBreakerRejections.add(1);
1290
+ lc.warn?.("Query rejected by its open hydration circuit breaker", {
1291
+ clientGroupID: this.id,
1292
+ queryHash: query.id,
1293
+ transformationHash: query.transformationHash,
1294
+ ...query.name !== void 0 && { queryName: query.name },
1295
+ hydrationTimeoutMs: this.#hydrationCircuitBreaker.timeoutMs,
1296
+ circuitBreakerOpenMs: this.#hydrationCircuitBreaker.openMs
1297
+ });
1298
+ }
1299
+ /**
1300
+ * Handles queries whose hydration circuit breaker is open: they are counted,
1301
+ * logged, and errored to the affected clients. The caller removes them from
1302
+ * the CVR.
1303
+ */
1304
+ #rejectCircuitBrokenQueries(lc, cvr, queries) {
1305
+ for (const query of queries) this.#recordCircuitBreakerRejection(lc, query);
1306
+ this.#queryEvictions.add(queries.length, { reason: "hydration-circuit-breaker" });
1307
+ this.#sendHydrationTimeoutErrors(cvr, queries);
1308
+ }
1309
+ /**
1310
+ * Sends a per-query error to every client that desires one of `queries`.
1311
+ * The error goes out as a `transformError` application error, which every
1312
+ * client understands as "this query errored" without affecting the
1313
+ * connection or the client's other queries.
1314
+ */
1315
+ #sendHydrationTimeoutErrors(cvr, queries) {
1316
+ const timeoutMs = this.#hydrationCircuitBreaker.timeoutMs;
1317
+ const errorsByClient = /* @__PURE__ */ new Map();
1318
+ for (const { id, name } of queries) {
1319
+ const query = cvr.queries[id];
1320
+ if (query === void 0 || query.type === "internal") continue;
1321
+ const error = {
1322
+ error: "app",
1323
+ id,
1324
+ name: name ?? (query.type === "custom" ? query.name : "legacy"),
1325
+ message: `Query hydration exceeded the ${timeoutMs}ms limit (ZERO_VIEW_SYNCER_QUERY_HYDRATION_TIMEOUT_MS) and was aborted`,
1326
+ details: {
1327
+ kind: "HydrationTimeout",
1328
+ timeoutMs
1329
+ }
1330
+ };
1331
+ for (const clientID of Object.keys(query.clientState)) getOrInsertComputed(errorsByClient, clientID, newArray).push(error);
1332
+ }
1333
+ for (const [clientID, errors] of errorsByClient) this.#clients.get(clientID)?.sendQueryTransformApplicationErrors(errors);
1334
+ }
1335
+ #recordHydrationBudgetExhaustion(lc, hydrationBudget, activeHydratedQueries, inactiveHydratedQueries, inactiveEvictedQueryIDs) {
1336
+ const elapsedMs = hydrationBudget.exhaustedAtMs;
1337
+ if (elapsedMs === void 0) return;
1338
+ this.#hydrationBudgetExhaustions.add(1);
1339
+ this.#hydrationBudgetEvictions.add(inactiveEvictedQueryIDs.length);
1340
+ this.#hydrationBudgetElapsed.record(elapsedMs);
1341
+ this.#hydrationBudgetOvershoot.record(Math.max(0, elapsedMs - hydrationBudget.limitMs));
1342
+ if (inactiveEvictedQueryIDs.length > 0) this.#queryEvictions.add(inactiveEvictedQueryIDs.length, { reason: "hydration-budget" });
1343
+ lc.info?.("view-syncer hydration budget exhausted", {
1344
+ clientGroupID: this.id,
1345
+ hydrationBudgetMs: hydrationBudget.limitMs,
1346
+ hydrationElapsedMs: elapsedMs,
1347
+ activeHydratedQueries,
1348
+ inactiveHydratedQueries,
1349
+ inactiveEvictedQueries: inactiveEvictedQueryIDs.length,
1350
+ firstEvictedQueryHash: inactiveEvictedQueryIDs[0] ?? null
1351
+ });
1352
+ }
1353
+ #addAndRemoveQueries(lc, cvr, requiredQueries, optionalQueries, removeQueries, hydrationBudget, hydrationPassStats, driftedQueryIDs = /* @__PURE__ */ new Set()) {
945
1354
  return startAsyncSpan(tracer, "vs.#addAndRemoveQueries", async () => {
1355
+ const addQueries = [...requiredQueries, ...optionalQueries];
946
1356
  assert(addQueries.length > 0 || removeQueries.length > 0, "Must have queries to add or remove");
947
1357
  const start = performance.now();
948
1358
  const stateVersion = this.#pipelines.currentVersion();
@@ -959,7 +1369,9 @@ var ViewSyncerService = class {
959
1369
  updater.ensureNewVersion();
960
1370
  }
961
1371
  const { queryPatches, newVersion } = updater.trackQueries(lc, addQueries, removeQueries);
962
- const pokers = startPoke(this.#getClients(), newVersion);
1372
+ if (hydrationBudget.limitMs !== 0 && optionalQueries.length > 0) assert(cmpVersions(cvr.version, newVersion) < 0, "Optional hydration requires a final poke version before row processing so a removal is actually poked");
1373
+ const clients = this.#getClients();
1374
+ const pokers = startPoke(lc, clients, newVersion);
963
1375
  for (const patch of queryPatches) await pokers.addPatch(patch);
964
1376
  for (const q of removeQueries) {
965
1377
  this.#pipelines.removeQuery(q.id);
@@ -975,22 +1387,54 @@ var ViewSyncerService = class {
975
1387
  let totalHydratedQueries = 0;
976
1388
  let coveredHydratedQueries = 0;
977
1389
  let firstCoveredQuery;
1390
+ const hydratedQueryIDs = [];
1391
+ const budgetEvictedQueryIDs = [];
1392
+ const timedOutQueries = [];
1393
+ const rejectedQueries = [];
1394
+ const circuitBreaker = this.#hydrationCircuitBreaker;
978
1395
  const self = this;
979
1396
  await yieldProcess(lc);
980
- function* generateRowChanges(slowHydrateThreshold) {
981
- for (const q of addQueries) {
1397
+ function* hydrateQueries(queries, optional, slowHydrateThreshold) {
1398
+ for (let i = 0; i < queries.length; i++) {
1399
+ if (optional && hydrationBudget.exhausted()) {
1400
+ budgetEvictedQueryIDs.push(...queries.slice(i).map((query) => query.id));
1401
+ return;
1402
+ }
1403
+ const q = must(queries[i]);
982
1404
  let queryLC = lc.withContext("hash", q.id).withContext("queryHash", q.id).withContext("transformationHash", q.transformationHash);
983
1405
  if (q.name !== void 0) queryLC = queryLC.withContext("queryName", q.name);
984
1406
  queryLC.debug?.(`adding pipeline for query`, q.ast);
1407
+ const breakable = cvr.queries[q.id]?.type !== "internal";
1408
+ if (breakable && circuitBreaker.isOpen(q.transformationHash)) {
1409
+ rejectedQueries.push(q);
1410
+ self.#recordCircuitBreakerRejection(queryLC, q);
1411
+ continue;
1412
+ }
985
1413
  const covered = queryCoveringIndex ? self.#findQueryCoverageShadowHit(queryCoveringIndex, q.id, q.transformationHash, q.ast, q.name) : void 0;
986
1414
  totalHydratedQueries++;
987
1415
  if (covered) {
988
1416
  coveredHydratedQueries++;
989
1417
  firstCoveredQuery ??= covered;
990
1418
  }
991
- yield* pipelines.addQuery(q.transformationHash, q.id, q.ast, timer.startWithoutYielding(), q.name, "query-set-sync");
1419
+ let timedOut = false;
1420
+ for (const change of pipelines.addQuery(q.transformationHash, q.id, q.ast, timer.startWithoutYielding(), q.name, "query-set-sync")) {
1421
+ if (change === "yield" && breakable && circuitBreaker.exceeded(timer.totalElapsed())) {
1422
+ timedOut = true;
1423
+ yield change;
1424
+ break;
1425
+ }
1426
+ yield change;
1427
+ }
992
1428
  const elapsed = timer.stop();
993
1429
  totalProcessTime += elapsed;
1430
+ if (timedOut) {
1431
+ timedOutQueries.push(q);
1432
+ self.#recordHydrationTimeout(queryLC, q, elapsed);
1433
+ continue;
1434
+ }
1435
+ hydratedQueryIDs.push(q.id);
1436
+ if (optional) hydrationPassStats.inactiveHydratedQueries++;
1437
+ else hydrationPassStats.activeHydratedQueries++;
994
1438
  self.#addQueryMaterializationServerMetric(q.id, elapsed);
995
1439
  self.#inspectorDelegate.addQuery(q.id, q.ast);
996
1440
  queryCoveringIndex?.add(q.id, {
@@ -998,24 +1442,49 @@ var ViewSyncerService = class {
998
1442
  transformationHash: q.transformationHash,
999
1443
  ...q.name !== void 0 && { queryName: q.name }
1000
1444
  });
1001
- if (elapsed > slowHydrateThreshold) queryLC.warn?.("Slow query materialization", elapsed, q.ast);
1445
+ if (elapsed > slowHydrateThreshold) self.#logSlowHydration(queryLC, q, elapsed);
1002
1446
  manualSpan(tracer, "vs.addAndConsumeQuery", elapsed, {
1003
1447
  hash: q.id,
1004
1448
  transformationHash: q.transformationHash,
1005
1449
  ...q.name !== void 0 && { name: q.name }
1006
1450
  });
1451
+ hydrations.add(1);
1452
+ hydrationTime.recordMs(elapsed);
1007
1453
  }
1008
- hydrations.add(1);
1009
- hydrationTime.recordMs(totalProcessTime);
1454
+ }
1455
+ function* generateRowChanges(slowHydrateThreshold) {
1456
+ yield* hydrateQueries(requiredQueries, false, slowHydrateThreshold);
1457
+ yield* hydrateQueries(optionalQueries, true, slowHydrateThreshold);
1010
1458
  }
1011
1459
  await this.#processChanges(lc, timer, generateRowChanges(this.#slowHydrateThreshold), updater, pokers);
1460
+ const abortedQueries = [...timedOutQueries, ...rejectedQueries];
1461
+ if (abortedQueries.length > 0) {
1462
+ const abortedQueryIDs = abortedQueries.map(({ id }) => id);
1463
+ for (const patch of await updater.abortExecutedQueries(lc, abortedQueryIDs)) await pokers.addPatch(patch);
1464
+ for (const queryID of abortedQueryIDs) {
1465
+ this.#pipelines.removeQuery(queryID);
1466
+ this.#inspectorDelegate.removeQuery(queryID);
1467
+ this.#queryReplacements.delete(queryID);
1468
+ }
1469
+ if (timedOutQueries.length > 0) this.#queryEvictions.add(timedOutQueries.length, { reason: "hydration-timeout" });
1470
+ if (rejectedQueries.length > 0) this.#queryEvictions.add(rejectedQueries.length, { reason: "hydration-circuit-breaker" });
1471
+ this.#sendHydrationTimeoutErrors(cvr, abortedQueries);
1472
+ }
1473
+ for (const patch of updater.removeTrackedQueries(budgetEvictedQueryIDs)) await pokers.addPatch(patch);
1474
+ for (const queryID of budgetEvictedQueryIDs) {
1475
+ this.#pipelines.removeQuery(queryID);
1476
+ this.#inspectorDelegate.removeQuery(queryID);
1477
+ this.#queryReplacements.delete(queryID);
1478
+ }
1479
+ this.#recordHydrationBudgetExhaustion(lc, hydrationBudget, hydrationPassStats.activeHydratedQueries, hydrationPassStats.inactiveHydratedQueries, budgetEvictedQueryIDs);
1012
1480
  this.#logQueryCoverageShadowSummary(lc, "add", totalHydratedQueries, coveredHydratedQueries, firstCoveredQuery);
1013
1481
  await startAsyncSpan(tracer, "vs.#syncQueryPipelineSet.deleteUnreferencedRows", async () => {
1014
1482
  for (const patch of await updater.deleteUnreferencedRows(lc)) await pokers.addPatch(patch);
1015
1483
  });
1016
- this.#cvr = await this.#flushUpdater(lc, updater);
1484
+ this.#cvr = await this.#flushPoked(lc, updater, pokers);
1485
+ if (budgetEvictedQueryIDs.length > 0) this.#scheduleExpireEviction(lc, this.#cvr);
1017
1486
  const finalVersion = this.#cvr.version;
1018
- await this.#catchupClients(lc, cvr, finalVersion, addQueries.map((q) => q.id), pokers);
1487
+ await this.#catchupClients(lc, cvr, finalVersion, hydratedQueryIDs, pokers);
1019
1488
  await startAsyncSpan(tracer, "vs.#syncQueryPipelineSet.pokeEnd", () => pokers.end(finalVersion));
1020
1489
  this.#markVersionServed(stateVersion);
1021
1490
  const wallTime = performance.now() - start;
@@ -1044,7 +1513,7 @@ var ViewSyncerService = class {
1044
1513
  return startAsyncSpan(tracer, "vs.#catchupClients", async (span) => {
1045
1514
  current ??= cvr.version;
1046
1515
  const clients = this.#getClients();
1047
- const pokers = usePokers ?? startPoke(clients, cvr.version);
1516
+ const pokers = usePokers ?? startPoke(lc, clients, cvr.version);
1048
1517
  span.setAttribute("numClients", clients.length);
1049
1518
  const catchupFrom = clients.map((c) => c.version()).reduce((a, b) => cmpVersions(a, b) < 0 ? a : b, cvr.version);
1050
1519
  const rowPatches = this.#cvrStore.catchupRowPatches(lc, catchupFrom, cvr, current, excludeQueryHashes);
@@ -1156,7 +1625,9 @@ var ViewSyncerService = class {
1156
1625
  *
1157
1626
  * Must be called from within the #lock.
1158
1627
  *
1159
- * Returns false if the advancement failed due to a schema change.
1628
+ * Returns 'success' if changes were successfully processed and poked,
1629
+ * or a `ResetPipelinesSignal` if advancement aborted (e.g. schema change,
1630
+ * timeout) and pipelines need to be reset and rehydrated.
1160
1631
  */
1161
1632
  #advancePipelines(lc, cvr) {
1162
1633
  return startAsyncSpan(tracer, "vs.#advancePipelines", async (span) => {
@@ -1164,21 +1635,29 @@ var ViewSyncerService = class {
1164
1635
  assert(this.#pipelines.initialized(), "pipelines must be initialized (advancePipelines");
1165
1636
  const start = performance.now();
1166
1637
  const timer = new TimeSliceTimer(lc);
1167
- const { version, numChanges, changes } = this.#pipelines.advance(timer);
1168
- lc = lc.withContext("newVersion", version);
1169
- const updater = new CVRQueryDrivenUpdater(this.#cvrStore, cvr, version, this.#pipelines.replicaVersion, (queryID) => this.#pipelines.rowSetSignature(queryID));
1170
- const pokers = startPoke(this.#getClients(cvr.version), updater.updatedVersion());
1171
- lc.debug?.(`applying ${numChanges} to advance to ${version}`);
1638
+ let pokers;
1639
+ let updater;
1640
+ let version;
1641
+ let numChanges = 0;
1172
1642
  try {
1173
- await this.#processChanges(lc, await timer.start(), changes, updater, pokers);
1643
+ const advancement = this.#pipelines.advance(timer);
1644
+ version = advancement.version;
1645
+ numChanges = advancement.numChanges;
1646
+ lc = lc.withContext("newVersion", version);
1647
+ updater = new CVRQueryDrivenUpdater(this.#cvrStore, cvr, version, this.#pipelines.replicaVersion, (queryID) => this.#pipelines.rowSetSignature(queryID));
1648
+ pokers = startPoke(lc, this.#getClients(cvr.version), updater.updatedVersion());
1649
+ lc.debug?.(`applying ${numChanges} to advance to ${version}`);
1650
+ await this.#processChanges(lc, await timer.start(), advancement.changes, updater, pokers);
1174
1651
  } catch (e) {
1175
1652
  if (e instanceof ResetPipelinesSignal) {
1176
- await pokers.cancel();
1653
+ await pokers?.cancel();
1654
+ this.#cvrStore.discardPending();
1177
1655
  return e;
1178
1656
  }
1179
1657
  throw e;
1180
1658
  }
1181
- this.#cvr = await this.#flushUpdater(lc, updater);
1659
+ assert(updater && pokers && version !== void 0, "advancement state missing");
1660
+ this.#cvr = await this.#flushPoked(lc, updater, pokers);
1182
1661
  const finalVersion = this.#cvr.version;
1183
1662
  await startAsyncSpan(tracer, "vs.#advancePipelines.pokeEnd", () => pokers.end(finalVersion));
1184
1663
  this.#markVersionServed(version);
@@ -1198,7 +1677,7 @@ var ViewSyncerService = class {
1198
1677
  clientID,
1199
1678
  wsID: client.wsID
1200
1679
  });
1201
- return handleInspect(lc, body, cvr, client, this.#inspectorDelegate, this.id, this.#cvrStore, this.#config, connCtx);
1680
+ return handleInspect(lc, body, cvr, client, this.#inspectorDelegate, this.id, this, this.#cvrStore, this.#config, connCtx);
1202
1681
  };
1203
1682
  async #runBackgroundRetransform(lc) {
1204
1683
  const attemptRetransform = async (connCtx) => {
@@ -1285,15 +1764,18 @@ var ViewSyncerService = class {
1285
1764
  return this.#stopped.promise;
1286
1765
  }
1287
1766
  async #cleanup(err) {
1767
+ this.#shuttingDown = true;
1288
1768
  this.connContextManager.setSharedRetransformReady(false);
1289
1769
  this.#stopTTLClockInterval();
1290
1770
  this.#stopExpireTimer();
1291
1771
  this.#stopAuthMaintenanceTimer();
1772
+ this.#stopShutdownTimer();
1292
1773
  this.#customQueryTransformer?.destroy();
1293
1774
  for (const client of this.#clients.values()) if (err) client.fail(err);
1294
1775
  else client.close(`closed clientGroupID=${this.id}`);
1295
1776
  await this.#lock.withLock(() => {});
1296
1777
  this.#pipelines.destroy();
1778
+ this.#inspectorDelegate.clearAuthenticated(this.id, this);
1297
1779
  }
1298
1780
  /**
1299
1781
  * Test helper: Manually mark initialization as complete.
@@ -1329,8 +1811,10 @@ function isTransformFailedError(error) {
1329
1811
  return error.errorBody.kind === "TransformFailed" && !isAuthErrorBody(error.errorBody);
1330
1812
  }
1331
1813
  /**
1332
- * A query must be expired for all clients in order to be considered
1333
- * expired.
1814
+ * Whether a query's TTL has elapsed. A query must be expired for all clients
1815
+ * in order to be considered expired.
1816
+ *
1817
+ * Exported for testing.
1334
1818
  */
1335
1819
  function expired(ttlClock, q) {
1336
1820
  if (q.type === "internal") return false;