@rocicorp/zero 0.24.2025091100 → 0.24.2025092400

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 (232) hide show
  1. package/out/analyze-query/src/bin-analyze.js +7 -8
  2. package/out/analyze-query/src/bin-analyze.js.map +1 -1
  3. package/out/analyze-query/src/explain-queries.d.ts +1 -1
  4. package/out/analyze-query/src/explain-queries.d.ts.map +1 -1
  5. package/out/analyze-query/src/run-ast.d.ts +13 -23
  6. package/out/analyze-query/src/run-ast.d.ts.map +1 -1
  7. package/out/analyze-query/src/run-ast.js +25 -20
  8. package/out/analyze-query/src/run-ast.js.map +1 -1
  9. package/out/{chunk-V2KPKXLX.js → chunk-5JTC5G4I.js} +254 -156
  10. package/out/chunk-5JTC5G4I.js.map +7 -0
  11. package/out/chunk-ASRS2LFV.js +35 -0
  12. package/out/chunk-ASRS2LFV.js.map +7 -0
  13. package/out/{chunk-FH5Q72JS.js → chunk-OQGMEB3H.js} +3 -3
  14. package/out/{chunk-MLYQCVBG.js → chunk-QZPMFA73.js} +1465 -945
  15. package/out/chunk-QZPMFA73.js.map +7 -0
  16. package/out/{inspector-NC6TPMRA.js → lazy-inspector-TOTYUTBC.js} +298 -231
  17. package/out/lazy-inspector-TOTYUTBC.js.map +7 -0
  18. package/out/react-native.js +276 -278
  19. package/out/react-native.js.map +4 -4
  20. package/out/react.js +13 -25
  21. package/out/react.js.map +2 -2
  22. package/out/replicache/src/connection-loop.d.ts.map +1 -1
  23. package/out/replicache/src/deleted-clients.d.ts +17 -10
  24. package/out/replicache/src/deleted-clients.d.ts.map +1 -1
  25. package/out/replicache/src/kv/expo-sqlite/store.d.ts +11 -0
  26. package/out/replicache/src/kv/expo-sqlite/store.d.ts.map +1 -0
  27. package/out/replicache/src/kv/idb-store.d.ts.map +1 -1
  28. package/out/replicache/src/kv/mem-store.d.ts.map +1 -1
  29. package/out/replicache/src/kv/op-sqlite/store.d.ts +14 -0
  30. package/out/replicache/src/kv/op-sqlite/store.d.ts.map +1 -0
  31. package/out/replicache/src/kv/op-sqlite/types.d.ts +13 -0
  32. package/out/replicache/src/kv/op-sqlite/types.d.ts.map +1 -0
  33. package/out/replicache/src/kv/read-impl.d.ts.map +1 -1
  34. package/out/replicache/src/kv/sqlite-store.d.ts +37 -63
  35. package/out/replicache/src/kv/sqlite-store.d.ts.map +1 -1
  36. package/out/replicache/src/kv/throw-if-closed.d.ts +12 -0
  37. package/out/replicache/src/kv/throw-if-closed.d.ts.map +1 -0
  38. package/out/replicache/src/kv/write-impl-base.d.ts.map +1 -1
  39. package/out/replicache/src/kv/write-impl.d.ts.map +1 -1
  40. package/out/replicache/src/persist/client-gc.d.ts.map +1 -1
  41. package/out/replicache/src/persist/client-group-gc.d.ts +2 -3
  42. package/out/replicache/src/persist/client-group-gc.d.ts.map +1 -1
  43. package/out/replicache/src/persist/clients.d.ts +2 -1
  44. package/out/replicache/src/persist/clients.d.ts.map +1 -1
  45. package/out/replicache/src/persist/collect-idb-databases.d.ts.map +1 -1
  46. package/out/replicache/src/process-scheduler.d.ts.map +1 -1
  47. package/out/replicache/src/replicache-impl.d.ts.map +1 -1
  48. package/out/shared/src/sentinels.d.ts +2 -0
  49. package/out/shared/src/sentinels.d.ts.map +1 -1
  50. package/out/shared/src/sentinels.js +7 -0
  51. package/out/shared/src/sentinels.js.map +1 -0
  52. package/out/shared/src/valita.js +1 -1
  53. package/out/shared/src/valita.js.map +1 -1
  54. package/out/solid.js +4 -4
  55. package/out/zero/package.json +4 -4
  56. package/out/zero/src/zero-cache-dev.js +4 -0
  57. package/out/zero/src/zero-cache-dev.js.map +1 -1
  58. package/out/zero-cache/src/config/network.d.ts.map +1 -1
  59. package/out/zero-cache/src/config/network.js +1 -2
  60. package/out/zero-cache/src/config/network.js.map +1 -1
  61. package/out/zero-cache/src/config/normalize.d.ts +1 -0
  62. package/out/zero-cache/src/config/normalize.d.ts.map +1 -1
  63. package/out/zero-cache/src/config/normalize.js +6 -0
  64. package/out/zero-cache/src/config/normalize.js.map +1 -1
  65. package/out/zero-cache/src/config/zero-config.d.ts +3 -0
  66. package/out/zero-cache/src/config/zero-config.d.ts.map +1 -1
  67. package/out/zero-cache/src/config/zero-config.js +35 -1
  68. package/out/zero-cache/src/config/zero-config.js.map +1 -1
  69. package/out/zero-cache/src/server/anonymous-otel-start.d.ts +1 -0
  70. package/out/zero-cache/src/server/anonymous-otel-start.d.ts.map +1 -1
  71. package/out/zero-cache/src/server/anonymous-otel-start.js +18 -0
  72. package/out/zero-cache/src/server/anonymous-otel-start.js.map +1 -1
  73. package/out/zero-cache/src/server/inspector-delegate.d.ts +9 -0
  74. package/out/zero-cache/src/server/inspector-delegate.d.ts.map +1 -1
  75. package/out/zero-cache/src/server/inspector-delegate.js +19 -0
  76. package/out/zero-cache/src/server/inspector-delegate.js.map +1 -1
  77. package/out/zero-cache/src/server/reaper.d.ts.map +1 -1
  78. package/out/zero-cache/src/server/reaper.js +8 -0
  79. package/out/zero-cache/src/server/reaper.js.map +1 -1
  80. package/out/zero-cache/src/server/syncer.js +2 -2
  81. package/out/zero-cache/src/server/syncer.js.map +1 -1
  82. package/out/zero-cache/src/services/analyze.d.ts +9 -1
  83. package/out/zero-cache/src/services/analyze.d.ts.map +1 -1
  84. package/out/zero-cache/src/services/analyze.js +109 -39
  85. package/out/zero-cache/src/services/analyze.js.map +1 -1
  86. package/out/zero-cache/src/services/change-source/pg/initial-sync.js +3 -1
  87. package/out/zero-cache/src/services/change-source/pg/initial-sync.js.map +1 -1
  88. package/out/zero-cache/src/services/change-streamer/schema/init.d.ts.map +1 -1
  89. package/out/zero-cache/src/services/change-streamer/schema/init.js +1 -0
  90. package/out/zero-cache/src/services/change-streamer/schema/init.js.map +1 -1
  91. package/out/zero-cache/src/services/heapz.d.ts +1 -1
  92. package/out/zero-cache/src/services/heapz.d.ts.map +1 -1
  93. package/out/zero-cache/src/services/heapz.js +2 -2
  94. package/out/zero-cache/src/services/heapz.js.map +1 -1
  95. package/out/zero-cache/src/services/mutagen/pusher.d.ts +36 -0
  96. package/out/zero-cache/src/services/mutagen/pusher.d.ts.map +1 -1
  97. package/out/zero-cache/src/services/replicator/change-processor.js +1 -1
  98. package/out/zero-cache/src/services/replicator/change-processor.js.map +1 -1
  99. package/out/zero-cache/src/services/replicator/incremental-sync.js +2 -2
  100. package/out/zero-cache/src/services/replicator/incremental-sync.js.map +1 -1
  101. package/out/zero-cache/src/services/statz.d.ts +1 -1
  102. package/out/zero-cache/src/services/statz.d.ts.map +1 -1
  103. package/out/zero-cache/src/services/statz.js +3 -3
  104. package/out/zero-cache/src/services/statz.js.map +1 -1
  105. package/out/zero-cache/src/services/view-syncer/active-users-gauge.d.ts +16 -0
  106. package/out/zero-cache/src/services/view-syncer/active-users-gauge.d.ts.map +1 -0
  107. package/out/zero-cache/src/services/view-syncer/active-users-gauge.js +50 -0
  108. package/out/zero-cache/src/services/view-syncer/active-users-gauge.js.map +1 -0
  109. package/out/zero-cache/src/services/view-syncer/client-schema.js +1 -1
  110. package/out/zero-cache/src/services/view-syncer/client-schema.js.map +1 -1
  111. package/out/zero-cache/src/services/view-syncer/cvr-purger.d.ts.map +1 -1
  112. package/out/zero-cache/src/services/view-syncer/cvr-purger.js +21 -5
  113. package/out/zero-cache/src/services/view-syncer/cvr-purger.js.map +1 -1
  114. package/out/zero-cache/src/services/view-syncer/row-record-cache.js +1 -1
  115. package/out/zero-cache/src/services/view-syncer/row-record-cache.js.map +1 -1
  116. package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts +2 -3
  117. package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts.map +1 -1
  118. package/out/zero-cache/src/services/view-syncer/view-syncer.js +41 -1
  119. package/out/zero-cache/src/services/view-syncer/view-syncer.js.map +1 -1
  120. package/out/zero-client/src/client/active-clients-manager.d.ts +2 -1
  121. package/out/zero-client/src/client/active-clients-manager.d.ts.map +1 -1
  122. package/out/zero-client/src/client/delete-clients-manager.d.ts +3 -3
  123. package/out/zero-client/src/client/delete-clients-manager.d.ts.map +1 -1
  124. package/out/zero-client/src/client/inspector/client-group.d.ts +12 -0
  125. package/out/zero-client/src/client/inspector/client-group.d.ts.map +1 -0
  126. package/out/zero-client/src/client/inspector/client.d.ts +15 -0
  127. package/out/zero-client/src/client/inspector/client.d.ts.map +1 -0
  128. package/out/zero-client/src/client/inspector/html-dialog-prompt.d.ts +5 -0
  129. package/out/zero-client/src/client/inspector/html-dialog-prompt.d.ts.map +1 -0
  130. package/out/zero-client/src/client/inspector/inspector.d.ts +14 -18
  131. package/out/zero-client/src/client/inspector/inspector.d.ts.map +1 -1
  132. package/out/zero-client/src/client/inspector/lazy-inspector.d.ts +49 -0
  133. package/out/zero-client/src/client/inspector/lazy-inspector.d.ts.map +1 -0
  134. package/out/zero-client/src/client/inspector/query.d.ts +31 -0
  135. package/out/zero-client/src/client/inspector/query.d.ts.map +1 -0
  136. package/out/zero-client/src/client/options.d.ts +8 -4
  137. package/out/zero-client/src/client/options.d.ts.map +1 -1
  138. package/out/zero-client/src/client/zero.d.ts +6 -6
  139. package/out/zero-client/src/client/zero.d.ts.map +1 -1
  140. package/out/zero-client/src/mod.d.ts +4 -1
  141. package/out/zero-client/src/mod.d.ts.map +1 -1
  142. package/out/zero-protocol/src/analyze-query-result.d.ts +22 -0
  143. package/out/zero-protocol/src/analyze-query-result.d.ts.map +1 -0
  144. package/out/zero-protocol/src/analyze-query-result.js +18 -0
  145. package/out/zero-protocol/src/analyze-query-result.js.map +1 -0
  146. package/out/zero-protocol/src/ast.d.ts +2 -0
  147. package/out/zero-protocol/src/ast.d.ts.map +1 -1
  148. package/out/zero-protocol/src/ast.js +2 -0
  149. package/out/zero-protocol/src/ast.js.map +1 -1
  150. package/out/zero-protocol/src/down.d.ts +20 -0
  151. package/out/zero-protocol/src/down.d.ts.map +1 -1
  152. package/out/zero-protocol/src/inspect-down.d.ts +64 -0
  153. package/out/zero-protocol/src/inspect-down.d.ts.map +1 -1
  154. package/out/zero-protocol/src/inspect-down.js +10 -1
  155. package/out/zero-protocol/src/inspect-down.js.map +1 -1
  156. package/out/zero-protocol/src/inspect-up.d.ts +73 -10
  157. package/out/zero-protocol/src/inspect-up.d.ts.map +1 -1
  158. package/out/zero-protocol/src/inspect-up.js +20 -3
  159. package/out/zero-protocol/src/inspect-up.js.map +1 -1
  160. package/out/zero-protocol/src/protocol-version.d.ts +1 -1
  161. package/out/zero-protocol/src/protocol-version.d.ts.map +1 -1
  162. package/out/zero-protocol/src/protocol-version.js +4 -1
  163. package/out/zero-protocol/src/protocol-version.js.map +1 -1
  164. package/out/zero-protocol/src/up.d.ts +19 -1
  165. package/out/zero-protocol/src/up.d.ts.map +1 -1
  166. package/out/zero-react/src/use-query.d.ts.map +1 -1
  167. package/out/zero-react-native/src/mod.d.ts +2 -2
  168. package/out/zero-react-native/src/mod.d.ts.map +1 -1
  169. package/out/zero.js +4 -4
  170. package/out/zql/src/builder/builder.d.ts.map +1 -1
  171. package/out/zql/src/builder/builder.js +23 -11
  172. package/out/zql/src/builder/builder.js.map +1 -1
  173. package/out/zql/src/builder/debug-delegate.d.ts +2 -5
  174. package/out/zql/src/builder/debug-delegate.d.ts.map +1 -1
  175. package/out/zql/src/builder/debug-delegate.js +1 -0
  176. package/out/zql/src/builder/debug-delegate.js.map +1 -1
  177. package/out/zql/src/ivm/constraint.js +1 -1
  178. package/out/zql/src/ivm/constraint.js.map +1 -1
  179. package/out/zql/src/ivm/fan-in.d.ts.map +1 -1
  180. package/out/zql/src/ivm/fan-in.js +3 -92
  181. package/out/zql/src/ivm/fan-in.js.map +1 -1
  182. package/out/zql/src/ivm/fan-out.js +2 -2
  183. package/out/zql/src/ivm/fan-out.js.map +1 -1
  184. package/out/zql/src/ivm/flipped-join.d.ts +33 -0
  185. package/out/zql/src/ivm/flipped-join.d.ts.map +1 -0
  186. package/out/zql/src/ivm/flipped-join.js +341 -0
  187. package/out/zql/src/ivm/flipped-join.js.map +1 -0
  188. package/out/zql/src/ivm/join-utils.d.ts +14 -0
  189. package/out/zql/src/ivm/join-utils.d.ts.map +1 -0
  190. package/out/zql/src/ivm/join-utils.js +94 -0
  191. package/out/zql/src/ivm/join-utils.js.map +1 -0
  192. package/out/zql/src/ivm/join.d.ts +1 -1
  193. package/out/zql/src/ivm/join.d.ts.map +1 -1
  194. package/out/zql/src/ivm/join.js +3 -101
  195. package/out/zql/src/ivm/join.js.map +1 -1
  196. package/out/zql/src/ivm/memory-source.d.ts.map +1 -1
  197. package/out/zql/src/ivm/memory-source.js +15 -4
  198. package/out/zql/src/ivm/memory-source.js.map +1 -1
  199. package/out/zql/src/ivm/push-accumulated.d.ts +88 -0
  200. package/out/zql/src/ivm/push-accumulated.d.ts.map +1 -0
  201. package/out/zql/src/ivm/push-accumulated.js +326 -0
  202. package/out/zql/src/ivm/push-accumulated.js.map +1 -0
  203. package/out/zql/src/query/expression.d.ts +3 -3
  204. package/out/zql/src/query/expression.d.ts.map +1 -1
  205. package/out/zql/src/query/expression.js +1 -1
  206. package/out/zql/src/query/expression.js.map +1 -1
  207. package/out/zql/src/query/query-impl.d.ts +3 -4
  208. package/out/zql/src/query/query-impl.d.ts.map +1 -1
  209. package/out/zql/src/query/query-impl.js +12 -5
  210. package/out/zql/src/query/query-impl.js.map +1 -1
  211. package/out/zql/src/query/query.d.ts +6 -3
  212. package/out/zql/src/query/query.d.ts.map +1 -1
  213. package/out/zql/src/query/query.js.map +1 -1
  214. package/out/zqlite/src/db.d.ts +1 -1
  215. package/out/zqlite/src/db.d.ts.map +1 -1
  216. package/out/zqlite/src/db.js +3 -3
  217. package/out/zqlite/src/db.js.map +1 -1
  218. package/out/zqlite/src/table-source.d.ts +0 -1
  219. package/out/zqlite/src/table-source.d.ts.map +1 -1
  220. package/out/zqlite/src/table-source.js +4 -5
  221. package/out/zqlite/src/table-source.js.map +1 -1
  222. package/package.json +4 -4
  223. package/out/chunk-MKB4RXL3.js +0 -15
  224. package/out/chunk-MKB4RXL3.js.map +0 -7
  225. package/out/chunk-MLYQCVBG.js.map +0 -7
  226. package/out/chunk-V2KPKXLX.js.map +0 -7
  227. package/out/inspector-NC6TPMRA.js.map +0 -7
  228. package/out/replicache/src/expo/store.d.ts +0 -4
  229. package/out/replicache/src/expo/store.d.ts.map +0 -1
  230. package/out/zero-client/src/client/inspector/types.d.ts +0 -50
  231. package/out/zero-client/src/client/inspector/types.d.ts.map +0 -1
  232. /package/out/{chunk-FH5Q72JS.js.map → chunk-OQGMEB3H.js.map} +0 -0
@@ -144,7 +144,7 @@ function getDeepestUnionParseError(value, schema, mode) {
144
144
  try {
145
145
  const str = JSON.stringify(value);
146
146
  return `Invalid union value: ${str}`;
147
- } catch (e) {
147
+ } catch {
148
148
  return `Invalid union value`;
149
149
  }
150
150
  }
@@ -236,100 +236,144 @@ function literalUnion(...literals) {
236
236
  return v.union(...literals.map(v.literal));
237
237
  }
238
238
 
239
- // ../replicache/src/dag/store.ts
240
- var ChunkNotFoundError = class extends Error {
241
- name = "ChunkNotFoundError";
242
- hash;
243
- constructor(hash2) {
244
- super(`Chunk not found ${hash2}`);
245
- this.hash = hash2;
239
+ // ../shared/src/json.ts
240
+ function deepEqual(a, b) {
241
+ if (a === b) {
242
+ return true;
246
243
  }
247
- };
248
- async function mustGetChunk(store, hash2) {
249
- const chunk = await store.getChunk(hash2);
250
- if (chunk) {
251
- return chunk;
244
+ if (typeof a !== typeof b) {
245
+ return false;
252
246
  }
253
- throw new ChunkNotFoundError(hash2);
247
+ switch (typeof a) {
248
+ case "boolean":
249
+ case "number":
250
+ case "string":
251
+ return false;
252
+ }
253
+ a = a;
254
+ if (Array.isArray(a)) {
255
+ if (!Array.isArray(b)) {
256
+ return false;
257
+ }
258
+ if (a.length !== b.length) {
259
+ return false;
260
+ }
261
+ for (let i = 0; i < a.length; i++) {
262
+ if (!deepEqual(a[i], b[i])) {
263
+ return false;
264
+ }
265
+ }
266
+ return true;
267
+ }
268
+ if (a === null || b === null) {
269
+ return false;
270
+ }
271
+ if (Array.isArray(b)) {
272
+ return false;
273
+ }
274
+ a = a;
275
+ b = b;
276
+ let aSize = 0;
277
+ for (const key in a) {
278
+ if (hasOwn(a, key)) {
279
+ if (!deepEqual(a[key], b[key])) {
280
+ return false;
281
+ }
282
+ aSize++;
283
+ }
284
+ }
285
+ let bSize = 0;
286
+ for (const key in b) {
287
+ if (hasOwn(b, key)) {
288
+ bSize++;
289
+ }
290
+ }
291
+ return aSize === bSize;
254
292
  }
255
- async function mustGetHeadHash(name, store) {
256
- const hash2 = await store.getHead(name);
257
- assert(hash2, `Missing head ${name}`);
258
- return hash2;
293
+ function assertJSONValue(v2) {
294
+ if (isProd) {
295
+ return;
296
+ }
297
+ switch (typeof v2) {
298
+ case "boolean":
299
+ case "number":
300
+ case "string":
301
+ return;
302
+ case "object":
303
+ if (v2 === null) {
304
+ return;
305
+ }
306
+ if (Array.isArray(v2)) {
307
+ return assertJSONArray(v2);
308
+ }
309
+ return assertObjectIsJSONObject(v2);
310
+ }
311
+ throwInvalidType(v2, "JSON value");
259
312
  }
260
-
261
- // ../replicache/src/with-transactions.ts
262
- function withRead(store, fn) {
263
- return using(store.read(), fn);
313
+ function assertJSONObject(v2) {
314
+ assertObject(v2);
315
+ assertObjectIsJSONObject(v2);
264
316
  }
265
- function withWriteNoImplicitCommit(store, fn) {
266
- return using(store.write(), fn);
317
+ function assertObjectIsJSONObject(v2) {
318
+ for (const k in v2) {
319
+ if (hasOwn(v2, k)) {
320
+ const value = v2[k];
321
+ if (value !== void 0) {
322
+ assertJSONValue(value);
323
+ }
324
+ }
325
+ }
267
326
  }
268
- function withWrite(store, fn) {
269
- return using(store.write(), async (write) => {
270
- const result = await fn(write);
271
- await write.commit();
272
- return result;
273
- });
327
+ function assertJSONArray(v2) {
328
+ for (const item of v2) {
329
+ assertJSONValue(item);
330
+ }
274
331
  }
275
- async function using(x, fn) {
276
- const write = await x;
277
- try {
278
- return await fn(write);
279
- } finally {
280
- write.release();
332
+ function isJSONValue(v2, path2) {
333
+ switch (typeof v2) {
334
+ case "boolean":
335
+ case "number":
336
+ case "string":
337
+ return true;
338
+ case "object":
339
+ if (v2 === null) {
340
+ return true;
341
+ }
342
+ if (Array.isArray(v2)) {
343
+ return isJSONArray(v2, path2);
344
+ }
345
+ return objectIsJSONObject(v2, path2);
281
346
  }
347
+ return false;
282
348
  }
283
-
284
- // ../replicache/src/dag/chunk.ts
285
- function asRefs(sortedRefs) {
286
- return sortedRefs;
349
+ function isJSONObject(v2, path2) {
350
+ if (typeof v2 !== "object" || v2 === null) {
351
+ return false;
352
+ }
353
+ return objectIsJSONObject(v2, path2);
287
354
  }
288
- function toRefs(refs) {
289
- if (Array.isArray(refs)) {
290
- refs.sort();
291
- for (let i = 1; i < refs.length; i++) {
292
- assert(refs[i - 1] !== refs[i], "Refs must not have duplicates");
355
+ function objectIsJSONObject(v2, path2) {
356
+ for (const k in v2) {
357
+ if (hasOwn(v2, k)) {
358
+ path2.push(k);
359
+ const value = v2[k];
360
+ if (value !== void 0 && !isJSONValue(value, path2)) {
361
+ return false;
362
+ }
363
+ path2.pop();
293
364
  }
294
- return asRefs(refs);
295
365
  }
296
- const refsArray = [...refs];
297
- refsArray.sort();
298
- return asRefs(refsArray);
366
+ return true;
299
367
  }
300
- var Chunk = class {
301
- hash;
302
- data;
303
- /**
304
- * Meta is an array of refs. If there are no refs we do not write a meta
305
- * chunk.
306
- */
307
- meta;
308
- constructor(hash2, data, refs) {
309
- assert(
310
- !refs.includes(hash2),
311
- "Chunk cannot reference itself"
312
- );
313
- assertDeepFrozen(data);
314
- this.hash = hash2;
315
- this.data = data;
316
- this.meta = refs;
317
- }
318
- };
319
- function assertRefs(v2) {
320
- if (!Array.isArray(v2)) {
321
- throw new Error("Refs must be an array");
322
- }
323
- if (v2.length > 0) {
324
- assertString(v2[0]);
325
- for (let i = 1; i < v2.length; i++) {
326
- assertString(v2[i]);
368
+ function isJSONArray(v2, path2) {
369
+ for (let i = 0; i < v2.length; i++) {
370
+ path2.push(i);
371
+ if (!isJSONValue(v2[i], path2)) {
372
+ return false;
327
373
  }
374
+ path2.pop();
328
375
  }
329
- }
330
- function createChunk(data, refs, chunkHasher) {
331
- const hash2 = chunkHasher();
332
- return new Chunk(hash2, data, refs);
376
+ return true;
333
377
  }
334
378
 
335
379
  // ../shared/src/random-uint64.ts
@@ -367,339 +411,6 @@ function assertHash(value) {
367
411
  }
368
412
  var hashSchema = valita_exports.string().assert(isHash, "Invalid hash");
369
413
 
370
- // ../replicache/src/index-defs.ts
371
- var indexDefinitionSchema = readonlyObject({
372
- prefix: valita_exports.string().optional(),
373
- jsonPointer: valita_exports.string(),
374
- allowEmpty: valita_exports.boolean().optional()
375
- });
376
- var indexDefinitionsSchema = readonlyRecord(
377
- indexDefinitionSchema
378
- );
379
- function indexDefinitionEqual(a, b) {
380
- return a.jsonPointer === b.jsonPointer && (a.allowEmpty ?? false) === (b.allowEmpty ?? false) && (a.prefix ?? "") === (b.prefix ?? "");
381
- }
382
- function indexDefinitionsEqual(a, b) {
383
- if (Object.keys(a).length !== Object.keys(b).length) {
384
- return false;
385
- }
386
- for (const [aKey, aValue] of Object.entries(a)) {
387
- const bValue = b[aKey];
388
- if (!bValue || !indexDefinitionEqual(aValue, bValue)) {
389
- return false;
390
- }
391
- }
392
- return true;
393
- }
394
-
395
- // ../replicache/src/persist/client-groups.ts
396
- var clientGroupSchema = readonlyObject({
397
- /**
398
- * The hash of the commit in the perdag last persisted to this client group.
399
- * Should only be updated by clients assigned to this client group.
400
- */
401
- headHash: hashSchema,
402
- /**
403
- * Set of mutator names common to all clients assigned to this client group.
404
- */
405
- mutatorNames: readonlyArray(valita_exports.string()),
406
- /**
407
- * Index definitions common to all clients assigned to this client group.
408
- */
409
- indexes: indexDefinitionsSchema,
410
- /**
411
- * The highest mutation ID of every client assigned to this client group.
412
- * Should only be updated by clients assigned to this client group. Read by
413
- * other clients to determine if there are unacknowledged pending mutations
414
- * for them to try to recover. This is redundant with information in the
415
- * commit graph at `headHash`, but allows other clients to determine if there
416
- * are unacknowledged pending mutations without having to load the commit
417
- * graph.
418
- */
419
- mutationIDs: readonlyRecord(valita_exports.number()),
420
- /**
421
- * The highest lastMutationID received from the server for every client
422
- * assigned to this client group.
423
- *
424
- * Should be updated by the clients assigned to this client group whenever
425
- * they persist to this client group. Read by other clients to determine if
426
- * there are unacknowledged pending mutations for them to recover and
427
- * *updated* by other clients upon successfully recovering pending mutations
428
- * to avoid redundant pushes of pending mutations.
429
- *
430
- * Note: This will be the same as the `lastMutationIDs` of the base snapshot
431
- * of the client group's commit graph when written by clients assigned to this
432
- * client group. However, when written by another client recovering mutations
433
- * it may be different because the other client does not update the commit
434
- * graph.
435
- */
436
- lastServerAckdMutationIDs: valita_exports.record(valita_exports.number()),
437
- /**
438
- * If the server deletes this client group it can signal that the client group
439
- * was deleted. If that happens we mark this client group as disabled so that
440
- * we do not use it again when creating new clients.
441
- */
442
- disabled: valita_exports.boolean()
443
- });
444
- var CLIENT_GROUPS_HEAD_NAME = "client-groups";
445
- function assertClientGroup(value) {
446
- assert2(value, clientGroupSchema);
447
- }
448
- function chunkDataToClientGroupMap(chunkData) {
449
- assertObject(chunkData);
450
- const clientGroups = /* @__PURE__ */ new Map();
451
- for (const [key, value] of Object.entries(chunkData)) {
452
- if (value !== void 0) {
453
- assertClientGroup(value);
454
- clientGroups.set(key, value);
455
- }
456
- }
457
- return clientGroups;
458
- }
459
- function clientGroupMapToChunkData(clientGroups, dagWrite) {
460
- const chunkData = {};
461
- for (const [clientGroupID, clientGroup] of clientGroups.entries()) {
462
- dagWrite.assertValidHash(clientGroup.headHash);
463
- chunkData[clientGroupID] = {
464
- ...clientGroup,
465
- mutatorNames: [...clientGroup.mutatorNames.values()]
466
- };
467
- }
468
- return deepFreeze(chunkData);
469
- }
470
- async function getClientGroupsAtHash(hash2, dagRead) {
471
- const chunk = await dagRead.getChunk(hash2);
472
- return chunkDataToClientGroupMap(chunk?.data);
473
- }
474
- async function getClientGroups(dagRead) {
475
- const hash2 = await dagRead.getHead(CLIENT_GROUPS_HEAD_NAME);
476
- if (!hash2) {
477
- return /* @__PURE__ */ new Map();
478
- }
479
- return getClientGroupsAtHash(hash2, dagRead);
480
- }
481
- async function setClientGroups(clientGroups, dagWrite) {
482
- const currClientGroups = await getClientGroups(dagWrite);
483
- for (const [clientGroupID, clientGroup] of clientGroups) {
484
- const currClientGroup = currClientGroups.get(clientGroupID);
485
- validateClientGroupUpdate(clientGroup, currClientGroup);
486
- }
487
- return setValidatedClientGroups(clientGroups, dagWrite);
488
- }
489
- async function setClientGroup(clientGroupID, clientGroup, dagWrite) {
490
- const currClientGroups = await getClientGroups(dagWrite);
491
- const currClientGroup = currClientGroups.get(clientGroupID);
492
- validateClientGroupUpdate(clientGroup, currClientGroup);
493
- const newClientGroups = new Map(currClientGroups);
494
- newClientGroups.set(clientGroupID, clientGroup);
495
- return setValidatedClientGroups(newClientGroups, dagWrite);
496
- }
497
- function validateClientGroupUpdate(clientGroup, currClientGroup) {
498
- const mutatorNamesSet = new Set(clientGroup.mutatorNames);
499
- assert(
500
- mutatorNamesSet.size === clientGroup.mutatorNames.length,
501
- "A client group's mutatorNames must be a set."
502
- );
503
- if (currClientGroup !== void 0) {
504
- assert(
505
- indexDefinitionsEqual(currClientGroup.indexes, clientGroup.indexes),
506
- "A client group's index definitions must never change."
507
- );
508
- assert(
509
- mutatorNamesEqual(mutatorNamesSet, currClientGroup.mutatorNames),
510
- "A client group's mutatorNames must never change."
511
- );
512
- }
513
- }
514
- async function setValidatedClientGroups(clientGroups, dagWrite) {
515
- const chunkData = clientGroupMapToChunkData(clientGroups, dagWrite);
516
- const refs = /* @__PURE__ */ new Set();
517
- for (const clientGroup of clientGroups.values()) {
518
- refs.add(clientGroup.headHash);
519
- }
520
- const chunk = dagWrite.createChunk(chunkData, toRefs(refs));
521
- await dagWrite.putChunk(chunk);
522
- await dagWrite.setHead(CLIENT_GROUPS_HEAD_NAME, chunk.hash);
523
- return clientGroups;
524
- }
525
- function mutatorNamesEqual(mutatorNamesSet, mutatorNames) {
526
- if (mutatorNames.length !== mutatorNamesSet.size) {
527
- return false;
528
- }
529
- for (const mutatorName of mutatorNames) {
530
- if (!mutatorNamesSet.has(mutatorName)) {
531
- return false;
532
- }
533
- }
534
- return true;
535
- }
536
- async function getClientGroup(id, dagRead) {
537
- const clientGroups = await getClientGroups(dagRead);
538
- return clientGroups.get(id);
539
- }
540
- function clientGroupHasPendingMutations(clientGroup) {
541
- for (const [clientID, mutationID] of Object.entries(
542
- clientGroup.mutationIDs
543
- )) {
544
- const lastServerAckdMutationID = clientGroup.lastServerAckdMutationIDs[clientID];
545
- if (lastServerAckdMutationID === void 0 && mutationID !== 0 || lastServerAckdMutationID < mutationID) {
546
- return true;
547
- }
548
- }
549
- return false;
550
- }
551
- async function disableClientGroup(clientGroupID, dagWrite) {
552
- const clientGroup = await getClientGroup(clientGroupID, dagWrite);
553
- if (!clientGroup) {
554
- return;
555
- }
556
- const disabledClientGroup = {
557
- ...clientGroup,
558
- disabled: true
559
- };
560
- await setClientGroup(clientGroupID, disabledClientGroup, dagWrite);
561
- }
562
-
563
- // ../shared/src/json.ts
564
- function deepEqual(a, b) {
565
- if (a === b) {
566
- return true;
567
- }
568
- if (typeof a !== typeof b) {
569
- return false;
570
- }
571
- switch (typeof a) {
572
- case "boolean":
573
- case "number":
574
- case "string":
575
- return false;
576
- }
577
- a = a;
578
- if (Array.isArray(a)) {
579
- if (!Array.isArray(b)) {
580
- return false;
581
- }
582
- if (a.length !== b.length) {
583
- return false;
584
- }
585
- for (let i = 0; i < a.length; i++) {
586
- if (!deepEqual(a[i], b[i])) {
587
- return false;
588
- }
589
- }
590
- return true;
591
- }
592
- if (a === null || b === null) {
593
- return false;
594
- }
595
- if (Array.isArray(b)) {
596
- return false;
597
- }
598
- a = a;
599
- b = b;
600
- let aSize = 0;
601
- for (const key in a) {
602
- if (hasOwn(a, key)) {
603
- if (!deepEqual(a[key], b[key])) {
604
- return false;
605
- }
606
- aSize++;
607
- }
608
- }
609
- let bSize = 0;
610
- for (const key in b) {
611
- if (hasOwn(b, key)) {
612
- bSize++;
613
- }
614
- }
615
- return aSize === bSize;
616
- }
617
- function assertJSONValue(v2) {
618
- if (isProd) {
619
- return;
620
- }
621
- switch (typeof v2) {
622
- case "boolean":
623
- case "number":
624
- case "string":
625
- return;
626
- case "object":
627
- if (v2 === null) {
628
- return;
629
- }
630
- if (Array.isArray(v2)) {
631
- return assertJSONArray(v2);
632
- }
633
- return assertObjectIsJSONObject(v2);
634
- }
635
- throwInvalidType(v2, "JSON value");
636
- }
637
- function assertJSONObject(v2) {
638
- assertObject(v2);
639
- assertObjectIsJSONObject(v2);
640
- }
641
- function assertObjectIsJSONObject(v2) {
642
- for (const k in v2) {
643
- if (hasOwn(v2, k)) {
644
- const value = v2[k];
645
- if (value !== void 0) {
646
- assertJSONValue(value);
647
- }
648
- }
649
- }
650
- }
651
- function assertJSONArray(v2) {
652
- for (const item of v2) {
653
- assertJSONValue(item);
654
- }
655
- }
656
- function isJSONValue(v2, path2) {
657
- switch (typeof v2) {
658
- case "boolean":
659
- case "number":
660
- case "string":
661
- return true;
662
- case "object":
663
- if (v2 === null) {
664
- return true;
665
- }
666
- if (Array.isArray(v2)) {
667
- return isJSONArray(v2, path2);
668
- }
669
- return objectIsJSONObject(v2, path2);
670
- }
671
- return false;
672
- }
673
- function isJSONObject(v2, path2) {
674
- if (typeof v2 !== "object" || v2 === null) {
675
- return false;
676
- }
677
- return objectIsJSONObject(v2, path2);
678
- }
679
- function objectIsJSONObject(v2, path2) {
680
- for (const k in v2) {
681
- if (hasOwn(v2, k)) {
682
- path2.push(k);
683
- const value = v2[k];
684
- if (value !== void 0 && !isJSONValue(value, path2)) {
685
- return false;
686
- }
687
- path2.pop();
688
- }
689
- }
690
- return true;
691
- }
692
- function isJSONArray(v2, path2) {
693
- for (let i = 0; i < v2.length; i++) {
694
- path2.push(i);
695
- if (!isJSONValue(v2[i], path2)) {
696
- return false;
697
- }
698
- path2.pop();
699
- }
700
- return true;
701
- }
702
-
703
414
  // ../replicache/src/size-of-value.ts
704
415
  var SIZE_TAG = 1;
705
416
  var SIZE_INT32 = 4;
@@ -965,13 +676,13 @@ var DataNodeImpl = class extends NodeImpl {
965
676
  }
966
677
  }
967
678
  };
968
- function readonlySplice(array6, start, deleteCount, ...items) {
969
- const arr = array6.slice(0, start);
679
+ function readonlySplice(array7, start, deleteCount, ...items) {
680
+ const arr = array7.slice(0, start);
970
681
  for (let i = 0; i < items.length; i++) {
971
682
  arr.push(items[i]);
972
683
  }
973
- for (let i = start + deleteCount; i < array6.length; i++) {
974
- arr.push(array6[i]);
684
+ for (let i = start + deleteCount; i < array7.length; i++) {
685
+ arr.push(array7[i]);
975
686
  }
976
687
  return arr;
977
688
  }
@@ -1551,28 +1262,101 @@ function compareCookies(a, b) {
1551
1262
  if (b === null) {
1552
1263
  return 1;
1553
1264
  }
1554
- const cva = getCompareValue(a);
1555
- const cvb = getCompareValue(b);
1556
- if (typeof cva === "string" || typeof cvb === "string") {
1557
- return stringCompare(String(cva), String(cvb));
1265
+ const cva = getCompareValue(a);
1266
+ const cvb = getCompareValue(b);
1267
+ if (typeof cva === "string" || typeof cvb === "string") {
1268
+ return stringCompare(String(cva), String(cvb));
1269
+ }
1270
+ return cva - cvb;
1271
+ }
1272
+ function getCompareValue(cookie) {
1273
+ if (typeof cookie === "string" || typeof cookie === "number") {
1274
+ return cookie;
1275
+ }
1276
+ return cookie.order;
1277
+ }
1278
+ function assertCookie(v2) {
1279
+ if (v2 === null || typeof v2 === "string" || typeof v2 === "number") {
1280
+ return;
1281
+ }
1282
+ assertJSONObject(v2);
1283
+ if (typeof v2.order === "string" || typeof v2.order === "number") {
1284
+ return;
1285
+ }
1286
+ throw new Error("Invalid cookie");
1287
+ }
1288
+
1289
+ // ../replicache/src/dag/chunk.ts
1290
+ function asRefs(sortedRefs) {
1291
+ return sortedRefs;
1292
+ }
1293
+ function toRefs(refs) {
1294
+ if (Array.isArray(refs)) {
1295
+ refs.sort();
1296
+ for (let i = 1; i < refs.length; i++) {
1297
+ assert(refs[i - 1] !== refs[i], "Refs must not have duplicates");
1298
+ }
1299
+ return asRefs(refs);
1300
+ }
1301
+ const refsArray = [...refs];
1302
+ refsArray.sort();
1303
+ return asRefs(refsArray);
1304
+ }
1305
+ var Chunk = class {
1306
+ hash;
1307
+ data;
1308
+ /**
1309
+ * Meta is an array of refs. If there are no refs we do not write a meta
1310
+ * chunk.
1311
+ */
1312
+ meta;
1313
+ constructor(hash2, data, refs) {
1314
+ assert(
1315
+ !refs.includes(hash2),
1316
+ "Chunk cannot reference itself"
1317
+ );
1318
+ assertDeepFrozen(data);
1319
+ this.hash = hash2;
1320
+ this.data = data;
1321
+ this.meta = refs;
1322
+ }
1323
+ };
1324
+ function assertRefs(v2) {
1325
+ if (!Array.isArray(v2)) {
1326
+ throw new Error("Refs must be an array");
1327
+ }
1328
+ if (v2.length > 0) {
1329
+ assertString(v2[0]);
1330
+ for (let i = 1; i < v2.length; i++) {
1331
+ assertString(v2[i]);
1332
+ }
1558
1333
  }
1559
- return cva - cvb;
1560
1334
  }
1561
- function getCompareValue(cookie) {
1562
- if (typeof cookie === "string" || typeof cookie === "number") {
1563
- return cookie;
1564
- }
1565
- return cookie.order;
1335
+ function createChunk(data, refs, chunkHasher) {
1336
+ const hash2 = chunkHasher();
1337
+ return new Chunk(hash2, data, refs);
1566
1338
  }
1567
- function assertCookie(v2) {
1568
- if (v2 === null || typeof v2 === "string" || typeof v2 === "number") {
1569
- return;
1339
+
1340
+ // ../replicache/src/dag/store.ts
1341
+ var ChunkNotFoundError = class extends Error {
1342
+ name = "ChunkNotFoundError";
1343
+ hash;
1344
+ constructor(hash2) {
1345
+ super(`Chunk not found ${hash2}`);
1346
+ this.hash = hash2;
1570
1347
  }
1571
- assertJSONObject(v2);
1572
- if (typeof v2.order === "string" || typeof v2.order === "number") {
1573
- return;
1348
+ };
1349
+ async function mustGetChunk(store, hash2) {
1350
+ const chunk = await store.getChunk(hash2);
1351
+ if (chunk) {
1352
+ return chunk;
1574
1353
  }
1575
- throw new Error("Invalid cookie");
1354
+ throw new ChunkNotFoundError(hash2);
1355
+ }
1356
+ async function mustGetHeadHash(name, store) {
1357
+ const hash2 = await store.getHead(name);
1358
+ assert(hash2, `Missing head ${name}`);
1359
+ return hash2;
1576
1360
  }
1577
1361
 
1578
1362
  // ../replicache/src/db/meta-type-enum.ts
@@ -2035,54 +1819,270 @@ var Read = class {
2035
1819
  has(key) {
2036
1820
  return this.map.has(key);
2037
1821
  }
2038
- get(key) {
2039
- return this.map.get(key);
1822
+ get(key) {
1823
+ return this.map.get(key);
1824
+ }
1825
+ isEmpty() {
1826
+ return this.map.isEmpty();
1827
+ }
1828
+ getMapForIndex(indexName) {
1829
+ const idx = this.indexes.get(indexName);
1830
+ if (idx === void 0) {
1831
+ throw new Error(`Unknown index name: ${indexName}`);
1832
+ }
1833
+ return idx.map;
1834
+ }
1835
+ get closed() {
1836
+ return this.#dagRead.closed;
1837
+ }
1838
+ close() {
1839
+ this.#dagRead.release();
1840
+ }
1841
+ };
1842
+ function readFromDefaultHead(dagRead, formatVersion) {
1843
+ return readFromHead(DEFAULT_HEAD_NAME, dagRead, formatVersion);
1844
+ }
1845
+ async function readFromHead(name, dagRead, formatVersion) {
1846
+ const commit = await commitFromHead(name, dagRead);
1847
+ return readFromCommit(commit, dagRead, formatVersion);
1848
+ }
1849
+ async function readFromHash(hash2, dagRead, formatVersion) {
1850
+ const commit = await commitFromHash(hash2, dagRead);
1851
+ return readFromCommit(commit, dagRead, formatVersion);
1852
+ }
1853
+ function readFromCommit(commit, dagRead, formatVersion) {
1854
+ const indexes = readIndexesForRead(commit, dagRead, formatVersion);
1855
+ const map = new BTreeRead(dagRead, formatVersion, commit.valueHash);
1856
+ return new Read(dagRead, map, indexes);
1857
+ }
1858
+ function readIndexesForRead(commit, dagRead, formatVersion) {
1859
+ const m = /* @__PURE__ */ new Map();
1860
+ for (const index of commit.indexes) {
1861
+ m.set(
1862
+ index.definition.name,
1863
+ new IndexRead(
1864
+ index,
1865
+ new BTreeRead(dagRead, formatVersion, index.valueHash)
1866
+ )
1867
+ );
1868
+ }
1869
+ return m;
1870
+ }
1871
+
1872
+ // ../replicache/src/with-transactions.ts
1873
+ function withRead(store, fn) {
1874
+ return using(store.read(), fn);
1875
+ }
1876
+ function withWriteNoImplicitCommit(store, fn) {
1877
+ return using(store.write(), fn);
1878
+ }
1879
+ function withWrite(store, fn) {
1880
+ return using(store.write(), async (write) => {
1881
+ const result = await fn(write);
1882
+ await write.commit();
1883
+ return result;
1884
+ });
1885
+ }
1886
+ async function using(x, fn) {
1887
+ const write = await x;
1888
+ try {
1889
+ return await fn(write);
1890
+ } finally {
1891
+ write.release();
1892
+ }
1893
+ }
1894
+
1895
+ // ../replicache/src/index-defs.ts
1896
+ var indexDefinitionSchema = readonlyObject({
1897
+ prefix: valita_exports.string().optional(),
1898
+ jsonPointer: valita_exports.string(),
1899
+ allowEmpty: valita_exports.boolean().optional()
1900
+ });
1901
+ var indexDefinitionsSchema = readonlyRecord(
1902
+ indexDefinitionSchema
1903
+ );
1904
+ function indexDefinitionEqual(a, b) {
1905
+ return a.jsonPointer === b.jsonPointer && (a.allowEmpty ?? false) === (b.allowEmpty ?? false) && (a.prefix ?? "") === (b.prefix ?? "");
1906
+ }
1907
+ function indexDefinitionsEqual(a, b) {
1908
+ if (Object.keys(a).length !== Object.keys(b).length) {
1909
+ return false;
1910
+ }
1911
+ for (const [aKey, aValue] of Object.entries(a)) {
1912
+ const bValue = b[aKey];
1913
+ if (!bValue || !indexDefinitionEqual(aValue, bValue)) {
1914
+ return false;
1915
+ }
1916
+ }
1917
+ return true;
1918
+ }
1919
+
1920
+ // ../replicache/src/persist/client-groups.ts
1921
+ var clientGroupSchema = readonlyObject({
1922
+ /**
1923
+ * The hash of the commit in the perdag last persisted to this client group.
1924
+ * Should only be updated by clients assigned to this client group.
1925
+ */
1926
+ headHash: hashSchema,
1927
+ /**
1928
+ * Set of mutator names common to all clients assigned to this client group.
1929
+ */
1930
+ mutatorNames: readonlyArray(valita_exports.string()),
1931
+ /**
1932
+ * Index definitions common to all clients assigned to this client group.
1933
+ */
1934
+ indexes: indexDefinitionsSchema,
1935
+ /**
1936
+ * The highest mutation ID of every client assigned to this client group.
1937
+ * Should only be updated by clients assigned to this client group. Read by
1938
+ * other clients to determine if there are unacknowledged pending mutations
1939
+ * for them to try to recover. This is redundant with information in the
1940
+ * commit graph at `headHash`, but allows other clients to determine if there
1941
+ * are unacknowledged pending mutations without having to load the commit
1942
+ * graph.
1943
+ */
1944
+ mutationIDs: readonlyRecord(valita_exports.number()),
1945
+ /**
1946
+ * The highest lastMutationID received from the server for every client
1947
+ * assigned to this client group.
1948
+ *
1949
+ * Should be updated by the clients assigned to this client group whenever
1950
+ * they persist to this client group. Read by other clients to determine if
1951
+ * there are unacknowledged pending mutations for them to recover and
1952
+ * *updated* by other clients upon successfully recovering pending mutations
1953
+ * to avoid redundant pushes of pending mutations.
1954
+ *
1955
+ * Note: This will be the same as the `lastMutationIDs` of the base snapshot
1956
+ * of the client group's commit graph when written by clients assigned to this
1957
+ * client group. However, when written by another client recovering mutations
1958
+ * it may be different because the other client does not update the commit
1959
+ * graph.
1960
+ */
1961
+ lastServerAckdMutationIDs: valita_exports.record(valita_exports.number()),
1962
+ /**
1963
+ * If the server deletes this client group it can signal that the client group
1964
+ * was deleted. If that happens we mark this client group as disabled so that
1965
+ * we do not use it again when creating new clients.
1966
+ */
1967
+ disabled: valita_exports.boolean()
1968
+ });
1969
+ var CLIENT_GROUPS_HEAD_NAME = "client-groups";
1970
+ function assertClientGroup(value) {
1971
+ assert2(value, clientGroupSchema);
1972
+ }
1973
+ function chunkDataToClientGroupMap(chunkData) {
1974
+ assertObject(chunkData);
1975
+ const clientGroups = /* @__PURE__ */ new Map();
1976
+ for (const [key, value] of Object.entries(chunkData)) {
1977
+ if (value !== void 0) {
1978
+ assertClientGroup(value);
1979
+ clientGroups.set(key, value);
1980
+ }
1981
+ }
1982
+ return clientGroups;
1983
+ }
1984
+ function clientGroupMapToChunkData(clientGroups, dagWrite) {
1985
+ const chunkData = {};
1986
+ for (const [clientGroupID, clientGroup] of clientGroups.entries()) {
1987
+ dagWrite.assertValidHash(clientGroup.headHash);
1988
+ chunkData[clientGroupID] = {
1989
+ ...clientGroup,
1990
+ mutatorNames: [...clientGroup.mutatorNames.values()]
1991
+ };
1992
+ }
1993
+ return deepFreeze(chunkData);
1994
+ }
1995
+ async function getClientGroupsAtHash(hash2, dagRead) {
1996
+ const chunk = await dagRead.getChunk(hash2);
1997
+ return chunkDataToClientGroupMap(chunk?.data);
1998
+ }
1999
+ async function getClientGroups(dagRead) {
2000
+ const hash2 = await dagRead.getHead(CLIENT_GROUPS_HEAD_NAME);
2001
+ if (!hash2) {
2002
+ return /* @__PURE__ */ new Map();
2003
+ }
2004
+ return getClientGroupsAtHash(hash2, dagRead);
2005
+ }
2006
+ async function setClientGroups(clientGroups, dagWrite) {
2007
+ const currClientGroups = await getClientGroups(dagWrite);
2008
+ for (const [clientGroupID, clientGroup] of clientGroups) {
2009
+ const currClientGroup = currClientGroups.get(clientGroupID);
2010
+ validateClientGroupUpdate(clientGroup, currClientGroup);
2011
+ }
2012
+ return setValidatedClientGroups(clientGroups, dagWrite);
2013
+ }
2014
+ async function setClientGroup(clientGroupID, clientGroup, dagWrite) {
2015
+ const currClientGroups = await getClientGroups(dagWrite);
2016
+ const currClientGroup = currClientGroups.get(clientGroupID);
2017
+ validateClientGroupUpdate(clientGroup, currClientGroup);
2018
+ const newClientGroups = new Map(currClientGroups);
2019
+ newClientGroups.set(clientGroupID, clientGroup);
2020
+ return setValidatedClientGroups(newClientGroups, dagWrite);
2021
+ }
2022
+ function validateClientGroupUpdate(clientGroup, currClientGroup) {
2023
+ const mutatorNamesSet = new Set(clientGroup.mutatorNames);
2024
+ assert(
2025
+ mutatorNamesSet.size === clientGroup.mutatorNames.length,
2026
+ "A client group's mutatorNames must be a set."
2027
+ );
2028
+ if (currClientGroup !== void 0) {
2029
+ assert(
2030
+ indexDefinitionsEqual(currClientGroup.indexes, clientGroup.indexes),
2031
+ "A client group's index definitions must never change."
2032
+ );
2033
+ assert(
2034
+ mutatorNamesEqual(mutatorNamesSet, currClientGroup.mutatorNames),
2035
+ "A client group's mutatorNames must never change."
2036
+ );
2037
+ }
2038
+ }
2039
+ async function setValidatedClientGroups(clientGroups, dagWrite) {
2040
+ const chunkData = clientGroupMapToChunkData(clientGroups, dagWrite);
2041
+ const refs = /* @__PURE__ */ new Set();
2042
+ for (const clientGroup of clientGroups.values()) {
2043
+ refs.add(clientGroup.headHash);
2040
2044
  }
2041
- isEmpty() {
2042
- return this.map.isEmpty();
2045
+ const chunk = dagWrite.createChunk(chunkData, toRefs(refs));
2046
+ await dagWrite.putChunk(chunk);
2047
+ await dagWrite.setHead(CLIENT_GROUPS_HEAD_NAME, chunk.hash);
2048
+ return clientGroups;
2049
+ }
2050
+ function mutatorNamesEqual(mutatorNamesSet, mutatorNames) {
2051
+ if (mutatorNames.length !== mutatorNamesSet.size) {
2052
+ return false;
2043
2053
  }
2044
- getMapForIndex(indexName) {
2045
- const idx = this.indexes.get(indexName);
2046
- if (idx === void 0) {
2047
- throw new Error(`Unknown index name: ${indexName}`);
2054
+ for (const mutatorName of mutatorNames) {
2055
+ if (!mutatorNamesSet.has(mutatorName)) {
2056
+ return false;
2048
2057
  }
2049
- return idx.map;
2050
- }
2051
- get closed() {
2052
- return this.#dagRead.closed;
2053
- }
2054
- close() {
2055
- this.#dagRead.release();
2056
2058
  }
2057
- };
2058
- function readFromDefaultHead(dagRead, formatVersion) {
2059
- return readFromHead(DEFAULT_HEAD_NAME, dagRead, formatVersion);
2060
- }
2061
- async function readFromHead(name, dagRead, formatVersion) {
2062
- const commit = await commitFromHead(name, dagRead);
2063
- return readFromCommit(commit, dagRead, formatVersion);
2059
+ return true;
2064
2060
  }
2065
- async function readFromHash(hash2, dagRead, formatVersion) {
2066
- const commit = await commitFromHash(hash2, dagRead);
2067
- return readFromCommit(commit, dagRead, formatVersion);
2061
+ async function getClientGroup(id, dagRead) {
2062
+ const clientGroups = await getClientGroups(dagRead);
2063
+ return clientGroups.get(id);
2068
2064
  }
2069
- function readFromCommit(commit, dagRead, formatVersion) {
2070
- const indexes = readIndexesForRead(commit, dagRead, formatVersion);
2071
- const map = new BTreeRead(dagRead, formatVersion, commit.valueHash);
2072
- return new Read(dagRead, map, indexes);
2065
+ function clientGroupHasPendingMutations(clientGroup) {
2066
+ for (const [clientID, mutationID] of Object.entries(
2067
+ clientGroup.mutationIDs
2068
+ )) {
2069
+ const lastServerAckdMutationID = clientGroup.lastServerAckdMutationIDs[clientID];
2070
+ if (lastServerAckdMutationID === void 0 && mutationID !== 0 || lastServerAckdMutationID < mutationID) {
2071
+ return true;
2072
+ }
2073
+ }
2074
+ return false;
2073
2075
  }
2074
- function readIndexesForRead(commit, dagRead, formatVersion) {
2075
- const m = /* @__PURE__ */ new Map();
2076
- for (const index of commit.indexes) {
2077
- m.set(
2078
- index.definition.name,
2079
- new IndexRead(
2080
- index,
2081
- new BTreeRead(dagRead, formatVersion, index.valueHash)
2082
- )
2083
- );
2076
+ async function disableClientGroup(clientGroupID, dagWrite) {
2077
+ const clientGroup = await getClientGroup(clientGroupID, dagWrite);
2078
+ if (!clientGroup) {
2079
+ return;
2084
2080
  }
2085
- return m;
2081
+ const disabledClientGroup = {
2082
+ ...clientGroup,
2083
+ disabled: true
2084
+ };
2085
+ await setClientGroup(clientGroupID, disabledClientGroup, dagWrite);
2086
2086
  }
2087
2087
 
2088
2088
  // ../replicache/src/async-iterable-to-array.ts
@@ -3290,73 +3290,6 @@ function makeID(row, schema) {
3290
3290
  return JSON.stringify(schema.primaryKey.map((k) => row[k]));
3291
3291
  }
3292
3292
 
3293
- // ../zql/src/query/ttl.ts
3294
- var DEFAULT_TTL_MS = 1e3 * 60 * 5;
3295
- var DEFAULT_PRELOAD_TTL_MS = 0;
3296
- var MAX_TTL = "10m";
3297
- var MAX_TTL_MS = 1e3 * 60 * 10;
3298
- var multiplier = {
3299
- s: 1e3,
3300
- m: 60 * 1e3,
3301
- h: 60 * 60 * 1e3,
3302
- d: 24 * 60 * 60 * 1e3,
3303
- y: 365 * 24 * 60 * 60 * 1e3
3304
- };
3305
- function parseTTL(ttl) {
3306
- if (typeof ttl === "number") {
3307
- return Number.isNaN(ttl) ? 0 : !Number.isFinite(ttl) || ttl < 0 ? -1 : ttl;
3308
- }
3309
- if (ttl === "none") {
3310
- return 0;
3311
- }
3312
- if (ttl === "forever") {
3313
- return -1;
3314
- }
3315
- const multi = multiplier[ttl[ttl.length - 1]];
3316
- return Number(ttl.slice(0, -1)) * multi;
3317
- }
3318
- function compareTTL(a, b) {
3319
- const ap = parseTTL(a);
3320
- const bp = parseTTL(b);
3321
- if (ap === -1 && bp !== -1) {
3322
- return 1;
3323
- }
3324
- if (ap !== -1 && bp === -1) {
3325
- return -1;
3326
- }
3327
- return ap - bp;
3328
- }
3329
- function normalizeTTL(ttl) {
3330
- if (typeof ttl === "string") {
3331
- return ttl;
3332
- }
3333
- if (ttl < 0) {
3334
- return "forever";
3335
- }
3336
- if (ttl === 0) {
3337
- return "none";
3338
- }
3339
- let shortest = ttl.toString();
3340
- const lengthOfNumber = shortest.length;
3341
- for (const unit of ["y", "d", "h", "m", "s"]) {
3342
- const multi = multiplier[unit];
3343
- const value = ttl / multi;
3344
- const candidate = `${value}${unit}`;
3345
- if (candidate.length < shortest.length) {
3346
- shortest = candidate;
3347
- }
3348
- }
3349
- return shortest.length < lengthOfNumber ? shortest : ttl;
3350
- }
3351
- function clampTTL(ttl, lc) {
3352
- const parsedTTL = parseTTL(ttl);
3353
- if (parsedTTL === -1 || parsedTTL > 10 * 60 * 1e3) {
3354
- lc?.warn?.(`TTL (${ttl}) is too high, clamping to ${MAX_TTL}`);
3355
- return parseTTL(MAX_TTL);
3356
- }
3357
- return parsedTTL;
3358
- }
3359
-
3360
3293
  // ../shared/src/json-schema.ts
3361
3294
  import * as valita from "@badrap/valita";
3362
3295
  var path = [];
@@ -3386,6 +3319,27 @@ var jsonObjectSchema = valita_exports.unknown().chain((v2) => {
3386
3319
  // ../shared/src/tdigest-schema.ts
3387
3320
  var tdigestSchema = valita_exports.tuple([valita_exports.number()]).concat(valita_exports.array(valita_exports.number()));
3388
3321
 
3322
+ // ../zero-protocol/src/data.ts
3323
+ var valueSchema = valita_exports.union(jsonSchema, valita_exports.undefined());
3324
+ var rowSchema = readonlyRecord(valueSchema);
3325
+
3326
+ // ../zero-protocol/src/analyze-query-result.ts
3327
+ var rowCountsByQuerySchema = valita_exports.record(valita_exports.number());
3328
+ var rowCountsBySourceSchema = valita_exports.record(rowCountsByQuerySchema);
3329
+ var rowsByQuerySchema = valita_exports.record(valita_exports.array(rowSchema));
3330
+ var rowsBySourceSchema = valita_exports.record(rowsByQuerySchema);
3331
+ var analyzeQueryResultSchema = valita_exports.object({
3332
+ warnings: valita_exports.array(valita_exports.string()),
3333
+ syncedRows: valita_exports.record(valita_exports.array(rowSchema)).optional(),
3334
+ syncedRowCount: valita_exports.number(),
3335
+ start: valita_exports.number(),
3336
+ end: valita_exports.number(),
3337
+ afterPermissions: valita_exports.string().optional(),
3338
+ vendedRowCounts: rowCountsBySourceSchema.optional(),
3339
+ vendedRows: rowsBySourceSchema.optional(),
3340
+ plans: valita_exports.record(valita_exports.array(valita_exports.string())).optional()
3341
+ });
3342
+
3389
3343
  // ../zero-protocol/src/ast.ts
3390
3344
  import { compareUTF8 as compareUTF83 } from "compare-utf8";
3391
3345
 
@@ -3408,10 +3362,6 @@ function areEqual(arr1, arr2) {
3408
3362
  return arr1.length === arr2.length && arr1.every((e, i) => e === arr2[i]);
3409
3363
  }
3410
3364
 
3411
- // ../zero-protocol/src/data.ts
3412
- var valueSchema = valita_exports.union(jsonSchema, valita_exports.undefined());
3413
- var rowSchema = readonlyRecord(valueSchema);
3414
-
3415
3365
  // ../zero-protocol/src/ast.ts
3416
3366
  var selectorSchema = valita_exports.string();
3417
3367
  var toStaticParam = Symbol();
@@ -3509,7 +3459,8 @@ var correlationSchema = readonlyObject({
3509
3459
  var correlatedSubquerySchemaOmitSubquery = readonlyObject({
3510
3460
  correlation: correlationSchema,
3511
3461
  hidden: valita_exports.boolean().optional(),
3512
- system: literalUnion("permissions", "client", "test").optional()
3462
+ system: literalUnion("permissions", "client", "test").optional(),
3463
+ flip: valita_exports.boolean().optional()
3513
3464
  });
3514
3465
  var correlatedSubquerySchema = correlatedSubquerySchemaOmitSubquery.extend({
3515
3466
  subquery: valita_exports.lazy(() => astSchema)
@@ -3549,7 +3500,8 @@ function transformAST(ast, transform) {
3549
3500
  },
3550
3501
  hidden: r.hidden,
3551
3502
  subquery: transformAST(r.subquery, transform),
3552
- system: r.system
3503
+ system: r.system,
3504
+ flip: r.flip
3553
3505
  })
3554
3506
  )
3555
3507
  ) : void 0,
@@ -3756,10 +3708,20 @@ var inspectVersionDownSchema = inspectBaseDownSchema.extend({
3756
3708
  op: valita_exports.literal("version"),
3757
3709
  value: valita_exports.string()
3758
3710
  });
3711
+ var inspectAuthenticatedDownSchema = inspectBaseDownSchema.extend({
3712
+ op: valita_exports.literal("authenticated"),
3713
+ value: valita_exports.boolean()
3714
+ });
3715
+ var inspectAnalyzeQueryDownSchema = inspectBaseDownSchema.extend({
3716
+ op: valita_exports.literal("analyze-query"),
3717
+ value: analyzeQueryResultSchema
3718
+ });
3759
3719
  var inspectDownBodySchema = valita_exports.union(
3760
3720
  inspectQueriesDownSchema,
3761
3721
  inspectMetricsDownSchema,
3762
- inspectVersionDownSchema
3722
+ inspectVersionDownSchema,
3723
+ inspectAuthenticatedDownSchema,
3724
+ inspectAnalyzeQueryDownSchema
3763
3725
  );
3764
3726
  var inspectDownMessageSchema = valita_exports.tuple([
3765
3727
  valita_exports.literal("inspect"),
@@ -3767,14 +3729,14 @@ var inspectDownMessageSchema = valita_exports.tuple([
3767
3729
  ]);
3768
3730
 
3769
3731
  // ../shared/src/random-values.ts
3770
- function getNonCryptoRandomValues(array6) {
3771
- if (array6 === null) {
3732
+ function getNonCryptoRandomValues(array7) {
3733
+ if (array7 === null) {
3772
3734
  throw new TypeError("array cannot be null");
3773
3735
  }
3774
- for (let i = 0; i < array6.length; i++) {
3775
- array6[i] = Math.floor(Math.random() * 256);
3736
+ for (let i = 0; i < array7.length; i++) {
3737
+ array7[i] = Math.floor(Math.random() * 256);
3776
3738
  }
3777
- return array6;
3739
+ return array7;
3778
3740
  }
3779
3741
 
3780
3742
  // ../zero-client/src/util/nanoid.ts
@@ -3851,6 +3813,56 @@ function sourceNameFromKey(key) {
3851
3813
  return key.slice(ENTITIES_KEY_PREFIX.length, slash);
3852
3814
  }
3853
3815
 
3816
+ // ../zero-client/src/client/inspector/client-group.ts
3817
+ var ClientGroup = class {
3818
+ #delegate;
3819
+ id;
3820
+ constructor(delegate, clientGroupID) {
3821
+ this.#delegate = delegate;
3822
+ this.id = clientGroupID;
3823
+ }
3824
+ async clients() {
3825
+ return (await this.#delegate.lazy).clientGroupClients(
3826
+ this.#delegate,
3827
+ this.id
3828
+ );
3829
+ }
3830
+ async clientsWithQueries() {
3831
+ return (await this.#delegate.lazy).clientGroupClientsWithQueries(
3832
+ this.#delegate,
3833
+ this.id
3834
+ );
3835
+ }
3836
+ async queries() {
3837
+ return (await this.#delegate.lazy).clientGroupQueries(this.#delegate);
3838
+ }
3839
+ };
3840
+
3841
+ // ../zero-client/src/client/inspector/client.ts
3842
+ var Client = class {
3843
+ #delegate;
3844
+ id;
3845
+ clientGroup;
3846
+ constructor(delegate, clientID, clientGroupID) {
3847
+ this.#delegate = delegate;
3848
+ this.id = clientID;
3849
+ this.clientGroup = new ClientGroup(this.#delegate, clientGroupID);
3850
+ }
3851
+ async queries() {
3852
+ return (await this.#delegate.lazy).clientQueries(this.#delegate, this.id);
3853
+ }
3854
+ async map() {
3855
+ return (await this.#delegate.lazy).clientMap(this.#delegate, this.id);
3856
+ }
3857
+ async rows(tableName) {
3858
+ return (await this.#delegate.lazy).clientRows(
3859
+ this.#delegate,
3860
+ this.id,
3861
+ tableName
3862
+ );
3863
+ }
3864
+ };
3865
+
3854
3866
  // ../shared/src/centroid.ts
3855
3867
  var Centroid = class {
3856
3868
  mean;
@@ -4154,17 +4166,128 @@ function unprocessedSize(size, compression) {
4154
4166
  return size;
4155
4167
  }
4156
4168
 
4169
+ // ../zero-client/src/client/inspector/inspector.ts
4170
+ var Inspector = class {
4171
+ #delegate;
4172
+ client;
4173
+ clientGroup;
4174
+ constructor(rep, delegate, getSocket) {
4175
+ this.#delegate = {
4176
+ getQueryMetrics: delegate.getQueryMetrics.bind(delegate),
4177
+ getAST: delegate.getAST.bind(delegate),
4178
+ get metrics() {
4179
+ return delegate.metrics;
4180
+ },
4181
+ rep,
4182
+ getSocket,
4183
+ lazy: import("./lazy-inspector-TOTYUTBC.js")
4184
+ };
4185
+ this.client = new Client(this.#delegate, rep.clientID, rep.clientGroupID);
4186
+ this.clientGroup = this.client.clientGroup;
4187
+ }
4188
+ async metrics() {
4189
+ return (await this.#delegate.lazy).inspectorMetrics(this.#delegate);
4190
+ }
4191
+ async clients() {
4192
+ return (await this.#delegate.lazy).inspectorClients(this.#delegate);
4193
+ }
4194
+ async clientsWithQueries() {
4195
+ return (await this.#delegate.lazy).inspectorClientsWithQueries(
4196
+ this.#delegate
4197
+ );
4198
+ }
4199
+ async serverVersion() {
4200
+ return (await this.#delegate.lazy).serverVersion(this.#delegate);
4201
+ }
4202
+ };
4203
+
4157
4204
  // ../zero-schema/src/table-schema.ts
4158
4205
  function isOneHop(r) {
4159
4206
  return r.length === 1;
4160
4207
  }
4161
- function isTwoHop(r) {
4162
- return r.length === 2;
4208
+ function isTwoHop(r) {
4209
+ return r.length === 2;
4210
+ }
4211
+
4212
+ // ../shared/src/sentinels.ts
4213
+ function emptyFunction() {
4214
+ }
4215
+ var emptyObject = Object.freeze({});
4216
+ var emptyArray = Object.freeze([]);
4217
+ function identity(x) {
4218
+ return x;
4219
+ }
4220
+
4221
+ // ../zql/src/query/query.ts
4222
+ var delegateSymbol = Symbol("delegate");
4223
+
4224
+ // ../zql/src/query/ttl.ts
4225
+ var DEFAULT_TTL_MS = 1e3 * 60 * 5;
4226
+ var DEFAULT_PRELOAD_TTL_MS = 0;
4227
+ var MAX_TTL = "10m";
4228
+ var MAX_TTL_MS = 1e3 * 60 * 10;
4229
+ var multiplier = {
4230
+ s: 1e3,
4231
+ m: 60 * 1e3,
4232
+ h: 60 * 60 * 1e3,
4233
+ d: 24 * 60 * 60 * 1e3,
4234
+ y: 365 * 24 * 60 * 60 * 1e3
4235
+ };
4236
+ function parseTTL(ttl) {
4237
+ if (typeof ttl === "number") {
4238
+ return Number.isNaN(ttl) ? 0 : !Number.isFinite(ttl) || ttl < 0 ? -1 : ttl;
4239
+ }
4240
+ if (ttl === "none") {
4241
+ return 0;
4242
+ }
4243
+ if (ttl === "forever") {
4244
+ return -1;
4245
+ }
4246
+ const multi = multiplier[ttl[ttl.length - 1]];
4247
+ return Number(ttl.slice(0, -1)) * multi;
4248
+ }
4249
+ function compareTTL(a, b) {
4250
+ const ap = parseTTL(a);
4251
+ const bp = parseTTL(b);
4252
+ if (ap === -1 && bp !== -1) {
4253
+ return 1;
4254
+ }
4255
+ if (ap !== -1 && bp === -1) {
4256
+ return -1;
4257
+ }
4258
+ return ap - bp;
4259
+ }
4260
+ function normalizeTTL(ttl) {
4261
+ if (typeof ttl === "string") {
4262
+ return ttl;
4263
+ }
4264
+ if (ttl < 0) {
4265
+ return "forever";
4266
+ }
4267
+ if (ttl === 0) {
4268
+ return "none";
4269
+ }
4270
+ let shortest = ttl.toString();
4271
+ const lengthOfNumber = shortest.length;
4272
+ for (const unit of ["y", "d", "h", "m", "s"]) {
4273
+ const multi = multiplier[unit];
4274
+ const value = ttl / multi;
4275
+ const candidate = `${value}${unit}`;
4276
+ if (candidate.length < shortest.length) {
4277
+ shortest = candidate;
4278
+ }
4279
+ }
4280
+ return shortest.length < lengthOfNumber ? shortest : ttl;
4281
+ }
4282
+ function clampTTL(ttl, lc) {
4283
+ const parsedTTL = parseTTL(ttl);
4284
+ if (parsedTTL === -1 || parsedTTL > 10 * 60 * 1e3) {
4285
+ lc?.warn?.(`TTL (${ttl}) is too high, clamping to ${MAX_TTL}`);
4286
+ return parseTTL(MAX_TTL);
4287
+ }
4288
+ return parsedTTL;
4163
4289
  }
4164
4290
 
4165
- // ../zql/src/query/query.ts
4166
- var delegateSymbol = Symbol("delegate");
4167
-
4168
4291
  // ../zql/src/query/query-impl.ts
4169
4292
  import { resolver } from "@rocicorp/resolver";
4170
4293
 
@@ -4466,315 +4589,779 @@ var Exists = class {
4466
4589
  const exists = (size ?? this.#getOrFetchSize(node)) > 0;
4467
4590
  return this.#not ? !exists : exists;
4468
4591
  }
4469
- /**
4470
- * Pushes a change if this.#filter is true for its row.
4471
- */
4472
- #pushWithFilter(change, size) {
4473
- if (this.#filter(change.node, size)) {
4474
- this.#output.push(change);
4475
- }
4592
+ /**
4593
+ * Pushes a change if this.#filter is true for its row.
4594
+ */
4595
+ #pushWithFilter(change, size) {
4596
+ if (this.#filter(change.node, size)) {
4597
+ this.#output.push(change);
4598
+ }
4599
+ }
4600
+ #getSize(node) {
4601
+ return this.#storage.get(this.#makeSizeStorageKey(node));
4602
+ }
4603
+ #setSize(node, size) {
4604
+ this.#storage.set(this.#makeSizeStorageKey(node), size);
4605
+ }
4606
+ #delSize(node) {
4607
+ this.#storage.del(this.#makeSizeStorageKey(node));
4608
+ }
4609
+ #getOrFetchSize(node) {
4610
+ const size = this.#getSize(node);
4611
+ if (size !== void 0) {
4612
+ return size;
4613
+ }
4614
+ return this.#fetchSize(node);
4615
+ }
4616
+ #fetchSize(node) {
4617
+ if (!this.#noSizeReuse && !this.#inPush) {
4618
+ const cachedSizeEntry = first(
4619
+ this.#storage.scan({
4620
+ prefix: this.#makeSizeStorageKeyPrefix(node)
4621
+ })
4622
+ );
4623
+ if (cachedSizeEntry !== void 0) {
4624
+ this.#setSize(node, cachedSizeEntry[1]);
4625
+ return cachedSizeEntry[1];
4626
+ }
4627
+ }
4628
+ const relationship = node.relationships[this.#relationshipName];
4629
+ assert(relationship);
4630
+ let size = 0;
4631
+ for (const _relatedNode of relationship()) {
4632
+ size++;
4633
+ }
4634
+ this.#setSize(node, size);
4635
+ return size;
4636
+ }
4637
+ #makeSizeStorageKeyPrefix(node) {
4638
+ return `row/${this.#noSizeReuse ? "" : JSON.stringify(this.#getKeyValues(node, this.#parentJoinKey))}/`;
4639
+ }
4640
+ #makeSizeStorageKey(node) {
4641
+ return `${this.#makeSizeStorageKeyPrefix(node)}${JSON.stringify(
4642
+ this.#getKeyValues(node, this.#input.getSchema().primaryKey)
4643
+ )}`;
4644
+ }
4645
+ #getKeyValues(node, def) {
4646
+ const values = [];
4647
+ for (const key of def) {
4648
+ values.push(normalizeUndefined(node.row[key]));
4649
+ }
4650
+ return values;
4651
+ }
4652
+ };
4653
+
4654
+ // ../zql/src/ivm/push-accumulated.ts
4655
+ function pushAccumulatedChanges(accumulatedPushes, output, fanOutChangeType, mergeRelationships, addEmptyRelationships) {
4656
+ if (accumulatedPushes.length === 0) {
4657
+ return;
4658
+ }
4659
+ const candidatesToPush = /* @__PURE__ */ new Map();
4660
+ for (const change of accumulatedPushes) {
4661
+ if (fanOutChangeType === "child" && change.type !== "child") {
4662
+ assert(
4663
+ candidatesToPush.has(change.type) === false,
4664
+ () => `Fan-in:child expected at most one ${change.type} when fan-out is of type child`
4665
+ );
4666
+ }
4667
+ const existing = candidatesToPush.get(change.type);
4668
+ let mergedChange = change;
4669
+ if (existing) {
4670
+ mergedChange = mergeRelationships(existing, change);
4671
+ }
4672
+ candidatesToPush.set(change.type, mergedChange);
4673
+ }
4674
+ accumulatedPushes.length = 0;
4675
+ const types = [...candidatesToPush.keys()];
4676
+ switch (fanOutChangeType) {
4677
+ case "remove":
4678
+ assert(
4679
+ types.length === 1 && types[0] === "remove",
4680
+ "Fan-in:remove expected all removes"
4681
+ );
4682
+ output.push(addEmptyRelationships(must(candidatesToPush.get("remove"))));
4683
+ return;
4684
+ case "add":
4685
+ assert(
4686
+ types.length === 1 && types[0] === "add",
4687
+ "Fan-in:add expected all adds"
4688
+ );
4689
+ output.push(addEmptyRelationships(must(candidatesToPush.get("add"))));
4690
+ return;
4691
+ case "edit": {
4692
+ assert(
4693
+ types.every(
4694
+ (type) => type === "add" || type === "remove" || type === "edit"
4695
+ ),
4696
+ "Fan-in:edit expected all adds, removes, or edits"
4697
+ );
4698
+ const addChange = candidatesToPush.get("add");
4699
+ const removeChange = candidatesToPush.get("remove");
4700
+ let editChange = candidatesToPush.get("edit");
4701
+ if (editChange) {
4702
+ if (addChange) {
4703
+ editChange = mergeRelationships(editChange, addChange);
4704
+ }
4705
+ if (removeChange) {
4706
+ editChange = mergeRelationships(editChange, removeChange);
4707
+ }
4708
+ output.push(addEmptyRelationships(editChange));
4709
+ return;
4710
+ }
4711
+ if (addChange && removeChange) {
4712
+ output.push(
4713
+ addEmptyRelationships({
4714
+ type: "edit",
4715
+ node: addChange.node,
4716
+ oldNode: removeChange.node
4717
+ })
4718
+ );
4719
+ return;
4720
+ }
4721
+ output.push(addEmptyRelationships(must(addChange ?? removeChange)));
4722
+ return;
4723
+ }
4724
+ case "child": {
4725
+ assert(
4726
+ types.every(
4727
+ (type) => type === "add" || // exists can change child to add or remove
4728
+ type === "remove" || // exists can change child to add or remove
4729
+ type === "child"
4730
+ // other operators may preserve the child change
4731
+ ),
4732
+ "Fan-in:child expected all adds, removes, or children"
4733
+ );
4734
+ assert(
4735
+ types.length <= 2,
4736
+ "Fan-in:child expected at most 2 types on a child change from fan-out"
4737
+ );
4738
+ const childChange = candidatesToPush.get("child");
4739
+ if (childChange) {
4740
+ output.push(childChange);
4741
+ return;
4742
+ }
4743
+ const addChange = candidatesToPush.get("add");
4744
+ const removeChange = candidatesToPush.get("remove");
4745
+ assert(
4746
+ addChange === void 0 || removeChange === void 0,
4747
+ "Fan-in:child expected either add or remove, not both"
4748
+ );
4749
+ output.push(addEmptyRelationships(must(addChange ?? removeChange)));
4750
+ return;
4751
+ }
4752
+ default:
4753
+ fanOutChangeType;
4754
+ }
4755
+ }
4756
+
4757
+ // ../zql/src/ivm/fan-in.ts
4758
+ var FanIn = class {
4759
+ #inputs;
4760
+ #schema;
4761
+ #output = throwFilterOutput;
4762
+ #accumulatedPushes = [];
4763
+ constructor(fanOut, inputs) {
4764
+ this.#inputs = inputs;
4765
+ this.#schema = fanOut.getSchema();
4766
+ for (const input of inputs) {
4767
+ input.setFilterOutput(this);
4768
+ assert(this.#schema === input.getSchema(), `Schema mismatch in fan-in`);
4769
+ }
4770
+ }
4771
+ setFilterOutput(output) {
4772
+ this.#output = output;
4773
+ }
4774
+ destroy() {
4775
+ for (const input of this.#inputs) {
4776
+ input.destroy();
4777
+ }
4778
+ }
4779
+ getSchema() {
4780
+ return this.#schema;
4781
+ }
4782
+ filter(node, cleanup) {
4783
+ return this.#output.filter(node, cleanup);
4784
+ }
4785
+ push(change) {
4786
+ this.#accumulatedPushes.push(change);
4787
+ }
4788
+ fanOutDonePushingToAllBranches(fanOutChangeType) {
4789
+ if (this.#inputs.length === 0) {
4790
+ assert(
4791
+ this.#accumulatedPushes.length === 0,
4792
+ "If there are no inputs then fan-in should not receive any pushes."
4793
+ );
4794
+ return;
4795
+ }
4796
+ pushAccumulatedChanges(
4797
+ this.#accumulatedPushes,
4798
+ this.#output,
4799
+ fanOutChangeType,
4800
+ identity,
4801
+ identity
4802
+ );
4803
+ }
4804
+ };
4805
+
4806
+ // ../zql/src/ivm/fan-out.ts
4807
+ var FanOut = class {
4808
+ #input;
4809
+ #outputs = [];
4810
+ #fanIn;
4811
+ #destroyCount = 0;
4812
+ constructor(input) {
4813
+ this.#input = input;
4814
+ input.setFilterOutput(this);
4815
+ }
4816
+ setFanIn(fanIn) {
4817
+ this.#fanIn = fanIn;
4818
+ }
4819
+ setFilterOutput(output) {
4820
+ this.#outputs.push(output);
4821
+ }
4822
+ destroy() {
4823
+ if (this.#destroyCount < this.#outputs.length) {
4824
+ ++this.#destroyCount;
4825
+ if (this.#destroyCount === this.#outputs.length) {
4826
+ this.#input.destroy();
4827
+ }
4828
+ } else {
4829
+ throw new Error("FanOut already destroyed once for each output");
4830
+ }
4831
+ }
4832
+ getSchema() {
4833
+ return this.#input.getSchema();
4834
+ }
4835
+ filter(node, cleanup) {
4836
+ let result = false;
4837
+ for (const output of this.#outputs) {
4838
+ result = output.filter(node, cleanup) || result;
4839
+ if (!cleanup && result) {
4840
+ return true;
4841
+ }
4842
+ }
4843
+ return result;
4844
+ }
4845
+ push(change) {
4846
+ for (const out of this.#outputs) {
4847
+ out.push(change);
4848
+ }
4849
+ must(
4850
+ this.#fanIn,
4851
+ "fan-out must have a corresponding fan-in set!"
4852
+ ).fanOutDonePushingToAllBranches(change.type);
4853
+ }
4854
+ };
4855
+
4856
+ // ../zql/src/ivm/maybe-split-and-push-edit-change.ts
4857
+ function maybeSplitAndPushEditChange(change, predicate, output) {
4858
+ const oldWasPresent = predicate(change.oldNode.row);
4859
+ const newIsPresent = predicate(change.node.row);
4860
+ if (oldWasPresent && newIsPresent) {
4861
+ output.push(change);
4862
+ } else if (oldWasPresent && !newIsPresent) {
4863
+ output.push({
4864
+ type: "remove",
4865
+ node: change.oldNode
4866
+ });
4867
+ } else if (!oldWasPresent && newIsPresent) {
4868
+ output.push({
4869
+ type: "add",
4870
+ node: change.node
4871
+ });
4872
+ }
4873
+ }
4874
+
4875
+ // ../zql/src/ivm/filter-push.ts
4876
+ function filterPush(change, output, predicate) {
4877
+ if (!predicate) {
4878
+ output.push(change);
4879
+ return;
4880
+ }
4881
+ switch (change.type) {
4882
+ case "add":
4883
+ case "remove":
4884
+ if (predicate(change.node.row)) {
4885
+ output.push(change);
4886
+ }
4887
+ break;
4888
+ case "child":
4889
+ if (predicate(change.node.row)) {
4890
+ output.push(change);
4891
+ }
4892
+ break;
4893
+ case "edit":
4894
+ maybeSplitAndPushEditChange(change, predicate, output);
4895
+ break;
4896
+ default:
4897
+ unreachable(change);
4898
+ }
4899
+ }
4900
+
4901
+ // ../zql/src/ivm/filter.ts
4902
+ var Filter = class {
4903
+ #input;
4904
+ #predicate;
4905
+ #output = throwFilterOutput;
4906
+ constructor(input, predicate) {
4907
+ this.#input = input;
4908
+ this.#predicate = predicate;
4909
+ input.setFilterOutput(this);
4910
+ }
4911
+ filter(node, cleanup) {
4912
+ return this.#predicate(node.row) && this.#output.filter(node, cleanup);
4476
4913
  }
4477
- #getSize(node) {
4478
- return this.#storage.get(this.#makeSizeStorageKey(node));
4914
+ setFilterOutput(output) {
4915
+ this.#output = output;
4479
4916
  }
4480
- #setSize(node, size) {
4481
- this.#storage.set(this.#makeSizeStorageKey(node), size);
4917
+ destroy() {
4918
+ this.#input.destroy();
4482
4919
  }
4483
- #delSize(node) {
4484
- this.#storage.del(this.#makeSizeStorageKey(node));
4920
+ getSchema() {
4921
+ return this.#input.getSchema();
4485
4922
  }
4486
- #getOrFetchSize(node) {
4487
- const size = this.#getSize(node);
4488
- if (size !== void 0) {
4489
- return size;
4490
- }
4491
- return this.#fetchSize(node);
4923
+ push(change) {
4924
+ filterPush(change, this.#output, this.#predicate);
4492
4925
  }
4493
- #fetchSize(node) {
4494
- if (!this.#noSizeReuse && !this.#inPush) {
4495
- const cachedSizeEntry = first(
4496
- this.#storage.scan({
4497
- prefix: this.#makeSizeStorageKeyPrefix(node)
4498
- })
4499
- );
4500
- if (cachedSizeEntry !== void 0) {
4501
- this.#setSize(node, cachedSizeEntry[1]);
4502
- return cachedSizeEntry[1];
4926
+ };
4927
+
4928
+ // ../zql/src/ivm/join-utils.ts
4929
+ function* generateWithOverlay(stream, overlay, schema) {
4930
+ let applied = false;
4931
+ let editOldApplied = false;
4932
+ let editNewApplied = false;
4933
+ for (const node of stream) {
4934
+ let yieldNode = true;
4935
+ if (!applied) {
4936
+ switch (overlay.type) {
4937
+ case "add": {
4938
+ if (schema.compareRows(overlay.node.row, node.row) === 0) {
4939
+ applied = true;
4940
+ yieldNode = false;
4941
+ }
4942
+ break;
4943
+ }
4944
+ case "remove": {
4945
+ if (schema.compareRows(overlay.node.row, node.row) < 0) {
4946
+ applied = true;
4947
+ yield overlay.node;
4948
+ }
4949
+ break;
4950
+ }
4951
+ case "edit": {
4952
+ if (!editOldApplied && schema.compareRows(overlay.oldNode.row, node.row) < 0) {
4953
+ editOldApplied = true;
4954
+ if (editNewApplied) {
4955
+ applied = true;
4956
+ }
4957
+ yield overlay.oldNode;
4958
+ }
4959
+ if (!editNewApplied && schema.compareRows(overlay.node.row, node.row) === 0) {
4960
+ editNewApplied = true;
4961
+ if (editOldApplied) {
4962
+ applied = true;
4963
+ }
4964
+ yieldNode = false;
4965
+ }
4966
+ break;
4967
+ }
4968
+ case "child": {
4969
+ if (schema.compareRows(overlay.node.row, node.row) === 0) {
4970
+ applied = true;
4971
+ yield {
4972
+ row: node.row,
4973
+ relationships: {
4974
+ ...node.relationships,
4975
+ [overlay.child.relationshipName]: () => generateWithOverlay(
4976
+ node.relationships[overlay.child.relationshipName](),
4977
+ overlay.child.change,
4978
+ schema.relationships[overlay.child.relationshipName]
4979
+ )
4980
+ }
4981
+ };
4982
+ yieldNode = false;
4983
+ }
4984
+ break;
4985
+ }
4503
4986
  }
4504
4987
  }
4505
- const relationship = node.relationships[this.#relationshipName];
4506
- assert(relationship);
4507
- let size = 0;
4508
- for (const _relatedNode of relationship()) {
4509
- size++;
4988
+ if (yieldNode) {
4989
+ yield node;
4510
4990
  }
4511
- this.#setSize(node, size);
4512
- return size;
4513
4991
  }
4514
- #makeSizeStorageKeyPrefix(node) {
4515
- return `row/${this.#noSizeReuse ? "" : JSON.stringify(this.#getKeyValues(node, this.#parentJoinKey))}/`;
4992
+ if (!applied) {
4993
+ if (overlay.type === "remove") {
4994
+ applied = true;
4995
+ yield overlay.node;
4996
+ } else if (overlay.type === "edit") {
4997
+ assert(editNewApplied);
4998
+ editOldApplied = true;
4999
+ applied = true;
5000
+ yield overlay.oldNode;
5001
+ }
4516
5002
  }
4517
- #makeSizeStorageKey(node) {
4518
- return `${this.#makeSizeStorageKeyPrefix(node)}${JSON.stringify(
4519
- this.#getKeyValues(node, this.#input.getSchema().primaryKey)
4520
- )}`;
5003
+ assert(applied);
5004
+ }
5005
+ function rowEqualsForCompoundKey(a, b, key) {
5006
+ for (let i = 0; i < key.length; i++) {
5007
+ if (compareValues(a[key[i]], b[key[i]]) !== 0) {
5008
+ return false;
5009
+ }
4521
5010
  }
4522
- #getKeyValues(node, def) {
4523
- const values = [];
4524
- for (const key of def) {
4525
- values.push(normalizeUndefined(node.row[key]));
5011
+ return true;
5012
+ }
5013
+ function isJoinMatch(parent, parentKey, child, childKey) {
5014
+ for (let i = 0; i < parentKey.length; i++) {
5015
+ if (!valuesEqual(parent[parentKey[i]], child[childKey[i]])) {
5016
+ return false;
4526
5017
  }
4527
- return values;
4528
5018
  }
4529
- };
5019
+ return true;
5020
+ }
4530
5021
 
4531
- // ../zql/src/ivm/fan-in.ts
4532
- var FanIn = class {
4533
- #inputs;
5022
+ // ../zql/src/ivm/flipped-join.ts
5023
+ var FlippedJoin = class {
5024
+ #parent;
5025
+ #child;
5026
+ #parentKey;
5027
+ #childKey;
5028
+ #relationshipName;
4534
5029
  #schema;
4535
- #output = throwFilterOutput;
4536
- #accumulatedPushes = [];
4537
- constructor(fanOut, inputs) {
4538
- this.#inputs = inputs;
4539
- this.#schema = fanOut.getSchema();
4540
- for (const input of inputs) {
4541
- input.setFilterOutput(this);
4542
- assert(this.#schema === input.getSchema(), `Schema mismatch in fan-in`);
4543
- }
4544
- }
4545
- setFilterOutput(output) {
4546
- this.#output = output;
5030
+ #output = throwOutput;
5031
+ #inprogressChildChange;
5032
+ constructor({
5033
+ parent,
5034
+ child,
5035
+ parentKey,
5036
+ childKey,
5037
+ relationshipName,
5038
+ hidden,
5039
+ system
5040
+ }) {
5041
+ assert(parent !== child, "Parent and child must be different operators");
5042
+ assert(
5043
+ parentKey.length === childKey.length,
5044
+ "The parentKey and childKey keys must have same length"
5045
+ );
5046
+ this.#parent = parent;
5047
+ this.#child = child;
5048
+ this.#parentKey = parentKey;
5049
+ this.#childKey = childKey;
5050
+ this.#relationshipName = relationshipName;
5051
+ const parentSchema = parent.getSchema();
5052
+ const childSchema = child.getSchema();
5053
+ this.#schema = {
5054
+ ...parentSchema,
5055
+ relationships: {
5056
+ ...parentSchema.relationships,
5057
+ [relationshipName]: {
5058
+ ...childSchema,
5059
+ isHidden: hidden,
5060
+ system
5061
+ }
5062
+ }
5063
+ };
5064
+ parent.setOutput({
5065
+ push: (change) => this.#pushParent(change)
5066
+ });
5067
+ child.setOutput({
5068
+ push: (change) => this.#pushChild(change)
5069
+ });
4547
5070
  }
4548
5071
  destroy() {
4549
- for (const input of this.#inputs) {
4550
- input.destroy();
4551
- }
5072
+ this.#child.destroy();
5073
+ this.#parent.destroy();
5074
+ }
5075
+ setOutput(output) {
5076
+ this.#output = output;
4552
5077
  }
4553
5078
  getSchema() {
4554
5079
  return this.#schema;
4555
5080
  }
4556
- filter(node, cleanup) {
4557
- return this.#output.filter(node, cleanup);
4558
- }
4559
- push(change) {
4560
- this.#accumulatedPushes.push(change);
4561
- }
4562
- fanOutDonePushingToAllBranches(fanOutChangeType) {
4563
- if (this.#inputs.length === 0) {
4564
- assert(
4565
- this.#accumulatedPushes.length === 0,
4566
- "If there are no inputs then fan-in should not receive any pushes."
5081
+ // TODO: When parentKey is the parent's primary key (or more
5082
+ // generally when the parent cardinality is expected to be small) a different
5083
+ // algorithm should be used: For each child node, fetch all parent nodes
5084
+ // eagerly and then sort using quicksort.
5085
+ *fetch(req) {
5086
+ const childNodes = [...this.#child.fetch({})];
5087
+ if (this.#inprogressChildChange?.change.type === "remove") {
5088
+ const removedNode = this.#inprogressChildChange.change.node;
5089
+ const compare = this.#child.getSchema().compareRows;
5090
+ const insertPos = binarySearch(
5091
+ childNodes.length,
5092
+ (i) => compare(childNodes[i].row, removedNode.row)
4567
5093
  );
4568
- return;
5094
+ childNodes.splice(insertPos, 0, removedNode);
4569
5095
  }
4570
- if (this.#accumulatedPushes.length === 0) {
4571
- return;
5096
+ const parentIterators = [];
5097
+ let threw = false;
5098
+ try {
5099
+ for (const childNode of childNodes) {
5100
+ const stream = this.#parent.fetch({
5101
+ ...req,
5102
+ constraint: {
5103
+ ...req.constraint,
5104
+ ...Object.fromEntries(
5105
+ this.#parentKey.map((key, i) => [
5106
+ key,
5107
+ childNode.row[this.#childKey[i]]
5108
+ ])
5109
+ )
5110
+ }
5111
+ });
5112
+ const iterator = stream[Symbol.iterator]();
5113
+ parentIterators.push(iterator);
5114
+ }
5115
+ const nextParentNodes = [];
5116
+ for (let i = 0; i < parentIterators.length; i++) {
5117
+ const iter = parentIterators[i];
5118
+ const result = iter.next();
5119
+ nextParentNodes[i] = result.done ? null : result.value;
5120
+ }
5121
+ while (true) {
5122
+ let minParentNode = null;
5123
+ let minParentNodeChildIndexes = [];
5124
+ for (let i = 0; i < nextParentNodes.length; i++) {
5125
+ const parentNode = nextParentNodes[i];
5126
+ if (parentNode === null) {
5127
+ continue;
5128
+ }
5129
+ if (minParentNode === null) {
5130
+ minParentNode = parentNode;
5131
+ minParentNodeChildIndexes.push(i);
5132
+ } else {
5133
+ const compareResult = this.#schema.compareRows(parentNode.row, minParentNode.row) * (req.reverse ? -1 : 1);
5134
+ if (compareResult === 0) {
5135
+ minParentNodeChildIndexes.push(i);
5136
+ } else if (compareResult < 0) {
5137
+ minParentNode = parentNode;
5138
+ minParentNodeChildIndexes = [i];
5139
+ }
5140
+ }
5141
+ }
5142
+ if (minParentNode === null) {
5143
+ return;
5144
+ }
5145
+ const relatedChildNodes = [];
5146
+ for (const minParentNodeChildIndex of minParentNodeChildIndexes) {
5147
+ relatedChildNodes.push(childNodes[minParentNodeChildIndex]);
5148
+ const iter = parentIterators[minParentNodeChildIndex];
5149
+ const result = iter.next();
5150
+ nextParentNodes[minParentNodeChildIndex] = result.done ? null : result.value;
5151
+ }
5152
+ let overlaidRelatedChildNodes = relatedChildNodes;
5153
+ if (this.#inprogressChildChange && this.#inprogressChildChange.position && isJoinMatch(
5154
+ this.#inprogressChildChange.change.node.row,
5155
+ this.#childKey,
5156
+ minParentNode.row,
5157
+ this.#parentKey
5158
+ )) {
5159
+ if (this.#inprogressChildChange.change.type === "remove") {
5160
+ if (this.#parent.getSchema().compareRows(
5161
+ minParentNode.row,
5162
+ this.#inprogressChildChange.position
5163
+ ) <= 0) {
5164
+ overlaidRelatedChildNodes = relatedChildNodes.filter(
5165
+ (n) => n !== this.#inprogressChildChange?.change.node
5166
+ );
5167
+ }
5168
+ } else if (this.#parent.getSchema().compareRows(
5169
+ minParentNode.row,
5170
+ this.#inprogressChildChange.position
5171
+ ) > 0) {
5172
+ overlaidRelatedChildNodes = [
5173
+ ...generateWithOverlay(
5174
+ relatedChildNodes,
5175
+ this.#inprogressChildChange.change,
5176
+ this.#child.getSchema()
5177
+ )
5178
+ ];
5179
+ }
5180
+ }
5181
+ if (overlaidRelatedChildNodes.length > 0) {
5182
+ yield {
5183
+ ...minParentNode,
5184
+ relationships: {
5185
+ ...minParentNode.relationships,
5186
+ [this.#relationshipName]: () => overlaidRelatedChildNodes
5187
+ }
5188
+ };
5189
+ }
5190
+ }
5191
+ } catch (e) {
5192
+ threw = true;
5193
+ for (const iter of parentIterators) {
5194
+ try {
5195
+ iter.throw?.(e);
5196
+ } catch (_cleanupError) {
5197
+ }
5198
+ }
5199
+ throw e;
5200
+ } finally {
5201
+ if (!threw) {
5202
+ for (const iter of parentIterators) {
5203
+ try {
5204
+ iter.return?.();
5205
+ } catch (_cleanupError) {
5206
+ }
5207
+ }
5208
+ }
4572
5209
  }
4573
- const candidatesToPush = /* @__PURE__ */ new Map();
4574
- for (const change of this.#accumulatedPushes) {
4575
- if (fanOutChangeType === "child" && change.type !== "child") {
5210
+ }
5211
+ *cleanup(_req) {
5212
+ }
5213
+ #pushChild(change) {
5214
+ const pushChildChange = (exists) => {
5215
+ this.#inprogressChildChange = {
5216
+ change,
5217
+ position: void 0
5218
+ };
5219
+ try {
5220
+ const parentNodeStream = this.#parent.fetch({
5221
+ constraint: Object.fromEntries(
5222
+ this.#parentKey.map((key, i) => [
5223
+ key,
5224
+ change.node.row[this.#childKey[i]]
5225
+ ])
5226
+ )
5227
+ });
5228
+ for (const parentNode of parentNodeStream) {
5229
+ this.#inprogressChildChange = {
5230
+ change,
5231
+ position: parentNode.row
5232
+ };
5233
+ const childNodeStream = () => this.#child.fetch({
5234
+ constraint: Object.fromEntries(
5235
+ this.#childKey.map((key, i) => [
5236
+ key,
5237
+ parentNode.row[this.#parentKey[i]]
5238
+ ])
5239
+ )
5240
+ });
5241
+ if (!exists) {
5242
+ for (const childNode of childNodeStream()) {
5243
+ if (this.#child.getSchema().compareRows(childNode.row, change.node.row) !== 0) {
5244
+ exists = true;
5245
+ break;
5246
+ }
5247
+ }
5248
+ }
5249
+ if (exists) {
5250
+ this.#output.push({
5251
+ type: "child",
5252
+ node: {
5253
+ ...parentNode,
5254
+ relationships: {
5255
+ ...parentNode.relationships,
5256
+ [this.#relationshipName]: childNodeStream
5257
+ }
5258
+ },
5259
+ child: {
5260
+ relationshipName: this.#relationshipName,
5261
+ change
5262
+ }
5263
+ });
5264
+ } else {
5265
+ this.#output.push({
5266
+ ...change,
5267
+ node: {
5268
+ ...parentNode,
5269
+ relationships: {
5270
+ ...parentNode.relationships,
5271
+ [this.#relationshipName]: () => [change.node]
5272
+ }
5273
+ }
5274
+ });
5275
+ }
5276
+ }
5277
+ } finally {
5278
+ this.#inprogressChildChange = void 0;
5279
+ }
5280
+ };
5281
+ switch (change.type) {
5282
+ case "add":
5283
+ case "remove":
5284
+ pushChildChange();
5285
+ break;
5286
+ case "edit": {
4576
5287
  assert(
4577
- candidatesToPush.has(change.type) === false,
4578
- () => `Fan-in:child expected at most one ${change.type} when fan-out is of type child`
5288
+ rowEqualsForCompoundKey(
5289
+ change.oldNode.row,
5290
+ change.node.row,
5291
+ this.#childKey
5292
+ ),
5293
+ `Child edit must not change relationship.`
4579
5294
  );
5295
+ pushChildChange(true);
5296
+ break;
4580
5297
  }
4581
- candidatesToPush.set(change.type, change);
5298
+ case "child":
5299
+ pushChildChange(true);
5300
+ break;
4582
5301
  }
4583
- this.#accumulatedPushes = [];
4584
- const types = [...candidatesToPush.keys()];
4585
- switch (fanOutChangeType) {
4586
- case "remove":
4587
- assert(
4588
- types.length === 1 && types[0] === "remove",
4589
- "Fan-in:remove expected all removes"
4590
- );
4591
- this.#output.push(must(candidatesToPush.get("remove")));
4592
- return;
5302
+ }
5303
+ #pushParent(change) {
5304
+ const childNodeStream = (node) => () => this.#child.fetch({
5305
+ constraint: Object.fromEntries(
5306
+ this.#childKey.map((key, i) => [key, node.row[this.#parentKey[i]]])
5307
+ )
5308
+ });
5309
+ const flip = (node) => ({
5310
+ ...node,
5311
+ relationships: {
5312
+ ...node.relationships,
5313
+ [this.#relationshipName]: childNodeStream(node)
5314
+ }
5315
+ });
5316
+ switch (change.type) {
4593
5317
  case "add":
4594
- assert(
4595
- types.length === 1 && types[0] === "add",
4596
- "Fan-in:add expected all adds"
4597
- );
4598
- this.#output.push(must(candidatesToPush.get("add")));
4599
- return;
5318
+ case "remove":
5319
+ case "child": {
5320
+ if (first(childNodeStream(change.node)()) === void 0) {
5321
+ return;
5322
+ }
5323
+ this.#output.push({
5324
+ ...change,
5325
+ node: flip(change.node)
5326
+ });
5327
+ break;
5328
+ }
4600
5329
  case "edit": {
5330
+ const oldHasChild = first(childNodeStream(change.oldNode)()) !== void 0;
5331
+ const hasChild = first(childNodeStream(change.node)()) !== void 0;
4601
5332
  assert(
4602
- types.every(
4603
- (type) => type === "add" || type === "remove" || type === "edit"
5333
+ rowEqualsForCompoundKey(
5334
+ change.oldNode.row,
5335
+ change.node.row,
5336
+ this.#parentKey
4604
5337
  ),
4605
- "Fan-in:edit expected all adds, removes, or edits"
5338
+ `Parent edit must not change relationship.`
4606
5339
  );
4607
- const addChange = candidatesToPush.get("add");
4608
- const removeChange = candidatesToPush.get("remove");
4609
- const editChange = candidatesToPush.get("edit");
4610
- if (editChange) {
4611
- this.#output.push(editChange);
4612
- return;
4613
- }
4614
- if (addChange && removeChange) {
5340
+ if (oldHasChild && hasChild) {
4615
5341
  this.#output.push({
4616
5342
  type: "edit",
4617
- node: addChange.node,
4618
- oldNode: removeChange.node
5343
+ oldNode: flip(change.oldNode),
5344
+ node: flip(change.node)
4619
5345
  });
4620
- return;
5346
+ break;
4621
5347
  }
4622
- this.#output.push(must(addChange ?? removeChange));
4623
- return;
4624
- }
4625
- case "child": {
4626
- assert(
4627
- types.every(
4628
- (type) => type === "add" || // exists can change child to add or remove
4629
- type === "remove" || // exists can change child to add or remove
4630
- type === "child"
4631
- // other operators may preserve the child change
4632
- ),
4633
- "Fan-in:child expected all adds, removes, or children"
4634
- );
4635
- assert(
4636
- types.length <= 2,
4637
- "Fan-in:child expected at most 2 types on a child change from fan-out"
4638
- );
4639
- const childChange = candidatesToPush.get("child");
4640
- if (childChange) {
4641
- this.#output.push(childChange);
4642
- return;
5348
+ if (oldHasChild) {
5349
+ this.#output.push({
5350
+ type: "remove",
5351
+ node: flip(change.node)
5352
+ });
4643
5353
  }
4644
- const addChange = candidatesToPush.get("add");
4645
- const removeChange = candidatesToPush.get("remove");
4646
- assert(
4647
- addChange === void 0 || removeChange === void 0,
4648
- "Fan-in:child expected either add or remove, not both"
4649
- );
4650
- this.#output.push(must(addChange ?? removeChange));
4651
- return;
5354
+ if (hasChild) {
5355
+ this.#output.push({
5356
+ type: "add",
5357
+ node: flip(change.node)
5358
+ });
5359
+ }
5360
+ break;
4652
5361
  }
4653
5362
  default:
4654
- fanOutChangeType;
4655
- }
4656
- }
4657
- };
4658
-
4659
- // ../zql/src/ivm/fan-out.ts
4660
- var FanOut = class {
4661
- #input;
4662
- #outputs = [];
4663
- #fanIn;
4664
- #destroyCount = 0;
4665
- constructor(input) {
4666
- this.#input = input;
4667
- input.setFilterOutput(this);
4668
- }
4669
- setFanIn(fanIn) {
4670
- this.#fanIn = fanIn;
4671
- }
4672
- setFilterOutput(output) {
4673
- this.#outputs.push(output);
4674
- }
4675
- destroy() {
4676
- if (this.#destroyCount < this.#outputs.length) {
4677
- if (this.#destroyCount === 0) {
4678
- this.#input.destroy();
4679
- }
4680
- ++this.#destroyCount;
4681
- } else {
4682
- throw new Error("FanOut already destroyed once for each output");
4683
- }
4684
- }
4685
- getSchema() {
4686
- return this.#input.getSchema();
4687
- }
4688
- filter(node, cleanup) {
4689
- let result = false;
4690
- for (const output of this.#outputs) {
4691
- result = output.filter(node, cleanup) || result;
4692
- if (!cleanup && result) {
4693
- return true;
4694
- }
4695
- }
4696
- return result;
4697
- }
4698
- push(change) {
4699
- for (const out of this.#outputs) {
4700
- out.push(change);
5363
+ unreachable(change);
4701
5364
  }
4702
- must(
4703
- this.#fanIn,
4704
- "fan-out must have a corresponding fan-in set!"
4705
- ).fanOutDonePushingToAllBranches(change.type);
4706
- }
4707
- };
4708
-
4709
- // ../zql/src/ivm/maybe-split-and-push-edit-change.ts
4710
- function maybeSplitAndPushEditChange(change, predicate, output) {
4711
- const oldWasPresent = predicate(change.oldNode.row);
4712
- const newIsPresent = predicate(change.node.row);
4713
- if (oldWasPresent && newIsPresent) {
4714
- output.push(change);
4715
- } else if (oldWasPresent && !newIsPresent) {
4716
- output.push({
4717
- type: "remove",
4718
- node: change.oldNode
4719
- });
4720
- } else if (!oldWasPresent && newIsPresent) {
4721
- output.push({
4722
- type: "add",
4723
- node: change.node
4724
- });
4725
- }
4726
- }
4727
-
4728
- // ../zql/src/ivm/filter-push.ts
4729
- function filterPush(change, output, predicate) {
4730
- if (!predicate) {
4731
- output.push(change);
4732
- return;
4733
- }
4734
- switch (change.type) {
4735
- case "add":
4736
- case "remove":
4737
- if (predicate(change.node.row)) {
4738
- output.push(change);
4739
- }
4740
- break;
4741
- case "child":
4742
- if (predicate(change.node.row)) {
4743
- output.push(change);
4744
- }
4745
- break;
4746
- case "edit":
4747
- maybeSplitAndPushEditChange(change, predicate, output);
4748
- break;
4749
- default:
4750
- unreachable(change);
4751
- }
4752
- }
4753
-
4754
- // ../zql/src/ivm/filter.ts
4755
- var Filter = class {
4756
- #input;
4757
- #predicate;
4758
- #output = throwFilterOutput;
4759
- constructor(input, predicate) {
4760
- this.#input = input;
4761
- this.#predicate = predicate;
4762
- input.setFilterOutput(this);
4763
- }
4764
- filter(node, cleanup) {
4765
- return this.#predicate(node.row) && this.#output.filter(node, cleanup);
4766
- }
4767
- setFilterOutput(output) {
4768
- this.#output = output;
4769
- }
4770
- destroy() {
4771
- this.#input.destroy();
4772
- }
4773
- getSchema() {
4774
- return this.#input.getSchema();
4775
- }
4776
- push(change) {
4777
- filterPush(change, this.#output, this.#predicate);
4778
5365
  }
4779
5366
  };
4780
5367
 
@@ -4973,81 +5560,6 @@ var Join = class {
4973
5560
  unreachable(change);
4974
5561
  }
4975
5562
  }
4976
- *#generateChildStreamWithOverlay(stream, overlay) {
4977
- let applied = false;
4978
- let editOldApplied = false;
4979
- let editNewApplied = false;
4980
- for (const child of stream) {
4981
- let yieldChild = true;
4982
- if (!applied) {
4983
- switch (overlay.type) {
4984
- case "add": {
4985
- if (this.#child.getSchema().compareRows(overlay.node.row, child.row) === 0) {
4986
- applied = true;
4987
- yieldChild = false;
4988
- }
4989
- break;
4990
- }
4991
- case "remove": {
4992
- if (this.#child.getSchema().compareRows(overlay.node.row, child.row) < 0) {
4993
- applied = true;
4994
- yield overlay.node;
4995
- }
4996
- break;
4997
- }
4998
- case "edit": {
4999
- if (this.#child.getSchema().compareRows(overlay.oldNode.row, child.row) < 0) {
5000
- editOldApplied = true;
5001
- if (editNewApplied) {
5002
- applied = true;
5003
- }
5004
- yield overlay.oldNode;
5005
- }
5006
- if (this.#child.getSchema().compareRows(overlay.node.row, child.row) === 0) {
5007
- editNewApplied = true;
5008
- if (editOldApplied) {
5009
- applied = true;
5010
- }
5011
- yieldChild = false;
5012
- }
5013
- break;
5014
- }
5015
- case "child": {
5016
- if (this.#child.getSchema().compareRows(overlay.node.row, child.row) === 0) {
5017
- applied = true;
5018
- yield {
5019
- row: child.row,
5020
- relationships: {
5021
- ...child.relationships,
5022
- [overlay.child.relationshipName]: () => this.#generateChildStreamWithOverlay(
5023
- child.relationships[overlay.child.relationshipName](),
5024
- overlay.child.change
5025
- )
5026
- }
5027
- };
5028
- yieldChild = false;
5029
- }
5030
- break;
5031
- }
5032
- }
5033
- }
5034
- if (yieldChild) {
5035
- yield child;
5036
- }
5037
- }
5038
- if (!applied) {
5039
- if (overlay.type === "remove") {
5040
- applied = true;
5041
- yield overlay.node;
5042
- } else if (overlay.type === "edit") {
5043
- assert(editNewApplied);
5044
- editOldApplied = true;
5045
- applied = true;
5046
- yield overlay.oldNode;
5047
- }
5048
- }
5049
- assert(applied);
5050
- }
5051
5563
  #processParentNode(parentNodeRow, parentNodeRelations, mode) {
5052
5564
  let method = mode;
5053
5565
  let storageUpdated = false;
@@ -5091,16 +5603,19 @@ var Join = class {
5091
5603
  ])
5092
5604
  )
5093
5605
  });
5094
- if (this.#inprogressChildChange && this.#isJoinMatch(
5606
+ if (this.#inprogressChildChange && isJoinMatch(
5095
5607
  parentNodeRow,
5096
- this.#inprogressChildChange.change.node.row
5608
+ this.#parentKey,
5609
+ this.#inprogressChildChange.change.node.row,
5610
+ this.#childKey
5097
5611
  ) && this.#inprogressChildChange.position && this.#schema.compareRows(
5098
5612
  parentNodeRow,
5099
5613
  this.#inprogressChildChange.position
5100
5614
  ) > 0) {
5101
- return this.#generateChildStreamWithOverlay(
5615
+ return generateWithOverlay(
5102
5616
  stream,
5103
- this.#inprogressChildChange.change
5617
+ this.#inprogressChildChange.change,
5618
+ this.#child.getSchema()
5104
5619
  );
5105
5620
  }
5106
5621
  return stream;
@@ -5113,14 +5628,6 @@ var Join = class {
5113
5628
  }
5114
5629
  };
5115
5630
  }
5116
- #isJoinMatch(parent, child) {
5117
- for (let i = 0; i < this.#parentKey.length; i++) {
5118
- if (!valuesEqual(parent[this.#parentKey[i]], child[this.#childKey[i]])) {
5119
- return false;
5120
- }
5121
- }
5122
- return true;
5123
- }
5124
5631
  };
5125
5632
  function makeStorageKeyForValues(values) {
5126
5633
  const json = JSON.stringify(["pKeySet", ...values]);
@@ -5136,14 +5643,6 @@ function makeStorageKey(key, primaryKey, row) {
5136
5643
  }
5137
5644
  return makeStorageKeyForValues(values);
5138
5645
  }
5139
- function rowEqualsForCompoundKey(a, b, key) {
5140
- for (let i = 0; i < key.length; i++) {
5141
- if (compareValues(a[key[i]], b[key[i]]) !== 0) {
5142
- return false;
5143
- }
5144
- }
5145
- return true;
5146
- }
5147
5646
 
5148
5647
  // ../zql/src/ivm/skip.ts
5149
5648
  var Skip = class {
@@ -5762,7 +6261,7 @@ var ExpressionBuilder = class {
5762
6261
  and = and;
5763
6262
  or = or;
5764
6263
  not = not;
5765
- exists = (relationship, cb) => this.#exists(relationship, cb);
6264
+ exists = (relationship, cb, options) => this.#exists(relationship, cb, options);
5766
6265
  };
5767
6266
  function and(...conditions) {
5768
6267
  const expressions = filterTrue(filterUndefined(conditions));
@@ -5897,8 +6396,8 @@ var negateOperatorMap = {
5897
6396
  function negateOperator(op) {
5898
6397
  return must(negateOperatorMap[op]);
5899
6398
  }
5900
- function filterUndefined(array6) {
5901
- return array6.filter((e) => e !== void 0);
6399
+ function filterUndefined(array7) {
6400
+ return array7.filter((e) => e !== void 0);
5902
6401
  }
5903
6402
  function filterTrue(conditions) {
5904
6403
  return conditions.filter((c) => !isAlwaysTrue(c));
@@ -6284,8 +6783,16 @@ function applyCorrelatedSubQuery(sq, delegate, queryID, end, name, fromCondition
6284
6783
  `${name}.${sq.subquery.alias}`,
6285
6784
  sq.correlation.childField
6286
6785
  );
6287
- const joinName = `${name}:join(${sq.subquery.alias})`;
6288
- const join = new Join({
6786
+ const joinName = `${name}:${sq.flip ? "flipped-join" : "join"}(${sq.subquery.alias})`;
6787
+ const join = sq.flip ? new FlippedJoin({
6788
+ parent: end,
6789
+ child,
6790
+ parentKey: sq.correlation.parentField,
6791
+ childKey: sq.correlation.childField,
6792
+ relationshipName: sq.subquery.alias,
6793
+ hidden: sq.hidden ?? false,
6794
+ system: sq.system ?? "client"
6795
+ }) : new Join({
6289
6796
  parent: end,
6290
6797
  child,
6291
6798
  storage: delegate.createStorage(joinName),
@@ -6630,7 +7137,12 @@ var AbstractQuery = class {
6630
7137
  this.customQueryID,
6631
7138
  this.#currentJunction
6632
7139
  );
6633
- whereExists = (relationship, cb) => this.where(({ exists }) => exists(relationship, cb));
7140
+ whereExists = (relationship, cbOrOptions, options) => {
7141
+ const cb = typeof cbOrOptions === "function" ? cbOrOptions : void 0;
7142
+ const opts = typeof cbOrOptions === "function" ? options : cbOrOptions;
7143
+ const flipped = opts?.flip ?? false;
7144
+ return this.where(({ exists }) => exists(relationship, cb, { flip: flipped }));
7145
+ };
6634
7146
  related = (relationship, cb) => {
6635
7147
  if (relationship.startsWith(SUBQ_PREFIX)) {
6636
7148
  throw new Error(
@@ -6869,7 +7381,9 @@ var AbstractQuery = class {
6869
7381
  this.#currentJunction
6870
7382
  );
6871
7383
  };
6872
- _exists = (relationship, cb = (q) => q) => {
7384
+ _exists = (relationship, cb, options) => {
7385
+ cb = cb ?? ((q) => q);
7386
+ const flip = options?.flip ?? false;
6873
7387
  const related = this.#schema.relationships[this.#tableName][relationship];
6874
7388
  assert(related, "Invalid relationship");
6875
7389
  if (isOneHop(related)) {
@@ -6901,7 +7415,8 @@ var AbstractQuery = class {
6901
7415
  subquery: addPrimaryKeysToAst(
6902
7416
  this.#schema.tables[destSchema],
6903
7417
  sq._ast
6904
- )
7418
+ ),
7419
+ flip
6905
7420
  },
6906
7421
  op: "EXISTS"
6907
7422
  };
@@ -6936,6 +7451,7 @@ var AbstractQuery = class {
6936
7451
  parentField: firstRelation.sourceField,
6937
7452
  childField: firstRelation.destField
6938
7453
  },
7454
+ flip,
6939
7455
  subquery: {
6940
7456
  table: junctionSchema,
6941
7457
  alias: `${SUBQ_PREFIX}${relationship}`,
@@ -6954,7 +7470,8 @@ var AbstractQuery = class {
6954
7470
  subquery: addPrimaryKeysToAst(
6955
7471
  this.#schema.tables[destSchema],
6956
7472
  queryToDest._ast
6957
- )
7473
+ ),
7474
+ flip
6958
7475
  },
6959
7476
  op: "EXISTS"
6960
7477
  }
@@ -6998,9 +7515,6 @@ var AbstractQuery = class {
6998
7515
  }
6999
7516
  return this.#completedAST;
7000
7517
  }
7001
- then(onFulfilled, onRejected) {
7002
- return this.run().then(onFulfilled, onRejected);
7003
- }
7004
7518
  };
7005
7519
  var completedAstSymbol = Symbol();
7006
7520
  var QueryImpl = class _QueryImpl extends AbstractQuery {
@@ -7222,16 +7736,6 @@ export {
7222
7736
  ChunkNotFoundError,
7223
7737
  mustGetChunk,
7224
7738
  mustGetHeadHash,
7225
- withRead,
7226
- withWriteNoImplicitCommit,
7227
- withWrite,
7228
- using,
7229
- getClientGroups,
7230
- setClientGroups,
7231
- setClientGroup,
7232
- getClientGroup,
7233
- clientGroupHasPendingMutations,
7234
- disableClientGroup,
7235
7739
  binarySearch,
7236
7740
  joinIterables,
7237
7741
  once,
@@ -7268,6 +7772,16 @@ export {
7268
7772
  newWriteSnapshotDD31,
7269
7773
  clientGroupIDSchema,
7270
7774
  clientIDSchema,
7775
+ withRead,
7776
+ withWriteNoImplicitCommit,
7777
+ withWrite,
7778
+ using,
7779
+ getClientGroups,
7780
+ setClientGroups,
7781
+ setClientGroup,
7782
+ getClientGroup,
7783
+ clientGroupHasPendingMutations,
7784
+ disableClientGroup,
7271
7785
  makeClientID,
7272
7786
  assertClientV6,
7273
7787
  getClients,
@@ -7300,6 +7814,8 @@ export {
7300
7814
  makeComparator,
7301
7815
  valuesEqual,
7302
7816
  throwOutput,
7817
+ emptyFunction,
7818
+ emptyObject,
7303
7819
  filterPush,
7304
7820
  ExpressionBuilder,
7305
7821
  createPredicate,
@@ -7323,6 +7839,8 @@ export {
7323
7839
  inspectQueriesDownSchema,
7324
7840
  inspectMetricsDownSchema,
7325
7841
  inspectVersionDownSchema,
7842
+ inspectAuthenticatedDownSchema,
7843
+ inspectAnalyzeQueryDownSchema,
7326
7844
  inspectDownMessageSchema,
7327
7845
  primaryKeySchema,
7328
7846
  primaryKeyValueRecordSchema,
@@ -7336,6 +7854,8 @@ export {
7336
7854
  toMutationResponseKey,
7337
7855
  toPrimaryKeyString,
7338
7856
  sourceNameFromKey,
7339
- TDigest
7857
+ Client,
7858
+ TDigest,
7859
+ Inspector
7340
7860
  };
7341
- //# sourceMappingURL=chunk-MLYQCVBG.js.map
7861
+ //# sourceMappingURL=chunk-QZPMFA73.js.map