@rotorsoft/act 1.25.2 → 1.25.3
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/builders/act-builder.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/index.cjs +55 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +55 -2
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -3022,6 +3022,19 @@ function build_handle_batch(logger) {
|
|
|
3022
3022
|
var SettleLoop = class {
|
|
3023
3023
|
_timer = void 0;
|
|
3024
3024
|
_running = false;
|
|
3025
|
+
/**
|
|
3026
|
+
* Resolves when the cycle currently in flight finishes; `undefined` when
|
|
3027
|
+
* idle (#1468). `_running` answers "is a cycle running?" for the
|
|
3028
|
+
* re-arm bookkeeping; this answers "tell me when it is done" for a
|
|
3029
|
+
* graceful shutdown.
|
|
3030
|
+
*
|
|
3031
|
+
* `stop()` only cancels *scheduling* — a cycle already inside its
|
|
3032
|
+
* correlate → drain loop keeps going, and because `DrainController.drain`
|
|
3033
|
+
* does not consult `_stopped`, it can claim a stream after teardown
|
|
3034
|
+
* returned and after the store adapter was disposed. Never rejects: the
|
|
3035
|
+
* cycle's own `catch` contains its errors, so awaiting this is safe.
|
|
3036
|
+
*/
|
|
3037
|
+
_inflight;
|
|
3025
3038
|
/**
|
|
3026
3039
|
* Set when a `schedule()` timer fires while a cycle is still running
|
|
3027
3040
|
* (ACT-1205). The in-flight cycle's `finally` re-arms one more pass so
|
|
@@ -3061,6 +3074,10 @@ var SettleLoop = class {
|
|
|
3061
3074
|
return;
|
|
3062
3075
|
}
|
|
3063
3076
|
this._running = true;
|
|
3077
|
+
let settle_done;
|
|
3078
|
+
this._inflight = new Promise((done) => {
|
|
3079
|
+
settle_done = done;
|
|
3080
|
+
});
|
|
3064
3081
|
(async () => {
|
|
3065
3082
|
await this._deps.init();
|
|
3066
3083
|
let settled_drain;
|
|
@@ -3086,6 +3103,8 @@ var SettleLoop = class {
|
|
|
3086
3103
|
this._deps.breaker.failed(Date.now(), err);
|
|
3087
3104
|
}).finally(() => {
|
|
3088
3105
|
this._running = false;
|
|
3106
|
+
this._inflight = void 0;
|
|
3107
|
+
settle_done();
|
|
3089
3108
|
const pending = this._pending;
|
|
3090
3109
|
if (pending !== void 0) {
|
|
3091
3110
|
this._pending = void 0;
|
|
@@ -3094,6 +3113,14 @@ var SettleLoop = class {
|
|
|
3094
3113
|
});
|
|
3095
3114
|
}, debounceMs);
|
|
3096
3115
|
}
|
|
3116
|
+
/**
|
|
3117
|
+
* The cycle currently in flight, or `undefined` when idle (#1468). A
|
|
3118
|
+
* graceful shutdown awaits this alongside the drain controllers so a
|
|
3119
|
+
* settle parked in `correlate` does not resume after teardown.
|
|
3120
|
+
*/
|
|
3121
|
+
get inflight() {
|
|
3122
|
+
return this._inflight;
|
|
3123
|
+
}
|
|
3097
3124
|
/** Cancel any pending or active settle cycle. Idempotent. */
|
|
3098
3125
|
stop() {
|
|
3099
3126
|
this._pending = void 0;
|
|
@@ -3636,10 +3663,12 @@ var Act = class {
|
|
|
3636
3663
|
const running = [...this._drain_controllers.values()].filter(
|
|
3637
3664
|
(c) => c.inflight !== void 0
|
|
3638
3665
|
);
|
|
3639
|
-
|
|
3666
|
+
const settling = this._settle.inflight;
|
|
3667
|
+
if (running.length === 0 && !settling) return;
|
|
3640
3668
|
const grace = grace_ms ?? this._derive_grace_ms(running);
|
|
3641
3669
|
if (grace <= 0) return;
|
|
3642
3670
|
const inflight = running.map((c) => c.inflight);
|
|
3671
|
+
if (settling) inflight.push(settling);
|
|
3643
3672
|
let timer;
|
|
3644
3673
|
const budget = new Promise((resolve) => {
|
|
3645
3674
|
timer = setTimeout(resolve, grace);
|
|
@@ -4591,6 +4620,14 @@ function act() {
|
|
|
4591
4620
|
autoclose_archiver: (state_name) => _aa.get(state_name) ?? null
|
|
4592
4621
|
};
|
|
4593
4622
|
const pending_projections = [];
|
|
4623
|
+
const projection_reactions = /* @__PURE__ */ new Set();
|
|
4624
|
+
const record_projection_reactions = (proj) => {
|
|
4625
|
+
for (const register of Object.values(
|
|
4626
|
+
proj.events
|
|
4627
|
+
))
|
|
4628
|
+
for (const reaction of register.reactions.values())
|
|
4629
|
+
projection_reactions.add(reaction);
|
|
4630
|
+
};
|
|
4594
4631
|
const fold_projections = [];
|
|
4595
4632
|
const batch_handlers = /* @__PURE__ */ new Map();
|
|
4596
4633
|
const fold_specs = [];
|
|
@@ -4687,6 +4724,7 @@ function act() {
|
|
|
4687
4724
|
return builder;
|
|
4688
4725
|
},
|
|
4689
4726
|
withProjection: (proj) => {
|
|
4727
|
+
record_projection_reactions(proj);
|
|
4690
4728
|
merge_projection(proj, registry.events);
|
|
4691
4729
|
register_batch_handler(proj, batch_handlers);
|
|
4692
4730
|
if (proj.fold)
|
|
@@ -4704,6 +4742,7 @@ function act() {
|
|
|
4704
4742
|
const patch_fn = options?.validateFoldedState === true ? validating_patch : bare_patch;
|
|
4705
4743
|
if (!_built) {
|
|
4706
4744
|
for (const proj of pending_projections) {
|
|
4745
|
+
record_projection_reactions(proj);
|
|
4707
4746
|
merge_projection(proj, registry.events);
|
|
4708
4747
|
register_batch_handler(proj, batch_handlers);
|
|
4709
4748
|
if (proj.fold) fold_projections.push(proj);
|
|
@@ -4722,17 +4761,31 @@ function act() {
|
|
|
4722
4761
|
throw new Error(
|
|
4723
4762
|
`State projection "${proj.target}" of "${fold.name}" is missing events ${missing.join(", ")} \u2014 pass every partial of the state to .of()`
|
|
4724
4763
|
);
|
|
4725
|
-
|
|
4764
|
+
const claimed = fold_specs.find((s) => s.target === proj.target);
|
|
4765
|
+
if (claimed?.projection === proj) continue;
|
|
4766
|
+
if (batch_handlers.has(proj.target) || claimed)
|
|
4726
4767
|
throw new Error(
|
|
4727
4768
|
`Duplicate projection target "${proj.target}" \u2014 a target is served by one batch handler or one state projection, never both`
|
|
4728
4769
|
);
|
|
4729
4770
|
fold_specs.push({
|
|
4730
4771
|
target: proj.target,
|
|
4772
|
+
projection: proj,
|
|
4731
4773
|
merged,
|
|
4732
4774
|
flush: fold.flush,
|
|
4733
4775
|
config: fold.config
|
|
4734
4776
|
});
|
|
4735
4777
|
}
|
|
4778
|
+
for (const register of Object.values(registry.events)) {
|
|
4779
|
+
for (const reaction of register.reactions.values()) {
|
|
4780
|
+
if (typeof reaction.resolver === "function") continue;
|
|
4781
|
+
const target = reaction.resolver.target;
|
|
4782
|
+
const claimed = batch_handlers.has(target) || fold_specs.some((f) => f.target === target);
|
|
4783
|
+
if (claimed && !projection_reactions.has(reaction))
|
|
4784
|
+
throw new Error(
|
|
4785
|
+
`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`
|
|
4786
|
+
);
|
|
4787
|
+
}
|
|
4788
|
+
}
|
|
4736
4789
|
finalize_deprecations();
|
|
4737
4790
|
validate_lane_references(registry, lanes);
|
|
4738
4791
|
for (const [event_name, reg] of Object.entries(
|