@statewalker/fsm 0.31.0 → 0.33.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 +58 -26
- package/dist/index.js +134 -155
- package/dist/index.js.map +1 -0
- package/package.json +7 -1
- package/src/{FsmProcess.ts → core/fsm-process.ts} +4 -4
- package/src/{FsmStateDescriptor.ts → core/fsm-state-descriptor.ts} +1 -1
- package/src/{FsmState.ts → core/fsm-state.ts} +3 -3
- package/src/core/index.ts +5 -0
- package/src/{newFsmProcess.ts → core/new-fsm-process.ts} +3 -3
- package/src/index.ts +6 -6
- package/src/orchestrator/index.ts +5 -2
- package/src/orchestrator/launcher.ts +77 -41
- package/src/orchestrator/{ProcessConfigManager.ts → process-config-manager.ts} +1 -1
- package/src/orchestrator/resolve-module-refs.ts +52 -0
- package/src/orchestrator/start-node-processes.ts +19 -0
- package/src/orchestrator/{startFsmProcess.ts → start-process.ts} +3 -3
- package/src/orchestrator/start-processes.ts +32 -0
- package/src/utils/handlers.ts +1 -1
- package/src/utils/printer.ts +2 -2
- package/src/utils/process.ts +3 -3
- package/src/utils/tracer.ts +2 -2
- package/src/utils/transitions.ts +4 -4
- /package/src/{FsmBaseClass.ts → core/fsm-base-class.ts} +0 -0
- /package/src/{FsmStateConfig.ts → core/fsm-state-config.ts} +0 -0
- /package/src/orchestrator/{isGenerator.ts → is-generator.ts} +0 -0
package/dist/index.d.ts
CHANGED
|
@@ -227,10 +227,17 @@ 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
|
-
}
|
|
236
|
+
} | {
|
|
237
|
+
default?: StageHandler | (StageHandler | {
|
|
238
|
+
[state: string]: StageHandler | StageHandler[];
|
|
239
|
+
})[];
|
|
240
|
+
});
|
|
234
241
|
declare function launcher(options: unknown): Promise<() => Promise<void>>;
|
|
235
242
|
|
|
236
243
|
interface IProcessConfigManager {
|
|
@@ -248,31 +255,56 @@ declare class ProcessConfigManager implements IProcessConfigManager {
|
|
|
248
255
|
registerHandlers(name: string, ...modules: unknown[]): () => void;
|
|
249
256
|
}
|
|
250
257
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
258
|
+
/**
|
|
259
|
+
* Resolve module paths relative to a base URL.
|
|
260
|
+
* This is useful for converting relative paths to absolute URLs.
|
|
261
|
+
*
|
|
262
|
+
* @param baseUrl - The base URL to resolve against.
|
|
263
|
+
* @param refs - An array of module references (relative or absolute).
|
|
264
|
+
* @returns An array of resolved absolute module URLs as strings.
|
|
265
|
+
* @example
|
|
266
|
+
* ```ts
|
|
267
|
+
* const urls = resolveModulesUrls(
|
|
268
|
+
* 'file:///home/user/project/', // base URL
|
|
269
|
+
* 'https://example.com/js/my-module.js', // absolute URL
|
|
270
|
+
* './module1.js', // relative path
|
|
271
|
+
* '../module2.js' // relative path
|
|
272
|
+
* );
|
|
273
|
+
* console.log(urls);
|
|
274
|
+
* // Output: [
|
|
275
|
+
* // 'https://example.com/js/my-module.js',
|
|
276
|
+
* // 'file:///home/user/project/module1.js',
|
|
277
|
+
* // 'file:///home/user/module2.js'
|
|
278
|
+
* // ] *
|
|
279
|
+
* ```
|
|
280
|
+
*/
|
|
281
|
+
declare function resolveModulesUrls(baseUrl: URL | string, ...refs: (URL | string)[]): string[];
|
|
282
|
+
/**
|
|
283
|
+
* Resolves module paths relative to a base URL.
|
|
284
|
+
* This is useful for converting relative paths to absolute file system paths.
|
|
285
|
+
* @param baseUrl - The base URL to resolve against
|
|
286
|
+
* @param refs - An array of module references (relative or absolute)
|
|
287
|
+
* @returns - An array of resolved absolute module paths as strings
|
|
288
|
+
* @example
|
|
289
|
+
* ```ts
|
|
290
|
+
* const paths = resolveModulesPaths('file:///home/user/project/', './module1.js', '../module2.js');
|
|
291
|
+
* console.log(paths);
|
|
292
|
+
* // Output: [
|
|
293
|
+
* // '/home/user/project/module1.js',
|
|
294
|
+
* // '/home/user/module2.js'
|
|
295
|
+
* // ]
|
|
296
|
+
* ```
|
|
297
|
+
*/
|
|
298
|
+
declare function resolveModulesPaths(baseUrl: URL | string, ...refs: (URL | string)[]): string[];
|
|
265
299
|
|
|
266
|
-
declare function
|
|
267
|
-
prefix?: string;
|
|
268
|
-
print?: (...args: any[]) => void;
|
|
269
|
-
lineNumbers?: boolean;
|
|
270
|
-
}): FsmProcess;
|
|
300
|
+
declare function startNodeProcesses(modules?: string[]): Promise<void>;
|
|
271
301
|
|
|
272
|
-
declare function
|
|
273
|
-
declare function setStateTracer(state: FsmState, print?: Printer): void;
|
|
302
|
+
declare function startFsmProcess<C = unknown>(context: C, config: FsmStateConfig, load: (state: string, event: undefined | string) => StageHandler<C>[] | Promise<StageHandler<C>[]>, startEvent?: string): Promise<() => Promise<void>>;
|
|
274
303
|
|
|
275
|
-
declare function
|
|
276
|
-
|
|
304
|
+
declare function startProcesses({ onExit, modules, init, }: {
|
|
305
|
+
onExit?: () => Promise<void> | void;
|
|
306
|
+
modules: unknown[];
|
|
307
|
+
init?: (context: Record<string, unknown>) => Promise<Record<string, unknown>> | Record<string, unknown>;
|
|
308
|
+
}): Promise<() => Promise<void>>;
|
|
277
309
|
|
|
278
|
-
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,
|
|
310
|
+
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_REGISTER_CONFIG, KEY_REGISTER_HANDLERS, KEY_STATES, KEY_TERMINATE, type Module, 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, startNodeProcesses as default, launcher, newFsmProcess, resolveModulesPaths, resolveModulesUrls, startFsmProcess, startNodeProcesses, startProcesses, toStageHandlers };
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// src/
|
|
1
|
+
// src/core/fsm-base-class.ts
|
|
2
2
|
var FsmBaseClass = class {
|
|
3
3
|
constructor() {
|
|
4
4
|
this.handlers = {};
|
|
@@ -69,11 +69,11 @@ function bindMethods(obj, ...methods) {
|
|
|
69
69
|
return obj;
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
// src/
|
|
72
|
+
// src/core/fsm-state.ts
|
|
73
73
|
var FsmState = class extends FsmBaseClass {
|
|
74
|
-
constructor(
|
|
74
|
+
constructor(process2, parent, key, descriptor) {
|
|
75
75
|
super();
|
|
76
|
-
this.process =
|
|
76
|
+
this.process = process2;
|
|
77
77
|
this.key = key;
|
|
78
78
|
this.parent = parent;
|
|
79
79
|
this.descriptor = descriptor;
|
|
@@ -117,14 +117,14 @@ var FsmState = class extends FsmBaseClass {
|
|
|
117
117
|
}
|
|
118
118
|
};
|
|
119
119
|
|
|
120
|
-
// src/
|
|
120
|
+
// src/core/fsm-state-config.ts
|
|
121
121
|
var STATE_ANY = "*";
|
|
122
122
|
var STATE_INITIAL = "";
|
|
123
123
|
var STATE_FINAL = "";
|
|
124
124
|
var EVENT_ANY = "*";
|
|
125
125
|
var EVENT_EMPTY = "";
|
|
126
126
|
|
|
127
|
-
// src/
|
|
127
|
+
// src/core/fsm-state-descriptor.ts
|
|
128
128
|
var FsmStateDescriptor = class _FsmStateDescriptor {
|
|
129
129
|
constructor() {
|
|
130
130
|
this.transitions = {};
|
|
@@ -164,7 +164,7 @@ var FsmStateDescriptor = class _FsmStateDescriptor {
|
|
|
164
164
|
}
|
|
165
165
|
};
|
|
166
166
|
|
|
167
|
-
// src/
|
|
167
|
+
// src/core/fsm-process.ts
|
|
168
168
|
var STATUS_NONE = 0;
|
|
169
169
|
var STATUS_FIRST = 1;
|
|
170
170
|
var STATUS_NEXT = 2;
|
|
@@ -307,8 +307,8 @@ var FsmProcess = class extends FsmBaseClass {
|
|
|
307
307
|
};
|
|
308
308
|
|
|
309
309
|
// src/utils/transitions.ts
|
|
310
|
-
function isStateTransitionEnabled(
|
|
311
|
-
const transitions = getStateTransitions(
|
|
310
|
+
function isStateTransitionEnabled(process2, event) {
|
|
311
|
+
const transitions = getStateTransitions(process2.state);
|
|
312
312
|
let active = false;
|
|
313
313
|
for (const [from, ev, to] of transitions) {
|
|
314
314
|
if (ev === event) {
|
|
@@ -320,7 +320,7 @@ function isStateTransitionEnabled(process, event) {
|
|
|
320
320
|
}
|
|
321
321
|
function getStateTransitions(state) {
|
|
322
322
|
const result = [];
|
|
323
|
-
|
|
323
|
+
const index = {};
|
|
324
324
|
if (state) {
|
|
325
325
|
let prevStateKey = state.key;
|
|
326
326
|
for (let parent = state?.parent; parent; parent = parent.parent) {
|
|
@@ -351,18 +351,18 @@ function getTransitionsFromDescriptor(descriptor, prevStateKey, index = {}) {
|
|
|
351
351
|
return result;
|
|
352
352
|
}
|
|
353
353
|
|
|
354
|
-
// src/
|
|
354
|
+
// src/core/new-fsm-process.ts
|
|
355
355
|
function newFsmProcess(context, config, load) {
|
|
356
356
|
let started = false;
|
|
357
357
|
let terminated = false;
|
|
358
|
-
const
|
|
358
|
+
const process2 = new FsmProcess(config);
|
|
359
359
|
async function dispatch(event) {
|
|
360
|
-
return terminated || event !== void 0 && (!started || isStateTransitionEnabled(
|
|
360
|
+
return terminated || event !== void 0 && (!started || isStateTransitionEnabled(process2, event)) ? process2.dispatch(event) : false;
|
|
361
361
|
}
|
|
362
|
-
|
|
362
|
+
process2.onStateCreate((state) => {
|
|
363
363
|
started = true;
|
|
364
364
|
state.onEnter(async () => {
|
|
365
|
-
const modules = await load(state.key,
|
|
365
|
+
const modules = await load(state.key, process2.event) ?? [];
|
|
366
366
|
for (const module of Array.isArray(modules) ? modules : [modules]) {
|
|
367
367
|
const result = await module?.(context);
|
|
368
368
|
if (isGenerator2(result)) {
|
|
@@ -387,7 +387,7 @@ function newFsmProcess(context, config, load) {
|
|
|
387
387
|
});
|
|
388
388
|
});
|
|
389
389
|
async function shutdown() {
|
|
390
|
-
await
|
|
390
|
+
await process2.shutdown();
|
|
391
391
|
terminated = true;
|
|
392
392
|
}
|
|
393
393
|
return [dispatch, shutdown];
|
|
@@ -428,7 +428,7 @@ function toStageHandlers(value, accept) {
|
|
|
428
428
|
}
|
|
429
429
|
}
|
|
430
430
|
|
|
431
|
-
// src/orchestrator/
|
|
431
|
+
// src/orchestrator/process-config-manager.ts
|
|
432
432
|
var ProcessConfigManager = class {
|
|
433
433
|
constructor() {
|
|
434
434
|
this.configs = {};
|
|
@@ -485,88 +485,23 @@ var ProcessConfigManager = class {
|
|
|
485
485
|
}
|
|
486
486
|
};
|
|
487
487
|
|
|
488
|
-
// src/
|
|
489
|
-
var KEY_PRINTER = "printer";
|
|
490
|
-
function preparePrinter(process, { prefix = "", print = console.log, lineNumbers = false }) {
|
|
491
|
-
let lineCounter = 0;
|
|
492
|
-
const shift = () => {
|
|
493
|
-
let prefix2 = "";
|
|
494
|
-
for (let s = process.state?.parent; s; s = s.parent) {
|
|
495
|
-
prefix2 += " ";
|
|
496
|
-
}
|
|
497
|
-
return prefix2;
|
|
498
|
-
};
|
|
499
|
-
const getPrefix = lineNumbers ? () => `[${++lineCounter}]${shift()}` : shift;
|
|
500
|
-
const printer = (...args) => print(prefix, getPrefix(), ...args);
|
|
501
|
-
return printer;
|
|
502
|
-
}
|
|
503
|
-
function setPrinter(state, config = {}) {
|
|
504
|
-
const printer = preparePrinter(state.process, config);
|
|
505
|
-
state.setData(KEY_PRINTER, printer);
|
|
506
|
-
}
|
|
507
|
-
function setProcessPrinter(process, config = {}) {
|
|
508
|
-
const printer = preparePrinter(process, config);
|
|
509
|
-
process.setData(KEY_PRINTER, printer);
|
|
510
|
-
}
|
|
511
|
-
function getProcessPrinter(process) {
|
|
512
|
-
return process.getData(KEY_PRINTER) || console.log;
|
|
513
|
-
}
|
|
514
|
-
function getPrinter(state) {
|
|
515
|
-
return state.getData(KEY_PRINTER, true) || getProcessPrinter(state.process);
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
// src/utils/tracer.ts
|
|
519
|
-
function setProcessTracer(process, print) {
|
|
520
|
-
return process.onStateCreate((state) => {
|
|
521
|
-
setStateTracer(state, print);
|
|
522
|
-
});
|
|
523
|
-
}
|
|
524
|
-
function setStateTracer(state, print) {
|
|
525
|
-
state.onEnter(() => {
|
|
526
|
-
const printLine = print || getPrinter(state);
|
|
527
|
-
printLine(`<${state?.key} event="${state.process.event}">`);
|
|
528
|
-
});
|
|
529
|
-
state.onExit(async () => {
|
|
530
|
-
await Promise.resolve().then(async () => {
|
|
531
|
-
const printLine = print || getPrinter(state);
|
|
532
|
-
printLine(`</${state.key}> <!-- event="${state.process.event}" -->`);
|
|
533
|
-
});
|
|
534
|
-
});
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
// src/utils/process.ts
|
|
538
|
-
function newProcess(config, {
|
|
539
|
-
prefix,
|
|
540
|
-
print,
|
|
541
|
-
lineNumbers = true
|
|
542
|
-
}) {
|
|
543
|
-
let process = new FsmProcess(config);
|
|
544
|
-
setProcessPrinter(process, {
|
|
545
|
-
prefix,
|
|
546
|
-
print,
|
|
547
|
-
lineNumbers
|
|
548
|
-
});
|
|
549
|
-
setProcessTracer(process);
|
|
550
|
-
return process;
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
// src/orchestrator/isGenerator.ts
|
|
488
|
+
// src/orchestrator/is-generator.ts
|
|
554
489
|
function isGenerator(value) {
|
|
555
490
|
return typeof value === "object" && value !== null && "next" in value && typeof value.next === "function";
|
|
556
491
|
}
|
|
557
492
|
|
|
558
|
-
// src/orchestrator/
|
|
493
|
+
// src/orchestrator/start-process.ts
|
|
559
494
|
async function startFsmProcess(context, config, load, startEvent = "") {
|
|
560
495
|
let terminated = false;
|
|
561
496
|
const ctx = context;
|
|
562
|
-
const
|
|
497
|
+
const process2 = new FsmProcess(config);
|
|
563
498
|
const statesStack = [];
|
|
564
|
-
|
|
499
|
+
process2.onStateCreate((state) => {
|
|
565
500
|
state.onEnter(async () => {
|
|
566
501
|
statesStack.push(state.key);
|
|
567
502
|
ctx[KEY_STATES] = [...statesStack];
|
|
568
|
-
ctx[KEY_EVENT] =
|
|
569
|
-
const modules = await load(state.key,
|
|
503
|
+
ctx[KEY_EVENT] = process2.event;
|
|
504
|
+
const modules = await load(state.key, process2.event) ?? [];
|
|
570
505
|
for (const module of Array.isArray(modules) ? modules : [modules]) {
|
|
571
506
|
const result = await module?.(context);
|
|
572
507
|
if (isGenerator(result)) {
|
|
@@ -591,25 +526,30 @@ async function startFsmProcess(context, config, load, startEvent = "") {
|
|
|
591
526
|
state.onExit(() => {
|
|
592
527
|
statesStack.pop();
|
|
593
528
|
ctx[KEY_STATES] = [...statesStack];
|
|
594
|
-
ctx[KEY_EVENT] =
|
|
529
|
+
ctx[KEY_EVENT] = process2.event;
|
|
595
530
|
});
|
|
596
531
|
});
|
|
597
532
|
async function terminate() {
|
|
598
533
|
terminated = true;
|
|
599
|
-
await
|
|
534
|
+
await process2.shutdown();
|
|
600
535
|
}
|
|
601
536
|
async function dispatch(event) {
|
|
602
|
-
if (event !== void 0 && isStateTransitionEnabled(
|
|
603
|
-
await
|
|
537
|
+
if (event !== void 0 && isStateTransitionEnabled(process2, event)) {
|
|
538
|
+
await process2.dispatch(event);
|
|
604
539
|
}
|
|
605
540
|
}
|
|
606
541
|
ctx[KEY_DISPATCH] = dispatch;
|
|
607
542
|
ctx[KEY_TERMINATE] = terminate;
|
|
608
|
-
await
|
|
543
|
+
await process2.dispatch(startEvent);
|
|
609
544
|
return terminate;
|
|
610
545
|
}
|
|
611
546
|
|
|
612
547
|
// src/orchestrator/launcher.ts
|
|
548
|
+
function asArray(value, filter = (v) => v) {
|
|
549
|
+
if (value === void 0) return [];
|
|
550
|
+
const array = Array.isArray(value) ? value : [value];
|
|
551
|
+
return array.filter(Boolean).map(filter).filter(Boolean);
|
|
552
|
+
}
|
|
613
553
|
async function launcher(options) {
|
|
614
554
|
const configsManager = new ProcessConfigManager();
|
|
615
555
|
async function launch(processName, context, startEvent = "start") {
|
|
@@ -617,32 +557,39 @@ async function launcher(options) {
|
|
|
617
557
|
const load = configsManager.getHandlersLoader(processName);
|
|
618
558
|
return startFsmProcess(context, config2, load, startEvent);
|
|
619
559
|
}
|
|
620
|
-
function registerProcess(configsManager2,
|
|
621
|
-
if (!
|
|
560
|
+
function registerProcess(configsManager2, process2) {
|
|
561
|
+
if (!process2 || typeof process2 !== "object") {
|
|
622
562
|
throw new Error("Invalid process configuration: not an object");
|
|
623
563
|
}
|
|
624
|
-
const processName =
|
|
564
|
+
const processName = process2.name;
|
|
625
565
|
if (!processName || typeof processName !== "string") {
|
|
626
566
|
throw new Error("Invalid process configuration: missing or invalid name");
|
|
627
567
|
}
|
|
628
|
-
const processConfig =
|
|
568
|
+
const processConfig = process2.config;
|
|
629
569
|
if (processConfig && typeof processConfig !== "object") {
|
|
630
570
|
throw new Error(
|
|
631
|
-
`Invalid process configuration: config is not an object in process ${
|
|
571
|
+
`Invalid process configuration: config is not an object in process ${process2.name}`
|
|
632
572
|
);
|
|
633
573
|
}
|
|
634
574
|
if (processConfig) {
|
|
635
|
-
configsManager2.registerConfig(
|
|
575
|
+
configsManager2.registerConfig(processName, processConfig);
|
|
636
576
|
}
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
577
|
+
const processHandlers = asArray(
|
|
578
|
+
process2.handlers ?? process2.handler ?? process2.default,
|
|
579
|
+
(v, idx) => {
|
|
580
|
+
if (typeof v === "function") return v;
|
|
581
|
+
if (typeof v === "object" && v !== null) return v;
|
|
640
582
|
throw new Error(
|
|
641
|
-
|
|
583
|
+
[
|
|
584
|
+
`Invalid process configuration:`,
|
|
585
|
+
`a process handler is not object nor function in process ${processName} at index ${idx}`,
|
|
586
|
+
`Recieved: ${v === null ? "null" : typeof v}`
|
|
587
|
+
].join("\n")
|
|
642
588
|
);
|
|
643
589
|
}
|
|
644
|
-
|
|
645
|
-
|
|
590
|
+
);
|
|
591
|
+
if (processHandlers.length > 0) {
|
|
592
|
+
configsManager2.registerHandlers(processName, ...processHandlers);
|
|
646
593
|
}
|
|
647
594
|
}
|
|
648
595
|
const rootContext = { "fsm:launch": launch };
|
|
@@ -651,16 +598,31 @@ async function launcher(options) {
|
|
|
651
598
|
if (typeof config !== "object" || !config) {
|
|
652
599
|
throw new Error("Invalid launcher configuration");
|
|
653
600
|
}
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
601
|
+
const processes = asArray(
|
|
602
|
+
config.processes ?? config.process ?? config.default,
|
|
603
|
+
(v) => {
|
|
604
|
+
if (typeof v === "function") {
|
|
605
|
+
return {
|
|
606
|
+
name: v.name || "",
|
|
607
|
+
handler: v
|
|
608
|
+
};
|
|
609
|
+
}
|
|
610
|
+
if (typeof v !== "object") {
|
|
611
|
+
throw new Error(
|
|
612
|
+
"Invalid launcher configuration: process is not an object"
|
|
613
|
+
);
|
|
614
|
+
}
|
|
615
|
+
return v;
|
|
616
|
+
}
|
|
617
|
+
);
|
|
618
|
+
for (const process2 of processes) {
|
|
619
|
+
registerProcess(configsManager, process2);
|
|
661
620
|
}
|
|
662
621
|
const shutdowns = [];
|
|
663
|
-
|
|
622
|
+
let startProcesses2 = asArray(config.start);
|
|
623
|
+
if (startProcesses2.length === 0) {
|
|
624
|
+
startProcesses2 = processes.map((p) => p.name).filter(Boolean);
|
|
625
|
+
}
|
|
664
626
|
let initContext = (context) => context;
|
|
665
627
|
const configContext = config.context ?? config.init;
|
|
666
628
|
if (configContext) {
|
|
@@ -672,7 +634,7 @@ async function launcher(options) {
|
|
|
672
634
|
throw new Error("Invalid launcher configuration: context");
|
|
673
635
|
}
|
|
674
636
|
}
|
|
675
|
-
for (const processName of
|
|
637
|
+
for (const processName of startProcesses2) {
|
|
676
638
|
let context = {
|
|
677
639
|
parent: rootContext,
|
|
678
640
|
"fsm:name": processName
|
|
@@ -692,44 +654,61 @@ async function launcher(options) {
|
|
|
692
654
|
}
|
|
693
655
|
};
|
|
694
656
|
}
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
}
|
|
657
|
+
|
|
658
|
+
// src/orchestrator/resolve-module-refs.ts
|
|
659
|
+
function resolveModulesUrls(baseUrl, ...refs) {
|
|
660
|
+
return refs.map((ref) => new URL(ref, baseUrl).href);
|
|
661
|
+
}
|
|
662
|
+
function resolveModulesPaths(baseUrl, ...refs) {
|
|
663
|
+
return refs.map((ref) => new URL(ref, baseUrl).pathname);
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
// src/orchestrator/start-processes.ts
|
|
667
|
+
async function startProcesses({
|
|
668
|
+
onExit,
|
|
669
|
+
modules,
|
|
670
|
+
init
|
|
671
|
+
}) {
|
|
672
|
+
const modulesList = [];
|
|
673
|
+
for (const module of modules) {
|
|
674
|
+
modulesList.push(
|
|
675
|
+
typeof module === "string" || module instanceof URL ? await import(String(module)) : module
|
|
676
|
+
);
|
|
677
|
+
}
|
|
678
|
+
return await launcher({
|
|
679
|
+
init,
|
|
680
|
+
processes: [
|
|
681
|
+
...modulesList,
|
|
682
|
+
// This function is called on exit at the end of the process chain
|
|
683
|
+
function Exit() {
|
|
684
|
+
return onExit;
|
|
685
|
+
}
|
|
686
|
+
]
|
|
687
|
+
});
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
// src/orchestrator/start-node-processes.ts
|
|
691
|
+
async function startNodeProcesses(modules) {
|
|
692
|
+
try {
|
|
693
|
+
if (!modules) {
|
|
694
|
+
modules = process.argv.slice(2);
|
|
695
|
+
}
|
|
696
|
+
const terminate = await startProcesses({
|
|
697
|
+
modules: resolveModulesPaths(`file://${process.cwd()}/`, ...modules),
|
|
698
|
+
onExit: () => process.exit(0)
|
|
699
|
+
});
|
|
700
|
+
process.on("SIGINT", terminate);
|
|
701
|
+
process.on("SIGTERM", terminate);
|
|
702
|
+
process.stdin.resume();
|
|
703
|
+
} catch (err) {
|
|
704
|
+
console.error("Fatal error:", err);
|
|
705
|
+
process.exit(1);
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
// src/index.ts
|
|
710
|
+
var index_default = startNodeProcesses;
|
|
711
|
+
|
|
712
|
+
export { EVENT_ANY, EVENT_EMPTY, FsmProcess, FsmState, FsmStateDescriptor, KEY_DISPATCH, KEY_EVENT, KEY_LAUNCH_PROCESS, KEY_REGISTER_CONFIG, KEY_REGISTER_HANDLERS, KEY_STATES, KEY_TERMINATE, ProcessConfigManager, STATE_ANY, STATE_FINAL, STATE_INITIAL, STATUS_ENTER, STATUS_EXIT, STATUS_FINISHED, STATUS_FIRST, STATUS_LAST, STATUS_LEAF, STATUS_NEXT, STATUS_NONE, index_default as default, launcher, newFsmProcess, resolveModulesPaths, resolveModulesUrls, startFsmProcess, startNodeProcesses, startProcesses, toStageHandlers };
|
|
713
|
+
//# sourceMappingURL=index.js.map
|
|
714
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/fsm-base-class.ts","../src/core/fsm-state.ts","../src/core/fsm-state-config.ts","../src/core/fsm-state-descriptor.ts","../src/core/fsm-process.ts","../src/utils/transitions.ts","../src/core/new-fsm-process.ts","../src/orchestrator/constants.ts","../src/orchestrator/types.ts","../src/orchestrator/process-config-manager.ts","../src/orchestrator/is-generator.ts","../src/orchestrator/start-process.ts","../src/orchestrator/launcher.ts","../src/orchestrator/resolve-module-refs.ts","../src/orchestrator/start-processes.ts","../src/orchestrator/start-node-processes.ts","../src/index.ts"],"names":["process","stateKey","eventKey","isGenerator","value","config","configsManager","startProcesses"],"mappings":";AAGO,IAAM,eAAN,MAAmB;AAAA,EAGxB,WAAA,GAAc;AAFd,IAAA,IAAA,CAAA,QAAA,GAAsC,EAAC;AACvC,IAAA,IAAA,CAAA,IAAA,GAAgC,EAAC;AAE/B,IAAA,WAAA,CAAY,IAAA,EAAM,WAAW,SAAS,CAAA;AAAA,EACxC;AAAA,EACA,OAAA,CAAW,KAAa,KAAA,EAAU;AAChC,IAAA,IAAA,CAAK,IAAA,CAAK,GAAG,CAAA,GAAI,KAAA;AACjB,IAAA,OAAO,IAAA;AAAA,EACT;AAAA,EACA,QAAW,GAAA,EAA4B;AACrC,IAAA,OAAO,IAAA,CAAK,KAAK,GAAG,CAAA;AAAA,EACtB;AAAA;AAAA;AAAA,EAIU,WAAA,CAAe,IAAA,EAAc,OAAA,EAAY,MAAA,GAAkB,IAAA,EAAM;AACzE,IAAA,IAAI,IAAA,GAAO,IAAA,CAAK,QAAA,CAAS,IAAI,CAAA;AAC7B,IAAA,IAAI,CAAC,IAAA,EAAM;AACT,MAAA,IAAA,GAAO,IAAA,CAAK,QAAA,CAAS,IAAI,CAAA,GAAI,EAAC;AAAA,IAChC;AACA,IAAA,MAAM,CAAA,GAAI,OAAA;AACV,IAAA,MAAA,GAAS,KAAK,IAAA,CAAK,CAAC,CAAA,GAAI,IAAA,CAAK,QAAQ,CAAC,CAAA;AACtC,IAAA,OAAO,MAAM,IAAA,CAAK,cAAA,CAAe,IAAA,EAAM,CAAC,CAAA;AAAA,EAC1C;AAAA,EAEU,cAAA,CAAkB,MAAc,OAAA,EAAY;AACpD,IAAA,IAAI,IAAA,GAAO,IAAA,CAAK,QAAA,CAAS,IAAI,CAAA;AAC7B,IAAA,IAAI,CAAC,IAAA,EAAM;AACX,IAAA,IAAA,GAAO,IAAA,CAAK,MAAA,CAAO,CAAC,CAAA,KAAM,MAAM,OAAO,CAAA;AACvC,IAAA,IAAI,IAAA,CAAK,SAAS,CAAA,EAAG;AACnB,MAAA,IAAA,CAAK,QAAA,CAAS,IAAI,CAAA,GAAI,IAAA;AAAA,IACxB,CAAA,MAAO;AACL,MAAA,OAAO,IAAA,CAAK,SAAS,IAAI,CAAA;AAAA,IAC3B;AAAA,EACF;AAAA,EAEA,MAAM,mBAAA,CAAoB,IAAA,EAAA,GAAiB,IAAA,EAAiB;AAC1D,IAAA,MAAM,IAAA,GAAO,IAAA,CAAK,QAAA,CAAS,IAAI,KAAK,EAAC;AACrC,IAAA,MAAM,OAAA,CAAQ,GAAA;AAAA,MACZ,IAAA,CAAK,GAAA,CAAI,OAAO,OAAA,KAAY;AAC1B,QAAA,IAAI;AACF,UAAA,MAAM,OAAA,CAAQ,GAAG,IAAI,CAAA;AAAA,QACvB,SAAS,KAAA,EAAO;AACd,UAAA,IAAA,CAAK,aAAa,KAAK,CAAA;AAAA,QACzB;AAAA,MACF,CAAC;AAAA,KACH;AAAA,EACF;AAAA,EAEA,MAAM,WAAA,CAAY,IAAA,EAAA,GAAiB,IAAA,EAAiB;AAClD,IAAA,MAAM,IAAA,GAAO,IAAA,CAAK,QAAA,CAAS,IAAI,KAAK,EAAC;AACrC,IAAA,KAAA,MAAW,WAAW,IAAA,EAAM;AAC1B,MAAA,IAAI;AACF,QAAA,MAAM,OAAA,CAAQ,GAAG,IAAI,CAAA;AAAA,MACvB,SAAS,KAAA,EAAO;AACd,QAAA,MAAM,IAAA,CAAK,aAAa,KAAK,CAAA;AAAA,MAC/B;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,aAAa,KAAA,EAAwB;AACzC,IAAA,OAAA,CAAQ,MAAM,KAAK,CAAA;AAAA,EACrB;AACF,CAAA;AAEO,SAAS,WAAA,CAAe,QAAW,OAAA,EAA8B;AACtE,EAAA,MAAM,CAAA,GAAI,GAAA;AACV,EAAA,KAAA,MAAW,cAAc,OAAA,EAAS;AAChC,IAAA,MAAM,MAAA,GAAS,EAAE,UAAU,CAAA;AAC3B,IAAA,IAAI,OAAO,WAAW,UAAA,EAAY;AAClC,IAAA,CAAA,CAAE,UAAU,CAAA,GAAI,MAAA,CAAO,IAAA,CAAK,CAAC,CAAA;AAAA,EAC/B;AACA,EAAA,OAAO,GAAA;AACT;;;ACtDO,IAAM,QAAA,GAAN,cAAuB,YAAA,CAAa;AAAA,EAMzC,WAAA,CACEA,QAAAA,EACA,MAAA,EACA,GAAA,EACA,UAAA,EACA;AACA,IAAA,KAAA,EAAM;AACN,IAAA,IAAA,CAAK,OAAA,GAAUA,QAAAA;AACf,IAAA,IAAA,CAAK,GAAA,GAAM,GAAA;AACX,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AACd,IAAA,IAAA,CAAK,UAAA,GAAa,UAAA;AAClB,IAAA,WAAA;AAAA,MACE,IAAA;AAAA,MACA,SAAA;AAAA,MACA,QAAA;AAAA,MACA,MAAA;AAAA,MACA,SAAA;AAAA,MACA,SAAA;AAAA,MACA;AAAA,KACF;AAAA,EACF;AAAA,EAEA,QAAQ,OAAA,EAA0B;AAChC,IAAA,OAAO,IAAA,CAAK,WAAA,CAAY,SAAA,EAAW,OAAA,EAAS,IAAI,CAAA;AAAA,EAClD;AAAA,EACA,OAAO,OAAA,EAA0B;AAC/B,IAAA,OAAO,IAAA,CAAK,WAAA,CAAY,QAAA,EAAU,OAAA,EAAS,KAAK,CAAA;AAAA,EAClD;AAAA,EACA,aAAa,OAAA,EAA+B;AAC1C,IAAA,OAAO,IAAA,CAAK,WAAA,CAAY,cAAA,EAAgB,OAAO,CAAA;AAAA,EACjD;AAAA,EACA,KAAK,OAAA,EAA8B;AACjC,IAAA,OAAO,IAAA,CAAK,WAAA,CAAY,MAAA,EAAQ,OAAA,EAAS,IAAI,CAAA;AAAA,EAC/C;AAAA,EACA,QAAQ,OAAA,EAA8B;AACpC,IAAA,OAAO,IAAA,CAAK,WAAA,CAAY,SAAA,EAAW,OAAA,EAAS,IAAI,CAAA;AAAA,EAClD;AAAA,EACA,OAAA,CAAW,GAAA,EAAa,SAAA,GAAqB,IAAA,EAAqB;AAChE,IAAA,OACG,IAAA,CAAK,IAAA,CAAK,GAAG,CAAA,KACb,SAAA,GAAY,KAAK,MAAA,EAAQ,OAAA,CAAW,GAAA,EAAK,SAAS,CAAA,GAAI,MAAA,CAAA;AAAA,EAE3D;AAAA,EACA,QAAW,GAAA,EAAa;AACtB,IAAA,OAAO;AAAA,MACL,CAAC,SAAA,GAAqB,IAAA,KAAS,IAAA,CAAK,OAAA,CAAW,KAAK,SAAS,CAAA;AAAA,MAC7D,CAAC,KAAA,KAAa,IAAA,CAAK,OAAA,CAAQ,KAAK,KAAK;AAAA,KACvC;AAAA,EACF;AAAA,EAEA,MAAM,aAAa,KAAA,EAAwB;AACzC,IAAA,MAAM,IAAA,CAAK,WAAA,CAAY,cAAA,EAAgB,IAAA,EAAM,KAAK,CAAA;AAClD,IAAA,MAAM,IAAA,CAAK,OAAA,CAAQ,iBAAA,CAAkB,IAAA,EAAM,KAAK,CAAA;AAAA,EAClD;AACF;;;ACnFO,IAAM,SAAA,GAAY;AAClB,IAAM,aAAA,GAAgB;AACtB,IAAM,WAAA,GAAc;AACpB,IAAM,SAAA,GAAY;AAClB,IAAM,WAAA,GAAc;;;ACGpB,IAAM,kBAAA,GAAN,MAAM,mBAAA,CAAmB;AAAA,EAAzB,WAAA,GAAA;AACL,IAAA,IAAA,CAAA,WAAA,GAAsD,EAAC;AACvD,IAAA,IAAA,CAAA,MAAA,GAA6C,EAAC;AAAA,EAAA;AAAA,EAE9C,OAAO,MAAM,MAAA,EAAwB;AACnC,IAAA,MAAM,UAAA,GAAa,IAAI,mBAAA,EAAmB;AAC1C,IAAA,KAAA,MAAW,CAAC,MAAM,KAAA,EAAO,EAAE,KAAK,MAAA,CAAO,WAAA,IAAe,EAAC,EAAG;AACxD,MAAA,IAAI,KAAA,GAAQ,UAAA,CAAW,WAAA,CAAY,IAAI,CAAA;AACvC,MAAA,IAAI,CAAC,KAAA,EAAO;AACV,QAAA,KAAA,GAAQ,UAAA,CAAW,WAAA,CAAY,IAAI,CAAA,GAAI,EAAC;AAAA,MAC1C;AACA,MAAA,KAAA,CAAM,KAAK,CAAA,GAAI,EAAA;AAAA,IACjB;AACA,IAAA,IAAI,OAAO,MAAA,EAAQ;AACjB,MAAA,KAAA,MAAW,cAAA,IAAkB,OAAO,MAAA,EAAQ;AAC1C,QAAA,UAAA,CAAW,OAAO,cAAA,CAAe,GAAG,CAAA,GAClC,mBAAA,CAAmB,MAAM,cAAc,CAAA;AAAA,MAC3C;AAAA,IACF;AACA,IAAA,OAAO,UAAA;AAAA,EACT;AAAA,EAEA,iBAAA,CAAkB,UAAkB,QAAA,EAAkB;AACpD,IAAA,MAAM,KAAA,GAAQ;AAAA,MACZ,CAAC,UAAU,QAAQ,CAAA;AAAA,MACnB,CAAC,WAAW,QAAQ,CAAA;AAAA,MACpB,CAAC,UAAU,SAAS,CAAA;AAAA,MACpB,CAAC,WAAW,SAAS;AAAA,KACvB;AACA,IAAA,IAAI,SAAA;AACJ,IAAA,KAAA,IACM,CAAA,GAAI,GAAG,GAAA,GAAM,KAAA,CAAM,QACvB,SAAA,KAAc,MAAA,IAAa,CAAA,GAAI,GAAA,EAC/B,CAAA,EAAA,EACA;AACA,MAAA,MAAM,CAACC,SAAAA,EAAUC,SAAQ,CAAA,GAAI,MAAM,CAAC,CAAA;AACpC,MAAA,MAAM,gBAAA,GAAmB,IAAA,CAAK,WAAA,CAAYD,SAAQ,CAAA;AAClD,MAAA,IAAI,CAAC,gBAAA,EAAkB;AACvB,MAAA,SAAA,GAAY,iBAAiBC,SAAQ,CAAA;AAAA,IACvC;AACA,IAAA,OAAO,SAAA,KAAc,SAAY,SAAA,GAAY,WAAA;AAAA,EAC/C;AACF;;;ACnCO,IAAM,WAAA,GAAc;AACpB,IAAM,YAAA,GAAe;AACrB,IAAM,WAAA,GAAc;AACpB,IAAM,WAAA,GAAc;AACpB,IAAM,WAAA,GAAc;AACpB,IAAM,eAAA,GAAkB;AAGxB,IAAM,eAAe,YAAA,GAAe;AACpC,IAAM,cAAc,WAAA,GAAc;AAkBlC,IAAM,UAAA,GAAN,cAAyB,YAAA,CAAa;AAAA,EAU3C,YAAY,MAAA,EAAwB;AAClC,IAAA,KAAA,EAAM;AAPR,IAAA,IAAA,CAAA,OAAA,GAAmB,KAAA;AACnB,IAAA,IAAA,CAAA,IAAA,GAAe,WAAA;AACf,IAAA,IAAA,CAAA,MAAA,GAAiB,CAAA;AAMf,IAAA,IAAA,CAAK,cAAA,GAAiB,kBAAA,CAAmB,KAAA,CAAM,MAAM,CAAA;AACrD,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AACd,IAAA,WAAA,CAAY,IAAA,EAAM,UAAA,EAAY,MAAA,EAAQ,SAAS,CAAA;AAAA,EACjD;AAAA,EAEA,MAAM,SAAS,KAAA,EAAgB;AAC7B,IAAA,OAAO,KAAK,KAAA,EAAO;AACjB,MAAA,IAAA,CAAK,KAAA,GAAQ,KAAA;AACb,MAAA,IAAA,CAAK,MAAA,GAAS,eAAA;AACd,MAAA,MAAM,IAAA,CAAK,KAAA,EAAO,WAAA,CAAY,QAAA,EAAU,KAAK,KAAK,CAAA;AAClD,MAAA,IAAA,CAAK,KAAA,GAAQ,KAAK,KAAA,CAAM,MAAA;AAAA,IAC1B;AAAA,EACF;AAAA,EAEA,MAAM,SAAS,KAAA,EAAiC;AAC9C,IAAA,IAAA,CAAK,SAAA,GAAY,KAAA;AACjB,IAAA,IAAI,CAAC,IAAA,CAAK,OAAA,IAAW,EAAE,IAAA,CAAK,SAAS,eAAA,CAAA,EAAkB;AACrD,MAAA,IAAA,CAAK,OAAA,GAAU,IAAA;AACf,MAAA,IAAI;AACF,QAAA,IAAA,CAAK,QAAQ,IAAA,CAAK,SAAA;AAClB,QAAA,IAAA,CAAK,SAAA,GAAY,KAAA,CAAA;AACjB,QAAA,OAAO,IAAA,EAAM;AAEX,UAAA,IAAI,IAAA,CAAK,SAAS,WAAA,EAAa;AAC7B,YAAA,MAAM,IAAA,CAAK,KAAA,EAAO,WAAA,CAAY,QAAA,EAAU,KAAK,KAAK,CAAA;AAAA,UACpD;AACA,UAAA,IAAI,CAAC,IAAA,CAAK,OAAA,EAAQ,EAAG;AACrB,UAAA,IAAI,IAAA,CAAK,SAAS,YAAA,EAAc;AAC9B,YAAA,MAAM,IAAA,CAAK,KAAA,EAAO,WAAA,CAAY,SAAA,EAAW,KAAK,KAAK,CAAA;AAAA,UACrD;AACA,UAAA,IAAI,IAAA,CAAK,MAAA,GAAS,IAAA,CAAK,IAAA,EAAM;AAAA,QAE/B;AAAA,MACF,CAAA,SAAE;AACA,QAAA,IAAA,CAAK,OAAA,GAAU,KAAA;AAAA,MACjB;AACA,MAAA,MAAM,YAAY,IAAA,CAAK,SAAA;AACvB,MAAA,IAAI,cAAc,MAAA,EAAW;AAC3B,QAAA,OAAO,OAAA,CAAQ,SAAQ,CAAE,IAAA,CAAK,MAAM,IAAA,CAAK,QAAA,CAAS,SAAS,CAAC,CAAA;AAAA,MAC9D;AAAA,IACF;AACA,IAAA,OAAO,EAAE,KAAK,MAAA,GAAS,eAAA,CAAA;AAAA,EACzB;AAAA,EAEA,MAAM,QAAQ,IAAA,EAA0C;AACtD,IAAA,MAAM,SAAA,GAAY,OAAO,KAAA,KAAoB;AAC3C,MAAA,MAAM,SAAA,GAA0B;AAAA,QAC9B,KAAK,KAAA,CAAM,GAAA;AAAA,QACX,MAAM;AAAC,OACT;AACA,MAAA,MAAM,MAAM,WAAA,CAAY,MAAA,EAAQ,OAAO,SAAA,CAAU,IAAA,EAAM,GAAG,IAAI,CAAA;AAC9D,MAAA,OAAO,SAAA;AAAA,IACT,CAAA;AACA,IAAA,MAAM,UAAA,GAAa,OACjB,KAAA,EACA,KAAA,GAAwB,EAAC,KACtB;AACH,MAAA,IAAI,CAAC,OAAO,OAAO,KAAA;AACnB,MAAA,KAAA,CAAM,MAAA,IAAW,MAAM,UAAA,CAAW,KAAA,CAAM,QAAQ,KAAK,CAAA;AACrD,MAAA,KAAA,CAAM,IAAA,CAAK,MAAM,SAAA,CAAU,KAAK,CAAC,CAAA;AACjC,MAAA,OAAO,KAAA;AAAA,IACT,CAAA;AACA,IAAA,MAAM,IAAA,GAAuB;AAAA,MAC3B,QAAQ,IAAA,CAAK,MAAA;AAAA,MACb,OAAO,IAAA,CAAK,KAAA;AAAA,MACZ,KAAA,EAAO,MAAM,UAAA,CAAW,IAAA,CAAK,KAAK;AAAA,KACpC;AACA,IAAA,OAAO,IAAA;AAAA,EACT;AAAA,EAEA,MAAM,OAAA,CAAQ,IAAA,EAAA,GAAyB,IAAA,EAAiB;AACtD,IAAA,IAAA,CAAK,MAAA,GAAS,KAAK,MAAA,IAAU,CAAA;AAC7B,IAAA,IAAA,CAAK,QAAQ,IAAA,CAAK,KAAA;AAClB,IAAA,IAAA,CAAK,KAAA,GAAQ,MAAA;AACb,IAAA,KAAA,IAAS,IAAI,CAAA,EAAG,CAAA,GAAI,IAAA,CAAK,KAAA,CAAM,QAAQ,CAAA,EAAA,EAAK;AAC1C,MAAA,MAAM,SAAA,GAAY,IAAA,CAAK,KAAA,CAAM,CAAC,CAAA;AAC9B,MAAA,IAAA,CAAK,QAAQ,IAAA,CAAK,KAAA,GACd,IAAA,CAAK,YAAA,CAAa,KAAK,KAAA,EAAO,SAAA,CAAU,GAAG,CAAA,GAC3C,KAAK,SAAA,CAAU,MAAA,EAAW,SAAA,CAAU,GAAA,EAAK,KAAK,cAAc,CAAA;AAChE,MAAA,MAAM,KAAK,KAAA,CAAM,WAAA;AAAA,QACf,SAAA;AAAA,QACA,IAAA,CAAK,KAAA;AAAA,QACL,SAAA,CAAU,IAAA;AAAA,QACV,GAAG;AAAA,OACL;AAAA,IACF;AACA,IAAA,OAAO,IAAA;AAAA,EACT;AAAA,EAEA,cAAc,OAAA,EAA0B;AACtC,IAAA,OAAO,IAAA,CAAK,WAAA,CAAY,eAAA,EAAiB,OAAA,EAAS,IAAI,CAAA;AAAA,EACxD;AAAA,EAEA,aACE,OAAA,EACA;AACA,IAAA,OAAO,IAAA,CAAK,WAAA,CAAY,cAAA,EAAgB,OAAO,CAAA;AAAA,EACjD;AAAA,EAEA,MAAM,iBAAA,CAAkB,KAAA,EAAiB,KAAA,EAAwB;AAC/D,IAAA,MAAM,IAAA,CAAK,WAAA,CAAY,cAAA,EAAgB,KAAA,EAAO,KAAK,CAAA;AACnD,IAAA,IAAA,CAAK,aAAa,KAAK,CAAA;AAAA,EACzB;AAAA,EAEA,SAAA,CACE,MAAA,EACA,GAAA,EACA,UAAA,EACA;AACA,IAAA,MAAM,QAAQ,IAAI,QAAA,CAAS,IAAA,EAAM,MAAA,EAAQ,KAAK,UAAU,CAAA;AACxD,IAAA,IAAA,CAAK,mBAAA,CAAoB,iBAAiB,KAAK,CAAA;AAC/C,IAAA,OAAO,KAAA;AAAA,EACT;AAAA,EAEA,YAAA,CAAa,QAA8B,YAAA,EAAkC;AAC3E,IAAA,IAAI,CAAC,MAAA,EAAQ;AACb,IAAA,MAAM,OAAA,GACJ,OAAO,UAAA,EAAY,iBAAA;AAAA,MACjB,YAAA,IAAgB,aAAA;AAAA,MAChB,KAAK,KAAA,IAAS;AAAA,KAChB,IAAK,WAAA;AACP,IAAA,IAAI,CAAC,OAAA,EAAS;AACd,IAAA,OAAO,IAAA,CAAK,YAAA,CAAa,MAAA,EAAQ,OAAO,CAAA;AAAA,EAC1C;AAAA,EAEA,YAAA,CAAa,QAA8B,OAAA,EAAiB;AAC1D,IAAA,IAAI,UAAA;AACJ,IAAA,KAAA,IACM,QAA8B,MAAA,EAClC,CAAC,cAAc,KAAA,EACf,KAAA,GAAQ,MAAM,MAAA,EACd;AACA,MAAA,UAAA,GAAa,KAAA,CAAM,UAAA,EAAY,MAAA,CAAO,OAAO,CAAA;AAAA,IAC/C;AACA,IAAA,OAAO,IAAA,CAAK,SAAA,CAAU,MAAA,EAAQ,OAAA,EAAS,UAAU,CAAA;AAAA,EACnD;AAAA,EAEA,OAAA,GAAU;AACR,IAAA,IAAI,IAAA,CAAK,MAAA,GAAS,eAAA,EAAiB,OAAO,KAAA;AAC1C,IAAA,MAAM,SAAA,GACJ,IAAA,CAAK,MAAA,KAAW,WAAA,GACZ,IAAA,CAAK,MAAA,GAAS,YAAA,GACZ,IAAA,CAAK,YAAA,CAAa,IAAA,CAAK,KAAA,EAAO,aAAa,CAAA,GAC3C,IAAA,CAAK,YAAA,CAAa,IAAA,CAAK,KAAA,EAAO,MAAA,EAAQ,IAAA,CAAK,KAAA,EAAO,GAAG,CAAA,GACvD,IAAA,CAAK,SAAA,CAAU,MAAA,EAAW,IAAA,CAAK,MAAA,CAAO,GAAA,EAAK,KAAK,cAAc,CAAA;AACpE,IAAA,IAAI,cAAc,MAAA,EAAW;AAC3B,MAAA,IAAA,CAAK,KAAA,GAAQ,SAAA;AACb,MAAA,IAAA,CAAK,MAAA,GAAS,IAAA,CAAK,MAAA,GAAS,WAAA,GAAc,WAAA,GAAc,YAAA;AAAA,IAC1D,CAAA,MAAO;AACL,MAAA,IAAI,IAAA,CAAK,SAAS,WAAA,EAAa;AAC7B,QAAA,IAAA,CAAK,KAAA,GAAQ,KAAK,KAAA,EAAO,MAAA;AACzB,QAAA,IAAA,CAAK,MAAA,GAAS,WAAA;AAAA,MAChB,CAAA,MAAO;AACL,QAAA,IAAA,CAAK,MAAA,GAAS,WAAA;AAAA,MAChB;AACA,MAAA,IAAI,CAAC,IAAA,CAAK,KAAA,EAAO,IAAA,CAAK,MAAA,GAAS,eAAA;AAAA,IACjC;AACA,IAAA,OAAO,EAAE,KAAK,MAAA,GAAS,eAAA,CAAA;AAAA,EACzB;AACF;;;AChNO,SAAS,wBAAA,CAAyBF,UAAqB,KAAA,EAAe;AAC3E,EAAA,MAAM,WAAA,GAAc,mBAAA,CAAoBA,QAAAA,CAAQ,KAAK,CAAA;AACrD,EAAA,IAAI,MAAA,GAAS,KAAA;AACb,EAAA,KAAA,MAAW,CAAC,IAAA,EAAM,EAAA,EAAI,EAAE,KAAK,WAAA,EAAa;AACxC,IAAA,IAAI,OAAO,KAAA,EAAO;AAChB,MAAA,MAAA,GAAS,IAAA;AACT,MAAA;AAAA,IACF;AAAA,EACF;AACA,EAAA,OAAO,MAAA;AACT;AAEO,SAAS,oBACd,KAAA,EAC6C;AAC7C,EAAA,MAAM,SAAsD,EAAC;AAC7D,EAAA,MAAM,QAAQ,EAAC;AACf,EAAA,IAAI,KAAA,EAAO;AACT,IAAA,IAAI,eAAe,KAAA,CAAM,GAAA;AACzB,IAAA,KAAA,IAAS,SAAS,KAAA,EAAO,MAAA,EAAQ,MAAA,EAAQ,MAAA,GAAS,OAAO,MAAA,EAAQ;AAC/D,MAAA,IAAI,CAAC,OAAO,UAAA,EAAY;AACxB,MAAA,MAAA,CAAO,IAAA;AAAA,QACL,GAAG,4BAAA,CAA6B,MAAA,CAAO,UAAA,EAAY,cAAc,KAAK;AAAA,OACxE;AACA,MAAA,YAAA,GAAe,MAAA,CAAO,GAAA;AAAA,IACxB;AAAA,EACF;AACA,EAAA,OAAO,OAAO,OAAA,EAAQ;AACxB;AAEA,SAAS,4BAAA,CACP,UAAA,EACA,YAAA,EACA,KAAA,GAAiC,EAAC,EAClC;AACA,EAAA,MAAM,SAAsD,EAAC;AAC7D,EAAA,MAAM,aAAA,GAAgB,CAAC,YAAA,EAAc,GAAG,CAAA;AACxC,EAAA,KAAA,MAAW,WAAW,aAAA,EAAe;AACnC,IAAA,MAAM,OAAA,GACJ,UAAA,CAAW,WAAA,CAAY,OAAO,CAAA;AAChC,IAAA,IAAI,OAAA,EAAS;AACX,MAAA,KAAA,MAAW,CAAC,KAAA,EAAO,MAAM,KAAK,MAAA,CAAO,OAAA,CAAQ,OAAO,CAAA,EAAG;AACrD,QAAA,IAAI,KAAA,CAAM,KAAK,CAAA,EAAG;AAClB,QAAA,IAAI,MAAA,EAAQ;AACV,UAAA,KAAA,CAAM,KAAK,CAAA,GAAI,IAAA;AAAA,QACjB;AACA,QAAA,MAAA,CAAO,IAAA,CAAK,CAAC,YAAA,EAAc,KAAA,EAAO,MAAM,CAAC,CAAA;AAAA,MAC3C;AAAA,IACF;AAAA,EACF;AACA,EAAA,OAAO,MAAA;AACT;;;AC3CO,SAAS,aAAA,CACd,OAAA,EACA,MAAA,EACA,IAAA,EAWA;AACA,EAAA,IAAI,OAAA,GAAU,KAAA;AACd,EAAA,IAAI,UAAA,GAAa,KAAA;AACjB,EAAA,MAAMA,QAAAA,GAAU,IAAI,UAAA,CAAW,MAAM,CAAA;AACrC,EAAA,eAAe,SAAS,KAAA,EAAiC;AACvD,IAAA,OAAO,UAAA,IACJ,KAAA,KAAU,MAAA,KACR,CAAC,OAAA,IAAW,wBAAA,CAAyBA,QAAAA,EAAS,KAAK,CAAA,CAAA,GACpDA,QAAAA,CAAQ,QAAA,CAAS,KAAK,CAAA,GACtB,KAAA;AAAA,EACN;AACA,EAAAA,QAAAA,CAAQ,aAAA,CAAc,CAAC,KAAA,KAAU;AAC/B,IAAA,OAAA,GAAU,IAAA;AACV,IAAA,KAAA,CAAM,QAAQ,YAAY;AACxB,MAAA,MAAM,OAAA,GAAW,MAAM,IAAA,CAAK,KAAA,CAAM,KAAKA,QAAAA,CAAQ,KAAK,KAAM,EAAC;AAC3D,MAAA,KAAA,MAAW,MAAA,IAAU,MAAM,OAAA,CAAQ,OAAO,IAAI,OAAA,GAAU,CAAC,OAAO,CAAA,EAAG;AACjE,QAAA,MAAM,MAAA,GAAS,MAAM,MAAA,GAAS,OAAO,CAAA;AACrC,QAAA,IAAIG,YAAAA,CAAY,MAAM,CAAA,EAAG;AACvB,UAAA,KAAA,CAAM,OAAO,MAAM;AACjB,YAAA,MAAA,CAAO,SAAS,MAAM,CAAA;AAAA,UACxB,CAAC,CAAA;AACD,UAAA,CAAC,YAAY;AACX,YAAA,WAAA,MAAiB,SAAS,MAAA,EAAQ;AAChC,cAAA,IAAI,UAAA,EAAY;AACd,gBAAA;AAAA,cACF;AACA,cAAA,MAAM,SAAS,KAAK,CAAA;AACpB,cAAA,IAAI,UAAA,EAAY;AACd,gBAAA;AAAA,cACF;AAAA,YACF;AAAA,UACF,CAAA,GAAG;AAAA,QACL,CAAA,MAAA,IAAW,OAAO,MAAA,KAAW,UAAA,EAAY;AACvC,UAAA,KAAA,CAAM,OAAO,MAAM,CAAA;AAAA,QACrB;AAAA,MACF;AAAA,IACF,CAAC,CAAA;AAAA,EACH,CAAC,CAAA;AACD,EAAA,eAAe,QAAA,GAA0B;AACvC,IAAA,MAAMH,SAAQ,QAAA,EAAS;AACvB,IAAA,UAAA,GAAa,IAAA;AAAA,EACf;AACA,EAAA,OAAO,CAAC,UAAU,QAAQ,CAAA;AAE1B,EAAA,SAASG,aACP,KAAA,EAGwC;AACxC,IAAA,OACE,OAAO,UAAU,QAAA,IACjB,KAAA,KAAU,QACV,MAAA,IAAU,KAAA,IACV,OAAQ,KAAA,CAA2C,IAAA,KAAS,UAAA;AAAA,EAEhE;AACF;;;ACvEO,IAAM,YAAA,GAAe;AAcrB,IAAM,aAAA,GAAgB;AAetB,IAAM,UAAA,GAAa;AAcnB,IAAM,SAAA,GAAY;AAsBlB,IAAM,mBAAA,GAAsB;AAkC5B,IAAM,qBAAA,GAAwB;AAmB9B,IAAM,kBAAA,GAAqB;;;ACxH3B,SAAS,eAAA,CACd,OACA,MAAA,EACmB;AACnB,EAAA,OAAO,MAAM,KAAK,CAAA;AAElB,EAAA,SAAS,MAAM,GAAA,EAAiC;AAC9C,IAAA,IAAI,CAAC,GAAA,EAAK;AACR,MAAA,OAAO,EAAC;AAAA,IACV;AACA,IAAA,IAAI,OAAO,QAAQ,UAAA,EAAY;AAC7B,MAAA,OAAO,CAAC,GAAG,CAAA;AAAA,IACb;AACA,IAAA,IAAI,OAAO,QAAQ,QAAA,EAAU;AAC3B,MAAA,OAAO,EAAC;AAAA,IACV;AACA,IAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,GAAG,CAAA,EAAG;AACtB,MAAA,OAAO,GAAA,CAAI,QAAQ,KAAK,CAAA;AAAA,IAC1B;AACA,IAAA,MAAM,YAAA,GAAe,GAAA;AACrB,IAAA,OAAO,MAAA,CAAO,QAAQ,YAAY,CAAA,CAAE,QAAQ,CAAC,CAAC,GAAA,EAAKC,MAAK,CAAA,KAAM;AAC5D,MAAA,OAAO,OAAO,GAAA,EAAKA,MAAK,IAAI,KAAA,CAAMA,MAAK,IAAI,EAAC;AAAA,IAC9C,CAAC,CAAA;AAAA,EACH;AACF;;;ACrBO,IAAM,uBAAN,MAA4D;AAAA,EAA5D,WAAA,GAAA;AACL,IAAA,IAAA,CAAU,UAA0C,EAAC;AACrD,IAAA,IAAA,CAAU,WAAsC,EAAC;AAAA,EAAA;AAAA,EAEjD,iBAAiB,WAAA,EAAqC;AACpD,IAAA,OAAO,KAAK,OAAA,CAAQ,WAAW,CAAA,IAAK,EAAE,KAAK,MAAA,EAAO;AAAA,EACpD;AAAA,EAEA,kBACE,WAAA,EACiE;AACjE,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,gBAAA,CAAiB,WAAW,CAAA;AAChD,IAAA,OAAO,CAAC,QAAA,KAAqB;AAC3B,MAAA,MAAM,cAAwB,EAAC;AAC/B,MAAA,IAAI,QAAA,KAAa,OAAO,GAAA,EAAK;AAC3B,QAAA,WAAA,CAAY,KAAK,SAAS,CAAA;AAAA,MAC5B;AACA,MAAA,WAAA,CAAY,IAAA;AAAA,QACV,QAAA;AAAA,QACA,GAAG,QAAQ,CAAA,UAAA,CAAA;AAAA,QACX,GAAG,QAAQ,CAAA,eAAA,CAAA;AAAA,QACX,GAAG,QAAQ,CAAA,IAAA,CAAA;AAAA,QACX,GAAG,QAAQ,CAAA,SAAA,CAAA;AAAA,QACX,GAAG,QAAQ,CAAA,OAAA,CAAA;AAAA,QACX,GAAG,QAAQ,CAAA,YAAA,CAAA;AAAA,QACX,GAAG,QAAQ,CAAA,IAAA,CAAA;AAAA,QACX,GAAG,QAAQ,CAAA,SAAA;AAAA,OACb;AACA,MAAA,MAAM,OAAA,GAAU,IAAI,GAAA,CAAI,WAAW,CAAA;AACnC,MAAA,MAAM,eAAA,GAAkB,IAAA,CAAK,QAAA,CAAS,WAAW,KAAK,EAAC;AACvD,MAAA,MAAM,QAAA,GAAW,eAAA;AAAA,QAAgB,eAAA;AAAA,QAAiB,CAAC,GAAA,KACjD,OAAA,CAAQ,GAAA,CAAI,GAAG;AAAA,OACjB;AACA,MAAA,OAAO,QAAA;AAAA,IACT,CAAA;AAAA,EACF;AAAA,EAEA,cAAA,CAAe,MAAc,MAAA,EAAoC;AAC/D,IAAA,IAAA,CAAK,OAAA,CAAQ,IAAI,CAAA,GAAI,MAAA;AACrB,IAAA,OAAO,MAAM;AACX,MAAA,OAAO,IAAA,CAAK,QAAQ,IAAI,CAAA;AAAA,IAC1B,CAAA;AAAA,EACF;AAAA,EAEA,gBAAA,CAAiB,SAAiB,OAAA,EAAgC;AAChE,IAAA,IAAI,IAAA,GAAkB,IAAA,CAAK,QAAA,CAAS,IAAI,CAAA;AACxC,IAAA,IAAI,CAAC,IAAA,EAAM;AACT,MAAA,IAAA,GAAO,IAAA,CAAK,QAAA,CAAS,IAAI,CAAA,GAAI,EAAC;AAAA,IAChC;AACA,IAAA,IAAA,CAAK,KAAK,OAAO,CAAA;AACjB,IAAA,OAAO,MAAM;AACX,MAAA,IAAA,GAAO,IAAA,CAAK,MAAA,CAAO,CAAC,CAAA,KAAM,MAAM,OAAO,CAAA;AACvC,MAAA,IAAI,IAAA,CAAK,WAAW,CAAA,EAAG;AACrB,QAAA,OAAO,IAAA,CAAK,SAAS,IAAI,CAAA;AAAA,MAC3B;AAAA,IACF,CAAA;AAAA,EACF;AACF;;;ACrEO,SAAS,YACd,KAAA,EAGwC;AACxC,EAAA,OACE,OAAO,UAAU,QAAA,IACjB,KAAA,KAAU,QACV,MAAA,IAAU,KAAA,IACV,OAAQ,KAAA,CAA2C,IAAA,KAAS,UAAA;AAEhE;;;ACCA,eAAsB,eAAA,CACpB,OAAA,EACA,MAAA,EACA,IAAA,EAIA,aAAa,EAAA,EACiB;AAC9B,EAAA,IAAI,UAAA,GAAa,KAAA;AACjB,EAAA,MAAM,GAAA,GAAM,OAAA;AACZ,EAAA,MAAMJ,QAAAA,GAAU,IAAI,UAAA,CAAW,MAAM,CAAA;AACrC,EAAA,MAAM,cAAwB,EAAC;AAE/B,EAAAA,QAAAA,CAAQ,aAAA,CAAc,CAAC,KAAA,KAAU;AAC/B,IAAA,KAAA,CAAM,QAAQ,YAAY;AACxB,MAAA,WAAA,CAAY,IAAA,CAAK,MAAM,GAAG,CAAA;AAC1B,MAAA,GAAA,CAAI,UAAU,CAAA,GAAI,CAAC,GAAG,WAAW,CAAA;AACjC,MAAA,GAAA,CAAI,SAAS,IAAIA,QAAAA,CAAQ,KAAA;AACzB,MAAA,MAAM,OAAA,GAAW,MAAM,IAAA,CAAK,KAAA,CAAM,KAAKA,QAAAA,CAAQ,KAAK,KAAM,EAAC;AAC3D,MAAA,KAAA,MAAW,MAAA,IAAU,MAAM,OAAA,CAAQ,OAAO,IAAI,OAAA,GAAU,CAAC,OAAO,CAAA,EAAG;AACjE,QAAA,MAAM,MAAA,GAAS,MAAM,MAAA,GAAS,OAAO,CAAA;AACrC,QAAA,IAAI,WAAA,CAAY,MAAM,CAAA,EAAG;AACvB,UAAA,IAAI,WAAA,GAAc,KAAA;AAClB,UAAA,KAAA,CAAM,OAAO,MAAM;AACjB,YAAA,WAAA,GAAc,IAAA;AACd,YAAA,MAAA,CAAO,SAAS,MAAM,CAAA;AAAA,UACxB,CAAC,CAAA;AACD,UAAA,CAAC,YAAY;AACX,YAAA,WAAA,MAAiB,SAAS,MAAA,EAAQ;AAChC,cAAA,IAAI,eAAe,UAAA,EAAY;AAC7B,gBAAA;AAAA,cACF;AACA,cAAA,MAAM,SAAS,KAAK,CAAA;AAAA,YACtB;AAAA,UACF,CAAA,GAAG;AAAA,QACL,CAAA,MAAA,IAAW,OAAO,MAAA,KAAW,UAAA,EAAY;AACvC,UAAA,KAAA,CAAM,OAAO,MAAM,CAAA;AAAA,QACrB;AAAA,MACF;AAAA,IACF,CAAC,CAAA;AACD,IAAA,KAAA,CAAM,OAAO,MAAM;AACjB,MAAA,WAAA,CAAY,GAAA,EAAI;AAChB,MAAA,GAAA,CAAI,UAAU,CAAA,GAAI,CAAC,GAAG,WAAW,CAAA;AACjC,MAAA,GAAA,CAAI,SAAS,IAAIA,QAAAA,CAAQ,KAAA;AAAA,IAC3B,CAAC,CAAA;AAAA,EACH,CAAC,CAAA;AACD,EAAA,eAAe,SAAA,GAA2B;AACxC,IAAA,UAAA,GAAa,IAAA;AACb,IAAA,MAAMA,SAAQ,QAAA,EAAS;AAAA,EACzB;AACA,EAAA,eAAe,SAAS,KAAA,EAA8B;AACpD,IAAA,IAAI,KAAA,KAAU,MAAA,IAAa,wBAAA,CAAyBA,QAAAA,EAAS,KAAK,CAAA,EAAG;AACnE,MAAA,MAAMA,QAAAA,CAAQ,SAAS,KAAK,CAAA;AAAA,IAC9B;AAAA,EACF;AACA,EAAA,GAAA,CAAI,YAAY,CAAA,GAAI,QAAA;AACpB,EAAA,GAAA,CAAI,aAAa,CAAA,GAAI,SAAA;AACrB,EAAA,MAAMA,QAAAA,CAAQ,SAAS,UAAU,CAAA;AACjC,EAAA,OAAO,SAAA;AACT;;;ACtCA,SAAS,OAAA,CACP,KAAA,EACA,MAAA,GAA+C,CAAC,MAAM,CAAA,EACjD;AACL,EAAA,IAAI,KAAA,KAAU,MAAA,EAAW,OAAO,EAAC;AACjC,EAAA,MAAM,QAAQ,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,GAAI,KAAA,GAAQ,CAAC,KAAK,CAAA;AACnD,EAAA,OAAO,KAAA,CAAM,OAAO,OAAO,CAAA,CAAE,IAAI,MAAM,CAAA,CAAE,OAAO,OAAO,CAAA;AACzD;AAEA,eAAsB,SAAS,OAAA,EAAkB;AAC/C,EAAA,MAAM,cAAA,GAAiB,IAAI,oBAAA,EAAqB;AAEhD,EAAA,eAAe,MAAA,CACb,WAAA,EACA,OAAA,EACA,UAAA,GAAqB,OAAA,EACrB;AACA,IAAA,MAAMK,OAAAA,GAAS,cAAA,CAAe,gBAAA,CAAiB,WAAW,CAAA;AAC1D,IAAA,MAAM,IAAA,GAAO,cAAA,CAAe,iBAAA,CAAkB,WAAW,CAAA;AACzD,IAAA,OAAO,eAAA,CAAgB,OAAA,EAASA,OAAAA,EAAQ,IAAA,EAAM,UAAU,CAAA;AAAA,EAC1D;AAEA,EAAA,SAAS,eAAA,CACPC,iBACAN,QAAAA,EACA;AACA,IAAA,IAAI,CAACA,QAAAA,IAAW,OAAOA,QAAAA,KAAY,QAAA,EAAU;AAC3C,MAAA,MAAM,IAAI,MAAM,8CAA8C,CAAA;AAAA,IAChE;AACA,IAAA,MAAM,cAAcA,QAAAA,CAAQ,IAAA;AAC5B,IAAA,IAAI,CAAC,WAAA,IAAe,OAAO,WAAA,KAAgB,QAAA,EAAU;AACnD,MAAA,MAAM,IAAI,MAAM,wDAAwD,CAAA;AAAA,IAC1E;AAEA,IAAA,MAAM,gBAAgBA,QAAAA,CAAQ,MAAA;AAC9B,IAAA,IAAI,aAAA,IAAiB,OAAO,aAAA,KAAkB,QAAA,EAAU;AACtD,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,CAAA,kEAAA,EAAqEA,SAAQ,IAAI,CAAA;AAAA,OACnF;AAAA,IACF;AACA,IAAA,IAAI,aAAA,EAAe;AACjB,MAAAM,eAAAA,CAAe,cAAA,CAAe,WAAA,EAAa,aAAa,CAAA;AAAA,IAC1D;AAEA,IAAA,MAAM,eAAA,GAAkB,OAAA;AAAA,MACtBN,QAAAA,CAAQ,QAAA,IAAYA,QAAAA,CAAQ,OAAA,IAAWA,QAAAA,CAAQ,OAAA;AAAA,MAC/C,CAAC,GAAG,GAAA,KAAQ;AACV,QAAA,IAAI,OAAO,CAAA,KAAM,UAAA,EAAY,OAAO,CAAA;AACpC,QAAA,IAAI,OAAO,CAAA,KAAM,QAAA,IAAY,CAAA,KAAM,MAAM,OAAO,CAAA;AAChD,QAAA,MAAM,IAAI,KAAA;AAAA,UACR;AAAA,YACE,CAAA,8BAAA,CAAA;AAAA,YACA,CAAA,wDAAA,EAA2D,WAAW,CAAA,UAAA,EAAa,GAAG,CAAA,CAAA;AAAA,YACtF,CAAA,UAAA,EAAa,CAAA,KAAM,IAAA,GAAO,MAAA,GAAS,OAAO,CAAC,CAAA;AAAA,WAC7C,CAAE,KAAK,IAAI;AAAA,SACb;AAAA,MACF;AAAA,KACF;AACA,IAAA,IAAI,eAAA,CAAgB,SAAS,CAAA,EAAG;AAC9B,MAAAM,eAAAA,CAAe,gBAAA,CAAiB,WAAA,EAAa,GAAG,eAAe,CAAA;AAAA,IACjE;AAAA,EACF;AAEA,EAAA,MAAM,WAAA,GAAc,EAAE,YAAA,EAAc,MAAA,EAAO;AAC3C,EAAA,MAAM,IAAA,GAAO,OAAO,OAAA,KAAY,UAAA,GAAa,UAAU,YAAY,OAAA;AACnE,EAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,WAAW,CAAA;AACrC,EAAA,IAAI,OAAO,MAAA,KAAW,QAAA,IAAY,CAAC,MAAA,EAAQ;AACzC,IAAA,MAAM,IAAI,MAAM,gCAAgC,CAAA;AAAA,EAClD;AAEA,EAAA,MAAM,SAAA,GAAY,OAAA;AAAA,IAChB,MAAA,CAAO,SAAA,IAAa,MAAA,CAAO,OAAA,IAAW,MAAA,CAAO,OAAA;AAAA,IAC7C,CAAC,CAAA,KAAM;AACL,MAAA,IAAI,OAAO,MAAM,UAAA,EAAY;AAC3B,QAAA,OAAO;AAAA,UACL,IAAA,EAAM,EAAE,IAAA,IAAQ,EAAA;AAAA,UAChB,OAAA,EAAS;AAAA,SACX;AAAA,MACF;AACA,MAAA,IAAI,OAAO,MAAM,QAAA,EAAU;AACzB,QAAA,MAAM,IAAI,KAAA;AAAA,UACR;AAAA,SACF;AAAA,MACF;AACA,MAAA,OAAO,CAAA;AAAA,IACT;AAAA,GACF;AACA,EAAA,KAAA,MAAWN,YAAW,SAAA,EAAW;AAC/B,IAAA,eAAA,CAAgB,gBAAgBA,QAAO,CAAA;AAAA,EACzC;AAEA,EAAA,MAAM,YAAqC,EAAC;AAC5C,EAAA,IAAIO,eAAAA,GAAiB,OAAA,CAAgB,MAAA,CAAO,KAAK,CAAA;AACjD,EAAA,IAAIA,eAAAA,CAAe,WAAW,CAAA,EAAG;AAC/B,IAAAA,eAAAA,GAAiB,UAAU,GAAA,CAAI,CAAC,MAAM,CAAA,CAAE,IAAI,CAAA,CAAE,MAAA,CAAO,OAAO,CAAA;AAAA,EAC9D;AAEA,EAAA,IAAI,WAAA,GAE2B,CAAC,OAAA,KAAY,OAAA;AAC5C,EAAA,MAAM,aAAA,GAAgB,MAAA,CAAO,OAAA,IAAW,MAAA,CAAO,IAAA;AAC/C,EAAA,IAAI,aAAA,EAAe;AACjB,IAAA,IAAI,OAAO,kBAAkB,UAAA,EAAY;AACvC,MAAA,WAAA,GAAc,aAAA;AAAA,IAChB,CAAA,MAAA,IAAW,OAAO,aAAA,KAAkB,QAAA,EAAU;AAC5C,MAAA,WAAA,GAAc,OAAO,EAAE,MAAA,EAAQ,aAAA,EAAc,CAAA;AAAA,IAC/C,CAAA,MAAO;AACL,MAAA,MAAM,IAAI,MAAM,yCAAyC,CAAA;AAAA,IAC3D;AAAA,EACF;AACA,EAAA,KAAA,MAAW,eAAeA,eAAAA,EAAgB;AACxC,IAAA,IAAI,OAAA,GAAmC;AAAA,MACrC,MAAA,EAAQ,WAAA;AAAA,MACR,UAAA,EAAY;AAAA,KACd;AACA,IAAA,OAAA,GAAU,WAAA,CAAY,OAAO,CAAA,IAAK,OAAA;AAClC,IAAA,IAAI,OAAO,YAAY,QAAA,EAAU;AAC/B,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,CAAA,sCAAA,EAAyC,WAAW,CAAA,oCAAA,EAAuC,OAAO,OAAO,CAAA,CAAA;AAAA,OAC3G;AAAA,IACF;AACA,IAAA,MAAM,QAAA,GAAW,MAAM,MAAA,CAAO,WAAA,EAAa,OAAO,CAAA;AAClD,IAAA,SAAA,CAAU,KAAK,QAAQ,CAAA;AAAA,EACzB;AAEA,EAAA,OAAO,YAAY;AACjB,IAAA,KAAA,MAAW,YAAY,SAAA,EAAW;AAChC,MAAA,MAAM,QAAA,EAAS;AAAA,IACjB;AAAA,EACF,CAAA;AACF;;;AC7IO,SAAS,kBAAA,CACd,YACG,IAAA,EACO;AACV,EAAA,OAAO,IAAA,CAAK,IAAI,CAAC,GAAA,KAAQ,IAAI,GAAA,CAAI,GAAA,EAAK,OAAO,CAAA,CAAE,IAAI,CAAA;AACrD;AAkBO,SAAS,mBAAA,CACd,YACG,IAAA,EACO;AACV,EAAA,OAAO,IAAA,CAAK,IAAI,CAAC,GAAA,KAAQ,IAAI,GAAA,CAAI,GAAA,EAAK,OAAO,CAAA,CAAE,QAAQ,CAAA;AACzD;;;ACjDA,eAAsB,cAAA,CAAe;AAAA,EACnC,MAAA;AAAA,EACA,OAAA;AAAA,EACA;AACF,CAAA,EAMG;AACD,EAAA,MAAM,cAAyB,EAAC;AAChC,EAAA,KAAA,MAAW,UAAU,OAAA,EAAS;AAC5B,IAAA,WAAA,CAAY,IAAA;AAAA,MACV,OAAO,WAAW,QAAA,IAAY,MAAA,YAAkB,MAC5C,MAAM,OAAO,MAAA,CAAO,MAAM,CAAA,CAAA,GAC1B;AAAA,KACN;AAAA,EACF;AACA,EAAA,OAAO,MAAM,QAAA,CAAS;AAAA,IACpB,IAAA;AAAA,IACA,SAAA,EAAW;AAAA,MACT,GAAG,WAAA;AAAA;AAAA,MAEH,SAAS,IAAA,GAAO;AACd,QAAA,OAAO,MAAA;AAAA,MACT;AAAA;AACF,GACD,CAAA;AACH;;;AC7BA,eAAsB,mBAAmB,OAAA,EAAmC;AAC1E,EAAA,IAAI;AACF,IAAA,IAAI,CAAC,OAAA,EAAS;AACZ,MAAA,OAAA,GAAU,OAAA,CAAQ,IAAA,CAAK,KAAA,CAAM,CAAC,CAAA;AAAA,IAChC;AACA,IAAA,MAAM,SAAA,GAAY,MAAM,cAAA,CAAe;AAAA,MACrC,OAAA,EAAS,oBAAoB,CAAA,OAAA,EAAU,OAAA,CAAQ,KAAK,CAAA,CAAA,CAAA,EAAK,GAAG,OAAO,CAAA;AAAA,MACnE,MAAA,EAAQ,MAAM,OAAA,CAAQ,IAAA,CAAK,CAAC;AAAA,KAC7B,CAAA;AACD,IAAA,OAAA,CAAQ,EAAA,CAAG,UAAU,SAAS,CAAA;AAC9B,IAAA,OAAA,CAAQ,EAAA,CAAG,WAAW,SAAS,CAAA;AAC/B,IAAA,OAAA,CAAQ,MAAM,MAAA,EAAO;AAAA,EACvB,SAAS,GAAA,EAAK;AACZ,IAAA,OAAA,CAAQ,KAAA,CAAM,gBAAgB,GAAG,CAAA;AACjC,IAAA,OAAA,CAAQ,KAAK,CAAC,CAAA;AAAA,EAChB;AACF;;;ACZA,IAAO,aAAA,GAAQ","file":"index.js","sourcesContent":["type Handler<P extends unknown[] = unknown[], R = unknown> = (...args: P) => R; // Function;\n// type Handler = Function;\n\nexport class FsmBaseClass {\n handlers: Record<string, Handler[]> = {};\n data: Record<string, unknown> = {};\n constructor() {\n bindMethods(this, \"setData\", \"getData\");\n }\n setData<T>(key: string, value: T) {\n this.data[key] = value;\n return this;\n }\n getData<T>(key: string): T | undefined {\n return this.data[key] as T;\n }\n\n // ----------------------------------------------\n // internal methods\n protected _addHandler<T>(type: string, handler: T, direct: boolean = true) {\n let list = this.handlers[type];\n if (!list) {\n list = this.handlers[type] = [];\n }\n const h = handler as Handler;\n direct ? list.push(h) : list.unshift(h);\n return () => this._removeHandler(type, h);\n }\n\n protected _removeHandler<T>(type: string, handler: T) {\n let list = this.handlers[type];\n if (!list) return;\n list = list.filter((h) => h !== handler);\n if (list.length > 0) {\n this.handlers[type] = list;\n } else {\n delete this.handlers[type];\n }\n }\n\n async _runHandlerParallel(type: string, ...args: unknown[]) {\n const list = this.handlers[type] || [];\n await Promise.all(\n list.map(async (handler) => {\n try {\n await handler(...args);\n } catch (error) {\n this._handleError(error);\n }\n }),\n );\n }\n\n async _runHandler(type: string, ...args: unknown[]) {\n const list = this.handlers[type] || [];\n for (const handler of list) {\n try {\n await handler(...args);\n } catch (error) {\n await this._handleError(error);\n }\n }\n }\n\n async _handleError(error: Error | unknown) {\n console.error(error);\n }\n}\n\nexport function bindMethods<T>(obj: T, ...methods: (string | symbol)[]) {\n const o = obj as Record<string | symbol, unknown>;\n for (const methodName of methods) {\n const method = o[methodName];\n if (typeof method !== \"function\") continue;\n o[methodName] = method.bind(o);\n }\n return obj;\n}\n","import { bindMethods, FsmBaseClass } from \"./fsm-base-class.ts\";\nimport type { FsmProcess } from \"./fsm-process.ts\";\nimport type { FsmStateDescriptor } from \"./fsm-state-descriptor.ts\";\n\nexport type FsmStateDump = Record<string, unknown> & {\n key: string;\n data: Record<string, unknown>;\n};\nexport type FsmStateHandler = (\n state: FsmState,\n ...args: unknown[]\n) => void | Promise<void>;\n\nexport type FsmStateDumpHandler = (\n state: FsmState,\n dump: FsmStateDump,\n) => void | Promise<void>;\n\nexport type FsmStateErrorHandler = (\n state: FsmState,\n error: unknown,\n) => void | Promise<void>;\n\nexport class FsmState extends FsmBaseClass {\n process: FsmProcess;\n key: string;\n parent?: FsmState;\n descriptor?: FsmStateDescriptor;\n\n constructor(\n process: FsmProcess,\n parent: FsmState | undefined,\n key: string,\n descriptor?: FsmStateDescriptor,\n ) {\n super();\n this.process = process;\n this.key = key;\n this.parent = parent;\n this.descriptor = descriptor;\n bindMethods(\n this,\n \"onEnter\",\n \"onExit\",\n \"dump\",\n \"restore\",\n \"useData\",\n \"onStateError\",\n );\n }\n\n onEnter(handler: FsmStateHandler) {\n return this._addHandler(\"onEnter\", handler, true);\n }\n onExit(handler: FsmStateHandler) {\n return this._addHandler(\"onExit\", handler, false);\n }\n onStateError(handler: FsmStateErrorHandler) {\n return this._addHandler(\"onStateError\", handler);\n }\n dump(handler: FsmStateDumpHandler) {\n return this._addHandler(\"dump\", handler, true);\n }\n restore(handler: FsmStateDumpHandler) {\n return this._addHandler(\"restore\", handler, true);\n }\n getData<T>(key: string, recursive: boolean = true): T | undefined {\n return (\n (this.data[key] as T) ??\n (recursive ? this.parent?.getData<T>(key, recursive) : undefined)\n );\n }\n useData<T>(key: string) {\n return [\n (recursive: boolean = true) => this.getData<T>(key, recursive),\n (value: T) => this.setData(key, value),\n ];\n }\n\n async _handleError(error: Error | unknown) {\n await this._runHandler(\"onStateError\", this, error);\n await this.process._handleStateError(this, error);\n }\n}\n","export const STATE_ANY = \"*\";\nexport const STATE_INITIAL = \"\";\nexport const STATE_FINAL = \"\";\nexport const EVENT_ANY = \"*\";\nexport const EVENT_EMPTY = \"\";\n\nexport type FsmStateKey = string;\nexport type FsmEventKey = string;\nexport type FsmStateConfig = {\n key: FsmStateKey;\n transitions?: [from: FsmStateKey, event: FsmEventKey, to: FsmStateKey][];\n states?: FsmStateConfig[];\n} & Record<string, unknown>;\n","import {\n EVENT_ANY,\n type FsmStateConfig,\n STATE_ANY,\n STATE_FINAL,\n} from \"./fsm-state-config.ts\";\n\nexport class FsmStateDescriptor {\n transitions: Record<string, Record<string, string>> = {};\n states: Record<string, FsmStateDescriptor> = {};\n\n static build(config: FsmStateConfig) {\n const descriptor = new FsmStateDescriptor();\n for (const [from, event, to] of config.transitions || []) {\n let index = descriptor.transitions[from];\n if (!index) {\n index = descriptor.transitions[from] = {};\n }\n index[event] = to;\n }\n if (config.states) {\n for (const substateConfig of config.states) {\n descriptor.states[substateConfig.key] =\n FsmStateDescriptor.build(substateConfig);\n }\n }\n return descriptor;\n }\n\n getTargetStateKey(stateKey: string, eventKey: string) {\n const pairs = [\n [stateKey, eventKey],\n [STATE_ANY, eventKey],\n [stateKey, EVENT_ANY],\n [STATE_ANY, EVENT_ANY],\n ];\n let targetKey: string | undefined;\n for (\n let i = 0, len = pairs.length;\n targetKey === undefined && i < len;\n i++\n ) {\n const [stateKey, eventKey] = pairs[i];\n const stateTransitions = this.transitions[stateKey];\n if (!stateTransitions) continue;\n targetKey = stateTransitions[eventKey];\n }\n return targetKey !== undefined ? targetKey : STATE_FINAL;\n }\n}\n","import { bindMethods, FsmBaseClass } from \"./fsm-base-class.ts\";\nimport {\n FsmState,\n type FsmStateDump,\n type FsmStateHandler,\n} from \"./fsm-state.ts\";\nimport {\n EVENT_EMPTY,\n type FsmStateConfig,\n STATE_FINAL,\n STATE_INITIAL,\n} from \"./fsm-state-config.ts\";\nimport { FsmStateDescriptor } from \"./fsm-state-descriptor.ts\";\n\nexport const STATUS_NONE = 0;\nexport const STATUS_FIRST = 1;\nexport const STATUS_NEXT = 2;\nexport const STATUS_LEAF = 4;\nexport const STATUS_LAST = 8;\nexport const STATUS_FINISHED = 16;\n\n//\nexport const STATUS_ENTER = STATUS_FIRST | STATUS_NEXT;\nexport const STATUS_EXIT = STATUS_LEAF | STATUS_LAST;\n\nexport type FsmProcessHandler = (\n process: FsmProcess,\n ...args: unknown[]\n) => void | Promise<void>;\n\nexport type FsmProcessDump = Record<string, unknown> & {\n status: number;\n event?: string;\n stack: FsmStateDump[];\n};\n\nexport type FsmProcessDumpHandler = (\n process: FsmProcess,\n dump: FsmProcessDump,\n) => void | Promise<void>;\n\nexport class FsmProcess extends FsmBaseClass {\n state?: FsmState;\n event?: string;\n nextEvent?: string;\n running: boolean = false;\n mask: number = STATUS_LEAF;\n status: number = 0;\n config: FsmStateConfig;\n rootDescriptor: FsmStateDescriptor;\n\n constructor(config: FsmStateConfig) {\n super();\n this.rootDescriptor = FsmStateDescriptor.build(config);\n this.config = config;\n bindMethods(this, \"dispatch\", \"dump\", \"restore\");\n }\n\n async shutdown(event?: string) {\n while (this.state) {\n this.event = event;\n this.status = STATUS_FINISHED;\n await this.state?._runHandler(\"onExit\", this.state);\n this.state = this.state.parent;\n }\n }\n\n async dispatch(event: string): Promise<boolean> {\n this.nextEvent = event;\n if (!this.running && !(this.status & STATUS_FINISHED)) {\n this.running = true;\n try {\n this.event = this.nextEvent;\n this.nextEvent = undefined;\n while (true) {\n // ---\n if (this.status & STATUS_EXIT) {\n await this.state?._runHandler(\"onExit\", this.state);\n }\n if (!this._update()) break;\n if (this.status & STATUS_ENTER) {\n await this.state?._runHandler(\"onEnter\", this.state);\n }\n if (this.status & this.mask) break;\n // ---\n }\n } finally {\n this.running = false;\n }\n const nextEvent = this.nextEvent;\n if (nextEvent !== undefined) {\n return Promise.resolve().then(() => this.dispatch(nextEvent));\n }\n }\n return !(this.status & STATUS_FINISHED);\n }\n\n async dump(...args: unknown[]): Promise<FsmProcessDump> {\n const dumpState = async (state: FsmState) => {\n const stateDump: FsmStateDump = {\n key: state.key,\n data: {},\n };\n await state._runHandler(\"dump\", state, stateDump.data, ...args);\n return stateDump;\n };\n const dumpStates = async (\n state: FsmState | undefined,\n stack: FsmStateDump[] = [],\n ) => {\n if (!state) return stack;\n state.parent && (await dumpStates(state.parent, stack));\n stack.push(await dumpState(state));\n return stack;\n };\n const dump: FsmProcessDump = {\n status: this.status,\n event: this.event,\n stack: await dumpStates(this.state),\n };\n return dump;\n }\n\n async restore(dump: FsmProcessDump, ...args: unknown[]) {\n this.status = dump.status || 0;\n this.event = dump.event;\n this.state = undefined;\n for (let i = 0; i < dump.stack.length; i++) {\n const stateDump = dump.stack[i];\n this.state = this.state\n ? this._newSubstate(this.state, stateDump.key)\n : this._newState(undefined, stateDump.key, this.rootDescriptor);\n await this.state._runHandler(\n \"restore\",\n this.state,\n stateDump.data,\n ...args,\n );\n }\n return this;\n }\n\n onStateCreate(handler: FsmStateHandler) {\n return this._addHandler(\"onStateCreate\", handler, true);\n }\n\n onStateError(\n handler: (state: FsmState, error: unknown) => void | Promise<void>,\n ) {\n return this._addHandler(\"onStateError\", handler);\n }\n\n async _handleStateError(state: FsmState, error: Error | unknown) {\n await this._runHandler(\"onStateError\", state, error);\n this._handleError(error);\n }\n\n _newState(\n parent: FsmState | undefined,\n key: string,\n descriptor: FsmStateDescriptor | undefined,\n ) {\n const state = new FsmState(this, parent, key, descriptor);\n this._runHandlerParallel(\"onStateCreate\", state);\n return state;\n }\n\n _getSubstate(parent: FsmState | undefined, prevStateKey: string | undefined) {\n if (!parent) return;\n const toState =\n parent.descriptor?.getTargetStateKey(\n prevStateKey || STATE_INITIAL,\n this.event || EVENT_EMPTY,\n ) || STATE_FINAL;\n if (!toState) return;\n return this._newSubstate(parent, toState);\n }\n\n _newSubstate(parent: FsmState | undefined, toState: string) {\n let descriptor: FsmStateDescriptor | undefined;\n for (\n let state: FsmState | undefined = parent;\n !descriptor && state;\n state = state.parent\n ) {\n descriptor = state.descriptor?.states[toState];\n }\n return this._newState(parent, toState, descriptor);\n }\n\n _update() {\n if (this.status & STATUS_FINISHED) return false;\n const nextState =\n this.status !== STATUS_NONE\n ? this.status & STATUS_ENTER\n ? this._getSubstate(this.state, STATE_INITIAL)\n : this._getSubstate(this.state?.parent, this.state?.key)\n : this._newState(undefined, this.config.key, this.rootDescriptor);\n if (nextState !== undefined) {\n this.state = nextState;\n this.status = this.status & STATUS_EXIT ? STATUS_NEXT : STATUS_FIRST;\n } else {\n if (this.status & STATUS_EXIT) {\n this.state = this.state?.parent;\n this.status = STATUS_LAST;\n } else {\n this.status = STATUS_LEAF;\n }\n if (!this.state) this.status = STATUS_FINISHED;\n }\n return !(this.status & STATUS_FINISHED);\n }\n}\n","import type { FsmProcess } from \"../core/fsm-process.ts\";\nimport type { FsmState } from \"../core/fsm-state.ts\";\nimport type { FsmStateDescriptor } from \"../core/fsm-state-descriptor.ts\";\n\nexport function isStateTransitionEnabled(process: FsmProcess, event: string) {\n const transitions = getStateTransitions(process.state);\n let active = false;\n for (const [from, ev, to] of transitions) {\n if (ev === event) {\n active = true;\n break;\n }\n }\n return active;\n}\n\nexport function getStateTransitions(\n state?: FsmState,\n): [from: string, event: string, to: string][] {\n const result: [from: string, event: string, to: string][] = [];\n const index = {};\n if (state) {\n let prevStateKey = state.key;\n for (let parent = state?.parent; parent; parent = parent.parent) {\n if (!parent.descriptor) continue;\n result.push(\n ...getTransitionsFromDescriptor(parent.descriptor, prevStateKey, index),\n );\n prevStateKey = parent.key;\n }\n }\n return result.reverse();\n}\n\nfunction getTransitionsFromDescriptor(\n descriptor: FsmStateDescriptor,\n prevStateKey: string,\n index: Record<string, boolean> = {},\n) {\n const result: [from: string, event: string, to: string][] = [];\n const prevStateKeys = [prevStateKey, \"*\"];\n for (const prevKey of prevStateKeys) {\n const targets: undefined | Record<string, string> =\n descriptor.transitions[prevKey];\n if (targets) {\n for (const [event, target] of Object.entries(targets)) {\n if (index[event]) continue;\n if (target) {\n index[event] = true;\n }\n result.push([prevStateKey, event, target]);\n }\n }\n }\n return result;\n}\n","import { isStateTransitionEnabled } from \"../utils/transitions.ts\";\nimport { FsmProcess } from \"./fsm-process.ts\";\nimport type { FsmStateConfig } from \"./fsm-state-config.ts\";\n\nexport type Module<C = unknown> = (context: C) =>\n | void\n | (() => void | Promise<void>)\n | Promise<void | (() => void | Promise<void>)>\n // Event emitters / triggers\n | Generator<string>\n | AsyncGenerator<string>;\n\nexport function newFsmProcess<C>(\n context: C,\n config: FsmStateConfig,\n load: (\n state: string,\n event: undefined | string,\n ) =>\n | undefined\n | Module<C>\n | Module<C>[]\n | Promise<undefined | Module<C> | Module<C>[]>,\n): [\n dispatch: (event: string) => Promise<boolean>,\n shutdown: () => Promise<void>,\n] {\n let started = false;\n let terminated = false;\n const process = new FsmProcess(config);\n async function dispatch(event: string): Promise<boolean> {\n return terminated ||\n (event !== undefined &&\n (!started || isStateTransitionEnabled(process, event)))\n ? process.dispatch(event)\n : false;\n }\n process.onStateCreate((state) => {\n started = true;\n state.onEnter(async () => {\n const modules = (await load(state.key, process.event)) ?? [];\n for (const module of Array.isArray(modules) ? modules : [modules]) {\n const result = await module?.(context);\n if (isGenerator(result)) {\n state.onExit(() => {\n result.return?.(void 0);\n });\n (async () => {\n for await (const event of result) {\n if (terminated) {\n break;\n }\n await dispatch(event);\n if (terminated) {\n break;\n }\n }\n })();\n } else if (typeof result === \"function\") {\n state.onExit(result);\n }\n }\n });\n });\n async function shutdown(): Promise<void> {\n await process.shutdown();\n terminated = true;\n }\n return [dispatch, shutdown] as const;\n\n function isGenerator(\n value: unknown,\n ): value is\n | Generator<string, void, unknown>\n | AsyncGenerator<string, void, unknown> {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"next\" in value &&\n typeof (value as Generator<string, void, unknown>).next === \"function\"\n );\n }\n}\n","/**\n * Key used to bind the dispatch function to the process context.\n * The dispatch function allows triggering state transitions by dispatching events.\n *\n * Example usage:\n * ```typescript\n * const context: Record<string, unknown> = {};\n * // Initialize the FSM process using `startFsmProcess`\n * const dispatch = context[\"fsm:dispatch\"] as (event: string) => Promise<void>;\n * await dispatch(\"someEvent\");\n */\nexport const KEY_DISPATCH = \"fsm:dispatch\" as const;\n\n/**\n * Key used to bind the terminate function to the process context.\n * The terminate function is used to gracefully shut down the FSM process.\n * It returns a Promise that resolves when the process has been fully terminated.\n * Example usage:\n * ```typescript\n * const context: Record<string, unknown> = {};\n * // Initialize the FSM process using `startFsmProcess`\n * const terminate = context[\"fsm:terminate\"] as () => Promise<void>;\n * await terminate();\n * ```\n */\nexport const KEY_TERMINATE = \"fsm:terminate\" as const;\n\n/**\n * Key used to bind the current stack of active states to the process context.\n * This provides a snapshot of the states the FSM process has entered.\n * It is represented as an array of strings -- state keys.\n *\n * Example usage:\n * ```typescript\n * const context: Record<string, unknown> = {};\n * // Initialize the FSM process using `startFsmProcess`\n * const states = context[\"fsm:states\"] as string[];\n * console.log(\"Current active states:\", states);\n * ```\n */\nexport const KEY_STATES = \"fsm:states\" as const;\n\n/**\n * Key used to bind the current event being processed to the process context.\n * This represents the event that triggered the current state transition.\n * It is represented as a string.\n * Example usage:\n * ```typescript\n * const context: Record<string, unknown> = {};\n * // Initialize the FSM process using `startFsmProcess`\n * const event = context[\"fsm:event\"] as string;\n * console.log(\"Current event:\", event);\n * ```\n */\nexport const KEY_EVENT = \"fsm:event\" as const;\n\n//-------------------------------------------------\n\n// export const KEY_START_PROCESS = \"fsm:sys:start\" as const;\n/**\n * Key used to register a new FSM process configuration in the process context.\n * This key is associated with a function that allows adding new FSM configurations.\n * The function takes a process name and its configuration, and returns a cleanup function\n * to remove the registered configuration.\n * Example usage:\n * ```typescript\n * const context: Record<string, unknown> = {};\n * initProcessManager(context); // Initialize the process manager in the context\n * ...\n * type StateConfig = { key: string; transitions?: string[][]; states?: StateConfig[] };\n * const registerConfig = context[\"fsm:sys:registerConfig\"] as (name: string, config: StateConfig) => () => void;\n * const unregister = registerConfig(\"myProcess\", { key: \"Main\", transitions: [...] });\n * // To unregister the configuration later\n * unregister();\n * ```\n */\nexport const KEY_REGISTER_CONFIG = \"fsm:sys:registerConfig\" as const;\n\n/**\n * Key used to register state and event handlers for FSM processes in the process context.\n * This key is associated with a function that allows adding handler modules for a specific process.\n * The function takes a process name and a variable number of handler modules, returning a cleanup function\n * to remove the registered handlers.\n * Example usage:\n * ```typescript\n * const context: Record<string, unknown> = {};\n * initProcessManager(context); // Initialize the process manager in the context\n * ...\n * const registerHandlers = context[\"fsm:sys:registerHandlers\"] as (name: string, ...modules: unknown[]) => () => void;\n * const handlerModule1 = {\n * Main: async (context) => { ... },\n * SomeState: async (context) => { ... },\n * }\n * // Views layer can be defined in the same or separate modules\n * const handlerModule3 = {\n * MainView: async (context) => { ... },\n * SomeStateView: async (context) => { ... },\n * }\n * // A common handler function to call for all states\n * const handlerModule2 = (context) => { ... };\n * const unregister = registerHandlers(\n * \"myProcess\",\n * handlerModule1,\n * handlerModule2,\n * handlerModule3\n * );\n * // To unregister the handlers later\n * unregister();\n * ```\n */\nexport const KEY_REGISTER_HANDLERS = \"fsm:sys:registerHandlers\" as const;\n\n/**\n * Key used to launch an FSM process in the process context.\n * This key is associated with a function that initiates the FSM process based on its name and context.\n * The function takes the process name and context, returning either nothing, a cleanup function,\n * or a Promise that resolves to either nothing or a cleanup function.\n * Example usage:\n * ```typescript\n * const context: Record<string, unknown> = {};\n * initProcessManager(context); // Initialize the process manager in the context\n * // Register process configurations and handlers as needed\n *\n * const launchProcess = context[\"fsm:sys:launch\"] as (name: string, context: Record<string, unknown>) => () => Promise<void>;\n * const terminate = await launchProcess(\"myProcess\", context);\n * // To terminate the process later\n * terminate?.();\n * ```\n */\nexport const KEY_LAUNCH_PROCESS = \"fsm:sys:launch\" as const;\n","export type StageHandler<C = Record<string, unknown>> = (\n context: C,\n) =>\n | void\n | (() => void | Promise<void>)\n | Promise<void | (() => void | Promise<void>)>\n | AsyncGenerator<string, void, unknown>\n | Generator<string, void, unknown>;\n\nexport function toStageHandlers<C>(\n value: unknown,\n accept: (key: string, value: unknown) => boolean,\n): StageHandler<C>[] {\n return visit(value);\n\n function visit(val: unknown): StageHandler<C>[] {\n if (!val) {\n return [];\n }\n if (typeof val === \"function\") {\n return [val] as StageHandler<C>[];\n }\n if (typeof val !== \"object\") {\n return [];\n }\n if (Array.isArray(val)) {\n return val.flatMap(visit);\n }\n const modulesIndex = val as Record<string, unknown>;\n return Object.entries(modulesIndex).flatMap(([key, value]) => {\n return accept(key, value) ? visit(value) : [];\n });\n }\n}\n","import type { FsmStateConfig } from \"../core/fsm-state-config.ts\";\nimport { type StageHandler, toStageHandlers } from \"./types.ts\";\n\nexport interface IProcessConfigManager {\n getProcessConfig(processName: string): FsmStateConfig;\n getHandlersLoader<C = unknown>(\n processName: string,\n ): (state: string, event: undefined | string) => StageHandler<C>[];\n registerConfig(name: string, config: FsmStateConfig): () => void;\n registerHandlers(name: string, ...modules: unknown[]): () => void;\n}\n\nexport class ProcessConfigManager implements IProcessConfigManager {\n protected configs: Record<string, FsmStateConfig> = {};\n protected handlers: Record<string, unknown[]> = {};\n\n getProcessConfig(processName: string): FsmStateConfig {\n return this.configs[processName] ?? { key: \"Main\" };\n }\n\n getHandlersLoader<C = unknown>(\n processName: string,\n ): (state: string, event: undefined | string) => StageHandler<C>[] {\n const config = this.getProcessConfig(processName);\n return (stateKey: string) => {\n const modulesKeys: string[] = [];\n if (stateKey === config.key) {\n modulesKeys.push(\"default\");\n }\n modulesKeys.push(\n stateKey,\n `${stateKey}Controller`,\n `${stateKey}StateController`,\n `${stateKey}View`,\n `${stateKey}StateView`,\n `${stateKey}Trigger`,\n `${stateKey}StateTrigger`,\n `${stateKey}Test`,\n `${stateKey}StateTest`,\n );\n const keysSet = new Set(modulesKeys);\n const processHandlers = this.handlers[processName] ?? [];\n const handlers = toStageHandlers(processHandlers, (key: string) =>\n keysSet.has(key),\n );\n return handlers;\n };\n }\n\n registerConfig(name: string, config: FsmStateConfig): () => void {\n this.configs[name] = config;\n return () => {\n delete this.configs[name];\n };\n }\n\n registerHandlers(name: string, ...modules: unknown[]): () => void {\n let list: unknown[] = this.handlers[name];\n if (!list) {\n list = this.handlers[name] = [];\n }\n list.push(modules);\n return () => {\n list = list.filter((v) => v !== modules);\n if (list.length === 0) {\n delete this.handlers[name];\n }\n };\n }\n}\n","export function isGenerator(\n value: unknown,\n): value is\n | Generator<string, void, unknown>\n | AsyncGenerator<string, void, unknown> {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"next\" in value &&\n typeof (value as Generator<string, void, unknown>).next === \"function\"\n );\n}\n","import { FsmProcess } from \"../core/fsm-process.ts\";\nimport type { FsmStateConfig } from \"../core/fsm-state-config.ts\";\nimport { isStateTransitionEnabled } from \"../utils/index.ts\";\nimport {\n KEY_DISPATCH,\n KEY_EVENT,\n KEY_STATES,\n KEY_TERMINATE,\n} from \"./constants.ts\";\nimport { isGenerator } from \"./is-generator.ts\";\nimport type { StageHandler } from \"./types.ts\";\n\nexport async function startFsmProcess<C = unknown>(\n context: C,\n config: FsmStateConfig,\n load: (\n state: string,\n event: undefined | string,\n ) => StageHandler<C>[] | Promise<StageHandler<C>[]>,\n startEvent = \"\",\n): Promise<() => Promise<void>> {\n let terminated = false;\n const ctx = context as Record<string, unknown>;\n const process = new FsmProcess(config);\n const statesStack: string[] = [];\n // ctx[KEY_PROCESS] = process;\n process.onStateCreate((state) => {\n state.onEnter(async () => {\n statesStack.push(state.key);\n ctx[KEY_STATES] = [...statesStack];\n ctx[KEY_EVENT] = process.event;\n const modules = (await load(state.key, process.event)) ?? [];\n for (const module of Array.isArray(modules) ? modules : [modules]) {\n const result = await module?.(context);\n if (isGenerator(result)) {\n let stateExited = false;\n state.onExit(() => {\n stateExited = true;\n result.return?.(void 0);\n });\n (async () => {\n for await (const event of result) {\n if (stateExited || terminated) {\n break;\n }\n await dispatch(event);\n }\n })();\n } else if (typeof result === \"function\") {\n state.onExit(result);\n }\n }\n });\n state.onExit(() => {\n statesStack.pop();\n ctx[KEY_STATES] = [...statesStack];\n ctx[KEY_EVENT] = process.event;\n });\n });\n async function terminate(): Promise<void> {\n terminated = true;\n await process.shutdown();\n }\n async function dispatch(event: string): Promise<void> {\n if (event !== undefined && isStateTransitionEnabled(process, event)) {\n await process.dispatch(event);\n }\n }\n ctx[KEY_DISPATCH] = dispatch;\n ctx[KEY_TERMINATE] = terminate;\n await process.dispatch(startEvent);\n return terminate;\n}\n","import type { FsmStateConfig } from \"../core/fsm-state-config.ts\";\nimport { ProcessConfigManager } from \"./process-config-manager.ts\";\nimport { startFsmProcess } from \"./start-process.ts\";\nimport type { StageHandler } from \"./types.ts\";\n\nexport type ProcessConfig = {\n name: string;\n config?: FsmStateConfig;\n} & (\n | {\n handler?: StageHandler;\n }\n | {\n handlers?:\n | StageHandler\n | (\n | StageHandler\n | {\n [state: string]: StageHandler | StageHandler[];\n }\n )[];\n }\n | {\n default?:\n | StageHandler\n | (\n | StageHandler\n | {\n [state: string]: StageHandler | StageHandler[];\n }\n )[];\n }\n);\n\nfunction asArray<T>(\n value: T | T[] | undefined,\n filter: (v: T, idx: number) => T | undefined = (v) => v,\n): T[] {\n if (value === undefined) return [];\n const array = Array.isArray(value) ? value : [value];\n return array.filter(Boolean).map(filter).filter(Boolean) as T[];\n}\n\nexport async function launcher(options: unknown) {\n const configsManager = new ProcessConfigManager();\n\n async function launch(\n processName: string,\n context: Record<string, unknown>,\n startEvent: string = \"start\",\n ) {\n const config = configsManager.getProcessConfig(processName);\n const load = configsManager.getHandlersLoader(processName);\n return startFsmProcess(context, config, load, startEvent);\n }\n\n function registerProcess(\n configsManager: ProcessConfigManager,\n process: Record<string, unknown>,\n ) {\n if (!process || typeof process !== \"object\") {\n throw new Error(\"Invalid process configuration: not an object\");\n }\n const processName = process.name;\n if (!processName || typeof processName !== \"string\") {\n throw new Error(\"Invalid process configuration: missing or invalid name\");\n }\n\n const processConfig = process.config as FsmStateConfig | undefined;\n if (processConfig && typeof processConfig !== \"object\") {\n throw new Error(\n `Invalid process configuration: config is not an object in process ${process.name}`,\n );\n }\n if (processConfig) {\n configsManager.registerConfig(processName, processConfig);\n }\n\n const processHandlers = asArray(\n process.handlers ?? process.handler ?? process.default,\n (v, idx) => {\n if (typeof v === \"function\") return v;\n if (typeof v === \"object\" && v !== null) return v;\n throw new Error(\n [\n `Invalid process configuration:`,\n `a process handler is not object nor function in process ${processName} at index ${idx}`,\n `Recieved: ${v === null ? \"null\" : typeof v}`,\n ].join(\"\\n\"),\n );\n },\n );\n if (processHandlers.length > 0) {\n configsManager.registerHandlers(processName, ...processHandlers);\n }\n }\n\n const rootContext = { \"fsm:launch\": launch };\n const init = typeof options === \"function\" ? options : async () => options;\n const config = await init(rootContext);\n if (typeof config !== \"object\" || !config) {\n throw new Error(\"Invalid launcher configuration\");\n }\n\n const processes = asArray(\n config.processes ?? config.process ?? config.default,\n (v) => {\n if (typeof v === \"function\") {\n return {\n name: v.name || \"\",\n handler: v,\n };\n }\n if (typeof v !== \"object\") {\n throw new Error(\n \"Invalid launcher configuration: process is not an object\",\n );\n }\n return v;\n },\n );\n for (const process of processes) {\n registerProcess(configsManager, process);\n }\n\n const shutdowns: (() => Promise<void>)[] = [];\n let startProcesses = asArray<string>(config.start);\n if (startProcesses.length === 0) {\n startProcesses = processes.map((p) => p.name).filter(Boolean) as string[];\n }\n\n let initContext: (\n parent: Record<string, unknown>,\n ) => Record<string, unknown> = (context) => context;\n const configContext = config.context ?? config.init;\n if (configContext) {\n if (typeof configContext === \"function\") {\n initContext = configContext;\n } else if (typeof configContext === \"object\") {\n initContext = () => ({ parent: configContext });\n } else {\n throw new Error(\"Invalid launcher configuration: context\");\n }\n }\n for (const processName of startProcesses) {\n let context: Record<string, unknown> = {\n parent: rootContext,\n \"fsm:name\": processName,\n };\n context = initContext(context) ?? context;\n if (typeof context !== \"object\") {\n throw new Error(\n `Invalid launcher context for process \"${processName}\". Expected an object, but recieved ${typeof context}.`,\n );\n }\n const shutdown = await launch(processName, context);\n shutdowns.push(shutdown);\n }\n\n return async () => {\n for (const shutdown of shutdowns) {\n await shutdown();\n }\n };\n}\n","/**\n * Resolve module paths relative to a base URL.\n * This is useful for converting relative paths to absolute URLs.\n *\n * @param baseUrl - The base URL to resolve against.\n * @param refs - An array of module references (relative or absolute).\n * @returns An array of resolved absolute module URLs as strings.\n * @example\n * ```ts\n * const urls = resolveModulesUrls(\n * 'file:///home/user/project/', // base URL\n * 'https://example.com/js/my-module.js', // absolute URL\n * './module1.js', // relative path\n * '../module2.js' // relative path\n * );\n * console.log(urls);\n * // Output: [\n * // 'https://example.com/js/my-module.js',\n * // 'file:///home/user/project/module1.js',\n * // 'file:///home/user/module2.js'\n * // ] *\n * ```\n */\nexport function resolveModulesUrls(\n baseUrl: URL | string,\n ...refs: (URL | string)[]\n): string[] {\n return refs.map((ref) => new URL(ref, baseUrl).href);\n}\n\n/**\n * Resolves module paths relative to a base URL.\n * This is useful for converting relative paths to absolute file system paths.\n * @param baseUrl - The base URL to resolve against\n * @param refs - An array of module references (relative or absolute)\n * @returns - An array of resolved absolute module paths as strings\n * @example\n * ```ts\n * const paths = resolveModulesPaths('file:///home/user/project/', './module1.js', '../module2.js');\n * console.log(paths);\n * // Output: [\n * // '/home/user/project/module1.js',\n * // '/home/user/module2.js'\n * // ]\n * ```\n */\nexport function resolveModulesPaths(\n baseUrl: URL | string,\n ...refs: (URL | string)[]\n): string[] {\n return refs.map((ref) => new URL(ref, baseUrl).pathname);\n}\n","import { launcher } from \"./launcher.ts\";\n\nexport async function startProcesses({\n onExit,\n modules,\n init,\n}: {\n onExit?: () => Promise<void> | void;\n modules: unknown[];\n init?: (\n context: Record<string, unknown>,\n ) => Promise<Record<string, unknown>> | Record<string, unknown>;\n}) {\n const modulesList: unknown[] = [];\n for (const module of modules) {\n modulesList.push(\n typeof module === \"string\" || module instanceof URL\n ? await import(String(module))\n : module,\n );\n }\n return await launcher({\n init,\n processes: [\n ...modulesList,\n // This function is called on exit at the end of the process chain\n function Exit() {\n return onExit;\n },\n ],\n });\n}\n","import { resolveModulesPaths } from \"./resolve-module-refs.ts\";\nimport { startProcesses } from \"./start-processes.ts\";\nexport async function startNodeProcesses(modules?: string[]): Promise<void> {\n try {\n if (!modules) {\n modules = process.argv.slice(2);\n }\n const terminate = await startProcesses({\n modules: resolveModulesPaths(`file://${process.cwd()}/`, ...modules),\n onExit: () => process.exit(0),\n });\n process.on(\"SIGINT\", terminate);\n process.on(\"SIGTERM\", terminate);\n process.stdin.resume();\n } catch (err) {\n console.error(\"Fatal error:\", err);\n process.exit(1);\n }\n}\n","export * from \"./core/index.ts\";\nexport * from \"./orchestrator/index.ts\";\n\n// export * from \"./utils/index.ts\";\n\nimport { startNodeProcesses } from \"./orchestrator/start-node-processes.ts\";\nexport default startNodeProcesses;\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@statewalker/fsm",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.33.0",
|
|
4
4
|
"description": "HFSM Implementation",
|
|
5
5
|
"keywords": [],
|
|
6
6
|
"homepage": "https://github.com/statewalker/statewalker-fsm",
|
|
@@ -24,6 +24,12 @@
|
|
|
24
24
|
"types": "./dist/index.d.ts",
|
|
25
25
|
"import": "./dist/index.js",
|
|
26
26
|
"default": "./dist/index.js"
|
|
27
|
+
},
|
|
28
|
+
"./*": {
|
|
29
|
+
"source": "./src/*.ts",
|
|
30
|
+
"types": "./dist/*.d.ts",
|
|
31
|
+
"import": "./dist/*.js",
|
|
32
|
+
"default": "./dist/*.js"
|
|
27
33
|
}
|
|
28
34
|
},
|
|
29
35
|
"devDependencies": {
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import { bindMethods, FsmBaseClass } from "./
|
|
1
|
+
import { bindMethods, FsmBaseClass } from "./fsm-base-class.ts";
|
|
2
2
|
import {
|
|
3
3
|
FsmState,
|
|
4
4
|
type FsmStateDump,
|
|
5
5
|
type FsmStateHandler,
|
|
6
|
-
} from "./
|
|
6
|
+
} from "./fsm-state.ts";
|
|
7
7
|
import {
|
|
8
8
|
EVENT_EMPTY,
|
|
9
9
|
type FsmStateConfig,
|
|
10
10
|
STATE_FINAL,
|
|
11
11
|
STATE_INITIAL,
|
|
12
|
-
} from "./
|
|
13
|
-
import { FsmStateDescriptor } from "./
|
|
12
|
+
} from "./fsm-state-config.ts";
|
|
13
|
+
import { FsmStateDescriptor } from "./fsm-state-descriptor.ts";
|
|
14
14
|
|
|
15
15
|
export const STATUS_NONE = 0;
|
|
16
16
|
export const STATUS_FIRST = 1;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { bindMethods, FsmBaseClass } from "./
|
|
2
|
-
import type { FsmProcess } from "./
|
|
3
|
-
import type { FsmStateDescriptor } from "./
|
|
1
|
+
import { bindMethods, FsmBaseClass } from "./fsm-base-class.ts";
|
|
2
|
+
import type { FsmProcess } from "./fsm-process.ts";
|
|
3
|
+
import type { FsmStateDescriptor } from "./fsm-state-descriptor.ts";
|
|
4
4
|
|
|
5
5
|
export type FsmStateDump = Record<string, unknown> & {
|
|
6
6
|
key: string;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
1
|
+
import { isStateTransitionEnabled } from "../utils/transitions.ts";
|
|
2
|
+
import { FsmProcess } from "./fsm-process.ts";
|
|
3
|
+
import type { FsmStateConfig } from "./fsm-state-config.ts";
|
|
4
4
|
|
|
5
5
|
export type Module<C = unknown> = (context: C) =>
|
|
6
6
|
| void
|
package/src/index.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
export * from "./
|
|
2
|
-
export * from "./FsmState.ts";
|
|
3
|
-
export * from "./FsmStateConfig.ts";
|
|
4
|
-
export * from "./FsmStateDescriptor.ts";
|
|
5
|
-
export * from "./newFsmProcess.ts";
|
|
1
|
+
export * from "./core/index.ts";
|
|
6
2
|
export * from "./orchestrator/index.ts";
|
|
7
|
-
|
|
3
|
+
|
|
4
|
+
// export * from "./utils/index.ts";
|
|
5
|
+
|
|
6
|
+
import { startNodeProcesses } from "./orchestrator/start-node-processes.ts";
|
|
7
|
+
export default startNodeProcesses;
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
export * from "./constants.ts";
|
|
2
2
|
export * from "./index.ts";
|
|
3
3
|
export * from "./launcher.ts";
|
|
4
|
-
export * from "./
|
|
5
|
-
export * from "./
|
|
4
|
+
export * from "./process-config-manager.ts";
|
|
5
|
+
export * from "./resolve-module-refs.ts";
|
|
6
|
+
export * from "./start-node-processes.ts";
|
|
7
|
+
export * from "./start-process.ts";
|
|
8
|
+
export * from "./start-processes.ts";
|
|
6
9
|
export * from "./types.ts";
|
|
@@ -1,31 +1,45 @@
|
|
|
1
|
-
import type { FsmStateConfig } from "../
|
|
2
|
-
import { ProcessConfigManager } from "./
|
|
3
|
-
import { startFsmProcess } from "./
|
|
1
|
+
import type { FsmStateConfig } from "../core/fsm-state-config.ts";
|
|
2
|
+
import { ProcessConfigManager } from "./process-config-manager.ts";
|
|
3
|
+
import { startFsmProcess } from "./start-process.ts";
|
|
4
4
|
import type { StageHandler } from "./types.ts";
|
|
5
5
|
|
|
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
|
-
|
|
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
|
+
}
|
|
29
43
|
|
|
30
44
|
export async function launcher(options: unknown) {
|
|
31
45
|
const configsManager = new ProcessConfigManager();
|
|
@@ -42,7 +56,7 @@ export async function launcher(options: unknown) {
|
|
|
42
56
|
|
|
43
57
|
function registerProcess(
|
|
44
58
|
configsManager: ProcessConfigManager,
|
|
45
|
-
process:
|
|
59
|
+
process: Record<string, unknown>,
|
|
46
60
|
) {
|
|
47
61
|
if (!process || typeof process !== "object") {
|
|
48
62
|
throw new Error("Invalid process configuration: not an object");
|
|
@@ -52,26 +66,32 @@ export async function launcher(options: unknown) {
|
|
|
52
66
|
throw new Error("Invalid process configuration: missing or invalid name");
|
|
53
67
|
}
|
|
54
68
|
|
|
55
|
-
const processConfig = process.config;
|
|
69
|
+
const processConfig = process.config as FsmStateConfig | undefined;
|
|
56
70
|
if (processConfig && typeof processConfig !== "object") {
|
|
57
71
|
throw new Error(
|
|
58
72
|
`Invalid process configuration: config is not an object in process ${process.name}`,
|
|
59
73
|
);
|
|
60
74
|
}
|
|
61
75
|
if (processConfig) {
|
|
62
|
-
configsManager.registerConfig(
|
|
76
|
+
configsManager.registerConfig(processName, processConfig);
|
|
63
77
|
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
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;
|
|
67
84
|
throw new Error(
|
|
68
|
-
|
|
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"),
|
|
69
90
|
);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
configsManager.registerHandlers(process.name, ...processHandlers);
|
|
91
|
+
},
|
|
92
|
+
);
|
|
93
|
+
if (processHandlers.length > 0) {
|
|
94
|
+
configsManager.registerHandlers(processName, ...processHandlers);
|
|
75
95
|
}
|
|
76
96
|
}
|
|
77
97
|
|
|
@@ -81,21 +101,37 @@ export async function launcher(options: unknown) {
|
|
|
81
101
|
if (typeof config !== "object" || !config) {
|
|
82
102
|
throw new Error("Invalid launcher configuration");
|
|
83
103
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
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
|
+
);
|
|
89
122
|
for (const process of processes) {
|
|
90
123
|
registerProcess(configsManager, process);
|
|
91
124
|
}
|
|
92
125
|
|
|
93
126
|
const shutdowns: (() => Promise<void>)[] = [];
|
|
94
|
-
|
|
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
|
+
|
|
95
132
|
let initContext: (
|
|
96
133
|
parent: Record<string, unknown>,
|
|
97
134
|
) => Record<string, unknown> = (context) => context;
|
|
98
|
-
|
|
99
135
|
const configContext = config.context ?? config.init;
|
|
100
136
|
if (configContext) {
|
|
101
137
|
if (typeof configContext === "function") {
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve module paths relative to a base URL.
|
|
3
|
+
* This is useful for converting relative paths to absolute URLs.
|
|
4
|
+
*
|
|
5
|
+
* @param baseUrl - The base URL to resolve against.
|
|
6
|
+
* @param refs - An array of module references (relative or absolute).
|
|
7
|
+
* @returns An array of resolved absolute module URLs as strings.
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* const urls = resolveModulesUrls(
|
|
11
|
+
* 'file:///home/user/project/', // base URL
|
|
12
|
+
* 'https://example.com/js/my-module.js', // absolute URL
|
|
13
|
+
* './module1.js', // relative path
|
|
14
|
+
* '../module2.js' // relative path
|
|
15
|
+
* );
|
|
16
|
+
* console.log(urls);
|
|
17
|
+
* // Output: [
|
|
18
|
+
* // 'https://example.com/js/my-module.js',
|
|
19
|
+
* // 'file:///home/user/project/module1.js',
|
|
20
|
+
* // 'file:///home/user/module2.js'
|
|
21
|
+
* // ] *
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export function resolveModulesUrls(
|
|
25
|
+
baseUrl: URL | string,
|
|
26
|
+
...refs: (URL | string)[]
|
|
27
|
+
): string[] {
|
|
28
|
+
return refs.map((ref) => new URL(ref, baseUrl).href);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Resolves module paths relative to a base URL.
|
|
33
|
+
* This is useful for converting relative paths to absolute file system paths.
|
|
34
|
+
* @param baseUrl - The base URL to resolve against
|
|
35
|
+
* @param refs - An array of module references (relative or absolute)
|
|
36
|
+
* @returns - An array of resolved absolute module paths as strings
|
|
37
|
+
* @example
|
|
38
|
+
* ```ts
|
|
39
|
+
* const paths = resolveModulesPaths('file:///home/user/project/', './module1.js', '../module2.js');
|
|
40
|
+
* console.log(paths);
|
|
41
|
+
* // Output: [
|
|
42
|
+
* // '/home/user/project/module1.js',
|
|
43
|
+
* // '/home/user/module2.js'
|
|
44
|
+
* // ]
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
export function resolveModulesPaths(
|
|
48
|
+
baseUrl: URL | string,
|
|
49
|
+
...refs: (URL | string)[]
|
|
50
|
+
): string[] {
|
|
51
|
+
return refs.map((ref) => new URL(ref, baseUrl).pathname);
|
|
52
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { resolveModulesPaths } from "./resolve-module-refs.ts";
|
|
2
|
+
import { startProcesses } from "./start-processes.ts";
|
|
3
|
+
export async function startNodeProcesses(modules?: string[]): Promise<void> {
|
|
4
|
+
try {
|
|
5
|
+
if (!modules) {
|
|
6
|
+
modules = process.argv.slice(2);
|
|
7
|
+
}
|
|
8
|
+
const terminate = await startProcesses({
|
|
9
|
+
modules: resolveModulesPaths(`file://${process.cwd()}/`, ...modules),
|
|
10
|
+
onExit: () => process.exit(0),
|
|
11
|
+
});
|
|
12
|
+
process.on("SIGINT", terminate);
|
|
13
|
+
process.on("SIGTERM", terminate);
|
|
14
|
+
process.stdin.resume();
|
|
15
|
+
} catch (err) {
|
|
16
|
+
console.error("Fatal error:", err);
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { FsmProcess } from "../
|
|
2
|
-
import type { FsmStateConfig } from "../
|
|
1
|
+
import { FsmProcess } from "../core/fsm-process.ts";
|
|
2
|
+
import type { FsmStateConfig } from "../core/fsm-state-config.ts";
|
|
3
3
|
import { isStateTransitionEnabled } from "../utils/index.ts";
|
|
4
4
|
import {
|
|
5
5
|
KEY_DISPATCH,
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
KEY_STATES,
|
|
8
8
|
KEY_TERMINATE,
|
|
9
9
|
} from "./constants.ts";
|
|
10
|
-
import { isGenerator } from "./
|
|
10
|
+
import { isGenerator } from "./is-generator.ts";
|
|
11
11
|
import type { StageHandler } from "./types.ts";
|
|
12
12
|
|
|
13
13
|
export async function startFsmProcess<C = unknown>(
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { launcher } from "./launcher.ts";
|
|
2
|
+
|
|
3
|
+
export async function startProcesses({
|
|
4
|
+
onExit,
|
|
5
|
+
modules,
|
|
6
|
+
init,
|
|
7
|
+
}: {
|
|
8
|
+
onExit?: () => Promise<void> | void;
|
|
9
|
+
modules: unknown[];
|
|
10
|
+
init?: (
|
|
11
|
+
context: Record<string, unknown>,
|
|
12
|
+
) => Promise<Record<string, unknown>> | Record<string, unknown>;
|
|
13
|
+
}) {
|
|
14
|
+
const modulesList: unknown[] = [];
|
|
15
|
+
for (const module of modules) {
|
|
16
|
+
modulesList.push(
|
|
17
|
+
typeof module === "string" || module instanceof URL
|
|
18
|
+
? await import(String(module))
|
|
19
|
+
: module,
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
return await launcher({
|
|
23
|
+
init,
|
|
24
|
+
processes: [
|
|
25
|
+
...modulesList,
|
|
26
|
+
// This function is called on exit at the end of the process chain
|
|
27
|
+
function Exit() {
|
|
28
|
+
return onExit;
|
|
29
|
+
},
|
|
30
|
+
],
|
|
31
|
+
});
|
|
32
|
+
}
|
package/src/utils/handlers.ts
CHANGED
package/src/utils/printer.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { FsmProcess } from "../
|
|
2
|
-
import type { FsmState } from "../
|
|
1
|
+
import type { FsmProcess } from "../core/fsm-process.ts";
|
|
2
|
+
import type { FsmState } from "../core/fsm-state.ts";
|
|
3
3
|
export type Printer = (...args: unknown[]) => void;
|
|
4
4
|
export type PrinterConfig = {
|
|
5
5
|
prefix?: string;
|
package/src/utils/process.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { FsmProcess } from "../
|
|
2
|
-
import type { FsmStateConfig } from "../
|
|
1
|
+
import { FsmProcess } from "../core/fsm-process.ts";
|
|
2
|
+
import type { FsmStateConfig } from "../core/fsm-state-config.ts";
|
|
3
3
|
import { setProcessPrinter } from "./printer.ts";
|
|
4
4
|
import { setProcessTracer } from "./tracer.ts";
|
|
5
5
|
|
|
@@ -15,7 +15,7 @@ export function newProcess(
|
|
|
15
15
|
lineNumbers?: boolean;
|
|
16
16
|
},
|
|
17
17
|
): FsmProcess {
|
|
18
|
-
|
|
18
|
+
const process = new FsmProcess(config);
|
|
19
19
|
setProcessPrinter(process, {
|
|
20
20
|
prefix,
|
|
21
21
|
print,
|
package/src/utils/tracer.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { FsmProcess } from "../
|
|
2
|
-
import type { FsmState } from "../
|
|
1
|
+
import type { FsmProcess } from "../core/fsm-process.ts";
|
|
2
|
+
import type { FsmState } from "../core/fsm-state.ts";
|
|
3
3
|
import { getPrinter, type Printer } from "./printer.ts";
|
|
4
4
|
|
|
5
5
|
export function setProcessTracer(process: FsmProcess, print?: Printer) {
|
package/src/utils/transitions.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { FsmProcess } from "../
|
|
2
|
-
import type { FsmState } from "../
|
|
3
|
-
import type { FsmStateDescriptor } from "../
|
|
1
|
+
import type { FsmProcess } from "../core/fsm-process.ts";
|
|
2
|
+
import type { FsmState } from "../core/fsm-state.ts";
|
|
3
|
+
import type { FsmStateDescriptor } from "../core/fsm-state-descriptor.ts";
|
|
4
4
|
|
|
5
5
|
export function isStateTransitionEnabled(process: FsmProcess, event: string) {
|
|
6
6
|
const transitions = getStateTransitions(process.state);
|
|
@@ -18,7 +18,7 @@ export function getStateTransitions(
|
|
|
18
18
|
state?: FsmState,
|
|
19
19
|
): [from: string, event: string, to: string][] {
|
|
20
20
|
const result: [from: string, event: string, to: string][] = [];
|
|
21
|
-
|
|
21
|
+
const index = {};
|
|
22
22
|
if (state) {
|
|
23
23
|
let prevStateKey = state.key;
|
|
24
24
|
for (let parent = state?.parent; parent; parent = parent.parent) {
|
|
File without changes
|
|
File without changes
|
|
File without changes
|