@rocicorp/zero 1.12.0-canary.1 → 1.12.0-canary.11
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.
- package/out/_virtual/{_@oxc-project_runtime@0.130.0/helpers → _@oxc-project_runtime@0.154.0/helpers/esm}/usingCtx.js +2 -2
- package/out/analyze-query/src/analyze-cli.d.ts.map +1 -1
- package/out/analyze-query/src/analyze-cli.js +6 -4
- package/out/analyze-query/src/analyze-cli.js.map +1 -1
- package/out/analyze-query/src/bin-transform.js +4 -3
- package/out/analyze-query/src/bin-transform.js.map +1 -1
- package/out/analyze-query/src/zql-chain.d.ts +23 -0
- package/out/analyze-query/src/zql-chain.d.ts.map +1 -0
- package/out/analyze-query/src/zql-chain.js +170 -0
- package/out/analyze-query/src/zql-chain.js.map +1 -0
- package/out/ast-to-zql/src/ast-to-zql.d.ts.map +1 -1
- package/out/ast-to-zql/src/ast-to-zql.js +61 -20
- package/out/ast-to-zql/src/ast-to-zql.js.map +1 -1
- package/out/ast-to-zql/src/bin.js +4 -3
- package/out/ast-to-zql/src/bin.js.map +1 -1
- package/out/ast-to-zql/src/format.js.map +1 -1
- package/out/datadog/src/datadog-log-sink.js +5 -4
- package/out/datadog/src/datadog-log-sink.js.map +1 -1
- package/out/otel/src/log-options.js.map +1 -1
- package/out/replicache/src/btree/node.d.ts +0 -2
- package/out/replicache/src/btree/node.d.ts.map +1 -1
- package/out/replicache/src/btree/node.js +14 -12
- package/out/replicache/src/btree/node.js.map +1 -1
- package/out/replicache/src/btree/read.js +4 -2
- package/out/replicache/src/btree/read.js.map +1 -1
- package/out/replicache/src/btree/splice.js.map +1 -1
- package/out/replicache/src/btree/write.js +9 -5
- package/out/replicache/src/btree/write.js.map +1 -1
- package/out/replicache/src/config.js +1 -2
- package/out/replicache/src/connection-loop.d.ts.map +1 -1
- package/out/replicache/src/connection-loop.js +1 -1
- package/out/replicache/src/connection-loop.js.map +1 -1
- package/out/replicache/src/dag/chunk.js +1 -1
- package/out/replicache/src/dag/gc.js.map +1 -1
- package/out/replicache/src/dag/lazy-store.js +8 -7
- package/out/replicache/src/dag/lazy-store.js.map +1 -1
- package/out/replicache/src/dag/store-impl.js +1 -1
- package/out/replicache/src/dag/store-impl.js.map +1 -1
- package/out/replicache/src/dag/visitor.js.map +1 -1
- package/out/replicache/src/db/commit.d.ts +0 -1
- package/out/replicache/src/db/commit.d.ts.map +1 -1
- package/out/replicache/src/db/commit.js +5 -3
- package/out/replicache/src/db/commit.js.map +1 -1
- package/out/replicache/src/db/read.js +1 -1
- package/out/replicache/src/db/read.js.map +1 -1
- package/out/replicache/src/db/rebase.js.map +1 -1
- package/out/replicache/src/db/write.d.ts +0 -2
- package/out/replicache/src/db/write.d.ts.map +1 -1
- package/out/replicache/src/db/write.js +5 -2
- package/out/replicache/src/db/write.js.map +1 -1
- package/out/replicache/src/deleted-clients.d.ts +0 -2
- package/out/replicache/src/deleted-clients.d.ts.map +1 -1
- package/out/replicache/src/deleted-clients.js +5 -3
- package/out/replicache/src/deleted-clients.js.map +1 -1
- package/out/replicache/src/expo-sqlite.js +1 -2
- package/out/replicache/src/frozen-json.d.ts +0 -1
- package/out/replicache/src/frozen-json.d.ts.map +1 -1
- package/out/replicache/src/frozen-json.js +1 -1
- package/out/replicache/src/frozen-json.js.map +1 -1
- package/out/replicache/src/get-default-puller.js +1 -1
- package/out/replicache/src/hash.js +1 -1
- package/out/replicache/src/hash.js.map +1 -1
- package/out/replicache/src/impl.js +1 -2
- package/out/replicache/src/index-defs.d.ts +0 -2
- package/out/replicache/src/index-defs.d.ts.map +1 -1
- package/out/replicache/src/index-defs.js +5 -3
- package/out/replicache/src/index-defs.js.map +1 -1
- package/out/replicache/src/kv/expo-sqlite/store.d.ts +0 -1
- package/out/replicache/src/kv/expo-sqlite/store.d.ts.map +1 -1
- package/out/replicache/src/kv/expo-sqlite/store.js.map +1 -1
- package/out/replicache/src/kv/idb-store.js +2 -2
- package/out/replicache/src/kv/idb-store.js.map +1 -1
- package/out/replicache/src/kv/mem-fallback-store.js +1 -1
- package/out/replicache/src/kv/mem-fallback-store.js.map +1 -1
- package/out/replicache/src/kv/mem-store.js.map +1 -1
- package/out/replicache/src/kv/op-sqlite/store.js.map +1 -1
- package/out/replicache/src/kv/op-sqlite/types.js.map +1 -1
- package/out/replicache/src/kv/read-impl.js.map +1 -1
- package/out/replicache/src/kv/sqlite-store.d.ts.map +1 -1
- package/out/replicache/src/kv/sqlite-store.js +8 -4
- package/out/replicache/src/kv/sqlite-store.js.map +1 -1
- package/out/replicache/src/kv/throw-if-closed.d.ts +0 -3
- package/out/replicache/src/kv/throw-if-closed.d.ts.map +1 -1
- package/out/replicache/src/kv/throw-if-closed.js.map +1 -1
- package/out/replicache/src/kv/write-impl-base.js +4 -1
- package/out/replicache/src/kv/write-impl-base.js.map +1 -1
- package/out/replicache/src/kv/write-impl.js.map +1 -1
- package/out/replicache/src/log-options.js +2 -1
- package/out/replicache/src/log-options.js.map +1 -1
- package/out/replicache/src/make-idb-name.js +1 -1
- package/out/replicache/src/new-client-channel.js +9 -7
- package/out/replicache/src/new-client-channel.js.map +1 -1
- package/out/replicache/src/on-persist-channel.js +1 -1
- package/out/replicache/src/on-persist-channel.js.map +1 -1
- package/out/replicache/src/op-sqlite.js +1 -2
- package/out/replicache/src/pending-mutations.js +2 -1
- package/out/replicache/src/pending-mutations.js.map +1 -1
- package/out/replicache/src/persist/client-gc.js +2 -2
- package/out/replicache/src/persist/client-gc.js.map +1 -1
- package/out/replicache/src/persist/client-group-gc.d.ts +0 -7
- package/out/replicache/src/persist/client-group-gc.d.ts.map +1 -1
- package/out/replicache/src/persist/client-group-gc.js +1 -1
- package/out/replicache/src/persist/client-group-gc.js.map +1 -1
- package/out/replicache/src/persist/client-groups.js +1 -1
- package/out/replicache/src/persist/client-groups.js.map +1 -1
- package/out/replicache/src/persist/clients.js +1 -1
- package/out/replicache/src/persist/clients.js.map +1 -1
- package/out/replicache/src/persist/collect-idb-databases.js +5 -4
- package/out/replicache/src/persist/collect-idb-databases.js.map +1 -1
- package/out/replicache/src/persist/gather-mem-only-visitor.js.map +1 -1
- package/out/replicache/src/persist/gather-not-cached-visitor.js.map +1 -1
- package/out/replicache/src/persist/heartbeat.js +2 -2
- package/out/replicache/src/persist/heartbeat.js.map +1 -1
- package/out/replicache/src/persist/idb-databases-store.js +1 -1
- package/out/replicache/src/persist/idb-databases-store.js.map +1 -1
- package/out/replicache/src/persist/make-client-id.js +1 -1
- package/out/replicache/src/persist/make-client-id.js.map +1 -1
- package/out/replicache/src/persist/persist.js +3 -2
- package/out/replicache/src/persist/persist.js.map +1 -1
- package/out/replicache/src/persist/refresh.js +8 -5
- package/out/replicache/src/persist/refresh.js.map +1 -1
- package/out/replicache/src/process-scheduler.js +1 -1
- package/out/replicache/src/process-scheduler.js.map +1 -1
- package/out/replicache/src/replicache-impl.d.ts +2 -7
- package/out/replicache/src/replicache-impl.d.ts.map +1 -1
- package/out/replicache/src/replicache-impl.js +21 -18
- package/out/replicache/src/replicache-impl.js.map +1 -1
- package/out/replicache/src/scan-iterator.js.map +1 -1
- package/out/replicache/src/scan-options.js +7 -6
- package/out/replicache/src/scan-options.js.map +1 -1
- package/out/replicache/src/sqlite.js +1 -2
- package/out/replicache/src/subscriptions.js +1 -1
- package/out/replicache/src/subscriptions.js.map +1 -1
- package/out/replicache/src/sync/diff.js +3 -1
- package/out/replicache/src/sync/diff.js.map +1 -1
- package/out/replicache/src/sync/ids.js.map +1 -1
- package/out/replicache/src/sync/patch.d.ts +0 -5
- package/out/replicache/src/sync/patch.d.ts.map +1 -1
- package/out/replicache/src/sync/patch.js +2 -4
- package/out/replicache/src/sync/patch.js.map +1 -1
- package/out/replicache/src/sync/pull.d.ts +0 -1
- package/out/replicache/src/sync/pull.d.ts.map +1 -1
- package/out/replicache/src/sync/pull.js +3 -1
- package/out/replicache/src/sync/pull.js.map +1 -1
- package/out/replicache/src/sync/push.d.ts +2 -1
- package/out/replicache/src/sync/push.d.ts.map +1 -1
- package/out/replicache/src/sync/push.js.map +1 -1
- package/out/replicache/src/sync/request-id.js +1 -1
- package/out/replicache/src/sync/request-id.js.map +1 -1
- package/out/replicache/src/transactions.js +1 -1
- package/out/replicache/src/transactions.js.map +1 -1
- package/out/replicache/src/types.d.ts +2 -1
- package/out/replicache/src/types.d.ts.map +1 -1
- package/out/shared/src/arrays.js +4 -1
- package/out/shared/src/arrays.js.map +1 -1
- package/out/shared/src/asserts.d.ts +0 -5
- package/out/shared/src/asserts.d.ts.map +1 -1
- package/out/shared/src/asserts.js.map +1 -1
- package/out/shared/src/bigint-json.d.ts +9 -0
- package/out/shared/src/bigint-json.d.ts.map +1 -1
- package/out/shared/src/bigint-json.js +27 -2
- package/out/shared/src/bigint-json.js.map +1 -1
- package/out/shared/src/broadcast-channel.js +1 -1
- package/out/shared/src/browser-env.d.ts +0 -17
- package/out/shared/src/browser-env.d.ts.map +1 -1
- package/out/shared/src/browser-env.js.map +1 -1
- package/out/shared/src/btree-set.js +11 -8
- package/out/shared/src/btree-set.js.map +1 -1
- package/out/shared/src/cache.js.map +1 -1
- package/out/shared/src/config.js +1 -1
- package/out/shared/src/custom-key-map.js.map +1 -1
- package/out/shared/src/custom-key-set.js.map +1 -1
- package/out/shared/src/deep-clone.d.ts +0 -1
- package/out/shared/src/deep-clone.d.ts.map +1 -1
- package/out/shared/src/deep-clone.js.map +1 -1
- package/out/shared/src/document-visible.js +1 -1
- package/out/shared/src/document-visible.js.map +1 -1
- package/out/shared/src/dotenv.js.map +1 -1
- package/out/shared/src/error.js +1 -1
- package/out/shared/src/error.js.map +1 -1
- package/out/shared/src/expand.d.ts +0 -3
- package/out/shared/src/expand.d.ts.map +1 -1
- package/out/shared/src/hash.js +2 -2
- package/out/shared/src/hash.js.map +1 -1
- package/out/shared/src/immutable.d.ts +1 -1
- package/out/shared/src/immutable.d.ts.map +1 -1
- package/out/shared/src/iterables.d.ts +0 -1
- package/out/shared/src/iterables.d.ts.map +1 -1
- package/out/shared/src/iterables.js.map +1 -1
- package/out/shared/src/json-schema.js.map +1 -1
- package/out/shared/src/json.js.map +1 -1
- package/out/shared/src/logging-test-utils.js.map +1 -1
- package/out/shared/src/logging.js +1 -1
- package/out/shared/src/logging.js.map +1 -1
- package/out/shared/src/navigator.js +1 -1
- package/out/shared/src/options-types.d.ts +1 -1
- package/out/shared/src/options-types.d.ts.map +1 -1
- package/out/shared/src/options.d.ts +2 -3
- package/out/shared/src/options.d.ts.map +1 -1
- package/out/shared/src/options.js +8 -11
- package/out/shared/src/options.js.map +1 -1
- package/out/shared/src/promise-race.js +1 -1
- package/out/shared/src/promise-race.js.map +1 -1
- package/out/shared/src/queue.js +1 -1
- package/out/shared/src/queue.js.map +1 -1
- package/out/shared/src/record-proxy.js.map +1 -1
- package/out/shared/src/resolved-promises.d.ts +0 -4
- package/out/shared/src/resolved-promises.d.ts.map +1 -1
- package/out/shared/src/resolved-promises.js +0 -1
- package/out/shared/src/resolved-promises.js.map +1 -1
- package/out/shared/src/resolver.d.ts +9 -0
- package/out/shared/src/resolver.d.ts.map +1 -0
- package/out/shared/src/resolver.js +6 -0
- package/out/shared/src/resolver.js.map +1 -0
- package/out/shared/src/ring-buffer.js.map +1 -1
- package/out/shared/src/size-of-value.js +7 -10
- package/out/shared/src/size-of-value.js.map +1 -1
- package/out/shared/src/sleep.js +1 -1
- package/out/shared/src/sleep.js.map +1 -1
- package/out/shared/src/sorted-entries.js.map +1 -1
- package/out/shared/src/tdigest-schema.js.map +1 -1
- package/out/shared/src/tdigest.d.ts +0 -1
- package/out/shared/src/tdigest.d.ts.map +1 -1
- package/out/shared/src/tdigest.js.map +1 -1
- package/out/shared/src/valita.js +1 -1
- package/out/shared/src/valita.js.map +1 -1
- package/out/z2s/src/compiler.d.ts +1 -1
- package/out/z2s/src/compiler.d.ts.map +1 -1
- package/out/z2s/src/compiler.js +344 -9
- package/out/z2s/src/compiler.js.map +1 -1
- package/out/z2s/src/sql.d.ts +9 -5
- package/out/z2s/src/sql.d.ts.map +1 -1
- package/out/z2s/src/sql.js +58 -11
- package/out/z2s/src/sql.js.map +1 -1
- package/out/zero/package.js +210 -189
- package/out/zero/package.js.map +1 -1
- package/out/zero/src/adapters/drizzle.js +1 -2
- package/out/zero/src/adapters/kysely.js +1 -2
- package/out/zero/src/adapters/pg.js +1 -2
- package/out/zero/src/adapters/postgresjs.js +1 -2
- package/out/zero/src/adapters/prisma.js +1 -2
- package/out/zero/src/analyze.js +1 -2
- package/out/zero/src/bindings.js +4 -4
- package/out/zero/src/change-protocol/v0.js +1 -2
- package/out/zero/src/expo-sqlite.js +1 -2
- package/out/zero/src/op-sqlite.js +1 -2
- package/out/zero/src/react-native.js.map +1 -1
- package/out/zero/src/sqlite.js +1 -2
- package/out/zero/src/zero-cache-dev.js +11 -10
- package/out/zero/src/zero-cache-dev.js.map +1 -1
- package/out/zero/src/zero-out.js +2 -1
- package/out/zero/src/zero-out.js.map +1 -1
- package/out/zero-cache/src/auth/auth.js +1 -1
- package/out/zero-cache/src/auth/auth.js.map +1 -1
- package/out/zero-cache/src/auth/jwt.js +4 -1
- package/out/zero-cache/src/auth/jwt.js.map +1 -1
- package/out/zero-cache/src/auth/load-permissions.js +1 -1
- package/out/zero-cache/src/auth/load-permissions.js.map +1 -1
- package/out/zero-cache/src/auth/read-authorizer.js +3 -2
- package/out/zero-cache/src/auth/read-authorizer.js.map +1 -1
- package/out/zero-cache/src/auth/write-authorizer.js +16 -20
- package/out/zero-cache/src/auth/write-authorizer.js.map +1 -1
- package/out/zero-cache/src/config/network.js +1 -1
- package/out/zero-cache/src/config/network.js.map +1 -1
- package/out/zero-cache/src/config/server-context.js.map +1 -1
- package/out/zero-cache/src/config/zero-config.d.ts +23 -11
- package/out/zero-cache/src/config/zero-config.d.ts.map +1 -1
- package/out/zero-cache/src/config/zero-config.js +51 -4
- package/out/zero-cache/src/config/zero-config.js.map +1 -1
- package/out/zero-cache/src/custom/fetch.js +1 -1
- package/out/zero-cache/src/custom/fetch.js.map +1 -1
- package/out/zero-cache/src/custom-queries/transform-query.js.map +1 -1
- package/out/zero-cache/src/db/create.js +1 -1
- package/out/zero-cache/src/db/create.js.map +1 -1
- package/out/zero-cache/src/db/index-predicate.js.map +1 -1
- package/out/zero-cache/src/db/lite-tables.d.ts +2 -2
- package/out/zero-cache/src/db/lite-tables.d.ts.map +1 -1
- package/out/zero-cache/src/db/lite-tables.js.map +1 -1
- package/out/zero-cache/src/db/migration-lite.js +1 -1
- package/out/zero-cache/src/db/migration-lite.js.map +1 -1
- package/out/zero-cache/src/db/migration.js +5 -3
- package/out/zero-cache/src/db/migration.js.map +1 -1
- package/out/zero-cache/src/db/pg-copy-binary.js +4 -3
- package/out/zero-cache/src/db/pg-copy-binary.js.map +1 -1
- package/out/zero-cache/src/db/pg-copy.js +0 -1
- package/out/zero-cache/src/db/pg-copy.js.map +1 -1
- package/out/zero-cache/src/db/pg-to-lite.js +1 -1
- package/out/zero-cache/src/db/pg-to-lite.js.map +1 -1
- package/out/zero-cache/src/db/pg-type-parser.js.map +1 -1
- package/out/zero-cache/src/db/run-transaction.js.map +1 -1
- package/out/zero-cache/src/db/specs.d.ts +3 -4
- package/out/zero-cache/src/db/specs.d.ts.map +1 -1
- package/out/zero-cache/src/db/specs.js +1 -1
- package/out/zero-cache/src/db/specs.js.map +1 -1
- package/out/zero-cache/src/db/sqlite-corruption.js.map +1 -1
- package/out/zero-cache/src/db/statements.d.ts.map +1 -1
- package/out/zero-cache/src/db/statements.js +9 -2
- package/out/zero-cache/src/db/statements.js.map +1 -1
- package/out/zero-cache/src/db/transaction-pool.js +6 -4
- package/out/zero-cache/src/db/transaction-pool.js.map +1 -1
- package/out/zero-cache/src/db/warmup.js.map +1 -1
- package/out/zero-cache/src/observability/events.js +1 -1
- package/out/zero-cache/src/observability/events.js.map +1 -1
- package/out/zero-cache/src/observability/log-throttle.js.map +1 -1
- package/out/zero-cache/src/observability/metrics.js.map +1 -1
- package/out/zero-cache/src/scripts/deploy-permissions.js +5 -3
- package/out/zero-cache/src/scripts/deploy-permissions.js.map +1 -1
- package/out/zero-cache/src/scripts/permissions.js.map +1 -1
- package/out/zero-cache/src/server/anonymous-otel-start.js +2 -1
- package/out/zero-cache/src/server/anonymous-otel-start.js.map +1 -1
- package/out/zero-cache/src/server/change-streamer.js +35 -11
- package/out/zero-cache/src/server/change-streamer.js.map +1 -1
- package/out/zero-cache/src/server/inspector-delegate.js.map +1 -1
- package/out/zero-cache/src/server/logging.js +1 -1
- package/out/zero-cache/src/server/logging.js.map +1 -1
- package/out/zero-cache/src/server/main.js +2 -2
- package/out/zero-cache/src/server/main.js.map +1 -1
- package/out/zero-cache/src/server/otel-log-sink.js.map +1 -1
- package/out/zero-cache/src/server/otel-start.js.map +1 -1
- package/out/zero-cache/src/server/reaper.js +2 -2
- package/out/zero-cache/src/server/reaper.js.map +1 -1
- package/out/zero-cache/src/server/replicator.js +1 -1
- package/out/zero-cache/src/server/replicator.js.map +1 -1
- package/out/zero-cache/src/server/runner/run-worker.d.ts.map +1 -1
- package/out/zero-cache/src/server/runner/run-worker.js +12 -8
- package/out/zero-cache/src/server/runner/run-worker.js.map +1 -1
- package/out/zero-cache/src/server/runner/runtime.js +2 -1
- package/out/zero-cache/src/server/runner/runtime.js.map +1 -1
- package/out/zero-cache/src/server/runner/zero-dispatcher.d.ts +9 -1
- package/out/zero-cache/src/server/runner/zero-dispatcher.d.ts.map +1 -1
- package/out/zero-cache/src/server/runner/zero-dispatcher.js +29 -2
- package/out/zero-cache/src/server/runner/zero-dispatcher.js.map +1 -1
- package/out/zero-cache/src/server/shadow-syncer.js +1 -1
- package/out/zero-cache/src/server/shadow-syncer.js.map +1 -1
- package/out/zero-cache/src/server/slot-keeper.js.map +1 -1
- package/out/zero-cache/src/server/syncer-assigner.js.map +1 -1
- package/out/zero-cache/src/server/syncer.js +10 -5
- package/out/zero-cache/src/server/syncer.js.map +1 -1
- package/out/zero-cache/src/server/worker-dispatcher.js +1 -1
- package/out/zero-cache/src/server/worker-dispatcher.js.map +1 -1
- package/out/zero-cache/src/server/worker-urls.js.map +1 -1
- package/out/zero-cache/src/services/analyze.js +2 -2
- package/out/zero-cache/src/services/analyze.js.map +1 -1
- package/out/zero-cache/src/services/change-source/common/backfill-manager.js +3 -3
- package/out/zero-cache/src/services/change-source/common/backfill-manager.js.map +1 -1
- package/out/zero-cache/src/services/change-source/common/change-stream-multiplexer.js +1 -1
- package/out/zero-cache/src/services/change-source/common/change-stream-multiplexer.js.map +1 -1
- package/out/zero-cache/src/services/change-source/common/init-cleanup.js.map +1 -1
- package/out/zero-cache/src/services/change-source/common/replica-restore.js.map +1 -1
- package/out/zero-cache/src/services/change-source/common/replica-schema.js +4 -4
- package/out/zero-cache/src/services/change-source/common/replica-schema.js.map +1 -1
- package/out/zero-cache/src/services/change-source/custom/change-source.js +3 -3
- package/out/zero-cache/src/services/change-source/custom/change-source.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/backfill-metadata.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/backfill-stream.js +3 -3
- package/out/zero-cache/src/services/change-source/pg/backfill-stream.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/change-source-init.js +52 -27
- package/out/zero-cache/src/services/change-source/pg/change-source-init.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/change-source.js +70 -15
- package/out/zero-cache/src/services/change-source/pg/change-source.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/decommission.js +2 -1
- package/out/zero-cache/src/services/change-source/pg/decommission.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/fork-request.js +54 -0
- package/out/zero-cache/src/services/change-source/pg/fork-request.js.map +1 -0
- package/out/zero-cache/src/services/change-source/pg/initial-sync.js +9 -7
- package/out/zero-cache/src/services/change-source/pg/initial-sync.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/logical-replication/binary-reader.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/logical-replication/pgoutput-parser.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/logical-replication/stream.js +4 -3
- package/out/zero-cache/src/services/change-source/pg/logical-replication/stream.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/lsn.d.ts +0 -2
- package/out/zero-cache/src/services/change-source/pg/lsn.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/lsn.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/replication-slot-cleanup-monitor.js +2 -2
- package/out/zero-cache/src/services/change-source/pg/replication-slot-cleanup-monitor.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/replication-slot-health.js +1 -1
- package/out/zero-cache/src/services/change-source/pg/replication-slot-health.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/replication-slots.js +9 -3
- package/out/zero-cache/src/services/change-source/pg/replication-slots.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/ddl.d.ts +0 -12
- package/out/zero-cache/src/services/change-source/pg/schema/ddl.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/ddl.js +5 -3
- package/out/zero-cache/src/services/change-source/pg/schema/ddl.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/index-predicate.d.ts +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/index-predicate.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/index-predicate.js +13 -12
- package/out/zero-cache/src/services/change-source/pg/schema/index-predicate.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/init.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/published.js +2 -2
- package/out/zero-cache/src/services/change-source/pg/schema/published.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/replica-stage-enum.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/shard.js +9 -6
- package/out/zero-cache/src/services/change-source/pg/schema/shard.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/validation.d.ts +0 -1
- package/out/zero-cache/src/services/change-source/pg/schema/validation.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/validation.js +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/validation.js.map +1 -1
- package/out/zero-cache/src/services/change-source/protocol/backfill-progress.js +1 -1
- package/out/zero-cache/src/services/change-source/protocol/backfill-progress.js.map +1 -1
- package/out/zero-cache/src/services/change-source/protocol/current/control.js.map +1 -1
- package/out/zero-cache/src/services/change-source/protocol/current/data.js.map +1 -1
- package/out/zero-cache/src/services/change-source/protocol/current/downstream.d.ts +1 -0
- package/out/zero-cache/src/services/change-source/protocol/current/downstream.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/protocol/current/downstream.js.map +1 -1
- package/out/zero-cache/src/services/change-source/protocol/current/status.d.ts +3 -0
- package/out/zero-cache/src/services/change-source/protocol/current/status.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/protocol/current/status.js +2 -1
- package/out/zero-cache/src/services/change-source/protocol/current/status.js.map +1 -1
- package/out/zero-cache/src/services/change-source/protocol/current/upstream.d.ts +1 -0
- package/out/zero-cache/src/services/change-source/protocol/current/upstream.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/protocol/current/upstream.js.map +1 -1
- package/out/zero-cache/src/services/change-source/protocol/current.js +1 -1
- package/out/zero-cache/src/services/change-source/protocol/mod.js +1 -2
- package/out/zero-cache/src/services/change-streamer/backfill-state-tracker.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/backfill-state.js +1 -1
- package/out/zero-cache/src/services/change-streamer/backfill-state.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/backup-cleanup-monitor-factory.js +6 -6
- package/out/zero-cache/src/services/change-streamer/backup-cleanup-monitor-factory.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/backup-monitor.js +56 -21
- package/out/zero-cache/src/services/change-streamer/backup-monitor.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/broadcast.js +2 -2
- package/out/zero-cache/src/services/change-streamer/broadcast.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-log-codec.js +2 -3
- package/out/zero-cache/src/services/change-streamer/change-log-codec.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-log-initializer.js +3 -3
- package/out/zero-cache/src/services/change-streamer/change-log-initializer.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-log-transaction-hash.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer-http.js +4 -2
- package/out/zero-cache/src/services/change-streamer/change-streamer-http.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer-service.js +49 -30
- package/out/zero-cache/src/services/change-streamer/change-streamer-service.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/drain-tracker.js +1 -1
- package/out/zero-cache/src/services/change-streamer/drain-tracker.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/forwarder.js +11 -10
- package/out/zero-cache/src/services/change-streamer/forwarder.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/litestream-sync-requester.js +81 -12
- package/out/zero-cache/src/services/change-streamer/litestream-sync-requester.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/litestream3-prometheus-poller.js +4 -4
- package/out/zero-cache/src/services/change-streamer/litestream3-prometheus-poller.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/replica-poller.js +2 -2
- package/out/zero-cache/src/services/change-streamer/replica-poller.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/restore-admission.js +12 -1
- package/out/zero-cache/src/services/change-streamer/restore-admission.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/schema/init.js +1 -1
- package/out/zero-cache/src/services/change-streamer/schema/init.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/schema/tables.js +1 -1
- package/out/zero-cache/src/services/change-streamer/schema/tables.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/server-start-metrics.js +42 -0
- package/out/zero-cache/src/services/change-streamer/server-start-metrics.js.map +1 -0
- package/out/zero-cache/src/services/change-streamer/snapshot-message.js +1 -2
- package/out/zero-cache/src/services/change-streamer/snapshot-message.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/snapshot-reservations.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-catchup.js +2 -2
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-catchup.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-comparator.js +2 -2
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-comparator.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-purge-scheduler.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-read-router.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-reader.js +4 -6
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-reader.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-writer.js +3 -5
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-writer.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/storer.js +4 -4
- package/out/zero-cache/src/services/change-streamer/storer.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/subscribe.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/subscriber.js +8 -7
- package/out/zero-cache/src/services/change-streamer/subscriber.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/upstream-acker.js +0 -1
- package/out/zero-cache/src/services/change-streamer/upstream-acker.js.map +1 -1
- package/out/zero-cache/src/services/heapz.js +2 -1
- package/out/zero-cache/src/services/heapz.js.map +1 -1
- package/out/zero-cache/src/services/http-service.d.ts +8 -2
- package/out/zero-cache/src/services/http-service.d.ts.map +1 -1
- package/out/zero-cache/src/services/http-service.js +19 -5
- package/out/zero-cache/src/services/http-service.js.map +1 -1
- package/out/zero-cache/src/services/life-cycle.d.ts +19 -0
- package/out/zero-cache/src/services/life-cycle.d.ts.map +1 -1
- package/out/zero-cache/src/services/life-cycle.js +55 -3
- package/out/zero-cache/src/services/life-cycle.js.map +1 -1
- package/out/zero-cache/src/services/limiter/sliding-window-limiter.js +4 -2
- package/out/zero-cache/src/services/limiter/sliding-window-limiter.js.map +1 -1
- package/out/zero-cache/src/services/litestream/commands.js +4 -4
- package/out/zero-cache/src/services/litestream/commands.js.map +1 -1
- package/out/zero-cache/src/services/litestream/litestream-checkpointer.js +2 -2
- package/out/zero-cache/src/services/litestream/litestream-checkpointer.js.map +1 -1
- package/out/zero-cache/src/services/litestream/litestream-controller.js.map +1 -1
- package/out/zero-cache/src/services/litestream/metrics.js.map +1 -1
- package/out/zero-cache/src/services/litestream/restore-progress.js.map +1 -1
- package/out/zero-cache/src/services/mutagen/mutagen.js +3 -4
- package/out/zero-cache/src/services/mutagen/mutagen.js.map +1 -1
- package/out/zero-cache/src/services/mutagen/pusher.js +61 -17
- package/out/zero-cache/src/services/mutagen/pusher.js.map +1 -1
- package/out/zero-cache/src/services/plannerz.d.ts +4 -12
- package/out/zero-cache/src/services/plannerz.d.ts.map +1 -1
- package/out/zero-cache/src/services/plannerz.js +6 -7
- package/out/zero-cache/src/services/plannerz.js.map +1 -1
- package/out/zero-cache/src/services/profz.js +5 -3
- package/out/zero-cache/src/services/profz.js.map +1 -1
- package/out/zero-cache/src/services/replicator/change-log-cookies.js.map +1 -1
- package/out/zero-cache/src/services/replicator/change-log-db.js +4 -3
- package/out/zero-cache/src/services/replicator/change-log-db.js.map +1 -1
- package/out/zero-cache/src/services/replicator/change-log-stream-writer.js.map +1 -1
- package/out/zero-cache/src/services/replicator/change-processor.js +1 -1
- package/out/zero-cache/src/services/replicator/change-processor.js.map +1 -1
- package/out/zero-cache/src/services/replicator/drain-handler.js +1 -1
- package/out/zero-cache/src/services/replicator/drain-handler.js.map +1 -1
- package/out/zero-cache/src/services/replicator/incremental-sync.js +4 -4
- package/out/zero-cache/src/services/replicator/incremental-sync.js.map +1 -1
- package/out/zero-cache/src/services/replicator/notifier.js.map +1 -1
- package/out/zero-cache/src/services/replicator/replication-status.js +4 -3
- package/out/zero-cache/src/services/replicator/replication-status.js.map +1 -1
- package/out/zero-cache/src/services/replicator/replicator.js.map +1 -1
- package/out/zero-cache/src/services/replicator/reporter/recorder.js +2 -2
- package/out/zero-cache/src/services/replicator/reporter/recorder.js.map +1 -1
- package/out/zero-cache/src/services/replicator/reporter/report-schema.d.ts +2 -11
- package/out/zero-cache/src/services/replicator/reporter/report-schema.d.ts.map +1 -1
- package/out/zero-cache/src/services/replicator/reporter/report-schema.js.map +1 -1
- package/out/zero-cache/src/services/replicator/schema/backfilling.js +2 -2
- package/out/zero-cache/src/services/replicator/schema/backfilling.js.map +1 -1
- package/out/zero-cache/src/services/replicator/schema/change-log.d.ts +19 -17
- package/out/zero-cache/src/services/replicator/schema/change-log.d.ts.map +1 -1
- package/out/zero-cache/src/services/replicator/schema/change-log.js +31 -15
- package/out/zero-cache/src/services/replicator/schema/change-log.js.map +1 -1
- package/out/zero-cache/src/services/replicator/schema/column-metadata.d.ts +0 -7
- package/out/zero-cache/src/services/replicator/schema/column-metadata.d.ts.map +1 -1
- package/out/zero-cache/src/services/replicator/schema/column-metadata.js +1 -1
- package/out/zero-cache/src/services/replicator/schema/column-metadata.js.map +1 -1
- package/out/zero-cache/src/services/replicator/schema/replication-state.js +10 -7
- package/out/zero-cache/src/services/replicator/schema/replication-state.js.map +1 -1
- package/out/zero-cache/src/services/replicator/schema/table-metadata.js.map +1 -1
- package/out/zero-cache/src/services/replicator/sqlite-change-log-observability.js +1 -1
- package/out/zero-cache/src/services/replicator/sqlite-change-log-observability.js.map +1 -1
- package/out/zero-cache/src/services/replicator/sqlite-change-log-purger.js +1 -1
- package/out/zero-cache/src/services/replicator/sqlite-change-log-purger.js.map +1 -1
- package/out/zero-cache/src/services/replicator/write-worker-client.js +2 -2
- package/out/zero-cache/src/services/replicator/write-worker-client.js.map +1 -1
- package/out/zero-cache/src/services/replicator/write-worker.js +3 -3
- package/out/zero-cache/src/services/replicator/write-worker.js.map +1 -1
- package/out/zero-cache/src/services/run-ast.js +1 -1
- package/out/zero-cache/src/services/run-ast.js.map +1 -1
- package/out/zero-cache/src/services/runner.js.map +1 -1
- package/out/zero-cache/src/services/running-state.js +1 -1
- package/out/zero-cache/src/services/running-state.js.map +1 -1
- package/out/zero-cache/src/services/shadow-sync/shadow-sync-service.js.map +1 -1
- package/out/zero-cache/src/services/statz.js +4 -3
- package/out/zero-cache/src/services/statz.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/active-users-gauge.js +2 -2
- package/out/zero-cache/src/services/view-syncer/active-users-gauge.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/advancement-metrics.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/batch-pacer.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/client-handler.js +71 -24
- package/out/zero-cache/src/services/view-syncer/client-handler.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/client-schema.js +46 -6
- package/out/zero-cache/src/services/view-syncer/client-schema.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/connection-context-manager.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/cvr-purger.js +2 -2
- package/out/zero-cache/src/services/view-syncer/cvr-purger.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/cvr-store.js +12 -7
- package/out/zero-cache/src/services/view-syncer/cvr-store.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/cvr.js +12 -4
- package/out/zero-cache/src/services/view-syncer/cvr.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/deferred-writes-budget.js +1 -1
- package/out/zero-cache/src/services/view-syncer/deferred-writes-budget.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/drain-coordinator.js +2 -2
- package/out/zero-cache/src/services/view-syncer/drain-coordinator.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/e2e-serving-lag.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/hydration-budget.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/hydration-circuit-breaker.js +2 -2
- package/out/zero-cache/src/services/view-syncer/hydration-circuit-breaker.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/inspect-handler.js +6 -4
- package/out/zero-cache/src/services/view-syncer/inspect-handler.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.js +112 -21
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/plan-warnings.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/push-cost.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/push-cutoff.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/query-covering.js +2 -2
- package/out/zero-cache/src/services/view-syncer/query-covering.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/query-shape.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/query-stats.js +1 -1
- package/out/zero-cache/src/services/view-syncer/query-stats.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/row-record-cache.js +2 -2
- package/out/zero-cache/src/services/view-syncer/row-record-cache.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/schema/cvr.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/schema/types.js +2 -16
- package/out/zero-cache/src/services/view-syncer/schema/types.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/snapshot-row-cache.js +7 -1
- package/out/zero-cache/src/services/view-syncer/snapshot-row-cache.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/snapshotter.js +13 -9
- package/out/zero-cache/src/services/view-syncer/snapshotter.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/ttl-clock.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/view-syncer.js +52 -28
- package/out/zero-cache/src/services/view-syncer/view-syncer.js.map +1 -1
- package/out/zero-cache/src/types/error-with-level.js.map +1 -1
- package/out/zero-cache/src/types/lexi-version.js.map +1 -1
- package/out/zero-cache/src/types/lite.d.ts +0 -1
- package/out/zero-cache/src/types/lite.d.ts.map +1 -1
- package/out/zero-cache/src/types/lite.js +1 -1
- package/out/zero-cache/src/types/lite.js.map +1 -1
- package/out/zero-cache/src/types/pg-data-type.js +1 -1
- package/out/zero-cache/src/types/pg-data-type.js.map +1 -1
- package/out/zero-cache/src/types/pg-types.d.ts +0 -40
- package/out/zero-cache/src/types/pg-types.d.ts.map +1 -1
- package/out/zero-cache/src/types/pg-types.js.map +1 -1
- package/out/zero-cache/src/types/pg.js +6 -4
- package/out/zero-cache/src/types/pg.js.map +1 -1
- package/out/zero-cache/src/types/poke-chunk.d.ts +0 -1
- package/out/zero-cache/src/types/poke-chunk.d.ts.map +1 -1
- package/out/zero-cache/src/types/poke-chunk.js +1 -1
- package/out/zero-cache/src/types/poke-chunk.js.map +1 -1
- package/out/zero-cache/src/types/processes.js +5 -5
- package/out/zero-cache/src/types/processes.js.map +1 -1
- package/out/zero-cache/src/types/profiler.js +1 -1
- package/out/zero-cache/src/types/profiler.js.map +1 -1
- package/out/zero-cache/src/types/row-key.d.ts +0 -5
- package/out/zero-cache/src/types/row-key.d.ts.map +1 -1
- package/out/zero-cache/src/types/row-key.js +8 -1
- package/out/zero-cache/src/types/row-key.js.map +1 -1
- package/out/zero-cache/src/types/sql.js.map +1 -1
- package/out/zero-cache/src/types/streams.d.ts.map +1 -1
- package/out/zero-cache/src/types/streams.js +11 -10
- package/out/zero-cache/src/types/streams.js.map +1 -1
- package/out/zero-cache/src/types/strings.js.map +1 -1
- package/out/zero-cache/src/types/subscription.js +1 -1
- package/out/zero-cache/src/types/subscription.js.map +1 -1
- package/out/zero-cache/src/types/timeout.js +1 -1
- package/out/zero-cache/src/types/websocket-handoff.d.ts +4 -7
- package/out/zero-cache/src/types/websocket-handoff.d.ts.map +1 -1
- package/out/zero-cache/src/types/websocket-handoff.js +16 -2
- package/out/zero-cache/src/types/websocket-handoff.js.map +1 -1
- package/out/zero-cache/src/types/ws.d.ts +2 -1
- package/out/zero-cache/src/types/ws.d.ts.map +1 -1
- package/out/zero-cache/src/types/ws.js.map +1 -1
- package/out/zero-cache/src/workers/connection.d.ts +1 -2
- package/out/zero-cache/src/workers/connection.d.ts.map +1 -1
- package/out/zero-cache/src/workers/connection.js +10 -8
- package/out/zero-cache/src/workers/connection.js.map +1 -1
- package/out/zero-cache/src/workers/mutator.js +1 -1
- package/out/zero-cache/src/workers/mutator.js.map +1 -1
- package/out/zero-cache/src/workers/rehome.d.ts +15 -0
- package/out/zero-cache/src/workers/rehome.d.ts.map +1 -0
- package/out/zero-cache/src/workers/rehome.js +36 -0
- package/out/zero-cache/src/workers/rehome.js.map +1 -0
- package/out/zero-cache/src/workers/replicator.js +5 -4
- package/out/zero-cache/src/workers/replicator.js.map +1 -1
- package/out/zero-cache/src/workers/syncer-ws-message-handler.js +9 -1
- package/out/zero-cache/src/workers/syncer-ws-message-handler.js.map +1 -1
- package/out/zero-cache/src/workers/syncer.js +32 -7
- package/out/zero-cache/src/workers/syncer.js.map +1 -1
- package/out/zero-client/src/client/active-clients-manager.d.ts.map +1 -1
- package/out/zero-client/src/client/active-clients-manager.js +2 -2
- package/out/zero-client/src/client/active-clients-manager.js.map +1 -1
- package/out/zero-client/src/client/bindings.d.ts +1 -1
- package/out/zero-client/src/client/bindings.d.ts.map +1 -1
- package/out/zero-client/src/client/bindings.js +11 -11
- package/out/zero-client/src/client/connection-manager.js +1 -1
- package/out/zero-client/src/client/connection-manager.js.map +1 -1
- package/out/zero-client/src/client/connection.js +1 -1
- package/out/zero-client/src/client/connection.js.map +1 -1
- package/out/zero-client/src/client/context.d.ts +7 -1
- package/out/zero-client/src/client/context.d.ts.map +1 -1
- package/out/zero-client/src/client/context.js +7 -0
- package/out/zero-client/src/client/context.js.map +1 -1
- package/out/zero-client/src/client/crud-impl.d.ts.map +1 -1
- package/out/zero-client/src/client/crud-impl.js +172 -3
- package/out/zero-client/src/client/crud-impl.js.map +1 -1
- package/out/zero-client/src/client/crud.d.ts +2 -8
- package/out/zero-client/src/client/crud.d.ts.map +1 -1
- package/out/zero-client/src/client/crud.js.map +1 -1
- package/out/zero-client/src/client/custom.d.ts +0 -2
- package/out/zero-client/src/client/custom.d.ts.map +1 -1
- package/out/zero-client/src/client/custom.js +42 -3
- package/out/zero-client/src/client/custom.js.map +1 -1
- package/out/zero-client/src/client/delete-clients-manager.js.map +1 -1
- package/out/zero-client/src/client/enable-analytics.d.ts +0 -1
- package/out/zero-client/src/client/enable-analytics.d.ts.map +1 -1
- package/out/zero-client/src/client/enable-analytics.js +1 -0
- package/out/zero-client/src/client/enable-analytics.js.map +1 -1
- package/out/zero-client/src/client/error.d.ts +4 -5
- package/out/zero-client/src/client/error.d.ts.map +1 -1
- package/out/zero-client/src/client/error.js.map +1 -1
- package/out/zero-client/src/client/inspector/client-group.js.map +1 -1
- package/out/zero-client/src/client/inspector/client.js.map +1 -1
- package/out/zero-client/src/client/inspector/html-dialog-prompt.js +1 -1
- package/out/zero-client/src/client/inspector/html-dialog-prompt.js.map +1 -1
- package/out/zero-client/src/client/inspector/inspector.js.map +1 -1
- package/out/zero-client/src/client/inspector/lazy-inspector.js.map +1 -1
- package/out/zero-client/src/client/inspector/query.js.map +1 -1
- package/out/zero-client/src/client/ivm-branch.d.ts +62 -2
- package/out/zero-client/src/client/ivm-branch.d.ts.map +1 -1
- package/out/zero-client/src/client/ivm-branch.js +153 -34
- package/out/zero-client/src/client/ivm-branch.js.map +1 -1
- package/out/zero-client/src/client/keys.d.ts +33 -1
- package/out/zero-client/src/client/keys.d.ts.map +1 -1
- package/out/zero-client/src/client/keys.js +49 -7
- package/out/zero-client/src/client/keys.js.map +1 -1
- package/out/zero-client/src/client/log-options.js.map +1 -1
- package/out/zero-client/src/client/make-replicache-mutators.js +5 -3
- package/out/zero-client/src/client/make-replicache-mutators.js.map +1 -1
- package/out/zero-client/src/client/metrics.js +3 -5
- package/out/zero-client/src/client/metrics.js.map +1 -1
- package/out/zero-client/src/client/mutation-tracker.d.ts.map +1 -1
- package/out/zero-client/src/client/mutation-tracker.js +1 -1
- package/out/zero-client/src/client/mutation-tracker.js.map +1 -1
- package/out/zero-client/src/client/mutator-proxy.js.map +1 -1
- package/out/zero-client/src/client/options.d.ts +0 -4
- package/out/zero-client/src/client/options.d.ts.map +1 -1
- package/out/zero-client/src/client/options.js.map +1 -1
- package/out/zero-client/src/client/query-manager.js +2 -2
- package/out/zero-client/src/client/query-manager.js.map +1 -1
- package/out/zero-client/src/client/reload-error-handler.js +4 -3
- package/out/zero-client/src/client/reload-error-handler.js.map +1 -1
- package/out/zero-client/src/client/replicache-types.d.ts +3 -2
- package/out/zero-client/src/client/replicache-types.d.ts.map +1 -1
- package/out/zero-client/src/client/version.js +1 -1
- package/out/zero-client/src/client/zero-poke-handler.d.ts +1 -2
- package/out/zero-client/src/client/zero-poke-handler.d.ts.map +1 -1
- package/out/zero-client/src/client/zero-poke-handler.js +30 -2
- package/out/zero-client/src/client/zero-poke-handler.js.map +1 -1
- package/out/zero-client/src/client/zero-rep.d.ts +1 -1
- package/out/zero-client/src/client/zero-rep.d.ts.map +1 -1
- package/out/zero-client/src/client/zero-rep.js +2 -15
- package/out/zero-client/src/client/zero-rep.js.map +1 -1
- package/out/zero-client/src/client/zero.d.ts +1 -5
- package/out/zero-client/src/client/zero.d.ts.map +1 -1
- package/out/zero-client/src/client/zero.js +21 -13
- package/out/zero-client/src/client/zero.js.map +1 -1
- package/out/zero-client/src/mod.d.ts +3 -3
- package/out/zero-client/src/mod.d.ts.map +1 -1
- package/out/zero-client/src/mod.js +23 -23
- package/out/zero-client/src/types/client-state.d.ts +0 -6
- package/out/zero-client/src/types/client-state.d.ts.map +1 -1
- package/out/zero-client/src/util/nanoid.js.map +1 -1
- package/out/zero-permissions/src/permissions.d.ts +1 -12
- package/out/zero-permissions/src/permissions.d.ts.map +1 -1
- package/out/zero-permissions/src/permissions.js +3 -3
- package/out/zero-permissions/src/permissions.js.map +1 -1
- package/out/zero-pg/src/mod.js +9 -9
- package/out/zero-protocol/src/aggregate-table.d.ts +15 -0
- package/out/zero-protocol/src/aggregate-table.d.ts.map +1 -0
- package/out/zero-protocol/src/aggregate-table.js +5 -0
- package/out/zero-protocol/src/aggregate-table.js.map +1 -0
- package/out/zero-protocol/src/analyze-query-result.js +1 -1
- package/out/zero-protocol/src/analyze-query-result.js.map +1 -1
- package/out/zero-protocol/src/application-error.js.map +1 -1
- package/out/zero-protocol/src/ast.d.ts +140 -8
- package/out/zero-protocol/src/ast.d.ts.map +1 -1
- package/out/zero-protocol/src/ast.js +264 -28
- package/out/zero-protocol/src/ast.js.map +1 -1
- package/out/zero-protocol/src/change-desired-queries.d.ts +0 -20
- package/out/zero-protocol/src/change-desired-queries.d.ts.map +1 -1
- package/out/zero-protocol/src/change-desired-queries.js.map +1 -1
- package/out/zero-protocol/src/client-schema.d.ts +2 -5
- package/out/zero-protocol/src/client-schema.d.ts.map +1 -1
- package/out/zero-protocol/src/client-schema.js.map +1 -1
- package/out/zero-protocol/src/close-connection.d.ts +0 -8
- package/out/zero-protocol/src/close-connection.d.ts.map +1 -1
- package/out/zero-protocol/src/close-connection.js.map +1 -1
- package/out/zero-protocol/src/connect.d.ts +0 -12
- package/out/zero-protocol/src/connect.d.ts.map +1 -1
- package/out/zero-protocol/src/connect.js.map +1 -1
- package/out/zero-protocol/src/custom-queries.d.ts +3 -17
- package/out/zero-protocol/src/custom-queries.d.ts.map +1 -1
- package/out/zero-protocol/src/custom-queries.js.map +1 -1
- package/out/zero-protocol/src/data.d.ts +0 -1
- package/out/zero-protocol/src/data.d.ts.map +1 -1
- package/out/zero-protocol/src/data.js +3 -1
- package/out/zero-protocol/src/data.js.map +1 -1
- package/out/zero-protocol/src/delete-clients.js.map +1 -1
- package/out/zero-protocol/src/down.d.ts +27 -27
- package/out/zero-protocol/src/down.js.map +1 -1
- package/out/zero-protocol/src/error.js.map +1 -1
- package/out/zero-protocol/src/inspect-down.d.ts +1 -3
- package/out/zero-protocol/src/inspect-down.d.ts.map +1 -1
- package/out/zero-protocol/src/inspect-down.js.map +1 -1
- package/out/zero-protocol/src/inspect-up.d.ts +0 -28
- package/out/zero-protocol/src/inspect-up.d.ts.map +1 -1
- package/out/zero-protocol/src/inspect-up.js.map +1 -1
- package/out/zero-protocol/src/mutate-server.d.ts +0 -21
- package/out/zero-protocol/src/mutate-server.d.ts.map +1 -1
- package/out/zero-protocol/src/mutate-server.js.map +1 -1
- package/out/zero-protocol/src/mutation-id.js.map +1 -1
- package/out/zero-protocol/src/mutation-type-enum.d.ts +0 -1
- package/out/zero-protocol/src/mutation-type-enum.d.ts.map +1 -1
- package/out/zero-protocol/src/mutation-type-enum.js.map +1 -1
- package/out/zero-protocol/src/mutation.d.ts +2 -4
- package/out/zero-protocol/src/mutation.d.ts.map +1 -1
- package/out/zero-protocol/src/mutation.js.map +1 -1
- package/out/zero-protocol/src/mutations-patch.d.ts +0 -33
- package/out/zero-protocol/src/mutations-patch.d.ts.map +1 -1
- package/out/zero-protocol/src/mutations-patch.js.map +1 -1
- package/out/zero-protocol/src/ping.d.ts +0 -2
- package/out/zero-protocol/src/ping.d.ts.map +1 -1
- package/out/zero-protocol/src/ping.js.map +1 -1
- package/out/zero-protocol/src/poke.d.ts +3 -2
- package/out/zero-protocol/src/poke.d.ts.map +1 -1
- package/out/zero-protocol/src/poke.js +1 -1
- package/out/zero-protocol/src/poke.js.map +1 -1
- package/out/zero-protocol/src/pong.d.ts +0 -2
- package/out/zero-protocol/src/pong.d.ts.map +1 -1
- package/out/zero-protocol/src/pong.js.map +1 -1
- package/out/zero-protocol/src/primary-key.js.map +1 -1
- package/out/zero-protocol/src/protocol-version.d.ts +1 -1
- package/out/zero-protocol/src/protocol-version.d.ts.map +1 -1
- package/out/zero-protocol/src/protocol-version.js +1 -0
- package/out/zero-protocol/src/protocol-version.js.map +1 -1
- package/out/zero-protocol/src/pull.d.ts +2 -7
- package/out/zero-protocol/src/pull.d.ts.map +1 -1
- package/out/zero-protocol/src/pull.js.map +1 -1
- package/out/zero-protocol/src/push.d.ts +1 -3
- package/out/zero-protocol/src/push.d.ts.map +1 -1
- package/out/zero-protocol/src/push.js.map +1 -1
- package/out/zero-protocol/src/queries-patch.d.ts +0 -16
- package/out/zero-protocol/src/queries-patch.d.ts.map +1 -1
- package/out/zero-protocol/src/queries-patch.js +1 -1
- package/out/zero-protocol/src/queries-patch.js.map +1 -1
- package/out/zero-protocol/src/query-hash-visitor.d.ts.map +1 -1
- package/out/zero-protocol/src/query-hash-visitor.js +38 -0
- package/out/zero-protocol/src/query-hash-visitor.js.map +1 -1
- package/out/zero-protocol/src/query-hash.js +2 -2
- package/out/zero-protocol/src/query-server.d.ts +2 -41
- package/out/zero-protocol/src/query-server.d.ts.map +1 -1
- package/out/zero-protocol/src/query-server.js.map +1 -1
- package/out/zero-protocol/src/row-patch.js.map +1 -1
- package/out/zero-protocol/src/up.d.ts +60 -60
- package/out/zero-protocol/src/up.js +1 -1
- package/out/zero-protocol/src/up.js.map +1 -1
- package/out/zero-protocol/src/update-auth.js.map +1 -1
- package/out/zero-protocol/src/version.d.ts +0 -1
- package/out/zero-protocol/src/version.d.ts.map +1 -1
- package/out/zero-protocol/src/version.js.map +1 -1
- package/out/zero-react/src/bindings.js +11 -11
- package/out/zero-react/src/mod.js +5 -5
- package/out/zero-react/src/use-query.d.ts +3 -1
- package/out/zero-react/src/use-query.d.ts.map +1 -1
- package/out/zero-react/src/use-query.js +6 -4
- package/out/zero-react/src/use-query.js.map +1 -1
- package/out/zero-react/src/zero-provider.d.ts +1 -1
- package/out/zero-react/src/zero-provider.d.ts.map +1 -1
- package/out/zero-react/src/zero-provider.js +2 -1
- package/out/zero-react/src/zero-provider.js.map +1 -1
- package/out/zero-react/src/zero.js +23 -23
- package/out/zero-schema/src/builder/relationship-builder.d.ts +0 -2
- package/out/zero-schema/src/builder/relationship-builder.d.ts.map +1 -1
- package/out/zero-schema/src/builder/relationship-builder.js.map +1 -1
- package/out/zero-schema/src/builder/schema-builder.d.ts.map +1 -1
- package/out/zero-schema/src/builder/schema-builder.js +5 -2
- package/out/zero-schema/src/builder/schema-builder.js.map +1 -1
- package/out/zero-schema/src/builder/table-builder.d.ts +1 -1
- package/out/zero-schema/src/builder/table-builder.d.ts.map +1 -1
- package/out/zero-schema/src/builder/table-builder.js +1 -1
- package/out/zero-schema/src/builder/table-builder.js.map +1 -1
- package/out/zero-schema/src/compiled-permissions.js.map +1 -1
- package/out/zero-schema/src/name-mapper.d.ts.map +1 -1
- package/out/zero-schema/src/name-mapper.js +14 -9
- package/out/zero-schema/src/name-mapper.js.map +1 -1
- package/out/zero-schema/src/schema-config.d.ts +0 -1
- package/out/zero-schema/src/schema-config.d.ts.map +1 -1
- package/out/zero-schema/src/schema-config.js +1 -1
- package/out/zero-schema/src/schema-config.js.map +1 -1
- package/out/zero-schema/src/table-schema.d.ts +3 -11
- package/out/zero-schema/src/table-schema.d.ts.map +1 -1
- package/out/zero-server/src/adapters/drizzle.js.map +1 -1
- package/out/zero-server/src/adapters/kysely.js.map +1 -1
- package/out/zero-server/src/adapters/pg.js.map +1 -1
- package/out/zero-server/src/adapters/postgresjs.js.map +1 -1
- package/out/zero-server/src/adapters/prisma.js.map +1 -1
- package/out/zero-server/src/closable-db-transaction.js.map +1 -1
- package/out/zero-server/src/custom.js +2 -2
- package/out/zero-server/src/custom.js.map +1 -1
- package/out/zero-server/src/mod.js +8 -8
- package/out/zero-server/src/process-mutations.js.map +1 -1
- package/out/zero-server/src/push-processor.js.map +1 -1
- package/out/zero-server/src/queries/process-queries.d.ts +2 -4
- package/out/zero-server/src/queries/process-queries.d.ts.map +1 -1
- package/out/zero-server/src/queries/process-queries.js +2 -1
- package/out/zero-server/src/queries/process-queries.js.map +1 -1
- package/out/zero-server/src/schema.d.ts.map +1 -1
- package/out/zero-server/src/schema.js +20 -9
- package/out/zero-server/src/schema.js.map +1 -1
- package/out/zero-server/src/zql-database.js.map +1 -1
- package/out/zero-solid/src/bindings.js +11 -11
- package/out/zero-solid/src/mod.js +5 -5
- package/out/zero-solid/src/solid-view.d.ts +0 -2
- package/out/zero-solid/src/solid-view.d.ts.map +1 -1
- package/out/zero-solid/src/solid-view.js +4 -4
- package/out/zero-solid/src/solid-view.js.map +1 -1
- package/out/zero-solid/src/use-connection-state.js +2 -1
- package/out/zero-solid/src/use-connection-state.js.map +1 -1
- package/out/zero-solid/src/use-query.js.map +1 -1
- package/out/zero-solid/src/use-zero-online.js +2 -1
- package/out/zero-solid/src/use-zero-online.js.map +1 -1
- package/out/zero-solid/src/use-zero.js +3 -2
- package/out/zero-solid/src/use-zero.js.map +1 -1
- package/out/zero-solid/src/zero.js +23 -23
- package/out/zero-types/src/format.d.ts +13 -0
- package/out/zero-types/src/format.d.ts.map +1 -1
- package/out/zero-types/src/format.js.map +1 -1
- package/out/zero-types/src/name-mapper.d.ts +16 -1
- package/out/zero-types/src/name-mapper.d.ts.map +1 -1
- package/out/zero-types/src/name-mapper.js +12 -0
- package/out/zero-types/src/name-mapper.js.map +1 -1
- package/out/zero-types/src/schema-value.d.ts +5 -2
- package/out/zero-types/src/schema-value.d.ts.map +1 -1
- package/out/zero-types/src/schema-value.js +15 -0
- package/out/zero-types/src/schema-value.js.map +1 -0
- package/out/zero-types/src/schema.d.ts +1 -1
- package/out/zero-types/src/schema.d.ts.map +1 -1
- package/out/zero-types/src/server-schema.d.ts +18 -0
- package/out/zero-types/src/server-schema.d.ts.map +1 -1
- package/out/zql/src/builder/builder.d.ts +124 -9
- package/out/zql/src/builder/builder.d.ts.map +1 -1
- package/out/zql/src/builder/builder.js +295 -23
- package/out/zql/src/builder/builder.js.map +1 -1
- package/out/zql/src/builder/correlated-predicate-pushdown.js.map +1 -1
- package/out/zql/src/builder/debug-delegate.js.map +1 -1
- package/out/zql/src/builder/filter.d.ts +1 -2
- package/out/zql/src/builder/filter.d.ts.map +1 -1
- package/out/zql/src/builder/filter.js +41 -3
- package/out/zql/src/builder/filter.js.map +1 -1
- package/out/zql/src/builder/like.js +0 -1
- package/out/zql/src/builder/like.js.map +1 -1
- package/out/zql/src/error.d.ts +0 -5
- package/out/zql/src/error.d.ts.map +1 -1
- package/out/zql/src/error.js.map +1 -1
- package/out/zql/src/ivm/aggregate.d.ts +188 -0
- package/out/zql/src/ivm/aggregate.d.ts.map +1 -0
- package/out/zql/src/ivm/aggregate.js +470 -0
- package/out/zql/src/ivm/aggregate.js.map +1 -0
- package/out/zql/src/ivm/array-view.d.ts +1 -1
- package/out/zql/src/ivm/array-view.d.ts.map +1 -1
- package/out/zql/src/ivm/array-view.js +3 -3
- package/out/zql/src/ivm/array-view.js.map +1 -1
- package/out/zql/src/ivm/cap.d.ts +1 -1
- package/out/zql/src/ivm/cap.d.ts.map +1 -1
- package/out/zql/src/ivm/cap.js +14 -6
- package/out/zql/src/ivm/cap.js.map +1 -1
- package/out/zql/src/ivm/constraint.d.ts +0 -7
- package/out/zql/src/ivm/constraint.d.ts.map +1 -1
- package/out/zql/src/ivm/constraint.js +3 -2
- package/out/zql/src/ivm/constraint.js.map +1 -1
- package/out/zql/src/ivm/data.d.ts +15 -2
- package/out/zql/src/ivm/data.d.ts.map +1 -1
- package/out/zql/src/ivm/data.js +15 -1
- package/out/zql/src/ivm/data.js.map +1 -1
- package/out/zql/src/ivm/deferred-input.js +1 -1
- package/out/zql/src/ivm/deferred-input.js.map +1 -1
- package/out/zql/src/ivm/exists.d.ts.map +1 -1
- package/out/zql/src/ivm/exists.js +32 -22
- package/out/zql/src/ivm/exists.js.map +1 -1
- package/out/zql/src/ivm/fan-in.js +1 -1
- package/out/zql/src/ivm/fan-in.js.map +1 -1
- package/out/zql/src/ivm/fan-out.js.map +1 -1
- package/out/zql/src/ivm/filter-operators.d.ts +5 -0
- package/out/zql/src/ivm/filter-operators.d.ts.map +1 -1
- package/out/zql/src/ivm/filter-operators.js +1 -1
- package/out/zql/src/ivm/filter-operators.js.map +1 -1
- package/out/zql/src/ivm/filter-push.js.map +1 -1
- package/out/zql/src/ivm/filter.js.map +1 -1
- package/out/zql/src/ivm/flipped-join.d.ts.map +1 -1
- package/out/zql/src/ivm/flipped-join.js +4 -5
- package/out/zql/src/ivm/flipped-join.js.map +1 -1
- package/out/zql/src/ivm/group-by.d.ts +98 -0
- package/out/zql/src/ivm/group-by.d.ts.map +1 -0
- package/out/zql/src/ivm/group-by.js +384 -0
- package/out/zql/src/ivm/group-by.js.map +1 -0
- package/out/zql/src/ivm/join-index-tap.js.map +1 -1
- package/out/zql/src/ivm/join-index.d.ts.map +1 -1
- package/out/zql/src/ivm/join-index.js +2 -1
- package/out/zql/src/ivm/join-index.js.map +1 -1
- package/out/zql/src/ivm/join-utils.d.ts.map +1 -1
- package/out/zql/src/ivm/join-utils.js +13 -14
- package/out/zql/src/ivm/join-utils.js.map +1 -1
- package/out/zql/src/ivm/join.d.ts.map +1 -1
- package/out/zql/src/ivm/join.js +7 -4
- package/out/zql/src/ivm/join.js.map +1 -1
- package/out/zql/src/ivm/lift-field.d.ts +54 -0
- package/out/zql/src/ivm/lift-field.d.ts.map +1 -0
- package/out/zql/src/ivm/lift-field.js +168 -0
- package/out/zql/src/ivm/lift-field.js.map +1 -0
- package/out/zql/src/ivm/maybe-split-and-push-edit-change.js +1 -1
- package/out/zql/src/ivm/maybe-split-and-push-edit-change.js.map +1 -1
- package/out/zql/src/ivm/memory-source.d.ts +3 -2
- package/out/zql/src/ivm/memory-source.d.ts.map +1 -1
- package/out/zql/src/ivm/memory-source.js +36 -27
- package/out/zql/src/ivm/memory-source.js.map +1 -1
- package/out/zql/src/ivm/memory-storage.js.map +1 -1
- package/out/zql/src/ivm/operator.d.ts +6 -0
- package/out/zql/src/ivm/operator.d.ts.map +1 -1
- package/out/zql/src/ivm/operator.js +2 -2
- package/out/zql/src/ivm/operator.js.map +1 -1
- package/out/zql/src/ivm/push-accumulated.js +1 -2
- package/out/zql/src/ivm/push-accumulated.js.map +1 -1
- package/out/zql/src/ivm/schema.d.ts +1 -0
- package/out/zql/src/ivm/schema.d.ts.map +1 -1
- package/out/zql/src/ivm/skip-yields.js.map +1 -1
- package/out/zql/src/ivm/skip.js.map +1 -1
- package/out/zql/src/ivm/source.d.ts +21 -0
- package/out/zql/src/ivm/source.d.ts.map +1 -1
- package/out/zql/src/ivm/source.js.map +1 -1
- package/out/zql/src/ivm/stream.d.ts +0 -1
- package/out/zql/src/ivm/stream.d.ts.map +1 -1
- package/out/zql/src/ivm/stream.js.map +1 -1
- package/out/zql/src/ivm/take-gate.js.map +1 -1
- package/out/zql/src/ivm/take.d.ts.map +1 -1
- package/out/zql/src/ivm/take.js +8 -9
- package/out/zql/src/ivm/take.js.map +1 -1
- package/out/zql/src/ivm/union-fan-in.d.ts +0 -1
- package/out/zql/src/ivm/union-fan-in.d.ts.map +1 -1
- package/out/zql/src/ivm/union-fan-in.js +1 -1
- package/out/zql/src/ivm/union-fan-in.js.map +1 -1
- package/out/zql/src/ivm/union-fan-out.js.map +1 -1
- package/out/zql/src/ivm/view-apply-change.d.ts +8 -33
- package/out/zql/src/ivm/view-apply-change.d.ts.map +1 -1
- package/out/zql/src/ivm/view-apply-change.js +23 -3
- package/out/zql/src/ivm/view-apply-change.js.map +1 -1
- package/out/zql/src/mutate/crud.d.ts +1 -3
- package/out/zql/src/mutate/crud.d.ts.map +1 -1
- package/out/zql/src/mutate/crud.js +2 -1
- package/out/zql/src/mutate/crud.js.map +1 -1
- package/out/zql/src/mutate/mutator-registry.d.ts +1 -1
- package/out/zql/src/mutate/mutator-registry.d.ts.map +1 -1
- package/out/zql/src/mutate/mutator-registry.js.map +1 -1
- package/out/zql/src/mutate/mutator.d.ts +1 -1
- package/out/zql/src/mutate/mutator.d.ts.map +1 -1
- package/out/zql/src/mutate/mutator.js.map +1 -1
- package/out/zql/src/planner/planner-builder.js +1 -1
- package/out/zql/src/planner/planner-builder.js.map +1 -1
- package/out/zql/src/planner/planner-connection.js.map +1 -1
- package/out/zql/src/planner/planner-debug.d.ts +11 -10
- package/out/zql/src/planner/planner-debug.d.ts.map +1 -1
- package/out/zql/src/planner/planner-debug.js +4 -0
- package/out/zql/src/planner/planner-debug.js.map +1 -1
- package/out/zql/src/planner/planner-fan-in.js.map +1 -1
- package/out/zql/src/planner/planner-fan-out.js.map +1 -1
- package/out/zql/src/planner/planner-filter.js.map +1 -1
- package/out/zql/src/planner/planner-graph.js +1 -5
- package/out/zql/src/planner/planner-graph.js.map +1 -1
- package/out/zql/src/planner/planner-join.js +1 -1
- package/out/zql/src/planner/planner-join.js.map +1 -1
- package/out/zql/src/planner/planner-node.d.ts +0 -1
- package/out/zql/src/planner/planner-node.d.ts.map +1 -1
- package/out/zql/src/planner/planner-node.js.map +1 -1
- package/out/zql/src/planner/planner-source.js.map +1 -1
- package/out/zql/src/planner/planner-terminus.js.map +1 -1
- package/out/zql/src/planner/planner-warnings.d.ts +3 -3
- package/out/zql/src/planner/planner-warnings.d.ts.map +1 -1
- package/out/zql/src/planner/planner-warnings.js.map +1 -1
- package/out/zql/src/query/create-builder.js +2 -1
- package/out/zql/src/query/create-builder.js.map +1 -1
- package/out/zql/src/query/expression.d.ts +49 -24
- package/out/zql/src/query/expression.d.ts.map +1 -1
- package/out/zql/src/query/expression.js +62 -6
- package/out/zql/src/query/expression.js.map +1 -1
- package/out/zql/src/query/measure-push-operator.js +1 -1
- package/out/zql/src/query/measure-push-operator.js.map +1 -1
- package/out/zql/src/query/named.js +2 -1
- package/out/zql/src/query/named.js.map +1 -1
- package/out/zql/src/query/query-delegate-base.d.ts +8 -7
- package/out/zql/src/query/query-delegate-base.d.ts.map +1 -1
- package/out/zql/src/query/query-delegate-base.js +14 -6
- package/out/zql/src/query/query-delegate-base.js.map +1 -1
- package/out/zql/src/query/query-delegate.d.ts +1 -4
- package/out/zql/src/query/query-delegate.d.ts.map +1 -1
- package/out/zql/src/query/query-impl.d.ts +17 -3
- package/out/zql/src/query/query-impl.d.ts.map +1 -1
- package/out/zql/src/query/query-impl.js +242 -9
- package/out/zql/src/query/query-impl.js.map +1 -1
- package/out/zql/src/query/query-internals.d.ts +0 -3
- package/out/zql/src/query/query-internals.d.ts.map +1 -1
- package/out/zql/src/query/query-internals.js.map +1 -1
- package/out/zql/src/query/query-registry.d.ts +5 -5
- package/out/zql/src/query/query-registry.d.ts.map +1 -1
- package/out/zql/src/query/query-registry.js +1 -1
- package/out/zql/src/query/query-registry.js.map +1 -1
- package/out/zql/src/query/query-transitions.js +1 -1
- package/out/zql/src/query/query-transitions.js.map +1 -1
- package/out/zql/src/query/query.d.ts +321 -20
- package/out/zql/src/query/query.d.ts.map +1 -1
- package/out/zql/src/query/runnable-query-impl.d.ts +1 -19
- package/out/zql/src/query/runnable-query-impl.d.ts.map +1 -1
- package/out/zql/src/query/runnable-query-impl.js +2 -1
- package/out/zql/src/query/runnable-query-impl.js.map +1 -1
- package/out/zql/src/query/static-query.js.map +1 -1
- package/out/zql/src/query/ttl.d.ts +2 -3
- package/out/zql/src/query/ttl.d.ts.map +1 -1
- package/out/zql/src/query/ttl.js +8 -8
- package/out/zql/src/query/ttl.js.map +1 -1
- package/out/zql/src/query/validate-input.js.map +1 -1
- package/out/zqlite/src/database-storage.js +195 -26
- package/out/zqlite/src/database-storage.js.map +1 -1
- package/out/zqlite/src/db.d.ts +47 -1
- package/out/zqlite/src/db.d.ts.map +1 -1
- package/out/zqlite/src/db.js +121 -21
- package/out/zqlite/src/db.js.map +1 -1
- package/out/zqlite/src/explain-queries.js.map +1 -1
- package/out/zqlite/src/fetch-sql.d.ts +27 -0
- package/out/zqlite/src/fetch-sql.d.ts.map +1 -0
- package/out/zqlite/src/fetch-sql.js +112 -0
- package/out/zqlite/src/fetch-sql.js.map +1 -0
- package/out/zqlite/src/index-usage.js.map +1 -1
- package/out/zqlite/src/internal/sql-inline.js.map +1 -1
- package/out/zqlite/src/internal/sql.js.map +1 -1
- package/out/zqlite/src/internal/statement-cache.d.ts +7 -0
- package/out/zqlite/src/internal/statement-cache.d.ts.map +1 -1
- package/out/zqlite/src/internal/statement-cache.js +11 -4
- package/out/zqlite/src/internal/statement-cache.js.map +1 -1
- package/out/zqlite/src/mod.js +5 -5
- package/out/zqlite/src/pending-delta.d.ts.map +1 -1
- package/out/zqlite/src/pending-delta.js +4 -3
- package/out/zqlite/src/pending-delta.js.map +1 -1
- package/out/zqlite/src/query-builder.d.ts +23 -4
- package/out/zqlite/src/query-builder.d.ts.map +1 -1
- package/out/zqlite/src/query-builder.js +135 -19
- package/out/zqlite/src/query-builder.js.map +1 -1
- package/out/zqlite/src/query-delegate.js.map +1 -1
- package/out/zqlite/src/resolve-scalar-subqueries.js +2 -5
- package/out/zqlite/src/resolve-scalar-subqueries.js.map +1 -1
- package/out/zqlite/src/sqlite-cost-model.js +3 -2
- package/out/zqlite/src/sqlite-cost-model.js.map +1 -1
- package/out/zqlite/src/sqlite-stat-fanout.js.map +1 -1
- package/out/zqlite/src/table-source.d.ts +20 -3
- package/out/zqlite/src/table-source.d.ts.map +1 -1
- package/out/zqlite/src/table-source.js +110 -42
- package/out/zqlite/src/table-source.js.map +1 -1
- package/package.json +39 -39
- package/out/analyze-query/src/bin-analyze.d.ts +0 -2
- package/out/analyze-query/src/bin-analyze.d.ts.map +0 -1
- package/out/analyze-query/src/bin-analyze.js +0 -283
- package/out/analyze-query/src/bin-analyze.js.map +0 -1
- package/out/otel/src/maybe-time.d.ts +0 -3
- package/out/otel/src/maybe-time.d.ts.map +0 -1
- package/out/otel/src/maybe-time.js +0 -15
- package/out/otel/src/maybe-time.js.map +0 -1
- package/out/shared/src/cache.d.ts +0 -22
- package/out/shared/src/cache.d.ts.map +0 -1
- package/out/shared/src/custom-key-map.d.ts +0 -26
- package/out/shared/src/custom-key-map.d.ts.map +0 -1
- package/out/shared/src/custom-key-set.d.ts +0 -25
- package/out/shared/src/custom-key-set.d.ts.map +0 -1
- package/out/shared/src/logging-test-utils.d.ts +0 -12
- package/out/shared/src/logging-test-utils.d.ts.map +0 -1
- package/out/shared/src/sorted-entries.d.ts +0 -2
- package/out/shared/src/sorted-entries.d.ts.map +0 -1
- package/out/zero/src/analyze-query.d.ts +0 -3
- package/out/zero/src/analyze-query.d.ts.map +0 -1
- package/out/zero/src/analyze-query.js +0 -3
- package/out/zero/src/server/change-streamer.d.ts +0 -2
- package/out/zero/src/server/change-streamer.d.ts.map +0 -1
- package/out/zero/src/server/main.d.ts +0 -2
- package/out/zero/src/server/main.d.ts.map +0 -1
- package/out/zero/src/server/reaper.d.ts +0 -2
- package/out/zero/src/server/reaper.d.ts.map +0 -1
- package/out/zero/src/server/replicator.d.ts +0 -2
- package/out/zero/src/server/replicator.d.ts.map +0 -1
- package/out/zero/src/server/syncer.d.ts +0 -2
- package/out/zero/src/server/syncer.d.ts.map +0 -1
- package/out/zero-cache/src/auth/jwt.d.ts +0 -12
- package/out/zero-cache/src/auth/jwt.d.ts.map +0 -1
- package/out/zero-cache/src/auth/load-permissions.d.ts +0 -17
- package/out/zero-cache/src/auth/load-permissions.d.ts.map +0 -1
- package/out/zero-cache/src/auth/write-authorizer.d.ts +0 -28
- package/out/zero-cache/src/auth/write-authorizer.d.ts.map +0 -1
- package/out/zero-cache/src/config/server-context.d.ts +0 -16
- package/out/zero-cache/src/config/server-context.d.ts.map +0 -1
- package/out/zero-cache/src/custom/fetch.d.ts +0 -38
- package/out/zero-cache/src/custom/fetch.d.ts.map +0 -1
- package/out/zero-cache/src/custom/metrics.d.ts +0 -31
- package/out/zero-cache/src/custom/metrics.d.ts.map +0 -1
- package/out/zero-cache/src/custom-queries/transform-query.d.ts +0 -68
- package/out/zero-cache/src/custom-queries/transform-query.d.ts.map +0 -1
- package/out/zero-cache/src/db/create.d.ts +0 -12
- package/out/zero-cache/src/db/create.d.ts.map +0 -1
- package/out/zero-cache/src/db/delete-lite-db.d.ts +0 -2
- package/out/zero-cache/src/db/delete-lite-db.d.ts.map +0 -1
- package/out/zero-cache/src/db/index-predicate.d.ts +0 -4
- package/out/zero-cache/src/db/index-predicate.d.ts.map +0 -1
- package/out/zero-cache/src/db/migration-lite.d.ts +0 -78
- package/out/zero-cache/src/db/migration-lite.d.ts.map +0 -1
- package/out/zero-cache/src/db/migration.d.ts +0 -80
- package/out/zero-cache/src/db/migration.d.ts.map +0 -1
- package/out/zero-cache/src/db/pg-copy-binary.d.ts +0 -101
- package/out/zero-cache/src/db/pg-copy-binary.d.ts.map +0 -1
- package/out/zero-cache/src/db/pg-copy.d.ts +0 -30
- package/out/zero-cache/src/db/pg-copy.d.ts.map +0 -1
- package/out/zero-cache/src/db/pg-type-parser.d.ts +0 -15
- package/out/zero-cache/src/db/pg-type-parser.d.ts.map +0 -1
- package/out/zero-cache/src/db/transaction-pool.d.ts +0 -205
- package/out/zero-cache/src/db/transaction-pool.d.ts.map +0 -1
- package/out/zero-cache/src/db/warmup.d.ts +0 -4
- package/out/zero-cache/src/db/warmup.d.ts.map +0 -1
- package/out/zero-cache/src/observability/events.d.ts +0 -15
- package/out/zero-cache/src/observability/events.d.ts.map +0 -1
- package/out/zero-cache/src/observability/log-throttle.d.ts +0 -44
- package/out/zero-cache/src/observability/log-throttle.d.ts.map +0 -1
- package/out/zero-cache/src/server/anonymous-otel-start.d.ts +0 -21
- package/out/zero-cache/src/server/anonymous-otel-start.d.ts.map +0 -1
- package/out/zero-cache/src/server/change-streamer.d.ts +0 -3
- package/out/zero-cache/src/server/change-streamer.d.ts.map +0 -1
- package/out/zero-cache/src/server/inspector-delegate.d.ts +0 -71
- package/out/zero-cache/src/server/inspector-delegate.d.ts.map +0 -1
- package/out/zero-cache/src/server/main.d.ts +0 -3
- package/out/zero-cache/src/server/main.d.ts.map +0 -1
- package/out/zero-cache/src/server/otel-diag-logger.d.ts +0 -16
- package/out/zero-cache/src/server/otel-diag-logger.d.ts.map +0 -1
- package/out/zero-cache/src/server/otel-start.d.ts +0 -3
- package/out/zero-cache/src/server/otel-start.d.ts.map +0 -1
- package/out/zero-cache/src/server/priority-op.d.ts +0 -8
- package/out/zero-cache/src/server/priority-op.d.ts.map +0 -1
- package/out/zero-cache/src/server/reaper.d.ts +0 -3
- package/out/zero-cache/src/server/reaper.d.ts.map +0 -1
- package/out/zero-cache/src/server/replicator.d.ts +0 -10
- package/out/zero-cache/src/server/replicator.d.ts.map +0 -1
- package/out/zero-cache/src/server/slot-keeper.d.ts +0 -26
- package/out/zero-cache/src/server/slot-keeper.d.ts.map +0 -1
- package/out/zero-cache/src/server/syncer.d.ts +0 -3
- package/out/zero-cache/src/server/syncer.d.ts.map +0 -1
- package/out/zero-cache/src/services/analyze.d.ts +0 -9
- package/out/zero-cache/src/services/analyze.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-source/change-source.d.ts +0 -32
- package/out/zero-cache/src/services/change-source/change-source.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-source/common/backfill-manager.d.ts +0 -57
- package/out/zero-cache/src/services/change-source/common/backfill-manager.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-source/common/change-stream-multiplexer.d.ts +0 -55
- package/out/zero-cache/src/services/change-source/common/change-stream-multiplexer.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-source/common/init-cleanup.d.ts +0 -24
- package/out/zero-cache/src/services/change-source/common/init-cleanup.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-source/common/replica-restore.d.ts +0 -115
- package/out/zero-cache/src/services/change-source/common/replica-restore.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-source/common/replica-schema.d.ts +0 -14
- package/out/zero-cache/src/services/change-source/common/replica-schema.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-source/custom/change-source.d.ts +0 -25
- package/out/zero-cache/src/services/change-source/custom/change-source.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-source/pg/backfill-metadata.d.ts +0 -14
- package/out/zero-cache/src/services/change-source/pg/backfill-metadata.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-source/pg/backfill-stream.d.ts +0 -36
- package/out/zero-cache/src/services/change-source/pg/backfill-stream.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-source/pg/change-source-init.d.ts +0 -65
- package/out/zero-cache/src/services/change-source/pg/change-source-init.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-source/pg/change-source.d.ts +0 -115
- package/out/zero-cache/src/services/change-source/pg/change-source.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-source/pg/initial-sync.d.ts +0 -155
- package/out/zero-cache/src/services/change-source/pg/initial-sync.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-source/pg/logical-replication/binary-reader.d.ts +0 -17
- package/out/zero-cache/src/services/change-source/pg/logical-replication/binary-reader.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-source/pg/logical-replication/pgoutput-parser.d.ts +0 -28
- package/out/zero-cache/src/services/change-source/pg/logical-replication/pgoutput-parser.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-source/pg/logical-replication/pgoutput.types.d.ts +0 -76
- package/out/zero-cache/src/services/change-source/pg/logical-replication/pgoutput.types.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-source/pg/logical-replication/stream.d.ts +0 -169
- package/out/zero-cache/src/services/change-source/pg/logical-replication/stream.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-source/pg/replication-slot-cleanup-monitor.d.ts +0 -16
- package/out/zero-cache/src/services/change-source/pg/replication-slot-cleanup-monitor.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-source/pg/replication-slot-health.d.ts +0 -15
- package/out/zero-cache/src/services/change-source/pg/replication-slot-health.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-source/pg/replication-slots.d.ts +0 -127
- package/out/zero-cache/src/services/change-source/pg/replication-slots.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-source/pg/schema/init.d.ts +0 -9
- package/out/zero-cache/src/services/change-source/pg/schema/init.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-source/protocol/backfill-progress.d.ts +0 -68
- package/out/zero-cache/src/services/change-source/protocol/backfill-progress.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/backfill-state-tracker.d.ts +0 -72
- package/out/zero-cache/src/services/change-streamer/backfill-state-tracker.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/backfill-state.d.ts +0 -50
- package/out/zero-cache/src/services/change-streamer/backfill-state.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/backup-cleanup-monitor-factory.d.ts +0 -14
- package/out/zero-cache/src/services/change-streamer/backup-cleanup-monitor-factory.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/backup-monitor.d.ts +0 -18
- package/out/zero-cache/src/services/change-streamer/backup-monitor.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/broadcast.d.ts +0 -98
- package/out/zero-cache/src/services/change-streamer/broadcast.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/change-log-codec.d.ts +0 -34
- package/out/zero-cache/src/services/change-streamer/change-log-codec.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/change-log-compare-digest.d.ts +0 -34
- package/out/zero-cache/src/services/change-streamer/change-log-compare-digest.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/change-log-initializer.d.ts +0 -158
- package/out/zero-cache/src/services/change-streamer/change-log-initializer.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/change-log-transaction-hash.d.ts +0 -19
- package/out/zero-cache/src/services/change-streamer/change-log-transaction-hash.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer-http.d.ts +0 -78
- package/out/zero-cache/src/services/change-streamer/change-streamer-http.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer-service.d.ts +0 -143
- package/out/zero-cache/src/services/change-streamer/change-streamer-service.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer.d.ts +0 -586
- package/out/zero-cache/src/services/change-streamer/change-streamer.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/drain-tracker.d.ts +0 -24
- package/out/zero-cache/src/services/change-streamer/drain-tracker.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/error-type-enum.d.ts +0 -15
- package/out/zero-cache/src/services/change-streamer/error-type-enum.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/forwarder.d.ts +0 -49
- package/out/zero-cache/src/services/change-streamer/forwarder.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/litestream-sync-requester.d.ts +0 -53
- package/out/zero-cache/src/services/change-streamer/litestream-sync-requester.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/litestream3-prometheus-poller.d.ts +0 -88
- package/out/zero-cache/src/services/change-streamer/litestream3-prometheus-poller.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/replica-poller.d.ts +0 -15
- package/out/zero-cache/src/services/change-streamer/replica-poller.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/restore-admission.d.ts +0 -243
- package/out/zero-cache/src/services/change-streamer/restore-admission.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/schema/init.d.ts +0 -6
- package/out/zero-cache/src/services/change-streamer/schema/init.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/schema/tables.d.ts +0 -152
- package/out/zero-cache/src/services/change-streamer/schema/tables.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/shard-sampling.d.ts +0 -11
- package/out/zero-cache/src/services/change-streamer/shard-sampling.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/snapshot-message.d.ts +0 -92
- package/out/zero-cache/src/services/change-streamer/snapshot-message.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/snapshot-reservations.d.ts +0 -36
- package/out/zero-cache/src/services/change-streamer/snapshot-reservations.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/snapshot.d.ts +0 -22
- package/out/zero-cache/src/services/change-streamer/snapshot.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-catchup.d.ts +0 -99
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-catchup.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-comparator.d.ts +0 -83
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-comparator.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-purge-scheduler.d.ts +0 -121
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-purge-scheduler.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-read-router.d.ts +0 -73
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-read-router.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-reader.d.ts +0 -62
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-reader.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-writer.d.ts +0 -114
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-writer.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/storer.d.ts +0 -276
- package/out/zero-cache/src/services/change-streamer/storer.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/subscribe.d.ts +0 -485
- package/out/zero-cache/src/services/change-streamer/subscribe.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/subscriber.d.ts +0 -194
- package/out/zero-cache/src/services/change-streamer/subscriber.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/upstream-acker.d.ts +0 -52
- package/out/zero-cache/src/services/change-streamer/upstream-acker.d.ts.map +0 -1
- package/out/zero-cache/src/services/limiter/sliding-window-limiter.d.ts +0 -57
- package/out/zero-cache/src/services/limiter/sliding-window-limiter.d.ts.map +0 -1
- package/out/zero-cache/src/services/litestream/commands.d.ts +0 -77
- package/out/zero-cache/src/services/litestream/commands.d.ts.map +0 -1
- package/out/zero-cache/src/services/litestream/litestream-controller.d.ts +0 -78
- package/out/zero-cache/src/services/litestream/litestream-controller.d.ts.map +0 -1
- package/out/zero-cache/src/services/litestream/metrics.d.ts +0 -31
- package/out/zero-cache/src/services/litestream/metrics.d.ts.map +0 -1
- package/out/zero-cache/src/services/litestream/restore-progress.d.ts +0 -24
- package/out/zero-cache/src/services/litestream/restore-progress.d.ts.map +0 -1
- package/out/zero-cache/src/services/mutagen/mutagen.d.ts +0 -40
- package/out/zero-cache/src/services/mutagen/mutagen.d.ts.map +0 -1
- package/out/zero-cache/src/services/mutagen/pusher.d.ts +0 -63
- package/out/zero-cache/src/services/mutagen/pusher.d.ts.map +0 -1
- package/out/zero-cache/src/services/replicator/change-log-db.d.ts +0 -368
- package/out/zero-cache/src/services/replicator/change-log-db.d.ts.map +0 -1
- package/out/zero-cache/src/services/replicator/change-log-stream-writer.d.ts +0 -56
- package/out/zero-cache/src/services/replicator/change-log-stream-writer.d.ts.map +0 -1
- package/out/zero-cache/src/services/replicator/change-processor.d.ts +0 -37
- package/out/zero-cache/src/services/replicator/change-processor.d.ts.map +0 -1
- package/out/zero-cache/src/services/replicator/drain-handler.d.ts +0 -82
- package/out/zero-cache/src/services/replicator/drain-handler.d.ts.map +0 -1
- package/out/zero-cache/src/services/replicator/incremental-sync.d.ts +0 -25
- package/out/zero-cache/src/services/replicator/incremental-sync.d.ts.map +0 -1
- package/out/zero-cache/src/services/replicator/notifier.d.ts +0 -9
- package/out/zero-cache/src/services/replicator/notifier.d.ts.map +0 -1
- package/out/zero-cache/src/services/replicator/replication-status.d.ts +0 -71
- package/out/zero-cache/src/services/replicator/replication-status.d.ts.map +0 -1
- package/out/zero-cache/src/services/replicator/replicator.d.ts +0 -86
- package/out/zero-cache/src/services/replicator/replicator.d.ts.map +0 -1
- package/out/zero-cache/src/services/replicator/reporter/recorder.d.ts +0 -55
- package/out/zero-cache/src/services/replicator/reporter/recorder.d.ts.map +0 -1
- package/out/zero-cache/src/services/replicator/sqlite-change-log-observability.d.ts +0 -132
- package/out/zero-cache/src/services/replicator/sqlite-change-log-observability.d.ts.map +0 -1
- package/out/zero-cache/src/services/replicator/sqlite-change-log-purger.d.ts +0 -120
- package/out/zero-cache/src/services/replicator/sqlite-change-log-purger.d.ts.map +0 -1
- package/out/zero-cache/src/services/replicator/write-worker-client.d.ts +0 -111
- package/out/zero-cache/src/services/replicator/write-worker-client.d.ts.map +0 -1
- package/out/zero-cache/src/services/run-ast.d.ts +0 -39
- package/out/zero-cache/src/services/run-ast.d.ts.map +0 -1
- package/out/zero-cache/src/services/runner.d.ts +0 -19
- package/out/zero-cache/src/services/runner.d.ts.map +0 -1
- package/out/zero-cache/src/services/view-syncer/active-users-gauge.d.ts +0 -17
- package/out/zero-cache/src/services/view-syncer/active-users-gauge.d.ts.map +0 -1
- package/out/zero-cache/src/services/view-syncer/advancement-metrics.d.ts +0 -26
- package/out/zero-cache/src/services/view-syncer/advancement-metrics.d.ts.map +0 -1
- package/out/zero-cache/src/services/view-syncer/batch-pacer.d.ts +0 -79
- package/out/zero-cache/src/services/view-syncer/batch-pacer.d.ts.map +0 -1
- package/out/zero-cache/src/services/view-syncer/client-handler.d.ts +0 -79
- package/out/zero-cache/src/services/view-syncer/client-handler.d.ts.map +0 -1
- package/out/zero-cache/src/services/view-syncer/client-schema.d.ts +0 -5
- package/out/zero-cache/src/services/view-syncer/client-schema.d.ts.map +0 -1
- package/out/zero-cache/src/services/view-syncer/connection-context-manager.d.ts +0 -184
- package/out/zero-cache/src/services/view-syncer/connection-context-manager.d.ts.map +0 -1
- package/out/zero-cache/src/services/view-syncer/cvr-purger.d.ts +0 -22
- package/out/zero-cache/src/services/view-syncer/cvr-purger.d.ts.map +0 -1
- package/out/zero-cache/src/services/view-syncer/cvr-store.d.ts +0 -128
- package/out/zero-cache/src/services/view-syncer/cvr-store.d.ts.map +0 -1
- package/out/zero-cache/src/services/view-syncer/cvr.d.ts +0 -294
- package/out/zero-cache/src/services/view-syncer/cvr.d.ts.map +0 -1
- package/out/zero-cache/src/services/view-syncer/deferred-writes-budget.d.ts +0 -81
- package/out/zero-cache/src/services/view-syncer/deferred-writes-budget.d.ts.map +0 -1
- package/out/zero-cache/src/services/view-syncer/drain-coordinator.d.ts +0 -45
- package/out/zero-cache/src/services/view-syncer/drain-coordinator.d.ts.map +0 -1
- package/out/zero-cache/src/services/view-syncer/e2e-serving-lag.d.ts +0 -53
- package/out/zero-cache/src/services/view-syncer/e2e-serving-lag.d.ts.map +0 -1
- package/out/zero-cache/src/services/view-syncer/hydration-budget.d.ts +0 -33
- package/out/zero-cache/src/services/view-syncer/hydration-budget.d.ts.map +0 -1
- package/out/zero-cache/src/services/view-syncer/hydration-circuit-breaker.d.ts +0 -51
- package/out/zero-cache/src/services/view-syncer/hydration-circuit-breaker.d.ts.map +0 -1
- package/out/zero-cache/src/services/view-syncer/inspect-handler.d.ts +0 -34
- package/out/zero-cache/src/services/view-syncer/inspect-handler.d.ts.map +0 -1
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts +0 -296
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts.map +0 -1
- package/out/zero-cache/src/services/view-syncer/plan-warnings.d.ts +0 -7
- package/out/zero-cache/src/services/view-syncer/plan-warnings.d.ts.map +0 -1
- package/out/zero-cache/src/services/view-syncer/push-cost.d.ts +0 -132
- package/out/zero-cache/src/services/view-syncer/push-cost.d.ts.map +0 -1
- package/out/zero-cache/src/services/view-syncer/push-cutoff.d.ts +0 -55
- package/out/zero-cache/src/services/view-syncer/push-cutoff.d.ts.map +0 -1
- package/out/zero-cache/src/services/view-syncer/query-covering.d.ts +0 -28
- package/out/zero-cache/src/services/view-syncer/query-covering.d.ts.map +0 -1
- package/out/zero-cache/src/services/view-syncer/query-shape.d.ts +0 -25
- package/out/zero-cache/src/services/view-syncer/query-shape.d.ts.map +0 -1
- package/out/zero-cache/src/services/view-syncer/query-stats.d.ts +0 -89
- package/out/zero-cache/src/services/view-syncer/query-stats.d.ts.map +0 -1
- package/out/zero-cache/src/services/view-syncer/row-record-cache.d.ts +0 -90
- package/out/zero-cache/src/services/view-syncer/row-record-cache.d.ts.map +0 -1
- package/out/zero-cache/src/services/view-syncer/row-set-signature.d.ts +0 -17
- package/out/zero-cache/src/services/view-syncer/row-set-signature.d.ts.map +0 -1
- package/out/zero-cache/src/services/view-syncer/schema/cvr.d.ts +0 -86
- package/out/zero-cache/src/services/view-syncer/schema/cvr.d.ts.map +0 -1
- package/out/zero-cache/src/services/view-syncer/schema/init.d.ts +0 -5
- package/out/zero-cache/src/services/view-syncer/schema/init.d.ts.map +0 -1
- package/out/zero-cache/src/services/view-syncer/schema/types.d.ts +0 -563
- package/out/zero-cache/src/services/view-syncer/schema/types.d.ts.map +0 -1
- package/out/zero-cache/src/services/view-syncer/snapshot-row-cache.d.ts +0 -95
- package/out/zero-cache/src/services/view-syncer/snapshot-row-cache.d.ts.map +0 -1
- package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts +0 -412
- package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts.map +0 -1
- package/out/zero-cache/src/services/view-syncer/tracer.d.ts +0 -2
- package/out/zero-cache/src/services/view-syncer/tracer.d.ts.map +0 -1
- package/out/zero-cache/src/services/view-syncer/ttl-clock.d.ts +0 -10
- package/out/zero-cache/src/services/view-syncer/ttl-clock.d.ts.map +0 -1
- package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts +0 -133
- package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts.map +0 -1
- package/out/zero-cache/src/types/pg-patch.d.ts +0 -21
- package/out/zero-cache/src/types/pg-patch.d.ts.map +0 -1
- package/out/zero-cache/src/types/pg-versions.d.ts +0 -3
- package/out/zero-cache/src/types/pg-versions.d.ts.map +0 -1
- package/out/zero-cache/src/workers/replicator.d.ts +0 -57
- package/out/zero-cache/src/workers/replicator.d.ts.map +0 -1
- package/out/zero-cache/src/workers/syncer-ws-message-handler.d.ts +0 -14
- package/out/zero-cache/src/workers/syncer-ws-message-handler.d.ts.map +0 -1
- package/out/zero-cache/src/workers/syncer.d.ts +0 -67
- package/out/zero-cache/src/workers/syncer.d.ts.map +0 -1
- package/out/zero-events/src/index.d.ts +0 -27
- package/out/zero-events/src/index.d.ts.map +0 -1
- package/out/zero-events/src/json.d.ts +0 -20
- package/out/zero-events/src/json.d.ts.map +0 -1
- package/out/zero-events/src/status.d.ts +0 -144
- package/out/zero-events/src/status.d.ts.map +0 -1
- package/out/zqlite/src/database-storage.d.ts +0 -24
- package/out/zqlite/src/database-storage.d.ts.map +0 -1
- package/out/zqlite/src/explain-queries.d.ts +0 -4
- package/out/zqlite/src/explain-queries.d.ts.map +0 -1
- package/out/zqlite/src/internal/sql-inline.d.ts +0 -13
- package/out/zqlite/src/internal/sql-inline.d.ts.map +0 -1
- package/out/zqlite/src/resolve-scalar-subqueries.d.ts +0 -72
- package/out/zqlite/src/resolve-scalar-subqueries.d.ts.map +0 -1
- package/out/zqlite/src/sqlite-cost-model.d.ts +0 -17
- package/out/zqlite/src/sqlite-cost-model.d.ts.map +0 -1
- package/out/zqlite/src/sqlite-stat-fanout.d.ts +0 -121
- package/out/zqlite/src/sqlite-stat-fanout.d.ts.map +0 -1
|
@@ -52,6 +52,6 @@ var current_exports = /* @__PURE__ */ __exportAll({
|
|
|
52
52
|
upstreamStatusMessageSchema: () => upstreamStatusMessageSchema
|
|
53
53
|
});
|
|
54
54
|
//#endregion
|
|
55
|
-
export { current_exports };
|
|
55
|
+
export { CHANGE_SOURCE_PATH, addColumnSchema, backfillCompletedSchema, backfillIDSchema, backfillProgressMarkSchema, backfillRequestSchema, backfillSchema, beginSchema, changeSourceUpstreamSchema, changeStreamControlSchema, changeStreamDataSchema, changeStreamMessageSchema, commitSchema, createIndexSchema, createTableSchema, current_exports, dataChangeSchema, deleteSchema, downloadStatusSchema, downstreamStatusMessageSchema, downstreamStatusSchema, dropColumnSchema, dropIndexSchema, dropTableSchema, identifierSchema, insertSchema, isDataChange, isSchemaChange, jsonObjectSchema, jsonValueSchema, newRelationSchema, relationSchema, renameTableSchema, resetRequiredSchema, rollbackSchema, rowSchema, schemaChangeSchema, tableMetadataSchema, truncateSchema, updateColumnSchema, updateSchema, updateTableMetadataSchema, upstreamStatusMessageSchema };
|
|
56
56
|
|
|
57
57
|
//# sourceMappingURL=current.js.map
|
|
@@ -1,2 +1 @@
|
|
|
1
|
-
|
|
2
|
-
export {};
|
|
1
|
+
export { current_exports as v0 } from "./current.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"backfill-state-tracker.js","names":["#lc","#subscribers","#restarts","#unexpectedIgnores","#restartReason","#logBackfills","#sessionBackfills","#checkCoverage"],"sources":["../../../../../../zero-cache/src/services/change-streamer/backfill-state-tracker.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {must} from '../../../../shared/src/must.ts';\nimport {getOrCreateCounter} from '../../observability/metrics.ts';\nimport type {Subscription} from '../../types/subscription.ts';\nimport {\n getSuperset,\n withResumePoint,\n} from '../change-source/protocol/backfill-progress.ts';\nimport type {ChangeStreamData} from '../change-source/protocol/current/downstream.ts';\nimport type {BackfillRequest} from '../change-source/protocol/current/upstream.ts';\nimport {BackfillState} from './backfill-state.ts';\nimport type {PreSerializedBatch} from './broadcast.ts';\nimport type {SubscriberContext} from './change-streamer.ts';\nimport type {Subscriber, SubscriberOptions} from './subscriber.ts';\n\nexport type SubscriberBackfillOptions = Pick<\n SubscriberOptions,\n 'backfills' | 'onAligned' | 'onBackfillIgnored'\n>;\n\n/**\n * Tracks the pending backfills (and their progress) of the change log, the\n * subscribers, and the current change stream, in order to determine:\n *\n * * the BackfillRequests with which to start a change stream, i.e. the\n * superset of the pending backfills of the change log and all aligned\n * subscribers, starting from the earliest progress, and\n * * whether (and why) the change stream must be restarted, i.e. when a\n * newly aligned subscriber's pending backfills are not covered by the\n * current stream.\n *\n * The change-streamer calls {@link startStream()} whenever it starts a change\n * stream, {@link track()} for every change that it forwards, and restarts\n * the stream at the next transaction boundary whenever a\n * {@link restartReason} is set.\n */\nexport class BackfillStateTracker {\n readonly #lc: LogContext;\n\n /**\n * The pending backfills of the change log itself, i.e. those of a\n * (hypothetical) subscriber that has applied every change in the log.\n * Whenever a stream is started, it is reset from the change log's cookie\n * jar (which is consistent with the stream's starting watermark), carrying\n * over the progress tracked in memory (as the cookie jar is\n * progress-agnostic). It stands in for subscribers that do not report their\n * pending backfills (i.e. protocol < v8), and ensures that backfills that\n * are pending in the change log continue to be requested.\n */\n #logBackfills = new BackfillState();\n\n /**\n * The backfill progress of the current change stream (i.e. \"session\"),\n * seeded from the BackfillRequests with which the stream was started.\n * This determines whether a (newly aligned) subscriber's pending backfills\n * are covered by the stream.\n */\n #sessionBackfills = new BackfillState();\n\n /** Subscribers that report their pending backfills (protocol v8+). */\n readonly #subscribers = new Set<Subscriber>();\n\n /**\n * Set (to the reason) when the change stream must be restarted with\n * new BackfillRequests.\n */\n #restartReason: string | null = null;\n\n readonly #restarts = getOrCreateCounter(\n 'replication',\n 'backfill_stream_restarts',\n 'Count of change stream restarts initiated to rewind backfills for ' +\n 'subscribers whose pending backfills were not covered by the stream',\n );\n readonly #unexpectedIgnores = getOrCreateCounter(\n 'replication',\n 'backfill_unexpected_ignores',\n 'Count of backfill messages unexpectedly ignored (for some columns) by ' +\n 'an aligned subscriber. The expected count is 0.',\n );\n\n constructor(lc: LogContext) {\n this.#lc = lc;\n }\n\n /**\n * The reason for which the change stream must be restarted, or `null` if\n * it need not be. The restart should happen at the next transaction\n * boundary, i.e. upon the next `commit`, or `status` message outside of a\n * transaction.\n */\n get restartReason(): string | null {\n return this.#restartReason;\n }\n\n /**\n * Computes the BackfillRequests with which to start a new change stream:\n * the superset of the pending backfills of the change log and of all\n * aligned subscribers, all of which are consistent with the stream's\n * starting watermark since streams are (re)started at transaction\n * boundaries.\n *\n * @param logBackfillRequests The BackfillRequests from the change log's\n * cookie jar, consistent with the stream's starting watermark.\n */\n startStream(logBackfillRequests: BackfillRequest[]): BackfillRequest[] {\n // The cookie jar can be behind #logBackfills (e.g. if the storer failed\n // to persist a forwarded commit), in which case the new stream\n // re-delivers those changes.\n this.#logBackfills = new BackfillState(\n this.#logBackfills.withProgress(logBackfillRequests),\n );\n\n const aligned = [...this.#subscribers].filter(s => s.aligned);\n const requests = getSuperset(\n this.#logBackfills.requests(),\n ...aligned.map(s => must(s.backfills).requests()),\n ).map(withResumePoint);\n\n this.#sessionBackfills = new BackfillState(requests);\n // Aligned subscribers are accounted for in the requests.\n this.#restartReason = null;\n if (requests.length) {\n this.#lc.info?.(\n `starting change stream with ${requests.length} backfill requests ` +\n `(from the change log and ${aligned.length} subscribers)`,\n {requests},\n );\n }\n return requests;\n }\n\n /**\n * Tracks a change that is forwarded to subscribers. This must be called\n * (synchronously) before the change is forwarded, so that the stream's\n * state is never ahead of that of aligned subscribers.\n */\n track(change: ChangeStreamData) {\n this.#sessionBackfills.apply(change);\n this.#logBackfills.apply(change);\n }\n\n /**\n * Requests a restart of the change stream (at the next transaction\n * boundary), e.g. to start it with BackfillRequests that it was not\n * started with.\n */\n requestRestart(reason: string) {\n this.#restartReason ??= reason;\n }\n\n /** Logs and records a (planned) restart for the {@link restartReason}. */\n recordRestart() {\n this.#lc.info?.(`restarting change stream: ${this.#restartReason}`);\n this.#restarts.add(1);\n }\n\n /**\n * Returns the backfill-related {@link SubscriberOptions} for a new\n * subscriber, which must subsequently be passed to {@link register()}.\n */\n subscriberOptions(\n lc: LogContext,\n ctx: SubscriberContext,\n ): SubscriberBackfillOptions {\n const backfills = newBackfillState(lc, ctx);\n if (!backfills) {\n return {};\n }\n return {\n backfills,\n onAligned: subscriber => {\n if (this.#subscribers.has(subscriber)) {\n this.#checkCoverage(subscriber);\n }\n },\n onBackfillIgnored: columns => {\n if (this.#restartReason === null) {\n lc.warn?.(\n `aligned subscriber ignored backfill data for ${columns.join(', ')}`,\n );\n this.#unexpectedIgnores.add(1);\n }\n },\n };\n }\n\n /**\n * Registers a subscriber (created with {@link subscriberOptions()}) until\n * its `downstream` is closed. This is a no-op for subscribers that do not\n * report their pending backfills.\n */\n register(\n subscriber: Subscriber,\n downstream: Subscription<string | PreSerializedBatch>,\n ) {\n if (subscriber.backfills) {\n this.#subscribers.add(subscriber);\n downstream.addCloseHandler(() => this.#subscribers.delete(subscriber));\n }\n }\n\n /**\n * Checks whether the pending backfills of a newly aligned subscriber are\n * covered by the current stream, requesting a restart of the stream if not.\n *\n * This can be checked as soon as the subscriber is aligned (even in the\n * middle of a transaction), since both the subscriber's and the stream's\n * BackfillStates compare their committed state, and the stream's state is\n * never updated with a change before the change is forwarded to (aligned)\n * subscribers. The restart itself happens at the next transaction boundary.\n */\n #checkCoverage(subscriber: Subscriber) {\n const uncovered = must(subscriber.backfills).uncovered(\n this.#sessionBackfills,\n );\n if (uncovered.length) {\n this.#restartReason ??=\n `subscriber ${subscriber.id} needs backfills that are not ` +\n `covered by the current stream: ${uncovered.join(', ')}`;\n }\n }\n}\n\nfunction newBackfillState(\n lc: LogContext,\n ctx: SubscriberContext,\n): BackfillState | undefined {\n if (ctx.backfills === undefined) {\n return undefined; // protocol < v8\n }\n try {\n return new BackfillState(ctx.backfills);\n } catch (e) {\n lc.warn?.(`invalid backfills from subscriber ${ctx.id}`, e);\n return undefined;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAoCA,IAAa,uBAAb,MAAkC;CAChC;;;;;;;;;;;CAYA,gBAAgB,IAAI,cAAc;;;;;;;CAQlC,oBAAoB,IAAI,cAAc;;CAGtC,+BAAwB,IAAI,IAAgB;;;;;CAM5C,iBAAgC;CAEhC,YAAqB,mBACnB,eACA,4BACA,sIAEF;CACA,qBAA8B,mBAC5B,eACA,+BACA,uHAEF;CAEA,YAAY,IAAgB;EAC1B,KAAKA,MAAM;CACb;;;;;;;CAQA,IAAI,gBAA+B;EACjC,OAAO,KAAKI;CACd;;;;;;;;;;;CAYA,YAAY,qBAA2D;EAIrE,KAAKC,gBAAgB,IAAI,cACvB,KAAKA,cAAc,aAAa,mBAAmB,CACrD;EAEA,MAAM,UAAU,CAAC,GAAG,KAAKJ,YAAY,EAAE,QAAO,MAAK,EAAE,OAAO;EAC5D,MAAM,WAAW,YACf,KAAKI,cAAc,SAAS,GAC5B,GAAG,QAAQ,KAAI,MAAK,KAAK,EAAE,SAAS,EAAE,SAAS,CAAC,CAClD,EAAE,IAAI,eAAe;EAErB,KAAKC,oBAAoB,IAAI,cAAc,QAAQ;EAEnD,KAAKF,iBAAiB;EACtB,IAAI,SAAS,QACX,KAAKJ,IAAI,OACP,+BAA+B,SAAS,OAAO,8CACjB,QAAQ,OAAO,gBAC7C,EAAC,SAAQ,CACX;EAEF,OAAO;CACT;;;;;;CAOA,MAAM,QAA0B;EAC9B,KAAKM,kBAAkB,MAAM,MAAM;EACnC,KAAKD,cAAc,MAAM,MAAM;CACjC;;;;;;CAOA,eAAe,QAAgB;EAC7B,KAAKD,mBAAmB;CAC1B;;CAGA,gBAAgB;EACd,KAAKJ,IAAI,OAAO,6BAA6B,KAAKI,gBAAgB;EAClE,KAAKF,UAAU,IAAI,CAAC;CACtB;;;;;CAMA,kBACE,IACA,KAC2B;EAC3B,MAAM,YAAY,iBAAiB,IAAI,GAAG;EAC1C,IAAI,CAAC,WACH,OAAO,CAAC;EAEV,OAAO;GACL;GACA,YAAW,eAAc;IACvB,IAAI,KAAKD,aAAa,IAAI,UAAU,GAClC,KAAKM,eAAe,UAAU;GAElC;GACA,oBAAmB,YAAW;IAC5B,IAAI,KAAKH,mBAAmB,MAAM;KAChC,GAAG,OACD,gDAAgD,QAAQ,KAAK,IAAI,GACnE;KACA,KAAKD,mBAAmB,IAAI,CAAC;IAC/B;GACF;EACF;CACF;;;;;;CAOA,SACE,YACA,YACA;EACA,IAAI,WAAW,WAAW;GACxB,KAAKF,aAAa,IAAI,UAAU;GAChC,WAAW,sBAAsB,KAAKA,aAAa,OAAO,UAAU,CAAC;EACvE;CACF;;;;;;;;;;;CAYA,eAAe,YAAwB;EACrC,MAAM,YAAY,KAAK,WAAW,SAAS,EAAE,UAC3C,KAAKK,iBACP;EACA,IAAI,UAAU,QACZ,KAAKF,mBACH,cAAc,WAAW,GAAG,+DACM,UAAU,KAAK,IAAI;CAE3D;AACF;AAEA,SAAS,iBACP,IACA,KAC2B;CAC3B,IAAI,IAAI,cAAc,KAAA,GACpB;CAEF,IAAI;EACF,OAAO,IAAI,cAAc,IAAI,SAAS;CACxC,SAAS,GAAG;EACV,GAAG,OAAO,qCAAqC,IAAI,MAAM,CAAC;EAC1D;CACF;AACF"}
|
|
1
|
+
{"version":3,"file":"backfill-state-tracker.js","names":[],"sources":["../../../../../../zero-cache/src/services/change-streamer/backfill-state-tracker.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {must} from '../../../../shared/src/must.ts';\nimport {getOrCreateCounter} from '../../observability/metrics.ts';\nimport type {Subscription} from '../../types/subscription.ts';\nimport {\n getSuperset,\n withResumePoint,\n} from '../change-source/protocol/backfill-progress.ts';\nimport type {ChangeStreamData} from '../change-source/protocol/current/downstream.ts';\nimport type {BackfillRequest} from '../change-source/protocol/current/upstream.ts';\nimport {BackfillState} from './backfill-state.ts';\nimport type {PreSerializedBatch} from './broadcast.ts';\nimport type {SubscriberContext} from './change-streamer.ts';\nimport type {Subscriber, SubscriberOptions} from './subscriber.ts';\n\nexport type SubscriberBackfillOptions = Pick<\n SubscriberOptions,\n 'backfills' | 'onAligned' | 'onBackfillIgnored'\n>;\n\n/**\n * Tracks the pending backfills (and their progress) of the change log, the\n * subscribers, and the current change stream, in order to determine:\n *\n * * the BackfillRequests with which to start a change stream, i.e. the\n * superset of the pending backfills of the change log and all aligned\n * subscribers, starting from the earliest progress, and\n * * whether (and why) the change stream must be restarted, i.e. when a\n * newly aligned subscriber's pending backfills are not covered by the\n * current stream.\n *\n * The change-streamer calls {@link startStream()} whenever it starts a change\n * stream, {@link track()} for every change that it forwards, and restarts\n * the stream at the next transaction boundary whenever a\n * {@link restartReason} is set.\n */\nexport class BackfillStateTracker {\n readonly #lc: LogContext;\n\n /**\n * The pending backfills of the change log itself, i.e. those of a\n * (hypothetical) subscriber that has applied every change in the log.\n * Whenever a stream is started, it is reset from the change log's cookie\n * jar (which is consistent with the stream's starting watermark), carrying\n * over the progress tracked in memory (as the cookie jar is\n * progress-agnostic). It stands in for subscribers that do not report their\n * pending backfills (i.e. protocol < v8), and ensures that backfills that\n * are pending in the change log continue to be requested.\n */\n #logBackfills = new BackfillState();\n\n /**\n * The backfill progress of the current change stream (i.e. \"session\"),\n * seeded from the BackfillRequests with which the stream was started.\n * This determines whether a (newly aligned) subscriber's pending backfills\n * are covered by the stream.\n */\n #sessionBackfills = new BackfillState();\n\n /** Subscribers that report their pending backfills (protocol v8+). */\n readonly #subscribers = new Set<Subscriber>();\n\n /**\n * Set (to the reason) when the change stream must be restarted with\n * new BackfillRequests.\n */\n #restartReason: string | null = null;\n\n readonly #restarts = getOrCreateCounter(\n 'replication',\n 'backfill_stream_restarts',\n 'Count of change stream restarts initiated to rewind backfills for ' +\n 'subscribers whose pending backfills were not covered by the stream',\n );\n readonly #unexpectedIgnores = getOrCreateCounter(\n 'replication',\n 'backfill_unexpected_ignores',\n 'Count of backfill messages unexpectedly ignored (for some columns) by ' +\n 'an aligned subscriber. The expected count is 0.',\n );\n\n constructor(lc: LogContext) {\n this.#lc = lc;\n }\n\n /**\n * The reason for which the change stream must be restarted, or `null` if\n * it need not be. The restart should happen at the next transaction\n * boundary, i.e. upon the next `commit`, or `status` message outside of a\n * transaction.\n */\n get restartReason(): string | null {\n return this.#restartReason;\n }\n\n /**\n * Computes the BackfillRequests with which to start a new change stream:\n * the superset of the pending backfills of the change log and of all\n * aligned subscribers, all of which are consistent with the stream's\n * starting watermark since streams are (re)started at transaction\n * boundaries.\n *\n * @param logBackfillRequests The BackfillRequests from the change log's\n * cookie jar, consistent with the stream's starting watermark.\n */\n startStream(logBackfillRequests: BackfillRequest[]): BackfillRequest[] {\n // The cookie jar can be behind #logBackfills (e.g. if the storer failed\n // to persist a forwarded commit), in which case the new stream\n // re-delivers those changes.\n this.#logBackfills = new BackfillState(\n this.#logBackfills.withProgress(logBackfillRequests),\n );\n\n const aligned = [...this.#subscribers].filter(s => s.aligned);\n const requests = getSuperset(\n this.#logBackfills.requests(),\n ...aligned.map(s => must(s.backfills).requests()),\n ).map(withResumePoint);\n\n this.#sessionBackfills = new BackfillState(requests);\n // Aligned subscribers are accounted for in the requests.\n this.#restartReason = null;\n if (requests.length) {\n this.#lc.info?.(\n `starting change stream with ${requests.length} backfill requests ` +\n `(from the change log and ${aligned.length} subscribers)`,\n {requests},\n );\n }\n return requests;\n }\n\n /**\n * Tracks a change that is forwarded to subscribers. This must be called\n * (synchronously) before the change is forwarded, so that the stream's\n * state is never ahead of that of aligned subscribers.\n */\n track(change: ChangeStreamData) {\n this.#sessionBackfills.apply(change);\n this.#logBackfills.apply(change);\n }\n\n /**\n * Requests a restart of the change stream (at the next transaction\n * boundary), e.g. to start it with BackfillRequests that it was not\n * started with.\n */\n requestRestart(reason: string) {\n this.#restartReason ??= reason;\n }\n\n /** Logs and records a (planned) restart for the {@link restartReason}. */\n recordRestart() {\n this.#lc.info?.(`restarting change stream: ${this.#restartReason}`);\n this.#restarts.add(1);\n }\n\n /**\n * Returns the backfill-related {@link SubscriberOptions} for a new\n * subscriber, which must subsequently be passed to {@link register()}.\n */\n subscriberOptions(\n lc: LogContext,\n ctx: SubscriberContext,\n ): SubscriberBackfillOptions {\n const backfills = newBackfillState(lc, ctx);\n if (!backfills) {\n return {};\n }\n return {\n backfills,\n onAligned: subscriber => {\n if (this.#subscribers.has(subscriber)) {\n this.#checkCoverage(subscriber);\n }\n },\n onBackfillIgnored: columns => {\n if (this.#restartReason === null) {\n lc.warn?.(\n `aligned subscriber ignored backfill data for ${columns.join(', ')}`,\n );\n this.#unexpectedIgnores.add(1);\n }\n },\n };\n }\n\n /**\n * Registers a subscriber (created with {@link subscriberOptions()}) until\n * its `downstream` is closed. This is a no-op for subscribers that do not\n * report their pending backfills.\n */\n register(\n subscriber: Subscriber,\n downstream: Subscription<string | PreSerializedBatch>,\n ) {\n if (subscriber.backfills) {\n this.#subscribers.add(subscriber);\n downstream.addCloseHandler(() => this.#subscribers.delete(subscriber));\n }\n }\n\n /**\n * Checks whether the pending backfills of a newly aligned subscriber are\n * covered by the current stream, requesting a restart of the stream if not.\n *\n * This can be checked as soon as the subscriber is aligned (even in the\n * middle of a transaction), since both the subscriber's and the stream's\n * BackfillStates compare their committed state, and the stream's state is\n * never updated with a change before the change is forwarded to (aligned)\n * subscribers. The restart itself happens at the next transaction boundary.\n */\n #checkCoverage(subscriber: Subscriber) {\n const uncovered = must(subscriber.backfills).uncovered(\n this.#sessionBackfills,\n );\n if (uncovered.length) {\n this.#restartReason ??=\n `subscriber ${subscriber.id} needs backfills that are not ` +\n `covered by the current stream: ${uncovered.join(', ')}`;\n }\n }\n}\n\nfunction newBackfillState(\n lc: LogContext,\n ctx: SubscriberContext,\n): BackfillState | undefined {\n if (ctx.backfills === undefined) {\n return undefined; // protocol < v8\n }\n try {\n return new BackfillState(ctx.backfills);\n } catch (e) {\n lc.warn?.(`invalid backfills from subscriber ${ctx.id}`, e);\n return undefined;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAoCA,IAAa,uBAAb,MAAkC;CAChC;;;;;;;;;;;CAYA,gBAAgB,IAAI,cAAc;;;;;;;CAQlC,oBAAoB,IAAI,cAAc;;CAGtC,+BAAwB,IAAI,IAAgB;;;;;CAM5C,iBAAgC;CAEhC,YAAqB,mBACnB,eACA,4BACA,sIAEF;CACA,qBAA8B,mBAC5B,eACA,+BACA,uHAEF;CAEA,YAAY,IAAgB;EAC1B,KAAK,MAAM;CACb;;;;;;;CAQA,IAAI,gBAA+B;EACjC,OAAO,KAAK;CACd;;;;;;;;;;;CAYA,YAAY,qBAA2D;EAIrE,KAAK,gBAAgB,IAAI,cACvB,KAAK,cAAc,aAAa,mBAAmB,CACrD;EAEA,MAAM,UAAU,CAAC,GAAG,KAAK,YAAY,CAAC,CAAC,QAAO,MAAK,EAAE,OAAO;EAC5D,MAAM,WAAW,YACf,KAAK,cAAc,SAAS,GAC5B,GAAG,QAAQ,KAAI,MAAK,KAAK,EAAE,SAAS,CAAC,CAAC,SAAS,CAAC,CAClD,CAAC,CAAC,IAAI,eAAe;EAErB,KAAK,oBAAoB,IAAI,cAAc,QAAQ;EAEnD,KAAK,iBAAiB;EACtB,IAAI,SAAS,QACX,KAAK,IAAI,OACP,+BAA+B,SAAS,OAAO,8CACjB,QAAQ,OAAO,gBAC7C,EAAC,SAAQ,CACX;EAEF,OAAO;CACT;;;;;;CAOA,MAAM,QAA0B;EAC9B,KAAK,kBAAkB,MAAM,MAAM;EACnC,KAAK,cAAc,MAAM,MAAM;CACjC;;;;;;CAOA,eAAe,QAAgB;EAC7B,KAAK,mBAAmB;CAC1B;;CAGA,gBAAgB;EACd,KAAK,IAAI,OAAO,6BAA6B,KAAK,gBAAgB;EAClE,KAAK,UAAU,IAAI,CAAC;CACtB;;;;;CAMA,kBACE,IACA,KAC2B;EAC3B,MAAM,YAAY,iBAAiB,IAAI,GAAG;EAC1C,IAAI,CAAC,WACH,OAAO,CAAC;EAEV,OAAO;GACL;GACA,YAAW,eAAc;IACvB,IAAI,KAAK,aAAa,IAAI,UAAU,GAClC,KAAK,eAAe,UAAU;GAElC;GACA,oBAAmB,YAAW;IAC5B,IAAI,KAAK,mBAAmB,MAAM;KAChC,GAAG,OACD,gDAAgD,QAAQ,KAAK,IAAI,GACnE;KACA,KAAK,mBAAmB,IAAI,CAAC;IAC/B;GACF;EACF;CACF;;;;;;CAOA,SACE,YACA,YACA;EACA,IAAI,WAAW,WAAW;GACxB,KAAK,aAAa,IAAI,UAAU;GAChC,WAAW,sBAAsB,KAAK,aAAa,OAAO,UAAU,CAAC;EACvE;CACF;;;;;;;;;;;CAYA,eAAe,YAAwB;EACrC,MAAM,YAAY,KAAK,WAAW,SAAS,CAAC,CAAC,UAC3C,KAAK,iBACP;EACA,IAAI,UAAU,QACZ,KAAK,mBACH,cAAc,WAAW,GAAG,+DACM,UAAU,KAAK,IAAI;CAE3D;AACF;AAEA,SAAS,iBACP,IACA,KAC2B;CAC3B,IAAI,IAAI,cAAc,KAAA,GACpB;CAEF,IAAI;EACF,OAAO,IAAI,cAAc,IAAI,SAAS;CACxC,SAAS,GAAG;EACV,GAAG,OAAO,qCAAqC,IAAI,MAAM,CAAC;EAC1D;CACF;AACF"}
|
|
@@ -18,7 +18,7 @@ function clone(state) {
|
|
|
18
18
|
* Tags of messages that affect the backfill state. Other messages need not be
|
|
19
19
|
* parsed.
|
|
20
20
|
*/
|
|
21
|
-
var RELEVANT_TAGS = new Set(["backfill", ...schemaChangeTags.filter((t) => t !== "create-index" && t !== "drop-index")]);
|
|
21
|
+
var RELEVANT_TAGS = /* @__PURE__ */ new Set(["backfill", ...schemaChangeTags.filter((t) => t !== "create-index" && t !== "drop-index")]);
|
|
22
22
|
var lastParsed;
|
|
23
23
|
function parse(json) {
|
|
24
24
|
if (lastParsed?.json !== json) lastParsed = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"backfill-state.js","names":["#state","#committed","#beforeTx","#begin","#commit","#rollback","#applyBackfill","#applySchemaChange"],"sources":["../../../../../../zero-cache/src/services/change-streamer/backfill-state.ts"],"sourcesContent":["import {unreachable} from '../../../../shared/src/asserts.ts';\nimport {BigIntJSON} from '../../../../shared/src/bigint-json.ts';\nimport {deepEqual} from '../../../../shared/src/json.ts';\nimport {\n acceptBackfill,\n covers,\n} from '../change-source/protocol/backfill-progress.ts';\nimport type {\n BackfillRequest,\n ChangeStreamData,\n Identifier,\n SchemaChange,\n TableMetadata,\n} from '../change-source/protocol/current.ts';\nimport {schemaChangeTags} from '../change-source/protocol/current/schema-change-tags.ts';\nimport {cookieOps} from '../replicator/change-log-cookies.ts';\nimport type {ChangeTag, WatermarkedChange} from './change-streamer.ts';\n\nfunction tableKey({schema, name}: Identifier) {\n return JSON.stringify([schema, name]);\n}\n\ntype Column = BackfillRequest['columns'][string];\n\n/** A mutable BackfillRequest. */\ntype Backfill = {\n table: {schema: string; name: string; metadata: TableMetadata | null};\n columns: Record<string, Column>;\n};\n\ntype State = Map<string, Backfill>;\n\nfunction clone(state: State): State {\n return new Map(\n Array.from(state, ([key, {table, columns}]) => [\n key,\n {table: {...table}, columns: {...columns}},\n ]),\n );\n}\n\n/**\n * Tags of messages that affect the backfill state. Other messages need not be\n * parsed.\n */\nconst RELEVANT_TAGS = new Set<ChangeTag>([\n 'backfill',\n ...schemaChangeTags.filter(t => t !== 'create-index' && t !== 'drop-index'),\n]);\n\n// Serialized changes are typically forwarded (as the same string) to every\n// subscriber, so a single entry cache avoids re-parsing the same message for\n// each subscriber.\nlet lastParsed: {json: string; change: ChangeStreamData} | undefined;\n\nfunction parse(json: string): ChangeStreamData {\n if (lastParsed?.json !== json) {\n lastParsed = {json, change: BigIntJSON.parse(json) as ChangeStreamData};\n }\n return lastParsed.change;\n}\n\n/**\n * Tracks the state of the pending backfills (and their progress) of a party\n * in the replication stream (e.g. a subscriber, or the change-log itself), by\n * applying the same policies that a subscriber applies to its replica:\n * schema changes are folded with the {@link cookieOps} shared by the\n * cookie jars, and `backfill` / `backfill-completed` messages are accepted\n * or ignored with the continuity policy of {@link acceptBackfill}.\n *\n * Changes are applied transactionally: the changes of a transaction are\n * discarded if it is rolled back, and {@link requests()} only reflects\n * committed transactions.\n */\nexport class BackfillState {\n #state: State;\n #beforeTx: State | null = null;\n\n constructor(requests: readonly BackfillRequest[] = []) {\n this.#state = new Map(\n requests\n .filter(req => Object.keys(req.columns).length > 0)\n .map(({table, columns}) => [\n tableKey(table),\n {table: {...table}, columns: {...columns}},\n ]),\n );\n }\n\n get #committed(): State {\n return this.#beforeTx ?? this.#state;\n }\n\n /** The (committed) pending backfills. */\n requests(): BackfillRequest[] {\n return [...clone(this.#committed).values()];\n }\n\n /**\n * Returns the `requests` with the (committed) progress of this state\n * applied to the columns that are pending in both, i.e. same table, column,\n * and backfill ID. Other columns have no progress (i.e. from scratch).\n */\n withProgress(requests: readonly BackfillRequest[]): BackfillRequest[] {\n const state = this.#committed;\n return requests.map(({table, columns}) => {\n const tracked = state.get(tableKey(table))?.columns;\n return {\n table,\n columns: Object.fromEntries(\n Object.entries(columns).map(([name, {id}]) => {\n const col = tracked?.[name];\n return [\n name,\n col?.progress && deepEqual(col.id, id)\n ? {id, progress: col.progress}\n : {id},\n ];\n }),\n ),\n };\n });\n }\n\n /** Whether there are no (committed) pending backfills. */\n get empty(): boolean {\n return this.#committed.size === 0;\n }\n\n /**\n * Returns the columns (as `schema.table.column` strings) with (committed)\n * pending backfills that are not covered by the (committed) progress of the\n * `stream`, i.e. columns for which the `stream` will not deliver all of the\n * necessary data.\n */\n uncovered(stream: BackfillState): string[] {\n const uncovered: string[] = [];\n const streamState = stream.#committed;\n for (const [key, {table, columns}] of this.#committed) {\n const streamColumns = streamState.get(key)?.columns;\n for (const [name, {id, progress}] of Object.entries(columns)) {\n const s = streamColumns?.[name];\n if (!s || !deepEqual(s.id, id) || !covers(s.progress, progress)) {\n uncovered.push(`${table.schema}.${table.name}.${name}`);\n }\n }\n }\n return uncovered;\n }\n\n /**\n * Applies a serialized change, parsing it only if it is relevant.\n *\n * @returns The columns (as `schema.table.column` strings) of a backfill\n * message that were ignored due to the continuity policy.\n */\n applySerialized([, tag, json]: WatermarkedChange): string[] {\n switch (tag) {\n case 'begin':\n this.#begin();\n return [];\n case 'commit':\n this.#commit();\n return [];\n case 'rollback':\n this.#rollback();\n return [];\n }\n if (!RELEVANT_TAGS.has(tag)) {\n return [];\n }\n return this.apply(parse(json));\n }\n\n /**\n * Applies a change.\n *\n * @returns The columns (as `schema.table.column` strings) of a backfill\n * message that were ignored due to the continuity policy.\n */\n apply(change: ChangeStreamData): string[] {\n switch (change[0]) {\n case 'begin':\n this.#begin();\n return [];\n case 'commit':\n this.#commit();\n return [];\n case 'rollback':\n this.#rollback();\n return [];\n }\n const msg = change[1];\n switch (msg.tag) {\n case 'backfill': {\n const {relation, columns, progressMarks} = msg;\n return this.#applyBackfill(relation, columns, (progress, col) => {\n const result = acceptBackfill(progress, progressMarks);\n if (result.accept) {\n col.progress = result.progress;\n if (col.progress === undefined) {\n delete col.progress;\n }\n }\n return result.accept;\n });\n }\n case 'backfill-completed': {\n const {relation, columns, progressMarks} = msg;\n const backfill = this.#state.get(tableKey(relation));\n const ignored = this.#applyBackfill(\n relation,\n columns,\n (progress, _, name) => {\n const {accept} = acceptBackfill(\n progress,\n progressMarks && {previous: progressMarks.previous},\n );\n if (accept && backfill) {\n delete backfill.columns[name];\n }\n return accept;\n },\n );\n if (backfill && Object.keys(backfill.columns).length === 0) {\n this.#state.delete(tableKey(relation));\n }\n return ignored;\n }\n case 'create-table':\n case 'rename-table':\n case 'update-table-metadata':\n case 'add-column':\n case 'update-column':\n case 'drop-column':\n case 'drop-table':\n this.#applySchemaChange(msg);\n return [];\n }\n return [];\n }\n\n #applyBackfill(\n relation: {schema: string; name: string; rowKey: {columns: string[]}},\n columns: readonly string[],\n apply: (progress: Column['progress'], col: Column, name: string) => boolean,\n ): string[] {\n const backfill = this.#state.get(tableKey(relation));\n if (!backfill) {\n return [];\n }\n const ignored: string[] = [];\n // rowKey columns are excluded from `columns` but are backfilled with them\n // (e.g. for a new table).\n for (const name of [...relation.rowKey.columns, ...columns]) {\n const col = backfill.columns[name];\n if (!col) {\n continue;\n }\n // Copy-on-write, since the column object may be shared with the\n // pre-transaction state.\n const updated = {...col};\n if (apply(col.progress, updated, name)) {\n if (name in backfill.columns) {\n backfill.columns[name] = updated;\n }\n } else {\n ignored.push(`${relation.schema}.${relation.name}.${name}`);\n }\n }\n return ignored;\n }\n\n #applySchemaChange(change: SchemaChange) {\n // Table metadata specified in the same change (e.g. a `create-table` or\n // `add-column`), for backfills of tables that are not yet tracked.\n const metadata = new Map<string, TableMetadata>();\n\n for (const op of cookieOps(change)) {\n switch (op.op) {\n case 'upsert-metadata': {\n const key = tableKey(op.table);\n metadata.set(key, op.metadata);\n const backfill = this.#state.get(key);\n if (backfill) {\n backfill.table.metadata = op.metadata;\n }\n break;\n }\n case 'upsert-backfill': {\n const key = tableKey(op.table);\n let backfill = this.#state.get(key);\n if (!backfill) {\n backfill = {\n table: {\n schema: op.table.schema,\n name: op.table.name,\n metadata: metadata.get(key) ?? null,\n },\n columns: {},\n };\n this.#state.set(key, backfill);\n }\n // A new backfill always starts from scratch.\n backfill.columns[op.column] = {id: op.backfill};\n break;\n }\n case 'rename-table': {\n const backfill = this.#state.get(tableKey(op.old));\n if (backfill) {\n this.#state.delete(tableKey(op.old));\n backfill.table.schema = op.new.schema;\n backfill.table.name = op.new.name;\n this.#state.set(tableKey(op.new), backfill);\n }\n break;\n }\n case 'drop-table':\n this.#state.delete(tableKey(op.table));\n break;\n case 'rename-column': {\n const backfill = this.#state.get(tableKey(op.table));\n const col = backfill?.columns[op.old];\n if (backfill && col) {\n delete backfill.columns[op.old];\n backfill.columns[op.new] = col;\n }\n break;\n }\n case 'drop-column': {\n const key = tableKey(op.table);\n const backfill = this.#state.get(key);\n if (backfill) {\n delete backfill.columns[op.column];\n if (Object.keys(backfill.columns).length === 0) {\n this.#state.delete(key);\n }\n }\n break;\n }\n case 'complete-backfill':\n // Only produced for `backfill-completed`, which is handled\n // separately (with the continuity policy).\n throw new Error(`unexpected ${op.op} op`);\n default:\n unreachable(op);\n }\n }\n }\n\n #begin() {\n // Tolerate a missing commit/rollback, e.g. from an interrupted stream.\n this.#beforeTx ??= clone(this.#state);\n }\n\n #commit() {\n this.#beforeTx = null;\n }\n\n #rollback() {\n if (this.#beforeTx) {\n this.#state = this.#beforeTx;\n this.#beforeTx = null;\n }\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"backfill-state.js","names":[],"sources":["../../../../../../zero-cache/src/services/change-streamer/backfill-state.ts"],"sourcesContent":["import {unreachable} from '../../../../shared/src/asserts.ts';\nimport {BigIntJSON} from '../../../../shared/src/bigint-json.ts';\nimport {deepEqual} from '../../../../shared/src/json.ts';\nimport {\n acceptBackfill,\n covers,\n} from '../change-source/protocol/backfill-progress.ts';\nimport type {\n BackfillRequest,\n ChangeStreamData,\n Identifier,\n SchemaChange,\n TableMetadata,\n} from '../change-source/protocol/current.ts';\nimport {schemaChangeTags} from '../change-source/protocol/current/schema-change-tags.ts';\nimport {cookieOps} from '../replicator/change-log-cookies.ts';\nimport type {ChangeTag, WatermarkedChange} from './change-streamer.ts';\n\nfunction tableKey({schema, name}: Identifier) {\n return JSON.stringify([schema, name]);\n}\n\ntype Column = BackfillRequest['columns'][string];\n\n/** A mutable BackfillRequest. */\ntype Backfill = {\n table: {schema: string; name: string; metadata: TableMetadata | null};\n columns: Record<string, Column>;\n};\n\ntype State = Map<string, Backfill>;\n\nfunction clone(state: State): State {\n return new Map(\n Array.from(state, ([key, {table, columns}]) => [\n key,\n {table: {...table}, columns: {...columns}},\n ]),\n );\n}\n\n/**\n * Tags of messages that affect the backfill state. Other messages need not be\n * parsed.\n */\nconst RELEVANT_TAGS = new Set<ChangeTag>([\n 'backfill',\n ...schemaChangeTags.filter(t => t !== 'create-index' && t !== 'drop-index'),\n]);\n\n// Serialized changes are typically forwarded (as the same string) to every\n// subscriber, so a single entry cache avoids re-parsing the same message for\n// each subscriber.\nlet lastParsed: {json: string; change: ChangeStreamData} | undefined;\n\nfunction parse(json: string): ChangeStreamData {\n if (lastParsed?.json !== json) {\n lastParsed = {json, change: BigIntJSON.parse(json) as ChangeStreamData};\n }\n return lastParsed.change;\n}\n\n/**\n * Tracks the state of the pending backfills (and their progress) of a party\n * in the replication stream (e.g. a subscriber, or the change-log itself), by\n * applying the same policies that a subscriber applies to its replica:\n * schema changes are folded with the {@link cookieOps} shared by the\n * cookie jars, and `backfill` / `backfill-completed` messages are accepted\n * or ignored with the continuity policy of {@link acceptBackfill}.\n *\n * Changes are applied transactionally: the changes of a transaction are\n * discarded if it is rolled back, and {@link requests()} only reflects\n * committed transactions.\n */\nexport class BackfillState {\n #state: State;\n #beforeTx: State | null = null;\n\n constructor(requests: readonly BackfillRequest[] = []) {\n this.#state = new Map(\n requests\n .filter(req => Object.keys(req.columns).length > 0)\n .map(({table, columns}) => [\n tableKey(table),\n {table: {...table}, columns: {...columns}},\n ]),\n );\n }\n\n get #committed(): State {\n return this.#beforeTx ?? this.#state;\n }\n\n /** The (committed) pending backfills. */\n requests(): BackfillRequest[] {\n return [...clone(this.#committed).values()];\n }\n\n /**\n * Returns the `requests` with the (committed) progress of this state\n * applied to the columns that are pending in both, i.e. same table, column,\n * and backfill ID. Other columns have no progress (i.e. from scratch).\n */\n withProgress(requests: readonly BackfillRequest[]): BackfillRequest[] {\n const state = this.#committed;\n return requests.map(({table, columns}) => {\n const tracked = state.get(tableKey(table))?.columns;\n return {\n table,\n columns: Object.fromEntries(\n Object.entries(columns).map(([name, {id}]) => {\n const col = tracked?.[name];\n return [\n name,\n col?.progress && deepEqual(col.id, id)\n ? {id, progress: col.progress}\n : {id},\n ];\n }),\n ),\n };\n });\n }\n\n /** Whether there are no (committed) pending backfills. */\n get empty(): boolean {\n return this.#committed.size === 0;\n }\n\n /**\n * Returns the columns (as `schema.table.column` strings) with (committed)\n * pending backfills that are not covered by the (committed) progress of the\n * `stream`, i.e. columns for which the `stream` will not deliver all of the\n * necessary data.\n */\n uncovered(stream: BackfillState): string[] {\n const uncovered: string[] = [];\n const streamState = stream.#committed;\n for (const [key, {table, columns}] of this.#committed) {\n const streamColumns = streamState.get(key)?.columns;\n for (const [name, {id, progress}] of Object.entries(columns)) {\n const s = streamColumns?.[name];\n if (!s || !deepEqual(s.id, id) || !covers(s.progress, progress)) {\n uncovered.push(`${table.schema}.${table.name}.${name}`);\n }\n }\n }\n return uncovered;\n }\n\n /**\n * Applies a serialized change, parsing it only if it is relevant.\n *\n * @returns The columns (as `schema.table.column` strings) of a backfill\n * message that were ignored due to the continuity policy.\n */\n applySerialized([, tag, json]: WatermarkedChange): string[] {\n switch (tag) {\n case 'begin':\n this.#begin();\n return [];\n case 'commit':\n this.#commit();\n return [];\n case 'rollback':\n this.#rollback();\n return [];\n }\n if (!RELEVANT_TAGS.has(tag)) {\n return [];\n }\n return this.apply(parse(json));\n }\n\n /**\n * Applies a change.\n *\n * @returns The columns (as `schema.table.column` strings) of a backfill\n * message that were ignored due to the continuity policy.\n */\n apply(change: ChangeStreamData): string[] {\n switch (change[0]) {\n case 'begin':\n this.#begin();\n return [];\n case 'commit':\n this.#commit();\n return [];\n case 'rollback':\n this.#rollback();\n return [];\n }\n const msg = change[1];\n switch (msg.tag) {\n case 'backfill': {\n const {relation, columns, progressMarks} = msg;\n return this.#applyBackfill(relation, columns, (progress, col) => {\n const result = acceptBackfill(progress, progressMarks);\n if (result.accept) {\n col.progress = result.progress;\n if (col.progress === undefined) {\n delete col.progress;\n }\n }\n return result.accept;\n });\n }\n case 'backfill-completed': {\n const {relation, columns, progressMarks} = msg;\n const backfill = this.#state.get(tableKey(relation));\n const ignored = this.#applyBackfill(\n relation,\n columns,\n (progress, _, name) => {\n const {accept} = acceptBackfill(\n progress,\n progressMarks && {previous: progressMarks.previous},\n );\n if (accept && backfill) {\n delete backfill.columns[name];\n }\n return accept;\n },\n );\n if (backfill && Object.keys(backfill.columns).length === 0) {\n this.#state.delete(tableKey(relation));\n }\n return ignored;\n }\n case 'create-table':\n case 'rename-table':\n case 'update-table-metadata':\n case 'add-column':\n case 'update-column':\n case 'drop-column':\n case 'drop-table':\n this.#applySchemaChange(msg);\n return [];\n }\n return [];\n }\n\n #applyBackfill(\n relation: {schema: string; name: string; rowKey: {columns: string[]}},\n columns: readonly string[],\n apply: (progress: Column['progress'], col: Column, name: string) => boolean,\n ): string[] {\n const backfill = this.#state.get(tableKey(relation));\n if (!backfill) {\n return [];\n }\n const ignored: string[] = [];\n // rowKey columns are excluded from `columns` but are backfilled with them\n // (e.g. for a new table).\n for (const name of [...relation.rowKey.columns, ...columns]) {\n const col = backfill.columns[name];\n if (!col) {\n continue;\n }\n // Copy-on-write, since the column object may be shared with the\n // pre-transaction state.\n const updated = {...col};\n if (apply(col.progress, updated, name)) {\n if (name in backfill.columns) {\n backfill.columns[name] = updated;\n }\n } else {\n ignored.push(`${relation.schema}.${relation.name}.${name}`);\n }\n }\n return ignored;\n }\n\n #applySchemaChange(change: SchemaChange) {\n // Table metadata specified in the same change (e.g. a `create-table` or\n // `add-column`), for backfills of tables that are not yet tracked.\n const metadata = new Map<string, TableMetadata>();\n\n for (const op of cookieOps(change)) {\n switch (op.op) {\n case 'upsert-metadata': {\n const key = tableKey(op.table);\n metadata.set(key, op.metadata);\n const backfill = this.#state.get(key);\n if (backfill) {\n backfill.table.metadata = op.metadata;\n }\n break;\n }\n case 'upsert-backfill': {\n const key = tableKey(op.table);\n let backfill = this.#state.get(key);\n if (!backfill) {\n backfill = {\n table: {\n schema: op.table.schema,\n name: op.table.name,\n metadata: metadata.get(key) ?? null,\n },\n columns: {},\n };\n this.#state.set(key, backfill);\n }\n // A new backfill always starts from scratch.\n backfill.columns[op.column] = {id: op.backfill};\n break;\n }\n case 'rename-table': {\n const backfill = this.#state.get(tableKey(op.old));\n if (backfill) {\n this.#state.delete(tableKey(op.old));\n backfill.table.schema = op.new.schema;\n backfill.table.name = op.new.name;\n this.#state.set(tableKey(op.new), backfill);\n }\n break;\n }\n case 'drop-table':\n this.#state.delete(tableKey(op.table));\n break;\n case 'rename-column': {\n const backfill = this.#state.get(tableKey(op.table));\n const col = backfill?.columns[op.old];\n if (backfill && col) {\n delete backfill.columns[op.old];\n backfill.columns[op.new] = col;\n }\n break;\n }\n case 'drop-column': {\n const key = tableKey(op.table);\n const backfill = this.#state.get(key);\n if (backfill) {\n delete backfill.columns[op.column];\n if (Object.keys(backfill.columns).length === 0) {\n this.#state.delete(key);\n }\n }\n break;\n }\n case 'complete-backfill':\n // Only produced for `backfill-completed`, which is handled\n // separately (with the continuity policy).\n throw new Error(`unexpected ${op.op} op`);\n default:\n unreachable(op);\n }\n }\n }\n\n #begin() {\n // Tolerate a missing commit/rollback, e.g. from an interrupted stream.\n this.#beforeTx ??= clone(this.#state);\n }\n\n #commit() {\n this.#beforeTx = null;\n }\n\n #rollback() {\n if (this.#beforeTx) {\n this.#state = this.#beforeTx;\n this.#beforeTx = null;\n }\n }\n}\n"],"mappings":"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"}
|
|
@@ -4,17 +4,17 @@ import { LitestreamSyncRequester } from "./litestream-sync-requester.js";
|
|
|
4
4
|
import { Litestream3PrometheusPoller } from "./litestream3-prometheus-poller.js";
|
|
5
5
|
import { ReplicaPoller } from "./replica-poller.js";
|
|
6
6
|
//#region ../zero-cache/src/services/change-streamer/backup-cleanup-monitor-factory.ts
|
|
7
|
-
function createBackupCleanupMonitor({ lc, config, replicaFile,
|
|
7
|
+
function createBackupCleanupMonitor({ lc, config, replicaFile, verifyBackupState }) {
|
|
8
8
|
const { litestream, replica } = config;
|
|
9
9
|
const backupURL = backupDestinationURL(litestream);
|
|
10
|
-
let
|
|
11
|
-
if (!backupURL)
|
|
12
|
-
else if (config.litestream.backupUsingV5)
|
|
10
|
+
let poller;
|
|
11
|
+
if (!backupURL) poller = new ReplicaPoller(lc, replicaFile);
|
|
12
|
+
else if (config.litestream.backupUsingV5) poller = new LitestreamSyncRequester(lc, replicaFile, { intervalMs: litestream.incrementalBackupIntervalSeconds * 1e3 });
|
|
13
13
|
else {
|
|
14
14
|
const { port: metricsPort } = litestream;
|
|
15
|
-
|
|
15
|
+
poller = new Litestream3PrometheusPoller(lc, replicaFile, backupURL, `http://localhost:${metricsPort}/metrics`, verifyBackupState ?? (() => getLastBackupTime(lc, litestream, replica.file)));
|
|
16
16
|
}
|
|
17
|
-
return new BackupMonitor(lc,
|
|
17
|
+
return new BackupMonitor(lc, poller, replicaFile);
|
|
18
18
|
}
|
|
19
19
|
//#endregion
|
|
20
20
|
export { createBackupCleanupMonitor };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"backup-cleanup-monitor-factory.js","names":[],"sources":["../../../../../../zero-cache/src/services/change-streamer/backup-cleanup-monitor-factory.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport type {NormalizedZeroConfig} from '../../config/normalize.ts';\nimport
|
|
1
|
+
{"version":3,"file":"backup-cleanup-monitor-factory.js","names":[],"sources":["../../../../../../zero-cache/src/services/change-streamer/backup-cleanup-monitor-factory.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport type {NormalizedZeroConfig} from '../../config/normalize.ts';\nimport {\n backupDestinationURL,\n getLastBackupTime,\n} from '../litestream/commands.ts';\nimport {BackupMonitor, type BackupPoller} from './backup-monitor.ts';\nimport {LitestreamSyncRequester} from './litestream-sync-requester.ts';\nimport {\n type BackupStateVerifier,\n Litestream3PrometheusPoller,\n} from './litestream3-prometheus-poller.ts';\nimport {ReplicaPoller} from './replica-poller.ts';\n\nexport type BackupCleanupMonitorFactoryOptions = {\n lc: LogContext;\n config: NormalizedZeroConfig;\n replicaFile: string;\n verifyBackupState?: BackupStateVerifier | undefined;\n};\n\nexport function createBackupCleanupMonitor({\n lc,\n config,\n replicaFile,\n verifyBackupState,\n}: BackupCleanupMonitorFactoryOptions): BackupMonitor {\n const {litestream, replica} = config;\n const backupURL = backupDestinationURL(litestream);\n\n let poller: BackupPoller;\n\n if (!backupURL) {\n poller = new ReplicaPoller(lc, replicaFile);\n } else if (config.litestream.backupUsingV5) {\n poller = new LitestreamSyncRequester(lc, replicaFile, {\n intervalMs: litestream.incrementalBackupIntervalSeconds * 1000,\n });\n } else {\n const {port: metricsPort} = litestream;\n poller = new Litestream3PrometheusPoller(\n lc,\n replicaFile,\n backupURL,\n `http://localhost:${metricsPort}/metrics`,\n verifyBackupState ??\n (() => getLastBackupTime(lc, litestream, replica.file)),\n );\n }\n\n return new BackupMonitor(lc, poller, replicaFile);\n}\n"],"mappings":";;;;;;AAqBA,SAAgB,2BAA2B,EACzC,IACA,QACA,aACA,qBACoD;CACpD,MAAM,EAAC,YAAY,YAAW;CAC9B,MAAM,YAAY,qBAAqB,UAAU;CAEjD,IAAI;CAEJ,IAAI,CAAC,WACH,SAAS,IAAI,cAAc,IAAI,WAAW;MACrC,IAAI,OAAO,WAAW,eAC3B,SAAS,IAAI,wBAAwB,IAAI,aAAa,EACpD,YAAY,WAAW,mCAAmC,IAC5D,CAAC;MACI;EACL,MAAM,EAAC,MAAM,gBAAe;EAC5B,SAAS,IAAI,4BACX,IACA,aACA,WACA,oBAAoB,YAAY,WAChC,4BACS,kBAAkB,IAAI,YAAY,QAAQ,IAAI,EACzD;CACF;CAEA,OAAO,IAAI,cAAc,IAAI,QAAQ,WAAW;AAClD"}
|
|
@@ -1,15 +1,23 @@
|
|
|
1
1
|
import { promiseVoid } from "../../../../shared/src/resolved-promises.js";
|
|
2
|
+
import { resolver } from "../../../../shared/src/resolver.js";
|
|
2
3
|
import { Database } from "../../../../zqlite/src/db.js";
|
|
3
4
|
import { getOrCreateGauge } from "../../observability/metrics.js";
|
|
4
|
-
import {
|
|
5
|
+
import { Subscription } from "../../types/subscription.js";
|
|
5
6
|
//#region ../zero-cache/src/services/change-streamer/backup-monitor.ts
|
|
7
|
+
/**
|
|
8
|
+
* Relays the watermarks backed up by a {@link BackupPoller} to the
|
|
9
|
+
* change-streamer, which consumes them (see {@link backups}) and requests
|
|
10
|
+
* prompt backups (see {@link requestSync}) as needed.
|
|
11
|
+
*/
|
|
6
12
|
var BackupMonitor = class {
|
|
7
13
|
id = "backup-monitor";
|
|
8
14
|
#lc;
|
|
9
|
-
#
|
|
10
|
-
#changeStreamer;
|
|
15
|
+
#poller;
|
|
11
16
|
#replicaFile;
|
|
12
17
|
#firstBackupReceived = resolver();
|
|
18
|
+
#backups = Subscription.create({ coalesce: (curr) => curr });
|
|
19
|
+
#watermarks;
|
|
20
|
+
#stopped = false;
|
|
13
21
|
#latestBackup;
|
|
14
22
|
#firstBackupResolved = false;
|
|
15
23
|
/**
|
|
@@ -19,36 +27,61 @@ var BackupMonitor = class {
|
|
|
19
27
|
* "any watermark" rather than hanging startup forever.
|
|
20
28
|
*/
|
|
21
29
|
#coverageTarget;
|
|
22
|
-
constructor(lc,
|
|
30
|
+
constructor(lc, poller, replicaFile) {
|
|
23
31
|
this.#lc = lc;
|
|
24
|
-
this.#
|
|
25
|
-
this.#changeStreamer = changeStreamer;
|
|
32
|
+
this.#poller = poller;
|
|
26
33
|
this.#replicaFile = replicaFile;
|
|
27
34
|
}
|
|
28
35
|
firstBackupReceived() {
|
|
29
36
|
return this.#firstBackupReceived.promise;
|
|
30
37
|
}
|
|
38
|
+
/**
|
|
39
|
+
* The stream of backed-up watermarks, each later than the last, coalesced
|
|
40
|
+
* to the latest one that has not been consumed. It ends when the monitor
|
|
41
|
+
* stops.
|
|
42
|
+
*/
|
|
43
|
+
backups() {
|
|
44
|
+
return this.#backups;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Requests that the replica be backed up through `watermark` promptly, if
|
|
48
|
+
* the poller supports it (see {@link BackupPoller.requestSync}). A no-op
|
|
49
|
+
* unless the monitor is running.
|
|
50
|
+
*/
|
|
51
|
+
requestSync(watermark) {
|
|
52
|
+
if (!this.#watermarks || this.#stopped || this.#latestBackup && this.#latestBackup.watermark >= watermark) return;
|
|
53
|
+
if (this.#poller.requestSync) {
|
|
54
|
+
this.#lc.info?.(`requesting backup through ${watermark}`);
|
|
55
|
+
this.#poller.requestSync(watermark);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
31
58
|
async run() {
|
|
59
|
+
if (this.#stopped) return;
|
|
32
60
|
this.#lc.info?.("starting backup monitor");
|
|
33
61
|
this.#initBackupLagMetric();
|
|
34
62
|
this.#coverageTarget = this.#readReplicaStateVersion();
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
63
|
+
this.#watermarks = this.#poller.start();
|
|
64
|
+
try {
|
|
65
|
+
for await (const backedUp of this.#watermarks) {
|
|
66
|
+
if (this.#latestBackup) {
|
|
67
|
+
if (backedUp.watermark < this.#latestBackup.watermark) {
|
|
68
|
+
this.#lc.warn?.(`ignoring earlier backup watermark ${backedUp.watermark}`, { backedUp });
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
if (backedUp.watermark === this.#latestBackup.watermark) {
|
|
72
|
+
this.#lc.debug?.(`ignoring redundant backup watermark ${backedUp.watermark}`, { backedUp });
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
44
75
|
}
|
|
76
|
+
this.#lc.info?.(`received backup watermark ${backedUp.watermark}`, { backedUp });
|
|
77
|
+
this.#latestBackup = backedUp;
|
|
78
|
+
this.#backups.push(backedUp);
|
|
79
|
+
this.#checkFirstBackupCovers(backedUp);
|
|
45
80
|
}
|
|
46
|
-
this.#lc.info?.(
|
|
47
|
-
|
|
48
|
-
this.#
|
|
49
|
-
this.#checkFirstBackupCovers(backedUp);
|
|
81
|
+
this.#lc.info?.("watermark stream closed. BackupMonitor stopped.");
|
|
82
|
+
} finally {
|
|
83
|
+
this.#backups.cancel();
|
|
50
84
|
}
|
|
51
|
-
this.#lc.info?.("watermark stream closed. BackupMonitor stopped.");
|
|
52
85
|
}
|
|
53
86
|
/**
|
|
54
87
|
* Resolves {@link firstBackupReceived} once the backup actually covers the
|
|
@@ -90,7 +123,9 @@ var BackupMonitor = class {
|
|
|
90
123
|
}
|
|
91
124
|
}
|
|
92
125
|
stop() {
|
|
93
|
-
this.#
|
|
126
|
+
this.#stopped = true;
|
|
127
|
+
this.#watermarks?.cancel();
|
|
128
|
+
this.#backups.cancel();
|
|
94
129
|
return promiseVoid;
|
|
95
130
|
}
|
|
96
131
|
#initBackupLagMetric() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"backup-monitor.js","names":["#lc","#watermarks","#changeStreamer","#replicaFile","#firstBackupReceived","#initBackupLagMetric","#coverageTarget","#readReplicaStateVersion","#latestBackup","#checkFirstBackupCovers","#firstBackupResolved"],"sources":["../../../../../../zero-cache/src/services/change-streamer/backup-monitor.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {resolver} from '@rocicorp/resolver';\nimport {promiseVoid} from '../../../../shared/src/resolved-promises.ts';\nimport {Database} from '../../../../zqlite/src/db.ts';\nimport {getOrCreateGauge} from '../../observability/metrics.ts';\nimport type {Source} from '../../types/streams.ts';\nimport type {SingletonService} from '../service.ts';\nimport type {ChangeStreamerService} from './change-streamer.ts';\n\nexport type BackedUpWatermark = {\n watermark: string;\n writeTimeMs?: number | undefined; // optional for debugging; available on v5\n backupTimeMs: number;\n};\n\nexport class BackupMonitor implements SingletonService {\n readonly id = 'backup-monitor';\n readonly #lc: LogContext;\n readonly #watermarks: Source<BackedUpWatermark>;\n readonly #changeStreamer: ChangeStreamerService;\n readonly #replicaFile: string;\n readonly #firstBackupReceived = resolver();\n\n #latestBackup: BackedUpWatermark | undefined;\n #firstBackupResolved = false;\n /**\n * The replica's `stateVersion` when the monitor started, i.e. the point the\n * backup has to reach before it covers what this task is about to serve.\n * `undefined` when the replica could not be read, which degrades the gate to\n * \"any watermark\" rather than hanging startup forever.\n */\n #coverageTarget: string | undefined;\n\n constructor(\n lc: LogContext,\n watermarks: Source<BackedUpWatermark>,\n changeStreamer: ChangeStreamerService,\n replicaFile: string,\n ) {\n this.#lc = lc;\n this.#watermarks = watermarks;\n this.#changeStreamer = changeStreamer;\n this.#replicaFile = replicaFile;\n }\n\n firstBackupReceived() {\n return this.#firstBackupReceived.promise;\n }\n\n async run() {\n this.#lc.info?.('starting backup monitor');\n this.#initBackupLagMetric();\n this.#coverageTarget = this.#readReplicaStateVersion();\n\n for await (const backedUp of this.#watermarks) {\n if (this.#latestBackup) {\n if (backedUp.watermark < this.#latestBackup.watermark) {\n this.#lc.warn?.(\n `ignoring earlier backup watermark ${backedUp.watermark}`,\n {backedUp},\n );\n continue;\n }\n if (backedUp.watermark === this.#latestBackup.watermark) {\n this.#lc.debug?.(\n `ignoring redundant backup watermark ${backedUp.watermark}`,\n {backedUp},\n );\n continue;\n }\n }\n this.#lc.info?.(`received backup watermark ${backedUp.watermark}`, {\n backedUp,\n });\n this.#latestBackup = backedUp;\n this.#changeStreamer.trackBackupWatermark(backedUp.watermark);\n this.#checkFirstBackupCovers(backedUp);\n }\n this.#lc.info?.('watermark stream closed. BackupMonitor stopped.');\n }\n\n /**\n * Resolves {@link firstBackupReceived} once the backup actually covers the\n * replica, rather than on the first watermark of any value.\n *\n * A new backup destination starts empty and is filled by re-uploading the\n * local LTX chain, so the first watermarks read back out of it are real but\n * far behind the replica. Releasing the readiness gate on one of those lets\n * the task serve against a backup that does not yet cover it, which is what\n * demotes a restoring view-syncer to Postgres catchup.\n *\n * The target is pinned at startup rather than compared against the replica's\n * current position, which keeps the gate satisfiable under sustained writes.\n */\n #checkFirstBackupCovers(backedUp: BackedUpWatermark) {\n if (this.#firstBackupResolved) {\n return;\n }\n const target = this.#coverageTarget;\n if (target !== undefined && backedUp.watermark < target) {\n this.#lc.info?.(`backup does not yet cover the replica`, {\n backedUp,\n coverageTarget: target,\n });\n return;\n }\n this.#firstBackupResolved = true;\n this.#firstBackupReceived.resolve();\n }\n\n #readReplicaStateVersion(): string | undefined {\n let db;\n try {\n db = new Database(this.#lc, this.#replicaFile, {readonly: true});\n const {stateVersion} = db\n .prepare(/*sql*/ `SELECT stateVersion FROM \"_zero.replicationState\"`)\n .get<{stateVersion: string}>();\n return stateVersion;\n } catch (e) {\n // Without a target the gate degrades to its previous behavior. That is\n // strictly better than blocking startup on a replica we cannot read.\n this.#lc.warn?.(\n `unable to read the replica's stateVersion; ` +\n `the initial backup gate will accept the first watermark`,\n e,\n );\n return undefined;\n } finally {\n db?.close();\n }\n }\n\n stop(): Promise<void> {\n this.#watermarks.cancel();\n return promiseVoid;\n }\n\n #initBackupLagMetric() {\n getOrCreateGauge('replica', 'backup_lag', {\n description:\n 'Latency from when a change is written to the replica ' +\n 'to when it is backed up to litestream. It is expected to create a saw ' +\n 'pattern from 0 to the configured ZERO_LITESTREAM_INCREMENTAL_BACKUP_INTERVAL_MINUTES.',\n unit: 'millisecond',\n }).addCallback(o => {\n const latestBackup = this.#latestBackup;\n if (!latestBackup) {\n this.#lc.warn?.(\n `no backed up watermarks. unable to report replica.backup_lag`,\n );\n return;\n }\n const db = new Database(this.#lc, this.#replicaFile, {readonly: true});\n try {\n const {writeTimeMs} = db\n .prepare(/*sql*/ `SELECT writeTimeMs FROM \"_zero.replicationState\"`)\n .get<{writeTimeMs: number}>();\n const backupLag = Math.max(0, writeTimeMs - latestBackup.backupTimeMs);\n o.observe(backupLag);\n } catch (e) {\n this.#lc.warn?.(`error measuring replica.backup_lag metric`, e);\n } finally {\n db.close();\n }\n });\n }\n}\n"],"mappings":";;;;;AAeA,IAAa,gBAAb,MAAuD;CACrD,KAAc;CACd;CACA;CACA;CACA;CACA,uBAAgC,SAAS;CAEzC;CACA,uBAAuB;;;;;;;CAOvB;CAEA,YACE,IACA,YACA,gBACA,aACA;EACA,KAAKA,MAAM;EACX,KAAKC,cAAc;EACnB,KAAKC,kBAAkB;EACvB,KAAKC,eAAe;CACtB;CAEA,sBAAsB;EACpB,OAAO,KAAKC,qBAAqB;CACnC;CAEA,MAAM,MAAM;EACV,KAAKJ,IAAI,OAAO,yBAAyB;EACzC,KAAKK,qBAAqB;EAC1B,KAAKC,kBAAkB,KAAKC,yBAAyB;EAErD,WAAW,MAAM,YAAY,KAAKN,aAAa;GAC7C,IAAI,KAAKO,eAAe;IACtB,IAAI,SAAS,YAAY,KAAKA,cAAc,WAAW;KACrD,KAAKR,IAAI,OACP,qCAAqC,SAAS,aAC9C,EAAC,SAAQ,CACX;KACA;IACF;IACA,IAAI,SAAS,cAAc,KAAKQ,cAAc,WAAW;KACvD,KAAKR,IAAI,QACP,uCAAuC,SAAS,aAChD,EAAC,SAAQ,CACX;KACA;IACF;GACF;GACA,KAAKA,IAAI,OAAO,6BAA6B,SAAS,aAAa,EACjE,SACF,CAAC;GACD,KAAKQ,gBAAgB;GACrB,KAAKN,gBAAgB,qBAAqB,SAAS,SAAS;GAC5D,KAAKO,wBAAwB,QAAQ;EACvC;EACA,KAAKT,IAAI,OAAO,iDAAiD;CACnE;;;;;;;;;;;;;;CAeA,wBAAwB,UAA6B;EACnD,IAAI,KAAKU,sBACP;EAEF,MAAM,SAAS,KAAKJ;EACpB,IAAI,WAAW,KAAA,KAAa,SAAS,YAAY,QAAQ;GACvD,KAAKN,IAAI,OAAO,yCAAyC;IACvD;IACA,gBAAgB;GAClB,CAAC;GACD;EACF;EACA,KAAKU,uBAAuB;EAC5B,KAAKN,qBAAqB,QAAQ;CACpC;CAEA,2BAA+C;EAC7C,IAAI;EACJ,IAAI;GACF,KAAK,IAAI,SAAS,KAAKJ,KAAK,KAAKG,cAAc,EAAC,UAAU,KAAI,CAAC;GAC/D,MAAM,EAAC,iBAAgB,GACpB,QAAgB,mDAAmD,EACnE,IAA4B;GAC/B,OAAO;EACT,SAAS,GAAG;GAGV,KAAKH,IAAI,OACP,sGAEA,CACF;GACA;EACF,UAAU;GACR,IAAI,MAAM;EACZ;CACF;CAEA,OAAsB;EACpB,KAAKC,YAAY,OAAO;EACxB,OAAO;CACT;CAEA,uBAAuB;EACrB,iBAAiB,WAAW,cAAc;GACxC,aACE;GAGF,MAAM;EACR,CAAC,EAAE,aAAY,MAAK;GAClB,MAAM,eAAe,KAAKO;GAC1B,IAAI,CAAC,cAAc;IACjB,KAAKR,IAAI,OACP,8DACF;IACA;GACF;GACA,MAAM,KAAK,IAAI,SAAS,KAAKA,KAAK,KAAKG,cAAc,EAAC,UAAU,KAAI,CAAC;GACrE,IAAI;IACF,MAAM,EAAC,gBAAe,GACnB,QAAgB,kDAAkD,EAClE,IAA2B;IAC9B,MAAM,YAAY,KAAK,IAAI,GAAG,cAAc,aAAa,YAAY;IACrE,EAAE,QAAQ,SAAS;GACrB,SAAS,GAAG;IACV,KAAKH,IAAI,OAAO,6CAA6C,CAAC;GAChE,UAAU;IACR,GAAG,MAAM;GACX;EACF,CAAC;CACH;AACF"}
|
|
1
|
+
{"version":3,"file":"backup-monitor.js","names":[],"sources":["../../../../../../zero-cache/src/services/change-streamer/backup-monitor.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {promiseVoid} from '../../../../shared/src/resolved-promises.ts';\nimport {resolver} from '../../../../shared/src/resolver.ts';\nimport {Database} from '../../../../zqlite/src/db.ts';\nimport {getOrCreateGauge} from '../../observability/metrics.ts';\nimport type {Source} from '../../types/streams.ts';\nimport {Subscription} from '../../types/subscription.ts';\nimport type {SingletonService} from '../service.ts';\n\nexport type BackedUpWatermark = {\n watermark: string;\n writeTimeMs?: number | undefined; // optional for debugging; available on v5\n backupTimeMs: number;\n};\n\n/**\n * Determines which watermarks of the replica are backed up, by whatever means\n * the backup (or its absence) allows.\n */\nexport interface BackupPoller {\n /**\n * Starts polling, returning the stream of backed-up watermarks. Must only\n * be called once.\n */\n start(): Source<BackedUpWatermark>;\n\n /**\n * Requests that the replica be backed up through `watermark` promptly,\n * rather than at the poller's regular cadence, once the replica has reached\n * it. The resulting watermark is emitted on the stream as usual. Pollers\n * that cannot initiate backups do not implement this.\n */\n requestSync?(watermark: string): void;\n}\n\n/**\n * The interface through which the change-streamer consumes backed-up\n * watermarks and requests prompt backups (see {@link BackupMonitor}).\n */\nexport type BackupSource = Pick<BackupMonitor, 'backups' | 'requestSync'>;\n\n/**\n * Relays the watermarks backed up by a {@link BackupPoller} to the\n * change-streamer, which consumes them (see {@link backups}) and requests\n * prompt backups (see {@link requestSync}) as needed.\n */\nexport class BackupMonitor implements SingletonService {\n readonly id = 'backup-monitor';\n readonly #lc: LogContext;\n readonly #poller: BackupPoller;\n readonly #replicaFile: string;\n readonly #firstBackupReceived = resolver();\n // Backed-up watermarks only move forward, so the consumer only needs the\n // latest one. Coalescing keeps at most one outstanding, so that the monitor\n // neither waits on, nor queues for, the consumer.\n readonly #backups = Subscription.create<BackedUpWatermark>({\n coalesce: curr => curr,\n });\n\n #watermarks: Source<BackedUpWatermark> | undefined;\n #stopped = false;\n #latestBackup: BackedUpWatermark | undefined;\n #firstBackupResolved = false;\n /**\n * The replica's `stateVersion` when the monitor started, i.e. the point the\n * backup has to reach before it covers what this task is about to serve.\n * `undefined` when the replica could not be read, which degrades the gate to\n * \"any watermark\" rather than hanging startup forever.\n */\n #coverageTarget: string | undefined;\n\n constructor(lc: LogContext, poller: BackupPoller, replicaFile: string) {\n this.#lc = lc;\n this.#poller = poller;\n this.#replicaFile = replicaFile;\n }\n\n firstBackupReceived() {\n return this.#firstBackupReceived.promise;\n }\n\n /**\n * The stream of backed-up watermarks, each later than the last, coalesced\n * to the latest one that has not been consumed. It ends when the monitor\n * stops.\n */\n backups(): Source<BackedUpWatermark> {\n return this.#backups;\n }\n\n /**\n * Requests that the replica be backed up through `watermark` promptly, if\n * the poller supports it (see {@link BackupPoller.requestSync}). A no-op\n * unless the monitor is running.\n */\n requestSync(watermark: string) {\n if (\n !this.#watermarks ||\n this.#stopped ||\n (this.#latestBackup && this.#latestBackup.watermark >= watermark)\n ) {\n return;\n }\n if (this.#poller.requestSync) {\n this.#lc.info?.(`requesting backup through ${watermark}`);\n this.#poller.requestSync(watermark);\n }\n }\n\n async run() {\n if (this.#stopped) {\n return;\n }\n this.#lc.info?.('starting backup monitor');\n this.#initBackupLagMetric();\n this.#coverageTarget = this.#readReplicaStateVersion();\n\n this.#watermarks = this.#poller.start();\n try {\n for await (const backedUp of this.#watermarks) {\n if (this.#latestBackup) {\n if (backedUp.watermark < this.#latestBackup.watermark) {\n this.#lc.warn?.(\n `ignoring earlier backup watermark ${backedUp.watermark}`,\n {backedUp},\n );\n continue;\n }\n if (backedUp.watermark === this.#latestBackup.watermark) {\n this.#lc.debug?.(\n `ignoring redundant backup watermark ${backedUp.watermark}`,\n {backedUp},\n );\n continue;\n }\n }\n this.#lc.info?.(`received backup watermark ${backedUp.watermark}`, {\n backedUp,\n });\n this.#latestBackup = backedUp;\n this.#backups.push(backedUp);\n this.#checkFirstBackupCovers(backedUp);\n }\n this.#lc.info?.('watermark stream closed. BackupMonitor stopped.');\n } finally {\n this.#backups.cancel();\n }\n }\n\n /**\n * Resolves {@link firstBackupReceived} once the backup actually covers the\n * replica, rather than on the first watermark of any value.\n *\n * A new backup destination starts empty and is filled by re-uploading the\n * local LTX chain, so the first watermarks read back out of it are real but\n * far behind the replica. Releasing the readiness gate on one of those lets\n * the task serve against a backup that does not yet cover it, which is what\n * demotes a restoring view-syncer to Postgres catchup.\n *\n * The target is pinned at startup rather than compared against the replica's\n * current position, which keeps the gate satisfiable under sustained writes.\n */\n #checkFirstBackupCovers(backedUp: BackedUpWatermark) {\n if (this.#firstBackupResolved) {\n return;\n }\n const target = this.#coverageTarget;\n if (target !== undefined && backedUp.watermark < target) {\n this.#lc.info?.(`backup does not yet cover the replica`, {\n backedUp,\n coverageTarget: target,\n });\n return;\n }\n this.#firstBackupResolved = true;\n this.#firstBackupReceived.resolve();\n }\n\n #readReplicaStateVersion(): string | undefined {\n let db;\n try {\n db = new Database(this.#lc, this.#replicaFile, {readonly: true});\n const {stateVersion} = db\n .prepare(/*sql*/ `SELECT stateVersion FROM \"_zero.replicationState\"`)\n .get<{stateVersion: string}>();\n return stateVersion;\n } catch (e) {\n // Without a target the gate degrades to its previous behavior. That is\n // strictly better than blocking startup on a replica we cannot read.\n this.#lc.warn?.(\n `unable to read the replica's stateVersion; ` +\n `the initial backup gate will accept the first watermark`,\n e,\n );\n return undefined;\n } finally {\n db?.close();\n }\n }\n\n stop(): Promise<void> {\n this.#stopped = true;\n this.#watermarks?.cancel();\n this.#backups.cancel();\n return promiseVoid;\n }\n\n #initBackupLagMetric() {\n getOrCreateGauge('replica', 'backup_lag', {\n description:\n 'Latency from when a change is written to the replica ' +\n 'to when it is backed up to litestream. It is expected to create a saw ' +\n 'pattern from 0 to the configured ZERO_LITESTREAM_INCREMENTAL_BACKUP_INTERVAL_MINUTES.',\n unit: 'millisecond',\n }).addCallback(o => {\n const latestBackup = this.#latestBackup;\n if (!latestBackup) {\n this.#lc.warn?.(\n `no backed up watermarks. unable to report replica.backup_lag`,\n );\n return;\n }\n const db = new Database(this.#lc, this.#replicaFile, {readonly: true});\n try {\n const {writeTimeMs} = db\n .prepare(/*sql*/ `SELECT writeTimeMs FROM \"_zero.replicationState\"`)\n .get<{writeTimeMs: number}>();\n const backupLag = Math.max(0, writeTimeMs - latestBackup.backupTimeMs);\n o.observe(backupLag);\n } catch (e) {\n this.#lc.warn?.(`error measuring replica.backup_lag metric`, e);\n } finally {\n db.close();\n }\n });\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { resolver } from "../../../../shared/src/resolver.js";
|
|
1
2
|
import { must } from "../../../../shared/src/must.js";
|
|
2
3
|
import "../../types/streams.js";
|
|
3
|
-
import { resolver } from "@rocicorp/resolver";
|
|
4
4
|
//#region ../zero-cache/src/services/change-streamer/broadcast.ts
|
|
5
5
|
function preSerializeBatch(changes) {
|
|
6
6
|
const jsonList = changes.map((c) => c[2]);
|
|
@@ -182,6 +182,6 @@ function toBatch(change) {
|
|
|
182
182
|
return Array.isArray(change[0]) ? change : [change];
|
|
183
183
|
}
|
|
184
184
|
//#endregion
|
|
185
|
-
export { Broadcast };
|
|
185
|
+
export { Broadcast, preSerializeBatch };
|
|
186
186
|
|
|
187
187
|
//# sourceMappingURL=broadcast.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"broadcast.js","names":["#lc","#pending","#completed","#done","#watermark","#majority","#start","#earlyReleaseTimeoutProportion","#setTimeout","#clearTimeout","#needsBackupResponse","#markCompleted","#setDone","#isDone","#earlyReleaseTimer","#logWithState","#releaseMode"],"sources":["../../../../../../zero-cache/src/services/change-streamer/broadcast.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {resolver} from '@rocicorp/resolver';\nimport {must} from '../../../../shared/src/must.ts';\nimport {isPreSerialized, type PreSerialized} from '../../types/streams.ts';\nimport type {WatermarkedChange} from './change-streamer.ts';\nimport type {Subscriber} from './subscriber.ts';\n\nexport type BroadcastReleaseMode = 'all-subscribers' | 'consensus-timeout';\n\nexport type PreSerializedBatch = PreSerialized & {\n readonly changes: readonly WatermarkedChange[];\n};\n\nexport function isPreSerializedBatch(val: unknown): val is PreSerializedBatch {\n return isPreSerialized(val) && 'changes' in val && Array.isArray(val.changes);\n}\n\nexport function preSerializeBatch(\n changes: readonly WatermarkedChange[],\n): PreSerializedBatch {\n const jsonList = changes.map(c => c[2]);\n const joined = jsonList.join(',');\n const payload = Buffer.from(\n changes.length === 1 ? `,\"msg\":${jsonList[0]}}` : `,\"batch\":[${joined}]}`,\n 'utf8',\n );\n return {\n changes,\n payload,\n byteLength: payload.length,\n };\n}\n\n/**\n * Enables event-driven early release of a {@link Broadcast}. When provided and a\n * majority has acked, the broadcast schedules its own consensus-timeout release\n * proportional to how long the majority took to ack, instead of relying on the\n * Forwarder's periodic progress tick.\n */\nexport type EarlyReleaseOptions = {\n /** Time to wait, proportional to majority completion, before releasing. */\n consensusTimeoutProportion: number;\n /** Injectable timer, for deterministic testing. */\n setTimeoutFn?: typeof setTimeout;\n /** Injectable timer cancellation, for deterministic testing. */\n clearTimeoutFn?: typeof clearTimeout;\n};\n\n/**\n * Initiates and tracks the progress of a change broadcasted to\n * a set of subscribers, implementing **consensus-based timeouts**\n * to effect short-term graceful degradation when a minority of\n * subscribers are behind.\n *\n * ### Background\n *\n * The purpose of flow control is to pull upstream replication changes\n * no faster than the rate they are processed by downstream subscribers\n * in the steady state. In the change-streamer, this is done by occasionally\n * waiting for ACKs from subscribers before continuing; without doing so,\n * I/O buffers fill up and cause the system to spend most of its time in GC.\n *\n * However, the naive algorithm of always waiting for all subscribers (e.g.\n * `Promise.all()`) can behave poorly in scenarios where subscribers\n * are imbalanced:\n * * New subscribers may have a backlog of changes to catch up with.\n * Having all subscribers wait for the new subscriber to catch up results\n * in delaying the entire application.\n * * Broken TCP connections similarly require all subscribers to wait until\n * connection liveness checks kick in and disconnect the subscriber.\n *\n * A simplistic approach is to add a limit to the amount of time waiting for\n * subscribers, i.e. an ack timeout. However, deciding what this timeout\n * should be is non-trivial because of the heterogeneous nature of changes;\n * while most changes operate on single rows and are relatively predictable\n * in terms of running time, some changes are table-wide operations and can\n * legitimately take an arbitrary amount of time. In such scenarios, a\n * timeout that is too short can stop progress on replication altogether.\n *\n * ### Consensus-based Timeout Algorithm\n *\n * To address these shortcomings, a \"consensus-based timeout\" algorithm is\n * used:\n * * Wait for more than half of the subscribers to finish. (In\n * case of a single node, or the case of one replication-manager\n * and one view-syncer, this reduces to waiting for all subscribers.)\n * * Once more than half of the subscribers have finished, proceed after\n * the configured timeout, proportional to the time it took for the\n * majority of subscribers to ack, even if not all subscribers have\n * finished.\n *\n * In other words, the subscribers themselves are used to determine the\n * timeout of each batch of changes; the majority determines this when\n * they complete, upon which a timeout is logically started.\n *\n * In the common case, the remaining subscribers finish soon afterward and\n * the timeout never elapses. However, in pathological cases where a minority\n * of subscribers have a disproportionate amount of load, some will still\n * be processing (or otherwise unresponsive). These subscribers are given\n * a bounded amount of time to catch up at each flushed batch, up to the\n * timeout interval. This guarantees eventual catchup because the\n * subscribers with a backlog of changes necessarily have a higher\n * processing rate than the subscribers that finished (and are made to wait).\n */\nexport class Broadcast {\n /**\n * Sends the change to the subscribers without the tracking machinery.\n * This is suitable for fire-and-forget (i.e. pipelined) sends.\n */\n static withoutTracking(\n subscribers: Iterable<Subscriber>,\n change: WatermarkedChange | readonly WatermarkedChange[],\n ) {\n const changes = toBatch(change);\n const preSerialized = preSerializeBatch(changes);\n for (const sub of subscribers) {\n void sub.sendBatch(changes, preSerialized);\n }\n }\n\n readonly #lc: LogContext;\n readonly #pending: Set<Subscriber>;\n readonly #completed: Completed[];\n readonly #done = resolver();\n #isDone = false;\n #releaseMode: BroadcastReleaseMode | undefined;\n\n readonly #watermark: string;\n readonly #majority: number;\n\n readonly #start = performance.now();\n\n // When set, the broadcast schedules its own consensus-timeout release instead\n // of waiting for the Forwarder's periodic progress tick.\n readonly #earlyReleaseTimeoutProportion: number | undefined;\n readonly #setTimeout: typeof setTimeout;\n readonly #clearTimeout: typeof clearTimeout;\n #earlyReleaseTimer: ReturnType<typeof setTimeout> | undefined;\n\n // Tracks whether the backup-replicator responded. It is a required member\n // of the consensus timeout since it cannot be dropped as a laggard (since\n // that would shutdown the replication-manager itself).\n #needsBackupResponse = false;\n\n /**\n * Broadcasts the `change` to the `subscribers` and tracks their\n * completion.\n */\n constructor(\n lc: LogContext,\n subscribers: Iterable<Subscriber>,\n change: WatermarkedChange | readonly WatermarkedChange[],\n earlyRelease?: EarlyReleaseOptions,\n ) {\n const changes = toBatch(change);\n const preSerialized = preSerializeBatch(changes);\n this.#lc = lc;\n this.#pending = new Set(subscribers);\n this.#completed = [];\n this.#watermark = must(changes.at(-1))[0];\n this.#majority = Math.floor(this.#pending.size / 2) + 1;\n this.#earlyReleaseTimeoutProportion =\n earlyRelease?.consensusTimeoutProportion;\n this.#setTimeout = earlyRelease?.setTimeoutFn ?? setTimeout;\n this.#clearTimeout = earlyRelease?.clearTimeoutFn ?? clearTimeout;\n\n for (const sub of this.#pending) {\n const totalChanges = sub.numPending + changes.length;\n if (sub.mode === 'backup') {\n // Only gate consensus on the backup-replicator after it has finished\n // its initial catchup.\n this.#needsBackupResponse ||= !sub.isBacklogged();\n }\n void sub\n .sendBatch(changes, preSerialized)\n .catch(() => {})\n .finally(() => this.#markCompleted(sub, totalChanges));\n }\n\n // set done if there are no subscribers (mainly for tests)\n if (this.#pending.size === 0) {\n this.#setDone('all-subscribers');\n }\n }\n\n #markCompleted(sub: Subscriber, changes: number) {\n if (this.#isDone) {\n return;\n }\n const elapsed = performance.now() - this.#start;\n sub.trackResponseResult('on-time');\n if (sub.mode === 'backup') {\n this.#needsBackupResponse = false;\n }\n this.#completed.push({sub, changes, elapsed});\n this.#pending.delete(sub);\n if (this.#pending.size === 0) {\n this.#setDone('all-subscribers');\n return;\n }\n // Event-driven consensus-timeout: the moment a majority acks, and it\n // includes the backup-replicator, arm a single release timer\n // proportional to how long the majority took to ack. The broadcast\n // resolves when it fires, unless all subscribers ack first.\n if (\n this.#earlyReleaseTimeoutProportion !== undefined &&\n this.#earlyReleaseTimer === undefined &&\n this.#completed.length >= this.#majority &&\n !this.#needsBackupResponse\n ) {\n const timeoutMs = Math.ceil(\n elapsed * this.#earlyReleaseTimeoutProportion,\n );\n this.#earlyReleaseTimer = this.#setTimeout(\n () => this.#setDone('consensus-timeout'),\n timeoutMs,\n );\n }\n }\n\n #setDone(releaseMode: BroadcastReleaseMode) {\n if (this.#isDone) {\n return;\n }\n if (releaseMode === 'consensus-timeout') {\n const elapsed = performance.now() - this.#start;\n this.#logWithState(\n `continuing with ${this.#pending.size} subscriber(s) still pending`,\n elapsed,\n );\n }\n this.#pending.forEach(sub => sub.trackResponseResult('timed-out'));\n this.#isDone = true;\n this.#releaseMode = releaseMode;\n this.#clearTimeout(this.#earlyReleaseTimer);\n this.#earlyReleaseTimer = undefined;\n this.#done.resolve();\n }\n\n get isDone(): boolean {\n return this.#isDone;\n }\n\n get done(): Promise<void> {\n return this.#done.promise;\n }\n\n get releaseMode(): BroadcastReleaseMode {\n return this.#releaseMode ?? 'all-subscribers';\n }\n\n logSlowRequests(now: number) {\n if (this.#isDone || this.#pending.size === 0) {\n return;\n }\n const elapsed = now - this.#start;\n if (this.#completed.length < this.#majority) {\n if (elapsed >= 1000) {\n this.#logWithState(\n `waiting for at least ${this.#majority} subscribers to finish`,\n elapsed,\n );\n }\n }\n }\n\n #logWithState(msg: string, elapsed: number) {\n this.#lc\n .withContext('watermark', this.#watermark)\n .info?.(`${msg} (${elapsed.toFixed(3)} ms)`, {\n completed: this.#completed.map(d => ({\n id: d.sub.id,\n processed: d.changes,\n elapsed: d.elapsed,\n })),\n pending: Array.from(this.#pending, sub => ({\n id: sub.id,\n ...sub.getStats(),\n })),\n });\n }\n}\n\n/** Tracks the completed result of a single subscriber. */\ntype Completed = {\n sub: Subscriber;\n /** The number of changes processed. */\n changes: number;\n /** The elapsed milliseconds. */\n elapsed: number;\n};\n\nfunction toBatch(\n change: WatermarkedChange | readonly WatermarkedChange[],\n): readonly WatermarkedChange[] {\n if (change.length === 0) {\n return [];\n }\n return Array.isArray(change[0])\n ? (change as readonly WatermarkedChange[])\n : [change as WatermarkedChange];\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"broadcast.js","names":[],"sources":["../../../../../../zero-cache/src/services/change-streamer/broadcast.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {must} from '../../../../shared/src/must.ts';\nimport {resolver} from '../../../../shared/src/resolver.ts';\nimport {isPreSerialized, type PreSerialized} from '../../types/streams.ts';\nimport type {WatermarkedChange} from './change-streamer.ts';\nimport type {Subscriber} from './subscriber.ts';\n\nexport type BroadcastReleaseMode = 'all-subscribers' | 'consensus-timeout';\n\nexport type PreSerializedBatch = PreSerialized & {\n readonly changes: readonly WatermarkedChange[];\n};\n\nexport function isPreSerializedBatch(val: unknown): val is PreSerializedBatch {\n return isPreSerialized(val) && 'changes' in val && Array.isArray(val.changes);\n}\n\nexport function preSerializeBatch(\n changes: readonly WatermarkedChange[],\n): PreSerializedBatch {\n const jsonList = changes.map(c => c[2]);\n const joined = jsonList.join(',');\n const payload = Buffer.from(\n changes.length === 1 ? `,\"msg\":${jsonList[0]}}` : `,\"batch\":[${joined}]}`,\n 'utf8',\n );\n return {\n changes,\n payload,\n byteLength: payload.length,\n };\n}\n\n/**\n * Enables event-driven early release of a {@link Broadcast}. When provided and a\n * majority has acked, the broadcast schedules its own consensus-timeout release\n * proportional to how long the majority took to ack, instead of relying on the\n * Forwarder's periodic progress tick.\n */\nexport type EarlyReleaseOptions = {\n /** Time to wait, proportional to majority completion, before releasing. */\n consensusTimeoutProportion: number;\n /** Injectable timer, for deterministic testing. */\n setTimeoutFn?: typeof setTimeout;\n /** Injectable timer cancellation, for deterministic testing. */\n clearTimeoutFn?: typeof clearTimeout;\n};\n\n/**\n * Initiates and tracks the progress of a change broadcasted to\n * a set of subscribers, implementing **consensus-based timeouts**\n * to effect short-term graceful degradation when a minority of\n * subscribers are behind.\n *\n * ### Background\n *\n * The purpose of flow control is to pull upstream replication changes\n * no faster than the rate they are processed by downstream subscribers\n * in the steady state. In the change-streamer, this is done by occasionally\n * waiting for ACKs from subscribers before continuing; without doing so,\n * I/O buffers fill up and cause the system to spend most of its time in GC.\n *\n * However, the naive algorithm of always waiting for all subscribers (e.g.\n * `Promise.all()`) can behave poorly in scenarios where subscribers\n * are imbalanced:\n * * New subscribers may have a backlog of changes to catch up with.\n * Having all subscribers wait for the new subscriber to catch up results\n * in delaying the entire application.\n * * Broken TCP connections similarly require all subscribers to wait until\n * connection liveness checks kick in and disconnect the subscriber.\n *\n * A simplistic approach is to add a limit to the amount of time waiting for\n * subscribers, i.e. an ack timeout. However, deciding what this timeout\n * should be is non-trivial because of the heterogeneous nature of changes;\n * while most changes operate on single rows and are relatively predictable\n * in terms of running time, some changes are table-wide operations and can\n * legitimately take an arbitrary amount of time. In such scenarios, a\n * timeout that is too short can stop progress on replication altogether.\n *\n * ### Consensus-based Timeout Algorithm\n *\n * To address these shortcomings, a \"consensus-based timeout\" algorithm is\n * used:\n * * Wait for more than half of the subscribers to finish. (In\n * case of a single node, or the case of one replication-manager\n * and one view-syncer, this reduces to waiting for all subscribers.)\n * * Once more than half of the subscribers have finished, proceed after\n * the configured timeout, proportional to the time it took for the\n * majority of subscribers to ack, even if not all subscribers have\n * finished.\n *\n * In other words, the subscribers themselves are used to determine the\n * timeout of each batch of changes; the majority determines this when\n * they complete, upon which a timeout is logically started.\n *\n * In the common case, the remaining subscribers finish soon afterward and\n * the timeout never elapses. However, in pathological cases where a minority\n * of subscribers have a disproportionate amount of load, some will still\n * be processing (or otherwise unresponsive). These subscribers are given\n * a bounded amount of time to catch up at each flushed batch, up to the\n * timeout interval. This guarantees eventual catchup because the\n * subscribers with a backlog of changes necessarily have a higher\n * processing rate than the subscribers that finished (and are made to wait).\n */\nexport class Broadcast {\n /**\n * Sends the change to the subscribers without the tracking machinery.\n * This is suitable for fire-and-forget (i.e. pipelined) sends.\n */\n static withoutTracking(\n subscribers: Iterable<Subscriber>,\n change: WatermarkedChange | readonly WatermarkedChange[],\n ) {\n const changes = toBatch(change);\n const preSerialized = preSerializeBatch(changes);\n for (const sub of subscribers) {\n void sub.sendBatch(changes, preSerialized);\n }\n }\n\n readonly #lc: LogContext;\n readonly #pending: Set<Subscriber>;\n readonly #completed: Completed[];\n readonly #done = resolver();\n #isDone = false;\n #releaseMode: BroadcastReleaseMode | undefined;\n\n readonly #watermark: string;\n readonly #majority: number;\n\n readonly #start = performance.now();\n\n // When set, the broadcast schedules its own consensus-timeout release instead\n // of waiting for the Forwarder's periodic progress tick.\n readonly #earlyReleaseTimeoutProportion: number | undefined;\n readonly #setTimeout: typeof setTimeout;\n readonly #clearTimeout: typeof clearTimeout;\n #earlyReleaseTimer: ReturnType<typeof setTimeout> | undefined;\n\n // Tracks whether the backup-replicator responded. It is a required member\n // of the consensus timeout since it cannot be dropped as a laggard (since\n // that would shutdown the replication-manager itself).\n #needsBackupResponse = false;\n\n /**\n * Broadcasts the `change` to the `subscribers` and tracks their\n * completion.\n */\n constructor(\n lc: LogContext,\n subscribers: Iterable<Subscriber>,\n change: WatermarkedChange | readonly WatermarkedChange[],\n earlyRelease?: EarlyReleaseOptions,\n ) {\n const changes = toBatch(change);\n const preSerialized = preSerializeBatch(changes);\n this.#lc = lc;\n this.#pending = new Set(subscribers);\n this.#completed = [];\n this.#watermark = must(changes.at(-1))[0];\n this.#majority = Math.floor(this.#pending.size / 2) + 1;\n this.#earlyReleaseTimeoutProportion =\n earlyRelease?.consensusTimeoutProportion;\n this.#setTimeout = earlyRelease?.setTimeoutFn ?? setTimeout;\n this.#clearTimeout = earlyRelease?.clearTimeoutFn ?? clearTimeout;\n\n for (const sub of this.#pending) {\n const totalChanges = sub.numPending + changes.length;\n if (sub.mode === 'backup') {\n // Only gate consensus on the backup-replicator after it has finished\n // its initial catchup.\n this.#needsBackupResponse ||= !sub.isBacklogged();\n }\n void sub\n .sendBatch(changes, preSerialized)\n .catch(() => {})\n .finally(() => this.#markCompleted(sub, totalChanges));\n }\n\n // set done if there are no subscribers (mainly for tests)\n if (this.#pending.size === 0) {\n this.#setDone('all-subscribers');\n }\n }\n\n #markCompleted(sub: Subscriber, changes: number) {\n if (this.#isDone) {\n return;\n }\n const elapsed = performance.now() - this.#start;\n sub.trackResponseResult('on-time');\n if (sub.mode === 'backup') {\n this.#needsBackupResponse = false;\n }\n this.#completed.push({sub, changes, elapsed});\n this.#pending.delete(sub);\n if (this.#pending.size === 0) {\n this.#setDone('all-subscribers');\n return;\n }\n // Event-driven consensus-timeout: the moment a majority acks, and it\n // includes the backup-replicator, arm a single release timer\n // proportional to how long the majority took to ack. The broadcast\n // resolves when it fires, unless all subscribers ack first.\n if (\n this.#earlyReleaseTimeoutProportion !== undefined &&\n this.#earlyReleaseTimer === undefined &&\n this.#completed.length >= this.#majority &&\n !this.#needsBackupResponse\n ) {\n const timeoutMs = Math.ceil(\n elapsed * this.#earlyReleaseTimeoutProportion,\n );\n this.#earlyReleaseTimer = this.#setTimeout(\n () => this.#setDone('consensus-timeout'),\n timeoutMs,\n );\n }\n }\n\n #setDone(releaseMode: BroadcastReleaseMode) {\n if (this.#isDone) {\n return;\n }\n if (releaseMode === 'consensus-timeout') {\n const elapsed = performance.now() - this.#start;\n this.#logWithState(\n `continuing with ${this.#pending.size} subscriber(s) still pending`,\n elapsed,\n );\n }\n this.#pending.forEach(sub => sub.trackResponseResult('timed-out'));\n this.#isDone = true;\n this.#releaseMode = releaseMode;\n this.#clearTimeout(this.#earlyReleaseTimer);\n this.#earlyReleaseTimer = undefined;\n this.#done.resolve();\n }\n\n get isDone(): boolean {\n return this.#isDone;\n }\n\n get done(): Promise<void> {\n return this.#done.promise;\n }\n\n get releaseMode(): BroadcastReleaseMode {\n return this.#releaseMode ?? 'all-subscribers';\n }\n\n logSlowRequests(now: number) {\n if (this.#isDone || this.#pending.size === 0) {\n return;\n }\n const elapsed = now - this.#start;\n if (this.#completed.length < this.#majority) {\n if (elapsed >= 1000) {\n this.#logWithState(\n `waiting for at least ${this.#majority} subscribers to finish`,\n elapsed,\n );\n }\n }\n }\n\n #logWithState(msg: string, elapsed: number) {\n this.#lc\n .withContext('watermark', this.#watermark)\n .info?.(`${msg} (${elapsed.toFixed(3)} ms)`, {\n completed: this.#completed.map(d => ({\n id: d.sub.id,\n processed: d.changes,\n elapsed: d.elapsed,\n })),\n pending: Array.from(this.#pending, sub => ({\n id: sub.id,\n ...sub.getStats(),\n })),\n });\n }\n}\n\n/** Tracks the completed result of a single subscriber. */\ntype Completed = {\n sub: Subscriber;\n /** The number of changes processed. */\n changes: number;\n /** The elapsed milliseconds. */\n elapsed: number;\n};\n\nfunction toBatch(\n change: WatermarkedChange | readonly WatermarkedChange[],\n): readonly WatermarkedChange[] {\n if (change.length === 0) {\n return [];\n }\n return Array.isArray(change[0])\n ? (change as readonly WatermarkedChange[])\n : [change as WatermarkedChange];\n}\n"],"mappings":"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"}
|
|
@@ -38,9 +38,8 @@ function extractChangeSubstring(streamMessageJSON, tag) {
|
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
/** Reconstructs the canonical downstream JSON around a stored change. */
|
|
41
|
-
function reconstructWatermarkedChange(
|
|
42
|
-
const
|
|
43
|
-
const tag = entry.tag;
|
|
41
|
+
function reconstructWatermarkedChange(watermark, entryTag, change) {
|
|
42
|
+
const tag = entryTag;
|
|
44
43
|
switch (tag) {
|
|
45
44
|
case "begin": return [
|
|
46
45
|
watermark,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"change-log-codec.js","names":[],"sources":["../../../../../../zero-cache/src/services/change-streamer/change-log-codec.ts"],"sourcesContent":["import {BigIntJSON} from '../../../../shared/src/bigint-json.ts';\nimport type {ChangeStreamData} from '../change-source/protocol/current/downstream.ts';\nimport type {ChangeTag, WatermarkedChange} from './change-streamer.ts';\n\nexport type ChangeLogEntry = {\n watermark: string;\n tag: string;\n change: string;\n};\n\nexport type SerializedChangeStreamData = {\n /** The canonical downstream representation forwarded to subscribers. */\n readonly json: string;\n /** The already-serialized change tuple element stored in change logs. */\n readonly change: string;\n};\n\n/**\n * Serializes a data-plane message and its stored change payload in one pass.\n *\n * Change logs retain only the second tuple element for backwards\n * compatibility. Serializing that element first avoids stringifying the full\n * message and then copying the payload back out of the resulting string on the\n * replication hot path.\n */\nexport function serializeChangeStreamDataWithChange(\n data: ChangeStreamData,\n): SerializedChangeStreamData {\n const change = BigIntJSON.stringify(data[1]);\n const type = data[0];\n switch (type) {\n case 'begin':\n case 'commit':\n return {\n json: `[${JSON.stringify(type)},${change},${BigIntJSON.stringify(data[2])}]`,\n change,\n };\n case 'data':\n case 'rollback':\n return {json: `[${JSON.stringify(type)},${change}]`, change};\n }\n}\n\n/** Serializes a data-plane message to the canonical downstream JSON form. */\nexport function serializeChangeStreamData(data: ChangeStreamData): string {\n return serializeChangeStreamDataWithChange(data).json;\n}\n\n/**\n * Extracts the second tuple element for callers that only have the canonical\n * downstream JSON. The live write path uses\n * {@link serializeChangeStreamDataWithChange} and does not scan or copy the\n * completed message.\n */\nexport function extractChangeSubstring(\n streamMessageJSON: string,\n tag: ChangeTag | undefined,\n): string {\n switch (tag) {\n case 'begin':\n case 'commit':\n // e.g.\n // [\"begin\",<message-json>,{\"commitWatermark\":\"92fj2d0s\"}]\n // [\"commit\",<message-json>,{\"watermark\":\"92fj2d0s\"}]\n return streamMessageJSON.substring(\n streamMessageJSON.indexOf(',') + 1,\n streamMessageJSON.lastIndexOf(','),\n );\n default:\n // [\"data\",<message-json>]\n return streamMessageJSON.substring(\n streamMessageJSON.indexOf(',') + 1,\n streamMessageJSON.lastIndexOf(']'),\n );\n }\n}\n\n/** Reconstructs the canonical downstream JSON around a stored change. */\nexport function reconstructWatermarkedChange(\n
|
|
1
|
+
{"version":3,"file":"change-log-codec.js","names":[],"sources":["../../../../../../zero-cache/src/services/change-streamer/change-log-codec.ts"],"sourcesContent":["import {BigIntJSON} from '../../../../shared/src/bigint-json.ts';\nimport type {ChangeStreamData} from '../change-source/protocol/current/downstream.ts';\nimport type {ChangeTag, WatermarkedChange} from './change-streamer.ts';\n\nexport type ChangeLogEntry = {\n watermark: string;\n tag: string;\n change: string;\n};\n\nexport type SerializedChangeStreamData = {\n /** The canonical downstream representation forwarded to subscribers. */\n readonly json: string;\n /** The already-serialized change tuple element stored in change logs. */\n readonly change: string;\n};\n\n/**\n * Serializes a data-plane message and its stored change payload in one pass.\n *\n * Change logs retain only the second tuple element for backwards\n * compatibility. Serializing that element first avoids stringifying the full\n * message and then copying the payload back out of the resulting string on the\n * replication hot path.\n */\nexport function serializeChangeStreamDataWithChange(\n data: ChangeStreamData,\n): SerializedChangeStreamData {\n const change = BigIntJSON.stringify(data[1]);\n const type = data[0];\n switch (type) {\n case 'begin':\n case 'commit':\n return {\n json: `[${JSON.stringify(type)},${change},${BigIntJSON.stringify(data[2])}]`,\n change,\n };\n case 'data':\n case 'rollback':\n return {json: `[${JSON.stringify(type)},${change}]`, change};\n }\n}\n\n/** Serializes a data-plane message to the canonical downstream JSON form. */\nexport function serializeChangeStreamData(data: ChangeStreamData): string {\n return serializeChangeStreamDataWithChange(data).json;\n}\n\n/**\n * Extracts the second tuple element for callers that only have the canonical\n * downstream JSON. The live write path uses\n * {@link serializeChangeStreamDataWithChange} and does not scan or copy the\n * completed message.\n */\nexport function extractChangeSubstring(\n streamMessageJSON: string,\n tag: ChangeTag | undefined,\n): string {\n switch (tag) {\n case 'begin':\n case 'commit':\n // e.g.\n // [\"begin\",<message-json>,{\"commitWatermark\":\"92fj2d0s\"}]\n // [\"commit\",<message-json>,{\"watermark\":\"92fj2d0s\"}]\n return streamMessageJSON.substring(\n streamMessageJSON.indexOf(',') + 1,\n streamMessageJSON.lastIndexOf(','),\n );\n default:\n // [\"data\",<message-json>]\n return streamMessageJSON.substring(\n streamMessageJSON.indexOf(',') + 1,\n streamMessageJSON.lastIndexOf(']'),\n );\n }\n}\n\n/** Reconstructs the canonical downstream JSON around a stored change. */\nexport function reconstructWatermarkedChange(\n watermark: string,\n entryTag: string,\n change: string,\n): WatermarkedChange {\n const tag = entryTag as ChangeTag;\n switch (tag) {\n case 'begin':\n return [\n watermark,\n tag,\n `[\"begin\",${change},{\"commitWatermark\":\"${watermark}\"}]`,\n ];\n case 'commit':\n return [\n watermark,\n tag,\n `[\"commit\",${change},{\"watermark\":\"${watermark}\"}]`,\n ];\n case 'rollback':\n return [watermark, tag, `[\"rollback\",${change}]`];\n default:\n return [watermark, tag, `[\"data\",${change}]`];\n }\n}\n"],"mappings":";;;;;;;;;;AAyBA,SAAgB,oCACd,MAC4B;CAC5B,MAAM,SAAS,WAAW,UAAU,KAAK,EAAE;CAC3C,MAAM,OAAO,KAAK;CAClB,QAAQ,MAAR;EACE,KAAK;EACL,KAAK,UACH,OAAO;GACL,MAAM,IAAI,KAAK,UAAU,IAAI,EAAE,GAAG,OAAO,GAAG,WAAW,UAAU,KAAK,EAAE,EAAE;GAC1E;EACF;EACF,KAAK;EACL,KAAK,YACH,OAAO;GAAC,MAAM,IAAI,KAAK,UAAU,IAAI,EAAE,GAAG,OAAO;GAAI;EAAM;CAC/D;AACF;;;;;;;AAaA,SAAgB,uBACd,mBACA,KACQ;CACR,QAAQ,KAAR;EACE,KAAK;EACL,KAAK,UAIH,OAAO,kBAAkB,UACvB,kBAAkB,QAAQ,GAAG,IAAI,GACjC,kBAAkB,YAAY,GAAG,CACnC;EACF,SAEE,OAAO,kBAAkB,UACvB,kBAAkB,QAAQ,GAAG,IAAI,GACjC,kBAAkB,YAAY,GAAG,CACnC;CACJ;AACF;;AAGA,SAAgB,6BACd,WACA,UACA,QACmB;CACnB,MAAM,MAAM;CACZ,QAAQ,KAAR;EACE,KAAK,SACH,OAAO;GACL;GACA;GACA,YAAY,OAAO,uBAAuB,UAAU;EACtD;EACF,KAAK,UACH,OAAO;GACL;GACA;GACA,aAAa,OAAO,iBAAiB,UAAU;EACjD;EACF,KAAK,YACH,OAAO;GAAC;GAAW;GAAK,eAAe,OAAO;EAAE;EAClD,SACE,OAAO;GAAC;GAAW;GAAK,WAAW,OAAO;EAAE;CAChD;AACF"}
|
|
@@ -4,10 +4,10 @@ import { BigIntJSON } from "../../../../shared/src/bigint-json.js";
|
|
|
4
4
|
import { schemaChangeTags } from "../change-source/protocol/current/schema-change-tags.js";
|
|
5
5
|
import { Database } from "../../../../zqlite/src/db.js";
|
|
6
6
|
import { getOrCreateCounter } from "../../observability/metrics.js";
|
|
7
|
+
import { StatementRunner } from "../../db/statements.js";
|
|
7
8
|
import { backfillRequestsFrom, foldCookies } from "../replicator/change-log-cookies.js";
|
|
8
9
|
import { readBackfillRequests, readReplicaCookies } from "../replicator/schema/backfilling.js";
|
|
9
10
|
import { getReplicationState } from "../replicator/schema/replication-state.js";
|
|
10
|
-
import { StatementRunner } from "../../db/statements.js";
|
|
11
11
|
import { CHANGE_LOG_STREAM_TABLE } from "../replicator/change-log-db.js";
|
|
12
12
|
import { SQLITE_CHANGE_LOG_BOUNDARY_SQL } from "./sqlite-change-log-reader.js";
|
|
13
13
|
//#region ../zero-cache/src/services/change-streamer/change-log-initializer.ts
|
|
@@ -251,7 +251,7 @@ function readSchemaChanges(db, after, through) {
|
|
|
251
251
|
SELECT count(*) AS "rows" FROM (
|
|
252
252
|
SELECT 1 FROM "${CHANGE_LOG_STREAM_TABLE}"
|
|
253
253
|
WHERE "watermark" > ? AND "watermark" <= ?
|
|
254
|
-
LIMIT
|
|
254
|
+
LIMIT 10001
|
|
255
255
|
)
|
|
256
256
|
`).get(after, through);
|
|
257
257
|
if (rows > MAX_FOLD_SCAN_ROWS) return;
|
|
@@ -308,6 +308,6 @@ function sortKeys(value) {
|
|
|
308
308
|
return Object.fromEntries(Object.entries(value).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([k, v]) => [k, sortKeys(v)]));
|
|
309
309
|
}
|
|
310
310
|
//#endregion
|
|
311
|
-
export { ChangeLogInitializer, replicaInitializationSource };
|
|
311
|
+
export { ChangeLogInitializer, readReplicaInitializationParameters, replicaInitializationSource };
|
|
312
312
|
|
|
313
313
|
//# sourceMappingURL=change-log-initializer.js.map
|