@tahaghafuri/tinyfsm gives you predictable state logic in any JavaScript or TypeScript project. No classes. No decorators. No runtime overhead.
npm install @tahaghafuri/tinyfsm
pnpm add @tahaghafuri/tinyfsm
yarn add @tahaghafuri/tinyfsm
https://cdn.jsdelivr.net/npm/@tahaghafuri/tinyfsm/dist/tinyfsm.umd.min.js
https://cdnjs.cloudflare.com/ajax/libs/@tahaghafuri/tinyfsm/1.0.0/tinyfsm.umd.min.js
import { createMachine } from '@tahaghafuri/tinyfsm'; const fetcher = createMachine({ initial: 'idle', states: { idle: { on: { FETCH: 'loading' } }, loading: { on: { RESOLVE: 'success', REJECT: 'error' } }, success: { on: { RESET: 'idle' } }, error: { on: { RETRY: 'loading', RESET: 'idle' } }, }, }); fetcher.send('FETCH'); // → loading fetcher.send('RESOLVE'); // → success fetcher.is('success'); // true // Subscribe to changes const unsub = fetcher.on((next, prev) => { console.log(`${prev} → ${next}`); }); // Unsubscribe when done unsub();
const door = createMachine({ initial: 'closed', states: { closed: { on: { OPEN: 'open' }, onExit: (to) => console.log(`Leaving closed → ${to}`), }, open: { on: { CLOSE: 'closed' }, onEnter: (from) => console.log(`Entered open from ${from}`), }, }, }); door.send('OPEN'); // Leaving closed → open // Entered open from closed
type State = 'idle' | 'loading' | 'success' | 'error'; type Event = 'FETCH' | 'RESOLVE' | 'REJECT' | 'RESET'; const machine = createMachine<State, Event>({ initial: 'idle', states: { /* ... */ }, }); // TS error if you use an invalid state or event ✓
| Method | Returns | Description |
|---|---|---|
.state |
S |
Current state (readonly getter) |
.send(event) |
boolean |
Send an event. Returns true if a transition happened |
.on(listener) |
() => void |
Subscribe to state changes. Returns an unsubscribe function |
.can(event) |
boolean |
Check if an event triggers a transition from current state |
.is(state) |
boolean |
Check if current state matches given state |