@vielzeug/clockwork 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +220 -0
- package/dist/_dev.cjs +2 -0
- package/dist/_dev.cjs.map +1 -0
- package/dist/_dev.d.ts +2 -0
- package/dist/_dev.d.ts.map +1 -0
- package/dist/_dev.js +9 -0
- package/dist/_dev.js.map +1 -0
- package/dist/_trace.cjs +2 -0
- package/dist/_trace.cjs.map +1 -0
- package/dist/_trace.d.ts +7 -0
- package/dist/_trace.d.ts.map +1 -0
- package/dist/_trace.js +17 -0
- package/dist/_trace.js.map +1 -0
- package/dist/clockwork.cjs +2 -0
- package/dist/clockwork.cjs.map +1 -0
- package/dist/clockwork.iife.js +2 -0
- package/dist/clockwork.iife.js.map +1 -0
- package/dist/clockwork.js +2 -0
- package/dist/clockwork.js.map +1 -0
- package/dist/definition.cjs +2 -0
- package/dist/definition.cjs.map +1 -0
- package/dist/definition.d.ts +16 -0
- package/dist/definition.d.ts.map +1 -0
- package/dist/definition.js +49 -0
- package/dist/definition.js.map +1 -0
- package/dist/devtools.cjs +2 -0
- package/dist/devtools.cjs.map +1 -0
- package/dist/devtools.d.ts +29 -0
- package/dist/devtools.d.ts.map +1 -0
- package/dist/devtools.js +36 -0
- package/dist/devtools.js.map +1 -0
- package/dist/errors.cjs +2 -0
- package/dist/errors.cjs.map +1 -0
- package/dist/errors.d.ts +57 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +64 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/interpret.cjs +2 -0
- package/dist/interpret.cjs.map +1 -0
- package/dist/interpret.d.ts +25 -0
- package/dist/interpret.d.ts.map +1 -0
- package/dist/interpret.js +298 -0
- package/dist/interpret.js.map +1 -0
- package/dist/types.d.ts +277 -0
- package/dist/types.d.ts.map +1 -0
- package/package.json +48 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clockwork.js","names":[],"sources":["../src/errors.ts","../src/_dev.ts","../src/_trace.ts","../src/definition.ts","../src/interpret.ts"],"sourcesContent":["/** Base class for all clockwork errors. Use `instanceof ClockworkError` to catch any clockwork-originated error. */\nexport class ClockworkError extends Error {\n constructor(message: string, opts?: ErrorOptions) {\n super(message, opts);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n\n static is(err: unknown): err is ClockworkError {\n return err instanceof ClockworkError;\n }\n}\n\n/** Thrown when a compound state does not declare an `initial` substate. */\nexport class ClockworkMissingCompoundInitialError extends ClockworkError {\n readonly path: string;\n constructor(message: string, path: string, opts?: ErrorOptions) {\n super(message, opts);\n this.path = path;\n }\n}\n\n/** Thrown when a compound state's `initial` value does not match any substate. */\nexport class ClockworkInvalidInitialStateError extends ClockworkError {\n readonly path: string;\n readonly initial: string;\n constructor(message: string, path: string, initial: string, opts?: ErrorOptions) {\n super(message, opts);\n this.path = path;\n this.initial = initial;\n }\n}\n\n/** Thrown when a transition definition is empty or not a valid array. */\nexport class ClockworkInvalidTransitionArrayError extends ClockworkError {\n readonly path: string;\n readonly eventType?: string;\n constructor(message: string, path: string, eventType?: string, opts?: ErrorOptions) {\n super(message, opts);\n this.path = path;\n this.eventType = eventType;\n }\n}\n\n/** Thrown when a transition or `after` definition targets an unknown state. */\nexport class ClockworkUnknownTargetError extends ClockworkError {\n readonly path: string;\n readonly target: string;\n readonly eventType?: string;\n constructor(message: string, path: string, target: string, eventType?: string, opts?: ErrorOptions) {\n super(message, opts);\n this.path = path;\n this.target = target;\n this.eventType = eventType;\n }\n}\n\n/** Thrown when an `after` delay value is invalid (must be a finite number ≥ 0). */\nexport class ClockworkInvalidAfterDelayError extends ClockworkError {\n readonly path: string;\n readonly delay: number;\n constructor(message: string, path: string, delay: number, opts?: ErrorOptions) {\n super(message, opts);\n this.path = path;\n this.delay = delay;\n }\n}\n\n/** Thrown when `maxTransitionsPerFlush` is configured with a value less than 1. */\nexport class ClockworkInvalidMaxTransitionsError extends ClockworkError {\n readonly maxTransitionsPerFlush: number;\n constructor(message: string, maxTransitionsPerFlush: number, opts?: ErrorOptions) {\n super(message, opts);\n this.maxTransitionsPerFlush = maxTransitionsPerFlush;\n }\n}\n\n/** Thrown when a persisted snapshot references a state that no longer exists in the machine definition. */\nexport class ClockworkInvalidSnapshotStateError extends ClockworkError {\n readonly state: string;\n constructor(message: string, state: string, opts?: ErrorOptions) {\n super(message, opts);\n this.state = state;\n }\n}\n\n/** Thrown when `validateContext` returns a failure reason during init or transition. */\nexport class ClockworkInvalidValidateContextError extends ClockworkError {\n readonly phase: 'init' | 'transition';\n readonly reason: string | true;\n constructor(message: string, phase: 'init' | 'transition', reason: string | true, opts?: ErrorOptions) {\n super(message, opts);\n this.phase = phase;\n this.reason = reason;\n }\n}\n\n/** Thrown when the transition queue exceeds `maxTransitionsPerFlush`, indicating an infinite loop. */\nexport class ClockworkTransitionLoopGuardError extends ClockworkError {\n readonly maxTransitionsPerFlush: number;\n constructor(message: string, maxTransitionsPerFlush: number, opts?: ErrorOptions) {\n super(message, opts);\n this.maxTransitionsPerFlush = maxTransitionsPerFlush;\n }\n}\n","const isDev = !(globalThis as { __CLOCKWORK_PROD__?: boolean }).__CLOCKWORK_PROD__;\n\n/** @internal */\nexport function warn(msg: string): void {\n if (isDev) console.warn(`[@vielzeug/clockwork] ${msg}`);\n}\n\n/** @internal — Run fn only in dev builds. Use when dev-only logic goes beyond a single warn() / error() call. */\nexport function devOnly(fn: () => void): void {\n if (isDev) fn();\n}\n","import type { MachineEvent, TransitionTraceEntry } from './types.js';\n\nexport interface TraceBuffer<State extends string, Ev extends MachineEvent> {\n get(): readonly TransitionTraceEntry<State, Ev>[];\n push(entry: TransitionTraceEntry<State, Ev>): void;\n}\n\nexport function createTraceBuffer<State extends string, Ev extends MachineEvent>(\n limit: number,\n): TraceBuffer<State, Ev> | null {\n if (limit <= 0) return null;\n\n const buffer: TransitionTraceEntry<State, Ev>[] = [];\n let head = 0;\n let count = 0;\n\n return {\n get() {\n if (count === 0) return [];\n\n const entries = count < limit ? buffer.slice(0, count) : [...buffer.slice(head), ...buffer.slice(0, head)];\n\n return entries.map((e) => ({ ...e }));\n },\n push(entry) {\n if (count < limit) {\n buffer.push(entry);\n count++;\n } else {\n buffer[head] = entry;\n head = (head + 1) % limit;\n }\n },\n };\n}\n","import type { MachineConfig, MachineEvent, StateNode, TransitionDef } from './types.js';\n\nimport {\n ClockworkInvalidAfterDelayError,\n ClockworkInvalidInitialStateError,\n ClockworkInvalidTransitionArrayError,\n ClockworkMissingCompoundInitialError,\n ClockworkUnknownTargetError,\n} from './errors.js';\n\n// ── Key safety ────────────────────────────────────────────────────────────────\n\n/**\n * Own-property-only lookup — state paths and event types ultimately come from strings\n * (persisted snapshots, event payloads) that may not be developer-authored. A plain\n * `obj[key]` or `key in obj` resolves inherited `Object.prototype` members (`__proto__`,\n * `constructor`, `toString`, …), which can turn an \"unknown state/event\" into a crash or\n * a silently-accepted bogus value instead of the intended \"not found\". Treat any such key\n * as absent instead.\n */\nconst getOwn = <T>(obj: Record<string, T> | undefined, key: string): T | undefined =>\n obj && Object.hasOwn(obj, key) ? obj[key] : undefined;\n\n// ── Hierarchy helpers (internal — not re-exported from index) ─────────────────\n\n/**\n * Resolves a target state to its deepest initial leaf.\n * For compound states (those with `states` + `initial`), recursively descends.\n */\nexport const resolveLeaf = <Ctx extends object, Ev extends MachineEvent>(\n topLevelStates: Record<string, StateNode<string, Ctx, Ev>>,\n target: string,\n): string => {\n const segments = target.split('.');\n let node = getOwn(topLevelStates, segments[0]);\n\n if (!node) return target;\n\n for (let i = 1; i < segments.length; i++) {\n node = getOwn(node.states, segments[i]);\n\n if (!node) return target;\n }\n\n let path = target;\n\n while (node?.states && node.initial) {\n path = `${path}.${node.initial}`;\n node = getOwn(node.states, node.initial);\n }\n\n return path;\n};\n\n/**\n * Returns the node at a given dot-path.\n */\nexport const getNodeAtPath = <Ctx extends object, Ev extends MachineEvent>(\n topLevelStates: Record<string, StateNode<string, Ctx, Ev>>,\n path: string,\n): StateNode<string, Ctx, Ev> | undefined => {\n const segments = path.split('.');\n let node = getOwn(topLevelStates, segments[0]);\n\n for (let i = 1; i < segments.length; i++) {\n if (!node?.states) return undefined;\n\n node = getOwn(node.states, segments[i]);\n }\n\n return node;\n};\n\n/**\n * Returns ancestor paths from root to leaf (inclusive), e.g. ['a', 'a.b', 'a.b.c']\n */\nexport const getAncestorPaths = (path: string): string[] => {\n const segments = path.split('.');\n const paths: string[] = [];\n\n for (let i = 1; i <= segments.length; i++) {\n paths.push(segments.slice(0, i).join('.'));\n }\n\n return paths;\n};\n\n// ── Validation ───────────────────────────────────────────────────────────────\n\nconst validateNode = <State extends string, Ctx extends object, Ev extends MachineEvent>(\n node: StateNode<string, Ctx, Ev>,\n path: string,\n allTopLevel: Record<string, StateNode<State, Ctx, Ev>>,\n): void => {\n if (node.states && !node.initial) {\n throw new ClockworkMissingCompoundInitialError(`compound state \"${path}\" must have an \"initial\" property`, path);\n }\n\n if (node.initial && node.states && !Object.hasOwn(node.states, node.initial)) {\n throw new ClockworkInvalidInitialStateError(\n `compound state \"${path}\" initial \"${node.initial}\" not found in substates`,\n path,\n node.initial,\n );\n }\n\n for (const [eventType, input] of Object.entries(node.on ?? {})) {\n const defs = Array.isArray(input) ? input : [input];\n\n if (defs.length === 0) {\n throw new ClockworkInvalidTransitionArrayError(\n `state \"${path}\" event \"${eventType}\" must be a non-empty transition or transition array`,\n path,\n eventType,\n );\n }\n\n for (const tr of defs as Array<TransitionDef<State, Ctx, Ev>>) {\n const targetRoot = tr.target.split('.')[0];\n\n if (!Object.hasOwn(allTopLevel, targetRoot)) {\n throw new ClockworkUnknownTargetError(\n `state \"${path}\" event \"${eventType}\" targets unknown state \"${tr.target}\"`,\n path,\n tr.target,\n eventType,\n );\n }\n\n if (tr.target.includes('.') && !getNodeAtPath(allTopLevel, tr.target)) {\n throw new ClockworkUnknownTargetError(\n `state \"${path}\" event \"${eventType}\" targets unknown nested state \"${tr.target}\"`,\n path,\n tr.target,\n eventType,\n );\n }\n }\n }\n\n // Validate empty invoke array (D1)\n if (node.invoke !== undefined && node.invoke.length === 0) {\n throw new ClockworkInvalidTransitionArrayError(`state \"${path}\" invoke must be a non-empty array`, path);\n }\n\n // Validate after targets and delays\n for (const afterDef of node.after ?? []) {\n if (!Number.isFinite(afterDef.delay) || afterDef.delay < 0) {\n throw new ClockworkInvalidAfterDelayError(\n `state \"${path}\" after delay must be a finite number >= 0, got ${afterDef.delay}`,\n path,\n afterDef.delay,\n );\n }\n\n const targetRoot = afterDef.target.split('.')[0];\n\n if (!Object.hasOwn(allTopLevel, targetRoot)) {\n throw new ClockworkUnknownTargetError(\n `state \"${path}\" after[${afterDef.delay}ms] targets unknown state \"${afterDef.target}\"`,\n path,\n afterDef.target,\n );\n }\n\n if (afterDef.target.includes('.') && !getNodeAtPath(allTopLevel, afterDef.target)) {\n throw new ClockworkUnknownTargetError(\n `state \"${path}\" after[${afterDef.delay}ms] targets unknown nested state \"${afterDef.target}\"`,\n path,\n afterDef.target,\n );\n }\n }\n\n if (node.states) {\n for (const [name, child] of Object.entries(node.states)) {\n validateNode(child, `${path}.${name}`, allTopLevel);\n }\n }\n};\n\nexport const validateDefinition = <State extends string, Ctx extends object, Ev extends MachineEvent>(\n definition: MachineConfig<State, Ctx, Ev>,\n): void => {\n const { states } = definition;\n\n if (!Object.hasOwn(states, definition.initial)) {\n throw new ClockworkInvalidInitialStateError(\n `initial state \"${definition.initial}\" not found in states`,\n '',\n definition.initial,\n );\n }\n\n for (const [stateName, node] of Object.entries(states) as Array<[string, StateNode<State, Ctx, Ev>]>) {\n validateNode(node, stateName, states);\n }\n};\n","import { batch, readonly, signal } from '@vielzeug/ripple';\n\nimport type {\n DebugEvent,\n EventByType,\n EventType,\n InterpretOptions,\n LifecycleEvent,\n MachineConfig,\n MachineDefinition,\n MachineEvent,\n MachineInstance,\n MachineSnapshot,\n SendResult,\n StateNode,\n TransitionDef,\n TransitionTraceEntry,\n} from './types.js';\n\nimport { warn } from './_dev';\nimport { createTraceBuffer } from './_trace.js';\nimport { getAncestorPaths, getNodeAtPath, resolveLeaf, validateDefinition } from './definition.js';\nimport {\n ClockworkInvalidMaxTransitionsError,\n ClockworkInvalidSnapshotStateError,\n ClockworkInvalidValidateContextError,\n ClockworkTransitionLoopGuardError,\n} from './errors.js';\n\n// ── Internal constants ────────────────────────────────────────────────────────\n\nconst INIT_EVENT = { type: '$init' } as const;\nconst HYDRATE_EVENT = { type: '$hydrate' } as const;\n\n// ── Pure resolver ─────────────────────────────────────────────────────────────\n\n/**\n * Resolves which transition should be taken for a given state + event.\n * Pure function — no side effects; useful for testing transition logic independently.\n *\n * Optionally calls `onGuard` for each guard evaluation.\n */\nconst resolveTransition = <State extends string, Ctx extends object, Ev extends MachineEvent>(\n definition: Readonly<MachineConfig<State, Ctx, Ev>>,\n input: {\n context: Readonly<Ctx>;\n event: NoInfer<Ev>;\n state: State;\n },\n onGuard?: (info: { context: Readonly<Ctx>; event: Ev; from: State; passed: boolean; target: State }) => void,\n): TransitionDef<State, Ctx, Ev> | undefined => {\n const { context, event, state } = input;\n\n // Defensive: callers piping untyped external data through an `Ev`-typed cast (e.g. a\n // deserialized network message passed to `send()`) can violate the MachineEvent contract\n // at runtime. Treat a missing/non-string `type` as \"no matching transition\" rather than\n // crashing with a raw TypeError.\n if (!event || typeof (event as unknown as { type?: unknown }).type !== 'string') return undefined;\n\n const ancestors = getAncestorPaths(state);\n\n for (let i = ancestors.length - 1; i >= 0; i--) {\n const node = getNodeAtPath(definition.states, ancestors[i]) as StateNode<State, Ctx, Ev> | undefined;\n\n if (!node?.on) continue;\n\n // Own-property check — an event `type` of \"__proto__\"/\"constructor\"/etc. must resolve\n // to \"no matching transition\", not an inherited Object.prototype member.\n const eventType = event.type as EventType<Ev>;\n const raw = Object.hasOwn(node.on, eventType) ? node.on[eventType] : undefined;\n\n if (!raw) continue;\n\n const defs = Array.isArray(raw) ? raw : [raw];\n\n for (const def of defs) {\n const passed = !def.guard || def.guard({ context, event: event as EventByType<Ev, EventType<Ev>> });\n\n onGuard?.({ context, event, from: state, passed, target: def.target as State });\n\n if (passed) return def as TransitionDef<State, Ctx, Ev>;\n }\n }\n\n return undefined;\n};\n\n// ── SendResult helpers ─────────────────────────────────────────────────────────\n\nconst RESULT_TRANSITIONED: SendResult = Object.freeze({ status: 'transitioned' });\nconst RESULT_QUEUED: SendResult = Object.freeze({ status: 'queued' });\nconst RESULT_REJECTED: SendResult = Object.freeze({ status: 'rejected' });\n\n// ── Core interpreter ──────────────────────────────────────────────────────────\n\nconst _interpret = <State extends string, Ctx extends object, Ev extends MachineEvent>(\n definition: Readonly<MachineConfig<State, Ctx, Ev>>,\n options: InterpretOptions<State, Ctx, Ev> = {},\n): MachineInstance<State, Ctx, Ev> => {\n // R8: unified onDebug — no more separate onTransition\n const onDebug = options.onDebug;\n // Auto-enable trace (default 50) when onDebug is set but traceLimit not explicit\n const traceLimit = options.traceLimit ?? (onDebug ? 50 : 0);\n\n if (options.maxTransitionsPerFlush !== undefined && options.maxTransitionsPerFlush < 1) {\n throw new ClockworkInvalidMaxTransitionsError(\n 'maxTransitionsPerFlush must be greater than 0',\n options.maxTransitionsPerFlush,\n );\n }\n\n const maxTransitionsPerFlush = options.maxTransitionsPerFlush ?? 1_000;\n const clone = options.clone ?? structuredClone;\n // Widen State keys to string so getNodeAtPath / getAncestorPaths work with plain string paths.\n const states = definition.states as unknown as Record<string, StateNode<string, Ctx, Ev>>;\n const interceptors = options.interceptors ?? [];\n const persistedSnapshot = options.snapshot ?? options.persistence?.load();\n\n if (persistedSnapshot) {\n const snapshotRoot = persistedSnapshot.state.split('.')[0];\n const snapshotValid =\n Object.hasOwn(definition.states, snapshotRoot) &&\n (!persistedSnapshot.state.includes('.') ||\n !!getNodeAtPath(definition.states as Record<string, StateNode<string, Ctx, Ev>>, persistedSnapshot.state));\n\n if (!snapshotValid) {\n throw new ClockworkInvalidSnapshotStateError(\n `snapshot state \"${persistedSnapshot.state}\" not found in states`,\n persistedSnapshot.state,\n );\n }\n }\n\n // R9: validateContext returns true | string — string is the failure reason\n const assertContext = (context: Ctx, phase: 'init' | 'transition'): void => {\n const validator = definition.validateContext;\n\n if (!validator) return;\n\n const result = validator(context);\n\n if (result !== true) {\n throw new ClockworkInvalidValidateContextError(\n `context failed validation during ${phase}${result ? `: ${result}` : ''}`,\n phase,\n result,\n );\n }\n };\n\n const resolvedInitial = persistedSnapshot\n ? persistedSnapshot.state\n : (resolveLeaf(states, definition.initial) as State);\n\n const initialContext = persistedSnapshot\n ? clone(persistedSnapshot.context)\n : clone(('context' in definition ? definition.context : ({} as Ctx)) as Ctx);\n\n if (!persistedSnapshot) assertContext(initialContext, 'init');\n\n // ── Section: State & context signals ──────────────────────────────────────\n\n const state_ = signal(resolvedInitial);\n const context_ = signal(initialContext);\n\n // ── Section: Trace ring buffer ─────────────────────────────────────────────\n\n const trace = createTraceBuffer<State, Ev>(traceLimit);\n\n // ── Section: Lifecycle ─────────────────────────────────────────────────────\n\n const disposeController = new AbortController();\n let disposed = false;\n\n // ── Section: Invoke scheduler ──────────────────────────────────────────────\n\n let invokeCounter = 0;\n\n const activeInvokes = new Set<{\n controller: AbortController;\n event: Ev | LifecycleEvent;\n id: string;\n /** Path of the state node that owns this invoke — scopes abort-on-exit to that subtree. */\n path: string;\n state: State;\n }>();\n\n /**\n * Aborts active invokes. With `paths`, only invokes owned by one of those state paths are\n * stopped (used when exiting part of the hierarchy); omit `paths` to stop everything (dispose).\n */\n const stopInvokes = (paths?: readonly string[]): void => {\n for (const invoke of activeInvokes) {\n if (paths && !paths.includes(invoke.path)) continue;\n\n invoke.controller.abort();\n onDebug?.({\n context: context_.value,\n event: invoke.event,\n invokeId: invoke.id,\n state: invoke.state,\n type: 'invoke-abort',\n });\n activeInvokes.delete(invoke);\n }\n };\n\n // ── Section: After-timer scheduler ────────────────────────────────────────\n\n const activeTimers = new Set<{ path: string; timer: ReturnType<typeof setTimeout> }>();\n\n /**\n * Clears active after-timers. With `paths`, only timers owned by one of those state paths are\n * cleared (used when exiting part of the hierarchy); omit `paths` to clear everything (dispose).\n */\n const clearTimers = (paths?: readonly string[]): void => {\n for (const entry of activeTimers) {\n if (paths && !paths.includes(entry.path)) continue;\n\n clearTimeout(entry.timer);\n activeTimers.delete(entry);\n }\n };\n\n // ── Section: Persistence ───────────────────────────────────────────────────\n\n const saveSnapshot = (): void => {\n options.persistence?.save({ context: clone(context_.value), state: state_.value });\n };\n\n // ── Section: Subscribe ─────────────────────────────────────────────────────\n\n const subscribers = new Set<(snapshot: MachineSnapshot<State, Ctx>) => void>();\n\n const notifySubscribers = (): void => {\n if (subscribers.size === 0) return;\n\n const snap: MachineSnapshot<State, Ctx> = Object.freeze({ context: context_.value, state: state_.value });\n\n for (const fn of subscribers) fn(snap);\n };\n\n // ── Section: Event queue (hoisted so executeTransition closures can reference) ──\n\n type EventQueueItem = { readonly event: Ev; readonly tag: 'event' };\n type AfterQueueItem = {\n readonly actions: Array<(args: { context: Ctx; readonly event: Ev | LifecycleEvent }) => void>;\n readonly afterEvent: { readonly delay: number; readonly type: '$after' };\n readonly from: State;\n readonly tag: 'after';\n readonly target: State;\n };\n\n type QueueItem = AfterQueueItem | EventQueueItem;\n\n const queue: QueueItem[] = [];\n let draining = false;\n\n // ── Section: Hierarchy / transition execution ──────────────────────────────\n\n const computeTransitionPaths = (from: string, to: string): { entryPaths: string[]; exitPaths: string[] } => {\n if (!from.includes('.') && !to.includes('.')) {\n return { entryPaths: [to], exitPaths: [from] };\n }\n\n if (from === to) {\n return { entryPaths: [to], exitPaths: [from] };\n }\n\n const fromAncestors = getAncestorPaths(from);\n const toAncestors = getAncestorPaths(to);\n\n // Advance while both paths share a common prefix — lcaIndex lands at\n // the first segment that diverges (the deepest common ancestor's depth + 1).\n let lcaIndex = 0;\n\n while (\n lcaIndex < fromAncestors.length &&\n lcaIndex < toAncestors.length &&\n fromAncestors[lcaIndex] === toAncestors[lcaIndex]\n ) {\n lcaIndex++;\n }\n\n return {\n entryPaths: toAncestors.slice(lcaIndex),\n exitPaths: fromAncestors.slice(lcaIndex).reverse(),\n };\n };\n\n const executeTransition = (\n from: State,\n resolvedTarget: State,\n actions: Array<(args: { context: Ctx; readonly event: Ev | LifecycleEvent }) => void>,\n event: Ev | LifecycleEvent,\n ): void => {\n const { entryPaths, exitPaths } = computeTransitionPaths(from, resolvedTarget);\n const draft = clone(context_.value);\n\n for (const path of exitPaths) {\n getNodeAtPath(states, path)?.exit?.({ context: draft, event });\n }\n\n for (const fn of actions) fn({ context: draft, event });\n\n for (const path of entryPaths) {\n getNodeAtPath(states, path)?.entry?.({ context: draft, event });\n }\n\n // Freeze before assertContext so validateContext always receives a read-only context\n Object.freeze(draft);\n assertContext(draft, 'transition');\n\n batch(() => {\n stopInvokes(exitPaths);\n clearTimers(exitPaths);\n state_.value = resolvedTarget;\n context_.value = draft;\n });\n\n // R8: emit unified 'transition' debug event (replaces onTransition callback)\n onDebug?.({ event, from, to: resolvedTarget, type: 'transition' } as DebugEvent<State, Ctx, Ev>);\n trace?.push({ event, from, timestamp: Date.now(), to: resolvedTarget });\n notifySubscribers();\n saveSnapshot();\n // Only (re)start invokes/timers for newly-entered paths — ancestors that remain active\n // across the transition (e.g. a sibling-to-sibling move under the same compound parent)\n // keep their invokes/timers running uninterrupted.\n runInvokes(event, entryPaths);\n scheduleAfterTransitions(entryPaths);\n };\n\n // ── Section: Invoke scheduling ─────────────────────────────────────────────\n\n const runInvokes = (triggerEvent: Ev | LifecycleEvent, paths: readonly string[]): void => {\n for (const path of paths) {\n const node = getNodeAtPath(states, path) as StateNode<State, Ctx, Ev> | undefined;\n\n if (!node?.invoke?.length) continue;\n\n for (const invokeDef of node.invoke) {\n const controller = new AbortController();\n const invokeId = invokeDef.id ?? String(++invokeCounter);\n const capturedContext = context_.value;\n const invokeInfo = { controller, event: triggerEvent, id: invokeId, path, state: state_.value };\n\n activeInvokes.add(invokeInfo);\n onDebug?.({\n context: capturedContext,\n event: triggerEvent,\n invokeId,\n state: state_.value,\n type: 'invoke-start',\n });\n\n void invokeDef\n .src({ context: capturedContext, entryEvent: triggerEvent, signal: controller.signal })\n .then((result) => {\n activeInvokes.delete(invokeInfo);\n\n if (disposed || controller.signal.aborted || !invokeDef.onDone) return;\n\n onDebug?.({\n context: capturedContext,\n event: triggerEvent,\n invokeId,\n result,\n state: state_.value,\n type: 'invoke-done',\n });\n\n queue.push({ event: invokeDef.onDone(result, capturedContext), tag: 'event' });\n\n if (!draining) drainQueue();\n })\n .catch((error: unknown) => {\n activeInvokes.delete(invokeInfo);\n\n if (disposed || controller.signal.aborted || !invokeDef.onError) return;\n\n onDebug?.({\n context: capturedContext,\n error,\n event: triggerEvent,\n invokeId,\n state: state_.value,\n type: 'invoke-error',\n });\n\n queue.push({ event: invokeDef.onError(error, capturedContext), tag: 'event' });\n\n if (!draining) drainQueue();\n });\n }\n }\n };\n\n // ── Section: After (delayed) transitions ───────────────────────────────────\n\n const scheduleAfterTransitions = (paths: readonly string[]): void => {\n for (const path of paths) {\n const node = getNodeAtPath(states, path) as StateNode<State, Ctx, Ev> | undefined;\n\n if (!node?.after?.length) continue;\n\n for (const afterDef of node.after) {\n const timer = setTimeout(() => {\n activeTimers.delete(entry);\n\n // A sibling-to-sibling transition elsewhere in the tree may have moved the leaf\n // while this timer's owning path stayed active — fire from wherever we are now,\n // and only if that path is still part of the live ancestor chain.\n if (disposed || !getAncestorPaths(state_.value).includes(path)) return;\n\n const from = state_.value;\n // R10: after.guard unified — receives { context, event } like all other guards\n const afterEvent = { delay: afterDef.delay, type: '$after' } as const;\n\n if (afterDef.guard && !afterDef.guard({ context: context_.value, event: afterEvent })) return;\n\n const resolvedTarget = resolveLeaf(states, afterDef.target) as State;\n\n queue.push({\n actions: (afterDef.actions ?? []) as Array<\n (args: { context: Ctx; readonly event: Ev | LifecycleEvent }) => void\n >,\n afterEvent,\n from,\n tag: 'after',\n target: resolvedTarget,\n });\n drainQueue();\n }, afterDef.delay);\n const entry = { path, timer };\n\n activeTimers.add(entry);\n }\n }\n };\n\n // ── Section: Event queue processing ─────────────────────────────────────────\n\n const processEvent = (item: QueueItem): boolean => {\n if (disposed) return false;\n\n if (item.tag === 'after') {\n executeTransition(item.from, item.target, item.actions, item.afterEvent);\n\n return true;\n }\n\n const from = state_.value;\n\n const transition = resolveTransition(\n definition,\n { context: context_.value, event: item.event, state: from },\n onDebug ? (info) => onDebug({ ...info, type: 'guard' }) : undefined,\n );\n\n if (!transition) {\n onDebug?.({ event: item.event, from, type: 'transition-skipped' });\n\n return false;\n }\n\n const resolvedTarget = resolveLeaf(states, transition.target) as State;\n const actions = (transition.actions ?? []) as Array<\n (args: { context: Ctx; readonly event: Ev | LifecycleEvent }) => void\n >;\n\n executeTransition(from, resolvedTarget, actions, item.event);\n\n return true;\n };\n\n const drainQueueInner = (): void => {\n let processed = 0;\n\n while (queue.length > 0) {\n if (++processed > maxTransitionsPerFlush) {\n throw new ClockworkTransitionLoopGuardError(\n 'transition queue exceeded maxTransitionsPerFlush',\n maxTransitionsPerFlush,\n );\n }\n\n processEvent(queue.shift()!);\n }\n };\n\n const drainQueue = (): void => {\n if (draining) return;\n\n draining = true;\n\n try {\n drainQueueInner();\n } catch (err) {\n queue.length = 0;\n throw err;\n } finally {\n draining = false;\n }\n };\n\n // ── Section: Public API ────────────────────────────────────────────────────\n\n const can = (event: Ev): boolean => {\n if (disposed) return false;\n\n return !!resolveTransition(definition, { context: context_.value, event, state: state_.value });\n };\n\n const send = (event: Ev): SendResult => {\n if (disposed) {\n warn('send() called on a disposed machine — event ignored');\n\n return RESULT_REJECTED;\n }\n\n // Run interceptors left-to-right — first null wins\n let intercepted: Ev | null = event;\n\n for (const fn of interceptors) {\n intercepted = fn(intercepted, { context: context_.value, state: state_.value });\n\n if (intercepted === null) return RESULT_REJECTED;\n }\n\n const interceptedEvent = intercepted;\n\n if (draining) {\n queue.push({ event: interceptedEvent, tag: 'event' });\n\n return RESULT_QUEUED;\n }\n\n draining = true;\n\n try {\n const transitioned = processEvent({ event: interceptedEvent, tag: 'event' });\n\n drainQueueInner();\n\n return transitioned ? RESULT_TRANSITIONED : RESULT_REJECTED;\n } catch (err) {\n queue.length = 0;\n throw err;\n } finally {\n draining = false;\n }\n };\n\n const getSnapshot = (): MachineSnapshot<State, Ctx> =>\n Object.freeze({ context: clone(context_.value), state: state_.value });\n\n const getTrace = (): readonly TransitionTraceEntry<State, Ev>[] => trace?.get() ?? [];\n\n const matches = (...stateArgs: string[]): boolean => {\n if (disposed) return false;\n\n const current = state_.value;\n\n return stateArgs.some((s) => current === s || current.startsWith(`${s}.`));\n };\n\n // R5: subscribe via plain Set — no ripple effect(), no prevState/prevCtx tracking\n const subscribe = (fn: (snapshot: MachineSnapshot<State, Ctx>) => void): (() => void) => {\n subscribers.add(fn);\n\n return () => subscribers.delete(fn);\n };\n\n // ── Section: Initialization ────────────────────────────────────────────────\n\n const initialPaths = getAncestorPaths(resolvedInitial);\n\n if (persistedSnapshot) {\n runInvokes(HYDRATE_EVENT, initialPaths);\n scheduleAfterTransitions(initialPaths);\n } else {\n const hasEntry = initialPaths.some((p) => getNodeAtPath(states, p)?.entry);\n\n if (hasEntry) {\n const initDraft = clone(context_.value);\n\n for (const p of initialPaths) {\n getNodeAtPath(states, p)?.entry?.({ context: initDraft, event: INIT_EVENT });\n }\n\n assertContext(initDraft, 'init');\n context_.value = initDraft;\n }\n\n runInvokes(INIT_EVENT, initialPaths);\n scheduleAfterTransitions(initialPaths);\n\n if (options.persistence) saveSnapshot();\n }\n\n const dispose = (): void => {\n if (disposed) return;\n\n disposed = true;\n disposeController.abort();\n stopInvokes();\n clearTimers();\n state_.dispose();\n context_.dispose();\n };\n\n return {\n can,\n context: readonly(context_),\n get disposalSignal() {\n return disposeController.signal;\n },\n dispose,\n get disposed() {\n return disposed;\n },\n getSnapshot,\n getTrace,\n matches,\n send,\n state: readonly(state_),\n subscribe,\n [Symbol.dispose]: dispose,\n };\n};\n\n// ── Public entry point ────────────────────────────────────────────────────────\n\n/**\n * Validates a machine configuration and returns a reusable definition handle.\n *\n * Call `.start(options?)` to create a running instance.\n * Call `.resolve(input, options?)` to inspect transitions without starting a machine.\n *\n * @example\n * const counterDef = createMachine({\n * context: { count: 0 },\n * initial: 'idle',\n * states: { idle: { on: { INC: { actions: [({ context }) => { context.count += 1 }], target: 'idle' } } } },\n * });\n *\n * const m1 = counterDef.start();\n * const m2 = counterDef.start({ snapshot: { context: { count: 10 }, state: 'idle' } });\n *\n * // Test transitions without a running machine:\n * counterDef.resolve({ context: { count: 0 }, event: { type: 'INC' }, state: 'idle' });\n *\n * // Or start immediately (one-shot):\n * const m3 = createMachine(config).start();\n */\nexport const createMachine = <State extends string, Ctx extends object, Ev extends MachineEvent>(\n config: MachineConfig<State, Ctx, Ev>,\n): MachineDefinition<State, Ctx, Ev> => {\n validateDefinition(config);\n\n return {\n resolve(input, options?) {\n return resolveTransition(config, input, options?.onGuard);\n },\n start(options?) {\n return _interpret(config, options);\n },\n };\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const e=require("./errors.cjs");var t=(e,t)=>e&&Object.hasOwn(e,t)?e[t]:void 0,n=(e,n)=>{let r=n.split(`.`),i=t(e,r[0]);if(!i)return n;for(let e=1;e<r.length;e++)if(i=t(i.states,r[e]),!i)return n;let a=n;for(;i?.states&&i.initial;)a=`${a}.${i.initial}`,i=t(i.states,i.initial);return a},r=(e,n)=>{let r=n.split(`.`),i=t(e,r[0]);for(let e=1;e<r.length;e++){if(!i?.states)return;i=t(i.states,r[e])}return i},i=e=>{let t=e.split(`.`),n=[];for(let e=1;e<=t.length;e++)n.push(t.slice(0,e).join(`.`));return n},a=(t,n,i)=>{if(t.states&&!t.initial)throw new e.ClockworkMissingCompoundInitialError(`compound state "${n}" must have an "initial" property`,n);if(t.initial&&t.states&&!Object.hasOwn(t.states,t.initial))throw new e.ClockworkInvalidInitialStateError(`compound state "${n}" initial "${t.initial}" not found in substates`,n,t.initial);for(let[a,o]of Object.entries(t.on??{})){let t=Array.isArray(o)?o:[o];if(t.length===0)throw new e.ClockworkInvalidTransitionArrayError(`state "${n}" event "${a}" must be a non-empty transition or transition array`,n,a);for(let o of t){let t=o.target.split(`.`)[0];if(!Object.hasOwn(i,t))throw new e.ClockworkUnknownTargetError(`state "${n}" event "${a}" targets unknown state "${o.target}"`,n,o.target,a);if(o.target.includes(`.`)&&!r(i,o.target))throw new e.ClockworkUnknownTargetError(`state "${n}" event "${a}" targets unknown nested state "${o.target}"`,n,o.target,a)}}if(t.invoke!==void 0&&t.invoke.length===0)throw new e.ClockworkInvalidTransitionArrayError(`state "${n}" invoke must be a non-empty array`,n);for(let a of t.after??[]){if(!Number.isFinite(a.delay)||a.delay<0)throw new e.ClockworkInvalidAfterDelayError(`state "${n}" after delay must be a finite number >= 0, got ${a.delay}`,n,a.delay);let t=a.target.split(`.`)[0];if(!Object.hasOwn(i,t))throw new e.ClockworkUnknownTargetError(`state "${n}" after[${a.delay}ms] targets unknown state "${a.target}"`,n,a.target);if(a.target.includes(`.`)&&!r(i,a.target))throw new e.ClockworkUnknownTargetError(`state "${n}" after[${a.delay}ms] targets unknown nested state "${a.target}"`,n,a.target)}if(t.states)for(let[e,r]of Object.entries(t.states))a(r,`${n}.${e}`,i)},o=t=>{let{states:n}=t;if(!Object.hasOwn(n,t.initial))throw new e.ClockworkInvalidInitialStateError(`initial state "${t.initial}" not found in states`,``,t.initial);for(let[e,t]of Object.entries(n))a(t,e,n)};exports.getAncestorPaths=i,exports.getNodeAtPath=r,exports.resolveLeaf=n,exports.validateDefinition=o;
|
|
2
|
+
//# sourceMappingURL=definition.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"definition.cjs","names":[],"sources":["../src/definition.ts"],"sourcesContent":["import type { MachineConfig, MachineEvent, StateNode, TransitionDef } from './types.js';\n\nimport {\n ClockworkInvalidAfterDelayError,\n ClockworkInvalidInitialStateError,\n ClockworkInvalidTransitionArrayError,\n ClockworkMissingCompoundInitialError,\n ClockworkUnknownTargetError,\n} from './errors.js';\n\n// ── Key safety ────────────────────────────────────────────────────────────────\n\n/**\n * Own-property-only lookup — state paths and event types ultimately come from strings\n * (persisted snapshots, event payloads) that may not be developer-authored. A plain\n * `obj[key]` or `key in obj` resolves inherited `Object.prototype` members (`__proto__`,\n * `constructor`, `toString`, …), which can turn an \"unknown state/event\" into a crash or\n * a silently-accepted bogus value instead of the intended \"not found\". Treat any such key\n * as absent instead.\n */\nconst getOwn = <T>(obj: Record<string, T> | undefined, key: string): T | undefined =>\n obj && Object.hasOwn(obj, key) ? obj[key] : undefined;\n\n// ── Hierarchy helpers (internal — not re-exported from index) ─────────────────\n\n/**\n * Resolves a target state to its deepest initial leaf.\n * For compound states (those with `states` + `initial`), recursively descends.\n */\nexport const resolveLeaf = <Ctx extends object, Ev extends MachineEvent>(\n topLevelStates: Record<string, StateNode<string, Ctx, Ev>>,\n target: string,\n): string => {\n const segments = target.split('.');\n let node = getOwn(topLevelStates, segments[0]);\n\n if (!node) return target;\n\n for (let i = 1; i < segments.length; i++) {\n node = getOwn(node.states, segments[i]);\n\n if (!node) return target;\n }\n\n let path = target;\n\n while (node?.states && node.initial) {\n path = `${path}.${node.initial}`;\n node = getOwn(node.states, node.initial);\n }\n\n return path;\n};\n\n/**\n * Returns the node at a given dot-path.\n */\nexport const getNodeAtPath = <Ctx extends object, Ev extends MachineEvent>(\n topLevelStates: Record<string, StateNode<string, Ctx, Ev>>,\n path: string,\n): StateNode<string, Ctx, Ev> | undefined => {\n const segments = path.split('.');\n let node = getOwn(topLevelStates, segments[0]);\n\n for (let i = 1; i < segments.length; i++) {\n if (!node?.states) return undefined;\n\n node = getOwn(node.states, segments[i]);\n }\n\n return node;\n};\n\n/**\n * Returns ancestor paths from root to leaf (inclusive), e.g. ['a', 'a.b', 'a.b.c']\n */\nexport const getAncestorPaths = (path: string): string[] => {\n const segments = path.split('.');\n const paths: string[] = [];\n\n for (let i = 1; i <= segments.length; i++) {\n paths.push(segments.slice(0, i).join('.'));\n }\n\n return paths;\n};\n\n// ── Validation ───────────────────────────────────────────────────────────────\n\nconst validateNode = <State extends string, Ctx extends object, Ev extends MachineEvent>(\n node: StateNode<string, Ctx, Ev>,\n path: string,\n allTopLevel: Record<string, StateNode<State, Ctx, Ev>>,\n): void => {\n if (node.states && !node.initial) {\n throw new ClockworkMissingCompoundInitialError(`compound state \"${path}\" must have an \"initial\" property`, path);\n }\n\n if (node.initial && node.states && !Object.hasOwn(node.states, node.initial)) {\n throw new ClockworkInvalidInitialStateError(\n `compound state \"${path}\" initial \"${node.initial}\" not found in substates`,\n path,\n node.initial,\n );\n }\n\n for (const [eventType, input] of Object.entries(node.on ?? {})) {\n const defs = Array.isArray(input) ? input : [input];\n\n if (defs.length === 0) {\n throw new ClockworkInvalidTransitionArrayError(\n `state \"${path}\" event \"${eventType}\" must be a non-empty transition or transition array`,\n path,\n eventType,\n );\n }\n\n for (const tr of defs as Array<TransitionDef<State, Ctx, Ev>>) {\n const targetRoot = tr.target.split('.')[0];\n\n if (!Object.hasOwn(allTopLevel, targetRoot)) {\n throw new ClockworkUnknownTargetError(\n `state \"${path}\" event \"${eventType}\" targets unknown state \"${tr.target}\"`,\n path,\n tr.target,\n eventType,\n );\n }\n\n if (tr.target.includes('.') && !getNodeAtPath(allTopLevel, tr.target)) {\n throw new ClockworkUnknownTargetError(\n `state \"${path}\" event \"${eventType}\" targets unknown nested state \"${tr.target}\"`,\n path,\n tr.target,\n eventType,\n );\n }\n }\n }\n\n // Validate empty invoke array (D1)\n if (node.invoke !== undefined && node.invoke.length === 0) {\n throw new ClockworkInvalidTransitionArrayError(`state \"${path}\" invoke must be a non-empty array`, path);\n }\n\n // Validate after targets and delays\n for (const afterDef of node.after ?? []) {\n if (!Number.isFinite(afterDef.delay) || afterDef.delay < 0) {\n throw new ClockworkInvalidAfterDelayError(\n `state \"${path}\" after delay must be a finite number >= 0, got ${afterDef.delay}`,\n path,\n afterDef.delay,\n );\n }\n\n const targetRoot = afterDef.target.split('.')[0];\n\n if (!Object.hasOwn(allTopLevel, targetRoot)) {\n throw new ClockworkUnknownTargetError(\n `state \"${path}\" after[${afterDef.delay}ms] targets unknown state \"${afterDef.target}\"`,\n path,\n afterDef.target,\n );\n }\n\n if (afterDef.target.includes('.') && !getNodeAtPath(allTopLevel, afterDef.target)) {\n throw new ClockworkUnknownTargetError(\n `state \"${path}\" after[${afterDef.delay}ms] targets unknown nested state \"${afterDef.target}\"`,\n path,\n afterDef.target,\n );\n }\n }\n\n if (node.states) {\n for (const [name, child] of Object.entries(node.states)) {\n validateNode(child, `${path}.${name}`, allTopLevel);\n }\n }\n};\n\nexport const validateDefinition = <State extends string, Ctx extends object, Ev extends MachineEvent>(\n definition: MachineConfig<State, Ctx, Ev>,\n): void => {\n const { states } = definition;\n\n if (!Object.hasOwn(states, definition.initial)) {\n throw new ClockworkInvalidInitialStateError(\n `initial state \"${definition.initial}\" not found in states`,\n '',\n definition.initial,\n );\n }\n\n for (const [stateName, node] of Object.entries(states) as Array<[string, StateNode<State, Ctx, Ev>]>) {\n validateNode(node, stateName, states);\n }\n};\n"],"mappings":"gCAoBA,IAAM,GAAa,EAAoC,IACrD,GAAO,OAAO,OAAO,EAAK,CAAG,EAAI,EAAI,GAAO,IAAA,GAQjC,GACX,EACA,IACW,CACX,IAAM,EAAW,EAAO,MAAM,GAAG,EAC7B,EAAO,EAAO,EAAgB,EAAS,EAAE,EAE7C,GAAI,CAAC,EAAM,OAAO,EAElB,IAAK,IAAI,EAAI,EAAG,EAAI,EAAS,OAAQ,IAGnC,GAFA,EAAO,EAAO,EAAK,OAAQ,EAAS,EAAE,EAElC,CAAC,EAAM,OAAO,EAGpB,IAAI,EAAO,EAEX,KAAO,GAAM,QAAU,EAAK,SAC1B,EAAO,GAAG,EAAK,GAAG,EAAK,UACvB,EAAO,EAAO,EAAK,OAAQ,EAAK,OAAO,EAGzC,OAAO,CACT,EAKa,GACX,EACA,IAC2C,CAC3C,IAAM,EAAW,EAAK,MAAM,GAAG,EAC3B,EAAO,EAAO,EAAgB,EAAS,EAAE,EAE7C,IAAK,IAAI,EAAI,EAAG,EAAI,EAAS,OAAQ,IAAK,CACxC,GAAI,CAAC,GAAM,OAAQ,OAEnB,EAAO,EAAO,EAAK,OAAQ,EAAS,EAAE,CACxC,CAEA,OAAO,CACT,EAKa,EAAoB,GAA2B,CAC1D,IAAM,EAAW,EAAK,MAAM,GAAG,EACzB,EAAkB,CAAC,EAEzB,IAAK,IAAI,EAAI,EAAG,GAAK,EAAS,OAAQ,IACpC,EAAM,KAAK,EAAS,MAAM,EAAG,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,EAG3C,OAAO,CACT,EAIM,GACJ,EACA,EACA,IACS,CACT,GAAI,EAAK,QAAU,CAAC,EAAK,QACvB,MAAM,IAAI,EAAA,qCAAqC,mBAAmB,EAAK,mCAAoC,CAAI,EAGjH,GAAI,EAAK,SAAW,EAAK,QAAU,CAAC,OAAO,OAAO,EAAK,OAAQ,EAAK,OAAO,EACzE,MAAM,IAAI,EAAA,kCACR,mBAAmB,EAAK,aAAa,EAAK,QAAQ,0BAClD,EACA,EAAK,OACP,EAGF,IAAK,GAAM,CAAC,EAAW,KAAU,OAAO,QAAQ,EAAK,IAAM,CAAC,CAAC,EAAG,CAC9D,IAAM,EAAO,MAAM,QAAQ,CAAK,EAAI,EAAQ,CAAC,CAAK,EAElD,GAAI,EAAK,SAAW,EAClB,MAAM,IAAI,EAAA,qCACR,UAAU,EAAK,WAAW,EAAU,sDACpC,EACA,CACF,EAGF,IAAK,IAAM,KAAM,EAA8C,CAC7D,IAAM,EAAa,EAAG,OAAO,MAAM,GAAG,CAAC,CAAC,GAExC,GAAI,CAAC,OAAO,OAAO,EAAa,CAAU,EACxC,MAAM,IAAI,EAAA,4BACR,UAAU,EAAK,WAAW,EAAU,2BAA2B,EAAG,OAAO,GACzE,EACA,EAAG,OACH,CACF,EAGF,GAAI,EAAG,OAAO,SAAS,GAAG,GAAK,CAAC,EAAc,EAAa,EAAG,MAAM,EAClE,MAAM,IAAI,EAAA,4BACR,UAAU,EAAK,WAAW,EAAU,kCAAkC,EAAG,OAAO,GAChF,EACA,EAAG,OACH,CACF,CAEJ,CACF,CAGA,GAAI,EAAK,SAAW,IAAA,IAAa,EAAK,OAAO,SAAW,EACtD,MAAM,IAAI,EAAA,qCAAqC,UAAU,EAAK,oCAAqC,CAAI,EAIzG,IAAK,IAAM,KAAY,EAAK,OAAS,CAAC,EAAG,CACvC,GAAI,CAAC,OAAO,SAAS,EAAS,KAAK,GAAK,EAAS,MAAQ,EACvD,MAAM,IAAI,EAAA,gCACR,UAAU,EAAK,kDAAkD,EAAS,QAC1E,EACA,EAAS,KACX,EAGF,IAAM,EAAa,EAAS,OAAO,MAAM,GAAG,CAAC,CAAC,GAE9C,GAAI,CAAC,OAAO,OAAO,EAAa,CAAU,EACxC,MAAM,IAAI,EAAA,4BACR,UAAU,EAAK,UAAU,EAAS,MAAM,6BAA6B,EAAS,OAAO,GACrF,EACA,EAAS,MACX,EAGF,GAAI,EAAS,OAAO,SAAS,GAAG,GAAK,CAAC,EAAc,EAAa,EAAS,MAAM,EAC9E,MAAM,IAAI,EAAA,4BACR,UAAU,EAAK,UAAU,EAAS,MAAM,oCAAoC,EAAS,OAAO,GAC5F,EACA,EAAS,MACX,CAEJ,CAEA,GAAI,EAAK,OACP,IAAK,GAAM,CAAC,EAAM,KAAU,OAAO,QAAQ,EAAK,MAAM,EACpD,EAAa,EAAO,GAAG,EAAK,GAAG,IAAQ,CAAW,CAGxD,EAEa,EACX,GACS,CACT,GAAM,CAAE,UAAW,EAEnB,GAAI,CAAC,OAAO,OAAO,EAAQ,EAAW,OAAO,EAC3C,MAAM,IAAI,EAAA,kCACR,kBAAkB,EAAW,QAAQ,uBACrC,GACA,EAAW,OACb,EAGF,IAAK,GAAM,CAAC,EAAW,KAAS,OAAO,QAAQ,CAAM,EACnD,EAAa,EAAM,EAAW,CAAM,CAExC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { MachineConfig, MachineEvent, StateNode } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Resolves a target state to its deepest initial leaf.
|
|
4
|
+
* For compound states (those with `states` + `initial`), recursively descends.
|
|
5
|
+
*/
|
|
6
|
+
export declare const resolveLeaf: <Ctx extends object, Ev extends MachineEvent>(topLevelStates: Record<string, StateNode<string, Ctx, Ev>>, target: string) => string;
|
|
7
|
+
/**
|
|
8
|
+
* Returns the node at a given dot-path.
|
|
9
|
+
*/
|
|
10
|
+
export declare const getNodeAtPath: <Ctx extends object, Ev extends MachineEvent>(topLevelStates: Record<string, StateNode<string, Ctx, Ev>>, path: string) => StateNode<string, Ctx, Ev> | undefined;
|
|
11
|
+
/**
|
|
12
|
+
* Returns ancestor paths from root to leaf (inclusive), e.g. ['a', 'a.b', 'a.b.c']
|
|
13
|
+
*/
|
|
14
|
+
export declare const getAncestorPaths: (path: string) => string[];
|
|
15
|
+
export declare const validateDefinition: <State extends string, Ctx extends object, Ev extends MachineEvent>(definition: MachineConfig<State, Ctx, Ev>) => void;
|
|
16
|
+
//# sourceMappingURL=definition.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"definition.d.ts","sourceRoot":"","sources":["../src/definition.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,SAAS,EAAiB,MAAM,YAAY,CAAC;AAyBxF;;;GAGG;AACH,eAAO,MAAM,WAAW,GAAI,GAAG,SAAS,MAAM,EAAE,EAAE,SAAS,YAAY,EACrE,gBAAgB,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,EAC1D,QAAQ,MAAM,KACb,MAoBF,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,aAAa,GAAI,GAAG,SAAS,MAAM,EAAE,EAAE,SAAS,YAAY,EACvE,gBAAgB,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,EAC1D,MAAM,MAAM,KACX,SAAS,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC,GAAG,SAW/B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,gBAAgB,GAAI,MAAM,MAAM,KAAG,MAAM,EASrD,CAAC;AAgGF,eAAO,MAAM,kBAAkB,GAAI,KAAK,SAAS,MAAM,EAAE,GAAG,SAAS,MAAM,EAAE,EAAE,SAAS,YAAY,EAClG,YAAY,aAAa,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC,KACxC,IAcF,CAAC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { ClockworkInvalidAfterDelayError as e, ClockworkInvalidInitialStateError as t, ClockworkInvalidTransitionArrayError as n, ClockworkMissingCompoundInitialError as r, ClockworkUnknownTargetError as i } from "./errors.js";
|
|
2
|
+
//#region src/definition.ts
|
|
3
|
+
var a = (e, t) => e && Object.hasOwn(e, t) ? e[t] : void 0, o = (e, t) => {
|
|
4
|
+
let n = t.split("."), r = a(e, n[0]);
|
|
5
|
+
if (!r) return t;
|
|
6
|
+
for (let e = 1; e < n.length; e++) if (r = a(r.states, n[e]), !r) return t;
|
|
7
|
+
let i = t;
|
|
8
|
+
for (; r?.states && r.initial;) i = `${i}.${r.initial}`, r = a(r.states, r.initial);
|
|
9
|
+
return i;
|
|
10
|
+
}, s = (e, t) => {
|
|
11
|
+
let n = t.split("."), r = a(e, n[0]);
|
|
12
|
+
for (let e = 1; e < n.length; e++) {
|
|
13
|
+
if (!r?.states) return;
|
|
14
|
+
r = a(r.states, n[e]);
|
|
15
|
+
}
|
|
16
|
+
return r;
|
|
17
|
+
}, c = (e) => {
|
|
18
|
+
let t = e.split("."), n = [];
|
|
19
|
+
for (let e = 1; e <= t.length; e++) n.push(t.slice(0, e).join("."));
|
|
20
|
+
return n;
|
|
21
|
+
}, l = (a, o, c) => {
|
|
22
|
+
if (a.states && !a.initial) throw new r(`compound state "${o}" must have an "initial" property`, o);
|
|
23
|
+
if (a.initial && a.states && !Object.hasOwn(a.states, a.initial)) throw new t(`compound state "${o}" initial "${a.initial}" not found in substates`, o, a.initial);
|
|
24
|
+
for (let [e, t] of Object.entries(a.on ?? {})) {
|
|
25
|
+
let r = Array.isArray(t) ? t : [t];
|
|
26
|
+
if (r.length === 0) throw new n(`state "${o}" event "${e}" must be a non-empty transition or transition array`, o, e);
|
|
27
|
+
for (let t of r) {
|
|
28
|
+
let n = t.target.split(".")[0];
|
|
29
|
+
if (!Object.hasOwn(c, n)) throw new i(`state "${o}" event "${e}" targets unknown state "${t.target}"`, o, t.target, e);
|
|
30
|
+
if (t.target.includes(".") && !s(c, t.target)) throw new i(`state "${o}" event "${e}" targets unknown nested state "${t.target}"`, o, t.target, e);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
if (a.invoke !== void 0 && a.invoke.length === 0) throw new n(`state "${o}" invoke must be a non-empty array`, o);
|
|
34
|
+
for (let t of a.after ?? []) {
|
|
35
|
+
if (!Number.isFinite(t.delay) || t.delay < 0) throw new e(`state "${o}" after delay must be a finite number >= 0, got ${t.delay}`, o, t.delay);
|
|
36
|
+
let n = t.target.split(".")[0];
|
|
37
|
+
if (!Object.hasOwn(c, n)) throw new i(`state "${o}" after[${t.delay}ms] targets unknown state "${t.target}"`, o, t.target);
|
|
38
|
+
if (t.target.includes(".") && !s(c, t.target)) throw new i(`state "${o}" after[${t.delay}ms] targets unknown nested state "${t.target}"`, o, t.target);
|
|
39
|
+
}
|
|
40
|
+
if (a.states) for (let [e, t] of Object.entries(a.states)) l(t, `${o}.${e}`, c);
|
|
41
|
+
}, u = (e) => {
|
|
42
|
+
let { states: n } = e;
|
|
43
|
+
if (!Object.hasOwn(n, e.initial)) throw new t(`initial state "${e.initial}" not found in states`, "", e.initial);
|
|
44
|
+
for (let [e, t] of Object.entries(n)) l(t, e, n);
|
|
45
|
+
};
|
|
46
|
+
//#endregion
|
|
47
|
+
export { c as getAncestorPaths, s as getNodeAtPath, o as resolveLeaf, u as validateDefinition };
|
|
48
|
+
|
|
49
|
+
//# sourceMappingURL=definition.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"definition.js","names":[],"sources":["../src/definition.ts"],"sourcesContent":["import type { MachineConfig, MachineEvent, StateNode, TransitionDef } from './types.js';\n\nimport {\n ClockworkInvalidAfterDelayError,\n ClockworkInvalidInitialStateError,\n ClockworkInvalidTransitionArrayError,\n ClockworkMissingCompoundInitialError,\n ClockworkUnknownTargetError,\n} from './errors.js';\n\n// ── Key safety ────────────────────────────────────────────────────────────────\n\n/**\n * Own-property-only lookup — state paths and event types ultimately come from strings\n * (persisted snapshots, event payloads) that may not be developer-authored. A plain\n * `obj[key]` or `key in obj` resolves inherited `Object.prototype` members (`__proto__`,\n * `constructor`, `toString`, …), which can turn an \"unknown state/event\" into a crash or\n * a silently-accepted bogus value instead of the intended \"not found\". Treat any such key\n * as absent instead.\n */\nconst getOwn = <T>(obj: Record<string, T> | undefined, key: string): T | undefined =>\n obj && Object.hasOwn(obj, key) ? obj[key] : undefined;\n\n// ── Hierarchy helpers (internal — not re-exported from index) ─────────────────\n\n/**\n * Resolves a target state to its deepest initial leaf.\n * For compound states (those with `states` + `initial`), recursively descends.\n */\nexport const resolveLeaf = <Ctx extends object, Ev extends MachineEvent>(\n topLevelStates: Record<string, StateNode<string, Ctx, Ev>>,\n target: string,\n): string => {\n const segments = target.split('.');\n let node = getOwn(topLevelStates, segments[0]);\n\n if (!node) return target;\n\n for (let i = 1; i < segments.length; i++) {\n node = getOwn(node.states, segments[i]);\n\n if (!node) return target;\n }\n\n let path = target;\n\n while (node?.states && node.initial) {\n path = `${path}.${node.initial}`;\n node = getOwn(node.states, node.initial);\n }\n\n return path;\n};\n\n/**\n * Returns the node at a given dot-path.\n */\nexport const getNodeAtPath = <Ctx extends object, Ev extends MachineEvent>(\n topLevelStates: Record<string, StateNode<string, Ctx, Ev>>,\n path: string,\n): StateNode<string, Ctx, Ev> | undefined => {\n const segments = path.split('.');\n let node = getOwn(topLevelStates, segments[0]);\n\n for (let i = 1; i < segments.length; i++) {\n if (!node?.states) return undefined;\n\n node = getOwn(node.states, segments[i]);\n }\n\n return node;\n};\n\n/**\n * Returns ancestor paths from root to leaf (inclusive), e.g. ['a', 'a.b', 'a.b.c']\n */\nexport const getAncestorPaths = (path: string): string[] => {\n const segments = path.split('.');\n const paths: string[] = [];\n\n for (let i = 1; i <= segments.length; i++) {\n paths.push(segments.slice(0, i).join('.'));\n }\n\n return paths;\n};\n\n// ── Validation ───────────────────────────────────────────────────────────────\n\nconst validateNode = <State extends string, Ctx extends object, Ev extends MachineEvent>(\n node: StateNode<string, Ctx, Ev>,\n path: string,\n allTopLevel: Record<string, StateNode<State, Ctx, Ev>>,\n): void => {\n if (node.states && !node.initial) {\n throw new ClockworkMissingCompoundInitialError(`compound state \"${path}\" must have an \"initial\" property`, path);\n }\n\n if (node.initial && node.states && !Object.hasOwn(node.states, node.initial)) {\n throw new ClockworkInvalidInitialStateError(\n `compound state \"${path}\" initial \"${node.initial}\" not found in substates`,\n path,\n node.initial,\n );\n }\n\n for (const [eventType, input] of Object.entries(node.on ?? {})) {\n const defs = Array.isArray(input) ? input : [input];\n\n if (defs.length === 0) {\n throw new ClockworkInvalidTransitionArrayError(\n `state \"${path}\" event \"${eventType}\" must be a non-empty transition or transition array`,\n path,\n eventType,\n );\n }\n\n for (const tr of defs as Array<TransitionDef<State, Ctx, Ev>>) {\n const targetRoot = tr.target.split('.')[0];\n\n if (!Object.hasOwn(allTopLevel, targetRoot)) {\n throw new ClockworkUnknownTargetError(\n `state \"${path}\" event \"${eventType}\" targets unknown state \"${tr.target}\"`,\n path,\n tr.target,\n eventType,\n );\n }\n\n if (tr.target.includes('.') && !getNodeAtPath(allTopLevel, tr.target)) {\n throw new ClockworkUnknownTargetError(\n `state \"${path}\" event \"${eventType}\" targets unknown nested state \"${tr.target}\"`,\n path,\n tr.target,\n eventType,\n );\n }\n }\n }\n\n // Validate empty invoke array (D1)\n if (node.invoke !== undefined && node.invoke.length === 0) {\n throw new ClockworkInvalidTransitionArrayError(`state \"${path}\" invoke must be a non-empty array`, path);\n }\n\n // Validate after targets and delays\n for (const afterDef of node.after ?? []) {\n if (!Number.isFinite(afterDef.delay) || afterDef.delay < 0) {\n throw new ClockworkInvalidAfterDelayError(\n `state \"${path}\" after delay must be a finite number >= 0, got ${afterDef.delay}`,\n path,\n afterDef.delay,\n );\n }\n\n const targetRoot = afterDef.target.split('.')[0];\n\n if (!Object.hasOwn(allTopLevel, targetRoot)) {\n throw new ClockworkUnknownTargetError(\n `state \"${path}\" after[${afterDef.delay}ms] targets unknown state \"${afterDef.target}\"`,\n path,\n afterDef.target,\n );\n }\n\n if (afterDef.target.includes('.') && !getNodeAtPath(allTopLevel, afterDef.target)) {\n throw new ClockworkUnknownTargetError(\n `state \"${path}\" after[${afterDef.delay}ms] targets unknown nested state \"${afterDef.target}\"`,\n path,\n afterDef.target,\n );\n }\n }\n\n if (node.states) {\n for (const [name, child] of Object.entries(node.states)) {\n validateNode(child, `${path}.${name}`, allTopLevel);\n }\n }\n};\n\nexport const validateDefinition = <State extends string, Ctx extends object, Ev extends MachineEvent>(\n definition: MachineConfig<State, Ctx, Ev>,\n): void => {\n const { states } = definition;\n\n if (!Object.hasOwn(states, definition.initial)) {\n throw new ClockworkInvalidInitialStateError(\n `initial state \"${definition.initial}\" not found in states`,\n '',\n definition.initial,\n );\n }\n\n for (const [stateName, node] of Object.entries(states) as Array<[string, StateNode<State, Ctx, Ev>]>) {\n validateNode(node, stateName, states);\n }\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./interpret.cjs");function t(t,n={}){return e.createMachine(t).start({...n,onDebug(e){switch(e.type){case`guard`:console.debug(`[clockwork:guard] ${e.event.type}: ${e.from} → ${e.target} — ${e.passed?`passed`:`blocked`}`);break;case`invoke-abort`:console.debug(`[clockwork:invoke] #${e.invokeId} aborted in "${e.state}"`);break;case`invoke-done`:console.debug(`[clockwork:invoke] #${e.invokeId} done in "${e.state}"`);break;case`invoke-error`:console.debug(`[clockwork:invoke] #${e.invokeId} error in "${e.state}"`,e.error);break;case`invoke-start`:console.debug(`[clockwork:invoke] #${e.invokeId} started in "${e.state}"`);break;case`transition`:console.debug(`[clockwork:transition] ${e.event.type}: ${e.from} → ${e.to}`);break;case`transition-skipped`:console.debug(`[clockwork:skip] ${e.event.type}: no matching transition in "${e.from}"`);break}}})}exports.debugMachine=t;
|
|
2
|
+
//# sourceMappingURL=devtools.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"devtools.cjs","names":[],"sources":["../src/devtools.ts"],"sourcesContent":["/**\n * @vielzeug/clockwork — debug utilities for state machine visualisation.\n *\n * Import from the dedicated sub-path so it is tree-shaken from production bundles:\n * ```ts\n * import { debugMachine } from '@vielzeug/clockwork/devtools';\n * ```\n */\n\nimport type { InterpretOptions, MachineConfig, MachineEvent, MachineInstance } from './types.js';\n\nimport { createMachine } from './interpret.js';\n\n/**\n * Wraps {@link createMachine} and attaches a `console.group`-based debug logger\n * that traces every guard evaluation, transition, invoke lifecycle event, and\n * skipped transition to the browser/Node console.\n *\n * **Development only.** Do not use in production — event payloads (including\n * any PII in context or event fields) are written to the console. Import from\n * the dedicated sub-path so the logging code is tree-shaken from production bundles.\n *\n * @example\n * ```ts\n * import { debugMachine } from '@vielzeug/clockwork/devtools';\n *\n * const m = debugMachine(trafficLight);\n * m.send({ type: 'NEXT' });\n * // [clockwork:transition] NEXT: idle → running\n * ```\n */\nexport function debugMachine<State extends string, Ctx extends object, Ev extends MachineEvent>(\n definition: MachineConfig<State, Ctx, Ev>,\n options: Omit<InterpretOptions<State, Ctx, Ev>, 'onDebug'> = {},\n): MachineInstance<State, Ctx, Ev> {\n return createMachine(definition).start({\n ...options,\n onDebug(event) {\n switch (event.type) {\n case 'guard':\n console.debug(\n `[clockwork:guard] ${event.event.type}: ${event.from} → ${event.target} — ${event.passed ? 'passed' : 'blocked'}`,\n );\n break;\n case 'invoke-abort':\n console.debug(`[clockwork:invoke] #${event.invokeId} aborted in \"${event.state}\"`);\n break;\n case 'invoke-done':\n console.debug(`[clockwork:invoke] #${event.invokeId} done in \"${event.state}\"`);\n break;\n case 'invoke-error':\n console.debug(`[clockwork:invoke] #${event.invokeId} error in \"${event.state}\"`, event.error);\n break;\n case 'invoke-start':\n console.debug(`[clockwork:invoke] #${event.invokeId} started in \"${event.state}\"`);\n break;\n case 'transition':\n console.debug(`[clockwork:transition] ${event.event.type}: ${event.from} → ${event.to}`);\n break;\n case 'transition-skipped':\n console.debug(`[clockwork:skip] ${event.event.type}: no matching transition in \"${event.from}\"`);\n break;\n }\n },\n } as InterpretOptions<State, Ctx, Ev>);\n}\n"],"mappings":"sGA+BA,SAAgB,EACd,EACA,EAA6D,CAAC,EAC7B,CACjC,OAAO,EAAA,cAAc,CAAU,CAAC,CAAC,MAAM,CACrC,GAAG,EACH,QAAQ,EAAO,CACb,OAAQ,EAAM,KAAd,CACE,IAAK,QACH,QAAQ,MACN,qBAAqB,EAAM,MAAM,KAAK,IAAI,EAAM,KAAK,KAAK,EAAM,OAAO,KAAK,EAAM,OAAS,SAAW,WACxG,EACA,MACF,IAAK,eACH,QAAQ,MAAM,uBAAuB,EAAM,SAAS,eAAe,EAAM,MAAM,EAAE,EACjF,MACF,IAAK,cACH,QAAQ,MAAM,uBAAuB,EAAM,SAAS,YAAY,EAAM,MAAM,EAAE,EAC9E,MACF,IAAK,eACH,QAAQ,MAAM,uBAAuB,EAAM,SAAS,aAAa,EAAM,MAAM,GAAI,EAAM,KAAK,EAC5F,MACF,IAAK,eACH,QAAQ,MAAM,uBAAuB,EAAM,SAAS,eAAe,EAAM,MAAM,EAAE,EACjF,MACF,IAAK,aACH,QAAQ,MAAM,0BAA0B,EAAM,MAAM,KAAK,IAAI,EAAM,KAAK,KAAK,EAAM,IAAI,EACvF,MACF,IAAK,qBACH,QAAQ,MAAM,oBAAoB,EAAM,MAAM,KAAK,+BAA+B,EAAM,KAAK,EAAE,EAC/F,KACJ,CACF,CACF,CAAqC,CACvC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @vielzeug/clockwork — debug utilities for state machine visualisation.
|
|
3
|
+
*
|
|
4
|
+
* Import from the dedicated sub-path so it is tree-shaken from production bundles:
|
|
5
|
+
* ```ts
|
|
6
|
+
* import { debugMachine } from '@vielzeug/clockwork/devtools';
|
|
7
|
+
* ```
|
|
8
|
+
*/
|
|
9
|
+
import type { InterpretOptions, MachineConfig, MachineEvent, MachineInstance } from './types.js';
|
|
10
|
+
/**
|
|
11
|
+
* Wraps {@link createMachine} and attaches a `console.group`-based debug logger
|
|
12
|
+
* that traces every guard evaluation, transition, invoke lifecycle event, and
|
|
13
|
+
* skipped transition to the browser/Node console.
|
|
14
|
+
*
|
|
15
|
+
* **Development only.** Do not use in production — event payloads (including
|
|
16
|
+
* any PII in context or event fields) are written to the console. Import from
|
|
17
|
+
* the dedicated sub-path so the logging code is tree-shaken from production bundles.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```ts
|
|
21
|
+
* import { debugMachine } from '@vielzeug/clockwork/devtools';
|
|
22
|
+
*
|
|
23
|
+
* const m = debugMachine(trafficLight);
|
|
24
|
+
* m.send({ type: 'NEXT' });
|
|
25
|
+
* // [clockwork:transition] NEXT: idle → running
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export declare function debugMachine<State extends string, Ctx extends object, Ev extends MachineEvent>(definition: MachineConfig<State, Ctx, Ev>, options?: Omit<InterpretOptions<State, Ctx, Ev>, 'onDebug'>): MachineInstance<State, Ctx, Ev>;
|
|
29
|
+
//# sourceMappingURL=devtools.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"devtools.d.ts","sourceRoot":"","sources":["../src/devtools.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAIjG;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,YAAY,CAAC,KAAK,SAAS,MAAM,EAAE,GAAG,SAAS,MAAM,EAAE,EAAE,SAAS,YAAY,EAC5F,UAAU,EAAE,aAAa,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC,EACzC,OAAO,GAAE,IAAI,CAAC,gBAAgB,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC,EAAE,SAAS,CAAM,GAC9D,eAAe,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC,CA+BjC"}
|
package/dist/devtools.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { createMachine as e } from "./interpret.js";
|
|
2
|
+
//#region src/devtools.ts
|
|
3
|
+
function t(t, n = {}) {
|
|
4
|
+
return e(t).start({
|
|
5
|
+
...n,
|
|
6
|
+
onDebug(e) {
|
|
7
|
+
switch (e.type) {
|
|
8
|
+
case "guard":
|
|
9
|
+
console.debug(`[clockwork:guard] ${e.event.type}: ${e.from} → ${e.target} — ${e.passed ? "passed" : "blocked"}`);
|
|
10
|
+
break;
|
|
11
|
+
case "invoke-abort":
|
|
12
|
+
console.debug(`[clockwork:invoke] #${e.invokeId} aborted in "${e.state}"`);
|
|
13
|
+
break;
|
|
14
|
+
case "invoke-done":
|
|
15
|
+
console.debug(`[clockwork:invoke] #${e.invokeId} done in "${e.state}"`);
|
|
16
|
+
break;
|
|
17
|
+
case "invoke-error":
|
|
18
|
+
console.debug(`[clockwork:invoke] #${e.invokeId} error in "${e.state}"`, e.error);
|
|
19
|
+
break;
|
|
20
|
+
case "invoke-start":
|
|
21
|
+
console.debug(`[clockwork:invoke] #${e.invokeId} started in "${e.state}"`);
|
|
22
|
+
break;
|
|
23
|
+
case "transition":
|
|
24
|
+
console.debug(`[clockwork:transition] ${e.event.type}: ${e.from} → ${e.to}`);
|
|
25
|
+
break;
|
|
26
|
+
case "transition-skipped":
|
|
27
|
+
console.debug(`[clockwork:skip] ${e.event.type}: no matching transition in "${e.from}"`);
|
|
28
|
+
break;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
//#endregion
|
|
34
|
+
export { t as debugMachine };
|
|
35
|
+
|
|
36
|
+
//# sourceMappingURL=devtools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"devtools.js","names":[],"sources":["../src/devtools.ts"],"sourcesContent":["/**\n * @vielzeug/clockwork — debug utilities for state machine visualisation.\n *\n * Import from the dedicated sub-path so it is tree-shaken from production bundles:\n * ```ts\n * import { debugMachine } from '@vielzeug/clockwork/devtools';\n * ```\n */\n\nimport type { InterpretOptions, MachineConfig, MachineEvent, MachineInstance } from './types.js';\n\nimport { createMachine } from './interpret.js';\n\n/**\n * Wraps {@link createMachine} and attaches a `console.group`-based debug logger\n * that traces every guard evaluation, transition, invoke lifecycle event, and\n * skipped transition to the browser/Node console.\n *\n * **Development only.** Do not use in production — event payloads (including\n * any PII in context or event fields) are written to the console. Import from\n * the dedicated sub-path so the logging code is tree-shaken from production bundles.\n *\n * @example\n * ```ts\n * import { debugMachine } from '@vielzeug/clockwork/devtools';\n *\n * const m = debugMachine(trafficLight);\n * m.send({ type: 'NEXT' });\n * // [clockwork:transition] NEXT: idle → running\n * ```\n */\nexport function debugMachine<State extends string, Ctx extends object, Ev extends MachineEvent>(\n definition: MachineConfig<State, Ctx, Ev>,\n options: Omit<InterpretOptions<State, Ctx, Ev>, 'onDebug'> = {},\n): MachineInstance<State, Ctx, Ev> {\n return createMachine(definition).start({\n ...options,\n onDebug(event) {\n switch (event.type) {\n case 'guard':\n console.debug(\n `[clockwork:guard] ${event.event.type}: ${event.from} → ${event.target} — ${event.passed ? 'passed' : 'blocked'}`,\n );\n break;\n case 'invoke-abort':\n console.debug(`[clockwork:invoke] #${event.invokeId} aborted in \"${event.state}\"`);\n break;\n case 'invoke-done':\n console.debug(`[clockwork:invoke] #${event.invokeId} done in \"${event.state}\"`);\n break;\n case 'invoke-error':\n console.debug(`[clockwork:invoke] #${event.invokeId} error in \"${event.state}\"`, event.error);\n break;\n case 'invoke-start':\n console.debug(`[clockwork:invoke] #${event.invokeId} started in \"${event.state}\"`);\n break;\n case 'transition':\n console.debug(`[clockwork:transition] ${event.event.type}: ${event.from} → ${event.to}`);\n break;\n case 'transition-skipped':\n console.debug(`[clockwork:skip] ${event.event.type}: no matching transition in \"${event.from}\"`);\n break;\n }\n },\n } as InterpretOptions<State, Ctx, Ev>);\n}\n"],"mappings":";;AA+BA,SAAgB,EACd,GACA,IAA6D,CAAC,GAC7B;CACjC,OAAO,EAAc,CAAU,CAAC,CAAC,MAAM;EACrC,GAAG;EACH,QAAQ,GAAO;GACb,QAAQ,EAAM,MAAd;IACE,KAAK;KACH,QAAQ,MACN,qBAAqB,EAAM,MAAM,KAAK,IAAI,EAAM,KAAK,KAAK,EAAM,OAAO,KAAK,EAAM,SAAS,WAAW,WACxG;KACA;IACF,KAAK;KACH,QAAQ,MAAM,uBAAuB,EAAM,SAAS,eAAe,EAAM,MAAM,EAAE;KACjF;IACF,KAAK;KACH,QAAQ,MAAM,uBAAuB,EAAM,SAAS,YAAY,EAAM,MAAM,EAAE;KAC9E;IACF,KAAK;KACH,QAAQ,MAAM,uBAAuB,EAAM,SAAS,aAAa,EAAM,MAAM,IAAI,EAAM,KAAK;KAC5F;IACF,KAAK;KACH,QAAQ,MAAM,uBAAuB,EAAM,SAAS,eAAe,EAAM,MAAM,EAAE;KACjF;IACF,KAAK;KACH,QAAQ,MAAM,0BAA0B,EAAM,MAAM,KAAK,IAAI,EAAM,KAAK,KAAK,EAAM,IAAI;KACvF;IACF,KAAK;KACH,QAAQ,MAAM,oBAAoB,EAAM,MAAM,KAAK,+BAA+B,EAAM,KAAK,EAAE;KAC/F;GACJ;EACF;CACF,CAAqC;AACvC"}
|
package/dist/errors.cjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var e=class e extends Error{constructor(e,t){super(e,t),this.name=new.target.name,Object.setPrototypeOf(this,new.target.prototype)}static is(t){return t instanceof e}},t=class extends e{path;constructor(e,t,n){super(e,n),this.path=t}},n=class extends e{path;initial;constructor(e,t,n,r){super(e,r),this.path=t,this.initial=n}},r=class extends e{path;eventType;constructor(e,t,n,r){super(e,r),this.path=t,this.eventType=n}},i=class extends e{path;target;eventType;constructor(e,t,n,r,i){super(e,i),this.path=t,this.target=n,this.eventType=r}},a=class extends e{path;delay;constructor(e,t,n,r){super(e,r),this.path=t,this.delay=n}},o=class extends e{maxTransitionsPerFlush;constructor(e,t,n){super(e,n),this.maxTransitionsPerFlush=t}},s=class extends e{state;constructor(e,t,n){super(e,n),this.state=t}},c=class extends e{phase;reason;constructor(e,t,n,r){super(e,r),this.phase=t,this.reason=n}},l=class extends e{maxTransitionsPerFlush;constructor(e,t,n){super(e,n),this.maxTransitionsPerFlush=t}};exports.ClockworkError=e,exports.ClockworkInvalidAfterDelayError=a,exports.ClockworkInvalidInitialStateError=n,exports.ClockworkInvalidMaxTransitionsError=o,exports.ClockworkInvalidSnapshotStateError=s,exports.ClockworkInvalidTransitionArrayError=r,exports.ClockworkInvalidValidateContextError=c,exports.ClockworkMissingCompoundInitialError=t,exports.ClockworkTransitionLoopGuardError=l,exports.ClockworkUnknownTargetError=i;
|
|
2
|
+
//# sourceMappingURL=errors.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.cjs","names":[],"sources":["../src/errors.ts"],"sourcesContent":["/** Base class for all clockwork errors. Use `instanceof ClockworkError` to catch any clockwork-originated error. */\nexport class ClockworkError extends Error {\n constructor(message: string, opts?: ErrorOptions) {\n super(message, opts);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n\n static is(err: unknown): err is ClockworkError {\n return err instanceof ClockworkError;\n }\n}\n\n/** Thrown when a compound state does not declare an `initial` substate. */\nexport class ClockworkMissingCompoundInitialError extends ClockworkError {\n readonly path: string;\n constructor(message: string, path: string, opts?: ErrorOptions) {\n super(message, opts);\n this.path = path;\n }\n}\n\n/** Thrown when a compound state's `initial` value does not match any substate. */\nexport class ClockworkInvalidInitialStateError extends ClockworkError {\n readonly path: string;\n readonly initial: string;\n constructor(message: string, path: string, initial: string, opts?: ErrorOptions) {\n super(message, opts);\n this.path = path;\n this.initial = initial;\n }\n}\n\n/** Thrown when a transition definition is empty or not a valid array. */\nexport class ClockworkInvalidTransitionArrayError extends ClockworkError {\n readonly path: string;\n readonly eventType?: string;\n constructor(message: string, path: string, eventType?: string, opts?: ErrorOptions) {\n super(message, opts);\n this.path = path;\n this.eventType = eventType;\n }\n}\n\n/** Thrown when a transition or `after` definition targets an unknown state. */\nexport class ClockworkUnknownTargetError extends ClockworkError {\n readonly path: string;\n readonly target: string;\n readonly eventType?: string;\n constructor(message: string, path: string, target: string, eventType?: string, opts?: ErrorOptions) {\n super(message, opts);\n this.path = path;\n this.target = target;\n this.eventType = eventType;\n }\n}\n\n/** Thrown when an `after` delay value is invalid (must be a finite number ≥ 0). */\nexport class ClockworkInvalidAfterDelayError extends ClockworkError {\n readonly path: string;\n readonly delay: number;\n constructor(message: string, path: string, delay: number, opts?: ErrorOptions) {\n super(message, opts);\n this.path = path;\n this.delay = delay;\n }\n}\n\n/** Thrown when `maxTransitionsPerFlush` is configured with a value less than 1. */\nexport class ClockworkInvalidMaxTransitionsError extends ClockworkError {\n readonly maxTransitionsPerFlush: number;\n constructor(message: string, maxTransitionsPerFlush: number, opts?: ErrorOptions) {\n super(message, opts);\n this.maxTransitionsPerFlush = maxTransitionsPerFlush;\n }\n}\n\n/** Thrown when a persisted snapshot references a state that no longer exists in the machine definition. */\nexport class ClockworkInvalidSnapshotStateError extends ClockworkError {\n readonly state: string;\n constructor(message: string, state: string, opts?: ErrorOptions) {\n super(message, opts);\n this.state = state;\n }\n}\n\n/** Thrown when `validateContext` returns a failure reason during init or transition. */\nexport class ClockworkInvalidValidateContextError extends ClockworkError {\n readonly phase: 'init' | 'transition';\n readonly reason: string | true;\n constructor(message: string, phase: 'init' | 'transition', reason: string | true, opts?: ErrorOptions) {\n super(message, opts);\n this.phase = phase;\n this.reason = reason;\n }\n}\n\n/** Thrown when the transition queue exceeds `maxTransitionsPerFlush`, indicating an infinite loop. */\nexport class ClockworkTransitionLoopGuardError extends ClockworkError {\n readonly maxTransitionsPerFlush: number;\n constructor(message: string, maxTransitionsPerFlush: number, opts?: ErrorOptions) {\n super(message, opts);\n this.maxTransitionsPerFlush = maxTransitionsPerFlush;\n }\n}\n"],"mappings":"AACA,IAAa,EAAb,MAAa,UAAuB,KAAM,CACxC,YAAY,EAAiB,EAAqB,CAChD,MAAM,EAAS,CAAI,EACnB,KAAK,KAAO,IAAI,OAAO,KACvB,OAAO,eAAe,KAAM,IAAI,OAAO,SAAS,CAClD,CAEA,OAAO,GAAG,EAAqC,CAC7C,OAAO,aAAe,CACxB,CACF,EAGa,EAAb,cAA0D,CAAe,CACvE,KACA,YAAY,EAAiB,EAAc,EAAqB,CAC9D,MAAM,EAAS,CAAI,EACnB,KAAK,KAAO,CACd,CACF,EAGa,EAAb,cAAuD,CAAe,CACpE,KACA,QACA,YAAY,EAAiB,EAAc,EAAiB,EAAqB,CAC/E,MAAM,EAAS,CAAI,EACnB,KAAK,KAAO,EACZ,KAAK,QAAU,CACjB,CACF,EAGa,EAAb,cAA0D,CAAe,CACvE,KACA,UACA,YAAY,EAAiB,EAAc,EAAoB,EAAqB,CAClF,MAAM,EAAS,CAAI,EACnB,KAAK,KAAO,EACZ,KAAK,UAAY,CACnB,CACF,EAGa,EAAb,cAAiD,CAAe,CAC9D,KACA,OACA,UACA,YAAY,EAAiB,EAAc,EAAgB,EAAoB,EAAqB,CAClG,MAAM,EAAS,CAAI,EACnB,KAAK,KAAO,EACZ,KAAK,OAAS,EACd,KAAK,UAAY,CACnB,CACF,EAGa,EAAb,cAAqD,CAAe,CAClE,KACA,MACA,YAAY,EAAiB,EAAc,EAAe,EAAqB,CAC7E,MAAM,EAAS,CAAI,EACnB,KAAK,KAAO,EACZ,KAAK,MAAQ,CACf,CACF,EAGa,EAAb,cAAyD,CAAe,CACtE,uBACA,YAAY,EAAiB,EAAgC,EAAqB,CAChF,MAAM,EAAS,CAAI,EACnB,KAAK,uBAAyB,CAChC,CACF,EAGa,EAAb,cAAwD,CAAe,CACrE,MACA,YAAY,EAAiB,EAAe,EAAqB,CAC/D,MAAM,EAAS,CAAI,EACnB,KAAK,MAAQ,CACf,CACF,EAGa,EAAb,cAA0D,CAAe,CACvE,MACA,OACA,YAAY,EAAiB,EAA8B,EAAuB,EAAqB,CACrG,MAAM,EAAS,CAAI,EACnB,KAAK,MAAQ,EACb,KAAK,OAAS,CAChB,CACF,EAGa,EAAb,cAAuD,CAAe,CACpE,uBACA,YAAY,EAAiB,EAAgC,EAAqB,CAChF,MAAM,EAAS,CAAI,EACnB,KAAK,uBAAyB,CAChC,CACF"}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/** Base class for all clockwork errors. Use `instanceof ClockworkError` to catch any clockwork-originated error. */
|
|
2
|
+
export declare class ClockworkError extends Error {
|
|
3
|
+
constructor(message: string, opts?: ErrorOptions);
|
|
4
|
+
static is(err: unknown): err is ClockworkError;
|
|
5
|
+
}
|
|
6
|
+
/** Thrown when a compound state does not declare an `initial` substate. */
|
|
7
|
+
export declare class ClockworkMissingCompoundInitialError extends ClockworkError {
|
|
8
|
+
readonly path: string;
|
|
9
|
+
constructor(message: string, path: string, opts?: ErrorOptions);
|
|
10
|
+
}
|
|
11
|
+
/** Thrown when a compound state's `initial` value does not match any substate. */
|
|
12
|
+
export declare class ClockworkInvalidInitialStateError extends ClockworkError {
|
|
13
|
+
readonly path: string;
|
|
14
|
+
readonly initial: string;
|
|
15
|
+
constructor(message: string, path: string, initial: string, opts?: ErrorOptions);
|
|
16
|
+
}
|
|
17
|
+
/** Thrown when a transition definition is empty or not a valid array. */
|
|
18
|
+
export declare class ClockworkInvalidTransitionArrayError extends ClockworkError {
|
|
19
|
+
readonly path: string;
|
|
20
|
+
readonly eventType?: string;
|
|
21
|
+
constructor(message: string, path: string, eventType?: string, opts?: ErrorOptions);
|
|
22
|
+
}
|
|
23
|
+
/** Thrown when a transition or `after` definition targets an unknown state. */
|
|
24
|
+
export declare class ClockworkUnknownTargetError extends ClockworkError {
|
|
25
|
+
readonly path: string;
|
|
26
|
+
readonly target: string;
|
|
27
|
+
readonly eventType?: string;
|
|
28
|
+
constructor(message: string, path: string, target: string, eventType?: string, opts?: ErrorOptions);
|
|
29
|
+
}
|
|
30
|
+
/** Thrown when an `after` delay value is invalid (must be a finite number ≥ 0). */
|
|
31
|
+
export declare class ClockworkInvalidAfterDelayError extends ClockworkError {
|
|
32
|
+
readonly path: string;
|
|
33
|
+
readonly delay: number;
|
|
34
|
+
constructor(message: string, path: string, delay: number, opts?: ErrorOptions);
|
|
35
|
+
}
|
|
36
|
+
/** Thrown when `maxTransitionsPerFlush` is configured with a value less than 1. */
|
|
37
|
+
export declare class ClockworkInvalidMaxTransitionsError extends ClockworkError {
|
|
38
|
+
readonly maxTransitionsPerFlush: number;
|
|
39
|
+
constructor(message: string, maxTransitionsPerFlush: number, opts?: ErrorOptions);
|
|
40
|
+
}
|
|
41
|
+
/** Thrown when a persisted snapshot references a state that no longer exists in the machine definition. */
|
|
42
|
+
export declare class ClockworkInvalidSnapshotStateError extends ClockworkError {
|
|
43
|
+
readonly state: string;
|
|
44
|
+
constructor(message: string, state: string, opts?: ErrorOptions);
|
|
45
|
+
}
|
|
46
|
+
/** Thrown when `validateContext` returns a failure reason during init or transition. */
|
|
47
|
+
export declare class ClockworkInvalidValidateContextError extends ClockworkError {
|
|
48
|
+
readonly phase: 'init' | 'transition';
|
|
49
|
+
readonly reason: string | true;
|
|
50
|
+
constructor(message: string, phase: 'init' | 'transition', reason: string | true, opts?: ErrorOptions);
|
|
51
|
+
}
|
|
52
|
+
/** Thrown when the transition queue exceeds `maxTransitionsPerFlush`, indicating an infinite loop. */
|
|
53
|
+
export declare class ClockworkTransitionLoopGuardError extends ClockworkError {
|
|
54
|
+
readonly maxTransitionsPerFlush: number;
|
|
55
|
+
constructor(message: string, maxTransitionsPerFlush: number, opts?: ErrorOptions);
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,oHAAoH;AACpH,qBAAa,cAAe,SAAQ,KAAK;gBAC3B,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,YAAY;IAMhD,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,GAAG,GAAG,IAAI,cAAc;CAG/C;AAED,2EAA2E;AAC3E,qBAAa,oCAAqC,SAAQ,cAAc;IACtE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;gBACV,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,YAAY;CAI/D;AAED,kFAAkF;AAClF,qBAAa,iCAAkC,SAAQ,cAAc;IACnE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;gBACb,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,YAAY;CAKhF;AAED,yEAAyE;AACzE,qBAAa,oCAAqC,SAAQ,cAAc;IACtE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;gBAChB,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,YAAY;CAKnF;AAED,+EAA+E;AAC/E,qBAAa,2BAA4B,SAAQ,cAAc;IAC7D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;gBAChB,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,YAAY;CAMnG;AAED,mFAAmF;AACnF,qBAAa,+BAAgC,SAAQ,cAAc;IACjE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;gBACX,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,YAAY;CAK9E;AAED,mFAAmF;AACnF,qBAAa,mCAAoC,SAAQ,cAAc;IACrE,QAAQ,CAAC,sBAAsB,EAAE,MAAM,CAAC;gBAC5B,OAAO,EAAE,MAAM,EAAE,sBAAsB,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,YAAY;CAIjF;AAED,2GAA2G;AAC3G,qBAAa,kCAAmC,SAAQ,cAAc;IACpE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;gBACX,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,YAAY;CAIhE;AAED,wFAAwF;AACxF,qBAAa,oCAAqC,SAAQ,cAAc;IACtE,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY,CAAC;IACtC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;gBACnB,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,YAAY,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,EAAE,IAAI,CAAC,EAAE,YAAY;CAKtG;AAED,sGAAsG;AACtG,qBAAa,iCAAkC,SAAQ,cAAc;IACnE,QAAQ,CAAC,sBAAsB,EAAE,MAAM,CAAC;gBAC5B,OAAO,EAAE,MAAM,EAAE,sBAAsB,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,YAAY;CAIjF"}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
//#region src/errors.ts
|
|
2
|
+
var e = class e extends Error {
|
|
3
|
+
constructor(e, t) {
|
|
4
|
+
super(e, t), this.name = new.target.name, Object.setPrototypeOf(this, new.target.prototype);
|
|
5
|
+
}
|
|
6
|
+
static is(t) {
|
|
7
|
+
return t instanceof e;
|
|
8
|
+
}
|
|
9
|
+
}, t = class extends e {
|
|
10
|
+
path;
|
|
11
|
+
constructor(e, t, n) {
|
|
12
|
+
super(e, n), this.path = t;
|
|
13
|
+
}
|
|
14
|
+
}, n = class extends e {
|
|
15
|
+
path;
|
|
16
|
+
initial;
|
|
17
|
+
constructor(e, t, n, r) {
|
|
18
|
+
super(e, r), this.path = t, this.initial = n;
|
|
19
|
+
}
|
|
20
|
+
}, r = class extends e {
|
|
21
|
+
path;
|
|
22
|
+
eventType;
|
|
23
|
+
constructor(e, t, n, r) {
|
|
24
|
+
super(e, r), this.path = t, this.eventType = n;
|
|
25
|
+
}
|
|
26
|
+
}, i = class extends e {
|
|
27
|
+
path;
|
|
28
|
+
target;
|
|
29
|
+
eventType;
|
|
30
|
+
constructor(e, t, n, r, i) {
|
|
31
|
+
super(e, i), this.path = t, this.target = n, this.eventType = r;
|
|
32
|
+
}
|
|
33
|
+
}, a = class extends e {
|
|
34
|
+
path;
|
|
35
|
+
delay;
|
|
36
|
+
constructor(e, t, n, r) {
|
|
37
|
+
super(e, r), this.path = t, this.delay = n;
|
|
38
|
+
}
|
|
39
|
+
}, o = class extends e {
|
|
40
|
+
maxTransitionsPerFlush;
|
|
41
|
+
constructor(e, t, n) {
|
|
42
|
+
super(e, n), this.maxTransitionsPerFlush = t;
|
|
43
|
+
}
|
|
44
|
+
}, s = class extends e {
|
|
45
|
+
state;
|
|
46
|
+
constructor(e, t, n) {
|
|
47
|
+
super(e, n), this.state = t;
|
|
48
|
+
}
|
|
49
|
+
}, c = class extends e {
|
|
50
|
+
phase;
|
|
51
|
+
reason;
|
|
52
|
+
constructor(e, t, n, r) {
|
|
53
|
+
super(e, r), this.phase = t, this.reason = n;
|
|
54
|
+
}
|
|
55
|
+
}, l = class extends e {
|
|
56
|
+
maxTransitionsPerFlush;
|
|
57
|
+
constructor(e, t, n) {
|
|
58
|
+
super(e, n), this.maxTransitionsPerFlush = t;
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
//#endregion
|
|
62
|
+
export { e as ClockworkError, a as ClockworkInvalidAfterDelayError, n as ClockworkInvalidInitialStateError, o as ClockworkInvalidMaxTransitionsError, s as ClockworkInvalidSnapshotStateError, r as ClockworkInvalidTransitionArrayError, c as ClockworkInvalidValidateContextError, t as ClockworkMissingCompoundInitialError, l as ClockworkTransitionLoopGuardError, i as ClockworkUnknownTargetError };
|
|
63
|
+
|
|
64
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","names":[],"sources":["../src/errors.ts"],"sourcesContent":["/** Base class for all clockwork errors. Use `instanceof ClockworkError` to catch any clockwork-originated error. */\nexport class ClockworkError extends Error {\n constructor(message: string, opts?: ErrorOptions) {\n super(message, opts);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n\n static is(err: unknown): err is ClockworkError {\n return err instanceof ClockworkError;\n }\n}\n\n/** Thrown when a compound state does not declare an `initial` substate. */\nexport class ClockworkMissingCompoundInitialError extends ClockworkError {\n readonly path: string;\n constructor(message: string, path: string, opts?: ErrorOptions) {\n super(message, opts);\n this.path = path;\n }\n}\n\n/** Thrown when a compound state's `initial` value does not match any substate. */\nexport class ClockworkInvalidInitialStateError extends ClockworkError {\n readonly path: string;\n readonly initial: string;\n constructor(message: string, path: string, initial: string, opts?: ErrorOptions) {\n super(message, opts);\n this.path = path;\n this.initial = initial;\n }\n}\n\n/** Thrown when a transition definition is empty or not a valid array. */\nexport class ClockworkInvalidTransitionArrayError extends ClockworkError {\n readonly path: string;\n readonly eventType?: string;\n constructor(message: string, path: string, eventType?: string, opts?: ErrorOptions) {\n super(message, opts);\n this.path = path;\n this.eventType = eventType;\n }\n}\n\n/** Thrown when a transition or `after` definition targets an unknown state. */\nexport class ClockworkUnknownTargetError extends ClockworkError {\n readonly path: string;\n readonly target: string;\n readonly eventType?: string;\n constructor(message: string, path: string, target: string, eventType?: string, opts?: ErrorOptions) {\n super(message, opts);\n this.path = path;\n this.target = target;\n this.eventType = eventType;\n }\n}\n\n/** Thrown when an `after` delay value is invalid (must be a finite number ≥ 0). */\nexport class ClockworkInvalidAfterDelayError extends ClockworkError {\n readonly path: string;\n readonly delay: number;\n constructor(message: string, path: string, delay: number, opts?: ErrorOptions) {\n super(message, opts);\n this.path = path;\n this.delay = delay;\n }\n}\n\n/** Thrown when `maxTransitionsPerFlush` is configured with a value less than 1. */\nexport class ClockworkInvalidMaxTransitionsError extends ClockworkError {\n readonly maxTransitionsPerFlush: number;\n constructor(message: string, maxTransitionsPerFlush: number, opts?: ErrorOptions) {\n super(message, opts);\n this.maxTransitionsPerFlush = maxTransitionsPerFlush;\n }\n}\n\n/** Thrown when a persisted snapshot references a state that no longer exists in the machine definition. */\nexport class ClockworkInvalidSnapshotStateError extends ClockworkError {\n readonly state: string;\n constructor(message: string, state: string, opts?: ErrorOptions) {\n super(message, opts);\n this.state = state;\n }\n}\n\n/** Thrown when `validateContext` returns a failure reason during init or transition. */\nexport class ClockworkInvalidValidateContextError extends ClockworkError {\n readonly phase: 'init' | 'transition';\n readonly reason: string | true;\n constructor(message: string, phase: 'init' | 'transition', reason: string | true, opts?: ErrorOptions) {\n super(message, opts);\n this.phase = phase;\n this.reason = reason;\n }\n}\n\n/** Thrown when the transition queue exceeds `maxTransitionsPerFlush`, indicating an infinite loop. */\nexport class ClockworkTransitionLoopGuardError extends ClockworkError {\n readonly maxTransitionsPerFlush: number;\n constructor(message: string, maxTransitionsPerFlush: number, opts?: ErrorOptions) {\n super(message, opts);\n this.maxTransitionsPerFlush = maxTransitionsPerFlush;\n }\n}\n"],"mappings":";AACA,IAAa,IAAb,MAAa,UAAuB,MAAM;CACxC,YAAY,GAAiB,GAAqB;EAGhD,AAFA,MAAM,GAAS,CAAI,GACnB,KAAK,OAAO,IAAI,OAAO,MACvB,OAAO,eAAe,MAAM,IAAI,OAAO,SAAS;CAClD;CAEA,OAAO,GAAG,GAAqC;EAC7C,OAAO,aAAe;CACxB;AACF,GAGa,IAAb,cAA0D,EAAe;CACvE;CACA,YAAY,GAAiB,GAAc,GAAqB;EAE9D,AADA,MAAM,GAAS,CAAI,GACnB,KAAK,OAAO;CACd;AACF,GAGa,IAAb,cAAuD,EAAe;CACpE;CACA;CACA,YAAY,GAAiB,GAAc,GAAiB,GAAqB;EAG/E,AAFA,MAAM,GAAS,CAAI,GACnB,KAAK,OAAO,GACZ,KAAK,UAAU;CACjB;AACF,GAGa,IAAb,cAA0D,EAAe;CACvE;CACA;CACA,YAAY,GAAiB,GAAc,GAAoB,GAAqB;EAGlF,AAFA,MAAM,GAAS,CAAI,GACnB,KAAK,OAAO,GACZ,KAAK,YAAY;CACnB;AACF,GAGa,IAAb,cAAiD,EAAe;CAC9D;CACA;CACA;CACA,YAAY,GAAiB,GAAc,GAAgB,GAAoB,GAAqB;EAIlG,AAHA,MAAM,GAAS,CAAI,GACnB,KAAK,OAAO,GACZ,KAAK,SAAS,GACd,KAAK,YAAY;CACnB;AACF,GAGa,IAAb,cAAqD,EAAe;CAClE;CACA;CACA,YAAY,GAAiB,GAAc,GAAe,GAAqB;EAG7E,AAFA,MAAM,GAAS,CAAI,GACnB,KAAK,OAAO,GACZ,KAAK,QAAQ;CACf;AACF,GAGa,IAAb,cAAyD,EAAe;CACtE;CACA,YAAY,GAAiB,GAAgC,GAAqB;EAEhF,AADA,MAAM,GAAS,CAAI,GACnB,KAAK,yBAAyB;CAChC;AACF,GAGa,IAAb,cAAwD,EAAe;CACrE;CACA,YAAY,GAAiB,GAAe,GAAqB;EAE/D,AADA,MAAM,GAAS,CAAI,GACnB,KAAK,QAAQ;CACf;AACF,GAGa,IAAb,cAA0D,EAAe;CACvE;CACA;CACA,YAAY,GAAiB,GAA8B,GAAuB,GAAqB;EAGrG,AAFA,MAAM,GAAS,CAAI,GACnB,KAAK,QAAQ,GACb,KAAK,SAAS;CAChB;AACF,GAGa,IAAb,cAAuD,EAAe;CACpE;CACA,YAAY,GAAiB,GAAgC,GAAqB;EAEhF,AADA,MAAM,GAAS,CAAI,GACnB,KAAK,yBAAyB;CAChC;AACF"}
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./errors.cjs"),t=require("./interpret.cjs");exports.ClockworkError=e.ClockworkError,exports.ClockworkInvalidAfterDelayError=e.ClockworkInvalidAfterDelayError,exports.ClockworkInvalidInitialStateError=e.ClockworkInvalidInitialStateError,exports.ClockworkInvalidMaxTransitionsError=e.ClockworkInvalidMaxTransitionsError,exports.ClockworkInvalidSnapshotStateError=e.ClockworkInvalidSnapshotStateError,exports.ClockworkInvalidTransitionArrayError=e.ClockworkInvalidTransitionArrayError,exports.ClockworkInvalidValidateContextError=e.ClockworkInvalidValidateContextError,exports.ClockworkMissingCompoundInitialError=e.ClockworkMissingCompoundInitialError,exports.ClockworkTransitionLoopGuardError=e.ClockworkTransitionLoopGuardError,exports.ClockworkUnknownTargetError=e.ClockworkUnknownTargetError,exports.createMachine=t.createMachine;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { ClockworkError, ClockworkInvalidAfterDelayError, ClockworkInvalidInitialStateError, ClockworkInvalidMaxTransitionsError, ClockworkInvalidSnapshotStateError, ClockworkInvalidTransitionArrayError, ClockworkInvalidValidateContextError, ClockworkMissingCompoundInitialError, ClockworkTransitionLoopGuardError, ClockworkUnknownTargetError, } from './errors.js';
|
|
2
|
+
export { createMachine } from './interpret.js';
|
|
3
|
+
export type { ActionArgs, ActionFn, AfterActionFn, AfterDef, AfterEvent, ContextValidator, DebugEvent, EventByType, EventType, GuardFn, InterceptorFn, InterpretOptions, InvokeArgs, InvokeDef, LifecycleEvent, LifecycleFn, MachineAction, MachineConfig, MachineDefinition, MachineEvent, MachineGuard, MachineInstance, MachineSchema, MachineSnapshot, MachineTypeConfig, MachineTypeDefinition, MachineTypeInstance, MachineTypeOptions, PersistenceAdapter, SendResult, StateNode, TransitionDef, TransitionInput, TransitionTraceEntry, } from './types.js';
|
|
4
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,+BAA+B,EAC/B,iCAAiC,EACjC,mCAAmC,EACnC,kCAAkC,EAClC,oCAAoC,EACpC,oCAAoC,EACpC,oCAAoC,EACpC,iCAAiC,EACjC,2BAA2B,GAC5B,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,YAAY,EACV,UAAU,EACV,QAAQ,EACR,aAAa,EACb,QAAQ,EACR,UAAU,EACV,gBAAgB,EAChB,UAAU,EACV,WAAW,EACX,SAAS,EACT,OAAO,EACP,aAAa,EACb,gBAAgB,EAChB,UAAU,EACV,SAAS,EACT,cAAc,EACd,WAAW,EACX,aAAa,EACb,aAAa,EACb,iBAAiB,EACjB,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,aAAa,EACb,eAAe,EACf,iBAAiB,EACjB,qBAAqB,EACrB,mBAAmB,EACnB,kBAAkB,EAClB,kBAAkB,EAClB,UAAU,EACV,SAAS,EACT,aAAa,EACb,eAAe,EACf,oBAAoB,GACrB,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { ClockworkError as e, ClockworkInvalidAfterDelayError as t, ClockworkInvalidInitialStateError as n, ClockworkInvalidMaxTransitionsError as r, ClockworkInvalidSnapshotStateError as i, ClockworkInvalidTransitionArrayError as a, ClockworkInvalidValidateContextError as o, ClockworkMissingCompoundInitialError as s, ClockworkTransitionLoopGuardError as c, ClockworkUnknownTargetError as l } from "./errors.js";
|
|
2
|
+
import { createMachine as u } from "./interpret.js";
|
|
3
|
+
export { e as ClockworkError, t as ClockworkInvalidAfterDelayError, n as ClockworkInvalidInitialStateError, r as ClockworkInvalidMaxTransitionsError, i as ClockworkInvalidSnapshotStateError, a as ClockworkInvalidTransitionArrayError, o as ClockworkInvalidValidateContextError, s as ClockworkMissingCompoundInitialError, c as ClockworkTransitionLoopGuardError, l as ClockworkUnknownTargetError, u as createMachine };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const e=require("./_dev.cjs"),t=require("./_trace.cjs"),n=require("./errors.cjs"),r=require("./definition.cjs");let i=require("@vielzeug/ripple");var a={type:`$init`},o={type:`$hydrate`},s=(e,t,n)=>{let{context:i,event:a,state:o}=t;if(!a||typeof a.type!=`string`)return;let s=r.getAncestorPaths(o);for(let t=s.length-1;t>=0;t--){let c=r.getNodeAtPath(e.states,s[t]);if(!c?.on)continue;let l=a.type,u=Object.hasOwn(c.on,l)?c.on[l]:void 0;if(!u)continue;let d=Array.isArray(u)?u:[u];for(let e of d){let t=!e.guard||e.guard({context:i,event:a});if(n?.({context:i,event:a,from:o,passed:t,target:e.target}),t)return e}}},c=Object.freeze({status:`transitioned`}),l=Object.freeze({status:`queued`}),u=Object.freeze({status:`rejected`}),d=(d,f={})=>{let p=f.onDebug,m=f.traceLimit??(p?50:0);if(f.maxTransitionsPerFlush!==void 0&&f.maxTransitionsPerFlush<1)throw new n.ClockworkInvalidMaxTransitionsError(`maxTransitionsPerFlush must be greater than 0`,f.maxTransitionsPerFlush);let h=f.maxTransitionsPerFlush??1e3,g=f.clone??structuredClone,_=d.states,v=f.interceptors??[],y=f.snapshot??f.persistence?.load();if(y){let e=y.state.split(`.`)[0];if(!(Object.hasOwn(d.states,e)&&(!y.state.includes(`.`)||r.getNodeAtPath(d.states,y.state))))throw new n.ClockworkInvalidSnapshotStateError(`snapshot state "${y.state}" not found in states`,y.state)}let b=(e,t)=>{let r=d.validateContext;if(!r)return;let i=r(e);if(i!==!0)throw new n.ClockworkInvalidValidateContextError(`context failed validation during ${t}${i?`: ${i}`:``}`,t,i)},x=y?y.state:r.resolveLeaf(_,d.initial),S=g(y?y.context:`context`in d?d.context:{});y||b(S,`init`);let C=(0,i.signal)(x),w=(0,i.signal)(S),T=t.createTraceBuffer(m),E=new AbortController,D=!1,O=0,k=new Set,A=e=>{for(let t of k)e&&!e.includes(t.path)||(t.controller.abort(),p?.({context:w.value,event:t.event,invokeId:t.id,state:t.state,type:`invoke-abort`}),k.delete(t))},j=new Set,M=e=>{for(let t of j)e&&!e.includes(t.path)||(clearTimeout(t.timer),j.delete(t))},N=()=>{f.persistence?.save({context:g(w.value),state:C.value})},P=new Set,F=()=>{if(P.size===0)return;let e=Object.freeze({context:w.value,state:C.value});for(let t of P)t(e)},I=[],L=!1,R=(e,t)=>{if(!e.includes(`.`)&&!t.includes(`.`)||e===t)return{entryPaths:[t],exitPaths:[e]};let n=r.getAncestorPaths(e),i=r.getAncestorPaths(t),a=0;for(;a<n.length&&a<i.length&&n[a]===i[a];)a++;return{entryPaths:i.slice(a),exitPaths:n.slice(a).reverse()}},z=(e,t,n,a)=>{let{entryPaths:o,exitPaths:s}=R(e,t),c=g(w.value);for(let e of s)r.getNodeAtPath(_,e)?.exit?.({context:c,event:a});for(let e of n)e({context:c,event:a});for(let e of o)r.getNodeAtPath(_,e)?.entry?.({context:c,event:a});Object.freeze(c),b(c,`transition`),(0,i.batch)(()=>{A(s),M(s),C.value=t,w.value=c}),p?.({event:a,from:e,to:t,type:`transition`}),T?.push({event:a,from:e,timestamp:Date.now(),to:t}),F(),N(),B(a,o),V(o)},B=(e,t)=>{for(let n of t){let t=r.getNodeAtPath(_,n);if(t?.invoke?.length)for(let r of t.invoke){let t=new AbortController,i=r.id??String(++O),a=w.value,o={controller:t,event:e,id:i,path:n,state:C.value};k.add(o),p?.({context:a,event:e,invokeId:i,state:C.value,type:`invoke-start`}),r.src({context:a,entryEvent:e,signal:t.signal}).then(n=>{k.delete(o),!(D||t.signal.aborted||!r.onDone)&&(p?.({context:a,event:e,invokeId:i,result:n,state:C.value,type:`invoke-done`}),I.push({event:r.onDone(n,a),tag:`event`}),L||W())}).catch(n=>{k.delete(o),!(D||t.signal.aborted||!r.onError)&&(p?.({context:a,error:n,event:e,invokeId:i,state:C.value,type:`invoke-error`}),I.push({event:r.onError(n,a),tag:`event`}),L||W())})}}},V=e=>{for(let t of e){let e=r.getNodeAtPath(_,t);if(e?.after?.length)for(let n of e.after){let e={path:t,timer:setTimeout(()=>{if(j.delete(e),D||!r.getAncestorPaths(C.value).includes(t))return;let i=C.value,a={delay:n.delay,type:`$after`};if(n.guard&&!n.guard({context:w.value,event:a}))return;let o=r.resolveLeaf(_,n.target);I.push({actions:n.actions??[],afterEvent:a,from:i,tag:`after`,target:o}),W()},n.delay)};j.add(e)}}},H=e=>{if(D)return!1;if(e.tag===`after`)return z(e.from,e.target,e.actions,e.afterEvent),!0;let t=C.value,n=s(d,{context:w.value,event:e.event,state:t},p?e=>p({...e,type:`guard`}):void 0);if(!n)return p?.({event:e.event,from:t,type:`transition-skipped`}),!1;let i=r.resolveLeaf(_,n.target),a=n.actions??[];return z(t,i,a,e.event),!0},U=()=>{let e=0;for(;I.length>0;){if(++e>h)throw new n.ClockworkTransitionLoopGuardError(`transition queue exceeded maxTransitionsPerFlush`,h);H(I.shift())}},W=()=>{if(!L){L=!0;try{U()}catch(e){throw I.length=0,e}finally{L=!1}}},G=e=>D?!1:!!s(d,{context:w.value,event:e,state:C.value}),K=t=>{if(D)return e.warn(`send() called on a disposed machine — event ignored`),u;let n=t;for(let e of v)if(n=e(n,{context:w.value,state:C.value}),n===null)return u;let r=n;if(L)return I.push({event:r,tag:`event`}),l;L=!0;try{let e=H({event:r,tag:`event`});return U(),e?c:u}catch(e){throw I.length=0,e}finally{L=!1}},q=()=>Object.freeze({context:g(w.value),state:C.value}),J=()=>T?.get()??[],Y=(...e)=>{if(D)return!1;let t=C.value;return e.some(e=>t===e||t.startsWith(`${e}.`))},X=e=>(P.add(e),()=>P.delete(e)),Z=r.getAncestorPaths(x);if(y)B(o,Z),V(Z);else{if(Z.some(e=>r.getNodeAtPath(_,e)?.entry)){let e=g(w.value);for(let t of Z)r.getNodeAtPath(_,t)?.entry?.({context:e,event:a});b(e,`init`),w.value=e}B(a,Z),V(Z),f.persistence&&N()}let Q=()=>{D||(D=!0,E.abort(),A(),M(),C.dispose(),w.dispose())};return{can:G,context:(0,i.readonly)(w),get disposalSignal(){return E.signal},dispose:Q,get disposed(){return D},getSnapshot:q,getTrace:J,matches:Y,send:K,state:(0,i.readonly)(C),subscribe:X,[Symbol.dispose]:Q}},f=e=>(r.validateDefinition(e),{resolve(t,n){return s(e,t,n?.onGuard)},start(t){return d(e,t)}});exports.createMachine=f;
|
|
2
|
+
//# sourceMappingURL=interpret.cjs.map
|