doxum 0.1.41 → 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 +137 -64
- package/dist/index.d.cts +4 -2
- package/dist/index.d.ts +4 -2
- package/dist/index.js +137 -64
- 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-D6njdP3k.cjs → transform-BPh55GWO.cjs} +80 -48
- package/dist/{transform-CKJ1ivhz.js → transform-BvDYPUMm.js} +80 -48
- package/package.json +1 -1
- package/skills/doxum-runtime/references/integrations.md +38 -7
- package/skills/doxum-runtime/references/invariants.md +13 -0
- package/skills/doxum-runtime/references/projections.md +22 -0
- package/skills/doxum-runtime/references/public-api.md +27 -8
package/README.md
CHANGED
|
@@ -276,8 +276,8 @@ runtime.dispose();
|
|
|
276
276
|
|
|
277
277
|
The stable vocabulary is `read` for a synchronous current value, `select` for a
|
|
278
278
|
`Readable`, and `observe` for declaring a lazy source boundary. `ProjectionRuntime`
|
|
279
|
-
exposes `read`, `select`, `items`, `update`, `batch`, `scope` and `dispose`.
|
|
280
|
-
`ProjectionScope` mirrors `read`, `select`, `items`, `update`, `batch` and `dispose`, plus
|
|
279
|
+
exposes `read`, `select`, `items`, `update`, `batch`, `scope`, `onDispose` and `dispose`.
|
|
280
|
+
`ProjectionScope` mirrors `read`, `select`, `items`, `update`, `batch`, `onDispose` and `dispose`, plus
|
|
281
281
|
`own(definitionOrTree)` for lifecycle ownership of lazy projection definitions.
|
|
282
282
|
|
|
283
283
|
### Commands inside a batch
|
|
@@ -638,8 +638,40 @@ values. Ordinary source resets preserve retained state when one exists. If a pro
|
|
|
638
638
|
faults, the Runtime owns recovery, recreates declared state, and performs a reset
|
|
639
639
|
evaluation. Stateless processors use the same recovery path without a state object.
|
|
640
640
|
|
|
641
|
+
### Projection disposal
|
|
642
|
+
|
|
643
|
+
`runtime.dispose()`, `scope.dispose()` and Doxum unsubscribe functions are idempotent.
|
|
644
|
+
A parent Runtime ends its scopes, so later component cleanup can safely dispose them
|
|
645
|
+
again. Every subscription registration is independent, including registrations with
|
|
646
|
+
the same callback; an old unsubscribe cannot cancel a later subscription.
|
|
647
|
+
|
|
648
|
+
`runtime.onDispose(cleanup)` / `scope.onDispose(cleanup)` register synchronous,
|
|
649
|
+
cancellable callbacks. The returned function unregisters that callback without
|
|
650
|
+
executing it. Owner callbacks run in LIFO order; Runtime shutdown runs child scope
|
|
651
|
+
callbacks before its own while all projections remain readable. Cleanup may read
|
|
652
|
+
current values and unsubscribe, but cannot update, batch, subscribe or register new
|
|
653
|
+
resources. Perform domain writes before disposal. After callbacks, consumers and
|
|
654
|
+
producers are released, then source connections; failures do not prevent remaining
|
|
655
|
+
cleanup, and are thrown after disposal completes. Repeated disposal does not retry
|
|
656
|
+
failed callbacks. Reads, commands and new subscriptions still throw after disposal.
|
|
657
|
+
|
|
641
658
|
### React
|
|
642
659
|
|
|
660
|
+
```tsx
|
|
661
|
+
// runtime is owned by the application/service; this Provider owns only its scope.
|
|
662
|
+
<ProjectionProvider runtime={runtime} fallback={<span>Loading…</span>}>
|
|
663
|
+
<TaskList />
|
|
664
|
+
</ProjectionProvider>
|
|
665
|
+
```
|
|
666
|
+
|
|
667
|
+
Managed Providers acquire a scope after commit and release it on cleanup. StrictMode
|
|
668
|
+
setup replay creates a fresh scope; runtime replacement also remounts the scoped subtree.
|
|
669
|
+
`useProjectionScope()` returns that scope for `scope.own(...)` and `scope.onDispose(...)`.
|
|
670
|
+
The initial render and SSR render `fallback` (default `null`). For synchronous SSR or
|
|
671
|
+
an externally managed lifetime, use `<ProjectionProvider value={runtimeOrScope}>`;
|
|
672
|
+
this mode only injects the owner and never disposes it. The two modes are mutually
|
|
673
|
+
exclusive. Do not create disposable scopes in `useMemo` or revive a disposed scope.
|
|
674
|
+
|
|
643
675
|
```ts
|
|
644
676
|
const task = useProjection(tasks, tasks => tasks.get(taskId), equality);
|
|
645
677
|
const [mode, setMode] = useInput(filter);
|
|
@@ -648,8 +680,8 @@ const [selectedRows, updateSelectedRows] = useInput(selection);
|
|
|
648
680
|
|
|
649
681
|
`useProjection(projection, selector, equality?)` uses the same keyed selector semantics
|
|
650
682
|
as Core. `useInput` handles both scalar `Input<T>` and `CollectionInput<K,V>`; collection
|
|
651
|
-
updates receive a keyed draft callback.
|
|
652
|
-
`
|
|
683
|
+
updates receive a keyed draft callback. Reading a root projection through a managed
|
|
684
|
+
scope does not transfer its ownership; use `scope.own(...)` for local definitions.
|
|
653
685
|
|
|
654
686
|
See [projection contracts](docs/projections.md).
|
|
655
687
|
|
package/dist/advanced.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
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
4
|
//#region core/src/projection/advanced.ts
|
|
5
5
|
const resetCollectionChange = Object.freeze({ kind: "reset" });
|
package/dist/advanced.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as ProjectionChange, d as CollectionRead, l as CollectionChange, n as KeyedDependencyValues, o as KeyedProjection, s as Projection, t as KeyedDependencies, u as CollectionDraft } from "./dependency-
|
|
1
|
+
import { c as ProjectionChange, d as CollectionRead, l as CollectionChange, n as KeyedDependencyValues, o as KeyedProjection, s as Projection, t as KeyedDependencies, u as CollectionDraft } from "./dependency-D0bo_xe_.cjs";
|
|
2
2
|
|
|
3
3
|
//#region core/src/projection/collection/change.d.ts
|
|
4
4
|
declare const collectionChange: {
|
package/dist/advanced.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as ProjectionChange, d as CollectionRead, l as CollectionChange, n as KeyedDependencyValues, o as KeyedProjection, s as Projection, t as KeyedDependencies, u as CollectionDraft } from "./dependency-
|
|
1
|
+
import { c as ProjectionChange, d as CollectionRead, l as CollectionChange, n as KeyedDependencyValues, o as KeyedProjection, s as Projection, t as KeyedDependencies, u as CollectionDraft } from "./dependency-BYiwTiBj.js";
|
|
2
2
|
|
|
3
3
|
//#region core/src/projection/collection/change.d.ts
|
|
4
4
|
declare const collectionChange: {
|
package/dist/advanced.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { D as defineProcessor, S as compileProjectionDependencies, _ as assertSynchronous, r as collectionChange, t as createKeyedTransform, w as collectionView } from "./transform-
|
|
1
|
+
import { D as defineProcessor, S as compileProjectionDependencies, _ as assertSynchronous, r as collectionChange, t as createKeyedTransform, w as collectionView } from "./transform-BvDYPUMm.js";
|
|
2
2
|
import { n as isPlainObject } from "./record-B2yRhYsc.js";
|
|
3
3
|
//#region core/src/projection/advanced.ts
|
|
4
4
|
const resetCollectionChange = Object.freeze({ kind: "reset" });
|
|
@@ -509,10 +509,11 @@ type MutationIssue = {
|
|
|
509
509
|
};
|
|
510
510
|
//#endregion
|
|
511
511
|
//#region core/src/readable.d.ts
|
|
512
|
+
/** Ends one registration at most once; safe after owner disposal. */
|
|
512
513
|
type Unsubscribe = () => void;
|
|
513
514
|
type Readable<TValue> = {
|
|
514
515
|
current(): TValue;
|
|
515
|
-
revision(): number;
|
|
516
|
+
revision(): number; /** Each call registers independently, even when the listener function is reused. */
|
|
516
517
|
subscribe(listener: () => void): Unsubscribe;
|
|
517
518
|
};
|
|
518
519
|
//#endregion
|
|
@@ -509,10 +509,11 @@ type MutationIssue = {
|
|
|
509
509
|
};
|
|
510
510
|
//#endregion
|
|
511
511
|
//#region core/src/readable.d.ts
|
|
512
|
+
/** Ends one registration at most once; safe after owner disposal. */
|
|
512
513
|
type Unsubscribe = () => void;
|
|
513
514
|
type Readable<TValue> = {
|
|
514
515
|
current(): TValue;
|
|
515
|
-
revision(): number;
|
|
516
|
+
revision(): number; /** Each call registers independently, even when the listener function is reused. */
|
|
516
517
|
subscribe(listener: () => void): Unsubscribe;
|
|
517
518
|
};
|
|
518
519
|
//#endregion
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { _ as Unsubscribe, b as CollectionImpact, p as Synchronous } from "./contract-
|
|
1
|
+
import { _ as Unsubscribe, b as CollectionImpact, p as Synchronous } from "./contract-PqdXNaP8.js";
|
|
2
2
|
|
|
3
3
|
//#region core/src/projection/contract.d.ts
|
|
4
4
|
/** The one processor-facing collection transition protocol. */
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { _ as Unsubscribe, b as CollectionImpact, p as Synchronous } from "./contract-
|
|
1
|
+
import { _ as Unsubscribe, b as CollectionImpact, p as Synchronous } from "./contract-DovG1Yp-.cjs";
|
|
2
2
|
|
|
3
3
|
//#region core/src/projection/contract.d.ts
|
|
4
4
|
/** The one processor-facing collection transition protocol. */
|
|
@@ -208,6 +208,20 @@ var AddressIndex = class {
|
|
|
208
208
|
}
|
|
209
209
|
};
|
|
210
210
|
//#endregion
|
|
211
|
+
//#region core/src/subscription.ts
|
|
212
|
+
/** Each registration owns its identity, independently of callback reuse. */
|
|
213
|
+
const addListener = (listeners, listener, removed) => {
|
|
214
|
+
const entry = (...args) => listener(...args);
|
|
215
|
+
listeners.add(entry);
|
|
216
|
+
let active = true;
|
|
217
|
+
return () => {
|
|
218
|
+
if (!active) return;
|
|
219
|
+
active = false;
|
|
220
|
+
listeners.delete(entry);
|
|
221
|
+
removed?.();
|
|
222
|
+
};
|
|
223
|
+
};
|
|
224
|
+
//#endregion
|
|
211
225
|
//#region core/src/mutation/changes.ts
|
|
212
226
|
const validated = /* @__PURE__ */ new WeakSet();
|
|
213
227
|
const compareChanges = (a, b) => {
|
|
@@ -399,4 +413,4 @@ const installRuntimeWriteDriver = (runtime, driver) => {
|
|
|
399
413
|
});
|
|
400
414
|
};
|
|
401
415
|
//#endregion
|
|
402
|
-
export { changeCount as a,
|
|
416
|
+
export { validate as _, changeCount as a, addListener as c, fail as d, invalidValue as f, parent as g, is as h, contextOf as i, AddressIndex as l, contains as m, installRuntimeWriteDriver as n, decodeChanges as o, children as p, bindContext as r, sealChanges as s, assertRuntimeWritable as t, MutationRejected as u };
|
|
@@ -208,6 +208,20 @@ var AddressIndex = class {
|
|
|
208
208
|
}
|
|
209
209
|
};
|
|
210
210
|
//#endregion
|
|
211
|
+
//#region core/src/subscription.ts
|
|
212
|
+
/** Each registration owns its identity, independently of callback reuse. */
|
|
213
|
+
const addListener = (listeners, listener, removed) => {
|
|
214
|
+
const entry = (...args) => listener(...args);
|
|
215
|
+
listeners.add(entry);
|
|
216
|
+
let active = true;
|
|
217
|
+
return () => {
|
|
218
|
+
if (!active) return;
|
|
219
|
+
active = false;
|
|
220
|
+
listeners.delete(entry);
|
|
221
|
+
removed?.();
|
|
222
|
+
};
|
|
223
|
+
};
|
|
224
|
+
//#endregion
|
|
211
225
|
//#region core/src/mutation/changes.ts
|
|
212
226
|
const validated = /* @__PURE__ */ new WeakSet();
|
|
213
227
|
const compareChanges = (a, b) => {
|
|
@@ -411,6 +425,12 @@ Object.defineProperty(exports, "MutationRejected", {
|
|
|
411
425
|
return MutationRejected;
|
|
412
426
|
}
|
|
413
427
|
});
|
|
428
|
+
Object.defineProperty(exports, "addListener", {
|
|
429
|
+
enumerable: true,
|
|
430
|
+
get: function() {
|
|
431
|
+
return addListener;
|
|
432
|
+
}
|
|
433
|
+
});
|
|
414
434
|
Object.defineProperty(exports, "assertRuntimeWritable", {
|
|
415
435
|
enumerable: true,
|
|
416
436
|
get: function() {
|
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;
|
|
@@ -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 = () => {
|
|
@@ -4209,8 +4243,7 @@ const createCollectionOutput = (binding) => {
|
|
|
4209
4243
|
},
|
|
4210
4244
|
observe: (listener) => {
|
|
4211
4245
|
binding.check();
|
|
4212
|
-
|
|
4213
|
-
return () => observers.delete(listener);
|
|
4246
|
+
return require_driver.addListener(observers, listener);
|
|
4214
4247
|
},
|
|
4215
4248
|
hasConsumers: () => consumers.size > 0,
|
|
4216
4249
|
forEachConsumer: (run) => consumers.forEach((_pending, consumer) => run(consumer)),
|
|
@@ -4242,8 +4275,7 @@ const createCollectionOutput = (binding) => {
|
|
|
4242
4275
|
},
|
|
4243
4276
|
subscribe: (listener) => {
|
|
4244
4277
|
binding.check();
|
|
4245
|
-
|
|
4246
|
-
return () => listeners.delete(listener);
|
|
4278
|
+
return require_driver.addListener(listeners, listener);
|
|
4247
4279
|
}
|
|
4248
4280
|
};
|
|
4249
4281
|
};
|
|
@@ -4358,8 +4390,7 @@ const createValueOutput = (binding) => {
|
|
|
4358
4390
|
},
|
|
4359
4391
|
observe: (listener) => {
|
|
4360
4392
|
binding.check();
|
|
4361
|
-
|
|
4362
|
-
return () => observers.delete(listener);
|
|
4393
|
+
return require_driver.addListener(observers, listener);
|
|
4363
4394
|
},
|
|
4364
4395
|
hasConsumers: () => consumers.size > 0,
|
|
4365
4396
|
forEachConsumer: (run) => consumers.forEach((_revision, consumer) => run(consumer)),
|
|
@@ -4388,8 +4419,7 @@ const createValueOutput = (binding) => {
|
|
|
4388
4419
|
},
|
|
4389
4420
|
subscribe: (listener) => {
|
|
4390
4421
|
binding.check();
|
|
4391
|
-
|
|
4392
|
-
return () => listeners.delete(listener);
|
|
4422
|
+
return require_driver.addListener(listeners, listener);
|
|
4393
4423
|
}
|
|
4394
4424
|
};
|
|
4395
4425
|
};
|
|
@@ -4593,7 +4623,7 @@ const selectionAffects = (selection, change) => {
|
|
|
4593
4623
|
const createDirectReadable = (source) => Object.freeze({
|
|
4594
4624
|
current: source.current,
|
|
4595
4625
|
revision: source.revision,
|
|
4596
|
-
subscribe:
|
|
4626
|
+
subscribe: source.subscribe
|
|
4597
4627
|
});
|
|
4598
4628
|
/** Consumer-side selector tracking; it never mutates processor dependencies. */
|
|
4599
4629
|
const createSelectorReadable = (source, selector, equality = Object.is) => {
|
|
@@ -4697,15 +4727,22 @@ const createSelectorReadable = (source, selector, equality = Object.is) => {
|
|
|
4697
4727
|
},
|
|
4698
4728
|
subscribe: (listener) => {
|
|
4699
4729
|
ensureCurrent();
|
|
4700
|
-
|
|
4701
|
-
|
|
4702
|
-
|
|
4703
|
-
listeners.delete(listener);
|
|
4704
|
-
if (!listeners.size && unsubscribeSource) {
|
|
4705
|
-
unsubscribeSource();
|
|
4730
|
+
const unsubscribe = require_driver.addListener(listeners, listener, () => {
|
|
4731
|
+
if (!listeners.size) {
|
|
4732
|
+
const stop = unsubscribeSource;
|
|
4706
4733
|
unsubscribeSource = void 0;
|
|
4734
|
+
stop?.();
|
|
4707
4735
|
}
|
|
4708
|
-
};
|
|
4736
|
+
});
|
|
4737
|
+
try {
|
|
4738
|
+
installSource();
|
|
4739
|
+
} catch (error) {
|
|
4740
|
+
try {
|
|
4741
|
+
unsubscribe();
|
|
4742
|
+
} catch {}
|
|
4743
|
+
throw error;
|
|
4744
|
+
}
|
|
4745
|
+
return unsubscribe;
|
|
4709
4746
|
}
|
|
4710
4747
|
});
|
|
4711
4748
|
};
|
|
@@ -6003,7 +6040,7 @@ const createSourceRegistry = (scheduler) => {
|
|
|
6003
6040
|
//#endregion
|
|
6004
6041
|
//#region core/src/projection/readable/keyed.ts
|
|
6005
6042
|
/** Runtime-owned keyed consumer family over one materialized collection output. */
|
|
6006
|
-
const createProjectionItems = (source, checkOwner) => {
|
|
6043
|
+
const createProjectionItems = (source, checkOwner, checkSubscription) => {
|
|
6007
6044
|
if (source.kind !== "collection") throw new TypeError("Projection items require a keyed collection projection.");
|
|
6008
6045
|
let disposed = false;
|
|
6009
6046
|
const active = /* @__PURE__ */ new Map();
|
|
@@ -6132,12 +6169,12 @@ const createProjectionItems = (source, checkOwner) => {
|
|
|
6132
6169
|
subscribe: (listener) => {
|
|
6133
6170
|
check();
|
|
6134
6171
|
ensureObserved();
|
|
6135
|
-
|
|
6136
|
-
|
|
6137
|
-
return () => {
|
|
6138
|
-
state.listeners.delete(listener);
|
|
6172
|
+
checkSubscription();
|
|
6173
|
+
const unsubscribe = require_driver.addListener(state.listeners, listener, () => {
|
|
6139
6174
|
if (!state.listeners.size && !state.tracked) unregisterWaiting(state);
|
|
6140
|
-
};
|
|
6175
|
+
});
|
|
6176
|
+
if (!state.tracked && !state.ended) registerWaiting(state);
|
|
6177
|
+
return unsubscribe;
|
|
6141
6178
|
}
|
|
6142
6179
|
});
|
|
6143
6180
|
return state;
|
|
@@ -6194,8 +6231,8 @@ const createProjectionItems = (source, checkOwner) => {
|
|
|
6194
6231
|
},
|
|
6195
6232
|
subscribe: (listener) => {
|
|
6196
6233
|
check();
|
|
6197
|
-
|
|
6198
|
-
return (
|
|
6234
|
+
checkSubscription();
|
|
6235
|
+
return require_driver.addListener(keyListeners, listener);
|
|
6199
6236
|
}
|
|
6200
6237
|
});
|
|
6201
6238
|
return {
|
|
@@ -6203,6 +6240,7 @@ const createProjectionItems = (source, checkOwner) => {
|
|
|
6203
6240
|
keys,
|
|
6204
6241
|
get: (key) => {
|
|
6205
6242
|
check();
|
|
6243
|
+
checkSubscription();
|
|
6206
6244
|
const current = source.current();
|
|
6207
6245
|
if (source.revision() !== settledRevision) pendingKeys.add(key);
|
|
6208
6246
|
const canonical = active.get(key);
|
|
@@ -6247,6 +6285,7 @@ const createProjectionRuntime = (options) => {
|
|
|
6247
6285
|
const materialized = /* @__PURE__ */ new WeakMap();
|
|
6248
6286
|
const publicViews = /* @__PURE__ */ new WeakMap();
|
|
6249
6287
|
const scopes = /* @__PURE__ */ new Set();
|
|
6288
|
+
const cleanups = createCleanupStack();
|
|
6250
6289
|
const rootItems = /* @__PURE__ */ new Map();
|
|
6251
6290
|
const disposeItemControllers = (registry, failures) => {
|
|
6252
6291
|
const controllers = [...registry.values()];
|
|
@@ -6276,7 +6315,7 @@ const createProjectionRuntime = (options) => {
|
|
|
6276
6315
|
const owner = definition.owner;
|
|
6277
6316
|
if (owner === void 0) return;
|
|
6278
6317
|
if (owner !== requester) throw new TypeError("Projection belongs to another scope.");
|
|
6279
|
-
if (
|
|
6318
|
+
if (requester?.status === "disposed") throw new require_transform.ProjectionDisposedError();
|
|
6280
6319
|
};
|
|
6281
6320
|
const rememberScoped = (definition, requester) => {
|
|
6282
6321
|
if (requester && definition.owner === requester) requester.materialized.push(definition);
|
|
@@ -6356,25 +6395,33 @@ const createProjectionRuntime = (options) => {
|
|
|
6356
6395
|
assertOutput(output);
|
|
6357
6396
|
return output.revision();
|
|
6358
6397
|
},
|
|
6359
|
-
subscribe:
|
|
6360
|
-
|
|
6398
|
+
subscribe: (listener) => {
|
|
6399
|
+
scheduler.assertCommand();
|
|
6400
|
+
return output.subscribe(listener);
|
|
6401
|
+
},
|
|
6402
|
+
observe: (listener) => {
|
|
6403
|
+
scheduler.assertCommand();
|
|
6404
|
+
return output.observe(listener);
|
|
6405
|
+
}
|
|
6361
6406
|
});
|
|
6362
6407
|
};
|
|
6363
6408
|
const projectionItems = (projection, requester) => {
|
|
6409
|
+
scheduler.assertCommand();
|
|
6364
6410
|
const output = resolveOutput(projection, requester);
|
|
6365
6411
|
if (output.kind !== "collection") throw new TypeError("Projection items require a keyed collection projection.");
|
|
6366
6412
|
const registry = requester?.items ?? rootItems;
|
|
6367
6413
|
const existing = registry.get(output);
|
|
6368
6414
|
if (existing) return existing.items;
|
|
6369
6415
|
const controller = createProjectionItems(readableSource(projection, requester), () => {
|
|
6370
|
-
if (requester
|
|
6416
|
+
if (requester?.status === "disposed") throw new require_transform.ProjectionDisposedError();
|
|
6371
6417
|
scheduler.ensureCurrent(output);
|
|
6372
6418
|
assertOutput(output);
|
|
6373
|
-
});
|
|
6419
|
+
}, scheduler.assertCommand);
|
|
6374
6420
|
registry.set(output, controller);
|
|
6375
6421
|
return controller.items;
|
|
6376
6422
|
};
|
|
6377
6423
|
const makeReadable = (projection, selector, equality, requester) => {
|
|
6424
|
+
scheduler.assertCommand();
|
|
6378
6425
|
const source = readableSource(projection, requester);
|
|
6379
6426
|
return selector ? createSelectorReadable(source, selector, equality) : createDirectReadable(source);
|
|
6380
6427
|
};
|
|
@@ -6382,8 +6429,8 @@ const createProjectionRuntime = (options) => {
|
|
|
6382
6429
|
return makeReadable(projection, selector, equality);
|
|
6383
6430
|
}
|
|
6384
6431
|
const inputAccess = (target, requester) => {
|
|
6385
|
-
scheduler.
|
|
6386
|
-
if (requester
|
|
6432
|
+
scheduler.assertCommand();
|
|
6433
|
+
if (requester?.status === "disposed") throw new require_transform.ProjectionDisposedError();
|
|
6387
6434
|
const ref = require_transform.projectionRef(target);
|
|
6388
6435
|
if (ref.output !== 0 || ref.producer.kind !== "source") throw new TypeError("Projection is not an input.");
|
|
6389
6436
|
if (ref.producer.source.kind !== "value-input" && ref.producer.source.kind !== "collection-input") throw new TypeError("Projection is not an input.");
|
|
@@ -6404,11 +6451,9 @@ const createProjectionRuntime = (options) => {
|
|
|
6404
6451
|
updateInput(target, valueOrRun);
|
|
6405
6452
|
}
|
|
6406
6453
|
const batch = (run, options) => scheduler.batch(run, options);
|
|
6407
|
-
const
|
|
6408
|
-
|
|
6409
|
-
|
|
6410
|
-
state.active = false;
|
|
6411
|
-
const failures = [];
|
|
6454
|
+
const releaseScope = (state, failures) => {
|
|
6455
|
+
state.status = "disposed";
|
|
6456
|
+
scopes.delete(state);
|
|
6412
6457
|
disposeScopeConsumers(state, failures);
|
|
6413
6458
|
for (let index = state.materialized.length - 1; index >= 0; index--) {
|
|
6414
6459
|
const definition = state.materialized[index];
|
|
@@ -6423,24 +6468,38 @@ const createProjectionRuntime = (options) => {
|
|
|
6423
6468
|
}
|
|
6424
6469
|
}
|
|
6425
6470
|
state.materialized.length = 0;
|
|
6426
|
-
|
|
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
|
+
}
|
|
6427
6484
|
throwCleanupFailures(failures, "Projection scope cleanup failed.");
|
|
6428
6485
|
};
|
|
6429
6486
|
const createScope = () => {
|
|
6430
|
-
scheduler.
|
|
6487
|
+
scheduler.assertCommand();
|
|
6431
6488
|
const state = {
|
|
6432
|
-
|
|
6489
|
+
status: "active",
|
|
6490
|
+
cleanups: createCleanupStack(),
|
|
6433
6491
|
materialized: [],
|
|
6434
6492
|
subscriptions: /* @__PURE__ */ new Set(),
|
|
6435
6493
|
items: /* @__PURE__ */ new Map()
|
|
6436
6494
|
};
|
|
6437
6495
|
scopes.add(state);
|
|
6438
6496
|
const assertActive = () => {
|
|
6439
|
-
if (
|
|
6497
|
+
if (state.status === "disposed") throw new require_transform.ProjectionDisposedError();
|
|
6440
6498
|
scheduler.assertActive();
|
|
6441
6499
|
};
|
|
6442
6500
|
function own(target) {
|
|
6443
6501
|
assertActive();
|
|
6502
|
+
scheduler.assertCommand();
|
|
6444
6503
|
const projections = [];
|
|
6445
6504
|
const collect = (value) => {
|
|
6446
6505
|
if (require_transform.isProjection(value)) {
|
|
@@ -6510,6 +6569,11 @@ const createProjectionRuntime = (options) => {
|
|
|
6510
6569
|
},
|
|
6511
6570
|
update: scopeUpdate,
|
|
6512
6571
|
batch: scopeBatch,
|
|
6572
|
+
onDispose: (callback) => {
|
|
6573
|
+
assertActive();
|
|
6574
|
+
scheduler.assertCommand();
|
|
6575
|
+
return state.cleanups.add(callback);
|
|
6576
|
+
},
|
|
6513
6577
|
dispose: () => disposeScope(state)
|
|
6514
6578
|
});
|
|
6515
6579
|
};
|
|
@@ -6520,24 +6584,33 @@ const createProjectionRuntime = (options) => {
|
|
|
6520
6584
|
update,
|
|
6521
6585
|
batch,
|
|
6522
6586
|
scope: createScope,
|
|
6587
|
+
onDispose: (callback) => {
|
|
6588
|
+
scheduler.assertCommand();
|
|
6589
|
+
return cleanups.add(callback);
|
|
6590
|
+
},
|
|
6523
6591
|
dispose: () => {
|
|
6524
|
-
if (!scheduler.
|
|
6525
|
-
scheduler.assertIdle();
|
|
6592
|
+
if (!scheduler.beginClose()) return;
|
|
6526
6593
|
const failures = [];
|
|
6527
|
-
|
|
6528
|
-
|
|
6529
|
-
disposeScopeConsumers(scope, failures);
|
|
6530
|
-
scope.materialized.length = 0;
|
|
6531
|
-
}
|
|
6532
|
-
scopes.clear();
|
|
6533
|
-
disposeItemControllers(rootItems, failures);
|
|
6594
|
+
const owned = [...scopes].reverse();
|
|
6595
|
+
for (const scope of owned) scope.status = "closing";
|
|
6534
6596
|
try {
|
|
6535
|
-
|
|
6597
|
+
scheduler.cleanup(() => {
|
|
6598
|
+
for (const scope of owned) scope.cleanups.drain(failures);
|
|
6599
|
+
cleanups.drain(failures);
|
|
6600
|
+
});
|
|
6536
6601
|
} catch (error) {
|
|
6537
6602
|
failures.push(error);
|
|
6538
6603
|
}
|
|
6539
6604
|
try {
|
|
6540
|
-
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);
|
|
6541
6614
|
} catch (error) {
|
|
6542
6615
|
failures.push(error);
|
|
6543
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?: {
|
package/dist/index.d.ts
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-PqdXNaP8.js";
|
|
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-BYiwTiBj.js";
|
|
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?: {
|