@rocicorp/zero 1.4.0-canary.5 → 1.5.0-canary.0
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/analyze-cli.js +2 -2
- package/out/analyze-query/src/analyze-cli.js.map +1 -1
- package/out/zero/package.js +1 -1
- package/out/zero/package.js.map +1 -1
- package/out/zero-cache/src/auth/auth.d.ts +1 -1
- package/out/zero-cache/src/auth/auth.d.ts.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/write-authorizer.d.ts +1 -1
- package/out/zero-cache/src/auth/write-authorizer.d.ts.map +1 -1
- package/out/zero-cache/src/auth/write-authorizer.js.map +1 -1
- package/out/zero-cache/src/config/normalize.d.ts.map +1 -1
- package/out/zero-cache/src/config/normalize.js +8 -0
- package/out/zero-cache/src/config/normalize.js.map +1 -1
- package/out/zero-cache/src/config/zero-config.d.ts +8 -4
- package/out/zero-cache/src/config/zero-config.d.ts.map +1 -1
- package/out/zero-cache/src/config/zero-config.js +28 -6
- package/out/zero-cache/src/config/zero-config.js.map +1 -1
- package/out/zero-cache/src/custom/fetch.d.ts +1 -1
- package/out/zero-cache/src/custom/fetch.d.ts.map +1 -1
- package/out/zero-cache/src/custom/fetch.js +2 -2
- package/out/zero-cache/src/custom/fetch.js.map +1 -1
- package/out/zero-cache/src/custom-queries/transform-query.d.ts +21 -7
- package/out/zero-cache/src/custom-queries/transform-query.d.ts.map +1 -1
- package/out/zero-cache/src/custom-queries/transform-query.js +26 -9
- package/out/zero-cache/src/custom-queries/transform-query.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 +2 -1
- package/out/zero-cache/src/server/change-streamer.js.map +1 -1
- package/out/zero-cache/src/server/runner/run-worker.d.ts.map +1 -1
- package/out/zero-cache/src/server/runner/run-worker.js +5 -2
- package/out/zero-cache/src/server/runner/run-worker.js.map +1 -1
- package/out/zero-cache/src/server/syncer.js +3 -3
- package/out/zero-cache/src/server/syncer.js.map +1 -1
- package/out/zero-cache/src/services/change-source/custom/change-source.js +2 -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 +24 -20
- package/out/zero-cache/src/services/change-source/pg/change-source.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/ddl.d.ts +258 -45
- package/out/zero-cache/src/services/change-source/pg/schema/ddl.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/ddl.js +119 -83
- 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/init.d.ts.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/shard.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/shard.js +11 -2
- package/out/zero-cache/src/services/change-source/pg/schema/shard.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer-http.d.ts +1 -0
- package/out/zero-cache/src/services/change-streamer/change-streamer-http.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer-http.js +3 -3
- package/out/zero-cache/src/services/change-streamer/change-streamer-http.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/http-service.d.ts +1 -0
- package/out/zero-cache/src/services/http-service.d.ts.map +1 -1
- package/out/zero-cache/src/services/http-service.js +5 -4
- package/out/zero-cache/src/services/http-service.js.map +1 -1
- package/out/zero-cache/src/services/life-cycle.d.ts +1 -1
- package/out/zero-cache/src/services/life-cycle.d.ts.map +1 -1
- package/out/zero-cache/src/services/life-cycle.js +1 -2
- package/out/zero-cache/src/services/life-cycle.js.map +1 -1
- package/out/zero-cache/src/services/mutagen/mutagen.d.ts +1 -1
- package/out/zero-cache/src/services/mutagen/mutagen.d.ts.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.d.ts +4 -3
- package/out/zero-cache/src/services/mutagen/pusher.d.ts.map +1 -1
- package/out/zero-cache/src/services/mutagen/pusher.js +57 -38
- package/out/zero-cache/src/services/mutagen/pusher.js.map +1 -1
- 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.map +1 -1
- package/out/zero-cache/src/services/shadow-sync/shadow-sync-service.js +2 -1
- package/out/zero-cache/src/services/shadow-sync/shadow-sync-service.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/client-handler.js +1 -1
- package/out/zero-cache/src/services/view-syncer/client-handler.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/connection-context-manager.d.ts +39 -27
- package/out/zero-cache/src/services/view-syncer/connection-context-manager.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/connection-context-manager.js +138 -102
- package/out/zero-cache/src/services/view-syncer/connection-context-manager.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 +22 -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 +6 -0
- package/out/zero-cache/src/services/view-syncer/cvr.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/cvr.js +8 -0
- package/out/zero-cache/src/services/view-syncer/cvr.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 +27 -3
- package/out/zero-cache/src/services/view-syncer/row-record-cache.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts +3 -3
- 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 +115 -86
- package/out/zero-cache/src/services/view-syncer/view-syncer.js.map +1 -1
- package/out/zero-cache/src/workers/connection.js +2 -2
- package/out/zero-cache/src/workers/connection.js.map +1 -1
- package/out/zero-cache/src/workers/syncer-ws-message-handler.d.ts +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 +7 -7
- package/out/zero-cache/src/workers/syncer-ws-message-handler.js.map +1 -1
- package/out/zero-cache/src/workers/syncer.d.ts +1 -1
- package/out/zero-cache/src/workers/syncer.d.ts.map +1 -1
- package/out/zero-cache/src/workers/syncer.js +11 -10
- package/out/zero-cache/src/workers/syncer.js.map +1 -1
- package/out/zero-client/src/client/connection.d.ts +15 -7
- 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/crud-impl.d.ts +1 -1
- package/out/zero-client/src/client/crud-impl.d.ts.map +1 -1
- package/out/zero-client/src/client/crud-impl.js +1 -1
- package/out/zero-client/src/client/crud-impl.js.map +1 -1
- package/out/zero-client/src/client/crud.d.ts +1 -1
- package/out/zero-client/src/client/crud.d.ts.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/keys.d.ts +1 -1
- package/out/zero-client/src/client/keys.d.ts.map +1 -1
- package/out/zero-client/src/client/keys.js.map +1 -1
- package/out/zero-client/src/client/make-replicache-mutators.js +1 -1
- package/out/zero-client/src/client/make-replicache-mutators.js.map +1 -1
- package/out/zero-client/src/client/mutation-tracker.d.ts +2 -1
- package/out/zero-client/src/client/mutation-tracker.d.ts.map +1 -1
- package/out/zero-client/src/client/mutation-tracker.js +3 -3
- package/out/zero-client/src/client/mutation-tracker.js.map +1 -1
- package/out/zero-client/src/client/version.js +1 -1
- package/out/zero-client/src/client/zero.d.ts.map +1 -1
- package/out/zero-client/src/client/zero.js +2 -2
- package/out/zero-client/src/client/zero.js.map +1 -1
- package/out/zero-client/src/types/client-state.d.ts +1 -1
- package/out/zero-client/src/types/client-state.d.ts.map +1 -1
- package/out/zero-protocol/src/custom-queries.js +1 -1
- package/out/zero-protocol/src/down.js +1 -1
- package/out/zero-protocol/src/error-kind-enum.d.ts +1 -2
- package/out/zero-protocol/src/error-kind-enum.d.ts.map +1 -1
- package/out/zero-protocol/src/error-kind-enum.js.map +1 -1
- package/out/zero-protocol/src/mutate-server.d.ts +165 -0
- package/out/zero-protocol/src/mutate-server.d.ts.map +1 -0
- package/out/zero-protocol/src/mutate-server.js +24 -0
- package/out/zero-protocol/src/mutate-server.js.map +1 -0
- package/out/zero-protocol/src/mutation.d.ts +229 -0
- package/out/zero-protocol/src/mutation.d.ts.map +1 -0
- package/out/zero-protocol/src/mutation.js +112 -0
- package/out/zero-protocol/src/mutation.js.map +1 -0
- 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/push.d.ts +3 -234
- package/out/zero-protocol/src/push.d.ts.map +1 -1
- package/out/zero-protocol/src/push.js +3 -114
- package/out/zero-protocol/src/push.js.map +1 -1
- package/out/zero-protocol/src/query-server.d.ts +150 -0
- package/out/zero-protocol/src/query-server.d.ts.map +1 -0
- package/out/zero-protocol/src/query-server.js +16 -0
- package/out/zero-protocol/src/query-server.js.map +1 -0
- package/out/zero-protocol/src/up.js +1 -1
- package/out/zero-server/src/mod.d.ts +4 -2
- package/out/zero-server/src/mod.d.ts.map +1 -1
- package/out/zero-server/src/process-mutations.d.ts +41 -4
- package/out/zero-server/src/process-mutations.d.ts.map +1 -1
- package/out/zero-server/src/process-mutations.js +52 -35
- package/out/zero-server/src/process-mutations.js.map +1 -1
- package/out/zero-server/src/push-processor.d.ts +3 -3
- package/out/zero-server/src/push-processor.d.ts.map +1 -1
- package/out/zero-server/src/push-processor.js.map +1 -1
- package/out/zero-server/src/queries/process-queries.d.ts +22 -52
- package/out/zero-server/src/queries/process-queries.d.ts.map +1 -1
- package/out/zero-server/src/queries/process-queries.js +50 -49
- package/out/zero-server/src/queries/process-queries.js.map +1 -1
- package/out/zero-server/src/zql-database.js.map +1 -1
- package/out/zero-types/src/default-types.d.ts +1 -0
- package/out/zero-types/src/default-types.d.ts.map +1 -1
- package/out/zql/src/builder/builder.d.ts.map +1 -1
- package/out/zql/src/builder/builder.js +17 -7
- package/out/zql/src/builder/builder.js.map +1 -1
- package/out/zql/src/ivm/cap.d.ts +32 -0
- package/out/zql/src/ivm/cap.d.ts.map +1 -0
- package/out/zql/src/ivm/cap.js +205 -0
- package/out/zql/src/ivm/cap.js.map +1 -0
- package/out/zql/src/ivm/constraint.js +1 -1
- package/out/zql/src/ivm/flipped-join.d.ts.map +1 -1
- package/out/zql/src/ivm/flipped-join.js +61 -15
- package/out/zql/src/ivm/flipped-join.js.map +1 -1
- package/out/zql/src/ivm/memory-source.d.ts.map +1 -1
- package/out/zql/src/ivm/memory-source.js +3 -4
- package/out/zql/src/ivm/memory-source.js.map +1 -1
- package/out/zql/src/ivm/schema.d.ts +8 -0
- package/out/zql/src/ivm/schema.d.ts.map +1 -1
- package/out/zql/src/ivm/take.js +2 -2
- package/out/zql/src/mutate/mutator-registry.js.map +1 -1
- package/out/zql/src/mutate/mutator.d.ts +11 -2
- package/out/zql/src/mutate/mutator.d.ts.map +1 -1
- package/out/zql/src/mutate/mutator.js.map +1 -1
- package/out/zql/src/query/query-registry.d.ts +9 -2
- package/out/zql/src/query/query-registry.d.ts.map +1 -1
- package/out/zql/src/query/query-registry.js.map +1 -1
- package/out/zqlite/src/table-source.d.ts.map +1 -1
- package/out/zqlite/src/table-source.js +4 -1
- package/out/zqlite/src/table-source.js.map +1 -1
- package/package.json +1 -1
|
@@ -11,6 +11,7 @@ import { transformAndHashQuery } from "../../auth/read-authorizer.js";
|
|
|
11
11
|
import { getOrCreateCounter, getOrCreateLatencyHistogram, getOrCreateUpDownCounter } from "../../observability/metrics.js";
|
|
12
12
|
import { rowIDString } from "../../types/row-key.js";
|
|
13
13
|
import "../replicator/schema/replication-state.js";
|
|
14
|
+
import { parseSignature } from "./row-set-signature.js";
|
|
14
15
|
import { ResetPipelinesSignal } from "./snapshotter.js";
|
|
15
16
|
import "./pipeline-driver.js";
|
|
16
17
|
import { randInt } from "../../../../shared/src/rand.js";
|
|
@@ -41,7 +42,7 @@ function randomID() {
|
|
|
41
42
|
var TTL_CLOCK_INTERVAL = 6e4;
|
|
42
43
|
var ViewSyncerService = class {
|
|
43
44
|
id;
|
|
44
|
-
|
|
45
|
+
connContextManager;
|
|
45
46
|
#shard;
|
|
46
47
|
#lc;
|
|
47
48
|
#pipelines;
|
|
@@ -94,13 +95,14 @@ var ViewSyncerService = class {
|
|
|
94
95
|
#queryTransformationNoOps = getOrCreateCounter("sync", "query.transformation-no-ops", "Number of times query transformation resulted in no-op (hash unchanged)");
|
|
95
96
|
#lockWaitTime = getOrCreateLatencyHistogram("sync", "lock-wait-time", "Time spent waiting to acquire the ViewSyncer lock.");
|
|
96
97
|
#pipelineResets = getOrCreateCounter("sync", "pipeline-resets", "Number of pipeline resets");
|
|
98
|
+
#rowSetSignatureDrifts = getOrCreateCounter("sync", "query.row-set-signature-drifts", "Number of times re-hydration of an unchanged query produced a different row-set signature than what is stored in the CVR (forcing a configVersion bump and full re-execution). Expected to be near-zero in steady state; persistent non-zero values indicate non-deterministic query execution (e.g. Cap operator picking different N-row subsets).");
|
|
97
99
|
#inspectorDelegate;
|
|
98
100
|
#config;
|
|
99
101
|
#runPriorityOp;
|
|
100
|
-
constructor(config, lc, shard, taskID, clientGroupID, cvrDb, pipelineDriver, versionChanges, drainCoordinator, slowHydrateThreshold, inspectorDelegate,
|
|
102
|
+
constructor(config, lc, shard, taskID, clientGroupID, cvrDb, pipelineDriver, versionChanges, drainCoordinator, slowHydrateThreshold, inspectorDelegate, connContextManager, customQueryTransformer, runPriorityOp, keepaliveMs = DEFAULT_KEEPALIVE_MS, setTimeoutFn = setTimeout.bind(globalThis)) {
|
|
101
103
|
this.#config = config;
|
|
102
104
|
this.id = clientGroupID;
|
|
103
|
-
this.
|
|
105
|
+
this.connContextManager = connContextManager;
|
|
104
106
|
this.#shard = shard;
|
|
105
107
|
this.#lc = lc;
|
|
106
108
|
this.#pipelines = pipelineDriver;
|
|
@@ -197,8 +199,8 @@ var ViewSyncerService = class {
|
|
|
197
199
|
return;
|
|
198
200
|
}
|
|
199
201
|
lc.info?.(`init pipelines@${version} (cvr@${cvrVer})`);
|
|
200
|
-
await this.#hydrateUnchangedQueries(lc, cvr);
|
|
201
|
-
await this.#syncQueryPipelineSet(lc, cvr, "missing", void 0);
|
|
202
|
+
const driftedQueryIDs = await this.#hydrateUnchangedQueries(lc, cvr);
|
|
203
|
+
await this.#syncQueryPipelineSet(lc, cvr, "missing", void 0, driftedQueryIDs);
|
|
202
204
|
this.#pipelinesSynced = true;
|
|
203
205
|
});
|
|
204
206
|
}
|
|
@@ -262,7 +264,7 @@ var ViewSyncerService = class {
|
|
|
262
264
|
return this.#clients.size === 0;
|
|
263
265
|
}
|
|
264
266
|
#deleteClientDueToDisconnect(clientID, client) {
|
|
265
|
-
this.
|
|
267
|
+
this.connContextManager.closeConnection({
|
|
266
268
|
clientID,
|
|
267
269
|
wsID: client.wsID
|
|
268
270
|
});
|
|
@@ -290,13 +292,10 @@ var ViewSyncerService = class {
|
|
|
290
292
|
* deadlines. The timer plumbing is intentionally separate from the actual
|
|
291
293
|
* revalidation/retransform work so future policy changes only need to update
|
|
292
294
|
* the maintenance workers, not the wakeup logic.
|
|
293
|
-
*
|
|
294
|
-
* This is intentionally cheap & idempotent, so it can be called frequently
|
|
295
|
-
* when upstream state might have changed.
|
|
296
295
|
*/
|
|
297
296
|
#scheduleAuthMaintenance(lc) {
|
|
298
297
|
this.#stopAuthMaintenanceTimer();
|
|
299
|
-
const plan = this.
|
|
298
|
+
const plan = this.connContextManager.planMaintenance();
|
|
300
299
|
if (plan.earliestDeadlineAt === void 0) {
|
|
301
300
|
lc.debug?.("No auth maintenance wakeup scheduled");
|
|
302
301
|
return;
|
|
@@ -306,13 +305,17 @@ var ViewSyncerService = class {
|
|
|
306
305
|
delay,
|
|
307
306
|
earliestDeadlineAt: plan.earliestDeadlineAt
|
|
308
307
|
});
|
|
309
|
-
this.#authMaintenanceTimer = this.#setTimeout(() => {
|
|
310
|
-
|
|
311
|
-
|
|
308
|
+
this.#authMaintenanceTimer = this.#setTimeout(async () => {
|
|
309
|
+
try {
|
|
310
|
+
this.#authMaintenanceTimer = 0;
|
|
311
|
+
await this.#runInLockWithCVR((lc, cvr) => this.#runAuthMaintenance(lc, cvr));
|
|
312
|
+
} catch (e) {
|
|
313
|
+
this.#stateChanges.fail(e instanceof Error ? e : new Error(String(e)));
|
|
314
|
+
}
|
|
312
315
|
}, delay);
|
|
313
316
|
}
|
|
314
317
|
async #runAuthMaintenance(lc, _cvr) {
|
|
315
|
-
const plan = this.
|
|
318
|
+
const plan = this.connContextManager.planMaintenance();
|
|
316
319
|
if (plan.dueRevalidations.length === 0 && !plan.dueRetransform) {
|
|
317
320
|
lc.debug?.("Auth maintenance woke up with no due work");
|
|
318
321
|
return;
|
|
@@ -321,52 +324,52 @@ var ViewSyncerService = class {
|
|
|
321
324
|
dueRevalidations: plan.dueRevalidations.length,
|
|
322
325
|
dueRetransform: plan.dueRetransform
|
|
323
326
|
});
|
|
324
|
-
for (const
|
|
325
|
-
await this.#validateConnection(
|
|
327
|
+
for (const connCtx of plan.dueRevalidations) try {
|
|
328
|
+
await this.#validateConnection(connCtx);
|
|
326
329
|
} catch (e) {
|
|
327
330
|
if (isProtocolError(e) && isTransformFailedError(e)) {
|
|
328
331
|
lc.warn?.("Scheduled auth revalidation failed; deferring auth maintenance", {
|
|
329
|
-
clientID:
|
|
330
|
-
wsID:
|
|
332
|
+
clientID: connCtx.clientID,
|
|
333
|
+
wsID: connCtx.wsID,
|
|
331
334
|
message: e.message
|
|
332
335
|
});
|
|
333
|
-
this.
|
|
336
|
+
this.connContextManager.deferMaintenance("revalidate");
|
|
334
337
|
return;
|
|
335
338
|
}
|
|
336
339
|
throw e;
|
|
337
340
|
}
|
|
338
|
-
if (this.
|
|
341
|
+
if (this.connContextManager.planMaintenance().dueRetransform) await this.#runBackgroundRetransform(lc);
|
|
339
342
|
}
|
|
340
343
|
initConnection(selector, initConnectionMessage) {
|
|
341
344
|
this.#lc.debug?.("viewSyncer.initConnection");
|
|
342
345
|
return startSpan(tracer, "vs.initConnection", () => {
|
|
343
|
-
const
|
|
344
|
-
const lc = this.#lc.withContext("clientID",
|
|
346
|
+
const connCtx = this.connContextManager.mustGetConnectionContext(selector);
|
|
347
|
+
const lc = this.#lc.withContext("clientID", connCtx.clientID).withContext("wsID", connCtx.wsID);
|
|
345
348
|
const downstream = Subscription.create({ cleanup: (_, err) => {
|
|
346
349
|
err ? lc[getLogLevel(err)]?.(`client closed with error`, err) : lc.info?.("client closed");
|
|
347
|
-
this.#deleteClientDueToDisconnect(
|
|
348
|
-
this.#activeClients.add(-1, { [PROTOCOL_VERSION_ATTR]:
|
|
350
|
+
this.#deleteClientDueToDisconnect(connCtx.clientID, newClient);
|
|
351
|
+
this.#activeClients.add(-1, { [PROTOCOL_VERSION_ATTR]: connCtx.protocolVersion });
|
|
349
352
|
} });
|
|
350
|
-
this.#activeClients.add(1, { [PROTOCOL_VERSION_ATTR]:
|
|
353
|
+
this.#activeClients.add(1, { [PROTOCOL_VERSION_ATTR]: connCtx.protocolVersion });
|
|
351
354
|
if (this.#clients.size === 0) this.#ttlClockBase = Date.now();
|
|
352
|
-
const newClient = new ClientHandler(lc, this.id,
|
|
353
|
-
this.#clients.get(
|
|
354
|
-
this.#clients.set(
|
|
355
|
-
startAsyncSpan(tracer, "vs.initConnection.async", () => this.#runInLockForClient(
|
|
355
|
+
const newClient = new ClientHandler(lc, this.id, connCtx.clientID, connCtx.wsID, this.#shard, connCtx.baseCookie, downstream);
|
|
356
|
+
this.#clients.get(connCtx.clientID)?.close(`replaced by wsID: ${connCtx.wsID}`);
|
|
357
|
+
this.#clients.set(connCtx.clientID, newClient);
|
|
358
|
+
startAsyncSpan(tracer, "vs.initConnection.async", () => this.#runInLockForClient(connCtx, initConnectionMessage, async (lc, clientID, msg, cvr) => {
|
|
356
359
|
if (cvr.clientSchema === null && !msg.clientSchema) throw new ProtocolErrorWithLevel({
|
|
357
360
|
kind: InvalidConnectionRequest,
|
|
358
361
|
message: "The initConnection message for a new client group must include client schema.",
|
|
359
362
|
origin: ZeroCache
|
|
360
363
|
}, "warn");
|
|
361
|
-
if (!await this.#validateConnection(
|
|
362
|
-
await this.#handleConfigUpdate(lc, clientID, msg, cvr, "all",
|
|
364
|
+
if (!await this.#validateConnection(connCtx)) return;
|
|
365
|
+
await this.#handleConfigUpdate(lc, clientID, msg, cvr, "all", connCtx.profileID ?? `cg${this.id}`, connCtx);
|
|
363
366
|
this.#initialized.resolve("initialized");
|
|
364
367
|
}, newClient)).catch((e) => newClient.fail(e));
|
|
365
368
|
return downstream;
|
|
366
369
|
});
|
|
367
370
|
}
|
|
368
371
|
async changeDesiredQueries(selector, msg) {
|
|
369
|
-
await this.#runInLockForClient(selector, msg, (lc, clientID, msg, cvr) => this.#handleConfigUpdate(lc, clientID, msg, cvr, "missing", void 0, this.
|
|
372
|
+
await this.#runInLockForClient(selector, msg, (lc, clientID, msg, cvr) => this.#handleConfigUpdate(lc, clientID, msg, cvr, "missing", void 0, this.connContextManager.mustGetConnectionContext(selector)));
|
|
370
373
|
}
|
|
371
374
|
async updateAuth(selector, msg, authRevisionChanged) {
|
|
372
375
|
await this.#runInLockForClient(selector, msg, async (lc, clientID, _, cvr) => {
|
|
@@ -375,15 +378,15 @@ var ViewSyncerService = class {
|
|
|
375
378
|
return;
|
|
376
379
|
}
|
|
377
380
|
lc.debug?.("Auth changed, re-validating and re-transforming queries");
|
|
378
|
-
const
|
|
381
|
+
const connCtx = this.connContextManager.mustGetConnectionContext(selector);
|
|
379
382
|
if (!this.#pipelinesSynced) {
|
|
380
|
-
if (!await this.#validateConnection(
|
|
383
|
+
if (!await this.#validateConnection(connCtx)) return;
|
|
381
384
|
}
|
|
382
|
-
return await this.#handleConfigUpdate(lc, clientID, {}, cvr, "all", void 0,
|
|
385
|
+
return await this.#handleConfigUpdate(lc, clientID, {}, cvr, "all", void 0, connCtx);
|
|
383
386
|
});
|
|
384
387
|
}
|
|
385
388
|
async deleteClients(selector, msg) {
|
|
386
|
-
return await this.#runInLockForClient(selector, [msg[0], { deleted: msg[1] }], (lc, clientID, msg, cvr) => this.#handleConfigUpdate(lc, clientID, msg, cvr, "missing", void 0, this.
|
|
389
|
+
return await this.#runInLockForClient(selector, [msg[0], { deleted: msg[1] }], (lc, clientID, msg, cvr) => this.#handleConfigUpdate(lc, clientID, msg, cvr, "missing", void 0, this.connContextManager.mustGetConnectionContext(selector))) ?? [];
|
|
387
390
|
}
|
|
388
391
|
#getTTLClock(now) {
|
|
389
392
|
const delta = now - this.#ttlClockBase;
|
|
@@ -425,7 +428,7 @@ var ViewSyncerService = class {
|
|
|
425
428
|
lc.warn?.("failed to update TTL clock", rid, `after ${Date.now() - start} ms`, e);
|
|
426
429
|
});
|
|
427
430
|
}
|
|
428
|
-
async #updateCVRConfig(lc, cvr, clientID, customQueryTransformMode,
|
|
431
|
+
async #updateCVRConfig(lc, cvr, clientID, customQueryTransformMode, connCtx, fn) {
|
|
429
432
|
const updater = new CVRConfigDrivenUpdater(this.#cvrStore, cvr, this.#shard);
|
|
430
433
|
updater.ensureClient(clientID);
|
|
431
434
|
const patches = fn(updater);
|
|
@@ -438,7 +441,7 @@ var ViewSyncerService = class {
|
|
|
438
441
|
await pokers.end(newCVR.version);
|
|
439
442
|
});
|
|
440
443
|
}
|
|
441
|
-
if (this.#pipelinesSynced) await this.#syncQueryPipelineSet(lc, this.#cvr, customQueryTransformMode,
|
|
444
|
+
if (this.#pipelinesSynced) await this.#syncQueryPipelineSet(lc, this.#cvr, customQueryTransformMode, connCtx);
|
|
442
445
|
return this.#cvr;
|
|
443
446
|
}
|
|
444
447
|
/**
|
|
@@ -455,7 +458,7 @@ var ViewSyncerService = class {
|
|
|
455
458
|
span.setAttribute("clientID", clientID);
|
|
456
459
|
let client;
|
|
457
460
|
let result;
|
|
458
|
-
let
|
|
461
|
+
let connCtx;
|
|
459
462
|
try {
|
|
460
463
|
await this.#runInLockWithCVR(async (lc, cvr) => {
|
|
461
464
|
lc = lc.withContext("clientID", clientID).withContext("wsID", wsID).withContext("cmd", cmd);
|
|
@@ -465,7 +468,7 @@ var ViewSyncerService = class {
|
|
|
465
468
|
lc.debug?.("mismatched wsID", client?.wsID, wsID);
|
|
466
469
|
return;
|
|
467
470
|
}
|
|
468
|
-
|
|
471
|
+
connCtx = this.connContextManager.getConnectionContext(selector);
|
|
469
472
|
if (newClient) {
|
|
470
473
|
assert(newClient === client, "newClient must match existing client");
|
|
471
474
|
checkClientAndCVRVersions(client.version(), cvr.version);
|
|
@@ -475,7 +478,7 @@ var ViewSyncerService = class {
|
|
|
475
478
|
});
|
|
476
479
|
} catch (e) {
|
|
477
480
|
this.#lc.withContext("clientID", clientID).withContext("wsID", wsID).withContext("cmd", cmd)[getLogLevel(e)]?.(`closing connection with error`, e);
|
|
478
|
-
if (
|
|
481
|
+
if (connCtx) this.connContextManager.failConnection(selector, connCtx.revision);
|
|
479
482
|
if (client) client.fail(e);
|
|
480
483
|
else throw e;
|
|
481
484
|
}
|
|
@@ -486,10 +489,10 @@ var ViewSyncerService = class {
|
|
|
486
489
|
const clients = [...this.#clients.values()];
|
|
487
490
|
return atVersion ? clients.filter((c) => cmpVersions(c.version() ?? EMPTY_CVR_VERSION, atVersion) === 0) : clients;
|
|
488
491
|
}
|
|
489
|
-
#handleConfigUpdate = (lc, clientID, { clientSchema, deleted, desiredQueriesPatch, activeClients }, cvr, customQueryTransformMode, profileID,
|
|
492
|
+
#handleConfigUpdate = (lc, clientID, { clientSchema, deleted, desiredQueriesPatch, activeClients }, cvr, customQueryTransformMode, profileID, connCtx) => startAsyncSpan(tracer, "vs.#handleConfigUpdate", async () => {
|
|
490
493
|
const deletedClientIDs = [];
|
|
491
494
|
const deletedClientGroupIDs = [];
|
|
492
|
-
cvr = await this.#updateCVRConfig(lc, cvr, clientID, customQueryTransformMode,
|
|
495
|
+
cvr = await this.#updateCVRConfig(lc, cvr, clientID, customQueryTransformMode, connCtx, (updater) => {
|
|
493
496
|
const { ttlClock } = cvr;
|
|
494
497
|
const patches = [];
|
|
495
498
|
if (clientSchema) updater.setClientSchema(lc, clientSchema);
|
|
@@ -567,7 +570,7 @@ var ViewSyncerService = class {
|
|
|
567
570
|
const cvrVersion = cvr.version;
|
|
568
571
|
if (cvrVersion.stateVersion !== dbVersion) {
|
|
569
572
|
lc.info?.(`CVR (${versionToCookie(cvrVersion)}) is behind db ${dbVersion}`);
|
|
570
|
-
return;
|
|
573
|
+
return /* @__PURE__ */ new Set();
|
|
571
574
|
}
|
|
572
575
|
const gotQueries = Object.entries(cvr.queries).filter(([_, state]) => state.transformationHash !== void 0);
|
|
573
576
|
const customQueries = /* @__PURE__ */ new Map();
|
|
@@ -586,11 +589,11 @@ var ViewSyncerService = class {
|
|
|
586
589
|
let customHashMismatchCount = 0;
|
|
587
590
|
let otherHashMismatchCount = 0;
|
|
588
591
|
if (customQueries.size > 0 && !this.#customQueryTransformer) lc.warn?.("Custom/named queries were requested but no `ZERO_QUERY_URL` is configured for Zero Cache.");
|
|
589
|
-
const backgroundContext = this.
|
|
592
|
+
const backgroundContext = this.connContextManager.mustGetBackgroundConnectionContext();
|
|
590
593
|
const customQueryTransformer = this.#customQueryTransformer;
|
|
591
594
|
if (customQueryTransformer && customQueries.size > 0) {
|
|
592
595
|
const transformedCustomQueries = await this.#runPriorityOp(lc, "#hydrateUnchangedQueries transforming custom queries", () => customQueryTransformer.transform(backgroundContext, customQueries.values()));
|
|
593
|
-
if (!transformedCustomQueries.cached) this.
|
|
596
|
+
if (transformedCustomQueries.kind === "success" && !transformedCustomQueries.cached) this.connContextManager.validateConnection(backgroundContext, backgroundContext.revision, transformedCustomQueries.validation);
|
|
594
597
|
if (Array.isArray(transformedCustomQueries.result)) for (const q of transformedCustomQueries.result) if ("error" in q) customErrorCount++;
|
|
595
598
|
else if (q.transformationHash !== customQueries.get(q.id)?.transformationHash) customHashMismatchCount++;
|
|
596
599
|
else transformedQueries.push(q);
|
|
@@ -601,6 +604,7 @@ var ViewSyncerService = class {
|
|
|
601
604
|
else otherHashMismatchCount++;
|
|
602
605
|
}
|
|
603
606
|
lc.info?.(`hydrateUnchangedQueries: ${gotQueries.length} got queries, ${inactivatedCount} inactivated, ${customErrorCount} custom transform errors, ${customHashMismatchCount} custom hash mismatches, ${otherHashMismatchCount} other hash mismatches, ${transformedQueries.length} hydrated`);
|
|
607
|
+
const driftedQueryIDs = /* @__PURE__ */ new Set();
|
|
604
608
|
for (const { id: queryID, transformationHash, transformedAst } of transformedQueries) {
|
|
605
609
|
const timer = new TimeSliceTimer(lc);
|
|
606
610
|
let count = 0;
|
|
@@ -616,7 +620,19 @@ var ViewSyncerService = class {
|
|
|
616
620
|
this.#hydrationTime.recordMs(elapsed);
|
|
617
621
|
this.#addQueryMaterializationServerMetric(transformationHash, elapsed);
|
|
618
622
|
lc.debug?.(`hydrated ${count} rows for ${queryID} (${elapsed} ms)`);
|
|
623
|
+
const storedSigHex = cvr.queries[queryID]?.rowSetSignature;
|
|
624
|
+
if (storedSigHex !== void 0 && storedSigHex !== null) {
|
|
625
|
+
const priorSig = parseSignature(storedSigHex);
|
|
626
|
+
const candidateSig = this.#pipelines.rowSetSignature(queryID) ?? 0n;
|
|
627
|
+
if (priorSig !== candidateSig) {
|
|
628
|
+
lc.warn?.(`rowSetSignature drift for query ${queryID}: prior=${priorSig.toString(16)} new=${candidateSig.toString(16)} (${count} rows). Removing from pipelines for full re-execution.`);
|
|
629
|
+
this.#rowSetSignatureDrifts.add(1);
|
|
630
|
+
this.#pipelines.removeQuery(queryID);
|
|
631
|
+
driftedQueryIDs.add(queryID);
|
|
632
|
+
}
|
|
633
|
+
}
|
|
619
634
|
}
|
|
635
|
+
return driftedQueryIDs;
|
|
620
636
|
}
|
|
621
637
|
#processTransformedCustomQueries(lc, transformedCustomQueries, cb, customQueryMap) {
|
|
622
638
|
if ("kind" in transformedCustomQueries) {
|
|
@@ -669,7 +685,7 @@ var ViewSyncerService = class {
|
|
|
669
685
|
*
|
|
670
686
|
* This must be called from within the #lock.
|
|
671
687
|
*/
|
|
672
|
-
#syncQueryPipelineSet(lc, cvr, customQueryTransformMode,
|
|
688
|
+
#syncQueryPipelineSet(lc, cvr, customQueryTransformMode, connCtx, driftedQueryIDs = /* @__PURE__ */ new Set()) {
|
|
673
689
|
return startAsyncSpan(tracer, "vs.#syncQueryPipelineSet", async (span) => {
|
|
674
690
|
span.setAttribute("clientGroupID", this.id);
|
|
675
691
|
assert(this.#pipelines.initialized(), "pipelines must be initialized (syncQueryPipelineSet)");
|
|
@@ -680,7 +696,7 @@ var ViewSyncerService = class {
|
|
|
680
696
|
const customQueries = /* @__PURE__ */ new Map();
|
|
681
697
|
const otherQueries = [];
|
|
682
698
|
const transformedQueries = [];
|
|
683
|
-
const
|
|
699
|
+
const resolvedConnCtx = connCtx ?? this.connContextManager.mustGetBackgroundConnectionContext();
|
|
684
700
|
for (const [id, query] of cvrQueryEntires) if (query.type === "custom") {
|
|
685
701
|
assert(id === query.id, "custom query id mismatch");
|
|
686
702
|
customQueries.set(id, query);
|
|
@@ -690,7 +706,7 @@ var ViewSyncerService = class {
|
|
|
690
706
|
});
|
|
691
707
|
for (const { id, query: origQuery } of otherQueries) {
|
|
692
708
|
assert(id === origQuery.id, "query id mismatch");
|
|
693
|
-
const transformed = transformAndHashQuery(lc, origQuery.id, origQuery.ast, must(this.#pipelines.currentPermissions()).permissions ?? { tables: {} },
|
|
709
|
+
const transformed = transformAndHashQuery(lc, origQuery.id, origQuery.ast, must(this.#pipelines.currentPermissions()).permissions ?? { tables: {} }, resolvedConnCtx.auth?.type === "jwt" ? resolvedConnCtx.auth : void 0, origQuery.type === "internal");
|
|
694
710
|
transformedQueries.push({
|
|
695
711
|
id,
|
|
696
712
|
origQuery,
|
|
@@ -705,10 +721,10 @@ var ViewSyncerService = class {
|
|
|
705
721
|
const transformStart = performance.now();
|
|
706
722
|
let transformedCustomQueries;
|
|
707
723
|
try {
|
|
708
|
-
transformedCustomQueries = await this.#runPriorityOp(lc, "#syncQueryPipelineSet transforming custom queries", () => customQueryTransformer.transform(
|
|
709
|
-
if (
|
|
724
|
+
transformedCustomQueries = await this.#runPriorityOp(lc, "#syncQueryPipelineSet transforming custom queries", () => customQueryTransformer.transform(resolvedConnCtx, customQueriesToTransform));
|
|
725
|
+
if (transformedCustomQueries.kind === "failed") throw new ProtocolErrorWithLevel(transformedCustomQueries.result, "warn");
|
|
710
726
|
else {
|
|
711
|
-
if (!transformedCustomQueries.cached) this.
|
|
727
|
+
if (!transformedCustomQueries.cached) this.connContextManager.validateConnection(resolvedConnCtx, resolvedConnCtx.revision, transformedCustomQueries.validation);
|
|
712
728
|
this.#queryTransformations.add(1, { result: "success" });
|
|
713
729
|
}
|
|
714
730
|
} catch (e) {
|
|
@@ -755,7 +771,7 @@ var ViewSyncerService = class {
|
|
|
755
771
|
const orig = cvr.queries[q.id];
|
|
756
772
|
lc.debug?.("ViewSyncer adding query", q.ast, "transformed from", orig.type === "custom" ? orig.name : orig.ast);
|
|
757
773
|
}
|
|
758
|
-
if (addQueries.length > 0 || removeQueriesQueryIds.size > 0) await this.#addAndRemoveQueries(lc, cvr, addQueries, Array.from(removeQueriesQueryIds, (id) => ({ id })));
|
|
774
|
+
if (addQueries.length > 0 || removeQueriesQueryIds.size > 0) await this.#addAndRemoveQueries(lc, cvr, addQueries, Array.from(removeQueriesQueryIds, (id) => ({ id })), driftedQueryIDs);
|
|
759
775
|
else await this.#catchupClients(lc, cvr);
|
|
760
776
|
});
|
|
761
777
|
}
|
|
@@ -787,7 +803,7 @@ var ViewSyncerService = class {
|
|
|
787
803
|
record.count++;
|
|
788
804
|
if (record.count >= THRASH_THRESHOLD) this.#lc.warn?.(`Query thrashing detected for query ${queryID}. ${record.count} replacements in 60s. This may indicate clients with different auth contexts connecting to the same client group.`);
|
|
789
805
|
}
|
|
790
|
-
#addAndRemoveQueries(lc, cvr, addQueries, removeQueries) {
|
|
806
|
+
#addAndRemoveQueries(lc, cvr, addQueries, removeQueries, driftedQueryIDs = /* @__PURE__ */ new Set()) {
|
|
791
807
|
return startAsyncSpan(tracer, "vs.#addAndRemoveQueries", async () => {
|
|
792
808
|
assert(addQueries.length > 0 || removeQueries.length > 0, "Must have queries to add or remove");
|
|
793
809
|
const start = performance.now();
|
|
@@ -795,9 +811,14 @@ var ViewSyncerService = class {
|
|
|
795
811
|
lc = lc.withContext("stateVersion", stateVersion);
|
|
796
812
|
lc.info?.(`hydrating ${addQueries.length} queries`);
|
|
797
813
|
const updater = new CVRQueryDrivenUpdater(this.#cvrStore, cvr, stateVersion, this.#pipelines.replicaVersion, (queryID) => this.#pipelines.rowSetSignature(queryID));
|
|
798
|
-
const {
|
|
814
|
+
const { queryPatches } = updater.trackQueries(lc, addQueries, removeQueries);
|
|
815
|
+
if (addQueries.some((q) => driftedQueryIDs.has(q.id))) updater.ensureNewVersion();
|
|
816
|
+
const newVersion = updater.updatedVersion();
|
|
799
817
|
const pokers = startPoke(this.#getClients(), newVersion);
|
|
800
|
-
for (const patch of queryPatches) await pokers.addPatch(
|
|
818
|
+
for (const patch of queryPatches) await pokers.addPatch({
|
|
819
|
+
...patch,
|
|
820
|
+
toVersion: newVersion
|
|
821
|
+
});
|
|
801
822
|
for (const q of removeQueries) {
|
|
802
823
|
this.#pipelines.removeQuery(q.id);
|
|
803
824
|
this.#inspectorDelegate.removeQuery(q.id);
|
|
@@ -1008,80 +1029,88 @@ var ViewSyncerService = class {
|
|
|
1008
1029
|
}
|
|
1009
1030
|
#handleInspect = async (lc, clientID, body, cvr) => {
|
|
1010
1031
|
const client = must(this.#clients.get(clientID));
|
|
1011
|
-
const
|
|
1032
|
+
const connCtx = this.connContextManager.mustGetConnectionContext({
|
|
1012
1033
|
clientID,
|
|
1013
1034
|
wsID: client.wsID
|
|
1014
1035
|
});
|
|
1015
|
-
return handleInspect(lc, body, cvr, client, this.#inspectorDelegate, this.id, this.#cvrStore, this.#config,
|
|
1036
|
+
return handleInspect(lc, body, cvr, client, this.#inspectorDelegate, this.id, this.#cvrStore, this.#config, connCtx);
|
|
1016
1037
|
};
|
|
1017
1038
|
async #runBackgroundRetransform(lc) {
|
|
1018
|
-
const attemptRetransform = async (
|
|
1019
|
-
await this.#syncQueryPipelineSet(lc, must(this.#cvr, "cvr missing during auth maintenance retransform"), "all",
|
|
1020
|
-
this.
|
|
1021
|
-
clientID:
|
|
1022
|
-
wsID:
|
|
1023
|
-
},
|
|
1039
|
+
const attemptRetransform = async (connCtx) => {
|
|
1040
|
+
await this.#syncQueryPipelineSet(lc, must(this.#cvr, "cvr missing during auth maintenance retransform"), "all", connCtx);
|
|
1041
|
+
this.connContextManager.markBackgroundRetransformSuccess({
|
|
1042
|
+
clientID: connCtx.clientID,
|
|
1043
|
+
wsID: connCtx.wsID
|
|
1044
|
+
}, connCtx.revision);
|
|
1024
1045
|
};
|
|
1025
|
-
let
|
|
1026
|
-
if (!
|
|
1046
|
+
let backgroundConnCtx = this.connContextManager.getBackgroundConnectionContext();
|
|
1047
|
+
if (!backgroundConnCtx) {
|
|
1027
1048
|
lc.debug?.("Skipping background retransform with no selected connection");
|
|
1028
1049
|
return;
|
|
1029
1050
|
}
|
|
1030
1051
|
for (;;) {
|
|
1031
1052
|
try {
|
|
1032
|
-
await attemptRetransform(
|
|
1053
|
+
await attemptRetransform(backgroundConnCtx);
|
|
1033
1054
|
return;
|
|
1034
1055
|
} catch (e) {
|
|
1035
1056
|
if (isProtocolError(e)) {
|
|
1036
1057
|
if (isAuthErrorBody(e.errorBody)) {
|
|
1037
1058
|
lc.warn?.("Background retransform auth failed; failing connection and searching for replacement", {
|
|
1038
|
-
clientID:
|
|
1059
|
+
clientID: backgroundConnCtx.clientID,
|
|
1039
1060
|
message: e.message
|
|
1040
1061
|
});
|
|
1041
|
-
this.#failMaintenanceConnection(
|
|
1062
|
+
this.#failMaintenanceConnection(backgroundConnCtx, e);
|
|
1042
1063
|
} else if (isTransformFailedError(e)) {
|
|
1043
1064
|
lc.warn?.("Background retransform failed; deferring auth maintenance", {
|
|
1044
|
-
clientID:
|
|
1065
|
+
clientID: backgroundConnCtx.clientID,
|
|
1045
1066
|
message: e.message
|
|
1046
1067
|
});
|
|
1047
|
-
this.
|
|
1068
|
+
this.connContextManager.deferMaintenance("retransform");
|
|
1048
1069
|
return;
|
|
1049
1070
|
}
|
|
1050
1071
|
} else throw e;
|
|
1051
1072
|
}
|
|
1052
|
-
const
|
|
1053
|
-
if (!
|
|
1073
|
+
const replacementConnCtx = this.connContextManager.getBackgroundConnectionContext();
|
|
1074
|
+
if (!replacementConnCtx) {
|
|
1054
1075
|
lc.debug?.("No replacement connection available for background retransform");
|
|
1055
1076
|
return;
|
|
1056
1077
|
}
|
|
1057
1078
|
lc.debug?.("Retrying background retransform with replacement connection", {
|
|
1058
|
-
clientID:
|
|
1059
|
-
wsID:
|
|
1079
|
+
clientID: replacementConnCtx.clientID,
|
|
1080
|
+
wsID: replacementConnCtx.wsID
|
|
1060
1081
|
});
|
|
1061
|
-
|
|
1082
|
+
backgroundConnCtx = replacementConnCtx;
|
|
1062
1083
|
}
|
|
1063
1084
|
}
|
|
1064
|
-
async #validateConnection(
|
|
1085
|
+
async #validateConnection(connCtx) {
|
|
1065
1086
|
try {
|
|
1087
|
+
let validation = void 0;
|
|
1066
1088
|
if (this.#customQueryTransformer) {
|
|
1067
|
-
const
|
|
1068
|
-
if (
|
|
1069
|
-
|
|
1070
|
-
|
|
1089
|
+
const response = await this.#customQueryTransformer.validate(connCtx);
|
|
1090
|
+
if (response.kind === "TransformFailed") throw new ProtocolErrorWithLevel(response, "warn");
|
|
1091
|
+
validation = response.validation;
|
|
1092
|
+
} else validation = { kind: "client-fallback" };
|
|
1093
|
+
this.connContextManager.validateConnection(connCtx, connCtx.revision, validation);
|
|
1071
1094
|
return true;
|
|
1072
1095
|
} catch (e) {
|
|
1073
1096
|
if (isProtocolError(e) && isAuthErrorBody(e.errorBody)) {
|
|
1074
|
-
this.#
|
|
1097
|
+
this.#lc.warn?.("Connection auth validation failed; invalidating connection", {
|
|
1098
|
+
clientID: connCtx.clientID,
|
|
1099
|
+
wsID: connCtx.wsID,
|
|
1100
|
+
revision: connCtx.revision,
|
|
1101
|
+
message: e.message
|
|
1102
|
+
});
|
|
1103
|
+
this.#failMaintenanceConnection(connCtx, e);
|
|
1075
1104
|
return false;
|
|
1076
1105
|
}
|
|
1077
1106
|
throw e;
|
|
1078
1107
|
}
|
|
1079
1108
|
}
|
|
1080
|
-
#failMaintenanceConnection(
|
|
1081
|
-
if (!this.
|
|
1109
|
+
#failMaintenanceConnection(connCtx, error) {
|
|
1110
|
+
if (!this.connContextManager.failConnection(connCtx, connCtx.revision)) return;
|
|
1082
1111
|
const wrapped = wrapWithProtocolError(error);
|
|
1083
|
-
const client = this.#clients.get(
|
|
1084
|
-
if (client?.wsID ===
|
|
1112
|
+
const client = this.#clients.get(connCtx.clientID);
|
|
1113
|
+
if (client?.wsID === connCtx.wsID) client.fail(wrapped);
|
|
1085
1114
|
}
|
|
1086
1115
|
stop() {
|
|
1087
1116
|
this.#lc.info?.("stopping view syncer");
|