API Reference

Complete reference for Floww's internal APIs, events, and data model.

The floww object is passed to every plugin lifecycle hook and provides access to all of Floww's internal systems. This page documents every available method, event, and data structure.

Canvas API

The floww.canvas namespace provides methods to manipulate the visual canvas — adding/removing nodes, controlling the viewport, and querying positions.

MethodReturnsDescription
pan(x, y) void Pan the canvas by the given delta in world coordinates.
panTo(x, y) void Center the viewport on the given world coordinates.
zoom(level) void Set the zoom level. 1.0 is 100%. Range: 0.1 to 5.0.
zoomBy(delta) void Adjust zoom by a relative amount (e.g., 0.1 to zoom in, -0.1 to zoom out).
fitToView(padding?) void Auto-zoom and pan to fit all nodes in the viewport. Optional padding in pixels (default: 50).
getViewport() Viewport Returns { x, y, width, height, zoom } describing the visible area in world coordinates.
addNode(type, position, config?) Node Create a new node on the canvas. position is { x, y }. Returns the created Node object.
removeNode(nodeId) boolean Remove a node and all its connected edges. Returns true if the node existed.
addEdge(sourceNodeId, sourcePort, targetNodeId, targetPort) Edge Connect two ports. Returns the created Edge object. Throws if the connection would create a cycle.
removeEdge(edgeId) boolean Remove a wire between two ports. Returns true if the edge existed.
getSelectedNodes() Node[] Returns an array of currently selected nodes.
selectNodes(nodeIds) void Set the selection to the given node IDs.
clearSelection() void Deselect all nodes.

Example

// Create two nodes and wire them together
const httpNode = floww.canvas.addNode('http-request', { x: 100, y: 200 }, {
  method: 'GET',
  url: 'https://api.example.com/data'
});

const parseNode = floww.canvas.addNode('json-parse', { x: 400, y: 200 });

floww.canvas.addEdge(httpNode.id, 'response', parseNode.id, 'input');
floww.canvas.fitToView(80);

Nodes API

The floww.nodes namespace handles node type registration and runtime interaction with node instances.

MethodReturnsDescription
register(definition) void Register a custom node type. The definition object must include type, displayName, inputs, outputs, and execute. See Custom Node Development.
registerAll(definitions[]) void Register multiple node types at once.
unregister(type) boolean Remove a registered node type. Existing instances on the canvas become inert.
get(nodeId) Node | null Get a node instance by its ID. Returns null if not found.
getAll() Node[] Get all node instances in the current workflow.
getByType(type) Node[] Get all node instances of a specific type.
execute(nodeId) Promise<object> Trigger execution of a single node. Returns a promise that resolves with the node's outputs.
validate(nodeId) ValidationResult Validate a node's configuration and input connections. Returns { valid: boolean, errors: string[] }.
getRegisteredTypes() string[] List all registered node type identifiers (built-in and custom).

Events

The floww.events namespace provides a pub/sub event bus for inter-system and inter-plugin communication.

Methods

MethodDescription
on(event, callback)Subscribe to an event. The callback receives an event data object.
off(event, callback)Unsubscribe a previously registered callback.
once(event, callback)Subscribe to an event, but auto-unsubscribe after the first invocation.
emit(event, data)Emit a custom event with associated data.

Built-in events

EventData shapeEmitted when
node:added { nodeId, type, position } A new node is placed on the canvas
node:removed { nodeId, type } A node is deleted from the canvas
node:executed { nodeId, outputs, duration, status } A node finishes execution (success or error)
edge:connected { edgeId, source: { nodeId, port }, target: { nodeId, port } } Two ports are wired together
edge:disconnected { edgeId, source: { nodeId, port }, target: { nodeId, port } } A wire is removed
workflow:started { workflowName, nodeCount } A workflow execution begins
workflow:completed { workflowName, duration, nodesExecuted } All nodes have finished successfully
workflow:error { workflowName, error, failedNodeId } A workflow-level error occurs
Custom event naming
When emitting custom events from your plugin, namespace them with your plugin name to avoid collisions: myplugin:event-name. Built-in events use the namespace:action format.

Hooks

Hooks are synchronous interceptors that let you modify behavior at specific points in the execution pipeline. Unlike events (which are notifications after something happened), hooks run before the action completes and can modify or cancel it.

onNodeExecute

floww.hooks.onNodeExecute((nodeId, inputs, config) => {
  // Inspect or modify inputs before the node runs
  console.log(`About to execute ${nodeId}`);

  // Return modified inputs, or return undefined to leave them unchanged
  return {
    ...inputs,
    timestamp: Date.now()  // inject extra data
  };
});

onWorkflowComplete

floww.hooks.onWorkflowComplete((result) => {
  // Called after all nodes finish but before the UI updates
  console.log(`Workflow done. ${result.nodesExecuted} nodes in ${result.duration}ms`);

  // Send metrics to an external service
  fetch('https://metrics.example.com/track', {
    method: 'POST',
    body: JSON.stringify(result)
  });
});

onNodeError

floww.hooks.onNodeError((nodeId, error) => {
  // Intercept errors before they reach the default handler
  console.error(`Node ${nodeId} failed:`, error.message);

  // Return a replacement error, or return null to suppress
  if (error.message.includes('rate limit')) {
    return new Error('Service rate-limited. Try again in 60 seconds.');
  }
  return error;  // pass through unchanged
});

onCanvasChange

floww.hooks.onCanvasChange((change) => {
  // Fires on any canvas modification: node add/remove/move, edge add/remove
  // change.type: 'node:add' | 'node:remove' | 'node:move' | 'edge:add' | 'edge:remove'
  console.log(`Canvas changed: ${change.type}`, change.data);
});

Data Model

These are the core data structures used throughout the Floww API. Shown in TypeScript-style interface notation for clarity.

Node

interface Node {
  id: string;                    // Unique identifier (UUID)
  type: string;                  // Registered node type (e.g., 'http-request')
  displayName: string;           // Human-readable name
  position: { x: number; y: number };
  config: Record<string, any>;   // User-configured values
  state: 'idle' | 'init' | 'validate' | 'execute' | 'complete' | 'error';
  inputs: Port[];
  outputs: Port[];
  error?: {
    message: string;
    stack?: string;
  };
  lastExecuted?: string;         // ISO 8601 timestamp
  duration?: number;             // Last execution time in ms
}

Edge

interface Edge {
  id: string;                    // Unique identifier (UUID)
  source: {
    nodeId: string;              // Source node ID
    port: string;                // Output port name
  };
  target: {
    nodeId: string;              // Target node ID
    port: string;                // Input port name
  };
}

Port

interface Port {
  name: string;                  // Port identifier
  type: 'string' | 'number' | 'boolean' | 'object' | 'array' | 'any';
  description?: string;
  optional?: boolean;            // Default: false
}

Variable

interface Variable {
  name: string;                  // Variable key
  type: 'string' | 'number' | 'boolean' | 'object';
  value: any;                    // Current value
  sensitive: boolean;            // If true, encrypted at rest and masked in UI
  description?: string;
}

Viewport

interface Viewport {
  x: number;       // Left edge in world coordinates
  y: number;       // Top edge in world coordinates
  width: number;   // Visible width in world coordinates
  height: number;  // Visible height in world coordinates
  zoom: number;    // Current zoom level (1.0 = 100%)
}

Variables API

The floww.variables namespace provides access to workflow-level variables. Variables are key-value pairs that persist across executions and can be referenced from node configurations using the {{variableName}} syntax.

MethodReturnsDescription
get(name) any Get the current value of a variable. Returns undefined if the variable does not exist.
set(name, value) void Set a variable's value. Creates the variable if it doesn't exist. Emits variable:changed.
getAll() Variable[] Get all variables in the current workflow as an array of Variable objects.
delete(name) boolean Remove a variable. Returns true if it existed.
subscribe(name, callback) () => void Watch a specific variable for changes. The callback receives { name, oldValue, newValue }. Returns an unsubscribe function.

Example

// Set and read variables
floww.variables.set('apiBaseUrl', 'https://api.example.com');
floww.variables.set('maxRetries', 3);

const baseUrl = floww.variables.get('apiBaseUrl');
console.log(baseUrl); // 'https://api.example.com'

// Watch for changes
const unsubscribe = floww.variables.subscribe('maxRetries', (change) => {
  console.log(`maxRetries changed from ${change.oldValue} to ${change.newValue}`);
});

// Later, stop watching
unsubscribe();
Sensitive variables
Variables marked as sensitive (like API keys) are encrypted at rest and their values are masked in the UI. Your plugin can still read them via floww.variables.get(), but this requires the variables:read permission.