@mantaq/core
state(id)
Section titled “state(id)”function state<const T extends string>(id: T): <Payload = unknown>() => StateRef<T, Payload, false>;Two calls: id, then payload type.
const basicInfo = state("basicInfo")();const payment = state("payment")<{ cardNumber: string }>();StateRef<T, Payload, IsFinal>
Section titled “StateRef<T, Payload, IsFinal>”| Property | Type | What |
|---|---|---|
name | T | State id |
isFinal | IsFinal | Terminal state? |
.final() | StateRef<T, Payload, true> | Mark final |
.create(payload) | { state, payload } | Make state entry. Payload required |
.regions(options) | this | Declared but not wired (no-op; kept internal) |
event(id)
Section titled “event(id)”function event<const T extends string>( id: T,): <Payload extends object | void = void>() => EventRef<T, Payload>;Two calls: id, then payload type. Payload must be object | void.
const submitBasicInfo = event("submitBasicInfo")<{ email: string; name: string }>();const back = event("back")();EventRef<T, Payload>
Section titled “EventRef<T, Payload>”| Property | Type | What |
|---|---|---|
type | T | Event type (discriminant) |
.is(event) | boolean | Identity check. Type guard |
.create() | { type: T } | Void-payload events only |
.create(payload) | { type: T; payload: Payload } | Payload events. Arg required |
Context
Section titled “Context”class Context<T> { constructor(get: () => T, set: (value: T) => void); get(): T; set(value: T): void;}Read/write handle to actor context. Passed to handlers and effects.
class Actor< const States extends readonly AnyStateRef[], const Inputs extends readonly AnyEventRef[], const Internal extends readonly AnyEventRef[] = readonly [], const Outputs extends readonly AnyEventRef[] = readonly [], ActorContext = Record<string, unknown>,>Constructor options
Section titled “Constructor options”| Option | Type | What |
|---|---|---|
inputs | EventRef[] | External events accepted |
outputs | EventRef[] | Events to parent |
internal | EventRef[] | Events from effects/transitions |
states | StateRef[] | All states |
initial | StateRef or { state, payload? } | Start state |
context | ActorContext | Initial context |
clock | Clock | Default: RealClock |
setup | (m: ActorBuilder) => void | Register transitions and effects |
regions | Record<string, AnyActor> | Static children |
internalBudget | number | Max internal events (default: 10000) |
Methods
Section titled “Methods”| Method | Signature | What |
|---|---|---|
send(event) | (event: CreatedOf<Inputs[number]>) => void | Send event |
inject(event) | (event: InternalEvent) => void | Push internal event and drain (tests/embedders) |
dispose() | () => void | Stop: abort effect, clear queue + subscribers |
recover(target) | (target: { state; context }) => void | Restart dead machine from caller-supplied state |
snapshot() | () => Snapshot | State tree |
on("change", fn) | (fn) => () => void | State or context changed ((snap, prev) => void) |
on("done", fn) | (fn) => () => void | Final or error state |
on("error", fn) | (fn) => () => void | Death signal, seeded to late subscribers ((info) => void) |
on("output", fn) | (fn) => () => void | Emitted output event ((event) => void) |
settled() | () => Promise<void> | Queue drained |
pendingEffectCount() | () => number | In-flight effects not yet settled (introspection) |
Properties
Section titled “Properties”| Property | Type | What |
|---|---|---|
state | States[number] | ErrorState | Current state (__error on error) |
context | ActorContext | Current context |
clock | Clock | Clock instance |
regions | Record<string, AnyActor> | Children |
options | InternalActorOptions<...> | Built options. Semi-internal |
ActorBuilder
Section titled “ActorBuilder”Type-safe registrar passed to setup. Targets validate against declared states, inputs, internal, and outputs. Undeclared state, event, or emit fails to compile.
setup: (m) => { m.on(basicInfo, submitBasicInfo, () => ({ state: payment })); m.onAny(back, () => ({ state: basicInfo })); m.effect(payment, { name: "chargePayment", fn: ({ signal, emit }) => {} });};| Method | Signature | What |
|---|---|---|
on(state, event, fn) | (stateRef, eventRef, fn) => this | Transition for one pair |
onAny(event, fn) | (eventRef, fn) => this | Handler in every state |
effect(state, { name, fn }) | (stateRef, { name, fn }) => this | Run fn on state entry |
Handler return: { state?; payload?; emit? } or {} to stay in place.
Effects run on every state entry. Each takes a required camelCase name;
executed effects are recorded in history as { stateName, effectName }, and
tests can assert on them by name (harness.assertEffectRan(stateName, effectName)). Initial state runs effects at construction with synthetic event
{ type: "__init" }. Terminal states run theirs on entry.
VirtualClock
Section titled “VirtualClock”class VirtualClock implements Clock { advance(ms: number): void; hasPending(): boolean; pendingTimers(): Array<{ id: number; deadline: number; ms: number; eventName?: string }>; setDrain(fn: () => void): void; now(): number; setTimeout(ms, cb, options?): number; clearTimeout(id): void; setInterval(ms, cb, options?): number; clearInterval(id): void;}Deterministic. advance(ms) fires all due timers instantly. Aborted signal passed to setTimeout/setInterval returns -1.
RealClock
Section titled “RealClock”class RealClock implements Clock { now(): number; setTimeout(ms, cb, options?): number; clearTimeout(id): void; setInterval(ms, cb, options?): number; clearInterval(id): void;}Real timers via globalThis.setTimeout. Default for actors.
Snapshot
Section titled “Snapshot”interface Snapshot<C = unknown> { path: string[]; context: C; regions: Record<string, Snapshot<unknown>>; done?: boolean; error?: ErrorInfo;}done set on final state including __error, so a died machine reports done: true and error. done alone means successful completion. error means it died. Either way sends are ignored.
interface Clock { setTimeout( ms: number, cb: () => void, options?: { signal?: AbortSignal; eventName?: string }, ): number; clearTimeout(id: number): void; setInterval(ms: number, cb: () => void, options?: { signal?: AbortSignal }): number; clearInterval(id: number): void; now(): number; setDrain?(fn: () => void): void;}EffectInput
Section titled “EffectInput”type EffectInput<ActorContext, Payload = unknown> = { signal: AbortSignal; state: { name: string; payload: Payload }; event: InternalEvent; context: Context<ActorContext>; emit: (event: InternalEvent) => void; clock: Clock;};TransitionResult
Section titled “TransitionResult”type TransitionResult<AllowedState = AnyStateRef, AllowedEmit = string> = { state?: AllowedState | { state: AllowedState; payload?: unknown }; payload?: unknown; emit?: Array<{ type: AllowedEmit }>;};Internal type. Not exported. Handler returns infer from it.
InternalEvent
Section titled “InternalEvent”type InternalEvent = { type: string; payload?: unknown };AnyActor
Section titled “AnyActor”interface AnyActor<C = Record<string, unknown>> { state: AnyStateRef; clock: Clock; regions: Record<string, AnyActor>; context?: C; options?: { transitions?: Record<string, Record<string, unknown>>; effects?: Record<string, unknown[]>; states?: ReadonlyArray<{ name: string; isFinal: boolean }>; }; send(event: AnyEventRef | InternalEvent): void; snapshot(): Snapshot<C>; on(event: "change", fn: (snapshot: Snapshot<C>, prev: Snapshot<C>) => void): () => void; on(event: "done", fn: () => void): () => void; on(event: "error", fn: (info: ErrorInfo) => void): () => void; settled(): Promise<void>;}More types
Section titled “More types”| Type | What |
|---|---|
NonFinalStateRef<States> | Non-terminal state refs |
CreatedOf<E> | Event instance type for E: { type } or { type; payload } |
CreatedOfEvent<Id, P> | Same, explicit id and payload |
EffectFn<C, P> | (input: EffectInput<C, P>) => void | Promise<void> |
ErrorInfo | { error; state; context; event; reason }. Last failure |
ErrorState | StateRef<"__error", unknown, true>. Terminal error state |
SetupFn<...> | (m: ActorBuilder<...>) => void. The setup option type |