@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":"types.js","names":[],"sources":["../../../../../../../zero-cache/src/services/view-syncer/schema/types.ts"],"sourcesContent":["import {jsonValueSchema} from '../../../../../shared/src/bigint-json.ts';\nimport {jsonSchema} from '../../../../../shared/src/json-schema.ts';\nimport * as v from '../../../../../shared/src/valita.ts';\nimport {astSchema} from '../../../../../zero-protocol/src/ast.ts';\nimport {versionFromLexi, versionToLexi} from '../../../types/lexi-version.ts';\nimport {\n majorVersionToString,\n stateVersionFromString,\n} from '../../../types/state-version.ts';\nimport {ttlClockSchema} from '../ttl-clock.ts';\nimport type {QueriesRow} from './cvr.ts';\n\nexport const cvrVersionSchema = v.object({\n /**\n * The database `stateVersion` with which the rows in the CVR are consistent.\n */\n stateVersion: v.string(), // LexiVersion\n\n /**\n * `configVersion` is subversion of `stateVersion` that is initially absent for each\n * `stateVersion`, and incremented for configuration changes that affect the contents\n * of the CVR such as:\n *\n * * query set changes\n * * query transformation changes (which may happen for changes\n * in server-side logic or authorization policies)\n *\n * Such configuration changes are always correlated with a change to one or more\n * `/meta/...` records in the CVR, often (but not always) with corresponding\n * patches in `/patches/meta/...`.\n *\n * When the `stateVersion` moves forward, the `minorVersion` is reset to absent.\n * In this manner it behaves like the analogous concept in semantic versioning.\n */\n configVersion: v.number().optional(),\n});\n\nexport type CVRVersion = v.Infer<typeof cvrVersionSchema>;\n\nexport const EMPTY_CVR_VERSION: CVRVersion = {\n stateVersion: majorVersionToString(0),\n} as const;\n\nexport function oneAfter(v: NullableCVRVersion): CVRVersion {\n return v === null\n ? {stateVersion: majorVersionToString(0)}\n : {\n stateVersion: v.stateVersion,\n configVersion: (v.configVersion ?? 0) + 1,\n };\n}\n\nexport type NullableCVRVersion = CVRVersion | null;\n\nexport function cmpVersions(\n a: NullableCVRVersion,\n b: NullableCVRVersion,\n): number {\n return a === null && b === null\n ? 0\n : a === null\n ? -1\n : b === null\n ? 1\n : a.stateVersion < b.stateVersion\n ? -1\n : a.stateVersion > b.stateVersion\n ? 1\n : (a.configVersion ?? 0) - (b.configVersion ?? 0);\n}\n\nexport function maxVersion(a: CVRVersion, b?: CVRVersion): CVRVersion {\n return !b ? a : cmpVersions(b, a) > 0 ? b : a;\n}\n\nexport function versionToCookie(v: CVRVersion): string {\n return versionString(v);\n}\n\nexport function versionToNullableCookie(v: NullableCVRVersion): string | null {\n return v === null ? null : versionToCookie(v);\n}\n\nexport function cookieToVersion(cookie: string | null): NullableCVRVersion {\n if (cookie === null) {\n return null;\n }\n return versionFromString(cookie);\n}\n\n// Last Active tracking.\n\nexport const cvrIDSchema = v.object({id: v.string()});\nexport type CvrID = v.Infer<typeof cvrIDSchema>;\n\nconst cvrRecordSchema = v.object({\n /**\n * CVR records store the CVRVersion at which the record was last patched into\n * the CVR, which corresponds with a patch row that is cleaned up when the\n * record is changed (updated, deleted, and re-added in the case of rows).\n *\n * Tombstones are stored for row records but not for config records. This means\n * that \"orphaned\" delete patches for config records may exist, and therefore\n * scans of config patches must always run until the end of the list. On the\n * contrary, for row patches, the row record tombstones allow cleanup of delete\n * patches.\n */\n patchVersion: cvrVersionSchema,\n});\n\nexport const clientRecordSchema = v.object({\n /** The client ID, of which there can be multiple for a client group view. */\n id: v.string(),\n\n /** The client's desired query IDs. Patch information is stored in the QueryRecord. */\n desiredQueryIDs: v.array(v.string()),\n});\n\nexport type ClientRecord = v.Infer<typeof clientRecordSchema>;\n\nexport const baseQueryRecordSchema = v.object({\n /** The client-specified ID used to identify this query. Typically a hash. */\n id: v.string(),\n\n /**\n * The hash of the query after server-side transformations, which include:\n *\n * * Normalization (which may differ from what the client does)\n * * Query \"expansion\" to include primary keys and query-execution-related columns\n * * Authorization transforms\n *\n * Transformations depend on conditions that are independent of the db state version,\n * such as server-side logic and authorization policies. As such, the version of a CVR\n * version may need to be advanced independent of db state changes. This is done\n * via the `minorVersion` counter of the CVRVersion object, which is used to account\n * for both changes to the query set and changes to query transformations (which are\n * effectively remove-old-query + add-new-query).\n *\n * Note that the transformed AST itself is **not** stored, as the result of the previous\n * transformation is not useful in and of itself. If the current transformation results in\n * a different hash than that of the transformation used for the last version of the CVR,\n * it is simply handled by invalidating the existing rows, re-executed the query with\n * the new transformation, and advancing the CVR's `minorVersion` and this query's\n * `transformationVersion`.\n *\n * Note that the transformationHash is only stored when the query has reached the \"gotten\"\n * state. If the query is in the \"desired\" but not yet \"gotten\" state, the field is absent.\n */\n transformationHash: v.string().optional(),\n\n /**\n * The CVR version corresponding to the `transformationHash`. This essentially tracks when\n * this version of the query was effectively added to the CVR (as opposed to the\n * `patchVersion`, which is simply when the client was notified that its query was added\n * to the gotten set). Catchup of clients from old CVR versions require executing all\n * queries with a newer `transformationVersion`.\n */\n transformationVersion: cvrVersionSchema.optional(),\n});\n\n/**\n * Internal queries track rows in the database for internal use, such as the\n * `lastMutationID`s in the `zero.clients` table. They participate in the standard\n * invalidation / update logic for row contents, but not in the desired/got or\n * size-based quota logic for client-requested queries.\n */\nexport const internalQueryRecordSchema = baseQueryRecordSchema.extend({\n type: v.literal('internal'),\n ast: astSchema,\n});\n\nexport type InternalQueryRecord = v.Infer<typeof internalQueryRecordSchema>;\n\nconst clientStateSchema = v.object({\n /**\n * The time at which the query was last inactivated. If this undefined or\n * missing then the query is active.\n *\n * Desired queries are always active and have an undefined inactivatedAt.\n */\n inactivatedAt: ttlClockSchema.optional(),\n\n /**\n * TTL, time to live in milliseconds. If the query is not updated within this\n * time. The time to live is the time after it has become inactive. Negative\n * values are treated as `'forever'`.\n *\n * We do clamp this to a maximum of 10 minutes, so that queries do not\n * live for a very long time in the CVR.\n */\n ttl: v.number(),\n\n /**\n * The version at which the client state changed (i.e. individual `patchVersion`s).\n */\n version: cvrVersionSchema,\n});\n\nconst externalQueryRecordSchema = baseQueryRecordSchema.extend({\n /**\n * The client state for this query, which includes the inactivatedAt, ttl and\n * version. The client state is stored in a record with the client ID as the\n * key.\n */\n clientState: v.record(clientStateSchema),\n\n // For queries, the `patchVersion` indicates when query was added to the got set,\n // and is absent if not yet gotten.\n patchVersion: cvrVersionSchema.optional(),\n});\n\nexport const clientQueryRecordSchema = externalQueryRecordSchema.extend({\n type: v.literal('client'),\n\n /** The original AST as supplied by the client. */\n ast: astSchema,\n});\n\nexport type ClientQueryRecord = v.Infer<typeof clientQueryRecordSchema>;\n\nexport const customQueryRecordSchema = externalQueryRecordSchema.extend({\n type: v.literal('custom'),\n name: v.string(),\n args: v.readonly(v.array(jsonSchema)),\n});\n\nexport type CustomQueryRecord = v.Infer<typeof customQueryRecordSchema>;\n\nexport const queryRecordSchema = v.union(\n clientQueryRecordSchema,\n customQueryRecordSchema,\n internalQueryRecordSchema,\n);\n\nexport type QueryRecord = v.Infer<typeof queryRecordSchema>;\n\nexport const rowIDSchema = v.object({\n schema: v.string(),\n table: v.string(),\n rowKey: v.record(jsonValueSchema),\n});\n\nexport type RowID = v.Infer<typeof rowIDSchema>;\n\nexport const rowRecordSchema = cvrRecordSchema.extend({\n id: rowIDSchema,\n rowVersion: v.string(), // '_0_version' of the row\n // query hashes => refCount, or `null` for a row that was removed from the\n // view (i.e. tombstone).\n refCounts: v.record(v.number()).nullable(),\n});\n\nexport type RowRecord = v.Infer<typeof rowRecordSchema>;\n\nexport const patchSchema = v.object({\n type: v.literalUnion('row', 'query'),\n op: v.literalUnion('put', 'del'),\n});\n\nexport const putRowPatchSchema = patchSchema.extend({\n type: v.literal('row'),\n op: v.literal('put'),\n id: rowIDSchema,\n rowVersion: v.string(), // '_0_version' of the row\n});\n\nexport type PutRowPatch = v.Infer<typeof putRowPatchSchema>;\n\nexport const delRowPatchSchema = patchSchema.extend({\n type: v.literal('row'),\n op: v.literal('del'),\n id: rowIDSchema,\n});\n\nexport type DelRowPatch = v.Infer<typeof delRowPatchSchema>;\n\nexport const rowPatchSchema = v.union(putRowPatchSchema, delRowPatchSchema);\n\nexport type RowPatch = v.Infer<typeof rowPatchSchema>;\n\nexport const queryPatchSchema = patchSchema.extend({\n type: v.literal('query'),\n id: v.string(),\n clientID: v.string().optional(), // defined for \"desired\", undefined for \"got\"\n});\n\nexport type QueryPatch = v.Infer<typeof queryPatchSchema>;\n\nexport type PutQueryPatch = QueryPatch & {op: 'put'};\nexport type DelQueryPatch = QueryPatch & {op: 'del'};\n\nexport const metadataPatchSchema = queryPatchSchema;\n\nexport type MetadataPatch = v.Infer<typeof metadataPatchSchema>;\n\nexport function versionString(v: CVRVersion) {\n // The separator (e.g. \":\") needs to be lexicographically greater than the\n // storage key path separator (e.g. \"/\") so that \"01/row-hash\" is less than \"01:01/row-hash\".\n // In particular, the traditional separator for major.minor versions (\".\") does not\n // satisfy this quality.\n return v.configVersion\n ? `${v.stateVersion}:${versionToLexi(v.configVersion)}`\n : v.stateVersion;\n}\n\nexport function versionFromString(str: string): CVRVersion {\n const parts = str.split(':');\n const stateVersion = parts[0];\n switch (parts.length) {\n case 1: {\n stateVersionFromString(stateVersion); // Purely for validation.\n return {stateVersion};\n }\n case 2: {\n const configVersion = versionFromLexi(parts[1]);\n if (configVersion > BigInt(Number.MAX_SAFE_INTEGER)) {\n throw new Error(`minorVersion ${parts[1]} exceeds max safe integer`);\n }\n return {stateVersion, configVersion: Number(configVersion)};\n }\n default:\n throw new TypeError(`Invalid version string ${str}`);\n }\n}\n\nexport function queryRecordToQueryRow(\n clientGroupID: string,\n query: QueryRecord,\n rowSetSignature: string | null,\n): QueriesRow {\n switch (query.type) {\n case 'internal':\n return {\n clientGroupID,\n queryHash: query.id,\n clientAST: query.ast,\n queryName: null,\n queryArgs: null,\n patchVersion: null,\n transformationHash: query.transformationHash ?? null,\n transformationVersion: maybeVersionString(query.transformationVersion),\n internal: true,\n deleted: false, // put vs del \"got\" query\n rowSetSignature,\n };\n case 'client':\n return {\n clientGroupID,\n queryHash: query.id,\n clientAST: query.ast,\n queryName: null,\n queryArgs: null,\n patchVersion: maybeVersionString(query.patchVersion),\n transformationHash: query.transformationHash ?? null,\n transformationVersion: maybeVersionString(query.transformationVersion),\n internal: null,\n deleted: false, // put vs del \"got\" query\n rowSetSignature,\n };\n case 'custom':\n return {\n clientGroupID,\n queryHash: query.id,\n clientAST: null,\n queryName: query.name,\n queryArgs: query.args,\n patchVersion: maybeVersionString(query.patchVersion),\n transformationHash: query.transformationHash ?? null,\n transformationVersion: maybeVersionString(query.transformationVersion),\n internal: null,\n deleted: false, // put vs del \"got\" query\n rowSetSignature,\n };\n }\n}\n\nexport const maybeVersionString = (v: CVRVersion | undefined) =>\n v ? versionString(v) : null;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"types.js","names":["v","v.readonly","v.literalUnion"],"sources":["../../../../../../../zero-cache/src/services/view-syncer/schema/types.ts"],"sourcesContent":["import {jsonValueSchema} from '../../../../../shared/src/bigint-json.ts';\nimport {jsonSchema} from '../../../../../shared/src/json-schema.ts';\nimport * as v from '../../../../../shared/src/valita.ts';\nimport {astSchema} from '../../../../../zero-protocol/src/ast.ts';\nimport {versionFromLexi, versionToLexi} from '../../../types/lexi-version.ts';\nimport {\n majorVersionToString,\n stateVersionFromString,\n} from '../../../types/state-version.ts';\nimport {ttlClockSchema} from '../ttl-clock.ts';\nimport type {QueriesRow} from './cvr.ts';\n\nconst cvrVersionSchema = v.object({\n /**\n * The database `stateVersion` with which the rows in the CVR are consistent.\n */\n stateVersion: v.string(), // LexiVersion\n\n /**\n * `configVersion` is subversion of `stateVersion` that is initially absent for each\n * `stateVersion`, and incremented for configuration changes that affect the contents\n * of the CVR such as:\n *\n * * query set changes\n * * query transformation changes (which may happen for changes\n * in server-side logic or authorization policies)\n *\n * Such configuration changes are always correlated with a change to one or more\n * `/meta/...` records in the CVR, often (but not always) with corresponding\n * patches in `/patches/meta/...`.\n *\n * When the `stateVersion` moves forward, the `minorVersion` is reset to absent.\n * In this manner it behaves like the analogous concept in semantic versioning.\n */\n configVersion: v.number().optional(),\n});\n\nexport type CVRVersion = v.Infer<typeof cvrVersionSchema>;\n\nexport const EMPTY_CVR_VERSION: CVRVersion = {\n stateVersion: majorVersionToString(0),\n} as const;\n\nexport function oneAfter(v: NullableCVRVersion): CVRVersion {\n return v === null\n ? {stateVersion: majorVersionToString(0)}\n : {\n stateVersion: v.stateVersion,\n configVersion: (v.configVersion ?? 0) + 1,\n };\n}\n\nexport type NullableCVRVersion = CVRVersion | null;\n\nexport function cmpVersions(\n a: NullableCVRVersion,\n b: NullableCVRVersion,\n): number {\n return a === null && b === null\n ? 0\n : a === null\n ? -1\n : b === null\n ? 1\n : a.stateVersion < b.stateVersion\n ? -1\n : a.stateVersion > b.stateVersion\n ? 1\n : (a.configVersion ?? 0) - (b.configVersion ?? 0);\n}\n\nexport function maxVersion(a: CVRVersion, b?: CVRVersion): CVRVersion {\n return !b ? a : cmpVersions(b, a) > 0 ? b : a;\n}\n\nexport function versionToCookie(v: CVRVersion): string {\n return versionString(v);\n}\n\nexport function versionToNullableCookie(v: NullableCVRVersion): string | null {\n return v === null ? null : versionToCookie(v);\n}\n\nexport function cookieToVersion(cookie: string | null): NullableCVRVersion {\n if (cookie === null) {\n return null;\n }\n return versionFromString(cookie);\n}\n\n// Last Active tracking.\n\nconst cvrRecordSchema = v.object({\n /**\n * CVR records store the CVRVersion at which the record was last patched into\n * the CVR, which corresponds with a patch row that is cleaned up when the\n * record is changed (updated, deleted, and re-added in the case of rows).\n *\n * Tombstones are stored for row records but not for config records. This means\n * that \"orphaned\" delete patches for config records may exist, and therefore\n * scans of config patches must always run until the end of the list. On the\n * contrary, for row patches, the row record tombstones allow cleanup of delete\n * patches.\n */\n patchVersion: cvrVersionSchema,\n});\n\nconst clientRecordSchema = v.object({\n /** The client ID, of which there can be multiple for a client group view. */\n id: v.string(),\n\n /** The client's desired query IDs. Patch information is stored in the QueryRecord. */\n desiredQueryIDs: v.array(v.string()),\n});\n\nexport type ClientRecord = v.Infer<typeof clientRecordSchema>;\n\nconst baseQueryRecordSchema = v.object({\n /** The client-specified ID used to identify this query. Typically a hash. */\n id: v.string(),\n\n /**\n * The hash of the query after server-side transformations, which include:\n *\n * * Normalization (which may differ from what the client does)\n * * Query \"expansion\" to include primary keys and query-execution-related columns\n * * Authorization transforms\n *\n * Transformations depend on conditions that are independent of the db state version,\n * such as server-side logic and authorization policies. As such, the version of a CVR\n * version may need to be advanced independent of db state changes. This is done\n * via the `minorVersion` counter of the CVRVersion object, which is used to account\n * for both changes to the query set and changes to query transformations (which are\n * effectively remove-old-query + add-new-query).\n *\n * Note that the transformed AST itself is **not** stored, as the result of the previous\n * transformation is not useful in and of itself. If the current transformation results in\n * a different hash than that of the transformation used for the last version of the CVR,\n * it is simply handled by invalidating the existing rows, re-executed the query with\n * the new transformation, and advancing the CVR's `minorVersion` and this query's\n * `transformationVersion`.\n *\n * Note that the transformationHash is only stored when the query has reached the \"gotten\"\n * state. If the query is in the \"desired\" but not yet \"gotten\" state, the field is absent.\n */\n transformationHash: v.string().optional(),\n\n /**\n * The CVR version corresponding to the `transformationHash`. This essentially tracks when\n * this version of the query was effectively added to the CVR (as opposed to the\n * `patchVersion`, which is simply when the client was notified that its query was added\n * to the gotten set). Catchup of clients from old CVR versions require executing all\n * queries with a newer `transformationVersion`.\n */\n transformationVersion: cvrVersionSchema.optional(),\n});\n\n/**\n * Internal queries track rows in the database for internal use, such as the\n * `lastMutationID`s in the `zero.clients` table. They participate in the standard\n * invalidation / update logic for row contents, but not in the desired/got or\n * size-based quota logic for client-requested queries.\n */\nconst internalQueryRecordSchema = baseQueryRecordSchema.extend({\n type: v.literal('internal'),\n ast: astSchema,\n});\n\nexport type InternalQueryRecord = v.Infer<typeof internalQueryRecordSchema>;\n\nconst clientStateSchema = v.object({\n /**\n * The time at which the query was last inactivated. If this undefined or\n * missing then the query is active.\n *\n * Desired queries are always active and have an undefined inactivatedAt.\n */\n inactivatedAt: ttlClockSchema.optional(),\n\n /**\n * TTL, time to live in milliseconds. If the query is not updated within this\n * time. The time to live is the time after it has become inactive. Negative\n * values are treated as `'forever'`.\n *\n * We do clamp this to a maximum of 10 minutes, so that queries do not\n * live for a very long time in the CVR.\n */\n ttl: v.number(),\n\n /**\n * The version at which the client state changed (i.e. individual `patchVersion`s).\n */\n version: cvrVersionSchema,\n});\n\nconst externalQueryRecordSchema = baseQueryRecordSchema.extend({\n /**\n * The client state for this query, which includes the inactivatedAt, ttl and\n * version. The client state is stored in a record with the client ID as the\n * key.\n */\n clientState: v.record(clientStateSchema),\n\n // For queries, the `patchVersion` indicates when query was added to the got set,\n // and is absent if not yet gotten.\n patchVersion: cvrVersionSchema.optional(),\n});\n\nconst clientQueryRecordSchema = externalQueryRecordSchema.extend({\n type: v.literal('client'),\n\n /** The original AST as supplied by the client. */\n ast: astSchema,\n});\n\nexport type ClientQueryRecord = v.Infer<typeof clientQueryRecordSchema>;\n\nconst customQueryRecordSchema = externalQueryRecordSchema.extend({\n type: v.literal('custom'),\n name: v.string(),\n args: v.readonly(v.array(jsonSchema)),\n});\n\nexport type CustomQueryRecord = v.Infer<typeof customQueryRecordSchema>;\n\nconst queryRecordSchema = v.union(\n clientQueryRecordSchema,\n customQueryRecordSchema,\n internalQueryRecordSchema,\n);\n\nexport type QueryRecord = v.Infer<typeof queryRecordSchema>;\n\nconst rowIDSchema = v.object({\n schema: v.string(),\n table: v.string(),\n rowKey: v.record(jsonValueSchema),\n});\n\nexport type RowID = v.Infer<typeof rowIDSchema>;\n\nconst rowRecordSchema = cvrRecordSchema.extend({\n id: rowIDSchema,\n rowVersion: v.string(), // '_0_version' of the row\n // query hashes => refCount, or `null` for a row that was removed from the\n // view (i.e. tombstone).\n refCounts: v.record(v.number()).nullable(),\n});\n\nexport type RowRecord = v.Infer<typeof rowRecordSchema>;\n\nconst patchSchema = v.object({\n type: v.literalUnion('row', 'query'),\n op: v.literalUnion('put', 'del'),\n});\n\nconst queryPatchSchema = patchSchema.extend({\n type: v.literal('query'),\n id: v.string(),\n clientID: v.string().optional(), // defined for \"desired\", undefined for \"got\"\n});\n\nexport type QueryPatch = v.Infer<typeof queryPatchSchema>;\n\nexport type PutQueryPatch = QueryPatch & {op: 'put'};\nexport type DelQueryPatch = QueryPatch & {op: 'del'};\n\nexport function versionString(v: CVRVersion) {\n // The separator (e.g. \":\") needs to be lexicographically greater than the\n // storage key path separator (e.g. \"/\") so that \"01/row-hash\" is less than \"01:01/row-hash\".\n // In particular, the traditional separator for major.minor versions (\".\") does not\n // satisfy this quality.\n return v.configVersion\n ? `${v.stateVersion}:${versionToLexi(v.configVersion)}`\n : v.stateVersion;\n}\n\nexport function versionFromString(str: string): CVRVersion {\n const parts = str.split(':');\n const stateVersion = parts[0];\n switch (parts.length) {\n case 1: {\n stateVersionFromString(stateVersion); // Purely for validation.\n return {stateVersion};\n }\n case 2: {\n const configVersion = versionFromLexi(parts[1]);\n if (configVersion > BigInt(Number.MAX_SAFE_INTEGER)) {\n throw new Error(`minorVersion ${parts[1]} exceeds max safe integer`);\n }\n return {stateVersion, configVersion: Number(configVersion)};\n }\n default:\n throw new TypeError(`Invalid version string ${str}`);\n }\n}\n\nexport function queryRecordToQueryRow(\n clientGroupID: string,\n query: QueryRecord,\n rowSetSignature: string | null,\n): QueriesRow {\n switch (query.type) {\n case 'internal':\n return {\n clientGroupID,\n queryHash: query.id,\n clientAST: query.ast,\n queryName: null,\n queryArgs: null,\n patchVersion: null,\n transformationHash: query.transformationHash ?? null,\n transformationVersion: maybeVersionString(query.transformationVersion),\n internal: true,\n deleted: false, // put vs del \"got\" query\n rowSetSignature,\n };\n case 'client':\n return {\n clientGroupID,\n queryHash: query.id,\n clientAST: query.ast,\n queryName: null,\n queryArgs: null,\n patchVersion: maybeVersionString(query.patchVersion),\n transformationHash: query.transformationHash ?? null,\n transformationVersion: maybeVersionString(query.transformationVersion),\n internal: null,\n deleted: false, // put vs del \"got\" query\n rowSetSignature,\n };\n case 'custom':\n return {\n clientGroupID,\n queryHash: query.id,\n clientAST: null,\n queryName: query.name,\n queryArgs: query.args,\n patchVersion: maybeVersionString(query.patchVersion),\n transformationHash: query.transformationHash ?? null,\n transformationVersion: maybeVersionString(query.transformationVersion),\n internal: null,\n deleted: false, // put vs del \"got\" query\n rowSetSignature,\n };\n }\n}\n\nconst maybeVersionString = (v: CVRVersion | undefined) =>\n v ? versionString(v) : null;\n"],"mappings":"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"}
|
|
@@ -31,6 +31,12 @@ function serialize(v) {
|
|
|
31
31
|
default: return "u" + String(v);
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
|
+
/**
|
|
35
|
+
* The maximum number of distinct SQL statements interned by a
|
|
36
|
+
* {@link SnapshotRowCache} before it is cleared. There is one per table and
|
|
37
|
+
* lookup shape, so this is only reached after many schema changes.
|
|
38
|
+
*/
|
|
39
|
+
var MAX_INTERNED_STATEMENTS = 1e4;
|
|
34
40
|
var HIT = { result: "hit" };
|
|
35
41
|
var MISS = { result: "miss" };
|
|
36
42
|
/**
|
|
@@ -150,6 +156,6 @@ var SnapshotRowCache = class {
|
|
|
150
156
|
}
|
|
151
157
|
};
|
|
152
158
|
//#endregion
|
|
153
|
-
export { SnapshotRowCache };
|
|
159
|
+
export { DEFAULT_MAX_SNAPSHOT_ROW_CACHE_ENTRIES, MAX_INTERNED_STATEMENTS, SnapshotRowCache };
|
|
154
160
|
|
|
155
161
|
//# sourceMappingURL=snapshot-row-cache.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"snapshot-row-cache.js","names":[
|
|
1
|
+
{"version":3,"file":"snapshot-row-cache.js","names":[],"sources":["../../../../../../zero-cache/src/services/view-syncer/snapshot-row-cache.ts"],"sourcesContent":["import {stringify} from '../../../../shared/src/bigint-json.ts';\nimport {getOrInsert} from '../../../../shared/src/map.ts';\nimport {must} from '../../../../shared/src/must.ts';\nimport {RingBuffer} from '../../../../shared/src/ring-buffer.ts';\nimport {getOrCreateCounter} from '../../observability/metrics.ts';\n\n/**\n * The default maximum number of entries retained by a {@link SnapshotRowCache}.\n *\n * Each entry is a raw SQLite row (or the list of rows conflicting with\n * a row on its unique keys) read while computing a snapshot diff. A\n * replicated transaction of N rows produces up to 2N entries (the new value\n * and the previous value(s) of each row), so the cache should be large enough\n * to hold the largest transactions that are commonly replicated in order for\n * all of the client groups on a worker to share the reads.\n */\nexport const DEFAULT_MAX_SNAPSHOT_ROW_CACHE_ENTRIES = 50_000;\n\n/**\n * Serializes a lookup key value (i.e. a SQLite-bound parameter). Numbers and\n * bigints serialize identically, as row keys parsed from the change log are\n * JSON numbers whereas the values read from SQLite are bigints; both address\n * the same row. Strings are prefixed to distinguish them from numbers.\n */\nfunction serialize(v: unknown): string {\n switch (typeof v) {\n case 'string':\n return 's' + v;\n case 'number':\n case 'bigint':\n return String(v);\n case 'boolean':\n return v ? 'true' : 'false';\n case 'object':\n return v === null ? 'null' : 'o' + stringify(v);\n default:\n return 'u' + String(v);\n }\n}\n\n/**\n * How a statement's results are read: a single row (`Statement.get()`) or\n * all rows (`Statement.all()`).\n */\nexport type ReadMode = 'get' | 'all';\n\n/**\n * The maximum number of distinct SQL statements interned by a\n * {@link SnapshotRowCache} before it is cleared. There is one per table and\n * lookup shape, so this is only reached after many schema changes.\n */\nexport const MAX_INTERNED_STATEMENTS = 10_000;\n\nconst HIT = {result: 'hit'} as const;\nconst MISS = {result: 'miss'} as const;\n\n/**\n * A worker-wide, bounded cache of the rows that a `Snapshotter` reads from\n * replica snapshots when computing the diff between two versions of the\n * replica.\n *\n * Every client group (i.e. view-syncer) on a sync worker computes its own\n * diff from the shared `_zero.changeLog2`, and each change in the diff costs\n * two SQLite reads: the new value of the row (from the `curr` snapshot) and\n * the previous value(s) that it replaces (from the `prev` snapshot). The\n * reads for a given change are identical for every client group that\n * traverses it, so a replicated transaction of N rows costs N × 2 × (client\n * groups) reads per worker, most of which are redundant. This cache lets the\n * client groups on a worker share those reads.\n *\n * ### Keys\n *\n * Entries are keyed by the exact SQL statement and arguments of the read\n * (which encodes the table, the selected columns and the lookup keys), plus\n * a `tag` supplied by the caller that pins the result to a version of the\n * replica:\n *\n * - The new value of a row is the row as of the `stateVersion` recorded in\n * its change log entry (its `_0_version` is asserted to equal that\n * version), and is tagged with that `stateVersion`. It is thus shareable\n * by all client groups regardless of the snapshots they are advancing\n * between.\n * - Previous values are read from the `prev` snapshot at its version, and\n * are tagged with that version (and, when the result can depend on the\n * changes applied to the snapshot before the read, the `curr` version\n * as well). See `Diff` in `snapshotter.ts` for the details.\n *\n * Because every key includes the version(s) that the result depends on,\n * entries never go stale and are never invalidated; they are only evicted.\n *\n * ### Eviction\n *\n * The cache is bounded by entry count and evicts in insertion (FIFO) order\n * rather than by recency. Diffs are traversed in change log order by every\n * client group, so the entries that will not be needed again are those that\n * were inserted the earliest (all groups have moved past them), while the\n * most recently inserted entries are the ones that the trailing groups have\n * yet to reach. Refreshing an entry on a hit would evict exactly the wrong\n * entries when a trailing group catches up.\n *\n * ### Sharing\n *\n * Cached values are shared by reference across client groups and must\n * therefore never be mutated by callers.\n */\nexport class SnapshotRowCache {\n readonly #maxEntries: number;\n readonly #entries = new Map<string, unknown>();\n // The keys of #entries in insertion order, so that the oldest can be\n // evicted in O(1). (Finding the oldest key with a fresh Map iterator\n // instead costs O(evictions) per insert, as V8 leaves deleted entries in\n // the table until it is compacted and every new iterator walks over them.)\n readonly #keys = new RingBuffer<string>();\n // Interns the SQL text of each distinct read so that entry keys\n // do not repeat the (long) column list of every statement.\n readonly #sqlIDs = new Map<string, number>();\n readonly #reads = getOrCreateCounter(\n 'sync',\n 'ivm.snapshot-row-reads',\n 'Row reads performed while computing snapshot diffs for IVM, labeled by whether the read was served by the worker-wide snapshot row cache.',\n );\n #hits = 0;\n #misses = 0;\n\n constructor(maxEntries = DEFAULT_MAX_SNAPSHOT_ROW_CACHE_ENTRIES) {\n this.#maxEntries = Math.max(0, maxEntries);\n }\n\n get size(): number {\n return this.#entries.size;\n }\n\n get maxEntries(): number {\n return this.#maxEntries;\n }\n\n stats(): {hits: number; misses: number; size: number} {\n return {hits: this.#hits, misses: this.#misses, size: this.#entries.size};\n }\n\n /**\n * Returns the cached result of the read identified by `tag`, `sql`, `mode`\n * and `args`, or performs the read via `read()`, caching and returning its\n * result. `undefined` results (i.e. a missing row) are not cached.\n *\n * `mode` is part of the key because the same statement can be read both\n * ways: for a table whose only unique key is its primary key, `getRow()`\n * and `getRows()` produce identical SQL, args and tags, but the former\n * caches a row and the latter an array of rows.\n */\n getOrRead<T>(\n tag: string,\n sql: string,\n mode: ReadMode,\n args: unknown[],\n read: () => T,\n ): T {\n const key = this.#key(tag, sql, mode, args);\n const cached = this.#entries.get(key);\n if (cached !== undefined) {\n this.#hits++;\n this.#reads.add(1, HIT);\n return cached as T;\n }\n this.#misses++;\n this.#reads.add(1, MISS);\n const value = read();\n if (value !== undefined && this.#maxEntries > 0) {\n // `key` is not in #entries (this is a miss), so it is always added.\n this.#entries.set(key, value);\n this.#keys.push(key);\n if (this.#keys.size > this.#maxEntries) {\n this.#entries.delete(must(this.#keys.shift()));\n }\n }\n return value;\n }\n\n clear(): void {\n this.#entries.clear();\n this.#keys.clear();\n this.#sqlIDs.clear();\n }\n\n #key(tag: string, sql: string, mode: ReadMode, args: unknown[]): string {\n if (\n this.#sqlIDs.size >= MAX_INTERNED_STATEMENTS &&\n !this.#sqlIDs.has(sql)\n ) {\n // Statements are only added (e.g. when schema changes produce new\n // column lists), so bound them by starting over. The entries refer to\n // statements by ID and are cleared with them.\n this.clear();\n }\n const sqlID = getOrInsert(this.#sqlIDs, sql, this.#sqlIDs.size);\n let key = `${tag}\\0${mode}${sqlID}`;\n // Include each value's length so separators inside string values cannot\n // make different argument arrays produce the same key.\n for (const arg of args) {\n const serialized = serialize(arg);\n key += `\\0${serialized.length}:${serialized}`;\n }\n return key;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAgBA,IAAa,yCAAyC;;;;;;;AAQtD,SAAS,UAAU,GAAoB;CACrC,QAAQ,OAAO,GAAf;EACE,KAAK,UACH,OAAO,MAAM;EACf,KAAK;EACL,KAAK,UACH,OAAO,OAAO,CAAC;EACjB,KAAK,WACH,OAAO,IAAI,SAAS;EACtB,KAAK,UACH,OAAO,MAAM,OAAO,SAAS,MAAM,UAAU,CAAC;EAChD,SACE,OAAO,MAAM,OAAO,CAAC;CACzB;AACF;;;;;;AAaA,IAAa,0BAA0B;AAEvC,IAAM,MAAM,EAAC,QAAQ,MAAK;AAC1B,IAAM,OAAO,EAAC,QAAQ,OAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmD5B,IAAa,mBAAb,MAA8B;CAC5B;CACA,2BAAoB,IAAI,IAAqB;CAK7C,QAAiB,IAAI,WAAmB;CAGxC,0BAAmB,IAAI,IAAoB;CAC3C,SAAkB,mBAChB,QACA,0BACA,2IACF;CACA,QAAQ;CACR,UAAU;CAEV,YAAY,aAAa,wCAAwC;EAC/D,KAAK,cAAc,KAAK,IAAI,GAAG,UAAU;CAC3C;CAEA,IAAI,OAAe;EACjB,OAAO,KAAK,SAAS;CACvB;CAEA,IAAI,aAAqB;EACvB,OAAO,KAAK;CACd;CAEA,QAAsD;EACpD,OAAO;GAAC,MAAM,KAAK;GAAO,QAAQ,KAAK;GAAS,MAAM,KAAK,SAAS;EAAI;CAC1E;;;;;;;;;;;CAYA,UACE,KACA,KACA,MACA,MACA,MACG;EACH,MAAM,MAAM,KAAK,KAAK,KAAK,KAAK,MAAM,IAAI;EAC1C,MAAM,SAAS,KAAK,SAAS,IAAI,GAAG;EACpC,IAAI,WAAW,KAAA,GAAW;GACxB,KAAK;GACL,KAAK,OAAO,IAAI,GAAG,GAAG;GACtB,OAAO;EACT;EACA,KAAK;EACL,KAAK,OAAO,IAAI,GAAG,IAAI;EACvB,MAAM,QAAQ,KAAK;EACnB,IAAI,UAAU,KAAA,KAAa,KAAK,cAAc,GAAG;GAE/C,KAAK,SAAS,IAAI,KAAK,KAAK;GAC5B,KAAK,MAAM,KAAK,GAAG;GACnB,IAAI,KAAK,MAAM,OAAO,KAAK,aACzB,KAAK,SAAS,OAAO,KAAK,KAAK,MAAM,MAAM,CAAC,CAAC;EAEjD;EACA,OAAO;CACT;CAEA,QAAc;EACZ,KAAK,SAAS,MAAM;EACpB,KAAK,MAAM,MAAM;EACjB,KAAK,QAAQ,MAAM;CACrB;CAEA,KAAK,KAAa,KAAa,MAAgB,MAAyB;EACtE,IACE,KAAK,QAAQ,QAAA,OACb,CAAC,KAAK,QAAQ,IAAI,GAAG,GAKrB,KAAK,MAAM;EAGb,IAAI,MAAM,GAAG,IAAI,IAAI,OADP,YAAY,KAAK,SAAS,KAAK,KAAK,QAAQ,IAC9B;EAG5B,KAAK,MAAM,OAAO,MAAM;GACtB,MAAM,aAAa,UAAU,GAAG;GAChC,OAAO,KAAK,WAAW,OAAO,GAAG;EACnC;EACA,OAAO;CACT;AACF"}
|
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
import { assert } from "../../../../shared/src/asserts.js";
|
|
2
|
-
import { parse } from "../../../../shared/src/valita.js";
|
|
3
2
|
import { getOrInsertComputed } from "../../../../shared/src/map.js";
|
|
4
3
|
import { stringify } from "../../../../shared/src/bigint-json.js";
|
|
5
4
|
import { Database } from "../../../../zqlite/src/db.js";
|
|
6
5
|
import { recordIndexUsage } from "../../../../zqlite/src/index-usage.js";
|
|
7
6
|
import { fromSQLiteTypes } from "../../../../zqlite/src/table-source.js";
|
|
8
7
|
import "../replicator/schema/constants.js";
|
|
8
|
+
import { StatementRunner } from "../../db/statements.js";
|
|
9
9
|
import { normalizedKeyOrder } from "../../types/row-key.js";
|
|
10
|
-
import {
|
|
10
|
+
import { parseChangeLogEntry } from "../replicator/schema/change-log.js";
|
|
11
11
|
import { getReplicationState } from "../replicator/schema/replication-state.js";
|
|
12
|
-
import { StatementRunner } from "../../db/statements.js";
|
|
13
12
|
import { id } from "../../types/sql.js";
|
|
14
13
|
//#region ../zero-cache/src/services/view-syncer/snapshotter.ts
|
|
15
14
|
/**
|
|
@@ -330,7 +329,8 @@ var Snapshot = class Snapshot {
|
|
|
330
329
|
if (pageCacheSizeKib !== void 0) conn.pragma(`cache_size = -${pageCacheSizeKib}`);
|
|
331
330
|
const [{ journal_mode: mode }] = conn.pragma("journal_mode");
|
|
332
331
|
assert(mode === "wal2", `replica db must be in wal2 mode (current: ${mode})`);
|
|
333
|
-
|
|
332
|
+
const db = new StatementRunner(conn);
|
|
333
|
+
return new Snapshot(db, appID);
|
|
334
334
|
}
|
|
335
335
|
db;
|
|
336
336
|
#appID;
|
|
@@ -443,6 +443,7 @@ var Snapshot = class Snapshot {
|
|
|
443
443
|
WHERE "stateVersion" > ? ORDER BY "stateVersion" ASC, "pos" ASC` : `SELECT "stateVersion", "table", "rowKey", "op" FROM "_zero.changeLog2"
|
|
444
444
|
WHERE "stateVersion" > ? AND ${CHANGE_LOG_TABLES_FILTER}
|
|
445
445
|
ORDER BY "stateVersion" ASC, "pos" ASC`);
|
|
446
|
+
cached.statement.raw(true);
|
|
446
447
|
return {
|
|
447
448
|
changes: tables === void 0 ? cached.statement.iterate(prevVersion) : cached.statement.iterate(prevVersion, "r", "t", tables),
|
|
448
449
|
cleanup: () => this.db.statementCache.return(cached)
|
|
@@ -654,7 +655,7 @@ var Diff = class {
|
|
|
654
655
|
}
|
|
655
656
|
this.changesScanned++;
|
|
656
657
|
const parseStart = performance.now();
|
|
657
|
-
const { table, rowKey, op, stateVersion } =
|
|
658
|
+
const { table, rowKey, op, stateVersion } = parseChangeLogEntry(...value);
|
|
658
659
|
this.stats.parseMs += performance.now() - parseStart;
|
|
659
660
|
this.changesScannedByTable.set(table, (this.changesScannedByTable.get(table) ?? 0) + 1);
|
|
660
661
|
if (op === "r") throw new ResetPipelinesSignal(`schema for table ${table} has changed`, "schema-change");
|
|
@@ -698,7 +699,10 @@ var Diff = class {
|
|
|
698
699
|
this.changesSkipped++;
|
|
699
700
|
continue;
|
|
700
701
|
}
|
|
701
|
-
if (table === this.#permissionsTable
|
|
702
|
+
if (table === this.#permissionsTable) {
|
|
703
|
+
const changed = prevValues.find((prevValue) => prevValue.permissions !== nextValue?.permissions);
|
|
704
|
+
if (changed) throw new ResetPipelinesSignal(`Permissions have changed ${changed.hash} => ${nextValue?.hash}`, "permissions-change");
|
|
705
|
+
}
|
|
702
706
|
return { value: {
|
|
703
707
|
table,
|
|
704
708
|
prevValues: prevValues.map((prevValue) => fromSQLiteTypes(zqlSpec, prevValue, table)),
|
|
@@ -725,7 +729,7 @@ var Diff = class {
|
|
|
725
729
|
checkThatDiffIsValid(stateVersion, op, prevValues, nextValue) {
|
|
726
730
|
if (stateVersion > this.curr.version) throw new InvalidDiffError(`Diff is no longer valid. curr db has advanced past ${this.curr.version}`);
|
|
727
731
|
if (prevValues.findIndex((prevValue) => (prevValue["_0_version"] ?? "~") > this.prev.version) !== -1) throw new InvalidDiffError(`Diff is no longer valid. prev db has advanced past ${this.prev.version}.`);
|
|
728
|
-
if (op === "s" && nextValue["_0_version"] !== stateVersion) throw new InvalidDiffError("Diff is no longer valid. curr db has advanced.");
|
|
732
|
+
if (op === "s" && nextValue?.["_0_version"] !== stateVersion) throw new InvalidDiffError("Diff is no longer valid. curr db has advanced.");
|
|
729
733
|
}
|
|
730
734
|
};
|
|
731
735
|
var InvalidDiffError = class extends Error {
|
|
@@ -734,6 +738,6 @@ var InvalidDiffError = class extends Error {
|
|
|
734
738
|
}
|
|
735
739
|
};
|
|
736
740
|
//#endregion
|
|
737
|
-
export { ResetPipelinesSignal, Snapshotter };
|
|
741
|
+
export { InvalidDiffError, ResetPipelinesSignal, Snapshotter };
|
|
738
742
|
|
|
739
743
|
//# sourceMappingURL=snapshotter.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"snapshotter.js","names":["#lc","#dbFile","#appID","#pageCacheSizeKib","#rowCache","#curr","#prev","#assertNotAdvanced","#reset","#permissionsTable","#syncableTables","#allTableNames","#observedTables","#readTables","#prevTagUniform","#prevTagDivergent","#prevWrites","#hasEntries","#nothingToRead","#permissionsChanged","#iterated"],"sources":["../../../../../../zero-cache/src/services/view-syncer/snapshotter.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {assert} from '../../../../shared/src/asserts.ts';\nimport {stringify, type JSONValue} from '../../../../shared/src/bigint-json.ts';\nimport {getOrInsertComputed} from '../../../../shared/src/map.ts';\nimport * as v from '../../../../shared/src/valita.ts';\nimport type {Row} from '../../../../zero-protocol/src/data.ts';\nimport type {PrimaryKey} from '../../../../zero-types/src/schema.ts';\nimport {Database} from '../../../../zqlite/src/db.ts';\nimport {recordIndexUsage} from '../../../../zqlite/src/index-usage.ts';\nimport {fromSQLiteTypes} from '../../../../zqlite/src/table-source.ts';\nimport type {\n LiteAndZqlSpec,\n LiteTableSpecWithKeysAndVersion,\n} from '../../db/specs.ts';\nimport {StatementRunner} from '../../db/statements.ts';\nimport {\n normalizedKeyOrder,\n type RowKey,\n type RowValue,\n} from '../../types/row-key.ts';\nimport type {AppID} from '../../types/shards.ts';\nimport {id} from '../../types/sql.ts';\nimport {\n RESET_OP,\n changeLogEntrySchema as schema,\n SET_OP,\n TRUNCATE_OP,\n} from '../replicator/schema/change-log.ts';\nimport {\n getReplicationState,\n ZERO_VERSION_COLUMN_NAME as ROW_VERSION,\n} from '../replicator/schema/replication-state.ts';\nimport type {SnapshotRowCache} from './snapshot-row-cache.ts';\n\n/**\n * A `Snapshotter` manages the progression of database snapshots for a\n * ViewSyncer.\n *\n * The Replicator and ViewSyncers operate on the same SQLite file, with the\n * Replicator being the sole writer to the database. The IVM logic in\n * ViewSyncers, however, rely on incrementally applying changes to the DB to\n * update the state of its pipelines.\n *\n * To avoid coupling the progress of the Replicator and all IVM pipelines on\n * each other, ViewSyncers operate on ephemeral forks of the database by holding\n * [concurrent](https://sqlite.org/src/doc/begin-concurrent/doc/begin_concurrent.md)\n * snapshots of the database and simulating (but ultimately rolling back)\n * mutations on these snapshots.\n *\n * Example:\n * 1. ViewSyncer takes `snapshot_a` at version `t1` of the database and\n * hydrates its pipeline(s).\n * 2. Replicator applies a new transaction to the database and notifies\n * subscribers.\n * 3. ViewSyncer takes `snapshot_b` at `t2`, and queries the `ChangeLog` at\n * that snapshot for changes since `t1`.\n * 4. ViewSyncer applies those changes to `snapshot_a` for IVM, but does not\n * commit them. (Recall that the Replicator is the sole writer to the db, so\n * the ViewSyncer never commits any writes.)\n * 5. Replicator applies the next transaction and advances the database to `t3`.\n * 6. ViewSyncer rolls back `snapshot_a` and opens `snapshot_c` at `t3`, using\n * `snapshot_b` to simulate changes from `t2` to `t3`.\n *\n * ```\n * Replicator: t1 --------------> t2 --------------> t3 --------------->\n * ViewSyncer: [snapshot_a] ----> [snapshot_b] ----> [snapshot_c]\n * ```\n *\n * Note that the Replicator (and ViewSyncers) do not wait on the progress of\n * other ViewSyncers. If a ViewSyncer is busy hydrating at `t1`, the Replicator\n * and other ViewSyncers can progress through `t2`, `t3`, etc. independently,\n * as the busy ViewSyncer simply takes its own snapshot when it is ready.\n *\n * ```\n * Replicator: t1 --------------> t2 --------------> t3 --------------->\n * ViewSyncer1: [snapshot_a] ----> [snapshot_b] ----> [snapshot_c]\n * ViewSyncer2: [.......... snapshot_a ..........] ----> [snapshot_b]\n * ```\n *\n * To minimize Database connections (and statement preparation, etc.), the\n * Snapshotter reuses the connection from the previous (rolled back)\n * snapshot when opening the new one.\n *\n * ```\n * Replicator: t1 --------------> t2 --------------> t3 --------------->\n * ViewSyncer: [snapshot_a] ----> [snapshot_b] ----> [snapshot_c]\n * (conn_1) (conn_2) (conn_1)\n * ```\n *\n * In this manner, each ViewSyncer uses two connections that continually\n * \"leapfrog\" each other to replay the timeline of changes in isolation from\n * the Replicator and other ViewSyncers.\n */\nexport class Snapshotter {\n readonly #lc: LogContext;\n readonly #dbFile: string;\n readonly #appID: string;\n readonly #pageCacheSizeKib: number | undefined;\n readonly #rowCache: SnapshotRowCache | undefined;\n #curr: Snapshot | undefined;\n #prev: Snapshot | undefined;\n\n /**\n * @param rowCache An optional worker-wide {@link SnapshotRowCache} through\n * which the row reads performed when iterating over a\n * {@link SnapshotDiff} are shared with the other Snapshotters\n * (i.e. client groups) on the worker.\n */\n constructor(\n lc: LogContext,\n dbFile: string,\n {appID}: AppID,\n pageCacheSizeKib?: number,\n rowCache?: SnapshotRowCache,\n ) {\n this.#lc = lc;\n this.#dbFile = dbFile;\n this.#appID = appID;\n this.#pageCacheSizeKib = pageCacheSizeKib;\n this.#rowCache = rowCache;\n }\n\n /**\n * Initializes the snapshot to the current head of the database. This must be\n * only be called once. The state of whether a Snapshotter has been initialized\n * can be determined by calling {@link initialized()}.\n */\n init(): this {\n assert(this.#curr === undefined, 'Already initialized');\n this.#curr = Snapshot.create(\n this.#lc,\n this.#dbFile,\n this.#appID,\n this.#pageCacheSizeKib,\n );\n this.#lc.debug?.(`Initial snapshot at version ${this.#curr.version}`);\n return this;\n }\n\n initialized(): boolean {\n return this.#curr !== undefined;\n }\n\n /** Returns the current snapshot. Asserts if {@link initialized()} is false. */\n current(): Snapshot {\n assert(this.#curr !== undefined, 'Snapshotter has not been initialized');\n return this.#curr;\n }\n\n /**\n * Advances to the head of the Database, returning a diff between the\n * previously current Snapshot and a new Snapshot at head. This is called\n * in response to a notification from a Replicator subscription. Subsequent\n * calls to {@link current()} return the new Snapshot. Note that the Snapshotter\n * must be initialized before advancing.\n *\n * The returned {@link SnapshotDiff} contains snapshots at the endpoints\n * of the database timeline. Iterating over the diff generates a sequence\n * of {@link Change}s between the two snapshots.\n *\n * Note that this sequence is not chronological; rather, the sequence is\n * ordered by `<table, row-key>`, such that a row can appear at most once\n * in the common case, or twice if its table is `TRUNCATE`'d and a new value\n * is subsequently `INSERT`'ed. This results in dropping most intermediate\n * changes to a row and bounds the amount of work needed to catch up;\n * however, as a consequence, a consistent database state is only guaranteed\n * when the sequence has been fully consumed.\n *\n * Note that Change generation relies on the state of the underlying\n * database connections, and because the connection for the previous snapshot\n * is reused to produce the next snapshot, the diff object is only valid\n * until the next call to `advance()`.\n *\n * It is okay for the caller to apply `Change`s to the `prev` snapshot\n * during the iteration (e.g. this is necessary for IVM); the remainder\n * of the iteration is not affected because a given row can appear at most\n * once in the sequence (with the exception being TRUNCATE, after which the\n * deleted rows can be re-inserted, but this will also behave correctly if\n * the changes are applied).\n *\n * Once the changes have been applied, however, a _subsequent_ iteration\n * will not produce the correct results. In order to perform multiple\n * change-applying iterations, the caller must (1) create a save point\n * on `prev` before each iteration, and (2) rollback to the save point after\n * the iteration.\n *\n * @param prevWrites How the caller writes to `prev` during the iteration,\n * which determines which `prev` reads can be shared through the\n * {@link SnapshotRowCache}. See {@link PrevWrites}.\n */\n advance(\n syncableTables: Map<string, LiteAndZqlSpec>,\n allTableNames: Set<string>,\n observedTables?: TableFilter | undefined,\n prevWrites: PrevWrites = 'uniform',\n ): SnapshotDiff {\n this.advanceWithoutDiff();\n return this.diff(syncableTables, allTableNames, observedTables, prevWrites);\n }\n\n /**\n * The diff between the two snapshots of the last\n * {@link advanceWithoutDiff()}, as {@link advance()} returns it.\n *\n * @param counts The counts of the change log entries between the two\n * snapshots, if the caller has counted them already (see\n * `Snapshot.countChangesSince()`). The diff then does not count\n * them again.\n * @param readTables If set, only the change log entries of these tables\n * (and of the permissions table) are read, along with the\n * table-wide ops of every table, where `observedTables` reads the\n * entries of every table and skips those it does not have. For a\n * caller that does not need the changes of the other tables, this\n * saves reading and parsing their entries. This requires `counts`.\n * If they show that there is no entry of these tables and no\n * table-wide op, the change log is not read at all, and the\n * diff's `changes` is 0.\n */\n diff(\n syncableTables: Map<string, LiteAndZqlSpec>,\n allTableNames: Set<string>,\n observedTables?: TableFilter | undefined,\n prevWrites: PrevWrites = 'uniform',\n counts?: ChangeLogCounts | undefined,\n readTables?: Iterable<string> | undefined,\n ): SnapshotDiff {\n assert(\n this.#prev !== undefined && this.#curr !== undefined,\n 'Snapshotter has not been advanced',\n );\n return new Diff(\n this.#appID,\n syncableTables,\n allTableNames,\n this.#prev,\n this.#curr,\n observedTables,\n this.#rowCache,\n prevWrites,\n counts,\n readTables,\n );\n }\n\n advanceWithoutDiff() {\n assert(this.#curr !== undefined, 'Snapshotter has not been initialized');\n const next = this.#prev\n ? this.#prev.resetToHead()\n : Snapshot.create(\n this.#lc,\n this.#curr.db.db.name,\n this.#appID,\n this.#pageCacheSizeKib,\n );\n this.#prev = this.#curr;\n this.#curr = next;\n return {prev: this.#prev, curr: this.#curr};\n }\n\n /**\n * The reset of the pipelines that iterating over the changes from the\n * previous snapshot to the current one ends in, if it does: the first of\n * a schema change, a truncation, and a change of the permissions. It is\n * found without iterating, so that a caller that would reset the pipelines\n * anyway does not first process the changes that come before it.\n *\n * If there is none, iterating over a {@link diff()} of the two snapshots\n * does not throw a {@link ResetPipelinesSignal}, and can be stopped at any\n * point without missing one.\n *\n * @param counts The changes from the previous snapshot to the current\n * one, from which it is known whether there is anything to look\n * for.\n */\n pendingReset(\n syncableTables: Map<string, LiteAndZqlSpec>,\n counts: ChangeLogCounts,\n ): ResetPipelinesSignal | undefined {\n assert(\n this.#prev !== undefined && this.#curr !== undefined,\n 'Snapshotter has not been advanced',\n );\n const prev = this.#prev;\n const curr = this.#curr;\n let first: (ChangeLogPosition & {signal: ResetPipelinesSignal}) | undefined;\n\n if (counts.tableWideOps > 0) {\n // Iterating aborts at a table-wide op whatever its table is.\n const {stateVersion, pos, table, op} = curr.firstTableWideOpSince(\n prev.version,\n );\n first = {\n stateVersion,\n pos,\n signal:\n op === TRUNCATE_OP\n ? new ResetPipelinesSignal(\n `table ${table} has been truncated`,\n 'truncation',\n )\n : new ResetPipelinesSignal(\n `schema for table ${table} has changed`,\n 'schema-change',\n ),\n };\n }\n\n // An entry of the permissions table only aborts the iteration if the\n // permissions are different, which takes reading the row to know.\n const permissionsTable = `${this.#appID}.permissions`;\n const specs = syncableTables.get(permissionsTable);\n if (\n specs &&\n (counts.sampled || (counts.byTable.get(permissionsTable) ?? 0) > 0)\n ) {\n const {tableSpec} = specs;\n for (const entry of curr.entriesSince(permissionsTable, prev.version)) {\n if (first && !isBefore(entry, first)) {\n break;\n }\n const rowKey: JSONValue = entry.rowKey && JSON.parse(entry.rowKey);\n if (rowKey === null) {\n continue;\n }\n const nextValue =\n entry.op === SET_OP ? curr.getRow(tableSpec, rowKey) : null;\n let prevValues;\n if (nextValue) {\n prevValues = prev.getRows(tableSpec, tableSpec.uniqueKeys, nextValue);\n } else {\n const prevValue = prev.getRow(tableSpec, rowKey);\n prevValues = prevValue ? [prevValue] : [];\n }\n const changed = prevValues.find(\n prevValue => prevValue.permissions !== nextValue?.permissions,\n );\n if (changed) {\n first = {\n ...entry,\n signal: new ResetPipelinesSignal(\n `Permissions have changed ${changed.hash} => ${nextValue?.hash}`,\n 'permissions-change',\n ),\n };\n break;\n }\n }\n }\n return first?.signal;\n }\n\n /**\n * Releases the previous snapshot, i.e. the `prev` of the last\n * {@link advance()} or {@link advanceWithoutDiff()}. It is only read\n * while the diff that it is the start of is iterated over, but its read\n * transaction otherwise stays open until the next advance, which keeps\n * the replica from checkpointing its write-ahead log past it. A diff that\n * starts at it can no longer be iterated over.\n */\n releasePrevious(): void {\n this.#prev?.release();\n }\n\n /**\n * Call this to close the database connections when the Snapshotter is\n * no longer needed.\n */\n destroy() {\n // The replica's statistics are maintained by the replicator. The\n // `PRAGMA optimize` that closing a writable connection otherwise runs\n // analyzes the tables that the connection read, which blocks the worker\n // for as long as that takes, and what it finds is discarded with the\n // snapshot's transaction.\n this.#curr?.db.db.close({optimize: false});\n this.#prev?.db.db.close({optimize: false});\n this.#lc.debug?.('closed database connections');\n }\n}\n\nexport type Change = {\n readonly table: string;\n /**\n * If this change represents a remove the row to remove,\n * if nextValue is not null then all rows that have a unique constraint\n * violation with nextValue.\n * In both cases these rows should be removed.\n */\n readonly prevValues: Readonly<Row>[];\n readonly nextValue: Readonly<Row> | null;\n readonly rowKey: RowKey;\n};\n\n/** See `Snapshot.countChangesSince()`. */\n/** Where an entry is in the order that the change log is read in. */\ntype ChangeLogPosition = {\n readonly stateVersion: string;\n readonly pos: number;\n};\n\nfunction isBefore(a: ChangeLogPosition, b: ChangeLogPosition): boolean {\n return a.stateVersion === b.stateVersion\n ? a.pos < b.pos\n : a.stateVersion < b.stateVersion;\n}\n\nexport type ChangeLogCounts = {\n /** The number of entries. */\n readonly total: number;\n /** The number of them that are table-wide ops (a RESET or TRUNCATE). */\n readonly tableWideOps: number;\n /**\n * The number of entries of each table. If {@link sampled}, these are\n * estimates, and a table with few entries may be missing.\n */\n readonly byTable: ReadonlyMap<string, number>;\n /** Whether {@link byTable} was estimated from a sample of the entries. */\n readonly sampled: boolean;\n};\n\n/**\n * The most change log entries that are read to count a batch's changes by\n * table. Reading an entry costs microseconds, and nothing else runs on the\n * sync worker in the meantime, so the cost of counting must not grow with\n * the number of changes that a client group has to catch up on.\n */\nexport const CHANGE_LOG_SAMPLE_SIZE = 1000;\n\nexport interface TableFilter {\n has(table: string): boolean;\n}\n\n/**\n * How the caller of {@link Snapshotter.advance()} writes the changes of a\n * {@link SnapshotDiff} to its `prev` snapshot while iterating over it.\n *\n * A `prev` read for a table with a single unique key (its primary key)\n * cannot observe earlier changes of the iteration, since a row key appears\n * once in the diff. A read for a table with other unique keys can, because\n * the rows it returns may have been displaced or edited by earlier changes.\n *\n * * `uniform`: every caller applies every change, so such a read depends on\n * the `<prev, curr>` versions of the diff, and is shared on that basis.\n * * `divergent`: callers apply different subsets of the changes (e.g. the\n * pipeline driver skips changes that no pipeline can observe), so such a\n * read depends on the caller and is not shared.\n * * `none`: the caller does not write to `prev` (e.g. IVM derivation is\n * held in memory), so every read depends solely on `prev.version`.\n */\nexport type PrevWrites = 'uniform' | 'divergent' | 'none';\n\n/**\n * Represents the difference between two database Snapshots.\n * Iterating over the object will produce a sequence of {@link Change}s\n * between the two snapshots.\n *\n * See {@link Snapshotter.advance()} for semantics and usage.\n */\nexport type DiffTimingStats = {\n changeLogReadMs: number;\n rowReadMs: number;\n parseMs: number;\n totalDiffMs: number;\n};\n\nexport interface SnapshotDiff extends Iterable<Change> {\n readonly prev: {\n readonly db: StatementRunner;\n readonly version: string;\n };\n readonly curr: {\n readonly db: StatementRunner;\n readonly version: string;\n };\n\n /**\n * The raw number of ChangeLog entries between the snapshots, before filtering\n * out unobserved/non-syncable tables or no-op changes. Progress against this\n * total must use {@link changesScanned}, rather than the number of yielded\n * changes. Table-wide operations abort iteration and reset the pipelines.\n */\n readonly changes: number;\n\n /** The number of raw ChangeLog entries read so far, including skipped entries. */\n readonly changesScanned: number;\n\n /**\n * The raw ChangeLog entries read so far, by table. Like\n * {@link changesScanned}, this includes the entries that are not yielded,\n * so it counts the same entries as {@link ChangeLogCounts.byTable} does.\n */\n readonly changesScannedByTable: ReadonlyMap<string, number>;\n\n /** The scanned entries omitted because their table is unobserved/non-syncable or the change is a no-op. */\n readonly changesSkipped: number;\n\n /**\n * The scanned entries whose rows were looked up in the snapshots. Unlike\n * the entries that are yielded, this includes the no-op changes, which are\n * only known to be that from their rows.\n */\n readonly changesLookedUp: number;\n\n /** Timing metrics recorded during diff iteration. */\n readonly stats?: DiffTimingStats | undefined;\n\n /**\n * Overrides the `prevWrites` passed to {@link Snapshotter.advance()}, for a\n * caller that decides how to write to `prev` once it knows the number of\n * {@link changes}. Must be called before the diff is iterated, except to\n * switch to `divergent`, which can be done between any two changes: it\n * shares only the reads that no write to `prev` can affect.\n */\n setPrevWrites(prevWrites: PrevWrites): void;\n}\n\n/**\n * Thrown during an iteration of a {@link SnapshotDiff} when a schema\n * change or truncate is encountered, which result in aborting the\n * advancement and resetting / rehydrating the pipelines.\n */\nexport type ResetPipelinesReason =\n | 'advancement-timeout'\n | 'scalar-subquery'\n | 'schema-change'\n | 'truncation'\n | 'permissions-change';\n\nexport class ResetPipelinesSignal extends Error {\n readonly name = 'ResetPipelinesSignal';\n readonly reason: ResetPipelinesReason;\n readonly breakdown?: string | undefined;\n\n constructor(msg: string, reason: ResetPipelinesReason, breakdown?: string) {\n super(msg);\n this.reason = reason;\n this.breakdown = breakdown;\n }\n}\n\n// Memoizes, per table spec, the SQL of the row lookups performed for each\n// change, which would otherwise be rebuilt from the table spec for every\n// read. Handing out the same string for every read of a given shape also\n// lets the SnapshotRowCache and the statement cache look it up without\n// rehashing it. Specs are recreated whenever they are recomputed, so stale\n// SQL is never served.\ntype TableReads = {\n /** `SELECT <columns> FROM <table> WHERE ` */\n readonly prefix: string;\n /** {@link Snapshot.getRow} SQL, by the NUL-joined key columns. */\n readonly byKeyColumns: Map<string, string>;\n /**\n * {@link Snapshot.getRows} SQL, by the bitmask of the table's `uniqueKeys`\n * that are queried.\n */\n readonly byUniqueKeys: Map<number, string>;\n};\n\nconst tableReads = new WeakMap<LiteTableSpecWithKeysAndVersion, TableReads>();\n\nfunction readsFor(table: LiteTableSpecWithKeysAndVersion): TableReads {\n return getOrInsertComputed(tableReads, table, () => ({\n prefix: `SELECT ${Object.keys(table.columns)\n .map(c => id(c))\n .join(',')} FROM ${id(table.name)} WHERE `,\n byKeyColumns: new Map(),\n byUniqueKeys: new Map(),\n }));\n}\n\n// The byUniqueKeys bitmask must fit in a (positive) 31-bit integer.\nconst MAX_MEMOIZED_UNIQUE_KEYS = 30;\n\n/**\n * The index that SQLite creates for the `PRIMARY KEY(\"stateVersion\", \"pos\")`\n * of `_zero.changeLog2` (the first constraint of its CREATE TABLE statement,\n * hence the `_1` suffix).\n *\n * For a `stateVersion > ?` query that reads a column outside of this index\n * (e.g. `op`) and has no ORDER BY, the query planner chooses between a range\n * search of the index and a full scan of the table based on `sqlite_stat1`.\n * Statistics recorded while the change log held only a few rows make the full\n * scan look cheaper, and they persist as the table grows to millions of rows:\n * the change log of a replication-manager's replica only receives entries\n * during column backfills, and view-syncers inherit its statistics when they\n * restore its backup. Such queries therefore pin this index with INDEXED BY,\n * which also makes them fail to prepare (rather than silently scan) if the\n * index is ever renamed.\n */\nconst CHANGE_LOG_STATE_VERSION_INDEX = 'sqlite_autoindex__zero.changeLog2_1';\n\n/**\n * The index that SQLite creates for the `UNIQUE(\"table\", \"rowKey\")` of\n * `_zero.changeLog2` (the second constraint of its CREATE TABLE statement).\n */\nconst CHANGE_LOG_TABLE_INDEX = 'sqlite_autoindex__zero.changeLog2_2';\n\n/**\n * Selects the change log entries of the tables in a JSON array of names,\n * and the table-wide ops (RESET and TRUNCATE) of every table, which abort\n * the diff whatever table they are for. Binds the two ops, then the array.\n * The array is a single parameter so that the statement is the same, and is\n * prepared once, for any set of tables.\n */\nconst CHANGE_LOG_TABLES_FILTER = `(\"op\" IN (?, ?) OR \"table\" IN (SELECT \"value\" FROM json_each(?)))`;\n\nclass Snapshot {\n static create(\n lc: LogContext,\n dbFile: string,\n appID: string,\n pageCacheSizeKib: number | undefined,\n ) {\n const conn = new Database(lc, dbFile);\n conn.pragma('synchronous = OFF'); // Applied changes are ephemeral; COMMIT is never called.\n if (pageCacheSizeKib !== undefined) {\n conn.pragma(`cache_size = -${pageCacheSizeKib}`); // Negative = size in KiB\n }\n const [{journal_mode: mode}] = conn.pragma('journal_mode') as [\n {journal_mode: string},\n ];\n // BEGIN CONCURRENT lets the Snapshotter simulate changes on a historic\n // snapshot without taking the WAL writer lock. These private changes are\n // always rolled back; the replicator is the only committer and can use\n // BEGIN IMMEDIATE on the same WAL2 database.\n assert(\n mode === 'wal2',\n `replica db must be in wal2 mode (current: ${mode})`,\n );\n\n const db = new StatementRunner(conn);\n return new Snapshot(db, appID);\n }\n\n readonly db: StatementRunner;\n readonly #appID: string;\n readonly version: string;\n #reset = false;\n\n /**\n * @param begun Whether `db` is already in a `BEGIN CONCURRENT` transaction\n * that has not read anything.\n */\n constructor(db: StatementRunner, appID: string, begun = false) {\n if (!begun) {\n db.beginConcurrent();\n }\n // Note: The subsequent read is necessary to acquire the read lock\n // (which results in the logical creation of the snapshot). Calling\n // `BEGIN CONCURRENT` alone does not result in acquiring the read lock.\n const {stateVersion} = getReplicationState(db);\n\n this.db = db;\n this.#appID = appID;\n this.version = stateVersion;\n }\n\n numChangesSince(prevVersion: string) {\n const {count} = this.db.get(\n 'SELECT COUNT(*) AS count FROM \"_zero.changeLog2\" WHERE stateVersion > ?',\n prevVersion,\n );\n return count;\n }\n\n /**\n * Counts the change log entries after `prevVersion`. The change log keeps\n * the latest entry of a row, so these are counts of the rows that changed,\n * which is what a diff from `prevVersion` to this snapshot reads.\n *\n * The total, and the number of table-wide ops (a RESET or TRUNCATE), are\n * exact, and are counted from the index alone. The counts by table are\n * exact if there are at most `sampleSize` entries. Otherwise they are\n * estimated from the newest `sampleSize` entries, so that at most that\n * many entries are read however many there are.\n */\n countChangesSince(\n prevVersion: string,\n sampleSize = CHANGE_LOG_SAMPLE_SIZE,\n ): ChangeLogCounts {\n // The index has the stateVersion and pos of every entry, and a\n // table-wide op is logged at pos -1 (see ChangeLog), so no entry is read.\n const {total, tableWideOps} = this.db.get(\n `SELECT COUNT(*) AS total, COALESCE(SUM(pos < 0), 0) AS tableWideOps\n FROM \"_zero.changeLog2\" INDEXED BY \"${CHANGE_LOG_STATE_VERSION_INDEX}\"\n WHERE stateVersion > ?`,\n prevVersion,\n );\n const byTable = new Map<string, number>();\n if (total === 0) {\n return {total, tableWideOps, byTable, sampled: false};\n }\n const rows: {table: string; count: number}[] = this.db.all(\n `SELECT \"table\", COUNT(*) AS count FROM (\n SELECT \"table\"\n FROM \"_zero.changeLog2\" INDEXED BY \"${CHANGE_LOG_STATE_VERSION_INDEX}\"\n WHERE stateVersion > ?\n ORDER BY stateVersion DESC, pos DESC LIMIT ?\n ) GROUP BY \"table\"`,\n prevVersion,\n sampleSize,\n );\n const sampled = total > sampleSize;\n const scale = sampled ? total / sampleSize : 1;\n for (const {table, count} of rows) {\n byTable.set(table, count * scale);\n }\n return {total, tableWideOps, byTable, sampled};\n }\n\n /**\n * Whether an entry of `table` was logged after `prevVersion`. This reads\n * the table's entries in the change log, however old, so it is for tables\n * with few rows.\n */\n tableChangedSince(table: string, prevVersion: string): boolean {\n const row = this.db.get(\n `SELECT 1 FROM \"_zero.changeLog2\" INDEXED BY \"${CHANGE_LOG_TABLE_INDEX}\"\n WHERE \"table\" = ? AND stateVersion > ? LIMIT 1`,\n table,\n prevVersion,\n );\n return row !== undefined;\n }\n\n /**\n * Whether a table-wide RESET op (i.e. a schema change) was logged after\n * `prevVersion`. Table specs computed at or before `prevVersion` are\n * stale with respect to this snapshot if so.\n */\n schemaChangedSince(prevVersion: string): boolean {\n const row = this.db.get(\n `SELECT 1 FROM \"_zero.changeLog2\" INDEXED BY \"${CHANGE_LOG_STATE_VERSION_INDEX}\"\n WHERE stateVersion > ? AND op = ? LIMIT 1`,\n prevVersion,\n RESET_OP,\n );\n return row !== undefined;\n }\n\n /**\n * Whether any table-wide op (i.e. a RESET or TRUNCATE) was logged after\n * `prevVersion`. Iterating over a diff ending at this snapshot will\n * abort with a {@link ResetPipelinesSignal} if so.\n */\n hasTableWideOpSince(prevVersion: string): boolean {\n const row = this.db.get(\n `SELECT 1 FROM \"_zero.changeLog2\" INDEXED BY \"${CHANGE_LOG_STATE_VERSION_INDEX}\"\n WHERE stateVersion > ? AND op IN (?, ?) LIMIT 1`,\n prevVersion,\n RESET_OP,\n TRUNCATE_OP,\n );\n return row !== undefined;\n }\n\n /**\n * The first table-wide op (a schema change or a truncation) logged after\n * `prevVersion`, in the order that {@link changesSince} reads the entries.\n */\n firstTableWideOpSince(\n prevVersion: string,\n ): ChangeLogPosition & {table: string; op: string} {\n return this.db.get(\n `SELECT \"stateVersion\", \"pos\", \"table\", \"op\" FROM \"_zero.changeLog2\" INDEXED BY \"${CHANGE_LOG_STATE_VERSION_INDEX}\"\n WHERE \"stateVersion\" > ? AND \"pos\" < 0\n ORDER BY \"stateVersion\" ASC, \"pos\" ASC LIMIT 1`,\n prevVersion,\n );\n }\n\n /**\n * The entries of `table` logged after `prevVersion`, in the order that\n * {@link changesSince} reads them. For a table with few rows.\n */\n entriesSince(\n table: string,\n prevVersion: string,\n ): (ChangeLogPosition & {rowKey: string | null; op: string})[] {\n return this.db.all(\n `SELECT \"stateVersion\", \"pos\", \"rowKey\", \"op\" FROM \"_zero.changeLog2\" INDEXED BY \"${CHANGE_LOG_TABLE_INDEX}\"\n WHERE \"table\" = ? AND \"stateVersion\" > ?\n ORDER BY \"stateVersion\" ASC, \"pos\" ASC`,\n table,\n prevVersion,\n );\n }\n\n /**\n * @param tables If set, only the entries of these tables, and the\n * table-wide ops of every table, are read.\n */\n changesSince(prevVersion: string, tables?: string | undefined) {\n // Note: The queried fields are constrained to only those that are relevant\n // to the snapshot diff, i.e. those defined in the changeLogEntrySchema.\n const cached = this.db.statementCache.get(\n tables === undefined\n ? `SELECT \"stateVersion\", \"table\", \"rowKey\", \"op\" FROM \"_zero.changeLog2\"\n WHERE \"stateVersion\" > ? ORDER BY \"stateVersion\" ASC, \"pos\" ASC`\n : `SELECT \"stateVersion\", \"table\", \"rowKey\", \"op\" FROM \"_zero.changeLog2\"\n WHERE \"stateVersion\" > ? AND ${CHANGE_LOG_TABLES_FILTER}\n ORDER BY \"stateVersion\" ASC, \"pos\" ASC`,\n );\n return {\n changes:\n tables === undefined\n ? cached.statement.iterate(prevVersion)\n : cached.statement.iterate(\n prevVersion,\n RESET_OP,\n TRUNCATE_OP,\n tables,\n ),\n cleanup: () => this.db.statementCache.return(cached),\n };\n }\n\n /**\n * Reads the row with the given `rowKey`, or `undefined` if it does not\n * exist.\n *\n * @param cache An optional {@link SnapshotRowCache} through which to\n * perform the read, along with the `tag` that identifies the\n * version(s) of the replica that the result depends on.\n */\n getRow(\n table: LiteTableSpecWithKeysAndVersion,\n rowKey: JSONValue,\n cache?: SnapshotRowCache,\n tag?: string,\n ) {\n const key = normalizedKeyOrder(rowKey as RowKey);\n const cols = Object.keys(key);\n const reads = readsFor(table);\n const sql = getOrInsertComputed(\n reads.byKeyColumns,\n cols.join('\\0'),\n () => reads.prefix + cols.map(c => `${id(c)}=?`).join(' AND '),\n );\n const args = Object.values(key);\n const read = () =>\n this.db.statementCache.use(sql, cached => {\n cached.statement.safeIntegers(true);\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n const row = cached.statement.get<any>(args);\n recordIndexUsage(cached.statement, table.name);\n return row;\n });\n return cache\n ? cache.getOrRead(tag ?? '', sql, 'get', args, () => {\n const row = read();\n if (row !== undefined) {\n this.#assertNotAdvanced(row);\n }\n return row;\n })\n : read();\n }\n\n /**\n * Reads the rows that conflict with `row` on any of the given unique\n * `keys` (which includes the row with the same primary key, if any).\n *\n * @param cache An optional {@link SnapshotRowCache} through which to\n * perform the read, along with the `tag` that identifies the\n * version(s) of the replica that the result depends on.\n */\n getRows(\n table: LiteTableSpecWithKeysAndVersion,\n keys: PrimaryKey[],\n row: RowValue,\n cache?: SnapshotRowCache,\n tag?: string,\n ) {\n // Filter out keys where any column is NULL. This is both correct and\n // critical for performance:\n // 1. Correctness: NULL values can't violate uniqueness (NULL != NULL in SQL)\n // 2. Performance: SQLite's MULTI-INDEX OR optimization completely fails when\n // any branch involves NULL, falling back to a full table scan. This was\n // causing slowdowns of hundreds of times on tables with nullable unique columns.\n let validKeys: PrimaryKey[] = keys;\n let mask = (1 << keys.length) - 1;\n\n for (let i = 0; i < keys.length; i++) {\n const key = keys[i];\n for (let j = 0; j < key.length; j++) {\n const val = row[key[j]];\n if (val === null || val === undefined) {\n validKeys = [];\n mask = 0;\n for (let k = 0; k < keys.length; k++) {\n const candidate = keys[k];\n if (\n candidate.every(\n col => row[col] !== null && row[col] !== undefined,\n )\n ) {\n validKeys.push(candidate);\n mask |= 1 << k;\n }\n }\n break;\n }\n }\n if (validKeys !== keys) {\n break;\n }\n }\n\n if (validKeys.length === 0) {\n return [];\n }\n const reads = readsFor(table);\n const buildSQL = () =>\n reads.prefix +\n validKeys\n .map(key => key.map(c => `${id(c)}=?`).join(' AND '))\n .join(' OR ');\n const sql =\n keys === table.uniqueKeys && keys.length <= MAX_MEMOIZED_UNIQUE_KEYS\n ? getOrInsertComputed(reads.byUniqueKeys, mask, buildSQL)\n : buildSQL();\n const args: unknown[] = [];\n for (let i = 0; i < validKeys.length; i++) {\n const key = validKeys[i];\n for (let j = 0; j < key.length; j++) {\n args.push(row[key[j]]);\n }\n }\n const read = () =>\n this.db.statementCache.use(sql, cached => {\n cached.statement.safeIntegers(true);\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n const rows = cached.statement.all<any>(args);\n recordIndexUsage(cached.statement, table.name);\n return rows;\n });\n return cache\n ? cache.getOrRead(tag ?? '', sql, 'all', args, () => {\n const rows = read();\n for (const row of rows) {\n this.#assertNotAdvanced(row);\n }\n return rows;\n })\n : read();\n }\n\n /**\n * Rows are shared with other client groups via the SnapshotRowCache, so\n * one read from a connection that has advanced past this snapshot (i.e. a\n * {@link SnapshotDiff} used after its Snapshotter advanced) must fail\n * before it is cached, rather than be served to the valid Diffs of other\n * client groups (whose own validity checks would then fail).\n */\n #assertNotAdvanced(row: RowValue) {\n if ((row[ROW_VERSION] ?? '~') > this.version) {\n throw new InvalidDiffError(\n `Diff is no longer valid. db has advanced past ${this.version}.`,\n );\n }\n }\n\n /**\n * Whether the snapshot has been released, or its connection reset to a\n * newer snapshot (i.e. via {@link release()} or {@link resetToHead()}),\n * after which reads no longer reflect {@link version}.\n */\n get reset(): boolean {\n return this.#reset;\n }\n\n /**\n * Ends the snapshot's read transaction, after which reads no longer\n * reflect {@link version}. An open read transaction keeps SQLite from\n * checkpointing the write-ahead log past the snapshot, so a snapshot that\n * is no longer read should not be left open.\n */\n release(): void {\n if (!this.#reset) {\n this.#reset = true;\n this.db.rollback();\n // The connection is put back into a transaction, which holds nothing\n // until it reads. A snapshot's connection is writable, and outside of\n // a transaction anything that is run on it would be committed to the\n // replica under the replica's write lock, which only the replicator\n // should take.\n this.db.beginConcurrent();\n }\n }\n\n resetToHead(): Snapshot {\n this.release();\n return new Snapshot(this.db, this.#appID, true);\n }\n}\n\nclass Diff implements SnapshotDiff {\n readonly #permissionsTable: string;\n readonly #syncableTables: Map<string, LiteAndZqlSpec>;\n readonly #allTableNames: Set<string>;\n readonly #observedTables: TableFilter | undefined;\n readonly #rowCache: SnapshotRowCache | undefined;\n /** The JSON array of the names of the tables whose entries are read. */\n readonly #readTables: string | undefined;\n #permissionsChanged: boolean | undefined;\n #nothingToRead = false;\n #prevWrites: PrevWrites;\n readonly #prevTagUniform: string;\n readonly #prevTagDivergent: string;\n #iterated = false;\n readonly prev: Snapshot;\n readonly curr: Snapshot;\n readonly changes: number;\n changesScanned = 0;\n readonly changesScannedByTable = new Map<string, number>();\n changesSkipped = 0;\n changesLookedUp = 0;\n readonly stats: DiffTimingStats = {\n changeLogReadMs: 0,\n rowReadMs: 0,\n parseMs: 0,\n totalDiffMs: 0,\n };\n\n constructor(\n appID: string,\n syncableTables: Map<string, LiteAndZqlSpec>,\n allTableNames: Set<string>,\n prev: Snapshot,\n curr: Snapshot,\n observedTables?: TableFilter | undefined,\n rowCache?: SnapshotRowCache | undefined,\n prevWrites: PrevWrites = 'uniform',\n counts?: ChangeLogCounts | undefined,\n readTables?: Iterable<string> | undefined,\n ) {\n this.#prevWrites = prevWrites;\n this.#permissionsTable = `${appID}.permissions`;\n // A change of the permissions is always looked for.\n const read = readTables && new Set(readTables).add(this.#permissionsTable);\n this.#readTables = read && JSON.stringify([...read]);\n this.#syncableTables = syncableTables;\n this.#allTableNames = allTableNames;\n this.#observedTables = observedTables;\n this.prev = prev;\n this.curr = curr;\n this.#prevTagUniform = `p:${prev.version}`;\n this.#prevTagDivergent = `p:${prev.version}:${curr.version}`;\n if (counts === undefined) {\n assert(read === undefined, 'readTables requires counts');\n this.changes = curr.numChangesSince(prev.version);\n } else {\n // Without an entry of a table that is read, or a table-wide op (which\n // aborts the diff whatever table it is for), there is nothing to read.\n const hasEntries = (table: string) => this.#hasEntries(counts, table);\n this.#nothingToRead =\n counts.total === 0 ||\n (read !== undefined &&\n counts.tableWideOps === 0 &&\n ![...read].some(hasEntries));\n // As without counts, this is the number of entries of every table.\n this.changes = this.#nothingToRead ? 0 : counts.total;\n }\n // Row values are only shared (via the cache) between Diffs that do not\n // straddle a table-wide op. This guarantees that any two Diffs that\n // encounter the same change log entry read the row from tables with\n // the same schema (and contents), since a RESET or TRUNCATE between\n // their `curr` versions would necessarily fall within the range of the\n // later Diff. (Such a Diff aborts with a ResetPipelinesSignal anyway.)\n const hasTableWideOp = counts\n ? counts.tableWideOps > 0\n : curr.hasTableWideOpSince(prev.version);\n this.#rowCache = rowCache && !hasTableWideOp ? rowCache : undefined;\n }\n\n /**\n * Whether the diff has an entry of `table`. Sampled counts cannot show\n * that a table has none, so the answer is then `true`, except for the\n * permissions table: it has few rows, so whether it has an entry is\n * looked up instead.\n */\n #hasEntries(counts: ChangeLogCounts, table: string): boolean {\n if (!counts.sampled) {\n return (counts.byTable.get(table) ?? 0) > 0;\n }\n if (table !== this.#permissionsTable) {\n return true;\n }\n return (this.#permissionsChanged ??= this.curr.tableChangedSince(\n table,\n this.prev.version,\n ));\n }\n\n setPrevWrites(prevWrites: PrevWrites): void {\n assert(\n !this.#iterated || prevWrites === 'divergent',\n 'prevWrites must be set before iterating the diff',\n );\n this.#prevWrites = prevWrites;\n }\n\n [Symbol.iterator](): Iterator<Change> {\n this.#iterated = true;\n if (this.#nothingToRead) {\n return [][Symbol.iterator]();\n }\n const {changes, cleanup: done} = this.curr.changesSince(\n this.prev.version,\n this.#readTables,\n );\n\n const cleanup = () => {\n try {\n // Allow open iterators to clean up their state.\n changes.return?.(undefined);\n } finally {\n done();\n }\n };\n\n return {\n next: () => {\n const nextStart = performance.now();\n try {\n for (;;) {\n const clStart = performance.now();\n const {value, done} = changes.next();\n this.stats.changeLogReadMs += performance.now() - clStart;\n if (done) {\n cleanup();\n return {value, done: true};\n }\n\n this.changesScanned++;\n const parseStart = performance.now();\n const {table, rowKey, op, stateVersion} = v.parse(value, schema);\n this.stats.parseMs += performance.now() - parseStart;\n this.changesScannedByTable.set(\n table,\n (this.changesScannedByTable.get(table) ?? 0) + 1,\n );\n if (op === RESET_OP) {\n // The current map of `TableSpec`s may not have the correct or complete information.\n throw new ResetPipelinesSignal(\n `schema for table ${table} has changed`,\n 'schema-change',\n );\n }\n if (op === TRUNCATE_OP) {\n // Truncates are also processed by rehydrating pipelines at current.\n throw new ResetPipelinesSignal(\n `table ${table} has been truncated`,\n 'truncation',\n );\n }\n if (\n this.#observedTables &&\n !this.#observedTables.has(table) &&\n table !== this.#permissionsTable\n ) {\n if (this.#allTableNames.has(table)) {\n this.changesSkipped++;\n continue; // skip change log entries for unobserved tables.\n }\n throw new Error(`change for unknown table ${table}`);\n }\n const specs = this.#syncableTables.get(table);\n if (!specs) {\n if (this.#allTableNames.has(table)) {\n this.changesSkipped++;\n continue; // skip change log entries for non-syncable tables.\n }\n throw new Error(`change for unknown table ${table}`);\n }\n const {tableSpec, zqlSpec} = specs;\n\n // Sanity check: All change log ops should have a stateVersion\n // greater than minRowVersion in the table metadata. This is a\n // mini-proof that the overlay does not need to be applied to\n // rows produced in incremental catchup, based on the invariant in\n // change-processor's #bumpVersions(), whereby the setting of the\n // minRowVersion is always followed by a RESET OP, meaning that\n // subsequent change-log traversal happens at a later version.\n assert(\n (tableSpec.minRowVersion ?? '') < stateVersion,\n () =>\n `unexpected change @${stateVersion} for table ${table} with ` +\n `minRowVersion ${tableSpec.minRowVersion}: ${op}(${rowKey})`,\n );\n\n assert(rowKey !== null, 'rowKey must be present for row changes');\n\n // Row reads are shared with the other client groups on the\n // worker via the SnapshotRowCache (if configured):\n //\n // * The new value of the row is read from `curr`, which is\n // never written to during the iteration, and is the version\n // of the row at `stateVersion` (as verified by\n // checkThatDiffIsValid()). It is thus identical for every\n // Diff that encounters the change log entry.\n //\n // * Previous values are read from `prev`, at `prev.version`,\n // which the caller (i.e. IVM) writes to as the iteration\n // progresses. For a table whose only unique key is its\n // primary key, no change applied before this one can affect\n // this row, so the result depends solely on `prev.version`.\n // Otherwise, the result can include rows that conflict on\n // other unique keys, which may have been added or removed by\n // preceding changes; see PrevWrites for when that can be\n // shared.\n // The first advance() after this Diff was created resets the\n // `prev` connection to head. Reads would then no longer reflect\n // `prev.version`, and cache hits would not reveal it (the cached\n // rows were read by valid Diffs), so this must be checked\n // explicitly rather than inferred from the rows' versions.\n if (this.prev.reset) {\n throw new InvalidDiffError(\n `Diff is no longer valid. prev db has advanced past ${this.prev.version}.`,\n );\n }\n\n const cache = this.#rowCache;\n const prevDependsOnWrites =\n tableSpec.uniqueKeys.length > 1 && this.#prevWrites !== 'none';\n const prevCache =\n prevDependsOnWrites && this.#prevWrites === 'divergent'\n ? undefined\n : cache;\n const prevTag = prevDependsOnWrites\n ? this.#prevTagDivergent\n : this.#prevTagUniform;\n this.changesLookedUp++;\n const rowStart = performance.now();\n const nextValue =\n op === SET_OP\n ? this.curr.getRow(\n tableSpec,\n rowKey,\n cache,\n `n:${stateVersion}`,\n )\n : null;\n let prevValues;\n if (nextValue) {\n prevValues = this.prev.getRows(\n tableSpec,\n tableSpec.uniqueKeys,\n nextValue,\n prevCache,\n prevTag,\n );\n } else {\n const prevValue = this.prev.getRow(\n tableSpec,\n rowKey,\n prevCache,\n prevTag,\n );\n prevValues = prevValue ? [prevValue] : [];\n }\n this.stats.rowReadMs += performance.now() - rowStart;\n if (nextValue === undefined) {\n throw new Error(\n `Missing value for ${table} ${stringify(rowKey)}`,\n );\n }\n // Sanity check detects if the diff is being accessed after the Snapshots have advanced.\n this.checkThatDiffIsValid(stateVersion, op, prevValues, nextValue);\n\n if (prevValues.length === 0 && nextValue === null) {\n // Filter out no-op changes (e.g. a delete of a row that does not exist in prev).\n // TODO: Consider doing this for deep-equal values.\n this.changesSkipped++;\n continue;\n }\n\n if (\n table === this.#permissionsTable &&\n prevValues.some(\n prevValue => prevValue.permissions !== nextValue.permissions,\n )\n ) {\n throw new ResetPipelinesSignal(\n `Permissions have changed ${\n prevValues.find(\n prevValue =>\n prevValue.permissions !== nextValue.permissions,\n ).hash\n } => ${nextValue.hash}`,\n 'permissions-change',\n );\n }\n\n // Note: The raw SQLite rows may be shared with other client\n // groups via the SnapshotRowCache, so they must not be modified.\n // fromSQLiteTypes() produces new row objects.\n // TODO Can we get rid of these RowValue casts?\n return {\n value: {\n table,\n prevValues: prevValues.map(prevValue =>\n fromSQLiteTypes(zqlSpec, prevValue, table),\n ),\n nextValue: nextValue\n ? fromSQLiteTypes(zqlSpec, nextValue, table)\n : null,\n rowKey,\n } satisfies Change,\n };\n }\n } catch (e) {\n // This control flow path is not covered by the return() method (i.e. `break`).\n cleanup();\n throw e;\n } finally {\n this.stats.totalDiffMs += performance.now() - nextStart;\n }\n },\n\n return: (value: unknown) => {\n cleanup();\n return {value, done: true};\n },\n };\n }\n\n checkThatDiffIsValid(\n stateVersion: string,\n op: string,\n prevValues: RowValue[],\n nextValue: RowValue,\n ) {\n // Sanity checks to detect that the diff is not being accessed after\n // the Snapshots have advanced.\n if (stateVersion > this.curr.version) {\n throw new InvalidDiffError(\n `Diff is no longer valid. curr db has advanced past ${this.curr.version}`,\n );\n }\n if (\n prevValues.findIndex(\n prevValue => (prevValue[ROW_VERSION] ?? '~') > this.prev.version,\n ) !== -1\n ) {\n throw new InvalidDiffError(\n `Diff is no longer valid. prev db has advanced past ${this.prev.version}.`,\n );\n }\n if (op === SET_OP && nextValue[ROW_VERSION] !== stateVersion) {\n throw new InvalidDiffError(\n 'Diff is no longer valid. curr db has advanced.',\n );\n }\n }\n}\n\nexport class InvalidDiffError extends Error {\n constructor(msg: string) {\n super(msg);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6FA,IAAa,cAAb,MAAyB;CACvB;CACA;CACA;CACA;CACA;CACA;CACA;;;;;;;CAQA,YACE,IACA,QACA,EAAC,SACD,kBACA,UACA;EACA,KAAKA,MAAM;EACX,KAAKC,UAAU;EACf,KAAKC,SAAS;EACd,KAAKC,oBAAoB;EACzB,KAAKC,YAAY;CACnB;;;;;;CAOA,OAAa;EACX,OAAO,KAAKC,UAAU,KAAA,GAAW,qBAAqB;EACtD,KAAKA,QAAQ,SAAS,OACpB,KAAKL,KACL,KAAKC,SACL,KAAKC,QACL,KAAKC,iBACP;EACA,KAAKH,IAAI,QAAQ,+BAA+B,KAAKK,MAAM,SAAS;EACpE,OAAO;CACT;CAEA,cAAuB;EACrB,OAAO,KAAKA,UAAU,KAAA;CACxB;;CAGA,UAAoB;EAClB,OAAO,KAAKA,UAAU,KAAA,GAAW,sCAAsC;EACvE,OAAO,KAAKA;CACd;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2CA,QACE,gBACA,eACA,gBACA,aAAyB,WACX;EACd,KAAK,mBAAmB;EACxB,OAAO,KAAK,KAAK,gBAAgB,eAAe,gBAAgB,UAAU;CAC5E;;;;;;;;;;;;;;;;;;;CAoBA,KACE,gBACA,eACA,gBACA,aAAyB,WACzB,QACA,YACc;EACd,OACE,KAAKC,UAAU,KAAA,KAAa,KAAKD,UAAU,KAAA,GAC3C,mCACF;EACA,OAAO,IAAI,KACT,KAAKH,QACL,gBACA,eACA,KAAKI,OACL,KAAKD,OACL,gBACA,KAAKD,WACL,YACA,QACA,UACF;CACF;CAEA,qBAAqB;EACnB,OAAO,KAAKC,UAAU,KAAA,GAAW,sCAAsC;EACvE,MAAM,OAAO,KAAKC,QACd,KAAKA,MAAM,YAAY,IACvB,SAAS,OACP,KAAKN,KACL,KAAKK,MAAM,GAAG,GAAG,MACjB,KAAKH,QACL,KAAKC,iBACP;EACJ,KAAKG,QAAQ,KAAKD;EAClB,KAAKA,QAAQ;EACb,OAAO;GAAC,MAAM,KAAKC;GAAO,MAAM,KAAKD;EAAK;CAC5C;;;;;;;;;;;;;;;;CAiBA,aACE,gBACA,QACkC;EAClC,OACE,KAAKC,UAAU,KAAA,KAAa,KAAKD,UAAU,KAAA,GAC3C,mCACF;EACA,MAAM,OAAO,KAAKC;EAClB,MAAM,OAAO,KAAKD;EAClB,IAAI;EAEJ,IAAI,OAAO,eAAe,GAAG;GAE3B,MAAM,EAAC,cAAc,KAAK,OAAO,OAAM,KAAK,sBAC1C,KAAK,OACP;GACA,QAAQ;IACN;IACA;IACA,QACE,OAAA,MACI,IAAI,qBACF,SAAS,MAAM,sBACf,YACF,IACA,IAAI,qBACF,oBAAoB,MAAM,eAC1B,eACF;GACR;EACF;EAIA,MAAM,mBAAmB,GAAG,KAAKH,OAAO;EACxC,MAAM,QAAQ,eAAe,IAAI,gBAAgB;EACjD,IACE,UACC,OAAO,YAAY,OAAO,QAAQ,IAAI,gBAAgB,KAAK,KAAK,IACjE;GACA,MAAM,EAAC,cAAa;GACpB,KAAK,MAAM,SAAS,KAAK,aAAa,kBAAkB,KAAK,OAAO,GAAG;IACrE,IAAI,SAAS,CAAC,SAAS,OAAO,KAAK,GACjC;IAEF,MAAM,SAAoB,MAAM,UAAU,KAAK,MAAM,MAAM,MAAM;IACjE,IAAI,WAAW,MACb;IAEF,MAAM,YACJ,MAAM,OAAA,MAAgB,KAAK,OAAO,WAAW,MAAM,IAAI;IACzD,IAAI;IACJ,IAAI,WACF,aAAa,KAAK,QAAQ,WAAW,UAAU,YAAY,SAAS;SAC/D;KACL,MAAM,YAAY,KAAK,OAAO,WAAW,MAAM;KAC/C,aAAa,YAAY,CAAC,SAAS,IAAI,CAAC;IAC1C;IACA,MAAM,UAAU,WAAW,MACzB,cAAa,UAAU,gBAAgB,WAAW,WACpD;IACA,IAAI,SAAS;KACX,QAAQ;MACN,GAAG;MACH,QAAQ,IAAI,qBACV,4BAA4B,QAAQ,KAAK,MAAM,WAAW,QAC1D,oBACF;KACF;KACA;IACF;GACF;EACF;EACA,OAAO,OAAO;CAChB;;;;;;;;;CAUA,kBAAwB;EACtB,KAAKI,OAAO,QAAQ;CACtB;;;;;CAMA,UAAU;EAMR,KAAKD,OAAO,GAAG,GAAG,MAAM,EAAC,UAAU,MAAK,CAAC;EACzC,KAAKC,OAAO,GAAG,GAAG,MAAM,EAAC,UAAU,MAAK,CAAC;EACzC,KAAKN,IAAI,QAAQ,6BAA6B;CAChD;AACF;AAsBA,SAAS,SAAS,GAAsB,GAA+B;CACrE,OAAO,EAAE,iBAAiB,EAAE,eACxB,EAAE,MAAM,EAAE,MACV,EAAE,eAAe,EAAE;AACzB;;;;;;;AAsBA,IAAa,yBAAyB;AAsGtC,IAAa,uBAAb,cAA0C,MAAM;CAC9C,OAAgB;CAChB;CACA;CAEA,YAAY,KAAa,QAA8B,WAAoB;EACzE,MAAM,GAAG;EACT,KAAK,SAAS;EACd,KAAK,YAAY;CACnB;AACF;AAoBA,IAAM,6BAAa,IAAI,QAAqD;AAE5E,SAAS,SAAS,OAAoD;CACpE,OAAO,oBAAoB,YAAY,cAAc;EACnD,QAAQ,UAAU,OAAO,KAAK,MAAM,OAAO,EACxC,KAAI,MAAK,GAAG,CAAC,CAAC,EACd,KAAK,GAAG,EAAE,QAAQ,GAAG,MAAM,IAAI,EAAE;EACpC,8BAAc,IAAI,IAAI;EACtB,8BAAc,IAAI,IAAI;CACxB,EAAE;AACJ;AAGA,IAAM,2BAA2B;;;;;;;;;;;;;;;;;AAkBjC,IAAM,iCAAiC;;;;;AAMvC,IAAM,yBAAyB;;;;;;;;AAS/B,IAAM,2BAA2B;AAEjC,IAAM,WAAN,MAAM,SAAS;CACb,OAAO,OACL,IACA,QACA,OACA,kBACA;EACA,MAAM,OAAO,IAAI,SAAS,IAAI,MAAM;EACpC,KAAK,OAAO,mBAAmB;EAC/B,IAAI,qBAAqB,KAAA,GACvB,KAAK,OAAO,iBAAiB,kBAAkB;EAEjD,MAAM,CAAC,EAAC,cAAc,UAAS,KAAK,OAAO,cAAc;EAOzD,OACE,SAAS,QACT,6CAA6C,KAAK,EACpD;EAGA,OAAO,IAAI,SAAS,IADL,gBAAgB,IACX,GAAI,KAAK;CAC/B;CAEA;CACA;CACA;CACA,SAAS;;;;;CAMT,YAAY,IAAqB,OAAe,QAAQ,OAAO;EAC7D,IAAI,CAAC,OACH,GAAG,gBAAgB;EAKrB,MAAM,EAAC,iBAAgB,oBAAoB,EAAE;EAE7C,KAAK,KAAK;EACV,KAAKE,SAAS;EACd,KAAK,UAAU;CACjB;CAEA,gBAAgB,aAAqB;EACnC,MAAM,EAAC,UAAS,KAAK,GAAG,IACtB,6EACA,WACF;EACA,OAAO;CACT;;;;;;;;;;;;CAaA,kBACE,aACA,aAAa,wBACI;EAGjB,MAAM,EAAC,OAAO,iBAAgB,KAAK,GAAG,IACpC;+CACyC,+BAA+B;kCAExE,WACF;EACA,MAAM,0BAAU,IAAI,IAAoB;EACxC,IAAI,UAAU,GACZ,OAAO;GAAC;GAAO;GAAc;GAAS,SAAS;EAAK;EAEtD,MAAM,OAAyC,KAAK,GAAG,IACrD;;mDAE6C,+BAA+B;;;8BAI5E,aACA,UACF;EACA,MAAM,UAAU,QAAQ;EACxB,MAAM,QAAQ,UAAU,QAAQ,aAAa;EAC7C,KAAK,MAAM,EAAC,OAAO,WAAU,MAC3B,QAAQ,IAAI,OAAO,QAAQ,KAAK;EAElC,OAAO;GAAC;GAAO;GAAc;GAAS;EAAO;CAC/C;;;;;;CAOA,kBAAkB,OAAe,aAA8B;EAO7D,OANY,KAAK,GAAG,IAClB,gDAAgD,uBAAuB;0DAEvE,OACA,WAEK,MAAQ,KAAA;CACjB;;;;;;CAOA,mBAAmB,aAA8B;EAO/C,OANY,KAAK,GAAG,IAClB,gDAAgD,+BAA+B;qDAE/E,aAAA,GAGK,MAAQ,KAAA;CACjB;;;;;;CAOA,oBAAoB,aAA8B;EAQhD,OAPY,KAAK,GAAG,IAClB,gDAAgD,+BAA+B;2DAE/E,aAAA,KAAA,GAIK,MAAQ,KAAA;CACjB;;;;;CAMA,sBACE,aACiD;EACjD,OAAO,KAAK,GAAG,IACb,mFAAmF,+BAA+B;;0DAGlH,WACF;CACF;;;;;CAMA,aACE,OACA,aAC6D;EAC7D,OAAO,KAAK,GAAG,IACb,oFAAoF,uBAAuB;;kDAG3G,OACA,WACF;CACF;;;;;CAMA,aAAa,aAAqB,QAA6B;EAG7D,MAAM,SAAS,KAAK,GAAG,eAAe,IACpC,WAAW,KAAA,IACP;4EAEA;wCAC8B,yBAAyB;gDAE7D;EACA,OAAO;GACL,SACE,WAAW,KAAA,IACP,OAAO,UAAU,QAAQ,WAAW,IACpC,OAAO,UAAU,QACf,aAAA,KAAA,KAGA,MACF;GACN,eAAe,KAAK,GAAG,eAAe,OAAO,MAAM;EACrD;CACF;;;;;;;;;CAUA,OACE,OACA,QACA,OACA,KACA;EACA,MAAM,MAAM,mBAAmB,MAAgB;EAC/C,MAAM,OAAO,OAAO,KAAK,GAAG;EAC5B,MAAM,QAAQ,SAAS,KAAK;EAC5B,MAAM,MAAM,oBACV,MAAM,cACN,KAAK,KAAK,IAAI,SACR,MAAM,SAAS,KAAK,KAAI,MAAK,GAAG,GAAG,CAAC,EAAE,GAAG,EAAE,KAAK,OAAO,CAC/D;EACA,MAAM,OAAO,OAAO,OAAO,GAAG;EAC9B,MAAM,aACJ,KAAK,GAAG,eAAe,IAAI,MAAK,WAAU;GACxC,OAAO,UAAU,aAAa,IAAI;GAElC,MAAM,MAAM,OAAO,UAAU,IAAS,IAAI;GAC1C,iBAAiB,OAAO,WAAW,MAAM,IAAI;GAC7C,OAAO;EACT,CAAC;EACH,OAAO,QACH,MAAM,UAAU,OAAO,IAAI,KAAK,OAAO,YAAY;GACjD,MAAM,MAAM,KAAK;GACjB,IAAI,QAAQ,KAAA,GACV,KAAKK,mBAAmB,GAAG;GAE7B,OAAO;EACT,CAAC,IACD,KAAK;CACX;;;;;;;;;CAUA,QACE,OACA,MACA,KACA,OACA,KACA;EAOA,IAAI,YAA0B;EAC9B,IAAI,QAAQ,KAAK,KAAK,UAAU;EAEhC,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;GACpC,MAAM,MAAM,KAAK;GACjB,KAAK,IAAI,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;IACnC,MAAM,MAAM,IAAI,IAAI;IACpB,IAAI,QAAQ,QAAQ,QAAQ,KAAA,GAAW;KACrC,YAAY,CAAC;KACb,OAAO;KACP,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;MACpC,MAAM,YAAY,KAAK;MACvB,IACE,UAAU,OACR,QAAO,IAAI,SAAS,QAAQ,IAAI,SAAS,KAAA,CAC3C,GACA;OACA,UAAU,KAAK,SAAS;OACxB,QAAQ,KAAK;MACf;KACF;KACA;IACF;GACF;GACA,IAAI,cAAc,MAChB;EAEJ;EAEA,IAAI,UAAU,WAAW,GACvB,OAAO,CAAC;EAEV,MAAM,QAAQ,SAAS,KAAK;EAC5B,MAAM,iBACJ,MAAM,SACN,UACG,KAAI,QAAO,IAAI,KAAI,MAAK,GAAG,GAAG,CAAC,EAAE,GAAG,EAAE,KAAK,OAAO,CAAC,EACnD,KAAK,MAAM;EAChB,MAAM,MACJ,SAAS,MAAM,cAAc,KAAK,UAAU,2BACxC,oBAAoB,MAAM,cAAc,MAAM,QAAQ,IACtD,SAAS;EACf,MAAM,OAAkB,CAAC;EACzB,KAAK,IAAI,IAAI,GAAG,IAAI,UAAU,QAAQ,KAAK;GACzC,MAAM,MAAM,UAAU;GACtB,KAAK,IAAI,IAAI,GAAG,IAAI,IAAI,QAAQ,KAC9B,KAAK,KAAK,IAAI,IAAI,GAAG;EAEzB;EACA,MAAM,aACJ,KAAK,GAAG,eAAe,IAAI,MAAK,WAAU;GACxC,OAAO,UAAU,aAAa,IAAI;GAElC,MAAM,OAAO,OAAO,UAAU,IAAS,IAAI;GAC3C,iBAAiB,OAAO,WAAW,MAAM,IAAI;GAC7C,OAAO;EACT,CAAC;EACH,OAAO,QACH,MAAM,UAAU,OAAO,IAAI,KAAK,OAAO,YAAY;GACjD,MAAM,OAAO,KAAK;GAClB,KAAK,MAAM,OAAO,MAChB,KAAKA,mBAAmB,GAAG;GAE7B,OAAO;EACT,CAAC,IACD,KAAK;CACX;;;;;;;;CASA,mBAAmB,KAAe;EAChC,KAAK,IAAA,iBAAoB,OAAO,KAAK,SACnC,MAAM,IAAI,iBACR,iDAAiD,KAAK,QAAQ,EAChE;CAEJ;;;;;;CAOA,IAAI,QAAiB;EACnB,OAAO,KAAKC;CACd;;;;;;;CAQA,UAAgB;EACd,IAAI,CAAC,KAAKA,QAAQ;GAChB,KAAKA,SAAS;GACd,KAAK,GAAG,SAAS;GAMjB,KAAK,GAAG,gBAAgB;EAC1B;CACF;CAEA,cAAwB;EACtB,KAAK,QAAQ;EACb,OAAO,IAAI,SAAS,KAAK,IAAI,KAAKN,QAAQ,IAAI;CAChD;AACF;AAEA,IAAM,OAAN,MAAmC;CACjC;CACA;CACA;CACA;CACA;;CAEA;CACA;CACA,iBAAiB;CACjB;CACA;CACA;CACA,YAAY;CACZ;CACA;CACA;CACA,iBAAiB;CACjB,wCAAiC,IAAI,IAAoB;CACzD,iBAAiB;CACjB,kBAAkB;CAClB,QAAkC;EAChC,iBAAiB;EACjB,WAAW;EACX,SAAS;EACT,aAAa;CACf;CAEA,YACE,OACA,gBACA,eACA,MACA,MACA,gBACA,UACA,aAAyB,WACzB,QACA,YACA;EACA,KAAKc,cAAc;EACnB,KAAKP,oBAAoB,GAAG,MAAM;EAElC,MAAM,OAAO,cAAc,IAAI,IAAI,UAAU,EAAE,IAAI,KAAKA,iBAAiB;EACzE,KAAKI,cAAc,QAAQ,KAAK,UAAU,CAAC,GAAG,IAAI,CAAC;EACnD,KAAKH,kBAAkB;EACvB,KAAKC,iBAAiB;EACtB,KAAKC,kBAAkB;EACvB,KAAK,OAAO;EACZ,KAAK,OAAO;EACZ,KAAKE,kBAAkB,KAAK,KAAK;EACjC,KAAKC,oBAAoB,KAAK,KAAK,QAAQ,GAAG,KAAK;EACnD,IAAI,WAAW,KAAA,GAAW;GACxB,OAAO,SAAS,KAAA,GAAW,4BAA4B;GACvD,KAAK,UAAU,KAAK,gBAAgB,KAAK,OAAO;EAClD,OAAO;GAGL,MAAM,cAAc,UAAkB,KAAKE,YAAY,QAAQ,KAAK;GACpE,KAAKC,iBACH,OAAO,UAAU,KAChB,SAAS,KAAA,KACR,OAAO,iBAAiB,KACxB,CAAC,CAAC,GAAG,IAAI,EAAE,KAAK,UAAU;GAE9B,KAAK,UAAU,KAAKA,iBAAiB,IAAI,OAAO;EAClD;EAOA,MAAM,iBAAiB,SACnB,OAAO,eAAe,IACtB,KAAK,oBAAoB,KAAK,OAAO;EACzC,KAAKd,YAAY,YAAY,CAAC,iBAAiB,WAAW,KAAA;CAC5D;;;;;;;CAQA,YAAY,QAAyB,OAAwB;EAC3D,IAAI,CAAC,OAAO,SACV,QAAQ,OAAO,QAAQ,IAAI,KAAK,KAAK,KAAK;EAE5C,IAAI,UAAU,KAAKK,mBACjB,OAAO;EAET,OAAQ,KAAKU,wBAAwB,KAAK,KAAK,kBAC7C,OACA,KAAK,KAAK,OACZ;CACF;CAEA,cAAc,YAA8B;EAC1C,OACE,CAAC,KAAKC,aAAa,eAAe,aAClC,kDACF;EACA,KAAKJ,cAAc;CACrB;CAEA,CAAC,OAAO,YAA8B;EACpC,KAAKI,YAAY;EACjB,IAAI,KAAKF,gBACP,OAAO,CAAC,EAAE,OAAO,UAAU;EAE7B,MAAM,EAAC,SAAS,SAAS,SAAQ,KAAK,KAAK,aACzC,KAAK,KAAK,SACV,KAAKL,WACP;EAEA,MAAM,gBAAgB;GACpB,IAAI;IAEF,QAAQ,SAAS,KAAA,CAAS;GAC5B,UAAU;IACR,KAAK;GACP;EACF;EAEA,OAAO;GACL,YAAY;IACV,MAAM,YAAY,YAAY,IAAI;IAClC,IAAI;KACF,SAAS;MACP,MAAM,UAAU,YAAY,IAAI;MAChC,MAAM,EAAC,OAAO,SAAQ,QAAQ,KAAK;MACnC,KAAK,MAAM,mBAAmB,YAAY,IAAI,IAAI;MAClD,IAAI,MAAM;OACR,QAAQ;OACR,OAAO;QAAC;QAAO,MAAM;OAAI;MAC3B;MAEA,KAAK;MACL,MAAM,aAAa,YAAY,IAAI;MACnC,MAAM,EAAC,OAAO,QAAQ,IAAI,iBAAgB,MAAQ,OAAO,oBAAM;MAC/D,KAAK,MAAM,WAAW,YAAY,IAAI,IAAI;MAC1C,KAAK,sBAAsB,IACzB,QACC,KAAK,sBAAsB,IAAI,KAAK,KAAK,KAAK,CACjD;MACA,IAAI,OAAA,KAEF,MAAM,IAAI,qBACR,oBAAoB,MAAM,eAC1B,eACF;MAEF,IAAI,OAAA,KAEF,MAAM,IAAI,qBACR,SAAS,MAAM,sBACf,YACF;MAEF,IACE,KAAKD,mBACL,CAAC,KAAKA,gBAAgB,IAAI,KAAK,KAC/B,UAAU,KAAKH,mBACf;OACA,IAAI,KAAKE,eAAe,IAAI,KAAK,GAAG;QAClC,KAAK;QACL;OACF;OACA,MAAM,IAAI,MAAM,4BAA4B,OAAO;MACrD;MACA,MAAM,QAAQ,KAAKD,gBAAgB,IAAI,KAAK;MAC5C,IAAI,CAAC,OAAO;OACV,IAAI,KAAKC,eAAe,IAAI,KAAK,GAAG;QAClC,KAAK;QACL;OACF;OACA,MAAM,IAAI,MAAM,4BAA4B,OAAO;MACrD;MACA,MAAM,EAAC,WAAW,YAAW;MAS7B,QACG,UAAU,iBAAiB,MAAM,oBAEhC,sBAAsB,aAAa,aAAa,MAAM,sBACrC,UAAU,cAAc,IAAI,GAAG,GAAG,OAAO,EAC9D;MAEA,OAAO,WAAW,MAAM,wCAAwC;MAyBhE,IAAI,KAAK,KAAK,OACZ,MAAM,IAAI,iBACR,sDAAsD,KAAK,KAAK,QAAQ,EAC1E;MAGF,MAAM,QAAQ,KAAKP;MACnB,MAAM,sBACJ,UAAU,WAAW,SAAS,KAAK,KAAKY,gBAAgB;MAC1D,MAAM,YACJ,uBAAuB,KAAKA,gBAAgB,cACxC,KAAA,IACA;MACN,MAAM,UAAU,sBACZ,KAAKD,oBACL,KAAKD;MACT,KAAK;MACL,MAAM,WAAW,YAAY,IAAI;MACjC,MAAM,YACJ,OAAA,MACI,KAAK,KAAK,OACR,WACA,QACA,OACA,KAAK,cACP,IACA;MACN,IAAI;MACJ,IAAI,WACF,aAAa,KAAK,KAAK,QACrB,WACA,UAAU,YACV,WACA,WACA,OACF;WACK;OACL,MAAM,YAAY,KAAK,KAAK,OAC1B,WACA,QACA,WACA,OACF;OACA,aAAa,YAAY,CAAC,SAAS,IAAI,CAAC;MAC1C;MACA,KAAK,MAAM,aAAa,YAAY,IAAI,IAAI;MAC5C,IAAI,cAAc,KAAA,GAChB,MAAM,IAAI,MACR,qBAAqB,MAAM,GAAG,UAAU,MAAM,GAChD;MAGF,KAAK,qBAAqB,cAAc,IAAI,YAAY,SAAS;MAEjE,IAAI,WAAW,WAAW,KAAK,cAAc,MAAM;OAGjD,KAAK;OACL;MACF;MAEA,IACE,UAAU,KAAKL,qBACf,WAAW,MACT,cAAa,UAAU,gBAAgB,UAAU,WACnD,GAEA,MAAM,IAAI,qBACR,4BACE,WAAW,MACT,cACE,UAAU,gBAAgB,UAAU,WACxC,EAAE,KACH,MAAM,UAAU,QACjB,oBACF;MAOF,OAAO,EACL,OAAO;OACL;OACA,YAAY,WAAW,KAAI,cACzB,gBAAgB,SAAS,WAAW,KAAK,CAC3C;OACA,WAAW,YACP,gBAAgB,SAAS,WAAW,KAAK,IACzC;OACJ;MACF,EACF;KACF;IACF,SAAS,GAAG;KAEV,QAAQ;KACR,MAAM;IACR,UAAU;KACR,KAAK,MAAM,eAAe,YAAY,IAAI,IAAI;IAChD;GACF;GAEA,SAAS,UAAmB;IAC1B,QAAQ;IACR,OAAO;KAAC;KAAO,MAAM;IAAI;GAC3B;EACF;CACF;CAEA,qBACE,cACA,IACA,YACA,WACA;EAGA,IAAI,eAAe,KAAK,KAAK,SAC3B,MAAM,IAAI,iBACR,sDAAsD,KAAK,KAAK,SAClE;EAEF,IACE,WAAW,WACT,eAAc,UAAA,iBAA0B,OAAO,KAAK,KAAK,OAC3D,MAAM,IAEN,MAAM,IAAI,iBACR,sDAAsD,KAAK,KAAK,QAAQ,EAC1E;EAEF,IAAI,OAAA,OAAiB,UAAA,kBAA2B,cAC9C,MAAM,IAAI,iBACR,gDACF;CAEJ;AACF;AAEA,IAAa,mBAAb,cAAsC,MAAM;CAC1C,YAAY,KAAa;EACvB,MAAM,GAAG;CACX;AACF"}
|
|
1
|
+
{"version":3,"file":"snapshotter.js","names":[],"sources":["../../../../../../zero-cache/src/services/view-syncer/snapshotter.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {assert} from '../../../../shared/src/asserts.ts';\nimport {stringify, type JSONValue} from '../../../../shared/src/bigint-json.ts';\nimport {getOrInsertComputed} from '../../../../shared/src/map.ts';\nimport type {Row} from '../../../../zero-protocol/src/data.ts';\nimport type {PrimaryKey} from '../../../../zero-types/src/schema.ts';\nimport {Database} from '../../../../zqlite/src/db.ts';\nimport {recordIndexUsage} from '../../../../zqlite/src/index-usage.ts';\nimport {\n fromSQLiteTypes,\n type SQLiteRow,\n} from '../../../../zqlite/src/table-source.ts';\nimport type {\n LiteAndZqlSpec,\n LiteTableSpecWithKeysAndVersion,\n} from '../../db/specs.ts';\nimport {StatementRunner} from '../../db/statements.ts';\nimport {normalizedKeyOrder, type RowKey} from '../../types/row-key.ts';\nimport type {AppID} from '../../types/shards.ts';\nimport {id} from '../../types/sql.ts';\nimport {\n RESET_OP,\n parseChangeLogEntry,\n SET_OP,\n TRUNCATE_OP,\n} from '../replicator/schema/change-log.ts';\nimport {\n getReplicationState,\n ZERO_VERSION_COLUMN_NAME as ROW_VERSION,\n} from '../replicator/schema/replication-state.ts';\nimport type {SnapshotRowCache} from './snapshot-row-cache.ts';\n\n/**\n * A `Snapshotter` manages the progression of database snapshots for a\n * ViewSyncer.\n *\n * The Replicator and ViewSyncers operate on the same SQLite file, with the\n * Replicator being the sole writer to the database. The IVM logic in\n * ViewSyncers, however, rely on incrementally applying changes to the DB to\n * update the state of its pipelines.\n *\n * To avoid coupling the progress of the Replicator and all IVM pipelines on\n * each other, ViewSyncers operate on ephemeral forks of the database by holding\n * [concurrent](https://sqlite.org/src/doc/begin-concurrent/doc/begin_concurrent.md)\n * snapshots of the database and simulating (but ultimately rolling back)\n * mutations on these snapshots.\n *\n * Example:\n * 1. ViewSyncer takes `snapshot_a` at version `t1` of the database and\n * hydrates its pipeline(s).\n * 2. Replicator applies a new transaction to the database and notifies\n * subscribers.\n * 3. ViewSyncer takes `snapshot_b` at `t2`, and queries the `ChangeLog` at\n * that snapshot for changes since `t1`.\n * 4. ViewSyncer applies those changes to `snapshot_a` for IVM, but does not\n * commit them. (Recall that the Replicator is the sole writer to the db, so\n * the ViewSyncer never commits any writes.)\n * 5. Replicator applies the next transaction and advances the database to `t3`.\n * 6. ViewSyncer rolls back `snapshot_a` and opens `snapshot_c` at `t3`, using\n * `snapshot_b` to simulate changes from `t2` to `t3`.\n *\n * ```\n * Replicator: t1 --------------> t2 --------------> t3 --------------->\n * ViewSyncer: [snapshot_a] ----> [snapshot_b] ----> [snapshot_c]\n * ```\n *\n * Note that the Replicator (and ViewSyncers) do not wait on the progress of\n * other ViewSyncers. If a ViewSyncer is busy hydrating at `t1`, the Replicator\n * and other ViewSyncers can progress through `t2`, `t3`, etc. independently,\n * as the busy ViewSyncer simply takes its own snapshot when it is ready.\n *\n * ```\n * Replicator: t1 --------------> t2 --------------> t3 --------------->\n * ViewSyncer1: [snapshot_a] ----> [snapshot_b] ----> [snapshot_c]\n * ViewSyncer2: [.......... snapshot_a ..........] ----> [snapshot_b]\n * ```\n *\n * To minimize Database connections (and statement preparation, etc.), the\n * Snapshotter reuses the connection from the previous (rolled back)\n * snapshot when opening the new one.\n *\n * ```\n * Replicator: t1 --------------> t2 --------------> t3 --------------->\n * ViewSyncer: [snapshot_a] ----> [snapshot_b] ----> [snapshot_c]\n * (conn_1) (conn_2) (conn_1)\n * ```\n *\n * In this manner, each ViewSyncer uses two connections that continually\n * \"leapfrog\" each other to replay the timeline of changes in isolation from\n * the Replicator and other ViewSyncers.\n */\nexport class Snapshotter {\n readonly #lc: LogContext;\n readonly #dbFile: string;\n readonly #appID: string;\n readonly #pageCacheSizeKib: number | undefined;\n readonly #rowCache: SnapshotRowCache | undefined;\n #curr: Snapshot | undefined;\n #prev: Snapshot | undefined;\n\n /**\n * @param rowCache An optional worker-wide {@link SnapshotRowCache} through\n * which the row reads performed when iterating over a\n * {@link SnapshotDiff} are shared with the other Snapshotters\n * (i.e. client groups) on the worker.\n */\n constructor(\n lc: LogContext,\n dbFile: string,\n {appID}: AppID,\n pageCacheSizeKib?: number,\n rowCache?: SnapshotRowCache,\n ) {\n this.#lc = lc;\n this.#dbFile = dbFile;\n this.#appID = appID;\n this.#pageCacheSizeKib = pageCacheSizeKib;\n this.#rowCache = rowCache;\n }\n\n /**\n * Initializes the snapshot to the current head of the database. This must be\n * only be called once. The state of whether a Snapshotter has been initialized\n * can be determined by calling {@link initialized()}.\n */\n init(): this {\n assert(this.#curr === undefined, 'Already initialized');\n this.#curr = Snapshot.create(\n this.#lc,\n this.#dbFile,\n this.#appID,\n this.#pageCacheSizeKib,\n );\n this.#lc.debug?.(`Initial snapshot at version ${this.#curr.version}`);\n return this;\n }\n\n initialized(): boolean {\n return this.#curr !== undefined;\n }\n\n /** Returns the current snapshot. Asserts if {@link initialized()} is false. */\n current(): Snapshot {\n assert(this.#curr !== undefined, 'Snapshotter has not been initialized');\n return this.#curr;\n }\n\n /**\n * Advances to the head of the Database, returning a diff between the\n * previously current Snapshot and a new Snapshot at head. This is called\n * in response to a notification from a Replicator subscription. Subsequent\n * calls to {@link current()} return the new Snapshot. Note that the Snapshotter\n * must be initialized before advancing.\n *\n * The returned {@link SnapshotDiff} contains snapshots at the endpoints\n * of the database timeline. Iterating over the diff generates a sequence\n * of {@link Change}s between the two snapshots.\n *\n * Note that this sequence is not chronological; rather, the sequence is\n * ordered by `<table, row-key>`, such that a row can appear at most once\n * in the common case, or twice if its table is `TRUNCATE`'d and a new value\n * is subsequently `INSERT`'ed. This results in dropping most intermediate\n * changes to a row and bounds the amount of work needed to catch up;\n * however, as a consequence, a consistent database state is only guaranteed\n * when the sequence has been fully consumed.\n *\n * Note that Change generation relies on the state of the underlying\n * database connections, and because the connection for the previous snapshot\n * is reused to produce the next snapshot, the diff object is only valid\n * until the next call to `advance()`.\n *\n * It is okay for the caller to apply `Change`s to the `prev` snapshot\n * during the iteration (e.g. this is necessary for IVM); the remainder\n * of the iteration is not affected because a given row can appear at most\n * once in the sequence (with the exception being TRUNCATE, after which the\n * deleted rows can be re-inserted, but this will also behave correctly if\n * the changes are applied).\n *\n * Once the changes have been applied, however, a _subsequent_ iteration\n * will not produce the correct results. In order to perform multiple\n * change-applying iterations, the caller must (1) create a save point\n * on `prev` before each iteration, and (2) rollback to the save point after\n * the iteration.\n *\n * @param prevWrites How the caller writes to `prev` during the iteration,\n * which determines which `prev` reads can be shared through the\n * {@link SnapshotRowCache}. See {@link PrevWrites}.\n */\n advance(\n syncableTables: Map<string, LiteAndZqlSpec>,\n allTableNames: Set<string>,\n observedTables?: TableFilter | undefined,\n prevWrites: PrevWrites = 'uniform',\n ): SnapshotDiff {\n this.advanceWithoutDiff();\n return this.diff(syncableTables, allTableNames, observedTables, prevWrites);\n }\n\n /**\n * The diff between the two snapshots of the last\n * {@link advanceWithoutDiff()}, as {@link advance()} returns it.\n *\n * @param counts The counts of the change log entries between the two\n * snapshots, if the caller has counted them already (see\n * `Snapshot.countChangesSince()`). The diff then does not count\n * them again.\n * @param readTables If set, only the change log entries of these tables\n * (and of the permissions table) are read, along with the\n * table-wide ops of every table, where `observedTables` reads the\n * entries of every table and skips those it does not have. For a\n * caller that does not need the changes of the other tables, this\n * saves reading and parsing their entries. This requires `counts`.\n * If they show that there is no entry of these tables and no\n * table-wide op, the change log is not read at all, and the\n * diff's `changes` is 0.\n */\n diff(\n syncableTables: Map<string, LiteAndZqlSpec>,\n allTableNames: Set<string>,\n observedTables?: TableFilter | undefined,\n prevWrites: PrevWrites = 'uniform',\n counts?: ChangeLogCounts | undefined,\n readTables?: Iterable<string> | undefined,\n ): SnapshotDiff {\n assert(\n this.#prev !== undefined && this.#curr !== undefined,\n 'Snapshotter has not been advanced',\n );\n return new Diff(\n this.#appID,\n syncableTables,\n allTableNames,\n this.#prev,\n this.#curr,\n observedTables,\n this.#rowCache,\n prevWrites,\n counts,\n readTables,\n );\n }\n\n advanceWithoutDiff() {\n assert(this.#curr !== undefined, 'Snapshotter has not been initialized');\n const next = this.#prev\n ? this.#prev.resetToHead()\n : Snapshot.create(\n this.#lc,\n this.#curr.db.db.name,\n this.#appID,\n this.#pageCacheSizeKib,\n );\n this.#prev = this.#curr;\n this.#curr = next;\n return {prev: this.#prev, curr: this.#curr};\n }\n\n /**\n * The reset of the pipelines that iterating over the changes from the\n * previous snapshot to the current one ends in, if it does: the first of\n * a schema change, a truncation, and a change of the permissions. It is\n * found without iterating, so that a caller that would reset the pipelines\n * anyway does not first process the changes that come before it.\n *\n * If there is none, iterating over a {@link diff()} of the two snapshots\n * does not throw a {@link ResetPipelinesSignal}, and can be stopped at any\n * point without missing one.\n *\n * @param counts The changes from the previous snapshot to the current\n * one, from which it is known whether there is anything to look\n * for.\n */\n pendingReset(\n syncableTables: Map<string, LiteAndZqlSpec>,\n counts: ChangeLogCounts,\n ): ResetPipelinesSignal | undefined {\n assert(\n this.#prev !== undefined && this.#curr !== undefined,\n 'Snapshotter has not been advanced',\n );\n const prev = this.#prev;\n const curr = this.#curr;\n let first: (ChangeLogPosition & {signal: ResetPipelinesSignal}) | undefined;\n\n if (counts.tableWideOps > 0) {\n // Iterating aborts at a table-wide op whatever its table is.\n const {stateVersion, pos, table, op} = curr.firstTableWideOpSince(\n prev.version,\n );\n first = {\n stateVersion,\n pos,\n signal:\n op === TRUNCATE_OP\n ? new ResetPipelinesSignal(\n `table ${table} has been truncated`,\n 'truncation',\n )\n : new ResetPipelinesSignal(\n `schema for table ${table} has changed`,\n 'schema-change',\n ),\n };\n }\n\n // An entry of the permissions table only aborts the iteration if the\n // permissions are different, which takes reading the row to know.\n const permissionsTable = `${this.#appID}.permissions`;\n const specs = syncableTables.get(permissionsTable);\n if (\n specs &&\n (counts.sampled || (counts.byTable.get(permissionsTable) ?? 0) > 0)\n ) {\n const {tableSpec} = specs;\n for (const entry of curr.entriesSince(permissionsTable, prev.version)) {\n if (first && !isBefore(entry, first)) {\n break;\n }\n const rowKey: JSONValue = entry.rowKey && JSON.parse(entry.rowKey);\n if (rowKey === null) {\n continue;\n }\n const nextValue =\n entry.op === SET_OP ? curr.getRow(tableSpec, rowKey) : null;\n let prevValues;\n if (nextValue) {\n prevValues = prev.getRows(tableSpec, tableSpec.uniqueKeys, nextValue);\n } else {\n const prevValue = prev.getRow(tableSpec, rowKey);\n prevValues = prevValue ? [prevValue] : [];\n }\n const changed = prevValues.find(\n prevValue => prevValue.permissions !== nextValue?.permissions,\n );\n if (changed) {\n first = {\n ...entry,\n signal: new ResetPipelinesSignal(\n `Permissions have changed ${changed.hash} => ${nextValue?.hash}`,\n 'permissions-change',\n ),\n };\n break;\n }\n }\n }\n return first?.signal;\n }\n\n /**\n * Releases the previous snapshot, i.e. the `prev` of the last\n * {@link advance()} or {@link advanceWithoutDiff()}. It is only read\n * while the diff that it is the start of is iterated over, but its read\n * transaction otherwise stays open until the next advance, which keeps\n * the replica from checkpointing its write-ahead log past it. A diff that\n * starts at it can no longer be iterated over.\n */\n releasePrevious(): void {\n this.#prev?.release();\n }\n\n /**\n * Call this to close the database connections when the Snapshotter is\n * no longer needed.\n */\n destroy() {\n // The replica's statistics are maintained by the replicator. The\n // `PRAGMA optimize` that closing a writable connection otherwise runs\n // analyzes the tables that the connection read, which blocks the worker\n // for as long as that takes, and what it finds is discarded with the\n // snapshot's transaction.\n this.#curr?.db.db.close({optimize: false});\n this.#prev?.db.db.close({optimize: false});\n this.#lc.debug?.('closed database connections');\n }\n}\n\nexport type Change = {\n readonly table: string;\n /**\n * If this change represents a remove the row to remove,\n * if nextValue is not null then all rows that have a unique constraint\n * violation with nextValue.\n * In both cases these rows should be removed.\n */\n readonly prevValues: Readonly<Row>[];\n readonly nextValue: Readonly<Row> | null;\n readonly rowKey: RowKey;\n};\n\n/** See `Snapshot.countChangesSince()`. */\n/** An entry of {@link Snapshot.changesSince}, in the order of its SELECT. */\ntype RawChangeLogEntry = readonly [\n stateVersion: string,\n table: string,\n rowKey: string,\n op: string,\n];\n\n/** Where an entry is in the order that the change log is read in. */\ntype ChangeLogPosition = {\n readonly stateVersion: string;\n readonly pos: number;\n};\n\nfunction isBefore(a: ChangeLogPosition, b: ChangeLogPosition): boolean {\n return a.stateVersion === b.stateVersion\n ? a.pos < b.pos\n : a.stateVersion < b.stateVersion;\n}\n\nexport type ChangeLogCounts = {\n /** The number of entries. */\n readonly total: number;\n /** The number of them that are table-wide ops (a RESET or TRUNCATE). */\n readonly tableWideOps: number;\n /**\n * The number of entries of each table. If {@link sampled}, these are\n * estimates, and a table with few entries may be missing.\n */\n readonly byTable: ReadonlyMap<string, number>;\n /** Whether {@link byTable} was estimated from a sample of the entries. */\n readonly sampled: boolean;\n};\n\n/**\n * The most change log entries that are read to count a batch's changes by\n * table. Reading an entry costs microseconds, and nothing else runs on the\n * sync worker in the meantime, so the cost of counting must not grow with\n * the number of changes that a client group has to catch up on.\n */\nconst CHANGE_LOG_SAMPLE_SIZE = 1000;\n\nexport interface TableFilter {\n has(table: string): boolean;\n}\n\n/**\n * How the caller of {@link Snapshotter.advance()} writes the changes of a\n * {@link SnapshotDiff} to its `prev` snapshot while iterating over it.\n *\n * A `prev` read for a table with a single unique key (its primary key)\n * cannot observe earlier changes of the iteration, since a row key appears\n * once in the diff. A read for a table with other unique keys can, because\n * the rows it returns may have been displaced or edited by earlier changes.\n *\n * * `uniform`: every caller applies every change, so such a read depends on\n * the `<prev, curr>` versions of the diff, and is shared on that basis.\n * * `divergent`: callers apply different subsets of the changes (e.g. the\n * pipeline driver skips changes that no pipeline can observe), so such a\n * read depends on the caller and is not shared.\n * * `none`: the caller does not write to `prev` (e.g. IVM derivation is\n * held in memory), so every read depends solely on `prev.version`.\n */\nexport type PrevWrites = 'uniform' | 'divergent' | 'none';\n\n/**\n * Represents the difference between two database Snapshots.\n * Iterating over the object will produce a sequence of {@link Change}s\n * between the two snapshots.\n *\n * See {@link Snapshotter.advance()} for semantics and usage.\n */\ntype DiffTimingStats = {\n changeLogReadMs: number;\n rowReadMs: number;\n parseMs: number;\n totalDiffMs: number;\n};\n\nexport interface SnapshotDiff extends Iterable<Change> {\n readonly prev: {\n readonly db: StatementRunner;\n readonly version: string;\n };\n readonly curr: {\n readonly db: StatementRunner;\n readonly version: string;\n };\n\n /**\n * The raw number of ChangeLog entries between the snapshots, before filtering\n * out unobserved/non-syncable tables or no-op changes. Progress against this\n * total must use {@link changesScanned}, rather than the number of yielded\n * changes. Table-wide operations abort iteration and reset the pipelines.\n */\n readonly changes: number;\n\n /** The number of raw ChangeLog entries read so far, including skipped entries. */\n readonly changesScanned: number;\n\n /**\n * The raw ChangeLog entries read so far, by table. Like\n * {@link changesScanned}, this includes the entries that are not yielded,\n * so it counts the same entries as {@link ChangeLogCounts.byTable} does.\n */\n readonly changesScannedByTable: ReadonlyMap<string, number>;\n\n /** The scanned entries omitted because their table is unobserved/non-syncable or the change is a no-op. */\n readonly changesSkipped: number;\n\n /**\n * The scanned entries whose rows were looked up in the snapshots. Unlike\n * the entries that are yielded, this includes the no-op changes, which are\n * only known to be that from their rows.\n */\n readonly changesLookedUp: number;\n\n /** Timing metrics recorded during diff iteration. */\n readonly stats?: DiffTimingStats | undefined;\n\n /**\n * Overrides the `prevWrites` passed to {@link Snapshotter.advance()}, for a\n * caller that decides how to write to `prev` once it knows the number of\n * {@link changes}. Must be called before the diff is iterated, except to\n * switch to `divergent`, which can be done between any two changes: it\n * shares only the reads that no write to `prev` can affect.\n */\n setPrevWrites(prevWrites: PrevWrites): void;\n}\n\n/**\n * Thrown during an iteration of a {@link SnapshotDiff} when a schema\n * change or truncate is encountered, which result in aborting the\n * advancement and resetting / rehydrating the pipelines.\n */\nexport type ResetPipelinesReason =\n | 'advancement-timeout'\n | 'scalar-subquery'\n | 'schema-change'\n | 'truncation'\n | 'permissions-change';\n\nexport class ResetPipelinesSignal extends Error {\n readonly name = 'ResetPipelinesSignal';\n readonly reason: ResetPipelinesReason;\n readonly breakdown?: string | undefined;\n\n constructor(msg: string, reason: ResetPipelinesReason, breakdown?: string) {\n super(msg);\n this.reason = reason;\n this.breakdown = breakdown;\n }\n}\n\n// Memoizes, per table spec, the SQL of the row lookups performed for each\n// change, which would otherwise be rebuilt from the table spec for every\n// read. Handing out the same string for every read of a given shape also\n// lets the SnapshotRowCache and the statement cache look it up without\n// rehashing it. Specs are recreated whenever they are recomputed, so stale\n// SQL is never served.\ntype TableReads = {\n /** `SELECT <columns> FROM <table> WHERE ` */\n readonly prefix: string;\n /** {@link Snapshot.getRow} SQL, by the NUL-joined key columns. */\n readonly byKeyColumns: Map<string, string>;\n /**\n * {@link Snapshot.getRows} SQL, by the bitmask of the table's `uniqueKeys`\n * that are queried.\n */\n readonly byUniqueKeys: Map<number, string>;\n};\n\nconst tableReads = new WeakMap<LiteTableSpecWithKeysAndVersion, TableReads>();\n\nfunction readsFor(table: LiteTableSpecWithKeysAndVersion): TableReads {\n return getOrInsertComputed(tableReads, table, () => ({\n prefix: `SELECT ${Object.keys(table.columns)\n .map(c => id(c))\n .join(',')} FROM ${id(table.name)} WHERE `,\n byKeyColumns: new Map(),\n byUniqueKeys: new Map(),\n }));\n}\n\n// The byUniqueKeys bitmask must fit in a (positive) 31-bit integer.\nconst MAX_MEMOIZED_UNIQUE_KEYS = 30;\n\n/**\n * The index that SQLite creates for the `PRIMARY KEY(\"stateVersion\", \"pos\")`\n * of `_zero.changeLog2` (the first constraint of its CREATE TABLE statement,\n * hence the `_1` suffix).\n *\n * For a `stateVersion > ?` query that reads a column outside of this index\n * (e.g. `op`) and has no ORDER BY, the query planner chooses between a range\n * search of the index and a full scan of the table based on `sqlite_stat1`.\n * Statistics recorded while the change log held only a few rows make the full\n * scan look cheaper, and they persist as the table grows to millions of rows:\n * the change log of a replication-manager's replica only receives entries\n * during column backfills, and view-syncers inherit its statistics when they\n * restore its backup. Such queries therefore pin this index with INDEXED BY,\n * which also makes them fail to prepare (rather than silently scan) if the\n * index is ever renamed.\n */\nconst CHANGE_LOG_STATE_VERSION_INDEX = 'sqlite_autoindex__zero.changeLog2_1';\n\n/**\n * The index that SQLite creates for the `UNIQUE(\"table\", \"rowKey\")` of\n * `_zero.changeLog2` (the second constraint of its CREATE TABLE statement).\n */\nconst CHANGE_LOG_TABLE_INDEX = 'sqlite_autoindex__zero.changeLog2_2';\n\n/**\n * Selects the change log entries of the tables in a JSON array of names,\n * and the table-wide ops (RESET and TRUNCATE) of every table, which abort\n * the diff whatever table they are for. Binds the two ops, then the array.\n * The array is a single parameter so that the statement is the same, and is\n * prepared once, for any set of tables.\n */\nconst CHANGE_LOG_TABLES_FILTER = `(\"op\" IN (?, ?) OR \"table\" IN (SELECT \"value\" FROM json_each(?)))`;\n\nclass Snapshot {\n static create(\n lc: LogContext,\n dbFile: string,\n appID: string,\n pageCacheSizeKib: number | undefined,\n ) {\n const conn = new Database(lc, dbFile);\n conn.pragma('synchronous = OFF'); // Applied changes are ephemeral; COMMIT is never called.\n if (pageCacheSizeKib !== undefined) {\n conn.pragma(`cache_size = -${pageCacheSizeKib}`); // Negative = size in KiB\n }\n const [{journal_mode: mode}] = conn.pragma('journal_mode') as [\n {journal_mode: string},\n ];\n // BEGIN CONCURRENT lets the Snapshotter simulate changes on a historic\n // snapshot without taking the WAL writer lock. These private changes are\n // always rolled back; the replicator is the only committer and can use\n // BEGIN IMMEDIATE on the same WAL2 database.\n assert(\n mode === 'wal2',\n `replica db must be in wal2 mode (current: ${mode})`,\n );\n\n const db = new StatementRunner(conn);\n return new Snapshot(db, appID);\n }\n\n readonly db: StatementRunner;\n readonly #appID: string;\n readonly version: string;\n #reset = false;\n\n /**\n * @param begun Whether `db` is already in a `BEGIN CONCURRENT` transaction\n * that has not read anything.\n */\n constructor(db: StatementRunner, appID: string, begun = false) {\n if (!begun) {\n db.beginConcurrent();\n }\n // Note: The subsequent read is necessary to acquire the read lock\n // (which results in the logical creation of the snapshot). Calling\n // `BEGIN CONCURRENT` alone does not result in acquiring the read lock.\n const {stateVersion} = getReplicationState(db);\n\n this.db = db;\n this.#appID = appID;\n this.version = stateVersion;\n }\n\n numChangesSince(prevVersion: string) {\n const {count} = this.db.get(\n 'SELECT COUNT(*) AS count FROM \"_zero.changeLog2\" WHERE stateVersion > ?',\n prevVersion,\n );\n return count;\n }\n\n /**\n * Counts the change log entries after `prevVersion`. The change log keeps\n * the latest entry of a row, so these are counts of the rows that changed,\n * which is what a diff from `prevVersion` to this snapshot reads.\n *\n * The total, and the number of table-wide ops (a RESET or TRUNCATE), are\n * exact, and are counted from the index alone. The counts by table are\n * exact if there are at most `sampleSize` entries. Otherwise they are\n * estimated from the newest `sampleSize` entries, so that at most that\n * many entries are read however many there are.\n */\n countChangesSince(\n prevVersion: string,\n sampleSize = CHANGE_LOG_SAMPLE_SIZE,\n ): ChangeLogCounts {\n // The index has the stateVersion and pos of every entry, and a\n // table-wide op is logged at pos -1 (see ChangeLog), so no entry is read.\n const {total, tableWideOps} = this.db.get(\n `SELECT COUNT(*) AS total, COALESCE(SUM(pos < 0), 0) AS tableWideOps\n FROM \"_zero.changeLog2\" INDEXED BY \"${CHANGE_LOG_STATE_VERSION_INDEX}\"\n WHERE stateVersion > ?`,\n prevVersion,\n );\n const byTable = new Map<string, number>();\n if (total === 0) {\n return {total, tableWideOps, byTable, sampled: false};\n }\n const rows: {table: string; count: number}[] = this.db.all(\n `SELECT \"table\", COUNT(*) AS count FROM (\n SELECT \"table\"\n FROM \"_zero.changeLog2\" INDEXED BY \"${CHANGE_LOG_STATE_VERSION_INDEX}\"\n WHERE stateVersion > ?\n ORDER BY stateVersion DESC, pos DESC LIMIT ?\n ) GROUP BY \"table\"`,\n prevVersion,\n sampleSize,\n );\n const sampled = total > sampleSize;\n const scale = sampled ? total / sampleSize : 1;\n for (const {table, count} of rows) {\n byTable.set(table, count * scale);\n }\n return {total, tableWideOps, byTable, sampled};\n }\n\n /**\n * Whether an entry of `table` was logged after `prevVersion`. This reads\n * the table's entries in the change log, however old, so it is for tables\n * with few rows.\n */\n tableChangedSince(table: string, prevVersion: string): boolean {\n const row = this.db.get(\n `SELECT 1 FROM \"_zero.changeLog2\" INDEXED BY \"${CHANGE_LOG_TABLE_INDEX}\"\n WHERE \"table\" = ? AND stateVersion > ? LIMIT 1`,\n table,\n prevVersion,\n );\n return row !== undefined;\n }\n\n /**\n * Whether a table-wide RESET op (i.e. a schema change) was logged after\n * `prevVersion`. Table specs computed at or before `prevVersion` are\n * stale with respect to this snapshot if so.\n */\n schemaChangedSince(prevVersion: string): boolean {\n const row = this.db.get(\n `SELECT 1 FROM \"_zero.changeLog2\" INDEXED BY \"${CHANGE_LOG_STATE_VERSION_INDEX}\"\n WHERE stateVersion > ? AND op = ? LIMIT 1`,\n prevVersion,\n RESET_OP,\n );\n return row !== undefined;\n }\n\n /**\n * Whether any table-wide op (i.e. a RESET or TRUNCATE) was logged after\n * `prevVersion`. Iterating over a diff ending at this snapshot will\n * abort with a {@link ResetPipelinesSignal} if so.\n */\n hasTableWideOpSince(prevVersion: string): boolean {\n const row = this.db.get(\n `SELECT 1 FROM \"_zero.changeLog2\" INDEXED BY \"${CHANGE_LOG_STATE_VERSION_INDEX}\"\n WHERE stateVersion > ? AND op IN (?, ?) LIMIT 1`,\n prevVersion,\n RESET_OP,\n TRUNCATE_OP,\n );\n return row !== undefined;\n }\n\n /**\n * The first table-wide op (a schema change or a truncation) logged after\n * `prevVersion`, in the order that {@link changesSince} reads the entries.\n */\n firstTableWideOpSince(\n prevVersion: string,\n ): ChangeLogPosition & {table: string; op: string} {\n return this.db.get(\n `SELECT \"stateVersion\", \"pos\", \"table\", \"op\" FROM \"_zero.changeLog2\" INDEXED BY \"${CHANGE_LOG_STATE_VERSION_INDEX}\"\n WHERE \"stateVersion\" > ? AND \"pos\" < 0\n ORDER BY \"stateVersion\" ASC, \"pos\" ASC LIMIT 1`,\n prevVersion,\n );\n }\n\n /**\n * The entries of `table` logged after `prevVersion`, in the order that\n * {@link changesSince} reads them. For a table with few rows.\n */\n entriesSince(\n table: string,\n prevVersion: string,\n ): (ChangeLogPosition & {rowKey: string | null; op: string})[] {\n return this.db.all(\n `SELECT \"stateVersion\", \"pos\", \"rowKey\", \"op\" FROM \"_zero.changeLog2\" INDEXED BY \"${CHANGE_LOG_TABLE_INDEX}\"\n WHERE \"table\" = ? AND \"stateVersion\" > ?\n ORDER BY \"stateVersion\" ASC, \"pos\" ASC`,\n table,\n prevVersion,\n );\n }\n\n /**\n * @param tables If set, only the entries of these tables, and the\n * table-wide ops of every table, are read.\n */\n changesSince(prevVersion: string, tables?: string | undefined) {\n // Note: The queried fields are constrained to only those that are relevant\n // to the snapshot diff, i.e. those of a ChangeLogEntry.\n const cached = this.db.statementCache.get(\n tables === undefined\n ? `SELECT \"stateVersion\", \"table\", \"rowKey\", \"op\" FROM \"_zero.changeLog2\"\n WHERE \"stateVersion\" > ? ORDER BY \"stateVersion\" ASC, \"pos\" ASC`\n : `SELECT \"stateVersion\", \"table\", \"rowKey\", \"op\" FROM \"_zero.changeLog2\"\n WHERE \"stateVersion\" > ? AND ${CHANGE_LOG_TABLES_FILTER}\n ORDER BY \"stateVersion\" ASC, \"pos\" ASC`,\n );\n // Raw rows skip building a row object per entry. See RawChangeLogEntry.\n cached.statement.raw(true);\n return {\n changes:\n tables === undefined\n ? cached.statement.iterate<RawChangeLogEntry>(prevVersion)\n : cached.statement.iterate<RawChangeLogEntry>(\n prevVersion,\n RESET_OP,\n TRUNCATE_OP,\n tables,\n ),\n cleanup: () => this.db.statementCache.return(cached),\n };\n }\n\n /**\n * Reads the row with the given `rowKey`, or `undefined` if it does not\n * exist.\n *\n * @param cache An optional {@link SnapshotRowCache} through which to\n * perform the read, along with the `tag` that identifies the\n * version(s) of the replica that the result depends on.\n */\n getRow(\n table: LiteTableSpecWithKeysAndVersion,\n rowKey: JSONValue,\n cache?: SnapshotRowCache,\n tag?: string,\n ) {\n const key = normalizedKeyOrder(rowKey as RowKey);\n const cols = Object.keys(key);\n const reads = readsFor(table);\n const sql = getOrInsertComputed(\n reads.byKeyColumns,\n cols.join('\\0'),\n () => reads.prefix + cols.map(c => `${id(c)}=?`).join(' AND '),\n );\n const args = Object.values(key);\n const read = () =>\n this.db.statementCache.use(sql, cached => {\n cached.statement.safeIntegers(true);\n const row = cached.statement.get<SQLiteRow>(args);\n recordIndexUsage(cached.statement, table.name);\n return row;\n });\n return cache\n ? cache.getOrRead(tag ?? '', sql, 'get', args, () => {\n const row = read();\n if (row !== undefined) {\n this.#assertNotAdvanced(row);\n }\n return row;\n })\n : read();\n }\n\n /**\n * Reads the rows that conflict with `row` on any of the given unique\n * `keys` (which includes the row with the same primary key, if any).\n *\n * @param cache An optional {@link SnapshotRowCache} through which to\n * perform the read, along with the `tag` that identifies the\n * version(s) of the replica that the result depends on.\n */\n getRows(\n table: LiteTableSpecWithKeysAndVersion,\n keys: PrimaryKey[],\n row: SQLiteRow,\n cache?: SnapshotRowCache,\n tag?: string,\n ) {\n // Filter out keys where any column is NULL. This is both correct and\n // critical for performance:\n // 1. Correctness: NULL values can't violate uniqueness (NULL != NULL in SQL)\n // 2. Performance: SQLite's MULTI-INDEX OR optimization completely fails when\n // any branch involves NULL, falling back to a full table scan. This was\n // causing slowdowns of hundreds of times on tables with nullable unique columns.\n let validKeys: PrimaryKey[] = keys;\n let mask = (1 << keys.length) - 1;\n\n for (let i = 0; i < keys.length; i++) {\n const key = keys[i];\n for (let j = 0; j < key.length; j++) {\n const val = row[key[j]];\n if (val === null || val === undefined) {\n validKeys = [];\n mask = 0;\n for (let k = 0; k < keys.length; k++) {\n const candidate = keys[k];\n if (\n candidate.every(\n col => row[col] !== null && row[col] !== undefined,\n )\n ) {\n validKeys.push(candidate);\n mask |= 1 << k;\n }\n }\n break;\n }\n }\n if (validKeys !== keys) {\n break;\n }\n }\n\n if (validKeys.length === 0) {\n return [];\n }\n const reads = readsFor(table);\n const buildSQL = () =>\n reads.prefix +\n validKeys\n .map(key => key.map(c => `${id(c)}=?`).join(' AND '))\n .join(' OR ');\n const sql =\n keys === table.uniqueKeys && keys.length <= MAX_MEMOIZED_UNIQUE_KEYS\n ? getOrInsertComputed(reads.byUniqueKeys, mask, buildSQL)\n : buildSQL();\n const args: unknown[] = [];\n for (let i = 0; i < validKeys.length; i++) {\n const key = validKeys[i];\n for (let j = 0; j < key.length; j++) {\n args.push(row[key[j]]);\n }\n }\n const read = () =>\n this.db.statementCache.use(sql, cached => {\n cached.statement.safeIntegers(true);\n const rows = cached.statement.all<SQLiteRow>(args);\n recordIndexUsage(cached.statement, table.name);\n return rows;\n });\n return cache\n ? cache.getOrRead(tag ?? '', sql, 'all', args, () => {\n const rows = read();\n for (const row of rows) {\n this.#assertNotAdvanced(row);\n }\n return rows;\n })\n : read();\n }\n\n /**\n * Rows are shared with other client groups via the SnapshotRowCache, so\n * one read from a connection that has advanced past this snapshot (i.e. a\n * {@link SnapshotDiff} used after its Snapshotter advanced) must fail\n * before it is cached, rather than be served to the valid Diffs of other\n * client groups (whose own validity checks would then fail).\n */\n #assertNotAdvanced(row: SQLiteRow) {\n if ((row[ROW_VERSION] ?? '~') > this.version) {\n throw new InvalidDiffError(\n `Diff is no longer valid. db has advanced past ${this.version}.`,\n );\n }\n }\n\n /**\n * Whether the snapshot has been released, or its connection reset to a\n * newer snapshot (i.e. via {@link release()} or {@link resetToHead()}),\n * after which reads no longer reflect {@link version}.\n */\n get reset(): boolean {\n return this.#reset;\n }\n\n /**\n * Ends the snapshot's read transaction, after which reads no longer\n * reflect {@link version}. An open read transaction keeps SQLite from\n * checkpointing the write-ahead log past the snapshot, so a snapshot that\n * is no longer read should not be left open.\n */\n release(): void {\n if (!this.#reset) {\n this.#reset = true;\n this.db.rollback();\n // The connection is put back into a transaction, which holds nothing\n // until it reads. A snapshot's connection is writable, and outside of\n // a transaction anything that is run on it would be committed to the\n // replica under the replica's write lock, which only the replicator\n // should take.\n this.db.beginConcurrent();\n }\n }\n\n resetToHead(): Snapshot {\n this.release();\n return new Snapshot(this.db, this.#appID, true);\n }\n}\n\nclass Diff implements SnapshotDiff {\n readonly #permissionsTable: string;\n readonly #syncableTables: Map<string, LiteAndZqlSpec>;\n readonly #allTableNames: Set<string>;\n readonly #observedTables: TableFilter | undefined;\n readonly #rowCache: SnapshotRowCache | undefined;\n /** The JSON array of the names of the tables whose entries are read. */\n readonly #readTables: string | undefined;\n #permissionsChanged: boolean | undefined;\n #nothingToRead = false;\n #prevWrites: PrevWrites;\n readonly #prevTagUniform: string;\n readonly #prevTagDivergent: string;\n #iterated = false;\n readonly prev: Snapshot;\n readonly curr: Snapshot;\n readonly changes: number;\n changesScanned = 0;\n readonly changesScannedByTable = new Map<string, number>();\n changesSkipped = 0;\n changesLookedUp = 0;\n readonly stats: DiffTimingStats = {\n changeLogReadMs: 0,\n rowReadMs: 0,\n parseMs: 0,\n totalDiffMs: 0,\n };\n\n constructor(\n appID: string,\n syncableTables: Map<string, LiteAndZqlSpec>,\n allTableNames: Set<string>,\n prev: Snapshot,\n curr: Snapshot,\n observedTables?: TableFilter | undefined,\n rowCache?: SnapshotRowCache | undefined,\n prevWrites: PrevWrites = 'uniform',\n counts?: ChangeLogCounts | undefined,\n readTables?: Iterable<string> | undefined,\n ) {\n this.#prevWrites = prevWrites;\n this.#permissionsTable = `${appID}.permissions`;\n // A change of the permissions is always looked for.\n const read = readTables && new Set(readTables).add(this.#permissionsTable);\n this.#readTables = read && JSON.stringify([...read]);\n this.#syncableTables = syncableTables;\n this.#allTableNames = allTableNames;\n this.#observedTables = observedTables;\n this.prev = prev;\n this.curr = curr;\n this.#prevTagUniform = `p:${prev.version}`;\n this.#prevTagDivergent = `p:${prev.version}:${curr.version}`;\n if (counts === undefined) {\n assert(read === undefined, 'readTables requires counts');\n this.changes = curr.numChangesSince(prev.version);\n } else {\n // Without an entry of a table that is read, or a table-wide op (which\n // aborts the diff whatever table it is for), there is nothing to read.\n const hasEntries = (table: string) => this.#hasEntries(counts, table);\n this.#nothingToRead =\n counts.total === 0 ||\n (read !== undefined &&\n counts.tableWideOps === 0 &&\n ![...read].some(hasEntries));\n // As without counts, this is the number of entries of every table.\n this.changes = this.#nothingToRead ? 0 : counts.total;\n }\n // Row values are only shared (via the cache) between Diffs that do not\n // straddle a table-wide op. This guarantees that any two Diffs that\n // encounter the same change log entry read the row from tables with\n // the same schema (and contents), since a RESET or TRUNCATE between\n // their `curr` versions would necessarily fall within the range of the\n // later Diff. (Such a Diff aborts with a ResetPipelinesSignal anyway.)\n const hasTableWideOp = counts\n ? counts.tableWideOps > 0\n : curr.hasTableWideOpSince(prev.version);\n this.#rowCache = rowCache && !hasTableWideOp ? rowCache : undefined;\n }\n\n /**\n * Whether the diff has an entry of `table`. Sampled counts cannot show\n * that a table has none, so the answer is then `true`, except for the\n * permissions table: it has few rows, so whether it has an entry is\n * looked up instead.\n */\n #hasEntries(counts: ChangeLogCounts, table: string): boolean {\n if (!counts.sampled) {\n return (counts.byTable.get(table) ?? 0) > 0;\n }\n if (table !== this.#permissionsTable) {\n return true;\n }\n return (this.#permissionsChanged ??= this.curr.tableChangedSince(\n table,\n this.prev.version,\n ));\n }\n\n setPrevWrites(prevWrites: PrevWrites): void {\n assert(\n !this.#iterated || prevWrites === 'divergent',\n 'prevWrites must be set before iterating the diff',\n );\n this.#prevWrites = prevWrites;\n }\n\n [Symbol.iterator](): Iterator<Change> {\n this.#iterated = true;\n if (this.#nothingToRead) {\n return [][Symbol.iterator]();\n }\n const {changes, cleanup: done} = this.curr.changesSince(\n this.prev.version,\n this.#readTables,\n );\n\n const cleanup = () => {\n try {\n // Allow open iterators to clean up their state.\n changes.return?.(undefined);\n } finally {\n done();\n }\n };\n\n return {\n next: () => {\n const nextStart = performance.now();\n try {\n for (;;) {\n const clStart = performance.now();\n const {value, done} = changes.next();\n this.stats.changeLogReadMs += performance.now() - clStart;\n if (done) {\n cleanup();\n return {value, done: true};\n }\n\n this.changesScanned++;\n const parseStart = performance.now();\n const {table, rowKey, op, stateVersion} = parseChangeLogEntry(\n ...value,\n );\n this.stats.parseMs += performance.now() - parseStart;\n this.changesScannedByTable.set(\n table,\n (this.changesScannedByTable.get(table) ?? 0) + 1,\n );\n if (op === RESET_OP) {\n // The current map of `TableSpec`s may not have the correct or complete information.\n throw new ResetPipelinesSignal(\n `schema for table ${table} has changed`,\n 'schema-change',\n );\n }\n if (op === TRUNCATE_OP) {\n // Truncates are also processed by rehydrating pipelines at current.\n throw new ResetPipelinesSignal(\n `table ${table} has been truncated`,\n 'truncation',\n );\n }\n if (\n this.#observedTables &&\n !this.#observedTables.has(table) &&\n table !== this.#permissionsTable\n ) {\n if (this.#allTableNames.has(table)) {\n this.changesSkipped++;\n continue; // skip change log entries for unobserved tables.\n }\n throw new Error(`change for unknown table ${table}`);\n }\n const specs = this.#syncableTables.get(table);\n if (!specs) {\n if (this.#allTableNames.has(table)) {\n this.changesSkipped++;\n continue; // skip change log entries for non-syncable tables.\n }\n throw new Error(`change for unknown table ${table}`);\n }\n const {tableSpec, zqlSpec} = specs;\n\n // Sanity check: All change log ops should have a stateVersion\n // greater than minRowVersion in the table metadata. This is a\n // mini-proof that the overlay does not need to be applied to\n // rows produced in incremental catchup, based on the invariant in\n // change-processor's #bumpVersions(), whereby the setting of the\n // minRowVersion is always followed by a RESET OP, meaning that\n // subsequent change-log traversal happens at a later version.\n assert(\n (tableSpec.minRowVersion ?? '') < stateVersion,\n () =>\n `unexpected change @${stateVersion} for table ${table} with ` +\n `minRowVersion ${tableSpec.minRowVersion}: ${op}(${rowKey})`,\n );\n\n assert(rowKey !== null, 'rowKey must be present for row changes');\n\n // Row reads are shared with the other client groups on the\n // worker via the SnapshotRowCache (if configured):\n //\n // * The new value of the row is read from `curr`, which is\n // never written to during the iteration, and is the version\n // of the row at `stateVersion` (as verified by\n // checkThatDiffIsValid()). It is thus identical for every\n // Diff that encounters the change log entry.\n //\n // * Previous values are read from `prev`, at `prev.version`,\n // which the caller (i.e. IVM) writes to as the iteration\n // progresses. For a table whose only unique key is its\n // primary key, no change applied before this one can affect\n // this row, so the result depends solely on `prev.version`.\n // Otherwise, the result can include rows that conflict on\n // other unique keys, which may have been added or removed by\n // preceding changes; see PrevWrites for when that can be\n // shared.\n // The first advance() after this Diff was created resets the\n // `prev` connection to head. Reads would then no longer reflect\n // `prev.version`, and cache hits would not reveal it (the cached\n // rows were read by valid Diffs), so this must be checked\n // explicitly rather than inferred from the rows' versions.\n if (this.prev.reset) {\n throw new InvalidDiffError(\n `Diff is no longer valid. prev db has advanced past ${this.prev.version}.`,\n );\n }\n\n const cache = this.#rowCache;\n const prevDependsOnWrites =\n tableSpec.uniqueKeys.length > 1 && this.#prevWrites !== 'none';\n const prevCache =\n prevDependsOnWrites && this.#prevWrites === 'divergent'\n ? undefined\n : cache;\n const prevTag = prevDependsOnWrites\n ? this.#prevTagDivergent\n : this.#prevTagUniform;\n this.changesLookedUp++;\n const rowStart = performance.now();\n const nextValue =\n op === SET_OP\n ? this.curr.getRow(\n tableSpec,\n rowKey,\n cache,\n `n:${stateVersion}`,\n )\n : null;\n let prevValues;\n if (nextValue) {\n prevValues = this.prev.getRows(\n tableSpec,\n tableSpec.uniqueKeys,\n nextValue,\n prevCache,\n prevTag,\n );\n } else {\n const prevValue = this.prev.getRow(\n tableSpec,\n rowKey,\n prevCache,\n prevTag,\n );\n prevValues = prevValue ? [prevValue] : [];\n }\n this.stats.rowReadMs += performance.now() - rowStart;\n if (nextValue === undefined) {\n throw new Error(\n `Missing value for ${table} ${stringify(rowKey)}`,\n );\n }\n // Sanity check detects if the diff is being accessed after the Snapshots have advanced.\n this.checkThatDiffIsValid(stateVersion, op, prevValues, nextValue);\n\n if (prevValues.length === 0 && nextValue === null) {\n // Filter out no-op changes (e.g. a delete of a row that does not exist in prev).\n // TODO: Consider doing this for deep-equal values.\n this.changesSkipped++;\n continue;\n }\n\n if (table === this.#permissionsTable) {\n const changed = prevValues.find(\n prevValue => prevValue.permissions !== nextValue?.permissions,\n );\n if (changed) {\n throw new ResetPipelinesSignal(\n `Permissions have changed ${changed.hash} => ${nextValue?.hash}`,\n 'permissions-change',\n );\n }\n }\n\n // Note: The raw SQLite rows may be shared with other client\n // groups via the SnapshotRowCache, so they must not be modified.\n // fromSQLiteTypes() produces new row objects.\n return {\n value: {\n table,\n prevValues: prevValues.map(prevValue =>\n fromSQLiteTypes(zqlSpec, prevValue, table),\n ),\n nextValue: nextValue\n ? fromSQLiteTypes(zqlSpec, nextValue, table)\n : null,\n rowKey,\n } satisfies Change,\n };\n }\n } catch (e) {\n // This control flow path is not covered by the return() method (i.e. `break`).\n cleanup();\n throw e;\n } finally {\n this.stats.totalDiffMs += performance.now() - nextStart;\n }\n },\n\n return: (value: unknown) => {\n cleanup();\n return {value, done: true};\n },\n };\n }\n\n checkThatDiffIsValid(\n stateVersion: string,\n op: string,\n prevValues: readonly SQLiteRow[],\n nextValue: SQLiteRow | null,\n ) {\n // Sanity checks to detect that the diff is not being accessed after\n // the Snapshots have advanced.\n if (stateVersion > this.curr.version) {\n throw new InvalidDiffError(\n `Diff is no longer valid. curr db has advanced past ${this.curr.version}`,\n );\n }\n if (\n prevValues.findIndex(\n prevValue => (prevValue[ROW_VERSION] ?? '~') > this.prev.version,\n ) !== -1\n ) {\n throw new InvalidDiffError(\n `Diff is no longer valid. prev db has advanced past ${this.prev.version}.`,\n );\n }\n if (op === SET_OP && nextValue?.[ROW_VERSION] !== stateVersion) {\n throw new InvalidDiffError(\n 'Diff is no longer valid. curr db has advanced.',\n );\n }\n }\n}\n\nexport class InvalidDiffError extends Error {\n constructor(msg: string) {\n super(msg);\n }\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ttl-clock.js","names":[],"sources":["../../../../../../zero-cache/src/services/view-syncer/ttl-clock.ts"],"sourcesContent":["import * as v from '../../../../shared/src/valita.ts';\n\ndeclare const ttlClockTag: unique symbol;\n\nexport type TTLClock = {[ttlClockTag]: true};\n\nexport const ttlClockSchema = v.number() as v.Type<unknown> as v.Type<TTLClock>;\n\nexport function ttlClockAsNumber(ttlClock: TTLClock): number {\n return ttlClock as unknown as number;\n}\n\nexport function ttlClockFromNumber(ttlClock: number): TTLClock {\n return ttlClock as unknown as TTLClock;\n}\n"],"mappings":";;AAMA,IAAa,
|
|
1
|
+
{"version":3,"file":"ttl-clock.js","names":["v"],"sources":["../../../../../../zero-cache/src/services/view-syncer/ttl-clock.ts"],"sourcesContent":["import * as v from '../../../../shared/src/valita.ts';\n\ndeclare const ttlClockTag: unique symbol;\n\nexport type TTLClock = {[ttlClockTag]: true};\n\nexport const ttlClockSchema = v.number() as v.Type<unknown> as v.Type<TTLClock>;\n\nexport function ttlClockAsNumber(ttlClock: TTLClock): number {\n return ttlClock as unknown as number;\n}\n\nexport function ttlClockFromNumber(ttlClock: number): TTLClock {\n return ttlClock as unknown as TTLClock;\n}\n"],"mappings":";;AAMA,IAAa,iBAAiBA,eAAE,OAAO;AAEvC,SAAgB,iBAAiB,UAA4B;CAC3D,OAAO;AACT;AAEA,SAAgB,mBAAmB,UAA4B;CAC7D,OAAO;AACT"}
|