Skip to content

@mantaq/traversal

function buildGraph<C>(
actor: AnyActor<C>,
options?: {
internalIds?: Set<string>;
sampleContext?: Record<string, unknown>;
sampleContexts?: Record<string, Record<string, unknown>>;
},
): ActorGraph;

Builds graph from actor definition. Nodes are states, edges are transitions. Effect self-loops and region children included.

internalIds marks event types as internal. Their edges excluded from coverage. sampleContexts provides context values for handler evaluation.

const graph = buildGraph(checkout, { internalIds: new Set(["paymentOk"]) });
graph.nodes.length; // number of states
graph.edges.length; // number of transitions

collectActiveStates(snapshot, prefix, activeSet)

Section titled “collectActiveStates(snapshot, prefix, activeSet)”
function collectActiveStates(snapshot: Snapshot, prefix: string, activeSet: Set<string>): void;

Recursively walks snapshot tree, adds active state node IDs to set. Used internally by buildGraph.


function instrument<C>(actor: AnyActor<C>): InstrumentedActor<C>;

Wraps actor to record every state visit, transition, and effect in a History instance. Returns InstrumentedActor with same API plus history property.

const wrapped = instrument(checkout);
wrapped.send(submitBasicInfo.create());
wrapped.history.visitedStates(); // Set<string>

class History {
append(entry: HistoryEntry): void;
entries(): readonly HistoryEntry[];
stateVisits(): StateVisit[];
transitions(): TransitionRecord[];
effects(): EffectRecord[];
sends(): Array<{ event: string }>;
visitedStates(): Set<string>;
firedTransitions(): Set<string>;
reset(): void;
}

Append-only log. Query by type or get derived sets.

  • visitedStates(): unique state names entered
  • firedTransitions(): "from:event" strings for fired transitions
  • reset(): clear all entries

function reachable(graph: ActorGraph, fromId: string, toId: string): boolean;

BFS reachability check.

function allPaths(graph: ActorGraph, fromId: string, toId: string): string[][];

All acyclic paths between two nodes. Returns arrays of node IDs.

function findCycles(graph: ActorGraph): string[][];

All cycles as arrays of node IDs.

function unreachableNodes(graph: ActorGraph, fromId: string): string[];

Node IDs not reachable from fromId.

function shortestPath(graph: ActorGraph, fromId: string, toId: string): string[] | null;

Shortest path by edge count. null if unreachable.


interface ActorGraph {
nodes: GraphNode[];
edges: GraphEdge[];
}
interface GraphNode {
id: string;
label: string;
isActive: boolean;
isFinal: boolean;
isInitial?: boolean;
}
interface GraphEdge {
id: string;
source: string;
target: string;
label: string;
isActive: boolean;
isInternal?: boolean;
isUndetermined?: boolean;
payload?: { action?: string };
contexts?: string[];
}
interface HistoryEntry {
type: "state_visit" | "transition" | "effect" | "send";
data: StateVisit | TransitionRecord | EffectRecord | { event: string };
}
interface StateVisit {
stateName: string;
}
interface TransitionRecord {
from: string;
event: string;
to: string | undefined;
}
interface EffectRecord {
stateName: string;
}
interface InstrumentedActor<C> {
history: History;
send(event: unknown): void;
state: AnyActor["state"];
snapshot(): Snapshot<C>;
regions: Record<string, AnyActor>;
context?: C;
clock: AnyActor["clock"];
on(event: "change", fn: (snapshot: Snapshot<C>, prev: Snapshot<C>) => void): () => void;
on(event: "transition", fn: (info: TransitionInfo) => void): () => void;
on(event: "done", fn: () => void): () => void;
on(event: "error", fn: (info: ErrorInfo) => void): () => void;
on(event: "output", fn: (event: InternalEvent) => void): () => void;
recover(target: { state: AnyActor["state"]; context: C }): void;
settled(): Promise<void>;
inject(event: InternalEvent): void;
dispose(): void;
}

ConstantValueWhat
INITIAL_NODE_ID"__initial__"Synthetic graph entry node ID