@rocicorp/zero 1.12.0-canary.0 → 1.12.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 (1387) hide show
  1. package/out/_virtual/{_@oxc-project_runtime@0.130.0/helpers → _@oxc-project_runtime@0.154.0/helpers/esm}/usingCtx.js +2 -2
  2. package/out/analyze-query/src/analyze-cli.d.ts.map +1 -1
  3. package/out/analyze-query/src/analyze-cli.js +4 -2
  4. package/out/analyze-query/src/analyze-cli.js.map +1 -1
  5. package/out/analyze-query/src/bin-transform.js +4 -3
  6. package/out/analyze-query/src/bin-transform.js.map +1 -1
  7. package/out/analyze-query/src/zql-chain.d.ts +23 -0
  8. package/out/analyze-query/src/zql-chain.d.ts.map +1 -0
  9. package/out/analyze-query/src/zql-chain.js +162 -0
  10. package/out/analyze-query/src/zql-chain.js.map +1 -0
  11. package/out/ast-to-zql/src/ast-to-zql.js.map +1 -1
  12. package/out/ast-to-zql/src/bin.js +4 -3
  13. package/out/ast-to-zql/src/bin.js.map +1 -1
  14. package/out/ast-to-zql/src/format.js.map +1 -1
  15. package/out/datadog/src/datadog-log-sink.js +5 -4
  16. package/out/datadog/src/datadog-log-sink.js.map +1 -1
  17. package/out/otel/src/log-options.js.map +1 -1
  18. package/out/replicache/src/btree/node.d.ts +0 -2
  19. package/out/replicache/src/btree/node.d.ts.map +1 -1
  20. package/out/replicache/src/btree/node.js +14 -12
  21. package/out/replicache/src/btree/node.js.map +1 -1
  22. package/out/replicache/src/btree/read.js +4 -2
  23. package/out/replicache/src/btree/read.js.map +1 -1
  24. package/out/replicache/src/btree/splice.js.map +1 -1
  25. package/out/replicache/src/btree/write.js +9 -5
  26. package/out/replicache/src/btree/write.js.map +1 -1
  27. package/out/replicache/src/config.js +1 -2
  28. package/out/replicache/src/connection-loop.d.ts.map +1 -1
  29. package/out/replicache/src/connection-loop.js +1 -1
  30. package/out/replicache/src/connection-loop.js.map +1 -1
  31. package/out/replicache/src/dag/chunk.js +1 -1
  32. package/out/replicache/src/dag/gc.js.map +1 -1
  33. package/out/replicache/src/dag/lazy-store.js +8 -7
  34. package/out/replicache/src/dag/lazy-store.js.map +1 -1
  35. package/out/replicache/src/dag/store-impl.js +1 -1
  36. package/out/replicache/src/dag/store-impl.js.map +1 -1
  37. package/out/replicache/src/dag/visitor.js.map +1 -1
  38. package/out/replicache/src/db/commit.d.ts +0 -1
  39. package/out/replicache/src/db/commit.d.ts.map +1 -1
  40. package/out/replicache/src/db/commit.js +5 -3
  41. package/out/replicache/src/db/commit.js.map +1 -1
  42. package/out/replicache/src/db/read.js +1 -1
  43. package/out/replicache/src/db/read.js.map +1 -1
  44. package/out/replicache/src/db/rebase.js.map +1 -1
  45. package/out/replicache/src/db/write.d.ts +0 -2
  46. package/out/replicache/src/db/write.d.ts.map +1 -1
  47. package/out/replicache/src/db/write.js +5 -2
  48. package/out/replicache/src/db/write.js.map +1 -1
  49. package/out/replicache/src/deleted-clients.d.ts +0 -2
  50. package/out/replicache/src/deleted-clients.d.ts.map +1 -1
  51. package/out/replicache/src/deleted-clients.js +5 -3
  52. package/out/replicache/src/deleted-clients.js.map +1 -1
  53. package/out/replicache/src/expo-sqlite.js +1 -2
  54. package/out/replicache/src/frozen-json.d.ts +0 -1
  55. package/out/replicache/src/frozen-json.d.ts.map +1 -1
  56. package/out/replicache/src/frozen-json.js +1 -1
  57. package/out/replicache/src/frozen-json.js.map +1 -1
  58. package/out/replicache/src/get-default-puller.js +1 -1
  59. package/out/replicache/src/hash.js +1 -1
  60. package/out/replicache/src/hash.js.map +1 -1
  61. package/out/replicache/src/impl.js +1 -2
  62. package/out/replicache/src/index-defs.d.ts +0 -2
  63. package/out/replicache/src/index-defs.d.ts.map +1 -1
  64. package/out/replicache/src/index-defs.js +5 -3
  65. package/out/replicache/src/index-defs.js.map +1 -1
  66. package/out/replicache/src/kv/expo-sqlite/store.d.ts +0 -1
  67. package/out/replicache/src/kv/expo-sqlite/store.d.ts.map +1 -1
  68. package/out/replicache/src/kv/expo-sqlite/store.js.map +1 -1
  69. package/out/replicache/src/kv/idb-store.js +2 -2
  70. package/out/replicache/src/kv/idb-store.js.map +1 -1
  71. package/out/replicache/src/kv/mem-fallback-store.js +1 -1
  72. package/out/replicache/src/kv/mem-fallback-store.js.map +1 -1
  73. package/out/replicache/src/kv/mem-store.js.map +1 -1
  74. package/out/replicache/src/kv/op-sqlite/store.js.map +1 -1
  75. package/out/replicache/src/kv/op-sqlite/types.js.map +1 -1
  76. package/out/replicache/src/kv/read-impl.js.map +1 -1
  77. package/out/replicache/src/kv/sqlite-store.d.ts.map +1 -1
  78. package/out/replicache/src/kv/sqlite-store.js +8 -4
  79. package/out/replicache/src/kv/sqlite-store.js.map +1 -1
  80. package/out/replicache/src/kv/throw-if-closed.d.ts +0 -3
  81. package/out/replicache/src/kv/throw-if-closed.d.ts.map +1 -1
  82. package/out/replicache/src/kv/throw-if-closed.js.map +1 -1
  83. package/out/replicache/src/kv/write-impl-base.js +4 -1
  84. package/out/replicache/src/kv/write-impl-base.js.map +1 -1
  85. package/out/replicache/src/kv/write-impl.js.map +1 -1
  86. package/out/replicache/src/log-options.js +2 -1
  87. package/out/replicache/src/log-options.js.map +1 -1
  88. package/out/replicache/src/make-idb-name.js +1 -1
  89. package/out/replicache/src/new-client-channel.js +9 -7
  90. package/out/replicache/src/new-client-channel.js.map +1 -1
  91. package/out/replicache/src/on-persist-channel.js +1 -1
  92. package/out/replicache/src/on-persist-channel.js.map +1 -1
  93. package/out/replicache/src/op-sqlite.js +1 -2
  94. package/out/replicache/src/pending-mutations.js +2 -1
  95. package/out/replicache/src/pending-mutations.js.map +1 -1
  96. package/out/replicache/src/persist/client-gc.js +2 -2
  97. package/out/replicache/src/persist/client-gc.js.map +1 -1
  98. package/out/replicache/src/persist/client-group-gc.d.ts +0 -7
  99. package/out/replicache/src/persist/client-group-gc.d.ts.map +1 -1
  100. package/out/replicache/src/persist/client-group-gc.js +1 -1
  101. package/out/replicache/src/persist/client-group-gc.js.map +1 -1
  102. package/out/replicache/src/persist/client-groups.js +1 -1
  103. package/out/replicache/src/persist/client-groups.js.map +1 -1
  104. package/out/replicache/src/persist/clients.js +1 -1
  105. package/out/replicache/src/persist/clients.js.map +1 -1
  106. package/out/replicache/src/persist/collect-idb-databases.js +5 -4
  107. package/out/replicache/src/persist/collect-idb-databases.js.map +1 -1
  108. package/out/replicache/src/persist/gather-mem-only-visitor.js.map +1 -1
  109. package/out/replicache/src/persist/gather-not-cached-visitor.js.map +1 -1
  110. package/out/replicache/src/persist/heartbeat.js +2 -2
  111. package/out/replicache/src/persist/heartbeat.js.map +1 -1
  112. package/out/replicache/src/persist/idb-databases-store.js +1 -1
  113. package/out/replicache/src/persist/idb-databases-store.js.map +1 -1
  114. package/out/replicache/src/persist/make-client-id.js +1 -1
  115. package/out/replicache/src/persist/make-client-id.js.map +1 -1
  116. package/out/replicache/src/persist/persist.js +3 -2
  117. package/out/replicache/src/persist/persist.js.map +1 -1
  118. package/out/replicache/src/persist/refresh.js +8 -5
  119. package/out/replicache/src/persist/refresh.js.map +1 -1
  120. package/out/replicache/src/process-scheduler.js +1 -1
  121. package/out/replicache/src/process-scheduler.js.map +1 -1
  122. package/out/replicache/src/replicache-impl.d.ts +2 -7
  123. package/out/replicache/src/replicache-impl.d.ts.map +1 -1
  124. package/out/replicache/src/replicache-impl.js +21 -18
  125. package/out/replicache/src/replicache-impl.js.map +1 -1
  126. package/out/replicache/src/scan-iterator.js.map +1 -1
  127. package/out/replicache/src/scan-options.js +7 -6
  128. package/out/replicache/src/scan-options.js.map +1 -1
  129. package/out/replicache/src/sqlite.js +1 -2
  130. package/out/replicache/src/subscriptions.js +1 -1
  131. package/out/replicache/src/subscriptions.js.map +1 -1
  132. package/out/replicache/src/sync/diff.js +3 -1
  133. package/out/replicache/src/sync/diff.js.map +1 -1
  134. package/out/replicache/src/sync/ids.js.map +1 -1
  135. package/out/replicache/src/sync/patch.d.ts +0 -5
  136. package/out/replicache/src/sync/patch.d.ts.map +1 -1
  137. package/out/replicache/src/sync/patch.js +2 -4
  138. package/out/replicache/src/sync/patch.js.map +1 -1
  139. package/out/replicache/src/sync/pull.d.ts +0 -1
  140. package/out/replicache/src/sync/pull.d.ts.map +1 -1
  141. package/out/replicache/src/sync/pull.js +3 -1
  142. package/out/replicache/src/sync/pull.js.map +1 -1
  143. package/out/replicache/src/sync/push.d.ts +2 -1
  144. package/out/replicache/src/sync/push.d.ts.map +1 -1
  145. package/out/replicache/src/sync/push.js.map +1 -1
  146. package/out/replicache/src/sync/request-id.js +1 -1
  147. package/out/replicache/src/sync/request-id.js.map +1 -1
  148. package/out/replicache/src/transactions.js +1 -1
  149. package/out/replicache/src/transactions.js.map +1 -1
  150. package/out/replicache/src/types.d.ts +2 -1
  151. package/out/replicache/src/types.d.ts.map +1 -1
  152. package/out/shared/src/arrays.js +4 -1
  153. package/out/shared/src/arrays.js.map +1 -1
  154. package/out/shared/src/asserts.d.ts +0 -5
  155. package/out/shared/src/asserts.d.ts.map +1 -1
  156. package/out/shared/src/asserts.js.map +1 -1
  157. package/out/shared/src/bigint-json.d.ts +9 -0
  158. package/out/shared/src/bigint-json.d.ts.map +1 -1
  159. package/out/shared/src/bigint-json.js +27 -2
  160. package/out/shared/src/bigint-json.js.map +1 -1
  161. package/out/shared/src/broadcast-channel.js +1 -1
  162. package/out/shared/src/browser-env.d.ts +0 -17
  163. package/out/shared/src/browser-env.d.ts.map +1 -1
  164. package/out/shared/src/browser-env.js.map +1 -1
  165. package/out/shared/src/btree-set.js +11 -8
  166. package/out/shared/src/btree-set.js.map +1 -1
  167. package/out/shared/src/cache.js.map +1 -1
  168. package/out/shared/src/config.js +1 -1
  169. package/out/shared/src/custom-key-map.js.map +1 -1
  170. package/out/shared/src/custom-key-set.js.map +1 -1
  171. package/out/shared/src/deep-clone.d.ts +0 -1
  172. package/out/shared/src/deep-clone.d.ts.map +1 -1
  173. package/out/shared/src/deep-clone.js.map +1 -1
  174. package/out/shared/src/document-visible.js +1 -1
  175. package/out/shared/src/document-visible.js.map +1 -1
  176. package/out/shared/src/dotenv.js.map +1 -1
  177. package/out/shared/src/error.js +1 -1
  178. package/out/shared/src/error.js.map +1 -1
  179. package/out/shared/src/expand.d.ts +0 -3
  180. package/out/shared/src/expand.d.ts.map +1 -1
  181. package/out/shared/src/hash.js +2 -2
  182. package/out/shared/src/hash.js.map +1 -1
  183. package/out/shared/src/immutable.d.ts +1 -1
  184. package/out/shared/src/immutable.d.ts.map +1 -1
  185. package/out/shared/src/iterables.d.ts +0 -1
  186. package/out/shared/src/iterables.d.ts.map +1 -1
  187. package/out/shared/src/iterables.js.map +1 -1
  188. package/out/shared/src/json-schema.js.map +1 -1
  189. package/out/shared/src/json.js.map +1 -1
  190. package/out/shared/src/logging-test-utils.js.map +1 -1
  191. package/out/shared/src/logging.js +1 -1
  192. package/out/shared/src/logging.js.map +1 -1
  193. package/out/shared/src/navigator.js +1 -1
  194. package/out/shared/src/options-types.d.ts +1 -1
  195. package/out/shared/src/options-types.d.ts.map +1 -1
  196. package/out/shared/src/options.d.ts +2 -3
  197. package/out/shared/src/options.d.ts.map +1 -1
  198. package/out/shared/src/options.js +8 -11
  199. package/out/shared/src/options.js.map +1 -1
  200. package/out/shared/src/promise-race.js +1 -1
  201. package/out/shared/src/promise-race.js.map +1 -1
  202. package/out/shared/src/queue.js +1 -1
  203. package/out/shared/src/queue.js.map +1 -1
  204. package/out/shared/src/record-proxy.js.map +1 -1
  205. package/out/shared/src/resolved-promises.d.ts +0 -4
  206. package/out/shared/src/resolved-promises.d.ts.map +1 -1
  207. package/out/shared/src/resolved-promises.js +0 -1
  208. package/out/shared/src/resolved-promises.js.map +1 -1
  209. package/out/shared/src/resolver.d.ts +9 -0
  210. package/out/shared/src/resolver.d.ts.map +1 -0
  211. package/out/shared/src/resolver.js +6 -0
  212. package/out/shared/src/resolver.js.map +1 -0
  213. package/out/shared/src/ring-buffer.js.map +1 -1
  214. package/out/shared/src/size-of-value.js +7 -10
  215. package/out/shared/src/size-of-value.js.map +1 -1
  216. package/out/shared/src/sleep.js +1 -1
  217. package/out/shared/src/sleep.js.map +1 -1
  218. package/out/shared/src/sorted-entries.js.map +1 -1
  219. package/out/shared/src/tdigest-schema.js.map +1 -1
  220. package/out/shared/src/tdigest.d.ts +0 -1
  221. package/out/shared/src/tdigest.d.ts.map +1 -1
  222. package/out/shared/src/tdigest.js.map +1 -1
  223. package/out/shared/src/valita.js +1 -1
  224. package/out/shared/src/valita.js.map +1 -1
  225. package/out/z2s/src/compiler.js +5 -7
  226. package/out/z2s/src/compiler.js.map +1 -1
  227. package/out/z2s/src/sql.d.ts +1 -5
  228. package/out/z2s/src/sql.d.ts.map +1 -1
  229. package/out/z2s/src/sql.js +1 -1
  230. package/out/z2s/src/sql.js.map +1 -1
  231. package/out/zero/package.js +210 -189
  232. package/out/zero/package.js.map +1 -1
  233. package/out/zero/src/adapters/drizzle.js +1 -2
  234. package/out/zero/src/adapters/kysely.js +1 -2
  235. package/out/zero/src/adapters/pg.js +1 -2
  236. package/out/zero/src/adapters/postgresjs.js +1 -2
  237. package/out/zero/src/adapters/prisma.js +1 -2
  238. package/out/zero/src/analyze.js +1 -2
  239. package/out/zero/src/change-protocol/v0.js +1 -2
  240. package/out/zero/src/expo-sqlite.js +1 -2
  241. package/out/zero/src/op-sqlite.js +1 -2
  242. package/out/zero/src/react-native.js.map +1 -1
  243. package/out/zero/src/sqlite.js +1 -2
  244. package/out/zero/src/zero-cache-dev.js +11 -10
  245. package/out/zero/src/zero-cache-dev.js.map +1 -1
  246. package/out/zero/src/zero-out.js +2 -1
  247. package/out/zero/src/zero-out.js.map +1 -1
  248. package/out/zero-cache/src/auth/auth.js +1 -1
  249. package/out/zero-cache/src/auth/auth.js.map +1 -1
  250. package/out/zero-cache/src/auth/jwt.js +4 -1
  251. package/out/zero-cache/src/auth/jwt.js.map +1 -1
  252. package/out/zero-cache/src/auth/load-permissions.js +1 -1
  253. package/out/zero-cache/src/auth/load-permissions.js.map +1 -1
  254. package/out/zero-cache/src/auth/read-authorizer.js +3 -2
  255. package/out/zero-cache/src/auth/read-authorizer.js.map +1 -1
  256. package/out/zero-cache/src/auth/write-authorizer.js +15 -19
  257. package/out/zero-cache/src/auth/write-authorizer.js.map +1 -1
  258. package/out/zero-cache/src/config/network.js +1 -1
  259. package/out/zero-cache/src/config/network.js.map +1 -1
  260. package/out/zero-cache/src/config/server-context.js.map +1 -1
  261. package/out/zero-cache/src/config/zero-config.d.ts +19 -11
  262. package/out/zero-cache/src/config/zero-config.d.ts.map +1 -1
  263. package/out/zero-cache/src/config/zero-config.js +47 -10
  264. package/out/zero-cache/src/config/zero-config.js.map +1 -1
  265. package/out/zero-cache/src/custom/fetch.js +1 -1
  266. package/out/zero-cache/src/custom/fetch.js.map +1 -1
  267. package/out/zero-cache/src/custom-queries/transform-query.js.map +1 -1
  268. package/out/zero-cache/src/db/create.js.map +1 -1
  269. package/out/zero-cache/src/db/index-predicate.js.map +1 -1
  270. package/out/zero-cache/src/db/lite-tables.d.ts +2 -2
  271. package/out/zero-cache/src/db/lite-tables.d.ts.map +1 -1
  272. package/out/zero-cache/src/db/lite-tables.js.map +1 -1
  273. package/out/zero-cache/src/db/migration-lite.js +1 -1
  274. package/out/zero-cache/src/db/migration-lite.js.map +1 -1
  275. package/out/zero-cache/src/db/migration.js +5 -3
  276. package/out/zero-cache/src/db/migration.js.map +1 -1
  277. package/out/zero-cache/src/db/pg-copy-binary.js +4 -3
  278. package/out/zero-cache/src/db/pg-copy-binary.js.map +1 -1
  279. package/out/zero-cache/src/db/pg-copy.js +0 -1
  280. package/out/zero-cache/src/db/pg-copy.js.map +1 -1
  281. package/out/zero-cache/src/db/pg-to-lite.js +1 -1
  282. package/out/zero-cache/src/db/pg-to-lite.js.map +1 -1
  283. package/out/zero-cache/src/db/pg-type-parser.js.map +1 -1
  284. package/out/zero-cache/src/db/run-transaction.js.map +1 -1
  285. package/out/zero-cache/src/db/specs.d.ts +3 -4
  286. package/out/zero-cache/src/db/specs.d.ts.map +1 -1
  287. package/out/zero-cache/src/db/specs.js +1 -1
  288. package/out/zero-cache/src/db/specs.js.map +1 -1
  289. package/out/zero-cache/src/db/sqlite-corruption.js.map +1 -1
  290. package/out/zero-cache/src/db/statements.d.ts.map +1 -1
  291. package/out/zero-cache/src/db/statements.js +9 -2
  292. package/out/zero-cache/src/db/statements.js.map +1 -1
  293. package/out/zero-cache/src/db/transaction-pool.js +6 -4
  294. package/out/zero-cache/src/db/transaction-pool.js.map +1 -1
  295. package/out/zero-cache/src/db/warmup.js.map +1 -1
  296. package/out/zero-cache/src/observability/events.js +1 -1
  297. package/out/zero-cache/src/observability/events.js.map +1 -1
  298. package/out/zero-cache/src/observability/log-throttle.js.map +1 -1
  299. package/out/zero-cache/src/observability/metrics.js.map +1 -1
  300. package/out/zero-cache/src/scripts/decommission.js +1 -1
  301. package/out/zero-cache/src/scripts/deploy-permissions.js +5 -3
  302. package/out/zero-cache/src/scripts/deploy-permissions.js.map +1 -1
  303. package/out/zero-cache/src/scripts/permissions.js.map +1 -1
  304. package/out/zero-cache/src/server/anonymous-otel-start.js +2 -1
  305. package/out/zero-cache/src/server/anonymous-otel-start.js.map +1 -1
  306. package/out/zero-cache/src/server/change-streamer.js +49 -16
  307. package/out/zero-cache/src/server/change-streamer.js.map +1 -1
  308. package/out/zero-cache/src/server/inspector-delegate.js.map +1 -1
  309. package/out/zero-cache/src/server/logging.js +1 -1
  310. package/out/zero-cache/src/server/logging.js.map +1 -1
  311. package/out/zero-cache/src/server/main.js +2 -2
  312. package/out/zero-cache/src/server/main.js.map +1 -1
  313. package/out/zero-cache/src/server/otel-log-sink.js.map +1 -1
  314. package/out/zero-cache/src/server/otel-start.js.map +1 -1
  315. package/out/zero-cache/src/server/reaper.js +2 -2
  316. package/out/zero-cache/src/server/reaper.js.map +1 -1
  317. package/out/zero-cache/src/server/replicator.js +1 -1
  318. package/out/zero-cache/src/server/replicator.js.map +1 -1
  319. package/out/zero-cache/src/server/runner/run-worker.d.ts.map +1 -1
  320. package/out/zero-cache/src/server/runner/run-worker.js +4 -3
  321. package/out/zero-cache/src/server/runner/run-worker.js.map +1 -1
  322. package/out/zero-cache/src/server/runner/runtime.js +2 -1
  323. package/out/zero-cache/src/server/runner/runtime.js.map +1 -1
  324. package/out/zero-cache/src/server/runner/zero-dispatcher.d.ts +9 -1
  325. package/out/zero-cache/src/server/runner/zero-dispatcher.d.ts.map +1 -1
  326. package/out/zero-cache/src/server/runner/zero-dispatcher.js +29 -2
  327. package/out/zero-cache/src/server/runner/zero-dispatcher.js.map +1 -1
  328. package/out/zero-cache/src/server/shadow-syncer.js +1 -1
  329. package/out/zero-cache/src/server/shadow-syncer.js.map +1 -1
  330. package/out/zero-cache/src/server/slot-keeper.js.map +1 -1
  331. package/out/zero-cache/src/server/syncer-assigner.js.map +1 -1
  332. package/out/zero-cache/src/server/syncer.js +10 -5
  333. package/out/zero-cache/src/server/syncer.js.map +1 -1
  334. package/out/zero-cache/src/server/worker-dispatcher.js +1 -1
  335. package/out/zero-cache/src/server/worker-dispatcher.js.map +1 -1
  336. package/out/zero-cache/src/server/worker-urls.js.map +1 -1
  337. package/out/zero-cache/src/services/analyze.js +2 -2
  338. package/out/zero-cache/src/services/analyze.js.map +1 -1
  339. package/out/zero-cache/src/services/change-source/common/backfill-manager.js +3 -3
  340. package/out/zero-cache/src/services/change-source/common/backfill-manager.js.map +1 -1
  341. package/out/zero-cache/src/services/change-source/common/change-stream-multiplexer.js +1 -1
  342. package/out/zero-cache/src/services/change-source/common/change-stream-multiplexer.js.map +1 -1
  343. package/out/zero-cache/src/services/change-source/common/init-cleanup.js.map +1 -1
  344. package/out/zero-cache/src/services/change-source/common/replica-restore.js.map +1 -1
  345. package/out/zero-cache/src/services/change-source/common/replica-schema.js +4 -4
  346. package/out/zero-cache/src/services/change-source/common/replica-schema.js.map +1 -1
  347. package/out/zero-cache/src/services/change-source/custom/change-source.js +1 -1
  348. package/out/zero-cache/src/services/change-source/custom/change-source.js.map +1 -1
  349. package/out/zero-cache/src/services/change-source/pg/backfill-metadata.js.map +1 -1
  350. package/out/zero-cache/src/services/change-source/pg/backfill-stream.js +4 -4
  351. package/out/zero-cache/src/services/change-source/pg/backfill-stream.js.map +1 -1
  352. package/out/zero-cache/src/services/change-source/pg/change-source-init.js +52 -27
  353. package/out/zero-cache/src/services/change-source/pg/change-source-init.js.map +1 -1
  354. package/out/zero-cache/src/services/change-source/pg/change-source.js +70 -15
  355. package/out/zero-cache/src/services/change-source/pg/change-source.js.map +1 -1
  356. package/out/zero-cache/src/services/change-source/pg/decommission.js +2 -1
  357. package/out/zero-cache/src/services/change-source/pg/decommission.js.map +1 -1
  358. package/out/zero-cache/src/services/change-source/pg/fork-request.js +54 -0
  359. package/out/zero-cache/src/services/change-source/pg/fork-request.js.map +1 -0
  360. package/out/zero-cache/src/services/change-source/pg/initial-sync.js +9 -7
  361. package/out/zero-cache/src/services/change-source/pg/initial-sync.js.map +1 -1
  362. package/out/zero-cache/src/services/change-source/pg/logical-replication/binary-reader.js.map +1 -1
  363. package/out/zero-cache/src/services/change-source/pg/logical-replication/pgoutput-parser.js.map +1 -1
  364. package/out/zero-cache/src/services/change-source/pg/logical-replication/stream.js +5 -4
  365. package/out/zero-cache/src/services/change-source/pg/logical-replication/stream.js.map +1 -1
  366. package/out/zero-cache/src/services/change-source/pg/lsn.d.ts +0 -2
  367. package/out/zero-cache/src/services/change-source/pg/lsn.d.ts.map +1 -1
  368. package/out/zero-cache/src/services/change-source/pg/lsn.js.map +1 -1
  369. package/out/zero-cache/src/services/change-source/pg/replication-slot-cleanup-monitor.js +2 -2
  370. package/out/zero-cache/src/services/change-source/pg/replication-slot-cleanup-monitor.js.map +1 -1
  371. package/out/zero-cache/src/services/change-source/pg/replication-slot-health.js +1 -1
  372. package/out/zero-cache/src/services/change-source/pg/replication-slot-health.js.map +1 -1
  373. package/out/zero-cache/src/services/change-source/pg/replication-slots.js +9 -3
  374. package/out/zero-cache/src/services/change-source/pg/replication-slots.js.map +1 -1
  375. package/out/zero-cache/src/services/change-source/pg/schema/ddl.d.ts +0 -12
  376. package/out/zero-cache/src/services/change-source/pg/schema/ddl.d.ts.map +1 -1
  377. package/out/zero-cache/src/services/change-source/pg/schema/ddl.js +6 -4
  378. package/out/zero-cache/src/services/change-source/pg/schema/ddl.js.map +1 -1
  379. package/out/zero-cache/src/services/change-source/pg/schema/index-predicate.d.ts +1 -1
  380. package/out/zero-cache/src/services/change-source/pg/schema/index-predicate.d.ts.map +1 -1
  381. package/out/zero-cache/src/services/change-source/pg/schema/index-predicate.js +13 -12
  382. package/out/zero-cache/src/services/change-source/pg/schema/index-predicate.js.map +1 -1
  383. package/out/zero-cache/src/services/change-source/pg/schema/init.js +1 -1
  384. package/out/zero-cache/src/services/change-source/pg/schema/init.js.map +1 -1
  385. package/out/zero-cache/src/services/change-source/pg/schema/published.js +2 -2
  386. package/out/zero-cache/src/services/change-source/pg/schema/published.js.map +1 -1
  387. package/out/zero-cache/src/services/change-source/pg/schema/replica-stage-enum.js.map +1 -1
  388. package/out/zero-cache/src/services/change-source/pg/schema/shard.js +10 -7
  389. package/out/zero-cache/src/services/change-source/pg/schema/shard.js.map +1 -1
  390. package/out/zero-cache/src/services/change-source/pg/schema/validation.d.ts +0 -1
  391. package/out/zero-cache/src/services/change-source/pg/schema/validation.d.ts.map +1 -1
  392. package/out/zero-cache/src/services/change-source/pg/schema/validation.js +1 -1
  393. package/out/zero-cache/src/services/change-source/pg/schema/validation.js.map +1 -1
  394. package/out/zero-cache/src/services/change-source/protocol/backfill-progress.js +1 -1
  395. package/out/zero-cache/src/services/change-source/protocol/backfill-progress.js.map +1 -1
  396. package/out/zero-cache/src/services/change-source/protocol/current/control.js.map +1 -1
  397. package/out/zero-cache/src/services/change-source/protocol/current/data.js.map +1 -1
  398. package/out/zero-cache/src/services/change-source/protocol/current/downstream.d.ts +1 -0
  399. package/out/zero-cache/src/services/change-source/protocol/current/downstream.d.ts.map +1 -1
  400. package/out/zero-cache/src/services/change-source/protocol/current/downstream.js.map +1 -1
  401. package/out/zero-cache/src/services/change-source/protocol/current/status.d.ts +3 -0
  402. package/out/zero-cache/src/services/change-source/protocol/current/status.d.ts.map +1 -1
  403. package/out/zero-cache/src/services/change-source/protocol/current/status.js +2 -1
  404. package/out/zero-cache/src/services/change-source/protocol/current/status.js.map +1 -1
  405. package/out/zero-cache/src/services/change-source/protocol/current/upstream.d.ts +1 -0
  406. package/out/zero-cache/src/services/change-source/protocol/current/upstream.d.ts.map +1 -1
  407. package/out/zero-cache/src/services/change-source/protocol/current/upstream.js.map +1 -1
  408. package/out/zero-cache/src/services/change-source/protocol/current.js +1 -1
  409. package/out/zero-cache/src/services/change-source/protocol/mod.js +1 -2
  410. package/out/zero-cache/src/services/change-streamer/backfill-state-tracker.js.map +1 -1
  411. package/out/zero-cache/src/services/change-streamer/backfill-state.js +1 -1
  412. package/out/zero-cache/src/services/change-streamer/backfill-state.js.map +1 -1
  413. package/out/zero-cache/src/services/change-streamer/backup-cleanup-monitor-factory.js +6 -6
  414. package/out/zero-cache/src/services/change-streamer/backup-cleanup-monitor-factory.js.map +1 -1
  415. package/out/zero-cache/src/services/change-streamer/backup-monitor.js +56 -21
  416. package/out/zero-cache/src/services/change-streamer/backup-monitor.js.map +1 -1
  417. package/out/zero-cache/src/services/change-streamer/broadcast.js +2 -2
  418. package/out/zero-cache/src/services/change-streamer/broadcast.js.map +1 -1
  419. package/out/zero-cache/src/services/change-streamer/change-log-codec.js +2 -3
  420. package/out/zero-cache/src/services/change-streamer/change-log-codec.js.map +1 -1
  421. package/out/zero-cache/src/services/change-streamer/change-log-initializer.js +3 -3
  422. package/out/zero-cache/src/services/change-streamer/change-log-initializer.js.map +1 -1
  423. package/out/zero-cache/src/services/change-streamer/change-log-transaction-hash.js.map +1 -1
  424. package/out/zero-cache/src/services/change-streamer/change-streamer-http.js +8 -4
  425. package/out/zero-cache/src/services/change-streamer/change-streamer-http.js.map +1 -1
  426. package/out/zero-cache/src/services/change-streamer/change-streamer-service.js +85 -59
  427. package/out/zero-cache/src/services/change-streamer/change-streamer-service.js.map +1 -1
  428. package/out/zero-cache/src/services/change-streamer/change-streamer.js.map +1 -1
  429. package/out/zero-cache/src/services/change-streamer/drain-tracker.js +1 -1
  430. package/out/zero-cache/src/services/change-streamer/drain-tracker.js.map +1 -1
  431. package/out/zero-cache/src/services/change-streamer/forwarder.js +11 -10
  432. package/out/zero-cache/src/services/change-streamer/forwarder.js.map +1 -1
  433. package/out/zero-cache/src/services/change-streamer/litestream-sync-requester.js +81 -12
  434. package/out/zero-cache/src/services/change-streamer/litestream-sync-requester.js.map +1 -1
  435. package/out/zero-cache/src/services/change-streamer/litestream3-prometheus-poller.js +4 -4
  436. package/out/zero-cache/src/services/change-streamer/litestream3-prometheus-poller.js.map +1 -1
  437. package/out/zero-cache/src/services/change-streamer/replica-poller.js +2 -2
  438. package/out/zero-cache/src/services/change-streamer/replica-poller.js.map +1 -1
  439. package/out/zero-cache/src/services/change-streamer/restore-admission.js +12 -1
  440. package/out/zero-cache/src/services/change-streamer/restore-admission.js.map +1 -1
  441. package/out/zero-cache/src/services/change-streamer/schema/init.js +1 -1
  442. package/out/zero-cache/src/services/change-streamer/schema/init.js.map +1 -1
  443. package/out/zero-cache/src/services/change-streamer/schema/tables.js +1 -1
  444. package/out/zero-cache/src/services/change-streamer/schema/tables.js.map +1 -1
  445. package/out/zero-cache/src/services/change-streamer/server-start-metrics.js +42 -0
  446. package/out/zero-cache/src/services/change-streamer/server-start-metrics.js.map +1 -0
  447. package/out/zero-cache/src/services/change-streamer/snapshot-message.js +1 -2
  448. package/out/zero-cache/src/services/change-streamer/snapshot-message.js.map +1 -1
  449. package/out/zero-cache/src/services/change-streamer/snapshot-reservations.js.map +1 -1
  450. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-catchup.js +2 -2
  451. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-catchup.js.map +1 -1
  452. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-comparator.js +2 -2
  453. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-comparator.js.map +1 -1
  454. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-purge-scheduler.js.map +1 -1
  455. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-read-router.js.map +1 -1
  456. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-reader.js +4 -6
  457. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-reader.js.map +1 -1
  458. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-writer.js +3 -5
  459. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-writer.js.map +1 -1
  460. package/out/zero-cache/src/services/change-streamer/storer.js +4 -4
  461. package/out/zero-cache/src/services/change-streamer/storer.js.map +1 -1
  462. package/out/zero-cache/src/services/change-streamer/subscribe.js.map +1 -1
  463. package/out/zero-cache/src/services/change-streamer/subscriber.js +8 -7
  464. package/out/zero-cache/src/services/change-streamer/subscriber.js.map +1 -1
  465. package/out/zero-cache/src/services/change-streamer/upstream-acker.js +0 -1
  466. package/out/zero-cache/src/services/change-streamer/upstream-acker.js.map +1 -1
  467. package/out/zero-cache/src/services/heapz.js +2 -1
  468. package/out/zero-cache/src/services/heapz.js.map +1 -1
  469. package/out/zero-cache/src/services/http-service.d.ts +2 -2
  470. package/out/zero-cache/src/services/http-service.d.ts.map +1 -1
  471. package/out/zero-cache/src/services/http-service.js +6 -4
  472. package/out/zero-cache/src/services/http-service.js.map +1 -1
  473. package/out/zero-cache/src/services/life-cycle.js +3 -3
  474. package/out/zero-cache/src/services/life-cycle.js.map +1 -1
  475. package/out/zero-cache/src/services/limiter/sliding-window-limiter.js +4 -2
  476. package/out/zero-cache/src/services/limiter/sliding-window-limiter.js.map +1 -1
  477. package/out/zero-cache/src/services/litestream/commands.js +4 -4
  478. package/out/zero-cache/src/services/litestream/commands.js.map +1 -1
  479. package/out/zero-cache/src/services/litestream/litestream-checkpointer.js +2 -2
  480. package/out/zero-cache/src/services/litestream/litestream-checkpointer.js.map +1 -1
  481. package/out/zero-cache/src/services/litestream/litestream-controller.js.map +1 -1
  482. package/out/zero-cache/src/services/litestream/metrics.js.map +1 -1
  483. package/out/zero-cache/src/services/litestream/restore-progress.js.map +1 -1
  484. package/out/zero-cache/src/services/mutagen/mutagen.js +3 -4
  485. package/out/zero-cache/src/services/mutagen/mutagen.js.map +1 -1
  486. package/out/zero-cache/src/services/mutagen/pusher.js +61 -17
  487. package/out/zero-cache/src/services/mutagen/pusher.js.map +1 -1
  488. package/out/zero-cache/src/services/plannerz.d.ts +4 -12
  489. package/out/zero-cache/src/services/plannerz.d.ts.map +1 -1
  490. package/out/zero-cache/src/services/plannerz.js +6 -7
  491. package/out/zero-cache/src/services/plannerz.js.map +1 -1
  492. package/out/zero-cache/src/services/profz.js +5 -3
  493. package/out/zero-cache/src/services/profz.js.map +1 -1
  494. package/out/zero-cache/src/services/replicator/change-log-cookies.js.map +1 -1
  495. package/out/zero-cache/src/services/replicator/change-log-db.js +4 -3
  496. package/out/zero-cache/src/services/replicator/change-log-db.js.map +1 -1
  497. package/out/zero-cache/src/services/replicator/change-log-stream-writer.js.map +1 -1
  498. package/out/zero-cache/src/services/replicator/change-processor.js.map +1 -1
  499. package/out/zero-cache/src/services/replicator/drain-handler.js +1 -1
  500. package/out/zero-cache/src/services/replicator/drain-handler.js.map +1 -1
  501. package/out/zero-cache/src/services/replicator/incremental-sync.js +4 -4
  502. package/out/zero-cache/src/services/replicator/incremental-sync.js.map +1 -1
  503. package/out/zero-cache/src/services/replicator/notifier.js.map +1 -1
  504. package/out/zero-cache/src/services/replicator/replication-status.js +4 -3
  505. package/out/zero-cache/src/services/replicator/replication-status.js.map +1 -1
  506. package/out/zero-cache/src/services/replicator/replicator.js.map +1 -1
  507. package/out/zero-cache/src/services/replicator/reporter/recorder.js +2 -2
  508. package/out/zero-cache/src/services/replicator/reporter/recorder.js.map +1 -1
  509. package/out/zero-cache/src/services/replicator/reporter/report-schema.d.ts +2 -11
  510. package/out/zero-cache/src/services/replicator/reporter/report-schema.d.ts.map +1 -1
  511. package/out/zero-cache/src/services/replicator/reporter/report-schema.js.map +1 -1
  512. package/out/zero-cache/src/services/replicator/schema/backfilling.js +2 -2
  513. package/out/zero-cache/src/services/replicator/schema/backfilling.js.map +1 -1
  514. package/out/zero-cache/src/services/replicator/schema/change-log.d.ts +19 -17
  515. package/out/zero-cache/src/services/replicator/schema/change-log.d.ts.map +1 -1
  516. package/out/zero-cache/src/services/replicator/schema/change-log.js +31 -15
  517. package/out/zero-cache/src/services/replicator/schema/change-log.js.map +1 -1
  518. package/out/zero-cache/src/services/replicator/schema/column-metadata.d.ts +0 -7
  519. package/out/zero-cache/src/services/replicator/schema/column-metadata.d.ts.map +1 -1
  520. package/out/zero-cache/src/services/replicator/schema/column-metadata.js +1 -1
  521. package/out/zero-cache/src/services/replicator/schema/column-metadata.js.map +1 -1
  522. package/out/zero-cache/src/services/replicator/schema/replication-state.js +10 -7
  523. package/out/zero-cache/src/services/replicator/schema/replication-state.js.map +1 -1
  524. package/out/zero-cache/src/services/replicator/schema/table-metadata.js.map +1 -1
  525. package/out/zero-cache/src/services/replicator/sqlite-change-log-observability.js +1 -1
  526. package/out/zero-cache/src/services/replicator/sqlite-change-log-observability.js.map +1 -1
  527. package/out/zero-cache/src/services/replicator/sqlite-change-log-purger.js +1 -1
  528. package/out/zero-cache/src/services/replicator/sqlite-change-log-purger.js.map +1 -1
  529. package/out/zero-cache/src/services/replicator/write-worker-client.js +2 -2
  530. package/out/zero-cache/src/services/replicator/write-worker-client.js.map +1 -1
  531. package/out/zero-cache/src/services/replicator/write-worker.js +3 -3
  532. package/out/zero-cache/src/services/replicator/write-worker.js.map +1 -1
  533. package/out/zero-cache/src/services/run-ast.js +1 -1
  534. package/out/zero-cache/src/services/run-ast.js.map +1 -1
  535. package/out/zero-cache/src/services/runner.js.map +1 -1
  536. package/out/zero-cache/src/services/running-state.js +1 -1
  537. package/out/zero-cache/src/services/running-state.js.map +1 -1
  538. package/out/zero-cache/src/services/shadow-sync/shadow-sync-service.js.map +1 -1
  539. package/out/zero-cache/src/services/statz.d.ts.map +1 -1
  540. package/out/zero-cache/src/services/statz.js +5 -4
  541. package/out/zero-cache/src/services/statz.js.map +1 -1
  542. package/out/zero-cache/src/services/view-syncer/active-users-gauge.js +2 -2
  543. package/out/zero-cache/src/services/view-syncer/active-users-gauge.js.map +1 -1
  544. package/out/zero-cache/src/services/view-syncer/advancement-metrics.js.map +1 -1
  545. package/out/zero-cache/src/services/view-syncer/batch-pacer.js.map +1 -1
  546. package/out/zero-cache/src/services/view-syncer/client-handler.js +71 -24
  547. package/out/zero-cache/src/services/view-syncer/client-handler.js.map +1 -1
  548. package/out/zero-cache/src/services/view-syncer/client-schema.js +46 -6
  549. package/out/zero-cache/src/services/view-syncer/client-schema.js.map +1 -1
  550. package/out/zero-cache/src/services/view-syncer/connection-context-manager.js.map +1 -1
  551. package/out/zero-cache/src/services/view-syncer/cvr-purger.js +2 -2
  552. package/out/zero-cache/src/services/view-syncer/cvr-purger.js.map +1 -1
  553. package/out/zero-cache/src/services/view-syncer/cvr-store.js +12 -7
  554. package/out/zero-cache/src/services/view-syncer/cvr-store.js.map +1 -1
  555. package/out/zero-cache/src/services/view-syncer/cvr.js +12 -4
  556. package/out/zero-cache/src/services/view-syncer/cvr.js.map +1 -1
  557. package/out/zero-cache/src/services/view-syncer/deferred-writes-budget.js +1 -1
  558. package/out/zero-cache/src/services/view-syncer/deferred-writes-budget.js.map +1 -1
  559. package/out/zero-cache/src/services/view-syncer/drain-coordinator.js +2 -2
  560. package/out/zero-cache/src/services/view-syncer/drain-coordinator.js.map +1 -1
  561. package/out/zero-cache/src/services/view-syncer/e2e-serving-lag.js.map +1 -1
  562. package/out/zero-cache/src/services/view-syncer/hydration-budget.js.map +1 -1
  563. package/out/zero-cache/src/services/view-syncer/hydration-circuit-breaker.js +2 -2
  564. package/out/zero-cache/src/services/view-syncer/hydration-circuit-breaker.js.map +1 -1
  565. package/out/zero-cache/src/services/view-syncer/inspect-handler.js +6 -4
  566. package/out/zero-cache/src/services/view-syncer/inspect-handler.js.map +1 -1
  567. package/out/zero-cache/src/services/view-syncer/pipeline-driver.js +13 -10
  568. package/out/zero-cache/src/services/view-syncer/pipeline-driver.js.map +1 -1
  569. package/out/zero-cache/src/services/view-syncer/plan-warnings.js.map +1 -1
  570. package/out/zero-cache/src/services/view-syncer/push-cost.js.map +1 -1
  571. package/out/zero-cache/src/services/view-syncer/push-cutoff.js.map +1 -1
  572. package/out/zero-cache/src/services/view-syncer/query-covering.js.map +1 -1
  573. package/out/zero-cache/src/services/view-syncer/query-shape.js.map +1 -1
  574. package/out/zero-cache/src/services/view-syncer/query-stats.js +1 -1
  575. package/out/zero-cache/src/services/view-syncer/query-stats.js.map +1 -1
  576. package/out/zero-cache/src/services/view-syncer/row-record-cache.js +2 -2
  577. package/out/zero-cache/src/services/view-syncer/row-record-cache.js.map +1 -1
  578. package/out/zero-cache/src/services/view-syncer/schema/cvr.js.map +1 -1
  579. package/out/zero-cache/src/services/view-syncer/schema/types.js +2 -16
  580. package/out/zero-cache/src/services/view-syncer/schema/types.js.map +1 -1
  581. package/out/zero-cache/src/services/view-syncer/snapshot-row-cache.js +7 -1
  582. package/out/zero-cache/src/services/view-syncer/snapshot-row-cache.js.map +1 -1
  583. package/out/zero-cache/src/services/view-syncer/snapshotter.js +12 -8
  584. package/out/zero-cache/src/services/view-syncer/snapshotter.js.map +1 -1
  585. package/out/zero-cache/src/services/view-syncer/ttl-clock.js.map +1 -1
  586. package/out/zero-cache/src/services/view-syncer/view-syncer.js +52 -28
  587. package/out/zero-cache/src/services/view-syncer/view-syncer.js.map +1 -1
  588. package/out/zero-cache/src/types/error-with-level.js.map +1 -1
  589. package/out/zero-cache/src/types/lexi-version.js.map +1 -1
  590. package/out/zero-cache/src/types/lite.d.ts +0 -1
  591. package/out/zero-cache/src/types/lite.d.ts.map +1 -1
  592. package/out/zero-cache/src/types/lite.js +1 -1
  593. package/out/zero-cache/src/types/lite.js.map +1 -1
  594. package/out/zero-cache/src/types/pg-data-type.js +1 -1
  595. package/out/zero-cache/src/types/pg-data-type.js.map +1 -1
  596. package/out/zero-cache/src/types/pg-types.d.ts +0 -40
  597. package/out/zero-cache/src/types/pg-types.d.ts.map +1 -1
  598. package/out/zero-cache/src/types/pg-types.js.map +1 -1
  599. package/out/zero-cache/src/types/pg.js +6 -4
  600. package/out/zero-cache/src/types/pg.js.map +1 -1
  601. package/out/zero-cache/src/types/poke-chunk.d.ts +0 -1
  602. package/out/zero-cache/src/types/poke-chunk.d.ts.map +1 -1
  603. package/out/zero-cache/src/types/poke-chunk.js +1 -1
  604. package/out/zero-cache/src/types/poke-chunk.js.map +1 -1
  605. package/out/zero-cache/src/types/processes.js +1 -1
  606. package/out/zero-cache/src/types/processes.js.map +1 -1
  607. package/out/zero-cache/src/types/profiler.js +1 -1
  608. package/out/zero-cache/src/types/profiler.js.map +1 -1
  609. package/out/zero-cache/src/types/row-key.d.ts +0 -5
  610. package/out/zero-cache/src/types/row-key.d.ts.map +1 -1
  611. package/out/zero-cache/src/types/row-key.js.map +1 -1
  612. package/out/zero-cache/src/types/sql.js.map +1 -1
  613. package/out/zero-cache/src/types/streams.d.ts.map +1 -1
  614. package/out/zero-cache/src/types/streams.js +11 -10
  615. package/out/zero-cache/src/types/streams.js.map +1 -1
  616. package/out/zero-cache/src/types/strings.js.map +1 -1
  617. package/out/zero-cache/src/types/subscription.js +1 -1
  618. package/out/zero-cache/src/types/subscription.js.map +1 -1
  619. package/out/zero-cache/src/types/timeout.js +1 -1
  620. package/out/zero-cache/src/types/websocket-handoff.d.ts +4 -7
  621. package/out/zero-cache/src/types/websocket-handoff.d.ts.map +1 -1
  622. package/out/zero-cache/src/types/websocket-handoff.js +16 -2
  623. package/out/zero-cache/src/types/websocket-handoff.js.map +1 -1
  624. package/out/zero-cache/src/types/ws.d.ts +2 -1
  625. package/out/zero-cache/src/types/ws.d.ts.map +1 -1
  626. package/out/zero-cache/src/types/ws.js.map +1 -1
  627. package/out/zero-cache/src/workers/connection.d.ts +1 -2
  628. package/out/zero-cache/src/workers/connection.d.ts.map +1 -1
  629. package/out/zero-cache/src/workers/connection.js +5 -3
  630. package/out/zero-cache/src/workers/connection.js.map +1 -1
  631. package/out/zero-cache/src/workers/mutator.js +1 -1
  632. package/out/zero-cache/src/workers/mutator.js.map +1 -1
  633. package/out/zero-cache/src/workers/rehome.d.ts +15 -0
  634. package/out/zero-cache/src/workers/rehome.d.ts.map +1 -0
  635. package/out/zero-cache/src/workers/rehome.js +36 -0
  636. package/out/zero-cache/src/workers/rehome.js.map +1 -0
  637. package/out/zero-cache/src/workers/replicator.js +5 -4
  638. package/out/zero-cache/src/workers/replicator.js.map +1 -1
  639. package/out/zero-cache/src/workers/syncer-ws-message-handler.js +9 -1
  640. package/out/zero-cache/src/workers/syncer-ws-message-handler.js.map +1 -1
  641. package/out/zero-cache/src/workers/syncer.js +30 -5
  642. package/out/zero-cache/src/workers/syncer.js.map +1 -1
  643. package/out/zero-client/src/client/active-clients-manager.d.ts.map +1 -1
  644. package/out/zero-client/src/client/active-clients-manager.js +2 -2
  645. package/out/zero-client/src/client/active-clients-manager.js.map +1 -1
  646. package/out/zero-client/src/client/bindings.js +11 -11
  647. package/out/zero-client/src/client/connection-manager.js +1 -1
  648. package/out/zero-client/src/client/connection-manager.js.map +1 -1
  649. package/out/zero-client/src/client/connection.js +1 -1
  650. package/out/zero-client/src/client/connection.js.map +1 -1
  651. package/out/zero-client/src/client/context.js.map +1 -1
  652. package/out/zero-client/src/client/crud-impl.js +1 -1
  653. package/out/zero-client/src/client/crud-impl.js.map +1 -1
  654. package/out/zero-client/src/client/crud.d.ts +2 -8
  655. package/out/zero-client/src/client/crud.d.ts.map +1 -1
  656. package/out/zero-client/src/client/crud.js.map +1 -1
  657. package/out/zero-client/src/client/custom.d.ts +0 -2
  658. package/out/zero-client/src/client/custom.d.ts.map +1 -1
  659. package/out/zero-client/src/client/custom.js.map +1 -1
  660. package/out/zero-client/src/client/delete-clients-manager.js.map +1 -1
  661. package/out/zero-client/src/client/enable-analytics.d.ts +0 -1
  662. package/out/zero-client/src/client/enable-analytics.d.ts.map +1 -1
  663. package/out/zero-client/src/client/enable-analytics.js +1 -0
  664. package/out/zero-client/src/client/enable-analytics.js.map +1 -1
  665. package/out/zero-client/src/client/error.d.ts +4 -5
  666. package/out/zero-client/src/client/error.d.ts.map +1 -1
  667. package/out/zero-client/src/client/error.js.map +1 -1
  668. package/out/zero-client/src/client/inspector/client-group.js.map +1 -1
  669. package/out/zero-client/src/client/inspector/client.js.map +1 -1
  670. package/out/zero-client/src/client/inspector/html-dialog-prompt.js +1 -1
  671. package/out/zero-client/src/client/inspector/html-dialog-prompt.js.map +1 -1
  672. package/out/zero-client/src/client/inspector/inspector.js.map +1 -1
  673. package/out/zero-client/src/client/inspector/lazy-inspector.js.map +1 -1
  674. package/out/zero-client/src/client/inspector/query.js.map +1 -1
  675. package/out/zero-client/src/client/ivm-branch.js +1 -3
  676. package/out/zero-client/src/client/ivm-branch.js.map +1 -1
  677. package/out/zero-client/src/client/keys.d.ts +0 -1
  678. package/out/zero-client/src/client/keys.d.ts.map +1 -1
  679. package/out/zero-client/src/client/keys.js +6 -3
  680. package/out/zero-client/src/client/keys.js.map +1 -1
  681. package/out/zero-client/src/client/log-options.js.map +1 -1
  682. package/out/zero-client/src/client/make-replicache-mutators.js +5 -3
  683. package/out/zero-client/src/client/make-replicache-mutators.js.map +1 -1
  684. package/out/zero-client/src/client/metrics.js +3 -5
  685. package/out/zero-client/src/client/metrics.js.map +1 -1
  686. package/out/zero-client/src/client/mutation-tracker.d.ts.map +1 -1
  687. package/out/zero-client/src/client/mutation-tracker.js +1 -1
  688. package/out/zero-client/src/client/mutation-tracker.js.map +1 -1
  689. package/out/zero-client/src/client/mutator-proxy.js.map +1 -1
  690. package/out/zero-client/src/client/options.d.ts +0 -4
  691. package/out/zero-client/src/client/options.d.ts.map +1 -1
  692. package/out/zero-client/src/client/options.js.map +1 -1
  693. package/out/zero-client/src/client/query-manager.js +2 -2
  694. package/out/zero-client/src/client/query-manager.js.map +1 -1
  695. package/out/zero-client/src/client/reload-error-handler.js +4 -3
  696. package/out/zero-client/src/client/reload-error-handler.js.map +1 -1
  697. package/out/zero-client/src/client/replicache-types.d.ts +3 -2
  698. package/out/zero-client/src/client/replicache-types.d.ts.map +1 -1
  699. package/out/zero-client/src/client/version.js +1 -1
  700. package/out/zero-client/src/client/zero-poke-handler.d.ts +1 -2
  701. package/out/zero-client/src/client/zero-poke-handler.d.ts.map +1 -1
  702. package/out/zero-client/src/client/zero-poke-handler.js +1 -1
  703. package/out/zero-client/src/client/zero-poke-handler.js.map +1 -1
  704. package/out/zero-client/src/client/zero-rep.js.map +1 -1
  705. package/out/zero-client/src/client/zero.d.ts +1 -5
  706. package/out/zero-client/src/client/zero.d.ts.map +1 -1
  707. package/out/zero-client/src/client/zero.js +20 -12
  708. package/out/zero-client/src/client/zero.js.map +1 -1
  709. package/out/zero-client/src/mod.js +23 -23
  710. package/out/zero-client/src/types/client-state.d.ts +0 -6
  711. package/out/zero-client/src/types/client-state.d.ts.map +1 -1
  712. package/out/zero-client/src/util/nanoid.js.map +1 -1
  713. package/out/zero-permissions/src/permissions.d.ts +1 -12
  714. package/out/zero-permissions/src/permissions.d.ts.map +1 -1
  715. package/out/zero-permissions/src/permissions.js +3 -3
  716. package/out/zero-permissions/src/permissions.js.map +1 -1
  717. package/out/zero-pg/src/mod.js +9 -9
  718. package/out/zero-protocol/src/analyze-query-result.js +1 -1
  719. package/out/zero-protocol/src/analyze-query-result.js.map +1 -1
  720. package/out/zero-protocol/src/application-error.js.map +1 -1
  721. package/out/zero-protocol/src/ast.d.ts +0 -4
  722. package/out/zero-protocol/src/ast.d.ts.map +1 -1
  723. package/out/zero-protocol/src/ast.js +21 -11
  724. package/out/zero-protocol/src/ast.js.map +1 -1
  725. package/out/zero-protocol/src/change-desired-queries.d.ts +0 -20
  726. package/out/zero-protocol/src/change-desired-queries.d.ts.map +1 -1
  727. package/out/zero-protocol/src/change-desired-queries.js.map +1 -1
  728. package/out/zero-protocol/src/client-schema.d.ts +2 -5
  729. package/out/zero-protocol/src/client-schema.d.ts.map +1 -1
  730. package/out/zero-protocol/src/client-schema.js.map +1 -1
  731. package/out/zero-protocol/src/close-connection.d.ts +0 -8
  732. package/out/zero-protocol/src/close-connection.d.ts.map +1 -1
  733. package/out/zero-protocol/src/close-connection.js.map +1 -1
  734. package/out/zero-protocol/src/connect.d.ts +0 -12
  735. package/out/zero-protocol/src/connect.d.ts.map +1 -1
  736. package/out/zero-protocol/src/connect.js.map +1 -1
  737. package/out/zero-protocol/src/custom-queries.d.ts +3 -17
  738. package/out/zero-protocol/src/custom-queries.d.ts.map +1 -1
  739. package/out/zero-protocol/src/custom-queries.js.map +1 -1
  740. package/out/zero-protocol/src/data.d.ts +0 -1
  741. package/out/zero-protocol/src/data.d.ts.map +1 -1
  742. package/out/zero-protocol/src/data.js +3 -1
  743. package/out/zero-protocol/src/data.js.map +1 -1
  744. package/out/zero-protocol/src/delete-clients.js.map +1 -1
  745. package/out/zero-protocol/src/down.d.ts +2 -2
  746. package/out/zero-protocol/src/down.js.map +1 -1
  747. package/out/zero-protocol/src/error.js.map +1 -1
  748. package/out/zero-protocol/src/inspect-down.d.ts +82 -84
  749. package/out/zero-protocol/src/inspect-down.d.ts.map +1 -1
  750. package/out/zero-protocol/src/inspect-down.js.map +1 -1
  751. package/out/zero-protocol/src/inspect-up.d.ts +0 -28
  752. package/out/zero-protocol/src/inspect-up.d.ts.map +1 -1
  753. package/out/zero-protocol/src/inspect-up.js.map +1 -1
  754. package/out/zero-protocol/src/mutate-server.d.ts +0 -21
  755. package/out/zero-protocol/src/mutate-server.d.ts.map +1 -1
  756. package/out/zero-protocol/src/mutate-server.js.map +1 -1
  757. package/out/zero-protocol/src/mutation-id.js.map +1 -1
  758. package/out/zero-protocol/src/mutation-type-enum.d.ts +0 -1
  759. package/out/zero-protocol/src/mutation-type-enum.d.ts.map +1 -1
  760. package/out/zero-protocol/src/mutation-type-enum.js.map +1 -1
  761. package/out/zero-protocol/src/mutation.d.ts +2 -4
  762. package/out/zero-protocol/src/mutation.d.ts.map +1 -1
  763. package/out/zero-protocol/src/mutation.js.map +1 -1
  764. package/out/zero-protocol/src/mutations-patch.d.ts +0 -33
  765. package/out/zero-protocol/src/mutations-patch.d.ts.map +1 -1
  766. package/out/zero-protocol/src/mutations-patch.js.map +1 -1
  767. package/out/zero-protocol/src/ping.d.ts +0 -2
  768. package/out/zero-protocol/src/ping.d.ts.map +1 -1
  769. package/out/zero-protocol/src/ping.js.map +1 -1
  770. package/out/zero-protocol/src/poke.d.ts +3 -2
  771. package/out/zero-protocol/src/poke.d.ts.map +1 -1
  772. package/out/zero-protocol/src/poke.js +1 -1
  773. package/out/zero-protocol/src/poke.js.map +1 -1
  774. package/out/zero-protocol/src/pong.d.ts +0 -2
  775. package/out/zero-protocol/src/pong.d.ts.map +1 -1
  776. package/out/zero-protocol/src/pong.js.map +1 -1
  777. package/out/zero-protocol/src/primary-key.js.map +1 -1
  778. package/out/zero-protocol/src/protocol-version.js +1 -0
  779. package/out/zero-protocol/src/protocol-version.js.map +1 -1
  780. package/out/zero-protocol/src/pull.d.ts +2 -7
  781. package/out/zero-protocol/src/pull.d.ts.map +1 -1
  782. package/out/zero-protocol/src/pull.js.map +1 -1
  783. package/out/zero-protocol/src/push.d.ts +1 -3
  784. package/out/zero-protocol/src/push.d.ts.map +1 -1
  785. package/out/zero-protocol/src/push.js.map +1 -1
  786. package/out/zero-protocol/src/queries-patch.d.ts +0 -16
  787. package/out/zero-protocol/src/queries-patch.d.ts.map +1 -1
  788. package/out/zero-protocol/src/queries-patch.js +1 -1
  789. package/out/zero-protocol/src/queries-patch.js.map +1 -1
  790. package/out/zero-protocol/src/query-hash-visitor.js.map +1 -1
  791. package/out/zero-protocol/src/query-hash.js +2 -2
  792. package/out/zero-protocol/src/query-server.d.ts +2 -41
  793. package/out/zero-protocol/src/query-server.d.ts.map +1 -1
  794. package/out/zero-protocol/src/query-server.js.map +1 -1
  795. package/out/zero-protocol/src/row-patch.js.map +1 -1
  796. package/out/zero-protocol/src/up.d.ts +60 -60
  797. package/out/zero-protocol/src/up.js +1 -1
  798. package/out/zero-protocol/src/up.js.map +1 -1
  799. package/out/zero-protocol/src/update-auth.js.map +1 -1
  800. package/out/zero-protocol/src/version.d.ts +0 -1
  801. package/out/zero-protocol/src/version.d.ts.map +1 -1
  802. package/out/zero-protocol/src/version.js.map +1 -1
  803. package/out/zero-react/src/bindings.js +11 -11
  804. package/out/zero-react/src/mod.js +5 -5
  805. package/out/zero-react/src/use-query.js +2 -2
  806. package/out/zero-react/src/use-query.js.map +1 -1
  807. package/out/zero-react/src/zero-provider.d.ts +1 -1
  808. package/out/zero-react/src/zero-provider.d.ts.map +1 -1
  809. package/out/zero-react/src/zero-provider.js +2 -1
  810. package/out/zero-react/src/zero-provider.js.map +1 -1
  811. package/out/zero-react/src/zero.js +23 -23
  812. package/out/zero-schema/src/builder/relationship-builder.d.ts +0 -2
  813. package/out/zero-schema/src/builder/relationship-builder.d.ts.map +1 -1
  814. package/out/zero-schema/src/builder/relationship-builder.js.map +1 -1
  815. package/out/zero-schema/src/builder/schema-builder.js +3 -2
  816. package/out/zero-schema/src/builder/schema-builder.js.map +1 -1
  817. package/out/zero-schema/src/builder/table-builder.d.ts +1 -1
  818. package/out/zero-schema/src/builder/table-builder.d.ts.map +1 -1
  819. package/out/zero-schema/src/builder/table-builder.js +1 -1
  820. package/out/zero-schema/src/builder/table-builder.js.map +1 -1
  821. package/out/zero-schema/src/compiled-permissions.js.map +1 -1
  822. package/out/zero-schema/src/name-mapper.js +7 -5
  823. package/out/zero-schema/src/name-mapper.js.map +1 -1
  824. package/out/zero-schema/src/schema-config.d.ts +0 -1
  825. package/out/zero-schema/src/schema-config.d.ts.map +1 -1
  826. package/out/zero-schema/src/schema-config.js +1 -1
  827. package/out/zero-schema/src/schema-config.js.map +1 -1
  828. package/out/zero-schema/src/table-schema.d.ts +3 -11
  829. package/out/zero-schema/src/table-schema.d.ts.map +1 -1
  830. package/out/zero-server/src/adapters/drizzle.js.map +1 -1
  831. package/out/zero-server/src/adapters/kysely.js.map +1 -1
  832. package/out/zero-server/src/adapters/pg.js.map +1 -1
  833. package/out/zero-server/src/adapters/postgresjs.js.map +1 -1
  834. package/out/zero-server/src/adapters/prisma.js.map +1 -1
  835. package/out/zero-server/src/closable-db-transaction.js.map +1 -1
  836. package/out/zero-server/src/custom.js +1 -1
  837. package/out/zero-server/src/custom.js.map +1 -1
  838. package/out/zero-server/src/mod.js +8 -8
  839. package/out/zero-server/src/process-mutations.js.map +1 -1
  840. package/out/zero-server/src/push-processor.js.map +1 -1
  841. package/out/zero-server/src/queries/process-queries.d.ts +2 -4
  842. package/out/zero-server/src/queries/process-queries.d.ts.map +1 -1
  843. package/out/zero-server/src/queries/process-queries.js +2 -1
  844. package/out/zero-server/src/queries/process-queries.js.map +1 -1
  845. package/out/zero-server/src/schema.js +7 -7
  846. package/out/zero-server/src/schema.js.map +1 -1
  847. package/out/zero-server/src/zql-database.js.map +1 -1
  848. package/out/zero-solid/src/bindings.js +11 -11
  849. package/out/zero-solid/src/mod.js +5 -5
  850. package/out/zero-solid/src/solid-view.d.ts +0 -2
  851. package/out/zero-solid/src/solid-view.d.ts.map +1 -1
  852. package/out/zero-solid/src/solid-view.js +1 -1
  853. package/out/zero-solid/src/solid-view.js.map +1 -1
  854. package/out/zero-solid/src/use-connection-state.js +2 -1
  855. package/out/zero-solid/src/use-connection-state.js.map +1 -1
  856. package/out/zero-solid/src/use-query.js.map +1 -1
  857. package/out/zero-solid/src/use-zero-online.js +2 -1
  858. package/out/zero-solid/src/use-zero-online.js.map +1 -1
  859. package/out/zero-solid/src/use-zero.js +3 -2
  860. package/out/zero-solid/src/use-zero.js.map +1 -1
  861. package/out/zero-solid/src/zero.js +23 -23
  862. package/out/zero-types/src/name-mapper.d.ts +2 -1
  863. package/out/zero-types/src/name-mapper.d.ts.map +1 -1
  864. package/out/zero-types/src/name-mapper.js.map +1 -1
  865. package/out/zero-types/src/schema-value.d.ts +3 -2
  866. package/out/zero-types/src/schema-value.d.ts.map +1 -1
  867. package/out/zero-types/src/schema.d.ts +1 -1
  868. package/out/zero-types/src/schema.d.ts.map +1 -1
  869. package/out/zql/src/builder/builder.d.ts +1 -11
  870. package/out/zql/src/builder/builder.d.ts.map +1 -1
  871. package/out/zql/src/builder/builder.js +15 -13
  872. package/out/zql/src/builder/builder.js.map +1 -1
  873. package/out/zql/src/builder/correlated-predicate-pushdown.js.map +1 -1
  874. package/out/zql/src/builder/debug-delegate.js.map +1 -1
  875. package/out/zql/src/builder/filter.d.ts +0 -1
  876. package/out/zql/src/builder/filter.d.ts.map +1 -1
  877. package/out/zql/src/builder/filter.js.map +1 -1
  878. package/out/zql/src/builder/like.js +0 -1
  879. package/out/zql/src/builder/like.js.map +1 -1
  880. package/out/zql/src/error.d.ts +0 -5
  881. package/out/zql/src/error.d.ts.map +1 -1
  882. package/out/zql/src/error.js.map +1 -1
  883. package/out/zql/src/ivm/array-view.js.map +1 -1
  884. package/out/zql/src/ivm/cap.d.ts +1 -1
  885. package/out/zql/src/ivm/cap.d.ts.map +1 -1
  886. package/out/zql/src/ivm/cap.js +12 -4
  887. package/out/zql/src/ivm/cap.js.map +1 -1
  888. package/out/zql/src/ivm/constraint.d.ts +0 -7
  889. package/out/zql/src/ivm/constraint.d.ts.map +1 -1
  890. package/out/zql/src/ivm/constraint.js +1 -1
  891. package/out/zql/src/ivm/constraint.js.map +1 -1
  892. package/out/zql/src/ivm/data.d.ts +15 -2
  893. package/out/zql/src/ivm/data.d.ts.map +1 -1
  894. package/out/zql/src/ivm/data.js +15 -1
  895. package/out/zql/src/ivm/data.js.map +1 -1
  896. package/out/zql/src/ivm/deferred-input.js.map +1 -1
  897. package/out/zql/src/ivm/exists.d.ts.map +1 -1
  898. package/out/zql/src/ivm/exists.js +32 -22
  899. package/out/zql/src/ivm/exists.js.map +1 -1
  900. package/out/zql/src/ivm/fan-in.js.map +1 -1
  901. package/out/zql/src/ivm/fan-out.js.map +1 -1
  902. package/out/zql/src/ivm/filter-operators.d.ts +5 -0
  903. package/out/zql/src/ivm/filter-operators.d.ts.map +1 -1
  904. package/out/zql/src/ivm/filter-operators.js +1 -1
  905. package/out/zql/src/ivm/filter-operators.js.map +1 -1
  906. package/out/zql/src/ivm/filter-push.js.map +1 -1
  907. package/out/zql/src/ivm/filter.js.map +1 -1
  908. package/out/zql/src/ivm/flipped-join.js +1 -3
  909. package/out/zql/src/ivm/flipped-join.js.map +1 -1
  910. package/out/zql/src/ivm/join-index-tap.js.map +1 -1
  911. package/out/zql/src/ivm/join-index.js.map +1 -1
  912. package/out/zql/src/ivm/join-utils.js +11 -13
  913. package/out/zql/src/ivm/join-utils.js.map +1 -1
  914. package/out/zql/src/ivm/join.d.ts.map +1 -1
  915. package/out/zql/src/ivm/join.js +6 -3
  916. package/out/zql/src/ivm/join.js.map +1 -1
  917. package/out/zql/src/ivm/maybe-split-and-push-edit-change.js.map +1 -1
  918. package/out/zql/src/ivm/memory-source.d.ts +1 -2
  919. package/out/zql/src/ivm/memory-source.d.ts.map +1 -1
  920. package/out/zql/src/ivm/memory-source.js +27 -23
  921. package/out/zql/src/ivm/memory-source.js.map +1 -1
  922. package/out/zql/src/ivm/memory-storage.js.map +1 -1
  923. package/out/zql/src/ivm/operator.d.ts +6 -0
  924. package/out/zql/src/ivm/operator.d.ts.map +1 -1
  925. package/out/zql/src/ivm/operator.js +2 -2
  926. package/out/zql/src/ivm/operator.js.map +1 -1
  927. package/out/zql/src/ivm/push-accumulated.js +0 -1
  928. package/out/zql/src/ivm/push-accumulated.js.map +1 -1
  929. package/out/zql/src/ivm/skip-yields.js.map +1 -1
  930. package/out/zql/src/ivm/skip.js.map +1 -1
  931. package/out/zql/src/ivm/stream.d.ts +0 -1
  932. package/out/zql/src/ivm/stream.d.ts.map +1 -1
  933. package/out/zql/src/ivm/stream.js.map +1 -1
  934. package/out/zql/src/ivm/take-gate.js.map +1 -1
  935. package/out/zql/src/ivm/take.d.ts.map +1 -1
  936. package/out/zql/src/ivm/take.js +7 -8
  937. package/out/zql/src/ivm/take.js.map +1 -1
  938. package/out/zql/src/ivm/union-fan-in.d.ts +0 -1
  939. package/out/zql/src/ivm/union-fan-in.d.ts.map +1 -1
  940. package/out/zql/src/ivm/union-fan-in.js.map +1 -1
  941. package/out/zql/src/ivm/union-fan-out.js.map +1 -1
  942. package/out/zql/src/ivm/view-apply-change.d.ts +5 -35
  943. package/out/zql/src/ivm/view-apply-change.d.ts.map +1 -1
  944. package/out/zql/src/ivm/view-apply-change.js.map +1 -1
  945. package/out/zql/src/mutate/crud.d.ts +1 -3
  946. package/out/zql/src/mutate/crud.d.ts.map +1 -1
  947. package/out/zql/src/mutate/crud.js +2 -1
  948. package/out/zql/src/mutate/crud.js.map +1 -1
  949. package/out/zql/src/mutate/mutator-registry.d.ts +1 -1
  950. package/out/zql/src/mutate/mutator-registry.d.ts.map +1 -1
  951. package/out/zql/src/mutate/mutator-registry.js.map +1 -1
  952. package/out/zql/src/mutate/mutator.d.ts +1 -1
  953. package/out/zql/src/mutate/mutator.d.ts.map +1 -1
  954. package/out/zql/src/mutate/mutator.js.map +1 -1
  955. package/out/zql/src/planner/planner-builder.js +1 -1
  956. package/out/zql/src/planner/planner-builder.js.map +1 -1
  957. package/out/zql/src/planner/planner-connection.js.map +1 -1
  958. package/out/zql/src/planner/planner-debug.d.ts +10 -9
  959. package/out/zql/src/planner/planner-debug.d.ts.map +1 -1
  960. package/out/zql/src/planner/planner-debug.js.map +1 -1
  961. package/out/zql/src/planner/planner-fan-in.js.map +1 -1
  962. package/out/zql/src/planner/planner-fan-out.js.map +1 -1
  963. package/out/zql/src/planner/planner-filter.js.map +1 -1
  964. package/out/zql/src/planner/planner-graph.js +1 -5
  965. package/out/zql/src/planner/planner-graph.js.map +1 -1
  966. package/out/zql/src/planner/planner-join.js +1 -1
  967. package/out/zql/src/planner/planner-join.js.map +1 -1
  968. package/out/zql/src/planner/planner-node.d.ts +0 -1
  969. package/out/zql/src/planner/planner-node.d.ts.map +1 -1
  970. package/out/zql/src/planner/planner-node.js.map +1 -1
  971. package/out/zql/src/planner/planner-source.js.map +1 -1
  972. package/out/zql/src/planner/planner-terminus.js.map +1 -1
  973. package/out/zql/src/planner/planner-warnings.d.ts +3 -3
  974. package/out/zql/src/planner/planner-warnings.d.ts.map +1 -1
  975. package/out/zql/src/planner/planner-warnings.js.map +1 -1
  976. package/out/zql/src/query/create-builder.js +2 -1
  977. package/out/zql/src/query/create-builder.js.map +1 -1
  978. package/out/zql/src/query/expression.d.ts +0 -22
  979. package/out/zql/src/query/expression.d.ts.map +1 -1
  980. package/out/zql/src/query/expression.js +1 -1
  981. package/out/zql/src/query/expression.js.map +1 -1
  982. package/out/zql/src/query/measure-push-operator.js.map +1 -1
  983. package/out/zql/src/query/named.js +2 -1
  984. package/out/zql/src/query/named.js.map +1 -1
  985. package/out/zql/src/query/query-delegate-base.d.ts +0 -7
  986. package/out/zql/src/query/query-delegate-base.d.ts.map +1 -1
  987. package/out/zql/src/query/query-delegate-base.js +1 -1
  988. package/out/zql/src/query/query-delegate-base.js.map +1 -1
  989. package/out/zql/src/query/query-delegate.d.ts +1 -4
  990. package/out/zql/src/query/query-delegate.d.ts.map +1 -1
  991. package/out/zql/src/query/query-impl.js +3 -2
  992. package/out/zql/src/query/query-impl.js.map +1 -1
  993. package/out/zql/src/query/query-internals.d.ts +0 -3
  994. package/out/zql/src/query/query-internals.d.ts.map +1 -1
  995. package/out/zql/src/query/query-internals.js.map +1 -1
  996. package/out/zql/src/query/query-registry.d.ts +5 -5
  997. package/out/zql/src/query/query-registry.d.ts.map +1 -1
  998. package/out/zql/src/query/query-registry.js +1 -1
  999. package/out/zql/src/query/query-registry.js.map +1 -1
  1000. package/out/zql/src/query/query-transitions.js +1 -1
  1001. package/out/zql/src/query/query-transitions.js.map +1 -1
  1002. package/out/zql/src/query/query.d.ts +2 -13
  1003. package/out/zql/src/query/query.d.ts.map +1 -1
  1004. package/out/zql/src/query/runnable-query-impl.d.ts +1 -19
  1005. package/out/zql/src/query/runnable-query-impl.d.ts.map +1 -1
  1006. package/out/zql/src/query/runnable-query-impl.js +2 -1
  1007. package/out/zql/src/query/runnable-query-impl.js.map +1 -1
  1008. package/out/zql/src/query/static-query.js.map +1 -1
  1009. package/out/zql/src/query/ttl.d.ts +2 -3
  1010. package/out/zql/src/query/ttl.d.ts.map +1 -1
  1011. package/out/zql/src/query/ttl.js +8 -8
  1012. package/out/zql/src/query/ttl.js.map +1 -1
  1013. package/out/zql/src/query/validate-input.js.map +1 -1
  1014. package/out/zqlite/src/database-storage.js +195 -26
  1015. package/out/zqlite/src/database-storage.js.map +1 -1
  1016. package/out/zqlite/src/db.d.ts +47 -1
  1017. package/out/zqlite/src/db.d.ts.map +1 -1
  1018. package/out/zqlite/src/db.js +121 -21
  1019. package/out/zqlite/src/db.js.map +1 -1
  1020. package/out/zqlite/src/explain-queries.js.map +1 -1
  1021. package/out/zqlite/src/fetch-sql.d.ts +27 -0
  1022. package/out/zqlite/src/fetch-sql.d.ts.map +1 -0
  1023. package/out/zqlite/src/fetch-sql.js +112 -0
  1024. package/out/zqlite/src/fetch-sql.js.map +1 -0
  1025. package/out/zqlite/src/index-usage.js.map +1 -1
  1026. package/out/zqlite/src/internal/sql-inline.js.map +1 -1
  1027. package/out/zqlite/src/internal/sql.js.map +1 -1
  1028. package/out/zqlite/src/internal/statement-cache.d.ts +7 -0
  1029. package/out/zqlite/src/internal/statement-cache.d.ts.map +1 -1
  1030. package/out/zqlite/src/internal/statement-cache.js +11 -4
  1031. package/out/zqlite/src/internal/statement-cache.js.map +1 -1
  1032. package/out/zqlite/src/mod.js +5 -5
  1033. package/out/zqlite/src/pending-delta.js.map +1 -1
  1034. package/out/zqlite/src/query-builder.d.ts +11 -3
  1035. package/out/zqlite/src/query-builder.d.ts.map +1 -1
  1036. package/out/zqlite/src/query-builder.js +22 -7
  1037. package/out/zqlite/src/query-builder.js.map +1 -1
  1038. package/out/zqlite/src/query-delegate.js.map +1 -1
  1039. package/out/zqlite/src/resolve-scalar-subqueries.js +2 -5
  1040. package/out/zqlite/src/resolve-scalar-subqueries.js.map +1 -1
  1041. package/out/zqlite/src/sqlite-cost-model.js +3 -2
  1042. package/out/zqlite/src/sqlite-cost-model.js.map +1 -1
  1043. package/out/zqlite/src/sqlite-stat-fanout.js.map +1 -1
  1044. package/out/zqlite/src/table-source.d.ts +20 -3
  1045. package/out/zqlite/src/table-source.d.ts.map +1 -1
  1046. package/out/zqlite/src/table-source.js +74 -40
  1047. package/out/zqlite/src/table-source.js.map +1 -1
  1048. package/package.json +39 -39
  1049. package/out/analyze-query/src/bin-analyze.d.ts +0 -2
  1050. package/out/analyze-query/src/bin-analyze.d.ts.map +0 -1
  1051. package/out/analyze-query/src/bin-analyze.js +0 -283
  1052. package/out/analyze-query/src/bin-analyze.js.map +0 -1
  1053. package/out/otel/src/maybe-time.d.ts +0 -3
  1054. package/out/otel/src/maybe-time.d.ts.map +0 -1
  1055. package/out/otel/src/maybe-time.js +0 -15
  1056. package/out/otel/src/maybe-time.js.map +0 -1
  1057. package/out/shared/src/cache.d.ts +0 -22
  1058. package/out/shared/src/cache.d.ts.map +0 -1
  1059. package/out/shared/src/custom-key-map.d.ts +0 -26
  1060. package/out/shared/src/custom-key-map.d.ts.map +0 -1
  1061. package/out/shared/src/custom-key-set.d.ts +0 -25
  1062. package/out/shared/src/custom-key-set.d.ts.map +0 -1
  1063. package/out/shared/src/logging-test-utils.d.ts +0 -12
  1064. package/out/shared/src/logging-test-utils.d.ts.map +0 -1
  1065. package/out/shared/src/sorted-entries.d.ts +0 -2
  1066. package/out/shared/src/sorted-entries.d.ts.map +0 -1
  1067. package/out/zero/src/analyze-query.d.ts +0 -3
  1068. package/out/zero/src/analyze-query.d.ts.map +0 -1
  1069. package/out/zero/src/analyze-query.js +0 -3
  1070. package/out/zero/src/server/change-streamer.d.ts +0 -2
  1071. package/out/zero/src/server/change-streamer.d.ts.map +0 -1
  1072. package/out/zero/src/server/main.d.ts +0 -2
  1073. package/out/zero/src/server/main.d.ts.map +0 -1
  1074. package/out/zero/src/server/reaper.d.ts +0 -2
  1075. package/out/zero/src/server/reaper.d.ts.map +0 -1
  1076. package/out/zero/src/server/replicator.d.ts +0 -2
  1077. package/out/zero/src/server/replicator.d.ts.map +0 -1
  1078. package/out/zero/src/server/syncer.d.ts +0 -2
  1079. package/out/zero/src/server/syncer.d.ts.map +0 -1
  1080. package/out/zero-cache/src/auth/jwt.d.ts +0 -12
  1081. package/out/zero-cache/src/auth/jwt.d.ts.map +0 -1
  1082. package/out/zero-cache/src/auth/load-permissions.d.ts +0 -17
  1083. package/out/zero-cache/src/auth/load-permissions.d.ts.map +0 -1
  1084. package/out/zero-cache/src/auth/write-authorizer.d.ts +0 -28
  1085. package/out/zero-cache/src/auth/write-authorizer.d.ts.map +0 -1
  1086. package/out/zero-cache/src/config/server-context.d.ts +0 -16
  1087. package/out/zero-cache/src/config/server-context.d.ts.map +0 -1
  1088. package/out/zero-cache/src/custom/fetch.d.ts +0 -38
  1089. package/out/zero-cache/src/custom/fetch.d.ts.map +0 -1
  1090. package/out/zero-cache/src/custom/metrics.d.ts +0 -31
  1091. package/out/zero-cache/src/custom/metrics.d.ts.map +0 -1
  1092. package/out/zero-cache/src/custom-queries/transform-query.d.ts +0 -68
  1093. package/out/zero-cache/src/custom-queries/transform-query.d.ts.map +0 -1
  1094. package/out/zero-cache/src/db/create.d.ts +0 -12
  1095. package/out/zero-cache/src/db/create.d.ts.map +0 -1
  1096. package/out/zero-cache/src/db/delete-lite-db.d.ts +0 -2
  1097. package/out/zero-cache/src/db/delete-lite-db.d.ts.map +0 -1
  1098. package/out/zero-cache/src/db/index-predicate.d.ts +0 -4
  1099. package/out/zero-cache/src/db/index-predicate.d.ts.map +0 -1
  1100. package/out/zero-cache/src/db/migration-lite.d.ts +0 -78
  1101. package/out/zero-cache/src/db/migration-lite.d.ts.map +0 -1
  1102. package/out/zero-cache/src/db/migration.d.ts +0 -80
  1103. package/out/zero-cache/src/db/migration.d.ts.map +0 -1
  1104. package/out/zero-cache/src/db/pg-copy-binary.d.ts +0 -101
  1105. package/out/zero-cache/src/db/pg-copy-binary.d.ts.map +0 -1
  1106. package/out/zero-cache/src/db/pg-copy.d.ts +0 -30
  1107. package/out/zero-cache/src/db/pg-copy.d.ts.map +0 -1
  1108. package/out/zero-cache/src/db/pg-type-parser.d.ts +0 -15
  1109. package/out/zero-cache/src/db/pg-type-parser.d.ts.map +0 -1
  1110. package/out/zero-cache/src/db/transaction-pool.d.ts +0 -205
  1111. package/out/zero-cache/src/db/transaction-pool.d.ts.map +0 -1
  1112. package/out/zero-cache/src/db/warmup.d.ts +0 -4
  1113. package/out/zero-cache/src/db/warmup.d.ts.map +0 -1
  1114. package/out/zero-cache/src/observability/events.d.ts +0 -15
  1115. package/out/zero-cache/src/observability/events.d.ts.map +0 -1
  1116. package/out/zero-cache/src/observability/log-throttle.d.ts +0 -44
  1117. package/out/zero-cache/src/observability/log-throttle.d.ts.map +0 -1
  1118. package/out/zero-cache/src/server/anonymous-otel-start.d.ts +0 -21
  1119. package/out/zero-cache/src/server/anonymous-otel-start.d.ts.map +0 -1
  1120. package/out/zero-cache/src/server/change-streamer.d.ts +0 -3
  1121. package/out/zero-cache/src/server/change-streamer.d.ts.map +0 -1
  1122. package/out/zero-cache/src/server/inspector-delegate.d.ts +0 -71
  1123. package/out/zero-cache/src/server/inspector-delegate.d.ts.map +0 -1
  1124. package/out/zero-cache/src/server/main.d.ts +0 -3
  1125. package/out/zero-cache/src/server/main.d.ts.map +0 -1
  1126. package/out/zero-cache/src/server/otel-diag-logger.d.ts +0 -16
  1127. package/out/zero-cache/src/server/otel-diag-logger.d.ts.map +0 -1
  1128. package/out/zero-cache/src/server/otel-start.d.ts +0 -3
  1129. package/out/zero-cache/src/server/otel-start.d.ts.map +0 -1
  1130. package/out/zero-cache/src/server/priority-op.d.ts +0 -8
  1131. package/out/zero-cache/src/server/priority-op.d.ts.map +0 -1
  1132. package/out/zero-cache/src/server/reaper.d.ts +0 -3
  1133. package/out/zero-cache/src/server/reaper.d.ts.map +0 -1
  1134. package/out/zero-cache/src/server/replicator.d.ts +0 -10
  1135. package/out/zero-cache/src/server/replicator.d.ts.map +0 -1
  1136. package/out/zero-cache/src/server/slot-keeper.d.ts +0 -26
  1137. package/out/zero-cache/src/server/slot-keeper.d.ts.map +0 -1
  1138. package/out/zero-cache/src/server/syncer.d.ts +0 -3
  1139. package/out/zero-cache/src/server/syncer.d.ts.map +0 -1
  1140. package/out/zero-cache/src/services/analyze.d.ts +0 -9
  1141. package/out/zero-cache/src/services/analyze.d.ts.map +0 -1
  1142. package/out/zero-cache/src/services/change-source/change-source.d.ts +0 -32
  1143. package/out/zero-cache/src/services/change-source/change-source.d.ts.map +0 -1
  1144. package/out/zero-cache/src/services/change-source/common/backfill-manager.d.ts +0 -57
  1145. package/out/zero-cache/src/services/change-source/common/backfill-manager.d.ts.map +0 -1
  1146. package/out/zero-cache/src/services/change-source/common/change-stream-multiplexer.d.ts +0 -55
  1147. package/out/zero-cache/src/services/change-source/common/change-stream-multiplexer.d.ts.map +0 -1
  1148. package/out/zero-cache/src/services/change-source/common/init-cleanup.d.ts +0 -24
  1149. package/out/zero-cache/src/services/change-source/common/init-cleanup.d.ts.map +0 -1
  1150. package/out/zero-cache/src/services/change-source/common/replica-restore.d.ts +0 -115
  1151. package/out/zero-cache/src/services/change-source/common/replica-restore.d.ts.map +0 -1
  1152. package/out/zero-cache/src/services/change-source/common/replica-schema.d.ts +0 -14
  1153. package/out/zero-cache/src/services/change-source/common/replica-schema.d.ts.map +0 -1
  1154. package/out/zero-cache/src/services/change-source/custom/change-source.d.ts +0 -25
  1155. package/out/zero-cache/src/services/change-source/custom/change-source.d.ts.map +0 -1
  1156. package/out/zero-cache/src/services/change-source/pg/backfill-metadata.d.ts +0 -14
  1157. package/out/zero-cache/src/services/change-source/pg/backfill-metadata.d.ts.map +0 -1
  1158. package/out/zero-cache/src/services/change-source/pg/backfill-stream.d.ts +0 -36
  1159. package/out/zero-cache/src/services/change-source/pg/backfill-stream.d.ts.map +0 -1
  1160. package/out/zero-cache/src/services/change-source/pg/change-source-init.d.ts +0 -65
  1161. package/out/zero-cache/src/services/change-source/pg/change-source-init.d.ts.map +0 -1
  1162. package/out/zero-cache/src/services/change-source/pg/change-source.d.ts +0 -115
  1163. package/out/zero-cache/src/services/change-source/pg/change-source.d.ts.map +0 -1
  1164. package/out/zero-cache/src/services/change-source/pg/initial-sync.d.ts +0 -155
  1165. package/out/zero-cache/src/services/change-source/pg/initial-sync.d.ts.map +0 -1
  1166. package/out/zero-cache/src/services/change-source/pg/logical-replication/binary-reader.d.ts +0 -17
  1167. package/out/zero-cache/src/services/change-source/pg/logical-replication/binary-reader.d.ts.map +0 -1
  1168. package/out/zero-cache/src/services/change-source/pg/logical-replication/pgoutput-parser.d.ts +0 -28
  1169. package/out/zero-cache/src/services/change-source/pg/logical-replication/pgoutput-parser.d.ts.map +0 -1
  1170. package/out/zero-cache/src/services/change-source/pg/logical-replication/pgoutput.types.d.ts +0 -76
  1171. package/out/zero-cache/src/services/change-source/pg/logical-replication/pgoutput.types.d.ts.map +0 -1
  1172. package/out/zero-cache/src/services/change-source/pg/logical-replication/stream.d.ts +0 -169
  1173. package/out/zero-cache/src/services/change-source/pg/logical-replication/stream.d.ts.map +0 -1
  1174. package/out/zero-cache/src/services/change-source/pg/replication-slot-cleanup-monitor.d.ts +0 -16
  1175. package/out/zero-cache/src/services/change-source/pg/replication-slot-cleanup-monitor.d.ts.map +0 -1
  1176. package/out/zero-cache/src/services/change-source/pg/replication-slot-health.d.ts +0 -15
  1177. package/out/zero-cache/src/services/change-source/pg/replication-slot-health.d.ts.map +0 -1
  1178. package/out/zero-cache/src/services/change-source/pg/replication-slots.d.ts +0 -127
  1179. package/out/zero-cache/src/services/change-source/pg/replication-slots.d.ts.map +0 -1
  1180. package/out/zero-cache/src/services/change-source/pg/schema/init.d.ts +0 -9
  1181. package/out/zero-cache/src/services/change-source/pg/schema/init.d.ts.map +0 -1
  1182. package/out/zero-cache/src/services/change-source/protocol/backfill-progress.d.ts +0 -68
  1183. package/out/zero-cache/src/services/change-source/protocol/backfill-progress.d.ts.map +0 -1
  1184. package/out/zero-cache/src/services/change-streamer/backfill-state-tracker.d.ts +0 -72
  1185. package/out/zero-cache/src/services/change-streamer/backfill-state-tracker.d.ts.map +0 -1
  1186. package/out/zero-cache/src/services/change-streamer/backfill-state.d.ts +0 -50
  1187. package/out/zero-cache/src/services/change-streamer/backfill-state.d.ts.map +0 -1
  1188. package/out/zero-cache/src/services/change-streamer/backup-cleanup-monitor-factory.d.ts +0 -14
  1189. package/out/zero-cache/src/services/change-streamer/backup-cleanup-monitor-factory.d.ts.map +0 -1
  1190. package/out/zero-cache/src/services/change-streamer/backup-monitor.d.ts +0 -18
  1191. package/out/zero-cache/src/services/change-streamer/backup-monitor.d.ts.map +0 -1
  1192. package/out/zero-cache/src/services/change-streamer/broadcast.d.ts +0 -98
  1193. package/out/zero-cache/src/services/change-streamer/broadcast.d.ts.map +0 -1
  1194. package/out/zero-cache/src/services/change-streamer/change-log-codec.d.ts +0 -34
  1195. package/out/zero-cache/src/services/change-streamer/change-log-codec.d.ts.map +0 -1
  1196. package/out/zero-cache/src/services/change-streamer/change-log-compare-digest.d.ts +0 -34
  1197. package/out/zero-cache/src/services/change-streamer/change-log-compare-digest.d.ts.map +0 -1
  1198. package/out/zero-cache/src/services/change-streamer/change-log-initializer.d.ts +0 -158
  1199. package/out/zero-cache/src/services/change-streamer/change-log-initializer.d.ts.map +0 -1
  1200. package/out/zero-cache/src/services/change-streamer/change-log-transaction-hash.d.ts +0 -19
  1201. package/out/zero-cache/src/services/change-streamer/change-log-transaction-hash.d.ts.map +0 -1
  1202. package/out/zero-cache/src/services/change-streamer/change-streamer-http.d.ts +0 -78
  1203. package/out/zero-cache/src/services/change-streamer/change-streamer-http.d.ts.map +0 -1
  1204. package/out/zero-cache/src/services/change-streamer/change-streamer-service.d.ts +0 -139
  1205. package/out/zero-cache/src/services/change-streamer/change-streamer-service.d.ts.map +0 -1
  1206. package/out/zero-cache/src/services/change-streamer/change-streamer.d.ts +0 -586
  1207. package/out/zero-cache/src/services/change-streamer/change-streamer.d.ts.map +0 -1
  1208. package/out/zero-cache/src/services/change-streamer/drain-tracker.d.ts +0 -24
  1209. package/out/zero-cache/src/services/change-streamer/drain-tracker.d.ts.map +0 -1
  1210. package/out/zero-cache/src/services/change-streamer/error-type-enum.d.ts +0 -15
  1211. package/out/zero-cache/src/services/change-streamer/error-type-enum.d.ts.map +0 -1
  1212. package/out/zero-cache/src/services/change-streamer/forwarder.d.ts +0 -49
  1213. package/out/zero-cache/src/services/change-streamer/forwarder.d.ts.map +0 -1
  1214. package/out/zero-cache/src/services/change-streamer/litestream-sync-requester.d.ts +0 -53
  1215. package/out/zero-cache/src/services/change-streamer/litestream-sync-requester.d.ts.map +0 -1
  1216. package/out/zero-cache/src/services/change-streamer/litestream3-prometheus-poller.d.ts +0 -88
  1217. package/out/zero-cache/src/services/change-streamer/litestream3-prometheus-poller.d.ts.map +0 -1
  1218. package/out/zero-cache/src/services/change-streamer/replica-poller.d.ts +0 -15
  1219. package/out/zero-cache/src/services/change-streamer/replica-poller.d.ts.map +0 -1
  1220. package/out/zero-cache/src/services/change-streamer/restore-admission.d.ts +0 -243
  1221. package/out/zero-cache/src/services/change-streamer/restore-admission.d.ts.map +0 -1
  1222. package/out/zero-cache/src/services/change-streamer/schema/init.d.ts +0 -6
  1223. package/out/zero-cache/src/services/change-streamer/schema/init.d.ts.map +0 -1
  1224. package/out/zero-cache/src/services/change-streamer/schema/tables.d.ts +0 -152
  1225. package/out/zero-cache/src/services/change-streamer/schema/tables.d.ts.map +0 -1
  1226. package/out/zero-cache/src/services/change-streamer/shard-sampling.d.ts +0 -11
  1227. package/out/zero-cache/src/services/change-streamer/shard-sampling.d.ts.map +0 -1
  1228. package/out/zero-cache/src/services/change-streamer/snapshot-message.d.ts +0 -92
  1229. package/out/zero-cache/src/services/change-streamer/snapshot-message.d.ts.map +0 -1
  1230. package/out/zero-cache/src/services/change-streamer/snapshot-reservations.d.ts +0 -36
  1231. package/out/zero-cache/src/services/change-streamer/snapshot-reservations.d.ts.map +0 -1
  1232. package/out/zero-cache/src/services/change-streamer/snapshot.d.ts +0 -22
  1233. package/out/zero-cache/src/services/change-streamer/snapshot.d.ts.map +0 -1
  1234. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-catchup.d.ts +0 -99
  1235. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-catchup.d.ts.map +0 -1
  1236. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-comparator.d.ts +0 -83
  1237. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-comparator.d.ts.map +0 -1
  1238. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-purge-scheduler.d.ts +0 -121
  1239. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-purge-scheduler.d.ts.map +0 -1
  1240. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-read-router.d.ts +0 -73
  1241. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-read-router.d.ts.map +0 -1
  1242. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-reader.d.ts +0 -62
  1243. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-reader.d.ts.map +0 -1
  1244. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-writer.d.ts +0 -114
  1245. package/out/zero-cache/src/services/change-streamer/sqlite-change-log-writer.d.ts.map +0 -1
  1246. package/out/zero-cache/src/services/change-streamer/storer.d.ts +0 -276
  1247. package/out/zero-cache/src/services/change-streamer/storer.d.ts.map +0 -1
  1248. package/out/zero-cache/src/services/change-streamer/subscribe.d.ts +0 -485
  1249. package/out/zero-cache/src/services/change-streamer/subscribe.d.ts.map +0 -1
  1250. package/out/zero-cache/src/services/change-streamer/subscriber.d.ts +0 -194
  1251. package/out/zero-cache/src/services/change-streamer/subscriber.d.ts.map +0 -1
  1252. package/out/zero-cache/src/services/change-streamer/upstream-acker.d.ts +0 -52
  1253. package/out/zero-cache/src/services/change-streamer/upstream-acker.d.ts.map +0 -1
  1254. package/out/zero-cache/src/services/limiter/sliding-window-limiter.d.ts +0 -57
  1255. package/out/zero-cache/src/services/limiter/sliding-window-limiter.d.ts.map +0 -1
  1256. package/out/zero-cache/src/services/litestream/commands.d.ts +0 -77
  1257. package/out/zero-cache/src/services/litestream/commands.d.ts.map +0 -1
  1258. package/out/zero-cache/src/services/litestream/litestream-controller.d.ts +0 -78
  1259. package/out/zero-cache/src/services/litestream/litestream-controller.d.ts.map +0 -1
  1260. package/out/zero-cache/src/services/litestream/metrics.d.ts +0 -31
  1261. package/out/zero-cache/src/services/litestream/metrics.d.ts.map +0 -1
  1262. package/out/zero-cache/src/services/litestream/restore-progress.d.ts +0 -24
  1263. package/out/zero-cache/src/services/litestream/restore-progress.d.ts.map +0 -1
  1264. package/out/zero-cache/src/services/mutagen/mutagen.d.ts +0 -40
  1265. package/out/zero-cache/src/services/mutagen/mutagen.d.ts.map +0 -1
  1266. package/out/zero-cache/src/services/mutagen/pusher.d.ts +0 -63
  1267. package/out/zero-cache/src/services/mutagen/pusher.d.ts.map +0 -1
  1268. package/out/zero-cache/src/services/replicator/change-log-db.d.ts +0 -368
  1269. package/out/zero-cache/src/services/replicator/change-log-db.d.ts.map +0 -1
  1270. package/out/zero-cache/src/services/replicator/change-log-stream-writer.d.ts +0 -56
  1271. package/out/zero-cache/src/services/replicator/change-log-stream-writer.d.ts.map +0 -1
  1272. package/out/zero-cache/src/services/replicator/change-processor.d.ts +0 -37
  1273. package/out/zero-cache/src/services/replicator/change-processor.d.ts.map +0 -1
  1274. package/out/zero-cache/src/services/replicator/drain-handler.d.ts +0 -82
  1275. package/out/zero-cache/src/services/replicator/drain-handler.d.ts.map +0 -1
  1276. package/out/zero-cache/src/services/replicator/incremental-sync.d.ts +0 -25
  1277. package/out/zero-cache/src/services/replicator/incremental-sync.d.ts.map +0 -1
  1278. package/out/zero-cache/src/services/replicator/notifier.d.ts +0 -9
  1279. package/out/zero-cache/src/services/replicator/notifier.d.ts.map +0 -1
  1280. package/out/zero-cache/src/services/replicator/replication-status.d.ts +0 -71
  1281. package/out/zero-cache/src/services/replicator/replication-status.d.ts.map +0 -1
  1282. package/out/zero-cache/src/services/replicator/replicator.d.ts +0 -86
  1283. package/out/zero-cache/src/services/replicator/replicator.d.ts.map +0 -1
  1284. package/out/zero-cache/src/services/replicator/reporter/recorder.d.ts +0 -55
  1285. package/out/zero-cache/src/services/replicator/reporter/recorder.d.ts.map +0 -1
  1286. package/out/zero-cache/src/services/replicator/sqlite-change-log-observability.d.ts +0 -132
  1287. package/out/zero-cache/src/services/replicator/sqlite-change-log-observability.d.ts.map +0 -1
  1288. package/out/zero-cache/src/services/replicator/sqlite-change-log-purger.d.ts +0 -120
  1289. package/out/zero-cache/src/services/replicator/sqlite-change-log-purger.d.ts.map +0 -1
  1290. package/out/zero-cache/src/services/replicator/write-worker-client.d.ts +0 -111
  1291. package/out/zero-cache/src/services/replicator/write-worker-client.d.ts.map +0 -1
  1292. package/out/zero-cache/src/services/run-ast.d.ts +0 -39
  1293. package/out/zero-cache/src/services/run-ast.d.ts.map +0 -1
  1294. package/out/zero-cache/src/services/runner.d.ts +0 -19
  1295. package/out/zero-cache/src/services/runner.d.ts.map +0 -1
  1296. package/out/zero-cache/src/services/view-syncer/active-users-gauge.d.ts +0 -17
  1297. package/out/zero-cache/src/services/view-syncer/active-users-gauge.d.ts.map +0 -1
  1298. package/out/zero-cache/src/services/view-syncer/advancement-metrics.d.ts +0 -26
  1299. package/out/zero-cache/src/services/view-syncer/advancement-metrics.d.ts.map +0 -1
  1300. package/out/zero-cache/src/services/view-syncer/batch-pacer.d.ts +0 -79
  1301. package/out/zero-cache/src/services/view-syncer/batch-pacer.d.ts.map +0 -1
  1302. package/out/zero-cache/src/services/view-syncer/client-handler.d.ts +0 -79
  1303. package/out/zero-cache/src/services/view-syncer/client-handler.d.ts.map +0 -1
  1304. package/out/zero-cache/src/services/view-syncer/client-schema.d.ts +0 -5
  1305. package/out/zero-cache/src/services/view-syncer/client-schema.d.ts.map +0 -1
  1306. package/out/zero-cache/src/services/view-syncer/connection-context-manager.d.ts +0 -184
  1307. package/out/zero-cache/src/services/view-syncer/connection-context-manager.d.ts.map +0 -1
  1308. package/out/zero-cache/src/services/view-syncer/cvr-purger.d.ts +0 -22
  1309. package/out/zero-cache/src/services/view-syncer/cvr-purger.d.ts.map +0 -1
  1310. package/out/zero-cache/src/services/view-syncer/cvr-store.d.ts +0 -128
  1311. package/out/zero-cache/src/services/view-syncer/cvr-store.d.ts.map +0 -1
  1312. package/out/zero-cache/src/services/view-syncer/cvr.d.ts +0 -294
  1313. package/out/zero-cache/src/services/view-syncer/cvr.d.ts.map +0 -1
  1314. package/out/zero-cache/src/services/view-syncer/deferred-writes-budget.d.ts +0 -81
  1315. package/out/zero-cache/src/services/view-syncer/deferred-writes-budget.d.ts.map +0 -1
  1316. package/out/zero-cache/src/services/view-syncer/drain-coordinator.d.ts +0 -45
  1317. package/out/zero-cache/src/services/view-syncer/drain-coordinator.d.ts.map +0 -1
  1318. package/out/zero-cache/src/services/view-syncer/e2e-serving-lag.d.ts +0 -53
  1319. package/out/zero-cache/src/services/view-syncer/e2e-serving-lag.d.ts.map +0 -1
  1320. package/out/zero-cache/src/services/view-syncer/hydration-budget.d.ts +0 -33
  1321. package/out/zero-cache/src/services/view-syncer/hydration-budget.d.ts.map +0 -1
  1322. package/out/zero-cache/src/services/view-syncer/hydration-circuit-breaker.d.ts +0 -51
  1323. package/out/zero-cache/src/services/view-syncer/hydration-circuit-breaker.d.ts.map +0 -1
  1324. package/out/zero-cache/src/services/view-syncer/inspect-handler.d.ts +0 -34
  1325. package/out/zero-cache/src/services/view-syncer/inspect-handler.d.ts.map +0 -1
  1326. package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts +0 -296
  1327. package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts.map +0 -1
  1328. package/out/zero-cache/src/services/view-syncer/plan-warnings.d.ts +0 -7
  1329. package/out/zero-cache/src/services/view-syncer/plan-warnings.d.ts.map +0 -1
  1330. package/out/zero-cache/src/services/view-syncer/push-cost.d.ts +0 -132
  1331. package/out/zero-cache/src/services/view-syncer/push-cost.d.ts.map +0 -1
  1332. package/out/zero-cache/src/services/view-syncer/push-cutoff.d.ts +0 -55
  1333. package/out/zero-cache/src/services/view-syncer/push-cutoff.d.ts.map +0 -1
  1334. package/out/zero-cache/src/services/view-syncer/query-covering.d.ts +0 -28
  1335. package/out/zero-cache/src/services/view-syncer/query-covering.d.ts.map +0 -1
  1336. package/out/zero-cache/src/services/view-syncer/query-shape.d.ts +0 -25
  1337. package/out/zero-cache/src/services/view-syncer/query-shape.d.ts.map +0 -1
  1338. package/out/zero-cache/src/services/view-syncer/query-stats.d.ts +0 -89
  1339. package/out/zero-cache/src/services/view-syncer/query-stats.d.ts.map +0 -1
  1340. package/out/zero-cache/src/services/view-syncer/row-record-cache.d.ts +0 -90
  1341. package/out/zero-cache/src/services/view-syncer/row-record-cache.d.ts.map +0 -1
  1342. package/out/zero-cache/src/services/view-syncer/row-set-signature.d.ts +0 -17
  1343. package/out/zero-cache/src/services/view-syncer/row-set-signature.d.ts.map +0 -1
  1344. package/out/zero-cache/src/services/view-syncer/schema/cvr.d.ts +0 -86
  1345. package/out/zero-cache/src/services/view-syncer/schema/cvr.d.ts.map +0 -1
  1346. package/out/zero-cache/src/services/view-syncer/schema/init.d.ts +0 -5
  1347. package/out/zero-cache/src/services/view-syncer/schema/init.d.ts.map +0 -1
  1348. package/out/zero-cache/src/services/view-syncer/schema/types.d.ts +0 -563
  1349. package/out/zero-cache/src/services/view-syncer/schema/types.d.ts.map +0 -1
  1350. package/out/zero-cache/src/services/view-syncer/snapshot-row-cache.d.ts +0 -95
  1351. package/out/zero-cache/src/services/view-syncer/snapshot-row-cache.d.ts.map +0 -1
  1352. package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts +0 -412
  1353. package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts.map +0 -1
  1354. package/out/zero-cache/src/services/view-syncer/tracer.d.ts +0 -2
  1355. package/out/zero-cache/src/services/view-syncer/tracer.d.ts.map +0 -1
  1356. package/out/zero-cache/src/services/view-syncer/ttl-clock.d.ts +0 -10
  1357. package/out/zero-cache/src/services/view-syncer/ttl-clock.d.ts.map +0 -1
  1358. package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts +0 -133
  1359. package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts.map +0 -1
  1360. package/out/zero-cache/src/types/pg-patch.d.ts +0 -21
  1361. package/out/zero-cache/src/types/pg-patch.d.ts.map +0 -1
  1362. package/out/zero-cache/src/types/pg-versions.d.ts +0 -3
  1363. package/out/zero-cache/src/types/pg-versions.d.ts.map +0 -1
  1364. package/out/zero-cache/src/workers/replicator.d.ts +0 -57
  1365. package/out/zero-cache/src/workers/replicator.d.ts.map +0 -1
  1366. package/out/zero-cache/src/workers/syncer-ws-message-handler.d.ts +0 -14
  1367. package/out/zero-cache/src/workers/syncer-ws-message-handler.d.ts.map +0 -1
  1368. package/out/zero-cache/src/workers/syncer.d.ts +0 -67
  1369. package/out/zero-cache/src/workers/syncer.d.ts.map +0 -1
  1370. package/out/zero-events/src/index.d.ts +0 -27
  1371. package/out/zero-events/src/index.d.ts.map +0 -1
  1372. package/out/zero-events/src/json.d.ts +0 -20
  1373. package/out/zero-events/src/json.d.ts.map +0 -1
  1374. package/out/zero-events/src/status.d.ts +0 -144
  1375. package/out/zero-events/src/status.d.ts.map +0 -1
  1376. package/out/zqlite/src/database-storage.d.ts +0 -24
  1377. package/out/zqlite/src/database-storage.d.ts.map +0 -1
  1378. package/out/zqlite/src/explain-queries.d.ts +0 -4
  1379. package/out/zqlite/src/explain-queries.d.ts.map +0 -1
  1380. package/out/zqlite/src/internal/sql-inline.d.ts +0 -13
  1381. package/out/zqlite/src/internal/sql-inline.d.ts.map +0 -1
  1382. package/out/zqlite/src/resolve-scalar-subqueries.d.ts +0 -72
  1383. package/out/zqlite/src/resolve-scalar-subqueries.d.ts.map +0 -1
  1384. package/out/zqlite/src/sqlite-cost-model.d.ts +0 -17
  1385. package/out/zqlite/src/sqlite-cost-model.d.ts.map +0 -1
  1386. package/out/zqlite/src/sqlite-stat-fanout.d.ts +0 -121
  1387. package/out/zqlite/src/sqlite-stat-fanout.d.ts.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"published.js","names":[],"sources":["../../../../../../../../zero-cache/src/services/change-source/pg/schema/published.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {literal} from 'pg-format';\nimport type postgres from 'postgres';\nimport {assert} from '../../../../../../shared/src/asserts.ts';\nimport {BigIntJSON} from '../../../../../../shared/src/bigint-json.ts';\nimport {equals} from '../../../../../../shared/src/set-utils.ts';\nimport * as v from '../../../../../../shared/src/valita.ts';\nimport {computeZqlSpecsFromLiteSpecs} from '../../../../db/lite-tables.ts';\nimport {\n mapPostgresToLite,\n mapPostgresToLiteIndex,\n} from '../../../../db/pg-to-lite.ts';\nimport {\n publishedColumnSpec,\n publishedIndexSpec,\n publishedTableSpec,\n type PublishedIndexSpec,\n} from '../../../../db/specs.ts';\nimport {getOrCreateCounter} from '../../../../observability/metrics.ts';\nimport {liteTableName} from '../../../../types/names.ts';\nimport {\n translatePostgresIndexPredicate,\n type UnsupportedPredicateReason,\n} from './index-predicate.ts';\n\nexport function publishedSchemaQuery(\n publications: readonly string[],\n includePartialIndexes = true,\n) {\n // Notes:\n // * There's a bug in PG15 in which generated columns are incorrectly\n // included in pg_publication_tables.attnames, (even though the generated\n // column values are not be included in the replication stream).\n // The WHERE condition `attgenerated = ''` fixes this by explicitly excluding\n // generated columns from the list.\n return (\n /*sql*/ `\nWITH published_columns AS (SELECT \n pc.oid::int8 AS \"oid\",\n nspname AS \"schema\",\n pc.relnamespace::int8 AS \"schemaOID\" ,\n pc.relname AS \"name\", \n pc.relreplident AS \"replicaIdentity\",\n attnum AS \"pos\", \n attname AS \"col\", \n pt.typname AS \"type\", \n atttypid::int8 AS \"typeOID\", \n pt.typtype,\n elem_pt.typtype AS \"elemTyptype\",\n coll.collisdeterministic AS \"collationIsDeterministic\",\n NULLIF(atttypmod, -1) AS \"maxLen\", \n attndims \"arrayDims\", \n attnotnull AS \"notNull\",\n pg_get_expr(pd.adbin, pd.adrelid) as \"dflt\",\n NULLIF(ARRAY_POSITION(conkey, attnum), -1) AS \"keyPos\", \n pb.rowfilter as \"rowFilter\",\n pb.pubname as \"publication\"\nFROM pg_attribute\nJOIN pg_class pc ON pc.oid = attrelid\nJOIN pg_namespace pns ON pns.oid = relnamespace\nJOIN pg_type pt ON atttypid = pt.oid\nLEFT JOIN pg_type elem_pt ON elem_pt.oid = pt.typelem\nLEFT JOIN pg_collation coll ON coll.oid = pg_attribute.attcollation\nJOIN pg_publication_tables as pb ON \n pb.schemaname = nspname AND \n pb.tablename = pc.relname AND\n attname = ANY(pb.attnames)\nLEFT JOIN pg_constraint pk ON pk.contype = 'p' AND pk.connamespace = relnamespace AND pk.conrelid = attrelid\nLEFT JOIN pg_attrdef pd ON pd.adrelid = attrelid AND pd.adnum = attnum\nWHERE pb.pubname IN (${literal(publications)}) AND \n (current_setting('server_version_num')::int >= 160000 OR attgenerated = '')\nORDER BY nspname, pc.relname),\n\ntables AS (SELECT json_build_object(\n 'oid', \"oid\",\n 'schema', \"schema\", \n 'schemaOID', \"schemaOID\",\n 'name', \"name\", \n 'replicaIdentity', \"replicaIdentity\",\n 'columns', json_object_agg(\n DISTINCT\n col,\n jsonb_build_object(\n 'pos', \"pos\",\n 'dataType', CASE WHEN \"arrayDims\" = 0 \n THEN \"type\" \n ELSE substring(\"type\" from 2) || repeat('[]', \"arrayDims\") END,\n 'pgTypeClass', \"typtype\",\n 'elemPgTypeClass', \"elemTyptype\",\n 'typeOID', \"typeOID\",\n 'collationIsDeterministic', \"collationIsDeterministic\",\n -- https://stackoverflow.com/a/52376230\n 'characterMaximumLength', CASE WHEN \"typeOID\" = 1043 OR \"typeOID\" = 1042 \n THEN \"maxLen\" - 4 \n ELSE \"maxLen\" END,\n 'notNull', \"notNull\",\n 'dflt', \"dflt\"\n )\n ),\n 'primaryKey', ARRAY( SELECT json_object_keys(\n json_strip_nulls(\n json_object_agg(\n DISTINCT \"col\", \"keyPos\" ORDER BY \"keyPos\"\n )\n )\n )),\n 'publications', json_object_agg(\n DISTINCT \n \"publication\", \n jsonb_build_object('rowFilter', \"rowFilter\")\n )\n) AS \"table\" FROM published_columns \n GROUP BY \"schema\", \"schemaOID\", \"name\", \"oid\", \"replicaIdentity\"),\n ` +\n // Note: pg_attribute contains column names for tables and for indexes.\n // However, the latter does not get updated when a column in a table is\n // renamed.\n //\n // https://www.postgresql.org/message-id/5860814f-c91d-4ab0-b771-ded90d7b9c55%40www.fastmail.com\n //\n // To address this, the pg_attribute rows are looked up for the index's\n // table rather than the index itself, using the pg_index.indkey array\n // to determine the set and order of columns to include.\n //\n // Notes:\n // * The first bit of indoption is 1 for DESC and 0 for ASC:\n // https://github.com/postgres/postgres/blob/4e1fad37872e49a711adad5d9870516e5c71a375/src/include/catalog/pg_index.h#L89\n // * pg_index.indkey is an int2vector which is 0-based instead of 1-based.\n // * The additional check for attgenerated is required for the aforementioned\n // (in publishedTableQuery) bug in PG15 in which generated columns are\n // incorrectly included in pg_publication_tables.attnames\n /*sql*/ `\n indexed_columns AS (SELECT\n pg_indexes.schemaname as \"schema\",\n pg_indexes.tablename as \"tableName\",\n pg_indexes.indexname as \"name\",\n index_column.name as \"col\",\n CASE WHEN pg_index.indoption[index_column.pos-1] & 1 = 1 THEN 'DESC' ELSE 'ASC' END as \"dir\",\n -- Partial indexes are always reported as non-unique. Nothing on the\n -- replica relies on the uniqueness of a partial index (it cannot serve\n -- as a row key), and reporting it as non-unique keeps the ddl event\n -- format compatible with older versions of the zero-cache, which\n -- ignore \"predicateSQL\" and would otherwise create a full UNIQUE index\n -- on the replica.\n (pg_index.indisunique AND pg_index.indpred IS NULL) as \"unique\",\n pg_index.indisprimary as \"isPrimaryKey\",\n pg_index.indisreplident as \"isReplicaIdentity\",\n pg_index.indimmediate as \"isImmediate\",\n pg_get_expr(pg_index.indpred, pg_index.indrelid, false) as \"predicateSQL\"\n FROM pg_indexes\n JOIN pg_namespace ON pg_indexes.schemaname = pg_namespace.nspname\n JOIN pg_class pc ON\n pc.relname = pg_indexes.indexname\n AND pc.relnamespace = pg_namespace.oid\n JOIN pg_publication_tables as pb ON \n pb.schemaname = pg_indexes.schemaname AND \n pb.tablename = pg_indexes.tablename\n JOIN pg_index ON pg_index.indexrelid = pc.oid\n JOIN LATERAL (\n SELECT array_agg(attname) as attnames, array_agg(attgenerated != '') as generated FROM pg_attribute\n WHERE attrelid = pg_index.indrelid\n AND attnum = ANY( (pg_index.indkey::smallint[] )[:pg_index.indnkeyatts - 1] )\n ) as indexed ON true\n JOIN LATERAL (\n SELECT pg_attribute.attname as name, col.index_pos as pos\n FROM UNNEST( (pg_index.indkey::smallint[])[:pg_index.indnkeyatts - 1] ) \n WITH ORDINALITY as col(table_pos, index_pos)\n JOIN pg_attribute ON attrelid = pg_index.indrelid AND attnum = col.table_pos\n ) AS index_column ON true\n LEFT JOIN pg_constraint ON pg_constraint.conindid = pc.oid\n WHERE pb.pubname IN (${literal(publications)})\n AND pg_index.indexprs IS NULL\n AND (${includePartialIndexes} OR pg_index.indpred IS NULL)\n AND (pg_constraint.contype IS NULL OR pg_constraint.contype IN ('p', 'u'))\n AND indexed.attnames <@ pb.attnames\n AND (current_setting('server_version_num')::int >= 160000 OR false = ALL(indexed.generated))\n ORDER BY\n pg_indexes.schemaname,\n pg_indexes.tablename,\n pg_indexes.indexname,\n index_column.pos ASC),\n \n indexes AS (SELECT json_build_object(\n 'schema', \"schema\",\n 'tableName', \"tableName\",\n 'name', \"name\",\n 'unique', \"unique\",\n 'isPrimaryKey', \"isPrimaryKey\",\n 'isReplicaIdentity', \"isReplicaIdentity\",\n 'isImmediate', \"isImmediate\",\n 'predicateSQL', \"predicateSQL\",\n 'columns', json_object_agg(\"col\", \"dir\")\n ) AS index FROM indexed_columns \n GROUP BY \"schema\", \"tableName\", \"name\", \"unique\", \n \"isPrimaryKey\", \"isReplicaIdentity\", \"isImmediate\", \"predicateSQL\")\n\n SELECT json_build_object(\n 'tables', COALESCE((SELECT json_agg(\"table\") FROM tables), '[]'::json),\n 'indexes', COALESCE((SELECT json_agg(\"index\") FROM indexes), '[]'::json)\n ) as \"publishedSchema\"\n `\n );\n}\n\nconst rawPublishedColumnSpec = publishedColumnSpec.extend({\n collationIsDeterministic: v.boolean().nullable().optional(),\n});\n\nconst rawPublishedTableSpec = publishedTableSpec.extend({\n columns: v.record(rawPublishedColumnSpec),\n});\n\nconst rawPublishedIndexSpec = publishedIndexSpec.extend({\n predicateSQL: v.string().nullable().optional(),\n});\n\nexport type SkippedIndexDiagnostic = {\n readonly schema: string;\n readonly index: string;\n readonly predicate: string;\n readonly reason: UnsupportedPredicateReason;\n};\n\nconst skippedIndexDiagnostics = new WeakMap<\n object,\n readonly SkippedIndexDiagnostic[]\n>();\nexport function getSkippedIndexDiagnostics(\n schema: PublishedSchema,\n): readonly SkippedIndexDiagnostic[] {\n return skippedIndexDiagnostics.get(schema) ?? [];\n}\n\nexport function warnForSkippedIndexes(\n lc: LogContext,\n schema: PublishedSchema,\n warned: Set<string> = new Set(),\n): void {\n for (const diagnostic of getSkippedIndexDiagnostics(schema)) {\n const key = JSON.stringify(diagnostic);\n if (warned.has(key)) continue;\n warned.add(key);\n lc.warn?.('Skipping unsupported PostgreSQL partial index', diagnostic);\n getOrCreateCounter('replication', 'skipped_index', {\n description: 'Number of PostgreSQL indexes skipped during replication.',\n unit: '{index}',\n }).add(1, {reason: diagnostic.reason, partial: true});\n }\n}\n\nexport const publishedSchema = v\n .object({\n tables: v.array(rawPublishedTableSpec),\n indexes: v.array(rawPublishedIndexSpec),\n })\n .map(({tables: rawTables, indexes: rawIndexes}) => {\n const diagnostics: SkippedIndexDiagnostic[] = [];\n const indexes: PublishedIndexSpec[] = [];\n for (const rawIndex of rawIndexes) {\n const {predicateSQL, ...index} = rawIndex;\n if (predicateSQL !== null && predicateSQL !== undefined) {\n const table = rawTables.find(\n candidate =>\n candidate.schema === index.schema &&\n candidate.name === index.tableName,\n );\n const translation = table\n ? translatePostgresIndexPredicate(predicateSQL, table)\n : {supported: false as const, reason: 'unpublished-column' as const};\n if (!translation.supported) {\n diagnostics.push({\n schema: index.schema,\n index: index.name,\n predicate: predicateSQL,\n reason: translation.reason,\n });\n continue;\n }\n indexes.push({...index, predicate: translation.predicate});\n } else {\n indexes.push(index);\n }\n }\n\n const tables = rawTables.map(table => ({\n ...table,\n columns: Object.fromEntries(\n Object.entries(table.columns).map(\n ([name, {collationIsDeterministic: _, ...column}]) => [name, column],\n ),\n ),\n }));\n const zqlSpecs = computeZqlSpecsFromLiteSpecs(\n tables.map(t => mapPostgresToLite(t)),\n indexes.map(mapPostgresToLiteIndex),\n {includeBackfillingColumns: true},\n );\n const result = {\n indexes,\n\n // Denormalize the schema such that each `table` includes the\n // `replicaIdentityColumns` corresponding to the table's\n // replica identity and associated primary key or index.\n tables: tables.map(table => {\n const replicaIdentityColumns: string[] = [];\n switch (table.replicaIdentity) {\n case 'd':\n replicaIdentityColumns.push(...(table.primaryKey ?? []));\n break;\n case 'i':\n replicaIdentityColumns.push(\n ...Object.keys(\n indexes.find(\n ind =>\n ind.schema === table.schema &&\n ind.tableName === table.name &&\n ind.isReplicaIdentity,\n )?.columns ?? {},\n ),\n );\n break;\n case 'f': {\n // For the key columns of replica identity \"full\", use the columns\n // that the replicator/change-processor will end up using\n // (in #getKey()) as the row key.\n const zqlTable = zqlSpecs.get(liteTableName(table));\n // Note: There zql spec will be absent if the table is not synced,\n // e.g. if it has no suitable unique indexes.\n if (zqlTable) {\n replicaIdentityColumns.push(...zqlTable.tableSpec.primaryKey);\n }\n break;\n }\n }\n return {\n ...table,\n replicaIdentityColumns,\n };\n }),\n };\n skippedIndexDiagnostics.set(result, diagnostics);\n return result;\n });\n\nexport type PublishedSchema = v.Infer<typeof publishedSchema>;\n\nexport type PublishedTableWithReplicaIdentity =\n PublishedSchema['tables'][number];\n\nconst publicationSchema = v.object({\n pubname: v.string(),\n pubinsert: v.boolean(),\n pubupdate: v.boolean(),\n pubdelete: v.boolean(),\n pubtruncate: v.boolean(),\n});\n\nconst publicationsResultSchema = v.array(publicationSchema);\n\nexport type PublicationInfo = PublishedSchema & {\n publications: v.Infer<typeof publicationsResultSchema>;\n};\n\n/**\n * Retrieves published tables and columns.\n */\nexport async function getPublicationInfo(\n sql: postgres.Sql,\n publications: string[],\n): Promise<PublicationInfo> {\n const result = await sql.unsafe(/*sql*/ `\n SELECT \n schemaname AS \"schema\",\n tablename AS \"table\", \n json_object_agg(pubname, attnames) AS \"publications\"\n FROM pg_publication_tables pb\n WHERE pb.pubname IN (${literal(publications)})\n GROUP BY schemaname, tablename;\n\n SELECT ${Object.keys(publicationSchema.shape).join(\n ',',\n )} FROM pg_publication pb\n WHERE pb.pubname IN (${literal(publications)})\n ORDER BY pubname;\n\n ${publishedSchemaQuery(publications)};\n`);\n\n // The first query is used to check that tables in multiple publications\n // always publish the same set of columns.\n const publishedColumns = result[0] as {\n schema: string;\n table: string;\n publications: Record<string, string[]>;\n }[];\n for (const {table, publications} of publishedColumns) {\n let expected: Set<string>;\n Object.entries(publications).forEach(([_, columns], i) => {\n const cols = new Set(columns);\n if (i === 0) {\n expected = cols;\n } else if (!equals(expected, cols)) {\n throw new Error(\n `Table ${table} is exported with different columns: [${[\n ...expected,\n ]}] vs [${[...cols]}]`,\n );\n }\n });\n }\n\n assert(\n result[2][0].publishedSchema,\n () => `Invalid publishedSchema result ${BigIntJSON.stringify(result[2])}`,\n );\n\n const schema = v.parse(result[2][0].publishedSchema, publishedSchema);\n const info = {\n publications: v.parse(result[1], publicationsResultSchema),\n ...schema,\n };\n skippedIndexDiagnostics.set(info, getSkippedIndexDiagnostics(schema));\n return info;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"published.js","names":["v","v.parse"],"sources":["../../../../../../../../zero-cache/src/services/change-source/pg/schema/published.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {literal} from 'pg-format';\nimport type postgres from 'postgres';\nimport {assert} from '../../../../../../shared/src/asserts.ts';\nimport {BigIntJSON} from '../../../../../../shared/src/bigint-json.ts';\nimport {equals} from '../../../../../../shared/src/set-utils.ts';\nimport * as v from '../../../../../../shared/src/valita.ts';\nimport {computeZqlSpecsFromLiteSpecs} from '../../../../db/lite-tables.ts';\nimport {\n mapPostgresToLite,\n mapPostgresToLiteIndex,\n} from '../../../../db/pg-to-lite.ts';\nimport {\n publishedColumnSpec,\n publishedIndexSpec,\n publishedTableSpec,\n type PublishedIndexSpec,\n} from '../../../../db/specs.ts';\nimport {getOrCreateCounter} from '../../../../observability/metrics.ts';\nimport {liteTableName} from '../../../../types/names.ts';\nimport {\n translatePostgresIndexPredicate,\n type UnsupportedPredicateReason,\n} from './index-predicate.ts';\n\nexport function publishedSchemaQuery(\n publications: readonly string[],\n includePartialIndexes = true,\n) {\n // Notes:\n // * There's a bug in PG15 in which generated columns are incorrectly\n // included in pg_publication_tables.attnames, (even though the generated\n // column values are not be included in the replication stream).\n // The WHERE condition `attgenerated = ''` fixes this by explicitly excluding\n // generated columns from the list.\n return (\n /*sql*/ `\nWITH published_columns AS (SELECT \n pc.oid::int8 AS \"oid\",\n nspname AS \"schema\",\n pc.relnamespace::int8 AS \"schemaOID\" ,\n pc.relname AS \"name\", \n pc.relreplident AS \"replicaIdentity\",\n attnum AS \"pos\", \n attname AS \"col\", \n pt.typname AS \"type\", \n atttypid::int8 AS \"typeOID\", \n pt.typtype,\n elem_pt.typtype AS \"elemTyptype\",\n coll.collisdeterministic AS \"collationIsDeterministic\",\n NULLIF(atttypmod, -1) AS \"maxLen\", \n attndims \"arrayDims\", \n attnotnull AS \"notNull\",\n pg_get_expr(pd.adbin, pd.adrelid) as \"dflt\",\n NULLIF(ARRAY_POSITION(conkey, attnum), -1) AS \"keyPos\", \n pb.rowfilter as \"rowFilter\",\n pb.pubname as \"publication\"\nFROM pg_attribute\nJOIN pg_class pc ON pc.oid = attrelid\nJOIN pg_namespace pns ON pns.oid = relnamespace\nJOIN pg_type pt ON atttypid = pt.oid\nLEFT JOIN pg_type elem_pt ON elem_pt.oid = pt.typelem\nLEFT JOIN pg_collation coll ON coll.oid = pg_attribute.attcollation\nJOIN pg_publication_tables as pb ON \n pb.schemaname = nspname AND \n pb.tablename = pc.relname AND\n attname = ANY(pb.attnames)\nLEFT JOIN pg_constraint pk ON pk.contype = 'p' AND pk.connamespace = relnamespace AND pk.conrelid = attrelid\nLEFT JOIN pg_attrdef pd ON pd.adrelid = attrelid AND pd.adnum = attnum\nWHERE pb.pubname IN (${literal(publications)}) AND \n (current_setting('server_version_num')::int >= 160000 OR attgenerated = '')\nORDER BY nspname, pc.relname),\n\ntables AS (SELECT json_build_object(\n 'oid', \"oid\",\n 'schema', \"schema\", \n 'schemaOID', \"schemaOID\",\n 'name', \"name\", \n 'replicaIdentity', \"replicaIdentity\",\n 'columns', json_object_agg(\n DISTINCT\n col,\n jsonb_build_object(\n 'pos', \"pos\",\n 'dataType', CASE WHEN \"arrayDims\" = 0 \n THEN \"type\" \n ELSE substring(\"type\" from 2) || repeat('[]', \"arrayDims\") END,\n 'pgTypeClass', \"typtype\",\n 'elemPgTypeClass', \"elemTyptype\",\n 'typeOID', \"typeOID\",\n 'collationIsDeterministic', \"collationIsDeterministic\",\n -- https://stackoverflow.com/a/52376230\n 'characterMaximumLength', CASE WHEN \"typeOID\" = 1043 OR \"typeOID\" = 1042 \n THEN \"maxLen\" - 4 \n ELSE \"maxLen\" END,\n 'notNull', \"notNull\",\n 'dflt', \"dflt\"\n )\n ),\n 'primaryKey', ARRAY( SELECT json_object_keys(\n json_strip_nulls(\n json_object_agg(\n DISTINCT \"col\", \"keyPos\" ORDER BY \"keyPos\"\n )\n )\n )),\n 'publications', json_object_agg(\n DISTINCT \n \"publication\", \n jsonb_build_object('rowFilter', \"rowFilter\")\n )\n) AS \"table\" FROM published_columns \n GROUP BY \"schema\", \"schemaOID\", \"name\", \"oid\", \"replicaIdentity\"),\n ` +\n // Note: pg_attribute contains column names for tables and for indexes.\n // However, the latter does not get updated when a column in a table is\n // renamed.\n //\n // https://www.postgresql.org/message-id/5860814f-c91d-4ab0-b771-ded90d7b9c55%40www.fastmail.com\n //\n // To address this, the pg_attribute rows are looked up for the index's\n // table rather than the index itself, using the pg_index.indkey array\n // to determine the set and order of columns to include.\n //\n // Notes:\n // * The first bit of indoption is 1 for DESC and 0 for ASC:\n // https://github.com/postgres/postgres/blob/4e1fad37872e49a711adad5d9870516e5c71a375/src/include/catalog/pg_index.h#L89\n // * pg_index.indkey is an int2vector which is 0-based instead of 1-based.\n // * The additional check for attgenerated is required for the aforementioned\n // (in publishedTableQuery) bug in PG15 in which generated columns are\n // incorrectly included in pg_publication_tables.attnames\n /*sql*/ `\n indexed_columns AS (SELECT\n pg_indexes.schemaname as \"schema\",\n pg_indexes.tablename as \"tableName\",\n pg_indexes.indexname as \"name\",\n index_column.name as \"col\",\n CASE WHEN pg_index.indoption[index_column.pos-1] & 1 = 1 THEN 'DESC' ELSE 'ASC' END as \"dir\",\n -- Partial indexes are always reported as non-unique. Nothing on the\n -- replica relies on the uniqueness of a partial index (it cannot serve\n -- as a row key), and reporting it as non-unique keeps the ddl event\n -- format compatible with older versions of the zero-cache, which\n -- ignore \"predicateSQL\" and would otherwise create a full UNIQUE index\n -- on the replica.\n (pg_index.indisunique AND pg_index.indpred IS NULL) as \"unique\",\n pg_index.indisprimary as \"isPrimaryKey\",\n pg_index.indisreplident as \"isReplicaIdentity\",\n pg_index.indimmediate as \"isImmediate\",\n pg_get_expr(pg_index.indpred, pg_index.indrelid, false) as \"predicateSQL\"\n FROM pg_indexes\n JOIN pg_namespace ON pg_indexes.schemaname = pg_namespace.nspname\n JOIN pg_class pc ON\n pc.relname = pg_indexes.indexname\n AND pc.relnamespace = pg_namespace.oid\n JOIN pg_publication_tables as pb ON \n pb.schemaname = pg_indexes.schemaname AND \n pb.tablename = pg_indexes.tablename\n JOIN pg_index ON pg_index.indexrelid = pc.oid\n JOIN LATERAL (\n SELECT array_agg(attname) as attnames, array_agg(attgenerated != '') as generated FROM pg_attribute\n WHERE attrelid = pg_index.indrelid\n AND attnum = ANY( (pg_index.indkey::smallint[] )[:pg_index.indnkeyatts - 1] )\n ) as indexed ON true\n JOIN LATERAL (\n SELECT pg_attribute.attname as name, col.index_pos as pos\n FROM UNNEST( (pg_index.indkey::smallint[])[:pg_index.indnkeyatts - 1] ) \n WITH ORDINALITY as col(table_pos, index_pos)\n JOIN pg_attribute ON attrelid = pg_index.indrelid AND attnum = col.table_pos\n ) AS index_column ON true\n LEFT JOIN pg_constraint ON pg_constraint.conindid = pc.oid\n WHERE pb.pubname IN (${literal(publications)})\n AND pg_index.indexprs IS NULL\n AND (${includePartialIndexes} OR pg_index.indpred IS NULL)\n AND (pg_constraint.contype IS NULL OR pg_constraint.contype IN ('p', 'u'))\n AND indexed.attnames <@ pb.attnames\n AND (current_setting('server_version_num')::int >= 160000 OR false = ALL(indexed.generated))\n ORDER BY\n pg_indexes.schemaname,\n pg_indexes.tablename,\n pg_indexes.indexname,\n index_column.pos ASC),\n \n indexes AS (SELECT json_build_object(\n 'schema', \"schema\",\n 'tableName', \"tableName\",\n 'name', \"name\",\n 'unique', \"unique\",\n 'isPrimaryKey', \"isPrimaryKey\",\n 'isReplicaIdentity', \"isReplicaIdentity\",\n 'isImmediate', \"isImmediate\",\n 'predicateSQL', \"predicateSQL\",\n 'columns', json_object_agg(\"col\", \"dir\")\n ) AS index FROM indexed_columns \n GROUP BY \"schema\", \"tableName\", \"name\", \"unique\", \n \"isPrimaryKey\", \"isReplicaIdentity\", \"isImmediate\", \"predicateSQL\")\n\n SELECT json_build_object(\n 'tables', COALESCE((SELECT json_agg(\"table\") FROM tables), '[]'::json),\n 'indexes', COALESCE((SELECT json_agg(\"index\") FROM indexes), '[]'::json)\n ) as \"publishedSchema\"\n `\n );\n}\n\nconst rawPublishedColumnSpec = publishedColumnSpec.extend({\n collationIsDeterministic: v.boolean().nullable().optional(),\n});\n\nconst rawPublishedTableSpec = publishedTableSpec.extend({\n columns: v.record(rawPublishedColumnSpec),\n});\n\nconst rawPublishedIndexSpec = publishedIndexSpec.extend({\n predicateSQL: v.string().nullable().optional(),\n});\n\nexport type SkippedIndexDiagnostic = {\n readonly schema: string;\n readonly index: string;\n readonly predicate: string;\n readonly reason: UnsupportedPredicateReason;\n};\n\nconst skippedIndexDiagnostics = new WeakMap<\n object,\n readonly SkippedIndexDiagnostic[]\n>();\nexport function getSkippedIndexDiagnostics(\n schema: PublishedSchema,\n): readonly SkippedIndexDiagnostic[] {\n return skippedIndexDiagnostics.get(schema) ?? [];\n}\n\nexport function warnForSkippedIndexes(\n lc: LogContext,\n schema: PublishedSchema,\n warned: Set<string> = new Set(),\n): void {\n for (const diagnostic of getSkippedIndexDiagnostics(schema)) {\n const key = JSON.stringify(diagnostic);\n if (warned.has(key)) continue;\n warned.add(key);\n lc.warn?.('Skipping unsupported PostgreSQL partial index', diagnostic);\n getOrCreateCounter('replication', 'skipped_index', {\n description: 'Number of PostgreSQL indexes skipped during replication.',\n unit: '{index}',\n }).add(1, {reason: diagnostic.reason, partial: true});\n }\n}\n\nexport const publishedSchema = v\n .object({\n tables: v.array(rawPublishedTableSpec),\n indexes: v.array(rawPublishedIndexSpec),\n })\n .map(({tables: rawTables, indexes: rawIndexes}) => {\n const diagnostics: SkippedIndexDiagnostic[] = [];\n const indexes: PublishedIndexSpec[] = [];\n for (const rawIndex of rawIndexes) {\n const {predicateSQL, ...index} = rawIndex;\n if (predicateSQL !== null && predicateSQL !== undefined) {\n const table = rawTables.find(\n candidate =>\n candidate.schema === index.schema &&\n candidate.name === index.tableName,\n );\n const translation = table\n ? translatePostgresIndexPredicate(predicateSQL, table)\n : {supported: false as const, reason: 'unpublished-column' as const};\n if (!translation.supported) {\n diagnostics.push({\n schema: index.schema,\n index: index.name,\n predicate: predicateSQL,\n reason: translation.reason,\n });\n continue;\n }\n indexes.push({...index, predicate: translation.predicate});\n } else {\n indexes.push(index);\n }\n }\n\n const tables = rawTables.map(table => ({\n ...table,\n columns: Object.fromEntries(\n Object.entries(table.columns).map(\n ([name, {collationIsDeterministic: _, ...column}]) => [name, column],\n ),\n ),\n }));\n const zqlSpecs = computeZqlSpecsFromLiteSpecs(\n tables.map(t => mapPostgresToLite(t)),\n indexes.map(mapPostgresToLiteIndex),\n {includeBackfillingColumns: true},\n );\n const result = {\n indexes,\n\n // Denormalize the schema such that each `table` includes the\n // `replicaIdentityColumns` corresponding to the table's\n // replica identity and associated primary key or index.\n tables: tables.map(table => {\n const replicaIdentityColumns: string[] = [];\n switch (table.replicaIdentity) {\n case 'd':\n replicaIdentityColumns.push(...(table.primaryKey ?? []));\n break;\n case 'i':\n replicaIdentityColumns.push(\n ...Object.keys(\n indexes.find(\n ind =>\n ind.schema === table.schema &&\n ind.tableName === table.name &&\n ind.isReplicaIdentity,\n )?.columns ?? {},\n ),\n );\n break;\n case 'f': {\n // For the key columns of replica identity \"full\", use the columns\n // that the replicator/change-processor will end up using\n // (in #getKey()) as the row key.\n const zqlTable = zqlSpecs.get(liteTableName(table));\n // Note: There zql spec will be absent if the table is not synced,\n // e.g. if it has no suitable unique indexes.\n if (zqlTable) {\n replicaIdentityColumns.push(...zqlTable.tableSpec.primaryKey);\n }\n break;\n }\n }\n return {\n ...table,\n replicaIdentityColumns,\n };\n }),\n };\n skippedIndexDiagnostics.set(result, diagnostics);\n return result;\n });\n\nexport type PublishedSchema = v.Infer<typeof publishedSchema>;\n\nexport type PublishedTableWithReplicaIdentity =\n PublishedSchema['tables'][number];\n\nconst publicationSchema = v.object({\n pubname: v.string(),\n pubinsert: v.boolean(),\n pubupdate: v.boolean(),\n pubdelete: v.boolean(),\n pubtruncate: v.boolean(),\n});\n\nconst publicationsResultSchema = v.array(publicationSchema);\n\nexport type PublicationInfo = PublishedSchema & {\n publications: v.Infer<typeof publicationsResultSchema>;\n};\n\n/**\n * Retrieves published tables and columns.\n */\nexport async function getPublicationInfo(\n sql: postgres.Sql,\n publications: string[],\n): Promise<PublicationInfo> {\n const result = await sql.unsafe(/*sql*/ `\n SELECT \n schemaname AS \"schema\",\n tablename AS \"table\", \n json_object_agg(pubname, attnames) AS \"publications\"\n FROM pg_publication_tables pb\n WHERE pb.pubname IN (${literal(publications)})\n GROUP BY schemaname, tablename;\n\n SELECT ${Object.keys(publicationSchema.shape).join(\n ',',\n )} FROM pg_publication pb\n WHERE pb.pubname IN (${literal(publications)})\n ORDER BY pubname;\n\n ${publishedSchemaQuery(publications)};\n`);\n\n // The first query is used to check that tables in multiple publications\n // always publish the same set of columns.\n const publishedColumns = result[0] as {\n schema: string;\n table: string;\n publications: Record<string, string[]>;\n }[];\n for (const {table, publications} of publishedColumns) {\n let expected: Set<string>;\n Object.entries(publications).forEach(([_, columns], i) => {\n const cols = new Set(columns);\n if (i === 0) {\n expected = cols;\n } else if (!equals(expected, cols)) {\n throw new Error(\n `Table ${table} is exported with different columns: [${[\n ...expected,\n ]}] vs [${[...cols]}]`,\n );\n }\n });\n }\n\n assert(\n result[2][0].publishedSchema,\n () => `Invalid publishedSchema result ${BigIntJSON.stringify(result[2])}`,\n );\n\n const schema = v.parse(result[2][0].publishedSchema, publishedSchema);\n const info = {\n publications: v.parse(result[1], publicationsResultSchema),\n ...schema,\n };\n skippedIndexDiagnostics.set(info, getSkippedIndexDiagnostics(schema));\n return info;\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"replica-stage-enum.js","names":[],"sources":["../../../../../../../../zero-cache/src/services/change-source/pg/schema/replica-stage-enum.ts"],"sourcesContent":["import * as v from '../../../../../../shared/src/valita.ts';\n\n// Note: The stages are ordered by restore availability:\n// * InitialSync is the first to create the generation, by definition.\n// * Replicate has already restored and thus can be restored from\n// * Restore is in the process of awaiting the backup\nexport const InitialSync = 0;\nexport const Replicate = 1;\nexport const Restore = 2;\n\nexport type InitialSync = typeof InitialSync;\nexport type Replicate = typeof Replicate;\nexport type Restore = typeof Restore;\n\nexport const replicaStageSchema = v.literalUnion(\n InitialSync,\n Replicate,\n Restore,\n);\n\nexport type ReplicaStage = v.Infer<typeof replicaStageSchema>;\n"],"mappings":";AAcA,IAAa,qBAAqB,aAAA,GAAA,GAAA,CAIlC"}
1
+ {"version":3,"file":"replica-stage-enum.js","names":["v.literalUnion"],"sources":["../../../../../../../../zero-cache/src/services/change-source/pg/schema/replica-stage-enum.ts"],"sourcesContent":["import * as v from '../../../../../../shared/src/valita.ts';\n\n// Note: The stages are ordered by restore availability:\n// * InitialSync is the first to create the generation, by definition.\n// * Replicate has already restored and thus can be restored from\n// * Restore is in the process of awaiting the backup\nexport const InitialSync = 0;\nexport const Replicate = 1;\nexport const Restore = 2;\n\nexport type InitialSync = typeof InitialSync;\nexport type Replicate = typeof Replicate;\nexport type Restore = typeof Restore;\n\nexport const replicaStageSchema = v.literalUnion(\n InitialSync,\n Replicate,\n Restore,\n);\n\nexport type ReplicaStage = v.Infer<typeof replicaStageSchema>;\n"],"mappings":";AAcA,IAAa,qBAAqBA,aAAAA,GAAAA,GAAAA,CAIlC"}
@@ -2,8 +2,8 @@ import { assert } from "../../../../../../shared/src/asserts.js";
2
2
  import { parse, valita_exports } from "../../../../../../shared/src/valita.js";
3
3
  import { jsonObjectSchema, stringify } from "../../../../../../shared/src/bigint-json.js";
4
4
  import { appSchema, check, upstreamSchema } from "../../../../types/shards.js";
5
- import { id } from "../../../../types/sql.js";
6
5
  import { getPublicationInfo, publishedSchema } from "./published.js";
6
+ import { id } from "../../../../types/sql.js";
7
7
  import { createEventFunctionStatements, createEventTriggerStatements } from "./ddl.js";
8
8
  import { replicaStageSchema } from "./replica-stage-enum.js";
9
9
  import { validate } from "./validation.js";
@@ -168,8 +168,9 @@ function shardSetup(shardConfig, metadataPublication) {
168
168
  function dropShard(appID, shardID) {
169
169
  const schema = `${appID}_${shardID}`;
170
170
  const metadataPublication = metadataPublicationName(appID, shardID);
171
+ const defaultPublication = defaultPublicationName(appID, shardID);
171
172
  return `
172
- DROP PUBLICATION IF EXISTS ${id(defaultPublicationName(appID, shardID))};
173
+ DROP PUBLICATION IF EXISTS ${id(defaultPublication)};
173
174
  DROP PUBLICATION IF EXISTS ${id(metadataPublication)};
174
175
  DROP SCHEMA IF EXISTS ${id(schema)} CASCADE;
175
176
  `;
@@ -296,7 +297,7 @@ async function getReplicaAtVersion(lc, sql, shard, replicaVersion, id = null, co
296
297
  return parse(result[0], replicaSchema, "passthrough");
297
298
  }
298
299
  async function getActiveReplicas(lc, sql, shard) {
299
- const replicas = parse(await sql`
300
+ const results = await sql`
300
301
  SELECT
301
302
  replicas."id",
302
303
  replicas."rank",
@@ -317,7 +318,8 @@ async function getActiveReplicas(lc, sql, shard) {
317
318
  AND slots.restart_lsn IS NOT NULL
318
319
  AND slots.wal_status IS DISTINCT FROM 'lost'
319
320
  ORDER BY generation DESC, confirmed_flush_lsn DESC;
320
- `, valita_exports.array(replicaStateSchema), "passthrough");
321
+ `;
322
+ const replicas = parse(results, valita_exports.array(replicaStateSchema), "passthrough");
321
323
  lc.info?.(`current replicas`, { replicas });
322
324
  return replicas;
323
325
  }
@@ -333,7 +335,7 @@ async function getActiveReplicas(lc, sql, shard) {
333
335
  */
334
336
  async function getRestoreCandidates(sql, shard, epoch) {
335
337
  const schema = sql(upstreamSchema(shard));
336
- return parse(await sql`
338
+ const results = await sql`
337
339
  SELECT
338
340
  replicas."id",
339
341
  replicas."rank",
@@ -368,7 +370,8 @@ async function getRestoreCandidates(sql, shard, epoch) {
368
370
  stage ASC, -- ordered by backup availalibility
369
371
  active DESC, -- prefer active slots (fork over resume)
370
372
  confirmed_flush_lsn DESC; -- prefer replicas further ahead
371
- `, valita_exports.array(replicaStateSchema), "passthrough");
373
+ `;
374
+ return parse(results, valita_exports.array(replicaStateSchema), "passthrough");
372
375
  }
373
376
  async function getReplicaState(sql, shard, id) {
374
377
  const results = await sql`
@@ -476,6 +479,6 @@ function replicaIdentitiesForTablesWithoutPrimaryKeys(pubs) {
476
479
  } };
477
480
  }
478
481
  //#endregion
479
- export { SHARD_CONFIG_TABLE, createReplica, dropShard, ensureGlobalTables, getActiveReplicas, getInternalShardConfig, getMutationsTableDefinition, getReplicaAtVersion, getReplicaState, getRestoreCandidates, initInitialSyncReplica, initRestoreReplica, internalPublicationPrefix, legacyReplicationSlot, metadataPublicationName, replicaIdentitiesForTablesWithoutPrimaryKeys, replicationSlotExpression, replicationSlotPrefix, setupTablesAndReplication, setupTriggers, validatePublications };
482
+ export { SHARD_CONFIG_TABLE, createReplica, dropShard, ensureGlobalTables, getActiveReplicas, getClientsTableDefinition, getInternalShardConfig, getMutationsTableDefinition, getReplicaAtVersion, getReplicaState, getRestoreCandidates, initInitialSyncReplica, initRestoreReplica, internalPublicationPrefix, legacyReplicationSlot, metadataPublicationName, replicaIdentitiesForTablesWithoutPrimaryKeys, replicationSlotExpression, replicationSlotPrefix, setupTablesAndReplication, setupTriggers, shardSetup, validatePublicationName, validatePublications };
480
483
 
481
484
  //# sourceMappingURL=shard.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"shard.js","names":[],"sources":["../../../../../../../../zero-cache/src/services/change-source/pg/schema/shard.ts"],"sourcesContent":["import {PG_INSUFFICIENT_PRIVILEGE} from '@drdgvhbh/postgres-error-codes';\nimport type {LogContext} from '@rocicorp/logger';\nimport {literal} from 'pg-format';\nimport postgres from 'postgres';\nimport {assert} from '../../../../../../shared/src/asserts.ts';\nimport {\n jsonObjectSchema,\n stringify,\n type JSONObject,\n} from '../../../../../../shared/src/bigint-json.ts';\nimport * as v from '../../../../../../shared/src/valita.ts';\nimport {Default} from '../../../../db/postgres-replica-identity-enum.ts';\nimport type {PostgresDB, PostgresTransaction} from '../../../../types/pg.ts';\nimport type {AppID, ShardConfig, ShardID} from '../../../../types/shards.ts';\nimport {appSchema, check, upstreamSchema} from '../../../../types/shards.ts';\nimport {id} from '../../../../types/sql.ts';\nimport {\n createEventFunctionStatements,\n createEventTriggerStatements,\n} from './ddl.ts';\nimport {\n getPublicationInfo,\n publishedSchema,\n type PublicationInfo,\n type PublishedSchema,\n} from './published.ts';\nimport {\n InitialSync,\n replicaStageSchema,\n type ReplicaStage,\n} from './replica-stage-enum.ts';\nimport {validate} from './validation.ts';\n\n/**\n * PostgreSQL unquoted identifiers must start with a letter or underscore\n * and contain only letters, digits, and underscores.\n */\nconst VALID_PUBLICATION_NAME = /^[a-zA-Z_][a-zA-Z0-9_]*$/;\n\n/**\n * Validates that a publication name is a valid PostgreSQL identifier.\n * This provides defense-in-depth against SQL injection when publication\n * names are used in replication commands.\n */\nexport function validatePublicationName(name: string): void {\n if (!VALID_PUBLICATION_NAME.test(name)) {\n throw new Error(\n `Invalid publication name \"${name}\". Publication names must start with a letter or underscore ` +\n `and contain only letters, digits, and underscores.`,\n );\n }\n if (name.length > 63) {\n throw new Error(\n `Publication name \"${name}\" exceeds PostgreSQL's 63-character identifier limit.`,\n );\n }\n}\n\nexport function internalPublicationPrefix({appID}: AppID) {\n return `_${appID}_`;\n}\n\nexport function legacyReplicationSlot({appID, shardNum}: ShardID) {\n return `${appID}_${shardNum}`;\n}\n\nexport function replicationSlotPrefix(shard: ShardID) {\n const {appID, shardNum} = check(shard);\n return `${appID}_${shardNum}_`;\n}\n\n/**\n * An expression used to match replication slots in the shard\n * in a Postgres `LIKE` operator.\n */\nexport function replicationSlotExpression(shard: ShardID) {\n // Underscores have a special meaning in LIKE values\n // so they have to be escaped.\n return `${replicationSlotPrefix(shard)}%`.replaceAll('_', '\\\\_');\n}\n\nfunction defaultPublicationName(appID: string, shardID: string | number) {\n return `_${appID}_public_${shardID}`;\n}\n\nexport function metadataPublicationName(\n appID: string,\n shardID: string | number,\n) {\n return `_${appID}_metadata_${shardID}`;\n}\n\n// The GLOBAL_SETUP must be idempotent as it can be run multiple times for different shards.\nfunction globalSetup(appID: AppID): string {\n const app = id(appSchema(appID));\n\n return /*sql*/ `\n CREATE SCHEMA IF NOT EXISTS ${app};\n\n CREATE TABLE IF NOT EXISTS ${app}.permissions (\n \"permissions\" JSONB,\n \"hash\" TEXT,\n\n -- Ensure that there is only a single row in the table.\n -- Application code can be agnostic to this column, and\n -- simply invoke UPDATE statements on the version columns.\n \"lock\" BOOL PRIMARY KEY DEFAULT true CHECK (lock)\n );\n\n CREATE OR REPLACE FUNCTION ${app}.set_permissions_hash()\n RETURNS TRIGGER AS $$\n BEGIN\n NEW.hash = md5(NEW.permissions::text);\n RETURN NEW;\n END;\n $$ LANGUAGE plpgsql;\n\n CREATE OR REPLACE TRIGGER on_set_permissions \n BEFORE INSERT OR UPDATE ON ${app}.permissions\n FOR EACH ROW\n EXECUTE FUNCTION ${app}.set_permissions_hash();\n\n INSERT INTO ${app}.permissions (permissions) VALUES (NULL) ON CONFLICT DO NOTHING;\n`;\n}\n\nexport async function ensureGlobalTables(db: PostgresDB, appID: AppID) {\n await db.unsafe(globalSetup(appID));\n}\n\nexport function getClientsTableDefinition(schema: string) {\n return /*sql*/ `\n CREATE TABLE ${schema}.\"clients\" (\n \"clientGroupID\" TEXT NOT NULL,\n \"clientID\" TEXT NOT NULL,\n \"lastMutationID\" BIGINT NOT NULL,\n \"userID\" TEXT,\n PRIMARY KEY(\"clientGroupID\", \"clientID\")\n );`;\n}\n\n/**\n * Tracks the results of mutations.\n * 1. It is an error for the same mutation ID to be used twice.\n * 2. The result is JSONB to allow for arbitrary results.\n *\n * The tables must be cleaned up as the clients\n * receive the mutation responses and as clients are removed.\n */\nexport function getMutationsTableDefinition(schema: string) {\n return /*sql*/ `\n CREATE TABLE ${schema}.\"mutations\" (\n \"clientGroupID\" TEXT NOT NULL,\n \"clientID\" TEXT NOT NULL,\n \"mutationID\" BIGINT NOT NULL,\n \"result\" JSON NOT NULL,\n PRIMARY KEY(\"clientGroupID\", \"clientID\", \"mutationID\")\n );`;\n}\n\nexport const SHARD_CONFIG_TABLE = 'shardConfig';\n\nexport function shardSetup(\n shardConfig: ShardConfig,\n metadataPublication: string,\n): string {\n const app = id(appSchema(shardConfig));\n const shard = id(upstreamSchema(shardConfig));\n\n const pubs = shardConfig.publications.toSorted();\n assert(\n pubs.includes(metadataPublication),\n () => `Publications must include ${metadataPublication}`,\n );\n\n return /*sql*/ `\n CREATE SCHEMA IF NOT EXISTS ${shard};\n\n ${getClientsTableDefinition(shard)}\n ${getMutationsTableDefinition(shard)}\n\n CREATE TABLE ${shard}.\"${SHARD_CONFIG_TABLE}\" (\n \"publications\" TEXT[] NOT NULL,\n \"ddlDetection\" BOOL NOT NULL,\n\n -- Ensure that there is only a single row in the table.\n \"lock\" BOOL PRIMARY KEY DEFAULT true CHECK (lock)\n );\n\n INSERT INTO ${shard}.\"${SHARD_CONFIG_TABLE}\" (\n \"publications\",\n \"ddlDetection\" \n ) VALUES (\n ARRAY[${literal(pubs)}], \n false -- set in SAVEPOINT with triggerSetup() statements\n );\n\n CREATE TABLE ${shard}.replicas (\n -- The DEFAULT exists purely for backwards compatibility support.\n -- New code always specifies a value based on Date.now().\n \"id\" TEXT PRIMARY KEY DEFAULT replace(gen_random_uuid()::text, '-', ''),\n \"rank\" BIGSERIAL,\n \"slot\" TEXT NOT NULL,\n \"version\" TEXT, -- replaced by generation, slated for deletion\n \"epoch\" INT4 DEFAULT 0,\n \"generation\" TEXT NOT NULL,\n \"stage\" INT4 DEFAULT ${InitialSync},\n \"backupPath\" TEXT, -- subpath within the litestream backup URL\n \"backupV5\" BOOL DEFAULT false,\n -- Whether the slot is acked only after storing in the PG change log.\n \"pgChangeLog\" BOOL DEFAULT false,\n \"initialSchema\" JSON, -- set after initial sync\n \"initialSyncContext\" JSON,\n \"subscriberContext\" JSON\n );\n\n DROP PUBLICATION IF EXISTS ${id(metadataPublication)};\n CREATE PUBLICATION ${id(metadataPublication)}\n FOR TABLE ${app}.\"permissions\", \n TABLE ${shard}.\"clients\", \n ${shard}.\"mutations\", \n ${shard}.\"replicas\" (id); -- advance the LSN/version with new replicas\n `;\n}\n\nexport function dropShard(appID: string, shardID: string | number): string {\n const schema = `${appID}_${shardID}`;\n const metadataPublication = metadataPublicationName(appID, shardID);\n const defaultPublication = defaultPublicationName(appID, shardID);\n\n // DROP SCHEMA ... CASCADE does not drop dependent PUBLICATIONS,\n // so PUBLICATIONs must be dropped explicitly.\n return /*sql*/ `\n DROP PUBLICATION IF EXISTS ${id(defaultPublication)};\n DROP PUBLICATION IF EXISTS ${id(metadataPublication)};\n DROP SCHEMA IF EXISTS ${id(schema)} CASCADE;\n `;\n}\n\nconst internalShardConfigSchema = v.object({\n publications: v.array(v.string()),\n ddlDetection: v.boolean(),\n});\n\nexport type InternalShardConfig = v.Infer<typeof internalShardConfigSchema>;\n\nconst replicaInfoSchema = v.object({\n id: v.string(),\n rank: v.bigint(),\n slot: v.string(),\n epoch: v.number(),\n generation: v.string(),\n stage: replicaStageSchema,\n backupPath: v.string().nullable(),\n backupV5: v.boolean(),\n /**\n * Whether the replication-manager that took over the replica's slot acks it\n * only after storing transactions in the PG change log (i.e. RMv1.5). The\n * slot's position past the change log's head then reflects acked\n * keepalives, rather than transactions missing from the change log.\n * False if unknown.\n */\n pgChangeLog: v.boolean(),\n});\n\nconst fullReplicaRowSchema = replicaInfoSchema.extend({\n initialSchema: publishedSchema,\n initialSyncContext: jsonObjectSchema.nullable(),\n subscriberContext: jsonObjectSchema.nullable(),\n});\n\nconst replicaSchema = internalShardConfigSchema.extend(\n fullReplicaRowSchema.shape,\n);\n\nexport type Replica = v.Infer<typeof replicaSchema>;\n\nconst replicationSlotStateSchema = v.object({\n active: v.boolean(),\n confirmedFlushLsn: v.string(),\n});\n\nconst replicaStateSchema = replicaInfoSchema.extend(\n replicationSlotStateSchema.shape,\n);\n\nexport type ReplicaState = v.Infer<typeof replicaStateSchema>;\n\n// triggerSetup is run separately in a sub-transaction (i.e. SAVEPOINT) so\n// that a failure (e.g. due to lack of superuser permissions) can be handled\n// by continuing in a degraded mode (ddlDetection = false).\nfunction triggerSetup(shard: ShardConfig): string {\n const schema = id(upstreamSchema(shard));\n return (\n createEventTriggerStatements(shard) +\n /*sql*/ `UPDATE ${schema}.\"shardConfig\" SET \"ddlDetection\" = true;`\n );\n}\n\nexport type BackupOptions = {\n backupPath: string | null;\n backupV5: boolean;\n /** See `pgChangeLog` in {@link ReplicaState}. */\n pgChangeLog: boolean;\n};\n\n/**\n * Creates a new replica to mark it as the owner of a specified `slot`.\n * This should be done with an advisory lock for replica/slot management\n * to ensure that the slot does not get dropped by concurrent cleanup\n * logic.\n *\n * Once initial sync is complete, {@link initInitialSyncReplica} should be called to\n * make the replica usable for incremental sync.\n */\nexport async function createReplica(\n sql: PostgresDB,\n shard: ShardID,\n id: string,\n slot: string,\n epoch: number,\n replicaVersion: string,\n {backupPath, backupV5, pgChangeLog}: BackupOptions,\n stage: ReplicaStage,\n) {\n const schema = upstreamSchema(shard);\n const values: Partial<v.Infer<typeof fullReplicaRowSchema>> & {\n version: string;\n } = {\n id,\n slot,\n epoch,\n generation: replicaVersion,\n // No longer read, but zero-cache 1.10 fails to start on a NULL \"version\",\n // so it is still written for rollbacks to 1.10.\n version: replicaVersion,\n backupPath,\n backupV5,\n pgChangeLog,\n stage,\n };\n await sql`INSERT INTO ${sql(schema)}.replicas ${sql(values)}`;\n}\n\n// Called in initial-sync to store the exact schema that was initially synced.\nexport async function initInitialSyncReplica(\n sql: PostgresDB,\n shard: ShardID,\n id: string,\n {tables, indexes}: PublishedSchema,\n initialSyncContext: JSONObject,\n) {\n const schema = upstreamSchema(shard);\n const synced: PublishedSchema = {tables, indexes};\n const values = {initialSchema: synced, initialSyncContext};\n await sql`UPDATE ${sql(schema)}.replicas SET ${sql(values)} WHERE id = ${id}`;\n}\n\n// Called to initialize a Restore replica (`destID`) with the generation\n// and initial sync context of the `sourceID` replica.\nexport async function initRestoreReplica(\n sql: PostgresDB,\n shard: ShardID,\n {sourceID, destID}: {sourceID: string; destID: string},\n): Promise<ReplicaState | null> {\n const schema = upstreamSchema(shard);\n await sql`\n UPDATE ${sql(schema)}.replicas dest \n SET \"generation\" = source.\"generation\",\n \"version\" = source.\"generation\",\n \"initialSchema\" = source.\"initialSchema\",\n \"initialSyncContext\" = source.\"initialSyncContext\"\n FROM ${sql(schema)}.replicas source\n WHERE source.id = ${sourceID} AND dest.id = ${destID};\n `;\n return getReplicaState(sql, shard, destID);\n}\n\n/**\n * Gets at the given version and optional ID. If no ID is specified, gets\n * the latest (i.e. highest rank) replica with that version.\n */\nexport async function getReplicaAtVersion(\n lc: LogContext,\n sql: PostgresDB,\n shard: ShardID,\n replicaVersion: string,\n id: string | null = null,\n context?: JSONObject,\n): Promise<Replica | null> {\n const schema = sql(upstreamSchema(shard));\n const result = await sql`\n SELECT\n replicas.\"id\",\n replicas.\"rank\",\n replicas.\"slot\",\n replicas.\"epoch\",\n replicas.\"generation\",\n replicas.\"stage\",\n replicas.\"backupPath\",\n replicas.\"backupV5\",\n replicas.\"pgChangeLog\",\n replicas.\"initialSchema\",\n replicas.\"initialSyncContext\",\n replicas.\"subscriberContext\",\n \"shardConfig\".\"publications\",\n \"shardConfig\".\"ddlDetection\"\n FROM ${schema}.replicas JOIN ${schema}.\"shardConfig\" ON true\n WHERE generation = ${replicaVersion} AND \"initialSyncContext\" IS NOT NULL\n AND id = COALESCE(${id}, id)\n ORDER BY rank DESC LIMIT 1;\n `;\n if (result.length === 0) {\n // log out all the replicas and the joined shardConfig\n const allReplicas = await sql`\n SELECT id, slot, generation, \"initialSyncContext\", \"subscriberContext\" \n FROM ${schema}.replicas`;\n lc.info?.(\n `Replica ${id}@${replicaVersion}` +\n (context ? `(context: ${stringify(context)}) ` : '') +\n `not found in: ${stringify(allReplicas)}`,\n );\n return null;\n }\n return v.parse(result[0], replicaSchema, 'passthrough');\n}\n\nexport async function getActiveReplicas(\n lc: LogContext,\n sql: PostgresDB,\n shard: ShardID,\n): Promise<ReplicaState[]> {\n const schema = sql(upstreamSchema(shard));\n const results = await sql`\n SELECT\n replicas.\"id\",\n replicas.\"rank\",\n replicas.\"slot\",\n replicas.\"epoch\",\n replicas.\"generation\",\n replicas.\"stage\",\n replicas.\"backupPath\",\n replicas.\"backupV5\",\n replicas.\"pgChangeLog\",\n slots.\"active\",\n slots.\"confirmed_flush_lsn\" as \"confirmedFlushLsn\"\n FROM ${schema}.replicas JOIN pg_replication_slots slots ON slot = slot_name\n WHERE \"initialSyncContext\" IS NOT NULL\n -- Exclude replicas whose slot has been invalidated (e.g. for exceeding\n -- max_slot_wal_keep_size). Such a replica can never be resumed, and\n -- restoring it just results in an AutoResetSignal on every attempt.\n AND slots.restart_lsn IS NOT NULL\n AND slots.wal_status IS DISTINCT FROM 'lost'\n ORDER BY generation DESC, confirmed_flush_lsn DESC;\n `;\n const replicas = v.parse(results, v.array(replicaStateSchema), 'passthrough');\n lc.info?.(`current replicas`, {replicas});\n return replicas;\n}\n\n/**\n * Returns candidates for restoring a new replica from. These include\n * all replicas in the newest `generation` of the given `epoch`, in order\n * of earliest available backup:\n * - An active InitialSync replica, which will be the only replica in\n * its generation by definition. Orphaned/inactive initial syncs are skipped.\n * - Replicas in the Replicate stage, active first.\n * - Replicas in the Restore stage, potentially available for resumption\n * as a last resort.\n */\nexport async function getRestoreCandidates(\n sql: PostgresDB,\n shard: ShardID,\n epoch: number,\n): Promise<ReplicaState[]> {\n const schema = sql(upstreamSchema(shard));\n const results = await sql`\n SELECT\n replicas.\"id\",\n replicas.\"rank\",\n replicas.\"slot\",\n replicas.\"epoch\",\n replicas.\"generation\",\n replicas.\"stage\",\n replicas.\"backupPath\",\n replicas.\"backupV5\",\n replicas.\"pgChangeLog\",\n slots.\"active\",\n slots.\"confirmed_flush_lsn\" as \"confirmedFlushLsn\"\n FROM ${schema}.replicas JOIN pg_replication_slots slots ON slot = slot_name\n\n -- coalesce on the newest generation in the epoch\n WHERE generation = (\n SELECT MAX(r.generation)\n FROM ${schema}.replicas r\n JOIN pg_replication_slots s ON r.slot = s.slot_name\n WHERE r.\"epoch\" = ${epoch} AND r.\"backupV5\"\n -- ignore orphaned InitialSyncs, which cannot be restored from\n AND (s.\"active\" OR r.\"stage\" != ${InitialSync})\n AND s.restart_lsn IS NOT NULL\n AND s.wal_status IS DISTINCT FROM 'lost'\n )\n AND \"epoch\" = ${epoch} AND \"backupV5\"\n AND (slots.active OR \"stage\" != ${InitialSync})\n AND slots.restart_lsn IS NOT NULL\n AND slots.wal_status IS DISTINCT FROM 'lost'\n\n ORDER BY \n stage ASC, -- ordered by backup availalibility\n active DESC, -- prefer active slots (fork over resume)\n confirmed_flush_lsn DESC; -- prefer replicas further ahead\n `;\n return v.parse(results, v.array(replicaStateSchema), 'passthrough');\n}\n\nexport async function getReplicaState(\n sql: PostgresDB,\n shard: ShardID,\n id: string,\n): Promise<ReplicaState | null> {\n const schema = sql(upstreamSchema(shard));\n const results = await sql`\n SELECT\n replicas.\"id\",\n replicas.\"rank\",\n replicas.\"slot\",\n replicas.\"epoch\",\n replicas.\"generation\",\n replicas.\"stage\",\n replicas.\"backupPath\",\n replicas.\"backupV5\",\n replicas.\"pgChangeLog\",\n slots.\"active\",\n slots.\"confirmed_flush_lsn\" as \"confirmedFlushLsn\"\n FROM ${schema}.replicas JOIN pg_replication_slots slots ON slot = slot_name\n WHERE \"id\" = ${id};\n `;\n return results.length\n ? v.parse(results[0], replicaStateSchema, 'passthrough')\n : null;\n}\n\nexport async function getInternalShardConfig(\n sql: PostgresDB,\n shard: ShardID,\n): Promise<InternalShardConfig> {\n const result = await sql`\n SELECT \"publications\", \"ddlDetection\"\n FROM ${sql(upstreamSchema(shard))}.\"shardConfig\";\n `;\n assert(\n result.length === 1,\n () => `Expected exactly one shardConfig row, got ${result.length}`,\n );\n return v.parse(result[0], internalShardConfigSchema, 'passthrough');\n}\n\n/**\n * Sets up and returns all publications (including internal ones) for\n * the given shard.\n */\nexport async function setupTablesAndReplication(\n lc: LogContext,\n sql: PostgresTransaction,\n requested: ShardConfig,\n includePartialIndexes = true,\n) {\n const {publications} = requested;\n // Validate requested publications.\n for (const pub of publications) {\n validatePublicationName(pub);\n if (pub.startsWith('_')) {\n throw new Error(\n `Publication names starting with \"_\" are reserved for internal use.\\n` +\n `Please use a different name for publication \"${pub}\".`,\n );\n }\n }\n const allPublications: string[] = [];\n\n // Setup application publications.\n if (publications.length) {\n const results = await sql<{pubname: string}[]>`\n SELECT pubname from pg_publication WHERE pubname IN ${sql(\n publications,\n )}`.values();\n\n if (results.length !== publications.length) {\n throw new Error(\n `Unknown or invalid publications. Specified: [${publications}]. Found: [${results.flat()}]`,\n );\n }\n allPublications.push(...publications);\n } else {\n const defaultPublication = defaultPublicationName(\n requested.appID,\n requested.shardNum,\n );\n await sql`\n DROP PUBLICATION IF EXISTS ${sql(defaultPublication)}`;\n await sql`\n CREATE PUBLICATION ${sql(defaultPublication)} \n FOR TABLES IN SCHEMA public\n WITH (publish_via_partition_root = true)`;\n allPublications.push(defaultPublication);\n }\n\n const metadataPublication = metadataPublicationName(\n requested.appID,\n requested.shardNum,\n );\n allPublications.push(metadataPublication);\n\n const shard = {...requested, publications: allPublications};\n\n // Setup the global tables and shard tables / publications.\n await sql.unsafe(globalSetup(shard) + shardSetup(shard, metadataPublication));\n\n const pubs = await getPublicationInfo(sql, allPublications);\n await replicaIdentitiesForTablesWithoutPrimaryKeys(pubs)?.apply(lc, sql);\n\n await setupTriggers(lc, sql, shard, includePartialIndexes);\n}\n\nexport async function setupTriggers(\n lc: LogContext,\n tx: PostgresTransaction,\n shard: ShardConfig,\n includePartialIndexes = true,\n) {\n const schema = upstreamSchema(shard);\n const [{ddlDetection}] = await tx<InternalShardConfig[]> /*sql*/ `\n SELECT \"ddlDetection\" FROM ${tx(schema)}.\"shardConfig\"`;\n\n // The functions invoked by event triggers are installed even if\n // event triggers are not supported/allowed by the db provider.\n // This allows users to manually invoke the update_schemas() function\n // as a workaround.\n await tx.unsafe(createEventFunctionStatements(shard, includePartialIndexes));\n try {\n await tx.savepoint(sub => sub.unsafe(triggerSetup(shard)));\n } catch (e) {\n if (ddlDetection) {\n // If ddlDetection has already been enabled, subsequent failures to\n // upgrade the trigger should be propagated rather than swallowed.\n throw e;\n }\n if (\n !(\n e instanceof postgres.PostgresError &&\n e.code === PG_INSUFFICIENT_PRIVILEGE\n )\n ) {\n throw e;\n }\n // If triggerSetup() fails, replication continues in ddlDetection=false mode.\n lc.warn?.(\n `Unable to create event triggers for schema change detection:\\n\\n` +\n `\"${e.hint ?? e.message}\"\\n\\n` +\n `Proceeding in degraded mode: schema changes will halt replication,\\n` +\n `requiring the replica to be reset (manually or with --auto-reset).`,\n );\n }\n}\n\nexport function validatePublications(\n lc: LogContext,\n published: PublicationInfo,\n) {\n // Verify that all publications export the proper events.\n published.publications.forEach(pub => {\n if (\n !pub.pubinsert ||\n !pub.pubupdate ||\n !pub.pubdelete ||\n !pub.pubtruncate\n ) {\n // TODO: Make APIError?\n throw new Error(\n `PUBLICATION ${pub.pubname} must publish insert, update, delete, and truncate`,\n );\n }\n });\n\n published.tables.forEach(table => validate(lc, table));\n}\n\ntype ReplicaIdentities = {\n apply(lc: LogContext, db: PostgresDB): Promise<void>;\n};\n\nexport function replicaIdentitiesForTablesWithoutPrimaryKeys(\n pubs: PublishedSchema,\n): ReplicaIdentities | undefined {\n const replicaIdentities: {\n schema: string;\n tableName: string;\n indexName: string;\n }[] = [];\n for (const table of pubs.tables) {\n if (!table.primaryKey?.length && table.replicaIdentity === Default) {\n // Look for an index that can serve as the REPLICA IDENTITY USING INDEX. It must be:\n // - UNIQUE\n // - NOT NULL columns\n // - not deferrable (i.e. isImmediate)\n // - not partial\n //\n // https://www.postgresql.org/docs/current/sql-altertable.html#SQL-ALTERTABLE-REPLICA-IDENTITY\n const {schema, name: tableName} = table;\n for (const {columns, name: indexName} of pubs.indexes.filter(\n idx =>\n idx.schema === schema &&\n idx.tableName === tableName &&\n idx.unique &&\n idx.isImmediate &&\n idx.predicate === undefined,\n )) {\n if (Object.keys(columns).some(col => !table.columns[col].notNull)) {\n continue; // Only indexes with all NOT NULL columns are suitable.\n }\n replicaIdentities.push({schema, tableName, indexName});\n break;\n }\n }\n }\n\n if (replicaIdentities.length === 0) {\n return undefined;\n }\n return {\n apply: async (lc: LogContext, sql: PostgresDB) => {\n for (const {schema, tableName, indexName} of replicaIdentities) {\n lc.info?.(\n `setting \"${indexName}\" as the REPLICA IDENTITY for \"${tableName}\"`,\n );\n await sql`\n ALTER TABLE ${sql(schema)}.${sql(tableName)} \n REPLICA IDENTITY USING INDEX ${sql(indexName)}`;\n }\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAqCA,IAAM,yBAAyB;;;;;;AAO/B,SAAgB,wBAAwB,MAAoB;CAC1D,IAAI,CAAC,uBAAuB,KAAK,IAAI,GACnC,MAAM,IAAI,MACR,6BAA6B,KAAK,+GAEpC;CAEF,IAAI,KAAK,SAAS,IAChB,MAAM,IAAI,MACR,qBAAqB,KAAK,sDAC5B;AAEJ;AAEA,SAAgB,0BAA0B,EAAC,SAAe;CACxD,OAAO,IAAI,MAAM;AACnB;AAEA,SAAgB,sBAAsB,EAAC,OAAO,YAAoB;CAChE,OAAO,GAAG,MAAM,GAAG;AACrB;AAEA,SAAgB,sBAAsB,OAAgB;CACpD,MAAM,EAAC,OAAO,aAAY,MAAM,KAAK;CACrC,OAAO,GAAG,MAAM,GAAG,SAAS;AAC9B;;;;;AAMA,SAAgB,0BAA0B,OAAgB;CAGxD,OAAO,GAAG,sBAAsB,KAAK,EAAE,GAAG,WAAW,KAAK,KAAK;AACjE;AAEA,SAAS,uBAAuB,OAAe,SAA0B;CACvE,OAAO,IAAI,MAAM,UAAU;AAC7B;AAEA,SAAgB,wBACd,OACA,SACA;CACA,OAAO,IAAI,MAAM,YAAY;AAC/B;AAGA,SAAS,YAAY,OAAsB;CACzC,MAAM,MAAM,GAAG,UAAU,KAAK,CAAC;CAE/B,OAAe;gCACe,IAAI;;+BAEL,IAAI;;;;;;;;;;+BAUJ,IAAI;;;;;;;;;iCASF,IAAI;;uBAEd,IAAI;;gBAEX,IAAI;;AAEpB;AAEA,eAAsB,mBAAmB,IAAgB,OAAc;CACrE,MAAM,GAAG,OAAO,YAAY,KAAK,CAAC;AACpC;AAEA,SAAgB,0BAA0B,QAAgB;CACxD,OAAe;iBACA,OAAO;;;;;;;AAOxB;;;;;;;;;AAUA,SAAgB,4BAA4B,QAAgB;CAC1D,OAAe;iBACA,OAAO;;;;;;;AAOxB;AAEA,IAAa,qBAAqB;AAElC,SAAgB,WACd,aACA,qBACQ;CACR,MAAM,MAAM,GAAG,UAAU,WAAW,CAAC;CACrC,MAAM,QAAQ,GAAG,eAAe,WAAW,CAAC;CAE5C,MAAM,OAAO,YAAY,aAAa,SAAS;CAC/C,OACE,KAAK,SAAS,mBAAmB,SAC3B,6BAA6B,qBACrC;CAEA,OAAe;gCACe,MAAM;;IAElC,0BAA0B,KAAK,EAAE;IACjC,4BAA4B,KAAK,EAAE;;iBAEtB,MAAM,IAAI,mBAAmB;;;;;;;;gBAQ9B,MAAM,IAAI,mBAAmB;;;;cAI/B,QAAQ,IAAI,EAAE;;;;iBAIX,MAAM;;;;;;;;;;;;;;;;;;;+BAmBQ,GAAG,mBAAmB,EAAE;uBAChC,GAAG,mBAAmB,EAAE;gBAC/B,IAAI;gBACJ,MAAM;gBACN,MAAM;gBACN,MAAM;;AAEtB;AAEA,SAAgB,UAAU,OAAe,SAAkC;CACzE,MAAM,SAAS,GAAG,MAAM,GAAG;CAC3B,MAAM,sBAAsB,wBAAwB,OAAO,OAAO;CAKlE,OAAe;iCACgB,GALJ,uBAAuB,OAAO,OAKvB,CAAkB,EAAE;iCACvB,GAAG,mBAAmB,EAAE;4BAC7B,GAAG,MAAM,EAAE;;AAEvC;AAEA,IAAM,4BAA4B,eAAE,OAAO;CACzC,cAAc,eAAE,MAAM,eAAE,OAAO,CAAC;CAChC,cAAc,eAAE,QAAQ;AAC1B,CAAC;AAID,IAAM,oBAAoB,eAAE,OAAO;CACjC,IAAI,eAAE,OAAO;CACb,MAAM,eAAE,OAAO;CACf,MAAM,eAAE,OAAO;CACf,OAAO,eAAE,OAAO;CAChB,YAAY,eAAE,OAAO;CACrB,OAAO;CACP,YAAY,eAAE,OAAO,EAAE,SAAS;CAChC,UAAU,eAAE,QAAQ;;;;;;;;CAQpB,aAAa,eAAE,QAAQ;AACzB,CAAC;AAED,IAAM,uBAAuB,kBAAkB,OAAO;CACpD,eAAe;CACf,oBAAoB,iBAAiB,SAAS;CAC9C,mBAAmB,iBAAiB,SAAS;AAC/C,CAAC;AAED,IAAM,gBAAgB,0BAA0B,OAC9C,qBAAqB,KACvB;AAIA,IAAM,6BAA6B,eAAE,OAAO;CAC1C,QAAQ,eAAE,QAAQ;CAClB,mBAAmB,eAAE,OAAO;AAC9B,CAAC;AAED,IAAM,qBAAqB,kBAAkB,OAC3C,2BAA2B,KAC7B;AAOA,SAAS,aAAa,OAA4B;CAChD,MAAM,SAAS,GAAG,eAAe,KAAK,CAAC;CACvC,OACE,6BAA6B,KAAK,IAC1B,UAAU,OAAO;AAE7B;;;;;;;;;;AAkBA,eAAsB,cACpB,KACA,OACA,IACA,MACA,OACA,gBACA,EAAC,YAAY,UAAU,eACvB,OACA;CACA,MAAM,SAAS,eAAe,KAAK;CACnC,MAAM,SAEF;EACF;EACA;EACA;EACA,YAAY;EAGZ,SAAS;EACT;EACA;EACA;EACA;CACF;CACA,MAAM,GAAG,eAAe,IAAI,MAAM,EAAE,YAAY,IAAI,MAAM;AAC5D;AAGA,eAAsB,uBACpB,KACA,OACA,IACA,EAAC,QAAQ,WACT,oBACA;CACA,MAAM,SAAS,eAAe,KAAK;CAEnC,MAAM,SAAS;EAAC,eAAe;GADE;GAAQ;EACV;EAAQ;CAAkB;CACzD,MAAM,GAAG,UAAU,IAAI,MAAM,EAAE,gBAAgB,IAAI,MAAM,EAAE,cAAc;AAC3E;AAIA,eAAsB,mBACpB,KACA,OACA,EAAC,UAAU,UACmB;CAC9B,MAAM,SAAS,eAAe,KAAK;CACnC,MAAM,GAAG;aACE,IAAI,MAAM,EAAE;;;;;aAKZ,IAAI,MAAM,EAAE;0BACC,SAAS,iBAAiB,OAAO;;CAEzD,OAAO,gBAAgB,KAAK,OAAO,MAAM;AAC3C;;;;;AAMA,eAAsB,oBACpB,IACA,KACA,OACA,gBACA,KAAoB,MACpB,SACyB;CACzB,MAAM,SAAS,IAAI,eAAe,KAAK,CAAC;CACxC,MAAM,SAAS,MAAM,GAAG;;;;;;;;;;;;;;;;WAgBf,OAAO,iBAAiB,OAAO;2BACf,eAAe;0BAChB,GAAG;;;CAG3B,IAAI,OAAO,WAAW,GAAG;EAEvB,MAAM,cAAc,MAAM,GAAG;;eAElB,OAAO;EAClB,GAAG,OACD,WAAW,GAAG,GAAG,oBACd,UAAU,aAAa,UAAU,OAAO,EAAE,MAAM,MACjD,iBAAiB,UAAU,WAAW,GAC1C;EACA,OAAO;CACT;CACA,OAAO,MAAQ,OAAO,IAAI,eAAe,aAAa;AACxD;AAEA,eAAsB,kBACpB,IACA,KACA,OACyB;CAwBzB,MAAM,WAAW,MAAQ,MAtBH,GAAG;;;;;;;;;;;;;WADV,IAAI,eAAe,KAAK,CAc9B,EAAO;;;;;;;;KASkB,eAAE,MAAM,kBAAkB,GAAG,aAAa;CAC5E,GAAG,OAAO,oBAAoB,EAAC,SAAQ,CAAC;CACxC,OAAO;AACT;;;;;;;;;;;AAYA,eAAsB,qBACpB,KACA,OACA,OACyB;CACzB,MAAM,SAAS,IAAI,eAAe,KAAK,CAAC;CAqCxC,OAAO,MAAQ,MApCO,GAAG;;;;;;;;;;;;;WAahB,OAAO;;;;;iBAKD,OAAO;;6BAEK,MAAM;;+CAEsB;;;;2BAI9B,MAAM;+CACwB;;;;;;;;KAS/B,eAAE,MAAM,kBAAkB,GAAG,aAAa;AACpE;AAEA,eAAsB,gBACpB,KACA,OACA,IAC8B;CAE9B,MAAM,UAAU,MAAM,GAAG;;;;;;;;;;;;;WADV,IAAI,eAAe,KAAK,CAc9B,EAAO;qBACG,GAAG;;CAEtB,OAAO,QAAQ,SACX,MAAQ,QAAQ,IAAI,oBAAoB,aAAa,IACrD;AACN;AAEA,eAAsB,uBACpB,KACA,OAC8B;CAC9B,MAAM,SAAS,MAAM,GAAG;;aAEb,IAAI,eAAe,KAAK,CAAC,EAAE;;CAEtC,OACE,OAAO,WAAW,SACZ,6CAA6C,OAAO,QAC5D;CACA,OAAO,MAAQ,OAAO,IAAI,2BAA2B,aAAa;AACpE;;;;;AAMA,eAAsB,0BACpB,IACA,KACA,WACA,wBAAwB,MACxB;CACA,MAAM,EAAC,iBAAgB;CAEvB,KAAK,MAAM,OAAO,cAAc;EAC9B,wBAAwB,GAAG;EAC3B,IAAI,IAAI,WAAW,GAAG,GACpB,MAAM,IAAI,MACR,oHACkD,IAAI,GACxD;CAEJ;CACA,MAAM,kBAA4B,CAAC;CAGnC,IAAI,aAAa,QAAQ;EACvB,MAAM,UAAU,MAAM,GAAwB;0DACQ,IACpD,YACF,IAAI,OAAO;EAEX,IAAI,QAAQ,WAAW,aAAa,QAClC,MAAM,IAAI,MACR,gDAAgD,aAAa,aAAa,QAAQ,KAAK,EAAE,EAC3F;EAEF,gBAAgB,KAAK,GAAG,YAAY;CACtC,OAAO;EACL,MAAM,qBAAqB,uBACzB,UAAU,OACV,UAAU,QACZ;EACA,MAAM,GAAG;mCACsB,IAAI,kBAAkB;EACrD,MAAM,GAAG;2BACc,IAAI,kBAAkB,EAAE;;;EAG/C,gBAAgB,KAAK,kBAAkB;CACzC;CAEA,MAAM,sBAAsB,wBAC1B,UAAU,OACV,UAAU,QACZ;CACA,gBAAgB,KAAK,mBAAmB;CAExC,MAAM,QAAQ;EAAC,GAAG;EAAW,cAAc;CAAe;CAG1D,MAAM,IAAI,OAAO,YAAY,KAAK,IAAI,WAAW,OAAO,mBAAmB,CAAC;CAG5E,MAAM,6CAA6C,MADhC,mBAAmB,KAAK,eAAe,CACH,GAAG,MAAM,IAAI,GAAG;CAEvE,MAAM,cAAc,IAAI,KAAK,OAAO,qBAAqB;AAC3D;AAEA,eAAsB,cACpB,IACA,IACA,OACA,wBAAwB,MACxB;CAEA,MAAM,CAAC,EAAC,kBAAiB,MAAM,EAAkC;iCAClC,GAFhB,eAAe,KAEI,CAAM,EAAE;CAM1C,MAAM,GAAG,OAAO,8BAA8B,OAAO,qBAAqB,CAAC;CAC3E,IAAI;EACF,MAAM,GAAG,WAAU,QAAO,IAAI,OAAO,aAAa,KAAK,CAAC,CAAC;CAC3D,SAAS,GAAG;EACV,IAAI,cAGF,MAAM;EAER,IACE,EACE,aAAa,SAAS,iBACtB,EAAE,SAAS,4BAGb,MAAM;EAGR,GAAG,OACD,oEACM,EAAE,QAAQ,EAAE,QAAQ,4IAG5B;CACF;AACF;AAEA,SAAgB,qBACd,IACA,WACA;CAEA,UAAU,aAAa,SAAQ,QAAO;EACpC,IACE,CAAC,IAAI,aACL,CAAC,IAAI,aACL,CAAC,IAAI,aACL,CAAC,IAAI,aAGL,MAAM,IAAI,MACR,eAAe,IAAI,QAAQ,mDAC7B;CAEJ,CAAC;CAED,UAAU,OAAO,SAAQ,UAAS,SAAS,IAAI,KAAK,CAAC;AACvD;AAMA,SAAgB,6CACd,MAC+B;CAC/B,MAAM,oBAIA,CAAC;CACP,KAAK,MAAM,SAAS,KAAK,QACvB,IAAI,CAAC,MAAM,YAAY,UAAU,MAAM,oBAAA,KAA6B;EAQlE,MAAM,EAAC,QAAQ,MAAM,cAAa;EAClC,KAAK,MAAM,EAAC,SAAS,MAAM,eAAc,KAAK,QAAQ,QACpD,QACE,IAAI,WAAW,UACf,IAAI,cAAc,aAClB,IAAI,UACJ,IAAI,eACJ,IAAI,cAAc,KAAA,CACtB,GAAG;GACD,IAAI,OAAO,KAAK,OAAO,EAAE,MAAK,QAAO,CAAC,MAAM,QAAQ,KAAK,OAAO,GAC9D;GAEF,kBAAkB,KAAK;IAAC;IAAQ;IAAW;GAAS,CAAC;GACrD;EACF;CACF;CAGF,IAAI,kBAAkB,WAAW,GAC/B;CAEF,OAAO,EACL,OAAO,OAAO,IAAgB,QAAoB;EAChD,KAAK,MAAM,EAAC,QAAQ,WAAW,eAAc,mBAAmB;GAC9D,GAAG,OACD,YAAY,UAAU,iCAAiC,UAAU,EACnE;GACA,MAAM,GAAG;sBACK,IAAI,MAAM,EAAE,GAAG,IAAI,SAAS,EAAE;yCACX,IAAI,SAAS;EAChD;CACF,EACF;AACF"}
1
+ {"version":3,"file":"shard.js","names":["v","v.parse"],"sources":["../../../../../../../../zero-cache/src/services/change-source/pg/schema/shard.ts"],"sourcesContent":["import {PG_INSUFFICIENT_PRIVILEGE} from '@drdgvhbh/postgres-error-codes';\nimport type {LogContext} from '@rocicorp/logger';\nimport {literal} from 'pg-format';\nimport postgres from 'postgres';\nimport {assert} from '../../../../../../shared/src/asserts.ts';\nimport {\n jsonObjectSchema,\n stringify,\n type JSONObject,\n} from '../../../../../../shared/src/bigint-json.ts';\nimport * as v from '../../../../../../shared/src/valita.ts';\nimport {Default} from '../../../../db/postgres-replica-identity-enum.ts';\nimport type {PostgresDB, PostgresTransaction} from '../../../../types/pg.ts';\nimport type {AppID, ShardConfig, ShardID} from '../../../../types/shards.ts';\nimport {appSchema, check, upstreamSchema} from '../../../../types/shards.ts';\nimport {id} from '../../../../types/sql.ts';\nimport {\n createEventFunctionStatements,\n createEventTriggerStatements,\n} from './ddl.ts';\nimport {\n getPublicationInfo,\n publishedSchema,\n type PublicationInfo,\n type PublishedSchema,\n} from './published.ts';\nimport {\n InitialSync,\n replicaStageSchema,\n type ReplicaStage,\n} from './replica-stage-enum.ts';\nimport {validate} from './validation.ts';\n\n/**\n * PostgreSQL unquoted identifiers must start with a letter or underscore\n * and contain only letters, digits, and underscores.\n */\nconst VALID_PUBLICATION_NAME = /^[a-zA-Z_][a-zA-Z0-9_]*$/;\n\n/**\n * Validates that a publication name is a valid PostgreSQL identifier.\n * This provides defense-in-depth against SQL injection when publication\n * names are used in replication commands.\n */\nexport function validatePublicationName(name: string): void {\n if (!VALID_PUBLICATION_NAME.test(name)) {\n throw new Error(\n `Invalid publication name \"${name}\". Publication names must start with a letter or underscore ` +\n `and contain only letters, digits, and underscores.`,\n );\n }\n if (name.length > 63) {\n throw new Error(\n `Publication name \"${name}\" exceeds PostgreSQL's 63-character identifier limit.`,\n );\n }\n}\n\nexport function internalPublicationPrefix({appID}: AppID) {\n return `_${appID}_`;\n}\n\nexport function legacyReplicationSlot({appID, shardNum}: ShardID) {\n return `${appID}_${shardNum}`;\n}\n\nexport function replicationSlotPrefix(shard: ShardID) {\n const {appID, shardNum} = check(shard);\n return `${appID}_${shardNum}_`;\n}\n\n/**\n * An expression used to match replication slots in the shard\n * in a Postgres `LIKE` operator.\n */\nexport function replicationSlotExpression(shard: ShardID) {\n // Underscores have a special meaning in LIKE values\n // so they have to be escaped.\n return `${replicationSlotPrefix(shard)}%`.replaceAll('_', '\\\\_');\n}\n\nfunction defaultPublicationName(appID: string, shardID: string | number) {\n return `_${appID}_public_${shardID}`;\n}\n\nexport function metadataPublicationName(\n appID: string,\n shardID: string | number,\n) {\n return `_${appID}_metadata_${shardID}`;\n}\n\n// The GLOBAL_SETUP must be idempotent as it can be run multiple times for different shards.\nfunction globalSetup(appID: AppID): string {\n const app = id(appSchema(appID));\n\n return /*sql*/ `\n CREATE SCHEMA IF NOT EXISTS ${app};\n\n CREATE TABLE IF NOT EXISTS ${app}.permissions (\n \"permissions\" JSONB,\n \"hash\" TEXT,\n\n -- Ensure that there is only a single row in the table.\n -- Application code can be agnostic to this column, and\n -- simply invoke UPDATE statements on the version columns.\n \"lock\" BOOL PRIMARY KEY DEFAULT true CHECK (lock)\n );\n\n CREATE OR REPLACE FUNCTION ${app}.set_permissions_hash()\n RETURNS TRIGGER AS $$\n BEGIN\n NEW.hash = md5(NEW.permissions::text);\n RETURN NEW;\n END;\n $$ LANGUAGE plpgsql;\n\n CREATE OR REPLACE TRIGGER on_set_permissions \n BEFORE INSERT OR UPDATE ON ${app}.permissions\n FOR EACH ROW\n EXECUTE FUNCTION ${app}.set_permissions_hash();\n\n INSERT INTO ${app}.permissions (permissions) VALUES (NULL) ON CONFLICT DO NOTHING;\n`;\n}\n\nexport async function ensureGlobalTables(db: PostgresDB, appID: AppID) {\n await db.unsafe(globalSetup(appID));\n}\n\nexport function getClientsTableDefinition(schema: string) {\n return /*sql*/ `\n CREATE TABLE ${schema}.\"clients\" (\n \"clientGroupID\" TEXT NOT NULL,\n \"clientID\" TEXT NOT NULL,\n \"lastMutationID\" BIGINT NOT NULL,\n \"userID\" TEXT,\n PRIMARY KEY(\"clientGroupID\", \"clientID\")\n );`;\n}\n\n/**\n * Tracks the results of mutations.\n * 1. It is an error for the same mutation ID to be used twice.\n * 2. The result is JSONB to allow for arbitrary results.\n *\n * The tables must be cleaned up as the clients\n * receive the mutation responses and as clients are removed.\n */\nexport function getMutationsTableDefinition(schema: string) {\n return /*sql*/ `\n CREATE TABLE ${schema}.\"mutations\" (\n \"clientGroupID\" TEXT NOT NULL,\n \"clientID\" TEXT NOT NULL,\n \"mutationID\" BIGINT NOT NULL,\n \"result\" JSON NOT NULL,\n PRIMARY KEY(\"clientGroupID\", \"clientID\", \"mutationID\")\n );`;\n}\n\nexport const SHARD_CONFIG_TABLE = 'shardConfig';\n\nexport function shardSetup(\n shardConfig: ShardConfig,\n metadataPublication: string,\n): string {\n const app = id(appSchema(shardConfig));\n const shard = id(upstreamSchema(shardConfig));\n\n const pubs = shardConfig.publications.toSorted();\n assert(\n pubs.includes(metadataPublication),\n () => `Publications must include ${metadataPublication}`,\n );\n\n return /*sql*/ `\n CREATE SCHEMA IF NOT EXISTS ${shard};\n\n ${getClientsTableDefinition(shard)}\n ${getMutationsTableDefinition(shard)}\n\n CREATE TABLE ${shard}.\"${SHARD_CONFIG_TABLE}\" (\n \"publications\" TEXT[] NOT NULL,\n \"ddlDetection\" BOOL NOT NULL,\n\n -- Ensure that there is only a single row in the table.\n \"lock\" BOOL PRIMARY KEY DEFAULT true CHECK (lock)\n );\n\n INSERT INTO ${shard}.\"${SHARD_CONFIG_TABLE}\" (\n \"publications\",\n \"ddlDetection\" \n ) VALUES (\n ARRAY[${literal(pubs)}], \n false -- set in SAVEPOINT with triggerSetup() statements\n );\n\n CREATE TABLE ${shard}.replicas (\n -- The DEFAULT exists purely for backwards compatibility support.\n -- New code always specifies a value based on Date.now().\n \"id\" TEXT PRIMARY KEY DEFAULT replace(gen_random_uuid()::text, '-', ''),\n \"rank\" BIGSERIAL,\n \"slot\" TEXT NOT NULL,\n \"version\" TEXT, -- replaced by generation, slated for deletion\n \"epoch\" INT4 DEFAULT 0,\n \"generation\" TEXT NOT NULL,\n \"stage\" INT4 DEFAULT ${InitialSync},\n \"backupPath\" TEXT, -- subpath within the litestream backup URL\n \"backupV5\" BOOL DEFAULT false,\n -- Whether the slot is acked only after storing in the PG change log.\n \"pgChangeLog\" BOOL DEFAULT false,\n \"initialSchema\" JSON, -- set after initial sync\n \"initialSyncContext\" JSON,\n \"subscriberContext\" JSON\n );\n\n DROP PUBLICATION IF EXISTS ${id(metadataPublication)};\n CREATE PUBLICATION ${id(metadataPublication)}\n FOR TABLE ${app}.\"permissions\", \n TABLE ${shard}.\"clients\", \n ${shard}.\"mutations\", \n ${shard}.\"replicas\" (id); -- advance the LSN/version with new replicas\n `;\n}\n\nexport function dropShard(appID: string, shardID: string | number): string {\n const schema = `${appID}_${shardID}`;\n const metadataPublication = metadataPublicationName(appID, shardID);\n const defaultPublication = defaultPublicationName(appID, shardID);\n\n // DROP SCHEMA ... CASCADE does not drop dependent PUBLICATIONS,\n // so PUBLICATIONs must be dropped explicitly.\n return /*sql*/ `\n DROP PUBLICATION IF EXISTS ${id(defaultPublication)};\n DROP PUBLICATION IF EXISTS ${id(metadataPublication)};\n DROP SCHEMA IF EXISTS ${id(schema)} CASCADE;\n `;\n}\n\nconst internalShardConfigSchema = v.object({\n publications: v.array(v.string()),\n ddlDetection: v.boolean(),\n});\n\nexport type InternalShardConfig = v.Infer<typeof internalShardConfigSchema>;\n\nconst replicaInfoSchema = v.object({\n id: v.string(),\n rank: v.bigint(),\n slot: v.string(),\n epoch: v.number(),\n generation: v.string(),\n stage: replicaStageSchema,\n backupPath: v.string().nullable(),\n backupV5: v.boolean(),\n /**\n * Whether the replication-manager that took over the replica's slot acks it\n * only after storing transactions in the PG change log (i.e. RMv1.5). The\n * slot's position past the change log's head then reflects acked\n * keepalives, rather than transactions missing from the change log.\n * False if unknown.\n */\n pgChangeLog: v.boolean(),\n});\n\nconst fullReplicaRowSchema = replicaInfoSchema.extend({\n initialSchema: publishedSchema,\n initialSyncContext: jsonObjectSchema.nullable(),\n subscriberContext: jsonObjectSchema.nullable(),\n});\n\nconst replicaSchema = internalShardConfigSchema.extend(\n fullReplicaRowSchema.shape,\n);\n\nexport type Replica = v.Infer<typeof replicaSchema>;\n\nconst replicationSlotStateSchema = v.object({\n active: v.boolean(),\n confirmedFlushLsn: v.string(),\n});\n\nconst replicaStateSchema = replicaInfoSchema.extend(\n replicationSlotStateSchema.shape,\n);\n\nexport type ReplicaState = v.Infer<typeof replicaStateSchema>;\n\n// triggerSetup is run separately in a sub-transaction (i.e. SAVEPOINT) so\n// that a failure (e.g. due to lack of superuser permissions) can be handled\n// by continuing in a degraded mode (ddlDetection = false).\nfunction triggerSetup(shard: ShardConfig): string {\n const schema = id(upstreamSchema(shard));\n return (\n createEventTriggerStatements(shard) +\n /*sql*/ `UPDATE ${schema}.\"shardConfig\" SET \"ddlDetection\" = true;`\n );\n}\n\nexport type BackupOptions = {\n backupPath: string | null;\n backupV5: boolean;\n /** See `pgChangeLog` in {@link ReplicaState}. */\n pgChangeLog: boolean;\n};\n\n/**\n * Creates a new replica to mark it as the owner of a specified `slot`.\n * This should be done with an advisory lock for replica/slot management\n * to ensure that the slot does not get dropped by concurrent cleanup\n * logic.\n *\n * Once initial sync is complete, {@link initInitialSyncReplica} should be called to\n * make the replica usable for incremental sync.\n */\nexport async function createReplica(\n sql: PostgresDB,\n shard: ShardID,\n id: string,\n slot: string,\n epoch: number,\n replicaVersion: string,\n {backupPath, backupV5, pgChangeLog}: BackupOptions,\n stage: ReplicaStage,\n) {\n const schema = upstreamSchema(shard);\n const values: Partial<v.Infer<typeof fullReplicaRowSchema>> & {\n version: string;\n } = {\n id,\n slot,\n epoch,\n generation: replicaVersion,\n // No longer read, but zero-cache 1.10 fails to start on a NULL \"version\",\n // so it is still written for rollbacks to 1.10.\n version: replicaVersion,\n backupPath,\n backupV5,\n pgChangeLog,\n stage,\n };\n await sql`INSERT INTO ${sql(schema)}.replicas ${sql(values)}`;\n}\n\n// Called in initial-sync to store the exact schema that was initially synced.\nexport async function initInitialSyncReplica(\n sql: PostgresDB,\n shard: ShardID,\n id: string,\n {tables, indexes}: PublishedSchema,\n initialSyncContext: JSONObject,\n) {\n const schema = upstreamSchema(shard);\n const synced: PublishedSchema = {tables, indexes};\n const values = {initialSchema: synced, initialSyncContext};\n await sql`UPDATE ${sql(schema)}.replicas SET ${sql(values)} WHERE id = ${id}`;\n}\n\n// Called to initialize a Restore replica (`destID`) with the generation\n// and initial sync context of the `sourceID` replica.\nexport async function initRestoreReplica(\n sql: PostgresDB,\n shard: ShardID,\n {sourceID, destID}: {sourceID: string; destID: string},\n): Promise<ReplicaState | null> {\n const schema = upstreamSchema(shard);\n await sql`\n UPDATE ${sql(schema)}.replicas dest \n SET \"generation\" = source.\"generation\",\n \"version\" = source.\"generation\",\n \"initialSchema\" = source.\"initialSchema\",\n \"initialSyncContext\" = source.\"initialSyncContext\"\n FROM ${sql(schema)}.replicas source\n WHERE source.id = ${sourceID} AND dest.id = ${destID};\n `;\n return getReplicaState(sql, shard, destID);\n}\n\n/**\n * Gets at the given version and optional ID. If no ID is specified, gets\n * the latest (i.e. highest rank) replica with that version.\n */\nexport async function getReplicaAtVersion(\n lc: LogContext,\n sql: PostgresDB,\n shard: ShardID,\n replicaVersion: string,\n id: string | null = null,\n context?: JSONObject,\n): Promise<Replica | null> {\n const schema = sql(upstreamSchema(shard));\n const result = await sql`\n SELECT\n replicas.\"id\",\n replicas.\"rank\",\n replicas.\"slot\",\n replicas.\"epoch\",\n replicas.\"generation\",\n replicas.\"stage\",\n replicas.\"backupPath\",\n replicas.\"backupV5\",\n replicas.\"pgChangeLog\",\n replicas.\"initialSchema\",\n replicas.\"initialSyncContext\",\n replicas.\"subscriberContext\",\n \"shardConfig\".\"publications\",\n \"shardConfig\".\"ddlDetection\"\n FROM ${schema}.replicas JOIN ${schema}.\"shardConfig\" ON true\n WHERE generation = ${replicaVersion} AND \"initialSyncContext\" IS NOT NULL\n AND id = COALESCE(${id}, id)\n ORDER BY rank DESC LIMIT 1;\n `;\n if (result.length === 0) {\n // log out all the replicas and the joined shardConfig\n const allReplicas = await sql`\n SELECT id, slot, generation, \"initialSyncContext\", \"subscriberContext\" \n FROM ${schema}.replicas`;\n lc.info?.(\n `Replica ${id}@${replicaVersion}` +\n (context ? `(context: ${stringify(context)}) ` : '') +\n `not found in: ${stringify(allReplicas)}`,\n );\n return null;\n }\n return v.parse(result[0], replicaSchema, 'passthrough');\n}\n\nexport async function getActiveReplicas(\n lc: LogContext,\n sql: PostgresDB,\n shard: ShardID,\n): Promise<ReplicaState[]> {\n const schema = sql(upstreamSchema(shard));\n const results = await sql`\n SELECT\n replicas.\"id\",\n replicas.\"rank\",\n replicas.\"slot\",\n replicas.\"epoch\",\n replicas.\"generation\",\n replicas.\"stage\",\n replicas.\"backupPath\",\n replicas.\"backupV5\",\n replicas.\"pgChangeLog\",\n slots.\"active\",\n slots.\"confirmed_flush_lsn\" as \"confirmedFlushLsn\"\n FROM ${schema}.replicas JOIN pg_replication_slots slots ON slot = slot_name\n WHERE \"initialSyncContext\" IS NOT NULL\n -- Exclude replicas whose slot has been invalidated (e.g. for exceeding\n -- max_slot_wal_keep_size). Such a replica can never be resumed, and\n -- restoring it just results in an AutoResetSignal on every attempt.\n AND slots.restart_lsn IS NOT NULL\n AND slots.wal_status IS DISTINCT FROM 'lost'\n ORDER BY generation DESC, confirmed_flush_lsn DESC;\n `;\n const replicas = v.parse(results, v.array(replicaStateSchema), 'passthrough');\n lc.info?.(`current replicas`, {replicas});\n return replicas;\n}\n\n/**\n * Returns candidates for restoring a new replica from. These include\n * all replicas in the newest `generation` of the given `epoch`, in order\n * of earliest available backup:\n * - An active InitialSync replica, which will be the only replica in\n * its generation by definition. Orphaned/inactive initial syncs are skipped.\n * - Replicas in the Replicate stage, active first.\n * - Replicas in the Restore stage, potentially available for resumption\n * as a last resort.\n */\nexport async function getRestoreCandidates(\n sql: PostgresDB,\n shard: ShardID,\n epoch: number,\n): Promise<ReplicaState[]> {\n const schema = sql(upstreamSchema(shard));\n const results = await sql`\n SELECT\n replicas.\"id\",\n replicas.\"rank\",\n replicas.\"slot\",\n replicas.\"epoch\",\n replicas.\"generation\",\n replicas.\"stage\",\n replicas.\"backupPath\",\n replicas.\"backupV5\",\n replicas.\"pgChangeLog\",\n slots.\"active\",\n slots.\"confirmed_flush_lsn\" as \"confirmedFlushLsn\"\n FROM ${schema}.replicas JOIN pg_replication_slots slots ON slot = slot_name\n\n -- coalesce on the newest generation in the epoch\n WHERE generation = (\n SELECT MAX(r.generation)\n FROM ${schema}.replicas r\n JOIN pg_replication_slots s ON r.slot = s.slot_name\n WHERE r.\"epoch\" = ${epoch} AND r.\"backupV5\"\n -- ignore orphaned InitialSyncs, which cannot be restored from\n AND (s.\"active\" OR r.\"stage\" != ${InitialSync})\n AND s.restart_lsn IS NOT NULL\n AND s.wal_status IS DISTINCT FROM 'lost'\n )\n AND \"epoch\" = ${epoch} AND \"backupV5\"\n AND (slots.active OR \"stage\" != ${InitialSync})\n AND slots.restart_lsn IS NOT NULL\n AND slots.wal_status IS DISTINCT FROM 'lost'\n\n ORDER BY \n stage ASC, -- ordered by backup availalibility\n active DESC, -- prefer active slots (fork over resume)\n confirmed_flush_lsn DESC; -- prefer replicas further ahead\n `;\n return v.parse(results, v.array(replicaStateSchema), 'passthrough');\n}\n\nexport async function getReplicaState(\n sql: PostgresDB,\n shard: ShardID,\n id: string,\n): Promise<ReplicaState | null> {\n const schema = sql(upstreamSchema(shard));\n const results = await sql`\n SELECT\n replicas.\"id\",\n replicas.\"rank\",\n replicas.\"slot\",\n replicas.\"epoch\",\n replicas.\"generation\",\n replicas.\"stage\",\n replicas.\"backupPath\",\n replicas.\"backupV5\",\n replicas.\"pgChangeLog\",\n slots.\"active\",\n slots.\"confirmed_flush_lsn\" as \"confirmedFlushLsn\"\n FROM ${schema}.replicas JOIN pg_replication_slots slots ON slot = slot_name\n WHERE \"id\" = ${id};\n `;\n return results.length\n ? v.parse(results[0], replicaStateSchema, 'passthrough')\n : null;\n}\n\nexport async function getInternalShardConfig(\n sql: PostgresDB,\n shard: ShardID,\n): Promise<InternalShardConfig> {\n const result = await sql`\n SELECT \"publications\", \"ddlDetection\"\n FROM ${sql(upstreamSchema(shard))}.\"shardConfig\";\n `;\n assert(\n result.length === 1,\n () => `Expected exactly one shardConfig row, got ${result.length}`,\n );\n return v.parse(result[0], internalShardConfigSchema, 'passthrough');\n}\n\n/**\n * Sets up and returns all publications (including internal ones) for\n * the given shard.\n */\nexport async function setupTablesAndReplication(\n lc: LogContext,\n sql: PostgresTransaction,\n requested: ShardConfig,\n includePartialIndexes = true,\n) {\n const {publications} = requested;\n // Validate requested publications.\n for (const pub of publications) {\n validatePublicationName(pub);\n if (pub.startsWith('_')) {\n throw new Error(\n `Publication names starting with \"_\" are reserved for internal use.\\n` +\n `Please use a different name for publication \"${pub}\".`,\n );\n }\n }\n const allPublications: string[] = [];\n\n // Setup application publications.\n if (publications.length) {\n const results = await sql<{pubname: string}[]>`\n SELECT pubname from pg_publication WHERE pubname IN ${sql(\n publications,\n )}`.values();\n\n if (results.length !== publications.length) {\n throw new Error(\n `Unknown or invalid publications. Specified: [${publications}]. Found: [${results.flat()}]`,\n );\n }\n allPublications.push(...publications);\n } else {\n const defaultPublication = defaultPublicationName(\n requested.appID,\n requested.shardNum,\n );\n await sql`\n DROP PUBLICATION IF EXISTS ${sql(defaultPublication)}`;\n await sql`\n CREATE PUBLICATION ${sql(defaultPublication)} \n FOR TABLES IN SCHEMA public\n WITH (publish_via_partition_root = true)`;\n allPublications.push(defaultPublication);\n }\n\n const metadataPublication = metadataPublicationName(\n requested.appID,\n requested.shardNum,\n );\n allPublications.push(metadataPublication);\n\n const shard = {...requested, publications: allPublications};\n\n // Setup the global tables and shard tables / publications.\n await sql.unsafe(globalSetup(shard) + shardSetup(shard, metadataPublication));\n\n const pubs = await getPublicationInfo(sql, allPublications);\n await replicaIdentitiesForTablesWithoutPrimaryKeys(pubs)?.apply(lc, sql);\n\n await setupTriggers(lc, sql, shard, includePartialIndexes);\n}\n\nexport async function setupTriggers(\n lc: LogContext,\n tx: PostgresTransaction,\n shard: ShardConfig,\n includePartialIndexes = true,\n) {\n const schema = upstreamSchema(shard);\n const [{ddlDetection}] = await tx<InternalShardConfig[]> /*sql*/ `\n SELECT \"ddlDetection\" FROM ${tx(schema)}.\"shardConfig\"`;\n\n // The functions invoked by event triggers are installed even if\n // event triggers are not supported/allowed by the db provider.\n // This allows users to manually invoke the update_schemas() function\n // as a workaround.\n await tx.unsafe(createEventFunctionStatements(shard, includePartialIndexes));\n try {\n await tx.savepoint(sub => sub.unsafe(triggerSetup(shard)));\n } catch (e) {\n if (ddlDetection) {\n // If ddlDetection has already been enabled, subsequent failures to\n // upgrade the trigger should be propagated rather than swallowed.\n throw e;\n }\n if (\n !(\n e instanceof postgres.PostgresError &&\n e.code === PG_INSUFFICIENT_PRIVILEGE\n )\n ) {\n throw e;\n }\n // If triggerSetup() fails, replication continues in ddlDetection=false mode.\n lc.warn?.(\n `Unable to create event triggers for schema change detection:\\n\\n` +\n `\"${e.hint ?? e.message}\"\\n\\n` +\n `Proceeding in degraded mode: schema changes will halt replication,\\n` +\n `requiring the replica to be reset (manually or with --auto-reset).`,\n );\n }\n}\n\nexport function validatePublications(\n lc: LogContext,\n published: PublicationInfo,\n) {\n // Verify that all publications export the proper events.\n published.publications.forEach(pub => {\n if (\n !pub.pubinsert ||\n !pub.pubupdate ||\n !pub.pubdelete ||\n !pub.pubtruncate\n ) {\n // TODO: Make APIError?\n throw new Error(\n `PUBLICATION ${pub.pubname} must publish insert, update, delete, and truncate`,\n );\n }\n });\n\n published.tables.forEach(table => validate(lc, table));\n}\n\ntype ReplicaIdentities = {\n apply(lc: LogContext, db: PostgresDB): Promise<void>;\n};\n\nexport function replicaIdentitiesForTablesWithoutPrimaryKeys(\n pubs: PublishedSchema,\n): ReplicaIdentities | undefined {\n const replicaIdentities: {\n schema: string;\n tableName: string;\n indexName: string;\n }[] = [];\n for (const table of pubs.tables) {\n if (!table.primaryKey?.length && table.replicaIdentity === Default) {\n // Look for an index that can serve as the REPLICA IDENTITY USING INDEX. It must be:\n // - UNIQUE\n // - NOT NULL columns\n // - not deferrable (i.e. isImmediate)\n // - not partial\n //\n // https://www.postgresql.org/docs/current/sql-altertable.html#SQL-ALTERTABLE-REPLICA-IDENTITY\n const {schema, name: tableName} = table;\n for (const {columns, name: indexName} of pubs.indexes.filter(\n idx =>\n idx.schema === schema &&\n idx.tableName === tableName &&\n idx.unique &&\n idx.isImmediate &&\n idx.predicate === undefined,\n )) {\n if (Object.keys(columns).some(col => !table.columns[col].notNull)) {\n continue; // Only indexes with all NOT NULL columns are suitable.\n }\n replicaIdentities.push({schema, tableName, indexName});\n break;\n }\n }\n }\n\n if (replicaIdentities.length === 0) {\n return undefined;\n }\n return {\n apply: async (lc: LogContext, sql: PostgresDB) => {\n for (const {schema, tableName, indexName} of replicaIdentities) {\n lc.info?.(\n `setting \"${indexName}\" as the REPLICA IDENTITY for \"${tableName}\"`,\n );\n await sql`\n ALTER TABLE ${sql(schema)}.${sql(tableName)} \n REPLICA IDENTITY USING INDEX ${sql(indexName)}`;\n }\n },\n };\n}\n"],"mappings":"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"}
@@ -1,6 +1,5 @@
1
1
  import type { LogContext } from '@rocicorp/logger';
2
2
  import type { PublishedTableWithReplicaIdentity } from './published.ts';
3
- export declare const ALLOWED_APP_ID_CHARACTERS: RegExp;
4
3
  export declare function validate(lc: LogContext, table: PublishedTableWithReplicaIdentity): void;
5
4
  export declare class UnsupportedTableSchemaError extends Error {
6
5
  readonly name = "UnsupportedTableSchemaError";
@@ -1 +1 @@
1
- {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../../../../../../../zero-cache/src/services/change-source/pg/schema/validation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAWjD,OAAO,KAAK,EAAC,iCAAiC,EAAC,MAAM,gBAAgB,CAAC;AAEtE,eAAO,MAAM,yBAAyB,QAAiB,CAAC;AAQxD,wBAAgB,QAAQ,CACtB,EAAE,EAAE,UAAU,EACd,KAAK,EAAE,iCAAiC,QAyCzC;AAED,qBAAa,2BAA4B,SAAQ,KAAK;IACpD,QAAQ,CAAC,IAAI,iCAAiC;IAE9C,YAAY,GAAG,EAAE,MAAM,EAEtB;CACF"}
1
+ {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../../../../../../../zero-cache/src/services/change-source/pg/schema/validation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAWjD,OAAO,KAAK,EAAC,iCAAiC,EAAC,MAAM,gBAAgB,CAAC;AAQtE,wBAAgB,QAAQ,CACtB,EAAE,EAAE,UAAU,EACd,KAAK,EAAE,iCAAiC,QAyCzC;AAED,qBAAa,2BAA4B,SAAQ,KAAK;IACpD,QAAQ,CAAC,IAAI,iCAAiC;IAE9C,YAAY,GAAG,EAAE,MAAM,EAEtB;CACF"}
@@ -21,6 +21,6 @@ var UnsupportedTableSchemaError = class extends Error {
21
21
  }
22
22
  };
23
23
  //#endregion
24
- export { validate };
24
+ export { UnsupportedTableSchemaError, validate };
25
25
 
26
26
  //# sourceMappingURL=validation.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"validation.js","names":[],"sources":["../../../../../../../../zero-cache/src/services/change-source/pg/schema/validation.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {\n mapPostgresToLite,\n warnIfDataTypeSupported,\n} from '../../../../db/pg-to-lite.ts';\nimport {\n Default,\n Index,\n Nothing,\n} from '../../../../db/postgres-replica-identity-enum.ts';\nimport {ZERO_VERSION_COLUMN_NAME} from '../../../replicator/schema/constants.ts';\nimport type {PublishedTableWithReplicaIdentity} from './published.ts';\n\nexport const ALLOWED_APP_ID_CHARACTERS = /^[a-z0-9_]+$/;\n\nconst ALLOWED_TABLE_CHARS = /^[A-Za-z_]+[A-Za-z0-9_-]*$/;\n\n// Dots are allowed in column names since there is no need for\n// a schema/table delimiter when mapped to SQLite names.\nconst ALLOWED_COLUMN_CHARS = /^[A-Za-z_]+[.A-Za-z0-9_-]*$/;\n\nexport function validate(\n lc: LogContext,\n table: PublishedTableWithReplicaIdentity,\n) {\n if (ZERO_VERSION_COLUMN_NAME in table.columns) {\n throw new UnsupportedTableSchemaError(\n `Table \"${table.name}\" uses reserved column name \"${ZERO_VERSION_COLUMN_NAME}\"`,\n );\n }\n if (!table.primaryKey?.length && table.replicaIdentity === Default) {\n lc.warn?.(\n `\\n\\n\\n` +\n `Table \"${table.name}\" needs a primary key in order to be synced to clients. ` +\n `Add one with 'ALTER TABLE \"${table.name}\" ADD PRIMARY KEY (...)'.` +\n `\\n\\n\\n`,\n );\n }\n if (table.replicaIdentity === Nothing) {\n throw new UnsupportedTableSchemaError(\n `Table \"${table.name}\" with REPLICA IDENTITY NOTHING cannot be replicated`,\n );\n }\n if (\n table.replicaIdentity === Index &&\n table.replicaIdentityColumns.length === 0\n ) {\n throw new UnsupportedTableSchemaError(\n `Table \"${table.name}\" is missing its REPLICA IDENTITY INDEX`,\n );\n }\n if (!ALLOWED_TABLE_CHARS.test(table.name)) {\n throw new UnsupportedTableSchemaError(\n `Table \"${table.name}\" has invalid characters.`,\n );\n }\n for (const [col, spec] of Object.entries(mapPostgresToLite(table).columns)) {\n if (!ALLOWED_COLUMN_CHARS.test(col)) {\n throw new UnsupportedTableSchemaError(\n `Column \"${col}\" in table \"${table.name}\" has invalid characters.`,\n );\n }\n warnIfDataTypeSupported(lc, spec.dataType, table.name, col);\n }\n}\n\nexport class UnsupportedTableSchemaError extends Error {\n readonly name = 'UnsupportedTableSchemaError';\n\n constructor(msg: string) {\n super(msg);\n }\n}\n"],"mappings":";;;AAeA,IAAM,sBAAsB;AAI5B,IAAM,uBAAuB;AAE7B,SAAgB,SACd,IACA,OACA;CACA,IAAA,gBAAgC,MAAM,SACpC,MAAM,IAAI,4BACR,UAAU,MAAM,KAAK,+BAA+B,yBAAyB,EAC/E;CAEF,IAAI,CAAC,MAAM,YAAY,UAAU,MAAM,oBAAA,KACrC,GAAG,OACD,gBACY,MAAM,KAAK,qFACS,MAAM,KAAK,gCAE7C;CAEF,IAAI,MAAM,oBAAA,KACR,MAAM,IAAI,4BACR,UAAU,MAAM,KAAK,qDACvB;CAEF,IACE,MAAM,oBAAA,OACN,MAAM,uBAAuB,WAAW,GAExC,MAAM,IAAI,4BACR,UAAU,MAAM,KAAK,wCACvB;CAEF,IAAI,CAAC,oBAAoB,KAAK,MAAM,IAAI,GACtC,MAAM,IAAI,4BACR,UAAU,MAAM,KAAK,0BACvB;CAEF,KAAK,MAAM,CAAC,KAAK,SAAS,OAAO,QAAQ,kBAAkB,KAAK,EAAE,OAAO,GAAG;EAC1E,IAAI,CAAC,qBAAqB,KAAK,GAAG,GAChC,MAAM,IAAI,4BACR,WAAW,IAAI,cAAc,MAAM,KAAK,0BAC1C;EAEF,wBAAwB,IAAI,KAAK,UAAU,MAAM,MAAM,GAAG;CAC5D;AACF;AAEA,IAAa,8BAAb,cAAiD,MAAM;CACrD,OAAgB;CAEhB,YAAY,KAAa;EACvB,MAAM,GAAG;CACX;AACF"}
1
+ {"version":3,"file":"validation.js","names":[],"sources":["../../../../../../../../zero-cache/src/services/change-source/pg/schema/validation.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {\n mapPostgresToLite,\n warnIfDataTypeSupported,\n} from '../../../../db/pg-to-lite.ts';\nimport {\n Default,\n Index,\n Nothing,\n} from '../../../../db/postgres-replica-identity-enum.ts';\nimport {ZERO_VERSION_COLUMN_NAME} from '../../../replicator/schema/constants.ts';\nimport type {PublishedTableWithReplicaIdentity} from './published.ts';\n\nconst ALLOWED_TABLE_CHARS = /^[A-Za-z_]+[A-Za-z0-9_-]*$/;\n\n// Dots are allowed in column names since there is no need for\n// a schema/table delimiter when mapped to SQLite names.\nconst ALLOWED_COLUMN_CHARS = /^[A-Za-z_]+[.A-Za-z0-9_-]*$/;\n\nexport function validate(\n lc: LogContext,\n table: PublishedTableWithReplicaIdentity,\n) {\n if (ZERO_VERSION_COLUMN_NAME in table.columns) {\n throw new UnsupportedTableSchemaError(\n `Table \"${table.name}\" uses reserved column name \"${ZERO_VERSION_COLUMN_NAME}\"`,\n );\n }\n if (!table.primaryKey?.length && table.replicaIdentity === Default) {\n lc.warn?.(\n `\\n\\n\\n` +\n `Table \"${table.name}\" needs a primary key in order to be synced to clients. ` +\n `Add one with 'ALTER TABLE \"${table.name}\" ADD PRIMARY KEY (...)'.` +\n `\\n\\n\\n`,\n );\n }\n if (table.replicaIdentity === Nothing) {\n throw new UnsupportedTableSchemaError(\n `Table \"${table.name}\" with REPLICA IDENTITY NOTHING cannot be replicated`,\n );\n }\n if (\n table.replicaIdentity === Index &&\n table.replicaIdentityColumns.length === 0\n ) {\n throw new UnsupportedTableSchemaError(\n `Table \"${table.name}\" is missing its REPLICA IDENTITY INDEX`,\n );\n }\n if (!ALLOWED_TABLE_CHARS.test(table.name)) {\n throw new UnsupportedTableSchemaError(\n `Table \"${table.name}\" has invalid characters.`,\n );\n }\n for (const [col, spec] of Object.entries(mapPostgresToLite(table).columns)) {\n if (!ALLOWED_COLUMN_CHARS.test(col)) {\n throw new UnsupportedTableSchemaError(\n `Column \"${col}\" in table \"${table.name}\" has invalid characters.`,\n );\n }\n warnIfDataTypeSupported(lc, spec.dataType, table.name, col);\n }\n}\n\nexport class UnsupportedTableSchemaError extends Error {\n readonly name = 'UnsupportedTableSchemaError';\n\n constructor(msg: string) {\n super(msg);\n }\n}\n"],"mappings":";;;AAaA,IAAM,sBAAsB;AAI5B,IAAM,uBAAuB;AAE7B,SAAgB,SACd,IACA,OACA;CACA,IAAA,gBAAgC,MAAM,SACpC,MAAM,IAAI,4BACR,UAAU,MAAM,KAAK,+BAA+B,yBAAyB,EAC/E;CAEF,IAAI,CAAC,MAAM,YAAY,UAAU,MAAM,oBAAA,KACrC,GAAG,OACD,gBACY,MAAM,KAAK,qFACS,MAAM,KAAK,gCAE7C;CAEF,IAAI,MAAM,oBAAA,KACR,MAAM,IAAI,4BACR,UAAU,MAAM,KAAK,qDACvB;CAEF,IACE,MAAM,oBAAA,OACN,MAAM,uBAAuB,WAAW,GAExC,MAAM,IAAI,4BACR,UAAU,MAAM,KAAK,wCACvB;CAEF,IAAI,CAAC,oBAAoB,KAAK,MAAM,IAAI,GACtC,MAAM,IAAI,4BACR,UAAU,MAAM,KAAK,0BACvB;CAEF,KAAK,MAAM,CAAC,KAAK,SAAS,OAAO,QAAQ,kBAAkB,KAAK,CAAC,CAAC,OAAO,GAAG;EAC1E,IAAI,CAAC,qBAAqB,KAAK,GAAG,GAChC,MAAM,IAAI,4BACR,WAAW,IAAI,cAAc,MAAM,KAAK,0BAC1C;EAEF,wBAAwB,IAAI,KAAK,UAAU,MAAM,MAAM,GAAG;CAC5D;AACF;AAEA,IAAa,8BAAb,cAAiD,MAAM;CACrD,OAAgB;CAEhB,YAAY,KAAa;EACvB,MAAM,GAAG;CACX;AACF"}
@@ -136,6 +136,6 @@ function getSuperset(...requestSets) {
136
136
  return [...merged.values()];
137
137
  }
138
138
  //#endregion
139
- export { acceptBackfill, covers, getSuperset, resumePoint, withResumePoint };
139
+ export { acceptBackfill, covers, getSuperset, getTableSuperset, resumePoint, withResumePoint };
140
140
 
141
141
  //# sourceMappingURL=backfill-progress.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"backfill-progress.js","names":[],"sources":["../../../../../../../zero-cache/src/services/change-source/protocol/backfill-progress.ts"],"sourcesContent":["import {deepEqual} from '../../../../../shared/src/json.ts';\nimport type {\n BackfillProgressMark,\n BackfillRequest,\n Identifier,\n} from './current.ts';\n\n/**\n * Whether two progress marks are on the same timeline, and are thus comparable.\n */\nfunction sameTimeline(a: BackfillProgressMark, b: BackfillProgressMark) {\n return a.timeline === b.timeline;\n}\n\n/** Returns the earlier of two marks on the same timeline. */\nfunction earlier(\n a: BackfillProgressMark,\n b: BackfillProgressMark,\n): BackfillProgressMark {\n return b.progressMark < a.progressMark ? b : a;\n}\n\n/** Returns the later of two marks on the same timeline. */\nfunction later(\n a: BackfillProgressMark,\n b: BackfillProgressMark,\n): BackfillProgressMark {\n return b.progressMark > a.progressMark ? b : a;\n}\n\n/**\n * The result of applying a backfill message to a column's tracked progress.\n * If `accept` is true, `progress` is the column's new progress.\n */\nexport type AcceptResult =\n | {accept: true; progress: BackfillProgressMark | undefined}\n | {accept: false};\n\n/**\n * Applies the continuity policy of `backfill` (and `backfill-completed`)\n * messages to a column's `own` tracked progress, where `undefined` means that\n * the column has not received any backfill data (i.e. it needs a backfill\n * from scratch).\n *\n * * Messages without `progressMarks` are from pre-v8 replication-managers\n * and are accepted unconditionally (i.e. the legacy behavior), with no\n * change to the tracked progress.\n * * A message without a `previous` mark starts a backfill from scratch (or on\n * a new timeline), and is always accepted.\n * * Otherwise, the message is only accepted if it is on the same timeline as\n * `own`, and continues from a position at or before `own` (i.e. it does not\n * create a gap).\n *\n * `current` is unset for `backfill-completed` messages, which do not advance\n * the progress.\n */\nexport function acceptBackfill(\n own: BackfillProgressMark | undefined,\n marks:\n | {\n previous?: BackfillProgressMark | undefined;\n current?: BackfillProgressMark;\n }\n | undefined,\n): AcceptResult {\n if (marks === undefined) {\n return {accept: true, progress: own}; // legacy (pre-v8)\n }\n const {previous, current} = marks;\n // Starting from scratch is always accepted, as there can be no gap.\n if (previous === undefined) {\n return {accept: true, progress: current};\n }\n if (\n own === undefined ||\n !sameTimeline(own, previous) ||\n previous.progressMark > own.progressMark\n ) {\n return {accept: false};\n }\n return {\n accept: true,\n progress:\n current === undefined\n ? own\n : sameTimeline(own, current)\n ? later(own, current)\n : current,\n };\n}\n\n/**\n * Returns whether a stream whose progress (for a column) is at `stream`\n * will deliver all of the data needed by a subscriber whose progress (for the\n * same column) is at `subscriber`. A `stream` progress of `undefined` indicates\n * a backfill that will start from scratch, which covers all subscribers.\n */\nexport function covers(\n stream: BackfillProgressMark | undefined,\n subscriber: BackfillProgressMark | undefined,\n): boolean {\n return (\n stream === undefined ||\n (subscriber !== undefined &&\n sameTimeline(stream, subscriber) &&\n stream.progressMark <= subscriber.progressMark)\n );\n}\n\n/**\n * Returns the position from which a backfill for the `req` must start\n * in order to satisfy the progress of all of its columns, i.e. the earliest\n * progress mark, or `undefined` (i.e. from scratch) if any column has no\n * progress or if the columns are on different timelines.\n */\nexport function resumePoint(\n req: BackfillRequest,\n): BackfillProgressMark | undefined {\n let point: BackfillProgressMark | undefined;\n for (const {progress} of Object.values(req.columns)) {\n if (progress === undefined) {\n return undefined;\n }\n if (point === undefined) {\n point = progress;\n } else if (!sameTimeline(point, progress)) {\n return undefined;\n } else {\n point = earlier(point, progress);\n }\n }\n return point;\n}\n\n/**\n * Returns a copy of the `req` with the progress of every column set to\n * the request's {@link resumePoint}, i.e. the position from which the\n * backfill of the request will actually start.\n */\nexport function withResumePoint(req: BackfillRequest): BackfillRequest {\n const progress = resumePoint(req);\n return {\n table: req.table,\n columns: Object.fromEntries(\n Object.entries(req.columns).map(([col, {id}]) => [\n col,\n progress === undefined ? {id} : {id, progress},\n ]),\n ),\n };\n}\n\n/**\n * Merges two BackfillRequests for the same table into one that satisfies\n * both. Both requests are expected to reflect the same (current) upstream\n * schema. For columns in both requests, the earlier progress mark is chosen,\n * or no progress mark (i.e. from scratch) if they are on different timelines.\n * If a column's backfill IDs differ (which is unexpected), the ID of `req1`\n * is chosen, and the column is backfilled from scratch.\n */\nexport function getTableSuperset(\n req1: BackfillRequest,\n req2: BackfillRequest,\n): BackfillRequest {\n const columns = {...req1.columns};\n for (const [name, col] of Object.entries(req2.columns)) {\n const exists = columns[name];\n if (!exists) {\n columns[name] = col;\n continue;\n }\n const {id, progress} = exists;\n if (\n progress === undefined ||\n col.progress === undefined ||\n !sameTimeline(progress, col.progress) ||\n !deepEqual(id, col.id)\n ) {\n // Different timelines (or IDs). Start from scratch.\n columns[name] = {id};\n } else {\n columns[name] = {id, progress: earlier(progress, col.progress)};\n }\n }\n return {\n table: {\n ...req1.table,\n metadata: req1.table.metadata ?? req2.table.metadata,\n },\n columns,\n };\n}\n\nfunction tableKey({schema, name}: Identifier) {\n return JSON.stringify([schema, name]);\n}\n\n/**\n * Merges the BackfillRequests of multiple parties (e.g. subscribers) into\n * one request per table, using {@link getTableSuperset}.\n */\nexport function getSuperset(\n ...requestSets: Iterable<BackfillRequest>[]\n): BackfillRequest[] {\n const merged = new Map<string, BackfillRequest>();\n for (const requests of requestSets) {\n for (const req of requests) {\n const key = tableKey(req.table);\n const existing = merged.get(key);\n merged.set(key, existing ? getTableSuperset(existing, req) : req);\n }\n }\n return [...merged.values()];\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"backfill-progress.js","names":[],"sources":["../../../../../../../zero-cache/src/services/change-source/protocol/backfill-progress.ts"],"sourcesContent":["import {deepEqual} from '../../../../../shared/src/json.ts';\nimport type {\n BackfillProgressMark,\n BackfillRequest,\n Identifier,\n} from './current.ts';\n\n/**\n * Whether two progress marks are on the same timeline, and are thus comparable.\n */\nfunction sameTimeline(a: BackfillProgressMark, b: BackfillProgressMark) {\n return a.timeline === b.timeline;\n}\n\n/** Returns the earlier of two marks on the same timeline. */\nfunction earlier(\n a: BackfillProgressMark,\n b: BackfillProgressMark,\n): BackfillProgressMark {\n return b.progressMark < a.progressMark ? b : a;\n}\n\n/** Returns the later of two marks on the same timeline. */\nfunction later(\n a: BackfillProgressMark,\n b: BackfillProgressMark,\n): BackfillProgressMark {\n return b.progressMark > a.progressMark ? b : a;\n}\n\n/**\n * The result of applying a backfill message to a column's tracked progress.\n * If `accept` is true, `progress` is the column's new progress.\n */\nexport type AcceptResult =\n | {accept: true; progress: BackfillProgressMark | undefined}\n | {accept: false};\n\n/**\n * Applies the continuity policy of `backfill` (and `backfill-completed`)\n * messages to a column's `own` tracked progress, where `undefined` means that\n * the column has not received any backfill data (i.e. it needs a backfill\n * from scratch).\n *\n * * Messages without `progressMarks` are from pre-v8 replication-managers\n * and are accepted unconditionally (i.e. the legacy behavior), with no\n * change to the tracked progress.\n * * A message without a `previous` mark starts a backfill from scratch (or on\n * a new timeline), and is always accepted.\n * * Otherwise, the message is only accepted if it is on the same timeline as\n * `own`, and continues from a position at or before `own` (i.e. it does not\n * create a gap).\n *\n * `current` is unset for `backfill-completed` messages, which do not advance\n * the progress.\n */\nexport function acceptBackfill(\n own: BackfillProgressMark | undefined,\n marks:\n | {\n previous?: BackfillProgressMark | undefined;\n current?: BackfillProgressMark;\n }\n | undefined,\n): AcceptResult {\n if (marks === undefined) {\n return {accept: true, progress: own}; // legacy (pre-v8)\n }\n const {previous, current} = marks;\n // Starting from scratch is always accepted, as there can be no gap.\n if (previous === undefined) {\n return {accept: true, progress: current};\n }\n if (\n own === undefined ||\n !sameTimeline(own, previous) ||\n previous.progressMark > own.progressMark\n ) {\n return {accept: false};\n }\n return {\n accept: true,\n progress:\n current === undefined\n ? own\n : sameTimeline(own, current)\n ? later(own, current)\n : current,\n };\n}\n\n/**\n * Returns whether a stream whose progress (for a column) is at `stream`\n * will deliver all of the data needed by a subscriber whose progress (for the\n * same column) is at `subscriber`. A `stream` progress of `undefined` indicates\n * a backfill that will start from scratch, which covers all subscribers.\n */\nexport function covers(\n stream: BackfillProgressMark | undefined,\n subscriber: BackfillProgressMark | undefined,\n): boolean {\n return (\n stream === undefined ||\n (subscriber !== undefined &&\n sameTimeline(stream, subscriber) &&\n stream.progressMark <= subscriber.progressMark)\n );\n}\n\n/**\n * Returns the position from which a backfill for the `req` must start\n * in order to satisfy the progress of all of its columns, i.e. the earliest\n * progress mark, or `undefined` (i.e. from scratch) if any column has no\n * progress or if the columns are on different timelines.\n */\nexport function resumePoint(\n req: BackfillRequest,\n): BackfillProgressMark | undefined {\n let point: BackfillProgressMark | undefined;\n for (const {progress} of Object.values(req.columns)) {\n if (progress === undefined) {\n return undefined;\n }\n if (point === undefined) {\n point = progress;\n } else if (!sameTimeline(point, progress)) {\n return undefined;\n } else {\n point = earlier(point, progress);\n }\n }\n return point;\n}\n\n/**\n * Returns a copy of the `req` with the progress of every column set to\n * the request's {@link resumePoint}, i.e. the position from which the\n * backfill of the request will actually start.\n */\nexport function withResumePoint(req: BackfillRequest): BackfillRequest {\n const progress = resumePoint(req);\n return {\n table: req.table,\n columns: Object.fromEntries(\n Object.entries(req.columns).map(([col, {id}]) => [\n col,\n progress === undefined ? {id} : {id, progress},\n ]),\n ),\n };\n}\n\n/**\n * Merges two BackfillRequests for the same table into one that satisfies\n * both. Both requests are expected to reflect the same (current) upstream\n * schema. For columns in both requests, the earlier progress mark is chosen,\n * or no progress mark (i.e. from scratch) if they are on different timelines.\n * If a column's backfill IDs differ (which is unexpected), the ID of `req1`\n * is chosen, and the column is backfilled from scratch.\n */\nexport function getTableSuperset(\n req1: BackfillRequest,\n req2: BackfillRequest,\n): BackfillRequest {\n const columns = {...req1.columns};\n for (const [name, col] of Object.entries(req2.columns)) {\n const exists = columns[name];\n if (!exists) {\n columns[name] = col;\n continue;\n }\n const {id, progress} = exists;\n if (\n progress === undefined ||\n col.progress === undefined ||\n !sameTimeline(progress, col.progress) ||\n !deepEqual(id, col.id)\n ) {\n // Different timelines (or IDs). Start from scratch.\n columns[name] = {id};\n } else {\n columns[name] = {id, progress: earlier(progress, col.progress)};\n }\n }\n return {\n table: {\n ...req1.table,\n metadata: req1.table.metadata ?? req2.table.metadata,\n },\n columns,\n };\n}\n\nfunction tableKey({schema, name}: Identifier) {\n return JSON.stringify([schema, name]);\n}\n\n/**\n * Merges the BackfillRequests of multiple parties (e.g. subscribers) into\n * one request per table, using {@link getTableSuperset}.\n */\nexport function getSuperset(\n ...requestSets: Iterable<BackfillRequest>[]\n): BackfillRequest[] {\n const merged = new Map<string, BackfillRequest>();\n for (const requests of requestSets) {\n for (const req of requests) {\n const key = tableKey(req.table);\n const existing = merged.get(key);\n merged.set(key, existing ? getTableSuperset(existing, req) : req);\n }\n }\n return [...merged.values()];\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"control.js","names":[],"sources":["../../../../../../../../zero-cache/src/services/change-source/protocol/current/control.ts"],"sourcesContent":["/**\n * Control plane messages communicate non-content related signals between a\n * ChangeSource and ChangeStreamer. These are not forwarded to subscribers\n * of the ChangeStreamer.\n */\nimport * as v from '../../../../../../shared/src/valita.ts';\nimport {jsonObjectSchema} from './json.ts';\n\n/**\n * Indicates that replication cannot continue and that the replica must be resynced\n * from scratch. The replication-manager will shutdown in response to this message,\n * and upon being restarted, it will wipe the current replica and resync if the\n * `--auto-reset` option is specified.\n *\n * This signal should only be used in well advertised scenarios, and is not suitable\n * as a common occurrence in production.\n */\nexport const resetRequiredSchema = v.object({\n tag: v.literal('reset-required'),\n message: v.string().optional(),\n\n // errorDetails can contain any standard JSON object. This will be\n // published in the `errorDetails` field of a replication ERROR event.\n errorDetails: jsonObjectSchema.optional(),\n});\n"],"mappings":";;;;;;;;;;;;;;;;;AAiBA,IAAa,sBAAsB,eAAE,OAAO;CAC1C,KAAK,eAAE,QAAQ,gBAAgB;CAC/B,SAAS,eAAE,OAAO,EAAE,SAAS;CAI7B,cAAc,iBAAiB,SAAS;AAC1C,CAAC"}
1
+ {"version":3,"file":"control.js","names":["v"],"sources":["../../../../../../../../zero-cache/src/services/change-source/protocol/current/control.ts"],"sourcesContent":["/**\n * Control plane messages communicate non-content related signals between a\n * ChangeSource and ChangeStreamer. These are not forwarded to subscribers\n * of the ChangeStreamer.\n */\nimport * as v from '../../../../../../shared/src/valita.ts';\nimport {jsonObjectSchema} from './json.ts';\n\n/**\n * Indicates that replication cannot continue and that the replica must be resynced\n * from scratch. The replication-manager will shutdown in response to this message,\n * and upon being restarted, it will wipe the current replica and resync if the\n * `--auto-reset` option is specified.\n *\n * This signal should only be used in well advertised scenarios, and is not suitable\n * as a common occurrence in production.\n */\nexport const resetRequiredSchema = v.object({\n tag: v.literal('reset-required'),\n message: v.string().optional(),\n\n // errorDetails can contain any standard JSON object. This will be\n // published in the `errorDetails` field of a replication ERROR event.\n errorDetails: jsonObjectSchema.optional(),\n});\n"],"mappings":";;;;;;;;;;;;;;;;;AAiBA,IAAa,sBAAsBA,eAAE,OAAO;CAC1C,KAAKA,eAAE,QAAQ,gBAAgB;CAC/B,SAASA,eAAE,OAAO,CAAC,CAAC,SAAS;CAI7B,cAAc,iBAAiB,SAAS;AAC1C,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"data.js","names":[],"sources":["../../../../../../../../zero-cache/src/services/change-source/protocol/current/data.ts"],"sourcesContent":["/**\n * Data plane messages encapsulate changes that are sent by ChangeSources,\n * forwarded / fanned out to subscribers by the ChangeStreamerService, and\n * stored in the Change DB for catchup of old subscribers.\n */\n\nimport {\n jsonValueSchema,\n type JSONObject,\n} from '../../../../../../shared/src/bigint-json.ts';\nimport {must} from '../../../../../../shared/src/must.ts';\nimport * as v from '../../../../../../shared/src/valita.ts';\nimport {columnSpec, indexSpec, tableSpec} from '../../../../db/specs.ts';\nimport type {Satisfies} from '../../../../types/satisfies.ts';\nimport {jsonObjectSchema} from './json.ts';\nimport {schemaChangeTags} from './schema-change-tags.ts';\n\nexport const beginSchema = v.object({\n tag: v.literal('begin'),\n // The format of values of \"json\"-typed columns (e.g. \"JSON\" and \"JSONB\").\n // - 'p' is for parsed JSON, which may include JSON values or JSON objects.\n // These values are parsed and stringified at every process boundary\n // between the change-source and the replica.\n // - 's' is for stringified JSON. These values skip the parsing and\n // stringification, and are directly ferried to the replica as a JSON\n // string. For JSON values this improves performance by 20~25% in the\n // change-streamer and 25~30% in the replicator.\n //\n // If absent, the format is assumed to be 'p' (parsed JSON objects/values).\n json: v.literalUnion('p', 's').optional(),\n\n // Directs the change-streamer to skip the ACK for the corresponding commit.\n skipAck: v.boolean().optional(),\n});\n\nexport const commitSchema = v.object({\n tag: v.literal('commit'),\n\n // Millisecond epoch at which the transaction committed upstream, as reported\n // by the upstream database (e.g. the `commitTime` of the Postgres logical\n // replication Commit message).\n //\n // This is the origin timestamp of the end-to-end serving lag measurement:\n // it is carried through the replication stream to the ViewSyncer, which\n // records `now - commitTimeMs` once the change has been poked to clients.\n //\n // Optional because it is absent from changes written to the Change DB by\n // older versions, which are replayed verbatim during catchup, and from\n // ChangeSources that do not report a commit time.\n commitTimeMs: v.number().optional(),\n});\n\nexport const rollbackSchema = v.object({\n tag: v.literal('rollback'),\n});\n\nconst rowKeySchema = v.object({\n // The columns used to identify a row in insert, update, and delete changes.\n columns: v.array(v.string()),\n\n // An optional qualifier identifying how the key is chosen. Currently this\n // is postgres-specific, describing the REPLICA IDENTITY, for which replica\n // identity 'full' (FULL) is handled differently; the replicator handles\n // these tables by extracting a row key from the full row based on the\n // table's PRIMARY KEY or UNIQUE INDEX.\n type: v.literalUnion('default', 'nothing', 'full', 'index').optional(),\n});\n\nexport const relationSchema = v\n .object({\n schema: v.string(),\n name: v.string(),\n\n // This will become required.\n rowKey: rowKeySchema.optional(),\n\n /** Deprecated: set the rowKey.columns instead. */\n keyColumns: v.array(v.string()).optional(),\n /** Deprecated: set the rowKey.columns instead. */\n replicaIdentity: v\n .literalUnion('default', 'nothing', 'full', 'index')\n .optional(),\n })\n .map(rel => {\n const {rowKey, ...rest} = rel;\n if (rowKey) {\n return {...rest, rowKey};\n }\n return {\n ...rest,\n rowKey: {\n columns: must(rel.keyColumns),\n type: rel.replicaIdentity,\n },\n };\n });\n\n// The eventual fate of relationSchema\nexport const newRelationSchema = v.object({\n schema: v.string(),\n name: v.string(),\n\n rowKey: rowKeySchema,\n});\n\n// TableMetadata contains table-related configuration that does not affect the\n// actual data in the table, but rather how the table's change messages are\n// handled. The is an opaque object that clients must track (and update) based\n// on `create-table`, `add-column`, and `table-update-metadata` messages, and\n// pass in BackfillRequests when there are columns to be backfilled.\n//\n// Note that the backfill-related change-source implementation does, however,\n// rely on the rowKey (columns) being specified in the message.\nexport const tableMetadataSchema = v\n .object({rowKey: v.record(jsonValueSchema)})\n .rest(jsonValueSchema);\n\nexport type TableMetadata = v.Infer<typeof tableMetadataSchema>;\n\nexport const rowSchema = v.record(jsonValueSchema);\n\nexport const insertSchema = v.object({\n tag: v.literal('insert'),\n relation: relationSchema,\n new: rowSchema,\n});\n\nexport const updateSchema = v.object({\n tag: v.literal('update'),\n relation: relationSchema,\n // `key` is present if the update changed the key of the row, or if the\n // table's replicaIdentity === 'full'\n key: rowSchema.nullable(),\n // `new` is the full row (and not just the updated columns). This is\n // necessary for \"catchup\" replication scenarios such as adding tables\n // to a publication, or resharding.\n new: rowSchema,\n});\n\nexport const deleteSchema = v.object({\n tag: v.literal('delete'),\n relation: relationSchema,\n // key is the full row if replicaIdentity === 'full'\n key: rowSchema,\n});\n\nexport const truncateSchema = v.object({\n tag: v.literal('truncate'),\n relations: v.array(relationSchema),\n});\n\nexport const identifierSchema = v.object({\n schema: v.string(),\n name: v.string(),\n});\n\nexport type Identifier = v.Infer<typeof identifierSchema>;\n\n// A BackfillID is an upstream specific stable identifier for a column\n// that needs backfilling. This id is used to ensure that the schema, table,\n// and column names of a requested backfill still match the original\n// underlying upstream ID.\n//\n// The change-streamer stores these IDs as opaque values while a column is\n// being backfilled, and initiates new change-source streams with the IDs\n// in order to restart backfills that did not complete in previous sessions.\nexport const backfillIDSchema = jsonObjectSchema;\n\nexport type BackfillID = v.Infer<typeof backfillIDSchema>;\n\nexport const backfillProgressMarkSchema = v\n .object({\n // A lexicographically sortable string delineating the progress of a\n // backfill. This is used to resume a backfill that did not complete.\n progressMark: v.string(),\n\n // Optionally, a timeline with which the progressMark is associated.\n // A timeline is an opaque string that determines if backfill streams\n // are \"compatible\" with each other, i.e. can be merged in a way that\n // avoids gaps. progressMarks from different timelines are not\n // compatible. If two timelines differ, a new backfill is started\n // from scratch in order to get all subscribers on the same timeline.\n //\n // Timeline changes should be rare events (e.g. Postgres VACUUM FULL).\n timeline: v.string().optional(),\n })\n // All other fields should be preserved and returned in BackfillRequests.\n .rest(v.union(v.number(), v.string()));\n\nexport type BackfillProgressMark = v.Infer<typeof backfillProgressMarkSchema>;\n\nexport const createTableSchema = v.object({\n tag: v.literal('create-table'),\n spec: tableSpec,\n\n // This must be set by change source implementations that support\n // table/column backfill.\n //\n // TODO: to simplify the protocol, see if we can make this required\n metadata: tableMetadataSchema.optional(),\n\n // Indicate that columns of the table require backfilling. These columns\n // should be created on the replica but not yet synced the clients.\n //\n // ## State Persistence\n //\n // To obviate the need for change-source implementations to persist state\n // related to backfill progress, the change-source only tracks backfills\n // **for the current session**. In the event that the session is interrupted\n // before columns have been fully backfilled, it is the responsibility of the\n // change-streamer to send {@link BackfillRequest}s when it reconnects.\n //\n // This means that the change-streamer must track and persist:\n // * the backfill IDs of the columns requiring backfilling\n // * the most current table metadata of the associated table(s)\n //\n // The change-streamer then uses this information to send backfill requests\n // when it reconnects.\n backfill: v.record(backfillIDSchema).optional(),\n});\n\nexport const renameTableSchema = v.object({\n tag: v.literal('rename-table'),\n old: identifierSchema,\n new: identifierSchema,\n});\n\nexport const updateTableMetadataSchema = v.object({\n tag: v.literal('update-table-metadata'),\n table: identifierSchema,\n old: tableMetadataSchema,\n new: tableMetadataSchema,\n});\n\nconst columnSchema = v.object({\n name: v.string(),\n spec: columnSpec,\n});\n\nexport const addColumnSchema = v.object({\n tag: v.literal('add-column'),\n table: identifierSchema,\n column: columnSchema,\n\n // This must be set by change source implementations that support\n // table/column backfill.\n //\n // TODO: to simplify the protocol, see if we can make this required\n tableMetadata: tableMetadataSchema.optional(),\n\n // See documentation for the `backfill` field of the `create-table` change.\n backfill: backfillIDSchema.optional(),\n});\n\nexport const updateColumnSchema = v.object({\n tag: v.literal('update-column'),\n table: identifierSchema,\n old: columnSchema,\n new: columnSchema,\n});\n\nexport const dropColumnSchema = v.object({\n tag: v.literal('drop-column'),\n table: identifierSchema,\n column: v.string(),\n});\n\nexport const dropTableSchema = v.object({\n tag: v.literal('drop-table'),\n id: identifierSchema,\n});\n\nexport const createIndexSchema = v.object({\n tag: v.literal('create-index'),\n spec: indexSpec,\n});\n\nexport const dropIndexSchema = v.object({\n tag: v.literal('drop-index'),\n id: identifierSchema,\n});\n\nexport const downloadStatusSchema = v.object({\n rows: v.number(),\n totalRows: v.number(),\n totalBytes: v.number().optional(),\n});\n\nexport type DownloadStatus = v.Infer<typeof downloadStatusSchema>;\n\n// A batch of rows from a single table containing column values\n// to be backfilled.\nexport const backfillSchema = v.object({\n tag: v.literal('backfill'),\n\n relation: newRelationSchema,\n\n // The columns to be backfilled. `rowKey` columns are automatically excluded,\n // which means that this field may be empty.\n columns: v.array(v.string()),\n\n // The watermark at which the backfill data was queried. Note that this\n // generally will be different from the commit watermarks of the main change\n // stream, and in particular, the commit watermark of the backfill change's\n // enclosing transaction.\n watermark: v.string(),\n\n // A batch of row values, each row consisting of the `rowKey`\n // values, followed by the `column` values, in the same order in which\n // the column names appear in their respective fields, e.g.\n //\n // ```\n // [\n // [...rowKeyValues, ...columnValues], // row 1\n // [...rowKeyValues, ...columnValues], // row 2\n // ]\n // ```\n rowValues: v.array(v.array(jsonValueSchema)),\n\n // Progress marks indicating the position of this backfill message\n // within the stream, for resumption / continuity enforcement.\n //\n // This should be considered non-optional as of protocol v8. It is only\n // absent in messages from pre-v8 replication-managers (including messages\n // persisted in a change-log by one), in which case subscribers accept the\n // message unconditionally (i.e. the legacy behavior).\n progressMarks: v\n .object({\n // The progress mark of the preceding backfill message, from which\n // the current backfill message is a continuation. (This may be a\n // \"logical\" continuation at which a new backfill stream is started when\n // resuming from a previous stream.)\n //\n // For the first backfill message of a stream starting from scratch,\n // this field is unset. When the field is unset, subscribers should\n // accept the backfill message unconditionally (i.e. starting a\n // backfill from scratch is always safe).\n //\n // If the field is set, subscribers should only accept the message if\n // it is of the same timeline as that of its own tracked progressMark,\n // and is contiguous with or earlier than its own progressMark.\n //\n // In other words, it should _ignore_ backfill messages from other\n // timelines, or messages that create a gap; this can happen when\n // receiving messages from before this subscriber's backfill requests\n // are taken into account.\n //\n // Implementation note: The change-streamer applies this same policy\n // (see `acceptBackfill()` in `protocol/backfill-progress.ts`) to track\n // the backfill state of each subscriber, which it uses to determine the\n // BackfillRequests with which to (re)start change streams.\n previous: backfillProgressMarkSchema.optional(),\n\n // The progressMark delineating the position of the last row in this\n // message. In the steady state, this will be the `previous`\n // progressMark of the next backfill message, unless a rewind is\n // requested, or new timeline encountered.\n current: backfillProgressMarkSchema,\n })\n .optional(),\n\n // Optionally includes the progress of the backfill operation,\n // for display purposes.\n status: downloadStatusSchema.optional(),\n});\n\n// Indicates that the backfill for the specified columns have\n// been successfully backfilled and can be published to clients.\nexport const backfillCompletedSchema = v.object({\n tag: v.literal('backfill-completed'),\n\n relation: newRelationSchema,\n\n // The columns to be backfilled. `rowKey` columns are automatically excluded,\n // which means that this field may be empty.\n columns: v.array(v.string()),\n\n // The watermark at which the backfill data was queried. Note that this\n // generally will be different from the commit watermarks of the main change\n // stream, and in particular, the commit watermark of the backfill change's\n // enclosing transaction.\n watermark: v.string(),\n\n // The progress mark of the last backfill message of the run, i.e. the\n // `current` progressMark of the last `backfill` message, or the progressMark\n // from which the run was resumed if it produced no `backfill` messages.\n // Subscribers apply the same continuity policy as for `backfill` messages,\n // and only consider the columns backfilled if the run is contiguous with\n // their own progress.\n //\n // `previous` is only unset for a run that started from scratch and\n // produced no rows (e.g. an empty table), which is always safe to accept.\n //\n // This should be considered non-optional as of protocol v8. It is only\n // absent in messages from pre-v8 replication-managers, in which case\n // subscribers accept the message unconditionally (i.e. legacy behavior).\n progressMarks: v\n .object({previous: backfillProgressMarkSchema.optional()})\n .optional(),\n\n // Optionally includes the final status of the backfill operation,\n // for display purposes.\n status: downloadStatusSchema.optional(),\n});\n\nexport type MessageBegin = v.Infer<typeof beginSchema>;\nexport type MessageCommit = v.Infer<typeof commitSchema>;\nexport type MessageRollback = v.Infer<typeof rollbackSchema>;\n\nexport type MessageRelation = v.Infer<typeof relationSchema>;\nexport type MessageInsert = v.Infer<typeof insertSchema>;\nexport type MessageUpdate = v.Infer<typeof updateSchema>;\nexport type MessageDelete = v.Infer<typeof deleteSchema>;\nexport type MessageTruncate = v.Infer<typeof truncateSchema>;\n\nexport type MessageBackfill = v.Infer<typeof backfillSchema>;\n\nexport type TableCreate = v.Infer<typeof createTableSchema>;\nexport type TableRename = v.Infer<typeof renameTableSchema>;\nexport type TableUpdateMetadata = v.Infer<typeof updateTableMetadataSchema>;\nexport type ColumnAdd = v.Infer<typeof addColumnSchema>;\nexport type ColumnUpdate = v.Infer<typeof updateColumnSchema>;\nexport type ColumnDrop = v.Infer<typeof dropColumnSchema>;\nexport type TableDrop = v.Infer<typeof dropTableSchema>;\nexport type IndexCreate = v.Infer<typeof createIndexSchema>;\nexport type IndexDrop = v.Infer<typeof dropIndexSchema>;\nexport type BackfillCompleted = v.Infer<typeof backfillCompletedSchema>;\n\nexport const dataChangeSchema = v.union(\n insertSchema,\n updateSchema,\n deleteSchema,\n truncateSchema,\n backfillSchema,\n);\n\n// Note: keep in sync or the tag tests will fail\nconst dataChangeTags = [\n 'insert',\n 'update',\n 'delete',\n 'truncate',\n 'backfill',\n] as const;\n\nconst dataChangeTagsSchema = v.literalUnion(...dataChangeTags);\n\nexport type DataChange = Satisfies<\n JSONObject, // guarantees serialization over IPC or network\n v.Infer<typeof dataChangeSchema>\n>;\n\nexport type DataChangeTag = v.Infer<typeof dataChangeTagsSchema>;\n\nconst schemaChanges = [\n createTableSchema,\n renameTableSchema,\n updateTableMetadataSchema,\n addColumnSchema,\n updateColumnSchema,\n dropColumnSchema,\n dropTableSchema,\n createIndexSchema,\n dropIndexSchema,\n backfillCompletedSchema,\n] as const;\n\nexport const schemaChangeSchema = v.union(...schemaChanges);\n\nconst schemaChangeTagsSchema = v.literalUnion(...schemaChangeTags);\n\nexport type SchemaChange = Satisfies<\n JSONObject,\n v.Infer<typeof schemaChangeSchema>\n>;\n\nexport type SchemaChangeTag = v.Infer<typeof schemaChangeTagsSchema>;\n\nexport type DataOrSchemaChange = DataChange | SchemaChange;\n\nexport type Change =\n | MessageBegin\n | DataOrSchemaChange\n | MessageCommit\n | MessageRollback;\n\nexport type ChangeTag = Change['tag'];\n\nconst schemaChangeTagSet = new Set<string>(schemaChangeTags);\n\nexport function isSchemaChange(change: Change): change is SchemaChange {\n return schemaChangeTagSet.has(change.tag);\n}\n\nconst dataChangeTagSet = new Set<string>(dataChangeTags);\n\nexport function isDataChange(change: Change): change is DataChange {\n return dataChangeTagSet.has(change.tag);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"data.js","names":["v","v.literalUnion"],"sources":["../../../../../../../../zero-cache/src/services/change-source/protocol/current/data.ts"],"sourcesContent":["/**\n * Data plane messages encapsulate changes that are sent by ChangeSources,\n * forwarded / fanned out to subscribers by the ChangeStreamerService, and\n * stored in the Change DB for catchup of old subscribers.\n */\n\nimport {\n jsonValueSchema,\n type JSONObject,\n} from '../../../../../../shared/src/bigint-json.ts';\nimport {must} from '../../../../../../shared/src/must.ts';\nimport * as v from '../../../../../../shared/src/valita.ts';\nimport {columnSpec, indexSpec, tableSpec} from '../../../../db/specs.ts';\nimport type {Satisfies} from '../../../../types/satisfies.ts';\nimport {jsonObjectSchema} from './json.ts';\nimport {schemaChangeTags} from './schema-change-tags.ts';\n\nexport const beginSchema = v.object({\n tag: v.literal('begin'),\n // The format of values of \"json\"-typed columns (e.g. \"JSON\" and \"JSONB\").\n // - 'p' is for parsed JSON, which may include JSON values or JSON objects.\n // These values are parsed and stringified at every process boundary\n // between the change-source and the replica.\n // - 's' is for stringified JSON. These values skip the parsing and\n // stringification, and are directly ferried to the replica as a JSON\n // string. For JSON values this improves performance by 20~25% in the\n // change-streamer and 25~30% in the replicator.\n //\n // If absent, the format is assumed to be 'p' (parsed JSON objects/values).\n json: v.literalUnion('p', 's').optional(),\n\n // Directs the change-streamer to skip the ACK for the corresponding commit.\n skipAck: v.boolean().optional(),\n});\n\nexport const commitSchema = v.object({\n tag: v.literal('commit'),\n\n // Millisecond epoch at which the transaction committed upstream, as reported\n // by the upstream database (e.g. the `commitTime` of the Postgres logical\n // replication Commit message).\n //\n // This is the origin timestamp of the end-to-end serving lag measurement:\n // it is carried through the replication stream to the ViewSyncer, which\n // records `now - commitTimeMs` once the change has been poked to clients.\n //\n // Optional because it is absent from changes written to the Change DB by\n // older versions, which are replayed verbatim during catchup, and from\n // ChangeSources that do not report a commit time.\n commitTimeMs: v.number().optional(),\n});\n\nexport const rollbackSchema = v.object({\n tag: v.literal('rollback'),\n});\n\nconst rowKeySchema = v.object({\n // The columns used to identify a row in insert, update, and delete changes.\n columns: v.array(v.string()),\n\n // An optional qualifier identifying how the key is chosen. Currently this\n // is postgres-specific, describing the REPLICA IDENTITY, for which replica\n // identity 'full' (FULL) is handled differently; the replicator handles\n // these tables by extracting a row key from the full row based on the\n // table's PRIMARY KEY or UNIQUE INDEX.\n type: v.literalUnion('default', 'nothing', 'full', 'index').optional(),\n});\n\nexport const relationSchema = v\n .object({\n schema: v.string(),\n name: v.string(),\n\n // This will become required.\n rowKey: rowKeySchema.optional(),\n\n /** Deprecated: set the rowKey.columns instead. */\n keyColumns: v.array(v.string()).optional(),\n /** Deprecated: set the rowKey.columns instead. */\n replicaIdentity: v\n .literalUnion('default', 'nothing', 'full', 'index')\n .optional(),\n })\n .map(rel => {\n const {rowKey, ...rest} = rel;\n if (rowKey) {\n return {...rest, rowKey};\n }\n return {\n ...rest,\n rowKey: {\n columns: must(rel.keyColumns),\n type: rel.replicaIdentity,\n },\n };\n });\n\n// The eventual fate of relationSchema\nexport const newRelationSchema = v.object({\n schema: v.string(),\n name: v.string(),\n\n rowKey: rowKeySchema,\n});\n\n// TableMetadata contains table-related configuration that does not affect the\n// actual data in the table, but rather how the table's change messages are\n// handled. The is an opaque object that clients must track (and update) based\n// on `create-table`, `add-column`, and `table-update-metadata` messages, and\n// pass in BackfillRequests when there are columns to be backfilled.\n//\n// Note that the backfill-related change-source implementation does, however,\n// rely on the rowKey (columns) being specified in the message.\nexport const tableMetadataSchema = v\n .object({rowKey: v.record(jsonValueSchema)})\n .rest(jsonValueSchema);\n\nexport type TableMetadata = v.Infer<typeof tableMetadataSchema>;\n\nexport const rowSchema = v.record(jsonValueSchema);\n\nexport const insertSchema = v.object({\n tag: v.literal('insert'),\n relation: relationSchema,\n new: rowSchema,\n});\n\nexport const updateSchema = v.object({\n tag: v.literal('update'),\n relation: relationSchema,\n // `key` is present if the update changed the key of the row, or if the\n // table's replicaIdentity === 'full'\n key: rowSchema.nullable(),\n // `new` is the full row (and not just the updated columns). This is\n // necessary for \"catchup\" replication scenarios such as adding tables\n // to a publication, or resharding.\n new: rowSchema,\n});\n\nexport const deleteSchema = v.object({\n tag: v.literal('delete'),\n relation: relationSchema,\n // key is the full row if replicaIdentity === 'full'\n key: rowSchema,\n});\n\nexport const truncateSchema = v.object({\n tag: v.literal('truncate'),\n relations: v.array(relationSchema),\n});\n\nexport const identifierSchema = v.object({\n schema: v.string(),\n name: v.string(),\n});\n\nexport type Identifier = v.Infer<typeof identifierSchema>;\n\n// A BackfillID is an upstream specific stable identifier for a column\n// that needs backfilling. This id is used to ensure that the schema, table,\n// and column names of a requested backfill still match the original\n// underlying upstream ID.\n//\n// The change-streamer stores these IDs as opaque values while a column is\n// being backfilled, and initiates new change-source streams with the IDs\n// in order to restart backfills that did not complete in previous sessions.\nexport const backfillIDSchema = jsonObjectSchema;\n\nexport type BackfillID = v.Infer<typeof backfillIDSchema>;\n\nexport const backfillProgressMarkSchema = v\n .object({\n // A lexicographically sortable string delineating the progress of a\n // backfill. This is used to resume a backfill that did not complete.\n progressMark: v.string(),\n\n // Optionally, a timeline with which the progressMark is associated.\n // A timeline is an opaque string that determines if backfill streams\n // are \"compatible\" with each other, i.e. can be merged in a way that\n // avoids gaps. progressMarks from different timelines are not\n // compatible. If two timelines differ, a new backfill is started\n // from scratch in order to get all subscribers on the same timeline.\n //\n // Timeline changes should be rare events (e.g. Postgres VACUUM FULL).\n timeline: v.string().optional(),\n })\n // All other fields should be preserved and returned in BackfillRequests.\n .rest(v.union(v.number(), v.string()));\n\nexport type BackfillProgressMark = v.Infer<typeof backfillProgressMarkSchema>;\n\nexport const createTableSchema = v.object({\n tag: v.literal('create-table'),\n spec: tableSpec,\n\n // This must be set by change source implementations that support\n // table/column backfill.\n //\n // TODO: to simplify the protocol, see if we can make this required\n metadata: tableMetadataSchema.optional(),\n\n // Indicate that columns of the table require backfilling. These columns\n // should be created on the replica but not yet synced the clients.\n //\n // ## State Persistence\n //\n // To obviate the need for change-source implementations to persist state\n // related to backfill progress, the change-source only tracks backfills\n // **for the current session**. In the event that the session is interrupted\n // before columns have been fully backfilled, it is the responsibility of the\n // change-streamer to send {@link BackfillRequest}s when it reconnects.\n //\n // This means that the change-streamer must track and persist:\n // * the backfill IDs of the columns requiring backfilling\n // * the most current table metadata of the associated table(s)\n //\n // The change-streamer then uses this information to send backfill requests\n // when it reconnects.\n backfill: v.record(backfillIDSchema).optional(),\n});\n\nexport const renameTableSchema = v.object({\n tag: v.literal('rename-table'),\n old: identifierSchema,\n new: identifierSchema,\n});\n\nexport const updateTableMetadataSchema = v.object({\n tag: v.literal('update-table-metadata'),\n table: identifierSchema,\n old: tableMetadataSchema,\n new: tableMetadataSchema,\n});\n\nconst columnSchema = v.object({\n name: v.string(),\n spec: columnSpec,\n});\n\nexport const addColumnSchema = v.object({\n tag: v.literal('add-column'),\n table: identifierSchema,\n column: columnSchema,\n\n // This must be set by change source implementations that support\n // table/column backfill.\n //\n // TODO: to simplify the protocol, see if we can make this required\n tableMetadata: tableMetadataSchema.optional(),\n\n // See documentation for the `backfill` field of the `create-table` change.\n backfill: backfillIDSchema.optional(),\n});\n\nexport const updateColumnSchema = v.object({\n tag: v.literal('update-column'),\n table: identifierSchema,\n old: columnSchema,\n new: columnSchema,\n});\n\nexport const dropColumnSchema = v.object({\n tag: v.literal('drop-column'),\n table: identifierSchema,\n column: v.string(),\n});\n\nexport const dropTableSchema = v.object({\n tag: v.literal('drop-table'),\n id: identifierSchema,\n});\n\nexport const createIndexSchema = v.object({\n tag: v.literal('create-index'),\n spec: indexSpec,\n});\n\nexport const dropIndexSchema = v.object({\n tag: v.literal('drop-index'),\n id: identifierSchema,\n});\n\nexport const downloadStatusSchema = v.object({\n rows: v.number(),\n totalRows: v.number(),\n totalBytes: v.number().optional(),\n});\n\nexport type DownloadStatus = v.Infer<typeof downloadStatusSchema>;\n\n// A batch of rows from a single table containing column values\n// to be backfilled.\nexport const backfillSchema = v.object({\n tag: v.literal('backfill'),\n\n relation: newRelationSchema,\n\n // The columns to be backfilled. `rowKey` columns are automatically excluded,\n // which means that this field may be empty.\n columns: v.array(v.string()),\n\n // The watermark at which the backfill data was queried. Note that this\n // generally will be different from the commit watermarks of the main change\n // stream, and in particular, the commit watermark of the backfill change's\n // enclosing transaction.\n watermark: v.string(),\n\n // A batch of row values, each row consisting of the `rowKey`\n // values, followed by the `column` values, in the same order in which\n // the column names appear in their respective fields, e.g.\n //\n // ```\n // [\n // [...rowKeyValues, ...columnValues], // row 1\n // [...rowKeyValues, ...columnValues], // row 2\n // ]\n // ```\n rowValues: v.array(v.array(jsonValueSchema)),\n\n // Progress marks indicating the position of this backfill message\n // within the stream, for resumption / continuity enforcement.\n //\n // This should be considered non-optional as of protocol v8. It is only\n // absent in messages from pre-v8 replication-managers (including messages\n // persisted in a change-log by one), in which case subscribers accept the\n // message unconditionally (i.e. the legacy behavior).\n progressMarks: v\n .object({\n // The progress mark of the preceding backfill message, from which\n // the current backfill message is a continuation. (This may be a\n // \"logical\" continuation at which a new backfill stream is started when\n // resuming from a previous stream.)\n //\n // For the first backfill message of a stream starting from scratch,\n // this field is unset. When the field is unset, subscribers should\n // accept the backfill message unconditionally (i.e. starting a\n // backfill from scratch is always safe).\n //\n // If the field is set, subscribers should only accept the message if\n // it is of the same timeline as that of its own tracked progressMark,\n // and is contiguous with or earlier than its own progressMark.\n //\n // In other words, it should _ignore_ backfill messages from other\n // timelines, or messages that create a gap; this can happen when\n // receiving messages from before this subscriber's backfill requests\n // are taken into account.\n //\n // Implementation note: The change-streamer applies this same policy\n // (see `acceptBackfill()` in `protocol/backfill-progress.ts`) to track\n // the backfill state of each subscriber, which it uses to determine the\n // BackfillRequests with which to (re)start change streams.\n previous: backfillProgressMarkSchema.optional(),\n\n // The progressMark delineating the position of the last row in this\n // message. In the steady state, this will be the `previous`\n // progressMark of the next backfill message, unless a rewind is\n // requested, or new timeline encountered.\n current: backfillProgressMarkSchema,\n })\n .optional(),\n\n // Optionally includes the progress of the backfill operation,\n // for display purposes.\n status: downloadStatusSchema.optional(),\n});\n\n// Indicates that the backfill for the specified columns have\n// been successfully backfilled and can be published to clients.\nexport const backfillCompletedSchema = v.object({\n tag: v.literal('backfill-completed'),\n\n relation: newRelationSchema,\n\n // The columns to be backfilled. `rowKey` columns are automatically excluded,\n // which means that this field may be empty.\n columns: v.array(v.string()),\n\n // The watermark at which the backfill data was queried. Note that this\n // generally will be different from the commit watermarks of the main change\n // stream, and in particular, the commit watermark of the backfill change's\n // enclosing transaction.\n watermark: v.string(),\n\n // The progress mark of the last backfill message of the run, i.e. the\n // `current` progressMark of the last `backfill` message, or the progressMark\n // from which the run was resumed if it produced no `backfill` messages.\n // Subscribers apply the same continuity policy as for `backfill` messages,\n // and only consider the columns backfilled if the run is contiguous with\n // their own progress.\n //\n // `previous` is only unset for a run that started from scratch and\n // produced no rows (e.g. an empty table), which is always safe to accept.\n //\n // This should be considered non-optional as of protocol v8. It is only\n // absent in messages from pre-v8 replication-managers, in which case\n // subscribers accept the message unconditionally (i.e. legacy behavior).\n progressMarks: v\n .object({previous: backfillProgressMarkSchema.optional()})\n .optional(),\n\n // Optionally includes the final status of the backfill operation,\n // for display purposes.\n status: downloadStatusSchema.optional(),\n});\n\nexport type MessageBegin = v.Infer<typeof beginSchema>;\nexport type MessageCommit = v.Infer<typeof commitSchema>;\nexport type MessageRollback = v.Infer<typeof rollbackSchema>;\n\nexport type MessageRelation = v.Infer<typeof relationSchema>;\nexport type MessageInsert = v.Infer<typeof insertSchema>;\nexport type MessageUpdate = v.Infer<typeof updateSchema>;\nexport type MessageDelete = v.Infer<typeof deleteSchema>;\nexport type MessageTruncate = v.Infer<typeof truncateSchema>;\n\nexport type MessageBackfill = v.Infer<typeof backfillSchema>;\n\nexport type TableCreate = v.Infer<typeof createTableSchema>;\nexport type TableRename = v.Infer<typeof renameTableSchema>;\nexport type TableUpdateMetadata = v.Infer<typeof updateTableMetadataSchema>;\nexport type ColumnAdd = v.Infer<typeof addColumnSchema>;\nexport type ColumnUpdate = v.Infer<typeof updateColumnSchema>;\nexport type ColumnDrop = v.Infer<typeof dropColumnSchema>;\nexport type TableDrop = v.Infer<typeof dropTableSchema>;\nexport type IndexCreate = v.Infer<typeof createIndexSchema>;\nexport type IndexDrop = v.Infer<typeof dropIndexSchema>;\nexport type BackfillCompleted = v.Infer<typeof backfillCompletedSchema>;\n\nexport const dataChangeSchema = v.union(\n insertSchema,\n updateSchema,\n deleteSchema,\n truncateSchema,\n backfillSchema,\n);\n\n// Note: keep in sync or the tag tests will fail\nconst dataChangeTags = [\n 'insert',\n 'update',\n 'delete',\n 'truncate',\n 'backfill',\n] as const;\n\nconst dataChangeTagsSchema = v.literalUnion(...dataChangeTags);\n\nexport type DataChange = Satisfies<\n JSONObject, // guarantees serialization over IPC or network\n v.Infer<typeof dataChangeSchema>\n>;\n\nexport type DataChangeTag = v.Infer<typeof dataChangeTagsSchema>;\n\nconst schemaChanges = [\n createTableSchema,\n renameTableSchema,\n updateTableMetadataSchema,\n addColumnSchema,\n updateColumnSchema,\n dropColumnSchema,\n dropTableSchema,\n createIndexSchema,\n dropIndexSchema,\n backfillCompletedSchema,\n] as const;\n\nexport const schemaChangeSchema = v.union(...schemaChanges);\n\nconst schemaChangeTagsSchema = v.literalUnion(...schemaChangeTags);\n\nexport type SchemaChange = Satisfies<\n JSONObject,\n v.Infer<typeof schemaChangeSchema>\n>;\n\nexport type SchemaChangeTag = v.Infer<typeof schemaChangeTagsSchema>;\n\nexport type DataOrSchemaChange = DataChange | SchemaChange;\n\nexport type Change =\n | MessageBegin\n | DataOrSchemaChange\n | MessageCommit\n | MessageRollback;\n\nexport type ChangeTag = Change['tag'];\n\nconst schemaChangeTagSet = new Set<string>(schemaChangeTags);\n\nexport function isSchemaChange(change: Change): change is SchemaChange {\n return schemaChangeTagSet.has(change.tag);\n}\n\nconst dataChangeTagSet = new Set<string>(dataChangeTags);\n\nexport function isDataChange(change: Change): change is DataChange {\n return dataChangeTagSet.has(change.tag);\n}\n"],"mappings":"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"}
@@ -768,6 +768,7 @@ export declare const changeStreamMessageSchema: v.UnionType<[v.UnionType<[v.Tupl
768
768
  };
769
769
  nextSendTimeMs: number;
770
770
  }>;
771
+ syncBackupThrough: v.Optional<string>;
771
772
  }, undefined>, v.ObjectType<{
772
773
  watermark: v.Type<string>;
773
774
  }, undefined>]>]>;
@@ -1 +1 @@
1
- {"version":3,"file":"downstream.d.ts","sourceRoot":"","sources":["../../../../../../../../zero-cache/src/services/change-source/protocol/current/downstream.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,wCAAwC,CAAC;AAW5D,QAAA,MAAM,KAAK;;;;;;eAIT,CAAC;AACH,QAAA,MAAM,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mBAGR,CAAC;AACH,QAAA,MAAM,MAAM;;;;;eAIV,CAAC;AACH,QAAA,MAAM,QAAQ;;eAAmD,CAAC;AAElE,MAAM,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,KAAK,CAAC,CAAC;AAC1C,MAAM,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC;AACxC,MAAM,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,MAAM,CAAC,CAAC;AAC5C,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,QAAQ,CAAC,CAAC;AAEhD,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAAyC,CAAC;AAC7E,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAEtE,eAAO,MAAM,yBAAyB;;;;eAGpC,CAAC;AACH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAE5E,4EAA4E;AAC5E,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAIrC,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC"}
1
+ {"version":3,"file":"downstream.d.ts","sourceRoot":"","sources":["../../../../../../../../zero-cache/src/services/change-source/protocol/current/downstream.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,wCAAwC,CAAC;AAW5D,QAAA,MAAM,KAAK;;;;;;eAIT,CAAC;AACH,QAAA,MAAM,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mBAGR,CAAC;AACH,QAAA,MAAM,MAAM;;;;;eAIV,CAAC;AACH,QAAA,MAAM,QAAQ;;eAAmD,CAAC;AAElE,MAAM,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,KAAK,CAAC,CAAC;AAC1C,MAAM,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC;AACxC,MAAM,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,MAAM,CAAC,CAAC;AAC5C,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,QAAQ,CAAC,CAAC;AAEhD,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAAyC,CAAC;AAC7E,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAEtE,eAAO,MAAM,yBAAyB;;;;eAGpC,CAAC;AACH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAE5E,4EAA4E;AAC5E,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAIrC,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC"}