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.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { A as ownProjections, C as snapshotProjectionValues, D as defineProcessor, E as snapshotCollectionView, M as projectionRef, N as profile, O as defineSource, S as compileProjectionDependencies, T as mapRead, _ as assertSynchronous, a as collectionChangeTouchesKey, b as ProjectionError, c as assertKeyedProjection, d as outputKind, f as createKeyRelation, g as assertScope, h as snapshotArray, i as collectionChangeIntersects, j as producerOf, k as isProjection, l as compileKeyedDependencies, m as sameArray, n as keyedAbsent, o as collectionHasStructuralChange, p as iterableMatchesArray, s as createCollectionChange, t as createKeyedTransform, u as createKeyedDependencyRuntime, v as createScheduler, w as collectionView, x as collectKeyedInvalidation, y as ProjectionDisposedError } from "./transform
|
|
1
|
+
import { A as ownProjections, C as snapshotProjectionValues, D as defineProcessor, E as snapshotCollectionView, M as projectionRef, N as profile, O as defineSource, S as compileProjectionDependencies, T as mapRead, _ as assertSynchronous, a as collectionChangeTouchesKey, b as ProjectionError, c as assertKeyedProjection, d as outputKind, f as createKeyRelation, g as assertScope, h as snapshotArray, i as collectionChangeIntersects, j as producerOf, k as isProjection, l as compileKeyedDependencies, m as sameArray, n as keyedAbsent, o as collectionHasStructuralChange, p as iterableMatchesArray, s as createCollectionChange, t as createKeyedTransform, u as createKeyedDependencyRuntime, v as createScheduler, w as collectionView, x as collectKeyedInvalidation, y as ProjectionDisposedError } from "./transform-BvDYPUMm.js";
|
|
2
2
|
import { n as isPlainObject, r as isRecord, t as installOwn } from "./record-B2yRhYsc.js";
|
|
3
|
-
import { c as
|
|
3
|
+
import { _ as validate, c as addListener, d as fail, f as invalidValue, g as parent, h as is, i as contextOf, l as AddressIndex, m as contains$1, o as decodeChanges, p as children, r as bindContext, s as sealChanges, t as assertRuntimeWritable, u as MutationRejected } from "./driver-B7Hu6D0u.js";
|
|
4
4
|
//#region core/src/schema/model.ts
|
|
5
5
|
const schemaNodeOf = (schema) => schema;
|
|
6
6
|
const collectionEntryNode = (node) => node.kind === "map" || node.kind === "table" || node.kind === "list" ? node.value : void 0;
|
|
@@ -651,7 +651,7 @@ function remove$2(session, container, ids) {
|
|
|
651
651
|
for (const id of removed) session.writeMember(container, id, void 0, "remove");
|
|
652
652
|
table.ids = table.ids.filter((id) => !removed.has(id));
|
|
653
653
|
}
|
|
654
|
-
function replace$
|
|
654
|
+
function replace$4(session, container, id, value) {
|
|
655
655
|
const { at, node, value: tableValue } = container;
|
|
656
656
|
if (node.kind !== "table") return fail(at, "invalid-collection", "Expected a table.");
|
|
657
657
|
const table = tableValue;
|
|
@@ -674,7 +674,7 @@ function insert$1(session, container, value, position) {
|
|
|
674
674
|
insert$2(items, index(keys$1, position), value);
|
|
675
675
|
session.invalidate();
|
|
676
676
|
}
|
|
677
|
-
function replace$
|
|
677
|
+
function replace$3(session, container, id, value) {
|
|
678
678
|
const { at, node, value: items } = container;
|
|
679
679
|
if (node.kind !== "list") return fail(at, "invalid-list-key", "Expected a list.");
|
|
680
680
|
const index = indexedKeys(items, node.keyOf).index(id);
|
|
@@ -720,7 +720,7 @@ const insert = (session, container, id, value, position) => {
|
|
|
720
720
|
else tree.rootId = id;
|
|
721
721
|
session.invalidate();
|
|
722
722
|
};
|
|
723
|
-
const replace$
|
|
723
|
+
const replace$2 = (session, container, id, value) => {
|
|
724
724
|
const { at, node: schema, value: tree } = container;
|
|
725
725
|
const entry = node$1(tree, id);
|
|
726
726
|
if (!entry) return fail(at, "missing-tree-node", "Tree node does not exist.");
|
|
@@ -1179,7 +1179,7 @@ const createAccess = (context, initial = []) => {
|
|
|
1179
1179
|
const [valueOrId, value] = args;
|
|
1180
1180
|
if (args.length === 1) return replaceCollection(target, node, valueOrId);
|
|
1181
1181
|
const writable = writableCollection(target, node);
|
|
1182
|
-
replace$
|
|
1182
|
+
replace$4(context.session, writable, valueOrId, value);
|
|
1183
1183
|
};
|
|
1184
1184
|
return orderedMethod(target, property, node);
|
|
1185
1185
|
};
|
|
@@ -1196,7 +1196,7 @@ const createAccess = (context, initial = []) => {
|
|
|
1196
1196
|
const [valueOrId, value] = args;
|
|
1197
1197
|
if (args.length === 1) return replaceCollection(target, node, valueOrId);
|
|
1198
1198
|
const writable = writableCollection(target, node);
|
|
1199
|
-
replace$
|
|
1199
|
+
replace$3(context.session, writable, valueOrId, value);
|
|
1200
1200
|
};
|
|
1201
1201
|
return orderedMethod(target, property, node);
|
|
1202
1202
|
};
|
|
@@ -1218,7 +1218,7 @@ const createAccess = (context, initial = []) => {
|
|
|
1218
1218
|
const [valueOrId, value] = args;
|
|
1219
1219
|
if (args.length === 1) return replaceCollection(target, node, valueOrId);
|
|
1220
1220
|
const writable = writableTree(target, node);
|
|
1221
|
-
replace$
|
|
1221
|
+
replace$2(context.session, writable, valueOrId, value);
|
|
1222
1222
|
};
|
|
1223
1223
|
const current = () => collectionValue(target, node);
|
|
1224
1224
|
if (property === "rootId") return () => {
|
|
@@ -1622,10 +1622,7 @@ const createHistory = (input) => {
|
|
|
1622
1622
|
revision: () => revision,
|
|
1623
1623
|
subscribe: (listener) => {
|
|
1624
1624
|
if (disposed) throw new DocumentDisposedError();
|
|
1625
|
-
listeners
|
|
1626
|
-
return () => {
|
|
1627
|
-
listeners.delete(listener);
|
|
1628
|
-
};
|
|
1625
|
+
return addListener(listeners, listener);
|
|
1629
1626
|
},
|
|
1630
1627
|
undo: () => {
|
|
1631
1628
|
input.assertIdle();
|
|
@@ -2296,6 +2293,7 @@ const addRoot = (notification, listener) => {
|
|
|
2296
2293
|
};
|
|
2297
2294
|
notification.root.add(entry);
|
|
2298
2295
|
return () => {
|
|
2296
|
+
if (!entry.active) return;
|
|
2299
2297
|
entry.active = false;
|
|
2300
2298
|
if (!notification.notifying) notification.root.delete(entry);
|
|
2301
2299
|
else notification.cleanups.add(() => {
|
|
@@ -2669,7 +2667,9 @@ const select = (document, selector, equality = Object.is) => {
|
|
|
2669
2667
|
};
|
|
2670
2668
|
};
|
|
2671
2669
|
const installSubscription = () => {
|
|
2672
|
-
unsubscribeDocument
|
|
2670
|
+
const stop = unsubscribeDocument;
|
|
2671
|
+
unsubscribeDocument = void 0;
|
|
2672
|
+
stop?.();
|
|
2673
2673
|
unsubscribeDocument = dependencies.length > 0 ? context.notifications.subscribeTargets(dependencies, () => {
|
|
2674
2674
|
const result = evaluate();
|
|
2675
2675
|
if (result.rebound) installSubscription();
|
|
@@ -2689,15 +2689,22 @@ const select = (document, selector, equality = Object.is) => {
|
|
|
2689
2689
|
},
|
|
2690
2690
|
subscribe: (listener) => {
|
|
2691
2691
|
ensureCurrent();
|
|
2692
|
-
listeners
|
|
2693
|
-
if (listeners.size === 1) installSubscription();
|
|
2694
|
-
return () => {
|
|
2695
|
-
listeners.delete(listener);
|
|
2692
|
+
const unsubscribe = addListener(listeners, listener, () => {
|
|
2696
2693
|
if (!listeners.size) {
|
|
2697
|
-
unsubscribeDocument
|
|
2694
|
+
const stop = unsubscribeDocument;
|
|
2698
2695
|
unsubscribeDocument = void 0;
|
|
2696
|
+
stop?.();
|
|
2699
2697
|
}
|
|
2700
|
-
};
|
|
2698
|
+
});
|
|
2699
|
+
try {
|
|
2700
|
+
if (listeners.size === 1) installSubscription();
|
|
2701
|
+
} catch (error) {
|
|
2702
|
+
try {
|
|
2703
|
+
unsubscribe();
|
|
2704
|
+
} catch {}
|
|
2705
|
+
throw error;
|
|
2706
|
+
}
|
|
2707
|
+
return unsubscribe;
|
|
2701
2708
|
}
|
|
2702
2709
|
});
|
|
2703
2710
|
};
|
|
@@ -3687,6 +3694,33 @@ function createValueDerive(dependencies, compute, equality = Object.is) {
|
|
|
3687
3694
|
}
|
|
3688
3695
|
const derive = Object.assign(createValueDerive, { keyed: keyedDerive });
|
|
3689
3696
|
//#endregion
|
|
3697
|
+
//#region core/src/projection/cleanup.ts
|
|
3698
|
+
/** Owner-local, cancellable LIFO callbacks. Lifecycle admission stays with the owner. */
|
|
3699
|
+
const createCleanupStack = () => {
|
|
3700
|
+
const entries = /* @__PURE__ */ new Set();
|
|
3701
|
+
return {
|
|
3702
|
+
add(callback) {
|
|
3703
|
+
const entry = () => {
|
|
3704
|
+
assertSynchronous(callback());
|
|
3705
|
+
};
|
|
3706
|
+
entries.add(entry);
|
|
3707
|
+
return () => {
|
|
3708
|
+
entries.delete(entry);
|
|
3709
|
+
};
|
|
3710
|
+
},
|
|
3711
|
+
drain(failures) {
|
|
3712
|
+
for (const entry of [...entries].reverse()) {
|
|
3713
|
+
if (!entries.delete(entry)) continue;
|
|
3714
|
+
try {
|
|
3715
|
+
entry();
|
|
3716
|
+
} catch (error) {
|
|
3717
|
+
failures.push(error);
|
|
3718
|
+
}
|
|
3719
|
+
}
|
|
3720
|
+
}
|
|
3721
|
+
};
|
|
3722
|
+
};
|
|
3723
|
+
//#endregion
|
|
3690
3724
|
//#region core/src/projection/collection/changes.ts
|
|
3691
3725
|
/** Net transitions for one consumer's unconsumed interval; bounded by touched keys. */
|
|
3692
3726
|
const createCollectionChanges = () => {
|
|
@@ -3797,49 +3831,109 @@ const node = (key, value, left, right) => {
|
|
|
3797
3831
|
height: Math.max(height(left), height(right)) + 1
|
|
3798
3832
|
});
|
|
3799
3833
|
};
|
|
3800
|
-
|
|
3801
|
-
|
|
3802
|
-
|
|
3803
|
-
|
|
3804
|
-
|
|
3805
|
-
|
|
3806
|
-
|
|
3807
|
-
}
|
|
3808
|
-
|
|
3809
|
-
|
|
3810
|
-
|
|
3811
|
-
|
|
3812
|
-
return
|
|
3813
|
-
}
|
|
3814
|
-
|
|
3815
|
-
|
|
3816
|
-
|
|
3817
|
-
|
|
3818
|
-
|
|
3819
|
-
|
|
3820
|
-
|
|
3821
|
-
|
|
3822
|
-
if (
|
|
3823
|
-
|
|
3824
|
-
|
|
3825
|
-
}
|
|
3826
|
-
|
|
3827
|
-
|
|
3828
|
-
|
|
3829
|
-
|
|
3830
|
-
if (key > current.key) return rebalance(node(current.key, current.value, current.left, removeNode(current.right, key)));
|
|
3834
|
+
/** Local repair after a join descent or a single deletion (height difference at most two). */
|
|
3835
|
+
const balance = (key, value, left, right) => {
|
|
3836
|
+
if (height(left) > height(right) + 1) {
|
|
3837
|
+
const heavy = left;
|
|
3838
|
+
if (height(heavy.left) >= height(heavy.right)) return node(heavy.key, heavy.value, heavy.left, node(key, value, heavy.right, right));
|
|
3839
|
+
const middle = heavy.right;
|
|
3840
|
+
return node(middle.key, middle.value, node(heavy.key, heavy.value, heavy.left, middle.left), node(key, value, middle.right, right));
|
|
3841
|
+
}
|
|
3842
|
+
if (height(right) > height(left) + 1) {
|
|
3843
|
+
const heavy = right;
|
|
3844
|
+
if (height(heavy.right) >= height(heavy.left)) return node(heavy.key, heavy.value, node(key, value, left, heavy.left), heavy.right);
|
|
3845
|
+
const middle = heavy.left;
|
|
3846
|
+
return node(middle.key, middle.value, node(key, value, left, middle.left), node(heavy.key, heavy.value, middle.right, heavy.right));
|
|
3847
|
+
}
|
|
3848
|
+
return node(key, value, left, right);
|
|
3849
|
+
};
|
|
3850
|
+
/** All left keys precede key, all right keys follow it; heights may differ arbitrarily. */
|
|
3851
|
+
const join = (key, value, left, right) => {
|
|
3852
|
+
if (height(left) > height(right) + 1) {
|
|
3853
|
+
profile.collectionIndex.visit();
|
|
3854
|
+
return balance(left.key, left.value, left.left, join(key, value, left.right, right));
|
|
3855
|
+
}
|
|
3856
|
+
if (height(right) > height(left) + 1) {
|
|
3857
|
+
profile.collectionIndex.visit();
|
|
3858
|
+
return balance(right.key, right.value, join(key, value, left, right.left), right.right);
|
|
3859
|
+
}
|
|
3860
|
+
return node(key, value, left, right);
|
|
3861
|
+
};
|
|
3862
|
+
const removeMin = (current) => {
|
|
3863
|
+
profile.collectionIndex.visit();
|
|
3831
3864
|
if (!current.left) return current.right;
|
|
3832
|
-
|
|
3833
|
-
|
|
3834
|
-
|
|
3865
|
+
return balance(current.key, current.value, removeMin(current.left), current.right);
|
|
3866
|
+
};
|
|
3867
|
+
const concat = (left, right) => {
|
|
3868
|
+
if (!left) return right;
|
|
3869
|
+
if (!right) return left;
|
|
3870
|
+
let first = right;
|
|
3871
|
+
while (first.left) {
|
|
3872
|
+
profile.collectionIndex.visit();
|
|
3873
|
+
first = first.left;
|
|
3874
|
+
}
|
|
3875
|
+
return join(first.key, first.value, left, removeMin(right));
|
|
3876
|
+
};
|
|
3877
|
+
const replace$1 = (current, entry, left, right) => {
|
|
3878
|
+
if (entry && !entry.present) return concat(left, right);
|
|
3879
|
+
const value = entry ? entry.value : current.value;
|
|
3880
|
+
if (left === current.left && right === current.right && Object.is(value, current.value)) return current;
|
|
3881
|
+
return join(current.key, value, left, right);
|
|
3882
|
+
};
|
|
3883
|
+
const edit = (current, key, entry) => {
|
|
3884
|
+
if (!current) return entry.present ? node(key, entry.value) : void 0;
|
|
3885
|
+
profile.collectionIndex.visit();
|
|
3886
|
+
if (key === current.key) return replace$1(current, entry, current.left, current.right);
|
|
3887
|
+
if (key < current.key) {
|
|
3888
|
+
const left = edit(current.left, key, entry);
|
|
3889
|
+
return left === current.left ? current : balance(current.key, current.value, left, current.right);
|
|
3890
|
+
}
|
|
3891
|
+
const right = edit(current.right, key, entry);
|
|
3892
|
+
return right === current.right ? current : balance(current.key, current.value, current.left, right);
|
|
3893
|
+
};
|
|
3894
|
+
/** Builds a new subtree in linear time, ignoring removals of absent keys. */
|
|
3895
|
+
const buildChanges = (keys, changes, start, end) => {
|
|
3896
|
+
let count = 0;
|
|
3897
|
+
for (let i = start; i < end; i++) if (changes.get(keys[i]).present) count++;
|
|
3898
|
+
let cursor = start;
|
|
3899
|
+
const build = (size) => {
|
|
3900
|
+
if (!size) return void 0;
|
|
3901
|
+
const leftSize = size >> 1;
|
|
3902
|
+
const left = build(leftSize);
|
|
3903
|
+
let key;
|
|
3904
|
+
let entry;
|
|
3905
|
+
do {
|
|
3906
|
+
key = keys[cursor++];
|
|
3907
|
+
entry = changes.get(key);
|
|
3908
|
+
} while (!entry.present);
|
|
3909
|
+
return node(key, entry.value, left, build(size - leftSize - 1));
|
|
3910
|
+
};
|
|
3911
|
+
return build(count);
|
|
3912
|
+
};
|
|
3913
|
+
const applyChanges = (current, keys, changes, start, end) => {
|
|
3914
|
+
if (start === end) return current;
|
|
3915
|
+
if (end - start === 1) return edit(current, keys[start], changes.get(keys[start]));
|
|
3916
|
+
if (!current) return buildChanges(keys, changes, start, end);
|
|
3917
|
+
profile.collectionIndex.visit();
|
|
3918
|
+
let low = start;
|
|
3919
|
+
let high = end;
|
|
3920
|
+
while (low < high) {
|
|
3921
|
+
const middle = low + high >>> 1;
|
|
3922
|
+
if (keys[middle] < current.key) low = middle + 1;
|
|
3923
|
+
else high = middle;
|
|
3924
|
+
}
|
|
3925
|
+
const matched = low < end && keys[low] === current.key;
|
|
3926
|
+
const left = applyChanges(current.left, keys, changes, start, low);
|
|
3927
|
+
const right = applyChanges(current.right, keys, changes, matched ? low + 1 : low, end);
|
|
3928
|
+
return replace$1(current, matched ? changes.get(current.key) : void 0, left, right);
|
|
3835
3929
|
};
|
|
3836
3930
|
const fromSorted = (entries, start = 0, end = entries.length) => {
|
|
3837
3931
|
if (start >= end) return void 0;
|
|
3838
|
-
const middle = start + end
|
|
3932
|
+
const middle = start + end >>> 1;
|
|
3839
3933
|
const [key, value] = entries[middle];
|
|
3840
3934
|
return node(key, value, fromSorted(entries, start, middle), fromSorted(entries, middle + 1, end));
|
|
3841
3935
|
};
|
|
3842
|
-
/** Immutable keyed lookup used to keep
|
|
3936
|
+
/** Immutable keyed lookup used to keep collection snapshots durable across revisions. */
|
|
3843
3937
|
var PersistentKeyedIndex = class PersistentKeyedIndex {
|
|
3844
3938
|
constructor(root) {
|
|
3845
3939
|
this.root = root;
|
|
@@ -3847,6 +3941,7 @@ var PersistentKeyedIndex = class PersistentKeyedIndex {
|
|
|
3847
3941
|
static empty() {
|
|
3848
3942
|
return new PersistentKeyedIndex();
|
|
3849
3943
|
}
|
|
3944
|
+
/** The input must contain unique keys. Formal collection order is owned separately. */
|
|
3850
3945
|
static from(entries) {
|
|
3851
3946
|
const sorted = [...entries].sort(([left], [right]) => left < right ? -1 : left > right ? 1 : 0);
|
|
3852
3947
|
profile.collectionIndex.build(sorted.length);
|
|
@@ -3867,11 +3962,19 @@ var PersistentKeyedIndex = class PersistentKeyedIndex {
|
|
|
3867
3962
|
}
|
|
3868
3963
|
return false;
|
|
3869
3964
|
}
|
|
3870
|
-
|
|
3871
|
-
|
|
3872
|
-
|
|
3873
|
-
|
|
3874
|
-
|
|
3965
|
+
/** Applies accepted final entry intents together; never calls user equality or changes old roots. */
|
|
3966
|
+
apply(changes) {
|
|
3967
|
+
if (!changes.size) return this;
|
|
3968
|
+
profile.collectionIndex.batch(changes.size > 1 ? changes.size : 0);
|
|
3969
|
+
let root;
|
|
3970
|
+
if (changes.size === 1) {
|
|
3971
|
+
const [key, entry] = changes.entries().next().value;
|
|
3972
|
+
root = edit(this.root, key, entry);
|
|
3973
|
+
} else {
|
|
3974
|
+
const keys = [...changes.keys()].sort();
|
|
3975
|
+
root = applyChanges(this.root, keys, changes, 0, keys.length);
|
|
3976
|
+
}
|
|
3977
|
+
return root === this.root ? this : new PersistentKeyedIndex(root);
|
|
3875
3978
|
}
|
|
3876
3979
|
};
|
|
3877
3980
|
//#endregion
|
|
@@ -3909,10 +4012,11 @@ const createCollectionState = (initial) => {
|
|
|
3909
4012
|
values.clear();
|
|
3910
4013
|
for (const [key, entry] of staged) if (entry.present) values.set(key, entry.value);
|
|
3911
4014
|
if (index) index = PersistentKeyedIndex.from(values);
|
|
3912
|
-
} else
|
|
3913
|
-
|
|
3914
|
-
if (entry.present) values.set(key, entry.value);
|
|
4015
|
+
} else {
|
|
4016
|
+
const nextIndex = index?.apply(staged);
|
|
4017
|
+
for (const [key, entry] of staged) if (entry.present) values.set(key, entry.value);
|
|
3915
4018
|
else values.delete(key);
|
|
4019
|
+
index = nextIndex;
|
|
3916
4020
|
}
|
|
3917
4021
|
ids = nextIds;
|
|
3918
4022
|
},
|
|
@@ -4138,8 +4242,7 @@ const createCollectionOutput = (binding) => {
|
|
|
4138
4242
|
},
|
|
4139
4243
|
observe: (listener) => {
|
|
4140
4244
|
binding.check();
|
|
4141
|
-
observers
|
|
4142
|
-
return () => observers.delete(listener);
|
|
4245
|
+
return addListener(observers, listener);
|
|
4143
4246
|
},
|
|
4144
4247
|
hasConsumers: () => consumers.size > 0,
|
|
4145
4248
|
forEachConsumer: (run) => consumers.forEach((_pending, consumer) => run(consumer)),
|
|
@@ -4171,8 +4274,7 @@ const createCollectionOutput = (binding) => {
|
|
|
4171
4274
|
},
|
|
4172
4275
|
subscribe: (listener) => {
|
|
4173
4276
|
binding.check();
|
|
4174
|
-
listeners
|
|
4175
|
-
return () => listeners.delete(listener);
|
|
4277
|
+
return addListener(listeners, listener);
|
|
4176
4278
|
}
|
|
4177
4279
|
};
|
|
4178
4280
|
};
|
|
@@ -4287,8 +4389,7 @@ const createValueOutput = (binding) => {
|
|
|
4287
4389
|
},
|
|
4288
4390
|
observe: (listener) => {
|
|
4289
4391
|
binding.check();
|
|
4290
|
-
observers
|
|
4291
|
-
return () => observers.delete(listener);
|
|
4392
|
+
return addListener(observers, listener);
|
|
4292
4393
|
},
|
|
4293
4394
|
hasConsumers: () => consumers.size > 0,
|
|
4294
4395
|
forEachConsumer: (run) => consumers.forEach((_revision, consumer) => run(consumer)),
|
|
@@ -4317,8 +4418,7 @@ const createValueOutput = (binding) => {
|
|
|
4317
4418
|
},
|
|
4318
4419
|
subscribe: (listener) => {
|
|
4319
4420
|
binding.check();
|
|
4320
|
-
listeners
|
|
4321
|
-
return () => listeners.delete(listener);
|
|
4421
|
+
return addListener(listeners, listener);
|
|
4322
4422
|
}
|
|
4323
4423
|
};
|
|
4324
4424
|
};
|
|
@@ -4522,7 +4622,7 @@ const selectionAffects = (selection, change) => {
|
|
|
4522
4622
|
const createDirectReadable = (source) => Object.freeze({
|
|
4523
4623
|
current: source.current,
|
|
4524
4624
|
revision: source.revision,
|
|
4525
|
-
subscribe:
|
|
4625
|
+
subscribe: source.subscribe
|
|
4526
4626
|
});
|
|
4527
4627
|
/** Consumer-side selector tracking; it never mutates processor dependencies. */
|
|
4528
4628
|
const createSelectorReadable = (source, selector, equality = Object.is) => {
|
|
@@ -4626,15 +4726,22 @@ const createSelectorReadable = (source, selector, equality = Object.is) => {
|
|
|
4626
4726
|
},
|
|
4627
4727
|
subscribe: (listener) => {
|
|
4628
4728
|
ensureCurrent();
|
|
4629
|
-
listeners
|
|
4630
|
-
|
|
4631
|
-
|
|
4632
|
-
listeners.delete(listener);
|
|
4633
|
-
if (!listeners.size && unsubscribeSource) {
|
|
4634
|
-
unsubscribeSource();
|
|
4729
|
+
const unsubscribe = addListener(listeners, listener, () => {
|
|
4730
|
+
if (!listeners.size) {
|
|
4731
|
+
const stop = unsubscribeSource;
|
|
4635
4732
|
unsubscribeSource = void 0;
|
|
4733
|
+
stop?.();
|
|
4636
4734
|
}
|
|
4637
|
-
};
|
|
4735
|
+
});
|
|
4736
|
+
try {
|
|
4737
|
+
installSource();
|
|
4738
|
+
} catch (error) {
|
|
4739
|
+
try {
|
|
4740
|
+
unsubscribe();
|
|
4741
|
+
} catch {}
|
|
4742
|
+
throw error;
|
|
4743
|
+
}
|
|
4744
|
+
return unsubscribe;
|
|
4638
4745
|
}
|
|
4639
4746
|
});
|
|
4640
4747
|
};
|
|
@@ -5932,7 +6039,7 @@ const createSourceRegistry = (scheduler) => {
|
|
|
5932
6039
|
//#endregion
|
|
5933
6040
|
//#region core/src/projection/readable/keyed.ts
|
|
5934
6041
|
/** Runtime-owned keyed consumer family over one materialized collection output. */
|
|
5935
|
-
const createProjectionItems = (source, checkOwner) => {
|
|
6042
|
+
const createProjectionItems = (source, checkOwner, checkSubscription) => {
|
|
5936
6043
|
if (source.kind !== "collection") throw new TypeError("Projection items require a keyed collection projection.");
|
|
5937
6044
|
let disposed = false;
|
|
5938
6045
|
const active = /* @__PURE__ */ new Map();
|
|
@@ -6061,12 +6168,12 @@ const createProjectionItems = (source, checkOwner) => {
|
|
|
6061
6168
|
subscribe: (listener) => {
|
|
6062
6169
|
check();
|
|
6063
6170
|
ensureObserved();
|
|
6064
|
-
|
|
6065
|
-
|
|
6066
|
-
return () => {
|
|
6067
|
-
state.listeners.delete(listener);
|
|
6171
|
+
checkSubscription();
|
|
6172
|
+
const unsubscribe = addListener(state.listeners, listener, () => {
|
|
6068
6173
|
if (!state.listeners.size && !state.tracked) unregisterWaiting(state);
|
|
6069
|
-
};
|
|
6174
|
+
});
|
|
6175
|
+
if (!state.tracked && !state.ended) registerWaiting(state);
|
|
6176
|
+
return unsubscribe;
|
|
6070
6177
|
}
|
|
6071
6178
|
});
|
|
6072
6179
|
return state;
|
|
@@ -6123,8 +6230,8 @@ const createProjectionItems = (source, checkOwner) => {
|
|
|
6123
6230
|
},
|
|
6124
6231
|
subscribe: (listener) => {
|
|
6125
6232
|
check();
|
|
6126
|
-
|
|
6127
|
-
return (
|
|
6233
|
+
checkSubscription();
|
|
6234
|
+
return addListener(keyListeners, listener);
|
|
6128
6235
|
}
|
|
6129
6236
|
});
|
|
6130
6237
|
return {
|
|
@@ -6132,6 +6239,7 @@ const createProjectionItems = (source, checkOwner) => {
|
|
|
6132
6239
|
keys,
|
|
6133
6240
|
get: (key) => {
|
|
6134
6241
|
check();
|
|
6242
|
+
checkSubscription();
|
|
6135
6243
|
const current = source.current();
|
|
6136
6244
|
if (source.revision() !== settledRevision) pendingKeys.add(key);
|
|
6137
6245
|
const canonical = active.get(key);
|
|
@@ -6176,6 +6284,7 @@ const createProjectionRuntime = (options) => {
|
|
|
6176
6284
|
const materialized = /* @__PURE__ */ new WeakMap();
|
|
6177
6285
|
const publicViews = /* @__PURE__ */ new WeakMap();
|
|
6178
6286
|
const scopes = /* @__PURE__ */ new Set();
|
|
6287
|
+
const cleanups = createCleanupStack();
|
|
6179
6288
|
const rootItems = /* @__PURE__ */ new Map();
|
|
6180
6289
|
const disposeItemControllers = (registry, failures) => {
|
|
6181
6290
|
const controllers = [...registry.values()];
|
|
@@ -6205,7 +6314,7 @@ const createProjectionRuntime = (options) => {
|
|
|
6205
6314
|
const owner = definition.owner;
|
|
6206
6315
|
if (owner === void 0) return;
|
|
6207
6316
|
if (owner !== requester) throw new TypeError("Projection belongs to another scope.");
|
|
6208
|
-
if (
|
|
6317
|
+
if (requester?.status === "disposed") throw new ProjectionDisposedError();
|
|
6209
6318
|
};
|
|
6210
6319
|
const rememberScoped = (definition, requester) => {
|
|
6211
6320
|
if (requester && definition.owner === requester) requester.materialized.push(definition);
|
|
@@ -6285,25 +6394,33 @@ const createProjectionRuntime = (options) => {
|
|
|
6285
6394
|
assertOutput(output);
|
|
6286
6395
|
return output.revision();
|
|
6287
6396
|
},
|
|
6288
|
-
subscribe:
|
|
6289
|
-
|
|
6397
|
+
subscribe: (listener) => {
|
|
6398
|
+
scheduler.assertCommand();
|
|
6399
|
+
return output.subscribe(listener);
|
|
6400
|
+
},
|
|
6401
|
+
observe: (listener) => {
|
|
6402
|
+
scheduler.assertCommand();
|
|
6403
|
+
return output.observe(listener);
|
|
6404
|
+
}
|
|
6290
6405
|
});
|
|
6291
6406
|
};
|
|
6292
6407
|
const projectionItems = (projection, requester) => {
|
|
6408
|
+
scheduler.assertCommand();
|
|
6293
6409
|
const output = resolveOutput(projection, requester);
|
|
6294
6410
|
if (output.kind !== "collection") throw new TypeError("Projection items require a keyed collection projection.");
|
|
6295
6411
|
const registry = requester?.items ?? rootItems;
|
|
6296
6412
|
const existing = registry.get(output);
|
|
6297
6413
|
if (existing) return existing.items;
|
|
6298
6414
|
const controller = createProjectionItems(readableSource(projection, requester), () => {
|
|
6299
|
-
if (requester
|
|
6415
|
+
if (requester?.status === "disposed") throw new ProjectionDisposedError();
|
|
6300
6416
|
scheduler.ensureCurrent(output);
|
|
6301
6417
|
assertOutput(output);
|
|
6302
|
-
});
|
|
6418
|
+
}, scheduler.assertCommand);
|
|
6303
6419
|
registry.set(output, controller);
|
|
6304
6420
|
return controller.items;
|
|
6305
6421
|
};
|
|
6306
6422
|
const makeReadable = (projection, selector, equality, requester) => {
|
|
6423
|
+
scheduler.assertCommand();
|
|
6307
6424
|
const source = readableSource(projection, requester);
|
|
6308
6425
|
return selector ? createSelectorReadable(source, selector, equality) : createDirectReadable(source);
|
|
6309
6426
|
};
|
|
@@ -6311,8 +6428,8 @@ const createProjectionRuntime = (options) => {
|
|
|
6311
6428
|
return makeReadable(projection, selector, equality);
|
|
6312
6429
|
}
|
|
6313
6430
|
const inputAccess = (target, requester) => {
|
|
6314
|
-
scheduler.
|
|
6315
|
-
if (requester
|
|
6431
|
+
scheduler.assertCommand();
|
|
6432
|
+
if (requester?.status === "disposed") throw new ProjectionDisposedError();
|
|
6316
6433
|
const ref = projectionRef(target);
|
|
6317
6434
|
if (ref.output !== 0 || ref.producer.kind !== "source") throw new TypeError("Projection is not an input.");
|
|
6318
6435
|
if (ref.producer.source.kind !== "value-input" && ref.producer.source.kind !== "collection-input") throw new TypeError("Projection is not an input.");
|
|
@@ -6333,11 +6450,9 @@ const createProjectionRuntime = (options) => {
|
|
|
6333
6450
|
updateInput(target, valueOrRun);
|
|
6334
6451
|
}
|
|
6335
6452
|
const batch = (run, options) => scheduler.batch(run, options);
|
|
6336
|
-
const
|
|
6337
|
-
|
|
6338
|
-
|
|
6339
|
-
state.active = false;
|
|
6340
|
-
const failures = [];
|
|
6453
|
+
const releaseScope = (state, failures) => {
|
|
6454
|
+
state.status = "disposed";
|
|
6455
|
+
scopes.delete(state);
|
|
6341
6456
|
disposeScopeConsumers(state, failures);
|
|
6342
6457
|
for (let index = state.materialized.length - 1; index >= 0; index--) {
|
|
6343
6458
|
const definition = state.materialized[index];
|
|
@@ -6352,24 +6467,38 @@ const createProjectionRuntime = (options) => {
|
|
|
6352
6467
|
}
|
|
6353
6468
|
}
|
|
6354
6469
|
state.materialized.length = 0;
|
|
6355
|
-
|
|
6470
|
+
};
|
|
6471
|
+
const disposeScope = (state) => {
|
|
6472
|
+
if (state.status !== "active") return;
|
|
6473
|
+
scheduler.assertCommand();
|
|
6474
|
+
state.status = "closing";
|
|
6475
|
+
const failures = [];
|
|
6476
|
+
try {
|
|
6477
|
+
scheduler.cleanup(() => state.cleanups.drain(failures));
|
|
6478
|
+
} catch (error) {
|
|
6479
|
+
failures.push(error);
|
|
6480
|
+
} finally {
|
|
6481
|
+
scheduler.releaseOwned(() => releaseScope(state, failures));
|
|
6482
|
+
}
|
|
6356
6483
|
throwCleanupFailures(failures, "Projection scope cleanup failed.");
|
|
6357
6484
|
};
|
|
6358
6485
|
const createScope = () => {
|
|
6359
|
-
scheduler.
|
|
6486
|
+
scheduler.assertCommand();
|
|
6360
6487
|
const state = {
|
|
6361
|
-
|
|
6488
|
+
status: "active",
|
|
6489
|
+
cleanups: createCleanupStack(),
|
|
6362
6490
|
materialized: [],
|
|
6363
6491
|
subscriptions: /* @__PURE__ */ new Set(),
|
|
6364
6492
|
items: /* @__PURE__ */ new Map()
|
|
6365
6493
|
};
|
|
6366
6494
|
scopes.add(state);
|
|
6367
6495
|
const assertActive = () => {
|
|
6368
|
-
if (
|
|
6496
|
+
if (state.status === "disposed") throw new ProjectionDisposedError();
|
|
6369
6497
|
scheduler.assertActive();
|
|
6370
6498
|
};
|
|
6371
6499
|
function own(target) {
|
|
6372
6500
|
assertActive();
|
|
6501
|
+
scheduler.assertCommand();
|
|
6373
6502
|
const projections = [];
|
|
6374
6503
|
const collect = (value) => {
|
|
6375
6504
|
if (isProjection(value)) {
|
|
@@ -6439,6 +6568,11 @@ const createProjectionRuntime = (options) => {
|
|
|
6439
6568
|
},
|
|
6440
6569
|
update: scopeUpdate,
|
|
6441
6570
|
batch: scopeBatch,
|
|
6571
|
+
onDispose: (callback) => {
|
|
6572
|
+
assertActive();
|
|
6573
|
+
scheduler.assertCommand();
|
|
6574
|
+
return state.cleanups.add(callback);
|
|
6575
|
+
},
|
|
6442
6576
|
dispose: () => disposeScope(state)
|
|
6443
6577
|
});
|
|
6444
6578
|
};
|
|
@@ -6449,24 +6583,33 @@ const createProjectionRuntime = (options) => {
|
|
|
6449
6583
|
update,
|
|
6450
6584
|
batch,
|
|
6451
6585
|
scope: createScope,
|
|
6586
|
+
onDispose: (callback) => {
|
|
6587
|
+
scheduler.assertCommand();
|
|
6588
|
+
return cleanups.add(callback);
|
|
6589
|
+
},
|
|
6452
6590
|
dispose: () => {
|
|
6453
|
-
if (!scheduler.
|
|
6454
|
-
scheduler.assertIdle();
|
|
6591
|
+
if (!scheduler.beginClose()) return;
|
|
6455
6592
|
const failures = [];
|
|
6456
|
-
|
|
6457
|
-
|
|
6458
|
-
disposeScopeConsumers(scope, failures);
|
|
6459
|
-
scope.materialized.length = 0;
|
|
6460
|
-
}
|
|
6461
|
-
scopes.clear();
|
|
6462
|
-
disposeItemControllers(rootItems, failures);
|
|
6593
|
+
const owned = [...scopes].reverse();
|
|
6594
|
+
for (const scope of owned) scope.status = "closing";
|
|
6463
6595
|
try {
|
|
6464
|
-
|
|
6596
|
+
scheduler.cleanup(() => {
|
|
6597
|
+
for (const scope of owned) scope.cleanups.drain(failures);
|
|
6598
|
+
cleanups.drain(failures);
|
|
6599
|
+
});
|
|
6465
6600
|
} catch (error) {
|
|
6466
6601
|
failures.push(error);
|
|
6467
6602
|
}
|
|
6468
6603
|
try {
|
|
6469
|
-
scheduler.dispose()
|
|
6604
|
+
scheduler.dispose(() => {
|
|
6605
|
+
for (const scope of owned) {
|
|
6606
|
+
scope.status = "disposed";
|
|
6607
|
+
scope.materialized.length = 0;
|
|
6608
|
+
disposeScopeConsumers(scope, failures);
|
|
6609
|
+
}
|
|
6610
|
+
scopes.clear();
|
|
6611
|
+
disposeItemControllers(rootItems, failures);
|
|
6612
|
+
}, sources.dispose);
|
|
6470
6613
|
} catch (error) {
|
|
6471
6614
|
failures.push(error);
|
|
6472
6615
|
}
|
package/dist/local-sync.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_record = require("./record-ChYUi8PP.cjs");
|
|
3
|
-
const require_driver = require("./driver-
|
|
3
|
+
const require_driver = require("./driver-i4G4iVX0.cjs");
|
|
4
4
|
//#region core/src/local-sync/error.ts
|
|
5
5
|
var LocalSyncError = class extends Error {
|
|
6
6
|
code;
|
|
@@ -467,10 +467,7 @@ const attachLocalSync = async (input) => {
|
|
|
467
467
|
revision: () => stateRevision,
|
|
468
468
|
subscribe: (listener) => {
|
|
469
469
|
if (disposed) throw new LocalSyncError("disposed", "Local sync has been disposed.");
|
|
470
|
-
|
|
471
|
-
return () => {
|
|
472
|
-
stateListeners.delete(listener);
|
|
473
|
-
};
|
|
470
|
+
return require_driver.addListener(stateListeners, listener);
|
|
474
471
|
}
|
|
475
472
|
}),
|
|
476
473
|
flush: async () => {
|
package/dist/local-sync.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { W as ObjectSchema, g as Readable, s as DocumentRuntime } from "./contract-
|
|
1
|
+
import { W as ObjectSchema, g as Readable, s as DocumentRuntime } from "./contract-DovG1Yp-.cjs";
|
|
2
2
|
|
|
3
3
|
//#region core/src/local-sync/json.d.ts
|
|
4
4
|
type JsonPrimitive = null | boolean | number | string;
|