diff --git a/docs/configuration.md b/docs/configuration.md index 8b5e2160c5..51473c0ef1 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -6,6 +6,32 @@ It is possible to change some of the n8n defaults via special environment variab The ones that currently exist are: +## Publish + +Sets how n8n should be made available. + +```bash +# The port n8n should be made available on +N8N_PORT=5678 + +# This ones are currently only important for the webhook URL creation. +# So if "WEBHOOK_TUNNEL_URL" got set they do get ignored. It is however +# encouraged to set them correctly anyway in case they will become +# important in the future. +N8N_PROTOCOL=https +N8N_HOST=n8n.example.com +``` + + +## Base URL + +Tells the frontend how to reach the REST API of the backend. + +```bash +export VUE_APP_URL_BASE_API="https://n8n.example.com/" +``` + + ## Execution Data Manual Runs n8n creates a random encryption key automatically on the first launch and saves @@ -99,3 +125,18 @@ user-folder via an environment variable. ```bash export N8N_USER_FOLDER="/home/jim/n8n" ``` + + +## Webhook URL + +The webhook URL will normally be created automatically by combining +`N8N_PROTOCOL`, `N8N_HOST` and `N8N_PORT`. If n8n runs, however, behind a +reverse proxy that would not work. Because n8n does for example run internally +on port 5678 but is exposed to the web via the reverse proxy on port 443. In +that case, it is important to set the webhook URL manually that it can be +displayed correctly in the Editor UI and even more important that the correct +webhook URLs get registred with external services. + +```bash +export WEBHOOK_TUNNEL_URL="https://n8n.example.com/" +``` diff --git a/packages/cli/package.json b/packages/cli/package.json index ad4bde475b..a7798fab7a 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "n8n", - "version": "0.33.0", + "version": "0.34.0", "description": "n8n Workflow Automation Tool", "license": "SEE LICENSE IN LICENSE.md", "homepage": "https://n8n.io", @@ -90,8 +90,8 @@ "localtunnel": "^1.9.1", "mongodb": "^3.2.3", "n8n-core": "~0.14.0", - "n8n-editor-ui": "~0.24.0", - "n8n-nodes-base": "~0.28.0", + "n8n-editor-ui": "~0.25.0", + "n8n-nodes-base": "~0.29.0", "n8n-workflow": "~0.15.0", "open": "^6.1.0", "pg": "^7.11.0", diff --git a/packages/core/src/NodeExecuteFunctions.ts b/packages/core/src/NodeExecuteFunctions.ts index 58e1e320d8..344abf9f83 100644 --- a/packages/core/src/NodeExecuteFunctions.ts +++ b/packages/core/src/NodeExecuteFunctions.ts @@ -220,7 +220,13 @@ export function getNodeParameter(workflow: Workflow, runExecutionData: IRunExecu throw new Error(`Could not get parameter "${parameterName}"!`); } - const returnData = workflow.getParameterValue(value, runExecutionData, runIndex, itemIndex, node.name, connectionInputData); + let returnData; + try { + returnData = workflow.getParameterValue(value, runExecutionData, runIndex, itemIndex, node.name, connectionInputData); + } catch (e) { + e.message += ` [Error in parameter: "${parameterName}"]`; + throw e; + } return returnData; } diff --git a/packages/editor-ui/package.json b/packages/editor-ui/package.json index 911257526e..193e6cf8d8 100644 --- a/packages/editor-ui/package.json +++ b/packages/editor-ui/package.json @@ -1,6 +1,6 @@ { "name": "n8n-editor-ui", - "version": "0.24.0", + "version": "0.25.0", "description": "Workflow Editor UI for n8n", "license": "SEE LICENSE IN LICENSE.md", "homepage": "https://n8n.io", diff --git a/packages/nodes-base/credentials/FreshdeskApi.credentials.ts b/packages/nodes-base/credentials/FreshdeskApi.credentials.ts new file mode 100644 index 0000000000..3179abff1f --- /dev/null +++ b/packages/nodes-base/credentials/FreshdeskApi.credentials.ts @@ -0,0 +1,25 @@ +import { + ICredentialType, + NodePropertyTypes, +} from 'n8n-workflow'; + + +export class FreshdeskApi implements ICredentialType { + name = 'freshdeskApi'; + displayName = 'Freshdesk API'; + properties = [ + { + displayName: 'API Key', + name: 'apiKey', + type: 'string' as NodePropertyTypes, + default: '', + }, + { + displayName: 'Domain', + name: 'domain', + type: 'string' as NodePropertyTypes, + placeholder: 'https://domain.freshdesk.com', + default: '' + } + ]; +} diff --git a/packages/nodes-base/nodes/Freshdesk/Freshdesk.node.ts b/packages/nodes-base/nodes/Freshdesk/Freshdesk.node.ts new file mode 100644 index 0000000000..a6594ec768 --- /dev/null +++ b/packages/nodes-base/nodes/Freshdesk/Freshdesk.node.ts @@ -0,0 +1,787 @@ +import { + IExecuteSingleFunctions, +} from 'n8n-core'; +import { + IDataObject, + INodeTypeDescription, + INodeExecutionData, + INodeType, + ILoadOptionsFunctions, + INodePropertyOptions, +} from 'n8n-workflow'; +import { + freshdeskApiRequest, + validateJSON, + capitalize +} from './GenericFunctions'; + +enum Status { + Open = 2, + Pending = 3, + Resolved = 4, + Closed = 5, +} + +enum Priority { + Low = 1, + Medium = 2, + High = 3, + Urgent = 4 +} + +enum Source { + Email = 1, + Portal = 2, + Phone = 3, + Chat = 4, + Mobihelp = 5, + FeedbackWidget = 6, + OutboundEmail = 7 +} + +interface ICreateTicketBody { + name?: string; + requester_id?: number; + email?: string; + facebook_id?: string; + phone?: string; + twitter_id?: string; + unique_external_id?: string; + subject?: string | null; + type?: string; + status: Status; + priority: Priority; + description?: string; + responder_id?: number; + cc_emails?: [string]; + custom_fields?: IDataObject; + due_by?: string; + email_config_id?: number; + fr_due_by?: string; + group_id?: number; + product_id?: number; + source: Source; + tags?: [string]; + company_id?: number; +} + +export class Freshdesk implements INodeType { + + description: INodeTypeDescription = { + displayName: 'Freshdesk', + name: 'freshdesk', + icon: 'file:freshdesk.png', + group: ['output'], + version: 1, + subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}', + description: 'Consume Freshdesk API', + defaults: { + name: 'Freshdesk', + color: '#c02428', + }, + inputs: ['main'], + outputs: ['main'], + credentials: [ + { + name: 'freshdeskApi', + required: true, + } + ], + properties: [ + { + displayName: 'Resource', + name: 'resource', + type: 'options', + required: true, + options: [ + { + name: 'Ticket', + value: 'ticket', + }, + ], + default: 'ticket', + description: 'The resource to operate on.', + }, + { + displayName: 'Operation', + name: 'operation', + type: 'options', + required: true, + displayOptions: { + show: { + resource: [ + 'ticket', + ] + }, + }, + options: [ + { + name: 'Create', + value: 'create', + description: 'Create a new ticket', + } + ], + default: 'create', + description: 'The operation to perform.', + }, + { + displayName: 'Requester Identification', + name: 'requester', + type: 'options', + required: true, + displayOptions: { + show: { + resource: [ + 'ticket', + ], + operation: [ + 'create' + ] + }, + }, + options: [ + { + name: 'Requester Id', + value: 'requesterId', + description: `User ID of the requester. For existing contacts, the requester_id can be passed instead of the requester's email.`, + }, + { + name: 'Email', + value: 'email', + description: `Email address of the requester. If no contact exists with this email address in Freshdesk, it will be added as a new contact.`, + }, + { + name: 'Facebook Id', + value: 'facebookId', + description: `Facebook ID of the requester. If no contact exists with this facebook_id, then a new contact will be created.`, + }, + { + name: 'Phone', + value: 'phone', + description: `Phone number of the requester. If no contact exists with this phone number in Freshdesk, it will be added as a new contact. If the phone number is set and the email address is not, then the name attribute is mandatory.`, + }, + { + name: 'Twitter Id', + value: 'twitterId', + description: `Twitter handle of the requester. If no contact exists with this handle in Freshdesk, it will be added as a new contact.`, + }, + { + name: 'Unique External Id', + value: 'uniqueExternalId', + description: `External ID of the requester. If no contact exists with this external ID in Freshdesk, they will be added as a new contact.`, + }, + ], + default: 'requesterId', + description: 'Requester Identification', + }, + { + displayName: 'Value', + name: 'requesterIdentificationValue', + type: 'string', + required: true, + displayOptions: { + show: { + resource: [ + 'ticket', + ], + operation: [ + 'create' + ] + }, + }, + default: '', + description: `Value of the identification selected `, + }, + { + displayName: 'Status', + name: 'status', + type: 'options', + required: true, + displayOptions: { + show: { + resource: [ + 'ticket', + ], + operation: [ + 'create' + ] + }, + }, + options: [ + { + name: 'Open', + value: 'open', + }, + { + name: 'Pending', + value: 'pending', + }, + { + name: 'Resolved', + value: 'resolved', + }, + { + name: 'Closed', + value: 'closed', + } + ], + default: 'pending', + description: 'Status', + }, + { + displayName: 'Priority', + name: 'priority', + type: 'options', + required: true, + displayOptions: { + show: { + resource: [ + 'ticket', + ], + operation: [ + 'create' + ] + }, + }, + options: [ + { + name: 'Low', + value: 'low', + }, + { + name: 'Medium', + value: 'medium', + }, + { + name: 'High', + value: 'high', + }, + { + name: 'Urgent', + value: 'urgent', + } + ], + default: 'low', + description: 'Priority', + }, + { + displayName: 'Source', + name: 'source', + type: 'options', + required: true, + displayOptions: { + show: { + resource: [ + 'ticket', + ], + operation: [ + 'create' + ] + }, + }, + options: [ + { + name: 'Email', + value: 'email', + }, + { + name: 'Portal', + value: 'portal', + }, + { + name: 'Phone', + value: 'phone', + }, + { + name: 'Chat', + value: 'chat', + }, + { + name: 'Mobihelp', + value: 'mobileHelp', + }, + { + name: 'Feedback Widget', + value: 'feedbackWidget', + }, + { + name: 'Outbound Email', + value: 'OutboundEmail', + } + ], + default: 'portal', + description: 'The channel through which the ticket was created.', + }, + // { + // displayName: 'JSON Parameters', + // name: 'jsonParameters', + // type: 'boolean', + // default: false, + // description: '', + // displayOptions: { + // show: { + // resource: [ + // 'ticket' + // ], + // operation: [ + // 'create', + // ] + // }, + // }, + // }, + { + displayName: 'Options', + name: 'options', + type: 'collection', + placeholder: 'Add Option', + default: {}, + displayOptions: { + show: { + resource: [ + 'ticket' + ], + operation: [ + 'create' + ], + }, + }, + options: [ + { + displayName: 'Name', + name: 'name', + type: 'string', + default: '', + placeholder: '', + description: 'Name of the requester', + }, + { + displayName: 'Subject', + name: 'subject', + type: 'string', + default: '', + placeholder: '', + description: 'Subject of the ticket.', + }, + { + displayName: 'Type', + name: 'type', + type: 'options', + default: 'Question', + description: 'Helps categorize the ticket according to the different kinds of issues your support team deals with.', + options: [ + { + name: 'Question', + value: 'Question' + }, + { + name: 'Incident', + value: 'Incident' + }, + { + name: 'Problem', + value: 'Problem' + }, + { + name: 'Feature Request', + value: 'Feature Request' + }, + { + name: 'Refund', + value: 'Refund' + }, + ] + }, + { + displayName: 'Description', + name: 'description', + type: 'string', + required: false, + default: '', + typeOptions: { + rows: 5, + alwaysOpenEditWindow: true, + }, + description: 'HTML content of the ticket.', + }, + { + displayName: 'Agent', + name: 'agent', + type: 'options', + required: false, + default: '', + typeOptions: { + loadOptionsMethod: 'getAgents' + }, + description: 'ID of the agent to whom the ticket has been assigned', + }, + { + displayName: 'CC Emails', + name: 'ccEmails', + required: false, + type: 'string', + default: '', + description: `separated by , email addresses added in the 'cc' field of the incoming ticket email`, + }, + { + displayName: 'Tags', + name: 'tags', + required: false, + type: 'string', + default: '', + description: `separated by , tags that have been associated with the ticket`, + }, + { + displayName: 'Due By', + name: 'dueBy', + required: false, + type: 'dateTime', + default: '', + description: `Timestamp that denotes when the ticket is due to be resolved`, + }, + { + displayName: 'Email config Id', + name: 'emailConfigId', + type: 'number', + required: false, + default: '', + description: `ID of email config which is used for this ticket. (i.e., support@yourcompany.com/sales@yourcompany.com) + If product_id is given and email_config_id is not given, product's primary email_config_id will be set`, + }, + { + displayName: 'FR Due By', + name: 'frDueBy', + type: 'dateTime', + required: false, + default: '', + description: `Timestamp that denotes when the first response is due`, + }, + { + displayName: 'Group', + name: 'group', + required: false, + type: 'options', + default: '', + typeOptions: { + loadOptionsMethod: 'getGroups' + }, + description: `ID of the group to which the ticket has been assigned. The default value is the ID of the group that is associated with the given email_config_id`, + }, + { + displayName: 'Product', + name: 'product', + required: false, + type: 'options', + default: '', + typeOptions: { + loadOptionsMethod: 'getProducts' + }, + description: `ID of the product to which the ticket is associated. + It will be ignored if the email_config_id attribute is set in the request.`, + }, + { + displayName: 'Company', + name: 'company', + required: false, + type: 'options', + default: '', + typeOptions: { + loadOptionsMethod: 'getCompanies' + }, + description: `Company ID of the requester. This attribute can only be set if the Multiple Companies feature is enabled (Estate plan and above)`, + }, + ] + }, + // { + // displayName: 'Custom Fields', + // name: 'customFieldsUi', + // placeholder: 'Add Custom fields', + // type: 'fixedCollection', + // required: false, + // default: '', + // typeOptions: { + // multipleValues: true, + // }, + // displayOptions: { + // show: { + // resource: [ + // 'ticket' + // ], + // operation: [ + // 'create' + // ], + // jsonParameters: [ + // false, + // ], + // }, + // }, + // description: 'Key value pairs containing the names and values of custom fields.', + // options: [ + // { + // name: 'customFieldsValues', + // displayName: 'Custom fields', + // values: [ + // { + // displayName: 'Key', + // required: false, + // name: 'key', + // type: 'string', + // default: '', + // }, + // { + // displayName: 'Value', + // name: 'value', + // type: 'string', + // required: false, + // default: '', + // }, + // ], + // }, + // ], + // }, + // { + // displayName: 'Custom Fields', + // name: 'customFieldsJson', + // type: 'json', + // typeOptions: { + // alwaysOpenEditWindow: true, + // }, + // displayOptions: { + // show: { + // resource: [ + // 'ticket' + // ], + // operation: [ + // 'create' + // ], + // jsonParameters: [ + // true, + // ], + // }, + // }, + // default: '', + // required: false, + // placeholder: `{ + // "gadget":"Cold Welder" + // }`, + // description: 'Key value pairs containing the names and values of custom fields.', + // }, + ] + }; + + methods = { + loadOptions: { + // Get all the agents to display them to user so that he can + // select them easily + async getAgents(this: ILoadOptionsFunctions): Promise { + const returnData: INodePropertyOptions[] = []; + let agents; + try { + agents = await freshdeskApiRequest.call(this, '/agents', 'GET'); + } catch (err) { + throw new Error(`Freshdesk Error: ${err}`); + } + for (const agent of agents) { + const agentName = agent.contact.name; + const agentId = agent.id; + + returnData.push({ + name: agentName, + value: agentId, + }); + } + return returnData; + }, + + // Get all the groups to display them to user so that he can + // select them easily + async getGroups(this: ILoadOptionsFunctions): Promise { + const returnData: INodePropertyOptions[] = []; + let groups; + try { + groups = await freshdeskApiRequest.call(this, '/groups', 'GET'); + } catch (err) { + throw new Error(`Freshdesk Error: ${err}`); + } + for (const group of groups) { + const groupName = group.name; + const groupId = group.id; + + returnData.push({ + name: groupName, + value: groupId, + }); + } + return returnData; + }, + + // Get all the products to display them to user so that he can + // select them easily + async getProducts(this: ILoadOptionsFunctions): Promise { + const returnData: INodePropertyOptions[] = []; + let products; + try { + products = await freshdeskApiRequest.call(this, '/products', 'GET'); + } catch (err) { + throw new Error(`Freshdesk Error: ${err}`); + } + for (const product of products) { + const productName = product.name; + const productId = product.id; + + returnData.push({ + name: productName, + value: productId, + }); + } + return returnData; + }, + + // Get all the companies to display them to user so that he can + // select them easily + async getCompanies(this: ILoadOptionsFunctions): Promise { + const returnData: INodePropertyOptions[] = []; + let companies; + try { + companies = await freshdeskApiRequest.call(this, '/companies', 'GET'); + } catch (err) { + throw new Error(`Freshdesk Error: ${err}`); + } + for (const company of companies) { + const companyName = company.name; + const companyId = company.id; + + returnData.push({ + name: companyName, + value: companyId, + }); + } + return returnData; + }, + }, + }; + + async executeSingle(this: IExecuteSingleFunctions): Promise { + const resource = this.getNodeParameter('resource') as string; + const opeation = this.getNodeParameter('operation') as string; + let response; + + if (resource === 'ticket') { + if (opeation === 'create') { + const requester = this.getNodeParameter('requester') as string; + const value = this.getNodeParameter('requesterIdentificationValue') as string; + const status = this.getNodeParameter('status') as string; + const priority = this.getNodeParameter('priority') as string; + const source = this.getNodeParameter('source') as string; + const options = this.getNodeParameter('options') as IDataObject; + //const jsonActive = this.getNodeParameter('jsonParameters') as boolean; + + const body: ICreateTicketBody = { + // @ts-ignore + status: Status[capitalize(status)], + // @ts-ignore + priority: Priority[capitalize(priority)], + // @ts-ignore + source: Source[capitalize(source)] + }; + + if (requester === 'requesterId') { + // @ts-ignore + if (isNaN(value)) { + throw new Error('Requester Id must be a number'); + } + body.requester_id = parseInt(value, 10); + } else if (requester === 'email'){ + body.email = value; + } else if (requester === 'facebookId'){ + body.facebook_id = value; + } else if (requester === 'phone'){ + body.phone = value; + } else if (requester === 'twitterId'){ + body.twitter_id = value; + } else if (requester === 'uniqueExternalId'){ + body.unique_external_id = value; + } + + // if (!jsonActive) { + // const customFieldsUi = this.getNodeParameter('customFieldsUi') as IDataObject; + // if (Object.keys(customFieldsUi).length > 0) { + // const aux: IDataObject = {}; + // // @ts-ignore + // customFieldsUi.customFieldsValues.forEach( o => { + // aux[`${o.key}`] = o.value; + // return aux; + // }); + // body.custom_fields = aux; + // } else { + // body.custom_fields = validateJSON(this.getNodeParameter('customFielsJson') as string); + // } + + if (options.name) { + body.name = options.name as string; + } + + if (options.subject) { + body.subject = options.subject as string; + } else { + body.subject = 'null'; + } + + if (options.type) { + body.type = options.type as string; + } + + if (options.description) { + body.description = options.description as string; + } else { + body.description = 'null'; + } + + if (options.agent) { + body.responder_id = options.agent as number; + } + + if (options.company) { + body.company_id = options.company as number; + } + + if (options.product) { + body.product_id = options.product as number; + } + + if (options.group) { + body.group_id = options.group as number; + } + + if (options.frDueBy) { + body.fr_due_by = options.frDueBy as string; + } + + if (options.emailConfigId) { + body.email_config_id = options.emailConfigId as number; + } + + if (options.dueBy) { + body.due_by = options.dueBy as string; + } + + if (options.tags) { + body.tags = (options.tags as string).split(',') as [string]; + } + + if (options.ccEmails) { + body.cc_emails = (options.ccEmails as string).split(',') as [string]; + } + + try { + response = await freshdeskApiRequest.call(this, '/tickets', 'POST', body); + } catch (err) { + throw new Error(`Freskdesk Error: ${JSON.stringify(err)}`); + } + } + } + + return { + json: response + }; + } +} diff --git a/packages/nodes-base/nodes/Freshdesk/GenericFunctions.ts b/packages/nodes-base/nodes/Freshdesk/GenericFunctions.ts new file mode 100644 index 0000000000..ea25ccadc8 --- /dev/null +++ b/packages/nodes-base/nodes/Freshdesk/GenericFunctions.ts @@ -0,0 +1,66 @@ +import { OptionsWithUri } from 'request'; + +import { + IExecuteFunctions, + IHookFunctions, + ILoadOptionsFunctions, + IExecuteSingleFunctions, + BINARY_ENCODING +} from 'n8n-core'; + +import * as _ from 'lodash'; + +export async function freshdeskApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, resource: string, method: string, body: any = {}, headers?: object): Promise { // tslint:disable-line:no-any + + const credentials = this.getCredentials('freshdeskApi'); + + if (credentials === undefined) { + throw new Error('No credentials got returned!'); + } + + const apiKey = `${credentials.apiKey}:X`; + + const headerWithAuthentication = Object.assign({}, headers, { Authorization: `${Buffer.from(apiKey).toString(BINARY_ENCODING)}` }); + + const endpoint = 'freshdesk.com/api/v2/'; + + const options: OptionsWithUri = { + headers: headerWithAuthentication, + method, + body, + uri: `https://${credentials.domain}.${endpoint}${resource}`, + json: true + }; + + if (_.isEmpty(options.body)) { + delete options.body; + } + + try { + return await this.helpers.request!(options); + } catch (error) { + console.error(error); + + const errorMessage = error.response.body.message || error.response.body.Message; + + if (errorMessage !== undefined) { + throw errorMessage; + } + throw error.response.body; + } +} + +export function validateJSON(json: string | undefined): any { // tslint:disable-line:no-any + let result; + try { + result = JSON.parse(json!); + } catch (exception) { + result = []; + } + return result; +} + +export function capitalize (s: string) : string { + if (typeof s !== 'string') return ''; + return s.charAt(0).toUpperCase() + s.slice(1); +} diff --git a/packages/nodes-base/nodes/Freshdesk/freshdesk.png b/packages/nodes-base/nodes/Freshdesk/freshdesk.png new file mode 100644 index 0000000000..36692057e4 Binary files /dev/null and b/packages/nodes-base/nodes/Freshdesk/freshdesk.png differ diff --git a/packages/nodes-base/nodes/Gitlab/Gitlab.node.ts b/packages/nodes-base/nodes/Gitlab/Gitlab.node.ts index f7d20787c0..1f1d0b5199 100644 --- a/packages/nodes-base/nodes/Gitlab/Gitlab.node.ts +++ b/packages/nodes-base/nodes/Gitlab/Gitlab.node.ts @@ -259,6 +259,23 @@ export class Gitlab implements INodeType { }, description: 'The body of the issue.', }, + { + displayName: 'Due Date', + name: 'due_date', + type: 'dateTime', + displayOptions: { + show: { + operation: [ + 'create', + ], + resource: [ + 'issue', + ], + }, + }, + default: '', + description: 'Due Date for issue.', + }, { displayName: 'Labels', name: 'labels', @@ -318,6 +335,7 @@ export class Gitlab implements INodeType { ], }, + // ---------------------------------- // issue:createComment // ---------------------------------- @@ -409,7 +427,7 @@ export class Gitlab implements INodeType { }, { displayName: 'Body', - name: 'body', + name: 'description', type: 'string', typeOptions: { rows: 5, @@ -474,6 +492,13 @@ export class Gitlab implements INodeType { }, ], }, + { + displayName: 'Due Date', + name: 'due_date', + type: 'dateTime', + default: '', + description: 'Due Date for issue.', + }, ], }, @@ -829,6 +854,7 @@ export class Gitlab implements INodeType { body.title = this.getNodeParameter('title', i) as string; body.description = this.getNodeParameter('body', i) as string; + body.due_date = this.getNodeParameter('due_date', i) as string; const labels = this.getNodeParameter('labels', i) as IDataObject[]; const assigneeIds = this.getNodeParameter('assignee_ids', i) as IDataObject[]; diff --git a/packages/nodes-base/package.json b/packages/nodes-base/package.json index 45f5a36615..07b986b4d7 100644 --- a/packages/nodes-base/package.json +++ b/packages/nodes-base/package.json @@ -1,6 +1,6 @@ { "name": "n8n-nodes-base", - "version": "0.28.0", + "version": "0.29.0", "description": "Base nodes of n8n", "license": "SEE LICENSE IN LICENSE.md", "homepage": "https://n8n.io", @@ -33,6 +33,7 @@ "dist/credentials/Aws.credentials.js", "dist/credentials/ChargebeeApi.credentials.js", "dist/credentials/DropboxApi.credentials.js", + "dist/credentials/FreshdeskApi.credentials.js", "dist/credentials/GithubApi.credentials.js", "dist/credentials/GitlabApi.credentials.js", "dist/credentials/GoogleApi.credentials.js", @@ -42,6 +43,7 @@ "dist/credentials/Imap.credentials.js", "dist/credentials/LinkFishApi.credentials.js", "dist/credentials/MailgunApi.credentials.js", + "dist/credentials/MandrillApi.credentials.js", "dist/credentials/MattermostApi.credentials.js", "dist/credentials/MongoDb.credentials.js", "dist/credentials/NextCloudApi.credentials.js", @@ -49,16 +51,18 @@ "dist/credentials/PipedriveApi.credentials.js", "dist/credentials/Postgres.credentials.js", "dist/credentials/Redis.credentials.js", + "dist/credentials/RocketchatApi.credentials.js", "dist/credentials/SlackApi.credentials.js", "dist/credentials/Smtp.credentials.js", "dist/credentials/StripeApi.credentials.js", "dist/credentials/TelegramApi.credentials.js", + "dist/credentials/TodoistApi.credentials.js", "dist/credentials/TrelloApi.credentials.js", "dist/credentials/TwilioApi.credentials.js", "dist/credentials/TypeformApi.credentials.js", "dist/credentials/MandrillApi.credentials.js", "dist/credentials/TodoistApi.credentials.js", - "dist/credentials/RocketchatApi.credentials.js" + "dist/credentials/TypeformApi.credentials.js" ], "nodes": [ "dist/nodes/ActiveCampaign/ActiveCampaign.node.js", @@ -79,6 +83,7 @@ "dist/nodes/EmailSend.node.js", "dist/nodes/ErrorTrigger.node.js", "dist/nodes/ExecuteCommand.node.js", + "dist/nodes/Freshdesk/Freshdesk.node.js", "dist/nodes/Function.node.js", "dist/nodes/FunctionItem.node.js", "dist/nodes/Github/Github.node.js", @@ -93,6 +98,7 @@ "dist/nodes/Interval.node.js", "dist/nodes/LinkFish/LinkFish.node.js", "dist/nodes/Mailgun/Mailgun.node.js", + "dist/nodes/Mandrill/Mandrill.node.js", "dist/nodes/Mattermost/Mattermost.node.js", "dist/nodes/Merge.node.js", "dist/nodes/MoveBinaryData.node.js", @@ -103,6 +109,7 @@ "dist/nodes/Pipedrive/Pipedrive.node.js", "dist/nodes/Pipedrive/PipedriveTrigger.node.js", "dist/nodes/Postgres/Postgres.node.js", + "dist/nodes/Rocketchat/Rocketchat.node.js", "dist/nodes/ReadBinaryFile.node.js", "dist/nodes/ReadBinaryFiles.node.js", "dist/nodes/Redis/Redis.node.js", @@ -117,6 +124,7 @@ "dist/nodes/Stripe/StripeTrigger.node.js", "dist/nodes/Telegram/Telegram.node.js", "dist/nodes/Telegram/TelegramTrigger.node.js", + "dist/nodes/Todoist/Todoist.node.js", "dist/nodes/Trello/Trello.node.js", "dist/nodes/Trello/TrelloTrigger.node.js", "dist/nodes/Twilio/Twilio.node.js", @@ -126,7 +134,7 @@ "dist/nodes/Xml.node.js", "dist/nodes/Mandrill/Mandrill.node.js", "dist/nodes/Todoist/Todoist.node.js", - "dist/nodes/Rocketchat/Rocketchat.node.js" + "dist/nodes/Xml.node.js" ] }, "devDependencies": {