Skip to content

Flow Hooks API

The Flow component exposes a comprehensive API through window.$useFlowCore that allows external JavaScript to configure, control, and interact with the flow editor.


// Hooks are available after flow.js is loaded
const {
configure,
getApp,
getFlow,
setFlow,
pushingNode,
pushNode,
reset,
clear,
theme,
setTheme,
onMapperPreview,
setMapperPreviewResult,
setStore,
setWorkflows,
setWorkflow,
} = window.$useFlowCore;

HookSignatureDescription
configure(signature: string, apps: App[]) => voidRegister available action modules
getApp(module: string) => App | undefinedGet app configuration by module name
HookSignatureDescription
getFlow() => WorkFlowGet current flow data (nodes, edges, variables)
setFlow(flow: WorkFlow) => voidLoad a flow into the editor
clear() => voidClear the entire flow
reset(nodeId?: string) => voidReset execution state
HookSignatureDescription
pushingNode(params: Response) => voidSignal that a node is executing
pushNode(params: Result) => voidReport node execution result
HookSignatureDescription
themeRef<'light' | 'dark'>Current theme value (reactive)
setTheme(theme: 'light' | 'dark') => voidChange the theme
HookSignatureDescription
onMapperPreview(fn: Function) => voidRegister mapper preview callback
setMapperPreviewResult(logs: any) => voidReport mapper preview results
HookSignatureDescription
setWorkflows(workflows: any) => voidSet available subflow workflows
setWorkflow(workflow: any) => voidSet a specific subflow
HookSignatureDescription
setStore(data: any) => voidSet additional store data

Register the available action modules that users can add to the flow:

const { configure } = window.$useFlowCore;
configure('ion.action', [
{
module: 'ion.action.http',
label: 'HTTP Request',
icon: 'globe',
group: 'core',
color: '#3B82F6',
spec: {
type: 'collection',
spec: [
{
type: 'select',
name: 'method',
label: 'Method',
options: [
{ label: 'GET', value: 'GET' },
{ label: 'POST', value: 'POST' },
{ label: 'PUT', value: 'PUT' },
{ label: 'DELETE', value: 'DELETE' },
],
},
{ type: 'url', name: 'url', label: 'URL', required: true },
{ type: 'text', name: 'body', label: 'Body', multiline: true },
],
},
},
{
module: 'ion.action.condition',
label: 'Condition',
icon: 'git-branch',
group: 'logic',
color: '#8B5CF6',
spec: {
type: 'collection',
spec: [
{ type: 'text', name: 'expression', label: 'Condition Expression' },
],
},
},
]);

Retrieve an app’s configuration by its module identifier:

const { getApp } = window.$useFlowCore;
const httpApp = getApp('ion.action.http');
if (httpApp) {
console.log('HTTP app label:', httpApp.label);
console.log('HTTP app spec:', httpApp.spec);
}

Get the current flow state including all nodes, edges, and variables:

const { getFlow } = window.$useFlowCore;
const flowData = getFlow();
// {
// nodes: [...],
// edges: [...],
// variables: {...}
// }
// Save to backend
await api.saveFlow(flowId, flowData);

Load a flow into the editor:

const { setFlow } = window.$useFlowCore;
const savedFlow = await api.getFlow(flowId);
setFlow({
nodes: savedFlow.nodes || [],
edges: savedFlow.edges || [],
variables: savedFlow.variables || {},
});

Clear all nodes and edges from the flow:

const { clear } = window.$useFlowCore;
function handleNewFlow() {
if (confirm('Create new flow? All changes will be lost.')) {
clear();
}
}

Reset execution state. If nodeId is provided, only reset that node’s context:

const { reset } = window.$useFlowCore;
// Reset all execution state
reset();
// Reset specific node
reset('node_123');

Signal that a node has started executing. This animates the incoming edge:

const { pushingNode } = window.$useFlowCore;
pushingNode({
node: 'node_123',
queue: {
edge_id: 'edge_456', // Edge being traversed
target: 'node_123', // Target node
data: { input: 'data' }, // Input data
},
message: null, // Error message if any
});

Report the result of node execution:

const { pushNode } = window.$useFlowCore;
// Success case
pushNode({
node: { id: 'node_123', data: { /* node config */ } },
status: 'success',
message: null,
edges: ['edge_789', 'edge_790'], // Outgoing edges
outputs: [
{ data: { response: 'data' } },
],
});
// Error case
pushNode({
node: { id: 'node_123' },
status: 'error',
message: 'Connection timeout after 30s',
edges: [],
outputs: [],
});

async function executeNode(nodeId: string) {
const {
getFlow,
pushingNode,
pushNode,
reset
} = window.$useFlowCore;
// 1. Reset any previous state for this node
reset(nodeId);
// 2. Get current flow state
const flow = getFlow();
const node = flow.nodes.find(n => n.id === nodeId);
if (!node) {
console.error('Node not found:', nodeId);
return;
}
// 3. Find the edge coming into this node
const incomingEdge = flow.edges.find(e => e.target === nodeId);
// 4. Signal execution start
pushingNode({
node: nodeId,
queue: {
edge_id: incomingEdge?.id ?? null,
target: nodeId,
data: node.data,
},
});
try {
// 5. Execute on backend
const result = await fetch('/api/execute', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
flowId: currentFlowId,
nodeId,
nodeType: node.type,
nodeData: node.data,
context: getExecutionContext(),
}),
}).then(r => r.json());
// 6. Report success
const outgoingEdges = flow.edges
.filter(e => e.source === nodeId)
.map(e => e.id);
pushNode({
node,
status: 'success',
message: null,
edges: outgoingEdges,
outputs: [{ data: result.output }],
});
} catch (error) {
// 6. Report error
pushNode({
node,
status: 'error',
message: error.message,
edges: [],
outputs: [],
});
}
}

const { theme, setTheme } = window.$useFlowCore;
// Read current theme (this is a Vue ref)
console.log('Current theme:', theme.value);
// Change theme
setTheme('dark');
// Toggle theme
function toggleTheme() {
setTheme(theme.value === 'light' ? 'dark' : 'light');
}

SubFlows allow embedding other workflows as nodes:

const { setWorkflows, setWorkflow } = window.$useFlowCore;
// Load all available subflows
const subflows = await api.getSubflows();
setWorkflows(subflows);
// Set a specific subflow for a node
setWorkflow({
id: 'subflow_123',
name: 'Order Processing',
nodes: [...],
edges: [...],
});

When using the mapper within nodes:

const { onMapperPreview, setMapperPreviewResult } = window.$useFlowCore;
// Register callback for when user clicks "Preview" in mapper
onMapperPreview(async (flow, params) => {
const result = await api.post('/mapper/preview', {
flow,
params,
});
setMapperPreviewResult(result.logs);
});

types/flow-hooks.d.ts
import type { Field } from '@ion-components/ui/types';
import type { Ref } from 'vue';
interface App {
module: string;
label: string;
icon?: string;
group?: string;
color?: string;
spec?: Field;
}
interface WorkFlow {
nodes: Array<{
id: string;
type: string;
position: { x: number; y: number };
data: Record<string, any>;
}>;
edges: Array<{
id: string;
source: string;
target: string;
sourceHandle?: string;
targetHandle?: string;
}>;
variables?: Record<string, any>;
}
interface Response {
node: string;
queue: {
edge_id: string | null;
target: string;
data?: any;
};
message?: string | null;
}
interface Result {
node: { id: string; data?: any };
status: 'success' | 'error';
message?: string | null;
edges?: string[];
outputs?: Array<{ data: any }>;
}
declare global {
interface Window {
$useFlowCore: {
configure: (signature: string, apps: App[]) => void;
getApp: (module: string) => App | undefined;
getFlow: () => WorkFlow;
setFlow: (flow: WorkFlow) => void;
clear: () => void;
reset: (nodeId?: string) => void;
pushingNode: (params: Response) => void;
pushNode: (params: Result) => void;
theme: Ref<'light' | 'dark'>;
setTheme: (theme: 'light' | 'dark') => void;
onMapperPreview: (fn: (flow: any, params: any) => void) => void;
setMapperPreviewResult: (logs: any) => void;
setStore: (data: any) => void;
setWorkflows: (workflows: any) => void;
setWorkflow: (workflow: any) => void;
};
}
}
export {};