The Workflow class manages nodes and connections in a workflow.
Class: Workflow
class Workflow {
// Properties
id: string;
name: string;
nodes: Map<NodeId, Node>;
graph: Graph;
// Methods
constructor(id?: string, name?: string);
addNode(nodeClass: typeof Node, options?: AddNodeOptions): Node;
removeNode(nodeId: string): void;
getNode(nodeId: string): Node | undefined;
connect(sourceId: string, sourcePort: string, targetId: string, targetPort: string): Connection;
disconnect(connectionId: string): void;
validate(): ValidationResult;
execute(options?: ExecutionOptions): Promise<ExecutionResult>;
toJSON(): WorkflowJSON;
static fromJSON(json: WorkflowJSON): Workflow;
}
Constructor
constructor(id?: string, name?: string);
Optional unique identifier. Auto-generated if not provided.
Optional workflow name. Defaults to 'Untitled Workflow'.
Example:
import { Workflow } from '@crystalflow/core';
const workflow = new Workflow();
// or
const workflow = new Workflow('workflow-1', 'My Workflow');
Properties
Unique workflow identifier.
Workflow name for display.
Map of node IDs to node instances.
Internal graph structure managing connections.
Methods
addNode()
Add a node to the workflow.
addNode(nodeClass: typeof Node, options?: AddNodeOptions): Node;
Node class constructor (must be registered).
Optional configuration:
id?: string - Custom node ID
position?: { x: number; y: number } - Visual position
data?: Record<string, any> - Initial property values
Returns: Created node instance.
Example:
import { AddNode } from './nodes/AddNode';
const node = workflow.addNode(AddNode, {
id: 'add-1',
position: { x: 100, y: 100 },
data: { a: 5, b: 3 }
});
removeNode()
Remove a node from the workflow.
removeNode(nodeId: string): void;
ID of the node to remove.
Example:
workflow.removeNode('add-1');
getNode()
Get a node by ID.
getNode(nodeId: string): Node | undefined;
ID of the node to retrieve.
Returns: Node instance or undefined if not found.
Example:
const node = workflow.getNode('add-1');
if (node) {
console.log(node.type);
}
connect()
Create a connection between two nodes.
connect(
sourceId: string,
sourcePort: string,
targetId: string,
targetPort: string
): Connection;
Output port name on source node.
Input port name on target node.
Returns: Created Connection object.
Example:
workflow.connect('add-1', 'result', 'display-1', 'value');
disconnect()
Remove a connection.
disconnect(connectionId: string): void;
ID of the connection to remove.
Example:
workflow.disconnect('conn-123');
validate()
Validate the workflow structure.
validate(): ValidationResult;
Returns: ValidationResult with validation status and errors.
Checks:
- No cycles in the graph
- All connections are valid
- All required inputs are connected or have default values
- All nodes are valid
Example:
const result = workflow.validate();
if (!result.isValid) {
console.error('Validation errors:', result.errors);
}
execute()
Execute the workflow.
execute(options?: ExecutionOptions): Promise<ExecutionResult>;
Optional execution configuration:
timeout?: number - Maximum execution time (ms)
variables?: Record<string, any> - Workflow variables
abortSignal?: AbortSignal - Cancellation signal
Returns: Promise resolving to ExecutionResult.
Example:
const result = await workflow.execute({
timeout: 30000,
variables: { apiKey: 'xxx' }
});
console.log(result.status); // 'success'
console.log(result.duration); // 1523 (ms)
toJSON()
Serialize workflow to JSON.
Returns: JSON representation of the workflow.
Example:
const json = workflow.toJSON();
console.log(json);
// {
// version: '1.0.0',
// id: 'workflow-1',
// name: 'My Workflow',
// nodes: [...],
// connections: [...],
// variables: {}
// }
fromJSON()
Deserialize workflow from JSON.
static fromJSON(json: WorkflowJSON): Workflow;
JSON representation of the workflow.
Returns: New Workflow instance.
Example:
const json = { version: '1.0.0', id: 'workflow-1', nodes: [...], connections: [...] };
const workflow = Workflow.fromJSON(json);
Types
AddNodeOptions
interface AddNodeOptions {
id?: string;
position?: { x: number; y: number };
data?: Record<string, any>;
}
ExecutionOptions
interface ExecutionOptions {
timeout?: number;
variables?: Record<string, any>;
abortSignal?: AbortSignal;
}
ExecutionResult
interface ExecutionResult {
id: string;
workflowId: string;
status: 'success' | 'failed' | 'cancelled';
startTime: Date;
endTime?: Date;
duration?: number;
nodeResults: Map<string, NodeExecutionResult>;
error?: Error;
cancellationReason?: CancellationReason;
cancelledAt?: Date;
}
WorkflowJSON
interface WorkflowJSON {
version: string;
id: string;
name: string;
nodes: NodeJSON[];
connections: ConnectionJSON[];
variables: Record<string, any>;
}
Usage Examples
Basic Workflow
import { Workflow } from '@crystalflow/core';
import { NumberInputNode, AddNode, DisplayNode } from './nodes';
// Create workflow
const workflow = new Workflow('calc-workflow', 'Calculator');
// Add nodes
const num1 = workflow.addNode(NumberInputNode, {
position: { x: 100, y: 100 },
data: { value: 5 }
});
const num2 = workflow.addNode(NumberInputNode, {
position: { x: 100, y: 200 },
data: { value: 3 }
});
const add = workflow.addNode(AddNode, {
position: { x: 300, y: 150 }
});
const display = workflow.addNode(DisplayNode, {
position: { x: 500, y: 150 }
});
// Connect nodes
workflow.connect(num1.id, 'value', add.id, 'a');
workflow.connect(num2.id, 'value', add.id, 'b');
workflow.connect(add.id, 'result', display.id, 'value');
// Execute
const result = await workflow.execute();
console.log(result.status); // 'success'
Save and Load
// Save workflow
const json = workflow.toJSON();
const jsonString = JSON.stringify(json, null, 2);
await fs.writeFile('workflow.json', jsonString);
// Load workflow
const loaded = JSON.parse(await fs.readFile('workflow.json', 'utf-8'));
const workflow = Workflow.fromJSON(loaded);
Validation Before Execute
const validation = workflow.validate();
if (!validation.isValid) {
console.error('Workflow is invalid:');
validation.errors?.forEach(error => console.error(`- ${error}`));
return;
}
const result = await workflow.execute();