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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (988) hide show
  1. package/out/analyze-query/src/analyze-cli.js +4 -4
  2. package/out/analyze-query/src/analyze-cli.js.map +1 -1
  3. package/out/analyze-query/src/bin-analyze.js +13 -12
  4. package/out/analyze-query/src/bin-analyze.js.map +1 -1
  5. package/out/analyze-query/src/bin-transform.js +1 -1
  6. package/out/analyze-query/src/bin-transform.js.map +1 -1
  7. package/out/ast-to-zql/src/ast-to-zql.d.ts +8 -1
  8. package/out/ast-to-zql/src/ast-to-zql.d.ts.map +1 -1
  9. package/out/ast-to-zql/src/ast-to-zql.js +25 -25
  10. package/out/ast-to-zql/src/ast-to-zql.js.map +1 -1
  11. package/out/otel/src/log-options.d.ts +16 -0
  12. package/out/otel/src/log-options.d.ts.map +1 -1
  13. package/out/otel/src/log-options.js +60 -6
  14. package/out/otel/src/log-options.js.map +1 -1
  15. package/out/replicache/src/bg-interval.d.ts +2 -1
  16. package/out/replicache/src/bg-interval.d.ts.map +1 -1
  17. package/out/replicache/src/bg-interval.js +13 -4
  18. package/out/replicache/src/bg-interval.js.map +1 -1
  19. package/out/replicache/src/btree/node.d.ts.map +1 -1
  20. package/out/replicache/src/btree/node.js +3 -6
  21. package/out/replicache/src/btree/node.js.map +1 -1
  22. package/out/replicache/src/dag/gc.d.ts.map +1 -1
  23. package/out/replicache/src/dag/gc.js +8 -11
  24. package/out/replicache/src/dag/gc.js.map +1 -1
  25. package/out/replicache/src/dag/invalid-ref-count-error.d.ts +12 -0
  26. package/out/replicache/src/dag/invalid-ref-count-error.d.ts.map +1 -0
  27. package/out/replicache/src/dag/invalid-ref-count-error.js +19 -0
  28. package/out/replicache/src/dag/invalid-ref-count-error.js.map +1 -0
  29. package/out/replicache/src/dag/lazy-store.d.ts +17 -4
  30. package/out/replicache/src/dag/lazy-store.d.ts.map +1 -1
  31. package/out/replicache/src/dag/lazy-store.js +35 -9
  32. package/out/replicache/src/dag/lazy-store.js.map +1 -1
  33. package/out/replicache/src/dag/store-impl.d.ts +12 -2
  34. package/out/replicache/src/dag/store-impl.d.ts.map +1 -1
  35. package/out/replicache/src/dag/store-impl.js +29 -9
  36. package/out/replicache/src/dag/store-impl.js.map +1 -1
  37. package/out/replicache/src/db/rebase.d.ts +14 -2
  38. package/out/replicache/src/db/rebase.d.ts.map +1 -1
  39. package/out/replicache/src/db/rebase.js +27 -5
  40. package/out/replicache/src/db/rebase.js.map +1 -1
  41. package/out/replicache/src/get-kv-store-provider.d.ts +1 -1
  42. package/out/replicache/src/get-kv-store-provider.d.ts.map +1 -1
  43. package/out/replicache/src/get-kv-store-provider.js +4 -4
  44. package/out/replicache/src/get-kv-store-provider.js.map +1 -1
  45. package/out/replicache/src/kv/expo-sqlite/store.d.ts.map +1 -1
  46. package/out/replicache/src/kv/expo-sqlite/store.js +28 -5
  47. package/out/replicache/src/kv/expo-sqlite/store.js.map +1 -1
  48. package/out/replicache/src/kv/idb-store.d.ts +18 -0
  49. package/out/replicache/src/kv/idb-store.d.ts.map +1 -1
  50. package/out/replicache/src/kv/idb-store.js +30 -2
  51. package/out/replicache/src/kv/idb-store.js.map +1 -1
  52. package/out/replicache/src/kv/mem-fallback-store.d.ts +54 -0
  53. package/out/replicache/src/kv/mem-fallback-store.d.ts.map +1 -0
  54. package/out/replicache/src/kv/mem-fallback-store.js +177 -0
  55. package/out/replicache/src/kv/mem-fallback-store.js.map +1 -0
  56. package/out/replicache/src/kv/mem-store.d.ts +1 -0
  57. package/out/replicache/src/kv/mem-store.d.ts.map +1 -1
  58. package/out/replicache/src/kv/mem-store.js +3 -0
  59. package/out/replicache/src/kv/mem-store.js.map +1 -1
  60. package/out/replicache/src/kv/op-sqlite/store.d.ts.map +1 -1
  61. package/out/replicache/src/kv/op-sqlite/store.js +4 -4
  62. package/out/replicache/src/kv/op-sqlite/store.js.map +1 -1
  63. package/out/replicache/src/kv/sqlite-store.d.ts +22 -1
  64. package/out/replicache/src/kv/sqlite-store.d.ts.map +1 -1
  65. package/out/replicache/src/kv/sqlite-store.js +159 -14
  66. package/out/replicache/src/kv/sqlite-store.js.map +1 -1
  67. package/out/replicache/src/kv/store.d.ts +6 -0
  68. package/out/replicache/src/kv/store.d.ts.map +1 -1
  69. package/out/replicache/src/new-client-channel.js.map +1 -1
  70. package/out/replicache/src/persist/client-gc.d.ts +2 -1
  71. package/out/replicache/src/persist/client-gc.d.ts.map +1 -1
  72. package/out/replicache/src/persist/client-gc.js +2 -2
  73. package/out/replicache/src/persist/client-gc.js.map +1 -1
  74. package/out/replicache/src/persist/client-group-gc.d.ts +2 -1
  75. package/out/replicache/src/persist/client-group-gc.d.ts.map +1 -1
  76. package/out/replicache/src/persist/client-group-gc.js +2 -2
  77. package/out/replicache/src/persist/client-group-gc.js.map +1 -1
  78. package/out/replicache/src/persist/clients.d.ts +2 -2
  79. package/out/replicache/src/persist/collect-idb-databases.d.ts +28 -8
  80. package/out/replicache/src/persist/collect-idb-databases.d.ts.map +1 -1
  81. package/out/replicache/src/persist/collect-idb-databases.js +97 -20
  82. package/out/replicache/src/persist/collect-idb-databases.js.map +1 -1
  83. package/out/replicache/src/persist/heartbeat.d.ts +2 -1
  84. package/out/replicache/src/persist/heartbeat.d.ts.map +1 -1
  85. package/out/replicache/src/persist/heartbeat.js +2 -2
  86. package/out/replicache/src/persist/heartbeat.js.map +1 -1
  87. package/out/replicache/src/persist/idb-databases-store-db-name.js +1 -1
  88. package/out/replicache/src/persist/idb-databases-store-db-name.js.map +1 -1
  89. package/out/replicache/src/persist/persist.d.ts.map +1 -1
  90. package/out/replicache/src/persist/persist.js +18 -8
  91. package/out/replicache/src/persist/persist.js.map +1 -1
  92. package/out/replicache/src/persist/refresh.js +6 -2
  93. package/out/replicache/src/persist/refresh.js.map +1 -1
  94. package/out/replicache/src/replicache-impl.d.ts +85 -3
  95. package/out/replicache/src/replicache-impl.d.ts.map +1 -1
  96. package/out/replicache/src/replicache-impl.js +321 -29
  97. package/out/replicache/src/replicache-impl.js.map +1 -1
  98. package/out/replicache/src/replicache-options.d.ts +9 -0
  99. package/out/replicache/src/replicache-options.d.ts.map +1 -1
  100. package/out/replicache/src/storage-failure.d.ts +37 -0
  101. package/out/replicache/src/storage-failure.d.ts.map +1 -0
  102. package/out/replicache/src/storage-failure.js +31 -0
  103. package/out/replicache/src/storage-failure.js.map +1 -0
  104. package/out/shared/src/arrays.d.ts +5 -0
  105. package/out/shared/src/arrays.d.ts.map +1 -1
  106. package/out/shared/src/arrays.js +8 -10
  107. package/out/shared/src/arrays.js.map +1 -1
  108. package/out/shared/src/base64.d.ts +19 -0
  109. package/out/shared/src/base64.d.ts.map +1 -0
  110. package/out/shared/src/base64.js +40 -0
  111. package/out/shared/src/base64.js.map +1 -0
  112. package/out/shared/src/centroid.d.ts +0 -1
  113. package/out/shared/src/centroid.d.ts.map +1 -1
  114. package/out/shared/src/centroid.js +1 -4
  115. package/out/shared/src/centroid.js.map +1 -1
  116. package/out/shared/src/error.d.ts +11 -0
  117. package/out/shared/src/error.d.ts.map +1 -1
  118. package/out/shared/src/error.js +35 -1
  119. package/out/shared/src/error.js.map +1 -1
  120. package/out/shared/src/hash.d.ts.map +1 -1
  121. package/out/shared/src/hash.js +32 -7
  122. package/out/shared/src/hash.js.map +1 -1
  123. package/out/shared/src/iterables.d.ts +2 -0
  124. package/out/shared/src/iterables.d.ts.map +1 -1
  125. package/out/shared/src/iterables.js +18 -1
  126. package/out/shared/src/iterables.js.map +1 -1
  127. package/out/shared/src/map.d.ts +24 -2
  128. package/out/shared/src/map.d.ts.map +1 -1
  129. package/out/shared/src/map.js +18 -4
  130. package/out/shared/src/map.js.map +1 -1
  131. package/out/shared/src/options-types.d.ts +2 -2
  132. package/out/shared/src/options.d.ts.map +1 -1
  133. package/out/shared/src/options.js +10 -7
  134. package/out/shared/src/options.js.map +1 -1
  135. package/out/shared/src/packed-boolean-map.d.ts +7 -0
  136. package/out/shared/src/packed-boolean-map.d.ts.map +1 -0
  137. package/out/shared/src/packed-boolean-map.js +36 -0
  138. package/out/shared/src/packed-boolean-map.js.map +1 -0
  139. package/out/shared/src/random-values.js +12 -1
  140. package/out/shared/src/random-values.js.map +1 -1
  141. package/out/shared/src/ring-buffer.d.ts +10 -0
  142. package/out/shared/src/ring-buffer.d.ts.map +1 -1
  143. package/out/shared/src/ring-buffer.js +26 -1
  144. package/out/shared/src/ring-buffer.js.map +1 -1
  145. package/out/shared/src/tdigest.d.ts +10 -0
  146. package/out/shared/src/tdigest.d.ts.map +1 -1
  147. package/out/shared/src/tdigest.js +147 -63
  148. package/out/shared/src/tdigest.js.map +1 -1
  149. package/out/shared/src/valita.d.ts +13 -0
  150. package/out/shared/src/valita.d.ts.map +1 -1
  151. package/out/shared/src/valita.js +23 -23
  152. package/out/shared/src/valita.js.map +1 -1
  153. package/out/z2s/src/compiler.d.ts.map +1 -1
  154. package/out/z2s/src/compiler.js +10 -6
  155. package/out/z2s/src/compiler.js.map +1 -1
  156. package/out/z2s/src/sql.d.ts.map +1 -1
  157. package/out/z2s/src/sql.js +9 -5
  158. package/out/z2s/src/sql.js.map +1 -1
  159. package/out/zero/package.js +4 -5
  160. package/out/zero/package.js.map +1 -1
  161. package/out/zero/src/zero.js +2 -1
  162. package/out/zero-cache/src/auth/write-authorizer.d.ts.map +1 -1
  163. package/out/zero-cache/src/auth/write-authorizer.js +1 -0
  164. package/out/zero-cache/src/auth/write-authorizer.js.map +1 -1
  165. package/out/zero-cache/src/config/normalize.d.ts +1 -0
  166. package/out/zero-cache/src/config/normalize.d.ts.map +1 -1
  167. package/out/zero-cache/src/config/normalize.js +46 -4
  168. package/out/zero-cache/src/config/normalize.js.map +1 -1
  169. package/out/zero-cache/src/config/zero-config.d.ts +116 -24
  170. package/out/zero-cache/src/config/zero-config.d.ts.map +1 -1
  171. package/out/zero-cache/src/config/zero-config.js +409 -157
  172. package/out/zero-cache/src/config/zero-config.js.map +1 -1
  173. package/out/zero-cache/src/custom/fetch.d.ts +1 -1
  174. package/out/zero-cache/src/custom/fetch.d.ts.map +1 -1
  175. package/out/zero-cache/src/custom/fetch.js.map +1 -1
  176. package/out/zero-cache/src/db/lite-tables.d.ts.map +1 -1
  177. package/out/zero-cache/src/db/lite-tables.js +3 -4
  178. package/out/zero-cache/src/db/lite-tables.js.map +1 -1
  179. package/out/zero-cache/src/db/migration-lite.d.ts.map +1 -1
  180. package/out/zero-cache/src/db/migration-lite.js +5 -3
  181. package/out/zero-cache/src/db/migration-lite.js.map +1 -1
  182. package/out/zero-cache/src/observability/events.js +4 -1
  183. package/out/zero-cache/src/observability/events.js.map +1 -1
  184. package/out/zero-cache/src/observability/log-throttle.d.ts +44 -0
  185. package/out/zero-cache/src/observability/log-throttle.d.ts.map +1 -0
  186. package/out/zero-cache/src/observability/log-throttle.js +76 -0
  187. package/out/zero-cache/src/observability/log-throttle.js.map +1 -0
  188. package/out/zero-cache/src/observability/metrics.d.ts.map +1 -1
  189. package/out/zero-cache/src/observability/metrics.js +2 -7
  190. package/out/zero-cache/src/observability/metrics.js.map +1 -1
  191. package/out/zero-cache/src/scripts/permissions.d.ts +16 -0
  192. package/out/zero-cache/src/scripts/permissions.d.ts.map +1 -1
  193. package/out/zero-cache/src/scripts/permissions.js +3 -3
  194. package/out/zero-cache/src/scripts/permissions.js.map +1 -1
  195. package/out/zero-cache/src/server/change-streamer.d.ts.map +1 -1
  196. package/out/zero-cache/src/server/change-streamer.js +117 -77
  197. package/out/zero-cache/src/server/change-streamer.js.map +1 -1
  198. package/out/zero-cache/src/server/inspector-delegate.d.ts +28 -2
  199. package/out/zero-cache/src/server/inspector-delegate.d.ts.map +1 -1
  200. package/out/zero-cache/src/server/inspector-delegate.js +37 -17
  201. package/out/zero-cache/src/server/inspector-delegate.js.map +1 -1
  202. package/out/zero-cache/src/server/main.d.ts.map +1 -1
  203. package/out/zero-cache/src/server/main.js +8 -1
  204. package/out/zero-cache/src/server/main.js.map +1 -1
  205. package/out/zero-cache/src/server/mutator.js +2 -0
  206. package/out/zero-cache/src/server/mutator.js.map +1 -1
  207. package/out/zero-cache/src/server/reaper.d.ts.map +1 -1
  208. package/out/zero-cache/src/server/reaper.js +2 -0
  209. package/out/zero-cache/src/server/reaper.js.map +1 -1
  210. package/out/zero-cache/src/server/replicator.d.ts +3 -0
  211. package/out/zero-cache/src/server/replicator.d.ts.map +1 -1
  212. package/out/zero-cache/src/server/replicator.js +95 -21
  213. package/out/zero-cache/src/server/replicator.js.map +1 -1
  214. package/out/zero-cache/src/server/runner/zero-dispatcher.d.ts.map +1 -1
  215. package/out/zero-cache/src/server/runner/zero-dispatcher.js +5 -0
  216. package/out/zero-cache/src/server/runner/zero-dispatcher.js.map +1 -1
  217. package/out/zero-cache/src/server/syncer-assigner.d.ts +14 -0
  218. package/out/zero-cache/src/server/syncer-assigner.d.ts.map +1 -0
  219. package/out/zero-cache/src/server/syncer-assigner.js +72 -0
  220. package/out/zero-cache/src/server/syncer-assigner.js.map +1 -0
  221. package/out/zero-cache/src/server/syncer.d.ts.map +1 -1
  222. package/out/zero-cache/src/server/syncer.js +24 -2
  223. package/out/zero-cache/src/server/syncer.js.map +1 -1
  224. package/out/zero-cache/src/server/worker-dispatcher.d.ts.map +1 -1
  225. package/out/zero-cache/src/server/worker-dispatcher.js +21 -4
  226. package/out/zero-cache/src/server/worker-dispatcher.js.map +1 -1
  227. package/out/zero-cache/src/services/analyze.d.ts.map +1 -1
  228. package/out/zero-cache/src/services/analyze.js +11 -9
  229. package/out/zero-cache/src/services/analyze.js.map +1 -1
  230. package/out/zero-cache/src/services/change-source/common/backfill-manager.d.ts.map +1 -1
  231. package/out/zero-cache/src/services/change-source/common/backfill-manager.js +198 -24
  232. package/out/zero-cache/src/services/change-source/common/backfill-manager.js.map +1 -1
  233. package/out/zero-cache/src/services/change-source/common/change-stream-multiplexer.d.ts.map +1 -1
  234. package/out/zero-cache/src/services/change-source/common/change-stream-multiplexer.js +16 -4
  235. package/out/zero-cache/src/services/change-source/common/change-stream-multiplexer.js.map +1 -1
  236. package/out/zero-cache/src/services/change-source/common/init-cleanup.d.ts +24 -0
  237. package/out/zero-cache/src/services/change-source/common/init-cleanup.d.ts.map +1 -0
  238. package/out/zero-cache/src/services/change-source/common/init-cleanup.js +44 -0
  239. package/out/zero-cache/src/services/change-source/common/init-cleanup.js.map +1 -0
  240. package/out/zero-cache/src/services/change-source/common/replica-restore.d.ts +92 -2
  241. package/out/zero-cache/src/services/change-source/common/replica-restore.d.ts.map +1 -1
  242. package/out/zero-cache/src/services/change-source/common/replica-restore.js +27 -10
  243. package/out/zero-cache/src/services/change-source/common/replica-restore.js.map +1 -1
  244. package/out/zero-cache/src/services/change-source/common/replica-schema.d.ts +1 -0
  245. package/out/zero-cache/src/services/change-source/common/replica-schema.d.ts.map +1 -1
  246. package/out/zero-cache/src/services/change-source/common/replica-schema.js +15 -3
  247. package/out/zero-cache/src/services/change-source/common/replica-schema.js.map +1 -1
  248. package/out/zero-cache/src/services/change-source/custom/change-source.d.ts +1 -1
  249. package/out/zero-cache/src/services/change-source/custom/change-source.d.ts.map +1 -1
  250. package/out/zero-cache/src/services/change-source/custom/change-source.js +7 -3
  251. package/out/zero-cache/src/services/change-source/custom/change-source.js.map +1 -1
  252. package/out/zero-cache/src/services/change-source/pg/backfill-stream.d.ts +9 -0
  253. package/out/zero-cache/src/services/change-source/pg/backfill-stream.d.ts.map +1 -1
  254. package/out/zero-cache/src/services/change-source/pg/backfill-stream.js +206 -19
  255. package/out/zero-cache/src/services/change-source/pg/backfill-stream.js.map +1 -1
  256. package/out/zero-cache/src/services/change-source/pg/change-source-init.d.ts +55 -0
  257. package/out/zero-cache/src/services/change-source/pg/change-source-init.d.ts.map +1 -0
  258. package/out/zero-cache/src/services/change-source/pg/change-source-init.js +305 -0
  259. package/out/zero-cache/src/services/change-source/pg/change-source-init.js.map +1 -0
  260. package/out/zero-cache/src/services/change-source/pg/change-source.d.ts +31 -18
  261. package/out/zero-cache/src/services/change-source/pg/change-source.d.ts.map +1 -1
  262. package/out/zero-cache/src/services/change-source/pg/change-source.js +130 -157
  263. package/out/zero-cache/src/services/change-source/pg/change-source.js.map +1 -1
  264. package/out/zero-cache/src/services/change-source/pg/initial-sync.d.ts +38 -2
  265. package/out/zero-cache/src/services/change-source/pg/initial-sync.d.ts.map +1 -1
  266. package/out/zero-cache/src/services/change-source/pg/initial-sync.js +55 -21
  267. package/out/zero-cache/src/services/change-source/pg/initial-sync.js.map +1 -1
  268. package/out/zero-cache/src/services/change-source/pg/logical-replication/stream.d.ts +31 -0
  269. package/out/zero-cache/src/services/change-source/pg/logical-replication/stream.d.ts.map +1 -1
  270. package/out/zero-cache/src/services/change-source/pg/logical-replication/stream.js +102 -3
  271. package/out/zero-cache/src/services/change-source/pg/logical-replication/stream.js.map +1 -1
  272. package/out/zero-cache/src/services/change-source/pg/replication-slot-cleanup-monitor.d.ts +16 -0
  273. package/out/zero-cache/src/services/change-source/pg/replication-slot-cleanup-monitor.d.ts.map +1 -0
  274. package/out/zero-cache/src/services/change-source/pg/replication-slot-cleanup-monitor.js +113 -0
  275. package/out/zero-cache/src/services/change-source/pg/replication-slot-cleanup-monitor.js.map +1 -0
  276. package/out/zero-cache/src/services/change-source/pg/replication-slots.d.ts +40 -15
  277. package/out/zero-cache/src/services/change-source/pg/replication-slots.d.ts.map +1 -1
  278. package/out/zero-cache/src/services/change-source/pg/replication-slots.js +149 -27
  279. package/out/zero-cache/src/services/change-source/pg/replication-slots.js.map +1 -1
  280. package/out/zero-cache/src/services/change-source/pg/schema/index-predicate.d.ts.map +1 -1
  281. package/out/zero-cache/src/services/change-source/pg/schema/index-predicate.js +68 -8
  282. package/out/zero-cache/src/services/change-source/pg/schema/index-predicate.js.map +1 -1
  283. package/out/zero-cache/src/services/change-source/pg/schema/init.d.ts.map +1 -1
  284. package/out/zero-cache/src/services/change-source/pg/schema/init.js +32 -1
  285. package/out/zero-cache/src/services/change-source/pg/schema/init.js.map +1 -1
  286. package/out/zero-cache/src/services/change-source/pg/schema/replica-stage-enum.d.ts +10 -0
  287. package/out/zero-cache/src/services/change-source/pg/schema/replica-stage-enum.d.ts.map +1 -0
  288. package/out/zero-cache/src/services/change-source/pg/schema/replica-stage-enum.js +6 -0
  289. package/out/zero-cache/src/services/change-source/pg/schema/replica-stage-enum.js.map +1 -0
  290. package/out/zero-cache/src/services/change-source/pg/schema/shard.d.ts +50 -27
  291. package/out/zero-cache/src/services/change-source/pg/schema/shard.d.ts.map +1 -1
  292. package/out/zero-cache/src/services/change-source/pg/schema/shard.js +98 -34
  293. package/out/zero-cache/src/services/change-source/pg/schema/shard.js.map +1 -1
  294. package/out/zero-cache/src/services/change-source/protocol/backfill-progress.d.ts +68 -0
  295. package/out/zero-cache/src/services/change-source/protocol/backfill-progress.d.ts.map +1 -0
  296. package/out/zero-cache/src/services/change-source/protocol/backfill-progress.js +141 -0
  297. package/out/zero-cache/src/services/change-source/protocol/backfill-progress.js.map +1 -0
  298. package/out/zero-cache/src/services/change-source/protocol/current/data.d.ts +45 -2
  299. package/out/zero-cache/src/services/change-source/protocol/current/data.d.ts.map +1 -1
  300. package/out/zero-cache/src/services/change-source/protocol/current/data.js +10 -1
  301. package/out/zero-cache/src/services/change-source/protocol/current/data.js.map +1 -1
  302. package/out/zero-cache/src/services/change-source/protocol/current/downstream.d.ts +60 -3
  303. package/out/zero-cache/src/services/change-source/protocol/current/downstream.d.ts.map +1 -1
  304. package/out/zero-cache/src/services/change-source/protocol/current/upstream.d.ts +23 -10
  305. package/out/zero-cache/src/services/change-source/protocol/current/upstream.d.ts.map +1 -1
  306. package/out/zero-cache/src/services/change-source/protocol/current/upstream.js +17 -7
  307. package/out/zero-cache/src/services/change-source/protocol/current/upstream.js.map +1 -1
  308. package/out/zero-cache/src/services/change-source/protocol/current.js +2 -1
  309. package/out/zero-cache/src/services/change-streamer/backfill-state-tracker.d.ts +72 -0
  310. package/out/zero-cache/src/services/change-streamer/backfill-state-tracker.d.ts.map +1 -0
  311. package/out/zero-cache/src/services/change-streamer/backfill-state-tracker.js +162 -0
  312. package/out/zero-cache/src/services/change-streamer/backfill-state-tracker.js.map +1 -0
  313. package/out/zero-cache/src/services/change-streamer/backfill-state.d.ts +50 -0
  314. package/out/zero-cache/src/services/change-streamer/backfill-state.d.ts.map +1 -0
  315. package/out/zero-cache/src/services/change-streamer/backfill-state.js +268 -0
  316. package/out/zero-cache/src/services/change-streamer/backfill-state.js.map +1 -0
  317. package/out/zero-cache/src/services/change-streamer/backup-cleanup-monitor-factory.d.ts.map +1 -1
  318. package/out/zero-cache/src/services/change-streamer/backup-cleanup-monitor-factory.js +6 -17
  319. package/out/zero-cache/src/services/change-streamer/backup-cleanup-monitor-factory.js.map +1 -1
  320. package/out/zero-cache/src/services/change-streamer/backup-monitor.d.ts.map +1 -1
  321. package/out/zero-cache/src/services/change-streamer/backup-monitor.js +59 -8
  322. package/out/zero-cache/src/services/change-streamer/backup-monitor.js.map +1 -1
  323. package/out/zero-cache/src/services/change-streamer/broadcast.d.ts +8 -2
  324. package/out/zero-cache/src/services/change-streamer/broadcast.d.ts.map +1 -1
  325. package/out/zero-cache/src/services/change-streamer/broadcast.js +24 -4
  326. package/out/zero-cache/src/services/change-streamer/broadcast.js.map +1 -1
  327. package/out/zero-cache/src/services/change-streamer/change-log-codec.d.ts +19 -4
  328. package/out/zero-cache/src/services/change-streamer/change-log-codec.d.ts.map +1 -1
  329. package/out/zero-cache/src/services/change-streamer/change-log-codec.js +28 -8
  330. package/out/zero-cache/src/services/change-streamer/change-log-codec.js.map +1 -1
  331. package/out/zero-cache/src/services/change-streamer/change-log-initializer.d.ts +17 -0
  332. package/out/zero-cache/src/services/change-streamer/change-log-initializer.d.ts.map +1 -1
  333. package/out/zero-cache/src/services/change-streamer/change-log-initializer.js +44 -1
  334. package/out/zero-cache/src/services/change-streamer/change-log-initializer.js.map +1 -1
  335. package/out/zero-cache/src/services/change-streamer/change-streamer-http.d.ts +48 -6
  336. package/out/zero-cache/src/services/change-streamer/change-streamer-http.d.ts.map +1 -1
  337. package/out/zero-cache/src/services/change-streamer/change-streamer-http.js +131 -34
  338. package/out/zero-cache/src/services/change-streamer/change-streamer-http.js.map +1 -1
  339. package/out/zero-cache/src/services/change-streamer/change-streamer-service.d.ts +22 -0
  340. package/out/zero-cache/src/services/change-streamer/change-streamer-service.d.ts.map +1 -1
  341. package/out/zero-cache/src/services/change-streamer/change-streamer-service.js +149 -78
  342. package/out/zero-cache/src/services/change-streamer/change-streamer-service.js.map +1 -1
  343. package/out/zero-cache/src/services/change-streamer/change-streamer.d.ts +38 -16
  344. package/out/zero-cache/src/services/change-streamer/change-streamer.d.ts.map +1 -1
  345. package/out/zero-cache/src/services/change-streamer/change-streamer.js.map +1 -1
  346. package/out/zero-cache/src/services/change-streamer/forwarder.d.ts +3 -3
  347. package/out/zero-cache/src/services/change-streamer/forwarder.d.ts.map +1 -1
  348. package/out/zero-cache/src/services/change-streamer/forwarder.js +36 -5
  349. package/out/zero-cache/src/services/change-streamer/forwarder.js.map +1 -1
  350. package/out/zero-cache/src/services/change-streamer/litestream-sync-requester.d.ts +53 -0
  351. package/out/zero-cache/src/services/change-streamer/litestream-sync-requester.d.ts.map +1 -0
  352. package/out/zero-cache/src/services/change-streamer/litestream-sync-requester.js +156 -0
  353. package/out/zero-cache/src/services/change-streamer/litestream-sync-requester.js.map +1 -0
  354. package/out/zero-cache/src/services/change-streamer/schema/tables.d.ts +58 -1
  355. package/out/zero-cache/src/services/change-streamer/schema/tables.d.ts.map +1 -1
  356. package/out/zero-cache/src/services/change-streamer/schema/tables.js +107 -16
  357. package/out/zero-cache/src/services/change-streamer/schema/tables.js.map +1 -1
  358. package/out/zero-cache/src/services/change-streamer/snapshot-message.d.ts +92 -0
  359. package/out/zero-cache/src/services/change-streamer/snapshot-message.d.ts.map +1 -0
  360. package/out/zero-cache/src/services/change-streamer/snapshot-message.js +42 -0
  361. package/out/zero-cache/src/services/change-streamer/snapshot-message.js.map +1 -0
  362. package/out/zero-cache/src/services/change-streamer/snapshot-reservations.d.ts +1 -1
  363. package/out/zero-cache/src/services/change-streamer/snapshot-reservations.d.ts.map +1 -1
  364. package/out/zero-cache/src/services/change-streamer/snapshot-reservations.js +16 -4
  365. package/out/zero-cache/src/services/change-streamer/snapshot-reservations.js.map +1 -1
  366. package/out/zero-cache/src/services/change-streamer/snapshot.d.ts +7 -69
  367. package/out/zero-cache/src/services/change-streamer/snapshot.d.ts.map +1 -1
  368. package/out/zero-cache/src/services/change-streamer/snapshot.js +21 -53
  369. package/out/zero-cache/src/services/change-streamer/snapshot.js.map +1 -1
  370. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-writer.d.ts +6 -1
  371. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-writer.d.ts.map +1 -1
  372. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-writer.js +27 -9
  373. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-writer.js.map +1 -1
  374. package/out/zero-cache/src/services/change-streamer/storer.d.ts +95 -4
  375. package/out/zero-cache/src/services/change-streamer/storer.d.ts.map +1 -1
  376. package/out/zero-cache/src/services/change-streamer/storer.js +293 -83
  377. package/out/zero-cache/src/services/change-streamer/storer.js.map +1 -1
  378. package/out/zero-cache/src/services/change-streamer/subscribe.d.ts +446 -0
  379. package/out/zero-cache/src/services/change-streamer/subscribe.d.ts.map +1 -0
  380. package/out/zero-cache/src/services/change-streamer/subscribe.js +76 -0
  381. package/out/zero-cache/src/services/change-streamer/subscribe.js.map +1 -0
  382. package/out/zero-cache/src/services/change-streamer/subscriber.d.ts +58 -1
  383. package/out/zero-cache/src/services/change-streamer/subscriber.d.ts.map +1 -1
  384. package/out/zero-cache/src/services/change-streamer/subscriber.js +123 -12
  385. package/out/zero-cache/src/services/change-streamer/subscriber.js.map +1 -1
  386. package/out/zero-cache/src/services/change-streamer/upstream-acker.d.ts +19 -1
  387. package/out/zero-cache/src/services/change-streamer/upstream-acker.d.ts.map +1 -1
  388. package/out/zero-cache/src/services/change-streamer/upstream-acker.js +23 -3
  389. package/out/zero-cache/src/services/change-streamer/upstream-acker.js.map +1 -1
  390. package/out/zero-cache/src/services/http-service.d.ts +1 -1
  391. package/out/zero-cache/src/services/http-service.d.ts.map +1 -1
  392. package/out/zero-cache/src/services/http-service.js.map +1 -1
  393. package/out/zero-cache/src/services/life-cycle.d.ts.map +1 -1
  394. package/out/zero-cache/src/services/life-cycle.js +3 -1
  395. package/out/zero-cache/src/services/life-cycle.js.map +1 -1
  396. package/out/zero-cache/src/services/litestream/commands.d.ts +34 -3
  397. package/out/zero-cache/src/services/litestream/commands.d.ts.map +1 -1
  398. package/out/zero-cache/src/services/litestream/commands.js +121 -35
  399. package/out/zero-cache/src/services/litestream/commands.js.map +1 -1
  400. package/out/zero-cache/src/services/litestream/config-v5.yml +6 -7
  401. package/out/zero-cache/src/services/litestream/litestream-checkpointer.js +51 -24
  402. package/out/zero-cache/src/services/litestream/litestream-checkpointer.js.map +1 -1
  403. package/out/zero-cache/src/services/litestream/litestream-controller.d.ts +10 -2
  404. package/out/zero-cache/src/services/litestream/litestream-controller.d.ts.map +1 -1
  405. package/out/zero-cache/src/services/litestream/litestream-controller.js +3 -2
  406. package/out/zero-cache/src/services/litestream/litestream-controller.js.map +1 -1
  407. package/out/zero-cache/src/services/litestream/restore-progress.d.ts +24 -0
  408. package/out/zero-cache/src/services/litestream/restore-progress.d.ts.map +1 -0
  409. package/out/zero-cache/src/services/litestream/restore-progress.js +91 -0
  410. package/out/zero-cache/src/services/litestream/restore-progress.js.map +1 -0
  411. package/out/zero-cache/src/services/litestream/wal-keeper.d.ts +33 -0
  412. package/out/zero-cache/src/services/litestream/wal-keeper.d.ts.map +1 -0
  413. package/out/zero-cache/src/services/litestream/wal-keeper.js +49 -0
  414. package/out/zero-cache/src/services/litestream/wal-keeper.js.map +1 -0
  415. package/out/zero-cache/src/services/mutagen/mutagen.d.ts +5 -0
  416. package/out/zero-cache/src/services/mutagen/mutagen.d.ts.map +1 -1
  417. package/out/zero-cache/src/services/mutagen/mutagen.js +7 -1
  418. package/out/zero-cache/src/services/mutagen/mutagen.js.map +1 -1
  419. package/out/zero-cache/src/services/mutagen/pusher.d.ts.map +1 -1
  420. package/out/zero-cache/src/services/mutagen/pusher.js +5 -6
  421. package/out/zero-cache/src/services/mutagen/pusher.js.map +1 -1
  422. package/out/zero-cache/src/services/plannerz.d.ts +163 -0
  423. package/out/zero-cache/src/services/plannerz.d.ts.map +1 -0
  424. package/out/zero-cache/src/services/plannerz.js +267 -0
  425. package/out/zero-cache/src/services/plannerz.js.map +1 -0
  426. package/out/zero-cache/src/services/profz.d.ts +30 -0
  427. package/out/zero-cache/src/services/profz.d.ts.map +1 -0
  428. package/out/zero-cache/src/services/profz.js +163 -0
  429. package/out/zero-cache/src/services/profz.js.map +1 -0
  430. package/out/zero-cache/src/services/replicator/change-log-cookies.js +1 -1
  431. package/out/zero-cache/src/services/replicator/change-log-cookies.js.map +1 -1
  432. package/out/zero-cache/src/services/replicator/change-log-stream-writer.d.ts +5 -4
  433. package/out/zero-cache/src/services/replicator/change-log-stream-writer.d.ts.map +1 -1
  434. package/out/zero-cache/src/services/replicator/change-log-stream-writer.js +20 -22
  435. package/out/zero-cache/src/services/replicator/change-log-stream-writer.js.map +1 -1
  436. package/out/zero-cache/src/services/replicator/change-processor.d.ts.map +1 -1
  437. package/out/zero-cache/src/services/replicator/change-processor.js +51 -5
  438. package/out/zero-cache/src/services/replicator/change-processor.js.map +1 -1
  439. package/out/zero-cache/src/services/replicator/incremental-sync.d.ts +5 -2
  440. package/out/zero-cache/src/services/replicator/incremental-sync.d.ts.map +1 -1
  441. package/out/zero-cache/src/services/replicator/incremental-sync.js +54 -21
  442. package/out/zero-cache/src/services/replicator/incremental-sync.js.map +1 -1
  443. package/out/zero-cache/src/services/replicator/replication-status.d.ts +35 -1
  444. package/out/zero-cache/src/services/replicator/replication-status.d.ts.map +1 -1
  445. package/out/zero-cache/src/services/replicator/replication-status.js +99 -8
  446. package/out/zero-cache/src/services/replicator/replication-status.js.map +1 -1
  447. package/out/zero-cache/src/services/replicator/replicator.d.ts +4 -1
  448. package/out/zero-cache/src/services/replicator/replicator.d.ts.map +1 -1
  449. package/out/zero-cache/src/services/replicator/replicator.js +5 -2
  450. package/out/zero-cache/src/services/replicator/replicator.js.map +1 -1
  451. package/out/zero-cache/src/services/replicator/reporter/recorder.d.ts +16 -1
  452. package/out/zero-cache/src/services/replicator/reporter/recorder.d.ts.map +1 -1
  453. package/out/zero-cache/src/services/replicator/reporter/recorder.js +70 -27
  454. package/out/zero-cache/src/services/replicator/reporter/recorder.js.map +1 -1
  455. package/out/zero-cache/src/services/replicator/schema/backfilling.d.ts +23 -2
  456. package/out/zero-cache/src/services/replicator/schema/backfilling.d.ts.map +1 -1
  457. package/out/zero-cache/src/services/replicator/schema/backfilling.js +54 -2
  458. package/out/zero-cache/src/services/replicator/schema/backfilling.js.map +1 -1
  459. package/out/zero-cache/src/services/replicator/sqlite-change-log-observability.d.ts +6 -6
  460. package/out/zero-cache/src/services/replicator/sqlite-change-log-observability.d.ts.map +1 -1
  461. package/out/zero-cache/src/services/replicator/sqlite-change-log-observability.js +19 -14
  462. package/out/zero-cache/src/services/replicator/sqlite-change-log-observability.js.map +1 -1
  463. package/out/zero-cache/src/services/replicator/write-worker-client.d.ts +11 -3
  464. package/out/zero-cache/src/services/replicator/write-worker-client.d.ts.map +1 -1
  465. package/out/zero-cache/src/services/replicator/write-worker-client.js.map +1 -1
  466. package/out/zero-cache/src/services/replicator/write-worker.js +5 -1
  467. package/out/zero-cache/src/services/replicator/write-worker.js.map +1 -1
  468. package/out/zero-cache/src/services/run-ast.d.ts +12 -0
  469. package/out/zero-cache/src/services/run-ast.d.ts.map +1 -1
  470. package/out/zero-cache/src/services/run-ast.js +42 -22
  471. package/out/zero-cache/src/services/run-ast.js.map +1 -1
  472. package/out/zero-cache/src/services/runner.d.ts +2 -1
  473. package/out/zero-cache/src/services/runner.d.ts.map +1 -1
  474. package/out/zero-cache/src/services/runner.js +10 -2
  475. package/out/zero-cache/src/services/runner.js.map +1 -1
  476. package/out/zero-cache/src/services/statz.d.ts +4 -0
  477. package/out/zero-cache/src/services/statz.d.ts.map +1 -1
  478. package/out/zero-cache/src/services/statz.js +22 -5
  479. package/out/zero-cache/src/services/statz.js.map +1 -1
  480. package/out/zero-cache/src/services/view-syncer/advancement-metrics.d.ts +26 -0
  481. package/out/zero-cache/src/services/view-syncer/advancement-metrics.d.ts.map +1 -0
  482. package/out/zero-cache/src/services/view-syncer/advancement-metrics.js +26 -0
  483. package/out/zero-cache/src/services/view-syncer/advancement-metrics.js.map +1 -0
  484. package/out/zero-cache/src/services/view-syncer/client-handler.d.ts +19 -2
  485. package/out/zero-cache/src/services/view-syncer/client-handler.d.ts.map +1 -1
  486. package/out/zero-cache/src/services/view-syncer/client-handler.js +42 -30
  487. package/out/zero-cache/src/services/view-syncer/client-handler.js.map +1 -1
  488. package/out/zero-cache/src/services/view-syncer/connection-context-manager.d.ts +2 -1
  489. package/out/zero-cache/src/services/view-syncer/connection-context-manager.d.ts.map +1 -1
  490. package/out/zero-cache/src/services/view-syncer/connection-context-manager.js +1 -0
  491. package/out/zero-cache/src/services/view-syncer/connection-context-manager.js.map +1 -1
  492. package/out/zero-cache/src/services/view-syncer/cvr-store.d.ts +27 -2
  493. package/out/zero-cache/src/services/view-syncer/cvr-store.d.ts.map +1 -1
  494. package/out/zero-cache/src/services/view-syncer/cvr-store.js +85 -20
  495. package/out/zero-cache/src/services/view-syncer/cvr-store.js.map +1 -1
  496. package/out/zero-cache/src/services/view-syncer/cvr.d.ts +76 -11
  497. package/out/zero-cache/src/services/view-syncer/cvr.d.ts.map +1 -1
  498. package/out/zero-cache/src/services/view-syncer/cvr.js +214 -40
  499. package/out/zero-cache/src/services/view-syncer/cvr.js.map +1 -1
  500. package/out/zero-cache/src/services/view-syncer/deferred-writes-budget.d.ts +81 -0
  501. package/out/zero-cache/src/services/view-syncer/deferred-writes-budget.d.ts.map +1 -0
  502. package/out/zero-cache/src/services/view-syncer/deferred-writes-budget.js +128 -0
  503. package/out/zero-cache/src/services/view-syncer/deferred-writes-budget.js.map +1 -0
  504. package/out/zero-cache/src/services/view-syncer/drain-coordinator.d.ts +14 -1
  505. package/out/zero-cache/src/services/view-syncer/drain-coordinator.d.ts.map +1 -1
  506. package/out/zero-cache/src/services/view-syncer/drain-coordinator.js +30 -4
  507. package/out/zero-cache/src/services/view-syncer/drain-coordinator.js.map +1 -1
  508. package/out/zero-cache/src/services/view-syncer/hydration-budget.d.ts +33 -0
  509. package/out/zero-cache/src/services/view-syncer/hydration-budget.d.ts.map +1 -0
  510. package/out/zero-cache/src/services/view-syncer/hydration-budget.js +62 -0
  511. package/out/zero-cache/src/services/view-syncer/hydration-budget.js.map +1 -0
  512. package/out/zero-cache/src/services/view-syncer/hydration-circuit-breaker.d.ts +51 -0
  513. package/out/zero-cache/src/services/view-syncer/hydration-circuit-breaker.d.ts.map +1 -0
  514. package/out/zero-cache/src/services/view-syncer/hydration-circuit-breaker.js +78 -0
  515. package/out/zero-cache/src/services/view-syncer/hydration-circuit-breaker.js.map +1 -0
  516. package/out/zero-cache/src/services/view-syncer/inspect-handler.d.ts +10 -1
  517. package/out/zero-cache/src/services/view-syncer/inspect-handler.d.ts.map +1 -1
  518. package/out/zero-cache/src/services/view-syncer/inspect-handler.js +18 -4
  519. package/out/zero-cache/src/services/view-syncer/inspect-handler.js.map +1 -1
  520. package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts +80 -6
  521. package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts.map +1 -1
  522. package/out/zero-cache/src/services/view-syncer/pipeline-driver.js +658 -195
  523. package/out/zero-cache/src/services/view-syncer/pipeline-driver.js.map +1 -1
  524. package/out/zero-cache/src/services/view-syncer/plan-warnings.d.ts +7 -0
  525. package/out/zero-cache/src/services/view-syncer/plan-warnings.d.ts.map +1 -0
  526. package/out/zero-cache/src/services/view-syncer/plan-warnings.js +35 -0
  527. package/out/zero-cache/src/services/view-syncer/plan-warnings.js.map +1 -0
  528. package/out/zero-cache/src/services/view-syncer/query-covering.d.ts.map +1 -1
  529. package/out/zero-cache/src/services/view-syncer/query-covering.js +2 -6
  530. package/out/zero-cache/src/services/view-syncer/query-covering.js.map +1 -1
  531. package/out/zero-cache/src/services/view-syncer/query-shape.d.ts +25 -0
  532. package/out/zero-cache/src/services/view-syncer/query-shape.d.ts.map +1 -0
  533. package/out/zero-cache/src/services/view-syncer/query-shape.js +28 -0
  534. package/out/zero-cache/src/services/view-syncer/query-shape.js.map +1 -0
  535. package/out/zero-cache/src/services/view-syncer/query-stats.d.ts +82 -0
  536. package/out/zero-cache/src/services/view-syncer/query-stats.d.ts.map +1 -0
  537. package/out/zero-cache/src/services/view-syncer/query-stats.js +214 -0
  538. package/out/zero-cache/src/services/view-syncer/query-stats.js.map +1 -0
  539. package/out/zero-cache/src/services/view-syncer/schema/types.d.ts +2 -107
  540. package/out/zero-cache/src/services/view-syncer/schema/types.d.ts.map +1 -1
  541. package/out/zero-cache/src/services/view-syncer/schema/types.js +5 -20
  542. package/out/zero-cache/src/services/view-syncer/schema/types.js.map +1 -1
  543. package/out/zero-cache/src/services/view-syncer/snapshot-row-cache.d.ts +95 -0
  544. package/out/zero-cache/src/services/view-syncer/snapshot-row-cache.d.ts.map +1 -0
  545. package/out/zero-cache/src/services/view-syncer/snapshot-row-cache.js +155 -0
  546. package/out/zero-cache/src/services/view-syncer/snapshot-row-cache.js.map +1 -0
  547. package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts +96 -14
  548. package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts.map +1 -1
  549. package/out/zero-cache/src/services/view-syncer/snapshotter.js +214 -30
  550. package/out/zero-cache/src/services/view-syncer/snapshotter.js.map +1 -1
  551. package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts +11 -1
  552. package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts.map +1 -1
  553. package/out/zero-cache/src/services/view-syncer/view-syncer.js +566 -107
  554. package/out/zero-cache/src/services/view-syncer/view-syncer.js.map +1 -1
  555. package/out/zero-cache/src/types/pg-data-type.d.ts +2 -0
  556. package/out/zero-cache/src/types/pg-data-type.d.ts.map +1 -1
  557. package/out/zero-cache/src/types/pg-data-type.js +6 -1
  558. package/out/zero-cache/src/types/pg-data-type.js.map +1 -1
  559. package/out/zero-cache/src/types/pg.d.ts.map +1 -1
  560. package/out/zero-cache/src/types/pg.js +1 -1
  561. package/out/zero-cache/src/types/pg.js.map +1 -1
  562. package/out/zero-cache/src/types/processes.d.ts +39 -0
  563. package/out/zero-cache/src/types/processes.d.ts.map +1 -1
  564. package/out/zero-cache/src/types/processes.js +43 -4
  565. package/out/zero-cache/src/types/processes.js.map +1 -1
  566. package/out/zero-cache/src/types/profiler.d.ts +12 -0
  567. package/out/zero-cache/src/types/profiler.d.ts.map +1 -1
  568. package/out/zero-cache/src/types/profiler.js +46 -1
  569. package/out/zero-cache/src/types/profiler.js.map +1 -1
  570. package/out/zero-cache/src/types/row-key.d.ts +1 -15
  571. package/out/zero-cache/src/types/row-key.d.ts.map +1 -1
  572. package/out/zero-cache/src/types/row-key.js +6 -8
  573. package/out/zero-cache/src/types/row-key.js.map +1 -1
  574. package/out/zero-cache/src/types/streams.d.ts +49 -7
  575. package/out/zero-cache/src/types/streams.d.ts.map +1 -1
  576. package/out/zero-cache/src/types/streams.js +190 -58
  577. package/out/zero-cache/src/types/streams.js.map +1 -1
  578. package/out/zero-cache/src/types/subscription.d.ts +15 -0
  579. package/out/zero-cache/src/types/subscription.d.ts.map +1 -1
  580. package/out/zero-cache/src/types/subscription.js +123 -31
  581. package/out/zero-cache/src/types/subscription.js.map +1 -1
  582. package/out/zero-cache/src/types/websocket-handoff.d.ts +1 -1
  583. package/out/zero-cache/src/types/websocket-handoff.d.ts.map +1 -1
  584. package/out/zero-cache/src/types/websocket-handoff.js +18 -9
  585. package/out/zero-cache/src/types/websocket-handoff.js.map +1 -1
  586. package/out/zero-cache/src/types/ws.d.ts.map +1 -1
  587. package/out/zero-cache/src/types/ws.js +1 -16
  588. package/out/zero-cache/src/types/ws.js.map +1 -1
  589. package/out/zero-cache/src/workers/connect-params.d.ts +18 -1
  590. package/out/zero-cache/src/workers/connect-params.d.ts.map +1 -1
  591. package/out/zero-cache/src/workers/connect-params.js +25 -1
  592. package/out/zero-cache/src/workers/connect-params.js.map +1 -1
  593. package/out/zero-cache/src/workers/connection.d.ts +4 -4
  594. package/out/zero-cache/src/workers/connection.d.ts.map +1 -1
  595. package/out/zero-cache/src/workers/connection.js +8 -8
  596. package/out/zero-cache/src/workers/connection.js.map +1 -1
  597. package/out/zero-cache/src/workers/replicator.d.ts.map +1 -1
  598. package/out/zero-cache/src/workers/replicator.js +15 -7
  599. package/out/zero-cache/src/workers/replicator.js.map +1 -1
  600. package/out/zero-cache/src/workers/syncer-ws-message-handler.d.ts.map +1 -1
  601. package/out/zero-cache/src/workers/syncer-ws-message-handler.js +21 -16
  602. package/out/zero-cache/src/workers/syncer-ws-message-handler.js.map +1 -1
  603. package/out/zero-cache/src/workers/syncer.d.ts.map +1 -1
  604. package/out/zero-cache/src/workers/syncer.js +55 -4
  605. package/out/zero-cache/src/workers/syncer.js.map +1 -1
  606. package/out/zero-client/src/client/active-clients-manager.d.ts.map +1 -1
  607. package/out/zero-client/src/client/active-clients-manager.js +4 -1
  608. package/out/zero-client/src/client/active-clients-manager.js.map +1 -1
  609. package/out/zero-client/src/client/connection-manager.d.ts +20 -0
  610. package/out/zero-client/src/client/connection-manager.d.ts.map +1 -1
  611. package/out/zero-client/src/client/connection-manager.js +77 -13
  612. package/out/zero-client/src/client/connection-manager.js.map +1 -1
  613. package/out/zero-client/src/client/connection-status-enum.d.ts +2 -0
  614. package/out/zero-client/src/client/connection-status-enum.d.ts.map +1 -1
  615. package/out/zero-client/src/client/connection-status-enum.js +3 -1
  616. package/out/zero-client/src/client/connection-status-enum.js.map +1 -1
  617. package/out/zero-client/src/client/connection.d.ts +6 -0
  618. package/out/zero-client/src/client/connection.d.ts.map +1 -1
  619. package/out/zero-client/src/client/connection.js +2 -1
  620. package/out/zero-client/src/client/connection.js.map +1 -1
  621. package/out/zero-client/src/client/context.d.ts +23 -13
  622. package/out/zero-client/src/client/context.d.ts.map +1 -1
  623. package/out/zero-client/src/client/context.js +94 -26
  624. package/out/zero-client/src/client/context.js.map +1 -1
  625. package/out/zero-client/src/client/crud-impl.d.ts.map +1 -1
  626. package/out/zero-client/src/client/crud-impl.js +1 -1
  627. package/out/zero-client/src/client/crud-impl.js.map +1 -1
  628. package/out/zero-client/src/client/custom.d.ts +5 -4
  629. package/out/zero-client/src/client/custom.d.ts.map +1 -1
  630. package/out/zero-client/src/client/custom.js +3 -3
  631. package/out/zero-client/src/client/custom.js.map +1 -1
  632. package/out/zero-client/src/client/inspector/lazy-inspector.js +1 -1
  633. package/out/zero-client/src/client/ivm-branch.d.ts.map +1 -1
  634. package/out/zero-client/src/client/ivm-branch.js +20 -3
  635. package/out/zero-client/src/client/ivm-branch.js.map +1 -1
  636. package/out/zero-client/src/client/keys.d.ts.map +1 -1
  637. package/out/zero-client/src/client/keys.js +19 -1
  638. package/out/zero-client/src/client/keys.js.map +1 -1
  639. package/out/zero-client/src/client/make-mutate-property.d.ts +1 -1
  640. package/out/zero-client/src/client/make-mutate-property.d.ts.map +1 -1
  641. package/out/zero-client/src/client/make-mutate-property.js.map +1 -1
  642. package/out/zero-client/src/client/make-replicache-mutators.d.ts.map +1 -1
  643. package/out/zero-client/src/client/make-replicache-mutators.js +1 -1
  644. package/out/zero-client/src/client/make-replicache-mutators.js.map +1 -1
  645. package/out/zero-client/src/client/mutation-tracker.d.ts +2 -2
  646. package/out/zero-client/src/client/mutation-tracker.d.ts.map +1 -1
  647. package/out/zero-client/src/client/mutation-tracker.js +3 -7
  648. package/out/zero-client/src/client/mutation-tracker.js.map +1 -1
  649. package/out/zero-client/src/client/mutator-proxy.d.ts.map +1 -1
  650. package/out/zero-client/src/client/mutator-proxy.js +9 -4
  651. package/out/zero-client/src/client/mutator-proxy.js.map +1 -1
  652. package/out/zero-client/src/client/options.d.ts +33 -0
  653. package/out/zero-client/src/client/options.d.ts.map +1 -1
  654. package/out/zero-client/src/client/options.js.map +1 -1
  655. package/out/zero-client/src/client/query-manager.d.ts +9 -0
  656. package/out/zero-client/src/client/query-manager.d.ts.map +1 -1
  657. package/out/zero-client/src/client/query-manager.js +47 -14
  658. package/out/zero-client/src/client/query-manager.js.map +1 -1
  659. package/out/zero-client/src/client/reload-error-handler.js +2 -2
  660. package/out/zero-client/src/client/reload-error-handler.js.map +1 -1
  661. package/out/zero-client/src/client/version.js +1 -1
  662. package/out/zero-client/src/client/zero-rep.d.ts +1 -0
  663. package/out/zero-client/src/client/zero-rep.d.ts.map +1 -1
  664. package/out/zero-client/src/client/zero-rep.js +8 -6
  665. package/out/zero-client/src/client/zero-rep.js.map +1 -1
  666. package/out/zero-client/src/client/zero.d.ts +18 -3
  667. package/out/zero-client/src/client/zero.d.ts.map +1 -1
  668. package/out/zero-client/src/client/zero.js +89 -50
  669. package/out/zero-client/src/client/zero.js.map +1 -1
  670. package/out/zero-client/src/mod.d.ts +2 -1
  671. package/out/zero-client/src/mod.d.ts.map +1 -1
  672. package/out/zero-client/src/mod.js +1 -0
  673. package/out/zero-client/src/types/query-result.d.ts +2 -0
  674. package/out/zero-client/src/types/query-result.d.ts.map +1 -1
  675. package/out/zero-events/src/status.d.ts +64 -0
  676. package/out/zero-events/src/status.d.ts.map +1 -1
  677. package/out/zero-protocol/src/analyze-query-result.d.ts +5 -0
  678. package/out/zero-protocol/src/analyze-query-result.d.ts.map +1 -1
  679. package/out/zero-protocol/src/analyze-query-result.js.map +1 -1
  680. package/out/zero-protocol/src/ast.d.ts.map +1 -1
  681. package/out/zero-protocol/src/ast.js +13 -14
  682. package/out/zero-protocol/src/ast.js.map +1 -1
  683. package/out/zero-protocol/src/connect.d.ts +16 -0
  684. package/out/zero-protocol/src/connect.d.ts.map +1 -1
  685. package/out/zero-protocol/src/connect.js +27 -1
  686. package/out/zero-protocol/src/connect.js.map +1 -1
  687. package/out/zero-protocol/src/down.d.ts +31 -31
  688. package/out/zero-protocol/src/feature-flag-enum.d.ts +14 -0
  689. package/out/zero-protocol/src/feature-flag-enum.d.ts.map +1 -0
  690. package/out/zero-protocol/src/feature-flag-enum.js +10 -0
  691. package/out/zero-protocol/src/feature-flag-enum.js.map +1 -0
  692. package/out/zero-protocol/src/feature-flag.d.ts +5 -0
  693. package/out/zero-protocol/src/feature-flag.d.ts.map +1 -0
  694. package/out/zero-protocol/src/inspect-down.d.ts +16 -16
  695. package/out/zero-protocol/src/poke.d.ts +17 -10
  696. package/out/zero-protocol/src/poke.d.ts.map +1 -1
  697. package/out/zero-protocol/src/poke.js +3 -2
  698. package/out/zero-protocol/src/poke.js.map +1 -1
  699. package/out/zero-protocol/src/protocol-version.d.ts +30 -6
  700. package/out/zero-protocol/src/protocol-version.d.ts.map +1 -1
  701. package/out/zero-protocol/src/protocol-version.js +1 -1
  702. package/out/zero-protocol/src/protocol-version.js.map +1 -1
  703. package/out/zero-protocol/src/query-hash.d.ts.map +1 -1
  704. package/out/zero-protocol/src/query-hash.js +2 -5
  705. package/out/zero-protocol/src/query-hash.js.map +1 -1
  706. package/out/zero-react/src/use-query.d.ts +5 -4
  707. package/out/zero-react/src/use-query.d.ts.map +1 -1
  708. package/out/zero-react/src/use-query.js +74 -7
  709. package/out/zero-react/src/use-query.js.map +1 -1
  710. package/out/zero-react/src/zero.js +1 -0
  711. package/out/zero-server/src/adapters/drizzle.d.ts +2 -1
  712. package/out/zero-server/src/adapters/drizzle.d.ts.map +1 -1
  713. package/out/zero-server/src/adapters/drizzle.js +12 -7
  714. package/out/zero-server/src/adapters/drizzle.js.map +1 -1
  715. package/out/zero-server/src/adapters/kysely.d.ts +2 -1
  716. package/out/zero-server/src/adapters/kysely.d.ts.map +1 -1
  717. package/out/zero-server/src/adapters/kysely.js +8 -2
  718. package/out/zero-server/src/adapters/kysely.js.map +1 -1
  719. package/out/zero-server/src/adapters/pg.d.ts +5 -1
  720. package/out/zero-server/src/adapters/pg.d.ts.map +1 -1
  721. package/out/zero-server/src/adapters/pg.js +28 -7
  722. package/out/zero-server/src/adapters/pg.js.map +1 -1
  723. package/out/zero-server/src/adapters/postgresjs.d.ts +1 -0
  724. package/out/zero-server/src/adapters/postgresjs.d.ts.map +1 -1
  725. package/out/zero-server/src/adapters/postgresjs.js +7 -1
  726. package/out/zero-server/src/adapters/postgresjs.js.map +1 -1
  727. package/out/zero-server/src/adapters/prisma.d.ts +3 -2
  728. package/out/zero-server/src/adapters/prisma.d.ts.map +1 -1
  729. package/out/zero-server/src/adapters/prisma.js +8 -2
  730. package/out/zero-server/src/adapters/prisma.js.map +1 -1
  731. package/out/zero-server/src/closable-db-transaction.d.ts +16 -0
  732. package/out/zero-server/src/closable-db-transaction.d.ts.map +1 -0
  733. package/out/zero-server/src/closable-db-transaction.js +31 -0
  734. package/out/zero-server/src/closable-db-transaction.js.map +1 -0
  735. package/out/zero-server/src/custom.d.ts +10 -4
  736. package/out/zero-server/src/custom.d.ts.map +1 -1
  737. package/out/zero-server/src/custom.js +15 -6
  738. package/out/zero-server/src/custom.js.map +1 -1
  739. package/out/zero-server/src/logging.d.ts +2 -2
  740. package/out/zero-server/src/logging.d.ts.map +1 -1
  741. package/out/zero-server/src/logging.js +2 -2
  742. package/out/zero-server/src/logging.js.map +1 -1
  743. package/out/zero-server/src/mod.d.ts +1 -1
  744. package/out/zero-server/src/mod.d.ts.map +1 -1
  745. package/out/zero-server/src/pg-query-executor.d.ts +2 -2
  746. package/out/zero-server/src/pg-query-executor.d.ts.map +1 -1
  747. package/out/zero-server/src/pg-query-executor.js +2 -2
  748. package/out/zero-server/src/pg-query-executor.js.map +1 -1
  749. package/out/zero-server/src/process-mutations.d.ts +25 -4
  750. package/out/zero-server/src/process-mutations.d.ts.map +1 -1
  751. package/out/zero-server/src/process-mutations.js +103 -52
  752. package/out/zero-server/src/process-mutations.js.map +1 -1
  753. package/out/zero-server/src/push-processor.d.ts +8 -2
  754. package/out/zero-server/src/push-processor.d.ts.map +1 -1
  755. package/out/zero-server/src/push-processor.js +12 -4
  756. package/out/zero-server/src/push-processor.js.map +1 -1
  757. package/out/zero-server/src/schema.d.ts +2 -2
  758. package/out/zero-server/src/schema.d.ts.map +1 -1
  759. package/out/zero-server/src/schema.js +3 -2
  760. package/out/zero-server/src/schema.js.map +1 -1
  761. package/out/zero-server/src/zql-database.d.ts +21 -1
  762. package/out/zero-server/src/zql-database.d.ts.map +1 -1
  763. package/out/zero-server/src/zql-database.js +61 -24
  764. package/out/zero-server/src/zql-database.js.map +1 -1
  765. package/out/zero-solid/src/solid-view.d.ts +17 -0
  766. package/out/zero-solid/src/solid-view.d.ts.map +1 -1
  767. package/out/zero-solid/src/solid-view.js +39 -1
  768. package/out/zero-solid/src/solid-view.js.map +1 -1
  769. package/out/zero-solid/src/use-query.js +1 -2
  770. package/out/zero-solid/src/use-query.js.map +1 -1
  771. package/out/zero-solid/src/zero.js +1 -0
  772. package/out/zql/src/builder/builder.d.ts +25 -0
  773. package/out/zql/src/builder/builder.d.ts.map +1 -1
  774. package/out/zql/src/builder/builder.js +69 -19
  775. package/out/zql/src/builder/builder.js.map +1 -1
  776. package/out/zql/src/builder/correlated-predicate-pushdown.d.ts +43 -0
  777. package/out/zql/src/builder/correlated-predicate-pushdown.d.ts.map +1 -0
  778. package/out/zql/src/builder/correlated-predicate-pushdown.js +161 -0
  779. package/out/zql/src/builder/correlated-predicate-pushdown.js.map +1 -0
  780. package/out/zql/src/builder/debug-delegate.d.ts +6 -1
  781. package/out/zql/src/builder/debug-delegate.d.ts.map +1 -1
  782. package/out/zql/src/builder/debug-delegate.js +14 -2
  783. package/out/zql/src/builder/debug-delegate.js.map +1 -1
  784. package/out/zql/src/ivm/array-view.d.ts +29 -0
  785. package/out/zql/src/ivm/array-view.d.ts.map +1 -1
  786. package/out/zql/src/ivm/array-view.js +74 -16
  787. package/out/zql/src/ivm/array-view.js.map +1 -1
  788. package/out/zql/src/ivm/cap.d.ts +2 -1
  789. package/out/zql/src/ivm/cap.d.ts.map +1 -1
  790. package/out/zql/src/ivm/cap.js +14 -4
  791. package/out/zql/src/ivm/cap.js.map +1 -1
  792. package/out/zql/src/ivm/data.d.ts.map +1 -1
  793. package/out/zql/src/ivm/data.js +8 -3
  794. package/out/zql/src/ivm/data.js.map +1 -1
  795. package/out/zql/src/ivm/deferred-input.d.ts.map +1 -1
  796. package/out/zql/src/ivm/deferred-input.js +3 -2
  797. package/out/zql/src/ivm/deferred-input.js.map +1 -1
  798. package/out/zql/src/ivm/exists.d.ts +3 -1
  799. package/out/zql/src/ivm/exists.d.ts.map +1 -1
  800. package/out/zql/src/ivm/exists.js +4 -1
  801. package/out/zql/src/ivm/exists.js.map +1 -1
  802. package/out/zql/src/ivm/fan-in.d.ts +6 -2
  803. package/out/zql/src/ivm/fan-in.d.ts.map +1 -1
  804. package/out/zql/src/ivm/fan-in.js +13 -5
  805. package/out/zql/src/ivm/fan-in.js.map +1 -1
  806. package/out/zql/src/ivm/fan-out.d.ts +5 -2
  807. package/out/zql/src/ivm/fan-out.d.ts.map +1 -1
  808. package/out/zql/src/ivm/fan-out.js +4 -0
  809. package/out/zql/src/ivm/fan-out.js.map +1 -1
  810. package/out/zql/src/ivm/filter-operators.d.ts +8 -6
  811. package/out/zql/src/ivm/filter-operators.d.ts.map +1 -1
  812. package/out/zql/src/ivm/filter-operators.js +19 -8
  813. package/out/zql/src/ivm/filter-operators.js.map +1 -1
  814. package/out/zql/src/ivm/filter.d.ts +5 -2
  815. package/out/zql/src/ivm/filter.d.ts.map +1 -1
  816. package/out/zql/src/ivm/filter.js +10 -4
  817. package/out/zql/src/ivm/filter.js.map +1 -1
  818. package/out/zql/src/ivm/flipped-join.d.ts +9 -4
  819. package/out/zql/src/ivm/flipped-join.d.ts.map +1 -1
  820. package/out/zql/src/ivm/flipped-join.js +97 -46
  821. package/out/zql/src/ivm/flipped-join.js.map +1 -1
  822. package/out/zql/src/ivm/join-index-tap.d.ts +33 -0
  823. package/out/zql/src/ivm/join-index-tap.d.ts.map +1 -0
  824. package/out/zql/src/ivm/join-index-tap.js +70 -0
  825. package/out/zql/src/ivm/join-index-tap.js.map +1 -0
  826. package/out/zql/src/ivm/join-index.d.ts +35 -0
  827. package/out/zql/src/ivm/join-index.d.ts.map +1 -0
  828. package/out/zql/src/ivm/join-index.js +141 -0
  829. package/out/zql/src/ivm/join-index.js.map +1 -0
  830. package/out/zql/src/ivm/join-utils.d.ts +6 -0
  831. package/out/zql/src/ivm/join-utils.d.ts.map +1 -1
  832. package/out/zql/src/ivm/join-utils.js +22 -1
  833. package/out/zql/src/ivm/join-utils.js.map +1 -1
  834. package/out/zql/src/ivm/join.d.ts +19 -1
  835. package/out/zql/src/ivm/join.d.ts.map +1 -1
  836. package/out/zql/src/ivm/join.js +107 -15
  837. package/out/zql/src/ivm/join.js.map +1 -1
  838. package/out/zql/src/ivm/maybe-split-and-push-edit-change.d.ts +1 -1
  839. package/out/zql/src/ivm/maybe-split-and-push-edit-change.d.ts.map +1 -1
  840. package/out/zql/src/ivm/maybe-split-and-push-edit-change.js +6 -4
  841. package/out/zql/src/ivm/maybe-split-and-push-edit-change.js.map +1 -1
  842. package/out/zql/src/ivm/memory-source.d.ts +29 -4
  843. package/out/zql/src/ivm/memory-source.d.ts.map +1 -1
  844. package/out/zql/src/ivm/memory-source.js +70 -34
  845. package/out/zql/src/ivm/memory-source.js.map +1 -1
  846. package/out/zql/src/ivm/memory-storage.d.ts +1 -0
  847. package/out/zql/src/ivm/memory-storage.d.ts.map +1 -1
  848. package/out/zql/src/ivm/memory-storage.js +1 -0
  849. package/out/zql/src/ivm/memory-storage.js.map +1 -1
  850. package/out/zql/src/ivm/operator.d.ts +45 -10
  851. package/out/zql/src/ivm/operator.d.ts.map +1 -1
  852. package/out/zql/src/ivm/operator.js +9 -4
  853. package/out/zql/src/ivm/operator.js.map +1 -1
  854. package/out/zql/src/ivm/push-accumulated.d.ts +6 -1
  855. package/out/zql/src/ivm/push-accumulated.d.ts.map +1 -1
  856. package/out/zql/src/ivm/push-accumulated.js +47 -2
  857. package/out/zql/src/ivm/push-accumulated.js.map +1 -1
  858. package/out/zql/src/ivm/skip.d.ts +2 -1
  859. package/out/zql/src/ivm/skip.d.ts.map +1 -1
  860. package/out/zql/src/ivm/skip.js +3 -0
  861. package/out/zql/src/ivm/skip.js.map +1 -1
  862. package/out/zql/src/ivm/take-gate.d.ts +57 -0
  863. package/out/zql/src/ivm/take-gate.d.ts.map +1 -0
  864. package/out/zql/src/ivm/take-gate.js +106 -0
  865. package/out/zql/src/ivm/take-gate.js.map +1 -0
  866. package/out/zql/src/ivm/take.d.ts +8 -2
  867. package/out/zql/src/ivm/take.d.ts.map +1 -1
  868. package/out/zql/src/ivm/take.js +139 -103
  869. package/out/zql/src/ivm/take.js.map +1 -1
  870. package/out/zql/src/ivm/union-fan-in.d.ts +3 -0
  871. package/out/zql/src/ivm/union-fan-in.d.ts.map +1 -1
  872. package/out/zql/src/ivm/union-fan-in.js +63 -10
  873. package/out/zql/src/ivm/union-fan-in.js.map +1 -1
  874. package/out/zql/src/ivm/union-fan-out.d.ts +2 -1
  875. package/out/zql/src/ivm/union-fan-out.d.ts.map +1 -1
  876. package/out/zql/src/ivm/union-fan-out.js +5 -0
  877. package/out/zql/src/ivm/union-fan-out.js.map +1 -1
  878. package/out/zql/src/ivm/view-apply-change.d.ts.map +1 -1
  879. package/out/zql/src/ivm/view-apply-change.js +9 -4
  880. package/out/zql/src/ivm/view-apply-change.js.map +1 -1
  881. package/out/zql/src/ivm/view.d.ts +15 -0
  882. package/out/zql/src/ivm/view.d.ts.map +1 -1
  883. package/out/zql/src/mutate/custom.d.ts +53 -1
  884. package/out/zql/src/mutate/custom.d.ts.map +1 -1
  885. package/out/zql/src/mutate/custom.js.map +1 -1
  886. package/out/zql/src/mutate/mutator-registry.d.ts.map +1 -1
  887. package/out/zql/src/mutate/mutator-registry.js +3 -3
  888. package/out/zql/src/mutate/mutator-registry.js.map +1 -1
  889. package/out/zql/src/mutate/mutator.d.ts +2 -2
  890. package/out/zql/src/mutate/mutator.d.ts.map +1 -1
  891. package/out/zql/src/mutate/mutator.js.map +1 -1
  892. package/out/zql/src/planner/planner-builder.d.ts +23 -3
  893. package/out/zql/src/planner/planner-builder.d.ts.map +1 -1
  894. package/out/zql/src/planner/planner-builder.js +34 -17
  895. package/out/zql/src/planner/planner-builder.js.map +1 -1
  896. package/out/zql/src/planner/planner-connection.d.ts +58 -2
  897. package/out/zql/src/planner/planner-connection.d.ts.map +1 -1
  898. package/out/zql/src/planner/planner-connection.js +103 -11
  899. package/out/zql/src/planner/planner-connection.js.map +1 -1
  900. package/out/zql/src/planner/planner-debug.d.ts.map +1 -1
  901. package/out/zql/src/planner/planner-debug.js +3 -8
  902. package/out/zql/src/planner/planner-debug.js.map +1 -1
  903. package/out/zql/src/planner/planner-graph.d.ts +10 -0
  904. package/out/zql/src/planner/planner-graph.d.ts.map +1 -1
  905. package/out/zql/src/planner/planner-graph.js +14 -0
  906. package/out/zql/src/planner/planner-graph.js.map +1 -1
  907. package/out/zql/src/planner/planner-source.d.ts +2 -2
  908. package/out/zql/src/planner/planner-source.d.ts.map +1 -1
  909. package/out/zql/src/planner/planner-source.js +2 -2
  910. package/out/zql/src/planner/planner-source.js.map +1 -1
  911. package/out/zql/src/planner/planner-warnings.d.ts +83 -0
  912. package/out/zql/src/planner/planner-warnings.d.ts.map +1 -0
  913. package/out/zql/src/planner/planner-warnings.js +78 -0
  914. package/out/zql/src/planner/planner-warnings.js.map +1 -0
  915. package/out/zql/src/query/measure-push-operator.d.ts +9 -2
  916. package/out/zql/src/query/measure-push-operator.d.ts.map +1 -1
  917. package/out/zql/src/query/measure-push-operator.js +52 -5
  918. package/out/zql/src/query/measure-push-operator.js.map +1 -1
  919. package/out/zql/src/query/query-delegate-base.d.ts +4 -2
  920. package/out/zql/src/query/query-delegate-base.d.ts.map +1 -1
  921. package/out/zql/src/query/query-delegate-base.js +66 -33
  922. package/out/zql/src/query/query-delegate-base.js.map +1 -1
  923. package/out/zql/src/query/query-delegate.d.ts +33 -6
  924. package/out/zql/src/query/query-delegate.d.ts.map +1 -1
  925. package/out/zql/src/query/query-impl.d.ts +1 -0
  926. package/out/zql/src/query/query-impl.d.ts.map +1 -1
  927. package/out/zql/src/query/query-impl.js +6 -23
  928. package/out/zql/src/query/query-impl.js.map +1 -1
  929. package/out/zql/src/query/query-transitions.d.ts.map +1 -1
  930. package/out/zql/src/query/query-transitions.js +2 -5
  931. package/out/zql/src/query/query-transitions.js.map +1 -1
  932. package/out/zql/src/query/query.d.ts +22 -5
  933. package/out/zql/src/query/query.d.ts.map +1 -1
  934. package/out/zql/src/query/runnable-query-impl.d.ts +1 -0
  935. package/out/zql/src/query/runnable-query-impl.d.ts.map +1 -1
  936. package/out/zql/src/query/runnable-query-impl.js +2 -10
  937. package/out/zql/src/query/runnable-query-impl.js.map +1 -1
  938. package/out/zql/src/query/typed-view.d.ts +1 -1
  939. package/out/zql/src/query/typed-view.d.ts.map +1 -1
  940. package/out/zqlite/src/database-storage.d.ts.map +1 -1
  941. package/out/zqlite/src/database-storage.js +9 -1
  942. package/out/zqlite/src/database-storage.js.map +1 -1
  943. package/out/zqlite/src/db.d.ts +9 -1
  944. package/out/zqlite/src/db.d.ts.map +1 -1
  945. package/out/zqlite/src/db.js +62 -30
  946. package/out/zqlite/src/db.js.map +1 -1
  947. package/out/zqlite/src/index-usage.d.ts +19 -0
  948. package/out/zqlite/src/index-usage.d.ts.map +1 -0
  949. package/out/zqlite/src/index-usage.js +49 -0
  950. package/out/zqlite/src/index-usage.js.map +1 -0
  951. package/out/zqlite/src/pending-delta.d.ts +110 -0
  952. package/out/zqlite/src/pending-delta.d.ts.map +1 -0
  953. package/out/zqlite/src/pending-delta.js +278 -0
  954. package/out/zqlite/src/pending-delta.js.map +1 -0
  955. package/out/zqlite/src/query-builder.d.ts +17 -1
  956. package/out/zqlite/src/query-builder.d.ts.map +1 -1
  957. package/out/zqlite/src/query-builder.js +111 -20
  958. package/out/zqlite/src/query-builder.js.map +1 -1
  959. package/out/zqlite/src/query-delegate.d.ts.map +1 -1
  960. package/out/zqlite/src/query-delegate.js +10 -7
  961. package/out/zqlite/src/query-delegate.js.map +1 -1
  962. package/out/zqlite/src/resolve-scalar-subqueries.d.ts +3 -1
  963. package/out/zqlite/src/resolve-scalar-subqueries.d.ts.map +1 -1
  964. package/out/zqlite/src/resolve-scalar-subqueries.js +1 -0
  965. package/out/zqlite/src/resolve-scalar-subqueries.js.map +1 -1
  966. package/out/zqlite/src/sqlite-cost-model.d.ts.map +1 -1
  967. package/out/zqlite/src/sqlite-cost-model.js +52 -1
  968. package/out/zqlite/src/sqlite-cost-model.js.map +1 -1
  969. package/out/zqlite/src/sqlite-stat-fanout.d.ts.map +1 -1
  970. package/out/zqlite/src/sqlite-stat-fanout.js +5 -31
  971. package/out/zqlite/src/sqlite-stat-fanout.js.map +1 -1
  972. package/out/zqlite/src/sqlite-stat4-sample.d.ts +37 -0
  973. package/out/zqlite/src/sqlite-stat4-sample.d.ts.map +1 -0
  974. package/out/zqlite/src/sqlite-stat4-sample.js +61 -0
  975. package/out/zqlite/src/sqlite-stat4-sample.js.map +1 -0
  976. package/out/zqlite/src/table-source.d.ts +87 -2
  977. package/out/zqlite/src/table-source.d.ts.map +1 -1
  978. package/out/zqlite/src/table-source.js +276 -42
  979. package/out/zqlite/src/table-source.js.map +1 -1
  980. package/package.json +4 -5
  981. package/out/replicache/src/kv/idb-store-with-mem-fallback.d.ts +0 -25
  982. package/out/replicache/src/kv/idb-store-with-mem-fallback.d.ts.map +0 -1
  983. package/out/replicache/src/kv/idb-store-with-mem-fallback.js +0 -83
  984. package/out/replicache/src/kv/idb-store-with-mem-fallback.js.map +0 -1
  985. package/out/zero-cache/src/services/change-streamer/vfs-watermark-poller.d.ts +0 -29
  986. package/out/zero-cache/src/services/change-streamer/vfs-watermark-poller.d.ts.map +0 -1
  987. package/out/zero-cache/src/services/change-streamer/vfs-watermark-poller.js +0 -154
  988. package/out/zero-cache/src/services/change-streamer/vfs-watermark-poller.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"connection.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/workers/connection.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"connection.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/workers/connection.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,UAAU,EAAW,MAAM,kBAAkB,CAAC;AAE3D,OAAO,SAAkC,MAAM,IAAI,CAAC;AAIpD,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,oCAAoC,CAAC;AAGnE,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,qCAAqC,CAAC;AACnE,OAAO,EAEL,KAAK,aAAa,EACnB,MAAM,qCAAqC,CAAC;AAE7C,OAAO,EACL,KAAK,SAAS,EAGf,MAAM,oCAAoC,CAAC;AAK5C,OAAO,EAEL,KAAK,gCAAgC,EACtC,MAAM,kCAAkC,CAAC;AAE1C,OAAO,KAAK,EAAC,oBAAoB,EAAC,MAAM,wBAAwB,CAAC;AAOjE,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,qBAAqB,CAAC;AAChD,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,qBAAqB,CAAC;AAEvD,MAAM,MAAM,aAAa,GACrB;IACE,IAAI,EAAE,IAAI,CAAC;CACZ,GACD;IACE,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,SAAS,CAAC;CAClB,GACD;IACE,IAAI,EAAE,WAAW,CAAC;IAClB,MAAM,EAAE,SAAS,EAAE,CAAC;CACrB,GACD,YAAY,CAAC;AAEjB,MAAM,MAAM,YAAY,GACpB;IACE,IAAI,EAAE,QAAQ,CAAC;IACf,MAAM,EAAE,YAAY,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC,oBAAoB,CAAC,CAAC;CACtC,GACD;IACE,IAAI,EAAE,QAAQ,CAAC;IACf,MAAM,EAAE,QAAQ,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC;CAC5B,CAAC;AAEN,MAAM,WAAW,cAAc;IAC7B,aAAa,CACX,GAAG,EAAE,gCAAgC,GACpC,OAAO,CAAC,aAAa,EAAE,CAAC,CAAC;CAC7B;AAqCD,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,OAAO,EACd,kBAAkB,EAAE,OAAO,GAC1B,gCAAgC,CAKlC;AAcD,eAAO,MAAM,yBAAyB,QAAS,CAAC;AAIhD;;;;;;;GAOG;AACH,qBAAa,UAAU;;IAoBrB,YACE,EAAE,EAAE,UAAU,EACd,aAAa,EAAE,aAAa,EAC5B,EAAE,EAAE,SAAS,EACb,kBAAkB,EAAE,OAAO,EAC3B,cAAc,EAAE,cAAc,EAC9B,OAAO,EAAE,MAAM,IAAI,EA+BpB;IAED;;;;;;OAMG;IACH,IAAI,IAAI,OAAO,CAuBd;IAED,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,QAoBvC;IAED,oBAAoB,CAAC,iBAAiB,EAAE,MAAM,iBAE7C;IA0KD,IAAI,CACF,IAAI,EAAE,UAAU,EAChB,QAAQ,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,KAAK,GAAG,IAAI,KAAK,IAAI,CAAC,GAAG,qBAAqB,EAChE,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,QAIhC;IAED,SAAS,CAAC,SAAS,EAAE,SAAS,EAAE,MAAM,CAAC,EAAE,OAAO,QAE/C;CACF;AAED,MAAM,MAAM,aAAa,GAAG,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG;IAC1D,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,EAAE,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK,KAAK,IAAI,GAAG,IAAI,CAAC;CAClE,CAAC;AAGF,wBAAgB,IAAI,CAClB,EAAE,EAAE,UAAU,EACd,EAAE,EAAE,aAAa,EACjB,IAAI,EAAE,UAAU,EAChB,QAAQ,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,KAAK,GAAG,IAAI,KAAK,IAAI,CAAC,GAAG,qBAAqB,EAChE,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,QA0ChC;AAED;;;;;;GAMG;AACH,qBAAa,gBAAgB;;IAM3B,YAAY,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE,aAAa,EAAE,UAAU,EAAE,OAAO,EAIjE;IAED,IAAI,CACF,IAAI,EAAE,UAAU,EAChB,QAAQ,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,KAAK,GAAG,IAAI,KAAK,IAAI,CAAC,GAAG,qBAAqB,EAChE,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,GAC9B,IAAI,CAmBN;CA+CF;AAmFD,wBAAgB,SAAS,CACvB,EAAE,EAAE,UAAU,EACd,EAAE,EAAE,SAAS,EACb,SAAS,EAAE,SAAS,EACpB,MAAM,CAAC,EAAE,OAAO,QA+BjB;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,aAAa,GAAG,SAAS,CAQ3E"}
@@ -62,7 +62,7 @@ var Connection = class {
62
62
  this.#wsID = wsID;
63
63
  this.#protocolVersion = protocolVersion;
64
64
  this.#lc = lc.withContext("connection").withContext("clientID", clientID).withContext("clientGroupID", clientGroupID).withContext("wsID", wsID);
65
- this.#downstreamSender = new DownstreamSender(this.#lc, ws, protocolVersion);
65
+ this.#downstreamSender = new DownstreamSender(this.#lc, ws, connectParams.features.has(0));
66
66
  this.#lc.debug?.("new connection");
67
67
  this.#onClose = onClose;
68
68
  this.#ws.addEventListener("close", this.#handleClose);
@@ -244,24 +244,24 @@ function send(lc, ws, data, callback, serialized) {
244
244
  }
245
245
  }
246
246
  /**
247
- * Sends downstream messages in the format supported by a connection's sync
248
- * protocol version. Keep version forks contained here so the view-syncer can
249
- * continue producing one canonical poke representation.
247
+ * Sends downstream messages in the format the client supports. Keep format
248
+ * forks contained here so the view-syncer can continue producing one
249
+ * canonical poke representation.
250
250
  *
251
251
  * Exported for compatibility testing.
252
252
  */
253
253
  var DownstreamSender = class {
254
254
  #lc;
255
255
  #ws;
256
- #protocolVersion;
256
+ #pokeChunks;
257
257
  #pokeChunkEncoder;
258
- constructor(lc, ws, protocolVersion) {
258
+ constructor(lc, ws, pokeChunks) {
259
259
  this.#lc = lc;
260
260
  this.#ws = ws;
261
- this.#protocolVersion = protocolVersion;
261
+ this.#pokeChunks = pokeChunks;
262
262
  }
263
263
  send(data, callback, serialized) {
264
- if (this.#protocolVersion >= 52) switch (data[0]) {
264
+ if (this.#pokeChunks) switch (data[0]) {
265
265
  case "pokeStart":
266
266
  assert(this.#pokeChunkEncoder === void 0, "cannot start a poke while another poke is in progress");
267
267
  this.#pokeChunkEncoder = new PokeChunkEncoder();
@@ -1 +1 @@
1
- {"version":3,"file":"connection.js","names":["#ws","#wsID","#protocolVersion","#lc","#onClose","#messageHandler","#allowLegacyQueries","#downstreamSender","#downstreamMsgTimer","#webSocketErrors","#handleClose","#handleError","#proxyInbound","#maybeSendPong","#closeWithError","#closed","#viewSyncerOutboundStream","#pusherOutboundStream","#handleMessage","#handleMessageResult","#closeWithThrown","#proxyOutbound","#recordWebSocketError","#lastDownstreamMsgTime","#pokeChunkEncoder","#sendPokePart","#sendPokeEnd"],"sources":["../../../../../zero-cache/src/workers/connection.ts"],"sourcesContent":["import {pipeline, Readable, Writable} from 'node:stream';\nimport type {LogContext, LogLevel} from '@rocicorp/logger';\nimport type {CloseEvent, Data, ErrorEvent} from 'ws';\nimport WebSocket, {createWebSocketStream} from 'ws';\nimport {assert} from '../../../shared/src/asserts.ts';\nimport * as valita from '../../../shared/src/valita.ts';\nimport type {ConnectedMessage} from '../../../zero-protocol/src/connect.ts';\nimport type {Downstream} from '../../../zero-protocol/src/down.ts';\nimport {ErrorKind} from '../../../zero-protocol/src/error-kind.ts';\nimport {ErrorOrigin} from '../../../zero-protocol/src/error-origin.ts';\nimport type {ErrorBody} from '../../../zero-protocol/src/error.ts';\nimport {\n isProtocolError,\n type ProtocolError,\n} from '../../../zero-protocol/src/error.ts';\nimport {\n POKE_CHUNK_PROTOCOL_VERSION,\n type PokeChunk,\n type PokeEndMessage,\n type PokePartMessage,\n} from '../../../zero-protocol/src/poke.ts';\nimport {\n MIN_SERVER_SUPPORTED_SYNC_PROTOCOL,\n PROTOCOL_VERSION,\n} from '../../../zero-protocol/src/protocol-version.ts';\nimport {\n upstreamSchemaWithUnparsedAnalyzeQuery,\n type UpstreamWithUnparsedAnalyzeQuery,\n} from '../../../zero-protocol/src/up.ts';\nimport {getOrCreateCounter} from '../observability/metrics.ts';\nimport type {ViewSyncerDownstream} from '../types/downstream.ts';\nimport {\n ProtocolErrorWithLevel,\n getLogLevel,\n wrapWithProtocolError,\n} from '../types/error-with-level.ts';\nimport {PokeChunkEncoder} from '../types/poke-chunk.ts';\nimport type {Source} from '../types/streams.ts';\nimport type {ConnectParams} from './connect-params.ts';\n\nexport type HandlerResult =\n | {\n type: 'ok';\n }\n | {\n type: 'fatal';\n error: ErrorBody;\n }\n | {\n type: 'transient';\n errors: ErrorBody[];\n }\n | StreamResult;\n\nexport type StreamResult =\n | {\n type: 'stream';\n source: 'viewSyncer';\n stream: Source<ViewSyncerDownstream>;\n }\n | {\n type: 'stream';\n source: 'pusher';\n stream: Source<Downstream>;\n };\n\nexport interface MessageHandler {\n handleMessage(\n msg: UpstreamWithUnparsedAnalyzeQuery,\n ): Promise<HandlerResult[]>;\n}\n\nfunction hasOwn(value: unknown, property: string): boolean {\n return (\n typeof value === 'object' &&\n value !== null &&\n Object.hasOwn(value, property)\n );\n}\n\nfunction containsLegacyQuery(message: unknown): boolean {\n if (!Array.isArray(message)) {\n return false;\n }\n\n const body = message[1];\n if (typeof body !== 'object' || body === null) {\n return false;\n }\n\n if (\n message[0] !== 'initConnection' &&\n message[0] !== 'changeDesiredQueries'\n ) {\n return false;\n }\n\n const patch = body['desiredQueriesPatch'];\n return (\n Array.isArray(patch) && patch.some(operation => hasOwn(operation, 'ast'))\n );\n}\n\nconst LEGACY_QUERIES_DISABLED_MESSAGE =\n 'Legacy queries are disabled by this Zero server. This client must use custom queries instead of sending query ASTs directly. To temporarily restore compatibility, set ZERO_ALLOW_LEGACY_QUERIES=true on zero-cache.';\n\n// Exported for testing purposes.\nexport function parseUpstreamMessage(\n value: unknown,\n allowLegacyQueries: boolean,\n): UpstreamWithUnparsedAnalyzeQuery {\n if (!allowLegacyQueries && containsLegacyQuery(value)) {\n throw new Error(LEGACY_QUERIES_DISABLED_MESSAGE);\n }\n return valita.parse(value, upstreamSchemaWithUnparsedAnalyzeQuery);\n}\n\n// Ensures that a downstream message is sent at least every interval, sending a\n// 'pong' if necessary. This is set to be slightly longer than the client-side\n// PING_INTERVAL of 5 seconds, so that in the common case, 'pong's are sent in\n// response to client-initiated 'ping's. However, if the inbound stream is\n// backed up because a command is taking a long time to process, the pings\n// will be stuck in the queue (i.e. back-pressured), in which case pongs will\n// be manually sent to notify the client of server liveness.\n//\n// This is equivalent to what is done for Postgres keepalives on the\n// replication stream (which can similarly be back-pressured):\n// https://github.com/rocicorp/mono/blob/f98cb369a2dbb15650328859c732db358f187ef0/packages/zero-cache/src/services/change-source/pg/logical-replication/stream.ts#L21\nconst DOWNSTREAM_MSG_INTERVAL_MS = 6_000;\nexport const WEBSOCKET_SEND_TIMEOUT_MS = 10_000;\nconst PROTOCOL_VERSION_ATTRIBUTE = 'protocol.version';\nconst EVENT_TYPE_ATTRIBUTE = 'event.type';\n\n/**\n * Represents a connection between the client and server.\n *\n * Handles incoming messages on the connection and dispatches\n * them to the correct service.\n *\n * Listens to the ViewSyncer and sends messages to the client.\n */\nexport class Connection {\n readonly #ws: WebSocket;\n readonly #wsID: string;\n readonly #protocolVersion: number;\n readonly #lc: LogContext;\n readonly #onClose: () => void;\n readonly #messageHandler: MessageHandler;\n readonly #allowLegacyQueries: boolean;\n readonly #downstreamSender: DownstreamSender;\n readonly #downstreamMsgTimer: NodeJS.Timeout | undefined;\n readonly #webSocketErrors = getOrCreateCounter(\n 'sync',\n 'websocket.errors',\n 'Client WebSocket error events.',\n );\n\n #viewSyncerOutboundStream: Source<ViewSyncerDownstream> | undefined;\n #pusherOutboundStream: Source<Downstream> | undefined;\n #closed = false;\n\n constructor(\n lc: LogContext,\n connectParams: ConnectParams,\n ws: WebSocket,\n allowLegacyQueries: boolean,\n messageHandler: MessageHandler,\n onClose: () => void,\n ) {\n const {clientGroupID, clientID, wsID, protocolVersion} = connectParams;\n this.#messageHandler = messageHandler;\n this.#allowLegacyQueries = allowLegacyQueries;\n\n this.#ws = ws;\n this.#wsID = wsID;\n this.#protocolVersion = protocolVersion;\n\n this.#lc = lc\n .withContext('connection')\n .withContext('clientID', clientID)\n .withContext('clientGroupID', clientGroupID)\n .withContext('wsID', wsID);\n this.#downstreamSender = new DownstreamSender(\n this.#lc,\n ws,\n protocolVersion,\n );\n this.#lc.debug?.('new connection');\n this.#onClose = onClose;\n\n this.#ws.addEventListener('close', this.#handleClose);\n this.#ws.addEventListener('error', this.#handleError);\n\n this.#proxyInbound();\n this.#downstreamMsgTimer = setInterval(\n this.#maybeSendPong,\n DOWNSTREAM_MSG_INTERVAL_MS / 2,\n );\n }\n\n /**\n * Checks the protocol version and errors for unsupported protocols,\n * sending the initial `connected` response on success.\n *\n * This is early in the connection lifecycle because {@link #handleMessage}\n * will only parse messages with schema(s) of supported protocol versions.\n */\n init(): boolean {\n if (\n this.#protocolVersion > PROTOCOL_VERSION ||\n this.#protocolVersion < MIN_SERVER_SUPPORTED_SYNC_PROTOCOL\n ) {\n this.#closeWithError({\n kind: ErrorKind.VersionNotSupported,\n message: `server is at sync protocol v${PROTOCOL_VERSION} and does not support v${\n this.#protocolVersion\n }. The ${\n this.#protocolVersion > PROTOCOL_VERSION ? 'server' : 'client'\n } must be updated to a newer release.`,\n origin: ErrorOrigin.ZeroCache,\n });\n } else {\n const connectedMessage: ConnectedMessage = [\n 'connected',\n {wsid: this.#wsID, timestamp: Date.now()},\n ];\n this.send(connectedMessage, 'ignore-backpressure');\n return true;\n }\n return false;\n }\n\n close(reason: string, ...args: unknown[]) {\n if (this.#closed) {\n return;\n }\n this.#closed = true;\n this.#lc.info?.(`closing connection: ${reason}`, ...args);\n this.#ws.removeEventListener('close', this.#handleClose);\n this.#ws.removeEventListener('error', this.#handleError);\n this.#viewSyncerOutboundStream?.cancel();\n this.#viewSyncerOutboundStream = undefined;\n this.#pusherOutboundStream?.cancel();\n this.#pusherOutboundStream = undefined;\n this.#onClose();\n if (this.#ws.readyState !== this.#ws.CLOSED) {\n this.#ws.close();\n }\n clearTimeout(this.#downstreamMsgTimer);\n\n // spin down services if we have\n // no more client connections for the client group?\n }\n\n handleInitConnection(initConnectionMsg: string) {\n return this.#handleMessage({data: initConnectionMsg});\n }\n\n #handleMessage = async (event: {data: Data}) => {\n const data = event.data.toString();\n if (this.#closed) {\n this.#lc.debug?.('Ignoring message received after closed', data);\n return;\n }\n\n let msg;\n try {\n const value = JSON.parse(data);\n msg = parseUpstreamMessage(value, this.#allowLegacyQueries);\n } catch (e) {\n const errorBody = {\n kind: ErrorKind.InvalidMessage,\n message: String(e),\n origin: ErrorOrigin.ZeroCache,\n } as const;\n this.#closeWithError(\n errorBody,\n new ProtocolErrorWithLevel(errorBody, 'warn'),\n );\n return;\n }\n\n try {\n const msgType = msg[0];\n if (msgType === 'ping') {\n this.send(['pong', {}], 'ignore-backpressure');\n return;\n }\n\n const result = await this.#messageHandler.handleMessage(msg);\n for (const r of result) {\n this.#handleMessageResult(r);\n }\n } catch (e) {\n this.#closeWithThrown(e);\n }\n };\n\n #handleMessageResult(result: HandlerResult): void {\n switch (result.type) {\n case 'fatal':\n this.#closeWithError(result.error);\n break;\n case 'ok':\n break;\n case 'stream': {\n switch (result.source) {\n case 'viewSyncer':\n assert(\n this.#viewSyncerOutboundStream === undefined,\n 'Outbound stream already set for this connection!',\n );\n this.#viewSyncerOutboundStream = result.stream;\n break;\n case 'pusher':\n assert(\n this.#pusherOutboundStream === undefined,\n 'Outbound stream already set for this connection!',\n );\n this.#pusherOutboundStream = result.stream;\n break;\n }\n if (result.source === 'viewSyncer') {\n this.#proxyOutbound(result.stream, (downstream, callback) =>\n this.send(downstream.message, callback, downstream.serialized),\n );\n } else {\n this.#proxyOutbound(result.stream, (downstream, callback) =>\n this.send(downstream, callback),\n );\n }\n break;\n }\n case 'transient': {\n for (const error of result.errors) {\n this.sendError(error);\n }\n }\n }\n }\n\n #handleClose = (e: CloseEvent) => {\n const {code, reason, wasClean} = e;\n if (!wasClean) {\n this.#recordWebSocketError('unclean_close');\n }\n this.close('WebSocket close event', {code, reason, wasClean});\n };\n\n #handleError = (e: ErrorEvent) => {\n this.#recordWebSocketError('error_event');\n this.#lc.warn?.('WebSocket error event', e.message, e.error);\n };\n\n #recordWebSocketError(eventType: string) {\n this.#webSocketErrors.add(1, {\n [PROTOCOL_VERSION_ATTRIBUTE]: this.#protocolVersion,\n [EVENT_TYPE_ATTRIBUTE]: eventType,\n });\n }\n\n #proxyInbound() {\n pipeline(\n createWebSocketStream(this.#ws),\n new Writable({\n write: (data, _encoding, callback) => {\n this.#handleMessage({data}).then(() => callback(), callback);\n },\n }),\n // The done callback is not used, as #handleClose and #handleError,\n // configured on the underlying WebSocket, provide more complete\n // information.\n () => {},\n );\n }\n\n #proxyOutbound<T>(\n outboundStream: Source<T>,\n sendMessage: (\n downstream: T,\n callback: (err?: Error | null) => void,\n ) => void,\n ) {\n // Note: createWebSocketStream() is avoided here in order to control\n // exception handling with #closeWithThrown(). If the Writable\n // from createWebSocketStream() were instead used, exceptions\n // from the outboundStream result in the Writable closing the\n // the websocket before the error message can be sent.\n pipeline(\n Readable.from(outboundStream),\n new Writable({\n objectMode: true,\n write: (downstream: T, _encoding, callback) =>\n sendMessage(downstream, callback),\n }),\n e =>\n e\n ? this.#closeWithThrown(e)\n : this.close(`downstream closed by ViewSyncer`),\n );\n }\n\n #closeWithThrown(e: unknown) {\n const errorBody =\n findProtocolError(e)?.errorBody ?? wrapWithProtocolError(e).errorBody;\n\n this.#closeWithError(errorBody, e);\n }\n\n #closeWithError(errorBody: ErrorBody, thrown?: unknown) {\n this.sendError(errorBody, thrown);\n this.close(\n `${errorBody.kind} (${errorBody.origin}): ${errorBody.message}`,\n errorBody,\n );\n }\n\n #lastDownstreamMsgTime = Date.now();\n\n #maybeSendPong = () => {\n if (Date.now() - this.#lastDownstreamMsgTime > DOWNSTREAM_MSG_INTERVAL_MS) {\n this.#lc.debug?.('manually sending pong');\n this.send(['pong', {}], 'ignore-backpressure');\n }\n };\n\n send(\n data: Downstream,\n callback: ((err?: Error | null) => void) | 'ignore-backpressure',\n serialized?: string | undefined,\n ) {\n this.#lastDownstreamMsgTime = Date.now();\n this.#downstreamSender.send(data, callback, serialized);\n }\n\n sendError(errorBody: ErrorBody, thrown?: unknown) {\n sendError(this.#lc, this.#ws, errorBody, thrown);\n }\n}\n\nexport type WebSocketLike = Pick<WebSocket, 'readyState'> & {\n send(data: string | PokeChunk, cb?: (err?: Error) => void): void;\n};\n\n// Exported for testing purposes.\nexport function send(\n lc: LogContext,\n ws: WebSocketLike,\n data: Downstream,\n callback: ((err?: Error | null) => void) | 'ignore-backpressure',\n serialized?: string | undefined,\n) {\n if (ws.readyState === WebSocket.OPEN) {\n serialized ??= JSON.stringify(data);\n if (callback === 'ignore-backpressure') {\n ws.send(serialized);\n return;\n }\n\n let completed = false;\n const timer = setTimeout(() => {\n complete(webSocketSendTimeoutError());\n }, WEBSOCKET_SEND_TIMEOUT_MS);\n timer.unref();\n\n const complete = (error?: Error | null) => {\n if (completed) {\n return;\n }\n completed = true;\n clearTimeout(timer);\n callback(error);\n };\n\n ws.send(serialized, complete);\n } else {\n lc.debug?.(`Dropping outbound message on ws (state: ${ws.readyState})`, {\n dropped: data,\n });\n if (callback !== 'ignore-backpressure') {\n callback(\n new ProtocolErrorWithLevel(\n {\n kind: ErrorKind.Internal,\n message: 'WebSocket closed',\n origin: ErrorOrigin.ZeroCache,\n },\n 'info',\n ),\n );\n }\n }\n}\n\n/**\n * Sends downstream messages in the format supported by a connection's sync\n * protocol version. Keep version forks contained here so the view-syncer can\n * continue producing one canonical poke representation.\n *\n * Exported for compatibility testing.\n */\nexport class DownstreamSender {\n readonly #lc: LogContext;\n readonly #ws: WebSocketLike;\n readonly #protocolVersion: number;\n #pokeChunkEncoder: PokeChunkEncoder | undefined;\n\n constructor(lc: LogContext, ws: WebSocketLike, protocolVersion: number) {\n this.#lc = lc;\n this.#ws = ws;\n this.#protocolVersion = protocolVersion;\n }\n\n send(\n data: Downstream,\n callback: ((err?: Error | null) => void) | 'ignore-backpressure',\n serialized?: string | undefined,\n ): void {\n if (this.#protocolVersion >= POKE_CHUNK_PROTOCOL_VERSION) {\n switch (data[0]) {\n case 'pokeStart':\n assert(\n this.#pokeChunkEncoder === undefined,\n 'cannot start a poke while another poke is in progress',\n );\n this.#pokeChunkEncoder = new PokeChunkEncoder();\n break;\n case 'pokePart':\n this.#sendPokePart(data, callback, serialized);\n return;\n case 'pokeEnd':\n this.#sendPokeEnd(data, callback);\n return;\n }\n }\n send(this.#lc, this.#ws, data, callback, serialized);\n }\n\n #sendPokePart(\n pokePart: PokePartMessage,\n callback: ((err?: Error | null) => void) | 'ignore-backpressure',\n serialized?: string | undefined,\n ): void {\n const encoder = this.#pokeChunkEncoder;\n assert(encoder, 'pokePart received without a pokeStart');\n\n serialized ??= JSON.stringify(pokePart);\n assert(\n serialized.startsWith(POKE_PART_PREFIX) && serialized.endsWith(']'),\n 'invalid serialized pokePart',\n );\n void encoder\n .addPatch(serialized.slice(POKE_PART_PREFIX.length, -1), chunk =>\n sendBinary(this.#lc, this.#ws, chunk),\n )\n .then(\n () => invokeCallback(callback),\n error => invokeCallback(callback, toError(error)),\n );\n }\n\n #sendPokeEnd(\n pokeEnd: PokeEndMessage,\n callback: ((err?: Error | null) => void) | 'ignore-backpressure',\n ): void {\n const encoder = this.#pokeChunkEncoder;\n assert(encoder, 'pokeEnd received without a pokeStart');\n this.#pokeChunkEncoder = undefined;\n\n if (pokeEnd[1].cancel) {\n encoder.cancel();\n send(this.#lc, this.#ws, pokeEnd, callback);\n return;\n }\n\n void encoder\n .finish(chunk => sendBinary(this.#lc, this.#ws, chunk))\n .then(() => sendAsync(this.#lc, this.#ws, pokeEnd))\n .then(\n () => invokeCallback(callback),\n error => invokeCallback(callback, toError(error)),\n );\n }\n}\n\nconst POKE_PART_PREFIX = '[\"pokePart\",';\n\nfunction sendAsync(\n lc: LogContext,\n ws: WebSocketLike,\n data: Downstream,\n): Promise<void> {\n return new Promise((resolve, reject) => {\n send(lc, ws, data, error => (error ? reject(error) : resolve()));\n });\n}\n\nfunction sendBinary(\n lc: LogContext,\n ws: WebSocketLike,\n chunk: PokeChunk,\n): Promise<void> {\n return new Promise((resolve, reject) => {\n if (ws.readyState !== WebSocket.OPEN) {\n const error = webSocketClosedError();\n lc.debug?.(\n `Dropping outbound binary message on ws (state: ${ws.readyState})`,\n );\n reject(error);\n return;\n }\n let completed = false;\n const timer = setTimeout(\n () => complete(webSocketSendTimeoutError()),\n WEBSOCKET_SEND_TIMEOUT_MS,\n );\n timer.unref();\n\n const complete = (error?: Error | null) => {\n if (completed) {\n return;\n }\n completed = true;\n clearTimeout(timer);\n error ? reject(error) : resolve();\n };\n\n ws.send(chunk, complete);\n });\n}\n\nfunction invokeCallback(\n callback: ((err?: Error | null) => void) | 'ignore-backpressure',\n error?: Error,\n): void {\n if (callback !== 'ignore-backpressure') {\n callback(error);\n }\n}\n\nfunction toError(error: unknown): Error {\n return error instanceof Error ? error : new Error(String(error));\n}\n\nfunction webSocketClosedError(): ProtocolErrorWithLevel {\n return new ProtocolErrorWithLevel(\n {\n kind: ErrorKind.Internal,\n message: 'WebSocket closed',\n origin: ErrorOrigin.ZeroCache,\n },\n 'info',\n );\n}\n\nfunction webSocketSendTimeoutError(): ProtocolErrorWithLevel {\n return new ProtocolErrorWithLevel(\n {\n kind: ErrorKind.Internal,\n message: `WebSocket send timed out after ${WEBSOCKET_SEND_TIMEOUT_MS} ms`,\n origin: ErrorOrigin.ZeroCache,\n },\n 'info',\n );\n}\n\nexport function sendError(\n lc: LogContext,\n ws: WebSocket,\n errorBody: ErrorBody,\n thrown?: unknown,\n) {\n lc = lc.withContext('errorKind', errorBody.kind);\n\n let logLevel: LogLevel;\n\n // If the thrown error is a ProtocolErrorWithLevel, its explicit logLevel takes precedence\n if (thrown instanceof ProtocolErrorWithLevel) {\n logLevel = thrown.logLevel;\n }\n // Errors with errno or transient socket codes are low-level, transient I/O issues\n // (e.g., EPIPE, ECONNRESET) and should be warnings, not errors\n else if (\n hasErrno(thrown) ||\n hasTransientSocketCode(thrown) ||\n isTransientSocketMessage(errorBody.message)\n ) {\n logLevel = 'warn';\n }\n // Fallback: check errorBody.kind for errors that weren't thrown as ProtocolErrorWithLevel\n else if (\n errorBody.kind === ErrorKind.ClientNotFound ||\n errorBody.kind === ErrorKind.TransformFailed\n ) {\n logLevel = 'warn';\n } else {\n logLevel = thrown ? getLogLevel(thrown) : 'info';\n }\n\n lc[logLevel]?.('Sending error on WebSocket', errorBody, thrown ?? '');\n send(lc, ws, ['error', errorBody], 'ignore-backpressure');\n}\n\nexport function findProtocolError(error: unknown): ProtocolError | undefined {\n if (isProtocolError(error)) {\n return error;\n }\n if (error instanceof Error && error.cause) {\n return findProtocolError(error.cause);\n }\n return undefined;\n}\n\nfunction hasErrno(error: unknown): boolean {\n return Boolean(\n error &&\n typeof error === 'object' &&\n 'errno' in error &&\n typeof (error as {errno: unknown}).errno !== 'undefined',\n );\n}\n\n// System error codes that indicate transient socket conditions.\n// These are checked via the `code` property on errors.\nconst TRANSIENT_SOCKET_ERROR_CODES = new Set([\n 'EPIPE',\n 'ECONNRESET',\n 'ECANCELED',\n]);\n\n// Error messages that indicate transient socket conditions but don't have\n// standard error codes (e.g., WebSocket library errors).\nconst TRANSIENT_SOCKET_MESSAGE_PATTERNS = [\n 'socket was closed while data was being compressed',\n];\n\nfunction hasTransientSocketCode(error: unknown): boolean {\n if (!error || typeof error !== 'object') {\n return false;\n }\n const maybeCode =\n 'code' in error ? String((error as {code?: unknown}).code) : undefined;\n return Boolean(\n maybeCode && TRANSIENT_SOCKET_ERROR_CODES.has(maybeCode.toUpperCase()),\n );\n}\n\nfunction isTransientSocketMessage(message: string | undefined): boolean {\n if (!message) {\n return false;\n }\n const lower = message.toLowerCase();\n return TRANSIENT_SOCKET_MESSAGE_PATTERNS.some(pattern =>\n lower.includes(pattern),\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"connection.js","names":["#ws","#wsID","#protocolVersion","#lc","#onClose","#messageHandler","#allowLegacyQueries","#downstreamSender","#downstreamMsgTimer","#webSocketErrors","#handleClose","#handleError","#proxyInbound","#maybeSendPong","#closeWithError","#closed","#viewSyncerOutboundStream","#pusherOutboundStream","#handleMessage","#handleMessageResult","#closeWithThrown","#proxyOutbound","#recordWebSocketError","#lastDownstreamMsgTime","#pokeChunks","#pokeChunkEncoder","#sendPokePart","#sendPokeEnd"],"sources":["../../../../../zero-cache/src/workers/connection.ts"],"sourcesContent":["import {pipeline, Readable, Writable} from 'node:stream';\nimport type {LogContext, LogLevel} from '@rocicorp/logger';\nimport type {CloseEvent, Data, ErrorEvent} from 'ws';\nimport WebSocket, {createWebSocketStream} from 'ws';\nimport {assert} from '../../../shared/src/asserts.ts';\nimport * as valita from '../../../shared/src/valita.ts';\nimport type {ConnectedMessage} from '../../../zero-protocol/src/connect.ts';\nimport type {Downstream} from '../../../zero-protocol/src/down.ts';\nimport {ErrorKind} from '../../../zero-protocol/src/error-kind.ts';\nimport {ErrorOrigin} from '../../../zero-protocol/src/error-origin.ts';\nimport type {ErrorBody} from '../../../zero-protocol/src/error.ts';\nimport {\n isProtocolError,\n type ProtocolError,\n} from '../../../zero-protocol/src/error.ts';\nimport {FeatureFlag} from '../../../zero-protocol/src/feature-flag.ts';\nimport {\n type PokeChunk,\n type PokeEndMessage,\n type PokePartMessage,\n} from '../../../zero-protocol/src/poke.ts';\nimport {\n MIN_SERVER_SUPPORTED_SYNC_PROTOCOL,\n PROTOCOL_VERSION,\n} from '../../../zero-protocol/src/protocol-version.ts';\nimport {\n upstreamSchemaWithUnparsedAnalyzeQuery,\n type UpstreamWithUnparsedAnalyzeQuery,\n} from '../../../zero-protocol/src/up.ts';\nimport {getOrCreateCounter} from '../observability/metrics.ts';\nimport type {ViewSyncerDownstream} from '../types/downstream.ts';\nimport {\n ProtocolErrorWithLevel,\n getLogLevel,\n wrapWithProtocolError,\n} from '../types/error-with-level.ts';\nimport {PokeChunkEncoder} from '../types/poke-chunk.ts';\nimport type {Source} from '../types/streams.ts';\nimport type {ConnectParams} from './connect-params.ts';\n\nexport type HandlerResult =\n | {\n type: 'ok';\n }\n | {\n type: 'fatal';\n error: ErrorBody;\n }\n | {\n type: 'transient';\n errors: ErrorBody[];\n }\n | StreamResult;\n\nexport type StreamResult =\n | {\n type: 'stream';\n source: 'viewSyncer';\n stream: Source<ViewSyncerDownstream>;\n }\n | {\n type: 'stream';\n source: 'pusher';\n stream: Source<Downstream>;\n };\n\nexport interface MessageHandler {\n handleMessage(\n msg: UpstreamWithUnparsedAnalyzeQuery,\n ): Promise<HandlerResult[]>;\n}\n\nfunction hasOwn(value: unknown, property: string): boolean {\n return (\n typeof value === 'object' &&\n value !== null &&\n Object.hasOwn(value, property)\n );\n}\n\nfunction containsLegacyQuery(message: unknown): boolean {\n if (!Array.isArray(message)) {\n return false;\n }\n\n const body = message[1];\n if (typeof body !== 'object' || body === null) {\n return false;\n }\n\n if (\n message[0] !== 'initConnection' &&\n message[0] !== 'changeDesiredQueries'\n ) {\n return false;\n }\n\n const patch = body['desiredQueriesPatch'];\n return (\n Array.isArray(patch) && patch.some(operation => hasOwn(operation, 'ast'))\n );\n}\n\nconst LEGACY_QUERIES_DISABLED_MESSAGE =\n 'Legacy queries are disabled by this Zero server. This client must use custom queries instead of sending query ASTs directly. To temporarily restore compatibility, set ZERO_ALLOW_LEGACY_QUERIES=true on zero-cache.';\n\n// Exported for testing purposes.\nexport function parseUpstreamMessage(\n value: unknown,\n allowLegacyQueries: boolean,\n): UpstreamWithUnparsedAnalyzeQuery {\n if (!allowLegacyQueries && containsLegacyQuery(value)) {\n throw new Error(LEGACY_QUERIES_DISABLED_MESSAGE);\n }\n return valita.parse(value, upstreamSchemaWithUnparsedAnalyzeQuery);\n}\n\n// Ensures that a downstream message is sent at least every interval, sending a\n// 'pong' if necessary. This is set to be slightly longer than the client-side\n// PING_INTERVAL of 5 seconds, so that in the common case, 'pong's are sent in\n// response to client-initiated 'ping's. However, if the inbound stream is\n// backed up because a command is taking a long time to process, the pings\n// will be stuck in the queue (i.e. back-pressured), in which case pongs will\n// be manually sent to notify the client of server liveness.\n//\n// This is equivalent to what is done for Postgres keepalives on the\n// replication stream (which can similarly be back-pressured):\n// https://github.com/rocicorp/mono/blob/f98cb369a2dbb15650328859c732db358f187ef0/packages/zero-cache/src/services/change-source/pg/logical-replication/stream.ts#L21\nconst DOWNSTREAM_MSG_INTERVAL_MS = 6_000;\nexport const WEBSOCKET_SEND_TIMEOUT_MS = 10_000;\nconst PROTOCOL_VERSION_ATTRIBUTE = 'protocol.version';\nconst EVENT_TYPE_ATTRIBUTE = 'event.type';\n\n/**\n * Represents a connection between the client and server.\n *\n * Handles incoming messages on the connection and dispatches\n * them to the correct service.\n *\n * Listens to the ViewSyncer and sends messages to the client.\n */\nexport class Connection {\n readonly #ws: WebSocket;\n readonly #wsID: string;\n readonly #protocolVersion: number;\n readonly #lc: LogContext;\n readonly #onClose: () => void;\n readonly #messageHandler: MessageHandler;\n readonly #allowLegacyQueries: boolean;\n readonly #downstreamSender: DownstreamSender;\n readonly #downstreamMsgTimer: NodeJS.Timeout | undefined;\n readonly #webSocketErrors = getOrCreateCounter(\n 'sync',\n 'websocket.errors',\n 'Client WebSocket error events.',\n );\n\n #viewSyncerOutboundStream: Source<ViewSyncerDownstream> | undefined;\n #pusherOutboundStream: Source<Downstream> | undefined;\n #closed = false;\n\n constructor(\n lc: LogContext,\n connectParams: ConnectParams,\n ws: WebSocket,\n allowLegacyQueries: boolean,\n messageHandler: MessageHandler,\n onClose: () => void,\n ) {\n const {clientGroupID, clientID, wsID, protocolVersion} = connectParams;\n this.#messageHandler = messageHandler;\n this.#allowLegacyQueries = allowLegacyQueries;\n\n this.#ws = ws;\n this.#wsID = wsID;\n this.#protocolVersion = protocolVersion;\n\n this.#lc = lc\n .withContext('connection')\n .withContext('clientID', clientID)\n .withContext('clientGroupID', clientGroupID)\n .withContext('wsID', wsID);\n this.#downstreamSender = new DownstreamSender(\n this.#lc,\n ws,\n connectParams.features.has(FeatureFlag.PokeChunk),\n );\n this.#lc.debug?.('new connection');\n this.#onClose = onClose;\n\n this.#ws.addEventListener('close', this.#handleClose);\n this.#ws.addEventListener('error', this.#handleError);\n\n this.#proxyInbound();\n this.#downstreamMsgTimer = setInterval(\n this.#maybeSendPong,\n DOWNSTREAM_MSG_INTERVAL_MS / 2,\n );\n }\n\n /**\n * Checks the protocol version and errors for unsupported protocols,\n * sending the initial `connected` response on success.\n *\n * This is early in the connection lifecycle because {@link #handleMessage}\n * will only parse messages with schema(s) of supported protocol versions.\n */\n init(): boolean {\n if (\n this.#protocolVersion > PROTOCOL_VERSION ||\n this.#protocolVersion < MIN_SERVER_SUPPORTED_SYNC_PROTOCOL\n ) {\n this.#closeWithError({\n kind: ErrorKind.VersionNotSupported,\n message: `server is at sync protocol v${PROTOCOL_VERSION} and does not support v${\n this.#protocolVersion\n }. The ${\n this.#protocolVersion > PROTOCOL_VERSION ? 'server' : 'client'\n } must be updated to a newer release.`,\n origin: ErrorOrigin.ZeroCache,\n });\n } else {\n const connectedMessage: ConnectedMessage = [\n 'connected',\n {wsid: this.#wsID, timestamp: Date.now()},\n ];\n this.send(connectedMessage, 'ignore-backpressure');\n return true;\n }\n return false;\n }\n\n close(reason: string, ...args: unknown[]) {\n if (this.#closed) {\n return;\n }\n this.#closed = true;\n this.#lc.info?.(`closing connection: ${reason}`, ...args);\n this.#ws.removeEventListener('close', this.#handleClose);\n this.#ws.removeEventListener('error', this.#handleError);\n this.#viewSyncerOutboundStream?.cancel();\n this.#viewSyncerOutboundStream = undefined;\n this.#pusherOutboundStream?.cancel();\n this.#pusherOutboundStream = undefined;\n this.#onClose();\n if (this.#ws.readyState !== this.#ws.CLOSED) {\n this.#ws.close();\n }\n clearTimeout(this.#downstreamMsgTimer);\n\n // spin down services if we have\n // no more client connections for the client group?\n }\n\n handleInitConnection(initConnectionMsg: string) {\n return this.#handleMessage({data: initConnectionMsg});\n }\n\n #handleMessage = async (event: {data: Data}) => {\n const data = event.data.toString();\n if (this.#closed) {\n this.#lc.debug?.('Ignoring message received after closed', data);\n return;\n }\n\n let msg;\n try {\n const value = JSON.parse(data);\n msg = parseUpstreamMessage(value, this.#allowLegacyQueries);\n } catch (e) {\n const errorBody = {\n kind: ErrorKind.InvalidMessage,\n message: String(e),\n origin: ErrorOrigin.ZeroCache,\n } as const;\n this.#closeWithError(\n errorBody,\n new ProtocolErrorWithLevel(errorBody, 'warn'),\n );\n return;\n }\n\n try {\n const msgType = msg[0];\n if (msgType === 'ping') {\n this.send(['pong', {}], 'ignore-backpressure');\n return;\n }\n\n const result = await this.#messageHandler.handleMessage(msg);\n for (const r of result) {\n this.#handleMessageResult(r);\n }\n } catch (e) {\n this.#closeWithThrown(e);\n }\n };\n\n #handleMessageResult(result: HandlerResult): void {\n switch (result.type) {\n case 'fatal':\n this.#closeWithError(result.error);\n break;\n case 'ok':\n break;\n case 'stream': {\n switch (result.source) {\n case 'viewSyncer':\n assert(\n this.#viewSyncerOutboundStream === undefined,\n 'Outbound stream already set for this connection!',\n );\n this.#viewSyncerOutboundStream = result.stream;\n break;\n case 'pusher':\n assert(\n this.#pusherOutboundStream === undefined,\n 'Outbound stream already set for this connection!',\n );\n this.#pusherOutboundStream = result.stream;\n break;\n }\n if (result.source === 'viewSyncer') {\n this.#proxyOutbound(result.stream, (downstream, callback) =>\n this.send(downstream.message, callback, downstream.serialized),\n );\n } else {\n this.#proxyOutbound(result.stream, (downstream, callback) =>\n this.send(downstream, callback),\n );\n }\n break;\n }\n case 'transient': {\n for (const error of result.errors) {\n this.sendError(error);\n }\n }\n }\n }\n\n #handleClose = (e: CloseEvent) => {\n const {code, reason, wasClean} = e;\n if (!wasClean) {\n this.#recordWebSocketError('unclean_close');\n }\n this.close('WebSocket close event', {code, reason, wasClean});\n };\n\n #handleError = (e: ErrorEvent) => {\n this.#recordWebSocketError('error_event');\n this.#lc.warn?.('WebSocket error event', e.message, e.error);\n };\n\n #recordWebSocketError(eventType: string) {\n this.#webSocketErrors.add(1, {\n [PROTOCOL_VERSION_ATTRIBUTE]: this.#protocolVersion,\n [EVENT_TYPE_ATTRIBUTE]: eventType,\n });\n }\n\n #proxyInbound() {\n pipeline(\n createWebSocketStream(this.#ws),\n new Writable({\n write: (data, _encoding, callback) => {\n this.#handleMessage({data}).then(() => callback(), callback);\n },\n }),\n // The done callback is not used, as #handleClose and #handleError,\n // configured on the underlying WebSocket, provide more complete\n // information.\n () => {},\n );\n }\n\n #proxyOutbound<T>(\n outboundStream: Source<T>,\n sendMessage: (\n downstream: T,\n callback: (err?: Error | null) => void,\n ) => void,\n ) {\n // Note: createWebSocketStream() is avoided here in order to control\n // exception handling with #closeWithThrown(). If the Writable\n // from createWebSocketStream() were instead used, exceptions\n // from the outboundStream result in the Writable closing the\n // the websocket before the error message can be sent.\n pipeline(\n Readable.from(outboundStream),\n new Writable({\n objectMode: true,\n write: (downstream: T, _encoding, callback) =>\n sendMessage(downstream, callback),\n }),\n e =>\n e\n ? this.#closeWithThrown(e)\n : this.close(`downstream closed by ViewSyncer`),\n );\n }\n\n #closeWithThrown(e: unknown) {\n const errorBody =\n findProtocolError(e)?.errorBody ?? wrapWithProtocolError(e).errorBody;\n\n this.#closeWithError(errorBody, e);\n }\n\n #closeWithError(errorBody: ErrorBody, thrown?: unknown) {\n this.sendError(errorBody, thrown);\n this.close(\n `${errorBody.kind} (${errorBody.origin}): ${errorBody.message}`,\n errorBody,\n );\n }\n\n #lastDownstreamMsgTime = Date.now();\n\n #maybeSendPong = () => {\n if (Date.now() - this.#lastDownstreamMsgTime > DOWNSTREAM_MSG_INTERVAL_MS) {\n this.#lc.debug?.('manually sending pong');\n this.send(['pong', {}], 'ignore-backpressure');\n }\n };\n\n send(\n data: Downstream,\n callback: ((err?: Error | null) => void) | 'ignore-backpressure',\n serialized?: string | undefined,\n ) {\n this.#lastDownstreamMsgTime = Date.now();\n this.#downstreamSender.send(data, callback, serialized);\n }\n\n sendError(errorBody: ErrorBody, thrown?: unknown) {\n sendError(this.#lc, this.#ws, errorBody, thrown);\n }\n}\n\nexport type WebSocketLike = Pick<WebSocket, 'readyState'> & {\n send(data: string | PokeChunk, cb?: (err?: Error) => void): void;\n};\n\n// Exported for testing purposes.\nexport function send(\n lc: LogContext,\n ws: WebSocketLike,\n data: Downstream,\n callback: ((err?: Error | null) => void) | 'ignore-backpressure',\n serialized?: string | undefined,\n) {\n if (ws.readyState === WebSocket.OPEN) {\n serialized ??= JSON.stringify(data);\n if (callback === 'ignore-backpressure') {\n ws.send(serialized);\n return;\n }\n\n let completed = false;\n const timer = setTimeout(() => {\n complete(webSocketSendTimeoutError());\n }, WEBSOCKET_SEND_TIMEOUT_MS);\n timer.unref();\n\n const complete = (error?: Error | null) => {\n if (completed) {\n return;\n }\n completed = true;\n clearTimeout(timer);\n callback(error);\n };\n\n ws.send(serialized, complete);\n } else {\n lc.debug?.(`Dropping outbound message on ws (state: ${ws.readyState})`, {\n dropped: data,\n });\n if (callback !== 'ignore-backpressure') {\n callback(\n new ProtocolErrorWithLevel(\n {\n kind: ErrorKind.Internal,\n message: 'WebSocket closed',\n origin: ErrorOrigin.ZeroCache,\n },\n 'info',\n ),\n );\n }\n }\n}\n\n/**\n * Sends downstream messages in the format the client supports. Keep format\n * forks contained here so the view-syncer can continue producing one\n * canonical poke representation.\n *\n * Exported for compatibility testing.\n */\nexport class DownstreamSender {\n readonly #lc: LogContext;\n readonly #ws: WebSocketLike;\n readonly #pokeChunks: boolean;\n #pokeChunkEncoder: PokeChunkEncoder | undefined;\n\n constructor(lc: LogContext, ws: WebSocketLike, pokeChunks: boolean) {\n this.#lc = lc;\n this.#ws = ws;\n this.#pokeChunks = pokeChunks;\n }\n\n send(\n data: Downstream,\n callback: ((err?: Error | null) => void) | 'ignore-backpressure',\n serialized?: string | undefined,\n ): void {\n if (this.#pokeChunks) {\n switch (data[0]) {\n case 'pokeStart':\n assert(\n this.#pokeChunkEncoder === undefined,\n 'cannot start a poke while another poke is in progress',\n );\n this.#pokeChunkEncoder = new PokeChunkEncoder();\n break;\n case 'pokePart':\n this.#sendPokePart(data, callback, serialized);\n return;\n case 'pokeEnd':\n this.#sendPokeEnd(data, callback);\n return;\n }\n }\n send(this.#lc, this.#ws, data, callback, serialized);\n }\n\n #sendPokePart(\n pokePart: PokePartMessage,\n callback: ((err?: Error | null) => void) | 'ignore-backpressure',\n serialized?: string | undefined,\n ): void {\n const encoder = this.#pokeChunkEncoder;\n assert(encoder, 'pokePart received without a pokeStart');\n\n serialized ??= JSON.stringify(pokePart);\n assert(\n serialized.startsWith(POKE_PART_PREFIX) && serialized.endsWith(']'),\n 'invalid serialized pokePart',\n );\n void encoder\n .addPatch(serialized.slice(POKE_PART_PREFIX.length, -1), chunk =>\n sendBinary(this.#lc, this.#ws, chunk),\n )\n .then(\n () => invokeCallback(callback),\n error => invokeCallback(callback, toError(error)),\n );\n }\n\n #sendPokeEnd(\n pokeEnd: PokeEndMessage,\n callback: ((err?: Error | null) => void) | 'ignore-backpressure',\n ): void {\n const encoder = this.#pokeChunkEncoder;\n assert(encoder, 'pokeEnd received without a pokeStart');\n this.#pokeChunkEncoder = undefined;\n\n if (pokeEnd[1].cancel) {\n encoder.cancel();\n send(this.#lc, this.#ws, pokeEnd, callback);\n return;\n }\n\n void encoder\n .finish(chunk => sendBinary(this.#lc, this.#ws, chunk))\n .then(() => sendAsync(this.#lc, this.#ws, pokeEnd))\n .then(\n () => invokeCallback(callback),\n error => invokeCallback(callback, toError(error)),\n );\n }\n}\n\nconst POKE_PART_PREFIX = '[\"pokePart\",';\n\nfunction sendAsync(\n lc: LogContext,\n ws: WebSocketLike,\n data: Downstream,\n): Promise<void> {\n return new Promise((resolve, reject) => {\n send(lc, ws, data, error => (error ? reject(error) : resolve()));\n });\n}\n\nfunction sendBinary(\n lc: LogContext,\n ws: WebSocketLike,\n chunk: PokeChunk,\n): Promise<void> {\n return new Promise((resolve, reject) => {\n if (ws.readyState !== WebSocket.OPEN) {\n const error = webSocketClosedError();\n lc.debug?.(\n `Dropping outbound binary message on ws (state: ${ws.readyState})`,\n );\n reject(error);\n return;\n }\n let completed = false;\n const timer = setTimeout(\n () => complete(webSocketSendTimeoutError()),\n WEBSOCKET_SEND_TIMEOUT_MS,\n );\n timer.unref();\n\n const complete = (error?: Error | null) => {\n if (completed) {\n return;\n }\n completed = true;\n clearTimeout(timer);\n error ? reject(error) : resolve();\n };\n\n ws.send(chunk, complete);\n });\n}\n\nfunction invokeCallback(\n callback: ((err?: Error | null) => void) | 'ignore-backpressure',\n error?: Error,\n): void {\n if (callback !== 'ignore-backpressure') {\n callback(error);\n }\n}\n\nfunction toError(error: unknown): Error {\n return error instanceof Error ? error : new Error(String(error));\n}\n\nfunction webSocketClosedError(): ProtocolErrorWithLevel {\n return new ProtocolErrorWithLevel(\n {\n kind: ErrorKind.Internal,\n message: 'WebSocket closed',\n origin: ErrorOrigin.ZeroCache,\n },\n 'info',\n );\n}\n\nfunction webSocketSendTimeoutError(): ProtocolErrorWithLevel {\n return new ProtocolErrorWithLevel(\n {\n kind: ErrorKind.Internal,\n message: `WebSocket send timed out after ${WEBSOCKET_SEND_TIMEOUT_MS} ms`,\n origin: ErrorOrigin.ZeroCache,\n },\n 'info',\n );\n}\n\nexport function sendError(\n lc: LogContext,\n ws: WebSocket,\n errorBody: ErrorBody,\n thrown?: unknown,\n) {\n lc = lc.withContext('errorKind', errorBody.kind);\n\n let logLevel: LogLevel;\n\n // If the thrown error is a ProtocolErrorWithLevel, its explicit logLevel takes precedence\n if (thrown instanceof ProtocolErrorWithLevel) {\n logLevel = thrown.logLevel;\n }\n // Errors with errno or transient socket codes are low-level, transient I/O issues\n // (e.g., EPIPE, ECONNRESET) and should be warnings, not errors\n else if (\n hasErrno(thrown) ||\n hasTransientSocketCode(thrown) ||\n isTransientSocketMessage(errorBody.message)\n ) {\n logLevel = 'warn';\n }\n // Fallback: check errorBody.kind for errors that weren't thrown as ProtocolErrorWithLevel\n else if (\n errorBody.kind === ErrorKind.ClientNotFound ||\n errorBody.kind === ErrorKind.TransformFailed\n ) {\n logLevel = 'warn';\n } else {\n logLevel = thrown ? getLogLevel(thrown) : 'info';\n }\n\n lc[logLevel]?.('Sending error on WebSocket', errorBody, thrown ?? '');\n send(lc, ws, ['error', errorBody], 'ignore-backpressure');\n}\n\nexport function findProtocolError(error: unknown): ProtocolError | undefined {\n if (isProtocolError(error)) {\n return error;\n }\n if (error instanceof Error && error.cause) {\n return findProtocolError(error.cause);\n }\n return undefined;\n}\n\nfunction hasErrno(error: unknown): boolean {\n return Boolean(\n error &&\n typeof error === 'object' &&\n 'errno' in error &&\n typeof (error as {errno: unknown}).errno !== 'undefined',\n );\n}\n\n// System error codes that indicate transient socket conditions.\n// These are checked via the `code` property on errors.\nconst TRANSIENT_SOCKET_ERROR_CODES = new Set([\n 'EPIPE',\n 'ECONNRESET',\n 'ECANCELED',\n]);\n\n// Error messages that indicate transient socket conditions but don't have\n// standard error codes (e.g., WebSocket library errors).\nconst TRANSIENT_SOCKET_MESSAGE_PATTERNS = [\n 'socket was closed while data was being compressed',\n];\n\nfunction hasTransientSocketCode(error: unknown): boolean {\n if (!error || typeof error !== 'object') {\n return false;\n }\n const maybeCode =\n 'code' in error ? String((error as {code?: unknown}).code) : undefined;\n return Boolean(\n maybeCode && TRANSIENT_SOCKET_ERROR_CODES.has(maybeCode.toUpperCase()),\n );\n}\n\nfunction isTransientSocketMessage(message: string | undefined): boolean {\n if (!message) {\n return false;\n }\n const lower = message.toLowerCase();\n return TRANSIENT_SOCKET_MESSAGE_PATTERNS.some(pattern =>\n lower.includes(pattern),\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"replicator.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/workers/replicator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAEjD,OAAO,KAAK,CAAC,MAAM,+BAA+B,CAAC;AAEnD,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,0BAA0B,CAAC;AAI7D,OAAO,EAAC,QAAQ,EAAC,MAAM,oCAAoC,CAAC;AAC5D,OAAO,KAAK,EACV,YAAY,EACZ,oBAAoB,EACpB,UAAU,EACX,MAAM,sCAAsC,CAAC;AAK9C,OAAO,EAEL,KAAK,YAAY,EAClB,MAAM,+CAA+C,CAAC;AACvD,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,uBAAuB,CAAC;AAElD,eAAO,MAAM,qBAAqB,+CAIjC,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAEpE,MAAM,MAAM,OAAO,GAAG,KAAK,GAAG,MAAM,CAAC;AAErC,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,eAAe,UAEzE;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,+BAA+B,CAC7C,mBAAmB,EAAE,MAAM,GAC1B,OAAO,CAET;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,mBAAmB,EAAE,MAAM,EAC3B,MAAM,EAAE,MAAM,GACb,OAAO,CAMT;AA2FD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,eAAe,GAAG,YAAY,CAMnE;AAED,wBAAgB,YAAY,CAC1B,EAAE,EAAE,UAAU,EACd,IAAI,EAAE,eAAe,EACrB,cAAc,EAAE,cAAc;UAjGd,MAAM;aAAW,OAAO;cAAY,MAAM;GAgI3D;AAED,wBAAgB,oBAAoB,CAClC,EAAE,EAAE,UAAU,EACd,UAAU,EAAE,UAAU,EACtB,MAAM,EAAE,MAAM,QAGf;AAID,wBAAgB,uBAAuB,CACrC,EAAE,EAAE,UAAU,EACd,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,oBAAoB,QA8B/B;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,UAAU,EACf,MAAM,EAAE,MAAM,EACd,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,GACvC,QAAQ,CAOV;AAED,wBAAgB,WAAW,CAAC,GAAG,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,QAE1D"}
1
+ {"version":3,"file":"replicator.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/workers/replicator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAGjD,OAAO,KAAK,CAAC,MAAM,+BAA+B,CAAC;AAEnD,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,0BAA0B,CAAC;AAI7D,OAAO,EAAC,QAAQ,EAAC,MAAM,oCAAoC,CAAC;AAC5D,OAAO,KAAK,EACV,YAAY,EACZ,oBAAoB,EACpB,UAAU,EACX,MAAM,sCAAsC,CAAC;AAK9C,OAAO,EAEL,KAAK,YAAY,EAClB,MAAM,+CAA+C,CAAC;AACvD,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,uBAAuB,CAAC;AAElD,eAAO,MAAM,qBAAqB,+CAIjC,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAEpE,MAAM,MAAM,OAAO,GAAG,KAAK,GAAG,MAAM,CAAC;AAErC,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,eAAe,UAEzE;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,+BAA+B,CAC7C,mBAAmB,EAAE,MAAM,GAC1B,OAAO,CAET;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,mBAAmB,EAAE,MAAM,EAC3B,MAAM,EAAE,MAAM,GACb,OAAO,CAMT;AA8GD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,eAAe,GAAG,YAAY,CAMnE;AAED,wBAAgB,YAAY,CAC1B,EAAE,EAAE,UAAU,EACd,IAAI,EAAE,eAAe,EACrB,cAAc,EAAE,cAAc;UApHd,MAAM;aAAW,OAAO;cAAY,MAAM;GAmJ3D;AAED,wBAAgB,oBAAoB,CAClC,EAAE,EAAE,UAAU,EACd,UAAU,EAAE,UAAU,EACtB,MAAM,EAAE,MAAM,QAGf;AAID,wBAAgB,uBAAuB,CACrC,EAAE,EAAE,UAAU,EACd,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,oBAAoB,QA8B/B;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,UAAU,EACf,MAAM,EAAE,MAAM,EACd,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,GACvC,QAAQ,CAOV;AAED,wBAAgB,WAAW,CAAC,GAAG,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,QAE1D"}
@@ -7,6 +7,7 @@ import { deleteChangeLogDB } from "../services/replicator/change-log-db.js";
7
7
  import { upgradeReplica } from "../services/change-source/common/replica-schema.js";
8
8
  import { Notifier } from "../services/replicator/notifier.js";
9
9
  import { applyPragmas } from "../services/replicator/write-worker-client.js";
10
+ import { SqliteError } from "@rocicorp/zero-sqlite3";
10
11
  //#region ../zero-cache/src/workers/replicator.ts
11
12
  var replicaFileModeSchema = literalUnion("serving", "serving-copy", "backup");
12
13
  function replicaFileName(replicaFile, mode) {
@@ -50,7 +51,8 @@ async function prepare(lc, { file, vacuumIntervalHours }, walMode, mode) {
50
51
  const replica = new Database(lc, file);
51
52
  let pageSize;
52
53
  try {
53
- await setJournalMode(lc, replica, "delete");
54
+ const [{ journal_mode: journalMode }] = replica.pragma("journal_mode");
55
+ if (journalMode !== walMode) await setJournalMode(lc, replica, "delete");
54
56
  [{page_size: pageSize}] = replica.pragma("page_size");
55
57
  const [{ page_count: pageCount }] = replica.pragma("page_count");
56
58
  const [{ freelist_count: freelistCount }] = replica.pragma("freelist_count");
@@ -64,12 +66,18 @@ async function prepare(lc, { file, vacuumIntervalHours }, walMode, mode) {
64
66
  lc.info?.(`Performing maintenance cleanup on ${file}`);
65
67
  const t0 = performance.now();
66
68
  replica.unsafeMode(true);
67
- replica.pragma("journal_mode = OFF");
68
- replica.exec("VACUUM");
69
- recordEvent(replica, "vacuum");
70
- replica.unsafeMode(false);
71
- const t1 = performance.now();
72
- lc.info?.(`VACUUM completed (${t1 - t0} ms)`);
69
+ try {
70
+ replica.pragma("journal_mode = OFF");
71
+ replica.exec("VACUUM");
72
+ recordEvent(replica, "vacuum");
73
+ const t1 = performance.now();
74
+ lc.info?.(`VACUUM completed (${t1 - t0} ms)`);
75
+ } catch (e) {
76
+ if (!(e instanceof SqliteError && e.code === "SQLITE_BUSY")) throw e;
77
+ lc.warn?.(`Skipping VACUUM of ${file}: the database is locked`, e);
78
+ } finally {
79
+ replica.unsafeMode(false);
80
+ }
73
81
  }
74
82
  }
75
83
  await setJournalMode(lc, replica, walMode);
@@ -1 +1 @@
1
- {"version":3,"file":"replicator.js","names":[],"sources":["../../../../../zero-cache/src/workers/replicator.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {sleep} from '../../../shared/src/sleep.ts';\nimport * as v from '../../../shared/src/valita.ts';\nimport {Database} from '../../../zqlite/src/db.ts';\nimport type {ReplicaOptions} from '../config/zero-config.ts';\nimport {deleteLiteDB} from '../db/delete-lite-db.ts';\nimport {upgradeReplica} from '../services/change-source/common/replica-schema.ts';\nimport {deleteChangeLogDB} from '../services/replicator/change-log-db.ts';\nimport {Notifier} from '../services/replicator/notifier.ts';\nimport type {\n ReplicaState,\n ReplicaStateNotifier,\n Replicator,\n} from '../services/replicator/replicator.ts';\nimport {\n getAscendingEvents,\n recordEvent,\n} from '../services/replicator/schema/replication-state.ts';\nimport {\n applyPragmas,\n type PragmaConfig,\n} from '../services/replicator/write-worker-client.ts';\nimport type {Worker} from '../types/processes.ts';\n\nexport const replicaFileModeSchema = v.literalUnion(\n 'serving',\n 'serving-copy',\n 'backup',\n);\n\nexport type ReplicaFileMode = v.Infer<typeof replicaFileModeSchema>;\n\nexport type WalMode = 'wal' | 'wal2';\n\nexport function replicaFileName(replicaFile: string, mode: ReplicaFileMode) {\n return mode === 'serving-copy' ? `${replicaFile}-serving-copy` : replicaFile;\n}\n\n/**\n * Whether a replicator worker deletes the change-log file beside its replica at\n * startup.\n *\n * The change log belongs to the change-streamer, so this only ever cleans up a\n * file that nothing is writing. The predicate is deliberately the config flag\n * and nothing else: keying it on anything derived per replica -- a file mode, or\n * the retired `logsChangeStream` -- would make every replicator start unlink the\n * change-streamer's live log, because no replicator writes it any more. Paths\n * coincide whenever `fileMode !== 'serving-copy'`, so that hazard is real in the\n * shipped no-`backupURL` configuration.\n *\n * Deleting is safe when nothing writes the log: it is excluded from the\n * litestream backup, only the writer purges it, and re-enabling the writer\n * reseeds at the resume watermark.\n */\nexport function replicatorDeletesStaleChangeLog(\n sqliteChangeLogMode: string,\n): boolean {\n return sqliteChangeLogMode === 'off';\n}\n\n/**\n * The `mode=off` cleanup itself: deletes the change-log file beside `dbPath`\n * when {@link replicatorDeletesStaleChangeLog} says nothing writes it, and\n * reports whether it did. The decision and the delete live in one function so\n * that the guard test covers the call the replicator actually makes, not just\n * the predicate.\n */\nexport function deleteStaleChangeLog(\n sqliteChangeLogMode: string,\n dbPath: string,\n): boolean {\n if (!replicatorDeletesStaleChangeLog(sqliteChangeLogMode)) {\n return false;\n }\n deleteChangeLogDB(dbPath);\n return true;\n}\n\nconst MILLIS_PER_HOUR = 1000 * 60 * 60;\nconst MB = 1024 * 1024;\n\nasync function prepare(\n lc: LogContext,\n {file, vacuumIntervalHours}: ReplicaOptions,\n walMode: WalMode,\n mode: ReplicaFileMode,\n): Promise<{file: string; walMode: WalMode; pageSize: number}> {\n // Perform any upgrades to the replica in case the backup is an\n // earlier version.\n await upgradeReplica(lc, `${mode}-replica`, file);\n\n const replica = new Database(lc, file);\n let pageSize: number;\n try {\n // Start by folding any (e.g. restored) WAL(2) files into the main db.\n await setJournalMode(lc, replica, 'delete');\n\n [{page_size: pageSize}] = replica.pragma<{page_size: number}>('page_size');\n const [{page_count: pageCount}] = replica.pragma<{page_count: number}>(\n 'page_count',\n );\n const [{freelist_count: freelistCount}] = replica.pragma<{\n freelist_count: number;\n }>('freelist_count');\n\n const dbSize = ((pageCount * pageSize) / MB).toFixed(2);\n const freelistSize = ((freelistCount * pageSize) / MB).toFixed(2);\n\n // TODO: Consider adding a freelist size or ratio based vacuum trigger.\n lc.info?.(`Size of db ${file}: ${dbSize} MB (${freelistSize} MB freeable)`);\n\n // Check for the VACUUM threshold.\n const events = getAscendingEvents(replica);\n lc.debug?.(`Runtime events for db ${file}`, {events});\n if (vacuumIntervalHours !== undefined) {\n const millisSinceLastEvent =\n Date.now() - (events.at(-1)?.timestamp.getTime() ?? 0);\n if (millisSinceLastEvent / MILLIS_PER_HOUR > vacuumIntervalHours) {\n lc.info?.(`Performing maintenance cleanup on ${file}`);\n const t0 = performance.now();\n replica.unsafeMode(true);\n replica.pragma('journal_mode = OFF');\n replica.exec('VACUUM');\n recordEvent(replica, 'vacuum');\n replica.unsafeMode(false);\n const t1 = performance.now();\n lc.info?.(`VACUUM completed (${t1 - t0} ms)`);\n }\n }\n\n await setJournalMode(lc, replica, walMode);\n\n const pragmas = getPragmaConfig(mode);\n applyPragmas(replica, pragmas);\n\n replica.pragma('optimize = 0x10002');\n lc.info?.(`optimized ${file}`);\n } finally {\n replica.close();\n }\n return {file, walMode, pageSize};\n}\n\n// Setting the journal_mode requires an exclusive lock on the replica.\n// Add resilience against random replica reads (for stats, etc.) by\n// retrying if the database is locked. Note that the busy_timeout doesn't\n// work here.\nasync function setJournalMode(\n lc: LogContext,\n replica: Database,\n mode: 'delete' | 'wal' | 'wal2',\n) {\n lc.info?.(`setting ${replica.name} to ${mode} mode`);\n let err: unknown;\n for (let i = 0; i < 5; i++) {\n try {\n replica.pragma(`journal_mode = ${mode}`);\n return;\n } catch (e) {\n lc.warn?.(`error setting journal_mode to ${mode} (attempt ${i + 1})`, e);\n err = e;\n }\n await sleep(500);\n }\n throw err;\n}\n\n/**\n * Returns the PragmaConfig for a given replica file mode.\n * This is used by both the main thread (setupReplica) and\n * the write worker thread to apply the same pragma settings.\n */\nexport function getPragmaConfig(mode: ReplicaFileMode): PragmaConfig {\n return {\n busyTimeout: 30000,\n analysisLimit: 1000,\n walAutocheckpoint: mode === 'backup' ? 0 : undefined,\n };\n}\n\nexport function setupReplica(\n lc: LogContext,\n mode: ReplicaFileMode,\n replicaOptions: ReplicaOptions,\n) {\n lc.info?.(`setting up ${mode} replica`);\n\n switch (mode) {\n case 'backup':\n return prepare(lc, replicaOptions, 'wal', mode);\n\n case 'serving-copy': {\n // In 'serving-copy' mode, the original file is being used for 'backup'\n // mode, so we make a copy for servicing sync requests.\n const {file} = replicaOptions;\n const copyLocation = replicaFileName(file, mode);\n deleteLiteDB(copyLocation);\n\n const start = Date.now();\n lc.info?.(`copying ${file} to ${copyLocation}`);\n const replica = new Database(lc, file);\n replica.prepare(`VACUUM INTO ?`).run(copyLocation);\n replica.close();\n lc.info?.(`finished copy (${Date.now() - start} ms)`);\n\n return prepare(lc, {...replicaOptions, file: copyLocation}, 'wal2', mode);\n }\n\n case 'serving':\n return prepare(lc, replicaOptions, 'wal2', mode);\n\n default:\n throw new Error(`Invalid ReplicaMode ${mode}`);\n }\n}\n\nexport function setUpMessageHandlers(\n lc: LogContext,\n replicator: Replicator,\n parent: Worker,\n) {\n handleSubscriptionsFrom(lc, parent, replicator);\n}\n\ntype Notification = ['notify', ReplicaState];\n\nexport function handleSubscriptionsFrom(\n lc: LogContext,\n subscriber: Worker,\n notifier: ReplicaStateNotifier,\n) {\n subscriber.onMessageType('subscribe', async () => {\n const subscription = notifier.subscribe();\n\n subscriber.on('close', () => {\n lc.debug?.(`closing replication subscription from ${subscriber.pid}`);\n subscription.cancel();\n });\n\n for await (const msg of subscription) {\n try {\n subscriber.send<Notification>(['notify', msg]);\n } catch (e) {\n const log =\n e instanceof Error &&\n 'code' in e &&\n // This can happen in a race condition if the subscribing process\n // is closed before the 'close' message is processed.\n e.code === 'ERR_IPC_CHANNEL_CLOSED'\n ? 'warn'\n : 'error';\n\n lc[log]?.(\n `error sending replicator notification to ${subscriber.pid}: ${String(e)}`,\n e,\n );\n }\n }\n });\n}\n\n/**\n * Creates a Notifier to relay notifications the notifier of another Worker.\n * This does not send the initial subscription message. Use {@link subscribeTo}\n * to initiate the subscription.\n */\nexport function createNotifierFrom(\n _lc: LogContext,\n source: Worker,\n onNotify?: (state: ReplicaState) => void,\n): Notifier {\n const notifier = new Notifier();\n source.onMessageType<Notification>('notify', msg => {\n onNotify?.(msg);\n void notifier.notifySubscribers(msg);\n });\n return notifier;\n}\n\nexport function subscribeTo(_lc: LogContext, source: Worker) {\n source.send(['subscribe', {}]);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"replicator.js","names":[],"sources":["../../../../../zero-cache/src/workers/replicator.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {SqliteError} from '@rocicorp/zero-sqlite3';\nimport {sleep} from '../../../shared/src/sleep.ts';\nimport * as v from '../../../shared/src/valita.ts';\nimport {Database} from '../../../zqlite/src/db.ts';\nimport type {ReplicaOptions} from '../config/zero-config.ts';\nimport {deleteLiteDB} from '../db/delete-lite-db.ts';\nimport {upgradeReplica} from '../services/change-source/common/replica-schema.ts';\nimport {deleteChangeLogDB} from '../services/replicator/change-log-db.ts';\nimport {Notifier} from '../services/replicator/notifier.ts';\nimport type {\n ReplicaState,\n ReplicaStateNotifier,\n Replicator,\n} from '../services/replicator/replicator.ts';\nimport {\n getAscendingEvents,\n recordEvent,\n} from '../services/replicator/schema/replication-state.ts';\nimport {\n applyPragmas,\n type PragmaConfig,\n} from '../services/replicator/write-worker-client.ts';\nimport type {Worker} from '../types/processes.ts';\n\nexport const replicaFileModeSchema = v.literalUnion(\n 'serving',\n 'serving-copy',\n 'backup',\n);\n\nexport type ReplicaFileMode = v.Infer<typeof replicaFileModeSchema>;\n\nexport type WalMode = 'wal' | 'wal2';\n\nexport function replicaFileName(replicaFile: string, mode: ReplicaFileMode) {\n return mode === 'serving-copy' ? `${replicaFile}-serving-copy` : replicaFile;\n}\n\n/**\n * Whether a replicator worker deletes the change-log file beside its replica at\n * startup.\n *\n * The change log belongs to the change-streamer, so this only ever cleans up a\n * file that nothing is writing. The predicate is deliberately the config flag\n * and nothing else: keying it on anything derived per replica -- a file mode, or\n * the retired `logsChangeStream` -- would make every replicator start unlink the\n * change-streamer's live log, because no replicator writes it any more. Paths\n * coincide whenever `fileMode !== 'serving-copy'`, so that hazard is real in the\n * shipped no-`backupURL` configuration.\n *\n * Deleting is safe when nothing writes the log: it is excluded from the\n * litestream backup, only the writer purges it, and re-enabling the writer\n * reseeds at the resume watermark.\n */\nexport function replicatorDeletesStaleChangeLog(\n sqliteChangeLogMode: string,\n): boolean {\n return sqliteChangeLogMode === 'off';\n}\n\n/**\n * The `mode=off` cleanup itself: deletes the change-log file beside `dbPath`\n * when {@link replicatorDeletesStaleChangeLog} says nothing writes it, and\n * reports whether it did. The decision and the delete live in one function so\n * that the guard test covers the call the replicator actually makes, not just\n * the predicate.\n */\nexport function deleteStaleChangeLog(\n sqliteChangeLogMode: string,\n dbPath: string,\n): boolean {\n if (!replicatorDeletesStaleChangeLog(sqliteChangeLogMode)) {\n return false;\n }\n deleteChangeLogDB(dbPath);\n return true;\n}\n\nconst MILLIS_PER_HOUR = 1000 * 60 * 60;\nconst MB = 1024 * 1024;\n\nasync function prepare(\n lc: LogContext,\n {file, vacuumIntervalHours}: ReplicaOptions,\n walMode: WalMode,\n mode: ReplicaFileMode,\n): Promise<{file: string; walMode: WalMode; pageSize: number}> {\n // Perform any upgrades to the replica in case the backup is an\n // earlier version.\n await upgradeReplica(lc, `${mode}-replica`, file);\n\n const replica = new Database(lc, file);\n let pageSize: number;\n try {\n // Switching between WAL modes (e.g. from a restored 'wal' replica to\n // 'wal2') goes through 'delete', which folds the WAL(2) files into the\n // main db. A replica already in the target mode keeps its WAL, from which\n // a litestream backup may continue (see WalKeeper).\n const [{journal_mode: journalMode}] = replica.pragma<{\n journal_mode: string;\n }>('journal_mode');\n if (journalMode !== walMode) {\n await setJournalMode(lc, replica, 'delete');\n }\n\n [{page_size: pageSize}] = replica.pragma<{page_size: number}>('page_size');\n const [{page_count: pageCount}] = replica.pragma<{page_count: number}>(\n 'page_count',\n );\n const [{freelist_count: freelistCount}] = replica.pragma<{\n freelist_count: number;\n }>('freelist_count');\n\n const dbSize = ((pageCount * pageSize) / MB).toFixed(2);\n const freelistSize = ((freelistCount * pageSize) / MB).toFixed(2);\n\n // TODO: Consider adding a freelist size or ratio based vacuum trigger.\n lc.info?.(`Size of db ${file}: ${dbSize} MB (${freelistSize} MB freeable)`);\n\n // Check for the VACUUM threshold.\n const events = getAscendingEvents(replica);\n lc.debug?.(`Runtime events for db ${file}`, {events});\n if (vacuumIntervalHours !== undefined) {\n const millisSinceLastEvent =\n Date.now() - (events.at(-1)?.timestamp.getTime() ?? 0);\n if (millisSinceLastEvent / MILLIS_PER_HOUR > vacuumIntervalHours) {\n lc.info?.(`Performing maintenance cleanup on ${file}`);\n const t0 = performance.now();\n replica.unsafeMode(true);\n try {\n replica.pragma('journal_mode = OFF');\n replica.exec('VACUUM');\n recordEvent(replica, 'vacuum');\n const t1 = performance.now();\n lc.info?.(`VACUUM completed (${t1 - t0} ms)`);\n } catch (e) {\n // Another connection holds the replica open, e.g. the WalKeeper\n // of a backup that litestream continues from the WAL. The VACUUM\n // is retried at the next startup.\n if (!(e instanceof SqliteError && e.code === 'SQLITE_BUSY')) {\n throw e;\n }\n lc.warn?.(`Skipping VACUUM of ${file}: the database is locked`, e);\n } finally {\n replica.unsafeMode(false);\n }\n }\n }\n\n await setJournalMode(lc, replica, walMode);\n\n const pragmas = getPragmaConfig(mode);\n applyPragmas(replica, pragmas);\n\n replica.pragma('optimize = 0x10002');\n lc.info?.(`optimized ${file}`);\n } finally {\n replica.close();\n }\n return {file, walMode, pageSize};\n}\n\n// Setting the journal_mode requires an exclusive lock on the replica.\n// Add resilience against random replica reads (for stats, etc.) by\n// retrying if the database is locked. Note that the busy_timeout doesn't\n// work here.\nasync function setJournalMode(\n lc: LogContext,\n replica: Database,\n mode: 'delete' | 'wal' | 'wal2',\n) {\n lc.info?.(`setting ${replica.name} to ${mode} mode`);\n let err: unknown;\n for (let i = 0; i < 5; i++) {\n try {\n replica.pragma(`journal_mode = ${mode}`);\n return;\n } catch (e) {\n lc.warn?.(`error setting journal_mode to ${mode} (attempt ${i + 1})`, e);\n err = e;\n }\n await sleep(500);\n }\n throw err;\n}\n\n/**\n * Returns the PragmaConfig for a given replica file mode.\n * This is used by both the main thread (setupReplica) and\n * the write worker thread to apply the same pragma settings.\n */\nexport function getPragmaConfig(mode: ReplicaFileMode): PragmaConfig {\n return {\n busyTimeout: 30000,\n analysisLimit: 1000,\n walAutocheckpoint: mode === 'backup' ? 0 : undefined,\n };\n}\n\nexport function setupReplica(\n lc: LogContext,\n mode: ReplicaFileMode,\n replicaOptions: ReplicaOptions,\n) {\n lc.info?.(`setting up ${mode} replica`);\n\n switch (mode) {\n case 'backup':\n return prepare(lc, replicaOptions, 'wal', mode);\n\n case 'serving-copy': {\n // In 'serving-copy' mode, the original file is being used for 'backup'\n // mode, so we make a copy for servicing sync requests.\n const {file} = replicaOptions;\n const copyLocation = replicaFileName(file, mode);\n deleteLiteDB(copyLocation);\n\n const start = Date.now();\n lc.info?.(`copying ${file} to ${copyLocation}`);\n const replica = new Database(lc, file);\n replica.prepare(`VACUUM INTO ?`).run(copyLocation);\n replica.close();\n lc.info?.(`finished copy (${Date.now() - start} ms)`);\n\n return prepare(lc, {...replicaOptions, file: copyLocation}, 'wal2', mode);\n }\n\n case 'serving':\n return prepare(lc, replicaOptions, 'wal2', mode);\n\n default:\n throw new Error(`Invalid ReplicaMode ${mode}`);\n }\n}\n\nexport function setUpMessageHandlers(\n lc: LogContext,\n replicator: Replicator,\n parent: Worker,\n) {\n handleSubscriptionsFrom(lc, parent, replicator);\n}\n\ntype Notification = ['notify', ReplicaState];\n\nexport function handleSubscriptionsFrom(\n lc: LogContext,\n subscriber: Worker,\n notifier: ReplicaStateNotifier,\n) {\n subscriber.onMessageType('subscribe', async () => {\n const subscription = notifier.subscribe();\n\n subscriber.on('close', () => {\n lc.debug?.(`closing replication subscription from ${subscriber.pid}`);\n subscription.cancel();\n });\n\n for await (const msg of subscription) {\n try {\n subscriber.send<Notification>(['notify', msg]);\n } catch (e) {\n const log =\n e instanceof Error &&\n 'code' in e &&\n // This can happen in a race condition if the subscribing process\n // is closed before the 'close' message is processed.\n e.code === 'ERR_IPC_CHANNEL_CLOSED'\n ? 'warn'\n : 'error';\n\n lc[log]?.(\n `error sending replicator notification to ${subscriber.pid}: ${String(e)}`,\n e,\n );\n }\n }\n });\n}\n\n/**\n * Creates a Notifier to relay notifications the notifier of another Worker.\n * This does not send the initial subscription message. Use {@link subscribeTo}\n * to initiate the subscription.\n */\nexport function createNotifierFrom(\n _lc: LogContext,\n source: Worker,\n onNotify?: (state: ReplicaState) => void,\n): Notifier {\n const notifier = new Notifier();\n source.onMessageType<Notification>('notify', msg => {\n onNotify?.(msg);\n void notifier.notifySubscribers(msg);\n });\n return notifier;\n}\n\nexport function subscribeTo(_lc: LogContext, source: Worker) {\n source.send(['subscribe', {}]);\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"syncer-ws-message-handler.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/workers/syncer-ws-message-handler.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAOjD,OAAO,KAAK,EAAC,gCAAgC,EAAC,MAAM,kCAAkC,CAAC;AACvF,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,gCAAgC,CAAC;AAC5D,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,+BAA+B,CAAC;AAC1D,OAAO,EACL,KAAK,wBAAwB,EAE9B,MAAM,uDAAuD,CAAC;AAC/D,OAAO,EAAC,KAAK,UAAU,EAAC,MAAM,wCAAwC,CAAC;AACvE,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,qBAAqB,CAAC;AACvD,OAAO,KAAK,EAAC,aAAa,EAAE,cAAc,EAAC,MAAM,iBAAiB,CAAC;AAiBnE,qBAAa,sBAAuB,YAAW,cAAc;;IAU3D,YACE,EAAE,EAAE,UAAU,EACd,aAAa,EAAE,aAAa,EAC5B,kBAAkB,EAAE,wBAAwB,EAC5C,UAAU,EAAE,UAAU,EACtB,OAAO,EAAE,OAAO,GAAG,SAAS,EAC5B,MAAM,EAAE,MAAM,GAAG,SAAS,EAkB3B;IAEK,aAAa,CACjB,GAAG,EAAE,gCAAgC,GACpC,OAAO,CAAC,aAAa,EAAE,CAAC,CAkN1B;CACF"}
1
+ {"version":3,"file":"syncer-ws-message-handler.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/workers/syncer-ws-message-handler.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAOjD,OAAO,KAAK,EAAC,gCAAgC,EAAC,MAAM,kCAAkC,CAAC;AACvF,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,gCAAgC,CAAC;AAC5D,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,+BAA+B,CAAC;AAC1D,OAAO,EACL,KAAK,wBAAwB,EAE9B,MAAM,uDAAuD,CAAC;AAC/D,OAAO,EAAC,KAAK,UAAU,EAAC,MAAM,wCAAwC,CAAC;AACvE,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,qBAAqB,CAAC;AACvD,OAAO,KAAK,EAAC,aAAa,EAAE,cAAc,EAAC,MAAM,iBAAiB,CAAC;AAiBnE,qBAAa,sBAAuB,YAAW,cAAc;;IAU3D,YACE,EAAE,EAAE,UAAU,EACd,aAAa,EAAE,aAAa,EAC5B,kBAAkB,EAAE,wBAAwB,EAC5C,UAAU,EAAE,UAAU,EACtB,OAAO,EAAE,OAAO,GAAG,SAAS,EAC5B,MAAM,EAAE,MAAM,GAAG,SAAS,EAkB3B;IAEK,aAAa,CACjB,GAAG,EAAE,gCAAgC,GACpC,OAAO,CAAC,aAAa,EAAE,CAAC,CA6N1B;CACF"}
@@ -86,22 +86,27 @@ var SyncerWsMessageHandler = class {
86
86
  }];
87
87
  const auth = this.#connContextManager.mustGetConnectionContext(this.#connectionSelector).auth;
88
88
  assert(auth?.type !== "opaque", "Only JWT auth is supported for CRUD mutations");
89
- return [await this.#mutationLock.withLock(async () => {
90
- const errors = [];
91
- for (const mutation of mutations) {
92
- const maybeError = await mutagen.processMutation(mutation, auth?.decoded, this.#pusher !== void 0);
93
- if (maybeError !== void 0) errors.push({
94
- kind: maybeError[0],
95
- message: maybeError[1],
96
- origin: ZeroCache
97
- });
98
- }
99
- if (errors.length > 0) return {
100
- type: "transient",
101
- errors
102
- };
103
- return { type: "ok" };
104
- })];
89
+ mutagen.ref();
90
+ try {
91
+ return [await this.#mutationLock.withLock(async () => {
92
+ const errors = [];
93
+ for (const mutation of mutations) {
94
+ const maybeError = await mutagen.processMutation(mutation, auth?.decoded, this.#pusher !== void 0);
95
+ if (maybeError !== void 0) errors.push({
96
+ kind: maybeError[0],
97
+ message: maybeError[1],
98
+ origin: ZeroCache
99
+ });
100
+ }
101
+ if (errors.length > 0) return {
102
+ type: "transient",
103
+ errors
104
+ };
105
+ return { type: "ok" };
106
+ })];
107
+ } finally {
108
+ mutagen.unref();
109
+ }
105
110
  }));
106
111
  case "changeDesiredQueries":
107
112
  await withTraceparent(msg[1].traceparent, () => startAsyncSpan(tracer, "connection.changeDesiredQueries", () => viewSyncer.changeDesiredQueries(this.#connectionSelector, msg)));
@@ -1 +1 @@
1
- {"version":3,"file":"syncer-ws-message-handler.js","names":["#viewSyncer","#mutagen","#mutationLock","#lc","#clientGroupID","#connectionSelector","#connContextManager","#pusher"],"sources":["../../../../../zero-cache/src/workers/syncer-ws-message-handler.ts"],"sourcesContent":["import {ROOT_CONTEXT, context, propagation, trace} from '@opentelemetry/api';\nimport {Lock} from '@rocicorp/lock';\nimport type {LogContext} from '@rocicorp/logger';\nimport {startAsyncSpan, startSpan} from '../../../otel/src/span.ts';\nimport {version} from '../../../otel/src/version.ts';\nimport {assert, unreachable} from '../../../shared/src/asserts.ts';\nimport {ErrorKind} from '../../../zero-protocol/src/error-kind.ts';\nimport {ErrorOrigin} from '../../../zero-protocol/src/error-origin.ts';\nimport type {ErrorBody} from '../../../zero-protocol/src/error.ts';\nimport type {UpstreamWithUnparsedAnalyzeQuery} from '../../../zero-protocol/src/up.ts';\nimport type {Mutagen} from '../services/mutagen/mutagen.ts';\nimport type {Pusher} from '../services/mutagen/pusher.ts';\nimport {\n type ConnectionContextManager,\n type ConnectionSelector,\n} from '../services/view-syncer/connection-context-manager.ts';\nimport {type ViewSyncer} from '../services/view-syncer/view-syncer.ts';\nimport type {ConnectParams} from './connect-params.ts';\nimport type {HandlerResult, MessageHandler} from './connection.ts';\n\nconst tracer = trace.getTracer('syncer-ws-server', version);\n\n/**\n * Wraps a function in an OTEL context extracted from a W3C traceparent header.\n * This enables distributed tracing from the client through zero-cache to\n * the user's API server.\n */\nfunction withTraceparent<T>(traceparent: string | undefined, fn: () => T): T {\n if (!traceparent) {\n return fn();\n }\n const extracted = propagation.extract(ROOT_CONTEXT, {traceparent});\n return context.with(extracted, fn);\n}\n\nexport class SyncerWsMessageHandler implements MessageHandler {\n readonly #viewSyncer: ViewSyncer;\n readonly #mutagen: Mutagen | undefined;\n readonly #mutationLock: Lock;\n readonly #lc: LogContext;\n readonly #clientGroupID: string;\n readonly #connectionSelector: ConnectionSelector;\n readonly #connContextManager: ConnectionContextManager;\n readonly #pusher: Pusher | undefined;\n\n constructor(\n lc: LogContext,\n connectParams: ConnectParams,\n connContextManager: ConnectionContextManager,\n viewSyncer: ViewSyncer,\n mutagen: Mutagen | undefined,\n pusher: Pusher | undefined,\n ) {\n const {clientGroupID, clientID, wsID} = connectParams;\n this.#viewSyncer = viewSyncer;\n this.#mutagen = mutagen;\n this.#connContextManager = connContextManager;\n this.#mutationLock = new Lock();\n this.#lc = lc\n .withContext('connection')\n .withContext('clientID', clientID)\n .withContext('clientGroupID', clientGroupID)\n .withContext('wsID', wsID);\n this.#clientGroupID = clientGroupID;\n this.#pusher = pusher;\n this.#connectionSelector = {\n clientID,\n wsID,\n };\n }\n\n async handleMessage(\n msg: UpstreamWithUnparsedAnalyzeQuery,\n ): Promise<HandlerResult[]> {\n const lc = this.#lc;\n const msgType = msg[0];\n const viewSyncer = this.#viewSyncer;\n switch (msgType) {\n case 'ping':\n lc.error?.('Ping is not supported at this layer by Zero');\n break;\n case 'pull':\n lc.error?.('Pull is not supported by Zero');\n break;\n case 'push': {\n return withTraceparent(msg[1].traceparent, () =>\n startAsyncSpan<HandlerResult[]>(\n tracer,\n 'connection.push',\n async () => {\n const {clientGroupID, mutations} = msg[1];\n if (clientGroupID !== this.#clientGroupID) {\n return [\n {\n type: 'fatal',\n error: {\n kind: ErrorKind.InvalidPush,\n message:\n `clientGroupID in mutation \"${clientGroupID}\" does not match ` +\n `clientGroupID of connection \"${this.#clientGroupID}`,\n origin: ErrorOrigin.ZeroCache,\n },\n } satisfies HandlerResult,\n ];\n }\n\n if (mutations.length === 0) {\n return [\n {\n type: 'ok',\n },\n ];\n }\n\n // The client only ever sends 1 mutation per push.\n // #pusher will throw if it sees a CRUD mutation.\n // #mutagen will throw if it see a custom mutation.\n if (mutations[0].type === 'custom') {\n if (!this.#pusher) {\n return [\n {\n type: 'fatal',\n error: {\n kind: ErrorKind.InvalidPush,\n message:\n 'A ZERO_MUTATE_URL must be set in order to process custom mutations.',\n origin: ErrorOrigin.ZeroCache,\n },\n } satisfies HandlerResult,\n ];\n }\n return [\n this.#pusher.enqueuePush(this.#connectionSelector, msg[1]),\n ];\n }\n\n const mutagen = this.#mutagen;\n if (!mutagen) {\n return [\n {\n type: 'fatal',\n error: {\n kind: ErrorKind.InvalidPush,\n message: `Support for legacy CRUD mutations is disabled`,\n origin: ErrorOrigin.ZeroCache,\n },\n } satisfies HandlerResult,\n ];\n }\n\n const auth = this.#connContextManager.mustGetConnectionContext(\n this.#connectionSelector,\n ).auth;\n assert(\n auth?.type !== 'opaque',\n 'Only JWT auth is supported for CRUD mutations',\n );\n\n // Hold a connection-level lock while processing mutations so that:\n // 1. Mutations are processed in the order in which they are received and\n // 2. A single view syncer connection cannot hog multiple upstream connections.\n const ret = await this.#mutationLock.withLock(async () => {\n const errors: ErrorBody[] = [];\n for (const mutation of mutations) {\n const maybeError = await mutagen.processMutation(\n mutation,\n auth?.decoded,\n this.#pusher !== undefined,\n );\n if (maybeError !== undefined) {\n errors.push({\n kind: maybeError[0],\n message: maybeError[1],\n origin: ErrorOrigin.ZeroCache,\n });\n }\n }\n if (errors.length > 0) {\n return {type: 'transient', errors} satisfies HandlerResult;\n }\n return {type: 'ok'} satisfies HandlerResult;\n });\n return [ret];\n },\n ),\n );\n }\n case 'changeDesiredQueries':\n await withTraceparent(msg[1].traceparent, () =>\n startAsyncSpan(tracer, 'connection.changeDesiredQueries', () =>\n viewSyncer.changeDesiredQueries(this.#connectionSelector, msg),\n ),\n );\n break;\n case 'updateAuth':\n await startAsyncSpan(tracer, 'connection.updateAuth', async () => {\n const initialConnCtx =\n this.#connContextManager.mustGetConnectionContext(\n this.#connectionSelector,\n );\n const updatedConnCtx = await this.#connContextManager.updateAuth(\n this.#connectionSelector,\n msg[1],\n );\n const authRevisionChanged =\n updatedConnCtx.revision !== initialConnCtx.revision;\n\n await viewSyncer.updateAuth(\n this.#connectionSelector,\n msg,\n authRevisionChanged,\n );\n });\n break;\n case 'deleteClients': {\n const deletedClientIDs = await startAsyncSpan(\n tracer,\n 'connection.deleteClients',\n () => viewSyncer.deleteClients(this.#connectionSelector, msg),\n );\n if (this.#pusher && deletedClientIDs.length > 0) {\n await this.#pusher.deleteClientMutations(\n this.#connectionSelector,\n deletedClientIDs,\n );\n }\n break;\n }\n case 'initConnection': {\n this.#connContextManager.initConnection(\n this.#connectionSelector,\n msg[1],\n );\n return withTraceparent(msg[1].traceparent, () => {\n const ret: HandlerResult[] = [\n {\n type: 'stream',\n source: 'viewSyncer',\n stream: startSpan(tracer, 'connection.initConnection', () =>\n viewSyncer.initConnection(this.#connectionSelector, msg),\n ),\n },\n ];\n\n // Given we support both CRUD and Custom mutators,\n // we do not initialize the `pusher` unless the user has opted\n // into custom mutations. We detect that by checking\n // if the pushURL has been set.\n if (this.#pusher) {\n ret.push({\n type: 'stream',\n source: 'pusher',\n stream: this.#pusher.initConnection(this.#connectionSelector),\n });\n }\n\n return ret;\n });\n }\n case 'closeConnection':\n // This message is deprecated and no longer used.\n break;\n\n case 'inspect':\n await startAsyncSpan(tracer, 'connection.inspect', () =>\n viewSyncer.inspect(this.#connectionSelector, msg),\n );\n break;\n\n case 'ackMutationResponses':\n if (this.#pusher) {\n await this.#pusher.ackMutationResponses(\n this.#connectionSelector,\n msg[1],\n );\n }\n break;\n\n default:\n unreachable(msgType);\n }\n\n return [{type: 'ok'}];\n }\n}\n"],"mappings":";;;;;;;;;;AAoBA,IAAM,SAAS,MAAM,UAAU,oBAAoB,OAAO;;;;;;AAO1D,SAAS,gBAAmB,aAAiC,IAAgB;CAC3E,IAAI,CAAC,aACH,OAAO,GAAG;CAEZ,MAAM,YAAY,YAAY,QAAQ,cAAc,EAAC,YAAW,CAAC;CACjE,OAAO,QAAQ,KAAK,WAAW,EAAE;AACnC;AAEA,IAAa,yBAAb,MAA8D;CAC5D;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CAEA,YACE,IACA,eACA,oBACA,YACA,SACA,QACA;EACA,MAAM,EAAC,eAAe,UAAU,SAAQ;EACxC,KAAKA,cAAc;EACnB,KAAKC,WAAW;EAChB,KAAKK,sBAAsB;EAC3B,KAAKJ,gBAAgB,IAAI,KAAK;EAC9B,KAAKC,MAAM,GACR,YAAY,YAAY,EACxB,YAAY,YAAY,QAAQ,EAChC,YAAY,iBAAiB,aAAa,EAC1C,YAAY,QAAQ,IAAI;EAC3B,KAAKC,iBAAiB;EACtB,KAAKG,UAAU;EACf,KAAKF,sBAAsB;GACzB;GACA;EACF;CACF;CAEA,MAAM,cACJ,KAC0B;EAC1B,MAAM,KAAK,KAAKF;EAChB,MAAM,UAAU,IAAI;EACpB,MAAM,aAAa,KAAKH;EACxB,QAAQ,SAAR;GACE,KAAK;IACH,GAAG,QAAQ,6CAA6C;IACxD;GACF,KAAK;IACH,GAAG,QAAQ,+BAA+B;IAC1C;GACF,KAAK,QACH,OAAO,gBAAgB,IAAI,GAAG,mBAC5B,eACE,QACA,mBACA,YAAY;IACV,MAAM,EAAC,eAAe,cAAa,IAAI;IACvC,IAAI,kBAAkB,KAAKI,gBACzB,OAAO,CACL;KACE,MAAM;KACN,OAAO;MACL,MAAM;MACN,SACE,8BAA8B,cAAc,gDACZ,KAAKA;MACvC,QAAQ;KACV;IACF,CACF;IAGF,IAAI,UAAU,WAAW,GACvB,OAAO,CACL,EACE,MAAM,KACR,CACF;IAMF,IAAI,UAAU,GAAG,SAAS,UAAU;KAClC,IAAI,CAAC,KAAKG,SACR,OAAO,CACL;MACE,MAAM;MACN,OAAO;OACL,MAAM;OACN,SACE;OACF,QAAQ;MACV;KACF,CACF;KAEF,OAAO,CACL,KAAKA,QAAQ,YAAY,KAAKF,qBAAqB,IAAI,EAAE,CAC3D;IACF;IAEA,MAAM,UAAU,KAAKJ;IACrB,IAAI,CAAC,SACH,OAAO,CACL;KACE,MAAM;KACN,OAAO;MACL,MAAM;MACN,SAAS;MACT,QAAQ;KACV;IACF,CACF;IAGF,MAAM,OAAO,KAAKK,oBAAoB,yBACpC,KAAKD,mBACP,EAAE;IACF,OACE,MAAM,SAAS,UACf,+CACF;IA0BA,OAAO,CAAC,MArBU,KAAKH,cAAc,SAAS,YAAY;KACxD,MAAM,SAAsB,CAAC;KAC7B,KAAK,MAAM,YAAY,WAAW;MAChC,MAAM,aAAa,MAAM,QAAQ,gBAC/B,UACA,MAAM,SACN,KAAKK,YAAY,KAAA,CACnB;MACA,IAAI,eAAe,KAAA,GACjB,OAAO,KAAK;OACV,MAAM,WAAW;OACjB,SAAS,WAAW;OACpB,QAAQ;MACV,CAAC;KAEL;KACA,IAAI,OAAO,SAAS,GAClB,OAAO;MAAC,MAAM;MAAa;KAAM;KAEnC,OAAO,EAAC,MAAM,KAAI;IACpB,CAAC,CACU;GACb,CACF,CACF;GAEF,KAAK;IACH,MAAM,gBAAgB,IAAI,GAAG,mBAC3B,eAAe,QAAQ,yCACrB,WAAW,qBAAqB,KAAKF,qBAAqB,GAAG,CAC/D,CACF;IACA;GACF,KAAK;IACH,MAAM,eAAe,QAAQ,yBAAyB,YAAY;KAChE,MAAM,iBACJ,KAAKC,oBAAoB,yBACvB,KAAKD,mBACP;KAKF,MAAM,uBACJ,MAL2B,KAAKC,oBAAoB,WACpD,KAAKD,qBACL,IAAI,EACN,GAEiB,aAAa,eAAe;KAE7C,MAAM,WAAW,WACf,KAAKA,qBACL,KACA,mBACF;IACF,CAAC;IACD;GACF,KAAK,iBAAiB;IACpB,MAAM,mBAAmB,MAAM,eAC7B,QACA,kCACM,WAAW,cAAc,KAAKA,qBAAqB,GAAG,CAC9D;IACA,IAAI,KAAKE,WAAW,iBAAiB,SAAS,GAC5C,MAAM,KAAKA,QAAQ,sBACjB,KAAKF,qBACL,gBACF;IAEF;GACF;GACA,KAAK;IACH,KAAKC,oBAAoB,eACvB,KAAKD,qBACL,IAAI,EACN;IACA,OAAO,gBAAgB,IAAI,GAAG,mBAAmB;KAC/C,MAAM,MAAuB,CAC3B;MACE,MAAM;MACN,QAAQ;MACR,QAAQ,UAAU,QAAQ,mCACxB,WAAW,eAAe,KAAKA,qBAAqB,GAAG,CACzD;KACF,CACF;KAMA,IAAI,KAAKE,SACP,IAAI,KAAK;MACP,MAAM;MACN,QAAQ;MACR,QAAQ,KAAKA,QAAQ,eAAe,KAAKF,mBAAmB;KAC9D,CAAC;KAGH,OAAO;IACT,CAAC;GAEH,KAAK,mBAEH;GAEF,KAAK;IACH,MAAM,eAAe,QAAQ,4BAC3B,WAAW,QAAQ,KAAKA,qBAAqB,GAAG,CAClD;IACA;GAEF,KAAK;IACH,IAAI,KAAKE,SACP,MAAM,KAAKA,QAAQ,qBACjB,KAAKF,qBACL,IAAI,EACN;IAEF;GAEF,SACE,YAAY,OAAO;EACvB;EAEA,OAAO,CAAC,EAAC,MAAM,KAAI,CAAC;CACtB;AACF"}
1
+ {"version":3,"file":"syncer-ws-message-handler.js","names":["#viewSyncer","#mutagen","#mutationLock","#lc","#clientGroupID","#connectionSelector","#connContextManager","#pusher"],"sources":["../../../../../zero-cache/src/workers/syncer-ws-message-handler.ts"],"sourcesContent":["import {ROOT_CONTEXT, context, propagation, trace} from '@opentelemetry/api';\nimport {Lock} from '@rocicorp/lock';\nimport type {LogContext} from '@rocicorp/logger';\nimport {startAsyncSpan, startSpan} from '../../../otel/src/span.ts';\nimport {version} from '../../../otel/src/version.ts';\nimport {assert, unreachable} from '../../../shared/src/asserts.ts';\nimport {ErrorKind} from '../../../zero-protocol/src/error-kind.ts';\nimport {ErrorOrigin} from '../../../zero-protocol/src/error-origin.ts';\nimport type {ErrorBody} from '../../../zero-protocol/src/error.ts';\nimport type {UpstreamWithUnparsedAnalyzeQuery} from '../../../zero-protocol/src/up.ts';\nimport type {Mutagen} from '../services/mutagen/mutagen.ts';\nimport type {Pusher} from '../services/mutagen/pusher.ts';\nimport {\n type ConnectionContextManager,\n type ConnectionSelector,\n} from '../services/view-syncer/connection-context-manager.ts';\nimport {type ViewSyncer} from '../services/view-syncer/view-syncer.ts';\nimport type {ConnectParams} from './connect-params.ts';\nimport type {HandlerResult, MessageHandler} from './connection.ts';\n\nconst tracer = trace.getTracer('syncer-ws-server', version);\n\n/**\n * Wraps a function in an OTEL context extracted from a W3C traceparent header.\n * This enables distributed tracing from the client through zero-cache to\n * the user's API server.\n */\nfunction withTraceparent<T>(traceparent: string | undefined, fn: () => T): T {\n if (!traceparent) {\n return fn();\n }\n const extracted = propagation.extract(ROOT_CONTEXT, {traceparent});\n return context.with(extracted, fn);\n}\n\nexport class SyncerWsMessageHandler implements MessageHandler {\n readonly #viewSyncer: ViewSyncer;\n readonly #mutagen: Mutagen | undefined;\n readonly #mutationLock: Lock;\n readonly #lc: LogContext;\n readonly #clientGroupID: string;\n readonly #connectionSelector: ConnectionSelector;\n readonly #connContextManager: ConnectionContextManager;\n readonly #pusher: Pusher | undefined;\n\n constructor(\n lc: LogContext,\n connectParams: ConnectParams,\n connContextManager: ConnectionContextManager,\n viewSyncer: ViewSyncer,\n mutagen: Mutagen | undefined,\n pusher: Pusher | undefined,\n ) {\n const {clientGroupID, clientID, wsID} = connectParams;\n this.#viewSyncer = viewSyncer;\n this.#mutagen = mutagen;\n this.#connContextManager = connContextManager;\n this.#mutationLock = new Lock();\n this.#lc = lc\n .withContext('connection')\n .withContext('clientID', clientID)\n .withContext('clientGroupID', clientGroupID)\n .withContext('wsID', wsID);\n this.#clientGroupID = clientGroupID;\n this.#pusher = pusher;\n this.#connectionSelector = {\n clientID,\n wsID,\n };\n }\n\n async handleMessage(\n msg: UpstreamWithUnparsedAnalyzeQuery,\n ): Promise<HandlerResult[]> {\n const lc = this.#lc;\n const msgType = msg[0];\n const viewSyncer = this.#viewSyncer;\n switch (msgType) {\n case 'ping':\n lc.error?.('Ping is not supported at this layer by Zero');\n break;\n case 'pull':\n lc.error?.('Pull is not supported by Zero');\n break;\n case 'push': {\n return withTraceparent(msg[1].traceparent, () =>\n startAsyncSpan<HandlerResult[]>(\n tracer,\n 'connection.push',\n async () => {\n const {clientGroupID, mutations} = msg[1];\n if (clientGroupID !== this.#clientGroupID) {\n return [\n {\n type: 'fatal',\n error: {\n kind: ErrorKind.InvalidPush,\n message:\n `clientGroupID in mutation \"${clientGroupID}\" does not match ` +\n `clientGroupID of connection \"${this.#clientGroupID}`,\n origin: ErrorOrigin.ZeroCache,\n },\n } satisfies HandlerResult,\n ];\n }\n\n if (mutations.length === 0) {\n return [\n {\n type: 'ok',\n },\n ];\n }\n\n // The client only ever sends 1 mutation per push.\n // #pusher will throw if it sees a CRUD mutation.\n // #mutagen will throw if it see a custom mutation.\n if (mutations[0].type === 'custom') {\n if (!this.#pusher) {\n return [\n {\n type: 'fatal',\n error: {\n kind: ErrorKind.InvalidPush,\n message:\n 'A ZERO_MUTATE_URL must be set in order to process custom mutations.',\n origin: ErrorOrigin.ZeroCache,\n },\n } satisfies HandlerResult,\n ];\n }\n return [\n this.#pusher.enqueuePush(this.#connectionSelector, msg[1]),\n ];\n }\n\n const mutagen = this.#mutagen;\n if (!mutagen) {\n return [\n {\n type: 'fatal',\n error: {\n kind: ErrorKind.InvalidPush,\n message: `Support for legacy CRUD mutations is disabled`,\n origin: ErrorOrigin.ZeroCache,\n },\n } satisfies HandlerResult,\n ];\n }\n\n const auth = this.#connContextManager.mustGetConnectionContext(\n this.#connectionSelector,\n ).auth;\n assert(\n auth?.type !== 'opaque',\n 'Only JWT auth is supported for CRUD mutations',\n );\n\n // Hold a ref on the mutagen for the duration of the push so that\n // the connection closing mid-push does not stop the service\n // (closing its replica handle) between two of its mutations.\n // (The connection holds a ref while open, and messages are not\n // dispatched after it has closed, so the service is running\n // here.)\n mutagen.ref();\n try {\n // Hold a connection-level lock while processing mutations so that:\n // 1. Mutations are processed in the order in which they are received and\n // 2. A single view syncer connection cannot hog multiple upstream connections.\n const ret = await this.#mutationLock.withLock(async () => {\n const errors: ErrorBody[] = [];\n for (const mutation of mutations) {\n const maybeError = await mutagen.processMutation(\n mutation,\n auth?.decoded,\n this.#pusher !== undefined,\n );\n if (maybeError !== undefined) {\n errors.push({\n kind: maybeError[0],\n message: maybeError[1],\n origin: ErrorOrigin.ZeroCache,\n });\n }\n }\n if (errors.length > 0) {\n return {type: 'transient', errors} satisfies HandlerResult;\n }\n return {type: 'ok'} satisfies HandlerResult;\n });\n return [ret];\n } finally {\n mutagen.unref();\n }\n },\n ),\n );\n }\n case 'changeDesiredQueries':\n await withTraceparent(msg[1].traceparent, () =>\n startAsyncSpan(tracer, 'connection.changeDesiredQueries', () =>\n viewSyncer.changeDesiredQueries(this.#connectionSelector, msg),\n ),\n );\n break;\n case 'updateAuth':\n await startAsyncSpan(tracer, 'connection.updateAuth', async () => {\n const initialConnCtx =\n this.#connContextManager.mustGetConnectionContext(\n this.#connectionSelector,\n );\n const updatedConnCtx = await this.#connContextManager.updateAuth(\n this.#connectionSelector,\n msg[1],\n );\n const authRevisionChanged =\n updatedConnCtx.revision !== initialConnCtx.revision;\n\n await viewSyncer.updateAuth(\n this.#connectionSelector,\n msg,\n authRevisionChanged,\n );\n });\n break;\n case 'deleteClients': {\n const deletedClientIDs = await startAsyncSpan(\n tracer,\n 'connection.deleteClients',\n () => viewSyncer.deleteClients(this.#connectionSelector, msg),\n );\n if (this.#pusher && deletedClientIDs.length > 0) {\n await this.#pusher.deleteClientMutations(\n this.#connectionSelector,\n deletedClientIDs,\n );\n }\n break;\n }\n case 'initConnection': {\n this.#connContextManager.initConnection(\n this.#connectionSelector,\n msg[1],\n );\n return withTraceparent(msg[1].traceparent, () => {\n const ret: HandlerResult[] = [\n {\n type: 'stream',\n source: 'viewSyncer',\n stream: startSpan(tracer, 'connection.initConnection', () =>\n viewSyncer.initConnection(this.#connectionSelector, msg),\n ),\n },\n ];\n\n // Given we support both CRUD and Custom mutators,\n // we do not initialize the `pusher` unless the user has opted\n // into custom mutations. We detect that by checking\n // if the pushURL has been set.\n if (this.#pusher) {\n ret.push({\n type: 'stream',\n source: 'pusher',\n stream: this.#pusher.initConnection(this.#connectionSelector),\n });\n }\n\n return ret;\n });\n }\n case 'closeConnection':\n // This message is deprecated and no longer used.\n break;\n\n case 'inspect':\n await startAsyncSpan(tracer, 'connection.inspect', () =>\n viewSyncer.inspect(this.#connectionSelector, msg),\n );\n break;\n\n case 'ackMutationResponses':\n if (this.#pusher) {\n await this.#pusher.ackMutationResponses(\n this.#connectionSelector,\n msg[1],\n );\n }\n break;\n\n default:\n unreachable(msgType);\n }\n\n return [{type: 'ok'}];\n }\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"syncer.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/workers/syncer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"syncer.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/workers/syncer.ts"],"names":[],"mappings":"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"}
@@ -14,7 +14,7 @@ import { DrainCoordinator } from "../services/view-syncer/drain-coordinator.js";
14
14
  import { Connection, sendError } from "./connection.js";
15
15
  import { SyncerWsMessageHandler } from "./syncer-ws-message-handler.js";
16
16
  import { resolver } from "@rocicorp/resolver";
17
- import { WebSocketServer } from "ws";
17
+ import { WebSocket, WebSocketServer } from "ws";
18
18
  import { pid } from "node:process";
19
19
  //#region ../zero-cache/src/workers/syncer.ts
20
20
  function computePipelineDedupStats(viewSyncers) {
@@ -153,6 +153,8 @@ var Syncer = class {
153
153
  #mutagens;
154
154
  #pushers;
155
155
  #connections = /* @__PURE__ */ new Map();
156
+ #pendingConnections = /* @__PURE__ */ new Map();
157
+ #clientGroupGenerations = /* @__PURE__ */ new Map();
156
158
  #drainCoordinator = new DrainCoordinator();
157
159
  #parent;
158
160
  #wss;
@@ -178,12 +180,30 @@ var Syncer = class {
178
180
  const notifier = createNotifierFrom(lc, parent, (state) => this.#recordReplicaReadyState(state));
179
181
  subscribeTo(lc, parent);
180
182
  this.#lc = lc;
181
- this.#viewSyncers = new ServiceRunner(lc, (id) => viewSyncerFactory(id, notifier.subscribe(), this.#drainCoordinator), (v) => v.keepalive());
183
+ this.#parent = parent;
184
+ this.#viewSyncers = new ServiceRunner(lc, (id) => viewSyncerFactory(id, notifier.subscribe(), this.#drainCoordinator), (v) => v.keepalive(), (id) => {
185
+ if ((this.#pendingConnections.get(id) ?? 0) === 0) {
186
+ const generation = this.#clientGroupGenerations.get(id);
187
+ this.#parent.send(["clientGroupStatus", {
188
+ clientGroupID: id,
189
+ active: false,
190
+ ...generation !== void 0 ? { generation } : {}
191
+ }]);
192
+ this.#clientGroupGenerations.delete(id);
193
+ }
194
+ });
182
195
  if (mutagenFactory) this.#mutagens = new ServiceRunner(lc, mutagenFactory, (m) => m.hasRefs());
183
196
  if (pusherFactory) this.#pushers = new ServiceRunner(lc, (id) => pusherFactory(id, this.#viewSyncers.getService(id).connContextManager), (p) => p.hasRefs());
184
- this.#parent = parent;
185
197
  this.#wss = new WebSocketServer(getWebSocketServerOptions(config));
186
- installWebSocketReceiver(lc, this.#wss, this.#createConnection, this.#parent);
198
+ installWebSocketReceiver(lc, this.#wss, this.#receiveConnection, this.#parent, (params) => {
199
+ this.#releasePending(params.clientGroupID, params.generation);
200
+ }, (params) => {
201
+ this.#pendingConnections.set(params.clientGroupID, (this.#pendingConnections.get(params.clientGroupID) ?? 0) + 1);
202
+ if (params.generation !== void 0) {
203
+ const current = this.#clientGroupGenerations.get(params.clientGroupID);
204
+ if (current === void 0 || params.generation > current) this.#clientGroupGenerations.set(params.clientGroupID, params.generation);
205
+ }
206
+ });
187
207
  setActiveClientGroupsGetter(() => this.#viewSyncers.size);
188
208
  getOrCreateGauge("sync", "active-client-groups", "Number of active client groups").addCallback((result) => result.observe(this.#viewSyncers.size));
189
209
  getOrCreateGauge("sync", "queries", "Active queries (pipelines) across all client groups").addCallback((result) => {
@@ -341,6 +361,15 @@ var Syncer = class {
341
361
  recordConnectionFailure("internal");
342
362
  throw e;
343
363
  }
364
+ if (ws.readyState !== WebSocket.OPEN) {
365
+ this.#lc.debug?.("websocket closed while resolving auth", {
366
+ clientGroupID,
367
+ clientID,
368
+ readyState: ws.readyState
369
+ });
370
+ recordConnectionFailure("closed_during_auth");
371
+ return;
372
+ }
344
373
  const viewSyncer = this.#viewSyncers.getService(clientGroupID);
345
374
  const connContextManager = viewSyncer.connContextManager;
346
375
  const group = connContextManager.getGroupState();
@@ -399,6 +428,28 @@ var Syncer = class {
399
428
  await connection.handleInitConnection(JSON.stringify(params.initConnectionMsg));
400
429
  }
401
430
  };
431
+ #receiveConnection = async (ws, params) => {
432
+ try {
433
+ await this.#createConnection(ws, params);
434
+ } finally {
435
+ this.#releasePending(params.clientGroupID, params.generation);
436
+ }
437
+ };
438
+ #releasePending(clientGroupID, generation) {
439
+ const remaining = (this.#pendingConnections.get(clientGroupID) ?? 1) - 1;
440
+ if (remaining <= 0) {
441
+ this.#pendingConnections.delete(clientGroupID);
442
+ if (!this.#viewSyncers.hasService(clientGroupID)) {
443
+ const gen = this.#clientGroupGenerations.get(clientGroupID) ?? generation;
444
+ this.#parent.send(["clientGroupStatus", {
445
+ clientGroupID,
446
+ active: false,
447
+ ...gen !== void 0 ? { generation: gen } : {}
448
+ }]);
449
+ this.#clientGroupGenerations.delete(clientGroupID);
450
+ }
451
+ } else this.#pendingConnections.set(clientGroupID, remaining);
452
+ }
402
453
  run() {
403
454
  return this.#stopped.promise;
404
455
  }