doxum 0.1.40 → 0.1.42
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 +36 -4
- 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-CNR6BS75.d.cts → contract-DovG1Yp-.d.cts} +2 -1
- package/dist/{contract-COgxO5sv.d.ts → contract-PqdXNaP8.d.ts} +2 -1
- package/dist/{dependency-DzxXGYe1.d.ts → dependency-BYiwTiBj.d.ts} +1 -1
- package/dist/{dependency-Cbf3C8eJ.d.cts → dependency-D0bo_xe_.d.cts} +1 -1
- package/dist/{driver-B7RR-VfX.js → driver-B7Hu6D0u.js} +15 -1
- package/dist/{driver-CN3dGxQI.cjs → driver-i4G4iVX0.cjs} +20 -0
- package/dist/index.cjs +257 -114
- package/dist/index.d.cts +4 -2
- package/dist/index.d.ts +4 -2
- package/dist/index.js +257 -114
- package/dist/local-sync.cjs +2 -5
- package/dist/local-sync.d.cts +1 -1
- package/dist/local-sync.d.ts +1 -1
- package/dist/local-sync.js +2 -5
- package/dist/react.cjs +38 -3
- package/dist/react.d.cts +19 -3
- package/dist/react.d.ts +19 -3
- package/dist/react.js +38 -4
- package/dist/{transform-8xXf0OKB.cjs → transform-BPh55GWO.cjs} +82 -48
- package/dist/{transform--WCn6_v0.js → transform-BvDYPUMm.js} +82 -48
- package/package.json +1 -1
- package/skills/doxum-runtime/references/integrations.md +38 -7
- package/skills/doxum-runtime/references/invariants.md +23 -0
- package/skills/doxum-runtime/references/projections.md +22 -0
- package/skills/doxum-runtime/references/public-api.md +27 -8
package/dist/index.cjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_transform = require("./transform-
|
|
2
|
+
const require_transform = require("./transform-BPh55GWO.cjs");
|
|
3
3
|
const require_record = require("./record-ChYUi8PP.cjs");
|
|
4
|
-
const require_driver = require("./driver-
|
|
4
|
+
const require_driver = require("./driver-i4G4iVX0.cjs");
|
|
5
5
|
//#region core/src/schema/model.ts
|
|
6
6
|
const schemaNodeOf = (schema) => schema;
|
|
7
7
|
const collectionEntryNode = (node) => node.kind === "map" || node.kind === "table" || node.kind === "list" ? node.value : void 0;
|
|
@@ -652,7 +652,7 @@ function remove$2(session, container, ids) {
|
|
|
652
652
|
for (const id of removed) session.writeMember(container, id, void 0, "remove");
|
|
653
653
|
table.ids = table.ids.filter((id) => !removed.has(id));
|
|
654
654
|
}
|
|
655
|
-
function replace$
|
|
655
|
+
function replace$4(session, container, id, value) {
|
|
656
656
|
const { at, node, value: tableValue } = container;
|
|
657
657
|
if (node.kind !== "table") return require_driver.fail(at, "invalid-collection", "Expected a table.");
|
|
658
658
|
const table = tableValue;
|
|
@@ -675,7 +675,7 @@ function insert$1(session, container, value, position) {
|
|
|
675
675
|
insert$2(items, index(keys$1, position), value);
|
|
676
676
|
session.invalidate();
|
|
677
677
|
}
|
|
678
|
-
function replace$
|
|
678
|
+
function replace$3(session, container, id, value) {
|
|
679
679
|
const { at, node, value: items } = container;
|
|
680
680
|
if (node.kind !== "list") return require_driver.fail(at, "invalid-list-key", "Expected a list.");
|
|
681
681
|
const index = indexedKeys(items, node.keyOf).index(id);
|
|
@@ -721,7 +721,7 @@ const insert = (session, container, id, value, position) => {
|
|
|
721
721
|
else tree.rootId = id;
|
|
722
722
|
session.invalidate();
|
|
723
723
|
};
|
|
724
|
-
const replace$
|
|
724
|
+
const replace$2 = (session, container, id, value) => {
|
|
725
725
|
const { at, node: schema, value: tree } = container;
|
|
726
726
|
const entry = node$1(tree, id);
|
|
727
727
|
if (!entry) return require_driver.fail(at, "missing-tree-node", "Tree node does not exist.");
|
|
@@ -1180,7 +1180,7 @@ const createAccess = (context, initial = []) => {
|
|
|
1180
1180
|
const [valueOrId, value] = args;
|
|
1181
1181
|
if (args.length === 1) return replaceCollection(target, node, valueOrId);
|
|
1182
1182
|
const writable = writableCollection(target, node);
|
|
1183
|
-
replace$
|
|
1183
|
+
replace$4(context.session, writable, valueOrId, value);
|
|
1184
1184
|
};
|
|
1185
1185
|
return orderedMethod(target, property, node);
|
|
1186
1186
|
};
|
|
@@ -1197,7 +1197,7 @@ const createAccess = (context, initial = []) => {
|
|
|
1197
1197
|
const [valueOrId, value] = args;
|
|
1198
1198
|
if (args.length === 1) return replaceCollection(target, node, valueOrId);
|
|
1199
1199
|
const writable = writableCollection(target, node);
|
|
1200
|
-
replace$
|
|
1200
|
+
replace$3(context.session, writable, valueOrId, value);
|
|
1201
1201
|
};
|
|
1202
1202
|
return orderedMethod(target, property, node);
|
|
1203
1203
|
};
|
|
@@ -1219,7 +1219,7 @@ const createAccess = (context, initial = []) => {
|
|
|
1219
1219
|
const [valueOrId, value] = args;
|
|
1220
1220
|
if (args.length === 1) return replaceCollection(target, node, valueOrId);
|
|
1221
1221
|
const writable = writableTree(target, node);
|
|
1222
|
-
replace$
|
|
1222
|
+
replace$2(context.session, writable, valueOrId, value);
|
|
1223
1223
|
};
|
|
1224
1224
|
const current = () => collectionValue(target, node);
|
|
1225
1225
|
if (property === "rootId") return () => {
|
|
@@ -1623,10 +1623,7 @@ const createHistory = (input) => {
|
|
|
1623
1623
|
revision: () => revision,
|
|
1624
1624
|
subscribe: (listener) => {
|
|
1625
1625
|
if (disposed) throw new DocumentDisposedError();
|
|
1626
|
-
|
|
1627
|
-
return () => {
|
|
1628
|
-
listeners.delete(listener);
|
|
1629
|
-
};
|
|
1626
|
+
return require_driver.addListener(listeners, listener);
|
|
1630
1627
|
},
|
|
1631
1628
|
undo: () => {
|
|
1632
1629
|
input.assertIdle();
|
|
@@ -2297,6 +2294,7 @@ const addRoot = (notification, listener) => {
|
|
|
2297
2294
|
};
|
|
2298
2295
|
notification.root.add(entry);
|
|
2299
2296
|
return () => {
|
|
2297
|
+
if (!entry.active) return;
|
|
2300
2298
|
entry.active = false;
|
|
2301
2299
|
if (!notification.notifying) notification.root.delete(entry);
|
|
2302
2300
|
else notification.cleanups.add(() => {
|
|
@@ -2670,7 +2668,9 @@ const select = (document, selector, equality = Object.is) => {
|
|
|
2670
2668
|
};
|
|
2671
2669
|
};
|
|
2672
2670
|
const installSubscription = () => {
|
|
2673
|
-
unsubscribeDocument
|
|
2671
|
+
const stop = unsubscribeDocument;
|
|
2672
|
+
unsubscribeDocument = void 0;
|
|
2673
|
+
stop?.();
|
|
2674
2674
|
unsubscribeDocument = dependencies.length > 0 ? context.notifications.subscribeTargets(dependencies, () => {
|
|
2675
2675
|
const result = evaluate();
|
|
2676
2676
|
if (result.rebound) installSubscription();
|
|
@@ -2690,15 +2690,22 @@ const select = (document, selector, equality = Object.is) => {
|
|
|
2690
2690
|
},
|
|
2691
2691
|
subscribe: (listener) => {
|
|
2692
2692
|
ensureCurrent();
|
|
2693
|
-
|
|
2694
|
-
if (listeners.size === 1) installSubscription();
|
|
2695
|
-
return () => {
|
|
2696
|
-
listeners.delete(listener);
|
|
2693
|
+
const unsubscribe = require_driver.addListener(listeners, listener, () => {
|
|
2697
2694
|
if (!listeners.size) {
|
|
2698
|
-
unsubscribeDocument
|
|
2695
|
+
const stop = unsubscribeDocument;
|
|
2699
2696
|
unsubscribeDocument = void 0;
|
|
2697
|
+
stop?.();
|
|
2700
2698
|
}
|
|
2701
|
-
};
|
|
2699
|
+
});
|
|
2700
|
+
try {
|
|
2701
|
+
if (listeners.size === 1) installSubscription();
|
|
2702
|
+
} catch (error) {
|
|
2703
|
+
try {
|
|
2704
|
+
unsubscribe();
|
|
2705
|
+
} catch {}
|
|
2706
|
+
throw error;
|
|
2707
|
+
}
|
|
2708
|
+
return unsubscribe;
|
|
2702
2709
|
}
|
|
2703
2710
|
});
|
|
2704
2711
|
};
|
|
@@ -3688,6 +3695,33 @@ function createValueDerive(dependencies, compute, equality = Object.is) {
|
|
|
3688
3695
|
}
|
|
3689
3696
|
const derive = Object.assign(createValueDerive, { keyed: keyedDerive });
|
|
3690
3697
|
//#endregion
|
|
3698
|
+
//#region core/src/projection/cleanup.ts
|
|
3699
|
+
/** Owner-local, cancellable LIFO callbacks. Lifecycle admission stays with the owner. */
|
|
3700
|
+
const createCleanupStack = () => {
|
|
3701
|
+
const entries = /* @__PURE__ */ new Set();
|
|
3702
|
+
return {
|
|
3703
|
+
add(callback) {
|
|
3704
|
+
const entry = () => {
|
|
3705
|
+
require_transform.assertSynchronous(callback());
|
|
3706
|
+
};
|
|
3707
|
+
entries.add(entry);
|
|
3708
|
+
return () => {
|
|
3709
|
+
entries.delete(entry);
|
|
3710
|
+
};
|
|
3711
|
+
},
|
|
3712
|
+
drain(failures) {
|
|
3713
|
+
for (const entry of [...entries].reverse()) {
|
|
3714
|
+
if (!entries.delete(entry)) continue;
|
|
3715
|
+
try {
|
|
3716
|
+
entry();
|
|
3717
|
+
} catch (error) {
|
|
3718
|
+
failures.push(error);
|
|
3719
|
+
}
|
|
3720
|
+
}
|
|
3721
|
+
}
|
|
3722
|
+
};
|
|
3723
|
+
};
|
|
3724
|
+
//#endregion
|
|
3691
3725
|
//#region core/src/projection/collection/changes.ts
|
|
3692
3726
|
/** Net transitions for one consumer's unconsumed interval; bounded by touched keys. */
|
|
3693
3727
|
const createCollectionChanges = () => {
|
|
@@ -3798,49 +3832,109 @@ const node = (key, value, left, right) => {
|
|
|
3798
3832
|
height: Math.max(height(left), height(right)) + 1
|
|
3799
3833
|
});
|
|
3800
3834
|
};
|
|
3801
|
-
|
|
3802
|
-
|
|
3803
|
-
|
|
3804
|
-
|
|
3805
|
-
|
|
3806
|
-
|
|
3807
|
-
|
|
3808
|
-
}
|
|
3809
|
-
|
|
3810
|
-
|
|
3811
|
-
|
|
3812
|
-
|
|
3813
|
-
return
|
|
3814
|
-
}
|
|
3815
|
-
|
|
3816
|
-
|
|
3817
|
-
|
|
3818
|
-
|
|
3819
|
-
|
|
3820
|
-
|
|
3821
|
-
|
|
3822
|
-
|
|
3823
|
-
if (
|
|
3824
|
-
|
|
3825
|
-
|
|
3826
|
-
}
|
|
3827
|
-
|
|
3828
|
-
|
|
3829
|
-
|
|
3830
|
-
|
|
3831
|
-
if (key > current.key) return rebalance(node(current.key, current.value, current.left, removeNode(current.right, key)));
|
|
3835
|
+
/** Local repair after a join descent or a single deletion (height difference at most two). */
|
|
3836
|
+
const balance = (key, value, left, right) => {
|
|
3837
|
+
if (height(left) > height(right) + 1) {
|
|
3838
|
+
const heavy = left;
|
|
3839
|
+
if (height(heavy.left) >= height(heavy.right)) return node(heavy.key, heavy.value, heavy.left, node(key, value, heavy.right, right));
|
|
3840
|
+
const middle = heavy.right;
|
|
3841
|
+
return node(middle.key, middle.value, node(heavy.key, heavy.value, heavy.left, middle.left), node(key, value, middle.right, right));
|
|
3842
|
+
}
|
|
3843
|
+
if (height(right) > height(left) + 1) {
|
|
3844
|
+
const heavy = right;
|
|
3845
|
+
if (height(heavy.right) >= height(heavy.left)) return node(heavy.key, heavy.value, node(key, value, left, heavy.left), heavy.right);
|
|
3846
|
+
const middle = heavy.left;
|
|
3847
|
+
return node(middle.key, middle.value, node(key, value, left, middle.left), node(heavy.key, heavy.value, middle.right, heavy.right));
|
|
3848
|
+
}
|
|
3849
|
+
return node(key, value, left, right);
|
|
3850
|
+
};
|
|
3851
|
+
/** All left keys precede key, all right keys follow it; heights may differ arbitrarily. */
|
|
3852
|
+
const join = (key, value, left, right) => {
|
|
3853
|
+
if (height(left) > height(right) + 1) {
|
|
3854
|
+
require_transform.profile.collectionIndex.visit();
|
|
3855
|
+
return balance(left.key, left.value, left.left, join(key, value, left.right, right));
|
|
3856
|
+
}
|
|
3857
|
+
if (height(right) > height(left) + 1) {
|
|
3858
|
+
require_transform.profile.collectionIndex.visit();
|
|
3859
|
+
return balance(right.key, right.value, join(key, value, left, right.left), right.right);
|
|
3860
|
+
}
|
|
3861
|
+
return node(key, value, left, right);
|
|
3862
|
+
};
|
|
3863
|
+
const removeMin = (current) => {
|
|
3864
|
+
require_transform.profile.collectionIndex.visit();
|
|
3832
3865
|
if (!current.left) return current.right;
|
|
3833
|
-
|
|
3834
|
-
|
|
3835
|
-
|
|
3866
|
+
return balance(current.key, current.value, removeMin(current.left), current.right);
|
|
3867
|
+
};
|
|
3868
|
+
const concat = (left, right) => {
|
|
3869
|
+
if (!left) return right;
|
|
3870
|
+
if (!right) return left;
|
|
3871
|
+
let first = right;
|
|
3872
|
+
while (first.left) {
|
|
3873
|
+
require_transform.profile.collectionIndex.visit();
|
|
3874
|
+
first = first.left;
|
|
3875
|
+
}
|
|
3876
|
+
return join(first.key, first.value, left, removeMin(right));
|
|
3877
|
+
};
|
|
3878
|
+
const replace$1 = (current, entry, left, right) => {
|
|
3879
|
+
if (entry && !entry.present) return concat(left, right);
|
|
3880
|
+
const value = entry ? entry.value : current.value;
|
|
3881
|
+
if (left === current.left && right === current.right && Object.is(value, current.value)) return current;
|
|
3882
|
+
return join(current.key, value, left, right);
|
|
3883
|
+
};
|
|
3884
|
+
const edit = (current, key, entry) => {
|
|
3885
|
+
if (!current) return entry.present ? node(key, entry.value) : void 0;
|
|
3886
|
+
require_transform.profile.collectionIndex.visit();
|
|
3887
|
+
if (key === current.key) return replace$1(current, entry, current.left, current.right);
|
|
3888
|
+
if (key < current.key) {
|
|
3889
|
+
const left = edit(current.left, key, entry);
|
|
3890
|
+
return left === current.left ? current : balance(current.key, current.value, left, current.right);
|
|
3891
|
+
}
|
|
3892
|
+
const right = edit(current.right, key, entry);
|
|
3893
|
+
return right === current.right ? current : balance(current.key, current.value, current.left, right);
|
|
3894
|
+
};
|
|
3895
|
+
/** Builds a new subtree in linear time, ignoring removals of absent keys. */
|
|
3896
|
+
const buildChanges = (keys, changes, start, end) => {
|
|
3897
|
+
let count = 0;
|
|
3898
|
+
for (let i = start; i < end; i++) if (changes.get(keys[i]).present) count++;
|
|
3899
|
+
let cursor = start;
|
|
3900
|
+
const build = (size) => {
|
|
3901
|
+
if (!size) return void 0;
|
|
3902
|
+
const leftSize = size >> 1;
|
|
3903
|
+
const left = build(leftSize);
|
|
3904
|
+
let key;
|
|
3905
|
+
let entry;
|
|
3906
|
+
do {
|
|
3907
|
+
key = keys[cursor++];
|
|
3908
|
+
entry = changes.get(key);
|
|
3909
|
+
} while (!entry.present);
|
|
3910
|
+
return node(key, entry.value, left, build(size - leftSize - 1));
|
|
3911
|
+
};
|
|
3912
|
+
return build(count);
|
|
3913
|
+
};
|
|
3914
|
+
const applyChanges = (current, keys, changes, start, end) => {
|
|
3915
|
+
if (start === end) return current;
|
|
3916
|
+
if (end - start === 1) return edit(current, keys[start], changes.get(keys[start]));
|
|
3917
|
+
if (!current) return buildChanges(keys, changes, start, end);
|
|
3918
|
+
require_transform.profile.collectionIndex.visit();
|
|
3919
|
+
let low = start;
|
|
3920
|
+
let high = end;
|
|
3921
|
+
while (low < high) {
|
|
3922
|
+
const middle = low + high >>> 1;
|
|
3923
|
+
if (keys[middle] < current.key) low = middle + 1;
|
|
3924
|
+
else high = middle;
|
|
3925
|
+
}
|
|
3926
|
+
const matched = low < end && keys[low] === current.key;
|
|
3927
|
+
const left = applyChanges(current.left, keys, changes, start, low);
|
|
3928
|
+
const right = applyChanges(current.right, keys, changes, matched ? low + 1 : low, end);
|
|
3929
|
+
return replace$1(current, matched ? changes.get(current.key) : void 0, left, right);
|
|
3836
3930
|
};
|
|
3837
3931
|
const fromSorted = (entries, start = 0, end = entries.length) => {
|
|
3838
3932
|
if (start >= end) return void 0;
|
|
3839
|
-
const middle = start + end
|
|
3933
|
+
const middle = start + end >>> 1;
|
|
3840
3934
|
const [key, value] = entries[middle];
|
|
3841
3935
|
return node(key, value, fromSorted(entries, start, middle), fromSorted(entries, middle + 1, end));
|
|
3842
3936
|
};
|
|
3843
|
-
/** Immutable keyed lookup used to keep
|
|
3937
|
+
/** Immutable keyed lookup used to keep collection snapshots durable across revisions. */
|
|
3844
3938
|
var PersistentKeyedIndex = class PersistentKeyedIndex {
|
|
3845
3939
|
constructor(root) {
|
|
3846
3940
|
this.root = root;
|
|
@@ -3848,6 +3942,7 @@ var PersistentKeyedIndex = class PersistentKeyedIndex {
|
|
|
3848
3942
|
static empty() {
|
|
3849
3943
|
return new PersistentKeyedIndex();
|
|
3850
3944
|
}
|
|
3945
|
+
/** The input must contain unique keys. Formal collection order is owned separately. */
|
|
3851
3946
|
static from(entries) {
|
|
3852
3947
|
const sorted = [...entries].sort(([left], [right]) => left < right ? -1 : left > right ? 1 : 0);
|
|
3853
3948
|
require_transform.profile.collectionIndex.build(sorted.length);
|
|
@@ -3868,11 +3963,19 @@ var PersistentKeyedIndex = class PersistentKeyedIndex {
|
|
|
3868
3963
|
}
|
|
3869
3964
|
return false;
|
|
3870
3965
|
}
|
|
3871
|
-
|
|
3872
|
-
|
|
3873
|
-
|
|
3874
|
-
|
|
3875
|
-
|
|
3966
|
+
/** Applies accepted final entry intents together; never calls user equality or changes old roots. */
|
|
3967
|
+
apply(changes) {
|
|
3968
|
+
if (!changes.size) return this;
|
|
3969
|
+
require_transform.profile.collectionIndex.batch(changes.size > 1 ? changes.size : 0);
|
|
3970
|
+
let root;
|
|
3971
|
+
if (changes.size === 1) {
|
|
3972
|
+
const [key, entry] = changes.entries().next().value;
|
|
3973
|
+
root = edit(this.root, key, entry);
|
|
3974
|
+
} else {
|
|
3975
|
+
const keys = [...changes.keys()].sort();
|
|
3976
|
+
root = applyChanges(this.root, keys, changes, 0, keys.length);
|
|
3977
|
+
}
|
|
3978
|
+
return root === this.root ? this : new PersistentKeyedIndex(root);
|
|
3876
3979
|
}
|
|
3877
3980
|
};
|
|
3878
3981
|
//#endregion
|
|
@@ -3910,10 +4013,11 @@ const createCollectionState = (initial) => {
|
|
|
3910
4013
|
values.clear();
|
|
3911
4014
|
for (const [key, entry] of staged) if (entry.present) values.set(key, entry.value);
|
|
3912
4015
|
if (index) index = PersistentKeyedIndex.from(values);
|
|
3913
|
-
} else
|
|
3914
|
-
|
|
3915
|
-
if (entry.present) values.set(key, entry.value);
|
|
4016
|
+
} else {
|
|
4017
|
+
const nextIndex = index?.apply(staged);
|
|
4018
|
+
for (const [key, entry] of staged) if (entry.present) values.set(key, entry.value);
|
|
3916
4019
|
else values.delete(key);
|
|
4020
|
+
index = nextIndex;
|
|
3917
4021
|
}
|
|
3918
4022
|
ids = nextIds;
|
|
3919
4023
|
},
|
|
@@ -4139,8 +4243,7 @@ const createCollectionOutput = (binding) => {
|
|
|
4139
4243
|
},
|
|
4140
4244
|
observe: (listener) => {
|
|
4141
4245
|
binding.check();
|
|
4142
|
-
|
|
4143
|
-
return () => observers.delete(listener);
|
|
4246
|
+
return require_driver.addListener(observers, listener);
|
|
4144
4247
|
},
|
|
4145
4248
|
hasConsumers: () => consumers.size > 0,
|
|
4146
4249
|
forEachConsumer: (run) => consumers.forEach((_pending, consumer) => run(consumer)),
|
|
@@ -4172,8 +4275,7 @@ const createCollectionOutput = (binding) => {
|
|
|
4172
4275
|
},
|
|
4173
4276
|
subscribe: (listener) => {
|
|
4174
4277
|
binding.check();
|
|
4175
|
-
|
|
4176
|
-
return () => listeners.delete(listener);
|
|
4278
|
+
return require_driver.addListener(listeners, listener);
|
|
4177
4279
|
}
|
|
4178
4280
|
};
|
|
4179
4281
|
};
|
|
@@ -4288,8 +4390,7 @@ const createValueOutput = (binding) => {
|
|
|
4288
4390
|
},
|
|
4289
4391
|
observe: (listener) => {
|
|
4290
4392
|
binding.check();
|
|
4291
|
-
|
|
4292
|
-
return () => observers.delete(listener);
|
|
4393
|
+
return require_driver.addListener(observers, listener);
|
|
4293
4394
|
},
|
|
4294
4395
|
hasConsumers: () => consumers.size > 0,
|
|
4295
4396
|
forEachConsumer: (run) => consumers.forEach((_revision, consumer) => run(consumer)),
|
|
@@ -4318,8 +4419,7 @@ const createValueOutput = (binding) => {
|
|
|
4318
4419
|
},
|
|
4319
4420
|
subscribe: (listener) => {
|
|
4320
4421
|
binding.check();
|
|
4321
|
-
|
|
4322
|
-
return () => listeners.delete(listener);
|
|
4422
|
+
return require_driver.addListener(listeners, listener);
|
|
4323
4423
|
}
|
|
4324
4424
|
};
|
|
4325
4425
|
};
|
|
@@ -4523,7 +4623,7 @@ const selectionAffects = (selection, change) => {
|
|
|
4523
4623
|
const createDirectReadable = (source) => Object.freeze({
|
|
4524
4624
|
current: source.current,
|
|
4525
4625
|
revision: source.revision,
|
|
4526
|
-
subscribe:
|
|
4626
|
+
subscribe: source.subscribe
|
|
4527
4627
|
});
|
|
4528
4628
|
/** Consumer-side selector tracking; it never mutates processor dependencies. */
|
|
4529
4629
|
const createSelectorReadable = (source, selector, equality = Object.is) => {
|
|
@@ -4627,15 +4727,22 @@ const createSelectorReadable = (source, selector, equality = Object.is) => {
|
|
|
4627
4727
|
},
|
|
4628
4728
|
subscribe: (listener) => {
|
|
4629
4729
|
ensureCurrent();
|
|
4630
|
-
|
|
4631
|
-
|
|
4632
|
-
|
|
4633
|
-
listeners.delete(listener);
|
|
4634
|
-
if (!listeners.size && unsubscribeSource) {
|
|
4635
|
-
unsubscribeSource();
|
|
4730
|
+
const unsubscribe = require_driver.addListener(listeners, listener, () => {
|
|
4731
|
+
if (!listeners.size) {
|
|
4732
|
+
const stop = unsubscribeSource;
|
|
4636
4733
|
unsubscribeSource = void 0;
|
|
4734
|
+
stop?.();
|
|
4637
4735
|
}
|
|
4638
|
-
};
|
|
4736
|
+
});
|
|
4737
|
+
try {
|
|
4738
|
+
installSource();
|
|
4739
|
+
} catch (error) {
|
|
4740
|
+
try {
|
|
4741
|
+
unsubscribe();
|
|
4742
|
+
} catch {}
|
|
4743
|
+
throw error;
|
|
4744
|
+
}
|
|
4745
|
+
return unsubscribe;
|
|
4639
4746
|
}
|
|
4640
4747
|
});
|
|
4641
4748
|
};
|
|
@@ -5933,7 +6040,7 @@ const createSourceRegistry = (scheduler) => {
|
|
|
5933
6040
|
//#endregion
|
|
5934
6041
|
//#region core/src/projection/readable/keyed.ts
|
|
5935
6042
|
/** Runtime-owned keyed consumer family over one materialized collection output. */
|
|
5936
|
-
const createProjectionItems = (source, checkOwner) => {
|
|
6043
|
+
const createProjectionItems = (source, checkOwner, checkSubscription) => {
|
|
5937
6044
|
if (source.kind !== "collection") throw new TypeError("Projection items require a keyed collection projection.");
|
|
5938
6045
|
let disposed = false;
|
|
5939
6046
|
const active = /* @__PURE__ */ new Map();
|
|
@@ -6062,12 +6169,12 @@ const createProjectionItems = (source, checkOwner) => {
|
|
|
6062
6169
|
subscribe: (listener) => {
|
|
6063
6170
|
check();
|
|
6064
6171
|
ensureObserved();
|
|
6065
|
-
|
|
6066
|
-
|
|
6067
|
-
return () => {
|
|
6068
|
-
state.listeners.delete(listener);
|
|
6172
|
+
checkSubscription();
|
|
6173
|
+
const unsubscribe = require_driver.addListener(state.listeners, listener, () => {
|
|
6069
6174
|
if (!state.listeners.size && !state.tracked) unregisterWaiting(state);
|
|
6070
|
-
};
|
|
6175
|
+
});
|
|
6176
|
+
if (!state.tracked && !state.ended) registerWaiting(state);
|
|
6177
|
+
return unsubscribe;
|
|
6071
6178
|
}
|
|
6072
6179
|
});
|
|
6073
6180
|
return state;
|
|
@@ -6124,8 +6231,8 @@ const createProjectionItems = (source, checkOwner) => {
|
|
|
6124
6231
|
},
|
|
6125
6232
|
subscribe: (listener) => {
|
|
6126
6233
|
check();
|
|
6127
|
-
|
|
6128
|
-
return (
|
|
6234
|
+
checkSubscription();
|
|
6235
|
+
return require_driver.addListener(keyListeners, listener);
|
|
6129
6236
|
}
|
|
6130
6237
|
});
|
|
6131
6238
|
return {
|
|
@@ -6133,6 +6240,7 @@ const createProjectionItems = (source, checkOwner) => {
|
|
|
6133
6240
|
keys,
|
|
6134
6241
|
get: (key) => {
|
|
6135
6242
|
check();
|
|
6243
|
+
checkSubscription();
|
|
6136
6244
|
const current = source.current();
|
|
6137
6245
|
if (source.revision() !== settledRevision) pendingKeys.add(key);
|
|
6138
6246
|
const canonical = active.get(key);
|
|
@@ -6177,6 +6285,7 @@ const createProjectionRuntime = (options) => {
|
|
|
6177
6285
|
const materialized = /* @__PURE__ */ new WeakMap();
|
|
6178
6286
|
const publicViews = /* @__PURE__ */ new WeakMap();
|
|
6179
6287
|
const scopes = /* @__PURE__ */ new Set();
|
|
6288
|
+
const cleanups = createCleanupStack();
|
|
6180
6289
|
const rootItems = /* @__PURE__ */ new Map();
|
|
6181
6290
|
const disposeItemControllers = (registry, failures) => {
|
|
6182
6291
|
const controllers = [...registry.values()];
|
|
@@ -6206,7 +6315,7 @@ const createProjectionRuntime = (options) => {
|
|
|
6206
6315
|
const owner = definition.owner;
|
|
6207
6316
|
if (owner === void 0) return;
|
|
6208
6317
|
if (owner !== requester) throw new TypeError("Projection belongs to another scope.");
|
|
6209
|
-
if (
|
|
6318
|
+
if (requester?.status === "disposed") throw new require_transform.ProjectionDisposedError();
|
|
6210
6319
|
};
|
|
6211
6320
|
const rememberScoped = (definition, requester) => {
|
|
6212
6321
|
if (requester && definition.owner === requester) requester.materialized.push(definition);
|
|
@@ -6286,25 +6395,33 @@ const createProjectionRuntime = (options) => {
|
|
|
6286
6395
|
assertOutput(output);
|
|
6287
6396
|
return output.revision();
|
|
6288
6397
|
},
|
|
6289
|
-
subscribe:
|
|
6290
|
-
|
|
6398
|
+
subscribe: (listener) => {
|
|
6399
|
+
scheduler.assertCommand();
|
|
6400
|
+
return output.subscribe(listener);
|
|
6401
|
+
},
|
|
6402
|
+
observe: (listener) => {
|
|
6403
|
+
scheduler.assertCommand();
|
|
6404
|
+
return output.observe(listener);
|
|
6405
|
+
}
|
|
6291
6406
|
});
|
|
6292
6407
|
};
|
|
6293
6408
|
const projectionItems = (projection, requester) => {
|
|
6409
|
+
scheduler.assertCommand();
|
|
6294
6410
|
const output = resolveOutput(projection, requester);
|
|
6295
6411
|
if (output.kind !== "collection") throw new TypeError("Projection items require a keyed collection projection.");
|
|
6296
6412
|
const registry = requester?.items ?? rootItems;
|
|
6297
6413
|
const existing = registry.get(output);
|
|
6298
6414
|
if (existing) return existing.items;
|
|
6299
6415
|
const controller = createProjectionItems(readableSource(projection, requester), () => {
|
|
6300
|
-
if (requester
|
|
6416
|
+
if (requester?.status === "disposed") throw new require_transform.ProjectionDisposedError();
|
|
6301
6417
|
scheduler.ensureCurrent(output);
|
|
6302
6418
|
assertOutput(output);
|
|
6303
|
-
});
|
|
6419
|
+
}, scheduler.assertCommand);
|
|
6304
6420
|
registry.set(output, controller);
|
|
6305
6421
|
return controller.items;
|
|
6306
6422
|
};
|
|
6307
6423
|
const makeReadable = (projection, selector, equality, requester) => {
|
|
6424
|
+
scheduler.assertCommand();
|
|
6308
6425
|
const source = readableSource(projection, requester);
|
|
6309
6426
|
return selector ? createSelectorReadable(source, selector, equality) : createDirectReadable(source);
|
|
6310
6427
|
};
|
|
@@ -6312,8 +6429,8 @@ const createProjectionRuntime = (options) => {
|
|
|
6312
6429
|
return makeReadable(projection, selector, equality);
|
|
6313
6430
|
}
|
|
6314
6431
|
const inputAccess = (target, requester) => {
|
|
6315
|
-
scheduler.
|
|
6316
|
-
if (requester
|
|
6432
|
+
scheduler.assertCommand();
|
|
6433
|
+
if (requester?.status === "disposed") throw new require_transform.ProjectionDisposedError();
|
|
6317
6434
|
const ref = require_transform.projectionRef(target);
|
|
6318
6435
|
if (ref.output !== 0 || ref.producer.kind !== "source") throw new TypeError("Projection is not an input.");
|
|
6319
6436
|
if (ref.producer.source.kind !== "value-input" && ref.producer.source.kind !== "collection-input") throw new TypeError("Projection is not an input.");
|
|
@@ -6334,11 +6451,9 @@ const createProjectionRuntime = (options) => {
|
|
|
6334
6451
|
updateInput(target, valueOrRun);
|
|
6335
6452
|
}
|
|
6336
6453
|
const batch = (run, options) => scheduler.batch(run, options);
|
|
6337
|
-
const
|
|
6338
|
-
|
|
6339
|
-
|
|
6340
|
-
state.active = false;
|
|
6341
|
-
const failures = [];
|
|
6454
|
+
const releaseScope = (state, failures) => {
|
|
6455
|
+
state.status = "disposed";
|
|
6456
|
+
scopes.delete(state);
|
|
6342
6457
|
disposeScopeConsumers(state, failures);
|
|
6343
6458
|
for (let index = state.materialized.length - 1; index >= 0; index--) {
|
|
6344
6459
|
const definition = state.materialized[index];
|
|
@@ -6353,24 +6468,38 @@ const createProjectionRuntime = (options) => {
|
|
|
6353
6468
|
}
|
|
6354
6469
|
}
|
|
6355
6470
|
state.materialized.length = 0;
|
|
6356
|
-
|
|
6471
|
+
};
|
|
6472
|
+
const disposeScope = (state) => {
|
|
6473
|
+
if (state.status !== "active") return;
|
|
6474
|
+
scheduler.assertCommand();
|
|
6475
|
+
state.status = "closing";
|
|
6476
|
+
const failures = [];
|
|
6477
|
+
try {
|
|
6478
|
+
scheduler.cleanup(() => state.cleanups.drain(failures));
|
|
6479
|
+
} catch (error) {
|
|
6480
|
+
failures.push(error);
|
|
6481
|
+
} finally {
|
|
6482
|
+
scheduler.releaseOwned(() => releaseScope(state, failures));
|
|
6483
|
+
}
|
|
6357
6484
|
throwCleanupFailures(failures, "Projection scope cleanup failed.");
|
|
6358
6485
|
};
|
|
6359
6486
|
const createScope = () => {
|
|
6360
|
-
scheduler.
|
|
6487
|
+
scheduler.assertCommand();
|
|
6361
6488
|
const state = {
|
|
6362
|
-
|
|
6489
|
+
status: "active",
|
|
6490
|
+
cleanups: createCleanupStack(),
|
|
6363
6491
|
materialized: [],
|
|
6364
6492
|
subscriptions: /* @__PURE__ */ new Set(),
|
|
6365
6493
|
items: /* @__PURE__ */ new Map()
|
|
6366
6494
|
};
|
|
6367
6495
|
scopes.add(state);
|
|
6368
6496
|
const assertActive = () => {
|
|
6369
|
-
if (
|
|
6497
|
+
if (state.status === "disposed") throw new require_transform.ProjectionDisposedError();
|
|
6370
6498
|
scheduler.assertActive();
|
|
6371
6499
|
};
|
|
6372
6500
|
function own(target) {
|
|
6373
6501
|
assertActive();
|
|
6502
|
+
scheduler.assertCommand();
|
|
6374
6503
|
const projections = [];
|
|
6375
6504
|
const collect = (value) => {
|
|
6376
6505
|
if (require_transform.isProjection(value)) {
|
|
@@ -6440,6 +6569,11 @@ const createProjectionRuntime = (options) => {
|
|
|
6440
6569
|
},
|
|
6441
6570
|
update: scopeUpdate,
|
|
6442
6571
|
batch: scopeBatch,
|
|
6572
|
+
onDispose: (callback) => {
|
|
6573
|
+
assertActive();
|
|
6574
|
+
scheduler.assertCommand();
|
|
6575
|
+
return state.cleanups.add(callback);
|
|
6576
|
+
},
|
|
6443
6577
|
dispose: () => disposeScope(state)
|
|
6444
6578
|
});
|
|
6445
6579
|
};
|
|
@@ -6450,24 +6584,33 @@ const createProjectionRuntime = (options) => {
|
|
|
6450
6584
|
update,
|
|
6451
6585
|
batch,
|
|
6452
6586
|
scope: createScope,
|
|
6587
|
+
onDispose: (callback) => {
|
|
6588
|
+
scheduler.assertCommand();
|
|
6589
|
+
return cleanups.add(callback);
|
|
6590
|
+
},
|
|
6453
6591
|
dispose: () => {
|
|
6454
|
-
if (!scheduler.
|
|
6455
|
-
scheduler.assertIdle();
|
|
6592
|
+
if (!scheduler.beginClose()) return;
|
|
6456
6593
|
const failures = [];
|
|
6457
|
-
|
|
6458
|
-
|
|
6459
|
-
disposeScopeConsumers(scope, failures);
|
|
6460
|
-
scope.materialized.length = 0;
|
|
6461
|
-
}
|
|
6462
|
-
scopes.clear();
|
|
6463
|
-
disposeItemControllers(rootItems, failures);
|
|
6594
|
+
const owned = [...scopes].reverse();
|
|
6595
|
+
for (const scope of owned) scope.status = "closing";
|
|
6464
6596
|
try {
|
|
6465
|
-
|
|
6597
|
+
scheduler.cleanup(() => {
|
|
6598
|
+
for (const scope of owned) scope.cleanups.drain(failures);
|
|
6599
|
+
cleanups.drain(failures);
|
|
6600
|
+
});
|
|
6466
6601
|
} catch (error) {
|
|
6467
6602
|
failures.push(error);
|
|
6468
6603
|
}
|
|
6469
6604
|
try {
|
|
6470
|
-
scheduler.dispose()
|
|
6605
|
+
scheduler.dispose(() => {
|
|
6606
|
+
for (const scope of owned) {
|
|
6607
|
+
scope.status = "disposed";
|
|
6608
|
+
scope.materialized.length = 0;
|
|
6609
|
+
disposeScopeConsumers(scope, failures);
|
|
6610
|
+
}
|
|
6611
|
+
scopes.clear();
|
|
6612
|
+
disposeItemControllers(rootItems, failures);
|
|
6613
|
+
}, sources.dispose);
|
|
6471
6614
|
} catch (error) {
|
|
6472
6615
|
failures.push(error);
|
|
6473
6616
|
}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { $ as table, A as ParseError, B as DocumentListConfig, C as Read, D as ChangeSet, E as Change, F as CollectionPath, G as ReadonlyValue, H as DocumentTreeValue, I as PathValueOf, J as field, K as Schema, L as SchemaPath, M as parse, N as CollectionEntry, O as MemberChange, P as CollectionId, Q as optional, R as DocumentAddress, S as Draft, T as snapshot, U as Infer, V as DocumentTreeNode, W as ObjectSchema, X as map, Y as list, Z as object, _ as Unsubscribe, a as DocumentProblem, b as CollectionImpact, c as HistoryState, d as OperationResult, et as tree, f as ReadonlyDocument, g as Readable, h as TransactionResult, i as DocumentDisposedError, j as ParseIssue, k as ValueTransition, l as LocalHistory, m as TransactionRejected, n as DocumentCommit, o as DocumentReentrancyError, p as Synchronous, q as Validator, r as DocumentDiagnostic, s as DocumentRuntime, t as CommitSource, tt as variant, u as ObserverError, v as MutationIssue, w as replace, x as DocumentImpact, y as MutationIssueCode, z as DocumentAnchor } from "./contract-
|
|
2
|
-
import { _ as ProjectionDisposedError, a as Input, f as ExternalCollectionEvent, g as ExternalValueSource, h as ExternalValueEvent, i as CollectionInputDraft, m as ExternalCollectionSource, n as KeyedDependencyValues, o as KeyedProjection, p as ExternalCollectionRead, r as CollectionInput, s as Projection, t as KeyedDependencies, v as ProjectionError } from "./dependency-
|
|
1
|
+
import { $ as table, A as ParseError, B as DocumentListConfig, C as Read, D as ChangeSet, E as Change, F as CollectionPath, G as ReadonlyValue, H as DocumentTreeValue, I as PathValueOf, J as field, K as Schema, L as SchemaPath, M as parse, N as CollectionEntry, O as MemberChange, P as CollectionId, Q as optional, R as DocumentAddress, S as Draft, T as snapshot, U as Infer, V as DocumentTreeNode, W as ObjectSchema, X as map, Y as list, Z as object, _ as Unsubscribe, a as DocumentProblem, b as CollectionImpact, c as HistoryState, d as OperationResult, et as tree, f as ReadonlyDocument, g as Readable, h as TransactionResult, i as DocumentDisposedError, j as ParseIssue, k as ValueTransition, l as LocalHistory, m as TransactionRejected, n as DocumentCommit, o as DocumentReentrancyError, p as Synchronous, q as Validator, r as DocumentDiagnostic, s as DocumentRuntime, t as CommitSource, tt as variant, u as ObserverError, v as MutationIssue, w as replace, x as DocumentImpact, y as MutationIssueCode, z as DocumentAnchor } from "./contract-DovG1Yp-.cjs";
|
|
2
|
+
import { _ as ProjectionDisposedError, a as Input, f as ExternalCollectionEvent, g as ExternalValueSource, h as ExternalValueEvent, i as CollectionInputDraft, m as ExternalCollectionSource, n as KeyedDependencyValues, o as KeyedProjection, p as ExternalCollectionRead, r as CollectionInput, s as Projection, t as KeyedDependencies, v as ProjectionError } from "./dependency-D0bo_xe_.cjs";
|
|
3
3
|
|
|
4
4
|
//#region core/src/runtime.d.ts
|
|
5
5
|
declare const createDocument: <S extends ObjectSchema<object>>(input: {
|
|
@@ -119,6 +119,7 @@ type ProjectionRuntime = {
|
|
|
119
119
|
readonly cause?: unknown;
|
|
120
120
|
}): T;
|
|
121
121
|
scope(): ProjectionScope;
|
|
122
|
+
onDispose<R>(cleanup: () => Synchronous<R>): Unsubscribe;
|
|
122
123
|
dispose(): void;
|
|
123
124
|
};
|
|
124
125
|
type ProjectionOwnershipTree = {
|
|
@@ -136,6 +137,7 @@ type ProjectionScope = {
|
|
|
136
137
|
batch<T>(run: () => Synchronous<T>, options?: {
|
|
137
138
|
readonly cause?: unknown;
|
|
138
139
|
}): T;
|
|
140
|
+
onDispose<R>(cleanup: () => Synchronous<R>): Unsubscribe;
|
|
139
141
|
dispose(): void;
|
|
140
142
|
};
|
|
141
143
|
declare const createProjectionRuntime: (options?: {
|