UNPKG

flowengine-n8n-workflow-builder

Version:

Build n8n workflows from text using AI. Connect to Claude, Cursor, or any LLM to generate and validate n8n workflows with expert knowledge and intelligent auto-fixing. Built by FlowEngine. Now with real node parameter schemas from n8n packages!

102 lines 3.66 kB
/** * Dynamic Node Loader * * Loads actual n8n node descriptions and properties from node modules */ import { readFileSync } from 'fs'; import { join, dirname } from 'path'; import { createRequire } from 'module'; const require = createRequire(import.meta.url); const nodeDescriptionCache = new Map(); /** * Load node description from n8n package */ export async function loadNodeDescription(nodeType) { if (nodeDescriptionCache.has(nodeType)) { return nodeDescriptionCache.get(nodeType); } try { // Extract package and node name const [packageName, ...nodeNameParts] = nodeType.split('.'); const nodeName = nodeNameParts.join('.'); // Map package names to npm packages const packageMap = { 'n8n-nodes-base': 'n8n-nodes-base', '@n8n/n8n-nodes-langchain': '@n8n/n8n-nodes-langchain', }; const npmPackage = packageMap[packageName]; if (!npmPackage) { console.error(`Unknown package: ${packageName}`); return null; } // Load package.json to find node path const pkgPath = require.resolve(`${npmPackage}/package.json`); const pkg = JSON.parse(readFileSync(pkgPath, 'utf8')); // Find the node file if (!pkg.n8n || !pkg.n8n.nodes) { return null; } // Try to find the node by matching the name const nodeFile = pkg.n8n.nodes.find((n) => { const fileName = n.split('/').pop()?.replace('.node.js', '') || ''; const fileNodeName = fileName.charAt(0).toLowerCase() + fileName.slice(1); return fileNodeName === nodeName || fileName.toLowerCase() === nodeName.toLowerCase(); }); if (!nodeFile) { console.error(`Node file not found for ${nodeType}`); return null; } // Load the node class const nodeModulePath = join(dirname(pkgPath), nodeFile); const nodeModule = await import(nodeModulePath); // Get the default export (the node class) const NodeClass = nodeModule.default || nodeModule; if (!NodeClass || !NodeClass.description) { console.error(`No description found for ${nodeType}`); return null; } const description = NodeClass.description; nodeDescriptionCache.set(nodeType, description); return description; } catch (error) { console.error(`Failed to load node description for ${nodeType}:`, error); return null; } } /** * Generate default parameters from node description */ export function generateDefaultParameters(description) { const params = {}; if (!description.properties) { return params; } for (const prop of description.properties) { // Skip if has displayOptions that would hide it if (prop.default !== undefined) { params[prop.name] = prop.default; } else if (prop.type === 'string') { params[prop.name] = ''; } else if (prop.type === 'number') { params[prop.name] = 0; } else if (prop.type === 'boolean') { params[prop.name] = false; } else if (prop.type === 'options' && prop.options && prop.options.length > 0) { params[prop.name] = prop.options[0].value; } } return params; } /** * Get parameter schema for a node type */ export async function getNodeParameterSchema(nodeType) { const description = await loadNodeDescription(nodeType); return description?.properties || null; } //# sourceMappingURL=node-loader.js.map