Setup
machine() builds and runs a machine. setup() is how you author the config with full type-checking — inferred types, compile-checked names, no manual type arguments.
machine(config)
Section titled “machine(config)”import { machine, act } from '@dunky-dev/state-machine'
const toggle = machine({ initial: 'inactive', context: { count: 0 }, states: { inactive: { on: { flip: { target: 'active', actions: act($ => ({ count: $.context.count + 1 })) }, }, }, active: { on: { flip: { target: 'inactive' } }, }, },})
toggle.start()toggle.send({ type: 'flip' })toggle.state // 'active'toggle.context // { count: 1 }Returns a service — built but not running. Call .start() to boot effects and watchers, .stop() to tear them down. .send() dispatches events; .state and .context are always readable.
setup() — lightweight path
Section titled “setup() — lightweight path”Infers State, Context, and Event from the literal. Named guards / actions / effects / delays stay as loose strings.
import { setup } from '@dunky-dev/state-machine'
const config = setup().createMachine({ initial: 'closed', context: { open: false }, states: { closed: { on: { toggle: { target: 'open' } } }, open: { on: { toggle: { target: 'closed' } } }, },})setup() — checked path
Section titled “setup() — checked path”Name a registry of guards / actions / effects / delays. Every reference in the config is compile-checked and autocompleted against the registry keys — a typo is a type error.
import { setup } from '@dunky-dev/state-machine'
type Ctx = { open: boolean; locked: boolean }type Ev = { type: 'toggle' }
const { createMachine } = setup<Ctx, Ev>().config({ guards: { isUnlocked: ({ context }) => !context.locked, }, actions: { logOpen: ({ context }) => console.log('open:', context.open), },})
const config = createMachine({ initial: 'closed', context: { open: false, locked: false }, states: { closed: { on: { toggle: { target: 'open', guard: 'isUnlocked', actions: 'logOpen' }, }, }, open: { on: { toggle: { target: 'closed' } }, }, },})