@rotorsoft/act 1.25.2 → 1.26.0
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/dist/.tsbuildinfo +1 -1
- package/dist/@types/act.d.ts.map +1 -1
- package/dist/@types/adapters/in-memory-store.d.ts +4 -1
- package/dist/@types/adapters/in-memory-store.d.ts.map +1 -1
- package/dist/@types/builders/act-builder.d.ts.map +1 -1
- package/dist/@types/internal/correlate-cycle.d.ts.map +1 -1
- package/dist/@types/internal/drain.d.ts +2 -1
- package/dist/@types/internal/drain.d.ts.map +1 -1
- package/dist/@types/internal/settle.d.ts +19 -0
- package/dist/@types/internal/settle.d.ts.map +1 -1
- package/dist/@types/types/ports.d.ts +33 -1
- package/dist/@types/types/ports.d.ts.map +1 -1
- package/dist/{chunk-NHJQCCBS.js → chunk-BAIMGDI4.js} +8 -3
- package/dist/chunk-BAIMGDI4.js.map +1 -0
- package/dist/index.cjs +68 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +62 -7
- package/dist/index.js.map +1 -1
- package/dist/test/index.cjs +7 -2
- package/dist/test/index.cjs.map +1 -1
- package/dist/test/index.js +1 -1
- package/package.json +2 -2
- package/dist/chunk-NHJQCCBS.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
sleep,
|
|
23
23
|
store,
|
|
24
24
|
validate
|
|
25
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-BAIMGDI4.js";
|
|
26
26
|
import {
|
|
27
27
|
ActorSchema,
|
|
28
28
|
CausationEventSchema,
|
|
@@ -1693,8 +1693,10 @@ var CorrelateCycle = class {
|
|
|
1693
1693
|
this._initialized = true;
|
|
1694
1694
|
}
|
|
1695
1695
|
async _run_init() {
|
|
1696
|
-
const { watermark } = await store().subscribe([
|
|
1697
|
-
|
|
1696
|
+
const { watermark, correlated_at } = await store().subscribe([
|
|
1697
|
+
...this._static_targets
|
|
1698
|
+
]);
|
|
1699
|
+
this._checkpoint = !this._has_dynamic_resolvers ? watermark : correlated_at >= 0 ? correlated_at : Math.max(-1, watermark - this._cold_start_back_scan);
|
|
1698
1700
|
this._on_init?.();
|
|
1699
1701
|
for (const { stream } of this._static_targets) {
|
|
1700
1702
|
this._subscribed.set(stream, Number.POSITIVE_INFINITY);
|
|
@@ -1774,7 +1776,7 @@ var CorrelateCycle = class {
|
|
|
1774
1776
|
lane
|
|
1775
1777
|
})
|
|
1776
1778
|
);
|
|
1777
|
-
const { subscribed } = await this._cd.subscribe(streams);
|
|
1779
|
+
const { subscribed } = await this._cd.subscribe(streams, last_id);
|
|
1778
1780
|
this._checkpoint = last_id;
|
|
1779
1781
|
if (subscribed) {
|
|
1780
1782
|
for (const { stream, priority } of streams) {
|
|
@@ -1960,7 +1962,7 @@ async function fetch(leased, eventLimit) {
|
|
|
1960
1962
|
}
|
|
1961
1963
|
var ack = (leases) => store().ack(leases);
|
|
1962
1964
|
var block = (leases) => store().block(leases);
|
|
1963
|
-
var subscribe = (streams) => store().subscribe(streams);
|
|
1965
|
+
var subscribe = (streams, correlated_at) => store().subscribe(streams, correlated_at);
|
|
1964
1966
|
|
|
1965
1967
|
// src/internal/event-sourcing.ts
|
|
1966
1968
|
import { patch } from "@rotorsoft/act-patch";
|
|
@@ -3022,6 +3024,19 @@ function build_handle_batch(logger) {
|
|
|
3022
3024
|
var SettleLoop = class {
|
|
3023
3025
|
_timer = void 0;
|
|
3024
3026
|
_running = false;
|
|
3027
|
+
/**
|
|
3028
|
+
* Resolves when the cycle currently in flight finishes; `undefined` when
|
|
3029
|
+
* idle (#1468). `_running` answers "is a cycle running?" for the
|
|
3030
|
+
* re-arm bookkeeping; this answers "tell me when it is done" for a
|
|
3031
|
+
* graceful shutdown.
|
|
3032
|
+
*
|
|
3033
|
+
* `stop()` only cancels *scheduling* — a cycle already inside its
|
|
3034
|
+
* correlate → drain loop keeps going, and because `DrainController.drain`
|
|
3035
|
+
* does not consult `_stopped`, it can claim a stream after teardown
|
|
3036
|
+
* returned and after the store adapter was disposed. Never rejects: the
|
|
3037
|
+
* cycle's own `catch` contains its errors, so awaiting this is safe.
|
|
3038
|
+
*/
|
|
3039
|
+
_inflight;
|
|
3025
3040
|
/**
|
|
3026
3041
|
* Set when a `schedule()` timer fires while a cycle is still running
|
|
3027
3042
|
* (ACT-1205). The in-flight cycle's `finally` re-arms one more pass so
|
|
@@ -3061,6 +3076,10 @@ var SettleLoop = class {
|
|
|
3061
3076
|
return;
|
|
3062
3077
|
}
|
|
3063
3078
|
this._running = true;
|
|
3079
|
+
let settle_done;
|
|
3080
|
+
this._inflight = new Promise((done) => {
|
|
3081
|
+
settle_done = done;
|
|
3082
|
+
});
|
|
3064
3083
|
(async () => {
|
|
3065
3084
|
await this._deps.init();
|
|
3066
3085
|
let settled_drain;
|
|
@@ -3086,6 +3105,8 @@ var SettleLoop = class {
|
|
|
3086
3105
|
this._deps.breaker.failed(Date.now(), err);
|
|
3087
3106
|
}).finally(() => {
|
|
3088
3107
|
this._running = false;
|
|
3108
|
+
this._inflight = void 0;
|
|
3109
|
+
settle_done();
|
|
3089
3110
|
const pending = this._pending;
|
|
3090
3111
|
if (pending !== void 0) {
|
|
3091
3112
|
this._pending = void 0;
|
|
@@ -3094,6 +3115,14 @@ var SettleLoop = class {
|
|
|
3094
3115
|
});
|
|
3095
3116
|
}, debounceMs);
|
|
3096
3117
|
}
|
|
3118
|
+
/**
|
|
3119
|
+
* The cycle currently in flight, or `undefined` when idle (#1468). A
|
|
3120
|
+
* graceful shutdown awaits this alongside the drain controllers so a
|
|
3121
|
+
* settle parked in `correlate` does not resume after teardown.
|
|
3122
|
+
*/
|
|
3123
|
+
get inflight() {
|
|
3124
|
+
return this._inflight;
|
|
3125
|
+
}
|
|
3097
3126
|
/** Cancel any pending or active settle cycle. Idempotent. */
|
|
3098
3127
|
stop() {
|
|
3099
3128
|
this._pending = void 0;
|
|
@@ -3636,10 +3665,12 @@ var Act = class {
|
|
|
3636
3665
|
const running = [...this._drain_controllers.values()].filter(
|
|
3637
3666
|
(c) => c.inflight !== void 0
|
|
3638
3667
|
);
|
|
3639
|
-
|
|
3668
|
+
const settling = this._settle.inflight;
|
|
3669
|
+
if (running.length === 0 && !settling) return;
|
|
3640
3670
|
const grace = grace_ms ?? this._derive_grace_ms(running);
|
|
3641
3671
|
if (grace <= 0) return;
|
|
3642
3672
|
const inflight = running.map((c) => c.inflight);
|
|
3673
|
+
if (settling) inflight.push(settling);
|
|
3643
3674
|
let timer;
|
|
3644
3675
|
const budget = new Promise((resolve) => {
|
|
3645
3676
|
timer = setTimeout(resolve, grace);
|
|
@@ -4591,6 +4622,14 @@ function act() {
|
|
|
4591
4622
|
autoclose_archiver: (state_name) => _aa.get(state_name) ?? null
|
|
4592
4623
|
};
|
|
4593
4624
|
const pending_projections = [];
|
|
4625
|
+
const projection_reactions = /* @__PURE__ */ new Set();
|
|
4626
|
+
const record_projection_reactions = (proj) => {
|
|
4627
|
+
for (const register of Object.values(
|
|
4628
|
+
proj.events
|
|
4629
|
+
))
|
|
4630
|
+
for (const reaction of register.reactions.values())
|
|
4631
|
+
projection_reactions.add(reaction);
|
|
4632
|
+
};
|
|
4594
4633
|
const fold_projections = [];
|
|
4595
4634
|
const batch_handlers = /* @__PURE__ */ new Map();
|
|
4596
4635
|
const fold_specs = [];
|
|
@@ -4687,6 +4726,7 @@ function act() {
|
|
|
4687
4726
|
return builder;
|
|
4688
4727
|
},
|
|
4689
4728
|
withProjection: (proj) => {
|
|
4729
|
+
record_projection_reactions(proj);
|
|
4690
4730
|
merge_projection(proj, registry.events);
|
|
4691
4731
|
register_batch_handler(proj, batch_handlers);
|
|
4692
4732
|
if (proj.fold)
|
|
@@ -4704,6 +4744,7 @@ function act() {
|
|
|
4704
4744
|
const patch_fn = options?.validateFoldedState === true ? validating_patch : bare_patch;
|
|
4705
4745
|
if (!_built) {
|
|
4706
4746
|
for (const proj of pending_projections) {
|
|
4747
|
+
record_projection_reactions(proj);
|
|
4707
4748
|
merge_projection(proj, registry.events);
|
|
4708
4749
|
register_batch_handler(proj, batch_handlers);
|
|
4709
4750
|
if (proj.fold) fold_projections.push(proj);
|
|
@@ -4722,17 +4763,31 @@ function act() {
|
|
|
4722
4763
|
throw new Error(
|
|
4723
4764
|
`State projection "${proj.target}" of "${fold.name}" is missing events ${missing.join(", ")} \u2014 pass every partial of the state to .of()`
|
|
4724
4765
|
);
|
|
4725
|
-
|
|
4766
|
+
const claimed = fold_specs.find((s) => s.target === proj.target);
|
|
4767
|
+
if (claimed?.projection === proj) continue;
|
|
4768
|
+
if (batch_handlers.has(proj.target) || claimed)
|
|
4726
4769
|
throw new Error(
|
|
4727
4770
|
`Duplicate projection target "${proj.target}" \u2014 a target is served by one batch handler or one state projection, never both`
|
|
4728
4771
|
);
|
|
4729
4772
|
fold_specs.push({
|
|
4730
4773
|
target: proj.target,
|
|
4774
|
+
projection: proj,
|
|
4731
4775
|
merged,
|
|
4732
4776
|
flush: fold.flush,
|
|
4733
4777
|
config: fold.config
|
|
4734
4778
|
});
|
|
4735
4779
|
}
|
|
4780
|
+
for (const register of Object.values(registry.events)) {
|
|
4781
|
+
for (const reaction of register.reactions.values()) {
|
|
4782
|
+
if (typeof reaction.resolver === "function") continue;
|
|
4783
|
+
const target = reaction.resolver.target;
|
|
4784
|
+
const claimed = batch_handlers.has(target) || fold_specs.some((f) => f.target === target);
|
|
4785
|
+
if (claimed && !projection_reactions.has(reaction))
|
|
4786
|
+
throw new Error(
|
|
4787
|
+
`Reaction on target "${target}" conflicts with the projection that already serves it \u2014 a target is served by one batch handler or one state projection, and a reaction to it would never run`
|
|
4788
|
+
);
|
|
4789
|
+
}
|
|
4790
|
+
}
|
|
4736
4791
|
finalize_deprecations();
|
|
4737
4792
|
validate_lane_references(registry, lanes);
|
|
4738
4793
|
for (const [event_name, reg] of Object.entries(
|