n8n-nodes-xcredentialsx
Version:
Enhanced n8n nodes for credentials management and improved node execution with dropdown selection
292 lines (291 loc) • 13.6 kB
JavaScript
;
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;