@rocicorp/zero 0.22.2025072901 → 0.22.2025080100

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 (99) hide show
  1. package/out/{chunk-4OOERLIO.js → chunk-CV3OCOGM.js} +168 -147
  2. package/out/chunk-CV3OCOGM.js.map +7 -0
  3. package/out/{chunk-T4AG3HHZ.js → chunk-DIPRUNYS.js} +9 -9
  4. package/out/{chunk-T4AG3HHZ.js.map → chunk-DIPRUNYS.js.map} +3 -3
  5. package/out/{chunk-P5M53J4D.js → chunk-LENWM5WE.js} +10 -5
  6. package/out/{chunk-P5M53J4D.js.map → chunk-LENWM5WE.js.map} +2 -2
  7. package/out/{inspector-TFZBDN6K.js → inspector-AF3UI76B.js} +2 -2
  8. package/out/react.js +15 -3
  9. package/out/react.js.map +4 -4
  10. package/out/shared/src/subscribable.d.ts +22 -0
  11. package/out/shared/src/subscribable.d.ts.map +1 -0
  12. package/out/solid.js +16 -4
  13. package/out/solid.js.map +4 -4
  14. package/out/zero/package.json +3 -3
  15. package/out/zero/src/adapters/drizzle-pg.d.ts +2 -0
  16. package/out/zero/src/adapters/drizzle-pg.d.ts.map +1 -0
  17. package/out/zero/src/adapters/drizzle-pg.js +2 -0
  18. package/out/zero/src/adapters/drizzle-pg.js.map +1 -0
  19. package/out/zero/src/adapters/postgresjs.d.ts +2 -0
  20. package/out/zero/src/adapters/postgresjs.d.ts.map +1 -0
  21. package/out/zero/src/adapters/postgresjs.js +2 -0
  22. package/out/zero/src/adapters/postgresjs.js.map +1 -0
  23. package/out/zero-cache/src/server/syncer.d.ts.map +1 -1
  24. package/out/zero-cache/src/server/syncer.js +3 -3
  25. package/out/zero-cache/src/server/syncer.js.map +1 -1
  26. package/out/zero-cache/src/services/mutagen/pusher.d.ts +16 -4
  27. package/out/zero-cache/src/services/mutagen/pusher.d.ts.map +1 -1
  28. package/out/zero-cache/src/services/mutagen/pusher.js +9 -24
  29. package/out/zero-cache/src/services/mutagen/pusher.js.map +1 -1
  30. package/out/zero-cache/src/services/view-syncer/client-handler.d.ts.map +1 -1
  31. package/out/zero-cache/src/services/view-syncer/client-handler.js +12 -2
  32. package/out/zero-cache/src/services/view-syncer/client-handler.js.map +1 -1
  33. package/out/zero-cache/src/services/view-syncer/cvr-store.d.ts +1 -1
  34. package/out/zero-cache/src/services/view-syncer/cvr-store.d.ts.map +1 -1
  35. package/out/zero-cache/src/services/view-syncer/cvr-store.js +23 -4
  36. package/out/zero-cache/src/services/view-syncer/cvr-store.js.map +1 -1
  37. package/out/zero-cache/src/services/view-syncer/cvr.d.ts +2 -1
  38. package/out/zero-cache/src/services/view-syncer/cvr.d.ts.map +1 -1
  39. package/out/zero-cache/src/services/view-syncer/cvr.js +35 -42
  40. package/out/zero-cache/src/services/view-syncer/cvr.js.map +1 -1
  41. package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts +1 -1
  42. package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts.map +1 -1
  43. package/out/zero-cache/src/services/view-syncer/view-syncer.js +12 -12
  44. package/out/zero-cache/src/services/view-syncer/view-syncer.js.map +1 -1
  45. package/out/zero-client/src/client/keys.d.ts +3 -0
  46. package/out/zero-client/src/client/keys.d.ts.map +1 -1
  47. package/out/zero-client/src/client/mutation-tracker.d.ts +7 -26
  48. package/out/zero-client/src/client/mutation-tracker.d.ts.map +1 -1
  49. package/out/zero-client/src/client/options.d.ts +6 -0
  50. package/out/zero-client/src/client/options.d.ts.map +1 -1
  51. package/out/zero-client/src/client/zero-poke-handler.d.ts +2 -1
  52. package/out/zero-client/src/client/zero-poke-handler.d.ts.map +1 -1
  53. package/out/zero-client/src/client/zero.d.ts +16 -1
  54. package/out/zero-client/src/client/zero.d.ts.map +1 -1
  55. package/out/zero-client/src/mod.d.ts +2 -2
  56. package/out/zero-client/src/mod.d.ts.map +1 -1
  57. package/out/zero-protocol/src/down.d.ts +8 -2
  58. package/out/zero-protocol/src/down.d.ts.map +1 -1
  59. package/out/zero-protocol/src/mutations-patch.d.ts +23 -4
  60. package/out/zero-protocol/src/mutations-patch.d.ts.map +1 -1
  61. package/out/zero-protocol/src/mutations-patch.js +6 -2
  62. package/out/zero-protocol/src/mutations-patch.js.map +1 -1
  63. package/out/zero-protocol/src/poke.d.ts +16 -4
  64. package/out/zero-protocol/src/poke.d.ts.map +1 -1
  65. package/out/zero-protocol/src/protocol-version.d.ts +1 -1
  66. package/out/zero-protocol/src/protocol-version.d.ts.map +1 -1
  67. package/out/zero-protocol/src/protocol-version.js +3 -2
  68. package/out/zero-protocol/src/protocol-version.js.map +1 -1
  69. package/out/zero-react/src/mod.d.ts +1 -0
  70. package/out/zero-react/src/mod.d.ts.map +1 -1
  71. package/out/zero-react/src/use-zero-online.d.ts +9 -0
  72. package/out/zero-react/src/use-zero-online.d.ts.map +1 -0
  73. package/out/zero-server/src/adapters/drizzle-pg.d.ts +22 -0
  74. package/out/zero-server/src/adapters/drizzle-pg.d.ts.map +1 -0
  75. package/out/zero-server/src/adapters/drizzle-pg.js +39 -0
  76. package/out/zero-server/src/adapters/drizzle-pg.js.map +1 -0
  77. package/out/zero-server/src/push-processor.d.ts +2 -1
  78. package/out/zero-server/src/push-processor.d.ts.map +1 -1
  79. package/out/zero-server/src/push-processor.js +12 -6
  80. package/out/zero-server/src/push-processor.js.map +1 -1
  81. package/out/zero-server/src/zql-database.d.ts.map +1 -1
  82. package/out/zero-server/src/zql-database.js +6 -0
  83. package/out/zero-server/src/zql-database.js.map +1 -1
  84. package/out/zero-solid/src/mod.d.ts +1 -0
  85. package/out/zero-solid/src/mod.d.ts.map +1 -1
  86. package/out/zero-solid/src/use-zero-online.d.ts +15 -0
  87. package/out/zero-solid/src/use-zero-online.d.ts.map +1 -0
  88. package/out/zero.js +7 -9
  89. package/out/zql/src/query/named.d.ts +2 -2
  90. package/out/zql/src/query/named.d.ts.map +1 -1
  91. package/out/zql/src/query/named.js +2 -2
  92. package/out/zql/src/query/named.js.map +1 -1
  93. package/out/zql/src/query/ttl.d.ts +3 -3
  94. package/out/zql/src/query/ttl.d.ts.map +1 -1
  95. package/out/zql/src/query/ttl.js +5 -5
  96. package/out/zql/src/query/ttl.js.map +1 -1
  97. package/package.json +3 -3
  98. package/out/chunk-4OOERLIO.js.map +0 -7
  99. /package/out/{inspector-TFZBDN6K.js.map → inspector-AF3UI76B.js.map} +0 -0
@@ -9,6 +9,7 @@ import {
9
9
  ENTITIES_KEY_PREFIX,
10
10
  GOT_QUERIES_KEY_PREFIX,
11
11
  Latest,
12
+ MUTATIONS_KEY_PREFIX,
12
13
  V6,
13
14
  V7,
14
15
  addDiffsForIndexes,
@@ -116,6 +117,7 @@ import {
116
117
  test,
117
118
  toDesiredQueriesKey,
118
119
  toGotQueriesKey,
120
+ toMutationResponseKey,
119
121
  toPrimaryKeyString,
120
122
  transformFilters,
121
123
  unreachable,
@@ -126,7 +128,7 @@ import {
126
128
  withWrite,
127
129
  withWriteNoImplicitCommit,
128
130
  wrapIterable
129
- } from "./chunk-P5M53J4D.js";
131
+ } from "./chunk-LENWM5WE.js";
130
132
  import {
131
133
  __export
132
134
  } from "./chunk-424PT5DM.js";
@@ -6152,7 +6154,11 @@ var putOpSchema2 = valita_exports.object({
6152
6154
  op: valita_exports.literal("put"),
6153
6155
  mutation: mutationResponseSchema
6154
6156
  });
6155
- var patchOpSchema2 = putOpSchema2;
6157
+ var delOpSchema2 = valita_exports.object({
6158
+ op: valita_exports.literal("del"),
6159
+ id: mutationIDSchema
6160
+ });
6161
+ var patchOpSchema2 = valita_exports.union(putOpSchema2, delOpSchema2);
6156
6162
  var mutationsPatchSchema = valita_exports.array(patchOpSchema2);
6157
6163
 
6158
6164
  // ../zero-protocol/src/row-patch.ts
@@ -6168,7 +6174,7 @@ var updateOpSchema2 = valita_exports.object({
6168
6174
  merge: jsonObjectSchema.optional(),
6169
6175
  constrain: valita_exports.array(valita_exports.string()).optional()
6170
6176
  });
6171
- var delOpSchema2 = valita_exports.object({
6177
+ var delOpSchema3 = valita_exports.object({
6172
6178
  op: valita_exports.literal("del"),
6173
6179
  tableName: valita_exports.string(),
6174
6180
  id: primaryKeyValueRecordSchema
@@ -6179,7 +6185,7 @@ var clearOpSchema2 = valita_exports.object({
6179
6185
  var rowPatchOpSchema = valita_exports.union(
6180
6186
  putOpSchema3,
6181
6187
  updateOpSchema2,
6182
- delOpSchema2,
6188
+ delOpSchema3,
6183
6189
  clearOpSchema2
6184
6190
  );
6185
6191
  var rowsPatchSchema = valita_exports.array(rowPatchOpSchema);
@@ -6282,7 +6288,7 @@ var downstreamSchema = valita_exports.union(
6282
6288
  );
6283
6289
 
6284
6290
  // ../zero-protocol/src/protocol-version.ts
6285
- var PROTOCOL_VERSION = 24;
6291
+ var PROTOCOL_VERSION = 25;
6286
6292
  var MIN_SERVER_SUPPORTED_SYNC_PROTOCOL = 18;
6287
6293
  assert(MIN_SERVER_SUPPORTED_SYNC_PROTOCOL < PROTOCOL_VERSION);
6288
6294
 
@@ -8574,7 +8580,7 @@ function makeMessage(message, context, logLevel) {
8574
8580
  }
8575
8581
 
8576
8582
  // ../zero-client/src/client/version.ts
8577
- var version2 = "0.22.2025072901";
8583
+ var version2 = "0.22.2025080100";
8578
8584
 
8579
8585
  // ../zero-client/src/client/log-options.ts
8580
8586
  var LevelFilterLogSink = class {
@@ -8870,12 +8876,6 @@ var State = class {
8870
8876
 
8871
8877
  // ../zero-client/src/client/mutation-tracker.ts
8872
8878
  import { resolver as resolver8 } from "@rocicorp/resolver";
8873
- var completeFailureTypes = [
8874
- // These should never actually be received as they cause the websocket
8875
- // connection to be closed.
8876
- "unsupportedPushVersion",
8877
- "unsupportedSchemaVersion"
8878
- ];
8879
8879
  var currentEphemeralID = 0;
8880
8880
  function nextEphemeralID() {
8881
8881
  return ++currentEphemeralID;
@@ -8885,11 +8885,6 @@ var MutationTracker = class {
8885
8885
  #ephemeralIDsByMutationID;
8886
8886
  #allMutationsAppliedListeners;
8887
8887
  #lc;
8888
- #limboMutations;
8889
- // This is only used in the new code path that processes
8890
- // mutation responses that arrive via the `poke` protocol.
8891
- // The old code path will be removed in the release after
8892
- // the one containing mutation-responses-via-poke.
8893
8888
  #ackMutations;
8894
8889
  #clientID;
8895
8890
  #largestOutstandingMutationID;
@@ -8899,13 +8894,22 @@ var MutationTracker = class {
8899
8894
  this.#outstandingMutations = /* @__PURE__ */ new Map();
8900
8895
  this.#ephemeralIDsByMutationID = /* @__PURE__ */ new Map();
8901
8896
  this.#allMutationsAppliedListeners = /* @__PURE__ */ new Set();
8902
- this.#limboMutations = /* @__PURE__ */ new Set();
8903
8897
  this.#largestOutstandingMutationID = 0;
8904
8898
  this.#currentMutationID = 0;
8905
8899
  this.#ackMutations = ackMutations;
8906
8900
  }
8907
- set clientID(clientID) {
8901
+ setClientIDAndWatch(clientID, experimentalWatch) {
8902
+ assert(this.#clientID === void 0, "clientID already set");
8908
8903
  this.#clientID = clientID;
8904
+ experimentalWatch(
8905
+ (diffs) => {
8906
+ this.#processMutationResponses(diffs);
8907
+ },
8908
+ {
8909
+ prefix: MUTATIONS_KEY_PREFIX + clientID + "/",
8910
+ initialValuesInFirstDiff: true
8911
+ }
8912
+ );
8909
8913
  }
8910
8914
  trackMutation() {
8911
8915
  const id = nextEphemeralID();
@@ -8939,23 +8943,39 @@ var MutationTracker = class {
8939
8943
  /**
8940
8944
  * Used when zero-cache pokes down mutation results.
8941
8945
  */
8942
- processMutationResponses(patches) {
8943
- try {
8944
- for (const patch of patches) {
8945
- if (patch.mutation.id.clientID !== this.#clientID) {
8946
- continue;
8947
- }
8948
- if ("error" in patch.mutation.result) {
8949
- this.#processMutationError(patch.mutation.id, patch.mutation.result);
8950
- } else {
8951
- this.#processMutationOk(patch.mutation.id, patch.mutation.result);
8946
+ #processMutationResponses(diffs) {
8947
+ const clientID = must(this.#clientID);
8948
+ let largestLmid = 0;
8949
+ for (const diff3 of diffs) {
8950
+ const mutationID = Number(
8951
+ diff3.key.slice(MUTATIONS_KEY_PREFIX.length + clientID.length + 1)
8952
+ );
8953
+ assert(
8954
+ !isNaN(mutationID),
8955
+ `MutationTracker received a diff with an invalid mutation ID: ${diff3.key}`
8956
+ );
8957
+ largestLmid = Math.max(largestLmid, mutationID);
8958
+ switch (diff3.op) {
8959
+ case "add": {
8960
+ const result = parse(diff3.newValue, mutationResultSchema);
8961
+ if ("error" in result) {
8962
+ this.#processMutationError(clientID, mutationID, result);
8963
+ } else {
8964
+ this.#processMutationOk(clientID, mutationID, result);
8965
+ }
8966
+ break;
8952
8967
  }
8968
+ case "del":
8969
+ break;
8970
+ case "change":
8971
+ throw new Error("MutationTracker does not expect change operations");
8953
8972
  }
8954
- } finally {
8955
- const last = patches[patches.length - 1];
8956
- if (last) {
8957
- this.#ackMutations(last.mutation.id);
8958
- }
8973
+ }
8974
+ if (largestLmid > 0) {
8975
+ this.#ackMutations({
8976
+ clientID: must(this.#clientID),
8977
+ id: largestLmid
8978
+ });
8959
8979
  }
8960
8980
  }
8961
8981
  processPushResponse(response) {
@@ -8964,12 +8984,14 @@ var MutationTracker = class {
8964
8984
  "Received an error response when pushing mutations",
8965
8985
  response
8966
8986
  );
8967
- this.#processPushError(response);
8968
8987
  } else {
8969
8988
  this.#processPushOk(response);
8970
8989
  }
8971
8990
  }
8972
8991
  /**
8992
+ * DEPRECATED: to be removed when we switch to fully driving
8993
+ * mutation resolution via poke.
8994
+ *
8973
8995
  * When we reconnect to zero-cache, we resolve all outstanding mutations
8974
8996
  * whose ID is less than or equal to the lastMutationID.
8975
8997
  *
@@ -8988,47 +9010,14 @@ var MutationTracker = class {
8988
9010
  * to the DB while writing the LMID.
8989
9011
  */
8990
9012
  onConnected(lastMutationID) {
8991
- for (const [id, entry] of this.#outstandingMutations) {
8992
- if (!entry.mutationID) {
8993
- continue;
8994
- }
8995
- if (entry.mutationID <= lastMutationID) {
8996
- this.#settleMutation(id, entry, "resolve", emptyObject);
8997
- } else {
8998
- break;
8999
- }
9000
- }
9001
- for (const [id, entry] of this.#outstandingMutations) {
9002
- if (entry.mutationID && entry.mutationID > lastMutationID) {
9003
- this.#limboMutations.add(id);
9004
- }
9005
- }
9006
9013
  this.lmidAdvanced(lastMutationID);
9007
9014
  }
9008
9015
  /**
9009
9016
  * lmid advance will:
9010
9017
  * 1. notify "allMutationsApplied" listeners if the lastMutationID
9011
9018
  * is greater than or equal to the largest outstanding mutation ID.
9012
- * 2. resolve all limbo mutations whose mutation ID is less than or equal to
9019
+ * 2. resolve all mutations whose mutation ID is less than or equal to
9013
9020
  * the lastMutationID.
9014
- *
9015
- * We only resolve "limbo mutations" since we want to give the mutation
9016
- * responses a chance to be received. `poke` and `pushResponse` are non transactional
9017
- * so they race.
9018
- *
9019
- * E.g., a `push` may call the api server which:
9020
- * writes to PG, replicates to zero-cache, then pokes the lmid down before the
9021
- * push response is sent.
9022
- *
9023
- * The only fix for this would be to have mutation responses be written to the database
9024
- * and sent down through the poke protocol.
9025
- *
9026
- * The artifact the user sees is that promise resolutions for mutations is not transactional
9027
- * with the update to synced data.
9028
- *
9029
- * It was a mistake to not just write the mutation responses to the database
9030
- * in the first place as this route ends up being more complicated
9031
- * and less reliable.
9032
9021
  */
9033
9022
  lmidAdvanced(lastMutationID) {
9034
9023
  assert(
@@ -9040,7 +9029,7 @@ var MutationTracker = class {
9040
9029
  }
9041
9030
  try {
9042
9031
  this.#currentMutationID = lastMutationID;
9043
- this.#resolveLimboMutations(lastMutationID);
9032
+ this.#resolveMutations(lastMutationID);
9044
9033
  } finally {
9045
9034
  if (lastMutationID >= this.#largestOutstandingMutationID) {
9046
9035
  this.#notifyAllMutationsAppliedListeners();
@@ -9050,75 +9039,38 @@ var MutationTracker = class {
9050
9039
  get size() {
9051
9040
  return this.#outstandingMutations.size;
9052
9041
  }
9053
- /**
9054
- * Push errors fall into two categories:
9055
- * - Those where we know the mutations were not applied
9056
- * - Those where we do not know the state of the mutations.
9057
- *
9058
- * The first category includes errors like "unsupportedPushVersion"
9059
- * and "unsupportedSchemaVersion". The mutations were never applied in those cases.
9060
- *
9061
- * The second category includes errors like "http" errors. E.g., a 500 on the user's
9062
- * API server or a network error.
9063
- *
9064
- * The mutations may have been applied by the API server but we never
9065
- * received the response.
9066
- *
9067
- * In this latter case, we must mark the mutations as being in limbo.
9068
- * This allows us to resolve them when we receive the next
9069
- * lmid bump if their lmids are lesser.
9070
- */
9071
- #processPushError(error) {
9072
- if (completeFailureTypes.includes(error.error)) {
9073
- return;
9074
- }
9075
- const mids = error.mutationIDs;
9076
- if (!mids) {
9077
- return;
9078
- }
9079
- for (const mid of mids) {
9080
- const ephemeralID = this.#ephemeralIDsByMutationID.get(mid.id);
9081
- if (ephemeralID) {
9082
- if (mid.id <= this.#currentMutationID) {
9083
- const entry = this.#outstandingMutations.get(ephemeralID);
9084
- if (entry) {
9085
- this.#settleMutation(ephemeralID, entry, "resolve", emptyObject);
9086
- }
9087
- continue;
9088
- }
9089
- this.#limboMutations.add(ephemeralID);
9090
- }
9091
- }
9092
- }
9093
- #resolveLimboMutations(lastMutationID) {
9094
- for (const id of this.#limboMutations) {
9095
- const entry = this.#outstandingMutations.get(id);
9096
- if (!entry || !entry.mutationID) {
9097
- this.#limboMutations.delete(id);
9098
- continue;
9099
- }
9100
- if (entry.mutationID <= lastMutationID) {
9101
- this.#limboMutations.delete(id);
9042
+ #resolveMutations(upTo) {
9043
+ for (const [id, entry] of this.#outstandingMutations) {
9044
+ if (entry.mutationID && entry.mutationID <= upTo) {
9102
9045
  this.#settleMutation(id, entry, "resolve", emptyObject);
9046
+ } else {
9047
+ break;
9103
9048
  }
9104
9049
  }
9105
9050
  }
9106
9051
  #processPushOk(ok) {
9107
9052
  for (const mutation of ok.mutations) {
9108
9053
  if ("error" in mutation.result) {
9109
- this.#processMutationError(mutation.id, mutation.result);
9054
+ this.#processMutationError(
9055
+ mutation.id.clientID,
9056
+ mutation.id.id,
9057
+ mutation.result
9058
+ );
9110
9059
  } else {
9111
- this.#processMutationOk(mutation.id, mutation.result);
9060
+ this.#processMutationOk(
9061
+ mutation.id.clientID,
9062
+ mutation.id.id,
9063
+ mutation.result
9064
+ );
9112
9065
  }
9113
9066
  }
9114
9067
  }
9115
- #processMutationError(mid, error) {
9068
+ #processMutationError(clientID, mid, error) {
9116
9069
  assert(
9117
- mid.clientID === this.#clientID,
9070
+ clientID === this.#clientID,
9118
9071
  "received mutation for the wrong client"
9119
9072
  );
9120
- this.#lc.error?.(`Mutation ${mid.id} returned an error`, error);
9121
- const ephemeralID = this.#ephemeralIDsByMutationID.get(mid.id);
9073
+ const ephemeralID = this.#ephemeralIDsByMutationID.get(mid);
9122
9074
  if (!ephemeralID && error.error === "alreadyProcessed") {
9123
9075
  return;
9124
9076
  }
@@ -9127,21 +9079,21 @@ var MutationTracker = class {
9127
9079
  `ephemeral ID is missing for mutation error: ${error.error}.`
9128
9080
  );
9129
9081
  const entry = this.#outstandingMutations.get(ephemeralID);
9130
- assert(entry && entry.mutationID === mid.id);
9082
+ assert(entry && entry.mutationID === mid);
9131
9083
  this.#settleMutation(ephemeralID, entry, "reject", error);
9132
9084
  }
9133
- #processMutationOk(mid, result) {
9085
+ #processMutationOk(clientID, mid, result) {
9134
9086
  assert(
9135
- mid.clientID === this.#clientID,
9087
+ clientID === this.#clientID,
9136
9088
  "received mutation for the wrong client"
9137
9089
  );
9138
- const ephemeralID = this.#ephemeralIDsByMutationID.get(mid.id);
9090
+ const ephemeralID = this.#ephemeralIDsByMutationID.get(mid);
9139
9091
  assert(
9140
9092
  ephemeralID,
9141
9093
  "ephemeral ID is missing. This can happen if a mutation response is received twice but it should be impossible to receive a success response twice for the same mutation."
9142
9094
  );
9143
9095
  const entry = this.#outstandingMutations.get(ephemeralID);
9144
- assert(entry && entry.mutationID === mid.id);
9096
+ assert(entry && entry.mutationID === mid);
9145
9097
  this.#settleMutation(ephemeralID, entry, "resolve", result);
9146
9098
  }
9147
9099
  #settleMutation(ephemeralID, entry, type, result) {
@@ -9157,7 +9109,6 @@ var MutationTracker = class {
9157
9109
  if (entry.mutationID) {
9158
9110
  this.#ephemeralIDsByMutationID.delete(entry.mutationID);
9159
9111
  }
9160
- this.#limboMutations.delete(ephemeralID);
9161
9112
  }
9162
9113
  /**
9163
9114
  * Be notified when all mutations have been included in the server snapshot.
@@ -9773,9 +9724,6 @@ var PokeHandler = class {
9773
9724
  lc.debug?.("poking replicache");
9774
9725
  await this.#replicachePoke(merged);
9775
9726
  lc.debug?.("poking replicache took", performance.now() - start);
9776
- this.#mutationTracker.processMutationResponses(
9777
- merged.mutationResults ?? []
9778
- );
9779
9727
  if (!("error" in merged.pullResponse)) {
9780
9728
  const lmid = merged.pullResponse.lastMutationIDChanges[this.#clientID];
9781
9729
  if (lmid !== void 0) {
@@ -9858,7 +9806,9 @@ function mergePokes(pokeBuffer, schema, serverToClient2) {
9858
9806
  }
9859
9807
  }
9860
9808
  if (pokePart.mutationsPatch) {
9861
- mutationResults.push(...pokePart.mutationsPatch);
9809
+ for (const op of pokePart.mutationsPatch) {
9810
+ mergedPatch.push(mutationPatchOpToReplicachePatchOp(op));
9811
+ }
9862
9812
  }
9863
9813
  }
9864
9814
  }
@@ -9894,6 +9844,21 @@ function queryPatchOpToReplicachePatchOp(op, toKey) {
9894
9844
  unreachable(op);
9895
9845
  }
9896
9846
  }
9847
+ function mutationPatchOpToReplicachePatchOp(op) {
9848
+ switch (op.op) {
9849
+ case "put":
9850
+ return {
9851
+ op: "put",
9852
+ key: toMutationResponseKey(op.mutation.id),
9853
+ value: op.mutation.result
9854
+ };
9855
+ case "del":
9856
+ return {
9857
+ op: "del",
9858
+ key: toMutationResponseKey(op.id)
9859
+ };
9860
+ }
9861
+ }
9897
9862
  function rowsPatchOpToReplicachePatchOp(op, schema, serverToClient2) {
9898
9863
  if (op.op === "clear") {
9899
9864
  return op;
@@ -10000,6 +9965,38 @@ var ZeroRep = class {
10000
9965
  }
10001
9966
  };
10002
9967
 
9968
+ // ../shared/src/subscribable.ts
9969
+ var Subscribable = class {
9970
+ _listeners = /* @__PURE__ */ new Set();
9971
+ /**
9972
+ * Subscribe to the subscribable.
9973
+ *
9974
+ * @param listener - The listener to subscribe to.
9975
+ * @returns A function to unsubscribe from the subscribable.
9976
+ */
9977
+ subscribe = (listener) => {
9978
+ this._listeners.add(listener);
9979
+ return () => {
9980
+ this._listeners.delete(listener);
9981
+ };
9982
+ };
9983
+ /**
9984
+ * Notify all listeners.
9985
+ *
9986
+ * @param update - The update to notify listeners with.
9987
+ */
9988
+ notify = (update) => {
9989
+ this._listeners.forEach((listener) => listener(update));
9990
+ };
9991
+ hasListeners = () => this._listeners.size > 0;
9992
+ /**
9993
+ * Unsubscribe all listeners.
9994
+ */
9995
+ cleanup = () => {
9996
+ this._listeners.clear();
9997
+ };
9998
+ };
9999
+
10003
10000
  // ../zero-client/src/client/zero.ts
10004
10001
  var onSetConnectionStateSymbol = Symbol();
10005
10002
  var exposedToTestingSymbol = Symbol();
@@ -10079,8 +10076,7 @@ var Zero = class _Zero {
10079
10076
  #deletedClients;
10080
10077
  #lastMutationIDSent = NULL_LAST_MUTATION_ID_SENT;
10081
10078
  #onPong = () => void 0;
10082
- #online = false;
10083
- #onOnlineChange;
10079
+ #onlineManager;
10084
10080
  #onUpdateNeeded;
10085
10081
  #onClientStateNotFound;
10086
10082
  // Last cookie used to initiate a connection
@@ -10180,7 +10176,10 @@ var Zero = class _Zero {
10180
10176
  "ZeroOptions.hiddenTabDisconnectDelay must not be negative."
10181
10177
  );
10182
10178
  }
10183
- this.#onOnlineChange = onOnlineChange;
10179
+ this.#onlineManager = new OnlineManager();
10180
+ if (onOnlineChange) {
10181
+ this.#onlineManager.subscribe(onOnlineChange);
10182
+ }
10184
10183
  this.#options = options;
10185
10184
  this.#logOptions = this.#createLogOptions({
10186
10185
  consoleLogLevel: options.logLevel ?? "warn",
@@ -10310,7 +10309,10 @@ var Zero = class _Zero {
10310
10309
  this.#server = server;
10311
10310
  this.userID = userID;
10312
10311
  this.#lc = lc.withContext("clientID", rep.clientID);
10313
- this.#mutationTracker.clientID = rep.clientID;
10312
+ this.#mutationTracker.setClientIDAndWatch(
10313
+ rep.clientID,
10314
+ rep.experimentalWatch.bind(rep)
10315
+ );
10314
10316
  this.#activeClientsManager = makeActiveClientsManager(
10315
10317
  rep.clientGroupID,
10316
10318
  this.clientID,
@@ -10550,6 +10552,7 @@ var Zero = class _Zero {
10550
10552
  async close() {
10551
10553
  const lc = this.#lc.withContext("close");
10552
10554
  lc.debug?.("Closing Zero instance. Stack:", new Error().stack);
10555
+ this.#onlineManager.cleanup();
10553
10556
  if (this.#connectionState !== Disconnected) {
10554
10557
  this.#disconnect(
10555
10558
  lc,
@@ -11240,19 +11243,24 @@ var Zero = class _Zero {
11240
11243
  }
11241
11244
  }
11242
11245
  #setOnline(online) {
11243
- if (this.#online === online) {
11244
- return;
11245
- }
11246
- this.#online = online;
11247
- this.#onOnlineChange?.(online);
11246
+ this.#onlineManager.setOnline(online);
11248
11247
  }
11249
11248
  /**
11250
11249
  * A rough heuristic for whether the client is currently online and
11251
11250
  * authenticated.
11252
11251
  */
11253
11252
  get online() {
11254
- return this.#online;
11253
+ return this.#onlineManager.online;
11255
11254
  }
11255
+ /**
11256
+ * Subscribe to online status changes.
11257
+ *
11258
+ * This is useful when you want to update state based on the online status.
11259
+ *
11260
+ * @param listener - The listener to subscribe to.
11261
+ * @returns A function to unsubscribe the listener.
11262
+ */
11263
+ onOnline = (listener) => this.#onlineManager.subscribe(listener);
11256
11264
  /**
11257
11265
  * Starts a ping and waits for a pong.
11258
11266
  *
@@ -11307,7 +11315,7 @@ var Zero = class _Zero {
11307
11315
  */
11308
11316
  async inspect() {
11309
11317
  BUNDLE_SIZE: {
11310
- const m = await import("./inspector-TFZBDN6K.js");
11318
+ const m = await import("./inspector-AF3UI76B.js");
11311
11319
  return m.newInspector(this.#rep, this.#schema, async () => {
11312
11320
  await this.#connectResolver.promise;
11313
11321
  return this.#socket;
@@ -11315,6 +11323,19 @@ var Zero = class _Zero {
11315
11323
  }
11316
11324
  }
11317
11325
  };
11326
+ var OnlineManager = class extends Subscribable {
11327
+ #online = false;
11328
+ setOnline(online) {
11329
+ if (this.#online === online) {
11330
+ return;
11331
+ }
11332
+ this.#online = online;
11333
+ this.notify(online);
11334
+ }
11335
+ get online() {
11336
+ return this.#online;
11337
+ }
11338
+ };
11318
11339
  async function createSocket(rep, queryManager, deleteClientsManager, socketOrigin, baseCookie, clientID, clientGroupID, clientSchema, userID, auth, lmid, wsid, debugPerf, lc, userPushParams, userQueryParams, maxHeaderLength = 1024 * 8, additionalConnectParams, activeClientsManager) {
11319
11340
  const url = new URL(
11320
11341
  appendPath(socketOrigin, `/sync/v${PROTOCOL_VERSION}/connect`)
@@ -11447,4 +11468,4 @@ export {
11447
11468
  update_needed_reason_type_enum_exports,
11448
11469
  Zero
11449
11470
  };
11450
- //# sourceMappingURL=chunk-4OOERLIO.js.map
11471
+ //# sourceMappingURL=chunk-CV3OCOGM.js.map