doxum 0.1.21 → 0.1.22
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.
- package/README.md +21 -2
- package/dist/{access-BeSV5ve-.js → access-CZXv_DIF.js} +179 -37
- package/dist/access-CZXv_DIF.js.map +1 -0
- package/dist/{access-Bienf28h.cjs → access-D64MFRSm.cjs} +228 -38
- package/dist/access-D64MFRSm.cjs.map +1 -0
- package/dist/{advanced-COFJtWMT.js → advanced-BTStm2cW.js} +29 -25
- package/dist/advanced-BTStm2cW.js.map +1 -0
- package/dist/{advanced-FgdTwu5b.d.ts → advanced-CqrR_4dh.d.ts} +3 -3
- package/dist/{advanced-DfKc7TZR.d.cts → advanced-CyR5o3Xr.d.cts} +3 -3
- package/dist/{advanced-BRL5pN0y.cjs → advanced-GKZ-CZ6a.cjs} +29 -25
- package/dist/advanced-GKZ-CZ6a.cjs.map +1 -0
- package/dist/advanced.cjs +1 -1
- package/dist/advanced.d.cts +1 -1
- package/dist/advanced.d.ts +1 -1
- package/dist/advanced.js +1 -1
- package/dist/{contract-KG5XnQZt.d.ts → contract-CRrZ-3sF.d.cts} +64 -34
- package/dist/{contract-CdmDHRUq.d.cts → contract-CxiNcqMn.d.ts} +64 -34
- package/dist/{driver-Djr3BVvo.cjs → driver-BC06FEMF.cjs} +2 -2
- package/dist/{driver-Djr3BVvo.cjs.map → driver-BC06FEMF.cjs.map} +1 -1
- package/dist/{driver-CLYJOGDQ.js → driver-BqRjwFmU.js} +2 -2
- package/dist/{driver-CLYJOGDQ.js.map → driver-BqRjwFmU.js.map} +1 -1
- package/dist/index.cjs +480 -117
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +478 -115
- package/dist/index.js.map +1 -1
- package/dist/{integration-Z6MsfFI7.cjs → integration-BqDw7e2w.cjs} +3 -4
- package/dist/{integration-Z6MsfFI7.cjs.map → integration-BqDw7e2w.cjs.map} +1 -1
- package/dist/{integration-C4Isp8lJ.js → integration-CSXaF8HP.js} +2 -3
- package/dist/{integration-C4Isp8lJ.js.map → integration-CSXaF8HP.js.map} +1 -1
- package/dist/integration.cjs +5 -4
- package/dist/integration.d.cts +1 -1
- package/dist/integration.d.ts +1 -1
- package/dist/integration.js +4 -3
- package/dist/{issue-W0hT8u8D.js → issue-9U6YLYz3.js} +11 -6
- package/dist/issue-9U6YLYz3.js.map +1 -0
- package/dist/{issue-DjK1xp5K.cjs → issue-Bo0FIO3b.cjs} +11 -6
- package/dist/issue-Bo0FIO3b.cjs.map +1 -0
- package/dist/local-sync.cjs +2 -2
- package/dist/local-sync.d.cts +1 -1
- package/dist/local-sync.d.ts +1 -1
- package/dist/local-sync.js +2 -2
- package/dist/{notification-Bkjau6B6.js → notification-CrZHVx3a.js} +3 -59
- package/dist/notification-CrZHVx3a.js.map +1 -0
- package/dist/{notification-DJfouMEb.cjs → notification-DFoA9bQY.cjs} +3 -77
- package/dist/notification-DFoA9bQY.cjs.map +1 -0
- package/dist/react.cjs +4 -3
- package/dist/react.cjs.map +1 -1
- package/dist/react.js +3 -2
- package/dist/react.js.map +1 -1
- package/package.json +1 -1
- package/skills/doxum-runtime/SKILL.md +5 -0
- package/skills/doxum-runtime/references/guide.en.md +9 -0
- package/skills/doxum-runtime/references/guide.zh-CN.md +8 -0
- package/skills/doxum-runtime/references/projections.en.md +5 -0
- package/skills/doxum-runtime/references/projections.zh-CN.md +5 -0
- package/dist/access-BeSV5ve-.js.map +0 -1
- package/dist/access-Bienf28h.cjs.map +0 -1
- package/dist/advanced-BRL5pN0y.cjs.map +0 -1
- package/dist/advanced-COFJtWMT.js.map +0 -1
- package/dist/issue-DjK1xp5K.cjs.map +0 -1
- package/dist/issue-W0hT8u8D.js.map +0 -1
- package/dist/notification-Bkjau6B6.js.map +0 -1
- package/dist/notification-DJfouMEb.cjs.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_issue = require("./issue-
|
|
3
|
-
const require_access = require("./access-
|
|
4
|
-
const require_advanced = require("./advanced-
|
|
5
|
-
const
|
|
6
|
-
const
|
|
2
|
+
const require_issue = require("./issue-Bo0FIO3b.cjs");
|
|
3
|
+
const require_access = require("./access-D64MFRSm.cjs");
|
|
4
|
+
const require_advanced = require("./advanced-GKZ-CZ6a.cjs");
|
|
5
|
+
const require_driver = require("./driver-BC06FEMF.cjs");
|
|
6
|
+
const require_notification = require("./notification-DFoA9bQY.cjs");
|
|
7
7
|
//#region core/src/impact.ts
|
|
8
8
|
const queries = /* @__PURE__ */ new WeakMap();
|
|
9
|
-
const affectsTarget = (impact, value) => queries.get(impact).affects(value);
|
|
10
|
-
const collectionImpact = (impact, selector) => queries.get(impact).collection(selector);
|
|
11
9
|
const createImpact = (schema, changes) => {
|
|
12
10
|
const reset = changes.changes.some((change) => change.kind === "reset");
|
|
13
11
|
let values;
|
|
@@ -17,10 +15,7 @@ const createImpact = (schema, changes) => {
|
|
|
17
15
|
require_issue.profile.impact.index();
|
|
18
16
|
values = new require_issue.AddressIndex();
|
|
19
17
|
orders = new require_issue.AddressIndex();
|
|
20
|
-
|
|
21
|
-
for (const member of change.members) values.add(change.at, true, member.key);
|
|
22
|
-
if (change.order) orders.add(change.at, true);
|
|
23
|
-
} else if (change.kind === "tree") values.add(change.at, true);
|
|
18
|
+
require_access.visitChangedLocations(changes, (at) => values.add(at, true), (at) => orders.add(at, true));
|
|
24
19
|
}
|
|
25
20
|
return values;
|
|
26
21
|
};
|
|
@@ -28,13 +23,13 @@ const createImpact = (schema, changes) => {
|
|
|
28
23
|
const implementation = {
|
|
29
24
|
affects(value) {
|
|
30
25
|
require_issue.profile.impact.affects();
|
|
31
|
-
if (!
|
|
26
|
+
if (!require_access.belongs(value, schema)) return false;
|
|
32
27
|
if (reset) return true;
|
|
33
|
-
return
|
|
28
|
+
return require_access.affected(value, index(), orders);
|
|
34
29
|
},
|
|
35
30
|
collection(selector) {
|
|
36
31
|
if (selector.schema !== schema) throw new TypeError("Collection belongs to another root model.");
|
|
37
|
-
const key = JSON.stringify(selector
|
|
32
|
+
const key = JSON.stringify(require_access.indexedAddress(selector)), cached = cache.get(key);
|
|
38
33
|
if (cached) return cached;
|
|
39
34
|
if (reset) {
|
|
40
35
|
const result = { kind: "reset" };
|
|
@@ -42,6 +37,7 @@ const createImpact = (schema, changes) => {
|
|
|
42
37
|
return result;
|
|
43
38
|
}
|
|
44
39
|
const at = selector.address;
|
|
40
|
+
const tree = selector.tree;
|
|
45
41
|
const added = /* @__PURE__ */ new Set(), removed = /* @__PURE__ */ new Set(), updated = /* @__PURE__ */ new Set();
|
|
46
42
|
let orderChanged = false;
|
|
47
43
|
for (const change of changes.changes) {
|
|
@@ -71,6 +67,12 @@ const createImpact = (schema, changes) => {
|
|
|
71
67
|
continue;
|
|
72
68
|
}
|
|
73
69
|
if (change.kind === "tree" && require_issue.contains(change.at, at)) {
|
|
70
|
+
if (tree?.kind === "nodes" && change.at.length === at.length && require_issue.contains(at, change.at)) {
|
|
71
|
+
for (const node of change.nodes) if (node.kind === "added") added.add(node.id);
|
|
72
|
+
else if (node.kind === "removed") removed.add(node.id);
|
|
73
|
+
else updated.add(node.id);
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
74
76
|
const result = { kind: "reset" };
|
|
75
77
|
cache.set(key, result);
|
|
76
78
|
return result;
|
|
@@ -309,10 +311,6 @@ const forgetMember = (group, key) => {
|
|
|
309
311
|
}
|
|
310
312
|
};
|
|
311
313
|
const emptyGroup = (group) => !group.order && (group.layout === "fixed" ? !group.members.some(Boolean) : !group.members?.size);
|
|
312
|
-
const copyNode = (node) => ({
|
|
313
|
-
...node,
|
|
314
|
-
children: [...node.children]
|
|
315
|
-
});
|
|
316
314
|
const transition = (node, key, beforePresent, before, afterPresent, after) => {
|
|
317
315
|
if (beforePresent === afterPresent && (!beforePresent || Object.is(before, after))) return;
|
|
318
316
|
if (node.kind !== "field" && beforePresent === afterPresent && require_access.equalValue(node, before, after)) return;
|
|
@@ -403,7 +401,7 @@ const restore = (fact, schema, root, skip = 0) => {
|
|
|
403
401
|
const tree = location.value;
|
|
404
402
|
if (fact.before === null) delete tree.rootId;
|
|
405
403
|
else tree.rootId = fact.before;
|
|
406
|
-
for (const [id, node] of fact.nodes) installMember(tree.nodes, id, node !== void 0, node &&
|
|
404
|
+
for (const [id, node] of fact.nodes) installMember(tree.nodes, id, node !== void 0, node && require_access.copyTreeNode(node));
|
|
407
405
|
}
|
|
408
406
|
return root;
|
|
409
407
|
};
|
|
@@ -442,17 +440,16 @@ const sealMembers = (fact, changes) => {
|
|
|
442
440
|
const sealTree = (fact, state, changes) => {
|
|
443
441
|
const location = require_issue.resolveValue(state.schema, state.document, fact.at);
|
|
444
442
|
const tree = location?.value;
|
|
445
|
-
|
|
446
|
-
if (node?.kind !== "tree") throw new Error("Tree schema disappeared before sealing.");
|
|
443
|
+
if ((location?.node)?.kind !== "tree") throw new Error("Tree schema disappeared before sealing.");
|
|
447
444
|
const nodes = [];
|
|
448
445
|
for (const [id, before] of fact.nodes) {
|
|
449
446
|
const after = Object.hasOwn(tree.nodes, id) ? tree.nodes[id] : void 0;
|
|
450
447
|
if (!before && !after) continue;
|
|
451
|
-
if (before && after &&
|
|
448
|
+
if (before && after && require_access.equalTreeNode(before, after)) continue;
|
|
452
449
|
nodes.push(!before ? {
|
|
453
450
|
id,
|
|
454
451
|
kind: "added",
|
|
455
|
-
after:
|
|
452
|
+
after: require_access.copyTreeNode(after)
|
|
456
453
|
} : !after ? {
|
|
457
454
|
id,
|
|
458
455
|
kind: "removed",
|
|
@@ -461,7 +458,7 @@ const sealTree = (fact, state, changes) => {
|
|
|
461
458
|
id,
|
|
462
459
|
kind: "updated",
|
|
463
460
|
before,
|
|
464
|
-
after:
|
|
461
|
+
after: require_access.copyTreeNode(after)
|
|
465
462
|
});
|
|
466
463
|
}
|
|
467
464
|
const after = tree.rootId ?? null;
|
|
@@ -643,7 +640,7 @@ var ChangeRecorder = class {
|
|
|
643
640
|
}
|
|
644
641
|
if (id !== void 0 && !fact.nodes.has(id)) {
|
|
645
642
|
require_issue.profile.recorder("treeNodes");
|
|
646
|
-
fact.nodes.set(id, Object.hasOwn(tree.nodes, id) ?
|
|
643
|
+
fact.nodes.set(id, Object.hasOwn(tree.nodes, id) ? require_access.copyTreeNode(tree.nodes[id]) : void 0);
|
|
647
644
|
}
|
|
648
645
|
}
|
|
649
646
|
rollback() {
|
|
@@ -830,12 +827,13 @@ function apply(session, changes, direction) {
|
|
|
830
827
|
else current.rootId = root;
|
|
831
828
|
for (const item of change.nodes) {
|
|
832
829
|
const next = side === "after" ? item.kind !== "removed" ? item.after : void 0 : item.kind !== "added" ? item.before : void 0;
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
}
|
|
830
|
+
if (next !== void 0) {
|
|
831
|
+
const issue = require_access.checkTreePayload(node.value, next, change.at.concat(item.id));
|
|
832
|
+
if (issue) require_issue.invalidValue(issue);
|
|
833
|
+
}
|
|
834
|
+
installMember(current.nodes, item.id, next !== void 0, next && require_access.copyTreeNode(next));
|
|
837
835
|
}
|
|
838
|
-
|
|
836
|
+
if (!require_issue.validate(current)) return require_issue.fail(change.at, "invalid-tree", "Invalid tree structure.");
|
|
839
837
|
session.invalidate();
|
|
840
838
|
}
|
|
841
839
|
}
|
|
@@ -1430,12 +1428,220 @@ const createSelectorReadable = (source, selector, equality = Object.is) => {
|
|
|
1430
1428
|
});
|
|
1431
1429
|
};
|
|
1432
1430
|
//#endregion
|
|
1431
|
+
//#region core/src/projection/document-materialization.ts
|
|
1432
|
+
const createDocumentDirty = () => ({
|
|
1433
|
+
replace: false,
|
|
1434
|
+
order: false,
|
|
1435
|
+
treeRoot: false,
|
|
1436
|
+
treeNodes: /* @__PURE__ */ new Set(),
|
|
1437
|
+
children: /* @__PURE__ */ new Map()
|
|
1438
|
+
});
|
|
1439
|
+
const clearDocumentDirty = (dirty) => {
|
|
1440
|
+
dirty.replace = false;
|
|
1441
|
+
dirty.order = false;
|
|
1442
|
+
dirty.treeRoot = false;
|
|
1443
|
+
dirty.treeNodes.clear();
|
|
1444
|
+
dirty.children.clear();
|
|
1445
|
+
};
|
|
1446
|
+
const hasDocumentDirty = (dirty) => dirty.replace || dirty.order || dirty.treeRoot || dirty.treeNodes.size > 0 || dirty.children.size > 0;
|
|
1447
|
+
const locate = (dirty, path) => {
|
|
1448
|
+
let current = dirty;
|
|
1449
|
+
for (const key of path) {
|
|
1450
|
+
if (current.replace) return void 0;
|
|
1451
|
+
let child = current.children.get(key);
|
|
1452
|
+
if (!child) {
|
|
1453
|
+
child = createDocumentDirty();
|
|
1454
|
+
current.children.set(key, child);
|
|
1455
|
+
}
|
|
1456
|
+
current = child;
|
|
1457
|
+
}
|
|
1458
|
+
return current;
|
|
1459
|
+
};
|
|
1460
|
+
const markDocumentReplace = (dirty, path) => {
|
|
1461
|
+
const current = locate(dirty, path);
|
|
1462
|
+
if (!current) return;
|
|
1463
|
+
current.replace = true;
|
|
1464
|
+
current.order = false;
|
|
1465
|
+
current.treeRoot = false;
|
|
1466
|
+
current.treeNodes.clear();
|
|
1467
|
+
current.children.clear();
|
|
1468
|
+
};
|
|
1469
|
+
const markDocumentOrder = (dirty, path) => {
|
|
1470
|
+
const current = locate(dirty, path);
|
|
1471
|
+
if (current && !current.replace) current.order = true;
|
|
1472
|
+
};
|
|
1473
|
+
const markDocumentTree = (dirty, path, root, nodes) => {
|
|
1474
|
+
const current = locate(dirty, path);
|
|
1475
|
+
if (!current || current.replace) return;
|
|
1476
|
+
current.treeRoot ||= root;
|
|
1477
|
+
for (const id of nodes) current.treeNodes.add(id);
|
|
1478
|
+
};
|
|
1479
|
+
const equivalent = (node, left, right) => node.kind === "field" ? Object.is(left, right) : require_access.equalValue(node, left, right);
|
|
1480
|
+
const replaceValue = (node, previous, current) => equivalent(node, previous, current) ? previous : require_access.copyValue(node, current);
|
|
1481
|
+
const cloneRecord = (value) => {
|
|
1482
|
+
require_issue.profile.copy.shallowRecord(Object.getOwnPropertyNames(value).length);
|
|
1483
|
+
return Object.create(Object.getPrototypeOf(value), Object.getOwnPropertyDescriptors(value));
|
|
1484
|
+
};
|
|
1485
|
+
const materializeRecordChild = (node, previous, current, key, dirty) => {
|
|
1486
|
+
const before = Object.hasOwn(previous, key);
|
|
1487
|
+
const after = Object.hasOwn(current, key);
|
|
1488
|
+
if (!before && !after) return { changed: false };
|
|
1489
|
+
if (!after) return {
|
|
1490
|
+
changed: true,
|
|
1491
|
+
present: false,
|
|
1492
|
+
value: void 0
|
|
1493
|
+
};
|
|
1494
|
+
const next = before ? materializeDocumentValue(node, previous[key], current[key], dirty) : require_access.copyValue(node, current[key]);
|
|
1495
|
+
if (before && next === previous[key]) return { changed: false };
|
|
1496
|
+
return {
|
|
1497
|
+
changed: true,
|
|
1498
|
+
present: true,
|
|
1499
|
+
value: next
|
|
1500
|
+
};
|
|
1501
|
+
};
|
|
1502
|
+
const materializeObject = (node, previous, current, dirty) => {
|
|
1503
|
+
if (node.kind === "variant" && previous[node.tag] !== current[node.tag]) return replaceValue(node, previous, current);
|
|
1504
|
+
const layout = require_issue.compiledShape(node, current);
|
|
1505
|
+
if (!layout) return replaceValue(node, previous, current);
|
|
1506
|
+
let result;
|
|
1507
|
+
for (const [key, childDirty] of dirty.children) {
|
|
1508
|
+
const member = layout.members.get(key);
|
|
1509
|
+
if (!member) return replaceValue(node, previous, current);
|
|
1510
|
+
const child = materializeRecordChild(member.node, previous, current, key, childDirty);
|
|
1511
|
+
if (!child.changed) continue;
|
|
1512
|
+
result ??= cloneRecord(previous);
|
|
1513
|
+
installMember(result, key, child.present, child.value);
|
|
1514
|
+
}
|
|
1515
|
+
return result ?? previous;
|
|
1516
|
+
};
|
|
1517
|
+
const materializeMap = (node, previous, current, dirty) => {
|
|
1518
|
+
let result;
|
|
1519
|
+
for (const [key, childDirty] of dirty.children) {
|
|
1520
|
+
const child = materializeRecordChild(node.value, previous, current, key, childDirty);
|
|
1521
|
+
if (!child.changed) continue;
|
|
1522
|
+
result ??= cloneRecord(previous);
|
|
1523
|
+
installMember(result, key, child.present, child.value);
|
|
1524
|
+
}
|
|
1525
|
+
return result ?? previous;
|
|
1526
|
+
};
|
|
1527
|
+
const materializeTable = (node, previous, current, dirty) => {
|
|
1528
|
+
if (!require_issue.isRecord(previous.byId) || !require_issue.isRecord(current.byId)) return replaceValue(node, previous, current);
|
|
1529
|
+
const beforeById = previous.byId;
|
|
1530
|
+
const afterById = current.byId;
|
|
1531
|
+
let result;
|
|
1532
|
+
let nextById;
|
|
1533
|
+
for (const [key, childDirty] of dirty.children) {
|
|
1534
|
+
const child = materializeRecordChild(node.value, beforeById, afterById, key, childDirty);
|
|
1535
|
+
if (!child.changed) continue;
|
|
1536
|
+
nextById ??= cloneRecord(beforeById);
|
|
1537
|
+
installMember(nextById, key, child.present, child.value);
|
|
1538
|
+
}
|
|
1539
|
+
if (nextById) {
|
|
1540
|
+
result = cloneRecord(previous);
|
|
1541
|
+
installMember(result, "byId", true, nextById);
|
|
1542
|
+
}
|
|
1543
|
+
if (dirty.order) {
|
|
1544
|
+
const beforeIds = previous.ids;
|
|
1545
|
+
const afterIds = current.ids;
|
|
1546
|
+
if (!Array.isArray(beforeIds) || !Array.isArray(afterIds)) return replaceValue(node, previous, current);
|
|
1547
|
+
if (!require_issue.equal(beforeIds, afterIds)) {
|
|
1548
|
+
result ??= cloneRecord(previous);
|
|
1549
|
+
installMember(result, "ids", true, [...afterIds]);
|
|
1550
|
+
}
|
|
1551
|
+
}
|
|
1552
|
+
return result ?? previous;
|
|
1553
|
+
};
|
|
1554
|
+
const materializeList = (node, previous, current, dirty) => {
|
|
1555
|
+
if (dirty.order) {
|
|
1556
|
+
const before = require_issue.listSequence(previous, node.keyOf);
|
|
1557
|
+
const after = require_issue.listSequence(current, node.keyOf);
|
|
1558
|
+
let changed = !require_issue.equal(before.order, after.order);
|
|
1559
|
+
const result = new Array(after.order.length);
|
|
1560
|
+
for (let index = 0; index < after.order.length; index++) {
|
|
1561
|
+
const key = after.order[index];
|
|
1562
|
+
const currentValue = after.values.get(key);
|
|
1563
|
+
if (!before.values.has(key)) {
|
|
1564
|
+
changed = true;
|
|
1565
|
+
result[index] = currentValue;
|
|
1566
|
+
continue;
|
|
1567
|
+
}
|
|
1568
|
+
const previousValue = before.values.get(key);
|
|
1569
|
+
const childDirty = dirty.children.get(key);
|
|
1570
|
+
const next = childDirty ? materializeDocumentValue(node.value, previousValue, currentValue, childDirty) : previousValue;
|
|
1571
|
+
changed ||= next !== previousValue;
|
|
1572
|
+
result[index] = next;
|
|
1573
|
+
}
|
|
1574
|
+
return changed ? result : previous;
|
|
1575
|
+
}
|
|
1576
|
+
let result;
|
|
1577
|
+
const before = require_issue.indexedKeys(previous, node.keyOf);
|
|
1578
|
+
const after = require_issue.indexedKeys(current, node.keyOf);
|
|
1579
|
+
for (const [key, childDirty] of dirty.children) {
|
|
1580
|
+
const previousIndex = before.index(key);
|
|
1581
|
+
const currentIndex = after.index(key);
|
|
1582
|
+
if (previousIndex < 0 || currentIndex < 0) return replaceValue(node, previous, current);
|
|
1583
|
+
const next = materializeDocumentValue(node.value, previous[previousIndex], current[currentIndex], childDirty);
|
|
1584
|
+
if (next === previous[previousIndex] && previousIndex === currentIndex) continue;
|
|
1585
|
+
result ??= [...previous];
|
|
1586
|
+
result[currentIndex] = next;
|
|
1587
|
+
}
|
|
1588
|
+
return result ?? previous;
|
|
1589
|
+
};
|
|
1590
|
+
const materializeTree = (node, previous, current, dirty) => {
|
|
1591
|
+
if (!require_issue.isRecord(previous.nodes) || !require_issue.isRecord(current.nodes)) return replaceValue(node, previous, current);
|
|
1592
|
+
let result;
|
|
1593
|
+
if (dirty.treeRoot) {
|
|
1594
|
+
const beforePresent = Object.hasOwn(previous, "rootId");
|
|
1595
|
+
const afterPresent = Object.hasOwn(current, "rootId");
|
|
1596
|
+
if (beforePresent !== afterPresent || !Object.is(previous.rootId, current.rootId)) {
|
|
1597
|
+
result = cloneRecord(previous);
|
|
1598
|
+
installMember(result, "rootId", afterPresent, current.rootId);
|
|
1599
|
+
}
|
|
1600
|
+
}
|
|
1601
|
+
let nodes;
|
|
1602
|
+
for (const id of dirty.treeNodes) {
|
|
1603
|
+
const beforePresent = Object.hasOwn(previous.nodes, id);
|
|
1604
|
+
const afterPresent = Object.hasOwn(current.nodes, id);
|
|
1605
|
+
const before = beforePresent ? previous.nodes[id] : void 0;
|
|
1606
|
+
const after = afterPresent ? current.nodes[id] : void 0;
|
|
1607
|
+
if (beforePresent === afterPresent && require_access.equalTreeNode(before, after)) continue;
|
|
1608
|
+
nodes ??= cloneRecord(previous.nodes);
|
|
1609
|
+
installMember(nodes, id, afterPresent, after && require_access.copyTreeNode(after));
|
|
1610
|
+
}
|
|
1611
|
+
if (nodes) {
|
|
1612
|
+
result ??= cloneRecord(previous);
|
|
1613
|
+
installMember(result, "nodes", true, nodes);
|
|
1614
|
+
}
|
|
1615
|
+
return result ?? previous;
|
|
1616
|
+
};
|
|
1617
|
+
const materializeDocumentValue = (node, previous, current, dirty) => {
|
|
1618
|
+
if (!hasDocumentDirty(dirty)) return previous;
|
|
1619
|
+
if (dirty.replace || previous === void 0 || current === void 0 || node.kind === "field") return replaceValue(node, previous, current);
|
|
1620
|
+
if (node.kind === "object" || node.kind === "variant") {
|
|
1621
|
+
if (!require_issue.isRecord(previous) || !require_issue.isRecord(current)) return replaceValue(node, previous, current);
|
|
1622
|
+
return materializeObject(node, previous, current, dirty);
|
|
1623
|
+
}
|
|
1624
|
+
if (node.kind === "map") {
|
|
1625
|
+
if (!require_issue.isRecord(previous) || !require_issue.isRecord(current)) return replaceValue(node, previous, current);
|
|
1626
|
+
return materializeMap(node, previous, current, dirty);
|
|
1627
|
+
}
|
|
1628
|
+
if (node.kind === "table") {
|
|
1629
|
+
if (!require_issue.isRecord(previous) || !require_issue.isRecord(current)) return replaceValue(node, previous, current);
|
|
1630
|
+
return materializeTable(node, previous, current, dirty);
|
|
1631
|
+
}
|
|
1632
|
+
if (node.kind === "list") {
|
|
1633
|
+
if (!Array.isArray(previous) || !Array.isArray(current)) return replaceValue(node, previous, current);
|
|
1634
|
+
return materializeList(node, previous, current, dirty);
|
|
1635
|
+
}
|
|
1636
|
+
if (!require_issue.isRecord(previous) || !require_issue.isRecord(current)) return replaceValue(node, previous, current);
|
|
1637
|
+
return materializeTree(node, previous, current, dirty);
|
|
1638
|
+
};
|
|
1639
|
+
//#endregion
|
|
1433
1640
|
//#region core/src/projection/source.ts
|
|
1434
1641
|
const sourceError = (source, cause) => new require_advanced.ProjectionError("source", source.name, [source.outputs[0].revision()], cause);
|
|
1435
|
-
const createValueBoundary = (scheduler, name, initial, equality) => {
|
|
1642
|
+
const createValueBoundary = (scheduler, name, initial, equality, prepare, clearSource) => {
|
|
1436
1643
|
const state = createValueOutput();
|
|
1437
1644
|
let boundary;
|
|
1438
|
-
let latest = initial;
|
|
1439
1645
|
let pendingReset = false;
|
|
1440
1646
|
let pendingCause;
|
|
1441
1647
|
let contextCause;
|
|
@@ -1477,7 +1683,8 @@ const createValueBoundary = (scheduler, name, initial, equality) => {
|
|
|
1477
1683
|
contextCause = cause;
|
|
1478
1684
|
let active = true;
|
|
1479
1685
|
try {
|
|
1480
|
-
state.begin(() => active, pendingReset)
|
|
1686
|
+
const evaluation = state.begin(() => active, pendingReset);
|
|
1687
|
+
evaluation.output.set(prepare(evaluation.previous));
|
|
1481
1688
|
const changed = state.seal(pendingReset, equality);
|
|
1482
1689
|
recovering = false;
|
|
1483
1690
|
return {
|
|
@@ -1490,11 +1697,13 @@ const createValueBoundary = (scheduler, name, initial, equality) => {
|
|
|
1490
1697
|
},
|
|
1491
1698
|
publish: state.publish,
|
|
1492
1699
|
clear: () => {
|
|
1700
|
+
const failed = boundary.fault !== void 0;
|
|
1493
1701
|
state.clear();
|
|
1494
1702
|
pendingReset = false;
|
|
1495
1703
|
pendingCause = void 0;
|
|
1496
1704
|
contextCause = void 0;
|
|
1497
1705
|
recovering = false;
|
|
1706
|
+
clearSource(failed);
|
|
1498
1707
|
},
|
|
1499
1708
|
release: () => {
|
|
1500
1709
|
cleanup?.();
|
|
@@ -1530,9 +1739,6 @@ const createValueBoundary = (scheduler, name, initial, equality) => {
|
|
|
1530
1739
|
return {
|
|
1531
1740
|
producer: boundary,
|
|
1532
1741
|
output,
|
|
1533
|
-
setLatest: (value) => {
|
|
1534
|
-
latest = value;
|
|
1535
|
-
},
|
|
1536
1742
|
mark,
|
|
1537
1743
|
fail,
|
|
1538
1744
|
detach: (next) => {
|
|
@@ -1540,7 +1746,7 @@ const createValueBoundary = (scheduler, name, initial, equality) => {
|
|
|
1540
1746
|
}
|
|
1541
1747
|
};
|
|
1542
1748
|
};
|
|
1543
|
-
const createCollectionBoundary = (scheduler, name, readLatest, equality) => {
|
|
1749
|
+
const createCollectionBoundary = (scheduler, name, readLatest, equality, clearSource) => {
|
|
1544
1750
|
const state = require_advanced.createCollectionOutput();
|
|
1545
1751
|
let boundary;
|
|
1546
1752
|
let pendingReset = false;
|
|
@@ -1587,7 +1793,7 @@ const createCollectionBoundary = (scheduler, name, readLatest, equality) => {
|
|
|
1587
1793
|
contextCause = cause;
|
|
1588
1794
|
let active = true;
|
|
1589
1795
|
try {
|
|
1590
|
-
const changed = require_advanced.stageCollectionRead(state, readLatest(() => active), () => active, {
|
|
1796
|
+
const changed = require_advanced.stageCollectionRead(state, readLatest(() => active, state.current(() => void 0)), () => active, {
|
|
1591
1797
|
reset: pendingReset,
|
|
1592
1798
|
...fullScan ? {} : { candidates },
|
|
1593
1799
|
orderMayChange,
|
|
@@ -1604,6 +1810,7 @@ const createCollectionBoundary = (scheduler, name, readLatest, equality) => {
|
|
|
1604
1810
|
},
|
|
1605
1811
|
publish: state.publish,
|
|
1606
1812
|
clear: () => {
|
|
1813
|
+
const failed = boundary.fault !== void 0;
|
|
1607
1814
|
state.clear();
|
|
1608
1815
|
pendingReset = false;
|
|
1609
1816
|
pendingCause = void 0;
|
|
@@ -1612,6 +1819,7 @@ const createCollectionBoundary = (scheduler, name, readLatest, equality) => {
|
|
|
1612
1819
|
fullScan = false;
|
|
1613
1820
|
orderMayChange = false;
|
|
1614
1821
|
candidates.clear();
|
|
1822
|
+
clearSource(failed);
|
|
1615
1823
|
},
|
|
1616
1824
|
release: () => {
|
|
1617
1825
|
cleanup?.();
|
|
@@ -1623,7 +1831,7 @@ const createCollectionBoundary = (scheduler, name, readLatest, equality) => {
|
|
|
1623
1831
|
scheduler.initialize(() => {
|
|
1624
1832
|
let active = true;
|
|
1625
1833
|
try {
|
|
1626
|
-
require_advanced.stageCollectionRead(state, readLatest(() => active), () => active, {
|
|
1834
|
+
require_advanced.stageCollectionRead(state, readLatest(() => active, state.current(() => void 0)), () => active, {
|
|
1627
1835
|
reset: true,
|
|
1628
1836
|
isEqual: equality
|
|
1629
1837
|
});
|
|
@@ -1659,6 +1867,109 @@ const createCollectionBoundary = (scheduler, name, readLatest, equality) => {
|
|
|
1659
1867
|
}
|
|
1660
1868
|
};
|
|
1661
1869
|
};
|
|
1870
|
+
const documentRootTarget = Object.freeze({
|
|
1871
|
+
kind: "value",
|
|
1872
|
+
at: Object.freeze([])
|
|
1873
|
+
});
|
|
1874
|
+
const createCollectionPending = () => ({
|
|
1875
|
+
reset: false,
|
|
1876
|
+
order: false,
|
|
1877
|
+
entries: /* @__PURE__ */ new Map()
|
|
1878
|
+
});
|
|
1879
|
+
const resetCollectionPending = (pending) => {
|
|
1880
|
+
pending.reset = true;
|
|
1881
|
+
pending.order = false;
|
|
1882
|
+
pending.entries.clear();
|
|
1883
|
+
};
|
|
1884
|
+
const clearCollectionPending = (pending) => {
|
|
1885
|
+
pending.reset = false;
|
|
1886
|
+
pending.order = false;
|
|
1887
|
+
pending.entries.clear();
|
|
1888
|
+
};
|
|
1889
|
+
const dirtyEntry = (pending, key) => {
|
|
1890
|
+
let dirty = pending.entries.get(key);
|
|
1891
|
+
if (!dirty) {
|
|
1892
|
+
dirty = createDocumentDirty();
|
|
1893
|
+
pending.entries.set(key, dirty);
|
|
1894
|
+
}
|
|
1895
|
+
return dirty;
|
|
1896
|
+
};
|
|
1897
|
+
const mergeValueChanges = (selector, dirty, changes) => {
|
|
1898
|
+
if (selector.tree) return;
|
|
1899
|
+
const at = selector.address;
|
|
1900
|
+
for (const change of changes.changes) {
|
|
1901
|
+
if (change.kind === "reset") {
|
|
1902
|
+
markDocumentReplace(dirty, []);
|
|
1903
|
+
return;
|
|
1904
|
+
}
|
|
1905
|
+
if (change.kind === "members") {
|
|
1906
|
+
for (const member of change.members) {
|
|
1907
|
+
const changed = [...change.at, member.key];
|
|
1908
|
+
if (require_issue.contains(changed, at)) markDocumentReplace(dirty, []);
|
|
1909
|
+
else if (require_issue.contains(at, changed)) markDocumentReplace(dirty, changed.slice(at.length));
|
|
1910
|
+
}
|
|
1911
|
+
if (change.order && require_issue.contains(at, change.at)) markDocumentOrder(dirty, change.at.slice(at.length));
|
|
1912
|
+
continue;
|
|
1913
|
+
}
|
|
1914
|
+
if (require_issue.contains(at, change.at)) markDocumentTree(dirty, change.at.slice(at.length), change.before !== change.after, change.nodes.map((node) => node.id));
|
|
1915
|
+
}
|
|
1916
|
+
};
|
|
1917
|
+
const mergeCollectionChanges = (selector, pending, changes) => {
|
|
1918
|
+
if (pending.reset) return;
|
|
1919
|
+
const at = selector.address;
|
|
1920
|
+
for (const change of changes.changes) {
|
|
1921
|
+
if (change.kind === "reset") {
|
|
1922
|
+
resetCollectionPending(pending);
|
|
1923
|
+
return;
|
|
1924
|
+
}
|
|
1925
|
+
if (selector.tree?.kind === "nodes") {
|
|
1926
|
+
if (change.kind === "members") {
|
|
1927
|
+
for (const member of change.members) if (require_issue.contains([...change.at, member.key], at)) {
|
|
1928
|
+
resetCollectionPending(pending);
|
|
1929
|
+
return;
|
|
1930
|
+
}
|
|
1931
|
+
} else if (change.at.length === at.length && require_issue.contains(change.at, at)) for (const node of change.nodes) {
|
|
1932
|
+
markDocumentReplace(dirtyEntry(pending, node.id), []);
|
|
1933
|
+
pending.order ||= node.kind !== "updated";
|
|
1934
|
+
}
|
|
1935
|
+
else if (require_issue.contains(change.at, at)) {
|
|
1936
|
+
resetCollectionPending(pending);
|
|
1937
|
+
return;
|
|
1938
|
+
}
|
|
1939
|
+
continue;
|
|
1940
|
+
}
|
|
1941
|
+
if (change.kind === "members") {
|
|
1942
|
+
for (const member of change.members) {
|
|
1943
|
+
const changed = [...change.at, member.key];
|
|
1944
|
+
if (require_issue.contains(changed, at)) {
|
|
1945
|
+
resetCollectionPending(pending);
|
|
1946
|
+
return;
|
|
1947
|
+
}
|
|
1948
|
+
if (!require_issue.contains(at, changed)) continue;
|
|
1949
|
+
const relative = changed.slice(at.length);
|
|
1950
|
+
if (!relative.length) {
|
|
1951
|
+
resetCollectionPending(pending);
|
|
1952
|
+
return;
|
|
1953
|
+
}
|
|
1954
|
+
markDocumentReplace(dirtyEntry(pending, relative[0]), relative.slice(1));
|
|
1955
|
+
if (relative.length === 1 && member.kind !== "updated") pending.order = true;
|
|
1956
|
+
}
|
|
1957
|
+
if (change.order && require_issue.contains(at, change.at)) {
|
|
1958
|
+
const relative = change.at.slice(at.length);
|
|
1959
|
+
if (!relative.length) pending.order = true;
|
|
1960
|
+
else markDocumentOrder(dirtyEntry(pending, relative[0]), relative.slice(1));
|
|
1961
|
+
}
|
|
1962
|
+
continue;
|
|
1963
|
+
}
|
|
1964
|
+
if (!require_issue.contains(at, change.at)) continue;
|
|
1965
|
+
const relative = change.at.slice(at.length);
|
|
1966
|
+
if (!relative.length) {
|
|
1967
|
+
resetCollectionPending(pending);
|
|
1968
|
+
return;
|
|
1969
|
+
}
|
|
1970
|
+
markDocumentTree(dirtyEntry(pending, relative[0]), relative.slice(1), change.before !== change.after, change.nodes.map((node) => node.id));
|
|
1971
|
+
}
|
|
1972
|
+
};
|
|
1662
1973
|
const createSourceRegistry = (scheduler) => {
|
|
1663
1974
|
const documents = /* @__PURE__ */ new Map();
|
|
1664
1975
|
const readables = /* @__PURE__ */ new Map();
|
|
@@ -1670,6 +1981,8 @@ const createSourceRegistry = (scheduler) => {
|
|
|
1670
1981
|
if (cached) return cached;
|
|
1671
1982
|
if (state.disposed) throw new Error("Document has been disposed.");
|
|
1672
1983
|
const bindings = /* @__PURE__ */ new Set();
|
|
1984
|
+
const index = new require_access.SubscriptionIndex(state.schema);
|
|
1985
|
+
const candidates = /* @__PURE__ */ new Set();
|
|
1673
1986
|
const guard = (locked) => {
|
|
1674
1987
|
state.projectionLocks = (state.projectionLocks ?? 0) + (locked ? 1 : -1);
|
|
1675
1988
|
};
|
|
@@ -1680,11 +1993,13 @@ const createSourceRegistry = (scheduler) => {
|
|
|
1680
1993
|
add(binding) {
|
|
1681
1994
|
if (closed) throw new Error("Document projection connection is closed.");
|
|
1682
1995
|
bindings.add(binding);
|
|
1996
|
+
index.add(binding.target, binding);
|
|
1683
1997
|
let active = true;
|
|
1684
1998
|
return () => {
|
|
1685
1999
|
if (!active) return;
|
|
1686
2000
|
active = false;
|
|
1687
2001
|
bindings.delete(binding);
|
|
2002
|
+
index.delete(binding.target, binding);
|
|
1688
2003
|
if (!bindings.size) connection.close();
|
|
1689
2004
|
};
|
|
1690
2005
|
},
|
|
@@ -1693,13 +2008,17 @@ const createSourceRegistry = (scheduler) => {
|
|
|
1693
2008
|
closed = true;
|
|
1694
2009
|
detach();
|
|
1695
2010
|
bindings.clear();
|
|
2011
|
+
candidates.clear();
|
|
2012
|
+
index.clear();
|
|
1696
2013
|
scheduler.guards.delete(guard);
|
|
1697
2014
|
documents.delete(state);
|
|
1698
2015
|
}
|
|
1699
2016
|
};
|
|
1700
2017
|
detach = require_notification.attachProjection(runtime, {
|
|
1701
2018
|
capture: (commit) => {
|
|
1702
|
-
|
|
2019
|
+
candidates.clear();
|
|
2020
|
+
index.collect(commit.changes, (binding) => candidates.add(binding));
|
|
2021
|
+
candidates.forEach((binding) => binding.capture(commit));
|
|
1703
2022
|
},
|
|
1704
2023
|
settle: scheduler.settle,
|
|
1705
2024
|
flush: scheduler.flush,
|
|
@@ -1714,14 +2033,15 @@ const createSourceRegistry = (scheduler) => {
|
|
|
1714
2033
|
const valueInput = (definition) => {
|
|
1715
2034
|
if (definition.source.kind !== "value-input") throw new Error("Invalid value input source.");
|
|
1716
2035
|
const source = definition.source;
|
|
1717
|
-
|
|
2036
|
+
let latest = source.initial;
|
|
2037
|
+
const boundary = createValueBoundary(scheduler, "projection input", source.initial, source.equality, () => latest, () => void 0);
|
|
1718
2038
|
return {
|
|
1719
2039
|
...boundary,
|
|
1720
2040
|
write: {
|
|
1721
2041
|
kind: "value",
|
|
1722
2042
|
set(value) {
|
|
1723
2043
|
scheduler.assertIdle();
|
|
1724
|
-
|
|
2044
|
+
latest = value;
|
|
1725
2045
|
boundary.mark();
|
|
1726
2046
|
scheduler.run();
|
|
1727
2047
|
}
|
|
@@ -1731,7 +2051,7 @@ const createSourceRegistry = (scheduler) => {
|
|
|
1731
2051
|
const collectionInput = (definition) => {
|
|
1732
2052
|
if (definition.source.kind !== "collection-input") throw new Error("Invalid collection input source.");
|
|
1733
2053
|
const values = new Map(definition.source.initial);
|
|
1734
|
-
const boundary = createCollectionBoundary(scheduler, "projection collection input", () => require_advanced.mapRead(values), definition.output.equality);
|
|
2054
|
+
const boundary = createCollectionBoundary(scheduler, "projection collection input", () => require_advanced.mapRead(values), definition.output.equality, () => void 0);
|
|
1735
2055
|
return {
|
|
1736
2056
|
...boundary,
|
|
1737
2057
|
write: {
|
|
@@ -1807,87 +2127,131 @@ const createSourceRegistry = (scheduler) => {
|
|
|
1807
2127
|
}
|
|
1808
2128
|
};
|
|
1809
2129
|
};
|
|
1810
|
-
const
|
|
1811
|
-
if (definition.source.kind !== "document
|
|
2130
|
+
const documentSource = (definition) => {
|
|
2131
|
+
if (definition.source.kind !== "document") throw new Error("Invalid document source.");
|
|
1812
2132
|
const { document, selector } = definition.source;
|
|
1813
2133
|
const state = require_access.accessOf(document);
|
|
1814
|
-
const
|
|
1815
|
-
const
|
|
1816
|
-
const
|
|
2134
|
+
const schemaNode = () => require_issue.nodeAt(state.schema, selector.address, state.document);
|
|
2135
|
+
const currentValue = () => require_issue.read(state.document, selector.address, state.schema);
|
|
2136
|
+
const disposed = () => {
|
|
1817
2137
|
if (state.disposed) throw new Error("Document has been disposed.");
|
|
1818
|
-
const node = schemaNode();
|
|
1819
|
-
if (!node) return void 0;
|
|
1820
|
-
return require_access.copyValue(node, selector ? require_issue.read(state.document, address, state.schema) : state.document);
|
|
1821
2138
|
};
|
|
1822
|
-
|
|
1823
|
-
const
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
2139
|
+
if (selector.kind === "value") {
|
|
2140
|
+
const dirty = createDocumentDirty();
|
|
2141
|
+
const read = (previous) => {
|
|
2142
|
+
disposed();
|
|
2143
|
+
const node = schemaNode();
|
|
2144
|
+
const current = currentValue();
|
|
2145
|
+
if (selector.tree?.kind === "root") return node?.kind === "tree" && require_issue.isRecord(current) && typeof current.rootId === "string" ? current.rootId : void 0;
|
|
2146
|
+
if (selector.tree?.kind === "node") {
|
|
2147
|
+
if (node?.kind !== "tree" || !require_issue.isRecord(current) || !require_issue.isRecord(current.nodes)) return void 0;
|
|
2148
|
+
const entry = Object.hasOwn(current.nodes, selector.tree.id) ? current.nodes[selector.tree.id] : void 0;
|
|
2149
|
+
if (require_access.equalTreeNode(previous, entry)) return previous;
|
|
2150
|
+
return entry ? require_access.copyTreeNode(entry) : void 0;
|
|
1834
2151
|
}
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
2152
|
+
if (!node) return void 0;
|
|
2153
|
+
return previous === void 0 ? require_access.copyValue(node, current) : materializeDocumentValue(node, previous, current, dirty);
|
|
2154
|
+
};
|
|
2155
|
+
const initial = read();
|
|
2156
|
+
let boundary;
|
|
2157
|
+
boundary = createValueBoundary(scheduler, "document source", initial, Object.is, (previous) => read(previous), (failed) => {
|
|
2158
|
+
if (failed) markDocumentReplace(dirty, []);
|
|
2159
|
+
else clearDocumentDirty(dirty);
|
|
2160
|
+
});
|
|
2161
|
+
const remove = documentConnection(document).add({
|
|
2162
|
+
target: selector,
|
|
2163
|
+
capture: (commit) => {
|
|
2164
|
+
try {
|
|
2165
|
+
mergeValueChanges(selector, dirty, commit.changes);
|
|
2166
|
+
boundary.mark({ reset: commit.changes.changes.some((change) => change.kind === "reset") });
|
|
2167
|
+
} catch (cause) {
|
|
2168
|
+
boundary.fail(cause);
|
|
2169
|
+
}
|
|
2170
|
+
},
|
|
2171
|
+
dispose: () => boundary.fail(/* @__PURE__ */ new Error("Document has been disposed."))
|
|
2172
|
+
});
|
|
2173
|
+
boundary.detach(remove);
|
|
2174
|
+
return boundary;
|
|
2175
|
+
}
|
|
2176
|
+
const pending = createCollectionPending();
|
|
2177
|
+
const read = (active, previous) => {
|
|
2178
|
+
disposed();
|
|
2179
|
+
const node = schemaNode();
|
|
2180
|
+
const value = currentValue();
|
|
2181
|
+
const treeNodes = selector.tree?.kind === "nodes";
|
|
2182
|
+
const entryNode = !treeNodes && node ? require_advanced.collectionEntryNode(node) : void 0;
|
|
1851
2183
|
const snapshots = /* @__PURE__ */ new Map();
|
|
2184
|
+
const replacement = createDocumentDirty();
|
|
2185
|
+
if (pending.reset) markDocumentReplace(replacement, []);
|
|
2186
|
+
const ids = () => {
|
|
2187
|
+
require_advanced.assertScope(active);
|
|
2188
|
+
if (treeNodes) return node?.kind === "tree" && require_issue.isRecord(value) && require_issue.isRecord(value.nodes) ? Object.freeze(Object.keys(value.nodes)) : Object.freeze([]);
|
|
2189
|
+
if (node?.kind === "map" && require_issue.isRecord(value)) return Object.freeze(Object.keys(value));
|
|
2190
|
+
if (node?.kind === "table" && require_issue.isRecord(value) && Array.isArray(value.ids)) return Object.freeze([...value.ids]);
|
|
2191
|
+
if (node?.kind === "list" && Array.isArray(value)) return Object.freeze(require_issue.toArray(require_issue.indexedKeys(value, node.keyOf)));
|
|
2192
|
+
return Object.freeze([]);
|
|
2193
|
+
};
|
|
2194
|
+
const has = (key) => {
|
|
2195
|
+
require_advanced.assertScope(active);
|
|
2196
|
+
if (treeNodes) return Boolean(node?.kind === "tree" && require_issue.isRecord(value) && require_issue.isRecord(value.nodes) && Object.hasOwn(value.nodes, key));
|
|
2197
|
+
if (node?.kind === "map" && require_issue.isRecord(value)) return Object.hasOwn(value, key);
|
|
2198
|
+
if (node?.kind === "table" && require_issue.isRecord(value) && require_issue.isRecord(value.byId)) return Object.hasOwn(value.byId, key);
|
|
2199
|
+
if (node?.kind === "list" && Array.isArray(value)) return require_issue.indexedKeys(value, node.keyOf).index(key) >= 0;
|
|
2200
|
+
return false;
|
|
2201
|
+
};
|
|
2202
|
+
const raw = (key) => {
|
|
2203
|
+
if (treeNodes) {
|
|
2204
|
+
if (node?.kind !== "tree" || !require_issue.isRecord(value) || !require_issue.isRecord(value.nodes)) return void 0;
|
|
2205
|
+
return Object.hasOwn(value.nodes, key) ? value.nodes[key] : void 0;
|
|
2206
|
+
}
|
|
2207
|
+
if (node?.kind === "map" && require_issue.isRecord(value)) return Object.hasOwn(value, key) ? value[key] : void 0;
|
|
2208
|
+
if (node?.kind === "table" && require_issue.isRecord(value) && require_issue.isRecord(value.byId)) return Object.hasOwn(value.byId, key) ? value.byId[key] : void 0;
|
|
2209
|
+
if (node?.kind === "list" && Array.isArray(value)) {
|
|
2210
|
+
const index = require_issue.indexedKeys(value, node.keyOf).index(key);
|
|
2211
|
+
return index < 0 ? void 0 : value[index];
|
|
2212
|
+
}
|
|
2213
|
+
};
|
|
1852
2214
|
return Object.freeze({
|
|
1853
2215
|
get: (key) => {
|
|
1854
2216
|
require_advanced.assertScope(active);
|
|
1855
|
-
if (!snapshots.has(key)) snapshots.set(key,
|
|
2217
|
+
if (!snapshots.has(key)) if (!has(key)) snapshots.set(key, void 0);
|
|
2218
|
+
else {
|
|
2219
|
+
const current = raw(key);
|
|
2220
|
+
if (treeNodes) {
|
|
2221
|
+
const entry = current;
|
|
2222
|
+
const before = previous.has(key) ? previous.get(key) : void 0;
|
|
2223
|
+
snapshots.set(key, require_access.equalTreeNode(before, entry) ? before : require_access.copyTreeNode(entry));
|
|
2224
|
+
} else if (!entryNode) snapshots.set(key, current);
|
|
2225
|
+
else if (!previous.has(key)) snapshots.set(key, require_access.copyValue(entryNode, current));
|
|
2226
|
+
else {
|
|
2227
|
+
const dirty = pending.entries.get(key) ?? (pending.reset ? replacement : void 0);
|
|
2228
|
+
snapshots.set(key, dirty ? materializeDocumentValue(entryNode, previous.get(key), current, dirty) : previous.get(key));
|
|
2229
|
+
}
|
|
2230
|
+
}
|
|
1856
2231
|
return snapshots.get(key);
|
|
1857
2232
|
},
|
|
1858
|
-
has
|
|
1859
|
-
|
|
1860
|
-
return raw.has(key);
|
|
1861
|
-
},
|
|
1862
|
-
ids: () => {
|
|
1863
|
-
require_advanced.assertScope(active);
|
|
1864
|
-
return raw.ids();
|
|
1865
|
-
}
|
|
2233
|
+
has,
|
|
2234
|
+
ids
|
|
1866
2235
|
});
|
|
1867
2236
|
};
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
return entry ? require_access.equalValue(entry, left, right) : Object.is(left, right);
|
|
2237
|
+
let boundary;
|
|
2238
|
+
boundary = createCollectionBoundary(scheduler, "document collection source", read, Object.is, (failed) => {
|
|
2239
|
+
if (failed) resetCollectionPending(pending);
|
|
2240
|
+
else clearCollectionPending(pending);
|
|
1873
2241
|
});
|
|
1874
2242
|
const remove = documentConnection(document).add({
|
|
1875
|
-
|
|
2243
|
+
target: selector,
|
|
1876
2244
|
capture: (commit) => {
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
boundary.mark({
|
|
1880
|
-
|
|
2245
|
+
try {
|
|
2246
|
+
mergeCollectionChanges(selector, pending, commit.changes);
|
|
2247
|
+
boundary.mark({
|
|
2248
|
+
reset: pending.reset,
|
|
2249
|
+
...pending.reset ? {} : { candidates: pending.entries.keys() },
|
|
2250
|
+
orderMayChange: pending.order
|
|
2251
|
+
});
|
|
2252
|
+
} catch (cause) {
|
|
2253
|
+
boundary.fail(cause);
|
|
1881
2254
|
}
|
|
1882
|
-
const candidates = new Set([
|
|
1883
|
-
...impact.added,
|
|
1884
|
-
...impact.updated,
|
|
1885
|
-
...impact.removed
|
|
1886
|
-
]);
|
|
1887
|
-
boundary.mark({
|
|
1888
|
-
candidates,
|
|
1889
|
-
orderMayChange: Boolean(impact.added.size || impact.removed.size || impact.orderChanged)
|
|
1890
|
-
});
|
|
1891
2255
|
},
|
|
1892
2256
|
dispose: () => boundary.fail(/* @__PURE__ */ new Error("Document has been disposed."))
|
|
1893
2257
|
});
|
|
@@ -1897,13 +2261,12 @@ const createSourceRegistry = (scheduler) => {
|
|
|
1897
2261
|
const readable = (definition) => {
|
|
1898
2262
|
if (definition.source.kind !== "readable") throw new Error("Invalid Readable source.");
|
|
1899
2263
|
const { readable, equality } = definition.source;
|
|
1900
|
-
let
|
|
1901
|
-
const boundary = createValueBoundary(scheduler, "external readable",
|
|
2264
|
+
let latest = readable.current();
|
|
2265
|
+
const boundary = createValueBoundary(scheduler, "external readable", latest, equality, () => latest, () => void 0);
|
|
1902
2266
|
const member = {
|
|
1903
2267
|
boundary,
|
|
1904
2268
|
receive(value, metadata) {
|
|
1905
|
-
|
|
1906
|
-
boundary.setLatest(value);
|
|
2269
|
+
latest = value;
|
|
1907
2270
|
boundary.mark(metadata);
|
|
1908
2271
|
}
|
|
1909
2272
|
};
|
|
@@ -1935,7 +2298,7 @@ const createSourceRegistry = (scheduler) => {
|
|
|
1935
2298
|
};
|
|
1936
2299
|
const owner = require_notification.documentReadableOwner(readable);
|
|
1937
2300
|
if (owner) detachDocument = documentConnection(owner).add({
|
|
1938
|
-
|
|
2301
|
+
target: documentRootTarget,
|
|
1939
2302
|
capture: () => receive(false),
|
|
1940
2303
|
dispose: () => {
|
|
1941
2304
|
members.forEach((next) => next.boundary.fail(/* @__PURE__ */ new Error("Document has been disposed.")));
|
|
@@ -1955,11 +2318,12 @@ const createSourceRegistry = (scheduler) => {
|
|
|
1955
2318
|
const externalValue = (definition) => {
|
|
1956
2319
|
if (definition.source.kind !== "external-value") throw new Error("Invalid external value source.");
|
|
1957
2320
|
const { source, equality } = definition.source;
|
|
1958
|
-
|
|
2321
|
+
let latest = source.current();
|
|
2322
|
+
const boundary = createValueBoundary(scheduler, "external source", latest, equality, () => latest, () => void 0);
|
|
1959
2323
|
const member = {
|
|
1960
2324
|
boundary,
|
|
1961
2325
|
receive(value, metadata) {
|
|
1962
|
-
|
|
2326
|
+
latest = value;
|
|
1963
2327
|
boundary.mark(metadata);
|
|
1964
2328
|
}
|
|
1965
2329
|
};
|
|
@@ -2013,7 +2377,7 @@ const createSourceRegistry = (scheduler) => {
|
|
|
2013
2377
|
has: (key) => current.has(key),
|
|
2014
2378
|
ids: () => current.ids()
|
|
2015
2379
|
});
|
|
2016
|
-
}, definition.output.equality);
|
|
2380
|
+
}, definition.output.equality, () => void 0);
|
|
2017
2381
|
let connection = externalCollections.get(source);
|
|
2018
2382
|
if (!connection) {
|
|
2019
2383
|
const members = /* @__PURE__ */ new Set();
|
|
@@ -2076,8 +2440,7 @@ const createSourceRegistry = (scheduler) => {
|
|
|
2076
2440
|
switch (definition.source.kind) {
|
|
2077
2441
|
case "value-input": return valueInput(definition);
|
|
2078
2442
|
case "collection-input": return collectionInput(definition);
|
|
2079
|
-
case "document
|
|
2080
|
-
case "document-collection": return documentCollection(definition);
|
|
2443
|
+
case "document": return documentSource(definition);
|
|
2081
2444
|
case "readable": return readable(definition);
|
|
2082
2445
|
case "external-value": return externalValue(definition);
|
|
2083
2446
|
case "external-collection": return externalCollection(definition);
|