From f06d541b12ccd54277f8104bfd61435e90d07ff5 Mon Sep 17 00:00:00 2001 From: Truong Giang Date: Tue, 4 Nov 2025 16:41:45 +0700 Subject: [PATCH 1/5] Version 1 --- credentials/FormidableFormsApi.credentials.ts | 29 +++++++++++ .../FormidableForms/FormidableForms.node.json | 0 nodes/FormidableForms/FormidableForms.node.ts | 50 +++++++++++++++++++ nodes/FormidableForms/logo.svg | 7 +++ package.json | 4 +- 5 files changed, 88 insertions(+), 2 deletions(-) create mode 100644 credentials/FormidableFormsApi.credentials.ts create mode 100644 nodes/FormidableForms/FormidableForms.node.json create mode 100644 nodes/FormidableForms/FormidableForms.node.ts create mode 100644 nodes/FormidableForms/logo.svg diff --git a/credentials/FormidableFormsApi.credentials.ts b/credentials/FormidableFormsApi.credentials.ts new file mode 100644 index 0000000..86980a1 --- /dev/null +++ b/credentials/FormidableFormsApi.credentials.ts @@ -0,0 +1,29 @@ +import { + IAuthenticateGeneric, + ICredentialType, + INodeProperties, +} from 'n8n-workflow'; + +export class FormidableFormsApi implements ICredentialType { + name = 'FormidableFormsApi'; + displayName = 'Formidable Forms API'; + // Uses the link to this tutorial as an example + // Replace with your own docs links when building your own nodes + documentationUrl = 'https://docs.n8n.io/integrations/creating-nodes/build/declarative-style-node/'; + properties: INodeProperties[] = [ + { + displayName: 'API Key', + name: 'apiKey', + type: 'string', + default: '', + }, + ]; + authenticate = { + type: 'generic', + properties: { + qs: { + 'api_key': '={{$credentials.apiKey}}' + } + }, + } as IAuthenticateGeneric; +} diff --git a/nodes/FormidableForms/FormidableForms.node.json b/nodes/FormidableForms/FormidableForms.node.json new file mode 100644 index 0000000..e69de29 diff --git a/nodes/FormidableForms/FormidableForms.node.ts b/nodes/FormidableForms/FormidableForms.node.ts new file mode 100644 index 0000000..12411f7 --- /dev/null +++ b/nodes/FormidableForms/FormidableForms.node.ts @@ -0,0 +1,50 @@ +import { INodeType, INodeTypeDescription } from 'n8n-workflow'; + +export class FormidableForms implements INodeType { + description: INodeTypeDescription = { + displayName: 'Formidable Forms', + name: 'formidableForms', + icon: 'file:logo.svg', + group: ['trigger'], + version: 1, + subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}', + description: 'Start a workflow when a Formidable Forms form action triggered', + defaults: { + name: 'Formidable Forms', + }, + inputs: ['main'], + outputs: ['main'], + credentials: [ + { + name: 'FormidableFormsApi', + required: true, + } + ], + requestDefaults: { + baseURL: 'https://api.formidableforms.com', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json' + } + }, + properties: [ + { + displayName: 'Resource', + name: 'resource', + type: 'options', + noDataExpression: true, + options: [ + { + name: 'Submitted values', + value: 'values' + }, + { + name: 'Form', + value: 'form' + } + ], + default: 'values' + } + ] + } +} diff --git a/nodes/FormidableForms/logo.svg b/nodes/FormidableForms/logo.svg new file mode 100644 index 0000000..ef3e9a8 --- /dev/null +++ b/nodes/FormidableForms/logo.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/package.json b/package.json index 66b8c45..3c272ec 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "n8n-nodes-<...>", + "name": "n8n-nodes-formidable-forms", "version": "0.1.0", "description": "", "license": "MIT", @@ -13,7 +13,7 @@ }, "repository": { "type": "git", - "url": "https://github.com/<...>/n8n-nodes-<...>.git" + "url": "https://github.com/formidable-forms/n8n-nodes-formidable-forms.git" }, "scripts": { "build": "n8n-node build", From 6aa6c0c1d06a7f637eaa9a3859dd504afa4da328 Mon Sep 17 00:00:00 2001 From: Truong Giang Date: Tue, 11 Nov 2025 01:32:00 +0700 Subject: [PATCH 2/5] Complete FormidableFormsTrigger node --- nodes/FormidableForms/FormidableForms.node.ts | 50 ----------- ....json => FormidableFormsTrigger.node.json} | 0 .../FormidableFormsTrigger.node.ts | 89 +++++++++++++++++++ package-lock.json | 4 +- 4 files changed, 91 insertions(+), 52 deletions(-) delete mode 100644 nodes/FormidableForms/FormidableForms.node.ts rename nodes/FormidableForms/{FormidableForms.node.json => FormidableFormsTrigger.node.json} (100%) create mode 100644 nodes/FormidableForms/FormidableFormsTrigger.node.ts diff --git a/nodes/FormidableForms/FormidableForms.node.ts b/nodes/FormidableForms/FormidableForms.node.ts deleted file mode 100644 index 12411f7..0000000 --- a/nodes/FormidableForms/FormidableForms.node.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { INodeType, INodeTypeDescription } from 'n8n-workflow'; - -export class FormidableForms implements INodeType { - description: INodeTypeDescription = { - displayName: 'Formidable Forms', - name: 'formidableForms', - icon: 'file:logo.svg', - group: ['trigger'], - version: 1, - subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}', - description: 'Start a workflow when a Formidable Forms form action triggered', - defaults: { - name: 'Formidable Forms', - }, - inputs: ['main'], - outputs: ['main'], - credentials: [ - { - name: 'FormidableFormsApi', - required: true, - } - ], - requestDefaults: { - baseURL: 'https://api.formidableforms.com', - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json' - } - }, - properties: [ - { - displayName: 'Resource', - name: 'resource', - type: 'options', - noDataExpression: true, - options: [ - { - name: 'Submitted values', - value: 'values' - }, - { - name: 'Form', - value: 'form' - } - ], - default: 'values' - } - ] - } -} diff --git a/nodes/FormidableForms/FormidableForms.node.json b/nodes/FormidableForms/FormidableFormsTrigger.node.json similarity index 100% rename from nodes/FormidableForms/FormidableForms.node.json rename to nodes/FormidableForms/FormidableFormsTrigger.node.json diff --git a/nodes/FormidableForms/FormidableFormsTrigger.node.ts b/nodes/FormidableForms/FormidableFormsTrigger.node.ts new file mode 100644 index 0000000..bc4b822 --- /dev/null +++ b/nodes/FormidableForms/FormidableFormsTrigger.node.ts @@ -0,0 +1,89 @@ +import { + IDataObject, + INodeType, + INodeTypeDescription, + IWebhookFunctions, + IWebhookResponseData +} from 'n8n-workflow'; + +export class FormidableFormsTrigger implements INodeType { + description: INodeTypeDescription = { + displayName: 'Formidable Forms Trigger', + name: 'formidableForms', + icon: 'file:logo.svg', + group: ['trigger'], + version: 1, + subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}', + description: 'Start a workflow when a Formidable Forms form action triggered', + defaults: { + name: 'Formidable Forms', + }, + inputs: [], + outputs: ['main'], + /*credentials: [ + { + name: 'FormidableFormsApi', + required: true, + } + ],*/ + webhooks: [ + { + name: 'default', + isWebhook: true, + httpMethod: 'POST', + responseMode: 'onReceived', + path: 'webhook', + } + ], + properties: [ + { + displayName: 'Resource', + name: 'resource', + type: 'options', + noDataExpression: true, + options: [ + { + name: 'Submitted values', + value: 'values' + }, + { + name: 'Form', + value: 'form' + } + ], + default: 'values' + } + ] + } + + async webhook(this: IWebhookFunctions): Promise { + // Access the raw HTTP request from n8n's webhook context. + const request = this.getRequestObject(); + const response = this.getResponseObject(); + if ( ! request.body ) { + response.status( 403 ).send( 'Permission denied!' ); + return { + noWebhookResponse: true, + workflowData: [ + [ + { + json: { + success: false, + message: 'Permission denied!' + } + } + ] + ] + } + } + + // Default: emit parsed JSON items for downstream nodes via helpers. + const data = this.helpers.returnJsonArray(request.body as IDataObject[]); + + data[0].json.success = true; + + return { + workflowData: [data], + }; + } +} diff --git a/package-lock.json b/package-lock.json index 566f960..64bb334 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,11 +1,11 @@ { - "name": "n8n-nodes-<...>", + "name": "n8n-nodes-formidable-forms", "version": "0.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "n8n-nodes-<...>", + "name": "n8n-nodes-formidable-forms", "version": "0.1.0", "license": "MIT", "devDependencies": { From 6dc3e8663d1c6682402bce1872cfd55836ef5c0d Mon Sep 17 00:00:00 2001 From: Truong Giang Date: Tue, 11 Nov 2025 03:40:10 +0700 Subject: [PATCH 3/5] Test credential --- nodes/FormidableForms/FormidableFormsTrigger.node.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nodes/FormidableForms/FormidableFormsTrigger.node.ts b/nodes/FormidableForms/FormidableFormsTrigger.node.ts index bc4b822..cba565e 100644 --- a/nodes/FormidableForms/FormidableFormsTrigger.node.ts +++ b/nodes/FormidableForms/FormidableFormsTrigger.node.ts @@ -20,12 +20,12 @@ export class FormidableFormsTrigger implements INodeType { }, inputs: [], outputs: ['main'], - /*credentials: [ + credentials: [ { name: 'FormidableFormsApi', required: true, } - ],*/ + ], webhooks: [ { name: 'default', From f1a2f3bfc23b76d70554024536a5db0a5cb804ca Mon Sep 17 00:00:00 2001 From: Truong Giang Date: Wed, 12 Nov 2025 00:09:43 +0700 Subject: [PATCH 4/5] Use custom authentication method, clean code --- credentials/FormidableFormsApi.credentials.ts | 29 ---- credentials/GithubIssuesApi.credentials.ts | 45 ------ .../GithubIssuesOAuth2Api.credentials.ts | 54 ------- icons/github.dark.svg | 3 - icons/github.svg | 3 - nodes/Example/Example.node.json | 18 --- nodes/Example/Example.node.ts | 78 --------- nodes/Example/example.dark.svg | 13 -- nodes/Example/example.svg | 13 -- .../FormidableFormsTrigger.node.json | 13 ++ .../FormidableFormsTrigger.node.ts | 74 +++++---- nodes/GithubIssues/GithubIssues.node.json | 18 --- nodes/GithubIssues/GithubIssues.node.ts | 96 ----------- nodes/GithubIssues/listSearch/getIssues.ts | 49 ------ .../listSearch/getRepositories.ts | 50 ------ nodes/GithubIssues/listSearch/getUsers.ts | 49 ------ nodes/GithubIssues/resources/issue/create.ts | 74 --------- nodes/GithubIssues/resources/issue/get.ts | 14 -- nodes/GithubIssues/resources/issue/getAll.ts | 124 -------------- nodes/GithubIssues/resources/issue/index.ts | 75 --------- .../resources/issueComment/getAll.ts | 65 -------- .../resources/issueComment/index.ts | 47 ------ nodes/GithubIssues/shared/descriptions.ts | 151 ------------------ nodes/GithubIssues/shared/transport.ts | 32 ---- nodes/GithubIssues/shared/utils.ts | 14 -- package.json | 8 +- 26 files changed, 59 insertions(+), 1150 deletions(-) delete mode 100644 credentials/FormidableFormsApi.credentials.ts delete mode 100644 credentials/GithubIssuesApi.credentials.ts delete mode 100644 credentials/GithubIssuesOAuth2Api.credentials.ts delete mode 100644 icons/github.dark.svg delete mode 100644 icons/github.svg delete mode 100644 nodes/Example/Example.node.json delete mode 100644 nodes/Example/Example.node.ts delete mode 100644 nodes/Example/example.dark.svg delete mode 100644 nodes/Example/example.svg delete mode 100644 nodes/GithubIssues/GithubIssues.node.json delete mode 100644 nodes/GithubIssues/GithubIssues.node.ts delete mode 100644 nodes/GithubIssues/listSearch/getIssues.ts delete mode 100644 nodes/GithubIssues/listSearch/getRepositories.ts delete mode 100644 nodes/GithubIssues/listSearch/getUsers.ts delete mode 100644 nodes/GithubIssues/resources/issue/create.ts delete mode 100644 nodes/GithubIssues/resources/issue/get.ts delete mode 100644 nodes/GithubIssues/resources/issue/getAll.ts delete mode 100644 nodes/GithubIssues/resources/issue/index.ts delete mode 100644 nodes/GithubIssues/resources/issueComment/getAll.ts delete mode 100644 nodes/GithubIssues/resources/issueComment/index.ts delete mode 100644 nodes/GithubIssues/shared/descriptions.ts delete mode 100644 nodes/GithubIssues/shared/transport.ts delete mode 100644 nodes/GithubIssues/shared/utils.ts diff --git a/credentials/FormidableFormsApi.credentials.ts b/credentials/FormidableFormsApi.credentials.ts deleted file mode 100644 index 86980a1..0000000 --- a/credentials/FormidableFormsApi.credentials.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { - IAuthenticateGeneric, - ICredentialType, - INodeProperties, -} from 'n8n-workflow'; - -export class FormidableFormsApi implements ICredentialType { - name = 'FormidableFormsApi'; - displayName = 'Formidable Forms API'; - // Uses the link to this tutorial as an example - // Replace with your own docs links when building your own nodes - documentationUrl = 'https://docs.n8n.io/integrations/creating-nodes/build/declarative-style-node/'; - properties: INodeProperties[] = [ - { - displayName: 'API Key', - name: 'apiKey', - type: 'string', - default: '', - }, - ]; - authenticate = { - type: 'generic', - properties: { - qs: { - 'api_key': '={{$credentials.apiKey}}' - } - }, - } as IAuthenticateGeneric; -} diff --git a/credentials/GithubIssuesApi.credentials.ts b/credentials/GithubIssuesApi.credentials.ts deleted file mode 100644 index f8b267e..0000000 --- a/credentials/GithubIssuesApi.credentials.ts +++ /dev/null @@ -1,45 +0,0 @@ -import type { - IAuthenticateGeneric, - Icon, - ICredentialTestRequest, - ICredentialType, - INodeProperties, -} from 'n8n-workflow'; - -export class GithubIssuesApi implements ICredentialType { - name = 'githubIssuesApi'; - - displayName = 'GitHub Issues API'; - - icon: Icon = { light: 'file:../icons/github.svg', dark: 'file:../icons/github.dark.svg' }; - - documentationUrl = - 'https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens#deleting-a-personal-access-token'; - - properties: INodeProperties[] = [ - { - displayName: 'Access Token', - name: 'accessToken', - type: 'string', - typeOptions: { password: true }, - default: '', - }, - ]; - - authenticate: IAuthenticateGeneric = { - type: 'generic', - properties: { - headers: { - Authorization: '=token {{$credentials?.accessToken}}', - }, - }, - }; - - test: ICredentialTestRequest = { - request: { - baseURL: 'https://api.github.com', - url: '/user', - method: 'GET', - }, - }; -} diff --git a/credentials/GithubIssuesOAuth2Api.credentials.ts b/credentials/GithubIssuesOAuth2Api.credentials.ts deleted file mode 100644 index 0eb98fc..0000000 --- a/credentials/GithubIssuesOAuth2Api.credentials.ts +++ /dev/null @@ -1,54 +0,0 @@ -import type { Icon, ICredentialType, INodeProperties } from 'n8n-workflow'; - -export class GithubIssuesOAuth2Api implements ICredentialType { - name = 'githubIssuesOAuth2Api'; - - extends = ['oAuth2Api']; - - displayName = 'GitHub Issues OAuth2 API'; - - icon: Icon = { light: 'file:../icons/github.svg', dark: 'file:../icons/github.dark.svg' }; - - documentationUrl = 'https://docs.github.com/en/apps/oauth-apps'; - - properties: INodeProperties[] = [ - { - displayName: 'Grant Type', - name: 'grantType', - type: 'hidden', - default: 'authorizationCode', - }, - { - displayName: 'Authorization URL', - name: 'authUrl', - type: 'hidden', - default: 'https://github.com/login/oauth/authorize', - required: true, - }, - { - displayName: 'Access Token URL', - name: 'accessTokenUrl', - type: 'hidden', - default: 'https://github.com/login/oauth/access_token', - required: true, - }, - { - displayName: 'Scope', - name: 'scope', - type: 'hidden', - default: 'repo', - }, - { - displayName: 'Auth URI Query Parameters', - name: 'authQueryParameters', - type: 'hidden', - default: '', - }, - { - displayName: 'Authentication', - name: 'authentication', - type: 'hidden', - default: 'header', - }, - ]; -} diff --git a/icons/github.dark.svg b/icons/github.dark.svg deleted file mode 100644 index 0366b08..0000000 --- a/icons/github.dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/icons/github.svg b/icons/github.svg deleted file mode 100644 index fe1ac05..0000000 --- a/icons/github.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/nodes/Example/Example.node.json b/nodes/Example/Example.node.json deleted file mode 100644 index 266250f..0000000 --- a/nodes/Example/Example.node.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "node": "n8n-nodes-example", - "nodeVersion": "1.0", - "codexVersion": "1.0", - "categories": ["Development", "Developer Tools"], - "resources": { - "credentialDocumentation": [ - { - "url": "https://github.com/org/repo?tab=readme-ov-file#credentials" - } - ], - "primaryDocumentation": [ - { - "url": "https://github.com/org/repo?tab=readme-ov-file" - } - ] - } -} diff --git a/nodes/Example/Example.node.ts b/nodes/Example/Example.node.ts deleted file mode 100644 index fb5e019..0000000 --- a/nodes/Example/Example.node.ts +++ /dev/null @@ -1,78 +0,0 @@ -import type { - IExecuteFunctions, - INodeExecutionData, - INodeType, - INodeTypeDescription, -} from 'n8n-workflow'; -import { NodeConnectionTypes, NodeOperationError } from 'n8n-workflow'; - -export class Example implements INodeType { - description: INodeTypeDescription = { - displayName: 'Example', - name: 'example', - icon: { light: 'file:example.svg', dark: 'file:example.dark.svg' }, - group: ['input'], - version: 1, - description: 'Basic Example Node', - defaults: { - name: 'Example', - }, - inputs: [NodeConnectionTypes.Main], - outputs: [NodeConnectionTypes.Main], - usableAsTool: true, - properties: [ - // Node properties which the user gets displayed and - // can change on the node. - { - displayName: 'My String', - name: 'myString', - type: 'string', - default: '', - placeholder: 'Placeholder value', - description: 'The description text', - }, - ], - }; - - // The function below is responsible for actually doing whatever this node - // is supposed to do. In this case, we're just appending the `myString` property - // with whatever the user has entered. - // You can make async calls and use `await`. - async execute(this: IExecuteFunctions): Promise { - const items = this.getInputData(); - - let item: INodeExecutionData; - let myString: string; - - // Iterates over all input items and add the key "myString" with the - // value the parameter "myString" resolves to. - // (This could be a different value for each item in case it contains an expression) - for (let itemIndex = 0; itemIndex < items.length; itemIndex++) { - try { - myString = this.getNodeParameter('myString', itemIndex, '') as string; - item = items[itemIndex]; - - item.json.myString = myString; - } catch (error) { - // This node should never fail but we want to showcase how - // to handle errors. - if (this.continueOnFail()) { - items.push({ json: this.getInputData(itemIndex)[0].json, error, pairedItem: itemIndex }); - } else { - // Adding `itemIndex` allows other workflows to handle this error - if (error.context) { - // If the error thrown already contains the context property, - // only append the itemIndex - error.context.itemIndex = itemIndex; - throw error; - } - throw new NodeOperationError(this.getNode(), error, { - itemIndex, - }); - } - } - } - - return [items]; - } -} diff --git a/nodes/Example/example.dark.svg b/nodes/Example/example.dark.svg deleted file mode 100644 index c07cb10..0000000 --- a/nodes/Example/example.dark.svg +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - diff --git a/nodes/Example/example.svg b/nodes/Example/example.svg deleted file mode 100644 index 703e1fe..0000000 --- a/nodes/Example/example.svg +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - diff --git a/nodes/FormidableForms/FormidableFormsTrigger.node.json b/nodes/FormidableForms/FormidableFormsTrigger.node.json index e69de29..0919a5a 100644 --- a/nodes/FormidableForms/FormidableFormsTrigger.node.json +++ b/nodes/FormidableForms/FormidableFormsTrigger.node.json @@ -0,0 +1,13 @@ +{ + "node": "n8n-nodes-formidable-forms.formidableFormsTrigger", + "nodeVersion": "1.0", + "codexVersion": "1.0", + "categories": ["Trigger", "Forms"], + "resources": { + "primaryDocumentation": [ + { + "url": "https://github.com/Strategy11/n8n-nodes-formidable-forms" + } + ] + } +} diff --git a/nodes/FormidableForms/FormidableFormsTrigger.node.ts b/nodes/FormidableForms/FormidableFormsTrigger.node.ts index cba565e..afd17c3 100644 --- a/nodes/FormidableForms/FormidableFormsTrigger.node.ts +++ b/nodes/FormidableForms/FormidableFormsTrigger.node.ts @@ -9,7 +9,7 @@ import { export class FormidableFormsTrigger implements INodeType { description: INodeTypeDescription = { displayName: 'Formidable Forms Trigger', - name: 'formidableForms', + name: 'formidableFormsTrigger', icon: 'file:logo.svg', group: ['trigger'], version: 1, @@ -20,12 +20,6 @@ export class FormidableFormsTrigger implements INodeType { }, inputs: [], outputs: ['main'], - credentials: [ - { - name: 'FormidableFormsApi', - required: true, - } - ], webhooks: [ { name: 'default', @@ -37,21 +31,33 @@ export class FormidableFormsTrigger implements INodeType { ], properties: [ { - displayName: 'Resource', - name: 'resource', + displayName: 'Authentication', + name: 'authentication', type: 'options', noDataExpression: true, options: [ { - name: 'Submitted values', - value: 'values' + name: 'Token', + value: 'token' }, { - name: 'Form', - value: 'form' + name: 'None', + value: 'none' } ], - default: 'values' + default: 'none' + }, + { + displayName: 'Token', + name: 'token', + type: 'string', + noDataExpression: true, + default: '', + displayOptions: { + show: { + authentication: ['token'], + } + } } ] } @@ -60,25 +66,16 @@ export class FormidableFormsTrigger implements INodeType { // Access the raw HTTP request from n8n's webhook context. const request = this.getRequestObject(); const response = this.getResponseObject(); - if ( ! request.body ) { - response.status( 403 ).send( 'Permission denied!' ); - return { - noWebhookResponse: true, - workflowData: [ - [ - { - json: { - success: false, - message: 'Permission denied!' - } - } - ] - ] - } + if ( ! request.body || ! request.body.token || request.body.token !== ( this.getNodeParameter( 'token' ) as string ) ) { + return showError( response, 403, 'Forbidden!' ); + } + + if ( ! request.body.event || ! request.body.mapping ) { + return showError( response, 400, 'Bad Request!' ); } // Default: emit parsed JSON items for downstream nodes via helpers. - const data = this.helpers.returnJsonArray(request.body as IDataObject[]); + const data = this.helpers.returnJsonArray( request.body as IDataObject[] ); data[0].json.success = true; @@ -87,3 +84,20 @@ export class FormidableFormsTrigger implements INodeType { }; } } + +const showError = ( response: any, code: number, message: string ) => { + response.status( code ).send( message ); + return { + noWebhookResponse: true, + workflowData: [ + [ + { + json: { + success: false, + message + } + } + ] + ] + }; +} diff --git a/nodes/GithubIssues/GithubIssues.node.json b/nodes/GithubIssues/GithubIssues.node.json deleted file mode 100644 index 5eca62e..0000000 --- a/nodes/GithubIssues/GithubIssues.node.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "node": "n8n-nodes-github-issues", - "nodeVersion": "1.0", - "codexVersion": "1.0", - "categories": ["Development", "Developer Tools"], - "resources": { - "credentialDocumentation": [ - { - "url": "https://github.com/org/repo?tab=readme-ov-file#credentials" - } - ], - "primaryDocumentation": [ - { - "url": "https://github.com/org/repo?tab=readme-ov-file" - } - ] - } -} diff --git a/nodes/GithubIssues/GithubIssues.node.ts b/nodes/GithubIssues/GithubIssues.node.ts deleted file mode 100644 index 9965864..0000000 --- a/nodes/GithubIssues/GithubIssues.node.ts +++ /dev/null @@ -1,96 +0,0 @@ -import { NodeConnectionTypes, type INodeType, type INodeTypeDescription } from 'n8n-workflow'; -import { issueDescription } from './resources/issue'; -import { issueCommentDescription } from './resources/issueComment'; -import { getRepositories } from './listSearch/getRepositories'; -import { getUsers } from './listSearch/getUsers'; -import { getIssues } from './listSearch/getIssues'; - -export class GithubIssues implements INodeType { - description: INodeTypeDescription = { - displayName: 'GitHub Issues', - name: 'githubIssues', - icon: { light: 'file:../../icons/github.svg', dark: 'file:../../icons/github.dark.svg' }, - group: ['input'], - version: 1, - subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}', - description: 'Consume issues from the GitHub API', - defaults: { - name: 'GitHub Issues', - }, - usableAsTool: true, - inputs: [NodeConnectionTypes.Main], - outputs: [NodeConnectionTypes.Main], - credentials: [ - { - name: 'githubIssuesApi', - required: true, - displayOptions: { - show: { - authentication: ['accessToken'], - }, - }, - }, - { - name: 'githubIssuesOAuth2Api', - required: true, - displayOptions: { - show: { - authentication: ['oAuth2'], - }, - }, - }, - ], - requestDefaults: { - baseURL: 'https://api.github.com', - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json', - }, - }, - properties: [ - { - displayName: 'Authentication', - name: 'authentication', - type: 'options', - options: [ - { - name: 'Access Token', - value: 'accessToken', - }, - { - name: 'OAuth2', - value: 'oAuth2', - }, - ], - default: 'accessToken', - }, - { - displayName: 'Resource', - name: 'resource', - type: 'options', - noDataExpression: true, - options: [ - { - name: 'Issue', - value: 'issue', - }, - { - name: 'Issue Comment', - value: 'issueComment', - }, - ], - default: 'issue', - }, - ...issueDescription, - ...issueCommentDescription, - ], - }; - - methods = { - listSearch: { - getRepositories, - getUsers, - getIssues, - }, - }; -} diff --git a/nodes/GithubIssues/listSearch/getIssues.ts b/nodes/GithubIssues/listSearch/getIssues.ts deleted file mode 100644 index f340b03..0000000 --- a/nodes/GithubIssues/listSearch/getIssues.ts +++ /dev/null @@ -1,49 +0,0 @@ -import type { - ILoadOptionsFunctions, - INodeListSearchResult, - INodeListSearchItems, -} from 'n8n-workflow'; -import { githubApiRequest } from '../shared/transport'; - -type IssueSearchItem = { - number: number; - title: string; - html_url: string; -}; - -type IssueSearchResponse = { - items: IssueSearchItem[]; - total_count: number; -}; - -export async function getIssues( - this: ILoadOptionsFunctions, - filter?: string, - paginationToken?: string, -): Promise { - const page = paginationToken ? +paginationToken : 1; - const per_page = 100; - - let responseData: IssueSearchResponse = { - items: [], - total_count: 0, - }; - const owner = this.getNodeParameter('owner', '', { extractValue: true }); - const repository = this.getNodeParameter('repository', '', { extractValue: true }); - const filters = [filter, `repo:${owner}/${repository}`]; - - responseData = await githubApiRequest.call(this, 'GET', '/search/issues', { - q: filters.filter(Boolean).join(' '), - page, - per_page, - }); - - const results: INodeListSearchItems[] = responseData.items.map((item: IssueSearchItem) => ({ - name: item.title, - value: item.number, - url: item.html_url, - })); - - const nextPaginationToken = page * per_page < responseData.total_count ? page + 1 : undefined; - return { results, paginationToken: nextPaginationToken }; -} diff --git a/nodes/GithubIssues/listSearch/getRepositories.ts b/nodes/GithubIssues/listSearch/getRepositories.ts deleted file mode 100644 index 9f5a6b1..0000000 --- a/nodes/GithubIssues/listSearch/getRepositories.ts +++ /dev/null @@ -1,50 +0,0 @@ -import type { - ILoadOptionsFunctions, - INodeListSearchItems, - INodeListSearchResult, -} from 'n8n-workflow'; -import { githubApiRequest } from '../shared/transport'; - -type RepositorySearchItem = { - name: string; - html_url: string; -}; - -type RepositorySearchResponse = { - items: RepositorySearchItem[]; - total_count: number; -}; - -export async function getRepositories( - this: ILoadOptionsFunctions, - filter?: string, - paginationToken?: string, -): Promise { - const owner = this.getCurrentNodeParameter('owner', { extractValue: true }); - const page = paginationToken ? +paginationToken : 1; - const per_page = 100; - const q = `${filter ?? ''} user:${owner} fork:true`; - let responseData: RepositorySearchResponse = { - items: [], - total_count: 0, - }; - - try { - responseData = await githubApiRequest.call(this, 'GET', '/search/repositories', { - q, - page, - per_page, - }); - } catch { - // will fail if the owner does not have any repositories - } - - const results: INodeListSearchItems[] = responseData.items.map((item: RepositorySearchItem) => ({ - name: item.name, - value: item.name, - url: item.html_url, - })); - - const nextPaginationToken = page * per_page < responseData.total_count ? page + 1 : undefined; - return { results, paginationToken: nextPaginationToken }; -} diff --git a/nodes/GithubIssues/listSearch/getUsers.ts b/nodes/GithubIssues/listSearch/getUsers.ts deleted file mode 100644 index d8e0853..0000000 --- a/nodes/GithubIssues/listSearch/getUsers.ts +++ /dev/null @@ -1,49 +0,0 @@ -import type { - ILoadOptionsFunctions, - INodeListSearchResult, - INodeListSearchItems, -} from 'n8n-workflow'; -import { githubApiRequest } from '../shared/transport'; - -type UserSearchItem = { - login: string; - html_url: string; -}; - -type UserSearchResponse = { - items: UserSearchItem[]; - total_count: number; -}; - -export async function getUsers( - this: ILoadOptionsFunctions, - filter?: string, - paginationToken?: string, -): Promise { - const page = paginationToken ? +paginationToken : 1; - const per_page = 100; - - let responseData: UserSearchResponse = { - items: [], - total_count: 0, - }; - - try { - responseData = await githubApiRequest.call(this, 'GET', '/search/users', { - q: filter, - page, - per_page, - }); - } catch { - // will fail if the owner does not have any users - } - - const results: INodeListSearchItems[] = responseData.items.map((item: UserSearchItem) => ({ - name: item.login, - value: item.login, - url: item.html_url, - })); - - const nextPaginationToken = page * per_page < responseData.total_count ? page + 1 : undefined; - return { results, paginationToken: nextPaginationToken }; -} diff --git a/nodes/GithubIssues/resources/issue/create.ts b/nodes/GithubIssues/resources/issue/create.ts deleted file mode 100644 index 4c7fd7e..0000000 --- a/nodes/GithubIssues/resources/issue/create.ts +++ /dev/null @@ -1,74 +0,0 @@ -import type { INodeProperties } from 'n8n-workflow'; - -const showOnlyForIssueCreate = { - operation: ['create'], - resource: ['issue'], -}; - -export const issueCreateDescription: INodeProperties[] = [ - { - displayName: 'Title', - name: 'title', - type: 'string', - default: '', - required: true, - displayOptions: { - show: showOnlyForIssueCreate, - }, - description: 'The title of the issue', - routing: { - send: { - type: 'body', - property: 'title', - }, - }, - }, - { - displayName: 'Body', - name: 'body', - type: 'string', - typeOptions: { - rows: 5, - }, - default: '', - displayOptions: { - show: showOnlyForIssueCreate, - }, - description: 'The body of the issue', - routing: { - send: { - type: 'body', - property: 'body', - }, - }, - }, - { - displayName: 'Labels', - name: 'labels', - type: 'collection', - typeOptions: { - multipleValues: true, - multipleValueButtonText: 'Add Label', - }, - displayOptions: { - show: showOnlyForIssueCreate, - }, - default: { label: '' }, - options: [ - { - displayName: 'Label', - name: 'label', - type: 'string', - default: '', - description: 'Label to add to issue', - }, - ], - routing: { - send: { - type: 'body', - property: 'labels', - value: '={{$value.map((data) => data.label)}}', - }, - }, - }, -]; diff --git a/nodes/GithubIssues/resources/issue/get.ts b/nodes/GithubIssues/resources/issue/get.ts deleted file mode 100644 index 7dc7181..0000000 --- a/nodes/GithubIssues/resources/issue/get.ts +++ /dev/null @@ -1,14 +0,0 @@ -import type { INodeProperties } from 'n8n-workflow'; -import { issueSelect } from '../../shared/descriptions'; - -const showOnlyForIssueGet = { - operation: ['get'], - resource: ['issue'], -}; - -export const issueGetDescription: INodeProperties[] = [ - { - ...issueSelect, - displayOptions: { show: showOnlyForIssueGet }, - }, -]; diff --git a/nodes/GithubIssues/resources/issue/getAll.ts b/nodes/GithubIssues/resources/issue/getAll.ts deleted file mode 100644 index b5b5fed..0000000 --- a/nodes/GithubIssues/resources/issue/getAll.ts +++ /dev/null @@ -1,124 +0,0 @@ -import type { INodeProperties } from 'n8n-workflow'; -import { parseLinkHeader } from '../../shared/utils'; - -const showOnlyForIssueGetMany = { - operation: ['getAll'], - resource: ['issue'], -}; - -export const issueGetManyDescription: INodeProperties[] = [ - { - displayName: 'Limit', - name: 'limit', - type: 'number', - displayOptions: { - show: { - ...showOnlyForIssueGetMany, - returnAll: [false], - }, - }, - typeOptions: { - minValue: 1, - maxValue: 100, - }, - default: 50, - routing: { - send: { - type: 'query', - property: 'per_page', - }, - output: { - maxResults: '={{$value}}', - }, - }, - description: 'Max number of results to return', - }, - { - displayName: 'Return All', - name: 'returnAll', - type: 'boolean', - displayOptions: { - show: showOnlyForIssueGetMany, - }, - default: false, - description: 'Whether to return all results or only up to a given limit', - routing: { - send: { - paginate: '={{ $value }}', - type: 'query', - property: 'per_page', - value: '100', - }, - operations: { - pagination: { - type: 'generic', - properties: { - continue: `={{ !!(${parseLinkHeader.toString()})($response.headers?.link).next }}`, - request: { - url: `={{ (${parseLinkHeader.toString()})($response.headers?.link)?.next ?? $request.url }}`, - }, - }, - }, - }, - }, - }, - { - displayName: 'Filters', - name: 'filters', - type: 'collection', - typeOptions: { - multipleValueButtonText: 'Add Filter', - }, - displayOptions: { - show: showOnlyForIssueGetMany, - }, - default: {}, - options: [ - { - displayName: 'Updated Since', - name: 'since', - type: 'dateTime', - default: '', - description: 'Return only issues updated at or after this time', - routing: { - request: { - qs: { - since: '={{$value}}', - }, - }, - }, - }, - { - displayName: 'State', - name: 'state', - type: 'options', - options: [ - { - name: 'All', - value: 'all', - description: 'Returns issues with any state', - }, - { - name: 'Closed', - value: 'closed', - description: 'Return issues with "closed" state', - }, - { - name: 'Open', - value: 'open', - description: 'Return issues with "open" state', - }, - ], - default: 'open', - description: 'The issue state to filter on', - routing: { - request: { - qs: { - state: '={{$value}}', - }, - }, - }, - }, - ], - }, -]; diff --git a/nodes/GithubIssues/resources/issue/index.ts b/nodes/GithubIssues/resources/issue/index.ts deleted file mode 100644 index 6c915d2..0000000 --- a/nodes/GithubIssues/resources/issue/index.ts +++ /dev/null @@ -1,75 +0,0 @@ -import type { INodeProperties } from 'n8n-workflow'; -import { repoNameSelect, repoOwnerSelect } from '../../shared/descriptions'; -import { issueGetManyDescription } from './getAll'; -import { issueGetDescription } from './get'; -import { issueCreateDescription } from './create'; - -const showOnlyForIssues = { - resource: ['issue'], -}; - -export const issueDescription: INodeProperties[] = [ - { - displayName: 'Operation', - name: 'operation', - type: 'options', - noDataExpression: true, - displayOptions: { - show: showOnlyForIssues, - }, - options: [ - { - name: 'Get Many', - value: 'getAll', - action: 'Get issues in a repository', - description: 'Get many issues in a repository', - routing: { - request: { - method: 'GET', - url: '=/repos/{{$parameter.owner}}/{{$parameter.repository}}/issues', - }, - }, - }, - { - name: 'Get', - value: 'get', - action: 'Get an issue', - description: 'Get the data of a single issue', - routing: { - request: { - method: 'GET', - url: '=/repos/{{$parameter.owner}}/{{$parameter.repository}}/issues/{{$parameter.issue}}', - }, - }, - }, - { - name: 'Create', - value: 'create', - action: 'Create a new issue', - description: 'Create a new issue', - routing: { - request: { - method: 'POST', - url: '=/repos/{{$parameter.owner}}/{{$parameter.repository}}/issues', - }, - }, - }, - ], - default: 'getAll', - }, - { - ...repoOwnerSelect, - displayOptions: { - show: showOnlyForIssues, - }, - }, - { - ...repoNameSelect, - displayOptions: { - show: showOnlyForIssues, - }, - }, - ...issueGetManyDescription, - ...issueGetDescription, - ...issueCreateDescription, -]; diff --git a/nodes/GithubIssues/resources/issueComment/getAll.ts b/nodes/GithubIssues/resources/issueComment/getAll.ts deleted file mode 100644 index 53b2057..0000000 --- a/nodes/GithubIssues/resources/issueComment/getAll.ts +++ /dev/null @@ -1,65 +0,0 @@ -import type { INodeProperties } from 'n8n-workflow'; -import { parseLinkHeader } from '../../shared/utils'; - -const showOnlyForIssueCommentGetMany = { - operation: ['getAll'], - resource: ['issueComment'], -}; - -export const issueCommentGetManyDescription: INodeProperties[] = [ - { - displayName: 'Limit', - name: 'limit', - type: 'number', - displayOptions: { - show: { - ...showOnlyForIssueCommentGetMany, - returnAll: [false], - }, - }, - typeOptions: { - minValue: 1, - maxValue: 100, - }, - default: 50, - routing: { - send: { - type: 'query', - property: 'per_page', - }, - output: { - maxResults: '={{$value}}', - }, - }, - description: 'Max number of results to return', - }, - { - displayName: 'Return All', - name: 'returnAll', - type: 'boolean', - displayOptions: { - show: showOnlyForIssueCommentGetMany, - }, - default: false, - description: 'Whether to return all results or only up to a given limit', - routing: { - send: { - paginate: '={{ $value }}', - type: 'query', - property: 'per_page', - value: '100', - }, - operations: { - pagination: { - type: 'generic', - properties: { - continue: `={{ !!(${parseLinkHeader.toString()})($response.headers?.link).next }}`, - request: { - url: `={{ (${parseLinkHeader.toString()})($response.headers?.link)?.next ?? $request.url }}`, - }, - }, - }, - }, - }, - }, -]; diff --git a/nodes/GithubIssues/resources/issueComment/index.ts b/nodes/GithubIssues/resources/issueComment/index.ts deleted file mode 100644 index 886f7c2..0000000 --- a/nodes/GithubIssues/resources/issueComment/index.ts +++ /dev/null @@ -1,47 +0,0 @@ -import type { INodeProperties } from 'n8n-workflow'; -import { repoNameSelect, repoOwnerSelect } from '../../shared/descriptions'; -import { issueCommentGetManyDescription } from './getAll'; - -const showOnlyForIssueComments = { - resource: ['issueComment'], -}; - -export const issueCommentDescription: INodeProperties[] = [ - { - displayName: 'Operation', - name: 'operation', - type: 'options', - noDataExpression: true, - displayOptions: { - show: showOnlyForIssueComments, - }, - options: [ - { - name: 'Get Many', - value: 'getAll', - action: 'Get issue comments', - description: 'Get issue comments', - routing: { - request: { - method: 'GET', - url: '=/repos/{{$parameter.owner}}/{{$parameter.repository}}/issues/comments', - }, - }, - }, - ], - default: 'getAll', - }, - { - ...repoOwnerSelect, - displayOptions: { - show: showOnlyForIssueComments, - }, - }, - { - ...repoNameSelect, - displayOptions: { - show: showOnlyForIssueComments, - }, - }, - ...issueCommentGetManyDescription, -]; diff --git a/nodes/GithubIssues/shared/descriptions.ts b/nodes/GithubIssues/shared/descriptions.ts deleted file mode 100644 index aaeaaa8..0000000 --- a/nodes/GithubIssues/shared/descriptions.ts +++ /dev/null @@ -1,151 +0,0 @@ -import type { INodeProperties } from 'n8n-workflow'; - -export const repoOwnerSelect: INodeProperties = { - displayName: 'Repository Owner', - name: 'owner', - type: 'resourceLocator', - default: { mode: 'list', value: '' }, - required: true, - modes: [ - { - displayName: 'Repository Owner', - name: 'list', - type: 'list', - placeholder: 'Select an owner...', - typeOptions: { - searchListMethod: 'getUsers', - searchable: true, - searchFilterRequired: false, - }, - }, - { - displayName: 'Link', - name: 'url', - type: 'string', - placeholder: 'e.g. https://github.com/n8n-io', - extractValue: { - type: 'regex', - regex: 'https:\\/\\/github.com\\/([-_0-9a-zA-Z]+)', - }, - validation: [ - { - type: 'regex', - properties: { - regex: 'https:\\/\\/github.com\\/([-_0-9a-zA-Z]+)(?:.*)', - errorMessage: 'Not a valid GitHub URL', - }, - }, - ], - }, - { - displayName: 'By Name', - name: 'name', - type: 'string', - placeholder: 'e.g. n8n-io', - validation: [ - { - type: 'regex', - properties: { - regex: '[-_a-zA-Z0-9]+', - errorMessage: 'Not a valid GitHub Owner Name', - }, - }, - ], - url: '=https://github.com/{{$value}}', - }, - ], -}; - -export const repoNameSelect: INodeProperties = { - displayName: 'Repository Name', - name: 'repository', - type: 'resourceLocator', - default: { - mode: 'list', - value: '', - }, - required: true, - modes: [ - { - displayName: 'Repository Name', - name: 'list', - type: 'list', - placeholder: 'Select an Repository...', - typeOptions: { - searchListMethod: 'getRepositories', - searchable: true, - }, - }, - { - displayName: 'Link', - name: 'url', - type: 'string', - placeholder: 'e.g. https://github.com/n8n-io/n8n', - extractValue: { - type: 'regex', - regex: 'https:\\/\\/github.com\\/(?:[-_0-9a-zA-Z]+)\\/([-_.0-9a-zA-Z]+)', - }, - validation: [ - { - type: 'regex', - properties: { - regex: 'https:\\/\\/github.com\\/(?:[-_0-9a-zA-Z]+)\\/([-_.0-9a-zA-Z]+)(?:.*)', - errorMessage: 'Not a valid GitHub Repository URL', - }, - }, - ], - }, - { - displayName: 'By Name', - name: 'name', - type: 'string', - placeholder: 'e.g. n8n', - validation: [ - { - type: 'regex', - properties: { - regex: '[-_.0-9a-zA-Z]+', - errorMessage: 'Not a valid GitHub Repository Name', - }, - }, - ], - url: '=https://github.com/{{$parameter["owner"]}}/{{$value}}', - }, - ], - displayOptions: { - hide: { - resource: ['user', 'organization'], - operation: ['getRepositories'], - }, - }, -}; - -export const issueSelect: INodeProperties = { - displayName: 'Issue', - name: 'issue', - type: 'resourceLocator', - default: { - mode: 'list', - value: '', - }, - required: true, - modes: [ - { - displayName: 'Issue', - name: 'list', - type: 'list', - placeholder: 'Select an Issue...', - typeOptions: { - searchListMethod: 'getIssues', - searchable: true, - }, - }, - { - displayName: 'By ID', - name: 'name', - type: 'string', - placeholder: 'e.g. 123', - url: '=https://github.com/{{$parameter.owner}}/{{$parameter.repository}}/issues/{{$value}}', - }, - ], -}; diff --git a/nodes/GithubIssues/shared/transport.ts b/nodes/GithubIssues/shared/transport.ts deleted file mode 100644 index 3555ee0..0000000 --- a/nodes/GithubIssues/shared/transport.ts +++ /dev/null @@ -1,32 +0,0 @@ -import type { - IHookFunctions, - IExecuteFunctions, - IExecuteSingleFunctions, - ILoadOptionsFunctions, - IHttpRequestMethods, - IDataObject, - IHttpRequestOptions, -} from 'n8n-workflow'; - -export async function githubApiRequest( - this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, - method: IHttpRequestMethods, - resource: string, - qs: IDataObject = {}, - body: IDataObject | undefined = undefined, -) { - const authenticationMethod = this.getNodeParameter('authentication', 0); - - const options: IHttpRequestOptions = { - method: method, - qs, - body, - url: `https://api.github.com${resource}`, - json: true, - }; - - const credentialType = - authenticationMethod === 'accessToken' ? 'githubIssuesApi' : 'githubIssuesOAuth2Api'; - - return this.helpers.httpRequestWithAuthentication.call(this, credentialType, options); -} diff --git a/nodes/GithubIssues/shared/utils.ts b/nodes/GithubIssues/shared/utils.ts deleted file mode 100644 index 2b91882..0000000 --- a/nodes/GithubIssues/shared/utils.ts +++ /dev/null @@ -1,14 +0,0 @@ -export function parseLinkHeader(header?: string): { [rel: string]: string } { - const links: { [rel: string]: string } = {}; - - for (const part of header?.split(',') ?? []) { - const section = part.trim(); - const match = section.match(/^<([^>]+)>\s*;\s*rel="?([^"]+)"?/); - if (match) { - const [, url, rel] = match; - links[rel] = url; - } - } - - return links; -} diff --git a/package.json b/package.json index 3c272ec..7165a10 100644 --- a/package.json +++ b/package.json @@ -30,13 +30,9 @@ "n8n": { "n8nNodesApiVersion": 1, "strict": true, - "credentials": [ - "dist/credentials/GithubIssuesApi.credentials.js", - "dist/credentials/GithubIssuesOAuth2Api.credentials.js" - ], + "credentials": [], "nodes": [ - "dist/nodes/GithubIssues/GithubIssues.node.js", - "dist/nodes/Example/Example.node.js" + "dist/nodes/FormidableForms/FormidableFormsTrigger.node.js" ] }, "devDependencies": { From c8a8879914a5052942f3c03f3acbf66f62d6bf26 Mon Sep 17 00:00:00 2001 From: Truong Giang Date: Thu, 13 Nov 2025 16:48:59 +0700 Subject: [PATCH 5/5] Fix error when running lint --- nodes/FormidableForms/FormidableFormsTrigger.node.ts | 12 ++++++++---- package.json | 6 +++--- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/nodes/FormidableForms/FormidableFormsTrigger.node.ts b/nodes/FormidableForms/FormidableFormsTrigger.node.ts index afd17c3..95345ed 100644 --- a/nodes/FormidableForms/FormidableFormsTrigger.node.ts +++ b/nodes/FormidableForms/FormidableFormsTrigger.node.ts @@ -15,6 +15,7 @@ export class FormidableFormsTrigger implements INodeType { version: 1, subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}', description: 'Start a workflow when a Formidable Forms form action triggered', + usableAsTool: true, defaults: { name: 'Formidable Forms', }, @@ -51,6 +52,9 @@ export class FormidableFormsTrigger implements INodeType { displayName: 'Token', name: 'token', type: 'string', + typeOptions: { + password: true, + }, noDataExpression: true, default: '', displayOptions: { @@ -65,13 +69,12 @@ export class FormidableFormsTrigger implements INodeType { async webhook(this: IWebhookFunctions): Promise { // Access the raw HTTP request from n8n's webhook context. const request = this.getRequestObject(); - const response = this.getResponseObject(); if ( ! request.body || ! request.body.token || request.body.token !== ( this.getNodeParameter( 'token' ) as string ) ) { - return showError( response, 403, 'Forbidden!' ); + return showError( this, 403, 'Forbidden!' ); } if ( ! request.body.event || ! request.body.mapping ) { - return showError( response, 400, 'Bad Request!' ); + return showError( this, 400, 'Bad Request!' ); } // Default: emit parsed JSON items for downstream nodes via helpers. @@ -85,7 +88,8 @@ export class FormidableFormsTrigger implements INodeType { } } -const showError = ( response: any, code: number, message: string ) => { +const showError = ( node: IWebhookFunctions, code: number, message: string ) => { + const response = node.getResponseObject(); response.status( code ).send( message ); return { noWebhookResponse: true, diff --git a/package.json b/package.json index 7165a10..528bc79 100644 --- a/package.json +++ b/package.json @@ -1,15 +1,15 @@ { "name": "n8n-nodes-formidable-forms", "version": "0.1.0", - "description": "", + "description": "Listen to the request from Formidable Forms", "license": "MIT", "homepage": "", "keywords": [ "n8n-community-node-package" ], "author": { - "name": "", - "email": "" + "name": "Strategy11", + "email": "steve@strategy11.com" }, "repository": { "type": "git",