doxum 0.1.19 → 0.1.21

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 (65) hide show
  1. package/README.md +30 -11
  2. package/dist/{scope-d-L87NeC.js → access-BeSV5ve-.js} +114 -20
  3. package/dist/access-BeSV5ve-.js.map +1 -0
  4. package/dist/{scope-Ezs-Y3TY.cjs → access-Bienf28h.cjs} +149 -19
  5. package/dist/access-Bienf28h.cjs.map +1 -0
  6. package/dist/advanced-BRL5pN0y.cjs +1361 -0
  7. package/dist/advanced-BRL5pN0y.cjs.map +1 -0
  8. package/dist/advanced-COFJtWMT.js +1188 -0
  9. package/dist/advanced-COFJtWMT.js.map +1 -0
  10. package/dist/{advanced-C2fpjbK3.d.ts → advanced-DfKc7TZR.d.cts} +27 -22
  11. package/dist/{advanced-DlOYk1vi.d.cts → advanced-FgdTwu5b.d.ts} +27 -22
  12. package/dist/advanced.cjs +1 -1
  13. package/dist/advanced.d.cts +2 -2
  14. package/dist/advanced.d.ts +2 -2
  15. package/dist/advanced.js +1 -1
  16. package/dist/{contract-XmKnroJq.d.cts → contract-CdmDHRUq.d.cts} +8 -6
  17. package/dist/{contract-CATCCVu5.d.ts → contract-KG5XnQZt.d.ts} +8 -6
  18. package/dist/{driver-CSnhMjbP.js → driver-CLYJOGDQ.js} +2 -2
  19. package/dist/{driver-CSnhMjbP.js.map → driver-CLYJOGDQ.js.map} +1 -1
  20. package/dist/{driver-BCyfqxsl.cjs → driver-Djr3BVvo.cjs} +2 -2
  21. package/dist/{driver-BCyfqxsl.cjs.map → driver-Djr3BVvo.cjs.map} +1 -1
  22. package/dist/index.cjs +1150 -1993
  23. package/dist/index.cjs.map +1 -1
  24. package/dist/index.d.cts +2 -2
  25. package/dist/index.d.ts +2 -2
  26. package/dist/index.js +1105 -1948
  27. package/dist/index.js.map +1 -1
  28. package/dist/{integration-CxVhq-KD.js → integration-C4Isp8lJ.js} +3 -2
  29. package/dist/{integration-CxVhq-KD.js.map → integration-C4Isp8lJ.js.map} +1 -1
  30. package/dist/{integration-B7VDgAOJ.cjs → integration-Z6MsfFI7.cjs} +4 -3
  31. package/dist/{integration-B7VDgAOJ.cjs.map → integration-Z6MsfFI7.cjs.map} +1 -1
  32. package/dist/integration.cjs +3 -3
  33. package/dist/integration.d.cts +1 -1
  34. package/dist/integration.d.ts +1 -1
  35. package/dist/integration.js +3 -3
  36. package/dist/{issue-DhrNdQNg.cjs → issue-DjK1xp5K.cjs} +106 -22
  37. package/dist/issue-DjK1xp5K.cjs.map +1 -0
  38. package/dist/{issue-DVaGQGeP.js → issue-W0hT8u8D.js} +81 -15
  39. package/dist/issue-W0hT8u8D.js.map +1 -0
  40. package/dist/local-sync.cjs +2 -2
  41. package/dist/local-sync.d.cts +1 -1
  42. package/dist/local-sync.d.ts +1 -1
  43. package/dist/local-sync.js +2 -2
  44. package/dist/{notification-IQIJyH3Q.js → notification-Bkjau6B6.js} +3 -56
  45. package/dist/notification-Bkjau6B6.js.map +1 -0
  46. package/dist/{notification-CDSUfiip.cjs → notification-DJfouMEb.cjs} +2 -91
  47. package/dist/notification-DJfouMEb.cjs.map +1 -0
  48. package/dist/react.cjs +2 -2
  49. package/dist/react.js +2 -2
  50. package/package.json +1 -1
  51. package/skills/doxum-runtime/SKILL.md +4 -1
  52. package/skills/doxum-runtime/references/guide.en.md +5 -2
  53. package/skills/doxum-runtime/references/guide.zh-CN.md +5 -2
  54. package/skills/doxum-runtime/references/projections.en.md +23 -9
  55. package/skills/doxum-runtime/references/projections.zh-CN.md +18 -6
  56. package/dist/advanced-BYZCjNWL.js +0 -680
  57. package/dist/advanced-BYZCjNWL.js.map +0 -1
  58. package/dist/advanced-CMMNk49G.cjs +0 -763
  59. package/dist/advanced-CMMNk49G.cjs.map +0 -1
  60. package/dist/issue-DVaGQGeP.js.map +0 -1
  61. package/dist/issue-DhrNdQNg.cjs.map +0 -1
  62. package/dist/notification-CDSUfiip.cjs.map +0 -1
  63. package/dist/notification-IQIJyH3Q.js.map +0 -1
  64. package/dist/scope-Ezs-Y3TY.cjs.map +0 -1
  65. package/dist/scope-d-L87NeC.js.map +0 -1
@@ -0,0 +1,1188 @@
1
+ import { B as profile } from "./issue-W0hT8u8D.js";
2
+ import { f as checkKey, t as accessOf } from "./access-BeSV5ve-.js";
3
+ //#region core/src/schema.ts
4
+ const collectionEntryNode = (node) => node.kind === "map" || node.kind === "table" || node.kind === "list" ? node.value : void 0;
5
+ const node = (value) => Object.freeze(value);
6
+ const field = (validator) => node({
7
+ kind: "field",
8
+ ...validator ? { validator } : {}
9
+ });
10
+ const optional = (value) => {
11
+ if (![
12
+ "field",
13
+ "variant",
14
+ "map",
15
+ "list",
16
+ "tree"
17
+ ].includes(value.kind)) throw new TypeError("Only field, variant, map, list and tree nodes support optional presence.");
18
+ return node({
19
+ ...value,
20
+ optional: true
21
+ });
22
+ };
23
+ const object = (shape) => node({
24
+ kind: "object",
25
+ shape: Object.freeze({ ...shape })
26
+ });
27
+ const variant = (tag, variants) => node({
28
+ kind: "variant",
29
+ tag,
30
+ variants: Object.freeze({ ...variants })
31
+ });
32
+ const table = (value, options) => node({
33
+ kind: "table",
34
+ value,
35
+ ...options
36
+ });
37
+ const map = (value, options) => node({
38
+ kind: "map",
39
+ value,
40
+ ...options
41
+ });
42
+ const list = (value, config) => node({
43
+ kind: "list",
44
+ keyOf: config.keyOf,
45
+ value
46
+ });
47
+ const tree = (value) => node({
48
+ kind: "tree",
49
+ value
50
+ });
51
+ const paths = /* @__PURE__ */ new WeakMap();
52
+ const pathProxy = (nodes, address, owner) => {
53
+ const proxy = new Proxy({}, { get: (_target, property) => {
54
+ if (typeof property !== "string") return void 0;
55
+ if (nodes.every((node) => collectionEntryNode(node) !== void 0) && property === "item") return (id) => {
56
+ if (typeof id !== "string") throw new TypeError("Collection keys must be strings.");
57
+ for (const node of nodes) if (node.kind === "table" || node.kind === "map") {
58
+ const invalid = checkKey(node.key, id, [...address, id]);
59
+ if (invalid) throw new TypeError(invalid.message);
60
+ }
61
+ return pathProxy(nodes.map((node) => collectionEntryNode(node)), [...address, id], owner);
62
+ };
63
+ const children = nodes.flatMap((node) => {
64
+ if (node.kind === "object") return Object.hasOwn(node.shape, property) ? [node.shape[property]] : [];
65
+ if (node.kind !== "variant") return [];
66
+ if (property === node.tag) return [field()];
67
+ return Object.values(node.variants).flatMap((branch) => Object.hasOwn(branch.shape, property) ? [branch.shape[property]] : []);
68
+ });
69
+ if (!children.length) throw new TypeError(`Invalid schema path segment: ${property}`);
70
+ return pathProxy(children, [...address, property], owner);
71
+ } });
72
+ paths.set(proxy, {
73
+ nodes,
74
+ address,
75
+ owner
76
+ });
77
+ return proxy;
78
+ };
79
+ const compilePath = (owner, kind, pick) => {
80
+ const scope = {};
81
+ const value = pick(pathProxy([owner], [], scope));
82
+ const selected = typeof value === "object" && value !== null ? paths.get(value) : void 0;
83
+ if (!selected || selected.owner !== scope) throw new TypeError("Selector must return a path from its callback.");
84
+ const collection = selected.nodes.every((node) => collectionEntryNode(node) !== void 0);
85
+ if (kind === "collection" && !collection) throw new TypeError("Collection selectors require a map, table or list path.");
86
+ return Object.freeze({
87
+ kind: kind === "auto" ? collection ? "collection" : "value" : kind,
88
+ schema: owner,
89
+ address: Object.freeze([...selected.address])
90
+ });
91
+ };
92
+ //#endregion
93
+ //#region core/src/projection/contract.ts
94
+ var ProjectionError = class extends Error {
95
+ constructor(phase, identity, revisions, cause) {
96
+ super(`Projection ${phase} failed: ${identity}`, { cause });
97
+ this.phase = phase;
98
+ this.identity = identity;
99
+ this.revisions = revisions;
100
+ this.name = "ProjectionError";
101
+ }
102
+ };
103
+ var ProjectionDisposedError = class extends Error {
104
+ constructor() {
105
+ super("Projection has been disposed.");
106
+ this.name = "ProjectionDisposedError";
107
+ }
108
+ };
109
+ //#endregion
110
+ //#region core/src/projection/scheduler.ts
111
+ const createScheduler = (onError) => {
112
+ let disposed = false;
113
+ let depth = 0;
114
+ let batchSequence = 0;
115
+ let activeBatch;
116
+ let phase = "idle";
117
+ let sequence = 0;
118
+ const sources = /* @__PURE__ */ new Set();
119
+ const processors = /* @__PURE__ */ new Set();
120
+ const pendingSources = /* @__PURE__ */ new Set();
121
+ const heap = [];
122
+ const queued = /* @__PURE__ */ new Set();
123
+ const completed = /* @__PURE__ */ new Set();
124
+ const emissions = /* @__PURE__ */ new Set();
125
+ const errors = [];
126
+ let reportingFailures = [];
127
+ const guards = /* @__PURE__ */ new Set();
128
+ const cleanups = /* @__PURE__ */ new Set();
129
+ const assertActive = () => {
130
+ if (disposed) throw new ProjectionDisposedError();
131
+ };
132
+ const assertIdle = () => {
133
+ assertActive();
134
+ if (phase !== "idle") throw new Error("Projection cannot be re-entered during processing or notification.");
135
+ };
136
+ const lock = (value) => guards.forEach((guard) => guard(value));
137
+ const enqueue = (processor) => {
138
+ if (processor.disposed || queued.has(processor)) return;
139
+ queued.add(processor);
140
+ profile.projection("scheduledNodes");
141
+ let index = heap.length;
142
+ heap.push(processor);
143
+ while (index > 0) {
144
+ const parent = index - 1 >> 1;
145
+ if (heap[parent].order < processor.order) break;
146
+ heap[index] = heap[parent];
147
+ index = parent;
148
+ }
149
+ heap[index] = processor;
150
+ };
151
+ const pop = () => {
152
+ const first = heap[0];
153
+ const last = heap.pop();
154
+ if (heap.length) {
155
+ let index = 0;
156
+ while (index * 2 + 1 < heap.length) {
157
+ let child = index * 2 + 1;
158
+ if (child + 1 < heap.length && heap[child + 1].order < heap[child].order) child++;
159
+ if (last.order < heap[child].order) break;
160
+ heap[index] = heap[child];
161
+ index = child;
162
+ }
163
+ heap[index] = last;
164
+ }
165
+ return first;
166
+ };
167
+ const revisionsOf = (producer) => producer.kind === "processor" ? producer.dependencies.map((output) => output.revision()) : producer.outputs.map((output) => output.revision());
168
+ const errorFor = (producer, cause, kind = producer.kind === "source" ? "source" : "processor") => new ProjectionError(kind, producer.name, revisionsOf(producer), cause);
169
+ const capture = (source) => {
170
+ if (disposed) return;
171
+ if (phase !== "idle") {
172
+ source.fault = errorFor(source, /* @__PURE__ */ new Error("Source changed while projection was running."), "source");
173
+ errors.push(source.fault);
174
+ throw source.fault;
175
+ }
176
+ pendingSources.add(source);
177
+ profile.projection("sourceEvents");
178
+ if (source.fault) errors.push(source.fault);
179
+ };
180
+ const settleCause = () => {
181
+ if (activeBatch?.cause !== void 0) return activeBatch.cause;
182
+ for (const source of pendingSources) {
183
+ const cause = source.pendingCause();
184
+ if (cause !== void 0) return cause;
185
+ }
186
+ };
187
+ const settle = () => {
188
+ if (disposed || depth || phase !== "idle") return;
189
+ phase = "compute";
190
+ lock(true);
191
+ const cause = settleCause();
192
+ try {
193
+ for (const source of pendingSources) {
194
+ if (source.disposed) continue;
195
+ const wasFaulted = source.fault !== void 0;
196
+ let changed = false;
197
+ let force = false;
198
+ if (!source.fault || source.recovering()) try {
199
+ const prepared = source.prepare(cause);
200
+ changed = prepared.changed;
201
+ force = prepared.force;
202
+ source.fault = void 0;
203
+ } catch (failure) {
204
+ source.fault = errorFor(source, failure, "source");
205
+ errors.push(source.fault);
206
+ }
207
+ const recovered = wasFaulted && !source.fault;
208
+ if (changed) source.publish();
209
+ if (source.fault || changed || force || recovered) {
210
+ const output = source.outputs[0];
211
+ emissions.add(output);
212
+ output.consumers.forEach(enqueue);
213
+ }
214
+ }
215
+ while (heap.length) {
216
+ const processor = pop();
217
+ if (processor.disposed) continue;
218
+ const wasFaulted = processor.fault !== void 0;
219
+ profile.projection("processedNodes");
220
+ let changedOutputs = Object.freeze([]);
221
+ const blocked = processor.dependencies.find((output) => output.owner.fault || output.owner.disposed);
222
+ if (blocked) processor.fault = errorFor(processor, blocked.owner.fault ?? new ProjectionDisposedError(), "blocked");
223
+ else {
224
+ const reset = wasFaulted || processor.dependencies.some((output) => output.reset());
225
+ try {
226
+ changedOutputs = processor.evaluate(reset, cause);
227
+ const dependencyFailure = processor.dependencies.find((output) => output.owner.fault)?.owner.fault;
228
+ if (dependencyFailure) throw dependencyFailure;
229
+ processor.fault = void 0;
230
+ } catch (failure) {
231
+ const error = errorFor(processor, failure);
232
+ processor.fault = error;
233
+ if (!reset) try {
234
+ changedOutputs = processor.evaluate(true, cause);
235
+ const dependencyFailure = processor.dependencies.find((output) => output.owner.fault)?.owner.fault;
236
+ if (dependencyFailure) throw dependencyFailure;
237
+ processor.fault = void 0;
238
+ errors.push(error);
239
+ } catch (rebuildFailure) {
240
+ processor.fault = errorFor(processor, rebuildFailure);
241
+ errors.push(processor.fault);
242
+ }
243
+ else errors.push(error);
244
+ }
245
+ }
246
+ completed.add(processor);
247
+ const recovered = wasFaulted && !processor.fault;
248
+ if (processor.fault) processor.outputs.forEach((output) => {
249
+ emissions.add(output);
250
+ output.consumers.forEach(enqueue);
251
+ });
252
+ else {
253
+ if (changedOutputs.length) {
254
+ processor.publish();
255
+ changedOutputs.forEach((output) => emissions.add(output));
256
+ }
257
+ (recovered ? processor.outputs : changedOutputs).forEach((output) => output.consumers.forEach(enqueue));
258
+ }
259
+ if (processor.fault || changedOutputs.length) profile.projection("publishedNodes");
260
+ }
261
+ } finally {
262
+ lock(false);
263
+ phase = "idle";
264
+ }
265
+ };
266
+ const flush = () => {
267
+ if (disposed || depth) return [];
268
+ if (pendingSources.size || completed.size) profile.projection("flushes");
269
+ phase = "notify";
270
+ lock(true);
271
+ const reportFailures = [];
272
+ try {
273
+ emissions.forEach((output) => output.emit((listener) => {
274
+ try {
275
+ listener();
276
+ } catch (cause) {
277
+ errors.push(errorFor(output.owner, cause, "listener"));
278
+ }
279
+ }));
280
+ for (const error of errors.slice()) try {
281
+ onError(error);
282
+ } catch (cause) {
283
+ reportFailures.push(cause);
284
+ }
285
+ return Object.freeze([...errors.map((error) => Object.freeze({
286
+ phase: error.phase === "listener" ? "listener" : "processor",
287
+ error
288
+ })), ...reportFailures.map((error) => Object.freeze({
289
+ phase: "listener",
290
+ error
291
+ }))]);
292
+ } finally {
293
+ pendingSources.forEach((source) => source.clear());
294
+ completed.forEach((processor) => processor.clear());
295
+ pendingSources.clear();
296
+ queued.clear();
297
+ completed.clear();
298
+ emissions.clear();
299
+ errors.length = 0;
300
+ reportingFailures = reportFailures;
301
+ lock(false);
302
+ phase = "idle";
303
+ }
304
+ };
305
+ const run = () => {
306
+ settle();
307
+ const result = flush();
308
+ const failures = reportingFailures;
309
+ reportingFailures = [];
310
+ if (failures.length) throw new AggregateError(failures, "Projection error reporter failed.");
311
+ return result;
312
+ };
313
+ const batch = (optionsOrCallback, maybeCallback) => {
314
+ assertIdle();
315
+ const options = typeof optionsOrCallback === "function" ? void 0 : optionsOrCallback;
316
+ const callback = typeof optionsOrCallback === "function" ? optionsOrCallback : maybeCallback;
317
+ if (!callback) throw new TypeError("Projection batch requires a callback.");
318
+ if (depth === 0) activeBatch = Object.freeze({
319
+ id: ++batchSequence,
320
+ ...options?.cause === void 0 ? {} : { cause: options.cause }
321
+ });
322
+ depth++;
323
+ let failed = false;
324
+ try {
325
+ const value = callback();
326
+ assertSynchronous(value);
327
+ return value;
328
+ } catch (error) {
329
+ failed = true;
330
+ throw error;
331
+ } finally {
332
+ depth--;
333
+ if (!depth) try {
334
+ if (failed) try {
335
+ run();
336
+ } catch {}
337
+ else run();
338
+ } finally {
339
+ activeBatch = void 0;
340
+ }
341
+ }
342
+ };
343
+ const releaseProducer = (producer) => {
344
+ assertIdle();
345
+ if (producer.outputs.some((output) => output.consumers.size)) throw new Error("Projection producer is still used by another processor.");
346
+ producer.disposed = true;
347
+ if (producer.kind === "processor") {
348
+ producer.dependencies.forEach((output) => output.consumers.delete(producer));
349
+ processors.delete(producer);
350
+ queued.delete(producer);
351
+ completed.delete(producer);
352
+ } else {
353
+ sources.delete(producer);
354
+ pendingSources.delete(producer);
355
+ }
356
+ producer.release();
357
+ producer.clear();
358
+ producer.outputs.forEach((output) => emissions.delete(output));
359
+ };
360
+ return {
361
+ assertActive,
362
+ assertIdle,
363
+ capture,
364
+ settle,
365
+ flush,
366
+ run,
367
+ guards,
368
+ cleanups,
369
+ get active() {
370
+ return !disposed;
371
+ },
372
+ addSource(source) {
373
+ assertIdle();
374
+ sources.add(source);
375
+ },
376
+ addProcessor(processor) {
377
+ assertIdle();
378
+ processors.add(processor);
379
+ processor.dependencies.forEach((output) => output.consumers.add(processor));
380
+ },
381
+ releaseProducer,
382
+ order: () => sequence++,
383
+ initialize(callback) {
384
+ assertIdle();
385
+ phase = "compute";
386
+ lock(true);
387
+ try {
388
+ return callback();
389
+ } finally {
390
+ lock(false);
391
+ phase = "idle";
392
+ }
393
+ },
394
+ batch,
395
+ batchContext: () => activeBatch,
396
+ dispose() {
397
+ if (disposed) return;
398
+ assertIdle();
399
+ disposed = true;
400
+ const failures = [];
401
+ cleanups.forEach((cleanup) => {
402
+ try {
403
+ cleanup();
404
+ } catch (error) {
405
+ failures.push(error);
406
+ }
407
+ });
408
+ cleanups.clear();
409
+ processors.forEach((processor) => {
410
+ processor.disposed = true;
411
+ try {
412
+ processor.release();
413
+ } catch (error) {
414
+ failures.push(error);
415
+ }
416
+ });
417
+ sources.forEach((source) => {
418
+ source.disposed = true;
419
+ try {
420
+ source.release();
421
+ } catch (error) {
422
+ failures.push(error);
423
+ }
424
+ });
425
+ processors.clear();
426
+ sources.clear();
427
+ pendingSources.clear();
428
+ heap.length = 0;
429
+ queued.clear();
430
+ completed.clear();
431
+ emissions.clear();
432
+ guards.clear();
433
+ errors.length = 0;
434
+ reportingFailures = [];
435
+ if (failures.length) throw new AggregateError(failures, "Projection cleanup failed.");
436
+ }
437
+ };
438
+ };
439
+ const assertSynchronous = (value) => {
440
+ if (value != null && (typeof value === "object" || typeof value === "function") && "then" in value && typeof value.then === "function") throw new TypeError("Projection callbacks must be synchronous.");
441
+ };
442
+ const assertScope = (active) => {
443
+ if (!active()) throw new Error("Projection reader or writer is no longer active.");
444
+ };
445
+ //#endregion
446
+ //#region core/src/projection/collection-output.ts
447
+ const height = (node) => node?.height ?? 0;
448
+ const makeTreeNode = (key, value, left, right) => Object.freeze({
449
+ key,
450
+ value,
451
+ left,
452
+ right,
453
+ height: Math.max(height(left), height(right)) + 1
454
+ });
455
+ const rotateLeft = (node) => {
456
+ const right = node.right;
457
+ return makeTreeNode(right.key, right.value, makeTreeNode(node.key, node.value, node.left, right.left), right.right);
458
+ };
459
+ const rotateRight = (node) => {
460
+ const left = node.left;
461
+ return makeTreeNode(left.key, left.value, left.left, makeTreeNode(node.key, node.value, left.right, node.right));
462
+ };
463
+ const rebalance = (node) => {
464
+ const balance = height(node.left) - height(node.right);
465
+ if (balance > 1) {
466
+ if (height(node.left.left) < height(node.left.right)) return rotateRight(makeTreeNode(node.key, node.value, rotateLeft(node.left), node.right));
467
+ return rotateRight(node);
468
+ }
469
+ if (balance < -1) {
470
+ if (height(node.right.right) < height(node.right.left)) return rotateLeft(makeTreeNode(node.key, node.value, node.left, rotateRight(node.right)));
471
+ return rotateLeft(node);
472
+ }
473
+ return node;
474
+ };
475
+ const treeSet = (node, key, value) => {
476
+ if (!node) return makeTreeNode(key, value);
477
+ if (key === node.key) return makeTreeNode(key, value, node.left, node.right);
478
+ if (key < node.key) return rebalance(makeTreeNode(node.key, node.value, treeSet(node.left, key, value), node.right));
479
+ return rebalance(makeTreeNode(node.key, node.value, node.left, treeSet(node.right, key, value)));
480
+ };
481
+ const treeMin = (node) => node.left ? treeMin(node.left) : node;
482
+ const treeRemove = (node, key) => {
483
+ if (!node) return void 0;
484
+ if (key < node.key) return rebalance(makeTreeNode(node.key, node.value, treeRemove(node.left, key), node.right));
485
+ if (key > node.key) return rebalance(makeTreeNode(node.key, node.value, node.left, treeRemove(node.right, key)));
486
+ if (!node.left) return node.right;
487
+ if (!node.right) return node.left;
488
+ const next = treeMin(node.right);
489
+ return rebalance(makeTreeNode(next.key, next.value, node.left, treeRemove(node.right, next.key)));
490
+ };
491
+ const treeGet = (node, key) => {
492
+ let current = node;
493
+ while (current) {
494
+ if (key === current.key) return current.value;
495
+ current = key < current.key ? current.left : current.right;
496
+ }
497
+ };
498
+ const treeHas = (node, key) => {
499
+ let current = node;
500
+ while (current) {
501
+ if (key === current.key) return true;
502
+ current = key < current.key ? current.left : current.right;
503
+ }
504
+ return false;
505
+ };
506
+ const treeFromSorted = (entries, start = 0, end = entries.length) => {
507
+ if (start >= end) return void 0;
508
+ const middle = start + end >> 1;
509
+ const [key, value] = entries[middle];
510
+ return makeTreeNode(key, value, treeFromSorted(entries, start, middle), treeFromSorted(entries, middle + 1, end));
511
+ };
512
+ /** Owns staged keyed intent, exact transitions and the persistent published lookup. */
513
+ const createCollectionOutput = () => {
514
+ const values = /* @__PURE__ */ new Map();
515
+ let ids = Object.freeze([]);
516
+ let staged = /* @__PURE__ */ new Map();
517
+ let nextIds = ids;
518
+ let change;
519
+ let initialized = false;
520
+ let reset = false;
521
+ let revision = 0;
522
+ let publishedRoot;
523
+ let explicitOrder;
524
+ let cleared = false;
525
+ const listeners = /* @__PURE__ */ new Set();
526
+ const hasNext = (key) => staged.has(key) ? staged.get(key).present : !cleared && values.has(key);
527
+ const getNext = (key) => {
528
+ const entry = staged.get(key);
529
+ return entry ? entry.present ? entry.value : void 0 : cleared ? void 0 : values.get(key);
530
+ };
531
+ const deriveIds = () => {
532
+ const result = cleared ? [] : ids.filter(hasNext);
533
+ for (const [key, entry] of staged) if (entry.present && (cleared || !values.has(key))) result.push(key);
534
+ return result;
535
+ };
536
+ const begin = (active, initialize) => {
537
+ staged = /* @__PURE__ */ new Map();
538
+ nextIds = ids;
539
+ change = void 0;
540
+ explicitOrder = void 0;
541
+ cleared = initialize;
542
+ reset = initialize;
543
+ const read = (next) => ({
544
+ get: (key) => {
545
+ assertScope(active);
546
+ return next ? getNext(key) : values.get(key);
547
+ },
548
+ has: (key) => {
549
+ assertScope(active);
550
+ return next ? hasNext(key) : values.has(key);
551
+ },
552
+ ids: () => {
553
+ assertScope(active);
554
+ return next ? Object.freeze(explicitOrder ? [...explicitOrder] : [...deriveIds()]) : ids;
555
+ }
556
+ });
557
+ return {
558
+ previous: read(false),
559
+ next: read(true),
560
+ output: {
561
+ set: (key, value) => {
562
+ assertScope(active);
563
+ if (typeof key !== "string") throw new TypeError("Projection keys must be strings.");
564
+ staged.set(key, {
565
+ present: true,
566
+ value
567
+ });
568
+ },
569
+ remove: (key) => {
570
+ assertScope(active);
571
+ staged.set(key, { present: false });
572
+ },
573
+ order: (order) => {
574
+ assertScope(active);
575
+ explicitOrder = Object.freeze([...order]);
576
+ }
577
+ }
578
+ };
579
+ };
580
+ const seal = (nextReset, isEqual) => {
581
+ if (cleared) {
582
+ for (const key of values.keys()) if (!staged.has(key)) staged.set(key, { present: false });
583
+ }
584
+ profile.projection("touchedKeys", staged.size);
585
+ const added = /* @__PURE__ */ new Set();
586
+ const removed = /* @__PURE__ */ new Set();
587
+ const updated = /* @__PURE__ */ new Set();
588
+ for (const [key, entry] of staged) {
589
+ const existed = values.has(key);
590
+ if (entry.present) {
591
+ if (!existed) added.add(key);
592
+ else if (!isEqual(values.get(key), entry.value)) updated.add(key);
593
+ else if (!nextReset) staged.delete(key);
594
+ } else if (existed) removed.add(key);
595
+ else staged.delete(key);
596
+ }
597
+ if (explicitOrder || added.size || removed.size) {
598
+ const order = explicitOrder ?? [...ids.filter((key) => !removed.has(key)), ...added];
599
+ if (new Set(order).size !== order.length || order.length !== values.size + added.size - removed.size || order.some((key) => !hasNext(key))) throw new TypeError("Projection order must contain every key exactly once.");
600
+ nextIds = ids.length === order.length && ids.every((key, index) => key === order[index]) ? ids : Object.freeze([...order]);
601
+ } else nextIds = ids;
602
+ const changedKeys = new Set([
603
+ ...added,
604
+ ...removed,
605
+ ...updated
606
+ ]);
607
+ profile.projection("changedKeys", changedKeys.size);
608
+ const addedEntries = [];
609
+ const updatedEntries = [];
610
+ const removedEntries = [];
611
+ for (const key of changedKeys) {
612
+ const beforePresent = values.has(key);
613
+ const afterPresent = hasNext(key);
614
+ if (beforePresent === afterPresent) {
615
+ if (!beforePresent || isEqual(values.get(key), getNext(key))) continue;
616
+ }
617
+ if (!beforePresent) addedEntries.push({
618
+ key,
619
+ after: getNext(key)
620
+ });
621
+ else if (!afterPresent) removedEntries.push({
622
+ key,
623
+ before: values.get(key)
624
+ });
625
+ else updatedEntries.push({
626
+ key,
627
+ before: values.get(key),
628
+ after: getNext(key)
629
+ });
630
+ }
631
+ const orderChanged = nextIds !== ids;
632
+ if (nextReset) change = Object.freeze({ kind: "reset" });
633
+ else if (addedEntries.length || updatedEntries.length || removedEntries.length || orderChanged) {
634
+ let commonOrderChanged = false;
635
+ if (orderChanged) {
636
+ const before = ids.filter((key) => !removed.has(key));
637
+ const after = nextIds.filter((key) => !added.has(key));
638
+ commonOrderChanged = before.some((key, index) => after[index] !== key);
639
+ }
640
+ change = Object.freeze({
641
+ kind: "incremental",
642
+ added: Object.freeze(addedEntries),
643
+ updated: Object.freeze(updatedEntries),
644
+ removed: Object.freeze(removedEntries),
645
+ ...commonOrderChanged ? { order: Object.freeze({
646
+ before: Object.freeze([...ids]),
647
+ after: Object.freeze([...nextIds])
648
+ }) } : {}
649
+ });
650
+ }
651
+ reset = nextReset;
652
+ return change !== void 0;
653
+ };
654
+ const context = (active, cause) => Object.freeze({
655
+ kind: "collection",
656
+ read: {
657
+ get: (key) => {
658
+ assertScope(active);
659
+ return getNext(key);
660
+ },
661
+ has: (key) => {
662
+ assertScope(active);
663
+ return hasNext(key);
664
+ },
665
+ ids: () => {
666
+ assertScope(active);
667
+ return nextIds;
668
+ }
669
+ },
670
+ change,
671
+ revision,
672
+ reset,
673
+ cause
674
+ });
675
+ const current = (check) => {
676
+ const root = publishedRoot;
677
+ const publishedIds = ids;
678
+ return Object.freeze({
679
+ get: (key) => {
680
+ check();
681
+ return treeGet(root, key);
682
+ },
683
+ has: (key) => {
684
+ check();
685
+ return treeHas(root, key);
686
+ },
687
+ ids: () => {
688
+ check();
689
+ return publishedIds;
690
+ }
691
+ });
692
+ };
693
+ return {
694
+ begin,
695
+ seal,
696
+ context,
697
+ current,
698
+ revision: () => revision,
699
+ reset: () => reset,
700
+ publish: () => {
701
+ if (change) if (change.kind === "reset") {
702
+ const entries = [];
703
+ for (const [key, entry] of staged) if (entry.present) entries.push([key, entry.value]);
704
+ entries.sort(([left], [right]) => left < right ? -1 : left > right ? 1 : 0);
705
+ publishedRoot = treeFromSorted(entries);
706
+ } else for (const [key, entry] of staged) publishedRoot = entry.present ? treeSet(publishedRoot, key, entry.value) : treeRemove(publishedRoot, key);
707
+ for (const [key, entry] of staged) if (entry.present) values.set(key, entry.value);
708
+ else values.delete(key);
709
+ if (change && initialized) revision++;
710
+ ids = nextIds;
711
+ initialized = true;
712
+ },
713
+ emit: (call) => {
714
+ const resetEvent = Object.freeze({ kind: "reset" });
715
+ Array.from(listeners).forEach((listener) => call(() => listener(change ?? resetEvent)));
716
+ },
717
+ clear: () => {
718
+ staged.clear();
719
+ nextIds = ids;
720
+ change = void 0;
721
+ reset = false;
722
+ explicitOrder = void 0;
723
+ cleared = false;
724
+ },
725
+ release: () => {
726
+ values.clear();
727
+ staged.clear();
728
+ publishedRoot = void 0;
729
+ listeners.clear();
730
+ ids = nextIds = Object.freeze([]);
731
+ change = void 0;
732
+ initialized = false;
733
+ revision = 0;
734
+ reset = false;
735
+ explicitOrder = void 0;
736
+ cleared = false;
737
+ },
738
+ subscribe: (listener) => listeners.add(listener),
739
+ unsubscribe: (listener) => listeners.delete(listener)
740
+ };
741
+ };
742
+ const mapRead = (value) => ({
743
+ get: (key) => value.get(key),
744
+ has: (key) => value.has(key),
745
+ ids: () => Object.freeze([...value.keys()])
746
+ });
747
+ /** Immutable map-like view over a CollectionRead. */
748
+ const collectionView = (read) => {
749
+ const ids = read.ids();
750
+ const entries = function* () {
751
+ for (const key of ids) yield [key, read.get(key)];
752
+ };
753
+ const values = function* () {
754
+ for (const key of ids) yield read.get(key);
755
+ };
756
+ const view = {
757
+ get: (key) => read.get(key),
758
+ has: (key) => read.has(key),
759
+ get size() {
760
+ return ids.length;
761
+ },
762
+ keys: () => ids[Symbol.iterator](),
763
+ values,
764
+ entries,
765
+ forEach: (callback, thisArg) => {
766
+ for (const key of ids) callback.call(thisArg, read.get(key), key, view);
767
+ },
768
+ [Symbol.iterator]: entries
769
+ };
770
+ return Object.freeze(view);
771
+ };
772
+ /** Eager durable view used when a processor result may retain its dependency value. */
773
+ const snapshotCollectionView = (read) => {
774
+ const ids = read.ids();
775
+ const values = /* @__PURE__ */ new Map();
776
+ for (const key of ids) values.set(key, read.get(key));
777
+ return collectionView(mapRead(values));
778
+ };
779
+ /**
780
+ * The one source-to-CollectionChange kernel. Candidate keys only narrow value work;
781
+ * exact membership/value/order semantics remain owned here.
782
+ */
783
+ const stageCollectionRead = (state, read, active, options) => {
784
+ const evaluation = state.begin(active, options.reset);
785
+ if (options.reset) {
786
+ const ids = read.ids();
787
+ profile.collectionView.idsScanned(ids.length);
788
+ for (const key of ids) {
789
+ profile.collectionView.mapped();
790
+ evaluation.output.set(key, read.get(key));
791
+ }
792
+ evaluation.output.order(ids);
793
+ } else {
794
+ const previous = state.current(() => void 0);
795
+ const keys = options.candidates ? [...new Set(options.candidates)] : [...new Set([...previous.ids(), ...read.ids()])];
796
+ if (!options.candidates) profile.collectionView.idsScanned(keys.length);
797
+ for (const key of keys) if (read.has(key)) {
798
+ profile.collectionView.mapped();
799
+ evaluation.output.set(key, read.get(key));
800
+ } else evaluation.output.remove(key);
801
+ if (options.orderMayChange || !options.candidates) {
802
+ const ids = read.ids();
803
+ if (options.candidates) profile.collectionView.idsScanned(ids.length);
804
+ evaluation.output.order(ids);
805
+ }
806
+ }
807
+ return state.seal(options.reset, options.isEqual ?? Object.is);
808
+ };
809
+ /** Exact net transition between two published map-like snapshots. */
810
+ const collectionChangeBetween = (previous, current, isEqual = Object.is) => {
811
+ const added = [];
812
+ const removed = [];
813
+ const updated = [];
814
+ for (const [key, before] of previous) if (!current.has(key)) removed.push({
815
+ key,
816
+ before
817
+ });
818
+ else {
819
+ const after = current.get(key);
820
+ if (!isEqual(before, after)) updated.push({
821
+ key,
822
+ before,
823
+ after
824
+ });
825
+ }
826
+ for (const [key, after] of current) if (!previous.has(key)) added.push({
827
+ key,
828
+ after
829
+ });
830
+ const beforeKeys = new Set(previous.keys());
831
+ const afterKeys = new Set(current.keys());
832
+ const beforeCommon = [...previous.keys()].filter((key) => afterKeys.has(key));
833
+ const afterCommon = [...current.keys()].filter((key) => beforeKeys.has(key));
834
+ const orderChanged = beforeCommon.some((key, index) => afterCommon[index] !== key);
835
+ if (!added.length && !removed.length && !updated.length && !orderChanged) return void 0;
836
+ return Object.freeze({
837
+ kind: "incremental",
838
+ added: Object.freeze(added),
839
+ updated: Object.freeze(updated),
840
+ removed: Object.freeze(removed),
841
+ ...orderChanged ? { order: Object.freeze({
842
+ before: Object.freeze([...previous.keys()]),
843
+ after: Object.freeze([...current.keys()])
844
+ }) } : {}
845
+ });
846
+ };
847
+ //#endregion
848
+ //#region core/src/projection/definition.ts
849
+ const projections = /* @__PURE__ */ new WeakMap();
850
+ const defineRef = (producer, output) => {
851
+ const handle = Object.freeze({});
852
+ projections.set(handle, Object.freeze({
853
+ producer,
854
+ output
855
+ }));
856
+ return handle;
857
+ };
858
+ const projectionRef = (projection) => {
859
+ const ref = projections.get(projection);
860
+ if (!ref) throw new TypeError("Unknown projection definition.");
861
+ return ref;
862
+ };
863
+ const producerOf = (projection) => projectionRef(projection).producer;
864
+ const isProjection = (value) => value !== null && typeof value === "object" && projections.has(value);
865
+ const ownProjection = (projection, owner) => {
866
+ const producer = producerOf(projection);
867
+ if (producer.owner !== void 0 && producer.owner !== owner) throw new TypeError("Projection producer already belongs to another scope.");
868
+ if (producer.kind === "processor") for (const dependency of producer.dependencies) {
869
+ const dependencyOwner = producerOf(dependency).owner;
870
+ if (dependencyOwner !== void 0 && dependencyOwner !== owner) throw new TypeError("A scope cannot depend on another scope.");
871
+ }
872
+ producer.owner = owner;
873
+ return projection;
874
+ };
875
+ const freezeOutput = (output) => Object.freeze({
876
+ kind: output.kind,
877
+ equality: output.equality,
878
+ ...output.path ? { path: Object.freeze([...output.path]) } : {}
879
+ });
880
+ const defineProcessor = (definition) => {
881
+ if (!Array.isArray(definition.dependencies)) throw new TypeError("Projection dependencies must be an array.");
882
+ definition.dependencies.forEach(projectionRef);
883
+ if (!definition.outputs.length) throw new TypeError("Projection processor requires an output.");
884
+ const producer = {
885
+ kind: "processor",
886
+ dependencies: Object.freeze([...definition.dependencies]),
887
+ outputs: Object.freeze(definition.outputs.map(freezeOutput)),
888
+ create: definition.create,
889
+ ...definition.name ? { name: definition.name } : {}
890
+ };
891
+ return Object.freeze(producer.outputs.map((_, output) => defineRef(producer, output)));
892
+ };
893
+ const defineSource = (source, output) => {
894
+ return defineRef({
895
+ kind: "source",
896
+ source,
897
+ output: freezeOutput(output)
898
+ }, 0);
899
+ };
900
+ const sourceValue = (source) => source.kind === "value" ? source.value : snapshotCollectionView(source.read);
901
+ const valueInput = (initial, equality = Object.is) => defineSource({
902
+ kind: "value-input",
903
+ initial,
904
+ equality
905
+ }, {
906
+ kind: "value",
907
+ equality
908
+ });
909
+ const collectionInput = (initial = /* @__PURE__ */ new Map()) => {
910
+ const entries = /* @__PURE__ */ new Map();
911
+ for (const [key, value] of initial) {
912
+ if (typeof key !== "string") throw new TypeError("Projection keys must be strings.");
913
+ entries.set(key, value);
914
+ }
915
+ return defineSource({
916
+ kind: "collection-input",
917
+ initial: entries
918
+ }, {
919
+ kind: "collection",
920
+ equality: Object.is
921
+ });
922
+ };
923
+ const input = Object.assign(valueInput, { collection: collectionInput });
924
+ function observe(source, selector) {
925
+ if (isExternalSource(source)) return source.kind === "collection" ? defineSource({
926
+ kind: "external-collection",
927
+ source
928
+ }, {
929
+ kind: "collection",
930
+ equality: Object.is
931
+ }) : defineSource({
932
+ kind: "external-value",
933
+ source,
934
+ equality: Object.is
935
+ }, {
936
+ kind: "value",
937
+ equality: Object.is
938
+ });
939
+ if ("current" in source && typeof source.current === "function") return defineSource({
940
+ kind: "readable",
941
+ readable: source,
942
+ equality: Object.is
943
+ }, {
944
+ kind: "value",
945
+ equality: Object.is
946
+ });
947
+ const document = source;
948
+ if (!selector) return defineSource({
949
+ kind: "document-value",
950
+ document
951
+ }, {
952
+ kind: "value",
953
+ equality: Object.is
954
+ });
955
+ const selected = compilePath(accessOf(document).schema, "auto", selector);
956
+ return selected.kind === "collection" ? defineSource({
957
+ kind: "document-collection",
958
+ document,
959
+ selector: selected
960
+ }, {
961
+ kind: "collection",
962
+ equality: Object.is
963
+ }) : defineSource({
964
+ kind: "document-value",
965
+ document,
966
+ selector: selected
967
+ }, {
968
+ kind: "value",
969
+ equality: Object.is
970
+ });
971
+ }
972
+ const isExternalSource = (source) => {
973
+ if (!source || typeof source !== "object") return false;
974
+ const candidate = source;
975
+ return (candidate.kind === "value" || candidate.kind === "collection") && typeof candidate.current === "function" && typeof candidate.revision === "function" && typeof candidate.subscribe === "function";
976
+ };
977
+ function derive(dependencies, compute, equality = Object.is) {
978
+ const [projection] = defineProcessor({
979
+ dependencies,
980
+ outputs: [{
981
+ kind: "value",
982
+ equality
983
+ }],
984
+ create: () => ({ evaluate: (evaluation) => {
985
+ const output = evaluation.outputs[0];
986
+ if (output.kind !== "value") throw new Error("derive requires a value output.");
987
+ const next = compute(...evaluation.sources.map(sourceValue));
988
+ assertSynchronous(next);
989
+ output.output.set(next);
990
+ } })
991
+ });
992
+ return projection;
993
+ }
994
+ //#endregion
995
+ //#region core/src/projection/advanced.ts
996
+ const resetCollectionChange = Object.freeze({ kind: "reset" });
997
+ const isRebuild = (value) => value !== null && typeof value === "object" && value.kind === "rebuild";
998
+ const publicValue = (source) => source.kind === "value" ? source.value : collectionView(source.read);
999
+ const publicInputs = (sources, reset) => ({
1000
+ values: Object.freeze(sources.map(publicValue)),
1001
+ changes: Object.freeze(sources.map((source) => source.kind === "collection" ? reset ? resetCollectionChange : source.change : void 0))
1002
+ });
1003
+ const validateDependencies = (dependencies) => {
1004
+ if (!Array.isArray(dependencies)) throw new TypeError("Incremental dependencies must be projections.");
1005
+ dependencies.forEach(projectionRef);
1006
+ };
1007
+ function createIncrementalValue(dependencies, processor) {
1008
+ validateDependencies(dependencies);
1009
+ const [projection] = defineProcessor({
1010
+ dependencies,
1011
+ outputs: [{
1012
+ kind: "value",
1013
+ equality: Object.is
1014
+ }],
1015
+ create: () => {
1016
+ const state = Object.create(null);
1017
+ return { evaluate: (evaluation) => {
1018
+ const output = evaluation.outputs[0];
1019
+ if (output.kind !== "value") throw new Error("Incremental value output is invalid.");
1020
+ const publicInput = publicInputs(evaluation.sources, evaluation.reset);
1021
+ const result = processor({
1022
+ sources: publicInput.values,
1023
+ changes: publicInput.changes,
1024
+ previous: output.previous,
1025
+ reset: evaluation.reset,
1026
+ cause: evaluation.cause,
1027
+ state
1028
+ });
1029
+ assertSynchronous(result);
1030
+ if (isRebuild(result)) return result;
1031
+ output.output.set(result);
1032
+ } };
1033
+ }
1034
+ });
1035
+ return projection;
1036
+ }
1037
+ function createIncrementalCollection(dependencies, processor) {
1038
+ validateDependencies(dependencies);
1039
+ const [projection] = defineProcessor({
1040
+ dependencies,
1041
+ outputs: [{
1042
+ kind: "collection",
1043
+ equality: Object.is
1044
+ }],
1045
+ create: () => {
1046
+ const state = Object.create(null);
1047
+ return { evaluate: (evaluation) => {
1048
+ const output = evaluation.outputs[0];
1049
+ if (output.kind !== "collection") throw new Error("Incremental collection output is invalid.");
1050
+ const publicInput = publicInputs(evaluation.sources, evaluation.reset);
1051
+ const result = processor({
1052
+ sources: publicInput.values,
1053
+ changes: publicInput.changes,
1054
+ previous: output.previous,
1055
+ next: output.next,
1056
+ reset: evaluation.reset,
1057
+ cause: evaluation.cause,
1058
+ state,
1059
+ output: output.output
1060
+ });
1061
+ assertSynchronous(result);
1062
+ return isRebuild(result) ? result : void 0;
1063
+ } };
1064
+ }
1065
+ });
1066
+ return projection;
1067
+ }
1068
+ const groupOutputMetadata = /* @__PURE__ */ new WeakMap();
1069
+ const isPlainGroupNamespace = (value) => value !== null && typeof value === "object" && !groupOutputMetadata.has(value) && !Array.isArray(value) && (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null);
1070
+ const compileGroupShape = (value, path, declaredOutputs, used, outputs) => {
1071
+ if (value !== null && typeof value === "object") {
1072
+ const metadata = groupOutputMetadata.get(value);
1073
+ if (metadata) {
1074
+ if (!declaredOutputs.has(value)) throw new TypeError("Incremental group outputs must be declared by this group.");
1075
+ if (used.has(value)) throw new TypeError("An incremental group output cannot be reused.");
1076
+ used.add(value);
1077
+ const index = outputs.length;
1078
+ outputs.push({
1079
+ kind: metadata.kind,
1080
+ equality: metadata.equality,
1081
+ path: Object.freeze([...path])
1082
+ });
1083
+ return index;
1084
+ }
1085
+ }
1086
+ if (!isPlainGroupNamespace(value)) throw new TypeError("Incremental group outputs must be a static object tree.");
1087
+ for (const key of Reflect.ownKeys(value)) {
1088
+ if (typeof key !== "string") throw new TypeError("Incremental group output names must be strings.");
1089
+ if (!Object.prototype.propertyIsEnumerable.call(value, key)) throw new TypeError("Incremental group namespaces must contain enumerable properties.");
1090
+ }
1091
+ const keys = Object.keys(value);
1092
+ if (!keys.length) throw new TypeError("Incremental group namespaces cannot be empty.");
1093
+ const result = Object.create(null);
1094
+ for (const key of keys) {
1095
+ if (key === "__proto__" || key === "prototype" || key === "constructor") throw new TypeError(`Invalid incremental group output name: ${key}`);
1096
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
1097
+ if (!descriptor || !("value" in descriptor)) throw new TypeError("Incremental group namespaces cannot contain accessors.");
1098
+ result[key] = compileGroupShape(descriptor.value, [...path, key], declaredOutputs, used, outputs);
1099
+ }
1100
+ return Object.freeze(result);
1101
+ };
1102
+ const hydrateGroupShape = (shape, values) => {
1103
+ if (typeof shape === "number") return values[shape];
1104
+ const result = {};
1105
+ for (const [key, child] of Object.entries(shape)) result[key] = hydrateGroupShape(child, values);
1106
+ return Object.freeze(result);
1107
+ };
1108
+ const hydrateGroupReads = (shape, outputs, next) => {
1109
+ if (typeof shape === "number") {
1110
+ const output = outputs[shape];
1111
+ return next && output.kind === "value" ? output.next() : next ? output.next : output.previous;
1112
+ }
1113
+ const result = {};
1114
+ for (const [key, child] of Object.entries(shape)) if (typeof child === "number" && next && outputs[child].kind === "value") Object.defineProperty(result, key, {
1115
+ enumerable: true,
1116
+ configurable: false,
1117
+ get: () => outputs[child].next()
1118
+ });
1119
+ else result[key] = hydrateGroupReads(child, outputs, next);
1120
+ return Object.freeze(result);
1121
+ };
1122
+ function createIncrementalGroup(dependencies, defineOutputs, processor) {
1123
+ validateDependencies(dependencies);
1124
+ if (typeof defineOutputs !== "function") throw new TypeError("Incremental group outputs must be declared by a callback.");
1125
+ if (typeof processor !== "function") throw new TypeError("Incremental group processor must be a function.");
1126
+ let active = true;
1127
+ const declaredOutputs = /* @__PURE__ */ new Set();
1128
+ const declared = defineOutputs({
1129
+ collection: (equality = Object.is) => {
1130
+ if (!active) throw new TypeError("Incremental group output declarations are synchronous.");
1131
+ const descriptor = Object.freeze({});
1132
+ groupOutputMetadata.set(descriptor, {
1133
+ kind: "collection",
1134
+ equality
1135
+ });
1136
+ declaredOutputs.add(descriptor);
1137
+ return descriptor;
1138
+ },
1139
+ value: (equality = Object.is) => {
1140
+ if (!active) throw new TypeError("Incremental group output declarations are synchronous.");
1141
+ const descriptor = Object.freeze({});
1142
+ groupOutputMetadata.set(descriptor, {
1143
+ kind: "value",
1144
+ equality
1145
+ });
1146
+ declaredOutputs.add(descriptor);
1147
+ return descriptor;
1148
+ }
1149
+ });
1150
+ assertSynchronous(declared);
1151
+ active = false;
1152
+ const outputs = [];
1153
+ const used = /* @__PURE__ */ new Set();
1154
+ const shape = compileGroupShape(declared, [], declaredOutputs, used, outputs);
1155
+ if (typeof shape === "number") throw new TypeError("Incremental group declarations must return an output namespace.");
1156
+ if (used.size === 0 || used.size !== declaredOutputs.size) throw new TypeError("Every incremental group output must be returned by the declaration.");
1157
+ return hydrateGroupShape(shape, defineProcessor({
1158
+ dependencies,
1159
+ outputs,
1160
+ create: () => {
1161
+ const state = Object.create(null);
1162
+ return { evaluate: (evaluation) => {
1163
+ const publicInput = publicInputs(evaluation.sources, evaluation.reset);
1164
+ const result = processor({
1165
+ sources: publicInput.values,
1166
+ changes: publicInput.changes,
1167
+ previous: hydrateGroupReads(shape, evaluation.outputs, false),
1168
+ next: hydrateGroupReads(shape, evaluation.outputs, true),
1169
+ outputs: hydrateGroupShape(shape, evaluation.outputs.map((output) => output.output)),
1170
+ reset: evaluation.reset,
1171
+ cause: evaluation.cause,
1172
+ state
1173
+ });
1174
+ assertSynchronous(result);
1175
+ return isRebuild(result) ? result : void 0;
1176
+ } };
1177
+ },
1178
+ name: `processor-group:${outputs.map((output) => output.path?.join(".") ?? "").join(",")}`
1179
+ }));
1180
+ }
1181
+ const incremental = Object.assign(createIncrementalValue, {
1182
+ collection: createIncrementalCollection,
1183
+ group: createIncrementalGroup
1184
+ });
1185
+ //#endregion
1186
+ export { list as C, table as D, optional as E, tree as O, field as S, object as T, createScheduler as _, observe as a, collectionEntryNode as b, projectionRef as c, createCollectionOutput as d, mapRead as f, assertSynchronous as g, assertScope as h, isProjection as i, variant as k, collectionChangeBetween as l, stageCollectionRead as m, derive as n, ownProjection as o, snapshotCollectionView as p, input as r, producerOf as s, incremental as t, collectionView as u, ProjectionDisposedError as v, map as w, compilePath as x, ProjectionError as y };
1187
+
1188
+ //# sourceMappingURL=advanced-COFJtWMT.js.map