Build

Define a pipeline

Design node graphs with typed payload wiring, branches, loops, child pipelines, and resilient start/signal flows.

Register every capability a graph may reference, then define the graph. Stable registrations give runtime validation and visual authoring a safe capability catalog.

import {
  definePipeline,
  registerPipelineEvent,
  registerPipelineJob,
  registerPipelineWorkflow,
} from "@damatjs/framework";
import { provisionTenant } from "../workflows/provision-tenant";

registerPipelineWorkflow(provisionTenant, {
  inputSchema: { type: "object", required: ["tenantId"] },
});
registerPipelineJob({ name: "billing.invoice" });
registerPipelineEvent({ name: "tenant.ready" });

export const tenantSetup = definePipeline("tenant.setup", {
  version: 1,
  start: "provision",
  inputSchema: { type: "object", required: ["tenantId", "plan"] },
  nodes: [
    {
      id: "provision",
      kind: "workflow",
      name: provisionTenant.name,
      input: { tenantId: { $ref: "input.tenantId" } },
    },
    {
      id: "paid",
      kind: "condition",
      expression: { op: "eq", left: { $ref: "input.plan" }, right: "paid" },
    },
    { id: "invoice", kind: "job", name: "billing.invoice" },
    { id: "announce", kind: "event.publish", event: "tenant.ready" },
  ],
  edges: [
    { from: "provision", to: "paid" },
    {
      from: "paid",
      to: "invoice",
      when: { op: "eq", left: { $ref: "nodes.paid.output" }, right: true },
    },
    {
      from: "paid",
      to: "announce",
      when: { op: "eq", left: { $ref: "nodes.paid.output" }, right: false },
    },
    { from: "invoice", to: "announce" },
  ],
  output: {
    tenantId: { $ref: "input.tenantId" },
    announcement: { $ref: "nodes.announce.output" },
  },
});

$ref reads pipeline input or a completed node's output. Declare output explicitly for branched or forked graphs so the result does not depend on which node happens to finish last.

Code definitions have stable version labels and checksums. Reusing a version label with a changed graph fails startup instead of rewriting running or historical instances.

Pre-arm an event completion wait

An event.wait starts its durable-event history at the creation of its node execution. Correlation filters that history but does not move the boundary backward, so a matching event published before the wait execution exists is not consumed. For start-work/await-completion flows, fork the wait and work branches before publishing the completion event, then require both branches at an all join:

fork ──> event.wait(completion, correlation) ──┐
  └──> work ──> event.publish(completion) ─────┴──> join(all)

This makes the event wait durable and correlated without relying on an earlier fact. If an earlier-history boundary is needed, that must be an additive API; the current graph contract does not provide one.