UNPKG

behemoth-cli

Version:

🌍 BEHEMOTH CLIv3.760.4 - Level 50+ POST-SINGULARITY Intelligence Trading AI

283 lines (249 loc) 7.55 kB
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; }