@rocicorp/zero 1.9.1-canary.1 → 1.10.0-canary.1

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 (344) hide show
  1. package/out/analyze-query/src/analyze-cli.js +2 -2
  2. package/out/analyze-query/src/analyze-cli.js.map +1 -1
  3. package/out/replicache/src/db/commit.js +1 -4
  4. package/out/replicache/src/db/commit.js.map +1 -1
  5. package/out/replicache/src/db/read.d.ts +1 -0
  6. package/out/replicache/src/db/read.d.ts.map +1 -1
  7. package/out/replicache/src/db/read.js +1 -4
  8. package/out/replicache/src/db/read.js.map +1 -1
  9. package/out/replicache/src/db/write.d.ts +2 -1
  10. package/out/replicache/src/db/write.d.ts.map +1 -1
  11. package/out/replicache/src/db/write.js +4 -51
  12. package/out/replicache/src/db/write.js.map +1 -1
  13. package/out/replicache/src/persist/clients.d.ts +1 -0
  14. package/out/replicache/src/persist/clients.d.ts.map +1 -1
  15. package/out/replicache/src/persist/clients.js +4 -31
  16. package/out/replicache/src/persist/clients.js.map +1 -1
  17. package/out/replicache/src/process-env.d.ts +28 -0
  18. package/out/replicache/src/process-env.d.ts.map +1 -0
  19. package/out/replicache/src/replicache-impl.d.ts.map +1 -1
  20. package/out/replicache/src/replicache-impl.js.map +1 -1
  21. package/out/replicache/src/scan-iterator.js +2 -14
  22. package/out/replicache/src/scan-iterator.js.map +1 -1
  23. package/out/replicache/src/subscriptions.d.ts +1 -0
  24. package/out/replicache/src/subscriptions.d.ts.map +1 -1
  25. package/out/replicache/src/subscriptions.js +2 -10
  26. package/out/replicache/src/subscriptions.js.map +1 -1
  27. package/out/replicache/src/transactions.d.ts +1 -0
  28. package/out/replicache/src/transactions.d.ts.map +1 -1
  29. package/out/replicache/src/transactions.js +2 -4
  30. package/out/replicache/src/transactions.js.map +1 -1
  31. package/out/zero/package.js +2 -2
  32. package/out/zero/package.js.map +1 -1
  33. package/out/zero-cache/src/config/normalize.d.ts +1 -0
  34. package/out/zero-cache/src/config/normalize.d.ts.map +1 -1
  35. package/out/zero-cache/src/config/normalize.js +10 -1
  36. package/out/zero-cache/src/config/normalize.js.map +1 -1
  37. package/out/zero-cache/src/config/zero-config.d.ts +43 -1
  38. package/out/zero-cache/src/config/zero-config.d.ts.map +1 -1
  39. package/out/zero-cache/src/config/zero-config.js +139 -20
  40. package/out/zero-cache/src/config/zero-config.js.map +1 -1
  41. package/out/zero-cache/src/db/migration.js +1 -1
  42. package/out/zero-cache/src/observability/metrics.d.ts +5 -0
  43. package/out/zero-cache/src/observability/metrics.d.ts.map +1 -1
  44. package/out/zero-cache/src/observability/metrics.js +15 -1
  45. package/out/zero-cache/src/observability/metrics.js.map +1 -1
  46. package/out/zero-cache/src/server/backup-watermark-poller.js +31 -0
  47. package/out/zero-cache/src/server/backup-watermark-poller.js.map +1 -0
  48. package/out/zero-cache/src/server/change-streamer.d.ts.map +1 -1
  49. package/out/zero-cache/src/server/change-streamer.js +90 -30
  50. package/out/zero-cache/src/server/change-streamer.js.map +1 -1
  51. package/out/zero-cache/src/server/main.d.ts.map +1 -1
  52. package/out/zero-cache/src/server/main.js +5 -15
  53. package/out/zero-cache/src/server/main.js.map +1 -1
  54. package/out/zero-cache/src/server/replicator.d.ts.map +1 -1
  55. package/out/zero-cache/src/server/replicator.js +46 -3
  56. package/out/zero-cache/src/server/replicator.js.map +1 -1
  57. package/out/zero-cache/src/server/runner/run-worker.js +2 -1
  58. package/out/zero-cache/src/server/runner/run-worker.js.map +1 -1
  59. package/out/zero-cache/src/server/worker-urls.d.ts +1 -1
  60. package/out/zero-cache/src/server/worker-urls.js +2 -2
  61. package/out/zero-cache/src/server/worker-urls.js.map +1 -1
  62. package/out/zero-cache/src/services/change-source/change-source.d.ts +4 -2
  63. package/out/zero-cache/src/services/change-source/change-source.d.ts.map +1 -1
  64. package/out/zero-cache/src/services/change-source/common/replica-restore.d.ts +35 -0
  65. package/out/zero-cache/src/services/change-source/common/replica-restore.d.ts.map +1 -0
  66. package/out/zero-cache/src/services/change-source/common/replica-restore.js +34 -0
  67. package/out/zero-cache/src/services/change-source/common/replica-restore.js.map +1 -0
  68. package/out/zero-cache/src/services/change-source/common/replica-schema.d.ts +2 -0
  69. package/out/zero-cache/src/services/change-source/common/replica-schema.d.ts.map +1 -1
  70. package/out/zero-cache/src/services/change-source/common/replica-schema.js +73 -1
  71. package/out/zero-cache/src/services/change-source/common/replica-schema.js.map +1 -1
  72. package/out/zero-cache/src/services/change-source/custom/change-source.d.ts +2 -6
  73. package/out/zero-cache/src/services/change-source/custom/change-source.d.ts.map +1 -1
  74. package/out/zero-cache/src/services/change-source/custom/change-source.js +16 -7
  75. package/out/zero-cache/src/services/change-source/custom/change-source.js.map +1 -1
  76. package/out/zero-cache/src/services/change-source/pg/backfill-stream.js +4 -7
  77. package/out/zero-cache/src/services/change-source/pg/backfill-stream.js.map +1 -1
  78. package/out/zero-cache/src/services/change-source/pg/change-source.d.ts +7 -7
  79. package/out/zero-cache/src/services/change-source/pg/change-source.d.ts.map +1 -1
  80. package/out/zero-cache/src/services/change-source/pg/change-source.js +75 -23
  81. package/out/zero-cache/src/services/change-source/pg/change-source.js.map +1 -1
  82. package/out/zero-cache/src/services/change-source/pg/initial-sync.d.ts +9 -1
  83. package/out/zero-cache/src/services/change-source/pg/initial-sync.d.ts.map +1 -1
  84. package/out/zero-cache/src/services/change-source/pg/initial-sync.js +34 -4
  85. package/out/zero-cache/src/services/change-source/pg/initial-sync.js.map +1 -1
  86. package/out/zero-cache/src/services/change-source/pg/logical-replication/stream.js +1 -1
  87. package/out/zero-cache/src/services/change-source/pg/replication-slots.d.ts +4 -2
  88. package/out/zero-cache/src/services/change-source/pg/replication-slots.d.ts.map +1 -1
  89. package/out/zero-cache/src/services/change-source/pg/replication-slots.js +7 -4
  90. package/out/zero-cache/src/services/change-source/pg/replication-slots.js.map +1 -1
  91. package/out/zero-cache/src/services/change-source/pg/schema/init.d.ts +0 -5
  92. package/out/zero-cache/src/services/change-source/pg/schema/init.d.ts.map +1 -1
  93. package/out/zero-cache/src/services/change-source/pg/schema/init.js +29 -41
  94. package/out/zero-cache/src/services/change-source/pg/schema/init.js.map +1 -1
  95. package/out/zero-cache/src/services/change-source/pg/schema/shard.d.ts +35 -16
  96. package/out/zero-cache/src/services/change-source/pg/schema/shard.d.ts.map +1 -1
  97. package/out/zero-cache/src/services/change-source/pg/schema/shard.js +77 -7
  98. package/out/zero-cache/src/services/change-source/pg/schema/shard.js.map +1 -1
  99. package/out/zero-cache/src/services/change-source/protocol/current/data.d.ts +1 -1
  100. package/out/zero-cache/src/services/change-source/protocol/current/data.d.ts.map +1 -1
  101. package/out/zero-cache/src/services/change-source/protocol/current/data.js +1 -12
  102. package/out/zero-cache/src/services/change-source/protocol/current/data.js.map +1 -1
  103. package/out/zero-cache/src/services/change-source/protocol/current/downstream.d.ts +3 -3
  104. package/out/zero-cache/src/services/change-source/protocol/current/schema-change-tags.d.ts +6 -0
  105. package/out/zero-cache/src/services/change-source/protocol/current/schema-change-tags.d.ts.map +1 -0
  106. package/out/zero-cache/src/services/change-source/protocol/current/schema-change-tags.js +21 -0
  107. package/out/zero-cache/src/services/change-source/protocol/current/schema-change-tags.js.map +1 -0
  108. package/out/zero-cache/src/services/change-streamer/backup-cleanup-monitor-factory.d.ts +5 -6
  109. package/out/zero-cache/src/services/change-streamer/backup-cleanup-monitor-factory.d.ts.map +1 -1
  110. package/out/zero-cache/src/services/change-streamer/backup-cleanup-monitor-factory.js +32 -9
  111. package/out/zero-cache/src/services/change-streamer/backup-cleanup-monitor-factory.js.map +1 -1
  112. package/out/zero-cache/src/services/change-streamer/backup-monitor.d.ts +15 -5
  113. package/out/zero-cache/src/services/change-streamer/backup-monitor.d.ts.map +1 -1
  114. package/out/zero-cache/src/services/change-streamer/backup-monitor.js +66 -0
  115. package/out/zero-cache/src/services/change-streamer/backup-monitor.js.map +1 -0
  116. package/out/zero-cache/src/services/change-streamer/broadcast.d.ts +68 -78
  117. package/out/zero-cache/src/services/change-streamer/broadcast.d.ts.map +1 -1
  118. package/out/zero-cache/src/services/change-streamer/broadcast.js +84 -92
  119. package/out/zero-cache/src/services/change-streamer/broadcast.js.map +1 -1
  120. package/out/zero-cache/src/services/change-streamer/change-log-codec.d.ts +19 -0
  121. package/out/zero-cache/src/services/change-streamer/change-log-codec.d.ts.map +1 -0
  122. package/out/zero-cache/src/services/change-streamer/change-log-codec.js +50 -0
  123. package/out/zero-cache/src/services/change-streamer/change-log-codec.js.map +1 -0
  124. package/out/zero-cache/src/services/change-streamer/change-log-initializer.d.ts +141 -0
  125. package/out/zero-cache/src/services/change-streamer/change-log-initializer.d.ts.map +1 -0
  126. package/out/zero-cache/src/services/change-streamer/change-log-initializer.js +270 -0
  127. package/out/zero-cache/src/services/change-streamer/change-log-initializer.js.map +1 -0
  128. package/out/zero-cache/src/services/change-streamer/change-log-transaction-hash.d.ts +19 -0
  129. package/out/zero-cache/src/services/change-streamer/change-log-transaction-hash.d.ts.map +1 -0
  130. package/out/zero-cache/src/services/change-streamer/change-log-transaction-hash.js +39 -0
  131. package/out/zero-cache/src/services/change-streamer/change-log-transaction-hash.js.map +1 -0
  132. package/out/zero-cache/src/services/change-streamer/change-streamer-http.d.ts +3 -4
  133. package/out/zero-cache/src/services/change-streamer/change-streamer-http.d.ts.map +1 -1
  134. package/out/zero-cache/src/services/change-streamer/change-streamer-http.js +15 -20
  135. package/out/zero-cache/src/services/change-streamer/change-streamer-http.js.map +1 -1
  136. package/out/zero-cache/src/services/change-streamer/change-streamer-service.d.ts +69 -24
  137. package/out/zero-cache/src/services/change-streamer/change-streamer-service.d.ts.map +1 -1
  138. package/out/zero-cache/src/services/change-streamer/change-streamer-service.js +330 -63
  139. package/out/zero-cache/src/services/change-streamer/change-streamer-service.js.map +1 -1
  140. package/out/zero-cache/src/services/change-streamer/change-streamer.d.ts +55 -13
  141. package/out/zero-cache/src/services/change-streamer/change-streamer.d.ts.map +1 -1
  142. package/out/zero-cache/src/services/change-streamer/change-streamer.js.map +1 -1
  143. package/out/zero-cache/src/services/change-streamer/error-type-enum.d.ts +8 -0
  144. package/out/zero-cache/src/services/change-streamer/error-type-enum.d.ts.map +1 -1
  145. package/out/zero-cache/src/services/change-streamer/forwarder.d.ts +14 -3
  146. package/out/zero-cache/src/services/change-streamer/forwarder.d.ts.map +1 -1
  147. package/out/zero-cache/src/services/change-streamer/forwarder.js +41 -11
  148. package/out/zero-cache/src/services/change-streamer/forwarder.js.map +1 -1
  149. package/out/zero-cache/src/services/change-streamer/{litestream3-backup-monitor.d.ts → litestream3-prometheus-poller.d.ts} +19 -45
  150. package/out/zero-cache/src/services/change-streamer/litestream3-prometheus-poller.d.ts.map +1 -0
  151. package/out/zero-cache/src/services/change-streamer/{litestream3-backup-monitor.js → litestream3-prometheus-poller.js} +57 -171
  152. package/out/zero-cache/src/services/change-streamer/litestream3-prometheus-poller.js.map +1 -0
  153. package/out/zero-cache/src/services/change-streamer/replica-poller.d.ts +15 -0
  154. package/out/zero-cache/src/services/change-streamer/replica-poller.d.ts.map +1 -0
  155. package/out/zero-cache/src/services/change-streamer/replica-poller.js +55 -0
  156. package/out/zero-cache/src/services/change-streamer/replica-poller.js.map +1 -0
  157. package/out/zero-cache/src/services/change-streamer/schema/tables.d.ts +5 -1
  158. package/out/zero-cache/src/services/change-streamer/schema/tables.d.ts.map +1 -1
  159. package/out/zero-cache/src/services/change-streamer/schema/tables.js +2 -1
  160. package/out/zero-cache/src/services/change-streamer/schema/tables.js.map +1 -1
  161. package/out/zero-cache/src/services/change-streamer/snapshot-reservations.d.ts +14 -0
  162. package/out/zero-cache/src/services/change-streamer/snapshot-reservations.d.ts.map +1 -0
  163. package/out/zero-cache/src/services/change-streamer/snapshot-reservations.js +86 -0
  164. package/out/zero-cache/src/services/change-streamer/snapshot-reservations.js.map +1 -0
  165. package/out/zero-cache/src/services/change-streamer/snapshot.d.ts +4 -1
  166. package/out/zero-cache/src/services/change-streamer/snapshot.d.ts.map +1 -1
  167. package/out/zero-cache/src/services/change-streamer/snapshot.js +39 -14
  168. package/out/zero-cache/src/services/change-streamer/snapshot.js.map +1 -1
  169. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-catchup.d.ts +75 -0
  170. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-catchup.d.ts.map +1 -0
  171. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-catchup.js +261 -0
  172. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-catchup.js.map +1 -0
  173. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-purge-scheduler.d.ts +121 -0
  174. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-purge-scheduler.d.ts.map +1 -0
  175. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-purge-scheduler.js +391 -0
  176. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-purge-scheduler.js.map +1 -0
  177. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-reader.d.ts +62 -0
  178. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-reader.d.ts.map +1 -0
  179. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-reader.js +159 -0
  180. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-reader.js.map +1 -0
  181. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-writer.d.ts +109 -0
  182. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-writer.d.ts.map +1 -0
  183. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-writer.js +258 -0
  184. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-writer.js.map +1 -0
  185. package/out/zero-cache/src/services/change-streamer/storer.d.ts +22 -12
  186. package/out/zero-cache/src/services/change-streamer/storer.d.ts.map +1 -1
  187. package/out/zero-cache/src/services/change-streamer/storer.js +93 -117
  188. package/out/zero-cache/src/services/change-streamer/storer.js.map +1 -1
  189. package/out/zero-cache/src/services/change-streamer/subscriber.d.ts +61 -10
  190. package/out/zero-cache/src/services/change-streamer/subscriber.d.ts.map +1 -1
  191. package/out/zero-cache/src/services/change-streamer/subscriber.js +101 -8
  192. package/out/zero-cache/src/services/change-streamer/subscriber.js.map +1 -1
  193. package/out/zero-cache/src/services/change-streamer/upstream-acker.d.ts +34 -0
  194. package/out/zero-cache/src/services/change-streamer/upstream-acker.d.ts.map +1 -0
  195. package/out/zero-cache/src/services/change-streamer/upstream-acker.js +86 -0
  196. package/out/zero-cache/src/services/change-streamer/upstream-acker.js.map +1 -0
  197. package/out/zero-cache/src/services/life-cycle.d.ts +1 -1
  198. package/out/zero-cache/src/services/life-cycle.d.ts.map +1 -1
  199. package/out/zero-cache/src/services/life-cycle.js +3 -2
  200. package/out/zero-cache/src/services/life-cycle.js.map +1 -1
  201. package/out/zero-cache/src/services/litestream/commands.d.ts +12 -11
  202. package/out/zero-cache/src/services/litestream/commands.d.ts.map +1 -1
  203. package/out/zero-cache/src/services/litestream/commands.js +50 -140
  204. package/out/zero-cache/src/services/litestream/commands.js.map +1 -1
  205. package/out/zero-cache/src/services/litestream/config-v5.yml +42 -0
  206. package/out/zero-cache/src/services/litestream/metrics.d.ts +4 -4
  207. package/out/zero-cache/src/services/litestream/metrics.d.ts.map +1 -1
  208. package/out/zero-cache/src/services/litestream/metrics.js +7 -10
  209. package/out/zero-cache/src/services/litestream/metrics.js.map +1 -1
  210. package/out/zero-cache/src/services/litestream/vfs-watermark-poller.d.ts +57 -0
  211. package/out/zero-cache/src/services/litestream/vfs-watermark-poller.d.ts.map +1 -0
  212. package/out/zero-cache/src/services/litestream/vfs-watermark-poller.js +137 -0
  213. package/out/zero-cache/src/services/litestream/vfs-watermark-poller.js.map +1 -0
  214. package/out/zero-cache/src/services/replicator/change-log-cookies.d.ts +169 -0
  215. package/out/zero-cache/src/services/replicator/change-log-cookies.d.ts.map +1 -0
  216. package/out/zero-cache/src/services/replicator/change-log-cookies.js +434 -0
  217. package/out/zero-cache/src/services/replicator/change-log-cookies.js.map +1 -0
  218. package/out/zero-cache/src/services/replicator/change-log-db.d.ts +358 -0
  219. package/out/zero-cache/src/services/replicator/change-log-db.d.ts.map +1 -0
  220. package/out/zero-cache/src/services/replicator/change-log-db.js +477 -0
  221. package/out/zero-cache/src/services/replicator/change-log-db.js.map +1 -0
  222. package/out/zero-cache/src/services/replicator/change-log-stream-writer.d.ts +55 -0
  223. package/out/zero-cache/src/services/replicator/change-log-stream-writer.d.ts.map +1 -0
  224. package/out/zero-cache/src/services/replicator/change-log-stream-writer.js +150 -0
  225. package/out/zero-cache/src/services/replicator/change-log-stream-writer.js.map +1 -0
  226. package/out/zero-cache/src/services/replicator/change-processor.d.ts.map +1 -1
  227. package/out/zero-cache/src/services/replicator/change-processor.js +44 -17
  228. package/out/zero-cache/src/services/replicator/change-processor.js.map +1 -1
  229. package/out/zero-cache/src/services/replicator/incremental-sync.d.ts +1 -1
  230. package/out/zero-cache/src/services/replicator/incremental-sync.d.ts.map +1 -1
  231. package/out/zero-cache/src/services/replicator/incremental-sync.js +11 -4
  232. package/out/zero-cache/src/services/replicator/incremental-sync.js.map +1 -1
  233. package/out/zero-cache/src/services/replicator/replicator.d.ts +1 -1
  234. package/out/zero-cache/src/services/replicator/replicator.d.ts.map +1 -1
  235. package/out/zero-cache/src/services/replicator/replicator.js +2 -2
  236. package/out/zero-cache/src/services/replicator/replicator.js.map +1 -1
  237. package/out/zero-cache/src/services/replicator/schema/backfilling.d.ts +119 -0
  238. package/out/zero-cache/src/services/replicator/schema/backfilling.d.ts.map +1 -0
  239. package/out/zero-cache/src/services/replicator/schema/backfilling.js +214 -0
  240. package/out/zero-cache/src/services/replicator/schema/backfilling.js.map +1 -0
  241. package/out/zero-cache/src/services/replicator/schema/change-log.d.ts +3 -3
  242. package/out/zero-cache/src/services/replicator/schema/column-metadata.js +1 -1
  243. package/out/zero-cache/src/services/replicator/schema/column-metadata.js.map +1 -1
  244. package/out/zero-cache/src/services/replicator/schema/replication-state.d.ts +1 -1
  245. package/out/zero-cache/src/services/replicator/schema/replication-state.d.ts.map +1 -1
  246. package/out/zero-cache/src/services/replicator/schema/replication-state.js +9 -5
  247. package/out/zero-cache/src/services/replicator/schema/replication-state.js.map +1 -1
  248. package/out/zero-cache/src/services/replicator/sqlite-change-log-observability.d.ts +131 -0
  249. package/out/zero-cache/src/services/replicator/sqlite-change-log-observability.d.ts.map +1 -0
  250. package/out/zero-cache/src/services/replicator/sqlite-change-log-observability.js +413 -0
  251. package/out/zero-cache/src/services/replicator/sqlite-change-log-observability.js.map +1 -0
  252. package/out/zero-cache/src/services/replicator/sqlite-change-log-purger.d.ts +120 -0
  253. package/out/zero-cache/src/services/replicator/sqlite-change-log-purger.d.ts.map +1 -0
  254. package/out/zero-cache/src/services/replicator/sqlite-change-log-purger.js +283 -0
  255. package/out/zero-cache/src/services/replicator/sqlite-change-log-purger.js.map +1 -0
  256. package/out/zero-cache/src/services/replicator/write-worker.js +9 -6
  257. package/out/zero-cache/src/services/replicator/write-worker.js.map +1 -1
  258. package/out/zero-cache/src/services/run-ast.d.ts.map +1 -1
  259. package/out/zero-cache/src/services/run-ast.js +2 -1
  260. package/out/zero-cache/src/services/run-ast.js.map +1 -1
  261. package/out/zero-cache/src/services/running-state.d.ts +1 -1
  262. package/out/zero-cache/src/services/running-state.d.ts.map +1 -1
  263. package/out/zero-cache/src/services/running-state.js +1 -0
  264. package/out/zero-cache/src/services/running-state.js.map +1 -1
  265. package/out/zero-cache/src/services/view-syncer/e2e-serving-lag.d.ts +9 -0
  266. package/out/zero-cache/src/services/view-syncer/e2e-serving-lag.d.ts.map +1 -1
  267. package/out/zero-cache/src/services/view-syncer/e2e-serving-lag.js +9 -0
  268. package/out/zero-cache/src/services/view-syncer/e2e-serving-lag.js.map +1 -1
  269. package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts.map +1 -1
  270. package/out/zero-cache/src/services/view-syncer/pipeline-driver.js +18 -3
  271. package/out/zero-cache/src/services/view-syncer/pipeline-driver.js.map +1 -1
  272. package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts +11 -1
  273. package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts.map +1 -1
  274. package/out/zero-cache/src/services/view-syncer/view-syncer.js +48 -7
  275. package/out/zero-cache/src/services/view-syncer/view-syncer.js.map +1 -1
  276. package/out/zero-cache/src/types/processes.d.ts +1 -2
  277. package/out/zero-cache/src/types/processes.d.ts.map +1 -1
  278. package/out/zero-cache/src/types/processes.js +1 -25
  279. package/out/zero-cache/src/types/processes.js.map +1 -1
  280. package/out/zero-cache/src/types/streams.d.ts +10 -0
  281. package/out/zero-cache/src/types/streams.d.ts.map +1 -1
  282. package/out/zero-cache/src/types/streams.js +25 -4
  283. package/out/zero-cache/src/types/streams.js.map +1 -1
  284. package/out/zero-cache/src/workers/connection.d.ts +1 -0
  285. package/out/zero-cache/src/workers/connection.d.ts.map +1 -1
  286. package/out/zero-cache/src/workers/connection.js +25 -3
  287. package/out/zero-cache/src/workers/connection.js.map +1 -1
  288. package/out/zero-cache/src/workers/replicator.d.ts +25 -0
  289. package/out/zero-cache/src/workers/replicator.d.ts.map +1 -1
  290. package/out/zero-cache/src/workers/replicator.js +33 -1
  291. package/out/zero-cache/src/workers/replicator.js.map +1 -1
  292. package/out/zero-cache/src/workers/syncer.d.ts +12 -0
  293. package/out/zero-cache/src/workers/syncer.d.ts.map +1 -1
  294. package/out/zero-cache/src/workers/syncer.js +75 -0
  295. package/out/zero-cache/src/workers/syncer.js.map +1 -1
  296. package/out/zero-client/src/client/version.js +1 -1
  297. package/out/zero-schema/src/builder/table-builder.d.ts +23 -0
  298. package/out/zero-schema/src/builder/table-builder.d.ts.map +1 -1
  299. package/out/zero-schema/src/builder/table-builder.js +18 -0
  300. package/out/zero-schema/src/builder/table-builder.js.map +1 -1
  301. package/out/zero-types/src/schema.d.ts +11 -0
  302. package/out/zero-types/src/schema.d.ts.map +1 -1
  303. package/out/zql/src/query/query-impl.d.ts +2 -2
  304. package/out/zql/src/query/query-impl.d.ts.map +1 -1
  305. package/out/zql/src/query/query-impl.js.map +1 -1
  306. package/out/zql/src/query/query.d.ts +83 -14
  307. package/out/zql/src/query/query.d.ts.map +1 -1
  308. package/out/zql/src/query/static-query.d.ts +1 -1
  309. package/out/zql/src/query/static-query.d.ts.map +1 -1
  310. package/out/zqlite/src/resolve-scalar-subqueries.d.ts +15 -0
  311. package/out/zqlite/src/resolve-scalar-subqueries.d.ts.map +1 -1
  312. package/out/zqlite/src/resolve-scalar-subqueries.js +20 -13
  313. package/out/zqlite/src/resolve-scalar-subqueries.js.map +1 -1
  314. package/package.json +2 -2
  315. package/out/replicache/src/db/index.js +0 -91
  316. package/out/replicache/src/db/index.js.map +0 -1
  317. package/out/replicache/src/lazy.d.ts +0 -2
  318. package/out/replicache/src/lazy.d.ts.map +0 -1
  319. package/out/replicache/src/lazy.js +0 -12
  320. package/out/replicache/src/lazy.js.map +0 -1
  321. package/out/zero-cache/src/server/backup-watermark-reader.js +0 -35
  322. package/out/zero-cache/src/server/backup-watermark-reader.js.map +0 -1
  323. package/out/zero-cache/src/services/change-streamer/litestream3-backup-monitor.d.ts.map +0 -1
  324. package/out/zero-cache/src/services/change-streamer/litestream3-backup-monitor.js.map +0 -1
  325. package/out/zero-cache/src/services/change-streamer/replica-monitor.d.ts +0 -16
  326. package/out/zero-cache/src/services/change-streamer/replica-monitor.d.ts.map +0 -1
  327. package/out/zero-cache/src/services/change-streamer/replica-monitor.js +0 -54
  328. package/out/zero-cache/src/services/change-streamer/replica-monitor.js.map +0 -1
  329. package/out/zero-cache/src/services/change-streamer/vfs-backup-monitor.d.ts +0 -25
  330. package/out/zero-cache/src/services/change-streamer/vfs-backup-monitor.d.ts.map +0 -1
  331. package/out/zero-cache/src/services/change-streamer/vfs-backup-monitor.js +0 -159
  332. package/out/zero-cache/src/services/change-streamer/vfs-backup-monitor.js.map +0 -1
  333. package/out/zero-cache/src/services/litestream/vfs-watermark-reader.d.ts +0 -44
  334. package/out/zero-cache/src/services/litestream/vfs-watermark-reader.d.ts.map +0 -1
  335. package/out/zero-cache/src/services/litestream/vfs-watermark-reader.js +0 -65
  336. package/out/zero-cache/src/services/litestream/vfs-watermark-reader.js.map +0 -1
  337. package/out/zero-cache/src/services/litestream/vfs-watermark-worker-source.d.ts +0 -11
  338. package/out/zero-cache/src/services/litestream/vfs-watermark-worker-source.d.ts.map +0 -1
  339. package/out/zero-cache/src/services/litestream/vfs-watermark-worker-source.js +0 -74
  340. package/out/zero-cache/src/services/litestream/vfs-watermark-worker-source.js.map +0 -1
  341. package/out/zero-cache/src/services/litestream/vfs-watermark-worker.d.ts +0 -42
  342. package/out/zero-cache/src/services/litestream/vfs-watermark-worker.d.ts.map +0 -1
  343. package/out/zero-cache/src/services/litestream/vfs-watermark-worker.js +0 -117
  344. package/out/zero-cache/src/services/litestream/vfs-watermark-worker.js.map +0 -1
@@ -1,4 +1,5 @@
1
1
  import { assert } from "../../../shared/src/asserts.js";
2
+ import { sleep } from "../../../shared/src/sleep.js";
2
3
  import { parse } from "../../../shared/src/valita.js";
3
4
  import { must } from "../../../shared/src/must.js";
4
5
  import { parentWorker, singleProcessMode } from "../types/processes.js";
@@ -10,10 +11,14 @@ import { exitAfter, runUntilKilled } from "../services/life-cycle.js";
10
11
  import { createLogContext } from "./logging.js";
11
12
  import { initEventSink } from "../observability/events.js";
12
13
  import { ReplicationStatusPublisher } from "../services/replicator/replication-status.js";
14
+ import { litestreamRestoreDuration, litestreamRestoreMetricAttrs, litestreamRestoreRuns } from "../services/litestream/metrics.js";
15
+ import { tryRestore } from "../services/litestream/commands.js";
16
+ import { reserveAndGetSnapshotStatus } from "../services/change-streamer/snapshot.js";
13
17
  import { ChangeStreamerHttpClient } from "../services/change-streamer/change-streamer-http.js";
18
+ import { sqliteFileBytes } from "../services/replicator/sqlite-change-log-observability.js";
14
19
  import { startOtelAuto } from "./otel-start.js";
15
20
  import { ThreadWriteWorkerClient } from "../services/replicator/write-worker-client.js";
16
- import { getPragmaConfig, replicaFileModeSchema, setUpMessageHandlers, setupReplica } from "../workers/replicator.js";
21
+ import { deleteStaleChangeLog, getPragmaConfig, replicaFileModeSchema, setUpMessageHandlers, setupReplica } from "../workers/replicator.js";
17
22
  import { ReplicatorService } from "../services/replicator/replicator.js";
18
23
  import { LogContext, consoleLogSink } from "@rocicorp/logger";
19
24
  import { pid } from "node:process";
@@ -28,6 +33,7 @@ async function runWorker(parent, env, ...args) {
28
33
  argv: args.slice(1)
29
34
  });
30
35
  const mode = fileMode === "backup" ? "backup" : "serving";
36
+ const runningLocalChangeStreamer = config.changeStreamer.mode === "dedicated" && !config.changeStreamer.uri;
31
37
  const workerName = `${mode}-replicator`;
32
38
  startOtelAuto(createLogContext(config, workerName, 0, false), workerName, 0);
33
39
  lc = createLogContext(config, workerName);
@@ -36,21 +42,22 @@ async function runWorker(parent, env, ...args) {
36
42
  dbPath: config.replica.file
37
43
  }, config.sqliteCorruptionChecks);
38
44
  initEventSink(lc, config);
45
+ if (fileMode === "serving" && (config.litestream.executable || config.litestream.executableV5)) await restoreReplica(lc, config);
39
46
  const { file: dbPath, walMode } = await setupReplica(lc, fileMode, config.replica);
40
47
  unregisterInitialCorruptionDiagnosticTarget();
41
48
  registerSQLiteCorruptionDiagnosticTarget({
42
49
  debugName: `${workerName} replica`,
43
50
  dbPath
44
51
  }, config.sqliteCorruptionChecks);
52
+ deleteStaleChangeLog(config.changeStreamer.sqliteChangeLogMode, dbPath);
45
53
  setupMetrics(lc, dbPath, walMode);
46
54
  const pragmas = getPragmaConfig(fileMode);
47
55
  const workerClient = new ThreadWriteWorkerClient();
48
56
  await workerClient.init(dbPath, mode, pragmas, config.log);
49
- const runningLocalChangeStreamer = config.changeStreamer.mode === "dedicated" && !config.changeStreamer.uri;
50
57
  const shard = getShardConfig(config);
51
58
  const { taskID, change, changeStreamer: { port, uri: changeStreamerURI = runningLocalChangeStreamer ? `http://localhost:${port}/` : void 0 } } = config;
52
59
  const changeStreamer = new ChangeStreamerHttpClient(lc, shard, change.db, changeStreamerURI);
53
- const replicator = new ReplicatorService(lc, taskID, `${workerName}-${pid}`, mode, changeStreamer, workerClient, runningLocalChangeStreamer ? ReplicationStatusPublisher.forReplicaFile(dbPath) : null);
60
+ const replicator = new ReplicatorService(lc, taskID, `${workerName}-${pid}`, mode, dbPath, changeStreamer, workerClient, runningLocalChangeStreamer ? ReplicationStatusPublisher.forReplicaFile(dbPath) : null);
54
61
  setUpMessageHandlers(lc, replicator, parent);
55
62
  const running = runUntilKilled(lc, parent, replicator);
56
63
  for await (const _ of replicator.subscribe()) {
@@ -72,6 +79,10 @@ function setupMetrics(lc, file, walMode) {
72
79
  description: `The size of the replica's wal2 file`,
73
80
  unit: "bytes"
74
81
  }).addCallback(observeFileSize(lc, `${file}-wal2`));
82
+ getOrCreateGauge("replica", "file_bytes", {
83
+ description: "The replica's total on-disk footprint: its main db file plus its wal sidecars.",
84
+ unit: "By"
85
+ }).addCallback(observeSQLiteFileBytes(lc, file));
75
86
  }
76
87
  function observeFileSize(lc, file) {
77
88
  return async (o) => {
@@ -83,6 +94,38 @@ function observeFileSize(lc, file) {
83
94
  }
84
95
  };
85
96
  }
97
+ function observeSQLiteFileBytes(lc, file) {
98
+ return async (o) => o.observe(await sqliteFileBytes(lc, file));
99
+ }
100
+ var RETRY_INTERVAL_MS = 3e3;
101
+ async function restoreReplica(lc, config) {
102
+ const start = performance.now();
103
+ let backupURL;
104
+ let result;
105
+ try {
106
+ for (;;) {
107
+ const snapshotStatus = await reserveAndGetSnapshotStatus(lc, config);
108
+ ({backupURL} = snapshotStatus);
109
+ const attempt = await tryRestore(lc, {
110
+ ...config.litestream,
111
+ backupURL
112
+ }, config.replica.file, snapshotStatus, "view_syncer");
113
+ if (attempt.restored) {
114
+ result = attempt.result;
115
+ return;
116
+ }
117
+ lc.info?.(`replica not found. retrying in ${RETRY_INTERVAL_MS / 1e3} seconds`);
118
+ await sleep(RETRY_INTERVAL_MS);
119
+ }
120
+ } finally {
121
+ const labels = {
122
+ ...litestreamRestoreMetricAttrs(config.litestream, "view_syncer", backupURL),
123
+ result: result ?? "error"
124
+ };
125
+ litestreamRestoreRuns().add(1, labels);
126
+ litestreamRestoreDuration().recordMs(performance.now() - start, labels);
127
+ }
128
+ }
86
129
  if (!singleProcessMode()) exitAfter(() => lc, () => runWorker(must(parentWorker), process.env, ...process.argv.slice(2)));
87
130
  //#endregion
88
131
  export { runWorker as default };
@@ -1 +1 @@
1
- {"version":3,"file":"replicator.js","names":[],"sources":["../../../../../zero-cache/src/server/replicator.ts"],"sourcesContent":["import {stat} from 'node:fs/promises';\nimport {pid} from 'node:process';\nimport type {ObservableCallback} from '@opentelemetry/api';\nimport {consoleLogSink, LogContext} from '@rocicorp/logger';\nimport {assert} from '../../../shared/src/asserts.ts';\nimport {must} from '../../../shared/src/must.ts';\nimport * as v from '../../../shared/src/valita.ts';\nimport {getNormalizedZeroConfig} from '../config/zero-config.ts';\nimport {registerSQLiteCorruptionDiagnosticTarget} from '../db/sqlite-corruption.ts';\nimport {initEventSink} from '../observability/events.ts';\nimport {getOrCreateGauge} from '../observability/metrics.ts';\nimport {ChangeStreamerHttpClient} from '../services/change-streamer/change-streamer-http.ts';\nimport {exitAfter, runUntilKilled} from '../services/life-cycle.ts';\nimport {ReplicationStatusPublisher} from '../services/replicator/replication-status.ts';\nimport {\n ReplicatorService,\n type ReplicatorMode,\n} from '../services/replicator/replicator.ts';\nimport {ThreadWriteWorkerClient} from '../services/replicator/write-worker-client.ts';\nimport {\n parentWorker,\n singleProcessMode,\n type Worker,\n} from '../types/processes.ts';\nimport {getShardConfig} from '../types/shards.ts';\nimport {\n getPragmaConfig,\n replicaFileModeSchema,\n setUpMessageHandlers,\n setupReplica,\n type WalMode,\n} from '../workers/replicator.ts';\nimport {createLogContext} from './logging.ts';\nimport {startOtelAuto} from './otel-start.ts';\n\n// Default LogContext, overridden in runWorker\nlet lc = new LogContext('info', {}, consoleLogSink);\n\nexport default async function runWorker(\n parent: Worker,\n env: NodeJS.ProcessEnv,\n ...args: string[]\n): Promise<void> {\n assert(args.length > 0, `replicator mode not specified`);\n const fileMode = v.parse(args[0], replicaFileModeSchema);\n\n const config = getNormalizedZeroConfig({env, argv: args.slice(1)});\n const mode: ReplicatorMode = fileMode === 'backup' ? 'backup' : 'serving';\n const workerName = `${mode}-replicator`;\n startOtelAuto(createLogContext(config, workerName, 0, false), workerName, 0);\n lc = createLogContext(config, workerName);\n const unregisterInitialCorruptionDiagnosticTarget =\n registerSQLiteCorruptionDiagnosticTarget(\n {\n debugName: `${workerName} replica`,\n dbPath: config.replica.file,\n },\n config.sqliteCorruptionChecks,\n );\n initEventSink(lc, config);\n\n const {file: dbPath, walMode} = await setupReplica(\n lc,\n fileMode,\n config.replica,\n );\n unregisterInitialCorruptionDiagnosticTarget();\n registerSQLiteCorruptionDiagnosticTarget(\n {\n debugName: `${workerName} replica`,\n dbPath,\n },\n config.sqliteCorruptionChecks,\n );\n\n setupMetrics(lc, dbPath, walMode);\n\n // Create the write worker for async SQLite writes.\n const pragmas = getPragmaConfig(fileMode);\n const workerClient = new ThreadWriteWorkerClient();\n await workerClient.init(dbPath, mode, pragmas, config.log);\n\n const runningLocalChangeStreamer =\n config.changeStreamer.mode === 'dedicated' && !config.changeStreamer.uri;\n const shard = getShardConfig(config);\n const {\n taskID,\n change,\n changeStreamer: {\n port,\n uri: changeStreamerURI = runningLocalChangeStreamer\n ? `http://localhost:${port}/`\n : undefined,\n },\n } = config;\n const changeStreamer = new ChangeStreamerHttpClient(\n lc,\n shard,\n change.db,\n changeStreamerURI,\n );\n\n const replicator = new ReplicatorService(\n lc,\n taskID,\n `${workerName}-${pid}`,\n mode,\n changeStreamer,\n workerClient,\n runningLocalChangeStreamer\n ? // publish ReplicationStatusEvents from backup-replicator only\n ReplicationStatusPublisher.forReplicaFile(dbPath)\n : null,\n );\n\n setUpMessageHandlers(lc, replicator, parent);\n\n const running = runUntilKilled(lc, parent, replicator);\n\n // Signal readiness once the first ReplicaVersionReady notification is received.\n for await (const _ of replicator.subscribe()) {\n parent.send(['ready', {ready: true}]);\n break;\n }\n\n return running;\n}\n\nfunction setupMetrics(lc: LogContext, file: string, walMode: WalMode) {\n getOrCreateGauge('replica', 'db_size', {\n description:\n `The size of the replica's main db file, ` +\n `which does not include the wal file(s)`,\n unit: 'bytes',\n }).addCallback(observeFileSize(lc, file));\n\n getOrCreateGauge('replica', 'wal_size', {\n description: `The size of the replica's wal file`,\n unit: 'bytes',\n }).addCallback(observeFileSize(lc, `${file}-wal`));\n\n if (walMode === 'wal2') {\n getOrCreateGauge('replica', 'wal2_size', {\n description: `The size of the replica's wal2 file`,\n unit: 'bytes',\n }).addCallback(observeFileSize(lc, `${file}-wal2`));\n }\n}\n\nfunction observeFileSize(lc: LogContext, file: string): ObservableCallback {\n return async o => {\n try {\n const stats = await stat(file);\n o.observe(stats.size);\n } catch (e) {\n lc.warn?.(`unable to stat ${file} for size metrics`, e);\n }\n };\n}\n\n// fork()\nif (!singleProcessMode()) {\n void exitAfter(\n () => lc,\n () => runWorker(must(parentWorker), process.env, ...process.argv.slice(2)),\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAoCA,IAAI,KAAK,IAAI,WAAW,QAAQ,CAAC,GAAG,cAAc;AAElD,eAA8B,UAC5B,QACA,KACA,GAAG,MACY;CACf,OAAO,KAAK,SAAS,GAAG,+BAA+B;CACvD,MAAM,WAAW,MAAQ,KAAK,IAAI,qBAAqB;CAEvD,MAAM,SAAS,wBAAwB;EAAC;EAAK,MAAM,KAAK,MAAM,CAAC;CAAC,CAAC;CACjE,MAAM,OAAuB,aAAa,WAAW,WAAW;CAChE,MAAM,aAAa,GAAG,KAAK;CAC3B,cAAc,iBAAiB,QAAQ,YAAY,GAAG,KAAK,GAAG,YAAY,CAAC;CAC3E,KAAK,iBAAiB,QAAQ,UAAU;CACxC,MAAM,8CACJ,yCACE;EACE,WAAW,GAAG,WAAW;EACzB,QAAQ,OAAO,QAAQ;CACzB,GACA,OAAO,sBACT;CACF,cAAc,IAAI,MAAM;CAExB,MAAM,EAAC,MAAM,QAAQ,YAAW,MAAM,aACpC,IACA,UACA,OAAO,OACT;CACA,4CAA4C;CAC5C,yCACE;EACE,WAAW,GAAG,WAAW;EACzB;CACF,GACA,OAAO,sBACT;CAEA,aAAa,IAAI,QAAQ,OAAO;CAGhC,MAAM,UAAU,gBAAgB,QAAQ;CACxC,MAAM,eAAe,IAAI,wBAAwB;CACjD,MAAM,aAAa,KAAK,QAAQ,MAAM,SAAS,OAAO,GAAG;CAEzD,MAAM,6BACJ,OAAO,eAAe,SAAS,eAAe,CAAC,OAAO,eAAe;CACvE,MAAM,QAAQ,eAAe,MAAM;CACnC,MAAM,EACJ,QACA,QACA,gBAAgB,EACd,MACA,KAAK,oBAAoB,6BACrB,oBAAoB,KAAK,KACzB,KAAA,QAEJ;CACJ,MAAM,iBAAiB,IAAI,yBACzB,IACA,OACA,OAAO,IACP,iBACF;CAEA,MAAM,aAAa,IAAI,kBACrB,IACA,QACA,GAAG,WAAW,GAAG,OACjB,MACA,gBACA,cACA,6BAEI,2BAA2B,eAAe,MAAM,IAChD,IACN;CAEA,qBAAqB,IAAI,YAAY,MAAM;CAE3C,MAAM,UAAU,eAAe,IAAI,QAAQ,UAAU;CAGrD,WAAW,MAAM,KAAK,WAAW,UAAU,GAAG;EAC5C,OAAO,KAAK,CAAC,SAAS,EAAC,OAAO,KAAI,CAAC,CAAC;EACpC;CACF;CAEA,OAAO;AACT;AAEA,SAAS,aAAa,IAAgB,MAAc,SAAkB;CACpE,iBAAiB,WAAW,WAAW;EACrC,aACE;EAEF,MAAM;CACR,CAAC,EAAE,YAAY,gBAAgB,IAAI,IAAI,CAAC;CAExC,iBAAiB,WAAW,YAAY;EACtC,aAAa;EACb,MAAM;CACR,CAAC,EAAE,YAAY,gBAAgB,IAAI,GAAG,KAAK,KAAK,CAAC;CAEjD,IAAI,YAAY,QACd,iBAAiB,WAAW,aAAa;EACvC,aAAa;EACb,MAAM;CACR,CAAC,EAAE,YAAY,gBAAgB,IAAI,GAAG,KAAK,MAAM,CAAC;AAEtD;AAEA,SAAS,gBAAgB,IAAgB,MAAkC;CACzE,OAAO,OAAM,MAAK;EAChB,IAAI;GACF,MAAM,QAAQ,MAAM,KAAK,IAAI;GAC7B,EAAE,QAAQ,MAAM,IAAI;EACtB,SAAS,GAAG;GACV,GAAG,OAAO,kBAAkB,KAAK,oBAAoB,CAAC;EACxD;CACF;AACF;AAGA,IAAI,CAAC,kBAAkB,GACrB,gBACQ,UACA,UAAU,KAAK,YAAY,GAAG,QAAQ,KAAK,GAAG,QAAQ,KAAK,MAAM,CAAC,CAAC,CAC3E"}
1
+ {"version":3,"file":"replicator.js","names":[],"sources":["../../../../../zero-cache/src/server/replicator.ts"],"sourcesContent":["import {stat} from 'node:fs/promises';\nimport {pid} from 'node:process';\nimport type {ObservableCallback} from '@opentelemetry/api';\nimport {consoleLogSink, LogContext} from '@rocicorp/logger';\nimport {assert} from '../../../shared/src/asserts.ts';\nimport {must} from '../../../shared/src/must.ts';\nimport {sleep} from '../../../shared/src/sleep.ts';\nimport * as v from '../../../shared/src/valita.ts';\nimport type {\n LitestreamConfig,\n NormalizedZeroConfig,\n} from '../config/normalize.ts';\nimport {getNormalizedZeroConfig} from '../config/zero-config.ts';\nimport {registerSQLiteCorruptionDiagnosticTarget} from '../db/sqlite-corruption.ts';\nimport {initEventSink} from '../observability/events.ts';\nimport {getOrCreateGauge} from '../observability/metrics.ts';\nimport {ChangeStreamerHttpClient} from '../services/change-streamer/change-streamer-http.ts';\nimport {reserveAndGetSnapshotStatus} from '../services/change-streamer/snapshot.ts';\nimport {exitAfter, runUntilKilled} from '../services/life-cycle.ts';\nimport {\n tryRestore,\n type RestoreResult,\n} from '../services/litestream/commands.ts';\nimport {\n litestreamRestoreDuration,\n litestreamRestoreMetricAttrs,\n litestreamRestoreRuns,\n} from '../services/litestream/metrics.ts';\nimport {ReplicationStatusPublisher} from '../services/replicator/replication-status.ts';\nimport {\n ReplicatorService,\n type ReplicatorMode,\n} from '../services/replicator/replicator.ts';\nimport {sqliteFileBytes} from '../services/replicator/sqlite-change-log-observability.ts';\nimport {ThreadWriteWorkerClient} from '../services/replicator/write-worker-client.ts';\nimport {\n parentWorker,\n singleProcessMode,\n type Worker,\n} from '../types/processes.ts';\nimport {getShardConfig} from '../types/shards.ts';\nimport {\n deleteStaleChangeLog,\n getPragmaConfig,\n replicaFileModeSchema,\n setUpMessageHandlers,\n setupReplica,\n type WalMode,\n} from '../workers/replicator.ts';\nimport {createLogContext} from './logging.ts';\nimport {startOtelAuto} from './otel-start.ts';\n\n// Default LogContext, overridden in runWorker\nlet lc = new LogContext('info', {}, consoleLogSink);\n\nexport default async function runWorker(\n parent: Worker,\n env: NodeJS.ProcessEnv,\n ...args: string[]\n): Promise<void> {\n assert(args.length > 0, `replicator mode not specified`);\n const fileMode = v.parse(args[0], replicaFileModeSchema);\n\n const config = getNormalizedZeroConfig({env, argv: args.slice(1)});\n const mode: ReplicatorMode = fileMode === 'backup' ? 'backup' : 'serving';\n const runningLocalChangeStreamer =\n config.changeStreamer.mode === 'dedicated' && !config.changeStreamer.uri;\n const workerName = `${mode}-replicator`;\n startOtelAuto(createLogContext(config, workerName, 0, false), workerName, 0);\n lc = createLogContext(config, workerName);\n const unregisterInitialCorruptionDiagnosticTarget =\n registerSQLiteCorruptionDiagnosticTarget(\n {\n debugName: `${workerName} replica`,\n dbPath: config.replica.file,\n },\n config.sqliteCorruptionChecks,\n );\n initEventSink(lc, config);\n\n if (\n fileMode === 'serving' &&\n (config.litestream.executable || config.litestream.executableV5)\n ) {\n await restoreReplica(lc, config);\n }\n\n const {file: dbPath, walMode} = await setupReplica(\n lc,\n fileMode,\n config.replica,\n );\n unregisterInitialCorruptionDiagnosticTarget();\n registerSQLiteCorruptionDiagnosticTarget(\n {\n debugName: `${workerName} replica`,\n dbPath,\n },\n config.sqliteCorruptionChecks,\n );\n\n // A file left behind by a run with the writer enabled would otherwise hold\n // local disk indefinitely. See `replicatorDeletesStaleChangeLog` for why\n // this is keyed on the config flag and nothing else.\n deleteStaleChangeLog(config.changeStreamer.sqliteChangeLogMode, dbPath);\n\n setupMetrics(lc, dbPath, walMode);\n\n // Create the write worker for async SQLite writes.\n const pragmas = getPragmaConfig(fileMode);\n const workerClient = new ThreadWriteWorkerClient();\n await workerClient.init(dbPath, mode, pragmas, config.log);\n\n const shard = getShardConfig(config);\n const {\n taskID,\n change,\n changeStreamer: {\n port,\n uri: changeStreamerURI = runningLocalChangeStreamer\n ? `http://localhost:${port}/`\n : undefined,\n },\n } = config;\n const changeStreamer = new ChangeStreamerHttpClient(\n lc,\n shard,\n change.db,\n changeStreamerURI,\n );\n\n const replicator = new ReplicatorService(\n lc,\n taskID,\n `${workerName}-${pid}`,\n mode,\n dbPath,\n changeStreamer,\n workerClient,\n runningLocalChangeStreamer\n ? // publish ReplicationStatusEvents from backup-replicator only\n ReplicationStatusPublisher.forReplicaFile(dbPath)\n : null,\n );\n\n setUpMessageHandlers(lc, replicator, parent);\n\n const running = runUntilKilled(lc, parent, replicator);\n\n // Signal readiness once the first ReplicaVersionReady notification is received.\n for await (const _ of replicator.subscribe()) {\n parent.send(['ready', {ready: true}]);\n break;\n }\n\n return running;\n}\n\nfunction setupMetrics(lc: LogContext, file: string, walMode: WalMode) {\n getOrCreateGauge('replica', 'db_size', {\n description:\n `The size of the replica's main db file, ` +\n `which does not include the wal file(s)`,\n unit: 'bytes',\n }).addCallback(observeFileSize(lc, file));\n\n getOrCreateGauge('replica', 'wal_size', {\n description: `The size of the replica's wal file`,\n unit: 'bytes',\n }).addCallback(observeFileSize(lc, `${file}-wal`));\n\n if (walMode === 'wal2') {\n getOrCreateGauge('replica', 'wal2_size', {\n description: `The size of the replica's wal2 file`,\n unit: 'bytes',\n }).addCallback(observeFileSize(lc, `${file}-wal2`));\n }\n\n // A whole-database total rather than a per-file one. Its counterpart,\n // `sqlite_change_log.file_bytes`, is emitted by the change-streamer, which is\n // the process that writes the log.\n getOrCreateGauge('replica', 'file_bytes', {\n description:\n `The replica's total on-disk footprint: its main db file plus its ` +\n `wal sidecars.`,\n unit: 'By',\n }).addCallback(observeSQLiteFileBytes(lc, file));\n}\n\nfunction observeFileSize(lc: LogContext, file: string): ObservableCallback {\n return async o => {\n try {\n const stats = await stat(file);\n o.observe(stats.size);\n } catch (e) {\n lc.warn?.(`unable to stat ${file} for size metrics`, e);\n }\n };\n}\n\nfunction observeSQLiteFileBytes(\n lc: LogContext,\n file: string,\n): ObservableCallback {\n return async o => o.observe(await sqliteFileBytes(lc, file));\n}\n\nconst RETRY_INTERVAL_MS = 3000;\n\n// View-syncers (no replicaConstraints) wait indefinitely for the\n// replication-manager to publish a restorable backup. On a fresh stack the\n// first backup is not durable until the initial sync completes and litestream\n// uploads the initial snapshot, which can take many minutes for a large\n// replica. The platform's startup probe budget (which scales with replica\n// size) is the backstop, so restoreReplica must not impose its own shorter\n// cap and self-terminate while the backup is still being produced.\nasync function restoreReplica(lc: LogContext, config: NormalizedZeroConfig) {\n const start = performance.now();\n let backupURL: string | undefined;\n let result: RestoreResult | undefined;\n try {\n for (;;) {\n const snapshotStatus = await reserveAndGetSnapshotStatus(lc, config);\n // The backupURL comes from the replication-manager's snapshot response.\n ({backupURL} = snapshotStatus);\n const litestream: LitestreamConfig = {...config.litestream, backupURL};\n const attempt = await tryRestore(\n lc,\n litestream,\n config.replica.file,\n snapshotStatus,\n 'view_syncer',\n );\n if (attempt.restored) {\n result = attempt.result;\n return;\n }\n lc.info?.(\n `replica not found. retrying in ${RETRY_INTERVAL_MS / 1000} seconds`,\n );\n await sleep(RETRY_INTERVAL_MS);\n }\n } finally {\n const attrs = litestreamRestoreMetricAttrs(\n config.litestream,\n 'view_syncer',\n backupURL,\n );\n const labels = {...attrs, result: result ?? 'error'};\n litestreamRestoreRuns().add(1, labels);\n litestreamRestoreDuration().recordMs(performance.now() - start, labels);\n }\n}\n\n// fork()\nif (!singleProcessMode()) {\n void exitAfter(\n () => lc,\n () => runWorker(must(parentWorker), process.env, ...process.argv.slice(2)),\n );\n}\n"],"mappings":"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"}
@@ -66,8 +66,9 @@ async function runWorker(parent, env) {
66
66
  }, startZeroCache, () => printStartupMessage(env)));
67
67
  } catch (err) {
68
68
  processes.logErrorAndExit(err, "main");
69
+ } finally {
70
+ await processes.shutdown();
69
71
  }
70
- await processes.done();
71
72
  }
72
73
  //#endregion
73
74
  export { runWorker };
@@ -1 +1 @@
1
- {"version":3,"file":"run-worker.js","names":[],"sources":["../../../../../../zero-cache/src/server/runner/run-worker.ts"],"sourcesContent":["import '../../../../shared/src/dotenv.ts';\n\nimport {styleText} from 'node:util';\nimport {resolver, type Resolver} from '@rocicorp/resolver';\nimport {colorConsole} from '../../../../shared/src/logging.ts';\nimport {PROTOCOL_VERSION} from '../../../../zero-protocol/src/protocol-version.ts';\nimport {normalizeZeroConfig} from '../../config/normalize.ts';\nimport {getServerVersion, getZeroConfig} from '../../config/zero-config.ts';\nimport {ProcessManager, runUntilKilled} from '../../services/life-cycle.ts';\nimport {childWorker, type Worker} from '../../types/processes.ts';\nimport {createLogContext} from '../logging.ts';\nimport {MAIN_URL} from '../worker-urls.ts';\nimport {getTaskID} from './runtime.ts';\nimport {ZeroDispatcher} from './zero-dispatcher.ts';\n\nconst startupMessageEnv = 'ZERO_ENABLE_STARTUP_MESSAGE';\n\nfunction printStartupMessage(env: NodeJS.ProcessEnv) {\n if (env[startupMessageEnv] !== '1') {\n return;\n }\n\n colorConsole.log(\n `\\nBTW, ${styleText(['bold', 'cyan'], 'Cloud Zero')} ` +\n 'is now available - professional Zero hosting from the team that built it.\\n' +\n `Get started now: ${styleText(['blue', 'underline'], 'https://zero.rocicorp.dev/cloud')}\\n\\n` +\n styleText('dim', `Disable this message with ${startupMessageEnv}=0`) +\n '\\n',\n );\n}\n\n/**\n * Top-level `runner` entry point to the zero-cache. This layer is responsible for:\n * * runtime-based config normalization\n * * lazy startup\n * * serving /statsz\n * * auto-reset restarts (TODO)\n */\nexport async function runWorker(\n parent: Worker | null,\n env: NodeJS.ProcessEnv,\n): Promise<void> {\n // Note: Deprecation warnings are only emitted at this top-level parse;\n // they are suppressed when parsed in subprocesses.\n const cfg = getZeroConfig({env, emitDeprecationWarnings: true});\n const lc = createLogContext(cfg, 'runner');\n\n const defaultTaskID = await getTaskID(lc);\n const config = normalizeZeroConfig(lc, cfg, env, defaultTaskID);\n const processes = new ProcessManager(lc, parent ?? process);\n\n const {port, keepaliveTimeoutMs, lazyStartup} = config;\n const serverVersion = getServerVersion(config);\n lc.info?.(`starting server${!serverVersion ? '' : `@${serverVersion}`} `, {\n protocolVersion: PROTOCOL_VERSION,\n taskID: config.taskID,\n app: config.app,\n shard: config.shard,\n port: config.port,\n });\n\n let zeroCache: Resolver<Worker> | undefined;\n function startZeroCache(): Promise<Worker> {\n if (zeroCache === undefined) {\n const startMs = performance.now();\n lc.info?.('starting zero-cache');\n\n const r = (zeroCache = resolver<Worker>());\n const w = childWorker(MAIN_URL, env)\n .once('message', () => {\n r.resolve(w);\n lc.info?.(`zero-cache ready (${performance.now() - startMs} ms)`);\n })\n .once('error', r.reject);\n\n processes.addWorker(w, 'user-facing', 'zero-cache');\n }\n return zeroCache.promise;\n }\n\n // Eagerly start the zero-cache if it was not configured with --lazy-startup.\n if (!lazyStartup) {\n void startZeroCache();\n }\n\n await processes.allWorkersReady();\n parent?.send(['ready', {ready: true}]);\n\n try {\n await runUntilKilled(\n lc,\n parent ?? process,\n new ZeroDispatcher(\n config,\n lc,\n {port, keepaliveTimeoutMs},\n startZeroCache,\n () => printStartupMessage(env),\n ),\n );\n } catch (err) {\n processes.logErrorAndExit(err, 'main');\n }\n\n await processes.done();\n}\n"],"mappings":";;;;;;;;;;;;;;AAeA,IAAM,oBAAoB;AAE1B,SAAS,oBAAoB,KAAwB;CACnD,IAAI,IAAI,uBAAuB,KAC7B;CAGF,aAAa,IACX,UAAU,UAAU,CAAC,QAAQ,MAAM,GAAG,YAAY,EAAE;mBAE9B,UAAU,CAAC,QAAQ,WAAW,GAAG,iCAAiC,EAAE,QACxF,UAAU,OAAO,6BAA6B,kBAAkB,GAAG,IACnE,IACJ;AACF;;;;;;;;AASA,eAAsB,UACpB,QACA,KACe;CAGf,MAAM,MAAM,cAAc;EAAC;EAAK,yBAAyB;CAAI,CAAC;CAC9D,MAAM,KAAK,iBAAiB,KAAK,QAAQ;CAGzC,MAAM,SAAS,oBAAoB,IAAI,KAAK,KAAK,MADrB,UAAU,EAAE,CACsB;CAC9D,MAAM,YAAY,IAAI,eAAe,IAAI,UAAU,OAAO;CAE1D,MAAM,EAAC,MAAM,oBAAoB,gBAAe;CAChD,MAAM,gBAAgB,iBAAiB,MAAM;CAC7C,GAAG,OAAO,kBAAkB,CAAC,gBAAgB,KAAK,IAAI,gBAAgB,IAAI;EACxE,iBAAA;EACA,QAAQ,OAAO;EACf,KAAK,OAAO;EACZ,OAAO,OAAO;EACd,MAAM,OAAO;CACf,CAAC;CAED,IAAI;CACJ,SAAS,iBAAkC;EACzC,IAAI,cAAc,KAAA,GAAW;GAC3B,MAAM,UAAU,YAAY,IAAI;GAChC,GAAG,OAAO,qBAAqB;GAE/B,MAAM,IAAK,YAAY,SAAiB;GACxC,MAAM,IAAI,YAAY,UAAU,GAAG,EAChC,KAAK,iBAAiB;IACrB,EAAE,QAAQ,CAAC;IACX,GAAG,OAAO,qBAAqB,YAAY,IAAI,IAAI,QAAQ,KAAK;GAClE,CAAC,EACA,KAAK,SAAS,EAAE,MAAM;GAEzB,UAAU,UAAU,GAAG,eAAe,YAAY;EACpD;EACA,OAAO,UAAU;CACnB;CAGA,IAAI,CAAC,aACH,eAAoB;CAGtB,MAAM,UAAU,gBAAgB;CAChC,QAAQ,KAAK,CAAC,SAAS,EAAC,OAAO,KAAI,CAAC,CAAC;CAErC,IAAI;EACF,MAAM,eACJ,IACA,UAAU,SACV,IAAI,eACF,QACA,IACA;GAAC;GAAM;EAAkB,GACzB,sBACM,oBAAoB,GAAG,CAC/B,CACF;CACF,SAAS,KAAK;EACZ,UAAU,gBAAgB,KAAK,MAAM;CACvC;CAEA,MAAM,UAAU,KAAK;AACvB"}
1
+ {"version":3,"file":"run-worker.js","names":[],"sources":["../../../../../../zero-cache/src/server/runner/run-worker.ts"],"sourcesContent":["import '../../../../shared/src/dotenv.ts';\n\nimport {styleText} from 'node:util';\nimport {resolver, type Resolver} from '@rocicorp/resolver';\nimport {colorConsole} from '../../../../shared/src/logging.ts';\nimport {PROTOCOL_VERSION} from '../../../../zero-protocol/src/protocol-version.ts';\nimport {normalizeZeroConfig} from '../../config/normalize.ts';\nimport {getServerVersion, getZeroConfig} from '../../config/zero-config.ts';\nimport {ProcessManager, runUntilKilled} from '../../services/life-cycle.ts';\nimport {childWorker, type Worker} from '../../types/processes.ts';\nimport {createLogContext} from '../logging.ts';\nimport {MAIN_URL} from '../worker-urls.ts';\nimport {getTaskID} from './runtime.ts';\nimport {ZeroDispatcher} from './zero-dispatcher.ts';\n\nconst startupMessageEnv = 'ZERO_ENABLE_STARTUP_MESSAGE';\n\nfunction printStartupMessage(env: NodeJS.ProcessEnv) {\n if (env[startupMessageEnv] !== '1') {\n return;\n }\n\n colorConsole.log(\n `\\nBTW, ${styleText(['bold', 'cyan'], 'Cloud Zero')} ` +\n 'is now available - professional Zero hosting from the team that built it.\\n' +\n `Get started now: ${styleText(['blue', 'underline'], 'https://zero.rocicorp.dev/cloud')}\\n\\n` +\n styleText('dim', `Disable this message with ${startupMessageEnv}=0`) +\n '\\n',\n );\n}\n\n/**\n * Top-level `runner` entry point to the zero-cache. This layer is responsible for:\n * * runtime-based config normalization\n * * lazy startup\n * * serving /statsz\n * * auto-reset restarts (TODO)\n */\nexport async function runWorker(\n parent: Worker | null,\n env: NodeJS.ProcessEnv,\n): Promise<void> {\n // Note: Deprecation warnings are only emitted at this top-level parse;\n // they are suppressed when parsed in subprocesses.\n const cfg = getZeroConfig({env, emitDeprecationWarnings: true});\n const lc = createLogContext(cfg, 'runner');\n\n const defaultTaskID = await getTaskID(lc);\n const config = normalizeZeroConfig(lc, cfg, env, defaultTaskID);\n const processes = new ProcessManager(lc, parent ?? process);\n\n const {port, keepaliveTimeoutMs, lazyStartup} = config;\n const serverVersion = getServerVersion(config);\n lc.info?.(`starting server${!serverVersion ? '' : `@${serverVersion}`} `, {\n protocolVersion: PROTOCOL_VERSION,\n taskID: config.taskID,\n app: config.app,\n shard: config.shard,\n port: config.port,\n });\n\n let zeroCache: Resolver<Worker> | undefined;\n function startZeroCache(): Promise<Worker> {\n if (zeroCache === undefined) {\n const startMs = performance.now();\n lc.info?.('starting zero-cache');\n\n const r = (zeroCache = resolver<Worker>());\n const w = childWorker(MAIN_URL, env)\n .once('message', () => {\n r.resolve(w);\n lc.info?.(`zero-cache ready (${performance.now() - startMs} ms)`);\n })\n .once('error', r.reject);\n\n processes.addWorker(w, 'user-facing', 'zero-cache');\n }\n return zeroCache.promise;\n }\n\n // Eagerly start the zero-cache if it was not configured with --lazy-startup.\n if (!lazyStartup) {\n void startZeroCache();\n }\n\n await processes.allWorkersReady();\n parent?.send(['ready', {ready: true}]);\n\n try {\n await runUntilKilled(\n lc,\n parent ?? process,\n new ZeroDispatcher(\n config,\n lc,\n {port, keepaliveTimeoutMs},\n startZeroCache,\n () => printStartupMessage(env),\n ),\n );\n } catch (err) {\n processes.logErrorAndExit(err, 'main');\n } finally {\n await processes.shutdown();\n }\n}\n"],"mappings":";;;;;;;;;;;;;;AAeA,IAAM,oBAAoB;AAE1B,SAAS,oBAAoB,KAAwB;CACnD,IAAI,IAAI,uBAAuB,KAC7B;CAGF,aAAa,IACX,UAAU,UAAU,CAAC,QAAQ,MAAM,GAAG,YAAY,EAAE;mBAE9B,UAAU,CAAC,QAAQ,WAAW,GAAG,iCAAiC,EAAE,QACxF,UAAU,OAAO,6BAA6B,kBAAkB,GAAG,IACnE,IACJ;AACF;;;;;;;;AASA,eAAsB,UACpB,QACA,KACe;CAGf,MAAM,MAAM,cAAc;EAAC;EAAK,yBAAyB;CAAI,CAAC;CAC9D,MAAM,KAAK,iBAAiB,KAAK,QAAQ;CAGzC,MAAM,SAAS,oBAAoB,IAAI,KAAK,KAAK,MADrB,UAAU,EAAE,CACsB;CAC9D,MAAM,YAAY,IAAI,eAAe,IAAI,UAAU,OAAO;CAE1D,MAAM,EAAC,MAAM,oBAAoB,gBAAe;CAChD,MAAM,gBAAgB,iBAAiB,MAAM;CAC7C,GAAG,OAAO,kBAAkB,CAAC,gBAAgB,KAAK,IAAI,gBAAgB,IAAI;EACxE,iBAAA;EACA,QAAQ,OAAO;EACf,KAAK,OAAO;EACZ,OAAO,OAAO;EACd,MAAM,OAAO;CACf,CAAC;CAED,IAAI;CACJ,SAAS,iBAAkC;EACzC,IAAI,cAAc,KAAA,GAAW;GAC3B,MAAM,UAAU,YAAY,IAAI;GAChC,GAAG,OAAO,qBAAqB;GAE/B,MAAM,IAAK,YAAY,SAAiB;GACxC,MAAM,IAAI,YAAY,UAAU,GAAG,EAChC,KAAK,iBAAiB;IACrB,EAAE,QAAQ,CAAC;IACX,GAAG,OAAO,qBAAqB,YAAY,IAAI,IAAI,QAAQ,KAAK;GAClE,CAAC,EACA,KAAK,SAAS,EAAE,MAAM;GAEzB,UAAU,UAAU,GAAG,eAAe,YAAY;EACpD;EACA,OAAO,UAAU;CACnB;CAGA,IAAI,CAAC,aACH,eAAoB;CAGtB,MAAM,UAAU,gBAAgB;CAChC,QAAQ,KAAK,CAAC,SAAS,EAAC,OAAO,KAAI,CAAC,CAAC;CAErC,IAAI;EACF,MAAM,eACJ,IACA,UAAU,SACV,IAAI,eACF,QACA,IACA;GAAC;GAAM;EAAkB,GACzB,sBACM,oBAAoB,GAAG,CAC/B,CACF;CACF,SAAS,KAAK;EACZ,UAAU,gBAAgB,KAAK,MAAM;CACvC,UAAU;EACR,MAAM,UAAU,SAAS;CAC3B;AACF"}
@@ -1,5 +1,5 @@
1
1
  export declare const CHANGE_STREAMER_URL: URL;
2
- export declare const BACKUP_WATERMARK_READER_URL: URL;
2
+ export declare const BACKUP_WATERMARK_POLLER_URL: URL;
3
3
  export declare const MAIN_URL: URL;
4
4
  export declare const MUTATOR_URL: URL;
5
5
  export declare const REAPER_URL: URL;
@@ -6,7 +6,7 @@ function resolve(path) {
6
6
  return new URL(path, url);
7
7
  }
8
8
  var CHANGE_STREAMER_URL = resolve("./change-streamer.ts");
9
- var BACKUP_WATERMARK_READER_URL = resolve("./backup-watermark-reader.ts");
9
+ var BACKUP_WATERMARK_POLLER_URL = resolve("./backup-watermark-poller.ts");
10
10
  var MAIN_URL = resolve("./main.ts");
11
11
  resolve("./mutator.ts");
12
12
  var REAPER_URL = resolve("./reaper.ts");
@@ -15,6 +15,6 @@ var SHADOW_SYNCER_URL = resolve("./shadow-syncer.ts");
15
15
  var SYNCER_URL = resolve("./syncer.ts");
16
16
  var WRITE_WORKER_URL = resolve("./write-worker.ts");
17
17
  //#endregion
18
- export { BACKUP_WATERMARK_READER_URL, CHANGE_STREAMER_URL, MAIN_URL, REAPER_URL, REPLICATOR_URL, SHADOW_SYNCER_URL, SYNCER_URL, WRITE_WORKER_URL };
18
+ export { BACKUP_WATERMARK_POLLER_URL, CHANGE_STREAMER_URL, MAIN_URL, REAPER_URL, REPLICATOR_URL, SHADOW_SYNCER_URL, SYNCER_URL, WRITE_WORKER_URL };
19
19
 
20
20
  //# sourceMappingURL=worker-urls.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"worker-urls.js","names":[],"sources":["../../../../../zero-cache/src/server/worker-urls.ts"],"sourcesContent":["// This module provides URLs for worker files.\n\nconst tsRe = /\\.ts$/;\n\nfunction resolve(path: string): URL {\n const {url} = import.meta;\n if (url.endsWith('.js')) {\n // When compiled, change .ts to .js\n path = path.replace(tsRe, '.js');\n }\n return new URL(path, url);\n}\n\n// These URLs are part of the build process. See ../../zero/tool/build.ts\n// All these urls must be relative to this file and be located in the same directory.\n\nexport const CHANGE_STREAMER_URL = resolve('./change-streamer.ts');\nexport const BACKUP_WATERMARK_READER_URL = resolve(\n './backup-watermark-reader.ts',\n);\nexport const MAIN_URL = resolve('./main.ts');\nexport const MUTATOR_URL = resolve('./mutator.ts');\nexport const REAPER_URL = resolve('./reaper.ts');\nexport const REPLICATOR_URL = resolve('./replicator.ts');\nexport const SHADOW_SYNCER_URL = resolve('./shadow-syncer.ts');\nexport const SYNCER_URL = resolve('./syncer.ts');\nexport const WRITE_WORKER_URL = resolve('./write-worker.ts');\n"],"mappings":";AAEA,IAAM,OAAO;AAEb,SAAS,QAAQ,MAAmB;CAClC,MAAM,EAAC,QAAO,OAAO;CACrB,IAAI,IAAI,SAAS,KAAK,GAEpB,OAAO,KAAK,QAAQ,MAAM,KAAK;CAEjC,OAAO,IAAI,IAAI,MAAM,GAAG;AAC1B;AAKA,IAAa,sBAAsB,QAAQ,sBAAsB;AACjE,IAAa,8BAA8B,QACzC,8BACF;AACA,IAAa,WAAW,QAAQ,WAAW;AAChB,QAAQ,cAAc;AACjD,IAAa,aAAa,QAAQ,aAAa;AAC/C,IAAa,iBAAiB,QAAQ,iBAAiB;AACvD,IAAa,oBAAoB,QAAQ,oBAAoB;AAC7D,IAAa,aAAa,QAAQ,aAAa;AAC/C,IAAa,mBAAmB,QAAQ,mBAAmB"}
1
+ {"version":3,"file":"worker-urls.js","names":[],"sources":["../../../../../zero-cache/src/server/worker-urls.ts"],"sourcesContent":["// This module provides URLs for worker files.\n\nconst tsRe = /\\.ts$/;\n\nfunction resolve(path: string): URL {\n const {url} = import.meta;\n if (url.endsWith('.js')) {\n // When compiled, change .ts to .js\n path = path.replace(tsRe, '.js');\n }\n return new URL(path, url);\n}\n\n// These URLs are part of the build process. See ../../zero/tool/build.ts\n// All these urls must be relative to this file and be located in the same directory.\n\nexport const CHANGE_STREAMER_URL = resolve('./change-streamer.ts');\nexport const BACKUP_WATERMARK_POLLER_URL = resolve(\n './backup-watermark-poller.ts',\n);\nexport const MAIN_URL = resolve('./main.ts');\nexport const MUTATOR_URL = resolve('./mutator.ts');\nexport const REAPER_URL = resolve('./reaper.ts');\nexport const REPLICATOR_URL = resolve('./replicator.ts');\nexport const SHADOW_SYNCER_URL = resolve('./shadow-syncer.ts');\nexport const SYNCER_URL = resolve('./syncer.ts');\nexport const WRITE_WORKER_URL = resolve('./write-worker.ts');\n"],"mappings":";AAEA,IAAM,OAAO;AAEb,SAAS,QAAQ,MAAmB;CAClC,MAAM,EAAC,QAAO,OAAO;CACrB,IAAI,IAAI,SAAS,KAAK,GAEpB,OAAO,KAAK,QAAQ,MAAM,KAAK;CAEjC,OAAO,IAAI,IAAI,MAAM,GAAG;AAC1B;AAKA,IAAa,sBAAsB,QAAQ,sBAAsB;AACjE,IAAa,8BAA8B,QACzC,8BACF;AACA,IAAa,WAAW,QAAQ,WAAW;AAChB,QAAQ,cAAc;AACjD,IAAa,aAAa,QAAQ,aAAa;AAC/C,IAAa,iBAAiB,QAAQ,iBAAiB;AACvD,IAAa,oBAAoB,QAAQ,oBAAoB;AAC7D,IAAa,aAAa,QAAQ,aAAa;AAC/C,IAAa,mBAAmB,QAAQ,mBAAmB"}
@@ -11,10 +11,12 @@ export type ChangeStream = {
11
11
  }; /** Encapsulates an upstream-specific implementation of a stream of Changes. */
12
12
  export interface ChangeSource {
13
13
  /**
14
- * Starts a replication lag reporter, returning the send time of the next
15
- * expected report, or `null` if lag reporting is not supported / enabled.
14
+ * Starts a replication lag reporter, returning the commit time of the first
15
+ * report, and the send time of the next expected report, or `null` if lag
16
+ * reporting is not supported / enabled.
16
17
  */
17
18
  startLagReporter(): Promise<{
19
+ firstCommitTimeMs: number;
18
20
  nextSendTimeMs: number;
19
21
  } | null> | null;
20
22
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"change-source.d.ts","sourceRoot":"","sources":["../../../../../../zero-cache/src/services/change-source/change-source.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,IAAI,EAAE,MAAM,EAAC,MAAM,wBAAwB,CAAC;AACzD,OAAO,KAAK,EACV,eAAe,EACf,oBAAoB,EACpB,mBAAmB,EACpB,MAAM,uBAAuB,CAAC;AAE/B,MAAM,MAAM,YAAY,GAAG;IACzB,OAAO,EAAE,MAAM,CAAC,mBAAmB,CAAC,CAAC;IAErC;;;;OAIG;IACH,IAAI,EAAE,IAAI,CAAC,oBAAoB,CAAC,CAAC;CAClC,CAAC,CAAC,+EAA+E;AAElF,MAAM,WAAW,YAAY;IAC3B;;;OAGG;IACH,gBAAgB,IAAI,OAAO,CAAC;QAAC,cAAc,EAAE,MAAM,CAAA;KAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC;IAEpE;;;OAGG;IACH,WAAW,CACT,cAAc,EAAE,MAAM,EACtB,gBAAgB,CAAC,EAAE,eAAe,EAAE,GACnC,OAAO,CAAC,YAAY,CAAC,CAAC;IAEzB;;OAEG;IACH,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB"}
1
+ {"version":3,"file":"change-source.d.ts","sourceRoot":"","sources":["../../../../../../zero-cache/src/services/change-source/change-source.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,IAAI,EAAE,MAAM,EAAC,MAAM,wBAAwB,CAAC;AACzD,OAAO,KAAK,EACV,eAAe,EACf,oBAAoB,EACpB,mBAAmB,EACpB,MAAM,uBAAuB,CAAC;AAE/B,MAAM,MAAM,YAAY,GAAG;IACzB,OAAO,EAAE,MAAM,CAAC,mBAAmB,CAAC,CAAC;IAErC;;;;OAIG;IACH,IAAI,EAAE,IAAI,CAAC,oBAAoB,CAAC,CAAC;CAClC,CAAC,CAAC,+EAA+E;AAElF,MAAM,WAAW,YAAY;IAC3B;;;;OAIG;IACH,gBAAgB,IAAI,OAAO,CAAC;QAC1B,iBAAiB,EAAE,MAAM,CAAC;QAC1B,cAAc,EAAE,MAAM,CAAC;KACxB,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC;IAEjB;;;OAGG;IACH,WAAW,CACT,cAAc,EAAE,MAAM,EACtB,gBAAgB,CAAC,EAAE,eAAe,EAAE,GACnC,OAAO,CAAC,YAAY,CAAC,CAAC;IAEzB;;OAEG;IACH,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB"}
@@ -0,0 +1,35 @@
1
+ import type { LogContext } from '@rocicorp/logger';
2
+ import type { LitestreamConfig } from '../../../config/normalize.ts';
3
+ import { type ReplicaConstraints } from '../../litestream/commands.ts';
4
+ import type { SubscriptionState } from '../../replicator/schema/replication-state.ts';
5
+ import type { ChangeSource } from '../change-source.ts';
6
+ export type RestoreOptions = {
7
+ litestream?: LitestreamConfig;
8
+ constraints?: ReplicaConstraints | undefined;
9
+ };
10
+ export type InitializeResult = {
11
+ subscriptionState: SubscriptionState;
12
+ changeSource: ChangeSource;
13
+ destinationBackupURL: string | undefined;
14
+ /**
15
+ * The replica this change stream belongs to, from the upstream `replicas`
16
+ * table. It is part of the identity the SQLite change log records, because a
17
+ * generation (i.e. `replicaVersion`) is shared by every sibling of a forked
18
+ * replica and so cannot distinguish two siblings' logs. `null` when the
19
+ * change source has no upstream table to identify itself from.
20
+ */
21
+ replicaID: string | null;
22
+ /**
23
+ * Whether server readiness should be gated on the first litestream backup,
24
+ * in order to ensure that a newly connecting subscriber can restore from
25
+ * this change-streamer's backup.
26
+ *
27
+ * This should be true when the backup destination differs from where the
28
+ * backup was restored from, which is the case for (1) initial-sync and
29
+ * (2) most initialization cases in RMv2, with the exception being when
30
+ * an abandoned replica is resumed.
31
+ */
32
+ waitForBackupBeforeServing: boolean;
33
+ };
34
+ export declare function restoreReplica(lc: LogContext, config: LitestreamConfig, replicaFile: string, replicaConstraints: ReplicaConstraints | undefined): Promise<void>;
35
+ //# sourceMappingURL=replica-restore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"replica-restore.d.ts","sourceRoot":"","sources":["../../../../../../../zero-cache/src/services/change-source/common/replica-restore.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAEjD,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,8BAA8B,CAAC;AACnE,OAAO,EAEL,KAAK,kBAAkB,EAExB,MAAM,8BAA8B,CAAC;AAMtC,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,8CAA8C,CAAC;AACpF,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,qBAAqB,CAAC;AAEtD,MAAM,MAAM,cAAc,GAAG;IAC3B,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,WAAW,CAAC,EAAE,kBAAkB,GAAG,SAAS,CAAC;CAC9C,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,iBAAiB,EAAE,iBAAiB,CAAC;IACrC,YAAY,EAAE,YAAY,CAAC;IAC3B,oBAAoB,EAAE,MAAM,GAAG,SAAS,CAAC;IACzC;;;;;;OAMG;IACH,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAEzB;;;;;;;;;OASG;IACH,0BAA0B,EAAE,OAAO,CAAC;CACrC,CAAC;AAOF,wBAAsB,cAAc,CAClC,EAAE,EAAE,UAAU,EACd,MAAM,EAAE,gBAAgB,EACxB,WAAW,EAAE,MAAM,EACnB,kBAAkB,EAAE,kBAAkB,GAAG,SAAS,GACjD,OAAO,CAAC,IAAI,CAAC,CAyCf"}
@@ -0,0 +1,34 @@
1
+ import { sleep } from "../../../../../shared/src/sleep.js";
2
+ import { litestreamRestoreDuration, litestreamRestoreMetricAttrs, litestreamRestoreRuns } from "../../litestream/metrics.js";
3
+ import { tryRestore } from "../../litestream/commands.js";
4
+ //#region ../zero-cache/src/services/change-source/common/replica-restore.ts
5
+ var MAX_RESTORE_ATTEMPTS = 3;
6
+ var RESTORE_RETRY_DELAY_MS = 5e3;
7
+ async function restoreReplica(lc, config, replicaFile, replicaConstraints) {
8
+ const start = performance.now();
9
+ let result;
10
+ try {
11
+ for (let attemptNum = 1; attemptNum <= MAX_RESTORE_ATTEMPTS; attemptNum++) try {
12
+ result = (await tryRestore(lc, config, replicaFile, replicaConstraints, "replication_manager")).result;
13
+ return;
14
+ } catch (e) {
15
+ if (attemptNum === MAX_RESTORE_ATTEMPTS) {
16
+ lc.error?.(`litestream restore failed after ${attemptNum} attempts; resyncing the replica`, e);
17
+ return;
18
+ }
19
+ lc.warn?.(`litestream restore attempt ${attemptNum} failed; retrying in ${RESTORE_RETRY_DELAY_MS}ms (attempt ${attemptNum + 1} of ${MAX_RESTORE_ATTEMPTS})`, e);
20
+ await sleep(RESTORE_RETRY_DELAY_MS);
21
+ }
22
+ } finally {
23
+ const labels = {
24
+ ...litestreamRestoreMetricAttrs(config, "replication_manager"),
25
+ result: result ?? "error"
26
+ };
27
+ litestreamRestoreRuns().add(1, labels);
28
+ litestreamRestoreDuration().recordMs(performance.now() - start, labels);
29
+ }
30
+ }
31
+ //#endregion
32
+ export { restoreReplica };
33
+
34
+ //# sourceMappingURL=replica-restore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"replica-restore.js","names":[],"sources":["../../../../../../../zero-cache/src/services/change-source/common/replica-restore.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {sleep} from '../../../../../shared/src/sleep.ts';\nimport type {LitestreamConfig} from '../../../config/normalize.ts';\nimport {\n tryRestore,\n type ReplicaConstraints,\n type RestoreResult,\n} from '../../litestream/commands.ts';\nimport {\n litestreamRestoreDuration,\n litestreamRestoreMetricAttrs,\n litestreamRestoreRuns,\n} from '../../litestream/metrics.ts';\nimport type {SubscriptionState} from '../../replicator/schema/replication-state.ts';\nimport type {ChangeSource} from '../change-source.ts';\n\nexport type RestoreOptions = {\n litestream?: LitestreamConfig;\n constraints?: ReplicaConstraints | undefined;\n};\n\nexport type InitializeResult = {\n subscriptionState: SubscriptionState;\n changeSource: ChangeSource;\n destinationBackupURL: string | undefined;\n /**\n * The replica this change stream belongs to, from the upstream `replicas`\n * table. It is part of the identity the SQLite change log records, because a\n * generation (i.e. `replicaVersion`) is shared by every sibling of a forked\n * replica and so cannot distinguish two siblings' logs. `null` when the\n * change source has no upstream table to identify itself from.\n */\n replicaID: string | null;\n\n /**\n * Whether server readiness should be gated on the first litestream backup,\n * in order to ensure that a newly connecting subscriber can restore from\n * this change-streamer's backup.\n *\n * This should be true when the backup destination differs from where the\n * backup was restored from, which is the case for (1) initial-sync and\n * (2) most initialization cases in RMv2, with the exception being when\n * an abandoned replica is resumed.\n */\n waitForBackupBeforeServing: boolean;\n};\n\n// A short retry is much cheaper than an initial Postgres sync, while keeping a\n// persistent failure from delaying startup appreciably.\nconst MAX_RESTORE_ATTEMPTS = 3;\nconst RESTORE_RETRY_DELAY_MS = 5_000;\n\nexport async function restoreReplica(\n lc: LogContext,\n config: LitestreamConfig,\n replicaFile: string,\n replicaConstraints: ReplicaConstraints | undefined,\n): Promise<void> {\n const start = performance.now();\n let result: RestoreResult | undefined;\n try {\n // `tryRestore` returns ordinary restore outcomes (no backup or an invalid\n // replica) rather than throwing; preserve their existing immediate\n // initial-sync fallback. Retry every thrown restore error twice before\n // falling back to the initial Postgres sync.\n for (let attemptNum = 1; attemptNum <= MAX_RESTORE_ATTEMPTS; attemptNum++) {\n try {\n const attempt = await tryRestore(\n lc,\n config,\n replicaFile,\n replicaConstraints,\n 'replication_manager',\n );\n result = attempt.result;\n return;\n } catch (e) {\n if (attemptNum === MAX_RESTORE_ATTEMPTS) {\n lc.error?.(\n `litestream restore failed after ${attemptNum} attempts; resyncing the replica`,\n e,\n );\n return;\n }\n\n lc.warn?.(\n `litestream restore attempt ${attemptNum} failed; retrying in ${RESTORE_RETRY_DELAY_MS}ms (attempt ${attemptNum + 1} of ${MAX_RESTORE_ATTEMPTS})`,\n e,\n );\n await sleep(RESTORE_RETRY_DELAY_MS);\n }\n }\n } finally {\n const attrs = litestreamRestoreMetricAttrs(config, 'replication_manager');\n const labels = {...attrs, result: result ?? 'error'};\n litestreamRestoreRuns().add(1, labels);\n litestreamRestoreDuration().recordMs(performance.now() - start, labels);\n }\n}\n"],"mappings":";;;;AAiDA,IAAM,uBAAuB;AAC7B,IAAM,yBAAyB;AAE/B,eAAsB,eACpB,IACA,QACA,aACA,oBACe;CACf,MAAM,QAAQ,YAAY,IAAI;CAC9B,IAAI;CACJ,IAAI;EAKF,KAAK,IAAI,aAAa,GAAG,cAAc,sBAAsB,cAC3D,IAAI;GAQF,UAAS,MAPa,WACpB,IACA,QACA,aACA,oBACA,qBACF,GACiB;GACjB;EACF,SAAS,GAAG;GACV,IAAI,eAAe,sBAAsB;IACvC,GAAG,QACD,mCAAmC,WAAW,mCAC9C,CACF;IACA;GACF;GAEA,GAAG,OACD,8BAA8B,WAAW,uBAAuB,uBAAuB,cAAc,aAAa,EAAE,MAAM,qBAAqB,IAC/I,CACF;GACA,MAAM,MAAM,sBAAsB;EACpC;CAEJ,UAAU;EAER,MAAM,SAAS;GAAC,GADF,6BAA6B,QAAQ,qBAChC;GAAO,QAAQ,UAAU;EAAO;EACnD,sBAAsB,EAAE,IAAI,GAAG,MAAM;EACrC,0BAA0B,EAAE,SAAS,YAAY,IAAI,IAAI,OAAO,MAAM;CACxE;AACF"}
@@ -6,6 +6,8 @@ export declare function upgradeReplica(log: LogContext, debugName: string, dbPat
6
6
  export declare const CREATE_V6_COLUMN_METADATA_TABLE = "\n CREATE TABLE \"_zero.column_metadata\" (\n table_name TEXT NOT NULL,\n column_name TEXT NOT NULL,\n upstream_type TEXT NOT NULL,\n is_not_null INTEGER NOT NULL,\n is_enum INTEGER NOT NULL,\n is_array INTEGER NOT NULL,\n character_max_length INTEGER,\n PRIMARY KEY (table_name, column_name)\n );\n";
7
7
  export declare const CREATE_V7_CHANGE_LOG = "\n CREATE TABLE \"_zero.changeLog2\" (\n \"stateVersion\" TEXT NOT NULL,\n \"pos\" INT NOT NULL,\n \"table\" TEXT NOT NULL,\n \"rowKey\" TEXT NOT NULL,\n \"op\" TEXT NOT NULL,\n PRIMARY KEY(\"stateVersion\", \"pos\"),\n UNIQUE(\"table\", \"rowKey\")\n );\n";
8
8
  export declare const CREATE_V9_TABLE_METADATA_TABLE = "\n CREATE TABLE \"_zero.tableMetadata\" (\n \"schema\" TEXT NOT NULL,\n \"table\" TEXT NOT NULL,\n \"metadata\" TEXT NOT NULL,\n PRIMARY KEY (\"schema\", \"table\")\n );\n";
9
+ export declare const V14_CHANGE_LOG_STREAM_TABLE = "_zero.changeLogStream";
10
+ export declare const CREATE_V14_CHANGE_LOG_STREAM = "\n CREATE TABLE \"_zero.changeLogStream\" (\n \"watermark\" TEXT NOT NULL,\n \"pos\" INTEGER NOT NULL,\n \"change\" TEXT NOT NULL,\n \"precommit\" TEXT,\n \"writeTimeMs\" INTEGER,\n PRIMARY KEY (\"watermark\", \"pos\")\n );\n\n CREATE INDEX \"_zero.changeLogStream_writeTimeMs\"\n ON \"_zero.changeLogStream\" (\"writeTimeMs\", \"watermark\")\n WHERE \"writeTimeMs\" IS NOT NULL;\n";
9
11
  export declare const schemaVersionMigrationMap: IncrementalMigrationMap;
10
12
  export declare const CURRENT_SCHEMA_VERSION: number;
11
13
  //# sourceMappingURL=replica-schema.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"replica-schema.d.ts","sourceRoot":"","sources":["../../../../../../../zero-cache/src/services/change-source/common/replica-schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AACjD,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,iCAAiC,CAAC;AAE9D,OAAO,EAEL,KAAK,uBAAuB,EAE7B,MAAM,+BAA+B,CAAC;AAYvC,wBAAsB,WAAW,CAC/B,GAAG,EAAE,UAAU,EACf,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,CAAC,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE,QAAQ,KAAK,OAAO,CAAC,IAAI,CAAC,GAC3D,OAAO,CAAC,IAAI,CAAC,CAiBf;AAED,wBAAsB,cAAc,CAClC,GAAG,EAAE,UAAU,EACf,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,iBAoBf;AAkBD,eAAO,MAAM,+BAA+B,0UAW3C,CAAC;AAEF,eAAO,MAAM,oBAAoB,8XAUhC,CAAC;AAEF,eAAO,MAAM,8BAA8B,sMAO1C,CAAC;AAEF,eAAO,MAAM,yBAAyB,EAAE,uBA8HvC,CAAC;AAGF,eAAO,MAAM,sBAAsB,QAEwB,CAAC"}
1
+ {"version":3,"file":"replica-schema.d.ts","sourceRoot":"","sources":["../../../../../../../zero-cache/src/services/change-source/common/replica-schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAEjD,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,iCAAiC,CAAC;AAE9D,OAAO,EAEL,KAAK,uBAAuB,EAE7B,MAAM,+BAA+B,CAAC;AAgBvC,wBAAsB,WAAW,CAC/B,GAAG,EAAE,UAAU,EACf,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,CAAC,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE,QAAQ,KAAK,OAAO,CAAC,IAAI,CAAC,GAC3D,OAAO,CAAC,IAAI,CAAC,CAiBf;AAED,wBAAsB,cAAc,CAClC,GAAG,EAAE,UAAU,EACf,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,iBAoBf;AAkBD,eAAO,MAAM,+BAA+B,0UAW3C,CAAC;AAEF,eAAO,MAAM,oBAAoB,8XAUhC,CAAC;AAEF,eAAO,MAAM,8BAA8B,sMAO1C,CAAC;AAKF,eAAO,MAAM,2BAA2B,0BAA0B,CAAC;AAQnE,eAAO,MAAM,4BAA4B,8aAaxC,CAAC;AA4BF,eAAO,MAAM,yBAAyB,EAAE,uBA+MvC,CAAC;AAGF,eAAO,MAAM,sBAAsB,QAEwB,CAAC"}
@@ -1,9 +1,11 @@
1
+ import { assert } from "../../../../../shared/src/asserts.js";
1
2
  import { populateFromExistingTables } from "../../replicator/schema/column-metadata.js";
2
3
  import { listTables } from "../../../db/lite-tables.js";
4
+ import { CREATE_BACKFILLING_TABLE, populateBackfillingFromColumnMetadata } from "../../replicator/schema/backfilling.js";
3
5
  import { CREATE_RUNTIME_EVENTS_TABLE, recordEvent } from "../../replicator/schema/replication-state.js";
4
6
  import { isSQLiteCorruption, logSQLiteCorruptionDiagnostics } from "../../../db/sqlite-corruption.js";
5
- import { runSchemaMigrations } from "../../../db/migration-lite.js";
6
7
  import { AutoResetSignal } from "../../change-streamer/schema/tables.js";
8
+ import { runSchemaMigrations } from "../../../db/migration-lite.js";
7
9
  //#region ../zero-cache/src/services/change-source/common/replica-schema.ts
8
10
  async function initReplica(log, debugName, dbPath, initialSync) {
9
11
  const setupMigration = {
@@ -63,6 +65,38 @@ var CREATE_V9_TABLE_METADATA_TABLE = `
63
65
  PRIMARY KEY ("schema", "table")
64
66
  );
65
67
  `;
68
+ var V14_CHANGE_LOG_STREAM_TABLE = "_zero.changeLogStream";
69
+ var V14_CHANGE_LOG_STREAM_WRITE_TIME_INDEX = "_zero.changeLogStream_writeTimeMs";
70
+ var CREATE_V14_CHANGE_LOG_STREAM = `
71
+ CREATE TABLE "${V14_CHANGE_LOG_STREAM_TABLE}" (
72
+ "watermark" TEXT NOT NULL,
73
+ "pos" INTEGER NOT NULL,
74
+ "change" TEXT NOT NULL,
75
+ "precommit" TEXT,
76
+ "writeTimeMs" INTEGER,
77
+ PRIMARY KEY ("watermark", "pos")
78
+ );
79
+
80
+ CREATE INDEX "${V14_CHANGE_LOG_STREAM_WRITE_TIME_INDEX}"
81
+ ON "${V14_CHANGE_LOG_STREAM_TABLE}" ("writeTimeMs", "watermark")
82
+ WHERE "writeTimeMs" IS NOT NULL;
83
+ `;
84
+ var SEED_V14_CHANGE_LOG_STREAM = `
85
+ INSERT INTO "${V14_CHANGE_LOG_STREAM_TABLE}"
86
+ ("watermark", "pos", "change", "precommit", "writeTimeMs")
87
+ VALUES
88
+ (@stateVersion, 0, '{"tag":"begin"}', NULL, NULL),
89
+ (@stateVersion, 1, '{"tag":"commit"}', @stateVersion, @writeTimeMs)
90
+ ON CONFLICT ("watermark", "pos") DO NOTHING
91
+ `;
92
+ function seedV14ChangeLogStream(db) {
93
+ const state = db.prepare(`
94
+ SELECT "stateVersion", "writeTimeMs" FROM "_zero.replicationState"
95
+ `).get();
96
+ assert(state !== void 0, "replication state must be initialized");
97
+ assert(state.writeTimeMs !== null, "replication state writeTimeMs must be initialized");
98
+ db.prepare(SEED_V14_CHANGE_LOG_STREAM).run(state);
99
+ }
66
100
  var schemaVersionMigrationMap = {
67
101
  4: {
68
102
  migrateSchema: () => {
@@ -145,6 +179,44 @@ var schemaVersionMigrationMap = {
145
179
  UPDATE "_zero.replicationState"
146
180
  SET writeTimeMs = COALESCE(writeTimeMs, unixepoch('subsec') * 1000)`);
147
181
  }
182
+ },
183
+ 14: {
184
+ migrateSchema: (_, db) => {
185
+ db.exec(CREATE_V14_CHANGE_LOG_STREAM);
186
+ },
187
+ migrateData: (_, db) => {
188
+ seedV14ChangeLogStream(db);
189
+ }
190
+ },
191
+ 15: { migrateSchema: (_, db) => {
192
+ db.exec(`
193
+ CREATE TABLE "_zero.replicationState2" (
194
+ stateVersion TEXT NOT NULL,
195
+ writeTimeMs INTEGER NOT NULL,
196
+ lock INTEGER PRIMARY KEY DEFAULT 1 CHECK (lock=1)
197
+ );
198
+
199
+ INSERT INTO "_zero.replicationState2" (stateVersion, writeTimeMs, lock)
200
+ SELECT stateVersion, writeTimeMs, lock FROM "_zero.replicationState";
201
+
202
+ DROP TABLE "_zero.replicationState";
203
+
204
+ ALTER TABLE "_zero.replicationState2" RENAME TO "_zero.replicationState";
205
+ `);
206
+ } },
207
+ 16: { migrateSchema: (_, db) => {
208
+ db.exec(`
209
+ DROP INDEX IF EXISTS "${V14_CHANGE_LOG_STREAM_WRITE_TIME_INDEX}";
210
+ DROP TABLE IF EXISTS "${V14_CHANGE_LOG_STREAM_TABLE}";
211
+ `);
212
+ } },
213
+ 17: {
214
+ migrateSchema: (_, db) => {
215
+ db.exec(CREATE_BACKFILLING_TABLE);
216
+ },
217
+ migrateData: (lc, db) => {
218
+ populateBackfillingFromColumnMetadata(lc, db);
219
+ }
148
220
  }
149
221
  };
150
222
  Object.keys(schemaVersionMigrationMap).reduce((prev, curr) => Math.max(prev, parseInt(curr)), 0);
@@ -1 +1 @@
1
- {"version":3,"file":"replica-schema.js","names":[],"sources":["../../../../../../../zero-cache/src/services/change-source/common/replica-schema.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport type {Database} from '../../../../../zqlite/src/db.ts';\nimport {listTables} from '../../../db/lite-tables.ts';\nimport {\n runSchemaMigrations,\n type IncrementalMigrationMap,\n type Migration,\n} from '../../../db/migration-lite.ts';\nimport {\n isSQLiteCorruption,\n logSQLiteCorruptionDiagnostics,\n} from '../../../db/sqlite-corruption.ts';\nimport {AutoResetSignal} from '../../change-streamer/schema/tables.ts';\nimport {populateFromExistingTables} from '../../replicator/schema/column-metadata.ts';\nimport {\n CREATE_RUNTIME_EVENTS_TABLE,\n recordEvent,\n} from '../../replicator/schema/replication-state.ts';\n\nexport async function initReplica(\n log: LogContext,\n debugName: string,\n dbPath: string,\n initialSync: (lc: LogContext, tx: Database) => Promise<void>,\n): Promise<void> {\n const setupMigration: Migration = {\n migrateSchema: (log, tx) => initialSync(log, tx),\n minSafeVersion: 1,\n };\n\n try {\n await runSchemaMigrations(\n log,\n debugName,\n dbPath,\n setupMigration,\n schemaVersionMigrationMap,\n );\n } catch (e) {\n throwAutoResetForCorruption(log, debugName, dbPath, e);\n }\n}\n\nexport async function upgradeReplica(\n log: LogContext,\n debugName: string,\n dbPath: string,\n) {\n try {\n await runSchemaMigrations(\n log,\n debugName,\n dbPath,\n // setupMigration should never be invoked\n {\n migrateSchema: () => {\n throw new Error(\n 'This should only be called for already synced replicas',\n );\n },\n },\n schemaVersionMigrationMap,\n );\n } catch (e) {\n throwAutoResetForCorruption(log, debugName, dbPath, e);\n }\n}\n\nfunction throwAutoResetForCorruption(\n log: LogContext,\n debugName: string,\n dbPath: string,\n e: unknown,\n): never {\n if (isSQLiteCorruption(e)) {\n logSQLiteCorruptionDiagnostics(log, debugName, dbPath, e);\n throw new AutoResetSignal(\n `replica database appears corrupt: ${String(e)}`,\n {cause: e},\n );\n }\n throw e;\n}\n\nexport const CREATE_V6_COLUMN_METADATA_TABLE = /*sql*/ `\n CREATE TABLE \"_zero.column_metadata\" (\n table_name TEXT NOT NULL,\n column_name TEXT NOT NULL,\n upstream_type TEXT NOT NULL,\n is_not_null INTEGER NOT NULL,\n is_enum INTEGER NOT NULL,\n is_array INTEGER NOT NULL,\n character_max_length INTEGER,\n PRIMARY KEY (table_name, column_name)\n );\n`;\n\nexport const CREATE_V7_CHANGE_LOG = /*sql*/ `\n CREATE TABLE \"_zero.changeLog2\" (\n \"stateVersion\" TEXT NOT NULL,\n \"pos\" INT NOT NULL,\n \"table\" TEXT NOT NULL,\n \"rowKey\" TEXT NOT NULL,\n \"op\" TEXT NOT NULL,\n PRIMARY KEY(\"stateVersion\", \"pos\"),\n UNIQUE(\"table\", \"rowKey\")\n );\n`;\n\nexport const CREATE_V9_TABLE_METADATA_TABLE = /*sql*/ `\n CREATE TABLE \"_zero.tableMetadata\" (\n \"schema\" TEXT NOT NULL,\n \"table\" TEXT NOT NULL,\n \"metadata\" TEXT NOT NULL,\n PRIMARY KEY (\"schema\", \"table\")\n );\n`;\n\nexport const schemaVersionMigrationMap: IncrementalMigrationMap = {\n // There's no incremental migration from v1. Just reset the replica.\n 4: {\n migrateSchema: () => {\n throw new AutoResetSignal('upgrading replica to new schema');\n },\n minSafeVersion: 3,\n },\n\n 5: {\n migrateSchema: (_, db) => {\n db.exec(CREATE_RUNTIME_EVENTS_TABLE);\n },\n migrateData: (_, db) => {\n recordEvent(db, 'upgrade');\n },\n },\n\n // Revised in the migration to v8 because the v6 code was incomplete.\n 6: {},\n\n 7: {\n migrateSchema: (_, db) => {\n // Note: The original \"changeLog\" table is kept so that the replica file\n // is compatible with older zero-caches. However, it is truncated for\n // space savings (since historic changes were never read).\n db.exec(`DELETE FROM \"_zero.changeLog\"`);\n // First version of changeLog2\n db.exec(CREATE_V7_CHANGE_LOG);\n },\n },\n\n 8: {\n migrateSchema: (_, db) => {\n const tableExists = db\n .prepare(\n `SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = '_zero.column_metadata'`,\n )\n .get();\n\n if (!tableExists) {\n db.exec(CREATE_V6_COLUMN_METADATA_TABLE);\n }\n },\n migrateData: (_, db) => {\n // Re-populate the ColumnMetadataStore; the original migration\n // at v6 was incomplete, as covered replicas migrated from earlier\n // versions but did not initialize the table for new replicas.\n db.exec(/*sql*/ `DELETE FROM \"_zero.column_metadata\"`);\n\n const tables = listTables(db, false, false);\n populateFromExistingTables(db, tables);\n },\n },\n\n 9: {\n migrateSchema: (_, db) => {\n db.exec(\n /*sql*/ `\n ALTER TABLE \"_zero.changeLog2\" \n ADD COLUMN \"backfillingColumnVersions\" TEXT DEFAULT '{}';\n ALTER TABLE \"_zero.column_metadata\"\n ADD COLUMN backfill TEXT;\n ` + CREATE_V9_TABLE_METADATA_TABLE,\n );\n },\n },\n\n 10: {\n migrateSchema: (_, db) => {\n db.exec(/*sql*/ `\n ALTER TABLE \"_zero.replicationConfig\" \n ADD COLUMN \"initialSyncContext\" TEXT DEFAULT '{}';\n `);\n },\n },\n\n 11: {\n migrateSchema: (_, db) => {\n db.exec(/*sql*/ `\n ALTER TABLE \"_zero.tableMetadata\"\n ADD COLUMN \"minRowVersion\" TEXT NOT NULL DEFAULT '00';\n\n -- Removing the NOT NULL constraint from \"metadata\" requires copying\n -- the column. We piggyback the rename to \"upstreamMetadata\" here.\n ALTER TABLE \"_zero.tableMetadata\"\n ADD COLUMN \"upstreamMetadata\" TEXT;\n UPDATE \"_zero.tableMetadata\" SET \"upstreamMetadata\" = \"metadata\";\n ALTER TABLE \"_zero.tableMetadata\" DROP \"metadata\";\n `);\n },\n },\n\n 12: {\n migrateSchema: (_, db) => {\n // Bring back the \"metadata\" column removed in v11, but as a NULL-able column.\n // It is needed for backwards compatibility.\n db.exec(/*sql*/ `\n ALTER TABLE \"_zero.tableMetadata\"\n ADD COLUMN \"metadata\" TEXT;\n `);\n },\n\n migrateData: (_, db) => {\n // For rollback then roll forward, re-copy anything written to metadata.\n db.exec(/*sql*/ `\n UPDATE \"_zero.tableMetadata\" \n SET \"upstreamMetadata\" = COALESCE(\"metadata\", \"upstreamMetadata\"),\n \"metadata\" = NULL;\n `);\n },\n },\n\n 13: {\n migrateSchema: (_, db) => {\n db.exec(/*sql*/ `\n ALTER TABLE \"_zero.replicationState\" ADD COLUMN writeTimeMs INTEGER;\n `);\n },\n\n migrateData: (_, db) => {\n db.exec(/*sql*/ `\n UPDATE \"_zero.replicationState\" \n SET writeTimeMs = COALESCE(writeTimeMs, unixepoch('subsec') * 1000)`);\n },\n },\n};\n\n// Referenced in tests.\nexport const CURRENT_SCHEMA_VERSION = Object.keys(\n schemaVersionMigrationMap,\n).reduce((prev, curr) => Math.max(prev, parseInt(curr)), 0);\n"],"mappings":";;;;;;;AAmBA,eAAsB,YACpB,KACA,WACA,QACA,aACe;CACf,MAAM,iBAA4B;EAChC,gBAAgB,KAAK,OAAO,YAAY,KAAK,EAAE;EAC/C,gBAAgB;CAClB;CAEA,IAAI;EACF,MAAM,oBACJ,KACA,WACA,QACA,gBACA,yBACF;CACF,SAAS,GAAG;EACV,4BAA4B,KAAK,WAAW,QAAQ,CAAC;CACvD;AACF;AAEA,eAAsB,eACpB,KACA,WACA,QACA;CACA,IAAI;EACF,MAAM,oBACJ,KACA,WACA,QAEA,EACE,qBAAqB;GACnB,MAAM,IAAI,MACR,wDACF;EACF,EACF,GACA,yBACF;CACF,SAAS,GAAG;EACV,4BAA4B,KAAK,WAAW,QAAQ,CAAC;CACvD;AACF;AAEA,SAAS,4BACP,KACA,WACA,QACA,GACO;CACP,IAAI,mBAAmB,CAAC,GAAG;EACzB,+BAA+B,KAAK,WAAW,QAAQ,CAAC;EACxD,MAAM,IAAI,gBACR,qCAAqC,OAAO,CAAC,KAC7C,EAAC,OAAO,EAAC,CACX;CACF;CACA,MAAM;AACR;AAEA,IAAa,kCAA0C;;;;;;;;;;;;AAavD,IAAa,uBAA+B;;;;;;;;;;;AAY5C,IAAa,iCAAyC;;;;;;;;AAStD,IAAa,4BAAqD;CAEhE,GAAG;EACD,qBAAqB;GACnB,MAAM,IAAI,gBAAgB,iCAAiC;EAC7D;EACA,gBAAgB;CAClB;CAEA,GAAG;EACD,gBAAgB,GAAG,OAAO;GACxB,GAAG,KAAK,2BAA2B;EACrC;EACA,cAAc,GAAG,OAAO;GACtB,YAAY,IAAI,SAAS;EAC3B;CACF;CAGA,GAAG,CAAC;CAEJ,GAAG,EACD,gBAAgB,GAAG,OAAO;EAIxB,GAAG,KAAK,+BAA+B;EAEvC,GAAG,KAAK,oBAAoB;CAC9B,EACF;CAEA,GAAG;EACD,gBAAgB,GAAG,OAAO;GAOxB,IAAI,CANgB,GACjB,QACC,qFACF,EACC,IAEE,GACH,GAAG,KAAK,+BAA+B;EAE3C;EACA,cAAc,GAAG,OAAO;GAItB,GAAG,KAAa,qCAAqC;GAGrD,2BAA2B,IADZ,WAAW,IAAI,OAAO,KACN,CAAM;EACvC;CACF;CAEA,GAAG,EACD,gBAAgB,GAAG,OAAO;EACxB,GAAG,KACO;;;;;UAKN,8BACJ;CACF,EACF;CAEA,IAAI,EACF,gBAAgB,GAAG,OAAO;EACxB,GAAG,KAAa;;;OAGf;CACH,EACF;CAEA,IAAI,EACF,gBAAgB,GAAG,OAAO;EACxB,GAAG,KAAa;;;;;;;;;;OAUf;CACH,EACF;CAEA,IAAI;EACF,gBAAgB,GAAG,OAAO;GAGxB,GAAG,KAAa;;;OAGf;EACH;EAEA,cAAc,GAAG,OAAO;GAEtB,GAAG,KAAa;;;;OAIf;EACH;CACF;CAEA,IAAI;EACF,gBAAgB,GAAG,OAAO;GACxB,GAAG,KAAa;;OAEf;EACH;EAEA,cAAc,GAAG,OAAO;GACtB,GAAG,KAAa;;8EAEwD;EAC1E;CACF;AACF;AAGsC,OAAO,KAC3C,yBACF,EAAE,QAAQ,MAAM,SAAS,KAAK,IAAI,MAAM,SAAS,IAAI,CAAC,GAAG,CAAC"}
1
+ {"version":3,"file":"replica-schema.js","names":[],"sources":["../../../../../../../zero-cache/src/services/change-source/common/replica-schema.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {assert} from '../../../../../shared/src/asserts.ts';\nimport type {Database} from '../../../../../zqlite/src/db.ts';\nimport {listTables} from '../../../db/lite-tables.ts';\nimport {\n runSchemaMigrations,\n type IncrementalMigrationMap,\n type Migration,\n} from '../../../db/migration-lite.ts';\nimport {\n isSQLiteCorruption,\n logSQLiteCorruptionDiagnostics,\n} from '../../../db/sqlite-corruption.ts';\nimport {AutoResetSignal} from '../../change-streamer/schema/tables.ts';\nimport {\n CREATE_BACKFILLING_TABLE,\n populateBackfillingFromColumnMetadata,\n} from '../../replicator/schema/backfilling.ts';\nimport {populateFromExistingTables} from '../../replicator/schema/column-metadata.ts';\nimport {\n CREATE_RUNTIME_EVENTS_TABLE,\n recordEvent,\n} from '../../replicator/schema/replication-state.ts';\n\nexport async function initReplica(\n log: LogContext,\n debugName: string,\n dbPath: string,\n initialSync: (lc: LogContext, tx: Database) => Promise<void>,\n): Promise<void> {\n const setupMigration: Migration = {\n migrateSchema: (log, tx) => initialSync(log, tx),\n minSafeVersion: 1,\n };\n\n try {\n await runSchemaMigrations(\n log,\n debugName,\n dbPath,\n setupMigration,\n schemaVersionMigrationMap,\n );\n } catch (e) {\n throwAutoResetForCorruption(log, debugName, dbPath, e);\n }\n}\n\nexport async function upgradeReplica(\n log: LogContext,\n debugName: string,\n dbPath: string,\n) {\n try {\n await runSchemaMigrations(\n log,\n debugName,\n dbPath,\n // setupMigration should never be invoked\n {\n migrateSchema: () => {\n throw new Error(\n 'This should only be called for already synced replicas',\n );\n },\n },\n schemaVersionMigrationMap,\n );\n } catch (e) {\n throwAutoResetForCorruption(log, debugName, dbPath, e);\n }\n}\n\nfunction throwAutoResetForCorruption(\n log: LogContext,\n debugName: string,\n dbPath: string,\n e: unknown,\n): never {\n if (isSQLiteCorruption(e)) {\n logSQLiteCorruptionDiagnostics(log, debugName, dbPath, e);\n throw new AutoResetSignal(\n `replica database appears corrupt: ${String(e)}`,\n {cause: e},\n );\n }\n throw e;\n}\n\nexport const CREATE_V6_COLUMN_METADATA_TABLE = /*sql*/ `\n CREATE TABLE \"_zero.column_metadata\" (\n table_name TEXT NOT NULL,\n column_name TEXT NOT NULL,\n upstream_type TEXT NOT NULL,\n is_not_null INTEGER NOT NULL,\n is_enum INTEGER NOT NULL,\n is_array INTEGER NOT NULL,\n character_max_length INTEGER,\n PRIMARY KEY (table_name, column_name)\n );\n`;\n\nexport const CREATE_V7_CHANGE_LOG = /*sql*/ `\n CREATE TABLE \"_zero.changeLog2\" (\n \"stateVersion\" TEXT NOT NULL,\n \"pos\" INT NOT NULL,\n \"table\" TEXT NOT NULL,\n \"rowKey\" TEXT NOT NULL,\n \"op\" TEXT NOT NULL,\n PRIMARY KEY(\"stateVersion\", \"pos\"),\n UNIQUE(\"table\", \"rowKey\")\n );\n`;\n\nexport const CREATE_V9_TABLE_METADATA_TABLE = /*sql*/ `\n CREATE TABLE \"_zero.tableMetadata\" (\n \"schema\" TEXT NOT NULL,\n \"table\" TEXT NOT NULL,\n \"metadata\" TEXT NOT NULL,\n PRIMARY KEY (\"schema\", \"table\")\n );\n`;\n\n// Deliberately shadows the same names in `replicator/change-log-db.ts`: these\n// are the v14 replica's, that module's are the change-log database's, and the\n// two are frozen apart.\nexport const V14_CHANGE_LOG_STREAM_TABLE = '_zero.changeLogStream';\nconst V14_CHANGE_LOG_STREAM_WRITE_TIME_INDEX =\n '_zero.changeLogStream_writeTimeMs';\n\n// The change-log stream table, as migration 14 created it and migration 16\n// drops it. Frozen at its v14 shape: a migration is history, so this must not\n// be kept in sync with the live definition in `replicator/change-log-db.ts`,\n// which now describes a table in a different database.\nexport const CREATE_V14_CHANGE_LOG_STREAM = /*sql*/ `\n CREATE TABLE \"${V14_CHANGE_LOG_STREAM_TABLE}\" (\n \"watermark\" TEXT NOT NULL,\n \"pos\" INTEGER NOT NULL,\n \"change\" TEXT NOT NULL,\n \"precommit\" TEXT,\n \"writeTimeMs\" INTEGER,\n PRIMARY KEY (\"watermark\", \"pos\")\n );\n\n CREATE INDEX \"${V14_CHANGE_LOG_STREAM_WRITE_TIME_INDEX}\"\n ON \"${V14_CHANGE_LOG_STREAM_TABLE}\" (\"writeTimeMs\", \"watermark\")\n WHERE \"writeTimeMs\" IS NOT NULL;\n`;\n\n// Idempotent because migrateData may run again after a rollback followed by a\n// roll-forward, and both rows go in with one statement so a partial seed is\n// not reachable.\nconst SEED_V14_CHANGE_LOG_STREAM = /*sql*/ `\n INSERT INTO \"${V14_CHANGE_LOG_STREAM_TABLE}\"\n (\"watermark\", \"pos\", \"change\", \"precommit\", \"writeTimeMs\")\n VALUES\n (@stateVersion, 0, '{\"tag\":\"begin\"}', NULL, NULL),\n (@stateVersion, 1, '{\"tag\":\"commit\"}', @stateVersion, @writeTimeMs)\n ON CONFLICT (\"watermark\", \"pos\") DO NOTHING\n`;\n\nfunction seedV14ChangeLogStream(db: Database): void {\n const state = db\n .prepare(/*sql*/ `\n SELECT \"stateVersion\", \"writeTimeMs\" FROM \"_zero.replicationState\"\n `)\n .get<{stateVersion: string; writeTimeMs: number | null} | undefined>();\n assert(state !== undefined, 'replication state must be initialized');\n assert(\n state.writeTimeMs !== null,\n 'replication state writeTimeMs must be initialized',\n );\n db.prepare(SEED_V14_CHANGE_LOG_STREAM).run(state);\n}\n\nexport const schemaVersionMigrationMap: IncrementalMigrationMap = {\n // There's no incremental migration from v1. Just reset the replica.\n 4: {\n migrateSchema: () => {\n throw new AutoResetSignal('upgrading replica to new schema');\n },\n minSafeVersion: 3,\n },\n\n 5: {\n migrateSchema: (_, db) => {\n db.exec(CREATE_RUNTIME_EVENTS_TABLE);\n },\n migrateData: (_, db) => {\n recordEvent(db, 'upgrade');\n },\n },\n\n // Revised in the migration to v8 because the v6 code was incomplete.\n 6: {},\n\n 7: {\n migrateSchema: (_, db) => {\n // Note: The original \"changeLog\" table is kept so that the replica file\n // is compatible with older zero-caches. However, it is truncated for\n // space savings (since historic changes were never read).\n db.exec(`DELETE FROM \"_zero.changeLog\"`);\n // First version of changeLog2\n db.exec(CREATE_V7_CHANGE_LOG);\n },\n },\n\n 8: {\n migrateSchema: (_, db) => {\n const tableExists = db\n .prepare(\n `SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = '_zero.column_metadata'`,\n )\n .get();\n\n if (!tableExists) {\n db.exec(CREATE_V6_COLUMN_METADATA_TABLE);\n }\n },\n migrateData: (_, db) => {\n // Re-populate the ColumnMetadataStore; the original migration\n // at v6 was incomplete, as covered replicas migrated from earlier\n // versions but did not initialize the table for new replicas.\n db.exec(/*sql*/ `DELETE FROM \"_zero.column_metadata\"`);\n\n const tables = listTables(db, false, false);\n populateFromExistingTables(db, tables);\n },\n },\n\n 9: {\n migrateSchema: (_, db) => {\n db.exec(\n /*sql*/ `\n ALTER TABLE \"_zero.changeLog2\" \n ADD COLUMN \"backfillingColumnVersions\" TEXT DEFAULT '{}';\n ALTER TABLE \"_zero.column_metadata\"\n ADD COLUMN backfill TEXT;\n ` + CREATE_V9_TABLE_METADATA_TABLE,\n );\n },\n },\n\n 10: {\n migrateSchema: (_, db) => {\n db.exec(/*sql*/ `\n ALTER TABLE \"_zero.replicationConfig\" \n ADD COLUMN \"initialSyncContext\" TEXT DEFAULT '{}';\n `);\n },\n },\n\n 11: {\n migrateSchema: (_, db) => {\n db.exec(/*sql*/ `\n ALTER TABLE \"_zero.tableMetadata\"\n ADD COLUMN \"minRowVersion\" TEXT NOT NULL DEFAULT '00';\n\n -- Removing the NOT NULL constraint from \"metadata\" requires copying\n -- the column. We piggyback the rename to \"upstreamMetadata\" here.\n ALTER TABLE \"_zero.tableMetadata\"\n ADD COLUMN \"upstreamMetadata\" TEXT;\n UPDATE \"_zero.tableMetadata\" SET \"upstreamMetadata\" = \"metadata\";\n ALTER TABLE \"_zero.tableMetadata\" DROP \"metadata\";\n `);\n },\n },\n\n 12: {\n migrateSchema: (_, db) => {\n // Bring back the \"metadata\" column removed in v11, but as a NULL-able column.\n // It is needed for backwards compatibility.\n db.exec(/*sql*/ `\n ALTER TABLE \"_zero.tableMetadata\"\n ADD COLUMN \"metadata\" TEXT;\n `);\n },\n\n migrateData: (_, db) => {\n // For rollback then roll forward, re-copy anything written to metadata.\n db.exec(/*sql*/ `\n UPDATE \"_zero.tableMetadata\" \n SET \"upstreamMetadata\" = COALESCE(\"metadata\", \"upstreamMetadata\"),\n \"metadata\" = NULL;\n `);\n },\n },\n\n 13: {\n migrateSchema: (_, db) => {\n db.exec(/*sql*/ `\n ALTER TABLE \"_zero.replicationState\" ADD COLUMN writeTimeMs INTEGER;\n `);\n },\n\n migrateData: (_, db) => {\n db.exec(/*sql*/ `\n UPDATE \"_zero.replicationState\" \n SET writeTimeMs = COALESCE(writeTimeMs, unixepoch('subsec') * 1000)`);\n },\n },\n\n // Deliberately left as it shipped, even though v16 immediately undoes it.\n // Rewriting it to a no-op would strand replicas already at v14: they roll\n // back to v14 code, which expects the table this created.\n 14: {\n migrateSchema: (_, db) => {\n db.exec(CREATE_V14_CHANGE_LOG_STREAM);\n },\n\n migrateData: (_, db) => {\n seedV14ChangeLogStream(db);\n },\n },\n\n 15: {\n migrateSchema: (_, db) => {\n // Make writeTimeMs NOT NULL. In SQLite the only way to do this is to\n // create a new table, copy the data over, delete the old table, and\n // rename. This is cheap because it's a single row table.\n db.exec(/*sql*/ `\n CREATE TABLE \"_zero.replicationState2\" (\n stateVersion TEXT NOT NULL,\n writeTimeMs INTEGER NOT NULL,\n lock INTEGER PRIMARY KEY DEFAULT 1 CHECK (lock=1)\n );\n\n INSERT INTO \"_zero.replicationState2\" (stateVersion, writeTimeMs, lock)\n SELECT stateVersion, writeTimeMs, lock FROM \"_zero.replicationState\";\n\n DROP TABLE \"_zero.replicationState\";\n\n ALTER TABLE \"_zero.replicationState2\" RENAME TO \"_zero.replicationState\";\n `);\n },\n },\n\n // The change log moved out of the replica and into its own database\n // (`${replicaFile}-change-log`), so the replica's copy is dead weight in\n // every file the backup ships and every follower downloads. Nothing reads it\n // as of this version.\n //\n // `IF EXISTS` because a fresh replica never runs the incremental migrations\n // at all — its setup migration creates the current schema directly, which no\n // longer includes this table — and because a rollback to v14 followed by a\n // roll-forward re-runs `migrateData` while skipping `migrateSchema`.\n //\n // The freed pages are reclaimed by the existing `vacuumIntervalHours`\n // trigger in `workers/replicator.ts`; no special handling here.\n //\n // No `minSafeVersion`: an older zero-cache still runs against a v16 replica,\n // and with `sqliteChangeLogMode=off` (the default) it never looks for this\n // table. Bumping the rollback limit would turn every rollback into a hard\n // startup failure to protect a configuration that is not enabled anywhere.\n 16: {\n migrateSchema: (_, db) => {\n db.exec(/*sql*/ `\n DROP INDEX IF EXISTS \"${V14_CHANGE_LOG_STREAM_WRITE_TIME_INDEX}\";\n DROP TABLE IF EXISTS \"${V14_CHANGE_LOG_STREAM_TABLE}\";\n `);\n },\n },\n\n // `_zero.column_metadata.backfill` records which columns are backfilling but\n // is keyed by lite table name, which has no inverse: it cannot be turned back\n // into the `BackfillRequest`s that a change log initialized from this replica\n // would have to send. This table carries the upstream identity alongside the\n // same state. See `replicator/schema/backfilling.ts`.\n //\n // No `minSafeVersion`: an older zero-cache runs fine against a v17 replica,\n // since nothing at v16 reads the new table. Its writes to\n // `column_metadata.backfill` are what `migrateData` rebuilds from when rolling\n // forward again, so a rollback costs nothing but the re-seed.\n 17: {\n migrateSchema: (_, db) => {\n db.exec(CREATE_BACKFILLING_TABLE);\n },\n\n migrateData: (lc, db) => {\n populateBackfillingFromColumnMetadata(lc, db);\n },\n },\n};\n\n// Referenced in tests.\nexport const CURRENT_SCHEMA_VERSION = Object.keys(\n schemaVersionMigrationMap,\n).reduce((prev, curr) => Math.max(prev, parseInt(curr)), 0);\n"],"mappings":"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"}
@@ -2,18 +2,14 @@ import type { LogContext } from '@rocicorp/logger';
2
2
  import { type JSONObject } from '../../../../../shared/src/bigint-json.ts';
3
3
  import { Database } from '../../../../../zqlite/src/db.ts';
4
4
  import type { ShardConfig } from '../../../types/shards.ts';
5
- import { type SubscriptionState } from '../../replicator/schema/replication-state.ts';
6
- import type { ChangeSource } from '../change-source.ts';
5
+ import { type InitializeResult, type RestoreOptions } from '../common/replica-restore.ts';
7
6
  /** Server context to store with the initial sync metadata for debugging. */
8
7
  export type ServerContext = JSONObject;
9
8
  /**
10
9
  * Initializes a Custom change source before streaming changes from the
11
10
  * corresponding logical replication stream.
12
11
  */
13
- export declare function initializeCustomChangeSource(lc: LogContext, upstreamURI: string, shard: ShardConfig, replicaDbFile: string, context: ServerContext): Promise<{
14
- subscriptionState: SubscriptionState;
15
- changeSource: ChangeSource;
16
- }>;
12
+ export declare function initializeCustomChangeSource(lc: LogContext, upstreamURI: string, shard: ShardConfig, replicaDbFile: string, context: ServerContext, { litestream, constraints }?: RestoreOptions): Promise<InitializeResult>;
17
13
  /**
18
14
  * Initial sync for a custom change source makes a request to the
19
15
  * change source endpoint with no `replicaVersion` or `lastWatermark`.
@@ -1 +1 @@
1
- {"version":3,"file":"change-source.d.ts","sourceRoot":"","sources":["../../../../../../../zero-cache/src/services/change-source/custom/change-source.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAGjD,OAAO,EAEL,KAAK,UAAU,EAChB,MAAM,0CAA0C,CAAC;AAGlD,OAAO,EAAC,QAAQ,EAAC,MAAM,iCAAiC,CAAC;AAGzD,OAAO,KAAK,EAAC,WAAW,EAAU,MAAM,0BAA0B,CAAC;AAQnE,OAAO,EAIL,KAAK,iBAAiB,EACvB,MAAM,8CAA8C,CAAC;AACtD,OAAO,KAAK,EAAC,YAAY,EAAe,MAAM,qBAAqB,CAAC;AAQpE,4EAA4E;AAC5E,MAAM,MAAM,aAAa,GAAG,UAAU,CAAC;AAEvC;;;GAGG;AACH,wBAAsB,4BAA4B,CAChD,EAAE,EAAE,UAAU,EACd,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,WAAW,EAClB,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC;IAAC,iBAAiB,EAAE,iBAAiB,CAAC;IAAC,YAAY,EAAE,YAAY,CAAA;CAAC,CAAC,CA+B7E;AA2ED;;;;;;;;;;GAUG;AACH,wBAAsB,WAAW,CAC/B,EAAE,EAAE,UAAU,EACd,KAAK,EAAE,WAAW,EAClB,EAAE,EAAE,QAAQ,EACZ,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,aAAa,iBAqFvB"}
1
+ {"version":3,"file":"change-source.d.ts","sourceRoot":"","sources":["../../../../../../../zero-cache/src/services/change-source/custom/change-source.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAGjD,OAAO,EAEL,KAAK,UAAU,EAChB,MAAM,0CAA0C,CAAC;AAGlD,OAAO,EAAC,QAAQ,EAAC,MAAM,iCAAiC,CAAC;AAGzD,OAAO,KAAK,EAAC,WAAW,EAAU,MAAM,0BAA0B,CAAC;AAcnE,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACpB,MAAM,8BAA8B,CAAC;AAQtC,4EAA4E;AAC5E,MAAM,MAAM,aAAa,GAAG,UAAU,CAAC;AAEvC;;;GAGG;AACH,wBAAsB,4BAA4B,CAChD,EAAE,EAAE,UAAU,EACd,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,WAAW,EAClB,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE,aAAa,EACtB,EAAC,UAAU,EAAE,WAAW,EAAC,GAAE,cAAmB,GAC7C,OAAO,CAAC,gBAAgB,CAAC,CAwD3B;AA2ED;;;;;;;;;;GAUG;AACH,wBAAsB,WAAW,CAC/B,EAAE,EAAE,UAAU,EACd,KAAK,EAAE,WAAW,EAClB,EAAE,EAAE,QAAQ,EACZ,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,aAAa,iBAqFvB"}
@@ -7,19 +7,25 @@ import { Database } from "../../../../../zqlite/src/db.js";
7
7
  import { computeZqlSpecs } from "../../../db/lite-tables.js";
8
8
  import { createReplicationStateTables, getSubscriptionState, initReplicationState } from "../../replicator/schema/replication-state.js";
9
9
  import { StatementRunner } from "../../../db/statements.js";
10
- import { AutoResetSignal } from "../../change-streamer/schema/tables.js";
11
- import { initReplica } from "../common/replica-schema.js";
12
10
  import { stream } from "../../../types/streams.js";
11
+ import { AutoResetSignal } from "../../change-streamer/schema/tables.js";
13
12
  import { ChangeProcessor } from "../../replicator/change-processor.js";
14
13
  import { ReplicationStatusPublisher } from "../../replicator/replication-status.js";
15
- import { WebSocket as WebSocket$1 } from "ws";
14
+ import { restoreReplica } from "../common/replica-restore.js";
15
+ import { initReplica } from "../common/replica-schema.js";
16
+ import { WebSocket } from "ws";
16
17
  //#region ../zero-cache/src/services/change-source/custom/change-source.ts
17
18
  /**
18
19
  * Initializes a Custom change source before streaming changes from the
19
20
  * corresponding logical replication stream.
20
21
  */
21
- async function initializeCustomChangeSource(lc, upstreamURI, shard, replicaDbFile, context) {
22
- await initReplica(lc, `replica-${shard.appID}-${shard.shardNum}`, replicaDbFile, (log, tx) => initialSync(log, shard, tx, upstreamURI, context));
22
+ async function initializeCustomChangeSource(lc, upstreamURI, shard, replicaDbFile, context, { litestream, constraints } = {}) {
23
+ if (litestream?.backupURL) await restoreReplica(lc, litestream, replicaDbFile, constraints);
24
+ let initialSynced = false;
25
+ await initReplica(lc, `replica-${shard.appID}-${shard.shardNum}`, replicaDbFile, (log, tx) => {
26
+ initialSynced = true;
27
+ return initialSync(log, shard, tx, upstreamURI, context);
28
+ });
23
29
  const replica = new Database(lc, replicaDbFile);
24
30
  const subscriptionState = getSubscriptionState(new StatementRunner(replica));
25
31
  replica.close();
@@ -30,7 +36,10 @@ async function initializeCustomChangeSource(lc, upstreamURI, shard, replicaDbFil
30
36
  }
31
37
  return {
32
38
  subscriptionState,
33
- changeSource: new CustomChangeSource(lc, upstreamURI, shard, subscriptionState)
39
+ changeSource: new CustomChangeSource(lc, upstreamURI, shard, subscriptionState),
40
+ destinationBackupURL: litestream?.backupURL,
41
+ replicaID: null,
42
+ waitForBackupBeforeServing: initialSynced
34
43
  };
35
44
  }
36
45
  var CustomChangeSource = class {
@@ -69,7 +78,7 @@ var CustomChangeSource = class {
69
78
  url.searchParams.set("lastWatermark", clientWatermark);
70
79
  url.searchParams.set("replicaVersion", replicaVersion);
71
80
  }
72
- const ws = new WebSocket$1(url);
81
+ const ws = new WebSocket(url);
73
82
  const { instream, outstream } = stream(this.#lc, ws, changeStreamMessageSchema, { coalesce: (curr) => curr });
74
83
  return {
75
84
  changes: instream,