import type { DtoMessage } from './dto.js'; import type { DomainEventSchema } from './domain-event.js'; import type { ExceptionSchema } from './exception.js'; import type { FlowMethodRef, FlowSchema, FlowSlot, FlowSlots, GuardCondition } from './flow.js'; /** A method call in statement position: invoke(m) mutates the input slot in * place, invoke(m, args) passes one explicit arg slot, invoke(m, args, result) * additionally assigns the method's results to a slot. args may be a slot * list (multi-input methods — e.g. a predicate over two slots). In condition * position (IF(...)), the same call is a utils predicate (result is rejected). */ export interface InvokeStep { kind: 'invoke'; method: FlowMethodRef; args?: FlowSlot | FlowSlot[]; result?: FlowSlot; } /** A construction: the slot is assigned without a method call. */ export interface WriteStep { kind: 'write'; slot: FlowSlot; } /** An unconditional throw (terminal — nothing runs after it in its block). */ export interface ThrowStep { kind: 'throw'; exception: ExceptionSchema; message?: string; } /** An early return to the flow's return end (terminal in its block). */ export interface ReturnStep { kind: 'return'; } /** A domain event publication: writes the event to the outbox inside the * surrounding transaction. The payload slot defaults to the flow input. */ export interface PublishStep { kind: 'publish'; event: DomainEventSchema; payload?: FlowSlot; } /** A conditional: the then-branch runs when the condition holds, the * else-branch (or the next statement) otherwise. */ export interface IfStep { kind: 'if'; cond: GuardCondition; then: ScriptStep[]; else?: ScriptStep[]; } export type CatchRoute = [exception: ExceptionSchema, steps: ScriptStep[]]; /** A protected region: body and catch handlers (and optional finally) compile * to sub-flows; a catch's steps may be empty (swallow). */ export interface TryStep { kind: 'try'; name?: string; body: ScriptStep[]; catches: CatchRoute[]; finally?: ScriptStep[]; } /** A named sub-flow region (a private method inlined as a sub-flow). */ export interface SubStep { kind: 'sub'; name: string; steps: ScriptStep[]; description?: string; } export type ScriptStep = InvokeStep | WriteStep | ThrowStep | ReturnStep | PublishStep | IfStep | TryStep | SubStep; /** Call a method as a statement or (in IF position) as a utils predicate. */ export declare function invoke(method: FlowMethodRef, args?: FlowSlot | FlowSlot[], result?: FlowSlot): InvokeStep; /** Assign a slot without a method call (a construction). */ export declare function write(slot: FlowSlot): WriteStep; /** Throw an exception — inside an IF branch the condition and the exit merge * into one guard check; bare in a block it is an unconditional exit. */ export declare function THROW(exception: ExceptionSchema, message?: string): ThrowStep; /** Return early to the flow's return end. */ export declare function RETURN(): ReturnStep; /** Publish a domain event — the outbox write joins the surrounding * transaction. The payload slot must carry exactly the event's fields * (compile-time checked against the slot's declared message). */ export declare function publish(event: DomainEventSchema, payload?: FlowSlot): PublishStep; export interface IfBuilder { THEN(...steps: ScriptStep[]): IfBuilt; } export interface IfBuilt extends IfStep { ELSE(...steps: ScriptStep[]): IfStep; } /** Conditional step: IF(cond).THEN(...) with optional .ELSE(...). The * condition is a comparison (lt/gt/eq/...) or a predicate call — an * invoke(...) in this position is a utils predicate. */ export declare function IF(cond: GuardCondition | InvokeStep): IfBuilder; export interface TryBuilt extends TryStep { CATCH(...routes: CatchRoute[]): TryBuilt; FINALLY(steps: ScriptStep[]): TryBuilt; } /** Protected region: TRY([...]).CATCH([Exception, [...]], ...).FINALLY([...]). */ export declare function TRY(body: ScriptStep[], name?: string): TryBuilt; /** A named sub-flow region. */ export declare function sub(name: string, steps: ScriptStep[], description?: string): SubStep; /** The script's slot registry: ctx.slots.args and named slots from options.slots. */ export interface FlowCtx { /** Append statements — they run in order. */ next(...steps: ScriptStep[]): void; slots: FlowSlots; } /** Compile a sequential script into a FlowSchema. options.slots declares the * named slots (message bindings); every declared slot must be used somewhere * in the compiled flow. */ export declare function flowScript(name: string, options: { args: DtoMessage; slots?: Record; description?: string; }, build: (ctx: FlowCtx) => void): FlowSchema;