Skip to content
@tde.io/plexis  ·  npm install @tde.io/plexis  ·  npm  ·  GitHub

Key Types

These types appear in return values and handler signatures throughout the library.

Return value of domain.follow() and domain.followFrom().

FieldTypeRequiredDescription
status'followed' | 'blocked' | 'ignored' | 'error'Yes'followed' — transition completed; 'blocked' — guard returned false; 'ignored' — no matching edge and strict is false; 'error' — a handler threw
eventstringYesThe event name that was processed
fromstringYesState ID before the transition
tostringNoState ID after the transition; present when status is 'followed'
contextTContextYesContext after the transition
traceIdstringYesTrace ID for this transition
errorunknownNoError thrown by a handler; present when status is 'error'
const result = await order.follow('submit');
if (result.status === 'followed') {
console.log(`Moved from ${result.from}${result.to}`);
} else if (result.status === 'blocked') {
console.log('Guard prevented the transition');
} else if (result.status === 'error') {
console.error('Handler threw:', result.error);
}

Return value of pipeline.run().

FieldTypeRequiredDescription
status'completed' | 'stopped' | 'error'Yes'completed' — reached a terminal node; 'stopped' — no matching fork and node is not terminal; 'error' — a handler threw
pipelineIdstringYesID of the pipeline
finalNodestringYesID of the last node reached
contextTContextYesContext after the run
traceIdstringYesTrace ID for this run
localTraceTraceEvent[]YesAll trace events recorded during this run
errorunknownNoError thrown by a handler; present when status is 'error'
const result = await payment.run({ validated: false, charged: false });
if (result.status === 'completed') {
console.log('Finished at node:', result.finalNode);
console.log('Final context:', result.context);
} else if (result.status === 'error') {
console.error('Pipeline error:', result.error);
}

Captured by domain.snapshot(); restored via domain.restore(snapshot).

FieldTypeRequiredDescription
phasestringYesCurrent phase ID at snapshot time
contextTContextYesContext at snapshot time
historyLengthnumberYesNumber of recorded history entries at snapshot time
const snap = order.snapshot();
// { phase: 'pending', context: { orderId: 'o1' }, historyLength: 0 }
await order.follow('submit');
order.restore(snap); // rolls back to 'pending'

Single transition record returned by domain.history().

FieldTypeRequiredDescription
fromstringYesState before the transition
tostringYesState after the transition
eventstringYesEvent name that triggered the transition
payloadunknownNoOptional event payload
contextTContextYesContext after the transition
timestampnumberYesTimestamp of the transition
traceIdstringYesTrace ID for this transition
await order.follow('submit', { userId: 'u1' });
const [entry] = order.history();
console.log(entry.from); // 'pending'
console.log(entry.to); // 'processing'
console.log(entry.event); // 'submit'
console.log(entry.payload); // { userId: 'u1' }

Return value of domain.inspectNode() and pipeline.inspectNode().

FieldTypeRequiredDescription
nodeGraphNodeYesThe inspected node
inboundGraphEdge[]YesAll edges pointing to this node
outboundGraphEdge[]YesAll edges pointing from this node
pathsToGraphPath[]YesAll paths leading to this node
pathsFromGraphPath[]YesAll paths starting from this node
reachableNodesGraphNode[]YesAll nodes reachable from this node
attachedPipelinesGraphAttachment[]YesPipelines attached to this node
runtimeStatsobjectNoRuntime statistics; populated after the node has been visited

runtimeStats fields:

FieldTypeRequiredDescription
visitsnumberYesNumber of times this node has been visited
lastVisitedAtnumberNoTimestamp of the most recent visit
observedLabelsstring[]YesFork labels selected at this node across all visits
recentTraceIdsstring[]YesTrace IDs of recent visits
const info = order.inspectNode('pending');
console.log(info.outbound.map((e) => e.event)); // ['submit']
console.log(info.reachableNodes.map((n) => n.id)); // ['processing']

Static graph representation returned by describe() and graph query methods.

FieldTypeRequiredDescription
idstringYesDomain or pipeline ID
kind'domain' | 'pipeline' | 'composed'YesWhether this describes a domain, pipeline, or composed graph
nodesGraphNode[]YesAll nodes in the graph
edgesGraphEdge[]YesAll edges in the graph
entryNodesGraphNodeRef[]YesReferences to entry (initial) nodes
terminalNodesGraphNodeRef[]YesReferences to terminal nodes
attachmentsGraphAttachment[]YesAll pipeline attachments
const descriptor = order.describe();
console.log(descriptor.kind); // 'domain'
console.log(descriptor.nodes.map((n) => n.id)); // all state IDs
console.log(descriptor.edges.map((e) => e.event)); // all event names

The type a handler may return to patch context.

type PatchLike<TContext> = Partial<TContext> | void | null | undefined

Return a Partial<TContext> to merge changes into the context. Return void, null, or undefined for no change. The default merge strategy is a shallow spread: { ...prev, ...patch }.

import { defineDomain, when, on, terminal } from '@tde.io/plexis';
type Ctx = { count: number };
const counter = defineDomain<Ctx>('counter', () => {
when('active', () => {
on('increment', () => {
action((ctx) => ({ count: ctx.count + 1 }));
return target('active');
});
on('noop', () => {
action(() => undefined); // returns void — no context change
return target('active');
});
});
return { context: { count: 0 }, initial: 'active' };
});

type ErrorPolicy = 'throw' | 'return' | 'trace-and-return'
ValueDescription
'throw'Re-throw the error; the caller receives a rejected promise
'return'Return a result with status: 'error' instead of throwing
'trace-and-return'Record the error in the trace and return status: 'error'
import { defineDomain, when, on, terminal } from '@tde.io/plexis';
const domain = defineDomain(
'order',
() => {
when('active', () => {});
return { context: {}, initial: 'active', errorPolicy: 'return' };
}
);
const result = await domain.follow('fail');
console.log(result.status); // 'error' — did not throw

Single recorded trace event returned by tracer.history() and tracer.byTraceId().

FieldTypeRequiredDescription
idstringYesUnique event ID
traceIdstringYesTrace ID grouping related events
parentIdstringNoParent event ID for nested events
timestampnumberYesTimestamp
levelTraceLevelYesEvent level
typestringYesEvent type string
domainIdstringNoDomain context
pipelineIdstringNoPipeline context
nodeIdstringNoNode context
phaseIdstringNoPhase context
eventstringNoEvent name (for domain events)
labelstringNoHuman-readable label
fromstringNoSource state or node
tostringNoTarget state or node
statusTraceStatusNoEvent status
inputunknownNoInput to the handler
outputPatchunknownNoPatch returned by the handler
contextSnapshotunknownNoContext snapshot (when captureContext is enabled)
errorunknownNoError if the handler threw
metadataRecord<string, unknown>NoUser-defined metadata
import { createTracer, defineDomain, when, on, terminal } from '@tde.io/plexis';
const tracer = createTracer({ captureContext: 'after' });
const domain = defineDomain('order', () => {
when('pending', () => {
on('submit', target('done'));
});
when('done', terminal());
return { context: {}, initial: 'pending' };
}, { tracer });
await domain.follow('submit');
const events = tracer.history();
events.forEach((e) => {
console.log(e.type, e.level, e.status);
});

'domain' | 'phase' | 'edge' | 'pipeline' | 'pipeline-node' | 'fork' | 'action' | 'guard' | 'condition'

import type { TraceLevel } from '@tde.io/plexis';
const level: TraceLevel = 'edge'; // valid level

'started' | 'completed' | 'blocked' | 'selected' | 'skipped' | 'failed'

import { createTracer } from '@tde.io/plexis';
import type { TraceStatus } from '@tde.io/plexis';
const tracer = createTracer();
// After running a domain or pipeline:
const failed = tracer.history().filter((e) => e.status === ('failed' as TraceStatus));