@vielzeug/clockwork 26.10.0 → 26.10.5
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 +1 -1
- package/dist/clockwork.cjs.map +1 -1
- package/dist/clockwork.iife.js.map +1 -1
- package/dist/clockwork.js.map +1 -1
- package/dist/interpret.cjs.map +1 -1
- package/dist/interpret.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -49,4 +49,4 @@ actor.dispose();
|
|
|
49
49
|
|
|
50
50
|
## License
|
|
51
51
|
|
|
52
|
-
MIT © [Helmuth Saatkamp](https://github.com/helmuthdu)
|
|
52
|
+
MIT © [Helmuth Saatkamp](https://github.com/helmuthdu): part of the [Vielzeug](https://github.com/helmuthdu/vielzeug) monorepo.
|
package/dist/clockwork.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"clockwork.cjs","names":[],"sources":["../src/errors.ts","../src/_dev.ts","../src/interpret.ts"],"sourcesContent":["/** Base class for every Clockwork failure. */\nexport class ClockworkError extends Error {\n readonly details: Readonly<Record<string, unknown>>;\n\n constructor(message: string, details: Record<string, unknown> = {}, opts?: ErrorOptions) {\n super(message, opts);\n this.name = new.target.name;\n this.details = Object.freeze({ ...details });\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** The machine definition failed validation at `defineMachine()` time. */\nexport class ClockworkDefinitionError extends ClockworkError {}\n\n/** A snapshot, its context, or a reducer result failed validation. */\nexport class ClockworkSnapshotError extends ClockworkError {}\n\n/** An actor exceeded the fixed queued-transition limit and disposed itself. */\nexport class ClockworkTransitionLimitError extends ClockworkError {}\n","const isDev = !(globalThis as { __CLOCKWORK_PROD__?: boolean }).__CLOCKWORK_PROD__;\n\nexport function warn(msg: string): void {\n if (isDev) console.warn(`[@vielzeug/clockwork] ${msg}`);\n}\n","import { tapper } from '@vielzeug/arsenal';\nimport { warn } from './_dev.js';\nimport { ClockworkDefinitionError, ClockworkSnapshotError, ClockworkTransitionLimitError } from './errors.js';\nimport type {\n Actor,\n ActorErrorContext,\n ActorOptions,\n ActorTapEvent,\n After,\n Effect,\n EventType,\n Machine,\n MachineConfig,\n MachineEvent,\n MachineSnapshot,\n StateNode,\n TransitionResult,\n} from './types.js';\n\nconst MAX_TIMER_MS = 2_147_483_647;\nconst MAX_TRANSITIONS = 1_000;\n\nconst isContextRecord = (value: unknown): value is Record<string, unknown> => {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return false;\n\n const prototype = Object.getPrototypeOf(value);\n\n return prototype === null || prototype === Object.prototype;\n};\n\n/** Fails fast on the definition footguns the type system cannot express: out-of-range\n * timer delays (platform timers fire immediately above 2^31 ms), empty transition\n * arrays, and a context that is not a plain record. Everything else — declared\n * targets, callback shapes, state keys — is compiler-checked in the typed definition. */\nconst assertDefinition = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n): void => {\n const context = (definition as { readonly context?: Context }).context;\n\n if (context !== undefined && !isContextRecord(context)) {\n throw new ClockworkDefinitionError('machine context must be a non-array object record', {});\n }\n\n for (const [state, node] of Object.entries(definition.states) as [string, StateNode<State, Context, Event>][]) {\n for (const [type, input] of Object.entries(node.on ?? {})) {\n if (Array.isArray(input) && input.length === 0) {\n throw new ClockworkDefinitionError('a transition array must not be empty', { state, type });\n }\n }\n\n for (const [index, after] of (node.after ?? []).entries()) {\n if (!Number.isFinite(after.delay) || after.delay < 0 || after.delay > MAX_TIMER_MS) {\n throw new ClockworkDefinitionError(`state \"${state}\" after delay must be between 0 and ${MAX_TIMER_MS}`, {\n delay: after.delay,\n index,\n state,\n });\n }\n }\n }\n};\n\ntype InternalEvent<State extends string, Context extends Record<string, unknown>, Event extends MachineEvent> = {\n readonly after: After<State, Context, Event>;\n readonly kind: 'after';\n};\n\ntype RuntimeEvent<State extends string, Context extends Record<string, unknown>, Event extends MachineEvent> =\n | { readonly event: Event; readonly kind: 'event' }\n | InternalEvent<State, Context, Event>;\n\n/** A transition or delayed transition selected for execution. The reducer's event\n * parameter is whatever the selector matched — the event for a user transition,\n * `undefined` for a timer — which the declared per-type signatures cannot express. */\ntype ExecutableTransition<State extends string, Context extends Record<string, unknown>, Event extends MachineEvent> = {\n readonly effects?: readonly Effect<Context, Event>[];\n readonly reduce?: (args: { readonly context: Readonly<Context>; readonly event: Event | undefined }) => Context;\n readonly target: State;\n};\n\ntype SelectedTransition<State extends string, Context extends Record<string, unknown>, Event extends MachineEvent> = {\n readonly event: Event | undefined;\n readonly transition: ExecutableTransition<State, Context, Event>;\n};\n\ntype TransitionOutcome<State extends string, Context extends Record<string, unknown>, Event extends MachineEvent> = {\n readonly event: Event | undefined;\n readonly result: TransitionResult<State, Context>;\n readonly transition?: ExecutableTransition<State, Context, Event>;\n};\n\nconst createSnapshot = <State extends string, Context extends Record<string, unknown>>(\n state: State,\n context: Context,\n): MachineSnapshot<State, Context> => {\n const cloned = Object.assign(Object.create(Object.getPrototypeOf(context)) as Context, context);\n\n return Object.freeze({ context: Object.freeze(cloned), state });\n};\n\nconst normalizeSnapshot = <State extends string, Context extends Record<string, unknown>>(\n snapshot: MachineSnapshot<State, Context>,\n): MachineSnapshot<State, Context> =>\n Object.isFrozen(snapshot) && Object.isFrozen(snapshot.context)\n ? snapshot\n : createSnapshot(snapshot.state, snapshot.context as Context);\n\nconst invalidSnapshot = (state: unknown): never => {\n throw new ClockworkSnapshotError(`snapshot state \"${String(state)}\" is not declared`, { state });\n};\n\nconst isMachineEvent = (event: unknown): event is MachineEvent =>\n typeof event === 'object' && event !== null && typeof (event as { type?: unknown }).type === 'string';\n\n/** Reads a declared state node. The own-property guard keeps prototype keys such as\n * `constructor` or `__proto__` from reading as declared states. */\nconst nodeFor = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n state: State,\n) => (Object.hasOwn(definition.states, state) ? definition.states[state] : invalidSnapshot(state));\n\nconst assertSnapshot = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n snapshot: MachineSnapshot<State, Context>,\n): void => {\n if (!isContextRecord(snapshot.context)) {\n throw new ClockworkSnapshotError('snapshot context must be a non-array object record', {});\n }\n\n nodeFor(definition, snapshot.state);\n};\n\nconst selectTransition = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n snapshot: MachineSnapshot<State, Context>,\n runtimeEvent: RuntimeEvent<State, Context, Event>,\n): SelectedTransition<State, Context, Event> | undefined => {\n assertSnapshot(definition, snapshot);\n const node = nodeFor(definition, snapshot.state);\n\n if (runtimeEvent.kind === 'after') {\n if (!node.after || !node.after.includes(runtimeEvent.after)) return undefined;\n\n if (!runtimeEvent.after.guard || runtimeEvent.after.guard({ context: snapshot.context, event: undefined })) {\n return { event: undefined, transition: runtimeEvent.after as ExecutableTransition<State, Context, Event> };\n }\n\n return undefined;\n }\n\n const on = node.on;\n\n if (!on || !Object.hasOwn(on, runtimeEvent.event.type)) return undefined;\n\n const input = on[runtimeEvent.event.type as EventType<Event>];\n const candidates = Array.isArray(input) ? input : [input];\n\n for (const candidate of candidates) {\n if (!candidate.guard || candidate.guard({ context: snapshot.context, event: runtimeEvent.event })) {\n return { event: runtimeEvent.event, transition: candidate as ExecutableTransition<State, Context, Event> };\n }\n }\n\n return undefined;\n};\n\nconst transition = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n snapshot: MachineSnapshot<State, Context>,\n runtimeEvent: RuntimeEvent<State, Context, Event>,\n): TransitionOutcome<State, Context, Event> => {\n const selected = selectTransition(definition, snapshot, runtimeEvent);\n\n if (!selected) {\n return {\n event: runtimeEvent.kind === 'event' ? runtimeEvent.event : undefined,\n result: { snapshot: normalizeSnapshot(snapshot), type: 'ignored' },\n };\n }\n\n const nextContext = selected.transition.reduce\n ? selected.transition.reduce({ context: snapshot.context, event: selected.event })\n : snapshot.context;\n\n if (!isContextRecord(nextContext)) {\n throw new ClockworkSnapshotError('a reducer must return a non-array object record', {\n state: snapshot.state,\n });\n }\n\n return {\n event: selected.event,\n result: { snapshot: createSnapshot(selected.transition.target, nextContext as Context), type: 'transition' },\n transition: selected.transition,\n };\n};\n\nconst canTransition = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n snapshot: MachineSnapshot<State, Context>,\n event: Event,\n): boolean => selectTransition(definition, snapshot, { event, kind: 'event' }) !== undefined;\n\nconst createActor = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n initialSnapshot: MachineSnapshot<State, Context>,\n options: ActorOptions<State, Context> = {},\n): Actor<State, Context, Event> => {\n const restored = options.snapshot ?? initialSnapshot;\n\n assertSnapshot(definition, restored);\n let current = createSnapshot(restored.state, restored.context as Context);\n\n const listeners = new Set<(snapshot: MachineSnapshot<State, Context>) => void>();\n const tappers = tapper<ActorTapEvent<State, Context, Event>>();\n const disposal = new AbortController();\n const timers = new Set<ReturnType<typeof setTimeout>>();\n const invokes = new Set<AbortController>();\n const queue: RuntimeEvent<State, Context, Event>[] = [];\n let disposed = false;\n let processing = false;\n\n const cancelStateResources = (): void => {\n for (const timer of timers) clearTimeout(timer);\n timers.clear();\n\n for (const controller of invokes) controller.abort();\n invokes.clear();\n };\n\n const dispose = (): void => {\n if (disposed) return;\n\n disposed = true;\n queue.length = 0;\n cancelStateResources();\n listeners.clear();\n tappers.emit({ type: 'dispose' });\n tappers.clear();\n disposal.abort();\n };\n\n const observeError = (error: unknown, context: ActorErrorContext<State, Event>): void => {\n tappers.emit({ error, event: context.event, phase: context.phase, state: context.state, type: 'error' });\n };\n\n const fail = (error: unknown, context: ActorErrorContext<State, Event>): void => {\n observeError(error, context);\n dispose();\n };\n\n const run = (runtimeEvent: RuntimeEvent<State, Context, Event>): void => {\n if (disposed) return;\n\n if (processing) {\n queue.push(runtimeEvent);\n\n return;\n }\n\n processing = true;\n\n try {\n process(runtimeEvent);\n flush();\n } finally {\n processing = false;\n }\n };\n\n const send = (event: Event): void => {\n if (disposed) return;\n\n if (!isMachineEvent(event)) {\n warn('ignored malformed event; expected an object with a string `type`');\n\n return;\n }\n\n run({ event, kind: 'event' });\n };\n\n const runEffects = (effects: readonly Effect<Context, Event>[], state: State, event: Event | undefined): void => {\n for (const effect of effects) {\n if (disposed) return;\n\n try {\n effect({ context: current.context, event, send, signal: disposal.signal });\n } catch (error) {\n fail(error, { event, phase: 'effect', state });\n }\n }\n };\n\n const establishStateResources = (state: State, event: Event | undefined): void => {\n const node = nodeFor(definition, state);\n\n for (const after of node.after ?? []) {\n const timer = setTimeout(() => {\n timers.delete(timer);\n run({ after, kind: 'after' });\n }, after.delay);\n\n timers.add(timer);\n }\n\n for (const invoke of node.invoke ?? []) {\n const controller = new AbortController();\n\n invokes.add(controller);\n\n const capturedContext = current.context;\n const capturedEvent = event;\n\n void Promise.resolve()\n .then(() => invoke.src({ context: capturedContext, event: capturedEvent, signal: controller.signal }))\n .then(\n (result) => {\n invokes.delete(controller);\n\n if (disposed || controller.signal.aborted || !invoke.onDone) return;\n\n try {\n send(invoke.onDone({ context: capturedContext, result }));\n } catch (error) {\n fail(error, { event: capturedEvent, phase: 'invoke', state });\n }\n },\n (error: unknown) => {\n invokes.delete(controller);\n\n if (disposed || controller.signal.aborted) return;\n\n try {\n if (invoke.onError) {\n send(invoke.onError({ context: capturedContext, error }));\n } else {\n fail(error, { event: capturedEvent, phase: 'invoke', state });\n }\n } catch (callbackError) {\n fail(callbackError, { event: capturedEvent, phase: 'invoke', state });\n }\n },\n );\n }\n };\n\n const notify = (event: Event | undefined): void => {\n for (const listener of [...listeners]) {\n if (disposed) return;\n\n try {\n listener(current);\n } catch (error) {\n observeError(error, { event, phase: 'subscriber', state: current.state });\n }\n }\n };\n\n const process = (runtimeEvent: RuntimeEvent<State, Context, Event>): void => {\n const previous = current;\n let outcome: TransitionOutcome<State, Context, Event>;\n\n try {\n outcome = transition(definition, current, runtimeEvent);\n } catch (error) {\n fail(error, {\n event: runtimeEvent.kind === 'event' ? runtimeEvent.event : undefined,\n phase: 'transition',\n state: current.state,\n });\n\n return;\n }\n\n if (outcome.result.type === 'ignored' || !outcome.transition) {\n tappers.emit({ event: outcome.event, snapshot: outcome.result.snapshot, type: 'ignored' });\n return;\n }\n\n const source = nodeFor(definition, previous.state);\n\n current = outcome.result.snapshot;\n tappers.emit({ event: outcome.event, snapshot: current, type: 'transition' });\n cancelStateResources();\n establishStateResources(current.state, outcome.event);\n notify(outcome.event);\n runEffects(source.exit ?? [], previous.state, outcome.event);\n runEffects(outcome.transition.effects ?? [], previous.state, outcome.event);\n runEffects(nodeFor(definition, current.state).entry ?? [], current.state, outcome.event);\n };\n\n const flush = (): void => {\n let transitions = 0;\n\n while (queue.length > 0 && !disposed) {\n transitions += 1;\n\n if (transitions > MAX_TRANSITIONS) {\n fail(\n new ClockworkTransitionLimitError('maximum queued transitions exceeded', { maxTransitions: MAX_TRANSITIONS }),\n {\n phase: 'transition',\n state: current.state,\n },\n );\n\n return;\n }\n\n const next = queue.shift();\n\n if (next) process(next);\n }\n };\n\n establishStateResources(current.state, undefined);\n\n if (!options.snapshot) {\n runEffects(nodeFor(definition, current.state).entry ?? [], current.state, undefined);\n }\n\n return {\n can: (event) => {\n if (disposed) return false;\n\n try {\n if (!isMachineEvent(event)) {\n warn('ignored malformed event; expected an object with a string `type`');\n return false;\n }\n\n return canTransition(definition, current, event);\n } catch (error) {\n fail(error, { event, phase: 'transition', state: current.state });\n return false;\n }\n },\n get disposalSignal() {\n return disposal.signal;\n },\n dispose,\n get disposed() {\n return disposed;\n },\n send,\n get snapshot() {\n return current;\n },\n subscribe(listener) {\n if (disposed) return () => undefined;\n\n listeners.add(listener);\n\n return () => listeners.delete(listener);\n },\n tap(handler, tapOptions) {\n if (disposed) return () => undefined;\n\n return tappers.tap(handler, tapOptions);\n },\n [Symbol.dispose]: dispose,\n };\n};\n\n/** Defines a typed flat finite-state machine. */\nexport const defineMachine =\n <Context extends Record<string, unknown> = Record<string, never>, Event extends MachineEvent = MachineEvent>() =>\n <State extends string>(definition: MachineConfig<State, Context, Event>): Machine<State, Context, Event> => {\n assertDefinition(definition);\n const context = (definition as { readonly context?: Context }).context ?? ({} as Context);\n const initialSnapshot = createSnapshot(definition.initial, context);\n\n return {\n can: (snapshot, event) => canTransition(definition, snapshot, event),\n createActor: (options) => createActor(definition, initialSnapshot, options),\n initialSnapshot,\n transition: (snapshot, event) => transition(definition, snapshot, { event, kind: 'event' }).result,\n };\n };\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"clockwork.cjs","names":[],"sources":["../src/errors.ts","../src/_dev.ts","../src/interpret.ts"],"sourcesContent":["/** Base class for every Clockwork failure. */\nexport class ClockworkError extends Error {\n readonly details: Readonly<Record<string, unknown>>;\n\n constructor(message: string, details: Record<string, unknown> = {}, opts?: ErrorOptions) {\n super(message, opts);\n this.name = new.target.name;\n this.details = Object.freeze({ ...details });\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** The machine definition failed validation at `defineMachine()` time. */\nexport class ClockworkDefinitionError extends ClockworkError {}\n\n/** A snapshot, its context, or a reducer result failed validation. */\nexport class ClockworkSnapshotError extends ClockworkError {}\n\n/** An actor exceeded the fixed queued-transition limit and disposed itself. */\nexport class ClockworkTransitionLimitError extends ClockworkError {}\n","const isDev = !(globalThis as { __CLOCKWORK_PROD__?: boolean }).__CLOCKWORK_PROD__;\n\nexport function warn(msg: string): void {\n if (isDev) console.warn(`[@vielzeug/clockwork] ${msg}`);\n}\n","import { tapper } from '@vielzeug/arsenal';\nimport { warn } from './_dev.js';\nimport { ClockworkDefinitionError, ClockworkSnapshotError, ClockworkTransitionLimitError } from './errors.js';\nimport type {\n Actor,\n ActorErrorContext,\n ActorOptions,\n ActorTapEvent,\n After,\n Effect,\n EventType,\n Machine,\n MachineConfig,\n MachineEvent,\n MachineSnapshot,\n StateNode,\n TransitionResult,\n} from './types.js';\n\nconst MAX_TIMER_MS = 2_147_483_647;\nconst MAX_TRANSITIONS = 1_000;\n\nconst isContextRecord = (value: unknown): value is Record<string, unknown> => {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return false;\n\n const prototype = Object.getPrototypeOf(value);\n\n return prototype === null || prototype === Object.prototype;\n};\n\n/** Fails fast on the definition footguns the type system cannot express: out-of-range\n * timer delays (platform timers fire immediately above 2^31 ms), empty transition\n * arrays, and a context that is not a plain record. Everything else: declared\n * targets, callback shapes, state keys: is compiler-checked in the typed definition. */\nconst assertDefinition = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n): void => {\n const context = (definition as { readonly context?: Context }).context;\n\n if (context !== undefined && !isContextRecord(context)) {\n throw new ClockworkDefinitionError('machine context must be a non-array object record', {});\n }\n\n for (const [state, node] of Object.entries(definition.states) as [string, StateNode<State, Context, Event>][]) {\n for (const [type, input] of Object.entries(node.on ?? {})) {\n if (Array.isArray(input) && input.length === 0) {\n throw new ClockworkDefinitionError('a transition array must not be empty', { state, type });\n }\n }\n\n for (const [index, after] of (node.after ?? []).entries()) {\n if (!Number.isFinite(after.delay) || after.delay < 0 || after.delay > MAX_TIMER_MS) {\n throw new ClockworkDefinitionError(`state \"${state}\" after delay must be between 0 and ${MAX_TIMER_MS}`, {\n delay: after.delay,\n index,\n state,\n });\n }\n }\n }\n};\n\ntype InternalEvent<State extends string, Context extends Record<string, unknown>, Event extends MachineEvent> = {\n readonly after: After<State, Context, Event>;\n readonly kind: 'after';\n};\n\ntype RuntimeEvent<State extends string, Context extends Record<string, unknown>, Event extends MachineEvent> =\n | { readonly event: Event; readonly kind: 'event' }\n | InternalEvent<State, Context, Event>;\n\n/** A transition or delayed transition selected for execution. The reducer's event\n * parameter is whatever the selector matched: the event for a user transition,\n * `undefined` for a timer, which the declared per-type signatures cannot express. */\ntype ExecutableTransition<State extends string, Context extends Record<string, unknown>, Event extends MachineEvent> = {\n readonly effects?: readonly Effect<Context, Event>[];\n readonly reduce?: (args: { readonly context: Readonly<Context>; readonly event: Event | undefined }) => Context;\n readonly target: State;\n};\n\ntype SelectedTransition<State extends string, Context extends Record<string, unknown>, Event extends MachineEvent> = {\n readonly event: Event | undefined;\n readonly transition: ExecutableTransition<State, Context, Event>;\n};\n\ntype TransitionOutcome<State extends string, Context extends Record<string, unknown>, Event extends MachineEvent> = {\n readonly event: Event | undefined;\n readonly result: TransitionResult<State, Context>;\n readonly transition?: ExecutableTransition<State, Context, Event>;\n};\n\nconst createSnapshot = <State extends string, Context extends Record<string, unknown>>(\n state: State,\n context: Context,\n): MachineSnapshot<State, Context> => {\n const cloned = Object.assign(Object.create(Object.getPrototypeOf(context)) as Context, context);\n\n return Object.freeze({ context: Object.freeze(cloned), state });\n};\n\nconst normalizeSnapshot = <State extends string, Context extends Record<string, unknown>>(\n snapshot: MachineSnapshot<State, Context>,\n): MachineSnapshot<State, Context> =>\n Object.isFrozen(snapshot) && Object.isFrozen(snapshot.context)\n ? snapshot\n : createSnapshot(snapshot.state, snapshot.context as Context);\n\nconst invalidSnapshot = (state: unknown): never => {\n throw new ClockworkSnapshotError(`snapshot state \"${String(state)}\" is not declared`, { state });\n};\n\nconst isMachineEvent = (event: unknown): event is MachineEvent =>\n typeof event === 'object' && event !== null && typeof (event as { type?: unknown }).type === 'string';\n\n/** Reads a declared state node. The own-property guard keeps prototype keys such as\n * `constructor` or `__proto__` from reading as declared states. */\nconst nodeFor = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n state: State,\n) => (Object.hasOwn(definition.states, state) ? definition.states[state] : invalidSnapshot(state));\n\nconst assertSnapshot = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n snapshot: MachineSnapshot<State, Context>,\n): void => {\n if (!isContextRecord(snapshot.context)) {\n throw new ClockworkSnapshotError('snapshot context must be a non-array object record', {});\n }\n\n nodeFor(definition, snapshot.state);\n};\n\nconst selectTransition = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n snapshot: MachineSnapshot<State, Context>,\n runtimeEvent: RuntimeEvent<State, Context, Event>,\n): SelectedTransition<State, Context, Event> | undefined => {\n assertSnapshot(definition, snapshot);\n const node = nodeFor(definition, snapshot.state);\n\n if (runtimeEvent.kind === 'after') {\n if (!node.after || !node.after.includes(runtimeEvent.after)) return undefined;\n\n if (!runtimeEvent.after.guard || runtimeEvent.after.guard({ context: snapshot.context, event: undefined })) {\n return { event: undefined, transition: runtimeEvent.after as ExecutableTransition<State, Context, Event> };\n }\n\n return undefined;\n }\n\n const on = node.on;\n\n if (!on || !Object.hasOwn(on, runtimeEvent.event.type)) return undefined;\n\n const input = on[runtimeEvent.event.type as EventType<Event>];\n const candidates = Array.isArray(input) ? input : [input];\n\n for (const candidate of candidates) {\n if (!candidate.guard || candidate.guard({ context: snapshot.context, event: runtimeEvent.event })) {\n return { event: runtimeEvent.event, transition: candidate as ExecutableTransition<State, Context, Event> };\n }\n }\n\n return undefined;\n};\n\nconst transition = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n snapshot: MachineSnapshot<State, Context>,\n runtimeEvent: RuntimeEvent<State, Context, Event>,\n): TransitionOutcome<State, Context, Event> => {\n const selected = selectTransition(definition, snapshot, runtimeEvent);\n\n if (!selected) {\n return {\n event: runtimeEvent.kind === 'event' ? runtimeEvent.event : undefined,\n result: { snapshot: normalizeSnapshot(snapshot), type: 'ignored' },\n };\n }\n\n const nextContext = selected.transition.reduce\n ? selected.transition.reduce({ context: snapshot.context, event: selected.event })\n : snapshot.context;\n\n if (!isContextRecord(nextContext)) {\n throw new ClockworkSnapshotError('a reducer must return a non-array object record', {\n state: snapshot.state,\n });\n }\n\n return {\n event: selected.event,\n result: { snapshot: createSnapshot(selected.transition.target, nextContext as Context), type: 'transition' },\n transition: selected.transition,\n };\n};\n\nconst canTransition = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n snapshot: MachineSnapshot<State, Context>,\n event: Event,\n): boolean => selectTransition(definition, snapshot, { event, kind: 'event' }) !== undefined;\n\nconst createActor = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n initialSnapshot: MachineSnapshot<State, Context>,\n options: ActorOptions<State, Context> = {},\n): Actor<State, Context, Event> => {\n const restored = options.snapshot ?? initialSnapshot;\n\n assertSnapshot(definition, restored);\n let current = createSnapshot(restored.state, restored.context as Context);\n\n const listeners = new Set<(snapshot: MachineSnapshot<State, Context>) => void>();\n const tappers = tapper<ActorTapEvent<State, Context, Event>>();\n const disposal = new AbortController();\n const timers = new Set<ReturnType<typeof setTimeout>>();\n const invokes = new Set<AbortController>();\n const queue: RuntimeEvent<State, Context, Event>[] = [];\n let disposed = false;\n let processing = false;\n\n const cancelStateResources = (): void => {\n for (const timer of timers) clearTimeout(timer);\n timers.clear();\n\n for (const controller of invokes) controller.abort();\n invokes.clear();\n };\n\n const dispose = (): void => {\n if (disposed) return;\n\n disposed = true;\n queue.length = 0;\n cancelStateResources();\n listeners.clear();\n tappers.emit({ type: 'dispose' });\n tappers.clear();\n disposal.abort();\n };\n\n const observeError = (error: unknown, context: ActorErrorContext<State, Event>): void => {\n tappers.emit({ error, event: context.event, phase: context.phase, state: context.state, type: 'error' });\n };\n\n const fail = (error: unknown, context: ActorErrorContext<State, Event>): void => {\n observeError(error, context);\n dispose();\n };\n\n const run = (runtimeEvent: RuntimeEvent<State, Context, Event>): void => {\n if (disposed) return;\n\n if (processing) {\n queue.push(runtimeEvent);\n\n return;\n }\n\n processing = true;\n\n try {\n process(runtimeEvent);\n flush();\n } finally {\n processing = false;\n }\n };\n\n const send = (event: Event): void => {\n if (disposed) return;\n\n if (!isMachineEvent(event)) {\n warn('ignored malformed event; expected an object with a string `type`');\n\n return;\n }\n\n run({ event, kind: 'event' });\n };\n\n const runEffects = (effects: readonly Effect<Context, Event>[], state: State, event: Event | undefined): void => {\n for (const effect of effects) {\n if (disposed) return;\n\n try {\n effect({ context: current.context, event, send, signal: disposal.signal });\n } catch (error) {\n fail(error, { event, phase: 'effect', state });\n }\n }\n };\n\n const establishStateResources = (state: State, event: Event | undefined): void => {\n const node = nodeFor(definition, state);\n\n for (const after of node.after ?? []) {\n const timer = setTimeout(() => {\n timers.delete(timer);\n run({ after, kind: 'after' });\n }, after.delay);\n\n timers.add(timer);\n }\n\n for (const invoke of node.invoke ?? []) {\n const controller = new AbortController();\n\n invokes.add(controller);\n\n const capturedContext = current.context;\n const capturedEvent = event;\n\n void Promise.resolve()\n .then(() => invoke.src({ context: capturedContext, event: capturedEvent, signal: controller.signal }))\n .then(\n (result) => {\n invokes.delete(controller);\n\n if (disposed || controller.signal.aborted || !invoke.onDone) return;\n\n try {\n send(invoke.onDone({ context: capturedContext, result }));\n } catch (error) {\n fail(error, { event: capturedEvent, phase: 'invoke', state });\n }\n },\n (error: unknown) => {\n invokes.delete(controller);\n\n if (disposed || controller.signal.aborted) return;\n\n try {\n if (invoke.onError) {\n send(invoke.onError({ context: capturedContext, error }));\n } else {\n fail(error, { event: capturedEvent, phase: 'invoke', state });\n }\n } catch (callbackError) {\n fail(callbackError, { event: capturedEvent, phase: 'invoke', state });\n }\n },\n );\n }\n };\n\n const notify = (event: Event | undefined): void => {\n for (const listener of [...listeners]) {\n if (disposed) return;\n\n try {\n listener(current);\n } catch (error) {\n observeError(error, { event, phase: 'subscriber', state: current.state });\n }\n }\n };\n\n const process = (runtimeEvent: RuntimeEvent<State, Context, Event>): void => {\n const previous = current;\n let outcome: TransitionOutcome<State, Context, Event>;\n\n try {\n outcome = transition(definition, current, runtimeEvent);\n } catch (error) {\n fail(error, {\n event: runtimeEvent.kind === 'event' ? runtimeEvent.event : undefined,\n phase: 'transition',\n state: current.state,\n });\n\n return;\n }\n\n if (outcome.result.type === 'ignored' || !outcome.transition) {\n tappers.emit({ event: outcome.event, snapshot: outcome.result.snapshot, type: 'ignored' });\n return;\n }\n\n const source = nodeFor(definition, previous.state);\n\n current = outcome.result.snapshot;\n tappers.emit({ event: outcome.event, snapshot: current, type: 'transition' });\n cancelStateResources();\n establishStateResources(current.state, outcome.event);\n notify(outcome.event);\n runEffects(source.exit ?? [], previous.state, outcome.event);\n runEffects(outcome.transition.effects ?? [], previous.state, outcome.event);\n runEffects(nodeFor(definition, current.state).entry ?? [], current.state, outcome.event);\n };\n\n const flush = (): void => {\n let transitions = 0;\n\n while (queue.length > 0 && !disposed) {\n transitions += 1;\n\n if (transitions > MAX_TRANSITIONS) {\n fail(\n new ClockworkTransitionLimitError('maximum queued transitions exceeded', { maxTransitions: MAX_TRANSITIONS }),\n {\n phase: 'transition',\n state: current.state,\n },\n );\n\n return;\n }\n\n const next = queue.shift();\n\n if (next) process(next);\n }\n };\n\n establishStateResources(current.state, undefined);\n\n if (!options.snapshot) {\n runEffects(nodeFor(definition, current.state).entry ?? [], current.state, undefined);\n }\n\n return {\n can: (event) => {\n if (disposed) return false;\n\n try {\n if (!isMachineEvent(event)) {\n warn('ignored malformed event; expected an object with a string `type`');\n return false;\n }\n\n return canTransition(definition, current, event);\n } catch (error) {\n fail(error, { event, phase: 'transition', state: current.state });\n return false;\n }\n },\n get disposalSignal() {\n return disposal.signal;\n },\n dispose,\n get disposed() {\n return disposed;\n },\n send,\n get snapshot() {\n return current;\n },\n subscribe(listener) {\n if (disposed) return () => undefined;\n\n listeners.add(listener);\n\n return () => listeners.delete(listener);\n },\n tap(handler, tapOptions) {\n if (disposed) return () => undefined;\n\n return tappers.tap(handler, tapOptions);\n },\n [Symbol.dispose]: dispose,\n };\n};\n\n/** Defines a typed flat finite-state machine. */\nexport const defineMachine =\n <Context extends Record<string, unknown> = Record<string, never>, Event extends MachineEvent = MachineEvent>() =>\n <State extends string>(definition: MachineConfig<State, Context, Event>): Machine<State, Context, Event> => {\n assertDefinition(definition);\n const context = (definition as { readonly context?: Context }).context ?? ({} as Context);\n const initialSnapshot = createSnapshot(definition.initial, context);\n\n return {\n can: (snapshot, event) => canTransition(definition, snapshot, event),\n createActor: (options) => createActor(definition, initialSnapshot, options),\n initialSnapshot,\n transition: (snapshot, event) => transition(definition, snapshot, { event, kind: 'event' }).result,\n };\n };\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"clockwork.iife.js","names":[],"sources":["../src/errors.ts","../src/_dev.ts","../src/interpret.ts"],"sourcesContent":["/** Base class for every Clockwork failure. */\nexport class ClockworkError extends Error {\n readonly details: Readonly<Record<string, unknown>>;\n\n constructor(message: string, details: Record<string, unknown> = {}, opts?: ErrorOptions) {\n super(message, opts);\n this.name = new.target.name;\n this.details = Object.freeze({ ...details });\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** The machine definition failed validation at `defineMachine()` time. */\nexport class ClockworkDefinitionError extends ClockworkError {}\n\n/** A snapshot, its context, or a reducer result failed validation. */\nexport class ClockworkSnapshotError extends ClockworkError {}\n\n/** An actor exceeded the fixed queued-transition limit and disposed itself. */\nexport class ClockworkTransitionLimitError extends ClockworkError {}\n","const isDev = !(globalThis as { __CLOCKWORK_PROD__?: boolean }).__CLOCKWORK_PROD__;\n\nexport function warn(msg: string): void {\n if (isDev) console.warn(`[@vielzeug/clockwork] ${msg}`);\n}\n","import { tapper } from '@vielzeug/arsenal';\nimport { warn } from './_dev.js';\nimport { ClockworkDefinitionError, ClockworkSnapshotError, ClockworkTransitionLimitError } from './errors.js';\nimport type {\n Actor,\n ActorErrorContext,\n ActorOptions,\n ActorTapEvent,\n After,\n Effect,\n EventType,\n Machine,\n MachineConfig,\n MachineEvent,\n MachineSnapshot,\n StateNode,\n TransitionResult,\n} from './types.js';\n\nconst MAX_TIMER_MS = 2_147_483_647;\nconst MAX_TRANSITIONS = 1_000;\n\nconst isContextRecord = (value: unknown): value is Record<string, unknown> => {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return false;\n\n const prototype = Object.getPrototypeOf(value);\n\n return prototype === null || prototype === Object.prototype;\n};\n\n/** Fails fast on the definition footguns the type system cannot express: out-of-range\n * timer delays (platform timers fire immediately above 2^31 ms), empty transition\n * arrays, and a context that is not a plain record. Everything else — declared\n * targets, callback shapes, state keys — is compiler-checked in the typed definition. */\nconst assertDefinition = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n): void => {\n const context = (definition as { readonly context?: Context }).context;\n\n if (context !== undefined && !isContextRecord(context)) {\n throw new ClockworkDefinitionError('machine context must be a non-array object record', {});\n }\n\n for (const [state, node] of Object.entries(definition.states) as [string, StateNode<State, Context, Event>][]) {\n for (const [type, input] of Object.entries(node.on ?? {})) {\n if (Array.isArray(input) && input.length === 0) {\n throw new ClockworkDefinitionError('a transition array must not be empty', { state, type });\n }\n }\n\n for (const [index, after] of (node.after ?? []).entries()) {\n if (!Number.isFinite(after.delay) || after.delay < 0 || after.delay > MAX_TIMER_MS) {\n throw new ClockworkDefinitionError(`state \"${state}\" after delay must be between 0 and ${MAX_TIMER_MS}`, {\n delay: after.delay,\n index,\n state,\n });\n }\n }\n }\n};\n\ntype InternalEvent<State extends string, Context extends Record<string, unknown>, Event extends MachineEvent> = {\n readonly after: After<State, Context, Event>;\n readonly kind: 'after';\n};\n\ntype RuntimeEvent<State extends string, Context extends Record<string, unknown>, Event extends MachineEvent> =\n | { readonly event: Event; readonly kind: 'event' }\n | InternalEvent<State, Context, Event>;\n\n/** A transition or delayed transition selected for execution. The reducer's event\n * parameter is whatever the selector matched — the event for a user transition,\n * `undefined` for a timer — which the declared per-type signatures cannot express. */\ntype ExecutableTransition<State extends string, Context extends Record<string, unknown>, Event extends MachineEvent> = {\n readonly effects?: readonly Effect<Context, Event>[];\n readonly reduce?: (args: { readonly context: Readonly<Context>; readonly event: Event | undefined }) => Context;\n readonly target: State;\n};\n\ntype SelectedTransition<State extends string, Context extends Record<string, unknown>, Event extends MachineEvent> = {\n readonly event: Event | undefined;\n readonly transition: ExecutableTransition<State, Context, Event>;\n};\n\ntype TransitionOutcome<State extends string, Context extends Record<string, unknown>, Event extends MachineEvent> = {\n readonly event: Event | undefined;\n readonly result: TransitionResult<State, Context>;\n readonly transition?: ExecutableTransition<State, Context, Event>;\n};\n\nconst createSnapshot = <State extends string, Context extends Record<string, unknown>>(\n state: State,\n context: Context,\n): MachineSnapshot<State, Context> => {\n const cloned = Object.assign(Object.create(Object.getPrototypeOf(context)) as Context, context);\n\n return Object.freeze({ context: Object.freeze(cloned), state });\n};\n\nconst normalizeSnapshot = <State extends string, Context extends Record<string, unknown>>(\n snapshot: MachineSnapshot<State, Context>,\n): MachineSnapshot<State, Context> =>\n Object.isFrozen(snapshot) && Object.isFrozen(snapshot.context)\n ? snapshot\n : createSnapshot(snapshot.state, snapshot.context as Context);\n\nconst invalidSnapshot = (state: unknown): never => {\n throw new ClockworkSnapshotError(`snapshot state \"${String(state)}\" is not declared`, { state });\n};\n\nconst isMachineEvent = (event: unknown): event is MachineEvent =>\n typeof event === 'object' && event !== null && typeof (event as { type?: unknown }).type === 'string';\n\n/** Reads a declared state node. The own-property guard keeps prototype keys such as\n * `constructor` or `__proto__` from reading as declared states. */\nconst nodeFor = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n state: State,\n) => (Object.hasOwn(definition.states, state) ? definition.states[state] : invalidSnapshot(state));\n\nconst assertSnapshot = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n snapshot: MachineSnapshot<State, Context>,\n): void => {\n if (!isContextRecord(snapshot.context)) {\n throw new ClockworkSnapshotError('snapshot context must be a non-array object record', {});\n }\n\n nodeFor(definition, snapshot.state);\n};\n\nconst selectTransition = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n snapshot: MachineSnapshot<State, Context>,\n runtimeEvent: RuntimeEvent<State, Context, Event>,\n): SelectedTransition<State, Context, Event> | undefined => {\n assertSnapshot(definition, snapshot);\n const node = nodeFor(definition, snapshot.state);\n\n if (runtimeEvent.kind === 'after') {\n if (!node.after || !node.after.includes(runtimeEvent.after)) return undefined;\n\n if (!runtimeEvent.after.guard || runtimeEvent.after.guard({ context: snapshot.context, event: undefined })) {\n return { event: undefined, transition: runtimeEvent.after as ExecutableTransition<State, Context, Event> };\n }\n\n return undefined;\n }\n\n const on = node.on;\n\n if (!on || !Object.hasOwn(on, runtimeEvent.event.type)) return undefined;\n\n const input = on[runtimeEvent.event.type as EventType<Event>];\n const candidates = Array.isArray(input) ? input : [input];\n\n for (const candidate of candidates) {\n if (!candidate.guard || candidate.guard({ context: snapshot.context, event: runtimeEvent.event })) {\n return { event: runtimeEvent.event, transition: candidate as ExecutableTransition<State, Context, Event> };\n }\n }\n\n return undefined;\n};\n\nconst transition = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n snapshot: MachineSnapshot<State, Context>,\n runtimeEvent: RuntimeEvent<State, Context, Event>,\n): TransitionOutcome<State, Context, Event> => {\n const selected = selectTransition(definition, snapshot, runtimeEvent);\n\n if (!selected) {\n return {\n event: runtimeEvent.kind === 'event' ? runtimeEvent.event : undefined,\n result: { snapshot: normalizeSnapshot(snapshot), type: 'ignored' },\n };\n }\n\n const nextContext = selected.transition.reduce\n ? selected.transition.reduce({ context: snapshot.context, event: selected.event })\n : snapshot.context;\n\n if (!isContextRecord(nextContext)) {\n throw new ClockworkSnapshotError('a reducer must return a non-array object record', {\n state: snapshot.state,\n });\n }\n\n return {\n event: selected.event,\n result: { snapshot: createSnapshot(selected.transition.target, nextContext as Context), type: 'transition' },\n transition: selected.transition,\n };\n};\n\nconst canTransition = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n snapshot: MachineSnapshot<State, Context>,\n event: Event,\n): boolean => selectTransition(definition, snapshot, { event, kind: 'event' }) !== undefined;\n\nconst createActor = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n initialSnapshot: MachineSnapshot<State, Context>,\n options: ActorOptions<State, Context> = {},\n): Actor<State, Context, Event> => {\n const restored = options.snapshot ?? initialSnapshot;\n\n assertSnapshot(definition, restored);\n let current = createSnapshot(restored.state, restored.context as Context);\n\n const listeners = new Set<(snapshot: MachineSnapshot<State, Context>) => void>();\n const tappers = tapper<ActorTapEvent<State, Context, Event>>();\n const disposal = new AbortController();\n const timers = new Set<ReturnType<typeof setTimeout>>();\n const invokes = new Set<AbortController>();\n const queue: RuntimeEvent<State, Context, Event>[] = [];\n let disposed = false;\n let processing = false;\n\n const cancelStateResources = (): void => {\n for (const timer of timers) clearTimeout(timer);\n timers.clear();\n\n for (const controller of invokes) controller.abort();\n invokes.clear();\n };\n\n const dispose = (): void => {\n if (disposed) return;\n\n disposed = true;\n queue.length = 0;\n cancelStateResources();\n listeners.clear();\n tappers.emit({ type: 'dispose' });\n tappers.clear();\n disposal.abort();\n };\n\n const observeError = (error: unknown, context: ActorErrorContext<State, Event>): void => {\n tappers.emit({ error, event: context.event, phase: context.phase, state: context.state, type: 'error' });\n };\n\n const fail = (error: unknown, context: ActorErrorContext<State, Event>): void => {\n observeError(error, context);\n dispose();\n };\n\n const run = (runtimeEvent: RuntimeEvent<State, Context, Event>): void => {\n if (disposed) return;\n\n if (processing) {\n queue.push(runtimeEvent);\n\n return;\n }\n\n processing = true;\n\n try {\n process(runtimeEvent);\n flush();\n } finally {\n processing = false;\n }\n };\n\n const send = (event: Event): void => {\n if (disposed) return;\n\n if (!isMachineEvent(event)) {\n warn('ignored malformed event; expected an object with a string `type`');\n\n return;\n }\n\n run({ event, kind: 'event' });\n };\n\n const runEffects = (effects: readonly Effect<Context, Event>[], state: State, event: Event | undefined): void => {\n for (const effect of effects) {\n if (disposed) return;\n\n try {\n effect({ context: current.context, event, send, signal: disposal.signal });\n } catch (error) {\n fail(error, { event, phase: 'effect', state });\n }\n }\n };\n\n const establishStateResources = (state: State, event: Event | undefined): void => {\n const node = nodeFor(definition, state);\n\n for (const after of node.after ?? []) {\n const timer = setTimeout(() => {\n timers.delete(timer);\n run({ after, kind: 'after' });\n }, after.delay);\n\n timers.add(timer);\n }\n\n for (const invoke of node.invoke ?? []) {\n const controller = new AbortController();\n\n invokes.add(controller);\n\n const capturedContext = current.context;\n const capturedEvent = event;\n\n void Promise.resolve()\n .then(() => invoke.src({ context: capturedContext, event: capturedEvent, signal: controller.signal }))\n .then(\n (result) => {\n invokes.delete(controller);\n\n if (disposed || controller.signal.aborted || !invoke.onDone) return;\n\n try {\n send(invoke.onDone({ context: capturedContext, result }));\n } catch (error) {\n fail(error, { event: capturedEvent, phase: 'invoke', state });\n }\n },\n (error: unknown) => {\n invokes.delete(controller);\n\n if (disposed || controller.signal.aborted) return;\n\n try {\n if (invoke.onError) {\n send(invoke.onError({ context: capturedContext, error }));\n } else {\n fail(error, { event: capturedEvent, phase: 'invoke', state });\n }\n } catch (callbackError) {\n fail(callbackError, { event: capturedEvent, phase: 'invoke', state });\n }\n },\n );\n }\n };\n\n const notify = (event: Event | undefined): void => {\n for (const listener of [...listeners]) {\n if (disposed) return;\n\n try {\n listener(current);\n } catch (error) {\n observeError(error, { event, phase: 'subscriber', state: current.state });\n }\n }\n };\n\n const process = (runtimeEvent: RuntimeEvent<State, Context, Event>): void => {\n const previous = current;\n let outcome: TransitionOutcome<State, Context, Event>;\n\n try {\n outcome = transition(definition, current, runtimeEvent);\n } catch (error) {\n fail(error, {\n event: runtimeEvent.kind === 'event' ? runtimeEvent.event : undefined,\n phase: 'transition',\n state: current.state,\n });\n\n return;\n }\n\n if (outcome.result.type === 'ignored' || !outcome.transition) {\n tappers.emit({ event: outcome.event, snapshot: outcome.result.snapshot, type: 'ignored' });\n return;\n }\n\n const source = nodeFor(definition, previous.state);\n\n current = outcome.result.snapshot;\n tappers.emit({ event: outcome.event, snapshot: current, type: 'transition' });\n cancelStateResources();\n establishStateResources(current.state, outcome.event);\n notify(outcome.event);\n runEffects(source.exit ?? [], previous.state, outcome.event);\n runEffects(outcome.transition.effects ?? [], previous.state, outcome.event);\n runEffects(nodeFor(definition, current.state).entry ?? [], current.state, outcome.event);\n };\n\n const flush = (): void => {\n let transitions = 0;\n\n while (queue.length > 0 && !disposed) {\n transitions += 1;\n\n if (transitions > MAX_TRANSITIONS) {\n fail(\n new ClockworkTransitionLimitError('maximum queued transitions exceeded', { maxTransitions: MAX_TRANSITIONS }),\n {\n phase: 'transition',\n state: current.state,\n },\n );\n\n return;\n }\n\n const next = queue.shift();\n\n if (next) process(next);\n }\n };\n\n establishStateResources(current.state, undefined);\n\n if (!options.snapshot) {\n runEffects(nodeFor(definition, current.state).entry ?? [], current.state, undefined);\n }\n\n return {\n can: (event) => {\n if (disposed) return false;\n\n try {\n if (!isMachineEvent(event)) {\n warn('ignored malformed event; expected an object with a string `type`');\n return false;\n }\n\n return canTransition(definition, current, event);\n } catch (error) {\n fail(error, { event, phase: 'transition', state: current.state });\n return false;\n }\n },\n get disposalSignal() {\n return disposal.signal;\n },\n dispose,\n get disposed() {\n return disposed;\n },\n send,\n get snapshot() {\n return current;\n },\n subscribe(listener) {\n if (disposed) return () => undefined;\n\n listeners.add(listener);\n\n return () => listeners.delete(listener);\n },\n tap(handler, tapOptions) {\n if (disposed) return () => undefined;\n\n return tappers.tap(handler, tapOptions);\n },\n [Symbol.dispose]: dispose,\n };\n};\n\n/** Defines a typed flat finite-state machine. */\nexport const defineMachine =\n <Context extends Record<string, unknown> = Record<string, never>, Event extends MachineEvent = MachineEvent>() =>\n <State extends string>(definition: MachineConfig<State, Context, Event>): Machine<State, Context, Event> => {\n assertDefinition(definition);\n const context = (definition as { readonly context?: Context }).context ?? ({} as Context);\n const initialSnapshot = createSnapshot(definition.initial, context);\n\n return {\n can: (snapshot, event) => canTransition(definition, snapshot, event),\n createActor: (options) => createActor(definition, initialSnapshot, options),\n initialSnapshot,\n transition: (snapshot, event) => transition(definition, snapshot, { event, kind: 'event' }).result,\n };\n };\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"clockwork.iife.js","names":[],"sources":["../src/errors.ts","../src/_dev.ts","../src/interpret.ts"],"sourcesContent":["/** Base class for every Clockwork failure. */\nexport class ClockworkError extends Error {\n readonly details: Readonly<Record<string, unknown>>;\n\n constructor(message: string, details: Record<string, unknown> = {}, opts?: ErrorOptions) {\n super(message, opts);\n this.name = new.target.name;\n this.details = Object.freeze({ ...details });\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** The machine definition failed validation at `defineMachine()` time. */\nexport class ClockworkDefinitionError extends ClockworkError {}\n\n/** A snapshot, its context, or a reducer result failed validation. */\nexport class ClockworkSnapshotError extends ClockworkError {}\n\n/** An actor exceeded the fixed queued-transition limit and disposed itself. */\nexport class ClockworkTransitionLimitError extends ClockworkError {}\n","const isDev = !(globalThis as { __CLOCKWORK_PROD__?: boolean }).__CLOCKWORK_PROD__;\n\nexport function warn(msg: string): void {\n if (isDev) console.warn(`[@vielzeug/clockwork] ${msg}`);\n}\n","import { tapper } from '@vielzeug/arsenal';\nimport { warn } from './_dev.js';\nimport { ClockworkDefinitionError, ClockworkSnapshotError, ClockworkTransitionLimitError } from './errors.js';\nimport type {\n Actor,\n ActorErrorContext,\n ActorOptions,\n ActorTapEvent,\n After,\n Effect,\n EventType,\n Machine,\n MachineConfig,\n MachineEvent,\n MachineSnapshot,\n StateNode,\n TransitionResult,\n} from './types.js';\n\nconst MAX_TIMER_MS = 2_147_483_647;\nconst MAX_TRANSITIONS = 1_000;\n\nconst isContextRecord = (value: unknown): value is Record<string, unknown> => {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return false;\n\n const prototype = Object.getPrototypeOf(value);\n\n return prototype === null || prototype === Object.prototype;\n};\n\n/** Fails fast on the definition footguns the type system cannot express: out-of-range\n * timer delays (platform timers fire immediately above 2^31 ms), empty transition\n * arrays, and a context that is not a plain record. Everything else: declared\n * targets, callback shapes, state keys: is compiler-checked in the typed definition. */\nconst assertDefinition = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n): void => {\n const context = (definition as { readonly context?: Context }).context;\n\n if (context !== undefined && !isContextRecord(context)) {\n throw new ClockworkDefinitionError('machine context must be a non-array object record', {});\n }\n\n for (const [state, node] of Object.entries(definition.states) as [string, StateNode<State, Context, Event>][]) {\n for (const [type, input] of Object.entries(node.on ?? {})) {\n if (Array.isArray(input) && input.length === 0) {\n throw new ClockworkDefinitionError('a transition array must not be empty', { state, type });\n }\n }\n\n for (const [index, after] of (node.after ?? []).entries()) {\n if (!Number.isFinite(after.delay) || after.delay < 0 || after.delay > MAX_TIMER_MS) {\n throw new ClockworkDefinitionError(`state \"${state}\" after delay must be between 0 and ${MAX_TIMER_MS}`, {\n delay: after.delay,\n index,\n state,\n });\n }\n }\n }\n};\n\ntype InternalEvent<State extends string, Context extends Record<string, unknown>, Event extends MachineEvent> = {\n readonly after: After<State, Context, Event>;\n readonly kind: 'after';\n};\n\ntype RuntimeEvent<State extends string, Context extends Record<string, unknown>, Event extends MachineEvent> =\n | { readonly event: Event; readonly kind: 'event' }\n | InternalEvent<State, Context, Event>;\n\n/** A transition or delayed transition selected for execution. The reducer's event\n * parameter is whatever the selector matched: the event for a user transition,\n * `undefined` for a timer, which the declared per-type signatures cannot express. */\ntype ExecutableTransition<State extends string, Context extends Record<string, unknown>, Event extends MachineEvent> = {\n readonly effects?: readonly Effect<Context, Event>[];\n readonly reduce?: (args: { readonly context: Readonly<Context>; readonly event: Event | undefined }) => Context;\n readonly target: State;\n};\n\ntype SelectedTransition<State extends string, Context extends Record<string, unknown>, Event extends MachineEvent> = {\n readonly event: Event | undefined;\n readonly transition: ExecutableTransition<State, Context, Event>;\n};\n\ntype TransitionOutcome<State extends string, Context extends Record<string, unknown>, Event extends MachineEvent> = {\n readonly event: Event | undefined;\n readonly result: TransitionResult<State, Context>;\n readonly transition?: ExecutableTransition<State, Context, Event>;\n};\n\nconst createSnapshot = <State extends string, Context extends Record<string, unknown>>(\n state: State,\n context: Context,\n): MachineSnapshot<State, Context> => {\n const cloned = Object.assign(Object.create(Object.getPrototypeOf(context)) as Context, context);\n\n return Object.freeze({ context: Object.freeze(cloned), state });\n};\n\nconst normalizeSnapshot = <State extends string, Context extends Record<string, unknown>>(\n snapshot: MachineSnapshot<State, Context>,\n): MachineSnapshot<State, Context> =>\n Object.isFrozen(snapshot) && Object.isFrozen(snapshot.context)\n ? snapshot\n : createSnapshot(snapshot.state, snapshot.context as Context);\n\nconst invalidSnapshot = (state: unknown): never => {\n throw new ClockworkSnapshotError(`snapshot state \"${String(state)}\" is not declared`, { state });\n};\n\nconst isMachineEvent = (event: unknown): event is MachineEvent =>\n typeof event === 'object' && event !== null && typeof (event as { type?: unknown }).type === 'string';\n\n/** Reads a declared state node. The own-property guard keeps prototype keys such as\n * `constructor` or `__proto__` from reading as declared states. */\nconst nodeFor = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n state: State,\n) => (Object.hasOwn(definition.states, state) ? definition.states[state] : invalidSnapshot(state));\n\nconst assertSnapshot = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n snapshot: MachineSnapshot<State, Context>,\n): void => {\n if (!isContextRecord(snapshot.context)) {\n throw new ClockworkSnapshotError('snapshot context must be a non-array object record', {});\n }\n\n nodeFor(definition, snapshot.state);\n};\n\nconst selectTransition = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n snapshot: MachineSnapshot<State, Context>,\n runtimeEvent: RuntimeEvent<State, Context, Event>,\n): SelectedTransition<State, Context, Event> | undefined => {\n assertSnapshot(definition, snapshot);\n const node = nodeFor(definition, snapshot.state);\n\n if (runtimeEvent.kind === 'after') {\n if (!node.after || !node.after.includes(runtimeEvent.after)) return undefined;\n\n if (!runtimeEvent.after.guard || runtimeEvent.after.guard({ context: snapshot.context, event: undefined })) {\n return { event: undefined, transition: runtimeEvent.after as ExecutableTransition<State, Context, Event> };\n }\n\n return undefined;\n }\n\n const on = node.on;\n\n if (!on || !Object.hasOwn(on, runtimeEvent.event.type)) return undefined;\n\n const input = on[runtimeEvent.event.type as EventType<Event>];\n const candidates = Array.isArray(input) ? input : [input];\n\n for (const candidate of candidates) {\n if (!candidate.guard || candidate.guard({ context: snapshot.context, event: runtimeEvent.event })) {\n return { event: runtimeEvent.event, transition: candidate as ExecutableTransition<State, Context, Event> };\n }\n }\n\n return undefined;\n};\n\nconst transition = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n snapshot: MachineSnapshot<State, Context>,\n runtimeEvent: RuntimeEvent<State, Context, Event>,\n): TransitionOutcome<State, Context, Event> => {\n const selected = selectTransition(definition, snapshot, runtimeEvent);\n\n if (!selected) {\n return {\n event: runtimeEvent.kind === 'event' ? runtimeEvent.event : undefined,\n result: { snapshot: normalizeSnapshot(snapshot), type: 'ignored' },\n };\n }\n\n const nextContext = selected.transition.reduce\n ? selected.transition.reduce({ context: snapshot.context, event: selected.event })\n : snapshot.context;\n\n if (!isContextRecord(nextContext)) {\n throw new ClockworkSnapshotError('a reducer must return a non-array object record', {\n state: snapshot.state,\n });\n }\n\n return {\n event: selected.event,\n result: { snapshot: createSnapshot(selected.transition.target, nextContext as Context), type: 'transition' },\n transition: selected.transition,\n };\n};\n\nconst canTransition = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n snapshot: MachineSnapshot<State, Context>,\n event: Event,\n): boolean => selectTransition(definition, snapshot, { event, kind: 'event' }) !== undefined;\n\nconst createActor = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n initialSnapshot: MachineSnapshot<State, Context>,\n options: ActorOptions<State, Context> = {},\n): Actor<State, Context, Event> => {\n const restored = options.snapshot ?? initialSnapshot;\n\n assertSnapshot(definition, restored);\n let current = createSnapshot(restored.state, restored.context as Context);\n\n const listeners = new Set<(snapshot: MachineSnapshot<State, Context>) => void>();\n const tappers = tapper<ActorTapEvent<State, Context, Event>>();\n const disposal = new AbortController();\n const timers = new Set<ReturnType<typeof setTimeout>>();\n const invokes = new Set<AbortController>();\n const queue: RuntimeEvent<State, Context, Event>[] = [];\n let disposed = false;\n let processing = false;\n\n const cancelStateResources = (): void => {\n for (const timer of timers) clearTimeout(timer);\n timers.clear();\n\n for (const controller of invokes) controller.abort();\n invokes.clear();\n };\n\n const dispose = (): void => {\n if (disposed) return;\n\n disposed = true;\n queue.length = 0;\n cancelStateResources();\n listeners.clear();\n tappers.emit({ type: 'dispose' });\n tappers.clear();\n disposal.abort();\n };\n\n const observeError = (error: unknown, context: ActorErrorContext<State, Event>): void => {\n tappers.emit({ error, event: context.event, phase: context.phase, state: context.state, type: 'error' });\n };\n\n const fail = (error: unknown, context: ActorErrorContext<State, Event>): void => {\n observeError(error, context);\n dispose();\n };\n\n const run = (runtimeEvent: RuntimeEvent<State, Context, Event>): void => {\n if (disposed) return;\n\n if (processing) {\n queue.push(runtimeEvent);\n\n return;\n }\n\n processing = true;\n\n try {\n process(runtimeEvent);\n flush();\n } finally {\n processing = false;\n }\n };\n\n const send = (event: Event): void => {\n if (disposed) return;\n\n if (!isMachineEvent(event)) {\n warn('ignored malformed event; expected an object with a string `type`');\n\n return;\n }\n\n run({ event, kind: 'event' });\n };\n\n const runEffects = (effects: readonly Effect<Context, Event>[], state: State, event: Event | undefined): void => {\n for (const effect of effects) {\n if (disposed) return;\n\n try {\n effect({ context: current.context, event, send, signal: disposal.signal });\n } catch (error) {\n fail(error, { event, phase: 'effect', state });\n }\n }\n };\n\n const establishStateResources = (state: State, event: Event | undefined): void => {\n const node = nodeFor(definition, state);\n\n for (const after of node.after ?? []) {\n const timer = setTimeout(() => {\n timers.delete(timer);\n run({ after, kind: 'after' });\n }, after.delay);\n\n timers.add(timer);\n }\n\n for (const invoke of node.invoke ?? []) {\n const controller = new AbortController();\n\n invokes.add(controller);\n\n const capturedContext = current.context;\n const capturedEvent = event;\n\n void Promise.resolve()\n .then(() => invoke.src({ context: capturedContext, event: capturedEvent, signal: controller.signal }))\n .then(\n (result) => {\n invokes.delete(controller);\n\n if (disposed || controller.signal.aborted || !invoke.onDone) return;\n\n try {\n send(invoke.onDone({ context: capturedContext, result }));\n } catch (error) {\n fail(error, { event: capturedEvent, phase: 'invoke', state });\n }\n },\n (error: unknown) => {\n invokes.delete(controller);\n\n if (disposed || controller.signal.aborted) return;\n\n try {\n if (invoke.onError) {\n send(invoke.onError({ context: capturedContext, error }));\n } else {\n fail(error, { event: capturedEvent, phase: 'invoke', state });\n }\n } catch (callbackError) {\n fail(callbackError, { event: capturedEvent, phase: 'invoke', state });\n }\n },\n );\n }\n };\n\n const notify = (event: Event | undefined): void => {\n for (const listener of [...listeners]) {\n if (disposed) return;\n\n try {\n listener(current);\n } catch (error) {\n observeError(error, { event, phase: 'subscriber', state: current.state });\n }\n }\n };\n\n const process = (runtimeEvent: RuntimeEvent<State, Context, Event>): void => {\n const previous = current;\n let outcome: TransitionOutcome<State, Context, Event>;\n\n try {\n outcome = transition(definition, current, runtimeEvent);\n } catch (error) {\n fail(error, {\n event: runtimeEvent.kind === 'event' ? runtimeEvent.event : undefined,\n phase: 'transition',\n state: current.state,\n });\n\n return;\n }\n\n if (outcome.result.type === 'ignored' || !outcome.transition) {\n tappers.emit({ event: outcome.event, snapshot: outcome.result.snapshot, type: 'ignored' });\n return;\n }\n\n const source = nodeFor(definition, previous.state);\n\n current = outcome.result.snapshot;\n tappers.emit({ event: outcome.event, snapshot: current, type: 'transition' });\n cancelStateResources();\n establishStateResources(current.state, outcome.event);\n notify(outcome.event);\n runEffects(source.exit ?? [], previous.state, outcome.event);\n runEffects(outcome.transition.effects ?? [], previous.state, outcome.event);\n runEffects(nodeFor(definition, current.state).entry ?? [], current.state, outcome.event);\n };\n\n const flush = (): void => {\n let transitions = 0;\n\n while (queue.length > 0 && !disposed) {\n transitions += 1;\n\n if (transitions > MAX_TRANSITIONS) {\n fail(\n new ClockworkTransitionLimitError('maximum queued transitions exceeded', { maxTransitions: MAX_TRANSITIONS }),\n {\n phase: 'transition',\n state: current.state,\n },\n );\n\n return;\n }\n\n const next = queue.shift();\n\n if (next) process(next);\n }\n };\n\n establishStateResources(current.state, undefined);\n\n if (!options.snapshot) {\n runEffects(nodeFor(definition, current.state).entry ?? [], current.state, undefined);\n }\n\n return {\n can: (event) => {\n if (disposed) return false;\n\n try {\n if (!isMachineEvent(event)) {\n warn('ignored malformed event; expected an object with a string `type`');\n return false;\n }\n\n return canTransition(definition, current, event);\n } catch (error) {\n fail(error, { event, phase: 'transition', state: current.state });\n return false;\n }\n },\n get disposalSignal() {\n return disposal.signal;\n },\n dispose,\n get disposed() {\n return disposed;\n },\n send,\n get snapshot() {\n return current;\n },\n subscribe(listener) {\n if (disposed) return () => undefined;\n\n listeners.add(listener);\n\n return () => listeners.delete(listener);\n },\n tap(handler, tapOptions) {\n if (disposed) return () => undefined;\n\n return tappers.tap(handler, tapOptions);\n },\n [Symbol.dispose]: dispose,\n };\n};\n\n/** Defines a typed flat finite-state machine. */\nexport const defineMachine =\n <Context extends Record<string, unknown> = Record<string, never>, Event extends MachineEvent = MachineEvent>() =>\n <State extends string>(definition: MachineConfig<State, Context, Event>): Machine<State, Context, Event> => {\n assertDefinition(definition);\n const context = (definition as { readonly context?: Context }).context ?? ({} as Context);\n const initialSnapshot = createSnapshot(definition.initial, context);\n\n return {\n can: (snapshot, event) => canTransition(definition, snapshot, event),\n createActor: (options) => createActor(definition, initialSnapshot, options),\n initialSnapshot,\n transition: (snapshot, event) => transition(definition, snapshot, { event, kind: 'event' }).result,\n };\n };\n"],"mappings":"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"}
|
package/dist/clockwork.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"clockwork.js","names":[],"sources":["../src/errors.ts","../src/_dev.ts","../src/interpret.ts"],"sourcesContent":["/** Base class for every Clockwork failure. */\nexport class ClockworkError extends Error {\n readonly details: Readonly<Record<string, unknown>>;\n\n constructor(message: string, details: Record<string, unknown> = {}, opts?: ErrorOptions) {\n super(message, opts);\n this.name = new.target.name;\n this.details = Object.freeze({ ...details });\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** The machine definition failed validation at `defineMachine()` time. */\nexport class ClockworkDefinitionError extends ClockworkError {}\n\n/** A snapshot, its context, or a reducer result failed validation. */\nexport class ClockworkSnapshotError extends ClockworkError {}\n\n/** An actor exceeded the fixed queued-transition limit and disposed itself. */\nexport class ClockworkTransitionLimitError extends ClockworkError {}\n","const isDev = !(globalThis as { __CLOCKWORK_PROD__?: boolean }).__CLOCKWORK_PROD__;\n\nexport function warn(msg: string): void {\n if (isDev) console.warn(`[@vielzeug/clockwork] ${msg}`);\n}\n","import { tapper } from '@vielzeug/arsenal';\nimport { warn } from './_dev.js';\nimport { ClockworkDefinitionError, ClockworkSnapshotError, ClockworkTransitionLimitError } from './errors.js';\nimport type {\n Actor,\n ActorErrorContext,\n ActorOptions,\n ActorTapEvent,\n After,\n Effect,\n EventType,\n Machine,\n MachineConfig,\n MachineEvent,\n MachineSnapshot,\n StateNode,\n TransitionResult,\n} from './types.js';\n\nconst MAX_TIMER_MS = 2_147_483_647;\nconst MAX_TRANSITIONS = 1_000;\n\nconst isContextRecord = (value: unknown): value is Record<string, unknown> => {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return false;\n\n const prototype = Object.getPrototypeOf(value);\n\n return prototype === null || prototype === Object.prototype;\n};\n\n/** Fails fast on the definition footguns the type system cannot express: out-of-range\n * timer delays (platform timers fire immediately above 2^31 ms), empty transition\n * arrays, and a context that is not a plain record. Everything else — declared\n * targets, callback shapes, state keys — is compiler-checked in the typed definition. */\nconst assertDefinition = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n): void => {\n const context = (definition as { readonly context?: Context }).context;\n\n if (context !== undefined && !isContextRecord(context)) {\n throw new ClockworkDefinitionError('machine context must be a non-array object record', {});\n }\n\n for (const [state, node] of Object.entries(definition.states) as [string, StateNode<State, Context, Event>][]) {\n for (const [type, input] of Object.entries(node.on ?? {})) {\n if (Array.isArray(input) && input.length === 0) {\n throw new ClockworkDefinitionError('a transition array must not be empty', { state, type });\n }\n }\n\n for (const [index, after] of (node.after ?? []).entries()) {\n if (!Number.isFinite(after.delay) || after.delay < 0 || after.delay > MAX_TIMER_MS) {\n throw new ClockworkDefinitionError(`state \"${state}\" after delay must be between 0 and ${MAX_TIMER_MS}`, {\n delay: after.delay,\n index,\n state,\n });\n }\n }\n }\n};\n\ntype InternalEvent<State extends string, Context extends Record<string, unknown>, Event extends MachineEvent> = {\n readonly after: After<State, Context, Event>;\n readonly kind: 'after';\n};\n\ntype RuntimeEvent<State extends string, Context extends Record<string, unknown>, Event extends MachineEvent> =\n | { readonly event: Event; readonly kind: 'event' }\n | InternalEvent<State, Context, Event>;\n\n/** A transition or delayed transition selected for execution. The reducer's event\n * parameter is whatever the selector matched — the event for a user transition,\n * `undefined` for a timer — which the declared per-type signatures cannot express. */\ntype ExecutableTransition<State extends string, Context extends Record<string, unknown>, Event extends MachineEvent> = {\n readonly effects?: readonly Effect<Context, Event>[];\n readonly reduce?: (args: { readonly context: Readonly<Context>; readonly event: Event | undefined }) => Context;\n readonly target: State;\n};\n\ntype SelectedTransition<State extends string, Context extends Record<string, unknown>, Event extends MachineEvent> = {\n readonly event: Event | undefined;\n readonly transition: ExecutableTransition<State, Context, Event>;\n};\n\ntype TransitionOutcome<State extends string, Context extends Record<string, unknown>, Event extends MachineEvent> = {\n readonly event: Event | undefined;\n readonly result: TransitionResult<State, Context>;\n readonly transition?: ExecutableTransition<State, Context, Event>;\n};\n\nconst createSnapshot = <State extends string, Context extends Record<string, unknown>>(\n state: State,\n context: Context,\n): MachineSnapshot<State, Context> => {\n const cloned = Object.assign(Object.create(Object.getPrototypeOf(context)) as Context, context);\n\n return Object.freeze({ context: Object.freeze(cloned), state });\n};\n\nconst normalizeSnapshot = <State extends string, Context extends Record<string, unknown>>(\n snapshot: MachineSnapshot<State, Context>,\n): MachineSnapshot<State, Context> =>\n Object.isFrozen(snapshot) && Object.isFrozen(snapshot.context)\n ? snapshot\n : createSnapshot(snapshot.state, snapshot.context as Context);\n\nconst invalidSnapshot = (state: unknown): never => {\n throw new ClockworkSnapshotError(`snapshot state \"${String(state)}\" is not declared`, { state });\n};\n\nconst isMachineEvent = (event: unknown): event is MachineEvent =>\n typeof event === 'object' && event !== null && typeof (event as { type?: unknown }).type === 'string';\n\n/** Reads a declared state node. The own-property guard keeps prototype keys such as\n * `constructor` or `__proto__` from reading as declared states. */\nconst nodeFor = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n state: State,\n) => (Object.hasOwn(definition.states, state) ? definition.states[state] : invalidSnapshot(state));\n\nconst assertSnapshot = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n snapshot: MachineSnapshot<State, Context>,\n): void => {\n if (!isContextRecord(snapshot.context)) {\n throw new ClockworkSnapshotError('snapshot context must be a non-array object record', {});\n }\n\n nodeFor(definition, snapshot.state);\n};\n\nconst selectTransition = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n snapshot: MachineSnapshot<State, Context>,\n runtimeEvent: RuntimeEvent<State, Context, Event>,\n): SelectedTransition<State, Context, Event> | undefined => {\n assertSnapshot(definition, snapshot);\n const node = nodeFor(definition, snapshot.state);\n\n if (runtimeEvent.kind === 'after') {\n if (!node.after || !node.after.includes(runtimeEvent.after)) return undefined;\n\n if (!runtimeEvent.after.guard || runtimeEvent.after.guard({ context: snapshot.context, event: undefined })) {\n return { event: undefined, transition: runtimeEvent.after as ExecutableTransition<State, Context, Event> };\n }\n\n return undefined;\n }\n\n const on = node.on;\n\n if (!on || !Object.hasOwn(on, runtimeEvent.event.type)) return undefined;\n\n const input = on[runtimeEvent.event.type as EventType<Event>];\n const candidates = Array.isArray(input) ? input : [input];\n\n for (const candidate of candidates) {\n if (!candidate.guard || candidate.guard({ context: snapshot.context, event: runtimeEvent.event })) {\n return { event: runtimeEvent.event, transition: candidate as ExecutableTransition<State, Context, Event> };\n }\n }\n\n return undefined;\n};\n\nconst transition = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n snapshot: MachineSnapshot<State, Context>,\n runtimeEvent: RuntimeEvent<State, Context, Event>,\n): TransitionOutcome<State, Context, Event> => {\n const selected = selectTransition(definition, snapshot, runtimeEvent);\n\n if (!selected) {\n return {\n event: runtimeEvent.kind === 'event' ? runtimeEvent.event : undefined,\n result: { snapshot: normalizeSnapshot(snapshot), type: 'ignored' },\n };\n }\n\n const nextContext = selected.transition.reduce\n ? selected.transition.reduce({ context: snapshot.context, event: selected.event })\n : snapshot.context;\n\n if (!isContextRecord(nextContext)) {\n throw new ClockworkSnapshotError('a reducer must return a non-array object record', {\n state: snapshot.state,\n });\n }\n\n return {\n event: selected.event,\n result: { snapshot: createSnapshot(selected.transition.target, nextContext as Context), type: 'transition' },\n transition: selected.transition,\n };\n};\n\nconst canTransition = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n snapshot: MachineSnapshot<State, Context>,\n event: Event,\n): boolean => selectTransition(definition, snapshot, { event, kind: 'event' }) !== undefined;\n\nconst createActor = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n initialSnapshot: MachineSnapshot<State, Context>,\n options: ActorOptions<State, Context> = {},\n): Actor<State, Context, Event> => {\n const restored = options.snapshot ?? initialSnapshot;\n\n assertSnapshot(definition, restored);\n let current = createSnapshot(restored.state, restored.context as Context);\n\n const listeners = new Set<(snapshot: MachineSnapshot<State, Context>) => void>();\n const tappers = tapper<ActorTapEvent<State, Context, Event>>();\n const disposal = new AbortController();\n const timers = new Set<ReturnType<typeof setTimeout>>();\n const invokes = new Set<AbortController>();\n const queue: RuntimeEvent<State, Context, Event>[] = [];\n let disposed = false;\n let processing = false;\n\n const cancelStateResources = (): void => {\n for (const timer of timers) clearTimeout(timer);\n timers.clear();\n\n for (const controller of invokes) controller.abort();\n invokes.clear();\n };\n\n const dispose = (): void => {\n if (disposed) return;\n\n disposed = true;\n queue.length = 0;\n cancelStateResources();\n listeners.clear();\n tappers.emit({ type: 'dispose' });\n tappers.clear();\n disposal.abort();\n };\n\n const observeError = (error: unknown, context: ActorErrorContext<State, Event>): void => {\n tappers.emit({ error, event: context.event, phase: context.phase, state: context.state, type: 'error' });\n };\n\n const fail = (error: unknown, context: ActorErrorContext<State, Event>): void => {\n observeError(error, context);\n dispose();\n };\n\n const run = (runtimeEvent: RuntimeEvent<State, Context, Event>): void => {\n if (disposed) return;\n\n if (processing) {\n queue.push(runtimeEvent);\n\n return;\n }\n\n processing = true;\n\n try {\n process(runtimeEvent);\n flush();\n } finally {\n processing = false;\n }\n };\n\n const send = (event: Event): void => {\n if (disposed) return;\n\n if (!isMachineEvent(event)) {\n warn('ignored malformed event; expected an object with a string `type`');\n\n return;\n }\n\n run({ event, kind: 'event' });\n };\n\n const runEffects = (effects: readonly Effect<Context, Event>[], state: State, event: Event | undefined): void => {\n for (const effect of effects) {\n if (disposed) return;\n\n try {\n effect({ context: current.context, event, send, signal: disposal.signal });\n } catch (error) {\n fail(error, { event, phase: 'effect', state });\n }\n }\n };\n\n const establishStateResources = (state: State, event: Event | undefined): void => {\n const node = nodeFor(definition, state);\n\n for (const after of node.after ?? []) {\n const timer = setTimeout(() => {\n timers.delete(timer);\n run({ after, kind: 'after' });\n }, after.delay);\n\n timers.add(timer);\n }\n\n for (const invoke of node.invoke ?? []) {\n const controller = new AbortController();\n\n invokes.add(controller);\n\n const capturedContext = current.context;\n const capturedEvent = event;\n\n void Promise.resolve()\n .then(() => invoke.src({ context: capturedContext, event: capturedEvent, signal: controller.signal }))\n .then(\n (result) => {\n invokes.delete(controller);\n\n if (disposed || controller.signal.aborted || !invoke.onDone) return;\n\n try {\n send(invoke.onDone({ context: capturedContext, result }));\n } catch (error) {\n fail(error, { event: capturedEvent, phase: 'invoke', state });\n }\n },\n (error: unknown) => {\n invokes.delete(controller);\n\n if (disposed || controller.signal.aborted) return;\n\n try {\n if (invoke.onError) {\n send(invoke.onError({ context: capturedContext, error }));\n } else {\n fail(error, { event: capturedEvent, phase: 'invoke', state });\n }\n } catch (callbackError) {\n fail(callbackError, { event: capturedEvent, phase: 'invoke', state });\n }\n },\n );\n }\n };\n\n const notify = (event: Event | undefined): void => {\n for (const listener of [...listeners]) {\n if (disposed) return;\n\n try {\n listener(current);\n } catch (error) {\n observeError(error, { event, phase: 'subscriber', state: current.state });\n }\n }\n };\n\n const process = (runtimeEvent: RuntimeEvent<State, Context, Event>): void => {\n const previous = current;\n let outcome: TransitionOutcome<State, Context, Event>;\n\n try {\n outcome = transition(definition, current, runtimeEvent);\n } catch (error) {\n fail(error, {\n event: runtimeEvent.kind === 'event' ? runtimeEvent.event : undefined,\n phase: 'transition',\n state: current.state,\n });\n\n return;\n }\n\n if (outcome.result.type === 'ignored' || !outcome.transition) {\n tappers.emit({ event: outcome.event, snapshot: outcome.result.snapshot, type: 'ignored' });\n return;\n }\n\n const source = nodeFor(definition, previous.state);\n\n current = outcome.result.snapshot;\n tappers.emit({ event: outcome.event, snapshot: current, type: 'transition' });\n cancelStateResources();\n establishStateResources(current.state, outcome.event);\n notify(outcome.event);\n runEffects(source.exit ?? [], previous.state, outcome.event);\n runEffects(outcome.transition.effects ?? [], previous.state, outcome.event);\n runEffects(nodeFor(definition, current.state).entry ?? [], current.state, outcome.event);\n };\n\n const flush = (): void => {\n let transitions = 0;\n\n while (queue.length > 0 && !disposed) {\n transitions += 1;\n\n if (transitions > MAX_TRANSITIONS) {\n fail(\n new ClockworkTransitionLimitError('maximum queued transitions exceeded', { maxTransitions: MAX_TRANSITIONS }),\n {\n phase: 'transition',\n state: current.state,\n },\n );\n\n return;\n }\n\n const next = queue.shift();\n\n if (next) process(next);\n }\n };\n\n establishStateResources(current.state, undefined);\n\n if (!options.snapshot) {\n runEffects(nodeFor(definition, current.state).entry ?? [], current.state, undefined);\n }\n\n return {\n can: (event) => {\n if (disposed) return false;\n\n try {\n if (!isMachineEvent(event)) {\n warn('ignored malformed event; expected an object with a string `type`');\n return false;\n }\n\n return canTransition(definition, current, event);\n } catch (error) {\n fail(error, { event, phase: 'transition', state: current.state });\n return false;\n }\n },\n get disposalSignal() {\n return disposal.signal;\n },\n dispose,\n get disposed() {\n return disposed;\n },\n send,\n get snapshot() {\n return current;\n },\n subscribe(listener) {\n if (disposed) return () => undefined;\n\n listeners.add(listener);\n\n return () => listeners.delete(listener);\n },\n tap(handler, tapOptions) {\n if (disposed) return () => undefined;\n\n return tappers.tap(handler, tapOptions);\n },\n [Symbol.dispose]: dispose,\n };\n};\n\n/** Defines a typed flat finite-state machine. */\nexport const defineMachine =\n <Context extends Record<string, unknown> = Record<string, never>, Event extends MachineEvent = MachineEvent>() =>\n <State extends string>(definition: MachineConfig<State, Context, Event>): Machine<State, Context, Event> => {\n assertDefinition(definition);\n const context = (definition as { readonly context?: Context }).context ?? ({} as Context);\n const initialSnapshot = createSnapshot(definition.initial, context);\n\n return {\n can: (snapshot, event) => canTransition(definition, snapshot, event),\n createActor: (options) => createActor(definition, initialSnapshot, options),\n initialSnapshot,\n transition: (snapshot, event) => transition(definition, snapshot, { event, kind: 'event' }).result,\n };\n };\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"clockwork.js","names":[],"sources":["../src/errors.ts","../src/_dev.ts","../src/interpret.ts"],"sourcesContent":["/** Base class for every Clockwork failure. */\nexport class ClockworkError extends Error {\n readonly details: Readonly<Record<string, unknown>>;\n\n constructor(message: string, details: Record<string, unknown> = {}, opts?: ErrorOptions) {\n super(message, opts);\n this.name = new.target.name;\n this.details = Object.freeze({ ...details });\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** The machine definition failed validation at `defineMachine()` time. */\nexport class ClockworkDefinitionError extends ClockworkError {}\n\n/** A snapshot, its context, or a reducer result failed validation. */\nexport class ClockworkSnapshotError extends ClockworkError {}\n\n/** An actor exceeded the fixed queued-transition limit and disposed itself. */\nexport class ClockworkTransitionLimitError extends ClockworkError {}\n","const isDev = !(globalThis as { __CLOCKWORK_PROD__?: boolean }).__CLOCKWORK_PROD__;\n\nexport function warn(msg: string): void {\n if (isDev) console.warn(`[@vielzeug/clockwork] ${msg}`);\n}\n","import { tapper } from '@vielzeug/arsenal';\nimport { warn } from './_dev.js';\nimport { ClockworkDefinitionError, ClockworkSnapshotError, ClockworkTransitionLimitError } from './errors.js';\nimport type {\n Actor,\n ActorErrorContext,\n ActorOptions,\n ActorTapEvent,\n After,\n Effect,\n EventType,\n Machine,\n MachineConfig,\n MachineEvent,\n MachineSnapshot,\n StateNode,\n TransitionResult,\n} from './types.js';\n\nconst MAX_TIMER_MS = 2_147_483_647;\nconst MAX_TRANSITIONS = 1_000;\n\nconst isContextRecord = (value: unknown): value is Record<string, unknown> => {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return false;\n\n const prototype = Object.getPrototypeOf(value);\n\n return prototype === null || prototype === Object.prototype;\n};\n\n/** Fails fast on the definition footguns the type system cannot express: out-of-range\n * timer delays (platform timers fire immediately above 2^31 ms), empty transition\n * arrays, and a context that is not a plain record. Everything else: declared\n * targets, callback shapes, state keys: is compiler-checked in the typed definition. */\nconst assertDefinition = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n): void => {\n const context = (definition as { readonly context?: Context }).context;\n\n if (context !== undefined && !isContextRecord(context)) {\n throw new ClockworkDefinitionError('machine context must be a non-array object record', {});\n }\n\n for (const [state, node] of Object.entries(definition.states) as [string, StateNode<State, Context, Event>][]) {\n for (const [type, input] of Object.entries(node.on ?? {})) {\n if (Array.isArray(input) && input.length === 0) {\n throw new ClockworkDefinitionError('a transition array must not be empty', { state, type });\n }\n }\n\n for (const [index, after] of (node.after ?? []).entries()) {\n if (!Number.isFinite(after.delay) || after.delay < 0 || after.delay > MAX_TIMER_MS) {\n throw new ClockworkDefinitionError(`state \"${state}\" after delay must be between 0 and ${MAX_TIMER_MS}`, {\n delay: after.delay,\n index,\n state,\n });\n }\n }\n }\n};\n\ntype InternalEvent<State extends string, Context extends Record<string, unknown>, Event extends MachineEvent> = {\n readonly after: After<State, Context, Event>;\n readonly kind: 'after';\n};\n\ntype RuntimeEvent<State extends string, Context extends Record<string, unknown>, Event extends MachineEvent> =\n | { readonly event: Event; readonly kind: 'event' }\n | InternalEvent<State, Context, Event>;\n\n/** A transition or delayed transition selected for execution. The reducer's event\n * parameter is whatever the selector matched: the event for a user transition,\n * `undefined` for a timer, which the declared per-type signatures cannot express. */\ntype ExecutableTransition<State extends string, Context extends Record<string, unknown>, Event extends MachineEvent> = {\n readonly effects?: readonly Effect<Context, Event>[];\n readonly reduce?: (args: { readonly context: Readonly<Context>; readonly event: Event | undefined }) => Context;\n readonly target: State;\n};\n\ntype SelectedTransition<State extends string, Context extends Record<string, unknown>, Event extends MachineEvent> = {\n readonly event: Event | undefined;\n readonly transition: ExecutableTransition<State, Context, Event>;\n};\n\ntype TransitionOutcome<State extends string, Context extends Record<string, unknown>, Event extends MachineEvent> = {\n readonly event: Event | undefined;\n readonly result: TransitionResult<State, Context>;\n readonly transition?: ExecutableTransition<State, Context, Event>;\n};\n\nconst createSnapshot = <State extends string, Context extends Record<string, unknown>>(\n state: State,\n context: Context,\n): MachineSnapshot<State, Context> => {\n const cloned = Object.assign(Object.create(Object.getPrototypeOf(context)) as Context, context);\n\n return Object.freeze({ context: Object.freeze(cloned), state });\n};\n\nconst normalizeSnapshot = <State extends string, Context extends Record<string, unknown>>(\n snapshot: MachineSnapshot<State, Context>,\n): MachineSnapshot<State, Context> =>\n Object.isFrozen(snapshot) && Object.isFrozen(snapshot.context)\n ? snapshot\n : createSnapshot(snapshot.state, snapshot.context as Context);\n\nconst invalidSnapshot = (state: unknown): never => {\n throw new ClockworkSnapshotError(`snapshot state \"${String(state)}\" is not declared`, { state });\n};\n\nconst isMachineEvent = (event: unknown): event is MachineEvent =>\n typeof event === 'object' && event !== null && typeof (event as { type?: unknown }).type === 'string';\n\n/** Reads a declared state node. The own-property guard keeps prototype keys such as\n * `constructor` or `__proto__` from reading as declared states. */\nconst nodeFor = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n state: State,\n) => (Object.hasOwn(definition.states, state) ? definition.states[state] : invalidSnapshot(state));\n\nconst assertSnapshot = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n snapshot: MachineSnapshot<State, Context>,\n): void => {\n if (!isContextRecord(snapshot.context)) {\n throw new ClockworkSnapshotError('snapshot context must be a non-array object record', {});\n }\n\n nodeFor(definition, snapshot.state);\n};\n\nconst selectTransition = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n snapshot: MachineSnapshot<State, Context>,\n runtimeEvent: RuntimeEvent<State, Context, Event>,\n): SelectedTransition<State, Context, Event> | undefined => {\n assertSnapshot(definition, snapshot);\n const node = nodeFor(definition, snapshot.state);\n\n if (runtimeEvent.kind === 'after') {\n if (!node.after || !node.after.includes(runtimeEvent.after)) return undefined;\n\n if (!runtimeEvent.after.guard || runtimeEvent.after.guard({ context: snapshot.context, event: undefined })) {\n return { event: undefined, transition: runtimeEvent.after as ExecutableTransition<State, Context, Event> };\n }\n\n return undefined;\n }\n\n const on = node.on;\n\n if (!on || !Object.hasOwn(on, runtimeEvent.event.type)) return undefined;\n\n const input = on[runtimeEvent.event.type as EventType<Event>];\n const candidates = Array.isArray(input) ? input : [input];\n\n for (const candidate of candidates) {\n if (!candidate.guard || candidate.guard({ context: snapshot.context, event: runtimeEvent.event })) {\n return { event: runtimeEvent.event, transition: candidate as ExecutableTransition<State, Context, Event> };\n }\n }\n\n return undefined;\n};\n\nconst transition = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n snapshot: MachineSnapshot<State, Context>,\n runtimeEvent: RuntimeEvent<State, Context, Event>,\n): TransitionOutcome<State, Context, Event> => {\n const selected = selectTransition(definition, snapshot, runtimeEvent);\n\n if (!selected) {\n return {\n event: runtimeEvent.kind === 'event' ? runtimeEvent.event : undefined,\n result: { snapshot: normalizeSnapshot(snapshot), type: 'ignored' },\n };\n }\n\n const nextContext = selected.transition.reduce\n ? selected.transition.reduce({ context: snapshot.context, event: selected.event })\n : snapshot.context;\n\n if (!isContextRecord(nextContext)) {\n throw new ClockworkSnapshotError('a reducer must return a non-array object record', {\n state: snapshot.state,\n });\n }\n\n return {\n event: selected.event,\n result: { snapshot: createSnapshot(selected.transition.target, nextContext as Context), type: 'transition' },\n transition: selected.transition,\n };\n};\n\nconst canTransition = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n snapshot: MachineSnapshot<State, Context>,\n event: Event,\n): boolean => selectTransition(definition, snapshot, { event, kind: 'event' }) !== undefined;\n\nconst createActor = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n initialSnapshot: MachineSnapshot<State, Context>,\n options: ActorOptions<State, Context> = {},\n): Actor<State, Context, Event> => {\n const restored = options.snapshot ?? initialSnapshot;\n\n assertSnapshot(definition, restored);\n let current = createSnapshot(restored.state, restored.context as Context);\n\n const listeners = new Set<(snapshot: MachineSnapshot<State, Context>) => void>();\n const tappers = tapper<ActorTapEvent<State, Context, Event>>();\n const disposal = new AbortController();\n const timers = new Set<ReturnType<typeof setTimeout>>();\n const invokes = new Set<AbortController>();\n const queue: RuntimeEvent<State, Context, Event>[] = [];\n let disposed = false;\n let processing = false;\n\n const cancelStateResources = (): void => {\n for (const timer of timers) clearTimeout(timer);\n timers.clear();\n\n for (const controller of invokes) controller.abort();\n invokes.clear();\n };\n\n const dispose = (): void => {\n if (disposed) return;\n\n disposed = true;\n queue.length = 0;\n cancelStateResources();\n listeners.clear();\n tappers.emit({ type: 'dispose' });\n tappers.clear();\n disposal.abort();\n };\n\n const observeError = (error: unknown, context: ActorErrorContext<State, Event>): void => {\n tappers.emit({ error, event: context.event, phase: context.phase, state: context.state, type: 'error' });\n };\n\n const fail = (error: unknown, context: ActorErrorContext<State, Event>): void => {\n observeError(error, context);\n dispose();\n };\n\n const run = (runtimeEvent: RuntimeEvent<State, Context, Event>): void => {\n if (disposed) return;\n\n if (processing) {\n queue.push(runtimeEvent);\n\n return;\n }\n\n processing = true;\n\n try {\n process(runtimeEvent);\n flush();\n } finally {\n processing = false;\n }\n };\n\n const send = (event: Event): void => {\n if (disposed) return;\n\n if (!isMachineEvent(event)) {\n warn('ignored malformed event; expected an object with a string `type`');\n\n return;\n }\n\n run({ event, kind: 'event' });\n };\n\n const runEffects = (effects: readonly Effect<Context, Event>[], state: State, event: Event | undefined): void => {\n for (const effect of effects) {\n if (disposed) return;\n\n try {\n effect({ context: current.context, event, send, signal: disposal.signal });\n } catch (error) {\n fail(error, { event, phase: 'effect', state });\n }\n }\n };\n\n const establishStateResources = (state: State, event: Event | undefined): void => {\n const node = nodeFor(definition, state);\n\n for (const after of node.after ?? []) {\n const timer = setTimeout(() => {\n timers.delete(timer);\n run({ after, kind: 'after' });\n }, after.delay);\n\n timers.add(timer);\n }\n\n for (const invoke of node.invoke ?? []) {\n const controller = new AbortController();\n\n invokes.add(controller);\n\n const capturedContext = current.context;\n const capturedEvent = event;\n\n void Promise.resolve()\n .then(() => invoke.src({ context: capturedContext, event: capturedEvent, signal: controller.signal }))\n .then(\n (result) => {\n invokes.delete(controller);\n\n if (disposed || controller.signal.aborted || !invoke.onDone) return;\n\n try {\n send(invoke.onDone({ context: capturedContext, result }));\n } catch (error) {\n fail(error, { event: capturedEvent, phase: 'invoke', state });\n }\n },\n (error: unknown) => {\n invokes.delete(controller);\n\n if (disposed || controller.signal.aborted) return;\n\n try {\n if (invoke.onError) {\n send(invoke.onError({ context: capturedContext, error }));\n } else {\n fail(error, { event: capturedEvent, phase: 'invoke', state });\n }\n } catch (callbackError) {\n fail(callbackError, { event: capturedEvent, phase: 'invoke', state });\n }\n },\n );\n }\n };\n\n const notify = (event: Event | undefined): void => {\n for (const listener of [...listeners]) {\n if (disposed) return;\n\n try {\n listener(current);\n } catch (error) {\n observeError(error, { event, phase: 'subscriber', state: current.state });\n }\n }\n };\n\n const process = (runtimeEvent: RuntimeEvent<State, Context, Event>): void => {\n const previous = current;\n let outcome: TransitionOutcome<State, Context, Event>;\n\n try {\n outcome = transition(definition, current, runtimeEvent);\n } catch (error) {\n fail(error, {\n event: runtimeEvent.kind === 'event' ? runtimeEvent.event : undefined,\n phase: 'transition',\n state: current.state,\n });\n\n return;\n }\n\n if (outcome.result.type === 'ignored' || !outcome.transition) {\n tappers.emit({ event: outcome.event, snapshot: outcome.result.snapshot, type: 'ignored' });\n return;\n }\n\n const source = nodeFor(definition, previous.state);\n\n current = outcome.result.snapshot;\n tappers.emit({ event: outcome.event, snapshot: current, type: 'transition' });\n cancelStateResources();\n establishStateResources(current.state, outcome.event);\n notify(outcome.event);\n runEffects(source.exit ?? [], previous.state, outcome.event);\n runEffects(outcome.transition.effects ?? [], previous.state, outcome.event);\n runEffects(nodeFor(definition, current.state).entry ?? [], current.state, outcome.event);\n };\n\n const flush = (): void => {\n let transitions = 0;\n\n while (queue.length > 0 && !disposed) {\n transitions += 1;\n\n if (transitions > MAX_TRANSITIONS) {\n fail(\n new ClockworkTransitionLimitError('maximum queued transitions exceeded', { maxTransitions: MAX_TRANSITIONS }),\n {\n phase: 'transition',\n state: current.state,\n },\n );\n\n return;\n }\n\n const next = queue.shift();\n\n if (next) process(next);\n }\n };\n\n establishStateResources(current.state, undefined);\n\n if (!options.snapshot) {\n runEffects(nodeFor(definition, current.state).entry ?? [], current.state, undefined);\n }\n\n return {\n can: (event) => {\n if (disposed) return false;\n\n try {\n if (!isMachineEvent(event)) {\n warn('ignored malformed event; expected an object with a string `type`');\n return false;\n }\n\n return canTransition(definition, current, event);\n } catch (error) {\n fail(error, { event, phase: 'transition', state: current.state });\n return false;\n }\n },\n get disposalSignal() {\n return disposal.signal;\n },\n dispose,\n get disposed() {\n return disposed;\n },\n send,\n get snapshot() {\n return current;\n },\n subscribe(listener) {\n if (disposed) return () => undefined;\n\n listeners.add(listener);\n\n return () => listeners.delete(listener);\n },\n tap(handler, tapOptions) {\n if (disposed) return () => undefined;\n\n return tappers.tap(handler, tapOptions);\n },\n [Symbol.dispose]: dispose,\n };\n};\n\n/** Defines a typed flat finite-state machine. */\nexport const defineMachine =\n <Context extends Record<string, unknown> = Record<string, never>, Event extends MachineEvent = MachineEvent>() =>\n <State extends string>(definition: MachineConfig<State, Context, Event>): Machine<State, Context, Event> => {\n assertDefinition(definition);\n const context = (definition as { readonly context?: Context }).context ?? ({} as Context);\n const initialSnapshot = createSnapshot(definition.initial, context);\n\n return {\n can: (snapshot, event) => canTransition(definition, snapshot, event),\n createActor: (options) => createActor(definition, initialSnapshot, options),\n initialSnapshot,\n transition: (snapshot, event) => transition(definition, snapshot, { event, kind: 'event' }).result,\n };\n };\n"],"mappings":"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"}
|
package/dist/interpret.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"interpret.cjs","names":[],"sources":["../src/interpret.ts"],"sourcesContent":["import { tapper } from '@vielzeug/arsenal';\nimport { warn } from './_dev.js';\nimport { ClockworkDefinitionError, ClockworkSnapshotError, ClockworkTransitionLimitError } from './errors.js';\nimport type {\n Actor,\n ActorErrorContext,\n ActorOptions,\n ActorTapEvent,\n After,\n Effect,\n EventType,\n Machine,\n MachineConfig,\n MachineEvent,\n MachineSnapshot,\n StateNode,\n TransitionResult,\n} from './types.js';\n\nconst MAX_TIMER_MS = 2_147_483_647;\nconst MAX_TRANSITIONS = 1_000;\n\nconst isContextRecord = (value: unknown): value is Record<string, unknown> => {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return false;\n\n const prototype = Object.getPrototypeOf(value);\n\n return prototype === null || prototype === Object.prototype;\n};\n\n/** Fails fast on the definition footguns the type system cannot express: out-of-range\n * timer delays (platform timers fire immediately above 2^31 ms), empty transition\n * arrays, and a context that is not a plain record. Everything else — declared\n * targets, callback shapes, state keys — is compiler-checked in the typed definition. */\nconst assertDefinition = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n): void => {\n const context = (definition as { readonly context?: Context }).context;\n\n if (context !== undefined && !isContextRecord(context)) {\n throw new ClockworkDefinitionError('machine context must be a non-array object record', {});\n }\n\n for (const [state, node] of Object.entries(definition.states) as [string, StateNode<State, Context, Event>][]) {\n for (const [type, input] of Object.entries(node.on ?? {})) {\n if (Array.isArray(input) && input.length === 0) {\n throw new ClockworkDefinitionError('a transition array must not be empty', { state, type });\n }\n }\n\n for (const [index, after] of (node.after ?? []).entries()) {\n if (!Number.isFinite(after.delay) || after.delay < 0 || after.delay > MAX_TIMER_MS) {\n throw new ClockworkDefinitionError(`state \"${state}\" after delay must be between 0 and ${MAX_TIMER_MS}`, {\n delay: after.delay,\n index,\n state,\n });\n }\n }\n }\n};\n\ntype InternalEvent<State extends string, Context extends Record<string, unknown>, Event extends MachineEvent> = {\n readonly after: After<State, Context, Event>;\n readonly kind: 'after';\n};\n\ntype RuntimeEvent<State extends string, Context extends Record<string, unknown>, Event extends MachineEvent> =\n | { readonly event: Event; readonly kind: 'event' }\n | InternalEvent<State, Context, Event>;\n\n/** A transition or delayed transition selected for execution. The reducer's event\n * parameter is whatever the selector matched — the event for a user transition,\n * `undefined` for a timer — which the declared per-type signatures cannot express. */\ntype ExecutableTransition<State extends string, Context extends Record<string, unknown>, Event extends MachineEvent> = {\n readonly effects?: readonly Effect<Context, Event>[];\n readonly reduce?: (args: { readonly context: Readonly<Context>; readonly event: Event | undefined }) => Context;\n readonly target: State;\n};\n\ntype SelectedTransition<State extends string, Context extends Record<string, unknown>, Event extends MachineEvent> = {\n readonly event: Event | undefined;\n readonly transition: ExecutableTransition<State, Context, Event>;\n};\n\ntype TransitionOutcome<State extends string, Context extends Record<string, unknown>, Event extends MachineEvent> = {\n readonly event: Event | undefined;\n readonly result: TransitionResult<State, Context>;\n readonly transition?: ExecutableTransition<State, Context, Event>;\n};\n\nconst createSnapshot = <State extends string, Context extends Record<string, unknown>>(\n state: State,\n context: Context,\n): MachineSnapshot<State, Context> => {\n const cloned = Object.assign(Object.create(Object.getPrototypeOf(context)) as Context, context);\n\n return Object.freeze({ context: Object.freeze(cloned), state });\n};\n\nconst normalizeSnapshot = <State extends string, Context extends Record<string, unknown>>(\n snapshot: MachineSnapshot<State, Context>,\n): MachineSnapshot<State, Context> =>\n Object.isFrozen(snapshot) && Object.isFrozen(snapshot.context)\n ? snapshot\n : createSnapshot(snapshot.state, snapshot.context as Context);\n\nconst invalidSnapshot = (state: unknown): never => {\n throw new ClockworkSnapshotError(`snapshot state \"${String(state)}\" is not declared`, { state });\n};\n\nconst isMachineEvent = (event: unknown): event is MachineEvent =>\n typeof event === 'object' && event !== null && typeof (event as { type?: unknown }).type === 'string';\n\n/** Reads a declared state node. The own-property guard keeps prototype keys such as\n * `constructor` or `__proto__` from reading as declared states. */\nconst nodeFor = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n state: State,\n) => (Object.hasOwn(definition.states, state) ? definition.states[state] : invalidSnapshot(state));\n\nconst assertSnapshot = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n snapshot: MachineSnapshot<State, Context>,\n): void => {\n if (!isContextRecord(snapshot.context)) {\n throw new ClockworkSnapshotError('snapshot context must be a non-array object record', {});\n }\n\n nodeFor(definition, snapshot.state);\n};\n\nconst selectTransition = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n snapshot: MachineSnapshot<State, Context>,\n runtimeEvent: RuntimeEvent<State, Context, Event>,\n): SelectedTransition<State, Context, Event> | undefined => {\n assertSnapshot(definition, snapshot);\n const node = nodeFor(definition, snapshot.state);\n\n if (runtimeEvent.kind === 'after') {\n if (!node.after || !node.after.includes(runtimeEvent.after)) return undefined;\n\n if (!runtimeEvent.after.guard || runtimeEvent.after.guard({ context: snapshot.context, event: undefined })) {\n return { event: undefined, transition: runtimeEvent.after as ExecutableTransition<State, Context, Event> };\n }\n\n return undefined;\n }\n\n const on = node.on;\n\n if (!on || !Object.hasOwn(on, runtimeEvent.event.type)) return undefined;\n\n const input = on[runtimeEvent.event.type as EventType<Event>];\n const candidates = Array.isArray(input) ? input : [input];\n\n for (const candidate of candidates) {\n if (!candidate.guard || candidate.guard({ context: snapshot.context, event: runtimeEvent.event })) {\n return { event: runtimeEvent.event, transition: candidate as ExecutableTransition<State, Context, Event> };\n }\n }\n\n return undefined;\n};\n\nconst transition = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n snapshot: MachineSnapshot<State, Context>,\n runtimeEvent: RuntimeEvent<State, Context, Event>,\n): TransitionOutcome<State, Context, Event> => {\n const selected = selectTransition(definition, snapshot, runtimeEvent);\n\n if (!selected) {\n return {\n event: runtimeEvent.kind === 'event' ? runtimeEvent.event : undefined,\n result: { snapshot: normalizeSnapshot(snapshot), type: 'ignored' },\n };\n }\n\n const nextContext = selected.transition.reduce\n ? selected.transition.reduce({ context: snapshot.context, event: selected.event })\n : snapshot.context;\n\n if (!isContextRecord(nextContext)) {\n throw new ClockworkSnapshotError('a reducer must return a non-array object record', {\n state: snapshot.state,\n });\n }\n\n return {\n event: selected.event,\n result: { snapshot: createSnapshot(selected.transition.target, nextContext as Context), type: 'transition' },\n transition: selected.transition,\n };\n};\n\nconst canTransition = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n snapshot: MachineSnapshot<State, Context>,\n event: Event,\n): boolean => selectTransition(definition, snapshot, { event, kind: 'event' }) !== undefined;\n\nconst createActor = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n initialSnapshot: MachineSnapshot<State, Context>,\n options: ActorOptions<State, Context> = {},\n): Actor<State, Context, Event> => {\n const restored = options.snapshot ?? initialSnapshot;\n\n assertSnapshot(definition, restored);\n let current = createSnapshot(restored.state, restored.context as Context);\n\n const listeners = new Set<(snapshot: MachineSnapshot<State, Context>) => void>();\n const tappers = tapper<ActorTapEvent<State, Context, Event>>();\n const disposal = new AbortController();\n const timers = new Set<ReturnType<typeof setTimeout>>();\n const invokes = new Set<AbortController>();\n const queue: RuntimeEvent<State, Context, Event>[] = [];\n let disposed = false;\n let processing = false;\n\n const cancelStateResources = (): void => {\n for (const timer of timers) clearTimeout(timer);\n timers.clear();\n\n for (const controller of invokes) controller.abort();\n invokes.clear();\n };\n\n const dispose = (): void => {\n if (disposed) return;\n\n disposed = true;\n queue.length = 0;\n cancelStateResources();\n listeners.clear();\n tappers.emit({ type: 'dispose' });\n tappers.clear();\n disposal.abort();\n };\n\n const observeError = (error: unknown, context: ActorErrorContext<State, Event>): void => {\n tappers.emit({ error, event: context.event, phase: context.phase, state: context.state, type: 'error' });\n };\n\n const fail = (error: unknown, context: ActorErrorContext<State, Event>): void => {\n observeError(error, context);\n dispose();\n };\n\n const run = (runtimeEvent: RuntimeEvent<State, Context, Event>): void => {\n if (disposed) return;\n\n if (processing) {\n queue.push(runtimeEvent);\n\n return;\n }\n\n processing = true;\n\n try {\n process(runtimeEvent);\n flush();\n } finally {\n processing = false;\n }\n };\n\n const send = (event: Event): void => {\n if (disposed) return;\n\n if (!isMachineEvent(event)) {\n warn('ignored malformed event; expected an object with a string `type`');\n\n return;\n }\n\n run({ event, kind: 'event' });\n };\n\n const runEffects = (effects: readonly Effect<Context, Event>[], state: State, event: Event | undefined): void => {\n for (const effect of effects) {\n if (disposed) return;\n\n try {\n effect({ context: current.context, event, send, signal: disposal.signal });\n } catch (error) {\n fail(error, { event, phase: 'effect', state });\n }\n }\n };\n\n const establishStateResources = (state: State, event: Event | undefined): void => {\n const node = nodeFor(definition, state);\n\n for (const after of node.after ?? []) {\n const timer = setTimeout(() => {\n timers.delete(timer);\n run({ after, kind: 'after' });\n }, after.delay);\n\n timers.add(timer);\n }\n\n for (const invoke of node.invoke ?? []) {\n const controller = new AbortController();\n\n invokes.add(controller);\n\n const capturedContext = current.context;\n const capturedEvent = event;\n\n void Promise.resolve()\n .then(() => invoke.src({ context: capturedContext, event: capturedEvent, signal: controller.signal }))\n .then(\n (result) => {\n invokes.delete(controller);\n\n if (disposed || controller.signal.aborted || !invoke.onDone) return;\n\n try {\n send(invoke.onDone({ context: capturedContext, result }));\n } catch (error) {\n fail(error, { event: capturedEvent, phase: 'invoke', state });\n }\n },\n (error: unknown) => {\n invokes.delete(controller);\n\n if (disposed || controller.signal.aborted) return;\n\n try {\n if (invoke.onError) {\n send(invoke.onError({ context: capturedContext, error }));\n } else {\n fail(error, { event: capturedEvent, phase: 'invoke', state });\n }\n } catch (callbackError) {\n fail(callbackError, { event: capturedEvent, phase: 'invoke', state });\n }\n },\n );\n }\n };\n\n const notify = (event: Event | undefined): void => {\n for (const listener of [...listeners]) {\n if (disposed) return;\n\n try {\n listener(current);\n } catch (error) {\n observeError(error, { event, phase: 'subscriber', state: current.state });\n }\n }\n };\n\n const process = (runtimeEvent: RuntimeEvent<State, Context, Event>): void => {\n const previous = current;\n let outcome: TransitionOutcome<State, Context, Event>;\n\n try {\n outcome = transition(definition, current, runtimeEvent);\n } catch (error) {\n fail(error, {\n event: runtimeEvent.kind === 'event' ? runtimeEvent.event : undefined,\n phase: 'transition',\n state: current.state,\n });\n\n return;\n }\n\n if (outcome.result.type === 'ignored' || !outcome.transition) {\n tappers.emit({ event: outcome.event, snapshot: outcome.result.snapshot, type: 'ignored' });\n return;\n }\n\n const source = nodeFor(definition, previous.state);\n\n current = outcome.result.snapshot;\n tappers.emit({ event: outcome.event, snapshot: current, type: 'transition' });\n cancelStateResources();\n establishStateResources(current.state, outcome.event);\n notify(outcome.event);\n runEffects(source.exit ?? [], previous.state, outcome.event);\n runEffects(outcome.transition.effects ?? [], previous.state, outcome.event);\n runEffects(nodeFor(definition, current.state).entry ?? [], current.state, outcome.event);\n };\n\n const flush = (): void => {\n let transitions = 0;\n\n while (queue.length > 0 && !disposed) {\n transitions += 1;\n\n if (transitions > MAX_TRANSITIONS) {\n fail(\n new ClockworkTransitionLimitError('maximum queued transitions exceeded', { maxTransitions: MAX_TRANSITIONS }),\n {\n phase: 'transition',\n state: current.state,\n },\n );\n\n return;\n }\n\n const next = queue.shift();\n\n if (next) process(next);\n }\n };\n\n establishStateResources(current.state, undefined);\n\n if (!options.snapshot) {\n runEffects(nodeFor(definition, current.state).entry ?? [], current.state, undefined);\n }\n\n return {\n can: (event) => {\n if (disposed) return false;\n\n try {\n if (!isMachineEvent(event)) {\n warn('ignored malformed event; expected an object with a string `type`');\n return false;\n }\n\n return canTransition(definition, current, event);\n } catch (error) {\n fail(error, { event, phase: 'transition', state: current.state });\n return false;\n }\n },\n get disposalSignal() {\n return disposal.signal;\n },\n dispose,\n get disposed() {\n return disposed;\n },\n send,\n get snapshot() {\n return current;\n },\n subscribe(listener) {\n if (disposed) return () => undefined;\n\n listeners.add(listener);\n\n return () => listeners.delete(listener);\n },\n tap(handler, tapOptions) {\n if (disposed) return () => undefined;\n\n return tappers.tap(handler, tapOptions);\n },\n [Symbol.dispose]: dispose,\n };\n};\n\n/** Defines a typed flat finite-state machine. */\nexport const defineMachine =\n <Context extends Record<string, unknown> = Record<string, never>, Event extends MachineEvent = MachineEvent>() =>\n <State extends string>(definition: MachineConfig<State, Context, Event>): Machine<State, Context, Event> => {\n assertDefinition(definition);\n const context = (definition as { readonly context?: Context }).context ?? ({} as Context);\n const initialSnapshot = createSnapshot(definition.initial, context);\n\n return {\n can: (snapshot, event) => canTransition(definition, snapshot, event),\n createActor: (options) => createActor(definition, initialSnapshot, options),\n initialSnapshot,\n transition: (snapshot, event) => transition(definition, snapshot, { event, kind: 'event' }).result,\n };\n };\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"interpret.cjs","names":[],"sources":["../src/interpret.ts"],"sourcesContent":["import { tapper } from '@vielzeug/arsenal';\nimport { warn } from './_dev.js';\nimport { ClockworkDefinitionError, ClockworkSnapshotError, ClockworkTransitionLimitError } from './errors.js';\nimport type {\n Actor,\n ActorErrorContext,\n ActorOptions,\n ActorTapEvent,\n After,\n Effect,\n EventType,\n Machine,\n MachineConfig,\n MachineEvent,\n MachineSnapshot,\n StateNode,\n TransitionResult,\n} from './types.js';\n\nconst MAX_TIMER_MS = 2_147_483_647;\nconst MAX_TRANSITIONS = 1_000;\n\nconst isContextRecord = (value: unknown): value is Record<string, unknown> => {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return false;\n\n const prototype = Object.getPrototypeOf(value);\n\n return prototype === null || prototype === Object.prototype;\n};\n\n/** Fails fast on the definition footguns the type system cannot express: out-of-range\n * timer delays (platform timers fire immediately above 2^31 ms), empty transition\n * arrays, and a context that is not a plain record. Everything else: declared\n * targets, callback shapes, state keys: is compiler-checked in the typed definition. */\nconst assertDefinition = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n): void => {\n const context = (definition as { readonly context?: Context }).context;\n\n if (context !== undefined && !isContextRecord(context)) {\n throw new ClockworkDefinitionError('machine context must be a non-array object record', {});\n }\n\n for (const [state, node] of Object.entries(definition.states) as [string, StateNode<State, Context, Event>][]) {\n for (const [type, input] of Object.entries(node.on ?? {})) {\n if (Array.isArray(input) && input.length === 0) {\n throw new ClockworkDefinitionError('a transition array must not be empty', { state, type });\n }\n }\n\n for (const [index, after] of (node.after ?? []).entries()) {\n if (!Number.isFinite(after.delay) || after.delay < 0 || after.delay > MAX_TIMER_MS) {\n throw new ClockworkDefinitionError(`state \"${state}\" after delay must be between 0 and ${MAX_TIMER_MS}`, {\n delay: after.delay,\n index,\n state,\n });\n }\n }\n }\n};\n\ntype InternalEvent<State extends string, Context extends Record<string, unknown>, Event extends MachineEvent> = {\n readonly after: After<State, Context, Event>;\n readonly kind: 'after';\n};\n\ntype RuntimeEvent<State extends string, Context extends Record<string, unknown>, Event extends MachineEvent> =\n | { readonly event: Event; readonly kind: 'event' }\n | InternalEvent<State, Context, Event>;\n\n/** A transition or delayed transition selected for execution. The reducer's event\n * parameter is whatever the selector matched: the event for a user transition,\n * `undefined` for a timer, which the declared per-type signatures cannot express. */\ntype ExecutableTransition<State extends string, Context extends Record<string, unknown>, Event extends MachineEvent> = {\n readonly effects?: readonly Effect<Context, Event>[];\n readonly reduce?: (args: { readonly context: Readonly<Context>; readonly event: Event | undefined }) => Context;\n readonly target: State;\n};\n\ntype SelectedTransition<State extends string, Context extends Record<string, unknown>, Event extends MachineEvent> = {\n readonly event: Event | undefined;\n readonly transition: ExecutableTransition<State, Context, Event>;\n};\n\ntype TransitionOutcome<State extends string, Context extends Record<string, unknown>, Event extends MachineEvent> = {\n readonly event: Event | undefined;\n readonly result: TransitionResult<State, Context>;\n readonly transition?: ExecutableTransition<State, Context, Event>;\n};\n\nconst createSnapshot = <State extends string, Context extends Record<string, unknown>>(\n state: State,\n context: Context,\n): MachineSnapshot<State, Context> => {\n const cloned = Object.assign(Object.create(Object.getPrototypeOf(context)) as Context, context);\n\n return Object.freeze({ context: Object.freeze(cloned), state });\n};\n\nconst normalizeSnapshot = <State extends string, Context extends Record<string, unknown>>(\n snapshot: MachineSnapshot<State, Context>,\n): MachineSnapshot<State, Context> =>\n Object.isFrozen(snapshot) && Object.isFrozen(snapshot.context)\n ? snapshot\n : createSnapshot(snapshot.state, snapshot.context as Context);\n\nconst invalidSnapshot = (state: unknown): never => {\n throw new ClockworkSnapshotError(`snapshot state \"${String(state)}\" is not declared`, { state });\n};\n\nconst isMachineEvent = (event: unknown): event is MachineEvent =>\n typeof event === 'object' && event !== null && typeof (event as { type?: unknown }).type === 'string';\n\n/** Reads a declared state node. The own-property guard keeps prototype keys such as\n * `constructor` or `__proto__` from reading as declared states. */\nconst nodeFor = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n state: State,\n) => (Object.hasOwn(definition.states, state) ? definition.states[state] : invalidSnapshot(state));\n\nconst assertSnapshot = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n snapshot: MachineSnapshot<State, Context>,\n): void => {\n if (!isContextRecord(snapshot.context)) {\n throw new ClockworkSnapshotError('snapshot context must be a non-array object record', {});\n }\n\n nodeFor(definition, snapshot.state);\n};\n\nconst selectTransition = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n snapshot: MachineSnapshot<State, Context>,\n runtimeEvent: RuntimeEvent<State, Context, Event>,\n): SelectedTransition<State, Context, Event> | undefined => {\n assertSnapshot(definition, snapshot);\n const node = nodeFor(definition, snapshot.state);\n\n if (runtimeEvent.kind === 'after') {\n if (!node.after || !node.after.includes(runtimeEvent.after)) return undefined;\n\n if (!runtimeEvent.after.guard || runtimeEvent.after.guard({ context: snapshot.context, event: undefined })) {\n return { event: undefined, transition: runtimeEvent.after as ExecutableTransition<State, Context, Event> };\n }\n\n return undefined;\n }\n\n const on = node.on;\n\n if (!on || !Object.hasOwn(on, runtimeEvent.event.type)) return undefined;\n\n const input = on[runtimeEvent.event.type as EventType<Event>];\n const candidates = Array.isArray(input) ? input : [input];\n\n for (const candidate of candidates) {\n if (!candidate.guard || candidate.guard({ context: snapshot.context, event: runtimeEvent.event })) {\n return { event: runtimeEvent.event, transition: candidate as ExecutableTransition<State, Context, Event> };\n }\n }\n\n return undefined;\n};\n\nconst transition = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n snapshot: MachineSnapshot<State, Context>,\n runtimeEvent: RuntimeEvent<State, Context, Event>,\n): TransitionOutcome<State, Context, Event> => {\n const selected = selectTransition(definition, snapshot, runtimeEvent);\n\n if (!selected) {\n return {\n event: runtimeEvent.kind === 'event' ? runtimeEvent.event : undefined,\n result: { snapshot: normalizeSnapshot(snapshot), type: 'ignored' },\n };\n }\n\n const nextContext = selected.transition.reduce\n ? selected.transition.reduce({ context: snapshot.context, event: selected.event })\n : snapshot.context;\n\n if (!isContextRecord(nextContext)) {\n throw new ClockworkSnapshotError('a reducer must return a non-array object record', {\n state: snapshot.state,\n });\n }\n\n return {\n event: selected.event,\n result: { snapshot: createSnapshot(selected.transition.target, nextContext as Context), type: 'transition' },\n transition: selected.transition,\n };\n};\n\nconst canTransition = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n snapshot: MachineSnapshot<State, Context>,\n event: Event,\n): boolean => selectTransition(definition, snapshot, { event, kind: 'event' }) !== undefined;\n\nconst createActor = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n initialSnapshot: MachineSnapshot<State, Context>,\n options: ActorOptions<State, Context> = {},\n): Actor<State, Context, Event> => {\n const restored = options.snapshot ?? initialSnapshot;\n\n assertSnapshot(definition, restored);\n let current = createSnapshot(restored.state, restored.context as Context);\n\n const listeners = new Set<(snapshot: MachineSnapshot<State, Context>) => void>();\n const tappers = tapper<ActorTapEvent<State, Context, Event>>();\n const disposal = new AbortController();\n const timers = new Set<ReturnType<typeof setTimeout>>();\n const invokes = new Set<AbortController>();\n const queue: RuntimeEvent<State, Context, Event>[] = [];\n let disposed = false;\n let processing = false;\n\n const cancelStateResources = (): void => {\n for (const timer of timers) clearTimeout(timer);\n timers.clear();\n\n for (const controller of invokes) controller.abort();\n invokes.clear();\n };\n\n const dispose = (): void => {\n if (disposed) return;\n\n disposed = true;\n queue.length = 0;\n cancelStateResources();\n listeners.clear();\n tappers.emit({ type: 'dispose' });\n tappers.clear();\n disposal.abort();\n };\n\n const observeError = (error: unknown, context: ActorErrorContext<State, Event>): void => {\n tappers.emit({ error, event: context.event, phase: context.phase, state: context.state, type: 'error' });\n };\n\n const fail = (error: unknown, context: ActorErrorContext<State, Event>): void => {\n observeError(error, context);\n dispose();\n };\n\n const run = (runtimeEvent: RuntimeEvent<State, Context, Event>): void => {\n if (disposed) return;\n\n if (processing) {\n queue.push(runtimeEvent);\n\n return;\n }\n\n processing = true;\n\n try {\n process(runtimeEvent);\n flush();\n } finally {\n processing = false;\n }\n };\n\n const send = (event: Event): void => {\n if (disposed) return;\n\n if (!isMachineEvent(event)) {\n warn('ignored malformed event; expected an object with a string `type`');\n\n return;\n }\n\n run({ event, kind: 'event' });\n };\n\n const runEffects = (effects: readonly Effect<Context, Event>[], state: State, event: Event | undefined): void => {\n for (const effect of effects) {\n if (disposed) return;\n\n try {\n effect({ context: current.context, event, send, signal: disposal.signal });\n } catch (error) {\n fail(error, { event, phase: 'effect', state });\n }\n }\n };\n\n const establishStateResources = (state: State, event: Event | undefined): void => {\n const node = nodeFor(definition, state);\n\n for (const after of node.after ?? []) {\n const timer = setTimeout(() => {\n timers.delete(timer);\n run({ after, kind: 'after' });\n }, after.delay);\n\n timers.add(timer);\n }\n\n for (const invoke of node.invoke ?? []) {\n const controller = new AbortController();\n\n invokes.add(controller);\n\n const capturedContext = current.context;\n const capturedEvent = event;\n\n void Promise.resolve()\n .then(() => invoke.src({ context: capturedContext, event: capturedEvent, signal: controller.signal }))\n .then(\n (result) => {\n invokes.delete(controller);\n\n if (disposed || controller.signal.aborted || !invoke.onDone) return;\n\n try {\n send(invoke.onDone({ context: capturedContext, result }));\n } catch (error) {\n fail(error, { event: capturedEvent, phase: 'invoke', state });\n }\n },\n (error: unknown) => {\n invokes.delete(controller);\n\n if (disposed || controller.signal.aborted) return;\n\n try {\n if (invoke.onError) {\n send(invoke.onError({ context: capturedContext, error }));\n } else {\n fail(error, { event: capturedEvent, phase: 'invoke', state });\n }\n } catch (callbackError) {\n fail(callbackError, { event: capturedEvent, phase: 'invoke', state });\n }\n },\n );\n }\n };\n\n const notify = (event: Event | undefined): void => {\n for (const listener of [...listeners]) {\n if (disposed) return;\n\n try {\n listener(current);\n } catch (error) {\n observeError(error, { event, phase: 'subscriber', state: current.state });\n }\n }\n };\n\n const process = (runtimeEvent: RuntimeEvent<State, Context, Event>): void => {\n const previous = current;\n let outcome: TransitionOutcome<State, Context, Event>;\n\n try {\n outcome = transition(definition, current, runtimeEvent);\n } catch (error) {\n fail(error, {\n event: runtimeEvent.kind === 'event' ? runtimeEvent.event : undefined,\n phase: 'transition',\n state: current.state,\n });\n\n return;\n }\n\n if (outcome.result.type === 'ignored' || !outcome.transition) {\n tappers.emit({ event: outcome.event, snapshot: outcome.result.snapshot, type: 'ignored' });\n return;\n }\n\n const source = nodeFor(definition, previous.state);\n\n current = outcome.result.snapshot;\n tappers.emit({ event: outcome.event, snapshot: current, type: 'transition' });\n cancelStateResources();\n establishStateResources(current.state, outcome.event);\n notify(outcome.event);\n runEffects(source.exit ?? [], previous.state, outcome.event);\n runEffects(outcome.transition.effects ?? [], previous.state, outcome.event);\n runEffects(nodeFor(definition, current.state).entry ?? [], current.state, outcome.event);\n };\n\n const flush = (): void => {\n let transitions = 0;\n\n while (queue.length > 0 && !disposed) {\n transitions += 1;\n\n if (transitions > MAX_TRANSITIONS) {\n fail(\n new ClockworkTransitionLimitError('maximum queued transitions exceeded', { maxTransitions: MAX_TRANSITIONS }),\n {\n phase: 'transition',\n state: current.state,\n },\n );\n\n return;\n }\n\n const next = queue.shift();\n\n if (next) process(next);\n }\n };\n\n establishStateResources(current.state, undefined);\n\n if (!options.snapshot) {\n runEffects(nodeFor(definition, current.state).entry ?? [], current.state, undefined);\n }\n\n return {\n can: (event) => {\n if (disposed) return false;\n\n try {\n if (!isMachineEvent(event)) {\n warn('ignored malformed event; expected an object with a string `type`');\n return false;\n }\n\n return canTransition(definition, current, event);\n } catch (error) {\n fail(error, { event, phase: 'transition', state: current.state });\n return false;\n }\n },\n get disposalSignal() {\n return disposal.signal;\n },\n dispose,\n get disposed() {\n return disposed;\n },\n send,\n get snapshot() {\n return current;\n },\n subscribe(listener) {\n if (disposed) return () => undefined;\n\n listeners.add(listener);\n\n return () => listeners.delete(listener);\n },\n tap(handler, tapOptions) {\n if (disposed) return () => undefined;\n\n return tappers.tap(handler, tapOptions);\n },\n [Symbol.dispose]: dispose,\n };\n};\n\n/** Defines a typed flat finite-state machine. */\nexport const defineMachine =\n <Context extends Record<string, unknown> = Record<string, never>, Event extends MachineEvent = MachineEvent>() =>\n <State extends string>(definition: MachineConfig<State, Context, Event>): Machine<State, Context, Event> => {\n assertDefinition(definition);\n const context = (definition as { readonly context?: Context }).context ?? ({} as Context);\n const initialSnapshot = createSnapshot(definition.initial, context);\n\n return {\n can: (snapshot, event) => canTransition(definition, snapshot, event),\n createActor: (options) => createActor(definition, initialSnapshot, options),\n initialSnapshot,\n transition: (snapshot, event) => transition(definition, snapshot, { event, kind: 'event' }).result,\n };\n };\n"],"mappings":"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"}
|
package/dist/interpret.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"interpret.js","names":[],"sources":["../src/interpret.ts"],"sourcesContent":["import { tapper } from '@vielzeug/arsenal';\nimport { warn } from './_dev.js';\nimport { ClockworkDefinitionError, ClockworkSnapshotError, ClockworkTransitionLimitError } from './errors.js';\nimport type {\n Actor,\n ActorErrorContext,\n ActorOptions,\n ActorTapEvent,\n After,\n Effect,\n EventType,\n Machine,\n MachineConfig,\n MachineEvent,\n MachineSnapshot,\n StateNode,\n TransitionResult,\n} from './types.js';\n\nconst MAX_TIMER_MS = 2_147_483_647;\nconst MAX_TRANSITIONS = 1_000;\n\nconst isContextRecord = (value: unknown): value is Record<string, unknown> => {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return false;\n\n const prototype = Object.getPrototypeOf(value);\n\n return prototype === null || prototype === Object.prototype;\n};\n\n/** Fails fast on the definition footguns the type system cannot express: out-of-range\n * timer delays (platform timers fire immediately above 2^31 ms), empty transition\n * arrays, and a context that is not a plain record. Everything else — declared\n * targets, callback shapes, state keys — is compiler-checked in the typed definition. */\nconst assertDefinition = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n): void => {\n const context = (definition as { readonly context?: Context }).context;\n\n if (context !== undefined && !isContextRecord(context)) {\n throw new ClockworkDefinitionError('machine context must be a non-array object record', {});\n }\n\n for (const [state, node] of Object.entries(definition.states) as [string, StateNode<State, Context, Event>][]) {\n for (const [type, input] of Object.entries(node.on ?? {})) {\n if (Array.isArray(input) && input.length === 0) {\n throw new ClockworkDefinitionError('a transition array must not be empty', { state, type });\n }\n }\n\n for (const [index, after] of (node.after ?? []).entries()) {\n if (!Number.isFinite(after.delay) || after.delay < 0 || after.delay > MAX_TIMER_MS) {\n throw new ClockworkDefinitionError(`state \"${state}\" after delay must be between 0 and ${MAX_TIMER_MS}`, {\n delay: after.delay,\n index,\n state,\n });\n }\n }\n }\n};\n\ntype InternalEvent<State extends string, Context extends Record<string, unknown>, Event extends MachineEvent> = {\n readonly after: After<State, Context, Event>;\n readonly kind: 'after';\n};\n\ntype RuntimeEvent<State extends string, Context extends Record<string, unknown>, Event extends MachineEvent> =\n | { readonly event: Event; readonly kind: 'event' }\n | InternalEvent<State, Context, Event>;\n\n/** A transition or delayed transition selected for execution. The reducer's event\n * parameter is whatever the selector matched — the event for a user transition,\n * `undefined` for a timer — which the declared per-type signatures cannot express. */\ntype ExecutableTransition<State extends string, Context extends Record<string, unknown>, Event extends MachineEvent> = {\n readonly effects?: readonly Effect<Context, Event>[];\n readonly reduce?: (args: { readonly context: Readonly<Context>; readonly event: Event | undefined }) => Context;\n readonly target: State;\n};\n\ntype SelectedTransition<State extends string, Context extends Record<string, unknown>, Event extends MachineEvent> = {\n readonly event: Event | undefined;\n readonly transition: ExecutableTransition<State, Context, Event>;\n};\n\ntype TransitionOutcome<State extends string, Context extends Record<string, unknown>, Event extends MachineEvent> = {\n readonly event: Event | undefined;\n readonly result: TransitionResult<State, Context>;\n readonly transition?: ExecutableTransition<State, Context, Event>;\n};\n\nconst createSnapshot = <State extends string, Context extends Record<string, unknown>>(\n state: State,\n context: Context,\n): MachineSnapshot<State, Context> => {\n const cloned = Object.assign(Object.create(Object.getPrototypeOf(context)) as Context, context);\n\n return Object.freeze({ context: Object.freeze(cloned), state });\n};\n\nconst normalizeSnapshot = <State extends string, Context extends Record<string, unknown>>(\n snapshot: MachineSnapshot<State, Context>,\n): MachineSnapshot<State, Context> =>\n Object.isFrozen(snapshot) && Object.isFrozen(snapshot.context)\n ? snapshot\n : createSnapshot(snapshot.state, snapshot.context as Context);\n\nconst invalidSnapshot = (state: unknown): never => {\n throw new ClockworkSnapshotError(`snapshot state \"${String(state)}\" is not declared`, { state });\n};\n\nconst isMachineEvent = (event: unknown): event is MachineEvent =>\n typeof event === 'object' && event !== null && typeof (event as { type?: unknown }).type === 'string';\n\n/** Reads a declared state node. The own-property guard keeps prototype keys such as\n * `constructor` or `__proto__` from reading as declared states. */\nconst nodeFor = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n state: State,\n) => (Object.hasOwn(definition.states, state) ? definition.states[state] : invalidSnapshot(state));\n\nconst assertSnapshot = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n snapshot: MachineSnapshot<State, Context>,\n): void => {\n if (!isContextRecord(snapshot.context)) {\n throw new ClockworkSnapshotError('snapshot context must be a non-array object record', {});\n }\n\n nodeFor(definition, snapshot.state);\n};\n\nconst selectTransition = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n snapshot: MachineSnapshot<State, Context>,\n runtimeEvent: RuntimeEvent<State, Context, Event>,\n): SelectedTransition<State, Context, Event> | undefined => {\n assertSnapshot(definition, snapshot);\n const node = nodeFor(definition, snapshot.state);\n\n if (runtimeEvent.kind === 'after') {\n if (!node.after || !node.after.includes(runtimeEvent.after)) return undefined;\n\n if (!runtimeEvent.after.guard || runtimeEvent.after.guard({ context: snapshot.context, event: undefined })) {\n return { event: undefined, transition: runtimeEvent.after as ExecutableTransition<State, Context, Event> };\n }\n\n return undefined;\n }\n\n const on = node.on;\n\n if (!on || !Object.hasOwn(on, runtimeEvent.event.type)) return undefined;\n\n const input = on[runtimeEvent.event.type as EventType<Event>];\n const candidates = Array.isArray(input) ? input : [input];\n\n for (const candidate of candidates) {\n if (!candidate.guard || candidate.guard({ context: snapshot.context, event: runtimeEvent.event })) {\n return { event: runtimeEvent.event, transition: candidate as ExecutableTransition<State, Context, Event> };\n }\n }\n\n return undefined;\n};\n\nconst transition = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n snapshot: MachineSnapshot<State, Context>,\n runtimeEvent: RuntimeEvent<State, Context, Event>,\n): TransitionOutcome<State, Context, Event> => {\n const selected = selectTransition(definition, snapshot, runtimeEvent);\n\n if (!selected) {\n return {\n event: runtimeEvent.kind === 'event' ? runtimeEvent.event : undefined,\n result: { snapshot: normalizeSnapshot(snapshot), type: 'ignored' },\n };\n }\n\n const nextContext = selected.transition.reduce\n ? selected.transition.reduce({ context: snapshot.context, event: selected.event })\n : snapshot.context;\n\n if (!isContextRecord(nextContext)) {\n throw new ClockworkSnapshotError('a reducer must return a non-array object record', {\n state: snapshot.state,\n });\n }\n\n return {\n event: selected.event,\n result: { snapshot: createSnapshot(selected.transition.target, nextContext as Context), type: 'transition' },\n transition: selected.transition,\n };\n};\n\nconst canTransition = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n snapshot: MachineSnapshot<State, Context>,\n event: Event,\n): boolean => selectTransition(definition, snapshot, { event, kind: 'event' }) !== undefined;\n\nconst createActor = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n initialSnapshot: MachineSnapshot<State, Context>,\n options: ActorOptions<State, Context> = {},\n): Actor<State, Context, Event> => {\n const restored = options.snapshot ?? initialSnapshot;\n\n assertSnapshot(definition, restored);\n let current = createSnapshot(restored.state, restored.context as Context);\n\n const listeners = new Set<(snapshot: MachineSnapshot<State, Context>) => void>();\n const tappers = tapper<ActorTapEvent<State, Context, Event>>();\n const disposal = new AbortController();\n const timers = new Set<ReturnType<typeof setTimeout>>();\n const invokes = new Set<AbortController>();\n const queue: RuntimeEvent<State, Context, Event>[] = [];\n let disposed = false;\n let processing = false;\n\n const cancelStateResources = (): void => {\n for (const timer of timers) clearTimeout(timer);\n timers.clear();\n\n for (const controller of invokes) controller.abort();\n invokes.clear();\n };\n\n const dispose = (): void => {\n if (disposed) return;\n\n disposed = true;\n queue.length = 0;\n cancelStateResources();\n listeners.clear();\n tappers.emit({ type: 'dispose' });\n tappers.clear();\n disposal.abort();\n };\n\n const observeError = (error: unknown, context: ActorErrorContext<State, Event>): void => {\n tappers.emit({ error, event: context.event, phase: context.phase, state: context.state, type: 'error' });\n };\n\n const fail = (error: unknown, context: ActorErrorContext<State, Event>): void => {\n observeError(error, context);\n dispose();\n };\n\n const run = (runtimeEvent: RuntimeEvent<State, Context, Event>): void => {\n if (disposed) return;\n\n if (processing) {\n queue.push(runtimeEvent);\n\n return;\n }\n\n processing = true;\n\n try {\n process(runtimeEvent);\n flush();\n } finally {\n processing = false;\n }\n };\n\n const send = (event: Event): void => {\n if (disposed) return;\n\n if (!isMachineEvent(event)) {\n warn('ignored malformed event; expected an object with a string `type`');\n\n return;\n }\n\n run({ event, kind: 'event' });\n };\n\n const runEffects = (effects: readonly Effect<Context, Event>[], state: State, event: Event | undefined): void => {\n for (const effect of effects) {\n if (disposed) return;\n\n try {\n effect({ context: current.context, event, send, signal: disposal.signal });\n } catch (error) {\n fail(error, { event, phase: 'effect', state });\n }\n }\n };\n\n const establishStateResources = (state: State, event: Event | undefined): void => {\n const node = nodeFor(definition, state);\n\n for (const after of node.after ?? []) {\n const timer = setTimeout(() => {\n timers.delete(timer);\n run({ after, kind: 'after' });\n }, after.delay);\n\n timers.add(timer);\n }\n\n for (const invoke of node.invoke ?? []) {\n const controller = new AbortController();\n\n invokes.add(controller);\n\n const capturedContext = current.context;\n const capturedEvent = event;\n\n void Promise.resolve()\n .then(() => invoke.src({ context: capturedContext, event: capturedEvent, signal: controller.signal }))\n .then(\n (result) => {\n invokes.delete(controller);\n\n if (disposed || controller.signal.aborted || !invoke.onDone) return;\n\n try {\n send(invoke.onDone({ context: capturedContext, result }));\n } catch (error) {\n fail(error, { event: capturedEvent, phase: 'invoke', state });\n }\n },\n (error: unknown) => {\n invokes.delete(controller);\n\n if (disposed || controller.signal.aborted) return;\n\n try {\n if (invoke.onError) {\n send(invoke.onError({ context: capturedContext, error }));\n } else {\n fail(error, { event: capturedEvent, phase: 'invoke', state });\n }\n } catch (callbackError) {\n fail(callbackError, { event: capturedEvent, phase: 'invoke', state });\n }\n },\n );\n }\n };\n\n const notify = (event: Event | undefined): void => {\n for (const listener of [...listeners]) {\n if (disposed) return;\n\n try {\n listener(current);\n } catch (error) {\n observeError(error, { event, phase: 'subscriber', state: current.state });\n }\n }\n };\n\n const process = (runtimeEvent: RuntimeEvent<State, Context, Event>): void => {\n const previous = current;\n let outcome: TransitionOutcome<State, Context, Event>;\n\n try {\n outcome = transition(definition, current, runtimeEvent);\n } catch (error) {\n fail(error, {\n event: runtimeEvent.kind === 'event' ? runtimeEvent.event : undefined,\n phase: 'transition',\n state: current.state,\n });\n\n return;\n }\n\n if (outcome.result.type === 'ignored' || !outcome.transition) {\n tappers.emit({ event: outcome.event, snapshot: outcome.result.snapshot, type: 'ignored' });\n return;\n }\n\n const source = nodeFor(definition, previous.state);\n\n current = outcome.result.snapshot;\n tappers.emit({ event: outcome.event, snapshot: current, type: 'transition' });\n cancelStateResources();\n establishStateResources(current.state, outcome.event);\n notify(outcome.event);\n runEffects(source.exit ?? [], previous.state, outcome.event);\n runEffects(outcome.transition.effects ?? [], previous.state, outcome.event);\n runEffects(nodeFor(definition, current.state).entry ?? [], current.state, outcome.event);\n };\n\n const flush = (): void => {\n let transitions = 0;\n\n while (queue.length > 0 && !disposed) {\n transitions += 1;\n\n if (transitions > MAX_TRANSITIONS) {\n fail(\n new ClockworkTransitionLimitError('maximum queued transitions exceeded', { maxTransitions: MAX_TRANSITIONS }),\n {\n phase: 'transition',\n state: current.state,\n },\n );\n\n return;\n }\n\n const next = queue.shift();\n\n if (next) process(next);\n }\n };\n\n establishStateResources(current.state, undefined);\n\n if (!options.snapshot) {\n runEffects(nodeFor(definition, current.state).entry ?? [], current.state, undefined);\n }\n\n return {\n can: (event) => {\n if (disposed) return false;\n\n try {\n if (!isMachineEvent(event)) {\n warn('ignored malformed event; expected an object with a string `type`');\n return false;\n }\n\n return canTransition(definition, current, event);\n } catch (error) {\n fail(error, { event, phase: 'transition', state: current.state });\n return false;\n }\n },\n get disposalSignal() {\n return disposal.signal;\n },\n dispose,\n get disposed() {\n return disposed;\n },\n send,\n get snapshot() {\n return current;\n },\n subscribe(listener) {\n if (disposed) return () => undefined;\n\n listeners.add(listener);\n\n return () => listeners.delete(listener);\n },\n tap(handler, tapOptions) {\n if (disposed) return () => undefined;\n\n return tappers.tap(handler, tapOptions);\n },\n [Symbol.dispose]: dispose,\n };\n};\n\n/** Defines a typed flat finite-state machine. */\nexport const defineMachine =\n <Context extends Record<string, unknown> = Record<string, never>, Event extends MachineEvent = MachineEvent>() =>\n <State extends string>(definition: MachineConfig<State, Context, Event>): Machine<State, Context, Event> => {\n assertDefinition(definition);\n const context = (definition as { readonly context?: Context }).context ?? ({} as Context);\n const initialSnapshot = createSnapshot(definition.initial, context);\n\n return {\n can: (snapshot, event) => canTransition(definition, snapshot, event),\n createActor: (options) => createActor(definition, initialSnapshot, options),\n initialSnapshot,\n transition: (snapshot, event) => transition(definition, snapshot, { event, kind: 'event' }).result,\n };\n };\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"interpret.js","names":[],"sources":["../src/interpret.ts"],"sourcesContent":["import { tapper } from '@vielzeug/arsenal';\nimport { warn } from './_dev.js';\nimport { ClockworkDefinitionError, ClockworkSnapshotError, ClockworkTransitionLimitError } from './errors.js';\nimport type {\n Actor,\n ActorErrorContext,\n ActorOptions,\n ActorTapEvent,\n After,\n Effect,\n EventType,\n Machine,\n MachineConfig,\n MachineEvent,\n MachineSnapshot,\n StateNode,\n TransitionResult,\n} from './types.js';\n\nconst MAX_TIMER_MS = 2_147_483_647;\nconst MAX_TRANSITIONS = 1_000;\n\nconst isContextRecord = (value: unknown): value is Record<string, unknown> => {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return false;\n\n const prototype = Object.getPrototypeOf(value);\n\n return prototype === null || prototype === Object.prototype;\n};\n\n/** Fails fast on the definition footguns the type system cannot express: out-of-range\n * timer delays (platform timers fire immediately above 2^31 ms), empty transition\n * arrays, and a context that is not a plain record. Everything else: declared\n * targets, callback shapes, state keys: is compiler-checked in the typed definition. */\nconst assertDefinition = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n): void => {\n const context = (definition as { readonly context?: Context }).context;\n\n if (context !== undefined && !isContextRecord(context)) {\n throw new ClockworkDefinitionError('machine context must be a non-array object record', {});\n }\n\n for (const [state, node] of Object.entries(definition.states) as [string, StateNode<State, Context, Event>][]) {\n for (const [type, input] of Object.entries(node.on ?? {})) {\n if (Array.isArray(input) && input.length === 0) {\n throw new ClockworkDefinitionError('a transition array must not be empty', { state, type });\n }\n }\n\n for (const [index, after] of (node.after ?? []).entries()) {\n if (!Number.isFinite(after.delay) || after.delay < 0 || after.delay > MAX_TIMER_MS) {\n throw new ClockworkDefinitionError(`state \"${state}\" after delay must be between 0 and ${MAX_TIMER_MS}`, {\n delay: after.delay,\n index,\n state,\n });\n }\n }\n }\n};\n\ntype InternalEvent<State extends string, Context extends Record<string, unknown>, Event extends MachineEvent> = {\n readonly after: After<State, Context, Event>;\n readonly kind: 'after';\n};\n\ntype RuntimeEvent<State extends string, Context extends Record<string, unknown>, Event extends MachineEvent> =\n | { readonly event: Event; readonly kind: 'event' }\n | InternalEvent<State, Context, Event>;\n\n/** A transition or delayed transition selected for execution. The reducer's event\n * parameter is whatever the selector matched: the event for a user transition,\n * `undefined` for a timer, which the declared per-type signatures cannot express. */\ntype ExecutableTransition<State extends string, Context extends Record<string, unknown>, Event extends MachineEvent> = {\n readonly effects?: readonly Effect<Context, Event>[];\n readonly reduce?: (args: { readonly context: Readonly<Context>; readonly event: Event | undefined }) => Context;\n readonly target: State;\n};\n\ntype SelectedTransition<State extends string, Context extends Record<string, unknown>, Event extends MachineEvent> = {\n readonly event: Event | undefined;\n readonly transition: ExecutableTransition<State, Context, Event>;\n};\n\ntype TransitionOutcome<State extends string, Context extends Record<string, unknown>, Event extends MachineEvent> = {\n readonly event: Event | undefined;\n readonly result: TransitionResult<State, Context>;\n readonly transition?: ExecutableTransition<State, Context, Event>;\n};\n\nconst createSnapshot = <State extends string, Context extends Record<string, unknown>>(\n state: State,\n context: Context,\n): MachineSnapshot<State, Context> => {\n const cloned = Object.assign(Object.create(Object.getPrototypeOf(context)) as Context, context);\n\n return Object.freeze({ context: Object.freeze(cloned), state });\n};\n\nconst normalizeSnapshot = <State extends string, Context extends Record<string, unknown>>(\n snapshot: MachineSnapshot<State, Context>,\n): MachineSnapshot<State, Context> =>\n Object.isFrozen(snapshot) && Object.isFrozen(snapshot.context)\n ? snapshot\n : createSnapshot(snapshot.state, snapshot.context as Context);\n\nconst invalidSnapshot = (state: unknown): never => {\n throw new ClockworkSnapshotError(`snapshot state \"${String(state)}\" is not declared`, { state });\n};\n\nconst isMachineEvent = (event: unknown): event is MachineEvent =>\n typeof event === 'object' && event !== null && typeof (event as { type?: unknown }).type === 'string';\n\n/** Reads a declared state node. The own-property guard keeps prototype keys such as\n * `constructor` or `__proto__` from reading as declared states. */\nconst nodeFor = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n state: State,\n) => (Object.hasOwn(definition.states, state) ? definition.states[state] : invalidSnapshot(state));\n\nconst assertSnapshot = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n snapshot: MachineSnapshot<State, Context>,\n): void => {\n if (!isContextRecord(snapshot.context)) {\n throw new ClockworkSnapshotError('snapshot context must be a non-array object record', {});\n }\n\n nodeFor(definition, snapshot.state);\n};\n\nconst selectTransition = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n snapshot: MachineSnapshot<State, Context>,\n runtimeEvent: RuntimeEvent<State, Context, Event>,\n): SelectedTransition<State, Context, Event> | undefined => {\n assertSnapshot(definition, snapshot);\n const node = nodeFor(definition, snapshot.state);\n\n if (runtimeEvent.kind === 'after') {\n if (!node.after || !node.after.includes(runtimeEvent.after)) return undefined;\n\n if (!runtimeEvent.after.guard || runtimeEvent.after.guard({ context: snapshot.context, event: undefined })) {\n return { event: undefined, transition: runtimeEvent.after as ExecutableTransition<State, Context, Event> };\n }\n\n return undefined;\n }\n\n const on = node.on;\n\n if (!on || !Object.hasOwn(on, runtimeEvent.event.type)) return undefined;\n\n const input = on[runtimeEvent.event.type as EventType<Event>];\n const candidates = Array.isArray(input) ? input : [input];\n\n for (const candidate of candidates) {\n if (!candidate.guard || candidate.guard({ context: snapshot.context, event: runtimeEvent.event })) {\n return { event: runtimeEvent.event, transition: candidate as ExecutableTransition<State, Context, Event> };\n }\n }\n\n return undefined;\n};\n\nconst transition = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n snapshot: MachineSnapshot<State, Context>,\n runtimeEvent: RuntimeEvent<State, Context, Event>,\n): TransitionOutcome<State, Context, Event> => {\n const selected = selectTransition(definition, snapshot, runtimeEvent);\n\n if (!selected) {\n return {\n event: runtimeEvent.kind === 'event' ? runtimeEvent.event : undefined,\n result: { snapshot: normalizeSnapshot(snapshot), type: 'ignored' },\n };\n }\n\n const nextContext = selected.transition.reduce\n ? selected.transition.reduce({ context: snapshot.context, event: selected.event })\n : snapshot.context;\n\n if (!isContextRecord(nextContext)) {\n throw new ClockworkSnapshotError('a reducer must return a non-array object record', {\n state: snapshot.state,\n });\n }\n\n return {\n event: selected.event,\n result: { snapshot: createSnapshot(selected.transition.target, nextContext as Context), type: 'transition' },\n transition: selected.transition,\n };\n};\n\nconst canTransition = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n snapshot: MachineSnapshot<State, Context>,\n event: Event,\n): boolean => selectTransition(definition, snapshot, { event, kind: 'event' }) !== undefined;\n\nconst createActor = <State extends string, Context extends Record<string, unknown>, Event extends MachineEvent>(\n definition: MachineConfig<State, Context, Event>,\n initialSnapshot: MachineSnapshot<State, Context>,\n options: ActorOptions<State, Context> = {},\n): Actor<State, Context, Event> => {\n const restored = options.snapshot ?? initialSnapshot;\n\n assertSnapshot(definition, restored);\n let current = createSnapshot(restored.state, restored.context as Context);\n\n const listeners = new Set<(snapshot: MachineSnapshot<State, Context>) => void>();\n const tappers = tapper<ActorTapEvent<State, Context, Event>>();\n const disposal = new AbortController();\n const timers = new Set<ReturnType<typeof setTimeout>>();\n const invokes = new Set<AbortController>();\n const queue: RuntimeEvent<State, Context, Event>[] = [];\n let disposed = false;\n let processing = false;\n\n const cancelStateResources = (): void => {\n for (const timer of timers) clearTimeout(timer);\n timers.clear();\n\n for (const controller of invokes) controller.abort();\n invokes.clear();\n };\n\n const dispose = (): void => {\n if (disposed) return;\n\n disposed = true;\n queue.length = 0;\n cancelStateResources();\n listeners.clear();\n tappers.emit({ type: 'dispose' });\n tappers.clear();\n disposal.abort();\n };\n\n const observeError = (error: unknown, context: ActorErrorContext<State, Event>): void => {\n tappers.emit({ error, event: context.event, phase: context.phase, state: context.state, type: 'error' });\n };\n\n const fail = (error: unknown, context: ActorErrorContext<State, Event>): void => {\n observeError(error, context);\n dispose();\n };\n\n const run = (runtimeEvent: RuntimeEvent<State, Context, Event>): void => {\n if (disposed) return;\n\n if (processing) {\n queue.push(runtimeEvent);\n\n return;\n }\n\n processing = true;\n\n try {\n process(runtimeEvent);\n flush();\n } finally {\n processing = false;\n }\n };\n\n const send = (event: Event): void => {\n if (disposed) return;\n\n if (!isMachineEvent(event)) {\n warn('ignored malformed event; expected an object with a string `type`');\n\n return;\n }\n\n run({ event, kind: 'event' });\n };\n\n const runEffects = (effects: readonly Effect<Context, Event>[], state: State, event: Event | undefined): void => {\n for (const effect of effects) {\n if (disposed) return;\n\n try {\n effect({ context: current.context, event, send, signal: disposal.signal });\n } catch (error) {\n fail(error, { event, phase: 'effect', state });\n }\n }\n };\n\n const establishStateResources = (state: State, event: Event | undefined): void => {\n const node = nodeFor(definition, state);\n\n for (const after of node.after ?? []) {\n const timer = setTimeout(() => {\n timers.delete(timer);\n run({ after, kind: 'after' });\n }, after.delay);\n\n timers.add(timer);\n }\n\n for (const invoke of node.invoke ?? []) {\n const controller = new AbortController();\n\n invokes.add(controller);\n\n const capturedContext = current.context;\n const capturedEvent = event;\n\n void Promise.resolve()\n .then(() => invoke.src({ context: capturedContext, event: capturedEvent, signal: controller.signal }))\n .then(\n (result) => {\n invokes.delete(controller);\n\n if (disposed || controller.signal.aborted || !invoke.onDone) return;\n\n try {\n send(invoke.onDone({ context: capturedContext, result }));\n } catch (error) {\n fail(error, { event: capturedEvent, phase: 'invoke', state });\n }\n },\n (error: unknown) => {\n invokes.delete(controller);\n\n if (disposed || controller.signal.aborted) return;\n\n try {\n if (invoke.onError) {\n send(invoke.onError({ context: capturedContext, error }));\n } else {\n fail(error, { event: capturedEvent, phase: 'invoke', state });\n }\n } catch (callbackError) {\n fail(callbackError, { event: capturedEvent, phase: 'invoke', state });\n }\n },\n );\n }\n };\n\n const notify = (event: Event | undefined): void => {\n for (const listener of [...listeners]) {\n if (disposed) return;\n\n try {\n listener(current);\n } catch (error) {\n observeError(error, { event, phase: 'subscriber', state: current.state });\n }\n }\n };\n\n const process = (runtimeEvent: RuntimeEvent<State, Context, Event>): void => {\n const previous = current;\n let outcome: TransitionOutcome<State, Context, Event>;\n\n try {\n outcome = transition(definition, current, runtimeEvent);\n } catch (error) {\n fail(error, {\n event: runtimeEvent.kind === 'event' ? runtimeEvent.event : undefined,\n phase: 'transition',\n state: current.state,\n });\n\n return;\n }\n\n if (outcome.result.type === 'ignored' || !outcome.transition) {\n tappers.emit({ event: outcome.event, snapshot: outcome.result.snapshot, type: 'ignored' });\n return;\n }\n\n const source = nodeFor(definition, previous.state);\n\n current = outcome.result.snapshot;\n tappers.emit({ event: outcome.event, snapshot: current, type: 'transition' });\n cancelStateResources();\n establishStateResources(current.state, outcome.event);\n notify(outcome.event);\n runEffects(source.exit ?? [], previous.state, outcome.event);\n runEffects(outcome.transition.effects ?? [], previous.state, outcome.event);\n runEffects(nodeFor(definition, current.state).entry ?? [], current.state, outcome.event);\n };\n\n const flush = (): void => {\n let transitions = 0;\n\n while (queue.length > 0 && !disposed) {\n transitions += 1;\n\n if (transitions > MAX_TRANSITIONS) {\n fail(\n new ClockworkTransitionLimitError('maximum queued transitions exceeded', { maxTransitions: MAX_TRANSITIONS }),\n {\n phase: 'transition',\n state: current.state,\n },\n );\n\n return;\n }\n\n const next = queue.shift();\n\n if (next) process(next);\n }\n };\n\n establishStateResources(current.state, undefined);\n\n if (!options.snapshot) {\n runEffects(nodeFor(definition, current.state).entry ?? [], current.state, undefined);\n }\n\n return {\n can: (event) => {\n if (disposed) return false;\n\n try {\n if (!isMachineEvent(event)) {\n warn('ignored malformed event; expected an object with a string `type`');\n return false;\n }\n\n return canTransition(definition, current, event);\n } catch (error) {\n fail(error, { event, phase: 'transition', state: current.state });\n return false;\n }\n },\n get disposalSignal() {\n return disposal.signal;\n },\n dispose,\n get disposed() {\n return disposed;\n },\n send,\n get snapshot() {\n return current;\n },\n subscribe(listener) {\n if (disposed) return () => undefined;\n\n listeners.add(listener);\n\n return () => listeners.delete(listener);\n },\n tap(handler, tapOptions) {\n if (disposed) return () => undefined;\n\n return tappers.tap(handler, tapOptions);\n },\n [Symbol.dispose]: dispose,\n };\n};\n\n/** Defines a typed flat finite-state machine. */\nexport const defineMachine =\n <Context extends Record<string, unknown> = Record<string, never>, Event extends MachineEvent = MachineEvent>() =>\n <State extends string>(definition: MachineConfig<State, Context, Event>): Machine<State, Context, Event> => {\n assertDefinition(definition);\n const context = (definition as { readonly context?: Context }).context ?? ({} as Context);\n const initialSnapshot = createSnapshot(definition.initial, context);\n\n return {\n can: (snapshot, event) => canTransition(definition, snapshot, event),\n createActor: (options) => createActor(definition, initialSnapshot, options),\n initialSnapshot,\n transition: (snapshot, event) => transition(definition, snapshot, { event, kind: 'event' }).result,\n };\n };\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vielzeug/clockwork",
|
|
3
|
-
"version": "26.10.
|
|
3
|
+
"version": "26.10.5",
|
|
4
4
|
"description": "Framework-neutral finite state machines with pure transitions and actors",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"verify:exports": "node verify-exports.mjs"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@vielzeug/arsenal": "26.10.
|
|
43
|
+
"@vielzeug/arsenal": "26.10.5"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@types/node": "^26.6.2",
|