@rotorsoft/act 1.10.2 → 1.11.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 +61 -2
- package/dist/@types/act.d.ts.map +1 -1
- package/dist/@types/builders/act-builder.d.ts.map +1 -1
- package/dist/@types/builders/state-builder.d.ts +88 -1
- package/dist/@types/builders/state-builder.d.ts.map +1 -1
- package/dist/@types/internal/autoclose-config.d.ts +72 -0
- package/dist/@types/internal/autoclose-config.d.ts.map +1 -0
- package/dist/@types/internal/autoclose-cycle.d.ts +171 -0
- package/dist/@types/internal/autoclose-cycle.d.ts.map +1 -0
- package/dist/@types/internal/index.d.ts +2 -0
- package/dist/@types/internal/index.d.ts.map +1 -1
- package/dist/@types/types/action.d.ts +63 -0
- package/dist/@types/types/action.d.ts.map +1 -1
- package/dist/@types/types/registry.d.ts +24 -4
- package/dist/@types/types/registry.d.ts.map +1 -1
- package/dist/index.cjs +321 -79
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +315 -77
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -486,57 +486,24 @@ var PASS_FACTORIES = {
|
|
|
486
486
|
"clock-anomalies": make_clock_anomalies_pass
|
|
487
487
|
};
|
|
488
488
|
|
|
489
|
-
// src/internal/
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
const set = existing_lanes ?? /* @__PURE__ */ new Set();
|
|
508
|
-
set.add(lane_name);
|
|
509
|
-
event_to_lanes.set(name, set);
|
|
510
|
-
}
|
|
511
|
-
const key = `${target}|${source ?? ""}`;
|
|
512
|
-
const existing = statics.get(key);
|
|
513
|
-
if (!existing) {
|
|
514
|
-
statics.set(key, { stream: target, source, priority, lane });
|
|
515
|
-
} else {
|
|
516
|
-
if ((existing.lane ?? void 0) !== (lane ?? void 0))
|
|
517
|
-
throw new Error(
|
|
518
|
-
`Stream "${target}" has conflicting lane assignments ("${existing.lane ?? "default"}" vs "${lane ?? "default"}")`
|
|
519
|
-
);
|
|
520
|
-
if (priority > existing.priority) {
|
|
521
|
-
statics.set(key, { ...existing, priority });
|
|
522
|
-
}
|
|
523
|
-
}
|
|
524
|
-
}
|
|
525
|
-
}
|
|
526
|
-
}
|
|
527
|
-
const event_to_state = /* @__PURE__ */ new Map();
|
|
528
|
-
for (const merged of states.values()) {
|
|
529
|
-
for (const event_name of Object.keys(merged.events)) {
|
|
530
|
-
event_to_state.set(event_name, merged);
|
|
531
|
-
}
|
|
532
|
-
}
|
|
533
|
-
return {
|
|
534
|
-
static_targets: [...statics.values()],
|
|
535
|
-
has_dynamic_resolvers,
|
|
536
|
-
reactive_events,
|
|
537
|
-
event_to_state,
|
|
538
|
-
event_to_lanes
|
|
539
|
-
};
|
|
489
|
+
// src/internal/autoclose-config.ts
|
|
490
|
+
import { z } from "zod";
|
|
491
|
+
var DEFAULT_AUTOCLOSE_CYCLE_MS = 6e4;
|
|
492
|
+
var DEFAULT_CLOSE_BATCH_SIZE = 64;
|
|
493
|
+
var DEFAULT_CLOSE_YIELD_MS = 0;
|
|
494
|
+
var AutocloseOptionsSchema = z.object({
|
|
495
|
+
autocloseCycleMs: z.number().min(1e4).max(36e5).default(DEFAULT_AUTOCLOSE_CYCLE_MS),
|
|
496
|
+
closeBatchSize: z.number().int().min(1).max(1024).default(DEFAULT_CLOSE_BATCH_SIZE),
|
|
497
|
+
closeYieldMs: z.number().min(0).max(1e3).default(DEFAULT_CLOSE_YIELD_MS),
|
|
498
|
+
closeOnError: z.boolean().default(false)
|
|
499
|
+
});
|
|
500
|
+
function resolveAutocloseConfig(options) {
|
|
501
|
+
return AutocloseOptionsSchema.parse({
|
|
502
|
+
autocloseCycleMs: options?.autocloseCycleMs,
|
|
503
|
+
closeBatchSize: options?.closeBatchSize,
|
|
504
|
+
closeYieldMs: options?.closeYieldMs,
|
|
505
|
+
closeOnError: options?.closeOnError
|
|
506
|
+
});
|
|
540
507
|
}
|
|
541
508
|
|
|
542
509
|
// src/internal/close-cycle.ts
|
|
@@ -686,6 +653,233 @@ async function truncate_and_warm_cache(guarded, seed_states, guard_events, corre
|
|
|
686
653
|
return truncated;
|
|
687
654
|
}
|
|
688
655
|
|
|
656
|
+
// src/internal/correlator.ts
|
|
657
|
+
import { randomInt } from "crypto";
|
|
658
|
+
var BASE = 36;
|
|
659
|
+
var SEG_WIDTH = 4;
|
|
660
|
+
var SEG_SPACE = BASE ** SEG_WIDTH;
|
|
661
|
+
function seg(n) {
|
|
662
|
+
return n.toString(BASE).padStart(SEG_WIDTH, "0");
|
|
663
|
+
}
|
|
664
|
+
var default_correlator = ({ state: state2, action: action2 }) => {
|
|
665
|
+
const s = state2.slice(0, SEG_WIDTH).toLowerCase();
|
|
666
|
+
const a = action2.slice(0, SEG_WIDTH).toLowerCase();
|
|
667
|
+
const ts = seg(Date.now() % SEG_SPACE);
|
|
668
|
+
const rnd = seg(randomInt(SEG_SPACE));
|
|
669
|
+
return `${s}-${a}-${ts}${rnd}`;
|
|
670
|
+
};
|
|
671
|
+
function close_correlation(correlator, actor) {
|
|
672
|
+
return correlator({
|
|
673
|
+
state: "$close",
|
|
674
|
+
action: "close",
|
|
675
|
+
stream: "$close",
|
|
676
|
+
actor
|
|
677
|
+
});
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
// src/internal/autoclose-cycle.ts
|
|
681
|
+
function yield_between_batches(ms) {
|
|
682
|
+
if (ms <= 0) return Promise.resolve();
|
|
683
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
684
|
+
}
|
|
685
|
+
async function run_autoclose_cycle(deps) {
|
|
686
|
+
const s = store();
|
|
687
|
+
let inspected = 0;
|
|
688
|
+
let evaluated = 0;
|
|
689
|
+
let predicate_errors = 0;
|
|
690
|
+
const truncated = /* @__PURE__ */ new Map();
|
|
691
|
+
const skipped = [];
|
|
692
|
+
const stats = await s.query_stats(
|
|
693
|
+
{},
|
|
694
|
+
{ count: true, exclude: [TOMBSTONE_EVENT] }
|
|
695
|
+
);
|
|
696
|
+
const flush_batch = async (candidates2) => {
|
|
697
|
+
if (candidates2.length === 0) return;
|
|
698
|
+
const result = await run_close_cycle(candidates2, {
|
|
699
|
+
reactive_events_size: deps.reactive_events_size,
|
|
700
|
+
event_to_state: deps.event_to_state,
|
|
701
|
+
load: deps.load,
|
|
702
|
+
tombstone: deps.tombstone,
|
|
703
|
+
logger: deps.logger,
|
|
704
|
+
correlation: deps.correlation
|
|
705
|
+
});
|
|
706
|
+
for (const [stream, entry] of result.truncated) {
|
|
707
|
+
truncated.set(stream, entry);
|
|
708
|
+
}
|
|
709
|
+
for (const stream of result.skipped) skipped.push(stream);
|
|
710
|
+
await yield_between_batches(deps.config.closeYieldMs);
|
|
711
|
+
};
|
|
712
|
+
let candidates = [];
|
|
713
|
+
for (const [stream, { head, count }] of stats) {
|
|
714
|
+
inspected += 1;
|
|
715
|
+
const owner = deps.event_to_state.get(head.name);
|
|
716
|
+
if (!owner) continue;
|
|
717
|
+
const predicate = deps.autoclose_policy(owner.name);
|
|
718
|
+
if (!predicate) continue;
|
|
719
|
+
let close = false;
|
|
720
|
+
try {
|
|
721
|
+
close = predicate(stream, head, count ?? 0);
|
|
722
|
+
evaluated += 1;
|
|
723
|
+
} catch (err) {
|
|
724
|
+
predicate_errors += 1;
|
|
725
|
+
deps.logger.error(
|
|
726
|
+
`Autoclose predicate for state "${owner.name}" threw on stream "${stream}": ${err instanceof Error ? err.message : String(err)}`
|
|
727
|
+
);
|
|
728
|
+
close = deps.config.closeOnError;
|
|
729
|
+
}
|
|
730
|
+
if (!close) continue;
|
|
731
|
+
const archiver = deps.autoclose_archiver(owner.name);
|
|
732
|
+
const archive = archiver ? () => archiver(stream, head) : void 0;
|
|
733
|
+
candidates.push({ stream, archive });
|
|
734
|
+
if (candidates.length >= deps.config.closeBatchSize) {
|
|
735
|
+
await flush_batch(candidates);
|
|
736
|
+
candidates = [];
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
await flush_batch(candidates);
|
|
740
|
+
return {
|
|
741
|
+
inspected,
|
|
742
|
+
evaluated,
|
|
743
|
+
predicate_errors,
|
|
744
|
+
close_result: { truncated, skipped }
|
|
745
|
+
};
|
|
746
|
+
}
|
|
747
|
+
var AutocloseController = class {
|
|
748
|
+
deps;
|
|
749
|
+
_timer;
|
|
750
|
+
/**
|
|
751
|
+
* Reentrancy guard. The interval fires the next tick on cadence
|
|
752
|
+
* regardless of how long the previous one took; this flag drops
|
|
753
|
+
* overlapping ticks so the cycle stays sequential per controller.
|
|
754
|
+
*/
|
|
755
|
+
_running = false;
|
|
756
|
+
constructor(deps) {
|
|
757
|
+
this.deps = deps;
|
|
758
|
+
}
|
|
759
|
+
/**
|
|
760
|
+
* Start the cycle ticker. Returns `false` if already running so
|
|
761
|
+
* accidental double-start doesn't stack timers (matches
|
|
762
|
+
* `_correlate.start_polling` semantics).
|
|
763
|
+
*/
|
|
764
|
+
start() {
|
|
765
|
+
if (this._timer) return false;
|
|
766
|
+
this._timer = setInterval(() => {
|
|
767
|
+
this.run_once().catch((err) => {
|
|
768
|
+
this.deps.logger.error(
|
|
769
|
+
`Autoclose cycle errored: ${err instanceof Error ? err.message : String(err)}`
|
|
770
|
+
);
|
|
771
|
+
});
|
|
772
|
+
}, this.deps.config.autocloseCycleMs);
|
|
773
|
+
this._timer.unref();
|
|
774
|
+
return true;
|
|
775
|
+
}
|
|
776
|
+
/**
|
|
777
|
+
* Stop the cycle ticker. Idempotent.
|
|
778
|
+
*/
|
|
779
|
+
stop() {
|
|
780
|
+
if (this._timer) {
|
|
781
|
+
clearInterval(this._timer);
|
|
782
|
+
this._timer = void 0;
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
/**
|
|
786
|
+
* Whether the ticker is currently running.
|
|
787
|
+
*/
|
|
788
|
+
get is_running() {
|
|
789
|
+
return this._timer !== void 0;
|
|
790
|
+
}
|
|
791
|
+
/**
|
|
792
|
+
* Run one cycle synchronously. The controller's interval callback
|
|
793
|
+
* delegates here; tests can invoke it directly to deterministically
|
|
794
|
+
* exercise the cycle without spinning real timers.
|
|
795
|
+
*
|
|
796
|
+
* Overlapping invocations short-circuit: if a previous tick is
|
|
797
|
+
* still running, this one drops and returns `null`. The orchestrator
|
|
798
|
+
* never sees a queue of pending ticks regardless of how slow the
|
|
799
|
+
* predicate / archive / truncate are.
|
|
800
|
+
*/
|
|
801
|
+
async run_once() {
|
|
802
|
+
if (this._running) return null;
|
|
803
|
+
this._running = true;
|
|
804
|
+
try {
|
|
805
|
+
const correlation = close_correlation(
|
|
806
|
+
this.deps.correlator,
|
|
807
|
+
this.deps.close_actor
|
|
808
|
+
);
|
|
809
|
+
const result = await run_autoclose_cycle({
|
|
810
|
+
autoclose_policy: this.deps.autoclose_policy,
|
|
811
|
+
autoclose_archiver: this.deps.autoclose_archiver,
|
|
812
|
+
event_to_state: this.deps.event_to_state,
|
|
813
|
+
reactive_events_size: this.deps.reactive_events_size,
|
|
814
|
+
load: this.deps.load,
|
|
815
|
+
tombstone: this.deps.tombstone,
|
|
816
|
+
logger: this.deps.logger,
|
|
817
|
+
config: this.deps.config,
|
|
818
|
+
correlation
|
|
819
|
+
});
|
|
820
|
+
if (result.close_result.truncated.size > 0) {
|
|
821
|
+
this.deps.on_closed(result.close_result);
|
|
822
|
+
}
|
|
823
|
+
return result;
|
|
824
|
+
} finally {
|
|
825
|
+
this._running = false;
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
};
|
|
829
|
+
|
|
830
|
+
// src/internal/build-classify.ts
|
|
831
|
+
var ALL_LANES = /* @__PURE__ */ Symbol("act-1103/all-lanes");
|
|
832
|
+
function classify_registry(registry, states) {
|
|
833
|
+
const statics = /* @__PURE__ */ new Map();
|
|
834
|
+
const reactive_events = /* @__PURE__ */ new Set();
|
|
835
|
+
const event_to_lanes = /* @__PURE__ */ new Map();
|
|
836
|
+
let has_dynamic_resolvers = false;
|
|
837
|
+
for (const [name, register] of Object.entries(registry.events)) {
|
|
838
|
+
if (register.reactions.size > 0) reactive_events.add(name);
|
|
839
|
+
for (const reaction of register.reactions.values()) {
|
|
840
|
+
if (typeof reaction.resolver === "function") {
|
|
841
|
+
has_dynamic_resolvers = true;
|
|
842
|
+
event_to_lanes.set(name, ALL_LANES);
|
|
843
|
+
} else {
|
|
844
|
+
const { target, source, priority = 0, lane } = reaction.resolver;
|
|
845
|
+
const lane_name = lane ?? "default";
|
|
846
|
+
const existing_lanes = event_to_lanes.get(name);
|
|
847
|
+
if (existing_lanes !== ALL_LANES) {
|
|
848
|
+
const set = existing_lanes ?? /* @__PURE__ */ new Set();
|
|
849
|
+
set.add(lane_name);
|
|
850
|
+
event_to_lanes.set(name, set);
|
|
851
|
+
}
|
|
852
|
+
const key = `${target}|${source ?? ""}`;
|
|
853
|
+
const existing = statics.get(key);
|
|
854
|
+
if (!existing) {
|
|
855
|
+
statics.set(key, { stream: target, source, priority, lane });
|
|
856
|
+
} else {
|
|
857
|
+
if ((existing.lane ?? void 0) !== (lane ?? void 0))
|
|
858
|
+
throw new Error(
|
|
859
|
+
`Stream "${target}" has conflicting lane assignments ("${existing.lane ?? "default"}" vs "${lane ?? "default"}")`
|
|
860
|
+
);
|
|
861
|
+
if (priority > existing.priority) {
|
|
862
|
+
statics.set(key, { ...existing, priority });
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
const event_to_state = /* @__PURE__ */ new Map();
|
|
869
|
+
for (const merged of states.values()) {
|
|
870
|
+
for (const event_name of Object.keys(merged.events)) {
|
|
871
|
+
event_to_state.set(event_name, merged);
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
return {
|
|
875
|
+
static_targets: [...statics.values()],
|
|
876
|
+
has_dynamic_resolvers,
|
|
877
|
+
reactive_events,
|
|
878
|
+
event_to_state,
|
|
879
|
+
event_to_lanes
|
|
880
|
+
};
|
|
881
|
+
}
|
|
882
|
+
|
|
689
883
|
// src/internal/correlate-cycle.ts
|
|
690
884
|
var CorrelateCycle = class {
|
|
691
885
|
_checkpoint = -1;
|
|
@@ -814,30 +1008,6 @@ var CorrelateCycle = class {
|
|
|
814
1008
|
}
|
|
815
1009
|
};
|
|
816
1010
|
|
|
817
|
-
// src/internal/correlator.ts
|
|
818
|
-
import { randomInt } from "crypto";
|
|
819
|
-
var BASE = 36;
|
|
820
|
-
var SEG_WIDTH = 4;
|
|
821
|
-
var SEG_SPACE = BASE ** SEG_WIDTH;
|
|
822
|
-
function seg(n) {
|
|
823
|
-
return n.toString(BASE).padStart(SEG_WIDTH, "0");
|
|
824
|
-
}
|
|
825
|
-
var default_correlator = ({ state: state2, action: action2 }) => {
|
|
826
|
-
const s = state2.slice(0, SEG_WIDTH).toLowerCase();
|
|
827
|
-
const a = action2.slice(0, SEG_WIDTH).toLowerCase();
|
|
828
|
-
const ts = seg(Date.now() % SEG_SPACE);
|
|
829
|
-
const rnd = seg(randomInt(SEG_SPACE));
|
|
830
|
-
return `${s}-${a}-${ts}${rnd}`;
|
|
831
|
-
};
|
|
832
|
-
function close_correlation(correlator, actor) {
|
|
833
|
-
return correlator({
|
|
834
|
-
state: "$close",
|
|
835
|
-
action: "close",
|
|
836
|
-
stream: "$close",
|
|
837
|
-
actor
|
|
838
|
-
});
|
|
839
|
-
}
|
|
840
|
-
|
|
841
1011
|
// src/internal/drain-cycle.ts
|
|
842
1012
|
import { randomUUID } from "crypto";
|
|
843
1013
|
|
|
@@ -1941,6 +2111,22 @@ var Act = class {
|
|
|
1941
2111
|
registry;
|
|
1942
2112
|
/** Map of state name → state definition; populated by the builder. */
|
|
1943
2113
|
_states;
|
|
2114
|
+
/**
|
|
2115
|
+
* Resolved autoclose configuration (#837 / epic #802). Frozen at
|
|
2116
|
+
* `act().build()` via {@link resolveAutocloseConfig}.
|
|
2117
|
+
*
|
|
2118
|
+
* @internal
|
|
2119
|
+
*/
|
|
2120
|
+
_autoclose_config;
|
|
2121
|
+
/**
|
|
2122
|
+
* App-level autoclose controller. `undefined` when no state declares
|
|
2123
|
+
* `.autocloses(...)` — the controller is never constructed, so
|
|
2124
|
+
* `start_correlations()` / `stop_correlations()` skip the autoclose
|
|
2125
|
+
* lifecycle and the orchestrator pays zero per-tick cost.
|
|
2126
|
+
*
|
|
2127
|
+
* @internal
|
|
2128
|
+
*/
|
|
2129
|
+
_autoclose;
|
|
1944
2130
|
/**
|
|
1945
2131
|
* Emit a lifecycle event. The payload type is inferred from the event name
|
|
1946
2132
|
* via {@link ActLifecycleEvents}.
|
|
@@ -2075,6 +2261,7 @@ var Act = class {
|
|
|
2075
2261
|
this._reactive_events = reactive_events;
|
|
2076
2262
|
this._listen = options.listen !== false;
|
|
2077
2263
|
this._drain = options.drain !== false;
|
|
2264
|
+
this._autoclose_config = resolveAutocloseConfig(options);
|
|
2078
2265
|
this._event_to_state = event_to_state;
|
|
2079
2266
|
this._event_to_lanes = event_to_lanes;
|
|
2080
2267
|
const all_lanes = ["default", ...lanes.map((l) => l.name)];
|
|
@@ -2138,6 +2325,26 @@ var Act = class {
|
|
|
2138
2325
|
},
|
|
2139
2326
|
options.settleDebounceMs ?? DEFAULT_SETTLE_DEBOUNCE_MS
|
|
2140
2327
|
);
|
|
2328
|
+
const states_with_policy = [...this._states.values()].filter(
|
|
2329
|
+
(s) => s.autoclose
|
|
2330
|
+
);
|
|
2331
|
+
this._autoclose = states_with_policy.length ? new AutocloseController({
|
|
2332
|
+
// Internal cycle takes the loose `(string) => …` signature; the
|
|
2333
|
+
// public `registry.autoclose_policy` narrows to
|
|
2334
|
+
// `keyof TStateMap & string`. Thin lambdas bridge across the
|
|
2335
|
+
// narrowing — runtime semantics are unchanged.
|
|
2336
|
+
autoclose_policy: (name) => this.registry.autoclose_policy(name),
|
|
2337
|
+
autoclose_archiver: (name) => this.registry.autoclose_archiver(name),
|
|
2338
|
+
event_to_state: this._event_to_state,
|
|
2339
|
+
reactive_events_size: this._reactive_events.size,
|
|
2340
|
+
load: this._es.load,
|
|
2341
|
+
tombstone: this._es.tombstone,
|
|
2342
|
+
logger: this._logger,
|
|
2343
|
+
config: this._autoclose_config,
|
|
2344
|
+
correlator: this._correlator,
|
|
2345
|
+
close_actor: { id: "$autoclose", name: "autoclose" },
|
|
2346
|
+
on_closed: (result) => this.emit("closed", result)
|
|
2347
|
+
}) : void 0;
|
|
2141
2348
|
this._notify_disposer = this._wire_notify(options.scoped?.store ?? store());
|
|
2142
2349
|
dispose(() => this.shutdown());
|
|
2143
2350
|
}
|
|
@@ -2629,7 +2836,9 @@ var Act = class {
|
|
|
2629
2836
|
* @see {@link stop_correlations} to stop the worker
|
|
2630
2837
|
*/
|
|
2631
2838
|
start_correlations(query = {}, frequency = 1e4, callback) {
|
|
2632
|
-
|
|
2839
|
+
const started = this._correlate.start_polling(query, frequency, callback);
|
|
2840
|
+
this._autoclose?.start();
|
|
2841
|
+
return started;
|
|
2633
2842
|
}
|
|
2634
2843
|
/**
|
|
2635
2844
|
* Stops the automatic correlation worker.
|
|
@@ -2650,6 +2859,7 @@ var Act = class {
|
|
|
2650
2859
|
*/
|
|
2651
2860
|
stop_correlations() {
|
|
2652
2861
|
this._correlate.stop_polling();
|
|
2862
|
+
this._autoclose?.stop();
|
|
2653
2863
|
}
|
|
2654
2864
|
/**
|
|
2655
2865
|
* Cancels any pending or active settle cycle.
|
|
@@ -3034,13 +3244,17 @@ function act() {
|
|
|
3034
3244
|
const _sf = /* @__PURE__ */ new Map();
|
|
3035
3245
|
const _dp = /* @__PURE__ */ new Map();
|
|
3036
3246
|
const _de = /* @__PURE__ */ new Map();
|
|
3247
|
+
const _ac = /* @__PURE__ */ new Map();
|
|
3248
|
+
const _aa = /* @__PURE__ */ new Map();
|
|
3037
3249
|
const EMPTY_DEPRECATED = /* @__PURE__ */ new Set();
|
|
3038
3250
|
const registry = {
|
|
3039
3251
|
actions: {},
|
|
3040
3252
|
events: {},
|
|
3041
3253
|
sensitive_fields: (event_name) => _sf.get(event_name) ?? [],
|
|
3042
3254
|
disclosure_predicate: (state_name) => _dp.get(state_name) ?? null,
|
|
3043
|
-
deprecated_events: (state_name) => _de.get(state_name) ?? EMPTY_DEPRECATED
|
|
3255
|
+
deprecated_events: (state_name) => _de.get(state_name) ?? EMPTY_DEPRECATED,
|
|
3256
|
+
autoclose_policy: (state_name) => _ac.get(state_name) ?? null,
|
|
3257
|
+
autoclose_archiver: (state_name) => _aa.get(state_name) ?? null
|
|
3044
3258
|
};
|
|
3045
3259
|
const pending_projections = [];
|
|
3046
3260
|
const batch_handlers = /* @__PURE__ */ new Map();
|
|
@@ -3167,6 +3381,8 @@ function act() {
|
|
|
3167
3381
|
}
|
|
3168
3382
|
for (const state2 of states.values()) {
|
|
3169
3383
|
if (state2.disclose) _dp.set(state2.name, state2.disclose);
|
|
3384
|
+
if (state2.autoclose) _ac.set(state2.name, state2.autoclose);
|
|
3385
|
+
if (state2.archive) _aa.set(state2.name, state2.archive);
|
|
3170
3386
|
const fields_by_event = /* @__PURE__ */ new Map();
|
|
3171
3387
|
for (const event_name of Object.keys(state2.events)) {
|
|
3172
3388
|
const fields = _sf.get(event_name);
|
|
@@ -3434,6 +3650,24 @@ function action_builder(state2) {
|
|
|
3434
3650
|
internal.disclose = disclose;
|
|
3435
3651
|
return builder;
|
|
3436
3652
|
},
|
|
3653
|
+
autocloses(predicate) {
|
|
3654
|
+
if (typeof predicate !== "function") {
|
|
3655
|
+
throw new Error(
|
|
3656
|
+
".autocloses(predicate) requires a function; got " + typeof predicate
|
|
3657
|
+
);
|
|
3658
|
+
}
|
|
3659
|
+
internal.autoclose = predicate;
|
|
3660
|
+
return builder;
|
|
3661
|
+
},
|
|
3662
|
+
archives(archive) {
|
|
3663
|
+
if (typeof archive !== "function") {
|
|
3664
|
+
throw new Error(
|
|
3665
|
+
".archives(archive) requires a function; got " + typeof archive
|
|
3666
|
+
);
|
|
3667
|
+
}
|
|
3668
|
+
internal.archive = archive;
|
|
3669
|
+
return builder;
|
|
3670
|
+
},
|
|
3437
3671
|
build() {
|
|
3438
3672
|
return internal;
|
|
3439
3673
|
}
|
|
@@ -3609,6 +3843,9 @@ export {
|
|
|
3609
3843
|
ConcurrencyError,
|
|
3610
3844
|
ConsoleLogger,
|
|
3611
3845
|
CsvFile,
|
|
3846
|
+
DEFAULT_AUTOCLOSE_CYCLE_MS,
|
|
3847
|
+
DEFAULT_CLOSE_BATCH_SIZE,
|
|
3848
|
+
DEFAULT_CLOSE_YIELD_MS,
|
|
3612
3849
|
DEFAULT_LANE,
|
|
3613
3850
|
DEFAULT_MAX_SUBSCRIBED_STREAMS,
|
|
3614
3851
|
DEFAULT_SETTLE_DEBOUNCE_MS,
|
|
@@ -3640,6 +3877,7 @@ export {
|
|
|
3640
3877
|
log,
|
|
3641
3878
|
port,
|
|
3642
3879
|
projection,
|
|
3880
|
+
resolveAutocloseConfig,
|
|
3643
3881
|
scoped,
|
|
3644
3882
|
sensitive,
|
|
3645
3883
|
sleep,
|