doxum 0.1.23 → 0.1.26

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 (66) hide show
  1. package/README.md +208 -102
  2. package/dist/advanced.cjs +237 -2
  3. package/dist/advanced.cjs.map +1 -0
  4. package/dist/advanced.d.cts +90 -2
  5. package/dist/advanced.d.ts +90 -2
  6. package/dist/advanced.js +236 -1
  7. package/dist/advanced.js.map +1 -0
  8. package/dist/{contract-ULPQmiEs.d.ts → contract-CNR6BS75.d.cts} +216 -30
  9. package/dist/{contract-SYJFP0lM.d.cts → contract-COgxO5sv.d.ts} +216 -30
  10. package/dist/definition-CDOuvb5C.d.cts +111 -0
  11. package/dist/definition-xgk3YNBp.d.ts +111 -0
  12. package/dist/{driver-yFfvDMX5.js → driver-B5vdPohL.js} +59 -3
  13. package/dist/driver-B5vdPohL.js.map +1 -0
  14. package/dist/{driver-BD3DQOW6.cjs → driver-BL91gn7_.cjs} +107 -9
  15. package/dist/driver-BL91gn7_.cjs.map +1 -0
  16. package/dist/index.cjs +1637 -703
  17. package/dist/index.cjs.map +1 -1
  18. package/dist/index.d.cts +65 -33
  19. package/dist/index.d.ts +65 -33
  20. package/dist/index.js +1432 -497
  21. package/dist/index.js.map +1 -1
  22. package/dist/local-sync.cjs +69 -103
  23. package/dist/local-sync.cjs.map +1 -1
  24. package/dist/local-sync.d.cts +14 -26
  25. package/dist/local-sync.d.ts +14 -26
  26. package/dist/local-sync.js +68 -96
  27. package/dist/local-sync.js.map +1 -1
  28. package/dist/react.cjs +4 -5
  29. package/dist/react.cjs.map +1 -1
  30. package/dist/react.d.cts +6 -8
  31. package/dist/react.d.ts +6 -8
  32. package/dist/react.js +4 -5
  33. package/dist/react.js.map +1 -1
  34. package/dist/record-B2yRhYsc.js +28 -0
  35. package/dist/record-B2yRhYsc.js.map +1 -0
  36. package/dist/record-ChYUi8PP.cjs +45 -0
  37. package/dist/record-ChYUi8PP.cjs.map +1 -0
  38. package/dist/scheduler--137L3j-.js +500 -0
  39. package/dist/scheduler--137L3j-.js.map +1 -0
  40. package/dist/scheduler-D4VthaaK.cjs +589 -0
  41. package/dist/scheduler-D4VthaaK.cjs.map +1 -0
  42. package/package.json +6 -3
  43. package/skills/doxum-runtime/SKILL.md +32 -7
  44. package/skills/doxum-runtime/agents/openai.yaml +1 -1
  45. package/skills/doxum-runtime/references/api.en.md +249 -0
  46. package/skills/doxum-runtime/references/api.zh-CN.md +242 -0
  47. package/skills/doxum-runtime/references/guide.en.md +18 -8
  48. package/skills/doxum-runtime/references/guide.zh-CN.md +14 -6
  49. package/skills/doxum-runtime/references/invariants.en.md +29 -5
  50. package/skills/doxum-runtime/references/invariants.zh-CN.md +24 -6
  51. package/skills/doxum-runtime/references/patterns.en.md +78 -18
  52. package/skills/doxum-runtime/references/patterns.zh-CN.md +76 -18
  53. package/skills/doxum-runtime/references/projections.en.md +209 -119
  54. package/skills/doxum-runtime/references/projections.zh-CN.md +200 -101
  55. package/dist/advanced-CLJCWkHa.d.cts +0 -176
  56. package/dist/advanced-CRNHfJBu.js +0 -1224
  57. package/dist/advanced-CRNHfJBu.js.map +0 -1
  58. package/dist/advanced-Cle5g3B4.cjs +0 -1517
  59. package/dist/advanced-Cle5g3B4.cjs.map +0 -1
  60. package/dist/advanced-d6J61er9.d.ts +0 -176
  61. package/dist/context-BcLKGfq8.cjs +0 -149
  62. package/dist/context-BcLKGfq8.cjs.map +0 -1
  63. package/dist/context-DFEaDUv5.js +0 -84
  64. package/dist/context-DFEaDUv5.js.map +0 -1
  65. package/dist/driver-BD3DQOW6.cjs.map +0 -1
  66. package/dist/driver-yFfvDMX5.js.map +0 -1
package/dist/index.cjs CHANGED
@@ -1,16 +1,432 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
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] ?? "")];
2
+ const require_scheduler = require("./scheduler-D4VthaaK.cjs");
3
+ const require_record = require("./record-ChYUi8PP.cjs");
4
+ const require_driver = require("./driver-BL91gn7_.cjs");
5
+ //#region core/src/schema/model.ts
6
+ const schemaNodeOf = (schema) => schema;
7
+ const collectionEntryNode = (node) => node.kind === "map" || node.kind === "table" || node.kind === "list" ? node.value : void 0;
8
+ const node$2 = (value) => Object.freeze(value);
9
+ const field = (validator) => node$2({
10
+ kind: "field",
11
+ ...validator ? { validator } : {}
12
+ });
13
+ function optional(value) {
14
+ const concrete = schemaNodeOf(value);
15
+ if (![
16
+ "field",
17
+ "variant",
18
+ "map",
19
+ "list",
20
+ "tree"
21
+ ].includes(concrete.kind)) throw new TypeError("Only field, variant, map, list and tree nodes support optional presence.");
22
+ return node$2({
23
+ ...concrete,
24
+ optional: true
25
+ });
26
+ }
27
+ const object = (shape) => node$2({
28
+ kind: "object",
29
+ shape: Object.freeze(Object.fromEntries(Object.entries(shape).map(([key, value]) => [key, schemaNodeOf(value)])))
30
+ });
31
+ const variant = (tag, variants) => node$2({
32
+ kind: "variant",
33
+ tag,
34
+ variants: Object.freeze(Object.fromEntries(Object.entries(variants).map(([key, value]) => [key, schemaNodeOf(value)])))
35
+ });
36
+ const table = (value, options) => node$2({
37
+ kind: "table",
38
+ value: schemaNodeOf(value),
39
+ ...options
40
+ });
41
+ const map = (value, options) => node$2({
42
+ kind: "map",
43
+ value: schemaNodeOf(value),
44
+ ...options
45
+ });
46
+ const list = (value, config) => node$2({
47
+ kind: "list",
48
+ keyOf: config.keyOf,
49
+ value: schemaNodeOf(value)
50
+ });
51
+ function tree(value) {
52
+ return Object.freeze({
53
+ kind: "tree",
54
+ value: schemaNodeOf(value)
55
+ });
56
+ }
57
+ //#endregion
58
+ //#region core/src/order/sequence.ts
59
+ const length$1 = (keys) => keys.length;
60
+ const keyAt = (keys, index) => Array.isArray(keys) ? keys[index] : keys.at(index);
61
+ const equal = (left, right) => {
62
+ require_scheduler.profile.equality.call();
63
+ if (left === right) return true;
64
+ require_scheduler.profile.equality.container();
65
+ if (left.length !== right.length) return false;
66
+ for (let index = 0; index < left.length; index++) if (left[index] !== keyAt(right, index)) return false;
67
+ return true;
68
+ };
69
+ const keys = (values, keyOf) => ({
70
+ length: values.length,
71
+ at: (index) => index >= 0 && index < values.length ? keyOf(values[index]) : void 0,
72
+ index: (key) => {
73
+ for (let index = 0; index < values.length; index += 1) if (keyOf(values[index]) === key) return index;
74
+ return -1;
75
+ }
76
+ });
77
+ const listIndexes = /* @__PURE__ */ new WeakMap();
78
+ const knownKeys = (values) => {
79
+ let positions;
80
+ return {
81
+ length: values.length,
82
+ at: (index) => values[index],
83
+ index: (key) => {
84
+ if (!positions) {
85
+ positions = /* @__PURE__ */ new Map();
86
+ for (let index = 0; index < values.length; index++) positions.set(values[index], index);
87
+ require_scheduler.profile.address.listIndex(values.length);
88
+ }
89
+ return positions.get(key) ?? -1;
90
+ }
91
+ };
92
+ };
93
+ const cacheKnownKeys = (values, keyOf, order) => {
94
+ listIndexes.set(values, {
95
+ keyOf,
96
+ order: knownKeys(order)
97
+ });
98
+ };
99
+ /** Canonical lists keep their key positions until a structural write invalidates them. */
100
+ const indexedKeys = (values, keyOf) => {
101
+ const cached = listIndexes.get(values);
102
+ if (cached?.keyOf === keyOf) return cached.order;
103
+ let positions;
104
+ const order = {
105
+ length: values.length,
106
+ at: (index) => index >= 0 && index < values.length ? keyOf(values[index]) : void 0,
107
+ index: (key) => {
108
+ if (!positions) {
109
+ positions = /* @__PURE__ */ new Map();
110
+ for (let index = 0; index < values.length; index++) positions.set(keyOf(values[index]), index);
111
+ require_scheduler.profile.address.listIndex(values.length);
112
+ }
113
+ return positions.get(key) ?? -1;
114
+ }
115
+ };
116
+ listIndexes.set(values, {
117
+ keyOf,
118
+ order
119
+ });
120
+ return order;
121
+ };
122
+ const toArray = (keys) => {
123
+ const result = new Array(length$1(keys));
124
+ for (let index = 0; index < result.length; index++) result[index] = keyAt(keys, index);
125
+ return result;
126
+ };
127
+ /** One operation-local list scan provides both stable keys and item association. */
128
+ const listSequence = (values, keyOf) => {
129
+ const current = indexedKeys(values, keyOf);
130
+ const order = new Array(values.length);
131
+ const byKey = /* @__PURE__ */ new Map();
132
+ for (let index = 0; index < values.length; index++) {
133
+ const key = current.at(index);
134
+ order[index] = key;
135
+ byKey.set(key, values[index]);
136
+ }
137
+ cacheKnownKeys(values, keyOf, order);
138
+ return {
139
+ order,
140
+ values: byKey
141
+ };
142
+ };
143
+ /** Structural sequence writes own invalidation, including rollback writes. */
144
+ const insert$2 = (values, index, value) => {
145
+ values.splice(index, 0, value);
146
+ listIndexes.delete(values);
147
+ };
148
+ const remove$3 = (values, index) => {
149
+ values.splice(index, 1);
150
+ listIndexes.delete(values);
151
+ };
152
+ /** Installs an exact string-key sequence such as table ids in one structural write. */
153
+ const installKeys = (values, order) => {
154
+ values.length = order.length;
155
+ for (let index = 0; index < order.length; index++) values[index] = order[index];
156
+ };
157
+ /** Installs a pre-resolved list sequence without running keyOf again. */
158
+ const installList = (values, keyOf, sequence, order) => {
159
+ values.length = order.length;
160
+ for (let index = 0; index < order.length; index++) values[index] = sequence.values.get(order[index]);
161
+ cacheKnownKeys(values, keyOf, order);
162
+ };
163
+ const install = (values, keyOf, order) => {
164
+ installList(values, keyOf, listSequence(values, keyOf), order);
165
+ };
166
+ const matches = (order, members) => {
167
+ if (order.length !== members.length) return false;
168
+ const ids = new Set(order);
169
+ return ids.size === order.length && members.every((id) => ids.has(id));
170
+ };
171
+ //#endregion
172
+ //#region core/src/schema/layout.ts
173
+ const compiledObjects = /* @__PURE__ */ new WeakMap();
174
+ const compiledEntries = /* @__PURE__ */ new WeakMap();
175
+ const variantBranch = (node, discriminator) => node.variants[discriminator ?? Object.keys(node.variants)[0] ?? ""];
176
+ const objectBranch = (node, value) => {
177
+ if (node.kind === "object") return node;
178
+ if (node.kind !== "variant" || typeof value !== "object" || value === null || Array.isArray(value)) return void 0;
179
+ const rawTag = value[node.tag];
180
+ return variantBranch(node, typeof rawTag === "string" ? rawTag : void 0);
181
+ };
182
+ const compiledShape = (node, value) => {
183
+ const branch = objectBranch(node, value);
184
+ if (!branch) return void 0;
185
+ const shape = branch.shape;
186
+ let layout = compiledObjects.get(shape);
187
+ if (!layout) {
188
+ const members = /* @__PURE__ */ new Map();
189
+ for (const key of Object.keys(shape).sort()) {
190
+ require_scheduler.profile.address.schemaStep();
191
+ members.set(key, {
192
+ kind: "fixed",
193
+ key,
194
+ node: shape[key],
195
+ field: shape[key].kind === "field",
196
+ slot: members.size
197
+ });
198
+ }
199
+ layout = {
200
+ kind: "fixed",
201
+ members
202
+ };
203
+ compiledObjects.set(shape, layout);
204
+ }
205
+ return layout;
206
+ };
207
+ const compiledLayout = (node, value) => {
208
+ if (node.kind !== "map" && node.kind !== "table" && node.kind !== "list") return compiledShape(node, value);
209
+ let layout = compiledEntries.get(node);
210
+ if (!layout) {
211
+ layout = {
212
+ kind: "dynamic",
213
+ entry: {
214
+ kind: "entry",
215
+ node: node.value,
216
+ field: node.value.kind === "field"
217
+ }
218
+ };
219
+ compiledEntries.set(node, layout);
220
+ }
221
+ return layout;
222
+ };
223
+ //#endregion
224
+ //#region core/src/schema/value.ts
225
+ var ParseError = class extends TypeError {
226
+ issues;
227
+ constructor(issue) {
228
+ super(`${issue.message} at ${JSON.stringify(issue.address)}`);
229
+ this.name = "ParseError";
230
+ this.issues = Object.freeze([Object.freeze({
231
+ ...issue,
232
+ address: Object.freeze([...issue.address])
233
+ })]);
234
+ }
235
+ };
236
+ const issue = (address, message, code = "invalid-value") => ({
237
+ address,
238
+ message,
239
+ code
240
+ });
241
+ const checkScalar = (validator, value, address, strict) => {
242
+ if (!validator) return strict ? issue(address, "A validator is required to parse an opaque value.", "missing-validator") : void 0;
243
+ try {
244
+ const result = typeof validator === "function" ? validator(value) : validator["~standard"].validate(value);
245
+ if (result && (typeof result === "object" || typeof result === "function") && "then" in result && typeof result.then === "function") return issue(address, "Validators must be synchronous.");
246
+ if (typeof validator === "function") {
247
+ if (result === false) return issue(address, "Value validation failed.");
248
+ if (result !== void 0 && result !== true) return issue(address, "Function validators must return boolean or undefined.");
249
+ } else {
250
+ if (!require_record.isRecord(result)) return issue(address, "Malformed validator result.");
251
+ if (Array.isArray(result.issues)) {
252
+ const first = result.issues[0];
253
+ return issue([...address, ...(first?.path ?? []).map((part) => String(typeof part === "object" ? part.key : part))], first?.message ?? "Value validation failed.");
254
+ }
255
+ if (!Object.hasOwn(result, "value")) return issue(address, "Malformed validator result.");
256
+ if (!Object.is(result.value, value)) return issue(address, "Validators must not transform values.");
257
+ }
258
+ return;
259
+ } catch (error) {
260
+ return issue(address, error instanceof Error ? error.message : "Value validation failed.");
261
+ }
262
+ };
263
+ const checkKey = (validator, value, address) => {
264
+ if (typeof value !== "string") return issue(address, "Collection keys must be strings.", "invalid-key");
265
+ const failure = checkScalar(validator, value, address, false);
266
+ return failure ? {
267
+ ...failure,
268
+ code: "invalid-key"
269
+ } : void 0;
270
+ };
271
+ const checkValue = (node, value, address = [], strict = false) => {
272
+ if (node.optional && value === void 0) return void 0;
273
+ if (node.kind === "field") return checkScalar(node.validator, value, address, strict);
274
+ if (node.kind === "object" || node.kind === "variant") {
275
+ if (!require_record.isPlainObject(value)) return issue(address, "Expected an object.");
276
+ if (node.kind === "variant") {
277
+ const tag = value[node.tag];
278
+ if (!Object.hasOwn(value, node.tag) || typeof tag !== "string" || !Object.hasOwn(node.variants, tag)) return issue([...address, node.tag], "Unknown variant tag.");
279
+ }
280
+ const { members } = compiledShape(node, value);
281
+ for (const key of Reflect.ownKeys(value)) {
282
+ if (node.kind === "variant" && key === node.tag) continue;
283
+ if (typeof key !== "string" || !members.has(key)) return issue([...address, String(key)], "Property is not declared in the object schema.");
284
+ }
285
+ for (const [key, member] of members) {
286
+ const child = member.node;
287
+ if (!Object.prototype.hasOwnProperty.call(value, key) && !child.optional) return issue([...address, key], "Required property is missing.");
288
+ const failure = checkValue(child, value[key], [...address, key], strict);
289
+ if (failure) return failure;
290
+ }
291
+ return;
292
+ }
293
+ if (node.kind === "table" || node.kind === "map") {
294
+ if (!require_record.isPlainObject(value)) return issue(address, "Expected a collection object.");
295
+ const entries = node.kind === "table" ? value.byId : value;
296
+ if (!require_record.isPlainObject(entries)) return issue(address, "Expected a byId object.");
297
+ if (node.kind === "table") {
298
+ if (!Array.isArray(value.ids) || value.ids.length !== Object.keys(entries).length) return issue(address, "Table ids and entries must agree.");
299
+ const seen = /* @__PURE__ */ new Set();
300
+ for (const id of value.ids) {
301
+ const failure = checkKey(node.key, id, address);
302
+ if (failure) return failure;
303
+ if (seen.has(id) || !Object.prototype.hasOwnProperty.call(entries, id)) return issue(address, "Table ids must be unique and reference existing entries.");
304
+ seen.add(id);
305
+ }
306
+ }
307
+ for (const id of Object.keys(entries)) {
308
+ const failure = checkKey(node.key, id, [...address, id]) ?? checkValue(node.value, entries[id], [...address, id], strict);
309
+ if (failure) return failure;
310
+ }
311
+ return;
312
+ }
313
+ if (node.kind === "list") {
314
+ if (!Array.isArray(value)) return issue(address, "Expected a list.");
315
+ const seen = /* @__PURE__ */ new Set();
316
+ const order = keys(value, node.keyOf);
317
+ for (let i = 0; i < value.length; i++) {
318
+ const failure = checkValue(node.value, value[i], [...address, String(i)], strict);
319
+ if (failure) return failure;
320
+ let key;
321
+ try {
322
+ key = order.at(i);
323
+ } catch {
324
+ return issue(address, "List keyOf failed.");
325
+ }
326
+ if (typeof key !== "string" || seen.has(key)) return issue(address, "List keys must be unique strings.", "invalid-key");
327
+ seen.add(key);
328
+ }
329
+ return;
330
+ }
331
+ if (!require_driver.validate(value)) return issue(address, "Invalid tree structure.", "invalid-tree");
332
+ for (const id of Object.keys(value.nodes)) {
333
+ const failure = checkTreePayload(node.value, value.nodes[id], [...address, id], strict);
334
+ if (failure) return failure;
335
+ }
336
+ };
337
+ const checkTreePayload = (node, value, address, strict = false) => {
338
+ if (!require_record.isRecord(value)) return issue(address, "Invalid tree node.", "invalid-tree");
339
+ const present = Object.prototype.hasOwnProperty.call(value, "value");
340
+ if (!present && !node.optional) return issue(address, "Tree node value is required.");
341
+ return present ? checkValue(node, value.value, address, strict) : void 0;
342
+ };
343
+ const copyTreeNode = (value) => {
344
+ require_scheduler.profile.copy.treeNode();
345
+ return {
346
+ ...value,
347
+ children: [...value.children]
348
+ };
349
+ };
350
+ const equalTreeNode = (left, right) => {
351
+ if (left === right) return true;
352
+ if (!left || !right) return false;
353
+ return left.parentId === right.parentId && equal(left.children, right.children) && Object.hasOwn(left, "value") === Object.hasOwn(right, "value") && Object.is(left.value, right.value);
354
+ };
355
+ /** Copy editable structure; atomic payloads retain their immutable ownership contract. */
356
+ const copyValue = (node, value) => {
357
+ if (value === void 0 || node.kind === "field") return value;
358
+ require_scheduler.profile.copy.structure();
359
+ if ((node.kind === "object" || node.kind === "variant") && require_record.isRecord(value)) {
360
+ const result = Object.create(Object.getPrototypeOf(value));
361
+ const { members } = compiledShape(node, value);
362
+ for (const key of Object.getOwnPropertyNames(value)) Object.defineProperty(result, key, {
363
+ value: node.kind === "variant" && key === node.tag ? value[key] : copyValue(members.get(key).node, value[key]),
364
+ writable: true,
365
+ enumerable: Object.getOwnPropertyDescriptor(value, key)?.enumerable,
366
+ configurable: true
367
+ });
368
+ return result;
369
+ }
370
+ if ((node.kind === "table" || node.kind === "map") && require_record.isRecord(value)) {
371
+ const entries = node.kind === "table" ? value.byId : value;
372
+ const result = Object.fromEntries(Object.keys(entries).map((id) => [id, copyValue(node.value, entries[id])]));
373
+ return node.kind === "table" ? {
374
+ ids: [...value.ids],
375
+ byId: result
376
+ } : result;
377
+ }
378
+ if (node.kind === "list") return [...value];
379
+ if (node.kind === "tree" && require_record.isRecord(value)) {
380
+ const entries = value.nodes;
381
+ return {
382
+ ...value,
383
+ nodes: Object.fromEntries(Object.entries(entries).map(([id, n]) => [id, copyTreeNode(n)]))
384
+ };
385
+ }
386
+ return value;
387
+ };
388
+ const equalValue = (node, left, right) => {
389
+ if (Object.is(left, right)) return true;
390
+ if (node.kind === "field" || left === void 0 || right === void 0) return false;
391
+ if ((node.kind === "object" || node.kind === "variant") && require_record.isRecord(left) && require_record.isRecord(right)) {
392
+ if (node.kind === "variant" && left[node.tag] !== right[node.tag]) return false;
393
+ for (const [key, member] of compiledShape(node, left).members) {
394
+ if (Object.hasOwn(left, key) !== Object.hasOwn(right, key)) return false;
395
+ if (!equalValue(member.node, left[key], right[key])) return false;
396
+ }
397
+ return true;
398
+ }
399
+ if (node.kind === "list" && Array.isArray(left) && Array.isArray(right)) return left.length === right.length && left.every((v, i) => equalValue(node.value, v, right[i]));
400
+ if (node.kind === "table" && require_record.isRecord(left) && require_record.isRecord(right)) return equal(left.ids, right.ids) && equalValue({
401
+ kind: "map",
402
+ value: node.value
403
+ }, left.byId, right.byId);
404
+ if (node.kind === "tree" && require_record.isRecord(left) && require_record.isRecord(right)) {
405
+ if (left.rootId !== right.rootId) return false;
406
+ const a = left.nodes, b = right.nodes;
407
+ return Object.keys(a).length === Object.keys(b).length && Object.keys(a).every((id) => Object.hasOwn(b, id) && equalTreeNode(a[id], b[id]));
408
+ }
409
+ if (node.kind === "map" && require_record.isRecord(left) && require_record.isRecord(right)) {
410
+ const keys = Object.keys(left);
411
+ return keys.length === Object.keys(right).length && keys.every((key) => Object.hasOwn(right, key) && equalValue(node.value, left[key], right[key]));
412
+ }
413
+ return false;
9
414
  };
415
+ const parse = (schema, input) => {
416
+ const valueNode = schemaNodeOf(schema);
417
+ const failure = checkValue(valueNode, input, [], true);
418
+ if (failure) throw new ParseError(failure);
419
+ return copyValue(valueNode, input);
420
+ };
421
+ //#endregion
422
+ //#region core/src/address/resolve.ts
10
423
  const step = (nodeInput, value, segment) => {
11
424
  let node = nodeInput;
12
425
  if (!node) return void 0;
13
- if (node.kind === "variant") node = variantNode(node, value);
426
+ if (node.kind === "variant") {
427
+ const rawTag = require_record.isRecord(value) ? value[node.tag] : void 0;
428
+ node = variantBranch(node, typeof rawTag === "string" ? rawTag : void 0);
429
+ }
14
430
  if (!node) return void 0;
15
431
  if (node.kind === "object") return Object.hasOwn(node.shape, segment) ? node.shape[segment] : void 0;
16
432
  if (node.kind === "table" || node.kind === "map") return node.value;
@@ -28,17 +444,17 @@ const nodeAt = (schema, address, document) => {
28
444
  return node;
29
445
  };
30
446
  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;
447
+ if (!require_record.isRecord(value) && !Array.isArray(value)) return void 0;
448
+ if (node?.kind === "list" && Array.isArray(value)) return value[indexedKeys(value, node.keyOf).index(segment)];
449
+ if (node?.kind === "table" && require_record.isRecord(value) && require_record.isRecord(value.byId)) return Object.hasOwn(value.byId, segment) ? value.byId[segment] : void 0;
34
450
  return Object.prototype.hasOwnProperty.call(value, segment) ? value[segment] : void 0;
35
451
  };
36
452
  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;
453
+ if (!node || !require_record.isRecord(value) && !Array.isArray(value)) return void 0;
454
+ const parent = node.kind === "table" && require_record.isRecord(value) ? value.byId : value;
455
+ if (!require_record.isRecord(parent) && !Array.isArray(parent)) return void 0;
40
456
  if (node.kind === "tree") return void 0;
41
- const layout = require_advanced.compiledLayout(node, value);
457
+ const layout = compiledLayout(node, value);
42
458
  if (!layout) return void 0;
43
459
  return {
44
460
  owner,
@@ -50,14 +466,14 @@ const resolveContainer = (owner, generation, at, node, value) => {
50
466
  layout
51
467
  };
52
468
  };
53
- const resolveTreeContainer = (owner, generation, at, node, value) => node?.kind === "tree" && require_context.is(value) ? {
469
+ const resolveTreeContainer = (owner, generation, at, node, value) => node?.kind === "tree" && require_driver.is(value) ? {
54
470
  owner,
55
471
  generation,
56
472
  at,
57
473
  node,
58
474
  value
59
475
  } : void 0;
60
- const memberKey = (container, key) => container.node.kind === "list" ? require_advanced.indexedKeys(container.parent, container.node.keyOf).index(key) : key;
476
+ const memberKey = (container, key) => container.node.kind === "list" ? indexedKeys(container.parent, container.node.keyOf).index(key) : key;
61
477
  /** One recent path per transaction; structural writes invalidate all retained locations. */
62
478
  const createAddressResolver = (schema, root) => {
63
479
  const prefix = [];
@@ -103,8 +519,8 @@ const resolveWithPrefix = (schema, root, address, prefix) => {
103
519
  }
104
520
  let cacheable = true;
105
521
  for (let index = start; index < address.length - 1; index += 1) {
106
- require_advanced.profile.address.schemaStep();
107
- require_advanced.profile.address.documentStep();
522
+ require_scheduler.profile.address.schemaStep();
523
+ require_scheduler.profile.address.documentStep();
108
524
  const resolved = step(node, current, address[index]);
109
525
  if (!resolved) return void 0;
110
526
  if (node?.kind !== "object" && node?.kind !== "table" && node?.kind !== "map") cacheable = false;
@@ -122,11 +538,11 @@ const resolveWithPrefix = (schema, root, address, prefix) => {
122
538
  };
123
539
  /** Resolves one member from an already current schema/container pair. */
124
540
  const resolveChild = (node, current, last) => {
125
- require_advanced.profile.address.schemaStep();
126
- require_advanced.profile.address.documentStep();
541
+ require_scheduler.profile.address.schemaStep();
542
+ require_scheduler.profile.address.documentStep();
127
543
  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 {
544
+ if (!resolved || !require_record.isRecord(current) && !Array.isArray(current)) return void 0;
545
+ if (node?.kind === "table" && require_record.isRecord(current) && require_record.isRecord(current.byId)) return {
130
546
  node: resolved,
131
547
  parent: current.byId,
132
548
  key: last
@@ -134,20 +550,10 @@ const resolveChild = (node, current, last) => {
134
550
  return {
135
551
  node: resolved,
136
552
  parent: current,
137
- key: node?.kind === "list" && Array.isArray(current) ? require_advanced.indexedKeys(current, node.keyOf).index(last) : last
553
+ key: node?.kind === "list" && Array.isArray(current) ? indexedKeys(current, node.keyOf).index(last) : last
138
554
  };
139
555
  };
140
556
  //#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
557
  //#region core/src/order/anchor.ts
152
558
  const length = (keys) => keys.length;
153
559
  const keyIndex = (keys, key) => Array.isArray(keys) ? keys.indexOf(key) : keys.index(key);
@@ -235,25 +641,25 @@ function insert$1(session, container, value, position) {
235
641
  session.validate(node.value, value, at);
236
642
  const id = node.keyOf(value);
237
643
  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);
644
+ const items = current, keys$1 = keys(items, node.keyOf);
239
645
  if (keys$1.index(id) >= 0) return require_driver.fail(at, "duplicate-list-item", "List key already exists.");
240
646
  if (!valid(keys$1, position)) return require_driver.fail(at, "invalid-anchor", "Unknown list anchor.");
241
647
  session.recorder.order(container);
242
648
  session.recorder.member(container, id, session.definition(container, id), -1);
243
- require_advanced.insert(items, index(keys$1, position), value);
649
+ insert$2(items, index(keys$1, position), value);
244
650
  session.invalidate();
245
651
  }
246
652
  function replace$2(session, container, id, value) {
247
653
  const { at, node, value: items } = container;
248
654
  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);
655
+ const index = indexedKeys(items, node.keyOf).index(id);
250
656
  if (index < 0) return require_driver.fail(at, "missing-list-item", "List key does not exist.");
251
657
  session.writeMember(container, id, value, "set", index);
252
658
  }
253
659
  function remove$1(session, container, id) {
254
660
  const { at, node, value } = container;
255
661
  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);
662
+ const index = keys(value, node.keyOf).index(id);
257
663
  if (index < 0) return require_driver.fail(at, "missing-list-item", "List key does not exist.");
258
664
  session.writeMember(container, id, void 0, "remove", index);
259
665
  }
@@ -267,7 +673,7 @@ const positionIndex = (index, length, at) => {
267
673
  const insert = (session, container, id, value, position) => {
268
674
  const { at, node: schema, value: tree } = container;
269
675
  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.");
676
+ if (require_driver.contains(tree, id)) return require_driver.fail(at, "duplicate-tree-node", "Tree node already exists.");
271
677
  const parentId = position?.parentId;
272
678
  const parent = parentId === void 0 ? void 0 : node$1(tree, parentId);
273
679
  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.");
@@ -322,7 +728,7 @@ const move$1 = (session, container, id, position) => {
322
728
  const { at, value: tree } = container;
323
729
  const entry = node$1(tree, id), parentId = position?.parentId;
324
730
  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.");
731
+ if (entry.parentId === void 0 || parentId === void 0 || !require_driver.contains(tree, parentId)) return require_driver.fail(at, "missing-tree-parent", "Moving requires a non-root node and an existing parent.");
326
732
  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
733
  const old = tree.nodes[entry.parentId], next = tree.nodes[parentId];
328
734
  const index = positionIndex(position?.index, next.children.length - (old === next ? 1 : 0), at);
@@ -359,16 +765,16 @@ function move(session, container, ids, position) {
359
765
  if (node.kind === "table") {
360
766
  const order = container.value.ids;
361
767
  const next = plannedOrder(container.at, order, selection, position);
362
- if (require_advanced.equal(order, next)) return;
768
+ if (equal(order, next)) return;
363
769
  session.recorder.order(container);
364
- require_advanced.installKeys(order, next);
770
+ installKeys(order, next);
365
771
  } else {
366
772
  const items = container.value;
367
- const current = require_advanced.listSequence(items, node.keyOf);
773
+ const current = listSequence(items, node.keyOf);
368
774
  const next = plannedOrder(container.at, current.order, selection, position);
369
- if (require_advanced.equal(current.order, next)) return;
775
+ if (equal(current.order, next)) return;
370
776
  session.recorder.order(container);
371
- require_advanced.installList(items, node.keyOf, current, next);
777
+ installList(items, node.keyOf, current, next);
372
778
  }
373
779
  session.invalidate();
374
780
  }
@@ -376,17 +782,17 @@ function reorder(session, container, next) {
376
782
  const node = assertOrdered(container);
377
783
  if (node.kind === "table") {
378
784
  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;
785
+ if (!matches(next, current)) return require_driver.fail(container.at, "invalid-collection", "Order must contain every key exactly once.");
786
+ if (equal(current, next)) return;
381
787
  session.recorder.order(container);
382
- require_advanced.installKeys(current, next);
788
+ installKeys(current, next);
383
789
  } else {
384
790
  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;
791
+ const current = listSequence(items, node.keyOf);
792
+ if (!matches(next, current.order)) return require_driver.fail(container.at, "invalid-collection", "Order must contain every key exactly once.");
793
+ if (equal(current.order, next)) return;
388
794
  session.recorder.order(container);
389
- require_advanced.installList(items, node.keyOf, current, next);
795
+ installList(items, node.keyOf, current, next);
390
796
  }
391
797
  session.invalidate();
392
798
  }
@@ -411,13 +817,17 @@ const sameTreeTarget = (left, right) => {
411
817
  return left.kind !== "node" || right.kind === "node" && left.id === right.id;
412
818
  };
413
819
  const same = (left, right) => {
820
+ require_scheduler.profile.dependency.comparison();
414
821
  if ("schema" in left && "schema" in right && left.schema !== right.schema) return false;
415
822
  if (!sameTreeTarget(treeTarget(left), treeTarget(right))) return false;
416
823
  if (left.kind !== right.kind) return false;
417
824
  const leftAddress = address(left);
418
825
  const rightAddress = address(right);
419
826
  if (leftAddress.length !== rightAddress.length) return false;
420
- for (let index = 0; index < leftAddress.length; index += 1) if (leftAddress[index] !== rightAddress[index]) return false;
827
+ for (let index = 0; index < leftAddress.length; index += 1) {
828
+ require_scheduler.profile.dependency.segmentCompared();
829
+ if (leftAddress[index] !== rightAddress[index]) return false;
830
+ }
421
831
  return left.kind !== "collection" || id(left) === id(right);
422
832
  };
423
833
  const indexedAddress = (target) => {
@@ -445,6 +855,12 @@ const indexedAddress = (target) => {
445
855
  key
446
856
  ];
447
857
  };
858
+ /**
859
+ * Coarse identity for dependency de-duplication. Schema is intentionally excluded because
860
+ * schema-bound and schema-free targets may compare equal; callers must still use same()
861
+ * inside a bucket for the final equality decision.
862
+ */
863
+ const dependencyBucket = (target) => JSON.stringify([target.kind, indexedAddress(target)]);
448
864
  const visitChangedLocations = (changes, value, order) => {
449
865
  for (const change of changes.changes) {
450
866
  if (change.kind === "reset") continue;
@@ -522,7 +938,7 @@ const locations = /* @__PURE__ */ new WeakMap();
522
938
  const locationOf = (value) => locations.get(value);
523
939
  const addressOf = (target) => {
524
940
  if (target.at) return target.at;
525
- require_advanced.profile.access("addresses");
941
+ require_scheduler.profile.access("addresses");
526
942
  return target.at = addressOf(target.parent).concat(target.key);
527
943
  };
528
944
  const assertActive = (context) => {
@@ -544,11 +960,11 @@ const snapshot = (value) => {
544
960
  if (!location) return value;
545
961
  const { context } = location;
546
962
  const at = addressOf(location.target);
547
- require_advanced.profile.access("snapshots");
963
+ require_scheduler.profile.access("snapshots");
548
964
  collect(context, at);
549
965
  const resolved = resolve(context, location.target);
550
966
  if (!resolved.node) throw new Error("The selected schema address no longer exists.");
551
- return require_advanced.copyValue(resolved.node, resolved.value);
967
+ return copyValue(resolved.node, resolved.value);
552
968
  };
553
969
  const replace = (container, key, value) => {
554
970
  if (!locationOf(container)) throw new TypeError("replace requires scoped document access.");
@@ -559,7 +975,7 @@ const resolve = (context, target) => {
559
975
  assertActive(context);
560
976
  const generation = context.session?.generation ?? 0;
561
977
  if (target.generation !== generation) {
562
- require_advanced.profile.access("resolutions");
978
+ require_scheduler.profile.access("resolutions");
563
979
  if (!target.parent && !target.at.length) {
564
980
  target.node = context.state.schema;
565
981
  target.value = context.state.document;
@@ -574,7 +990,7 @@ const resolve = (context, target) => {
574
990
  return target;
575
991
  };
576
992
  const createAccess = (context, initial = []) => {
577
- require_advanced.profile.access("scopes");
993
+ require_scheduler.profile.access("scopes");
578
994
  const mutable = () => {
579
995
  assertActive(context);
580
996
  if (!context.session) throw new TypeError("Cannot modify read-only document access.");
@@ -585,13 +1001,13 @@ const createAccess = (context, initial = []) => {
585
1001
  return target.container = session.bind(addressOf(target), target.node, target.value);
586
1002
  };
587
1003
  const childAt = (target, key) => {
588
- require_advanced.profile.access("addresses");
1004
+ require_scheduler.profile.access("addresses");
589
1005
  return addressOf(target).concat(key);
590
1006
  };
591
1007
  const access = (target) => {
592
1008
  if (target.proxy) return target.proxy;
593
1009
  const proxy = new Proxy(target, handler);
594
- require_advanced.profile.access("proxies");
1010
+ require_scheduler.profile.access("proxies");
595
1011
  locations.set(proxy, {
596
1012
  context,
597
1013
  target
@@ -621,7 +1037,7 @@ const createAccess = (context, initial = []) => {
621
1037
  if (children?.kind !== "fixed" || children.schema !== target.node) children = {
622
1038
  kind: "fixed",
623
1039
  schema: target.node,
624
- slots: new Array(require_advanced.compiledShape(target.node, target.value).members.size)
1040
+ slots: new Array(compiledShape(target.node, target.value).members.size)
625
1041
  };
626
1042
  child = children.slots[member.slot] ??= createTarget(void 0, target, key);
627
1043
  } else {
@@ -683,12 +1099,14 @@ const createAccess = (context, initial = []) => {
683
1099
  return childAccess(target, id, node.value, current[id]);
684
1100
  };
685
1101
  if (property === "put") return (id, value) => {
1102
+ const session = mutable();
686
1103
  const writable = writableCollection(target, node);
687
- put(context.session, writable, id, value);
1104
+ session.writeMember(writable, id, value, "set");
688
1105
  };
689
1106
  if (property === "remove") return (id) => {
1107
+ const session = mutable();
690
1108
  const writable = writableCollection(target, node);
691
- remove$3(context.session, writable, id);
1109
+ session.writeMember(writable, id, void 0, "remove");
692
1110
  };
693
1111
  if (property === "replace") return (value) => replaceCollection(target, node, value);
694
1112
  };
@@ -702,7 +1120,7 @@ const createAccess = (context, initial = []) => {
702
1120
  if (property === "has") return (id) => {
703
1121
  const current = collectionValue(target, node);
704
1122
  collect(context, at, "collection", id);
705
- return node.kind === "table" ? Object.hasOwn(current.byId, id) : require_advanced.indexedKeys(current, node.keyOf).index(id) >= 0;
1123
+ return node.kind === "table" ? Object.hasOwn(current.byId, id) : indexedKeys(current, node.keyOf).index(id) >= 0;
706
1124
  };
707
1125
  if (property === "get") return (id) => {
708
1126
  const current = collectionValue(target, node);
@@ -788,28 +1206,28 @@ const createAccess = (context, initial = []) => {
788
1206
  id
789
1207
  });
790
1208
  const value = current();
791
- return require_context.contains(value, id) ? value.nodes[id].value : void 0;
1209
+ return require_driver.contains(value, id) ? value.nodes[id].value : void 0;
792
1210
  };
793
1211
  if (property === "has") return (id) => {
794
1212
  collectTree(context, at, {
795
1213
  kind: "node",
796
1214
  id
797
1215
  });
798
- return require_context.contains(current(), id);
1216
+ return require_driver.contains(current(), id);
799
1217
  };
800
1218
  if (property === "parent") return (id) => {
801
1219
  collectTree(context, at, {
802
1220
  kind: "node",
803
1221
  id
804
1222
  });
805
- return require_context.parent(current(), id);
1223
+ return require_driver.parent(current(), id);
806
1224
  };
807
1225
  if (property === "children") return (id) => {
808
1226
  collectTree(context, at, {
809
1227
  kind: "node",
810
1228
  id
811
1229
  });
812
- const children$1 = require_context.children(current(), id);
1230
+ const children$1 = require_driver.children(current(), id);
813
1231
  return children$1 ? [...children$1] : void 0;
814
1232
  };
815
1233
  };
@@ -826,7 +1244,7 @@ const createAccess = (context, initial = []) => {
826
1244
  collect(context, childAt(target, property));
827
1245
  return value[property];
828
1246
  }
829
- const member = require_advanced.compiledShape(node, value)?.members.get(property);
1247
+ const member = compiledShape(node, value)?.members.get(property);
830
1248
  if (!member) return void 0;
831
1249
  if (member.field) {
832
1250
  if (context.dependencies) collect(context, childAt(target, property));
@@ -889,12 +1307,68 @@ const createAccess = (context, initial = []) => {
889
1307
  return access(root);
890
1308
  };
891
1309
  //#endregion
1310
+ //#region core/src/schema/path.ts
1311
+ const paths = /* @__PURE__ */ new WeakMap();
1312
+ const pathProxy = (nodes, address, owner, treeSelection) => {
1313
+ const proxy = new Proxy({}, { get: (_target, property) => {
1314
+ if (typeof property !== "string") return void 0;
1315
+ const trees = nodes.every((node) => node.kind === "tree");
1316
+ if (!treeSelection && trees && property === "rootId") return pathProxy(nodes, address, owner, { kind: "root" });
1317
+ if (!treeSelection && trees && property === "nodes") return pathProxy(nodes, address, owner, { kind: "nodes" });
1318
+ if (treeSelection?.kind === "nodes" && property === "item") return (id) => {
1319
+ if (typeof id !== "string") throw new TypeError("Tree node keys must be strings.");
1320
+ return pathProxy(nodes, address, owner, {
1321
+ kind: "node",
1322
+ id
1323
+ });
1324
+ };
1325
+ if (treeSelection) throw new TypeError(`Invalid tree path segment: ${property}`);
1326
+ if (nodes.every((node) => collectionEntryNode(node) !== void 0) && property === "item") return (id) => {
1327
+ if (typeof id !== "string") throw new TypeError("Collection keys must be strings.");
1328
+ for (const node of nodes) if (node.kind === "table" || node.kind === "map") {
1329
+ const invalid = checkKey(node.key, id, [...address, id]);
1330
+ if (invalid) throw new TypeError(invalid.message);
1331
+ }
1332
+ return pathProxy(nodes.map((node) => collectionEntryNode(node)), [...address, id], owner);
1333
+ };
1334
+ const children = nodes.flatMap((node) => {
1335
+ if (node.kind === "object") return Object.hasOwn(node.shape, property) ? [node.shape[property]] : [];
1336
+ if (node.kind !== "variant") return [];
1337
+ if (property === node.tag) return [Object.freeze({ kind: "field" })];
1338
+ return Object.values(node.variants).flatMap((branch) => Object.hasOwn(branch.shape, property) ? [branch.shape[property]] : []);
1339
+ });
1340
+ if (!children.length) throw new TypeError(`Invalid schema path segment: ${property}`);
1341
+ return pathProxy(children, [...address, property], owner);
1342
+ } });
1343
+ paths.set(proxy, {
1344
+ nodes,
1345
+ address,
1346
+ owner,
1347
+ ...treeSelection ? { tree: treeSelection } : {}
1348
+ });
1349
+ return proxy;
1350
+ };
1351
+ const compilePath = (owner, kind, pick) => {
1352
+ const scope = {};
1353
+ const value = pick(pathProxy([owner], [], scope));
1354
+ const selected = typeof value === "object" && value !== null ? paths.get(value) : void 0;
1355
+ if (!selected || selected.owner !== scope) throw new TypeError("Selector must return a path from its callback.");
1356
+ const collection = selected.tree?.kind === "nodes" || selected.nodes.every((node) => collectionEntryNode(node) !== void 0);
1357
+ if (kind === "collection" && !collection) throw new TypeError("Collection selectors require a map, table, list or tree nodes path.");
1358
+ return Object.freeze({
1359
+ kind: kind === "auto" ? collection ? "collection" : "value" : kind,
1360
+ schema: owner,
1361
+ address: Object.freeze([...selected.address]),
1362
+ ...selected.tree ? { tree: Object.freeze({ ...selected.tree }) } : {}
1363
+ });
1364
+ };
1365
+ //#endregion
892
1366
  //#region core/src/address/relation.ts
893
1367
  const contains = (parent, child) => {
894
- require_advanced.profile.address.prefixComparison();
1368
+ require_scheduler.profile.address.prefixComparison();
895
1369
  if (parent.length > child.length) return false;
896
1370
  for (let index = 0; index < parent.length; index += 1) {
897
- require_advanced.profile.address.segmentCompared();
1371
+ require_scheduler.profile.address.segmentCompared();
898
1372
  if (parent[index] !== child[index]) return false;
899
1373
  }
900
1374
  return true;
@@ -907,7 +1381,7 @@ const createImpact = (schema, changes) => {
907
1381
  let orders;
908
1382
  const index = () => {
909
1383
  if (!values) {
910
- require_advanced.profile.impact.index();
1384
+ require_scheduler.profile.impact.index();
911
1385
  values = new require_driver.AddressIndex();
912
1386
  orders = new require_driver.AddressIndex();
913
1387
  visitChangedLocations(changes, (at) => values.add(at, true), (at) => orders.add(at, true));
@@ -916,7 +1390,7 @@ const createImpact = (schema, changes) => {
916
1390
  };
917
1391
  const cache = /* @__PURE__ */ new Map();
918
1392
  const affects = (value) => {
919
- require_advanced.profile.impact.affects();
1393
+ require_scheduler.profile.impact.affects();
920
1394
  if (!belongs(value, schema)) return false;
921
1395
  if (reset) return true;
922
1396
  return affected(value, index(), orders);
@@ -990,8 +1464,8 @@ const createImpact = (schema, changes) => {
990
1464
  };
991
1465
  return Object.freeze({
992
1466
  kind: reset ? "reset" : "incremental",
993
- affects: (pick) => affects(require_advanced.compilePath(schema, "value", pick)),
994
- collection: (pick) => collection(require_advanced.compilePath(schema, "collection", pick))
1467
+ affects: (pick) => affects(compilePath(schema, "value", pick)),
1468
+ collection: (pick) => collection(compilePath(schema, "collection", pick))
995
1469
  });
996
1470
  };
997
1471
  //#endregion
@@ -1193,18 +1667,18 @@ const createHistory = (input) => {
1193
1667
  const installMember = (parent, key, present, value) => {
1194
1668
  if (Array.isArray(parent)) {
1195
1669
  const index = Number(key);
1196
- if (present) if (index < 0) require_advanced.insert(parent, parent.length, value);
1670
+ if (present) if (index < 0) insert$2(parent, parent.length, value);
1197
1671
  else parent[index] = value;
1198
- else if (index >= 0) require_advanced.remove(parent, index);
1199
- } else require_context.installOwn(parent, key, present, value);
1672
+ else if (index >= 0) remove$3(parent, index);
1673
+ } else require_record.installOwn(parent, key, present, value);
1200
1674
  };
1201
1675
  const orderOf = (node, value) => {
1202
- if (node.kind === "list") return require_advanced.toArray(require_advanced.indexedKeys(value, node.keyOf));
1676
+ if (node.kind === "list") return toArray(indexedKeys(value, node.keyOf));
1203
1677
  if (node.kind === "table") return [...value.ids];
1204
1678
  throw new Error("Order requires a table or list.");
1205
1679
  };
1206
1680
  const installOrder = (node, value, order) => {
1207
- if (node.kind === "list") require_advanced.install(value, node.keyOf, order);
1681
+ if (node.kind === "list") install(value, node.keyOf, order);
1208
1682
  else if (node.kind === "table") value.ids = [...order];
1209
1683
  else throw new Error("Order requires a table or list.");
1210
1684
  };
@@ -1225,9 +1699,9 @@ const forgetMember = (group, key) => {
1225
1699
  const emptyGroup = (group) => !group.order && (group.layout === "fixed" ? !group.members.some(Boolean) : !group.members?.size);
1226
1700
  const transition = (node, key, beforePresent, before, afterPresent, after) => {
1227
1701
  if (beforePresent === afterPresent && (!beforePresent || Object.is(before, after))) return;
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");
1702
+ if (node.kind !== "field" && beforePresent === afterPresent && equalValue(node, before, after)) return;
1703
+ const value = afterPresent ? node.kind === "field" ? after : copyValue(node, after) : void 0;
1704
+ require_scheduler.profile.recorder("transitions");
1231
1705
  return !beforePresent ? {
1232
1706
  key,
1233
1707
  kind: "added",
@@ -1268,7 +1742,7 @@ const diffMember = (changes, members, node, at, key, beforePresent, before, afte
1268
1742
  const left = before, right = after;
1269
1743
  const childAt = at.concat(key);
1270
1744
  const children = [];
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]);
1745
+ for (const [child, definition] of compiledShape(node, before).members) diffMember(changes, children, definition.node, childAt, child, Object.hasOwn(left, child), left[child], Object.hasOwn(right, child), right[child]);
1272
1746
  publishMembers(changes, childAt, children);
1273
1747
  return;
1274
1748
  }
@@ -1281,8 +1755,8 @@ const diffMember = (changes, members, node, at, key, beforePresent, before, afte
1281
1755
  for (const id of Object.keys(left)) diffMember(changes, children, node.value, childAt, id, true, left[id], Object.hasOwn(right, id), right[id]);
1282
1756
  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]);
1283
1757
  let order;
1284
- if (node.kind === "table" && !require_advanced.equal(a.ids, b.ids)) {
1285
- require_advanced.profile.recorder("publishedOrderItems", b.ids.length);
1758
+ if (node.kind === "table" && !equal(a.ids, b.ids)) {
1759
+ require_scheduler.profile.recorder("publishedOrderItems", b.ids.length);
1286
1760
  order = {
1287
1761
  before: a.ids,
1288
1762
  after: [...b.ids]
@@ -1299,7 +1773,7 @@ const restore = (fact, schema, root, skip = 0) => {
1299
1773
  const at = skip ? fact.at.slice(skip) : fact.at;
1300
1774
  if (fact.kind === "member") {
1301
1775
  const member = fact.member;
1302
- const value = member.present ? require_advanced.copyValue(member.node, member.value) : void 0;
1776
+ const value = member.present ? copyValue(member.node, member.value) : void 0;
1303
1777
  if (!at.length) return value;
1304
1778
  const location = resolveLocated(schema, root, at);
1305
1779
  if (!location) throw new Error("Cannot restore an unresolved member.");
@@ -1313,12 +1787,12 @@ const restore = (fact, schema, root, skip = 0) => {
1313
1787
  const tree = location.value;
1314
1788
  if (fact.before === null) delete tree.rootId;
1315
1789
  else tree.rootId = fact.before;
1316
- for (const [id, node] of fact.nodes) installMember(tree.nodes, id, node !== void 0, node && require_advanced.copyTreeNode(node));
1790
+ for (const [id, node] of fact.nodes) installMember(tree.nodes, id, node !== void 0, node && copyTreeNode(node));
1317
1791
  }
1318
1792
  return root;
1319
1793
  };
1320
1794
  const reconstructBefore = (node, current, records, offset) => {
1321
- let before = require_advanced.copyValue(node, current);
1795
+ let before = copyValue(node, current);
1322
1796
  for (let i = records.length - 1; i >= 0; i--) if (records[i].kind !== "order") before = restore(records[i], node, before, offset);
1323
1797
  for (const record of records) if (record.kind === "order") before = restore(record, node, before, offset);
1324
1798
  return before;
@@ -1337,10 +1811,10 @@ const sealMembers = (fact, changes) => {
1337
1811
  }
1338
1812
  let order;
1339
1813
  if (fact.order) {
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)) {
1814
+ const current = fact.node.kind === "list" ? indexedKeys(fact.value, fact.node.keyOf) : fact.value.ids;
1815
+ if (!equal(fact.order, current)) {
1342
1816
  const after = orderOf(fact.node, fact.value);
1343
- require_advanced.profile.recorder("publishedOrderItems", after.length);
1817
+ require_scheduler.profile.recorder("publishedOrderItems", after.length);
1344
1818
  order = {
1345
1819
  before: fact.order,
1346
1820
  after
@@ -1357,11 +1831,11 @@ const sealTree = (fact, canonical, changes) => {
1357
1831
  for (const [id, before] of fact.nodes) {
1358
1832
  const after = Object.hasOwn(tree.nodes, id) ? tree.nodes[id] : void 0;
1359
1833
  if (!before && !after) continue;
1360
- if (before && after && require_advanced.equalTreeNode(before, after)) continue;
1834
+ if (before && after && equalTreeNode(before, after)) continue;
1361
1835
  nodes.push(!before ? {
1362
1836
  id,
1363
1837
  kind: "added",
1364
- after: require_advanced.copyTreeNode(after)
1838
+ after: copyTreeNode(after)
1365
1839
  } : !after ? {
1366
1840
  id,
1367
1841
  kind: "removed",
@@ -1370,7 +1844,7 @@ const sealTree = (fact, canonical, changes) => {
1370
1844
  id,
1371
1845
  kind: "updated",
1372
1846
  before,
1373
- after: require_advanced.copyTreeNode(after)
1847
+ after: copyTreeNode(after)
1374
1848
  });
1375
1849
  }
1376
1850
  const after = tree.rootId ?? null;
@@ -1398,7 +1872,7 @@ var ChangeRecorder = class {
1398
1872
  this.indexedGroups = true;
1399
1873
  for (const fact of this.facts) if (fact.kind === "members") {
1400
1874
  index.add(fact.at, fact);
1401
- require_advanced.profile.recorder("indexedGroups");
1875
+ require_scheduler.profile.recorder("indexedGroups");
1402
1876
  }
1403
1877
  }
1404
1878
  return index;
@@ -1447,7 +1921,7 @@ var ChangeRecorder = class {
1447
1921
  releaseCovered(children) {
1448
1922
  let changedGroups;
1449
1923
  for (const child of children) {
1450
- require_advanced.profile.recorder("absorbed");
1924
+ require_scheduler.profile.recorder("absorbed");
1451
1925
  if (child.kind === "member") {
1452
1926
  const { group, member } = child;
1453
1927
  forgetMember(group, member.key);
@@ -1463,9 +1937,9 @@ var ChangeRecorder = class {
1463
1937
  this.facts.add(fact);
1464
1938
  if (fact.kind === "members") {
1465
1939
  this.groups.set(fact.parent, fact);
1466
- require_advanced.profile.recorder("groups");
1940
+ require_scheduler.profile.recorder("groups");
1467
1941
  if (!this.indexedGroups) return;
1468
- require_advanced.profile.recorder("indexedGroups");
1942
+ require_scheduler.profile.recorder("indexedGroups");
1469
1943
  }
1470
1944
  (this.index ??= new require_driver.AddressIndex()).add(fact.at, fact);
1471
1945
  }
@@ -1495,14 +1969,14 @@ var ChangeRecorder = class {
1495
1969
  if (group.layout === "dynamic") (group.members ??= /* @__PURE__ */ new Map()).set(key, member);
1496
1970
  else if (definition.kind === "fixed") group.members[definition.slot] = member;
1497
1971
  else throw new Error("A fixed member group requires a fixed schema member.");
1498
- require_advanced.profile.recorder("facts");
1972
+ require_scheduler.profile.recorder("facts");
1499
1973
  }
1500
1974
  reset() {
1501
1975
  if (this.resetBefore) return;
1502
1976
  const value = this.absorb([], this.state.schema, this.state.document, true);
1503
1977
  this.resetBefore = { value };
1504
1978
  this.groups = /* @__PURE__ */ new WeakMap();
1505
- require_advanced.profile.recorder("facts");
1979
+ require_scheduler.profile.recorder("facts");
1506
1980
  }
1507
1981
  createGroup(container) {
1508
1982
  const group = container.layout.kind === "fixed" ? {
@@ -1527,13 +2001,13 @@ var ChangeRecorder = class {
1527
2001
  return group;
1528
2002
  }
1529
2003
  order(container) {
1530
- require_advanced.profile.recorder("orderCaptures");
2004
+ require_scheduler.profile.recorder("orderCaptures");
1531
2005
  let group = this.groups.get(container.parent);
1532
2006
  if (group?.order || this.covered(container.at)) return;
1533
2007
  group ??= this.createGroup(container);
1534
2008
  group.order = orderOf(container.node, container.value);
1535
- require_advanced.profile.recorder("orderSnapshots");
1536
- require_advanced.profile.recorder("orderItems", group.order.length);
2009
+ require_scheduler.profile.recorder("orderSnapshots");
2010
+ require_scheduler.profile.recorder("orderItems", group.order.length);
1537
2011
  }
1538
2012
  tree(container, id) {
1539
2013
  const { at, value: tree } = container;
@@ -1551,8 +2025,8 @@ var ChangeRecorder = class {
1551
2025
  this.register(fact);
1552
2026
  }
1553
2027
  if (id !== void 0 && !fact.nodes.has(id)) {
1554
- require_advanced.profile.recorder("treeNodes");
1555
- fact.nodes.set(id, Object.hasOwn(tree.nodes, id) ? require_advanced.copyTreeNode(tree.nodes[id]) : void 0);
2028
+ require_scheduler.profile.recorder("treeNodes");
2029
+ fact.nodes.set(id, Object.hasOwn(tree.nodes, id) ? copyTreeNode(tree.nodes[id]) : void 0);
1556
2030
  }
1557
2031
  }
1558
2032
  rollback() {
@@ -1565,7 +2039,7 @@ var ChangeRecorder = class {
1565
2039
  const fact = facts[i];
1566
2040
  if (fact.kind === "members") for (const member of fact.members?.values() ?? []) {
1567
2041
  if (!member) continue;
1568
- installMember(fact.parent, memberKey(fact, member.key), member.present, member.present ? require_advanced.copyValue(member.node, member.value) : void 0);
2042
+ installMember(fact.parent, memberKey(fact, member.key), member.present, member.present ? copyValue(member.node, member.value) : void 0);
1569
2043
  }
1570
2044
  else if (fact.kind === "tree") restore(fact, this.state.schema, this.state.document);
1571
2045
  }
@@ -1573,19 +2047,19 @@ var ChangeRecorder = class {
1573
2047
  }
1574
2048
  seal() {
1575
2049
  if (this.resetBefore) {
1576
- if (require_advanced.equalValue(this.state.schema, this.resetBefore.value, this.state.document)) return require_driver.sealChanges([]);
1577
- require_advanced.profile.recorder("sealed");
2050
+ if (equalValue(this.state.schema, this.resetBefore.value, this.state.document)) return require_driver.sealChanges([]);
2051
+ require_scheduler.profile.recorder("sealed");
1578
2052
  return require_driver.sealChanges([{
1579
2053
  kind: "reset",
1580
2054
  before: this.resetBefore.value,
1581
- after: require_advanced.copyValue(this.state.schema, this.state.document)
2055
+ after: copyValue(this.state.schema, this.state.document)
1582
2056
  }]);
1583
2057
  }
1584
2058
  const changes = [];
1585
2059
  for (const fact of this.facts) if (fact.kind === "members") sealMembers(fact, changes);
1586
2060
  else sealTree(fact, this.state, changes);
1587
2061
  const result = require_driver.sealChanges(changes);
1588
- require_advanced.profile.recorder("sealed", result.changes.length);
2062
+ require_scheduler.profile.recorder("sealed", result.changes.length);
1589
2063
  return result;
1590
2064
  }
1591
2065
  };
@@ -1605,7 +2079,7 @@ var MutationSession = class {
1605
2079
  this.resolvedRoot = state.document;
1606
2080
  }
1607
2081
  validate(node, value, at) {
1608
- const failure = require_advanced.checkValue(node, value, at);
2082
+ const failure = checkValue(node, value, at);
1609
2083
  if (failure) require_driver.invalidValue(failure);
1610
2084
  }
1611
2085
  resolveContainer(at) {
@@ -1627,7 +2101,7 @@ var MutationSession = class {
1627
2101
  this.validate(this.state.schema, value, at);
1628
2102
  if (Object.is(this.state.document, value)) return;
1629
2103
  this.recorder.reset();
1630
- this.state.document = require_advanced.copyValue(this.state.schema, value);
2104
+ this.state.document = copyValue(this.state.schema, value);
1631
2105
  this.invalidate();
1632
2106
  return;
1633
2107
  }
@@ -1669,12 +2143,12 @@ var MutationSession = class {
1669
2143
  const previous = container.parent[physicalKey];
1670
2144
  if (existed === present && (!present || Object.is(previous, value))) return false;
1671
2145
  if (parentNode.kind === "map" || parentNode.kind === "table") {
1672
- const failure = require_advanced.checkKey(parentNode.key, key, []);
2146
+ const failure = checkKey(parentNode.key, key, []);
1673
2147
  if (failure) return require_driver.fail(container.at.concat(key, ...failure.address), "invalid-key", failure.message);
1674
2148
  }
1675
2149
  if (present) {
1676
2150
  if (node.kind === "field") {
1677
- const failure = require_advanced.checkValue(node, value, []);
2151
+ const failure = checkValue(node, value, []);
1678
2152
  if (failure) return require_driver.invalidValue(failure, container.at.concat(key, ...failure.address));
1679
2153
  } else this.validate(node, value, container.at.concat(key));
1680
2154
  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.");
@@ -1682,7 +2156,7 @@ var MutationSession = class {
1682
2156
  const membershipChanged = entry && existed !== present;
1683
2157
  if (membershipChanged && (parentNode.kind === "list" || parentNode.kind === "table")) this.recorder.order(container);
1684
2158
  this.recorder.member(container, key, member, physicalKey);
1685
- const next = present ? node.kind === "field" ? value : require_advanced.copyValue(node, value) : void 0;
2159
+ const next = present ? node.kind === "field" ? value : copyValue(node, value) : void 0;
1686
2160
  installMember(container.parent, physicalKey, present, next);
1687
2161
  if (node.kind !== "field" || membershipChanged) this.invalidate();
1688
2162
  return membershipChanged;
@@ -1722,12 +2196,12 @@ function apply(session, changes, direction) {
1722
2196
  }
1723
2197
  if (change.order) {
1724
2198
  const keys = node.kind === "table" ? Object.keys(container.parent) : orderOf(node, current);
1725
- if (!require_advanced.matches(change.order[side], keys)) return require_driver.fail(change.at, "invalid-changes", "Order must contain exactly the resulting keys.");
2199
+ if (!matches(change.order[side], keys)) return require_driver.fail(change.at, "invalid-changes", "Order must contain exactly the resulting keys.");
1726
2200
  installOrder(node, current, change.order[side]);
1727
2201
  session.invalidate();
1728
2202
  } else if (membershipChanged && node.kind === "table") {
1729
2203
  const ids = current.ids;
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.");
2204
+ if (!matches(ids, Object.keys(container.parent))) return require_driver.fail(change.at, "invalid-changes", "Table membership changes require a matching order.");
1731
2205
  }
1732
2206
  } else {
1733
2207
  const container = session.resolveTree(change.at);
@@ -1740,16 +2214,26 @@ function apply(session, changes, direction) {
1740
2214
  for (const item of change.nodes) {
1741
2215
  const next = side === "after" ? item.kind !== "removed" ? item.after : void 0 : item.kind !== "added" ? item.before : void 0;
1742
2216
  if (next !== void 0) {
1743
- const diagnostic = require_advanced.checkTreePayload(node.value, next, change.at.concat(item.id));
2217
+ const diagnostic = checkTreePayload(node.value, next, change.at.concat(item.id));
1744
2218
  if (diagnostic) require_driver.invalidValue(diagnostic);
1745
2219
  }
1746
- installMember(current.nodes, item.id, next !== void 0, next && require_advanced.copyTreeNode(next));
2220
+ installMember(current.nodes, item.id, next !== void 0, next && copyTreeNode(next));
1747
2221
  }
1748
- if (!require_context.validate(current)) return require_driver.fail(change.at, "invalid-tree", "Invalid tree structure.");
2222
+ if (!require_driver.validate(current)) return require_driver.fail(change.at, "invalid-tree", "Invalid tree structure.");
1749
2223
  session.invalidate();
1750
2224
  }
1751
2225
  }
1752
2226
  //#endregion
2227
+ //#region core/src/runtime/readable.ts
2228
+ const readonlyDocument = (runtime) => {
2229
+ const readable = {
2230
+ revision: runtime.revision,
2231
+ subscribe: runtime.subscribe
2232
+ };
2233
+ require_driver.bindContext(readable, require_driver.contextOf(runtime));
2234
+ return Object.freeze(readable);
2235
+ };
2236
+ //#endregion
1753
2237
  //#region core/src/runtime/notification.ts
1754
2238
  const attachProjection = (notification, processor) => {
1755
2239
  const entry = {
@@ -1913,18 +2397,19 @@ const createNotificationCenter = (schema) => {
1913
2397
  //#endregion
1914
2398
  //#region core/src/runtime.ts
1915
2399
  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);
2400
+ const schema = schemaNodeOf(input.schema);
2401
+ const invalid = checkValue(schema, input.initial);
2402
+ if (invalid) throw new ParseError(invalid);
1919
2403
  const state = {
1920
- schema: input.schema,
1921
- document: require_advanced.copyValue(input.schema, input.initial),
2404
+ schema,
2405
+ document: copyValue(schema, input.initial),
1922
2406
  disposed: false,
1923
2407
  projectionLocks: 0
1924
2408
  };
1925
2409
  let revision = 0, busy = false;
1926
- const notifications = createNotificationCenter(input.schema);
2410
+ const notifications = createNotificationCenter(schema);
1927
2411
  let runtime, context;
2412
+ let readonlyAlias;
1928
2413
  const idle = () => {
1929
2414
  if (state.disposed) throw new DocumentDisposedError();
1930
2415
  if (busy || state.projectionLocks) throw new DocumentReentrancyError();
@@ -1957,7 +2442,7 @@ const createDocument = (input) => {
1957
2442
  revision: ++revision,
1958
2443
  source,
1959
2444
  changes,
1960
- impact: createImpact(input.schema, changes)
2445
+ impact: createImpact(schema, changes)
1961
2446
  };
1962
2447
  if (source === "remote") history.invalidate();
1963
2448
  else if (recordHistory && (source === "local" || source === "system")) history.record(changes);
@@ -2004,6 +2489,7 @@ const createDocument = (input) => {
2004
2489
  runtime = {
2005
2490
  schema: input.schema,
2006
2491
  revision: () => revision,
2492
+ readonly: () => readonlyAlias ??= readonlyDocument(runtime),
2007
2493
  update: (run, options) => {
2008
2494
  const source = options?.source ?? "local";
2009
2495
  let value;
@@ -2022,13 +2508,16 @@ const createDocument = (input) => {
2022
2508
  value
2023
2509
  };
2024
2510
  },
2025
- apply: (inputChanges, options) => mutate({
2026
- kind: "apply",
2027
- source: options?.source ?? "local"
2028
- }, options?.history ?? true, (session) => {
2029
- if (!options || options.expectedRevision !== revision) require_driver.fail([], "baseline-mismatch", "apply requires the current expectedRevision.");
2030
- apply(session, require_driver.decodeChanges(inputChanges), "forward");
2031
- }),
2511
+ apply: (inputChanges, options) => {
2512
+ const source = options?.source ?? "local";
2513
+ return mutate({
2514
+ kind: "apply",
2515
+ source
2516
+ }, source === "remote" ? false : options?.history ?? true, (session) => {
2517
+ if (!options || options.expectedRevision !== revision) require_driver.fail([], "baseline-mismatch", "apply requires the current expectedRevision.");
2518
+ apply(session, require_driver.decodeChanges(inputChanges), "forward");
2519
+ });
2520
+ },
2032
2521
  replace: (value, options) => {
2033
2522
  const source = options?.source ?? "system";
2034
2523
  return mutate({
@@ -2038,14 +2527,14 @@ const createDocument = (input) => {
2038
2527
  },
2039
2528
  snapshot: () => {
2040
2529
  if (state.disposed) throw new DocumentDisposedError();
2041
- return require_advanced.copyValue(input.schema, state.document);
2530
+ return copyValue(schema, state.document);
2042
2531
  },
2043
2532
  subscribe: ((pick, listener) => {
2044
2533
  if (state.disposed) throw new DocumentDisposedError();
2045
2534
  if (!listener) return notifications.subscribe(pick);
2046
2535
  const picks = Array.isArray(pick) ? pick : [pick];
2047
2536
  if (!picks.length) throw new TypeError("Expected at least one subscription path.");
2048
- return notifications.subscribeTargets(picks.map((p) => require_advanced.compilePath(input.schema, "value", p)), listener);
2537
+ return notifications.subscribeTargets(picks.map((p) => compilePath(schema, "value", p)), listener);
2049
2538
  }),
2050
2539
  history: history.api,
2051
2540
  dispose: () => {
@@ -2067,27 +2556,25 @@ const createDocument = (input) => {
2067
2556
  driver: void 0,
2068
2557
  bypassDepth: 0
2069
2558
  };
2070
- require_context.bindContext(runtime, context);
2071
- require_context.bindContext(history.api, context);
2559
+ require_driver.bindContext(runtime, context);
2560
+ require_driver.bindContext(history.api, context);
2072
2561
  return runtime;
2073
2562
  };
2074
2563
  //#endregion
2075
- //#region core/src/runtime/readable.ts
2076
- const asReadable = (runtime) => {
2077
- const readable = {
2078
- revision: runtime.revision,
2079
- subscribe: runtime.subscribe
2080
- };
2081
- require_context.bindContext(readable, require_context.contextOf(runtime));
2082
- return Object.freeze(readable);
2083
- };
2084
- //#endregion
2085
2564
  //#region core/src/access/dependency.ts
2086
2565
  const createDependencyTracker = () => {
2087
2566
  const targets = [];
2567
+ const buckets = /* @__PURE__ */ new Map();
2088
2568
  return {
2089
2569
  record: (value) => {
2090
- if (!targets.some((entry) => same(entry, value))) targets.push(value);
2570
+ const key = dependencyBucket(value);
2571
+ let entries = buckets.get(key);
2572
+ if (!entries) {
2573
+ entries = [];
2574
+ buckets.set(key, entries);
2575
+ } else if (entries.some((entry) => same(entry, value))) return;
2576
+ entries.push(value);
2577
+ targets.push(value);
2091
2578
  },
2092
2579
  snapshot: () => Object.freeze(targets.slice())
2093
2580
  };
@@ -2095,7 +2582,7 @@ const createDependencyTracker = () => {
2095
2582
  //#endregion
2096
2583
  //#region core/src/runtime/access.ts
2097
2584
  const readWith = (runtime, run, dependencies) => {
2098
- const state = require_context.contextOf(runtime).state;
2585
+ const state = require_driver.contextOf(runtime).state;
2099
2586
  if (state.disposed) throw new DocumentDisposedError();
2100
2587
  state.projectionLocks += 1;
2101
2588
  try {
@@ -2116,7 +2603,7 @@ const sameDependencySet = (left, right) => {
2116
2603
  return true;
2117
2604
  };
2118
2605
  const select = (document, selector, equality = Object.is) => {
2119
- const context = require_context.contextOf(document);
2606
+ const context = require_driver.contextOf(document);
2120
2607
  let initialized = false;
2121
2608
  let value;
2122
2609
  let selectedRevision = 0;
@@ -2176,6 +2663,281 @@ const select = (document, selector, equality = Object.is) => {
2176
2663
  });
2177
2664
  };
2178
2665
  //#endregion
2666
+ //#region core/src/projection/input.ts
2667
+ const valueInput = (initial, equality = Object.is) => require_scheduler.defineSource({
2668
+ kind: "value-input",
2669
+ initial,
2670
+ equality
2671
+ }, {
2672
+ kind: "value",
2673
+ equality
2674
+ });
2675
+ const collectionInput = (initial = /* @__PURE__ */ new Map(), equality = Object.is) => {
2676
+ const entries = /* @__PURE__ */ new Map();
2677
+ for (const [key, value] of initial) {
2678
+ if (typeof key !== "string") throw new TypeError("Projection keys must be strings.");
2679
+ entries.set(key, value);
2680
+ }
2681
+ return require_scheduler.defineSource({
2682
+ kind: "collection-input",
2683
+ initial: entries,
2684
+ equality
2685
+ }, {
2686
+ kind: "collection",
2687
+ equality
2688
+ });
2689
+ };
2690
+ const input = Object.assign(valueInput, { collection: collectionInput });
2691
+ //#endregion
2692
+ //#region core/src/projection/observe.ts
2693
+ function observe(source, selector) {
2694
+ if (isExternalSource(source)) return source.kind === "collection" ? require_scheduler.defineSource({
2695
+ kind: "external-collection",
2696
+ source
2697
+ }, {
2698
+ kind: "collection",
2699
+ equality: Object.is
2700
+ }) : require_scheduler.defineSource({
2701
+ kind: "external-value",
2702
+ source,
2703
+ equality: Object.is
2704
+ }, {
2705
+ kind: "value",
2706
+ equality: Object.is
2707
+ });
2708
+ if ("current" in source && typeof source.current === "function") return require_scheduler.defineSource({
2709
+ kind: "readable",
2710
+ readable: source,
2711
+ equality: Object.is
2712
+ }, {
2713
+ kind: "value",
2714
+ equality: Object.is
2715
+ });
2716
+ const document = source;
2717
+ const state = require_driver.contextOf(document).state;
2718
+ const selected = selector ? compilePath(state.schema, "auto", selector) : Object.freeze({
2719
+ kind: "value",
2720
+ schema: state.schema,
2721
+ address: Object.freeze([])
2722
+ });
2723
+ return require_scheduler.defineSource({
2724
+ kind: "document",
2725
+ document,
2726
+ selector: selected
2727
+ }, {
2728
+ kind: selected.kind,
2729
+ equality: Object.is
2730
+ });
2731
+ }
2732
+ const isExternalSource = (source) => {
2733
+ if (!source || typeof source !== "object") return false;
2734
+ const candidate = source;
2735
+ return (candidate.kind === "value" || candidate.kind === "collection") && typeof candidate.current === "function" && typeof candidate.revision === "function" && typeof candidate.subscribe === "function";
2736
+ };
2737
+ //#endregion
2738
+ //#region core/src/projection/derive.ts
2739
+ const sourceValue = (source) => source.kind === "value" ? source.value : require_scheduler.snapshotCollectionView(source.read);
2740
+ const outputKind = (projection) => {
2741
+ const ref = require_scheduler.projectionRef(projection);
2742
+ const definition = ref.producer;
2743
+ const output = definition.kind === "source" ? definition.output : definition.outputs[ref.output];
2744
+ if (!output) throw new TypeError("Projection output does not exist.");
2745
+ return output.kind;
2746
+ };
2747
+ const assertKeyedProjection = (projection, role) => {
2748
+ if (outputKind(projection) !== "collection") throw new TypeError(`${role} must be a keyed collection projection.`);
2749
+ };
2750
+ const isKeyedDependency = (value) => {
2751
+ if (!value || typeof value !== "object" || require_scheduler.isProjection(value)) return false;
2752
+ const candidate = value;
2753
+ return require_scheduler.isProjection(candidate.source) && typeof candidate.key === "function";
2754
+ };
2755
+ const bindKey = (index, outputKey, sourceKey) => {
2756
+ const previous = index.forward.get(outputKey);
2757
+ if (previous === sourceKey) return;
2758
+ if (previous !== void 0) {
2759
+ const dependents = index.reverse.get(previous);
2760
+ dependents?.delete(outputKey);
2761
+ if (dependents?.size === 0) index.reverse.delete(previous);
2762
+ index.forward.delete(outputKey);
2763
+ }
2764
+ if (sourceKey === void 0) return;
2765
+ index.forward.set(outputKey, sourceKey);
2766
+ const dependents = index.reverse.get(sourceKey);
2767
+ if (dependents) dependents.add(outputKey);
2768
+ else index.reverse.set(sourceKey, new Set([outputKey]));
2769
+ };
2770
+ const unbindKey = (indexes, outputKey) => {
2771
+ for (const index of indexes) bindKey(index, outputKey, void 0);
2772
+ };
2773
+ const createBindingIndex = () => ({
2774
+ forward: /* @__PURE__ */ new Map(),
2775
+ reverse: /* @__PURE__ */ new Map()
2776
+ });
2777
+ function createValueDerive(dependencies, compute, equality = Object.is) {
2778
+ if (!require_record.isPlainObject(dependencies) || require_scheduler.isProjection(dependencies)) throw new TypeError("Derive dependencies must be a plain object.");
2779
+ const names = Object.keys(dependencies);
2780
+ const ordered = names.map((name) => dependencies[name]);
2781
+ ordered.forEach(require_scheduler.projectionRef);
2782
+ const [projection] = require_scheduler.defineProcessor({
2783
+ dependencies: ordered,
2784
+ outputs: [{
2785
+ kind: "value",
2786
+ equality
2787
+ }],
2788
+ create: () => ({ evaluate: (evaluation) => {
2789
+ const output = evaluation.outputs[0];
2790
+ if (output.kind !== "value") throw new Error("derive requires a value output.");
2791
+ const values = Object.create(null);
2792
+ for (let index = 0; index < names.length; index++) values[names[index]] = sourceValue(evaluation.sources[index]);
2793
+ const next = compute(Object.freeze(values));
2794
+ require_scheduler.assertSynchronous(next);
2795
+ output.output.set(next);
2796
+ } })
2797
+ });
2798
+ return projection;
2799
+ }
2800
+ function createKeyedDerive(source, dependenciesOrSelect, selectOrEquality, maybeEquality) {
2801
+ assertKeyedProjection(source, "Keyed derive source");
2802
+ const dependencySpecs = typeof dependenciesOrSelect === "function" ? void 0 : dependenciesOrSelect;
2803
+ const select = dependencySpecs === void 0 ? dependenciesOrSelect : selectOrEquality;
2804
+ const equality = dependencySpecs === void 0 ? selectOrEquality : maybeEquality;
2805
+ if (typeof select !== "function") throw new TypeError("Keyed derive requires a selector.");
2806
+ const dependencies = [source];
2807
+ const dependencyNames = [];
2808
+ const keyed = [];
2809
+ if (dependencySpecs !== void 0) {
2810
+ if (!require_record.isPlainObject(dependencySpecs) || require_scheduler.isProjection(dependencySpecs)) throw new TypeError("Keyed derive dependencies must be a plain object.");
2811
+ for (const name of Reflect.ownKeys(dependencySpecs)) {
2812
+ if (typeof name !== "string") throw new TypeError("Keyed derive dependency names must be strings.");
2813
+ const descriptor = Object.getOwnPropertyDescriptor(dependencySpecs, name);
2814
+ if (!descriptor?.enumerable || !("value" in descriptor)) throw new TypeError("Keyed derive dependencies must be enumerable data properties.");
2815
+ const dependency = descriptor.value;
2816
+ dependencyNames.push(name);
2817
+ if (require_scheduler.isProjection(dependency)) {
2818
+ dependencies.push(dependency);
2819
+ keyed.push(void 0);
2820
+ continue;
2821
+ }
2822
+ if (!isKeyedDependency(dependency)) throw new TypeError("Keyed derive dependencies must be projections or keyed lookups.");
2823
+ assertKeyedProjection(dependency.source, "Dynamic keyed dependency source");
2824
+ dependencies.push(dependency.source);
2825
+ keyed.push(dependency);
2826
+ }
2827
+ }
2828
+ const [projection] = require_scheduler.defineProcessor({
2829
+ dependencies,
2830
+ outputs: [{
2831
+ kind: "collection",
2832
+ equality: equality ?? Object.is
2833
+ }],
2834
+ create: () => {
2835
+ const bindings = keyed.map((dependency) => dependency ? createBindingIndex() : void 0);
2836
+ const bindingIndexes = bindings.filter((index) => index !== void 0);
2837
+ const globalValues = keyed.map(() => void 0);
2838
+ let revisions = Object.freeze([]);
2839
+ const clearBindings = () => {
2840
+ for (const index of bindings) {
2841
+ index?.forward.clear();
2842
+ index?.reverse.clear();
2843
+ }
2844
+ };
2845
+ return {
2846
+ evaluate: (evaluation) => {
2847
+ const driver = evaluation.sources[0];
2848
+ const output = evaluation.outputs[0];
2849
+ if (driver.kind !== "collection" || output.kind !== "collection") throw new Error("Keyed derive requires collection input and output.");
2850
+ const currentRevisions = evaluation.sources.map((current) => current.revision);
2851
+ for (let index = 0; index < keyed.length; index++) {
2852
+ if (keyed[index]) continue;
2853
+ if (evaluation.reset || revisions[index + 1] !== currentRevisions[index + 1]) globalValues[index] = sourceValue(evaluation.sources[index + 1]);
2854
+ }
2855
+ const project = (key) => {
2856
+ if (!driver.read.has(key)) return;
2857
+ const value = driver.read.get(key);
2858
+ const dependencyValues = Object.create(null);
2859
+ for (let index = 0; index < keyed.length; index++) {
2860
+ const dependency = keyed[index];
2861
+ if (!dependency) {
2862
+ dependencyValues[dependencyNames[index]] = globalValues[index];
2863
+ continue;
2864
+ }
2865
+ const sourceContext = evaluation.sources[index + 1];
2866
+ if (sourceContext.kind !== "collection") throw new TypeError("Dynamic keyed dependency resolved to a non-collection source.");
2867
+ const selectedKey = dependency.key(value, key);
2868
+ require_scheduler.assertSynchronous(selectedKey);
2869
+ if (selectedKey !== void 0 && typeof selectedKey !== "string") throw new TypeError("Dynamic keyed dependency keys must be strings or undefined.");
2870
+ bindKey(bindings[index], key, selectedKey);
2871
+ dependencyValues[dependencyNames[index]] = selectedKey === void 0 ? void 0 : sourceContext.read.get(selectedKey);
2872
+ }
2873
+ const next = dependencySpecs === void 0 ? select(value, key) : select(value, key, Object.freeze(dependencyValues));
2874
+ require_scheduler.assertSynchronous(next);
2875
+ output.output.set(key, next);
2876
+ };
2877
+ if (evaluation.reset) {
2878
+ clearBindings();
2879
+ const ids = driver.read.ids();
2880
+ for (const key of ids) project(key);
2881
+ output.output.order(ids);
2882
+ revisions = Object.freeze(currentRevisions);
2883
+ return;
2884
+ }
2885
+ const dirty = /* @__PURE__ */ new Set();
2886
+ let all = false;
2887
+ let updateOrder = false;
2888
+ if (revisions[0] !== currentRevisions[0]) {
2889
+ const change = driver.change;
2890
+ if (!change || change.kind === "reset") {
2891
+ all = true;
2892
+ updateOrder = true;
2893
+ } else {
2894
+ for (const entry of change.removed) {
2895
+ output.output.remove(entry.key);
2896
+ unbindKey(bindingIndexes, entry.key);
2897
+ dirty.delete(entry.key);
2898
+ }
2899
+ for (const entry of change.added) dirty.add(entry.key);
2900
+ for (const entry of change.updated) dirty.add(entry.key);
2901
+ updateOrder = Boolean(change.added.length || change.removed.length || change.order);
2902
+ }
2903
+ }
2904
+ for (let index = 0; index < keyed.length; index++) {
2905
+ if (revisions[index + 1] === currentRevisions[index + 1]) continue;
2906
+ if (!keyed[index]) {
2907
+ all = true;
2908
+ continue;
2909
+ }
2910
+ const sourceContext = evaluation.sources[index + 1];
2911
+ if (sourceContext.kind !== "collection" || !sourceContext.change) {
2912
+ all = true;
2913
+ continue;
2914
+ }
2915
+ if (sourceContext.change.kind === "reset") {
2916
+ all = true;
2917
+ continue;
2918
+ }
2919
+ const reverse = bindings[index].reverse;
2920
+ for (const transition of sourceContext.change.added) for (const outputKey of reverse.get(transition.key) ?? []) dirty.add(outputKey);
2921
+ for (const transition of sourceContext.change.updated) for (const outputKey of reverse.get(transition.key) ?? []) dirty.add(outputKey);
2922
+ for (const transition of sourceContext.change.removed) for (const outputKey of reverse.get(transition.key) ?? []) dirty.add(outputKey);
2923
+ }
2924
+ if (all) for (const key of driver.read.ids()) dirty.add(key);
2925
+ for (const key of dirty) if (driver.read.has(key)) project(key);
2926
+ if (updateOrder) output.output.order(driver.read.ids());
2927
+ revisions = Object.freeze(currentRevisions);
2928
+ },
2929
+ release: () => {
2930
+ clearBindings();
2931
+ revisions = Object.freeze([]);
2932
+ }
2933
+ };
2934
+ },
2935
+ name: "derive.keyed"
2936
+ });
2937
+ return projection;
2938
+ }
2939
+ const derive = Object.assign(createValueDerive, { keyed: createKeyedDerive });
2940
+ //#endregion
2179
2941
  //#region core/src/projection/collection/change.ts
2180
2942
  const commonOrderChanged = (before, after, added, removed) => {
2181
2943
  const beforeCommon = before.filter((key) => !removed.has(key));
@@ -2239,7 +3001,7 @@ const collectionHasAnyChange = (change) => change.kind === "reset" || Boolean(ch
2239
3001
  //#region core/src/projection/collection/index.ts
2240
3002
  const height = (node) => node?.height ?? 0;
2241
3003
  const node = (key, value, left, right) => {
2242
- require_advanced.profile.collectionIndex.node();
3004
+ require_scheduler.profile.collectionIndex.node();
2243
3005
  return Object.freeze({
2244
3006
  key,
2245
3007
  value,
@@ -2300,7 +3062,7 @@ var PersistentKeyedIndex = class PersistentKeyedIndex {
2300
3062
  }
2301
3063
  static from(entries) {
2302
3064
  const sorted = [...entries].sort(([left], [right]) => left < right ? -1 : left > right ? 1 : 0);
2303
- require_advanced.profile.collectionIndex.build(sorted.length);
3065
+ require_scheduler.profile.collectionIndex.build(sorted.length);
2304
3066
  return new PersistentKeyedIndex(fromSorted(sorted));
2305
3067
  }
2306
3068
  get(key) {
@@ -2374,7 +3136,7 @@ const createPublishedCollection = () => {
2374
3136
  };
2375
3137
  };
2376
3138
  /** Owns staged keyed intent, exact transitions and published collection state. */
2377
- const createCollectionOutput = () => {
3139
+ const createCollectionOutput = (binding) => {
2378
3140
  const published = createPublishedCollection();
2379
3141
  let staged = /* @__PURE__ */ new Map();
2380
3142
  let nextIds = published.ids();
@@ -2385,6 +3147,7 @@ const createCollectionOutput = () => {
2385
3147
  let explicitOrder;
2386
3148
  let cleared = false;
2387
3149
  const listeners = /* @__PURE__ */ new Set();
3150
+ const consumers = /* @__PURE__ */ new Set();
2388
3151
  const hasNext = (key) => staged.has(key) ? staged.get(key).present : !cleared && published.has(key);
2389
3152
  const getNext = (key) => {
2390
3153
  const entry = staged.get(key);
@@ -2404,15 +3167,15 @@ const createCollectionOutput = () => {
2404
3167
  reset = initialize;
2405
3168
  const read = (next) => ({
2406
3169
  get: (key) => {
2407
- require_advanced.assertScope(active);
3170
+ require_scheduler.assertScope(active);
2408
3171
  return next ? getNext(key) : published.get(key);
2409
3172
  },
2410
3173
  has: (key) => {
2411
- require_advanced.assertScope(active);
3174
+ require_scheduler.assertScope(active);
2412
3175
  return next ? hasNext(key) : published.has(key);
2413
3176
  },
2414
3177
  ids: () => {
2415
- require_advanced.assertScope(active);
3178
+ require_scheduler.assertScope(active);
2416
3179
  return next ? Object.freeze(explicitOrder ? [...explicitOrder] : [...deriveIds()]) : published.ids();
2417
3180
  }
2418
3181
  });
@@ -2421,7 +3184,7 @@ const createCollectionOutput = () => {
2421
3184
  next: read(true),
2422
3185
  output: {
2423
3186
  set: (key, value) => {
2424
- require_advanced.assertScope(active);
3187
+ require_scheduler.assertScope(active);
2425
3188
  if (typeof key !== "string") throw new TypeError("Projection keys must be strings.");
2426
3189
  staged.set(key, {
2427
3190
  present: true,
@@ -2429,11 +3192,11 @@ const createCollectionOutput = () => {
2429
3192
  });
2430
3193
  },
2431
3194
  remove: (key) => {
2432
- require_advanced.assertScope(active);
3195
+ require_scheduler.assertScope(active);
2433
3196
  staged.set(key, { present: false });
2434
3197
  },
2435
3198
  order: (order) => {
2436
- require_advanced.assertScope(active);
3199
+ require_scheduler.assertScope(active);
2437
3200
  explicitOrder = Object.freeze([...order]);
2438
3201
  }
2439
3202
  }
@@ -2443,7 +3206,7 @@ const createCollectionOutput = () => {
2443
3206
  if (cleared) {
2444
3207
  for (const key of published.keys()) if (!staged.has(key)) staged.set(key, { present: false });
2445
3208
  }
2446
- require_advanced.profile.projection("touchedKeys", staged.size);
3209
+ require_scheduler.profile.projection("touchedKeys", staged.size);
2447
3210
  const added = /* @__PURE__ */ new Set();
2448
3211
  const removed = /* @__PURE__ */ new Set();
2449
3212
  const updated = /* @__PURE__ */ new Set();
@@ -2462,12 +3225,11 @@ const createCollectionOutput = () => {
2462
3225
  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
3226
  nextIds = ids.length === order.length && ids.every((key, index) => key === order[index]) ? ids : Object.freeze([...order]);
2464
3227
  } else nextIds = ids;
2465
- const changedKeys = new Set([
2466
- ...added,
2467
- ...removed,
2468
- ...updated
2469
- ]);
2470
- require_advanced.profile.projection("changedKeys", changedKeys.size);
3228
+ const changedKeys = /* @__PURE__ */ new Set();
3229
+ added.forEach((key) => changedKeys.add(key));
3230
+ removed.forEach((key) => changedKeys.add(key));
3231
+ updated.forEach((key) => changedKeys.add(key));
3232
+ require_scheduler.profile.projection("changedKeys", changedKeys.size);
2471
3233
  const addedEntries = [];
2472
3234
  const updatedEntries = [];
2473
3235
  const removedEntries = [];
@@ -2475,7 +3237,8 @@ const createCollectionOutput = () => {
2475
3237
  const beforePresent = published.has(key);
2476
3238
  const afterPresent = hasNext(key);
2477
3239
  if (beforePresent === afterPresent) {
2478
- if (!beforePresent || isEqual(published.get(key), getNext(key))) continue;
3240
+ if (!beforePresent) continue;
3241
+ if (isEqual !== Object.is && isEqual(published.get(key), getNext(key))) continue;
2479
3242
  }
2480
3243
  if (!beforePresent) addedEntries.push({
2481
3244
  key,
@@ -2505,15 +3268,15 @@ const createCollectionOutput = () => {
2505
3268
  kind: "collection",
2506
3269
  read: {
2507
3270
  get: (key) => {
2508
- require_advanced.assertScope(active);
3271
+ require_scheduler.assertScope(active);
2509
3272
  return getNext(key);
2510
3273
  },
2511
3274
  has: (key) => {
2512
- require_advanced.assertScope(active);
3275
+ require_scheduler.assertScope(active);
2513
3276
  return hasNext(key);
2514
3277
  },
2515
3278
  ids: () => {
2516
- require_advanced.assertScope(active);
3279
+ require_scheduler.assertScope(active);
2517
3280
  return nextIds;
2518
3281
  }
2519
3282
  },
@@ -2523,10 +3286,14 @@ const createCollectionOutput = () => {
2523
3286
  cause
2524
3287
  });
2525
3288
  return {
3289
+ kind: "collection",
3290
+ get owner() {
3291
+ return binding.owner();
3292
+ },
2526
3293
  begin,
2527
3294
  seal,
2528
- context,
2529
- current: (check) => published.read(check),
3295
+ context: (active) => context(active, binding.cause()),
3296
+ current: () => published.read(binding.check),
2530
3297
  revision: () => revision,
2531
3298
  reset: () => reset,
2532
3299
  publish: () => {
@@ -2535,9 +3302,12 @@ const createCollectionOutput = () => {
2535
3302
  initialized = true;
2536
3303
  },
2537
3304
  emit: (call) => {
2538
- const resetEvent = Object.freeze({ kind: "reset" });
2539
- Array.from(listeners).forEach((listener) => call(() => listener(change ?? resetEvent)));
3305
+ Array.from(listeners).forEach((listener) => call(listener));
2540
3306
  },
3307
+ hasConsumers: () => consumers.size > 0,
3308
+ forEachConsumer: (run) => consumers.forEach(run),
3309
+ attachConsumer: (consumer) => consumers.add(consumer),
3310
+ detachConsumer: (consumer) => consumers.delete(consumer),
2541
3311
  clear: () => {
2542
3312
  staged.clear();
2543
3313
  nextIds = published.ids();
@@ -2550,6 +3320,7 @@ const createCollectionOutput = () => {
2550
3320
  published.release();
2551
3321
  staged.clear();
2552
3322
  listeners.clear();
3323
+ consumers.clear();
2553
3324
  nextIds = Object.freeze([]);
2554
3325
  change = void 0;
2555
3326
  initialized = false;
@@ -2558,15 +3329,18 @@ const createCollectionOutput = () => {
2558
3329
  explicitOrder = void 0;
2559
3330
  cleared = false;
2560
3331
  },
2561
- subscribe: (listener) => listeners.add(listener),
2562
- unsubscribe: (listener) => listeners.delete(listener)
3332
+ subscribe: (listener) => {
3333
+ binding.check();
3334
+ listeners.add(listener);
3335
+ return () => listeners.delete(listener);
3336
+ }
2563
3337
  };
2564
3338
  };
2565
3339
  //#endregion
2566
3340
  //#region core/src/projection/output/value.ts
2567
3341
  const unset = Symbol("projection-value-unset");
2568
3342
  /** Owns staged and published state for one scalar Projection output. */
2569
- const createValueOutput = () => {
3343
+ const createValueOutput = (binding) => {
2570
3344
  let value;
2571
3345
  let staged = unset;
2572
3346
  let next;
@@ -2575,6 +3349,7 @@ const createValueOutput = () => {
2575
3349
  let changed = false;
2576
3350
  let reset = false;
2577
3351
  const listeners = /* @__PURE__ */ new Set();
3352
+ const consumers = /* @__PURE__ */ new Set();
2578
3353
  const begin = (active, initialize) => {
2579
3354
  staged = unset;
2580
3355
  next = value;
@@ -2583,12 +3358,12 @@ const createValueOutput = () => {
2583
3358
  return {
2584
3359
  previous: initialized ? value : void 0,
2585
3360
  next: () => {
2586
- require_advanced.assertScope(active);
3361
+ require_scheduler.assertScope(active);
2587
3362
  if (staged !== unset) return staged;
2588
3363
  return initialize ? void 0 : initialized ? value : void 0;
2589
3364
  },
2590
3365
  output: Object.freeze({ set: (candidate) => {
2591
- require_advanced.assertScope(active);
3366
+ require_scheduler.assertScope(active);
2592
3367
  staged = candidate;
2593
3368
  } })
2594
3369
  };
@@ -2608,20 +3383,24 @@ const createValueOutput = () => {
2608
3383
  return changed;
2609
3384
  };
2610
3385
  return {
3386
+ kind: "value",
3387
+ get owner() {
3388
+ return binding.owner();
3389
+ },
2611
3390
  begin,
2612
3391
  seal,
2613
- context: (active, cause) => {
2614
- require_advanced.assertScope(active);
3392
+ context: (active) => {
3393
+ require_scheduler.assertScope(active);
2615
3394
  return Object.freeze({
2616
3395
  kind: "value",
2617
3396
  value: next,
2618
3397
  revision,
2619
3398
  reset,
2620
- cause
3399
+ cause: binding.cause()
2621
3400
  });
2622
3401
  },
2623
- current: (check) => {
2624
- check();
3402
+ current: () => {
3403
+ binding.check();
2625
3404
  return value;
2626
3405
  },
2627
3406
  revision: () => revision,
@@ -2632,9 +3411,13 @@ const createValueOutput = () => {
2632
3411
  initialized = true;
2633
3412
  },
2634
3413
  emit: (call) => {
2635
- require_advanced.profile.materialized.notification();
3414
+ require_scheduler.profile.materialized.notification();
2636
3415
  Array.from(listeners).forEach((listener) => call(listener));
2637
3416
  },
3417
+ hasConsumers: () => consumers.size > 0,
3418
+ forEachConsumer: (run) => consumers.forEach(run),
3419
+ attachConsumer: (consumer) => consumers.add(consumer),
3420
+ detachConsumer: (consumer) => consumers.delete(consumer),
2638
3421
  clear: () => {
2639
3422
  staged = unset;
2640
3423
  next = value;
@@ -2643,6 +3426,7 @@ const createValueOutput = () => {
2643
3426
  },
2644
3427
  release: () => {
2645
3428
  listeners.clear();
3429
+ consumers.clear();
2646
3430
  staged = unset;
2647
3431
  value = next = void 0;
2648
3432
  initialized = false;
@@ -2650,8 +3434,11 @@ const createValueOutput = () => {
2650
3434
  changed = false;
2651
3435
  reset = false;
2652
3436
  },
2653
- subscribe: (listener) => listeners.add(listener),
2654
- unsubscribe: (listener) => listeners.delete(listener)
3437
+ subscribe: (listener) => {
3438
+ binding.check();
3439
+ listeners.add(listener);
3440
+ return () => listeners.delete(listener);
3441
+ }
2655
3442
  };
2656
3443
  };
2657
3444
  //#endregion
@@ -2663,63 +3450,27 @@ const createProcessor = (scheduler, definition, dependencies) => {
2663
3450
  let instance;
2664
3451
  let cause;
2665
3452
  const check = () => {
2666
- if (!scheduler.active || processor.disposed) throw new require_advanced.ProjectionDisposedError();
3453
+ if (!scheduler.active || processor.disposed) throw new require_scheduler.ProjectionDisposedError();
2667
3454
  if (processor.fault) throw processor.fault;
2668
3455
  };
2669
3456
  const bound = definition.outputs.map((outputDefinition) => {
2670
- if (outputDefinition.kind === "value") {
2671
- const state = createValueOutput();
2672
- return {
2673
- kind: "value",
2674
- definition: outputDefinition,
2675
- state,
2676
- output: {
2677
- kind: "value",
2678
- get owner() {
2679
- return processor;
2680
- },
2681
- consumers: /* @__PURE__ */ new Set(),
2682
- context: (active) => state.context(active, cause),
2683
- current: () => state.current(check),
2684
- revision: state.revision,
2685
- reset: state.reset,
2686
- subscribe: (listener) => {
2687
- check();
2688
- const wrapped = () => listener();
2689
- state.subscribe(wrapped);
2690
- return () => state.unsubscribe(wrapped);
2691
- },
2692
- emit: state.emit,
2693
- clear: state.clear,
2694
- release: state.release
2695
- }
2696
- };
2697
- }
2698
- const state = createCollectionOutput();
3457
+ if (outputDefinition.kind === "value") return {
3458
+ kind: "value",
3459
+ definition: outputDefinition,
3460
+ state: createValueOutput({
3461
+ owner: () => processor,
3462
+ check,
3463
+ cause: () => cause
3464
+ })
3465
+ };
2699
3466
  return {
2700
3467
  kind: "collection",
2701
3468
  definition: outputDefinition,
2702
- state,
2703
- output: {
2704
- kind: "collection",
2705
- get owner() {
2706
- return processor;
2707
- },
2708
- consumers: /* @__PURE__ */ new Set(),
2709
- context: (active) => state.context(active, cause),
2710
- current: () => state.current(check),
2711
- revision: state.revision,
2712
- reset: state.reset,
2713
- subscribe: (listener) => {
2714
- check();
2715
- const wrapped = (change) => listener(change);
2716
- state.subscribe(wrapped);
2717
- return () => state.unsubscribe(wrapped);
2718
- },
2719
- emit: state.emit,
2720
- clear: state.clear,
2721
- release: state.release
2722
- }
3469
+ state: createCollectionOutput({
3470
+ owner: () => processor,
3471
+ check,
3472
+ cause: () => cause
3473
+ })
2723
3474
  };
2724
3475
  });
2725
3476
  const begin = (active, initialize) => Object.freeze(bound.map((entry) => {
@@ -2738,40 +3489,28 @@ const createProcessor = (scheduler, definition, dependencies) => {
2738
3489
  }));
2739
3490
  const seal = (reset) => {
2740
3491
  const changed = [];
2741
- for (const entry of bound) if (entry.state.seal(reset, entry.definition.equality)) changed.push(entry.output);
3492
+ for (const entry of bound) if (entry.state.seal(reset, entry.definition.equality)) changed.push(entry.state);
2742
3493
  return Object.freeze(changed);
2743
3494
  };
2744
- const run = (reset, runCause) => {
3495
+ const run = (reset, runCause, recreate = false) => {
2745
3496
  cause = runCause;
2746
3497
  let active = true;
2747
3498
  try {
2748
3499
  const scopeActive = () => active;
2749
3500
  const sources = Object.freeze(dependencies.map((output) => output.context(scopeActive)));
2750
- let outputs = begin(scopeActive, reset);
3501
+ const outputs = begin(scopeActive, reset);
3502
+ if (recreate && instance) {
3503
+ instance.release?.();
3504
+ instance = void 0;
3505
+ }
2751
3506
  if (!instance) instance = definition.create();
2752
- require_advanced.profile.materialized[reset ? "rebuilt" : "updated"]();
2753
- let result = instance.evaluate({
3507
+ require_scheduler.profile.materialized[reset ? "rebuilt" : "updated"]();
3508
+ require_scheduler.assertSynchronous(instance.evaluate({
2754
3509
  reset,
2755
3510
  cause: runCause,
2756
3511
  sources,
2757
3512
  outputs
2758
- });
2759
- require_advanced.assertSynchronous(result);
2760
- if (result?.kind === "rebuild") {
2761
- if (reset) throw new TypeError("Initial or reset projection processor cannot rebuild.");
2762
- instance.release?.();
2763
- instance = definition.create();
2764
- outputs = begin(scopeActive, true);
2765
- result = instance.evaluate({
2766
- reset: true,
2767
- cause: runCause,
2768
- sources,
2769
- outputs
2770
- });
2771
- require_advanced.assertSynchronous(result);
2772
- if (result?.kind === "rebuild") throw new TypeError("Reset projection processor cannot rebuild again.");
2773
- return seal(true);
2774
- }
3513
+ }));
2775
3514
  return seal(reset);
2776
3515
  } finally {
2777
3516
  active = false;
@@ -2783,7 +3522,7 @@ const createProcessor = (scheduler, definition, dependencies) => {
2783
3522
  order,
2784
3523
  name: definition.name ? `${definition.name} (${order})` : `projection-${order}`,
2785
3524
  dependencies: Object.freeze([...dependencies]),
2786
- outputs: Object.freeze(bound.map((entry) => entry.output)),
3525
+ outputs: Object.freeze(bound.map((entry) => entry.state)),
2787
3526
  fault: void 0,
2788
3527
  disposed: false,
2789
3528
  evaluate: run,
@@ -2793,27 +3532,38 @@ const createProcessor = (scheduler, definition, dependencies) => {
2793
3532
  cause = void 0;
2794
3533
  },
2795
3534
  release: () => {
2796
- instance?.release?.();
3535
+ const current = instance;
2797
3536
  instance = void 0;
2798
- bound.forEach((entry) => {
2799
- entry.output.consumers.clear();
3537
+ const failures = [];
3538
+ try {
3539
+ current?.release?.();
3540
+ } catch (error) {
3541
+ failures.push(error);
3542
+ }
3543
+ for (const entry of bound) try {
2800
3544
  entry.state.release();
2801
- });
3545
+ } catch (error) {
3546
+ failures.push(error);
3547
+ }
2802
3548
  cause = void 0;
3549
+ if (failures.length) throw failures[0];
2803
3550
  }
2804
3551
  };
2805
3552
  try {
2806
3553
  scheduler.initialize(() => {
2807
3554
  const invalid = dependencies.find((output) => output.owner.fault || output.owner.disposed);
2808
- if (invalid) throw invalid.owner.fault ?? new require_advanced.ProjectionDisposedError();
3555
+ if (invalid) throw invalid.owner.fault ?? new require_scheduler.ProjectionDisposedError();
2809
3556
  if (processor.evaluate(true, void 0).length) processor.publish();
2810
3557
  processor.clear();
2811
3558
  });
3559
+ scheduler.addProcessor(processor);
2812
3560
  } catch (error) {
2813
- processor.release();
3561
+ processor.disposed = true;
3562
+ try {
3563
+ processor.release();
3564
+ } catch {}
2814
3565
  throw error;
2815
3566
  }
2816
- scheduler.addProcessor(processor);
2817
3567
  return processor;
2818
3568
  };
2819
3569
  //#endregion
@@ -2979,57 +3729,11 @@ const createSelectorReadable = (source, selector, equality = Object.is) => {
2979
3729
  };
2980
3730
  //#endregion
2981
3731
  //#region core/src/projection/source/materialization.ts
2982
- const createDocumentDirty = () => ({
2983
- replace: false,
2984
- order: false,
2985
- treeRoot: false,
2986
- treeNodes: /* @__PURE__ */ new Set(),
2987
- children: /* @__PURE__ */ new Map()
2988
- });
2989
- const clearDocumentDirty = (dirty) => {
2990
- dirty.replace = false;
2991
- dirty.order = false;
2992
- dirty.treeRoot = false;
2993
- dirty.treeNodes.clear();
2994
- dirty.children.clear();
2995
- };
2996
3732
  const hasDocumentDirty = (dirty) => dirty.replace || dirty.order || dirty.treeRoot || dirty.treeNodes.size > 0 || dirty.children.size > 0;
2997
- const locate = (dirty, path) => {
2998
- let current = dirty;
2999
- for (const key of path) {
3000
- if (current.replace) return void 0;
3001
- let child = current.children.get(key);
3002
- if (!child) {
3003
- child = createDocumentDirty();
3004
- current.children.set(key, child);
3005
- }
3006
- current = child;
3007
- }
3008
- return current;
3009
- };
3010
- const markDocumentReplace = (dirty, path) => {
3011
- const current = locate(dirty, path);
3012
- if (!current) return;
3013
- current.replace = true;
3014
- current.order = false;
3015
- current.treeRoot = false;
3016
- current.treeNodes.clear();
3017
- current.children.clear();
3018
- };
3019
- const markDocumentOrder = (dirty, path) => {
3020
- const current = locate(dirty, path);
3021
- if (current && !current.replace) current.order = true;
3022
- };
3023
- const markDocumentTree = (dirty, path, root, nodes) => {
3024
- const current = locate(dirty, path);
3025
- if (!current || current.replace) return;
3026
- current.treeRoot ||= root;
3027
- for (const id of nodes) current.treeNodes.add(id);
3028
- };
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);
3733
+ const equivalent = (node, left, right) => node.kind === "field" ? Object.is(left, right) : equalValue(node, left, right);
3734
+ const replaceValue = (node, previous, current) => equivalent(node, previous, current) ? previous : copyValue(node, current);
3031
3735
  const cloneRecord = (value) => {
3032
- require_advanced.profile.copy.shallowRecord(Object.getOwnPropertyNames(value).length);
3736
+ require_scheduler.profile.copy.shallowRecord(Object.getOwnPropertyNames(value).length);
3033
3737
  return Object.create(Object.getPrototypeOf(value), Object.getOwnPropertyDescriptors(value));
3034
3738
  };
3035
3739
  const materializeRecordChild = (node, previous, current, key, dirty) => {
@@ -3041,7 +3745,7 @@ const materializeRecordChild = (node, previous, current, key, dirty) => {
3041
3745
  present: false,
3042
3746
  value: void 0
3043
3747
  };
3044
- const next = before ? materializeDocumentValue(node, previous[key], current[key], dirty) : require_advanced.copyValue(node, current[key]);
3748
+ const next = before ? materializeDocumentValue(node, previous[key], current[key], dirty) : copyValue(node, current[key]);
3045
3749
  if (before && next === previous[key]) return { changed: false };
3046
3750
  return {
3047
3751
  changed: true,
@@ -3051,7 +3755,7 @@ const materializeRecordChild = (node, previous, current, key, dirty) => {
3051
3755
  };
3052
3756
  const materializeObject = (node, previous, current, dirty) => {
3053
3757
  if (node.kind === "variant" && previous[node.tag] !== current[node.tag]) return replaceValue(node, previous, current);
3054
- const layout = require_advanced.compiledShape(node, current);
3758
+ const layout = compiledShape(node, current);
3055
3759
  if (!layout) return replaceValue(node, previous, current);
3056
3760
  let result;
3057
3761
  for (const [key, childDirty] of dirty.children) {
@@ -3060,7 +3764,7 @@ const materializeObject = (node, previous, current, dirty) => {
3060
3764
  const child = materializeRecordChild(member.node, previous, current, key, childDirty);
3061
3765
  if (!child.changed) continue;
3062
3766
  result ??= cloneRecord(previous);
3063
- require_context.installOwn(result, key, child.present, child.value);
3767
+ require_record.installOwn(result, key, child.present, child.value);
3064
3768
  }
3065
3769
  return result ?? previous;
3066
3770
  };
@@ -3070,12 +3774,12 @@ const materializeMap = (node, previous, current, dirty) => {
3070
3774
  const child = materializeRecordChild(node.value, previous, current, key, childDirty);
3071
3775
  if (!child.changed) continue;
3072
3776
  result ??= cloneRecord(previous);
3073
- require_context.installOwn(result, key, child.present, child.value);
3777
+ require_record.installOwn(result, key, child.present, child.value);
3074
3778
  }
3075
3779
  return result ?? previous;
3076
3780
  };
3077
3781
  const materializeTable = (node, previous, current, dirty) => {
3078
- if (!require_context.isRecord(previous.byId) || !require_context.isRecord(current.byId)) return replaceValue(node, previous, current);
3782
+ if (!require_record.isRecord(previous.byId) || !require_record.isRecord(current.byId)) return replaceValue(node, previous, current);
3079
3783
  const beforeById = previous.byId;
3080
3784
  const afterById = current.byId;
3081
3785
  let result;
@@ -3084,28 +3788,28 @@ const materializeTable = (node, previous, current, dirty) => {
3084
3788
  const child = materializeRecordChild(node.value, beforeById, afterById, key, childDirty);
3085
3789
  if (!child.changed) continue;
3086
3790
  nextById ??= cloneRecord(beforeById);
3087
- require_context.installOwn(nextById, key, child.present, child.value);
3791
+ require_record.installOwn(nextById, key, child.present, child.value);
3088
3792
  }
3089
3793
  if (nextById) {
3090
3794
  result = cloneRecord(previous);
3091
- require_context.installOwn(result, "byId", true, nextById);
3795
+ require_record.installOwn(result, "byId", true, nextById);
3092
3796
  }
3093
3797
  if (dirty.order) {
3094
3798
  const beforeIds = previous.ids;
3095
3799
  const afterIds = current.ids;
3096
3800
  if (!Array.isArray(beforeIds) || !Array.isArray(afterIds)) return replaceValue(node, previous, current);
3097
- if (!require_advanced.equal(beforeIds, afterIds)) {
3801
+ if (!equal(beforeIds, afterIds)) {
3098
3802
  result ??= cloneRecord(previous);
3099
- require_context.installOwn(result, "ids", true, [...afterIds]);
3803
+ require_record.installOwn(result, "ids", true, [...afterIds]);
3100
3804
  }
3101
3805
  }
3102
3806
  return result ?? previous;
3103
3807
  };
3104
3808
  const materializeList = (node, previous, current, dirty) => {
3105
3809
  if (dirty.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);
3810
+ const before = listSequence(previous, node.keyOf);
3811
+ const after = listSequence(current, node.keyOf);
3812
+ let changed = !equal(before.order, after.order);
3109
3813
  const result = new Array(after.order.length);
3110
3814
  for (let index = 0; index < after.order.length; index++) {
3111
3815
  const key = after.order[index];
@@ -3124,8 +3828,8 @@ const materializeList = (node, previous, current, dirty) => {
3124
3828
  return changed ? result : previous;
3125
3829
  }
3126
3830
  let result;
3127
- const before = require_advanced.indexedKeys(previous, node.keyOf);
3128
- const after = require_advanced.indexedKeys(current, node.keyOf);
3831
+ const before = indexedKeys(previous, node.keyOf);
3832
+ const after = indexedKeys(current, node.keyOf);
3129
3833
  for (const [key, childDirty] of dirty.children) {
3130
3834
  const previousIndex = before.index(key);
3131
3835
  const currentIndex = after.index(key);
@@ -3138,14 +3842,14 @@ const materializeList = (node, previous, current, dirty) => {
3138
3842
  return result ?? previous;
3139
3843
  };
3140
3844
  const materializeTree = (node, previous, current, dirty) => {
3141
- if (!require_context.isRecord(previous.nodes) || !require_context.isRecord(current.nodes)) return replaceValue(node, previous, current);
3845
+ if (!require_record.isRecord(previous.nodes) || !require_record.isRecord(current.nodes)) return replaceValue(node, previous, current);
3142
3846
  let result;
3143
3847
  if (dirty.treeRoot) {
3144
3848
  const beforePresent = Object.hasOwn(previous, "rootId");
3145
3849
  const afterPresent = Object.hasOwn(current, "rootId");
3146
3850
  if (beforePresent !== afterPresent || !Object.is(previous.rootId, current.rootId)) {
3147
3851
  result = cloneRecord(previous);
3148
- require_context.installOwn(result, "rootId", afterPresent, current.rootId);
3852
+ require_record.installOwn(result, "rootId", afterPresent, current.rootId);
3149
3853
  }
3150
3854
  }
3151
3855
  let nodes;
@@ -3154,13 +3858,13 @@ const materializeTree = (node, previous, current, dirty) => {
3154
3858
  const afterPresent = Object.hasOwn(current.nodes, id);
3155
3859
  const before = beforePresent ? previous.nodes[id] : void 0;
3156
3860
  const after = afterPresent ? current.nodes[id] : void 0;
3157
- if (beforePresent === afterPresent && require_advanced.equalTreeNode(before, after)) continue;
3861
+ if (beforePresent === afterPresent && equalTreeNode(before, after)) continue;
3158
3862
  nodes ??= cloneRecord(previous.nodes);
3159
- require_context.installOwn(nodes, id, afterPresent, after && require_advanced.copyTreeNode(after));
3863
+ require_record.installOwn(nodes, id, afterPresent, after && copyTreeNode(after));
3160
3864
  }
3161
3865
  if (nodes) {
3162
3866
  result ??= cloneRecord(previous);
3163
- require_context.installOwn(result, "nodes", true, nodes);
3867
+ require_record.installOwn(result, "nodes", true, nodes);
3164
3868
  }
3165
3869
  return result ?? previous;
3166
3870
  };
@@ -3168,26 +3872,72 @@ const materializeDocumentValue = (node, previous, current, dirty) => {
3168
3872
  if (!hasDocumentDirty(dirty)) return previous;
3169
3873
  if (dirty.replace || previous === void 0 || current === void 0 || node.kind === "field") return replaceValue(node, previous, current);
3170
3874
  if (node.kind === "object" || node.kind === "variant") {
3171
- if (!require_context.isRecord(previous) || !require_context.isRecord(current)) return replaceValue(node, previous, current);
3875
+ if (!require_record.isRecord(previous) || !require_record.isRecord(current)) return replaceValue(node, previous, current);
3172
3876
  return materializeObject(node, previous, current, dirty);
3173
3877
  }
3174
3878
  if (node.kind === "map") {
3175
- if (!require_context.isRecord(previous) || !require_context.isRecord(current)) return replaceValue(node, previous, current);
3879
+ if (!require_record.isRecord(previous) || !require_record.isRecord(current)) return replaceValue(node, previous, current);
3176
3880
  return materializeMap(node, previous, current, dirty);
3177
3881
  }
3178
3882
  if (node.kind === "table") {
3179
- if (!require_context.isRecord(previous) || !require_context.isRecord(current)) return replaceValue(node, previous, current);
3883
+ if (!require_record.isRecord(previous) || !require_record.isRecord(current)) return replaceValue(node, previous, current);
3180
3884
  return materializeTable(node, previous, current, dirty);
3181
3885
  }
3182
3886
  if (node.kind === "list") {
3183
3887
  if (!Array.isArray(previous) || !Array.isArray(current)) return replaceValue(node, previous, current);
3184
3888
  return materializeList(node, previous, current, dirty);
3185
3889
  }
3186
- if (!require_context.isRecord(previous) || !require_context.isRecord(current)) return replaceValue(node, previous, current);
3890
+ if (!require_record.isRecord(previous) || !require_record.isRecord(current)) return replaceValue(node, previous, current);
3187
3891
  return materializeTree(node, previous, current, dirty);
3188
3892
  };
3189
3893
  //#endregion
3190
3894
  //#region core/src/projection/source/dirty.ts
3895
+ const createDocumentDirty = () => ({
3896
+ replace: false,
3897
+ order: false,
3898
+ treeRoot: false,
3899
+ treeNodes: /* @__PURE__ */ new Set(),
3900
+ children: /* @__PURE__ */ new Map()
3901
+ });
3902
+ const clearDocumentDirty = (dirty) => {
3903
+ dirty.replace = false;
3904
+ dirty.order = false;
3905
+ dirty.treeRoot = false;
3906
+ dirty.treeNodes.clear();
3907
+ dirty.children.clear();
3908
+ };
3909
+ const locate = (dirty, path) => {
3910
+ let current = dirty;
3911
+ for (const key of path) {
3912
+ if (current.replace) return void 0;
3913
+ let child = current.children.get(key);
3914
+ if (!child) {
3915
+ child = createDocumentDirty();
3916
+ current.children.set(key, child);
3917
+ }
3918
+ current = child;
3919
+ }
3920
+ return current;
3921
+ };
3922
+ const markDocumentReplace = (dirty, path) => {
3923
+ const current = locate(dirty, path);
3924
+ if (!current) return;
3925
+ current.replace = true;
3926
+ current.order = false;
3927
+ current.treeRoot = false;
3928
+ current.treeNodes.clear();
3929
+ current.children.clear();
3930
+ };
3931
+ const markDocumentOrder = (dirty, path) => {
3932
+ const current = locate(dirty, path);
3933
+ if (current && !current.replace) current.order = true;
3934
+ };
3935
+ const markDocumentTree = (dirty, path, root, nodes) => {
3936
+ const current = locate(dirty, path);
3937
+ if (!current || current.replace) return;
3938
+ current.treeRoot ||= root;
3939
+ for (const id of nodes) current.treeNodes.add(id);
3940
+ };
3191
3941
  const createCollectionPending = () => ({
3192
3942
  reset: false,
3193
3943
  order: false,
@@ -3289,9 +4039,8 @@ const mergeCollectionChanges = (selector, pending, changes) => {
3289
4039
  };
3290
4040
  //#endregion
3291
4041
  //#region core/src/projection/source/boundary.ts
3292
- const sourceError = (source, cause) => new require_advanced.ProjectionError("source", source.name, [source.outputs[0].revision()], cause);
4042
+ const sourceError = (cause) => new require_scheduler.ProjectionError("source", cause);
3293
4043
  const createValueBoundary = (scheduler, name, initial, equality, prepare, clearSource) => {
3294
- const state = createValueOutput();
3295
4044
  let boundary;
3296
4045
  let pendingReset = false;
3297
4046
  let pendingCause;
@@ -3299,29 +4048,15 @@ const createValueBoundary = (scheduler, name, initial, equality, prepare, clearS
3299
4048
  let recovering = false;
3300
4049
  let cleanup;
3301
4050
  const check = () => {
3302
- if (!scheduler.active || boundary.disposed) throw new require_advanced.ProjectionDisposedError();
4051
+ if (!scheduler.active || boundary.disposed) throw new require_scheduler.ProjectionDisposedError();
3303
4052
  if (boundary.fault) throw boundary.fault;
3304
4053
  };
3305
- const output = {
3306
- kind: "value",
3307
- get owner() {
3308
- return boundary;
3309
- },
3310
- consumers: /* @__PURE__ */ new Set(),
3311
- context: (active) => state.context(active, contextCause),
3312
- current: () => state.current(check),
3313
- revision: state.revision,
3314
- reset: state.reset,
3315
- subscribe: (listener) => {
3316
- check();
3317
- const wrapped = () => listener();
3318
- state.subscribe(wrapped);
3319
- return () => state.unsubscribe(wrapped);
3320
- },
3321
- emit: state.emit,
3322
- clear: state.clear,
3323
- release: state.release
3324
- };
4054
+ const state = createValueOutput({
4055
+ owner: () => boundary,
4056
+ check,
4057
+ cause: () => contextCause
4058
+ });
4059
+ const output = state;
3325
4060
  boundary = {
3326
4061
  kind: "source",
3327
4062
  name,
@@ -3357,24 +4092,42 @@ const createValueBoundary = (scheduler, name, initial, equality, prepare, clearS
3357
4092
  clearSource(failed);
3358
4093
  },
3359
4094
  release: () => {
3360
- cleanup?.();
4095
+ const detach = cleanup;
3361
4096
  cleanup = void 0;
3362
- state.release();
3363
- output.consumers.clear();
4097
+ const failures = [];
4098
+ try {
4099
+ detach?.();
4100
+ } catch (error) {
4101
+ failures.push(error);
4102
+ }
4103
+ try {
4104
+ state.release();
4105
+ } catch (error) {
4106
+ failures.push(error);
4107
+ }
4108
+ if (failures.length) throw failures[0];
3364
4109
  }
3365
4110
  };
3366
- scheduler.initialize(() => {
3367
- let active = true;
4111
+ try {
4112
+ scheduler.initialize(() => {
4113
+ let active = true;
4114
+ try {
4115
+ state.begin(() => active, true).output.set(initial);
4116
+ state.seal(true, equality);
4117
+ state.publish();
4118
+ state.clear();
4119
+ } finally {
4120
+ active = false;
4121
+ }
4122
+ });
4123
+ scheduler.addSource(boundary);
4124
+ } catch (error) {
4125
+ boundary.disposed = true;
3368
4126
  try {
3369
- state.begin(() => active, true).output.set(initial);
3370
- state.seal(true, equality);
3371
- state.publish();
3372
- state.clear();
3373
- } finally {
3374
- active = false;
3375
- }
3376
- });
3377
- scheduler.addSource(boundary);
4127
+ boundary.release();
4128
+ } catch {}
4129
+ throw error;
4130
+ }
3378
4131
  const mark = (metadata = {}) => {
3379
4132
  scheduler.assertIdle();
3380
4133
  pendingReset ||= metadata.reset ?? false;
@@ -3383,7 +4136,7 @@ const createValueBoundary = (scheduler, name, initial, equality, prepare, clearS
3383
4136
  scheduler.capture(boundary);
3384
4137
  };
3385
4138
  const fail = (cause) => {
3386
- boundary.fault = sourceError(boundary, cause);
4139
+ boundary.fault = sourceError(cause);
3387
4140
  recovering = false;
3388
4141
  scheduler.capture(boundary);
3389
4142
  };
@@ -3402,30 +4155,29 @@ const stageCollectionRead = (state, read, active, options) => {
3402
4155
  const evaluation = state.begin(active, options.reset);
3403
4156
  if (options.reset) {
3404
4157
  const ids = read.ids();
3405
- require_advanced.profile.collectionView.idsScanned(ids.length);
4158
+ require_scheduler.profile.collectionView.idsScanned(ids.length);
3406
4159
  for (const key of ids) {
3407
- require_advanced.profile.collectionView.mapped();
4160
+ require_scheduler.profile.collectionView.mapped();
3408
4161
  evaluation.output.set(key, read.get(key));
3409
4162
  }
3410
4163
  evaluation.output.order(ids);
3411
4164
  } else {
3412
- const previous = state.current(() => void 0);
4165
+ const previous = state.current();
3413
4166
  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);
4167
+ if (!options.candidates) require_scheduler.profile.collectionView.idsScanned(keys.length);
3415
4168
  for (const key of keys) if (read.has(key)) {
3416
- require_advanced.profile.collectionView.mapped();
4169
+ require_scheduler.profile.collectionView.mapped();
3417
4170
  evaluation.output.set(key, read.get(key));
3418
4171
  } else evaluation.output.remove(key);
3419
4172
  if (options.orderMayChange || !options.candidates) {
3420
4173
  const ids = read.ids();
3421
- if (options.candidates) require_advanced.profile.collectionView.idsScanned(ids.length);
4174
+ if (options.candidates) require_scheduler.profile.collectionView.idsScanned(ids.length);
3422
4175
  evaluation.output.order(ids);
3423
4176
  }
3424
4177
  }
3425
4178
  return state.seal(options.reset, options.isEqual ?? Object.is);
3426
4179
  };
3427
4180
  const createCollectionBoundary = (scheduler, name, readLatest, equality, clearSource) => {
3428
- const state = createCollectionOutput();
3429
4181
  let boundary;
3430
4182
  let pendingReset = false;
3431
4183
  let pendingCause;
@@ -3436,29 +4188,15 @@ const createCollectionBoundary = (scheduler, name, readLatest, equality, clearSo
3436
4188
  const candidates = /* @__PURE__ */ new Set();
3437
4189
  let cleanup;
3438
4190
  const check = () => {
3439
- if (!scheduler.active || boundary.disposed) throw new require_advanced.ProjectionDisposedError();
4191
+ if (!scheduler.active || boundary.disposed) throw new require_scheduler.ProjectionDisposedError();
3440
4192
  if (boundary.fault) throw boundary.fault;
3441
4193
  };
3442
- const output = {
3443
- kind: "collection",
3444
- get owner() {
3445
- return boundary;
3446
- },
3447
- consumers: /* @__PURE__ */ new Set(),
3448
- context: (active) => state.context(active, contextCause),
3449
- current: () => state.current(check),
3450
- revision: state.revision,
3451
- reset: state.reset,
3452
- subscribe: (listener) => {
3453
- check();
3454
- const wrapped = (change) => listener(change);
3455
- state.subscribe(wrapped);
3456
- return () => state.unsubscribe(wrapped);
3457
- },
3458
- emit: state.emit,
3459
- clear: state.clear,
3460
- release: state.release
3461
- };
4194
+ const state = createCollectionOutput({
4195
+ owner: () => boundary,
4196
+ check,
4197
+ cause: () => contextCause
4198
+ });
4199
+ const output = state;
3462
4200
  boundary = {
3463
4201
  kind: "source",
3464
4202
  name,
@@ -3471,7 +4209,7 @@ const createCollectionBoundary = (scheduler, name, readLatest, equality, clearSo
3471
4209
  contextCause = cause;
3472
4210
  let active = true;
3473
4211
  try {
3474
- const changed = stageCollectionRead(state, readLatest(() => active, state.current(() => void 0)), () => active, {
4212
+ const changed = stageCollectionRead(state, readLatest(() => active, state.current()), () => active, {
3475
4213
  reset: pendingReset,
3476
4214
  ...fullScan ? {} : { candidates },
3477
4215
  orderMayChange,
@@ -3500,26 +4238,44 @@ const createCollectionBoundary = (scheduler, name, readLatest, equality, clearSo
3500
4238
  clearSource(failed);
3501
4239
  },
3502
4240
  release: () => {
3503
- cleanup?.();
4241
+ const detach = cleanup;
3504
4242
  cleanup = void 0;
3505
- state.release();
3506
- output.consumers.clear();
4243
+ const failures = [];
4244
+ try {
4245
+ detach?.();
4246
+ } catch (error) {
4247
+ failures.push(error);
4248
+ }
4249
+ try {
4250
+ state.release();
4251
+ } catch (error) {
4252
+ failures.push(error);
4253
+ }
4254
+ if (failures.length) throw failures[0];
3507
4255
  }
3508
4256
  };
3509
- scheduler.initialize(() => {
3510
- let active = true;
4257
+ try {
4258
+ scheduler.initialize(() => {
4259
+ let active = true;
4260
+ try {
4261
+ stageCollectionRead(state, readLatest(() => active, state.current()), () => active, {
4262
+ reset: true,
4263
+ isEqual: equality
4264
+ });
4265
+ state.publish();
4266
+ state.clear();
4267
+ } finally {
4268
+ active = false;
4269
+ }
4270
+ });
4271
+ scheduler.addSource(boundary);
4272
+ } catch (error) {
4273
+ boundary.disposed = true;
3511
4274
  try {
3512
- stageCollectionRead(state, readLatest(() => active, state.current(() => void 0)), () => active, {
3513
- reset: true,
3514
- isEqual: equality
3515
- });
3516
- state.publish();
3517
- state.clear();
3518
- } finally {
3519
- active = false;
3520
- }
3521
- });
3522
- scheduler.addSource(boundary);
4275
+ boundary.release();
4276
+ } catch {}
4277
+ throw error;
4278
+ }
3523
4279
  const mark = (metadata = {}) => {
3524
4280
  scheduler.assertIdle();
3525
4281
  pendingReset ||= metadata.reset ?? false;
@@ -3531,7 +4287,7 @@ const createCollectionBoundary = (scheduler, name, readLatest, equality, clearSo
3531
4287
  scheduler.capture(boundary);
3532
4288
  };
3533
4289
  const fail = (cause) => {
3534
- boundary.fault = sourceError(boundary, cause);
4290
+ boundary.fault = sourceError(cause);
3535
4291
  recovering = false;
3536
4292
  scheduler.capture(boundary);
3537
4293
  };
@@ -3554,7 +4310,7 @@ const documentRootTarget = Object.freeze({
3554
4310
  const createDocumentSourceRegistry = (scheduler) => {
3555
4311
  const documents = /* @__PURE__ */ new Map();
3556
4312
  const connection = (runtime) => {
3557
- const context = require_context.contextOf(runtime);
4313
+ const context = require_driver.contextOf(runtime);
3558
4314
  const state = context.state;
3559
4315
  const cached = documents.get(state);
3560
4316
  if (cached) return cached;
@@ -3565,14 +4321,19 @@ const createDocumentSourceRegistry = (scheduler) => {
3565
4321
  const guard = (locked) => {
3566
4322
  state.projectionLocks += locked ? 1 : -1;
3567
4323
  };
3568
- scheduler.guards.add(guard);
4324
+ let unregisterGuard = scheduler.registerGuard(guard);
3569
4325
  let closed = false;
3570
- let detach = () => void 0;
4326
+ let detach;
3571
4327
  const documentConnection = {
3572
4328
  add(binding) {
3573
4329
  if (closed) throw new Error("Document projection connection is closed.");
3574
4330
  bindings.add(binding);
3575
- index.add(binding.target, binding);
4331
+ try {
4332
+ index.add(binding.target, binding);
4333
+ } catch (error) {
4334
+ bindings.delete(binding);
4335
+ throw error;
4336
+ }
3576
4337
  let active = true;
3577
4338
  return () => {
3578
4339
  if (!active) return;
@@ -3585,34 +4346,65 @@ const createDocumentSourceRegistry = (scheduler) => {
3585
4346
  close() {
3586
4347
  if (closed) return;
3587
4348
  closed = true;
3588
- detach();
4349
+ const stopNotifications = detach;
4350
+ detach = void 0;
4351
+ const stopGuard = unregisterGuard;
4352
+ unregisterGuard = () => void 0;
3589
4353
  bindings.clear();
3590
4354
  candidates.clear();
3591
4355
  index.clear();
3592
- scheduler.guards.delete(guard);
3593
4356
  documents.delete(state);
4357
+ const failures = [];
4358
+ try {
4359
+ stopNotifications?.();
4360
+ } catch (error) {
4361
+ failures.push(error);
4362
+ }
4363
+ try {
4364
+ stopGuard();
4365
+ } catch (error) {
4366
+ failures.push(error);
4367
+ }
4368
+ if (failures.length) throw failures[0];
3594
4369
  }
3595
4370
  };
3596
- detach = context.notifications.attachProjection({
3597
- capture: (commit) => {
3598
- candidates.clear();
3599
- index.collect(commit.changes, (binding) => candidates.add(binding));
3600
- candidates.forEach((binding) => binding.capture(commit));
3601
- },
3602
- settle: scheduler.settle,
3603
- flush: scheduler.flush,
3604
- dispose: () => {
3605
- for (const binding of bindings) binding.dispose();
3606
- scheduler.run();
3607
- }
3608
- });
4371
+ try {
4372
+ detach = context.notifications.attachProjection({
4373
+ capture: (commit) => {
4374
+ candidates.clear();
4375
+ index.collect(commit.changes, (binding) => candidates.add(binding));
4376
+ candidates.forEach((binding) => binding.capture(commit));
4377
+ },
4378
+ settle: scheduler.settle,
4379
+ flush: scheduler.flush,
4380
+ dispose: () => {
4381
+ const failures = [];
4382
+ for (const binding of [...bindings]) try {
4383
+ binding.dispose();
4384
+ } catch (error) {
4385
+ failures.push(error);
4386
+ }
4387
+ try {
4388
+ scheduler.run();
4389
+ } catch (error) {
4390
+ failures.push(error);
4391
+ }
4392
+ if (failures.length) throw failures[0];
4393
+ }
4394
+ });
4395
+ } catch (error) {
4396
+ try {
4397
+ documentConnection.close();
4398
+ } catch {}
4399
+ throw error;
4400
+ }
3609
4401
  documents.set(state, documentConnection);
3610
4402
  return documentConnection;
3611
4403
  };
3612
4404
  const materialize = (definition) => {
3613
4405
  if (definition.source.kind !== "document") throw new Error("Invalid document source.");
3614
4406
  const { document, selector } = definition.source;
3615
- const state = require_context.contextOf(document).state;
4407
+ const state = require_driver.contextOf(document).state;
3616
4408
  const current = () => resolveValue(state.schema, state.document, selector.address);
3617
4409
  const disposed = () => {
3618
4410
  if (state.disposed) throw new Error("Document has been disposed.");
@@ -3624,15 +4416,15 @@ const createDocumentSourceRegistry = (scheduler) => {
3624
4416
  const resolved = current();
3625
4417
  const node = resolved?.node;
3626
4418
  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;
4419
+ if (selector.tree?.kind === "root") return node?.kind === "tree" && require_record.isRecord(value) && typeof value.rootId === "string" ? value.rootId : void 0;
3628
4420
  if (selector.tree?.kind === "node") {
3629
- if (node?.kind !== "tree" || !require_context.isRecord(value) || !require_context.isRecord(value.nodes)) return void 0;
4421
+ if (node?.kind !== "tree" || !require_record.isRecord(value) || !require_record.isRecord(value.nodes)) return void 0;
3630
4422
  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;
4423
+ if (equalTreeNode(previous, entry)) return previous;
4424
+ return entry ? copyTreeNode(entry) : void 0;
3633
4425
  }
3634
4426
  if (!node) return void 0;
3635
- return previous === void 0 ? require_advanced.copyValue(node, value) : materializeDocumentValue(node, previous, value, dirty);
4427
+ return previous === void 0 ? copyValue(node, value) : materializeDocumentValue(node, previous, value, dirty);
3636
4428
  };
3637
4429
  const initial = read();
3638
4430
  let boundary;
@@ -3640,18 +4432,26 @@ const createDocumentSourceRegistry = (scheduler) => {
3640
4432
  if (failed) markDocumentReplace(dirty, []);
3641
4433
  else clearDocumentDirty(dirty);
3642
4434
  });
3643
- const remove = connection(document).add({
3644
- target: selector,
3645
- capture: (commit) => {
3646
- try {
3647
- mergeValueChanges(selector, dirty, commit.changes);
3648
- boundary.mark({ reset: commit.changes.changes.some((change) => change.kind === "reset") });
3649
- } catch (cause) {
3650
- boundary.fail(cause);
3651
- }
3652
- },
3653
- dispose: () => boundary.fail(/* @__PURE__ */ new Error("Document has been disposed."))
3654
- });
4435
+ let remove;
4436
+ try {
4437
+ remove = connection(document).add({
4438
+ target: selector,
4439
+ capture: (commit) => {
4440
+ try {
4441
+ mergeValueChanges(selector, dirty, commit.changes);
4442
+ boundary.mark({ reset: commit.changes.changes.some((change) => change.kind === "reset") });
4443
+ } catch (cause) {
4444
+ boundary.fail(cause);
4445
+ }
4446
+ },
4447
+ dispose: () => boundary.fail(/* @__PURE__ */ new Error("Document has been disposed."))
4448
+ });
4449
+ } catch (error) {
4450
+ try {
4451
+ scheduler.releaseProducer(boundary.producer);
4452
+ } catch {}
4453
+ throw error;
4454
+ }
3655
4455
  boundary.detach(remove);
3656
4456
  return boundary;
3657
4457
  }
@@ -3662,50 +4462,50 @@ const createDocumentSourceRegistry = (scheduler) => {
3662
4462
  const node = resolved?.node;
3663
4463
  const value = resolved?.value;
3664
4464
  const treeNodes = selector.tree?.kind === "nodes";
3665
- const entryNode = !treeNodes && node ? require_advanced.collectionEntryNode(node) : void 0;
4465
+ const entryNode = !treeNodes && node ? collectionEntryNode(node) : void 0;
3666
4466
  const snapshots = /* @__PURE__ */ new Map();
3667
4467
  const replacement = createDocumentDirty();
3668
4468
  if (pending.reset) markDocumentReplace(replacement, []);
3669
4469
  const ids = () => {
3670
- require_advanced.assertScope(active);
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)));
4470
+ require_scheduler.assertScope(active);
4471
+ if (treeNodes) return node?.kind === "tree" && require_record.isRecord(value) && require_record.isRecord(value.nodes) ? Object.freeze(Object.keys(value.nodes)) : Object.freeze([]);
4472
+ if (node?.kind === "map" && require_record.isRecord(value)) return Object.freeze(Object.keys(value));
4473
+ if (node?.kind === "table" && require_record.isRecord(value) && Array.isArray(value.ids)) return Object.freeze([...value.ids]);
4474
+ if (node?.kind === "list" && Array.isArray(value)) return Object.freeze(toArray(indexedKeys(value, node.keyOf)));
3675
4475
  return Object.freeze([]);
3676
4476
  };
3677
4477
  const has = (key) => {
3678
- require_advanced.assertScope(active);
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;
4478
+ require_scheduler.assertScope(active);
4479
+ if (treeNodes) return Boolean(node?.kind === "tree" && require_record.isRecord(value) && require_record.isRecord(value.nodes) && Object.hasOwn(value.nodes, key));
4480
+ if (node?.kind === "map" && require_record.isRecord(value)) return Object.hasOwn(value, key);
4481
+ if (node?.kind === "table" && require_record.isRecord(value) && require_record.isRecord(value.byId)) return Object.hasOwn(value.byId, key);
4482
+ if (node?.kind === "list" && Array.isArray(value)) return indexedKeys(value, node.keyOf).index(key) >= 0;
3683
4483
  return false;
3684
4484
  };
3685
4485
  const raw = (key) => {
3686
4486
  if (treeNodes) {
3687
- if (node?.kind !== "tree" || !require_context.isRecord(value) || !require_context.isRecord(value.nodes)) return void 0;
4487
+ if (node?.kind !== "tree" || !require_record.isRecord(value) || !require_record.isRecord(value.nodes)) return void 0;
3688
4488
  return Object.hasOwn(value.nodes, key) ? value.nodes[key] : void 0;
3689
4489
  }
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;
4490
+ if (node?.kind === "map" && require_record.isRecord(value)) return Object.hasOwn(value, key) ? value[key] : void 0;
4491
+ if (node?.kind === "table" && require_record.isRecord(value) && require_record.isRecord(value.byId)) return Object.hasOwn(value.byId, key) ? value.byId[key] : void 0;
3692
4492
  if (node?.kind === "list" && Array.isArray(value)) {
3693
- const index = require_advanced.indexedKeys(value, node.keyOf).index(key);
4493
+ const index = indexedKeys(value, node.keyOf).index(key);
3694
4494
  return index < 0 ? void 0 : value[index];
3695
4495
  }
3696
4496
  };
3697
4497
  return Object.freeze({
3698
4498
  get: (key) => {
3699
- require_advanced.assertScope(active);
4499
+ require_scheduler.assertScope(active);
3700
4500
  if (!snapshots.has(key)) if (!has(key)) snapshots.set(key, void 0);
3701
4501
  else {
3702
4502
  const current = raw(key);
3703
4503
  if (treeNodes) {
3704
4504
  const entry = current;
3705
4505
  const before = previous.has(key) ? previous.get(key) : void 0;
3706
- snapshots.set(key, require_advanced.equalTreeNode(before, entry) ? before : require_advanced.copyTreeNode(entry));
4506
+ snapshots.set(key, equalTreeNode(before, entry) ? before : copyTreeNode(entry));
3707
4507
  } else if (!entryNode) snapshots.set(key, current);
3708
- else if (!previous.has(key)) snapshots.set(key, require_advanced.copyValue(entryNode, current));
4508
+ else if (!previous.has(key)) snapshots.set(key, copyValue(entryNode, current));
3709
4509
  else {
3710
4510
  const dirty = pending.entries.get(key) ?? (pending.reset ? replacement : void 0);
3711
4511
  snapshots.set(key, dirty ? materializeDocumentValue(entryNode, previous.get(key), current, dirty) : previous.get(key));
@@ -3722,22 +4522,30 @@ const createDocumentSourceRegistry = (scheduler) => {
3722
4522
  if (failed) resetCollectionPending(pending);
3723
4523
  else clearCollectionPending(pending);
3724
4524
  });
3725
- const remove = connection(document).add({
3726
- target: selector,
3727
- capture: (commit) => {
3728
- try {
3729
- mergeCollectionChanges(selector, pending, commit.changes);
3730
- boundary.mark({
3731
- reset: pending.reset,
3732
- ...pending.reset ? {} : { candidates: pending.entries.keys() },
3733
- orderMayChange: pending.order
3734
- });
3735
- } catch (cause) {
3736
- boundary.fail(cause);
3737
- }
3738
- },
3739
- dispose: () => boundary.fail(/* @__PURE__ */ new Error("Document has been disposed."))
3740
- });
4525
+ let remove;
4526
+ try {
4527
+ remove = connection(document).add({
4528
+ target: selector,
4529
+ capture: (commit) => {
4530
+ try {
4531
+ mergeCollectionChanges(selector, pending, commit.changes);
4532
+ boundary.mark({
4533
+ reset: pending.reset,
4534
+ ...pending.reset ? {} : { candidates: pending.entries.keys() },
4535
+ orderMayChange: pending.order
4536
+ });
4537
+ } catch (cause) {
4538
+ boundary.fail(cause);
4539
+ }
4540
+ },
4541
+ dispose: () => boundary.fail(/* @__PURE__ */ new Error("Document has been disposed."))
4542
+ });
4543
+ } catch (error) {
4544
+ try {
4545
+ scheduler.releaseProducer(boundary.producer);
4546
+ } catch {}
4547
+ throw error;
4548
+ }
3741
4549
  boundary.detach(remove);
3742
4550
  return boundary;
3743
4551
  };
@@ -3751,115 +4559,23 @@ const createDocumentSourceRegistry = (scheduler) => {
3751
4559
  });
3752
4560
  },
3753
4561
  dispose() {
3754
- documents.forEach((document) => document.close());
4562
+ const failures = [];
4563
+ for (const document of [...documents.values()]) try {
4564
+ document.close();
4565
+ } catch (error) {
4566
+ failures.push(error);
4567
+ }
3755
4568
  documents.clear();
4569
+ if (failures.length) throw failures[0];
3756
4570
  }
3757
4571
  };
3758
4572
  };
3759
4573
  //#endregion
3760
- //#region core/src/projection/source/registry.ts
3761
- const createSourceRegistry = (scheduler) => {
3762
- const documents = createDocumentSourceRegistry(scheduler);
4574
+ //#region core/src/projection/source/external.ts
4575
+ const createExternalSourceRegistry = (scheduler, documents) => {
3763
4576
  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
- };
4577
+ const externalValues = /* @__PURE__ */ new Map();
4578
+ const externalCollections = /* @__PURE__ */ new Map();
3863
4579
  const readable = (definition) => {
3864
4580
  if (definition.source.kind !== "readable") throw new Error("Invalid Readable source.");
3865
4581
  const { readable, equality } = definition.source;
@@ -3893,19 +4609,44 @@ const createSourceRegistry = (scheduler) => {
3893
4609
  close() {
3894
4610
  if (closed) return;
3895
4611
  closed = true;
3896
- unsubscribe?.();
3897
- detachDocument?.();
4612
+ const stopReadable = unsubscribe;
4613
+ unsubscribe = void 0;
4614
+ const stopDocument = detachDocument;
4615
+ detachDocument = void 0;
3898
4616
  readables.delete(readable);
4617
+ members.clear();
4618
+ const failures = [];
4619
+ try {
4620
+ stopReadable?.();
4621
+ } catch (error) {
4622
+ failures.push(error);
4623
+ }
4624
+ try {
4625
+ stopDocument?.();
4626
+ } catch (error) {
4627
+ failures.push(error);
4628
+ }
4629
+ if (failures.length) throw failures[0];
3899
4630
  }
3900
4631
  };
3901
- const owner = require_context.contextOf(readable, false)?.owner;
3902
- if (owner) detachDocument = documents.attachRoot(owner, {
3903
- capture: () => receive(false),
3904
- dispose: () => {
3905
- members.forEach((next) => next.boundary.fail(/* @__PURE__ */ new Error("Document has been disposed.")));
3906
- }
3907
- });
3908
- unsubscribe = readable.subscribe(() => receive(true));
4632
+ try {
4633
+ const owner = require_driver.contextOf(readable, false)?.owner;
4634
+ if (owner) detachDocument = documents.attachRoot(owner, {
4635
+ capture: () => receive(false),
4636
+ dispose: () => {
4637
+ members.forEach((next) => next.boundary.fail(/* @__PURE__ */ new Error("Document has been disposed.")));
4638
+ }
4639
+ });
4640
+ unsubscribe = readable.subscribe(() => receive(true));
4641
+ } catch (error) {
4642
+ try {
4643
+ created.close();
4644
+ } catch {}
4645
+ try {
4646
+ scheduler.releaseProducer(boundary.producer);
4647
+ } catch {}
4648
+ throw error;
4649
+ }
3909
4650
  connection = created;
3910
4651
  readables.set(readable, connection);
3911
4652
  }
@@ -3938,8 +4679,11 @@ const createSourceRegistry = (scheduler) => {
3938
4679
  close() {
3939
4680
  if (closed) return;
3940
4681
  closed = true;
3941
- unsubscribe?.();
4682
+ const stop = unsubscribe;
4683
+ unsubscribe = void 0;
3942
4684
  externalValues.delete(source);
4685
+ members.clear();
4686
+ stop?.();
3943
4687
  }
3944
4688
  };
3945
4689
  try {
@@ -3954,9 +4698,14 @@ const createSourceRegistry = (scheduler) => {
3954
4698
  }
3955
4699
  scheduler.run();
3956
4700
  });
3957
- } catch (cause) {
3958
- created.close();
3959
- throw cause;
4701
+ } catch (error) {
4702
+ try {
4703
+ created.close();
4704
+ } catch {}
4705
+ try {
4706
+ scheduler.releaseProducer(boundary.producer);
4707
+ } catch {}
4708
+ throw error;
3960
4709
  }
3961
4710
  connection = created;
3962
4711
  externalValues.set(source, connection);
@@ -3989,8 +4738,11 @@ const createSourceRegistry = (scheduler) => {
3989
4738
  close() {
3990
4739
  if (closed) return;
3991
4740
  closed = true;
3992
- unsubscribe?.();
4741
+ const stop = unsubscribe;
4742
+ unsubscribe = void 0;
3993
4743
  externalCollections.delete(source);
4744
+ members.clear();
4745
+ stop?.();
3994
4746
  }
3995
4747
  };
3996
4748
  try {
@@ -4022,9 +4774,14 @@ const createSourceRegistry = (scheduler) => {
4022
4774
  }
4023
4775
  scheduler.run();
4024
4776
  });
4025
- } catch (cause) {
4026
- created.close();
4027
- throw cause;
4777
+ } catch (error) {
4778
+ try {
4779
+ created.close();
4780
+ } catch {}
4781
+ try {
4782
+ scheduler.releaseProducer(boundary.producer);
4783
+ } catch {}
4784
+ throw error;
4028
4785
  }
4029
4786
  connection = created;
4030
4787
  externalCollections.set(source, connection);
@@ -4039,25 +4796,173 @@ const createSourceRegistry = (scheduler) => {
4039
4796
  return {
4040
4797
  materialize(definition) {
4041
4798
  switch (definition.source.kind) {
4042
- case "value-input": return valueInput(definition);
4043
- case "collection-input": return collectionInput(definition);
4044
- case "document": return documents.materialize(definition);
4045
4799
  case "readable": return readable(definition);
4046
4800
  case "external-value": return externalValue(definition);
4047
4801
  case "external-collection": return externalCollection(definition);
4802
+ default: throw new Error("Invalid external projection source.");
4048
4803
  }
4049
4804
  },
4050
4805
  dispose() {
4051
- documents.dispose();
4052
- readables.forEach((connection) => connection.close());
4806
+ const failures = [];
4807
+ const connections = new Set([
4808
+ ...readables.values(),
4809
+ ...externalValues.values(),
4810
+ ...externalCollections.values()
4811
+ ]);
4812
+ for (const connection of connections) try {
4813
+ connection.close();
4814
+ } catch (error) {
4815
+ failures.push(error);
4816
+ }
4053
4817
  readables.clear();
4818
+ externalValues.clear();
4819
+ externalCollections.clear();
4820
+ if (failures.length) throw failures[0];
4821
+ }
4822
+ };
4823
+ };
4824
+ //#endregion
4825
+ //#region core/src/projection/source/input.ts
4826
+ const materializeInputSource = (scheduler, definition) => {
4827
+ const source = definition.source;
4828
+ if (source.kind === "value-input") {
4829
+ let latest = source.initial;
4830
+ const boundary = createValueBoundary(scheduler, "projection input", source.initial, source.equality, () => latest, () => void 0);
4831
+ return {
4832
+ ...boundary,
4833
+ write: {
4834
+ kind: "value",
4835
+ set(value) {
4836
+ scheduler.assertIdle();
4837
+ latest = value;
4838
+ boundary.mark();
4839
+ scheduler.run();
4840
+ }
4841
+ }
4842
+ };
4843
+ }
4844
+ if (source.kind !== "collection-input") throw new Error("Invalid projection input source.");
4845
+ const values = new Map(source.initial);
4846
+ const boundary = createCollectionBoundary(scheduler, "projection collection input", () => require_scheduler.mapRead(values), definition.output.equality, () => void 0);
4847
+ return {
4848
+ ...boundary,
4849
+ write: {
4850
+ kind: "collection",
4851
+ update(run) {
4852
+ scheduler.assertIdle();
4853
+ const staged = /* @__PURE__ */ new Map();
4854
+ const operations = [];
4855
+ let active = true;
4856
+ const draft = Object.freeze({
4857
+ get: (key) => {
4858
+ require_scheduler.assertScope(() => active);
4859
+ const entry = staged.get(key);
4860
+ return entry ? entry.present ? entry.value : void 0 : values.get(key);
4861
+ },
4862
+ has: (key) => {
4863
+ require_scheduler.assertScope(() => active);
4864
+ const entry = staged.get(key);
4865
+ return entry ? entry.present : values.has(key);
4866
+ },
4867
+ set: (key, value) => {
4868
+ require_scheduler.assertScope(() => active);
4869
+ if (typeof key !== "string") throw new TypeError("Projection keys must be strings.");
4870
+ staged.set(key, {
4871
+ present: true,
4872
+ value
4873
+ });
4874
+ operations.push({
4875
+ kind: "set",
4876
+ key,
4877
+ value
4878
+ });
4879
+ },
4880
+ remove: (key) => {
4881
+ require_scheduler.assertScope(() => active);
4882
+ if (typeof key !== "string") throw new TypeError("Projection keys must be strings.");
4883
+ staged.set(key, { present: false });
4884
+ operations.push({
4885
+ kind: "remove",
4886
+ key
4887
+ });
4888
+ }
4889
+ });
4890
+ try {
4891
+ require_scheduler.assertSynchronous(run(draft));
4892
+ } finally {
4893
+ active = false;
4894
+ }
4895
+ const candidates = /* @__PURE__ */ new Set();
4896
+ let structural = false;
4897
+ const accepted = [];
4898
+ const overlay = /* @__PURE__ */ new Map();
4899
+ for (const operation of operations) {
4900
+ const overlayValue = overlay.get(operation.key);
4901
+ const present = overlayValue ? overlayValue.present : values.has(operation.key);
4902
+ if (operation.kind === "set") {
4903
+ const previous = overlayValue ? overlayValue.present ? overlayValue.value : void 0 : values.get(operation.key);
4904
+ if (present && source.equality(previous, operation.value)) continue;
4905
+ structural ||= !present;
4906
+ overlay.set(operation.key, {
4907
+ present: true,
4908
+ value: operation.value
4909
+ });
4910
+ } else {
4911
+ if (!present) continue;
4912
+ structural = true;
4913
+ overlay.set(operation.key, { present: false });
4914
+ }
4915
+ accepted.push(operation);
4916
+ candidates.add(operation.key);
4917
+ }
4918
+ if (!accepted.length) return;
4919
+ for (const operation of accepted) if (operation.kind === "set") values.set(operation.key, operation.value);
4920
+ else values.delete(operation.key);
4921
+ boundary.mark({
4922
+ candidates,
4923
+ orderMayChange: structural
4924
+ });
4925
+ scheduler.run();
4926
+ }
4927
+ }
4928
+ };
4929
+ };
4930
+ //#endregion
4931
+ //#region core/src/projection/source/registry.ts
4932
+ const createSourceRegistry = (scheduler) => {
4933
+ const documents = createDocumentSourceRegistry(scheduler);
4934
+ const external = createExternalSourceRegistry(scheduler, documents);
4935
+ return {
4936
+ materialize(definition) {
4937
+ switch (definition.source.kind) {
4938
+ case "value-input":
4939
+ case "collection-input": return materializeInputSource(scheduler, definition);
4940
+ case "document": return documents.materialize(definition);
4941
+ case "readable":
4942
+ case "external-value":
4943
+ case "external-collection": return external.materialize(definition);
4944
+ }
4945
+ },
4946
+ dispose() {
4947
+ const failures = [];
4948
+ try {
4949
+ external.dispose();
4950
+ } catch (error) {
4951
+ failures.push(error);
4952
+ }
4953
+ try {
4954
+ documents.dispose();
4955
+ } catch (error) {
4956
+ failures.push(error);
4957
+ }
4958
+ if (failures.length) throw failures[0];
4054
4959
  }
4055
4960
  };
4056
4961
  };
4057
4962
  //#endregion
4058
4963
  //#region core/src/projection/runtime.ts
4059
4964
  const createProjectionRuntime = (options) => {
4060
- const scheduler = require_advanced.createScheduler(options?.onError ?? (() => void 0));
4965
+ const scheduler = require_scheduler.createScheduler(options?.onError ?? (() => void 0));
4061
4966
  const sources = createSourceRegistry(scheduler);
4062
4967
  const materialized = /* @__PURE__ */ new WeakMap();
4063
4968
  const publicViews = /* @__PURE__ */ new WeakMap();
@@ -4067,7 +4972,7 @@ const createProjectionRuntime = (options) => {
4067
4972
  const owner = definition.owner;
4068
4973
  if (owner === void 0) return;
4069
4974
  if (owner !== requester) throw new TypeError("Projection belongs to another scope.");
4070
- if (!requester?.active) throw new require_advanced.ProjectionDisposedError();
4975
+ if (!requester?.active) throw new require_scheduler.ProjectionDisposedError();
4071
4976
  };
4072
4977
  const rememberScoped = (definition, requester) => {
4073
4978
  if (requester && definition.owner === requester) requester.materialized.push(definition);
@@ -4085,7 +4990,7 @@ const createProjectionRuntime = (options) => {
4085
4990
  ...source.write ? { write: source.write } : {}
4086
4991
  });
4087
4992
  } else {
4088
- if (definition.owner === void 0 && definition.dependencies.some((dependency) => require_advanced.producerOf(dependency).owner !== void 0)) throw new TypeError("A root projection cannot depend on a scoped projection.");
4993
+ if (definition.owner === void 0 && definition.dependencies.some((dependency) => require_scheduler.producerOf(dependency).owner !== void 0)) throw new TypeError("A root projection cannot depend on a scoped projection.");
4089
4994
  const dependencies = definition.dependencies.map((dependency) => resolveOutput(dependency, requester));
4090
4995
  const processor = createProcessor(scheduler, definition, Object.freeze(dependencies));
4091
4996
  result = Object.freeze({
@@ -4093,19 +4998,20 @@ const createProjectionRuntime = (options) => {
4093
4998
  outputs: processor.outputs
4094
4999
  });
4095
5000
  }
5001
+ definition.materialized = true;
4096
5002
  materialized.set(definition, result);
4097
5003
  rememberScoped(definition, requester);
4098
5004
  return result;
4099
5005
  };
4100
5006
  const resolveOutput = (projection, requester) => {
4101
- const ref = require_advanced.projectionRef(projection);
5007
+ const ref = require_scheduler.projectionRef(projection);
4102
5008
  const output = materializeProducer(ref.producer, requester).outputs[ref.output];
4103
5009
  if (!output) throw new TypeError("Projection output does not exist.");
4104
5010
  return output;
4105
5011
  };
4106
5012
  const assertOutput = (output) => {
4107
5013
  scheduler.assertActive();
4108
- if (output.owner.disposed) throw new require_advanced.ProjectionDisposedError();
5014
+ if (output.owner.disposed) throw new require_scheduler.ProjectionDisposedError();
4109
5015
  if (output.owner.fault) throw output.owner.fault;
4110
5016
  };
4111
5017
  const publicCurrent = (output) => {
@@ -4115,7 +5021,7 @@ const createProjectionRuntime = (options) => {
4115
5021
  const cached = publicViews.get(output);
4116
5022
  if (cached?.revision === revision) return cached.value;
4117
5023
  if (output.kind === "collection") {
4118
- const value = require_advanced.collectionView(current);
5024
+ const value = require_scheduler.collectionView(current);
4119
5025
  publicViews.set(output, {
4120
5026
  revision,
4121
5027
  value
@@ -4123,7 +5029,7 @@ const createProjectionRuntime = (options) => {
4123
5029
  return value;
4124
5030
  }
4125
5031
  if (isMapLike(current)) {
4126
- const value = require_advanced.snapshotCollectionView(require_advanced.mapRead(current));
5032
+ const value = require_scheduler.snapshotCollectionView(require_scheduler.mapRead(current));
4127
5033
  publicViews.set(output, {
4128
5034
  revision,
4129
5035
  value
@@ -4133,12 +5039,12 @@ const createProjectionRuntime = (options) => {
4133
5039
  publicViews.delete(output);
4134
5040
  return current;
4135
5041
  };
4136
- const get = (projection, requester) => publicCurrent(resolveOutput(projection, requester));
5042
+ const readProjection = (projection, requester) => publicCurrent(resolveOutput(projection, requester));
4137
5043
  const readableSource = (projection, requester) => {
4138
5044
  const output = resolveOutput(projection, requester);
4139
5045
  return Object.freeze({
4140
5046
  kind: output.kind,
4141
- current: () => get(projection, requester),
5047
+ current: () => readProjection(projection, requester),
4142
5048
  revision: () => {
4143
5049
  assertOutput(output);
4144
5050
  return output.revision();
@@ -4150,45 +5056,57 @@ const createProjectionRuntime = (options) => {
4150
5056
  const source = readableSource(projection, requester);
4151
5057
  return selector ? createSelectorReadable(source, selector, equality) : createDirectReadable(source);
4152
5058
  };
4153
- function readable(projection, selector, equality) {
5059
+ function selectProjection(projection, selector, equality) {
4154
5060
  return makeReadable(projection, selector, equality);
4155
5061
  }
4156
5062
  const inputWrite = (target, requester) => {
4157
- const ref = require_advanced.projectionRef(target);
5063
+ const ref = require_scheduler.projectionRef(target);
4158
5064
  if (ref.output !== 0 || ref.producer.kind !== "source") throw new TypeError("Projection is not an input.");
4159
5065
  if (ref.producer.source.kind !== "value-input" && ref.producer.source.kind !== "collection-input") throw new TypeError("Projection is not an input.");
4160
5066
  const write = materializeProducer(ref.producer, requester).write;
4161
5067
  if (!write) throw new TypeError("Projection input is not writable.");
4162
5068
  return write;
4163
5069
  };
4164
- const setInput = (target, value, requester) => {
4165
- const write = inputWrite(target, requester);
4166
- if (write.kind !== "value") throw new TypeError("Projection is not a value input.");
4167
- write.set(value);
4168
- };
4169
- const updateInput = (target, run, requester) => {
5070
+ const updateInput = (target, valueOrRun, requester) => {
4170
5071
  const write = inputWrite(target, requester);
4171
- if (write.kind !== "collection") throw new TypeError("Projection is not a collection input.");
4172
- write.update(run);
5072
+ if (write.kind === "value") {
5073
+ write.set(valueOrRun);
5074
+ return;
5075
+ }
5076
+ if (typeof valueOrRun !== "function") throw new TypeError("Collection input update requires a draft callback.");
5077
+ write.update(valueOrRun);
4173
5078
  };
4174
- function batch(optionsOrCallback, maybeCallback) {
4175
- return typeof optionsOrCallback === "function" ? scheduler.batch(optionsOrCallback) : scheduler.batch(optionsOrCallback, maybeCallback);
5079
+ function update(target, valueOrRun) {
5080
+ updateInput(target, valueOrRun);
4176
5081
  }
5082
+ const batch = (run, options) => scheduler.batch(run, options);
4177
5083
  const disposeScope = (state) => {
4178
5084
  if (!state.active) return;
4179
5085
  scheduler.assertIdle();
4180
5086
  state.active = false;
4181
- state.subscriptions.forEach((unsubscribe) => unsubscribe());
5087
+ const failures = [];
5088
+ const subscriptions = [...state.subscriptions];
4182
5089
  state.subscriptions.clear();
5090
+ for (const unsubscribe of subscriptions) try {
5091
+ unsubscribe();
5092
+ } catch (error) {
5093
+ failures.push(error);
5094
+ }
4183
5095
  for (let index = state.materialized.length - 1; index >= 0; index--) {
4184
5096
  const definition = state.materialized[index];
4185
5097
  const current = materialized.get(definition);
4186
5098
  if (!current) continue;
4187
- scheduler.releaseProducer(current.record);
4188
- materialized.delete(definition);
5099
+ try {
5100
+ scheduler.releaseProducer(current.record);
5101
+ } catch (error) {
5102
+ failures.push(error);
5103
+ } finally {
5104
+ materialized.delete(definition);
5105
+ }
4189
5106
  }
4190
5107
  state.materialized.length = 0;
4191
5108
  scopes.delete(state);
5109
+ if (failures.length) throw failures[0];
4192
5110
  };
4193
5111
  const createScope = () => {
4194
5112
  scheduler.assertIdle();
@@ -4199,26 +5117,33 @@ const createProjectionRuntime = (options) => {
4199
5117
  };
4200
5118
  scopes.add(state);
4201
5119
  const assertActive = () => {
4202
- if (!state.active) throw new require_advanced.ProjectionDisposedError();
5120
+ if (!state.active) throw new require_scheduler.ProjectionDisposedError();
4203
5121
  scheduler.assertActive();
4204
5122
  };
4205
- const own = (projection) => {
5123
+ function own(target) {
4206
5124
  assertActive();
4207
- return require_advanced.ownProjection(projection, state);
4208
- };
4209
- const ownOutputTree = (tree) => {
4210
- if (require_advanced.isProjection(tree)) return own(tree);
4211
- if (!tree || typeof tree !== "object") throw new TypeError("Incremental group output tree must be an object.");
4212
- for (const value of Object.values(tree)) ownOutputTree(value);
4213
- return tree;
4214
- };
4215
- const scopedInput = Object.assign((initial, equality) => own(require_advanced.input(initial, equality)), { collection: (initial) => own(require_advanced.input.collection(initial)) });
4216
- const scopedDerive = (dependencies, compute, equality) => own(require_advanced.derive(dependencies, compute, equality));
4217
- const scopedIncremental = Object.assign((dependencies, processor) => own(require_advanced.incremental(dependencies, processor)), {
4218
- collection: (dependencies, processor) => own(require_advanced.incremental.collection(dependencies, processor)),
4219
- group: (dependencies, defineOutputs, processor) => ownOutputTree(require_advanced.incremental.group(dependencies, defineOutputs, processor))
4220
- });
4221
- function scopeReadable(projection, selector, equality) {
5125
+ const projections = [];
5126
+ const collect = (value) => {
5127
+ if (require_scheduler.isProjection(value)) {
5128
+ projections.push(value);
5129
+ return;
5130
+ }
5131
+ if (!require_record.isPlainObject(value)) throw new TypeError("Projection ownership tree must be a plain object.");
5132
+ for (const key of Reflect.ownKeys(value)) {
5133
+ if (typeof key !== "string") throw new TypeError("Projection ownership tree keys must be strings.");
5134
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
5135
+ if (!descriptor?.enumerable || !("value" in descriptor)) throw new TypeError("Projection ownership tree must use enumerable data properties.");
5136
+ const child = descriptor.value;
5137
+ if (!require_scheduler.isProjection(child) && !require_record.isPlainObject(child)) throw new TypeError("Projection ownership tree leaves must be projections.");
5138
+ collect(child);
5139
+ }
5140
+ };
5141
+ collect(target);
5142
+ if (!projections.length) throw new TypeError("Projection ownership tree must contain a projection.");
5143
+ require_scheduler.ownProjections(projections, state);
5144
+ return target;
5145
+ }
5146
+ function scopeSelect(projection, selector, equality) {
4222
5147
  assertActive();
4223
5148
  const source = makeReadable(projection, selector, equality, state);
4224
5149
  return Object.freeze({
@@ -4245,78 +5170,87 @@ const createProjectionRuntime = (options) => {
4245
5170
  }
4246
5171
  });
4247
5172
  }
4248
- function scopeBatch(optionsOrCallback, maybeCallback) {
5173
+ function scopeUpdate(target, valueOrRun) {
5174
+ assertActive();
5175
+ updateInput(target, valueOrRun, state);
5176
+ }
5177
+ function scopeBatch(run, options) {
4249
5178
  assertActive();
4250
- return typeof optionsOrCallback === "function" ? batch(optionsOrCallback) : batch(optionsOrCallback, maybeCallback);
5179
+ return batch(run, options);
4251
5180
  }
4252
5181
  return Object.freeze({
4253
- input: scopedInput,
4254
- derive: scopedDerive,
4255
- incremental: scopedIncremental,
4256
- get: (projection) => {
5182
+ own,
5183
+ read: (projection) => {
4257
5184
  assertActive();
4258
- return get(projection, state);
4259
- },
4260
- readable: scopeReadable,
4261
- set: (target, value) => {
4262
- assertActive();
4263
- setInput(target, value, state);
4264
- },
4265
- update: (target, run) => {
4266
- assertActive();
4267
- updateInput(target, run, state);
5185
+ return readProjection(projection, state);
4268
5186
  },
5187
+ select: scopeSelect,
5188
+ update: scopeUpdate,
4269
5189
  batch: scopeBatch,
4270
5190
  dispose: () => disposeScope(state)
4271
5191
  });
4272
5192
  };
4273
5193
  return Object.freeze({
4274
- get,
4275
- readable,
4276
- set: setInput,
4277
- update: updateInput,
5194
+ read: readProjection,
5195
+ select: selectProjection,
5196
+ update,
4278
5197
  batch,
4279
5198
  scope: createScope,
4280
5199
  dispose: () => {
4281
5200
  if (!scheduler.active) return;
4282
5201
  scheduler.assertIdle();
5202
+ const failures = [];
4283
5203
  for (const scope of scopes) {
4284
5204
  scope.active = false;
4285
- scope.subscriptions.forEach((unsubscribe) => unsubscribe());
5205
+ const subscriptions = [...scope.subscriptions];
4286
5206
  scope.subscriptions.clear();
5207
+ for (const unsubscribe of subscriptions) try {
5208
+ unsubscribe();
5209
+ } catch (error) {
5210
+ failures.push(error);
5211
+ }
4287
5212
  scope.materialized.length = 0;
4288
5213
  }
4289
5214
  scopes.clear();
4290
- sources.dispose();
4291
- scheduler.dispose();
5215
+ try {
5216
+ sources.dispose();
5217
+ } catch (error) {
5218
+ failures.push(error);
5219
+ }
5220
+ try {
5221
+ scheduler.dispose();
5222
+ } catch (error) {
5223
+ failures.push(error);
5224
+ }
5225
+ if (failures.length === 1) throw failures[0];
5226
+ if (failures.length) throw new AggregateError(failures, "Projection cleanup failed.");
4292
5227
  }
4293
5228
  });
4294
5229
  };
4295
5230
  //#endregion
4296
5231
  exports.DocumentDisposedError = DocumentDisposedError;
4297
5232
  exports.DocumentReentrancyError = DocumentReentrancyError;
4298
- exports.ParseError = require_advanced.ParseError;
4299
- exports.ProjectionDisposedError = require_advanced.ProjectionDisposedError;
4300
- exports.ProjectionError = require_advanced.ProjectionError;
5233
+ exports.ParseError = ParseError;
5234
+ exports.ProjectionDisposedError = require_scheduler.ProjectionDisposedError;
5235
+ exports.ProjectionError = require_scheduler.ProjectionError;
4301
5236
  exports.TransactionRejected = TransactionRejected;
4302
- exports.asReadable = asReadable;
4303
5237
  exports.createDocument = createDocument;
4304
5238
  exports.createProjectionRuntime = createProjectionRuntime;
4305
- exports.derive = require_advanced.derive;
4306
- exports.field = require_advanced.field;
4307
- exports.input = require_advanced.input;
4308
- exports.list = require_advanced.list;
4309
- exports.map = require_advanced.map;
4310
- exports.object = require_advanced.object;
4311
- exports.observe = require_advanced.observe;
4312
- exports.optional = require_advanced.optional;
4313
- exports.parse = require_advanced.parse;
5239
+ exports.derive = derive;
5240
+ exports.field = field;
5241
+ exports.input = input;
5242
+ exports.list = list;
5243
+ exports.map = map;
5244
+ exports.object = object;
5245
+ exports.observe = observe;
5246
+ exports.optional = optional;
5247
+ exports.parse = parse;
4314
5248
  exports.read = read;
4315
5249
  exports.replace = replace;
4316
5250
  exports.select = select;
4317
5251
  exports.snapshot = snapshot;
4318
- exports.table = require_advanced.table;
4319
- exports.tree = require_advanced.tree;
4320
- exports.variant = require_advanced.variant;
5252
+ exports.table = table;
5253
+ exports.tree = tree;
5254
+ exports.variant = variant;
4321
5255
 
4322
5256
  //# sourceMappingURL=index.cjs.map