@rocicorp/zero 0.14.2025021404 → 0.15.2025021400

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 (235) hide show
  1. package/out/{chunk-3XESAURC.js → chunk-PEVTLPCO.js} +656 -404
  2. package/out/chunk-PEVTLPCO.js.map +7 -0
  3. package/out/replicache/src/deleted-clients.d.ts +26 -0
  4. package/out/replicache/src/deleted-clients.d.ts.map +1 -0
  5. package/out/replicache/src/persist/client-gc.d.ts.map +1 -1
  6. package/out/replicache/src/persist/client-group-gc.d.ts +6 -2
  7. package/out/replicache/src/persist/client-group-gc.d.ts.map +1 -1
  8. package/out/replicache/src/persist/clients.d.ts +1 -2
  9. package/out/replicache/src/persist/clients.d.ts.map +1 -1
  10. package/out/replicache/src/persist/collect-idb-databases.d.ts.map +1 -1
  11. package/out/replicache/src/replicache-impl.d.ts +1 -1
  12. package/out/replicache/src/replicache-impl.d.ts.map +1 -1
  13. package/out/shared/src/immutable.d.ts +1 -1
  14. package/out/shared/src/immutable.d.ts.map +1 -1
  15. package/out/shared/src/queue.d.ts +15 -0
  16. package/out/shared/src/queue.d.ts.map +1 -1
  17. package/out/shared/src/queue.js +23 -0
  18. package/out/shared/src/queue.js.map +1 -1
  19. package/out/shared/src/resolved-promises.d.ts +4 -0
  20. package/out/shared/src/resolved-promises.d.ts.map +1 -1
  21. package/out/shared/src/resolved-promises.js +4 -0
  22. package/out/shared/src/resolved-promises.js.map +1 -1
  23. package/out/solid.js +1 -1
  24. package/out/zero/src/build-schema.d.ts +1 -1
  25. package/out/zero/src/build-schema.d.ts.map +1 -1
  26. package/out/zero/src/build-schema.js +5 -1
  27. package/out/zero/src/build-schema.js.map +1 -1
  28. package/out/zero/src/deploy-permissions.d.ts +3 -0
  29. package/out/zero/src/deploy-permissions.d.ts.map +1 -0
  30. package/out/zero/src/deploy-permissions.js +3 -0
  31. package/out/zero/src/deploy-permissions.js.map +1 -0
  32. package/out/zero/src/zero-cache-dev.js +55 -47
  33. package/out/zero/src/zero-cache-dev.js.map +1 -1
  34. package/out/zero-cache/src/auth/jwt.d.ts +0 -1
  35. package/out/zero-cache/src/auth/jwt.d.ts.map +1 -1
  36. package/out/zero-cache/src/auth/jwt.js +3 -5
  37. package/out/zero-cache/src/auth/jwt.js.map +1 -1
  38. package/out/zero-cache/src/auth/load-permissions.d.ts +16 -0
  39. package/out/zero-cache/src/auth/load-permissions.d.ts.map +1 -0
  40. package/out/zero-cache/src/auth/load-permissions.js +51 -0
  41. package/out/zero-cache/src/auth/load-permissions.js.map +1 -0
  42. package/out/zero-cache/src/auth/read-authorizer.d.ts +2 -2
  43. package/out/zero-cache/src/auth/read-authorizer.d.ts.map +1 -1
  44. package/out/zero-cache/src/auth/read-authorizer.js +10 -3
  45. package/out/zero-cache/src/auth/read-authorizer.js.map +1 -1
  46. package/out/zero-cache/src/auth/write-authorizer.d.ts +1 -3
  47. package/out/zero-cache/src/auth/write-authorizer.d.ts.map +1 -1
  48. package/out/zero-cache/src/auth/write-authorizer.js +11 -7
  49. package/out/zero-cache/src/auth/write-authorizer.js.map +1 -1
  50. package/out/zero-cache/src/config/zero-config.d.ts +0 -215
  51. package/out/zero-cache/src/config/zero-config.d.ts.map +1 -1
  52. package/out/zero-cache/src/config/zero-config.js +0 -38
  53. package/out/zero-cache/src/config/zero-config.js.map +1 -1
  54. package/out/zero-cache/src/scripts/deploy-permissions.d.ts +2 -0
  55. package/out/zero-cache/src/scripts/deploy-permissions.d.ts.map +1 -0
  56. package/out/zero-cache/src/scripts/deploy-permissions.js +114 -0
  57. package/out/zero-cache/src/scripts/deploy-permissions.js.map +1 -0
  58. package/out/zero-cache/src/scripts/permissions.d.ts +40 -0
  59. package/out/zero-cache/src/scripts/permissions.d.ts.map +1 -0
  60. package/out/zero-cache/src/scripts/permissions.js +90 -0
  61. package/out/zero-cache/src/scripts/permissions.js.map +1 -0
  62. package/out/zero-cache/src/server/logging.d.ts.map +1 -1
  63. package/out/zero-cache/src/server/logging.js +5 -1
  64. package/out/zero-cache/src/server/logging.js.map +1 -1
  65. package/out/zero-cache/src/server/main.d.ts.map +1 -1
  66. package/out/zero-cache/src/server/main.js +7 -2
  67. package/out/zero-cache/src/server/main.js.map +1 -1
  68. package/out/zero-cache/src/server/multi/config.d.ts +4 -10
  69. package/out/zero-cache/src/server/multi/config.d.ts.map +1 -1
  70. package/out/zero-cache/src/server/multi/config.js +4 -0
  71. package/out/zero-cache/src/server/multi/config.js.map +1 -1
  72. package/out/zero-cache/src/server/multi/run-worker.d.ts.map +1 -1
  73. package/out/zero-cache/src/server/multi/run-worker.js +4 -2
  74. package/out/zero-cache/src/server/multi/run-worker.js.map +1 -1
  75. package/out/zero-cache/src/server/syncer.d.ts.map +1 -1
  76. package/out/zero-cache/src/server/syncer.js +8 -6
  77. package/out/zero-cache/src/server/syncer.js.map +1 -1
  78. package/out/zero-cache/src/services/change-source/custom/change-source.js +4 -0
  79. package/out/zero-cache/src/services/change-source/custom/change-source.js.map +1 -1
  80. package/out/zero-cache/src/services/change-source/pg/schema/init.js +5 -5
  81. package/out/zero-cache/src/services/change-source/pg/schema/init.js.map +1 -1
  82. package/out/zero-cache/src/services/change-source/pg/schema/shard.d.ts +4 -2
  83. package/out/zero-cache/src/services/change-source/pg/schema/shard.d.ts.map +1 -1
  84. package/out/zero-cache/src/services/change-source/pg/schema/shard.js +34 -5
  85. package/out/zero-cache/src/services/change-source/pg/schema/shard.js.map +1 -1
  86. package/out/zero-cache/src/services/change-source/pg/sync-schema.js +1 -1
  87. package/out/zero-cache/src/services/change-streamer/schema/tables.d.ts.map +1 -1
  88. package/out/zero-cache/src/services/change-streamer/schema/tables.js +5 -1
  89. package/out/zero-cache/src/services/change-streamer/schema/tables.js.map +1 -1
  90. package/out/zero-cache/src/services/dispatcher/{sync-dispatcher.d.ts → dispatcher.d.ts} +5 -4
  91. package/out/zero-cache/src/services/dispatcher/dispatcher.d.ts.map +1 -0
  92. package/out/zero-cache/src/services/dispatcher/dispatcher.js +64 -0
  93. package/out/zero-cache/src/services/dispatcher/dispatcher.js.map +1 -0
  94. package/out/zero-cache/src/services/mutagen/mutagen.d.ts +1 -3
  95. package/out/zero-cache/src/services/mutagen/mutagen.d.ts.map +1 -1
  96. package/out/zero-cache/src/services/mutagen/mutagen.js +2 -2
  97. package/out/zero-cache/src/services/mutagen/mutagen.js.map +1 -1
  98. package/out/zero-cache/src/services/mutagen/pusher.d.ts +48 -0
  99. package/out/zero-cache/src/services/mutagen/pusher.d.ts.map +1 -0
  100. package/out/zero-cache/src/services/mutagen/pusher.js +137 -0
  101. package/out/zero-cache/src/services/mutagen/pusher.js.map +1 -0
  102. package/out/zero-cache/src/services/view-syncer/client-handler.d.ts +6 -4
  103. package/out/zero-cache/src/services/view-syncer/client-handler.d.ts.map +1 -1
  104. package/out/zero-cache/src/services/view-syncer/client-handler.js +49 -11
  105. package/out/zero-cache/src/services/view-syncer/client-handler.js.map +1 -1
  106. package/out/zero-cache/src/services/view-syncer/cvr-store.d.ts +1 -1
  107. package/out/zero-cache/src/services/view-syncer/cvr-store.d.ts.map +1 -1
  108. package/out/zero-cache/src/services/view-syncer/cvr-store.js +18 -3
  109. package/out/zero-cache/src/services/view-syncer/cvr-store.js.map +1 -1
  110. package/out/zero-cache/src/services/view-syncer/cvr.d.ts +8 -8
  111. package/out/zero-cache/src/services/view-syncer/cvr.d.ts.map +1 -1
  112. package/out/zero-cache/src/services/view-syncer/cvr.js +14 -16
  113. package/out/zero-cache/src/services/view-syncer/cvr.js.map +1 -1
  114. package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts +6 -1
  115. package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts.map +1 -1
  116. package/out/zero-cache/src/services/view-syncer/pipeline-driver.js +8 -0
  117. package/out/zero-cache/src/services/view-syncer/pipeline-driver.js.map +1 -1
  118. package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts.map +1 -1
  119. package/out/zero-cache/src/services/view-syncer/snapshotter.js +4 -0
  120. package/out/zero-cache/src/services/view-syncer/snapshotter.js.map +1 -1
  121. package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts +5 -2
  122. package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts.map +1 -1
  123. package/out/zero-cache/src/services/view-syncer/view-syncer.js +45 -21
  124. package/out/zero-cache/src/services/view-syncer/view-syncer.js.map +1 -1
  125. package/out/zero-cache/src/types/pg.d.ts +6 -0
  126. package/out/zero-cache/src/types/pg.d.ts.map +1 -1
  127. package/out/zero-cache/src/types/pg.js +15 -2
  128. package/out/zero-cache/src/types/pg.js.map +1 -1
  129. package/out/zero-cache/src/types/strings.d.ts +2 -0
  130. package/out/zero-cache/src/types/strings.d.ts.map +1 -0
  131. package/out/zero-cache/src/types/strings.js +12 -0
  132. package/out/zero-cache/src/types/strings.js.map +1 -0
  133. package/out/zero-cache/src/types/ws.d.ts.map +1 -1
  134. package/out/zero-cache/src/types/ws.js +4 -14
  135. package/out/zero-cache/src/types/ws.js.map +1 -1
  136. package/out/zero-cache/src/workers/connection.d.ts +18 -3
  137. package/out/zero-cache/src/workers/connection.d.ts.map +1 -1
  138. package/out/zero-cache/src/workers/connection.js +25 -66
  139. package/out/zero-cache/src/workers/connection.js.map +1 -1
  140. package/out/zero-cache/src/workers/syncer-ws-message-handler.d.ts +13 -0
  141. package/out/zero-cache/src/workers/syncer-ws-message-handler.d.ts.map +1 -0
  142. package/out/zero-cache/src/workers/syncer-ws-message-handler.js +110 -0
  143. package/out/zero-cache/src/workers/syncer-ws-message-handler.js.map +1 -0
  144. package/out/zero-cache/src/workers/syncer.d.ts +2 -1
  145. package/out/zero-cache/src/workers/syncer.d.ts.map +1 -1
  146. package/out/zero-cache/src/workers/syncer.js +8 -3
  147. package/out/zero-cache/src/workers/syncer.js.map +1 -1
  148. package/out/zero-client/src/client/crud.d.ts +2 -19
  149. package/out/zero-client/src/client/crud.d.ts.map +1 -1
  150. package/out/zero-client/src/client/custom.d.ts +13 -58
  151. package/out/zero-client/src/client/custom.d.ts.map +1 -1
  152. package/out/zero-client/src/client/delete-clients-manager.d.ts +35 -0
  153. package/out/zero-client/src/client/delete-clients-manager.d.ts.map +1 -0
  154. package/out/zero-client/src/client/query-manager.d.ts +1 -1
  155. package/out/zero-client/src/client/query-manager.d.ts.map +1 -1
  156. package/out/zero-client/src/client/zero-poke-handler.d.ts +1 -0
  157. package/out/zero-client/src/client/zero-poke-handler.d.ts.map +1 -1
  158. package/out/zero-client/src/client/zero.d.ts +8 -2
  159. package/out/zero-client/src/client/zero.d.ts.map +1 -1
  160. package/out/zero-client/src/mod.d.ts +2 -1
  161. package/out/zero-client/src/mod.d.ts.map +1 -1
  162. package/out/zero-protocol/src/connect.d.ts +8 -0
  163. package/out/zero-protocol/src/connect.d.ts.map +1 -1
  164. package/out/zero-protocol/src/connect.js +2 -0
  165. package/out/zero-protocol/src/connect.js.map +1 -1
  166. package/out/zero-protocol/src/delete-clients.d.ts +8 -7
  167. package/out/zero-protocol/src/delete-clients.d.ts.map +1 -1
  168. package/out/zero-protocol/src/delete-clients.js +4 -3
  169. package/out/zero-protocol/src/delete-clients.js.map +1 -1
  170. package/out/zero-protocol/src/down.d.ts +5 -1
  171. package/out/zero-protocol/src/down.d.ts.map +1 -1
  172. package/out/zero-protocol/src/down.js +2 -1
  173. package/out/zero-protocol/src/down.js.map +1 -1
  174. package/out/zero-protocol/src/poke.d.ts +2 -0
  175. package/out/zero-protocol/src/poke.d.ts.map +1 -1
  176. package/out/zero-protocol/src/poke.js +4 -0
  177. package/out/zero-protocol/src/poke.js.map +1 -1
  178. package/out/zero-protocol/src/protocol-version.d.ts +11 -3
  179. package/out/zero-protocol/src/protocol-version.d.ts.map +1 -1
  180. package/out/zero-protocol/src/protocol-version.js +14 -4
  181. package/out/zero-protocol/src/protocol-version.js.map +1 -1
  182. package/out/zero-protocol/src/push.d.ts +20 -0
  183. package/out/zero-protocol/src/push.d.ts.map +1 -1
  184. package/out/zero-protocol/src/push.js +30 -0
  185. package/out/zero-protocol/src/push.js.map +1 -1
  186. package/out/zero-protocol/src/up.d.ts +8 -3
  187. package/out/zero-protocol/src/up.d.ts.map +1 -1
  188. package/out/zero-schema/src/builder/schema-builder.d.ts +0 -1
  189. package/out/zero-schema/src/builder/schema-builder.d.ts.map +1 -1
  190. package/out/zero-schema/src/builder/schema-builder.js +0 -49
  191. package/out/zero-schema/src/builder/schema-builder.js.map +1 -1
  192. package/out/zero-schema/src/compiled-permissions.d.ts +22 -19
  193. package/out/zero-schema/src/compiled-permissions.d.ts.map +1 -1
  194. package/out/zero-schema/src/compiled-permissions.js +6 -4
  195. package/out/zero-schema/src/compiled-permissions.js.map +1 -1
  196. package/out/zero-schema/src/mod.d.ts +1 -1
  197. package/out/zero-schema/src/mod.d.ts.map +1 -1
  198. package/out/zero-schema/src/name-mapper.d.ts +6 -0
  199. package/out/zero-schema/src/name-mapper.d.ts.map +1 -1
  200. package/out/zero-schema/src/name-mapper.js +16 -0
  201. package/out/zero-schema/src/name-mapper.js.map +1 -1
  202. package/out/zero-schema/src/permissions.d.ts.map +1 -1
  203. package/out/zero.js +1 -1
  204. package/out/zql/src/ivm/join.d.ts.map +1 -1
  205. package/out/zql/src/ivm/join.js +6 -2
  206. package/out/zql/src/ivm/join.js.map +1 -1
  207. package/out/zql/src/mutate/custom.d.ts +72 -0
  208. package/out/zql/src/mutate/custom.d.ts.map +1 -0
  209. package/out/zql/src/query/query-impl.d.ts +2 -2
  210. package/out/zql/src/query/query-impl.d.ts.map +1 -1
  211. package/out/zql/src/query/query-impl.js +6 -8
  212. package/out/zql/src/query/query-impl.js.map +1 -1
  213. package/out/zql/src/query/{auth-query.d.ts → static-query.d.ts} +7 -3
  214. package/out/zql/src/query/static-query.d.ts.map +1 -0
  215. package/out/zql/src/query/{auth-query.js → static-query.js} +9 -5
  216. package/out/zql/src/query/static-query.js.map +1 -0
  217. package/package.json +4 -5
  218. package/out/chunk-3XESAURC.js.map +0 -7
  219. package/out/zero-cache/src/auth/load-schema.d.ts +0 -8
  220. package/out/zero-cache/src/auth/load-schema.d.ts.map +0 -1
  221. package/out/zero-cache/src/auth/load-schema.js +0 -26
  222. package/out/zero-cache/src/auth/load-schema.js.map +0 -1
  223. package/out/zero-cache/src/services/dispatcher/sync-dispatcher.d.ts.map +0 -1
  224. package/out/zero-cache/src/services/dispatcher/sync-dispatcher.js +0 -54
  225. package/out/zero-cache/src/services/dispatcher/sync-dispatcher.js.map +0 -1
  226. package/out/zero-schema/src/build-schema-options.d.ts +0 -17
  227. package/out/zero-schema/src/build-schema-options.d.ts.map +0 -1
  228. package/out/zero-schema/src/build-schema-options.js +0 -25
  229. package/out/zero-schema/src/build-schema-options.js.map +0 -1
  230. package/out/zero-schema/src/build-schema.d.ts +0 -2
  231. package/out/zero-schema/src/build-schema.d.ts.map +0 -1
  232. package/out/zero-schema/src/build-schema.js +0 -27
  233. package/out/zero-schema/src/build-schema.js.map +0 -1
  234. package/out/zql/src/query/auth-query.d.ts.map +0 -1
  235. package/out/zql/src/query/auth-query.js.map +0 -1
@@ -397,6 +397,8 @@ var promiseTrue = Promise.resolve(true);
397
397
  var promiseFalse = Promise.resolve(false);
398
398
  var promiseUndefined = Promise.resolve(void 0);
399
399
  var promiseVoid = Promise.resolve();
400
+ var promiseNever = new Promise(() => {
401
+ });
400
402
 
401
403
  // ../replicache/src/frozen-json.ts
402
404
  var deepFrozenObjects = /* @__PURE__ */ new WeakSet();
@@ -723,7 +725,7 @@ var AbortError = class extends Error {
723
725
  // ../shared/src/sleep.ts
724
726
  import { resolver as resolver2 } from "@rocicorp/resolver";
725
727
  var promiseVoid2 = Promise.resolve();
726
- var promiseNever = new Promise(() => void 0);
728
+ var promiseNever2 = new Promise(() => void 0);
727
729
  function sleep(ms, signal) {
728
730
  const newAbortError = () => new AbortError("Aborted");
729
731
  if (signal?.aborted) {
@@ -749,7 +751,7 @@ function sleep(ms, signal) {
749
751
  }
750
752
  function sleepWithAbort(ms, signal) {
751
753
  if (ms === 0) {
752
- return [promiseVoid2, promiseNever];
754
+ return [promiseVoid2, promiseNever2];
753
755
  }
754
756
  const { promise: abortedPromise, resolve: abortedResolve } = resolver2();
755
757
  const sleepPromise = new Promise((resolve) => {
@@ -1416,6 +1418,58 @@ var WriteImpl2 = class extends ReadImpl2 {
1416
1418
  }
1417
1419
  };
1418
1420
 
1421
+ // ../replicache/src/deleted-clients.ts
1422
+ var DELETED_CLIENTS_HEAD_NAME = "deleted-clients";
1423
+ var deletedClientsSchema = readonlyObject({
1424
+ clientIDs: readonlyArray(valita_exports.string()),
1425
+ clientGroupIDs: readonlyArray(valita_exports.string())
1426
+ });
1427
+ var legacyDeletedClientsSchema = readonlyArray(valita_exports.string());
1428
+ async function setDeletedClients(dagWrite, clientIDs, clientGroupIDs) {
1429
+ const data = {
1430
+ clientIDs: normalize(clientIDs),
1431
+ clientGroupIDs: normalize(clientGroupIDs)
1432
+ };
1433
+ const chunkData = deepFreeze(data);
1434
+ const chunk = dagWrite.createChunk(chunkData, []);
1435
+ await dagWrite.putChunk(chunk);
1436
+ await dagWrite.setHead(DELETED_CLIENTS_HEAD_NAME, chunk.hash);
1437
+ return data;
1438
+ }
1439
+ async function getDeletedClients(dagRead) {
1440
+ const hash2 = await dagRead.getHead(DELETED_CLIENTS_HEAD_NAME);
1441
+ if (hash2 === void 0) {
1442
+ return { clientIDs: [], clientGroupIDs: [] };
1443
+ }
1444
+ const chunk = await dagRead.mustGetChunk(hash2);
1445
+ const res = test(chunk.data, legacyDeletedClientsSchema);
1446
+ if (res.ok) {
1447
+ return { clientIDs: res.value, clientGroupIDs: [] };
1448
+ }
1449
+ return parse(chunk.data, deletedClientsSchema);
1450
+ }
1451
+ async function addDeletedClients(dagWrite, clientIDs, clientGroupIDs) {
1452
+ const { clientIDs: oldClientIDs, clientGroupIDs: oldClientGroupIDs } = await getDeletedClients(dagWrite);
1453
+ return setDeletedClients(
1454
+ dagWrite,
1455
+ [...oldClientIDs, ...clientIDs],
1456
+ [...oldClientGroupIDs, ...clientGroupIDs]
1457
+ );
1458
+ }
1459
+ async function removeDeletedClients(dagWrite, clientIDs, clientGroupIDs) {
1460
+ const { clientIDs: oldClientIDs, clientGroupIDs: oldClientGroupIDs } = await getDeletedClients(dagWrite);
1461
+ const newDeletedClients = oldClientIDs.filter(
1462
+ (clientID) => !clientIDs.includes(clientID)
1463
+ );
1464
+ const newDeletedClientGroups = oldClientGroupIDs.filter(
1465
+ (clientGroupID) => !clientGroupIDs.includes(clientGroupID)
1466
+ );
1467
+ return setDeletedClients(dagWrite, newDeletedClients, newDeletedClientGroups);
1468
+ }
1469
+ function normalize(arr) {
1470
+ return [...new Set(arr)].sort();
1471
+ }
1472
+
1419
1473
  // ../replicache/src/format-version-enum.ts
1420
1474
  var DD31 = 5;
1421
1475
  var V6 = 6;
@@ -5736,7 +5790,7 @@ async function mustGetClient(id, dagRead) {
5736
5790
  return client;
5737
5791
  }
5738
5792
  function initClientV6(newClientID, lc, perdag, mutatorNames, indexes, formatVersion, enableClientGroupForking) {
5739
- return withWriteNoImplicitCommit(perdag, async (dagWrite) => {
5793
+ return withWrite(perdag, async (dagWrite) => {
5740
5794
  async function setClientsAndClientGroupAndCommit(basisHash, cookieJSON, valueHash2, indexRecords2) {
5741
5795
  const newSnapshotData = newSnapshotCommitDataDD31(
5742
5796
  basisHash,
@@ -5770,7 +5824,6 @@ function initClientV6(newClientID, lc, perdag, mutatorNames, indexes, formatVers
5770
5824
  setClients(newClients, dagWrite),
5771
5825
  setClientGroup(newClientGroupID, clientGroup, dagWrite)
5772
5826
  ]);
5773
- await dagWrite.commit();
5774
5827
  return [newClient, chunk.hash, newClients, true];
5775
5828
  }
5776
5829
  const clients = await getClients(dagWrite);
@@ -5785,7 +5838,6 @@ function initClientV6(newClientID, lc, perdag, mutatorNames, indexes, formatVers
5785
5838
  };
5786
5839
  const newClients = new Map(clients).set(newClientID, newClient);
5787
5840
  await setClients(newClients, dagWrite);
5788
- await dagWrite.commit();
5789
5841
  return [newClient, headHash, newClients, false];
5790
5842
  }
5791
5843
  if (!enableClientGroupForking || res.type === FIND_MATCHING_CLIENT_TYPE_NEW) {
@@ -5973,7 +6025,13 @@ function gcClients(clientID, dagStore, clientMaxInactiveTime, onClientsDeleted)
5973
6025
  return clients;
5974
6026
  }
5975
6027
  await setClients(newClients, dagWrite);
5976
- onClientsDeleted(deletedClients);
6028
+ const { clientIDs, clientGroupIDs } = await addDeletedClients(
6029
+ dagWrite,
6030
+ deletedClients,
6031
+ // gcClients does not delete client groups
6032
+ []
6033
+ );
6034
+ onClientsDeleted(clientIDs, clientGroupIDs);
5977
6035
  return newClients;
5978
6036
  });
5979
6037
  }
@@ -5981,11 +6039,15 @@ function gcClients(clientID, dagStore, clientMaxInactiveTime, onClientsDeleted)
5981
6039
  // ../replicache/src/persist/client-group-gc.ts
5982
6040
  var GC_INTERVAL_MS = 5 * 60 * 1e3;
5983
6041
  var latestGCUpdate2;
5984
- function initClientGroupGC(dagStore, lc, signal) {
6042
+ function initClientGroupGC(dagStore, enableMutationRecovery, onClientsDeleted, lc, signal) {
5985
6043
  initBgIntervalProcess(
5986
6044
  "ClientGroupGC",
5987
6045
  () => {
5988
- latestGCUpdate2 = gcClientGroups(dagStore);
6046
+ latestGCUpdate2 = gcClientGroups(
6047
+ dagStore,
6048
+ enableMutationRecovery,
6049
+ onClientsDeleted
6050
+ );
5989
6051
  return latestGCUpdate2;
5990
6052
  },
5991
6053
  () => GC_INTERVAL_MS,
@@ -5993,21 +6055,24 @@ function initClientGroupGC(dagStore, lc, signal) {
5993
6055
  signal
5994
6056
  );
5995
6057
  }
5996
- function gcClientGroups(dagStore) {
6058
+ function gcClientGroups(dagStore, enableMutationRecovery, onClientsDeleted) {
5997
6059
  return withWrite(dagStore, async (tx) => {
5998
6060
  const clients = await getClients(tx);
5999
6061
  const clientGroupIDs = /* @__PURE__ */ new Set();
6000
6062
  for (const client of clients.values()) {
6001
- assertClientV6(client);
6002
6063
  clientGroupIDs.add(client.clientGroupID);
6003
6064
  }
6004
6065
  const clientGroups = /* @__PURE__ */ new Map();
6066
+ const removeClientGroups = /* @__PURE__ */ new Set();
6005
6067
  for (const [clientGroupID, clientGroup] of await getClientGroups(tx)) {
6006
- if (clientGroupIDs.has(clientGroupID) || clientGroupHasPendingMutations(clientGroup)) {
6068
+ if (clientGroupIDs.has(clientGroupID) || enableMutationRecovery && clientGroupHasPendingMutations(clientGroup)) {
6007
6069
  clientGroups.set(clientGroupID, clientGroup);
6070
+ } else {
6071
+ removeClientGroups.add(clientGroupID);
6008
6072
  }
6009
6073
  }
6010
6074
  await setClientGroups(clientGroups, tx);
6075
+ onClientsDeleted([], [...removeClientGroups].sort());
6011
6076
  return clientGroups;
6012
6077
  });
6013
6078
  }
@@ -7244,8 +7309,7 @@ var ReplicacheImpl = class {
7244
7309
  enableScheduledRefresh = true,
7245
7310
  enablePullAndPushInOpen = true,
7246
7311
  enableClientGroupForking = true,
7247
- onClientsDeleted = (clientIDs) => {
7248
- this.#lc.info?.("ClientIDs deleted", clientIDs);
7312
+ onClientsDeleted = () => {
7249
7313
  }
7250
7314
  } = implOptions;
7251
7315
  this.auth = auth ?? "";
@@ -7389,7 +7453,13 @@ var ReplicacheImpl = class {
7389
7453
  this.#lc,
7390
7454
  signal
7391
7455
  );
7392
- initClientGroupGC(this.perdag, this.#lc, signal);
7456
+ initClientGroupGC(
7457
+ this.perdag,
7458
+ enableMutationRecovery,
7459
+ onClientsDeleted,
7460
+ this.#lc,
7461
+ signal
7462
+ );
7393
7463
  initNewClientChannel(
7394
7464
  this.name,
7395
7465
  this.idbName,
@@ -8251,11 +8321,19 @@ async function collectIDBDatabases(idbDatabasesStore, now, maxAge, kvDropStore,
8251
8321
  )
8252
8322
  );
8253
8323
  const dbNamesToRemove = [];
8324
+ const dbNamesToKeep = [];
8254
8325
  const clientIDsToRemove = [];
8255
- for (const [dbName, [canCollect, clientIDs]] of collectResults) {
8326
+ const clientGroupIDsToRemove = [];
8327
+ for (const [
8328
+ dbName,
8329
+ [canCollect, clientIDs, clientGroupIDs]
8330
+ ] of collectResults) {
8256
8331
  if (canCollect) {
8257
8332
  dbNamesToRemove.push(dbName);
8258
8333
  clientIDsToRemove.push(...clientIDs);
8334
+ clientGroupIDsToRemove.push(...clientGroupIDs);
8335
+ } else {
8336
+ dbNamesToKeep.push(dbName);
8259
8337
  }
8260
8338
  }
8261
8339
  const { errors } = await dropDatabases(
@@ -8266,8 +8344,24 @@ async function collectIDBDatabases(idbDatabasesStore, now, maxAge, kvDropStore,
8266
8344
  if (errors.length) {
8267
8345
  throw errors[0];
8268
8346
  }
8269
- if (clientIDsToRemove.length) {
8270
- onClientsDeleted(clientIDsToRemove);
8347
+ if (clientIDsToRemove.length || clientGroupIDsToRemove.length) {
8348
+ const newClientIDsToRemove = clientIDsToRemove;
8349
+ const newClientGroupIDsToRemove = clientGroupIDsToRemove;
8350
+ for (const name of dbNamesToKeep) {
8351
+ await withWrite(newDagStore(name), async (dagWrite) => {
8352
+ const { clientIDs, clientGroupIDs } = await addDeletedClients(
8353
+ dagWrite,
8354
+ clientIDsToRemove,
8355
+ clientGroupIDsToRemove
8356
+ );
8357
+ newClientIDsToRemove.push(...clientIDs);
8358
+ newClientGroupIDsToRemove.push(...clientGroupIDs);
8359
+ });
8360
+ }
8361
+ onClientsDeleted(
8362
+ normalize(newClientIDsToRemove),
8363
+ normalize(newClientGroupIDsToRemove)
8364
+ );
8271
8365
  }
8272
8366
  }
8273
8367
  async function dropDatabaseInternal(name, idbDatabasesStore, kvDropStore) {
@@ -8345,7 +8439,14 @@ function canDatabaseBeCollectedAndGetDeletedClientIDs(enableMutationRecovery, pe
8345
8439
  }
8346
8440
  }
8347
8441
  const clients = await getClients(read);
8348
- return [true, [...clients.keys()]];
8442
+ const { clientIDs, clientGroupIDs } = await getDeletedClients(read);
8443
+ const newClientIDs = [...clientIDs];
8444
+ const newClientGroupIDs = [...clientGroupIDs];
8445
+ for (const [clientID, client] of clients) {
8446
+ newClientIDs.push(clientID);
8447
+ newClientGroupIDs.push(client.clientGroupID);
8448
+ }
8449
+ return [true, newClientIDs, newClientGroupIDs];
8349
8450
  });
8350
8451
  }
8351
8452
 
@@ -8374,87 +8475,6 @@ function one(...args) {
8374
8475
  }));
8375
8476
  }
8376
8477
 
8377
- // ../zero-schema/src/name-mapper.ts
8378
- function clientToServer(tables) {
8379
- return createMapperFrom("client", tables);
8380
- }
8381
- function serverToClient(tables) {
8382
- return createMapperFrom("server", tables);
8383
- }
8384
- function createMapperFrom(src, tables) {
8385
- const mapping = new Map(
8386
- Object.entries(tables).map(
8387
- ([tableName, { serverName: serverTableName, columns }]) => {
8388
- let allColumnsSame = true;
8389
- const names = {};
8390
- for (const [name, { serverName }] of Object.entries(columns)) {
8391
- if (serverName && serverName !== name) {
8392
- allColumnsSame = false;
8393
- }
8394
- if (src === "client") {
8395
- names[name] = serverName ?? name;
8396
- } else {
8397
- names[serverName ?? name] = name;
8398
- }
8399
- }
8400
- return [
8401
- src === "client" ? tableName : serverTableName ?? tableName,
8402
- {
8403
- tableName: src === "client" ? serverTableName ?? tableName : tableName,
8404
- columns: names,
8405
- allColumnsSame
8406
- }
8407
- ];
8408
- }
8409
- )
8410
- );
8411
- return new NameMapper(mapping);
8412
- }
8413
- var NameMapper = class {
8414
- #tables = /* @__PURE__ */ new Map();
8415
- constructor(tables) {
8416
- this.#tables = tables;
8417
- }
8418
- #getTable(src, ctx) {
8419
- const table2 = this.#tables.get(src);
8420
- if (!table2) {
8421
- throw new Error(
8422
- `unknown table "${src}" ${!ctx ? "" : `in ${JSON.stringify(ctx)}`}`
8423
- );
8424
- }
8425
- return table2;
8426
- }
8427
- tableName(src, context) {
8428
- return this.#getTable(src, context).tableName;
8429
- }
8430
- columnName(table2, src, ctx) {
8431
- const dst = this.#getTable(table2, ctx).columns[src];
8432
- if (!dst) {
8433
- throw new Error(
8434
- `unknown column "${src}" of "${table2}" table ${!ctx ? "" : `in ${JSON.stringify(ctx)}`}`
8435
- );
8436
- }
8437
- return dst;
8438
- }
8439
- row(table2, row) {
8440
- const dest = this.#getTable(table2);
8441
- const { allColumnsSame, columns } = dest;
8442
- if (allColumnsSame) {
8443
- return row;
8444
- }
8445
- const clientRow = {};
8446
- for (const col in row) {
8447
- clientRow[columns[col] ?? col] = row[col];
8448
- }
8449
- return clientRow;
8450
- }
8451
- columns(table2, cols) {
8452
- const dest = this.#getTable(table2);
8453
- const { allColumnsSame, columns } = dest;
8454
- return cols === void 0 || allColumnsSame ? cols : cols.map((col) => columns[col] ?? col);
8455
- }
8456
- };
8457
-
8458
8478
  // ../zero-schema/src/builder/table-builder.ts
8459
8479
  function table(name) {
8460
8480
  return new TableBuilder({
@@ -8463,7 +8483,7 @@ function table(name) {
8463
8483
  primaryKey: []
8464
8484
  });
8465
8485
  }
8466
- function string7() {
8486
+ function string8() {
8467
8487
  return new ColumnBuilder({
8468
8488
  type: "string",
8469
8489
  optional: false,
@@ -8971,242 +8991,90 @@ function compareUTF8MaybeNull(a, b) {
8971
8991
  return 0;
8972
8992
  }
8973
8993
 
8974
- // ../zql/src/query/expression.ts
8975
- var ExpressionBuilder = class {
8976
- #exists;
8977
- constructor(exists) {
8978
- this.#exists = exists;
8979
- this.exists = this.exists.bind(this);
8980
- }
8981
- get eb() {
8982
- return this;
8983
- }
8984
- cmp(field, opOrValue, value) {
8985
- return cmp(field, opOrValue, value);
8994
+ // ../zql/src/query/query-impl.ts
8995
+ import { resolver as resolver7 } from "@rocicorp/resolver";
8996
+
8997
+ // ../shared/src/hash.ts
8998
+ import { xxHash32 } from "js-xxhash";
8999
+ var h64 = (s) => hash(s, 2);
9000
+ var h128 = (s) => hash(s, 4);
9001
+ function hash(str, words) {
9002
+ let hash2 = 0n;
9003
+ for (let i = 0; i < words; i++) {
9004
+ hash2 = (hash2 << 32n) + BigInt(xxHash32(str, i));
8986
9005
  }
8987
- cmpLit(left, op, right) {
8988
- return {
8989
- type: "simple",
8990
- left: isParameterReference(left) ? left[toStaticParam]() : { type: "literal", value: left },
8991
- right: isParameterReference(right) ? right[toStaticParam]() : { type: "literal", value: right },
8992
- op
8993
- };
9006
+ return hash2;
9007
+ }
9008
+
9009
+ // ../zero-protocol/src/ast-hash.ts
9010
+ var hashCache = /* @__PURE__ */ new WeakMap();
9011
+ function hashOfAST(ast) {
9012
+ const normalized = normalizeAST(ast);
9013
+ const cached = hashCache.get(normalized);
9014
+ if (cached) {
9015
+ return cached;
8994
9016
  }
8995
- and = and;
8996
- or = or;
8997
- not = not;
8998
- exists(relationship, cb) {
8999
- return this.#exists(relationship, cb);
9017
+ const hash2 = h64(JSON.stringify(normalized)).toString(36);
9018
+ hashCache.set(normalized, hash2);
9019
+ return hash2;
9020
+ }
9021
+
9022
+ // ../zero-schema/src/table-schema.ts
9023
+ function isOneHop(r) {
9024
+ return r.length === 1;
9025
+ }
9026
+ function isTwoHop(r) {
9027
+ return r.length === 2;
9028
+ }
9029
+
9030
+ // ../zql/src/ivm/operator.ts
9031
+ var throwOutput = {
9032
+ push(_change) {
9033
+ throw new Error("Output not set");
9000
9034
  }
9001
9035
  };
9002
- function and(...conditions) {
9003
- const expressions = filterTrue(filterUndefined(conditions));
9004
- if (expressions.length === 1) {
9005
- return expressions[0];
9036
+
9037
+ // ../zql/src/ivm/stream.ts
9038
+ function* take(stream, limit) {
9039
+ if (limit < 1) {
9040
+ return;
9006
9041
  }
9007
- if (expressions.some(isAlwaysFalse)) {
9008
- return FALSE;
9042
+ let count = 0;
9043
+ for (const v2 of stream) {
9044
+ yield v2;
9045
+ if (++count === limit) {
9046
+ break;
9047
+ }
9009
9048
  }
9010
- return { type: "and", conditions: expressions };
9011
9049
  }
9012
- function or(...conditions) {
9013
- const expressions = filterFalse(filterUndefined(conditions));
9014
- if (expressions.length === 1) {
9015
- return expressions[0];
9016
- }
9017
- if (expressions.some(isAlwaysTrue)) {
9018
- return TRUE;
9019
- }
9020
- return { type: "or", conditions: expressions };
9050
+ function first(stream) {
9051
+ const it = stream[Symbol.iterator]();
9052
+ const { value } = it.next();
9053
+ it.return?.();
9054
+ return value;
9021
9055
  }
9022
- function not(expression) {
9023
- switch (expression.type) {
9024
- case "and":
9025
- return {
9026
- type: "or",
9027
- conditions: expression.conditions.map(not)
9028
- };
9029
- case "or":
9030
- return {
9031
- type: "and",
9032
- conditions: expression.conditions.map(not)
9033
- };
9034
- case "correlatedSubquery":
9035
- return {
9036
- type: "correlatedSubquery",
9037
- related: expression.related,
9038
- op: negateOperator(expression.op)
9039
- };
9040
- case "simple":
9041
- return {
9042
- type: "simple",
9043
- op: negateOperator(expression.op),
9044
- left: expression.left,
9045
- right: expression.right
9046
- };
9047
- }
9048
- }
9049
- function cmp(field, opOrValue, value) {
9050
- let op;
9051
- if (value === void 0) {
9052
- value = opOrValue;
9053
- op = "=";
9054
- } else {
9055
- op = opOrValue;
9056
- }
9057
- return {
9058
- type: "simple",
9059
- left: { type: "column", name: field },
9060
- right: isParameterReference(value) ? value[toStaticParam]() : { type: "literal", value },
9061
- op
9062
- };
9063
- }
9064
- function isParameterReference(value) {
9065
- return value !== null && typeof value === "object" && value[toStaticParam];
9066
- }
9067
- var TRUE = {
9068
- type: "and",
9069
- conditions: []
9070
- };
9071
- var FALSE = {
9072
- type: "or",
9073
- conditions: []
9074
- };
9075
- function isAlwaysTrue(condition) {
9076
- return condition.type === "and" && condition.conditions.length === 0;
9077
- }
9078
- function isAlwaysFalse(condition) {
9079
- return condition.type === "or" && condition.conditions.length === 0;
9080
- }
9081
- function flatten(type, conditions) {
9082
- const flattened2 = [];
9083
- for (const c of conditions) {
9084
- if (c.type === type) {
9085
- flattened2.push(...c.conditions);
9086
- } else {
9087
- flattened2.push(c);
9088
- }
9089
- }
9090
- return flattened2;
9091
- }
9092
- var negateSimpleOperatorMap = {
9093
- ["="]: "!=",
9094
- ["!="]: "=",
9095
- ["<"]: ">=",
9096
- [">"]: "<=",
9097
- [">="]: "<",
9098
- ["<="]: ">",
9099
- ["IN"]: "NOT IN",
9100
- ["NOT IN"]: "IN",
9101
- ["LIKE"]: "NOT LIKE",
9102
- ["NOT LIKE"]: "LIKE",
9103
- ["ILIKE"]: "NOT ILIKE",
9104
- ["NOT ILIKE"]: "ILIKE",
9105
- ["IS"]: "IS NOT",
9106
- ["IS NOT"]: "IS"
9107
- };
9108
- var negateOperatorMap = {
9109
- ...negateSimpleOperatorMap,
9110
- ["EXISTS"]: "NOT EXISTS",
9111
- ["NOT EXISTS"]: "EXISTS"
9112
- };
9113
- function negateOperator(op) {
9114
- return must(negateOperatorMap[op]);
9115
- }
9116
- function filterUndefined(array9) {
9117
- return array9.filter((e) => e !== void 0);
9118
- }
9119
- function filterTrue(conditions) {
9120
- return conditions.filter((c) => !isAlwaysTrue(c));
9121
- }
9122
- function filterFalse(conditions) {
9123
- return conditions.filter((c) => !isAlwaysFalse(c));
9124
- }
9125
-
9126
- // ../zql/src/query/query-impl.ts
9127
- import { resolver as resolver7 } from "@rocicorp/resolver";
9128
-
9129
- // ../shared/src/hash.ts
9130
- import { xxHash32 } from "js-xxhash";
9131
- var h64 = (s) => hash(s, 2);
9132
- var h128 = (s) => hash(s, 4);
9133
- function hash(str, words) {
9134
- let hash2 = 0n;
9135
- for (let i = 0; i < words; i++) {
9136
- hash2 = (hash2 << 32n) + BigInt(xxHash32(str, i));
9137
- }
9138
- return hash2;
9139
- }
9140
-
9141
- // ../zero-protocol/src/ast-hash.ts
9142
- var hashCache = /* @__PURE__ */ new WeakMap();
9143
- function hashOfAST(ast) {
9144
- const normalized = normalizeAST(ast);
9145
- const cached = hashCache.get(normalized);
9146
- if (cached) {
9147
- return cached;
9148
- }
9149
- const hash2 = h64(JSON.stringify(normalized)).toString(36);
9150
- hashCache.set(normalized, hash2);
9151
- return hash2;
9152
- }
9153
-
9154
- // ../zero-schema/src/table-schema.ts
9155
- function isOneHop(r) {
9156
- return r.length === 1;
9157
- }
9158
- function isTwoHop(r) {
9159
- return r.length === 2;
9160
- }
9161
-
9162
- // ../zql/src/ivm/operator.ts
9163
- var throwOutput = {
9164
- push(_change) {
9165
- throw new Error("Output not set");
9166
- }
9167
- };
9168
-
9169
- // ../zql/src/ivm/stream.ts
9170
- function* take(stream, limit) {
9171
- if (limit < 1) {
9172
- return;
9173
- }
9174
- let count = 0;
9175
- for (const v2 of stream) {
9176
- yield v2;
9177
- if (++count === limit) {
9178
- break;
9179
- }
9180
- }
9181
- }
9182
- function first(stream) {
9183
- const it = stream[Symbol.iterator]();
9184
- const { value } = it.next();
9185
- it.return?.();
9186
- return value;
9187
- }
9188
-
9189
- // ../zql/src/ivm/exists.ts
9190
- var Exists = class {
9191
- #input;
9192
- #relationshipName;
9193
- #storage;
9194
- #not;
9195
- #parentJoinKey;
9196
- #skipCache;
9197
- #output = throwOutput;
9198
- constructor(input, storage, relationshipName, parentJoinKey, type) {
9199
- this.#input = input;
9200
- this.#relationshipName = relationshipName;
9201
- this.#input.setOutput(this);
9202
- this.#storage = storage;
9203
- assert(this.#input.getSchema().relationships[relationshipName]);
9204
- this.#not = type === "NOT EXISTS";
9205
- this.#parentJoinKey = parentJoinKey;
9206
- this.#skipCache = areEqual(
9207
- parentJoinKey,
9208
- this.#input.getSchema().primaryKey
9209
- );
9056
+
9057
+ // ../zql/src/ivm/exists.ts
9058
+ var Exists = class {
9059
+ #input;
9060
+ #relationshipName;
9061
+ #storage;
9062
+ #not;
9063
+ #parentJoinKey;
9064
+ #skipCache;
9065
+ #output = throwOutput;
9066
+ constructor(input, storage, relationshipName, parentJoinKey, type) {
9067
+ this.#input = input;
9068
+ this.#relationshipName = relationshipName;
9069
+ this.#input.setOutput(this);
9070
+ this.#storage = storage;
9071
+ assert(this.#input.getSchema().relationships[relationshipName]);
9072
+ this.#not = type === "NOT EXISTS";
9073
+ this.#parentJoinKey = parentJoinKey;
9074
+ this.#skipCache = areEqual(
9075
+ parentJoinKey,
9076
+ this.#input.getSchema().primaryKey
9077
+ );
9210
9078
  }
9211
9079
  setOutput(output) {
9212
9080
  this.#output = output;
@@ -9619,11 +9487,11 @@ var Join = class {
9619
9487
  const childSchema = child.getSchema();
9620
9488
  this.#schema = {
9621
9489
  ...parentSchema,
9622
- isHidden: hidden,
9623
9490
  relationships: {
9624
9491
  ...parentSchema.relationships,
9625
9492
  [relationshipName]: {
9626
9493
  ...childSchema,
9494
+ isHidden: hidden,
9627
9495
  system
9628
9496
  }
9629
9497
  }
@@ -9686,7 +9554,15 @@ var Join = class {
9686
9554
  });
9687
9555
  break;
9688
9556
  case "child":
9689
- this.#output.push(change);
9557
+ this.#output.push({
9558
+ type: "child",
9559
+ node: this.#processParentNode(
9560
+ change.node.row,
9561
+ change.node.relationships,
9562
+ "fetch"
9563
+ ),
9564
+ child: change.child
9565
+ });
9690
9566
  break;
9691
9567
  case "edit": {
9692
9568
  if (rowEqualsForCompoundKey(
@@ -10564,11 +10440,11 @@ function createPredicateImpl(rhs, operator) {
10564
10440
  case "LIKE":
10565
10441
  return getLikePredicate(rhs, "");
10566
10442
  case "NOT LIKE":
10567
- return not2(getLikePredicate(rhs, ""));
10443
+ return not(getLikePredicate(rhs, ""));
10568
10444
  case "ILIKE":
10569
10445
  return getLikePredicate(rhs, "i");
10570
10446
  case "NOT ILIKE":
10571
- return not2(getLikePredicate(rhs, "i"));
10447
+ return not(getLikePredicate(rhs, "i"));
10572
10448
  case "IN": {
10573
10449
  assert(Array.isArray(rhs));
10574
10450
  const set = new Set(rhs);
@@ -10584,7 +10460,7 @@ function createPredicateImpl(rhs, operator) {
10584
10460
  throw new Error(`Unexpected operator: ${operator}`);
10585
10461
  }
10586
10462
  }
10587
- function not2(f) {
10463
+ function not(f) {
10588
10464
  return (lhs) => !f(lhs);
10589
10465
  }
10590
10466
  function transformFilters(filters) {
@@ -10955,6 +10831,158 @@ var ArrayView = class {
10955
10831
  }
10956
10832
  };
10957
10833
 
10834
+ // ../zql/src/query/expression.ts
10835
+ var ExpressionBuilder = class {
10836
+ #exists;
10837
+ constructor(exists) {
10838
+ this.#exists = exists;
10839
+ this.exists = this.exists.bind(this);
10840
+ }
10841
+ get eb() {
10842
+ return this;
10843
+ }
10844
+ cmp(field, opOrValue, value) {
10845
+ return cmp(field, opOrValue, value);
10846
+ }
10847
+ cmpLit(left, op, right) {
10848
+ return {
10849
+ type: "simple",
10850
+ left: isParameterReference(left) ? left[toStaticParam]() : { type: "literal", value: left },
10851
+ right: isParameterReference(right) ? right[toStaticParam]() : { type: "literal", value: right },
10852
+ op
10853
+ };
10854
+ }
10855
+ and = and;
10856
+ or = or;
10857
+ not = not2;
10858
+ exists(relationship, cb) {
10859
+ return this.#exists(relationship, cb);
10860
+ }
10861
+ };
10862
+ function and(...conditions) {
10863
+ const expressions = filterTrue(filterUndefined(conditions));
10864
+ if (expressions.length === 1) {
10865
+ return expressions[0];
10866
+ }
10867
+ if (expressions.some(isAlwaysFalse)) {
10868
+ return FALSE;
10869
+ }
10870
+ return { type: "and", conditions: expressions };
10871
+ }
10872
+ function or(...conditions) {
10873
+ const expressions = filterFalse(filterUndefined(conditions));
10874
+ if (expressions.length === 1) {
10875
+ return expressions[0];
10876
+ }
10877
+ if (expressions.some(isAlwaysTrue)) {
10878
+ return TRUE;
10879
+ }
10880
+ return { type: "or", conditions: expressions };
10881
+ }
10882
+ function not2(expression) {
10883
+ switch (expression.type) {
10884
+ case "and":
10885
+ return {
10886
+ type: "or",
10887
+ conditions: expression.conditions.map(not2)
10888
+ };
10889
+ case "or":
10890
+ return {
10891
+ type: "and",
10892
+ conditions: expression.conditions.map(not2)
10893
+ };
10894
+ case "correlatedSubquery":
10895
+ return {
10896
+ type: "correlatedSubquery",
10897
+ related: expression.related,
10898
+ op: negateOperator(expression.op)
10899
+ };
10900
+ case "simple":
10901
+ return {
10902
+ type: "simple",
10903
+ op: negateOperator(expression.op),
10904
+ left: expression.left,
10905
+ right: expression.right
10906
+ };
10907
+ }
10908
+ }
10909
+ function cmp(field, opOrValue, value) {
10910
+ let op;
10911
+ if (value === void 0) {
10912
+ value = opOrValue;
10913
+ op = "=";
10914
+ } else {
10915
+ op = opOrValue;
10916
+ }
10917
+ return {
10918
+ type: "simple",
10919
+ left: { type: "column", name: field },
10920
+ right: isParameterReference(value) ? value[toStaticParam]() : { type: "literal", value },
10921
+ op
10922
+ };
10923
+ }
10924
+ function isParameterReference(value) {
10925
+ return value !== null && typeof value === "object" && value[toStaticParam];
10926
+ }
10927
+ var TRUE = {
10928
+ type: "and",
10929
+ conditions: []
10930
+ };
10931
+ var FALSE = {
10932
+ type: "or",
10933
+ conditions: []
10934
+ };
10935
+ function isAlwaysTrue(condition) {
10936
+ return condition.type === "and" && condition.conditions.length === 0;
10937
+ }
10938
+ function isAlwaysFalse(condition) {
10939
+ return condition.type === "or" && condition.conditions.length === 0;
10940
+ }
10941
+ function flatten(type, conditions) {
10942
+ const flattened2 = [];
10943
+ for (const c of conditions) {
10944
+ if (c.type === type) {
10945
+ flattened2.push(...c.conditions);
10946
+ } else {
10947
+ flattened2.push(c);
10948
+ }
10949
+ }
10950
+ return flattened2;
10951
+ }
10952
+ var negateSimpleOperatorMap = {
10953
+ ["="]: "!=",
10954
+ ["!="]: "=",
10955
+ ["<"]: ">=",
10956
+ [">"]: "<=",
10957
+ [">="]: "<",
10958
+ ["<="]: ">",
10959
+ ["IN"]: "NOT IN",
10960
+ ["NOT IN"]: "IN",
10961
+ ["LIKE"]: "NOT LIKE",
10962
+ ["NOT LIKE"]: "LIKE",
10963
+ ["ILIKE"]: "NOT ILIKE",
10964
+ ["NOT ILIKE"]: "ILIKE",
10965
+ ["IS"]: "IS NOT",
10966
+ ["IS NOT"]: "IS"
10967
+ };
10968
+ var negateOperatorMap = {
10969
+ ...negateSimpleOperatorMap,
10970
+ ["EXISTS"]: "NOT EXISTS",
10971
+ ["NOT EXISTS"]: "EXISTS"
10972
+ };
10973
+ function negateOperator(op) {
10974
+ return must(negateOperatorMap[op]);
10975
+ }
10976
+ function filterUndefined(array9) {
10977
+ return array9.filter((e) => e !== void 0);
10978
+ }
10979
+ function filterTrue(conditions) {
10980
+ return conditions.filter((c) => !isAlwaysTrue(c));
10981
+ }
10982
+ function filterFalse(conditions) {
10983
+ return conditions.filter((c) => !isAlwaysFalse(c));
10984
+ }
10985
+
10958
10986
  // ../zql/src/query/dnf.ts
10959
10987
  function dnf(condition) {
10960
10988
  return unwrap(dnfInner(condition));
@@ -11009,6 +11037,7 @@ function unwrap(c) {
11009
11037
  }
11010
11038
 
11011
11039
  // ../zql/src/query/query-impl.ts
11040
+ var astForTestingSymbol = Symbol();
11012
11041
  function newQuery(delegate, schema, table2) {
11013
11042
  return new QueryImpl(delegate, schema, table2);
11014
11043
  }
@@ -11039,6 +11068,10 @@ var AbstractQuery = class {
11039
11068
  get format() {
11040
11069
  return this.#format;
11041
11070
  }
11071
+ // Not part of Query or QueryInternal interface
11072
+ get [astForTestingSymbol]() {
11073
+ return this.#ast;
11074
+ }
11042
11075
  hash() {
11043
11076
  if (!this.#hash) {
11044
11077
  const ast = this._completeAst();
@@ -11166,6 +11199,7 @@ var AbstractQuery = class {
11166
11199
  parentField: firstRelation.sourceField,
11167
11200
  childField: firstRelation.destField
11168
11201
  },
11202
+ hidden: true,
11169
11203
  subquery: {
11170
11204
  table: junctionSchema,
11171
11205
  alias: relationship,
@@ -11180,7 +11214,6 @@ var AbstractQuery = class {
11180
11214
  parentField: secondRelation.sourceField,
11181
11215
  childField: secondRelation.destField
11182
11216
  },
11183
- hidden: true,
11184
11217
  subquery: addPrimaryKeysToAst(
11185
11218
  this.#schema.tables[destSchema],
11186
11219
  sq.#ast
@@ -11393,21 +11426,14 @@ var AbstractQuery = class {
11393
11426
  return this.#completedAST;
11394
11427
  }
11395
11428
  };
11396
- var astForTestingSymbol = Symbol();
11397
11429
  var completedAstSymbol = Symbol();
11398
11430
  var QueryImpl = class extends AbstractQuery {
11399
11431
  #delegate;
11400
- #ast;
11401
11432
  constructor(delegate, schema, tableName, ast = { table: tableName }, format) {
11402
11433
  super(schema, tableName, ast, format);
11403
11434
  this.#delegate = delegate;
11404
- this.#ast = ast;
11405
11435
  }
11406
11436
  _system = "client";
11407
- // Not part of Query or QueryInternal interface
11408
- get [astForTestingSymbol]() {
11409
- return this.#ast;
11410
- }
11411
11437
  get [completedAstSymbol]() {
11412
11438
  return this._completeAst();
11413
11439
  }
@@ -11498,8 +11524,8 @@ function isCompoundKey(field) {
11498
11524
  return Array.isArray(field) && field.length >= 1;
11499
11525
  }
11500
11526
 
11501
- // ../zql/src/query/auth-query.ts
11502
- var AuthQuery = class _AuthQuery extends AbstractQuery {
11527
+ // ../zql/src/query/static-query.ts
11528
+ var StaticQuery = class _StaticQuery extends AbstractQuery {
11503
11529
  constructor(schema, tableName, ast = { table: tableName }, format) {
11504
11530
  super(schema, tableName, ast, format);
11505
11531
  }
@@ -11508,7 +11534,7 @@ var AuthQuery = class _AuthQuery extends AbstractQuery {
11508
11534
  }
11509
11535
  _system = "permissions";
11510
11536
  _newQuery(schema, tableName, ast, format) {
11511
- return new _AuthQuery(schema, tableName, ast, format);
11537
+ return new _StaticQuery(schema, tableName, ast, format);
11512
11538
  }
11513
11539
  get ast() {
11514
11540
  return this._completeAst();
@@ -11524,13 +11550,97 @@ var AuthQuery = class _AuthQuery extends AbstractQuery {
11524
11550
  }
11525
11551
  };
11526
11552
 
11553
+ // ../zero-schema/src/name-mapper.ts
11554
+ function clientToServer(tables) {
11555
+ return createMapperFrom("client", tables);
11556
+ }
11557
+ function serverToClient(tables) {
11558
+ return createMapperFrom("server", tables);
11559
+ }
11560
+ function createMapperFrom(src, tables) {
11561
+ const mapping = new Map(
11562
+ Object.entries(tables).map(
11563
+ ([tableName, { serverName: serverTableName, columns }]) => {
11564
+ let allColumnsSame = true;
11565
+ const names = {};
11566
+ for (const [name, { serverName }] of Object.entries(columns)) {
11567
+ if (serverName && serverName !== name) {
11568
+ allColumnsSame = false;
11569
+ }
11570
+ if (src === "client") {
11571
+ names[name] = serverName ?? name;
11572
+ } else {
11573
+ names[serverName ?? name] = name;
11574
+ }
11575
+ }
11576
+ return [
11577
+ src === "client" ? tableName : serverTableName ?? tableName,
11578
+ {
11579
+ tableName: src === "client" ? serverTableName ?? tableName : tableName,
11580
+ columns: names,
11581
+ allColumnsSame
11582
+ }
11583
+ ];
11584
+ }
11585
+ )
11586
+ );
11587
+ return new NameMapper(mapping);
11588
+ }
11589
+ var NameMapper = class {
11590
+ #tables = /* @__PURE__ */ new Map();
11591
+ constructor(tables) {
11592
+ this.#tables = tables;
11593
+ }
11594
+ #getTable(src, ctx) {
11595
+ const table2 = this.#tables.get(src);
11596
+ if (!table2) {
11597
+ throw new Error(
11598
+ `unknown table "${src}" ${!ctx ? "" : `in ${JSON.stringify(ctx)}`}`
11599
+ );
11600
+ }
11601
+ return table2;
11602
+ }
11603
+ tableName(src, context) {
11604
+ return this.#getTable(src, context).tableName;
11605
+ }
11606
+ columnName(table2, src, ctx) {
11607
+ const dst = this.#getTable(table2, ctx).columns[src];
11608
+ if (!dst) {
11609
+ throw new Error(
11610
+ `unknown column "${src}" of "${table2}" table ${!ctx ? "" : `in ${JSON.stringify(ctx)}`}`
11611
+ );
11612
+ }
11613
+ return dst;
11614
+ }
11615
+ row(table2, row) {
11616
+ const dest = this.#getTable(table2);
11617
+ const { allColumnsSame, columns } = dest;
11618
+ if (allColumnsSame) {
11619
+ return row;
11620
+ }
11621
+ const clientRow = {};
11622
+ for (const col in row) {
11623
+ clientRow[columns[col] ?? col] = row[col];
11624
+ }
11625
+ return clientRow;
11626
+ }
11627
+ columns(table2, cols) {
11628
+ const dest = this.#getTable(table2);
11629
+ const { allColumnsSame, columns } = dest;
11630
+ return cols === void 0 || allColumnsSame ? cols : cols.map((col) => columns[col] ?? col);
11631
+ }
11632
+ };
11633
+
11527
11634
  // ../zero-schema/src/permissions.ts
11528
11635
  var ANYONE_CAN = void 0;
11529
11636
  var NOBODY_CAN = [];
11530
11637
  async function definePermissions(schema, definer) {
11531
11638
  const expressionBuilders = {};
11532
11639
  for (const name of Object.keys(schema.tables)) {
11533
- expressionBuilders[name] = new AuthQuery(schema, name).expressionBuilder();
11640
+ expressionBuilders[name] = new StaticQuery(
11641
+ schema,
11642
+ name
11643
+ ).expressionBuilder();
11534
11644
  }
11535
11645
  const config = await definer();
11536
11646
  return compilePermissions(schema, config, expressionBuilders);
@@ -11540,10 +11650,10 @@ function compilePermissions(schema, authz, expressionBuilders) {
11540
11650
  return void 0;
11541
11651
  }
11542
11652
  const nameMapper = clientToServer(schema.tables);
11543
- const ret = {};
11653
+ const ret = { tables: {} };
11544
11654
  for (const [tableName, tableConfig] of Object.entries(authz)) {
11545
11655
  const serverName = schema.tables[tableName].serverName ?? tableName;
11546
- ret[serverName] = {
11656
+ ret.tables[serverName] = {
11547
11657
  row: compileRowConfig(
11548
11658
  nameMapper,
11549
11659
  tableName,
@@ -11694,6 +11804,18 @@ function escapeLike(val) {
11694
11804
  import { LogContext as LogContext4 } from "@rocicorp/logger";
11695
11805
  import { resolver as resolver8 } from "@rocicorp/resolver";
11696
11806
 
11807
+ // ../zero-protocol/src/delete-clients.ts
11808
+ var deleteClientsBodySchema = valita_exports.union(
11809
+ readonlyObject({
11810
+ clientIDs: readonlyArray(valita_exports.string()).optional(),
11811
+ clientGroupIDs: readonlyArray(valita_exports.string()).optional()
11812
+ })
11813
+ );
11814
+ var deleteClientsMessageSchema = valita_exports.tuple([
11815
+ valita_exports.literal("deleteClients"),
11816
+ deleteClientsBodySchema
11817
+ ]);
11818
+
11697
11819
  // ../zero-protocol/src/queries-patch.ts
11698
11820
  var putOpSchema = valita_exports.object({
11699
11821
  op: valita_exports.literal("put"),
@@ -11720,7 +11842,8 @@ var connectedMessageSchema = valita_exports.tuple([
11720
11842
  connectedBodySchema
11721
11843
  ]);
11722
11844
  var initConnectionBodySchema = valita_exports.object({
11723
- desiredQueriesPatch: queriesPatchSchema
11845
+ desiredQueriesPatch: queriesPatchSchema,
11846
+ deleted: deleteClientsBodySchema.optional()
11724
11847
  });
11725
11848
  var initConnectionMessageSchema = valita_exports.tuple([
11726
11849
  valita_exports.literal("initConnection"),
@@ -11895,6 +12018,10 @@ var pokePartBodySchema = valita_exports.object({
11895
12018
  });
11896
12019
  var pokeEndBodySchema = valita_exports.object({
11897
12020
  pokeID: valita_exports.string(),
12021
+ // If present, this should be the cookie stored with the client,
12022
+ // instead of the cookie presented in pokeStart.
12023
+ // TODO: Consider making this required and removing it from pokeStart.
12024
+ cookie: versionSchema.optional(),
11898
12025
  // If `true`, the poke with id `pokeID` should be discarded without
11899
12026
  // applying it.
11900
12027
  cancel: valita_exports.boolean().optional()
@@ -11954,7 +12081,8 @@ var downstreamSchema = valita_exports.union(
11954
12081
  pokeStartMessageSchema,
11955
12082
  pokePartMessageSchema,
11956
12083
  pokeEndMessageSchema,
11957
- pullResponseMessageSchema
12084
+ pullResponseMessageSchema,
12085
+ deleteClientsMessageSchema
11958
12086
  );
11959
12087
 
11960
12088
  // ../zero-protocol/src/mutation-type-enum.ts
@@ -11962,9 +12090,11 @@ var CRUD = "crud";
11962
12090
  var Custom = "custom";
11963
12091
 
11964
12092
  // ../zero-protocol/src/protocol-version.ts
11965
- var PROTOCOL_VERSION = 4;
11966
- var MIN_SERVER_SUPPORTED_PROTOCOL_VERSION = 2;
11967
- assert(MIN_SERVER_SUPPORTED_PROTOCOL_VERSION < PROTOCOL_VERSION);
12093
+ var PROTOCOL_VERSION = 5;
12094
+ var MIN_SERVER_SUPPORTED_SYNC_PROTOCOL = 2;
12095
+ assert(MIN_SERVER_SUPPORTED_SYNC_PROTOCOL < PROTOCOL_VERSION);
12096
+ var MIN_SERVER_SUPPORTED_PERMISSIONS_PROTOCOL = 4;
12097
+ assert(MIN_SERVER_SUPPORTED_PERMISSIONS_PROTOCOL < PROTOCOL_VERSION);
11968
12098
 
11969
12099
  // ../zero-protocol/src/push.ts
11970
12100
  var CRUD_MUTATION_NAME = "_zero_crud";
@@ -12030,6 +12160,39 @@ var pushBodySchema = valita_exports.object({
12030
12160
  requestID: valita_exports.string()
12031
12161
  });
12032
12162
  var pushMessageSchema = valita_exports.tuple([valita_exports.literal("push"), pushBodySchema]);
12163
+ var mutationIDSchema = valita_exports.object({
12164
+ id: valita_exports.number(),
12165
+ clientID: valita_exports.string()
12166
+ });
12167
+ var appErrorSchema = valita_exports.object({
12168
+ type: valita_exports.literal("app"),
12169
+ error: valita_exports.string()
12170
+ });
12171
+ var zeroErrorSchema = valita_exports.object({
12172
+ type: valita_exports.literal("zero"),
12173
+ error: valita_exports.literal("ooo-mutation")
12174
+ });
12175
+ var mutationOkSchema = valita_exports.object({});
12176
+ var mutationErrorSchema = valita_exports.union(appErrorSchema, zeroErrorSchema);
12177
+ var mutationResultSchema = valita_exports.union(mutationOkSchema, mutationErrorSchema);
12178
+ var mutationResponseSchema = valita_exports.object({
12179
+ id: mutationIDSchema,
12180
+ result: mutationResultSchema
12181
+ });
12182
+ var pushOkSchema = valita_exports.object({
12183
+ mutations: valita_exports.array(mutationResponseSchema)
12184
+ });
12185
+ var unsupportedPushVersionSchema = valita_exports.object({
12186
+ error: valita_exports.literal("unsupported-push-version")
12187
+ });
12188
+ var unsupportedSchemaVersionSchema = valita_exports.object({
12189
+ error: valita_exports.literal("unsupported-schema-version")
12190
+ });
12191
+ var pushErrorSchema = valita_exports.union(
12192
+ unsupportedPushVersionSchema,
12193
+ unsupportedSchemaVersionSchema
12194
+ );
12195
+ var pushResponseSchema = valita_exports.union(pushOkSchema, pushErrorSchema);
12033
12196
  function mapCRUD(arg, map) {
12034
12197
  return {
12035
12198
  ops: arg.ops.map(
@@ -13308,48 +13471,28 @@ var ZeroContext = class {
13308
13471
  // ../zero-client/src/client/crud.ts
13309
13472
  function makeCRUDMutate(schema, repMutate) {
13310
13473
  const { [CRUD_MUTATION_NAME]: zeroCRUD } = repMutate;
13311
- let inBatch = false;
13312
13474
  const mutateBatch = async (body) => {
13313
- if (inBatch) {
13314
- throw new Error("Cannot call mutate inside a batch");
13315
- }
13316
- inBatch = true;
13317
- try {
13318
- const ops = [];
13319
- const m = {};
13320
- for (const name of Object.keys(schema.tables)) {
13321
- m[name] = makeBatchCRUDMutate(name, schema, ops);
13322
- }
13323
- const rv = await body(m);
13324
- await zeroCRUD({ ops });
13325
- return rv;
13326
- } finally {
13327
- inBatch = false;
13328
- }
13329
- };
13330
- const assertNotInBatch = (tableName, op) => {
13331
- if (inBatch) {
13332
- throw new Error(`Cannot call mutate.${tableName}.${op} inside a batch`);
13475
+ const ops = [];
13476
+ const m = {};
13477
+ for (const name of Object.keys(schema.tables)) {
13478
+ m[name] = makeBatchCRUDMutate(name, schema, ops);
13333
13479
  }
13480
+ const rv = await body(m);
13481
+ await zeroCRUD({ ops });
13482
+ return rv;
13334
13483
  };
13335
13484
  const mutate = {};
13336
13485
  for (const [name, tableSchema] of Object.entries(schema.tables)) {
13337
- mutate[name] = makeEntityCRUDMutate(
13338
- name,
13339
- tableSchema.primaryKey,
13340
- zeroCRUD,
13341
- assertNotInBatch
13342
- );
13486
+ mutate[name] = makeEntityCRUDMutate(name, tableSchema.primaryKey, zeroCRUD);
13343
13487
  }
13344
13488
  return {
13345
13489
  mutate,
13346
13490
  mutateBatch
13347
13491
  };
13348
13492
  }
13349
- function makeEntityCRUDMutate(tableName, primaryKey, zeroCRUD, assertNotInBatch) {
13493
+ function makeEntityCRUDMutate(tableName, primaryKey, zeroCRUD) {
13350
13494
  return {
13351
13495
  insert: (value) => {
13352
- assertNotInBatch(tableName, "insert");
13353
13496
  const op = {
13354
13497
  op: "insert",
13355
13498
  tableName,
@@ -13359,7 +13502,6 @@ function makeEntityCRUDMutate(tableName, primaryKey, zeroCRUD, assertNotInBatch)
13359
13502
  return zeroCRUD({ ops: [op] });
13360
13503
  },
13361
13504
  upsert: (value) => {
13362
- assertNotInBatch(tableName, "upsert");
13363
13505
  const op = {
13364
13506
  op: "upsert",
13365
13507
  tableName,
@@ -13369,7 +13511,6 @@ function makeEntityCRUDMutate(tableName, primaryKey, zeroCRUD, assertNotInBatch)
13369
13511
  return zeroCRUD({ ops: [op] });
13370
13512
  },
13371
13513
  update: (value) => {
13372
- assertNotInBatch(tableName, "update");
13373
13514
  const op = {
13374
13515
  op: "update",
13375
13516
  tableName,
@@ -13379,7 +13520,6 @@ function makeEntityCRUDMutate(tableName, primaryKey, zeroCRUD, assertNotInBatch)
13379
13520
  return zeroCRUD({ ops: [op] });
13380
13521
  },
13381
13522
  delete: (id) => {
13382
- assertNotInBatch(tableName, "delete");
13383
13523
  const op = {
13384
13524
  op: "delete",
13385
13525
  tableName,
@@ -13570,6 +13710,7 @@ var TransactionImpl = class {
13570
13710
  clientID;
13571
13711
  mutationID;
13572
13712
  reason;
13713
+ location = "client";
13573
13714
  mutate;
13574
13715
  query;
13575
13716
  };
@@ -13630,6 +13771,57 @@ function makeTableCRUD(schema, tableName, tx, ivmBranch) {
13630
13771
  };
13631
13772
  }
13632
13773
 
13774
+ // ../zero-client/src/client/delete-clients-manager.ts
13775
+ var DeleteClientsManager = class {
13776
+ #send;
13777
+ #lc;
13778
+ #dagStore;
13779
+ constructor(send2, dagStore, lc) {
13780
+ this.#send = send2;
13781
+ this.#dagStore = dagStore;
13782
+ this.#lc = lc;
13783
+ }
13784
+ /**
13785
+ * This gets called by Replicache when it deletes clients from the persistent
13786
+ * storage.
13787
+ */
13788
+ onClientsDeleted(clientIDs, clientGroupIDs) {
13789
+ this.#lc.debug?.("DeletedClientsManager, send:", clientIDs);
13790
+ this.#send(["deleteClients", { clientIDs, clientGroupIDs }]);
13791
+ }
13792
+ /**
13793
+ * Zero calls this after it connects to ensure that the server knows about all
13794
+ * the clients that might have been deleted locally since the last connection.
13795
+ */
13796
+ async sendDeletedClientsToServer() {
13797
+ const deleted = await withRead(
13798
+ this.#dagStore,
13799
+ (dagRead) => getDeletedClients(dagRead)
13800
+ );
13801
+ if (deleted.clientIDs.length > 0 || deleted.clientGroupIDs.length > 0) {
13802
+ this.#send(["deleteClients", deleted]);
13803
+ this.#lc.debug?.("DeletedClientsManager, send:", deleted);
13804
+ }
13805
+ }
13806
+ /**
13807
+ * This is called as a response to the server telling us which clients it
13808
+ * actually deleted.
13809
+ */
13810
+ clientsDeletedOnServer(deletedClients) {
13811
+ const { clientIDs = [], clientGroupIDs = [] } = deletedClients;
13812
+ if (clientIDs.length > 0 || clientGroupIDs.length > 0) {
13813
+ return withWrite(this.#dagStore, async (dagWrite) => {
13814
+ this.#lc.debug?.("clientsDeletedOnServer:", clientIDs, clientGroupIDs);
13815
+ await removeDeletedClients(dagWrite, clientIDs, clientGroupIDs);
13816
+ });
13817
+ }
13818
+ return promiseVoid;
13819
+ }
13820
+ getDeletedClients() {
13821
+ return withRead(this.#dagStore, getDeletedClients);
13822
+ }
13823
+ };
13824
+
13633
13825
  // ../zero-client/src/client/enable-analytics.ts
13634
13826
  var IPV4_ADDRESS_REGEX = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
13635
13827
  var IPV6_ADDRESS_HOSTNAME_REGEX = /^\[[a-fA-F0-9:]*:[a-fA-F0-9:]*\]$/;
@@ -13878,7 +14070,7 @@ function makeMessage(message, context, logLevel) {
13878
14070
  }
13879
14071
 
13880
14072
  // ../zero-client/src/client/version.ts
13881
- var version2 = "0.14.2025021404";
14073
+ var version2 = "0.15.2025021400";
13882
14074
 
13883
14075
  // ../zero-client/src/client/log-options.ts
13884
14076
  var LevelFilterLogSink = class {
@@ -14568,7 +14760,7 @@ var PokeHandler = class {
14568
14760
  this.#receivingPoke = void 0;
14569
14761
  return;
14570
14762
  }
14571
- this.#pokeBuffer.push(this.#receivingPoke);
14763
+ this.#pokeBuffer.push({ ...this.#receivingPoke, pokeEnd });
14572
14764
  this.#receivingPoke = void 0;
14573
14765
  if (!this.#pokePlaybackLoopRunning) {
14574
14766
  this.#startPlaybackLoop();
@@ -14644,7 +14836,8 @@ function mergePokes(pokeBuffer, schema, serverToClient2) {
14644
14836
  return void 0;
14645
14837
  }
14646
14838
  const { baseCookie } = pokeBuffer[0].pokeStart;
14647
- const { cookie } = pokeBuffer[pokeBuffer.length - 1].pokeStart;
14839
+ const lastPoke = pokeBuffer[pokeBuffer.length - 1];
14840
+ const cookie = lastPoke.pokeEnd.cookie ?? lastPoke.pokeStart.cookie;
14648
14841
  const mergedPatch = [];
14649
14842
  const mergedLastMutationIDChanges = {};
14650
14843
  let prevPokeStart = void 0;
@@ -14850,6 +15043,7 @@ var Zero = class {
14850
15043
  #queryManager;
14851
15044
  #ivmSources;
14852
15045
  #clientToServer;
15046
+ #deleteClientsManager;
14853
15047
  /**
14854
15048
  * The queries we sent when inside the sec-protocol header when establishing a connection.
14855
15049
  * More queries could be registered while we're waiting for the 'connected' message
@@ -14860,6 +15054,13 @@ var Zero = class {
14860
15054
  * and an `initConnection` message must be sent to the server after receiving the `connected` message.
14861
15055
  */
14862
15056
  #initConnectionQueries;
15057
+ /**
15058
+ * We try to send the deleted clients and (client groups) as part of the
15059
+ * sec-protocol header. If we can't because the header would get too large we
15060
+ * keep track of the deleted clients and send them after the connection is
15061
+ * established.
15062
+ */
15063
+ #deletedClients;
14863
15064
  #lastMutationIDSent = NULL_LAST_MUTATION_ID_SENT;
14864
15065
  #onPong = () => void 0;
14865
15066
  #online = false;
@@ -14995,7 +15196,8 @@ var Zero = class {
14995
15196
  };
14996
15197
  const replicacheImplOptions = {
14997
15198
  enableClientGroupForking: false,
14998
- enableMutationRecovery: false
15199
+ enableMutationRecovery: false,
15200
+ onClientsDeleted: (clientIDs, clientGroupIDs) => this.#deleteClientsManager.onClientsDeleted(clientIDs, clientGroupIDs)
14999
15201
  };
15000
15202
  const rep = new ReplicacheImpl(replicacheOptions, replicacheImplOptions);
15001
15203
  this.#rep = rep;
@@ -15054,6 +15256,11 @@ var Zero = class {
15054
15256
  maxRecentQueries
15055
15257
  );
15056
15258
  this.#clientToServer = clientToServer(schema.tables);
15259
+ this.#deleteClientsManager = new DeleteClientsManager(
15260
+ (msg) => this.#send(msg),
15261
+ rep.perdag,
15262
+ this.#lc
15263
+ );
15057
15264
  this.#zeroContext = new ZeroContext(
15058
15265
  this.#ivmSources.main,
15059
15266
  (ast, gotCallback) => this.#queryManager.add(ast, gotCallback),
@@ -15104,6 +15311,9 @@ var Zero = class {
15104
15311
  }
15105
15312
  }
15106
15313
  #sendChangeDesiredQueries(msg) {
15314
+ this.#send(msg);
15315
+ }
15316
+ #send(msg) {
15107
15317
  if (this.#socket && this.#connectionState === Connected) {
15108
15318
  send(this.#socket, msg);
15109
15319
  }
@@ -15250,6 +15460,10 @@ var Zero = class {
15250
15460
  return this.#handlePullResponse(lc, downMessage);
15251
15461
  case "warm":
15252
15462
  break;
15463
+ case "deleteClients":
15464
+ return this.#deleteClientsManager.clientsDeletedOnServer(
15465
+ downMessage[1]
15466
+ );
15253
15467
  default:
15254
15468
  msgType;
15255
15469
  rejectInvalidMessage();
@@ -15320,8 +15534,8 @@ var Zero = class {
15320
15534
  this.#metrics.lastConnectError.clear();
15321
15535
  const proceedingConnectErrorCount = this.#connectErrorCount;
15322
15536
  this.#connectErrorCount = 0;
15323
- let timeToConnectMs = void 0;
15324
- let connectMsgLatencyMs = void 0;
15537
+ let timeToConnectMs;
15538
+ let connectMsgLatencyMs;
15325
15539
  if (this.#connectStart === void 0) {
15326
15540
  lc.error?.(
15327
15541
  "Got connected message but connect start time is undefined. This should not happen."
@@ -15332,7 +15546,7 @@ var Zero = class {
15332
15546
  connectMsgLatencyMs = connectBody.timestamp !== void 0 ? now - connectBody.timestamp : void 0;
15333
15547
  this.#connectStart = void 0;
15334
15548
  }
15335
- let totalTimeToConnectMs = void 0;
15549
+ let totalTimeToConnectMs;
15336
15550
  if (this.#totalToConnectStart === void 0) {
15337
15551
  lc.error?.(
15338
15552
  "Got connected message but total to connect start time is undefined. This should not happen."
@@ -15352,26 +15566,37 @@ var Zero = class {
15352
15566
  });
15353
15567
  this.#lastMutationIDSent = NULL_LAST_MUTATION_ID_SENT;
15354
15568
  lc.debug?.("Resolving connect resolver");
15355
- assert(this.#socket);
15569
+ const socket = must(this.#socket);
15356
15570
  const queriesPatch = await this.#rep.query(
15357
15571
  (tx) => this.#queryManager.getQueriesPatch(tx, this.#initConnectionQueries)
15358
15572
  );
15573
+ const hasDeletedClients = () => skipEmptyArray(this.#deletedClients?.clientIDs) || skipEmptyArray(this.#deletedClients?.clientGroupIDs);
15574
+ const maybeSendDeletedClients = () => {
15575
+ if (hasDeletedClients()) {
15576
+ send(socket, ["deleteClients", this.#deletedClients]);
15577
+ this.#deletedClients = void 0;
15578
+ }
15579
+ };
15359
15580
  if (queriesPatch.size > 0 && this.#initConnectionQueries !== void 0) {
15360
- send(this.#socket, [
15581
+ maybeSendDeletedClients();
15582
+ send(socket, [
15361
15583
  "changeDesiredQueries",
15362
15584
  {
15363
15585
  desiredQueriesPatch: [...queriesPatch.values()]
15364
15586
  }
15365
15587
  ]);
15366
15588
  } else if (this.#initConnectionQueries === void 0) {
15367
- send(this.#socket, [
15589
+ send(socket, [
15368
15590
  "initConnection",
15369
15591
  {
15370
- desiredQueriesPatch: [...queriesPatch.values()]
15592
+ desiredQueriesPatch: [...queriesPatch.values()],
15593
+ deleted: skipEmptyDeletedClients(this.#deletedClients)
15371
15594
  }
15372
15595
  ]);
15596
+ this.#deletedClients = void 0;
15373
15597
  }
15374
15598
  this.#initConnectionQueries = void 0;
15599
+ maybeSendDeletedClients();
15375
15600
  this.#setConnectionState(Connected);
15376
15601
  this.#connectResolver.resolve();
15377
15602
  }
@@ -15425,9 +15650,10 @@ var Zero = class {
15425
15650
  clearTimeout(timeoutID);
15426
15651
  };
15427
15652
  this.#closeAbortController.signal.addEventListener("abort", abortHandler);
15428
- const [ws, initConnectionQueries] = await createSocket(
15653
+ const [ws, initConnectionQueries, deletedClients] = await createSocket(
15429
15654
  this.#rep,
15430
15655
  this.#queryManager,
15656
+ this.#deleteClientsManager,
15431
15657
  toWSString(this.#server),
15432
15658
  this.#connectCookie,
15433
15659
  this.clientID,
@@ -15446,6 +15672,7 @@ var Zero = class {
15446
15672
  return;
15447
15673
  }
15448
15674
  this.#initConnectionQueries = initConnectionQueries;
15675
+ this.#deletedClients = deletedClients;
15449
15676
  ws.addEventListener("message", this.#onMessage);
15450
15677
  ws.addEventListener("open", this.#onOpen);
15451
15678
  ws.addEventListener("close", this.#onClose);
@@ -15901,7 +16128,7 @@ var Zero = class {
15901
16128
  return rv;
15902
16129
  }
15903
16130
  };
15904
- async function createSocket(rep, queryManager, socketOrigin, baseCookie, clientID, clientGroupID, schemaVersion, userID, auth, lmid, wsid, debugPerf, lc, maxHeaderLength = 1024 * 8, additionalConnectParams) {
16131
+ async function createSocket(rep, queryManager, deleteClientsManager, socketOrigin, baseCookie, clientID, clientGroupID, schemaVersion, userID, auth, lmid, wsid, debugPerf, lc, maxHeaderLength = 1024 * 8, additionalConnectParams) {
15905
16132
  const url = new URL(
15906
16133
  appendPath(socketOrigin, `/sync/v${PROTOCOL_VERSION}/connect`)
15907
16134
  );
@@ -15928,16 +16155,24 @@ async function createSocket(rep, queryManager, socketOrigin, baseCookie, clientI
15928
16155
  }
15929
16156
  lc.info?.("Connecting to", url.toString());
15930
16157
  const WS = mustGetBrowserGlobal("WebSocket");
15931
- let queriesPatch = await rep.query(
15932
- (tx) => queryManager.getQueriesPatch(tx)
15933
- );
16158
+ const queriesPatchP = rep.query((tx) => queryManager.getQueriesPatch(tx));
16159
+ let deletedClients = await deleteClientsManager.getDeletedClients();
16160
+ let queriesPatch = await queriesPatchP;
15934
16161
  let secProtocol = encodeSecProtocols(
15935
- ["initConnection", { desiredQueriesPatch: [...queriesPatch.values()] }],
16162
+ [
16163
+ "initConnection",
16164
+ {
16165
+ desiredQueriesPatch: [...queriesPatch.values()],
16166
+ deleted: skipEmptyDeletedClients(deletedClients)
16167
+ }
16168
+ ],
15936
16169
  auth
15937
16170
  );
15938
16171
  if (secProtocol.length > maxHeaderLength) {
15939
16172
  secProtocol = encodeSecProtocols(void 0, auth);
15940
16173
  queriesPatch = void 0;
16174
+ } else {
16175
+ deletedClients = void 0;
15941
16176
  }
15942
16177
  return [
15943
16178
  new WS(
@@ -15945,9 +16180,26 @@ async function createSocket(rep, queryManager, socketOrigin, baseCookie, clientI
15945
16180
  url.toString(),
15946
16181
  secProtocol
15947
16182
  ),
15948
- queriesPatch
16183
+ queriesPatch,
16184
+ skipEmptyDeletedClients(deletedClients)
15949
16185
  ];
15950
16186
  }
16187
+ function skipEmptyArray(arr) {
16188
+ return arr && arr.length > 0 ? arr : void 0;
16189
+ }
16190
+ function skipEmptyDeletedClients(deletedClients) {
16191
+ if (!deletedClients) {
16192
+ return void 0;
16193
+ }
16194
+ const { clientIDs, clientGroupIDs } = deletedClients;
16195
+ if ((!clientIDs || clientIDs.length === 0) && (!clientGroupIDs || clientGroupIDs.length === 0)) {
16196
+ return void 0;
16197
+ }
16198
+ const data = {};
16199
+ data.clientIDs = skipEmptyArray(clientIDs);
16200
+ data.clientGroupIDs = skipEmptyArray(clientGroupIDs);
16201
+ return data;
16202
+ }
15951
16203
  function addWebSocketIDFromSocketToLogContext({ url }, lc) {
15952
16204
  const wsid = new URL(url).searchParams.get("wsid") ?? nanoid();
15953
16205
  return addWebSocketIDToLogContext(wsid, lc);
@@ -15978,7 +16230,7 @@ export {
15978
16230
  dropAllDatabases,
15979
16231
  relationships,
15980
16232
  table,
15981
- string7 as string,
16233
+ string8 as string,
15982
16234
  number4 as number,
15983
16235
  boolean3 as boolean,
15984
16236
  json,
@@ -15990,4 +16242,4 @@ export {
15990
16242
  escapeLike,
15991
16243
  Zero
15992
16244
  };
15993
- //# sourceMappingURL=chunk-3XESAURC.js.map
16245
+ //# sourceMappingURL=chunk-PEVTLPCO.js.map