extract out load-options context

This commit is contained in:
कारतोफ्फेलस्क्रिप्ट™ 2024-10-27 16:27:41 +01:00
parent 47764ca805
commit 7230788438
No known key found for this signature in database
4 changed files with 123 additions and 86 deletions

View file

@ -1,4 +1,4 @@
import { NodeExecuteFunctions } from 'n8n-core';
import { LoadOptionsContext, NodeExecuteFunctions } from 'n8n-core';
import type {
ILoadOptions,
ILoadOptionsFunctions,
@ -253,6 +253,6 @@ export class DynamicNodeParametersService {
workflow: Workflow,
) {
const node = workflow.nodes['Temp-Node'];
return NodeExecuteFunctions.getLoadOptionsFunctions(workflow, node, path, additionalData);
return new LoadOptionsContext(workflow, node, additionalData, path);
}
}

View file

@ -23,12 +23,11 @@ import type {
} from 'axios';
import axios from 'axios';
import crypto, { createHmac } from 'crypto';
import type { Request, Response } from 'express';
import FileType from 'file-type';
import FormData from 'form-data';
import { createReadStream } from 'fs';
import { access as fsAccess, writeFile as fsWriteFile } from 'fs/promises';
import { IncomingMessage, type IncomingHttpHeaders } from 'http';
import { IncomingMessage } from 'http';
import { Agent, type AgentOptions } from 'https';
import get from 'lodash/get';
import isEmpty from 'lodash/isEmpty';
@ -60,7 +59,6 @@ import type {
IGetNodeParameterOptions,
IHookFunctions,
IHttpRequestOptions,
ILoadOptionsFunctions,
IN8nHttpFullResponse,
IN8nHttpResponse,
INode,
@ -100,7 +98,6 @@ import type {
INodeParameters,
EnsureTypeOptions,
SSHTunnelFunctions,
SchedulingFunctions,
DeduplicationHelperFunctions,
IDeduplicationOutput,
IDeduplicationOutputItems,
@ -163,7 +160,6 @@ import {
import { extractValue } from './ExtractValue';
import { InstanceSettings } from './InstanceSettings';
import type { ExtendedValidationResult, IResponseError } from './Interfaces';
import { ScheduledTaskManager } from './ScheduledTaskManager';
import { getSecretsProxy } from './Secrets';
import { SSHClientsManager } from './SSHClientsManager';
import { HookContext, PollContext } from './node-execution-context';
@ -3591,85 +3587,6 @@ export function getCredentialTestFunctions(): ICredentialTestFunctions {
};
}
/**
* Returns the execute functions regular nodes have access to in load-options-function.
*/
export function getLoadOptionsFunctions(
workflow: Workflow,
node: INode,
path: string,
additionalData: IWorkflowExecuteAdditionalData,
): ILoadOptionsFunctions {
return ((workflow: Workflow, node: INode, path: string) => {
return {
...getCommonWorkflowFunctions(workflow, node, additionalData),
getCredentials: async (type) =>
await getCredentials(workflow, node, type, additionalData, 'internal'),
getCurrentNodeParameter: (
parameterPath: string,
options?: IGetNodeParameterOptions,
): NodeParameterValueType | object | undefined => {
const nodeParameters = additionalData.currentNodeParameters;
if (parameterPath.charAt(0) === '&') {
parameterPath = `${path.split('.').slice(1, -1).join('.')}.${parameterPath.slice(1)}`;
}
let returnData = get(nodeParameters, parameterPath);
// This is outside the try/catch because it throws errors with proper messages
if (options?.extractValue) {
const nodeType = workflow.nodeTypes.getByNameAndVersion(node.type, node.typeVersion);
if (nodeType === undefined) {
throw new ApplicationError('Node type is not known so cannot return parameter value', {
tags: { nodeType: node.type },
});
}
returnData = extractValue(
returnData,
parameterPath,
node,
nodeType,
) as NodeParameterValueType;
}
return returnData;
},
getCurrentNodeParameters: () => additionalData.currentNodeParameters,
getNodeParameter: (
parameterName: string,
fallbackValue?: any,
options?: IGetNodeParameterOptions,
): NodeParameterValueType | object => {
const runExecutionData: IRunExecutionData | null = null;
const itemIndex = 0;
const runIndex = 0;
const mode = 'internal' as WorkflowExecuteMode;
const connectionInputData: INodeExecutionData[] = [];
return getNodeParameter(
workflow,
runExecutionData,
runIndex,
connectionInputData,
node,
parameterName,
itemIndex,
mode,
getAdditionalKeys(additionalData, mode, runExecutionData),
undefined,
fallbackValue,
options,
);
},
helpers: {
...getSSHTunnelFunctions(),
...getRequestHelperFunctions(workflow, node, additionalData),
},
};
})(workflow, node, path);
}
/** @deprecated */
export function getExecuteHookFunctions(
workflow: Workflow,

View file

@ -1,5 +1,6 @@
export { ExecuteSingleContext } from './execute-single-context';
export { HookContext } from './hook-context';
export { LoadOptionsContext } from './load-options-context';
export { PollContext } from './poll-context';
export { TriggerContext } from './trigger-context';
export { WebhookContext } from './webhook-context';

View file

@ -0,0 +1,119 @@
import type {
ICredentialDataDecryptedObject,
IGetNodeParameterOptions,
INode,
INodeExecutionData,
ILoadOptionsFunctions,
IRunExecutionData,
IWorkflowExecuteAdditionalData,
NodeParameterValueType,
Workflow,
} from 'n8n-workflow';
import { ApplicationError } from 'n8n-workflow';
import { getAdditionalKeys, getCredentials, getNodeParameter } from '@/NodeExecuteFunctions';
import { BaseContext } from './base-contexts';
import { RequestHelpers } from './helpers/request-helpers';
import { get } from 'lodash';
import { extractValue } from '@/ExtractValue';
import { SSHTunnelHelpers } from './helpers/ssh-tunnel-helpers';
export class LoadOptionsContext extends BaseContext implements ILoadOptionsFunctions {
readonly helpers: ILoadOptionsFunctions['helpers'];
constructor(
workflow: Workflow,
node: INode,
additionalData: IWorkflowExecuteAdditionalData,
private readonly path: string,
) {
super(workflow, node, additionalData);
const requestHelpers = new RequestHelpers(this, workflow, node, additionalData);
const sshTunnelHelpers = new SSHTunnelHelpers();
this.helpers = {
httpRequest: requestHelpers.httpRequest.bind(requestHelpers),
httpRequestWithAuthentication:
requestHelpers.httpRequestWithAuthentication.bind(requestHelpers),
requestWithAuthenticationPaginated:
requestHelpers.requestWithAuthenticationPaginated.bind(requestHelpers),
request: requestHelpers.request.bind(requestHelpers),
requestWithAuthentication: requestHelpers.requestWithAuthentication.bind(requestHelpers),
requestOAuth1: requestHelpers.requestOAuth1.bind(requestHelpers),
requestOAuth2: requestHelpers.requestOAuth2.bind(requestHelpers),
getSSHClient: sshTunnelHelpers.getSSHClient.bind(sshTunnelHelpers),
};
}
// TODO: This is mostly identical to PollContext
async getCredentials<T extends object = ICredentialDataDecryptedObject>(type: string) {
// TODO: move `this.mode` to the base class, instead of repeating `internal` everywhere in this class
return await getCredentials<T>(this.workflow, this.node, type, this.additionalData, 'internal');
}
getCurrentNodeParameter(
parameterPath: string,
options?: IGetNodeParameterOptions,
): NodeParameterValueType | object | undefined {
const nodeParameters = this.additionalData.currentNodeParameters;
if (parameterPath.charAt(0) === '&') {
parameterPath = `${this.path.split('.').slice(1, -1).join('.')}.${parameterPath.slice(1)}`;
}
let returnData = get(nodeParameters, parameterPath);
// This is outside the try/catch because it throws errors with proper messages
if (options?.extractValue) {
const nodeType = this.workflow.nodeTypes.getByNameAndVersion(
this.node.type,
this.node.typeVersion,
);
if (nodeType === undefined) {
throw new ApplicationError('Node type is not known so cannot return parameter value', {
tags: { nodeType: this.node.type },
});
}
returnData = extractValue(
returnData,
parameterPath,
this.node,
nodeType,
) as NodeParameterValueType;
}
return returnData;
}
getCurrentNodeParameters() {
return this.additionalData.currentNodeParameters;
}
// TODO: This is identical to PollContext
getNodeParameter(
parameterName: string,
fallbackValue?: any,
options?: IGetNodeParameterOptions,
): NodeParameterValueType | object {
const runExecutionData: IRunExecutionData | null = null;
const itemIndex = 0;
const runIndex = 0;
const connectionInputData: INodeExecutionData[] = [];
return getNodeParameter(
this.workflow,
runExecutionData,
runIndex,
connectionInputData,
this.node,
parameterName,
itemIndex,
'internal',
getAdditionalKeys(this.additionalData, 'internal', runExecutionData),
undefined,
fallbackValue,
options,
);
}
}