behemoth-cli
Version:
🌍 BEHEMOTH CLIv3.760.4 - Level 50+ POST-SINGULARITY Intelligence Trading AI
283 lines (249 loc) • 7.55 kB
text/typescript
import {
N8nWorkflow,
N8nNode,
N8nConnection,
SuperCodeNode,
createSuperCodeNode,
generateNodeId
} from './n8n-types.js';
import { N8N_SUPER_CODE_GLOBAL_LIBRARIES, SUPER_CODE_NODE_TYPE, N8N_WORKFLOW_DEFAULT_SETTINGS } from '../utils/constants.js';
export class N8nWorkflowBuilder {
private workflow: Partial<N8nWorkflow>;
private nodes: N8nNode[] = [];
private connections: Record<string, N8nConnection[]> = {};
private nodeCounter = 0;
constructor(name: string = 'Generated Workflow') {
this.workflow = {
name,
nodes: [],
connections: {},
active: false,
settings: N8N_WORKFLOW_DEFAULT_SETTINGS,
staticData: null,
meta: {},
tags: []
};
}
// Add a generic node
addNode(node: N8nNode): string {
const nodeId = node.id || generateNodeId();
node.id = nodeId;
this.nodes.push(node);
return nodeId;
}
// Add a Super Code node
addSuperCodeNode(
name: string,
code: string,
position: [number, number] = [this.nodeCounter * 300, 0],
mode: 'runOnceForAllItems' | 'runOnceForEachItem' = 'runOnceForAllItems'
): string {
const superNode = createSuperCodeNode(name, code, position, mode);
this.nodeCounter++;
return this.addNode(superNode);
}
// Add a standard n8n node
addStandardNode(
type: string,
name: string,
parameters: Record<string, any> = {},
position: [number, number] = [this.nodeCounter * 300, 0]
): string {
const node: N8nNode = {
parameters,
name,
type,
typeVersion: 1,
position,
id: generateNodeId()
};
this.nodeCounter++;
return this.addNode(node);
}
// Connect two nodes
connectNodes(
sourceNodeId: string,
targetNodeId: string,
sourceOutput: string = 'main',
targetInput: string = 'main',
sourceIndex: number = 0
): void {
if (!this.connections[sourceNodeId]) {
this.connections[sourceNodeId] = [];
}
this.connections[sourceNodeId].push({
node: targetNodeId,
type: targetInput,
index: sourceIndex
});
}
// Add a trigger node (common starting point)
addTriggerNode(type: string = 'n8n-nodes-base.manualTrigger', name: string = 'Manual Trigger'): string {
return this.addStandardNode(type, name, {}, [0, 0]);
}
// Add a webhook trigger
addWebhookTrigger(
name: string = 'Webhook',
path: string = '/webhook',
method: string = 'POST'
): string {
const parameters = {
path,
httpMethod: method,
responseMode: 'lastNode',
options: {}
};
return this.addStandardNode('n8n-nodes-base.webhook', name, parameters, [0, 0]);
}
// Add a schedule trigger
addScheduleTrigger(
name: string = 'Schedule',
cronExpression: string = '0 0 * * *'
): string {
const parameters = {
rule: {
interval: [{
field: 'cronExpression',
expression: cronExpression
}]
}
};
return this.addStandardNode('n8n-nodes-base.scheduleTrigger', name, parameters, [0, 0]);
}
// Add an HTTP Request node
addHttpRequestNode(
name: string = 'HTTP Request',
url: string = '',
method: string = 'GET',
position?: [number, number]
): string {
const parameters = {
url,
method,
sendBody: method !== 'GET',
bodyContentType: 'json',
options: {}
};
return this.addStandardNode('n8n-nodes-base.httpRequest', name, parameters, position);
}
// Add a Set node for data manipulation
addSetNode(
name: string = 'Set',
values: Record<string, any> = {},
position?: [number, number]
): string {
const parameters = {
values: {
...values
},
options: {}
};
return this.addStandardNode('n8n-nodes-base.set', name, parameters, position);
}
// Add an If node for conditional logic
addIfNode(
name: string = 'IF',
conditions: any = {},
position?: [number, number]
): string {
const parameters = {
conditions,
options: {}
};
return this.addStandardNode('n8n-nodes-base.if', name, parameters, position);
}
// Build the final workflow
build(): N8nWorkflow {
return {
...this.workflow,
nodes: this.nodes,
connections: this.connections
} as N8nWorkflow;
}
// Get workflow as JSON string
toJSON(): string {
return JSON.stringify(this.build(), null, 2);
}
// Validate the workflow structure
validate(): { valid: boolean; errors: string[] } {
const errors: string[] = [];
if (this.nodes.length === 0) {
errors.push('Workflow must have at least one node');
return { valid: false, errors };
}
// Check for nodes that have no connections at all (completely isolated)
const allConnectedNodes = new Set<string>();
// Add all source nodes
Object.keys(this.connections).forEach(sourceId => {
allConnectedNodes.add(sourceId);
});
// Add all target nodes
Object.values(this.connections).forEach(connections => {
connections.forEach(conn => allConnectedNodes.add(conn.node));
});
// Check for completely isolated nodes
this.nodes.forEach(node => {
if (!allConnectedNodes.has(node.id)) {
// Allow single-node workflows or trigger nodes
const isTriggerNode = node.type.includes('Trigger') ||
node.type === 'n8n-nodes-base.manualTrigger' ||
node.type === 'n8n-nodes-base.webhook' ||
node.type === 'n8n-nodes-base.scheduleTrigger';
if (this.nodes.length > 1 && !isTriggerNode) {
errors.push(`Node "${node.name}" (${node.id}) is not connected to the workflow`);
}
}
});
// Check for invalid connection targets
Object.entries(this.connections).forEach(([sourceId, connections]) => {
connections.forEach((connection, index) => {
const targetExists = this.nodes.some(node => node.id === connection.node);
if (!targetExists) {
errors.push(`Connection from "${sourceId}" to "${connection.node}" targets a non-existent node`);
}
});
});
return { valid: errors.length === 0, errors };
}
// Reset the builder
reset(): void {
this.nodes = [];
this.connections = {};
this.nodeCounter = 0;
}
}
// Helper functions for common workflow patterns
export function createBasicWorkflowWithSuperCode(
name: string,
superCode: string,
triggerType: 'manual' | 'webhook' | 'schedule' = 'manual'
): N8nWorkflowBuilder {
const builder = new N8nWorkflowBuilder(name);
let triggerId: string;
switch (triggerType) {
case 'webhook':
triggerId = builder.addWebhookTrigger();
break;
case 'schedule':
triggerId = builder.addScheduleTrigger();
break;
default:
triggerId = builder.addTriggerNode();
}
const superCodeId = builder.addSuperCodeNode('Super Code', superCode, [300, 0]);
builder.connectNodes(triggerId, superCodeId);
return builder;
}
export function createHttpWorkflowWithSuperCode(
name: string,
url: string,
superCode: string
): N8nWorkflowBuilder {
const builder = new N8nWorkflowBuilder(name);
const triggerId = builder.addTriggerNode();
const httpId = builder.addHttpRequestNode('HTTP Request', url, 'GET', [300, 0]);
const superCodeId = builder.addSuperCodeNode('Process Data', superCode, [600, 0]);
builder.connectNodes(triggerId, httpId);
builder.connectNodes(httpId, superCodeId);
return builder;
}