Merge branch 'feature/rocketchat-node' of https://github.com/RicardoE105/n8n into feature/rocketchat-node

This commit is contained in:
Ricardo Espinoza 2019-11-11 00:02:49 -05:00
commit 05a0bd89ef
10 changed files with 968 additions and 9 deletions

View file

@ -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/"
```

View file

@ -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",

View file

@ -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;
}

View file

@ -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",

View file

@ -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: ''
}
];
}

View file

@ -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<INodePropertyOptions[]> {
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<INodePropertyOptions[]> {
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<INodePropertyOptions[]> {
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<INodePropertyOptions[]> {
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<INodeExecutionData> {
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
};
}
}

View file

@ -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<any> { // 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);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

View file

@ -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[];

View file

@ -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": {