aifsmjs 0.5.9 → 0.6.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.
Files changed (70) hide show
  1. package/README.md +14 -7
  2. package/README_ZHTW.md +14 -7
  3. package/dist/{chunk-ZLQ7HZCE.js → chunk-D6H64FSI.js} +66 -46
  4. package/dist/chunk-D6H64FSI.js.map +1 -0
  5. package/dist/{chunk-NEJYZAKR.js → chunk-Q45LGXHO.js} +3 -3
  6. package/dist/{chunk-NEJYZAKR.js.map → chunk-Q45LGXHO.js.map} +1 -1
  7. package/dist/{chunk-CDK25FTD.cjs → chunk-QCTA2X4J.cjs} +7 -3
  8. package/dist/chunk-QCTA2X4J.cjs.map +1 -0
  9. package/dist/{chunk-A7U7QQL5.js → chunk-SSNKGEVB.js} +7 -4
  10. package/dist/chunk-SSNKGEVB.js.map +1 -0
  11. package/dist/{chunk-I354FONA.cjs → chunk-VGLF5NQH.cjs} +69 -46
  12. package/dist/chunk-VGLF5NQH.cjs.map +1 -0
  13. package/dist/{chunk-FHTQ7LSQ.cjs → chunk-VV5TKFQO.cjs} +4 -4
  14. package/dist/{chunk-FHTQ7LSQ.cjs.map → chunk-VV5TKFQO.cjs.map} +1 -1
  15. package/dist/{chunk-LG2AH5X6.js → chunk-XA24A7VP.js} +143 -152
  16. package/dist/chunk-XA24A7VP.js.map +1 -0
  17. package/dist/{chunk-TPCDOVU4.cjs → chunk-YK25NVFC.cjs} +147 -156
  18. package/dist/chunk-YK25NVFC.cjs.map +1 -0
  19. package/dist/effects/index.cjs +3 -4
  20. package/dist/effects/index.cjs.map +1 -1
  21. package/dist/effects/index.d.cts +1 -1
  22. package/dist/effects/index.d.ts +1 -1
  23. package/dist/effects/index.js +2 -3
  24. package/dist/effects/index.js.map +1 -1
  25. package/dist/guards/index.cjs +5 -6
  26. package/dist/guards/index.cjs.map +1 -1
  27. package/dist/guards/index.d.cts +1 -1
  28. package/dist/guards/index.d.ts +1 -1
  29. package/dist/guards/index.js +2 -3
  30. package/dist/guards/index.js.map +1 -1
  31. package/dist/index.cjs +31 -28
  32. package/dist/index.d.cts +66 -18
  33. package/dist/index.d.ts +66 -18
  34. package/dist/index.js +3 -4
  35. package/dist/inspect/index.cjs +0 -2
  36. package/dist/inspect/index.cjs.map +1 -1
  37. package/dist/inspect/index.d.cts +1 -1
  38. package/dist/inspect/index.d.ts +1 -1
  39. package/dist/inspect/index.js +0 -2
  40. package/dist/inspect/index.js.map +1 -1
  41. package/dist/pbt/index.cjs +65 -49
  42. package/dist/pbt/index.cjs.map +1 -1
  43. package/dist/pbt/index.d.cts +13 -17
  44. package/dist/pbt/index.d.ts +13 -17
  45. package/dist/pbt/index.js +57 -41
  46. package/dist/pbt/index.js.map +1 -1
  47. package/dist/replay/index.cjs +4 -5
  48. package/dist/replay/index.d.cts +1 -1
  49. package/dist/replay/index.d.ts +1 -1
  50. package/dist/replay/index.js +3 -4
  51. package/dist/timer/index.cjs +18 -5
  52. package/dist/timer/index.cjs.map +1 -1
  53. package/dist/timer/index.d.cts +6 -0
  54. package/dist/timer/index.d.ts +6 -0
  55. package/dist/timer/index.js +18 -5
  56. package/dist/timer/index.js.map +1 -1
  57. package/dist/{types-DIM7QTtf.d.ts → types-CrDxFfBx.d.cts} +64 -16
  58. package/dist/{types-DIM7QTtf.d.cts → types-CrDxFfBx.d.ts} +64 -16
  59. package/llms-full.txt +70 -16
  60. package/package.json +57 -22
  61. package/dist/chunk-A7U7QQL5.js.map +0 -1
  62. package/dist/chunk-CDK25FTD.cjs.map +0 -1
  63. package/dist/chunk-I354FONA.cjs.map +0 -1
  64. package/dist/chunk-LG2AH5X6.js.map +0 -1
  65. package/dist/chunk-PZ5AY32C.js +0 -9
  66. package/dist/chunk-PZ5AY32C.js.map +0 -1
  67. package/dist/chunk-Q7SFCCGT.cjs +0 -11
  68. package/dist/chunk-Q7SFCCGT.cjs.map +0 -1
  69. package/dist/chunk-TPCDOVU4.cjs.map +0 -1
  70. package/dist/chunk-ZLQ7HZCE.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/fsm/resolver.ts","../src/fsm/snapshot.ts","../src/fsm/lifecycle.ts","../src/fsm/updater.ts"],"names":["ownValue","IS_DEV","createEnqueuer","evalGuard"],"mappings":"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","file":"chunk-VGLF5NQH.cjs","sourcesContent":["import { ownValue } from \"./evaluator.js\";\nimport type { MachineDef, TransitionConfig, TransitionDef } from \"./types.js\";\n\n/**\n * Normalize a single transition config into its object form. The string\n * shorthand `\"targetState\"` (à la XState) becomes `{ target: \"targetState\" }`;\n * the object form is returned unchanged. Centralised here so every consumer\n * (`step`, `resolveTransitions`, `can`, validation) sees the same shape.\n *\n * @since 0.5.3\n */\nexport function normalizeTransition<Ctx, Evt, States extends string>(\n entry: TransitionConfig<Ctx, Evt, States>,\n): TransitionDef<Ctx, Evt, States> {\n return typeof entry === \"string\" ? ({ target: entry } as TransitionDef<Ctx, Evt, States>) : entry;\n}\n\n/**\n * Normalize the raw `state.on[eventType]` value (object, string shorthand, or\n * an array mixing both) into an ordered list of {@link TransitionDef} objects.\n * Declaration order is preserved.\n *\n * @since 0.5.3\n */\nexport function normalizeTransitions<Ctx, Evt, States extends string>(\n entry:\n | TransitionConfig<Ctx, Evt, States>\n | readonly TransitionConfig<Ctx, Evt, States>[]\n | undefined,\n): readonly TransitionDef<Ctx, Evt, States>[] {\n if (entry === undefined) return [];\n if (Array.isArray(entry)) {\n // Hot path (send/step/can run this per event): when no string shorthand is\n // present, return the original array instead of allocating a normalized copy.\n return entry.some((t) => typeof t === \"string\")\n ? entry.map((t) => normalizeTransition(t))\n : (entry as readonly TransitionDef<Ctx, Evt, States>[]);\n }\n return [normalizeTransition(entry as TransitionConfig<Ctx, Evt, States>)];\n}\n\n/**\n * Return all transition candidates for (state, eventType). Order is preserved\n * from the declaration so that guard fallthrough behaves predictably. String\n * shorthands are normalized to `{ target }` objects.\n *\n * If the event has no entry under the given state, an empty array is returned.\n */\nexport function resolveTransitions<Ctx, Evt extends { type: string }, States extends string>(\n def: MachineDef<Ctx, Evt, States>,\n stateValue: States,\n eventType: string,\n): readonly TransitionDef<Ctx, Evt, States>[] {\n const state = def.states[stateValue];\n if (!state || !state.on) return [];\n return normalizeTransitions(ownValue(state.on, eventType));\n}\n","import type { Snapshot } from \"./types.js\";\n\n// Written so a bundler define-replacement of `process.env.NODE_ENV` (Vite,\n// webpack 5, ...) still applies: those tools replace only the\n// `process.env.NODE_ENV` expression, not a runtime `process` global, so\n// gating on `typeof process !== \"undefined\"` first left IS_DEV permanently\n// false in a browser build even though NODE_ENV !== \"production\". A plain\n// try/catch around the read lets the replaced literal survive while still\n// falling back to false wherever `process` is entirely absent. Exported for\n// internal dev-only diagnostics (runtime.ts); not re-exported from the root.\nexport let IS_DEV = false;\ntry {\n IS_DEV = process.env.NODE_ENV !== \"production\";\n} catch {\n /* no `process` global (browser without bundler define-replacement) */\n}\n\nexport function isPlainObject(value: unknown): value is Record<string, unknown> {\n if (value === null || typeof value !== \"object\") return false;\n const proto = Object.getPrototypeOf(value);\n return proto === Object.prototype || proto === null;\n}\n\n// Trees already deep-frozen here. Short-circuits re-walking carried-over\n// context and guards cycles; unlike `Object.isFrozen` it does not stop at a\n// shallow-frozen object (e.g. an effect descriptor) whose children are mutable.\nconst DEEP_FROZEN = new WeakSet<object>();\n\nexport function deepFreeze<T>(value: T): T {\n if (value === null || typeof value !== \"object\") return value;\n if (DEEP_FROZEN.has(value)) return value;\n DEEP_FROZEN.add(value);\n // Object.freeze throws on a non-empty TypedArray / Buffer; binary data in\n // context or event payloads is left mutable (caller-owned) instead.\n if (ArrayBuffer.isView(value)) return value;\n Object.freeze(value);\n if (Array.isArray(value)) {\n for (const item of value) deepFreeze(item);\n } else if (isPlainObject(value)) {\n for (const key of Object.keys(value)) {\n deepFreeze((value as Record<string, unknown>)[key]);\n }\n }\n return value;\n}\n\n/**\n * Wrap a freshly built snapshot. In dev mode the whole tree is deep-frozen so\n * accidental mutation throws immediately. In production only the top object is\n * frozen, keeping the cost negligible.\n */\nexport function freezeSnapshot<C, S extends string>(snap: Snapshot<C, S>): Snapshot<C, S> {\n // IS_DEV is always true in vitest; the production branch (`Object.freeze`)\n // is exercised only when NODE_ENV === \"production\" and is intentionally\n // left out of the coverage threshold.\n return IS_DEV ? deepFreeze(snap) : Object.freeze(snap);\n}\n\nexport function createSnapshot<C, S extends string>(args: {\n value: S;\n context: C;\n status?: \"active\" | \"final\";\n}): Snapshot<C, S> {\n return freezeSnapshot({\n value: args.value,\n context: args.context,\n status: args.status ?? \"active\",\n });\n}\n","import { createEnqueuer } from \"../effects/enqueuer.js\";\nimport { evalGuard, ownValue } from \"./evaluator.js\";\nimport { resolveTransitions } from \"./resolver.js\";\nimport { freezeSnapshot } from \"./snapshot.js\";\nimport type {\n Action,\n ActionRef,\n Effect,\n Implementations,\n MachineDef,\n Snapshot,\n StepResult,\n TransitionDef,\n} from \"./types.js\";\nimport { mergeContext } from \"./updater.js\";\n\nexport class UnknownActionError extends Error {\n readonly actionName: string;\n constructor(actionName: string) {\n super(`aifsmjs: action \"${actionName}\" not found in implementations.actions`);\n this.name = \"UnknownActionError\";\n this.actionName = actionName;\n }\n}\n\n/**\n * Thrown (from `step()`, and so from `send()` before anything is committed)\n * when an action returns a non-nullish primitive (`false`, `0`, `\"\"`, ...) as\n * the patch for an object context. An object context accepts only a\n * plain-object patch or `undefined`/`null` (no change).\n *\n * `actionName` is the string ref, the inline function's name, or `\"<inline>\"`\n * for an anonymous inline action (mirrors guard naming).\n *\n * @since 0.6.0\n */\nexport class InvalidActionResultError extends Error {\n readonly actionName: string;\n constructor(actionName: string, patch: unknown) {\n super(\n `aifsmjs: action \"${actionName}\" returned ${typeof patch}; an object context accepts only a plain-object patch (or undefined)`,\n );\n this.name = \"InvalidActionResultError\";\n this.actionName = actionName;\n }\n}\n\nfunction resolveAction<Ctx, Evt>(\n ref: ActionRef<Ctx, Evt>,\n impl: Implementations<Ctx, Evt>,\n): Action<Ctx, Evt> {\n if (typeof ref === \"function\") return ref;\n const fn = ownValue(impl.actions, ref);\n if (!fn) throw new UnknownActionError(ref);\n return fn;\n}\n\nfunction runActions<Ctx, Evt>(\n refs: readonly ActionRef<Ctx, Evt>[] | undefined,\n ctx: Ctx,\n event: Evt,\n impl: Implementations<Ctx, Evt>,\n effectSink: Effect[],\n): Ctx {\n if (!refs || refs.length === 0) return ctx;\n const enqueue = createEnqueuer(effectSink as { type: string; payload?: unknown }[]);\n let current = ctx;\n for (const ref of refs) {\n const fn = resolveAction(ref, impl);\n const patch = fn({ context: current, event, enqueue });\n current = mergeContext(current, patch, typeof ref === \"string\" ? ref : fn.name || \"<inline>\");\n }\n return current;\n}\n\n/**\n * The transition `event` would fire from `snapshot`: the first candidate (in\n * declaration order) with no guard or a passing guard, or `undefined` (also\n * for a final state, which never reacts). Shared by `step()` and\n * `Runtime.can()` so both resolve candidates the same way.\n */\nexport function chooseTransition<Ctx, Evt extends { type: string }, States extends string>(\n def: MachineDef<Ctx, Evt, States>,\n snapshot: Snapshot<Ctx, States>,\n event: Evt,\n impl: Implementations<Ctx, Evt>,\n): TransitionDef<Ctx, Evt, States> | undefined {\n if (snapshot.status === \"final\") return undefined;\n for (const t of resolveTransitions(def, snapshot.value, event.type)) {\n if (!t.guard || evalGuard(t.guard, snapshot.context, event, impl, snapshot.value)) return t;\n }\n return undefined;\n}\n\nconst NO_EFFECTS: readonly Effect[] = Object.freeze([]);\n\n/**\n * Internal `step()` that also reports whether the chosen transition is\n * external (has a `target`, including a same-value self-target). The runtime\n * uses it to decide the sub-machine lifecycle from the SAME guard pass that\n * produced the snapshot, so a non-idempotent guard is evaluated exactly once\n * per event. Not re-exported from the package root.\n */\nexport function stepWithMeta<Ctx, Evt extends { type: string }, States extends string>(\n def: MachineDef<Ctx, Evt, States>,\n snapshot: Snapshot<Ctx, States>,\n event: Evt,\n impl: Implementations<Ctx, Evt>,\n): { result: StepResult<Ctx, States>; external: boolean } {\n // Nothing fires for a final state (inert), an undeclared event type, or\n // when every candidate's guard fails.\n const chosen = chooseTransition(def, snapshot, event, impl);\n if (!chosen) {\n return {\n result: Object.freeze({ snapshot, effects: NO_EFFECTS, changed: false }),\n external: false,\n };\n }\n // A chosen transition implies snapshot.value is a declared state.\n const state = def.states[snapshot.value];\n\n const isExternal = chosen.target !== undefined;\n const nextStateValue = (chosen.target ?? snapshot.value) as States;\n const nextState = def.states[nextStateValue];\n\n const effectSink: Effect[] = [];\n let ctx = snapshot.context;\n\n if (isExternal) {\n ctx = runActions(state.exit, ctx, event, impl, effectSink);\n }\n ctx = runActions(chosen.actions, ctx, event, impl, effectSink);\n if (isExternal && nextState) {\n ctx = runActions(nextState.entry, ctx, event, impl, effectSink);\n }\n\n const status: \"active\" | \"final\" = nextState?.final === true ? \"final\" : \"active\";\n const nextSnapshot = freezeSnapshot({\n value: nextStateValue,\n context: ctx,\n status,\n });\n\n return {\n result: Object.freeze({\n snapshot: nextSnapshot,\n effects: Object.freeze(effectSink.slice()) as readonly Effect[],\n changed: true,\n }),\n external: isExternal,\n };\n}\n\n/**\n * Compute the next snapshot and collected effects from a single event.\n *\n * Order is fixed and uninterruptible:\n * 1. resolve candidate transitions for (state, event.type)\n * 2. evaluate guards in declaration order; pick the first passing one\n * 3. if external (target defined), run exit actions of the old state\n * 4. run transition.actions in declaration order\n * 5. if external, run entry actions of the new state\n * 6. return { snapshot, effects, changed }\n *\n * The function is pure: it never dispatches effects and never mutates inputs.\n * Each guard on the path is evaluated at most once.\n */\nexport function step<Ctx, Evt extends { type: string }, States extends string>(\n def: MachineDef<Ctx, Evt, States>,\n snapshot: Snapshot<Ctx, States>,\n event: Evt,\n impl: Implementations<Ctx, Evt>,\n): StepResult<Ctx, States> {\n return stepWithMeta(def, snapshot, event, impl).result;\n}\n","import { InvalidActionResultError } from \"./lifecycle.js\";\nimport { isPlainObject } from \"./snapshot.js\";\nimport type { Action } from \"./types.js\";\n\n/**\n * Build an Action that returns a Partial<Ctx> from a pure updater.\n * The partial is merged into the current context by `step()`.\n */\nexport function assign<Ctx, Evt>(\n updater: (args: { context: Ctx; event: Evt }) => Partial<Ctx>,\n): Action<Ctx, Evt> {\n return ({ context, event }) => updater({ context, event });\n}\n\n/**\n * Merge an action's result into the current context. The function never\n * mutates either argument.\n *\n * - `undefined` / `null` patch: `current` is returned unchanged.\n * - Object context (not an array or `ArrayBuffer` view) + plain-object patch:\n * shallow merge into a new object that keeps `current`'s prototype, so a\n * class-instance context keeps its methods and untouched fields. Only own\n * enumerable (string and symbol) properties are carried; `#private` and\n * non-enumerable members are not, so prefer plain-object contexts.\n * - Object context + non-nullish primitive patch (`false`, `0`, `\"\"`, ...):\n * throws {@link InvalidActionResultError} (`actionName` names the action).\n * - Anything else (a primitive or array context, or a non-plain-object patch\n * such as an array or class instance): the patch replaces `current`.\n */\nexport function mergeContext<Ctx>(\n current: Ctx,\n patch: Partial<Ctx> | void,\n actionName = \"<inline>\",\n): Ctx {\n if (patch === undefined || patch === null) return current;\n if (\n current !== null &&\n typeof current === \"object\" &&\n !Array.isArray(current) &&\n !ArrayBuffer.isView(current)\n ) {\n // Spread (CreateDataProperty) rather than Object.assign ([[Set]]): an own\n // `__proto__` key in a JSON-derived patch stays a plain data property\n // instead of re-prototyping the merged context, and prototype setters\n // are never invoked. Object.setPrototypeOf is a no-op for plain contexts.\n if (isPlainObject(patch)) {\n return Object.setPrototypeOf({ ...current, ...patch }, Object.getPrototypeOf(current));\n }\n if (typeof patch !== \"object\" && typeof patch !== \"function\") {\n throw new InvalidActionResultError(actionName, patch);\n }\n }\n return patch as Ctx;\n}\n"]}
@@ -1,13 +1,13 @@
1
1
  'use strict';
2
2
 
3
- var chunkI354FONA_cjs = require('./chunk-I354FONA.cjs');
3
+ var chunkVGLF5NQH_cjs = require('./chunk-VGLF5NQH.cjs');
4
4
 
5
5
  // src/replay/index.ts
6
6
  function replay(initial, events, def, impl) {
7
7
  let snapshot = initial;
8
8
  const effects = [];
9
9
  for (const event of events) {
10
- const r = chunkI354FONA_cjs.step(def, snapshot, event, impl);
10
+ const r = chunkVGLF5NQH_cjs.step(def, snapshot, event, impl);
11
11
  snapshot = r.snapshot;
12
12
  if (r.effects.length > 0) {
13
13
  for (const eff of r.effects) effects.push(eff);
@@ -17,5 +17,5 @@ function replay(initial, events, def, impl) {
17
17
  }
18
18
 
19
19
  exports.replay = replay;
20
- //# sourceMappingURL=chunk-FHTQ7LSQ.cjs.map
21
- //# sourceMappingURL=chunk-FHTQ7LSQ.cjs.map
20
+ //# sourceMappingURL=chunk-VV5TKFQO.cjs.map
21
+ //# sourceMappingURL=chunk-VV5TKFQO.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/replay/index.ts"],"names":["step"],"mappings":";;;;;AAiBO,SAAS,MAAA,CACd,OAAA,EACA,MAAA,EACA,GAAA,EACA,IAAA,EAC2B;AAC3B,EAAA,IAAI,QAAA,GAAW,OAAA;AACf,EAAA,MAAM,UAAoB,EAAC;AAC3B,EAAA,KAAA,MAAW,SAAS,MAAA,EAAQ;AAC1B,IAAA,MAAM,CAAA,GAAIA,sBAAA,CAAK,GAAA,EAAK,QAAA,EAAU,OAAO,IAAI,CAAA;AACzC,IAAA,QAAA,GAAW,CAAA,CAAE,QAAA;AACb,IAAA,IAAI,CAAA,CAAE,OAAA,CAAQ,MAAA,GAAS,CAAA,EAAG;AACxB,MAAA,KAAA,MAAW,GAAA,IAAO,CAAA,CAAE,OAAA,EAAS,OAAA,CAAQ,KAAK,GAAG,CAAA;AAAA,IAC/C;AAAA,EACF;AACA,EAAA,OAAO,MAAA,CAAO,MAAA,CAAO,EAAE,QAAA,EAAU,OAAA,EAAS,MAAA,CAAO,MAAA,CAAO,OAAA,CAAQ,KAAA,EAAO,CAAA,EAAG,CAAA;AAC5E","file":"chunk-FHTQ7LSQ.cjs","sourcesContent":["import { step } from \"../fsm/lifecycle.js\";\nimport type { Effect, Implementations, MachineDef, Snapshot } from \"../fsm/types.js\";\n\nexport type ReplayResult<Ctx, States extends string> = Readonly<{\n snapshot: Snapshot<Ctx, States>;\n effects: readonly Effect[];\n}>;\n\n/**\n * Fold an event log into a final snapshot via `step()`. Effects are collected\n * but never dispatched — this is a pure function, suitable for PBT, time\n * travel, and incident reproduction.\n *\n * Equivalent to:\n * events.reduce((s, e) => step(def, s, e, impl).snapshot, initial)\n * but also accumulates the effects across all events.\n */\nexport function replay<Ctx, Evt extends { type: string }, States extends string>(\n initial: Snapshot<Ctx, States>,\n events: readonly Evt[],\n def: MachineDef<Ctx, Evt, States>,\n impl: Implementations<Ctx, Evt>,\n): ReplayResult<Ctx, States> {\n let snapshot = initial;\n const effects: Effect[] = [];\n for (const event of events) {\n const r = step(def, snapshot, event, impl);\n snapshot = r.snapshot;\n if (r.effects.length > 0) {\n for (const eff of r.effects) effects.push(eff);\n }\n }\n return Object.freeze({ snapshot, effects: Object.freeze(effects.slice()) });\n}\n"]}
1
+ {"version":3,"sources":["../src/replay/index.ts"],"names":["step"],"mappings":";;;;;AAiBO,SAAS,MAAA,CACd,OAAA,EACA,MAAA,EACA,GAAA,EACA,IAAA,EAC2B;AAC3B,EAAA,IAAI,QAAA,GAAW,OAAA;AACf,EAAA,MAAM,UAAoB,EAAC;AAC3B,EAAA,KAAA,MAAW,SAAS,MAAA,EAAQ;AAC1B,IAAA,MAAM,CAAA,GAAIA,sBAAA,CAAK,GAAA,EAAK,QAAA,EAAU,OAAO,IAAI,CAAA;AACzC,IAAA,QAAA,GAAW,CAAA,CAAE,QAAA;AACb,IAAA,IAAI,CAAA,CAAE,OAAA,CAAQ,MAAA,GAAS,CAAA,EAAG;AACxB,MAAA,KAAA,MAAW,GAAA,IAAO,CAAA,CAAE,OAAA,EAAS,OAAA,CAAQ,KAAK,GAAG,CAAA;AAAA,IAC/C;AAAA,EACF;AACA,EAAA,OAAO,MAAA,CAAO,MAAA,CAAO,EAAE,QAAA,EAAU,OAAA,EAAS,MAAA,CAAO,MAAA,CAAO,OAAA,CAAQ,KAAA,EAAO,CAAA,EAAG,CAAA;AAC5E","file":"chunk-VV5TKFQO.cjs","sourcesContent":["import { step } from \"../fsm/lifecycle.js\";\nimport type { Effect, Implementations, MachineDef, Snapshot } from \"../fsm/types.js\";\n\nexport type ReplayResult<Ctx, States extends string> = Readonly<{\n snapshot: Snapshot<Ctx, States>;\n effects: readonly Effect[];\n}>;\n\n/**\n * Fold an event log into a final snapshot via `step()`. Effects are collected\n * but never dispatched — this is a pure function, suitable for PBT, time\n * travel, and incident reproduction.\n *\n * Equivalent to:\n * events.reduce((s, e) => step(def, s, e, impl).snapshot, initial)\n * but also accumulates the effects across all events.\n */\nexport function replay<Ctx, Evt extends { type: string }, States extends string>(\n initial: Snapshot<Ctx, States>,\n events: readonly Evt[],\n def: MachineDef<Ctx, Evt, States>,\n impl: Implementations<Ctx, Evt>,\n): ReplayResult<Ctx, States> {\n let snapshot = initial;\n const effects: Effect[] = [];\n for (const event of events) {\n const r = step(def, snapshot, event, impl);\n snapshot = r.snapshot;\n if (r.effects.length > 0) {\n for (const eff of r.effects) effects.push(eff);\n }\n }\n return Object.freeze({ snapshot, effects: Object.freeze(effects.slice()) });\n}\n"]}
@@ -1,5 +1,5 @@
1
- import { freezeSnapshot, step, normalizeTransitions, deepFreeze } from './chunk-ZLQ7HZCE.js';
2
- import { evalGuard, isAsyncGuardFn, isThenable } from './chunk-A7U7QQL5.js';
1
+ import { freezeSnapshot, chooseTransition, normalizeTransitions, stepWithMeta, deepFreeze, IS_DEV } from './chunk-D6H64FSI.js';
2
+ import { isAsyncGuardFn, ownValue, isThenable } from './chunk-SSNKGEVB.js';
3
3
 
4
4
  // src/fsm/types.ts
5
5
  var RESET_EVENT_TYPE = "@@aifsmjs/RESET";
@@ -11,13 +11,16 @@ var InvalidDefinitionError = class extends Error {
11
11
  this.name = "InvalidDefinitionError";
12
12
  }
13
13
  };
14
+ function assertObject(value, subject) {
15
+ if (value === null || typeof value !== "object") {
16
+ throw new InvalidDefinitionError(`${subject} must be an object`);
17
+ }
18
+ }
14
19
  function validateDefinition(def, seen = /* @__PURE__ */ new WeakSet()) {
15
20
  if (!def.id || typeof def.id !== "string") {
16
21
  throw new InvalidDefinitionError("definition must have a non-empty string `id`");
17
22
  }
18
- if (!def.states || typeof def.states !== "object") {
19
- throw new InvalidDefinitionError("definition must have a `states` object");
20
- }
23
+ assertObject(def.states, "definition states");
21
24
  const stateKeys = Object.keys(def.states);
22
25
  if (stateKeys.length === 0) {
23
26
  throw new InvalidDefinitionError("`states` must declare at least one state");
@@ -28,6 +31,7 @@ function validateDefinition(def, seen = /* @__PURE__ */ new WeakSet()) {
28
31
  );
29
32
  }
30
33
  for (const [stateName, stateDef] of Object.entries(def.states)) {
34
+ assertObject(stateDef, `state "${stateName}"`);
31
35
  if (stateDef.sub !== void 0) {
32
36
  const sub = stateDef.sub;
33
37
  const subStates = sub.states;
@@ -48,6 +52,7 @@ function validateDefinition(def, seen = /* @__PURE__ */ new WeakSet()) {
48
52
  for (const [evtType, entry] of Object.entries(stateDef.on)) {
49
53
  const transitions = normalizeTransitions(entry);
50
54
  for (const t of transitions) {
55
+ assertObject(t, `transition ${stateName} -[${evtType}]->`);
51
56
  if (t.target !== void 0 && !stateKeys.includes(t.target)) {
52
57
  throw new InvalidDefinitionError(
53
58
  `transition ${stateName} -[${evtType}]-> "${String(t.target)}" targets an unknown state`
@@ -61,20 +66,26 @@ function validateDefinition(def, seen = /* @__PURE__ */ new WeakSet()) {
61
66
  }
62
67
  }
63
68
  }
69
+ const path = /* @__PURE__ */ new Set();
70
+ let d = def;
71
+ while (d) {
72
+ if (path.has(d)) {
73
+ throw new InvalidDefinitionError(
74
+ `sub-machine cycle through initial states: "${d.id}" is re-entered via initial-state subs`
75
+ );
76
+ }
77
+ path.add(d);
78
+ d = d.states[d.initial]?.sub;
79
+ }
64
80
  }
65
81
  function defineMachine(def) {
66
- const normalized = !("context" in def) ? { ...def, context: {} } : def;
82
+ assertObject(def, "definition");
83
+ const normalized = def.context === void 0 ? { ...def, context: {} } : def;
67
84
  validateDefinition(normalized);
68
85
  return normalized;
69
86
  }
70
87
  function setup() {
71
- return {
72
- defineMachine: (def) => {
73
- const cast = !("context" in def) ? { ...def, context: {} } : def;
74
- validateDefinition(cast);
75
- return cast;
76
- }
77
- };
88
+ return { defineMachine };
78
89
  }
79
90
  function initialSnapshot(def) {
80
91
  const isFinal = def.states[def.initial]?.final === true;
@@ -124,15 +135,29 @@ function composeMiddleware(middleware) {
124
135
  dispatch(0);
125
136
  };
126
137
  }
138
+ function assertListener(listener) {
139
+ if (typeof listener !== "function") {
140
+ throw new InvalidDefinitionError("listener must be a function");
141
+ }
142
+ }
127
143
  function createRuntime(def, impl, opts = {}) {
144
+ assertObject(def, "definition");
145
+ assertObject(def.states, "definition states");
146
+ assertObject(impl, "implementations");
147
+ assertObject(opts, "options");
148
+ const middleware = opts.middleware;
149
+ if (middleware !== void 0 && !(Array.isArray(middleware) && middleware.every((fn) => typeof fn === "function"))) {
150
+ throw new InvalidDefinitionError("options.middleware must be an array of functions");
151
+ }
128
152
  let snapshot = initialSnapshot(def);
129
153
  const listeners = /* @__PURE__ */ new Set();
130
- const middlewareChain = opts.middleware && opts.middleware.length > 0 ? composeMiddleware(opts.middleware) : void 0;
154
+ const middlewareChain = middleware && middleware.length > 0 ? composeMiddleware(middleware) : void 0;
131
155
  const shouldDispatch = opts.dispatchEffects !== false;
132
156
  const controller = new AbortController();
133
157
  let disposed = false;
158
+ let dispatching = false;
159
+ const mailbox = [];
134
160
  let childRuntime;
135
- let childAbortCleanup;
136
161
  const eventListeners = {
137
162
  transition: /* @__PURE__ */ new Set(),
138
163
  error: /* @__PURE__ */ new Set(),
@@ -140,162 +165,131 @@ function createRuntime(def, impl, opts = {}) {
140
165
  };
141
166
  const externalAbortCleanups = /* @__PURE__ */ new Set();
142
167
  function emit(type, payload) {
143
- for (const fn of Array.from(eventListeners[type])) fn(payload);
144
- }
145
- function notify(committed) {
146
- const captured = committed ?? snapshot;
147
- for (const l of Array.from(listeners)) l(captured);
148
- }
149
- function runMiddleware(prev, event, effects, changed) {
150
- if (!middlewareChain) return;
151
- middlewareChain(deepFreeze({ prev, next: snapshot, event, effects, changed }), () => {
152
- });
168
+ const set = eventListeners[type];
169
+ let failed = false;
170
+ let firstError;
171
+ for (const fn of Array.from(set)) {
172
+ if (!set.has(fn)) continue;
173
+ try {
174
+ fn(payload);
175
+ } catch (err) {
176
+ if (!failed) {
177
+ failed = true;
178
+ firstError = err;
179
+ }
180
+ }
181
+ }
182
+ if (failed) throw firstError;
153
183
  }
154
184
  function dispatchEffects(effects, context, event) {
155
185
  if (!impl.effects || effects.length === 0) return;
156
186
  for (const eff of effects) {
157
- const handler = impl.effects[eff.type];
187
+ const handler = ownValue(impl.effects, eff.type);
158
188
  if (!handler) continue;
159
189
  const r = handler(eff, { context, event, signal: controller.signal });
160
190
  if (isThenable(r)) {
161
191
  Promise.resolve(r).catch((err) => {
162
- emit("error", { error: err, event });
192
+ if (eventListeners.error.size > 0) emit("error", { error: err, event });
193
+ else if (IS_DEV) {
194
+ console.warn(
195
+ 'aifsmjs: unhandled async effect rejection; register runtime.on("error", ...)',
196
+ err
197
+ );
198
+ }
163
199
  });
164
200
  }
165
201
  }
166
202
  }
167
- function wireChildAbort(child) {
168
- if (controller.signal.aborted) {
203
+ function swapChild(prevValue, nextValue) {
204
+ const stateDef = def.states[nextValue];
205
+ let next;
206
+ if (stateDef?.sub) {
169
207
  try {
170
- child.dispose();
171
- } catch {
172
- }
173
- return () => {
174
- };
175
- }
176
- const onAbort = () => {
177
- try {
178
- child.dispose();
179
- } catch {
180
- }
181
- };
182
- controller.signal.addEventListener("abort", onAbort, { once: true });
183
- return () => controller.signal.removeEventListener("abort", onAbort);
184
- }
185
- function initChildFor(stateValue) {
186
- const stateDef = def.states[stateValue];
187
- const sub = stateDef?.sub;
188
- if (sub === void 0) return;
189
- let newChild;
190
- try {
191
- newChild = createRuntime(sub, stateDef.subImpl ?? {});
192
- } catch (cause) {
193
- throw new SubMachineError(stateValue, "init", cause);
194
- }
195
- childRuntime = newChild;
196
- childAbortCleanup = wireChildAbort(newChild);
197
- }
198
- function findChosenIsExternal(value, event, context) {
199
- const state = def.states[value];
200
- if (!state?.on) return false;
201
- const list = normalizeTransitions(state.on[event.type]);
202
- if (list.length === 0) return false;
203
- for (const t of list) {
204
- if (!t.guard || evalGuard(t.guard, context, event, impl, value)) {
205
- return t.target !== void 0;
208
+ next = createRuntime(stateDef.sub, stateDef.subImpl ?? {});
209
+ } catch (cause) {
210
+ throw new SubMachineError(nextValue, "init", cause);
206
211
  }
207
212
  }
208
- return false;
209
- }
210
- function applySubLifecycle(prevValue, nextValue) {
211
- const prevStateDef = def.states[prevValue];
212
- const nextStateDef = def.states[nextValue];
213
- if (prevStateDef?.sub !== void 0 && childRuntime !== void 0) {
214
- const child = childRuntime;
213
+ const old = childRuntime;
214
+ if (old) {
215
215
  childRuntime = void 0;
216
- childAbortCleanup?.();
217
- childAbortCleanup = void 0;
218
216
  try {
219
- child.dispose();
217
+ old.dispose();
220
218
  } catch (cause) {
219
+ next?.dispose();
221
220
  throw new SubMachineError(prevValue, "dispose", cause);
222
221
  }
223
222
  }
224
- if (nextStateDef?.sub !== void 0) {
225
- initChildFor(nextValue);
226
- }
223
+ if (disposed) next?.dispose();
224
+ else childRuntime = next;
227
225
  }
228
- function send(event) {
229
- if (disposed) throw new RuntimeDisposedError();
230
- const prev = snapshot;
231
- const result = step(def, prev, event, impl);
232
- const isExternal = result.changed && (prev.value !== result.snapshot.value || findChosenIsExternal(prev.value, event, prev.context));
233
- if (result.changed && isExternal) applySubLifecycle(prev.value, result.snapshot.value);
234
- snapshot = result.snapshot;
235
- const committed = result.snapshot;
236
- runMiddleware(prev, event, result.effects, result.changed);
237
- if (shouldDispatch) dispatchEffects(result.effects, committed.context, event);
238
- if (result.changed) {
239
- notify(committed);
226
+ function commit(prev, next, event, effects, changed) {
227
+ snapshot = next;
228
+ middlewareChain?.(
229
+ Object.freeze({ prev, next, event, effects: deepFreeze(effects), changed }),
230
+ () => {
231
+ }
232
+ );
233
+ if (shouldDispatch) dispatchEffects(effects, next.context, event);
234
+ if (changed) {
235
+ for (const l of Array.from(listeners)) if (listeners.has(l)) l(next);
240
236
  emit("transition", {
241
237
  prev,
242
- next: committed,
238
+ next,
243
239
  event,
244
- effects: result.effects,
240
+ effects,
245
241
  changed: true
246
242
  });
247
243
  }
248
- return snapshot;
249
244
  }
250
- function reset(event) {
251
- if (disposed) throw new RuntimeDisposedError();
245
+ function processSend(event) {
252
246
  const prev = snapshot;
253
- const nextSnap = initialSnapshot(def);
254
- const changed = prev.value !== nextSnap.value;
255
- if (childRuntime) {
256
- const child = childRuntime;
257
- childRuntime = void 0;
258
- childAbortCleanup?.();
259
- childAbortCleanup = void 0;
260
- try {
261
- child.dispose();
262
- } catch (cause) {
263
- throw new SubMachineError(prev.value, "dispose", cause);
264
- }
247
+ const { result, external } = stepWithMeta(def, prev, event, impl);
248
+ if (result.changed && (prev.value !== result.snapshot.value || external)) {
249
+ swapChild(prev.value, result.snapshot.value);
265
250
  }
266
- const initStateDef = def.states[nextSnap.value];
267
- if (initStateDef?.sub) {
268
- initChildFor(nextSnap.value);
251
+ commit(prev, result.snapshot, event, result.effects, result.changed);
252
+ }
253
+ function processReset(event) {
254
+ const prev = snapshot;
255
+ const next = initialSnapshot(def);
256
+ swapChild(prev.value, next.value);
257
+ commit(
258
+ prev,
259
+ next,
260
+ event ?? RESET_EVENT,
261
+ [],
262
+ prev.value !== next.value || prev.status !== next.status || prev.context !== next.context
263
+ );
264
+ }
265
+ function run(entry) {
266
+ if (disposed) throw new RuntimeDisposedError();
267
+ if ((entry.kind === "send" || entry.event !== void 0) && typeof entry.event?.type !== "string") {
268
+ throw new InvalidDefinitionError(
269
+ `${entry.kind}() event must be an object with a string type`
270
+ );
269
271
  }
270
- snapshot = nextSnap;
271
- const committed = nextSnap;
272
- const triggerEvent = event ?? RESET_EVENT;
273
- runMiddleware(prev, triggerEvent, [], changed);
274
- if (changed) {
275
- notify(committed);
276
- emit("transition", {
277
- prev,
278
- next: committed,
279
- event: triggerEvent,
280
- effects: [],
281
- changed: true
282
- });
272
+ if (dispatching) {
273
+ mailbox.push(entry);
274
+ return snapshot;
283
275
  }
284
- return snapshot;
285
- }
286
- function can(event) {
287
- if (disposed || snapshot.status === "final") return false;
288
- const state = def.states[snapshot.value];
289
- if (!state) return false;
290
- const list = normalizeTransitions(state.on?.[event.type]);
291
- if (list.length === 0) return false;
292
- for (const t of list) {
293
- if (!t.guard) return true;
294
- if (evalGuard(t.guard, snapshot.context, event, impl, snapshot.value)) return true;
276
+ dispatching = true;
277
+ try {
278
+ for (let m = entry; m && !disposed; m = mailbox.shift()) {
279
+ if (m.kind === "send") processSend(m.event);
280
+ else processReset(m.event);
281
+ }
282
+ } finally {
283
+ dispatching = false;
284
+ mailbox.length = 0;
295
285
  }
296
- return false;
286
+ return snapshot;
297
287
  }
298
288
  function on(type, listener, options) {
289
+ if (!Object.hasOwn(eventListeners, type)) {
290
+ throw new InvalidDefinitionError('on() type must be "transition", "error" or "dispose"');
291
+ }
292
+ assertListener(listener);
299
293
  if (disposed || options?.signal?.aborted) return () => {
300
294
  };
301
295
  const target = eventListeners[type];
@@ -327,14 +321,12 @@ function createRuntime(def, impl, opts = {}) {
327
321
  function dispose() {
328
322
  if (disposed) return;
329
323
  disposed = true;
330
- if (childRuntime) {
331
- childAbortCleanup?.();
332
- childAbortCleanup = void 0;
333
- try {
334
- childRuntime.dispose();
335
- } catch {
336
- }
337
- childRuntime = void 0;
324
+ mailbox.length = 0;
325
+ const child = childRuntime;
326
+ childRuntime = void 0;
327
+ try {
328
+ child?.dispose();
329
+ } catch {
338
330
  }
339
331
  controller.abort();
340
332
  listeners.clear();
@@ -350,9 +342,10 @@ function createRuntime(def, impl, opts = {}) {
350
342
  const runtime = {
351
343
  getSnapshot: () => snapshot,
352
344
  snapshot: () => snapshot,
353
- send,
354
- can,
355
- reset,
345
+ send: (event) => run({ kind: "send", event }),
346
+ // Same candidate resolution as step(), without running any action.
347
+ can: (event) => !disposed && chooseTransition(def, snapshot, event, impl) !== void 0,
348
+ reset: (event) => run({ kind: "reset", event }),
356
349
  dispose,
357
350
  on,
358
351
  get disposed() {
@@ -362,6 +355,7 @@ function createRuntime(def, impl, opts = {}) {
362
355
  return controller.signal;
363
356
  },
364
357
  subscribe(listener) {
358
+ assertListener(listener);
365
359
  if (disposed) return () => {
366
360
  };
367
361
  listeners.add(listener);
@@ -370,13 +364,10 @@ function createRuntime(def, impl, opts = {}) {
370
364
  subRuntime: () => childRuntime,
371
365
  onTransition: (handler, options) => on("transition", handler, options)
372
366
  };
373
- const bootStateDef = def.states[snapshot.value];
374
- if (bootStateDef?.sub) {
375
- initChildFor(snapshot.value);
376
- }
367
+ swapChild(snapshot.value, snapshot.value);
377
368
  return runtime;
378
369
  }
379
370
 
380
371
  export { InvalidDefinitionError, RESET_EVENT_TYPE, RuntimeDisposedError, SubMachineError, createMachine, createRuntime, defineMachine, initialSnapshot, setup };
381
- //# sourceMappingURL=chunk-LG2AH5X6.js.map
382
- //# sourceMappingURL=chunk-LG2AH5X6.js.map
372
+ //# sourceMappingURL=chunk-XA24A7VP.js.map
373
+ //# sourceMappingURL=chunk-XA24A7VP.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/fsm/types.ts","../src/fsm/definition.ts","../src/fsm/runtime.ts"],"names":[],"mappings":"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","file":"chunk-XA24A7VP.js","sourcesContent":["// All public types live here so AI agents and humans can read the entire\n// public surface in one file.\n\nexport type Effect = Readonly<{ type: string; payload?: unknown }>;\n\nexport type Enqueuer = Readonly<{\n effect: (type: string, payload?: unknown) => void;\n}>;\n\nexport type GuardArgs<Ctx, Evt> = Readonly<{\n context: Ctx;\n event: Evt;\n /**\n * Optional guard registry, threaded by `evalGuard` so combinators can resolve\n * string refs nested inside `and / or / not`. Inline user guards may safely\n * ignore this field — it is `undefined` when guards are evaluated outside of\n * `evalGuard` (e.g. in unit tests calling the function directly).\n */\n guards?: Readonly<Record<string, Guard<Ctx, Evt>>>;\n /**\n * Current state value, threaded by `evalGuard` from the live snapshot. Used\n * by the `stateIn` combinator. `undefined` when guards are called outside of\n * a lifecycle evaluation.\n */\n value?: string;\n}>;\n\nexport type Guard<Ctx, Evt> = (args: GuardArgs<Ctx, Evt>) => boolean;\n\nexport type Action<Ctx, Evt> = (args: {\n context: Ctx;\n event: Evt;\n enqueue: Enqueuer;\n}) => Partial<Ctx> | void;\n\nexport type EffectHandler<Ctx, Evt> = (\n effect: Effect,\n args: { context: Ctx; event: Evt; signal: AbortSignal },\n) => void | Promise<void>;\n\nexport type GuardRef<Ctx, Evt> = string | Guard<Ctx, Evt>;\nexport type ActionRef<Ctx, Evt> = string | Action<Ctx, Evt>;\n\nexport type TransitionDef<Ctx, Evt, States extends string> = Readonly<{\n target?: States;\n guard?: GuardRef<Ctx, Evt>;\n actions?: readonly ActionRef<Ctx, Evt>[];\n}>;\n\n/**\n * A single transition as written in a `StateDef.on` map. Either the full\n * {@link TransitionDef} object form, or the string shorthand `\"targetState\"`\n * (à la XState) which the resolver normalizes to `{ target: \"targetState\" }`\n * before processing. The shorthand carries no guard or actions.\n *\n * @since 0.5.3\n */\nexport type TransitionConfig<Ctx, Evt, States extends string> =\n | States\n | TransitionDef<Ctx, Evt, States>;\n\n/**\n * @experimental v0.3.0\n *\n * A nested machine definition attachable to StateDef.sub. The type parameters\n * are independent from the parent machine's <Ctx, Evt, States>; sub-machines\n * may have entirely unrelated context and event shapes.\n *\n * This is an alias for MachineDef — sub-machines have the same definition\n * shape as top-level machines. The relationship is purely lifecycle:\n * a sub-machine instance is created when its parent state becomes active\n * and disposed when the parent state exits.\n */\nexport type SubMachineDef<\n SubCtx,\n SubEvt extends { type: string },\n SubStates extends string,\n> = MachineDef<SubCtx, SubEvt, SubStates>;\n\nexport type StateDef<Ctx, Evt, States extends string> = Readonly<{\n on?: Readonly<\n Record<\n string,\n TransitionConfig<Ctx, Evt, States> | readonly TransitionConfig<Ctx, Evt, States>[]\n >\n >;\n entry?: readonly ActionRef<Ctx, Evt>[];\n exit?: readonly ActionRef<Ctx, Evt>[];\n final?: boolean;\n /**\n * Optional sub-machine. When the runtime enters a state with `sub`,\n * the sub-machine is lazily instantiated; when it exits, the sub-machine\n * is disposed. See STABILITY.md for the experimental contract.\n *\n * The generic parameters are erased to `any` because sub-machine type\n * parameters are intentionally independent from the parent's `Ctx` / `Evt`\n * / `States`. `MachineDef`'s generics are invariant (guards / actions\n * consume them), so the storage position must use `any` rather than\n * `unknown`. Caller narrows via `runtime.subRuntime() as Runtime<...>`.\n *\n * @experimental since 0.3.0\n */\n // biome-ignore lint/suspicious/noExplicitAny: see JSDoc — invariant generic escape hatch\n sub?: MachineDef<any, any, any>;\n /**\n * Implementations for `sub`. Ignored if `sub` is absent. Defaults to `{}`\n * (sub-machine must rely on inline guards / actions / effects only).\n *\n * @experimental since 0.3.0\n */\n // biome-ignore lint/suspicious/noExplicitAny: same reason as `sub` above\n subImpl?: Implementations<any, any>;\n}>;\n\nexport type MachineDef<Ctx, Evt extends { type: string }, States extends string> = Readonly<{\n id: string;\n initial: States;\n context: Ctx;\n states: Readonly<Record<States, StateDef<Ctx, Evt, States>>>;\n}>;\n\n/**\n * Input shape accepted by `defineMachine` / `setup().defineMachine`. Identical\n * to {@link MachineDef} except `context` is **optional** — when omitted it\n * defaults to `{}` (paired with the `Ctx = Record<string, never>` default type\n * parameter). The returned value is always a fully-normalized\n * {@link MachineDef} with `context` present, so downstream consumers are\n * unaffected.\n *\n * @since 0.5.3\n */\nexport type MachineConfig<Ctx, Evt extends { type: string }, States extends string> = Readonly<{\n id: string;\n initial: States;\n states: Readonly<Record<States, StateDef<Ctx, Evt, States>>>;\n}> &\n // `context` may be omitted only when `Ctx` has no required properties (e.g. the\n // default `Record<string, never>`). If `Ctx` has required fields it must be\n // supplied, so omitting it can't silently default to `{}` and crash at runtime.\n (Record<string, never> extends Ctx ? { readonly context?: Ctx } : { readonly context: Ctx });\n\nexport type Snapshot<Ctx, States extends string> = Readonly<{\n value: States;\n context: Ctx;\n status: \"active\" | \"final\";\n}>;\n\nexport type Implementations<Ctx, Evt> = Readonly<{\n guards?: Readonly<Record<string, Guard<Ctx, Evt>>>;\n actions?: Readonly<Record<string, Action<Ctx, Evt>>>;\n effects?: Readonly<Record<string, EffectHandler<Ctx, Evt>>>;\n}>;\n\nexport type StepResult<Ctx, States extends string> = Readonly<{\n snapshot: Snapshot<Ctx, States>;\n effects: readonly Effect[];\n changed: boolean;\n}>;\n\n/**\n * Sentinel event type that `Runtime.reset()` synthesises when the caller does\n * not pass an explicit event. Middleware receives it through\n * `MiddlewareContext.event`. Exposed so user code can discriminate.\n */\nexport const RESET_EVENT_TYPE = \"@@aifsmjs/RESET\" as const;\nexport type ResetEvent = Readonly<{ type: typeof RESET_EVENT_TYPE }>;\n\nexport type MiddlewareContext<Ctx, Evt, States extends string> = Readonly<{\n prev: Snapshot<Ctx, States>;\n next: Snapshot<Ctx, States>;\n /**\n * The triggering event. May be the user's `Evt` (from `send()` or an\n * explicit `reset(event)`) or the `ResetEvent` sentinel emitted by a\n * `reset()` with no event argument. This is the caller's event object,\n * passed unfrozen; treat it as read-only.\n */\n event: Evt | ResetEvent;\n /** Deep-frozen effect descriptors (payloads included) about to be dispatched. */\n effects: readonly Effect[];\n changed: boolean;\n}>;\n\nexport type Middleware<Ctx, Evt, States extends string> = (\n ctx: MiddlewareContext<Ctx, Evt, States>,\n next: () => void,\n) => void;\n\n/**\n * Payload of the `'transition'` runtime event — emitted whenever a transition\n * fired (`changed === true`), including an internal transition whose state\n * `value` did not change (only its `context` did).\n */\nexport type RuntimeTransitionEvent<Ctx, Evt, States extends string> = Readonly<{\n prev: Snapshot<Ctx, States>;\n next: Snapshot<Ctx, States>;\n event: Evt | ResetEvent;\n effects: readonly Effect[];\n changed: boolean;\n}>;\n\n/**\n * Payload of the `'error'` runtime event — currently emitted for async effect\n * handler rejections (which would otherwise become unhandled). With no\n * `'error'` listener (none registered, or cleared by `dispose()`) a rejection\n * is discarded; outside production (`NODE_ENV !== \"production\"`) it is also\n * reported via `console.warn`. Synchronous throws from effect handlers and\n * middleware still propagate to the caller of `send()` / `reset()`.\n */\nexport type RuntimeErrorEvent<Evt> = Readonly<{\n error: unknown;\n event: Evt | ResetEvent | undefined;\n}>;\n\nexport type RuntimeEventMap<Ctx, Evt, States extends string> = {\n transition: RuntimeTransitionEvent<Ctx, Evt, States>;\n error: RuntimeErrorEvent<Evt>;\n dispose: void;\n};\n\nexport interface Runtime<Ctx, Evt extends { type: string }, States extends string> {\n getSnapshot(): Snapshot<Ctx, States>;\n /** Alias for `getSnapshot()`. */\n snapshot(): Snapshot<Ctx, States>;\n /**\n * Process `event`: `step()` -> sub-machine lifecycle -> commit ->\n * middleware -> effects -> `subscribe` listeners -> `'transition'`\n * listeners, then return the committed snapshot.\n *\n * Run-to-completion: a `send()`/`reset()` made while this runtime is already\n * processing an event (from middleware, an effect handler, a listener, or a\n * child runtime's listener) is queued FIFO and processed after the current\n * event's last notification, with the same full sequence. Such a nested\n * call returns the snapshot committed at the time of the call, not the\n * outcome of its own event — read `getSnapshot()` after the outermost call\n * returns (or subscribe). A throw from any queued event discards the rest\n * of the queue and propagates from the outermost call.\n *\n * Throws `RuntimeDisposedError` after `dispose()`, and\n * `InvalidDefinitionError` when `event` is not an object with a string\n * `type`.\n */\n send(event: Evt): Snapshot<Ctx, States>;\n /**\n * Predict whether sending `event` would fire a transition. Reuses\n * `resolveTransitions` + `evalGuard` without applying any actions. Guards\n * are expected to be pure; `can` then matches `send` for the same input.\n */\n can(event: Evt): boolean;\n /**\n * Call `listener` with the committed snapshot after every event that fired\n * a transition (`changed === true`), after middleware and effects and before\n * `'transition'` listeners. A listener removed during a notification round\n * is skipped for the rest of it; one added waits for the next event.\n * Throws `InvalidDefinitionError` if `listener` is not a function. Returns\n * an unsubscribe function (a no-op after `dispose()`).\n */\n subscribe(listener: (snap: Snapshot<Ctx, States>) => void): () => void;\n /**\n * EventTarget-like typed listener API. Returns an unsubscribe function.\n * `options.signal` removes the listener when aborted; `options.once`\n * removes the listener before its first invocation. A listener removed\n * while an event is being dispatched (by its unsubscribe, `once`, its\n * signal, or `dispose()`) is skipped for the rest of that dispatch; one\n * added waits for the next event. Throws `InvalidDefinitionError` for an\n * unknown event `type` or a non-function `listener`. After `dispose()`,\n * `on()` is a no-op and returns a no-op unsubscribe.\n */\n on<K extends keyof RuntimeEventMap<Ctx, Evt, States>>(\n type: K,\n listener: (payload: RuntimeEventMap<Ctx, Evt, States>[K]) => void,\n options?: { signal?: AbortSignal; once?: boolean },\n ): () => void;\n /**\n * Re-initialise the runtime to the definition's initial snapshot. Does NOT\n * run entry actions (reset = re-birth, not \"transition into initial\"); the\n * current sub-machine child is always replaced. Notifies subscribers,\n * middleware (`changed: true`) and `'transition'` listeners whenever the\n * value, status, or context reference differs from the initial snapshot.\n * Throws RuntimeDisposedError if disposed. If an `event` is supplied (an\n * object with a string `type`, else `InvalidDefinitionError`), middleware\n * sees it as the trigger; otherwise a sentinel\n * `{ type: \"@@aifsmjs/RESET\" }` is synthesised. Run-to-completion like\n * `send()`: a nested call is queued.\n */\n reset(event?: Evt): Snapshot<Ctx, States>;\n /**\n * Tear down: abort the internal AbortController (effect handlers see signal\n * fire), clear listeners, and mark this runtime as disposed. Subsequent\n * send()/reset() calls throw RuntimeDisposedError. Idempotent and never\n * throws. Never queued: called during a dispatch it runs at once, drops any\n * queued send()/reset() calls, and the outer call returns the last\n * committed snapshot.\n */\n dispose(): void;\n /**\n * True after `dispose()` has been called.\n */\n readonly disposed: boolean;\n /**\n * AbortSignal scoped to this runtime's lifetime. Fires once on dispose().\n * Threaded to every EffectHandler invocation; external integrations\n * (e.g. component teardown) can also attach `signal.addEventListener(\"abort\", ...)`.\n */\n readonly signal: AbortSignal;\n /**\n * @experimental v0.3.0\n *\n * Returns the currently active sub-Runtime for the current parent state,\n * or undefined if:\n * - the current state has no `sub` definition, OR\n * - the previous child's `dispose()` threw during a transition\n * (SubMachineError phase \"dispose\"; the parent stays in its state and\n * the child is recreated when the state is re-entered), OR\n * - the parent runtime has been disposed.\n *\n * When a transition's new child fails to initialise (SubMachineError phase\n * \"init\"), the previous child is left untouched and is still returned. A\n * child that fails to initialise at `createRuntime` bootstrap makes\n * `createRuntime` itself throw, so there is no runtime to ask.\n *\n * The returned Runtime is typed at the loosest sub-machine signature.\n * Caller casts to the concrete sub type.\n *\n * Re-entry: when the parent leaves and re-enters a state with `sub`, a\n * fresh sub-Runtime is constructed. Previous sub-Runtime references held\n * by the caller are stale and MUST NOT be used (disposed).\n */\n subRuntime(): Runtime<unknown, { type: string }, string> | undefined;\n /**\n * Semantic sugar for `runtime.on('transition', handler, opts)`. Returns\n * the same unsubscribe function. Sharing the same listener Set with\n * `on('transition', ...)` means registration order determines invocation\n * order across both APIs.\n *\n * @since 0.3.0\n */\n onTransition(\n handler: (payload: RuntimeTransitionEvent<Ctx, Evt, States>) => void,\n options?: { signal?: AbortSignal; once?: boolean },\n ): () => void;\n}\n\nexport type RuntimeOptions<Ctx, Evt, States extends string> = Readonly<{\n middleware?: readonly Middleware<Ctx, Evt, States>[];\n /**\n * If false, do not dispatch effects through the effect handler map.\n * Useful for replay / dry-run modes. Defaults to true.\n */\n dispatchEffects?: boolean;\n}>;\n","import { isAsyncGuardFn } from \"./evaluator.js\";\nimport { normalizeTransitions } from \"./resolver.js\";\nimport { createRuntime } from \"./runtime.js\";\nimport { freezeSnapshot } from \"./snapshot.js\";\nimport type {\n Implementations,\n MachineConfig,\n MachineDef,\n Runtime,\n RuntimeOptions,\n Snapshot,\n StateDef,\n} from \"./types.js\";\n\n/**\n * Thrown for an invalid machine definition and, since 0.6.0, for argument\n * misuse at the definition/runtime boundary (`defineMachine`,\n * `setup().defineMachine`, `createMachine`, `createRuntime`, and the\n * `send` / `reset` / `subscribe` / `on` / `onTransition` runtime methods).\n * Messages read `aifsmjs: <subject> must be <constraint>`.\n */\nexport class InvalidDefinitionError extends Error {\n constructor(message: string) {\n super(`aifsmjs: ${message}`);\n this.name = \"InvalidDefinitionError\";\n }\n}\n\n/** Throw `InvalidDefinitionError(\"<subject> must be an object\")` unless `value` is a non-null object. */\nexport function assertObject(value: unknown, subject: string): void {\n if (value === null || typeof value !== \"object\") {\n throw new InvalidDefinitionError(`${subject} must be an object`);\n }\n}\n\nfunction validateDefinition<Ctx, Evt extends { type: string }, States extends string>(\n def: MachineDef<Ctx, Evt, States>,\n // Cycle guard: subs may reference each other (or themselves) by object\n // identity. We validate each distinct definition object at most once so a\n // self/mutually-referential sub graph terminates instead of recursing\n // forever (C2). Seeded by the public entry points below.\n seen: WeakSet<object> = new WeakSet(),\n): void {\n if (!def.id || typeof def.id !== \"string\") {\n throw new InvalidDefinitionError(\"definition must have a non-empty string `id`\");\n }\n assertObject(def.states, \"definition states\");\n const stateKeys = Object.keys(def.states) as States[];\n if (stateKeys.length === 0) {\n throw new InvalidDefinitionError(\"`states` must declare at least one state\");\n }\n if (!def.initial || !stateKeys.includes(def.initial)) {\n throw new InvalidDefinitionError(\n `\\`initial\\` \"${String(def.initial)}\" is not declared in states (${stateKeys.join(\", \")})`,\n );\n }\n for (const [stateName, stateDef] of Object.entries(def.states) as [\n States,\n (typeof def.states)[States],\n ][]) {\n assertObject(stateDef, `state \"${stateName}\"`);\n // §4 sub-shape check + deep recursion (C2). The shallow shape check rejects\n // a malformed sub; recursing validateDefinition into the sub then rejects an\n // unknown transition target or a declared-async guard at construction\n // instead of leaving it to blow up at child.send(). Closes the FSM-07 sub\n // async-guard discrepancy (same root). The cycle guard makes this safe for\n // self/mutually-referential subs.\n if (stateDef.sub !== undefined) {\n const sub = stateDef.sub;\n const subStates = (sub as { states?: unknown }).states;\n const subInitial = (sub as { initial?: unknown }).initial;\n if (\n typeof sub !== \"object\" ||\n sub === null ||\n typeof subStates !== \"object\" ||\n subStates === null ||\n typeof subInitial !== \"string\" ||\n // initial must name one of the sub's own states — otherwise the child\n // boots pointing at a non-existent state and no-ops forever (FSM-S-02).\n !Object.hasOwn(subStates as object, subInitial)\n ) {\n throw new InvalidDefinitionError(\n `state \"${stateName}\".sub is not a valid sub-machine definition (missing states or initial)`,\n );\n }\n // Recurse — but only once per distinct sub object (cycle guard).\n if (!seen.has(sub as object)) {\n seen.add(sub as object);\n validateDefinition(sub as MachineDef<unknown, { type: string }, string>, seen);\n }\n }\n if (!stateDef.on) continue;\n for (const [evtType, entry] of Object.entries(stateDef.on)) {\n const transitions = normalizeTransitions(entry);\n for (const t of transitions) {\n assertObject(t, `transition ${stateName} -[${evtType}]->`);\n if (t.target !== undefined && !stateKeys.includes(t.target)) {\n throw new InvalidDefinitionError(\n `transition ${stateName} -[${evtType}]-> \"${String(t.target)}\" targets an unknown state`,\n );\n }\n if (t.guard !== undefined && isAsyncGuardFn(t.guard)) {\n throw new InvalidDefinitionError(\n `transition ${stateName} -[${evtType}]-> uses an async guard. Guards must be sync; move I/O into an effect.`,\n );\n }\n }\n }\n }\n // Initial-state sub chain (C2 cycle guard does not cover it): createRuntime\n // boots the child of every initial state eagerly, so a chain of initial-state\n // subs that revisits a definition would recurse until the stack overflows.\n // Runs once per distinct definition (root + each sub reached above). Subs\n // reachable only through non-initial states may still be self-referential.\n const path = new Set<object>();\n let d = def as MachineDef<unknown, { type: string }, string> | undefined;\n while (d) {\n if (path.has(d)) {\n throw new InvalidDefinitionError(\n `sub-machine cycle through initial states: \"${d.id}\" is re-entered via initial-state subs`,\n );\n }\n path.add(d);\n d = d.states[d.initial]?.sub;\n }\n}\n\n/**\n * Validate a machine definition shape and return it. When `context` is\n * provided the same reference is returned; when it is omitted a shallow copy\n * with `context: {}` is returned. Validation is intentionally shallow.\n *\n * Two call forms:\n *\n * defineMachine<Ctx, Evt, States>({ ... })\n * Explicit generics. Use when you need full control (e.g. union event\n * types). Required because TypeScript cannot otherwise infer `Evt`.\n *\n * setup<Ctx, Evt>().defineMachine({ ... })\n * Curried form. Lets `States` be inferred from `keyof states`, so you\n * can omit it. Recommended for typical usage.\n */\nexport function defineMachine<\n Ctx = Record<string, never>,\n Evt extends { type: string } = { type: string },\n States extends string = string,\n>(def: MachineConfig<Ctx, Evt, States>): MachineDef<Ctx, Evt, States> {\n assertObject(def, \"definition\");\n const normalized = (\n def.context === undefined ? { ...def, context: {} as Ctx } : def\n ) as MachineDef<Ctx, Evt, States>;\n validateDefinition(normalized);\n return normalized;\n}\n\n/**\n * Curried builder so `States` can be inferred from `keyof states` without\n * `initial` or a transition `target` collapsing it to a single literal. Pass\n * `Ctx` and `Evt` as the type arguments; pass the def to the returned\n * `defineMachine`.\n *\n * const machine = setup<MyCtx, MyEvt>().defineMachine({\n * id: \"m\",\n * initial: \"a\",\n * context: { ... },\n * states: { a: {...}, b: {...} }, // States inferred as \"a\" | \"b\"\n * });\n */\nexport function setup<\n Ctx = Record<string, never>,\n Evt extends { type: string } = { type: string },\n>(): {\n defineMachine: <const States extends string>(\n def: Readonly<{\n id: string;\n initial: NoInfer<States>;\n states: Readonly<{ [K in States]: StateDef<Ctx, Evt, NoInfer<States>> }>;\n }> &\n (Record<string, never> extends Ctx ? { readonly context?: Ctx } : { readonly context: Ctx }),\n ) => MachineDef<Ctx, Evt, States>;\n} {\n // Same normalisation + validation as defineMachine; only the type-level\n // signature differs (States inferred from `keyof states`).\n return { defineMachine: defineMachine as never };\n}\n\n/**\n * Build the initial snapshot for a machine.\n */\nexport function initialSnapshot<Ctx, Evt extends { type: string }, States extends string>(\n def: MachineDef<Ctx, Evt, States>,\n): Snapshot<Ctx, States> {\n const isFinal = def.states[def.initial]?.final === true;\n return freezeSnapshot({\n value: def.initial,\n context: def.context,\n status: isFinal ? (\"final\" as const) : (\"active\" as const),\n });\n}\n\n/**\n * Convenience factory that composes `defineMachine` and `createRuntime` in\n * one call for the common case where you do not need to keep the machine\n * definition around for serialization or sharing.\n *\n * For type inference over `States` from `keyof states`, prefer\n * `setup<Ctx, Evt>().defineMachine(...)` then pass the result to\n * `createRuntime` separately. `createMachine` is the spec-style entry point\n * documented in the ai*js ecosystem review.\n */\nexport function createMachine<Ctx, Evt extends { type: string }, States extends string>(\n def: MachineDef<Ctx, Evt, States>,\n impl: Implementations<Ctx, Evt>,\n opts?: RuntimeOptions<Ctx, Evt, States>,\n): Runtime<Ctx, Evt, States> {\n return createRuntime(defineMachine(def), impl, opts ?? {});\n}\n","import { InvalidDefinitionError, assertObject, initialSnapshot } from \"./definition.js\";\nimport { isThenable, ownValue } from \"./evaluator.js\";\nimport { chooseTransition, stepWithMeta } from \"./lifecycle.js\";\nimport { IS_DEV, deepFreeze } from \"./snapshot.js\";\nimport {\n type Effect,\n type Implementations,\n type MachineDef,\n type Middleware,\n RESET_EVENT_TYPE,\n type ResetEvent,\n type Runtime,\n type RuntimeEventMap,\n type RuntimeOptions,\n type RuntimeTransitionEvent,\n type Snapshot,\n} from \"./types.js\";\n\nexport class RuntimeDisposedError extends Error {\n constructor() {\n super(\"aifsmjs: runtime has been disposed; send()/reset() are not allowed\");\n this.name = \"RuntimeDisposedError\";\n }\n}\n\n/**\n * Thrown by `send()` / `reset()` when a sub-machine init or dispose throws.\n *\n * Prepare-then-commit: the new child is constructed before the previous one\n * is disposed. Invariants:\n * - `phase: \"init\"` — the new child's constructor threw. The parent snapshot\n * is not committed and the previous child (if any) is untouched: still live\n * and still returned by `subRuntime()`. No middleware ran, no `'transition'`\n * was emitted, no effects were dispatched.\n * - `phase: \"dispose\"` — the previous child's `dispose()` threw. The new\n * child (if any) was discarded, the parent snapshot is not committed, and\n * `subRuntime()` returns `undefined` until the sub state is re-entered.\n * - Never thrown from `runtime.dispose()` cascade (never-throws contract).\n *\n * @since 0.3.0\n */\nexport class SubMachineError extends Error {\n readonly parentState: string;\n readonly phase: \"init\" | \"dispose\";\n override readonly cause: unknown;\n\n constructor(parentState: string, phase: \"init\" | \"dispose\", cause: unknown) {\n super(`aifsmjs: sub-machine ${phase} failed at parent state \"${parentState}\"`, { cause });\n this.name = \"SubMachineError\";\n this.parentState = parentState;\n this.phase = phase;\n this.cause = cause; // belt-and-suspenders: legacy bundlers ignore ES2022 cause option\n }\n}\n\nconst RESET_EVENT: ResetEvent = Object.freeze({ type: RESET_EVENT_TYPE });\n\nfunction composeMiddleware<Ctx, Evt, States extends string>(\n middleware: readonly Middleware<Ctx, Evt, States>[],\n): Middleware<Ctx, Evt, States> {\n return (ctx, finalNext) => {\n let index = -1;\n const dispatch = (i: number): void => {\n if (i <= index) throw new Error(\"aifsmjs: next() called multiple times in middleware\");\n index = i;\n const fn = middleware[i];\n if (!fn) {\n finalNext();\n return;\n }\n fn(ctx, () => dispatch(i + 1));\n };\n dispatch(0);\n };\n}\n\ntype Queued<Evt> = { kind: \"send\"; event: Evt } | { kind: \"reset\"; event?: Evt | undefined };\n\nfunction assertListener(listener: unknown): void {\n if (typeof listener !== \"function\") {\n throw new InvalidDefinitionError(\"listener must be a function\");\n }\n}\n\n/**\n * Build a thin stateful runtime around a machine. `send()` calls `step()`,\n * commits, runs the read-only middleware pipeline, dispatches effects, and\n * notifies subscribers then `'transition'` listeners. `send()`/`reset()` are\n * run-to-completion: a call made while the runtime is already dispatching\n * (from middleware, an effect handler, a listener, or a child runtime) is\n * queued FIFO and processed after the current event's last notification.\n * The runtime owns an `AbortController`; `dispose()` aborts it and clears all\n * state.\n *\n * Arguments are validated before anything is created: a non-object `def`,\n * `def.states`, `impl` or `opts`, or a `middleware` option that is not an\n * array of functions, throws `InvalidDefinitionError`. The rest of `def` is\n * trusted (build it with `defineMachine` / `setup().defineMachine`).\n */\nexport function createRuntime<Ctx, Evt extends { type: string }, States extends string>(\n def: MachineDef<Ctx, Evt, States>,\n impl: Implementations<Ctx, Evt>,\n opts: RuntimeOptions<Ctx, Evt, States> = {},\n): Runtime<Ctx, Evt, States> {\n assertObject(def, \"definition\");\n assertObject(def.states, \"definition states\");\n assertObject(impl, \"implementations\");\n assertObject(opts, \"options\");\n const middleware = opts.middleware;\n if (\n middleware !== undefined &&\n !(Array.isArray(middleware) && middleware.every((fn) => typeof fn === \"function\"))\n ) {\n throw new InvalidDefinitionError(\"options.middleware must be an array of functions\");\n }\n let snapshot: Snapshot<Ctx, States> = initialSnapshot(def);\n const listeners = new Set<(snap: Snapshot<Ctx, States>) => void>();\n const middlewareChain =\n middleware && middleware.length > 0 ? composeMiddleware(middleware) : undefined;\n const shouldDispatch = opts.dispatchEffects !== false;\n const controller = new AbortController();\n let disposed = false;\n // Run-to-completion (ai*js state-owning dispatcher rule): while one event is\n // being processed, nested send()/reset() calls land in this FIFO mailbox.\n let dispatching = false;\n const mailbox: Queued<Evt>[] = [];\n // §3.1 The live child of the current state's `sub`, if any. Replaced only by\n // swapChild(); cleared by dispose().\n let childRuntime: Runtime<unknown, { type: string }, string> | undefined;\n\n type EventListeners = {\n [K in keyof RuntimeEventMap<Ctx, Evt, States>]: Set<\n (payload: RuntimeEventMap<Ctx, Evt, States>[K]) => void\n >;\n };\n const eventListeners: EventListeners = {\n transition: new Set(),\n error: new Set(),\n dispose: new Set(),\n };\n const externalAbortCleanups = new Set<() => void>();\n\n function emit<K extends keyof RuntimeEventMap<Ctx, Evt, States>>(\n type: K,\n payload: RuntimeEventMap<Ctx, Evt, States>[K],\n ): void {\n // Snapshot-before-iterate (ai*js fan-out rule): a listener added during\n // dispatch first fires on the next event, and one removed meanwhile\n // (unsubscribe, `once`, signal abort, dispose) is skipped for the rest of\n // this dispatch. Per-listener isolation: a throwing listener must not skip\n // the ones after it (a 'dispose' cleanup hook would leak). The first error\n // is rethrown once every listener has run, so it still surfaces.\n const set = eventListeners[type];\n let failed = false;\n let firstError: unknown;\n for (const fn of Array.from(set)) {\n if (!set.has(fn)) continue;\n try {\n fn(payload);\n } catch (err) {\n if (!failed) {\n failed = true;\n firstError = err;\n }\n }\n }\n if (failed) throw firstError;\n }\n\n function dispatchEffects(effects: readonly Effect[], context: Ctx, event: Evt): void {\n if (!impl.effects || effects.length === 0) return;\n for (const eff of effects) {\n const handler = ownValue(impl.effects, eff.type);\n if (!handler) continue;\n const r = handler(eff, { context, event, signal: controller.signal });\n // isThenable (not instanceof Promise) so cross-realm Promises and\n // user-defined PromiseLike results also have their rejections routed to\n // the 'error' channel; Promise.resolve() normalises them (FSM-B-03).\n if (isThenable(r)) {\n Promise.resolve(r).catch((err: unknown) => {\n // Never re-thrown: an unhandledRejection would crash Node >= 15 and\n // break fire-and-forget. With no 'error' listener (none registered,\n // or cleared by dispose()) it is discarded, with a dev-only warning.\n if (eventListeners.error.size > 0) emit(\"error\", { error: err, event });\n else if (IS_DEV) {\n console.warn(\n 'aifsmjs: unhandled async effect rejection; register runtime.on(\"error\", ...)',\n err,\n );\n }\n });\n }\n }\n }\n\n // §3.1 Prepare-then-commit child swap for a move from `prevValue` into\n // `nextValue` (transitions, reset() and bootstrap). Throws SubMachineError;\n // the caller must NOT commit the parent snapshot on throw.\n // 1. Construct the new child first: an init failure leaves the old child\n // live and untouched.\n // 2. Dispose the old child: a failure discards the new child.\n // 3. Adopt the new child — or discard it when a listener run by step 2\n // disposed this runtime meanwhile.\n function swapChild(prevValue: States, nextValue: States): void {\n const stateDef = def.states[nextValue];\n let next: Runtime<unknown, { type: string }, string> | undefined;\n if (stateDef?.sub) {\n try {\n next = createRuntime(stateDef.sub, stateDef.subImpl ?? {});\n } catch (cause) {\n throw new SubMachineError(nextValue, \"init\", cause);\n }\n }\n const old = childRuntime;\n if (old) {\n childRuntime = undefined;\n try {\n old.dispose();\n } catch (cause) {\n next?.dispose(); // a freshly built runtime's dispose() never throws\n throw new SubMachineError(prevValue, \"dispose\", cause);\n }\n }\n if (disposed) next?.dispose();\n else childRuntime = next;\n }\n\n // Commit, then middleware -> effects -> subscribers -> 'transition'.\n function commit(\n prev: Snapshot<Ctx, States>,\n next: Snapshot<Ctx, States>,\n event: Evt | ResetEvent,\n effects: readonly Effect[],\n changed: boolean,\n ): void {\n snapshot = next;\n // Middleware gets the caller's event by reference, never frozen (the\n // caller owns it). The wrapper is frozen, prev/next are already frozen to\n // the NODE_ENV depth (STABILITY.md), and effects are deep-frozen so no\n // middleware can alter a payload before dispatch.\n middlewareChain?.(\n Object.freeze({ prev, next, event, effects: deepFreeze(effects), changed }),\n () => {},\n );\n // reset() commits no effects, so its sentinel event never reaches a handler.\n if (shouldDispatch) dispatchEffects(effects, next.context, event as Evt);\n if (changed) {\n // Same snapshot-before-iterate / skip-removed rule as emit().\n for (const l of Array.from(listeners)) if (listeners.has(l)) l(next);\n emit(\"transition\", {\n prev,\n next,\n event,\n effects,\n changed: true,\n } as RuntimeTransitionEvent<Ctx, Evt, States>);\n }\n }\n\n function processSend(event: Evt): void {\n const prev = snapshot;\n const { result, external } = stepWithMeta(def, prev, event, impl);\n // Sub lifecycle BEFORE snapshot commit (§3.4), decided from the same guard\n // pass as the snapshot; throws SubMachineError on failure → no commit.\n if (result.changed && (prev.value !== result.snapshot.value || external)) {\n swapChild(prev.value, result.snapshot.value);\n }\n commit(prev, result.snapshot, event, result.effects, result.changed);\n }\n\n function processReset(event: Evt | undefined): void {\n const prev = snapshot;\n const next = initialSnapshot(def);\n // reset() is re-birth: the current child is always replaced (§3.5).\n swapChild(prev.value, next.value);\n commit(\n prev,\n next,\n event ?? RESET_EVENT,\n [],\n prev.value !== next.value || prev.status !== next.status || prev.context !== next.context,\n );\n }\n\n function run(entry: Queued<Evt>): Snapshot<Ctx, States> {\n if (disposed) throw new RuntimeDisposedError();\n if (\n (entry.kind === \"send\" || entry.event !== undefined) &&\n typeof entry.event?.type !== \"string\"\n ) {\n throw new InvalidDefinitionError(\n `${entry.kind}() event must be an object with a string type`,\n );\n }\n if (dispatching) {\n // Nested call: queue it and hand back what is committed right now.\n mailbox.push(entry);\n return snapshot;\n }\n dispatching = true;\n try {\n // dispose() empties the mailbox, so the drain stops there too.\n for (let m: Queued<Evt> | undefined = entry; m && !disposed; m = mailbox.shift()) {\n if (m.kind === \"send\") processSend(m.event);\n else processReset(m.event);\n }\n } finally {\n // A throw discards whatever is still queued; the error propagates from\n // this (outermost) call and the snapshot stays at the last commit.\n dispatching = false;\n mailbox.length = 0;\n }\n return snapshot;\n }\n\n function on<K extends keyof RuntimeEventMap<Ctx, Evt, States>>(\n type: K,\n listener: (payload: RuntimeEventMap<Ctx, Evt, States>[K]) => void,\n options?: { signal?: AbortSignal; once?: boolean },\n ): () => void {\n if (!Object.hasOwn(eventListeners, type)) {\n throw new InvalidDefinitionError('on() type must be \"transition\", \"error\" or \"dispose\"');\n }\n assertListener(listener);\n if (disposed || options?.signal?.aborted) return () => {};\n const target = eventListeners[type];\n let detachAbort: (() => void) | undefined;\n // Full teardown shared by the once-wrapper, the abort handler, and the\n // returned unsubscribe so every path detaches the abort listener too — a\n // once-handler that also passed a { signal } previously left the abort\n // listener attached until dispose()/abort (memory leak).\n const cleanup = (): void => {\n target.delete(wrapped);\n if (detachAbort) {\n detachAbort();\n externalAbortCleanups.delete(detachAbort);\n }\n };\n let wrapped: (payload: RuntimeEventMap<Ctx, Evt, States>[K]) => void = listener;\n if (options?.once) {\n // Inert before its first call: removed first, then invoked.\n wrapped = (payload) => {\n cleanup();\n listener(payload);\n };\n }\n target.add(wrapped);\n const signal = options?.signal;\n if (signal) {\n const onAbort = () => cleanup();\n signal.addEventListener(\"abort\", onAbort, { once: true });\n detachAbort = () => signal.removeEventListener(\"abort\", onAbort);\n externalAbortCleanups.add(detachAbort);\n }\n return cleanup;\n }\n\n function dispose(): void {\n if (disposed) return;\n disposed = true;\n // Never queued: runs at once, even mid-dispatch, and drops queued events.\n mailbox.length = 0;\n // Cascade child dispose; swallow exceptions (dispose contract) (§3.6)\n const child = childRuntime;\n childRuntime = undefined;\n try {\n child?.dispose();\n } catch {\n /* swallow */\n }\n controller.abort();\n listeners.clear();\n // §3.6 dispose() is contractually never-throws + idempotent (README,\n // STABILITY.md). emit('dispose') runs user listeners; a throwing one\n // must neither escape dispose() nor abort the remaining teardown (which\n // would leak external-signal abort listeners, since a second dispose()\n // short-circuits on `if (disposed) return`). The try/finally guarantees\n // the listener-set clear + externalAbortCleanups loop ALWAYS run.\n try {\n emit(\"dispose\", undefined as RuntimeEventMap<Ctx, Evt, States>[\"dispose\"]);\n } catch {\n /* swallow — never-throws contract */\n } finally {\n for (const set of Object.values(eventListeners)) set.clear();\n for (const cleanup of externalAbortCleanups) cleanup();\n externalAbortCleanups.clear();\n }\n }\n\n const runtime: Runtime<Ctx, Evt, States> = {\n getSnapshot: () => snapshot,\n snapshot: () => snapshot,\n send: (event) => run({ kind: \"send\", event }),\n // Same candidate resolution as step(), without running any action.\n can: (event) => !disposed && chooseTransition(def, snapshot, event, impl) !== undefined,\n reset: (event) => run({ kind: \"reset\", event }),\n dispose,\n on,\n get disposed() {\n return disposed;\n },\n get signal() {\n return controller.signal;\n },\n subscribe(listener) {\n assertListener(listener);\n if (disposed) return () => {};\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n subRuntime: () => childRuntime,\n onTransition: (handler, options) => on(\"transition\", handler, options),\n };\n\n // §2 Bootstrap: if the initial state has a sub, instantiate the child BEFORE\n // returning. Failure throws SubMachineError(initialState, \"init\", cause).\n swapChild(snapshot.value, snapshot.value);\n\n return runtime;\n}\n"]}