UNPKG

n8n-nodes-xcredentialsx

Version:

Enhanced n8n nodes for credentials management and improved node execution with dropdown selection

292 lines (291 loc) 13.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.RunNodeWithCredentialsXImproved = void 0; const n8n_workflow_1 = require("n8n-workflow"); class RunNodeWithCredentialsXImproved { constructor() { this.description = { displayName: 'Run Node With Credentials X (Improved)', name: 'runNodeWithCredentialsXImproved', group: ['transform'], version: 1, icon: 'fa:key', subtitle: '={{"CredentialId: " + $parameter["credentialsId"]}}', description: 'Run any node with specified credentials - with dropdown selection', defaults: { name: 'Run Node With Credentials X (Improved)', }, inputs: ["main" /* NodeConnectionType.Main */], outputs: ["main" /* NodeConnectionType.Main */], credentials: [ { name: 'n8nApi', required: true, }, ], properties: [ { displayName: 'Credentials ID', name: 'credentialsId', type: 'options', typeOptions: { loadOptionsMethod: 'getCredentials', }, default: '', required: true, description: 'Select the credentials to use', }, { displayName: 'Node Selection Method', name: 'nodeSelectionMethod', type: 'options', options: [ { name: 'Select from Existing Nodes', value: 'selectExisting', description: 'Choose from nodes in existing workflows', }, { name: 'Paste Node JSON', value: 'pasteJson', description: 'Manually paste node JSON configuration', }, ], default: 'selectExisting', description: 'How to specify the node to execute', }, { displayName: 'Workflow', name: 'workflowId', type: 'options', typeOptions: { loadOptionsMethod: 'getWorkflows', }, displayOptions: { show: { nodeSelectionMethod: ['selectExisting'], }, }, default: '', description: 'Select the workflow containing the node', }, { displayName: 'Node', name: 'nodeId', type: 'options', typeOptions: { loadOptionsMethod: 'getNodesFromWorkflow', loadOptionsDependsOn: ['workflowId'], }, displayOptions: { show: { nodeSelectionMethod: ['selectExisting'], }, }, default: '', description: 'Select the node to execute', }, { displayName: 'Node JSON', name: 'nodeJson', type: 'json', displayOptions: { show: { nodeSelectionMethod: ['pasteJson'], }, }, required: true, default: '', description: 'JSON configuration of the node to execute', }, { displayName: 'Override Credentials', name: 'overrideCredentials', type: 'boolean', default: true, description: 'Whether to override the node\'s original credentials with the selected ones', }, ], }; this.methods = { loadOptions: { // 获取所有可用的 credentials async getCredentials() { try { const credentials = await this.helpers.requestWithAuthentication.call(this, 'n8nApi', { method: 'GET', url: '/rest/credentials', json: true, }); const options = []; if (Array.isArray(credentials.data)) { for (const credential of credentials.data) { options.push({ name: `${credential.name} (${credential.type}) - ${credential.id}`, value: credential.id, description: `Type: ${credential.type}, Created: ${credential.createdAt}`, }); } } return options.sort((a, b) => a.name.localeCompare(b.name)); } catch (error) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Failed to load credentials: ${error instanceof Error ? error.message : 'Unknown error'}`); } }, // 获取所有工作流 async getWorkflows() { try { const workflows = await this.helpers.requestWithAuthentication.call(this, 'n8nApi', { method: 'GET', url: '/rest/workflows', json: true, }); const options = []; if (Array.isArray(workflows.data)) { for (const workflow of workflows.data) { options.push({ name: `${workflow.name} (${workflow.id})`, value: workflow.id, description: `Active: ${workflow.active}, Updated: ${workflow.updatedAt}`, }); } } return options.sort((a, b) => a.name.localeCompare(b.name)); } catch (error) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Failed to load workflows: ${error instanceof Error ? error.message : 'Unknown error'}`); } }, // 获取指定工作流中的节点 async getNodesFromWorkflow() { try { const workflowId = this.getCurrentNodeParameter('workflowId'); if (!workflowId) { return []; } const workflow = await this.helpers.requestWithAuthentication.call(this, 'n8nApi', { method: 'GET', url: `/rest/workflows/${workflowId}`, json: true, }); const options = []; if (workflow.nodes && Array.isArray(workflow.nodes)) { for (const node of workflow.nodes) { // 只显示有 credentials 的节点 if (node.credentials && Object.keys(node.credentials).length > 0) { const credentialTypes = Object.keys(node.credentials).join(', '); options.push({ name: `${node.name} (${node.type})`, value: node.id, description: `Type: ${node.type}, Credentials: ${credentialTypes}`, }); } } } return options.sort((a, b) => a.name.localeCompare(b.name)); } catch (error) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Failed to load nodes from workflow: ${error instanceof Error ? error.message : 'Unknown error'}`); } }, }, }; } async execute() { var _a; const items = this.getInputData(); const returnData = []; for (let i = 0; i < items.length; i++) { try { const credentialsId = this.getNodeParameter('credentialsId', i); const nodeSelectionMethod = this.getNodeParameter('nodeSelectionMethod', i); const overrideCredentials = this.getNodeParameter('overrideCredentials', i, true); let nodeJson; if (nodeSelectionMethod === 'selectExisting') { // 从选择的工作流和节点获取配置 const workflowId = this.getNodeParameter('workflowId', i); const nodeId = this.getNodeParameter('nodeId', i); if (!workflowId || !nodeId) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Workflow and Node must be selected'); } // 获取工作流详情 const workflow = await this.helpers.requestWithAuthentication.call(this, 'n8nApi', { method: 'GET', url: `/rest/workflows/${workflowId}`, json: true, }); // 找到指定的节点 const selectedNode = (_a = workflow.nodes) === null || _a === void 0 ? void 0 : _a.find((node) => node.id === nodeId); if (!selectedNode) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Node with ID ${nodeId} not found in workflow`); } nodeJson = selectedNode; } else { // 使用手动输入的 JSON nodeJson = this.getNodeParameter('nodeJson', i, ''); if (typeof nodeJson === 'string') { try { nodeJson = JSON.parse(nodeJson); } catch (error) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Invalid JSON format for node configuration'); } } } if (!nodeJson) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Node configuration is required'); } // 如果启用了覆盖凭据,则替换节点的凭据 if (overrideCredentials && credentialsId) { if (!nodeJson.credentials) { nodeJson.credentials = {}; } // 获取凭据详情以确定类型 const credentialDetails = await this.helpers.requestWithAuthentication.call(this, 'n8nApi', { method: 'GET', url: `/rest/credentials/${credentialsId}`, json: true, }); // 替换或添加凭据 nodeJson.credentials[credentialDetails.type] = { id: credentialsId, name: credentialDetails.name, }; } // 执行节点(这里需要实现实际的节点执行逻辑) // 注意:实际的节点执行需要更复杂的实现,这里只是返回配置信息 returnData.push({ json: { executedNode: { name: nodeJson.name, type: nodeJson.type, credentials: nodeJson.credentials, parameters: nodeJson.parameters, }, credentialsId, overrideCredentials, message: 'Node configuration prepared for execution', }, pairedItem: { item: i }, }); } catch (error) { if (this.continueOnFail()) { returnData.push({ json: { error: error instanceof Error ? error.message : 'Unknown error', item: i, }, pairedItem: { item: i }, }); continue; } throw error; } } return [returnData]; } } exports.RunNodeWithCredentialsXImproved = RunNodeWithCredentialsXImproved;