diff --git a/README.md b/README.md index c672021..0be793b 100644 --- a/README.md +++ b/README.md @@ -1,48 +1,57 @@ -![Banner image](https://user-images.githubusercontent.com/10284570/173569848-c624317f-42b1-45a6-ab09-f0ea3c247648.png) +# Outgrow Trigger Node for n8n -# n8n-nodes-starter +[![n8n Community Node](https://img.shields.io/badge/n8n-Community%20Node-green.svg)](https://n8n.io/integrations) -This repo contains example nodes to help you get started building your own custom integrations for [n8n](https://n8n.io). It includes the node linter and other dependencies. +Trigger node that fetches leads from Outgrow calculators at configurable intervals. -To make your custom node available to the community, you must create it as an npm package, and [submit it to the npm registry](https://docs.npmjs.com/packages-and-modules/contributing-packages-to-the-registry). +![Outgrow Trigger Node Screenshot](./outgrow-node-screenshot.png) *(Optional: Add screenshot later)* -If you would like your node to be available on n8n cloud you can also [submit your node for verification](https://docs.n8n.io/integrations/creating-nodes/deploy/submit-community-nodes/). +## Features + +- 🕒 **Polling API**: Checks for new leads at customizable intervals (default: 5 minutes) +- 📋 **Calculator Selection**: Dynamic dropdown of available calculators +- 🔔 **Smart Notifications**: Clear "no leads" messages in the UI +- ⚙️ **Manual Trigger**: Instant API calls for testing ## Prerequisites -You need the following installed on your development machine: +- Outgrow account with API access +- API key from [Outgrow Settings](https://app.outgrow.co/settings/api) -* [git](https://git-scm.com/downloads) -* Node.js and npm. Minimum version Node 20. You can find instructions on how to install both using nvm (Node Version Manager) for Linux, Mac, and WSL [here](https://github.com/nvm-sh/nvm). For Windows users, refer to Microsoft's guide to [Install NodeJS on Windows](https://docs.microsoft.com/en-us/windows/dev-environment/javascript/nodejs-on-windows). -* Install n8n with: - ``` - npm install n8n -g - ``` -* Recommended: follow n8n's guide to [set up your development environment](https://docs.n8n.io/integrations/creating-nodes/build/node-development-environment/). +## Installation -## Using this starter +1. Add the node to your n8n instance +2. Configure Outgrow API credentials: + - Navigate to **Credentials > Add New > Outgrow API** + - Enter your API key -These are the basic steps for working with the starter. For detailed guidance on creating and publishing nodes, refer to the [documentation](https://docs.n8n.io/integrations/creating-nodes/). +## Node Configuration -1. [Generate a new repository](https://github.com/n8n-io/n8n-nodes-starter/generate) from this template repository. -2. Clone your new repo: - ``` - git clone https://github.com//.git - ``` -3. Run `npm i` to install dependencies. -4. Open the project in your editor. -5. Browse the examples in `/nodes` and `/credentials`. Modify the examples, or replace them with your own nodes. -6. Update the `package.json` to match your details. -7. Run `npm run lint` to check for errors or `npm run lintfix` to automatically fix errors when possible. -8. Test your node locally. Refer to [Run your node locally](https://docs.n8n.io/integrations/creating-nodes/test/run-node-locally/) for guidance. -9. Replace this README with documentation for your node. Use the [README_TEMPLATE](README_TEMPLATE.md) to get started. -10. Update the LICENSE file to use your details. -11. [Publish](https://docs.npmjs.com/packages-and-modules/contributing-packages-to-the-registry) your package to npm. +### Parameters +| Field | Required | Description | +|---------------------|----------|-----------------------------------------------------------------------------| +| **Calculator** | Yes | Select which Outgrow calculator to monitor | +| **Polling Interval**| No | Frequency (in minutes) to check for new leads (default: 5) | -## More information +## Usage Examples -Refer to our [documentation on creating nodes](https://docs.n8n.io/integrations/creating-nodes/) for detailed information on building your own nodes. - -## License - -[MIT](https://github.com/n8n-io/n8n-nodes-starter/blob/master/LICENSE.md) +### Basic Automation +```json +{ + "workflow": { + "nodes": [ + { + "parameters": { + "calcId": "{{CALCULATOR_ID}}", + "pollingInterval": 10 + }, + "name": "Outgrow Trigger", + "type": "outgrowTrigger", + "typeVersion": 1 + }, + { + // Connect to other nodes (Email, Slack, etc.) + } + ] + } +} \ No newline at end of file diff --git a/credentials/ExampleCredentialsApi.credentials.ts b/credentials/ExampleCredentialsApi.credentials.ts deleted file mode 100644 index 79a6ac2..0000000 --- a/credentials/ExampleCredentialsApi.credentials.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { - IAuthenticateGeneric, - ICredentialTestRequest, - ICredentialType, - INodeProperties, -} from 'n8n-workflow'; - -export class ExampleCredentialsApi implements ICredentialType { - name = 'exampleCredentialsApi'; - displayName = 'Example Credentials API'; - - documentationUrl = 'https://your-docs-url'; - - properties: INodeProperties[] = [ - // The credentials to get from user and save encrypted. - // Properties can be defined exactly in the same way - // as node properties. - { - displayName: 'User Name', - name: 'username', - type: 'string', - default: '', - }, - { - displayName: 'Password', - name: 'password', - type: 'string', - typeOptions: { - password: true, - }, - default: '', - }, - ]; - - // This credential is currently not used by any node directly - // but the HTTP Request node can use it to make requests. - // The credential is also testable due to the `test` property below - authenticate: IAuthenticateGeneric = { - type: 'generic', - properties: { - auth: { - username: '={{ $credentials.username }}', - password: '={{ $credentials.password }}', - }, - qs: { - // Send this as part of the query string - n8n: 'rocks', - }, - }, - }; - - // The block below tells how this credential can be tested - test: ICredentialTestRequest = { - request: { - baseURL: 'https://example.com/', - url: '', - }, - }; -} diff --git a/credentials/HttpBinApi.credentials.ts b/credentials/HttpBinApi.credentials.ts deleted file mode 100644 index b9772e4..0000000 --- a/credentials/HttpBinApi.credentials.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { - IAuthenticateGeneric, - ICredentialTestRequest, - ICredentialType, - INodeProperties, -} from 'n8n-workflow'; - -export class HttpBinApi implements ICredentialType { - name = 'httpbinApi'; - displayName = 'HttpBin API'; - documentationUrl = 'https://your-docs-url'; - properties: INodeProperties[] = [ - { - displayName: 'Token', - name: 'token', - type: 'string', - default: '', - typeOptions: { - password: true, - } - }, - { - displayName: 'Domain', - name: 'domain', - type: 'string', - default: 'https://httpbin.org', - }, - ]; - - // This allows the credential to be used by other parts of n8n - // stating how this credential is injected as part of the request - // An example is the Http Request node that can make generic calls - // reusing this credential - authenticate: IAuthenticateGeneric = { - type: 'generic', - properties: { - headers: { - Authorization: '={{"Bearer " + $credentials.token}}', - }, - }, - }; - - // The block below tells how this credential can be tested - test: ICredentialTestRequest = { - request: { - baseURL: '={{$credentials?.domain}}', - url: '/bearer', - }, - }; -} diff --git a/credentials/outgrowApi.credentials.ts b/credentials/outgrowApi.credentials.ts new file mode 100644 index 0000000..3c4ef05 --- /dev/null +++ b/credentials/outgrowApi.credentials.ts @@ -0,0 +1,22 @@ +import { + ICredentialType, + INodeProperties, +} from 'n8n-workflow'; + +export class outgrowApi implements ICredentialType { + name = 'outgrowApi'; // 👈 Must match what you use in the node + displayName = 'Outgrow API'; + documentationUrl = 'https://docs.n8n.io/integrations/creating-nodes/build/credentials/'; + properties: INodeProperties[] = [ + { + displayName: 'API Key', + name: 'apiKey', + type: 'string', + default: '', + required: true, + description: 'Your Outgrow API key', + }, + ]; + + // No built-in auth here since we inject key manually in node code +} \ No newline at end of file diff --git a/nodes/ExampleNode/ExampleNode.node.ts b/nodes/ExampleNode/ExampleNode.node.ts deleted file mode 100644 index 1e0c9f6..0000000 --- a/nodes/ExampleNode/ExampleNode.node.ts +++ /dev/null @@ -1,77 +0,0 @@ -import type { - IExecuteFunctions, - INodeExecutionData, - INodeType, - INodeTypeDescription, -} from 'n8n-workflow'; -import { NodeConnectionType, NodeOperationError } from 'n8n-workflow'; - -export class ExampleNode implements INodeType { - description: INodeTypeDescription = { - displayName: 'Example Node', - name: 'exampleNode', - group: ['transform'], - version: 1, - description: 'Basic Example Node', - defaults: { - name: 'Example Node', - }, - inputs: [NodeConnectionType.Main], - outputs: [NodeConnectionType.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/HttpBin/HttpBin.node.json b/nodes/HttpBin/HttpBin.node.json deleted file mode 100644 index 2e5596c..0000000 --- a/nodes/HttpBin/HttpBin.node.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "node": "n8n-nodes-base.httpbin", - "nodeVersion": "1.0", - "codexVersion": "1.0", - "categories": ["Development", "Developer Tools"], - "resources": { - "credentialDocumentation": [ - { - "url": "http://httpbin.org/#/Auth/get_bearer" - } - ], - "primaryDocumentation": [ - { - "url": "http://httpbin.org/" - } - ] - } -} diff --git a/nodes/HttpBin/HttpBin.node.ts b/nodes/HttpBin/HttpBin.node.ts deleted file mode 100644 index 0c7d5c2..0000000 --- a/nodes/HttpBin/HttpBin.node.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { INodeType, INodeTypeDescription, NodeConnectionType } from 'n8n-workflow'; -import { httpVerbFields, httpVerbOperations } from './HttpVerbDescription'; - -export class HttpBin implements INodeType { - description: INodeTypeDescription = { - displayName: 'HttpBin', - name: 'httpBin', - icon: { light: 'file:httpbin.svg', dark: 'file:httpbin.svg' }, - group: ['transform'], - version: 1, - subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}', - description: 'Interact with HttpBin API', - defaults: { - name: 'HttpBin', - }, - inputs: [NodeConnectionType.Main], - outputs: [NodeConnectionType.Main], - usableAsTool: true, - credentials: [ - { - name: 'httpbinApi', - required: false, - }, - ], - requestDefaults: { - baseURL: 'https://httpbin.org', - url: '', - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json', - }, - }, - /** - * In the properties array we have two mandatory options objects required - * - * [Resource & Operation] - * - * https://docs.n8n.io/integrations/creating-nodes/code/create-first-node/#resources-and-operations - * - * In our example, the operations are separated into their own file (HTTPVerbDescription.ts) - * to keep this class easy to read. - * - */ - properties: [ - { - displayName: 'Resource', - name: 'resource', - type: 'options', - noDataExpression: true, - options: [ - { - name: 'HTTP Verb', - value: 'httpVerb', - }, - ], - default: 'httpVerb', - }, - - ...httpVerbOperations, - ...httpVerbFields, - ], - }; -} diff --git a/nodes/HttpBin/HttpVerbDescription.ts b/nodes/HttpBin/HttpVerbDescription.ts deleted file mode 100644 index fc8aac4..0000000 --- a/nodes/HttpBin/HttpVerbDescription.ts +++ /dev/null @@ -1,250 +0,0 @@ -import { INodeProperties } from 'n8n-workflow'; - -// When the resource `httpVerb` is selected, this `operation` parameter will be shown. -export const httpVerbOperations: INodeProperties[] = [ - { - displayName: 'Operation', - name: 'operation', - type: 'options', - noDataExpression: true, - - displayOptions: { - show: { - resource: ['httpVerb'], - }, - }, - options: [ - { - name: 'GET', - value: 'get', - description: 'Perform a GET request', - action: 'Perform a GET request', - routing: { - request: { - method: 'GET', - url: '/get', - }, - }, - }, - { - name: 'DELETE', - value: 'delete', - description: 'Perform a DELETE request', - action: 'Perform a DELETE request', - routing: { - request: { - method: 'DELETE', - url: '/delete', - }, - }, - }, - ], - default: 'get', - }, -]; - -// Here we define what to show when the `get` operation is selected. -// We do that by adding `operation: ["get"]` to `displayOptions.show` -const getOperation: INodeProperties[] = [ - { - displayName: 'Type of Data', - name: 'typeofData', - default: 'queryParameter', - description: 'Select type of data to send [Query Parameters]', - displayOptions: { - show: { - resource: ['httpVerb'], - operation: ['get'], - }, - }, - type: 'options', - options: [ - { - name: 'Query', - value: 'queryParameter', - }, - ], - required: true, - }, - { - displayName: 'Query Parameters', - name: 'arguments', - default: {}, - description: "The request's query parameters", - displayOptions: { - show: { - resource: ['httpVerb'], - operation: ['get'], - }, - }, - options: [ - { - name: 'keyvalue', - displayName: 'Key:Value', - values: [ - { - displayName: 'Key', - name: 'key', - type: 'string', - default: '', - required: true, - description: 'Key of query parameter', - }, - { - displayName: 'Value', - name: 'value', - type: 'string', - default: '', - routing: { - send: { - property: '={{$parent.key}}', - type: 'query', - }, - }, - required: true, - description: 'Value of query parameter', - }, - ], - }, - ], - type: 'fixedCollection', - typeOptions: { - multipleValues: true, - }, - }, -]; - -// Here we define what to show when the DELETE Operation is selected. -// We do that by adding `operation: ["delete"]` to `displayOptions.show` -const deleteOperation: INodeProperties[] = [ - { - displayName: 'Type of Data', - name: 'typeofData', - default: 'queryParameter', - description: 'Select type of data to send [Query Parameter Arguments, JSON-Body]', - displayOptions: { - show: { - resource: ['httpVerb'], - operation: ['delete'], - }, - }, - options: [ - { - name: 'Query', - value: 'queryParameter', - }, - { - name: 'JSON', - value: 'jsonData', - }, - ], - required: true, - type: 'options', - }, - { - displayName: 'Query Parameters', - name: 'arguments', - default: {}, - description: "The request's query parameters", - displayOptions: { - show: { - resource: ['httpVerb'], - operation: ['delete'], - typeofData: ['queryParameter'], - }, - }, - options: [ - { - name: 'keyvalue', - displayName: 'Key:Value', - values: [ - { - displayName: 'Key', - name: 'key', - type: 'string', - default: '', - required: true, - description: 'Key of query parameter', - }, - { - displayName: 'Value', - name: 'value', - type: 'string', - default: '', - routing: { - send: { - property: '={{$parent.key}}', - type: 'query', - }, - }, - required: true, - description: 'Value of query parameter', - }, - ], - }, - ], - type: 'fixedCollection', - typeOptions: { - multipleValues: true, - }, - }, - { - displayName: 'JSON Object', - name: 'arguments', - default: {}, - description: "The request's JSON properties", - displayOptions: { - show: { - resource: ['httpVerb'], - operation: ['delete'], - typeofData: ['jsonData'], - }, - }, - options: [ - { - name: 'keyvalue', - displayName: 'Key:Value', - values: [ - { - displayName: 'Key', - name: 'key', - type: 'string', - default: '', - required: true, - description: 'Key of JSON property', - }, - { - displayName: 'Value', - name: 'value', - type: 'string', - default: '', - routing: { - send: { - property: '={{$parent.key}}', - type: 'body', - }, - }, - required: true, - description: 'Value of JSON property', - }, - ], - }, - ], - type: 'fixedCollection', - typeOptions: { - multipleValues: true, - }, - }, -]; - -export const httpVerbFields: INodeProperties[] = [ - /* -------------------------------------------------------------------------- */ - /* httpVerb:get */ - /* -------------------------------------------------------------------------- */ - ...getOperation, - - /* -------------------------------------------------------------------------- */ - /* httpVerb:delete */ - /* -------------------------------------------------------------------------- */ - ...deleteOperation, -]; diff --git a/nodes/HttpBin/httpbin.svg b/nodes/HttpBin/httpbin.svg deleted file mode 100644 index aee1de1..0000000 --- a/nodes/HttpBin/httpbin.svg +++ /dev/null @@ -1,18 +0,0 @@ - - - - diff --git a/nodes/outgrow/outgrow.node.json b/nodes/outgrow/outgrow.node.json new file mode 100644 index 0000000..bf32feb --- /dev/null +++ b/nodes/outgrow/outgrow.node.json @@ -0,0 +1,20 @@ +{ + "node": "n8n-nodes-base.outgrow", + "nodeVersion": "1.0", + "codexVersion": "1.0", + "categories": [ + "Miscellaneous" + ], + "resources": { + "credentialDocumentation": [ + { + "url": "" + } + ], + "primaryDocumentation": [ + { + "url": "" + } + ] + } +} \ No newline at end of file diff --git a/nodes/outgrow/outgrow.node.ts b/nodes/outgrow/outgrow.node.ts new file mode 100644 index 0000000..5785ad0 --- /dev/null +++ b/nodes/outgrow/outgrow.node.ts @@ -0,0 +1,145 @@ +import { + ITriggerFunctions, + INodeType, + INodeTypeDescription, + ILoadOptionsFunctions, + INodePropertyOptions, + ITriggerResponse, + NodeApiError, + NodeConnectionType, +} from 'n8n-workflow'; + +export class outgrow implements INodeType { + description: INodeTypeDescription = { + displayName: 'Outgrow Trigger', + name: 'outgrowTrigger', + icon: 'file:outgrow.svg', + group: ['trigger'], + version: 1, + subtitle: '={{$parameter["calcId"]}}', + description: 'Fetch leads from Outgrow calculators at regular intervals', + defaults: { + name: 'Outgrow Trigger', + }, + inputs: [], + outputs: [NodeConnectionType.Main], + credentials: [ + { + name: 'outgrowApi', + required: true, + }, + ], + properties: [ + { + displayName: 'Calculator', + name: 'calcId', + type: 'options', + required: true, + typeOptions: { + loadOptionsMethod: 'getCalculators', + }, + default: '', + description: 'Which Outgrow calculator to fetch leads from', + }, + { + displayName: 'Polling Interval (Minutes)', + name: 'pollingInterval', + type: 'number', + required: false, + default: 5, + description: 'How often (in minutes) to check for new leads', + }, + ], + }; + + methods = { + loadOptions: { + async getCalculators(this: ILoadOptionsFunctions): Promise { + const credentials = await this.getCredentials('outgrowApi'); + if (!credentials?.apiKey) { + throw new NodeApiError(this.getNode(), { + message: 'API Key is missing or invalid', + }); + } + + const url = `https://api-calc.outgrow.co/api/v1/get_cal/${credentials.apiKey}`; + try { + const response = await this.helpers.request({ method: 'GET', url }); + const calculators = JSON.parse(response); + + return calculators.map((calc: { id: string; calculator: string }) => ({ + name: calc.calculator, + value: calc.id, + })); + } catch (error) { + throw new NodeApiError(this.getNode(), error, { + message: 'Failed to load calculators', + }); + } + }, + }, + }; + + async trigger(this: ITriggerFunctions): Promise { + const credentials = await this.getCredentials('outgrowApi'); + if (!credentials?.apiKey) { + throw new NodeApiError(this.getNode(), { + message: 'API Key is missing or invalid', + }); + } + + const calcId = this.getNodeParameter('calcId', 0) as string; + if (!calcId) { + throw new NodeApiError(this.getNode(), { + message: 'No calculator selected', + }); + } + + const pollingInterval = (this.getNodeParameter('pollingInterval', 0) as number) * 60 * 1000; + const url = `https://api-calc.outgrow.co/api/v1/get_leads/${credentials.apiKey}/${calcId}`; + + const poll = async () => { + try { + const responseData = await this.helpers.request({ + method: 'GET', + url, + json: true, + }); + + if (responseData?.length > 0) { + this.emit([this.helpers.returnJsonArray(responseData)]); + } else { + // UI-friendly "no leads" response + this.emit([this.helpers.returnJsonArray([{ + status: 'no_data', + message: 'No new leads in the last 24 hours', + calculatorId: calcId, + timestamp: new Date().toISOString(), + }])]); + } + } catch (error) { + throw new NodeApiError(this.getNode(), error, { + message: 'Outgrow API Error', + }); + } + }; + + const mode = this.getMode(); + if (mode === 'manual') { + return { + manualTriggerFunction: async () => await poll(), + }; + } + + if (mode === 'trigger') { + const interval = setInterval(poll, pollingInterval); + await poll(); // Initial call + + return { + closeFunction: async () => clearInterval(interval), + }; + } + + return {}; + } +} \ No newline at end of file diff --git a/nodes/outgrow/outgrow.svg b/nodes/outgrow/outgrow.svg new file mode 100644 index 0000000..76931bf --- /dev/null +++ b/nodes/outgrow/outgrow.svg @@ -0,0 +1,3 @@ + + + diff --git a/package.json b/package.json index d0acf22..2eb9d9c 100644 --- a/package.json +++ b/package.json @@ -1,19 +1,16 @@ { - "name": "n8n-nodes-<...>", + "name": "n8n-nodes-outgrow", "version": "0.1.0", - "description": "", + "description": "![Banner image](https://user-images.githubusercontent.com/10284570/173569848-c624317f-42b1-45a6-ab09-f0ea3c247648.png)", "keywords": [ "n8n-community-node-package" ], "license": "MIT", - "homepage": "", - "author": { - "name": "", - "email": "" - }, + "homepage": "https://github.com/outgrow/n8n-nodes-outgrow#readme", + "author": "", "repository": { "type": "git", - "url": "https://github.com/<...>/n8n-nodes-<...>.git" + "url": "git+https://github.com/outgrow/n8n-nodes-outgrow.git" }, "engines": { "node": ">=20.15" @@ -33,12 +30,10 @@ "n8n": { "n8nNodesApiVersion": 1, "credentials": [ - "dist/credentials/ExampleCredentialsApi.credentials.js", - "dist/credentials/HttpBinApi.credentials.js" + "dist/credentials/outgrowApi.credentials.js" ], "nodes": [ - "dist/nodes/ExampleNode/ExampleNode.node.js", - "dist/nodes/HttpBin/HttpBin.node.js" + "dist/nodes/outgrow/outgrow.node.js" ] }, "devDependencies": { @@ -51,5 +46,325 @@ }, "peerDependencies": { "n8n-workflow": "*" + }, + "dependencies": { + "acorn": "^8.14.1", + "acorn-jsx": "^5.3.2", + "ajv": "^6.12.6", + "ansi-regex": "^5.0.1", + "ansi-styles": "^4.3.0", + "anymatch": "^3.1.3", + "argparse": "^2.0.1", + "array-each": "^1.0.1", + "array-slice": "^1.1.0", + "array-union": "^2.1.0", + "assert": "^2.1.0", + "ast-types": "^0.15.2", + "async-done": "^2.0.0", + "async-settle": "^2.0.0", + "asynckit": "^0.4.0", + "available-typed-arrays": "^1.0.7", + "axios": "^1.8.2", + "b4a": "^1.6.7", + "bach": "^2.0.1", + "balanced-match": "^1.0.2", + "bare-events": "^2.5.4", + "base64-js": "^1.5.1", + "binary-extensions": "^2.3.0", + "bl": "^5.1.0", + "brace-expansion": "^2.0.1", + "braces": "^3.0.3", + "buffer": "^6.0.3", + "call-bind": "^1.0.8", + "call-bind-apply-helpers": "^1.0.2", + "call-bound": "^1.0.4", + "callsites": "^3.1.0", + "camel-case": "^4.1.2", + "chalk": "^4.1.2", + "charenc": "^0.0.2", + "chokidar": "^3.6.0", + "cliui": "^7.0.4", + "clone": "^2.1.2", + "color-convert": "^2.0.1", + "color-name": "^1.1.4", + "combined-stream": "^1.0.8", + "concat-map": "^0.0.1", + "convert-source-map": "^2.0.0", + "copy-props": "^4.0.0", + "cross-spawn": "^7.0.6", + "crypt": "^0.0.2", + "debug": "^4.4.1", + "deep-equal": "^2.2.0", + "deep-is": "^0.1.4", + "define-data-property": "^1.1.4", + "define-properties": "^1.2.1", + "delayed-stream": "^1.0.0", + "detect-file": "^1.0.0", + "dir-glob": "^3.0.1", + "doctrine": "^3.0.0", + "dunder-proto": "^1.0.1", + "each-props": "^3.0.0", + "emoji-regex": "^8.0.0", + "end-of-stream": "^1.4.4", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-get-iterator": "^1.1.3", + "es-object-atoms": "^1.1.1", + "escalade": "^3.2.0", + "escape-string-regexp": "^4.0.0", + "eslint-config-riot": "^1.0.0", + "eslint-plugin-local": "^1.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^4.2.0", + "espree": "^9.6.1", + "esprima": "^4.0.1", + "esprima-next": "^5.8.4", + "esquery": "^1.6.0", + "esrecurse": "^4.3.0", + "estraverse": "^5.3.0", + "esutils": "^2.0.3", + "expand-tilde": "^2.0.2", + "extend": "^3.0.2", + "fast-deep-equal": "^3.1.3", + "fast-fifo": "^1.3.2", + "fast-glob": "^3.3.3", + "fast-json-stable-stringify": "^2.1.0", + "fast-levenshtein": "^2.0.6", + "fastest-levenshtein": "^1.0.16", + "fastq": "^1.19.1", + "file-entry-cache": "^6.0.1", + "fill-range": "^7.1.1", + "find-up": "^5.0.0", + "findup-sync": "^5.0.0", + "fined": "^2.0.0", + "flagged-respawn": "^2.0.0", + "flat-cache": "^3.2.0", + "flatted": "^3.3.3", + "follow-redirects": "^1.15.9", + "for-each": "^0.3.5", + "for-in": "^1.0.2", + "for-own": "^1.0.0", + "form-data": "^4.0.0", + "fs-mkdirp-stream": "^2.0.1", + "fs.realpath": "^1.0.0", + "function-bind": "^1.1.2", + "functions-have-names": "^1.2.3", + "get-caller-file": "^2.0.5", + "get-intrinsic": "^1.3.0", + "get-proto": "^1.0.1", + "glob": "^7.2.3", + "glob-parent": "^6.0.2", + "glob-stream": "^8.0.3", + "glob-watcher": "^6.0.0", + "global-modules": "^1.0.0", + "global-prefix": "^1.0.2", + "globals": "^13.24.0", + "globby": "^11.1.0", + "glogg": "^2.2.0", + "gopd": "^1.2.0", + "graceful-fs": "^4.2.11", + "graphemer": "^1.4.0", + "gulp-cli": "^3.1.0", + "gulplog": "^2.2.0", + "has-bigints": "^1.1.0", + "has-flag": "^4.0.0", + "has-property-descriptors": "^1.0.2", + "has-symbols": "^1.1.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2", + "homedir-polyfill": "^1.0.3", + "iconv-lite": "^0.6.3", + "ieee754": "^1.2.1", + "ignore": "^5.3.2", + "import-fresh": "^3.3.1", + "imurmurhash": "^0.1.4", + "indefinite": "^2.5.1", + "inflight": "^1.0.6", + "inherits": "^2.0.4", + "ini": "^1.3.8", + "internal-slot": "^1.1.0", + "interpret": "^3.1.1", + "is-absolute": "^1.0.0", + "is-arguments": "^1.2.0", + "is-array-buffer": "^3.0.5", + "is-bigint": "^1.1.0", + "is-binary-path": "^2.1.0", + "is-boolean-object": "^1.2.2", + "is-buffer": "^1.1.6", + "is-callable": "^1.2.7", + "is-core-module": "^2.16.1", + "is-date-object": "^1.1.0", + "is-extglob": "^2.1.1", + "is-fullwidth-code-point": "^3.0.0", + "is-generator-function": "^1.1.0", + "is-glob": "^4.0.3", + "is-map": "^2.0.3", + "is-nan": "^1.3.2", + "is-negated-glob": "^1.0.0", + "is-number": "^7.0.0", + "is-number-object": "^1.1.1", + "is-path-inside": "^3.0.3", + "is-plain-object": "^5.0.0", + "is-regex": "^1.2.1", + "is-relative": "^1.0.0", + "is-set": "^2.0.3", + "is-shared-array-buffer": "^1.0.4", + "is-string": "^1.1.1", + "is-symbol": "^1.1.1", + "is-typed-array": "^1.1.15", + "is-unc-path": "^1.0.0", + "is-valid-glob": "^1.0.0", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.4", + "is-windows": "^1.0.2", + "isarray": "^2.0.5", + "isexe": "^2.0.0", + "isobject": "^3.0.1", + "jmespath": "^0.16.0", + "js-base64": "^3.7.2", + "js-yaml": "^4.1.0", + "json-buffer": "^3.0.1", + "json-schema-traverse": "^0.4.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "jssha": "^3.3.1", + "keyv": "^4.5.4", + "last-run": "^2.0.0", + "lead": "^4.0.0", + "levn": "^0.4.1", + "liftoff": "^5.0.1", + "locate-path": "^6.0.0", + "lodash": "^4.17.21", + "lodash.merge": "^4.6.2", + "lower-case": "^2.0.2", + "luxon": "^3.4.4", + "map-cache": "^0.2.2", + "math-intrinsics": "^1.1.0", + "md5": "^2.3.0", + "merge2": "^1.4.1", + "micromatch": "^4.0.8", + "mime-db": "^1.52.0", + "mime-types": "^2.1.35", + "minimatch": "^9.0.5", + "ms": "^2.1.3", + "mute-stdout": "^2.0.0", + "n8n-workflow": "^1.82.0", + "natural-compare": "^1.4.0", + "no-case": "^3.0.4", + "normalize-path": "^3.0.0", + "now-and-later": "^3.0.0", + "object-inspect": "^1.13.4", + "object-is": "^1.1.6", + "object-keys": "^1.1.1", + "object.assign": "^4.1.7", + "object.defaults": "^1.1.0", + "object.pick": "^1.3.0", + "once": "^1.4.0", + "optionator": "^0.9.4", + "p-limit": "^3.1.0", + "p-locate": "^5.0.0", + "parent-module": "^1.0.1", + "parse-filepath": "^1.0.2", + "parse-passwd": "^1.0.0", + "pascal-case": "^3.1.2", + "path-exists": "^4.0.0", + "path-is-absolute": "^1.0.1", + "path-key": "^3.1.1", + "path-parse": "^1.0.7", + "path-root": "^0.1.1", + "path-root-regex": "^0.1.2", + "path-type": "^4.0.0", + "picomatch": "^2.3.1", + "pluralize": "^8.0.0", + "possible-typed-array-names": "^1.1.0", + "prelude-ls": "^1.2.1", + "proxy-from-env": "^1.1.0", + "punycode": "^2.3.1", + "queue-microtask": "^1.2.3", + "readable-stream": "^3.6.2", + "readdirp": "^3.6.0", + "recast": "^0.21.5", + "rechoir": "^0.8.0", + "regexp.prototype.flags": "^1.5.4", + "remove-trailing-separator": "^1.1.0", + "replace-ext": "^2.0.0", + "replace-homedir": "^2.0.0", + "require-directory": "^2.1.1", + "resolve": "^1.22.10", + "resolve-dir": "^1.0.1", + "resolve-from": "^4.0.0", + "resolve-options": "^2.0.0", + "reusify": "^1.1.0", + "rimraf": "^3.0.2", + "run-parallel": "^1.2.0", + "safe-buffer": "^5.2.1", + "safe-regex-test": "^1.1.0", + "safer-buffer": "^2.1.2", + "sax": "^1.4.1", + "semver": "^7.7.2", + "semver-greatest-satisfied-range": "^2.0.0", + "sentence-case": "^3.0.4", + "set-function-length": "^1.2.2", + "set-function-name": "^2.0.2", + "shebang-command": "^2.0.0", + "shebang-regex": "^3.0.0", + "side-channel": "^1.1.0", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2", + "slash": "^3.0.0", + "source-map": "^0.6.1", + "sparkles": "^2.1.0", + "stop-iteration-iterator": "^1.1.0", + "stream-composer": "^1.0.2", + "stream-exhaust": "^1.0.2", + "streamx": "^2.22.1", + "string-width": "^4.2.3", + "string_decoder": "^1.3.0", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.1", + "supports-color": "^7.2.0", + "supports-preserve-symlinks-flag": "^1.0.0", + "sver": "^1.8.4", + "teex": "^1.0.1", + "text-decoder": "^1.2.3", + "text-table": "^0.2.0", + "title-case": "^3.0.3", + "to-regex-range": "^5.0.1", + "to-through": "^3.0.0", + "transliteration": "^2.3.5", + "ts-api-utils": "^2.1.0", + "tslib": "^2.8.1", + "type-check": "^0.4.0", + "type-fest": "^0.20.2", + "unc-path-regex": "^0.1.2", + "undertaker": "^2.0.0", + "undertaker-registry": "^2.0.0", + "upper-case-first": "^2.0.2", + "uri-js": "^4.4.1", + "util": "^0.12.5", + "util-deprecate": "^1.0.2", + "v8flags": "^4.0.1", + "value-or-function": "^4.0.0", + "vinyl": "^3.0.1", + "vinyl-contents": "^2.0.0", + "vinyl-fs": "^4.0.2", + "vinyl-sourcemap": "^2.0.0", + "which": "^2.0.2", + "which-boxed-primitive": "^1.1.1", + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.19", + "word-wrap": "^1.2.5", + "wrap-ansi": "^7.0.0", + "wrappy": "^1.0.2", + "xml2js": "^0.6.2", + "xmlbuilder": "^11.0.1", + "y18n": "^5.0.8", + "yargs": "^16.2.0", + "yargs-parser": "^20.2.9", + "yocto-queue": "^0.1.0", + "zod": "^3.24.1" + }, + "bugs": { + "url": "https://github.com/outgrow/n8n-nodes-outgrow/issues" } -} \ No newline at end of file +} diff --git a/tsconfig.json b/tsconfig.json index 7469d24..7865ad8 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,8 +3,8 @@ "strict": true, "module": "commonjs", "moduleResolution": "node", - "target": "es2019", - "lib": ["es2019", "es2020", "es2022.error"], + "target": "ES2020", + "lib": ["es2019", "es2020", "DOM","es2022.error"], "removeComments": true, "useUnknownInCatchVariables": false, "forceConsistentCasingInFileNames": true,