@rocicorp/zero 0.12.2025013100 → 0.13.2025020200

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 (59) hide show
  1. package/out/chunk-5JO5DB4D.js +50 -0
  2. package/out/chunk-5JO5DB4D.js.map +7 -0
  3. package/out/{chunk-XBQPXRPX.js → chunk-5S3K5CU2.js} +141 -60
  4. package/out/chunk-5S3K5CU2.js.map +7 -0
  5. package/out/react.js +3 -44
  6. package/out/react.js.map +3 -3
  7. package/out/replicache/src/persist/client-gc.d.ts +2 -1
  8. package/out/replicache/src/persist/client-gc.d.ts.map +1 -1
  9. package/out/replicache/src/persist/clients.d.ts +4 -0
  10. package/out/replicache/src/persist/clients.d.ts.map +1 -1
  11. package/out/replicache/src/persist/collect-idb-databases.d.ts +3 -11
  12. package/out/replicache/src/persist/collect-idb-databases.d.ts.map +1 -1
  13. package/out/replicache/src/replicache-impl.d.ts +5 -0
  14. package/out/replicache/src/replicache-impl.d.ts.map +1 -1
  15. package/out/shared/src/btree-set.d.ts +1 -0
  16. package/out/shared/src/btree-set.d.ts.map +1 -1
  17. package/out/shared/src/btree-set.js +7 -0
  18. package/out/shared/src/btree-set.js.map +1 -1
  19. package/out/shared/src/resolved-promises.d.ts +2 -2
  20. package/out/shared/src/resolved-promises.d.ts.map +1 -1
  21. package/out/shared/src/resolved-promises.js.map +1 -1
  22. package/out/solid.js +37 -34
  23. package/out/solid.js.map +2 -2
  24. package/out/zero-cache/src/server/change-streamer.d.ts.map +1 -1
  25. package/out/zero-cache/src/server/change-streamer.js +11 -11
  26. package/out/zero-cache/src/server/change-streamer.js.map +1 -1
  27. package/out/zero-cache/src/services/change-streamer/change-streamer-service.d.ts +1 -1
  28. package/out/zero-cache/src/services/change-streamer/change-streamer-service.d.ts.map +1 -1
  29. package/out/zero-cache/src/services/change-streamer/change-streamer-service.js +12 -14
  30. package/out/zero-cache/src/services/change-streamer/change-streamer-service.js.map +1 -1
  31. package/out/zero-cache/src/services/change-streamer/schema/init.d.ts +1 -0
  32. package/out/zero-cache/src/services/change-streamer/schema/init.d.ts.map +1 -1
  33. package/out/zero-cache/src/services/change-streamer/schema/init.js +28 -3
  34. package/out/zero-cache/src/services/change-streamer/schema/init.js.map +1 -1
  35. package/out/zero-cache/src/services/change-streamer/schema/tables.d.ts +9 -0
  36. package/out/zero-cache/src/services/change-streamer/schema/tables.d.ts.map +1 -1
  37. package/out/zero-cache/src/services/change-streamer/schema/tables.js +29 -14
  38. package/out/zero-cache/src/services/change-streamer/schema/tables.js.map +1 -1
  39. package/out/zero-cache/src/services/change-streamer/storer.d.ts +3 -2
  40. package/out/zero-cache/src/services/change-streamer/storer.d.ts.map +1 -1
  41. package/out/zero-cache/src/services/change-streamer/storer.js +50 -8
  42. package/out/zero-cache/src/services/change-streamer/storer.js.map +1 -1
  43. package/out/zero-client/src/client/crud.d.ts +5 -1
  44. package/out/zero-client/src/client/crud.d.ts.map +1 -1
  45. package/out/zero-client/src/client/custom.d.ts +19 -9
  46. package/out/zero-client/src/client/custom.d.ts.map +1 -1
  47. package/out/zero-client/src/client/options.d.ts +3 -3
  48. package/out/zero-client/src/client/options.d.ts.map +1 -1
  49. package/out/zero-client/src/client/zero.d.ts +4 -3
  50. package/out/zero-client/src/client/zero.d.ts.map +1 -1
  51. package/out/zero-protocol/src/ast.d.ts +5 -4
  52. package/out/zero-protocol/src/ast.d.ts.map +1 -1
  53. package/out/zero-protocol/src/ast.js.map +1 -1
  54. package/out/zero-react/src/use-zero.d.ts +1 -1
  55. package/out/zero-react/src/use-zero.d.ts.map +1 -1
  56. package/out/zero-solid/src/solid-view.d.ts.map +1 -1
  57. package/out/zero.js +1 -1
  58. package/package.json +1 -1
  59. package/out/chunk-XBQPXRPX.js.map +0 -7
@@ -0,0 +1,50 @@
1
+ import {
2
+ hasOwn
3
+ } from "./chunk-HARIWJ2J.js";
4
+
5
+ // ../shared/src/deep-clone.ts
6
+ function deepClone(value) {
7
+ const seen = [];
8
+ return internalDeepClone(value, seen);
9
+ }
10
+ function internalDeepClone(value, seen) {
11
+ switch (typeof value) {
12
+ case "boolean":
13
+ case "number":
14
+ case "string":
15
+ case "undefined":
16
+ return value;
17
+ case "object": {
18
+ if (value === null) {
19
+ return null;
20
+ }
21
+ if (seen.includes(value)) {
22
+ throw new Error("Cyclic object");
23
+ }
24
+ seen.push(value);
25
+ if (Array.isArray(value)) {
26
+ const rv = value.map((v) => internalDeepClone(v, seen));
27
+ seen.pop();
28
+ return rv;
29
+ }
30
+ const obj = {};
31
+ for (const k in value) {
32
+ if (hasOwn(value, k)) {
33
+ const v = value[k];
34
+ if (v !== void 0) {
35
+ obj[k] = internalDeepClone(v, seen);
36
+ }
37
+ }
38
+ }
39
+ seen.pop();
40
+ return obj;
41
+ }
42
+ default:
43
+ throw new Error(`Invalid type: ${typeof value}`);
44
+ }
45
+ }
46
+
47
+ export {
48
+ deepClone
49
+ };
50
+ //# sourceMappingURL=chunk-5JO5DB4D.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../shared/src/deep-clone.ts"],
4
+ "sourcesContent": ["import {hasOwn} from './has-own.ts';\nimport type {JSONValue, ReadonlyJSONValue} from './json.ts';\n\nexport function deepClone(value: ReadonlyJSONValue): JSONValue {\n const seen: Array<ReadonlyJSONValue> = [];\n return internalDeepClone(value, seen);\n}\n\nexport function internalDeepClone(\n value: ReadonlyJSONValue,\n seen: Array<ReadonlyJSONValue>,\n): JSONValue {\n switch (typeof value) {\n case 'boolean':\n case 'number':\n case 'string':\n case 'undefined':\n return value;\n case 'object': {\n if (value === null) {\n return null;\n }\n if (seen.includes(value)) {\n throw new Error('Cyclic object');\n }\n seen.push(value);\n if (Array.isArray(value)) {\n const rv = value.map(v => internalDeepClone(v, seen));\n seen.pop();\n return rv;\n }\n\n const obj: JSONValue = {};\n\n for (const k in value) {\n if (hasOwn(value, k)) {\n const v = (value as Record<string, ReadonlyJSONValue>)[k];\n if (v !== undefined) {\n obj[k] = internalDeepClone(v, seen);\n }\n }\n }\n seen.pop();\n return obj;\n }\n\n default:\n throw new Error(`Invalid type: ${typeof value}`);\n }\n}\n"],
5
+ "mappings": ";;;;;AAGO,SAAS,UAAU,OAAqC;AAC7D,QAAM,OAAiC,CAAC;AACxC,SAAO,kBAAkB,OAAO,IAAI;AACtC;AAEO,SAAS,kBACd,OACA,MACW;AACX,UAAQ,OAAO,OAAO;AAAA,IACpB,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK,UAAU;AACb,UAAI,UAAU,MAAM;AAClB,eAAO;AAAA,MACT;AACA,UAAI,KAAK,SAAS,KAAK,GAAG;AACxB,cAAM,IAAI,MAAM,eAAe;AAAA,MACjC;AACA,WAAK,KAAK,KAAK;AACf,UAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,cAAM,KAAK,MAAM,IAAI,OAAK,kBAAkB,GAAG,IAAI,CAAC;AACpD,aAAK,IAAI;AACT,eAAO;AAAA,MACT;AAEA,YAAM,MAAiB,CAAC;AAExB,iBAAW,KAAK,OAAO;AACrB,YAAI,OAAO,OAAO,CAAC,GAAG;AACpB,gBAAM,IAAK,MAA4C,CAAC;AACxD,cAAI,MAAM,QAAW;AACnB,gBAAI,CAAC,IAAI,kBAAkB,GAAG,IAAI;AAAA,UACpC;AAAA,QACF;AAAA,MACF;AACA,WAAK,IAAI;AACT,aAAO;AAAA,IACT;AAAA,IAEA;AACE,YAAM,IAAI,MAAM,iBAAiB,OAAO,KAAK,EAAE;AAAA,EACnD;AACF;",
6
+ "names": []
7
+ }
@@ -5920,11 +5920,16 @@ async function setClients(clients, dagWrite) {
5920
5920
  var CLIENT_MAX_INACTIVE_TIME = 24 * 60 * 60 * 1e3;
5921
5921
  var GC_INTERVAL = 5 * 60 * 1e3;
5922
5922
  var latestGCUpdate;
5923
- function initClientGC(clientID, dagStore, clientMaxInactiveTime, gcInterval, lc, signal) {
5923
+ function initClientGC(clientID, dagStore, clientMaxInactiveTime, gcInterval, onClientsDeleted, lc, signal) {
5924
5924
  initBgIntervalProcess(
5925
5925
  "ClientGC",
5926
5926
  () => {
5927
- latestGCUpdate = gcClients(clientID, dagStore, clientMaxInactiveTime);
5927
+ latestGCUpdate = gcClients(
5928
+ clientID,
5929
+ dagStore,
5930
+ clientMaxInactiveTime,
5931
+ onClientsDeleted
5932
+ );
5928
5933
  return latestGCUpdate;
5929
5934
  },
5930
5935
  () => gcInterval,
@@ -5932,18 +5937,24 @@ function initClientGC(clientID, dagStore, clientMaxInactiveTime, gcInterval, lc,
5932
5937
  signal
5933
5938
  );
5934
5939
  }
5935
- function gcClients(clientID, dagStore, clientMaxInactiveTime) {
5940
+ function gcClients(clientID, dagStore, clientMaxInactiveTime, onClientsDeleted) {
5936
5941
  return withWrite(dagStore, async (dagWrite) => {
5937
5942
  const now = Date.now();
5938
5943
  const clients = await getClients(dagWrite);
5939
- const clientsAfterGC = Array.from(clients).filter(
5940
- ([id, client]) => id === clientID || now - client.heartbeatTimestampMs <= clientMaxInactiveTime
5941
- );
5942
- if (clientsAfterGC.length === clients.size) {
5944
+ const deletedClients = [];
5945
+ const newClients = /* @__PURE__ */ new Map();
5946
+ for (const [id, client] of clients) {
5947
+ if (id === clientID || now - client.heartbeatTimestampMs <= clientMaxInactiveTime) {
5948
+ newClients.set(id, client);
5949
+ } else {
5950
+ deletedClients.push(id);
5951
+ }
5952
+ }
5953
+ if (newClients.size === clients.size) {
5943
5954
  return clients;
5944
5955
  }
5945
- const newClients = new Map(clientsAfterGC);
5946
5956
  await setClients(newClients, dagWrite);
5957
+ onClientsDeleted(deletedClients);
5947
5958
  return newClients;
5948
5959
  });
5949
5960
  }
@@ -7213,7 +7224,10 @@ var ReplicacheImpl = class {
7213
7224
  enableScheduledPersist = true,
7214
7225
  enableScheduledRefresh = true,
7215
7226
  enablePullAndPushInOpen = true,
7216
- enableClientGroupForking = true
7227
+ enableClientGroupForking = true,
7228
+ onClientsDeleted = (clientIDs) => {
7229
+ this.#lc.info?.("ClientIDs deleted", clientIDs);
7230
+ }
7217
7231
  } = implOptions;
7218
7232
  this.auth = auth ?? "";
7219
7233
  this.pullURL = pullURL;
@@ -7296,10 +7310,11 @@ var ReplicacheImpl = class {
7296
7310
  clientMaxAgeMs,
7297
7311
  profileIDResolver.resolve,
7298
7312
  clientGroupIDResolver.resolve,
7299
- readyResolver.resolve
7313
+ readyResolver.resolve,
7314
+ onClientsDeleted
7300
7315
  );
7301
7316
  }
7302
- async #open(indexes, enableClientGroupForking, clientMaxAgeMs, profileIDResolver, resolveClientGroupID, resolveReady) {
7317
+ async #open(indexes, enableClientGroupForking, clientMaxAgeMs, profileIDResolver, resolveClientGroupID, resolveReady, onClientsDeleted) {
7303
7318
  const { clientID } = this;
7304
7319
  await closingInstances.get(this.name);
7305
7320
  await this.#idbDatabases.getProfileID().then(profileIDResolver);
@@ -7339,6 +7354,7 @@ var ReplicacheImpl = class {
7339
7354
  this.perdag,
7340
7355
  clientMaxAgeMs,
7341
7356
  GC_INTERVAL,
7357
+ onClientsDeleted,
7342
7358
  this.#lc,
7343
7359
  signal
7344
7360
  );
@@ -7347,8 +7363,8 @@ var ReplicacheImpl = class {
7347
7363
  this.#kvStoreProvider.drop,
7348
7364
  COLLECT_IDB_INTERVAL,
7349
7365
  INITIAL_COLLECT_IDB_DELAY,
7350
- SDD_IDB_MAX_AGE,
7351
7366
  2 * clientMaxAgeMs,
7367
+ onClientsDeleted,
7352
7368
  this.#lc,
7353
7369
  signal
7354
7370
  );
@@ -8169,10 +8185,8 @@ function getKVStoreProvider(lc, kvStore) {
8169
8185
 
8170
8186
  // ../replicache/src/persist/collect-idb-databases.ts
8171
8187
  var COLLECT_IDB_INTERVAL = 12 * 60 * 60 * 1e3;
8172
- var SDD_IDB_MAX_AGE = 30 * 24 * 60 * 60 * 1e3;
8173
- var DD31_IDB_MAX_AGE = 14 * 24 * 60 * 60 * 1e3;
8174
8188
  var INITIAL_COLLECT_IDB_DELAY = 5 * 60 * 1e3;
8175
- function initCollectIDBDatabases(idbDatabasesStore, kvDropStore, collectInterval, initialCollectDelay, sddMaxAge, dd31MaxAge, lc, signal) {
8189
+ function initCollectIDBDatabases(idbDatabasesStore, kvDropStore, collectInterval, initialCollectDelay, maxAge, onClientsDeleted, lc, signal) {
8176
8190
  let initial = true;
8177
8191
  initBgIntervalProcess(
8178
8192
  "CollectIDBDatabases",
@@ -8180,9 +8194,9 @@ function initCollectIDBDatabases(idbDatabasesStore, kvDropStore, collectInterval
8180
8194
  await collectIDBDatabases(
8181
8195
  idbDatabasesStore,
8182
8196
  Date.now(),
8183
- sddMaxAge,
8184
- dd31MaxAge,
8185
- kvDropStore
8197
+ maxAge,
8198
+ kvDropStore,
8199
+ onClientsDeleted
8186
8200
  );
8187
8201
  },
8188
8202
  () => {
@@ -8196,26 +8210,36 @@ function initCollectIDBDatabases(idbDatabasesStore, kvDropStore, collectInterval
8196
8210
  signal
8197
8211
  );
8198
8212
  }
8199
- async function collectIDBDatabases(idbDatabasesStore, now, sddMaxAge, dd31MaxAge, kvDropStore, newDagStore = defaultNewDagStore) {
8213
+ async function collectIDBDatabases(idbDatabasesStore, now, maxAge, kvDropStore, onClientsDeleted, newDagStore = defaultNewDagStore) {
8200
8214
  const databases = await idbDatabasesStore.getDatabases();
8201
8215
  const dbs = Object.values(databases);
8202
- const canCollectResults = await Promise.all(
8216
+ const collectResults = await Promise.all(
8203
8217
  dbs.map(
8204
8218
  async (db) => [
8205
8219
  db.name,
8206
- await canCollectDatabase(db, now, sddMaxAge, dd31MaxAge, newDagStore)
8220
+ await gatherDatabaseInfoForCollect(db, now, maxAge, newDagStore)
8207
8221
  ]
8208
8222
  )
8209
8223
  );
8210
- const namesToRemove = canCollectResults.filter((result) => result[1]).map((result) => result[0]);
8224
+ const dbNamesToRemove = [];
8225
+ const clientIDsToRemove = [];
8226
+ for (const [dbName, [canCollect, clientIDs]] of collectResults) {
8227
+ if (canCollect) {
8228
+ dbNamesToRemove.push(dbName);
8229
+ clientIDsToRemove.push(...clientIDs);
8230
+ }
8231
+ }
8211
8232
  const { errors } = await dropDatabases(
8212
8233
  idbDatabasesStore,
8213
- namesToRemove,
8234
+ dbNamesToRemove,
8214
8235
  kvDropStore
8215
8236
  );
8216
8237
  if (errors.length) {
8217
8238
  throw errors[0];
8218
8239
  }
8240
+ if (clientIDsToRemove.length) {
8241
+ onClientsDeleted(clientIDsToRemove);
8242
+ }
8219
8243
  }
8220
8244
  async function dropDatabaseInternal(name, idbDatabasesStore, kvDropStore) {
8221
8245
  await kvDropStore(name);
@@ -8243,35 +8267,18 @@ function defaultNewDagStore(name) {
8243
8267
  const perKvStore = new IDBStore(name);
8244
8268
  return new StoreImpl(perKvStore, newRandomHash, assertHash);
8245
8269
  }
8246
- async function canCollectDatabase(db, now, sddMaxAge, dd31MaxAge, newDagStore) {
8270
+ function gatherDatabaseInfoForCollect(db, now, maxAge, newDagStore) {
8247
8271
  if (db.replicacheFormatVersion > Latest) {
8248
- return false;
8249
- }
8250
- if (db.lastOpenedTimestampMS !== void 0) {
8251
- const isDD31 = db.replicacheFormatVersion >= DD31;
8252
- if (now - db.lastOpenedTimestampMS < (isDD31 ? dd31MaxAge : sddMaxAge)) {
8253
- return false;
8254
- }
8255
- if (!isDD31) {
8256
- return true;
8257
- }
8258
- assert(
8259
- db.replicacheFormatVersion === DD31 || db.replicacheFormatVersion === V6 || db.replicacheFormatVersion === V7
8260
- );
8261
- return !await anyPendingMutationsInClientGroups(newDagStore(db.name));
8272
+ return [false];
8262
8273
  }
8263
- const perdag = newDagStore(db.name);
8264
- const clientMap = await withRead(perdag, getClients);
8265
- await perdag.close();
8266
- return allClientsOlderThan(clientMap, now, sddMaxAge);
8267
- }
8268
- function allClientsOlderThan(clients, now, maxAge) {
8269
- for (const client of clients.values()) {
8270
- if (now - client.heartbeatTimestampMs < maxAge) {
8271
- return false;
8272
- }
8274
+ assert(db.lastOpenedTimestampMS !== void 0);
8275
+ if (now - db.lastOpenedTimestampMS < maxAge) {
8276
+ return [false];
8273
8277
  }
8274
- return true;
8278
+ assert(
8279
+ db.replicacheFormatVersion === DD31 || db.replicacheFormatVersion === V6 || db.replicacheFormatVersion === V7
8280
+ );
8281
+ return gatherPendingMutationsInClientGroups(newDagStore(db.name));
8275
8282
  }
8276
8283
  async function dropDatabase(dbName, opts) {
8277
8284
  const logContext = createLogContext(opts?.logLevel, opts?.logSinks, {
@@ -8295,14 +8302,17 @@ async function dropAllDatabases(opts) {
8295
8302
  const result = await dropDatabases(store, dbNames, kvStoreProvider.drop);
8296
8303
  return result;
8297
8304
  }
8298
- async function anyPendingMutationsInClientGroups(perdag) {
8299
- const clientGroups = await withRead(perdag, getClientGroups);
8300
- for (const clientGroup of clientGroups.values()) {
8301
- if (clientGroupHasPendingMutations(clientGroup)) {
8302
- return true;
8305
+ function gatherPendingMutationsInClientGroups(perdag) {
8306
+ return withRead(perdag, async (read) => {
8307
+ const clientGroups = await getClientGroups(read);
8308
+ for (const clientGroup of clientGroups.values()) {
8309
+ if (clientGroupHasPendingMutations(clientGroup)) {
8310
+ return [false];
8311
+ }
8303
8312
  }
8304
- }
8305
- return false;
8313
+ const clients = await getClients(read);
8314
+ return [true, [...clients.keys()]];
8315
+ });
8306
8316
  }
8307
8317
 
8308
8318
  // ../zero-schema/src/builder/relationship-builder.ts
@@ -11790,7 +11800,7 @@ var Connected = 2;
11790
11800
 
11791
11801
  // ../shared/src/btree-set.ts
11792
11802
  var MAX_NODE_SIZE = 32;
11793
- var BTreeSet = class {
11803
+ var BTreeSet = class _BTreeSet {
11794
11804
  #root = emptyLeaf;
11795
11805
  size = 0;
11796
11806
  comparator;
@@ -11807,6 +11817,13 @@ var BTreeSet = class {
11807
11817
  this.#root = emptyLeaf;
11808
11818
  this.size = 0;
11809
11819
  }
11820
+ clone() {
11821
+ this.#root.isShared = true;
11822
+ const ret = new _BTreeSet(this.comparator);
11823
+ ret.#root = this.#root;
11824
+ ret.size = this.size;
11825
+ return ret;
11826
+ }
11810
11827
  get(key) {
11811
11828
  return this.#root.get(key, this);
11812
11829
  }
@@ -13335,7 +13352,7 @@ function makeMessage(message, context, logLevel) {
13335
13352
  }
13336
13353
 
13337
13354
  // ../zero-client/src/client/version.ts
13338
- var version2 = "0.12.2025013100";
13355
+ var version2 = "0.13.2025020200";
13339
13356
 
13340
13357
  // ../zero-client/src/client/log-options.ts
13341
13358
  var LevelFilterLogSink = class {
@@ -14237,6 +14254,44 @@ function rafFallback(callback) {
14237
14254
  setTimeout(callback, 0);
14238
14255
  }
14239
14256
 
14257
+ // ../zero-client/src/client/custom.ts
14258
+ var TransactionImpl = class {
14259
+ constructor(repTx, schema) {
14260
+ must(repTx.reason === "initial" || repTx.reason === "rebase");
14261
+ this.clientID = repTx.clientID;
14262
+ this.mutationID = repTx.mutationID;
14263
+ this.reason = repTx.reason === "initial" ? "optimistic" : "rebase";
14264
+ this.mutate = makeSchemaCRUD(schema, repTx);
14265
+ }
14266
+ clientID;
14267
+ mutationID;
14268
+ reason;
14269
+ mutate;
14270
+ };
14271
+ function makeReplicacheMutator(mutator, schema) {
14272
+ return (repTx, args) => {
14273
+ const tx = new TransactionImpl(repTx, schema);
14274
+ return mutator(tx, args);
14275
+ };
14276
+ }
14277
+ function makeSchemaCRUD(schema, tx) {
14278
+ const mutate = {};
14279
+ for (const [name] of Object.entries(schema.tables)) {
14280
+ mutate[name] = makeTableCRUD(schema, name, tx);
14281
+ }
14282
+ return mutate;
14283
+ }
14284
+ function makeTableCRUD(schema, tableName, tx) {
14285
+ const table2 = must(schema.tables[tableName]);
14286
+ const { primaryKey } = table2;
14287
+ return {
14288
+ insert: (value) => insertImpl(tx, { op: "insert", tableName, primaryKey, value }, schema),
14289
+ upsert: (value) => upsertImpl(tx, { op: "upsert", tableName, primaryKey, value }, schema),
14290
+ update: (value) => updateImpl(tx, { op: "update", tableName, primaryKey, value }, schema),
14291
+ delete: (id) => deleteImpl(tx, { op: "delete", tableName, primaryKey, value: id }, schema)
14292
+ };
14293
+ }
14294
+
14240
14295
  // ../zero-client/src/client/zero.ts
14241
14296
  var onSetConnectionStateSymbol = Symbol();
14242
14297
  var exposedToTestingSymbol = Symbol();
@@ -14403,8 +14458,17 @@ var Zero = class {
14403
14458
  });
14404
14459
  const logOptions = this.#logOptions;
14405
14460
  const replicacheMutators = {
14406
- ["_zero_crud"]: makeCRUDMutator(schema)
14461
+ [CRUD_MUTATION_NAME]: makeCRUDMutator(schema)
14407
14462
  };
14463
+ for (const [namespace, mutatorsForNamespace] of Object.entries(
14464
+ options.mutators ?? {}
14465
+ )) {
14466
+ for (const [name, mutator] of Object.entries(
14467
+ mutatorsForNamespace
14468
+ )) {
14469
+ replicacheMutators[customMutatorKey(namespace, name)] = makeReplicacheMutator(mutator, schema);
14470
+ }
14471
+ }
14408
14472
  this.storageKey = storageKey ?? "";
14409
14473
  const replicacheOptions = {
14410
14474
  // The schema stored in IDB is dependent upon both the application schema
@@ -14461,6 +14525,20 @@ var Zero = class {
14461
14525
  this.#onClientStateNotFound = onClientStateNotFoundCallback;
14462
14526
  this.#rep.onClientStateNotFound = onClientStateNotFoundCallback;
14463
14527
  const { mutate, mutateBatch } = makeCRUDMutate(schema, rep.mutate);
14528
+ for (const [namespace, mutatorsForNamespace] of Object.entries(
14529
+ options.mutators ?? {}
14530
+ )) {
14531
+ let existing = mutate[namespace];
14532
+ if (existing === void 0) {
14533
+ existing = {};
14534
+ mutate[namespace] = existing;
14535
+ }
14536
+ for (const name of Object.keys(
14537
+ mutatorsForNamespace
14538
+ )) {
14539
+ existing[name] = must(rep.mutate[customMutatorKey(namespace, name)]);
14540
+ }
14541
+ }
14464
14542
  this.mutate = mutate;
14465
14543
  this.mutateBatch = mutateBatch;
14466
14544
  this.#queryManager = new QueryManager(
@@ -15380,6 +15458,9 @@ var TimedOutError = class extends Error {
15380
15458
  };
15381
15459
  var CloseError = class extends Error {
15382
15460
  };
15461
+ function customMutatorKey(namespace, name) {
15462
+ return `${namespace}.${name}`;
15463
+ }
15383
15464
 
15384
15465
  export {
15385
15466
  getDefaultPuller,
@@ -15402,4 +15483,4 @@ export {
15402
15483
  escapeLike,
15403
15484
  Zero
15404
15485
  };
15405
- //# sourceMappingURL=chunk-XBQPXRPX.js.map
15486
+ //# sourceMappingURL=chunk-5S3K5CU2.js.map