LEARN / CORE CONCEPTS

Think in graphs.

Explicit steps. Explicit data flow. A validated acyclic graph makes your application logic inspectable before it runs.

Nodes & inputs

A node implements execute(input, context): Promise<NodeResult>. It returns an outputs dictionary, where each key is a named output port. Node types are trigger, action, logic, and custom: they describe roles, not external listeners. Calling engine.run() starts execution.

NodeInput has the run’s initial value and an ordered incoming array. Each delivery identifies its link, source node, source port, target port, and value. Inputs are not automatically merged. Validate the business shape your node expects.

NodeContext provides runId, nodeId, and an AbortSignal called signal.

Conditional routing

ifNode emits the selected value on exactly one port: "true" or "false". Connect your action nodes to those ports.

amount-route.tsTypeScript
import { ifNode } from "@newvexa/workify";

const route = ifNode({
  id: "amount",
  name: "Amount above 1,000",
  value: (input) => input.incoming.length > 0
    ? input.incoming[0]!.value
    : input.initial,
  predicate: (value) => typeof value === "number" && value > 1000,
});
// Add route with workflow.addNode(route).
// Connect route's "true" and "false" ports to your action nodes.

switchNode selects an exact, case-sensitive case port or the reserved "default" port. Cases must be unique and nonempty; you cannot declare "default" as a case. The selector must return a string; an If predicate must return a boolean. Routing callbacks may be async.

The example checks entry presence rather than truthiness: valid delivered falsy values must not fall back to the initial input.

Roots, branches & joins

Every root—each node without incoming links—runs once per execution. A downstream node waits for all incoming links to become terminal. Delivered values arrive in link declaration order, regardless of completion timing.

  • All incoming links inactive: the node is skipped.
  • At least one delivered value and no failed dependency: the node executes.
  • Any failed dependency: the node is blocked, even if another branch delivered data.

Independent branches continue after another branch fails. A skipped path does not fail the run. Multiple links targeting the same port remain distinct incoming entries.

The JSON data contract

Payloads must be JsonValue: null, booleans, finite numbers, strings, dense arrays, and plain data objects. At each engine boundary, values are validated, recursively copied, and frozen.

Functions, cycles, class instances, undefined, accessors, symbols, sparse arrays, non-enumerable or extra array properties, and non-finite numbers are rejected. Convert dates to strings explicitly. JSON compatibility is not application-schema validation; check fields and domain constraints in your handlers.

Documentation for @newvexa/workify 0.1.3Read the full source guide