@rocicorp/zero 1.12.0-canary.0 → 1.12.0-canary.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +4 -2
- 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 +162 -0
- package/out/analyze-query/src/zql-chain.js.map +1 -0
- 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.js +5 -7
- package/out/z2s/src/compiler.js.map +1 -1
- package/out/z2s/src/sql.d.ts +1 -5
- package/out/z2s/src/sql.d.ts.map +1 -1
- package/out/z2s/src/sql.js +1 -1
- 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/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 +15 -19
- 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 +19 -11
- package/out/zero-cache/src/config/zero-config.d.ts.map +1 -1
- package/out/zero-cache/src/config/zero-config.js +47 -10
- 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.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/decommission.js +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 +49 -16
- 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 +4 -3
- 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 +1 -1
- 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 +4 -4
- 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 +5 -4
- 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 +6 -4
- 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 +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 +10 -7
- 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 +8 -4
- 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 +85 -59
- 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 +2 -2
- package/out/zero-cache/src/services/http-service.d.ts.map +1 -1
- package/out/zero-cache/src/services/http-service.js +6 -4
- package/out/zero-cache/src/services/http-service.js.map +1 -1
- package/out/zero-cache/src/services/life-cycle.js +3 -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.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.d.ts.map +1 -1
- package/out/zero-cache/src/services/statz.js +5 -4
- 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 +13 -10
- 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.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 +12 -8
- 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 +1 -1
- 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.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 +5 -3
- 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 +30 -5
- 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.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.js.map +1 -1
- package/out/zero-client/src/client/crud-impl.js +1 -1
- 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.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.js +1 -3
- package/out/zero-client/src/client/ivm-branch.js.map +1 -1
- package/out/zero-client/src/client/keys.d.ts +0 -1
- package/out/zero-client/src/client/keys.d.ts.map +1 -1
- package/out/zero-client/src/client/keys.js +6 -3
- 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 +1 -1
- package/out/zero-client/src/client/zero-poke-handler.js.map +1 -1
- 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 +20 -12
- package/out/zero-client/src/client/zero.js.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/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 +0 -4
- package/out/zero-protocol/src/ast.d.ts.map +1 -1
- package/out/zero-protocol/src/ast.js +21 -11
- 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 +2 -2
- 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 +82 -84
- 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.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.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.js +2 -2
- 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.js +3 -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.js +7 -5
- 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 +1 -1
- 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.js +7 -7
- 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 +1 -1
- 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/name-mapper.d.ts +2 -1
- package/out/zero-types/src/name-mapper.d.ts.map +1 -1
- package/out/zero-types/src/name-mapper.js.map +1 -1
- package/out/zero-types/src/schema-value.d.ts +3 -2
- package/out/zero-types/src/schema-value.d.ts.map +1 -1
- package/out/zero-types/src/schema.d.ts +1 -1
- package/out/zero-types/src/schema.d.ts.map +1 -1
- package/out/zql/src/builder/builder.d.ts +1 -11
- package/out/zql/src/builder/builder.d.ts.map +1 -1
- package/out/zql/src/builder/builder.js +15 -13
- 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 +0 -1
- package/out/zql/src/builder/filter.d.ts.map +1 -1
- 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/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 +12 -4
- 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 +1 -1
- 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.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.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.js +1 -3
- package/out/zql/src/ivm/flipped-join.js.map +1 -1
- package/out/zql/src/ivm/join-index-tap.js.map +1 -1
- package/out/zql/src/ivm/join-index.js.map +1 -1
- package/out/zql/src/ivm/join-utils.js +11 -13
- 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 +6 -3
- package/out/zql/src/ivm/join.js.map +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 +1 -2
- package/out/zql/src/ivm/memory-source.d.ts.map +1 -1
- package/out/zql/src/ivm/memory-source.js +27 -23
- 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 +0 -1
- package/out/zql/src/ivm/push-accumulated.js.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/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 +7 -8
- 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.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 +5 -35
- package/out/zql/src/ivm/view-apply-change.d.ts.map +1 -1
- 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 +10 -9
- package/out/zql/src/planner/planner-debug.d.ts.map +1 -1
- 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 +0 -22
- package/out/zql/src/query/expression.d.ts.map +1 -1
- package/out/zql/src/query/expression.js +1 -1
- package/out/zql/src/query/expression.js.map +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 +0 -7
- package/out/zql/src/query/query-delegate-base.d.ts.map +1 -1
- package/out/zql/src/query/query-delegate-base.js +1 -1
- 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.js +3 -2
- 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 +2 -13
- 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.js.map +1 -1
- package/out/zqlite/src/query-builder.d.ts +11 -3
- package/out/zqlite/src/query-builder.d.ts.map +1 -1
- package/out/zqlite/src/query-builder.js +22 -7
- 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 +74 -40
- 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 -139
- 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
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"replication-status.js","names":["#dbRunner","#publishFn","#publish","#growthTimer","#last","#send","#timer","#totalIndexes","#now","#count","#current","#completedMs"],"sources":["../../../../../../zero-cache/src/services/replicator/replication-status.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {createSilentLogContext} from '../../../../shared/src/logging-test-utils.ts';\nimport type {JSONObject} from '../../../../zero-events/src/json.ts';\nimport type {\n IndexingStatus,\n ReplicatedIndex,\n ReplicatedTable,\n ReplicationStage,\n ReplicationState,\n ReplicationStatusEvent,\n Status,\n} from '../../../../zero-events/src/status.ts';\nimport {Database} from '../../../../zqlite/src/db.ts';\nimport {computeZqlSpecs, listIndexes} from '../../db/lite-tables.ts';\nimport type {LiteIndexSpec, LiteTableSpec} from '../../db/specs.ts';\nimport {\n makeErrorDetails,\n publishCriticalEvent,\n} from '../../observability/events.ts';\n\nconst byKeys = (a: [string, unknown], b: [string, unknown]) =>\n a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0;\n\nexport type GrowthOptions = {\n /** How often to check the replica size. */\n pollMs?: number;\n /** Republish when the replica grew by at least this many bytes ... */\n minDeltaBytes?: number;\n /** ... and by at least this fraction of the last published size. */\n minDeltaRatio?: number;\n};\n\nconst DEFAULT_GROWTH_OPTIONS: Required<GrowthOptions> = {\n pollMs: 30_000,\n minDeltaBytes: 1024 ** 3,\n minDeltaRatio: 0.05,\n};\n\ntype PublishedStatus = {\n stage: ReplicationStage;\n description: string | undefined;\n extraState: (() => Partial<ReplicationState>) | undefined;\n replicaSize: number | undefined;\n};\n\nexport class ReplicationStatusPublisher {\n readonly #dbRunner: <T>(lc: LogContext, fn: (db: Database) => T) => T;\n readonly #publishFn: typeof publishCriticalEvent;\n #timer: NodeJS.Timeout | undefined;\n #growthTimer: NodeJS.Timeout | undefined;\n #last: PublishedStatus | undefined;\n\n static forTesting() {\n return ReplicationStatusPublisher.forReplicaFile(':memory:');\n }\n\n static forRunningTransaction(tx: Database, publishFn = publishCriticalEvent) {\n return new ReplicationStatusPublisher((_lc, fn) => fn(tx), publishFn);\n }\n\n static forReplicaFile(file: string, publishFn = publishCriticalEvent) {\n return new ReplicationStatusPublisher((lc, fn) => {\n const db = new Database(lc, file, {readonly: true});\n try {\n return fn(db);\n } finally {\n db.close();\n }\n }, publishFn);\n }\n\n constructor(\n dbRunner: <T>(lc: LogContext, fn: (db: Database) => T) => T,\n publishFn = publishCriticalEvent,\n ) {\n this.#dbRunner = dbRunner;\n this.#publishFn = publishFn;\n }\n\n publish(\n lc: LogContext,\n stage: ReplicationStage,\n description?: string,\n interval = 0,\n extraState?: () => Partial<ReplicationState>,\n now = new Date(),\n ): this {\n void this.#publish(lc, stage, description, interval, extraState, now);\n return this;\n }\n\n /**\n * Like {@link publish}, but waits (for at most `maxWaitMs`) for the event\n * to be sent. Use this before a long synchronous operation (e.g. creating\n * an index) that blocks the event loop and would otherwise prevent the\n * event from being sent until the operation completes.\n */\n async publishAndFlush(\n lc: LogContext,\n stage: ReplicationStage,\n description?: string,\n interval = 0,\n extraState?: () => Partial<ReplicationState>,\n maxWaitMs = 1000,\n ): Promise<void> {\n const published = this.#publish(\n lc,\n stage,\n description,\n interval,\n extraState,\n );\n let timer: NodeJS.Timeout | undefined;\n try {\n await Promise.race([\n published,\n new Promise<void>(resolve => {\n timer = setTimeout(resolve, maxWaitMs);\n }),\n ]);\n } finally {\n clearTimeout(timer);\n }\n }\n\n /**\n * Republishes the last published status whenever the replica has grown by\n * the given delta since the last published `replicaSize`, until\n * {@link stop}. Consumers (e.g. Cloud Zero, which sizes the disk requests of\n * replicas from it) thereby see growth from any source, not only from\n * backfills and initial syncs. The status interval of {@link publish} keeps\n * running alongside.\n */\n watchGrowth(lc: LogContext, options: GrowthOptions = {}): this {\n const {pollMs, minDeltaBytes, minDeltaRatio} = {\n ...DEFAULT_GROWTH_OPTIONS,\n ...options,\n };\n clearInterval(this.#growthTimer);\n this.#growthTimer = setInterval(() => {\n const last = this.#last;\n if (!last) {\n return;\n }\n let size: number;\n try {\n size = this.#dbRunner(lc, getReplicaSize);\n } catch (e) {\n lc.warn?.(`Unable to read the replica size`, e);\n return;\n }\n const published = last.replicaSize ?? 0;\n if (\n size - published >=\n Math.max(minDeltaBytes, published * minDeltaRatio)\n ) {\n lc.info?.(\n `Replica grew from ${published} to ${size} bytes. Republishing status.`,\n );\n void this.#send(lc, last.stage, last.description, last.extraState);\n }\n }, pollMs);\n return this;\n }\n\n #publish(\n lc: LogContext,\n stage: ReplicationStage,\n description: string | undefined,\n interval: number,\n extraState: (() => Partial<ReplicationState>) | undefined,\n now = new Date(),\n ): Promise<void> {\n clearInterval(this.#timer);\n\n const published = this.#send(lc, stage, description, extraState, now);\n\n if (interval) {\n this.#timer = setInterval(\n () => this.publish(lc, stage, description, interval, extraState),\n interval,\n );\n }\n return published;\n }\n\n #send(\n lc: LogContext,\n stage: ReplicationStage,\n description: string | undefined,\n extraState: (() => Partial<ReplicationState>) | undefined,\n now = new Date(),\n ): Promise<void> {\n const event = this.#dbRunner(lc, db =>\n replicationStatusEvent(lc, db, stage, 'OK', description, now),\n );\n if (event.state) {\n event.state = {\n ...event.state,\n ...extraState?.(),\n };\n }\n this.#last = {\n stage,\n description,\n extraState,\n replicaSize: event.state?.replicaSize,\n };\n return this.#publishFn(lc, event);\n }\n\n async publishAndThrowError(\n lc: LogContext,\n stage: ReplicationStage,\n e: unknown,\n ): Promise<never> {\n this.stop();\n const event = this.#dbRunner(lc, db =>\n replicationStatusError(lc, stage, e, db),\n );\n await this.#publishFn(lc, event);\n throw e;\n }\n\n /** Stops the status interval and the growth watch. */\n stop(): this {\n clearInterval(this.#timer);\n clearInterval(this.#growthTimer);\n return this;\n }\n}\n\n/**\n * Tracks the progress of a sequence of index creations for reporting in\n * the `indexingStatus` field of {@link ReplicationState}.\n */\nexport class IndexingProgress {\n readonly #totalIndexes: number | undefined;\n readonly #now: () => number;\n #count = 0;\n #completedMs = 0;\n #current:\n | {index: LiteIndexSpec; start: number; elapsedMs: number | undefined}\n | undefined;\n\n /**\n * @param totalIndexes The total number of indexes to be created, if known.\n */\n constructor(totalIndexes?: number, now = () => performance.now()) {\n this.#totalIndexes = totalIndexes;\n this.#now = now;\n }\n\n /** Marks the start of creating the `index`. */\n start(index: LiteIndexSpec) {\n this.#count++;\n this.#current = {index, start: this.#now(), elapsedMs: undefined};\n }\n\n /**\n * Restarts the timer of the current index, e.g. to exclude time spent\n * reporting its start from its creation time.\n */\n restartTimer() {\n if (this.#current) {\n this.#current.start = this.#now();\n }\n }\n\n /**\n * Marks the completion of the index passed to the last call to\n * {@link start}, returning the milliseconds it took to create.\n */\n finish(): number {\n const current = this.#current;\n if (!current) {\n return 0;\n }\n if (current.elapsedMs === undefined) {\n current.elapsedMs = this.#now() - current.start;\n this.#completedMs += current.elapsedMs;\n }\n return current.elapsedMs;\n }\n\n /** The `extraState` for {@link ReplicationStatusPublisher.publish}. */\n readonly state = (): Partial<ReplicationState> => {\n const status = this.status();\n return status ? {indexingStatus: status} : {};\n };\n\n status(): IndexingStatus | undefined {\n const current = this.#current;\n if (!current) {\n return undefined;\n }\n const {index, start, elapsedMs} = current;\n const done = elapsedMs !== undefined;\n return {\n name: index.name,\n table: index.tableName,\n columns: Object.keys(index.columns),\n unique: index.unique,\n index: this.#count,\n totalIndexes: this.#totalIndexes,\n elapsedMs: Math.round(done ? elapsedMs : this.#now() - start),\n completedMs: Math.round(\n done ? this.#completedMs - elapsedMs : this.#completedMs,\n ),\n done,\n };\n }\n}\n\nexport async function publishReplicationError(\n lc: LogContext,\n stage: ReplicationStage,\n description: string,\n errorDetails?: JSONObject,\n now = new Date(),\n) {\n const event: ReplicationStatusEvent = {\n type: 'zero/events/status/replication/v1',\n component: 'replication',\n status: 'ERROR',\n stage,\n description,\n errorDetails,\n time: now.toISOString(),\n };\n await publishCriticalEvent(lc, event);\n}\n\nexport function replicationStatusError(\n lc: LogContext,\n stage: ReplicationStage,\n e: unknown,\n db?: Database,\n now = new Date(),\n) {\n const event = replicationStatusEvent(lc, db, stage, 'ERROR', String(e), now);\n event.errorDetails = makeErrorDetails(e);\n return event;\n}\n\n// Exported for testing.\nexport function replicationStatusEvent(\n lc: LogContext,\n db: Database | undefined,\n stage: ReplicationStage,\n status: Status,\n description?: string,\n now = new Date(),\n): ReplicationStatusEvent {\n const start = performance.now();\n try {\n return {\n type: 'zero/events/status/replication/v1',\n component: 'replication',\n status,\n stage,\n description,\n time: now.toISOString(),\n state: {\n tables: db ? getReplicatedTables(db) : [],\n indexes: db ? getReplicatedIndexes(db) : [],\n replicaSize: db ? getReplicaSize(db) : undefined,\n },\n };\n } catch (e) {\n lc.warn?.(`Unable to create full ReplicationStatusEvent`, e);\n return {\n type: 'zero/events/status/replication/v1',\n component: 'replication',\n status,\n stage,\n description,\n time: now.toISOString(),\n state: {\n tables: [],\n indexes: [],\n replicaSize: 0,\n },\n };\n } finally {\n const elapsed = (performance.now() - start).toFixed(3);\n lc.debug?.(`computed schema for replication event (${elapsed} ms)`);\n }\n}\n\nfunction getReplicatedTables(db: Database): ReplicatedTable[] {\n const fullTables = new Map<string, LiteTableSpec>();\n const clientSchema = computeZqlSpecs(\n createSilentLogContext(), // avoid logging warnings about indexes\n db,\n {includeBackfillingColumns: false},\n new Map(),\n fullTables,\n );\n\n // oxlint-disable-next-line e18e/prefer-array-to-sorted\n return [...fullTables.entries()].sort(byKeys).map(([table, spec]) => ({\n table,\n columns: Object.entries(spec.columns)\n .sort(byKeys)\n .map(([column, spec]) => ({\n column,\n upstreamType: spec.dataType.split('|')[0],\n clientType: clientSchema.get(table)?.zqlSpec[column]?.type ?? null,\n })),\n }));\n}\n\nfunction getReplicatedIndexes(db: Database): ReplicatedIndex[] {\n return listIndexes(db).map(({name, tableName: table, columns, unique}) => ({\n name,\n table,\n unique,\n columns: Object.entries(columns).map(([column, dir]) => ({column, dir})),\n }));\n}\n\nfunction getReplicaSize(db: Database) {\n const [{page_count: pageCount}] = db.pragma<{page_count: number}>(\n 'page_count',\n );\n const [{page_size: pageSize}] = db.pragma<{page_size: number}>('page_size');\n return pageCount * pageSize;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"replication-status.js","names":[],"sources":["../../../../../../zero-cache/src/services/replicator/replication-status.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {createSilentLogContext} from '../../../../shared/src/logging-test-utils.ts';\nimport type {JSONObject} from '../../../../zero-events/src/json.ts';\nimport type {\n IndexingStatus,\n ReplicatedIndex,\n ReplicatedTable,\n ReplicationStage,\n ReplicationState,\n ReplicationStatusEvent,\n Status,\n} from '../../../../zero-events/src/status.ts';\nimport {Database} from '../../../../zqlite/src/db.ts';\nimport {computeZqlSpecs, listIndexes} from '../../db/lite-tables.ts';\nimport type {LiteIndexSpec, LiteTableSpec} from '../../db/specs.ts';\nimport {\n makeErrorDetails,\n publishCriticalEvent,\n} from '../../observability/events.ts';\n\nconst byKeys = (a: [string, unknown], b: [string, unknown]) =>\n a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0;\n\nexport type GrowthOptions = {\n /** How often to check the replica size. */\n pollMs?: number;\n /** Republish when the replica grew by at least this many bytes ... */\n minDeltaBytes?: number;\n /** ... and by at least this fraction of the last published size. */\n minDeltaRatio?: number;\n};\n\nconst DEFAULT_GROWTH_OPTIONS: Required<GrowthOptions> = {\n pollMs: 30_000,\n minDeltaBytes: 1024 ** 3,\n minDeltaRatio: 0.05,\n};\n\ntype PublishedStatus = {\n stage: ReplicationStage;\n description: string | undefined;\n extraState: (() => Partial<ReplicationState>) | undefined;\n replicaSize: number | undefined;\n};\n\nexport class ReplicationStatusPublisher {\n readonly #dbRunner: <T>(lc: LogContext, fn: (db: Database) => T) => T;\n readonly #publishFn: typeof publishCriticalEvent;\n #timer: NodeJS.Timeout | undefined;\n #growthTimer: NodeJS.Timeout | undefined;\n #last: PublishedStatus | undefined;\n\n static forTesting() {\n return ReplicationStatusPublisher.forReplicaFile(':memory:');\n }\n\n static forRunningTransaction(tx: Database, publishFn = publishCriticalEvent) {\n return new ReplicationStatusPublisher((_lc, fn) => fn(tx), publishFn);\n }\n\n static forReplicaFile(file: string, publishFn = publishCriticalEvent) {\n return new ReplicationStatusPublisher((lc, fn) => {\n const db = new Database(lc, file, {readonly: true});\n try {\n return fn(db);\n } finally {\n db.close();\n }\n }, publishFn);\n }\n\n constructor(\n dbRunner: <T>(lc: LogContext, fn: (db: Database) => T) => T,\n publishFn = publishCriticalEvent,\n ) {\n this.#dbRunner = dbRunner;\n this.#publishFn = publishFn;\n }\n\n publish(\n lc: LogContext,\n stage: ReplicationStage,\n description?: string,\n interval = 0,\n extraState?: () => Partial<ReplicationState>,\n now = new Date(),\n ): this {\n void this.#publish(lc, stage, description, interval, extraState, now);\n return this;\n }\n\n /**\n * Like {@link publish}, but waits (for at most `maxWaitMs`) for the event\n * to be sent. Use this before a long synchronous operation (e.g. creating\n * an index) that blocks the event loop and would otherwise prevent the\n * event from being sent until the operation completes.\n */\n async publishAndFlush(\n lc: LogContext,\n stage: ReplicationStage,\n description?: string,\n interval = 0,\n extraState?: () => Partial<ReplicationState>,\n maxWaitMs = 1000,\n ): Promise<void> {\n const published = this.#publish(\n lc,\n stage,\n description,\n interval,\n extraState,\n );\n let timer: NodeJS.Timeout | undefined;\n try {\n await Promise.race([\n published,\n new Promise<void>(resolve => {\n timer = setTimeout(resolve, maxWaitMs);\n }),\n ]);\n } finally {\n clearTimeout(timer);\n }\n }\n\n /**\n * Republishes the last published status whenever the replica has grown by\n * the given delta since the last published `replicaSize`, until\n * {@link stop}. Consumers (e.g. Cloud Zero, which sizes the disk requests of\n * replicas from it) thereby see growth from any source, not only from\n * backfills and initial syncs. The status interval of {@link publish} keeps\n * running alongside.\n */\n watchGrowth(lc: LogContext, options: GrowthOptions = {}): this {\n const {pollMs, minDeltaBytes, minDeltaRatio} = {\n ...DEFAULT_GROWTH_OPTIONS,\n ...options,\n };\n clearInterval(this.#growthTimer);\n this.#growthTimer = setInterval(() => {\n const last = this.#last;\n if (!last) {\n return;\n }\n let size: number;\n try {\n size = this.#dbRunner(lc, getReplicaSize);\n } catch (e) {\n lc.warn?.(`Unable to read the replica size`, e);\n return;\n }\n const published = last.replicaSize ?? 0;\n if (\n size - published >=\n Math.max(minDeltaBytes, published * minDeltaRatio)\n ) {\n lc.info?.(\n `Replica grew from ${published} to ${size} bytes. Republishing status.`,\n );\n void this.#send(lc, last.stage, last.description, last.extraState);\n }\n }, pollMs);\n return this;\n }\n\n #publish(\n lc: LogContext,\n stage: ReplicationStage,\n description: string | undefined,\n interval: number,\n extraState: (() => Partial<ReplicationState>) | undefined,\n now = new Date(),\n ): Promise<void> {\n clearInterval(this.#timer);\n\n const published = this.#send(lc, stage, description, extraState, now);\n\n if (interval) {\n this.#timer = setInterval(\n () => this.publish(lc, stage, description, interval, extraState),\n interval,\n );\n }\n return published;\n }\n\n #send(\n lc: LogContext,\n stage: ReplicationStage,\n description: string | undefined,\n extraState: (() => Partial<ReplicationState>) | undefined,\n now = new Date(),\n ): Promise<void> {\n const event = this.#dbRunner(lc, db =>\n replicationStatusEvent(lc, db, stage, 'OK', description, now),\n );\n if (event.state) {\n event.state = {\n ...event.state,\n ...extraState?.(),\n };\n }\n this.#last = {\n stage,\n description,\n extraState,\n replicaSize: event.state?.replicaSize,\n };\n return this.#publishFn(lc, event);\n }\n\n async publishAndThrowError(\n lc: LogContext,\n stage: ReplicationStage,\n e: unknown,\n ): Promise<never> {\n this.stop();\n const event = this.#dbRunner(lc, db =>\n replicationStatusError(lc, stage, e, db),\n );\n await this.#publishFn(lc, event);\n throw e;\n }\n\n /** Stops the status interval and the growth watch. */\n stop(): this {\n clearInterval(this.#timer);\n clearInterval(this.#growthTimer);\n return this;\n }\n}\n\n/**\n * Tracks the progress of a sequence of index creations for reporting in\n * the `indexingStatus` field of {@link ReplicationState}.\n */\nexport class IndexingProgress {\n readonly #totalIndexes: number | undefined;\n readonly #now: () => number;\n #count = 0;\n #completedMs = 0;\n #current:\n | {index: LiteIndexSpec; start: number; elapsedMs: number | undefined}\n | undefined;\n\n /**\n * @param totalIndexes The total number of indexes to be created, if known.\n */\n constructor(totalIndexes?: number, now = () => performance.now()) {\n this.#totalIndexes = totalIndexes;\n this.#now = now;\n }\n\n /** Marks the start of creating the `index`. */\n start(index: LiteIndexSpec) {\n this.#count++;\n this.#current = {index, start: this.#now(), elapsedMs: undefined};\n }\n\n /**\n * Restarts the timer of the current index, e.g. to exclude time spent\n * reporting its start from its creation time.\n */\n restartTimer() {\n if (this.#current) {\n this.#current.start = this.#now();\n }\n }\n\n /**\n * Marks the completion of the index passed to the last call to\n * {@link start}, returning the milliseconds it took to create.\n */\n finish(): number {\n const current = this.#current;\n if (!current) {\n return 0;\n }\n if (current.elapsedMs === undefined) {\n current.elapsedMs = this.#now() - current.start;\n this.#completedMs += current.elapsedMs;\n }\n return current.elapsedMs;\n }\n\n /** The `extraState` for {@link ReplicationStatusPublisher.publish}. */\n readonly state = (): Partial<ReplicationState> => {\n const status = this.status();\n return status ? {indexingStatus: status} : {};\n };\n\n status(): IndexingStatus | undefined {\n const current = this.#current;\n if (!current) {\n return undefined;\n }\n const {index, start, elapsedMs} = current;\n const done = elapsedMs !== undefined;\n return {\n name: index.name,\n table: index.tableName,\n columns: Object.keys(index.columns),\n unique: index.unique,\n index: this.#count,\n totalIndexes: this.#totalIndexes,\n elapsedMs: Math.round(done ? elapsedMs : this.#now() - start),\n completedMs: Math.round(\n done ? this.#completedMs - elapsedMs : this.#completedMs,\n ),\n done,\n };\n }\n}\n\nexport async function publishReplicationError(\n lc: LogContext,\n stage: ReplicationStage,\n description: string,\n errorDetails?: JSONObject,\n now = new Date(),\n) {\n const event: ReplicationStatusEvent = {\n type: 'zero/events/status/replication/v1',\n component: 'replication',\n status: 'ERROR',\n stage,\n description,\n errorDetails,\n time: now.toISOString(),\n };\n await publishCriticalEvent(lc, event);\n}\n\nexport function replicationStatusError(\n lc: LogContext,\n stage: ReplicationStage,\n e: unknown,\n db?: Database,\n now = new Date(),\n) {\n const event = replicationStatusEvent(lc, db, stage, 'ERROR', String(e), now);\n event.errorDetails = makeErrorDetails(e);\n return event;\n}\n\n// Exported for testing.\nexport function replicationStatusEvent(\n lc: LogContext,\n db: Database | undefined,\n stage: ReplicationStage,\n status: Status,\n description?: string,\n now = new Date(),\n): ReplicationStatusEvent {\n const start = performance.now();\n try {\n return {\n type: 'zero/events/status/replication/v1',\n component: 'replication',\n status,\n stage,\n description,\n time: now.toISOString(),\n state: {\n tables: db ? getReplicatedTables(db) : [],\n indexes: db ? getReplicatedIndexes(db) : [],\n replicaSize: db ? getReplicaSize(db) : undefined,\n },\n };\n } catch (e) {\n lc.warn?.(`Unable to create full ReplicationStatusEvent`, e);\n return {\n type: 'zero/events/status/replication/v1',\n component: 'replication',\n status,\n stage,\n description,\n time: now.toISOString(),\n state: {\n tables: [],\n indexes: [],\n replicaSize: 0,\n },\n };\n } finally {\n const elapsed = (performance.now() - start).toFixed(3);\n lc.debug?.(`computed schema for replication event (${elapsed} ms)`);\n }\n}\n\nfunction getReplicatedTables(db: Database): ReplicatedTable[] {\n const fullTables = new Map<string, LiteTableSpec>();\n const clientSchema = computeZqlSpecs(\n createSilentLogContext(), // avoid logging warnings about indexes\n db,\n {includeBackfillingColumns: false},\n new Map(),\n fullTables,\n );\n\n // oxlint-disable-next-line e18e/prefer-array-to-sorted\n return [...fullTables.entries()].sort(byKeys).map(([table, spec]) => ({\n table,\n columns: Object.entries(spec.columns)\n .sort(byKeys)\n .map(([column, spec]) => ({\n column,\n upstreamType: spec.dataType.split('|')[0],\n clientType: clientSchema.get(table)?.zqlSpec[column]?.type ?? null,\n })),\n }));\n}\n\nfunction getReplicatedIndexes(db: Database): ReplicatedIndex[] {\n return listIndexes(db).map(({name, tableName: table, columns, unique}) => ({\n name,\n table,\n unique,\n columns: Object.entries(columns).map(([column, dir]) => ({column, dir})),\n }));\n}\n\nfunction getReplicaSize(db: Database) {\n const [{page_count: pageCount}] = db.pragma<{page_count: number}>(\n 'page_count',\n );\n const [{page_size: pageSize}] = db.pragma<{page_size: number}>('page_size');\n return pageCount * pageSize;\n}\n"],"mappings":";;;;;AAoBA,IAAM,UAAU,GAAsB,MACpC,EAAE,KAAK,EAAE,KAAK,KAAK,EAAE,KAAK,EAAE,KAAK,IAAI;AAWvC,IAAM,yBAAkD;CACtD,QAAQ;CACR,eAAe,QAAQ;CACvB,eAAe;AACjB;AASA,IAAa,6BAAb,MAAa,2BAA2B;CACtC;CACA;CACA;CACA;CACA;CAEA,OAAO,aAAa;EAClB,OAAO,2BAA2B,eAAe,UAAU;CAC7D;CAEA,OAAO,sBAAsB,IAAc,YAAY,sBAAsB;EAC3E,OAAO,IAAI,4BAA4B,KAAK,OAAO,GAAG,EAAE,GAAG,SAAS;CACtE;CAEA,OAAO,eAAe,MAAc,YAAY,sBAAsB;EACpE,OAAO,IAAI,4BAA4B,IAAI,OAAO;GAChD,MAAM,KAAK,IAAI,SAAS,IAAI,MAAM,EAAC,UAAU,KAAI,CAAC;GAClD,IAAI;IACF,OAAO,GAAG,EAAE;GACd,UAAU;IACR,GAAG,MAAM;GACX;EACF,GAAG,SAAS;CACd;CAEA,YACE,UACA,YAAY,sBACZ;EACA,KAAK,YAAY;EACjB,KAAK,aAAa;CACpB;CAEA,QACE,IACA,OACA,aACA,WAAW,GACX,YACA,sBAAM,IAAI,KAAK,GACT;EACN,KAAU,SAAS,IAAI,OAAO,aAAa,UAAU,YAAY,GAAG;EACpE,OAAO;CACT;;;;;;;CAQA,MAAM,gBACJ,IACA,OACA,aACA,WAAW,GACX,YACA,YAAY,KACG;EACf,MAAM,YAAY,KAAK,SACrB,IACA,OACA,aACA,UACA,UACF;EACA,IAAI;EACJ,IAAI;GACF,MAAM,QAAQ,KAAK,CACjB,WACA,IAAI,SAAc,YAAW;IAC3B,QAAQ,WAAW,SAAS,SAAS;GACvC,CAAC,CACH,CAAC;EACH,UAAU;GACR,aAAa,KAAK;EACpB;CACF;;;;;;;;;CAUA,YAAY,IAAgB,UAAyB,CAAC,GAAS;EAC7D,MAAM,EAAC,QAAQ,eAAe,kBAAiB;GAC7C,GAAG;GACH,GAAG;EACL;EACA,cAAc,KAAK,YAAY;EAC/B,KAAK,eAAe,kBAAkB;GACpC,MAAM,OAAO,KAAK;GAClB,IAAI,CAAC,MACH;GAEF,IAAI;GACJ,IAAI;IACF,OAAO,KAAK,UAAU,IAAI,cAAc;GAC1C,SAAS,GAAG;IACV,GAAG,OAAO,mCAAmC,CAAC;IAC9C;GACF;GACA,MAAM,YAAY,KAAK,eAAe;GACtC,IACE,OAAO,aACP,KAAK,IAAI,eAAe,YAAY,aAAa,GACjD;IACA,GAAG,OACD,qBAAqB,UAAU,MAAM,KAAK,6BAC5C;IACA,KAAU,MAAM,IAAI,KAAK,OAAO,KAAK,aAAa,KAAK,UAAU;GACnE;EACF,GAAG,MAAM;EACT,OAAO;CACT;CAEA,SACE,IACA,OACA,aACA,UACA,YACA,sBAAM,IAAI,KAAK,GACA;EACf,cAAc,KAAK,MAAM;EAEzB,MAAM,YAAY,KAAK,MAAM,IAAI,OAAO,aAAa,YAAY,GAAG;EAEpE,IAAI,UACF,KAAK,SAAS,kBACN,KAAK,QAAQ,IAAI,OAAO,aAAa,UAAU,UAAU,GAC/D,QACF;EAEF,OAAO;CACT;CAEA,MACE,IACA,OACA,aACA,YACA,sBAAM,IAAI,KAAK,GACA;EACf,MAAM,QAAQ,KAAK,UAAU,KAAI,OAC/B,uBAAuB,IAAI,IAAI,OAAO,MAAM,aAAa,GAAG,CAC9D;EACA,IAAI,MAAM,OACR,MAAM,QAAQ;GACZ,GAAG,MAAM;GACT,GAAG,aAAa;EAClB;EAEF,KAAK,QAAQ;GACX;GACA;GACA;GACA,aAAa,MAAM,OAAO;EAC5B;EACA,OAAO,KAAK,WAAW,IAAI,KAAK;CAClC;CAEA,MAAM,qBACJ,IACA,OACA,GACgB;EAChB,KAAK,KAAK;EACV,MAAM,QAAQ,KAAK,UAAU,KAAI,OAC/B,uBAAuB,IAAI,OAAO,GAAG,EAAE,CACzC;EACA,MAAM,KAAK,WAAW,IAAI,KAAK;EAC/B,MAAM;CACR;;CAGA,OAAa;EACX,cAAc,KAAK,MAAM;EACzB,cAAc,KAAK,YAAY;EAC/B,OAAO;CACT;AACF;;;;;AAMA,IAAa,mBAAb,MAA8B;CAC5B;CACA;CACA,SAAS;CACT,eAAe;CACf;;;;CAOA,YAAY,cAAuB,YAAY,YAAY,IAAI,GAAG;EAChE,KAAK,gBAAgB;EACrB,KAAK,OAAO;CACd;;CAGA,MAAM,OAAsB;EAC1B,KAAK;EACL,KAAK,WAAW;GAAC;GAAO,OAAO,KAAK,KAAK;GAAG,WAAW,KAAA;EAAS;CAClE;;;;;CAMA,eAAe;EACb,IAAI,KAAK,UACP,KAAK,SAAS,QAAQ,KAAK,KAAK;CAEpC;;;;;CAMA,SAAiB;EACf,MAAM,UAAU,KAAK;EACrB,IAAI,CAAC,SACH,OAAO;EAET,IAAI,QAAQ,cAAc,KAAA,GAAW;GACnC,QAAQ,YAAY,KAAK,KAAK,IAAI,QAAQ;GAC1C,KAAK,gBAAgB,QAAQ;EAC/B;EACA,OAAO,QAAQ;CACjB;;CAGA,cAAkD;EAChD,MAAM,SAAS,KAAK,OAAO;EAC3B,OAAO,SAAS,EAAC,gBAAgB,OAAM,IAAI,CAAC;CAC9C;CAEA,SAAqC;EACnC,MAAM,UAAU,KAAK;EACrB,IAAI,CAAC,SACH;EAEF,MAAM,EAAC,OAAO,OAAO,cAAa;EAClC,MAAM,OAAO,cAAc,KAAA;EAC3B,OAAO;GACL,MAAM,MAAM;GACZ,OAAO,MAAM;GACb,SAAS,OAAO,KAAK,MAAM,OAAO;GAClC,QAAQ,MAAM;GACd,OAAO,KAAK;GACZ,cAAc,KAAK;GACnB,WAAW,KAAK,MAAM,OAAO,YAAY,KAAK,KAAK,IAAI,KAAK;GAC5D,aAAa,KAAK,MAChB,OAAO,KAAK,eAAe,YAAY,KAAK,YAC9C;GACA;EACF;CACF;AACF;AAEA,eAAsB,wBACpB,IACA,OACA,aACA,cACA,sBAAM,IAAI,KAAK,GACf;CACA,MAAM,QAAgC;EACpC,MAAM;EACN,WAAW;EACX,QAAQ;EACR;EACA;EACA;EACA,MAAM,IAAI,YAAY;CACxB;CACA,MAAM,qBAAqB,IAAI,KAAK;AACtC;AAEA,SAAgB,uBACd,IACA,OACA,GACA,IACA,sBAAM,IAAI,KAAK,GACf;CACA,MAAM,QAAQ,uBAAuB,IAAI,IAAI,OAAO,SAAS,OAAO,CAAC,GAAG,GAAG;CAC3E,MAAM,eAAe,iBAAiB,CAAC;CACvC,OAAO;AACT;AAGA,SAAgB,uBACd,IACA,IACA,OACA,QACA,aACA,sBAAM,IAAI,KAAK,GACS;CACxB,MAAM,QAAQ,YAAY,IAAI;CAC9B,IAAI;EACF,OAAO;GACL,MAAM;GACN,WAAW;GACX;GACA;GACA;GACA,MAAM,IAAI,YAAY;GACtB,OAAO;IACL,QAAQ,KAAK,oBAAoB,EAAE,IAAI,CAAC;IACxC,SAAS,KAAK,qBAAqB,EAAE,IAAI,CAAC;IAC1C,aAAa,KAAK,eAAe,EAAE,IAAI,KAAA;GACzC;EACF;CACF,SAAS,GAAG;EACV,GAAG,OAAO,gDAAgD,CAAC;EAC3D,OAAO;GACL,MAAM;GACN,WAAW;GACX;GACA;GACA;GACA,MAAM,IAAI,YAAY;GACtB,OAAO;IACL,QAAQ,CAAC;IACT,SAAS,CAAC;IACV,aAAa;GACf;EACF;CACF,UAAU;EACR,MAAM,WAAW,YAAY,IAAI,IAAI,MAAA,CAAO,QAAQ,CAAC;EACrD,GAAG,QAAQ,0CAA0C,QAAQ,KAAK;CACpE;AACF;AAEA,SAAS,oBAAoB,IAAiC;CAC5D,MAAM,6BAAa,IAAI,IAA2B;CAClD,MAAM,eAAe,gBACnB,uBAAuB,GACvB,IACA,EAAC,2BAA2B,MAAK,mBACjC,IAAI,IAAI,GACR,UACF;CAGA,OAAO,CAAC,GAAG,WAAW,QAAQ,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW;EACpE;EACA,SAAS,OAAO,QAAQ,KAAK,OAAO,CAAC,CAClC,KAAK,MAAM,CAAC,CACZ,KAAK,CAAC,QAAQ,WAAW;GACxB;GACA,cAAc,KAAK,SAAS,MAAM,GAAG,CAAC,CAAC;GACvC,YAAY,aAAa,IAAI,KAAK,CAAC,EAAE,QAAQ,OAAO,EAAE,QAAQ;EAChE,EAAE;CACN,EAAE;AACJ;AAEA,SAAS,qBAAqB,IAAiC;CAC7D,OAAO,YAAY,EAAE,CAAC,CAAC,KAAK,EAAC,MAAM,WAAW,OAAO,SAAS,cAAa;EACzE;EACA;EACA;EACA,SAAS,OAAO,QAAQ,OAAO,CAAC,CAAC,KAAK,CAAC,QAAQ,UAAU;GAAC;GAAQ;EAAG,EAAE;CACzE,EAAE;AACJ;AAEA,SAAS,eAAe,IAAc;CACpC,MAAM,CAAC,EAAC,YAAY,eAAc,GAAG,OACnC,YACF;CACA,MAAM,CAAC,EAAC,WAAW,cAAa,GAAG,OAA4B,WAAW;CAC1E,OAAO,YAAY;AACrB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"replicator.js","names":[
|
|
1
|
+
{"version":3,"file":"replicator.js","names":[],"sources":["../../../../../../zero-cache/src/services/replicator/replicator.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport type {ReadonlyJSONObject} from '../../../../shared/src/json.ts';\nimport type {Source} from '../../types/streams.ts';\nimport type {ReservationFollowup} from '../change-streamer/change-streamer-http.ts';\nimport type {ChangeStreamer} from '../change-streamer/change-streamer.ts';\nimport type {Service} from '../service.ts';\nimport type {SwitchoverOptions} from './drain-handler.ts';\nimport {IncrementalSyncer} from './incremental-sync.ts';\nimport {\n publishReplicationError,\n type ReplicationStatusPublisher,\n} from './replication-status.ts';\nimport type {ReplicationLagReadinessOptions} from './reporter/recorder.ts';\nimport type {WriteWorkerClient} from './write-worker-client.ts';\n\n/** See {@link ReplicaStateNotifier.subscribe()}. */\nexport type ReplicaState = {\n readonly state: 'version-ready';\n /**\n * The replica watermark that became ready. Omitted for the initial\n * \"current state is ready\" notification, which should not count as newly\n * unserved work for a freshly-started ViewSyncer.\n */\n readonly watermark?: string | undefined;\n /**\n * Millisecond epoch when `watermark` became ready to read from the replica.\n */\n readonly replicaReadyTimeMs?: number | undefined;\n\n /**\n * Millisecond epoch at which the transaction behind `watermark` committed\n * *upstream*, as reported by the ChangeSource. Unlike `replicaReadyTimeMs`,\n * which is stamped locally when the change lands in the replica, this is the\n * origin of the whole pipeline, so `now - upstreamCommitTimeMs` at the point\n * the change is poked to clients is the end-to-end serving lag.\n *\n * Note that this crosses a clock domain: it comes from the upstream\n * database, whereas it is subtracted from the local clock in the ViewSyncer.\n * The existing `zero.replication.total_lag` metric spans the same boundary.\n *\n * Undefined when the ChangeSource does not report a commit time, and for the\n * initial \"current state is ready\" notification.\n */\n readonly upstreamCommitTimeMs?: number | undefined;\n\n // Used in tests to verify behavior when additional information\n // is ferried in the future. Not set in production.\n readonly testSeqNum?: number | undefined;\n};\n\nexport interface ReplicaStateNotifier {\n /**\n * Creates a cancelable subscription of changes in the replica state.\n *\n * A `version-ready` message indicates that the replica is ready to be\n * read, and henceforth that a _new_ version is ready, i.e. whenever a\n * change is committed to the replica. The `version-ready` message itself\n * otherwise contains no other information; the subscriber queries the\n * replica for the current data.\n *\n * A `maintenance` state indicates that the replica should not be read from.\n * If a subscriber is holding any transaction locks, it should release them\n * until the next `version-ready` signal.\n *\n * Upon subscription, the current state of the replica is sent immediately\n * if known. If multiple notifications occur before the subscriber\n * can consume them, all but the last notification are discarded by the\n * Subscription object (i.e. not buffered). Thus, a subscriber only\n * ever consumes the current (i.e. known) state of the replica. This avoids\n * a buildup of \"work\" if a subscriber is too busy to consume all\n * notifications.\n */\n subscribe(): Source<ReplicaState>;\n}\n\nexport interface Replicator extends ReplicaStateNotifier {\n /**\n * Returns an opaque message for human-readable consumption. This is\n * purely for ensuring that the Replicator has started at least once to\n * bootstrap a new replica.\n */\n status(): Promise<ReadonlyJSONObject>;\n}\n\nexport type ReplicatorMode = 'backup' | 'serving';\n\nexport class ReplicatorService implements Replicator, Service {\n readonly id: string;\n readonly #lc: LogContext;\n readonly #incrementalSyncer: IncrementalSyncer;\n readonly #shouldPublishErrors: boolean;\n readonly #worker: WriteWorkerClient;\n #runPromise: Promise<void> | undefined;\n\n constructor(\n lc: LogContext,\n taskID: string,\n id: string,\n mode: ReplicatorMode,\n changeStreamer: ChangeStreamer,\n worker: WriteWorkerClient,\n statusPublisher: ReplicationStatusPublisher | null,\n replicationLagReadinessOptions: ReplicationLagReadinessOptions = {},\n // The still-open connection from the snapshot reservation that produced\n // the replica this process just restored (serving mode only). Used for\n // IncrementalSyncer's first subscribe() so the replication-manager that\n // reserved the change log is the one that serves the subscription.\n initialConnection?: ReservationFollowup,\n switchover?: SwitchoverOptions,\n ) {\n this.id = id;\n this.#lc = lc\n .withContext('component', 'replicator')\n .withContext('serviceID', this.id);\n this.#worker = worker;\n this.#shouldPublishErrors = statusPublisher !== null;\n\n this.#incrementalSyncer = new IncrementalSyncer(\n this.#lc,\n taskID,\n `${taskID}/${id}`,\n changeStreamer,\n worker,\n mode,\n statusPublisher,\n replicationLagReadinessOptions,\n initialConnection,\n switchover,\n );\n }\n\n status() {\n return Promise.resolve({status: 'ok'});\n }\n\n ready(): Promise<void> {\n return this.#incrementalSyncer.ready();\n }\n\n run() {\n this.#runPromise = this.#incrementalSyncer.run().catch(async error => {\n if (this.#shouldPublishErrors) {\n await publishReplicationError(\n this.#lc,\n 'Replicating',\n 'Replication stopped because the replica writer failed',\n );\n }\n throw error;\n });\n return this.#runPromise;\n }\n\n subscribe(): Source<ReplicaState> {\n return this.#incrementalSyncer.subscribe();\n }\n\n async stop() {\n this.#incrementalSyncer.stop(this.#lc);\n // Wait for the syncer's run loop to finish so that any in-flight\n // worker.processMessages() call completes and clears #pending\n // before we send the 'stop' message to the worker.\n await this.#runPromise;\n await this.#worker.stop();\n }\n}\n"],"mappings":";;;AAsFA,IAAa,oBAAb,MAA8D;CAC5D;CACA;CACA;CACA;CACA;CACA;CAEA,YACE,IACA,QACA,IACA,MACA,gBACA,QACA,iBACA,iCAAiE,CAAC,GAKlE,mBACA,YACA;EACA,KAAK,KAAK;EACV,KAAK,MAAM,GACR,YAAY,aAAa,YAAY,CAAC,CACtC,YAAY,aAAa,KAAK,EAAE;EACnC,KAAK,UAAU;EACf,KAAK,uBAAuB,oBAAoB;EAEhD,KAAK,qBAAqB,IAAI,kBAC5B,KAAK,KACL,QACA,GAAG,OAAO,GAAG,MACb,gBACA,QACA,MACA,iBACA,gCACA,mBACA,UACF;CACF;CAEA,SAAS;EACP,OAAO,QAAQ,QAAQ,EAAC,QAAQ,KAAI,CAAC;CACvC;CAEA,QAAuB;EACrB,OAAO,KAAK,mBAAmB,MAAM;CACvC;CAEA,MAAM;EACJ,KAAK,cAAc,KAAK,mBAAmB,IAAI,CAAC,CAAC,MAAM,OAAM,UAAS;GACpE,IAAI,KAAK,sBACP,MAAM,wBACJ,KAAK,KACL,eACA,uDACF;GAEF,MAAM;EACR,CAAC;EACD,OAAO,KAAK;CACd;CAEA,YAAkC;EAChC,OAAO,KAAK,mBAAmB,UAAU;CAC3C;CAEA,MAAM,OAAO;EACX,KAAK,mBAAmB,KAAK,KAAK,GAAG;EAIrC,MAAM,KAAK;EACX,MAAM,KAAK,QAAQ,KAAK;CAC1B;AACF"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { resolver } from "../../../../../shared/src/resolver.js";
|
|
1
2
|
import { getOrCreateGauge } from "../../../observability/metrics.js";
|
|
2
|
-
import { resolver } from "@rocicorp/resolver";
|
|
3
3
|
//#region ../zero-cache/src/services/replicator/reporter/recorder.ts
|
|
4
4
|
var LOG_ALL_REPLICATION_REPORTS_AT_DEBUG = process.env.ZERO_LOG_ALL_REPLICATION_REPORTS_AT_DEBUG === "1";
|
|
5
5
|
var ReplicationReportRecorder = class {
|
|
@@ -129,6 +129,6 @@ function isLagReportingDisabledSignal(report) {
|
|
|
129
129
|
return report.nextSendTimeMs === 0 && report.lastTimings === void 0;
|
|
130
130
|
}
|
|
131
131
|
//#endregion
|
|
132
|
-
export { ReplicationReportRecorder };
|
|
132
|
+
export { ReplicationReportRecorder, estimateUpstreamClockSkewMs, isLagReportingDisabledSignal };
|
|
133
133
|
|
|
134
134
|
//# sourceMappingURL=recorder.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"recorder.js","names":["#lc","#readinessThresholdMs","#readyGate","#clearTimeout","#readinessTimer","#setReady","#last","#ready"],"sources":["../../../../../../../zero-cache/src/services/replicator/reporter/recorder.ts"],"sourcesContent":["import type {ObservableResult} from '@opentelemetry/api';\nimport type {LogContext, LogLevel} from '@rocicorp/logger';\nimport {resolver} from '@rocicorp/resolver';\nimport {getOrCreateGauge} from '../../../observability/metrics.ts';\nimport type {ReplicationReport} from './report-schema.ts';\n\n// Hook for sanity checking lag reports in development.\nconst LOG_ALL_REPLICATION_REPORTS_AT_DEBUG =\n process.env.ZERO_LOG_ALL_REPLICATION_REPORTS_AT_DEBUG === '1';\n\nexport type ReplicationLagReadinessOptions = {\n readinessThresholdMs?: number | undefined;\n maxReadinessDelayMs?: number | undefined;\n setTimeoutFn?: typeof setTimeout | undefined;\n clearTimeoutFn?: typeof clearTimeout | undefined;\n};\n\nexport class ReplicationReportRecorder {\n readonly #lc: LogContext;\n readonly #readinessThresholdMs: number;\n readonly #readyGate = resolver();\n readonly #clearTimeout: typeof clearTimeout;\n readonly #readinessTimer: ReturnType<typeof setTimeout>;\n #ready = false;\n #last: ReplicationReport | null = null;\n\n constructor(\n lc: LogContext,\n {\n readinessThresholdMs = 1000,\n maxReadinessDelayMs = 600_000,\n setTimeoutFn = setTimeout,\n clearTimeoutFn = clearTimeout,\n }: ReplicationLagReadinessOptions = {},\n ) {\n this.#lc = lc;\n this.#readinessThresholdMs = readinessThresholdMs;\n this.#clearTimeout = clearTimeoutFn;\n\n this.#readinessTimer = setTimeoutFn(\n () =>\n this.#setReady(\n 'warn',\n `timed out waiting for replication lag readiness threshold of ${this.#readinessThresholdMs} ms`,\n ),\n maxReadinessDelayMs,\n );\n // The timer should not keep the process alive.\n this.#readinessTimer?.unref?.();\n }\n\n ready(): Promise<void> {\n return this.#readyGate.promise;\n }\n\n record(report: ReplicationReport) {\n if (isLagReportingDisabledSignal(report)) {\n this.#setReady(\n 'info',\n `replica is caught up (replication lag reporting is disabled upstream)`,\n );\n return;\n }\n this.#last = report;\n\n const {lastTimings} = report;\n if (lastTimings) {\n const total = lastTimings.replicateTimeMs - lastTimings.sendTimeMs;\n if (total > 10_000) {\n const log = this.#ready ? 'warn' : 'info';\n this.#lc[log]?.(`high replication lag: ${total} ms`, {\n ready: this.#ready,\n report,\n });\n } else if (total > 1_000) {\n this.#lc.info?.(`replication lag: ${total} ms`, {\n ready: this.#ready,\n report,\n });\n }\n if (LOG_ALL_REPLICATION_REPORTS_AT_DEBUG) {\n this.#lc.debug?.(`replication lag ${total} ms`, {\n ready: this.#ready,\n report,\n });\n }\n if (!this.#ready && total <= this.#readinessThresholdMs) {\n this.#setReady(\n 'info',\n `replicator is now ready with replication lag (${total} ms) less than ${this.#readinessThresholdMs} ms readiness threshold`,\n );\n }\n }\n }\n\n #setReady(log: LogLevel, message: string) {\n if (this.#ready) {\n return;\n }\n this.#lc[log]?.(message, {lastReport: this.#last});\n this.#ready = true;\n this.#clearTimeout(this.#readinessTimer);\n this.#readyGate.resolve();\n\n getOrCreateGauge('replication', 'upstream_lag', {\n description:\n 'Latency from sending an upstream replication report ' +\n 'to receiving it in the replication stream',\n unit: 'millisecond',\n }).addCallback(this.reportUpstreamLag);\n\n getOrCreateGauge('replication', 'replica_lag', {\n description:\n 'Latency from receiving an upstream replication report ' +\n 'to its reaching the replica',\n unit: 'millisecond',\n }).addCallback(this.reportReplicaLag);\n\n getOrCreateGauge('replication', 'total_lag', {\n description:\n 'Latency from sending an upstream replication report to its ' +\n 'reaching the replica. This reflects the actual measured ' +\n 'round-trip of the most recently received report and does not ' +\n 'grow when reports stop arriving.',\n unit: 'millisecond',\n }).addCallback(this.reportTotalLag);\n\n getOrCreateGauge('replication', 'last_total_lag', {\n description:\n 'Latency from sending the most recently received upstream ' +\n 'replication report to its reaching the replica. This is an alias ' +\n 'of replication.total_lag retained for dashboards that explicitly ' +\n 'want the non-extrapolated value.',\n unit: 'millisecond',\n }).addCallback(this.reportLastTotalLag);\n\n getOrCreateGauge('replication', 'upstream_clock_skew', {\n description:\n 'Estimated offset of the upstream database clock relative to ' +\n \"zero-cache's. Positive means upstream is running ahead. \" +\n 'Derived from the lag report round-trip, whose send and receive ' +\n 'times are stamped on our clock either side of the upstream ' +\n 'commit timestamp. This matters because ' +\n 'sync.e2e_serving_lag subtracts an upstream commit timestamp from ' +\n 'a local clock, so a skewed upstream clock biases it directly -- ' +\n 'and an upstream clock running ahead biases it *low*, which looks ' +\n 'like healthy serving rather than a broken measurement.',\n unit: 'millisecond',\n }).addCallback(this.reportUpstreamClockSkew);\n }\n\n readonly reportUpstreamLag = (o: ObservableResult) => {\n const last = this.#last?.lastTimings;\n if (last) {\n o.observe(last.receiveTimeMs - last.sendTimeMs);\n }\n };\n\n readonly reportReplicaLag = (o: ObservableResult) => {\n const last = this.#last?.lastTimings;\n if (last) {\n o.observe(last.replicateTimeMs - last.receiveTimeMs);\n }\n };\n\n readonly reportTotalLag = (o: ObservableResult) => {\n const last = this.#last?.lastTimings;\n if (last) {\n o.observe(last.replicateTimeMs - last.sendTimeMs);\n }\n };\n\n readonly reportLastTotalLag = (o: ObservableResult) => {\n const last = this.#last?.lastTimings;\n if (last) {\n o.observe(last.replicateTimeMs - last.sendTimeMs);\n }\n };\n\n readonly reportUpstreamClockSkew = (o: ObservableResult) => {\n const last = this.#last?.lastTimings;\n if (last) {\n o.observe(estimateUpstreamClockSkewMs(last));\n }\n };\n}\n\n/**\n * Estimates how far the upstream database's clock is from ours, in\n * milliseconds, positive meaning upstream is ahead.\n *\n * `sendTimeMs` and `receiveTimeMs` are both stamped in the\n * replication-manager, either side of `commitTimeMs`, which upstream stamps.\n * Assuming the upstream commit fell midway through that round trip, the\n * difference between where it actually landed and that midpoint is the clock\n * offset -- the same round-trip estimate NTP uses.\n *\n * The estimate is biased by any asymmetry between the two legs: the outbound\n * leg is a SQL round trip, while the return leg additionally waits on a WAL\n * flush and the walsender (which the pre-PG-17 path notes can add 50~100ms on\n * an idle database). So treat this as a detector of gross skew -- the kind\n * that invalidates sync.e2e_serving_lag -- and not as a sub-100ms correction.\n *\n * The rigorous bound, if a tighter reading is ever needed: the commit\n * genuinely happened between send and receive, so a `commitTimeMs` outside\n * that window proves skew of at least the amount by which it falls outside,\n * independent of any latency assumption.\n */\nexport function estimateUpstreamClockSkewMs({\n sendTimeMs,\n commitTimeMs,\n receiveTimeMs,\n}: {\n sendTimeMs: number;\n commitTimeMs: number;\n receiveTimeMs: number;\n}): number {\n return commitTimeMs - (sendTimeMs + receiveTimeMs) / 2;\n}\n\n/**\n * Returns whether the `report` is the signal sent by the change-streamer,\n * once the subscriber is caught up, to indicate that lag reporting is\n * disabled upstream (and thus readiness cannot be gated on lag reports).\n *\n * This is a lag report with a `nextSendTimeMs` of 0 and no `lastTimings`.\n */\nexport function isLagReportingDisabledSignal(\n report: ReplicationReport,\n): boolean {\n return report.nextSendTimeMs === 0 && report.lastTimings === undefined;\n}\n"],"mappings":";;;AAOA,IAAM,uCACJ,QAAQ,IAAI,8CAA8C;AAS5D,IAAa,4BAAb,MAAuC;CACrC;CACA;CACA,aAAsB,SAAS;CAC/B;CACA;CACA,SAAS;CACT,QAAkC;CAElC,YACE,IACA,EACE,uBAAuB,KACvB,sBAAsB,KACtB,eAAe,YACf,iBAAiB,iBACiB,CAAC,GACrC;EACA,KAAKA,MAAM;EACX,KAAKC,wBAAwB;EAC7B,KAAKE,gBAAgB;EAErB,KAAKC,kBAAkB,mBAEnB,KAAKC,UACH,QACA,gEAAgE,KAAKJ,sBAAsB,IAC7F,GACF,mBACF;EAEA,KAAKG,iBAAiB,QAAQ;CAChC;CAEA,QAAuB;EACrB,OAAO,KAAKF,WAAW;CACzB;CAEA,OAAO,QAA2B;EAChC,IAAI,6BAA6B,MAAM,GAAG;GACxC,KAAKG,UACH,QACA,uEACF;GACA;EACF;EACA,KAAKC,QAAQ;EAEb,MAAM,EAAC,gBAAe;EACtB,IAAI,aAAa;GACf,MAAM,QAAQ,YAAY,kBAAkB,YAAY;GACxD,IAAI,QAAQ,KAAQ;IAClB,MAAM,MAAM,KAAKC,SAAS,SAAS;IACnC,KAAKP,IAAI,OAAO,yBAAyB,MAAM,MAAM;KACnD,OAAO,KAAKO;KACZ;IACF,CAAC;GACH,OAAO,IAAI,QAAQ,KACjB,KAAKP,IAAI,OAAO,oBAAoB,MAAM,MAAM;IAC9C,OAAO,KAAKO;IACZ;GACF,CAAC;GAEH,IAAI,sCACF,KAAKP,IAAI,QAAQ,mBAAmB,MAAM,MAAM;IAC9C,OAAO,KAAKO;IACZ;GACF,CAAC;GAEH,IAAI,CAAC,KAAKA,UAAU,SAAS,KAAKN,uBAChC,KAAKI,UACH,QACA,iDAAiD,MAAM,iBAAiB,KAAKJ,sBAAsB,wBACrG;EAEJ;CACF;CAEA,UAAU,KAAe,SAAiB;EACxC,IAAI,KAAKM,QACP;EAEF,KAAKP,IAAI,OAAO,SAAS,EAAC,YAAY,KAAKM,MAAK,CAAC;EACjD,KAAKC,SAAS;EACd,KAAKJ,cAAc,KAAKC,eAAe;EACvC,KAAKF,WAAW,QAAQ;EAExB,iBAAiB,eAAe,gBAAgB;GAC9C,aACE;GAEF,MAAM;EACR,CAAC,EAAE,YAAY,KAAK,iBAAiB;EAErC,iBAAiB,eAAe,eAAe;GAC7C,aACE;GAEF,MAAM;EACR,CAAC,EAAE,YAAY,KAAK,gBAAgB;EAEpC,iBAAiB,eAAe,aAAa;GAC3C,aACE;GAIF,MAAM;EACR,CAAC,EAAE,YAAY,KAAK,cAAc;EAElC,iBAAiB,eAAe,kBAAkB;GAChD,aACE;GAIF,MAAM;EACR,CAAC,EAAE,YAAY,KAAK,kBAAkB;EAEtC,iBAAiB,eAAe,uBAAuB;GACrD,aACE;GASF,MAAM;EACR,CAAC,EAAE,YAAY,KAAK,uBAAuB;CAC7C;CAEA,qBAA8B,MAAwB;EACpD,MAAM,OAAO,KAAKI,OAAO;EACzB,IAAI,MACF,EAAE,QAAQ,KAAK,gBAAgB,KAAK,UAAU;CAElD;CAEA,oBAA6B,MAAwB;EACnD,MAAM,OAAO,KAAKA,OAAO;EACzB,IAAI,MACF,EAAE,QAAQ,KAAK,kBAAkB,KAAK,aAAa;CAEvD;CAEA,kBAA2B,MAAwB;EACjD,MAAM,OAAO,KAAKA,OAAO;EACzB,IAAI,MACF,EAAE,QAAQ,KAAK,kBAAkB,KAAK,UAAU;CAEpD;CAEA,sBAA+B,MAAwB;EACrD,MAAM,OAAO,KAAKA,OAAO;EACzB,IAAI,MACF,EAAE,QAAQ,KAAK,kBAAkB,KAAK,UAAU;CAEpD;CAEA,2BAAoC,MAAwB;EAC1D,MAAM,OAAO,KAAKA,OAAO;EACzB,IAAI,MACF,EAAE,QAAQ,4BAA4B,IAAI,CAAC;CAE/C;AACF;;;;;;;;;;;;;;;;;;;;;;AAuBA,SAAgB,4BAA4B,EAC1C,YACA,cACA,iBAKS;CACT,OAAO,gBAAgB,aAAa,iBAAiB;AACvD;;;;;;;;AASA,SAAgB,6BACd,QACS;CACT,OAAO,OAAO,mBAAmB,KAAK,OAAO,gBAAgB,KAAA;AAC/D"}
|
|
1
|
+
{"version":3,"file":"recorder.js","names":[],"sources":["../../../../../../../zero-cache/src/services/replicator/reporter/recorder.ts"],"sourcesContent":["import type {ObservableResult} from '@opentelemetry/api';\nimport type {LogContext, LogLevel} from '@rocicorp/logger';\nimport {resolver} from '../../../../../shared/src/resolver.ts';\nimport {getOrCreateGauge} from '../../../observability/metrics.ts';\nimport type {ReplicationReport} from './report-schema.ts';\n\n// Hook for sanity checking lag reports in development.\nconst LOG_ALL_REPLICATION_REPORTS_AT_DEBUG =\n process.env.ZERO_LOG_ALL_REPLICATION_REPORTS_AT_DEBUG === '1';\n\nexport type ReplicationLagReadinessOptions = {\n readinessThresholdMs?: number | undefined;\n maxReadinessDelayMs?: number | undefined;\n setTimeoutFn?: typeof setTimeout | undefined;\n clearTimeoutFn?: typeof clearTimeout | undefined;\n};\n\nexport class ReplicationReportRecorder {\n readonly #lc: LogContext;\n readonly #readinessThresholdMs: number;\n readonly #readyGate = resolver();\n readonly #clearTimeout: typeof clearTimeout;\n readonly #readinessTimer: ReturnType<typeof setTimeout>;\n #ready = false;\n #last: ReplicationReport | null = null;\n\n constructor(\n lc: LogContext,\n {\n readinessThresholdMs = 1000,\n maxReadinessDelayMs = 600_000,\n setTimeoutFn = setTimeout,\n clearTimeoutFn = clearTimeout,\n }: ReplicationLagReadinessOptions = {},\n ) {\n this.#lc = lc;\n this.#readinessThresholdMs = readinessThresholdMs;\n this.#clearTimeout = clearTimeoutFn;\n\n this.#readinessTimer = setTimeoutFn(\n () =>\n this.#setReady(\n 'warn',\n `timed out waiting for replication lag readiness threshold of ${this.#readinessThresholdMs} ms`,\n ),\n maxReadinessDelayMs,\n );\n // The timer should not keep the process alive.\n this.#readinessTimer?.unref?.();\n }\n\n ready(): Promise<void> {\n return this.#readyGate.promise;\n }\n\n record(report: ReplicationReport) {\n if (isLagReportingDisabledSignal(report)) {\n this.#setReady(\n 'info',\n `replica is caught up (replication lag reporting is disabled upstream)`,\n );\n return;\n }\n this.#last = report;\n\n const {lastTimings} = report;\n if (lastTimings) {\n const total = lastTimings.replicateTimeMs - lastTimings.sendTimeMs;\n if (total > 10_000) {\n const log = this.#ready ? 'warn' : 'info';\n this.#lc[log]?.(`high replication lag: ${total} ms`, {\n ready: this.#ready,\n report,\n });\n } else if (total > 1_000) {\n this.#lc.info?.(`replication lag: ${total} ms`, {\n ready: this.#ready,\n report,\n });\n }\n if (LOG_ALL_REPLICATION_REPORTS_AT_DEBUG) {\n this.#lc.debug?.(`replication lag ${total} ms`, {\n ready: this.#ready,\n report,\n });\n }\n if (!this.#ready && total <= this.#readinessThresholdMs) {\n this.#setReady(\n 'info',\n `replicator is now ready with replication lag (${total} ms) less than ${this.#readinessThresholdMs} ms readiness threshold`,\n );\n }\n }\n }\n\n #setReady(log: LogLevel, message: string) {\n if (this.#ready) {\n return;\n }\n this.#lc[log]?.(message, {lastReport: this.#last});\n this.#ready = true;\n this.#clearTimeout(this.#readinessTimer);\n this.#readyGate.resolve();\n\n getOrCreateGauge('replication', 'upstream_lag', {\n description:\n 'Latency from sending an upstream replication report ' +\n 'to receiving it in the replication stream',\n unit: 'millisecond',\n }).addCallback(this.reportUpstreamLag);\n\n getOrCreateGauge('replication', 'replica_lag', {\n description:\n 'Latency from receiving an upstream replication report ' +\n 'to its reaching the replica',\n unit: 'millisecond',\n }).addCallback(this.reportReplicaLag);\n\n getOrCreateGauge('replication', 'total_lag', {\n description:\n 'Latency from sending an upstream replication report to its ' +\n 'reaching the replica. This reflects the actual measured ' +\n 'round-trip of the most recently received report and does not ' +\n 'grow when reports stop arriving.',\n unit: 'millisecond',\n }).addCallback(this.reportTotalLag);\n\n getOrCreateGauge('replication', 'last_total_lag', {\n description:\n 'Latency from sending the most recently received upstream ' +\n 'replication report to its reaching the replica. This is an alias ' +\n 'of replication.total_lag retained for dashboards that explicitly ' +\n 'want the non-extrapolated value.',\n unit: 'millisecond',\n }).addCallback(this.reportLastTotalLag);\n\n getOrCreateGauge('replication', 'upstream_clock_skew', {\n description:\n 'Estimated offset of the upstream database clock relative to ' +\n \"zero-cache's. Positive means upstream is running ahead. \" +\n 'Derived from the lag report round-trip, whose send and receive ' +\n 'times are stamped on our clock either side of the upstream ' +\n 'commit timestamp. This matters because ' +\n 'sync.e2e_serving_lag subtracts an upstream commit timestamp from ' +\n 'a local clock, so a skewed upstream clock biases it directly -- ' +\n 'and an upstream clock running ahead biases it *low*, which looks ' +\n 'like healthy serving rather than a broken measurement.',\n unit: 'millisecond',\n }).addCallback(this.reportUpstreamClockSkew);\n }\n\n readonly reportUpstreamLag = (o: ObservableResult) => {\n const last = this.#last?.lastTimings;\n if (last) {\n o.observe(last.receiveTimeMs - last.sendTimeMs);\n }\n };\n\n readonly reportReplicaLag = (o: ObservableResult) => {\n const last = this.#last?.lastTimings;\n if (last) {\n o.observe(last.replicateTimeMs - last.receiveTimeMs);\n }\n };\n\n readonly reportTotalLag = (o: ObservableResult) => {\n const last = this.#last?.lastTimings;\n if (last) {\n o.observe(last.replicateTimeMs - last.sendTimeMs);\n }\n };\n\n readonly reportLastTotalLag = (o: ObservableResult) => {\n const last = this.#last?.lastTimings;\n if (last) {\n o.observe(last.replicateTimeMs - last.sendTimeMs);\n }\n };\n\n readonly reportUpstreamClockSkew = (o: ObservableResult) => {\n const last = this.#last?.lastTimings;\n if (last) {\n o.observe(estimateUpstreamClockSkewMs(last));\n }\n };\n}\n\n/**\n * Estimates how far the upstream database's clock is from ours, in\n * milliseconds, positive meaning upstream is ahead.\n *\n * `sendTimeMs` and `receiveTimeMs` are both stamped in the\n * replication-manager, either side of `commitTimeMs`, which upstream stamps.\n * Assuming the upstream commit fell midway through that round trip, the\n * difference between where it actually landed and that midpoint is the clock\n * offset -- the same round-trip estimate NTP uses.\n *\n * The estimate is biased by any asymmetry between the two legs: the outbound\n * leg is a SQL round trip, while the return leg additionally waits on a WAL\n * flush and the walsender (which the pre-PG-17 path notes can add 50~100ms on\n * an idle database). So treat this as a detector of gross skew -- the kind\n * that invalidates sync.e2e_serving_lag -- and not as a sub-100ms correction.\n *\n * The rigorous bound, if a tighter reading is ever needed: the commit\n * genuinely happened between send and receive, so a `commitTimeMs` outside\n * that window proves skew of at least the amount by which it falls outside,\n * independent of any latency assumption.\n */\nexport function estimateUpstreamClockSkewMs({\n sendTimeMs,\n commitTimeMs,\n receiveTimeMs,\n}: {\n sendTimeMs: number;\n commitTimeMs: number;\n receiveTimeMs: number;\n}): number {\n return commitTimeMs - (sendTimeMs + receiveTimeMs) / 2;\n}\n\n/**\n * Returns whether the `report` is the signal sent by the change-streamer,\n * once the subscriber is caught up, to indicate that lag reporting is\n * disabled upstream (and thus readiness cannot be gated on lag reports).\n *\n * This is a lag report with a `nextSendTimeMs` of 0 and no `lastTimings`.\n */\nexport function isLagReportingDisabledSignal(\n report: ReplicationReport,\n): boolean {\n return report.nextSendTimeMs === 0 && report.lastTimings === undefined;\n}\n"],"mappings":"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"}
|
|
@@ -12,14 +12,7 @@ export declare const changeSourceReportSchema: v.ObjectType<{
|
|
|
12
12
|
}, undefined>;
|
|
13
13
|
nextSendTimeMs: v.Type<number>;
|
|
14
14
|
}, undefined>;
|
|
15
|
-
|
|
16
|
-
sendTimeMs: v.Type<number>;
|
|
17
|
-
commitTimeMs: v.Type<number>;
|
|
18
|
-
receiveTimeMs: v.Type<number>;
|
|
19
|
-
}, "replicateTimeMs"> & {
|
|
20
|
-
replicateTimeMs: v.Type<number>;
|
|
21
|
-
}, undefined>;
|
|
22
|
-
export declare const replicationReportSchema: v.ObjectType<{
|
|
15
|
+
declare const replicationReportSchema: v.ObjectType<{
|
|
23
16
|
lastTimings: v.Optional<{
|
|
24
17
|
sendTimeMs: number;
|
|
25
18
|
commitTimeMs: number;
|
|
@@ -28,8 +21,6 @@ export declare const replicationReportSchema: v.ObjectType<{
|
|
|
28
21
|
}>;
|
|
29
22
|
nextSendTimeMs: v.Type<number>;
|
|
30
23
|
}, undefined>;
|
|
31
|
-
export type ChangeSourceTimings = v.Infer<typeof changeSourceTimingsSchema>;
|
|
32
|
-
export type ChangeSourceReport = v.Infer<typeof changeSourceReportSchema>;
|
|
33
|
-
export type ReplicationTimings = v.Infer<typeof replicationTimingsSchema>;
|
|
34
24
|
export type ReplicationReport = v.Infer<typeof replicationReportSchema>;
|
|
25
|
+
export {};
|
|
35
26
|
//# sourceMappingURL=report-schema.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"report-schema.d.ts","sourceRoot":"","sources":["../../../../../../../zero-cache/src/services/replicator/reporter/report-schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,qCAAqC,CAAC;AAEzD,eAAO,MAAM,yBAAyB;;;;aAIpC,CAAC;AAEH,eAAO,MAAM,wBAAwB;;;;;;;aAGnC,CAAC;
|
|
1
|
+
{"version":3,"file":"report-schema.d.ts","sourceRoot":"","sources":["../../../../../../../zero-cache/src/services/replicator/reporter/report-schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,qCAAqC,CAAC;AAEzD,eAAO,MAAM,yBAAyB;;;;aAIpC,CAAC;AAEH,eAAO,MAAM,wBAAwB;;;;;;;aAGnC,CAAC;AAMH,QAAA,MAAM,uBAAuB;;;;;;;;aAG3B,CAAC;AAEH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"report-schema.js","names":[],"sources":["../../../../../../../zero-cache/src/services/replicator/reporter/report-schema.ts"],"sourcesContent":["import * as v from '../../../../../shared/src/valita.ts';\n\nexport const changeSourceTimingsSchema = v.object({\n sendTimeMs: v.number(),\n commitTimeMs: v.number(),\n receiveTimeMs: v.number(),\n});\n\nexport const changeSourceReportSchema = v.object({\n lastTimings: changeSourceTimingsSchema,\n nextSendTimeMs: v.number(),\n});\n\
|
|
1
|
+
{"version":3,"file":"report-schema.js","names":["v"],"sources":["../../../../../../../zero-cache/src/services/replicator/reporter/report-schema.ts"],"sourcesContent":["import * as v from '../../../../../shared/src/valita.ts';\n\nexport const changeSourceTimingsSchema = v.object({\n sendTimeMs: v.number(),\n commitTimeMs: v.number(),\n receiveTimeMs: v.number(),\n});\n\nexport const changeSourceReportSchema = v.object({\n lastTimings: changeSourceTimingsSchema,\n nextSendTimeMs: v.number(),\n});\n\nconst replicationTimingsSchema = changeSourceTimingsSchema.extend({\n replicateTimeMs: v.number(),\n});\n\nconst replicationReportSchema = v.object({\n lastTimings: replicationTimingsSchema.optional(),\n nextSendTimeMs: v.number(),\n});\n\nexport type ReplicationReport = v.Infer<typeof replicationReportSchema>;\n"],"mappings":";;AAEA,IAAa,4BAA4BA,eAAE,OAAO;CAChD,YAAYA,eAAE,OAAO;CACrB,cAAcA,eAAE,OAAO;CACvB,eAAeA,eAAE,OAAO;AAC1B,CAAC;AAED,IAAa,2BAA2BA,eAAE,OAAO;CAC/C,aAAa;CACb,gBAAgBA,eAAE,OAAO;AAC3B,CAAC;AAED,IAAM,2BAA2B,0BAA0B,OAAO,EAChE,iBAAiBA,eAAE,OAAO,EAC5B,CAAC;AAE+BA,eAAE,OAAO;CACvC,aAAa,yBAAyB,SAAS;CAC/C,gBAAgBA,eAAE,OAAO;AAC3B,CAAC"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { unreachable } from "../../../../../shared/src/asserts.js";
|
|
2
2
|
import { BigIntJSON } from "../../../../../shared/src/bigint-json.js";
|
|
3
|
-
import { liteTableName } from "../../../types/names.js";
|
|
4
3
|
import { getOrCreateCounter } from "../../../observability/metrics.js";
|
|
4
|
+
import { liteTableName } from "../../../types/names.js";
|
|
5
5
|
import { backfillRequestsFrom, cookieOps } from "../change-log-cookies.js";
|
|
6
6
|
//#region ../zero-cache/src/services/replicator/schema/backfilling.ts
|
|
7
7
|
var BACKFILLING_TABLE = "_zero.backfilling";
|
|
@@ -227,7 +227,7 @@ function populateBackfillingFromColumnMetadata(lc, db) {
|
|
|
227
227
|
WHERE backfill IS NOT NULL
|
|
228
228
|
ORDER BY table_name, column_name
|
|
229
229
|
`).all();
|
|
230
|
-
const unresolvable = getOrCreateCounter("replica", "backfilling_unresolvable_rows", "In-flight backfills whose upstream table identity could not be recovered from the replica when \"
|
|
230
|
+
const unresolvable = getOrCreateCounter("replica", "backfilling_unresolvable_rows", "In-flight backfills whose upstream table identity could not be recovered from the replica when \"_zero.backfilling\" was created. A best-effort identity is stored; the expected count is 0.");
|
|
231
231
|
if (backfilling.length === 0) {
|
|
232
232
|
unresolvable.add(0);
|
|
233
233
|
return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"backfilling.js","names":["#db","#run","#upsert","#renameTable","#dropTable","#renameColumn","#deleteColumn","#getProgress","#setProgress","#dropColumn"],"sources":["../../../../../../../zero-cache/src/services/replicator/schema/backfilling.ts"],"sourcesContent":["/**\n * The replica's backfill cookie, keyed by upstream identity.\n *\n * `_zero.column_metadata.backfill` already records which columns are being\n * backfilled, and it stays authoritative for `isBackfilling`, which is what the\n * replica's own read paths use. What it cannot do is name the table an upstream\n * would recognize: it is keyed by *lite* table name, and `liteTableName()`\n * collapses the `public` schema and has no inverse anywhere in the tree. A lite\n * name containing a dot is ambiguous — `{public, \"a.b\"}` and `{a, b}` produce\n * the same string — and a table with backfilling columns and no\n * `_zero.tableMetadata` row (legal, since its metadata is optional) cannot be\n * resolved at all.\n *\n * That is the whole of what blocks a change log from being initialized out of a\n * restored replica, so this table carries the identity the reconstruction needs:\n * a straight row copy into the change log's own cookie tables, with nothing to\n * reconstruct and nothing to guess. The replica's copy is the *seed* source; the\n * change log's copy (`replicator/change-log-cookies.ts`) is the *working* set,\n * folded forward from the seed as the log's head advances.\n *\n * The cost is a second copy of `backfill` inside the replica, taken\n * deliberately — though not to save writes: `_zero.column_metadata` is written\n * only by initial sync, the DDL handlers, and backfill completion, so two more\n * columns on it would be free. It is a matter of shape. That table is keyed by\n * lite table name, so `schema`/`table` would be non-key duplicates of its own\n * key, to be held in sync with it across every rename with no answer to which\n * encoding is authoritative. This one is keyed exactly as `cdc.backfilling` and\n * `_zero.changeLogBackfilling` are, which is what makes the change log's\n * initialization comparison a row-set diff rather than a translation, and what\n * lets all three stores interpret the same fold. It also holds in-flight backfills and nothing else,\n * where the same query against `column_metadata` is an unindexed scan over a row\n * per column of every table.\n *\n * This table is write-only from the replica's perspective. Nothing in the\n * replicator reads it; it exists to be read by the change-streamer.\n */\n\nimport type {LogContext} from '@rocicorp/logger';\nimport {unreachable} from '../../../../../shared/src/asserts.ts';\nimport {BigIntJSON} from '../../../../../shared/src/bigint-json.ts';\nimport type {Database, Statement} from '../../../../../zqlite/src/db.ts';\nimport {getOrCreateCounter} from '../../../observability/metrics.ts';\nimport {liteTableName} from '../../../types/names.ts';\nimport type {\n BackfillID,\n BackfillProgressMark,\n Identifier,\n SchemaChange,\n TableMetadata,\n} from '../../change-source/protocol/current/data.ts';\nimport type {BackfillRequest} from '../../change-source/protocol/current/upstream.ts';\nimport {\n backfillRequestsFrom,\n cookieOps,\n type CookieOp,\n type CookieSet,\n} from '../change-log-cookies.ts';\n\nexport const BACKFILLING_TABLE = '_zero.backfilling';\n\n// `backfill` holds the JSON that `cdc.backfilling` holds as JSONB. SQLite has\n// no JSONB, and nothing here queries into the document: it is stored to be\n// handed back to the change source verbatim.\n//\n// `progress` holds the JSON of the BackfillProgressMark up to which the\n// column's backfill data has been received contiguously (see\n// `acceptBackfill()`), or NULL if no data has been received (i.e. the backfill\n// must start from scratch). It is deliberately a separate column from\n// `backfill` so that the cookie set (and its comparison with the change log's\n// cookie jars) is unaffected by it.\nexport const CREATE_BACKFILLING_TABLE = /*sql*/ `\n CREATE TABLE \"${BACKFILLING_TABLE}\" (\n \"schema\" TEXT NOT NULL,\n \"table\" TEXT NOT NULL,\n \"column\" TEXT NOT NULL,\n \"backfill\" TEXT NOT NULL,\n \"progress\" TEXT,\n PRIMARY KEY (\"schema\", \"table\", \"column\")\n );\n`;\n\n/**\n * The replica's interpreter of the cookie fold in\n * `replicator/change-log-cookies.ts`.\n *\n * The fold is shared rather than re-implemented for the same reason the\n * Postgres and SQLite change logs share it: the three stores must agree on every\n * transition forever, and the failure mode when they drift is a backfill that is\n * silently never re-requested, on a column that is then silently never\n * populated. Sharing it makes the replica-versus-Postgres comparison a\n * regression test on the interpreters rather than on three implementations of\n * the same switch.\n *\n * Only the backfill half of the fold is interpreted here. The replica's metadata\n * cookie is `_zero.tableMetadata.upstreamMetadata`, which `TableMetadataTracker`\n * already maintains at the same sites, so an `upsert-metadata` op is inert.\n *\n * Statements are lazily prepared, matching `TableMetadataTracker`: a replica\n * that never sees a schema change never prepares any of them.\n */\nexport class BackfillingTracker {\n readonly #db: Database;\n\n #upsert: Statement | undefined;\n #renameTable: Statement | undefined;\n #dropTable: Statement | undefined;\n #renameColumn: Statement | undefined;\n #dropColumn: Statement | undefined;\n #getProgress: Statement | undefined;\n #setProgress: Statement | undefined;\n\n constructor(db: Database) {\n this.#db = db;\n }\n\n /**\n * Applies the change's backfill-cookie ops, returning the ops that were\n * applied. Changes that carry no backfill state — index changes, metadata-only\n * updates, and the `create-table` / `add-column` variants from a change source\n * that does not support backfill — apply nothing.\n */\n apply(change: SchemaChange): CookieOp[] {\n const ops = cookieOps(change);\n for (const op of ops) {\n this.#run(op);\n }\n return ops;\n }\n\n #run(op: CookieOp): void {\n switch (op.op) {\n case 'upsert-metadata':\n // Maintained by TableMetadataTracker in \"_zero.tableMetadata\".\n break;\n\n case 'upsert-backfill':\n (this.#upsert ??= this.#db.prepare(/*sql*/ `\n INSERT INTO \"${BACKFILLING_TABLE}\"\n (\"schema\", \"table\", \"column\", \"backfill\") VALUES (?, ?, ?, ?)\n ON CONFLICT (\"schema\", \"table\", \"column\")\n DO UPDATE SET \"backfill\" = excluded.\"backfill\", \"progress\" = NULL\n `)).run(\n op.table.schema,\n op.table.name,\n op.column,\n BigIntJSON.stringify(op.backfill),\n );\n break;\n\n case 'rename-table':\n (this.#renameTable ??= this.#db.prepare(/*sql*/ `\n UPDATE \"${BACKFILLING_TABLE}\"\n SET \"schema\" = ?, \"table\" = ? WHERE \"schema\" = ? AND \"table\" = ?\n `)).run(op.new.schema, op.new.name, op.old.schema, op.old.name);\n break;\n\n case 'drop-table':\n (this.#dropTable ??= this.#db.prepare(/*sql*/ `\n DELETE FROM \"${BACKFILLING_TABLE}\"\n WHERE \"schema\" = ? AND \"table\" = ?\n `)).run(op.table.schema, op.table.name);\n break;\n\n case 'rename-column':\n (this.#renameColumn ??= this.#db.prepare(/*sql*/ `\n UPDATE \"${BACKFILLING_TABLE}\" SET \"column\" = ?\n WHERE \"schema\" = ? AND \"table\" = ? AND \"column\" = ?\n `)).run(op.new, op.table.schema, op.table.name, op.old);\n break;\n\n case 'drop-column':\n this.#deleteColumn(op.table, op.column);\n break;\n\n case 'complete-backfill':\n // A per-column delete rather than an `IN` list, which cannot be a\n // single prepared statement across arities. The columns of one\n // completed backfill are few, and this runs only on schema changes.\n for (const column of op.columns) {\n this.#deleteColumn(op.table, column);\n }\n break;\n\n default:\n unreachable(op);\n }\n }\n\n /**\n * Returns the tracked progress of the backfilling columns of the `table`,\n * keyed by column name. Columns that are not backfilling are absent.\n */\n getProgress(\n table: Identifier,\n ): Map<string, BackfillProgressMark | undefined> {\n const rows = (this.#getProgress ??= this.#db.prepare(/*sql*/ `\n SELECT \"column\", \"progress\" FROM \"${BACKFILLING_TABLE}\"\n WHERE \"schema\" = ? AND \"table\" = ?\n `)).all<{column: string; progress: string | null}>(\n table.schema,\n table.name,\n );\n return new Map(\n rows.map(({column, progress}) => [\n column,\n progress === null\n ? undefined\n : (BigIntJSON.parse(progress) as BackfillProgressMark),\n ]),\n );\n }\n\n /** Sets (or clears) the tracked progress of a backfilling column. */\n setProgress(\n table: Identifier,\n column: string,\n progress: BackfillProgressMark | undefined,\n ): void {\n (this.#setProgress ??= this.#db.prepare(/*sql*/ `\n UPDATE \"${BACKFILLING_TABLE}\" SET \"progress\" = ?\n WHERE \"schema\" = ? AND \"table\" = ? AND \"column\" = ?\n `)).run(\n progress === undefined ? null : BigIntJSON.stringify(progress),\n table.schema,\n table.name,\n column,\n );\n }\n\n /**\n * Marks the backfill of the `columns` as complete. This is the subset of\n * a `backfill-completed` message's columns (including row key columns)\n * whose progress is contiguous with the message.\n */\n complete(table: Identifier, columns: readonly string[]): void {\n this.#run({op: 'complete-backfill', table, columns});\n }\n\n #deleteColumn(table: Identifier, column: string): void {\n (this.#dropColumn ??= this.#db.prepare(/*sql*/ `\n DELETE FROM \"${BACKFILLING_TABLE}\"\n WHERE \"schema\" = ? AND \"table\" = ? AND \"column\" = ?\n `)).run(table.schema, table.name, column);\n }\n}\n\n/**\n * Returns the {@link BackfillRequest}s from the current replica cookies. The\n * result has the same shape as the Postgres initialization result.\n *\n * The caller must pair this snapshot with the replica state version. When the\n * replica trails the change log, the comparison applies the missing schema\n * changes before it compares the results.\n */\nexport function readBackfillRequests(db: Database): BackfillRequest[] {\n return backfillRequestsFrom(readReplicaCookies(db));\n}\n\n/**\n * Returns the {@link BackfillRequest}s of the replica's pending backfills,\n * including the tracked progress of each column. These are the backfills that\n * a subscriber reports to the change-streamer when starting a subscription.\n *\n * The caller must pair this snapshot with the replica state version.\n */\nexport function readReplicaBackfills(db: Database): BackfillRequest[] {\n const requests = readBackfillRequests(db);\n const progress = db\n .prepare(/*sql*/ `\n SELECT \"schema\", \"table\", \"column\", \"progress\"\n FROM \"${BACKFILLING_TABLE}\" WHERE \"progress\" IS NOT NULL\n `)\n .all<{schema: string; table: string; column: string; progress: string}>();\n for (const {schema, table, column, progress: mark} of progress) {\n const req = requests.find(\n r => r.table.schema === schema && r.table.name === table,\n );\n const col = req?.columns[column];\n if (col) {\n col.progress = BigIntJSON.parse(mark) as BackfillProgressMark;\n }\n }\n return requests;\n}\n\n/**\n * The replica's whole cookie set, in the shape the change log holds it — the\n * seed a change log would be initialized from, and the replica-derived half of\n * the initialization comparison.\n *\n * The metadata half is filtered on `upstreamMetadata IS NOT NULL` because\n * `_zero.tableMetadata` carries `minRowVersion` as well, so a row exists for\n * every table whose rows were ever force-re-downloaded, whether or not upstream\n * ever sent metadata for it. Neither cookie store can represent that row:\n * `cdc.tableMetadata.\"metadata\"` and `_zero.changeLogTableMetadata.\"metadata\"`\n * are both `NOT NULL`.\n *\n * Only meaningful paired with `_zero.replicationState.stateVersion`, read in\n * the same snapshot (invariant 15).\n */\nexport function readReplicaCookies(db: Database): CookieSet {\n const tableMetadata = db\n .prepare(/*sql*/ `\n SELECT \"schema\", \"table\", \"upstreamMetadata\" AS \"metadata\"\n FROM \"_zero.tableMetadata\"\n WHERE \"upstreamMetadata\" IS NOT NULL\n ORDER BY \"schema\", \"table\"\n `)\n .all<{schema: string; table: string; metadata: string}>()\n .map(({schema, table, metadata}) => ({\n schema,\n table,\n metadata: BigIntJSON.parse(metadata) as TableMetadata,\n }));\n\n const backfilling = db\n .prepare(/*sql*/ `\n SELECT \"schema\", \"table\", \"column\", \"backfill\"\n FROM \"${BACKFILLING_TABLE}\"\n ORDER BY \"schema\", \"table\", \"column\"\n `)\n .all<{schema: string; table: string; column: string; backfill: string}>()\n .map(({schema, table, column, backfill}) => ({\n schema,\n table,\n column,\n backfill: BigIntJSON.parse(backfill) as BackfillID,\n }));\n\n return {tableMetadata, backfilling};\n}\n\n/**\n * Seeds {@link BACKFILLING_TABLE} from `_zero.column_metadata`, resolving each\n * lite table name back to its upstream identity. Used by the v17 migration.\n *\n * The resolution is exact for a table that has a `_zero.tableMetadata` row, and\n * exact for a lite name with no dot in it — `liteTableName()` only omits the\n * schema for `public`. What is left over is an in-flight backfill, on a\n * non-`public` schema, on a table with no metadata row, at the instant of\n * upgrade. Those get the best-effort first-dot split and are counted, because a\n * wrong identity produces a `BackfillRequest` the change source will reject\n * rather than a silently wrong one, and because the initialization comparison\n * surfaces it before anything depends on it. The expected count is zero.\n *\n * A full replace rather than an insert-if-absent: `migrateData` re-runs after a\n * rollback and roll-forward, during which a v16 zero-cache advanced the replica\n * without knowing this table existed. Rebuilding it from `column_metadata` —\n * which that zero-cache *did* maintain — is what makes the re-run both\n * idempotent and correct.\n */\nexport function populateBackfillingFromColumnMetadata(\n lc: LogContext,\n db: Database,\n): void {\n db.prepare(/*sql*/ `DELETE FROM \"${BACKFILLING_TABLE}\"`).run();\n\n const backfilling = db\n .prepare(/*sql*/ `\n SELECT table_name, column_name, backfill FROM \"_zero.column_metadata\"\n WHERE backfill IS NOT NULL\n ORDER BY table_name, column_name\n `)\n .all<{table_name: string; column_name: string; backfill: string}>();\n\n const unresolvable = getOrCreateCounter(\n 'replica',\n 'backfilling_unresolvable_rows',\n 'In-flight backfills whose upstream table identity could not be recovered ' +\n 'from the replica when \"' +\n BACKFILLING_TABLE +\n '\" was created. A best-effort identity is stored; the expected count is 0.',\n );\n if (backfilling.length === 0) {\n unresolvable.add(0); // the common case: publish the series anyway\n return;\n }\n\n const byLiteName = new Map<string, Identifier>(\n db\n .prepare(/*sql*/ `SELECT \"schema\", \"table\" FROM \"_zero.tableMetadata\"`)\n .all<{schema: string; table: string}>()\n .map(({schema, table}) => [\n liteTableName({schema, name: table}),\n {schema, name: table},\n ]),\n );\n\n const insert = db.prepare(/*sql*/ `\n INSERT INTO \"${BACKFILLING_TABLE}\"\n (\"schema\", \"table\", \"column\", \"backfill\") VALUES (?, ?, ?, ?)\n `);\n let unresolved = 0;\n for (const {table_name: liteName, column_name, backfill} of backfilling) {\n const known = byLiteName.get(liteName);\n const dot = known ? -1 : liteName.indexOf('.');\n const table = known ?? {\n schema: dot < 0 ? 'public' : liteName.slice(0, dot),\n name: dot < 0 ? liteName : liteName.slice(dot + 1),\n };\n if (!known && dot >= 0) {\n unresolved++;\n lc.warn?.(\n `no metadata for backfilling table \"${liteName}\"; ` +\n `assuming {schema: \"${table.schema}\", name: \"${table.name}\"}`,\n );\n }\n insert.run(table.schema, table.name, column_name, backfill);\n }\n unresolvable.add(unresolved);\n lc.info?.(\n `seeded \"${BACKFILLING_TABLE}\" with ${backfilling.length} in-flight ` +\n `backfill(s), ${unresolved} of which could not be resolved`,\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"backfilling.js","names":[],"sources":["../../../../../../../zero-cache/src/services/replicator/schema/backfilling.ts"],"sourcesContent":["/**\n * The replica's backfill cookie, keyed by upstream identity.\n *\n * `_zero.column_metadata.backfill` already records which columns are being\n * backfilled, and it stays authoritative for `isBackfilling`, which is what the\n * replica's own read paths use. What it cannot do is name the table an upstream\n * would recognize: it is keyed by *lite* table name, and `liteTableName()`\n * collapses the `public` schema and has no inverse anywhere in the tree. A lite\n * name containing a dot is ambiguous — `{public, \"a.b\"}` and `{a, b}` produce\n * the same string — and a table with backfilling columns and no\n * `_zero.tableMetadata` row (legal, since its metadata is optional) cannot be\n * resolved at all.\n *\n * That is the whole of what blocks a change log from being initialized out of a\n * restored replica, so this table carries the identity the reconstruction needs:\n * a straight row copy into the change log's own cookie tables, with nothing to\n * reconstruct and nothing to guess. The replica's copy is the *seed* source; the\n * change log's copy (`replicator/change-log-cookies.ts`) is the *working* set,\n * folded forward from the seed as the log's head advances.\n *\n * The cost is a second copy of `backfill` inside the replica, taken\n * deliberately — though not to save writes: `_zero.column_metadata` is written\n * only by initial sync, the DDL handlers, and backfill completion, so two more\n * columns on it would be free. It is a matter of shape. That table is keyed by\n * lite table name, so `schema`/`table` would be non-key duplicates of its own\n * key, to be held in sync with it across every rename with no answer to which\n * encoding is authoritative. This one is keyed exactly as `cdc.backfilling` and\n * `_zero.changeLogBackfilling` are, which is what makes the change log's\n * initialization comparison a row-set diff rather than a translation, and what\n * lets all three stores interpret the same fold. It also holds in-flight backfills and nothing else,\n * where the same query against `column_metadata` is an unindexed scan over a row\n * per column of every table.\n *\n * This table is write-only from the replica's perspective. Nothing in the\n * replicator reads it; it exists to be read by the change-streamer.\n */\n\nimport type {LogContext} from '@rocicorp/logger';\nimport {unreachable} from '../../../../../shared/src/asserts.ts';\nimport {BigIntJSON} from '../../../../../shared/src/bigint-json.ts';\nimport type {Database, Statement} from '../../../../../zqlite/src/db.ts';\nimport {getOrCreateCounter} from '../../../observability/metrics.ts';\nimport {liteTableName} from '../../../types/names.ts';\nimport type {\n BackfillID,\n BackfillProgressMark,\n Identifier,\n SchemaChange,\n TableMetadata,\n} from '../../change-source/protocol/current/data.ts';\nimport type {BackfillRequest} from '../../change-source/protocol/current/upstream.ts';\nimport {\n backfillRequestsFrom,\n cookieOps,\n type CookieOp,\n type CookieSet,\n} from '../change-log-cookies.ts';\n\nexport const BACKFILLING_TABLE = '_zero.backfilling';\n\n// `backfill` holds the JSON that `cdc.backfilling` holds as JSONB. SQLite has\n// no JSONB, and nothing here queries into the document: it is stored to be\n// handed back to the change source verbatim.\n//\n// `progress` holds the JSON of the BackfillProgressMark up to which the\n// column's backfill data has been received contiguously (see\n// `acceptBackfill()`), or NULL if no data has been received (i.e. the backfill\n// must start from scratch). It is deliberately a separate column from\n// `backfill` so that the cookie set (and its comparison with the change log's\n// cookie jars) is unaffected by it.\nexport const CREATE_BACKFILLING_TABLE = /*sql*/ `\n CREATE TABLE \"${BACKFILLING_TABLE}\" (\n \"schema\" TEXT NOT NULL,\n \"table\" TEXT NOT NULL,\n \"column\" TEXT NOT NULL,\n \"backfill\" TEXT NOT NULL,\n \"progress\" TEXT,\n PRIMARY KEY (\"schema\", \"table\", \"column\")\n );\n`;\n\n/**\n * The replica's interpreter of the cookie fold in\n * `replicator/change-log-cookies.ts`.\n *\n * The fold is shared rather than re-implemented for the same reason the\n * Postgres and SQLite change logs share it: the three stores must agree on every\n * transition forever, and the failure mode when they drift is a backfill that is\n * silently never re-requested, on a column that is then silently never\n * populated. Sharing it makes the replica-versus-Postgres comparison a\n * regression test on the interpreters rather than on three implementations of\n * the same switch.\n *\n * Only the backfill half of the fold is interpreted here. The replica's metadata\n * cookie is `_zero.tableMetadata.upstreamMetadata`, which `TableMetadataTracker`\n * already maintains at the same sites, so an `upsert-metadata` op is inert.\n *\n * Statements are lazily prepared, matching `TableMetadataTracker`: a replica\n * that never sees a schema change never prepares any of them.\n */\nexport class BackfillingTracker {\n readonly #db: Database;\n\n #upsert: Statement | undefined;\n #renameTable: Statement | undefined;\n #dropTable: Statement | undefined;\n #renameColumn: Statement | undefined;\n #dropColumn: Statement | undefined;\n #getProgress: Statement | undefined;\n #setProgress: Statement | undefined;\n\n constructor(db: Database) {\n this.#db = db;\n }\n\n /**\n * Applies the change's backfill-cookie ops, returning the ops that were\n * applied. Changes that carry no backfill state — index changes, metadata-only\n * updates, and the `create-table` / `add-column` variants from a change source\n * that does not support backfill — apply nothing.\n */\n apply(change: SchemaChange): CookieOp[] {\n const ops = cookieOps(change);\n for (const op of ops) {\n this.#run(op);\n }\n return ops;\n }\n\n #run(op: CookieOp): void {\n switch (op.op) {\n case 'upsert-metadata':\n // Maintained by TableMetadataTracker in \"_zero.tableMetadata\".\n break;\n\n case 'upsert-backfill':\n (this.#upsert ??= this.#db.prepare(/*sql*/ `\n INSERT INTO \"${BACKFILLING_TABLE}\"\n (\"schema\", \"table\", \"column\", \"backfill\") VALUES (?, ?, ?, ?)\n ON CONFLICT (\"schema\", \"table\", \"column\")\n DO UPDATE SET \"backfill\" = excluded.\"backfill\", \"progress\" = NULL\n `)).run(\n op.table.schema,\n op.table.name,\n op.column,\n BigIntJSON.stringify(op.backfill),\n );\n break;\n\n case 'rename-table':\n (this.#renameTable ??= this.#db.prepare(/*sql*/ `\n UPDATE \"${BACKFILLING_TABLE}\"\n SET \"schema\" = ?, \"table\" = ? WHERE \"schema\" = ? AND \"table\" = ?\n `)).run(op.new.schema, op.new.name, op.old.schema, op.old.name);\n break;\n\n case 'drop-table':\n (this.#dropTable ??= this.#db.prepare(/*sql*/ `\n DELETE FROM \"${BACKFILLING_TABLE}\"\n WHERE \"schema\" = ? AND \"table\" = ?\n `)).run(op.table.schema, op.table.name);\n break;\n\n case 'rename-column':\n (this.#renameColumn ??= this.#db.prepare(/*sql*/ `\n UPDATE \"${BACKFILLING_TABLE}\" SET \"column\" = ?\n WHERE \"schema\" = ? AND \"table\" = ? AND \"column\" = ?\n `)).run(op.new, op.table.schema, op.table.name, op.old);\n break;\n\n case 'drop-column':\n this.#deleteColumn(op.table, op.column);\n break;\n\n case 'complete-backfill':\n // A per-column delete rather than an `IN` list, which cannot be a\n // single prepared statement across arities. The columns of one\n // completed backfill are few, and this runs only on schema changes.\n for (const column of op.columns) {\n this.#deleteColumn(op.table, column);\n }\n break;\n\n default:\n unreachable(op);\n }\n }\n\n /**\n * Returns the tracked progress of the backfilling columns of the `table`,\n * keyed by column name. Columns that are not backfilling are absent.\n */\n getProgress(\n table: Identifier,\n ): Map<string, BackfillProgressMark | undefined> {\n const rows = (this.#getProgress ??= this.#db.prepare(/*sql*/ `\n SELECT \"column\", \"progress\" FROM \"${BACKFILLING_TABLE}\"\n WHERE \"schema\" = ? AND \"table\" = ?\n `)).all<{column: string; progress: string | null}>(\n table.schema,\n table.name,\n );\n return new Map(\n rows.map(({column, progress}) => [\n column,\n progress === null\n ? undefined\n : (BigIntJSON.parse(progress) as BackfillProgressMark),\n ]),\n );\n }\n\n /** Sets (or clears) the tracked progress of a backfilling column. */\n setProgress(\n table: Identifier,\n column: string,\n progress: BackfillProgressMark | undefined,\n ): void {\n (this.#setProgress ??= this.#db.prepare(/*sql*/ `\n UPDATE \"${BACKFILLING_TABLE}\" SET \"progress\" = ?\n WHERE \"schema\" = ? AND \"table\" = ? AND \"column\" = ?\n `)).run(\n progress === undefined ? null : BigIntJSON.stringify(progress),\n table.schema,\n table.name,\n column,\n );\n }\n\n /**\n * Marks the backfill of the `columns` as complete. This is the subset of\n * a `backfill-completed` message's columns (including row key columns)\n * whose progress is contiguous with the message.\n */\n complete(table: Identifier, columns: readonly string[]): void {\n this.#run({op: 'complete-backfill', table, columns});\n }\n\n #deleteColumn(table: Identifier, column: string): void {\n (this.#dropColumn ??= this.#db.prepare(/*sql*/ `\n DELETE FROM \"${BACKFILLING_TABLE}\"\n WHERE \"schema\" = ? AND \"table\" = ? AND \"column\" = ?\n `)).run(table.schema, table.name, column);\n }\n}\n\n/**\n * Returns the {@link BackfillRequest}s from the current replica cookies. The\n * result has the same shape as the Postgres initialization result.\n *\n * The caller must pair this snapshot with the replica state version. When the\n * replica trails the change log, the comparison applies the missing schema\n * changes before it compares the results.\n */\nexport function readBackfillRequests(db: Database): BackfillRequest[] {\n return backfillRequestsFrom(readReplicaCookies(db));\n}\n\n/**\n * Returns the {@link BackfillRequest}s of the replica's pending backfills,\n * including the tracked progress of each column. These are the backfills that\n * a subscriber reports to the change-streamer when starting a subscription.\n *\n * The caller must pair this snapshot with the replica state version.\n */\nexport function readReplicaBackfills(db: Database): BackfillRequest[] {\n const requests = readBackfillRequests(db);\n const progress = db\n .prepare(/*sql*/ `\n SELECT \"schema\", \"table\", \"column\", \"progress\"\n FROM \"${BACKFILLING_TABLE}\" WHERE \"progress\" IS NOT NULL\n `)\n .all<{schema: string; table: string; column: string; progress: string}>();\n for (const {schema, table, column, progress: mark} of progress) {\n const req = requests.find(\n r => r.table.schema === schema && r.table.name === table,\n );\n const col = req?.columns[column];\n if (col) {\n col.progress = BigIntJSON.parse(mark) as BackfillProgressMark;\n }\n }\n return requests;\n}\n\n/**\n * The replica's whole cookie set, in the shape the change log holds it — the\n * seed a change log would be initialized from, and the replica-derived half of\n * the initialization comparison.\n *\n * The metadata half is filtered on `upstreamMetadata IS NOT NULL` because\n * `_zero.tableMetadata` carries `minRowVersion` as well, so a row exists for\n * every table whose rows were ever force-re-downloaded, whether or not upstream\n * ever sent metadata for it. Neither cookie store can represent that row:\n * `cdc.tableMetadata.\"metadata\"` and `_zero.changeLogTableMetadata.\"metadata\"`\n * are both `NOT NULL`.\n *\n * Only meaningful paired with `_zero.replicationState.stateVersion`, read in\n * the same snapshot (invariant 15).\n */\nexport function readReplicaCookies(db: Database): CookieSet {\n const tableMetadata = db\n .prepare(/*sql*/ `\n SELECT \"schema\", \"table\", \"upstreamMetadata\" AS \"metadata\"\n FROM \"_zero.tableMetadata\"\n WHERE \"upstreamMetadata\" IS NOT NULL\n ORDER BY \"schema\", \"table\"\n `)\n .all<{schema: string; table: string; metadata: string}>()\n .map(({schema, table, metadata}) => ({\n schema,\n table,\n metadata: BigIntJSON.parse(metadata) as TableMetadata,\n }));\n\n const backfilling = db\n .prepare(/*sql*/ `\n SELECT \"schema\", \"table\", \"column\", \"backfill\"\n FROM \"${BACKFILLING_TABLE}\"\n ORDER BY \"schema\", \"table\", \"column\"\n `)\n .all<{schema: string; table: string; column: string; backfill: string}>()\n .map(({schema, table, column, backfill}) => ({\n schema,\n table,\n column,\n backfill: BigIntJSON.parse(backfill) as BackfillID,\n }));\n\n return {tableMetadata, backfilling};\n}\n\n/**\n * Seeds {@link BACKFILLING_TABLE} from `_zero.column_metadata`, resolving each\n * lite table name back to its upstream identity. Used by the v17 migration.\n *\n * The resolution is exact for a table that has a `_zero.tableMetadata` row, and\n * exact for a lite name with no dot in it — `liteTableName()` only omits the\n * schema for `public`. What is left over is an in-flight backfill, on a\n * non-`public` schema, on a table with no metadata row, at the instant of\n * upgrade. Those get the best-effort first-dot split and are counted, because a\n * wrong identity produces a `BackfillRequest` the change source will reject\n * rather than a silently wrong one, and because the initialization comparison\n * surfaces it before anything depends on it. The expected count is zero.\n *\n * A full replace rather than an insert-if-absent: `migrateData` re-runs after a\n * rollback and roll-forward, during which a v16 zero-cache advanced the replica\n * without knowing this table existed. Rebuilding it from `column_metadata` —\n * which that zero-cache *did* maintain — is what makes the re-run both\n * idempotent and correct.\n */\nexport function populateBackfillingFromColumnMetadata(\n lc: LogContext,\n db: Database,\n): void {\n db.prepare(/*sql*/ `DELETE FROM \"${BACKFILLING_TABLE}\"`).run();\n\n const backfilling = db\n .prepare(/*sql*/ `\n SELECT table_name, column_name, backfill FROM \"_zero.column_metadata\"\n WHERE backfill IS NOT NULL\n ORDER BY table_name, column_name\n `)\n .all<{table_name: string; column_name: string; backfill: string}>();\n\n const unresolvable = getOrCreateCounter(\n 'replica',\n 'backfilling_unresolvable_rows',\n 'In-flight backfills whose upstream table identity could not be recovered ' +\n 'from the replica when \"' +\n BACKFILLING_TABLE +\n '\" was created. A best-effort identity is stored; the expected count is 0.',\n );\n if (backfilling.length === 0) {\n unresolvable.add(0); // the common case: publish the series anyway\n return;\n }\n\n const byLiteName = new Map<string, Identifier>(\n db\n .prepare(/*sql*/ `SELECT \"schema\", \"table\" FROM \"_zero.tableMetadata\"`)\n .all<{schema: string; table: string}>()\n .map(({schema, table}) => [\n liteTableName({schema, name: table}),\n {schema, name: table},\n ]),\n );\n\n const insert = db.prepare(/*sql*/ `\n INSERT INTO \"${BACKFILLING_TABLE}\"\n (\"schema\", \"table\", \"column\", \"backfill\") VALUES (?, ?, ?, ?)\n `);\n let unresolved = 0;\n for (const {table_name: liteName, column_name, backfill} of backfilling) {\n const known = byLiteName.get(liteName);\n const dot = known ? -1 : liteName.indexOf('.');\n const table = known ?? {\n schema: dot < 0 ? 'public' : liteName.slice(0, dot),\n name: dot < 0 ? liteName : liteName.slice(dot + 1),\n };\n if (!known && dot >= 0) {\n unresolved++;\n lc.warn?.(\n `no metadata for backfilling table \"${liteName}\"; ` +\n `assuming {schema: \"${table.schema}\", name: \"${table.name}\"}`,\n );\n }\n insert.run(table.schema, table.name, column_name, backfill);\n }\n unresolvable.add(unresolved);\n lc.info?.(\n `seeded \"${BACKFILLING_TABLE}\" with ${backfilling.length} in-flight ` +\n `backfill(s), ${unresolved} of which could not be resolved`,\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { type JSONValue } from '../../../../../shared/src/bigint-json.ts';
|
|
2
2
|
import type { Database } from '../../../../../zqlite/src/db.ts';
|
|
3
3
|
import type { LexiVersion } from '../../../types/lexi-version.ts';
|
|
4
4
|
import type { LiteRowKey } from '../../../types/lite.ts';
|
|
@@ -43,21 +43,24 @@ export declare const CREATE_CHANGELOG_SCHEMA = "\n CREATE TABLE \"_zero.changeL
|
|
|
43
43
|
* fields are excluded, though the query should be ordered by
|
|
44
44
|
* `<stateVersion, pos>`.
|
|
45
45
|
*/
|
|
46
|
-
export
|
|
47
|
-
stateVersion: string;
|
|
48
|
-
table: string;
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
46
|
+
export type ChangeLogEntry = {
|
|
47
|
+
readonly stateVersion: string;
|
|
48
|
+
readonly table: string;
|
|
49
|
+
readonly rowKey: Readonly<Record<string, JSONValue>>;
|
|
50
|
+
readonly op: typeof SET_OP | typeof DEL_OP;
|
|
51
|
+
} | {
|
|
52
|
+
readonly stateVersion: string;
|
|
53
|
+
readonly table: string;
|
|
54
|
+
readonly rowKey: null;
|
|
55
|
+
readonly op: typeof TRUNCATE_OP | typeof RESET_OP;
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* The {@link ChangeLogEntry} for the columns of a change log row. This does
|
|
59
|
+
* not validate what zero-cache itself wrote: the columns are
|
|
60
|
+
* `TEXT NOT NULL`, and `rowKey` is the JSON of an object (see
|
|
61
|
+
* {@link ChangeLog}).
|
|
62
|
+
*/
|
|
63
|
+
export declare function parseChangeLogEntry(stateVersion: string, table: string, rowKey: string, op: string): ChangeLogEntry;
|
|
61
64
|
export declare class ChangeLog {
|
|
62
65
|
#private;
|
|
63
66
|
constructor(db: Database);
|
|
@@ -84,5 +87,4 @@ export declare class ChangeLog {
|
|
|
84
87
|
logTruncateOp(version: LexiVersion, table: string): void;
|
|
85
88
|
logResetOp(version: LexiVersion, table: string): void;
|
|
86
89
|
}
|
|
87
|
-
export {};
|
|
88
90
|
//# sourceMappingURL=change-log.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"change-log.d.ts","sourceRoot":"","sources":["../../../../../../../zero-cache/src/services/replicator/schema/change-log.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"change-log.d.ts","sourceRoot":"","sources":["../../../../../../../zero-cache/src/services/replicator/schema/change-log.ts"],"names":[],"mappings":"AACA,OAAO,EAGL,KAAK,SAAS,EACf,MAAM,0CAA0C,CAAC;AAElD,OAAO,KAAK,EAAC,QAAQ,EAAY,MAAM,iCAAiC,CAAC;AACzE,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,gCAAgC,CAAC;AAChE,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,wBAAwB,CAAC;AAGvD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,eAAO,MAAM,MAAM,MAAM,CAAC;AAC1B,eAAO,MAAM,MAAM,MAAM,CAAC;AAC1B,eAAO,MAAM,WAAW,MAAM,CAAC;AAC/B,eAAO,MAAM,QAAQ,MAAM,CAAC;AAG5B,eAAO,MAAM,uBAAuB,sbAmCjC,CAAC;AAEJ;;;;;GAKG;AACH,MAAM,MAAM,cAAc,GACtB;IACE,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC;IACrD,QAAQ,CAAC,EAAE,EAAE,OAAO,MAAM,GAAG,OAAO,MAAM,CAAC;CAC5C,GACD;IACE,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAEvB,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC;IACtB,QAAQ,CAAC,EAAE,EAAE,OAAO,WAAW,GAAG,OAAO,QAAQ,CAAC;CACnD,CAAC;AAEN;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,EAAE,EAAE,MAAM,GACT,cAAc,CAWhB;AAqBD,qBAAa,SAAS;;IAMpB,YAAY,EAAE,EAAE,QAAQ,EAqCvB;IAED;;;;;;;;;;OAUG;IACH,QAAQ,CACN,OAAO,EAAE,WAAW,EACpB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,UAAU,EACf,UAAU,EAAE,MAAM,EAAE,GAAG,SAAS,GAC/B,MAAM,CAER;IAED,WAAW,CACT,OAAO,EAAE,WAAW,EACpB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,UAAU,GACd,MAAM,CAKR;IAED,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU;;;;;;kBAM5C;IA8BD,aAAa,CAAC,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,QAEhD;IAED,UAAU,CAAC,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,QAE7C;CACF"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { assert } from "../../../../../shared/src/asserts.js";
|
|
1
2
|
import { literalUnion, parse, valita_exports } from "../../../../../shared/src/valita.js";
|
|
2
|
-
import {
|
|
3
|
+
import { parse as parse$1, stringify } from "../../../../../shared/src/bigint-json.js";
|
|
3
4
|
import { normalizedKeyOrder } from "../../../types/row-key.js";
|
|
4
5
|
var CREATE_CHANGELOG_SCHEMA = `
|
|
5
6
|
CREATE TABLE "_zero.changeLog2" (
|
|
@@ -14,20 +15,35 @@ var CREATE_CHANGELOG_SCHEMA = `
|
|
|
14
15
|
);
|
|
15
16
|
`;
|
|
16
17
|
/**
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
18
|
+
* The {@link ChangeLogEntry} for the columns of a change log row. This does
|
|
19
|
+
* not validate what zero-cache itself wrote: the columns are
|
|
20
|
+
* `TEXT NOT NULL`, and `rowKey` is the JSON of an object (see
|
|
21
|
+
* {@link ChangeLog}).
|
|
21
22
|
*/
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}
|
|
23
|
+
function parseChangeLogEntry(stateVersion, table, rowKey, op) {
|
|
24
|
+
switch (op) {
|
|
25
|
+
case "s":
|
|
26
|
+
case "d": return {
|
|
27
|
+
stateVersion,
|
|
28
|
+
table,
|
|
29
|
+
rowKey: parseRowKey(rowKey),
|
|
30
|
+
op
|
|
31
|
+
};
|
|
32
|
+
case "t":
|
|
33
|
+
case "r": return {
|
|
34
|
+
stateVersion,
|
|
35
|
+
table,
|
|
36
|
+
rowKey: null,
|
|
37
|
+
op
|
|
38
|
+
};
|
|
39
|
+
default: throw new Error(`Invalid change log op "${op}" for table "${table}"`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function parseRowKey(rowKey) {
|
|
43
|
+
const key = parse$1(rowKey);
|
|
44
|
+
assert(typeof key === "object" && key !== null && !Array.isArray(key), () => `Invalid change log rowKey ${rowKey}`);
|
|
45
|
+
return key;
|
|
46
|
+
}
|
|
31
47
|
var rawChangeLogEntrySchema = valita_exports.object({
|
|
32
48
|
stateVersion: valita_exports.string(),
|
|
33
49
|
table: valita_exports.string(),
|
|
@@ -128,6 +144,6 @@ var ChangeLog = class {
|
|
|
128
144
|
}
|
|
129
145
|
};
|
|
130
146
|
//#endregion
|
|
131
|
-
export { CREATE_CHANGELOG_SCHEMA, ChangeLog,
|
|
147
|
+
export { CREATE_CHANGELOG_SCHEMA, ChangeLog, parseChangeLogEntry };
|
|
132
148
|
|
|
133
149
|
//# sourceMappingURL=change-log.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"change-log.js","names":["#logRowOpStmt","#logRowOpWithBackfillStmt","#logTableWideOpStmt","#getRowOpStmt","#logRowOp"],"sources":["../../../../../../../zero-cache/src/services/replicator/schema/change-log.ts"],"sourcesContent":["import {\n jsonObjectSchema,\n parse,\n stringify,\n} from '../../../../../shared/src/bigint-json.ts';\nimport * as v from '../../../../../shared/src/valita.ts';\nimport type {Database, Statement} from '../../../../../zqlite/src/db.ts';\nimport type {LexiVersion} from '../../../types/lexi-version.ts';\nimport type {LiteRowKey} from '../../../types/lite.ts';\nimport {normalizedKeyOrder} from '../../../types/row-key.ts';\n\n/**\n * The Change Log tracks the last operation (set or delete) for each row in the\n * data base, ordered by state version; in other words, a cross-table\n * index of row changes ordered by version. This facilitates a minimal \"diff\"\n * of row changes needed to advance a pipeline from one state version to another.\n *\n * The Change Log stores identifiers only, i.e. it does not store contents.\n * A database snapshot at the previous version can be used to query a row's\n * old contents, if any, and the current snapshot can be used to query a row's\n * new contents. (In the common case, the new contents will have just been applied\n * and thus has a high likelihood of being in the SQLite cache.)\n *\n * There are two table-wide operations:\n * - `t` corresponds to the postgres `TRUNCATE` operation\n * - `r` represents any schema (i.e. column) change\n *\n * For both operations, the corresponding row changes are not explicitly included\n * in the change log. The consumer has the option of simulating them be reading\n * from pre- and post- snapshots, or resetting their state entirely with the current\n * snapshot.\n *\n * To achieve the desired ordering semantics when processing tables that have been\n * truncated, reset, and modified, the \"rowKey\" is set to `null` for resets and\n * the empty string `\"\"` for truncates. This means that resets will be encountered\n * before truncates, which will be processed before any subsequent row changes.\n *\n * This ordering is chosen because resets are currently the more \"destructive\" op\n * and result in aborting the processing (and starting from scratch); doing this\n * earlier reduces wasted work.\n */\n\nexport const SET_OP = 's';\nexport const DEL_OP = 'd';\nexport const TRUNCATE_OP = 't';\nexport const RESET_OP = 'r';\n\n// Exported for testing (and migrations)\nexport const CREATE_CHANGELOG_SCHEMA =\n // stateVersion : a.k.a. row version\n // pos : order in which to process the change (within the version)\n // table : The table associated with the change\n // rowKey : JSON row key for a row change. For table-wide changes RESET\n // and TRUNCATE, there is no associated row; instead, `pos` is\n // set to -1 and the rowKey is set to the stateVersion,\n // guaranteeing when attempting to process the transaction,\n // the pipeline is reset (and the change log traversal\n // aborted).\n // op : 's' for set (insert/update)\n // : 'd' for delete\n // : 'r' for table reset (schema change)\n // : 't' for table truncation (which also resets the pipeline)\n // backfillingColumnVersions\n // : A JSON mapping from column name to stateVersion tracked\n // for replicated writes of columns that are being backfilled.\n // This is used to prevent backfill data, which is at a\n // fixed snapshot/version outside of the replication stream,\n // from overwriting newer column values.\n //\n // Naming note: To maintain compatibility between a new replication-manager\n // and old view-syncers, the previous _zero.changeLog table is preserved\n // and its replacement given a new name \"changeLog2\".\n `\n CREATE TABLE \"_zero.changeLog2\" (\n \"stateVersion\" TEXT NOT NULL,\n \"pos\" INT NOT NULL,\n \"table\" TEXT NOT NULL,\n \"rowKey\" TEXT NOT NULL,\n \"op\" TEXT NOT NULL,\n \"backfillingColumnVersions\" TEXT DEFAULT '{}',\n PRIMARY KEY(\"stateVersion\", \"pos\"),\n UNIQUE(\"table\", \"rowKey\")\n );\n `;\n\n/**\n * Contains the changeLog fields relevant for computing the diff between\n * two snapshots of a replica. The `pos` and `backfillingColumnVersions`\n * fields are excluded, though the query should be ordered by\n * `<stateVersion, pos>`.\n */\nexport const changeLogEntrySchema = v\n .object({\n stateVersion: v.string(),\n table: v.string(),\n rowKey: v.string(),\n op: v.literalUnion(SET_OP, DEL_OP, TRUNCATE_OP, RESET_OP),\n })\n .map(val => ({\n ...val,\n // Note: sets the rowKey to `null` for table-wide ops / resets\n rowKey:\n val.op === 't' || val.op === 'r'\n ? null\n : v.parse(parse(val.rowKey), jsonObjectSchema),\n }));\n\nexport type ChangeLogEntry = v.Infer<typeof changeLogEntrySchema>;\n\nconst rawChangeLogEntrySchema = v.object({\n stateVersion: v.string(),\n table: v.string(),\n rowKey: v.string(),\n op: v.literalUnion(SET_OP, DEL_OP, TRUNCATE_OP, RESET_OP),\n backfillingColumnVersions: v\n .string()\n .map(val => v.record(v.string()).parse(JSON.parse(val))),\n});\n\nexport type RawChangeLogEntry = v.Infer<typeof rawChangeLogEntrySchema>;\n\nexport class ChangeLog {\n readonly #logRowOpStmt: Statement;\n readonly #logRowOpWithBackfillStmt: Statement;\n readonly #logTableWideOpStmt;\n readonly #getRowOpStmt: Statement;\n\n constructor(db: Database) {\n this.#logRowOpStmt = db.prepare(/*sql*/ `\n INSERT OR REPLACE INTO \"_zero.changeLog2\" \n (stateVersion, pos, \"table\", rowKey, op)\n VALUES (@version, @pos, @table, JSON(@rowKey), @op)\n `);\n\n this.#logRowOpWithBackfillStmt = db.prepare(/*sql*/ `\n INSERT INTO \"_zero.changeLog2\" \n (stateVersion, pos, \"table\", rowKey, op, backfillingColumnVersions)\n VALUES (@version, @pos, @table, JSON(@rowKey), @op, \n JSON(@backfillingColumnVersions))\n ON CONFLICT (\"table\", rowKey) DO UPDATE \n SET stateVersion = excluded.stateVersion,\n pos = excluded.pos,\n op = excluded.op,\n backfillingColumnVersions = json_patch(\n backfillingColumnVersions, excluded.backfillingColumnVersions)\n `);\n\n // Because table-wide ops result in aborting an incremental update\n // and rehydrating all queries at \"head\", they are assigned pos = -1\n // as an optimization to abort as early as possible to skip unnecessary\n // updates.\n //\n // However, changeLog entries that are destined to be \"skipped\" are\n // nonetheless kept for the purpose of tracking backfillingColumnVersions.\n this.#logTableWideOpStmt = db.prepare(/*sql*/ `\n INSERT OR REPLACE INTO \"_zero.changeLog2\" \n (stateVersion, pos, \"table\", rowKey, op) \n VALUES (@version, -1, @table, @version, @op)\n `);\n\n // oxlint-disable-next-line zero/no-select-star -- Local SQLite replica query; not run through pg prepared statements.\n this.#getRowOpStmt = db.prepare(/*sql*/ `\n SELECT * FROM \"_zero.changeLog2\" WHERE \"table\" = ? AND \"rowKey\" = JSON(?)\n `);\n }\n\n /**\n *\n * @param backfilled The backfilling columns for which values were set. Note\n * that an empty list and the `undefined` value mean different things;\n * * An empty list indicates that a backfill is in progress but no\n * backfilling values were set. In this case, existing\n * backfillingColumnVersions are preserved.\n * * `undefined` indicates that there are no columns being backfilled.\n * In this case, any vestigial `backfillingColumnVersions` value\n * is cleared.\n */\n logSetOp(\n version: LexiVersion,\n pos: number,\n table: string,\n row: LiteRowKey,\n backfilled: string[] | undefined,\n ): string {\n return this.#logRowOp(version, pos, table, row, SET_OP, backfilled);\n }\n\n logDeleteOp(\n version: LexiVersion,\n pos: number,\n table: string,\n row: LiteRowKey,\n ): string {\n // Note: For delete ops, it is always safe to clear the\n // backfillingColumnVersions because the backfill algorithm\n // understands that deletes apply to the whole row.\n return this.#logRowOp(version, pos, table, row, DEL_OP, undefined);\n }\n\n getLatestRowOp(table: string, row: LiteRowKey) {\n const rowKey = stringify(normalizedKeyOrder(row));\n const result = this.#getRowOpStmt.get(table, rowKey);\n return result === undefined\n ? undefined\n : v.parse(result, rawChangeLogEntrySchema, 'passthrough');\n }\n\n #logRowOp(\n version: LexiVersion,\n pos: number,\n table: string,\n row: LiteRowKey,\n op: string,\n backfilled: string[] | undefined,\n ): string {\n const rowKey = stringify(normalizedKeyOrder(row));\n if (backfilled === undefined) {\n this.#logRowOpStmt.run({version, pos, table, rowKey, op});\n } else {\n const versions: Record<string, string> = {};\n for (const col of backfilled) {\n versions[col] = version;\n }\n this.#logRowOpWithBackfillStmt.run({\n version,\n pos,\n table,\n rowKey,\n op,\n backfillingColumnVersions: JSON.stringify(versions),\n });\n }\n return rowKey;\n }\n\n logTruncateOp(version: LexiVersion, table: string) {\n this.#logTableWideOpStmt.run({version, table, op: TRUNCATE_OP});\n }\n\n logResetOp(version: LexiVersion, table: string) {\n this.#logTableWideOpStmt.run({version, table, op: RESET_OP});\n }\n}\n"],"mappings":";;;AAgDA,IAAa,0BAwBX;;;;;;;;;;;;;;;;;;AAmBF,IAAa,uBAAuB,eACjC,OAAO;CACN,cAAc,eAAE,OAAO;CACvB,OAAO,eAAE,OAAO;CAChB,QAAQ,eAAE,OAAO;CACjB,IAAI,aAAA,KAAA,KAAA,KAAA,GAAoD;AAC1D,CAAC,EACA,KAAI,SAAQ;CACX,GAAG;CAEH,QACE,IAAI,OAAO,OAAO,IAAI,OAAO,MACzB,OACA,MAAQ,QAAM,IAAI,MAAM,GAAG,gBAAgB;AACnD,EAAE;AAIJ,IAAM,0BAA0B,eAAE,OAAO;CACvC,cAAc,eAAE,OAAO;CACvB,OAAO,eAAE,OAAO;CAChB,QAAQ,eAAE,OAAO;CACjB,IAAI,aAAA,KAAA,KAAA,KAAA,GAAoD;CACxD,2BAA2B,eACxB,OAAO,EACP,KAAI,QAAO,eAAE,OAAO,eAAE,OAAO,CAAC,EAAE,MAAM,KAAK,MAAM,GAAG,CAAC,CAAC;AAC3D,CAAC;AAID,IAAa,YAAb,MAAuB;CACrB;CACA;CACA;CACA;CAEA,YAAY,IAAc;EACxB,KAAKA,gBAAgB,GAAG,QAAgB;;;;KAIvC;EAED,KAAKC,4BAA4B,GAAG,QAAgB;;;;;;;;;;;KAWnD;EASD,KAAKC,sBAAsB,GAAG,QAAgB;;;;KAI7C;EAGD,KAAKC,gBAAgB,GAAG,QAAgB;;KAEvC;CACH;;;;;;;;;;;;CAaA,SACE,SACA,KACA,OACA,KACA,YACQ;EACR,OAAO,KAAKC,UAAU,SAAS,KAAK,OAAO,KAAA,KAAa,UAAU;CACpE;CAEA,YACE,SACA,KACA,OACA,KACQ;EAIR,OAAO,KAAKA,UAAU,SAAS,KAAK,OAAO,KAAA,KAAa,KAAA,CAAS;CACnE;CAEA,eAAe,OAAe,KAAiB;EAC7C,MAAM,SAAS,UAAU,mBAAmB,GAAG,CAAC;EAChD,MAAM,SAAS,KAAKD,cAAc,IAAI,OAAO,MAAM;EACnD,OAAO,WAAW,KAAA,IACd,KAAA,IACA,MAAQ,QAAQ,yBAAyB,aAAa;CAC5D;CAEA,UACE,SACA,KACA,OACA,KACA,IACA,YACQ;EACR,MAAM,SAAS,UAAU,mBAAmB,GAAG,CAAC;EAChD,IAAI,eAAe,KAAA,GACjB,KAAKH,cAAc,IAAI;GAAC;GAAS;GAAK;GAAO;GAAQ;EAAE,CAAC;OACnD;GACL,MAAM,WAAmC,CAAC;GAC1C,KAAK,MAAM,OAAO,YAChB,SAAS,OAAO;GAElB,KAAKC,0BAA0B,IAAI;IACjC;IACA;IACA;IACA;IACA;IACA,2BAA2B,KAAK,UAAU,QAAQ;GACpD,CAAC;EACH;EACA,OAAO;CACT;CAEA,cAAc,SAAsB,OAAe;EACjD,KAAKC,oBAAoB,IAAI;GAAC;GAAS;GAAO,IAAA;EAAe,CAAC;CAChE;CAEA,WAAW,SAAsB,OAAe;EAC9C,KAAKA,oBAAoB,IAAI;GAAC;GAAS;GAAO,IAAA;EAAY,CAAC;CAC7D;AACF"}
|
|
1
|
+
{"version":3,"file":"change-log.js","names":["parse","v","v.literalUnion","v.parse"],"sources":["../../../../../../../zero-cache/src/services/replicator/schema/change-log.ts"],"sourcesContent":["import {assert} from '../../../../../shared/src/asserts.ts';\nimport {\n parse,\n stringify,\n type JSONValue,\n} from '../../../../../shared/src/bigint-json.ts';\nimport * as v from '../../../../../shared/src/valita.ts';\nimport type {Database, Statement} from '../../../../../zqlite/src/db.ts';\nimport type {LexiVersion} from '../../../types/lexi-version.ts';\nimport type {LiteRowKey} from '../../../types/lite.ts';\nimport {normalizedKeyOrder} from '../../../types/row-key.ts';\n\n/**\n * The Change Log tracks the last operation (set or delete) for each row in the\n * data base, ordered by state version; in other words, a cross-table\n * index of row changes ordered by version. This facilitates a minimal \"diff\"\n * of row changes needed to advance a pipeline from one state version to another.\n *\n * The Change Log stores identifiers only, i.e. it does not store contents.\n * A database snapshot at the previous version can be used to query a row's\n * old contents, if any, and the current snapshot can be used to query a row's\n * new contents. (In the common case, the new contents will have just been applied\n * and thus has a high likelihood of being in the SQLite cache.)\n *\n * There are two table-wide operations:\n * - `t` corresponds to the postgres `TRUNCATE` operation\n * - `r` represents any schema (i.e. column) change\n *\n * For both operations, the corresponding row changes are not explicitly included\n * in the change log. The consumer has the option of simulating them be reading\n * from pre- and post- snapshots, or resetting their state entirely with the current\n * snapshot.\n *\n * To achieve the desired ordering semantics when processing tables that have been\n * truncated, reset, and modified, the \"rowKey\" is set to `null` for resets and\n * the empty string `\"\"` for truncates. This means that resets will be encountered\n * before truncates, which will be processed before any subsequent row changes.\n *\n * This ordering is chosen because resets are currently the more \"destructive\" op\n * and result in aborting the processing (and starting from scratch); doing this\n * earlier reduces wasted work.\n */\n\nexport const SET_OP = 's';\nexport const DEL_OP = 'd';\nexport const TRUNCATE_OP = 't';\nexport const RESET_OP = 'r';\n\n// Exported for testing (and migrations)\nexport const CREATE_CHANGELOG_SCHEMA =\n // stateVersion : a.k.a. row version\n // pos : order in which to process the change (within the version)\n // table : The table associated with the change\n // rowKey : JSON row key for a row change. For table-wide changes RESET\n // and TRUNCATE, there is no associated row; instead, `pos` is\n // set to -1 and the rowKey is set to the stateVersion,\n // guaranteeing when attempting to process the transaction,\n // the pipeline is reset (and the change log traversal\n // aborted).\n // op : 's' for set (insert/update)\n // : 'd' for delete\n // : 'r' for table reset (schema change)\n // : 't' for table truncation (which also resets the pipeline)\n // backfillingColumnVersions\n // : A JSON mapping from column name to stateVersion tracked\n // for replicated writes of columns that are being backfilled.\n // This is used to prevent backfill data, which is at a\n // fixed snapshot/version outside of the replication stream,\n // from overwriting newer column values.\n //\n // Naming note: To maintain compatibility between a new replication-manager\n // and old view-syncers, the previous _zero.changeLog table is preserved\n // and its replacement given a new name \"changeLog2\".\n `\n CREATE TABLE \"_zero.changeLog2\" (\n \"stateVersion\" TEXT NOT NULL,\n \"pos\" INT NOT NULL,\n \"table\" TEXT NOT NULL,\n \"rowKey\" TEXT NOT NULL,\n \"op\" TEXT NOT NULL,\n \"backfillingColumnVersions\" TEXT DEFAULT '{}',\n PRIMARY KEY(\"stateVersion\", \"pos\"),\n UNIQUE(\"table\", \"rowKey\")\n );\n `;\n\n/**\n * Contains the changeLog fields relevant for computing the diff between\n * two snapshots of a replica. The `pos` and `backfillingColumnVersions`\n * fields are excluded, though the query should be ordered by\n * `<stateVersion, pos>`.\n */\nexport type ChangeLogEntry =\n | {\n readonly stateVersion: string;\n readonly table: string;\n readonly rowKey: Readonly<Record<string, JSONValue>>;\n readonly op: typeof SET_OP | typeof DEL_OP;\n }\n | {\n readonly stateVersion: string;\n readonly table: string;\n // Table-wide ops have no row.\n readonly rowKey: null;\n readonly op: typeof TRUNCATE_OP | typeof RESET_OP;\n };\n\n/**\n * The {@link ChangeLogEntry} for the columns of a change log row. This does\n * not validate what zero-cache itself wrote: the columns are\n * `TEXT NOT NULL`, and `rowKey` is the JSON of an object (see\n * {@link ChangeLog}).\n */\nexport function parseChangeLogEntry(\n stateVersion: string,\n table: string,\n rowKey: string,\n op: string,\n): ChangeLogEntry {\n switch (op) {\n case SET_OP:\n case DEL_OP:\n return {stateVersion, table, rowKey: parseRowKey(rowKey), op};\n case TRUNCATE_OP:\n case RESET_OP:\n return {stateVersion, table, rowKey: null, op};\n default:\n throw new Error(`Invalid change log op \"${op}\" for table \"${table}\"`);\n }\n}\n\nfunction parseRowKey(rowKey: string): Readonly<Record<string, JSONValue>> {\n const key = parse(rowKey);\n assert(\n typeof key === 'object' && key !== null && !Array.isArray(key),\n () => `Invalid change log rowKey ${rowKey}`,\n );\n return key as Readonly<Record<string, JSONValue>>;\n}\n\nconst rawChangeLogEntrySchema = v.object({\n stateVersion: v.string(),\n table: v.string(),\n rowKey: v.string(),\n op: v.literalUnion(SET_OP, DEL_OP, TRUNCATE_OP, RESET_OP),\n backfillingColumnVersions: v\n .string()\n .map(val => v.record(v.string()).parse(JSON.parse(val))),\n});\n\nexport class ChangeLog {\n readonly #logRowOpStmt: Statement;\n readonly #logRowOpWithBackfillStmt: Statement;\n readonly #logTableWideOpStmt;\n readonly #getRowOpStmt: Statement;\n\n constructor(db: Database) {\n this.#logRowOpStmt = db.prepare(/*sql*/ `\n INSERT OR REPLACE INTO \"_zero.changeLog2\" \n (stateVersion, pos, \"table\", rowKey, op)\n VALUES (@version, @pos, @table, JSON(@rowKey), @op)\n `);\n\n this.#logRowOpWithBackfillStmt = db.prepare(/*sql*/ `\n INSERT INTO \"_zero.changeLog2\" \n (stateVersion, pos, \"table\", rowKey, op, backfillingColumnVersions)\n VALUES (@version, @pos, @table, JSON(@rowKey), @op, \n JSON(@backfillingColumnVersions))\n ON CONFLICT (\"table\", rowKey) DO UPDATE \n SET stateVersion = excluded.stateVersion,\n pos = excluded.pos,\n op = excluded.op,\n backfillingColumnVersions = json_patch(\n backfillingColumnVersions, excluded.backfillingColumnVersions)\n `);\n\n // Because table-wide ops result in aborting an incremental update\n // and rehydrating all queries at \"head\", they are assigned pos = -1\n // as an optimization to abort as early as possible to skip unnecessary\n // updates.\n //\n // However, changeLog entries that are destined to be \"skipped\" are\n // nonetheless kept for the purpose of tracking backfillingColumnVersions.\n this.#logTableWideOpStmt = db.prepare(/*sql*/ `\n INSERT OR REPLACE INTO \"_zero.changeLog2\" \n (stateVersion, pos, \"table\", rowKey, op) \n VALUES (@version, -1, @table, @version, @op)\n `);\n\n // oxlint-disable-next-line zero/no-select-star -- Local SQLite replica query; not run through pg prepared statements.\n this.#getRowOpStmt = db.prepare(/*sql*/ `\n SELECT * FROM \"_zero.changeLog2\" WHERE \"table\" = ? AND \"rowKey\" = JSON(?)\n `);\n }\n\n /**\n *\n * @param backfilled The backfilling columns for which values were set. Note\n * that an empty list and the `undefined` value mean different things;\n * * An empty list indicates that a backfill is in progress but no\n * backfilling values were set. In this case, existing\n * backfillingColumnVersions are preserved.\n * * `undefined` indicates that there are no columns being backfilled.\n * In this case, any vestigial `backfillingColumnVersions` value\n * is cleared.\n */\n logSetOp(\n version: LexiVersion,\n pos: number,\n table: string,\n row: LiteRowKey,\n backfilled: string[] | undefined,\n ): string {\n return this.#logRowOp(version, pos, table, row, SET_OP, backfilled);\n }\n\n logDeleteOp(\n version: LexiVersion,\n pos: number,\n table: string,\n row: LiteRowKey,\n ): string {\n // Note: For delete ops, it is always safe to clear the\n // backfillingColumnVersions because the backfill algorithm\n // understands that deletes apply to the whole row.\n return this.#logRowOp(version, pos, table, row, DEL_OP, undefined);\n }\n\n getLatestRowOp(table: string, row: LiteRowKey) {\n const rowKey = stringify(normalizedKeyOrder(row));\n const result = this.#getRowOpStmt.get(table, rowKey);\n return result === undefined\n ? undefined\n : v.parse(result, rawChangeLogEntrySchema, 'passthrough');\n }\n\n #logRowOp(\n version: LexiVersion,\n pos: number,\n table: string,\n row: LiteRowKey,\n op: string,\n backfilled: string[] | undefined,\n ): string {\n const rowKey = stringify(normalizedKeyOrder(row));\n if (backfilled === undefined) {\n this.#logRowOpStmt.run({version, pos, table, rowKey, op});\n } else {\n const versions: Record<string, string> = {};\n for (const col of backfilled) {\n versions[col] = version;\n }\n this.#logRowOpWithBackfillStmt.run({\n version,\n pos,\n table,\n rowKey,\n op,\n backfillingColumnVersions: JSON.stringify(versions),\n });\n }\n return rowKey;\n }\n\n logTruncateOp(version: LexiVersion, table: string) {\n this.#logTableWideOpStmt.run({version, table, op: TRUNCATE_OP});\n }\n\n logResetOp(version: LexiVersion, table: string) {\n this.#logTableWideOpStmt.run({version, table, op: RESET_OP});\n }\n}\n"],"mappings":";;;;AAiDA,IAAa,0BAwBX;;;;;;;;;;;;;;;;;;AAwCF,SAAgB,oBACd,cACA,OACA,QACA,IACgB;CAChB,QAAQ,IAAR;EACE,KAAA;EACA,KAAA,KACE,OAAO;GAAC;GAAc;GAAO,QAAQ,YAAY,MAAM;GAAG;EAAE;EAC9D,KAAA;EACA,KAAA,KACE,OAAO;GAAC;GAAc;GAAO,QAAQ;GAAM;EAAE;EAC/C,SACE,MAAM,IAAI,MAAM,0BAA0B,GAAG,eAAe,MAAM,EAAE;CACxE;AACF;AAEA,SAAS,YAAY,QAAqD;CACxE,MAAM,MAAMA,QAAM,MAAM;CACxB,OACE,OAAO,QAAQ,YAAY,QAAQ,QAAQ,CAAC,MAAM,QAAQ,GAAG,SACvD,6BAA6B,QACrC;CACA,OAAO;AACT;AAEA,IAAM,0BAA0BC,eAAE,OAAO;CACvC,cAAcA,eAAE,OAAO;CACvB,OAAOA,eAAE,OAAO;CAChB,QAAQA,eAAE,OAAO;CACjB,IAAIC,aAAAA,KAAAA,KAAAA,KAAAA,GAAoD;CACxD,2BAA2BD,eACxB,OAAO,CAAC,CACR,KAAI,QAAOA,eAAE,OAAOA,eAAE,OAAO,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,GAAG,CAAC,CAAC;AAC3D,CAAC;AAED,IAAa,YAAb,MAAuB;CACrB;CACA;CACA;CACA;CAEA,YAAY,IAAc;EACxB,KAAK,gBAAgB,GAAG,QAAgB;;;;KAIvC;EAED,KAAK,4BAA4B,GAAG,QAAgB;;;;;;;;;;;KAWnD;EASD,KAAK,sBAAsB,GAAG,QAAgB;;;;KAI7C;EAGD,KAAK,gBAAgB,GAAG,QAAgB;;KAEvC;CACH;;;;;;;;;;;;CAaA,SACE,SACA,KACA,OACA,KACA,YACQ;EACR,OAAO,KAAK,UAAU,SAAS,KAAK,OAAO,KAAA,KAAa,UAAU;CACpE;CAEA,YACE,SACA,KACA,OACA,KACQ;EAIR,OAAO,KAAK,UAAU,SAAS,KAAK,OAAO,KAAA,KAAa,KAAA,CAAS;CACnE;CAEA,eAAe,OAAe,KAAiB;EAC7C,MAAM,SAAS,UAAU,mBAAmB,GAAG,CAAC;EAChD,MAAM,SAAS,KAAK,cAAc,IAAI,OAAO,MAAM;EACnD,OAAO,WAAW,KAAA,IACd,KAAA,IACAE,MAAQ,QAAQ,yBAAyB,aAAa;CAC5D;CAEA,UACE,SACA,KACA,OACA,KACA,IACA,YACQ;EACR,MAAM,SAAS,UAAU,mBAAmB,GAAG,CAAC;EAChD,IAAI,eAAe,KAAA,GACjB,KAAK,cAAc,IAAI;GAAC;GAAS;GAAK;GAAO;GAAQ;EAAE,CAAC;OACnD;GACL,MAAM,WAAmC,CAAC;GAC1C,KAAK,MAAM,OAAO,YAChB,SAAS,OAAO;GAElB,KAAK,0BAA0B,IAAI;IACjC;IACA;IACA;IACA;IACA;IACA,2BAA2B,KAAK,UAAU,QAAQ;GACpD,CAAC;EACH;EACA,OAAO;CACT;CAEA,cAAc,SAAsB,OAAe;EACjD,KAAK,oBAAoB,IAAI;GAAC;GAAS;GAAO,IAAA;EAAe,CAAC;CAChE;CAEA,WAAW,SAAsB,OAAe;EAC9C,KAAK,oBAAoB,IAAI;GAAC;GAAS;GAAO,IAAA;EAAY,CAAC;CAC7D;AACF"}
|
|
@@ -65,11 +65,4 @@ export declare function liteTypeStringToMetadata(liteTypeString: string, charact
|
|
|
65
65
|
* This is a compatibility helper for the migration period.
|
|
66
66
|
*/
|
|
67
67
|
export declare function metadataToLiteTypeString(metadata: ColumnMetadata): string;
|
|
68
|
-
/**
|
|
69
|
-
* Converts PostgreSQL ColumnSpec to structured ColumnMetadata.
|
|
70
|
-
* Used during replication to populate the metadata table from upstream schema.
|
|
71
|
-
*
|
|
72
|
-
* Uses the same logic as liteTypeString() and mapPostgresToLiteColumn() via shared helpers.
|
|
73
|
-
*/
|
|
74
|
-
export declare function pgColumnSpecToMetadata(spec: ColumnSpec): ColumnMetadata;
|
|
75
68
|
//# sourceMappingURL=column-metadata.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"column-metadata.d.ts","sourceRoot":"","sources":["../../../../../../../zero-cache/src/services/replicator/schema/column-metadata.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAC,QAAQ,EAAY,MAAM,iCAAiC,CAAC;AAEzE,OAAO,KAAK,EAAC,UAAU,EAAE,aAAa,EAAC,MAAM,sBAAsB,CAAC;AAQpE,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,yCAAyC,CAAC;AAExE;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,2EAA2E;IAC3E,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,sDAAsD;IACtD,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,aAAa,EAAE,OAAO,CAAC;CACxB;AAWD,eAAO,MAAM,4BAA4B,8VAYxC,CAAC;AAEF;;;;;;GAMG;AACH,qBAAa,mBAAmB;;IAa9B,OAAO,eAyDN;IAED;;;OAGG;IACH,MAAM,CAAC,WAAW,CAAC,EAAE,EAAE,QAAQ,GAAG,mBAAmB,GAAG,SAAS,CAkBhE;IAED,MAAM,CACJ,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,UAAU,EAChB,QAAQ,CAAC,EAAE,UAAU,GACpB,IAAI,CAGN;IAoBD,MAAM,CACJ,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,MAAM,EACrB,aAAa,EAAE,MAAM,EACrB,IAAI,EAAE,UAAU,GACf,IAAI,CAYN;IAED,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,CAE5D;IAED,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,CAExD;IAED,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAEnC;IAED,WAAW,CAAC,YAAY,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI,CAE5D;IAED,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,CAiB3E;IAED,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAkBvD;IAED,QAAQ,IAAI,OAAO,CAGlB;CACF;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CACxC,EAAE,EAAE,QAAQ,EACZ,MAAM,EAAE,aAAa,EAAE,GACtB,IAAI,CA0BN;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CACtC,cAAc,EAAE,MAAM,EACtB,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,GACjC,cAAc,CAkBhB;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,cAAc,GAAG,MAAM,CAOzE
|
|
1
|
+
{"version":3,"file":"column-metadata.d.ts","sourceRoot":"","sources":["../../../../../../../zero-cache/src/services/replicator/schema/column-metadata.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAC,QAAQ,EAAY,MAAM,iCAAiC,CAAC;AAEzE,OAAO,KAAK,EAAC,UAAU,EAAE,aAAa,EAAC,MAAM,sBAAsB,CAAC;AAQpE,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,yCAAyC,CAAC;AAExE;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,2EAA2E;IAC3E,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,sDAAsD;IACtD,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,aAAa,EAAE,OAAO,CAAC;CACxB;AAWD,eAAO,MAAM,4BAA4B,8VAYxC,CAAC;AAEF;;;;;;GAMG;AACH,qBAAa,mBAAmB;;IAa9B,OAAO,eAyDN;IAED;;;OAGG;IACH,MAAM,CAAC,WAAW,CAAC,EAAE,EAAE,QAAQ,GAAG,mBAAmB,GAAG,SAAS,CAkBhE;IAED,MAAM,CACJ,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,UAAU,EAChB,QAAQ,CAAC,EAAE,UAAU,GACpB,IAAI,CAGN;IAoBD,MAAM,CACJ,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,MAAM,EACrB,aAAa,EAAE,MAAM,EACrB,IAAI,EAAE,UAAU,GACf,IAAI,CAYN;IAED,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,CAE5D;IAED,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,CAExD;IAED,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAEnC;IAED,WAAW,CAAC,YAAY,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI,CAE5D;IAED,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,CAiB3E;IAED,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAkBvD;IAED,QAAQ,IAAI,OAAO,CAGlB;CACF;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CACxC,EAAE,EAAE,QAAQ,EACZ,MAAM,EAAE,aAAa,EAAE,GACtB,IAAI,CA0BN;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CACtC,cAAc,EAAE,MAAM,EACtB,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,GACjC,cAAc,CAkBhB;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,cAAc,GAAG,MAAM,CAOzE"}
|
|
@@ -202,6 +202,6 @@ function pgColumnSpecToMetadata(spec) {
|
|
|
202
202
|
};
|
|
203
203
|
}
|
|
204
204
|
//#endregion
|
|
205
|
-
export { CREATE_COLUMN_METADATA_TABLE, ColumnMetadataStore, metadataToLiteTypeString, populateFromExistingTables };
|
|
205
|
+
export { CREATE_COLUMN_METADATA_TABLE, ColumnMetadataStore, liteTypeStringToMetadata, metadataToLiteTypeString, populateFromExistingTables };
|
|
206
206
|
|
|
207
207
|
//# sourceMappingURL=column-metadata.js.map
|