import { GenericValue , IAllExecuteFunctions , IBinaryData , IContextObject , ICredentialDataDecryptedObject , ICredentialsExpressionResolveValues , IDataObject , IExecuteFunctions , IExecuteResponsePromiseData , IExecuteSingleFunctions , IExecuteWorkflowInfo , IHttpRequestOptions , IN8nHttpFullResponse , IN8nHttpResponse , INode , INodeExecutionData , INodeParameters , INodeType , IOAuth2Options , IPollFunctions , IRunExecutionData , ITaskDataConnections , ITriggerFunctions , IWebhookData , IWebhookDescription , IWebhookFunctions , IWorkflowDataProxyAdditionalKeys , IWorkflowDataProxyData , IWorkflowExecuteAdditionalData , IWorkflowMetadata , NodeHelpers , NodeOperationError , NodeParameterValue , Workflow , WorkflowActivateMode , WorkflowDataProxy , WorkflowExecuteMode , LoggerProxy as Logger , } from 'n8n-workflow' ; import { Agent } from 'https' ; import { stringify } from 'qs' ; import * as clientOAuth1 from 'oauth-1.0a' ; import { Token } from 'oauth-1.0a' ; import * as clientOAuth2 from 'client-oauth2' ; import * as crypto from 'crypto' ; import * as url from 'url' ; import { get } from 'lodash' ; import * as express from 'express' ; import * as FormData from 'form-data' ; import * as path from 'path' ; import { OptionsWithUri , OptionsWithUrl } from 'request' ; import * as requestPromise from 'request-promise-native' ; import { createHmac } from 'crypto' ; import { fromBuffer } from 'file-type' ; import { lookup } from 'mime-types' ; import axios , { AxiosPromise , AxiosProxyConfig , AxiosRequestConfig , AxiosResponse , Method , } from 'axios' ; import { URL , URLSearchParams } from 'url' ; import { BinaryDataManager } from './BinaryDataManager' ; import { ICredentialTestFunctions , IHookFunctions , ILoadOptionsFunctions , IResponseError , IWorkflowSettings , PLACEHOLDER_EMPTY_EXECUTION_ID , } from '.' ; axios . defaults . timeout = 300000 ; axios . defaults . headers . post = { } ; axios . defaults . headers . put = { } ; axios . defaults . headers . patch = { } ; axios . defaults . paramsSerializer = ( params ) => { if ( params instanceof URLSearchParams ) { return params . toString ( ) ; } return stringify ( params , { arrayFormat : 'indices' } ) ; } ; const requestPromiseWithDefaults = requestPromise . defaults ( { timeout : 300000 , } ) ; const pushFormDataValue = ( form , key , value ) => { if ( value ?. hasOwnProperty ( 'value' ) && value . hasOwnProperty ( 'options' ) ) { form . append ( key , value . value , value . options ) ; } else { form . append ( key , value ) ; } } ; const createFormDataObject = ( data ) => { const formData = new FormData ( ) ; const keys = Object . keys ( data ) ; keys . forEach ( ( key ) => { const formField = data [ key ] ; if ( formField instanceof Array ) { formField . forEach ( ( item ) => { pushFormDataValue ( formData , key , item ) ; } ) ; } else { pushFormDataValue ( formData , key , formField ) ; } } ) ; return formData ; } ; function searchForHeader ( headers , headerName ) { if ( headers === undefined ) { return undefined ; } const headerNames = Object . keys ( headers ) ; headerName = headerName . toLowerCase ( ) ; return headerNames . find ( ( thisHeader ) => thisHeader . toLowerCase ( ) === headerName ) ; } async function generateContentLengthHeader ( formData , headers ) { if ( ! formData || ! formData . getLength ) { return ; } try { const length = await new Promise ( ( res , rej ) => { formData . getLength ( ( error , length ) => { if ( error ) { rej ( error ) ; return ; } res ( length ) ; } ) ; } ) ; headers = Object . assign ( headers , { 'content-length' : length , } ) ; } catch ( error ) { Logger . error ( 'Unable to calculate form data length' , { error } ) ; } } async function parseRequestObject ( requestObject ) { const axiosConfig = { } ; if ( requestObject . headers !== undefined ) { axiosConfig . headers = requestObject . headers as string ; } const contentTypeHeaderKeyName = axiosConfig . headers && Object . keys ( axiosConfig . headers ) . find ( ( headerName ) => headerName . toLowerCase ( ) === 'content-type' ) ; const contentType = contentTypeHeaderKeyName && ( axiosConfig . headers [ contentTypeHeaderKeyName ] as string | undefined ) ; if ( contentType === 'application/x-www-form-urlencoded' && requestObject . formData === undefined ) { if ( typeof requestObject . body === 'string' ) { axiosConfig . data = requestObject . body ; } else { const allData = Object . assign ( requestObject . body || { } , requestObject . form || { } ) as Record < string , string > ; if ( requestObject . useQuerystring === true ) { axiosConfig . data = stringify ( allData , { arrayFormat : 'repeat' } ) ; } else { axiosConfig . data = stringify ( allData ) ; } } } else if ( contentType && contentType . includes ( 'multipart/form-data' ) !== false ) { if ( requestObject . formData !== undefined && requestObject . formData instanceof FormData ) { axiosConfig . data = requestObject . formData ; } else { const allData = { ... ( requestObject . body as object | undefined ) , ... ( requestObject . formData as object | undefined ) , } ; axiosConfig . data = createFormDataObject ( allData ) ; } delete axiosConfig . headers [ contentTypeHeaderKeyName ] ; const headers = axiosConfig . data . getHeaders ( ) ; axiosConfig . headers = Object . assign ( axiosConfig . headers || { } , headers ) ; await generateContentLengthHeader ( axiosConfig . data , axiosConfig . headers ) ; } else { if ( requestObject . form !== undefined && requestObject . body === undefined ) { axiosConfig . data = typeof requestObject . form === 'string' ? stringify ( requestObject . form , { format : 'RFC3986' } ) : stringify ( requestObject . form ) . toString ( ) ; if ( axiosConfig . headers !== undefined ) { const headerName = searchForHeader ( axiosConfig . headers , 'content-type' ) ; if ( headerName ) { delete axiosConfig . headers [ headerName ] ; } axiosConfig . headers [ 'Content-Type' ] = 'application/x-www-form-urlencoded' ; } else { axiosConfig . headers = { 'Content-Type' : 'application/x-www-form-urlencoded' , } ; } } else if ( requestObject . formData !== undefined ) { if ( axiosConfig . headers !== undefined ) { const headers = Object . keys ( axiosConfig . headers ) ; headers . forEach ( ( header ) => header . toLowerCase ( ) === 'content-type' ? delete axiosConfig . headers [ header ] : null ) ; } if ( requestObject . formData instanceof FormData ) { axiosConfig . data = requestObject . formData ; } else { axiosConfig . data = createFormDataObject ( requestObject . formData as object ) ; } const headers = axiosConfig . data . getHeaders ( ) ; axiosConfig . headers = Object . assign ( axiosConfig . headers || { } , headers ) ; await generateContentLengthHeader ( axiosConfig . data , axiosConfig . headers ) ; } else if ( requestObject . body !== undefined ) { if ( requestObject . form !== undefined ) { requestObject . body = Object . assign ( requestObject . body , requestObject . form ) ; } axiosConfig . data = requestObject . body as FormData | GenericValue | GenericValue [ ] ; } } if ( requestObject . uri !== undefined ) { axiosConfig . url = requestObject . uri ?. toString ( ) as string ; } if ( requestObject . url !== undefined ) { axiosConfig . url = requestObject . url ?. toString ( ) as string ; } if ( requestObject . method !== undefined ) { axiosConfig . method = requestObject . method as Method ; } if ( requestObject . qs !== undefined && Object . keys ( requestObject . qs as object ) . length > 0 ) { axiosConfig . params = requestObject . qs as IDataObject ; } if ( requestObject . useQuerystring === true || requestObject . qsStringifyOptions ?. arrayFormat === 'repeat' ) { axiosConfig . paramsSerializer = ( params ) => { return stringify ( params , { arrayFormat : 'repeat' } ) ; } ; } else if ( requestObject . useQuerystring === false ) { axiosConfig . paramsSerializer = ( params ) => { return stringify ( params , { arrayFormat : 'indices' } ) ; } ; } if ( requestObject . qsStringifyOptions ?. arrayFormat === 'brackets' ) { axiosConfig . paramsSerializer = ( params ) => { return stringify ( params , { arrayFormat : 'brackets' } ) ; } ; } if ( requestObject . auth !== undefined ) { if ( ( requestObject . auth as IDataObject ) . bearer !== undefined ) { axiosConfig . headers = Object . assign ( axiosConfig . headers || { } , { Authorization : `Bearer ${ ( requestObject . auth as IDataObject ) . bearer }` , } ) ; } else { const authObj = requestObject . auth as IDataObject ; axiosConfig . auth = { username : ( authObj . user || authObj . username ) as string , password : ( authObj . password || authObj . pass ) as string , } ; } } if ( requestObject . json === true ) { const acceptHeaderExists = axiosConfig . headers === undefined ? false : Object . keys ( axiosConfig . headers ) . map ( ( headerKey ) => headerKey . toLowerCase ( ) ) . includes ( 'accept' ) ; if ( ! acceptHeaderExists ) { axiosConfig . headers = Object . assign ( axiosConfig . headers || { } , { Accept : 'application/json' , } ) ; } } if ( requestObject . json === false || requestObject . json === undefined ) { axiosConfig . transformResponse = ( res ) => res ; } if ( requestObject . followRedirect === false && ( ( requestObject . method as string | undefined ) || 'get' ) . toLowerCase ( ) === 'get' ) { axiosConfig . maxRedirects = 0 ; } if ( requestObject . followAllRedirects === false && ( ( requestObject . method as string | undefined ) || 'get' ) . toLowerCase ( ) !== 'get' ) { axiosConfig . maxRedirects = 0 ; } if ( requestObject . rejectUnauthorized === false ) { axiosConfig . httpsAgent = new Agent ( { rejectUnauthorized : false , } ) ; } if ( requestObject . timeout !== undefined ) { axiosConfig . timeout = requestObject . timeout as number ; } if ( requestObject . proxy !== undefined ) { if ( typeof requestObject . proxy === 'string' ) { try { const url = new URL ( requestObject . proxy ) ; axiosConfig . proxy = { host : url . hostname , port : parseInt ( url . port , 10 ) , protocol : url . protocol , } ; if ( ! url . port ) { if ( url . protocol === 'http' ) { axiosConfig . proxy . port = 80 ; } else if ( url . protocol === 'https' ) { axiosConfig . proxy . port = 443 ; } } if ( url . username || url . password ) { axiosConfig . proxy . auth = { username : url . username , password : url . password , } ; } } catch ( error ) { if ( requestObject . proxy . includes ( '@' ) ) { const [ userpass , hostport ] = requestObject . proxy . split ( '@' ) ; const [ username , password ] = userpass . split ( ':' ) ; const [ hostname , port ] = hostport . split ( ':' ) ; axiosConfig . proxy = { host : hostname , port : parseInt ( port , 10 ) , protocol : 'http' , auth : { username , password , } , } ; } else if ( requestObject . proxy . includes ( ':' ) ) { const [ hostname , port ] = requestObject . proxy . split ( ':' ) ; axiosConfig . proxy = { host : hostname , port : parseInt ( port , 10 ) , protocol : 'http' , } ; } else { axiosConfig . proxy = { host : requestObject . proxy , port : 80 , protocol : 'http' , } ; } } } else { axiosConfig . proxy = requestObject . proxy as AxiosProxyConfig ; } } if ( requestObject . encoding === null ) { axiosConfig . responseType = 'arraybuffer' ; } const allHeaders = axiosConfig . headers ? Object . keys ( axiosConfig . headers ) : [ ] ; if ( ! allHeaders . some ( ( headerKey ) => headerKey . toLowerCase ( ) === 'accept' ) ) { axiosConfig . headers = Object . assign ( axiosConfig . headers || { } , { accept : '*/*' } ) ; } if ( requestObject . json !== false && axiosConfig . data !== undefined && axiosConfig . data !== '' && ! ( axiosConfig . data instanceof Buffer ) && ! allHeaders . some ( ( headerKey ) => headerKey . toLowerCase ( ) === 'content-type' ) ) { axiosConfig . headers = Object . assign ( axiosConfig . headers || { } , { 'content-type' : 'application/json' , } ) ; } /**
     * Missing properties:
     * encoding (need testing)
     * gzip (ignored - default already works)
     * resolveWithFullResponse (implemented elsewhere)
     * simple (???)
     */ return axiosConfig ; } function digestAuthAxiosConfig ( axiosConfig , response , auth ) { const authDetails = response . headers [ 'www-authenticate' ] . split ( ',' ) . map ( ( v ) => v . split ( '=' ) ) ; if ( authDetails ) { const nonceCount = `000000001` ; const cnonce = crypto . randomBytes ( 24 ) . toString ( 'hex' ) ; const realm = authDetails . find ( ( el ) => el [ 0 ] . toLowerCase ( ) . indexOf ( 'realm' ) > - 1 ) [ 1 ] . replace ( /"/g , '' ) ; const nonce = authDetails . find ( ( el ) => el [ 0 ] . toLowerCase ( ) . indexOf ( 'nonce' ) > - 1 ) [ 1 ] . replace ( /"/g , '' ) ; const ha1 = crypto . createHash ( 'md5' ) . update ( `${ auth ?. username as string }:${ realm }:${ auth ?. password as string }` ) . digest ( 'hex' ) ; const path = new url . URL ( axiosConfig . url ! ) . pathname ; const ha2 = crypto . createHash ( 'md5' ) . update ( `${ axiosConfig . method ?? 'GET' }:${ path }` ) . digest ( 'hex' ) ; const response = crypto . createHash ( 'md5' ) . update ( `${ ha1 }:${ nonce }:${ nonceCount }:${ cnonce }:auth:${ ha2 }` ) . digest ( 'hex' ) ; const authorization = `Digest username="${ auth ?. username as string }",realm="${ realm }",` + `nonce="${ nonce }",uri="${ path }",qop="auth",algorithm="MD5",` + `response="${ response }",nc="${ nonceCount }",cnonce="${ cnonce }"` ; if ( axiosConfig . headers ) { axiosConfig . headers . authorization = authorization ; } else { axiosConfig . headers = { authorization } ; } } return axiosConfig ; } async function proxyRequestToAxios ( uriOrObject , options ? ) { if ( process . env . N8N_USE_DEPRECATED_REQUEST_LIB ) { return requestPromiseWithDefaults . call ( null , uriOrObject , options ) ; } let axiosConfig = { } ; let axiosPromise ; type ConfigObject = { auth ? : { sendImmediately : boolean ; } ; resolveWithFullResponse ? : boolean ; simple ? : boolean ; } ; let configObject ; if ( uriOrObject !== undefined && typeof uriOrObject === 'string' ) { axiosConfig . url = uriOrObject ; } if ( uriOrObject !== undefined && typeof uriOrObject === 'object' ) { configObject = uriOrObject ; } else { configObject = options || { } ; } axiosConfig = Object . assign ( axiosConfig , await parseRequestObject ( configObject ) ) ; Logger . debug ( 'Proxying request to axios' , { originalConfig : configObject , parsedConfig : axiosConfig , } ) ; if ( configObject . auth ?. sendImmediately === false ) { const { auth } = axiosConfig ; delete axiosConfig . auth ; axiosPromise = new Promise ( async ( resolve , reject ) => { try { const result = await axios ( axiosConfig ) ; resolve ( result ) ; } catch ( resp ) { if ( resp . response === undefined || resp . response . status !== 401 || ! resp . response . headers [ 'www-authenticate' ] ?. includes ( 'nonce' ) ) { reject ( resp ) ; } axiosConfig = digestAuthAxiosConfig ( axiosConfig , resp . response , auth ) ; resolve ( axios ( axiosConfig ) ) ; } } ) ; } else { axiosPromise = axios ( axiosConfig ) ; } return new Promise ( ( resolve , reject ) => { axiosPromise . then ( ( response ) => { if ( configObject . resolveWithFullResponse === true ) { let body = response . data ; if ( response . data === '' ) { if ( axiosConfig . responseType === 'arraybuffer' ) { body = Buffer . alloc ( 0 ) ; } else { body = undefined ; } } resolve ( { body , headers : response . headers , statusCode : response . status , statusMessage : response . statusText , request : response . request , } ) ; } else { let body = response . data ; if ( response . data === '' ) { if ( axiosConfig . responseType === 'arraybuffer' ) { body = Buffer . alloc ( 0 ) ; } else { body = undefined ; } } resolve ( body ) ; } } ) . catch ( ( error ) => { if ( configObject . simple === false && error . response ) { if ( configObject . resolveWithFullResponse ) { resolve ( { body : error . response . data , headers : error . response . headers , statusCode : error . response . status , statusMessage : error . response . statusText , } ) ; } else { resolve ( error . response . data ) ; } return ; } Logger . debug ( 'Request proxied to Axios failed' , { error } ) ; const { request , response , isAxiosError , toJSON , config , ... errorData } = error ; if ( response ) { error . message = `${ response . status as number } - ${ JSON . stringify ( response . data ) }` ; } error . cause = errorData ; error . error = error . response ?. data || errorData ; error . statusCode = error . response ?. status ; error . options = config || { } ; error . request = undefined ; error . config = undefined ; error . options . adapter = undefined ; error . options . httpsAgent = undefined ; error . options . paramsSerializer = undefined ; error . options . transformRequest = undefined ; error . options . transformResponse = undefined ; error . options . validateStatus = undefined ; reject ( error ) ; } ) ; } ) ; } function convertN8nRequestToAxios ( n8nRequest ) { const { headers , method , timeout , auth , proxy , url } = n8nRequest ; const axiosRequest = { headers : headers ?? { } , method , timeout , auth , proxy , url , } as AxiosRequestConfig ; axiosRequest . params = n8nRequest . qs ; if ( n8nRequest . disableFollowRedirect === true ) { axiosRequest . maxRedirects = 0 ; } if ( n8nRequest . encoding !== undefined ) { axiosRequest . responseType = n8nRequest . encoding ; } if ( n8nRequest . skipSslCertificateValidation === true ) { axiosRequest . httpsAgent = new Agent ( { rejectUnauthorized : false , } ) ; } if ( n8nRequest . arrayFormat !== undefined ) { axiosRequest . paramsSerializer = ( params ) => { return stringify ( params , { arrayFormat : n8nRequest . arrayFormat } ) ; } ; } if ( n8nRequest . body ) { axiosRequest . data = n8nRequest . body ; const existingContentTypeHeaderKey = searchForHeader ( axiosRequest . headers , 'content-type' ) ; if ( existingContentTypeHeaderKey === undefined ) { if ( axiosRequest . data instanceof FormData ) { axiosRequest . headers = axiosRequest . headers || { } ; axiosRequest . headers [ 'Content-Type' ] = 'multipart/form-data' ; } else if ( axiosRequest . data instanceof URLSearchParams ) { axiosRequest . headers = axiosRequest . headers || { } ; axiosRequest . headers [ 'Content-Type' ] = 'application/x-www-form-urlencoded' ; } } } if ( n8nRequest . json ) { const key = searchForHeader ( axiosRequest . headers , 'accept' ) ; if ( ! key ) { axiosRequest . headers . Accept = 'application/json' ; } } const userAgentHeader = searchForHeader ( axiosRequest . headers , 'user-agent' ) ; if ( ! userAgentHeader ) { axiosRequest . headers [ 'User-Agent' ] = 'n8n' ; } return axiosRequest ; } async function httpRequest ( requestParams ) { const axiosRequest = convertN8nRequestToAxios ( requestParams ) ; const result = await axios ( axiosRequest ) ; if ( requestParams . returnFullResponse ) { return { body : result . data , headers : result . headers , statusCode : result . status , statusMessage : result . statusText , } ; } return result . data ; } export param { ITaskDataConnections } inputData param { number } itemIndex param { string } propertyName param { number } inputIndex returns { Promise < Buffer > } export async function getBinaryDataBuffer ( inputData , itemIndex , propertyName , inputIndex ) { const binaryData = inputData . main ! [ inputIndex ] ! [ itemIndex ] ! . binary ! [ propertyName ] ! ; return BinaryDataManager . getInstance ( ) . retrieveBinaryData ( binaryData ) ; } export param { Buffer } binaryData param { string } filePath param { string } mimeType returns { Promise < IBinaryData > } export async function prepareBinaryData ( binaryData , executionId , filePath ? , mimeType ? ) { if ( ! mimeType ) { if ( filePath ) { const mimeTypeLookup = lookup ( filePath ) ; if ( mimeTypeLookup ) { mimeType = mimeTypeLookup ; } } if ( ! mimeType ) { const fileTypeData = await fromBuffer ( binaryData ) ; if ( fileTypeData ) { mimeType = fileTypeData . mime ; } } if ( ! mimeType ) { mimeType = 'text/plain' ; } } const returnData = { mimeType , data : '' , } ; if ( filePath ) { if ( filePath . includes ( '?' ) ) { filePath = filePath . split ( '?' ) . shift ( ) ; } const filePathParts = path . parse ( filePath as string ) ; if ( filePathParts . dir !== '' ) { returnData . directory = filePathParts . dir ; } returnData . fileName = filePathParts . base ; const fileExtension = filePathParts . ext . slice ( 1 ) ; if ( fileExtension ) { returnData . fileExtension = fileExtension ; } } return BinaryDataManager . getInstance ( ) . storeBinaryData ( returnData , binaryData , executionId ) ; } export param { IAllExecuteFunctions } this param { string } credentialsType param { ( OptionsWithUri | requestPromise . RequestPromiseOptions ) } requestOptions param { INode } node param { IWorkflowExecuteAdditionalData } additionalData returns export async function requestOAuth2 ( this , credentialsType , requestOptions , node , additionalData , oAuth2Options ? ) { const credentials = ( await this . getCredentials ( credentialsType ) ) as ICredentialDataDecryptedObject ; if ( credentials === undefined ) { throw new Error ( 'No credentials were returned!' ) ; } if ( credentials . oauthTokenData === undefined ) { throw new Error ( 'OAuth credentials not connected!' ) ; } const oAuthClient = new clientOAuth2 ( { clientId : credentials . clientId as string , clientSecret : credentials . clientSecret as string , accessTokenUri : credentials . accessTokenUrl as string , } ) ; const oauthTokenData = credentials . oauthTokenData as clientOAuth2 . Data ; const token = oAuthClient . createToken ( get ( oauthTokenData , oAuth2Options ?. property as string ) || oauthTokenData . accessToken , oauthTokenData . refreshToken , oAuth2Options ?. tokenType || oauthTokenData . tokenType , oauthTokenData ) ; const newRequestOptions = token . sign ( requestOptions as clientOAuth2 . RequestObject ) ; if ( oAuth2Options ?. keepBearer === false ) { newRequestOptions ?. headers ?. Authorization = newRequestOptions ?. headers ?. Authorization . split ( ' ' ) [ 1 ] ; } return this . helpers . request ! ( newRequestOptions ) . catch ( async ( error ) => { const statusCodeReturned = oAuth2Options ?. tokenExpiredStatusCode === undefined ? 401 : oAuth2Options ?. tokenExpiredStatusCode ; if ( error . statusCode === statusCodeReturned ) { const tokenRefreshOptions = { } ; if ( oAuth2Options ?. includeCredentialsOnRefreshOnBody ) { const body = { client_id : credentials . clientId as string , client_secret : credentials . clientSecret as string , } ; tokenRefreshOptions . body = body ; tokenRefreshOptions . headers = { Authorization : '' , } ; } Logger . debug ( `OAuth2 token for "${ credentialsType }" used by node "${ node . name }" expired. Should revalidate.` ) ; const newToken = await token . refresh ( tokenRefreshOptions ) ; Logger . debug ( `OAuth2 token for "${ credentialsType }" used by node "${ node . name }" has been renewed.` ) ; credentials . oauthTokenData = newToken . data ; if ( ! node . credentials || ! node . credentials [ credentialsType ] ) { throw new Error ( `The node "${ node . name }" does not have credentials of type "${ credentialsType }"!` ) ; } const nodeCredentials = node . credentials [ credentialsType ] ; await additionalData . credentialsHelper . updateCredentials ( nodeCredentials , credentialsType , credentials ) ; Logger . debug ( `OAuth2 token for "${ credentialsType }" used by node "${ node . name }" has been saved to database successfully.` ) ; const newRequestOptions = newToken . sign ( requestOptions as clientOAuth2 . RequestObject ) ; return this . helpers . request ! ( newRequestOptions ) ; } throw error ; } ) ; } export async function requestOAuth1 ( this , credentialsType , requestOptions ) { const credentials = ( await this . getCredentials ( credentialsType ) ) as ICredentialDataDecryptedObject ; if ( credentials === undefined ) { throw new Error ( 'No credentials were returned!' ) ; } if ( credentials . oauthTokenData === undefined ) { throw new Error ( 'OAuth credentials not connected!' ) ; } const oauth = new clientOAuth1 ( { consumer : { key : credentials . consumerKey as string , secret : credentials . consumerSecret as string , } , signature_method : credentials . signatureMethod as string , hash_function ( base , key ) { const algorithm = credentials . signatureMethod === 'HMAC-SHA1' ? 'sha1' : 'sha256' ; return createHmac ( algorithm , key ) . update ( base ) . digest ( 'base64' ) ; } , } ) ; const oauthTokenData = credentials . oauthTokenData as IDataObject ; const token = { key : oauthTokenData . oauth_token as string , secret : oauthTokenData . oauth_token_secret as string , } ; requestOptions . data = { ... requestOptions . qs , ... requestOptions . form } ; if ( requestOptions . uri && ! requestOptions . url ) { requestOptions . url = requestOptions . uri ; delete requestOptions . uri ; } requestOptions . headers = oauth . toHeader ( oauth . authorize ( requestOptions , token ) ) ; return this . helpers . request ! ( requestOptions ) . catch ( async ( error ) => { throw error ; } ) ; } export param { ( IDataObject | IDataObject [ ] ) } jsonData returns { INodeExecutionData [ ] } export function returnJsonArray ( jsonData ) { const returnData = [ ] ; if ( ! Array . isArray ( jsonData ) ) { jsonData = [ jsonData ] ; } jsonData . forEach ( ( data ) => { returnData . push ( { json : data } ) ; } ) ; return returnData ; } export param { IWorkflowExecuteAdditionalData } additionalData returns { ( IWorkflowDataProxyAdditionalKeys ) } export function getAdditionalKeys ( additionalData ) { const executionId = additionalData . executionId || PLACEHOLDER_EMPTY_EXECUTION_ID ; return { $executionId : executionId , $resumeWebhookUrl : `${ additionalData . webhookWaitingBaseUrl }/${ executionId }` , } ; } export param { Workflow } workflow param { INode } node param { string } type param { IWorkflowExecuteAdditionalData } additionalData returns { ( ICredentialDataDecryptedObject | undefined ) } export async function getCredentials ( workflow , node , type , additionalData , mode , runExecutionData ? , runIndex ? , connectionInputData ? , itemIndex ? ) { const nodeType = workflow . nodeTypes . getByNameAndVersion ( node . type , node . typeVersion ) ; if ( nodeType === undefined ) { throw new NodeOperationError ( node , `Node type "${ node . type }" is not known so can not get credentials!` ) ; } if ( nodeType . description . credentials === undefined ) { throw new NodeOperationError ( node , `Node type "${ node . type }" does not have any credentials defined!` ) ; } const nodeCredentialDescription = nodeType . description . credentials . find ( ( credentialTypeDescription ) => credentialTypeDescription . name === type ) ; if ( nodeCredentialDescription === undefined ) { throw new NodeOperationError ( node , `Node type "${ node . type }" does not have any credentials of type "${ type }" defined!` ) ; } if ( ! NodeHelpers . displayParameter ( additionalData . currentNodeParameters || node . parameters , nodeCredentialDescription , node . parameters ) ) { return undefined ; } if ( ! node . credentials || ! node . credentials [ type ] ) { if ( nodeCredentialDescription . required === true ) { if ( ! node . credentials ) { throw new NodeOperationError ( node , 'Node does not have any credentials set!' ) ; } if ( ! node . credentials [ type ] ) { throw new NodeOperationError ( node , `Node does not have any credentials set for "${ type }"!` ) ; } } else { return undefined ; } } let expressionResolveValues ; if ( connectionInputData && runExecutionData && runIndex !== undefined ) { expressionResolveValues = { connectionInputData , itemIndex : itemIndex || 0 , node , runExecutionData , runIndex , workflow , } as ICredentialsExpressionResolveValues ; } const nodeCredentials = node . credentials [ type ] ; const decryptedDataObject = await additionalData . credentialsHelper . getDecrypted ( nodeCredentials , type , mode , false , expressionResolveValues ) ; return decryptedDataObject ; } export param { INode } node returns { INode } export function getNode ( node ) { return JSON . parse ( JSON . stringify ( node ) ) ; } export param { Workflow } workflow param { ( IRunExecutionData | null ) } runExecutionData param { number } runIndex param { INodeExecutionData [ ] } connectionInputData param { INode } node param { string } parameterName param { number } itemIndex param { * } fallbackValue returns { ( NodeParameterValue | INodeParameters | NodeParameterValue [ ] | INodeParameters [ ] | object ) } export function getNodeParameter ( workflow , runExecutionData , runIndex , connectionInputData , node , parameterName , itemIndex , mode , additionalKeys , fallbackValue ? ) { const nodeType = workflow . nodeTypes . getByNameAndVersion ( node . type , node . typeVersion ) ; if ( nodeType === undefined ) { throw new Error ( `Node type "${ node . type }" is not known so can not return paramter value!` ) ; } const value = get ( node . parameters , parameterName , fallbackValue ) ; if ( value === undefined ) { throw new Error ( `Could not get parameter "${ parameterName }"!` ) ; } let returnData ; try { returnData = workflow . expression . getParameterValue ( value , runExecutionData , runIndex , itemIndex , node . name , connectionInputData , mode , additionalKeys ) ; } catch ( e ) { e . message += ` [Error in parameter: "${ parameterName }"]` ; throw e ; } return returnData ; } export param { INode } node returns { boolean } export function continueOnFail ( node ) { return get ( node , 'continueOnFail' , false ) ; } export param { string } name param { Workflow } workflow param { INode } node param { IWorkflowExecuteAdditionalData } additionalData param { boolean } isTest returns { ( string | undefined ) } export function getNodeWebhookUrl ( name , workflow , node , additionalData , mode , additionalKeys , isTest ? ) { let baseUrl = additionalData . webhookBaseUrl ; if ( isTest === true ) { baseUrl = additionalData . webhookTestBaseUrl ; } const webhookDescription = getWebhookDescription ( name , workflow , node ) ; if ( webhookDescription === undefined ) { return undefined ; } const path = workflow . expression . getSimpleParameterValue ( node , webhookDescription . path , mode , additionalKeys ) ; if ( path === undefined ) { return undefined ; } const isFullPath = workflow . expression . getSimpleParameterValue ( node , webhookDescription . isFullPath , mode , additionalKeys , false ) as boolean ; return NodeHelpers . getNodeWebhookUrl ( baseUrl , workflow . id ! , node , path . toString ( ) , isFullPath ) ; } export param { Workflow } workflow param { IWorkflowExecuteAdditionalData } additionalData returns { string } export function getTimezone ( workflow , additionalData ) { if ( workflow . settings !== undefined && workflow . settings . timezone !== undefined ) { return ( workflow . settings as IWorkflowSettings ) . timezone as string ; } return additionalData . timezone ; } export param { string } name param { Workflow } workflow param { INode } node returns { ( IWebhookDescription | undefined ) } export function getWebhookDescription ( name , workflow , node ) { const nodeType = workflow . nodeTypes . getByNameAndVersion ( node . type , node . typeVersion ) as INodeType ; if ( nodeType . description . webhooks === undefined ) { return undefined ; } for ( const webhookDescription of nodeType . description . webhooks ) { if ( webhookDescription . name === name ) { return webhookDescription ; } } return undefined ; } export param { Workflow } workflow returns { IWorkflowMetadata } export function getWorkflowMetadata ( workflow ) { return { id : workflow . id , name : workflow . name , active : workflow . active , } ; } export param { Workflow } workflow param { INode } node param { IWorkflowExecuteAdditionalData } additionalData param { WorkflowExecuteMode } mode returns { ITriggerFunctions } export function getExecutePollFunctions ( workflow , node , additionalData , mode , activation ) { return ( ( workflow , node ) => { return { __emit : ( data ) : void => { throw new Error ( 'Overwrite NodeExecuteFunctions.getExecutePullFunctions.__emit function!' ) ; } , async getCredentials ( type ) { return getCredentials ( workflow , node , type , additionalData , mode ) ; } , getMode : ( ) : WorkflowExecuteMode => { return mode ; } , getActivationMode : ( ) : WorkflowActivateMode => { return activation ; } , getNode : ( ) => { return getNode ( node ) ; } , getNodeParameter : ( parameterName , fallbackValue ? ) : NodeParameterValue | INodeParameters | NodeParameterValue [ ] | INodeParameters [ ] | object => { const runExecutionData = null ; const itemIndex = 0 ; const runIndex = 0 ; const connectionInputData = [ ] ; return getNodeParameter ( workflow , runExecutionData , runIndex , connectionInputData , node , parameterName , itemIndex , mode , getAdditionalKeys ( additionalData ) , fallbackValue ) ; } , getRestApiUrl : ( ) : string => { return additionalData . restApiUrl ; } , getTimezone : ( ) : string => { return getTimezone ( workflow , additionalData ) ; } , getWorkflow : ( ) => { return getWorkflowMetadata ( workflow ) ; } , getWorkflowStaticData ( type ) { return workflow . getStaticData ( type , node ) ; } , helpers : { httpRequest , async prepareBinaryData ( binaryData , filePath ? , mimeType ? ) { return prepareBinaryData . call ( this , binaryData , additionalData . executionId ! , filePath , mimeType ) ; } , request : proxyRequestToAxios , async requestOAuth2 ( this , credentialsType , requestOptions , oAuth2Options ? ) { return requestOAuth2 . call ( this , credentialsType , requestOptions , node , additionalData , oAuth2Options ) ; } , async requestOAuth1 ( this , credentialsType , requestOptions ) { return requestOAuth1 . call ( this , credentialsType , requestOptions ) ; } , returnJsonArray , } , } ; } ) ( workflow , node ) ; } export param { Workflow } workflow param { INode } node param { IWorkflowExecuteAdditionalData } additionalData param { WorkflowExecuteMode } mode returns { ITriggerFunctions } export function getExecuteTriggerFunctions ( workflow , node , additionalData , mode , activation ) { return ( ( workflow , node ) => { return { emit : ( data ) : void => { throw new Error ( 'Overwrite NodeExecuteFunctions.getExecuteTriggerFunctions.emit function!' ) ; } , async getCredentials ( type ) { return getCredentials ( workflow , node , type , additionalData , mode ) ; } , getNode : ( ) => { return getNode ( node ) ; } , getMode : ( ) : WorkflowExecuteMode => { return mode ; } , getActivationMode : ( ) : WorkflowActivateMode => { return activation ; } , getNodeParameter : ( parameterName , fallbackValue ? ) : NodeParameterValue | INodeParameters | NodeParameterValue [ ] | INodeParameters [ ] | object => { const runExecutionData = null ; const itemIndex = 0 ; const runIndex = 0 ; const connectionInputData = [ ] ; return getNodeParameter ( workflow , runExecutionData , runIndex , connectionInputData , node , parameterName , itemIndex , mode , getAdditionalKeys ( additionalData ) , fallbackValue ) ; } , getRestApiUrl : ( ) : string => { return additionalData . restApiUrl ; } , getTimezone : ( ) : string => { return getTimezone ( workflow , additionalData ) ; } , getWorkflow : ( ) => { return getWorkflowMetadata ( workflow ) ; } , getWorkflowStaticData ( type ) { return workflow . getStaticData ( type , node ) ; } , helpers : { httpRequest , async prepareBinaryData ( binaryData , filePath ? , mimeType ? ) { return prepareBinaryData . call ( this , binaryData , additionalData . executionId ! , filePath , mimeType ) ; } , request : proxyRequestToAxios , async requestOAuth2 ( this , credentialsType , requestOptions , oAuth2Options ? ) { return requestOAuth2 . call ( this , credentialsType , requestOptions , node , additionalData , oAuth2Options ) ; } , async requestOAuth1 ( this , credentialsType , requestOptions ) { return requestOAuth1 . call ( this , credentialsType , requestOptions ) ; } , returnJsonArray , } , } ; } ) ( workflow , node ) ; } export param { Workflow } workflow param { IRunExecutionData } runExecutionData param { number } runIndex param { INodeExecutionData [ ] } connectionInputData param { ITaskDataConnections } inputData param { INode } node param { IWorkflowExecuteAdditionalData } additionalData param { WorkflowExecuteMode } mode returns { IExecuteFunctions } export function getExecuteFunctions ( workflow , runExecutionData , runIndex , connectionInputData , inputData , node , additionalData , mode ) { return ( ( workflow , runExecutionData , connectionInputData , inputData , node ) => { return { continueOnFail : ( ) => { return continueOnFail ( node ) ; } , evaluateExpression : ( expression , itemIndex ) => { return workflow . expression . resolveSimpleParameterValue ( `=${ expression }` , { } , runExecutionData , runIndex , itemIndex , node . name , connectionInputData , mode , getAdditionalKeys ( additionalData ) ) ; } , async executeWorkflow ( workflowInfo , inputData ? ) { return additionalData . executeWorkflow ( workflowInfo , additionalData , inputData ) . then ( async ( result ) => BinaryDataManager . getInstance ( ) . duplicateBinaryData ( result , additionalData . executionId ! ) ) ; } , getContext ( type ) { return NodeHelpers . getContext ( runExecutionData , type , node ) ; } , async getCredentials ( type , itemIndex ? ) { return getCredentials ( workflow , node , type , additionalData , mode , runExecutionData , runIndex , connectionInputData , itemIndex ) ; } , getExecutionId : ( ) : string => { return additionalData . executionId ! ; } , getInputData : ( inputIndex = 0 , inputName = 'main' ) => { if ( ! inputData . hasOwnProperty ( inputName ) ) { return [ ] ; } if ( inputData [ inputName ] . length < inputIndex ) { throw new Error ( `Could not get input index "${ inputIndex }" of input "${ inputName }"!` ) ; } if ( inputData [ inputName ] [ inputIndex ] === null ) { throw new Error ( `Value "${ inputIndex }" of input "${ inputName }" did not get set!` ) ; } return inputData [ inputName ] [ inputIndex ] as INodeExecutionData [ ] ; } , getNodeParameter : ( parameterName , itemIndex , fallbackValue ? ) : NodeParameterValue | INodeParameters | NodeParameterValue [ ] | INodeParameters [ ] | object => { return getNodeParameter ( workflow , runExecutionData , runIndex , connectionInputData , node , parameterName , itemIndex , mode , getAdditionalKeys ( additionalData ) , fallbackValue ) ; } , getMode : ( ) : WorkflowExecuteMode => { return mode ; } , getNode : ( ) => { return getNode ( node ) ; } , getRestApiUrl : ( ) : string => { return additionalData . restApiUrl ; } , getTimezone : ( ) : string => { return getTimezone ( workflow , additionalData ) ; } , getWorkflow : ( ) => { return getWorkflowMetadata ( workflow ) ; } , getWorkflowDataProxy : ( itemIndex ) : IWorkflowDataProxyData => { const dataProxy = new WorkflowDataProxy ( workflow , runExecutionData , runIndex , itemIndex , node . name , connectionInputData , { } , mode , getAdditionalKeys ( additionalData ) ) ; return dataProxy . getDataProxy ( ) ; } , getWorkflowStaticData ( type ) { return workflow . getStaticData ( type , node ) ; } , prepareOutputData : NodeHelpers . prepareOutputData , async putExecutionToWait ( waitTill ) { runExecutionData . waitTill = waitTill ; } , sendMessageToUI ( ... args ) { if ( mode !== 'manual' ) { return ; } try { if ( additionalData . sendMessageToUI ) { additionalData . sendMessageToUI ( node . name , args ) ; } } catch ( error ) { Logger . warn ( `There was a problem sending messsage to UI: ${ error . message }` ) ; } } , async sendResponse ( response ) { await additionalData . hooks ?. executeHookFunctions ( 'sendResponse' , [ response ] ) ; } , helpers : { httpRequest , async prepareBinaryData ( binaryData , filePath ? , mimeType ? ) { return prepareBinaryData . call ( this , binaryData , additionalData . executionId ! , filePath , mimeType ) ; } , async getBinaryDataBuffer ( itemIndex , propertyName , inputIndex = 0 ) { return getBinaryDataBuffer . call ( this , inputData , itemIndex , propertyName , inputIndex ) ; } , request : proxyRequestToAxios , async requestOAuth2 ( this , credentialsType , requestOptions , oAuth2Options ? ) { return requestOAuth2 . call ( this , credentialsType , requestOptions , node , additionalData , oAuth2Options ) ; } , async requestOAuth1 ( this , credentialsType , requestOptions ) { return requestOAuth1 . call ( this , credentialsType , requestOptions ) ; } , returnJsonArray , } , } ; } ) ( workflow , runExecutionData , connectionInputData , inputData , node ) ; } export param { Workflow } workflow param { IRunExecutionData } runExecutionData param { number } runIndex param { INodeExecutionData [ ] } connectionInputData param { ITaskDataConnections } inputData param { INode } node param { number } itemIndex param { IWorkflowExecuteAdditionalData } additionalData param { WorkflowExecuteMode } mode returns { IExecuteSingleFunctions } export function getExecuteSingleFunctions ( workflow , runExecutionData , runIndex , connectionInputData , inputData , node , itemIndex , additionalData , mode ) { return ( ( workflow , runExecutionData , connectionInputData , inputData , node , itemIndex ) => { return { continueOnFail : ( ) => { return continueOnFail ( node ) ; } , evaluateExpression : ( expression , evaluateItemIndex ) => { evaluateItemIndex = evaluateItemIndex === undefined ? itemIndex : evaluateItemIndex ; return workflow . expression . resolveSimpleParameterValue ( `=${ expression }` , { } , runExecutionData , runIndex , evaluateItemIndex , node . name , connectionInputData , mode , getAdditionalKeys ( additionalData ) ) ; } , getContext ( type ) { return NodeHelpers . getContext ( runExecutionData , type , node ) ; } , async getCredentials ( type ) { return getCredentials ( workflow , node , type , additionalData , mode , runExecutionData , runIndex , connectionInputData , itemIndex ) ; } , getInputData : ( inputIndex = 0 , inputName = 'main' ) => { if ( ! inputData . hasOwnProperty ( inputName ) ) { return { json : { } } ; } if ( inputData [ inputName ] . length < inputIndex ) { throw new Error ( `Could not get input index "${ inputIndex }" of input "${ inputName }"!` ) ; } const allItems = inputData [ inputName ] [ inputIndex ] ; if ( allItems === null ) { throw new Error ( `Value "${ inputIndex }" of input "${ inputName }" did not get set!` ) ; } if ( allItems [ itemIndex ] === null ) { throw new Error ( `Value "${ inputIndex }" of input "${ inputName }" with itemIndex "${ itemIndex }" did not get set!` ) ; } return allItems [ itemIndex ] ; } , getMode : ( ) : WorkflowExecuteMode => { return mode ; } , getNode : ( ) => { return getNode ( node ) ; } , getRestApiUrl : ( ) : string => { return additionalData . restApiUrl ; } , getTimezone : ( ) : string => { return getTimezone ( workflow , additionalData ) ; } , getNodeParameter : ( parameterName , fallbackValue ? ) : NodeParameterValue | INodeParameters | NodeParameterValue [ ] | INodeParameters [ ] | object => { return getNodeParameter ( workflow , runExecutionData , runIndex , connectionInputData , node , parameterName , itemIndex , mode , getAdditionalKeys ( additionalData ) , fallbackValue ) ; } , getWorkflow : ( ) => { return getWorkflowMetadata ( workflow ) ; } , getWorkflowDataProxy : ( ) : IWorkflowDataProxyData => { const dataProxy = new WorkflowDataProxy ( workflow , runExecutionData , runIndex , itemIndex , node . name , connectionInputData , { } , mode , getAdditionalKeys ( additionalData ) ) ; return dataProxy . getDataProxy ( ) ; } , getWorkflowStaticData ( type ) { return workflow . getStaticData ( type , node ) ; } , helpers : { httpRequest , async prepareBinaryData ( binaryData , filePath ? , mimeType ? ) { return prepareBinaryData . call ( this , binaryData , additionalData . executionId ! , filePath , mimeType ) ; } , request : proxyRequestToAxios , async requestOAuth2 ( this , credentialsType , requestOptions , oAuth2Options ? ) { return requestOAuth2 . call ( this , credentialsType , requestOptions , node , additionalData , oAuth2Options ) ; } , async requestOAuth1 ( this , credentialsType , requestOptions ) { return requestOAuth1 . call ( this , credentialsType , requestOptions ) ; } , } , } ; } ) ( workflow , runExecutionData , connectionInputData , inputData , node , itemIndex ) ; } export function getCredentialTestFunctions ( ) { return { helpers : { request : requestPromiseWithDefaults , } , } ; } export param { Workflow } workflow param { INode } node param { IWorkflowExecuteAdditionalData } additionalData returns { ILoadOptionsFunctions } export function getLoadOptionsFunctions ( workflow , node , path , additionalData ) { return ( ( workflow , node , path ) => { const that = { async getCredentials ( type ) { return getCredentials ( workflow , node , type , additionalData , 'internal' ) ; } , getCurrentNodeParameter : ( parameterPath ) : NodeParameterValue | INodeParameters | NodeParameterValue [ ] | INodeParameters [ ] | object | undefined => { const nodeParameters = additionalData . currentNodeParameters ; if ( parameterPath . charAt ( 0 ) === '&' ) { parameterPath = `${ path . split ( '.' ) . slice ( 1 , - 1 ) . join ( '.' ) }.${ parameterPath . slice ( 1 ) }` ; } return get ( nodeParameters , parameterPath ) ; } , getCurrentNodeParameters : ( ) : INodeParameters | undefined => { return additionalData . currentNodeParameters ; } , getNode : ( ) => { return getNode ( node ) ; } , getNodeParameter : ( parameterName , fallbackValue ? ) : NodeParameterValue | INodeParameters | NodeParameterValue [ ] | INodeParameters [ ] | object => { const runExecutionData = null ; const itemIndex = 0 ; const runIndex = 0 ; const connectionInputData = [ ] ; return getNodeParameter ( workflow , runExecutionData , runIndex , connectionInputData , node , parameterName , itemIndex , 'internal' as WorkflowExecuteMode , getAdditionalKeys ( additionalData ) , fallbackValue ) ; } , getTimezone : ( ) : string => { return getTimezone ( workflow , additionalData ) ; } , getRestApiUrl : ( ) : string => { return additionalData . restApiUrl ; } , helpers : { httpRequest , request : proxyRequestToAxios , async requestOAuth2 ( this , credentialsType , requestOptions , oAuth2Options ? ) { return requestOAuth2 . call ( this , credentialsType , requestOptions , node , additionalData , oAuth2Options ) ; } , async requestOAuth1 ( this , credentialsType , requestOptions ) { return requestOAuth1 . call ( this , credentialsType , requestOptions ) ; } , } , } ; return that ; } ) ( workflow , node , path ) ; } export param { Workflow } workflow param { INode } node param { IWorkflowExecuteAdditionalData } additionalData param { WorkflowExecuteMode } mode returns { IHookFunctions } export function getExecuteHookFunctions ( workflow , node , additionalData , mode , activation , isTest ? , webhookData ? ) { return ( ( workflow , node ) => { const that = { async getCredentials ( type ) { return getCredentials ( workflow , node , type , additionalData , mode ) ; } , getMode : ( ) : WorkflowExecuteMode => { return mode ; } , getActivationMode : ( ) : WorkflowActivateMode => { return activation ; } , getNode : ( ) => { return getNode ( node ) ; } , getNodeParameter : ( parameterName , fallbackValue ? ) : NodeParameterValue | INodeParameters | NodeParameterValue [ ] | INodeParameters [ ] | object => { const runExecutionData = null ; const itemIndex = 0 ; const runIndex = 0 ; const connectionInputData = [ ] ; return getNodeParameter ( workflow , runExecutionData , runIndex , connectionInputData , node , parameterName , itemIndex , mode , getAdditionalKeys ( additionalData ) , fallbackValue ) ; } , getNodeWebhookUrl : ( name ) : string | undefined => { return getNodeWebhookUrl ( name , workflow , node , additionalData , mode , getAdditionalKeys ( additionalData ) , isTest ) ; } , getTimezone : ( ) : string => { return getTimezone ( workflow , additionalData ) ; } , getWebhookName ( ) { if ( webhookData === undefined ) { throw new Error ( 'Is only supported in webhook functions!' ) ; } return webhookData . webhookDescription . name ; } , getWebhookDescription ( name ) { return getWebhookDescription ( name , workflow , node ) ; } , getWorkflow : ( ) => { return getWorkflowMetadata ( workflow ) ; } , getWorkflowStaticData ( type ) { return workflow . getStaticData ( type , node ) ; } , helpers : { httpRequest , request : proxyRequestToAxios , async requestOAuth2 ( this , credentialsType , requestOptions , oAuth2Options ? ) { return requestOAuth2 . call ( this , credentialsType , requestOptions , node , additionalData , oAuth2Options ) ; } , async requestOAuth1 ( this , credentialsType , requestOptions ) { return requestOAuth1 . call ( this , credentialsType , requestOptions ) ; } , } , } ; return that ; } ) ( workflow , node ) ; } export param { Workflow } workflow param { IRunExecutionData } runExecutionData param { INode } node param { IWorkflowExecuteAdditionalData } additionalData param { WorkflowExecuteMode } mode returns { IWebhookFunctions } export function getExecuteWebhookFunctions ( workflow , node , additionalData , mode , webhookData ) { return ( ( workflow , node ) => { return { getBodyData ( ) { if ( additionalData . httpRequest === undefined ) { throw new Error ( 'Request is missing!' ) ; } return additionalData . httpRequest . body ; } , async getCredentials ( type ) { return getCredentials ( workflow , node , type , additionalData , mode ) ; } , getHeaderData ( ) { if ( additionalData . httpRequest === undefined ) { throw new Error ( 'Request is missing!' ) ; } return additionalData . httpRequest . headers ; } , getMode : ( ) : WorkflowExecuteMode => { return mode ; } , getNode : ( ) => { return getNode ( node ) ; } , getNodeParameter : ( parameterName , fallbackValue ? ) : NodeParameterValue | INodeParameters | NodeParameterValue [ ] | INodeParameters [ ] | object => { const runExecutionData = null ; const itemIndex = 0 ; const runIndex = 0 ; const connectionInputData = [ ] ; return getNodeParameter ( workflow , runExecutionData , runIndex , connectionInputData , node , parameterName , itemIndex , mode , getAdditionalKeys ( additionalData ) , fallbackValue ) ; } , getParamsData ( ) { if ( additionalData . httpRequest === undefined ) { throw new Error ( 'Request is missing!' ) ; } return additionalData . httpRequest . params ; } , getQueryData ( ) { if ( additionalData . httpRequest === undefined ) { throw new Error ( 'Request is missing!' ) ; } return additionalData . httpRequest . query ; } , getRequestObject ( ) { if ( additionalData . httpRequest === undefined ) { throw new Error ( 'Request is missing!' ) ; } return additionalData . httpRequest ; } , getResponseObject ( ) { if ( additionalData . httpResponse === undefined ) { throw new Error ( 'Response is missing!' ) ; } return additionalData . httpResponse ; } , getNodeWebhookUrl : ( name ) : string | undefined => { return getNodeWebhookUrl ( name , workflow , node , additionalData , mode , getAdditionalKeys ( additionalData ) ) ; } , getTimezone : ( ) : string => { return getTimezone ( workflow , additionalData ) ; } , getWorkflow : ( ) => { return getWorkflowMetadata ( workflow ) ; } , getWorkflowStaticData ( type ) { return workflow . getStaticData ( type , node ) ; } , getWebhookName ( ) { return webhookData . webhookDescription . name ; } , prepareOutputData : NodeHelpers . prepareOutputData , helpers : { httpRequest , async prepareBinaryData ( binaryData , filePath ? , mimeType ? ) { return prepareBinaryData . call ( this , binaryData , additionalData . executionId ! , filePath , mimeType ) ; } , request : proxyRequestToAxios , async requestOAuth2 ( this , credentialsType , requestOptions , oAuth2Options ? ) { return requestOAuth2 . call ( this , credentialsType , requestOptions , node , additionalData , oAuth2Options ) ; } , async requestOAuth1 ( this , credentialsType , requestOptions ) { return requestOAuth1 . call ( this , credentialsType , requestOptions ) ; } , returnJsonArray , } , } ; } ) ( workflow , node ) ; }