doxum 0.1.22 → 0.1.23

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 (70) hide show
  1. package/README.md +14 -5
  2. package/dist/{advanced-CqrR_4dh.d.ts → advanced-CLJCWkHa.d.cts} +2 -2
  3. package/dist/{advanced-BTStm2cW.js → advanced-CRNHfJBu.js} +457 -425
  4. package/dist/advanced-CRNHfJBu.js.map +1 -0
  5. package/dist/{advanced-GKZ-CZ6a.cjs → advanced-Cle5g3B4.cjs} +590 -438
  6. package/dist/advanced-Cle5g3B4.cjs.map +1 -0
  7. package/dist/{advanced-CyR5o3Xr.d.cts → advanced-d6J61er9.d.ts} +2 -2
  8. package/dist/advanced.cjs +1 -1
  9. package/dist/advanced.d.cts +1 -1
  10. package/dist/advanced.d.ts +1 -1
  11. package/dist/advanced.js +1 -1
  12. package/dist/context-BcLKGfq8.cjs +149 -0
  13. package/dist/context-BcLKGfq8.cjs.map +1 -0
  14. package/dist/context-DFEaDUv5.js +84 -0
  15. package/dist/context-DFEaDUv5.js.map +1 -0
  16. package/dist/{contract-CxiNcqMn.d.ts → contract-SYJFP0lM.d.cts} +19 -75
  17. package/dist/{contract-CRrZ-3sF.d.cts → contract-ULPQmiEs.d.ts} +19 -75
  18. package/dist/driver-BD3DQOW6.cjs +382 -0
  19. package/dist/driver-BD3DQOW6.cjs.map +1 -0
  20. package/dist/{driver-BqRjwFmU.js → driver-yFfvDMX5.js} +155 -26
  21. package/dist/driver-yFfvDMX5.js.map +1 -0
  22. package/dist/index.cjs +2130 -529
  23. package/dist/index.cjs.map +1 -1
  24. package/dist/index.d.cts +6 -5
  25. package/dist/index.d.ts +6 -5
  26. package/dist/index.js +2003 -403
  27. package/dist/index.js.map +1 -1
  28. package/dist/local-sync.cjs +5 -5
  29. package/dist/local-sync.cjs.map +1 -1
  30. package/dist/local-sync.d.cts +1 -1
  31. package/dist/local-sync.d.ts +1 -1
  32. package/dist/local-sync.js +2 -2
  33. package/dist/local-sync.js.map +1 -1
  34. package/dist/react.cjs +2 -70
  35. package/dist/react.cjs.map +1 -1
  36. package/dist/react.d.cts +0 -1
  37. package/dist/react.d.ts +1 -2
  38. package/dist/react.js +3 -71
  39. package/dist/react.js.map +1 -1
  40. package/package.json +1 -6
  41. package/skills/doxum-runtime/SKILL.md +2 -1
  42. package/skills/doxum-runtime/references/guide.en.md +8 -6
  43. package/skills/doxum-runtime/references/guide.zh-CN.md +7 -5
  44. package/skills/doxum-runtime/references/invariants.en.md +5 -3
  45. package/skills/doxum-runtime/references/invariants.zh-CN.md +4 -3
  46. package/dist/access-CZXv_DIF.js +0 -958
  47. package/dist/access-CZXv_DIF.js.map +0 -1
  48. package/dist/access-D64MFRSm.cjs +0 -1101
  49. package/dist/access-D64MFRSm.cjs.map +0 -1
  50. package/dist/advanced-BTStm2cW.js.map +0 -1
  51. package/dist/advanced-GKZ-CZ6a.cjs.map +0 -1
  52. package/dist/driver-BC06FEMF.cjs +0 -241
  53. package/dist/driver-BC06FEMF.cjs.map +0 -1
  54. package/dist/driver-BqRjwFmU.js.map +0 -1
  55. package/dist/integration-BqDw7e2w.cjs +0 -30
  56. package/dist/integration-BqDw7e2w.cjs.map +0 -1
  57. package/dist/integration-CSXaF8HP.js +0 -25
  58. package/dist/integration-CSXaF8HP.js.map +0 -1
  59. package/dist/integration.cjs +0 -13
  60. package/dist/integration.d.cts +0 -17
  61. package/dist/integration.d.ts +0 -17
  62. package/dist/integration.js +0 -5
  63. package/dist/issue-9U6YLYz3.js +0 -647
  64. package/dist/issue-9U6YLYz3.js.map +0 -1
  65. package/dist/issue-Bo0FIO3b.cjs +0 -886
  66. package/dist/issue-Bo0FIO3b.cjs.map +0 -1
  67. package/dist/notification-CrZHVx3a.js +0 -176
  68. package/dist/notification-CrZHVx3a.js.map +0 -1
  69. package/dist/notification-DFoA9bQY.cjs +0 -235
  70. package/dist/notification-DFoA9bQY.cjs.map +0 -1
package/dist/index.cjs CHANGED
@@ -1,107 +1,1026 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_issue = require("./issue-Bo0FIO3b.cjs");
3
- const require_access = require("./access-D64MFRSm.cjs");
4
- const require_advanced = require("./advanced-GKZ-CZ6a.cjs");
5
- const require_driver = require("./driver-BC06FEMF.cjs");
6
- const require_notification = require("./notification-DFoA9bQY.cjs");
2
+ const require_advanced = require("./advanced-Cle5g3B4.cjs");
3
+ const require_context = require("./context-BcLKGfq8.cjs");
4
+ const require_driver = require("./driver-BD3DQOW6.cjs");
5
+ //#region core/src/address/resolve.ts
6
+ const variantNode = (node, value) => {
7
+ const tag = require_context.isRecord(value) && typeof value[node.tag] === "string" ? value[node.tag] : void 0;
8
+ return node.variants[String(tag ?? Object.keys(node.variants)[0] ?? "")];
9
+ };
10
+ const step = (nodeInput, value, segment) => {
11
+ let node = nodeInput;
12
+ if (!node) return void 0;
13
+ if (node.kind === "variant") node = variantNode(node, value);
14
+ if (!node) return void 0;
15
+ if (node.kind === "object") return Object.hasOwn(node.shape, segment) ? node.shape[segment] : void 0;
16
+ if (node.kind === "table" || node.kind === "map") return node.value;
17
+ if (node.kind === "list") return node.value;
18
+ };
19
+ const nodeAt = (schema, address, document) => {
20
+ let node = schema;
21
+ let value = document;
22
+ for (const segment of address) {
23
+ const resolved = step(node, value, segment);
24
+ value = readSegment(value, segment, node);
25
+ node = resolved;
26
+ if (!node) return void 0;
27
+ }
28
+ return node;
29
+ };
30
+ const readSegment = (value, segment, node) => {
31
+ if (!require_context.isRecord(value) && !Array.isArray(value)) return void 0;
32
+ if (node?.kind === "list" && Array.isArray(value)) return value[require_advanced.indexedKeys(value, node.keyOf).index(segment)];
33
+ if (node?.kind === "table" && require_context.isRecord(value) && require_context.isRecord(value.byId)) return Object.hasOwn(value.byId, segment) ? value.byId[segment] : void 0;
34
+ return Object.prototype.hasOwnProperty.call(value, segment) ? value[segment] : void 0;
35
+ };
36
+ const resolveContainer = (owner, generation, at, node, value) => {
37
+ if (!node || !require_context.isRecord(value) && !Array.isArray(value)) return void 0;
38
+ const parent = node.kind === "table" && require_context.isRecord(value) ? value.byId : value;
39
+ if (!require_context.isRecord(parent) && !Array.isArray(parent)) return void 0;
40
+ if (node.kind === "tree") return void 0;
41
+ const layout = require_advanced.compiledLayout(node, value);
42
+ if (!layout) return void 0;
43
+ return {
44
+ owner,
45
+ generation,
46
+ at,
47
+ node,
48
+ parent,
49
+ value,
50
+ layout
51
+ };
52
+ };
53
+ const resolveTreeContainer = (owner, generation, at, node, value) => node?.kind === "tree" && require_context.is(value) ? {
54
+ owner,
55
+ generation,
56
+ at,
57
+ node,
58
+ value
59
+ } : void 0;
60
+ const memberKey = (container, key) => container.node.kind === "list" ? require_advanced.indexedKeys(container.parent, container.node.keyOf).index(key) : key;
61
+ /** One recent path per transaction; structural writes invalidate all retained locations. */
62
+ const createAddressResolver = (schema, root) => {
63
+ const prefix = [];
64
+ return {
65
+ container: (owner, generation, at) => {
66
+ if (!at.length) return resolveContainer(owner, generation, at, schema, root);
67
+ const location = resolveWithPrefix(schema, root, at, prefix);
68
+ if (!location || !Object.hasOwn(location.parent, location.key)) return void 0;
69
+ return resolveContainer(owner, generation, at, location.node, location.parent[location.key]);
70
+ },
71
+ invalidate: () => {
72
+ prefix.length = 0;
73
+ }
74
+ };
75
+ };
76
+ /** A subtree root is a value, not a fabricated member of an ObjectNode. */
77
+ const resolveValue = (schema, root, address, prefix) => {
78
+ if (!address.length) return {
79
+ node: schema,
80
+ value: root
81
+ };
82
+ const location = resolveWithPrefix(schema, root, address, prefix);
83
+ return location && {
84
+ node: location.node,
85
+ value: Object.hasOwn(location.parent, location.key) ? location.parent[location.key] : void 0
86
+ };
87
+ };
88
+ /** Resolves schema and document location in one address traversal. */
89
+ const resolveLocated = (schema, root, address) => resolveWithPrefix(schema, root, address);
90
+ const resolveWithPrefix = (schema, root, address, prefix) => {
91
+ if (address.length === 0) return void 0;
92
+ let node = schema;
93
+ let current = root;
94
+ let start = 0;
95
+ if (prefix) {
96
+ while (start < prefix.length && start < address.length - 1 && prefix[start].segment === address[start]) start++;
97
+ prefix.length = start;
98
+ if (start) {
99
+ const retained = prefix[start - 1];
100
+ node = retained.node;
101
+ current = retained.value;
102
+ }
103
+ }
104
+ let cacheable = true;
105
+ for (let index = start; index < address.length - 1; index += 1) {
106
+ require_advanced.profile.address.schemaStep();
107
+ require_advanced.profile.address.documentStep();
108
+ const resolved = step(node, current, address[index]);
109
+ if (!resolved) return void 0;
110
+ if (node?.kind !== "object" && node?.kind !== "table" && node?.kind !== "map") cacheable = false;
111
+ current = readSegment(current, address[index], node);
112
+ node = resolved;
113
+ if (prefix && cacheable) prefix.push({
114
+ segment: address[index],
115
+ node: resolved,
116
+ value: current
117
+ });
118
+ if (!node) return void 0;
119
+ }
120
+ const last = address[address.length - 1];
121
+ return resolveChild(node, current, last);
122
+ };
123
+ /** Resolves one member from an already current schema/container pair. */
124
+ const resolveChild = (node, current, last) => {
125
+ require_advanced.profile.address.schemaStep();
126
+ require_advanced.profile.address.documentStep();
127
+ const resolved = step(node, current, last);
128
+ if (!resolved || !require_context.isRecord(current) && !Array.isArray(current)) return void 0;
129
+ if (node?.kind === "table" && require_context.isRecord(current) && require_context.isRecord(current.byId)) return {
130
+ node: resolved,
131
+ parent: current.byId,
132
+ key: last
133
+ };
134
+ return {
135
+ node: resolved,
136
+ parent: current,
137
+ key: node?.kind === "list" && Array.isArray(current) ? require_advanced.indexedKeys(current, node.keyOf).index(last) : last
138
+ };
139
+ };
140
+ //#endregion
141
+ //#region core/src/mutation/operations/map.ts
142
+ function put(session, container, id, value) {
143
+ if (container.node.kind !== "map") return require_driver.fail(container.at, "invalid-collection", "Expected a map.");
144
+ session.writeMember(container, id, value, "set");
145
+ }
146
+ function remove$3(session, container, id) {
147
+ if (container.node.kind !== "map") return require_driver.fail(container.at, "invalid-collection", "Expected a map.");
148
+ session.writeMember(container, id, void 0, "remove");
149
+ }
150
+ //#endregion
151
+ //#region core/src/order/anchor.ts
152
+ const length = (keys) => keys.length;
153
+ const keyIndex = (keys, key) => Array.isArray(keys) ? keys.indexOf(key) : keys.index(key);
154
+ /** Plan one relative move against the order that remains after removing the selection. */
155
+ const moveSelection = (current, selection, position) => {
156
+ if (!selection.length) return {
157
+ kind: "ok",
158
+ order: current
159
+ };
160
+ const selected = /* @__PURE__ */ new Set();
161
+ for (const key of selection) {
162
+ if (selected.has(key)) return { kind: "duplicate" };
163
+ selected.add(key);
164
+ }
165
+ const moved = [];
166
+ const remaining = [];
167
+ for (const key of current) (selected.has(key) ? moved : remaining).push(key);
168
+ if (moved.length !== selected.size) return { kind: "missing" };
169
+ if (!valid(remaining, position)) return { kind: "invalid-anchor" };
170
+ const insertion = index(remaining, position);
171
+ return {
172
+ kind: "ok",
173
+ order: [
174
+ ...remaining.slice(0, insertion),
175
+ ...moved,
176
+ ...remaining.slice(insertion)
177
+ ]
178
+ };
179
+ };
180
+ const index = (keys, anchor) => {
181
+ if (!anchor) return length(keys);
182
+ if ("at" in anchor) return anchor.at === "start" ? 0 : length(keys);
183
+ if ("before" in anchor) return keyIndex(keys, anchor.before);
184
+ return keyIndex(keys, anchor.after) + 1;
185
+ };
186
+ const valid = (keys, anchor) => {
187
+ if (!anchor) return true;
188
+ if (typeof anchor !== "object" || anchor === null) return false;
189
+ if (Number("at" in anchor) + Number("before" in anchor) + Number("after" in anchor) !== 1) return false;
190
+ if ("at" in anchor) return anchor.at === "start" || anchor.at === "end";
191
+ return keyIndex(keys, "before" in anchor ? anchor.before : anchor.after) >= 0;
192
+ };
193
+ //#endregion
194
+ //#region core/src/mutation/operations/table.ts
195
+ function create(session, container, entries, position) {
196
+ const { at, node, value } = container;
197
+ if (node.kind !== "table") return require_driver.fail(at, "invalid-collection", "Expected a table.");
198
+ const table = value;
199
+ if (!valid(table.ids, position)) return require_driver.fail(at, "invalid-anchor", "Unknown table anchor.");
200
+ const ids = /* @__PURE__ */ new Set();
201
+ for (const entry of entries) {
202
+ if (Object.hasOwn(table.byId, entry.id) || ids.has(entry.id)) return require_driver.fail(at, "duplicate-entity", "Table key already exists.");
203
+ ids.add(entry.id);
204
+ }
205
+ if (!entries.length) return;
206
+ const index$1 = index(table.ids, position);
207
+ for (const entry of entries) session.writeMember(container, entry.id, entry.value, "set");
208
+ const length = table.ids.length;
209
+ table.ids.length += entries.length;
210
+ table.ids.copyWithin(index$1 + entries.length, index$1, length);
211
+ for (let i = 0; i < entries.length; i++) table.ids[index$1 + i] = entries[i].id;
212
+ }
213
+ function remove$2(session, container, ids) {
214
+ const { at, node, value } = container;
215
+ if (node.kind !== "table") return require_driver.fail(at, "invalid-collection", "Expected a table.");
216
+ const table = value;
217
+ for (const id of ids) if (!Object.hasOwn(table.byId, id)) return require_driver.fail(at, "missing-entity", "Table key does not exist.");
218
+ if (!ids.length) return;
219
+ const removed = new Set(ids);
220
+ for (const id of removed) session.writeMember(container, id, void 0, "remove");
221
+ table.ids = table.ids.filter((id) => !removed.has(id));
222
+ }
223
+ function replace$3(session, container, id, value) {
224
+ const { at, node, value: tableValue } = container;
225
+ if (node.kind !== "table") return require_driver.fail(at, "invalid-collection", "Expected a table.");
226
+ const table = tableValue;
227
+ if (!Object.hasOwn(table.byId, id)) return require_driver.fail(at.concat(id), "missing-entity", "Table key does not exist.");
228
+ session.writeMember(container, id, value, "set");
229
+ }
230
+ //#endregion
231
+ //#region core/src/mutation/operations/list.ts
232
+ function insert$1(session, container, value, position) {
233
+ const { at, node, value: current } = container;
234
+ if (node.kind !== "list") return require_driver.fail(at, "invalid-list-key", "Expected a list.");
235
+ session.validate(node.value, value, at);
236
+ const id = node.keyOf(value);
237
+ if (typeof id !== "string") return require_driver.fail(at, "invalid-list-key", "List key must be a string.");
238
+ const items = current, keys$1 = require_advanced.keys(items, node.keyOf);
239
+ if (keys$1.index(id) >= 0) return require_driver.fail(at, "duplicate-list-item", "List key already exists.");
240
+ if (!valid(keys$1, position)) return require_driver.fail(at, "invalid-anchor", "Unknown list anchor.");
241
+ session.recorder.order(container);
242
+ session.recorder.member(container, id, session.definition(container, id), -1);
243
+ require_advanced.insert(items, index(keys$1, position), value);
244
+ session.invalidate();
245
+ }
246
+ function replace$2(session, container, id, value) {
247
+ const { at, node, value: items } = container;
248
+ if (node.kind !== "list") return require_driver.fail(at, "invalid-list-key", "Expected a list.");
249
+ const index = require_advanced.indexedKeys(items, node.keyOf).index(id);
250
+ if (index < 0) return require_driver.fail(at, "missing-list-item", "List key does not exist.");
251
+ session.writeMember(container, id, value, "set", index);
252
+ }
253
+ function remove$1(session, container, id) {
254
+ const { at, node, value } = container;
255
+ if (node.kind !== "list") return require_driver.fail(at, "missing-list-item", "List key does not exist.");
256
+ const index = require_advanced.keys(value, node.keyOf).index(id);
257
+ if (index < 0) return require_driver.fail(at, "missing-list-item", "List key does not exist.");
258
+ session.writeMember(container, id, void 0, "remove", index);
259
+ }
260
+ //#endregion
261
+ //#region core/src/mutation/operations/tree.ts
262
+ const node$1 = (tree, id) => Object.hasOwn(tree.nodes, id) ? tree.nodes[id] : void 0;
263
+ const positionIndex = (index, length, at) => {
264
+ if (index !== void 0 && (!Number.isInteger(index) || index < 0)) return require_driver.fail(at, "invalid-tree-index", "Tree index must be nonnegative.");
265
+ return Math.min(index ?? length, length);
266
+ };
267
+ const insert = (session, container, id, value, position) => {
268
+ const { at, node: schema, value: tree } = container;
269
+ if (typeof id !== "string") return require_driver.fail(at, "invalid-key", "Tree keys must be strings.");
270
+ if (require_context.contains(tree, id)) return require_driver.fail(at, "duplicate-tree-node", "Tree node already exists.");
271
+ const parentId = position?.parentId;
272
+ const parent = parentId === void 0 ? void 0 : node$1(tree, parentId);
273
+ if (tree.rootId !== void 0 && !parent || tree.rootId === void 0 && parentId !== void 0) return require_driver.fail(at, "missing-tree-parent", "A nonempty tree requires an existing parent.");
274
+ const index = positionIndex(position?.index, parent?.children.length ?? 0, at);
275
+ session.validate(schema.value, value, at.concat(id));
276
+ session.recorder.tree(container, id);
277
+ if (parentId !== void 0) session.recorder.tree(container, parentId);
278
+ Object.defineProperty(tree.nodes, id, {
279
+ value: {
280
+ ...parentId === void 0 ? {} : { parentId },
281
+ children: [],
282
+ value
283
+ },
284
+ writable: true,
285
+ configurable: true,
286
+ enumerable: true
287
+ });
288
+ if (parent) parent.children.splice(index, 0, id);
289
+ else tree.rootId = id;
290
+ session.invalidate();
291
+ };
292
+ const replace$1 = (session, container, id, value) => {
293
+ const { at, node: schema, value: tree } = container;
294
+ const entry = node$1(tree, id);
295
+ if (!entry) return require_driver.fail(at, "missing-tree-node", "Tree node does not exist.");
296
+ if (Object.is(entry.value, value) && Object.hasOwn(entry, "value")) return;
297
+ session.validate(schema.value, value, at.concat(id));
298
+ session.recorder.tree(container, id);
299
+ entry.value = value;
300
+ };
301
+ const remove = (session, container, id) => {
302
+ const { at, value: tree } = container;
303
+ const entry = node$1(tree, id);
304
+ if (!entry) return require_driver.fail(at, "missing-tree-node", "Tree node does not exist.");
305
+ const ids = [], stack = [id];
306
+ while (stack.length) {
307
+ const current = stack.pop();
308
+ ids.push(current);
309
+ for (const child of tree.nodes[current].children) stack.push(child);
310
+ }
311
+ for (const key of ids) session.recorder.tree(container, key);
312
+ if (entry.parentId !== void 0) session.recorder.tree(container, entry.parentId);
313
+ if (entry.parentId === void 0) delete tree.rootId;
314
+ else {
315
+ const children = tree.nodes[entry.parentId].children;
316
+ children.splice(children.indexOf(id), 1);
317
+ }
318
+ for (const key of ids) delete tree.nodes[key];
319
+ session.invalidate();
320
+ };
321
+ const move$1 = (session, container, id, position) => {
322
+ const { at, value: tree } = container;
323
+ const entry = node$1(tree, id), parentId = position?.parentId;
324
+ if (!entry) return require_driver.fail(at, "missing-tree-node", "Tree node does not exist.");
325
+ if (entry.parentId === void 0 || parentId === void 0 || !require_context.contains(tree, parentId)) return require_driver.fail(at, "missing-tree-parent", "Moving requires a non-root node and an existing parent.");
326
+ for (let ancestor = parentId; ancestor !== void 0; ancestor = tree.nodes[ancestor].parentId) if (ancestor === id) return require_driver.fail(at, "tree-cycle", "Cannot move a node under its descendant.");
327
+ const old = tree.nodes[entry.parentId], next = tree.nodes[parentId];
328
+ const index = positionIndex(position?.index, next.children.length - (old === next ? 1 : 0), at);
329
+ const previous = old.children.indexOf(id);
330
+ if (old === next && previous === index) return;
331
+ session.recorder.tree(container, id);
332
+ session.recorder.tree(container, entry.parentId);
333
+ session.recorder.tree(container, parentId);
334
+ old.children.splice(previous, 1);
335
+ next.children.splice(index, 0, id);
336
+ entry.parentId = parentId;
337
+ session.invalidate();
338
+ };
339
+ //#endregion
340
+ //#region core/src/mutation/operations/order.ts
341
+ const assertOrdered = (container) => {
342
+ const { at, node } = container;
343
+ if (node.kind !== "table" && node.kind !== "list") return require_driver.fail(at, "invalid-collection", "Expected an ordered container.");
344
+ return node;
345
+ };
346
+ const plannedOrder = (at, current, selection, position) => {
347
+ const plan = moveSelection(current, selection, position);
348
+ switch (plan.kind) {
349
+ case "ok": return plan.order;
350
+ case "duplicate": return require_driver.fail(at, "invalid-key", "Moved keys must be unique.");
351
+ case "missing": return require_driver.fail(at, "missing-entity", "Ordered key does not exist.");
352
+ case "invalid-anchor": return require_driver.fail(at, "invalid-anchor", "Unknown order anchor.");
353
+ }
354
+ };
355
+ function move(session, container, ids, position) {
356
+ const node = assertOrdered(container);
357
+ const selection = typeof ids === "string" ? [ids] : ids;
358
+ if (!selection.length) return;
359
+ if (node.kind === "table") {
360
+ const order = container.value.ids;
361
+ const next = plannedOrder(container.at, order, selection, position);
362
+ if (require_advanced.equal(order, next)) return;
363
+ session.recorder.order(container);
364
+ require_advanced.installKeys(order, next);
365
+ } else {
366
+ const items = container.value;
367
+ const current = require_advanced.listSequence(items, node.keyOf);
368
+ const next = plannedOrder(container.at, current.order, selection, position);
369
+ if (require_advanced.equal(current.order, next)) return;
370
+ session.recorder.order(container);
371
+ require_advanced.installList(items, node.keyOf, current, next);
372
+ }
373
+ session.invalidate();
374
+ }
375
+ function reorder(session, container, next) {
376
+ const node = assertOrdered(container);
377
+ if (node.kind === "table") {
378
+ const current = container.value.ids;
379
+ if (!require_advanced.matches(next, current)) return require_driver.fail(container.at, "invalid-collection", "Order must contain every key exactly once.");
380
+ if (require_advanced.equal(current, next)) return;
381
+ session.recorder.order(container);
382
+ require_advanced.installKeys(current, next);
383
+ } else {
384
+ const items = container.value;
385
+ const current = require_advanced.listSequence(items, node.keyOf);
386
+ if (!require_advanced.matches(next, current.order)) return require_driver.fail(container.at, "invalid-collection", "Order must contain every key exactly once.");
387
+ if (require_advanced.equal(current.order, next)) return;
388
+ session.recorder.order(container);
389
+ require_advanced.installList(items, node.keyOf, current, next);
390
+ }
391
+ session.invalidate();
392
+ }
393
+ //#endregion
394
+ //#region core/src/impact/target.ts
395
+ const treeRootSegment = "rootId";
396
+ const treeNodesSegment = "nodes";
397
+ const ordinaryNamespace = "\0value";
398
+ const treeNamespace = "\0tree";
399
+ const tree$1 = (at, selection) => ({
400
+ kind: "value",
401
+ at,
402
+ tree: selection
403
+ });
404
+ const address = (target) => "at" in target ? target.at : target.address;
405
+ const id = (target) => target.kind === "collection" && "id" in target ? target.id : void 0;
406
+ const belongs = (target, schema) => !("schema" in target) || target.schema === schema;
407
+ const treeTarget = (target) => "tree" in target ? target.tree : void 0;
408
+ const sameTreeTarget = (left, right) => {
409
+ if (!left || !right) return left === right;
410
+ if (left.kind !== right.kind) return false;
411
+ return left.kind !== "node" || right.kind === "node" && left.id === right.id;
412
+ };
413
+ const same = (left, right) => {
414
+ if ("schema" in left && "schema" in right && left.schema !== right.schema) return false;
415
+ if (!sameTreeTarget(treeTarget(left), treeTarget(right))) return false;
416
+ if (left.kind !== right.kind) return false;
417
+ const leftAddress = address(left);
418
+ const rightAddress = address(right);
419
+ if (leftAddress.length !== rightAddress.length) return false;
420
+ for (let index = 0; index < leftAddress.length; index += 1) if (leftAddress[index] !== rightAddress[index]) return false;
421
+ return left.kind !== "collection" || id(left) === id(right);
422
+ };
423
+ const indexedAddress = (target) => {
424
+ const tree = treeTarget(target);
425
+ if (tree?.kind === "root") return [
426
+ treeNamespace,
427
+ ...address(target),
428
+ treeRootSegment
429
+ ];
430
+ if (tree?.kind === "nodes") return [
431
+ treeNamespace,
432
+ ...address(target),
433
+ treeNodesSegment
434
+ ];
435
+ if (tree?.kind === "node") return [
436
+ treeNamespace,
437
+ ...address(target),
438
+ treeNodesSegment,
439
+ tree.id
440
+ ];
441
+ const key = id(target);
442
+ return key === void 0 ? [ordinaryNamespace, ...address(target)] : [
443
+ ordinaryNamespace,
444
+ ...address(target),
445
+ key
446
+ ];
447
+ };
448
+ const visitChangedLocations = (changes, value, order) => {
449
+ for (const change of changes.changes) {
450
+ if (change.kind === "reset") continue;
451
+ if (change.kind === "members") {
452
+ for (const member of change.members) {
453
+ value([
454
+ ordinaryNamespace,
455
+ ...change.at,
456
+ member.key
457
+ ]);
458
+ value([
459
+ treeNamespace,
460
+ ...change.at,
461
+ member.key
462
+ ]);
463
+ }
464
+ if (change.order) order([ordinaryNamespace, ...change.at]);
465
+ continue;
466
+ }
467
+ value([ordinaryNamespace, ...change.at]);
468
+ if (change.before !== change.after) value([
469
+ treeNamespace,
470
+ ...change.at,
471
+ treeRootSegment
472
+ ]);
473
+ for (const node of change.nodes) value([
474
+ treeNamespace,
475
+ ...change.at,
476
+ treeNodesSegment,
477
+ node.id
478
+ ]);
479
+ }
480
+ };
481
+ const affected = (target, values, orders) => {
482
+ const at = indexedAddress(target);
483
+ return id(target) !== void 0 ? values.hasAncestor(at) : values.overlaps(at) || orders.hasDescendant(at);
484
+ };
485
+ /** Targets are classified once; commit matching never builds a reverse impact index. */
486
+ var SubscriptionIndex = class {
487
+ ordinary = new require_driver.AddressIndex();
488
+ membership = new require_driver.AddressIndex();
489
+ constructor(schema) {
490
+ this.schema = schema;
491
+ }
492
+ add(target, value) {
493
+ if (!belongs(target, this.schema)) return;
494
+ (id(target) === void 0 ? this.ordinary : this.membership).add(indexedAddress(target), value);
495
+ }
496
+ delete(target, value) {
497
+ if (!belongs(target, this.schema)) return;
498
+ (id(target) === void 0 ? this.ordinary : this.membership).delete(indexedAddress(target), value);
499
+ }
500
+ collect(changes, visit) {
501
+ const values = this.ordinary.query(visit);
502
+ const members = this.membership.query(visit, "descendants");
503
+ const orders = this.ordinary.query(visit, "ancestors");
504
+ if (changes.changes.some((change) => change.kind === "reset")) {
505
+ values([]);
506
+ members([]);
507
+ return;
508
+ }
509
+ visitChangedLocations(changes, (at) => {
510
+ values(at);
511
+ members(at);
512
+ }, orders);
513
+ }
514
+ clear() {
515
+ this.ordinary.clear();
516
+ this.membership.clear();
517
+ }
518
+ };
519
+ //#endregion
520
+ //#region core/src/access/scope.ts
521
+ const locations = /* @__PURE__ */ new WeakMap();
522
+ const locationOf = (value) => locations.get(value);
523
+ const addressOf = (target) => {
524
+ if (target.at) return target.at;
525
+ require_advanced.profile.access("addresses");
526
+ return target.at = addressOf(target.parent).concat(target.key);
527
+ };
528
+ const assertActive = (context) => {
529
+ if (context.active && !context.active()) throw new Error("Document access scope has expired.");
530
+ };
531
+ const collect = (context, at, kind = "value", id) => {
532
+ context.dependencies?.record(kind === "value" ? {
533
+ kind,
534
+ at
535
+ } : {
536
+ kind,
537
+ at,
538
+ ...id === void 0 ? {} : { id }
539
+ });
540
+ };
541
+ const collectTree = (context, at, selection) => context.dependencies?.record(tree$1(at, selection));
542
+ const snapshot = (value) => {
543
+ const location = value && typeof value === "object" ? locationOf(value) : void 0;
544
+ if (!location) return value;
545
+ const { context } = location;
546
+ const at = addressOf(location.target);
547
+ require_advanced.profile.access("snapshots");
548
+ collect(context, at);
549
+ const resolved = resolve(context, location.target);
550
+ if (!resolved.node) throw new Error("The selected schema address no longer exists.");
551
+ return require_advanced.copyValue(resolved.node, resolved.value);
552
+ };
553
+ const replace = (container, key, value) => {
554
+ if (!locationOf(container)) throw new TypeError("replace requires scoped document access.");
555
+ if (typeof key !== "string") throw new TypeError("Document keys must be strings.");
556
+ Reflect.set(container, key, value);
557
+ };
558
+ const resolve = (context, target) => {
559
+ assertActive(context);
560
+ const generation = context.session?.generation ?? 0;
561
+ if (target.generation !== generation) {
562
+ require_advanced.profile.access("resolutions");
563
+ if (!target.parent && !target.at.length) {
564
+ target.node = context.state.schema;
565
+ target.value = context.state.document;
566
+ } else {
567
+ const parent = target.parent && resolve(context, target.parent);
568
+ const location = parent ? resolveChild(parent.node, parent.value, target.key) : resolveLocated(context.state.schema, context.state.document, target.at);
569
+ target.node = location?.node ?? nodeAt(context.state.schema, addressOf(target), context.state.document);
570
+ target.value = location && Object.hasOwn(location.parent, location.key) ? location.parent[location.key] : void 0;
571
+ }
572
+ target.generation = generation;
573
+ }
574
+ return target;
575
+ };
576
+ const createAccess = (context, initial = []) => {
577
+ require_advanced.profile.access("scopes");
578
+ const mutable = () => {
579
+ assertActive(context);
580
+ if (!context.session) throw new TypeError("Cannot modify read-only document access.");
581
+ return context.session;
582
+ };
583
+ const writableContainer = (target, session) => {
584
+ if (target.container?.generation === session.generation && "layout" in target.container) return target.container;
585
+ return target.container = session.bind(addressOf(target), target.node, target.value);
586
+ };
587
+ const childAt = (target, key) => {
588
+ require_advanced.profile.access("addresses");
589
+ return addressOf(target).concat(key);
590
+ };
591
+ const access = (target) => {
592
+ if (target.proxy) return target.proxy;
593
+ const proxy = new Proxy(target, handler);
594
+ require_advanced.profile.access("proxies");
595
+ locations.set(proxy, {
596
+ context,
597
+ target
598
+ });
599
+ target.proxy = proxy;
600
+ return proxy;
601
+ };
602
+ const createTarget = (at, parent, key) => ({
603
+ at,
604
+ parent,
605
+ key,
606
+ node: void 0,
607
+ value: void 0,
608
+ generation: -1,
609
+ children: void 0,
610
+ proxy: void 0
611
+ });
612
+ const childAccess = (target, member, node, value) => {
613
+ const key = typeof member === "string" ? member : member.key;
614
+ if (node.kind === "field" || value === void 0) {
615
+ if (context.dependencies) collect(context, childAt(target, key));
616
+ return value;
617
+ }
618
+ let children = target.children;
619
+ let child;
620
+ if (typeof member !== "string") {
621
+ if (children?.kind !== "fixed" || children.schema !== target.node) children = {
622
+ kind: "fixed",
623
+ schema: target.node,
624
+ slots: new Array(require_advanced.compiledShape(target.node, target.value).members.size)
625
+ };
626
+ child = children.slots[member.slot] ??= createTarget(void 0, target, key);
627
+ } else {
628
+ if (children?.kind !== "dynamic") children = {
629
+ kind: "dynamic",
630
+ keys: /* @__PURE__ */ new Map()
631
+ };
632
+ const retained = children.keys.get(key);
633
+ child = retained ?? createTarget(void 0, target, key);
634
+ if (!retained) children.keys.set(key, child);
635
+ }
636
+ target.children = children;
637
+ if (child.generation === target.generation) return child.proxy;
638
+ child.node = node;
639
+ child.value = value;
640
+ child.generation = target.generation;
641
+ return access(child);
642
+ };
643
+ const collectionValue = (target, node) => {
644
+ const current = resolve(context, target);
645
+ if (current.node !== node || current.value === void 0) throw new TypeError("The collection method belongs to a replaced schema branch.");
646
+ return current.value;
647
+ };
648
+ const writableCollection = (target, node) => {
649
+ const session = mutable();
650
+ collectionValue(target, node);
651
+ return writableContainer(target, session);
652
+ };
653
+ const writableTree = (target, node) => {
654
+ const session = mutable();
655
+ collectionValue(target, node);
656
+ if (target.container?.generation === session.generation && !("layout" in target.container)) return target.container;
657
+ return target.container = session.bindTree(addressOf(target), target.node, target.value);
658
+ };
659
+ const replaceCollection = (target, node, value) => {
660
+ const session = mutable();
661
+ collectionValue(target, node);
662
+ session.replace(addressOf(target), value);
663
+ };
664
+ const mapMethod = (target, property, node) => {
665
+ if (property === "ids") return () => {
666
+ const current = collectionValue(target, node);
667
+ if (context.dependencies) collect(context, addressOf(target), "collection");
668
+ return Object.keys(current);
669
+ };
670
+ if (property === "has") return (id) => {
671
+ const current = collectionValue(target, node);
672
+ if (context.dependencies) collect(context, addressOf(target), "collection", id);
673
+ return Object.hasOwn(current, id);
674
+ };
675
+ if (property === "get") return (id) => {
676
+ const current = collectionValue(target, node);
677
+ if (context.dependencies) collect(context, addressOf(target), "collection", id);
678
+ if (!Object.hasOwn(current, id)) return void 0;
679
+ if (node.value.kind === "field") {
680
+ if (context.dependencies) collect(context, childAt(target, id));
681
+ return current[id];
682
+ }
683
+ return childAccess(target, id, node.value, current[id]);
684
+ };
685
+ if (property === "put") return (id, value) => {
686
+ const writable = writableCollection(target, node);
687
+ put(context.session, writable, id, value);
688
+ };
689
+ if (property === "remove") return (id) => {
690
+ const writable = writableCollection(target, node);
691
+ remove$3(context.session, writable, id);
692
+ };
693
+ if (property === "replace") return (value) => replaceCollection(target, node, value);
694
+ };
695
+ const orderedMethod = (target, property, node) => {
696
+ const at = addressOf(target);
697
+ if (property === "ids") return () => {
698
+ const current = collectionValue(target, node);
699
+ collect(context, at, "collection");
700
+ return node.kind === "table" ? [...current.ids] : current.map(node.keyOf);
701
+ };
702
+ if (property === "has") return (id) => {
703
+ const current = collectionValue(target, node);
704
+ collect(context, at, "collection", id);
705
+ return node.kind === "table" ? Object.hasOwn(current.byId, id) : require_advanced.indexedKeys(current, node.keyOf).index(id) >= 0;
706
+ };
707
+ if (property === "get") return (id) => {
708
+ const current = collectionValue(target, node);
709
+ collect(context, at, "collection", id);
710
+ const location = resolveChild(node, current, id);
711
+ if (!location || !Object.hasOwn(location.parent, location.key)) return void 0;
712
+ return childAccess(target, id, location.node, location.parent[location.key]);
713
+ };
714
+ if (property === "move") return (ids, position) => {
715
+ const writable = writableCollection(target, node);
716
+ move(context.session, writable, ids, position);
717
+ };
718
+ if (property === "reorder") return (ids) => {
719
+ const writable = writableCollection(target, node);
720
+ reorder(context.session, writable, ids);
721
+ };
722
+ };
723
+ const tableMethod = (target, property, node) => {
724
+ if (property === "create") return (input, valueOrPosition, position) => {
725
+ const writable = writableCollection(target, node);
726
+ create(context.session, writable, Array.isArray(input) ? input : [{
727
+ id: input,
728
+ value: valueOrPosition
729
+ }], Array.isArray(input) ? valueOrPosition : position);
730
+ };
731
+ if (property === "remove") return (ids) => {
732
+ const writable = writableCollection(target, node);
733
+ remove$2(context.session, writable, typeof ids === "string" ? [ids] : ids);
734
+ };
735
+ if (property === "replace") return (...args) => {
736
+ const [valueOrId, value] = args;
737
+ if (args.length === 1) return replaceCollection(target, node, valueOrId);
738
+ const writable = writableCollection(target, node);
739
+ replace$3(context.session, writable, valueOrId, value);
740
+ };
741
+ return orderedMethod(target, property, node);
742
+ };
743
+ const listMethod = (target, property, node) => {
744
+ if (property === "insert") return (value, position) => {
745
+ const writable = writableCollection(target, node);
746
+ insert$1(context.session, writable, value, position);
747
+ };
748
+ if (property === "remove") return (id) => {
749
+ const writable = writableCollection(target, node);
750
+ remove$1(context.session, writable, id);
751
+ };
752
+ if (property === "replace") return (...args) => {
753
+ const [valueOrId, value] = args;
754
+ if (args.length === 1) return replaceCollection(target, node, valueOrId);
755
+ const writable = writableCollection(target, node);
756
+ replace$2(context.session, writable, valueOrId, value);
757
+ };
758
+ return orderedMethod(target, property, node);
759
+ };
760
+ const treeMethod = (target, property, node) => {
761
+ const at = addressOf(target);
762
+ if (property === "insert") return (id, value, position) => {
763
+ const writable = writableTree(target, node);
764
+ insert(context.session, writable, id, value, position);
765
+ };
766
+ if (property === "remove") return (id) => {
767
+ const writable = writableTree(target, node);
768
+ remove(context.session, writable, id);
769
+ };
770
+ if (property === "move") return (id, position) => {
771
+ const writable = writableTree(target, node);
772
+ move$1(context.session, writable, id, position);
773
+ };
774
+ if (property === "replace") return (...args) => {
775
+ const [valueOrId, value] = args;
776
+ if (args.length === 1) return replaceCollection(target, node, valueOrId);
777
+ const writable = writableTree(target, node);
778
+ replace$1(context.session, writable, valueOrId, value);
779
+ };
780
+ const current = () => collectionValue(target, node);
781
+ if (property === "rootId") return () => {
782
+ collectTree(context, at, { kind: "root" });
783
+ return current().rootId;
784
+ };
785
+ if (property === "get") return (id) => {
786
+ collectTree(context, at, {
787
+ kind: "node",
788
+ id
789
+ });
790
+ const value = current();
791
+ return require_context.contains(value, id) ? value.nodes[id].value : void 0;
792
+ };
793
+ if (property === "has") return (id) => {
794
+ collectTree(context, at, {
795
+ kind: "node",
796
+ id
797
+ });
798
+ return require_context.contains(current(), id);
799
+ };
800
+ if (property === "parent") return (id) => {
801
+ collectTree(context, at, {
802
+ kind: "node",
803
+ id
804
+ });
805
+ return require_context.parent(current(), id);
806
+ };
807
+ if (property === "children") return (id) => {
808
+ collectTree(context, at, {
809
+ kind: "node",
810
+ id
811
+ });
812
+ const children$1 = require_context.children(current(), id);
813
+ return children$1 ? [...children$1] : void 0;
814
+ };
815
+ };
816
+ const handler = {
817
+ get: (target, property) => {
818
+ const { node, value } = resolve(context, target);
819
+ if (!node || value === void 0) return void 0;
820
+ if (typeof property !== "string") return void 0;
821
+ if (node.kind === "map") return mapMethod(target, property, node);
822
+ if (node.kind === "table") return tableMethod(target, property, node);
823
+ if (node.kind === "list") return listMethod(target, property, node);
824
+ if (node.kind === "tree") return treeMethod(target, property, node);
825
+ if (node.kind === "variant" && property === node.tag) {
826
+ collect(context, childAt(target, property));
827
+ return value[property];
828
+ }
829
+ const member = require_advanced.compiledShape(node, value)?.members.get(property);
830
+ if (!member) return void 0;
831
+ if (member.field) {
832
+ if (context.dependencies) collect(context, childAt(target, property));
833
+ return value[property];
834
+ }
835
+ return childAccess(target, node.kind === "object" ? member : property, member.node, value[property]);
836
+ },
837
+ set: (target, property, value) => {
838
+ const session = mutable(), { node } = resolve(context, target);
839
+ if (typeof property !== "string" || !node || node.kind !== "object" && node.kind !== "variant") throw new TypeError("Invalid structural assignment.");
840
+ if (node.kind === "variant" && node.tag === property) throw new TypeError("Variant discriminants are read-only.");
841
+ session.assignMember(writableContainer(target, session), property, value);
842
+ return true;
843
+ },
844
+ deleteProperty: (target, property) => {
845
+ const session = mutable(), { node } = resolve(context, target);
846
+ if (typeof property !== "string" || node?.kind === "map" || node?.kind === "variant" && node.tag === property) throw new TypeError("Invalid structural deletion.");
847
+ session.removeMember(writableContainer(target, session), property);
848
+ return true;
849
+ },
850
+ has: (target, property) => {
851
+ const { node, value } = resolve(context, target);
852
+ if (typeof property !== "string") return false;
853
+ if (node?.kind === "map") return false;
854
+ collect(context, addressOf(target));
855
+ return value !== void 0 && Object.hasOwn(value, property);
856
+ },
857
+ ownKeys: (target) => {
858
+ const { node, value } = resolve(context, target);
859
+ if (node?.kind === "map") return [];
860
+ if (context.dependencies) collect(context, addressOf(target));
861
+ return value && typeof value === "object" ? Object.keys(value) : [];
862
+ },
863
+ getOwnPropertyDescriptor: (target, property) => {
864
+ const { node, value } = resolve(context, target);
865
+ if (node?.kind === "map") return void 0;
866
+ return value && Object.hasOwn(value, property) ? {
867
+ enumerable: true,
868
+ configurable: true
869
+ } : void 0;
870
+ },
871
+ defineProperty: () => {
872
+ assertActive(context);
873
+ throw new TypeError("Use schema assignments.");
874
+ },
875
+ setPrototypeOf: () => {
876
+ assertActive(context);
877
+ throw new TypeError("Document prototypes are immutable.");
878
+ },
879
+ preventExtensions: () => {
880
+ assertActive(context);
881
+ throw new TypeError("Document access cannot be frozen.");
882
+ }
883
+ };
884
+ const root = resolve(context, createTarget(initial, void 0, ""));
885
+ if (!root.node || root.node.kind === "field" || root.value === void 0) {
886
+ if (context.dependencies) collect(context, initial);
887
+ return root.value;
888
+ }
889
+ return access(root);
890
+ };
891
+ //#endregion
892
+ //#region core/src/address/relation.ts
893
+ const contains = (parent, child) => {
894
+ require_advanced.profile.address.prefixComparison();
895
+ if (parent.length > child.length) return false;
896
+ for (let index = 0; index < parent.length; index += 1) {
897
+ require_advanced.profile.address.segmentCompared();
898
+ if (parent[index] !== child[index]) return false;
899
+ }
900
+ return true;
901
+ };
902
+ //#endregion
7
903
  //#region core/src/impact.ts
8
- const queries = /* @__PURE__ */ new WeakMap();
9
904
  const createImpact = (schema, changes) => {
10
905
  const reset = changes.changes.some((change) => change.kind === "reset");
11
906
  let values;
12
907
  let orders;
13
908
  const index = () => {
14
909
  if (!values) {
15
- require_issue.profile.impact.index();
16
- values = new require_issue.AddressIndex();
17
- orders = new require_issue.AddressIndex();
18
- require_access.visitChangedLocations(changes, (at) => values.add(at, true), (at) => orders.add(at, true));
910
+ require_advanced.profile.impact.index();
911
+ values = new require_driver.AddressIndex();
912
+ orders = new require_driver.AddressIndex();
913
+ visitChangedLocations(changes, (at) => values.add(at, true), (at) => orders.add(at, true));
19
914
  }
20
915
  return values;
21
916
  };
22
917
  const cache = /* @__PURE__ */ new Map();
23
- const implementation = {
24
- affects(value) {
25
- require_issue.profile.impact.affects();
26
- if (!require_access.belongs(value, schema)) return false;
27
- if (reset) return true;
28
- return require_access.affected(value, index(), orders);
29
- },
30
- collection(selector) {
31
- if (selector.schema !== schema) throw new TypeError("Collection belongs to another root model.");
32
- const key = JSON.stringify(require_access.indexedAddress(selector)), cached = cache.get(key);
33
- if (cached) return cached;
34
- if (reset) {
35
- const result = { kind: "reset" };
36
- cache.set(key, result);
37
- return result;
38
- }
39
- const at = selector.address;
40
- const tree = selector.tree;
41
- const added = /* @__PURE__ */ new Set(), removed = /* @__PURE__ */ new Set(), updated = /* @__PURE__ */ new Set();
42
- let orderChanged = false;
43
- for (const change of changes.changes) {
44
- if (change.kind === "reset") continue;
45
- if (change.kind === "members") {
46
- if (change.at.length < at.length && require_issue.contains(change.at, at)) {
47
- if (change.members.some((member) => member.key === at[change.at.length])) {
48
- const result = { kind: "reset" };
49
- cache.set(key, result);
50
- return result;
51
- }
52
- } else if (require_issue.contains(at, change.at)) if (change.at.length === at.length) {
53
- if (change.order) {
54
- const positions = new Map(change.order.after.map((id, i) => [id, i]));
55
- let previous = -1;
56
- for (const id of change.order.before) {
57
- const position = positions.get(id);
58
- if (position === void 0) continue;
59
- if (position < previous) orderChanged = true;
60
- previous = position;
61
- }
918
+ const affects = (value) => {
919
+ require_advanced.profile.impact.affects();
920
+ if (!belongs(value, schema)) return false;
921
+ if (reset) return true;
922
+ return affected(value, index(), orders);
923
+ };
924
+ const collection = (selector) => {
925
+ if (selector.schema !== schema) throw new TypeError("Collection belongs to another root model.");
926
+ const key = JSON.stringify(indexedAddress(selector)), cached = cache.get(key);
927
+ if (cached) return cached;
928
+ if (reset) {
929
+ const result = { kind: "reset" };
930
+ cache.set(key, result);
931
+ return result;
932
+ }
933
+ const at = selector.address;
934
+ const tree = selector.tree;
935
+ const added = /* @__PURE__ */ new Set(), removed = /* @__PURE__ */ new Set(), updated = /* @__PURE__ */ new Set();
936
+ let orderChanged = false;
937
+ for (const change of changes.changes) {
938
+ if (change.kind === "reset") continue;
939
+ if (change.kind === "members") {
940
+ if (change.at.length < at.length && contains(change.at, at)) {
941
+ if (change.members.some((member) => member.key === at[change.at.length])) {
942
+ const result = { kind: "reset" };
943
+ cache.set(key, result);
944
+ return result;
945
+ }
946
+ } else if (contains(at, change.at)) if (change.at.length === at.length) {
947
+ if (change.order) {
948
+ const positions = new Map(change.order.after.map((id, i) => [id, i]));
949
+ let previous = -1;
950
+ for (const id of change.order.before) {
951
+ const position = positions.get(id);
952
+ if (position === void 0) continue;
953
+ if (position < previous) orderChanged = true;
954
+ previous = position;
62
955
  }
63
- for (const member of change.members) if (member.kind === "added") added.add(member.key);
64
- else if (member.kind === "removed") removed.add(member.key);
65
- else updated.add(member.key);
66
- } else updated.add(change.at[at.length]);
67
- continue;
68
- }
69
- if (change.kind === "tree" && require_issue.contains(change.at, at)) {
70
- if (tree?.kind === "nodes" && change.at.length === at.length && require_issue.contains(at, change.at)) {
71
- for (const node of change.nodes) if (node.kind === "added") added.add(node.id);
72
- else if (node.kind === "removed") removed.add(node.id);
73
- else updated.add(node.id);
74
- continue;
75
956
  }
76
- const result = { kind: "reset" };
77
- cache.set(key, result);
78
- return result;
957
+ for (const member of change.members) if (member.kind === "added") added.add(member.key);
958
+ else if (member.kind === "removed") removed.add(member.key);
959
+ else updated.add(member.key);
960
+ } else updated.add(change.at[at.length]);
961
+ continue;
962
+ }
963
+ if (change.kind === "tree" && contains(change.at, at)) {
964
+ if (tree?.kind === "nodes" && change.at.length === at.length && contains(at, change.at)) {
965
+ for (const node of change.nodes) if (node.kind === "added") added.add(node.id);
966
+ else if (node.kind === "removed") removed.add(node.id);
967
+ else updated.add(node.id);
968
+ continue;
79
969
  }
80
- if (!require_issue.contains(at, change.at)) continue;
81
- if (change.at.length === at.length) continue;
82
- const id = change.at[at.length];
83
- updated.add(id);
970
+ const result = { kind: "reset" };
971
+ cache.set(key, result);
972
+ return result;
84
973
  }
85
- added.forEach((id) => updated.delete(id));
86
- removed.forEach((id) => updated.delete(id));
87
- const result = {
88
- kind: "incremental",
89
- added,
90
- removed,
91
- updated,
92
- orderChanged
93
- };
94
- cache.set(key, result);
95
- return result;
974
+ if (!contains(at, change.at)) continue;
975
+ if (change.at.length === at.length) continue;
976
+ const id = change.at[at.length];
977
+ updated.add(id);
96
978
  }
979
+ added.forEach((id) => updated.delete(id));
980
+ removed.forEach((id) => updated.delete(id));
981
+ const result = {
982
+ kind: "incremental",
983
+ added,
984
+ removed,
985
+ updated,
986
+ orderChanged
987
+ };
988
+ cache.set(key, result);
989
+ return result;
97
990
  };
98
- const impact = Object.freeze({
991
+ return Object.freeze({
99
992
  kind: reset ? "reset" : "incremental",
100
- affects: (pick) => implementation.affects(require_advanced.compilePath(schema, "value", pick)),
101
- collection: (pick) => implementation.collection(require_advanced.compilePath(schema, "collection", pick))
993
+ affects: (pick) => affects(require_advanced.compilePath(schema, "value", pick)),
994
+ collection: (pick) => collection(require_advanced.compilePath(schema, "collection", pick))
102
995
  });
103
- queries.set(impact, implementation);
104
- return impact;
996
+ };
997
+ //#endregion
998
+ //#region core/src/runtime/contract.ts
999
+ var DocumentReentrancyError = class extends Error {
1000
+ constructor() {
1001
+ super("Document writes cannot be re-entered during an update or notification.");
1002
+ this.name = "DocumentReentrancyError";
1003
+ }
1004
+ };
1005
+ var DocumentDisposedError = class extends Error {
1006
+ constructor() {
1007
+ super("Doxum runtime has been disposed.");
1008
+ this.name = "DocumentDisposedError";
1009
+ }
1010
+ };
1011
+ var TransactionRejected = class extends Error {
1012
+ issues;
1013
+ constructor(input) {
1014
+ super("Document update rejected.");
1015
+ this.name = "TransactionRejected";
1016
+ const issues = Array.isArray(input) ? input : [input];
1017
+ this.issues = Object.freeze(issues.map((issue) => Object.freeze({
1018
+ code: issue.code,
1019
+ message: issue.message,
1020
+ source: "application",
1021
+ ...issue.address === void 0 ? {} : { address: Object.freeze([...issue.address]) }
1022
+ })));
1023
+ }
105
1024
  };
106
1025
  //#endregion
107
1026
  //#region core/src/history.ts
@@ -192,7 +1111,7 @@ const createHistory = (input) => {
192
1111
  current: () => state,
193
1112
  revision: () => revision,
194
1113
  subscribe: (listener) => {
195
- if (disposed) throw new require_access.DocumentDisposedError();
1114
+ if (disposed) throw new DocumentDisposedError();
196
1115
  listeners.add(listener);
197
1116
  return () => {
198
1117
  listeners.delete(listener);
@@ -274,25 +1193,18 @@ const createHistory = (input) => {
274
1193
  const installMember = (parent, key, present, value) => {
275
1194
  if (Array.isArray(parent)) {
276
1195
  const index = Number(key);
277
- if (present) if (index < 0) require_issue.insert(parent, parent.length, value);
1196
+ if (present) if (index < 0) require_advanced.insert(parent, parent.length, value);
278
1197
  else parent[index] = value;
279
- else if (index >= 0) require_issue.remove(parent, index);
280
- } else if (!present) delete parent[key];
281
- else if (Object.hasOwn(parent, key)) parent[key] = value;
282
- else Object.defineProperty(parent, key, {
283
- value,
284
- writable: true,
285
- configurable: true,
286
- enumerable: true
287
- });
1198
+ else if (index >= 0) require_advanced.remove(parent, index);
1199
+ } else require_context.installOwn(parent, key, present, value);
288
1200
  };
289
1201
  const orderOf = (node, value) => {
290
- if (node.kind === "list") return require_issue.toArray(require_issue.indexedKeys(value, node.keyOf));
1202
+ if (node.kind === "list") return require_advanced.toArray(require_advanced.indexedKeys(value, node.keyOf));
291
1203
  if (node.kind === "table") return [...value.ids];
292
1204
  throw new Error("Order requires a table or list.");
293
1205
  };
294
1206
  const installOrder = (node, value, order) => {
295
- if (node.kind === "list") require_issue.install(value, node.keyOf, order);
1207
+ if (node.kind === "list") require_advanced.install(value, node.keyOf, order);
296
1208
  else if (node.kind === "table") value.ids = [...order];
297
1209
  else throw new Error("Order requires a table or list.");
298
1210
  };
@@ -313,9 +1225,9 @@ const forgetMember = (group, key) => {
313
1225
  const emptyGroup = (group) => !group.order && (group.layout === "fixed" ? !group.members.some(Boolean) : !group.members?.size);
314
1226
  const transition = (node, key, beforePresent, before, afterPresent, after) => {
315
1227
  if (beforePresent === afterPresent && (!beforePresent || Object.is(before, after))) return;
316
- if (node.kind !== "field" && beforePresent === afterPresent && require_access.equalValue(node, before, after)) return;
317
- const value = afterPresent ? node.kind === "field" ? after : require_access.copyValue(node, after) : void 0;
318
- require_issue.profile.recorder("transitions");
1228
+ if (node.kind !== "field" && beforePresent === afterPresent && require_advanced.equalValue(node, before, after)) return;
1229
+ const value = afterPresent ? node.kind === "field" ? after : require_advanced.copyValue(node, after) : void 0;
1230
+ require_advanced.profile.recorder("transitions");
319
1231
  return !beforePresent ? {
320
1232
  key,
321
1233
  kind: "added",
@@ -356,7 +1268,7 @@ const diffMember = (changes, members, node, at, key, beforePresent, before, afte
356
1268
  const left = before, right = after;
357
1269
  const childAt = at.concat(key);
358
1270
  const children = [];
359
- for (const [child, definition] of require_issue.compiledShape(node, before).members) diffMember(changes, children, definition.node, childAt, child, Object.hasOwn(left, child), left[child], Object.hasOwn(right, child), right[child]);
1271
+ for (const [child, definition] of require_advanced.compiledShape(node, before).members) diffMember(changes, children, definition.node, childAt, child, Object.hasOwn(left, child), left[child], Object.hasOwn(right, child), right[child]);
360
1272
  publishMembers(changes, childAt, children);
361
1273
  return;
362
1274
  }
@@ -369,8 +1281,8 @@ const diffMember = (changes, members, node, at, key, beforePresent, before, afte
369
1281
  for (const id of Object.keys(left)) diffMember(changes, children, node.value, childAt, id, true, left[id], Object.hasOwn(right, id), right[id]);
370
1282
  for (const id of Object.keys(right)) if (!Object.hasOwn(left, id)) diffMember(changes, children, node.value, childAt, id, false, void 0, true, right[id]);
371
1283
  let order;
372
- if (node.kind === "table" && !require_issue.equal(a.ids, b.ids)) {
373
- require_issue.profile.recorder("publishedOrderItems", b.ids.length);
1284
+ if (node.kind === "table" && !require_advanced.equal(a.ids, b.ids)) {
1285
+ require_advanced.profile.recorder("publishedOrderItems", b.ids.length);
374
1286
  order = {
375
1287
  before: a.ids,
376
1288
  after: [...b.ids]
@@ -387,26 +1299,26 @@ const restore = (fact, schema, root, skip = 0) => {
387
1299
  const at = skip ? fact.at.slice(skip) : fact.at;
388
1300
  if (fact.kind === "member") {
389
1301
  const member = fact.member;
390
- const value = member.present ? require_access.copyValue(member.node, member.value) : void 0;
1302
+ const value = member.present ? require_advanced.copyValue(member.node, member.value) : void 0;
391
1303
  if (!at.length) return value;
392
- const location = require_issue.resolveLocated(schema, root, at);
1304
+ const location = resolveLocated(schema, root, at);
393
1305
  if (!location) throw new Error("Cannot restore an unresolved member.");
394
1306
  installMember(location.parent, location.key, member.present, value);
395
1307
  return root;
396
1308
  }
397
- const location = require_issue.resolveValue(schema, root, at);
1309
+ const location = resolveValue(schema, root, at);
398
1310
  if (!location) throw new Error("Cannot restore an unresolved subtree.");
399
1311
  if (fact.kind === "order") installOrder(location.node, location.value, fact.group.order);
400
1312
  else {
401
1313
  const tree = location.value;
402
1314
  if (fact.before === null) delete tree.rootId;
403
1315
  else tree.rootId = fact.before;
404
- for (const [id, node] of fact.nodes) installMember(tree.nodes, id, node !== void 0, node && require_access.copyTreeNode(node));
1316
+ for (const [id, node] of fact.nodes) installMember(tree.nodes, id, node !== void 0, node && require_advanced.copyTreeNode(node));
405
1317
  }
406
1318
  return root;
407
1319
  };
408
1320
  const reconstructBefore = (node, current, records, offset) => {
409
- let before = require_access.copyValue(node, current);
1321
+ let before = require_advanced.copyValue(node, current);
410
1322
  for (let i = records.length - 1; i >= 0; i--) if (records[i].kind !== "order") before = restore(records[i], node, before, offset);
411
1323
  for (const record of records) if (record.kind === "order") before = restore(record, node, before, offset);
412
1324
  return before;
@@ -415,7 +1327,7 @@ const sealMembers = (fact, changes) => {
415
1327
  const members = [];
416
1328
  for (const member of fact.members?.values() ?? []) {
417
1329
  if (!member) continue;
418
- const key = require_issue.memberKey(fact, member.key);
1330
+ const key = memberKey(fact, member.key);
419
1331
  const present = Object.hasOwn(fact.parent, key);
420
1332
  const value = fact.parent[key];
421
1333
  if (member.node.kind === "field") {
@@ -425,10 +1337,10 @@ const sealMembers = (fact, changes) => {
425
1337
  }
426
1338
  let order;
427
1339
  if (fact.order) {
428
- const current = fact.node.kind === "list" ? require_issue.indexedKeys(fact.value, fact.node.keyOf) : fact.value.ids;
429
- if (!require_issue.equal(fact.order, current)) {
1340
+ const current = fact.node.kind === "list" ? require_advanced.indexedKeys(fact.value, fact.node.keyOf) : fact.value.ids;
1341
+ if (!require_advanced.equal(fact.order, current)) {
430
1342
  const after = orderOf(fact.node, fact.value);
431
- require_issue.profile.recorder("publishedOrderItems", after.length);
1343
+ require_advanced.profile.recorder("publishedOrderItems", after.length);
432
1344
  order = {
433
1345
  before: fact.order,
434
1346
  after
@@ -437,19 +1349,19 @@ const sealMembers = (fact, changes) => {
437
1349
  }
438
1350
  publishMembers(changes, fact.at, members, order);
439
1351
  };
440
- const sealTree = (fact, state, changes) => {
441
- const location = require_issue.resolveValue(state.schema, state.document, fact.at);
1352
+ const sealTree = (fact, canonical, changes) => {
1353
+ const location = resolveValue(canonical.schema, canonical.document, fact.at);
442
1354
  const tree = location?.value;
443
1355
  if ((location?.node)?.kind !== "tree") throw new Error("Tree schema disappeared before sealing.");
444
1356
  const nodes = [];
445
1357
  for (const [id, before] of fact.nodes) {
446
1358
  const after = Object.hasOwn(tree.nodes, id) ? tree.nodes[id] : void 0;
447
1359
  if (!before && !after) continue;
448
- if (before && after && require_access.equalTreeNode(before, after)) continue;
1360
+ if (before && after && require_advanced.equalTreeNode(before, after)) continue;
449
1361
  nodes.push(!before ? {
450
1362
  id,
451
1363
  kind: "added",
452
- after: require_access.copyTreeNode(after)
1364
+ after: require_advanced.copyTreeNode(after)
453
1365
  } : !after ? {
454
1366
  id,
455
1367
  kind: "removed",
@@ -458,7 +1370,7 @@ const sealTree = (fact, state, changes) => {
458
1370
  id,
459
1371
  kind: "updated",
460
1372
  before,
461
- after: require_access.copyTreeNode(after)
1373
+ after: require_advanced.copyTreeNode(after)
462
1374
  });
463
1375
  }
464
1376
  const after = tree.rootId ?? null;
@@ -481,12 +1393,12 @@ var ChangeRecorder = class {
481
1393
  this.state = state;
482
1394
  }
483
1395
  indexGroups() {
484
- const index = this.index ??= new require_issue.AddressIndex();
1396
+ const index = this.index ??= new require_driver.AddressIndex();
485
1397
  if (!this.indexedGroups) {
486
1398
  this.indexedGroups = true;
487
1399
  for (const fact of this.facts) if (fact.kind === "members") {
488
1400
  index.add(fact.at, fact);
489
- require_issue.profile.recorder("indexedGroups");
1401
+ require_advanced.profile.recorder("indexedGroups");
490
1402
  }
491
1403
  }
492
1404
  return index;
@@ -511,7 +1423,7 @@ var ChangeRecorder = class {
511
1423
  }
512
1424
  return;
513
1425
  }
514
- if (fact.order && require_issue.contains(at, fact.at)) children.push({
1426
+ if (fact.order && contains(at, fact.at)) children.push({
515
1427
  kind: "order",
516
1428
  at: fact.at,
517
1429
  group: fact
@@ -519,14 +1431,14 @@ var ChangeRecorder = class {
519
1431
  for (const member of fact.members?.values() ?? []) {
520
1432
  if (!member) continue;
521
1433
  const memberAt = fact.at.concat(member.key);
522
- if (require_issue.contains(at, memberAt)) children.push({
1434
+ if (contains(at, memberAt)) children.push({
523
1435
  kind: "member",
524
1436
  at: memberAt,
525
1437
  group: fact,
526
1438
  member
527
1439
  });
528
1440
  }
529
- } else if (require_issue.contains(at, fact.at)) children.push(fact);
1441
+ } else if (contains(at, fact.at)) children.push(fact);
530
1442
  })(at);
531
1443
  if (present) value = reconstructBefore(node, value, children, at.length);
532
1444
  this.releaseCovered(children);
@@ -535,7 +1447,7 @@ var ChangeRecorder = class {
535
1447
  releaseCovered(children) {
536
1448
  let changedGroups;
537
1449
  for (const child of children) {
538
- require_issue.profile.recorder("absorbed");
1450
+ require_advanced.profile.recorder("absorbed");
539
1451
  if (child.kind === "member") {
540
1452
  const { group, member } = child;
541
1453
  forgetMember(group, member.key);
@@ -551,11 +1463,11 @@ var ChangeRecorder = class {
551
1463
  this.facts.add(fact);
552
1464
  if (fact.kind === "members") {
553
1465
  this.groups.set(fact.parent, fact);
554
- require_issue.profile.recorder("groups");
1466
+ require_advanced.profile.recorder("groups");
555
1467
  if (!this.indexedGroups) return;
556
- require_issue.profile.recorder("indexedGroups");
1468
+ require_advanced.profile.recorder("indexedGroups");
557
1469
  }
558
- (this.index ??= new require_issue.AddressIndex()).add(fact.at, fact);
1470
+ (this.index ??= new require_driver.AddressIndex()).add(fact.at, fact);
559
1471
  }
560
1472
  unregister(fact) {
561
1473
  this.facts.delete(fact);
@@ -583,14 +1495,14 @@ var ChangeRecorder = class {
583
1495
  if (group.layout === "dynamic") (group.members ??= /* @__PURE__ */ new Map()).set(key, member);
584
1496
  else if (definition.kind === "fixed") group.members[definition.slot] = member;
585
1497
  else throw new Error("A fixed member group requires a fixed schema member.");
586
- require_issue.profile.recorder("facts");
1498
+ require_advanced.profile.recorder("facts");
587
1499
  }
588
1500
  reset() {
589
1501
  if (this.resetBefore) return;
590
1502
  const value = this.absorb([], this.state.schema, this.state.document, true);
591
1503
  this.resetBefore = { value };
592
1504
  this.groups = /* @__PURE__ */ new WeakMap();
593
- require_issue.profile.recorder("facts");
1505
+ require_advanced.profile.recorder("facts");
594
1506
  }
595
1507
  createGroup(container) {
596
1508
  const group = container.layout.kind === "fixed" ? {
@@ -615,18 +1527,18 @@ var ChangeRecorder = class {
615
1527
  return group;
616
1528
  }
617
1529
  order(container) {
618
- require_issue.profile.recorder("orderCaptures");
1530
+ require_advanced.profile.recorder("orderCaptures");
619
1531
  let group = this.groups.get(container.parent);
620
1532
  if (group?.order || this.covered(container.at)) return;
621
1533
  group ??= this.createGroup(container);
622
1534
  group.order = orderOf(container.node, container.value);
623
- require_issue.profile.recorder("orderSnapshots");
624
- require_issue.profile.recorder("orderItems", group.order.length);
1535
+ require_advanced.profile.recorder("orderSnapshots");
1536
+ require_advanced.profile.recorder("orderItems", group.order.length);
625
1537
  }
626
1538
  tree(container, id) {
627
1539
  const { at, value: tree } = container;
628
1540
  if (this.covered(at)) return;
629
- const index = this.index ??= new require_issue.AddressIndex();
1541
+ const index = this.index ??= new require_driver.AddressIndex();
630
1542
  let fact;
631
1543
  for (const item of index.exact(at) ?? []) if (item.kind === "tree") fact = item;
632
1544
  if (!fact) {
@@ -639,8 +1551,8 @@ var ChangeRecorder = class {
639
1551
  this.register(fact);
640
1552
  }
641
1553
  if (id !== void 0 && !fact.nodes.has(id)) {
642
- require_issue.profile.recorder("treeNodes");
643
- fact.nodes.set(id, Object.hasOwn(tree.nodes, id) ? require_access.copyTreeNode(tree.nodes[id]) : void 0);
1554
+ require_advanced.profile.recorder("treeNodes");
1555
+ fact.nodes.set(id, Object.hasOwn(tree.nodes, id) ? require_advanced.copyTreeNode(tree.nodes[id]) : void 0);
644
1556
  }
645
1557
  }
646
1558
  rollback() {
@@ -653,7 +1565,7 @@ var ChangeRecorder = class {
653
1565
  const fact = facts[i];
654
1566
  if (fact.kind === "members") for (const member of fact.members?.values() ?? []) {
655
1567
  if (!member) continue;
656
- installMember(fact.parent, require_issue.memberKey(fact, member.key), member.present, member.present ? require_access.copyValue(member.node, member.value) : void 0);
1568
+ installMember(fact.parent, memberKey(fact, member.key), member.present, member.present ? require_advanced.copyValue(member.node, member.value) : void 0);
657
1569
  }
658
1570
  else if (fact.kind === "tree") restore(fact, this.state.schema, this.state.document);
659
1571
  }
@@ -661,19 +1573,19 @@ var ChangeRecorder = class {
661
1573
  }
662
1574
  seal() {
663
1575
  if (this.resetBefore) {
664
- if (require_access.equalValue(this.state.schema, this.resetBefore.value, this.state.document)) return require_driver.sealChanges([]);
665
- require_issue.profile.recorder("sealed");
1576
+ if (require_advanced.equalValue(this.state.schema, this.resetBefore.value, this.state.document)) return require_driver.sealChanges([]);
1577
+ require_advanced.profile.recorder("sealed");
666
1578
  return require_driver.sealChanges([{
667
1579
  kind: "reset",
668
1580
  before: this.resetBefore.value,
669
- after: require_access.copyValue(this.state.schema, this.state.document)
1581
+ after: require_advanced.copyValue(this.state.schema, this.state.document)
670
1582
  }]);
671
1583
  }
672
1584
  const changes = [];
673
1585
  for (const fact of this.facts) if (fact.kind === "members") sealMembers(fact, changes);
674
1586
  else sealTree(fact, this.state, changes);
675
1587
  const result = require_driver.sealChanges(changes);
676
- require_issue.profile.recorder("sealed", result.changes.length);
1588
+ require_advanced.profile.recorder("sealed", result.changes.length);
677
1589
  return result;
678
1590
  }
679
1591
  };
@@ -689,25 +1601,25 @@ var MutationSession = class {
689
1601
  constructor(state) {
690
1602
  this.state = state;
691
1603
  this.recorder = new ChangeRecorder(state);
692
- this.resolver = require_issue.createAddressResolver(state.schema, state.document);
1604
+ this.resolver = createAddressResolver(state.schema, state.document);
693
1605
  this.resolvedRoot = state.document;
694
1606
  }
695
1607
  validate(node, value, at) {
696
- const issue = require_access.checkValue(node, value, at);
697
- if (issue) require_issue.invalidValue(issue);
1608
+ const failure = require_advanced.checkValue(node, value, at);
1609
+ if (failure) require_driver.invalidValue(failure);
698
1610
  }
699
1611
  resolveContainer(at) {
700
- return this.resolver.container(this.identity, this.generation, at) ?? require_issue.fail(at, "invalid-address", "Container does not exist.");
1612
+ return this.resolver.container(this.identity, this.generation, at) ?? require_driver.fail(at, "invalid-address", "Container does not exist.");
701
1613
  }
702
1614
  /** Bind access-resolved canonical facts without walking the address again. */
703
1615
  bind(at, node, value) {
704
- return require_issue.resolveContainer(this.identity, this.generation, at, node, value) ?? require_issue.fail(at, "invalid-address", "Container does not exist.");
1616
+ return resolveContainer(this.identity, this.generation, at, node, value) ?? require_driver.fail(at, "invalid-address", "Container does not exist.");
705
1617
  }
706
1618
  bindTree(at, node, value) {
707
- return require_issue.resolveTreeContainer(this.identity, this.generation, at, node, value) ?? require_issue.fail(at, "invalid-tree", "Expected a tree.");
1619
+ return resolveTreeContainer(this.identity, this.generation, at, node, value) ?? require_driver.fail(at, "invalid-tree", "Expected a tree.");
708
1620
  }
709
1621
  resolveTree(at) {
710
- const location = require_issue.resolveValue(this.state.schema, this.state.document, at);
1622
+ const location = resolveValue(this.state.schema, this.state.document, at);
711
1623
  return this.bindTree(at, location?.node, location?.value);
712
1624
  }
713
1625
  replace(at, value) {
@@ -715,7 +1627,7 @@ var MutationSession = class {
715
1627
  this.validate(this.state.schema, value, at);
716
1628
  if (Object.is(this.state.document, value)) return;
717
1629
  this.recorder.reset();
718
- this.state.document = require_access.copyValue(this.state.schema, value);
1630
+ this.state.document = require_advanced.copyValue(this.state.schema, value);
719
1631
  this.invalidate();
720
1632
  return;
721
1633
  }
@@ -724,24 +1636,24 @@ var MutationSession = class {
724
1636
  assignMember(container, key, value) {
725
1637
  container = this.refresh(container);
726
1638
  const member = this.definition(container, key);
727
- if (container.layout.kind === "fixed" && member.node.kind !== "field" && member.node.kind !== "variant" && !member.node.optional) return require_issue.fail(container.at.concat(key), "invalid-value", "Replace fields, variants, or collection entries; edit object members individually.");
728
- this.writeLocatedMember(container, key, member, require_issue.memberKey(container, key), value, "set");
1639
+ if (container.layout.kind === "fixed" && member.node.kind !== "field" && member.node.kind !== "variant" && !member.node.optional) return require_driver.fail(container.at.concat(key), "invalid-value", "Replace fields, variants, or collection entries; edit object members individually.");
1640
+ this.writeLocatedMember(container, key, member, memberKey(container, key), value, "set");
729
1641
  }
730
1642
  removeMember(container, key) {
731
1643
  this.writeMember(this.refresh(container), key, void 0, "remove");
732
1644
  }
733
1645
  refresh(container) {
734
- if (container.owner !== this.identity) return require_issue.fail(container.at, "invalid-address", "Container belongs to another mutation session.");
1646
+ if (container.owner !== this.identity) return require_driver.fail(container.at, "invalid-address", "Container belongs to another mutation session.");
735
1647
  return container.generation === this.generation ? container : this.resolveContainer(container.at);
736
1648
  }
737
1649
  definition(container, key) {
738
1650
  const layout = container.layout;
739
1651
  const member = layout.kind === "dynamic" ? layout.entry : layout.members.get(key);
740
- if (!member) return require_issue.fail(container.at.concat(key), "invalid-address", "Address does not exist.");
1652
+ if (!member) return require_driver.fail(container.at.concat(key), "invalid-address", "Address does not exist.");
741
1653
  return member;
742
1654
  }
743
1655
  /** Consume a current command-local container; bulk writes retain its storage. */
744
- writeMember(container, key, value, operation, physicalKey = require_issue.memberKey(container, key)) {
1656
+ writeMember(container, key, value, operation, physicalKey = memberKey(container, key)) {
745
1657
  const member = this.definition(container, key);
746
1658
  return this.writeLocatedMember(container, key, member, physicalKey, value, operation);
747
1659
  }
@@ -750,27 +1662,27 @@ var MutationSession = class {
750
1662
  const parentNode = container.node;
751
1663
  const node = member.node;
752
1664
  const present = operation === "set";
753
- if (parentNode.kind === "variant" && parentNode.tag === key) return require_issue.fail(container.at.concat(key), "invalid-value", "Variant discriminants are read-only.");
1665
+ if (parentNode.kind === "variant" && parentNode.tag === key) return require_driver.fail(container.at.concat(key), "invalid-value", "Variant discriminants are read-only.");
754
1666
  const entry = container.layout.kind === "dynamic";
755
- if (!present && !node.optional && !entry) return require_issue.fail(container.at.concat(key), "required-field", "A required value cannot be removed.");
1667
+ if (!present && !node.optional && !entry) return require_driver.fail(container.at.concat(key), "required-field", "A required value cannot be removed.");
756
1668
  const existed = Object.hasOwn(container.parent, physicalKey);
757
1669
  const previous = container.parent[physicalKey];
758
1670
  if (existed === present && (!present || Object.is(previous, value))) return false;
759
1671
  if (parentNode.kind === "map" || parentNode.kind === "table") {
760
- const issue = require_access.checkKey(parentNode.key, key, []);
761
- if (issue) return require_issue.fail(container.at.concat(key, ...issue.address), "invalid-key", issue.message);
1672
+ const failure = require_advanced.checkKey(parentNode.key, key, []);
1673
+ if (failure) return require_driver.fail(container.at.concat(key, ...failure.address), "invalid-key", failure.message);
762
1674
  }
763
1675
  if (present) {
764
1676
  if (node.kind === "field") {
765
- const issue = require_access.checkValue(node, value, []);
766
- if (issue) return require_issue.invalidValue(issue, container.at.concat(key, ...issue.address));
1677
+ const failure = require_advanced.checkValue(node, value, []);
1678
+ if (failure) return require_driver.invalidValue(failure, container.at.concat(key, ...failure.address));
767
1679
  } else this.validate(node, value, container.at.concat(key));
768
- if (parentNode.kind === "list" && parentNode.keyOf(value) !== key) return require_issue.fail(container.at.concat(key), "invalid-list-key", "Replacing an item must retain its addressed key.");
1680
+ if (parentNode.kind === "list" && parentNode.keyOf(value) !== key) return require_driver.fail(container.at.concat(key), "invalid-list-key", "Replacing an item must retain its addressed key.");
769
1681
  }
770
1682
  const membershipChanged = entry && existed !== present;
771
1683
  if (membershipChanged && (parentNode.kind === "list" || parentNode.kind === "table")) this.recorder.order(container);
772
1684
  this.recorder.member(container, key, member, physicalKey);
773
- const next = present ? node.kind === "field" ? value : require_access.copyValue(node, value) : void 0;
1685
+ const next = present ? node.kind === "field" ? value : require_advanced.copyValue(node, value) : void 0;
774
1686
  installMember(container.parent, physicalKey, present, next);
775
1687
  if (node.kind !== "field" || membershipChanged) this.invalidate();
776
1688
  return membershipChanged;
@@ -779,7 +1691,7 @@ var MutationSession = class {
779
1691
  this.generation++;
780
1692
  if (this.resolvedRoot !== this.state.document) {
781
1693
  this.resolvedRoot = this.state.document;
782
- this.resolver = require_issue.createAddressResolver(this.state.schema, this.state.document);
1694
+ this.resolver = createAddressResolver(this.state.schema, this.state.document);
783
1695
  } else this.resolver.invalidate();
784
1696
  }
785
1697
  finish() {
@@ -799,7 +1711,7 @@ function apply(session, changes, direction) {
799
1711
  const container = session.resolveContainer(change.at);
800
1712
  const { node, value: current } = container;
801
1713
  if (change.order) {
802
- if (node.kind !== "table" && node.kind !== "list") return require_issue.fail(change.at, "invalid-changes", "Order requires an ordered container.");
1714
+ if (node.kind !== "table" && node.kind !== "list") return require_driver.fail(change.at, "invalid-changes", "Order requires an ordered container.");
803
1715
  session.recorder.order(container);
804
1716
  }
805
1717
  let membershipChanged = false;
@@ -810,12 +1722,12 @@ function apply(session, changes, direction) {
810
1722
  }
811
1723
  if (change.order) {
812
1724
  const keys = node.kind === "table" ? Object.keys(container.parent) : orderOf(node, current);
813
- if (!require_issue.matches(change.order[side], keys)) return require_issue.fail(change.at, "invalid-changes", "Order must contain exactly the resulting keys.");
1725
+ if (!require_advanced.matches(change.order[side], keys)) return require_driver.fail(change.at, "invalid-changes", "Order must contain exactly the resulting keys.");
814
1726
  installOrder(node, current, change.order[side]);
815
1727
  session.invalidate();
816
1728
  } else if (membershipChanged && node.kind === "table") {
817
1729
  const ids = current.ids;
818
- if (!require_issue.matches(ids, Object.keys(container.parent))) return require_issue.fail(change.at, "invalid-changes", "Table membership changes require a matching order.");
1730
+ if (!require_advanced.matches(ids, Object.keys(container.parent))) return require_driver.fail(change.at, "invalid-changes", "Table membership changes require a matching order.");
819
1731
  }
820
1732
  } else {
821
1733
  const container = session.resolveTree(change.at);
@@ -828,57 +1740,220 @@ function apply(session, changes, direction) {
828
1740
  for (const item of change.nodes) {
829
1741
  const next = side === "after" ? item.kind !== "removed" ? item.after : void 0 : item.kind !== "added" ? item.before : void 0;
830
1742
  if (next !== void 0) {
831
- const issue = require_access.checkTreePayload(node.value, next, change.at.concat(item.id));
832
- if (issue) require_issue.invalidValue(issue);
1743
+ const diagnostic = require_advanced.checkTreePayload(node.value, next, change.at.concat(item.id));
1744
+ if (diagnostic) require_driver.invalidValue(diagnostic);
833
1745
  }
834
- installMember(current.nodes, item.id, next !== void 0, next && require_access.copyTreeNode(next));
1746
+ installMember(current.nodes, item.id, next !== void 0, next && require_advanced.copyTreeNode(next));
835
1747
  }
836
- if (!require_issue.validate(current)) return require_issue.fail(change.at, "invalid-tree", "Invalid tree structure.");
1748
+ if (!require_context.validate(current)) return require_driver.fail(change.at, "invalid-tree", "Invalid tree structure.");
837
1749
  session.invalidate();
838
1750
  }
839
1751
  }
840
1752
  //#endregion
841
- //#region core/src/runtime.ts
842
- const createDocument = (input) => {
843
- if (input.schema.kind !== "object") throw new TypeError("Document schema must be a root object node.");
844
- const invalid = require_access.checkValue(input.schema, input.initial);
845
- if (invalid) throw new require_access.ParseError(invalid);
846
- const state = {
847
- schema: input.schema,
848
- document: require_access.copyValue(input.schema, input.initial),
849
- disposed: false
1753
+ //#region core/src/runtime/notification.ts
1754
+ const attachProjection = (notification, processor) => {
1755
+ const entry = {
1756
+ processor,
1757
+ active: true
850
1758
  };
851
- let revision = 0, busy = false;
852
- let runtime, notification;
853
- const idle = () => {
854
- if (state.disposed) throw new require_access.DocumentDisposedError();
855
- if (busy || require_access.accessOf(runtime).projectionLocks) throw new require_access.DocumentReentrancyError();
1759
+ notification.processors.push(entry);
1760
+ return () => {
1761
+ if (!entry.active) return;
1762
+ entry.active = false;
1763
+ if (!notification.notifying) {
1764
+ const index = notification.processors.indexOf(entry);
1765
+ if (index >= 0) notification.processors.splice(index, 1);
1766
+ }
856
1767
  };
857
- const writable = (intent) => {
858
- idle();
859
- require_driver.assertRuntimeWritable(runtime, intent);
1768
+ };
1769
+ const addRoot = (notification, listener) => {
1770
+ const entry = {
1771
+ listener,
1772
+ active: true
860
1773
  };
861
- const history = createHistory({
862
- capacity: input.history === false ? 0 : Math.max(0, input.history?.capacity ?? 100),
863
- revision: () => revision,
864
- apply: (changes, direction) => mutate({
865
- kind: "apply",
866
- source: "history"
867
- }, false, (session) => {
868
- for (const change of changes) apply(session, change, direction);
869
- }),
870
- assertIdle: idle,
871
- notify: (run) => {
872
- busy = true;
873
- try {
874
- return run();
875
- } finally {
876
- busy = false;
877
- }
878
- }
879
- });
880
- const publish = (changes, source, recordHistory) => {
881
- const commit = {
1774
+ notification.root.add(entry);
1775
+ return () => {
1776
+ entry.active = false;
1777
+ if (!notification.notifying) notification.root.delete(entry);
1778
+ else notification.cleanups.add(() => {
1779
+ notification.root.delete(entry);
1780
+ });
1781
+ };
1782
+ };
1783
+ const addFiltered = (notification, targets, listener) => {
1784
+ const entry = {
1785
+ targets: Object.freeze(targets.slice()),
1786
+ listener,
1787
+ active: true
1788
+ };
1789
+ notification.filtered.add(entry);
1790
+ entry.targets.forEach((value) => notification.index.add(value, entry));
1791
+ const remove = () => {
1792
+ notification.filtered.delete(entry);
1793
+ entry.targets.forEach((value) => notification.index.delete(value, entry));
1794
+ };
1795
+ return () => {
1796
+ if (!entry.active) return;
1797
+ entry.active = false;
1798
+ if (notification.notifying) notification.cleanups.add(remove);
1799
+ else remove();
1800
+ };
1801
+ };
1802
+ const publishState = (notification, commit, afterSettle) => {
1803
+ notification.notifying = true;
1804
+ const errors = [];
1805
+ const call = (listener) => {
1806
+ try {
1807
+ listener(commit);
1808
+ } catch (error) {
1809
+ errors.push(Object.freeze({
1810
+ phase: "listener",
1811
+ error
1812
+ }));
1813
+ }
1814
+ };
1815
+ try {
1816
+ const processorCount = notification.processors.length;
1817
+ for (let index = 0; index < processorCount; index += 1) {
1818
+ const entry = notification.processors[index];
1819
+ if (!entry?.active) continue;
1820
+ try {
1821
+ entry.processor.capture(commit);
1822
+ } catch (error) {
1823
+ errors.push(Object.freeze({
1824
+ phase: "processor",
1825
+ error
1826
+ }));
1827
+ }
1828
+ }
1829
+ for (let index = 0; index < processorCount; index += 1) {
1830
+ const entry = notification.processors[index];
1831
+ if (!entry?.active) continue;
1832
+ try {
1833
+ entry.processor.settle();
1834
+ } catch (error) {
1835
+ errors.push(Object.freeze({
1836
+ phase: "processor",
1837
+ error
1838
+ }));
1839
+ }
1840
+ }
1841
+ for (let index = 0; index < processorCount; index += 1) {
1842
+ const entry = notification.processors[index];
1843
+ if (!entry?.active) continue;
1844
+ try {
1845
+ errors.push(...entry.processor.flush());
1846
+ } catch (error) {
1847
+ errors.push(Object.freeze({
1848
+ phase: "flush",
1849
+ error
1850
+ }));
1851
+ }
1852
+ }
1853
+ if (afterSettle) errors.push(...afterSettle());
1854
+ const candidates = notification.candidates;
1855
+ candidates.clear();
1856
+ if (notification.filtered.size) notification.index.collect(commit.changes, (entry) => candidates.add(entry));
1857
+ candidates.forEach((entry) => {
1858
+ if (entry.active) call(entry.listener);
1859
+ });
1860
+ const rootSnapshot = notification.rootSnapshot;
1861
+ rootSnapshot.length = 0;
1862
+ notification.root.forEach((entry) => rootSnapshot.push(entry));
1863
+ for (const entry of rootSnapshot) if (entry.active) call(entry.listener);
1864
+ } finally {
1865
+ notification.notifying = false;
1866
+ let writeIndex = 0;
1867
+ for (const entry of notification.processors) if (entry.active) notification.processors[writeIndex++] = entry;
1868
+ notification.processors.length = writeIndex;
1869
+ notification.cleanups.forEach((cleanup) => cleanup());
1870
+ notification.cleanups.clear();
1871
+ }
1872
+ return Object.freeze(errors);
1873
+ };
1874
+ const disposeState = (notification) => {
1875
+ const attachments = notification.processors.slice();
1876
+ notification.root.clear();
1877
+ notification.filtered.clear();
1878
+ notification.index.clear();
1879
+ notification.cleanups.clear();
1880
+ notification.processors.length = 0;
1881
+ notification.candidates.clear();
1882
+ notification.rootSnapshot.length = 0;
1883
+ const errors = [];
1884
+ attachments.forEach((entry) => {
1885
+ if (!entry.active) return;
1886
+ try {
1887
+ entry.processor.dispose();
1888
+ } catch (error) {
1889
+ errors.push(error);
1890
+ }
1891
+ });
1892
+ if (errors.length) throw new AggregateError(errors, "Projection disposal notification failed.");
1893
+ };
1894
+ const createNotificationCenter = (schema) => {
1895
+ const state = {
1896
+ root: /* @__PURE__ */ new Set(),
1897
+ filtered: /* @__PURE__ */ new Set(),
1898
+ index: new SubscriptionIndex(schema),
1899
+ cleanups: /* @__PURE__ */ new Set(),
1900
+ processors: [],
1901
+ candidates: /* @__PURE__ */ new Set(),
1902
+ rootSnapshot: [],
1903
+ notifying: false
1904
+ };
1905
+ return Object.freeze({
1906
+ subscribe: (listener) => addRoot(state, listener),
1907
+ subscribeTargets: (targets, listener) => addFiltered(state, targets, listener),
1908
+ attachProjection: (processor) => attachProjection(state, processor),
1909
+ publish: (commit, afterSettle) => publishState(state, commit, afterSettle),
1910
+ dispose: () => disposeState(state)
1911
+ });
1912
+ };
1913
+ //#endregion
1914
+ //#region core/src/runtime.ts
1915
+ const createDocument = (input) => {
1916
+ if (input.schema.kind !== "object") throw new TypeError("Document schema must be a root object node.");
1917
+ const invalid = require_advanced.checkValue(input.schema, input.initial);
1918
+ if (invalid) throw new require_advanced.ParseError(invalid);
1919
+ const state = {
1920
+ schema: input.schema,
1921
+ document: require_advanced.copyValue(input.schema, input.initial),
1922
+ disposed: false,
1923
+ projectionLocks: 0
1924
+ };
1925
+ let revision = 0, busy = false;
1926
+ const notifications = createNotificationCenter(input.schema);
1927
+ let runtime, context;
1928
+ const idle = () => {
1929
+ if (state.disposed) throw new DocumentDisposedError();
1930
+ if (busy || state.projectionLocks) throw new DocumentReentrancyError();
1931
+ };
1932
+ const writable = (intent) => {
1933
+ idle();
1934
+ require_driver.assertRuntimeWritable(runtime, intent);
1935
+ };
1936
+ const history = createHistory({
1937
+ capacity: input.history === false ? 0 : Math.max(0, input.history?.capacity ?? 100),
1938
+ revision: () => revision,
1939
+ apply: (changes, direction) => mutate({
1940
+ kind: "apply",
1941
+ source: "history"
1942
+ }, false, (session) => {
1943
+ for (const change of changes) apply(session, change, direction);
1944
+ }),
1945
+ assertIdle: idle,
1946
+ notify: (run) => {
1947
+ busy = true;
1948
+ try {
1949
+ return run();
1950
+ } finally {
1951
+ busy = false;
1952
+ }
1953
+ }
1954
+ });
1955
+ const publish = (changes, source, recordHistory) => {
1956
+ const commit = {
882
1957
  revision: ++revision,
883
1958
  source,
884
1959
  changes,
@@ -891,7 +1966,7 @@ const createDocument = (input) => {
891
1966
  return {
892
1967
  status: "committed",
893
1968
  commit,
894
- observerErrors: require_notification.notify(notification, commit, history.flush)
1969
+ observerErrors: notifications.publish(commit, history.flush)
895
1970
  };
896
1971
  };
897
1972
  function mutate(intent, recordHistory, execute) {
@@ -905,12 +1980,12 @@ const createDocument = (input) => {
905
1980
  changes = session.finish();
906
1981
  } catch (error) {
907
1982
  session.rollback();
908
- if (error instanceof require_issue.MutationRejected) return {
1983
+ if (error instanceof require_driver.MutationRejected) return {
909
1984
  status: "rejected",
910
1985
  issues: [error.issue],
911
1986
  revision
912
1987
  };
913
- if (intent.kind === "update" && error instanceof require_access.TransactionRejected) return {
1988
+ if (intent.kind === "update" && error instanceof TransactionRejected) return {
914
1989
  status: "rejected",
915
1990
  issues: error.issues,
916
1991
  revision
@@ -928,13 +2003,6 @@ const createDocument = (input) => {
928
2003
  }
929
2004
  runtime = {
930
2005
  schema: input.schema,
931
- address: {
932
- resolve: (at) => require_issue.resolveAddress(input.schema, at, state.document),
933
- read: (at) => require_issue.read(state.document, at, input.schema),
934
- contains: require_issue.contains,
935
- overlaps: require_issue.overlaps,
936
- debugKey: require_issue.debugKey
937
- },
938
2006
  revision: () => revision,
939
2007
  update: (run, options) => {
940
2008
  const source = options?.source ?? "local";
@@ -943,7 +2011,7 @@ const createDocument = (input) => {
943
2011
  kind: "update",
944
2012
  source
945
2013
  }, options?.history ?? true, (session) => {
946
- value = run(require_access.createAccess({
2014
+ value = run(createAccess({
947
2015
  state,
948
2016
  session
949
2017
  }));
@@ -958,7 +2026,7 @@ const createDocument = (input) => {
958
2026
  kind: "apply",
959
2027
  source: options?.source ?? "local"
960
2028
  }, options?.history ?? true, (session) => {
961
- if (!options || options.expectedRevision !== revision) require_issue.fail([], "baseline-mismatch", "apply requires the current expectedRevision.");
2029
+ if (!options || options.expectedRevision !== revision) require_driver.fail([], "baseline-mismatch", "apply requires the current expectedRevision.");
962
2030
  apply(session, require_driver.decodeChanges(inputChanges), "forward");
963
2031
  }),
964
2032
  replace: (value, options) => {
@@ -969,15 +2037,15 @@ const createDocument = (input) => {
969
2037
  }, source !== "remote", (session) => session.replace([], value));
970
2038
  },
971
2039
  snapshot: () => {
972
- if (state.disposed) throw new require_access.DocumentDisposedError();
973
- return require_access.copyValue(input.schema, state.document);
2040
+ if (state.disposed) throw new DocumentDisposedError();
2041
+ return require_advanced.copyValue(input.schema, state.document);
974
2042
  },
975
2043
  subscribe: ((pick, listener) => {
976
- if (state.disposed) throw new require_access.DocumentDisposedError();
977
- if (!listener) return require_notification.subscribeRoot(notification, pick);
2044
+ if (state.disposed) throw new DocumentDisposedError();
2045
+ if (!listener) return notifications.subscribe(pick);
978
2046
  const picks = Array.isArray(pick) ? pick : [pick];
979
2047
  if (!picks.length) throw new TypeError("Expected at least one subscription path.");
980
- return require_notification.subscribeTargets(notification, picks.map((p) => require_advanced.compilePath(input.schema, "value", p)), listener);
2048
+ return notifications.subscribeTargets(picks.map((p) => require_advanced.compilePath(input.schema, "value", p)), listener);
981
2049
  }),
982
2050
  history: history.api,
983
2051
  dispose: () => {
@@ -985,36 +2053,517 @@ const createDocument = (input) => {
985
2053
  idle();
986
2054
  state.disposed = true;
987
2055
  try {
988
- require_notification.disposeNotification(notification);
2056
+ notifications.dispose();
989
2057
  } finally {
990
2058
  history.dispose();
991
- require_driver.disposeRuntimeDriver(runtime);
2059
+ context.driver = void 0;
992
2060
  }
993
2061
  }
994
2062
  };
995
- require_access.bindRuntimeAccess(runtime, state);
996
- require_driver.bindRuntimeDriver(runtime);
997
- notification = require_notification.createNotification(runtime);
998
- require_notification.bindDocumentReadable(history.api, runtime);
2063
+ context = {
2064
+ state,
2065
+ owner: runtime,
2066
+ notifications,
2067
+ driver: void 0,
2068
+ bypassDepth: 0
2069
+ };
2070
+ require_context.bindContext(runtime, context);
2071
+ require_context.bindContext(history.api, context);
999
2072
  return runtime;
1000
2073
  };
1001
2074
  //#endregion
1002
2075
  //#region core/src/runtime/readable.ts
1003
2076
  const asReadable = (runtime) => {
1004
2077
  const readable = {
1005
- address: runtime.address,
1006
2078
  revision: runtime.revision,
1007
2079
  subscribe: runtime.subscribe
1008
2080
  };
1009
- require_access.bindRuntimeAccess(readable, require_access.accessOf(runtime));
1010
- require_notification.shareNotification(runtime, readable);
2081
+ require_context.bindContext(readable, require_context.contextOf(runtime));
1011
2082
  return Object.freeze(readable);
1012
2083
  };
1013
2084
  //#endregion
1014
- //#region core/src/projection/select.ts
1015
- const read = (runtime, selector) => require_access.readWith(runtime, selector);
2085
+ //#region core/src/access/dependency.ts
2086
+ const createDependencyTracker = () => {
2087
+ const targets = [];
2088
+ return {
2089
+ record: (value) => {
2090
+ if (!targets.some((entry) => same(entry, value))) targets.push(value);
2091
+ },
2092
+ snapshot: () => Object.freeze(targets.slice())
2093
+ };
2094
+ };
2095
+ //#endregion
2096
+ //#region core/src/runtime/access.ts
2097
+ const readWith = (runtime, run, dependencies) => {
2098
+ const state = require_context.contextOf(runtime).state;
2099
+ if (state.disposed) throw new DocumentDisposedError();
2100
+ state.projectionLocks += 1;
2101
+ try {
2102
+ return run(createAccess({
2103
+ state,
2104
+ dependencies
2105
+ }));
2106
+ } finally {
2107
+ state.projectionLocks--;
2108
+ }
2109
+ };
2110
+ //#endregion
2111
+ //#region core/src/runtime/select.ts
2112
+ const read = (document, selector) => readWith(document, selector);
2113
+ const sameDependencySet = (left, right) => {
2114
+ if (left.length !== right.length) return false;
2115
+ for (let index = 0; index < left.length; index += 1) if (!same(left[index], right[index])) return false;
2116
+ return true;
2117
+ };
2118
+ const select = (document, selector, equality = Object.is) => {
2119
+ const context = require_context.contextOf(document);
2120
+ let initialized = false;
2121
+ let value;
2122
+ let selectedRevision = 0;
2123
+ let documentRevision = -1;
2124
+ let dependencies = Object.freeze([]);
2125
+ let unsubscribeDocument;
2126
+ const listeners = /* @__PURE__ */ new Set();
2127
+ const evaluate = () => {
2128
+ const tracker = createDependencyTracker();
2129
+ const next = readWith(document, selector, tracker);
2130
+ const nextDependencies = tracker.snapshot();
2131
+ const changed = !initialized || !equality(value, next);
2132
+ const rebound = !sameDependencySet(dependencies, nextDependencies);
2133
+ if (changed) {
2134
+ if (initialized) selectedRevision += 1;
2135
+ value = next;
2136
+ }
2137
+ dependencies = nextDependencies;
2138
+ initialized = true;
2139
+ documentRevision = document.revision();
2140
+ return {
2141
+ changed,
2142
+ rebound
2143
+ };
2144
+ };
2145
+ const installSubscription = () => {
2146
+ unsubscribeDocument?.();
2147
+ unsubscribeDocument = dependencies.length > 0 ? context.notifications.subscribeTargets(dependencies, () => {
2148
+ const result = evaluate();
2149
+ if (result.rebound) installSubscription();
2150
+ if (result.changed) for (const listener of [...listeners]) listener();
2151
+ }) : void 0;
2152
+ };
2153
+ const ensureCurrent = () => {
2154
+ if (context.state.disposed) throw new DocumentDisposedError();
2155
+ if (!initialized || !unsubscribeDocument && documentRevision !== document.revision()) evaluate();
2156
+ return value;
2157
+ };
2158
+ return Object.freeze({
2159
+ current: ensureCurrent,
2160
+ revision: () => {
2161
+ ensureCurrent();
2162
+ return selectedRevision;
2163
+ },
2164
+ subscribe: (listener) => {
2165
+ ensureCurrent();
2166
+ listeners.add(listener);
2167
+ if (listeners.size === 1) installSubscription();
2168
+ return () => {
2169
+ listeners.delete(listener);
2170
+ if (!listeners.size) {
2171
+ unsubscribeDocument?.();
2172
+ unsubscribeDocument = void 0;
2173
+ }
2174
+ };
2175
+ }
2176
+ });
2177
+ };
2178
+ //#endregion
2179
+ //#region core/src/projection/collection/change.ts
2180
+ const commonOrderChanged = (before, after, added, removed) => {
2181
+ const beforeCommon = before.filter((key) => !removed.has(key));
2182
+ const afterCommon = after.filter((key) => !added.has(key));
2183
+ return beforeCommon.some((key, index) => afterCommon[index] !== key);
2184
+ };
2185
+ /** Builds the canonical incremental CollectionChange from already-known net transitions. */
2186
+ const createCollectionChange = (input) => {
2187
+ const addedKeys = new Set(input.added.map((entry) => entry.key));
2188
+ const removedKeys = new Set(input.removed.map((entry) => entry.key));
2189
+ const orderChanged = input.beforeOrder !== input.afterOrder && commonOrderChanged(input.beforeOrder, input.afterOrder, addedKeys, removedKeys);
2190
+ if (!input.added.length && !input.updated.length && !input.removed.length && !orderChanged) return void 0;
2191
+ return Object.freeze({
2192
+ kind: "incremental",
2193
+ added: Object.freeze([...input.added]),
2194
+ updated: Object.freeze([...input.updated]),
2195
+ removed: Object.freeze([...input.removed]),
2196
+ ...orderChanged ? { order: Object.freeze({
2197
+ before: Object.freeze([...input.beforeOrder]),
2198
+ after: Object.freeze([...input.afterOrder])
2199
+ }) } : {}
2200
+ });
2201
+ };
2202
+ /** Exact fallback diff between two published map-like snapshots. */
2203
+ const diffCollection = (previous, current, isEqual = Object.is) => {
2204
+ const added = [];
2205
+ const updated = [];
2206
+ const removed = [];
2207
+ for (const [key, before] of previous) if (!current.has(key)) removed.push({
2208
+ key,
2209
+ before
2210
+ });
2211
+ else {
2212
+ const after = current.get(key);
2213
+ if (!isEqual(before, after)) updated.push({
2214
+ key,
2215
+ before,
2216
+ after
2217
+ });
2218
+ }
2219
+ for (const [key, after] of current) if (!previous.has(key)) added.push({
2220
+ key,
2221
+ after
2222
+ });
2223
+ return createCollectionChange({
2224
+ added,
2225
+ updated,
2226
+ removed,
2227
+ beforeOrder: [...previous.keys()],
2228
+ afterOrder: [...current.keys()]
2229
+ });
2230
+ };
2231
+ const collectionChangedKeys = (change) => change.kind === "reset" ? /* @__PURE__ */ new Set() : new Set([
2232
+ ...change.added.map((entry) => entry.key),
2233
+ ...change.updated.map((entry) => entry.key),
2234
+ ...change.removed.map((entry) => entry.key)
2235
+ ]);
2236
+ const collectionHasStructuralChange = (change) => change.kind === "reset" || Boolean(change.added.length || change.removed.length || change.order);
2237
+ const collectionHasAnyChange = (change) => change.kind === "reset" || Boolean(change.added.length || change.updated.length || change.removed.length || change.order);
2238
+ //#endregion
2239
+ //#region core/src/projection/collection/index.ts
2240
+ const height = (node) => node?.height ?? 0;
2241
+ const node = (key, value, left, right) => {
2242
+ require_advanced.profile.collectionIndex.node();
2243
+ return Object.freeze({
2244
+ key,
2245
+ value,
2246
+ left,
2247
+ right,
2248
+ height: Math.max(height(left), height(right)) + 1
2249
+ });
2250
+ };
2251
+ const rotateLeft = (current) => {
2252
+ const right = current.right;
2253
+ return node(right.key, right.value, node(current.key, current.value, current.left, right.left), right.right);
2254
+ };
2255
+ const rotateRight = (current) => {
2256
+ const left = current.left;
2257
+ return node(left.key, left.value, left.left, node(current.key, current.value, left.right, current.right));
2258
+ };
2259
+ const rebalance = (current) => {
2260
+ const balance = height(current.left) - height(current.right);
2261
+ if (balance > 1) {
2262
+ if (height(current.left.left) < height(current.left.right)) return rotateRight(node(current.key, current.value, rotateLeft(current.left), current.right));
2263
+ return rotateRight(current);
2264
+ }
2265
+ if (balance < -1) {
2266
+ if (height(current.right.right) < height(current.right.left)) return rotateLeft(node(current.key, current.value, current.left, rotateRight(current.right)));
2267
+ return rotateLeft(current);
2268
+ }
2269
+ return current;
2270
+ };
2271
+ const setNode = (current, key, value) => {
2272
+ if (!current) return node(key, value);
2273
+ if (key === current.key) return node(key, value, current.left, current.right);
2274
+ if (key < current.key) return rebalance(node(current.key, current.value, setNode(current.left, key, value), current.right));
2275
+ return rebalance(node(current.key, current.value, current.left, setNode(current.right, key, value)));
2276
+ };
2277
+ const minNode = (current) => current.left ? minNode(current.left) : current;
2278
+ const removeNode = (current, key) => {
2279
+ if (!current) return void 0;
2280
+ if (key < current.key) return rebalance(node(current.key, current.value, removeNode(current.left, key), current.right));
2281
+ if (key > current.key) return rebalance(node(current.key, current.value, current.left, removeNode(current.right, key)));
2282
+ if (!current.left) return current.right;
2283
+ if (!current.right) return current.left;
2284
+ const next = minNode(current.right);
2285
+ return rebalance(node(next.key, next.value, current.left, removeNode(current.right, next.key)));
2286
+ };
2287
+ const fromSorted = (entries, start = 0, end = entries.length) => {
2288
+ if (start >= end) return void 0;
2289
+ const middle = start + end >> 1;
2290
+ const [key, value] = entries[middle];
2291
+ return node(key, value, fromSorted(entries, start, middle), fromSorted(entries, middle + 1, end));
2292
+ };
2293
+ /** Immutable keyed lookup used to keep published collection snapshots durable across revisions. */
2294
+ var PersistentKeyedIndex = class PersistentKeyedIndex {
2295
+ constructor(root) {
2296
+ this.root = root;
2297
+ }
2298
+ static empty() {
2299
+ return new PersistentKeyedIndex();
2300
+ }
2301
+ static from(entries) {
2302
+ const sorted = [...entries].sort(([left], [right]) => left < right ? -1 : left > right ? 1 : 0);
2303
+ require_advanced.profile.collectionIndex.build(sorted.length);
2304
+ return new PersistentKeyedIndex(fromSorted(sorted));
2305
+ }
2306
+ get(key) {
2307
+ let current = this.root;
2308
+ while (current) {
2309
+ if (key === current.key) return current.value;
2310
+ current = key < current.key ? current.left : current.right;
2311
+ }
2312
+ }
2313
+ has(key) {
2314
+ let current = this.root;
2315
+ while (current) {
2316
+ if (key === current.key) return true;
2317
+ current = key < current.key ? current.left : current.right;
2318
+ }
2319
+ return false;
2320
+ }
2321
+ set(key, value) {
2322
+ return new PersistentKeyedIndex(setNode(this.root, key, value));
2323
+ }
2324
+ remove(key) {
2325
+ return new PersistentKeyedIndex(removeNode(this.root, key));
2326
+ }
2327
+ };
2328
+ //#endregion
2329
+ //#region core/src/projection/output/collection.ts
2330
+ const createPublishedCollection = () => {
2331
+ const values = /* @__PURE__ */ new Map();
2332
+ let ids = Object.freeze([]);
2333
+ let index = PersistentKeyedIndex.empty();
2334
+ return {
2335
+ get: (key) => values.get(key),
2336
+ has: (key) => values.has(key),
2337
+ keys: () => values.keys(),
2338
+ size: () => values.size,
2339
+ ids: () => ids,
2340
+ read: (check) => {
2341
+ const snapshotIndex = index;
2342
+ const snapshotIds = ids;
2343
+ return Object.freeze({
2344
+ get: (key) => {
2345
+ check();
2346
+ return snapshotIndex.get(key);
2347
+ },
2348
+ has: (key) => {
2349
+ check();
2350
+ return snapshotIndex.has(key);
2351
+ },
2352
+ ids: () => {
2353
+ check();
2354
+ return snapshotIds;
2355
+ }
2356
+ });
2357
+ },
2358
+ publish: (staged, nextIds, reset) => {
2359
+ if (reset) {
2360
+ const entries = [];
2361
+ for (const [key, entry] of staged) if (entry.present) entries.push([key, entry.value]);
2362
+ index = PersistentKeyedIndex.from(entries);
2363
+ values.clear();
2364
+ } else for (const [key, entry] of staged) index = entry.present ? index.set(key, entry.value) : index.remove(key);
2365
+ for (const [key, entry] of staged) if (entry.present) values.set(key, entry.value);
2366
+ else values.delete(key);
2367
+ ids = nextIds;
2368
+ },
2369
+ release: () => {
2370
+ values.clear();
2371
+ ids = Object.freeze([]);
2372
+ index = PersistentKeyedIndex.empty();
2373
+ }
2374
+ };
2375
+ };
2376
+ /** Owns staged keyed intent, exact transitions and published collection state. */
2377
+ const createCollectionOutput = () => {
2378
+ const published = createPublishedCollection();
2379
+ let staged = /* @__PURE__ */ new Map();
2380
+ let nextIds = published.ids();
2381
+ let change;
2382
+ let initialized = false;
2383
+ let reset = false;
2384
+ let revision = 0;
2385
+ let explicitOrder;
2386
+ let cleared = false;
2387
+ const listeners = /* @__PURE__ */ new Set();
2388
+ const hasNext = (key) => staged.has(key) ? staged.get(key).present : !cleared && published.has(key);
2389
+ const getNext = (key) => {
2390
+ const entry = staged.get(key);
2391
+ return entry ? entry.present ? entry.value : void 0 : cleared ? void 0 : published.get(key);
2392
+ };
2393
+ const deriveIds = () => {
2394
+ const result = cleared ? [] : published.ids().filter(hasNext);
2395
+ for (const [key, entry] of staged) if (entry.present && (cleared || !published.has(key))) result.push(key);
2396
+ return result;
2397
+ };
2398
+ const begin = (active, initialize) => {
2399
+ staged = /* @__PURE__ */ new Map();
2400
+ nextIds = published.ids();
2401
+ change = void 0;
2402
+ explicitOrder = void 0;
2403
+ cleared = initialize;
2404
+ reset = initialize;
2405
+ const read = (next) => ({
2406
+ get: (key) => {
2407
+ require_advanced.assertScope(active);
2408
+ return next ? getNext(key) : published.get(key);
2409
+ },
2410
+ has: (key) => {
2411
+ require_advanced.assertScope(active);
2412
+ return next ? hasNext(key) : published.has(key);
2413
+ },
2414
+ ids: () => {
2415
+ require_advanced.assertScope(active);
2416
+ return next ? Object.freeze(explicitOrder ? [...explicitOrder] : [...deriveIds()]) : published.ids();
2417
+ }
2418
+ });
2419
+ return {
2420
+ previous: read(false),
2421
+ next: read(true),
2422
+ output: {
2423
+ set: (key, value) => {
2424
+ require_advanced.assertScope(active);
2425
+ if (typeof key !== "string") throw new TypeError("Projection keys must be strings.");
2426
+ staged.set(key, {
2427
+ present: true,
2428
+ value
2429
+ });
2430
+ },
2431
+ remove: (key) => {
2432
+ require_advanced.assertScope(active);
2433
+ staged.set(key, { present: false });
2434
+ },
2435
+ order: (order) => {
2436
+ require_advanced.assertScope(active);
2437
+ explicitOrder = Object.freeze([...order]);
2438
+ }
2439
+ }
2440
+ };
2441
+ };
2442
+ const seal = (nextReset, isEqual) => {
2443
+ if (cleared) {
2444
+ for (const key of published.keys()) if (!staged.has(key)) staged.set(key, { present: false });
2445
+ }
2446
+ require_advanced.profile.projection("touchedKeys", staged.size);
2447
+ const added = /* @__PURE__ */ new Set();
2448
+ const removed = /* @__PURE__ */ new Set();
2449
+ const updated = /* @__PURE__ */ new Set();
2450
+ for (const [key, entry] of staged) {
2451
+ const existed = published.has(key);
2452
+ if (entry.present) {
2453
+ if (!existed) added.add(key);
2454
+ else if (!isEqual(published.get(key), entry.value)) updated.add(key);
2455
+ else if (!nextReset) staged.delete(key);
2456
+ } else if (existed) removed.add(key);
2457
+ else staged.delete(key);
2458
+ }
2459
+ const ids = published.ids();
2460
+ if (explicitOrder || added.size || removed.size) {
2461
+ const order = explicitOrder ?? [...ids.filter((key) => !removed.has(key)), ...added];
2462
+ if (new Set(order).size !== order.length || order.length !== published.size() + added.size - removed.size || order.some((key) => !hasNext(key))) throw new TypeError("Projection order must contain every key exactly once.");
2463
+ nextIds = ids.length === order.length && ids.every((key, index) => key === order[index]) ? ids : Object.freeze([...order]);
2464
+ } else nextIds = ids;
2465
+ const changedKeys = new Set([
2466
+ ...added,
2467
+ ...removed,
2468
+ ...updated
2469
+ ]);
2470
+ require_advanced.profile.projection("changedKeys", changedKeys.size);
2471
+ const addedEntries = [];
2472
+ const updatedEntries = [];
2473
+ const removedEntries = [];
2474
+ for (const key of changedKeys) {
2475
+ const beforePresent = published.has(key);
2476
+ const afterPresent = hasNext(key);
2477
+ if (beforePresent === afterPresent) {
2478
+ if (!beforePresent || isEqual(published.get(key), getNext(key))) continue;
2479
+ }
2480
+ if (!beforePresent) addedEntries.push({
2481
+ key,
2482
+ after: getNext(key)
2483
+ });
2484
+ else if (!afterPresent) removedEntries.push({
2485
+ key,
2486
+ before: published.get(key)
2487
+ });
2488
+ else updatedEntries.push({
2489
+ key,
2490
+ before: published.get(key),
2491
+ after: getNext(key)
2492
+ });
2493
+ }
2494
+ change = nextReset ? Object.freeze({ kind: "reset" }) : createCollectionChange({
2495
+ added: addedEntries,
2496
+ updated: updatedEntries,
2497
+ removed: removedEntries,
2498
+ beforeOrder: ids,
2499
+ afterOrder: nextIds
2500
+ });
2501
+ reset = nextReset;
2502
+ return change !== void 0;
2503
+ };
2504
+ const context = (active, cause) => Object.freeze({
2505
+ kind: "collection",
2506
+ read: {
2507
+ get: (key) => {
2508
+ require_advanced.assertScope(active);
2509
+ return getNext(key);
2510
+ },
2511
+ has: (key) => {
2512
+ require_advanced.assertScope(active);
2513
+ return hasNext(key);
2514
+ },
2515
+ ids: () => {
2516
+ require_advanced.assertScope(active);
2517
+ return nextIds;
2518
+ }
2519
+ },
2520
+ change,
2521
+ revision,
2522
+ reset,
2523
+ cause
2524
+ });
2525
+ return {
2526
+ begin,
2527
+ seal,
2528
+ context,
2529
+ current: (check) => published.read(check),
2530
+ revision: () => revision,
2531
+ reset: () => reset,
2532
+ publish: () => {
2533
+ if (change) published.publish(staged, nextIds, change.kind === "reset");
2534
+ if (change && initialized) revision++;
2535
+ initialized = true;
2536
+ },
2537
+ emit: (call) => {
2538
+ const resetEvent = Object.freeze({ kind: "reset" });
2539
+ Array.from(listeners).forEach((listener) => call(() => listener(change ?? resetEvent)));
2540
+ },
2541
+ clear: () => {
2542
+ staged.clear();
2543
+ nextIds = published.ids();
2544
+ change = void 0;
2545
+ reset = false;
2546
+ explicitOrder = void 0;
2547
+ cleared = false;
2548
+ },
2549
+ release: () => {
2550
+ published.release();
2551
+ staged.clear();
2552
+ listeners.clear();
2553
+ nextIds = Object.freeze([]);
2554
+ change = void 0;
2555
+ initialized = false;
2556
+ revision = 0;
2557
+ reset = false;
2558
+ explicitOrder = void 0;
2559
+ cleared = false;
2560
+ },
2561
+ subscribe: (listener) => listeners.add(listener),
2562
+ unsubscribe: (listener) => listeners.delete(listener)
2563
+ };
2564
+ };
1016
2565
  //#endregion
1017
- //#region core/src/projection/value-output.ts
2566
+ //#region core/src/projection/output/value.ts
1018
2567
  const unset = Symbol("projection-value-unset");
1019
2568
  /** Owns staged and published state for one scalar Projection output. */
1020
2569
  const createValueOutput = () => {
@@ -1083,7 +2632,7 @@ const createValueOutput = () => {
1083
2632
  initialized = true;
1084
2633
  },
1085
2634
  emit: (call) => {
1086
- require_issue.profile.materialized.notification();
2635
+ require_advanced.profile.materialized.notification();
1087
2636
  Array.from(listeners).forEach((listener) => call(listener));
1088
2637
  },
1089
2638
  clear: () => {
@@ -1106,7 +2655,7 @@ const createValueOutput = () => {
1106
2655
  };
1107
2656
  };
1108
2657
  //#endregion
1109
- //#region core/src/projection/processor.ts
2658
+ //#region core/src/projection/graph/processor.ts
1110
2659
  /** Materializes every derive/incremental/group definition through one processor lifecycle. */
1111
2660
  const createProcessor = (scheduler, definition, dependencies) => {
1112
2661
  scheduler.assertIdle();
@@ -1146,7 +2695,7 @@ const createProcessor = (scheduler, definition, dependencies) => {
1146
2695
  }
1147
2696
  };
1148
2697
  }
1149
- const state = require_advanced.createCollectionOutput();
2698
+ const state = createCollectionOutput();
1150
2699
  return {
1151
2700
  kind: "collection",
1152
2701
  definition: outputDefinition,
@@ -1200,7 +2749,7 @@ const createProcessor = (scheduler, definition, dependencies) => {
1200
2749
  const sources = Object.freeze(dependencies.map((output) => output.context(scopeActive)));
1201
2750
  let outputs = begin(scopeActive, reset);
1202
2751
  if (!instance) instance = definition.create();
1203
- require_issue.profile.materialized[reset ? "rebuilt" : "updated"]();
2752
+ require_advanced.profile.materialized[reset ? "rebuilt" : "updated"]();
1204
2753
  let result = instance.evaluate({
1205
2754
  reset,
1206
2755
  cause: runCause,
@@ -1268,7 +2817,7 @@ const createProcessor = (scheduler, definition, dependencies) => {
1268
2817
  return processor;
1269
2818
  };
1270
2819
  //#endregion
1271
- //#region core/src/projection/projection-readable.ts
2820
+ //#region core/src/projection/readable/selection.ts
1272
2821
  let activeTracker;
1273
2822
  const trackKey = (key) => {
1274
2823
  activeTracker?.keys.add(key);
@@ -1319,9 +2868,10 @@ const trackedMap = (source) => {
1319
2868
  };
1320
2869
  const selectionAffects = (selection, change) => {
1321
2870
  if (!change || change.kind === "reset") return true;
1322
- if (selection.all && (change.added.length || change.removed.length || change.updated.length || change.order)) return true;
1323
- if (selection.structure && (change.added.length || change.removed.length || change.order)) return true;
1324
- for (const key of selection.keys) if (change.added.some((entry) => entry.key === key) || change.removed.some((entry) => entry.key === key) || change.updated.some((entry) => entry.key === key)) return true;
2871
+ if (selection.all && collectionHasAnyChange(change)) return true;
2872
+ if (selection.structure && collectionHasStructuralChange(change)) return true;
2873
+ const changedKeys = collectionChangedKeys(change);
2874
+ for (const key of selection.keys) if (changedKeys.has(key)) return true;
1325
2875
  return false;
1326
2876
  };
1327
2877
  const createDirectReadable = (source) => Object.freeze({
@@ -1389,7 +2939,7 @@ const createSelectorReadable = (source, selector, equality = Object.is) => {
1389
2939
  if (!change && previousCollection) {
1390
2940
  const current = source.current();
1391
2941
  if (isMapLike(current)) {
1392
- change = require_advanced.collectionChangeBetween(previousCollection, current);
2942
+ change = diffCollection(previousCollection, current);
1393
2943
  previousCollection = current;
1394
2944
  if (!change) {
1395
2945
  sourceRevision = source.revision();
@@ -1428,7 +2978,7 @@ const createSelectorReadable = (source, selector, equality = Object.is) => {
1428
2978
  });
1429
2979
  };
1430
2980
  //#endregion
1431
- //#region core/src/projection/document-materialization.ts
2981
+ //#region core/src/projection/source/materialization.ts
1432
2982
  const createDocumentDirty = () => ({
1433
2983
  replace: false,
1434
2984
  order: false,
@@ -1476,10 +3026,10 @@ const markDocumentTree = (dirty, path, root, nodes) => {
1476
3026
  current.treeRoot ||= root;
1477
3027
  for (const id of nodes) current.treeNodes.add(id);
1478
3028
  };
1479
- const equivalent = (node, left, right) => node.kind === "field" ? Object.is(left, right) : require_access.equalValue(node, left, right);
1480
- const replaceValue = (node, previous, current) => equivalent(node, previous, current) ? previous : require_access.copyValue(node, current);
3029
+ const equivalent = (node, left, right) => node.kind === "field" ? Object.is(left, right) : require_advanced.equalValue(node, left, right);
3030
+ const replaceValue = (node, previous, current) => equivalent(node, previous, current) ? previous : require_advanced.copyValue(node, current);
1481
3031
  const cloneRecord = (value) => {
1482
- require_issue.profile.copy.shallowRecord(Object.getOwnPropertyNames(value).length);
3032
+ require_advanced.profile.copy.shallowRecord(Object.getOwnPropertyNames(value).length);
1483
3033
  return Object.create(Object.getPrototypeOf(value), Object.getOwnPropertyDescriptors(value));
1484
3034
  };
1485
3035
  const materializeRecordChild = (node, previous, current, key, dirty) => {
@@ -1491,7 +3041,7 @@ const materializeRecordChild = (node, previous, current, key, dirty) => {
1491
3041
  present: false,
1492
3042
  value: void 0
1493
3043
  };
1494
- const next = before ? materializeDocumentValue(node, previous[key], current[key], dirty) : require_access.copyValue(node, current[key]);
3044
+ const next = before ? materializeDocumentValue(node, previous[key], current[key], dirty) : require_advanced.copyValue(node, current[key]);
1495
3045
  if (before && next === previous[key]) return { changed: false };
1496
3046
  return {
1497
3047
  changed: true,
@@ -1501,7 +3051,7 @@ const materializeRecordChild = (node, previous, current, key, dirty) => {
1501
3051
  };
1502
3052
  const materializeObject = (node, previous, current, dirty) => {
1503
3053
  if (node.kind === "variant" && previous[node.tag] !== current[node.tag]) return replaceValue(node, previous, current);
1504
- const layout = require_issue.compiledShape(node, current);
3054
+ const layout = require_advanced.compiledShape(node, current);
1505
3055
  if (!layout) return replaceValue(node, previous, current);
1506
3056
  let result;
1507
3057
  for (const [key, childDirty] of dirty.children) {
@@ -1510,7 +3060,7 @@ const materializeObject = (node, previous, current, dirty) => {
1510
3060
  const child = materializeRecordChild(member.node, previous, current, key, childDirty);
1511
3061
  if (!child.changed) continue;
1512
3062
  result ??= cloneRecord(previous);
1513
- installMember(result, key, child.present, child.value);
3063
+ require_context.installOwn(result, key, child.present, child.value);
1514
3064
  }
1515
3065
  return result ?? previous;
1516
3066
  };
@@ -1520,12 +3070,12 @@ const materializeMap = (node, previous, current, dirty) => {
1520
3070
  const child = materializeRecordChild(node.value, previous, current, key, childDirty);
1521
3071
  if (!child.changed) continue;
1522
3072
  result ??= cloneRecord(previous);
1523
- installMember(result, key, child.present, child.value);
3073
+ require_context.installOwn(result, key, child.present, child.value);
1524
3074
  }
1525
3075
  return result ?? previous;
1526
3076
  };
1527
3077
  const materializeTable = (node, previous, current, dirty) => {
1528
- if (!require_issue.isRecord(previous.byId) || !require_issue.isRecord(current.byId)) return replaceValue(node, previous, current);
3078
+ if (!require_context.isRecord(previous.byId) || !require_context.isRecord(current.byId)) return replaceValue(node, previous, current);
1529
3079
  const beforeById = previous.byId;
1530
3080
  const afterById = current.byId;
1531
3081
  let result;
@@ -1534,28 +3084,28 @@ const materializeTable = (node, previous, current, dirty) => {
1534
3084
  const child = materializeRecordChild(node.value, beforeById, afterById, key, childDirty);
1535
3085
  if (!child.changed) continue;
1536
3086
  nextById ??= cloneRecord(beforeById);
1537
- installMember(nextById, key, child.present, child.value);
3087
+ require_context.installOwn(nextById, key, child.present, child.value);
1538
3088
  }
1539
3089
  if (nextById) {
1540
3090
  result = cloneRecord(previous);
1541
- installMember(result, "byId", true, nextById);
3091
+ require_context.installOwn(result, "byId", true, nextById);
1542
3092
  }
1543
3093
  if (dirty.order) {
1544
3094
  const beforeIds = previous.ids;
1545
3095
  const afterIds = current.ids;
1546
3096
  if (!Array.isArray(beforeIds) || !Array.isArray(afterIds)) return replaceValue(node, previous, current);
1547
- if (!require_issue.equal(beforeIds, afterIds)) {
3097
+ if (!require_advanced.equal(beforeIds, afterIds)) {
1548
3098
  result ??= cloneRecord(previous);
1549
- installMember(result, "ids", true, [...afterIds]);
3099
+ require_context.installOwn(result, "ids", true, [...afterIds]);
1550
3100
  }
1551
3101
  }
1552
3102
  return result ?? previous;
1553
3103
  };
1554
3104
  const materializeList = (node, previous, current, dirty) => {
1555
3105
  if (dirty.order) {
1556
- const before = require_issue.listSequence(previous, node.keyOf);
1557
- const after = require_issue.listSequence(current, node.keyOf);
1558
- let changed = !require_issue.equal(before.order, after.order);
3106
+ const before = require_advanced.listSequence(previous, node.keyOf);
3107
+ const after = require_advanced.listSequence(current, node.keyOf);
3108
+ let changed = !require_advanced.equal(before.order, after.order);
1559
3109
  const result = new Array(after.order.length);
1560
3110
  for (let index = 0; index < after.order.length; index++) {
1561
3111
  const key = after.order[index];
@@ -1574,8 +3124,8 @@ const materializeList = (node, previous, current, dirty) => {
1574
3124
  return changed ? result : previous;
1575
3125
  }
1576
3126
  let result;
1577
- const before = require_issue.indexedKeys(previous, node.keyOf);
1578
- const after = require_issue.indexedKeys(current, node.keyOf);
3127
+ const before = require_advanced.indexedKeys(previous, node.keyOf);
3128
+ const after = require_advanced.indexedKeys(current, node.keyOf);
1579
3129
  for (const [key, childDirty] of dirty.children) {
1580
3130
  const previousIndex = before.index(key);
1581
3131
  const currentIndex = after.index(key);
@@ -1588,14 +3138,14 @@ const materializeList = (node, previous, current, dirty) => {
1588
3138
  return result ?? previous;
1589
3139
  };
1590
3140
  const materializeTree = (node, previous, current, dirty) => {
1591
- if (!require_issue.isRecord(previous.nodes) || !require_issue.isRecord(current.nodes)) return replaceValue(node, previous, current);
3141
+ if (!require_context.isRecord(previous.nodes) || !require_context.isRecord(current.nodes)) return replaceValue(node, previous, current);
1592
3142
  let result;
1593
3143
  if (dirty.treeRoot) {
1594
3144
  const beforePresent = Object.hasOwn(previous, "rootId");
1595
3145
  const afterPresent = Object.hasOwn(current, "rootId");
1596
3146
  if (beforePresent !== afterPresent || !Object.is(previous.rootId, current.rootId)) {
1597
3147
  result = cloneRecord(previous);
1598
- installMember(result, "rootId", afterPresent, current.rootId);
3148
+ require_context.installOwn(result, "rootId", afterPresent, current.rootId);
1599
3149
  }
1600
3150
  }
1601
3151
  let nodes;
@@ -1604,13 +3154,13 @@ const materializeTree = (node, previous, current, dirty) => {
1604
3154
  const afterPresent = Object.hasOwn(current.nodes, id);
1605
3155
  const before = beforePresent ? previous.nodes[id] : void 0;
1606
3156
  const after = afterPresent ? current.nodes[id] : void 0;
1607
- if (beforePresent === afterPresent && require_access.equalTreeNode(before, after)) continue;
3157
+ if (beforePresent === afterPresent && require_advanced.equalTreeNode(before, after)) continue;
1608
3158
  nodes ??= cloneRecord(previous.nodes);
1609
- installMember(nodes, id, afterPresent, after && require_access.copyTreeNode(after));
3159
+ require_context.installOwn(nodes, id, afterPresent, after && require_advanced.copyTreeNode(after));
1610
3160
  }
1611
3161
  if (nodes) {
1612
3162
  result ??= cloneRecord(previous);
1613
- installMember(result, "nodes", true, nodes);
3163
+ require_context.installOwn(result, "nodes", true, nodes);
1614
3164
  }
1615
3165
  return result ?? previous;
1616
3166
  };
@@ -1618,28 +3168,129 @@ const materializeDocumentValue = (node, previous, current, dirty) => {
1618
3168
  if (!hasDocumentDirty(dirty)) return previous;
1619
3169
  if (dirty.replace || previous === void 0 || current === void 0 || node.kind === "field") return replaceValue(node, previous, current);
1620
3170
  if (node.kind === "object" || node.kind === "variant") {
1621
- if (!require_issue.isRecord(previous) || !require_issue.isRecord(current)) return replaceValue(node, previous, current);
3171
+ if (!require_context.isRecord(previous) || !require_context.isRecord(current)) return replaceValue(node, previous, current);
1622
3172
  return materializeObject(node, previous, current, dirty);
1623
3173
  }
1624
3174
  if (node.kind === "map") {
1625
- if (!require_issue.isRecord(previous) || !require_issue.isRecord(current)) return replaceValue(node, previous, current);
3175
+ if (!require_context.isRecord(previous) || !require_context.isRecord(current)) return replaceValue(node, previous, current);
1626
3176
  return materializeMap(node, previous, current, dirty);
1627
3177
  }
1628
3178
  if (node.kind === "table") {
1629
- if (!require_issue.isRecord(previous) || !require_issue.isRecord(current)) return replaceValue(node, previous, current);
3179
+ if (!require_context.isRecord(previous) || !require_context.isRecord(current)) return replaceValue(node, previous, current);
1630
3180
  return materializeTable(node, previous, current, dirty);
1631
3181
  }
1632
3182
  if (node.kind === "list") {
1633
3183
  if (!Array.isArray(previous) || !Array.isArray(current)) return replaceValue(node, previous, current);
1634
3184
  return materializeList(node, previous, current, dirty);
1635
3185
  }
1636
- if (!require_issue.isRecord(previous) || !require_issue.isRecord(current)) return replaceValue(node, previous, current);
3186
+ if (!require_context.isRecord(previous) || !require_context.isRecord(current)) return replaceValue(node, previous, current);
1637
3187
  return materializeTree(node, previous, current, dirty);
1638
3188
  };
1639
3189
  //#endregion
1640
- //#region core/src/projection/source.ts
1641
- const sourceError = (source, cause) => new require_advanced.ProjectionError("source", source.name, [source.outputs[0].revision()], cause);
1642
- const createValueBoundary = (scheduler, name, initial, equality, prepare, clearSource) => {
3190
+ //#region core/src/projection/source/dirty.ts
3191
+ const createCollectionPending = () => ({
3192
+ reset: false,
3193
+ order: false,
3194
+ entries: /* @__PURE__ */ new Map()
3195
+ });
3196
+ const resetCollectionPending = (pending) => {
3197
+ pending.reset = true;
3198
+ pending.order = false;
3199
+ pending.entries.clear();
3200
+ };
3201
+ const clearCollectionPending = (pending) => {
3202
+ pending.reset = false;
3203
+ pending.order = false;
3204
+ pending.entries.clear();
3205
+ };
3206
+ const dirtyEntry = (pending, key) => {
3207
+ let dirty = pending.entries.get(key);
3208
+ if (!dirty) {
3209
+ dirty = createDocumentDirty();
3210
+ pending.entries.set(key, dirty);
3211
+ }
3212
+ return dirty;
3213
+ };
3214
+ const mergeValueChanges = (selector, dirty, changes) => {
3215
+ if (selector.tree) return;
3216
+ const at = selector.address;
3217
+ for (const change of changes.changes) {
3218
+ if (change.kind === "reset") {
3219
+ markDocumentReplace(dirty, []);
3220
+ return;
3221
+ }
3222
+ if (change.kind === "members") {
3223
+ for (const member of change.members) {
3224
+ const changed = [...change.at, member.key];
3225
+ if (contains(changed, at)) markDocumentReplace(dirty, []);
3226
+ else if (contains(at, changed)) markDocumentReplace(dirty, changed.slice(at.length));
3227
+ }
3228
+ if (change.order && contains(at, change.at)) markDocumentOrder(dirty, change.at.slice(at.length));
3229
+ continue;
3230
+ }
3231
+ if (contains(at, change.at)) markDocumentTree(dirty, change.at.slice(at.length), change.before !== change.after, change.nodes.map((node) => node.id));
3232
+ }
3233
+ };
3234
+ const mergeCollectionChanges = (selector, pending, changes) => {
3235
+ if (pending.reset) return;
3236
+ const at = selector.address;
3237
+ for (const change of changes.changes) {
3238
+ if (change.kind === "reset") {
3239
+ resetCollectionPending(pending);
3240
+ return;
3241
+ }
3242
+ if (selector.tree?.kind === "nodes") {
3243
+ if (change.kind === "members") {
3244
+ for (const member of change.members) if (contains([...change.at, member.key], at)) {
3245
+ resetCollectionPending(pending);
3246
+ return;
3247
+ }
3248
+ } else if (change.at.length === at.length && contains(change.at, at)) for (const node of change.nodes) {
3249
+ markDocumentReplace(dirtyEntry(pending, node.id), []);
3250
+ pending.order ||= node.kind !== "updated";
3251
+ }
3252
+ else if (contains(change.at, at)) {
3253
+ resetCollectionPending(pending);
3254
+ return;
3255
+ }
3256
+ continue;
3257
+ }
3258
+ if (change.kind === "members") {
3259
+ for (const member of change.members) {
3260
+ const changed = [...change.at, member.key];
3261
+ if (contains(changed, at)) {
3262
+ resetCollectionPending(pending);
3263
+ return;
3264
+ }
3265
+ if (!contains(at, changed)) continue;
3266
+ const relative = changed.slice(at.length);
3267
+ if (!relative.length) {
3268
+ resetCollectionPending(pending);
3269
+ return;
3270
+ }
3271
+ markDocumentReplace(dirtyEntry(pending, relative[0]), relative.slice(1));
3272
+ if (relative.length === 1 && member.kind !== "updated") pending.order = true;
3273
+ }
3274
+ if (change.order && contains(at, change.at)) {
3275
+ const relative = change.at.slice(at.length);
3276
+ if (!relative.length) pending.order = true;
3277
+ else markDocumentOrder(dirtyEntry(pending, relative[0]), relative.slice(1));
3278
+ }
3279
+ continue;
3280
+ }
3281
+ if (!contains(at, change.at)) continue;
3282
+ const relative = change.at.slice(at.length);
3283
+ if (!relative.length) {
3284
+ resetCollectionPending(pending);
3285
+ return;
3286
+ }
3287
+ markDocumentTree(dirtyEntry(pending, relative[0]), relative.slice(1), change.before !== change.after, change.nodes.map((node) => node.id));
3288
+ }
3289
+ };
3290
+ //#endregion
3291
+ //#region core/src/projection/source/boundary.ts
3292
+ const sourceError = (source, cause) => new require_advanced.ProjectionError("source", source.name, [source.outputs[0].revision()], cause);
3293
+ const createValueBoundary = (scheduler, name, initial, equality, prepare, clearSource) => {
1643
3294
  const state = createValueOutput();
1644
3295
  let boundary;
1645
3296
  let pendingReset = false;
@@ -1746,8 +3397,35 @@ const createValueBoundary = (scheduler, name, initial, equality, prepare, clearS
1746
3397
  }
1747
3398
  };
1748
3399
  };
3400
+ /** Applies source hints to an output draft; exact net change semantics remain in the output. */
3401
+ const stageCollectionRead = (state, read, active, options) => {
3402
+ const evaluation = state.begin(active, options.reset);
3403
+ if (options.reset) {
3404
+ const ids = read.ids();
3405
+ require_advanced.profile.collectionView.idsScanned(ids.length);
3406
+ for (const key of ids) {
3407
+ require_advanced.profile.collectionView.mapped();
3408
+ evaluation.output.set(key, read.get(key));
3409
+ }
3410
+ evaluation.output.order(ids);
3411
+ } else {
3412
+ const previous = state.current(() => void 0);
3413
+ const keys = options.candidates ? [...new Set(options.candidates)] : [...new Set([...previous.ids(), ...read.ids()])];
3414
+ if (!options.candidates) require_advanced.profile.collectionView.idsScanned(keys.length);
3415
+ for (const key of keys) if (read.has(key)) {
3416
+ require_advanced.profile.collectionView.mapped();
3417
+ evaluation.output.set(key, read.get(key));
3418
+ } else evaluation.output.remove(key);
3419
+ if (options.orderMayChange || !options.candidates) {
3420
+ const ids = read.ids();
3421
+ if (options.candidates) require_advanced.profile.collectionView.idsScanned(ids.length);
3422
+ evaluation.output.order(ids);
3423
+ }
3424
+ }
3425
+ return state.seal(options.reset, options.isEqual ?? Object.is);
3426
+ };
1749
3427
  const createCollectionBoundary = (scheduler, name, readLatest, equality, clearSource) => {
1750
- const state = require_advanced.createCollectionOutput();
3428
+ const state = createCollectionOutput();
1751
3429
  let boundary;
1752
3430
  let pendingReset = false;
1753
3431
  let pendingCause;
@@ -1793,7 +3471,7 @@ const createCollectionBoundary = (scheduler, name, readLatest, equality, clearSo
1793
3471
  contextCause = cause;
1794
3472
  let active = true;
1795
3473
  try {
1796
- const changed = require_advanced.stageCollectionRead(state, readLatest(() => active, state.current(() => void 0)), () => active, {
3474
+ const changed = stageCollectionRead(state, readLatest(() => active, state.current(() => void 0)), () => active, {
1797
3475
  reset: pendingReset,
1798
3476
  ...fullScan ? {} : { candidates },
1799
3477
  orderMayChange,
@@ -1831,7 +3509,7 @@ const createCollectionBoundary = (scheduler, name, readLatest, equality, clearSo
1831
3509
  scheduler.initialize(() => {
1832
3510
  let active = true;
1833
3511
  try {
1834
- require_advanced.stageCollectionRead(state, readLatest(() => active, state.current(() => void 0)), () => active, {
3512
+ stageCollectionRead(state, readLatest(() => active, state.current(() => void 0)), () => active, {
1835
3513
  reset: true,
1836
3514
  isEqual: equality
1837
3515
  });
@@ -1867,129 +3545,30 @@ const createCollectionBoundary = (scheduler, name, readLatest, equality, clearSo
1867
3545
  }
1868
3546
  };
1869
3547
  };
3548
+ //#endregion
3549
+ //#region core/src/projection/source/document.ts
1870
3550
  const documentRootTarget = Object.freeze({
1871
3551
  kind: "value",
1872
3552
  at: Object.freeze([])
1873
3553
  });
1874
- const createCollectionPending = () => ({
1875
- reset: false,
1876
- order: false,
1877
- entries: /* @__PURE__ */ new Map()
1878
- });
1879
- const resetCollectionPending = (pending) => {
1880
- pending.reset = true;
1881
- pending.order = false;
1882
- pending.entries.clear();
1883
- };
1884
- const clearCollectionPending = (pending) => {
1885
- pending.reset = false;
1886
- pending.order = false;
1887
- pending.entries.clear();
1888
- };
1889
- const dirtyEntry = (pending, key) => {
1890
- let dirty = pending.entries.get(key);
1891
- if (!dirty) {
1892
- dirty = createDocumentDirty();
1893
- pending.entries.set(key, dirty);
1894
- }
1895
- return dirty;
1896
- };
1897
- const mergeValueChanges = (selector, dirty, changes) => {
1898
- if (selector.tree) return;
1899
- const at = selector.address;
1900
- for (const change of changes.changes) {
1901
- if (change.kind === "reset") {
1902
- markDocumentReplace(dirty, []);
1903
- return;
1904
- }
1905
- if (change.kind === "members") {
1906
- for (const member of change.members) {
1907
- const changed = [...change.at, member.key];
1908
- if (require_issue.contains(changed, at)) markDocumentReplace(dirty, []);
1909
- else if (require_issue.contains(at, changed)) markDocumentReplace(dirty, changed.slice(at.length));
1910
- }
1911
- if (change.order && require_issue.contains(at, change.at)) markDocumentOrder(dirty, change.at.slice(at.length));
1912
- continue;
1913
- }
1914
- if (require_issue.contains(at, change.at)) markDocumentTree(dirty, change.at.slice(at.length), change.before !== change.after, change.nodes.map((node) => node.id));
1915
- }
1916
- };
1917
- const mergeCollectionChanges = (selector, pending, changes) => {
1918
- if (pending.reset) return;
1919
- const at = selector.address;
1920
- for (const change of changes.changes) {
1921
- if (change.kind === "reset") {
1922
- resetCollectionPending(pending);
1923
- return;
1924
- }
1925
- if (selector.tree?.kind === "nodes") {
1926
- if (change.kind === "members") {
1927
- for (const member of change.members) if (require_issue.contains([...change.at, member.key], at)) {
1928
- resetCollectionPending(pending);
1929
- return;
1930
- }
1931
- } else if (change.at.length === at.length && require_issue.contains(change.at, at)) for (const node of change.nodes) {
1932
- markDocumentReplace(dirtyEntry(pending, node.id), []);
1933
- pending.order ||= node.kind !== "updated";
1934
- }
1935
- else if (require_issue.contains(change.at, at)) {
1936
- resetCollectionPending(pending);
1937
- return;
1938
- }
1939
- continue;
1940
- }
1941
- if (change.kind === "members") {
1942
- for (const member of change.members) {
1943
- const changed = [...change.at, member.key];
1944
- if (require_issue.contains(changed, at)) {
1945
- resetCollectionPending(pending);
1946
- return;
1947
- }
1948
- if (!require_issue.contains(at, changed)) continue;
1949
- const relative = changed.slice(at.length);
1950
- if (!relative.length) {
1951
- resetCollectionPending(pending);
1952
- return;
1953
- }
1954
- markDocumentReplace(dirtyEntry(pending, relative[0]), relative.slice(1));
1955
- if (relative.length === 1 && member.kind !== "updated") pending.order = true;
1956
- }
1957
- if (change.order && require_issue.contains(at, change.at)) {
1958
- const relative = change.at.slice(at.length);
1959
- if (!relative.length) pending.order = true;
1960
- else markDocumentOrder(dirtyEntry(pending, relative[0]), relative.slice(1));
1961
- }
1962
- continue;
1963
- }
1964
- if (!require_issue.contains(at, change.at)) continue;
1965
- const relative = change.at.slice(at.length);
1966
- if (!relative.length) {
1967
- resetCollectionPending(pending);
1968
- return;
1969
- }
1970
- markDocumentTree(dirtyEntry(pending, relative[0]), relative.slice(1), change.before !== change.after, change.nodes.map((node) => node.id));
1971
- }
1972
- };
1973
- const createSourceRegistry = (scheduler) => {
3554
+ const createDocumentSourceRegistry = (scheduler) => {
1974
3555
  const documents = /* @__PURE__ */ new Map();
1975
- const readables = /* @__PURE__ */ new Map();
1976
- const externalValues = /* @__PURE__ */ new WeakMap();
1977
- const externalCollections = /* @__PURE__ */ new WeakMap();
1978
- const documentConnection = (runtime) => {
1979
- const state = require_access.accessOf(runtime);
3556
+ const connection = (runtime) => {
3557
+ const context = require_context.contextOf(runtime);
3558
+ const state = context.state;
1980
3559
  const cached = documents.get(state);
1981
3560
  if (cached) return cached;
1982
3561
  if (state.disposed) throw new Error("Document has been disposed.");
1983
3562
  const bindings = /* @__PURE__ */ new Set();
1984
- const index = new require_access.SubscriptionIndex(state.schema);
3563
+ const index = new SubscriptionIndex(state.schema);
1985
3564
  const candidates = /* @__PURE__ */ new Set();
1986
3565
  const guard = (locked) => {
1987
- state.projectionLocks = (state.projectionLocks ?? 0) + (locked ? 1 : -1);
3566
+ state.projectionLocks += locked ? 1 : -1;
1988
3567
  };
1989
3568
  scheduler.guards.add(guard);
1990
3569
  let closed = false;
1991
3570
  let detach = () => void 0;
1992
- const connection = {
3571
+ const documentConnection = {
1993
3572
  add(binding) {
1994
3573
  if (closed) throw new Error("Document projection connection is closed.");
1995
3574
  bindings.add(binding);
@@ -2000,7 +3579,7 @@ const createSourceRegistry = (scheduler) => {
2000
3579
  active = false;
2001
3580
  bindings.delete(binding);
2002
3581
  index.delete(binding.target, binding);
2003
- if (!bindings.size) connection.close();
3582
+ if (!bindings.size) documentConnection.close();
2004
3583
  };
2005
3584
  },
2006
3585
  close() {
@@ -2014,7 +3593,7 @@ const createSourceRegistry = (scheduler) => {
2014
3593
  documents.delete(state);
2015
3594
  }
2016
3595
  };
2017
- detach = require_notification.attachProjection(runtime, {
3596
+ detach = context.notifications.attachProjection({
2018
3597
  capture: (commit) => {
2019
3598
  candidates.clear();
2020
3599
  index.collect(commit.changes, (binding) => candidates.add(binding));
@@ -2027,112 +3606,14 @@ const createSourceRegistry = (scheduler) => {
2027
3606
  scheduler.run();
2028
3607
  }
2029
3608
  });
2030
- documents.set(state, connection);
2031
- return connection;
3609
+ documents.set(state, documentConnection);
3610
+ return documentConnection;
2032
3611
  };
2033
- const valueInput = (definition) => {
2034
- if (definition.source.kind !== "value-input") throw new Error("Invalid value input source.");
2035
- const source = definition.source;
2036
- let latest = source.initial;
2037
- const boundary = createValueBoundary(scheduler, "projection input", source.initial, source.equality, () => latest, () => void 0);
2038
- return {
2039
- ...boundary,
2040
- write: {
2041
- kind: "value",
2042
- set(value) {
2043
- scheduler.assertIdle();
2044
- latest = value;
2045
- boundary.mark();
2046
- scheduler.run();
2047
- }
2048
- }
2049
- };
2050
- };
2051
- const collectionInput = (definition) => {
2052
- if (definition.source.kind !== "collection-input") throw new Error("Invalid collection input source.");
2053
- const values = new Map(definition.source.initial);
2054
- const boundary = createCollectionBoundary(scheduler, "projection collection input", () => require_advanced.mapRead(values), definition.output.equality, () => void 0);
2055
- return {
2056
- ...boundary,
2057
- write: {
2058
- kind: "collection",
2059
- update(run) {
2060
- scheduler.assertIdle();
2061
- const staged = /* @__PURE__ */ new Map();
2062
- const operations = [];
2063
- let active = true;
2064
- const draft = Object.freeze({
2065
- get: (key) => {
2066
- require_advanced.assertScope(() => active);
2067
- const entry = staged.get(key);
2068
- return entry ? entry.present ? entry.value : void 0 : values.get(key);
2069
- },
2070
- has: (key) => {
2071
- require_advanced.assertScope(() => active);
2072
- const entry = staged.get(key);
2073
- return entry ? entry.present : values.has(key);
2074
- },
2075
- set: (key, value) => {
2076
- require_advanced.assertScope(() => active);
2077
- if (typeof key !== "string") throw new TypeError("Projection keys must be strings.");
2078
- staged.set(key, {
2079
- present: true,
2080
- value
2081
- });
2082
- operations.push({
2083
- kind: "set",
2084
- key,
2085
- value
2086
- });
2087
- },
2088
- remove: (key) => {
2089
- require_advanced.assertScope(() => active);
2090
- if (typeof key !== "string") throw new TypeError("Projection keys must be strings.");
2091
- staged.set(key, { present: false });
2092
- operations.push({
2093
- kind: "remove",
2094
- key
2095
- });
2096
- }
2097
- });
2098
- try {
2099
- require_advanced.assertSynchronous(run(draft));
2100
- } finally {
2101
- active = false;
2102
- }
2103
- const candidates = /* @__PURE__ */ new Set();
2104
- let structural = false;
2105
- let changed = false;
2106
- for (const operation of operations) {
2107
- const present = values.has(operation.key);
2108
- if (operation.kind === "set") {
2109
- if (present && Object.is(values.get(operation.key), operation.value)) continue;
2110
- structural ||= !present;
2111
- values.set(operation.key, operation.value);
2112
- } else {
2113
- if (!present) continue;
2114
- structural = true;
2115
- values.delete(operation.key);
2116
- }
2117
- candidates.add(operation.key);
2118
- changed = true;
2119
- }
2120
- if (!changed) return;
2121
- boundary.mark({
2122
- candidates,
2123
- orderMayChange: structural
2124
- });
2125
- scheduler.run();
2126
- }
2127
- }
2128
- };
2129
- };
2130
- const documentSource = (definition) => {
3612
+ const materialize = (definition) => {
2131
3613
  if (definition.source.kind !== "document") throw new Error("Invalid document source.");
2132
3614
  const { document, selector } = definition.source;
2133
- const state = require_access.accessOf(document);
2134
- const schemaNode = () => require_issue.nodeAt(state.schema, selector.address, state.document);
2135
- const currentValue = () => require_issue.read(state.document, selector.address, state.schema);
3615
+ const state = require_context.contextOf(document).state;
3616
+ const current = () => resolveValue(state.schema, state.document, selector.address);
2136
3617
  const disposed = () => {
2137
3618
  if (state.disposed) throw new Error("Document has been disposed.");
2138
3619
  };
@@ -2140,17 +3621,18 @@ const createSourceRegistry = (scheduler) => {
2140
3621
  const dirty = createDocumentDirty();
2141
3622
  const read = (previous) => {
2142
3623
  disposed();
2143
- const node = schemaNode();
2144
- const current = currentValue();
2145
- if (selector.tree?.kind === "root") return node?.kind === "tree" && require_issue.isRecord(current) && typeof current.rootId === "string" ? current.rootId : void 0;
3624
+ const resolved = current();
3625
+ const node = resolved?.node;
3626
+ const value = resolved?.value;
3627
+ if (selector.tree?.kind === "root") return node?.kind === "tree" && require_context.isRecord(value) && typeof value.rootId === "string" ? value.rootId : void 0;
2146
3628
  if (selector.tree?.kind === "node") {
2147
- if (node?.kind !== "tree" || !require_issue.isRecord(current) || !require_issue.isRecord(current.nodes)) return void 0;
2148
- const entry = Object.hasOwn(current.nodes, selector.tree.id) ? current.nodes[selector.tree.id] : void 0;
2149
- if (require_access.equalTreeNode(previous, entry)) return previous;
2150
- return entry ? require_access.copyTreeNode(entry) : void 0;
3629
+ if (node?.kind !== "tree" || !require_context.isRecord(value) || !require_context.isRecord(value.nodes)) return void 0;
3630
+ const entry = Object.hasOwn(value.nodes, selector.tree.id) ? value.nodes[selector.tree.id] : void 0;
3631
+ if (require_advanced.equalTreeNode(previous, entry)) return previous;
3632
+ return entry ? require_advanced.copyTreeNode(entry) : void 0;
2151
3633
  }
2152
3634
  if (!node) return void 0;
2153
- return previous === void 0 ? require_access.copyValue(node, current) : materializeDocumentValue(node, previous, current, dirty);
3635
+ return previous === void 0 ? require_advanced.copyValue(node, value) : materializeDocumentValue(node, previous, value, dirty);
2154
3636
  };
2155
3637
  const initial = read();
2156
3638
  let boundary;
@@ -2158,7 +3640,7 @@ const createSourceRegistry = (scheduler) => {
2158
3640
  if (failed) markDocumentReplace(dirty, []);
2159
3641
  else clearDocumentDirty(dirty);
2160
3642
  });
2161
- const remove = documentConnection(document).add({
3643
+ const remove = connection(document).add({
2162
3644
  target: selector,
2163
3645
  capture: (commit) => {
2164
3646
  try {
@@ -2176,8 +3658,9 @@ const createSourceRegistry = (scheduler) => {
2176
3658
  const pending = createCollectionPending();
2177
3659
  const read = (active, previous) => {
2178
3660
  disposed();
2179
- const node = schemaNode();
2180
- const value = currentValue();
3661
+ const resolved = current();
3662
+ const node = resolved?.node;
3663
+ const value = resolved?.value;
2181
3664
  const treeNodes = selector.tree?.kind === "nodes";
2182
3665
  const entryNode = !treeNodes && node ? require_advanced.collectionEntryNode(node) : void 0;
2183
3666
  const snapshots = /* @__PURE__ */ new Map();
@@ -2185,29 +3668,29 @@ const createSourceRegistry = (scheduler) => {
2185
3668
  if (pending.reset) markDocumentReplace(replacement, []);
2186
3669
  const ids = () => {
2187
3670
  require_advanced.assertScope(active);
2188
- if (treeNodes) return node?.kind === "tree" && require_issue.isRecord(value) && require_issue.isRecord(value.nodes) ? Object.freeze(Object.keys(value.nodes)) : Object.freeze([]);
2189
- if (node?.kind === "map" && require_issue.isRecord(value)) return Object.freeze(Object.keys(value));
2190
- if (node?.kind === "table" && require_issue.isRecord(value) && Array.isArray(value.ids)) return Object.freeze([...value.ids]);
2191
- if (node?.kind === "list" && Array.isArray(value)) return Object.freeze(require_issue.toArray(require_issue.indexedKeys(value, node.keyOf)));
3671
+ if (treeNodes) return node?.kind === "tree" && require_context.isRecord(value) && require_context.isRecord(value.nodes) ? Object.freeze(Object.keys(value.nodes)) : Object.freeze([]);
3672
+ if (node?.kind === "map" && require_context.isRecord(value)) return Object.freeze(Object.keys(value));
3673
+ if (node?.kind === "table" && require_context.isRecord(value) && Array.isArray(value.ids)) return Object.freeze([...value.ids]);
3674
+ if (node?.kind === "list" && Array.isArray(value)) return Object.freeze(require_advanced.toArray(require_advanced.indexedKeys(value, node.keyOf)));
2192
3675
  return Object.freeze([]);
2193
3676
  };
2194
3677
  const has = (key) => {
2195
3678
  require_advanced.assertScope(active);
2196
- if (treeNodes) return Boolean(node?.kind === "tree" && require_issue.isRecord(value) && require_issue.isRecord(value.nodes) && Object.hasOwn(value.nodes, key));
2197
- if (node?.kind === "map" && require_issue.isRecord(value)) return Object.hasOwn(value, key);
2198
- if (node?.kind === "table" && require_issue.isRecord(value) && require_issue.isRecord(value.byId)) return Object.hasOwn(value.byId, key);
2199
- if (node?.kind === "list" && Array.isArray(value)) return require_issue.indexedKeys(value, node.keyOf).index(key) >= 0;
3679
+ if (treeNodes) return Boolean(node?.kind === "tree" && require_context.isRecord(value) && require_context.isRecord(value.nodes) && Object.hasOwn(value.nodes, key));
3680
+ if (node?.kind === "map" && require_context.isRecord(value)) return Object.hasOwn(value, key);
3681
+ if (node?.kind === "table" && require_context.isRecord(value) && require_context.isRecord(value.byId)) return Object.hasOwn(value.byId, key);
3682
+ if (node?.kind === "list" && Array.isArray(value)) return require_advanced.indexedKeys(value, node.keyOf).index(key) >= 0;
2200
3683
  return false;
2201
3684
  };
2202
3685
  const raw = (key) => {
2203
3686
  if (treeNodes) {
2204
- if (node?.kind !== "tree" || !require_issue.isRecord(value) || !require_issue.isRecord(value.nodes)) return void 0;
3687
+ if (node?.kind !== "tree" || !require_context.isRecord(value) || !require_context.isRecord(value.nodes)) return void 0;
2205
3688
  return Object.hasOwn(value.nodes, key) ? value.nodes[key] : void 0;
2206
3689
  }
2207
- if (node?.kind === "map" && require_issue.isRecord(value)) return Object.hasOwn(value, key) ? value[key] : void 0;
2208
- if (node?.kind === "table" && require_issue.isRecord(value) && require_issue.isRecord(value.byId)) return Object.hasOwn(value.byId, key) ? value.byId[key] : void 0;
3690
+ if (node?.kind === "map" && require_context.isRecord(value)) return Object.hasOwn(value, key) ? value[key] : void 0;
3691
+ if (node?.kind === "table" && require_context.isRecord(value) && require_context.isRecord(value.byId)) return Object.hasOwn(value.byId, key) ? value.byId[key] : void 0;
2209
3692
  if (node?.kind === "list" && Array.isArray(value)) {
2210
- const index = require_issue.indexedKeys(value, node.keyOf).index(key);
3693
+ const index = require_advanced.indexedKeys(value, node.keyOf).index(key);
2211
3694
  return index < 0 ? void 0 : value[index];
2212
3695
  }
2213
3696
  };
@@ -2220,9 +3703,9 @@ const createSourceRegistry = (scheduler) => {
2220
3703
  if (treeNodes) {
2221
3704
  const entry = current;
2222
3705
  const before = previous.has(key) ? previous.get(key) : void 0;
2223
- snapshots.set(key, require_access.equalTreeNode(before, entry) ? before : require_access.copyTreeNode(entry));
3706
+ snapshots.set(key, require_advanced.equalTreeNode(before, entry) ? before : require_advanced.copyTreeNode(entry));
2224
3707
  } else if (!entryNode) snapshots.set(key, current);
2225
- else if (!previous.has(key)) snapshots.set(key, require_access.copyValue(entryNode, current));
3708
+ else if (!previous.has(key)) snapshots.set(key, require_advanced.copyValue(entryNode, current));
2226
3709
  else {
2227
3710
  const dirty = pending.entries.get(key) ?? (pending.reset ? replacement : void 0);
2228
3711
  snapshots.set(key, dirty ? materializeDocumentValue(entryNode, previous.get(key), current, dirty) : previous.get(key));
@@ -2239,7 +3722,7 @@ const createSourceRegistry = (scheduler) => {
2239
3722
  if (failed) resetCollectionPending(pending);
2240
3723
  else clearCollectionPending(pending);
2241
3724
  });
2242
- const remove = documentConnection(document).add({
3725
+ const remove = connection(document).add({
2243
3726
  target: selector,
2244
3727
  capture: (commit) => {
2245
3728
  try {
@@ -2258,6 +3741,125 @@ const createSourceRegistry = (scheduler) => {
2258
3741
  boundary.detach(remove);
2259
3742
  return boundary;
2260
3743
  };
3744
+ return {
3745
+ materialize,
3746
+ attachRoot(runtime, handlers) {
3747
+ return connection(runtime).add({
3748
+ target: documentRootTarget,
3749
+ capture: handlers.capture,
3750
+ dispose: handlers.dispose
3751
+ });
3752
+ },
3753
+ dispose() {
3754
+ documents.forEach((document) => document.close());
3755
+ documents.clear();
3756
+ }
3757
+ };
3758
+ };
3759
+ //#endregion
3760
+ //#region core/src/projection/source/registry.ts
3761
+ const createSourceRegistry = (scheduler) => {
3762
+ const documents = createDocumentSourceRegistry(scheduler);
3763
+ const readables = /* @__PURE__ */ new Map();
3764
+ const externalValues = /* @__PURE__ */ new WeakMap();
3765
+ const externalCollections = /* @__PURE__ */ new WeakMap();
3766
+ const valueInput = (definition) => {
3767
+ if (definition.source.kind !== "value-input") throw new Error("Invalid value input source.");
3768
+ const source = definition.source;
3769
+ let latest = source.initial;
3770
+ const boundary = createValueBoundary(scheduler, "projection input", source.initial, source.equality, () => latest, () => void 0);
3771
+ return {
3772
+ ...boundary,
3773
+ write: {
3774
+ kind: "value",
3775
+ set(value) {
3776
+ scheduler.assertIdle();
3777
+ latest = value;
3778
+ boundary.mark();
3779
+ scheduler.run();
3780
+ }
3781
+ }
3782
+ };
3783
+ };
3784
+ const collectionInput = (definition) => {
3785
+ if (definition.source.kind !== "collection-input") throw new Error("Invalid collection input source.");
3786
+ const values = new Map(definition.source.initial);
3787
+ const boundary = createCollectionBoundary(scheduler, "projection collection input", () => require_advanced.mapRead(values), definition.output.equality, () => void 0);
3788
+ return {
3789
+ ...boundary,
3790
+ write: {
3791
+ kind: "collection",
3792
+ update(run) {
3793
+ scheduler.assertIdle();
3794
+ const staged = /* @__PURE__ */ new Map();
3795
+ const operations = [];
3796
+ let active = true;
3797
+ const draft = Object.freeze({
3798
+ get: (key) => {
3799
+ require_advanced.assertScope(() => active);
3800
+ const entry = staged.get(key);
3801
+ return entry ? entry.present ? entry.value : void 0 : values.get(key);
3802
+ },
3803
+ has: (key) => {
3804
+ require_advanced.assertScope(() => active);
3805
+ const entry = staged.get(key);
3806
+ return entry ? entry.present : values.has(key);
3807
+ },
3808
+ set: (key, value) => {
3809
+ require_advanced.assertScope(() => active);
3810
+ if (typeof key !== "string") throw new TypeError("Projection keys must be strings.");
3811
+ staged.set(key, {
3812
+ present: true,
3813
+ value
3814
+ });
3815
+ operations.push({
3816
+ kind: "set",
3817
+ key,
3818
+ value
3819
+ });
3820
+ },
3821
+ remove: (key) => {
3822
+ require_advanced.assertScope(() => active);
3823
+ if (typeof key !== "string") throw new TypeError("Projection keys must be strings.");
3824
+ staged.set(key, { present: false });
3825
+ operations.push({
3826
+ kind: "remove",
3827
+ key
3828
+ });
3829
+ }
3830
+ });
3831
+ try {
3832
+ require_advanced.assertSynchronous(run(draft));
3833
+ } finally {
3834
+ active = false;
3835
+ }
3836
+ const candidates = /* @__PURE__ */ new Set();
3837
+ let structural = false;
3838
+ let changed = false;
3839
+ for (const operation of operations) {
3840
+ const present = values.has(operation.key);
3841
+ if (operation.kind === "set") {
3842
+ if (present && Object.is(values.get(operation.key), operation.value)) continue;
3843
+ structural ||= !present;
3844
+ values.set(operation.key, operation.value);
3845
+ } else {
3846
+ if (!present) continue;
3847
+ structural = true;
3848
+ values.delete(operation.key);
3849
+ }
3850
+ candidates.add(operation.key);
3851
+ changed = true;
3852
+ }
3853
+ if (!changed) return;
3854
+ boundary.mark({
3855
+ candidates,
3856
+ orderMayChange: structural
3857
+ });
3858
+ scheduler.run();
3859
+ }
3860
+ }
3861
+ };
3862
+ };
2261
3863
  const readable = (definition) => {
2262
3864
  if (definition.source.kind !== "readable") throw new Error("Invalid Readable source.");
2263
3865
  const { readable, equality } = definition.source;
@@ -2296,9 +3898,8 @@ const createSourceRegistry = (scheduler) => {
2296
3898
  readables.delete(readable);
2297
3899
  }
2298
3900
  };
2299
- const owner = require_notification.documentReadableOwner(readable);
2300
- if (owner) detachDocument = documentConnection(owner).add({
2301
- target: documentRootTarget,
3901
+ const owner = require_context.contextOf(readable, false)?.owner;
3902
+ if (owner) detachDocument = documents.attachRoot(owner, {
2302
3903
  capture: () => receive(false),
2303
3904
  dispose: () => {
2304
3905
  members.forEach((next) => next.boundary.fail(/* @__PURE__ */ new Error("Document has been disposed.")));
@@ -2440,16 +4041,15 @@ const createSourceRegistry = (scheduler) => {
2440
4041
  switch (definition.source.kind) {
2441
4042
  case "value-input": return valueInput(definition);
2442
4043
  case "collection-input": return collectionInput(definition);
2443
- case "document": return documentSource(definition);
4044
+ case "document": return documents.materialize(definition);
2444
4045
  case "readable": return readable(definition);
2445
4046
  case "external-value": return externalValue(definition);
2446
4047
  case "external-collection": return externalCollection(definition);
2447
4048
  }
2448
4049
  },
2449
4050
  dispose() {
2450
- documents.forEach((connection) => connection.close());
4051
+ documents.dispose();
2451
4052
  readables.forEach((connection) => connection.close());
2452
- documents.clear();
2453
4053
  readables.clear();
2454
4054
  }
2455
4055
  };
@@ -2693,12 +4293,12 @@ const createProjectionRuntime = (options) => {
2693
4293
  });
2694
4294
  };
2695
4295
  //#endregion
2696
- exports.DocumentDisposedError = require_access.DocumentDisposedError;
2697
- exports.DocumentReentrancyError = require_access.DocumentReentrancyError;
2698
- exports.ParseError = require_access.ParseError;
4296
+ exports.DocumentDisposedError = DocumentDisposedError;
4297
+ exports.DocumentReentrancyError = DocumentReentrancyError;
4298
+ exports.ParseError = require_advanced.ParseError;
2699
4299
  exports.ProjectionDisposedError = require_advanced.ProjectionDisposedError;
2700
4300
  exports.ProjectionError = require_advanced.ProjectionError;
2701
- exports.TransactionRejected = require_access.TransactionRejected;
4301
+ exports.TransactionRejected = TransactionRejected;
2702
4302
  exports.asReadable = asReadable;
2703
4303
  exports.createDocument = createDocument;
2704
4304
  exports.createProjectionRuntime = createProjectionRuntime;
@@ -2710,10 +4310,11 @@ exports.map = require_advanced.map;
2710
4310
  exports.object = require_advanced.object;
2711
4311
  exports.observe = require_advanced.observe;
2712
4312
  exports.optional = require_advanced.optional;
2713
- exports.parse = require_access.parse;
4313
+ exports.parse = require_advanced.parse;
2714
4314
  exports.read = read;
2715
- exports.replace = require_access.replace;
2716
- exports.snapshot = require_access.snapshot;
4315
+ exports.replace = replace;
4316
+ exports.select = select;
4317
+ exports.snapshot = snapshot;
2717
4318
  exports.table = require_advanced.table;
2718
4319
  exports.tree = require_advanced.tree;
2719
4320
  exports.variant = require_advanced.variant;