@rocicorp/zero 1.4.0 → 1.5.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.
Files changed (189) hide show
  1. package/out/analyze-query/src/analyze-cli.js +2 -2
  2. package/out/analyze-query/src/analyze-cli.js.map +1 -1
  3. package/out/zero/package.js +1 -1
  4. package/out/zero/package.js.map +1 -1
  5. package/out/zero-cache/src/auth/auth.d.ts +1 -1
  6. package/out/zero-cache/src/auth/auth.d.ts.map +1 -1
  7. package/out/zero-cache/src/auth/auth.js +1 -1
  8. package/out/zero-cache/src/auth/auth.js.map +1 -1
  9. package/out/zero-cache/src/auth/write-authorizer.d.ts +1 -1
  10. package/out/zero-cache/src/auth/write-authorizer.d.ts.map +1 -1
  11. package/out/zero-cache/src/auth/write-authorizer.js.map +1 -1
  12. package/out/zero-cache/src/config/normalize.d.ts.map +1 -1
  13. package/out/zero-cache/src/config/normalize.js +8 -0
  14. package/out/zero-cache/src/config/normalize.js.map +1 -1
  15. package/out/zero-cache/src/config/zero-config.d.ts +8 -4
  16. package/out/zero-cache/src/config/zero-config.d.ts.map +1 -1
  17. package/out/zero-cache/src/config/zero-config.js +28 -6
  18. package/out/zero-cache/src/config/zero-config.js.map +1 -1
  19. package/out/zero-cache/src/custom/fetch.d.ts +1 -1
  20. package/out/zero-cache/src/custom/fetch.d.ts.map +1 -1
  21. package/out/zero-cache/src/custom/fetch.js +2 -2
  22. package/out/zero-cache/src/custom/fetch.js.map +1 -1
  23. package/out/zero-cache/src/custom-queries/transform-query.d.ts +21 -7
  24. package/out/zero-cache/src/custom-queries/transform-query.d.ts.map +1 -1
  25. package/out/zero-cache/src/custom-queries/transform-query.js +26 -9
  26. package/out/zero-cache/src/custom-queries/transform-query.js.map +1 -1
  27. package/out/zero-cache/src/server/change-streamer.d.ts.map +1 -1
  28. package/out/zero-cache/src/server/change-streamer.js +2 -1
  29. package/out/zero-cache/src/server/change-streamer.js.map +1 -1
  30. package/out/zero-cache/src/server/runner/run-worker.d.ts.map +1 -1
  31. package/out/zero-cache/src/server/runner/run-worker.js +5 -2
  32. package/out/zero-cache/src/server/runner/run-worker.js.map +1 -1
  33. package/out/zero-cache/src/server/syncer.js +3 -3
  34. package/out/zero-cache/src/server/syncer.js.map +1 -1
  35. package/out/zero-cache/src/services/change-source/custom/change-source.js +2 -2
  36. package/out/zero-cache/src/services/change-source/custom/change-source.js.map +1 -1
  37. package/out/zero-cache/src/services/change-source/pg/change-source.d.ts.map +1 -1
  38. package/out/zero-cache/src/services/change-source/pg/change-source.js +24 -20
  39. package/out/zero-cache/src/services/change-source/pg/change-source.js.map +1 -1
  40. package/out/zero-cache/src/services/change-source/pg/schema/ddl.d.ts +258 -45
  41. package/out/zero-cache/src/services/change-source/pg/schema/ddl.d.ts.map +1 -1
  42. package/out/zero-cache/src/services/change-source/pg/schema/ddl.js +119 -83
  43. package/out/zero-cache/src/services/change-source/pg/schema/ddl.js.map +1 -1
  44. package/out/zero-cache/src/services/change-source/pg/schema/init.d.ts.map +1 -1
  45. package/out/zero-cache/src/services/change-source/pg/schema/init.js +1 -1
  46. package/out/zero-cache/src/services/change-source/pg/schema/init.js.map +1 -1
  47. package/out/zero-cache/src/services/change-source/pg/schema/shard.d.ts.map +1 -1
  48. package/out/zero-cache/src/services/change-source/pg/schema/shard.js +2 -1
  49. package/out/zero-cache/src/services/change-source/pg/schema/shard.js.map +1 -1
  50. package/out/zero-cache/src/services/change-streamer/change-streamer-http.d.ts +1 -0
  51. package/out/zero-cache/src/services/change-streamer/change-streamer-http.d.ts.map +1 -1
  52. package/out/zero-cache/src/services/change-streamer/change-streamer-http.js +3 -3
  53. package/out/zero-cache/src/services/change-streamer/change-streamer-http.js.map +1 -1
  54. package/out/zero-cache/src/services/http-service.d.ts +1 -0
  55. package/out/zero-cache/src/services/http-service.d.ts.map +1 -1
  56. package/out/zero-cache/src/services/http-service.js +5 -4
  57. package/out/zero-cache/src/services/http-service.js.map +1 -1
  58. package/out/zero-cache/src/services/life-cycle.d.ts +1 -1
  59. package/out/zero-cache/src/services/life-cycle.d.ts.map +1 -1
  60. package/out/zero-cache/src/services/life-cycle.js +1 -2
  61. package/out/zero-cache/src/services/life-cycle.js.map +1 -1
  62. package/out/zero-cache/src/services/mutagen/mutagen.d.ts +1 -1
  63. package/out/zero-cache/src/services/mutagen/mutagen.d.ts.map +1 -1
  64. package/out/zero-cache/src/services/mutagen/mutagen.js +1 -1
  65. package/out/zero-cache/src/services/mutagen/mutagen.js.map +1 -1
  66. package/out/zero-cache/src/services/mutagen/pusher.d.ts +4 -3
  67. package/out/zero-cache/src/services/mutagen/pusher.d.ts.map +1 -1
  68. package/out/zero-cache/src/services/mutagen/pusher.js +57 -38
  69. package/out/zero-cache/src/services/mutagen/pusher.js.map +1 -1
  70. package/out/zero-cache/src/services/shadow-sync/shadow-sync-service.js +2 -1
  71. package/out/zero-cache/src/services/shadow-sync/shadow-sync-service.js.map +1 -1
  72. package/out/zero-cache/src/services/view-syncer/client-handler.js +1 -1
  73. package/out/zero-cache/src/services/view-syncer/client-handler.js.map +1 -1
  74. package/out/zero-cache/src/services/view-syncer/connection-context-manager.d.ts +41 -27
  75. package/out/zero-cache/src/services/view-syncer/connection-context-manager.d.ts.map +1 -1
  76. package/out/zero-cache/src/services/view-syncer/connection-context-manager.js +147 -104
  77. package/out/zero-cache/src/services/view-syncer/connection-context-manager.js.map +1 -1
  78. package/out/zero-cache/src/services/view-syncer/cvr.d.ts +6 -0
  79. package/out/zero-cache/src/services/view-syncer/cvr.d.ts.map +1 -1
  80. package/out/zero-cache/src/services/view-syncer/cvr.js +8 -0
  81. package/out/zero-cache/src/services/view-syncer/cvr.js.map +1 -1
  82. package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts +3 -3
  83. package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts.map +1 -1
  84. package/out/zero-cache/src/services/view-syncer/view-syncer.js +119 -86
  85. package/out/zero-cache/src/services/view-syncer/view-syncer.js.map +1 -1
  86. package/out/zero-cache/src/workers/connection.js +2 -2
  87. package/out/zero-cache/src/workers/connection.js.map +1 -1
  88. package/out/zero-cache/src/workers/syncer-ws-message-handler.d.ts +1 -1
  89. package/out/zero-cache/src/workers/syncer-ws-message-handler.d.ts.map +1 -1
  90. package/out/zero-cache/src/workers/syncer-ws-message-handler.js +7 -7
  91. package/out/zero-cache/src/workers/syncer-ws-message-handler.js.map +1 -1
  92. package/out/zero-cache/src/workers/syncer.d.ts +1 -1
  93. package/out/zero-cache/src/workers/syncer.d.ts.map +1 -1
  94. package/out/zero-cache/src/workers/syncer.js +11 -10
  95. package/out/zero-cache/src/workers/syncer.js.map +1 -1
  96. package/out/zero-client/src/client/connection.d.ts +15 -7
  97. package/out/zero-client/src/client/connection.d.ts.map +1 -1
  98. package/out/zero-client/src/client/connection.js.map +1 -1
  99. package/out/zero-client/src/client/crud-impl.d.ts +1 -1
  100. package/out/zero-client/src/client/crud-impl.d.ts.map +1 -1
  101. package/out/zero-client/src/client/crud-impl.js +1 -1
  102. package/out/zero-client/src/client/crud-impl.js.map +1 -1
  103. package/out/zero-client/src/client/crud.d.ts +1 -1
  104. package/out/zero-client/src/client/crud.d.ts.map +1 -1
  105. package/out/zero-client/src/client/crud.js +1 -1
  106. package/out/zero-client/src/client/crud.js.map +1 -1
  107. package/out/zero-client/src/client/keys.d.ts +1 -1
  108. package/out/zero-client/src/client/keys.d.ts.map +1 -1
  109. package/out/zero-client/src/client/keys.js.map +1 -1
  110. package/out/zero-client/src/client/make-replicache-mutators.js +1 -1
  111. package/out/zero-client/src/client/make-replicache-mutators.js.map +1 -1
  112. package/out/zero-client/src/client/mutation-tracker.d.ts +2 -1
  113. package/out/zero-client/src/client/mutation-tracker.d.ts.map +1 -1
  114. package/out/zero-client/src/client/mutation-tracker.js +3 -3
  115. package/out/zero-client/src/client/mutation-tracker.js.map +1 -1
  116. package/out/zero-client/src/client/version.js +1 -1
  117. package/out/zero-client/src/client/zero.d.ts.map +1 -1
  118. package/out/zero-client/src/client/zero.js +2 -2
  119. package/out/zero-client/src/client/zero.js.map +1 -1
  120. package/out/zero-client/src/types/client-state.d.ts +1 -1
  121. package/out/zero-client/src/types/client-state.d.ts.map +1 -1
  122. package/out/zero-protocol/src/custom-queries.js +1 -1
  123. package/out/zero-protocol/src/down.js +1 -1
  124. package/out/zero-protocol/src/error-kind-enum.d.ts +1 -2
  125. package/out/zero-protocol/src/error-kind-enum.d.ts.map +1 -1
  126. package/out/zero-protocol/src/error-kind-enum.js.map +1 -1
  127. package/out/zero-protocol/src/mutate-server.d.ts +165 -0
  128. package/out/zero-protocol/src/mutate-server.d.ts.map +1 -0
  129. package/out/zero-protocol/src/mutate-server.js +24 -0
  130. package/out/zero-protocol/src/mutate-server.js.map +1 -0
  131. package/out/zero-protocol/src/mutation.d.ts +229 -0
  132. package/out/zero-protocol/src/mutation.d.ts.map +1 -0
  133. package/out/zero-protocol/src/mutation.js +112 -0
  134. package/out/zero-protocol/src/mutation.js.map +1 -0
  135. package/out/zero-protocol/src/mutations-patch.js +1 -1
  136. package/out/zero-protocol/src/mutations-patch.js.map +1 -1
  137. package/out/zero-protocol/src/push.d.ts +3 -234
  138. package/out/zero-protocol/src/push.d.ts.map +1 -1
  139. package/out/zero-protocol/src/push.js +3 -114
  140. package/out/zero-protocol/src/push.js.map +1 -1
  141. package/out/zero-protocol/src/query-server.d.ts +150 -0
  142. package/out/zero-protocol/src/query-server.d.ts.map +1 -0
  143. package/out/zero-protocol/src/query-server.js +16 -0
  144. package/out/zero-protocol/src/query-server.js.map +1 -0
  145. package/out/zero-protocol/src/up.js +1 -1
  146. package/out/zero-server/src/mod.d.ts +4 -2
  147. package/out/zero-server/src/mod.d.ts.map +1 -1
  148. package/out/zero-server/src/process-mutations.d.ts +50 -4
  149. package/out/zero-server/src/process-mutations.d.ts.map +1 -1
  150. package/out/zero-server/src/process-mutations.js +73 -36
  151. package/out/zero-server/src/process-mutations.js.map +1 -1
  152. package/out/zero-server/src/push-processor.d.ts +3 -3
  153. package/out/zero-server/src/push-processor.d.ts.map +1 -1
  154. package/out/zero-server/src/push-processor.js.map +1 -1
  155. package/out/zero-server/src/queries/process-queries.d.ts +45 -53
  156. package/out/zero-server/src/queries/process-queries.d.ts.map +1 -1
  157. package/out/zero-server/src/queries/process-queries.js +72 -53
  158. package/out/zero-server/src/queries/process-queries.js.map +1 -1
  159. package/out/zero-server/src/zql-database.js.map +1 -1
  160. package/out/zero-types/src/default-types.d.ts +1 -0
  161. package/out/zero-types/src/default-types.d.ts.map +1 -1
  162. package/out/zql/src/builder/builder.d.ts.map +1 -1
  163. package/out/zql/src/builder/builder.js +17 -7
  164. package/out/zql/src/builder/builder.js.map +1 -1
  165. package/out/zql/src/ivm/cap.d.ts +32 -0
  166. package/out/zql/src/ivm/cap.d.ts.map +1 -0
  167. package/out/zql/src/ivm/cap.js +205 -0
  168. package/out/zql/src/ivm/cap.js.map +1 -0
  169. package/out/zql/src/ivm/constraint.js +1 -1
  170. package/out/zql/src/ivm/flipped-join.d.ts.map +1 -1
  171. package/out/zql/src/ivm/flipped-join.js +61 -15
  172. package/out/zql/src/ivm/flipped-join.js.map +1 -1
  173. package/out/zql/src/ivm/memory-source.d.ts.map +1 -1
  174. package/out/zql/src/ivm/memory-source.js +3 -4
  175. package/out/zql/src/ivm/memory-source.js.map +1 -1
  176. package/out/zql/src/ivm/schema.d.ts +8 -0
  177. package/out/zql/src/ivm/schema.d.ts.map +1 -1
  178. package/out/zql/src/ivm/take.js +2 -2
  179. package/out/zql/src/mutate/mutator-registry.js.map +1 -1
  180. package/out/zql/src/mutate/mutator.d.ts +11 -2
  181. package/out/zql/src/mutate/mutator.d.ts.map +1 -1
  182. package/out/zql/src/mutate/mutator.js.map +1 -1
  183. package/out/zql/src/query/query-registry.d.ts +9 -2
  184. package/out/zql/src/query/query-registry.d.ts.map +1 -1
  185. package/out/zql/src/query/query-registry.js.map +1 -1
  186. package/out/zqlite/src/table-source.d.ts.map +1 -1
  187. package/out/zqlite/src/table-source.js +4 -1
  188. package/out/zqlite/src/table-source.js.map +1 -1
  189. 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
- contextManager;
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, contextManager, customQueryTransformer, runPriorityOp, keepaliveMs = DEFAULT_KEEPALIVE_MS, setTimeoutFn = setTimeout.bind(globalThis)) {
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.contextManager = contextManager;
105
+ this.connContextManager = connContextManager;
104
106
  this.#shard = shard;
105
107
  this.#lc = lc;
106
108
  this.#pipelines = pipelineDriver;
@@ -189,6 +191,7 @@ var ViewSyncerService = class {
189
191
  this.#pipelineResets.add(1, { reason: result.reason });
190
192
  this.#pipelines.reset(clientSchema);
191
193
  this.#pipelinesSynced = false;
194
+ this.connContextManager.setSharedRetransformReady(false);
192
195
  }
193
196
  const version = this.#pipelines.advanceWithoutDiff();
194
197
  const cvrVer = versionString(cvr.version);
@@ -197,9 +200,10 @@ var ViewSyncerService = class {
197
200
  return;
198
201
  }
199
202
  lc.info?.(`init pipelines@${version} (cvr@${cvrVer})`);
200
- await this.#hydrateUnchangedQueries(lc, cvr);
201
- await this.#syncQueryPipelineSet(lc, cvr, "missing", void 0);
203
+ const driftedQueryIDs = await this.#hydrateUnchangedQueries(lc, cvr);
204
+ await this.#syncQueryPipelineSet(lc, cvr, "missing", void 0, driftedQueryIDs);
202
205
  this.#pipelinesSynced = true;
206
+ this.connContextManager.setSharedRetransformReady(true);
203
207
  });
204
208
  }
205
209
  if (this.#drainCoordinator.shouldDrain()) this.#drainCoordinator.drainNextIn(this.#totalHydrationTimeMs());
@@ -262,7 +266,7 @@ var ViewSyncerService = class {
262
266
  return this.#clients.size === 0;
263
267
  }
264
268
  #deleteClientDueToDisconnect(clientID, client) {
265
- this.contextManager.closeConnection({
269
+ this.connContextManager.closeConnection({
266
270
  clientID,
267
271
  wsID: client.wsID
268
272
  });
@@ -290,13 +294,10 @@ var ViewSyncerService = class {
290
294
  * deadlines. The timer plumbing is intentionally separate from the actual
291
295
  * revalidation/retransform work so future policy changes only need to update
292
296
  * 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
297
  */
297
298
  #scheduleAuthMaintenance(lc) {
298
299
  this.#stopAuthMaintenanceTimer();
299
- const plan = this.contextManager.planMaintenance();
300
+ const plan = this.connContextManager.planMaintenance();
300
301
  if (plan.earliestDeadlineAt === void 0) {
301
302
  lc.debug?.("No auth maintenance wakeup scheduled");
302
303
  return;
@@ -306,13 +307,17 @@ var ViewSyncerService = class {
306
307
  delay,
307
308
  earliestDeadlineAt: plan.earliestDeadlineAt
308
309
  });
309
- this.#authMaintenanceTimer = this.#setTimeout(() => {
310
- this.#authMaintenanceTimer = 0;
311
- this.#runInLockWithCVR((lc, cvr) => this.#runAuthMaintenance(lc, cvr)).catch((e) => this.#stateChanges.fail(e));
310
+ this.#authMaintenanceTimer = this.#setTimeout(async () => {
311
+ try {
312
+ this.#authMaintenanceTimer = 0;
313
+ await this.#runInLockWithCVR((lc, cvr) => this.#runAuthMaintenance(lc, cvr));
314
+ } catch (e) {
315
+ this.#stateChanges.fail(e instanceof Error ? e : new Error(String(e)));
316
+ }
312
317
  }, delay);
313
318
  }
314
319
  async #runAuthMaintenance(lc, _cvr) {
315
- const plan = this.contextManager.planMaintenance();
320
+ const plan = this.connContextManager.planMaintenance();
316
321
  if (plan.dueRevalidations.length === 0 && !plan.dueRetransform) {
317
322
  lc.debug?.("Auth maintenance woke up with no due work");
318
323
  return;
@@ -321,52 +326,52 @@ var ViewSyncerService = class {
321
326
  dueRevalidations: plan.dueRevalidations.length,
322
327
  dueRetransform: plan.dueRetransform
323
328
  });
324
- for (const connection of plan.dueRevalidations) try {
325
- await this.#validateConnection(connection);
329
+ for (const connCtx of plan.dueRevalidations) try {
330
+ await this.#validateConnection(connCtx);
326
331
  } catch (e) {
327
332
  if (isProtocolError(e) && isTransformFailedError(e)) {
328
333
  lc.warn?.("Scheduled auth revalidation failed; deferring auth maintenance", {
329
- clientID: connection.clientID,
330
- wsID: connection.wsID,
334
+ clientID: connCtx.clientID,
335
+ wsID: connCtx.wsID,
331
336
  message: e.message
332
337
  });
333
- this.contextManager.deferMaintenance("revalidate");
338
+ this.connContextManager.deferMaintenance("revalidate");
334
339
  return;
335
340
  }
336
341
  throw e;
337
342
  }
338
- if (this.contextManager.planMaintenance().dueRetransform) await this.#runBackgroundRetransform(lc);
343
+ if (this.connContextManager.planMaintenance().dueRetransform) await this.#runBackgroundRetransform(lc);
339
344
  }
340
345
  initConnection(selector, initConnectionMessage) {
341
346
  this.#lc.debug?.("viewSyncer.initConnection");
342
347
  return startSpan(tracer, "vs.initConnection", () => {
343
- const ctx = this.contextManager.mustGetConnectionContext(selector);
344
- const lc = this.#lc.withContext("clientID", ctx.clientID).withContext("wsID", ctx.wsID);
348
+ const connCtx = this.connContextManager.mustGetConnectionContext(selector);
349
+ const lc = this.#lc.withContext("clientID", connCtx.clientID).withContext("wsID", connCtx.wsID);
345
350
  const downstream = Subscription.create({ cleanup: (_, err) => {
346
351
  err ? lc[getLogLevel(err)]?.(`client closed with error`, err) : lc.info?.("client closed");
347
- this.#deleteClientDueToDisconnect(ctx.clientID, newClient);
348
- this.#activeClients.add(-1, { [PROTOCOL_VERSION_ATTR]: ctx.protocolVersion });
352
+ this.#deleteClientDueToDisconnect(connCtx.clientID, newClient);
353
+ this.#activeClients.add(-1, { [PROTOCOL_VERSION_ATTR]: connCtx.protocolVersion });
349
354
  } });
350
- this.#activeClients.add(1, { [PROTOCOL_VERSION_ATTR]: ctx.protocolVersion });
355
+ this.#activeClients.add(1, { [PROTOCOL_VERSION_ATTR]: connCtx.protocolVersion });
351
356
  if (this.#clients.size === 0) this.#ttlClockBase = Date.now();
352
- const newClient = new ClientHandler(lc, this.id, ctx.clientID, ctx.wsID, this.#shard, ctx.baseCookie, downstream);
353
- this.#clients.get(ctx.clientID)?.close(`replaced by wsID: ${ctx.wsID}`);
354
- this.#clients.set(ctx.clientID, newClient);
355
- startAsyncSpan(tracer, "vs.initConnection.async", () => this.#runInLockForClient(ctx, initConnectionMessage, async (lc, clientID, msg, cvr) => {
357
+ const newClient = new ClientHandler(lc, this.id, connCtx.clientID, connCtx.wsID, this.#shard, connCtx.baseCookie, downstream);
358
+ this.#clients.get(connCtx.clientID)?.close(`replaced by wsID: ${connCtx.wsID}`);
359
+ this.#clients.set(connCtx.clientID, newClient);
360
+ startAsyncSpan(tracer, "vs.initConnection.async", () => this.#runInLockForClient(connCtx, initConnectionMessage, async (lc, clientID, msg, cvr) => {
356
361
  if (cvr.clientSchema === null && !msg.clientSchema) throw new ProtocolErrorWithLevel({
357
362
  kind: InvalidConnectionRequest,
358
363
  message: "The initConnection message for a new client group must include client schema.",
359
364
  origin: ZeroCache
360
365
  }, "warn");
361
- if (!await this.#validateConnection(ctx)) return;
362
- await this.#handleConfigUpdate(lc, clientID, msg, cvr, "all", ctx.profileID ?? `cg${this.id}`, ctx);
366
+ if (!await this.#validateConnection(connCtx)) return;
367
+ await this.#handleConfigUpdate(lc, clientID, msg, cvr, "all", connCtx.profileID ?? `cg${this.id}`, connCtx);
363
368
  this.#initialized.resolve("initialized");
364
369
  }, newClient)).catch((e) => newClient.fail(e));
365
370
  return downstream;
366
371
  });
367
372
  }
368
373
  async changeDesiredQueries(selector, msg) {
369
- await this.#runInLockForClient(selector, msg, (lc, clientID, msg, cvr) => this.#handleConfigUpdate(lc, clientID, msg, cvr, "missing", void 0, this.contextManager.mustGetConnectionContext(selector)));
374
+ await this.#runInLockForClient(selector, msg, (lc, clientID, msg, cvr) => this.#handleConfigUpdate(lc, clientID, msg, cvr, "missing", void 0, this.connContextManager.mustGetConnectionContext(selector)));
370
375
  }
371
376
  async updateAuth(selector, msg, authRevisionChanged) {
372
377
  await this.#runInLockForClient(selector, msg, async (lc, clientID, _, cvr) => {
@@ -375,15 +380,15 @@ var ViewSyncerService = class {
375
380
  return;
376
381
  }
377
382
  lc.debug?.("Auth changed, re-validating and re-transforming queries");
378
- const connection = this.contextManager.mustGetConnectionContext(selector);
383
+ const connCtx = this.connContextManager.mustGetConnectionContext(selector);
379
384
  if (!this.#pipelinesSynced) {
380
- if (!await this.#validateConnection(connection)) return;
385
+ if (!await this.#validateConnection(connCtx)) return;
381
386
  }
382
- return await this.#handleConfigUpdate(lc, clientID, {}, cvr, "all", void 0, connection);
387
+ return await this.#handleConfigUpdate(lc, clientID, {}, cvr, "all", void 0, connCtx);
383
388
  });
384
389
  }
385
390
  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.contextManager.mustGetConnectionContext(selector))) ?? [];
391
+ 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
392
  }
388
393
  #getTTLClock(now) {
389
394
  const delta = now - this.#ttlClockBase;
@@ -425,7 +430,7 @@ var ViewSyncerService = class {
425
430
  lc.warn?.("failed to update TTL clock", rid, `after ${Date.now() - start} ms`, e);
426
431
  });
427
432
  }
428
- async #updateCVRConfig(lc, cvr, clientID, customQueryTransformMode, ctx, fn) {
433
+ async #updateCVRConfig(lc, cvr, clientID, customQueryTransformMode, connCtx, fn) {
429
434
  const updater = new CVRConfigDrivenUpdater(this.#cvrStore, cvr, this.#shard);
430
435
  updater.ensureClient(clientID);
431
436
  const patches = fn(updater);
@@ -438,7 +443,7 @@ var ViewSyncerService = class {
438
443
  await pokers.end(newCVR.version);
439
444
  });
440
445
  }
441
- if (this.#pipelinesSynced) await this.#syncQueryPipelineSet(lc, this.#cvr, customQueryTransformMode, ctx);
446
+ if (this.#pipelinesSynced) await this.#syncQueryPipelineSet(lc, this.#cvr, customQueryTransformMode, connCtx);
442
447
  return this.#cvr;
443
448
  }
444
449
  /**
@@ -455,7 +460,7 @@ var ViewSyncerService = class {
455
460
  span.setAttribute("clientID", clientID);
456
461
  let client;
457
462
  let result;
458
- let ctx;
463
+ let connCtx;
459
464
  try {
460
465
  await this.#runInLockWithCVR(async (lc, cvr) => {
461
466
  lc = lc.withContext("clientID", clientID).withContext("wsID", wsID).withContext("cmd", cmd);
@@ -465,7 +470,7 @@ var ViewSyncerService = class {
465
470
  lc.debug?.("mismatched wsID", client?.wsID, wsID);
466
471
  return;
467
472
  }
468
- ctx = this.contextManager.getConnectionContext(selector);
473
+ connCtx = this.connContextManager.getConnectionContext(selector);
469
474
  if (newClient) {
470
475
  assert(newClient === client, "newClient must match existing client");
471
476
  checkClientAndCVRVersions(client.version(), cvr.version);
@@ -475,7 +480,7 @@ var ViewSyncerService = class {
475
480
  });
476
481
  } catch (e) {
477
482
  this.#lc.withContext("clientID", clientID).withContext("wsID", wsID).withContext("cmd", cmd)[getLogLevel(e)]?.(`closing connection with error`, e);
478
- if (ctx) this.contextManager.failConnection(selector, ctx.revision);
483
+ if (connCtx) this.connContextManager.failConnection(selector, connCtx.revision);
479
484
  if (client) client.fail(e);
480
485
  else throw e;
481
486
  }
@@ -486,10 +491,10 @@ var ViewSyncerService = class {
486
491
  const clients = [...this.#clients.values()];
487
492
  return atVersion ? clients.filter((c) => cmpVersions(c.version() ?? EMPTY_CVR_VERSION, atVersion) === 0) : clients;
488
493
  }
489
- #handleConfigUpdate = (lc, clientID, { clientSchema, deleted, desiredQueriesPatch, activeClients }, cvr, customQueryTransformMode, profileID, ctx) => startAsyncSpan(tracer, "vs.#handleConfigUpdate", async () => {
494
+ #handleConfigUpdate = (lc, clientID, { clientSchema, deleted, desiredQueriesPatch, activeClients }, cvr, customQueryTransformMode, profileID, connCtx) => startAsyncSpan(tracer, "vs.#handleConfigUpdate", async () => {
490
495
  const deletedClientIDs = [];
491
496
  const deletedClientGroupIDs = [];
492
- cvr = await this.#updateCVRConfig(lc, cvr, clientID, customQueryTransformMode, ctx, (updater) => {
497
+ cvr = await this.#updateCVRConfig(lc, cvr, clientID, customQueryTransformMode, connCtx, (updater) => {
493
498
  const { ttlClock } = cvr;
494
499
  const patches = [];
495
500
  if (clientSchema) updater.setClientSchema(lc, clientSchema);
@@ -567,7 +572,7 @@ var ViewSyncerService = class {
567
572
  const cvrVersion = cvr.version;
568
573
  if (cvrVersion.stateVersion !== dbVersion) {
569
574
  lc.info?.(`CVR (${versionToCookie(cvrVersion)}) is behind db ${dbVersion}`);
570
- return;
575
+ return /* @__PURE__ */ new Set();
571
576
  }
572
577
  const gotQueries = Object.entries(cvr.queries).filter(([_, state]) => state.transformationHash !== void 0);
573
578
  const customQueries = /* @__PURE__ */ new Map();
@@ -586,11 +591,11 @@ var ViewSyncerService = class {
586
591
  let customHashMismatchCount = 0;
587
592
  let otherHashMismatchCount = 0;
588
593
  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.contextManager.mustGetBackgroundConnectionContext();
594
+ const backgroundContext = this.connContextManager.mustGetBackgroundConnectionContext();
590
595
  const customQueryTransformer = this.#customQueryTransformer;
591
596
  if (customQueryTransformer && customQueries.size > 0) {
592
597
  const transformedCustomQueries = await this.#runPriorityOp(lc, "#hydrateUnchangedQueries transforming custom queries", () => customQueryTransformer.transform(backgroundContext, customQueries.values()));
593
- if (!transformedCustomQueries.cached) this.contextManager.validateConnection(backgroundContext, backgroundContext.revision);
598
+ if (transformedCustomQueries.kind === "success" && !transformedCustomQueries.cached) this.connContextManager.validateConnection(backgroundContext, backgroundContext.revision, transformedCustomQueries.validation);
594
599
  if (Array.isArray(transformedCustomQueries.result)) for (const q of transformedCustomQueries.result) if ("error" in q) customErrorCount++;
595
600
  else if (q.transformationHash !== customQueries.get(q.id)?.transformationHash) customHashMismatchCount++;
596
601
  else transformedQueries.push(q);
@@ -601,6 +606,7 @@ var ViewSyncerService = class {
601
606
  else otherHashMismatchCount++;
602
607
  }
603
608
  lc.info?.(`hydrateUnchangedQueries: ${gotQueries.length} got queries, ${inactivatedCount} inactivated, ${customErrorCount} custom transform errors, ${customHashMismatchCount} custom hash mismatches, ${otherHashMismatchCount} other hash mismatches, ${transformedQueries.length} hydrated`);
609
+ const driftedQueryIDs = /* @__PURE__ */ new Set();
604
610
  for (const { id: queryID, transformationHash, transformedAst } of transformedQueries) {
605
611
  const timer = new TimeSliceTimer(lc);
606
612
  let count = 0;
@@ -616,7 +622,19 @@ var ViewSyncerService = class {
616
622
  this.#hydrationTime.recordMs(elapsed);
617
623
  this.#addQueryMaterializationServerMetric(transformationHash, elapsed);
618
624
  lc.debug?.(`hydrated ${count} rows for ${queryID} (${elapsed} ms)`);
625
+ const storedSigHex = cvr.queries[queryID]?.rowSetSignature;
626
+ if (storedSigHex !== void 0 && storedSigHex !== null) {
627
+ const priorSig = parseSignature(storedSigHex);
628
+ const candidateSig = this.#pipelines.rowSetSignature(queryID) ?? 0n;
629
+ if (priorSig !== candidateSig) {
630
+ lc.warn?.(`rowSetSignature drift for query ${queryID}: prior=${priorSig.toString(16)} new=${candidateSig.toString(16)} (${count} rows). Removing from pipelines for full re-execution.`);
631
+ this.#rowSetSignatureDrifts.add(1);
632
+ this.#pipelines.removeQuery(queryID);
633
+ driftedQueryIDs.add(queryID);
634
+ }
635
+ }
619
636
  }
637
+ return driftedQueryIDs;
620
638
  }
621
639
  #processTransformedCustomQueries(lc, transformedCustomQueries, cb, customQueryMap) {
622
640
  if ("kind" in transformedCustomQueries) {
@@ -669,7 +687,7 @@ var ViewSyncerService = class {
669
687
  *
670
688
  * This must be called from within the #lock.
671
689
  */
672
- #syncQueryPipelineSet(lc, cvr, customQueryTransformMode, ctx) {
690
+ #syncQueryPipelineSet(lc, cvr, customQueryTransformMode, connCtx, driftedQueryIDs = /* @__PURE__ */ new Set()) {
673
691
  return startAsyncSpan(tracer, "vs.#syncQueryPipelineSet", async (span) => {
674
692
  span.setAttribute("clientGroupID", this.id);
675
693
  assert(this.#pipelines.initialized(), "pipelines must be initialized (syncQueryPipelineSet)");
@@ -680,7 +698,7 @@ var ViewSyncerService = class {
680
698
  const customQueries = /* @__PURE__ */ new Map();
681
699
  const otherQueries = [];
682
700
  const transformedQueries = [];
683
- const resolvedContext = ctx ?? this.contextManager.mustGetBackgroundConnectionContext();
701
+ const resolvedConnCtx = connCtx ?? this.connContextManager.mustGetBackgroundConnectionContext();
684
702
  for (const [id, query] of cvrQueryEntires) if (query.type === "custom") {
685
703
  assert(id === query.id, "custom query id mismatch");
686
704
  customQueries.set(id, query);
@@ -690,7 +708,7 @@ var ViewSyncerService = class {
690
708
  });
691
709
  for (const { id, query: origQuery } of otherQueries) {
692
710
  assert(id === origQuery.id, "query id mismatch");
693
- 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");
711
+ 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
712
  transformedQueries.push({
695
713
  id,
696
714
  origQuery,
@@ -705,10 +723,10 @@ var ViewSyncerService = class {
705
723
  const transformStart = performance.now();
706
724
  let transformedCustomQueries;
707
725
  try {
708
- transformedCustomQueries = await this.#runPriorityOp(lc, "#syncQueryPipelineSet transforming custom queries", () => customQueryTransformer.transform(resolvedContext, customQueriesToTransform));
709
- if ("kind" in transformedCustomQueries.result) throw new ProtocolErrorWithLevel(transformedCustomQueries.result, "warn");
726
+ transformedCustomQueries = await this.#runPriorityOp(lc, "#syncQueryPipelineSet transforming custom queries", () => customQueryTransformer.transform(resolvedConnCtx, customQueriesToTransform));
727
+ if (transformedCustomQueries.kind === "failed") throw new ProtocolErrorWithLevel(transformedCustomQueries.result, "warn");
710
728
  else {
711
- if (!transformedCustomQueries.cached) this.contextManager.validateConnection(resolvedContext, resolvedContext.revision);
729
+ if (!transformedCustomQueries.cached) this.connContextManager.validateConnection(resolvedConnCtx, resolvedConnCtx.revision, transformedCustomQueries.validation);
712
730
  this.#queryTransformations.add(1, { result: "success" });
713
731
  }
714
732
  } catch (e) {
@@ -755,7 +773,7 @@ var ViewSyncerService = class {
755
773
  const orig = cvr.queries[q.id];
756
774
  lc.debug?.("ViewSyncer adding query", q.ast, "transformed from", orig.type === "custom" ? orig.name : orig.ast);
757
775
  }
758
- if (addQueries.length > 0 || removeQueriesQueryIds.size > 0) await this.#addAndRemoveQueries(lc, cvr, addQueries, Array.from(removeQueriesQueryIds, (id) => ({ id })));
776
+ if (addQueries.length > 0 || removeQueriesQueryIds.size > 0) await this.#addAndRemoveQueries(lc, cvr, addQueries, Array.from(removeQueriesQueryIds, (id) => ({ id })), driftedQueryIDs);
759
777
  else await this.#catchupClients(lc, cvr);
760
778
  });
761
779
  }
@@ -787,7 +805,7 @@ var ViewSyncerService = class {
787
805
  record.count++;
788
806
  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
807
  }
790
- #addAndRemoveQueries(lc, cvr, addQueries, removeQueries) {
808
+ #addAndRemoveQueries(lc, cvr, addQueries, removeQueries, driftedQueryIDs = /* @__PURE__ */ new Set()) {
791
809
  return startAsyncSpan(tracer, "vs.#addAndRemoveQueries", async () => {
792
810
  assert(addQueries.length > 0 || removeQueries.length > 0, "Must have queries to add or remove");
793
811
  const start = performance.now();
@@ -795,9 +813,14 @@ var ViewSyncerService = class {
795
813
  lc = lc.withContext("stateVersion", stateVersion);
796
814
  lc.info?.(`hydrating ${addQueries.length} queries`);
797
815
  const updater = new CVRQueryDrivenUpdater(this.#cvrStore, cvr, stateVersion, this.#pipelines.replicaVersion, (queryID) => this.#pipelines.rowSetSignature(queryID));
798
- const { newVersion, queryPatches } = updater.trackQueries(lc, addQueries, removeQueries);
816
+ const { queryPatches } = updater.trackQueries(lc, addQueries, removeQueries);
817
+ if (addQueries.some((q) => driftedQueryIDs.has(q.id))) updater.ensureNewVersion();
818
+ const newVersion = updater.updatedVersion();
799
819
  const pokers = startPoke(this.#getClients(), newVersion);
800
- for (const patch of queryPatches) await pokers.addPatch(patch);
820
+ for (const patch of queryPatches) await pokers.addPatch({
821
+ ...patch,
822
+ toVersion: newVersion
823
+ });
801
824
  for (const q of removeQueries) {
802
825
  this.#pipelines.removeQuery(q.id);
803
826
  this.#inspectorDelegate.removeQuery(q.id);
@@ -1008,88 +1031,98 @@ var ViewSyncerService = class {
1008
1031
  }
1009
1032
  #handleInspect = async (lc, clientID, body, cvr) => {
1010
1033
  const client = must(this.#clients.get(clientID));
1011
- const ctx = this.contextManager.mustGetConnectionContext({
1034
+ const connCtx = this.connContextManager.mustGetConnectionContext({
1012
1035
  clientID,
1013
1036
  wsID: client.wsID
1014
1037
  });
1015
- return handleInspect(lc, body, cvr, client, this.#inspectorDelegate, this.id, this.#cvrStore, this.#config, ctx);
1038
+ return handleInspect(lc, body, cvr, client, this.#inspectorDelegate, this.id, this.#cvrStore, this.#config, connCtx);
1016
1039
  };
1017
1040
  async #runBackgroundRetransform(lc) {
1018
- const attemptRetransform = async (connection) => {
1019
- await this.#syncQueryPipelineSet(lc, must(this.#cvr, "cvr missing during auth maintenance retransform"), "all", connection);
1020
- this.contextManager.markBackgroundRetransformSuccess({
1021
- clientID: connection.clientID,
1022
- wsID: connection.wsID
1023
- }, connection.revision);
1041
+ const attemptRetransform = async (connCtx) => {
1042
+ await this.#syncQueryPipelineSet(lc, must(this.#cvr, "cvr missing during auth maintenance retransform"), "all", connCtx);
1043
+ this.connContextManager.markBackgroundRetransformSuccess({
1044
+ clientID: connCtx.clientID,
1045
+ wsID: connCtx.wsID
1046
+ }, connCtx.revision);
1024
1047
  };
1025
- let backgroundConnection = this.contextManager.getBackgroundConnectionContext();
1026
- if (!backgroundConnection) {
1048
+ let backgroundConnCtx = this.connContextManager.getBackgroundConnectionContext();
1049
+ if (!backgroundConnCtx) {
1027
1050
  lc.debug?.("Skipping background retransform with no selected connection");
1028
1051
  return;
1029
1052
  }
1030
1053
  for (;;) {
1031
1054
  try {
1032
- await attemptRetransform(backgroundConnection);
1055
+ await attemptRetransform(backgroundConnCtx);
1033
1056
  return;
1034
1057
  } catch (e) {
1035
1058
  if (isProtocolError(e)) {
1036
1059
  if (isAuthErrorBody(e.errorBody)) {
1037
1060
  lc.warn?.("Background retransform auth failed; failing connection and searching for replacement", {
1038
- clientID: backgroundConnection.clientID,
1061
+ clientID: backgroundConnCtx.clientID,
1039
1062
  message: e.message
1040
1063
  });
1041
- this.#failMaintenanceConnection(backgroundConnection, e);
1064
+ this.#failMaintenanceConnection(backgroundConnCtx, e);
1042
1065
  } else if (isTransformFailedError(e)) {
1043
1066
  lc.warn?.("Background retransform failed; deferring auth maintenance", {
1044
- clientID: backgroundConnection.clientID,
1067
+ clientID: backgroundConnCtx.clientID,
1045
1068
  message: e.message
1046
1069
  });
1047
- this.contextManager.deferMaintenance("retransform");
1070
+ this.connContextManager.deferMaintenance("retransform");
1048
1071
  return;
1049
1072
  }
1050
1073
  } else throw e;
1051
1074
  }
1052
- const replacement = this.contextManager.getBackgroundConnectionContext();
1053
- if (!replacement) {
1075
+ const replacementConnCtx = this.connContextManager.getBackgroundConnectionContext();
1076
+ if (!replacementConnCtx) {
1054
1077
  lc.debug?.("No replacement connection available for background retransform");
1055
1078
  return;
1056
1079
  }
1057
1080
  lc.debug?.("Retrying background retransform with replacement connection", {
1058
- clientID: replacement.clientID,
1059
- wsID: replacement.wsID
1081
+ clientID: replacementConnCtx.clientID,
1082
+ wsID: replacementConnCtx.wsID
1060
1083
  });
1061
- backgroundConnection = replacement;
1084
+ backgroundConnCtx = replacementConnCtx;
1062
1085
  }
1063
1086
  }
1064
- async #validateConnection(ctx) {
1087
+ async #validateConnection(connCtx) {
1065
1088
  try {
1089
+ let validation = void 0;
1066
1090
  if (this.#customQueryTransformer) {
1067
- const validation = await this.#customQueryTransformer.validate(ctx);
1068
- if (validation !== void 0) throw new ProtocolErrorWithLevel(validation, "warn");
1069
- }
1070
- this.contextManager.validateConnection(ctx, ctx.revision);
1091
+ const response = await this.#customQueryTransformer.validate(connCtx);
1092
+ if (response.kind === "TransformFailed") throw new ProtocolErrorWithLevel(response, "warn");
1093
+ validation = response.validation;
1094
+ } else validation = { kind: "client-fallback" };
1095
+ this.connContextManager.validateConnection(connCtx, connCtx.revision, validation);
1071
1096
  return true;
1072
1097
  } catch (e) {
1073
1098
  if (isProtocolError(e) && isAuthErrorBody(e.errorBody)) {
1074
- this.#failMaintenanceConnection(ctx, e);
1099
+ this.#lc.warn?.("Connection auth validation failed; invalidating connection", {
1100
+ clientID: connCtx.clientID,
1101
+ wsID: connCtx.wsID,
1102
+ revision: connCtx.revision,
1103
+ message: e.message
1104
+ });
1105
+ this.#failMaintenanceConnection(connCtx, e);
1075
1106
  return false;
1076
1107
  }
1077
1108
  throw e;
1078
1109
  }
1079
1110
  }
1080
- #failMaintenanceConnection(ctx, error) {
1081
- if (!this.contextManager.failConnection(ctx, ctx.revision)) return;
1111
+ #failMaintenanceConnection(connCtx, error) {
1112
+ if (!this.connContextManager.failConnection(connCtx, connCtx.revision)) return;
1082
1113
  const wrapped = wrapWithProtocolError(error);
1083
- const client = this.#clients.get(ctx.clientID);
1084
- if (client?.wsID === ctx.wsID) client.fail(wrapped);
1114
+ const client = this.#clients.get(connCtx.clientID);
1115
+ if (client?.wsID === connCtx.wsID) client.fail(wrapped);
1085
1116
  }
1086
1117
  stop() {
1087
1118
  this.#lc.info?.("stopping view syncer");
1119
+ this.connContextManager.setSharedRetransformReady(false);
1088
1120
  this.#initialized.reject("shut down before initialization completed");
1089
1121
  this.#stateChanges.cancel();
1090
1122
  return this.#stopped.promise;
1091
1123
  }
1092
1124
  async #cleanup(err) {
1125
+ this.connContextManager.setSharedRetransformReady(false);
1093
1126
  this.#stopTTLClockInterval();
1094
1127
  this.#stopExpireTimer();
1095
1128
  this.#stopAuthMaintenanceTimer();