@statewalker/fsm 0.36.0 → 0.38.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.js.map CHANGED
@@ -1 +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/utils/printer.ts","../src/utils/tracer.ts","../src/utils/process.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","prefix","config","configsManager"],"mappings":"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","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","import type { FsmProcess } from \"../core/fsm-process.ts\";\nimport type { FsmState } from \"../core/fsm-state.ts\";\nexport type Printer = (...args: unknown[]) => void;\nexport type PrinterConfig = {\n prefix?: string;\n print?: (...args: unknown[]) => void;\n lineNumbers?: boolean;\n};\n\nexport const KEY_PRINTER = \"printer\";\n\nexport function preparePrinter(\n process: FsmProcess,\n { prefix = \"\", print = console.log, lineNumbers = false }: PrinterConfig,\n): Printer {\n let lineCounter = 0;\n const shift = () => {\n let prefix = \"\";\n for (let s = process.state?.parent; s; s = s.parent) {\n prefix += \" \";\n }\n return prefix;\n };\n const getPrefix = lineNumbers ? () => `[${++lineCounter}]${shift()}` : shift;\n const printer = (...args: unknown[]) => print(prefix, getPrefix(), ...args);\n return printer;\n}\n\nexport function setPrinter(state: FsmState, config: PrinterConfig = {}) {\n const printer = preparePrinter(state.process, config);\n state.setData(KEY_PRINTER, printer);\n}\n\nexport function setProcessPrinter(\n process: FsmProcess,\n config: PrinterConfig = {},\n) {\n const printer = preparePrinter(process, config);\n process.setData(KEY_PRINTER, printer);\n}\n\nexport function getProcessPrinter(process: FsmProcess): Printer {\n return process.getData(KEY_PRINTER) || console.log;\n}\n\nexport function getPrinter(state: FsmState): Printer {\n return state.getData(KEY_PRINTER, true) || getProcessPrinter(state.process);\n}\n","import type { FsmProcess } from \"../core/fsm-process.ts\";\nimport type { FsmState } from \"../core/fsm-state.ts\";\nimport { getPrinter, type Printer } from \"./printer.ts\";\n\nexport function setProcessTracer(process: FsmProcess, print?: Printer) {\n return process.onStateCreate((state) => {\n setStateTracer(state, print);\n });\n}\n\nexport function setStateTracer(state: FsmState, print?: Printer) {\n state.onEnter(() => {\n const printLine = print || getPrinter(state);\n printLine(`<${state?.key} event=\"${state.process.event}\">`);\n });\n state.onExit(async () => {\n await Promise.resolve().then(async () => {\n const printLine = print || getPrinter(state);\n printLine(`</${state.key}> <!-- event=\"${state.process.event}\" -->`);\n });\n });\n}\n","import { FsmProcess } from \"../core/fsm-process.ts\";\nimport type { FsmStateConfig } from \"../core/fsm-state-config.ts\";\nimport { setProcessPrinter } from \"./printer.ts\";\nimport { setProcessTracer } from \"./tracer.ts\";\n\nexport function newProcess(\n config: FsmStateConfig,\n {\n prefix,\n print,\n lineNumbers = true,\n }: {\n prefix?: string;\n print?: (...args: any[]) => void;\n lineNumbers?: boolean;\n },\n): FsmProcess {\n const process = new FsmProcess(config);\n setProcessPrinter(process, {\n prefix,\n print,\n lineNumbers,\n });\n setProcessTracer(process);\n return process;\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\n const processesToStart = {} as Record<string, undefined | boolean>;\n for (const process of processes) {\n const processName = process.name;\n const start = process.start;\n if (start === undefined) {\n if (!(processName in processesToStart)) {\n processesToStart[processName] = undefined;\n }\n } else {\n processesToStart[processName] = start;\n }\n registerProcess(configsManager, process);\n }\n\n const shutdowns: (() => Promise<void>)[] = [];\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, start] of Object.entries(processesToStart)) {\n if (start === false) continue;\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\";\nexport * from \"./utils/index.ts\";\n\nimport { startNodeProcesses } from \"./orchestrator/start-node-processes.ts\";\nexport default startNodeProcesses;\n"]}
1
+ {"version":3,"file":"index.js","names":[],"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/core/fsm-transitions.ts","../src/start-process.ts","../src/trace/printer.ts","../src/trace/tracer.ts"],"sourcesContent":["type Handler<P extends unknown[] = unknown[], R = unknown> = (...args: P) => R;\n\n/**\n * Shared handler-registry substrate under both `FsmProcess` and `FsmState`.\n *\n * Both the process and every state need the same primitive: keep named lists of\n * callbacks (`onEnter`, `onExit`, `dump`, …) and run them with consistent ordering\n * and error routing. Centralising it here keeps the two subclasses thin and their\n * hook methods one-liners. `handlers` maps a hook name to its ordered callback list;\n * the protected `_addHandler` / `_removeHandler` / `_runHandler` manage and invoke\n * them. Handlers run **sequentially** (awaited in turn); a throwing handler is routed\n * to `_handleError` rather than aborting the batch. Subclasses expose typed sugar\n * (e.g. `state.onEnter(fn)` calls `_addHandler(\"onEnter\", fn)`) and override\n * `_handleError` to forward errors.\n */\nexport class FsmBaseClass {\n handlers: Record<string, Handler[]> = {};\n\n // ----------------------------------------------\n // internal methods\n\n /**\n * Register `handler` under `type`; returns a disposer that removes it.\n * `direct=false` prepends instead of appends — used so `onExit` handlers run in\n * reverse (inner-to-outer) unwinding order.\n */\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 /** Run every handler of `type` in order, awaiting each; route throws to `_handleError`. */\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 /** Default error sink — logs. `FsmState`/`FsmProcess` override it to fire `onStateError`. */\n async _handleError(error: Error | unknown) {\n console.error(error);\n }\n}\n\n/**\n * Bind the named methods of `obj` to `obj` in place, so they can be passed as bare\n * callbacks (e.g. `ctx[KEY_DISPATCH] = process.dispatch`) without losing `this`.\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\n/** Serialized form of a single state: its `key` plus the `data` bag its `dump` hooks filled. */\nexport type FsmStateDump = Record<string, unknown> & {\n key: string;\n data: Record<string, unknown>;\n};\n/** An `onEnter` / `onExit` callback; receives the state it fired on. */\nexport type FsmStateHandler = (\n state: FsmState,\n ...args: unknown[]\n) => void | Promise<void>;\n\n/** A `dump` / `restore` callback; reads or fills the mutable per-state `data` bag. */\nexport type FsmStateDumpHandler = (\n state: FsmState,\n dump: FsmStateDump,\n) => void | Promise<void>;\n\n/** An `onStateError` callback; receives the error thrown by another handler on this state. */\nexport type FsmStateErrorHandler = (\n state: FsmState,\n error: unknown,\n) => void | Promise<void>;\n\n/**\n * One live node in a running machine's active-state stack.\n *\n * A state needs a place to attach behaviour and record data while it is active.\n * `FsmState` is that handle — created by the engine each time a state is entered,\n * discarded when it exits — so handlers can capture per-activation closures instead\n * of sharing mutable machine-wide state. It offers lifecycle hooks `onEnter` /\n * `onExit` / `onStateError`, serialization hooks `dump` / `restore`, and the tree\n * links `key` / `parent` / `descriptor`; every hook method returns a disposer.\n * Attach hooks from within `FsmProcess.onStateCreate((state) => …)`, or let\n * `startProcess` install them for you from a `load` callback.\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(this, \"onEnter\", \"onExit\", \"dump\", \"restore\", \"onStateError\");\n }\n\n /** Run when this state is entered. */\n onEnter(handler: FsmStateHandler) {\n return this._addHandler(\"onEnter\", handler, true);\n }\n /** Run when this state exits — registered inner-first so unwinding is inner-to-outer. */\n onExit(handler: FsmStateHandler) {\n return this._addHandler(\"onExit\", handler, false);\n }\n /** Handle an error thrown by another handler on this state (also bubbles to the process). */\n onStateError(handler: FsmStateErrorHandler) {\n return this._addHandler(\"onStateError\", handler);\n }\n /** Contribute to this state's snapshot: fill `dump.data` when the process is dumped. */\n dump(handler: FsmStateDumpHandler) {\n return this._addHandler(\"dump\", handler, true);\n }\n /** Rehydrate from this state's snapshot: read `dump.data` when the process is restored. */\n restore(handler: FsmStateDumpHandler) {\n return this._addHandler(\"restore\", handler, true);\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","// Sentinel keys used inside `FsmStateConfig.transitions` tuples. The raw `\"\"` and\n// `\"*\"` literals are ambiguous at the call site — `[\"\", \"start\", \"Active\"]` does not\n// visibly say \"from the *initial* state\" — so these named constants document intent\n// while keeping the runtime value (a shared empty string / asterisk) identical, which\n// keeps configs plain-serializable.\n\n/** Wildcard `from`-state: a transition that applies in *any* state. */\nexport const STATE_ANY = \"*\";\n/** Empty `from`-state: the *initial* pseudo-state a parent enters into. */\nexport const STATE_INITIAL = \"\";\n/** Empty `to`-state: the *final* pseudo-state; entering it exits the parent. */\nexport const STATE_FINAL = \"\";\n/** Wildcard `event`: a transition triggered by *any* event. */\nexport const EVENT_ANY = \"*\";\n/** Empty event: the eventless/automatic transition (fires with no named event). */\nexport const EVENT_EMPTY = \"\";\n\nexport type FsmStateKey = string;\nexport type FsmEventKey = string;\n\n/**\n * Declarative definition of a (possibly nested) state machine.\n *\n * One plain-object shape describes an entire HFSM, so machines stay serializable,\n * diffable, and inspectable by tooling — the config is data, not code. A config has:\n * - `key` — the state's name (unique among its siblings);\n * - `transitions` — `[from, event, to]` tuples, where `from`/`to` name sibling\n * states, `\"\"` is the initial (`from`) or final (`to`) pseudo-state, and `\"*\"` is a\n * wildcard (see the constants above);\n * - `states` — nested child configs; entering this state descends into its initial\n * child. The index signature lets consumers attach arbitrary metadata.\n *\n * Pass a config to `new FsmProcess(config)` or `startProcess(ctx, config, …)`; it is\n * compiled once into an `FsmStateDescriptor` for fast lookup at runtime.\n */\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\n/**\n * The *compiled* form of an `FsmStateConfig` subtree.\n *\n * Resolving a transition happens on every event, so the flat `[from, event, to]`\n * tuple list is pre-indexed once into nested maps for O(1) lookup, and the\n * wildcard-fallback order is applied here rather than re-derived on each dispatch.\n * The shape is `transitions[from][event] = to` plus a `states` map of child\n * descriptors. `FsmProcess` builds one from your config in its constructor; you\n * rarely construct a descriptor directly.\n */\nexport class FsmStateDescriptor {\n transitions: Record<string, Record<string, string>> = {};\n states: Record<string, FsmStateDescriptor> = {};\n\n /**\n * Recursively compile a config (and its nested `states`) into descriptors,\n * turning the tuple list into the indexed `transitions` map.\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 /**\n * Resolve the target state for a `(stateKey, eventKey)` pair. Tries the most\n * specific match first, then falls back through the wildcards —\n * `(state, event)` → `(*, event)` → `(state, *)` → `(*, *)` — and returns\n * `STATE_FINAL` if nothing matches, so an unmatched event exits the state rather\n * than silently doing nothing.\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\n// Status bitmask: where the process is in the enter/exit cycle of `dispatch`.\n// Why a bitmask (rather than an enum): the loop tests *phases* with cheap bitwise\n// masks — `status & STATUS_ENTER`, `status & this.mask` — and composite masks\n// (ENTER / EXIT) are just OR-combinations of the primitive bits.\n/** Not started / no current transition. */\nexport const STATUS_NONE = 0;\n/** Entering: descended into a parent's first (initial) child. */\nexport const STATUS_FIRST = 1;\n/** Entering: advanced to a resolved target (sibling) state. */\nexport const STATUS_NEXT = 2;\n/** Rested on a leaf — dispatch returns control here (the default `mask`). */\nexport const STATUS_LEAF = 4;\n/** Exiting: popped back up to the parent state. */\nexport const STATUS_LAST = 8;\n/** Terminated: the machine has exited its root and cannot advance further. */\nexport const STATUS_FINISHED = 16;\n\n//\n/** Composite: any \"entering\" phase. */\nexport const STATUS_ENTER = STATUS_FIRST | STATUS_NEXT;\n/** Composite: any \"exiting\" phase. */\nexport const STATUS_EXIT = STATUS_LEAF | STATUS_LAST;\n\n/** A process-level handler (`onStateCreate` / `onStateError`). */\nexport type FsmProcessHandler = (\n process: FsmProcess,\n ...args: unknown[]\n) => void | Promise<void>;\n\n/** Serialized form of the whole machine: status, last event, and the root→leaf state stack. */\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\n/**\n * The running state machine — owner of the active-state stack and the traversal.\n *\n * This is the engine: given a compiled config it drives the enter/exit walk in\n * response to events, so callers reason in terms of states and events, not manual\n * stack bookkeeping. `dispatch(event)` advances the machine to the next resting leaf;\n * `shutdown(event?)` unwinds every active state; `state` is the current leaf;\n * `onStateCreate(handler)` is the primary extension point (fires once per created\n * state — attach that state's hooks there); and `dump()` / `restore(dump)` snapshot\n * and rehydrate the whole stack. Typical use: `new FsmProcess(config)`, register\n * `onStateCreate`, then `dispatch(\"\")` to enter the initial state and\n * `dispatch(event)` for each subsequent event.\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 /** Force-exit the whole stack (root last), running each state's `onExit`; ends the machine. */\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 /**\n * Feed an event to the machine and run the enter/exit cycle until it rests on a\n * leaf (`status & mask`) or finishes.\n *\n * If a dispatch is already running (e.g. an `onEnter` handler dispatches\n * synchronously), the event is queued in `nextEvent` and applied when the current\n * run settles — runs never nest. Returns `false` once the machine has finished,\n * `true` otherwise.\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 (!(await 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 /**\n * Snapshot the machine to a plain object: `{ status, event, stack }` where the\n * stack is root→leaf, each entry carrying whatever its `dump` hooks recorded.\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 /**\n * Rebuild the machine from a `dump`: recreate each state in the stack (firing\n * `onStateCreate`) and replay its `restore` hooks, leaving the process resumable\n * from where it was snapshotted.\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 ? await this._newSubstate(this.state, stateDump.key)\n : await 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 /** Primary extension point: fires once for every state the machine creates. */\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 async _newState(\n parent: FsmState | undefined,\n key: string,\n descriptor: FsmStateDescriptor | undefined,\n ) {\n const state = new FsmState(this, parent, key, descriptor);\n await this._runHandler(\"onStateCreate\", state);\n return state;\n }\n\n async _getSubstate(\n parent: FsmState | undefined,\n prevStateKey: string | undefined,\n ) {\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 async _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 /**\n * One step of the traversal: compute the next state and update `status`.\n *\n * Either descends to a child / advances to a resolved target (setting an ENTER\n * status), or — when no target resolves — settles on the current leaf\n * (`STATUS_LEAF`) or pops to the parent (`STATUS_LAST`), reaching `STATUS_FINISHED`\n * once the root is exited. Returns `false` when finished.\n */\n async _update() {\n if (this.status & STATUS_FINISHED) return false;\n const nextState =\n this.status !== STATUS_NONE\n ? this.status & STATUS_ENTER\n ? await this._getSubstate(this.state, STATE_INITIAL)\n : await this._getSubstate(this.state?.parent, this.state?.key)\n : await 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 \"./fsm-process.ts\";\nimport type { FsmState } from \"./fsm-state.ts\";\nimport type { FsmStateDescriptor } from \"./fsm-state-descriptor.ts\";\n\n// ---------------------------------------------------------------------------\n// Transition introspection — read-only queries over the state/transition graph\n// ---------------------------------------------------------------------------\n\n/**\n * List the transitions currently reachable from `state` — for a UI or viewer that\n * needs to know which events can fire right now (e.g. to render only the enabled\n * buttons). Collects `[from, event, to]` tuples by walking up the parent chain; the\n * nearest state's rule for an event wins, so an outer fallback is masked by an inner\n * override. The returned tuples are ordered outer→inner (root first).\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: Record<string, boolean> = {};\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): [from: string, event: string, to: string][] {\n const result: [from: string, event: string, to: string][] = [];\n const prevStateKeys = [prevStateKey, \"*\"];\n for (const prevKey of prevStateKeys) {\n const targets = descriptor.transitions[prevKey];\n if (targets) {\n for (const [event, target] of Object.entries(targets)) {\n if (index[event]) continue;\n // Mark the event seen regardless of target — an inner exit-to-final\n // (`to === \"\"`, a falsy target) must still mask an outer rule for the\n // same event, matching what `dispatch` actually resolves.\n index[event] = true;\n result.push([prevStateKey, event, target]);\n }\n }\n }\n return result;\n}\n\n/**\n * Guard: would `event` trigger any transition in the process's current state? Used\n * to avoid dispatching dead events — the runner calls it before `dispatch`, and\n * consumers use it to enable/disable controls. Returns `true` iff `event` appears\n * among `getStateTransitions(process.state)`.\n */\nexport function isStateTransitionEnabled(\n process: FsmProcess,\n event: string,\n): boolean {\n const transitions = getStateTransitions(process.state);\n for (const [, ev] of transitions) {\n if (ev === event) return true;\n }\n return false;\n}\n","import { FsmProcess, type FsmProcessDump } from \"./core/fsm-process.ts\";\nimport type { FsmState } from \"./core/fsm-state.ts\";\nimport type { FsmStateConfig } from \"./core/fsm-state-config.ts\";\nimport { isStateTransitionEnabled } from \"./core/fsm-transitions.ts\";\n\n/**\n * Per-state behaviour contract used by `startProcess`. One function shape expresses\n * what to do while in a state, and its *return value* wires up the rest, so a state's\n * setup and teardown live together. The handler runs on entry with the shared\n * `context` and may return:\n * - nothing — no teardown;\n * - a cleanup `function` — registered as this state's `onExit`;\n * - an async/sync generator — run concurrently, each yielded string dispatched back\n * into the machine (self-driving/reactive states), auto-`return()`ed on exit.\n */\nexport 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\n/**\n * The caller's remote control returned by `startProcess`: stop the machine and\n * snapshot/rehydrate it without holding a reference to the underlying `FsmProcess`.\n */\nexport interface ProcessHandle {\n shutdown(): Promise<void>;\n dump(...args: unknown[]): Promise<FsmProcessDump>;\n restore(dump: FsmProcessDump, ...args: unknown[]): Promise<void>;\n}\n\n// Context keys under which `startProcess` binds the machine into the shared context\n// object. Why via context (not closures): handlers reach the running machine\n// uniformly — `(ctx[KEY_DISPATCH])(event)` — regardless of where they are defined.\n/** Context key: `(event) => Promise<void>` that dispatches an event (guarded). */\nexport const KEY_DISPATCH = \"fsm:dispatch\";\n/** Context key: `() => Promise<void>` that shuts the machine down. */\nexport const KEY_TERMINATE = \"fsm:terminate\";\n/** Context key: the current state-key stack (root→leaf), refreshed on every transition. */\nexport const KEY_STATES = \"fsm:states\";\n/** Context key: the last dispatched event. */\nexport const KEY_EVENT = \"fsm:event\";\n\n// ---------------------------------------------------------------------------\n// Generator detection\n// ---------------------------------------------------------------------------\n\nfunction 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 { next: unknown }).next === \"function\"\n );\n}\n\n// ---------------------------------------------------------------------------\n// startProcess (also exported as startFsmProcess for backward compat)\n// ---------------------------------------------------------------------------\n\n/**\n * Ergonomic runner: build a machine, attach behaviour via one `load` callback, and\n * bind the machine into `context`.\n *\n * Doing this by hand (`new FsmProcess` + `onStateCreate` + `onEnter` + a loader +\n * context wiring) is boilerplate every consumer repeats, so `startProcess` does it\n * once — most callers use this instead of the raw engine. It creates the process; on\n * each state entry calls `load(stateKey, event)` and installs the returned\n * `StageHandler`s (their return values become `onExit` cleanups or event-yielding\n * generators — see `StageHandler`); binds `KEY_DISPATCH` / `KEY_TERMINATE` /\n * `KEY_STATES` / `KEY_EVENT` into `context`; dispatches `startEvent` to enter the\n * initial state; and returns a `ProcessHandle`.\n *\n * @param context shared object handlers read/write and the machine is bound into\n * @param config the declarative machine definition\n * @param load returns the handler(s) to run for a given `(stateKey, event)`\n * @param startEvent initial event (default `\"\"`, the eventless start)\n */\nexport async function startProcess<C = unknown>(\n context: C,\n config: FsmStateConfig,\n load: (\n state: string,\n event: string | undefined,\n ) => StageHandler<C>[] | Promise<StageHandler<C>[]>,\n startEvent = \"\",\n): Promise<ProcessHandle> {\n let terminated = false;\n const ctx = context as Record<string, unknown>;\n const process = new FsmProcess(config);\n const statesStack: string[] = [];\n\n process.onStateCreate((state: FsmState) => {\n state.onEnter(async () => {\n statesStack.push(state.key);\n ctx[KEY_STATES] = [...statesStack];\n ctx[KEY_EVENT] = process.event;\n\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?.(undefined as never);\n });\n (async () => {\n try {\n for await (const event of result) {\n if (stateExited || terminated) break;\n await dispatch(event);\n if (stateExited || terminated) break;\n }\n } catch (error) {\n // A generator `return()` during state exit / termination throws an\n // abort we intentionally swallow; a genuine error thrown by the\n // generator body must surface through the state's error handling\n // rather than vanish.\n if (!stateExited && !terminated) await state._handleError(error);\n }\n })();\n } else if (typeof result === \"function\") {\n state.onExit(result as () => void | Promise<void>);\n }\n }\n });\n state.onExit(() => {\n statesStack.pop();\n ctx[KEY_STATES] = [...statesStack];\n ctx[KEY_EVENT] = process.event;\n });\n });\n\n async function dispatch(event: string): Promise<void> {\n if (event !== undefined && isStateTransitionEnabled(process, event)) {\n await process.dispatch(event);\n }\n }\n async function terminate(): Promise<void> {\n terminated = true;\n await process.shutdown();\n }\n\n async function dumpProcess(...args: unknown[]): Promise<FsmProcessDump> {\n return process.dump(...args);\n }\n\n async function restoreProcess(\n dumpData: FsmProcessDump,\n ...args: unknown[]\n ): Promise<void> {\n statesStack.length = 0;\n terminated = false;\n await process.restore(dumpData, ...args);\n for (\n let state: FsmState | undefined = process.state;\n state;\n state = state.parent\n ) {\n statesStack.unshift(state.key);\n }\n ctx[KEY_STATES] = [...statesStack];\n ctx[KEY_EVENT] = process.event;\n }\n\n ctx[KEY_DISPATCH] = dispatch;\n ctx[KEY_TERMINATE] = terminate;\n await process.dispatch(startEvent);\n return {\n shutdown: terminate,\n dump: dumpProcess,\n restore: restoreProcess,\n };\n}\n\n/** Permanent equal alias of {@link startProcess} — the name existing consumers import. */\nexport const startFsmProcess = startProcess;\n","import type { FsmProcess } from \"../core/fsm-process.ts\";\n\n/** A sink for trace output — anything shaped like `console.log`. */\nexport type Printer = (...args: unknown[]) => void;\n/**\n * Tuning for a `Printer`.\n * - `prefix` — string prepended to every line (e.g. a process tag).\n * - `print` — the underlying sink (defaults to `console.log`).\n * - `lineNumbers` — prepend an incrementing `[n]` counter.\n */\nexport type PrinterConfig = {\n prefix?: string;\n print?: (...args: unknown[]) => void;\n lineNumbers?: boolean;\n};\n\nconst printerStore = new WeakMap<object, Printer>();\n\n/**\n * Build a `Printer` bound to `process` that indents each line by the current state\n * nesting depth (two spaces per level), so log output visually mirrors the state\n * tree — hierarchical indentation makes enter/exit traces readable at a glance.\n */\nexport function preparePrinter(\n process: FsmProcess,\n { prefix = \"\", print = console.log, lineNumbers = false }: PrinterConfig,\n): Printer {\n let lineCounter = 0;\n const shift = () => {\n let prefix = \"\";\n for (let s = process.state?.parent; s; s = s.parent) {\n prefix += \" \";\n }\n return prefix;\n };\n const getPrefix = lineNumbers ? () => `[${++lineCounter}]${shift()}` : shift;\n const printer = (...args: unknown[]) => print(prefix, getPrefix(), ...args);\n return printer;\n}\n\n/**\n * Attach a printer to `process` (stored in a weak map so it is GC'd with the\n * process). Handlers/tracers then reach it via {@link getProcessPrinter} /\n * {@link getPrinter} rather than threading a logger through every call.\n */\nexport function setProcessPrinter(\n process: FsmProcess,\n config: PrinterConfig = {},\n) {\n const printer = preparePrinter(process, config);\n printerStore.set(process, printer);\n}\n\n/** The printer attached to `process`, or `console.log` if none was set. */\nexport function getProcessPrinter(process: FsmProcess): Printer {\n return printerStore.get(process) || console.log;\n}\n\n/** The printer for a state — its own if set, else its process's (see {@link getProcessPrinter}). */\nexport function getPrinter(state: { process: FsmProcess }): Printer {\n return printerStore.get(state) || getProcessPrinter(state.process);\n}\n","import type { FsmProcess } from \"../core/fsm-process.ts\";\nimport type { FsmState } from \"../core/fsm-state.ts\";\nimport { getPrinter, type Printer } from \"./printer.ts\";\n\n/**\n * Trace every state of `process`: as each state is created, attach a state tracer —\n * so you can watch the machine move as a readable stream of enter/exit markers\n * without editing any handler. Hooks `onStateCreate` and delegates to\n * {@link setStateTracer}; pass a `print` sink to override the process printer.\n */\nexport function setProcessTracer(process: FsmProcess, print?: Printer) {\n return process.onStateCreate((state: FsmState) => {\n setStateTracer(state, print);\n });\n}\n\n/**\n * Trace one state's lifecycle: emit `<key event=\"…\">` on enter and `</key>` on exit\n * (XML-like, so nested states read as nested tags). Falls back to the state's\n * printer ({@link getPrinter}) when no `print` sink is given.\n */\nexport function setStateTracer(state: FsmState, print?: Printer) {\n state.onEnter(() => {\n const printLine = print || getPrinter(state);\n printLine(`<${state?.key} event=\"${state.process.event}\">`);\n });\n state.onExit(async () => {\n await Promise.resolve().then(async () => {\n const printLine = print || getPrinter(state);\n printLine(`</${state.key}> <!-- event=\"${state.process.event}\" -->`);\n });\n });\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@statewalker/fsm",
3
- "version": "0.36.0",
3
+ "version": "0.38.0",
4
4
  "description": "HFSM Implementation",
5
5
  "keywords": [],
6
6
  "homepage": "https://github.com/statewalker/statewalker-fsm",
@@ -10,11 +10,7 @@
10
10
  },
11
11
  "license": "MIT",
12
12
  "type": "module",
13
- "bin": {
14
- "fsm": "./bin/cli.js"
15
- },
16
13
  "files": [
17
- "bin",
18
14
  "dist",
19
15
  "src"
20
16
  ],
@@ -28,35 +24,29 @@
28
24
  "types": "./dist/index.d.ts",
29
25
  "import": "./dist/index.js",
30
26
  "default": "./dist/index.js"
31
- },
32
- "./*": {
33
- "source": "./src/*.ts",
34
- "types": "./dist/*.d.ts",
35
- "import": "./dist/*.js",
36
- "default": "./dist/*.js"
37
27
  }
38
28
  },
39
29
  "devDependencies": {
40
- "@biomejs/biome": "^2.2.2",
41
- "tsup": "^8.5.0",
42
- "typescript": "^5.9.2",
43
- "vitest": "^3.2.4"
30
+ "@biomejs/biome": "catalog:",
31
+ "tsdown": "catalog:",
32
+ "typescript": "^6.0.3",
33
+ "vitest": "catalog:"
44
34
  },
45
35
  "repository": {
46
36
  "type": "git",
47
37
  "url": "git@github.com:statewalker/statewalker-fsm.git"
48
38
  },
49
39
  "scripts": {
50
- "dist": "yarn test && tsup",
51
- "build": "yarn dist",
52
- "watch": "tsup --watch",
40
+ "dist": "pnpm test && tsdown",
41
+ "build": "pnpm dist",
42
+ "watch": "tsdown --watch",
53
43
  "clean": "rm -rf dist",
54
44
  "format": "biome format . --write",
55
45
  "check": "biome check .",
56
- "fix": "yarn format && biome check . --fix --unsafe",
46
+ "fix": "pnpm format && biome check . --fix --unsafe",
57
47
  "test": "vitest --run",
58
48
  "test:watch": "vitest",
59
- "prepublish": "yarn dist"
49
+ "prepublish": "pnpm dist"
60
50
  },
61
51
  "sideEffects": false,
62
52
  "publishConfig": {
@@ -1,22 +1,29 @@
1
- type Handler<P extends unknown[] = unknown[], R = unknown> = (...args: P) => R; // Function;
2
- // type Handler = Function;
1
+ type Handler<P extends unknown[] = unknown[], R = unknown> = (...args: P) => R;
3
2
 
3
+ /**
4
+ * Shared handler-registry substrate under both `FsmProcess` and `FsmState`.
5
+ *
6
+ * Both the process and every state need the same primitive: keep named lists of
7
+ * callbacks (`onEnter`, `onExit`, `dump`, …) and run them with consistent ordering
8
+ * and error routing. Centralising it here keeps the two subclasses thin and their
9
+ * hook methods one-liners. `handlers` maps a hook name to its ordered callback list;
10
+ * the protected `_addHandler` / `_removeHandler` / `_runHandler` manage and invoke
11
+ * them. Handlers run **sequentially** (awaited in turn); a throwing handler is routed
12
+ * to `_handleError` rather than aborting the batch. Subclasses expose typed sugar
13
+ * (e.g. `state.onEnter(fn)` calls `_addHandler("onEnter", fn)`) and override
14
+ * `_handleError` to forward errors.
15
+ */
4
16
  export class FsmBaseClass {
5
17
  handlers: Record<string, Handler[]> = {};
6
- data: Record<string, unknown> = {};
7
- constructor() {
8
- bindMethods(this, "setData", "getData");
9
- }
10
- setData<T>(key: string, value: T) {
11
- this.data[key] = value;
12
- return this;
13
- }
14
- getData<T>(key: string): T | undefined {
15
- return this.data[key] as T;
16
- }
17
18
 
18
19
  // ----------------------------------------------
19
20
  // internal methods
21
+
22
+ /**
23
+ * Register `handler` under `type`; returns a disposer that removes it.
24
+ * `direct=false` prepends instead of appends — used so `onExit` handlers run in
25
+ * reverse (inner-to-outer) unwinding order.
26
+ */
20
27
  protected _addHandler<T>(type: string, handler: T, direct: boolean = true) {
21
28
  let list = this.handlers[type];
22
29
  if (!list) {
@@ -38,19 +45,7 @@ export class FsmBaseClass {
38
45
  }
39
46
  }
40
47
 
41
- async _runHandlerParallel(type: string, ...args: unknown[]) {
42
- const list = this.handlers[type] || [];
43
- await Promise.all(
44
- list.map(async (handler) => {
45
- try {
46
- await handler(...args);
47
- } catch (error) {
48
- this._handleError(error);
49
- }
50
- }),
51
- );
52
- }
53
-
48
+ /** Run every handler of `type` in order, awaiting each; route throws to `_handleError`. */
54
49
  async _runHandler(type: string, ...args: unknown[]) {
55
50
  const list = this.handlers[type] || [];
56
51
  for (const handler of list) {
@@ -62,11 +57,16 @@ export class FsmBaseClass {
62
57
  }
63
58
  }
64
59
 
60
+ /** Default error sink — logs. `FsmState`/`FsmProcess` override it to fire `onStateError`. */
65
61
  async _handleError(error: Error | unknown) {
66
62
  console.error(error);
67
63
  }
68
64
  }
69
65
 
66
+ /**
67
+ * Bind the named methods of `obj` to `obj` in place, so they can be passed as bare
68
+ * callbacks (e.g. `ctx[KEY_DISPATCH] = process.dispatch`) without losing `this`.
69
+ */
70
70
  export function bindMethods<T>(obj: T, ...methods: (string | symbol)[]) {
71
71
  const o = obj as Record<string | symbol, unknown>;
72
72
  for (const methodName of methods) {
@@ -12,22 +12,36 @@ import {
12
12
  } from "./fsm-state-config.ts";
13
13
  import { FsmStateDescriptor } from "./fsm-state-descriptor.ts";
14
14
 
15
+ // Status bitmask: where the process is in the enter/exit cycle of `dispatch`.
16
+ // Why a bitmask (rather than an enum): the loop tests *phases* with cheap bitwise
17
+ // masks — `status & STATUS_ENTER`, `status & this.mask` — and composite masks
18
+ // (ENTER / EXIT) are just OR-combinations of the primitive bits.
19
+ /** Not started / no current transition. */
15
20
  export const STATUS_NONE = 0;
21
+ /** Entering: descended into a parent's first (initial) child. */
16
22
  export const STATUS_FIRST = 1;
23
+ /** Entering: advanced to a resolved target (sibling) state. */
17
24
  export const STATUS_NEXT = 2;
25
+ /** Rested on a leaf — dispatch returns control here (the default `mask`). */
18
26
  export const STATUS_LEAF = 4;
27
+ /** Exiting: popped back up to the parent state. */
19
28
  export const STATUS_LAST = 8;
29
+ /** Terminated: the machine has exited its root and cannot advance further. */
20
30
  export const STATUS_FINISHED = 16;
21
31
 
22
32
  //
33
+ /** Composite: any "entering" phase. */
23
34
  export const STATUS_ENTER = STATUS_FIRST | STATUS_NEXT;
35
+ /** Composite: any "exiting" phase. */
24
36
  export const STATUS_EXIT = STATUS_LEAF | STATUS_LAST;
25
37
 
38
+ /** A process-level handler (`onStateCreate` / `onStateError`). */
26
39
  export type FsmProcessHandler = (
27
40
  process: FsmProcess,
28
41
  ...args: unknown[]
29
42
  ) => void | Promise<void>;
30
43
 
44
+ /** Serialized form of the whole machine: status, last event, and the root→leaf state stack. */
31
45
  export type FsmProcessDump = Record<string, unknown> & {
32
46
  status: number;
33
47
  event?: string;
@@ -39,6 +53,19 @@ export type FsmProcessDumpHandler = (
39
53
  dump: FsmProcessDump,
40
54
  ) => void | Promise<void>;
41
55
 
56
+ /**
57
+ * The running state machine — owner of the active-state stack and the traversal.
58
+ *
59
+ * This is the engine: given a compiled config it drives the enter/exit walk in
60
+ * response to events, so callers reason in terms of states and events, not manual
61
+ * stack bookkeeping. `dispatch(event)` advances the machine to the next resting leaf;
62
+ * `shutdown(event?)` unwinds every active state; `state` is the current leaf;
63
+ * `onStateCreate(handler)` is the primary extension point (fires once per created
64
+ * state — attach that state's hooks there); and `dump()` / `restore(dump)` snapshot
65
+ * and rehydrate the whole stack. Typical use: `new FsmProcess(config)`, register
66
+ * `onStateCreate`, then `dispatch("")` to enter the initial state and
67
+ * `dispatch(event)` for each subsequent event.
68
+ */
42
69
  export class FsmProcess extends FsmBaseClass {
43
70
  state?: FsmState;
44
71
  event?: string;
@@ -56,6 +83,7 @@ export class FsmProcess extends FsmBaseClass {
56
83
  bindMethods(this, "dispatch", "dump", "restore");
57
84
  }
58
85
 
86
+ /** Force-exit the whole stack (root last), running each state's `onExit`; ends the machine. */
59
87
  async shutdown(event?: string) {
60
88
  while (this.state) {
61
89
  this.event = event;
@@ -65,6 +93,15 @@ export class FsmProcess extends FsmBaseClass {
65
93
  }
66
94
  }
67
95
 
96
+ /**
97
+ * Feed an event to the machine and run the enter/exit cycle until it rests on a
98
+ * leaf (`status & mask`) or finishes.
99
+ *
100
+ * If a dispatch is already running (e.g. an `onEnter` handler dispatches
101
+ * synchronously), the event is queued in `nextEvent` and applied when the current
102
+ * run settles — runs never nest. Returns `false` once the machine has finished,
103
+ * `true` otherwise.
104
+ */
68
105
  async dispatch(event: string): Promise<boolean> {
69
106
  this.nextEvent = event;
70
107
  if (!this.running && !(this.status & STATUS_FINISHED)) {
@@ -77,7 +114,7 @@ export class FsmProcess extends FsmBaseClass {
77
114
  if (this.status & STATUS_EXIT) {
78
115
  await this.state?._runHandler("onExit", this.state);
79
116
  }
80
- if (!this._update()) break;
117
+ if (!(await this._update())) break;
81
118
  if (this.status & STATUS_ENTER) {
82
119
  await this.state?._runHandler("onEnter", this.state);
83
120
  }
@@ -95,6 +132,10 @@ export class FsmProcess extends FsmBaseClass {
95
132
  return !(this.status & STATUS_FINISHED);
96
133
  }
97
134
 
135
+ /**
136
+ * Snapshot the machine to a plain object: `{ status, event, stack }` where the
137
+ * stack is root→leaf, each entry carrying whatever its `dump` hooks recorded.
138
+ */
98
139
  async dump(...args: unknown[]): Promise<FsmProcessDump> {
99
140
  const dumpState = async (state: FsmState) => {
100
141
  const stateDump: FsmStateDump = {
@@ -121,6 +162,11 @@ export class FsmProcess extends FsmBaseClass {
121
162
  return dump;
122
163
  }
123
164
 
165
+ /**
166
+ * Rebuild the machine from a `dump`: recreate each state in the stack (firing
167
+ * `onStateCreate`) and replay its `restore` hooks, leaving the process resumable
168
+ * from where it was snapshotted.
169
+ */
124
170
  async restore(dump: FsmProcessDump, ...args: unknown[]) {
125
171
  this.status = dump.status || 0;
126
172
  this.event = dump.event;
@@ -128,8 +174,8 @@ export class FsmProcess extends FsmBaseClass {
128
174
  for (let i = 0; i < dump.stack.length; i++) {
129
175
  const stateDump = dump.stack[i];
130
176
  this.state = this.state
131
- ? this._newSubstate(this.state, stateDump.key)
132
- : this._newState(undefined, stateDump.key, this.rootDescriptor);
177
+ ? await this._newSubstate(this.state, stateDump.key)
178
+ : await this._newState(undefined, stateDump.key, this.rootDescriptor);
133
179
  await this.state._runHandler(
134
180
  "restore",
135
181
  this.state,
@@ -140,6 +186,7 @@ export class FsmProcess extends FsmBaseClass {
140
186
  return this;
141
187
  }
142
188
 
189
+ /** Primary extension point: fires once for every state the machine creates. */
143
190
  onStateCreate(handler: FsmStateHandler) {
144
191
  return this._addHandler("onStateCreate", handler, true);
145
192
  }
@@ -155,17 +202,20 @@ export class FsmProcess extends FsmBaseClass {
155
202
  this._handleError(error);
156
203
  }
157
204
 
158
- _newState(
205
+ async _newState(
159
206
  parent: FsmState | undefined,
160
207
  key: string,
161
208
  descriptor: FsmStateDescriptor | undefined,
162
209
  ) {
163
210
  const state = new FsmState(this, parent, key, descriptor);
164
- this._runHandlerParallel("onStateCreate", state);
211
+ await this._runHandler("onStateCreate", state);
165
212
  return state;
166
213
  }
167
214
 
168
- _getSubstate(parent: FsmState | undefined, prevStateKey: string | undefined) {
215
+ async _getSubstate(
216
+ parent: FsmState | undefined,
217
+ prevStateKey: string | undefined,
218
+ ) {
169
219
  if (!parent) return;
170
220
  const toState =
171
221
  parent.descriptor?.getTargetStateKey(
@@ -176,7 +226,7 @@ export class FsmProcess extends FsmBaseClass {
176
226
  return this._newSubstate(parent, toState);
177
227
  }
178
228
 
179
- _newSubstate(parent: FsmState | undefined, toState: string) {
229
+ async _newSubstate(parent: FsmState | undefined, toState: string) {
180
230
  let descriptor: FsmStateDescriptor | undefined;
181
231
  for (
182
232
  let state: FsmState | undefined = parent;
@@ -188,14 +238,22 @@ export class FsmProcess extends FsmBaseClass {
188
238
  return this._newState(parent, toState, descriptor);
189
239
  }
190
240
 
191
- _update() {
241
+ /**
242
+ * One step of the traversal: compute the next state and update `status`.
243
+ *
244
+ * Either descends to a child / advances to a resolved target (setting an ENTER
245
+ * status), or — when no target resolves — settles on the current leaf
246
+ * (`STATUS_LEAF`) or pops to the parent (`STATUS_LAST`), reaching `STATUS_FINISHED`
247
+ * once the root is exited. Returns `false` when finished.
248
+ */
249
+ async _update() {
192
250
  if (this.status & STATUS_FINISHED) return false;
193
251
  const nextState =
194
252
  this.status !== STATUS_NONE
195
253
  ? this.status & STATUS_ENTER
196
- ? this._getSubstate(this.state, STATE_INITIAL)
197
- : this._getSubstate(this.state?.parent, this.state?.key)
198
- : this._newState(undefined, this.config.key, this.rootDescriptor);
254
+ ? await this._getSubstate(this.state, STATE_INITIAL)
255
+ : await this._getSubstate(this.state?.parent, this.state?.key)
256
+ : await this._newState(undefined, this.config.key, this.rootDescriptor);
199
257
  if (nextState !== undefined) {
200
258
  this.state = nextState;
201
259
  this.status = this.status & STATUS_EXIT ? STATUS_NEXT : STATUS_FIRST;
@@ -1,11 +1,38 @@
1
+ // Sentinel keys used inside `FsmStateConfig.transitions` tuples. The raw `""` and
2
+ // `"*"` literals are ambiguous at the call site — `["", "start", "Active"]` does not
3
+ // visibly say "from the *initial* state" — so these named constants document intent
4
+ // while keeping the runtime value (a shared empty string / asterisk) identical, which
5
+ // keeps configs plain-serializable.
6
+
7
+ /** Wildcard `from`-state: a transition that applies in *any* state. */
1
8
  export const STATE_ANY = "*";
9
+ /** Empty `from`-state: the *initial* pseudo-state a parent enters into. */
2
10
  export const STATE_INITIAL = "";
11
+ /** Empty `to`-state: the *final* pseudo-state; entering it exits the parent. */
3
12
  export const STATE_FINAL = "";
13
+ /** Wildcard `event`: a transition triggered by *any* event. */
4
14
  export const EVENT_ANY = "*";
15
+ /** Empty event: the eventless/automatic transition (fires with no named event). */
5
16
  export const EVENT_EMPTY = "";
6
17
 
7
18
  export type FsmStateKey = string;
8
19
  export type FsmEventKey = string;
20
+
21
+ /**
22
+ * Declarative definition of a (possibly nested) state machine.
23
+ *
24
+ * One plain-object shape describes an entire HFSM, so machines stay serializable,
25
+ * diffable, and inspectable by tooling — the config is data, not code. A config has:
26
+ * - `key` — the state's name (unique among its siblings);
27
+ * - `transitions` — `[from, event, to]` tuples, where `from`/`to` name sibling
28
+ * states, `""` is the initial (`from`) or final (`to`) pseudo-state, and `"*"` is a
29
+ * wildcard (see the constants above);
30
+ * - `states` — nested child configs; entering this state descends into its initial
31
+ * child. The index signature lets consumers attach arbitrary metadata.
32
+ *
33
+ * Pass a config to `new FsmProcess(config)` or `startProcess(ctx, config, …)`; it is
34
+ * compiled once into an `FsmStateDescriptor` for fast lookup at runtime.
35
+ */
9
36
  export type FsmStateConfig = {
10
37
  key: FsmStateKey;
11
38
  transitions?: [from: FsmStateKey, event: FsmEventKey, to: FsmStateKey][];