@rocicorp/zero 1.12.0-canary.3 → 1.12.0-canary.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/out/_virtual/{_@oxc-project_runtime@0.130.0/helpers → _@oxc-project_runtime@0.154.0/helpers/esm}/usingCtx.js +2 -2
- package/out/analyze-query/src/analyze-cli.d.ts.map +1 -1
- package/out/analyze-query/src/analyze-cli.js +6 -4
- package/out/analyze-query/src/analyze-cli.js.map +1 -1
- package/out/analyze-query/src/bin-transform.js +4 -3
- package/out/analyze-query/src/bin-transform.js.map +1 -1
- package/out/analyze-query/src/zql-chain.d.ts +23 -0
- package/out/analyze-query/src/zql-chain.d.ts.map +1 -0
- package/out/analyze-query/src/zql-chain.js +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.js +13 -11
- 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.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.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.js +5 -2
- package/out/replicache/src/db/write.js.map +1 -1
- package/out/replicache/src/deleted-clients.js +3 -2
- 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.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.js +5 -3
- package/out/replicache/src/index-defs.js.map +1 -1
- package/out/replicache/src/kv/expo-sqlite/store.js +1 -1
- package/out/replicache/src/kv/expo-sqlite/store.js.map +1 -1
- package/out/replicache/src/kv/idb-store.js +1 -1
- 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.js +1 -1
- package/out/replicache/src/kv/sqlite-store.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.js +2 -2
- 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.map +1 -1
- package/out/replicache/src/replicache-impl.js +3 -3
- 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.js +2 -4
- package/out/replicache/src/sync/patch.js.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.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/shared/src/arrays.js +4 -1
- package/out/shared/src/arrays.js.map +1 -1
- package/out/shared/src/asserts.js +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/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.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/hash.js +2 -2
- package/out/shared/src/hash.js.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 +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.js +9 -12
- package/out/shared/src/options.js.map +1 -1
- package/out/shared/src/promise-race.js.map +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/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/sorted-entries.js.map +1 -1
- package/out/shared/src/tdigest-schema.js.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 +2 -4
- package/out/z2s/src/compiler.js.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 +211 -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 +10 -9
- 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 +6 -17
- 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 +5 -0
- package/out/zero-cache/src/config/zero-config.d.ts.map +1 -1
- package/out/zero-cache/src/config/zero-config.js +13 -2
- 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/run-transaction.js.map +1 -1
- package/out/zero-cache/src/db/specs.js +7 -5
- 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 +5 -3
- 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.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 +1 -1
- 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.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.js +2 -1
- 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.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.d.ts.map +1 -1
- package/out/zero-cache/src/server/syncer.js +9 -4
- 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 +2 -2
- 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.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 +4 -4
- 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 +3 -3
- 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 +6 -8
- 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/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.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 +3 -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.js +2 -2
- 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.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.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.js.map +1 -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.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.map +1 -1
- package/out/zero-cache/src/services/change-streamer/backup-monitor.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/broadcast.js +1 -1
- package/out/zero-cache/src/services/change-streamer/broadcast.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-log-codec.d.ts +1 -1
- package/out/zero-cache/src/services/change-streamer/change-log-codec.d.ts.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 +5 -3
- 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 +21 -21
- 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 +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.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 +1 -1
- 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 +3 -3
- 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/snapshot-message.js +1 -1
- 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 +1 -1
- 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.d.ts.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.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/storer.js +3 -3
- package/out/zero-cache/src/services/change-streamer/storer.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/subscribe.js +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 +2 -2
- 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.js.map +1 -1
- package/out/zero-cache/src/services/life-cycle.js +2 -2
- 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 +3 -3
- 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 +1 -1
- package/out/zero-cache/src/services/mutagen/mutagen.js.map +1 -1
- package/out/zero-cache/src/services/mutagen/pusher.js +3 -2
- package/out/zero-cache/src/services/mutagen/pusher.js.map +1 -1
- package/out/zero-cache/src/services/plannerz.js +6 -5
- 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 +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.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 +1 -1
- package/out/zero-cache/src/services/replicator/reporter/recorder.js.map +1 -1
- package/out/zero-cache/src/services/replicator/reporter/report-schema.js +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 -7
- 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.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 +1 -1
- 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.map +1 -1
- package/out/zero-cache/src/services/shadow-sync/shadow-sync-service.js.map +1 -1
- package/out/zero-cache/src/services/statz.js +4 -3
- package/out/zero-cache/src/services/statz.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/active-users-gauge.js +2 -2
- package/out/zero-cache/src/services/view-syncer/active-users-gauge.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/advancement-metrics.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/batch-pacer.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/client-handler.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/client-handler.js +24 -3
- package/out/zero-cache/src/services/view-syncer/client-handler.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/client-schema.d.ts +15 -2
- package/out/zero-cache/src/services/view-syncer/client-schema.d.ts.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.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/cvr-store.js +11 -6
- 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.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.d.ts.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 +1 -1
- 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 +1 -1
- package/out/zero-cache/src/services/view-syncer/schema/types.js +1 -1
- 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.d.ts +8 -1
- package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/snapshotter.js +7 -6
- 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.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/view-syncer.js +19 -15
- 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.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.js +6 -4
- package/out/zero-cache/src/types/pg.js.map +1 -1
- package/out/zero-cache/src/types/poke-chunk.js +2 -2
- 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.js.map +1 -1
- package/out/zero-cache/src/types/sql.js.map +1 -1
- package/out/zero-cache/src/types/streams.js +10 -9
- 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.map +1 -1
- package/out/zero-cache/src/types/timeout.js +1 -1
- package/out/zero-cache/src/types/websocket-handoff.js +1 -1
- package/out/zero-cache/src/types/ws.js +1 -1
- package/out/zero-cache/src/workers/connection.js +5 -6
- package/out/zero-cache/src/workers/connection.js.map +1 -1
- package/out/zero-cache/src/workers/mutator.js.map +1 -1
- 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.d.ts.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 +4 -4
- package/out/zero-cache/src/workers/syncer.js.map +1 -1
- package/out/zero-client/src/client/active-clients-manager.js +1 -1
- 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.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.js +1 -1
- package/out/zero-client/src/client/crud.js.map +1 -1
- package/out/zero-client/src/client/custom.js +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.js +1 -1
- package/out/zero-client/src/client/enable-analytics.js.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.js +2 -1
- 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.js.map +1 -1
- package/out/zero-client/src/client/mutator-proxy.js.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/version.js +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.js +19 -11
- 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/util/nanoid.js.map +1 -1
- package/out/zero-permissions/src/permissions.js +3 -2
- 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.js +19 -9
- package/out/zero-protocol/src/ast.js.map +1 -1
- package/out/zero-protocol/src/change-desired-queries.js.map +1 -1
- package/out/zero-protocol/src/client-schema.js +1 -1
- package/out/zero-protocol/src/client-schema.js.map +1 -1
- package/out/zero-protocol/src/close-connection.js +1 -1
- package/out/zero-protocol/src/close-connection.js.map +1 -1
- package/out/zero-protocol/src/connect.js +1 -1
- package/out/zero-protocol/src/connect.js.map +1 -1
- package/out/zero-protocol/src/custom-queries.js +1 -1
- package/out/zero-protocol/src/custom-queries.js.map +1 -1
- package/out/zero-protocol/src/data.js +4 -2
- package/out/zero-protocol/src/data.js.map +1 -1
- package/out/zero-protocol/src/delete-clients.js.map +1 -1
- package/out/zero-protocol/src/down.d.ts +27 -27
- package/out/zero-protocol/src/down.js.map +1 -1
- package/out/zero-protocol/src/error.js.map +1 -1
- package/out/zero-protocol/src/inspect-down.d.ts +81 -81
- package/out/zero-protocol/src/inspect-down.js +1 -1
- package/out/zero-protocol/src/inspect-down.js.map +1 -1
- package/out/zero-protocol/src/inspect-up.js +1 -1
- package/out/zero-protocol/src/inspect-up.js.map +1 -1
- package/out/zero-protocol/src/mutate-server.js +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.js +1 -1
- package/out/zero-protocol/src/mutation.js.map +1 -1
- package/out/zero-protocol/src/mutations-patch.js +1 -1
- package/out/zero-protocol/src/mutations-patch.js.map +1 -1
- package/out/zero-protocol/src/ping.js +1 -1
- package/out/zero-protocol/src/ping.js.map +1 -1
- package/out/zero-protocol/src/poke.d.ts +6 -6
- 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.js +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.js +1 -1
- package/out/zero-protocol/src/pull.js.map +1 -1
- package/out/zero-protocol/src/push.js +1 -1
- package/out/zero-protocol/src/push.js.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.js +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.map +1 -1
- package/out/zero-protocol/src/update-auth.js.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 +1 -1
- 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/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.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.js +1 -1
- package/out/zero-schema/src/schema-config.js.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.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.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.js.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/like.js +0 -1
- package/out/zql/src/builder/like.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 +10 -0
- package/out/zql/src/ivm/cap.js.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 -1
- 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.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/take-gate.js.map +1 -1
- package/out/zql/src/ivm/take.d.ts.map +1 -1
- package/out/zql/src/ivm/take.js +5 -4
- package/out/zql/src/ivm/take.js.map +1 -1
- package/out/zql/src/ivm/union-fan-in.js +1 -1
- package/out/zql/src/ivm/union-fan-in.js.map +1 -1
- package/out/zql/src/ivm/union-fan-out.js.map +1 -1
- package/out/zql/src/ivm/view-apply-change.js +1 -1
- package/out/zql/src/ivm/view-apply-change.js.map +1 -1
- package/out/zql/src/mutate/crud.js +3 -2
- package/out/zql/src/mutate/crud.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.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-source.js.map +1 -1
- package/out/zql/src/planner/planner-terminus.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.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.js +1 -1
- package/out/zql/src/query/query-delegate-base.js.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-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/runnable-query-impl.js +3 -2
- 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.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.d.ts +27 -8
- package/out/zqlite/src/database-storage.d.ts.map +1 -1
- package/out/zqlite/src/database-storage.js +190 -53
- 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.js.map +1 -1
- 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.js +1 -1
- 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 +11 -0
- package/out/zqlite/src/table-source.d.ts.map +1 -1
- package/out/zqlite/src/table-source.js +63 -26
- package/out/zqlite/src/table-source.js.map +1 -1
- package/package.json +37 -36
- 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/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
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"html-dialog-prompt.js","names":[],"sources":["../../../../../../zero-client/src/client/inspector/html-dialog-prompt.ts"],"sourcesContent":["/**\n * Checks if we can create HTML elements and are in a browser document context\n */\nfunction canUseHTMLDialog(): boolean {\n try {\n // Check if we're in a test environment (vitest sets this)\n if (\n typeof globalThis !== 'undefined' &&\n '__vitest_worker__' in globalThis\n ) {\n return false;\n }\n\n return (\n typeof document !== 'undefined' &&\n typeof document.createElement === 'function' &&\n typeof HTMLDialogElement !== 'undefined' &&\n document.body !== null &&\n // Make sure we can actually create a dialog element\n document.createElement('dialog') instanceof HTMLDialogElement\n );\n } catch {\n return false;\n }\n}\n\n/**\n * Creates a password prompt using HTML <dialog> element\n */\nexport function createHTMLPasswordPrompt(\n message: string,\n): Promise<string | null> {\n if (!canUseHTMLDialog()) {\n // Fallback to browser prompt if HTML dialog is not available\n return Promise.resolve(prompt(message));\n }\n\n return new Promise<string | null>(resolve => {\n // Shared CSS constants\n const reset = 'all:revert;';\n const w = 'rgba(255,255,255,';\n const white = w + '1)';\n const whiteTransp = w + '0.4)';\n const r1 = '0.25rem';\n const font = `font-family:system-ui,sans-serif;color:${white};`;\n const btnBase = `${reset}${font}cursor:pointer;font-size:1rem;font-weight:500;border:none;padding:0.4rem 0.75rem;border-radius:${r1};background:`;\n\n const dialog = document.createElement('dialog');\n dialog.style.cssText = `${reset}${font}background:rgba(0,0,0,0.95);padding:2rem;border:1px solid ${whiteTransp};border-radius:0.5rem;`;\n\n // Prevent keydown from escaping the dialog which can be interfered by other\n // listeners (e.g. global hotkeys)\n dialog.addEventListener('keydown', e => {\n e.stopPropagation();\n });\n\n dialog.oncancel = () => {\n dialog.remove();\n resolve(null);\n };\n\n const form = document.createElement('form');\n form.method = 'dialog';\n form.style.cssText = `${reset}margin:0;`;\n\n const messagePara = document.createElement('p');\n messagePara.style.cssText = `${reset}${font}font-size:1.5rem;margin:0 0 1rem 0;`;\n messagePara.append(message);\n\n const passwordInput = document.createElement('input');\n passwordInput.type = 'password';\n passwordInput.placeholder = 'Admin password';\n passwordInput.autocomplete = 'current-password';\n passwordInput.autofocus = true;\n passwordInput.style.cssText = `${reset}${font}font-size:1rem;display:block;margin:0 0 1rem 0;padding:0.5rem;background:rgba(0,0,0,0.5);border:1px solid ${whiteTransp};border-radius:${r1};`;\n\n const buttonDiv = document.createElement('div');\n buttonDiv.style.cssText = reset;\n\n const cancelBtn = document.createElement('button');\n cancelBtn.type = 'reset';\n cancelBtn.append('Cancel');\n cancelBtn.style.cssText = btnBase + w + '0.25);';\n\n const okBtn = document.createElement('button');\n okBtn.type = 'submit';\n okBtn.value = 'ok';\n okBtn.append('OK');\n okBtn.style.cssText = btnBase + 'rgba(19,106,235,1);margin-right:0.5rem;';\n\n buttonDiv.append(okBtn, cancelBtn);\n form.append(messagePara, passwordInput, buttonDiv);\n dialog.append(form);\n\n form.onreset = () => {\n dialog.close();\n };\n\n dialog.onclose = () => {\n if (dialog.returnValue === 'ok') {\n resolve(passwordInput.value || null);\n } else {\n resolve(null);\n }\n dialog.remove();\n };\n\n document.body.append(dialog);\n dialog.showModal();\n });\n}\n"],"mappings":";;;;AAGA,SAAS,mBAA4B;CACnC,IAAI;EAEF,IACE,OAAO,eAAe,eACtB,uBAAuB,YAEvB,OAAO;EAGT,OACE,OAAO,aAAa,eACpB,OAAO,SAAS,kBAAkB,cAClC,OAAO,sBAAsB,eAC7B,SAAS,SAAS,QAElB,SAAS,cAAc,QAAQ,aAAa;CAEhD,QAAQ;EACN,OAAO;CACT;AACF;;;;AAKA,SAAgB,yBACd,SACwB;CACxB,IAAI,CAAC,iBAAiB,GAEpB,OAAO,QAAQ,QAAQ,OAAO,OAAO,CAAC;CAGxC,OAAO,IAAI,SAAuB,YAAW;EAE3C,MAAM,QAAQ;EACd,MAAM,IAAI;EACV,MAAM,QAAQ,IAAI;EAClB,MAAM,cAAc,IAAI;EACxB,MAAM,KAAK;EACX,MAAM,OAAO,0CAA0C,MAAM;EAC7D,MAAM,UAAU,GAAG,QAAQ,KAAK,iGAAiG,GAAG;EAEpI,MAAM,SAAS,SAAS,cAAc,QAAQ;EAC9C,OAAO,MAAM,UAAU,GAAG,QAAQ,KAAK,4DAA4D,YAAY;EAI/G,OAAO,iBAAiB,YAAW,MAAK;GACtC,EAAE,gBAAgB;EACpB,CAAC;EAED,OAAO,iBAAiB;GACtB,OAAO,OAAO;GACd,QAAQ,IAAI;EACd;EAEA,MAAM,OAAO,SAAS,cAAc,MAAM;EAC1C,KAAK,SAAS;EACd,KAAK,MAAM,UAAU,GAAG,MAAM;EAE9B,MAAM,cAAc,SAAS,cAAc,GAAG;EAC9C,YAAY,MAAM,UAAU,GAAG,QAAQ,KAAK;EAC5C,YAAY,OAAO,OAAO;EAE1B,MAAM,gBAAgB,SAAS,cAAc,OAAO;EACpD,cAAc,OAAO;EACrB,cAAc,cAAc;EAC5B,cAAc,eAAe;EAC7B,cAAc,YAAY;EAC1B,cAAc,MAAM,UAAU,GAAG,QAAQ,KAAK,4GAA4G,YAAY,iBAAiB,GAAG;EAE1L,MAAM,YAAY,SAAS,cAAc,KAAK;EAC9C,UAAU,MAAM,UAAU;EAE1B,MAAM,YAAY,SAAS,cAAc,QAAQ;EACjD,UAAU,OAAO;EACjB,UAAU,OAAO,QAAQ;EACzB,UAAU,MAAM,UAAU,UAAU
|
|
1
|
+
{"version":3,"file":"html-dialog-prompt.js","names":[],"sources":["../../../../../../zero-client/src/client/inspector/html-dialog-prompt.ts"],"sourcesContent":["/**\n * Checks if we can create HTML elements and are in a browser document context\n */\nfunction canUseHTMLDialog(): boolean {\n try {\n // Check if we're in a test environment (vitest sets this)\n if (\n typeof globalThis !== 'undefined' &&\n '__vitest_worker__' in globalThis\n ) {\n return false;\n }\n\n return (\n typeof document !== 'undefined' &&\n typeof document.createElement === 'function' &&\n typeof HTMLDialogElement !== 'undefined' &&\n document.body !== null &&\n // Make sure we can actually create a dialog element\n document.createElement('dialog') instanceof HTMLDialogElement\n );\n } catch {\n return false;\n }\n}\n\n/**\n * Creates a password prompt using HTML <dialog> element\n */\nexport function createHTMLPasswordPrompt(\n message: string,\n): Promise<string | null> {\n if (!canUseHTMLDialog()) {\n // Fallback to browser prompt if HTML dialog is not available\n return Promise.resolve(prompt(message));\n }\n\n return new Promise<string | null>(resolve => {\n // Shared CSS constants\n const reset = 'all:revert;';\n const w = 'rgba(255,255,255,';\n const white = w + '1)';\n const whiteTransp = w + '0.4)';\n const r1 = '0.25rem';\n const font = `font-family:system-ui,sans-serif;color:${white};`;\n const btnBase = `${reset}${font}cursor:pointer;font-size:1rem;font-weight:500;border:none;padding:0.4rem 0.75rem;border-radius:${r1};background:`;\n\n const dialog = document.createElement('dialog');\n dialog.style.cssText = `${reset}${font}background:rgba(0,0,0,0.95);padding:2rem;border:1px solid ${whiteTransp};border-radius:0.5rem;`;\n\n // Prevent keydown from escaping the dialog which can be interfered by other\n // listeners (e.g. global hotkeys)\n dialog.addEventListener('keydown', e => {\n e.stopPropagation();\n });\n\n dialog.oncancel = () => {\n dialog.remove();\n resolve(null);\n };\n\n const form = document.createElement('form');\n form.method = 'dialog';\n form.style.cssText = `${reset}margin:0;`;\n\n const messagePara = document.createElement('p');\n messagePara.style.cssText = `${reset}${font}font-size:1.5rem;margin:0 0 1rem 0;`;\n messagePara.append(message);\n\n const passwordInput = document.createElement('input');\n passwordInput.type = 'password';\n passwordInput.placeholder = 'Admin password';\n passwordInput.autocomplete = 'current-password';\n passwordInput.autofocus = true;\n passwordInput.style.cssText = `${reset}${font}font-size:1rem;display:block;margin:0 0 1rem 0;padding:0.5rem;background:rgba(0,0,0,0.5);border:1px solid ${whiteTransp};border-radius:${r1};`;\n\n const buttonDiv = document.createElement('div');\n buttonDiv.style.cssText = reset;\n\n const cancelBtn = document.createElement('button');\n cancelBtn.type = 'reset';\n cancelBtn.append('Cancel');\n cancelBtn.style.cssText = btnBase + w + '0.25);';\n\n const okBtn = document.createElement('button');\n okBtn.type = 'submit';\n okBtn.value = 'ok';\n okBtn.append('OK');\n okBtn.style.cssText = btnBase + 'rgba(19,106,235,1);margin-right:0.5rem;';\n\n buttonDiv.append(okBtn, cancelBtn);\n form.append(messagePara, passwordInput, buttonDiv);\n dialog.append(form);\n\n form.onreset = () => {\n dialog.close();\n };\n\n dialog.onclose = () => {\n if (dialog.returnValue === 'ok') {\n resolve(passwordInput.value || null);\n } else {\n resolve(null);\n }\n dialog.remove();\n };\n\n document.body.append(dialog);\n dialog.showModal();\n });\n}\n"],"mappings":";;;;AAGA,SAAS,mBAA4B;CACnC,IAAI;EAEF,IACE,OAAO,eAAe,eACtB,uBAAuB,YAEvB,OAAO;EAGT,OACE,OAAO,aAAa,eACpB,OAAO,SAAS,kBAAkB,cAClC,OAAO,sBAAsB,eAC7B,SAAS,SAAS,QAElB,SAAS,cAAc,QAAQ,aAAa;CAEhD,QAAQ;EACN,OAAO;CACT;AACF;;;;AAKA,SAAgB,yBACd,SACwB;CACxB,IAAI,CAAC,iBAAiB,GAEpB,OAAO,QAAQ,QAAQ,OAAO,OAAO,CAAC;CAGxC,OAAO,IAAI,SAAuB,YAAW;EAE3C,MAAM,QAAQ;EACd,MAAM,IAAI;EACV,MAAM,QAAQ,IAAI;EAClB,MAAM,cAAc,IAAI;EACxB,MAAM,KAAK;EACX,MAAM,OAAO,0CAA0C,MAAM;EAC7D,MAAM,UAAU,GAAG,QAAQ,KAAK,iGAAiG,GAAG;EAEpI,MAAM,SAAS,SAAS,cAAc,QAAQ;EAC9C,OAAO,MAAM,UAAU,GAAG,QAAQ,KAAK,4DAA4D,YAAY;EAI/G,OAAO,iBAAiB,YAAW,MAAK;GACtC,EAAE,gBAAgB;EACpB,CAAC;EAED,OAAO,iBAAiB;GACtB,OAAO,OAAO;GACd,QAAQ,IAAI;EACd;EAEA,MAAM,OAAO,SAAS,cAAc,MAAM;EAC1C,KAAK,SAAS;EACd,KAAK,MAAM,UAAU,GAAG,MAAM;EAE9B,MAAM,cAAc,SAAS,cAAc,GAAG;EAC9C,YAAY,MAAM,UAAU,GAAG,QAAQ,KAAK;EAC5C,YAAY,OAAO,OAAO;EAE1B,MAAM,gBAAgB,SAAS,cAAc,OAAO;EACpD,cAAc,OAAO;EACrB,cAAc,cAAc;EAC5B,cAAc,eAAe;EAC7B,cAAc,YAAY;EAC1B,cAAc,MAAM,UAAU,GAAG,QAAQ,KAAK,4GAA4G,YAAY,iBAAiB,GAAG;EAE1L,MAAM,YAAY,SAAS,cAAc,KAAK;EAC9C,UAAU,MAAM,UAAU;EAE1B,MAAM,YAAY,SAAS,cAAc,QAAQ;EACjD,UAAU,OAAO;EACjB,UAAU,OAAO,QAAQ;EACzB,UAAU,MAAM,UAAU,UAAU;EAEpC,MAAM,QAAQ,SAAS,cAAc,QAAQ;EAC7C,MAAM,OAAO;EACb,MAAM,QAAQ;EACd,MAAM,OAAO,IAAI;EACjB,MAAM,MAAM,UAAU,UAAU;EAEhC,UAAU,OAAO,OAAO,SAAS;EACjC,KAAK,OAAO,aAAa,eAAe,SAAS;EACjD,OAAO,OAAO,IAAI;EAElB,KAAK,gBAAgB;GACnB,OAAO,MAAM;EACf;EAEA,OAAO,gBAAgB;GACrB,IAAI,OAAO,gBAAgB,MACzB,QAAQ,cAAc,SAAS,IAAI;QAEnC,QAAQ,IAAI;GAEd,OAAO,OAAO;EAChB;EAEA,SAAS,KAAK,OAAO,MAAM;EAC3B,OAAO,UAAU;CACnB,CAAC;AACH"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"inspector.js","names":[
|
|
1
|
+
{"version":3,"file":"inspector.js","names":[],"sources":["../../../../../../zero-client/src/client/inspector/inspector.ts"],"sourcesContent":["import type {ReadonlyJSONValue} from '../../../../shared/src/json.ts';\nimport type {\n AnalyzeQueryResult,\n PlanDebugEventJSON,\n} from '../../../../zero-protocol/src/analyze-query-result.ts';\nimport type {AST} from '../../../../zero-protocol/src/ast.ts';\nimport type {AnalyzeQueryOptions} from '../../../../zero-protocol/src/inspect-up.ts';\nimport {formatPlannerEvents} from '../../../../zql/src/planner/planner-debug.ts';\nimport type {QueryDelegate} from '../../../../zql/src/query/query-delegate.ts';\nimport type {AnyQuery} from '../../../../zql/src/query/query.ts';\nimport type {ClientGroup} from './client-group.ts';\nimport {Client} from './client.ts';\nimport type {\n ExtendedInspectorDelegate,\n InspectorDelegate,\n Metrics,\n QueryClientMetrics,\n Rep,\n} from './lazy-inspector.ts';\n\nexport type {InspectorDelegate};\n\n// oxlint-disable-next-line consistent-type-imports\nexport type Lazy = typeof import('./lazy-inspector.ts');\n\nexport class Inspector {\n readonly #delegate: ExtendedInspectorDelegate;\n readonly #deletedQueries = new Map<\n string,\n {readonly ast: AST; readonly metrics: QueryClientMetrics}\n >();\n readonly client: Client;\n readonly clientGroup: ClientGroup;\n\n constructor(\n rep: Rep,\n inspectorDelegate: InspectorDelegate,\n queryDelegate: QueryDelegate,\n getSocket: () => Promise<WebSocket>,\n ) {\n const deletedQueries = this.#deletedQueries;\n inspectorDelegate.setQueryEvictedCallback((hash, ast, metrics) => {\n deletedQueries.set(hash, {ast, metrics});\n });\n this.#delegate = {\n getQueryMetrics(hash) {\n return (\n inspectorDelegate.getQueryMetrics(hash) ??\n deletedQueries.get(hash)?.metrics\n );\n },\n getAST(queryID) {\n return (\n inspectorDelegate.getAST(queryID) ?? deletedQueries.get(queryID)?.ast\n );\n },\n mapClientASTToServer:\n inspectorDelegate.mapClientASTToServer.bind(inspectorDelegate),\n get metrics() {\n return inspectorDelegate.metrics;\n },\n setQueryEvictedCallback() {},\n queryDelegate,\n rep,\n getSocket,\n lazy: import('./lazy-inspector.ts'),\n };\n\n this.client = new Client(this.#delegate, rep.clientID, rep.clientGroupID);\n this.clientGroup = this.client.clientGroup;\n }\n\n async metrics(): Promise<Metrics> {\n return (await this.#delegate.lazy).inspectorMetrics(this.#delegate);\n }\n\n async clients(): Promise<Client[]> {\n return (await this.#delegate.lazy).inspectorClients(this.#delegate);\n }\n\n async clientsWithQueries(): Promise<Client[]> {\n return (await this.#delegate.lazy).inspectorClientsWithQueries(\n this.#delegate,\n );\n }\n\n async serverVersion(): Promise<string> {\n return (await this.#delegate.lazy).serverVersion(this.#delegate);\n }\n\n async analyzeQuery(\n query: AnyQuery,\n options?: AnalyzeQueryOptions,\n ): Promise<AnalyzeQueryResult> {\n return (await this.#delegate.lazy).analyzeQuery(\n this.#delegate,\n query,\n options,\n );\n }\n\n /**\n * Analyze a query specified by a server-side AST. Unlike {@link analyzeQuery}\n * the AST is sent to the server verbatim with no client-to-server name\n * mapping; callers should provide an AST already in the server shape.\n */\n async analyzeServerAST(\n ast: AST,\n options?: AnalyzeQueryOptions,\n ): Promise<AnalyzeQueryResult> {\n return (await this.#delegate.lazy).analyzeServerAST(\n this.#delegate,\n ast,\n options,\n );\n }\n\n /**\n * Analyze a server-registered named (custom) query. The server resolves\n * the name and args to an AST using its registered custom-query handler.\n */\n async analyzeNamedQuery(\n name: string,\n args: ReadonlyArray<ReadonlyJSONValue>,\n options?: AnalyzeQueryOptions,\n ): Promise<AnalyzeQueryResult> {\n return (await this.#delegate.lazy).analyzeNamedQuery(\n this.#delegate,\n name,\n args,\n options,\n );\n }\n\n /**\n * Authenticate with the server's admin password. Other inspector RPCs\n * (e.g. {@link analyzeQuery}) fall back to an interactive HTML password\n * prompt when authentication is needed, which is unavailable in non-DOM\n * environments. Call this first from Node contexts to establish the\n * session.\n *\n * Returns `true` if the password is accepted (or the server runs in a\n * development mode that bypasses the check), `false` otherwise.\n */\n async authenticate(password: string): Promise<boolean> {\n return (await this.#delegate.lazy).authenticate(this.#delegate, password);\n }\n\n /**\n * Format planner debug events as a human-readable string.\n */\n formatPlannerEvents(events: PlanDebugEventJSON[]): string {\n return formatPlannerEvents(events);\n }\n}\n"],"mappings":";;;AAyBA,IAAa,YAAb,MAAuB;CACrB;CACA,kCAA2B,IAAI,IAG7B;CACF;CACA;CAEA,YACE,KACA,mBACA,eACA,WACA;EACA,MAAM,iBAAiB,KAAK;EAC5B,kBAAkB,yBAAyB,MAAM,KAAK,YAAY;GAChE,eAAe,IAAI,MAAM;IAAC;IAAK;GAAO,CAAC;EACzC,CAAC;EACD,KAAK,YAAY;GACf,gBAAgB,MAAM;IACpB,OACE,kBAAkB,gBAAgB,IAAI,KACtC,eAAe,IAAI,IAAI,CAAC,EAAE;GAE9B;GACA,OAAO,SAAS;IACd,OACE,kBAAkB,OAAO,OAAO,KAAK,eAAe,IAAI,OAAO,CAAC,EAAE;GAEtE;GACA,sBACE,kBAAkB,qBAAqB,KAAK,iBAAiB;GAC/D,IAAI,UAAU;IACZ,OAAO,kBAAkB;GAC3B;GACA,0BAA0B,CAAC;GAC3B;GACA;GACA;GACA,MAAM,OAAO;EACf;EAEA,KAAK,SAAS,IAAI,OAAO,KAAK,WAAW,IAAI,UAAU,IAAI,aAAa;EACxE,KAAK,cAAc,KAAK,OAAO;CACjC;CAEA,MAAM,UAA4B;EAChC,QAAQ,MAAM,KAAK,UAAU,KAAA,CAAM,iBAAiB,KAAK,SAAS;CACpE;CAEA,MAAM,UAA6B;EACjC,QAAQ,MAAM,KAAK,UAAU,KAAA,CAAM,iBAAiB,KAAK,SAAS;CACpE;CAEA,MAAM,qBAAwC;EAC5C,QAAQ,MAAM,KAAK,UAAU,KAAA,CAAM,4BACjC,KAAK,SACP;CACF;CAEA,MAAM,gBAAiC;EACrC,QAAQ,MAAM,KAAK,UAAU,KAAA,CAAM,cAAc,KAAK,SAAS;CACjE;CAEA,MAAM,aACJ,OACA,SAC6B;EAC7B,QAAQ,MAAM,KAAK,UAAU,KAAA,CAAM,aACjC,KAAK,WACL,OACA,OACF;CACF;;;;;;CAOA,MAAM,iBACJ,KACA,SAC6B;EAC7B,QAAQ,MAAM,KAAK,UAAU,KAAA,CAAM,iBACjC,KAAK,WACL,KACA,OACF;CACF;;;;;CAMA,MAAM,kBACJ,MACA,MACA,SAC6B;EAC7B,QAAQ,MAAM,KAAK,UAAU,KAAA,CAAM,kBACjC,KAAK,WACL,MACA,MACA,OACF;CACF;;;;;;;;;;;CAYA,MAAM,aAAa,UAAoC;EACrD,QAAQ,MAAM,KAAK,UAAU,KAAA,CAAM,aAAa,KAAK,WAAW,QAAQ;CAC1E;;;;CAKA,oBAAoB,QAAsC;EACxD,OAAO,oBAAoB,MAAM;CACnC;AACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lazy-inspector.js","names":[],"sources":["../../../../../../zero-client/src/client/inspector/lazy-inspector.ts"],"sourcesContent":["import type {BTreeRead} from '../../../../replicache/src/btree/read.ts';\nimport type {Read} from '../../../../replicache/src/dag/store.ts';\nimport {readFromHash} from '../../../../replicache/src/db/read.ts';\nimport * as FormatVersion from '../../../../replicache/src/format-version-enum.ts';\nimport {getClientGroup} from '../../../../replicache/src/persist/client-groups.ts';\nimport {\n getClient,\n getClients,\n type ClientMap,\n} from '../../../../replicache/src/persist/clients.ts';\nimport type {ReplicacheImpl} from '../../../../replicache/src/replicache-impl.ts';\nimport {withRead} from '../../../../replicache/src/with-transactions.ts';\nimport {assert} from '../../../../shared/src/asserts.ts';\nimport type {ReadonlyJSONValue} from '../../../../shared/src/json.ts';\nimport {TDigest, type ReadonlyTDigest} from '../../../../shared/src/tdigest.ts';\nimport * as valita from '../../../../shared/src/valita.ts';\nimport type {AnalyzeQueryResult} from '../../../../zero-protocol/src/analyze-query-result.ts';\nimport type {AST} from '../../../../zero-protocol/src/ast.ts';\nimport type {Row} from '../../../../zero-protocol/src/data.ts';\nimport {\n inspectAnalyzeQueryDownSchema,\n inspectAuthenticatedDownSchema,\n inspectErrorDownSchema,\n inspectMetricsDownSchema,\n inspectQueriesDownSchema,\n inspectVersionDownSchema,\n type InspectDownBody,\n type InspectQueryRow,\n type QueryServerMetrics as QueryServerMetricsJSON,\n} from '../../../../zero-protocol/src/inspect-down.ts';\nimport type {\n AnalyzeQueryOptions,\n InspectUpBody,\n} from '../../../../zero-protocol/src/inspect-up.ts';\nimport type {\n ClientMetricMap,\n ServerMetricMap,\n} from '../../../../zql/src/query/metrics-delegate.ts';\nimport type {QueryDelegate} from '../../../../zql/src/query/query-delegate.ts';\nimport {asQueryInternals} from '../../../../zql/src/query/query-internals.ts';\nimport type {AnyQuery} from '../../../../zql/src/query/query.ts';\nimport {nanoid} from '../../util/nanoid.ts';\nimport {ENTITIES_KEY_PREFIX} from '../keys.ts';\nimport type {MutatorDefs} from '../replicache-types.ts';\nimport {Client} from './client.ts';\nimport {createHTMLPasswordPrompt} from './html-dialog-prompt.ts';\nimport {type Lazy} from './inspector.ts';\nimport {Query} from './query.ts';\n\nexport type GetWebSocket = () => Promise<WebSocket>;\n\nexport type Metrics = {\n readonly [K in keyof (ClientMetricMap & ServerMetricMap)]: ReadonlyTDigest;\n};\n\ntype DistributiveOmit<T, K extends string> = T extends object\n ? Omit<T, K>\n : never;\n\nexport async function rpc<T extends InspectDownBody>(\n socket: WebSocket,\n arg: DistributiveOmit<InspectUpBody, 'id'>,\n downSchema: valita.Type<T>,\n): Promise<T['value']> {\n try {\n return await rpcNoAuthTry(socket, arg, downSchema);\n } catch (e) {\n if (e instanceof UnauthenticatedError) {\n const password = await createHTMLPasswordPrompt('Enter password:');\n if (password) {\n // Do authenticate rpc\n const authRes = await rpcNoAuthTry(\n socket,\n {op: 'authenticate', value: password},\n inspectAuthenticatedDownSchema,\n );\n if (authRes) {\n // If authentication is successful, retry the original RPC\n return rpcNoAuthTry(socket, arg, downSchema);\n }\n }\n throw new Error('Authentication failed');\n }\n throw e;\n }\n}\n\nfunction rpcNoAuthTry<T extends InspectDownBody>(\n socket: WebSocket,\n arg: DistributiveOmit<InspectUpBody, 'id'>,\n downSchema: valita.Type<T>,\n): Promise<T['value']> {\n return new Promise((resolve, reject) => {\n const id = nanoid();\n const f = (ev: MessageEvent) => {\n if (typeof ev.data !== 'string') {\n // Binary messages (such as poke chunks) are not inspector messages.\n return;\n }\n let msg: unknown;\n try {\n msg = JSON.parse(ev.data);\n } catch {\n return;\n }\n if (!Array.isArray(msg) || msg[0] !== 'inspect') {\n return;\n }\n const body = msg[1];\n if (body.id !== id) {\n return;\n }\n const errorRes = valita.test(body, inspectErrorDownSchema);\n if (errorRes.ok) {\n reject(new Error(errorRes.value.value));\n } else {\n const res = valita.test(body, downSchema);\n if (res.ok) {\n resolve(res.value.value);\n } else {\n // Check if we got un authenticated/false response\n const authRes = valita.test(body, inspectAuthenticatedDownSchema);\n if (authRes.ok) {\n // Handle authenticated response\n assert(\n authRes.value.value === false,\n 'Expected unauthenticated response',\n );\n reject(new UnauthenticatedError());\n } else {\n reject(res.error);\n }\n }\n }\n socket.removeEventListener('message', f);\n };\n socket.addEventListener('message', f);\n socket.send(JSON.stringify(['inspect', {...arg, id}]));\n });\n} // T extends forces T to be resolved\n\nexport function mergeMetrics(\n clientMetrics: QueryClientMetrics | undefined,\n serverMetrics: QueryServerMetricsJSON | null | undefined,\n): ClientMetrics & ServerMetrics {\n const cm = clientMetrics ?? newClientMetrics();\n return {\n ...convertClientMetrics(cm),\n ...(serverMetrics\n ? convertServerMetrics(serverMetrics)\n : newServerMetrics()),\n };\n}\n\nfunction newClientMetrics(): QueryClientMetrics {\n return {\n 'query-materialization-client': undefined,\n 'query-materialization-end-to-end': undefined,\n 'query-update-client': new TDigest(),\n };\n}\n\nfunction convertClientMetrics(metrics: QueryClientMetrics): ClientMetrics {\n const hydrateDigest = new TDigest();\n if (metrics['query-materialization-client'] !== undefined) {\n hydrateDigest.add(metrics['query-materialization-client']);\n }\n const totalDigest = new TDigest();\n if (metrics['query-materialization-end-to-end'] !== undefined) {\n totalDigest.add(metrics['query-materialization-end-to-end']);\n }\n return {\n 'query-materialization-client': hydrateDigest,\n 'query-materialization-end-to-end': totalDigest,\n 'query-update-client': metrics['query-update-client'] as TDigest,\n };\n}\n\nfunction newServerMetrics(): ServerMetrics {\n return {\n 'query-materialization-server': new TDigest(),\n 'query-update-server': new TDigest(),\n };\n}\n\nfunction convertServerMetrics(metrics: QueryServerMetricsJSON): ServerMetrics {\n const hydrateMs = metrics['query-hydration-server-ms'];\n const hydrateDigest = new TDigest();\n if (hydrateMs !== undefined) {\n hydrateDigest.add(hydrateMs);\n }\n return {\n 'query-materialization-server': hydrateDigest,\n 'query-update-server': TDigest.fromJSON(metrics['query-update-server']),\n };\n}\n\nexport async function inspectorMetrics(\n delegate: ExtendedInspectorDelegate,\n): Promise<Metrics> {\n const clientMetrics = delegate.metrics;\n const serverMetricsJSON = await rpc(\n await delegate.getSocket(),\n {op: 'metrics'},\n inspectMetricsDownSchema,\n );\n return {\n ...(clientMetrics ?? newClientMetrics()),\n 'query-materialization-server': TDigest.fromJSON(\n serverMetricsJSON['query-materialization-server'],\n ),\n 'query-update-server': TDigest.fromJSON(\n serverMetricsJSON['query-update-server'],\n ),\n };\n}\n\nexport function inspectorClients(\n delegate: ExtendedInspectorDelegate,\n): Promise<Client[]> {\n return withDagRead(delegate, dagRead => clients(delegate, dagRead));\n}\n\nexport function inspectorClientsWithQueries(\n delegate: ExtendedInspectorDelegate,\n): Promise<Client[]> {\n return withDagRead(delegate, dagRead =>\n clientsWithQueries(delegate, dagRead),\n );\n}\n\nasync function withDagRead<T>(\n delegate: ExtendedInspectorDelegate,\n f: (dagRead: Read) => Promise<T>,\n): Promise<T> {\n const {rep} = delegate;\n await rep.refresh();\n await rep.persist();\n return withRead(rep.perdag, f);\n}\n\nasync function getBTree(dagRead: Read, clientID: string): Promise<BTreeRead> {\n const client = await getClient(clientID, dagRead);\n assert(client, `Client not found: ${clientID}`);\n const {clientGroupID} = client;\n const clientGroup = await getClientGroup(clientGroupID, dagRead);\n assert(clientGroup, `Client group not found: ${clientGroupID}`);\n const dbRead = await readFromHash(\n clientGroup.headHash,\n dagRead,\n FormatVersion.Latest,\n );\n return dbRead.map;\n}\n\n// oxlint-disable-next-line @typescript-eslint/no-explicit-any\ntype MapEntry<T extends ReadonlyMap<any, any>> =\n T extends ReadonlyMap<infer K, infer V> ? readonly [K, V] : never;\n\nasync function clients(\n delegate: ExtendedInspectorDelegate,\n dagRead: Read,\n predicate: (entry: MapEntry<ClientMap>) => boolean = () => true,\n): Promise<Client[]> {\n const clients = await getClients(dagRead);\n return [...clients.entries()]\n .filter(predicate)\n .map(\n ([clientID, {clientGroupID}]) =>\n new Client(delegate, clientID, clientGroupID),\n );\n}\n\nasync function clientsWithQueries(\n delegate: ExtendedInspectorDelegate,\n dagRead: Read,\n predicate: (entry: MapEntry<ClientMap>) => boolean = () => true,\n): Promise<Client[]> {\n const allClients = await clients(delegate, dagRead, predicate);\n const clientsWithQueries: Client[] = [];\n await Promise.all(\n allClients.map(async client => {\n const queries = await client.queries();\n if (queries.length > 0) {\n clientsWithQueries.push(client);\n }\n }),\n );\n return clientsWithQueries;\n}\n\nexport async function clientGroupClients(\n delegate: ExtendedInspectorDelegate,\n clientGroupID: Promise<string> | string,\n): Promise<Client[]> {\n const id = await clientGroupID;\n return withDagRead(delegate, dagRead =>\n clients(delegate, dagRead, ([_, v]) => v.clientGroupID === id),\n );\n}\n\nexport async function clientGroupClientsWithQueries(\n delegate: ExtendedInspectorDelegate,\n clientGroupID: Promise<string> | string,\n): Promise<Client[]> {\n const id = await clientGroupID;\n return withDagRead(delegate, dagRead =>\n clientsWithQueries(delegate, dagRead, ([_, v]) => v.clientGroupID === id),\n );\n}\n\nexport function clientGroupQueries(\n delegate: ExtendedInspectorDelegate,\n): Promise<Query[]> {\n return queries(delegate, {op: 'queries'});\n}\nexport function clientMap(\n delegate: ExtendedInspectorDelegate,\n clientID: string,\n): Promise<Map<string, ReadonlyJSONValue>> {\n return withDagRead(delegate, async dagRead => {\n const tree = await getBTree(dagRead, clientID);\n const map = new Map<string, ReadonlyJSONValue>();\n for await (const [key, value] of tree.scan('', true)) {\n map.set(key, value);\n }\n return map;\n });\n}\n\nexport function clientRows(\n delegate: ExtendedInspectorDelegate,\n clientID: string,\n tableName: string,\n): Promise<Row[]> {\n return withDagRead(delegate, async dagRead => {\n const prefix = ENTITIES_KEY_PREFIX + tableName + '/';\n const tree = await getBTree(dagRead, clientID);\n const rows: Row[] = [];\n for await (const [key, value] of tree.scan(prefix, false)) {\n if (!key.startsWith(prefix)) {\n break;\n }\n rows.push(value as Row);\n }\n return rows;\n });\n}\n\nexport async function serverVersion(\n delegate: ExtendedInspectorDelegate,\n): Promise<string> {\n return rpc(\n await delegate.getSocket(),\n {op: 'version'},\n inspectVersionDownSchema,\n );\n}\n\nexport function clientQueries(\n delegate: ExtendedInspectorDelegate,\n clientID: string,\n): Promise<Query[]> {\n return queries(delegate, {op: 'queries', clientID});\n}\n\nasync function queries(\n delegate: ExtendedInspectorDelegate,\n arg: {op: 'queries'; clientID?: string},\n): Promise<Query[]> {\n const rows: InspectQueryRow[] = await rpc(\n await delegate.getSocket(),\n arg,\n inspectQueriesDownSchema,\n );\n const queries = rows.map(row => new Query(row, delegate, delegate.getSocket));\n queries.sort((a, b) => (b.hydrateServer ?? 0) - (a.hydrateServer ?? 0));\n return queries;\n}\n\nexport async function analyzeQuery(\n delegate: ExtendedInspectorDelegate,\n query: AnyQuery,\n options?: AnalyzeQueryOptions,\n): Promise<AnalyzeQueryResult> {\n const qi = asQueryInternals(query);\n const {customQueryID} = qi;\n const queryParameters = customQueryID\n ? {name: customQueryID.name, args: customQueryID.args}\n : {ast: delegate.mapClientASTToServer(qi.ast)};\n\n return rpc(\n await delegate.getSocket(),\n {\n op: 'analyze-query',\n ...queryParameters,\n options,\n },\n inspectAnalyzeQueryDownSchema,\n );\n}\n\nexport async function analyzeServerAST(\n delegate: ExtendedInspectorDelegate,\n ast: AST,\n options?: AnalyzeQueryOptions,\n): Promise<AnalyzeQueryResult> {\n return rpc(\n await delegate.getSocket(),\n {op: 'analyze-query', ast, options},\n inspectAnalyzeQueryDownSchema,\n );\n}\n\nexport async function analyzeNamedQuery(\n delegate: ExtendedInspectorDelegate,\n name: string,\n args: ReadonlyArray<ReadonlyJSONValue>,\n options?: AnalyzeQueryOptions,\n): Promise<AnalyzeQueryResult> {\n return rpc(\n await delegate.getSocket(),\n {op: 'analyze-query', name, args, options},\n inspectAnalyzeQueryDownSchema,\n );\n}\n\n/**\n * Sends an `authenticate` op to the server. Returns `true` if the password\n * is accepted (or the server is in a development mode that bypasses the\n * check). Use this from Node contexts where the default interactive HTML\n * prompt used by other inspector RPCs is not available.\n */\nexport async function authenticate(\n delegate: ExtendedInspectorDelegate,\n password: string,\n): Promise<boolean> {\n return rpc(\n await delegate.getSocket(),\n {op: 'authenticate', value: password},\n inspectAuthenticatedDownSchema,\n );\n}\n\nclass UnauthenticatedError extends Error {}\n\nexport interface InspectorDelegate {\n getQueryMetrics(hash: string): QueryClientMetrics | undefined;\n getAST(queryID: string): AST | undefined;\n readonly metrics: ClientMetrics;\n mapClientASTToServer(ast: AST): AST;\n setQueryEvictedCallback(\n cb: (hash: string, ast: AST, metrics: QueryClientMetrics) => void,\n ): void;\n}\n\nexport interface ExtendedInspectorDelegate extends InspectorDelegate {\n readonly rep: Rep;\n readonly getSocket: () => Promise<WebSocket>;\n readonly queryDelegate: QueryDelegate;\n lazy: Promise<Lazy>;\n}\n\nexport type Rep = ReplicacheImpl<MutatorDefs>;\n\nexport type QueryClientMetrics = {\n readonly 'query-materialization-client': number | undefined;\n readonly 'query-materialization-end-to-end': number | undefined;\n readonly 'query-update-client': ReadonlyTDigest;\n};\n\nexport type ClientMetrics = {\n readonly [K in keyof ClientMetricMap]: ReadonlyTDigest;\n};\n\nexport type ServerMetrics = {\n readonly [K in keyof ServerMetricMap]: ReadonlyTDigest;\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"lazy-inspector.js","names":["valita.test"],"sources":["../../../../../../zero-client/src/client/inspector/lazy-inspector.ts"],"sourcesContent":["import type {BTreeRead} from '../../../../replicache/src/btree/read.ts';\nimport type {Read} from '../../../../replicache/src/dag/store.ts';\nimport {readFromHash} from '../../../../replicache/src/db/read.ts';\nimport * as FormatVersion from '../../../../replicache/src/format-version-enum.ts';\nimport {getClientGroup} from '../../../../replicache/src/persist/client-groups.ts';\nimport {\n getClient,\n getClients,\n type ClientMap,\n} from '../../../../replicache/src/persist/clients.ts';\nimport type {ReplicacheImpl} from '../../../../replicache/src/replicache-impl.ts';\nimport {withRead} from '../../../../replicache/src/with-transactions.ts';\nimport {assert} from '../../../../shared/src/asserts.ts';\nimport type {ReadonlyJSONValue} from '../../../../shared/src/json.ts';\nimport {TDigest, type ReadonlyTDigest} from '../../../../shared/src/tdigest.ts';\nimport * as valita from '../../../../shared/src/valita.ts';\nimport type {AnalyzeQueryResult} from '../../../../zero-protocol/src/analyze-query-result.ts';\nimport type {AST} from '../../../../zero-protocol/src/ast.ts';\nimport type {Row} from '../../../../zero-protocol/src/data.ts';\nimport {\n inspectAnalyzeQueryDownSchema,\n inspectAuthenticatedDownSchema,\n inspectErrorDownSchema,\n inspectMetricsDownSchema,\n inspectQueriesDownSchema,\n inspectVersionDownSchema,\n type InspectDownBody,\n type InspectQueryRow,\n type QueryServerMetrics as QueryServerMetricsJSON,\n} from '../../../../zero-protocol/src/inspect-down.ts';\nimport type {\n AnalyzeQueryOptions,\n InspectUpBody,\n} from '../../../../zero-protocol/src/inspect-up.ts';\nimport type {\n ClientMetricMap,\n ServerMetricMap,\n} from '../../../../zql/src/query/metrics-delegate.ts';\nimport type {QueryDelegate} from '../../../../zql/src/query/query-delegate.ts';\nimport {asQueryInternals} from '../../../../zql/src/query/query-internals.ts';\nimport type {AnyQuery} from '../../../../zql/src/query/query.ts';\nimport {nanoid} from '../../util/nanoid.ts';\nimport {ENTITIES_KEY_PREFIX} from '../keys.ts';\nimport type {MutatorDefs} from '../replicache-types.ts';\nimport {Client} from './client.ts';\nimport {createHTMLPasswordPrompt} from './html-dialog-prompt.ts';\nimport {type Lazy} from './inspector.ts';\nimport {Query} from './query.ts';\n\nexport type GetWebSocket = () => Promise<WebSocket>;\n\nexport type Metrics = {\n readonly [K in keyof (ClientMetricMap & ServerMetricMap)]: ReadonlyTDigest;\n};\n\ntype DistributiveOmit<T, K extends string> = T extends object\n ? Omit<T, K>\n : never;\n\nexport async function rpc<T extends InspectDownBody>(\n socket: WebSocket,\n arg: DistributiveOmit<InspectUpBody, 'id'>,\n downSchema: valita.Type<T>,\n): Promise<T['value']> {\n try {\n return await rpcNoAuthTry(socket, arg, downSchema);\n } catch (e) {\n if (e instanceof UnauthenticatedError) {\n const password = await createHTMLPasswordPrompt('Enter password:');\n if (password) {\n // Do authenticate rpc\n const authRes = await rpcNoAuthTry(\n socket,\n {op: 'authenticate', value: password},\n inspectAuthenticatedDownSchema,\n );\n if (authRes) {\n // If authentication is successful, retry the original RPC\n return rpcNoAuthTry(socket, arg, downSchema);\n }\n }\n throw new Error('Authentication failed');\n }\n throw e;\n }\n}\n\nfunction rpcNoAuthTry<T extends InspectDownBody>(\n socket: WebSocket,\n arg: DistributiveOmit<InspectUpBody, 'id'>,\n downSchema: valita.Type<T>,\n): Promise<T['value']> {\n return new Promise((resolve, reject) => {\n const id = nanoid();\n const f = (ev: MessageEvent) => {\n if (typeof ev.data !== 'string') {\n // Binary messages (such as poke chunks) are not inspector messages.\n return;\n }\n let msg: unknown;\n try {\n msg = JSON.parse(ev.data);\n } catch {\n return;\n }\n if (!Array.isArray(msg) || msg[0] !== 'inspect') {\n return;\n }\n const body = msg[1];\n if (body.id !== id) {\n return;\n }\n const errorRes = valita.test(body, inspectErrorDownSchema);\n if (errorRes.ok) {\n reject(new Error(errorRes.value.value));\n } else {\n const res = valita.test(body, downSchema);\n if (res.ok) {\n resolve(res.value.value);\n } else {\n // Check if we got un authenticated/false response\n const authRes = valita.test(body, inspectAuthenticatedDownSchema);\n if (authRes.ok) {\n // Handle authenticated response\n assert(\n authRes.value.value === false,\n 'Expected unauthenticated response',\n );\n reject(new UnauthenticatedError());\n } else {\n reject(res.error);\n }\n }\n }\n socket.removeEventListener('message', f);\n };\n socket.addEventListener('message', f);\n socket.send(JSON.stringify(['inspect', {...arg, id}]));\n });\n} // T extends forces T to be resolved\n\nexport function mergeMetrics(\n clientMetrics: QueryClientMetrics | undefined,\n serverMetrics: QueryServerMetricsJSON | null | undefined,\n): ClientMetrics & ServerMetrics {\n const cm = clientMetrics ?? newClientMetrics();\n return {\n ...convertClientMetrics(cm),\n ...(serverMetrics\n ? convertServerMetrics(serverMetrics)\n : newServerMetrics()),\n };\n}\n\nfunction newClientMetrics(): QueryClientMetrics {\n return {\n 'query-materialization-client': undefined,\n 'query-materialization-end-to-end': undefined,\n 'query-update-client': new TDigest(),\n };\n}\n\nfunction convertClientMetrics(metrics: QueryClientMetrics): ClientMetrics {\n const hydrateDigest = new TDigest();\n if (metrics['query-materialization-client'] !== undefined) {\n hydrateDigest.add(metrics['query-materialization-client']);\n }\n const totalDigest = new TDigest();\n if (metrics['query-materialization-end-to-end'] !== undefined) {\n totalDigest.add(metrics['query-materialization-end-to-end']);\n }\n return {\n 'query-materialization-client': hydrateDigest,\n 'query-materialization-end-to-end': totalDigest,\n 'query-update-client': metrics['query-update-client'] as TDigest,\n };\n}\n\nfunction newServerMetrics(): ServerMetrics {\n return {\n 'query-materialization-server': new TDigest(),\n 'query-update-server': new TDigest(),\n };\n}\n\nfunction convertServerMetrics(metrics: QueryServerMetricsJSON): ServerMetrics {\n const hydrateMs = metrics['query-hydration-server-ms'];\n const hydrateDigest = new TDigest();\n if (hydrateMs !== undefined) {\n hydrateDigest.add(hydrateMs);\n }\n return {\n 'query-materialization-server': hydrateDigest,\n 'query-update-server': TDigest.fromJSON(metrics['query-update-server']),\n };\n}\n\nexport async function inspectorMetrics(\n delegate: ExtendedInspectorDelegate,\n): Promise<Metrics> {\n const clientMetrics = delegate.metrics;\n const serverMetricsJSON = await rpc(\n await delegate.getSocket(),\n {op: 'metrics'},\n inspectMetricsDownSchema,\n );\n return {\n ...(clientMetrics ?? newClientMetrics()),\n 'query-materialization-server': TDigest.fromJSON(\n serverMetricsJSON['query-materialization-server'],\n ),\n 'query-update-server': TDigest.fromJSON(\n serverMetricsJSON['query-update-server'],\n ),\n };\n}\n\nexport function inspectorClients(\n delegate: ExtendedInspectorDelegate,\n): Promise<Client[]> {\n return withDagRead(delegate, dagRead => clients(delegate, dagRead));\n}\n\nexport function inspectorClientsWithQueries(\n delegate: ExtendedInspectorDelegate,\n): Promise<Client[]> {\n return withDagRead(delegate, dagRead =>\n clientsWithQueries(delegate, dagRead),\n );\n}\n\nasync function withDagRead<T>(\n delegate: ExtendedInspectorDelegate,\n f: (dagRead: Read) => Promise<T>,\n): Promise<T> {\n const {rep} = delegate;\n await rep.refresh();\n await rep.persist();\n return withRead(rep.perdag, f);\n}\n\nasync function getBTree(dagRead: Read, clientID: string): Promise<BTreeRead> {\n const client = await getClient(clientID, dagRead);\n assert(client, `Client not found: ${clientID}`);\n const {clientGroupID} = client;\n const clientGroup = await getClientGroup(clientGroupID, dagRead);\n assert(clientGroup, `Client group not found: ${clientGroupID}`);\n const dbRead = await readFromHash(\n clientGroup.headHash,\n dagRead,\n FormatVersion.Latest,\n );\n return dbRead.map;\n}\n\n// oxlint-disable-next-line @typescript-eslint/no-explicit-any\ntype MapEntry<T extends ReadonlyMap<any, any>> =\n T extends ReadonlyMap<infer K, infer V> ? readonly [K, V] : never;\n\nasync function clients(\n delegate: ExtendedInspectorDelegate,\n dagRead: Read,\n predicate: (entry: MapEntry<ClientMap>) => boolean = () => true,\n): Promise<Client[]> {\n const clients = await getClients(dagRead);\n return [...clients.entries()]\n .filter(predicate)\n .map(\n ([clientID, {clientGroupID}]) =>\n new Client(delegate, clientID, clientGroupID),\n );\n}\n\nasync function clientsWithQueries(\n delegate: ExtendedInspectorDelegate,\n dagRead: Read,\n predicate: (entry: MapEntry<ClientMap>) => boolean = () => true,\n): Promise<Client[]> {\n const allClients = await clients(delegate, dagRead, predicate);\n const clientsWithQueries: Client[] = [];\n await Promise.all(\n allClients.map(async client => {\n const queries = await client.queries();\n if (queries.length > 0) {\n clientsWithQueries.push(client);\n }\n }),\n );\n return clientsWithQueries;\n}\n\nexport async function clientGroupClients(\n delegate: ExtendedInspectorDelegate,\n clientGroupID: Promise<string> | string,\n): Promise<Client[]> {\n const id = await clientGroupID;\n return withDagRead(delegate, dagRead =>\n clients(delegate, dagRead, ([_, v]) => v.clientGroupID === id),\n );\n}\n\nexport async function clientGroupClientsWithQueries(\n delegate: ExtendedInspectorDelegate,\n clientGroupID: Promise<string> | string,\n): Promise<Client[]> {\n const id = await clientGroupID;\n return withDagRead(delegate, dagRead =>\n clientsWithQueries(delegate, dagRead, ([_, v]) => v.clientGroupID === id),\n );\n}\n\nexport function clientGroupQueries(\n delegate: ExtendedInspectorDelegate,\n): Promise<Query[]> {\n return queries(delegate, {op: 'queries'});\n}\nexport function clientMap(\n delegate: ExtendedInspectorDelegate,\n clientID: string,\n): Promise<Map<string, ReadonlyJSONValue>> {\n return withDagRead(delegate, async dagRead => {\n const tree = await getBTree(dagRead, clientID);\n const map = new Map<string, ReadonlyJSONValue>();\n for await (const [key, value] of tree.scan('', true)) {\n map.set(key, value);\n }\n return map;\n });\n}\n\nexport function clientRows(\n delegate: ExtendedInspectorDelegate,\n clientID: string,\n tableName: string,\n): Promise<Row[]> {\n return withDagRead(delegate, async dagRead => {\n const prefix = ENTITIES_KEY_PREFIX + tableName + '/';\n const tree = await getBTree(dagRead, clientID);\n const rows: Row[] = [];\n for await (const [key, value] of tree.scan(prefix, false)) {\n if (!key.startsWith(prefix)) {\n break;\n }\n rows.push(value as Row);\n }\n return rows;\n });\n}\n\nexport async function serverVersion(\n delegate: ExtendedInspectorDelegate,\n): Promise<string> {\n return rpc(\n await delegate.getSocket(),\n {op: 'version'},\n inspectVersionDownSchema,\n );\n}\n\nexport function clientQueries(\n delegate: ExtendedInspectorDelegate,\n clientID: string,\n): Promise<Query[]> {\n return queries(delegate, {op: 'queries', clientID});\n}\n\nasync function queries(\n delegate: ExtendedInspectorDelegate,\n arg: {op: 'queries'; clientID?: string},\n): Promise<Query[]> {\n const rows: InspectQueryRow[] = await rpc(\n await delegate.getSocket(),\n arg,\n inspectQueriesDownSchema,\n );\n const queries = rows.map(row => new Query(row, delegate, delegate.getSocket));\n queries.sort((a, b) => (b.hydrateServer ?? 0) - (a.hydrateServer ?? 0));\n return queries;\n}\n\nexport async function analyzeQuery(\n delegate: ExtendedInspectorDelegate,\n query: AnyQuery,\n options?: AnalyzeQueryOptions,\n): Promise<AnalyzeQueryResult> {\n const qi = asQueryInternals(query);\n const {customQueryID} = qi;\n const queryParameters = customQueryID\n ? {name: customQueryID.name, args: customQueryID.args}\n : {ast: delegate.mapClientASTToServer(qi.ast)};\n\n return rpc(\n await delegate.getSocket(),\n {\n op: 'analyze-query',\n ...queryParameters,\n options,\n },\n inspectAnalyzeQueryDownSchema,\n );\n}\n\nexport async function analyzeServerAST(\n delegate: ExtendedInspectorDelegate,\n ast: AST,\n options?: AnalyzeQueryOptions,\n): Promise<AnalyzeQueryResult> {\n return rpc(\n await delegate.getSocket(),\n {op: 'analyze-query', ast, options},\n inspectAnalyzeQueryDownSchema,\n );\n}\n\nexport async function analyzeNamedQuery(\n delegate: ExtendedInspectorDelegate,\n name: string,\n args: ReadonlyArray<ReadonlyJSONValue>,\n options?: AnalyzeQueryOptions,\n): Promise<AnalyzeQueryResult> {\n return rpc(\n await delegate.getSocket(),\n {op: 'analyze-query', name, args, options},\n inspectAnalyzeQueryDownSchema,\n );\n}\n\n/**\n * Sends an `authenticate` op to the server. Returns `true` if the password\n * is accepted (or the server is in a development mode that bypasses the\n * check). Use this from Node contexts where the default interactive HTML\n * prompt used by other inspector RPCs is not available.\n */\nexport async function authenticate(\n delegate: ExtendedInspectorDelegate,\n password: string,\n): Promise<boolean> {\n return rpc(\n await delegate.getSocket(),\n {op: 'authenticate', value: password},\n inspectAuthenticatedDownSchema,\n );\n}\n\nclass UnauthenticatedError extends Error {}\n\nexport interface InspectorDelegate {\n getQueryMetrics(hash: string): QueryClientMetrics | undefined;\n getAST(queryID: string): AST | undefined;\n readonly metrics: ClientMetrics;\n mapClientASTToServer(ast: AST): AST;\n setQueryEvictedCallback(\n cb: (hash: string, ast: AST, metrics: QueryClientMetrics) => void,\n ): void;\n}\n\nexport interface ExtendedInspectorDelegate extends InspectorDelegate {\n readonly rep: Rep;\n readonly getSocket: () => Promise<WebSocket>;\n readonly queryDelegate: QueryDelegate;\n lazy: Promise<Lazy>;\n}\n\nexport type Rep = ReplicacheImpl<MutatorDefs>;\n\nexport type QueryClientMetrics = {\n readonly 'query-materialization-client': number | undefined;\n readonly 'query-materialization-end-to-end': number | undefined;\n readonly 'query-update-client': ReadonlyTDigest;\n};\n\nexport type ClientMetrics = {\n readonly [K in keyof ClientMetricMap]: ReadonlyTDigest;\n};\n\nexport type ServerMetrics = {\n readonly [K in keyof ServerMetricMap]: ReadonlyTDigest;\n};\n"],"mappings":";;;;;;;;;;;;;;;;AA2DA,eAAsB,IACpB,QACA,KACA,YACqB;CACrB,IAAI;EACF,OAAO,MAAM,aAAa,QAAQ,KAAK,UAAU;CACnD,SAAS,GAAG;EACV,IAAI,aAAa,sBAAsB;GACrC,MAAM,WAAW,MAAM,yBAAyB,iBAAiB;GACjE,IAAI,UAOE;QAAA,MALkB,aACpB,QACA;KAAC,IAAI;KAAgB,OAAO;IAAQ,GACpC,8BACF,GAGE,OAAO,aAAa,QAAQ,KAAK,UAAU;GAAA;GAG/C,MAAM,IAAI,MAAM,uBAAuB;EACzC;EACA,MAAM;CACR;AACF;AAEA,SAAS,aACP,QACA,KACA,YACqB;CACrB,OAAO,IAAI,SAAS,SAAS,WAAW;EACtC,MAAM,KAAK,OAAO;EAClB,MAAM,KAAK,OAAqB;GAC9B,IAAI,OAAO,GAAG,SAAS,UAErB;GAEF,IAAI;GACJ,IAAI;IACF,MAAM,KAAK,MAAM,GAAG,IAAI;GAC1B,QAAQ;IACN;GACF;GACA,IAAI,CAAC,MAAM,QAAQ,GAAG,KAAK,IAAI,OAAO,WACpC;GAEF,MAAM,OAAO,IAAI;GACjB,IAAI,KAAK,OAAO,IACd;GAEF,MAAM,WAAWA,KAAY,MAAM,sBAAsB;GACzD,IAAI,SAAS,IACX,OAAO,IAAI,MAAM,SAAS,MAAM,KAAK,CAAC;QACjC;IACL,MAAM,MAAMA,KAAY,MAAM,UAAU;IACxC,IAAI,IAAI,IACN,QAAQ,IAAI,MAAM,KAAK;SAClB;KAEL,MAAM,UAAUA,KAAY,MAAM,8BAA8B;KAChE,IAAI,QAAQ,IAAI;MAEd,OACE,QAAQ,MAAM,UAAU,OACxB,mCACF;MACA,OAAO,IAAI,qBAAqB,CAAC;KACnC,OACE,OAAO,IAAI,KAAK;IAEpB;GACF;GACA,OAAO,oBAAoB,WAAW,CAAC;EACzC;EACA,OAAO,iBAAiB,WAAW,CAAC;EACpC,OAAO,KAAK,KAAK,UAAU,CAAC,WAAW;GAAC,GAAG;GAAK;EAAE,CAAC,CAAC,CAAC;CACvD,CAAC;AACH;AAEA,SAAgB,aACd,eACA,eAC+B;CAE/B,OAAO;EACL,GAAG,qBAFM,iBAAiB,iBAAiB,CAEjB;EAC1B,GAAI,gBACA,qBAAqB,aAAa,IAClC,iBAAiB;CACvB;AACF;AAEA,SAAS,mBAAuC;CAC9C,OAAO;EACL,gCAAgC,KAAA;EAChC,oCAAoC,KAAA;EACpC,uBAAuB,IAAI,QAAQ;CACrC;AACF;AAEA,SAAS,qBAAqB,SAA4C;CACxE,MAAM,gBAAgB,IAAI,QAAQ;CAClC,IAAI,QAAQ,oCAAoC,KAAA,GAC9C,cAAc,IAAI,QAAQ,+BAA+B;CAE3D,MAAM,cAAc,IAAI,QAAQ;CAChC,IAAI,QAAQ,wCAAwC,KAAA,GAClD,YAAY,IAAI,QAAQ,mCAAmC;CAE7D,OAAO;EACL,gCAAgC;EAChC,oCAAoC;EACpC,uBAAuB,QAAQ;CACjC;AACF;AAEA,SAAS,mBAAkC;CACzC,OAAO;EACL,gCAAgC,IAAI,QAAQ;EAC5C,uBAAuB,IAAI,QAAQ;CACrC;AACF;AAEA,SAAS,qBAAqB,SAAgD;CAC5E,MAAM,YAAY,QAAQ;CAC1B,MAAM,gBAAgB,IAAI,QAAQ;CAClC,IAAI,cAAc,KAAA,GAChB,cAAc,IAAI,SAAS;CAE7B,OAAO;EACL,gCAAgC;EAChC,uBAAuB,QAAQ,SAAS,QAAQ,sBAAsB;CACxE;AACF;AAEA,eAAsB,iBACpB,UACkB;CAClB,MAAM,gBAAgB,SAAS;CAC/B,MAAM,oBAAoB,MAAM,IAC9B,MAAM,SAAS,UAAU,GACzB,EAAC,IAAI,UAAS,GACd,wBACF;CACA,OAAO;EACL,GAAI,iBAAiB,iBAAiB;EACtC,gCAAgC,QAAQ,SACtC,kBAAkB,+BACpB;EACA,uBAAuB,QAAQ,SAC7B,kBAAkB,sBACpB;CACF;AACF;AAEA,SAAgB,iBACd,UACmB;CACnB,OAAO,YAAY,WAAU,YAAW,QAAQ,UAAU,OAAO,CAAC;AACpE;AAEA,SAAgB,4BACd,UACmB;CACnB,OAAO,YAAY,WAAU,YAC3B,mBAAmB,UAAU,OAAO,CACtC;AACF;AAEA,eAAe,YACb,UACA,GACY;CACZ,MAAM,EAAC,QAAO;CACd,MAAM,IAAI,QAAQ;CAClB,MAAM,IAAI,QAAQ;CAClB,OAAO,SAAS,IAAI,QAAQ,CAAC;AAC/B;AAEA,eAAe,SAAS,SAAe,UAAsC;CAC3E,MAAM,SAAS,MAAM,UAAU,UAAU,OAAO;CAChD,OAAO,QAAQ,qBAAqB,UAAU;CAC9C,MAAM,EAAC,kBAAiB;CACxB,MAAM,cAAc,MAAM,eAAe,eAAe,OAAO;CAC/D,OAAO,aAAa,2BAA2B,eAAe;CAM9D,QAAO,MALc,aACnB,YAAY,UACZ,SACA,CACF,EAAA,CACc;AAChB;AAMA,eAAe,QACb,UACA,SACA,kBAA2D,MACxC;CAEnB,OAAO,CAAC,IAAG,MADW,WAAW,OAAO,EAAA,CACrB,QAAQ,CAAC,CAAC,CAC1B,OAAO,SAAS,CAAC,CACjB,KACE,CAAC,UAAU,EAAC,qBACX,IAAI,OAAO,UAAU,UAAU,aAAa,CAChD;AACJ;AAEA,eAAe,mBACb,UACA,SACA,kBAA2D,MACxC;CACnB,MAAM,aAAa,MAAM,QAAQ,UAAU,SAAS,SAAS;CAC7D,MAAM,qBAA+B,CAAC;CACtC,MAAM,QAAQ,IACZ,WAAW,IAAI,OAAM,WAAU;EAE7B,KAAI,MADkB,OAAO,QAAQ,EAAA,CACzB,SAAS,GACnB,mBAAmB,KAAK,MAAM;CAElC,CAAC,CACH;CACA,OAAO;AACT;AAEA,eAAsB,mBACpB,UACA,eACmB;CACnB,MAAM,KAAK,MAAM;CACjB,OAAO,YAAY,WAAU,YAC3B,QAAQ,UAAU,UAAU,CAAC,GAAG,OAAO,EAAE,kBAAkB,EAAE,CAC/D;AACF;AAEA,eAAsB,8BACpB,UACA,eACmB;CACnB,MAAM,KAAK,MAAM;CACjB,OAAO,YAAY,WAAU,YAC3B,mBAAmB,UAAU,UAAU,CAAC,GAAG,OAAO,EAAE,kBAAkB,EAAE,CAC1E;AACF;AAEA,SAAgB,mBACd,UACkB;CAClB,OAAO,QAAQ,UAAU,EAAC,IAAI,UAAS,CAAC;AAC1C;AACA,SAAgB,UACd,UACA,UACyC;CACzC,OAAO,YAAY,UAAU,OAAM,YAAW;EAC5C,MAAM,OAAO,MAAM,SAAS,SAAS,QAAQ;EAC7C,MAAM,sBAAM,IAAI,IAA+B;EAC/C,WAAW,MAAM,CAAC,KAAK,UAAU,KAAK,KAAK,IAAI,IAAI,GACjD,IAAI,IAAI,KAAK,KAAK;EAEpB,OAAO;CACT,CAAC;AACH;AAEA,SAAgB,WACd,UACA,UACA,WACgB;CAChB,OAAO,YAAY,UAAU,OAAM,YAAW;EAC5C,MAAM,SAAA,OAA+B,YAAY;EACjD,MAAM,OAAO,MAAM,SAAS,SAAS,QAAQ;EAC7C,MAAM,OAAc,CAAC;EACrB,WAAW,MAAM,CAAC,KAAK,UAAU,KAAK,KAAK,QAAQ,KAAK,GAAG;GACzD,IAAI,CAAC,IAAI,WAAW,MAAM,GACxB;GAEF,KAAK,KAAK,KAAY;EACxB;EACA,OAAO;CACT,CAAC;AACH;AAEA,eAAsB,cACpB,UACiB;CACjB,OAAO,IACL,MAAM,SAAS,UAAU,GACzB,EAAC,IAAI,UAAS,GACd,wBACF;AACF;AAEA,SAAgB,cACd,UACA,UACkB;CAClB,OAAO,QAAQ,UAAU;EAAC,IAAI;EAAW;CAAQ,CAAC;AACpD;AAEA,eAAe,QACb,UACA,KACkB;CAMlB,MAAM,WAAU,MALsB,IACpC,MAAM,SAAS,UAAU,GACzB,KACA,wBACF,EAAA,CACqB,KAAI,QAAO,IAAI,MAAM,KAAK,UAAU,SAAS,SAAS,CAAC;CAC5E,QAAQ,MAAM,GAAG,OAAO,EAAE,iBAAiB,MAAM,EAAE,iBAAiB,EAAE;CACtE,OAAO;AACT;AAEA,eAAsB,aACpB,UACA,OACA,SAC6B;CAC7B,MAAM,KAAK,iBAAiB,KAAK;CACjC,MAAM,EAAC,kBAAiB;CACxB,MAAM,kBAAkB,gBACpB;EAAC,MAAM,cAAc;EAAM,MAAM,cAAc;CAAI,IACnD,EAAC,KAAK,SAAS,qBAAqB,GAAG,GAAG,EAAC;CAE/C,OAAO,IACL,MAAM,SAAS,UAAU,GACzB;EACE,IAAI;EACJ,GAAG;EACH;CACF,GACA,6BACF;AACF;AAEA,eAAsB,iBACpB,UACA,KACA,SAC6B;CAC7B,OAAO,IACL,MAAM,SAAS,UAAU,GACzB;EAAC,IAAI;EAAiB;EAAK;CAAO,GAClC,6BACF;AACF;AAEA,eAAsB,kBACpB,UACA,MACA,MACA,SAC6B;CAC7B,OAAO,IACL,MAAM,SAAS,UAAU,GACzB;EAAC,IAAI;EAAiB;EAAM;EAAM;CAAO,GACzC,6BACF;AACF;;;;;;;AAQA,eAAsB,aACpB,UACA,UACkB;CAClB,OAAO,IACL,MAAM,SAAS,UAAU,GACzB;EAAC,IAAI;EAAgB,OAAO;CAAQ,GACpC,8BACF;AACF;AAEA,IAAM,uBAAN,cAAmC,MAAM,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query.js","names":[
|
|
1
|
+
{"version":3,"file":"query.js","names":[],"sources":["../../../../../../zero-client/src/client/inspector/query.ts"],"sourcesContent":["import {astToZQL} from '../../../../ast-to-zql/src/ast-to-zql.ts';\nimport type {ReadonlyJSONValue} from '../../../../shared/src/json.ts';\nimport {must} from '../../../../shared/src/must.ts';\nimport type {AnalyzeQueryResult} from '../../../../zero-protocol/src/analyze-query-result.ts';\nimport type {AST} from '../../../../zero-protocol/src/ast.ts';\nimport {\n type InspectQueryRow,\n inspectAnalyzeQueryDownSchema,\n} from '../../../../zero-protocol/src/inspect-down.ts';\nimport type {AnalyzeQueryOptions} from '../../../../zero-protocol/src/inspect-up.ts';\nimport {type TTL, normalizeTTL} from '../../../../zql/src/query/ttl.ts';\nimport {\n type ExtendedInspectorDelegate,\n type GetWebSocket,\n type Metrics,\n mergeMetrics,\n rpc,\n} from './lazy-inspector.ts';\n\nexport class Query {\n readonly #socket: GetWebSocket;\n\n readonly name: string | null;\n readonly args: ReadonlyArray<ReadonlyJSONValue> | null;\n readonly got: boolean;\n readonly ttl: TTL;\n readonly inactivatedAt: Date | null;\n readonly rowCount: number;\n readonly deleted: boolean;\n readonly id: string;\n readonly clientID: string;\n readonly metrics: Metrics | null;\n readonly clientZQL: string | null;\n readonly serverZQL: string | null;\n readonly #serverAST: AST | null;\n\n readonly hydrateClient: number | null;\n readonly hydrateServer: number | null;\n readonly hydrateTotal: number | null;\n\n readonly updateClientP50: number | null;\n readonly updateClientP95: number | null;\n readonly updateServerP50: number | null;\n readonly updateServerP95: number | null;\n\n constructor(\n row: InspectQueryRow,\n delegate: ExtendedInspectorDelegate,\n socket: GetWebSocket,\n ) {\n this.#socket = socket;\n\n const {ast, queryID, inactivatedAt} = row;\n // Use own properties to make this more useful in dev tools. For example, in\n // Chrome dev tools, if you do console.table(queries) you'll see the\n // properties in the table, if these were getters you would not see them in the table.\n this.clientID = row.clientID;\n this.id = queryID;\n this.inactivatedAt =\n inactivatedAt === null ? null : new Date(inactivatedAt);\n this.ttl = normalizeTTL(row.ttl);\n this.name = row.name;\n this.args = row.args;\n this.got = row.got;\n this.rowCount = row.rowCount;\n this.deleted = row.deleted;\n this.#serverAST = ast;\n this.serverZQL = ast ? ast.table + astToZQL(ast) : null;\n const clientAST = delegate.getAST(queryID);\n this.clientZQL = clientAST ? clientAST.table + astToZQL(clientAST) : null;\n\n // Merge client and server metrics\n const clientMetrics = delegate.getQueryMetrics(queryID);\n const serverMetrics = row.metrics;\n\n const merged = mergeMetrics(clientMetrics, serverMetrics);\n this.metrics = merged;\n\n const percentile = (\n name: keyof typeof merged,\n percentile: number,\n ): number | null => {\n if (!merged?.[name]) {\n return null;\n }\n const n = merged[name].quantile(percentile);\n return Number.isNaN(n) ? null : n;\n };\n\n // Hydration times are plain numbers (performance.now()-based durations), so\n // read them directly instead of going through the TDigest percentile path.\n this.hydrateClient =\n clientMetrics?.['query-materialization-client'] ?? null;\n this.hydrateServer = serverMetrics?.['query-hydration-server-ms'] ?? null;\n this.hydrateTotal =\n clientMetrics?.['query-materialization-end-to-end'] ?? null;\n\n // Extract update metrics (P50 and P95) - handle NaN by defaulting to 0\n this.updateClientP50 = percentile('query-update-client', 0.5);\n this.updateClientP95 = percentile('query-update-client', 0.95);\n\n this.updateServerP50 = percentile('query-update-server', 0.5);\n this.updateServerP95 = percentile('query-update-server', 0.95);\n }\n\n async analyze(options?: AnalyzeQueryOptions): Promise<AnalyzeQueryResult> {\n const details =\n this.name && this.args\n ? {\n name: this.name,\n args: this.args,\n }\n : {value: must(this.#serverAST, 'AST is required for unnamed queries')};\n\n return rpc(\n await this.#socket(),\n {\n op: 'analyze-query',\n ...details,\n options,\n },\n inspectAnalyzeQueryDownSchema,\n );\n }\n}\n"],"mappings":";;;;;;AAmBA,IAAa,QAAb,MAAmB;CACjB;CAEA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CAEA;CACA;CACA;CAEA;CACA;CACA;CACA;CAEA,YACE,KACA,UACA,QACA;EACA,KAAK,UAAU;EAEf,MAAM,EAAC,KAAK,SAAS,kBAAiB;EAItC,KAAK,WAAW,IAAI;EACpB,KAAK,KAAK;EACV,KAAK,gBACH,kBAAkB,OAAO,OAAO,IAAI,KAAK,aAAa;EACxD,KAAK,MAAM,aAAa,IAAI,GAAG;EAC/B,KAAK,OAAO,IAAI;EAChB,KAAK,OAAO,IAAI;EAChB,KAAK,MAAM,IAAI;EACf,KAAK,WAAW,IAAI;EACpB,KAAK,UAAU,IAAI;EACnB,KAAK,aAAa;EAClB,KAAK,YAAY,MAAM,IAAI,QAAQ,SAAS,GAAG,IAAI;EACnD,MAAM,YAAY,SAAS,OAAO,OAAO;EACzC,KAAK,YAAY,YAAY,UAAU,QAAQ,SAAS,SAAS,IAAI;EAGrE,MAAM,gBAAgB,SAAS,gBAAgB,OAAO;EACtD,MAAM,gBAAgB,IAAI;EAE1B,MAAM,SAAS,aAAa,eAAe,aAAa;EACxD,KAAK,UAAU;EAEf,MAAM,cACJ,MACA,eACkB;GAClB,IAAI,CAAC,SAAS,OACZ,OAAO;GAET,MAAM,IAAI,OAAO,KAAK,CAAC,SAAS,UAAU;GAC1C,OAAO,OAAO,MAAM,CAAC,IAAI,OAAO;EAClC;EAIA,KAAK,gBACH,gBAAgB,mCAAmC;EACrD,KAAK,gBAAgB,gBAAgB,gCAAgC;EACrE,KAAK,eACH,gBAAgB,uCAAuC;EAGzD,KAAK,kBAAkB,WAAW,uBAAuB,EAAG;EAC5D,KAAK,kBAAkB,WAAW,uBAAuB,GAAI;EAE7D,KAAK,kBAAkB,WAAW,uBAAuB,EAAG;EAC5D,KAAK,kBAAkB,WAAW,uBAAuB,GAAI;CAC/D;CAEA,MAAM,QAAQ,SAA4D;EACxE,MAAM,UACJ,KAAK,QAAQ,KAAK,OACd;GACE,MAAM,KAAK;GACX,MAAM,KAAK;EACb,IACA,EAAC,OAAO,KAAK,KAAK,YAAY,qCAAqC,EAAC;EAE1E,OAAO,IACL,MAAM,KAAK,QAAQ,GACnB;GACE,IAAI;GACJ,GAAG;GACH;EACF,GACA,6BACF;CACF;AACF"}
|
|
@@ -125,9 +125,7 @@ function applyDiffs(diffs, branch) {
|
|
|
125
125
|
source.pushAdds(rows);
|
|
126
126
|
break;
|
|
127
127
|
}
|
|
128
|
-
case "change":
|
|
129
|
-
consume(source.push(makeSourceChangeEdit(diff.newValue, diff.oldValue)));
|
|
130
|
-
break;
|
|
128
|
+
case "change": consume(source.push(makeSourceChangeEdit(diff.newValue, diff.oldValue)));
|
|
131
129
|
}
|
|
132
130
|
}
|
|
133
131
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ivm-branch.js","names":["#sources","#tables","#throwIfInvalid","#advanceError"],"sources":["../../../../../zero-client/src/client/ivm-branch.ts"],"sourcesContent":["import type {\n InternalDiff,\n InternalDiffOperation,\n NoIndexDiff,\n} from '../../../replicache/src/btree/node.ts';\nimport type {LazyStore} from '../../../replicache/src/dag/lazy-store.ts';\nimport {type Read, type Store} from '../../../replicache/src/dag/store.ts';\nimport {readFromHash} from '../../../replicache/src/db/read.ts';\nimport * as FormatVersion from '../../../replicache/src/format-version-enum.ts';\nimport type {Hash} from '../../../replicache/src/hash.ts';\nimport type {ZeroReadOptions} from '../../../replicache/src/replicache-options.ts';\nimport {diffBinarySearch} from '../../../replicache/src/subscriptions.ts';\nimport type {DiffsMap} from '../../../replicache/src/sync/diff.ts';\nimport {diff} from '../../../replicache/src/sync/diff.ts';\nimport {using, withRead} from '../../../replicache/src/with-transactions.ts';\nimport {assert} from '../../../shared/src/asserts.ts';\nimport {wrapIterable} from '../../../shared/src/iterables.ts';\nimport {must} from '../../../shared/src/must.ts';\nimport type {Row} from '../../../zero-protocol/src/data.ts';\nimport type {TableSchema} from '../../../zero-schema/src/table-schema.ts';\nimport {MemorySource} from '../../../zql/src/ivm/memory-source.ts';\nimport {consume} from '../../../zql/src/ivm/stream.ts';\nimport {ENTITIES_KEY_PREFIX, sourceNameFromKey} from './keys.ts';\n\nimport {\n makeSourceChangeEdit,\n makeSourceChangeRemove,\n} from '../../../zql/src/ivm/source.ts';\n/**\n * Replicache needs to rebase mutations onto different\n * commits of it's b-tree. These mutations can have reads\n * in them and those reads must be run against the IVM sources.\n *\n * To ensure the reads get the correct state, the IVM\n * sources need to reflect the state of the commit\n * being rebased onto. `IVMSourceBranch` allows us to:\n * 1. fork the IVM sources\n * 2. patch them up to match the desired head\n * 3. run the reads against the forked sources\n *\n * (2) is expected to be a cheap operation as there should only\n * ever be a few outstanding diffs to apply given Zero is meant\n * to be run in a connected state.\n */\nexport class IVMSourceBranch {\n readonly #sources: Map<string, MemorySource | undefined>;\n readonly #tables: Record<string, TableSchema>;\n #advanceError: unknown;\n hash: Hash | undefined;\n\n constructor(\n tables: Record<string, TableSchema>,\n hash?: Hash,\n sources: Map<string, MemorySource | undefined> = new Map(),\n ) {\n this.#tables = tables;\n this.#sources = sources;\n this.hash = hash;\n }\n\n getSource(name: string): MemorySource | undefined {\n this.#throwIfInvalid();\n\n if (this.#sources.has(name)) {\n return this.#sources.get(name);\n }\n\n const schema = this.#tables[name];\n const source = schema\n ? new MemorySource(name, schema.columns, schema.primaryKey)\n : undefined;\n this.#sources.set(name, source);\n return source;\n }\n\n clear() {\n this.#sources.clear();\n }\n\n #throwIfInvalid() {\n if (this.#advanceError) {\n throw this.#advanceError;\n }\n }\n\n /**\n * Mutates the current branch, advancing it to the new head\n * by applying the given diffs.\n */\n advance(expectedHead: Hash | undefined, newHead: Hash, diffs: NoIndexDiff) {\n this.#throwIfInvalid();\n\n assert(\n this.hash === expectedHead,\n () =>\n `Expected head must match the main head. Got: ${this.hash}, expected: ${expectedHead}`,\n );\n\n try {\n applyDiffs(diffs, this);\n this.hash = newHead;\n } catch (e) {\n this.#advanceError = e;\n this.clear();\n throw e;\n }\n }\n\n /**\n * Fork the branch and patch it up to match the desired head.\n */\n async forkToHead(\n store: LazyStore,\n desiredHead: Hash,\n readOptions?: ZeroReadOptions,\n ): Promise<IVMSourceBranch> {\n this.#throwIfInvalid();\n\n const fork = this.fork();\n\n if (fork.hash === desiredHead) {\n return fork;\n }\n\n await patchBranch(desiredHead, store, fork, readOptions);\n fork.hash = desiredHead;\n return fork;\n }\n\n /**\n * Creates a new IVMSourceBranch that is a copy of the current one.\n * This is a cheap operation since the b-trees are shared until a write is performed\n * and then only the modified nodes are copied.\n *\n * IVM branches are forked when we need to rebase mutations.\n * The mutations modify the fork rather than original branch.\n */\n fork() {\n this.#throwIfInvalid();\n\n return new IVMSourceBranch(\n this.#tables,\n this.hash,\n new Map(\n wrapIterable(this.#sources.entries()).map(([name, source]) => [\n name,\n source?.fork(),\n ]),\n ),\n );\n }\n}\n\nexport async function initFromStore(\n branch: IVMSourceBranch,\n hash: Hash,\n store: Store,\n) {\n const diffs: InternalDiffOperation[] = [];\n await withRead(store, async dagRead => {\n const read = await readFromHash(hash, dagRead, FormatVersion.Latest);\n for await (const entry of read.map.scan(ENTITIES_KEY_PREFIX, true)) {\n if (!entry[0].startsWith(ENTITIES_KEY_PREFIX)) {\n break;\n }\n diffs.push({\n op: 'add',\n key: entry[0],\n newValue: entry[1],\n });\n }\n });\n\n branch.advance(undefined, hash, diffs);\n}\n\nasync function patchBranch(\n desiredHead: Hash,\n store: LazyStore,\n fork: IVMSourceBranch,\n readOptions: ZeroReadOptions | undefined,\n) {\n const diffs = await computeDiffs(\n must(fork.hash),\n desiredHead,\n store,\n readOptions,\n );\n if (!diffs) {\n return;\n }\n applyDiffs(diffs, fork);\n}\n\nasync function computeDiffs(\n startHash: Hash,\n endHash: Hash,\n store: LazyStore,\n readOptions: ZeroReadOptions | undefined,\n): Promise<InternalDiff | undefined> {\n const readFn = (dagRead: Read) =>\n diff(\n startHash,\n endHash,\n dagRead,\n {\n shouldComputeDiffs: () => true,\n shouldComputeDiffsForIndex(_name) {\n return false;\n },\n },\n FormatVersion.Latest,\n );\n\n let diffs: DiffsMap;\n if (readOptions?.openLazySourceRead) {\n diffs = await using(store.read(readOptions.openLazySourceRead), readFn);\n } else if (readOptions?.openLazyRead) {\n diffs = await readFn(readOptions.openLazyRead);\n } else {\n diffs = await withRead(store, readFn);\n }\n\n return diffs.get('');\n}\n\nfunction applyDiffs(diffs: NoIndexDiff, branch: IVMSourceBranch) {\n for (\n let i = diffBinarySearch(diffs, ENTITIES_KEY_PREFIX, diff => diff.key);\n i < diffs.length;\n i++\n ) {\n const diff = diffs[i];\n const {key} = diff;\n if (!key.startsWith(ENTITIES_KEY_PREFIX)) {\n break;\n }\n const name = sourceNameFromKey(key);\n const source = must(branch.getSource(name));\n switch (diff.op) {\n case 'del':\n consume(source.push(makeSourceChangeRemove(diff.oldValue as Row)));\n break;\n case 'add': {\n const rows = takeAddsForSource(diffs, i, name);\n i += rows.length - 1;\n source.pushAdds(rows);\n break;\n }\n case 'change':\n consume(\n source.push(\n makeSourceChangeEdit(diff.newValue as Row, diff.oldValue as Row),\n ),\n );\n break;\n }\n }\n}\n\n/**\n * Returns the rows of the run of `add` diffs for the source `name` that starts\n * at `start`. Diffs are ordered by key so a table's rows are contiguous.\n */\nfunction takeAddsForSource(\n diffs: NoIndexDiff,\n start: number,\n name: string,\n): Row[] {\n const prefix = ENTITIES_KEY_PREFIX + name + '/';\n const rows: Row[] = [];\n for (let i = start; i < diffs.length; i++) {\n const diff = diffs[i];\n if (diff.op !== 'add' || !diff.key.startsWith(prefix)) {\n break;\n }\n rows.push(diff.newValue as Row);\n }\n return rows;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ivm-branch.js","names":[],"sources":["../../../../../zero-client/src/client/ivm-branch.ts"],"sourcesContent":["import type {\n InternalDiff,\n InternalDiffOperation,\n NoIndexDiff,\n} from '../../../replicache/src/btree/node.ts';\nimport type {LazyStore} from '../../../replicache/src/dag/lazy-store.ts';\nimport {type Read, type Store} from '../../../replicache/src/dag/store.ts';\nimport {readFromHash} from '../../../replicache/src/db/read.ts';\nimport * as FormatVersion from '../../../replicache/src/format-version-enum.ts';\nimport type {Hash} from '../../../replicache/src/hash.ts';\nimport type {ZeroReadOptions} from '../../../replicache/src/replicache-options.ts';\nimport {diffBinarySearch} from '../../../replicache/src/subscriptions.ts';\nimport type {DiffsMap} from '../../../replicache/src/sync/diff.ts';\nimport {diff} from '../../../replicache/src/sync/diff.ts';\nimport {using, withRead} from '../../../replicache/src/with-transactions.ts';\nimport {assert} from '../../../shared/src/asserts.ts';\nimport {wrapIterable} from '../../../shared/src/iterables.ts';\nimport {must} from '../../../shared/src/must.ts';\nimport type {Row} from '../../../zero-protocol/src/data.ts';\nimport type {TableSchema} from '../../../zero-schema/src/table-schema.ts';\nimport {MemorySource} from '../../../zql/src/ivm/memory-source.ts';\nimport {consume} from '../../../zql/src/ivm/stream.ts';\nimport {ENTITIES_KEY_PREFIX, sourceNameFromKey} from './keys.ts';\n\nimport {\n makeSourceChangeEdit,\n makeSourceChangeRemove,\n} from '../../../zql/src/ivm/source.ts';\n/**\n * Replicache needs to rebase mutations onto different\n * commits of it's b-tree. These mutations can have reads\n * in them and those reads must be run against the IVM sources.\n *\n * To ensure the reads get the correct state, the IVM\n * sources need to reflect the state of the commit\n * being rebased onto. `IVMSourceBranch` allows us to:\n * 1. fork the IVM sources\n * 2. patch them up to match the desired head\n * 3. run the reads against the forked sources\n *\n * (2) is expected to be a cheap operation as there should only\n * ever be a few outstanding diffs to apply given Zero is meant\n * to be run in a connected state.\n */\nexport class IVMSourceBranch {\n readonly #sources: Map<string, MemorySource | undefined>;\n readonly #tables: Record<string, TableSchema>;\n #advanceError: unknown;\n hash: Hash | undefined;\n\n constructor(\n tables: Record<string, TableSchema>,\n hash?: Hash,\n sources: Map<string, MemorySource | undefined> = new Map(),\n ) {\n this.#tables = tables;\n this.#sources = sources;\n this.hash = hash;\n }\n\n getSource(name: string): MemorySource | undefined {\n this.#throwIfInvalid();\n\n if (this.#sources.has(name)) {\n return this.#sources.get(name);\n }\n\n const schema = this.#tables[name];\n const source = schema\n ? new MemorySource(name, schema.columns, schema.primaryKey)\n : undefined;\n this.#sources.set(name, source);\n return source;\n }\n\n clear() {\n this.#sources.clear();\n }\n\n #throwIfInvalid() {\n if (this.#advanceError) {\n throw this.#advanceError;\n }\n }\n\n /**\n * Mutates the current branch, advancing it to the new head\n * by applying the given diffs.\n */\n advance(expectedHead: Hash | undefined, newHead: Hash, diffs: NoIndexDiff) {\n this.#throwIfInvalid();\n\n assert(\n this.hash === expectedHead,\n () =>\n `Expected head must match the main head. Got: ${this.hash}, expected: ${expectedHead}`,\n );\n\n try {\n applyDiffs(diffs, this);\n this.hash = newHead;\n } catch (e) {\n this.#advanceError = e;\n this.clear();\n throw e;\n }\n }\n\n /**\n * Fork the branch and patch it up to match the desired head.\n */\n async forkToHead(\n store: LazyStore,\n desiredHead: Hash,\n readOptions?: ZeroReadOptions,\n ): Promise<IVMSourceBranch> {\n this.#throwIfInvalid();\n\n const fork = this.fork();\n\n if (fork.hash === desiredHead) {\n return fork;\n }\n\n await patchBranch(desiredHead, store, fork, readOptions);\n fork.hash = desiredHead;\n return fork;\n }\n\n /**\n * Creates a new IVMSourceBranch that is a copy of the current one.\n * This is a cheap operation since the b-trees are shared until a write is performed\n * and then only the modified nodes are copied.\n *\n * IVM branches are forked when we need to rebase mutations.\n * The mutations modify the fork rather than original branch.\n */\n fork() {\n this.#throwIfInvalid();\n\n return new IVMSourceBranch(\n this.#tables,\n this.hash,\n new Map(\n wrapIterable(this.#sources.entries()).map(([name, source]) => [\n name,\n source?.fork(),\n ]),\n ),\n );\n }\n}\n\nexport async function initFromStore(\n branch: IVMSourceBranch,\n hash: Hash,\n store: Store,\n) {\n const diffs: InternalDiffOperation[] = [];\n await withRead(store, async dagRead => {\n const read = await readFromHash(hash, dagRead, FormatVersion.Latest);\n for await (const entry of read.map.scan(ENTITIES_KEY_PREFIX, true)) {\n if (!entry[0].startsWith(ENTITIES_KEY_PREFIX)) {\n break;\n }\n diffs.push({\n op: 'add',\n key: entry[0],\n newValue: entry[1],\n });\n }\n });\n\n branch.advance(undefined, hash, diffs);\n}\n\nasync function patchBranch(\n desiredHead: Hash,\n store: LazyStore,\n fork: IVMSourceBranch,\n readOptions: ZeroReadOptions | undefined,\n) {\n const diffs = await computeDiffs(\n must(fork.hash),\n desiredHead,\n store,\n readOptions,\n );\n if (!diffs) {\n return;\n }\n applyDiffs(diffs, fork);\n}\n\nasync function computeDiffs(\n startHash: Hash,\n endHash: Hash,\n store: LazyStore,\n readOptions: ZeroReadOptions | undefined,\n): Promise<InternalDiff | undefined> {\n const readFn = (dagRead: Read) =>\n diff(\n startHash,\n endHash,\n dagRead,\n {\n shouldComputeDiffs: () => true,\n shouldComputeDiffsForIndex(_name) {\n return false;\n },\n },\n FormatVersion.Latest,\n );\n\n let diffs: DiffsMap;\n if (readOptions?.openLazySourceRead) {\n diffs = await using(store.read(readOptions.openLazySourceRead), readFn);\n } else if (readOptions?.openLazyRead) {\n diffs = await readFn(readOptions.openLazyRead);\n } else {\n diffs = await withRead(store, readFn);\n }\n\n return diffs.get('');\n}\n\nfunction applyDiffs(diffs: NoIndexDiff, branch: IVMSourceBranch) {\n for (\n let i = diffBinarySearch(diffs, ENTITIES_KEY_PREFIX, diff => diff.key);\n i < diffs.length;\n i++\n ) {\n const diff = diffs[i];\n const {key} = diff;\n if (!key.startsWith(ENTITIES_KEY_PREFIX)) {\n break;\n }\n const name = sourceNameFromKey(key);\n const source = must(branch.getSource(name));\n switch (diff.op) {\n case 'del':\n consume(source.push(makeSourceChangeRemove(diff.oldValue as Row)));\n break;\n case 'add': {\n const rows = takeAddsForSource(diffs, i, name);\n i += rows.length - 1;\n source.pushAdds(rows);\n break;\n }\n case 'change':\n consume(\n source.push(\n makeSourceChangeEdit(diff.newValue as Row, diff.oldValue as Row),\n ),\n );\n break;\n }\n }\n}\n\n/**\n * Returns the rows of the run of `add` diffs for the source `name` that starts\n * at `start`. Diffs are ordered by key so a table's rows are contiguous.\n */\nfunction takeAddsForSource(\n diffs: NoIndexDiff,\n start: number,\n name: string,\n): Row[] {\n const prefix = ENTITIES_KEY_PREFIX + name + '/';\n const rows: Row[] = [];\n for (let i = start; i < diffs.length; i++) {\n const diff = diffs[i];\n if (diff.op !== 'add' || !diff.key.startsWith(prefix)) {\n break;\n }\n rows.push(diff.newValue as Row);\n }\n return rows;\n}\n"],"mappings":"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"}
|
|
@@ -16,7 +16,8 @@ function toMutationResponseKey(mid) {
|
|
|
16
16
|
function toPrimaryKeyString(tableName, primaryKey, value) {
|
|
17
17
|
if (primaryKey.length === 1) return "e/" + tableName + "/" + parse(value[primaryKey[0]], primaryKeyValueSchema);
|
|
18
18
|
const values = primaryKey.map((k) => parse(value[k], primaryKeyValueSchema));
|
|
19
|
-
const
|
|
19
|
+
const str = JSON.stringify(values);
|
|
20
|
+
const idSegment = u128ToDecimal(h128(str));
|
|
20
21
|
return "e/" + tableName + "/" + idSegment;
|
|
21
22
|
}
|
|
22
23
|
var E19 = 10n ** 19n;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keys.js","names":[],"sources":["../../../../../zero-client/src/client/keys.ts"],"sourcesContent":["import {h128} from '../../../shared/src/hash.ts';\nimport * as v from '../../../shared/src/valita.ts';\nimport type {CompoundKey} from '../../../zero-protocol/src/ast.ts';\nimport type {Row} from '../../../zero-protocol/src/data.ts';\nimport type {MutationID} from '../../../zero-protocol/src/mutation-id.ts';\nimport {primaryKeyValueSchema} from '../../../zero-protocol/src/primary-key.ts';\n\nexport const DESIRED_QUERIES_KEY_PREFIX = 'd/';\nexport const GOT_QUERIES_KEY_PREFIX = 'g/';\nexport const ENTITIES_KEY_PREFIX = 'e/';\nexport const MUTATIONS_KEY_PREFIX = 'm/';\n\nexport function toDesiredQueriesKey(clientID: string, hash: string): string {\n return DESIRED_QUERIES_KEY_PREFIX + clientID + '/' + hash;\n}\n\nexport function desiredQueriesPrefixForClient(clientID: string): string {\n return DESIRED_QUERIES_KEY_PREFIX + clientID + '/';\n}\n\nexport function toGotQueriesKey(hash: string): string {\n return GOT_QUERIES_KEY_PREFIX + hash;\n}\n\nexport function toMutationResponseKey(mid: MutationID): string {\n return MUTATIONS_KEY_PREFIX + mid.clientID + '/' + mid.id;\n}\n\nexport function toPrimaryKeyString(\n tableName: string,\n primaryKey: CompoundKey,\n value: Row,\n): string {\n if (primaryKey.length === 1) {\n return (\n ENTITIES_KEY_PREFIX +\n tableName +\n '/' +\n v.parse(value[primaryKey[0]], primaryKeyValueSchema)\n );\n }\n\n const values = primaryKey.map(k => v.parse(value[k], primaryKeyValueSchema));\n const str = JSON.stringify(values);\n\n const idSegment = u128ToDecimal(h128(str));\n return ENTITIES_KEY_PREFIX + tableName + '/' + idSegment;\n}\n\nconst E19 = 10n ** 19n;\n\n/**\n * `String(x)` for an unsigned 128-bit `x`: the decimal form entity keys have\n * always used for compound primary keys, so it must not change.\n *\n * Chromium 148 (V8 14.8) takes ~4us to stringify a bigint wider than 64 bits\n * in base 10, against ~100ns in node 24, Firefox and WebKit; bigints that fit\n * in 64 bits stay fast everywhere. Splitting `x` into base-10^19 pieces, each\n * under 2^64, keeps every conversion on that fast path: ~35x faster in\n * Chromium and within ~10% elsewhere.\n */\nfunction u128ToDecimal(x: bigint): string {\n if (x < E19) {\n return String(x);\n }\n const t = x / E19;\n const low = String(x % E19).padStart(19, '0');\n if (t < E19) {\n return String(t) + low;\n }\n return String(t / E19) + String(t % E19).padStart(19, '0') + low;\n}\n\nexport function sourceNameFromKey(key: string): string {\n const slash = key.indexOf('/', ENTITIES_KEY_PREFIX.length);\n return key.slice(ENTITIES_KEY_PREFIX.length, slash);\n}\n"],"mappings":";;;AAYA,SAAgB,oBAAoB,UAAkB,MAAsB;CAC1E,OAAA,OAAoC,WAAW,MAAM;AACvD;AAEA,SAAgB,8BAA8B,UAA0B;CACtE,OAAA,OAAoC,WAAW;AACjD;AAEA,SAAgB,gBAAgB,MAAsB;CACpD,OAAA,OAAgC;AAClC;AAEA,SAAgB,sBAAsB,KAAyB;CAC7D,OAAA,OAA8B,IAAI,WAAW,MAAM,IAAI;AACzD;AAEA,SAAgB,mBACd,WACA,YACA,OACQ;CACR,IAAI,WAAW,WAAW,GACxB,OAAA,OAEE,YACA,
|
|
1
|
+
{"version":3,"file":"keys.js","names":["v.parse"],"sources":["../../../../../zero-client/src/client/keys.ts"],"sourcesContent":["import {h128} from '../../../shared/src/hash.ts';\nimport * as v from '../../../shared/src/valita.ts';\nimport type {CompoundKey} from '../../../zero-protocol/src/ast.ts';\nimport type {Row} from '../../../zero-protocol/src/data.ts';\nimport type {MutationID} from '../../../zero-protocol/src/mutation-id.ts';\nimport {primaryKeyValueSchema} from '../../../zero-protocol/src/primary-key.ts';\n\nexport const DESIRED_QUERIES_KEY_PREFIX = 'd/';\nexport const GOT_QUERIES_KEY_PREFIX = 'g/';\nexport const ENTITIES_KEY_PREFIX = 'e/';\nexport const MUTATIONS_KEY_PREFIX = 'm/';\n\nexport function toDesiredQueriesKey(clientID: string, hash: string): string {\n return DESIRED_QUERIES_KEY_PREFIX + clientID + '/' + hash;\n}\n\nexport function desiredQueriesPrefixForClient(clientID: string): string {\n return DESIRED_QUERIES_KEY_PREFIX + clientID + '/';\n}\n\nexport function toGotQueriesKey(hash: string): string {\n return GOT_QUERIES_KEY_PREFIX + hash;\n}\n\nexport function toMutationResponseKey(mid: MutationID): string {\n return MUTATIONS_KEY_PREFIX + mid.clientID + '/' + mid.id;\n}\n\nexport function toPrimaryKeyString(\n tableName: string,\n primaryKey: CompoundKey,\n value: Row,\n): string {\n if (primaryKey.length === 1) {\n return (\n ENTITIES_KEY_PREFIX +\n tableName +\n '/' +\n v.parse(value[primaryKey[0]], primaryKeyValueSchema)\n );\n }\n\n const values = primaryKey.map(k => v.parse(value[k], primaryKeyValueSchema));\n const str = JSON.stringify(values);\n\n const idSegment = u128ToDecimal(h128(str));\n return ENTITIES_KEY_PREFIX + tableName + '/' + idSegment;\n}\n\nconst E19 = 10n ** 19n;\n\n/**\n * `String(x)` for an unsigned 128-bit `x`: the decimal form entity keys have\n * always used for compound primary keys, so it must not change.\n *\n * Chromium 148 (V8 14.8) takes ~4us to stringify a bigint wider than 64 bits\n * in base 10, against ~100ns in node 24, Firefox and WebKit; bigints that fit\n * in 64 bits stay fast everywhere. Splitting `x` into base-10^19 pieces, each\n * under 2^64, keeps every conversion on that fast path: ~35x faster in\n * Chromium and within ~10% elsewhere.\n */\nfunction u128ToDecimal(x: bigint): string {\n if (x < E19) {\n return String(x);\n }\n const t = x / E19;\n const low = String(x % E19).padStart(19, '0');\n if (t < E19) {\n return String(t) + low;\n }\n return String(t / E19) + String(t % E19).padStart(19, '0') + low;\n}\n\nexport function sourceNameFromKey(key: string): string {\n const slash = key.indexOf('/', ENTITIES_KEY_PREFIX.length);\n return key.slice(ENTITIES_KEY_PREFIX.length, slash);\n}\n"],"mappings":";;;AAYA,SAAgB,oBAAoB,UAAkB,MAAsB;CAC1E,OAAA,OAAoC,WAAW,MAAM;AACvD;AAEA,SAAgB,8BAA8B,UAA0B;CACtE,OAAA,OAAoC,WAAW;AACjD;AAEA,SAAgB,gBAAgB,MAAsB;CACpD,OAAA,OAAgC;AAClC;AAEA,SAAgB,sBAAsB,KAAyB;CAC7D,OAAA,OAA8B,IAAI,WAAW,MAAM,IAAI;AACzD;AAEA,SAAgB,mBACd,WACA,YACA,OACQ;CACR,IAAI,WAAW,WAAW,GACxB,OAAA,OAEE,YACA,MACAA,MAAQ,MAAM,WAAW,KAAK,qBAAqB;CAIvD,MAAM,SAAS,WAAW,KAAI,MAAKA,MAAQ,MAAM,IAAI,qBAAqB,CAAC;CAC3E,MAAM,MAAM,KAAK,UAAU,MAAM;CAEjC,MAAM,YAAY,cAAc,KAAK,GAAG,CAAC;CACzC,OAAA,OAA6B,YAAY,MAAM;AACjD;AAEA,IAAM,MAAM,OAAO;;;;;;;;;;;AAYnB,SAAS,cAAc,GAAmB;CACxC,IAAI,IAAI,KACN,OAAO,OAAO,CAAC;CAEjB,MAAM,IAAI,IAAI;CACd,MAAM,MAAM,OAAO,IAAI,GAAG,CAAC,CAAC,SAAS,IAAI,GAAG;CAC5C,IAAI,IAAI,KACN,OAAO,OAAO,CAAC,IAAI;CAErB,OAAO,OAAO,IAAI,GAAG,IAAI,OAAO,IAAI,GAAG,CAAC,CAAC,SAAS,IAAI,GAAG,IAAI;AAC/D;AAEA,SAAgB,kBAAkB,KAAqB;CACrD,MAAM,QAAQ,IAAI,QAAQ,KAAK,CAA0B;CACzD,OAAO,IAAI,MAAM,GAA4B,KAAK;AACpD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"log-options.js","names":[
|
|
1
|
+
{"version":3,"file":"log-options.js","names":[],"sources":["../../../../../zero-client/src/client/log-options.ts"],"sourcesContent":["import {\n TeeLogSink,\n consoleLogSink,\n type Context,\n type LogLevel,\n type LogSink,\n} from '@rocicorp/logger';\nimport {\n DatadogLogSink,\n type DatadogLogSinkOptions,\n} from '../../../datadog/src/datadog-log-sink.ts';\nimport {appendPath, type HTTPString} from './http-string.ts';\nimport {version} from './version.ts';\n\nclass LevelFilterLogSink implements LogSink {\n readonly #wrappedLogSink: LogSink;\n readonly #level: LogLevel;\n\n constructor(wrappedLogSink: LogSink, level: LogLevel) {\n this.#wrappedLogSink = wrappedLogSink;\n this.#level = level;\n }\n\n log(level: LogLevel, context: Context | undefined, ...args: unknown[]): void {\n if (this.#level === 'error' && level !== 'error') {\n return;\n }\n if (this.#level === 'info' && level === 'debug') {\n return;\n }\n this.#wrappedLogSink.log(level, context, ...args);\n }\n\n async flush() {\n await consoleLogSink.flush?.();\n }\n}\n\nconst DATADOG_LOG_LEVEL = 'info';\nconst ZERO_SASS_DOMAIN = '.reflect-server.net';\n\nexport type LogOptions = {\n readonly logLevel: LogLevel;\n readonly logSink: LogSink;\n};\n\nexport function createLogOptions(\n options: {\n consoleLogLevel: LogLevel;\n server: HTTPString | null;\n enableAnalytics: boolean;\n consoleLogSink?: LogSink | undefined;\n },\n createDatadogLogSink: (options: DatadogLogSinkOptions) => LogSink = (\n options: DatadogLogSinkOptions,\n ) => new DatadogLogSink(options),\n): LogOptions {\n const {consoleLogLevel, server, enableAnalytics} = options;\n const userSink = options.consoleLogSink ?? consoleLogSink;\n\n if (!enableAnalytics || server === null) {\n return {\n logLevel: consoleLogLevel,\n logSink: userSink,\n };\n }\n\n const serverURL = new URL(server);\n const {hostname} = serverURL;\n const datadogServiceLabel = hostname.endsWith(ZERO_SASS_DOMAIN)\n ? hostname\n .substring(0, hostname.length - ZERO_SASS_DOMAIN.length)\n .toLowerCase()\n : hostname;\n const baseURL = new URL(appendPath(server, '/logs/v0/log'));\n const logLevel = consoleLogLevel === 'debug' ? 'debug' : 'info';\n const logSink = new TeeLogSink([\n new LevelFilterLogSink(userSink, consoleLogLevel),\n new LevelFilterLogSink(\n createDatadogLogSink({\n service: datadogServiceLabel,\n host: location.host,\n version,\n baseURL,\n }),\n DATADOG_LOG_LEVEL,\n ),\n ]);\n return {\n logLevel,\n logSink,\n };\n}\n"],"mappings":";;;;;AAcA,IAAM,qBAAN,MAA4C;CAC1C;CACA;CAEA,YAAY,gBAAyB,OAAiB;EACpD,KAAK,kBAAkB;EACvB,KAAK,SAAS;CAChB;CAEA,IAAI,OAAiB,SAA8B,GAAG,MAAuB;EAC3E,IAAI,KAAK,WAAW,WAAW,UAAU,SACvC;EAEF,IAAI,KAAK,WAAW,UAAU,UAAU,SACtC;EAEF,KAAK,gBAAgB,IAAI,OAAO,SAAS,GAAG,IAAI;CAClD;CAEA,MAAM,QAAQ;EACZ,MAAM,eAAe,QAAQ;CAC/B;AACF;AAEA,IAAM,oBAAoB;AAC1B,IAAM,mBAAmB;AAOzB,SAAgB,iBACd,SAMA,wBACE,YACG,IAAI,eAAe,OAAO,GACnB;CACZ,MAAM,EAAC,iBAAiB,QAAQ,oBAAmB;CACnD,MAAM,WAAW,QAAQ,kBAAkB;CAE3C,IAAI,CAAC,mBAAmB,WAAW,MACjC,OAAO;EACL,UAAU;EACV,SAAS;CACX;CAIF,MAAM,EAAC,aAAY,IADG,IAAI,MACP;CACnB,MAAM,sBAAsB,SAAS,SAAS,gBAAgB,IAC1D,SACG,UAAU,GAAG,SAAS,SAAS,EAAuB,CAAC,CACvD,YAAY,IACf;CACJ,MAAM,UAAU,IAAI,IAAI,WAAW,QAAQ,cAAc,CAAC;CAc1D,OAAO;EACL,UAde,oBAAoB,UAAU,UAAU;EAevD,SAAA,IAdkB,WAAW,CAC7B,IAAI,mBAAmB,UAAU,eAAe,GAChD,IAAI,mBACF,qBAAqB;GACnB,SAAS;GACT,MAAM,SAAS;GACf;GACA;EACF,CAAC,GACD,iBACF,CACF,CAGE;CACF;AACF"}
|
|
@@ -63,8 +63,10 @@ function makeReplicacheMutators(schema, mutators, context, lc) {
|
|
|
63
63
|
kind: Internal,
|
|
64
64
|
message: "Zero CRUD mutators are not enabled."
|
|
65
65
|
})) };
|
|
66
|
-
if (mutators)
|
|
67
|
-
|
|
66
|
+
if (mutators) {
|
|
67
|
+
if (isMutatorRegistry(mutators)) extendFromMutatorRegistry(lc, context, mutators, schema, replicacheMutators);
|
|
68
|
+
else extendReplicacheMutators(lc, context, mutators, schema, replicacheMutators);
|
|
69
|
+
}
|
|
68
70
|
return replicacheMutators;
|
|
69
71
|
}
|
|
70
72
|
/**
|
|
@@ -87,6 +89,6 @@ function extendFromMutatorRegistry(lc, context, registry, schema, mutateObject)
|
|
|
87
89
|
walk(registry);
|
|
88
90
|
}
|
|
89
91
|
//#endregion
|
|
90
|
-
export { makeReplicacheMutators };
|
|
92
|
+
export { extendReplicacheMutators, makeReplicacheMutators };
|
|
91
93
|
|
|
92
94
|
//# sourceMappingURL=make-replicache-mutators.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"make-replicache-mutators.js","names":[],"sources":["../../../../../zero-client/src/client/make-replicache-mutators.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport type {MutatorDefs} from '../../../replicache/src/types.ts';\nimport type {ReadonlyJSONValue} from '../../../shared/src/json.ts';\nimport {CRUD_MUTATION_NAME} from '../../../zero-protocol/src/mutation.ts';\nimport type {Schema} from '../../../zero-types/src/schema.ts';\nimport {customMutatorKey} from '../../../zql/src/mutate/custom.ts';\nimport {\n isMutatorRegistry,\n type AnyMutatorRegistry,\n} from '../../../zql/src/mutate/mutator-registry.ts';\nimport {isMutator, type Mutator} from '../../../zql/src/mutate/mutator.ts';\nimport {ClientErrorKind} from './client-error-kind.ts';\nimport {makeCRUDMutator, type CRUDMutator} from './crud.ts';\nimport type {CustomMutatorDefs, CustomMutatorImpl} from './custom.ts';\nimport {\n makeReplicacheMutator as makeReplicacheMutatorLegacy,\n TransactionImpl,\n} from './custom.ts';\nimport {ClientError} from './error.ts';\nimport type {WriteTransaction} from './replicache-types.ts';\n\nexport function extendReplicacheMutators<S extends Schema, C>(\n lc: LogContext,\n context: C,\n mutators: AnyMutatorRegistry | CustomMutatorDefs,\n schema: S,\n mutateObject: Record<string, unknown>,\n): void {\n // Recursively process mutator definitions at arbitrary depth\n const processMutators = (mutators: object, path: string[]) => {\n for (const [key, mutator] of Object.entries(mutators)) {\n if (key === '~') {\n // Skip phantom type\n continue;\n }\n\n path.push(key);\n if (isMutator(mutator)) {\n const fullKey = customMutatorKey('.', path);\n mutateObject[fullKey] = makeReplicacheMutator(\n lc,\n mutator,\n schema,\n context,\n );\n } else if (typeof mutator === 'function') {\n const fullKey = customMutatorKey('|', path);\n mutateObject[fullKey] = makeReplicacheMutatorLegacy(\n lc,\n // oxlint-disable-next-line no-explicit-any\n mutator as CustomMutatorImpl<any>,\n schema,\n context,\n );\n } else if (mutator !== null && typeof mutator === 'object') {\n processMutators(mutator, path);\n }\n path.pop();\n }\n };\n\n processMutators(mutators, []);\n}\n\nfunction makeReplicacheMutator<\n TArgs extends ReadonlyJSONValue | undefined,\n TSchema extends Schema,\n TContext,\n TWrappedTransaction,\n>(\n lc: LogContext,\n mutator: Mutator<TArgs, TSchema, TContext, TWrappedTransaction>,\n schema: TSchema,\n context: TContext,\n): (\n repTx: WriteTransaction,\n args: ReadonlyJSONValue,\n) => Promise<ReadonlyJSONValue | void> {\n return async (\n repTx: WriteTransaction,\n args: ReadonlyJSONValue,\n ): Promise<ReadonlyJSONValue | void> => {\n const tx = new TransactionImpl(lc, repTx, schema);\n // fn does input validation internally\n return await mutator.fn({\n args: args as TArgs,\n ctx: context,\n tx: tx,\n });\n };\n}\n\n/**\n * Creates Replicache mutators from mutator definitions.\n *\n * This function processes mutator definitions at arbitrary depth, supporting both\n * new-style mutator definitions and legacy custom mutator implementations. It creates\n * a mutator object with the CRUD mutator and any provided custom mutators, with keys\n * generated based on their path in the mutator definition hierarchy.\n *\n * @template S - The schema type that defines the structure of the data\n * @template C - The type of the context object passed to mutators\n *\n * @param schema - The schema instance used for validation and type checking\n * @param mutators - The mutator definitions to process, can be nested objects or custom mutator definitions\n * @param context - The context to be passed to mutators\n * @param lc - The log context used for logging operations\n *\n * @returns A mutator definitions object containing the CRUD mutator and any custom mutators\n *\n * @remarks\n * - New-style mutator definitions use '.' as a separator in their keys\n * - Legacy custom mutator implementations use '|' as a separator in their keys\n * - The CRUD mutator can be disabled by setting `enableLegacyMutators: false` in the schema\n */\nexport function makeReplicacheMutators<const S extends Schema, C>(\n schema: S,\n mutators: AnyMutatorRegistry | CustomMutatorDefs | undefined,\n context: C,\n lc: LogContext,\n): MutatorDefs & {_zero_crud: CRUDMutator} {\n const {enableLegacyMutators = false} = schema;\n\n const replicacheMutators = {\n [CRUD_MUTATION_NAME]: enableLegacyMutators\n ? makeCRUDMutator(schema)\n : // TODO(arv): This code is unreachable since the public API prevents\n // calling CRUD mutators when enableLegacyMutators is false. Remove this.\n () =>\n Promise.reject(\n new ClientError({\n kind: ClientErrorKind.Internal,\n message: 'Zero CRUD mutators are not enabled.',\n }),\n ),\n };\n\n if (mutators) {\n if (isMutatorRegistry(mutators)) {\n extendFromMutatorRegistry(\n lc,\n context,\n mutators,\n schema,\n replicacheMutators,\n );\n } else {\n extendReplicacheMutators(\n lc,\n context,\n mutators as CustomMutatorDefs,\n schema,\n replicacheMutators,\n );\n }\n }\n\n return replicacheMutators;\n}\n\n/**\n * Extends replicache mutators from a MutatorRegistry.\n * Walks the registry tree and wraps each Mutator.fn for Replicache.\n */\nfunction extendFromMutatorRegistry<S extends Schema, C>(\n lc: LogContext,\n context: C,\n registry: AnyMutatorRegistry,\n schema: S,\n mutateObject: Record<string, unknown>,\n): void {\n const walk = (node: unknown) => {\n if (typeof node !== 'object' || node === null) {\n return;\n }\n for (const value of Object.values(node)) {\n if (isMutator<S>(value)) {\n // Mutator.fn already handles validation internally\n mutateObject[value.mutatorName] = (\n repTx: WriteTransaction,\n args: ReadonlyJSONValue,\n ): Promise<ReadonlyJSONValue | void> => {\n const tx = new TransactionImpl(lc, repTx, schema);\n return value.fn({args, ctx: context, tx});\n };\n } else if (typeof value === 'object' && value !== null) {\n // Nested namespace\n walk(value);\n }\n }\n };\n walk(registry);\n}\n"],"mappings":";;;;;;;;;AAqBA,SAAgB,yBACd,IACA,SACA,UACA,QACA,cACM;CAEN,MAAM,mBAAmB,UAAkB,SAAmB;EAC5D,KAAK,MAAM,CAAC,KAAK,YAAY,OAAO,QAAQ,QAAQ,GAAG;GACrD,IAAI,QAAQ,KAEV;GAGF,KAAK,KAAK,GAAG;GACb,IAAI,UAAU,OAAO,GAAG;IACtB,MAAM,UAAU,iBAAiB,KAAK,IAAI;IAC1C,aAAa,WAAW,sBACtB,IACA,SACA,QACA,OACF;GACF,OAAO,IAAI,OAAO,YAAY,YAAY;IACxC,MAAM,UAAU,iBAAiB,KAAK,IAAI;IAC1C,aAAa,
|
|
1
|
+
{"version":3,"file":"make-replicache-mutators.js","names":["makeReplicacheMutatorLegacy","ClientErrorKind.Internal"],"sources":["../../../../../zero-client/src/client/make-replicache-mutators.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport type {MutatorDefs} from '../../../replicache/src/types.ts';\nimport type {ReadonlyJSONValue} from '../../../shared/src/json.ts';\nimport {CRUD_MUTATION_NAME} from '../../../zero-protocol/src/mutation.ts';\nimport type {Schema} from '../../../zero-types/src/schema.ts';\nimport {customMutatorKey} from '../../../zql/src/mutate/custom.ts';\nimport {\n isMutatorRegistry,\n type AnyMutatorRegistry,\n} from '../../../zql/src/mutate/mutator-registry.ts';\nimport {isMutator, type Mutator} from '../../../zql/src/mutate/mutator.ts';\nimport {ClientErrorKind} from './client-error-kind.ts';\nimport {makeCRUDMutator, type CRUDMutator} from './crud.ts';\nimport type {CustomMutatorDefs, CustomMutatorImpl} from './custom.ts';\nimport {\n makeReplicacheMutator as makeReplicacheMutatorLegacy,\n TransactionImpl,\n} from './custom.ts';\nimport {ClientError} from './error.ts';\nimport type {WriteTransaction} from './replicache-types.ts';\n\nexport function extendReplicacheMutators<S extends Schema, C>(\n lc: LogContext,\n context: C,\n mutators: AnyMutatorRegistry | CustomMutatorDefs,\n schema: S,\n mutateObject: Record<string, unknown>,\n): void {\n // Recursively process mutator definitions at arbitrary depth\n const processMutators = (mutators: object, path: string[]) => {\n for (const [key, mutator] of Object.entries(mutators)) {\n if (key === '~') {\n // Skip phantom type\n continue;\n }\n\n path.push(key);\n if (isMutator(mutator)) {\n const fullKey = customMutatorKey('.', path);\n mutateObject[fullKey] = makeReplicacheMutator(\n lc,\n mutator,\n schema,\n context,\n );\n } else if (typeof mutator === 'function') {\n const fullKey = customMutatorKey('|', path);\n mutateObject[fullKey] = makeReplicacheMutatorLegacy(\n lc,\n // oxlint-disable-next-line no-explicit-any\n mutator as CustomMutatorImpl<any>,\n schema,\n context,\n );\n } else if (mutator !== null && typeof mutator === 'object') {\n processMutators(mutator, path);\n }\n path.pop();\n }\n };\n\n processMutators(mutators, []);\n}\n\nfunction makeReplicacheMutator<\n TArgs extends ReadonlyJSONValue | undefined,\n TSchema extends Schema,\n TContext,\n TWrappedTransaction,\n>(\n lc: LogContext,\n mutator: Mutator<TArgs, TSchema, TContext, TWrappedTransaction>,\n schema: TSchema,\n context: TContext,\n): (\n repTx: WriteTransaction,\n args: ReadonlyJSONValue,\n) => Promise<ReadonlyJSONValue | void> {\n return async (\n repTx: WriteTransaction,\n args: ReadonlyJSONValue,\n ): Promise<ReadonlyJSONValue | void> => {\n const tx = new TransactionImpl(lc, repTx, schema);\n // fn does input validation internally\n return await mutator.fn({\n args: args as TArgs,\n ctx: context,\n tx: tx,\n });\n };\n}\n\n/**\n * Creates Replicache mutators from mutator definitions.\n *\n * This function processes mutator definitions at arbitrary depth, supporting both\n * new-style mutator definitions and legacy custom mutator implementations. It creates\n * a mutator object with the CRUD mutator and any provided custom mutators, with keys\n * generated based on their path in the mutator definition hierarchy.\n *\n * @template S - The schema type that defines the structure of the data\n * @template C - The type of the context object passed to mutators\n *\n * @param schema - The schema instance used for validation and type checking\n * @param mutators - The mutator definitions to process, can be nested objects or custom mutator definitions\n * @param context - The context to be passed to mutators\n * @param lc - The log context used for logging operations\n *\n * @returns A mutator definitions object containing the CRUD mutator and any custom mutators\n *\n * @remarks\n * - New-style mutator definitions use '.' as a separator in their keys\n * - Legacy custom mutator implementations use '|' as a separator in their keys\n * - The CRUD mutator can be disabled by setting `enableLegacyMutators: false` in the schema\n */\nexport function makeReplicacheMutators<const S extends Schema, C>(\n schema: S,\n mutators: AnyMutatorRegistry | CustomMutatorDefs | undefined,\n context: C,\n lc: LogContext,\n): MutatorDefs & {_zero_crud: CRUDMutator} {\n const {enableLegacyMutators = false} = schema;\n\n const replicacheMutators = {\n [CRUD_MUTATION_NAME]: enableLegacyMutators\n ? makeCRUDMutator(schema)\n : // TODO(arv): This code is unreachable since the public API prevents\n // calling CRUD mutators when enableLegacyMutators is false. Remove this.\n () =>\n Promise.reject(\n new ClientError({\n kind: ClientErrorKind.Internal,\n message: 'Zero CRUD mutators are not enabled.',\n }),\n ),\n };\n\n if (mutators) {\n if (isMutatorRegistry(mutators)) {\n extendFromMutatorRegistry(\n lc,\n context,\n mutators,\n schema,\n replicacheMutators,\n );\n } else {\n extendReplicacheMutators(\n lc,\n context,\n mutators as CustomMutatorDefs,\n schema,\n replicacheMutators,\n );\n }\n }\n\n return replicacheMutators;\n}\n\n/**\n * Extends replicache mutators from a MutatorRegistry.\n * Walks the registry tree and wraps each Mutator.fn for Replicache.\n */\nfunction extendFromMutatorRegistry<S extends Schema, C>(\n lc: LogContext,\n context: C,\n registry: AnyMutatorRegistry,\n schema: S,\n mutateObject: Record<string, unknown>,\n): void {\n const walk = (node: unknown) => {\n if (typeof node !== 'object' || node === null) {\n return;\n }\n for (const value of Object.values(node)) {\n if (isMutator<S>(value)) {\n // Mutator.fn already handles validation internally\n mutateObject[value.mutatorName] = (\n repTx: WriteTransaction,\n args: ReadonlyJSONValue,\n ): Promise<ReadonlyJSONValue | void> => {\n const tx = new TransactionImpl(lc, repTx, schema);\n return value.fn({args, ctx: context, tx});\n };\n } else if (typeof value === 'object' && value !== null) {\n // Nested namespace\n walk(value);\n }\n }\n };\n walk(registry);\n}\n"],"mappings":";;;;;;;;;AAqBA,SAAgB,yBACd,IACA,SACA,UACA,QACA,cACM;CAEN,MAAM,mBAAmB,UAAkB,SAAmB;EAC5D,KAAK,MAAM,CAAC,KAAK,YAAY,OAAO,QAAQ,QAAQ,GAAG;GACrD,IAAI,QAAQ,KAEV;GAGF,KAAK,KAAK,GAAG;GACb,IAAI,UAAU,OAAO,GAAG;IACtB,MAAM,UAAU,iBAAiB,KAAK,IAAI;IAC1C,aAAa,WAAW,sBACtB,IACA,SACA,QACA,OACF;GACF,OAAO,IAAI,OAAO,YAAY,YAAY;IACxC,MAAM,UAAU,iBAAiB,KAAK,IAAI;IAC1C,aAAa,WAAWA,wBACtB,IAEA,SACA,QACA,OACF;GACF,OAAO,IAAI,YAAY,QAAQ,OAAO,YAAY,UAChD,gBAAgB,SAAS,IAAI;GAE/B,KAAK,IAAI;EACX;CACF;CAEA,gBAAgB,UAAU,CAAC,CAAC;AAC9B;AAEA,SAAS,sBAMP,IACA,SACA,QACA,SAIqC;CACrC,OAAO,OACL,OACA,SACsC;EACtC,MAAM,KAAK,IAAI,gBAAgB,IAAI,OAAO,MAAM;EAEhD,OAAO,MAAM,QAAQ,GAAG;GAChB;GACN,KAAK;GACD;EACN,CAAC;CACH;AACF;;;;;;;;;;;;;;;;;;;;;;;;AAyBA,SAAgB,uBACd,QACA,UACA,SACA,IACyC;CACzC,MAAM,EAAC,uBAAuB,UAAS;CAEvC,MAAM,qBAAqB,GACxB,qBAAqB,uBAClB,gBAAgB,MAAM,UAIpB,QAAQ,OACN,IAAI,YAAY;EACd,MAAMC;EACN,SAAS;CACX,CAAC,CACH,EACR;CAEA,IAAI,UAAU;EACZ,IAAI,kBAAkB,QAAQ,GAC5B,0BACE,IACA,SACA,UACA,QACA,kBACF;OAEA,yBACE,IACA,SACA,UACA,QACA,kBACF;CAEJ;CAEA,OAAO;AACT;;;;;AAMA,SAAS,0BACP,IACA,SACA,UACA,QACA,cACM;CACN,MAAM,QAAQ,SAAkB;EAC9B,IAAI,OAAO,SAAS,YAAY,SAAS,MACvC;EAEF,KAAK,MAAM,SAAS,OAAO,OAAO,IAAI,GACpC,IAAI,UAAa,KAAK,GAEpB,aAAa,MAAM,gBACjB,OACA,SACsC;GACtC,MAAM,KAAK,IAAI,gBAAgB,IAAI,OAAO,MAAM;GAChD,OAAO,MAAM,GAAG;IAAC;IAAM,KAAK;IAAS;GAAE,CAAC;EAC1C;OACK,IAAI,OAAO,UAAU,YAAY,UAAU,MAEhD,KAAK,KAAK;CAGhB;CACA,KAAK,QAAQ;AACf"}
|
|
@@ -2,7 +2,7 @@ import { AbruptClose, CleanClose, ClientClosed, Hidden, UserDisconnect } from ".
|
|
|
2
2
|
import { isClientError, isServerError } from "./error.js";
|
|
3
3
|
import { LastConnectError, LastConnectErrorV2, NotConnected, TimeToConnectMs, TimeToConnectMsV2, TotalTimeToConnectMs } from "./metric-name-enum.js";
|
|
4
4
|
//#region ../zero-client/src/client/metrics.ts
|
|
5
|
-
var DID_NOT_CONNECT_VALUE =
|
|
5
|
+
var DID_NOT_CONNECT_VALUE = 1e5;
|
|
6
6
|
var REPORT_INTERVAL_MS = 5e3;
|
|
7
7
|
function getLastConnectErrorValue(reason) {
|
|
8
8
|
return `${isServerError(reason) ? "server_" : "client_"}${camelToSnake(reason.kind)}`;
|
|
@@ -80,9 +80,7 @@ var MetricManager = class {
|
|
|
80
80
|
case "error":
|
|
81
81
|
notConnectedReason = "hidden_was_error";
|
|
82
82
|
break;
|
|
83
|
-
default:
|
|
84
|
-
notConnectedReason = "hidden";
|
|
85
|
-
break;
|
|
83
|
+
default: notConnectedReason = "hidden";
|
|
86
84
|
}
|
|
87
85
|
this.#setNotConnectedReason(notConnectedReason);
|
|
88
86
|
}
|
|
@@ -218,6 +216,6 @@ var State = class {
|
|
|
218
216
|
}
|
|
219
217
|
};
|
|
220
218
|
//#endregion
|
|
221
|
-
export { DID_NOT_CONNECT_VALUE, MetricManager, REPORT_INTERVAL_MS, getLastConnectErrorValue, shouldReportConnectError };
|
|
219
|
+
export { DID_NOT_CONNECT_VALUE, Gauge, MetricManager, REPORT_INTERVAL_MS, State, getLastConnectErrorValue, shouldReportConnectError };
|
|
222
220
|
|
|
223
221
|
//# sourceMappingURL=metrics.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metrics.js","names":["#reportIntervalMs","#host","#reporter","#lc","#setNotConnectedReason","#timerID","#register","#notConnected","#timeToConnectMsV2","#lastConnectErrorV2","#totalTimeToConnectMs","#metrics","#name","#value","#prefix","#clearOnFlush","#current"],"sources":["../../../../../zero-client/src/client/metrics.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport type {MaybePromise} from '../../../shared/src/types.ts';\nimport {ClientErrorKind} from './client-error-kind.ts';\nimport {\n isClientError,\n isServerError,\n type ZeroError,\n type ZeroErrorKind,\n} from './error.ts';\nimport {MetricName} from './metric-name.ts';\n\n// This value is used to indicate that the client's last connection attempt\n// failed. We don't make this -1 because we want to stack this never connected\n// state in a graph on top of actual connection times, so it should be greater\n// than any other value.\nexport const DID_NOT_CONNECT_VALUE = 100 * 1000;\n\nexport const REPORT_INTERVAL_MS = 5_000;\n\ntype NotConnectedReason =\n | 'init'\n | 'error'\n | 'hidden'\n | 'hidden_was_init'\n | 'hidden_was_error';\n\nexport function getLastConnectErrorValue(reason: ZeroError) {\n return `${isServerError(reason) ? 'server_' : 'client_'}${camelToSnake(reason.kind)}` as const;\n}\n\nconst upperCasesRegExp = /\\.?(?=[A-Z])/;\n\n// camelToSnake is used to convert a ZeroErrorKind into a suitable\n// metric name, eg AuthInvalidated => auth_invalidated. It converts\n// both PascalCase and camelCase to snake_case.\nfunction camelToSnake(kind: ZeroErrorKind): string {\n return kind.split(upperCasesRegExp).join('_').toLowerCase();\n}\n\n/**\n * Returns whether an error should be reported in metrics and\n * increment the connect error count.\n *\n * Returns `true` for all server errors and client errors that represent actual\n * connection problems. Returns `false` for expected client-side disconnections\n * (user disconnect, client closed, hidden tab, clean/abrupt close).\n */\nexport function shouldReportConnectError(reason: ZeroError): boolean {\n if (!isClientError(reason)) {\n return true;\n }\n switch (reason.kind) {\n case ClientErrorKind.Hidden:\n case ClientErrorKind.ClientClosed:\n case ClientErrorKind.UserDisconnect:\n case ClientErrorKind.CleanClose:\n case ClientErrorKind.AbruptClose:\n return false;\n default:\n return true;\n }\n}\n\ntype MetricsReporter = (metrics: Series[]) => MaybePromise<void>;\n\nexport type MetricManagerOptions = {\n reportIntervalMs: number;\n host: string;\n source: string;\n reporter: MetricsReporter;\n lc: LogContext;\n};\n\n/**\n * MetricManager keeps track of the set of metrics in use and flushes them\n * to a format suitable for reporting.\n */\nexport class MetricManager {\n #reportIntervalMs: number;\n #host: string;\n #reporter: MetricsReporter;\n #lc: LogContext;\n #timerID: ReturnType<typeof setInterval> | null;\n\n constructor(opts: MetricManagerOptions) {\n this.#reportIntervalMs = opts.reportIntervalMs;\n this.#host = opts.host;\n this.#reporter = opts.reporter;\n this.#lc = opts.lc;\n\n this.tags.push(`source:${opts.source}`);\n\n this.timeToConnectMs.set(DID_NOT_CONNECT_VALUE);\n this.#setNotConnectedReason('init');\n\n this.#timerID = setInterval(() => {\n void this.flush();\n }, this.#reportIntervalMs);\n }\n\n #metrics: Flushable[] = [];\n\n // timeToConnectMs measures the time from the call to connect() to receiving\n // the 'connected' ws message. We record the DID_NOT_CONNECT_VALUE if the previous\n // connection attempt failed for any reason.\n //\n // We set the gauge using #connectStart as follows:\n // - #connectStart is undefined if we are disconnected or connected; it is\n // defined only in the Connecting state, as a number representing the timestamp\n // at which we started connecting.\n // - #connectStart is set to the current time when connect() is called.\n // - When we receive the 'connected' message we record the time to connect and\n // set #connectStart to undefined.\n // - If disconnect() is called with a defined #connectStart then we record\n // DID_NOT_CONNECT_VALUE and set #connectStart to undefined.\n //\n // TODO: this should be folded into the ConnectionManager.\n readonly timeToConnectMs = this.#register(\n new Gauge(MetricName.TimeToConnectMs),\n );\n\n // lastConnectError records the last error that occurred when connecting,\n // if any. It is cleared when connecting successfully or when reported, so this\n // state only gets reported if there was a failure during the reporting period and\n // we are still not connected.\n readonly lastConnectError = this.#register(\n new State(\n MetricName.LastConnectError,\n true, // clearOnFlush\n ),\n );\n\n // notConnected records the reason why the client is not currently connected.\n // It is cleared when the client successfully connects.\n readonly #notConnected = this.#register(new State(MetricName.NotConnected));\n\n // The time from the call to connect() to receiving the 'connected' ws message\n // for the current connection. Cleared when the client is not connected.\n // TODO: Not actually currently cleared on disconnect untill there is a\n // connect error, or client reports disconnected and waiting for visible.\n // Should have a value iff _notConnected has no value.\n readonly #timeToConnectMsV2 = this.#register(\n new Gauge(MetricName.TimeToConnectMsV2),\n );\n\n // lastConnectErrorV2 records the last error that occurred when connecting,\n // if any. It is cleared when the client successfully connects or\n // stops trying to connect due to being hidden.\n // Should have a value iff notConnected state is NotConnectedReason.Error.\n readonly #lastConnectErrorV2 = this.#register(\n new State(MetricName.LastConnectErrorV2),\n );\n\n // The total time it took to connect across retries for the current\n // connection. Cleared when the client is not connected.\n // TODO: Not actually currently cleared on disconnect until there is a\n // connect error, or client reports disconnected and waiting for visible.\n // See Zero.#totalToConnectStart for details of how this total is computed.\n // Should have a value iff _notConnected has no value.\n readonly #totalTimeToConnectMs = this.#register(\n new Gauge(MetricName.TotalTimeToConnectMs),\n );\n\n #setNotConnectedReason(reason: NotConnectedReason) {\n this.#notConnected.set(reason);\n }\n\n setConnected(timeToConnectMs: number, totalTimeToConnectMs: number) {\n this.#notConnected.clear();\n this.#lastConnectErrorV2.clear();\n this.#timeToConnectMsV2.set(timeToConnectMs);\n this.#totalTimeToConnectMs.set(totalTimeToConnectMs);\n }\n\n setDisconnectedWaitingForVisible() {\n this.#timeToConnectMsV2.clear();\n this.#totalTimeToConnectMs.clear();\n this.#lastConnectErrorV2.clear();\n let notConnectedReason: NotConnectedReason;\n switch (this.#notConnected.get()) {\n case 'init':\n notConnectedReason = 'hidden_was_init';\n break;\n case 'error':\n notConnectedReason = 'hidden_was_error';\n break;\n default:\n notConnectedReason = 'hidden';\n break;\n }\n this.#setNotConnectedReason(notConnectedReason);\n }\n\n setConnectError(reason: ZeroError) {\n this.#timeToConnectMsV2.clear();\n this.#totalTimeToConnectMs.clear();\n this.#setNotConnectedReason('error');\n this.#lastConnectErrorV2.set(getLastConnectErrorValue(reason));\n }\n\n /**\n * Tags to include in all metrics.\n */\n readonly tags: string[] = [];\n\n // Flushes all metrics to an array of time series (plural), one Series\n // per metric.\n async flush() {\n const lc = this.#lc;\n if (this.#timerID === null) {\n lc.error?.('MetricManager.flush() called but already stopped');\n return;\n }\n const allSeries: Series[] = [];\n for (const metric of this.#metrics) {\n const series = metric.flush();\n if (series !== undefined) {\n allSeries.push({\n ...series,\n host: this.#host,\n tags: this.tags,\n });\n }\n }\n if (allSeries.length === 0) {\n lc?.debug?.('No metrics to report');\n return;\n }\n try {\n await this.#reporter(allSeries);\n } catch (e) {\n lc?.error?.('Error reporting metrics', e);\n }\n }\n\n stop() {\n if (this.#timerID === null) {\n this.#lc.error?.('MetricManager.stop() called but already stopped');\n return;\n }\n clearInterval(this.#timerID);\n this.#timerID = null;\n }\n\n #register<M extends Flushable>(metric: M) {\n this.#metrics.push(metric);\n return metric;\n }\n}\n\n// These two types are influenced by Datadog's API's needs. We could change what\n// we use internally if necessary, but we'd just have to convert to/from before\n// sending to DD. So for convenience we go with their format.\n\n/** Series is a time series of points for a single metric. */\nexport type Series = {\n host: string;\n metric: string; // We call this 'name' bc 'metric' is overloaded in code.\n points: Point[];\n tags?: string[];\n};\n/**\n * A point is a second-resolution timestamp and a set of values for that\n * timestamp. A point represents exactly one second in time and the values\n * are those recorded for that second. The first element of this array\n * is the timestamp and the second element is an array of values.\n */\nexport type Point = [number, number[]];\n\nfunction makePoint(ts: number, value: number): Point {\n return [ts, [value]];\n}\n\ntype Flushable = {\n flush(): Pick<Series, 'metric' | 'points'> | undefined;\n};\n\n/**\n * Gauge is a metric type that represents a single value that can go up and\n * down. It's typically used to track discrete values or counts eg the number\n * of active users, number of connections, cpu load, etc. A gauge retains\n * its value when flushed.\n *\n * We use a Gauge to sample at the client. If we are interested in tracking\n * a metric value *per client*, the client can note the latest value in\n * a Gauge metric. The metric is periodically reported via Reporter. On the\n * server, we graph the value of the metric rolled up over the periodic\n * reporting period, that is, counted over a span of time equal to the\n * reporting period. The result is ~one point per client per reporting\n * period.\n */\nexport class Gauge implements Flushable {\n readonly #name: string;\n #value: number | undefined = undefined;\n\n constructor(name: string) {\n this.#name = name;\n }\n\n set(value: number) {\n this.#value = value;\n }\n\n get() {\n return this.#value;\n }\n\n clear() {\n this.#value = undefined;\n }\n\n flush() {\n if (this.#value === undefined) {\n return undefined;\n }\n // Gauge reports the timestamp at flush time, not at the point the value was\n // recorded.\n const points = [makePoint(t(), this.#value)];\n return {metric: this.#name, points};\n }\n}\n\nfunction t() {\n return Math.round(Date.now() / 1000);\n}\n\n/**\n * State is a metric type that represents a specific state that the system is\n * in, for example the state of a connection which may be 'open' or 'closed'.\n * The state is given a name/prefix at construction time (eg 'connection') and\n * then can be set to a specific state (eg 'open'). The prefix is prepended to\n * the set state (eg, 'connection_open') and a value of 1 is reported.\n * Unset/cleared states are not reported.\n *\n * Example:\n * const s = new State('connection');\n * s.set('open');\n * s.flush(); // returns {metric: 'connection_open', points: [[now(), [1]]]}\n */\nexport class State implements Flushable {\n readonly #prefix: string;\n readonly #clearOnFlush: boolean;\n #current: string | undefined = undefined;\n\n constructor(prefix: string, clearOnFlush = false) {\n this.#prefix = prefix;\n this.#clearOnFlush = clearOnFlush;\n }\n\n set(state: string) {\n this.#current = state;\n }\n\n get() {\n return this.#current;\n }\n\n clear() {\n this.#current = undefined;\n }\n\n flush() {\n if (this.#current === undefined) {\n return undefined;\n }\n const gauge = new Gauge([this.#prefix, this.#current].join('_'));\n gauge.set(1);\n const series = gauge.flush();\n if (this.#clearOnFlush) {\n this.clear();\n }\n return series;\n }\n}\n"],"mappings":";;;;AAeA,IAAa,wBAAwB,MAAM;AAE3C,IAAa,qBAAqB;AASlC,SAAgB,yBAAyB,QAAmB;CAC1D,OAAO,GAAG,cAAc,MAAM,IAAI,YAAY,YAAY,aAAa,OAAO,IAAI;AACpF;AAEA,IAAM,mBAAmB;AAKzB,SAAS,aAAa,MAA6B;CACjD,OAAO,KAAK,MAAM,gBAAgB,EAAE,KAAK,GAAG,EAAE,YAAY;AAC5D;;;;;;;;;AAUA,SAAgB,yBAAyB,QAA4B;CACnE,IAAI,CAAC,cAAc,MAAM,GACvB,OAAO;CAET,QAAQ,OAAO,MAAf;EACE,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK,aACH,OAAO;EACT,SACE,OAAO;CACX;AACF;;;;;AAgBA,IAAa,gBAAb,MAA2B;CACzB;CACA;CACA;CACA;CACA;CAEA,YAAY,MAA4B;EACtC,KAAKA,oBAAoB,KAAK;EAC9B,KAAKC,QAAQ,KAAK;EAClB,KAAKC,YAAY,KAAK;EACtB,KAAKC,MAAM,KAAK;EAEhB,KAAK,KAAK,KAAK,UAAU,KAAK,QAAQ;EAEtC,KAAK,gBAAgB,IAAI,qBAAqB;EAC9C,KAAKC,uBAAuB,MAAM;EAElC,KAAKC,WAAW,kBAAkB;GAChC,KAAU,MAAM;EAClB,GAAG,KAAKL,iBAAiB;CAC3B;CAEA,WAAwB,CAAC;CAiBzB,kBAA2B,KAAKM,UAC9B,IAAI,MAAM,eAA0B,CACtC;CAMA,mBAA4B,KAAKA,UAC/B,IAAI,MACF,kBACA,IACF,CACF;CAIA,gBAAyB,KAAKA,UAAU,IAAI,MAAM,YAAuB,CAAC;CAO1E,qBAA8B,KAAKA,UACjC,IAAI,MAAM,iBAA4B,CACxC;CAMA,sBAA+B,KAAKA,UAClC,IAAI,MAAM,kBAA6B,CACzC;CAQA,wBAAiC,KAAKA,UACpC,IAAI,MAAM,oBAA+B,CAC3C;CAEA,uBAAuB,QAA4B;EACjD,KAAKC,cAAc,IAAI,MAAM;CAC/B;CAEA,aAAa,iBAAyB,sBAA8B;EAClE,KAAKA,cAAc,MAAM;EACzB,KAAKE,oBAAoB,MAAM;EAC/B,KAAKD,mBAAmB,IAAI,eAAe;EAC3C,KAAKE,sBAAsB,IAAI,oBAAoB;CACrD;CAEA,mCAAmC;EACjC,KAAKF,mBAAmB,MAAM;EAC9B,KAAKE,sBAAsB,MAAM;EACjC,KAAKD,oBAAoB,MAAM;EAC/B,IAAI;EACJ,QAAQ,KAAKF,cAAc,IAAI,GAA/B;GACE,KAAK;IACH,qBAAqB;IACrB;GACF,KAAK;IACH,qBAAqB;IACrB;GACF;IACE,qBAAqB;IACrB;EACJ;EACA,KAAKH,uBAAuB,kBAAkB;CAChD;CAEA,gBAAgB,QAAmB;EACjC,KAAKI,mBAAmB,MAAM;EAC9B,KAAKE,sBAAsB,MAAM;EACjC,KAAKN,uBAAuB,OAAO;EACnC,KAAKK,oBAAoB,IAAI,yBAAyB,MAAM,CAAC;CAC/D;;;;CAKA,OAA0B,CAAC;CAI3B,MAAM,QAAQ;EACZ,MAAM,KAAK,KAAKN;EAChB,IAAI,KAAKE,aAAa,MAAM;GAC1B,GAAG,QAAQ,kDAAkD;GAC7D;EACF;EACA,MAAM,YAAsB,CAAC;EAC7B,KAAK,MAAM,UAAU,KAAKM,UAAU;GAClC,MAAM,SAAS,OAAO,MAAM;GAC5B,IAAI,WAAW,KAAA,GACb,UAAU,KAAK;IACb,GAAG;IACH,MAAM,KAAKV;IACX,MAAM,KAAK;GACb,CAAC;EAEL;EACA,IAAI,UAAU,WAAW,GAAG;GAC1B,IAAI,QAAQ,sBAAsB;GAClC;EACF;EACA,IAAI;GACF,MAAM,KAAKC,UAAU,SAAS;EAChC,SAAS,GAAG;GACV,IAAI,QAAQ,2BAA2B,CAAC;EAC1C;CACF;CAEA,OAAO;EACL,IAAI,KAAKG,aAAa,MAAM;GAC1B,KAAKF,IAAI,QAAQ,iDAAiD;GAClE;EACF;EACA,cAAc,KAAKE,QAAQ;EAC3B,KAAKA,WAAW;CAClB;CAEA,UAA+B,QAAW;EACxC,KAAKM,SAAS,KAAK,MAAM;EACzB,OAAO;CACT;AACF;AAqBA,SAAS,UAAU,IAAY,OAAsB;CACnD,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC;AACrB;;;;;;;;;;;;;;;AAoBA,IAAa,QAAb,MAAwC;CACtC;CACA,SAA6B,KAAA;CAE7B,YAAY,MAAc;EACxB,KAAKC,QAAQ;CACf;CAEA,IAAI,OAAe;EACjB,KAAKC,SAAS;CAChB;CAEA,MAAM;EACJ,OAAO,KAAKA;CACd;CAEA,QAAQ;EACN,KAAKA,SAAS,KAAA;CAChB;CAEA,QAAQ;EACN,IAAI,KAAKA,WAAW,KAAA,GAClB;EAIF,MAAM,SAAS,CAAC,UAAU,EAAE,GAAG,KAAKA,MAAM,CAAC;EAC3C,OAAO;GAAC,QAAQ,KAAKD;GAAO;EAAM;CACpC;AACF;AAEA,SAAS,IAAI;CACX,OAAO,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;AACrC;;;;;;;;;;;;;;AAeA,IAAa,QAAb,MAAwC;CACtC;CACA;CACA,WAA+B,KAAA;CAE/B,YAAY,QAAgB,eAAe,OAAO;EAChD,KAAKE,UAAU;EACf,KAAKC,gBAAgB;CACvB;CAEA,IAAI,OAAe;EACjB,KAAKC,WAAW;CAClB;CAEA,MAAM;EACJ,OAAO,KAAKA;CACd;CAEA,QAAQ;EACN,KAAKA,WAAW,KAAA;CAClB;CAEA,QAAQ;EACN,IAAI,KAAKA,aAAa,KAAA,GACpB;EAEF,MAAM,QAAQ,IAAI,MAAM,CAAC,KAAKF,SAAS,KAAKE,QAAQ,EAAE,KAAK,GAAG,CAAC;EAC/D,MAAM,IAAI,CAAC;EACX,MAAM,SAAS,MAAM,MAAM;EAC3B,IAAI,KAAKD,eACP,KAAK,MAAM;EAEb,OAAO;CACT;AACF"}
|
|
1
|
+
{"version":3,"file":"metrics.js","names":["ClientErrorKind.Hidden","ClientErrorKind.ClientClosed","ClientErrorKind.UserDisconnect","ClientErrorKind.CleanClose","ClientErrorKind.AbruptClose","MetricName.TimeToConnectMs","MetricName.LastConnectError","MetricName.NotConnected","MetricName.TimeToConnectMsV2","MetricName.LastConnectErrorV2","MetricName.TotalTimeToConnectMs"],"sources":["../../../../../zero-client/src/client/metrics.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport type {MaybePromise} from '../../../shared/src/types.ts';\nimport {ClientErrorKind} from './client-error-kind.ts';\nimport {\n isClientError,\n isServerError,\n type ZeroError,\n type ZeroErrorKind,\n} from './error.ts';\nimport {MetricName} from './metric-name.ts';\n\n// This value is used to indicate that the client's last connection attempt\n// failed. We don't make this -1 because we want to stack this never connected\n// state in a graph on top of actual connection times, so it should be greater\n// than any other value.\nexport const DID_NOT_CONNECT_VALUE = 100 * 1000;\n\nexport const REPORT_INTERVAL_MS = 5_000;\n\ntype NotConnectedReason =\n | 'init'\n | 'error'\n | 'hidden'\n | 'hidden_was_init'\n | 'hidden_was_error';\n\nexport function getLastConnectErrorValue(reason: ZeroError) {\n return `${isServerError(reason) ? 'server_' : 'client_'}${camelToSnake(reason.kind)}` as const;\n}\n\nconst upperCasesRegExp = /\\.?(?=[A-Z])/;\n\n// camelToSnake is used to convert a ZeroErrorKind into a suitable\n// metric name, eg AuthInvalidated => auth_invalidated. It converts\n// both PascalCase and camelCase to snake_case.\nfunction camelToSnake(kind: ZeroErrorKind): string {\n return kind.split(upperCasesRegExp).join('_').toLowerCase();\n}\n\n/**\n * Returns whether an error should be reported in metrics and\n * increment the connect error count.\n *\n * Returns `true` for all server errors and client errors that represent actual\n * connection problems. Returns `false` for expected client-side disconnections\n * (user disconnect, client closed, hidden tab, clean/abrupt close).\n */\nexport function shouldReportConnectError(reason: ZeroError): boolean {\n if (!isClientError(reason)) {\n return true;\n }\n switch (reason.kind) {\n case ClientErrorKind.Hidden:\n case ClientErrorKind.ClientClosed:\n case ClientErrorKind.UserDisconnect:\n case ClientErrorKind.CleanClose:\n case ClientErrorKind.AbruptClose:\n return false;\n default:\n return true;\n }\n}\n\ntype MetricsReporter = (metrics: Series[]) => MaybePromise<void>;\n\nexport type MetricManagerOptions = {\n reportIntervalMs: number;\n host: string;\n source: string;\n reporter: MetricsReporter;\n lc: LogContext;\n};\n\n/**\n * MetricManager keeps track of the set of metrics in use and flushes them\n * to a format suitable for reporting.\n */\nexport class MetricManager {\n #reportIntervalMs: number;\n #host: string;\n #reporter: MetricsReporter;\n #lc: LogContext;\n #timerID: ReturnType<typeof setInterval> | null;\n\n constructor(opts: MetricManagerOptions) {\n this.#reportIntervalMs = opts.reportIntervalMs;\n this.#host = opts.host;\n this.#reporter = opts.reporter;\n this.#lc = opts.lc;\n\n this.tags.push(`source:${opts.source}`);\n\n this.timeToConnectMs.set(DID_NOT_CONNECT_VALUE);\n this.#setNotConnectedReason('init');\n\n this.#timerID = setInterval(() => {\n void this.flush();\n }, this.#reportIntervalMs);\n }\n\n #metrics: Flushable[] = [];\n\n // timeToConnectMs measures the time from the call to connect() to receiving\n // the 'connected' ws message. We record the DID_NOT_CONNECT_VALUE if the previous\n // connection attempt failed for any reason.\n //\n // We set the gauge using #connectStart as follows:\n // - #connectStart is undefined if we are disconnected or connected; it is\n // defined only in the Connecting state, as a number representing the timestamp\n // at which we started connecting.\n // - #connectStart is set to the current time when connect() is called.\n // - When we receive the 'connected' message we record the time to connect and\n // set #connectStart to undefined.\n // - If disconnect() is called with a defined #connectStart then we record\n // DID_NOT_CONNECT_VALUE and set #connectStart to undefined.\n //\n // TODO: this should be folded into the ConnectionManager.\n readonly timeToConnectMs = this.#register(\n new Gauge(MetricName.TimeToConnectMs),\n );\n\n // lastConnectError records the last error that occurred when connecting,\n // if any. It is cleared when connecting successfully or when reported, so this\n // state only gets reported if there was a failure during the reporting period and\n // we are still not connected.\n readonly lastConnectError = this.#register(\n new State(\n MetricName.LastConnectError,\n true, // clearOnFlush\n ),\n );\n\n // notConnected records the reason why the client is not currently connected.\n // It is cleared when the client successfully connects.\n readonly #notConnected = this.#register(new State(MetricName.NotConnected));\n\n // The time from the call to connect() to receiving the 'connected' ws message\n // for the current connection. Cleared when the client is not connected.\n // TODO: Not actually currently cleared on disconnect untill there is a\n // connect error, or client reports disconnected and waiting for visible.\n // Should have a value iff _notConnected has no value.\n readonly #timeToConnectMsV2 = this.#register(\n new Gauge(MetricName.TimeToConnectMsV2),\n );\n\n // lastConnectErrorV2 records the last error that occurred when connecting,\n // if any. It is cleared when the client successfully connects or\n // stops trying to connect due to being hidden.\n // Should have a value iff notConnected state is NotConnectedReason.Error.\n readonly #lastConnectErrorV2 = this.#register(\n new State(MetricName.LastConnectErrorV2),\n );\n\n // The total time it took to connect across retries for the current\n // connection. Cleared when the client is not connected.\n // TODO: Not actually currently cleared on disconnect until there is a\n // connect error, or client reports disconnected and waiting for visible.\n // See Zero.#totalToConnectStart for details of how this total is computed.\n // Should have a value iff _notConnected has no value.\n readonly #totalTimeToConnectMs = this.#register(\n new Gauge(MetricName.TotalTimeToConnectMs),\n );\n\n #setNotConnectedReason(reason: NotConnectedReason) {\n this.#notConnected.set(reason);\n }\n\n setConnected(timeToConnectMs: number, totalTimeToConnectMs: number) {\n this.#notConnected.clear();\n this.#lastConnectErrorV2.clear();\n this.#timeToConnectMsV2.set(timeToConnectMs);\n this.#totalTimeToConnectMs.set(totalTimeToConnectMs);\n }\n\n setDisconnectedWaitingForVisible() {\n this.#timeToConnectMsV2.clear();\n this.#totalTimeToConnectMs.clear();\n this.#lastConnectErrorV2.clear();\n let notConnectedReason: NotConnectedReason;\n switch (this.#notConnected.get()) {\n case 'init':\n notConnectedReason = 'hidden_was_init';\n break;\n case 'error':\n notConnectedReason = 'hidden_was_error';\n break;\n default:\n notConnectedReason = 'hidden';\n break;\n }\n this.#setNotConnectedReason(notConnectedReason);\n }\n\n setConnectError(reason: ZeroError) {\n this.#timeToConnectMsV2.clear();\n this.#totalTimeToConnectMs.clear();\n this.#setNotConnectedReason('error');\n this.#lastConnectErrorV2.set(getLastConnectErrorValue(reason));\n }\n\n /**\n * Tags to include in all metrics.\n */\n readonly tags: string[] = [];\n\n // Flushes all metrics to an array of time series (plural), one Series\n // per metric.\n async flush() {\n const lc = this.#lc;\n if (this.#timerID === null) {\n lc.error?.('MetricManager.flush() called but already stopped');\n return;\n }\n const allSeries: Series[] = [];\n for (const metric of this.#metrics) {\n const series = metric.flush();\n if (series !== undefined) {\n allSeries.push({\n ...series,\n host: this.#host,\n tags: this.tags,\n });\n }\n }\n if (allSeries.length === 0) {\n lc?.debug?.('No metrics to report');\n return;\n }\n try {\n await this.#reporter(allSeries);\n } catch (e) {\n lc?.error?.('Error reporting metrics', e);\n }\n }\n\n stop() {\n if (this.#timerID === null) {\n this.#lc.error?.('MetricManager.stop() called but already stopped');\n return;\n }\n clearInterval(this.#timerID);\n this.#timerID = null;\n }\n\n #register<M extends Flushable>(metric: M) {\n this.#metrics.push(metric);\n return metric;\n }\n}\n\n// These two types are influenced by Datadog's API's needs. We could change what\n// we use internally if necessary, but we'd just have to convert to/from before\n// sending to DD. So for convenience we go with their format.\n\n/** Series is a time series of points for a single metric. */\nexport type Series = {\n host: string;\n metric: string; // We call this 'name' bc 'metric' is overloaded in code.\n points: Point[];\n tags?: string[];\n};\n/**\n * A point is a second-resolution timestamp and a set of values for that\n * timestamp. A point represents exactly one second in time and the values\n * are those recorded for that second. The first element of this array\n * is the timestamp and the second element is an array of values.\n */\nexport type Point = [number, number[]];\n\nfunction makePoint(ts: number, value: number): Point {\n return [ts, [value]];\n}\n\ntype Flushable = {\n flush(): Pick<Series, 'metric' | 'points'> | undefined;\n};\n\n/**\n * Gauge is a metric type that represents a single value that can go up and\n * down. It's typically used to track discrete values or counts eg the number\n * of active users, number of connections, cpu load, etc. A gauge retains\n * its value when flushed.\n *\n * We use a Gauge to sample at the client. If we are interested in tracking\n * a metric value *per client*, the client can note the latest value in\n * a Gauge metric. The metric is periodically reported via Reporter. On the\n * server, we graph the value of the metric rolled up over the periodic\n * reporting period, that is, counted over a span of time equal to the\n * reporting period. The result is ~one point per client per reporting\n * period.\n */\nexport class Gauge implements Flushable {\n readonly #name: string;\n #value: number | undefined = undefined;\n\n constructor(name: string) {\n this.#name = name;\n }\n\n set(value: number) {\n this.#value = value;\n }\n\n get() {\n return this.#value;\n }\n\n clear() {\n this.#value = undefined;\n }\n\n flush() {\n if (this.#value === undefined) {\n return undefined;\n }\n // Gauge reports the timestamp at flush time, not at the point the value was\n // recorded.\n const points = [makePoint(t(), this.#value)];\n return {metric: this.#name, points};\n }\n}\n\nfunction t() {\n return Math.round(Date.now() / 1000);\n}\n\n/**\n * State is a metric type that represents a specific state that the system is\n * in, for example the state of a connection which may be 'open' or 'closed'.\n * The state is given a name/prefix at construction time (eg 'connection') and\n * then can be set to a specific state (eg 'open'). The prefix is prepended to\n * the set state (eg, 'connection_open') and a value of 1 is reported.\n * Unset/cleared states are not reported.\n *\n * Example:\n * const s = new State('connection');\n * s.set('open');\n * s.flush(); // returns {metric: 'connection_open', points: [[now(), [1]]]}\n */\nexport class State implements Flushable {\n readonly #prefix: string;\n readonly #clearOnFlush: boolean;\n #current: string | undefined = undefined;\n\n constructor(prefix: string, clearOnFlush = false) {\n this.#prefix = prefix;\n this.#clearOnFlush = clearOnFlush;\n }\n\n set(state: string) {\n this.#current = state;\n }\n\n get() {\n return this.#current;\n }\n\n clear() {\n this.#current = undefined;\n }\n\n flush() {\n if (this.#current === undefined) {\n return undefined;\n }\n const gauge = new Gauge([this.#prefix, this.#current].join('_'));\n gauge.set(1);\n const series = gauge.flush();\n if (this.#clearOnFlush) {\n this.clear();\n }\n return series;\n }\n}\n"],"mappings":"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"}
|