import { IWebhookData , WebhookHttpMethod , Workflow , WorkflowActivateMode , WorkflowExecuteMode , } from 'n8n-workflow' ; import { NodeExecuteFunctions } from '.' ; export class ActiveWebhooks { private workflowWebhooks : { [ key ] : IWebhookData [ ] ; } = { } ; private webhookUrls : { [ key ] : IWebhookData [ ] ; } = { } ; testWebhooks = false ; param { IWebhookData } webhookData param { WorkflowExecuteMode } mode returns { Promise < void > } memberof async add ( workflow , webhookData , mode , activation ) { if ( workflow . id === undefined ) { throw new Error ( 'Webhooks can only be added for saved workflows as an id is needed!' ) ; } if ( webhookData . path . endsWith ( '/' ) ) { webhookData . path = webhookData . path . slice ( 0 , - 1 ) ; } const webhookKey = this . getWebhookKey ( webhookData . httpMethod , webhookData . path , webhookData . webhookId ) ; if ( this . webhookUrls [ webhookKey ] && ! webhookData . webhookId ) { throw new Error ( `Test-Webhook can not be activated because another one with the same method "${ webhookData . httpMethod }" and path "${ webhookData . path }" is already active!` ) ; } if ( this . workflowWebhooks [ webhookData . workflowId ] === undefined ) { this . workflowWebhooks [ webhookData . workflowId ] = [ ] ; } if ( ! this . webhookUrls [ webhookKey ] ) { this . webhookUrls [ webhookKey ] = [ ] ; } this . webhookUrls [ webhookKey ] . push ( webhookData ) ; try { const webhookExists = await workflow . runWebhookMethod ( 'checkExists' , webhookData , NodeExecuteFunctions , mode , activation , this . testWebhooks ) ; if ( webhookExists !== true ) { await workflow . runWebhookMethod ( 'create' , webhookData , NodeExecuteFunctions , mode , activation , this . testWebhooks ) ; } } catch ( error ) { if ( this . webhookUrls [ webhookKey ] . length <= 1 ) { delete this . webhookUrls [ webhookKey ] ; } else { this . webhookUrls [ webhookKey ] = this . webhookUrls [ webhookKey ] . filter ( ( webhook ) => webhook . path !== webhookData . path ) ; } throw error ; } this . workflowWebhooks [ webhookData . workflowId ] . push ( webhookData ) ; } param { WebhookHttpMethod } httpMethod param { string } path param { ( string | undefined ) } webhookId returns { ( IWebhookData | undefined ) } memberof get ( httpMethod , path , webhookId ? ) { const webhookKey = this . getWebhookKey ( httpMethod , path , webhookId ) ; if ( this . webhookUrls [ webhookKey ] === undefined ) { return undefined ; } let webhook ; let maxMatches = 0 ; const pathElementsSet = new Set ( path . split ( '/' ) ) ; this . webhookUrls [ webhookKey ] . forEach ( ( dynamicWebhook ) => { const staticElements = dynamicWebhook . path . split ( '/' ) . filter ( ( ele ) => ! ele . startsWith ( ':' ) ) ; const allStaticExist = staticElements . every ( ( staticEle ) => pathElementsSet . has ( staticEle ) ) ; if ( allStaticExist && staticElements . length > maxMatches ) { maxMatches = staticElements . length ; webhook = dynamicWebhook ; } else if ( staticElements . length === 0 && ! webhook ) { webhook = dynamicWebhook ; } } ) ; return webhook ; } param path getWebhookMethods ( path ) { const methods = [ ] ; Object . keys ( this . webhookUrls ) . filter ( ( key ) => key . includes ( path ) ) . map ( ( key ) => { methods . push ( key . split ( '|' ) [ 0 ] ) ; } ) ; return methods ; } returns { string [ ] } memberof getWorkflowIds ( ) { return Object . keys ( this . workflowWebhooks ) ; } param { WebhookHttpMethod } httpMethod param { string } path param { ( string | undefined ) } webhookId returns { string } memberof getWebhookKey ( httpMethod , path , webhookId ? ) { if ( webhookId ) { if ( path . startsWith ( webhookId ) ) { const cutFromIndex = path . indexOf ( '/' ) + 1 ; path = path . slice ( cutFromIndex ) ; } return `${ httpMethod }|${ webhookId }|${ path . split ( '/' ) . length }` ; } return `${ httpMethod }|${ path }` ; } param { Workflow } workflow returns { boolean } memberof async removeWorkflow ( workflow ) { const workflowId = workflow . id ! . toString ( ) ; if ( this . workflowWebhooks [ workflowId ] === undefined ) { return false ; } const webhooks = this . workflowWebhooks [ workflowId ] ; const mode = 'internal' ; for ( const webhookData of webhooks ) { await workflow . runWebhookMethod ( 'delete' , webhookData , NodeExecuteFunctions , mode , 'update' , this . testWebhooks ) ; delete this . webhookUrls [ this . getWebhookKey ( webhookData . httpMethod , webhookData . path , webhookData . webhookId ) ] ; } delete this . workflowWebhooks [ workflowId ] ; return true ; } /**
     * Removes all the webhooks of the given workflows
     */ async removeAll ( workflows ) { const removePromises = [ ] ; for ( const workflow of workflows ) { removePromises . push ( this . removeWorkflow ( workflow ) ) ; } await Promise . all ( removePromises ) ; } }