Context
context is the machine’s data — a plain object declared in the config and read directly off the service. Writes go through setContext, the single batched entry point.
import { machine } from '@dunky-dev/state-machine'
const m = machine({ initial: 'idle', context: { name: 'Ada', age: 36 }, states: { idle: { on: { birthday: { actions: $ => $.setContext({ age: $.context.age + 1 }) }, rename: { actions: $ => $.setContext({ name: $.event.name }) }, }, }, },})
m.start()m.context.name // 'Ada'm.send({ type: 'birthday' })m.context.age // 37Memory model
Section titled “Memory model”Context is one plain object per machine, copied from the config at construction. Its identity never changes — only its fields are mutated in place. This means:
- Reads are zero-cost — no proxy, no getter.
- Writes are batched:
setContextapplies a shallow merge, deduplicates unchanged fields, then notifies subscribers once. - A field that didn’t change wakes no observer.
setContext
Section titled “setContext”Accepts a partial patch object or an updater function:
// patch — shallow-merged$.setContext({ count: 5 })
// updater — receives current context, returns patch$.setContext(ctx => ({ count: ctx.count + 1 }))setContext is available in actions, effects, and watchers via the $ argument. Outside the machine, use m.setContext(patch) directly.
act() shorthand
Section titled “act() shorthand”For the common case of writing context in a transition action, act() is write-sugar that drops the $ => $.setContext(...) wrapper:
import { act } from '@dunky-dev/state-machine'
on: { increment: { actions: act($ => ({ count: $.context.count + 1 })) }, reset: { actions: act({ count: 0 }) },}