@rocicorp/zero 1.2.0 → 1.3.0-canary.1
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/analyze-query/src/bin-analyze.js +25 -25
- package/out/analyze-query/src/bin-analyze.js.map +1 -1
- package/out/ast-to-zql/src/ast-to-zql.d.ts.map +1 -1
- package/out/ast-to-zql/src/ast-to-zql.js +2 -1
- package/out/ast-to-zql/src/ast-to-zql.js.map +1 -1
- package/out/replicache/src/btree/node.d.ts.map +1 -1
- package/out/replicache/src/btree/node.js +2 -2
- package/out/replicache/src/btree/node.js.map +1 -1
- package/out/replicache/src/connection-loop.js +3 -3
- package/out/replicache/src/connection-loop.js.map +1 -1
- package/out/replicache/src/deleted-clients.d.ts +0 -4
- package/out/replicache/src/deleted-clients.d.ts.map +1 -1
- package/out/replicache/src/deleted-clients.js +1 -1
- package/out/replicache/src/deleted-clients.js.map +1 -1
- package/out/replicache/src/hash.d.ts.map +1 -1
- package/out/replicache/src/hash.js.map +1 -1
- package/out/replicache/src/process-scheduler.d.ts.map +1 -1
- package/out/replicache/src/process-scheduler.js.map +1 -1
- package/out/replicache/src/request-idle.js +1 -1
- package/out/replicache/src/request-idle.js.map +1 -1
- package/out/replicache/src/sync/patch.d.ts +1 -1
- package/out/replicache/src/sync/patch.d.ts.map +1 -1
- package/out/replicache/src/sync/patch.js +1 -1
- package/out/replicache/src/sync/patch.js.map +1 -1
- package/out/shared/src/arrays.d.ts.map +1 -1
- package/out/shared/src/arrays.js +1 -2
- package/out/shared/src/arrays.js.map +1 -1
- package/out/shared/src/bigint-json.js +1 -1
- package/out/shared/src/bigint-json.js.map +1 -1
- package/out/shared/src/btree-set.js +1 -1
- package/out/shared/src/btree-set.js.map +1 -1
- package/out/shared/src/iterables.d.ts +7 -0
- package/out/shared/src/iterables.d.ts.map +1 -1
- package/out/shared/src/iterables.js +10 -1
- package/out/shared/src/iterables.js.map +1 -1
- package/out/shared/src/logging.d.ts.map +1 -1
- package/out/shared/src/logging.js +10 -9
- package/out/shared/src/logging.js.map +1 -1
- package/out/shared/src/options.js +1 -1
- package/out/shared/src/options.js.map +1 -1
- package/out/shared/src/sorted-entries.d.ts +2 -0
- package/out/shared/src/sorted-entries.d.ts.map +1 -0
- package/out/shared/src/sorted-entries.js +9 -0
- package/out/shared/src/sorted-entries.js.map +1 -0
- package/out/shared/src/tdigest-schema.d.ts.map +1 -1
- package/out/shared/src/tdigest-schema.js.map +1 -1
- package/out/shared/src/tdigest.d.ts.map +1 -1
- package/out/shared/src/tdigest.js +7 -7
- package/out/shared/src/tdigest.js.map +1 -1
- package/out/shared/src/valita.d.ts.map +1 -1
- package/out/shared/src/valita.js +1 -1
- package/out/shared/src/valita.js.map +1 -1
- package/out/z2s/src/sql.d.ts +2 -2
- package/out/z2s/src/sql.d.ts.map +1 -1
- package/out/z2s/src/sql.js +3 -3
- package/out/z2s/src/sql.js.map +1 -1
- package/out/zero/package.js +6 -7
- package/out/zero/package.js.map +1 -1
- package/out/zero/src/pg.js +1 -1
- package/out/zero/src/server.js +1 -1
- package/out/zero-cache/src/auth/auth.d.ts +8 -26
- package/out/zero-cache/src/auth/auth.d.ts.map +1 -1
- package/out/zero-cache/src/auth/auth.js +57 -82
- package/out/zero-cache/src/auth/auth.js.map +1 -1
- package/out/zero-cache/src/auth/jwt.d.ts +3 -3
- package/out/zero-cache/src/auth/jwt.d.ts.map +1 -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/config/zero-config.d.ts +38 -2
- package/out/zero-cache/src/config/zero-config.d.ts.map +1 -1
- package/out/zero-cache/src/config/zero-config.js +56 -1
- package/out/zero-cache/src/config/zero-config.js.map +1 -1
- package/out/zero-cache/src/custom/fetch.d.ts +2 -9
- package/out/zero-cache/src/custom/fetch.d.ts.map +1 -1
- package/out/zero-cache/src/custom/fetch.js +10 -4
- package/out/zero-cache/src/custom/fetch.js.map +1 -1
- package/out/zero-cache/src/custom-queries/transform-query.d.ts +20 -9
- package/out/zero-cache/src/custom-queries/transform-query.d.ts.map +1 -1
- package/out/zero-cache/src/custom-queries/transform-query.js +74 -37
- package/out/zero-cache/src/custom-queries/transform-query.js.map +1 -1
- package/out/zero-cache/src/db/migration-lite.d.ts.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.d.ts.map +1 -1
- package/out/zero-cache/src/db/migration.js +1 -1
- package/out/zero-cache/src/db/migration.js.map +1 -1
- package/out/zero-cache/src/db/pg-copy-binary.d.ts +101 -0
- package/out/zero-cache/src/db/pg-copy-binary.d.ts.map +1 -0
- package/out/zero-cache/src/db/pg-copy-binary.js +381 -0
- package/out/zero-cache/src/db/pg-copy-binary.js.map +1 -0
- package/out/zero-cache/src/db/transaction-pool.d.ts.map +1 -1
- package/out/zero-cache/src/db/transaction-pool.js +3 -0
- package/out/zero-cache/src/db/transaction-pool.js.map +1 -1
- package/out/zero-cache/src/db/warmup.d.ts.map +1 -1
- package/out/zero-cache/src/db/warmup.js +3 -1
- package/out/zero-cache/src/db/warmup.js.map +1 -1
- package/out/zero-cache/src/server/anonymous-otel-start.d.ts.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.d.ts.map +1 -1
- package/out/zero-cache/src/server/change-streamer.js +5 -2
- package/out/zero-cache/src/server/change-streamer.js.map +1 -1
- package/out/zero-cache/src/server/inspector-delegate.d.ts +2 -2
- package/out/zero-cache/src/server/inspector-delegate.d.ts.map +1 -1
- package/out/zero-cache/src/server/inspector-delegate.js +4 -4
- package/out/zero-cache/src/server/inspector-delegate.js.map +1 -1
- package/out/zero-cache/src/server/main.js +1 -1
- package/out/zero-cache/src/server/main.js.map +1 -1
- package/out/zero-cache/src/server/reaper.d.ts.map +1 -1
- package/out/zero-cache/src/server/reaper.js +4 -1
- package/out/zero-cache/src/server/reaper.js.map +1 -1
- package/out/zero-cache/src/server/runner/run-worker.js +1 -1
- package/out/zero-cache/src/server/syncer.d.ts.map +1 -1
- package/out/zero-cache/src/server/syncer.js +41 -20
- package/out/zero-cache/src/server/syncer.js.map +1 -1
- package/out/zero-cache/src/server/worker-urls.d.ts.map +1 -1
- package/out/zero-cache/src/server/worker-urls.js +2 -1
- package/out/zero-cache/src/server/worker-urls.js.map +1 -1
- package/out/zero-cache/src/services/change-source/change-source.d.ts +4 -0
- package/out/zero-cache/src/services/change-source/change-source.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/common/backfill-manager.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/common/backfill-manager.js +3 -2
- package/out/zero-cache/src/services/change-source/common/backfill-manager.js.map +1 -1
- package/out/zero-cache/src/services/change-source/custom/change-source.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/custom/change-source.js +5 -2
- package/out/zero-cache/src/services/change-source/custom/change-source.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/change-source.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/change-source.js +13 -4
- package/out/zero-cache/src/services/change-source/pg/change-source.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/initial-sync.d.ts +3 -1
- package/out/zero-cache/src/services/change-source/pg/initial-sync.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/initial-sync.js +91 -9
- package/out/zero-cache/src/services/change-source/pg/initial-sync.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/shard.js +2 -2
- package/out/zero-cache/src/services/change-source/pg/schema/shard.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-streamer-service.js +3 -0
- package/out/zero-cache/src/services/change-streamer/change-streamer-service.js.map +1 -1
- package/out/zero-cache/src/services/life-cycle.d.ts +5 -4
- package/out/zero-cache/src/services/life-cycle.d.ts.map +1 -1
- package/out/zero-cache/src/services/life-cycle.js +11 -11
- package/out/zero-cache/src/services/life-cycle.js.map +1 -1
- package/out/zero-cache/src/services/litestream/commands.d.ts.map +1 -1
- package/out/zero-cache/src/services/litestream/commands.js +5 -5
- package/out/zero-cache/src/services/litestream/commands.js.map +1 -1
- package/out/zero-cache/src/services/mutagen/pusher.d.ts +20 -20
- package/out/zero-cache/src/services/mutagen/pusher.d.ts.map +1 -1
- package/out/zero-cache/src/services/mutagen/pusher.js +91 -104
- package/out/zero-cache/src/services/mutagen/pusher.js.map +1 -1
- package/out/zero-cache/src/services/replicator/change-processor.js +1 -1
- package/out/zero-cache/src/services/replicator/change-processor.js.map +1 -1
- package/out/zero-cache/src/services/replicator/replication-status.js.map +1 -1
- 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 +4 -3
- 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.d.ts +168 -0
- package/out/zero-cache/src/services/view-syncer/connection-context-manager.d.ts.map +1 -0
- package/out/zero-cache/src/services/view-syncer/connection-context-manager.js +385 -0
- package/out/zero-cache/src/services/view-syncer/connection-context-manager.js.map +1 -0
- package/out/zero-cache/src/services/view-syncer/cvr-store.js +2 -2
- package/out/zero-cache/src/services/view-syncer/cvr-store.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/cvr.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/cvr.js +5 -4
- package/out/zero-cache/src/services/view-syncer/cvr.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/inspect-handler.d.ts +2 -3
- package/out/zero-cache/src/services/view-syncer/inspect-handler.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/inspect-handler.js +3 -3
- 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 +5 -3
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/row-record-cache.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/row-record-cache.js +13 -7
- package/out/zero-cache/src/services/view-syncer/row-record-cache.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts +3 -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 +6 -9
- package/out/zero-cache/src/services/view-syncer/snapshotter.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts +24 -26
- 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 +236 -124
- package/out/zero-cache/src/services/view-syncer/view-syncer.js.map +1 -1
- package/out/zero-cache/src/types/lite.d.ts.map +1 -1
- package/out/zero-cache/src/types/lite.js +3 -2
- package/out/zero-cache/src/types/lite.js.map +1 -1
- package/out/zero-cache/src/types/pg-types.js +4 -1
- package/out/zero-cache/src/types/pg-types.js.map +1 -1
- package/out/zero-cache/src/types/pg-versions.d.ts +3 -0
- package/out/zero-cache/src/types/pg-versions.d.ts.map +1 -0
- package/out/zero-cache/src/types/pg-versions.js +7 -0
- package/out/zero-cache/src/types/pg-versions.js.map +1 -0
- package/out/zero-cache/src/types/pg.d.ts.map +1 -1
- package/out/zero-cache/src/types/pg.js +6 -1
- package/out/zero-cache/src/types/pg.js.map +1 -1
- package/out/zero-cache/src/types/subscription.d.ts.map +1 -1
- package/out/zero-cache/src/types/subscription.js +2 -2
- package/out/zero-cache/src/types/subscription.js.map +1 -1
- package/out/zero-cache/src/workers/connect-params.d.ts +1 -1
- package/out/zero-cache/src/workers/connect-params.d.ts.map +1 -1
- package/out/zero-cache/src/workers/connect-params.js +1 -1
- package/out/zero-cache/src/workers/connect-params.js.map +1 -1
- package/out/zero-cache/src/workers/connection.js +2 -2
- package/out/zero-cache/src/workers/syncer-ws-message-handler.d.ts +2 -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 +64 -38
- package/out/zero-cache/src/workers/syncer-ws-message-handler.js.map +1 -1
- package/out/zero-cache/src/workers/syncer.d.ts +2 -1
- package/out/zero-cache/src/workers/syncer.d.ts.map +1 -1
- package/out/zero-cache/src/workers/syncer.js +70 -31
- package/out/zero-cache/src/workers/syncer.js.map +1 -1
- package/out/zero-client/src/client/connection.d.ts +4 -4
- package/out/zero-client/src/client/connection.d.ts.map +1 -1
- package/out/zero-client/src/client/connection.js.map +1 -1
- package/out/zero-client/src/client/http-string.d.ts.map +1 -1
- package/out/zero-client/src/client/http-string.js.map +1 -1
- package/out/zero-client/src/client/metrics.d.ts.map +1 -1
- package/out/zero-client/src/client/metrics.js +2 -1
- package/out/zero-client/src/client/metrics.js.map +1 -1
- package/out/zero-client/src/client/options.d.ts +30 -5
- package/out/zero-client/src/client/options.d.ts.map +1 -1
- package/out/zero-client/src/client/options.js.map +1 -1
- package/out/zero-client/src/client/server-option.js +1 -1
- package/out/zero-client/src/client/server-option.js.map +1 -1
- package/out/zero-client/src/client/version.js +1 -1
- package/out/zero-client/src/client/zero-poke-handler.d.ts.map +1 -1
- package/out/zero-client/src/client/zero-poke-handler.js +1 -1
- package/out/zero-client/src/client/zero-poke-handler.js.map +1 -1
- package/out/zero-client/src/client/zero.d.ts +4 -3
- package/out/zero-client/src/client/zero.d.ts.map +1 -1
- package/out/zero-client/src/client/zero.js +33 -11
- package/out/zero-client/src/client/zero.js.map +1 -1
- package/out/zero-pg/src/mod.js +1 -1
- package/out/zero-protocol/src/ast.d.ts.map +1 -1
- package/out/zero-protocol/src/ast.js.map +1 -1
- package/out/zero-protocol/src/change-desired-queries.d.ts +4 -0
- package/out/zero-protocol/src/change-desired-queries.d.ts.map +1 -1
- package/out/zero-protocol/src/change-desired-queries.js +4 -1
- package/out/zero-protocol/src/change-desired-queries.js.map +1 -1
- package/out/zero-protocol/src/connect.d.ts +4 -0
- package/out/zero-protocol/src/connect.d.ts.map +1 -1
- package/out/zero-protocol/src/connect.js +2 -1
- package/out/zero-protocol/src/connect.js.map +1 -1
- package/out/zero-protocol/src/primary-key.d.ts.map +1 -1
- package/out/zero-protocol/src/primary-key.js.map +1 -1
- package/out/zero-protocol/src/protocol-version.d.ts +1 -1
- package/out/zero-protocol/src/protocol-version.d.ts.map +1 -1
- package/out/zero-protocol/src/protocol-version.js.map +1 -1
- package/out/zero-protocol/src/push.d.ts +4 -0
- package/out/zero-protocol/src/push.d.ts.map +1 -1
- package/out/zero-protocol/src/push.js +2 -1
- package/out/zero-protocol/src/push.js.map +1 -1
- package/out/zero-protocol/src/up.d.ts +3 -0
- package/out/zero-protocol/src/up.d.ts.map +1 -1
- package/out/zero-react/src/zero-provider.d.ts.map +1 -1
- package/out/zero-react/src/zero-provider.js +11 -5
- package/out/zero-react/src/zero-provider.js.map +1 -1
- package/out/zero-schema/src/name-mapper.js +1 -1
- package/out/zero-schema/src/name-mapper.js.map +1 -1
- package/out/zero-server/src/mod.js +1 -1
- package/out/zero-server/src/process-mutations.d.ts.map +1 -1
- package/out/zero-server/src/process-mutations.js +2 -1
- package/out/zero-server/src/process-mutations.js.map +1 -1
- package/out/zero-server/src/push-processor.d.ts +1 -0
- package/out/zero-server/src/push-processor.d.ts.map +1 -1
- package/out/zero-server/src/push-processor.js +3 -2
- package/out/zero-server/src/push-processor.js.map +1 -1
- package/out/zero-solid/src/use-zero.d.ts.map +1 -1
- package/out/zero-solid/src/use-zero.js +8 -9
- package/out/zero-solid/src/use-zero.js.map +1 -1
- package/out/zql/src/builder/like.js +2 -1
- package/out/zql/src/builder/like.js.map +1 -1
- package/out/zql/src/ivm/data.d.ts.map +1 -1
- package/out/zql/src/ivm/data.js +6 -15
- package/out/zql/src/ivm/data.js.map +1 -1
- package/out/zql/src/ivm/memory-source.d.ts.map +1 -1
- package/out/zql/src/ivm/memory-source.js +14 -8
- package/out/zql/src/ivm/memory-source.js.map +1 -1
- package/out/zql/src/query/complete-ordering.js +1 -1
- package/out/zql/src/query/complete-ordering.js.map +1 -1
- package/out/zql/src/query/query-impl.d.ts.map +1 -1
- package/out/zql/src/query/query-impl.js +2 -2
- package/out/zql/src/query/query-impl.js.map +1 -1
- package/out/zql/src/query/query-registry.d.ts.map +1 -1
- package/out/zql/src/query/query-registry.js +2 -1
- package/out/zql/src/query/query-registry.js.map +1 -1
- package/out/zql/src/query/ttl.js +1 -1
- package/out/zql/src/query/ttl.js.map +1 -1
- package/out/zqlite/src/internal/sql.d.ts +2 -2
- package/out/zqlite/src/internal/sql.d.ts.map +1 -1
- package/out/zqlite/src/internal/sql.js +1 -2
- package/out/zqlite/src/internal/sql.js.map +1 -1
- package/out/zqlite/src/sqlite-cost-model.d.ts +1 -1
- package/out/zqlite/src/sqlite-cost-model.d.ts.map +1 -1
- package/out/zqlite/src/sqlite-cost-model.js +1 -1
- package/out/zqlite/src/sqlite-cost-model.js.map +1 -1
- package/out/zqlite/src/sqlite-stat-fanout.js +1 -1
- package/out/zqlite/src/sqlite-stat-fanout.js.map +1 -1
- package/out/zqlite/src/table-source.d.ts.map +1 -1
- package/out/zqlite/src/table-source.js +8 -12
- package/out/zqlite/src/table-source.js.map +1 -1
- package/package.json +6 -7
|
@@ -2,7 +2,6 @@ import { assert, unreachable } from "../../../../shared/src/asserts.js";
|
|
|
2
2
|
import { must } from "../../../../shared/src/must.js";
|
|
3
3
|
import { InvalidConnectionRequest, InvalidConnectionRequestBaseCookie, Rehome } from "../../../../zero-protocol/src/error-kind-enum.js";
|
|
4
4
|
import { ZeroCache } from "../../../../zero-protocol/src/error-origin-enum.js";
|
|
5
|
-
import "../../../../zero-protocol/src/error-reason-enum.js";
|
|
6
5
|
import { ProtocolError, isProtocolError } from "../../../../zero-protocol/src/error.js";
|
|
7
6
|
import { MAX_TTL_MS, clampTTL } from "../../../../zql/src/query/ttl.js";
|
|
8
7
|
import { stringify } from "../../../../shared/src/bigint-json.js";
|
|
@@ -19,10 +18,11 @@ import { Subscription } from "../../types/subscription.js";
|
|
|
19
18
|
import { CustomKeyMap } from "../../../../shared/src/custom-key-map.js";
|
|
20
19
|
import { ttlClockAsNumber, ttlClockFromNumber } from "./ttl-clock.js";
|
|
21
20
|
import { EMPTY_CVR_VERSION, cmpVersions, versionFromString, versionString, versionToCookie } from "./schema/types.js";
|
|
22
|
-
import { ProtocolErrorWithLevel, getLogLevel } from "../../types/error-with-level.js";
|
|
21
|
+
import { ProtocolErrorWithLevel, getLogLevel, wrapWithProtocolError } from "../../types/error-with-level.js";
|
|
22
|
+
import { isAuthErrorBody } from "../../auth/auth.js";
|
|
23
23
|
import { ClientHandler, startPoke } from "./client-handler.js";
|
|
24
|
-
import { CVRStore, ClientNotFoundError } from "./cvr-store.js";
|
|
25
24
|
import { tracer } from "./tracer.js";
|
|
25
|
+
import { CVRStore, ClientNotFoundError } from "./cvr-store.js";
|
|
26
26
|
import { CVRConfigDrivenUpdater, CVRQueryDrivenUpdater, nextEvictionTime } from "./cvr.js";
|
|
27
27
|
import { handleInspect } from "./inspect-handler.js";
|
|
28
28
|
import { resolver } from "@rocicorp/resolver";
|
|
@@ -41,6 +41,7 @@ function randomID() {
|
|
|
41
41
|
var TTL_CLOCK_INTERVAL = 6e4;
|
|
42
42
|
var ViewSyncerService = class {
|
|
43
43
|
id;
|
|
44
|
+
contextManager;
|
|
44
45
|
#shard;
|
|
45
46
|
#lc;
|
|
46
47
|
#pipelines;
|
|
@@ -48,10 +49,6 @@ var ViewSyncerService = class {
|
|
|
48
49
|
#drainCoordinator;
|
|
49
50
|
#keepaliveMs;
|
|
50
51
|
#slowHydrateThreshold;
|
|
51
|
-
#queryConfig;
|
|
52
|
-
#authSession;
|
|
53
|
-
userQueryURL;
|
|
54
|
-
userQueryHeaders;
|
|
55
52
|
#lastConnectTime = Date.now();
|
|
56
53
|
/**
|
|
57
54
|
* The TTL clock is used to determine the time at which queries are considered
|
|
@@ -82,10 +79,8 @@ var ViewSyncerService = class {
|
|
|
82
79
|
#initialized = resolver();
|
|
83
80
|
#cvr;
|
|
84
81
|
#pipelinesSynced = false;
|
|
85
|
-
#httpCookie;
|
|
86
|
-
#origin;
|
|
87
|
-
#lastAuthRevision = 0;
|
|
88
82
|
#expiredQueriesTimer = 0;
|
|
83
|
+
#authMaintenanceTimer = 0;
|
|
89
84
|
#setTimeout;
|
|
90
85
|
#customQueryTransformer;
|
|
91
86
|
#queryReplacements = /* @__PURE__ */ new Map();
|
|
@@ -106,15 +101,19 @@ var ViewSyncerService = class {
|
|
|
106
101
|
});
|
|
107
102
|
#queryTransformationHashChanges = getOrCreateCounter("sync", "query.transformation-hash-changes", "Number of times query transformation hash changed");
|
|
108
103
|
#queryTransformationNoOps = getOrCreateCounter("sync", "query.transformation-no-ops", "Number of times query transformation resulted in no-op (hash unchanged)");
|
|
104
|
+
#lockWaitTime = getOrCreateHistogram("sync", "lock-wait-time", {
|
|
105
|
+
description: "Time spent waiting to acquire the ViewSyncer lock.",
|
|
106
|
+
unit: "s"
|
|
107
|
+
});
|
|
108
|
+
#pipelineResets = getOrCreateCounter("sync", "pipeline-resets", "Number of pipeline resets");
|
|
109
109
|
#inspectorDelegate;
|
|
110
110
|
#config;
|
|
111
111
|
#runPriorityOp;
|
|
112
|
-
constructor(config, lc, shard, taskID, clientGroupID, cvrDb, pipelineDriver, versionChanges, drainCoordinator, slowHydrateThreshold, inspectorDelegate, customQueryTransformer, runPriorityOp,
|
|
113
|
-
const queryConfig = config.query?.url ? config.query : config.getQueries;
|
|
112
|
+
constructor(config, lc, shard, taskID, clientGroupID, cvrDb, pipelineDriver, versionChanges, drainCoordinator, slowHydrateThreshold, inspectorDelegate, contextManager, customQueryTransformer, runPriorityOp, keepaliveMs = DEFAULT_KEEPALIVE_MS, setTimeoutFn = setTimeout.bind(globalThis)) {
|
|
114
113
|
this.#config = config;
|
|
115
114
|
this.id = clientGroupID;
|
|
115
|
+
this.contextManager = contextManager;
|
|
116
116
|
this.#shard = shard;
|
|
117
|
-
this.#queryConfig = queryConfig;
|
|
118
117
|
this.#lc = lc;
|
|
119
118
|
this.#pipelines = pipelineDriver;
|
|
120
119
|
this.#stateChanges = versionChanges;
|
|
@@ -123,36 +122,17 @@ var ViewSyncerService = class {
|
|
|
123
122
|
this.#slowHydrateThreshold = slowHydrateThreshold;
|
|
124
123
|
this.#inspectorDelegate = inspectorDelegate;
|
|
125
124
|
this.#customQueryTransformer = customQueryTransformer;
|
|
126
|
-
this.#authSession = authSession;
|
|
127
125
|
this.#cvrStore = new CVRStore(lc, cvrDb, shard, taskID, clientGroupID, () => this.#stateChanges.cancel());
|
|
128
126
|
this.#setTimeout = setTimeoutFn;
|
|
129
127
|
this.#runPriorityOp = runPriorityOp;
|
|
130
128
|
this.keepalive();
|
|
131
129
|
}
|
|
132
|
-
get auth() {
|
|
133
|
-
return this.#authSession.auth;
|
|
134
|
-
}
|
|
135
|
-
clearAuth() {
|
|
136
|
-
this.#authSession.clear();
|
|
137
|
-
this.#lastAuthRevision = 0;
|
|
138
|
-
}
|
|
139
|
-
initAuthSession(userID, wireAuth) {
|
|
140
|
-
return this.#authSession.update(userID, wireAuth);
|
|
141
|
-
}
|
|
142
|
-
#getHeaderOptions(forwardCookie) {
|
|
143
|
-
return {
|
|
144
|
-
apiKey: this.#queryConfig.apiKey,
|
|
145
|
-
customHeaders: this.userQueryHeaders,
|
|
146
|
-
allowedClientHeaders: this.#queryConfig.allowedClientHeaders,
|
|
147
|
-
token: this.#authSession.auth?.raw,
|
|
148
|
-
cookie: forwardCookie ? this.#httpCookie : void 0,
|
|
149
|
-
origin: this.#origin
|
|
150
|
-
};
|
|
151
|
-
}
|
|
152
130
|
#runInLockWithCVR(fn) {
|
|
153
131
|
const rid = randomID();
|
|
154
132
|
this.#lc.debug?.("about to acquire lock for cvr ", rid);
|
|
133
|
+
const lockWaitStart = performance.now();
|
|
155
134
|
return this.#lock.withLock(async () => {
|
|
135
|
+
this.#lockWaitTime.record((performance.now() - lockWaitStart) / 1e3);
|
|
156
136
|
this.#lc.debug?.("acquired lock in #runInLockWithCVR ", rid);
|
|
157
137
|
const lc = this.#lc.withContext("lock", rid);
|
|
158
138
|
if (!this.#stateChanges.active) {
|
|
@@ -186,6 +166,8 @@ var ViewSyncerService = class {
|
|
|
186
166
|
} catch (e) {
|
|
187
167
|
this.#cvr = void 0;
|
|
188
168
|
throw e;
|
|
169
|
+
} finally {
|
|
170
|
+
this.#scheduleAuthMaintenance(lc);
|
|
189
171
|
}
|
|
190
172
|
});
|
|
191
173
|
}
|
|
@@ -216,6 +198,7 @@ var ViewSyncerService = class {
|
|
|
216
198
|
const result = await this.#advancePipelines(lc, cvr);
|
|
217
199
|
if (result === "success") return;
|
|
218
200
|
lc.info?.(`resetting pipelines: ${result.message}`);
|
|
201
|
+
this.#pipelineResets.add(1, { reason: result.reason });
|
|
219
202
|
this.#pipelines.reset(clientSchema);
|
|
220
203
|
this.#pipelinesSynced = false;
|
|
221
204
|
}
|
|
@@ -227,7 +210,7 @@ var ViewSyncerService = class {
|
|
|
227
210
|
}
|
|
228
211
|
lc.info?.(`init pipelines@${version} (cvr@${cvrVer})`);
|
|
229
212
|
await this.#hydrateUnchangedQueries(lc, cvr);
|
|
230
|
-
await this.#syncQueryPipelineSet(lc, cvr, "missing");
|
|
213
|
+
await this.#syncQueryPipelineSet(lc, cvr, "missing", void 0);
|
|
231
214
|
this.#pipelinesSynced = true;
|
|
232
215
|
});
|
|
233
216
|
}
|
|
@@ -246,13 +229,19 @@ var ViewSyncerService = class {
|
|
|
246
229
|
if (hasExpiredQueries(cvr)) {
|
|
247
230
|
lc = lc.withContext("method", "#removeExpiredQueries");
|
|
248
231
|
lc.debug?.("Queries have expired");
|
|
249
|
-
if (this.#pipelinesSynced) await this.#syncQueryPipelineSet(lc, cvr, "missing");
|
|
232
|
+
if (this.#pipelinesSynced) await this.#syncQueryPipelineSet(lc, cvr, "missing", void 0);
|
|
250
233
|
}
|
|
251
234
|
this.#scheduleExpireEviction(lc, cvr);
|
|
252
235
|
};
|
|
253
236
|
#totalHydrationTimeMs() {
|
|
254
237
|
return this.#pipelines.totalHydrationTimeMs();
|
|
255
238
|
}
|
|
239
|
+
get queryCount() {
|
|
240
|
+
return this.#pipelines.initialized() ? this.#pipelines.queries().size : 0;
|
|
241
|
+
}
|
|
242
|
+
get rowCount() {
|
|
243
|
+
return this.#cvrStore.rowCount;
|
|
244
|
+
}
|
|
256
245
|
#keepAliveUntil = 0;
|
|
257
246
|
/**
|
|
258
247
|
* Guarantees that the ViewSyncer will remain running for at least
|
|
@@ -285,6 +274,10 @@ var ViewSyncerService = class {
|
|
|
285
274
|
return this.#clients.size === 0;
|
|
286
275
|
}
|
|
287
276
|
#deleteClientDueToDisconnect(clientID, client) {
|
|
277
|
+
this.contextManager.closeConnection({
|
|
278
|
+
clientID,
|
|
279
|
+
wsID: client.wsID
|
|
280
|
+
});
|
|
288
281
|
if (this.#clients.get(clientID) === client) {
|
|
289
282
|
this.#clients.delete(clientID);
|
|
290
283
|
if (this.#clients.size === 0) {
|
|
@@ -299,73 +292,110 @@ var ViewSyncerService = class {
|
|
|
299
292
|
clearTimeout(this.#expiredQueriesTimer);
|
|
300
293
|
this.#expiredQueriesTimer = 0;
|
|
301
294
|
}
|
|
302
|
-
|
|
295
|
+
#stopAuthMaintenanceTimer() {
|
|
296
|
+
if (this.#authMaintenanceTimer !== 0) this.#lc.debug?.("Stopping auth maintenance timer");
|
|
297
|
+
clearTimeout(this.#authMaintenanceTimer);
|
|
298
|
+
this.#authMaintenanceTimer = 0;
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Schedules the auth maintenance wakeup from coordinator-derived
|
|
302
|
+
* deadlines. The timer plumbing is intentionally separate from the actual
|
|
303
|
+
* revalidation/retransform work so future policy changes only need to update
|
|
304
|
+
* the maintenance workers, not the wakeup logic.
|
|
305
|
+
*
|
|
306
|
+
* This is intentionally cheap & idempotent, so it can be called frequently
|
|
307
|
+
* when upstream state might have changed.
|
|
308
|
+
*/
|
|
309
|
+
#scheduleAuthMaintenance(lc) {
|
|
310
|
+
this.#stopAuthMaintenanceTimer();
|
|
311
|
+
const plan = this.contextManager.planMaintenance();
|
|
312
|
+
if (plan.earliestDeadlineAt === void 0) {
|
|
313
|
+
lc.debug?.("No auth maintenance wakeup scheduled");
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
const delay = Math.max(0, plan.earliestDeadlineAt - Date.now());
|
|
317
|
+
lc.debug?.(`Scheduling auth maintenance timer at ${new Date(plan.earliestDeadlineAt).toISOString()}`, {
|
|
318
|
+
delay,
|
|
319
|
+
earliestDeadlineAt: plan.earliestDeadlineAt
|
|
320
|
+
});
|
|
321
|
+
this.#authMaintenanceTimer = this.#setTimeout(() => {
|
|
322
|
+
this.#authMaintenanceTimer = 0;
|
|
323
|
+
this.#runInLockWithCVR((lc, cvr) => this.#runAuthMaintenance(lc, cvr)).catch((e) => this.#stateChanges.fail(e));
|
|
324
|
+
}, delay);
|
|
325
|
+
}
|
|
326
|
+
async #runAuthMaintenance(lc, _cvr) {
|
|
327
|
+
const plan = this.contextManager.planMaintenance();
|
|
328
|
+
if (plan.dueRevalidations.length === 0 && !plan.dueRetransform) {
|
|
329
|
+
lc.debug?.("Auth maintenance woke up with no due work");
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
lc.debug?.("Auth maintenance woke up with pending work", {
|
|
333
|
+
dueRevalidations: plan.dueRevalidations.length,
|
|
334
|
+
dueRetransform: plan.dueRetransform
|
|
335
|
+
});
|
|
336
|
+
for (const connection of plan.dueRevalidations) try {
|
|
337
|
+
await this.#validateConnection(connection);
|
|
338
|
+
} catch (e) {
|
|
339
|
+
if (isProtocolError(e) && isTransformFailedError(e)) {
|
|
340
|
+
lc.warn?.("Scheduled auth revalidation failed; deferring auth maintenance", {
|
|
341
|
+
clientID: connection.clientID,
|
|
342
|
+
wsID: connection.wsID,
|
|
343
|
+
message: e.message
|
|
344
|
+
});
|
|
345
|
+
this.contextManager.deferMaintenance("revalidate");
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
throw e;
|
|
349
|
+
}
|
|
350
|
+
if (this.contextManager.planMaintenance().dueRetransform) await this.#runBackgroundRetransform(lc);
|
|
351
|
+
}
|
|
352
|
+
initConnection(selector, initConnectionMessage) {
|
|
303
353
|
this.#lc.debug?.("viewSyncer.initConnection");
|
|
304
354
|
return startSpan(tracer, "vs.initConnection", () => {
|
|
305
|
-
const
|
|
306
|
-
this.#
|
|
307
|
-
this.#origin = origin;
|
|
308
|
-
const [, { userQueryURL, userQueryHeaders }] = initConnectionMessage;
|
|
309
|
-
if (this.userQueryURL === void 0) {
|
|
310
|
-
this.userQueryURL = userQueryURL;
|
|
311
|
-
this.userQueryHeaders = userQueryHeaders;
|
|
312
|
-
} else if (this.userQueryURL !== userQueryURL) this.#lc.warn?.("Client provided different query parameters than client group", {
|
|
313
|
-
clientID,
|
|
314
|
-
clientURL: userQueryURL,
|
|
315
|
-
clientGroupURL: this.userQueryURL
|
|
316
|
-
});
|
|
317
|
-
const lc = this.#lc.withContext("clientID", clientID).withContext("wsID", wsID);
|
|
355
|
+
const ctx = this.contextManager.mustGetConnectionContext(selector);
|
|
356
|
+
const lc = this.#lc.withContext("clientID", ctx.clientID).withContext("wsID", ctx.wsID);
|
|
318
357
|
const downstream = Subscription.create({ cleanup: (_, err) => {
|
|
319
358
|
err ? lc[getLogLevel(err)]?.(`client closed with error`, err) : lc.info?.("client closed");
|
|
320
|
-
this.#deleteClientDueToDisconnect(clientID, newClient);
|
|
321
|
-
this.#activeClients.add(-1, { [PROTOCOL_VERSION_ATTR]: protocolVersion });
|
|
359
|
+
this.#deleteClientDueToDisconnect(ctx.clientID, newClient);
|
|
360
|
+
this.#activeClients.add(-1, { [PROTOCOL_VERSION_ATTR]: ctx.protocolVersion });
|
|
322
361
|
} });
|
|
323
|
-
this.#activeClients.add(1, { [PROTOCOL_VERSION_ATTR]: protocolVersion });
|
|
362
|
+
this.#activeClients.add(1, { [PROTOCOL_VERSION_ATTR]: ctx.protocolVersion });
|
|
324
363
|
if (this.#clients.size === 0) this.#ttlClockBase = Date.now();
|
|
325
|
-
const newClient = new ClientHandler(lc, this.id, clientID, wsID, this.#shard, baseCookie, downstream);
|
|
326
|
-
this.#clients.get(clientID)?.close(`replaced by wsID: ${wsID}`);
|
|
327
|
-
this.#clients.set(clientID, newClient);
|
|
328
|
-
this.#runInLockForClient(ctx, initConnectionMessage, async (lc, clientID, msg, cvr) => {
|
|
364
|
+
const newClient = new ClientHandler(lc, this.id, ctx.clientID, ctx.wsID, this.#shard, ctx.baseCookie, downstream);
|
|
365
|
+
this.#clients.get(ctx.clientID)?.close(`replaced by wsID: ${ctx.wsID}`);
|
|
366
|
+
this.#clients.set(ctx.clientID, newClient);
|
|
367
|
+
startAsyncSpan(tracer, "vs.initConnection.async", () => this.#runInLockForClient(ctx, initConnectionMessage, async (lc, clientID, msg, cvr) => {
|
|
329
368
|
if (cvr.clientSchema === null && !msg.clientSchema) throw new ProtocolErrorWithLevel({
|
|
330
369
|
kind: InvalidConnectionRequest,
|
|
331
370
|
message: "The initConnection message for a new client group must include client schema.",
|
|
332
371
|
origin: ZeroCache
|
|
333
372
|
}, "warn");
|
|
334
|
-
await this.#
|
|
373
|
+
if (!await this.#validateConnection(ctx)) return;
|
|
374
|
+
await this.#handleConfigUpdate(lc, clientID, msg, cvr, "all", ctx.profileID ?? `cg${this.id}`, ctx);
|
|
335
375
|
this.#initialized.resolve("initialized");
|
|
336
|
-
}, newClient).catch((e) => newClient.fail(e));
|
|
376
|
+
}, newClient)).catch((e) => newClient.fail(e));
|
|
337
377
|
return downstream;
|
|
338
378
|
});
|
|
339
379
|
}
|
|
340
|
-
async changeDesiredQueries(
|
|
341
|
-
await this.#runInLockForClient(
|
|
342
|
-
let customQueryTransformMode = "missing";
|
|
343
|
-
const currentAuthRevision = this.#authSession.revision;
|
|
344
|
-
if (this.#lastAuthRevision < currentAuthRevision) {
|
|
345
|
-
customQueryTransformMode = "all";
|
|
346
|
-
lc.debug?.("Auth revision changed, setting customQueryTransformMode to all");
|
|
347
|
-
}
|
|
348
|
-
const result = await this.#handleConfigUpdate(lc, clientID, msg, cvr, customQueryTransformMode);
|
|
349
|
-
if (customQueryTransformMode === "all") this.#lastAuthRevision = currentAuthRevision;
|
|
350
|
-
return result;
|
|
351
|
-
});
|
|
380
|
+
async changeDesiredQueries(selector, msg) {
|
|
381
|
+
await this.#runInLockForClient(selector, msg, (lc, clientID, msg, cvr) => this.#handleConfigUpdate(lc, clientID, msg, cvr, "missing", void 0, this.contextManager.mustGetConnectionContext(selector)));
|
|
352
382
|
}
|
|
353
|
-
async updateAuth(
|
|
354
|
-
await this.#runInLockForClient(
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
const currentAuthRevision = this.#authSession.revision;
|
|
358
|
-
if (this.#lastAuthRevision >= currentAuthRevision) {
|
|
359
|
-
lc.debug?.("Auth revision unchanged, skipping query re-transformation");
|
|
383
|
+
async updateAuth(selector, msg, authRevisionChanged) {
|
|
384
|
+
await this.#runInLockForClient(selector, msg, async (lc, clientID, _, cvr) => {
|
|
385
|
+
if (!authRevisionChanged) {
|
|
386
|
+
lc.debug?.("Auth unchanged, skipping query re-transformation");
|
|
360
387
|
return;
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
388
|
+
}
|
|
389
|
+
lc.debug?.("Auth changed, re-validating and re-transforming queries");
|
|
390
|
+
const connection = this.contextManager.mustGetConnectionContext(selector);
|
|
391
|
+
if (!this.#pipelinesSynced) {
|
|
392
|
+
if (!await this.#validateConnection(connection)) return;
|
|
393
|
+
}
|
|
394
|
+
return await this.#handleConfigUpdate(lc, clientID, {}, cvr, "all", void 0, connection);
|
|
365
395
|
});
|
|
366
396
|
}
|
|
367
|
-
async deleteClients(
|
|
368
|
-
return await this.#runInLockForClient(
|
|
397
|
+
async deleteClients(selector, msg) {
|
|
398
|
+
return await this.#runInLockForClient(selector, [msg[0], { deleted: msg[1] }], (lc, clientID, msg, cvr) => this.#handleConfigUpdate(lc, clientID, msg, cvr, "missing", void 0, this.contextManager.mustGetConnectionContext(selector))) ?? [];
|
|
369
399
|
}
|
|
370
400
|
#getTTLClock(now) {
|
|
371
401
|
const delta = now - this.#ttlClockBase;
|
|
@@ -407,7 +437,7 @@ var ViewSyncerService = class {
|
|
|
407
437
|
lc.warn?.("failed to update TTL clock", rid, `after ${Date.now() - start} ms`, e);
|
|
408
438
|
});
|
|
409
439
|
}
|
|
410
|
-
async #updateCVRConfig(lc, cvr, clientID, customQueryTransformMode, fn) {
|
|
440
|
+
async #updateCVRConfig(lc, cvr, clientID, customQueryTransformMode, ctx, fn) {
|
|
411
441
|
const updater = new CVRConfigDrivenUpdater(this.#cvrStore, cvr, this.#shard);
|
|
412
442
|
updater.ensureClient(clientID);
|
|
413
443
|
const patches = fn(updater);
|
|
@@ -420,21 +450,24 @@ var ViewSyncerService = class {
|
|
|
420
450
|
await pokers.end(newCVR.version);
|
|
421
451
|
});
|
|
422
452
|
}
|
|
423
|
-
if (this.#pipelinesSynced) await this.#syncQueryPipelineSet(lc, this.#cvr, customQueryTransformMode);
|
|
453
|
+
if (this.#pipelinesSynced) await this.#syncQueryPipelineSet(lc, this.#cvr, customQueryTransformMode, ctx);
|
|
424
454
|
return this.#cvr;
|
|
425
455
|
}
|
|
426
456
|
/**
|
|
427
457
|
* Runs the given `fn` to process the `msg` from within the `#lock`,
|
|
428
458
|
* optionally adding the `newClient` if supplied.
|
|
429
459
|
*/
|
|
430
|
-
#runInLockForClient(
|
|
460
|
+
#runInLockForClient(selector, msg, fn, newClient) {
|
|
431
461
|
this.#lc.debug?.("viewSyncer.#runInLockForClient");
|
|
432
|
-
const { clientID, wsID } =
|
|
462
|
+
const { clientID, wsID } = selector;
|
|
433
463
|
const [cmd, body] = msg;
|
|
434
464
|
if (newClient || !this.#clients.has(clientID)) this.#lastConnectTime = Date.now();
|
|
435
|
-
return startAsyncSpan(tracer, `vs.#runInLockForClient(${cmd})`, async () => {
|
|
465
|
+
return startAsyncSpan(tracer, `vs.#runInLockForClient(${cmd})`, async (span) => {
|
|
466
|
+
span.setAttribute("clientGroupID", this.id);
|
|
467
|
+
span.setAttribute("clientID", clientID);
|
|
436
468
|
let client;
|
|
437
469
|
let result;
|
|
470
|
+
let ctx;
|
|
438
471
|
try {
|
|
439
472
|
await this.#runInLockWithCVR(async (lc, cvr) => {
|
|
440
473
|
lc = lc.withContext("clientID", clientID).withContext("wsID", wsID).withContext("cmd", cmd);
|
|
@@ -444,6 +477,7 @@ var ViewSyncerService = class {
|
|
|
444
477
|
lc.debug?.("mismatched wsID", client?.wsID, wsID);
|
|
445
478
|
return;
|
|
446
479
|
}
|
|
480
|
+
ctx = this.contextManager.getConnectionContext(selector);
|
|
447
481
|
if (newClient) {
|
|
448
482
|
assert(newClient === client, "newClient must match existing client");
|
|
449
483
|
checkClientAndCVRVersions(client.version(), cvr.version);
|
|
@@ -452,12 +486,8 @@ var ViewSyncerService = class {
|
|
|
452
486
|
result = await fn(lc, clientID, body, cvr);
|
|
453
487
|
});
|
|
454
488
|
} catch (e) {
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
if (isTransformAuthFailure(e)) {
|
|
458
|
-
lc.debug?.("Auth failure detected in transform response");
|
|
459
|
-
this.clearAuth();
|
|
460
|
-
}
|
|
489
|
+
this.#lc.withContext("clientID", clientID).withContext("wsID", wsID).withContext("cmd", cmd)[getLogLevel(e)]?.(`closing connection with error`, e);
|
|
490
|
+
if (ctx) this.contextManager.failConnection(selector, ctx.revision);
|
|
461
491
|
if (client) client.fail(e);
|
|
462
492
|
else throw e;
|
|
463
493
|
}
|
|
@@ -468,10 +498,10 @@ var ViewSyncerService = class {
|
|
|
468
498
|
const clients = [...this.#clients.values()];
|
|
469
499
|
return atVersion ? clients.filter((c) => cmpVersions(c.version() ?? EMPTY_CVR_VERSION, atVersion) === 0) : clients;
|
|
470
500
|
}
|
|
471
|
-
#handleConfigUpdate = (lc, clientID, { clientSchema, deleted, desiredQueriesPatch, activeClients }, cvr, customQueryTransformMode, profileID) => startAsyncSpan(tracer, "vs.#handleConfigUpdate", async () => {
|
|
501
|
+
#handleConfigUpdate = (lc, clientID, { clientSchema, deleted, desiredQueriesPatch, activeClients }, cvr, customQueryTransformMode, profileID, ctx) => startAsyncSpan(tracer, "vs.#handleConfigUpdate", async () => {
|
|
472
502
|
const deletedClientIDs = [];
|
|
473
503
|
const deletedClientGroupIDs = [];
|
|
474
|
-
cvr = await this.#updateCVRConfig(lc, cvr, clientID, customQueryTransformMode, (updater) => {
|
|
504
|
+
cvr = await this.#updateCVRConfig(lc, cvr, clientID, customQueryTransformMode, ctx, (updater) => {
|
|
475
505
|
const { ttlClock } = cvr;
|
|
476
506
|
const patches = [];
|
|
477
507
|
if (clientSchema) updater.setClientSchema(lc, clientSchema);
|
|
@@ -568,16 +598,17 @@ var ViewSyncerService = class {
|
|
|
568
598
|
let customHashMismatchCount = 0;
|
|
569
599
|
let otherHashMismatchCount = 0;
|
|
570
600
|
if (customQueries.size > 0 && !this.#customQueryTransformer) lc.warn?.("Custom/named queries were requested but no `ZERO_QUERY_URL` is configured for Zero Cache.");
|
|
601
|
+
const backgroundContext = this.contextManager.mustGetBackgroundConnectionContext();
|
|
571
602
|
const customQueryTransformer = this.#customQueryTransformer;
|
|
572
603
|
if (customQueryTransformer && customQueries.size > 0) {
|
|
573
|
-
const transformedCustomQueries = await this.#runPriorityOp(lc, "#hydrateUnchangedQueries transforming custom queries", () => customQueryTransformer.transform(
|
|
574
|
-
if (
|
|
604
|
+
const transformedCustomQueries = await this.#runPriorityOp(lc, "#hydrateUnchangedQueries transforming custom queries", () => customQueryTransformer.transform(backgroundContext, customQueries.values()));
|
|
605
|
+
if (!transformedCustomQueries.cached) this.contextManager.validateConnection(backgroundContext, backgroundContext.revision);
|
|
606
|
+
if (Array.isArray(transformedCustomQueries.result)) for (const q of transformedCustomQueries.result) if ("error" in q) customErrorCount++;
|
|
575
607
|
else if (q.transformationHash !== customQueries.get(q.id)?.transformationHash) customHashMismatchCount++;
|
|
576
608
|
else transformedQueries.push(q);
|
|
577
609
|
}
|
|
578
610
|
for (const q of otherQueries) {
|
|
579
|
-
const
|
|
580
|
-
const transformed = transformAndHashQuery(lc, q.id, q.ast, must(this.#pipelines.currentPermissions()).permissions ?? { tables: {} }, auth?.type === "jwt" ? auth : void 0, q.type === "internal");
|
|
611
|
+
const transformed = transformAndHashQuery(lc, q.id, q.ast, must(this.#pipelines.currentPermissions()).permissions ?? { tables: {} }, backgroundContext.auth?.type === "jwt" ? backgroundContext.auth : void 0, q.type === "internal");
|
|
581
612
|
if (transformed.transformationHash === q.transformationHash) transformedQueries.push(transformed);
|
|
582
613
|
else otherHashMismatchCount++;
|
|
583
614
|
}
|
|
@@ -650,8 +681,9 @@ var ViewSyncerService = class {
|
|
|
650
681
|
*
|
|
651
682
|
* This must be called from within the #lock.
|
|
652
683
|
*/
|
|
653
|
-
#syncQueryPipelineSet(lc, cvr, customQueryTransformMode) {
|
|
654
|
-
return startAsyncSpan(tracer, "vs.#syncQueryPipelineSet", async () => {
|
|
684
|
+
#syncQueryPipelineSet(lc, cvr, customQueryTransformMode, ctx) {
|
|
685
|
+
return startAsyncSpan(tracer, "vs.#syncQueryPipelineSet", async (span) => {
|
|
686
|
+
span.setAttribute("clientGroupID", this.id);
|
|
655
687
|
assert(this.#pipelines.initialized(), "pipelines must be initialized (syncQueryPipelineSet)");
|
|
656
688
|
if (this.#ttlClock === void 0) this.#ttlClock = cvr.ttlClock;
|
|
657
689
|
const now = Date.now();
|
|
@@ -660,6 +692,7 @@ var ViewSyncerService = class {
|
|
|
660
692
|
const customQueries = /* @__PURE__ */ new Map();
|
|
661
693
|
const otherQueries = [];
|
|
662
694
|
const transformedQueries = [];
|
|
695
|
+
const resolvedContext = ctx ?? this.contextManager.mustGetBackgroundConnectionContext();
|
|
663
696
|
for (const [id, query] of cvrQueryEntires) if (query.type === "custom") {
|
|
664
697
|
assert(id === query.id, "custom query id mismatch");
|
|
665
698
|
customQueries.set(id, query);
|
|
@@ -669,8 +702,7 @@ var ViewSyncerService = class {
|
|
|
669
702
|
});
|
|
670
703
|
for (const { id, query: origQuery } of otherQueries) {
|
|
671
704
|
assert(id === origQuery.id, "query id mismatch");
|
|
672
|
-
const
|
|
673
|
-
const transformed = transformAndHashQuery(lc, origQuery.id, origQuery.ast, must(this.#pipelines.currentPermissions()).permissions ?? { tables: {} }, auth?.type === "jwt" ? auth : void 0, origQuery.type === "internal");
|
|
705
|
+
const transformed = transformAndHashQuery(lc, origQuery.id, origQuery.ast, must(this.#pipelines.currentPermissions()).permissions ?? { tables: {} }, resolvedContext.auth?.type === "jwt" ? resolvedContext.auth : void 0, origQuery.type === "internal");
|
|
674
706
|
transformedQueries.push({
|
|
675
707
|
id,
|
|
676
708
|
origQuery,
|
|
@@ -685,9 +717,12 @@ var ViewSyncerService = class {
|
|
|
685
717
|
const transformStart = performance.now();
|
|
686
718
|
let transformedCustomQueries;
|
|
687
719
|
try {
|
|
688
|
-
transformedCustomQueries = await this.#runPriorityOp(lc, "#syncQueryPipelineSet transforming custom queries", () => customQueryTransformer.transform(
|
|
689
|
-
if (
|
|
690
|
-
else
|
|
720
|
+
transformedCustomQueries = await this.#runPriorityOp(lc, "#syncQueryPipelineSet transforming custom queries", () => customQueryTransformer.transform(resolvedContext, customQueriesToTransform));
|
|
721
|
+
if ("kind" in transformedCustomQueries.result) throw new ProtocolErrorWithLevel(transformedCustomQueries.result, "warn");
|
|
722
|
+
else {
|
|
723
|
+
if (!transformedCustomQueries.cached) this.contextManager.validateConnection(resolvedContext, resolvedContext.revision);
|
|
724
|
+
this.#queryTransformations.add(1, { result: "success" });
|
|
725
|
+
}
|
|
691
726
|
} catch (e) {
|
|
692
727
|
this.#queryTransformations.add(1, { result: "error" });
|
|
693
728
|
throw e;
|
|
@@ -696,7 +731,7 @@ var ViewSyncerService = class {
|
|
|
696
731
|
this.#queryTransformationTime.record(transformDuration);
|
|
697
732
|
}
|
|
698
733
|
const successfullyTransformedCustomQueries = /* @__PURE__ */ new Map();
|
|
699
|
-
erroredQueryIDs = this.#processTransformedCustomQueries(lc, transformedCustomQueries, (q) => {
|
|
734
|
+
erroredQueryIDs = this.#processTransformedCustomQueries(lc, transformedCustomQueries.result, (q) => {
|
|
700
735
|
const origQuery = customQueries.get(q.id);
|
|
701
736
|
if (origQuery) {
|
|
702
737
|
successfullyTransformedCustomQueries.set(q.id, q);
|
|
@@ -720,7 +755,7 @@ var ViewSyncerService = class {
|
|
|
720
755
|
}
|
|
721
756
|
}
|
|
722
757
|
}
|
|
723
|
-
const removeQueriesQueryIds = new Set(Object.values(cvr.queries).filter((q) => expired(ttlClock, q)).map((q) => q.id)
|
|
758
|
+
const removeQueriesQueryIds = new Set([...Object.values(cvr.queries).filter((q) => expired(ttlClock, q)).map((q) => q.id), ...erroredQueryIDs || []]);
|
|
724
759
|
const addQueries = transformedQueries.map(({ id, transformed }) => ({
|
|
725
760
|
id,
|
|
726
761
|
ast: transformed.transformedAst,
|
|
@@ -731,7 +766,7 @@ var ViewSyncerService = class {
|
|
|
731
766
|
const orig = cvr.queries[q.id];
|
|
732
767
|
lc.debug?.("ViewSyncer adding query", q.ast, "transformed from", orig.type === "custom" ? orig.name : orig.ast);
|
|
733
768
|
}
|
|
734
|
-
if (addQueries.length > 0 || removeQueriesQueryIds.size > 0) await this.#addAndRemoveQueries(lc, cvr, addQueries,
|
|
769
|
+
if (addQueries.length > 0 || removeQueriesQueryIds.size > 0) await this.#addAndRemoveQueries(lc, cvr, addQueries, Array.from(removeQueriesQueryIds, (id) => ({ id })));
|
|
735
770
|
else await this.#catchupClients(lc, cvr);
|
|
736
771
|
});
|
|
737
772
|
}
|
|
@@ -804,11 +839,13 @@ var ViewSyncerService = class {
|
|
|
804
839
|
hydrationTime.record(totalProcessTime / 1e3);
|
|
805
840
|
}
|
|
806
841
|
await this.#processChanges(lc, timer, generateRowChanges(this.#slowHydrateThreshold), updater, pokers);
|
|
807
|
-
|
|
842
|
+
await startAsyncSpan(tracer, "vs.#syncQueryPipelineSet.deleteUnreferencedRows", async () => {
|
|
843
|
+
for (const patch of await updater.deleteUnreferencedRows(lc)) await pokers.addPatch(patch);
|
|
844
|
+
});
|
|
808
845
|
this.#cvr = await this.#flushUpdater(lc, updater);
|
|
809
846
|
const finalVersion = this.#cvr.version;
|
|
810
847
|
await this.#catchupClients(lc, cvr, finalVersion, addQueries.map((q) => q.id), pokers);
|
|
811
|
-
await pokers.end(finalVersion);
|
|
848
|
+
await startAsyncSpan(tracer, "vs.#syncQueryPipelineSet.pokeEnd", () => pokers.end(finalVersion));
|
|
812
849
|
const wallTime = performance.now() - start;
|
|
813
850
|
lc.info?.(`finished processing queries (process: ${totalProcessTime} ms, wall: ${wallTime} ms)`);
|
|
814
851
|
});
|
|
@@ -889,7 +926,10 @@ var ViewSyncerService = class {
|
|
|
889
926
|
total += rows.size;
|
|
890
927
|
lc.debug?.(`processing ${rows.size} (of ${total}) rows (${wallElapsed} ms)`);
|
|
891
928
|
const patches = await updater.received(lc, rows);
|
|
892
|
-
|
|
929
|
+
await startAsyncSpan(tracer, "processBatch.flushToClient", async (span) => {
|
|
930
|
+
span.setAttribute("patches", patches.length);
|
|
931
|
+
for (const patch of patches) await pokers.addPatch(patch);
|
|
932
|
+
});
|
|
893
933
|
rows.clear();
|
|
894
934
|
});
|
|
895
935
|
await startAsyncSpan(tracer, "loopingChanges", async (span) => {
|
|
@@ -944,7 +984,8 @@ var ViewSyncerService = class {
|
|
|
944
984
|
* Returns false if the advancement failed due to a schema change.
|
|
945
985
|
*/
|
|
946
986
|
#advancePipelines(lc, cvr) {
|
|
947
|
-
return startAsyncSpan(tracer, "vs.#advancePipelines", async () => {
|
|
987
|
+
return startAsyncSpan(tracer, "vs.#advancePipelines", async (span) => {
|
|
988
|
+
span.setAttribute("clientGroupID", this.id);
|
|
948
989
|
assert(this.#pipelines.initialized(), "pipelines must be initialized (advancePipelines");
|
|
949
990
|
const start = performance.now();
|
|
950
991
|
const timer = new TimeSliceTimer(lc);
|
|
@@ -964,7 +1005,7 @@ var ViewSyncerService = class {
|
|
|
964
1005
|
}
|
|
965
1006
|
this.#cvr = await this.#flushUpdater(lc, updater);
|
|
966
1007
|
const finalVersion = this.#cvr.version;
|
|
967
|
-
await pokers.end(finalVersion);
|
|
1008
|
+
await startAsyncSpan(tracer, "vs.#advancePipelines.pokeEnd", () => pokers.end(finalVersion));
|
|
968
1009
|
const wallTime = performance.now() - start;
|
|
969
1010
|
const totalProcessTime = timer.totalElapsed();
|
|
970
1011
|
lc.info?.(`finished processing advancement of ${numChanges} changes ((process: ${totalProcessTime} ms, wall: ${wallTime} ms))`);
|
|
@@ -972,14 +1013,86 @@ var ViewSyncerService = class {
|
|
|
972
1013
|
return "success";
|
|
973
1014
|
});
|
|
974
1015
|
}
|
|
975
|
-
async inspect(
|
|
976
|
-
await this.#runInLockForClient(
|
|
1016
|
+
async inspect(selector, msg) {
|
|
1017
|
+
await this.#runInLockForClient(selector, msg, this.#handleInspect);
|
|
977
1018
|
}
|
|
978
1019
|
#handleInspect = async (lc, clientID, body, cvr) => {
|
|
979
1020
|
const client = must(this.#clients.get(clientID));
|
|
980
|
-
const
|
|
981
|
-
|
|
1021
|
+
const ctx = this.contextManager.mustGetConnectionContext({
|
|
1022
|
+
clientID,
|
|
1023
|
+
wsID: client.wsID
|
|
1024
|
+
});
|
|
1025
|
+
return handleInspect(lc, body, cvr, client, this.#inspectorDelegate, this.id, this.#cvrStore, this.#config, ctx);
|
|
982
1026
|
};
|
|
1027
|
+
async #runBackgroundRetransform(lc) {
|
|
1028
|
+
const attemptRetransform = async (connection) => {
|
|
1029
|
+
await this.#syncQueryPipelineSet(lc, must(this.#cvr, "cvr missing during auth maintenance retransform"), "all", connection);
|
|
1030
|
+
this.contextManager.markBackgroundRetransformSuccess({
|
|
1031
|
+
clientID: connection.clientID,
|
|
1032
|
+
wsID: connection.wsID
|
|
1033
|
+
}, connection.revision);
|
|
1034
|
+
};
|
|
1035
|
+
let backgroundConnection = this.contextManager.getBackgroundConnectionContext();
|
|
1036
|
+
if (!backgroundConnection) {
|
|
1037
|
+
lc.debug?.("Skipping background retransform with no selected connection");
|
|
1038
|
+
return;
|
|
1039
|
+
}
|
|
1040
|
+
for (;;) {
|
|
1041
|
+
try {
|
|
1042
|
+
await attemptRetransform(backgroundConnection);
|
|
1043
|
+
return;
|
|
1044
|
+
} catch (e) {
|
|
1045
|
+
if (isProtocolError(e)) {
|
|
1046
|
+
if (isAuthErrorBody(e.errorBody)) {
|
|
1047
|
+
lc.warn?.("Background retransform auth failed; failing connection and searching for replacement", {
|
|
1048
|
+
clientID: backgroundConnection.clientID,
|
|
1049
|
+
message: e.message
|
|
1050
|
+
});
|
|
1051
|
+
this.#failMaintenanceConnection(backgroundConnection, e);
|
|
1052
|
+
} else if (isTransformFailedError(e)) {
|
|
1053
|
+
lc.warn?.("Background retransform failed; deferring auth maintenance", {
|
|
1054
|
+
clientID: backgroundConnection.clientID,
|
|
1055
|
+
message: e.message
|
|
1056
|
+
});
|
|
1057
|
+
this.contextManager.deferMaintenance("retransform");
|
|
1058
|
+
return;
|
|
1059
|
+
}
|
|
1060
|
+
} else throw e;
|
|
1061
|
+
}
|
|
1062
|
+
const replacement = this.contextManager.getBackgroundConnectionContext();
|
|
1063
|
+
if (!replacement) {
|
|
1064
|
+
lc.debug?.("No replacement connection available for background retransform");
|
|
1065
|
+
return;
|
|
1066
|
+
}
|
|
1067
|
+
lc.debug?.("Retrying background retransform with replacement connection", {
|
|
1068
|
+
clientID: replacement.clientID,
|
|
1069
|
+
wsID: replacement.wsID
|
|
1070
|
+
});
|
|
1071
|
+
backgroundConnection = replacement;
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1074
|
+
async #validateConnection(ctx) {
|
|
1075
|
+
try {
|
|
1076
|
+
if (this.#customQueryTransformer) {
|
|
1077
|
+
const validation = await this.#customQueryTransformer.validate(ctx);
|
|
1078
|
+
if (validation !== void 0) throw new ProtocolErrorWithLevel(validation, "warn");
|
|
1079
|
+
}
|
|
1080
|
+
this.contextManager.validateConnection(ctx, ctx.revision);
|
|
1081
|
+
return true;
|
|
1082
|
+
} catch (e) {
|
|
1083
|
+
if (isProtocolError(e) && isAuthErrorBody(e.errorBody)) {
|
|
1084
|
+
this.#failMaintenanceConnection(ctx, e);
|
|
1085
|
+
return false;
|
|
1086
|
+
}
|
|
1087
|
+
throw e;
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1090
|
+
#failMaintenanceConnection(ctx, error) {
|
|
1091
|
+
if (!this.contextManager.failConnection(ctx, ctx.revision)) return;
|
|
1092
|
+
const wrapped = wrapWithProtocolError(error);
|
|
1093
|
+
const client = this.#clients.get(ctx.clientID);
|
|
1094
|
+
if (client?.wsID === ctx.wsID) client.fail(wrapped);
|
|
1095
|
+
}
|
|
983
1096
|
stop() {
|
|
984
1097
|
this.#lc.info?.("stopping view syncer");
|
|
985
1098
|
this.#initialized.reject("shut down before initialization completed");
|
|
@@ -987,9 +1100,9 @@ var ViewSyncerService = class {
|
|
|
987
1100
|
return this.#stopped.promise;
|
|
988
1101
|
}
|
|
989
1102
|
async #cleanup(err) {
|
|
990
|
-
this.clearAuth();
|
|
991
1103
|
this.#stopTTLClockInterval();
|
|
992
1104
|
this.#stopExpireTimer();
|
|
1105
|
+
this.#stopAuthMaintenanceTimer();
|
|
993
1106
|
for (const client of this.#clients.values()) if (err) client.fail(err);
|
|
994
1107
|
else client.close(`closed clientGroupID=${this.id}`);
|
|
995
1108
|
await this.#lock.withLock(() => {});
|
|
@@ -1025,9 +1138,8 @@ function checkClientAndCVRVersions(client, cvr) {
|
|
|
1025
1138
|
origin: ZeroCache
|
|
1026
1139
|
});
|
|
1027
1140
|
}
|
|
1028
|
-
function
|
|
1029
|
-
|
|
1030
|
-
return error.errorBody.kind === "TransformFailed" && error.errorBody.reason === "http" && (error.errorBody.status === 401 || error.errorBody.status === 403);
|
|
1141
|
+
function isTransformFailedError(error) {
|
|
1142
|
+
return error.errorBody.kind === "TransformFailed" && !isAuthErrorBody(error.errorBody);
|
|
1031
1143
|
}
|
|
1032
1144
|
/**
|
|
1033
1145
|
* A query must be expired for all clients in order to be considered
|