@statewalker/fsm 0.30.1 → 0.32.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/index.d.ts +11 -12
- package/dist/index.js +90 -13
- package/package.json +1 -1
- package/src/orchestrator/launcher.ts +129 -36
package/dist/index.d.ts
CHANGED
|
@@ -227,19 +227,18 @@ declare function toStageHandlers<C>(value: unknown, accept: (key: string, value:
|
|
|
227
227
|
type ProcessConfig = {
|
|
228
228
|
name: string;
|
|
229
229
|
config?: FsmStateConfig;
|
|
230
|
-
|
|
230
|
+
} & ({
|
|
231
|
+
handler?: StageHandler;
|
|
232
|
+
} | {
|
|
233
|
+
handlers?: StageHandler | (StageHandler | {
|
|
231
234
|
[state: string]: StageHandler | StageHandler[];
|
|
232
235
|
})[];
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
type LauncherRootContext = Record<string, unknown> & {
|
|
240
|
-
launch: (processName: string, context: Record<string, unknown>, startEvent?: string) => Promise<() => Promise<void>>;
|
|
241
|
-
};
|
|
242
|
-
declare function launcher(init: (root: LauncherRootContext) => ProcessLauncherConfig | Promise<ProcessLauncherConfig>): Promise<() => Promise<void>>;
|
|
236
|
+
} | {
|
|
237
|
+
default?: StageHandler | (StageHandler | {
|
|
238
|
+
[state: string]: StageHandler | StageHandler[];
|
|
239
|
+
})[];
|
|
240
|
+
});
|
|
241
|
+
declare function launcher(options: unknown): Promise<() => Promise<void>>;
|
|
243
242
|
|
|
244
243
|
interface IProcessConfigManager {
|
|
245
244
|
getProcessConfig(processName: string): FsmStateConfig;
|
|
@@ -283,4 +282,4 @@ declare function setStateTracer(state: FsmState, print?: Printer): void;
|
|
|
283
282
|
declare function isStateTransitionEnabled(process: FsmProcess, event: string): boolean;
|
|
284
283
|
declare function getStateTransitions(state?: FsmState): [from: string, event: string, to: string][];
|
|
285
284
|
|
|
286
|
-
export { EVENT_ANY, EVENT_EMPTY, type FsmEventKey, FsmProcess, type FsmProcessDump, type FsmProcessDumpHandler, type FsmProcessHandler, FsmState, type FsmStateConfig, FsmStateDescriptor, type FsmStateDump, type FsmStateDumpHandler, type FsmStateErrorHandler, type FsmStateHandler, type FsmStateKey, type IProcessConfigManager, KEY_DISPATCH, KEY_EVENT, KEY_LAUNCH_PROCESS, KEY_PRINTER, KEY_REGISTER_CONFIG, KEY_REGISTER_HANDLERS, KEY_STATES, KEY_TERMINATE, type
|
|
285
|
+
export { EVENT_ANY, EVENT_EMPTY, type FsmEventKey, FsmProcess, type FsmProcessDump, type FsmProcessDumpHandler, type FsmProcessHandler, FsmState, type FsmStateConfig, FsmStateDescriptor, type FsmStateDump, type FsmStateDumpHandler, type FsmStateErrorHandler, type FsmStateHandler, type FsmStateKey, type IProcessConfigManager, KEY_DISPATCH, KEY_EVENT, KEY_LAUNCH_PROCESS, KEY_PRINTER, KEY_REGISTER_CONFIG, KEY_REGISTER_HANDLERS, KEY_STATES, KEY_TERMINATE, type Module, type Printer, type PrinterConfig, type ProcessConfig, ProcessConfigManager, STATE_ANY, STATE_FINAL, STATE_INITIAL, STATUS_ENTER, STATUS_EXIT, STATUS_FINISHED, STATUS_FIRST, STATUS_LAST, STATUS_LEAF, STATUS_NEXT, STATUS_NONE, type StageHandler, getPrinter, getProcessPrinter, getStateTransitions, isStateTransitionEnabled, launcher, newFsmProcess, newProcess, preparePrinter, setPrinter, setProcessPrinter, setProcessTracer, setStateTracer, startFsmProcess, toStageHandlers };
|
package/dist/index.js
CHANGED
|
@@ -610,29 +610,106 @@ async function startFsmProcess(context, config, load, startEvent = "") {
|
|
|
610
610
|
}
|
|
611
611
|
|
|
612
612
|
// src/orchestrator/launcher.ts
|
|
613
|
-
|
|
613
|
+
function asArray(value, filter = (v) => v) {
|
|
614
|
+
if (value === void 0) return [];
|
|
615
|
+
const array = Array.isArray(value) ? value : [value];
|
|
616
|
+
return array.filter(Boolean).map(filter).filter(Boolean);
|
|
617
|
+
}
|
|
618
|
+
async function launcher(options) {
|
|
614
619
|
const configsManager = new ProcessConfigManager();
|
|
615
620
|
async function launch(processName, context, startEvent = "start") {
|
|
616
621
|
const config2 = configsManager.getProcessConfig(processName);
|
|
617
622
|
const load = configsManager.getHandlersLoader(processName);
|
|
618
623
|
return startFsmProcess(context, config2, load, startEvent);
|
|
619
624
|
}
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
if (
|
|
626
|
-
|
|
625
|
+
function registerProcess(configsManager2, process) {
|
|
626
|
+
if (!process || typeof process !== "object") {
|
|
627
|
+
throw new Error("Invalid process configuration: not an object");
|
|
628
|
+
}
|
|
629
|
+
const processName = process.name;
|
|
630
|
+
if (!processName || typeof processName !== "string") {
|
|
631
|
+
throw new Error("Invalid process configuration: missing or invalid name");
|
|
632
|
+
}
|
|
633
|
+
const processConfig = process.config;
|
|
634
|
+
if (processConfig && typeof processConfig !== "object") {
|
|
635
|
+
throw new Error(
|
|
636
|
+
`Invalid process configuration: config is not an object in process ${process.name}`
|
|
637
|
+
);
|
|
638
|
+
}
|
|
639
|
+
if (processConfig) {
|
|
640
|
+
configsManager2.registerConfig(processName, processConfig);
|
|
641
|
+
}
|
|
642
|
+
const processHandlers = asArray(
|
|
643
|
+
process.handlers ?? process.handler ?? process.default,
|
|
644
|
+
(v, idx) => {
|
|
645
|
+
if (typeof v === "function") return v;
|
|
646
|
+
if (typeof v === "object" && v !== null) return v;
|
|
647
|
+
throw new Error(
|
|
648
|
+
[
|
|
649
|
+
`Invalid process configuration:`,
|
|
650
|
+
`a process handler is not object nor function in process ${processName} at index ${idx}`,
|
|
651
|
+
`Recieved: ${v === null ? "null" : typeof v}`
|
|
652
|
+
].join("\n")
|
|
653
|
+
);
|
|
654
|
+
}
|
|
655
|
+
);
|
|
656
|
+
if (processHandlers.length > 0) {
|
|
657
|
+
configsManager2.registerHandlers(processName, ...processHandlers);
|
|
627
658
|
}
|
|
628
|
-
|
|
629
|
-
|
|
659
|
+
}
|
|
660
|
+
const rootContext = { "fsm:launch": launch };
|
|
661
|
+
const init = typeof options === "function" ? options : async () => options;
|
|
662
|
+
const config = await init(rootContext);
|
|
663
|
+
if (typeof config !== "object" || !config) {
|
|
664
|
+
throw new Error("Invalid launcher configuration");
|
|
665
|
+
}
|
|
666
|
+
const processes = asArray(
|
|
667
|
+
config.processes ?? config.process ?? config.default,
|
|
668
|
+
(v) => {
|
|
669
|
+
if (typeof v === "function") {
|
|
670
|
+
return {
|
|
671
|
+
name: v.name || "",
|
|
672
|
+
handler: v
|
|
673
|
+
};
|
|
674
|
+
}
|
|
675
|
+
if (typeof v !== "object") {
|
|
676
|
+
throw new Error(
|
|
677
|
+
"Invalid launcher configuration: process is not an object"
|
|
678
|
+
);
|
|
679
|
+
}
|
|
680
|
+
return v;
|
|
630
681
|
}
|
|
682
|
+
);
|
|
683
|
+
for (const process of processes) {
|
|
684
|
+
registerProcess(configsManager, process);
|
|
631
685
|
}
|
|
632
686
|
const shutdowns = [];
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
687
|
+
let startProcesses = asArray(config.start);
|
|
688
|
+
if (startProcesses.length === 0) {
|
|
689
|
+
startProcesses = processes.map((p) => p.name).filter(Boolean);
|
|
690
|
+
}
|
|
691
|
+
let initContext = (context) => context;
|
|
692
|
+
const configContext = config.context ?? config.init;
|
|
693
|
+
if (configContext) {
|
|
694
|
+
if (typeof configContext === "function") {
|
|
695
|
+
initContext = configContext;
|
|
696
|
+
} else if (typeof configContext === "object") {
|
|
697
|
+
initContext = () => ({ parent: configContext });
|
|
698
|
+
} else {
|
|
699
|
+
throw new Error("Invalid launcher configuration: context");
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
for (const processName of startProcesses) {
|
|
703
|
+
let context = {
|
|
704
|
+
parent: rootContext,
|
|
705
|
+
"fsm:name": processName
|
|
706
|
+
};
|
|
707
|
+
context = initContext(context) ?? context;
|
|
708
|
+
if (typeof context !== "object") {
|
|
709
|
+
throw new Error(
|
|
710
|
+
`Invalid launcher context for process "${processName}". Expected an object, but recieved ${typeof context}.`
|
|
711
|
+
);
|
|
712
|
+
}
|
|
636
713
|
const shutdown = await launch(processName, context);
|
|
637
714
|
shutdowns.push(shutdown);
|
|
638
715
|
}
|
package/package.json
CHANGED
|
@@ -6,31 +6,42 @@ import type { StageHandler } from "./types.ts";
|
|
|
6
6
|
export type ProcessConfig = {
|
|
7
7
|
name: string;
|
|
8
8
|
config?: FsmStateConfig;
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
}
|
|
9
|
+
} & (
|
|
10
|
+
| {
|
|
11
|
+
handler?: StageHandler;
|
|
12
|
+
}
|
|
13
|
+
| {
|
|
14
|
+
handlers?:
|
|
15
|
+
| StageHandler
|
|
16
|
+
| (
|
|
17
|
+
| StageHandler
|
|
18
|
+
| {
|
|
19
|
+
[state: string]: StageHandler | StageHandler[];
|
|
20
|
+
}
|
|
21
|
+
)[];
|
|
22
|
+
}
|
|
23
|
+
| {
|
|
24
|
+
default?:
|
|
25
|
+
| StageHandler
|
|
26
|
+
| (
|
|
27
|
+
| StageHandler
|
|
28
|
+
| {
|
|
29
|
+
[state: string]: StageHandler | StageHandler[];
|
|
30
|
+
}
|
|
31
|
+
)[];
|
|
32
|
+
}
|
|
33
|
+
);
|
|
21
34
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
) => ProcessLauncherConfig | Promise<ProcessLauncherConfig>,
|
|
33
|
-
) {
|
|
35
|
+
function asArray<T>(
|
|
36
|
+
value: T | T[] | undefined,
|
|
37
|
+
filter: (v: T, idx: number) => T | undefined = (v) => v,
|
|
38
|
+
): T[] {
|
|
39
|
+
if (value === undefined) return [];
|
|
40
|
+
const array = Array.isArray(value) ? value : [value];
|
|
41
|
+
return array.filter(Boolean).map(filter).filter(Boolean) as T[];
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export async function launcher(options: unknown) {
|
|
34
45
|
const configsManager = new ProcessConfigManager();
|
|
35
46
|
|
|
36
47
|
async function launch(
|
|
@@ -43,23 +54,105 @@ export async function launcher(
|
|
|
43
54
|
return startFsmProcess(context, config, load, startEvent);
|
|
44
55
|
}
|
|
45
56
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
57
|
+
function registerProcess(
|
|
58
|
+
configsManager: ProcessConfigManager,
|
|
59
|
+
process: Record<string, unknown>,
|
|
60
|
+
) {
|
|
61
|
+
if (!process || typeof process !== "object") {
|
|
62
|
+
throw new Error("Invalid process configuration: not an object");
|
|
63
|
+
}
|
|
64
|
+
const processName = process.name;
|
|
65
|
+
if (!processName || typeof processName !== "string") {
|
|
66
|
+
throw new Error("Invalid process configuration: missing or invalid name");
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const processConfig = process.config as FsmStateConfig | undefined;
|
|
70
|
+
if (processConfig && typeof processConfig !== "object") {
|
|
71
|
+
throw new Error(
|
|
72
|
+
`Invalid process configuration: config is not an object in process ${process.name}`,
|
|
73
|
+
);
|
|
53
74
|
}
|
|
54
|
-
if (
|
|
55
|
-
configsManager.
|
|
75
|
+
if (processConfig) {
|
|
76
|
+
configsManager.registerConfig(processName, processConfig);
|
|
56
77
|
}
|
|
78
|
+
|
|
79
|
+
const processHandlers = asArray(
|
|
80
|
+
process.handlers ?? process.handler ?? process.default,
|
|
81
|
+
(v, idx) => {
|
|
82
|
+
if (typeof v === "function") return v;
|
|
83
|
+
if (typeof v === "object" && v !== null) return v;
|
|
84
|
+
throw new Error(
|
|
85
|
+
[
|
|
86
|
+
`Invalid process configuration:`,
|
|
87
|
+
`a process handler is not object nor function in process ${processName} at index ${idx}`,
|
|
88
|
+
`Recieved: ${v === null ? "null" : typeof v}`,
|
|
89
|
+
].join("\n"),
|
|
90
|
+
);
|
|
91
|
+
},
|
|
92
|
+
);
|
|
93
|
+
if (processHandlers.length > 0) {
|
|
94
|
+
configsManager.registerHandlers(processName, ...processHandlers);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const rootContext = { "fsm:launch": launch };
|
|
99
|
+
const init = typeof options === "function" ? options : async () => options;
|
|
100
|
+
const config = await init(rootContext);
|
|
101
|
+
if (typeof config !== "object" || !config) {
|
|
102
|
+
throw new Error("Invalid launcher configuration");
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const processes = asArray(
|
|
106
|
+
config.processes ?? config.process ?? config.default,
|
|
107
|
+
(v) => {
|
|
108
|
+
if (typeof v === "function") {
|
|
109
|
+
return {
|
|
110
|
+
name: v.name || "",
|
|
111
|
+
handler: v,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
if (typeof v !== "object") {
|
|
115
|
+
throw new Error(
|
|
116
|
+
"Invalid launcher configuration: process is not an object",
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
return v;
|
|
120
|
+
},
|
|
121
|
+
);
|
|
122
|
+
for (const process of processes) {
|
|
123
|
+
registerProcess(configsManager, process);
|
|
57
124
|
}
|
|
58
125
|
|
|
59
126
|
const shutdowns: (() => Promise<void>)[] = [];
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
127
|
+
let startProcesses = asArray<string>(config.start);
|
|
128
|
+
if (startProcesses.length === 0) {
|
|
129
|
+
startProcesses = processes.map((p) => p.name).filter(Boolean) as string[];
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
let initContext: (
|
|
133
|
+
parent: Record<string, unknown>,
|
|
134
|
+
) => Record<string, unknown> = (context) => context;
|
|
135
|
+
const configContext = config.context ?? config.init;
|
|
136
|
+
if (configContext) {
|
|
137
|
+
if (typeof configContext === "function") {
|
|
138
|
+
initContext = configContext;
|
|
139
|
+
} else if (typeof configContext === "object") {
|
|
140
|
+
initContext = () => ({ parent: configContext });
|
|
141
|
+
} else {
|
|
142
|
+
throw new Error("Invalid launcher configuration: context");
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
for (const processName of startProcesses) {
|
|
146
|
+
let context: Record<string, unknown> = {
|
|
147
|
+
parent: rootContext,
|
|
148
|
+
"fsm:name": processName,
|
|
149
|
+
};
|
|
150
|
+
context = initContext(context) ?? context;
|
|
151
|
+
if (typeof context !== "object") {
|
|
152
|
+
throw new Error(
|
|
153
|
+
`Invalid launcher context for process "${processName}". Expected an object, but recieved ${typeof context}.`,
|
|
154
|
+
);
|
|
155
|
+
}
|
|
63
156
|
const shutdown = await launch(processName, context);
|
|
64
157
|
shutdowns.push(shutdown);
|
|
65
158
|
}
|