@ap-ent/state-machine
v1.0.0
Published
Zero-dependency typed finite state machine for TypeScript
Maintainers
Readme
@ap/state-machine
Zero-dependency typed finite state machine for TypeScript.
Features
- ✅ Fully typed states and events via TypeScript generics
- ✅ Guard functions — conditionally block transitions
- ✅ Lifecycle hooks:
onEntry,onExit, transitionaction - ✅ Shallow history with
goBack() - ✅ Reactive subscriptions:
subscribe(fn)returns unsubscribe - ✅ Serialization:
toJSON()/fromJSON() - ✅ Dual ESM + CJS build
- ✅ Zero runtime dependencies
Install
npm install @ap/state-machineQuick Start
import { createMachine } from '@ap/state-machine'
type State = 'IDLE' | 'LOADING' | 'DONE' | 'ERROR'
type Event = 'FETCH' | 'RESOLVE' | 'REJECT' | 'RESET'
const machine = createMachine<State, Event>({
initial: 'IDLE',
states: {
IDLE: { on: { FETCH: { target: 'LOADING' } } },
LOADING: {
on: {
RESOLVE: { target: 'DONE' },
REJECT: { target: 'ERROR' },
},
},
DONE: { on: { RESET: { target: 'IDLE' } } },
ERROR: { on: { RESET: { target: 'IDLE' } } },
},
})
machine.subscribe((state) => {
console.log('State changed to:', state)
})
machine.send('FETCH') // → 'LOADING'
machine.send('RESOLVE') // → 'DONE'
machine.send('RESET') // → 'IDLE'Traffic-Light Example
type Light = 'RED' | 'GREEN' | 'YELLOW'
type Tick = 'TICK'
const traffic = createMachine<Light, Tick>({
initial: 'RED',
history: true,
states: {
RED: { on: { TICK: { target: 'GREEN' } }, onEntry: () => console.log('STOP') },
GREEN: { on: { TICK: { target: 'YELLOW' } }, onEntry: () => console.log('GO') },
YELLOW: { on: { TICK: { target: 'RED' } }, onEntry: () => console.log('SLOW') },
},
})
traffic.send('TICK') // GO
traffic.send('TICK') // SLOW
traffic.goBack() // back to GREENAPI
createMachine(config, initialContext?)
Creates a new machine instance. Config is immutable after creation.
| Option | Type | Description |
|---|---|---|
| initial | TState | Starting state |
| states | Record | Per-state config (transitions, hooks) |
| history | boolean | Enable shallow history stack |
machine.send(event)
Triggers a transition. Returns the new state (unchanged if blocked).
machine.subscribe(fn)
Registers a listener called on every state change. Returns an unsubscribe function.
machine.goBack()
Pops the history stack and restores the previous state. Returns undefined if unavailable.
machine.toJSON() / fromJSON(snapshot)
Serialize and restore machine state including history stack.
Guards
const vault = createMachine<'LOCKED' | 'OPEN', 'UNLOCK'>(
{
initial: 'LOCKED',
states: {
LOCKED: {
on: {
UNLOCK: {
target: 'OPEN',
guard: (ctx) => ctx['pin'] === 9876,
},
},
},
OPEN: {},
},
},
{ pin: 9876 },
)License
MIT © Gordon Schauer
