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

Registration Helpers

These functions are only valid inside an active defineDomain or definePipeline setup function (or inside when/node scopes). Calling them outside throws PlexisError with code BUILDER_CLOSED.

Registers a phase in the current domain builder scope.

function when<TContext>(id: string, x: (() => void) | TerminalSentinel): void

id string

Unique phase identifier.

x (() => void) | TerminalSentinel

Either a synchronous setup function that calls enter, exit, and on to configure the phase, or the result of terminal() to register a terminal phase with no further behavior.

None (void).

import { defineDomain, when, enter, exit, on, terminal } from '@tde.io/plexis';
const door = defineDomain('door', () => {
when('closed', () => {
exit(async (ctx) => ({ lastClosed: Date.now() }));
on('open', target('open'));
});
when('open', () => {
enter(async (ctx) => ({ lastOpened: Date.now() }));
on('close', target('closed'));
});
return { context: { lastOpened: 0, lastClosed: 0 }, initial: 'closed' };
});

Registers an entry lifecycle hook for the current phase. Must be called inside a when() setup function.

function enter<TContext>(
fn: (ctx: TContext, input: PhaseHookInput) => PatchLike | Promise<PatchLike>
): void

Registers an exit lifecycle hook for the current phase. Must be called inside a when() setup function.

function exit<TContext>(
fn: (ctx: TContext, input: PhaseHookInput) => PatchLike | Promise<PatchLike>
): void

Registers an event on the current phase. Must be called inside a when() setup function.

function on<TContext>(event: string, def: TargetDef | OnSetupFn): void

event string

Event name.

def TargetDef | OnSetupFn

Either target(id) (simple form) or a synchronous setup function that calls guard, action, and pipeline as ambient helpers and returns target(id) (setup function form).

  • Simple form: on('cancel', target('cancelled'))
  • Setup function form: on('submit', () => { guard(fn); action(fn); pipeline(p); return target('processing'); })

Inside the setup function, guard, action, and pipeline are each valid at most once — a second call to any of them throws DUPLICATE_REGISTRATION. The setup function must return a target(id) sentinel; returning nothing throws MISSING_TARGET.

import { defineDomain, when, on, guard, action, pipeline, target, terminal } from '@tde.io/plexis';
type Ctx = { approved: boolean; approvedBy?: string };
const approval = defineDomain<Ctx>('approval', () => {
when('pending', () => {
on('approve', () => {
guard((ctx, { payload }) => payload != null);
action((ctx, { payload }) => ({ approvedBy: payload as string }));
return target('approved');
});
on('reject', target('rejected'));
});
when('approved', terminal());
when('rejected', terminal());
return { context: { approved: false }, initial: 'pending' };
});

Registers a node in the current pipeline builder scope.

function node<TContext>(id: string, x: (() => void) | TerminalSentinel): void

id string

Unique node identifier.

x (() => void) | TerminalSentinel

Either a synchronous setup function that calls action and fork to configure the node, or the result of terminal(fn?) to register a terminal node with an optional final action.

None (void).

import { definePipeline, node, action, fork, target, terminal } from '@tde.io/plexis';
type Ctx = { score: number; passed: boolean };
const quiz = definePipeline<Ctx>('quiz', () => {
node('grade', () => {
action(async (ctx) => ({ score: 90 }));
fork('pass', target('pass'), (ctx) => ctx.score >= 70);
fork('fail', target('fail'), (ctx) => ctx.score < 70);
});
node('pass', terminal(async () => ({ passed: true })));
node('fail', terminal(async () => ({ passed: false })));
return { initial: 'grade' };
});

Registers the action handler for the current node. Must be called inside a node() setup function.

function action<TContext>(
fn: (ctx: TContext, input: PipelineActionInput) => PatchLike | Promise<PatchLike>
): void

Registers a forward transition on the current node in declaration order. Must be called inside a node() setup function.

function fork<TContext>(
label: string,
target: TargetDef,
condition?: (ctx: TContext, input: PipelineConditionInput) => boolean | Promise<boolean>
): void

label string

Required name for this fork. Appears in tracer events and graph introspection output.

target TargetDef

A target(...) sentinel wrapping either a node-id string or a sub-pipeline. Pass target('node-id') or target(pipeline). Bare strings and bare Pipeline objects are rejected at compile time and at runtime.

condition ((ctx, input) => boolean | Promise<boolean>) (optional)

Fork predicate. Omit for an unconditional forward edge; otherwise the first fork whose condition returns true is followed.

import { definePipeline, node, action, fork, target, terminal } from '@tde.io/plexis';
type Ctx = { score: number };
const pipeline = definePipeline<Ctx>('check', () => {
node('evaluate', () => {
fork('high-score', target('excellent'), (ctx) => ctx.score >= 90);
fork('passing', target('passing'), (ctx) => ctx.score >= 60);
fork('failing', target('failing')); // unconditional fallback
});
node('excellent', terminal());
node('passing', terminal());
node('failing', terminal());
return { initial: 'evaluate' };
});

Returns a TerminalSentinel — a scope-independent branded value accepted as the second argument to when() and node(). Never throws BUILDER_CLOSED; safe to call at any scope level.

function terminal<TContext>(
fn?: (ctx: TContext, input: PipelineActionInput) => PatchLike | Promise<PatchLike>
): TerminalSentinel

fn (optional)

Optional final action that runs when a terminal node is reached (ignored for terminal phases). Its patch is merged before the run completes.

TerminalSentinel — a branded sentinel object.

import { definePipeline, node, action, fork, terminal } from '@tde.io/plexis';
type Ctx = { result: string };
const pipeline = definePipeline<Ctx>('process', () => {
node('start', () => {
fork('next', target('finish'));
});
// terminal with a final action that patches context before stopping
node('finish', terminal(async (ctx) => ({ result: 'done' })));
return { initial: 'start' };
});