Skip to content

Introduction

Mantaq is a state machine library for TypeScript. Model flows as states and events; Mantaq runs transitions, side effects, and cleanup.

Booleans and nested conditionals drift apart as flows grow. A state machine makes the flow the source of truth: every state and transition declared upfront, typed, and testable.

Use Mantaq for flows with known steps and clear transitions. It models where a process is, not every piece of data in your app.

  • Actor. One running machine. Holds current state, context, effects, transitions, clock.
  • State. A node in the flow. May be final.
  • Event. A typed message that triggers transitions.
  • Effect. Code that runs on state entry and aborts on state exit.
  • Context. Data the machine carries. Survives transitions.
PackageExports
@mantaq/coreActor, state, event, VirtualClock, RealClock, Context
@mantaq/sugarmatches, states, events, tag, isIn, activeLeaves, ActorMap, onOutput, withPromise, withTimeout, actorSpec, definePart, use, withParts
@mantaq/testcreateTestHarness, state/transition/effect assertions
@mantaq/traversalbuildGraph, instrument, History

Three states, two events:

import { Actor, state, event } from "@mantaq/core";
const basicInfo = state("basicInfo")();
const payment = state("payment")();
const success = state("success")().final();
const submitBasicInfo = event("submitBasicInfo")();
const submitPayment = event("submitPayment")();
const checkout = new Actor({
inputs: [submitBasicInfo, submitPayment],
states: [basicInfo, payment, success],
initial: basicInfo,
setup: (m) => {
m.on(basicInfo, submitBasicInfo, () => ({ state: payment }));
m.on(payment, submitPayment, () => ({ state: success }));
},
});
checkout.send(submitBasicInfo.create());
checkout.snapshot().path[0]; // "payment"

success is final. Actor stops there; entering it fires "done" subscribers.