@rocicorp/zero 1.10.0-canary.0 → 1.10.0-canary.10

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 (484) hide show
  1. package/out/replicache/src/db/commit.js +1 -4
  2. package/out/replicache/src/db/commit.js.map +1 -1
  3. package/out/replicache/src/db/read.d.ts +1 -0
  4. package/out/replicache/src/db/read.d.ts.map +1 -1
  5. package/out/replicache/src/db/read.js +1 -4
  6. package/out/replicache/src/db/read.js.map +1 -1
  7. package/out/replicache/src/db/write.d.ts +2 -1
  8. package/out/replicache/src/db/write.d.ts.map +1 -1
  9. package/out/replicache/src/db/write.js +4 -51
  10. package/out/replicache/src/db/write.js.map +1 -1
  11. package/out/replicache/src/persist/clients.d.ts +1 -0
  12. package/out/replicache/src/persist/clients.d.ts.map +1 -1
  13. package/out/replicache/src/persist/clients.js +4 -31
  14. package/out/replicache/src/persist/clients.js.map +1 -1
  15. package/out/replicache/src/process-env.d.ts +28 -0
  16. package/out/replicache/src/process-env.d.ts.map +1 -0
  17. package/out/replicache/src/replicache-impl.d.ts.map +1 -1
  18. package/out/replicache/src/replicache-impl.js.map +1 -1
  19. package/out/replicache/src/scan-iterator.js +2 -14
  20. package/out/replicache/src/scan-iterator.js.map +1 -1
  21. package/out/replicache/src/subscriptions.d.ts +1 -0
  22. package/out/replicache/src/subscriptions.d.ts.map +1 -1
  23. package/out/replicache/src/subscriptions.js +2 -10
  24. package/out/replicache/src/subscriptions.js.map +1 -1
  25. package/out/replicache/src/transactions.d.ts +1 -0
  26. package/out/replicache/src/transactions.d.ts.map +1 -1
  27. package/out/replicache/src/transactions.js +2 -4
  28. package/out/replicache/src/transactions.js.map +1 -1
  29. package/out/shared/src/promise-race.d.ts +14 -0
  30. package/out/shared/src/promise-race.d.ts.map +1 -1
  31. package/out/shared/src/promise-race.js +32 -1
  32. package/out/shared/src/promise-race.js.map +1 -1
  33. package/out/z2s/src/compiler.d.ts.map +1 -1
  34. package/out/z2s/src/compiler.js +1 -22
  35. package/out/z2s/src/compiler.js.map +1 -1
  36. package/out/zero/package.js +3 -3
  37. package/out/zero/package.js.map +1 -1
  38. package/out/zero-cache/src/auth/write-authorizer.d.ts.map +1 -1
  39. package/out/zero-cache/src/auth/write-authorizer.js +8 -1
  40. package/out/zero-cache/src/auth/write-authorizer.js.map +1 -1
  41. package/out/zero-cache/src/config/normalize.d.ts +6 -0
  42. package/out/zero-cache/src/config/normalize.d.ts.map +1 -1
  43. package/out/zero-cache/src/config/normalize.js +24 -2
  44. package/out/zero-cache/src/config/normalize.js.map +1 -1
  45. package/out/zero-cache/src/config/zero-config.d.ts +65 -4
  46. package/out/zero-cache/src/config/zero-config.d.ts.map +1 -1
  47. package/out/zero-cache/src/config/zero-config.js +202 -35
  48. package/out/zero-cache/src/config/zero-config.js.map +1 -1
  49. package/out/zero-cache/src/custom/fetch.js +1 -1
  50. package/out/zero-cache/src/custom/fetch.js.map +1 -1
  51. package/out/zero-cache/src/db/delete-lite-db.js +2 -1
  52. package/out/zero-cache/src/db/delete-lite-db.js.map +1 -1
  53. package/out/zero-cache/src/db/migration-lite.d.ts.map +1 -1
  54. package/out/zero-cache/src/db/migration-lite.js +10 -5
  55. package/out/zero-cache/src/db/migration-lite.js.map +1 -1
  56. package/out/zero-cache/src/db/migration.d.ts.map +1 -1
  57. package/out/zero-cache/src/db/migration.js +4 -2
  58. package/out/zero-cache/src/db/migration.js.map +1 -1
  59. package/out/zero-cache/src/db/sqlite-corruption.d.ts +3 -2
  60. package/out/zero-cache/src/db/sqlite-corruption.d.ts.map +1 -1
  61. package/out/zero-cache/src/db/sqlite-corruption.js +13 -8
  62. package/out/zero-cache/src/db/sqlite-corruption.js.map +1 -1
  63. package/out/zero-cache/src/db/transaction-pool.d.ts +5 -15
  64. package/out/zero-cache/src/db/transaction-pool.d.ts.map +1 -1
  65. package/out/zero-cache/src/db/transaction-pool.js +8 -72
  66. package/out/zero-cache/src/db/transaction-pool.js.map +1 -1
  67. package/out/zero-cache/src/observability/metrics.d.ts +6 -1
  68. package/out/zero-cache/src/observability/metrics.d.ts.map +1 -1
  69. package/out/zero-cache/src/observability/metrics.js +20 -2
  70. package/out/zero-cache/src/observability/metrics.js.map +1 -1
  71. package/out/zero-cache/src/server/change-streamer.d.ts.map +1 -1
  72. package/out/zero-cache/src/server/change-streamer.js +105 -34
  73. package/out/zero-cache/src/server/change-streamer.js.map +1 -1
  74. package/out/zero-cache/src/server/main.d.ts.map +1 -1
  75. package/out/zero-cache/src/server/main.js +8 -18
  76. package/out/zero-cache/src/server/main.js.map +1 -1
  77. package/out/zero-cache/src/server/replicator.d.ts.map +1 -1
  78. package/out/zero-cache/src/server/replicator.js +48 -5
  79. package/out/zero-cache/src/server/replicator.js.map +1 -1
  80. package/out/zero-cache/src/server/runner/run-worker.js +3 -2
  81. package/out/zero-cache/src/server/runner/run-worker.js.map +1 -1
  82. package/out/zero-cache/src/server/syncer.d.ts.map +1 -1
  83. package/out/zero-cache/src/server/syncer.js +1 -1
  84. package/out/zero-cache/src/server/syncer.js.map +1 -1
  85. package/out/zero-cache/src/server/worker-urls.d.ts +0 -1
  86. package/out/zero-cache/src/server/worker-urls.d.ts.map +1 -1
  87. package/out/zero-cache/src/server/worker-urls.js +1 -2
  88. package/out/zero-cache/src/server/worker-urls.js.map +1 -1
  89. package/out/zero-cache/src/services/change-source/change-source.d.ts +4 -2
  90. package/out/zero-cache/src/services/change-source/change-source.d.ts.map +1 -1
  91. package/out/zero-cache/src/services/change-source/common/replica-restore.d.ts +35 -0
  92. package/out/zero-cache/src/services/change-source/common/replica-restore.d.ts.map +1 -0
  93. package/out/zero-cache/src/services/change-source/common/replica-restore.js +34 -0
  94. package/out/zero-cache/src/services/change-source/common/replica-restore.js.map +1 -0
  95. package/out/zero-cache/src/services/change-source/common/replica-schema.d.ts +2 -0
  96. package/out/zero-cache/src/services/change-source/common/replica-schema.d.ts.map +1 -1
  97. package/out/zero-cache/src/services/change-source/common/replica-schema.js +81 -3
  98. package/out/zero-cache/src/services/change-source/common/replica-schema.js.map +1 -1
  99. package/out/zero-cache/src/services/change-source/custom/change-source.d.ts +2 -6
  100. package/out/zero-cache/src/services/change-source/custom/change-source.d.ts.map +1 -1
  101. package/out/zero-cache/src/services/change-source/custom/change-source.js +14 -5
  102. package/out/zero-cache/src/services/change-source/custom/change-source.js.map +1 -1
  103. package/out/zero-cache/src/services/change-source/pg/backfill-stream.d.ts.map +1 -1
  104. package/out/zero-cache/src/services/change-source/pg/backfill-stream.js +22 -11
  105. package/out/zero-cache/src/services/change-source/pg/backfill-stream.js.map +1 -1
  106. package/out/zero-cache/src/services/change-source/pg/change-source.d.ts +7 -7
  107. package/out/zero-cache/src/services/change-source/pg/change-source.d.ts.map +1 -1
  108. package/out/zero-cache/src/services/change-source/pg/change-source.js +90 -31
  109. package/out/zero-cache/src/services/change-source/pg/change-source.js.map +1 -1
  110. package/out/zero-cache/src/services/change-source/pg/decommission.d.ts.map +1 -1
  111. package/out/zero-cache/src/services/change-source/pg/decommission.js +20 -11
  112. package/out/zero-cache/src/services/change-source/pg/decommission.js.map +1 -1
  113. package/out/zero-cache/src/services/change-source/pg/initial-sync.d.ts +9 -1
  114. package/out/zero-cache/src/services/change-source/pg/initial-sync.d.ts.map +1 -1
  115. package/out/zero-cache/src/services/change-source/pg/initial-sync.js +61 -76
  116. package/out/zero-cache/src/services/change-source/pg/initial-sync.js.map +1 -1
  117. package/out/zero-cache/src/services/change-source/pg/logical-replication/stream.d.ts +65 -2
  118. package/out/zero-cache/src/services/change-source/pg/logical-replication/stream.d.ts.map +1 -1
  119. package/out/zero-cache/src/services/change-source/pg/logical-replication/stream.js +101 -10
  120. package/out/zero-cache/src/services/change-source/pg/logical-replication/stream.js.map +1 -1
  121. package/out/zero-cache/src/services/change-source/pg/replication-slots.d.ts +27 -2
  122. package/out/zero-cache/src/services/change-source/pg/replication-slots.d.ts.map +1 -1
  123. package/out/zero-cache/src/services/change-source/pg/replication-slots.js +41 -8
  124. package/out/zero-cache/src/services/change-source/pg/replication-slots.js.map +1 -1
  125. package/out/zero-cache/src/services/change-source/pg/schema/init.d.ts +0 -5
  126. package/out/zero-cache/src/services/change-source/pg/schema/init.d.ts.map +1 -1
  127. package/out/zero-cache/src/services/change-source/pg/schema/init.js +29 -41
  128. package/out/zero-cache/src/services/change-source/pg/schema/init.js.map +1 -1
  129. package/out/zero-cache/src/services/change-source/pg/schema/shard.d.ts +35 -16
  130. package/out/zero-cache/src/services/change-source/pg/schema/shard.d.ts.map +1 -1
  131. package/out/zero-cache/src/services/change-source/pg/schema/shard.js +77 -7
  132. package/out/zero-cache/src/services/change-source/pg/schema/shard.js.map +1 -1
  133. package/out/zero-cache/src/services/change-source/protocol/current/data.d.ts +2 -1
  134. package/out/zero-cache/src/services/change-source/protocol/current/data.d.ts.map +1 -1
  135. package/out/zero-cache/src/services/change-source/protocol/current/data.js +5 -13
  136. package/out/zero-cache/src/services/change-source/protocol/current/data.js.map +1 -1
  137. package/out/zero-cache/src/services/change-source/protocol/current/downstream.d.ts +6 -3
  138. package/out/zero-cache/src/services/change-source/protocol/current/downstream.d.ts.map +1 -1
  139. package/out/zero-cache/src/services/change-source/protocol/current/schema-change-tags.d.ts +6 -0
  140. package/out/zero-cache/src/services/change-source/protocol/current/schema-change-tags.d.ts.map +1 -0
  141. package/out/zero-cache/src/services/change-source/protocol/current/schema-change-tags.js +21 -0
  142. package/out/zero-cache/src/services/change-source/protocol/current/schema-change-tags.js.map +1 -0
  143. package/out/zero-cache/src/services/change-source/protocol/current/status.d.ts +1 -0
  144. package/out/zero-cache/src/services/change-source/protocol/current/status.d.ts.map +1 -1
  145. package/out/zero-cache/src/services/change-source/protocol/current/upstream.d.ts +1 -0
  146. package/out/zero-cache/src/services/change-source/protocol/current/upstream.d.ts.map +1 -1
  147. package/out/zero-cache/src/services/change-streamer/backup-cleanup-monitor-factory.d.ts +3 -7
  148. package/out/zero-cache/src/services/change-streamer/backup-cleanup-monitor-factory.d.ts.map +1 -1
  149. package/out/zero-cache/src/services/change-streamer/backup-cleanup-monitor-factory.js +26 -10
  150. package/out/zero-cache/src/services/change-streamer/backup-cleanup-monitor-factory.js.map +1 -1
  151. package/out/zero-cache/src/services/change-streamer/backup-monitor.d.ts +15 -5
  152. package/out/zero-cache/src/services/change-streamer/backup-monitor.d.ts.map +1 -1
  153. package/out/zero-cache/src/services/change-streamer/backup-monitor.js +71 -0
  154. package/out/zero-cache/src/services/change-streamer/backup-monitor.js.map +1 -0
  155. package/out/zero-cache/src/services/change-streamer/broadcast.d.ts +68 -78
  156. package/out/zero-cache/src/services/change-streamer/broadcast.d.ts.map +1 -1
  157. package/out/zero-cache/src/services/change-streamer/broadcast.js +84 -92
  158. package/out/zero-cache/src/services/change-streamer/broadcast.js.map +1 -1
  159. package/out/zero-cache/src/services/change-streamer/change-log-codec.d.ts +19 -0
  160. package/out/zero-cache/src/services/change-streamer/change-log-codec.d.ts.map +1 -0
  161. package/out/zero-cache/src/services/change-streamer/change-log-codec.js +50 -0
  162. package/out/zero-cache/src/services/change-streamer/change-log-codec.js.map +1 -0
  163. package/out/zero-cache/src/services/change-streamer/change-log-compare-digest.d.ts +34 -0
  164. package/out/zero-cache/src/services/change-streamer/change-log-compare-digest.d.ts.map +1 -0
  165. package/out/zero-cache/src/services/change-streamer/change-log-compare-digest.js +67 -0
  166. package/out/zero-cache/src/services/change-streamer/change-log-compare-digest.js.map +1 -0
  167. package/out/zero-cache/src/services/change-streamer/change-log-initializer.d.ts +141 -0
  168. package/out/zero-cache/src/services/change-streamer/change-log-initializer.d.ts.map +1 -0
  169. package/out/zero-cache/src/services/change-streamer/change-log-initializer.js +270 -0
  170. package/out/zero-cache/src/services/change-streamer/change-log-initializer.js.map +1 -0
  171. package/out/zero-cache/src/services/change-streamer/change-log-transaction-hash.d.ts +19 -0
  172. package/out/zero-cache/src/services/change-streamer/change-log-transaction-hash.d.ts.map +1 -0
  173. package/out/zero-cache/src/services/change-streamer/change-log-transaction-hash.js +39 -0
  174. package/out/zero-cache/src/services/change-streamer/change-log-transaction-hash.js.map +1 -0
  175. package/out/zero-cache/src/services/change-streamer/change-streamer-http.d.ts +5 -8
  176. package/out/zero-cache/src/services/change-streamer/change-streamer-http.d.ts.map +1 -1
  177. package/out/zero-cache/src/services/change-streamer/change-streamer-http.js +20 -19
  178. package/out/zero-cache/src/services/change-streamer/change-streamer-http.js.map +1 -1
  179. package/out/zero-cache/src/services/change-streamer/change-streamer-service.d.ts +90 -24
  180. package/out/zero-cache/src/services/change-streamer/change-streamer-service.d.ts.map +1 -1
  181. package/out/zero-cache/src/services/change-streamer/change-streamer-service.js +456 -66
  182. package/out/zero-cache/src/services/change-streamer/change-streamer-service.js.map +1 -1
  183. package/out/zero-cache/src/services/change-streamer/change-streamer.d.ts +50 -13
  184. package/out/zero-cache/src/services/change-streamer/change-streamer.d.ts.map +1 -1
  185. package/out/zero-cache/src/services/change-streamer/change-streamer.js.map +1 -1
  186. package/out/zero-cache/src/services/change-streamer/error-type-enum.d.ts +8 -0
  187. package/out/zero-cache/src/services/change-streamer/error-type-enum.d.ts.map +1 -1
  188. package/out/zero-cache/src/services/change-streamer/forwarder.d.ts +14 -3
  189. package/out/zero-cache/src/services/change-streamer/forwarder.d.ts.map +1 -1
  190. package/out/zero-cache/src/services/change-streamer/forwarder.js +42 -12
  191. package/out/zero-cache/src/services/change-streamer/forwarder.js.map +1 -1
  192. package/out/zero-cache/src/services/change-streamer/{litestream3-backup-monitor.d.ts → litestream3-prometheus-poller.d.ts} +19 -45
  193. package/out/zero-cache/src/services/change-streamer/litestream3-prometheus-poller.d.ts.map +1 -0
  194. package/out/zero-cache/src/services/change-streamer/{litestream3-backup-monitor.js → litestream3-prometheus-poller.js} +68 -176
  195. package/out/zero-cache/src/services/change-streamer/litestream3-prometheus-poller.js.map +1 -0
  196. package/out/zero-cache/src/services/change-streamer/replica-poller.d.ts +15 -0
  197. package/out/zero-cache/src/services/change-streamer/replica-poller.d.ts.map +1 -0
  198. package/out/zero-cache/src/services/change-streamer/replica-poller.js +55 -0
  199. package/out/zero-cache/src/services/change-streamer/replica-poller.js.map +1 -0
  200. package/out/zero-cache/src/services/change-streamer/schema/tables.d.ts +5 -1
  201. package/out/zero-cache/src/services/change-streamer/schema/tables.d.ts.map +1 -1
  202. package/out/zero-cache/src/services/change-streamer/schema/tables.js +2 -1
  203. package/out/zero-cache/src/services/change-streamer/schema/tables.js.map +1 -1
  204. package/out/zero-cache/src/services/change-streamer/shard-sampling.d.ts +11 -0
  205. package/out/zero-cache/src/services/change-streamer/shard-sampling.d.ts.map +1 -0
  206. package/out/zero-cache/src/services/change-streamer/shard-sampling.js +19 -0
  207. package/out/zero-cache/src/services/change-streamer/shard-sampling.js.map +1 -0
  208. package/out/zero-cache/src/services/change-streamer/snapshot-reservations.d.ts +24 -0
  209. package/out/zero-cache/src/services/change-streamer/snapshot-reservations.d.ts.map +1 -0
  210. package/out/zero-cache/src/services/change-streamer/snapshot-reservations.js +119 -0
  211. package/out/zero-cache/src/services/change-streamer/snapshot-reservations.js.map +1 -0
  212. package/out/zero-cache/src/services/change-streamer/snapshot.d.ts +4 -1
  213. package/out/zero-cache/src/services/change-streamer/snapshot.d.ts.map +1 -1
  214. package/out/zero-cache/src/services/change-streamer/snapshot.js +39 -14
  215. package/out/zero-cache/src/services/change-streamer/snapshot.js.map +1 -1
  216. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-catchup.d.ts +99 -0
  217. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-catchup.d.ts.map +1 -0
  218. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-catchup.js +344 -0
  219. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-catchup.js.map +1 -0
  220. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-comparator.d.ts +83 -0
  221. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-comparator.d.ts.map +1 -0
  222. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-comparator.js +417 -0
  223. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-comparator.js.map +1 -0
  224. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-purge-scheduler.d.ts +121 -0
  225. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-purge-scheduler.d.ts.map +1 -0
  226. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-purge-scheduler.js +391 -0
  227. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-purge-scheduler.js.map +1 -0
  228. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-read-router.d.ts +73 -0
  229. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-read-router.d.ts.map +1 -0
  230. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-read-router.js +157 -0
  231. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-read-router.js.map +1 -0
  232. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-reader.d.ts +62 -0
  233. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-reader.d.ts.map +1 -0
  234. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-reader.js +164 -0
  235. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-reader.js.map +1 -0
  236. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-writer.d.ts +109 -0
  237. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-writer.d.ts.map +1 -0
  238. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-writer.js +258 -0
  239. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-writer.js.map +1 -0
  240. package/out/zero-cache/src/services/change-streamer/storer.d.ts +85 -12
  241. package/out/zero-cache/src/services/change-streamer/storer.d.ts.map +1 -1
  242. package/out/zero-cache/src/services/change-streamer/storer.js +286 -141
  243. package/out/zero-cache/src/services/change-streamer/storer.js.map +1 -1
  244. package/out/zero-cache/src/services/change-streamer/subscriber.d.ts +61 -10
  245. package/out/zero-cache/src/services/change-streamer/subscriber.d.ts.map +1 -1
  246. package/out/zero-cache/src/services/change-streamer/subscriber.js +101 -8
  247. package/out/zero-cache/src/services/change-streamer/subscriber.js.map +1 -1
  248. package/out/zero-cache/src/services/change-streamer/upstream-acker.d.ts +34 -0
  249. package/out/zero-cache/src/services/change-streamer/upstream-acker.d.ts.map +1 -0
  250. package/out/zero-cache/src/services/change-streamer/upstream-acker.js +86 -0
  251. package/out/zero-cache/src/services/change-streamer/upstream-acker.js.map +1 -0
  252. package/out/zero-cache/src/services/change-streamer/vfs-watermark-poller.d.ts +29 -0
  253. package/out/zero-cache/src/services/change-streamer/vfs-watermark-poller.d.ts.map +1 -0
  254. package/out/zero-cache/src/services/change-streamer/vfs-watermark-poller.js +154 -0
  255. package/out/zero-cache/src/services/change-streamer/vfs-watermark-poller.js.map +1 -0
  256. package/out/zero-cache/src/services/http-service.d.ts +1 -0
  257. package/out/zero-cache/src/services/http-service.d.ts.map +1 -1
  258. package/out/zero-cache/src/services/http-service.js +7 -3
  259. package/out/zero-cache/src/services/http-service.js.map +1 -1
  260. package/out/zero-cache/src/services/life-cycle.d.ts +1 -1
  261. package/out/zero-cache/src/services/life-cycle.d.ts.map +1 -1
  262. package/out/zero-cache/src/services/life-cycle.js +4 -3
  263. package/out/zero-cache/src/services/life-cycle.js.map +1 -1
  264. package/out/zero-cache/src/services/litestream/commands.d.ts +12 -11
  265. package/out/zero-cache/src/services/litestream/commands.d.ts.map +1 -1
  266. package/out/zero-cache/src/services/litestream/commands.js +115 -152
  267. package/out/zero-cache/src/services/litestream/commands.js.map +1 -1
  268. package/out/zero-cache/src/services/litestream/config-v5.yml +42 -0
  269. package/out/zero-cache/src/services/litestream/config.yml +3 -2
  270. package/out/zero-cache/src/services/litestream/metrics.d.ts +5 -4
  271. package/out/zero-cache/src/services/litestream/metrics.d.ts.map +1 -1
  272. package/out/zero-cache/src/services/litestream/metrics.js +10 -10
  273. package/out/zero-cache/src/services/litestream/metrics.js.map +1 -1
  274. package/out/zero-cache/src/services/mutagen/mutagen.d.ts.map +1 -1
  275. package/out/zero-cache/src/services/mutagen/mutagen.js +5 -2
  276. package/out/zero-cache/src/services/mutagen/mutagen.js.map +1 -1
  277. package/out/zero-cache/src/services/replicator/change-log-cookies.d.ts +169 -0
  278. package/out/zero-cache/src/services/replicator/change-log-cookies.d.ts.map +1 -0
  279. package/out/zero-cache/src/services/replicator/change-log-cookies.js +434 -0
  280. package/out/zero-cache/src/services/replicator/change-log-cookies.js.map +1 -0
  281. package/out/zero-cache/src/services/replicator/change-log-db.d.ts +368 -0
  282. package/out/zero-cache/src/services/replicator/change-log-db.d.ts.map +1 -0
  283. package/out/zero-cache/src/services/replicator/change-log-db.js +491 -0
  284. package/out/zero-cache/src/services/replicator/change-log-db.js.map +1 -0
  285. package/out/zero-cache/src/services/replicator/change-log-stream-writer.d.ts +55 -0
  286. package/out/zero-cache/src/services/replicator/change-log-stream-writer.d.ts.map +1 -0
  287. package/out/zero-cache/src/services/replicator/change-log-stream-writer.js +150 -0
  288. package/out/zero-cache/src/services/replicator/change-log-stream-writer.js.map +1 -0
  289. package/out/zero-cache/src/services/replicator/change-processor.d.ts +6 -0
  290. package/out/zero-cache/src/services/replicator/change-processor.d.ts.map +1 -1
  291. package/out/zero-cache/src/services/replicator/change-processor.js +70 -25
  292. package/out/zero-cache/src/services/replicator/change-processor.js.map +1 -1
  293. package/out/zero-cache/src/services/replicator/incremental-sync.d.ts +1 -1
  294. package/out/zero-cache/src/services/replicator/incremental-sync.d.ts.map +1 -1
  295. package/out/zero-cache/src/services/replicator/incremental-sync.js +19 -6
  296. package/out/zero-cache/src/services/replicator/incremental-sync.js.map +1 -1
  297. package/out/zero-cache/src/services/replicator/notifier.d.ts +0 -22
  298. package/out/zero-cache/src/services/replicator/notifier.d.ts.map +1 -1
  299. package/out/zero-cache/src/services/replicator/notifier.js +7 -1
  300. package/out/zero-cache/src/services/replicator/notifier.js.map +1 -1
  301. package/out/zero-cache/src/services/replicator/replicator.d.ts +17 -2
  302. package/out/zero-cache/src/services/replicator/replicator.d.ts.map +1 -1
  303. package/out/zero-cache/src/services/replicator/replicator.js +9 -3
  304. package/out/zero-cache/src/services/replicator/replicator.js.map +1 -1
  305. package/out/zero-cache/src/services/replicator/reporter/recorder.d.ts +27 -0
  306. package/out/zero-cache/src/services/replicator/reporter/recorder.d.ts.map +1 -1
  307. package/out/zero-cache/src/services/replicator/reporter/recorder.js +32 -0
  308. package/out/zero-cache/src/services/replicator/reporter/recorder.js.map +1 -1
  309. package/out/zero-cache/src/services/replicator/reporter/report-schema.d.ts +1 -1
  310. package/out/zero-cache/src/services/replicator/schema/backfilling.d.ts +119 -0
  311. package/out/zero-cache/src/services/replicator/schema/backfilling.d.ts.map +1 -0
  312. package/out/zero-cache/src/services/replicator/schema/backfilling.js +214 -0
  313. package/out/zero-cache/src/services/replicator/schema/backfilling.js.map +1 -0
  314. package/out/zero-cache/src/services/replicator/schema/change-log.d.ts +3 -3
  315. package/out/zero-cache/src/services/replicator/schema/column-metadata.js +1 -1
  316. package/out/zero-cache/src/services/replicator/schema/column-metadata.js.map +1 -1
  317. package/out/zero-cache/src/services/replicator/schema/replication-state.d.ts +1 -1
  318. package/out/zero-cache/src/services/replicator/schema/replication-state.d.ts.map +1 -1
  319. package/out/zero-cache/src/services/replicator/schema/replication-state.js +9 -5
  320. package/out/zero-cache/src/services/replicator/schema/replication-state.js.map +1 -1
  321. package/out/zero-cache/src/services/replicator/sqlite-change-log-observability.d.ts +132 -0
  322. package/out/zero-cache/src/services/replicator/sqlite-change-log-observability.d.ts.map +1 -0
  323. package/out/zero-cache/src/services/replicator/sqlite-change-log-observability.js +415 -0
  324. package/out/zero-cache/src/services/replicator/sqlite-change-log-observability.js.map +1 -0
  325. package/out/zero-cache/src/services/replicator/sqlite-change-log-purger.d.ts +120 -0
  326. package/out/zero-cache/src/services/replicator/sqlite-change-log-purger.d.ts.map +1 -0
  327. package/out/zero-cache/src/services/replicator/sqlite-change-log-purger.js +283 -0
  328. package/out/zero-cache/src/services/replicator/sqlite-change-log-purger.js.map +1 -0
  329. package/out/zero-cache/src/services/replicator/write-worker.js +23 -12
  330. package/out/zero-cache/src/services/replicator/write-worker.js.map +1 -1
  331. package/out/zero-cache/src/services/run-ast.d.ts.map +1 -1
  332. package/out/zero-cache/src/services/run-ast.js +2 -1
  333. package/out/zero-cache/src/services/run-ast.js.map +1 -1
  334. package/out/zero-cache/src/services/running-state.d.ts +1 -1
  335. package/out/zero-cache/src/services/running-state.d.ts.map +1 -1
  336. package/out/zero-cache/src/services/running-state.js +1 -0
  337. package/out/zero-cache/src/services/running-state.js.map +1 -1
  338. package/out/zero-cache/src/services/view-syncer/client-handler.d.ts +3 -2
  339. package/out/zero-cache/src/services/view-syncer/client-handler.d.ts.map +1 -1
  340. package/out/zero-cache/src/services/view-syncer/client-handler.js +25 -17
  341. package/out/zero-cache/src/services/view-syncer/client-handler.js.map +1 -1
  342. package/out/zero-cache/src/services/view-syncer/cvr-store.d.ts.map +1 -1
  343. package/out/zero-cache/src/services/view-syncer/cvr-store.js +14 -1
  344. package/out/zero-cache/src/services/view-syncer/cvr-store.js.map +1 -1
  345. package/out/zero-cache/src/services/view-syncer/e2e-serving-lag.d.ts +53 -0
  346. package/out/zero-cache/src/services/view-syncer/e2e-serving-lag.d.ts.map +1 -0
  347. package/out/zero-cache/src/services/view-syncer/e2e-serving-lag.js +68 -0
  348. package/out/zero-cache/src/services/view-syncer/e2e-serving-lag.js.map +1 -0
  349. package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts.map +1 -1
  350. package/out/zero-cache/src/services/view-syncer/pipeline-driver.js +18 -3
  351. package/out/zero-cache/src/services/view-syncer/pipeline-driver.js.map +1 -1
  352. package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts.map +1 -1
  353. package/out/zero-cache/src/services/view-syncer/snapshotter.js.map +1 -1
  354. package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts +14 -4
  355. package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts.map +1 -1
  356. package/out/zero-cache/src/services/view-syncer/view-syncer.js +70 -8
  357. package/out/zero-cache/src/services/view-syncer/view-syncer.js.map +1 -1
  358. package/out/zero-cache/src/types/downstream.d.ts +11 -0
  359. package/out/zero-cache/src/types/downstream.d.ts.map +1 -0
  360. package/out/zero-cache/src/types/pg.d.ts.map +1 -1
  361. package/out/zero-cache/src/types/pg.js +14 -4
  362. package/out/zero-cache/src/types/pg.js.map +1 -1
  363. package/out/zero-cache/src/types/poke-chunk.d.ts +18 -0
  364. package/out/zero-cache/src/types/poke-chunk.d.ts.map +1 -0
  365. package/out/zero-cache/src/types/poke-chunk.js +57 -0
  366. package/out/zero-cache/src/types/poke-chunk.js.map +1 -0
  367. package/out/zero-cache/src/types/processes.d.ts +1 -2
  368. package/out/zero-cache/src/types/processes.d.ts.map +1 -1
  369. package/out/zero-cache/src/types/processes.js +1 -28
  370. package/out/zero-cache/src/types/processes.js.map +1 -1
  371. package/out/zero-cache/src/types/streams.d.ts +16 -0
  372. package/out/zero-cache/src/types/streams.d.ts.map +1 -1
  373. package/out/zero-cache/src/types/streams.js +25 -4
  374. package/out/zero-cache/src/types/streams.js.map +1 -1
  375. package/out/zero-cache/src/types/subscription.d.ts +2 -0
  376. package/out/zero-cache/src/types/subscription.d.ts.map +1 -1
  377. package/out/zero-cache/src/types/subscription.js +6 -0
  378. package/out/zero-cache/src/types/subscription.js.map +1 -1
  379. package/out/zero-cache/src/workers/connection.d.ts +23 -4
  380. package/out/zero-cache/src/workers/connection.d.ts.map +1 -1
  381. package/out/zero-cache/src/workers/connection.js +130 -10
  382. package/out/zero-cache/src/workers/connection.js.map +1 -1
  383. package/out/zero-cache/src/workers/replicator.d.ts +25 -0
  384. package/out/zero-cache/src/workers/replicator.d.ts.map +1 -1
  385. package/out/zero-cache/src/workers/replicator.js +33 -1
  386. package/out/zero-cache/src/workers/replicator.js.map +1 -1
  387. package/out/zero-cache/src/workers/syncer.d.ts +12 -0
  388. package/out/zero-cache/src/workers/syncer.d.ts.map +1 -1
  389. package/out/zero-cache/src/workers/syncer.js +75 -0
  390. package/out/zero-cache/src/workers/syncer.js.map +1 -1
  391. package/out/zero-client/src/client/version.js +1 -1
  392. package/out/zero-client/src/client/zero-poke-handler.d.ts +7 -2
  393. package/out/zero-client/src/client/zero-poke-handler.d.ts.map +1 -1
  394. package/out/zero-client/src/client/zero-poke-handler.js +52 -2
  395. package/out/zero-client/src/client/zero-poke-handler.js.map +1 -1
  396. package/out/zero-client/src/client/zero.d.ts +6 -7
  397. package/out/zero-client/src/client/zero.d.ts.map +1 -1
  398. package/out/zero-client/src/client/zero.js +194 -107
  399. package/out/zero-client/src/client/zero.js.map +1 -1
  400. package/out/zero-protocol/src/down.d.ts +1 -1
  401. package/out/zero-protocol/src/poke.d.ts +89 -7
  402. package/out/zero-protocol/src/poke.d.ts.map +1 -1
  403. package/out/zero-protocol/src/poke.js +16 -8
  404. package/out/zero-protocol/src/poke.js.map +1 -1
  405. package/out/zero-protocol/src/protocol-version.d.ts +12 -7
  406. package/out/zero-protocol/src/protocol-version.d.ts.map +1 -1
  407. package/out/zero-protocol/src/protocol-version.js.map +1 -1
  408. package/out/zero-schema/src/builder/table-builder.d.ts +23 -0
  409. package/out/zero-schema/src/builder/table-builder.d.ts.map +1 -1
  410. package/out/zero-schema/src/builder/table-builder.js +18 -0
  411. package/out/zero-schema/src/builder/table-builder.js.map +1 -1
  412. package/out/zero-server/src/custom.js +10 -3
  413. package/out/zero-server/src/custom.js.map +1 -1
  414. package/out/zero-server/src/schema.d.ts +8 -0
  415. package/out/zero-server/src/schema.d.ts.map +1 -1
  416. package/out/zero-server/src/schema.js +63 -24
  417. package/out/zero-server/src/schema.js.map +1 -1
  418. package/out/zero-types/src/schema.d.ts +11 -0
  419. package/out/zero-types/src/schema.d.ts.map +1 -1
  420. package/out/zql/src/ivm/memory-source.d.ts +10 -2
  421. package/out/zql/src/ivm/memory-source.d.ts.map +1 -1
  422. package/out/zql/src/ivm/memory-source.js +14 -6
  423. package/out/zql/src/ivm/memory-source.js.map +1 -1
  424. package/out/zql/src/ivm/stream.d.ts +0 -1
  425. package/out/zql/src/ivm/stream.d.ts.map +1 -1
  426. package/out/zql/src/ivm/stream.js +1 -7
  427. package/out/zql/src/ivm/stream.js.map +1 -1
  428. package/out/zql/src/ivm/union-fan-in.d.ts +1 -1
  429. package/out/zql/src/ivm/union-fan-in.d.ts.map +1 -1
  430. package/out/zql/src/ivm/union-fan-in.js +11 -2
  431. package/out/zql/src/ivm/union-fan-in.js.map +1 -1
  432. package/out/zql/src/mutate/crud.d.ts +10 -8
  433. package/out/zql/src/mutate/crud.d.ts.map +1 -1
  434. package/out/zql/src/mutate/crud.js.map +1 -1
  435. package/out/zql/src/query/query-delegate-base.d.ts.map +1 -1
  436. package/out/zql/src/query/query-delegate-base.js +5 -1
  437. package/out/zql/src/query/query-delegate-base.js.map +1 -1
  438. package/out/zql/src/query/query-impl.d.ts +2 -2
  439. package/out/zql/src/query/query-impl.d.ts.map +1 -1
  440. package/out/zql/src/query/query-impl.js.map +1 -1
  441. package/out/zql/src/query/query.d.ts +83 -14
  442. package/out/zql/src/query/query.d.ts.map +1 -1
  443. package/out/zql/src/query/static-query.d.ts +1 -1
  444. package/out/zql/src/query/static-query.d.ts.map +1 -1
  445. package/out/zqlite/src/db.js +2 -2
  446. package/out/zqlite/src/resolve-scalar-subqueries.d.ts +15 -0
  447. package/out/zqlite/src/resolve-scalar-subqueries.d.ts.map +1 -1
  448. package/out/zqlite/src/resolve-scalar-subqueries.js +33 -14
  449. package/out/zqlite/src/resolve-scalar-subqueries.js.map +1 -1
  450. package/out/zqlite/src/sqlite-cost-model.js +5 -5
  451. package/out/zqlite/src/table-source.d.ts.map +1 -1
  452. package/out/zqlite/src/table-source.js +4 -4
  453. package/out/zqlite/src/table-source.js.map +1 -1
  454. package/package.json +3 -3
  455. package/out/replicache/src/db/index.js +0 -91
  456. package/out/replicache/src/db/index.js.map +0 -1
  457. package/out/replicache/src/lazy.d.ts +0 -2
  458. package/out/replicache/src/lazy.d.ts.map +0 -1
  459. package/out/replicache/src/lazy.js +0 -12
  460. package/out/replicache/src/lazy.js.map +0 -1
  461. package/out/zero-cache/src/server/backup-watermark-reader.js +0 -35
  462. package/out/zero-cache/src/server/backup-watermark-reader.js.map +0 -1
  463. package/out/zero-cache/src/services/change-streamer/litestream3-backup-monitor.d.ts.map +0 -1
  464. package/out/zero-cache/src/services/change-streamer/litestream3-backup-monitor.js.map +0 -1
  465. package/out/zero-cache/src/services/change-streamer/replica-monitor.d.ts +0 -16
  466. package/out/zero-cache/src/services/change-streamer/replica-monitor.d.ts.map +0 -1
  467. package/out/zero-cache/src/services/change-streamer/replica-monitor.js +0 -54
  468. package/out/zero-cache/src/services/change-streamer/replica-monitor.js.map +0 -1
  469. package/out/zero-cache/src/services/change-streamer/vfs-backup-monitor.d.ts +0 -25
  470. package/out/zero-cache/src/services/change-streamer/vfs-backup-monitor.d.ts.map +0 -1
  471. package/out/zero-cache/src/services/change-streamer/vfs-backup-monitor.js +0 -159
  472. package/out/zero-cache/src/services/change-streamer/vfs-backup-monitor.js.map +0 -1
  473. package/out/zero-cache/src/services/litestream/vfs-watermark-reader.d.ts +0 -44
  474. package/out/zero-cache/src/services/litestream/vfs-watermark-reader.d.ts.map +0 -1
  475. package/out/zero-cache/src/services/litestream/vfs-watermark-reader.js +0 -65
  476. package/out/zero-cache/src/services/litestream/vfs-watermark-reader.js.map +0 -1
  477. package/out/zero-cache/src/services/litestream/vfs-watermark-worker-source.d.ts +0 -11
  478. package/out/zero-cache/src/services/litestream/vfs-watermark-worker-source.d.ts.map +0 -1
  479. package/out/zero-cache/src/services/litestream/vfs-watermark-worker-source.js +0 -74
  480. package/out/zero-cache/src/services/litestream/vfs-watermark-worker-source.js.map +0 -1
  481. package/out/zero-cache/src/services/litestream/vfs-watermark-worker.d.ts +0 -42
  482. package/out/zero-cache/src/services/litestream/vfs-watermark-worker.d.ts.map +0 -1
  483. package/out/zero-cache/src/services/litestream/vfs-watermark-worker.js +0 -117
  484. package/out/zero-cache/src/services/litestream/vfs-watermark-worker.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"migration.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/db/migration.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AACjD,OAAO,KAAK,QAAQ,MAAM,UAAU,CAAC;AAGrC,OAAO,KAAK,CAAC,MAAM,+BAA+B,CAAC;AACnD,OAAO,EAAC,KAAK,UAAU,EAAE,KAAK,mBAAmB,EAAC,MAAM,gBAAgB,CAAC;AAGzE,KAAK,UAAU,GAAG,CAAC,GAAG,EAAE,UAAU,EAAE,EAAE,EAAE,mBAAmB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAE9E;;;;GAIG;AACH,MAAM,MAAM,SAAS,GAAG;IACtB;;;;OAIG;IACH,aAAa,CAAC,EAAE,UAAU,CAAC;IAE3B;;;;;;;OAOG;IACH,WAAW,CAAC,EAAE,UAAU,CAAC;IAEzB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF;;;;;;;;;;GAUG;AACH,MAAM,MAAM,uBAAuB,GAAG;IACpC,CAAC,kBAAkB,EAAE,MAAM,GAAG,SAAS,CAAC;CACzC,CAAC;AAEF;;;GAGG;AACH,wBAAsB,mBAAmB,CACvC,GAAG,EAAE,UAAU,EACf,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,EAAE,EAAE,UAAU,EACd,cAAc,EAAE,SAAS,EACzB,uBAAuB,EAAE,uBAAuB,GAC/C,OAAO,CAAC,IAAI,CAAC,CA8Ef;AAaD,eAAO,MAAM,cAAc;IACzB;;;;;;OAMG;;IAGH;;;;;;OAMG;;IAGH;;;;OAIG;;aAEH,CAAC;AAGH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAG5D,wBAAsB,yBAAyB,CAC7C,GAAG,EAAE,QAAQ,CAAC,GAAG,EACjB,UAAU,EAAE,MAAM,iBAcnB;AASD,wBAAsB,iBAAiB,CACrC,GAAG,EAAE,QAAQ,CAAC,GAAG,EACjB,UAAU,EAAE,MAAM,EAClB,MAAM,UAAQ,GACb,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAuBhC"}
1
+ {"version":3,"file":"migration.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/db/migration.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AACjD,OAAO,KAAK,QAAQ,MAAM,UAAU,CAAC;AAIrC,OAAO,KAAK,CAAC,MAAM,+BAA+B,CAAC;AACnD,OAAO,EAAC,KAAK,UAAU,EAAE,KAAK,mBAAmB,EAAC,MAAM,gBAAgB,CAAC;AAGzE,KAAK,UAAU,GAAG,CAAC,GAAG,EAAE,UAAU,EAAE,EAAE,EAAE,mBAAmB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAE9E;;;;GAIG;AACH,MAAM,MAAM,SAAS,GAAG;IACtB;;;;OAIG;IACH,aAAa,CAAC,EAAE,UAAU,CAAC;IAE3B;;;;;;;OAOG;IACH,WAAW,CAAC,EAAE,UAAU,CAAC;IAEzB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF;;;;;;;;;;GAUG;AACH,MAAM,MAAM,uBAAuB,GAAG;IACpC,CAAC,kBAAkB,EAAE,MAAM,GAAG,SAAS,CAAC;CACzC,CAAC;AAEF;;;GAGG;AACH,wBAAsB,mBAAmB,CACvC,GAAG,EAAE,UAAU,EACf,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,EAAE,EAAE,UAAU,EACd,cAAc,EAAE,SAAS,EACzB,uBAAuB,EAAE,uBAAuB,GAC/C,OAAO,CAAC,IAAI,CAAC,CAuFf;AAaD,eAAO,MAAM,cAAc;IACzB;;;;;;OAMG;;IAGH;;;;;;OAMG;;IAGH;;;;OAIG;;aAEH,CAAC;AAGH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAG5D,wBAAsB,yBAAyB,CAC7C,GAAG,EAAE,QAAQ,CAAC,GAAG,EACjB,UAAU,EAAE,MAAM,iBAcnB;AASD,wBAAsB,iBAAiB,CACrC,GAAG,EAAE,QAAQ,CAAC,GAAG,EACjB,UAAU,EAAE,MAAM,EAClB,MAAM,UAAQ,GACb,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAuBhC"}
@@ -1,4 +1,5 @@
1
1
  import { assert } from "../../../shared/src/asserts.js";
2
+ import { AbortError } from "../../../shared/src/abort-error.js";
2
3
  import { parse, valita_exports } from "../../../shared/src/valita.js";
3
4
  import { must } from "../../../shared/src/must.js";
4
5
  import "../types/pg.js";
@@ -35,7 +36,8 @@ async function runSchemaMigrations(log, debugName, schemaName, db, setupMigratio
35
36
  });
36
37
  log.info?.(`Running ${debugName} at schema v${codeVersion}`);
37
38
  } catch (e) {
38
- log.error?.("Error in ensureSchemaMigrated", e);
39
+ if (e instanceof AbortError) log.warn?.("Schema requires reset; resync will follow", e);
40
+ else log.error?.("Error in ensureSchemaMigrated", e);
39
41
  throw e;
40
42
  } finally {
41
43
  log.flush();
@@ -134,6 +136,6 @@ function getMinSafeVersion(log, current, proposedSafeVersion) {
134
136
  return proposedSafeVersion;
135
137
  }
136
138
  //#endregion
137
- export { getVersionHistory, runSchemaMigrations };
139
+ export { runSchemaMigrations };
138
140
 
139
141
  //# sourceMappingURL=migration.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"migration.js","names":[],"sources":["../../../../../zero-cache/src/db/migration.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport type postgres from 'postgres';\nimport {assert} from '../../../shared/src/asserts.ts';\nimport {must} from '../../../shared/src/must.ts';\nimport * as v from '../../../shared/src/valita.ts';\nimport {type PostgresDB, type PostgresTransaction} from '../types/pg.ts';\nimport {runTx} from './run-transaction.ts';\n\ntype Operations = (log: LogContext, tx: PostgresTransaction) => Promise<void>;\n\n/**\n * Encapsulates the logic for setting up or upgrading to a new schema. After the\n * Migration code successfully completes, {@link runSchemaMigrations}\n * will update the schema version and commit the transaction.\n */\nexport type Migration = {\n /**\n * Perform database operations that create or alter table structure. This is\n * called at most once during lifetime of the application. If a `migrateData()`\n * operation is defined, that will be performed after `migrateSchema()` succeeds.\n */\n migrateSchema?: Operations;\n\n /**\n * Perform database operations to migrate data to the new schema. This is\n * called after `migrateSchema()` (if defined), and may be called again\n * to re-migrate data after the server was rolled back to an earlier version,\n * and rolled forward again.\n *\n * Consequently, the logic in `migrateData()` must be idempotent.\n */\n migrateData?: Operations;\n\n /**\n * Sets the `minSafeVersion` to the specified value, prohibiting running\n * any earlier code versions.\n */\n minSafeVersion?: number;\n};\n\n/**\n * Mapping of incremental migrations to move from the previous old code\n * version to next one. Versions must be non-zero.\n *\n * The schema resulting from performing incremental migrations should be\n * equivalent to that of the `setupMigration` on a blank database.\n *\n * The highest destinationVersion of this map denotes the current\n * \"code version\", and is also used as the destination version when\n * running the initial setup migration on a blank database.\n */\nexport type IncrementalMigrationMap = {\n [destinationVersion: number]: Migration;\n};\n\n/**\n * Ensures that the schema is compatible with the current code, updating and\n * migrating the schema if necessary.\n */\nexport async function runSchemaMigrations(\n log: LogContext,\n debugName: string,\n schemaName: string,\n db: PostgresDB,\n setupMigration: Migration,\n incrementalMigrationMap: IncrementalMigrationMap,\n): Promise<void> {\n log = log.withContext('initSchema', schemaName);\n\n const versionMigrations = sorted(incrementalMigrationMap);\n assert(\n versionMigrations.length,\n `Must specify at least one version migration`,\n );\n assert(\n versionMigrations[0][0] > 0,\n `Versions must be non-zero positive numbers`,\n );\n // oxlint-disable-next-line typescript/no-non-null-assertion\n const codeVersion = versionMigrations.at(-1)![0];\n\n log.info?.(\n `Checking schema for compatibility with ${debugName} at schema v${codeVersion}`,\n );\n\n try {\n await runTx(db, async tx => {\n // Acquire advisory lock to prevent concurrent migrations from racing.\n // This can happen during rolling deployments when multiple pods start\n // up simultaneously. The lock auto-releases when the transaction ends.\n const lockName = `migrate-schema:${schemaName}`;\n await tx`SELECT pg_advisory_xact_lock(hashtext(${lockName}))`;\n\n let versions = await ensureVersionHistory(tx, schemaName);\n\n if (codeVersion < versions.minSafeVersion) {\n throw new Error(\n `Cannot run ${debugName} at schema v${codeVersion} because rollback limit is v${versions.minSafeVersion}`,\n );\n }\n\n if (versions.dataVersion > codeVersion) {\n log.info?.(\n `Data is at v${versions.dataVersion}. Resetting to v${codeVersion}`,\n );\n await updateVersionHistory(log, tx, schemaName, versions, codeVersion);\n return;\n }\n\n if (versions.dataVersion === codeVersion) {\n return;\n }\n\n const migrations =\n versions.dataVersion === 0\n ? // For an empty database (v0), only run the setup migration.\n ([[codeVersion, setupMigration]] as const)\n : versionMigrations;\n\n for (const [dest, migration] of migrations) {\n if (versions.dataVersion < dest) {\n log.info?.(\n `Migrating schema from v${versions.dataVersion} to v${dest}`,\n );\n void log.flush();\n versions = await runMigration(\n log,\n schemaName,\n tx,\n versions,\n dest,\n migration,\n );\n }\n }\n });\n\n log.info?.(`Running ${debugName} at schema v${codeVersion}`);\n } catch (e) {\n log.error?.('Error in ensureSchemaMigrated', e);\n throw e;\n } finally {\n void log.flush();\n }\n}\n\nfunction sorted(\n incrementalMigrationMap: IncrementalMigrationMap,\n): [number, Migration][] {\n const versionMigrations: [number, Migration][] = [];\n for (const [v, m] of Object.entries(incrementalMigrationMap)) {\n versionMigrations.push([Number(v), m]);\n }\n return versionMigrations.sort(([a], [b]) => a - b);\n}\n\n// Exposed for tests.\nexport const versionHistory = v.object({\n /**\n * The `schemaVersion` is highest code version that has ever been run\n * on the database, and is used to delineate the structure of the tables\n * in the database. A schemaVersion only moves forward; rolling back to\n * an earlier (safe) code version does not revert schema changes that\n * have already been applied.\n */\n schemaVersion: v.number(),\n\n /**\n * The data version is the code version of the latest server that ran.\n * Note that this may be less than the schemaVersion in the case that\n * a server is rolled back to an earlier version after a schema change.\n * In such a case, data (but not schema), may need to be re-migrated\n * when rolling forward again.\n */\n dataVersion: v.number(),\n\n /**\n * The minimum code version that is safe to run. This is used when\n * a schema migration is not backwards compatible with an older version\n * of the code.\n */\n minSafeVersion: v.number(),\n});\n\n// Exposed for tests.\nexport type VersionHistory = v.Infer<typeof versionHistory>;\n\n// Exposed for tests.\nexport async function createVersionHistoryTable(\n sql: postgres.Sql,\n schemaName: string,\n) {\n // Note: The `lock` column transparently ensures that at most one row exists.\n await sql`\n CREATE SCHEMA IF NOT EXISTS ${sql(schemaName)};\n CREATE TABLE IF NOT EXISTS ${sql(schemaName)}.\"versionHistory\" (\n \"dataVersion\" int NOT NULL,\n \"schemaVersion\" int NOT NULL,\n \"minSafeVersion\" int NOT NULL,\n\n lock char(1) NOT NULL CONSTRAINT DF_schema_meta_lock DEFAULT 'v',\n CONSTRAINT PK_schema_meta_lock PRIMARY KEY (lock),\n CONSTRAINT CK_schema_meta_lock CHECK (lock='v')\n );`.simple();\n}\n\nasync function ensureVersionHistory(\n sql: postgres.Sql,\n schemaName: string,\n): Promise<VersionHistory> {\n return must(await getVersionHistory(sql, schemaName, true));\n}\n\nexport async function getVersionHistory(\n sql: postgres.Sql,\n schemaName: string,\n create = false,\n): Promise<VersionHistory | null> {\n const exists = await sql`\n SELECT nspname, relname FROM pg_class\n JOIN pg_namespace ON relnamespace = pg_namespace.oid\n WHERE nspname = ${schemaName} AND relname = ${'versionHistory'}`;\n\n if (exists.length === 0) {\n if (create) {\n await createVersionHistoryTable(sql, schemaName);\n } else {\n return null;\n }\n }\n const rows = await sql`\n SELECT \"dataVersion\", \"schemaVersion\", \"minSafeVersion\"\n FROM ${sql(schemaName)}.\"versionHistory\"`;\n\n if (rows.length === 0) {\n return create\n ? {schemaVersion: 0, dataVersion: 0, minSafeVersion: 0}\n : null;\n }\n return v.parse(rows[0], versionHistory);\n}\n\nasync function updateVersionHistory(\n log: LogContext,\n sql: postgres.Sql,\n schemaName: string,\n prev: VersionHistory,\n newVersion: number,\n minSafeVersion?: number,\n): Promise<VersionHistory> {\n assert(newVersion > 0, 'newVersion must be positive');\n const versions = {\n dataVersion: newVersion,\n // The schemaVersion never moves backwards.\n schemaVersion: Math.max(newVersion, prev.schemaVersion),\n minSafeVersion: getMinSafeVersion(log, prev, minSafeVersion),\n } satisfies VersionHistory;\n\n await sql`\n INSERT INTO ${sql(schemaName)}.\"versionHistory\" ${sql(versions)}\n ON CONFLICT (lock) DO UPDATE SET ${sql(versions)}\n `;\n return versions;\n}\n\nasync function runMigration(\n log: LogContext,\n schemaName: string,\n tx: PostgresTransaction,\n versions: VersionHistory,\n destinationVersion: number,\n migration: Migration,\n): Promise<VersionHistory> {\n if (versions.schemaVersion < destinationVersion) {\n await migration.migrateSchema?.(log, tx);\n }\n if (versions.dataVersion < destinationVersion) {\n await migration.migrateData?.(log, tx);\n }\n return updateVersionHistory(\n log,\n tx,\n schemaName,\n versions,\n destinationVersion,\n migration.minSafeVersion,\n );\n}\n\n/**\n * Bumps the rollback limit [[toAtLeast]] the specified version.\n * Leaves the rollback limit unchanged if it is equal or greater.\n */\nfunction getMinSafeVersion(\n log: LogContext,\n current: VersionHistory,\n proposedSafeVersion?: number,\n): number {\n if (proposedSafeVersion === undefined) {\n return current.minSafeVersion;\n }\n if (current.minSafeVersion >= proposedSafeVersion) {\n // The rollback limit must never move backwards.\n log.debug?.(\n `rollback limit is already at ${current.minSafeVersion}, ` +\n `don't need to bump to ${proposedSafeVersion}`,\n );\n return current.minSafeVersion;\n }\n log.info?.(\n `bumping rollback limit from ${current.minSafeVersion} to ${proposedSafeVersion}`,\n );\n return proposedSafeVersion;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"migration.js","names":[],"sources":["../../../../../zero-cache/src/db/migration.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport type postgres from 'postgres';\nimport {AbortError} from '../../../shared/src/abort-error.ts';\nimport {assert} from '../../../shared/src/asserts.ts';\nimport {must} from '../../../shared/src/must.ts';\nimport * as v from '../../../shared/src/valita.ts';\nimport {type PostgresDB, type PostgresTransaction} from '../types/pg.ts';\nimport {runTx} from './run-transaction.ts';\n\ntype Operations = (log: LogContext, tx: PostgresTransaction) => Promise<void>;\n\n/**\n * Encapsulates the logic for setting up or upgrading to a new schema. After the\n * Migration code successfully completes, {@link runSchemaMigrations}\n * will update the schema version and commit the transaction.\n */\nexport type Migration = {\n /**\n * Perform database operations that create or alter table structure. This is\n * called at most once during lifetime of the application. If a `migrateData()`\n * operation is defined, that will be performed after `migrateSchema()` succeeds.\n */\n migrateSchema?: Operations;\n\n /**\n * Perform database operations to migrate data to the new schema. This is\n * called after `migrateSchema()` (if defined), and may be called again\n * to re-migrate data after the server was rolled back to an earlier version,\n * and rolled forward again.\n *\n * Consequently, the logic in `migrateData()` must be idempotent.\n */\n migrateData?: Operations;\n\n /**\n * Sets the `minSafeVersion` to the specified value, prohibiting running\n * any earlier code versions.\n */\n minSafeVersion?: number;\n};\n\n/**\n * Mapping of incremental migrations to move from the previous old code\n * version to next one. Versions must be non-zero.\n *\n * The schema resulting from performing incremental migrations should be\n * equivalent to that of the `setupMigration` on a blank database.\n *\n * The highest destinationVersion of this map denotes the current\n * \"code version\", and is also used as the destination version when\n * running the initial setup migration on a blank database.\n */\nexport type IncrementalMigrationMap = {\n [destinationVersion: number]: Migration;\n};\n\n/**\n * Ensures that the schema is compatible with the current code, updating and\n * migrating the schema if necessary.\n */\nexport async function runSchemaMigrations(\n log: LogContext,\n debugName: string,\n schemaName: string,\n db: PostgresDB,\n setupMigration: Migration,\n incrementalMigrationMap: IncrementalMigrationMap,\n): Promise<void> {\n log = log.withContext('initSchema', schemaName);\n\n const versionMigrations = sorted(incrementalMigrationMap);\n assert(\n versionMigrations.length,\n `Must specify at least one version migration`,\n );\n assert(\n versionMigrations[0][0] > 0,\n `Versions must be non-zero positive numbers`,\n );\n // oxlint-disable-next-line typescript/no-non-null-assertion\n const codeVersion = versionMigrations.at(-1)![0];\n\n log.info?.(\n `Checking schema for compatibility with ${debugName} at schema v${codeVersion}`,\n );\n\n try {\n await runTx(db, async tx => {\n // Acquire advisory lock to prevent concurrent migrations from racing.\n // This can happen during rolling deployments when multiple pods start\n // up simultaneously. The lock auto-releases when the transaction ends.\n const lockName = `migrate-schema:${schemaName}`;\n await tx`SELECT pg_advisory_xact_lock(hashtext(${lockName}))`;\n\n let versions = await ensureVersionHistory(tx, schemaName);\n\n if (codeVersion < versions.minSafeVersion) {\n throw new Error(\n `Cannot run ${debugName} at schema v${codeVersion} because rollback limit is v${versions.minSafeVersion}`,\n );\n }\n\n if (versions.dataVersion > codeVersion) {\n log.info?.(\n `Data is at v${versions.dataVersion}. Resetting to v${codeVersion}`,\n );\n await updateVersionHistory(log, tx, schemaName, versions, codeVersion);\n return;\n }\n\n if (versions.dataVersion === codeVersion) {\n return;\n }\n\n const migrations =\n versions.dataVersion === 0\n ? // For an empty database (v0), only run the setup migration.\n ([[codeVersion, setupMigration]] as const)\n : versionMigrations;\n\n for (const [dest, migration] of migrations) {\n if (versions.dataVersion < dest) {\n log.info?.(\n `Migrating schema from v${versions.dataVersion} to v${dest}`,\n );\n void log.flush();\n versions = await runMigration(\n log,\n schemaName,\n tx,\n versions,\n dest,\n migration,\n );\n }\n }\n });\n\n log.info?.(`Running ${debugName} at schema v${codeVersion}`);\n } catch (e) {\n if (e instanceof AbortError) {\n // AbortErrors (e.g. AutoResetSignal) are not failures. They are the\n // expected mechanism for signaling that the schema is not initialized\n // (or otherwise needs a reset) so that the caller can backtrack and\n // resync. Logging them at `error` would trip error-based alerting for a\n // normal, self-healing path.\n log.warn?.('Schema requires reset; resync will follow', e);\n } else {\n log.error?.('Error in ensureSchemaMigrated', e);\n }\n throw e;\n } finally {\n void log.flush();\n }\n}\n\nfunction sorted(\n incrementalMigrationMap: IncrementalMigrationMap,\n): [number, Migration][] {\n const versionMigrations: [number, Migration][] = [];\n for (const [v, m] of Object.entries(incrementalMigrationMap)) {\n versionMigrations.push([Number(v), m]);\n }\n return versionMigrations.sort(([a], [b]) => a - b);\n}\n\n// Exposed for tests.\nexport const versionHistory = v.object({\n /**\n * The `schemaVersion` is highest code version that has ever been run\n * on the database, and is used to delineate the structure of the tables\n * in the database. A schemaVersion only moves forward; rolling back to\n * an earlier (safe) code version does not revert schema changes that\n * have already been applied.\n */\n schemaVersion: v.number(),\n\n /**\n * The data version is the code version of the latest server that ran.\n * Note that this may be less than the schemaVersion in the case that\n * a server is rolled back to an earlier version after a schema change.\n * In such a case, data (but not schema), may need to be re-migrated\n * when rolling forward again.\n */\n dataVersion: v.number(),\n\n /**\n * The minimum code version that is safe to run. This is used when\n * a schema migration is not backwards compatible with an older version\n * of the code.\n */\n minSafeVersion: v.number(),\n});\n\n// Exposed for tests.\nexport type VersionHistory = v.Infer<typeof versionHistory>;\n\n// Exposed for tests.\nexport async function createVersionHistoryTable(\n sql: postgres.Sql,\n schemaName: string,\n) {\n // Note: The `lock` column transparently ensures that at most one row exists.\n await sql`\n CREATE SCHEMA IF NOT EXISTS ${sql(schemaName)};\n CREATE TABLE IF NOT EXISTS ${sql(schemaName)}.\"versionHistory\" (\n \"dataVersion\" int NOT NULL,\n \"schemaVersion\" int NOT NULL,\n \"minSafeVersion\" int NOT NULL,\n\n lock char(1) NOT NULL CONSTRAINT DF_schema_meta_lock DEFAULT 'v',\n CONSTRAINT PK_schema_meta_lock PRIMARY KEY (lock),\n CONSTRAINT CK_schema_meta_lock CHECK (lock='v')\n );`.simple();\n}\n\nasync function ensureVersionHistory(\n sql: postgres.Sql,\n schemaName: string,\n): Promise<VersionHistory> {\n return must(await getVersionHistory(sql, schemaName, true));\n}\n\nexport async function getVersionHistory(\n sql: postgres.Sql,\n schemaName: string,\n create = false,\n): Promise<VersionHistory | null> {\n const exists = await sql`\n SELECT nspname, relname FROM pg_class\n JOIN pg_namespace ON relnamespace = pg_namespace.oid\n WHERE nspname = ${schemaName} AND relname = ${'versionHistory'}`;\n\n if (exists.length === 0) {\n if (create) {\n await createVersionHistoryTable(sql, schemaName);\n } else {\n return null;\n }\n }\n const rows = await sql`\n SELECT \"dataVersion\", \"schemaVersion\", \"minSafeVersion\"\n FROM ${sql(schemaName)}.\"versionHistory\"`;\n\n if (rows.length === 0) {\n return create\n ? {schemaVersion: 0, dataVersion: 0, minSafeVersion: 0}\n : null;\n }\n return v.parse(rows[0], versionHistory);\n}\n\nasync function updateVersionHistory(\n log: LogContext,\n sql: postgres.Sql,\n schemaName: string,\n prev: VersionHistory,\n newVersion: number,\n minSafeVersion?: number,\n): Promise<VersionHistory> {\n assert(newVersion > 0, 'newVersion must be positive');\n const versions = {\n dataVersion: newVersion,\n // The schemaVersion never moves backwards.\n schemaVersion: Math.max(newVersion, prev.schemaVersion),\n minSafeVersion: getMinSafeVersion(log, prev, minSafeVersion),\n } satisfies VersionHistory;\n\n await sql`\n INSERT INTO ${sql(schemaName)}.\"versionHistory\" ${sql(versions)}\n ON CONFLICT (lock) DO UPDATE SET ${sql(versions)}\n `;\n return versions;\n}\n\nasync function runMigration(\n log: LogContext,\n schemaName: string,\n tx: PostgresTransaction,\n versions: VersionHistory,\n destinationVersion: number,\n migration: Migration,\n): Promise<VersionHistory> {\n if (versions.schemaVersion < destinationVersion) {\n await migration.migrateSchema?.(log, tx);\n }\n if (versions.dataVersion < destinationVersion) {\n await migration.migrateData?.(log, tx);\n }\n return updateVersionHistory(\n log,\n tx,\n schemaName,\n versions,\n destinationVersion,\n migration.minSafeVersion,\n );\n}\n\n/**\n * Bumps the rollback limit [[toAtLeast]] the specified version.\n * Leaves the rollback limit unchanged if it is equal or greater.\n */\nfunction getMinSafeVersion(\n log: LogContext,\n current: VersionHistory,\n proposedSafeVersion?: number,\n): number {\n if (proposedSafeVersion === undefined) {\n return current.minSafeVersion;\n }\n if (current.minSafeVersion >= proposedSafeVersion) {\n // The rollback limit must never move backwards.\n log.debug?.(\n `rollback limit is already at ${current.minSafeVersion}, ` +\n `don't need to bump to ${proposedSafeVersion}`,\n );\n return current.minSafeVersion;\n }\n log.info?.(\n `bumping rollback limit from ${current.minSafeVersion} to ${proposedSafeVersion}`,\n );\n return proposedSafeVersion;\n}\n"],"mappings":"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"}
@@ -3,9 +3,10 @@ type DiagnosticTarget = {
3
3
  readonly debugName: string;
4
4
  readonly dbPath: string;
5
5
  };
6
+ export type SQLiteCorruptionChecks = boolean;
6
7
  export declare function isSQLiteCorruption(e: unknown): boolean;
7
- export declare function registerSQLiteCorruptionDiagnosticTarget(target: DiagnosticTarget): () => void;
8
+ export declare function registerSQLiteCorruptionDiagnosticTarget(target: DiagnosticTarget, corruptionChecks?: SQLiteCorruptionChecks): () => void;
8
9
  export declare function logLastChanceSQLiteCorruptionDiagnostics(lc: LogContext, cause: unknown): boolean;
9
- export declare function logSQLiteCorruptionDiagnostics(lc: LogContext, debugName: string, dbPath: string, cause: unknown): void;
10
+ export declare function logSQLiteCorruptionDiagnostics(lc: LogContext, debugName: string, dbPath: string, cause: unknown, corruptionChecks?: SQLiteCorruptionChecks): void;
10
11
  export {};
11
12
  //# sourceMappingURL=sqlite-corruption.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"sqlite-corruption.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/db/sqlite-corruption.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAiCjD,KAAK,gBAAgB,GAAG;IACtB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB,CAAC;AAKF,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAEtD;AAED,wBAAgB,wCAAwC,CACtD,MAAM,EAAE,gBAAgB,GACvB,MAAM,IAAI,CAIZ;AAED,wBAAgB,wCAAwC,CACtD,EAAE,EAAE,UAAU,EACd,KAAK,EAAE,OAAO,GACb,OAAO,CAQT;AAED,wBAAgB,8BAA8B,CAC5C,EAAE,EAAE,UAAU,EACd,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,OAAO,GACb,IAAI,CA+CN"}
1
+ {"version":3,"file":"sqlite-corruption.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/db/sqlite-corruption.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAoCjD,KAAK,gBAAgB,GAAG;IACtB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB,CAAC;AASF,MAAM,MAAM,sBAAsB,GAAG,OAAO,CAAC;AAE7C,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAEtD;AAED,wBAAgB,wCAAwC,CACtD,MAAM,EAAE,gBAAgB,EACxB,gBAAgB,GAAE,sBAA8B,GAC/C,MAAM,IAAI,CAIZ;AAED,wBAAgB,wCAAwC,CACtD,EAAE,EAAE,UAAU,EACd,KAAK,EAAE,OAAO,GACb,OAAO,CAkBT;AAED,wBAAgB,8BAA8B,CAC5C,EAAE,EAAE,UAAU,EACd,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,OAAO,EACd,gBAAgB,GAAE,sBAA8B,GAC/C,IAAI,CAiDN"}
@@ -2,7 +2,7 @@ import { Database } from "../../../zqlite/src/db.js";
2
2
  import { SqliteError } from "@rocicorp/zero-sqlite3";
3
3
  import { existsSync, statSync } from "node:fs";
4
4
  //#region ../zero-cache/src/db/sqlite-corruption.ts
5
- var SQLITE_CORRUPTION_CODES = new Set(["SQLITE_CORRUPT", "SQLITE_NOTADB"]);
5
+ var SQLITE_CORRUPTION_CODE = /^SQLITE_(CORRUPT(_|$)|NOTADB$)/;
6
6
  var SQLITE_CORRUPTION_MESSAGE = /database disk image is malformed|file is not a database|database is malformed|malformed database/i;
7
7
  var SQLITE_FILE_SUFFIXES = [
8
8
  "",
@@ -17,17 +17,20 @@ var nextDiagnosticTargetID = 0;
17
17
  function isSQLiteCorruption(e) {
18
18
  return getSQLiteCorruptionCode(e) !== void 0;
19
19
  }
20
- function registerSQLiteCorruptionDiagnosticTarget(target) {
20
+ function registerSQLiteCorruptionDiagnosticTarget(target, corruptionChecks = false) {
21
21
  const id = nextDiagnosticTargetID++;
22
- diagnosticTargets.set(id, target);
22
+ diagnosticTargets.set(id, {
23
+ ...target,
24
+ corruptionChecks
25
+ });
23
26
  return () => diagnosticTargets.delete(id);
24
27
  }
25
28
  function logLastChanceSQLiteCorruptionDiagnostics(lc, cause) {
26
29
  if (!isSQLiteCorruption(cause) || diagnosticTargets.size === 0) return false;
27
- for (const { debugName, dbPath } of diagnosticTargets.values()) logSQLiteCorruptionDiagnostics(lc, debugName, dbPath, cause);
30
+ for (const { debugName, dbPath, corruptionChecks } of diagnosticTargets.values()) logSQLiteCorruptionDiagnostics(lc, debugName, dbPath, cause, corruptionChecks);
28
31
  return true;
29
32
  }
30
- function logSQLiteCorruptionDiagnostics(lc, debugName, dbPath, cause) {
33
+ function logSQLiteCorruptionDiagnostics(lc, debugName, dbPath, cause, corruptionChecks = false) {
31
34
  const start = Date.now();
32
35
  lc.error?.("SQLite replica corruption detected", {
33
36
  debugName,
@@ -51,8 +54,10 @@ function logSQLiteCorruptionDiagnostics(lc, debugName, dbPath, cause) {
51
54
  try {
52
55
  logDiagnostic(lc, debugName, "basic-pragmas", () => ({ pragmas: getBasicPragmas(db) }));
53
56
  logDiagnostic(lc, debugName, "replica-metadata", () => ({ metadata: getReplicaMetadata(db) }));
54
- logDiagnostic(lc, debugName, "quick-check", () => ({ check: runCheck(db, "quick_check") }));
55
- logDiagnostic(lc, debugName, "integrity-check", () => ({ check: runCheck(db, "integrity_check") }));
57
+ if (corruptionChecks) {
58
+ logDiagnostic(lc, debugName, "quick-check", () => ({ check: runCheck(db, "quick_check") }));
59
+ logDiagnostic(lc, debugName, "integrity-check", () => ({ check: runCheck(db, "integrity_check") }));
60
+ }
56
61
  lc.error?.("SQLite corruption diagnostics completed", {
57
62
  debugName,
58
63
  dbPath,
@@ -68,7 +73,7 @@ function getSQLiteCorruptionCode(e) {
68
73
  while (current !== void 0 && current !== null && !seen.has(current)) {
69
74
  seen.add(current);
70
75
  const code = getErrorCode(current);
71
- if (code !== void 0 && SQLITE_CORRUPTION_CODES.has(code)) return code;
76
+ if (code !== void 0 && SQLITE_CORRUPTION_CODE.test(code)) return code;
72
77
  if (current instanceof SqliteError || current instanceof Error) {
73
78
  if (SQLITE_CORRUPTION_MESSAGE.test(current.message)) return code ?? "SQLITE_CORRUPT";
74
79
  current = getErrorCause(current);
@@ -1 +1 @@
1
- {"version":3,"file":"sqlite-corruption.js","names":[],"sources":["../../../../../zero-cache/src/db/sqlite-corruption.ts"],"sourcesContent":["import {existsSync, statSync} from 'node:fs';\nimport type {LogContext} from '@rocicorp/logger';\nimport {SqliteError} from '@rocicorp/zero-sqlite3';\nimport {Database} from '../../../zqlite/src/db.ts';\n\nconst SQLITE_CORRUPTION_CODES = new Set(['SQLITE_CORRUPT', 'SQLITE_NOTADB']);\nconst SQLITE_CORRUPTION_MESSAGE =\n /database disk image is malformed|file is not a database|database is malformed|malformed database/i;\nconst SQLITE_FILE_SUFFIXES = ['', '-wal', '-wal2', '-shm', '-journal'] as const;\nconst MAX_LOGGED_CHECK_ISSUES = 20;\n\ntype ErrorSummary = {\n readonly name: string;\n readonly message: string;\n readonly code?: string | undefined;\n readonly cause?: ErrorSummary | string | undefined;\n};\n\ntype SQLiteFileStats = {\n readonly suffix: string;\n readonly path: string;\n readonly sizeBytes: number;\n readonly mtimeMs: number;\n};\n\ntype CheckSummary = {\n readonly status: 'ok' | 'failed';\n readonly rowCount: number;\n readonly issueCount: number;\n readonly loggedIssueCount: number;\n readonly truncated: boolean;\n readonly issues: string[];\n};\n\ntype DiagnosticTarget = {\n readonly debugName: string;\n readonly dbPath: string;\n};\n\nconst diagnosticTargets = new Map<number, DiagnosticTarget>();\nlet nextDiagnosticTargetID = 0;\n\nexport function isSQLiteCorruption(e: unknown): boolean {\n return getSQLiteCorruptionCode(e) !== undefined;\n}\n\nexport function registerSQLiteCorruptionDiagnosticTarget(\n target: DiagnosticTarget,\n): () => void {\n const id = nextDiagnosticTargetID++;\n diagnosticTargets.set(id, target);\n return () => diagnosticTargets.delete(id);\n}\n\nexport function logLastChanceSQLiteCorruptionDiagnostics(\n lc: LogContext,\n cause: unknown,\n): boolean {\n if (!isSQLiteCorruption(cause) || diagnosticTargets.size === 0) {\n return false;\n }\n for (const {debugName, dbPath} of diagnosticTargets.values()) {\n logSQLiteCorruptionDiagnostics(lc, debugName, dbPath, cause);\n }\n return true;\n}\n\nexport function logSQLiteCorruptionDiagnostics(\n lc: LogContext,\n debugName: string,\n dbPath: string,\n cause: unknown,\n): void {\n const start = Date.now();\n lc.error?.('SQLite replica corruption detected', {\n debugName,\n dbPath,\n cause: summarizeError(cause),\n });\n\n logDiagnostic(lc, debugName, 'file-stats', () => ({\n files: getSQLiteFileStats(dbPath),\n }));\n\n let db: Database | undefined;\n try {\n db = new Database(lc, dbPath, {readonly: true});\n db.pragma('busy_timeout = 1000');\n } catch (e) {\n lc.error?.('SQLite corruption diagnostic failed', {\n debugName,\n step: 'open-readonly',\n durationMs: Date.now() - start,\n error: summarizeError(e),\n });\n return;\n }\n\n try {\n logDiagnostic(lc, debugName, 'basic-pragmas', () => ({\n pragmas: getBasicPragmas(db),\n }));\n logDiagnostic(lc, debugName, 'replica-metadata', () => ({\n metadata: getReplicaMetadata(db),\n }));\n logDiagnostic(lc, debugName, 'quick-check', () => ({\n check: runCheck(db, 'quick_check'),\n }));\n logDiagnostic(lc, debugName, 'integrity-check', () => ({\n check: runCheck(db, 'integrity_check'),\n }));\n lc.error?.('SQLite corruption diagnostics completed', {\n debugName,\n dbPath,\n durationMs: Date.now() - start,\n });\n } finally {\n db.close();\n }\n}\n\nfunction getSQLiteCorruptionCode(e: unknown): string | undefined {\n let current = e;\n const seen = new Set<unknown>();\n\n while (current !== undefined && current !== null && !seen.has(current)) {\n seen.add(current);\n\n const code = getErrorCode(current);\n if (code !== undefined && SQLITE_CORRUPTION_CODES.has(code)) {\n return code;\n }\n\n if (current instanceof SqliteError || current instanceof Error) {\n if (SQLITE_CORRUPTION_MESSAGE.test(current.message)) {\n return code ?? 'SQLITE_CORRUPT';\n }\n current = getErrorCause(current);\n continue;\n }\n\n break;\n }\n\n return undefined;\n}\n\nfunction getErrorCode(e: unknown): string | undefined {\n if (e && typeof e === 'object' && 'code' in e) {\n const code = (e as {readonly code?: unknown}).code;\n return typeof code === 'string' ? code : undefined;\n }\n return undefined;\n}\n\nfunction getErrorCause(e: Error): unknown {\n return (e as {readonly cause?: unknown}).cause;\n}\n\nfunction summarizeError(e: unknown, depth = 0): ErrorSummary | string {\n if (!(e instanceof Error)) {\n return String(e);\n }\n const cause = getErrorCause(e);\n return {\n name: e.name,\n message: e.message,\n code: getErrorCode(e),\n cause:\n cause === undefined || depth >= 4\n ? undefined\n : summarizeError(cause, depth + 1),\n };\n}\n\nfunction getSQLiteFileStats(dbPath: string): SQLiteFileStats[] {\n const stats: SQLiteFileStats[] = [];\n for (const suffix of SQLITE_FILE_SUFFIXES) {\n const path = `${dbPath}${suffix}`;\n if (!existsSync(path)) {\n continue;\n }\n const stat = statSync(path);\n stats.push({\n suffix,\n path,\n sizeBytes: stat.size,\n mtimeMs: stat.mtimeMs,\n });\n }\n return stats;\n}\n\nfunction getBasicPragmas(db: Database) {\n return {\n pageSize: firstPragmaValue<number>(db, 'page_size', 'page_size'),\n pageCount: firstPragmaValue<number>(db, 'page_count', 'page_count'),\n freelistCount: firstPragmaValue<number>(\n db,\n 'freelist_count',\n 'freelist_count',\n ),\n journalMode: firstPragmaValue<string>(db, 'journal_mode', 'journal_mode'),\n schemaVersion: firstPragmaValue<number>(\n db,\n 'schema_version',\n 'schema_version',\n ),\n userVersion: firstPragmaValue<number>(db, 'user_version', 'user_version'),\n applicationID: firstPragmaValue<number>(\n db,\n 'application_id',\n 'application_id',\n ),\n };\n}\n\nfunction getReplicaMetadata(db: Database) {\n return {\n versionHistory: queryDiagnostic(() =>\n db\n .prepare(\n `SELECT dataVersion, schemaVersion, minSafeVersion\n FROM \"_zero.versionHistory\"`,\n )\n .get(),\n ),\n subscriptionState: queryDiagnostic(() =>\n db\n .prepare(\n `SELECT c.replicaVersion, s.stateVersion as watermark\n FROM \"_zero.replicationConfig\" as c\n JOIN \"_zero.replicationState\" as s\n ON c.lock = s.lock`,\n )\n .get(),\n ),\n sqliteCatalogCounts: queryDiagnostic(() =>\n db\n .prepare(\n `SELECT type, count(*) as count\n FROM sqlite_master\n GROUP BY type\n ORDER BY type`,\n )\n .all(),\n ),\n };\n}\n\nfunction queryDiagnostic<T>(query: () => T):\n | {readonly ok: true; readonly value: T}\n | {\n readonly ok: false;\n readonly error: ErrorSummary | string;\n } {\n try {\n return {ok: true, value: query()};\n } catch (e) {\n return {ok: false, error: summarizeError(e)};\n }\n}\n\nfunction firstPragmaValue<T>(\n db: Database,\n pragma: string,\n column: string,\n): T | undefined {\n const [row] = db.pragma<Record<string, T>>(pragma);\n return row?.[column];\n}\n\nfunction runCheck(db: Database, pragma: 'quick_check' | 'integrity_check') {\n const rows = db.pragma<Record<string, string>>(pragma);\n const issues = rows\n .map(row => row[pragma] ?? Object.values(row)[0] ?? '')\n .filter(issue => issue !== '' && issue !== 'ok');\n const loggedIssues = issues.slice(0, MAX_LOGGED_CHECK_ISSUES);\n return {\n status: issues.length === 0 ? 'ok' : 'failed',\n rowCount: rows.length,\n issueCount: issues.length,\n loggedIssueCount: loggedIssues.length,\n truncated: issues.length > loggedIssues.length,\n issues: loggedIssues,\n } satisfies CheckSummary;\n}\n\nfunction logDiagnostic<T>(\n lc: LogContext,\n debugName: string,\n step: string,\n fn: () => T,\n): void {\n const start = Date.now();\n try {\n const result = fn();\n lc.error?.('SQLite corruption diagnostic', {\n debugName,\n step,\n durationMs: Date.now() - start,\n result,\n });\n } catch (e) {\n lc.error?.('SQLite corruption diagnostic failed', {\n debugName,\n step,\n durationMs: Date.now() - start,\n error: summarizeError(e),\n });\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"sqlite-corruption.js","names":[],"sources":["../../../../../zero-cache/src/db/sqlite-corruption.ts"],"sourcesContent":["import {existsSync, statSync} from 'node:fs';\nimport type {LogContext} from '@rocicorp/logger';\nimport {SqliteError} from '@rocicorp/zero-sqlite3';\nimport {Database} from '../../../zqlite/src/db.ts';\n\n// Matches primary corruption codes and extended variants (e.g.\n// SQLITE_CORRUPT_INDEX, SQLITE_CORRUPT_VTAB, SQLITE_CORRUPT_SEQUENCE), which\n// the driver reports because it enables sqlite3_extended_result_codes().\nconst SQLITE_CORRUPTION_CODE = /^SQLITE_(CORRUPT(_|$)|NOTADB$)/;\nconst SQLITE_CORRUPTION_MESSAGE =\n /database disk image is malformed|file is not a database|database is malformed|malformed database/i;\nconst SQLITE_FILE_SUFFIXES = ['', '-wal', '-wal2', '-shm', '-journal'] as const;\nconst MAX_LOGGED_CHECK_ISSUES = 20;\n\ntype ErrorSummary = {\n readonly name: string;\n readonly message: string;\n readonly code?: string | undefined;\n readonly cause?: ErrorSummary | string | undefined;\n};\n\ntype SQLiteFileStats = {\n readonly suffix: string;\n readonly path: string;\n readonly sizeBytes: number;\n readonly mtimeMs: number;\n};\n\ntype CheckSummary = {\n readonly status: 'ok' | 'failed';\n readonly rowCount: number;\n readonly issueCount: number;\n readonly loggedIssueCount: number;\n readonly truncated: boolean;\n readonly issues: string[];\n};\n\ntype DiagnosticTarget = {\n readonly debugName: string;\n readonly dbPath: string;\n};\n\ntype RegisteredDiagnosticTarget = DiagnosticTarget & {\n readonly corruptionChecks: SQLiteCorruptionChecks;\n};\n\nconst diagnosticTargets = new Map<number, RegisteredDiagnosticTarget>();\nlet nextDiagnosticTargetID = 0;\n\nexport type SQLiteCorruptionChecks = boolean;\n\nexport function isSQLiteCorruption(e: unknown): boolean {\n return getSQLiteCorruptionCode(e) !== undefined;\n}\n\nexport function registerSQLiteCorruptionDiagnosticTarget(\n target: DiagnosticTarget,\n corruptionChecks: SQLiteCorruptionChecks = false,\n): () => void {\n const id = nextDiagnosticTargetID++;\n diagnosticTargets.set(id, {...target, corruptionChecks});\n return () => diagnosticTargets.delete(id);\n}\n\nexport function logLastChanceSQLiteCorruptionDiagnostics(\n lc: LogContext,\n cause: unknown,\n): boolean {\n if (!isSQLiteCorruption(cause) || diagnosticTargets.size === 0) {\n return false;\n }\n for (const {\n debugName,\n dbPath,\n corruptionChecks,\n } of diagnosticTargets.values()) {\n logSQLiteCorruptionDiagnostics(\n lc,\n debugName,\n dbPath,\n cause,\n corruptionChecks,\n );\n }\n return true;\n}\n\nexport function logSQLiteCorruptionDiagnostics(\n lc: LogContext,\n debugName: string,\n dbPath: string,\n cause: unknown,\n corruptionChecks: SQLiteCorruptionChecks = false,\n): void {\n const start = Date.now();\n lc.error?.('SQLite replica corruption detected', {\n debugName,\n dbPath,\n cause: summarizeError(cause),\n });\n\n logDiagnostic(lc, debugName, 'file-stats', () => ({\n files: getSQLiteFileStats(dbPath),\n }));\n\n let db: Database | undefined;\n try {\n db = new Database(lc, dbPath, {readonly: true});\n db.pragma('busy_timeout = 1000');\n } catch (e) {\n lc.error?.('SQLite corruption diagnostic failed', {\n debugName,\n step: 'open-readonly',\n durationMs: Date.now() - start,\n error: summarizeError(e),\n });\n return;\n }\n\n try {\n logDiagnostic(lc, debugName, 'basic-pragmas', () => ({\n pragmas: getBasicPragmas(db),\n }));\n logDiagnostic(lc, debugName, 'replica-metadata', () => ({\n metadata: getReplicaMetadata(db),\n }));\n if (corruptionChecks) {\n logDiagnostic(lc, debugName, 'quick-check', () => ({\n check: runCheck(db, 'quick_check'),\n }));\n logDiagnostic(lc, debugName, 'integrity-check', () => ({\n check: runCheck(db, 'integrity_check'),\n }));\n }\n lc.error?.('SQLite corruption diagnostics completed', {\n debugName,\n dbPath,\n durationMs: Date.now() - start,\n });\n } finally {\n db.close();\n }\n}\n\nfunction getSQLiteCorruptionCode(e: unknown): string | undefined {\n let current = e;\n const seen = new Set<unknown>();\n\n while (current !== undefined && current !== null && !seen.has(current)) {\n seen.add(current);\n\n const code = getErrorCode(current);\n if (code !== undefined && SQLITE_CORRUPTION_CODE.test(code)) {\n return code;\n }\n\n if (current instanceof SqliteError || current instanceof Error) {\n if (SQLITE_CORRUPTION_MESSAGE.test(current.message)) {\n return code ?? 'SQLITE_CORRUPT';\n }\n current = getErrorCause(current);\n continue;\n }\n\n break;\n }\n\n return undefined;\n}\n\nfunction getErrorCode(e: unknown): string | undefined {\n if (e && typeof e === 'object' && 'code' in e) {\n const code = (e as {readonly code?: unknown}).code;\n return typeof code === 'string' ? code : undefined;\n }\n return undefined;\n}\n\nfunction getErrorCause(e: Error): unknown {\n return (e as {readonly cause?: unknown}).cause;\n}\n\nfunction summarizeError(e: unknown, depth = 0): ErrorSummary | string {\n if (!(e instanceof Error)) {\n return String(e);\n }\n const cause = getErrorCause(e);\n return {\n name: e.name,\n message: e.message,\n code: getErrorCode(e),\n cause:\n cause === undefined || depth >= 4\n ? undefined\n : summarizeError(cause, depth + 1),\n };\n}\n\nfunction getSQLiteFileStats(dbPath: string): SQLiteFileStats[] {\n const stats: SQLiteFileStats[] = [];\n for (const suffix of SQLITE_FILE_SUFFIXES) {\n const path = `${dbPath}${suffix}`;\n if (!existsSync(path)) {\n continue;\n }\n const stat = statSync(path);\n stats.push({\n suffix,\n path,\n sizeBytes: stat.size,\n mtimeMs: stat.mtimeMs,\n });\n }\n return stats;\n}\n\nfunction getBasicPragmas(db: Database) {\n return {\n pageSize: firstPragmaValue<number>(db, 'page_size', 'page_size'),\n pageCount: firstPragmaValue<number>(db, 'page_count', 'page_count'),\n freelistCount: firstPragmaValue<number>(\n db,\n 'freelist_count',\n 'freelist_count',\n ),\n journalMode: firstPragmaValue<string>(db, 'journal_mode', 'journal_mode'),\n schemaVersion: firstPragmaValue<number>(\n db,\n 'schema_version',\n 'schema_version',\n ),\n userVersion: firstPragmaValue<number>(db, 'user_version', 'user_version'),\n applicationID: firstPragmaValue<number>(\n db,\n 'application_id',\n 'application_id',\n ),\n };\n}\n\nfunction getReplicaMetadata(db: Database) {\n return {\n versionHistory: queryDiagnostic(() =>\n db\n .prepare(\n `SELECT dataVersion, schemaVersion, minSafeVersion\n FROM \"_zero.versionHistory\"`,\n )\n .get(),\n ),\n subscriptionState: queryDiagnostic(() =>\n db\n .prepare(\n `SELECT c.replicaVersion, s.stateVersion as watermark\n FROM \"_zero.replicationConfig\" as c\n JOIN \"_zero.replicationState\" as s\n ON c.lock = s.lock`,\n )\n .get(),\n ),\n sqliteCatalogCounts: queryDiagnostic(() =>\n db\n .prepare(\n `SELECT type, count(*) as count\n FROM sqlite_master\n GROUP BY type\n ORDER BY type`,\n )\n .all(),\n ),\n };\n}\n\nfunction queryDiagnostic<T>(query: () => T):\n | {readonly ok: true; readonly value: T}\n | {\n readonly ok: false;\n readonly error: ErrorSummary | string;\n } {\n try {\n return {ok: true, value: query()};\n } catch (e) {\n return {ok: false, error: summarizeError(e)};\n }\n}\n\nfunction firstPragmaValue<T>(\n db: Database,\n pragma: string,\n column: string,\n): T | undefined {\n const [row] = db.pragma<Record<string, T>>(pragma);\n return row?.[column];\n}\n\nfunction runCheck(db: Database, pragma: 'quick_check' | 'integrity_check') {\n const rows = db.pragma<Record<string, string>>(pragma);\n const issues = rows\n .map(row => row[pragma] ?? Object.values(row)[0] ?? '')\n .filter(issue => issue !== '' && issue !== 'ok');\n const loggedIssues = issues.slice(0, MAX_LOGGED_CHECK_ISSUES);\n return {\n status: issues.length === 0 ? 'ok' : 'failed',\n rowCount: rows.length,\n issueCount: issues.length,\n loggedIssueCount: loggedIssues.length,\n truncated: issues.length > loggedIssues.length,\n issues: loggedIssues,\n } satisfies CheckSummary;\n}\n\nfunction logDiagnostic<T>(\n lc: LogContext,\n debugName: string,\n step: string,\n fn: () => T,\n): void {\n const start = Date.now();\n try {\n const result = fn();\n lc.error?.('SQLite corruption diagnostic', {\n debugName,\n step,\n durationMs: Date.now() - start,\n result,\n });\n } catch (e) {\n lc.error?.('SQLite corruption diagnostic failed', {\n debugName,\n step,\n durationMs: Date.now() - start,\n error: summarizeError(e),\n });\n }\n}\n"],"mappings":"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"}
@@ -1,6 +1,7 @@
1
1
  import type { LogContext } from '@rocicorp/logger';
2
2
  import type postgres from 'postgres';
3
3
  import type { Enum } from '../../../shared/src/enum.ts';
4
+ import { Queue } from '../../../shared/src/queue.ts';
4
5
  import { type PostgresDB, type PostgresTransaction } from '../types/pg.ts';
5
6
  import type * as Mode from './mode-enum.ts';
6
7
  type Mode = Enum<typeof Mode>;
@@ -47,15 +48,6 @@ export type Options = {
47
48
  * workers will be shut down after an idle timeout of 5 seconds.
48
49
  */
49
50
  maxWorkers?: number;
50
- /**
51
- * Aborts the transaction if the response for a statement is not received
52
- * within the specified timeout. Note that this is different from a Postgres
53
- * `statement_timeout` or `lock_timeout` in that it is specifically intended
54
- * to detect situations in which Postgres either never received the
55
- * statement, or the application never got the response for the executed
56
- * statement.
57
- */
58
- statementResponseTimeout?: number;
59
51
  };
60
52
  /**
61
53
  * A TransactionPool is a pool of one or more {@link postgres.TransactionSql}
@@ -181,11 +173,13 @@ export declare function sharedSnapshot(): {
181
173
  snapshotID: Promise<string>;
182
174
  };
183
175
  /**
184
- * @returns An `init` Task for importing a snapshot from another transaction.
176
+ * @returns An `init` Task for importing a snapshot from another transaction,
177
+ * as well as an `imported` Queue which resolves or rejects when each
178
+ * worker is initialized.
185
179
  */
186
180
  export declare function importSnapshot(snapshotID: string): {
187
181
  init: Task;
188
- imported: Promise<void>;
182
+ imported: Queue<void>;
189
183
  };
190
184
  /**
191
185
  * A superclass of Errors used for control flow that is needed to handle
@@ -205,9 +199,5 @@ type TimeoutTasks = {
205
199
  forExtraWorkers: TimeoutTask;
206
200
  };
207
201
  export declare const TIMEOUT_TASKS: TimeoutTasks;
208
- export declare class ResponseTimeoutError extends Error {
209
- static readonly name = "ResponseTimeoutError";
210
- constructor(msg: string);
211
- }
212
202
  export {};
213
203
  //# sourceMappingURL=transaction-pool.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"transaction-pool.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/db/transaction-pool.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"transaction-pool.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/db/transaction-pool.ts"],"names":[],"mappings":"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"}
@@ -22,16 +22,14 @@ var TransactionPool = class {
22
22
  #workers = [];
23
23
  #initialWorkers;
24
24
  #maxWorkers;
25
- #responseTimeout;
26
25
  #timeoutTask;
27
26
  #numWorkers;
28
27
  #numWorking = 0;
29
28
  #db;
30
29
  #done = false;
31
30
  #failure;
32
- #orphanedQueryCheckInterval;
33
31
  constructor(lc, opts, timeoutTasks = TIMEOUT_TASKS) {
34
- const { mode, init, cleanup, initialWorkers = 1, maxWorkers = initialWorkers, statementResponseTimeout } = opts;
32
+ const { mode, init, cleanup, initialWorkers = 1, maxWorkers = initialWorkers } = opts;
35
33
  assert(initialWorkers > 0, "initialWorkers must be positive");
36
34
  assert(maxWorkers >= initialWorkers, "maxWorkers must be >= initialWorkers");
37
35
  this.#lc = lc;
@@ -42,8 +40,6 @@ var TransactionPool = class {
42
40
  this.#numWorkers = initialWorkers;
43
41
  this.#maxWorkers = maxWorkers;
44
42
  this.#timeoutTask = timeoutTasks;
45
- this.#responseTimeout = statementResponseTimeout;
46
- this.#orphanedQueryCheckInterval = setInterval(this.#checkForOrphanedQueries, Math.min(5e3, statementResponseTimeout ?? 5e3));
47
43
  }
48
44
  /**
49
45
  * Starts the pool of workers to process Tasks with transactions opened from the
@@ -159,9 +155,6 @@ var TransactionPool = class {
159
155
  }
160
156
  #start = performance.now();
161
157
  #stmts = 0;
162
- #latestDoneIndex = 0;
163
- #latestDoneTime = 0;
164
- #pending = /* @__PURE__ */ new Map();
165
158
  /**
166
159
  * Implements the semantics specified in {@link process()}.
167
160
  *
@@ -188,69 +181,18 @@ var TransactionPool = class {
188
181
  r.resolve();
189
182
  return { pending: null };
190
183
  }
191
- const time = Date.now();
192
184
  return { pending: stmts.reduce((_, stmt) => {
193
185
  const query = stmt;
194
186
  const index = ++this.#stmts;
195
- const { promise: aborted, reject: abort } = resolver();
196
- aborted.catch(() => {});
197
- this.#pending.set(query, {
198
- index,
199
- time,
200
- abort
201
- });
202
- const responded = stmt.execute().then(() => {
187
+ return stmt.execute().then(() => {
203
188
  if (index % 1e3 === 0) lc[index % 1e4 === 0 ? "info" : "debug"]?.(`executed ${this.#stmts}th statement (${(performance.now() - this.#start).toFixed(3)} ms)`, { statement: query.string });
204
- }).catch((e) => this.fail(e)).finally(() => {
205
- this.#pending.delete(query);
206
- if (index > this.#latestDoneIndex) {
207
- this.#latestDoneIndex = index;
208
- this.#latestDoneTime = Date.now();
209
- }
210
- });
211
- const done = Promise.race([responded, aborted]);
212
- done.catch(() => {});
213
- return done;
189
+ }).catch((e) => this.fail(e));
214
190
  }, promiseVoid).finally(r.resolve) };
215
191
  },
216
192
  rejected: r.resolve
217
193
  };
218
194
  }
219
195
  /**
220
- * Periodically checks the map of `#pending` queries for which Promises
221
- * have yet to be resolved. Checks for pathological scenarios that have
222
- * been observed:
223
- *
224
- * * A promise does not resolve, even though the transaction is otherwise
225
- * healthy with keepalives being sent.
226
- * * A transaction never "finishes" at the postgres.js level after the
227
- * worker exits, implying that postgres.js is awaiting the `last` promise
228
- * returned. In this case Postgres disconnected the application with an
229
- * idle-in-transaction timeout, suggesting that all statements did in
230
- * fact complete.
231
- */
232
- #checkForOrphanedQueries = () => {
233
- if (this.#pending.size === 0) return;
234
- const now = Date.now();
235
- for (const [query, { index, time, abort }] of this.#pending.entries()) {
236
- const statement = query.string;
237
- const abortWith = (msg) => {
238
- this.#lc.warn?.(msg, { statement });
239
- const err = new ResponseTimeoutError(msg);
240
- abort(err);
241
- this.fail(err);
242
- this.#pending.delete(query);
243
- };
244
- if (index < this.#latestDoneIndex) {
245
- const elapsed = now - this.#latestDoneTime;
246
- if (this.#responseTimeout && elapsed > this.#responseTimeout) abortWith(`statement ${this.#latestDoneIndex} completed ${elapsed} ms ago, but statement ${index} has not.`);
247
- } else {
248
- const elapsed = now - time;
249
- if (this.#responseTimeout && elapsed > this.#responseTimeout) abortWith(`response for statement timed out after ${elapsed} ms`);
250
- }
251
- }
252
- };
253
- /**
254
196
  * Processes and returns the result of executing the {@link ReadTask} from
255
197
  * within the transaction. An error thrown by the task will result in
256
198
  * rejecting the returned Promise, but will not affect the transaction pool
@@ -317,7 +259,6 @@ var TransactionPool = class {
317
259
  assert(!this.#done, "already set done");
318
260
  this.#done = true;
319
261
  for (let i = 0; i < this.#numWorkers; i++) this.#tasks.enqueue("done");
320
- Promise.allSettled(this.#workers).then(() => clearInterval(this.#orphanedQueryCheckInterval));
321
262
  }
322
263
  isRunning() {
323
264
  return this.#db !== void 0 && !this.#done && this.#failure === void 0;
@@ -331,19 +272,20 @@ var TransactionPool = class {
331
272
  const level = this.#failure instanceof ControlFlowError ? "debug" : "info";
332
273
  this.#lc[level]?.(this.#failure);
333
274
  for (let i = 0; i < this.#numWorkers; i++) this.#tasks.enqueue(this.#failure);
334
- Promise.allSettled(this.#workers).then(() => clearInterval(this.#orphanedQueryCheckInterval));
335
275
  }
336
276
  }
337
277
  };
338
278
  /**
339
- * @returns An `init` Task for importing a snapshot from another transaction.
279
+ * @returns An `init` Task for importing a snapshot from another transaction,
280
+ * as well as an `imported` Queue which resolves or rejects when each
281
+ * worker is initialized.
340
282
  */
341
283
  function importSnapshot(snapshotID) {
342
- const { promise: imported, resolve, reject } = resolver();
284
+ const imported = new Queue();
343
285
  return {
344
286
  init: (tx) => {
345
287
  const stmt = tx.unsafe(`SET TRANSACTION SNAPSHOT '${snapshotID}'`);
346
- stmt.then(() => resolve(), reject);
288
+ stmt.then(() => imported.enqueue(), (err) => imported.enqueueRejection(err));
347
289
  return [stmt];
348
290
  },
349
291
  imported
@@ -397,12 +339,6 @@ var TIMEOUT_TASKS = {
397
339
  task: "done"
398
340
  }
399
341
  };
400
- var ResponseTimeoutError = class extends Error {
401
- static name = "ResponseTimeoutError";
402
- constructor(msg) {
403
- super(msg);
404
- }
405
- };
406
342
  //#endregion
407
343
  export { TransactionPool, importSnapshot };
408
344