@rocicorp/zero 0.24.2025102100 → 0.25.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.
Files changed (95) hide show
  1. package/out/{chunk-VHLCXJ6Q.js → chunk-4RB4OYLQ.js} +3 -2
  2. package/out/{chunk-VHLCXJ6Q.js.map → chunk-4RB4OYLQ.js.map} +2 -2
  3. package/out/{chunk-TTBIQGLF.js → chunk-BJ2CGCME.js} +3 -3
  4. package/out/chunk-BJ2CGCME.js.map +7 -0
  5. package/out/{chunk-TA2NZPJQ.js → chunk-MXPHMVU7.js} +505 -206
  6. package/out/chunk-MXPHMVU7.js.map +7 -0
  7. package/out/{lazy-inspector-NCBESZMS.js → lazy-inspector-2SW772W4.js} +2 -2
  8. package/out/react.js +2 -2
  9. package/out/solid.js +3 -3
  10. package/out/zero/package.json +2 -2
  11. package/out/zero-cache/src/db/lite-tables.d.ts.map +1 -1
  12. package/out/zero-cache/src/db/lite-tables.js +36 -15
  13. package/out/zero-cache/src/db/lite-tables.js.map +1 -1
  14. package/out/zero-cache/src/db/specs.d.ts +12 -7
  15. package/out/zero-cache/src/db/specs.d.ts.map +1 -1
  16. package/out/zero-cache/src/db/specs.js.map +1 -1
  17. package/out/zero-cache/src/services/change-source/column-metadata.d.ts +65 -0
  18. package/out/zero-cache/src/services/change-source/column-metadata.d.ts.map +1 -0
  19. package/out/zero-cache/src/services/change-source/column-metadata.js +198 -0
  20. package/out/zero-cache/src/services/change-source/column-metadata.js.map +1 -0
  21. package/out/zero-cache/src/services/view-syncer/client-schema.js +1 -1
  22. package/out/zero-cache/src/services/view-syncer/client-schema.js.map +1 -1
  23. package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts +1 -1
  24. package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts.map +1 -1
  25. package/out/zero-cache/src/services/view-syncer/pipeline-driver.js +38 -25
  26. package/out/zero-cache/src/services/view-syncer/pipeline-driver.js.map +1 -1
  27. package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts +11 -6
  28. package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts.map +1 -1
  29. package/out/zero-cache/src/services/view-syncer/snapshotter.js +34 -22
  30. package/out/zero-cache/src/services/view-syncer/snapshotter.js.map +1 -1
  31. package/out/zero-client/src/client/client-error-kind-enum.d.ts +19 -0
  32. package/out/zero-client/src/client/client-error-kind-enum.d.ts.map +1 -0
  33. package/out/zero-client/src/client/client-error-kind.d.ts +5 -0
  34. package/out/zero-client/src/client/client-error-kind.d.ts.map +1 -0
  35. package/out/zero-client/src/client/connection-manager.d.ts +86 -0
  36. package/out/zero-client/src/client/connection-manager.d.ts.map +1 -0
  37. package/out/zero-client/src/client/connection-status-enum.d.ts +9 -0
  38. package/out/zero-client/src/client/connection-status-enum.d.ts.map +1 -0
  39. package/out/zero-client/src/client/connection-status.d.ts +5 -0
  40. package/out/zero-client/src/client/connection-status.d.ts.map +1 -0
  41. package/out/zero-client/src/client/crud.d.ts.map +1 -1
  42. package/out/zero-client/src/client/error.d.ts +37 -0
  43. package/out/zero-client/src/client/error.d.ts.map +1 -0
  44. package/out/zero-client/src/client/metric-name.d.ts +5 -0
  45. package/out/zero-client/src/client/metric-name.d.ts.map +1 -0
  46. package/out/zero-client/src/client/metrics.d.ts +3 -9
  47. package/out/zero-client/src/client/metrics.d.ts.map +1 -1
  48. package/out/zero-client/src/client/zero.d.ts +28 -6
  49. package/out/zero-client/src/client/zero.d.ts.map +1 -1
  50. package/out/zero-protocol/src/ast.d.ts +2 -0
  51. package/out/zero-protocol/src/ast.d.ts.map +1 -1
  52. package/out/zero-protocol/src/ast.js +1 -0
  53. package/out/zero-protocol/src/ast.js.map +1 -1
  54. package/out/zero-schema/src/builder/relationship-builder.d.ts +20 -18
  55. package/out/zero-schema/src/builder/relationship-builder.d.ts.map +1 -1
  56. package/out/zero-schema/src/builder/relationship-builder.js.map +1 -1
  57. package/out/zero-server/src/adapters/drizzle.d.ts +2 -3
  58. package/out/zero-server/src/adapters/drizzle.d.ts.map +1 -1
  59. package/out/zero-server/src/adapters/drizzle.js.map +1 -1
  60. package/out/zero-server/src/adapters/pg.d.ts +1 -0
  61. package/out/zero-server/src/adapters/pg.d.ts.map +1 -1
  62. package/out/zero-server/src/adapters/pg.js.map +1 -1
  63. package/out/zero-server/src/adapters/postgresjs.d.ts +1 -0
  64. package/out/zero-server/src/adapters/postgresjs.d.ts.map +1 -1
  65. package/out/zero-server/src/adapters/postgresjs.js.map +1 -1
  66. package/out/zero.js +3 -3
  67. package/out/zql/src/builder/builder.d.ts +12 -0
  68. package/out/zql/src/builder/builder.d.ts.map +1 -1
  69. package/out/zql/src/builder/builder.js +28 -1
  70. package/out/zql/src/builder/builder.js.map +1 -1
  71. package/out/zql/src/ivm/memory-source.d.ts +3 -3
  72. package/out/zql/src/ivm/memory-source.d.ts.map +1 -1
  73. package/out/zql/src/ivm/memory-source.js +0 -16
  74. package/out/zql/src/ivm/memory-source.js.map +1 -1
  75. package/out/zql/src/ivm/source.d.ts +1 -5
  76. package/out/zql/src/ivm/source.d.ts.map +1 -1
  77. package/out/zql/src/query/query-impl.d.ts.map +1 -1
  78. package/out/zql/src/query/query-impl.js +0 -6
  79. package/out/zql/src/query/query-impl.js.map +1 -1
  80. package/out/zqlite/src/table-source.d.ts +3 -3
  81. package/out/zqlite/src/table-source.d.ts.map +1 -1
  82. package/out/zqlite/src/table-source.js +0 -16
  83. package/out/zqlite/src/table-source.js.map +1 -1
  84. package/package.json +2 -2
  85. package/out/chunk-TA2NZPJQ.js.map +0 -7
  86. package/out/chunk-TTBIQGLF.js.map +0 -7
  87. package/out/zero-client/src/client/connection-state-enum.d.ts +0 -7
  88. package/out/zero-client/src/client/connection-state-enum.d.ts.map +0 -1
  89. package/out/zero-client/src/client/server-error.d.ts +0 -15
  90. package/out/zero-client/src/client/server-error.d.ts.map +0 -1
  91. package/out/zql/src/query/assert-no-not-exists.d.ts +0 -17
  92. package/out/zql/src/query/assert-no-not-exists.d.ts.map +0 -1
  93. package/out/zql/src/query/assert-no-not-exists.js +0 -40
  94. package/out/zql/src/query/assert-no-not-exists.js.map +0 -1
  95. /package/out/{lazy-inspector-NCBESZMS.js.map → lazy-inspector-2SW772W4.js.map} +0 -0
@@ -123,7 +123,7 @@ import {
123
123
  withWrite,
124
124
  withWriteNoImplicitCommit,
125
125
  wrapIterable
126
- } from "./chunk-VHLCXJ6Q.js";
126
+ } from "./chunk-4RB4OYLQ.js";
127
127
  import {
128
128
  assert,
129
129
  assertArray,
@@ -2185,7 +2185,7 @@ var SchemaVersionNotSupported2 = "SchemaVersionNotSupported";
2185
2185
 
2186
2186
  // ../zero-client/src/client/zero.ts
2187
2187
  import "@rocicorp/logger";
2188
- import { resolver as resolver10 } from "@rocicorp/resolver";
2188
+ import { resolver as resolver11 } from "@rocicorp/resolver";
2189
2189
 
2190
2190
  // ../replicache/src/replicache-impl.ts
2191
2191
  import { Lock } from "@rocicorp/lock";
@@ -9672,12 +9672,36 @@ function buildPipeline(ast, delegate, queryID) {
9672
9672
  }
9673
9673
  var EXISTS_LIMIT = 3;
9674
9674
  var PERMISSIONS_EXISTS_LIMIT = 1;
9675
+ function assertNoNotExists(condition) {
9676
+ switch (condition.type) {
9677
+ case "simple":
9678
+ return;
9679
+ case "correlatedSubquery":
9680
+ if (condition.op === "NOT EXISTS") {
9681
+ throw new Error(
9682
+ "not(exists()) is not supported on the client - see https://bugs.rocicorp.dev/issue/3438"
9683
+ );
9684
+ }
9685
+ return;
9686
+ case "and":
9687
+ case "or":
9688
+ for (const c of condition.conditions) {
9689
+ assertNoNotExists(c);
9690
+ }
9691
+ return;
9692
+ default:
9693
+ unreachable(condition);
9694
+ }
9695
+ }
9675
9696
  function buildPipelineInternal(ast, delegate, queryID, name, partitionKey) {
9676
9697
  const source = delegate.getSource(ast.table);
9677
9698
  if (!source) {
9678
9699
  throw new Error(`Source not found: ${ast.table}`);
9679
9700
  }
9680
9701
  ast = uniquifyCorrelatedSubqueryConditionAliases(ast);
9702
+ if (!delegate.enableNotExists && ast.where) {
9703
+ assertNoNotExists(ast.where);
9704
+ }
9681
9705
  const csqConditions = gatherCorrelatedSubqueryQueryConditions(ast.where);
9682
9706
  const splitEditKeys = partitionKey ? new Set(partitionKey) : /* @__PURE__ */ new Set();
9683
9707
  const aliases = /* @__PURE__ */ new Set();
@@ -10200,32 +10224,6 @@ var defaultFormat = {
10200
10224
  relationships: {}
10201
10225
  };
10202
10226
 
10203
- // ../zql/src/query/assert-no-not-exists.ts
10204
- function assertNoNotExists(condition) {
10205
- switch (condition.type) {
10206
- case "simple":
10207
- return;
10208
- case "correlatedSubquery":
10209
- if (condition.op === "NOT EXISTS") {
10210
- throw new Error(
10211
- "not(exists()) is not supported on the client - see https://bugs.rocicorp.dev/issue/3438"
10212
- );
10213
- }
10214
- if (condition.related.subquery.where) {
10215
- assertNoNotExists(condition.related.subquery.where);
10216
- }
10217
- return;
10218
- case "and":
10219
- case "or":
10220
- for (const c of condition.conditions) {
10221
- assertNoNotExists(c);
10222
- }
10223
- return;
10224
- default:
10225
- unreachable(condition);
10226
- }
10227
- }
10228
-
10229
10227
  // ../zql/src/query/query.ts
10230
10228
  var delegateSymbol = Symbol("delegate");
10231
10229
 
@@ -10489,9 +10487,6 @@ var AbstractQuery = class {
10489
10487
  cond = and(existingWhere, cond);
10490
10488
  }
10491
10489
  const where = simplifyCondition(cond);
10492
- if (this.#system === "client") {
10493
- assertNoNotExists(where);
10494
- }
10495
10490
  return this[newQuerySymbol](
10496
10491
  this._delegate,
10497
10492
  this.#schema,
@@ -11099,10 +11094,238 @@ var MockClientLockManager = class {
11099
11094
  }
11100
11095
  };
11101
11096
 
11102
- // ../zero-client/src/client/connection-state-enum.ts
11103
- var Disconnected = 0;
11104
- var Connecting = 1;
11105
- var Connected = 2;
11097
+ // ../zero-client/src/client/connection-manager.ts
11098
+ import { resolver as resolver9 } from "@rocicorp/resolver";
11099
+
11100
+ // ../zero-client/src/client/connection-status-enum.ts
11101
+ var connection_status_enum_exports = {};
11102
+ __export(connection_status_enum_exports, {
11103
+ Closed: () => Closed,
11104
+ Connected: () => Connected,
11105
+ Connecting: () => Connecting,
11106
+ Disconnected: () => Disconnected
11107
+ });
11108
+ var Disconnected = "disconnected";
11109
+ var Connecting = "connecting";
11110
+ var Connected = "connected";
11111
+ var Closed = "closed";
11112
+
11113
+ // ../zero-client/src/client/connection-manager.ts
11114
+ var DEFAULT_TIMEOUT_CHECK_INTERVAL_MS = 1e3;
11115
+ var ConnectionManager = class extends Subscribable {
11116
+ #state;
11117
+ /**
11118
+ * The timestamp when we first started trying to connect.
11119
+ * This is used to track the retry window.
11120
+ * Reset to undefined when we successfully connect or when we transition to disconnected.
11121
+ */
11122
+ #connectingStartedAt;
11123
+ /**
11124
+ * The amount of time we allow for continuous connecting attempts before
11125
+ * transitioning to disconnected state.
11126
+ */
11127
+ #disconnectTimeoutMs;
11128
+ /**
11129
+ * Handle for the timeout interval that periodically checks whether we've
11130
+ * exceeded the allowed connecting window.
11131
+ */
11132
+ #timeoutInterval;
11133
+ /**
11134
+ * Interval duration for checking whether the connecting timeout has elapsed.
11135
+ */
11136
+ #timeoutCheckIntervalMs;
11137
+ /**
11138
+ * Resolver used to signal waiting callers when the state changes.
11139
+ */
11140
+ #stateChangeResolver = resolver9();
11141
+ constructor(options) {
11142
+ super();
11143
+ const now = Date.now();
11144
+ this.#disconnectTimeoutMs = options.disconnectTimeoutMs;
11145
+ this.#timeoutCheckIntervalMs = options.timeoutCheckIntervalMs ?? DEFAULT_TIMEOUT_CHECK_INTERVAL_MS;
11146
+ this.#state = {
11147
+ name: connection_status_enum_exports.Connecting,
11148
+ attempt: 0,
11149
+ disconnectAt: now + this.#disconnectTimeoutMs
11150
+ };
11151
+ this.#connectingStartedAt = now;
11152
+ this.#maybeStartTimeoutInterval();
11153
+ }
11154
+ get state() {
11155
+ return this.#state;
11156
+ }
11157
+ /**
11158
+ * Returns true if the current state is equal to the given status.
11159
+ */
11160
+ is(status) {
11161
+ return this.#state.name === status;
11162
+ }
11163
+ /**
11164
+ * Returns true if the run loop should continue.
11165
+ * The run loop continues in disconnected, connecting, and connected states.
11166
+ * It stops in closed state.
11167
+ */
11168
+ shouldContinueRunLoop() {
11169
+ return this.#state.name !== connection_status_enum_exports.Closed;
11170
+ }
11171
+ waitForStateChange() {
11172
+ return this.#nextStatePromise();
11173
+ }
11174
+ /**
11175
+ * Transition to connecting state.
11176
+ *
11177
+ * This starts the 5-minute timeout timer, but if we've entered disconnected state,
11178
+ * we stay there and continue retrying.
11179
+ *
11180
+ * @returns An object containing a promise that resolves on the next state change.
11181
+ */
11182
+ connecting(reason) {
11183
+ if (this.#state.name === connection_status_enum_exports.Closed) {
11184
+ return { nextStatePromise: this.#nextStatePromise() };
11185
+ }
11186
+ if (this.#state.name === connection_status_enum_exports.Disconnected) {
11187
+ return { nextStatePromise: this.#nextStatePromise() };
11188
+ }
11189
+ const now = Date.now();
11190
+ if (this.#state.name === connection_status_enum_exports.Connecting) {
11191
+ this.#state = {
11192
+ ...this.#state,
11193
+ attempt: this.#state.attempt + 1,
11194
+ reason
11195
+ };
11196
+ const nextStatePromise2 = this.#publishStateAndGetPromise();
11197
+ this.#maybeStartTimeoutInterval();
11198
+ return { nextStatePromise: nextStatePromise2 };
11199
+ }
11200
+ if (this.#connectingStartedAt === void 0) {
11201
+ this.#connectingStartedAt = now;
11202
+ }
11203
+ const disconnectAt = this.#connectingStartedAt + this.#disconnectTimeoutMs;
11204
+ this.#state = {
11205
+ name: connection_status_enum_exports.Connecting,
11206
+ attempt: 1,
11207
+ disconnectAt,
11208
+ reason
11209
+ };
11210
+ const nextStatePromise = this.#publishStateAndGetPromise();
11211
+ this.#maybeStartTimeoutInterval();
11212
+ return { nextStatePromise };
11213
+ }
11214
+ /**
11215
+ * Transition to connected state.
11216
+ * This resets the connecting timeout timer.
11217
+ *
11218
+ * @returns An object containing a promise that resolves on the next state change.
11219
+ */
11220
+ connected() {
11221
+ if (this.#state.name === connection_status_enum_exports.Closed) {
11222
+ return { nextStatePromise: this.#nextStatePromise() };
11223
+ }
11224
+ if (this.#state.name === connection_status_enum_exports.Connected) {
11225
+ return { nextStatePromise: this.#nextStatePromise() };
11226
+ }
11227
+ this.#connectingStartedAt = void 0;
11228
+ this.#maybeStopTimeoutInterval();
11229
+ this.#state = {
11230
+ name: connection_status_enum_exports.Connected
11231
+ };
11232
+ const nextStatePromise = this.#publishStateAndGetPromise();
11233
+ return { nextStatePromise };
11234
+ }
11235
+ /**
11236
+ * Transition to disconnected state.
11237
+ * This is called when the 5-minute timeout expires, or when we're intentionally
11238
+ * disconnecting due to an error (this will eventually be a separate state, error).
11239
+ * The run loop will continue trying to reconnect.
11240
+ *
11241
+ * @returns An object containing a promise that resolves on the next state change.
11242
+ */
11243
+ disconnected(reason) {
11244
+ if (this.#state.name === connection_status_enum_exports.Closed) {
11245
+ return { nextStatePromise: this.#nextStatePromise() };
11246
+ }
11247
+ if (this.#state.name === connection_status_enum_exports.Disconnected) {
11248
+ return { nextStatePromise: this.#nextStatePromise() };
11249
+ }
11250
+ if (this.#state.name === connection_status_enum_exports.Connected) {
11251
+ this.#connectingStartedAt = void 0;
11252
+ }
11253
+ this.#maybeStopTimeoutInterval();
11254
+ this.#state = {
11255
+ name: connection_status_enum_exports.Disconnected,
11256
+ reason
11257
+ };
11258
+ const nextStatePromise = this.#publishStateAndGetPromise();
11259
+ return { nextStatePromise };
11260
+ }
11261
+ /**
11262
+ * Transition to closed state.
11263
+ * This is terminal - no further transitions are allowed.
11264
+ *
11265
+ * @returns An object containing a promise that resolves on the next state change.
11266
+ */
11267
+ closed() {
11268
+ if (this.#state.name === connection_status_enum_exports.Closed) {
11269
+ return { nextStatePromise: this.#nextStatePromise() };
11270
+ }
11271
+ this.#connectingStartedAt = void 0;
11272
+ this.#maybeStopTimeoutInterval();
11273
+ this.#state = {
11274
+ name: connection_status_enum_exports.Closed
11275
+ };
11276
+ const nextStatePromise = this.#publishStateAndGetPromise();
11277
+ return { nextStatePromise };
11278
+ }
11279
+ cleanup = () => {
11280
+ this._listeners.clear();
11281
+ this.#resolveNextStateWaiters();
11282
+ };
11283
+ #resolveNextStateWaiters() {
11284
+ this.#stateChangeResolver.resolve();
11285
+ this.#stateChangeResolver = resolver9();
11286
+ }
11287
+ #publishState() {
11288
+ this.notify(this.#state);
11289
+ this.#resolveNextStateWaiters();
11290
+ }
11291
+ #nextStatePromise() {
11292
+ return this.#stateChangeResolver.promise;
11293
+ }
11294
+ #publishStateAndGetPromise() {
11295
+ this.#publishState();
11296
+ return this.#nextStatePromise();
11297
+ }
11298
+ /**
11299
+ * Check if we should transition from connecting to disconnected due to timeout.
11300
+ * Returns true if the transition happened.
11301
+ */
11302
+ #checkTimeout() {
11303
+ if (this.#state.name !== connection_status_enum_exports.Connecting) {
11304
+ return false;
11305
+ }
11306
+ const now = Date.now();
11307
+ if (now >= this.#state.disconnectAt) {
11308
+ this.disconnected();
11309
+ return true;
11310
+ }
11311
+ return false;
11312
+ }
11313
+ #maybeStartTimeoutInterval() {
11314
+ if (this.#timeoutInterval !== void 0) {
11315
+ return;
11316
+ }
11317
+ this.#timeoutInterval = setInterval(() => {
11318
+ this.#checkTimeout();
11319
+ }, this.#timeoutCheckIntervalMs);
11320
+ }
11321
+ #maybeStopTimeoutInterval() {
11322
+ if (this.#timeoutInterval === void 0) {
11323
+ return;
11324
+ }
11325
+ clearInterval(this.#timeoutInterval);
11326
+ this.#timeoutInterval = void 0;
11327
+ }
11328
+ };
11106
11329
 
11107
11330
  // ../zql/src/ivm/memory-storage.ts
11108
11331
  import { compareUTF8 as compareUTF83 } from "compare-utf8";
@@ -11866,21 +12089,6 @@ var MemorySource = class _MemorySource {
11866
12089
  const exists = (row) => data.has(row);
11867
12090
  const setOverlay = (o) => this.#overlay = o;
11868
12091
  const writeChange = (c) => this.#writeChange(c);
11869
- if (change.type === "set") {
11870
- const existing = data.get(change.row);
11871
- if (existing !== void 0) {
11872
- change = {
11873
- type: "edit",
11874
- row: change.row,
11875
- oldRow: existing
11876
- };
11877
- } else {
11878
- change = {
11879
- type: "add",
11880
- row: change.row
11881
- };
11882
- }
11883
- }
11884
12092
  yield* genPushAndWriteWithSplitEdit(
11885
12093
  this.#connections,
11886
12094
  change,
@@ -12579,16 +12787,10 @@ async function upsertImpl(tx, arg, schema, ivmBranch) {
12579
12787
  schema.tables[arg.tableName].primaryKey,
12580
12788
  arg.value
12581
12789
  );
12582
- const val = defaultOptionalFieldsToNull(
12583
- schema.tables[arg.tableName],
12584
- arg.value
12585
- );
12586
- await tx.set(key, val);
12587
- if (ivmBranch) {
12588
- must(ivmBranch.getSource(arg.tableName)).push({
12589
- type: "set",
12590
- row: arg.value
12591
- });
12790
+ if (await tx.has(key)) {
12791
+ await updateImpl(tx, { ...arg, op: "update" }, schema, ivmBranch);
12792
+ } else {
12793
+ await insertImpl(tx, { ...arg, op: "insert" }, schema, ivmBranch);
12592
12794
  }
12593
12795
  }
12594
12796
  async function updateImpl(tx, arg, schema, ivmBranch) {
@@ -13065,7 +13267,7 @@ function makeMessage(message, context, logLevel) {
13065
13267
  }
13066
13268
 
13067
13269
  // ../zero-client/src/client/version.ts
13068
- var version2 = "0.24.2025102100";
13270
+ var version2 = "0.25.0-canary.0";
13069
13271
 
13070
13272
  // ../zero-client/src/client/log-options.ts
13071
13273
  var LevelFilterLogSink = class {
@@ -13121,7 +13323,84 @@ function createLogOptions(options, createDatadogLogSink = (options2) => new Data
13121
13323
  };
13122
13324
  }
13123
13325
 
13326
+ // ../zero-client/src/client/client-error-kind-enum.ts
13327
+ var client_error_kind_enum_exports = {};
13328
+ __export(client_error_kind_enum_exports, {
13329
+ AbruptClose: () => AbruptClose,
13330
+ CleanClose: () => CleanClose,
13331
+ ClientClosed: () => ClientClosed,
13332
+ ConnectTimeout: () => ConnectTimeout,
13333
+ DisconnectTimeout: () => DisconnectTimeout,
13334
+ Hidden: () => Hidden,
13335
+ NoSocketOrigin: () => NoSocketOrigin,
13336
+ PingTimeout: () => PingTimeout,
13337
+ UnexpectedBaseCookie: () => UnexpectedBaseCookie
13338
+ });
13339
+ var AbruptClose = "AbruptClose";
13340
+ var CleanClose = "CleanClose";
13341
+ var ClientClosed = "ClientClosed";
13342
+ var ConnectTimeout = "ConnectTimeout";
13343
+ var DisconnectTimeout = "DisconnectTimeout";
13344
+ var UnexpectedBaseCookie = "UnexpectedBaseCookie";
13345
+ var PingTimeout = "PingTimeout";
13346
+ var Hidden = "Hidden";
13347
+ var NoSocketOrigin = "NoSocketOrigin";
13348
+
13349
+ // ../zero-client/src/client/error.ts
13350
+ var BaseError = class extends Error {
13351
+ errorBody;
13352
+ constructor(errorBody, options) {
13353
+ super(errorBody.kind + ": " + errorBody.message, options);
13354
+ this.errorBody = errorBody;
13355
+ }
13356
+ get kind() {
13357
+ return this.errorBody.kind;
13358
+ }
13359
+ };
13360
+ var ServerError = class extends BaseError {
13361
+ get name() {
13362
+ return "ServerError";
13363
+ }
13364
+ };
13365
+ var ClientError = class extends BaseError {
13366
+ get name() {
13367
+ return "ClientError";
13368
+ }
13369
+ };
13370
+ function isServerError(ex) {
13371
+ return ex instanceof ServerError;
13372
+ }
13373
+ function isAuthError(ex) {
13374
+ return isServerError(ex) && isAuthErrorKind(ex.kind);
13375
+ }
13376
+ function isAuthErrorKind(kind) {
13377
+ return kind === error_kind_enum_exports.AuthInvalidated || kind === error_kind_enum_exports.Unauthorized;
13378
+ }
13379
+ function isBackoffError(ex) {
13380
+ if (isServerError(ex)) {
13381
+ switch (ex.errorBody.kind) {
13382
+ case error_kind_enum_exports.Rebalance:
13383
+ case error_kind_enum_exports.Rehome:
13384
+ case error_kind_enum_exports.ServerOverloaded:
13385
+ return ex.errorBody;
13386
+ }
13387
+ }
13388
+ return void 0;
13389
+ }
13390
+ function isClientError(ex) {
13391
+ return ex instanceof ClientError;
13392
+ }
13393
+
13124
13394
  // ../zero-client/src/client/metric-name-enum.ts
13395
+ var metric_name_enum_exports = {};
13396
+ __export(metric_name_enum_exports, {
13397
+ LastConnectError: () => LastConnectError,
13398
+ LastConnectErrorV2: () => LastConnectErrorV2,
13399
+ NotConnected: () => NotConnected,
13400
+ TimeToConnectMs: () => TimeToConnectMs,
13401
+ TimeToConnectMsV2: () => TimeToConnectMsV2,
13402
+ TotalTimeToConnectMs: () => TotalTimeToConnectMs
13403
+ });
13125
13404
  var TimeToConnectMs = "time_to_connect_ms";
13126
13405
  var LastConnectError = "last_connect_error";
13127
13406
  var TimeToConnectMsV2 = "time_to_connect_ms_v2";
@@ -13133,13 +13412,10 @@ var NotConnected = "not_connected";
13133
13412
  var DID_NOT_CONNECT_VALUE = 100 * 1e3;
13134
13413
  var REPORT_INTERVAL_MS = 5e3;
13135
13414
  function getLastConnectErrorValue(reason) {
13136
- if ("server" in reason) {
13137
- return `server_${camelToSnake(reason.server)}`;
13138
- }
13139
- return `client_${camelToSnake(reason.client)}`;
13415
+ return `${isServerError(reason) ? "server_" : "client_"}${camelToSnake(reason.kind)}`;
13140
13416
  }
13141
- function camelToSnake(s) {
13142
- return s.split(/\.?(?=[A-Z])/).join("_").toLowerCase();
13417
+ function camelToSnake(kind) {
13418
+ return kind.split(/\.?(?=[A-Z])/).join("_").toLowerCase();
13143
13419
  }
13144
13420
  var MetricManager = class {
13145
13421
  #reportIntervalMs;
@@ -13180,7 +13456,7 @@ var MetricManager = class {
13180
13456
  // be encapsulated with the ConnectionState. This will probably happen as part
13181
13457
  // of https://github.com/rocicorp/reflect-server/issues/255.
13182
13458
  timeToConnectMs = this.#register(
13183
- new Gauge(TimeToConnectMs)
13459
+ new Gauge(metric_name_enum_exports.TimeToConnectMs)
13184
13460
  );
13185
13461
  // lastConnectError records the last error that occurred when connecting,
13186
13462
  // if any. It is cleared when connecting successfully or when reported, so this
@@ -13188,28 +13464,28 @@ var MetricManager = class {
13188
13464
  // we are still not connected.
13189
13465
  lastConnectError = this.#register(
13190
13466
  new State(
13191
- LastConnectError,
13467
+ metric_name_enum_exports.LastConnectError,
13192
13468
  true
13193
13469
  // clearOnFlush
13194
13470
  )
13195
13471
  );
13196
13472
  // notConnected records the reason why the client is not currently connected.
13197
13473
  // It is cleared when the client successfully connects.
13198
- #notConnected = this.#register(new State(NotConnected));
13474
+ #notConnected = this.#register(new State(metric_name_enum_exports.NotConnected));
13199
13475
  // The time from the call to connect() to receiving the 'connected' ws message
13200
13476
  // for the current connection. Cleared when the client is not connected.
13201
13477
  // TODO: Not actually currently cleared on disconnect untill there is a
13202
13478
  // connect error, or client reports disconnected and waiting for visible.
13203
13479
  // Should have a value iff _notConnected has no value.
13204
13480
  #timeToConnectMsV2 = this.#register(
13205
- new Gauge(TimeToConnectMsV2)
13481
+ new Gauge(metric_name_enum_exports.TimeToConnectMsV2)
13206
13482
  );
13207
13483
  // lastConnectErrorV2 records the last error that occurred when connecting,
13208
13484
  // if any. It is cleared when the client successfully connects or
13209
13485
  // stops trying to connect due to being hidden.
13210
13486
  // Should have a value iff notConnected state is NotConnectedReason.Error.
13211
13487
  #lastConnectErrorV2 = this.#register(
13212
- new State(LastConnectErrorV2)
13488
+ new State(metric_name_enum_exports.LastConnectErrorV2)
13213
13489
  );
13214
13490
  // The total time it took to connect across retries for the current
13215
13491
  // connection. Cleared when the client is not connected.
@@ -13218,7 +13494,7 @@ var MetricManager = class {
13218
13494
  // See Zero.#totalToConnectStart for details of how this total is computed.
13219
13495
  // Should have a value iff _notConnected has no value.
13220
13496
  #totalTimeToConnectMs = this.#register(
13221
- new Gauge(TotalTimeToConnectMs)
13497
+ new Gauge(metric_name_enum_exports.TotalTimeToConnectMs)
13222
13498
  );
13223
13499
  #setNotConnectedReason(reason) {
13224
13500
  this.#notConnected.set(reason);
@@ -13360,7 +13636,7 @@ var State = class {
13360
13636
  };
13361
13637
 
13362
13638
  // ../zero-client/src/client/mutation-tracker.ts
13363
- import { resolver as resolver9 } from "@rocicorp/resolver";
13639
+ import { resolver as resolver10 } from "@rocicorp/resolver";
13364
13640
  var currentEphemeralID = 0;
13365
13641
  function nextEphemeralID() {
13366
13642
  return ++currentEphemeralID;
@@ -13398,7 +13674,7 @@ var MutationTracker = class {
13398
13674
  }
13399
13675
  trackMutation() {
13400
13676
  const id = nextEphemeralID();
13401
- const mutationResolver = resolver9();
13677
+ const mutationResolver = resolver10();
13402
13678
  this.#outstandingMutations.set(id, {
13403
13679
  resolver: mutationResolver
13404
13680
  });
@@ -14052,39 +14328,6 @@ function nextBackoff(lc, now) {
14052
14328
  };
14053
14329
  }
14054
14330
 
14055
- // ../zero-client/src/client/server-error.ts
14056
- var ServerError = class extends Error {
14057
- name = "ServerError";
14058
- errorBody;
14059
- get kind() {
14060
- return this.errorBody.kind;
14061
- }
14062
- constructor(errorBody) {
14063
- super(errorBody.kind + ": " + errorBody.message);
14064
- this.errorBody = errorBody;
14065
- }
14066
- };
14067
- function isServerError(ex) {
14068
- return ex instanceof ServerError;
14069
- }
14070
- function isAuthError(ex) {
14071
- return isServerError(ex) && isAuthErrorKind(ex.kind);
14072
- }
14073
- function isAuthErrorKind(kind) {
14074
- return kind === error_kind_enum_exports.AuthInvalidated || kind === error_kind_enum_exports.Unauthorized;
14075
- }
14076
- function isBackoffError(ex) {
14077
- if (isServerError(ex)) {
14078
- switch (ex.errorBody.kind) {
14079
- case error_kind_enum_exports.Rebalance:
14080
- case error_kind_enum_exports.Rehome:
14081
- case error_kind_enum_exports.ServerOverloaded:
14082
- return ex.errorBody;
14083
- }
14084
- }
14085
- return void 0;
14086
- }
14087
-
14088
14331
  // ../zero-client/src/client/server-option.ts
14089
14332
  function validateServerParam(paramName, server) {
14090
14333
  const expectedProtocol = "http";
@@ -14508,7 +14751,6 @@ var ZeroRep = class {
14508
14751
  };
14509
14752
 
14510
14753
  // ../zero-client/src/client/zero.ts
14511
- var onSetConnectionStateSymbol = Symbol();
14512
14754
  var exposedToTestingSymbol = Symbol();
14513
14755
  var createLogOptionsSymbol = Symbol();
14514
14756
  var RUN_LOOP_INTERVAL_MS = 5e3;
@@ -14516,6 +14758,7 @@ var PING_INTERVAL_MS = 5e3;
14516
14758
  var PING_TIMEOUT_MS = 5e3;
14517
14759
  var PULL_TIMEOUT_MS = 5e3;
14518
14760
  var DEFAULT_DISCONNECT_HIDDEN_DELAY_MS = 5e3;
14761
+ var DEFAULT_DISCONNECT_TIMEOUT_MS = 5 * 60 * 1e3;
14519
14762
  var CONNECT_TIMEOUT_MS = 1e4;
14520
14763
  var CHECK_CONNECTIVITY_ON_ERROR_FREQUENCY = 6;
14521
14764
  var NULL_LAST_MUTATION_ID_SENT = { clientID: "", id: -1 };
@@ -14602,12 +14845,11 @@ var Zero = class _Zero {
14602
14845
  };
14603
14846
  #zeroContext;
14604
14847
  queryDelegate;
14605
- #connectResolver = resolver10();
14848
+ #connectResolver = resolver11();
14606
14849
  #pendingPullsByRequestID = /* @__PURE__ */ new Map();
14607
14850
  #lastMutationIDReceived = 0;
14608
14851
  #socket = void 0;
14609
- #socketResolver = resolver10();
14610
- #connectionStateChangeResolver = resolver10();
14852
+ #socketResolver = resolver11();
14611
14853
  /**
14612
14854
  * This resolver is only used for rejections. It is awaited in the connected
14613
14855
  * state (including when waiting for a pong). It is rejected when we get an
@@ -14616,21 +14858,9 @@ var Zero = class _Zero {
14616
14858
  #rejectMessageError = void 0;
14617
14859
  #closeAbortController = new AbortController();
14618
14860
  #visibilityWatcher;
14619
- // We use an accessor pair to allow the subclass to override the setter.
14620
- #connectionState = Disconnected;
14861
+ #connectionManager;
14621
14862
  #activeClientsManager;
14622
14863
  #inspector;
14623
- #setConnectionState(state) {
14624
- if (state === this.#connectionState) {
14625
- return;
14626
- }
14627
- this.#connectionState = state;
14628
- this.#connectionStateChangeResolver.resolve(state);
14629
- this.#connectionStateChangeResolver = resolver10();
14630
- if (false) {
14631
- asTestZero(this)[onSetConnectionStateSymbol]?.(state);
14632
- }
14633
- }
14634
14864
  #connectStart = void 0;
14635
14865
  // Set on connect attempt if currently undefined.
14636
14866
  // Reset to undefined when
@@ -14698,6 +14928,9 @@ var Zero = class _Zero {
14698
14928
  enableAnalytics: this.#enableAnalytics
14699
14929
  });
14700
14930
  const logOptions = this.#logOptions;
14931
+ this.#connectionManager = new ConnectionManager({
14932
+ disconnectTimeoutMs: DEFAULT_DISCONNECT_TIMEOUT_MS
14933
+ });
14701
14934
  const { enableLegacyMutators = true, enableLegacyQueries = true } = schema;
14702
14935
  const replicacheMutators = {
14703
14936
  [CRUD_MUTATION_NAME]: enableLegacyMutators ? makeCRUDMutator(schema) : () => Promise.reject(new Error("Zero CRUD mutators are not enabled."))
@@ -14946,7 +15179,7 @@ var Zero = class _Zero {
14946
15179
  logOptions: this.#logOptions,
14947
15180
  connectStart: () => this.#connectStart,
14948
15181
  socketResolver: () => this.#socketResolver,
14949
- connectionState: () => this.#connectionState
15182
+ connectionManager: () => this.#connectionManager
14950
15183
  };
14951
15184
  }
14952
15185
  }
@@ -14978,7 +15211,7 @@ var Zero = class _Zero {
14978
15211
  }
14979
15212
  }
14980
15213
  #send(msg) {
14981
- if (this.#socket && this.#connectionState === Connected) {
15214
+ if (this.#socket && this.#connectionManager.is(connection_status_enum_exports.Connected)) {
14982
15215
  send(this.#socket, msg);
14983
15216
  }
14984
15217
  }
@@ -15025,6 +15258,27 @@ var Zero = class _Zero {
15025
15258
  get schemaVersion() {
15026
15259
  return this.#rep.schemaVersion;
15027
15260
  }
15261
+ /**
15262
+ * The schema passed into Zero when it was constructed.
15263
+ *
15264
+ * This can be paired with the inspector API to explore the client cache for
15265
+ * debugging or tooling. The inspector exposes the raw key/value map as well
15266
+ * as the per-table rows that back `zero.query[tableName].run()`.
15267
+ *
15268
+ * ```ts
15269
+ * const inspector = __zero.inspector;
15270
+ * const client = inspector.client;
15271
+ *
15272
+ * console.log('client map:', await client.map());
15273
+ *
15274
+ * for (const tableName of Object.keys(__zero.schema.tables)) {
15275
+ * console.table(await client.rows(tableName));
15276
+ * }
15277
+ * ```
15278
+ */
15279
+ get schema() {
15280
+ return this.#options.schema;
15281
+ }
15028
15282
  /**
15029
15283
  * The client ID for this instance of Zero. Each instance
15030
15284
  * gets a unique client ID.
@@ -15079,7 +15333,7 @@ var Zero = class _Zero {
15079
15333
  * longer query or mutate data with it, and its query views stop updating.
15080
15334
  */
15081
15335
  get closed() {
15082
- return this.#rep.closed;
15336
+ return this.#connectionManager.is(connection_status_enum_exports.Closed);
15083
15337
  }
15084
15338
  /**
15085
15339
  * Closes this Zero instance.
@@ -15089,23 +15343,36 @@ var Zero = class _Zero {
15089
15343
  */
15090
15344
  async close() {
15091
15345
  const lc = this.#lc.withContext("close");
15092
- lc.debug?.("Closing Zero instance. Stack:", new Error().stack);
15093
- this.#onlineManager.cleanup();
15094
- if (this.#connectionState !== Disconnected) {
15095
- this.#disconnect(
15096
- lc,
15097
- {
15098
- client: "ClientClosed"
15099
- },
15100
- CLOSE_CODE_NORMAL
15101
- );
15346
+ try {
15347
+ if (this.closed) {
15348
+ lc.debug?.("close() called on already closed instance");
15349
+ return;
15350
+ }
15351
+ lc.debug?.("Closing Zero instance. Stack:", new Error().stack);
15352
+ this.#onlineManager.cleanup();
15353
+ if (!this.#connectionManager.is(connection_status_enum_exports.Disconnected)) {
15354
+ this.#disconnect(
15355
+ lc,
15356
+ new ClientError({
15357
+ kind: client_error_kind_enum_exports.ClientClosed,
15358
+ message: "Zero instance closed by user"
15359
+ }),
15360
+ CLOSE_CODE_NORMAL
15361
+ );
15362
+ }
15363
+ lc.debug?.("Aborting closeAbortController due to close()");
15364
+ this.#closeAbortController.abort();
15365
+ this.#metrics.stop();
15366
+ const ret = await this.#rep.close();
15367
+ this.#unexpose();
15368
+ return ret;
15369
+ } catch (e) {
15370
+ lc.error?.("Error closing Zero instance", e);
15371
+ throw e;
15372
+ } finally {
15373
+ this.#connectionManager.closed();
15374
+ this.#connectionManager.cleanup();
15102
15375
  }
15103
- lc.debug?.("Aborting closeAbortController due to close()");
15104
- this.#closeAbortController.abort();
15105
- this.#metrics.stop();
15106
- const ret = await this.#rep.close();
15107
- this.#unexpose();
15108
- return ret;
15109
15376
  }
15110
15377
  #onMessage = (e) => {
15111
15378
  const lc = this.#lc;
@@ -15193,9 +15460,17 @@ var Zero = class _Zero {
15193
15460
  wasClean
15194
15461
  });
15195
15462
  }
15196
- const closeKind = wasClean ? "CleanClose" : "AbruptClose";
15197
- this.#connectResolver.reject(new CloseError(closeKind));
15198
- this.#disconnect(lc, { client: closeKind });
15463
+ const closeError2 = new ClientError(
15464
+ wasClean ? {
15465
+ kind: client_error_kind_enum_exports.CleanClose,
15466
+ message: "WebSocket connection closed cleanly"
15467
+ } : {
15468
+ kind: client_error_kind_enum_exports.AbruptClose,
15469
+ message: "WebSocket connection closed abruptly"
15470
+ }
15471
+ );
15472
+ this.#connectResolver.reject(closeError2);
15473
+ this.#disconnect(lc, closeError2);
15199
15474
  };
15200
15475
  // An error on the connection is fatal for the connection.
15201
15476
  async #handleErrorMessage(lc, downMessage) {
@@ -15213,7 +15488,7 @@ ${error.errorBody.message}`, error);
15213
15488
  this.#rejectMessageError?.reject(error);
15214
15489
  lc.debug?.("Rejecting connect resolver due to error", error);
15215
15490
  this.#connectResolver.reject(error);
15216
- this.#disconnect(lc, { server: kind });
15491
+ this.#disconnect(lc, error);
15217
15492
  if (kind === error_kind_enum_exports.VersionNotSupported) {
15218
15493
  this.#onUpdateNeeded({ type: kind, message });
15219
15494
  } else if (kind === error_kind_enum_exports.SchemaVersionNotSupported) {
@@ -15311,7 +15586,7 @@ ${error.errorBody.message}`, error);
15311
15586
  }
15312
15587
  this.#initConnectionQueries = void 0;
15313
15588
  maybeSendDeletedClients();
15314
- this.#setConnectionState(Connected);
15589
+ this.#connectionManager.connected();
15315
15590
  this.#connectResolver.resolve();
15316
15591
  }
15317
15592
  /**
@@ -15319,8 +15594,9 @@ ${error.errorBody.message}`, error);
15319
15594
  * request to the server.
15320
15595
  *
15321
15596
  * {@link #connect} will throw an assertion error if the
15322
- * {@link #connectionState} is not {@link ConnectionState.Disconnected}.
15323
- * Callers MUST check the connection state before calling this method and log
15597
+ * {@link #connectionManager} status is not {@link ConnectionState.Disconnected}
15598
+ * or {@link ConnectionState.Connecting}.
15599
+ * Callers MUST check the connection status before calling this method and log
15324
15600
  * an error as needed.
15325
15601
  *
15326
15602
  * The function will resolve once the socket is connected. If you need to know
@@ -15332,11 +15608,13 @@ ${error.errorBody.message}`, error);
15332
15608
  */
15333
15609
  async #connect(lc, additionalConnectParams) {
15334
15610
  assert(this.#server);
15335
- assert(this.#connectionState === Disconnected);
15611
+ assert(
15612
+ this.#connectionManager.is(connection_status_enum_exports.Disconnected) || this.#connectionManager.is(connection_status_enum_exports.Connecting)
15613
+ );
15336
15614
  const wsid = nanoid();
15337
15615
  lc = addWebSocketIDToLogContext(wsid, lc);
15338
15616
  lc.info?.("Connecting...", { navigatorOnline: localNavigator?.onLine });
15339
- this.#setConnectionState(Connecting);
15617
+ this.#connectionManager.connecting();
15340
15618
  assert(this.#connectStart === void 0);
15341
15619
  const now = Date.now();
15342
15620
  this.#connectStart = now;
@@ -15356,10 +15634,12 @@ ${error.errorBody.message}`, error);
15356
15634
  }
15357
15635
  const timeoutID = setTimeout(() => {
15358
15636
  lc.debug?.("Rejecting connect resolver due to timeout");
15359
- this.#connectResolver.reject(new TimedOutError("Connect"));
15360
- this.#disconnect(lc, {
15361
- client: "ConnectTimeout"
15637
+ const timeoutError = new ClientError({
15638
+ kind: client_error_kind_enum_exports.ConnectTimeout,
15639
+ message: `Connection attempt timed out after ${CONNECT_TIMEOUT_MS / 1e3} seconds`
15362
15640
  });
15641
+ this.#connectResolver.reject(timeoutError);
15642
+ this.#disconnect(lc, timeoutError);
15363
15643
  }, CONNECT_TIMEOUT_MS);
15364
15644
  const abortHandler = () => {
15365
15645
  clearTimeout(timeoutID);
@@ -15411,22 +15691,23 @@ ${error.errorBody.message}`, error);
15411
15691
  }
15412
15692
  }
15413
15693
  #disconnect(lc, reason, closeCode) {
15414
- if (this.#connectionState === Connecting) {
15694
+ if (this.#connectionManager.is(connection_status_enum_exports.Connecting)) {
15415
15695
  this.#connectErrorCount++;
15416
15696
  }
15417
15697
  lc.info?.("disconnecting", {
15418
15698
  navigatorOnline: localNavigator?.onLine,
15419
- reason,
15699
+ reason: reason.kind,
15420
15700
  connectStart: this.#connectStart,
15421
15701
  totalToConnectStart: this.#totalToConnectStart,
15422
15702
  connectedAt: this.#connectedAt,
15423
15703
  connectionDuration: this.#connectedAt ? Date.now() - this.#connectedAt : 0,
15424
15704
  messageCount: this.#messageCount,
15425
- connectionState: this.#connectionState,
15705
+ connectionState: this.#connectionManager.state,
15426
15706
  connectErrorCount: this.#connectErrorCount
15427
15707
  });
15428
- switch (this.#connectionState) {
15429
- case Connected: {
15708
+ const connectionState = this.#connectionManager.state.name;
15709
+ switch (connectionState) {
15710
+ case connection_status_enum_exports.Connected: {
15430
15711
  if (this.#connectStart !== void 0) {
15431
15712
  lc.error?.(
15432
15713
  "disconnect() called while connected but connect start time is defined."
@@ -15434,7 +15715,8 @@ ${error.errorBody.message}`, error);
15434
15715
  }
15435
15716
  break;
15436
15717
  }
15437
- case Connecting: {
15718
+ case connection_status_enum_exports.Disconnected:
15719
+ case connection_status_enum_exports.Connecting: {
15438
15720
  this.#metrics.lastConnectError.set(getLastConnectErrorValue(reason));
15439
15721
  this.#metrics.timeToConnectMs.set(DID_NOT_CONNECT_VALUE);
15440
15722
  this.#metrics.setConnectError(reason);
@@ -15450,14 +15732,13 @@ ${error.errorBody.message}`, error);
15450
15732
  }
15451
15733
  break;
15452
15734
  }
15453
- case Disconnected:
15454
- lc.error?.("disconnect() called while disconnected");
15455
- break;
15735
+ case connection_status_enum_exports.Closed:
15736
+ lc.error?.("disconnect() called while closed");
15737
+ return;
15456
15738
  }
15457
- this.#socketResolver = resolver10();
15739
+ this.#socketResolver = resolver11();
15458
15740
  lc.debug?.("Creating new connect resolver");
15459
- this.#connectResolver = resolver10();
15460
- this.#setConnectionState(Disconnected);
15741
+ this.#connectResolver = resolver11();
15461
15742
  this.#messageCount = 0;
15462
15743
  this.#connectStart = void 0;
15463
15744
  this.#connectedAt = 0;
@@ -15468,6 +15749,12 @@ ${error.errorBody.message}`, error);
15468
15749
  this.#socket = void 0;
15469
15750
  this.#lastMutationIDSent = NULL_LAST_MUTATION_ID_SENT;
15470
15751
  this.#pokeHandler.handleDisconnect();
15752
+ const isStillConnecting = reason instanceof ClientError && (reason.kind === client_error_kind_enum_exports.ConnectTimeout || reason.kind === client_error_kind_enum_exports.Hidden);
15753
+ if (isStillConnecting) {
15754
+ this.#connectionManager.connecting(reason);
15755
+ } else {
15756
+ this.#connectionManager.disconnected(reason);
15757
+ }
15471
15758
  }
15472
15759
  #handlePokeStart(_lc, pokeMessage) {
15473
15760
  this.#abortPingTimeout();
@@ -15490,12 +15777,16 @@ ${error.errorBody.message}`, error);
15490
15777
  const lc = this.#lc;
15491
15778
  lc.info?.(
15492
15779
  "poke error, disconnecting?",
15493
- this.#connectionState !== Disconnected
15780
+ !this.#connectionManager.is(connection_status_enum_exports.Disconnected)
15494
15781
  );
15495
- if (this.#connectionState !== Disconnected) {
15496
- this.#disconnect(lc, {
15497
- client: "UnexpectedBaseCookie"
15498
- });
15782
+ if (!this.#connectionManager.is(connection_status_enum_exports.Disconnected)) {
15783
+ this.#disconnect(
15784
+ lc,
15785
+ new ClientError({
15786
+ kind: client_error_kind_enum_exports.UnexpectedBaseCookie,
15787
+ message: "Server returned unexpected base cookie during sync"
15788
+ })
15789
+ );
15499
15790
  }
15500
15791
  }
15501
15792
  #handlePullResponse(lc, pullResponseMessage) {
@@ -15503,12 +15794,12 @@ ${error.errorBody.message}`, error);
15503
15794
  const body = pullResponseMessage[1];
15504
15795
  lc = lc.withContext("requestID", body.requestID);
15505
15796
  lc.debug?.("Handling pull response", body);
15506
- const resolver11 = this.#pendingPullsByRequestID.get(body.requestID);
15507
- if (!resolver11) {
15797
+ const resolver12 = this.#pendingPullsByRequestID.get(body.requestID);
15798
+ if (!resolver12) {
15508
15799
  lc.debug?.("No resolver found");
15509
15800
  return;
15510
15801
  }
15511
- resolver11.resolve(pullResponseMessage[1]);
15802
+ resolver12.resolve(pullResponseMessage[1]);
15512
15803
  }
15513
15804
  async #pusher(req, requestID) {
15514
15805
  assert(req.pushVersion === 1);
@@ -15581,6 +15872,12 @@ ${error.errorBody.message}`, error);
15581
15872
  this.#lc.info?.(`Starting Zero version: ${this.version}`);
15582
15873
  if (this.#server === null) {
15583
15874
  this.#lc.info?.("No socket origin provided, not starting connect loop.");
15875
+ this.#connectionManager.disconnected(
15876
+ new ClientError({
15877
+ kind: client_error_kind_enum_exports.NoSocketOrigin,
15878
+ message: "No server socket origin provided"
15879
+ })
15880
+ );
15584
15881
  return;
15585
15882
  }
15586
15883
  let runLoopCounter = 0;
@@ -15598,13 +15895,14 @@ ${error.errorBody.message}`, error);
15598
15895
  let gotError = false;
15599
15896
  let backoffMs = RUN_LOOP_INTERVAL_MS;
15600
15897
  let additionalConnectParams;
15601
- while (!this.closed) {
15898
+ while (this.#connectionManager.shouldContinueRunLoop()) {
15602
15899
  runLoopCounter++;
15603
15900
  let lc = getLogContext();
15604
15901
  backoffMs = RUN_LOOP_INTERVAL_MS;
15605
15902
  try {
15606
- switch (this.#connectionState) {
15607
- case Disconnected: {
15903
+ switch (this.#connectionManager.state.name) {
15904
+ case connection_status_enum_exports.Connecting:
15905
+ case connection_status_enum_exports.Disconnected: {
15608
15906
  if (this.#visibilityWatcher.visibilityState === "hidden") {
15609
15907
  this.#metrics.setDisconnectedWaitingForVisible();
15610
15908
  this.#totalToConnectStart = void 0;
@@ -15630,25 +15928,21 @@ ${error.errorBody.message}`, error);
15630
15928
  this.#setOnline(true);
15631
15929
  break;
15632
15930
  }
15633
- case Connecting:
15634
- lc.error?.("unreachable");
15635
- gotError = true;
15636
- break;
15637
- case Connected: {
15931
+ case connection_status_enum_exports.Connected: {
15638
15932
  const controller = new AbortController();
15639
15933
  this.#abortPingTimeout = () => controller.abort();
15640
15934
  const [pingTimeoutPromise, pingTimeoutAborted] = sleepWithAbort(
15641
15935
  PING_INTERVAL_MS,
15642
15936
  controller.signal
15643
15937
  );
15644
- this.#rejectMessageError = resolver10();
15938
+ this.#rejectMessageError = resolver11();
15645
15939
  const PING = 0;
15646
15940
  const HIDDEN = 2;
15647
15941
  const raceResult = await promiseRace([
15648
15942
  pingTimeoutPromise,
15649
15943
  pingTimeoutAborted,
15650
15944
  this.#visibilityWatcher.waitForHidden(),
15651
- this.#connectionStateChangeResolver.promise,
15945
+ this.#connectionManager.waitForStateChange(),
15652
15946
  this.#rejectMessageError.promise
15653
15947
  ]);
15654
15948
  if (this.closed) {
@@ -15667,17 +15961,25 @@ ${error.errorBody.message}`, error);
15667
15961
  break;
15668
15962
  }
15669
15963
  case HIDDEN:
15670
- this.#disconnect(lc, {
15671
- client: "Hidden"
15672
- });
15964
+ this.#disconnect(
15965
+ lc,
15966
+ new ClientError({
15967
+ kind: client_error_kind_enum_exports.Hidden,
15968
+ message: "Connection closed because tab was hidden"
15969
+ })
15970
+ );
15673
15971
  this.#setOnline(false);
15674
15972
  break;
15675
15973
  }
15676
15974
  this.#rejectMessageError = void 0;
15975
+ break;
15677
15976
  }
15977
+ case connection_status_enum_exports.Closed:
15978
+ this.#rejectMessageError = void 0;
15979
+ break;
15678
15980
  }
15679
15981
  } catch (ex) {
15680
- if (this.#connectionState !== Connected) {
15982
+ if (!this.#connectionManager.is(connection_status_enum_exports.Connected)) {
15681
15983
  const level = isAuthError(ex) ? "warn" : "error";
15682
15984
  const kind = isServerError(ex) ? ex.kind : "Unknown Error";
15683
15985
  lc[level]?.("Failed to connect", ex, kind, {
@@ -15688,7 +15990,7 @@ ${error.errorBody.message}`, error);
15688
15990
  lc.debug?.(
15689
15991
  "Got an exception in the run loop",
15690
15992
  "state:",
15691
- this.#connectionState,
15993
+ this.#connectionManager.state,
15692
15994
  "exception:",
15693
15995
  ex
15694
15996
  );
@@ -15700,7 +16002,7 @@ ${error.errorBody.message}`, error);
15700
16002
  continue;
15701
16003
  }
15702
16004
  }
15703
- if (isServerError(ex) || ex instanceof TimedOutError || ex instanceof CloseError) {
16005
+ if (isServerError(ex) || isClientError(ex) && (ex.kind === client_error_kind_enum_exports.ConnectTimeout || ex.kind === client_error_kind_enum_exports.AbruptClose || ex.kind === client_error_kind_enum_exports.CleanClose)) {
15704
16006
  gotError = true;
15705
16007
  }
15706
16008
  const backoffError = isBackoffError(ex);
@@ -15720,7 +16022,7 @@ ${error.errorBody.message}`, error);
15720
16022
  "Sleeping",
15721
16023
  backoffMs,
15722
16024
  "ms before reconnecting due to error, state:",
15723
- this.#connectionState
16025
+ this.#connectionManager.state
15724
16026
  );
15725
16027
  await sleep(backoffMs);
15726
16028
  }
@@ -15756,7 +16058,7 @@ ${error.errorBody.message}`, error);
15756
16058
  }
15757
16059
  ];
15758
16060
  send(socket, pullRequestMessage);
15759
- const pullResponseResolver = resolver10();
16061
+ const pullResponseResolver = resolver11();
15760
16062
  this.#pendingPullsByRequestID.set(requestID, pullResponseResolver);
15761
16063
  try {
15762
16064
  const TIMEOUT = 0;
@@ -15819,7 +16121,7 @@ ${error.errorBody.message}`, error);
15819
16121
  */
15820
16122
  async #ping(lc, messageErrorRejectionPromise) {
15821
16123
  lc.debug?.("pinging");
15822
- const { promise, resolve } = resolver10();
16124
+ const { promise, resolve } = resolver11();
15823
16125
  this.#onPong = resolve;
15824
16126
  const pingMessage = ["ping", {}];
15825
16127
  const t0 = performance.now();
@@ -15833,9 +16135,13 @@ ${error.errorBody.message}`, error);
15833
16135
  const delta = performance.now() - t0;
15834
16136
  if (!connected) {
15835
16137
  lc.info?.("ping failed in", delta, "ms - disconnecting");
15836
- this.#disconnect(lc, {
15837
- client: "PingTimeout"
15838
- });
16138
+ this.#disconnect(
16139
+ lc,
16140
+ new ClientError({
16141
+ kind: client_error_kind_enum_exports.PingTimeout,
16142
+ message: "Server ping request timed out"
16143
+ })
16144
+ );
15839
16145
  return TimedOut;
15840
16146
  }
15841
16147
  lc.debug?.("ping succeeded in", delta, "ms");
@@ -16001,13 +16307,6 @@ function addWebSocketIDToLogContext(wsid, lc) {
16001
16307
  function promiseRace(ps) {
16002
16308
  return Promise.race(ps.map((p, i) => p.then(() => i)));
16003
16309
  }
16004
- var TimedOutError = class extends Error {
16005
- constructor(m) {
16006
- super(`${m} timed out`);
16007
- }
16008
- };
16009
- var CloseError = class extends Error {
16010
- };
16011
16310
  function assertValidRunOptions2(_options) {
16012
16311
  }
16013
16312
  async function makeActiveClientsManager(clientGroupID, clientID, signal, onDelete) {
@@ -16048,4 +16347,4 @@ export {
16048
16347
  update_needed_reason_type_enum_exports,
16049
16348
  Zero
16050
16349
  };
16051
- //# sourceMappingURL=chunk-TA2NZPJQ.js.map
16350
+ //# sourceMappingURL=chunk-MXPHMVU7.js.map