@rocicorp/zero 1.10.0-canary.2 → 1.10.0-canary.20

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 (372) hide show
  1. package/out/replicache/src/btree/read.d.ts +12 -1
  2. package/out/replicache/src/btree/read.d.ts.map +1 -1
  3. package/out/replicache/src/btree/read.js +24 -12
  4. package/out/replicache/src/btree/read.js.map +1 -1
  5. package/out/replicache/src/db/write.js.map +1 -1
  6. package/out/replicache/src/kv/expo-sqlite/store.d.ts.map +1 -1
  7. package/out/replicache/src/kv/expo-sqlite/store.js +27 -4
  8. package/out/replicache/src/kv/expo-sqlite/store.js.map +1 -1
  9. package/out/replicache/src/kv/sqlite-store.d.ts +11 -0
  10. package/out/replicache/src/kv/sqlite-store.d.ts.map +1 -1
  11. package/out/replicache/src/kv/sqlite-store.js +43 -3
  12. package/out/replicache/src/kv/sqlite-store.js.map +1 -1
  13. package/out/replicache/src/replicache-impl.d.ts.map +1 -1
  14. package/out/replicache/src/replicache-impl.js +10 -0
  15. package/out/replicache/src/replicache-impl.js.map +1 -1
  16. package/out/replicache/src/transactions.d.ts.map +1 -1
  17. package/out/replicache/src/transactions.js +1 -1
  18. package/out/replicache/src/transactions.js.map +1 -1
  19. package/out/shared/src/error.d.ts +11 -0
  20. package/out/shared/src/error.d.ts.map +1 -1
  21. package/out/shared/src/error.js +35 -1
  22. package/out/shared/src/error.js.map +1 -1
  23. package/out/shared/src/hash.d.ts.map +1 -1
  24. package/out/shared/src/hash.js +105 -10
  25. package/out/shared/src/hash.js.map +1 -1
  26. package/out/shared/src/map.d.ts +7 -2
  27. package/out/shared/src/map.d.ts.map +1 -1
  28. package/out/shared/src/map.js.map +1 -1
  29. package/out/shared/src/promise-race.d.ts +14 -0
  30. package/out/shared/src/promise-race.d.ts.map +1 -1
  31. package/out/shared/src/promise-race.js +32 -1
  32. package/out/shared/src/promise-race.js.map +1 -1
  33. package/out/zero/package.js +2 -3
  34. package/out/zero/package.js.map +1 -1
  35. package/out/zero-cache/src/auth/write-authorizer.d.ts.map +1 -1
  36. package/out/zero-cache/src/auth/write-authorizer.js +8 -1
  37. package/out/zero-cache/src/auth/write-authorizer.js.map +1 -1
  38. package/out/zero-cache/src/config/normalize.d.ts +5 -0
  39. package/out/zero-cache/src/config/normalize.d.ts.map +1 -1
  40. package/out/zero-cache/src/config/normalize.js +16 -3
  41. package/out/zero-cache/src/config/normalize.js.map +1 -1
  42. package/out/zero-cache/src/config/zero-config.d.ts +36 -7
  43. package/out/zero-cache/src/config/zero-config.d.ts.map +1 -1
  44. package/out/zero-cache/src/config/zero-config.js +121 -46
  45. package/out/zero-cache/src/config/zero-config.js.map +1 -1
  46. package/out/zero-cache/src/db/create.d.ts.map +1 -1
  47. package/out/zero-cache/src/db/create.js +4 -1
  48. package/out/zero-cache/src/db/create.js.map +1 -1
  49. package/out/zero-cache/src/db/index-predicate.d.ts +4 -0
  50. package/out/zero-cache/src/db/index-predicate.d.ts.map +1 -0
  51. package/out/zero-cache/src/db/index-predicate.js +46 -0
  52. package/out/zero-cache/src/db/index-predicate.js.map +1 -0
  53. package/out/zero-cache/src/db/lite-tables.d.ts +10 -2
  54. package/out/zero-cache/src/db/lite-tables.d.ts.map +1 -1
  55. package/out/zero-cache/src/db/lite-tables.js +8 -3
  56. package/out/zero-cache/src/db/lite-tables.js.map +1 -1
  57. package/out/zero-cache/src/db/migration-lite.d.ts.map +1 -1
  58. package/out/zero-cache/src/db/migration-lite.js +5 -3
  59. package/out/zero-cache/src/db/migration-lite.js.map +1 -1
  60. package/out/zero-cache/src/db/specs.d.ts +41 -0
  61. package/out/zero-cache/src/db/specs.d.ts.map +1 -1
  62. package/out/zero-cache/src/db/specs.js +30 -3
  63. package/out/zero-cache/src/db/specs.js.map +1 -1
  64. package/out/zero-cache/src/db/transaction-pool.d.ts +5 -15
  65. package/out/zero-cache/src/db/transaction-pool.d.ts.map +1 -1
  66. package/out/zero-cache/src/db/transaction-pool.js +39 -73
  67. package/out/zero-cache/src/db/transaction-pool.js.map +1 -1
  68. package/out/zero-cache/src/server/change-streamer.d.ts.map +1 -1
  69. package/out/zero-cache/src/server/change-streamer.js +27 -15
  70. package/out/zero-cache/src/server/change-streamer.js.map +1 -1
  71. package/out/zero-cache/src/server/main.d.ts.map +1 -1
  72. package/out/zero-cache/src/server/main.js +4 -4
  73. package/out/zero-cache/src/server/main.js.map +1 -1
  74. package/out/zero-cache/src/server/replicator.d.ts.map +1 -1
  75. package/out/zero-cache/src/server/replicator.js +8 -4
  76. package/out/zero-cache/src/server/replicator.js.map +1 -1
  77. package/out/zero-cache/src/server/runner/run-worker.js +1 -1
  78. package/out/zero-cache/src/server/worker-urls.d.ts +0 -1
  79. package/out/zero-cache/src/server/worker-urls.d.ts.map +1 -1
  80. package/out/zero-cache/src/server/worker-urls.js +1 -2
  81. package/out/zero-cache/src/server/worker-urls.js.map +1 -1
  82. package/out/zero-cache/src/services/analyze.d.ts.map +1 -1
  83. package/out/zero-cache/src/services/analyze.js +1 -0
  84. package/out/zero-cache/src/services/analyze.js.map +1 -1
  85. package/out/zero-cache/src/services/change-source/common/backfill-manager.d.ts +12 -2
  86. package/out/zero-cache/src/services/change-source/common/backfill-manager.d.ts.map +1 -1
  87. package/out/zero-cache/src/services/change-source/common/backfill-manager.js +14 -3
  88. package/out/zero-cache/src/services/change-source/common/backfill-manager.js.map +1 -1
  89. package/out/zero-cache/src/services/change-source/common/replica-schema.d.ts.map +1 -1
  90. package/out/zero-cache/src/services/change-source/common/replica-schema.js +10 -41
  91. package/out/zero-cache/src/services/change-source/common/replica-schema.js.map +1 -1
  92. package/out/zero-cache/src/services/change-source/pg/backfill-stream.d.ts +3 -2
  93. package/out/zero-cache/src/services/change-source/pg/backfill-stream.d.ts.map +1 -1
  94. package/out/zero-cache/src/services/change-source/pg/backfill-stream.js +42 -16
  95. package/out/zero-cache/src/services/change-source/pg/backfill-stream.js.map +1 -1
  96. package/out/zero-cache/src/services/change-source/pg/change-source.d.ts +34 -2
  97. package/out/zero-cache/src/services/change-source/pg/change-source.d.ts.map +1 -1
  98. package/out/zero-cache/src/services/change-source/pg/change-source.js +47 -19
  99. package/out/zero-cache/src/services/change-source/pg/change-source.js.map +1 -1
  100. package/out/zero-cache/src/services/change-source/pg/decommission.d.ts.map +1 -1
  101. package/out/zero-cache/src/services/change-source/pg/decommission.js +20 -11
  102. package/out/zero-cache/src/services/change-source/pg/decommission.js.map +1 -1
  103. package/out/zero-cache/src/services/change-source/pg/initial-sync.d.ts +1 -0
  104. package/out/zero-cache/src/services/change-source/pg/initial-sync.d.ts.map +1 -1
  105. package/out/zero-cache/src/services/change-source/pg/initial-sync.js +58 -80
  106. package/out/zero-cache/src/services/change-source/pg/initial-sync.js.map +1 -1
  107. package/out/zero-cache/src/services/change-source/pg/logical-replication/stream.d.ts +20 -0
  108. package/out/zero-cache/src/services/change-source/pg/logical-replication/stream.d.ts.map +1 -1
  109. package/out/zero-cache/src/services/change-source/pg/logical-replication/stream.js +43 -3
  110. package/out/zero-cache/src/services/change-source/pg/logical-replication/stream.js.map +1 -1
  111. package/out/zero-cache/src/services/change-source/pg/replication-slots.d.ts +24 -1
  112. package/out/zero-cache/src/services/change-source/pg/replication-slots.d.ts.map +1 -1
  113. package/out/zero-cache/src/services/change-source/pg/replication-slots.js +35 -5
  114. package/out/zero-cache/src/services/change-source/pg/replication-slots.js.map +1 -1
  115. package/out/zero-cache/src/services/change-source/pg/schema/ddl.d.ts +1513 -229
  116. package/out/zero-cache/src/services/change-source/pg/schema/ddl.d.ts.map +1 -1
  117. package/out/zero-cache/src/services/change-source/pg/schema/ddl.js +2 -2
  118. package/out/zero-cache/src/services/change-source/pg/schema/ddl.js.map +1 -1
  119. package/out/zero-cache/src/services/change-source/pg/schema/index-predicate.d.ts +19 -0
  120. package/out/zero-cache/src/services/change-source/pg/schema/index-predicate.d.ts.map +1 -0
  121. package/out/zero-cache/src/services/change-source/pg/schema/index-predicate.js +581 -0
  122. package/out/zero-cache/src/services/change-source/pg/schema/index-predicate.js.map +1 -0
  123. package/out/zero-cache/src/services/change-source/pg/schema/init.d.ts +1 -1
  124. package/out/zero-cache/src/services/change-source/pg/schema/init.d.ts.map +1 -1
  125. package/out/zero-cache/src/services/change-source/pg/schema/init.js +15 -6
  126. package/out/zero-cache/src/services/change-source/pg/schema/init.js.map +1 -1
  127. package/out/zero-cache/src/services/change-source/pg/schema/published.d.ts +137 -20
  128. package/out/zero-cache/src/services/change-source/pg/schema/published.d.ts.map +1 -1
  129. package/out/zero-cache/src/services/change-source/pg/schema/published.js +82 -13
  130. package/out/zero-cache/src/services/change-source/pg/schema/published.js.map +1 -1
  131. package/out/zero-cache/src/services/change-source/pg/schema/shard.d.ts +128 -21
  132. package/out/zero-cache/src/services/change-source/pg/schema/shard.d.ts.map +1 -1
  133. package/out/zero-cache/src/services/change-source/pg/schema/shard.js +5 -5
  134. package/out/zero-cache/src/services/change-source/pg/schema/shard.js.map +1 -1
  135. package/out/zero-cache/src/services/change-source/protocol/current/data.d.ts +2 -0
  136. package/out/zero-cache/src/services/change-source/protocol/current/data.d.ts.map +1 -1
  137. package/out/zero-cache/src/services/change-source/protocol/current/downstream.d.ts +3 -0
  138. package/out/zero-cache/src/services/change-source/protocol/current/downstream.d.ts.map +1 -1
  139. package/out/zero-cache/src/services/change-streamer/backup-cleanup-monitor-factory.d.ts +1 -4
  140. package/out/zero-cache/src/services/change-streamer/backup-cleanup-monitor-factory.d.ts.map +1 -1
  141. package/out/zero-cache/src/services/change-streamer/backup-cleanup-monitor-factory.js +11 -18
  142. package/out/zero-cache/src/services/change-streamer/backup-cleanup-monitor-factory.js.map +1 -1
  143. package/out/zero-cache/src/services/change-streamer/backup-monitor.d.ts.map +1 -1
  144. package/out/zero-cache/src/services/change-streamer/backup-monitor.js +8 -3
  145. package/out/zero-cache/src/services/change-streamer/backup-monitor.js.map +1 -1
  146. package/out/zero-cache/src/services/change-streamer/broadcast.d.ts.map +1 -1
  147. package/out/zero-cache/src/services/change-streamer/broadcast.js +4 -1
  148. package/out/zero-cache/src/services/change-streamer/broadcast.js.map +1 -1
  149. package/out/zero-cache/src/services/change-streamer/change-log-compare-digest.d.ts +34 -0
  150. package/out/zero-cache/src/services/change-streamer/change-log-compare-digest.d.ts.map +1 -0
  151. package/out/zero-cache/src/services/change-streamer/change-log-compare-digest.js +67 -0
  152. package/out/zero-cache/src/services/change-streamer/change-log-compare-digest.js.map +1 -0
  153. package/out/zero-cache/src/services/change-streamer/change-streamer-http.d.ts +2 -4
  154. package/out/zero-cache/src/services/change-streamer/change-streamer-http.d.ts.map +1 -1
  155. package/out/zero-cache/src/services/change-streamer/change-streamer-http.js +8 -2
  156. package/out/zero-cache/src/services/change-streamer/change-streamer-http.js.map +1 -1
  157. package/out/zero-cache/src/services/change-streamer/change-streamer-service.d.ts +34 -13
  158. package/out/zero-cache/src/services/change-streamer/change-streamer-service.d.ts.map +1 -1
  159. package/out/zero-cache/src/services/change-streamer/change-streamer-service.js +165 -36
  160. package/out/zero-cache/src/services/change-streamer/change-streamer-service.js.map +1 -1
  161. package/out/zero-cache/src/services/change-streamer/change-streamer.d.ts +4 -9
  162. package/out/zero-cache/src/services/change-streamer/change-streamer.d.ts.map +1 -1
  163. package/out/zero-cache/src/services/change-streamer/change-streamer.js.map +1 -1
  164. package/out/zero-cache/src/services/change-streamer/forwarder.d.ts.map +1 -1
  165. package/out/zero-cache/src/services/change-streamer/forwarder.js +12 -3
  166. package/out/zero-cache/src/services/change-streamer/forwarder.js.map +1 -1
  167. package/out/zero-cache/src/services/change-streamer/litestream3-prometheus-poller.d.ts.map +1 -1
  168. package/out/zero-cache/src/services/change-streamer/litestream3-prometheus-poller.js +11 -5
  169. package/out/zero-cache/src/services/change-streamer/litestream3-prometheus-poller.js.map +1 -1
  170. package/out/zero-cache/src/services/change-streamer/shard-sampling.d.ts +11 -0
  171. package/out/zero-cache/src/services/change-streamer/shard-sampling.d.ts.map +1 -0
  172. package/out/zero-cache/src/services/change-streamer/shard-sampling.js +19 -0
  173. package/out/zero-cache/src/services/change-streamer/shard-sampling.js.map +1 -0
  174. package/out/zero-cache/src/services/change-streamer/snapshot-reservations.d.ts +11 -1
  175. package/out/zero-cache/src/services/change-streamer/snapshot-reservations.d.ts.map +1 -1
  176. package/out/zero-cache/src/services/change-streamer/snapshot-reservations.js +38 -5
  177. package/out/zero-cache/src/services/change-streamer/snapshot-reservations.js.map +1 -1
  178. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-catchup.d.ts +25 -1
  179. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-catchup.d.ts.map +1 -1
  180. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-catchup.js +95 -12
  181. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-catchup.js.map +1 -1
  182. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-comparator.d.ts +83 -0
  183. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-comparator.d.ts.map +1 -0
  184. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-comparator.js +417 -0
  185. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-comparator.js.map +1 -0
  186. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-read-router.d.ts +73 -0
  187. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-read-router.d.ts.map +1 -0
  188. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-read-router.js +157 -0
  189. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-read-router.js.map +1 -0
  190. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-reader.d.ts +1 -1
  191. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-reader.d.ts.map +1 -1
  192. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-reader.js +8 -3
  193. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-reader.js.map +1 -1
  194. package/out/zero-cache/src/services/change-streamer/storer.d.ts +63 -1
  195. package/out/zero-cache/src/services/change-streamer/storer.d.ts.map +1 -1
  196. package/out/zero-cache/src/services/change-streamer/storer.js +217 -49
  197. package/out/zero-cache/src/services/change-streamer/storer.js.map +1 -1
  198. package/out/zero-cache/src/services/change-streamer/subscriber.d.ts +8 -1
  199. package/out/zero-cache/src/services/change-streamer/subscriber.d.ts.map +1 -1
  200. package/out/zero-cache/src/services/change-streamer/subscriber.js +10 -1
  201. package/out/zero-cache/src/services/change-streamer/subscriber.js.map +1 -1
  202. package/out/zero-cache/src/services/change-streamer/vfs-watermark-poller.d.ts +29 -0
  203. package/out/zero-cache/src/services/change-streamer/vfs-watermark-poller.d.ts.map +1 -0
  204. package/out/zero-cache/src/services/change-streamer/vfs-watermark-poller.js +154 -0
  205. package/out/zero-cache/src/services/change-streamer/vfs-watermark-poller.js.map +1 -0
  206. package/out/zero-cache/src/services/http-service.d.ts +1 -0
  207. package/out/zero-cache/src/services/http-service.d.ts.map +1 -1
  208. package/out/zero-cache/src/services/http-service.js +7 -3
  209. package/out/zero-cache/src/services/http-service.js.map +1 -1
  210. package/out/zero-cache/src/services/litestream/commands.d.ts.map +1 -1
  211. package/out/zero-cache/src/services/litestream/commands.js +16 -7
  212. package/out/zero-cache/src/services/litestream/commands.js.map +1 -1
  213. package/out/zero-cache/src/services/litestream/config-v5.yml +15 -1
  214. package/out/zero-cache/src/services/litestream/litestream-checkpointer.js +131 -0
  215. package/out/zero-cache/src/services/litestream/litestream-checkpointer.js.map +1 -0
  216. package/out/zero-cache/src/services/litestream/litestream-controller.d.ts +70 -0
  217. package/out/zero-cache/src/services/litestream/litestream-controller.d.ts.map +1 -0
  218. package/out/zero-cache/src/services/litestream/litestream-controller.js +101 -0
  219. package/out/zero-cache/src/services/litestream/litestream-controller.js.map +1 -0
  220. package/out/zero-cache/src/services/litestream/metrics.d.ts +1 -0
  221. package/out/zero-cache/src/services/litestream/metrics.d.ts.map +1 -1
  222. package/out/zero-cache/src/services/litestream/metrics.js +4 -1
  223. package/out/zero-cache/src/services/litestream/metrics.js.map +1 -1
  224. package/out/zero-cache/src/services/mutagen/mutagen.d.ts.map +1 -1
  225. package/out/zero-cache/src/services/mutagen/mutagen.js +1 -1
  226. package/out/zero-cache/src/services/mutagen/mutagen.js.map +1 -1
  227. package/out/zero-cache/src/services/replicator/change-log-db.d.ts +10 -0
  228. package/out/zero-cache/src/services/replicator/change-log-db.d.ts.map +1 -1
  229. package/out/zero-cache/src/services/replicator/change-log-db.js +15 -1
  230. package/out/zero-cache/src/services/replicator/change-log-db.js.map +1 -1
  231. package/out/zero-cache/src/services/replicator/change-processor.d.ts.map +1 -1
  232. package/out/zero-cache/src/services/replicator/change-processor.js +18 -21
  233. package/out/zero-cache/src/services/replicator/change-processor.js.map +1 -1
  234. package/out/zero-cache/src/services/replicator/incremental-sync.d.ts +1 -1
  235. package/out/zero-cache/src/services/replicator/incremental-sync.d.ts.map +1 -1
  236. package/out/zero-cache/src/services/replicator/incremental-sync.js +2 -6
  237. package/out/zero-cache/src/services/replicator/incremental-sync.js.map +1 -1
  238. package/out/zero-cache/src/services/replicator/replicator.d.ts +1 -1
  239. package/out/zero-cache/src/services/replicator/replicator.d.ts.map +1 -1
  240. package/out/zero-cache/src/services/replicator/replicator.js +2 -2
  241. package/out/zero-cache/src/services/replicator/replicator.js.map +1 -1
  242. package/out/zero-cache/src/services/replicator/sqlite-change-log-observability.d.ts +3 -2
  243. package/out/zero-cache/src/services/replicator/sqlite-change-log-observability.d.ts.map +1 -1
  244. package/out/zero-cache/src/services/replicator/sqlite-change-log-observability.js +8 -6
  245. package/out/zero-cache/src/services/replicator/sqlite-change-log-observability.js.map +1 -1
  246. package/out/zero-cache/src/services/replicator/write-worker-client.d.ts +27 -2
  247. package/out/zero-cache/src/services/replicator/write-worker-client.d.ts.map +1 -1
  248. package/out/zero-cache/src/services/replicator/write-worker-client.js +3 -2
  249. package/out/zero-cache/src/services/replicator/write-worker-client.js.map +1 -1
  250. package/out/zero-cache/src/services/replicator/write-worker.js +24 -5
  251. package/out/zero-cache/src/services/replicator/write-worker.js.map +1 -1
  252. package/out/zero-cache/src/services/view-syncer/client-handler.d.ts +3 -2
  253. package/out/zero-cache/src/services/view-syncer/client-handler.d.ts.map +1 -1
  254. package/out/zero-cache/src/services/view-syncer/client-handler.js +25 -17
  255. package/out/zero-cache/src/services/view-syncer/client-handler.js.map +1 -1
  256. package/out/zero-cache/src/services/view-syncer/cvr-store.d.ts.map +1 -1
  257. package/out/zero-cache/src/services/view-syncer/cvr-store.js +14 -1
  258. package/out/zero-cache/src/services/view-syncer/cvr-store.js.map +1 -1
  259. package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts +3 -3
  260. package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts.map +1 -1
  261. package/out/zero-cache/src/services/view-syncer/view-syncer.js +6 -2
  262. package/out/zero-cache/src/services/view-syncer/view-syncer.js.map +1 -1
  263. package/out/zero-cache/src/types/downstream.d.ts +11 -0
  264. package/out/zero-cache/src/types/downstream.d.ts.map +1 -0
  265. package/out/zero-cache/src/types/pg.d.ts +15 -2
  266. package/out/zero-cache/src/types/pg.d.ts.map +1 -1
  267. package/out/zero-cache/src/types/pg.js +21 -8
  268. package/out/zero-cache/src/types/pg.js.map +1 -1
  269. package/out/zero-cache/src/types/poke-chunk.d.ts +18 -0
  270. package/out/zero-cache/src/types/poke-chunk.d.ts.map +1 -0
  271. package/out/zero-cache/src/types/poke-chunk.js +57 -0
  272. package/out/zero-cache/src/types/poke-chunk.js.map +1 -0
  273. package/out/zero-cache/src/types/processes.js +1 -4
  274. package/out/zero-cache/src/types/processes.js.map +1 -1
  275. package/out/zero-cache/src/types/streams.d.ts +4 -9
  276. package/out/zero-cache/src/types/streams.d.ts.map +1 -1
  277. package/out/zero-cache/src/types/streams.js.map +1 -1
  278. package/out/zero-cache/src/types/subscription.d.ts +2 -11
  279. package/out/zero-cache/src/types/subscription.d.ts.map +1 -1
  280. package/out/zero-cache/src/types/subscription.js +4 -25
  281. package/out/zero-cache/src/types/subscription.js.map +1 -1
  282. package/out/zero-cache/src/workers/connection.d.ts +22 -4
  283. package/out/zero-cache/src/workers/connection.d.ts.map +1 -1
  284. package/out/zero-cache/src/workers/connection.js +112 -14
  285. package/out/zero-cache/src/workers/connection.js.map +1 -1
  286. package/out/zero-cache/src/workers/replicator.d.ts +1 -0
  287. package/out/zero-cache/src/workers/replicator.d.ts.map +1 -1
  288. package/out/zero-cache/src/workers/replicator.js +4 -2
  289. package/out/zero-cache/src/workers/replicator.js.map +1 -1
  290. package/out/zero-client/src/client/connection-manager.d.ts.map +1 -1
  291. package/out/zero-client/src/client/connection-manager.js +46 -0
  292. package/out/zero-client/src/client/connection-manager.js.map +1 -1
  293. package/out/zero-client/src/client/context.d.ts +15 -0
  294. package/out/zero-client/src/client/context.d.ts.map +1 -1
  295. package/out/zero-client/src/client/context.js +44 -0
  296. package/out/zero-client/src/client/context.js.map +1 -1
  297. package/out/zero-client/src/client/inspector/lazy-inspector.d.ts.map +1 -1
  298. package/out/zero-client/src/client/inspector/lazy-inspector.js +19 -12
  299. package/out/zero-client/src/client/inspector/lazy-inspector.js.map +1 -1
  300. package/out/zero-client/src/client/ivm-branch.js.map +1 -1
  301. package/out/zero-client/src/client/version.js +1 -1
  302. package/out/zero-client/src/client/zero-poke-handler.d.ts +7 -2
  303. package/out/zero-client/src/client/zero-poke-handler.d.ts.map +1 -1
  304. package/out/zero-client/src/client/zero-poke-handler.js +52 -2
  305. package/out/zero-client/src/client/zero-poke-handler.js.map +1 -1
  306. package/out/zero-client/src/client/zero-rep.d.ts.map +1 -1
  307. package/out/zero-client/src/client/zero-rep.js +2 -1
  308. package/out/zero-client/src/client/zero-rep.js.map +1 -1
  309. package/out/zero-client/src/client/zero.d.ts.map +1 -1
  310. package/out/zero-client/src/client/zero.js +98 -25
  311. package/out/zero-client/src/client/zero.js.map +1 -1
  312. package/out/zero-protocol/src/custom-queries.d.ts +1 -1
  313. package/out/zero-protocol/src/down.d.ts +1 -1
  314. package/out/zero-protocol/src/error.d.ts +4 -4
  315. package/out/zero-protocol/src/inspect-down.js +1 -1
  316. package/out/zero-protocol/src/mutate-server.d.ts +2 -2
  317. package/out/zero-protocol/src/poke.d.ts +89 -7
  318. package/out/zero-protocol/src/poke.d.ts.map +1 -1
  319. package/out/zero-protocol/src/poke.js +16 -8
  320. package/out/zero-protocol/src/poke.js.map +1 -1
  321. package/out/zero-protocol/src/protocol-version.d.ts +12 -7
  322. package/out/zero-protocol/src/protocol-version.d.ts.map +1 -1
  323. package/out/zero-protocol/src/protocol-version.js.map +1 -1
  324. package/out/zero-protocol/src/push.d.ts +1 -1
  325. package/out/zero-protocol/src/query-server.d.ts +2 -2
  326. package/out/zql/src/ivm/array-view.d.ts.map +1 -1
  327. package/out/zql/src/ivm/array-view.js +5 -3
  328. package/out/zql/src/ivm/array-view.js.map +1 -1
  329. package/out/zql/src/ivm/data.d.ts.map +1 -1
  330. package/out/zql/src/ivm/data.js +8 -3
  331. package/out/zql/src/ivm/data.js.map +1 -1
  332. package/out/zql/src/ivm/deferred-input.d.ts +44 -0
  333. package/out/zql/src/ivm/deferred-input.d.ts.map +1 -0
  334. package/out/zql/src/ivm/deferred-input.js +88 -0
  335. package/out/zql/src/ivm/deferred-input.js.map +1 -0
  336. package/out/zql/src/ivm/memory-source.d.ts +10 -2
  337. package/out/zql/src/ivm/memory-source.d.ts.map +1 -1
  338. package/out/zql/src/ivm/memory-source.js +19 -16
  339. package/out/zql/src/ivm/memory-source.js.map +1 -1
  340. package/out/zql/src/ivm/stream.d.ts +0 -1
  341. package/out/zql/src/ivm/stream.d.ts.map +1 -1
  342. package/out/zql/src/ivm/stream.js +1 -7
  343. package/out/zql/src/ivm/stream.js.map +1 -1
  344. package/out/zql/src/ivm/union-fan-in.d.ts +1 -1
  345. package/out/zql/src/ivm/union-fan-in.d.ts.map +1 -1
  346. package/out/zql/src/ivm/union-fan-in.js +11 -2
  347. package/out/zql/src/ivm/union-fan-in.js.map +1 -1
  348. package/out/zql/src/ivm/view-apply-change.js +6 -1
  349. package/out/zql/src/ivm/view-apply-change.js.map +1 -1
  350. package/out/zql/src/query/query-delegate-base.d.ts +6 -0
  351. package/out/zql/src/query/query-delegate-base.d.ts.map +1 -1
  352. package/out/zql/src/query/query-delegate-base.js +73 -10
  353. package/out/zql/src/query/query-delegate-base.js.map +1 -1
  354. package/out/zql/src/query/query-delegate.d.ts +22 -0
  355. package/out/zql/src/query/query-delegate.d.ts.map +1 -1
  356. package/out/zqlite/src/query-builder.d.ts.map +1 -1
  357. package/out/zqlite/src/query-builder.js +2 -1
  358. package/out/zqlite/src/query-builder.js.map +1 -1
  359. package/out/zqlite/src/sqlite-stat-fanout.d.ts.map +1 -1
  360. package/out/zqlite/src/sqlite-stat-fanout.js +1 -0
  361. package/out/zqlite/src/sqlite-stat-fanout.js.map +1 -1
  362. package/out/zqlite/src/table-source.d.ts +1 -1
  363. package/out/zqlite/src/table-source.d.ts.map +1 -1
  364. package/out/zqlite/src/table-source.js +3 -2
  365. package/out/zqlite/src/table-source.js.map +1 -1
  366. package/package.json +2 -3
  367. package/out/zero-cache/src/server/backup-watermark-poller.js +0 -31
  368. package/out/zero-cache/src/server/backup-watermark-poller.js.map +0 -1
  369. package/out/zero-cache/src/services/litestream/vfs-watermark-poller.d.ts +0 -57
  370. package/out/zero-cache/src/services/litestream/vfs-watermark-poller.d.ts.map +0 -1
  371. package/out/zero-cache/src/services/litestream/vfs-watermark-poller.js +0 -137
  372. package/out/zero-cache/src/services/litestream/vfs-watermark-poller.js.map +0 -1
@@ -2,6 +2,7 @@ import { assert, unreachable } from "../../../../shared/src/asserts.js";
2
2
  import { promiseVoid } from "../../../../shared/src/resolved-promises.js";
3
3
  import { AbortError } from "../../../../shared/src/abort-error.js";
4
4
  import { parse, valita_exports } from "../../../../shared/src/valita.js";
5
+ import { BigIntJSON } from "../../../../shared/src/bigint-json.js";
5
6
  import { cdcSchema } from "../../types/shards.js";
6
7
  import { isDataChange, isSchemaChange } from "../change-source/protocol/current/data.js";
7
8
  import "../change-source/protocol/current/downstream.js";
@@ -13,7 +14,7 @@ import { READONLY, READ_COMMITTED } from "../../db/mode-enum.js";
13
14
  import { runTx } from "../../db/run-transaction.js";
14
15
  import { Queue } from "../../../../shared/src/queue.js";
15
16
  import { AutoResetSignal, markResetRequired } from "./schema/tables.js";
16
- import { TransactionPool } from "../../db/transaction-pool.js";
17
+ import { TransactionPool, sharedSnapshot } from "../../db/transaction-pool.js";
17
18
  import { orTimeout } from "../../types/timeout.js";
18
19
  import { extractChangeSubstring, reconstructWatermarkedChange, serializeChangeStreamData } from "./change-log-codec.js";
19
20
  import { resolver } from "@rocicorp/resolver";
@@ -58,7 +59,10 @@ var Storer = class {
58
59
  #taskID;
59
60
  #discoveryAddress;
60
61
  #discoveryProtocol;
62
+ #makeConnectionPool;
61
63
  #db;
64
+ #inserter;
65
+ #purger;
62
66
  #replicaVersion;
63
67
  #onCommitted;
64
68
  #onFatal;
@@ -67,21 +71,26 @@ var Storer = class {
67
71
  #statementTimeoutMs;
68
72
  #changeLogBatchSize;
69
73
  #drainTimeoutMs;
74
+ #progressMonitor;
70
75
  #approximateQueuedBytes = 0;
71
76
  #running = false;
72
- constructor(lc, shard, taskID, discoveryAddress, discoveryProtocol, db, replicaVersion, onCommitted, onFatal, { backPressureLimitHeapProportion, statementTimeoutMs, changeLogBatchSize, drainTimeoutMs = 3e4 }) {
77
+ constructor(lc, shard, taskID, discoveryAddress, discoveryProtocol, dbProvider, replicaVersion, onCommitted, onFatal, { backPressureLimitHeapProportion, statementTimeoutMs, changeLogBatchSize, drainTimeoutMs = 3e4 }) {
73
78
  this.#lc = lc.withContext("component", "change-log");
74
79
  this.#shard = shard;
75
80
  this.#taskID = taskID;
76
81
  this.#discoveryAddress = discoveryAddress;
77
82
  this.#discoveryProtocol = discoveryProtocol;
78
- this.#db = db;
83
+ this.#makeConnectionPool = dbProvider;
84
+ this.#db = dbProvider("change-stream-init", 3);
85
+ this.#inserter = dbProvider("change-log-inserter", 1);
86
+ this.#purger = dbProvider("change-log-purger", 1);
79
87
  this.#replicaVersion = replicaVersion;
80
88
  this.#onCommitted = onCommitted;
81
89
  this.#onFatal = onFatal;
82
90
  this.#statementTimeoutMs = statementTimeoutMs;
83
91
  this.#changeLogBatchSize = Math.max(1, changeLogBatchSize);
84
92
  this.#drainTimeoutMs = drainTimeoutMs;
93
+ this.#progressMonitor = new ProgressMonitor(lc, statementTimeoutMs, onFatal);
85
94
  const heapStats = getHeapStatistics();
86
95
  this.#backPressureThresholdBytes = (heapStats.heap_size_limit - heapStats.used_heap_size) * backPressureLimitHeapProportion;
87
96
  this.#lc.info?.(`Using up to ${(this.#backPressureThresholdBytes / 1024 ** 2).toFixed(2)} MB of --max-old-space-size (~${(heapStats.heap_size_limit / 1024 ** 2).toFixed(2)} MB) to absorb upstream spikes`, { heapStats });
@@ -89,6 +98,28 @@ var Storer = class {
89
98
  #cdc(table) {
90
99
  return this.#db(`${cdcSchema(this.#shard)}.${table}`);
91
100
  }
101
+ /**
102
+ * Bounds a one-off db call (i.e. not part of the main storer loop or the
103
+ * background catchup read, which are tracked by the ProgressMonitor
104
+ * instead) with a plain timeout. This covers calls like
105
+ * {@link assumeOwnership} and {@link getStartStreamInitializationParameters}
106
+ * that are made by the caller *before* {@link run()} -- and thus before the
107
+ * ProgressMonitor's polling starts -- as well as ones made well after,
108
+ * where a continuously-polling watchdog would be overkill for a single
109
+ * bounded db round trip.
110
+ *
111
+ * Does not cancel `promise` on timeout (there is no cancellation mechanism
112
+ * for a postgres.js query); it just stops waiting for it, and swallows a
113
+ * later rejection so it doesn't surface as an unhandled rejection.
114
+ */
115
+ async #withTimeout(name, promise) {
116
+ const result = await orTimeout(promise, this.#statementTimeoutMs);
117
+ if (result === "timed-out") {
118
+ promise.catch(() => {});
119
+ throw new AbortError(`${name} did not complete within ${this.#statementTimeoutMs}ms`);
120
+ }
121
+ return result;
122
+ }
92
123
  async assumeOwnership(purgeLock) {
93
124
  const db = this.#db;
94
125
  const owner = this.#taskID;
@@ -97,10 +128,10 @@ var Storer = class {
97
128
  const addressWithProtocol = ownerProtocol === "ws" ? ownerAddress : `${ownerProtocol}://${ownerAddress}`;
98
129
  this.#lc.info?.(`assuming ownership at ${addressWithProtocol}`);
99
130
  const start = performance.now();
100
- await db`UPDATE ${this.#cdc("replicationState")} SET ${db({
131
+ await this.#withTimeout("assume-ownership", db`UPDATE ${this.#cdc("replicationState")} SET ${db({
101
132
  owner,
102
133
  ownerAddress: addressWithProtocol
103
- })}`;
134
+ })}`);
104
135
  const elapsed = (performance.now() - start).toFixed(2);
105
136
  this.#lc.info?.(`assumed ownership at ${addressWithProtocol} (${elapsed} ms)`);
106
137
  if (purgeLock) purgeLock.release();
@@ -123,7 +154,7 @@ var Storer = class {
123
154
  * snapshot that the SQLite change log continues folding onto.
124
155
  */
125
156
  async getStartStreamInitializationParameters() {
126
- const [[{ lastWatermark }], result, tableMetadata, backfilling] = await runTx(this.#db, (sql) => [
157
+ const [[{ lastWatermark }], result, tableMetadata, backfilling] = await this.#withTimeout("get-stream-params", runTx(this.#db, (sql) => [
127
158
  sql`
128
159
  SELECT "lastWatermark" FROM ${this.#cdc("replicationState")}`,
129
160
  sql`
@@ -146,7 +177,7 @@ var Storer = class {
146
177
  sql`
147
178
  SELECT "schema", "table", "column", "backfill" FROM ${this.#cdc("backfilling")}
148
179
  ORDER BY "schema" COLLATE "C", "table" COLLATE "C", "column" COLLATE "C"`
149
- ], { mode: READONLY });
180
+ ], { mode: READONLY }));
150
181
  return {
151
182
  lastWatermark,
152
183
  backfillRequests: parse(result, backfillRequestsSchema),
@@ -157,12 +188,52 @@ var Storer = class {
157
188
  };
158
189
  }
159
190
  async getMinWatermarkForCatchup() {
160
- const [{ minWatermark }] = await this.#db`
161
- SELECT min(watermark) as "minWatermark" FROM ${this.#cdc("changeLog")}`;
191
+ const [{ minWatermark }] = await this.#withTimeout("get-min-watermark", this.#db`
192
+ SELECT min(watermark) as "minWatermark" FROM ${this.#cdc("changeLog")}`);
162
193
  return minWatermark;
163
194
  }
195
+ /**
196
+ * Returns the retained Postgres catchup bounds.
197
+ * `minWatermark` is the oldest transaction, or `null` for a new replica.
198
+ * `lastWatermark` is the durable head.
199
+ */
200
+ async getCatchupBounds() {
201
+ const [bounds] = await this.#withTimeout("get-catchup-bounds", this.#db`
202
+ SELECT
203
+ (SELECT min(watermark) FROM ${this.#cdc("changeLog")}) as "minWatermark",
204
+ (SELECT "lastWatermark" FROM ${this.#cdc("replicationState")}) as "lastWatermark"`);
205
+ return bounds;
206
+ }
207
+ /**
208
+ * Lists at most `limit` committed transaction watermarks in
209
+ * `(afterWatermark, throughWatermark]`, in ascending order.
210
+ */
211
+ async listCommitWatermarks(afterWatermark, throughWatermark, limit) {
212
+ return (await this.#db`
213
+ SELECT watermark FROM ${this.#cdc("changeLog")}
214
+ WHERE precommit IS NOT NULL
215
+ AND watermark > ${afterWatermark}
216
+ AND watermark <= ${throughWatermark}
217
+ ORDER BY watermark
218
+ LIMIT ${limit}`).map(({ watermark }) => watermark);
219
+ }
220
+ /**
221
+ * Reads `(afterWatermark, throughWatermark]` in stream order and bounded batches.
222
+ * This query matches the subscriber catchup query.
223
+ *
224
+ * Both queries fail when an escaped NUL reaches `change->'tag'`.
225
+ * Postgres cannot convert that value to text.
226
+ */
227
+ readCatchupRange(afterWatermark, throughWatermark, batchRows = 2e3) {
228
+ assert(Number.isSafeInteger(batchRows) && batchRows > 0, "Postgres change log batch size must be a positive safe integer");
229
+ return this.#db`
230
+ SELECT watermark, change->'tag' as tag, change::text FROM ${this.#cdc("changeLog")}
231
+ WHERE watermark > ${afterWatermark}
232
+ AND watermark <= ${throughWatermark}
233
+ ORDER BY watermark, pos`.cursor(batchRows);
234
+ }
164
235
  purgeRecordsBefore(watermark) {
165
- return runTx(this.#db, async (sql) => {
236
+ return runTx(this.#purger, async (sql) => {
166
237
  await sql`
167
238
  SELECT watermark FROM ${this.#cdc("changeLog")}
168
239
  ORDER BY watermark, pos LIMIT 1
@@ -214,30 +285,22 @@ var Storer = class {
214
285
  }]);
215
286
  }
216
287
  #readyForMore = null;
217
- #backpressureTimeout;
218
288
  readyForMore() {
219
289
  if (!this.#running) return;
220
290
  if (this.#readyForMore === null && this.#approximateQueuedBytes > this.#backPressureThresholdBytes) {
221
291
  this.#lc.warn?.(`applying back pressure with ${this.#queue.size()} queued changes (~${(this.#approximateQueuedBytes / 1024 ** 2).toFixed(2)} MB)\n\nTo inspect changeLog backlog in your change DB:\n SELECT\n (change->'relation'->>'schema') || '.' || (change->'relation'->>'name') AS table_name,\n change->>'tag' AS operation,\n COUNT(*) AS count\n FROM "<app_id>/cdc"."changeLog"\n GROUP BY 1, 2\n ORDER BY 3 DESC\n LIMIT 20;`);
222
292
  this.#readyForMore = resolver();
223
- this.#resetBackpressureTimeout(true);
224
293
  }
225
294
  return this.#readyForMore?.promise;
226
295
  }
227
- #resetBackpressureTimeout(reschedule) {
228
- clearTimeout(this.#backpressureTimeout);
229
- this.#backpressureTimeout = reschedule ? setTimeout(() => {
230
- this.#readyForMore?.reject(new AbortError(`No statement processed within the last ${this.#statementTimeoutMs}ms. Considering the change-log to be wedged.`));
231
- this.#readyForMore = null;
232
- }, this.#statementTimeoutMs) : void 0;
233
- }
234
296
  #maybeReleaseBackPressure() {
235
- if (this.#readyForMore !== null) if (this.#approximateQueuedBytes < this.#backPressureThresholdBytes * .8) {
236
- this.#lc.info?.(`releasing back pressure with ${this.#queue.size()} queued changes (~${(this.#approximateQueuedBytes / 1024 ** 2).toFixed(2)} MB)`);
237
- this.#readyForMore.resolve();
238
- this.#readyForMore = null;
239
- this.#resetBackpressureTimeout(false);
240
- } else this.#resetBackpressureTimeout(true);
297
+ if (this.#readyForMore !== null) {
298
+ if (this.#approximateQueuedBytes < this.#backPressureThresholdBytes * .8) {
299
+ this.#lc.info?.(`releasing back pressure with ${this.#queue.size()} queued changes (~${(this.#approximateQueuedBytes / 1024 ** 2).toFixed(2)} MB)`);
300
+ this.#readyForMore.resolve();
301
+ this.#readyForMore = null;
302
+ }
303
+ }
241
304
  }
242
305
  /**
243
306
  * Flushes any buffered {@link PendingTransaction.batch} rows to the changeLog.
@@ -276,6 +339,7 @@ var Storer = class {
276
339
  this.#running = true;
277
340
  this.#stopped = stopped;
278
341
  this.#lc.info?.("starting storer");
342
+ this.#progressMonitor.start();
279
343
  let err;
280
344
  try {
281
345
  await this.#processQueue();
@@ -287,7 +351,6 @@ var Storer = class {
287
351
  this.#readyForMore.resolve();
288
352
  this.#readyForMore = null;
289
353
  }
290
- this.#resetBackpressureTimeout(false);
291
354
  this.#cancelQueueEntries(this.#queue.drain().filter((entry) => entry !== void 0), err);
292
355
  this.#running = false;
293
356
  signalStopped();
@@ -313,9 +376,20 @@ var Storer = class {
313
376
  async #processQueue() {
314
377
  let tx = null;
315
378
  let msg;
379
+ let lastTaskDone;
380
+ const nextMessage = async () => {
381
+ lastTaskDone?.();
382
+ lastTaskDone = void 0;
383
+ const entry = await this.#queue.dequeue();
384
+ if (entry !== "stop") lastTaskDone = this.#progressMonitor.trackTask({
385
+ task: "queue-entry",
386
+ type: entry[0]
387
+ });
388
+ return entry;
389
+ };
316
390
  const catchupQueue = [];
317
391
  try {
318
- while ((msg = await this.#queue.dequeue()) !== "stop") {
392
+ while ((msg = await nextMessage()) !== "stop") {
319
393
  const [msgType] = msg;
320
394
  switch (msgType) {
321
395
  case "ready": {
@@ -345,10 +419,7 @@ var Storer = class {
345
419
  const { promise, resolve, reject } = resolver();
346
420
  promise.catch(() => {});
347
421
  tx = {
348
- pool: new TransactionPool(this.#lc.withContext("watermark", watermark), {
349
- mode: READ_COMMITTED,
350
- statementResponseTimeout: this.#statementTimeoutMs
351
- }),
422
+ pool: new TransactionPool(this.#lc.withContext("watermark", watermark), { mode: READ_COMMITTED }),
352
423
  preCommitWatermark: watermark,
353
424
  pos: 0,
354
425
  startingReplicationState: promise,
@@ -356,7 +427,7 @@ var Storer = class {
356
427
  batch: [],
357
428
  lastFlush: void 0
358
429
  };
359
- tx.pool.run(this.#db);
430
+ tx.pool.run(this.#inserter);
360
431
  tx.pool.process((tx) => {
361
432
  tx`
362
433
  SELECT "owner" FROM ${this.#cdc("replicationState")} FOR UPDATE`.then(([result]) => resolve(result), reject);
@@ -415,22 +486,46 @@ var Storer = class {
415
486
  }
416
487
  }
417
488
  async #startCatchup(subs) {
418
- if (subs.length === 0) return;
489
+ const numCatchups = subs.length;
490
+ if (numCatchups === 0) return;
419
491
  const lc = this.#lc.withContext("pool", "catchup");
420
- const reader = new TransactionPool(lc, { mode: READONLY });
421
- reader.run(this.#db);
492
+ const { init, cleanup, snapshotID } = sharedSnapshot();
493
+ const reader = new TransactionPool(lc, {
494
+ mode: READONLY,
495
+ init,
496
+ cleanup,
497
+ initialWorkers: subs.length
498
+ });
499
+ const catchupConns = this.#makeConnectionPool("subscriber-catchup", numCatchups);
500
+ reader.run(catchupConns);
422
501
  let lastWatermark;
502
+ const catchupSnapshotted = this.#progressMonitor.trackTask({
503
+ task: "capture-catchup-snapshot",
504
+ subscribers: subs.map(({ subscriber: s }) => s.id)
505
+ });
423
506
  try {
424
507
  [{lastWatermark}] = await reader.processReadTask((sql) => sql`
425
508
  SELECT "lastWatermark" FROM ${this.#cdc("replicationState")}
426
509
  `);
510
+ lc.info?.(`snapshotted db at ${lastWatermark} (${await snapshotID}) to catchup ${numCatchups} subscriber(s)`);
427
511
  } catch (e) {
428
512
  subs.map(({ subscriber }) => subscriber.fail(e));
429
513
  throw e;
514
+ } finally {
515
+ catchupSnapshotted();
430
516
  }
431
- Promise.all(subs.map((sub) => this.#catchup(lc.withContext("subscriber", sub.subscriber.id), sub, lastWatermark, reader))).finally(() => reader.setDone());
517
+ Promise.allSettled(subs.map((sub) => this.#catchup(lc.withContext("subscriber", sub.subscriber.id), sub, lastWatermark, reader))).finally(() => {
518
+ reader.setDone();
519
+ catchupConns.end().catch(() => {});
520
+ });
432
521
  }
433
522
  async #catchup(lc, { subscriber: sub, mode }, lastWatermark, reader) {
523
+ let entriesReceived = 0;
524
+ let catchupProgressed = this.#progressMonitor.trackTask({
525
+ task: "catchup",
526
+ subscriber: sub.id,
527
+ entriesReceived
528
+ });
434
529
  try {
435
530
  lc.info?.(`starting catchup`);
436
531
  await reader.processReadTask(async (tx) => {
@@ -444,21 +539,32 @@ var Storer = class {
444
539
  WHERE watermark >= ${sub.watermark}
445
540
  AND watermark <= ${lastWatermark}
446
541
  ORDER BY watermark, pos`.cursor(2e3)) {
447
- const start = performance.now();
448
- await lastBatchConsumed;
449
- const elapsed = performance.now() - start;
450
- if (lastBatchConsumed) lc[elapsed > 100 ? "info" : "debug"]?.(`waited ${elapsed.toFixed(3)} ms for ${sub.id} to consume last batch of catchup entries`);
451
- for (const entry of entries) if (entry.watermark === sub.watermark) watermarkFound = true;
452
- else if (watermarkFound) {
453
- lastBatchConsumed = sub.catchup(reconstructWatermarkedChange(entry));
454
- count++;
455
- } else if (mode === "backup") throw new AutoResetSignal(`backup replica at watermark ${sub.watermark} is behind change db: ${entry.watermark})`);
456
- else {
457
- lc.warn?.(`rejecting subscriber at watermark ${sub.watermark} (earliest watermark: ${entry.watermark})`);
458
- sub.close(2, `earliest supported watermark is ${entry.watermark} (requested ${sub.watermark})`);
459
- return;
542
+ catchupProgressed();
543
+ entriesReceived += entries.length;
544
+ try {
545
+ const start = performance.now();
546
+ await lastBatchConsumed;
547
+ const elapsed = performance.now() - start;
548
+ if (lastBatchConsumed) lc[elapsed > 100 ? "info" : "debug"]?.(`waited ${elapsed.toFixed(3)} ms for ${sub.id} to consume last batch of catchup entries`);
549
+ for (const entry of entries) if (entry.watermark === sub.watermark) watermarkFound = true;
550
+ else if (watermarkFound) {
551
+ lastBatchConsumed = sub.catchup(reconstructWatermarkedChange(entry));
552
+ count++;
553
+ } else if (mode === "backup") throw new AutoResetSignal(`backup replica at watermark ${sub.watermark} is behind change db: ${entry.watermark})`);
554
+ else {
555
+ lc.warn?.(`rejecting subscriber at watermark ${sub.watermark} (earliest watermark: ${entry.watermark})`);
556
+ sub.close(2, `earliest supported watermark is ${entry.watermark} (requested ${sub.watermark})`);
557
+ return;
558
+ }
559
+ } finally {
560
+ catchupProgressed = this.#progressMonitor.trackTask({
561
+ task: "catchup",
562
+ subscriber: sub.id,
563
+ entriesReceived
564
+ });
460
565
  }
461
566
  }
567
+ catchupProgressed();
462
568
  if (watermarkFound) {
463
569
  await lastBatchConsumed;
464
570
  lc.info?.(`caught up ${sub.id} with ${count} changes (${Date.now() - start} ms)`);
@@ -472,6 +578,8 @@ var Storer = class {
472
578
  this.#onFatal(err);
473
579
  }
474
580
  sub.fail(err);
581
+ } finally {
582
+ catchupProgressed();
475
583
  }
476
584
  }
477
585
  /**
@@ -569,6 +677,7 @@ var Storer = class {
569
677
  */
570
678
  async stop() {
571
679
  if (this.#running) {
680
+ this.#progressMonitor.stop();
572
681
  this.#lc.info?.(`draining ${this.#queue.size()} changeLog entries`);
573
682
  this.abort();
574
683
  this.#queue.enqueue("stop");
@@ -629,6 +738,65 @@ var PurgeLocker = class {
629
738
  return new PurgeLock(this.#lc, tx, replicaVersion, watermark);
630
739
  }
631
740
  };
741
+ /**
742
+ * Periodic monitor for detecting the pathological condition in which a db
743
+ * query hangs forever because of a connection problem, such as a half-closed
744
+ * socket.
745
+ *
746
+ * Use this for db calls that recur or accumulate progress within a single
747
+ * logical operation on the main storer loop (e.g. the queue-processing loop,
748
+ * or a multi-batch catchup read), where "no progress for N ms" is the
749
+ * meaningful signal. For a one-off db call -- including ones made before
750
+ * {@link Storer.run} starts this monitor's polling -- use a plain timeout
751
+ * (see `Storer.#withTimeout`) instead.
752
+ *
753
+ * The failure handler should stop the server. The ProgressMonitor will
754
+ * assume this and stop itself after calling it.
755
+ *
756
+ * Internal to the Storer, but exported for testing.
757
+ */
758
+ var ProgressMonitor = class {
759
+ #lc;
760
+ #failureThresholdMs;
761
+ #onFailure;
762
+ #taskUpdates = /* @__PURE__ */ new Map();
763
+ #timer;
764
+ constructor(lc, failureThresholdMs, onFailure) {
765
+ this.#lc = lc.withContext("component", "storer-progress-monitor");
766
+ this.#failureThresholdMs = failureThresholdMs;
767
+ this.#onFailure = onFailure;
768
+ }
769
+ start() {
770
+ clearInterval(this.#timer);
771
+ this.#timer = setInterval(() => this.checkTaskProgress(/* @__PURE__ */ new Date()), this.#failureThresholdMs).unref();
772
+ }
773
+ checkTaskProgress(now) {
774
+ for (const [task, lastUpdate] of this.#taskUpdates.entries()) if (now.getTime() - lastUpdate.getTime() >= this.#failureThresholdMs) {
775
+ this.#lc.error?.(`Last task update was more than ${this.#failureThresholdMs}ms ago`, {
776
+ task,
777
+ lastUpdate
778
+ });
779
+ this.#onFailure(/* @__PURE__ */ new Error(`Task failed to progress for over ${this.#failureThresholdMs}ms: ${BigIntJSON.stringify(task)}`));
780
+ this.stop();
781
+ return;
782
+ }
783
+ }
784
+ /**
785
+ * Starts a task to be tracked.
786
+ *
787
+ * @return a callback to invoke when the task is done.
788
+ */
789
+ trackTask(task, now = /* @__PURE__ */ new Date()) {
790
+ this.#taskUpdates.set(task, now);
791
+ return () => {
792
+ this.#taskUpdates.delete(task);
793
+ };
794
+ }
795
+ stop() {
796
+ clearInterval(this.#timer);
797
+ this.#taskUpdates.clear();
798
+ }
799
+ };
632
800
  //#endregion
633
801
  export { PurgeLocker, Storer };
634
802