import { INode , IRunExecutionData , NodeHelpers , WebhookHttpMethod , Workflow , LoggerProxy as Logger , } from 'n8n-workflow' ; import * as express from 'express' ; import { Db , IExecutionResponse , IResponseCallbackData , IWorkflowDb , NodeTypes , ResponseHelper , WebhookHelpers , WorkflowCredentials , WorkflowExecuteAdditionalData , } from '.' ; export class WaitingWebhooks { async executeWebhook ( httpMethod , fullPath , req , res ) { Logger . debug ( `Received waiting-webhoook "${ httpMethod }" for path "${ fullPath }"` ) ; req . params = { } ; if ( fullPath . endsWith ( '/' ) ) { fullPath = fullPath . slice ( 0 , - 1 ) ; } const pathParts = fullPath . split ( '/' ) ; const executionId = pathParts . shift ( ) ; const path = pathParts . join ( '/' ) ; const execution = await Db . collections . Execution ?. findOne ( executionId ) ; if ( execution === undefined ) { throw new ResponseHelper . ResponseError ( `The execution "${ executionId } does not exist.` , 404 , 404 ) ; } const fullExecutionData = ResponseHelper . unflattenExecutionData ( execution ) ; if ( fullExecutionData . finished || fullExecutionData . data . resultData . error ) { throw new ResponseHelper . ResponseError ( `The execution "${ executionId } has finished already.` , 409 , 409 ) ; } return this . startExecution ( httpMethod , path , fullExecutionData , req , res ) ; } async startExecution ( httpMethod , path , fullExecutionData , req , res ) { const executionId = fullExecutionData . id ; if ( fullExecutionData . finished ) { throw new Error ( 'The execution did succeed and can so not be started again.' ) ; } const lastNodeExecuted = fullExecutionData . data . resultData . lastNodeExecuted as string ; fullExecutionData . data . executionData ! . nodeExecutionStack [ 0 ] . node . disabled = true ; fullExecutionData . data . waitTill = undefined ; fullExecutionData . data . resultData . runData [ lastNodeExecuted ] . pop ( ) ; const { workflowData } = fullExecutionData ; const nodeTypes = NodeTypes ( ) ; const workflow = new Workflow ( { id : workflowData . id ! . toString ( ) , name : workflowData . name , nodes : workflowData . nodes , connections : workflowData . connections , active : workflowData . active , nodeTypes , staticData : workflowData . staticData , settings : workflowData . settings , } ) ; const additionalData = await WorkflowExecuteAdditionalData . getBase ( ) ; const webhookData = NodeHelpers . getNodeWebhooks ( workflow , workflow . getNode ( lastNodeExecuted ) as INode , additionalData ) . filter ( ( webhook ) => { return ( webhook . httpMethod === httpMethod && webhook . path === path && webhook . webhookDescription . restartWebhook === true ) ; } ) [ 0 ] ; if ( webhookData === undefined ) { const errorMessage = `The execution "${ executionId }" with webhook suffix path "${ path }" is not known.` ; throw new ResponseHelper . ResponseError ( errorMessage , 404 , 404 ) ; } const workflowStartNode = workflow . getNode ( lastNodeExecuted ) ; if ( workflowStartNode === null ) { throw new ResponseHelper . ResponseError ( 'Could not find node to process webhook.' , 404 , 404 ) ; } const runExecutionData = fullExecutionData . data ; return new Promise ( ( resolve , reject ) => { const executionMode = 'webhook' ; WebhookHelpers . executeWebhook ( workflow , webhookData , workflowData as IWorkflowDb , workflowStartNode , executionMode , undefined , runExecutionData , fullExecutionData . id , req , res , ( error , data ) => { if ( error !== null ) { return reject ( error ) ; } resolve ( data ) ; } ) ; } ) ; } }