{"version":3,"file":"index.mjs","names":[],"sources":["../src/emitter.ts","../src/types.ts","../src/behavioral-fsm.ts","../src/fsm.ts"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype Listener = (...args: any[]) => void;\ntype WildcardListener = (eventName: string, data: unknown) => void;\n\n/**\n * Returned by `on()`. Call `off()` to remove the subscription.\n * Safe to call multiple times — subsequent calls are no-ops because\n * the underlying Set deduplicates membership.\n */\nexport type Subscription = { off(): void };\n\n/**\n * Minimal typed event emitter used internally by Fsm and BehavioralFsm.\n *\n * Two listener categories exist at runtime: named listeners (keyed by event\n * name) and wildcard listeners (keyed as `\"*\"`). The wildcard fires on EVERY\n * emit, regardless of event name, and its callback receives both the event\n * name and the data. Named listeners receive only the data.\n *\n * @typeParam TEventMap - Record mapping event names to their payload types.\n *   Constrains `on()` and `emit()` to matching event/payload pairs.\n */\nexport class Emitter<TEventMap extends Record<string, unknown>> {\n    private listeners = new Map<string, Set<Listener>>();\n\n    /**\n     * Subscribe to a named event or the wildcard.\n     *\n     * Named overload: callback receives only the typed payload.\n     * Wildcard overload (`\"*\"`): callback receives `(eventName, data)` — useful\n     * for proxying all events to another emitter, as Fsm does with its bfsm.\n     *\n     * Wildcard listeners fire BEFORE named listeners. If a wildcard listener\n     * removes a named listener via `off()`, the named listener still fires for\n     * the current emit — Set iteration is not affected by concurrent deletes.\n     *\n     * Returns a `Subscription` whose `off()` removes this specific listener.\n     */\n    on<K extends keyof TEventMap & string>(\n        event: K,\n        cb: (data: TEventMap[K]) => void\n    ): Subscription;\n    on(event: \"*\", cb: WildcardListener): Subscription;\n    on(event: string, cb: Listener): Subscription {\n        let set = this.listeners.get(event);\n        if (!set) {\n            set = new Set();\n            this.listeners.set(event, set);\n        }\n        set.add(cb);\n        return {\n            off: () => {\n                set.delete(cb);\n            },\n        };\n    }\n\n    /**\n     * Emit a named event, notifying wildcard listeners first, then named listeners.\n     *\n     * Wildcard listeners receive `(eventName, data)`; named listeners receive\n     * only `data`. The firing order (wildcards before named) is intentional —\n     * it lets relay listeners (like Fsm's bfsm proxy) observe all events\n     * before specific subscribers react.\n     */\n    emit<K extends keyof TEventMap & string>(event: K, data: TEventMap[K]): void {\n        const wildcards = this.listeners.get(\"*\");\n        if (wildcards) {\n            for (const cb of wildcards) {\n                (cb as WildcardListener)(event, data);\n            }\n        }\n        const named = this.listeners.get(event);\n        if (named) {\n            for (const cb of named) {\n                cb(data);\n            }\n        }\n    }\n\n    /**\n     * Remove all listeners (named and wildcard).\n     *\n     * Existing `Subscription` objects remain valid — their `off()` closures\n     * hold a reference to the now-empty Set, so calling them is harmless.\n     * Called by `dispose()` to prevent memory retention after an FSM shuts down.\n     */\n    clear(): void {\n        this.listeners.clear();\n    }\n}\n","// =============================================================================\n// types.ts — Shared type foundations for machina v6\n//\n// Pure type definitions. No runtime code. Every type here is consumed by\n// behavioral-fsm.ts, fsm.ts, or both. The factory functions (createFsm,\n// createBehavioralFsm) use these as building blocks for their own generics.\n//\n// =============================================================================\n\n// -----------------------------------------------------------------------------\n// Utility types for state/input name extraction\n//\n// These are the inference primitives that power machina's \"zero-ceremony\"\n// type safety. Given a states config object, they extract the state name\n// union and input name union as string literal types.\n// -----------------------------------------------------------------------------\n\n/**\n * Keys on a state object that have special meaning and are NOT input names.\n * Used by InputNamesOf to filter these out when collecting input names.\n */\ntype SpecialStateKeys = \"_onEnter\" | \"_onExit\" | \"_child\" | \"*\";\n\n/**\n * Extracts state names as a string literal union from a states config object.\n *\n * @example\n * ```ts\n * type S = StateNamesOf<{ green: {...}, yellow: {...}, red: {...} }>;\n * // => \"green\" | \"yellow\" | \"red\"\n * ```\n */\nexport type StateNamesOf<TStates> = keyof TStates & string;\n\n/**\n * Extracts input names as a string literal union from a states config object.\n * Collects all handler keys across ALL states, then strips out lifecycle hooks\n * and special keys (_onEnter, _onExit, _child, *).\n *\n * This is what flows into `handle(inputName)` to provide compile-time\n * validation of input names.\n *\n * @example\n * ```ts\n * type I = InputNamesOf<{\n *   idle:    { start: \"running\", reset: fn };\n *   running: { pause: \"paused\", stop: \"idle\" };\n * }>;\n * // => \"start\" | \"reset\" | \"pause\" | \"stop\"\n * ```\n *\n * How it works:\n * 1. `{ [S in keyof TStates]: keyof TStates[S] & string }` — maps each state\n *    to the union of its handler key names\n * 2. `[keyof TStates]` — collapses the mapped type into a flat union of ALL\n *    handler keys across every state\n * 3. `Exclude<..., SpecialStateKeys>` — strips lifecycle/special keys\n */\nexport type InputNamesOf<TStates> = Exclude<\n    { [S in keyof TStates]: keyof TStates[S] & string }[keyof TStates],\n    SpecialStateKeys\n>;\n\n// -----------------------------------------------------------------------------\n// Handler argument object\n//\n// Every handler in machina receives this as its first argument. This replaces\n// the old v5 pattern of binding `this` to the FSM and passing the client as\n// a separate parameter. Benefits:\n//   - Works with arrow functions (no `this` caveat)\n//   - BehavioralFsm and Fsm handler signatures are identical\n//   - Destructure only what you need: tick({ ctx }) { ... }\n//   - Easy to mock in tests: just construct the object\n//\n// Handlers RETURN a state name to trigger a transition (or void/undefined\n// to stay in the current state). This replaces the imperative transition()\n// call and mirrors gen_fsm's {next_state, StateName, NewStateData} pattern.\n// -----------------------------------------------------------------------------\n\n/**\n * The single combined object passed to every handler.\n *\n * Handlers return a state name to transition, or void to stay put.\n * This replaces imperative `transition()` calls — closer to gen_fsm's\n * return-based model and symmetrical with string shorthand handlers.\n *\n * @typeParam TCtx - The context type. For Fsm this is the config-defined\n *   context object. For BehavioralFsm this is the client object itself.\n * @typeParam TStateNames - String literal union of valid state names.\n *   Defaults to `string` for loose usage; the factory functions narrow this\n *   to the actual state names inferred from the config.\n *\n * @example\n * ```ts\n * // Conditional transition — return the target state:\n * timeout({ ctx }) {\n *   if (ctx.tickCount >= 3) return \"yellow\";\n * }\n *\n * // Side effects without transition — return nothing:\n * tick({ ctx }) {\n *   ctx.tickCount++;\n * }\n *\n * // In a catch-all — inputName tells you what was received:\n * \"*\"({ inputName }) {\n *   console.log(`unhandled input: ${inputName}`);\n * }\n * ```\n */\nexport interface HandlerArgs<TCtx, TStateNames extends string = string> {\n    /** The context (Fsm) or client object (BehavioralFsm) */\n    ctx: TCtx;\n\n    /**\n     * The name of the input currently being handled.\n     *\n     * Typed as `string` rather than the inferred input union because:\n     * 1. Inside a named handler you already know the input name\n     * 2. In a catch-all (*) handler it could be anything\n     * 3. Narrowing to the literal per-handler would require complex\n     *    mapped types for zero practical benefit\n     */\n    inputName: string;\n\n    /**\n     * Defer the current input for replay after a future transition.\n     * Erlang's selective receive, in JS form.\n     *\n     * @example\n     * ```ts\n     * // Replay on the next transition to any state\n     * defer();\n     *\n     * // Replay only when entering \"yellow\"\n     * defer({ until: \"yellow\" });\n     * ```\n     */\n    defer(opts?: { until: TStateNames }): void;\n\n    /**\n     * Emit a custom event through the FSM's emitter.\n     * Built-in events (transitioning, transitioned, etc.) are emitted\n     * automatically by the FSM engine — this is for user-defined events.\n     */\n    emit(eventName: string, data?: unknown): void;\n}\n\n// -----------------------------------------------------------------------------\n// Handler function type\n//\n// A single callable type for all handler forms: state input handlers,\n// lifecycle hooks (_onEnter, _onExit), and the catch-all (*).\n//\n// Handlers return a state name to trigger a transition, or void/undefined\n// to stay in the current state. This is the dynamic counterpart to string\n// shorthand — same concept (determine next state), two expressions.\n// -----------------------------------------------------------------------------\n\n/**\n * A function handler for state inputs, lifecycle hooks (_onEnter, _onExit),\n * and catch-all (*) handlers.\n *\n * **Return value determines transition:**\n * - Return a valid state name → FSM transitions to that state\n * - Return void/undefined → FSM stays in the current state\n *\n * This mirrors gen_fsm's `{next_state, StateName, NewStateData}` return.\n * Guards are just `if` statements. Actions are just code before the return.\n *\n * The `...extra` rest parameter captures additional arguments passed through\n * `handle(inputName, ...extraArgs)`. These are untyped (`unknown[]`) because\n * correlating per-input arg types with handle() call sites would require\n * prohibitively complex mapped types for minimal benefit.\n *\n * @example\n * ```ts\n * // Side effects only, no transition:\n * tick({ ctx }) { ctx.tickCount++; }\n *\n * // Conditional transition (replaces guard + target):\n * timeout({ ctx }) {\n *   if (ctx.tickCount >= 3) return \"yellow\";\n * }\n *\n * // Unconditional transition with side effect (replaces action + target):\n * timeout({ ctx }) {\n *   console.log(\"transitioning after\", ctx.tickCount, \"ticks\");\n *   return \"yellow\";\n * }\n *\n * // Handler with extra args passed via handle(\"success\", responseData):\n * success({ ctx }, data) { ctx.result = data; }\n * ```\n */\nexport type HandlerFn<TCtx, TStateNames extends string = string> = (\n    args: HandlerArgs<TCtx, TStateNames>,\n    ...extra: unknown[]\n) => TStateNames | void;\n\n// -----------------------------------------------------------------------------\n// Handler definition forms\n//\n// A handler property on a state object is one of two things:\n//   1. A string — auto-transition shorthand: `timeout: \"yellow\"`\n//   2. A function — returns target state or void: `tick({ ctx }) { ... }`\n//\n// Two forms, one concept: \"a handler determines the next state.\"\n// String is the static case, function is the dynamic case.\n//\n// The FSM engine checks typeof at runtime: \"string\" → immediate transition,\n// \"function\" → call it and transition if it returns a state name.\n// -----------------------------------------------------------------------------\n\n/**\n * The union of valid handler definition forms for a state input.\n *\n * - `TStateNames` — string shorthand, auto-transitions to that state\n * - `HandlerFn` — function that returns a state name (transition) or void (stay)\n *\n * @example\n * ```ts\n * states: {\n *   green: {\n *     timeout: \"yellow\",                    // string shorthand\n *     tick({ ctx }) { ctx.tickCount++; },   // function, no transition\n *     emergency({ ctx }) {                  // function, conditional transition\n *       if (ctx.severity > 5) return \"red\";\n *     },\n *   },\n * }\n * ```\n */\n/**\n * The union of valid handler definition forms for a state input.\n *\n * - `TStateNames` — string shorthand, auto-transitions to that state\n * - `HandlerFn` — function that returns a state name (transition) or void (stay)\n * - `MachinaInstance` — included to satisfy TypeScript's structural widening\n *   when `ValidateStates` falls back to its constraint type. The per-key\n *   restriction on `_child` is still enforced by `ValidateStates`; this\n *   union member just prevents the inference engine from rejecting\n *   `_child: childFsm` before the conditional mapping can evaluate it.\n *\n * @example\n * ```ts\n * states: {\n *   green: {\n *     timeout: \"yellow\",                    // string shorthand\n *     tick({ ctx }) { ctx.tickCount++; },   // function, no transition\n *     emergency({ ctx }) {                  // function, conditional transition\n *       if (ctx.severity > 5) return \"red\";\n *     },\n *   },\n * }\n * ```\n */\nexport type HandlerDef<TCtx, TStateNames extends string = string> =\n    | TStateNames\n    | HandlerFn<TCtx, TStateNames>\n    | MachinaInstance;\n\n// -----------------------------------------------------------------------------\n// State validation\n//\n// ValidateStates is the mapped type that makes config-inferred type safety\n// work. It re-maps the user's states object, constraining each property to\n// the correct type based on its key name. This is where typos in string\n// shorthand targets get caught at compile time.\n//\n// The key trick: `keyof TStates & string` is self-referential — it derives\n// the state name union FROM the same states object being validated. So when\n// a user writes `timeout: \"yellw\"`, TypeScript checks \"yellw\" against the\n// actual state keys and reports the error.\n// -----------------------------------------------------------------------------\n\n/**\n * Validates and constrains the states object at the type level.\n *\n * This is a mapped type that walks every state and every property within\n * each state, assigning the correct expected type based on the property key:\n *\n * | Key              | Expected type                           |\n * |------------------|-----------------------------------------|\n * | `_onEnter`       | HandlerFn (lifecycle hook)              |\n * | `_onExit`        | HandlerFn (lifecycle hook)              |\n * | `_child`         | MachinaInstance (Fsm or BehavioralFsm)  |\n * | `*`              | HandlerFn (catch-all)                   |\n * | anything else    | HandlerDef (string or fn)               |\n *\n * @typeParam TCtx - Context/client type, flows into handler signatures\n * @typeParam TStates - The literal states object type captured by the\n *   factory function's generic parameter\n */\nexport type ValidateStates<TCtx, TStates extends Record<string, Record<string, unknown>>> = {\n    [S in keyof TStates]: {\n        [K in keyof TStates[S]]: K extends \"_onEnter\" | \"_onExit\"\n            ? HandlerFn<TCtx, keyof TStates & string>\n            : K extends \"_child\"\n              ? MachinaInstance\n              : K extends \"*\"\n                ? HandlerFn<TCtx, keyof TStates & string>\n                : HandlerDef<TCtx, keyof TStates & string>;\n    };\n};\n\n// -----------------------------------------------------------------------------\n// FSM configuration\n//\n// The config shape passed to createFsm() and createBehavioralFsm().\n// Both factory functions share this type — the difference is in how TCtx\n// is resolved:\n//   - createFsm: TCtx inferred from the `context` property\n//   - createBehavioralFsm: TCtx is the client type (context property ignored)\n// -----------------------------------------------------------------------------\n\n/**\n * Configuration object for creating an FSM.\n *\n * @typeParam TCtx - The context type (Fsm) or client type (BehavioralFsm).\n *   For Fsm, this is inferred from the `context` property. For BehavioralFsm,\n *   it's the client object type provided explicitly or as a generic parameter.\n *\n * @typeParam TStates - The literal states object type. Captured by the factory\n *   function's generic parameter (ideally with `const` to preserve string\n *   literal types). Defaults to a loose record for unconstrained usage.\n *\n * @example\n * ```ts\n * // TCtx inferred as { tickCount: number }, TStates inferred from states object:\n * createFsm({\n *   id: \"traffic-light\",\n *   initialState: \"green\",         // validated against state keys\n *   context: { tickCount: 0 },     // inference site for TCtx\n *   states: {\n *     green:  { timeout: \"yellow\" }, // \"yellow\" validated against state keys\n *     yellow: { timeout: \"red\" },\n *     red:    { timeout: \"green\" },\n *   },\n * });\n * ```\n */\nexport interface FsmConfig<\n    TCtx,\n    TStates extends Record<string, Record<string, unknown>> = Record<\n        string,\n        Record<string, unknown>\n    >,\n> {\n    /** Unique identifier for this FSM */\n    id: string;\n\n    /**\n     * The state to start in. Must be a key of `states`.\n     *\n     * Wrapped in NoInfer to prevent TypeScript from using this value as an\n     * inference site for TStates. Without it, `initialState: \"green\"` could\n     * narrow TStates to only have a \"green\" key. We want inference to come\n     * exclusively from the `states` property.\n     */\n    initialState: NoInfer<keyof TStates & string>;\n\n    /**\n     * Initial context data. The type is inferred from this value and flows\n     * into every handler's `ctx` parameter.\n     *\n     * For BehavioralFsm, this property is optional and serves only as a\n     * type constraint — the client object IS the context.\n     */\n    context?: TCtx;\n\n    /** State definitions. Keys become the state name union. */\n    states: ValidateStates<TCtx, TStates>;\n}\n\n// -----------------------------------------------------------------------------\n// Type discriminant — runtime distinguishing of Fsm vs BehavioralFsm\n//\n// Used internally by the ChildLink adapter to normalize delegation calls\n// without introducing circular imports. Not exported to users.\n// -----------------------------------------------------------------------------\n\n/**\n * Symbol used as a property key to identify machina FSM instances at runtime.\n * Each class stamps itself with a MachinaType value so the ChildLink adapter\n * can dispatch handle()/canHandle()/reset() correctly without circular imports.\n */\nexport const MACHINA_TYPE = Symbol(\"machina.type\");\n\n/**\n * Discriminant values stamped onto FSM instances via `MACHINA_TYPE`.\n * Used by the `ChildLink` adapter to dispatch calls correctly without\n * importing either class directly (which would create circular dependencies).\n */\nexport type MachinaType = \"Fsm\" | \"BehavioralFsm\";\n\n/** Structural type matching any machina FSM instance (Fsm or BehavioralFsm) */\nexport type MachinaInstance = { readonly [MACHINA_TYPE]: MachinaType };\n\n// -----------------------------------------------------------------------------\n// ChildLink — internal adapter interface\n//\n// Normalizes Fsm (no client arg) vs BehavioralFsm (client arg) delegation.\n// The BehavioralFsm engine uses this internally; never exported to users.\n// -----------------------------------------------------------------------------\n\n/**\n * Internal adapter that wraps either an Fsm or BehavioralFsm child,\n * presenting a uniform API for parent-initiated delegation.\n */\nexport interface ChildLink {\n    /** Check if the child's current state can handle this input */\n    canHandle(client: object, inputName: string): boolean;\n    /** Dispatch the input to the child */\n    handle(client: object, inputName: string, ...args: unknown[]): void;\n    /** Reset the child to its initialState */\n    reset(client: object): void;\n    /** Subscribe to all child events (wildcard). Returns unsubscribe fn. */\n    onAny(callback: (eventName: string, data: unknown) => void): { off(): void };\n    /** The child FSM's compositeState for the given client */\n    compositeState(client: object): string;\n    /**\n     * Silently place `client` at the given composite state within the child hierarchy.\n     * Throws for Fsm children (no per-client state to rehydrate).\n     */\n    rehydrate(client: object, compositeState: string): void;\n    /** Dispose the child FSM */\n    dispose(): void;\n    /**\n     * The raw Fsm or BehavioralFsm instance this ChildLink wraps.\n     * Exposed for inspection tooling (machina-inspect) — allows external\n     * tools to introspect child graph structure without reaching through\n     * private fields.\n     */\n    instance: MachinaInstance;\n}\n\n/**\n * Options for FSM disposal.\n */\nexport interface DisposeOptions {\n    /**\n     * When true, child FSMs declared via _child are NOT disposed.\n     * Default: false (children ARE disposed along with the parent).\n     */\n    preserveChildren?: boolean;\n}\n\n// -----------------------------------------------------------------------------\n// Built-in FSM event maps\n//\n// machina FSMs emit lifecycle events that external code can subscribe to.\n// These types define the payload shape for each built-in event. Custom\n// events (emitted via emit() in handlers) are untyped — they flow through\n// the emitter's wildcard path with `unknown` payloads.\n//\n// Event naming follows a grammatical pattern:\n//   - Present participle = \"about to happen\": transitioning, handling\n//   - Past participle = \"just happened\": transitioned, handled\n// -----------------------------------------------------------------------------\n\n/**\n * Built-in event map for Fsm instances.\n * Payloads do NOT include a client reference (Fsm is its own client).\n *\n * @typeParam TStateNames - The state name union, flows into transition\n *   event payloads so fromState/toState are narrowed to actual state names.\n */\nexport interface FsmEventMap<TStateNames extends string = string> {\n    /** Fired just before a state transition occurs */\n    transitioning: { fromState: TStateNames; toState: TStateNames };\n\n    /** Fired just after a state transition completes */\n    transitioned: { fromState: TStateNames; toState: TStateNames };\n\n    /** Fired when an input is about to be dispatched to a handler */\n    handling: { inputName: string };\n\n    /** Fired after an input has been successfully handled */\n    handled: { inputName: string };\n\n    /** Fired when an input has no matching handler in the current state */\n    nohandler: { inputName: string; args: unknown[] };\n\n    /** Fired when a transition targets a state that doesn't exist */\n    invalidstate: { stateName: string };\n\n    /** Fired when an input is deferred for later replay */\n    deferred: { inputName: string };\n}\n\n/**\n * Built-in event map for BehavioralFsm instances.\n * Every payload is intersected with `{ client: TClient }` so subscribers\n * can identify which client the event pertains to.\n *\n * @typeParam TClient - The client object type\n * @typeParam TStateNames - The state name union\n */\nexport type BehavioralFsmEventMap<TClient, TStateNames extends string = string> = {\n    [K in keyof FsmEventMap<TStateNames>]: FsmEventMap<TStateNames>[K] & {\n        client: TClient;\n    };\n};\n\n// -----------------------------------------------------------------------------\n// Internal per-client metadata\n//\n// BehavioralFsm tracks per-client state in a WeakMap<TClient, ClientMeta>.\n// When the client object is garbage collected, its metadata goes with it.\n// This replaces v5's __machina__ property stamping on client objects.\n// -----------------------------------------------------------------------------\n\n/**\n * A deferred input queue entry. Created when a handler calls\n * deferUntilTransition() — the input is stored here and replayed\n * after a future state transition.\n */\nexport interface DeferredInput {\n    /** The input name that was deferred */\n    inputName: string;\n\n    /** The original arguments passed to handle() for this input */\n    args: unknown[];\n\n    /**\n     * If set, only replay when entering this specific state.\n     * When undefined, replays on the next transition to any state.\n     */\n    untilState?: string;\n}\n\n/**\n * Internal metadata stored per client in the WeakMap.\n * This is the bookkeeping the FSM engine needs — NOT user-facing data.\n *\n * @typeParam TStateNames - The state name union. The `state` field is\n *   typed to this so internal code gets compile-time validation.\n */\nexport interface ClientMeta<TStateNames extends string = string> {\n    /** The client's current state */\n    state: TStateNames;\n\n    /** Queue of inputs deferred for later replay */\n    deferredQueue: DeferredInput[];\n\n    /**\n     * The args array for the currently-executing handle() call.\n     * Captured before handler dispatch so that deferUntilTransition()\n     * can snapshot them for later replay. Cleared after dispatch.\n     */\n    currentActionArgs?: unknown[];\n}\n","/* eslint-disable @typescript-eslint/no-explicit-any */\n// =============================================================================\n// behavioral-fsm.ts — The core FSM engine\n//\n// BehavioralFsm defines behavior (states + transitions) while tracking state\n// externally per-client via a WeakMap. One FSM definition can drive any number\n// of independent client objects.\n//\n// =============================================================================\n\nimport { Emitter, type Subscription } from \"./emitter\";\nimport {\n    MACHINA_TYPE,\n    type FsmConfig,\n    type StateNamesOf,\n    type InputNamesOf,\n    type HandlerArgs,\n    type HandlerFn,\n    type BehavioralFsmEventMap,\n    type ClientMeta,\n    type DeferredInput,\n    type ChildLink,\n    type DisposeOptions,\n} from \"./types\";\n\n// Safety valve for _onEnter → transition loops. Instance-level counter works\n// because the engine is synchronous — only one transition chain is active at\n// a time. Throws on overflow, then resets so the FSM isn't permanently broken.\nconst MAX_TRANSITION_DEPTH = 20;\n\n/**\n * Defines FSM behavior (states + transitions) while tracking per-client state\n * in a `WeakMap`. A single `BehavioralFsm` instance can drive any number of\n * independent client objects simultaneously — each gets its own state,\n * deferred queue, and lifecycle.\n *\n * Prefer `createBehavioralFsm()` over constructing this directly — the factory\n * infers all generic parameters from the config object.\n *\n * All public methods silently no-op after `dispose()` is called.\n *\n * @typeParam TClient - The client object type. Must be an object (non-primitive)\n *   so it can serve as a WeakMap key.\n * @typeParam TStateNames - String literal union of valid state names.\n * @typeParam TInputNames - String literal union of valid input names.\n */\nexport class BehavioralFsm<\n    TClient extends object,\n    TStateNames extends string,\n    TInputNames extends string,\n> {\n    readonly id: string;\n    readonly initialState: TStateNames;\n    // Type discriminant — lets ChildLink adapter identify this at runtime\n    readonly [MACHINA_TYPE] = \"BehavioralFsm\" as const;\n    // Public so inspection tooling (machina-inspect) can read the state graph\n    // without private field access. The states object is mutated by wrapChildLinks()\n    // at construction time — _child values become ChildLink wrappers in-place.\n    readonly states: Record<string, Record<string, unknown>>;\n    private readonly emitter = new Emitter<BehavioralFsmEventMap<TClient, TStateNames>>();\n    private readonly clients = new WeakMap<TClient, ClientMeta<TStateNames>>();\n    // Tracks all initialized clients so the Fsm-child nohandler listener can\n    // find which clients need bubbling (Fsm events have no client in payload).\n    // WeakRef prevents retention; clients clean themselves up naturally.\n    private readonly knownClients: Set<WeakRef<TClient>> = new Set();\n    // Subscriptions to child FSM wildcard events, keyed by state name.\n    // Set up once during construction, torn down in dispose().\n    private readonly childSubscriptions: Array<{ off(): void }> = [];\n    private disposed = false;\n    private transitionDepth = 0;\n\n    constructor(config: FsmConfig<TClient, Record<string, Record<string, unknown>>>) {\n        this.id = config.id;\n        this.initialState = config.initialState as TStateNames;\n        this.states = config.states as Record<string, Record<string, unknown>>;\n        this.wrapChildLinks();\n        this.setupChildSubscriptions();\n    }\n\n    // -------------------------------------------------------------------------\n    // Public API\n    // -------------------------------------------------------------------------\n\n    /**\n     * Dispatch an input to the given client's current state handler.\n     *\n     * Delegation order: if the current state has a `_child` FSM that can\n     * handle the input, it is dispatched there. If the child emits `nohandler`,\n     * the input bubbles up to this FSM's local handler. If no handler exists\n     * here either, `nohandler` is emitted on this FSM's emitter.\n     *\n     * No-ops silently when disposed.\n     */\n    handle(client: TClient, inputName: TInputNames, ...args: unknown[]): void {\n        if (this.disposed) {\n            return;\n        }\n\n        const meta = this.getOrCreateClientMeta(client);\n        meta.currentActionArgs = args;\n\n        // Delegation: if the current state has a _child and the child can\n        // handle this input, send it there. Otherwise fall through to\n        // handleLocally(). No nohandler emitted for the delegation path.\n        const stateObj = this.states[meta.state];\n        const childLink = stateObj?._child as ChildLink | undefined;\n        if (childLink) {\n            if (childLink.canHandle(client, inputName)) {\n                try {\n                    childLink.handle(client, inputName, ...args);\n                } finally {\n                    // Clear args even if the child handler throws — stale args\n                    // on meta would corrupt subsequent handle() calls for this client.\n                    meta.currentActionArgs = undefined;\n                }\n                return;\n            }\n        }\n\n        this.handleLocally(client, inputName, args, meta);\n    }\n\n    /**\n     * Returns true if the client's current state has a handler for `inputName`\n     * (or a catch-all `\"*\"` handler). Does NOT initialize the client — no\n     * `_onEnter`, no events, no side effects. Unseen clients are treated as\n     * if they were already in `initialState`. Returns false when disposed.\n     */\n    canHandle(client: TClient, inputName: string): boolean {\n        if (this.disposed) {\n            return false;\n        }\n        // Does NOT initialize the client. We want a pure state check —\n        // no side effects, no _onEnter, no events. Use initialState as the\n        // fallback for unseen clients (they'd start there anyway).\n        const state = this.clients.get(client)?.state ?? this.initialState;\n        const stateObj = this.states[state];\n        return !!(stateObj?.[inputName] ?? stateObj?.[\"*\"]);\n    }\n\n    /**\n     * Transition the client back to `initialState`, firing `_onEnter` and\n     * lifecycle events as if entering it fresh. No-ops when disposed.\n     */\n    reset(client: TClient): void {\n        if (this.disposed) {\n            return;\n        }\n        this.transition(client, this.initialState);\n    }\n\n    /**\n     * Returns the client's current state, or `undefined` if the client has\n     * never been initialized (i.e. `handle()`, `transition()`, or `reset()`\n     * have never been called for it). Does NOT trigger initialization.\n     */\n    currentState(client: TClient): TStateNames | undefined {\n        // Intentionally uses WeakMap.get() directly — does NOT trigger initialization.\n        // Returns undefined for clients the FSM has never seen.\n        return this.clients.get(client)?.state;\n    }\n\n    /**\n     * Directly transition `client` to `toState`, running the full lifecycle:\n     * `_onExit` for the current state → `transitioning` event → update state →\n     * `_onEnter` for new state → `transitioned` event → child reset → deferred\n     * queue replay → bounce (if `_onEnter` returned a state name).\n     *\n     * Same-state transitions are silently ignored. Transitions to unknown state\n     * names emit `invalidstate` instead of throwing. Throws if the transition\n     * depth exceeds `MAX_TRANSITION_DEPTH` (likely an `_onEnter` → transition loop).\n     *\n     * No-ops when disposed.\n     */\n    transition(client: TClient, toState: TStateNames): void {\n        if (this.disposed) {\n            return;\n        }\n\n        const meta = this.getOrCreateClientMeta(client);\n        const fromState = meta.state;\n\n        if (toState === fromState) {\n            return;\n        }\n\n        if (!(toState in this.states)) {\n            this.emitter.emit(\"invalidstate\", { stateName: toState, client });\n            return;\n        }\n\n        this.transitionDepth++;\n        if (this.transitionDepth > MAX_TRANSITION_DEPTH) {\n            this.transitionDepth = 0;\n            throw new Error(\n                `Max transition depth (${MAX_TRANSITION_DEPTH}) exceeded in FSM \"${this.id}\". ` +\n                    \"Likely an infinite _onEnter → transition loop.\"\n            );\n        }\n\n        try {\n            const curStateObj = this.states[fromState];\n            const newStateObj = this.states[toState];\n\n            // _onExit for current state. The optional chain handles two cases:\n            // 1. First-time initialization — fromState is `undefined as TStateNames`,\n            //    so this.states[undefined] is undefined; no exit hook to run.\n            // 2. States that simply have no _onExit defined — equally valid, equally ignored.\n            if (curStateObj?._onExit && typeof curStateObj._onExit === \"function\") {\n                const exitArgs = this.buildHandlerArgs(client, \"\", meta);\n                (curStateObj._onExit as HandlerFn<TClient, TStateNames>)(exitArgs);\n                // _onExit return value is intentionally ignored — you're already leaving\n            }\n\n            meta.state = toState;\n\n            const payload = { fromState, toState, client };\n            this.emitter.emit(\"transitioning\", payload);\n\n            // _onEnter for new state — return value is a bounce target\n            let bounceTarget: TStateNames | void = undefined;\n            if (newStateObj?._onEnter && typeof newStateObj._onEnter === \"function\") {\n                const enterArgs = this.buildHandlerArgs(client, \"\", meta);\n                bounceTarget = (newStateObj._onEnter as HandlerFn<TClient, TStateNames>)(enterArgs);\n            }\n\n            this.emitter.emit(\"transitioned\", payload);\n\n            // Reset child FSM after entering the new state. This ensures the child\n            // always starts from its initialState when the parent enters. Happens\n            // after _onEnter and transitioned but before deferred queue processing,\n            // so deferred inputs see the post-reset child state.\n            const childLink = newStateObj?._child as ChildLink | undefined;\n            if (childLink) {\n                childLink.reset(client);\n            }\n\n            // Replay deferred inputs targeting this state\n            this.processQueue(client, meta);\n\n            // Bounce: _onEnter returned a state name. Only fires if we're still\n            // in the state _onEnter belongs to — a deferred replay might have\n            // already moved us elsewhere.\n            if (typeof bounceTarget === \"string\" && meta.state === toState) {\n                this.transition(client, bounceTarget);\n            }\n        } finally {\n            this.transitionDepth--;\n        }\n    }\n\n    /**\n     * Returns the client's state as a dot-delimited path including any active\n     * child FSM states (e.g. `\"active.connecting.retrying\"`). Returns just the\n     * current state name when no child is active. Returns `\"\"` for clients that\n     * have never been initialized (unlike `currentState()` which returns `undefined`).\n     */\n    compositeState(client: TClient): string {\n        const meta = this.clients.get(client);\n        if (!meta) {\n            // Returns \"\" (not undefined like currentState()) because compositeState\n            // produces dot-delimited paths (\"stateA.child.grandchild\") for hierarchies.\n            // Empty string is the correct \"nothing to report\" sentinel for string concat.\n            return \"\";\n        }\n\n        const stateObj = this.states[meta.state];\n        const childLink = stateObj?._child as ChildLink | undefined;\n        if (childLink) {\n            const childComposite = childLink.compositeState(client);\n            if (childComposite) {\n                return `${meta.state}.${childComposite}`;\n            }\n        }\n\n        return meta.state;\n    }\n\n    /**\n     * Silently place `client` at `compositeState` with no lifecycle activity.\n     * Designed to work with `compositeState()`, which produces the dot-path\n     * string that `rehydrate()` consumes.\n     *\n     * No `_onEnter`, no `_onExit`, no `transitioning`/`transitioned` events.\n     * If `compositeState` is a dot-delimited path (`\"active.connecting\"`), the client\n     * is placed at each level of the hierarchy in turn. Subsequent `handle()` calls\n     * proceed as if the client had reached that state through normal transitions.\n     *\n     * Throws synchronously for unknown state names, missing `_child` at an inner level,\n     * or Fsm children in the hierarchy (Fsm owns its context; nothing to rehydrate there).\n     *\n     * No-ops silently when disposed.\n     */\n    rehydrate(client: TClient, compositeState: string): void {\n        if (this.disposed) {\n            return;\n        }\n\n        const [state, ...rest] = compositeState.split(\".\");\n\n        if (!(state in this.states)) {\n            throw new Error(\n                `rehydrate: unknown state \"${state}\" in FSM \"${this.id}\". ` +\n                    `Valid states: ${Object.keys(this.states).join(\", \")}`\n            );\n        }\n\n        // Validate and delegate to children BEFORE writing to the parent WeakMap.\n        // This ensures a throw mid-hierarchy doesn't leave a half-registered client.\n        if (rest.length > 0) {\n            const childPath = rest.join(\".\");\n            const stateObj = this.states[state];\n            const childLink = stateObj?._child as ChildLink | undefined;\n\n            if (!childLink) {\n                throw new Error(\n                    `rehydrate: state \"${state}\" in FSM \"${this.id}\" has no _child, ` +\n                        `but composite path \"${compositeState}\" requires one.`\n                );\n            }\n\n            childLink.rehydrate(client, childPath);\n        }\n\n        // Guard knownClients before writing meta — if the client is already tracked,\n        // skip adding another WeakRef to avoid accumulating duplicate live refs.\n        if (!this.clients.has(client)) {\n            this.knownClients.add(new WeakRef(client));\n        }\n        this.clients.set(client, { state: state as TStateNames, deferredQueue: [] });\n    }\n\n    /**\n     * Subscribe to a built-in lifecycle event or the wildcard.\n     *\n     * Named overload: typed payload includes `{ client: TClient }` so you can\n     * identify which client the event pertains to. Wildcard (`\"*\"`) receives\n     * `(eventName, data)` for every event. Returns a no-op `Subscription`\n     * when disposed.\n     */\n    on<K extends keyof BehavioralFsmEventMap<TClient, TStateNames> & string>(\n        eventName: K,\n        callback: (data: BehavioralFsmEventMap<TClient, TStateNames>[K]) => void\n    ): Subscription;\n    on(eventName: \"*\", callback: (eventName: string, data: unknown) => void): Subscription;\n    on(eventName: string, callback: (...args: any[]) => void): Subscription {\n        if (this.disposed) {\n            return { off() {} };\n        }\n        return this.emitter.on(eventName as any, callback as any);\n    }\n\n    /**\n     * Emit a custom event through the FSM. Built-in lifecycle events are\n     * emitted automatically — this is for user-defined events from handlers.\n     * No-ops when disposed.\n     */\n    emit(eventName: string, data?: unknown): void {\n        if (this.disposed) {\n            return;\n        }\n        // Public emit is for user-defined custom events. Built-in events are\n        // emitted automatically by the engine.\n        (this.emitter as any).emit(eventName, data);\n    }\n\n    /**\n     * Permanently shut down this FSM. Irreversible — all subsequent method\n     * calls become silent no-ops. Tears down child subscriptions, clears all\n     * listeners, and cascades disposal to child FSMs (unless `preserveChildren`\n     * is set). The same child appearing in multiple states is disposed once.\n     */\n    dispose(options?: DisposeOptions): void {\n        this.disposed = true;\n        // Tear down all child wildcard subscriptions before clearing our emitter.\n        for (const sub of this.childSubscriptions) {\n            sub.off();\n        }\n        // Cascade disposal to child FSMs unless explicitly opted out.\n        // Deduplication via Set handles the same child appearing in multiple states.\n        if (!options?.preserveChildren) {\n            const seen = new Set<ChildLink>();\n            for (const stateName of Object.keys(this.states)) {\n                const childLink = this.states[stateName]?._child as ChildLink | undefined;\n                if (childLink && !seen.has(childLink)) {\n                    seen.add(childLink);\n                    childLink.dispose();\n                }\n            }\n        }\n        this.emitter.clear();\n        // WeakMap entries are GC'd naturally — can't iterate, don't need to\n    }\n\n    // -------------------------------------------------------------------------\n    // Internal\n    // -------------------------------------------------------------------------\n\n    /**\n     * Walks all states at construction time, detects raw FSM instances assigned\n     * to _child, and wraps them into ChildLink adapters via createChildLink().\n     * Must run BEFORE setupChildSubscriptions() so the subscriptions see\n     * ChildLink objects, not raw FSM instances.\n     */\n    private wrapChildLinks(): void {\n        for (const stateName of Object.keys(this.states)) {\n            const stateObj = this.states[stateName];\n            const rawChild = stateObj?._child;\n            if (!rawChild) {\n                continue;\n            }\n            if (typeof rawChild !== \"object\") {\n                throw new Error(\n                    `State \"${stateName}\"._child: expected an Fsm or BehavioralFsm instance, got ${String(rawChild)}`\n                );\n            }\n            if (!(MACHINA_TYPE in rawChild)) {\n                throw new Error(\n                    `State \"${stateName}\"._child: expected an Fsm or BehavioralFsm instance, got a plain object`\n                );\n            }\n            stateObj._child = createChildLink(rawChild);\n        }\n    }\n\n    /**\n     * Walks all states at construction time, finds states with _child, and\n     * subscribes once to each unique child's wildcard events. Subscriptions are\n     * stored for cleanup in dispose(). We deduplicate by child reference to\n     * avoid double-subscribing when the same child appears in multiple states.\n     */\n    private setupChildSubscriptions(): void {\n        const seenChildren = new Set<ChildLink>();\n\n        for (const stateName of Object.keys(this.states)) {\n            const stateObj = this.states[stateName];\n            const childLink = stateObj?._child as ChildLink | undefined;\n\n            if (!childLink || seenChildren.has(childLink)) {\n                continue;\n            }\n            seenChildren.add(childLink);\n\n            // Subscribe to all child events. We use the wildcard so we get\n            // every event type in a single listener.\n            const sub = childLink.onAny((eventName: string, data: unknown) => {\n                // Nohandler from child = child couldn't handle the input.\n                // Re-dispatch to parent via handleLocally() (not handle(), to\n                // avoid re-entering the delegation path and looping).\n                if (eventName === \"nohandler\") {\n                    const payload = data as {\n                        inputName: string;\n                        args: unknown[];\n                        client?: TClient;\n                    };\n\n                    if (payload.client !== undefined) {\n                        // BehavioralFsm child: payload includes the client.\n                        // Filter stale events: only bubble if this client is\n                        // currently in a state that has this child.\n                        this.bubbleNohandler(\n                            payload.client,\n                            childLink,\n                            payload.inputName,\n                            payload.args ?? []\n                        );\n                    } else {\n                        // Fsm child: single-client, no client in payload.\n                        // Walk all known clients and bubble for any that are\n                        // currently in a state with this child.\n                        for (const ref of this.knownClients) {\n                            const client = ref.deref();\n                            if (client === undefined) {\n                                // GC'd — clean up the dead ref\n                                this.knownClients.delete(ref);\n                                continue;\n                            }\n                            this.bubbleNohandler(\n                                client,\n                                childLink,\n                                payload.inputName,\n                                payload.args ?? []\n                            );\n                        }\n                    }\n                    return;\n                }\n\n                // All other child events: only relay if at least one client\n                // is currently in a parent state that delegates to this child.\n                // Prevents stale events from leaking through the parent emitter\n                // when the child fires during construction or after the parent\n                // has moved to a different state.\n                const payload = data as Record<string, unknown> | undefined;\n                if (payload && typeof payload === \"object\" && \"client\" in payload) {\n                    // BehavioralFsm child: payload includes the client.\n                    if (this.isChildActiveForClient(payload.client as TClient, childLink)) {\n                        (this.emitter as any).emit(eventName, data);\n                    }\n                } else {\n                    // Fsm child (or payload without client): walk known clients,\n                    // relay if ANY client is currently in a state with this child.\n                    for (const ref of this.knownClients) {\n                        const client = ref.deref();\n                        if (!client) {\n                            this.knownClients.delete(ref);\n                            continue;\n                        }\n                        if (this.isChildActiveForClient(client, childLink)) {\n                            (this.emitter as any).emit(eventName, data);\n                            break; // one match is enough — relay once\n                        }\n                    }\n                }\n            });\n\n            this.childSubscriptions.push(sub);\n        }\n    }\n\n    /**\n     * Bubbles a child nohandler to the parent for the given client.\n     * Only fires if the client is currently in a state that has this childLink.\n     * Extracted from the lambda in setupChildSubscriptions to keep it readable.\n     */\n    private bubbleNohandler(\n        client: TClient,\n        childLink: ChildLink,\n        inputName: string,\n        args: unknown[]\n    ): void {\n        if (!this.isChildActiveForClient(client, childLink)) {\n            return;\n        }\n        // Safe to assert — isChildActiveForClient confirmed meta exists AND\n        // the client is in a state whose _child matches childLink.\n        const meta = this.clients.get(client)!;\n        meta.currentActionArgs = args;\n        this.handleLocally(client, inputName as TInputNames, args, meta);\n    }\n\n    /**\n     * Returns true if the given client is currently in a parent state whose\n     * _child is the specified childLink. Returns false if the client has no\n     * meta (never initialized) or is in a state with a different (or no) child.\n     */\n    private isChildActiveForClient(client: TClient, childLink: ChildLink): boolean {\n        const meta = this.clients.get(client);\n        if (!meta) {\n            return false;\n        }\n        const parentStateObj = this.states[meta.state];\n        return parentStateObj?._child === childLink;\n    }\n\n    /**\n     * The inner handler dispatch — no delegation, no initialization side effects\n     * beyond what getOrCreateClientMeta already did. Called by handle() after\n     * the delegation check, and by the nohandler child listener for bubbling.\n     */\n    private handleLocally(\n        client: TClient,\n        inputName: TInputNames | string,\n        args: unknown[],\n        meta: ClientMeta<TStateNames>\n    ): void {\n        const stateObj = this.states[meta.state];\n        const handler = stateObj?.[inputName] ?? stateObj?.[\"*\"];\n\n        if (!handler) {\n            this.emitter.emit(\"nohandler\", { inputName: inputName as string, args, client });\n            meta.currentActionArgs = undefined;\n            return;\n        }\n\n        try {\n            this.emitter.emit(\"handling\", { inputName: inputName as string, client });\n\n            const handlerArgs = this.buildHandlerArgs(client, inputName as string, meta);\n            let targetState: TStateNames | void = undefined;\n\n            if (typeof handler === \"string\") {\n                targetState = handler as TStateNames;\n            } else if (typeof handler === \"function\") {\n                targetState = (handler as HandlerFn<TClient, TStateNames>)(handlerArgs, ...args);\n            }\n\n            this.emitter.emit(\"handled\", { inputName: inputName as string, client });\n\n            if (typeof targetState === \"string\") {\n                this.transition(client, targetState);\n            }\n        } finally {\n            meta.currentActionArgs = undefined;\n        }\n    }\n\n    private getOrCreateClientMeta(client: TClient): ClientMeta<TStateNames> {\n        let meta = this.clients.get(client);\n        if (meta) {\n            return meta;\n        }\n\n        // State starts as undefined so transition()'s same-state check passes\n        // (undefined !== initialState). The transition immediately sets state\n        // to initialState before returning, so any code that triggered\n        // initialization (handle/reset/transition) sees the correct state.\n        // currentState() for uninitialized clients still returns undefined —\n        // it reads the WeakMap directly without triggering init.\n        meta = {\n            state: undefined as unknown as TStateNames,\n            deferredQueue: [],\n        };\n        this.clients.set(client, meta);\n        // Track this client weakly so Fsm-child nohandler listeners can find\n        // which clients to bubble to (Fsm events carry no client in payload).\n        this.knownClients.add(new WeakRef(client));\n\n        // v5-style active initialization: full transition into initialState.\n        // Fires _onEnter, emits transitioning/transitioned, processes deferred\n        // queue. _onExit is skipped (no state object for undefined).\n        this.transition(client, this.initialState);\n\n        return meta;\n    }\n\n    private buildHandlerArgs(\n        client: TClient,\n        inputName: string,\n        meta: ClientMeta<TStateNames>\n    ): HandlerArgs<TClient, TStateNames> {\n        return {\n            ctx: client,\n            inputName,\n            defer: (opts?: { until: TStateNames }) => {\n                // Only meaningful inside a handle() context where currentActionArgs\n                // is set. No-ops during lifecycle hooks (matches v5 behavior).\n                if (!meta.currentActionArgs) {\n                    return;\n                }\n                const deferred: DeferredInput = {\n                    inputName,\n                    args: [...meta.currentActionArgs],\n                    untilState: opts?.until,\n                };\n                meta.deferredQueue.push(deferred);\n                this.emitter.emit(\"deferred\", { inputName, client });\n            },\n            emit: (evtName: string, evtData?: unknown) => {\n                (this.emitter as any).emit(evtName, evtData);\n            },\n        };\n    }\n\n    private processQueue(client: TClient, meta: ClientMeta<TStateNames>): void {\n        const toReplay: DeferredInput[] = [];\n        const remaining: DeferredInput[] = [];\n\n        for (const item of meta.deferredQueue) {\n            if (item.untilState === undefined || item.untilState === meta.state) {\n                toReplay.push(item);\n            } else {\n                remaining.push(item);\n            }\n        }\n\n        meta.deferredQueue = remaining;\n\n        for (const item of toReplay) {\n            this.handle(client, item.inputName as TInputNames, ...item.args);\n        }\n    }\n}\n\n// -----------------------------------------------------------------------------\n// createChildLink — internal adapter factory\n//\n// Wraps either an Fsm or BehavioralFsm child and presents a uniform interface\n// for the parent engine to call. Never exported. The MACHINA_TYPE discriminant\n// tells us which call shape to use.\n// -----------------------------------------------------------------------------\n\n/**\n * Internal factory called by `wrapChildLinks()` during construction.\n * Wraps a raw Fsm or BehavioralFsm instance in a uniform `ChildLink` adapter\n * so the parent engine doesn't need to know which type it's talking to.\n *\n * Users never call this directly — they assign an FSM instance to `_child`\n * in their state config and `wrapChildLinks()` handles the wrapping.\n */\nfunction createChildLink(child: any): ChildLink {\n    if (!child || typeof child !== \"object\") {\n        throw new Error(\n            `createChildLink: expected an Fsm or BehavioralFsm instance, got ${String(child)}`\n        );\n    }\n    const childType: string = child[MACHINA_TYPE];\n\n    if (childType === \"BehavioralFsm\") {\n        return {\n            instance: child,\n            canHandle(client: object, inputName: string): boolean {\n                return child.canHandle(client, inputName);\n            },\n            handle(client: object, inputName: string, ...args: unknown[]): void {\n                child.handle(client, inputName, ...args);\n            },\n            reset(client: object): void {\n                child.transition(client, child.initialState);\n            },\n            onAny(callback: (eventName: string, data: unknown) => void): { off(): void } {\n                return child.on(\"*\", callback);\n            },\n            compositeState(client: object): string {\n                return child.compositeState(client);\n            },\n            rehydrate(client: object, compositeState: string): void {\n                child.rehydrate(client, compositeState);\n            },\n            dispose(): void {\n                child.dispose();\n            },\n        };\n    }\n\n    if (childType === \"Fsm\") {\n        return {\n            instance: child,\n            canHandle(_client: object, inputName: string): boolean {\n                return child.canHandle(inputName);\n            },\n            handle(_client: object, inputName: string, ...args: unknown[]): void {\n                child.handle(inputName, ...args);\n            },\n            reset(_client: object): void {\n                child.reset();\n            },\n            onAny(callback: (eventName: string, data: unknown) => void): { off(): void } {\n                return child.on(\"*\", callback);\n            },\n            compositeState(_client: object): string {\n                return child.compositeState();\n            },\n            rehydrate(_client: object, _compositeState: string): void {\n                // Fsm owns its context internally — there is no per-client state to restore.\n                // Rehydrating into a BehavioralFsm hierarchy that has Fsm children is a\n                // structural mismatch; throw immediately so the caller gets a clear signal.\n                throw new Error(\n                    `rehydrate: cannot rehydrate an Fsm child. Fsm owns its own context; ` +\n                        `rehydrate is only valid for BehavioralFsm hierarchies.`\n                );\n            },\n            dispose(): void {\n                child.dispose();\n            },\n        };\n    }\n\n    throw new Error(\n        `createChildLink: expected an Fsm or BehavioralFsm instance, ` +\n            `got [MACHINA_TYPE] = ${String(childType ?? \"undefined\")}`\n    );\n}\n\n/**\n * Create a behavioral FSM (one definition, many clients) from a config object.\n *\n * Generic parameters are inferred automatically:\n * - `TClient` must be provided explicitly as a type parameter (it can't be\n *   inferred from the config since no `context` property exists at the FSM level).\n * - `TStates` is captured with `const` inference to preserve string literal\n *   types, enabling compile-time validation of transition targets and `handle()`\n *   input names.\n *\n * State names, input names, and all handler signatures derive from `TStates`.\n *\n * @example\n * ```ts\n * interface Connection { url: string; retries: number; }\n *\n * const connFsm = createBehavioralFsm<Connection>({\n *   id: \"connectivity\",\n *   initialState: \"disconnected\",\n *   states: {\n *     disconnected: { connect: \"connecting\" },\n *     connecting:   { connected: \"online\", failed: \"disconnected\" },\n *     online:       { disconnect: \"disconnected\" },\n *   },\n * });\n *\n * const conn = { url: \"wss://example.com\", retries: 0 };\n * connFsm.handle(conn, \"connect\");\n * ```\n */\nexport function createBehavioralFsm<\n    TClient extends object,\n    const TStates extends Record<string, Record<string, unknown>>,\n>(\n    config: FsmConfig<TClient, TStates>\n): BehavioralFsm<TClient, StateNamesOf<TStates>, InputNamesOf<TStates>> {\n    return new BehavioralFsm(config as FsmConfig<TClient, Record<string, Record<string, unknown>>>);\n}\n","/* eslint-disable @typescript-eslint/no-explicit-any */\n// =============================================================================\n// fsm.ts — Single-client FSM convenience wrapper\n//\n// Fsm wraps a BehavioralFsm, using the config's `context` object as the\n// internal client. Same engine, same lifecycle, but without the client\n// parameter on every method call.\n//\n// =============================================================================\n\nimport { Emitter, type Subscription } from \"./emitter\";\nimport { BehavioralFsm } from \"./behavioral-fsm\";\nimport {\n    MACHINA_TYPE,\n    type FsmConfig,\n    type FsmEventMap,\n    type StateNamesOf,\n    type InputNamesOf,\n    type DisposeOptions,\n} from \"./types\";\n\n/**\n * Single-client FSM. Wraps a BehavioralFsm and uses the config's `context`\n * object as the implicit client, so callers never pass a client argument.\n *\n * Prefer `createFsm()` over constructing this directly — the factory infers\n * all generic parameters from the config object.\n *\n * All public methods silently no-op after `dispose()` is called.\n *\n * @typeParam TCtx - The context type, inferred from `config.context`.\n * @typeParam TStateNames - String literal union of valid state names.\n * @typeParam TInputNames - String literal union of valid input names.\n */\nexport class Fsm<TCtx extends object, TStateNames extends string, TInputNames extends string> {\n    readonly id: string;\n    readonly initialState: TStateNames;\n    // Type discriminant — lets ChildLink adapter identify this at runtime\n    readonly [MACHINA_TYPE] = \"Fsm\" as const;\n    // Public so inspection tooling (machina-inspect) can read the state graph.\n    // Set from config.states — same object reference as BehavioralFsm.states,\n    // so ChildLink wrapping done by wrapChildLinks() is reflected automatically.\n    readonly states: Record<string, Record<string, unknown>>;\n    private readonly bfsm: BehavioralFsm<TCtx, TStateNames, TInputNames>;\n    // Public readonly so external tooling (and walkAll's invariant) can read\n    // context without needing to plumb it through every call site. The context\n    // is already visible inside handlers via ctx — this just makes it accessible\n    // from outside the FSM instance too.\n    readonly context: TCtx;\n    // FsmEventMap is an interface, which lacks the implicit index signature\n    // that Emitter's Record<string, unknown> constraint needs. The mapped type\n    // BehavioralFsmEventMap doesn't have this issue. Intersect with Record to\n    // satisfy the constraint while preserving typed event signatures.\n    private readonly emitter = new Emitter<FsmEventMap<TStateNames> & Record<string, unknown>>();\n    private disposed = false;\n\n    constructor(config: FsmConfig<TCtx, Record<string, Record<string, unknown>>>) {\n        this.id = config.id;\n        this.initialState = config.initialState as TStateNames;\n        this.context = (config.context ?? {}) as TCtx;\n\n        this.bfsm = new BehavioralFsm(config);\n        // Assign after bfsm construction so ChildLink wrapping (done by\n        // BehavioralFsm.wrapChildLinks) is already reflected in config.states.\n        this.states = config.states as Record<string, Record<string, unknown>>;\n\n        // Relay events from BehavioralFsm → Fsm emitter, stripping the\n        // `client` field from built-in event payloads. Custom events (from\n        // handler emit() or public emit()) pass through unchanged.\n        this.bfsm.on(\"*\", (eventName: string, data: unknown) => {\n            if (data && typeof data === \"object\" && \"client\" in data) {\n                const { client: _, ...payload } = data as Record<string, unknown>;\n                (this.emitter as any).emit(eventName, payload);\n            } else {\n                (this.emitter as any).emit(eventName, data);\n            }\n        });\n\n        // Eager init: call bfsm.transition() to enter initialState now.\n        // bfsm.transition() calls getOrCreateClientMeta(), which bootstraps\n        // the client and calls this.transition() internally (the real init,\n        // which fires _onEnter and emits transitioning/transitioned). After\n        // that inner call completes, meta.state === initialState, so the\n        // original bfsm.transition() call hits the same-state guard and exits.\n        this.bfsm.transition(this.context, config.initialState as TStateNames);\n    }\n\n    // -------------------------------------------------------------------------\n    // Public API — same as BehavioralFsm, minus the client parameter\n    // -------------------------------------------------------------------------\n\n    /**\n     * Dispatch an input to the current state's handler.\n     * If a `_child` FSM in the current state can handle it, delegation occurs\n     * there first; unhandled inputs bubble up to the parent.\n     * No-ops silently when disposed.\n     */\n    handle(inputName: TInputNames, ...args: unknown[]): void {\n        if (this.disposed) {\n            return;\n        }\n        this.bfsm.handle(this.context, inputName, ...args);\n    }\n\n    /**\n     * Returns true if the current state has a handler for `inputName`\n     * (or a catch-all `\"*\"` handler). Does not trigger initialization\n     * or any side effects. Returns false when disposed.\n     */\n    canHandle(inputName: string): boolean {\n        if (this.disposed) {\n            return false;\n        }\n        return this.bfsm.canHandle(this.context, inputName);\n    }\n\n    /**\n     * Transition back to `initialState`, firing `_onEnter` and lifecycle\n     * events as if entering it fresh. No-ops silently when disposed.\n     */\n    reset(): void {\n        if (this.disposed) {\n            return;\n        }\n        this.bfsm.reset(this.context);\n    }\n\n    /**\n     * Returns the current state name. Always defined — Fsm eagerly\n     * initializes into `initialState` during construction.\n     */\n    currentState(): TStateNames {\n        return this.bfsm.currentState(this.context) as TStateNames;\n    }\n\n    /**\n     * Directly transition to `toState`, firing `_onExit`, `_onEnter`, and\n     * lifecycle events. Same-state transitions are silently ignored.\n     * No-ops when disposed.\n     */\n    transition(toState: TStateNames): void {\n        if (this.disposed) {\n            return;\n        }\n        this.bfsm.transition(this.context, toState);\n    }\n\n    /**\n     * Returns the current state as a dot-delimited path that includes\n     * any active child FSM states (e.g. `\"active.connecting.retrying\"`).\n     * Returns just the current state name when no child is active.\n     */\n    compositeState(): string {\n        return this.bfsm.compositeState(this.context);\n    }\n\n    /**\n     * Subscribe to a built-in lifecycle event or the wildcard.\n     *\n     * Named overload: typed payload, no event name in callback.\n     * Wildcard (`\"*\"`): receives `(eventName, data)` for every event.\n     * Returns a no-op `Subscription` when disposed.\n     */\n    on<K extends keyof FsmEventMap<TStateNames> & string>(\n        eventName: K,\n        callback: (data: FsmEventMap<TStateNames>[K]) => void\n    ): Subscription;\n    on(eventName: \"*\", callback: (eventName: string, data: unknown) => void): Subscription;\n    on(eventName: string, callback: (...args: any[]) => void): Subscription {\n        if (this.disposed) {\n            return { off() {} };\n        }\n        return this.emitter.on(eventName as any, callback as any);\n    }\n\n    /**\n     * Emit a custom event through the FSM. Built-in lifecycle events are\n     * emitted automatically — this is for user-defined events from handlers.\n     * Routes through the BehavioralFsm so all relay paths are consistent.\n     * No-ops when disposed.\n     */\n    emit(eventName: string, data?: unknown): void {\n        if (this.disposed) {\n            return;\n        }\n        // Route through BehavioralFsm so custom events from handler emit()\n        // and public fsm.emit() take the same path through the relay.\n        this.bfsm.emit(eventName, data);\n    }\n\n    /**\n     * Permanently shut down this FSM. Irreversible — all subsequent method\n     * calls become silent no-ops. Clears all listeners and cascades disposal\n     * to child FSMs (unless `preserveChildren` is set).\n     */\n    dispose(options?: DisposeOptions): void {\n        this.disposed = true;\n        this.bfsm.dispose(options);\n        this.emitter.clear();\n    }\n}\n\n/**\n * Create a single-client FSM from a config object.\n *\n * Generic parameters are inferred automatically:\n * - `TCtx` comes from `config.context` (defaults to `{}` if omitted).\n * - `TStates` is captured with `const` inference to preserve string literal\n *   types, enabling compile-time validation of transition targets and `handle()`\n *   input names.\n *\n * State names, input names, and all handler signatures derive from `TStates`.\n *\n * @example\n * ```ts\n * const light = createFsm({\n *   id: \"traffic-light\",\n *   initialState: \"green\",\n *   context: { tickCount: 0 },\n *   states: {\n *     green:  { timeout: \"yellow\" },\n *     yellow: { timeout: \"red\" },\n *     red:    { timeout: \"green\" },\n *   },\n * });\n *\n * light.handle(\"timeout\"); // transitions green → yellow\n * ```\n */\nexport function createFsm<\n    TCtx extends object = Record<string, never>,\n    const TStates extends Record<string, Record<string, unknown>> = Record<\n        string,\n        Record<string, unknown>\n    >,\n>(config: FsmConfig<TCtx, TStates>): Fsm<TCtx, StateNamesOf<TStates>, InputNamesOf<TStates>> {\n    return new Fsm(config as FsmConfig<TCtx, Record<string, Record<string, unknown>>>);\n}\n"],"mappings":"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"}