make declarative nodes work more like regular nodes

This commit is contained in:
कारतोफ्फेलस्क्रिप्ट™ 2025-01-30 16:37:52 +01:00
parent 1a915239c6
commit 57f6c33928
No known key found for this signature in database
13 changed files with 188 additions and 201 deletions

View file

@ -2,6 +2,8 @@ import { Service } from '@n8n/di';
import type { NeededNodeType } from '@n8n/task-runner';
import type { Dirent } from 'fs';
import { readdir } from 'fs/promises';
import { RoutingNode } from 'n8n-core';
import type { ExecuteContext } from 'n8n-core';
import type { INodeType, INodeTypeDescription, INodeTypes, IVersionedNodeType } from 'n8n-workflow';
import { ApplicationError, NodeHelpers } from 'n8n-workflow';
import { join, dirname } from 'path';
@ -60,6 +62,12 @@ export class NodeTypes implements INodeTypes {
description: { value: clonedDescription },
}) as INodeType;
const tool = this.loadNodesAndCredentials.convertNodeToAiTool(clonedNode);
// eslint-disable-next-line @typescript-eslint/unbound-method
tool.execute ??= async function (this: ExecuteContext) {
const routingNode = new RoutingNode(this, tool);
const data = await routingNode.runNode();
return data ?? [];
};
loadedNodes[nodeType + 'Tool'] = { sourcePath: '', type: tool };
return tool;
}

View file

@ -6,9 +6,10 @@
import { Service } from '@n8n/di';
import get from 'lodash/get';
import {
CredentialTestContext,
ErrorReporter,
ExecuteContext,
Logger,
NodeExecuteFunctions,
RoutingNode,
isObjectLiteral,
} from 'n8n-core';
@ -29,6 +30,7 @@ import type {
INodeTypes,
ICredentialTestFunctions,
IDataObject,
IExecuteData,
} from 'n8n-workflow';
import { VersionedNodeType, NodeHelpers, Workflow, ApplicationError } from 'n8n-workflow';
@ -205,9 +207,8 @@ export class CredentialsTester {
if (typeof credentialTestFunction === 'function') {
// The credentials get tested via a function that is defined on the node
const credentialTestFunctions = NodeExecuteFunctions.getCredentialTestFunctions();
return credentialTestFunction.call(credentialTestFunctions, credentialsDecrypted);
const context = new CredentialTestContext();
return credentialTestFunction.call(context, credentialsDecrypted);
}
// Credentials get tested via request instructions
@ -293,25 +294,25 @@ export class CredentialsTester {
const additionalData = await WorkflowExecuteAdditionalData.getBase(user.id, node.parameters);
const routingNode = new RoutingNode(
// TODO: define `credentialTestFunction` for declarative nodes, to make this method smaller
const executeData: IExecuteData = { node, data: {}, source: null };
const executeFunctions = new ExecuteContext(
workflow,
node,
connectionInputData,
runExecutionData ?? null,
additionalData,
mode,
runExecutionData,
runIndex,
connectionInputData,
inputData,
executeData,
[],
);
const routingNode = new RoutingNode(executeFunctions, nodeTypeCopy, credentialsDecrypted);
let response: INodeExecutionData[][] | null | undefined;
try {
response = await routingNode.runNode(
inputData,
runIndex,
nodeTypeCopy,
{ node, data: {}, source: null },
credentialsDecrypted,
);
response = await routingNode.runNode();
} catch (error) {
this.errorReporter.error(error);
// Do not fail any requests to allow custom error messages and

View file

@ -1,5 +1,5 @@
import { Service } from '@n8n/di';
import { LoadOptionsContext, RoutingNode, LocalLoadOptionsContext } from 'n8n-core';
import { LoadOptionsContext, RoutingNode, LocalLoadOptionsContext, ExecuteContext } from 'n8n-core';
import type {
ILoadOptions,
ILoadOptionsFunctions,
@ -19,6 +19,7 @@ import type {
NodeParameterValueType,
IDataObject,
ILocalLoadOptionsFunctions,
IExecuteData,
} from 'n8n-workflow';
import { Workflow, ApplicationError } from 'n8n-workflow';
@ -103,17 +104,8 @@ export class DynamicNodeParametersService {
const workflow = this.getWorkflow(nodeTypeAndVersion, currentNodeParameters, credentials);
const node = workflow.nodes['Temp-Node'];
const routingNode = new RoutingNode(
workflow,
node,
connectionInputData,
runExecutionData ?? null,
additionalData,
mode,
);
// Create copy of node-type with the single property we want to get the data off
const tempNode: INodeType = {
const tempNodeType: INodeType = {
...nodeType,
...{
description: {
@ -135,11 +127,25 @@ export class DynamicNodeParametersService {
main: [[{ json: {} }]],
};
const optionsData = await routingNode.runNode(inputData, runIndex, tempNode, {
const executeData: IExecuteData = {
node,
source: null,
data: {},
});
};
const executeFunctions = new ExecuteContext(
workflow,
node,
additionalData,
mode,
runExecutionData,
runIndex,
connectionInputData,
inputData,
executeData,
[],
);
const routingNode = new RoutingNode(executeFunctions, tempNodeType);
const optionsData = await routingNode.runNode();
if (optionsData?.length === 0) {
return [];

View file

@ -744,14 +744,17 @@ describe('RoutingNode', () => {
nodeTypes,
});
const routingNode = new RoutingNode(
const executeFunctions = mock<executionContexts.ExecuteContext>();
Object.assign(executeFunctions, {
runIndex,
additionalData,
workflow,
node,
connectionInputData,
runExecutionData ?? null,
additionalData,
mode,
);
connectionInputData,
runExecutionData,
});
const routingNode = new RoutingNode(executeFunctions, nodeType);
const executeSingleFunctions = getExecuteSingleFunctions(
workflow,
@ -1947,15 +1950,6 @@ describe('RoutingNode', () => {
nodeTypes,
});
const routingNode = new RoutingNode(
workflow,
node,
connectionInputData,
runExecutionData ?? null,
additionalData,
mode,
);
const executeData = {
data: {},
node,
@ -1963,6 +1957,18 @@ describe('RoutingNode', () => {
} as IExecuteData;
const executeFunctions = mock<executionContexts.ExecuteContext>();
Object.assign(executeFunctions, {
executeData,
inputData,
runIndex,
additionalData,
workflow,
node,
mode,
connectionInputData,
runExecutionData,
});
const executeSingleFunctions = getExecuteSingleFunctions(
workflow,
runExecutionData,
@ -1971,7 +1977,6 @@ describe('RoutingNode', () => {
itemIndex,
);
jest.spyOn(executionContexts, 'ExecuteContext').mockReturnValue(executeFunctions);
jest
.spyOn(executionContexts, 'ExecuteSingleContext')
.mockReturnValue(executeSingleFunctions);
@ -2004,7 +2009,8 @@ describe('RoutingNode', () => {
? testData.input.node.parameters[parameterName]
: (getNodeParameter(parameterName) ?? {});
const result = await routingNode.runNode(inputData, runIndex, nodeType, executeData);
const routingNode = new RoutingNode(executeFunctions, nodeType);
const result = await routingNode.runNode();
if (testData.input.specialTestOptions?.sleepCalls) {
expect(spy.mock.calls).toEqual(testData.input.specialTestOptions?.sleepCalls);

View file

@ -40,7 +40,6 @@ export const describeCommonTests = (
executeData: IExecuteData;
},
) => {
// @ts-expect-error `additionalData` is private
const additionalData = context.additionalData as MockProxy<IWorkflowExecuteAdditionalData>;
describe('getExecutionCancelSignal', () => {

View file

@ -41,11 +41,11 @@ export class BaseExecuteContext extends NodeExecutionContext {
node: INode,
additionalData: IWorkflowExecuteAdditionalData,
mode: WorkflowExecuteMode,
protected readonly runExecutionData: IRunExecutionData,
readonly runExecutionData: IRunExecutionData,
runIndex: number,
protected readonly connectionInputData: INodeExecutionData[],
protected readonly inputData: ITaskDataConnections,
protected readonly executeData: IExecuteData,
readonly connectionInputData: INodeExecutionData[],
readonly inputData: ITaskDataConnections,
readonly executeData: IExecuteData,
protected readonly abortSignal?: AbortSignal,
) {
super(workflow, node, additionalData, mode, runExecutionData, runIndex);

View file

@ -0,0 +1,26 @@
import { Container } from '@n8n/di';
import type { ICredentialTestFunctions } from 'n8n-workflow';
import { Memoized } from '@/decorators';
import { Logger } from '@/logging';
// eslint-disable-next-line import/no-cycle
import { getSSHTunnelFunctions, proxyRequestToAxios } from '@/node-execute-functions';
export class CredentialTestContext implements ICredentialTestFunctions {
readonly helpers: ICredentialTestFunctions['helpers'];
constructor() {
this.helpers = {
...getSSHTunnelFunctions(),
request: async (uriOrObject: string | object, options?: object) => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
return await proxyRequestToAxios(undefined, undefined, undefined, uriOrObject, options);
},
};
}
@Memoized
get logger() {
return Container.get(Logger);
}
}

View file

@ -1,4 +1,6 @@
// eslint-disable-next-line import/no-cycle
export { CredentialTestContext } from './credentials-test-context';
// eslint-disable-next-line import/no-cycle
export { ExecuteContext } from './execute-context';
export { ExecuteSingleContext } from './execute-single-context';
export { HookContext } from './hook-context';

View file

@ -43,12 +43,12 @@ export abstract class NodeExecutionContext implements Omit<FunctionsBase, 'getCr
protected readonly instanceSettings = Container.get(InstanceSettings);
constructor(
protected readonly workflow: Workflow,
protected readonly node: INode,
protected readonly additionalData: IWorkflowExecuteAdditionalData,
protected readonly mode: WorkflowExecuteMode,
readonly workflow: Workflow,
readonly node: INode,
readonly additionalData: IWorkflowExecuteAdditionalData,
readonly mode: WorkflowExecuteMode,
protected readonly runExecutionData: IRunExecutionData | null = null,
protected readonly runIndex = 0,
readonly runIndex = 0,
protected readonly connectionInputData: INodeExecutionData[] = [],
protected readonly executeData?: IExecuteData,
) {}

View file

@ -6,24 +6,25 @@
import get from 'lodash/get';
import merge from 'lodash/merge';
import set from 'lodash/set';
import { NodeHelpers, NodeApiError, NodeOperationError, sleep } from 'n8n-workflow';
import {
NodeHelpers,
NodeApiError,
NodeOperationError,
sleep,
NodeConnectionType,
} from 'n8n-workflow';
import type {
ICredentialDataDecryptedObject,
ICredentialsDecrypted,
IHttpRequestOptions,
IN8nHttpFullResponse,
INode,
INodeExecutionData,
INodeParameters,
INodePropertyOptions,
INodeType,
DeclarativeRestApiSettings,
IRunExecutionData,
ITaskDataConnections,
IWorkflowDataProxyAdditionalKeys,
IWorkflowExecuteAdditionalData,
NodeParameterValue,
WorkflowExecuteMode,
IDataObject,
IExecuteData,
IExecuteSingleFunctions,
@ -33,70 +34,39 @@ import type {
NodeParameterValueType,
PostReceiveAction,
JsonObject,
CloseFunction,
INodeCredentialDescription,
IExecutePaginationFunctions,
Workflow,
} from 'n8n-workflow';
import url from 'node:url';
import { ExecuteContext, ExecuteSingleContext } from './node-execution-context';
import { type ExecuteContext, ExecuteSingleContext } from './node-execution-context';
export class RoutingNode {
additionalData: IWorkflowExecuteAdditionalData;
connectionInputData: INodeExecutionData[];
node: INode;
mode: WorkflowExecuteMode;
runExecutionData: IRunExecutionData;
workflow: Workflow;
constructor(
workflow: Workflow,
node: INode,
connectionInputData: INodeExecutionData[],
runExecutionData: IRunExecutionData,
additionalData: IWorkflowExecuteAdditionalData,
mode: WorkflowExecuteMode,
) {
this.additionalData = additionalData;
this.connectionInputData = connectionInputData;
this.runExecutionData = runExecutionData;
this.mode = mode;
this.node = node;
this.workflow = workflow;
}
private readonly context: ExecuteContext,
private readonly nodeType: INodeType,
private readonly credentialsDecrypted?: ICredentialsDecrypted,
) {}
// eslint-disable-next-line complexity
async runNode(
inputData: ITaskDataConnections,
runIndex: number,
nodeType: INodeType,
executeData: IExecuteData,
credentialsDecrypted?: ICredentialsDecrypted,
abortSignal?: AbortSignal,
): Promise<INodeExecutionData[][] | null | undefined> {
const items = inputData.main[0] as INodeExecutionData[];
const returnData: INodeExecutionData[] = [];
const closeFunctions: CloseFunction[] = [];
const executeFunctions = new ExecuteContext(
this.workflow,
this.node,
this.additionalData,
this.mode,
this.runExecutionData,
runIndex,
this.connectionInputData,
inputData,
async runNode(): Promise<INodeExecutionData[][] | undefined> {
const { context, nodeType, credentialsDecrypted } = this;
const {
additionalData,
executeData,
closeFunctions,
abortSignal,
);
inputData,
node,
workflow,
mode,
runIndex,
connectionInputData,
runExecutionData,
} = context;
const abortSignal = context.getExecutionCancelSignal();
const items = (inputData[NodeConnectionType.Main] ??
inputData[NodeConnectionType.AiTool])[0] as INodeExecutionData[];
const returnData: INodeExecutionData[] = [];
let credentialDescription: INodeCredentialDescription | undefined;
@ -104,17 +74,14 @@ export class RoutingNode {
if (nodeType.description.credentials.length === 1) {
credentialDescription = nodeType.description.credentials[0];
} else {
const authenticationMethod = executeFunctions.getNodeParameter(
'authentication',
0,
) as string;
const authenticationMethod = context.getNodeParameter('authentication', 0) as string;
credentialDescription = nodeType.description.credentials.find((x) =>
x.displayOptions?.show?.authentication?.includes(authenticationMethod),
);
if (!credentialDescription) {
throw new NodeOperationError(
this.node,
`Node type "${this.node.type}" does not have any credentials of type "${authenticationMethod}" defined`,
node,
`Node type "${node.type}" does not have any credentials of type "${authenticationMethod}" defined`,
{ level: 'warning' },
);
}
@ -127,7 +94,7 @@ export class RoutingNode {
} else if (credentialDescription) {
try {
credentials =
(await executeFunctions.getCredentials<ICredentialDataDecryptedObject>(
(await context.getCredentials<ICredentialDataDecryptedObject>(
credentialDescription.name,
0,
)) || {};
@ -142,7 +109,7 @@ export class RoutingNode {
}
}
const { batching } = executeFunctions.getNodeParameter('requestOptions', 0, {}) as {
const { batching } = context.getNodeParameter('requestOptions', 0, {}) as {
batching: { batch: { batchSize: number; batchInterval: number } };
};
@ -163,13 +130,13 @@ export class RoutingNode {
}
const thisArgs = new ExecuteSingleContext(
this.workflow,
this.node,
this.additionalData,
this.mode,
this.runExecutionData,
workflow,
node,
additionalData,
mode,
runExecutionData,
runIndex,
this.connectionInputData,
connectionInputData,
inputData,
itemIndex,
executeData,
@ -214,7 +181,7 @@ export class RoutingNode {
itemIndex,
runIndex,
executeData,
{ $credentials: credentials, $version: this.node.typeVersion },
{ $credentials: credentials, $version: node.typeVersion },
false,
) as string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@ -223,14 +190,14 @@ export class RoutingNode {
}
for (const property of nodeType.description.properties) {
let value = get(this.node.parameters, property.name, []) as string | NodeParameterValue;
let value = get(node.parameters, property.name, []) as string | NodeParameterValue;
// If the value is an expression resolve it
value = this.getParameterValue(
value,
itemIndex,
runIndex,
executeData,
{ $credentials: credentials, $version: this.node.typeVersion },
{ $credentials: credentials, $version: node.typeVersion },
false,
) as string | NodeParameterValue;
@ -240,7 +207,7 @@ export class RoutingNode {
itemIndex,
runIndex,
'',
{ $credentials: credentials, $value: value, $version: this.node.typeVersion },
{ $credentials: credentials, $value: value, $version: node.typeVersion },
);
this.mergeOptions(itemContext[itemIndex].requestData, tempOptions);
@ -255,7 +222,7 @@ export class RoutingNode {
!(property in proxyParsed) ||
proxyParsed[property as keyof typeof proxyParsed] === null
) {
throw new NodeOperationError(this.node, 'The proxy is not value', {
throw new NodeOperationError(node, 'The proxy is not value', {
runIndex,
itemIndex,
description: `The proxy URL does not contain a valid value for "${property}"`,
@ -291,7 +258,7 @@ export class RoutingNode {
}
requestPromises.push(
this.makeRoutingRequest(
this.makeRequest(
itemContext[itemIndex].requestData,
itemContext[itemIndex].thisArgs,
itemIndex,
@ -327,7 +294,7 @@ export class RoutingNode {
throw error;
}
throw new NodeApiError(this.node, error as JsonObject, {
throw new NodeApiError(node, error as JsonObject, {
runIndex,
itemIndex,
message: error?.message,
@ -347,7 +314,7 @@ export class RoutingNode {
return [returnData];
}
mergeOptions(
private mergeOptions(
destinationOptions: DeclarativeRestApiSettings.ResultOptions,
sourceOptions?: DeclarativeRestApiSettings.ResultOptions,
): void {
@ -368,7 +335,7 @@ export class RoutingNode {
}
}
async runPostReceiveAction(
private async runPostReceiveAction(
executeSingleFunctions: IExecuteSingleFunctions,
action: PostReceiveAction,
inputData: INodeExecutionData[],
@ -380,6 +347,9 @@ export class RoutingNode {
if (typeof action === 'function') {
return await action.call(executeSingleFunctions, inputData, responseData);
}
const { node } = this.context;
if (action.type === 'rootProperty') {
try {
return inputData.flatMap((item) => {
@ -395,13 +365,14 @@ export class RoutingNode {
});
});
} catch (error) {
throw new NodeOperationError(this.node, error as Error, {
throw new NodeOperationError(node, error as Error, {
runIndex,
itemIndex,
description: `The rootProperty "${action.properties.property}" could not be found on item.`,
});
}
}
if (action.type === 'filter') {
const passValue = action.properties.pass;
@ -416,7 +387,7 @@ export class RoutingNode {
$response: responseData,
$responseItem: item.json,
$value: parameterValue,
$version: this.node.typeVersion,
$version: node.typeVersion,
},
false,
) as boolean;
@ -424,17 +395,19 @@ export class RoutingNode {
return inputData;
}
if (action.type === 'limit') {
const maxResults = this.getParameterValue(
action.properties.maxResults,
itemIndex,
runIndex,
executeSingleFunctions.getExecuteData(),
{ $response: responseData, $value: parameterValue, $version: this.node.typeVersion },
{ $response: responseData, $value: parameterValue, $version: node.typeVersion },
false,
) as string;
return inputData.slice(0, parseInt(maxResults, 10));
}
if (action.type === 'set') {
const { value } = action.properties;
// If the value is an expression resolve it
@ -445,12 +418,13 @@ export class RoutingNode {
itemIndex,
runIndex,
executeSingleFunctions.getExecuteData(),
{ $response: responseData, $value: parameterValue, $version: this.node.typeVersion },
{ $response: responseData, $value: parameterValue, $version: node.typeVersion },
false,
) as IDataObject,
},
];
}
if (action.type === 'sort') {
// Sort the returned options
const sortKey = action.properties.key;
@ -468,6 +442,7 @@ export class RoutingNode {
return inputData;
}
if (action.type === 'setKeyValue') {
const returnData: INodeExecutionData[] = [];
@ -491,7 +466,7 @@ export class RoutingNode {
$response: responseData,
$responseItem: item.json,
$value: parameterValue,
$version: this.node.typeVersion,
$version: node.typeVersion,
},
false,
) as string;
@ -503,6 +478,7 @@ export class RoutingNode {
return returnData;
}
if (action.type === 'binaryData') {
const body = (responseData.body = Buffer.from(responseData.body as string));
let { destinationProperty } = action.properties;
@ -512,7 +488,7 @@ export class RoutingNode {
itemIndex,
runIndex,
executeSingleFunctions.getExecuteData(),
{ $response: responseData, $value: parameterValue, $version: this.node.typeVersion },
{ $response: responseData, $value: parameterValue, $version: node.typeVersion },
false,
) as string;
@ -535,7 +511,7 @@ export class RoutingNode {
return [];
}
async postProcessResponseData(
private async postProcessResponseData(
executeSingleFunctions: IExecuteSingleFunctions,
responseData: IN8nHttpFullResponse,
requestData: DeclarativeRestApiSettings.ResultOptions,
@ -580,7 +556,7 @@ export class RoutingNode {
return returnData;
}
async rawRoutingRequest(
private async rawRoutingRequest(
executeSingleFunctions: IExecuteSingleFunctions,
requestData: DeclarativeRestApiSettings.ResultOptions,
credentialType?: string,
@ -604,7 +580,7 @@ export class RoutingNode {
return responseData;
}
async makeRoutingRequest(
private async makeRequest(
requestData: DeclarativeRestApiSettings.ResultOptions,
executeSingleFunctions: IExecuteSingleFunctions,
itemIndex: number,
@ -639,6 +615,7 @@ export class RoutingNode {
);
};
const { node } = this.context;
const executePaginationFunctions = Object.create(executeSingleFunctions, {
makeRoutingRequest: { value: makeRoutingRequest },
}) as IExecutePaginationFunctions;
@ -669,7 +646,7 @@ export class RoutingNode {
const additionalKeys = {
$request: requestData.options,
$response: {} as IN8nHttpFullResponse,
$version: this.node.typeVersion,
$version: node.typeVersion,
};
do {
@ -763,7 +740,7 @@ export class RoutingNode {
| undefined;
if (tempResponseValue === undefined) {
throw new NodeOperationError(
this.node,
node,
`The rootProperty "${properties.rootProperty}" could not be found on item.`,
{ runIndex, itemIndex },
);
@ -801,7 +778,7 @@ export class RoutingNode {
return responseData;
}
getParameterValue(
private getParameterValue(
parameterValue: NodeParameterValueType,
itemIndex: number,
runIndex: number,
@ -813,14 +790,15 @@ export class RoutingNode {
typeof parameterValue === 'object' ||
(typeof parameterValue === 'string' && parameterValue.charAt(0) === '=')
) {
return this.workflow.expression.getParameterValue(
const { node, workflow, mode, connectionInputData, runExecutionData } = this.context;
return workflow.expression.getParameterValue(
parameterValue,
this.runExecutionData ?? null,
runExecutionData ?? null,
runIndex,
itemIndex,
this.node.name,
this.connectionInputData,
this.mode,
node.name,
connectionInputData,
mode,
additionalKeys ?? {},
executeData,
returnObjectAsString,
@ -851,14 +829,8 @@ export class RoutingNode {
};
let basePath = path ? `${path}.` : '';
if (
!NodeHelpers.displayParameter(
this.node.parameters,
nodeProperties,
this.node,
this.node.parameters,
)
) {
const { node } = this.context;
if (!NodeHelpers.displayParameter(node.parameters, nodeProperties, node, node.parameters)) {
return undefined;
}
if (nodeProperties.routing) {
@ -1032,7 +1004,7 @@ export class RoutingNode {
let value;
if (nodeProperties.type === 'options') {
const optionValue = NodeHelpers.getParameterValueByPath(
this.node.parameters,
node.parameters,
nodeProperties.name,
basePath.slice(0, -1),
);
@ -1050,14 +1022,14 @@ export class RoutingNode {
itemIndex,
runIndex,
`${basePath}${nodeProperties.name}`,
{ $value: optionValue, $version: this.node.typeVersion },
{ $value: optionValue, $version: node.typeVersion },
);
this.mergeOptions(returnData, tempOptions);
}
} else if (nodeProperties.type === 'collection') {
value = NodeHelpers.getParameterValueByPath(
this.node.parameters,
node.parameters,
nodeProperties.name,
basePath.slice(0, -1),
);
@ -1074,7 +1046,7 @@ export class RoutingNode {
itemIndex,
runIndex,
`${basePath}${nodeProperties.name}`,
{ $version: this.node.typeVersion },
{ $version: node.typeVersion },
);
this.mergeOptions(returnData, tempOptions);
@ -1085,7 +1057,7 @@ export class RoutingNode {
for (const propertyOptions of nodeProperties.options as INodePropertyCollection[]) {
// Check if the option got set and if not skip it
value = NodeHelpers.getParameterValueByPath(
this.node.parameters,
node.parameters,
propertyOptions.name,
basePath.slice(0, -1),
);

View file

@ -69,7 +69,6 @@ import {
handleCycles,
filterDisabledNodes,
} from './partial-execution-utils';
import { RoutingNode } from './routing-node';
import { TriggersAndPollers } from './triggers-and-pollers';
export class WorkflowExecute {
@ -1171,27 +1170,7 @@ export class WorkflowExecute {
// For webhook nodes always simply pass the data through
return { data: inputData.main as INodeExecutionData[][] };
} else {
// For nodes which have routing information on properties
const routingNode = new RoutingNode(
workflow,
node,
connectionInputData,
runExecutionData ?? null,
additionalData,
mode,
);
return {
data: await routingNode.runNode(
inputData,
runIndex,
nodeType,
executionData,
undefined,
abortSignal,
),
};
throw new ApplicationError('This should not have happened');
}
}

View file

@ -38,7 +38,6 @@ import type {
IAllExecuteFunctions,
IBinaryData,
ICredentialDataDecryptedObject,
ICredentialTestFunctions,
IDataObject,
IExecuteData,
IExecuteFunctions,
@ -2555,15 +2554,3 @@ export function getExecuteTriggerFunctions(
): ITriggerFunctions {
return new TriggerContext(workflow, node, additionalData, mode, activation);
}
export function getCredentialTestFunctions(): ICredentialTestFunctions {
return {
logger: Container.get(Logger),
helpers: {
...getSSHTunnelFunctions(),
request: async (uriOrObject: string | object, options?: object) => {
return await proxyRequestToAxios(undefined, undefined, undefined, uriOrObject, options);
},
},
};
}

View file

@ -18,6 +18,7 @@ export class Npm implements INodeType {
},
inputs: [NodeConnectionType.Main],
outputs: [NodeConnectionType.Main],
usableAsTool: true,
credentials: [
{
name: 'npmApi',