@rocicorp/zero 0.22.2025071100 → 0.22.2025071101
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/out/{chunk-ZVMEFHVU.js → chunk-4FQJO7OM.js} +2 -2
- package/out/{chunk-ZRSXCDPE.js → chunk-5A6QECBY.js} +127 -23
- package/out/{chunk-ZRSXCDPE.js.map → chunk-5A6QECBY.js.map} +2 -2
- package/out/react.js +1 -1
- package/out/solid.js +2 -2
- package/out/zero-cache/src/observability/histograms.d.ts.map +1 -1
- package/out/zero-cache/src/observability/histograms.js +8 -14
- package/out/zero-cache/src/observability/histograms.js.map +1 -1
- package/out/zero-cache/src/server/otel-start.js +1 -1
- package/out/zero-cache/src/server/otel-start.js.map +1 -1
- package/out/zero-client/src/client/mutation-tracker.d.ts +38 -5
- package/out/zero-client/src/client/mutation-tracker.d.ts.map +1 -1
- package/out/zero-client/src/client/zero.d.ts.map +1 -1
- package/out/zero-protocol/src/connect.d.ts.map +1 -1
- package/out/zero-protocol/src/connect.js +9 -3
- package/out/zero-protocol/src/connect.js.map +1 -1
- package/out/zero.js +2 -2
- package/package.json +1 -1
- /package/out/{chunk-ZVMEFHVU.js.map → chunk-4FQJO7OM.js.map} +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
clientToServer
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-5A6QECBY.js";
|
|
4
4
|
import {
|
|
5
5
|
AbstractQuery,
|
|
6
6
|
ExpressionBuilder,
|
|
@@ -337,4 +337,4 @@ export {
|
|
|
337
337
|
querify,
|
|
338
338
|
namedQuery
|
|
339
339
|
};
|
|
340
|
-
//# sourceMappingURL=chunk-
|
|
340
|
+
//# sourceMappingURL=chunk-4FQJO7OM.js.map
|
|
@@ -5916,7 +5916,8 @@ function encodeSecProtocols(initConnectionMessage, authToken) {
|
|
|
5916
5916
|
initConnectionMessage,
|
|
5917
5917
|
authToken
|
|
5918
5918
|
};
|
|
5919
|
-
|
|
5919
|
+
const bytes = new TextEncoder().encode(JSON.stringify(protocols));
|
|
5920
|
+
return encodeURIComponent(btoa(String.fromCharCode(...bytes)));
|
|
5920
5921
|
}
|
|
5921
5922
|
|
|
5922
5923
|
// ../zero-protocol/src/error.ts
|
|
@@ -8537,7 +8538,7 @@ function makeMessage(message, context, logLevel) {
|
|
|
8537
8538
|
}
|
|
8538
8539
|
|
|
8539
8540
|
// ../zero-client/src/client/version.ts
|
|
8540
|
-
var version2 = "0.22.
|
|
8541
|
+
var version2 = "0.22.2025071101";
|
|
8541
8542
|
|
|
8542
8543
|
// ../zero-client/src/client/log-options.ts
|
|
8543
8544
|
var LevelFilterLogSink = class {
|
|
@@ -8833,9 +8834,7 @@ var State = class {
|
|
|
8833
8834
|
|
|
8834
8835
|
// ../zero-client/src/client/mutation-tracker.ts
|
|
8835
8836
|
import { resolver as resolver8 } from "@rocicorp/resolver";
|
|
8836
|
-
var
|
|
8837
|
-
"zeroPusher",
|
|
8838
|
-
"http",
|
|
8837
|
+
var completeFailureTypes = [
|
|
8839
8838
|
// These should never actually be received as they cause the websocket
|
|
8840
8839
|
// connection to be closed.
|
|
8841
8840
|
"unsupportedPushVersion",
|
|
@@ -8848,14 +8847,20 @@ function nextEphemeralID() {
|
|
|
8848
8847
|
var MutationTracker = class {
|
|
8849
8848
|
#outstandingMutations;
|
|
8850
8849
|
#ephemeralIDsByMutationID;
|
|
8851
|
-
#
|
|
8850
|
+
#allMutationsAppliedListeners;
|
|
8852
8851
|
#lc;
|
|
8852
|
+
#limboMutations;
|
|
8853
8853
|
#clientID;
|
|
8854
|
+
#largestOutstandingMutationID;
|
|
8855
|
+
#currentMutationID;
|
|
8854
8856
|
constructor(lc) {
|
|
8855
8857
|
this.#lc = lc.withContext("MutationTracker");
|
|
8856
8858
|
this.#outstandingMutations = /* @__PURE__ */ new Map();
|
|
8857
8859
|
this.#ephemeralIDsByMutationID = /* @__PURE__ */ new Map();
|
|
8858
|
-
this.#
|
|
8860
|
+
this.#allMutationsAppliedListeners = /* @__PURE__ */ new Set();
|
|
8861
|
+
this.#limboMutations = /* @__PURE__ */ new Set();
|
|
8862
|
+
this.#largestOutstandingMutationID = 0;
|
|
8863
|
+
this.#currentMutationID = 0;
|
|
8859
8864
|
}
|
|
8860
8865
|
set clientID(clientID) {
|
|
8861
8866
|
this.#clientID = clientID;
|
|
@@ -8873,6 +8878,10 @@ var MutationTracker = class {
|
|
|
8873
8878
|
if (entry) {
|
|
8874
8879
|
entry.mutationID = mutationID;
|
|
8875
8880
|
this.#ephemeralIDsByMutationID.set(mutationID, id);
|
|
8881
|
+
this.#largestOutstandingMutationID = Math.max(
|
|
8882
|
+
this.#largestOutstandingMutationID,
|
|
8883
|
+
mutationID
|
|
8884
|
+
);
|
|
8876
8885
|
}
|
|
8877
8886
|
}
|
|
8878
8887
|
/**
|
|
@@ -8904,7 +8913,7 @@ var MutationTracker = class {
|
|
|
8904
8913
|
* to those mutations have been lost.
|
|
8905
8914
|
*
|
|
8906
8915
|
* An example case: the API server responds while the connection
|
|
8907
|
-
* is down. Those responses are
|
|
8916
|
+
* is down. Those responses are lost.
|
|
8908
8917
|
*
|
|
8909
8918
|
* Mutations whose LMID is > the lastMutationID are not resolved
|
|
8910
8919
|
* since they will be retried by the client, giving us another chance
|
|
@@ -8913,9 +8922,6 @@ var MutationTracker = class {
|
|
|
8913
8922
|
* The only way to ensure that all API server responses are
|
|
8914
8923
|
* received would be to have the API server write them
|
|
8915
8924
|
* to the DB while writing the LMID.
|
|
8916
|
-
*
|
|
8917
|
-
* This would have the downside of not being able to provide responses to a
|
|
8918
|
-
* mutation with data gathered after the transaction.
|
|
8919
8925
|
*/
|
|
8920
8926
|
onConnected(lastMutationID) {
|
|
8921
8927
|
for (const [id, entry] of this.#outstandingMutations) {
|
|
@@ -8928,12 +8934,78 @@ var MutationTracker = class {
|
|
|
8928
8934
|
break;
|
|
8929
8935
|
}
|
|
8930
8936
|
}
|
|
8937
|
+
for (const [id, entry] of this.#outstandingMutations) {
|
|
8938
|
+
if (entry.mutationID && entry.mutationID > lastMutationID) {
|
|
8939
|
+
this.#limboMutations.add(id);
|
|
8940
|
+
}
|
|
8941
|
+
}
|
|
8942
|
+
this.lmidAdvanced(lastMutationID);
|
|
8943
|
+
}
|
|
8944
|
+
/**
|
|
8945
|
+
* lmid advance will:
|
|
8946
|
+
* 1. notify "allMutationsApplied" listeners if the lastMutationID
|
|
8947
|
+
* is greater than or equal to the largest outstanding mutation ID.
|
|
8948
|
+
* 2. resolve all limbo mutations whose mutation ID is less than or equal to
|
|
8949
|
+
* the lastMutationID.
|
|
8950
|
+
*
|
|
8951
|
+
* We only resolve "limbo mutations" since we want to give the mutation
|
|
8952
|
+
* responses a chance to be received. `poke` and `pushResponse` are non transactional
|
|
8953
|
+
* so they race.
|
|
8954
|
+
*
|
|
8955
|
+
* E.g., a `push` may call the api server which:
|
|
8956
|
+
* writes to PG, replicates to zero-cache, then pokes the lmid down before the
|
|
8957
|
+
* push response is sent.
|
|
8958
|
+
*
|
|
8959
|
+
* The only fix for this would be to have mutation responses be written to the database
|
|
8960
|
+
* and sent down through the poke protocol.
|
|
8961
|
+
*
|
|
8962
|
+
* The artifact the user sees is that promise resolutions for mutations is not transactional
|
|
8963
|
+
* with the update to synced data.
|
|
8964
|
+
*
|
|
8965
|
+
* It was a mistake to not just write the mutation responses to the database
|
|
8966
|
+
* in the first place as this route ends up being more complicated
|
|
8967
|
+
* and less reliable.
|
|
8968
|
+
*/
|
|
8969
|
+
lmidAdvanced(lastMutationID) {
|
|
8970
|
+
assert(
|
|
8971
|
+
lastMutationID >= this.#currentMutationID,
|
|
8972
|
+
"lmid must be greater than or equal to current lmid"
|
|
8973
|
+
);
|
|
8974
|
+
if (lastMutationID === this.#currentMutationID) {
|
|
8975
|
+
return;
|
|
8976
|
+
}
|
|
8977
|
+
try {
|
|
8978
|
+
this.#currentMutationID = lastMutationID;
|
|
8979
|
+
this.#resolveLimboMutations(lastMutationID);
|
|
8980
|
+
} finally {
|
|
8981
|
+
if (lastMutationID >= this.#largestOutstandingMutationID) {
|
|
8982
|
+
this.#notifyAllMutationsAppliedListeners();
|
|
8983
|
+
}
|
|
8984
|
+
}
|
|
8931
8985
|
}
|
|
8932
8986
|
get size() {
|
|
8933
8987
|
return this.#outstandingMutations.size;
|
|
8934
8988
|
}
|
|
8989
|
+
/**
|
|
8990
|
+
* Push errors fall into two categories:
|
|
8991
|
+
* - Those where we know the mutations were not applied
|
|
8992
|
+
* - Those where we do not know the state of the mutations.
|
|
8993
|
+
*
|
|
8994
|
+
* The first category includes errors like "unsupportedPushVersion"
|
|
8995
|
+
* and "unsupportedSchemaVersion". The mutations were never applied in those cases.
|
|
8996
|
+
*
|
|
8997
|
+
* The second category includes errors like "http" errors. E.g., a 500 on the user's
|
|
8998
|
+
* API server or a network error.
|
|
8999
|
+
*
|
|
9000
|
+
* The mutations may have been applied by the API server but we never
|
|
9001
|
+
* received the response.
|
|
9002
|
+
*
|
|
9003
|
+
* In this latter case, we must mark the mutations as being in limbo.
|
|
9004
|
+
* This allows us to resolve them when we receive the next
|
|
9005
|
+
* lmid bump if their lmids are lesser.
|
|
9006
|
+
*/
|
|
8935
9007
|
#processPushError(error) {
|
|
8936
|
-
if (
|
|
9008
|
+
if (completeFailureTypes.includes(error.error)) {
|
|
8937
9009
|
return;
|
|
8938
9010
|
}
|
|
8939
9011
|
const mids = error.mutationIDs;
|
|
@@ -8941,7 +9013,30 @@ var MutationTracker = class {
|
|
|
8941
9013
|
return;
|
|
8942
9014
|
}
|
|
8943
9015
|
for (const mid of mids) {
|
|
8944
|
-
this.#
|
|
9016
|
+
const ephemeralID = this.#ephemeralIDsByMutationID.get(mid.id);
|
|
9017
|
+
if (ephemeralID) {
|
|
9018
|
+
if (mid.id <= this.#currentMutationID) {
|
|
9019
|
+
const entry = this.#outstandingMutations.get(ephemeralID);
|
|
9020
|
+
if (entry) {
|
|
9021
|
+
this.#settleMutation(ephemeralID, entry, "resolve", emptyObject);
|
|
9022
|
+
}
|
|
9023
|
+
continue;
|
|
9024
|
+
}
|
|
9025
|
+
this.#limboMutations.add(ephemeralID);
|
|
9026
|
+
}
|
|
9027
|
+
}
|
|
9028
|
+
}
|
|
9029
|
+
#resolveLimboMutations(lastMutationID) {
|
|
9030
|
+
for (const id of this.#limboMutations) {
|
|
9031
|
+
const entry = this.#outstandingMutations.get(id);
|
|
9032
|
+
if (!entry || !entry.mutationID) {
|
|
9033
|
+
this.#limboMutations.delete(id);
|
|
9034
|
+
continue;
|
|
9035
|
+
}
|
|
9036
|
+
if (entry.mutationID <= lastMutationID) {
|
|
9037
|
+
this.#limboMutations.delete(id);
|
|
9038
|
+
this.#settleMutation(id, entry, "resolve", emptyObject);
|
|
9039
|
+
}
|
|
8945
9040
|
}
|
|
8946
9041
|
}
|
|
8947
9042
|
#processPushOk(ok) {
|
|
@@ -8994,19 +9089,27 @@ var MutationTracker = class {
|
|
|
8994
9089
|
entry.resolver.reject(result);
|
|
8995
9090
|
break;
|
|
8996
9091
|
}
|
|
8997
|
-
|
|
9092
|
+
this.#outstandingMutations.delete(ephemeralID);
|
|
8998
9093
|
if (entry.mutationID) {
|
|
8999
9094
|
this.#ephemeralIDsByMutationID.delete(entry.mutationID);
|
|
9000
9095
|
}
|
|
9001
|
-
|
|
9002
|
-
this.#notifyAllMutationsConfirmedListeners();
|
|
9003
|
-
}
|
|
9096
|
+
this.#limboMutations.delete(ephemeralID);
|
|
9004
9097
|
}
|
|
9005
|
-
|
|
9006
|
-
|
|
9098
|
+
/**
|
|
9099
|
+
* Be notified when all mutations have been included in the server snapshot.
|
|
9100
|
+
*
|
|
9101
|
+
* The query manager will not de-register queries from the server until there
|
|
9102
|
+
* are no pending mutations.
|
|
9103
|
+
*
|
|
9104
|
+
* The reason is that a mutation may need to be rebased. We do not want
|
|
9105
|
+
* data that was available the first time it was run to not be available
|
|
9106
|
+
* on a rebase.
|
|
9107
|
+
*/
|
|
9108
|
+
onAllMutationsApplied(listener) {
|
|
9109
|
+
this.#allMutationsAppliedListeners.add(listener);
|
|
9007
9110
|
}
|
|
9008
|
-
#
|
|
9009
|
-
for (const listener of this.#
|
|
9111
|
+
#notifyAllMutationsAppliedListeners() {
|
|
9112
|
+
for (const listener of this.#allMutationsAppliedListeners) {
|
|
9010
9113
|
listener();
|
|
9011
9114
|
}
|
|
9012
9115
|
}
|
|
@@ -9039,7 +9142,7 @@ var QueryManager = class {
|
|
|
9039
9142
|
this.#send = send2;
|
|
9040
9143
|
this.#mutationTracker = mutationTracker;
|
|
9041
9144
|
this.#queryChangeThrottleMs = queryChangeThrottleMs;
|
|
9042
|
-
this.#mutationTracker.
|
|
9145
|
+
this.#mutationTracker.onAllMutationsApplied(() => {
|
|
9043
9146
|
if (this.#pendingRemovals.length === 0) {
|
|
9044
9147
|
return;
|
|
9045
9148
|
}
|
|
@@ -10735,6 +10838,7 @@ var Zero = class _Zero {
|
|
|
10735
10838
|
#handlePokeEnd(_lc, pokeMessage) {
|
|
10736
10839
|
this.#abortPingTimeout();
|
|
10737
10840
|
this.#pokeHandler.handlePokeEnd(pokeMessage[1]);
|
|
10841
|
+
this.#mutationTracker.lmidAdvanced(this.#lastMutationIDReceived);
|
|
10738
10842
|
}
|
|
10739
10843
|
#onPokeError() {
|
|
10740
10844
|
const lc = this.#lc;
|
|
@@ -11241,4 +11345,4 @@ export {
|
|
|
11241
11345
|
update_needed_reason_type_enum_exports,
|
|
11242
11346
|
Zero
|
|
11243
11347
|
};
|
|
11244
|
-
//# sourceMappingURL=chunk-
|
|
11348
|
+
//# sourceMappingURL=chunk-5A6QECBY.js.map
|