doxum 0.1.13 → 0.1.15
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 +10 -2
- package/dist/advanced.cjs +3 -2
- package/dist/advanced.cjs.map +1 -1
- package/dist/advanced.d.cts +1 -1
- package/dist/advanced.d.ts +1 -1
- package/dist/advanced.js +2 -1
- package/dist/advanced.js.map +1 -1
- package/dist/{contract-BT53Gg94.d.ts → contract-CATCCVu5.d.ts} +1 -1
- package/dist/{definition-BlMeHwdz.d.ts → definition-B6J0SSNa.d.ts} +38 -37
- package/dist/{definition-kxnWUvX9.d.cts → definition-DN6yW2vi.d.cts} +37 -36
- package/dist/definition-Z6TagMup.cjs +107 -0
- package/dist/definition-Z6TagMup.cjs.map +1 -0
- package/dist/definition-c6XQXzvK.js +72 -0
- package/dist/definition-c6XQXzvK.js.map +1 -0
- package/dist/index.cjs +2054 -55
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +16 -3
- package/dist/index.d.ts +17 -4
- package/dist/index.js +2001 -2
- package/dist/index.js.map +1 -1
- package/dist/integration-B7VDgAOJ.cjs +30 -0
- package/dist/integration-B7VDgAOJ.cjs.map +1 -0
- package/dist/{integration-Bco8ZB16.js → integration-CxVhq-KD.js} +3 -7
- package/dist/integration-CxVhq-KD.js.map +1 -0
- package/dist/integration.cjs +4 -9
- package/dist/integration.d.cts +2 -7
- package/dist/integration.d.ts +2 -7
- package/dist/integration.js +3 -3
- package/dist/local-sync.d.ts +1 -1
- package/dist/notification-CDSUfiip.cjs +398 -0
- package/dist/notification-CDSUfiip.cjs.map +1 -0
- package/dist/notification-IQIJyH3Q.js +285 -0
- package/dist/notification-IQIJyH3Q.js.map +1 -0
- package/dist/react.cjs +6 -52
- package/dist/react.cjs.map +1 -1
- package/dist/react.js +4 -50
- package/dist/react.js.map +1 -1
- package/dist/{definition-177L4Amk.cjs → scope-Ezs-Y3TY.cjs} +1 -118
- package/dist/scope-Ezs-Y3TY.cjs.map +1 -0
- package/dist/{definition-DXrKMVs7.js → scope-d-L87NeC.js} +2 -65
- package/dist/scope-d-L87NeC.js.map +1 -0
- package/package.json +1 -1
- package/skills/doxum-runtime/references/guide.en.md +2 -1
- package/skills/doxum-runtime/references/guide.zh-CN.md +2 -1
- package/skills/doxum-runtime/references/projections.en.md +15 -6
- package/skills/doxum-runtime/references/projections.zh-CN.md +13 -5
- package/dist/definition-177L4Amk.cjs.map +0 -1
- package/dist/definition-DXrKMVs7.js.map +0 -1
- package/dist/integration-Bco8ZB16.js.map +0 -1
- package/dist/integration-CEUn96tx.cjs +0 -52
- package/dist/integration-CEUn96tx.cjs.map +0 -1
- package/dist/store-CDeqZEE3.d.cts +0 -28
- package/dist/store-CtgvCVFg.js +0 -2222
- package/dist/store-CtgvCVFg.js.map +0 -1
- package/dist/store-DcDpDgjk.cjs +0 -2401
- package/dist/store-DcDpDgjk.cjs.map +0 -1
- package/dist/store-P5dJ7TVe.d.ts +0 -28
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
const require_notification = require("./notification-CDSUfiip.cjs");
|
|
2
|
+
//#region core/src/access/dependency.ts
|
|
3
|
+
const createDependencyTracker = () => {
|
|
4
|
+
const targets = [];
|
|
5
|
+
return {
|
|
6
|
+
record: (value) => {
|
|
7
|
+
if (!targets.some((entry) => require_notification.same(entry, value))) targets.push(value);
|
|
8
|
+
},
|
|
9
|
+
snapshot: () => Object.freeze(targets.slice())
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
//#endregion
|
|
13
|
+
//#region core/src/integration.ts
|
|
14
|
+
const track = (runtime, selector) => {
|
|
15
|
+
const dependencies = createDependencyTracker();
|
|
16
|
+
const value = require_notification.readWith(runtime, selector, dependencies);
|
|
17
|
+
return Object.freeze({
|
|
18
|
+
value,
|
|
19
|
+
targets: dependencies.snapshot()
|
|
20
|
+
});
|
|
21
|
+
};
|
|
22
|
+
//#endregion
|
|
23
|
+
Object.defineProperty(exports, "track", {
|
|
24
|
+
enumerable: true,
|
|
25
|
+
get: function() {
|
|
26
|
+
return track;
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
//# sourceMappingURL=integration-B7VDgAOJ.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"integration-B7VDgAOJ.cjs","names":["readWith"],"sources":["../core/src/access/dependency.ts","../core/src/integration.ts"],"sourcesContent":["import type { ImpactTarget } from '../schema';\nimport * as impactTarget from '../impact-target';\n\nexport type DependencyTracker = {\n readonly record: (target: ImpactTarget<unknown>) => void;\n readonly snapshot: () => readonly ImpactTarget<unknown>[];\n};\n\nexport const createDependencyTracker = (): DependencyTracker => {\n const targets: ImpactTarget<unknown>[] = [];\n return {\n record: value => {\n if (!targets.some(entry => impactTarget.same(entry, value))) targets.push(value);\n },\n snapshot: () => Object.freeze(targets.slice()),\n };\n};\n","import type { ObjectNode, ImpactTarget } from './schema';\nimport type { Read } from './access/scope';\nimport type { DocumentReadable } from './runtime/contract';\nimport { createDependencyTracker } from './access/dependency';\nimport { readWith } from './runtime/access';\nexport type { AddressRef } from './address';\nexport { contains, debugKey, overlaps, read as readAddress, resolveAddress } from './address';\nexport { subscribeDependencies } from './runtime/notification';\nexport { same as sameTarget } from './impact-target';\n\nexport type { ImpactTarget } from './schema';\n\nexport type TrackedSelection<TValue> = {\n readonly value: TValue;\n readonly targets: readonly ImpactTarget<unknown>[];\n};\n\n// Framework adapters receive one immutable result instead of coordinating a\n// mutable collector with the reader's scoped lifetime themselves.\nexport const track = <TSchema extends ObjectNode, TValue>(\n runtime: DocumentReadable<TSchema>,\n selector: (read: Read<TSchema>) => TValue\n): TrackedSelection<TValue> => {\n const dependencies = createDependencyTracker();\n const value = readWith(runtime, selector, dependencies);\n return Object.freeze({ value, targets: dependencies.snapshot() });\n};\n"],"mappings":";;AAQA,MAAa,gCAAmD;CAC9D,MAAM,UAAmC,EAAE;AAC3C,QAAO;EACL,SAAQ,UAAS;AACf,OAAI,CAAC,QAAQ,MAAK,UAAA,qBAAA,KAA2B,OAAO,MAAM,CAAC,CAAE,SAAQ,KAAK,MAAM;;EAElF,gBAAgB,OAAO,OAAO,QAAQ,OAAO,CAAC;EAC/C;;;;ACIH,MAAa,SACX,SACA,aAC6B;CAC7B,MAAM,eAAe,yBAAyB;CAC9C,MAAM,QAAQA,qBAAAA,SAAS,SAAS,UAAU,aAAa;AACvD,QAAO,OAAO,OAAO;EAAE;EAAO,SAAS,aAAa,UAAU;EAAE,CAAC"}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { g as readWith, x as same } from "./store-CtgvCVFg.js";
|
|
1
|
+
import { p as readWith, y as same } from "./notification-IQIJyH3Q.js";
|
|
3
2
|
//#region core/src/access/dependency.ts
|
|
4
3
|
const createDependencyTracker = () => {
|
|
5
4
|
const targets = [];
|
|
@@ -12,9 +11,6 @@ const createDependencyTracker = () => {
|
|
|
12
11
|
};
|
|
13
12
|
//#endregion
|
|
14
13
|
//#region core/src/integration.ts
|
|
15
|
-
const observeReadable = (readable) => defineReadable(readable);
|
|
16
|
-
const observeExternal = (source) => defineExternalValue(source);
|
|
17
|
-
const observeExternalCollection = (source) => defineExternalCollection(source);
|
|
18
14
|
const track = (runtime, selector) => {
|
|
19
15
|
const dependencies = createDependencyTracker();
|
|
20
16
|
const value = readWith(runtime, selector, dependencies);
|
|
@@ -24,6 +20,6 @@ const track = (runtime, selector) => {
|
|
|
24
20
|
});
|
|
25
21
|
};
|
|
26
22
|
//#endregion
|
|
27
|
-
export { track as
|
|
23
|
+
export { track as t };
|
|
28
24
|
|
|
29
|
-
//# sourceMappingURL=integration-
|
|
25
|
+
//# sourceMappingURL=integration-CxVhq-KD.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"integration-CxVhq-KD.js","names":["impactTarget.same"],"sources":["../core/src/access/dependency.ts","../core/src/integration.ts"],"sourcesContent":["import type { ImpactTarget } from '../schema';\nimport * as impactTarget from '../impact-target';\n\nexport type DependencyTracker = {\n readonly record: (target: ImpactTarget<unknown>) => void;\n readonly snapshot: () => readonly ImpactTarget<unknown>[];\n};\n\nexport const createDependencyTracker = (): DependencyTracker => {\n const targets: ImpactTarget<unknown>[] = [];\n return {\n record: value => {\n if (!targets.some(entry => impactTarget.same(entry, value))) targets.push(value);\n },\n snapshot: () => Object.freeze(targets.slice()),\n };\n};\n","import type { ObjectNode, ImpactTarget } from './schema';\nimport type { Read } from './access/scope';\nimport type { DocumentReadable } from './runtime/contract';\nimport { createDependencyTracker } from './access/dependency';\nimport { readWith } from './runtime/access';\nexport type { AddressRef } from './address';\nexport { contains, debugKey, overlaps, read as readAddress, resolveAddress } from './address';\nexport { subscribeDependencies } from './runtime/notification';\nexport { same as sameTarget } from './impact-target';\n\nexport type { ImpactTarget } from './schema';\n\nexport type TrackedSelection<TValue> = {\n readonly value: TValue;\n readonly targets: readonly ImpactTarget<unknown>[];\n};\n\n// Framework adapters receive one immutable result instead of coordinating a\n// mutable collector with the reader's scoped lifetime themselves.\nexport const track = <TSchema extends ObjectNode, TValue>(\n runtime: DocumentReadable<TSchema>,\n selector: (read: Read<TSchema>) => TValue\n): TrackedSelection<TValue> => {\n const dependencies = createDependencyTracker();\n const value = readWith(runtime, selector, dependencies);\n return Object.freeze({ value, targets: dependencies.snapshot() });\n};\n"],"mappings":";;AAQA,MAAa,gCAAmD;CAC9D,MAAM,UAAmC,EAAE;AAC3C,QAAO;EACL,SAAQ,UAAS;AACf,OAAI,CAAC,QAAQ,MAAK,UAASA,KAAkB,OAAO,MAAM,CAAC,CAAE,SAAQ,KAAK,MAAM;;EAElF,gBAAgB,OAAO,OAAO,QAAQ,OAAO,CAAC;EAC/C;;;;ACIH,MAAa,SACX,SACA,aAC6B;CAC7B,MAAM,eAAe,yBAAyB;CAC9C,MAAM,QAAQ,SAAS,SAAS,UAAU,aAAa;AACvD,QAAO,OAAO,OAAO;EAAE;EAAO,SAAS,aAAa,UAAU;EAAE,CAAC"}
|
package/dist/integration.cjs
CHANGED
|
@@ -1,17 +1,12 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_issue = require("./issue-DhrNdQNg.cjs");
|
|
3
|
-
const
|
|
4
|
-
const require_integration = require("./integration-
|
|
3
|
+
const require_notification = require("./notification-CDSUfiip.cjs");
|
|
4
|
+
const require_integration = require("./integration-B7VDgAOJ.cjs");
|
|
5
5
|
exports.contains = require_issue.contains;
|
|
6
6
|
exports.debugKey = require_issue.debugKey;
|
|
7
|
-
exports.observeExternal = require_integration.observeExternal;
|
|
8
|
-
exports.observeExternalCollection = require_integration.observeExternalCollection;
|
|
9
|
-
exports.observeReadable = require_integration.observeReadable;
|
|
10
7
|
exports.overlaps = require_issue.overlaps;
|
|
11
8
|
exports.readAddress = require_issue.read;
|
|
12
9
|
exports.resolveAddress = require_issue.resolveAddress;
|
|
13
|
-
exports.sameTarget =
|
|
14
|
-
exports.subscribeDependencies =
|
|
15
|
-
exports.subscribeProjection = require_store.subscribeProjection;
|
|
10
|
+
exports.sameTarget = require_notification.same;
|
|
11
|
+
exports.subscribeDependencies = require_notification.subscribeDependencies;
|
|
16
12
|
exports.track = require_integration.track;
|
|
17
|
-
exports.trackProjection = require_store.trackProjection;
|
package/dist/integration.d.cts
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import { A as overlaps, D as AddressRef, M as resolveAddress, O as contains, Z as ObjectNode, _ as Unsubscribe, j as read, k as debugKey, q as ImpactTarget, s as DocumentReadable, t as CommitListener,
|
|
2
|
-
import { d as ExternalCollectionSource, f as ExternalValueSource, i as PublicCollection, n as Projection } from "./definition-kxnWUvX9.cjs";
|
|
3
|
-
import { a as trackProjection, i as subscribeProjection, n as ProjectionSelection } from "./store-CDeqZEE3.cjs";
|
|
1
|
+
import { A as overlaps, D as AddressRef, M as resolveAddress, O as contains, Z as ObjectNode, _ as Unsubscribe, j as read, k as debugKey, q as ImpactTarget, s as DocumentReadable, t as CommitListener, w as Read } from "./contract-XmKnroJq.cjs";
|
|
4
2
|
|
|
5
3
|
//#region core/src/impact-target.d.ts
|
|
6
4
|
declare const same: (left: ImpactTarget<unknown>, right: ImpactTarget<unknown>) => boolean;
|
|
@@ -9,14 +7,11 @@ declare const same: (left: ImpactTarget<unknown>, right: ImpactTarget<unknown>)
|
|
|
9
7
|
declare const subscribeDependencies: <S extends ObjectNode>(runtime: DocumentReadable<S>, targets: readonly ImpactTarget[], listener: CommitListener<S>) => Unsubscribe;
|
|
10
8
|
//#endregion
|
|
11
9
|
//#region core/src/integration.d.ts
|
|
12
|
-
declare const observeReadable: <T>(readable: Readable<T>) => Projection<T>;
|
|
13
|
-
declare const observeExternal: <T, D>(source: ExternalValueSource<T, D>) => Projection<T>;
|
|
14
|
-
declare const observeExternalCollection: <K extends string, V, D>(source: ExternalCollectionSource<K, V, D>) => Projection<PublicCollection<K, V>>;
|
|
15
10
|
type TrackedSelection<TValue> = {
|
|
16
11
|
readonly value: TValue;
|
|
17
12
|
readonly targets: readonly ImpactTarget<unknown>[];
|
|
18
13
|
};
|
|
19
14
|
declare const track: <TSchema extends ObjectNode, TValue>(runtime: DocumentReadable<TSchema>, selector: (read: Read<TSchema>) => TValue) => TrackedSelection<TValue>;
|
|
20
15
|
//#endregion
|
|
21
|
-
export { type AddressRef, type ImpactTarget,
|
|
16
|
+
export { type AddressRef, type ImpactTarget, TrackedSelection, contains, debugKey, overlaps, read as readAddress, resolveAddress, same as sameTarget, subscribeDependencies, track };
|
|
22
17
|
//# sourceMappingURL=integration.d.cts.map
|
package/dist/integration.d.ts
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import { A as overlaps, D as AddressRef, M as resolveAddress, O as contains, Z as ObjectNode, _ as Unsubscribe, j as read, k as debugKey, q as ImpactTarget, s as DocumentReadable, t as CommitListener,
|
|
2
|
-
import { d as ExternalCollectionSource, f as ExternalValueSource, i as PublicCollection, n as Projection } from "./definition-BlMeHwdz.js";
|
|
3
|
-
import { a as trackProjection, i as subscribeProjection, n as ProjectionSelection } from "./store-P5dJ7TVe.js";
|
|
1
|
+
import { A as overlaps, D as AddressRef, M as resolveAddress, O as contains, Z as ObjectNode, _ as Unsubscribe, j as read, k as debugKey, q as ImpactTarget, s as DocumentReadable, t as CommitListener, w as Read } from "./contract-CATCCVu5.js";
|
|
4
2
|
|
|
5
3
|
//#region core/src/impact-target.d.ts
|
|
6
4
|
declare const same: (left: ImpactTarget<unknown>, right: ImpactTarget<unknown>) => boolean;
|
|
@@ -9,14 +7,11 @@ declare const same: (left: ImpactTarget<unknown>, right: ImpactTarget<unknown>)
|
|
|
9
7
|
declare const subscribeDependencies: <S extends ObjectNode>(runtime: DocumentReadable<S>, targets: readonly ImpactTarget[], listener: CommitListener<S>) => Unsubscribe;
|
|
10
8
|
//#endregion
|
|
11
9
|
//#region core/src/integration.d.ts
|
|
12
|
-
declare const observeReadable: <T>(readable: Readable<T>) => Projection<T>;
|
|
13
|
-
declare const observeExternal: <T, D>(source: ExternalValueSource<T, D>) => Projection<T>;
|
|
14
|
-
declare const observeExternalCollection: <K extends string, V, D>(source: ExternalCollectionSource<K, V, D>) => Projection<PublicCollection<K, V>>;
|
|
15
10
|
type TrackedSelection<TValue> = {
|
|
16
11
|
readonly value: TValue;
|
|
17
12
|
readonly targets: readonly ImpactTarget<unknown>[];
|
|
18
13
|
};
|
|
19
14
|
declare const track: <TSchema extends ObjectNode, TValue>(runtime: DocumentReadable<TSchema>, selector: (read: Read<TSchema>) => TValue) => TrackedSelection<TValue>;
|
|
20
15
|
//#endregion
|
|
21
|
-
export { type AddressRef, type ImpactTarget,
|
|
16
|
+
export { type AddressRef, type ImpactTarget, TrackedSelection, contains, debugKey, overlaps, read as readAddress, resolveAddress, same as sameTarget, subscribeDependencies, track };
|
|
22
17
|
//# sourceMappingURL=integration.d.ts.map
|
package/dist/integration.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { c as debugKey, d as overlaps, f as read, o as contains, p as resolveAddress } from "./issue-DVaGQGeP.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
export { contains, debugKey,
|
|
2
|
+
import { c as subscribeDependencies, y as same } from "./notification-IQIJyH3Q.js";
|
|
3
|
+
import { t as track } from "./integration-CxVhq-KD.js";
|
|
4
|
+
export { contains, debugKey, overlaps, read as readAddress, resolveAddress, same as sameTarget, subscribeDependencies, track };
|
package/dist/local-sync.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Z as ObjectNode, l as DocumentRuntime, v as Readable } from "./contract-
|
|
1
|
+
import { Z as ObjectNode, l as DocumentRuntime, v as Readable } from "./contract-CATCCVu5.js";
|
|
2
2
|
|
|
3
3
|
//#region core/src/local-sync/json.d.ts
|
|
4
4
|
type JsonPrimitive = null | boolean | number | string;
|
|
@@ -0,0 +1,398 @@
|
|
|
1
|
+
const require_issue = require("./issue-DhrNdQNg.cjs");
|
|
2
|
+
const require_scope = require("./scope-Ezs-Y3TY.cjs");
|
|
3
|
+
//#region core/src/impact-target.ts
|
|
4
|
+
const address = (target) => "at" in target ? target.at : target.address;
|
|
5
|
+
const id = (target) => target.kind === "collection" && "id" in target ? target.id : void 0;
|
|
6
|
+
const belongs = (target, schema) => !("schema" in target) || target.schema === schema;
|
|
7
|
+
const same = (left, right) => {
|
|
8
|
+
if (left.kind !== right.kind) return false;
|
|
9
|
+
if ("schema" in left && "schema" in right && left.schema !== right.schema) return false;
|
|
10
|
+
const leftAddress = address(left);
|
|
11
|
+
const rightAddress = address(right);
|
|
12
|
+
if (leftAddress.length !== rightAddress.length) return false;
|
|
13
|
+
for (let index = 0; index < leftAddress.length; index += 1) if (leftAddress[index] !== rightAddress[index]) return false;
|
|
14
|
+
return left.kind !== "collection" || id(left) === id(right);
|
|
15
|
+
};
|
|
16
|
+
const indexedAddress = (target) => {
|
|
17
|
+
const key = id(target);
|
|
18
|
+
return key === void 0 ? address(target) : [...address(target), key];
|
|
19
|
+
};
|
|
20
|
+
const affected = (target, values, orders) => {
|
|
21
|
+
const at = indexedAddress(target);
|
|
22
|
+
return id(target) !== void 0 ? values.hasAncestor(at) : values.overlaps(at) || orders.hasDescendant(at);
|
|
23
|
+
};
|
|
24
|
+
/** Targets are classified once; commit matching never builds a reverse impact index. */
|
|
25
|
+
var SubscriptionIndex = class {
|
|
26
|
+
ordinary = new require_issue.AddressIndex();
|
|
27
|
+
membership = new require_issue.AddressIndex();
|
|
28
|
+
constructor(schema) {
|
|
29
|
+
this.schema = schema;
|
|
30
|
+
}
|
|
31
|
+
add(target, value) {
|
|
32
|
+
if (belongs(target, this.schema)) (id(target) === void 0 ? this.ordinary : this.membership).add(indexedAddress(target), value);
|
|
33
|
+
}
|
|
34
|
+
delete(target, value) {
|
|
35
|
+
if (belongs(target, this.schema)) (id(target) === void 0 ? this.ordinary : this.membership).delete(indexedAddress(target), value);
|
|
36
|
+
}
|
|
37
|
+
collect(changes, visit) {
|
|
38
|
+
const values = this.ordinary.query(visit);
|
|
39
|
+
const members = this.membership.query(visit, "descendants");
|
|
40
|
+
const orders = this.ordinary.query(visit, "ancestors");
|
|
41
|
+
for (const change of changes.changes) if (change.kind === "reset") {
|
|
42
|
+
values([]);
|
|
43
|
+
members([]);
|
|
44
|
+
} else if (change.kind === "members") {
|
|
45
|
+
values(change.at, change.members);
|
|
46
|
+
members(change.at, change.members);
|
|
47
|
+
if (change.order) orders(change.at);
|
|
48
|
+
} else {
|
|
49
|
+
values(change.at);
|
|
50
|
+
members(change.at);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
clear() {
|
|
54
|
+
this.ordinary.clear();
|
|
55
|
+
this.membership.clear();
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
//#endregion
|
|
59
|
+
//#region core/src/runtime/contract.ts
|
|
60
|
+
var DocumentReentrancyError = class extends Error {
|
|
61
|
+
constructor() {
|
|
62
|
+
super("Document writes cannot be re-entered during an update or notification.");
|
|
63
|
+
this.name = "DocumentReentrancyError";
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
var DocumentDisposedError = class extends Error {
|
|
67
|
+
constructor() {
|
|
68
|
+
super("Doxum runtime has been disposed.");
|
|
69
|
+
this.name = "DocumentDisposedError";
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
var TransactionRejected = class extends Error {
|
|
73
|
+
issues;
|
|
74
|
+
constructor(input) {
|
|
75
|
+
super("Document update rejected.");
|
|
76
|
+
this.name = "TransactionRejected";
|
|
77
|
+
const issues = Array.isArray(input) ? input : [input];
|
|
78
|
+
this.issues = Object.freeze(issues.map((issue) => Object.freeze({
|
|
79
|
+
code: issue.code,
|
|
80
|
+
message: issue.message,
|
|
81
|
+
source: "application",
|
|
82
|
+
...issue.address === void 0 ? {} : { address: Object.freeze([...issue.address]) }
|
|
83
|
+
})));
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
//#endregion
|
|
87
|
+
//#region core/src/runtime/access.ts
|
|
88
|
+
const states = /* @__PURE__ */ new WeakMap();
|
|
89
|
+
const bindRuntimeAccess = (runtime, state) => {
|
|
90
|
+
states.set(runtime, state);
|
|
91
|
+
};
|
|
92
|
+
const accessOf = (runtime) => {
|
|
93
|
+
const state = states.get(runtime);
|
|
94
|
+
if (!state) throw new Error("Unknown Doxum runtime.");
|
|
95
|
+
return state;
|
|
96
|
+
};
|
|
97
|
+
const readWith = (runtime, run, dependencies) => {
|
|
98
|
+
const state = accessOf(runtime);
|
|
99
|
+
if (state.disposed) throw new DocumentDisposedError();
|
|
100
|
+
state.projectionLocks = (state.projectionLocks ?? 0) + 1;
|
|
101
|
+
try {
|
|
102
|
+
return run(require_scope.createAccess({
|
|
103
|
+
state,
|
|
104
|
+
dependencies
|
|
105
|
+
}));
|
|
106
|
+
} finally {
|
|
107
|
+
state.projectionLocks--;
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
//#endregion
|
|
111
|
+
//#region core/src/runtime/notification.ts
|
|
112
|
+
const notifications = /* @__PURE__ */ new WeakMap();
|
|
113
|
+
const readableOwners = /* @__PURE__ */ new WeakMap();
|
|
114
|
+
const bindDocumentReadable = (readable, runtime) => {
|
|
115
|
+
readableOwners.set(readable, runtime);
|
|
116
|
+
};
|
|
117
|
+
const documentReadableOwner = (readable) => readableOwners.get(readable);
|
|
118
|
+
const createNotification = (runtime) => {
|
|
119
|
+
const notification = {
|
|
120
|
+
root: /* @__PURE__ */ new Set(),
|
|
121
|
+
filtered: /* @__PURE__ */ new Set(),
|
|
122
|
+
index: new SubscriptionIndex(runtime.schema),
|
|
123
|
+
cleanups: /* @__PURE__ */ new Set(),
|
|
124
|
+
processors: [],
|
|
125
|
+
candidates: /* @__PURE__ */ new Set(),
|
|
126
|
+
rootSnapshot: [],
|
|
127
|
+
notifying: false
|
|
128
|
+
};
|
|
129
|
+
notifications.set(runtime, notification);
|
|
130
|
+
return notification;
|
|
131
|
+
};
|
|
132
|
+
const notificationOf = (runtime) => {
|
|
133
|
+
const value = notifications.get(runtime);
|
|
134
|
+
if (!value) throw new Error("Unknown Doxum runtime.");
|
|
135
|
+
return value;
|
|
136
|
+
};
|
|
137
|
+
const shareNotification = (source, target) => {
|
|
138
|
+
notifications.set(target, notificationOf(source));
|
|
139
|
+
};
|
|
140
|
+
const attachProjection = (runtime, processor) => {
|
|
141
|
+
const notification = notificationOf(runtime);
|
|
142
|
+
const entry = {
|
|
143
|
+
processor,
|
|
144
|
+
active: true
|
|
145
|
+
};
|
|
146
|
+
notification.processors.push(entry);
|
|
147
|
+
return () => {
|
|
148
|
+
if (!entry.active) return;
|
|
149
|
+
entry.active = false;
|
|
150
|
+
if (!notification.notifying) {
|
|
151
|
+
const index = notification.processors.indexOf(entry);
|
|
152
|
+
if (index >= 0) notification.processors.splice(index, 1);
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
};
|
|
156
|
+
const subscribeRoot = (notification, listener) => {
|
|
157
|
+
const entry = {
|
|
158
|
+
listener,
|
|
159
|
+
active: true
|
|
160
|
+
};
|
|
161
|
+
notification.root.add(entry);
|
|
162
|
+
return () => {
|
|
163
|
+
entry.active = false;
|
|
164
|
+
if (!notification.notifying) notification.root.delete(entry);
|
|
165
|
+
else notification.cleanups.add(() => {
|
|
166
|
+
notification.root.delete(entry);
|
|
167
|
+
});
|
|
168
|
+
};
|
|
169
|
+
};
|
|
170
|
+
const subscribeTargets = (notification, targets, listener) => {
|
|
171
|
+
const entry = {
|
|
172
|
+
targets: Object.freeze(targets.slice()),
|
|
173
|
+
listener,
|
|
174
|
+
active: true
|
|
175
|
+
};
|
|
176
|
+
notification.filtered.add(entry);
|
|
177
|
+
entry.targets.forEach((value) => notification.index.add(value, entry));
|
|
178
|
+
const remove = () => {
|
|
179
|
+
notification.filtered.delete(entry);
|
|
180
|
+
entry.targets.forEach((value) => notification.index.delete(value, entry));
|
|
181
|
+
};
|
|
182
|
+
return () => {
|
|
183
|
+
if (!entry.active) return;
|
|
184
|
+
entry.active = false;
|
|
185
|
+
if (notification.notifying) notification.cleanups.add(remove);
|
|
186
|
+
else remove();
|
|
187
|
+
};
|
|
188
|
+
};
|
|
189
|
+
const notify = (notification, commit, afterSettle) => {
|
|
190
|
+
notification.notifying = true;
|
|
191
|
+
const errors = [];
|
|
192
|
+
const call = (listener) => {
|
|
193
|
+
try {
|
|
194
|
+
listener(commit);
|
|
195
|
+
} catch (error) {
|
|
196
|
+
errors.push(Object.freeze({
|
|
197
|
+
phase: "listener",
|
|
198
|
+
error
|
|
199
|
+
}));
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
try {
|
|
203
|
+
const processorCount = notification.processors.length;
|
|
204
|
+
for (let index = 0; index < processorCount; index += 1) {
|
|
205
|
+
const entry = notification.processors[index];
|
|
206
|
+
if (!entry?.active) continue;
|
|
207
|
+
try {
|
|
208
|
+
entry.processor.capture(commit);
|
|
209
|
+
} catch (error) {
|
|
210
|
+
errors.push(Object.freeze({
|
|
211
|
+
phase: "processor",
|
|
212
|
+
error
|
|
213
|
+
}));
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
for (let index = 0; index < processorCount; index += 1) {
|
|
217
|
+
const entry = notification.processors[index];
|
|
218
|
+
if (!entry?.active) continue;
|
|
219
|
+
try {
|
|
220
|
+
entry.processor.settle();
|
|
221
|
+
} catch (error) {
|
|
222
|
+
errors.push(Object.freeze({
|
|
223
|
+
phase: "processor",
|
|
224
|
+
error
|
|
225
|
+
}));
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
for (let index = 0; index < processorCount; index += 1) {
|
|
229
|
+
const entry = notification.processors[index];
|
|
230
|
+
if (!entry?.active) continue;
|
|
231
|
+
try {
|
|
232
|
+
errors.push(...entry.processor.flush());
|
|
233
|
+
} catch (error) {
|
|
234
|
+
errors.push(Object.freeze({
|
|
235
|
+
phase: "flush",
|
|
236
|
+
error
|
|
237
|
+
}));
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
if (afterSettle) errors.push(...afterSettle());
|
|
241
|
+
const candidates = notification.candidates;
|
|
242
|
+
candidates.clear();
|
|
243
|
+
if (notification.filtered.size) notification.index.collect(commit.changes, (entry) => candidates.add(entry));
|
|
244
|
+
candidates.forEach((entry) => {
|
|
245
|
+
if (entry.active) call(entry.listener);
|
|
246
|
+
});
|
|
247
|
+
const rootSnapshot = notification.rootSnapshot;
|
|
248
|
+
rootSnapshot.length = 0;
|
|
249
|
+
notification.root.forEach((entry) => rootSnapshot.push(entry));
|
|
250
|
+
for (const entry of rootSnapshot) if (entry.active) call(entry.listener);
|
|
251
|
+
} finally {
|
|
252
|
+
notification.notifying = false;
|
|
253
|
+
let writeIndex = 0;
|
|
254
|
+
for (const entry of notification.processors) if (entry.active) notification.processors[writeIndex++] = entry;
|
|
255
|
+
notification.processors.length = writeIndex;
|
|
256
|
+
notification.cleanups.forEach((cleanup) => cleanup());
|
|
257
|
+
notification.cleanups.clear();
|
|
258
|
+
}
|
|
259
|
+
return Object.freeze(errors);
|
|
260
|
+
};
|
|
261
|
+
const subscribeDependencies = (runtime, targets, listener) => subscribeTargets(notificationOf(runtime), targets, listener);
|
|
262
|
+
const disposeNotification = (notification) => {
|
|
263
|
+
const attachments = notification.processors.slice();
|
|
264
|
+
notification.root.clear();
|
|
265
|
+
notification.filtered.clear();
|
|
266
|
+
notification.index.clear();
|
|
267
|
+
notification.cleanups.clear();
|
|
268
|
+
notification.processors.length = 0;
|
|
269
|
+
notification.candidates.clear();
|
|
270
|
+
notification.rootSnapshot.length = 0;
|
|
271
|
+
const errors = [];
|
|
272
|
+
attachments.forEach((entry) => {
|
|
273
|
+
if (!entry.active) return;
|
|
274
|
+
try {
|
|
275
|
+
entry.processor.dispose();
|
|
276
|
+
} catch (error) {
|
|
277
|
+
errors.push(error);
|
|
278
|
+
}
|
|
279
|
+
});
|
|
280
|
+
if (errors.length) throw new AggregateError(errors, "Projection disposal notification failed.");
|
|
281
|
+
};
|
|
282
|
+
//#endregion
|
|
283
|
+
Object.defineProperty(exports, "DocumentDisposedError", {
|
|
284
|
+
enumerable: true,
|
|
285
|
+
get: function() {
|
|
286
|
+
return DocumentDisposedError;
|
|
287
|
+
}
|
|
288
|
+
});
|
|
289
|
+
Object.defineProperty(exports, "DocumentReentrancyError", {
|
|
290
|
+
enumerable: true,
|
|
291
|
+
get: function() {
|
|
292
|
+
return DocumentReentrancyError;
|
|
293
|
+
}
|
|
294
|
+
});
|
|
295
|
+
Object.defineProperty(exports, "TransactionRejected", {
|
|
296
|
+
enumerable: true,
|
|
297
|
+
get: function() {
|
|
298
|
+
return TransactionRejected;
|
|
299
|
+
}
|
|
300
|
+
});
|
|
301
|
+
Object.defineProperty(exports, "accessOf", {
|
|
302
|
+
enumerable: true,
|
|
303
|
+
get: function() {
|
|
304
|
+
return accessOf;
|
|
305
|
+
}
|
|
306
|
+
});
|
|
307
|
+
Object.defineProperty(exports, "affected", {
|
|
308
|
+
enumerable: true,
|
|
309
|
+
get: function() {
|
|
310
|
+
return affected;
|
|
311
|
+
}
|
|
312
|
+
});
|
|
313
|
+
Object.defineProperty(exports, "attachProjection", {
|
|
314
|
+
enumerable: true,
|
|
315
|
+
get: function() {
|
|
316
|
+
return attachProjection;
|
|
317
|
+
}
|
|
318
|
+
});
|
|
319
|
+
Object.defineProperty(exports, "belongs", {
|
|
320
|
+
enumerable: true,
|
|
321
|
+
get: function() {
|
|
322
|
+
return belongs;
|
|
323
|
+
}
|
|
324
|
+
});
|
|
325
|
+
Object.defineProperty(exports, "bindDocumentReadable", {
|
|
326
|
+
enumerable: true,
|
|
327
|
+
get: function() {
|
|
328
|
+
return bindDocumentReadable;
|
|
329
|
+
}
|
|
330
|
+
});
|
|
331
|
+
Object.defineProperty(exports, "bindRuntimeAccess", {
|
|
332
|
+
enumerable: true,
|
|
333
|
+
get: function() {
|
|
334
|
+
return bindRuntimeAccess;
|
|
335
|
+
}
|
|
336
|
+
});
|
|
337
|
+
Object.defineProperty(exports, "createNotification", {
|
|
338
|
+
enumerable: true,
|
|
339
|
+
get: function() {
|
|
340
|
+
return createNotification;
|
|
341
|
+
}
|
|
342
|
+
});
|
|
343
|
+
Object.defineProperty(exports, "disposeNotification", {
|
|
344
|
+
enumerable: true,
|
|
345
|
+
get: function() {
|
|
346
|
+
return disposeNotification;
|
|
347
|
+
}
|
|
348
|
+
});
|
|
349
|
+
Object.defineProperty(exports, "documentReadableOwner", {
|
|
350
|
+
enumerable: true,
|
|
351
|
+
get: function() {
|
|
352
|
+
return documentReadableOwner;
|
|
353
|
+
}
|
|
354
|
+
});
|
|
355
|
+
Object.defineProperty(exports, "notify", {
|
|
356
|
+
enumerable: true,
|
|
357
|
+
get: function() {
|
|
358
|
+
return notify;
|
|
359
|
+
}
|
|
360
|
+
});
|
|
361
|
+
Object.defineProperty(exports, "readWith", {
|
|
362
|
+
enumerable: true,
|
|
363
|
+
get: function() {
|
|
364
|
+
return readWith;
|
|
365
|
+
}
|
|
366
|
+
});
|
|
367
|
+
Object.defineProperty(exports, "same", {
|
|
368
|
+
enumerable: true,
|
|
369
|
+
get: function() {
|
|
370
|
+
return same;
|
|
371
|
+
}
|
|
372
|
+
});
|
|
373
|
+
Object.defineProperty(exports, "shareNotification", {
|
|
374
|
+
enumerable: true,
|
|
375
|
+
get: function() {
|
|
376
|
+
return shareNotification;
|
|
377
|
+
}
|
|
378
|
+
});
|
|
379
|
+
Object.defineProperty(exports, "subscribeDependencies", {
|
|
380
|
+
enumerable: true,
|
|
381
|
+
get: function() {
|
|
382
|
+
return subscribeDependencies;
|
|
383
|
+
}
|
|
384
|
+
});
|
|
385
|
+
Object.defineProperty(exports, "subscribeRoot", {
|
|
386
|
+
enumerable: true,
|
|
387
|
+
get: function() {
|
|
388
|
+
return subscribeRoot;
|
|
389
|
+
}
|
|
390
|
+
});
|
|
391
|
+
Object.defineProperty(exports, "subscribeTargets", {
|
|
392
|
+
enumerable: true,
|
|
393
|
+
get: function() {
|
|
394
|
+
return subscribeTargets;
|
|
395
|
+
}
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
//# sourceMappingURL=notification-CDSUfiip.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notification-CDSUfiip.cjs","names":["AddressIndex","createAccess","target.SubscriptionIndex"],"sources":["../core/src/impact-target.ts","../core/src/runtime/contract.ts","../core/src/runtime/access.ts","../core/src/runtime/notification.ts"],"sourcesContent":["import type { DocumentAddress, ObjectNode, ImpactTarget } from './schema';\nimport type { ChangeSet } from './changes';\nimport { AddressIndex } from './address';\n\nexport const address = (target: ImpactTarget<unknown>): DocumentAddress =>\n 'at' in target ? target.at : target.address;\n\nexport const id = (target: ImpactTarget<unknown>): string | undefined =>\n target.kind === 'collection' && 'id' in target ? target.id : undefined;\n\nexport const belongs = (target: ImpactTarget<unknown>, schema: ObjectNode): boolean =>\n !('schema' in target) || target.schema === schema;\n\nexport const same = (left: ImpactTarget<unknown>, right: ImpactTarget<unknown>): boolean => {\n if (left.kind !== right.kind) return false;\n if ('schema' in left && 'schema' in right && left.schema !== right.schema) return false;\n const leftAddress = address(left);\n const rightAddress = address(right);\n if (leftAddress.length !== rightAddress.length) return false;\n for (let index = 0; index < leftAddress.length; index += 1)\n if (leftAddress[index] !== rightAddress[index]) return false;\n return left.kind !== 'collection' || id(left) === id(right);\n};\n\nexport const indexedAddress = (target: ImpactTarget<unknown>): DocumentAddress => {\n const key = id(target);\n return key === undefined ? address(target) : [...address(target), key];\n};\n\nexport const affected = (\n target: ImpactTarget,\n values: AddressIndex<true>,\n orders: AddressIndex<true>\n): boolean => {\n const at = indexedAddress(target);\n return id(target) !== undefined\n ? values.hasAncestor(at)\n : values.overlaps(at) || orders.hasDescendant(at);\n};\n\n/** Targets are classified once; commit matching never builds a reverse impact index. */\nexport class SubscriptionIndex<T> {\n private readonly ordinary = new AddressIndex<T>();\n private readonly membership = new AddressIndex<T>();\n constructor(private readonly schema: ObjectNode) {}\n add(target: ImpactTarget, value: T): void {\n if (belongs(target, this.schema))\n (id(target) === undefined ? this.ordinary : this.membership).add(\n indexedAddress(target),\n value\n );\n }\n delete(target: ImpactTarget, value: T): void {\n if (belongs(target, this.schema))\n (id(target) === undefined ? this.ordinary : this.membership).delete(\n indexedAddress(target),\n value\n );\n }\n collect(changes: ChangeSet, visit: (value: T) => void): void {\n const values = this.ordinary.query(visit);\n const members = this.membership.query(visit, 'descendants');\n const orders = this.ordinary.query(visit, 'ancestors');\n for (const change of changes.changes) {\n if (change.kind === 'reset') {\n values([]);\n members([]);\n } else if (change.kind === 'members') {\n values(change.at, change.members);\n members(change.at, change.members);\n if (change.order) orders(change.at);\n } else {\n values(change.at);\n members(change.at);\n }\n }\n }\n clear(): void {\n this.ordinary.clear();\n this.membership.clear();\n }\n}\n","import type { DocumentAddress, ObjectNode, PathPick, Infer } from '../schema';\nimport type { AddressRef } from '../address';\nimport type { ChangeSet } from '../changes';\nimport type { DocumentImpact } from '../impact';\nimport type { Draft } from '../access/scope';\nimport type { MutationIssue } from '../mutation/issue';\nimport type { Readable } from '../projection/readable';\nexport type Unsubscribe = () => void;\nexport type Synchronous<T> = T extends PromiseLike<unknown> ? never : T;\nexport type CommitSource = 'local' | 'system' | 'history' | 'remote';\nexport class DocumentReentrancyError extends Error {\n constructor() {\n super('Document writes cannot be re-entered during an update or notification.');\n this.name = 'DocumentReentrancyError';\n }\n}\nexport class DocumentDisposedError extends Error {\n constructor() {\n super('Doxum runtime has been disposed.');\n this.name = 'DocumentDisposedError';\n }\n}\nexport type DiagnosticInput = {\n readonly code: string;\n readonly message: string;\n readonly address?: DocumentAddress;\n};\nexport type DocumentDiagnostic = DiagnosticInput & { readonly source: 'application' };\nexport type DocumentProblem = DocumentDiagnostic | MutationIssue;\nexport class TransactionRejected extends Error {\n readonly issues: readonly DocumentDiagnostic[];\n constructor(input: DiagnosticInput | readonly DiagnosticInput[]) {\n super('Document update rejected.');\n this.name = 'TransactionRejected';\n const issues: readonly DiagnosticInput[] = Array.isArray(input)\n ? input\n : [input as DiagnosticInput];\n this.issues = Object.freeze(\n issues.map(issue =>\n Object.freeze({\n code: issue.code,\n message: issue.message,\n source: 'application' as const,\n ...(issue.address === undefined ? {} : { address: Object.freeze([...issue.address]) }),\n })\n )\n );\n }\n}\nexport type DocumentCommit<S extends ObjectNode> = {\n readonly revision: number;\n readonly source: CommitSource;\n readonly changes: ChangeSet;\n readonly impact: DocumentImpact<S>;\n};\nexport type ObserverError = {\n readonly phase: 'processor' | 'flush' | 'listener';\n readonly error: unknown;\n};\nexport type TransactionResult<V, C> =\n | {\n readonly status: 'committed';\n readonly value: V;\n readonly commit: C;\n readonly observerErrors: readonly ObserverError[];\n }\n | { readonly status: 'unchanged'; readonly value: V; readonly revision: number }\n | {\n readonly status: 'rejected';\n readonly issues: readonly DocumentProblem[];\n readonly revision: number;\n };\nexport type OperationResult<C> =\n | {\n readonly status: 'committed';\n readonly commit: C;\n readonly observerErrors: readonly ObserverError[];\n }\n | { readonly status: 'unchanged'; readonly revision: number }\n | {\n readonly status: 'rejected';\n readonly issues: readonly MutationIssue[];\n readonly revision: number;\n };\nexport type HistoryState = { readonly undoDepth: number; readonly redoDepth: number };\nexport type LocalHistory<C> = Readable<HistoryState> & {\n undo(): OperationResult<C>;\n redo(): OperationResult<C>;\n clear(): void;\n group(): { end(): void; cancel(): OperationResult<C> };\n};\nexport type CommitListener<S extends ObjectNode> = (commit: DocumentCommit<S>) => void;\nexport type DocumentReadable<S extends ObjectNode> = {\n readonly address: {\n resolve(address: DocumentAddress): AddressRef | undefined;\n read(address: DocumentAddress): unknown;\n contains(parent: DocumentAddress, child: DocumentAddress): boolean;\n overlaps(left: DocumentAddress, right: DocumentAddress): boolean;\n debugKey(address: DocumentAddress): string;\n };\n revision(): number;\n subscribe(listener: CommitListener<S>): Unsubscribe;\n subscribe(\n pick: PathPick<S> | readonly [PathPick<S>, ...PathPick<S>[]],\n listener: CommitListener<S>\n ): Unsubscribe;\n};\nexport type DocumentRuntime<S extends ObjectNode> = DocumentReadable<S> & {\n readonly schema: S;\n update<V>(\n run: (draft: Draft<S>) => Synchronous<V>,\n options?: {\n readonly source?: Extract<CommitSource, 'local' | 'system'>;\n readonly history?: boolean;\n }\n ): TransactionResult<V, DocumentCommit<S>>;\n apply(\n changes: unknown,\n options: {\n readonly expectedRevision: number;\n readonly source?: Exclude<CommitSource, 'history'>;\n readonly history?: boolean;\n }\n ): OperationResult<DocumentCommit<S>>;\n replace(\n value: Infer<S>,\n options?: { readonly source?: Extract<CommitSource, 'system' | 'remote'> }\n ): OperationResult<DocumentCommit<S>>;\n snapshot(): Infer<S>;\n readonly history: LocalHistory<DocumentCommit<S>>;\n dispose(): void;\n};\n","import type { ObjectNode, Infer } from '../schema';\nimport { createAccess, type Read } from '../access/scope';\nimport type { DependencyTracker } from '../access/dependency';\nimport { DocumentDisposedError } from './contract';\nimport type { DocumentReadable } from './contract';\n\nexport type RuntimeAccessState<TSchema extends ObjectNode> = {\n readonly schema: TSchema;\n document: Infer<TSchema>;\n disposed: boolean;\n projectionLocks?: number;\n};\n\nconst states = new WeakMap<object, RuntimeAccessState<ObjectNode>>();\n\nexport const bindRuntimeAccess = <TSchema extends ObjectNode>(\n runtime: DocumentReadable<TSchema>,\n state: RuntimeAccessState<TSchema>\n): void => {\n states.set(runtime as object, state as RuntimeAccessState<ObjectNode>);\n};\n\nexport const accessOf = <TSchema extends ObjectNode>(\n runtime: DocumentReadable<TSchema>\n): RuntimeAccessState<TSchema> => {\n const state = states.get(runtime as object);\n if (!state) throw new Error('Unknown Doxum runtime.');\n return state as RuntimeAccessState<TSchema>;\n};\n\nexport const readWith = <TSchema extends ObjectNode, TResult>(\n runtime: DocumentReadable<TSchema>,\n run: (read: Read<TSchema>) => TResult,\n dependencies?: DependencyTracker\n): TResult => {\n const state = accessOf(runtime);\n if (state.disposed) throw new DocumentDisposedError();\n state.projectionLocks = (state.projectionLocks ?? 0) + 1;\n try {\n const reader = createAccess({\n state,\n dependencies,\n }) as Read<TSchema>;\n return run(reader);\n } finally {\n // readWith is an internal borrowed-reader boundary. Retaining its reader or\n // collection methods after this callback is undefined behavior.\n state.projectionLocks!--;\n }\n};\n","import type { ObjectNode, ImpactTarget } from '../schema';\nimport type {\n CommitListener,\n DocumentCommit,\n DocumentReadable,\n DocumentRuntime,\n Unsubscribe,\n ObserverError,\n} from './contract';\nimport * as target from '../impact-target';\n\nexport type ProjectionAttachment<TSchema extends ObjectNode> = {\n capture(commit: DocumentCommit<TSchema>): void;\n settle(): void;\n flush(): readonly ObserverError[];\n dispose(): void;\n};\ntype ProcessorEntry<TSchema extends ObjectNode> = {\n readonly processor: ProjectionAttachment<TSchema>;\n active: boolean;\n};\ntype RootEntry<TSchema extends ObjectNode> = {\n readonly listener: CommitListener<TSchema>;\n active: boolean;\n};\ntype FilteredEntry<TSchema extends ObjectNode> = {\n readonly targets: readonly ImpactTarget<unknown>[];\n readonly listener: CommitListener<TSchema>;\n active: boolean;\n};\nexport type RuntimeNotification<TSchema extends ObjectNode> = {\n readonly root: Set<RootEntry<TSchema>>;\n readonly filtered: Set<FilteredEntry<TSchema>>;\n readonly index: target.SubscriptionIndex<FilteredEntry<TSchema>>;\n readonly cleanups: Set<() => void>;\n readonly processors: ProcessorEntry<TSchema>[];\n readonly candidates: Set<FilteredEntry<TSchema>>;\n readonly rootSnapshot: RootEntry<TSchema>[];\n notifying: boolean;\n};\n\nconst notifications = new WeakMap<object, RuntimeNotification<ObjectNode>>();\nconst readableOwners = new WeakMap<object, DocumentReadable<ObjectNode>>();\n\nexport const bindDocumentReadable = (\n readable: object,\n runtime: DocumentReadable<ObjectNode>\n): void => {\n readableOwners.set(readable, runtime);\n};\nexport const documentReadableOwner = (readable: object): DocumentReadable<ObjectNode> | undefined =>\n readableOwners.get(readable);\n\nexport const createNotification = <TSchema extends ObjectNode>(\n runtime: DocumentRuntime<TSchema>\n): RuntimeNotification<TSchema> => {\n const notification: RuntimeNotification<TSchema> = {\n root: new Set(),\n filtered: new Set(),\n index: new target.SubscriptionIndex(runtime.schema),\n cleanups: new Set(),\n processors: [],\n candidates: new Set(),\n rootSnapshot: [],\n notifying: false,\n };\n notifications.set(runtime as object, notification as RuntimeNotification<ObjectNode>);\n return notification;\n};\n\nconst notificationOf = <TSchema extends ObjectNode>(\n runtime: DocumentReadable<TSchema>\n): RuntimeNotification<TSchema> => {\n const value = notifications.get(runtime as object);\n if (!value) throw new Error('Unknown Doxum runtime.');\n return value as RuntimeNotification<TSchema>;\n};\n\nexport const shareNotification = <TSchema extends ObjectNode>(\n source: DocumentRuntime<TSchema>,\n target: DocumentReadable<TSchema>\n): void => {\n notifications.set(target as object, notificationOf(source) as RuntimeNotification<ObjectNode>);\n};\n\nexport const attachProjection = <TSchema extends ObjectNode>(\n runtime: DocumentReadable<TSchema>,\n processor: ProjectionAttachment<TSchema>\n): Unsubscribe => {\n const notification = notificationOf(runtime);\n const entry: ProcessorEntry<TSchema> = { processor, active: true };\n notification.processors.push(entry);\n return () => {\n if (!entry.active) return;\n entry.active = false;\n if (!notification.notifying) {\n const index = notification.processors.indexOf(entry);\n if (index >= 0) notification.processors.splice(index, 1);\n }\n };\n};\n\nexport const subscribeRoot = <TSchema extends ObjectNode>(\n notification: RuntimeNotification<TSchema>,\n listener: CommitListener<TSchema>\n): Unsubscribe => {\n const entry: RootEntry<TSchema> = { listener, active: true };\n notification.root.add(entry);\n return () => {\n entry.active = false;\n if (!notification.notifying) notification.root.delete(entry);\n else\n notification.cleanups.add(() => {\n notification.root.delete(entry);\n });\n };\n};\n\nexport const subscribeTargets = <TSchema extends ObjectNode>(\n notification: RuntimeNotification<TSchema>,\n targets: readonly ImpactTarget<unknown>[],\n listener: CommitListener<TSchema>\n): Unsubscribe => {\n const entry: FilteredEntry<TSchema> = {\n targets: Object.freeze(targets.slice()),\n listener,\n active: true,\n };\n notification.filtered.add(entry);\n entry.targets.forEach(value => notification.index.add(value, entry));\n const remove = () => {\n notification.filtered.delete(entry);\n entry.targets.forEach(value => notification.index.delete(value, entry));\n };\n return () => {\n if (!entry.active) return;\n entry.active = false;\n if (notification.notifying) notification.cleanups.add(remove);\n else remove();\n };\n};\n\nexport const notify = <TSchema extends ObjectNode>(\n notification: RuntimeNotification<TSchema>,\n commit: DocumentCommit<TSchema>,\n afterSettle?: () => readonly ObserverError[]\n): readonly ObserverError[] => {\n notification.notifying = true;\n const errors: ObserverError[] = [];\n const call = (listener: CommitListener<TSchema>): void => {\n try {\n listener(commit);\n } catch (error) {\n errors.push(Object.freeze({ phase: 'listener', error }));\n }\n };\n try {\n const processorCount = notification.processors.length;\n for (let index = 0; index < processorCount; index += 1) {\n const entry = notification.processors[index];\n if (!entry?.active) continue;\n try {\n entry.processor.capture(commit);\n } catch (error) {\n errors.push(Object.freeze({ phase: 'processor', error }));\n }\n }\n for (let index = 0; index < processorCount; index += 1) {\n const entry = notification.processors[index];\n if (!entry?.active) continue;\n try {\n entry.processor.settle();\n } catch (error) {\n errors.push(Object.freeze({ phase: 'processor', error }));\n }\n }\n for (let index = 0; index < processorCount; index += 1) {\n const entry = notification.processors[index];\n if (!entry?.active) continue;\n try {\n errors.push(...entry.processor.flush());\n } catch (error) {\n errors.push(Object.freeze({ phase: 'flush', error }));\n }\n }\n\n if (afterSettle) errors.push(...afterSettle());\n const candidates = notification.candidates;\n candidates.clear();\n if (notification.filtered.size)\n notification.index.collect(commit.changes, entry => candidates.add(entry));\n candidates.forEach(entry => {\n if (entry.active) call(entry.listener);\n });\n const rootSnapshot = notification.rootSnapshot;\n rootSnapshot.length = 0;\n notification.root.forEach(entry => rootSnapshot.push(entry));\n for (const entry of rootSnapshot) if (entry.active) call(entry.listener);\n } finally {\n notification.notifying = false;\n let writeIndex = 0;\n for (const entry of notification.processors)\n if (entry.active) notification.processors[writeIndex++] = entry;\n notification.processors.length = writeIndex;\n notification.cleanups.forEach(cleanup => cleanup());\n notification.cleanups.clear();\n }\n return Object.freeze(errors);\n};\n\nexport const subscribeDependencies = <S extends ObjectNode>(\n runtime: DocumentReadable<S>,\n targets: readonly ImpactTarget[],\n listener: CommitListener<S>\n): Unsubscribe => subscribeTargets(notificationOf(runtime), targets, listener);\n\nexport const disposeNotification = <TSchema extends ObjectNode>(\n notification: RuntimeNotification<TSchema>\n): void => {\n const attachments = notification.processors.slice();\n notification.root.clear();\n notification.filtered.clear();\n notification.index.clear();\n notification.cleanups.clear();\n notification.processors.length = 0;\n notification.candidates.clear();\n notification.rootSnapshot.length = 0;\n const errors: unknown[] = [];\n attachments.forEach(entry => {\n if (!entry.active) return;\n try {\n entry.processor.dispose();\n } catch (error) {\n errors.push(error);\n }\n });\n if (errors.length) throw new AggregateError(errors, 'Projection disposal notification failed.');\n};\n"],"mappings":"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"}
|