@traien/n8n-nodes-espocrm
Version:
n8n integration with EspoCRM
277 lines • 10.7 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.EspoCRMTrigger = void 0;
const n8n_workflow_1 = require("n8n-workflow");
const crypto_1 = require("crypto");
class EspoCRMTrigger {
constructor() {
this.description = {
displayName: 'EspoCRM Trigger',
name: 'espoCrmTrigger',
icon: 'file:espocrm-trigger.svg',
group: ['trigger'],
version: 1,
subtitle: '={{$parameter["eventType"] + ": " + $parameter["entityType"]}}',
description: 'Handle EspoCRM Webhooks',
defaults: {
name: 'EspoCRM Trigger',
},
inputs: [],
outputs: ['main'],
documentationUrl: 'https://docs.espocrm.com/administration/webhooks',
credentials: [
{
name: 'espoCRMApi',
required: true,
},
],
webhooks: [
{
name: 'default',
httpMethod: 'POST',
responseMode: 'onReceived',
path: 'webhook',
},
],
properties: [
{
displayName: 'Event Type',
name: 'eventType',
type: 'options',
options: [
{
name: 'Record Created',
value: 'create',
description: 'Triggered when a record is created',
},
{
name: 'Record Updated',
value: 'update',
description: 'Triggered when a record is updated',
},
{
name: 'Record Deleted',
value: 'delete',
description: 'Triggered when a record is deleted',
},
{
name: 'Field Updated',
value: 'fieldUpdate',
description: 'Triggered when a specific field is updated',
},
],
default: 'create',
required: true,
description: 'Type of event to listen for',
},
{
displayName: 'Entity Type',
name: 'entityType',
type: 'string',
default: '',
required: true,
description: 'Type of entity to monitor (e.g., Contact, Account, Lead)',
placeholder: 'Account',
},
{
displayName: 'Field Name',
name: 'fieldName',
type: 'string',
default: '',
placeholder: 'assignedUserId',
description: 'Name of the field to monitor for updates',
displayOptions: {
show: {
eventType: ['fieldUpdate'],
},
},
},
{
displayName: 'Verification',
name: 'verification',
type: 'boolean',
default: true,
description: 'Whether to verify the webhook signature to ensure it comes from EspoCRM',
},
],
};
}
async webhookCreate() {
const webhookUrl = this.getNodeWebhookUrl('default');
const webhookData = this.getWorkflowStaticData('node');
const eventType = this.getNodeParameter('eventType');
const entityType = this.getNodeParameter('entityType');
const credentials = await this.getCredentials('espoCRMApi');
let eventName = `${entityType}.${eventType}`;
if (eventType === 'fieldUpdate') {
const fieldName = this.getNodeParameter('fieldName');
if (!fieldName) {
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Field name is required for field update events');
}
eventName += `.${fieldName}`;
}
const options = {
method: 'POST',
url: '/Webhook',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: {
event: eventName,
url: webhookUrl,
},
};
if (credentials.authType === 'hmac' && credentials.secretKey) {
const hmacString = 'POST /Webhook';
const hmac = (0, crypto_1.createHmac)('sha256', credentials.secretKey);
hmac.update(hmacString);
const signature = hmac.digest('base64');
const authPart = Buffer.from(credentials.apiKey + ':').toString('base64') + signature;
options.headers['X-Hmac-Authorization'] = authPart;
}
else {
options.headers['X-Api-Key'] = credentials.apiKey;
}
try {
const response = await this.helpers.httpRequest({
baseURL: `${credentials.baseUrl}/api/v1`,
...options,
});
if (response.id && response.secretKey) {
webhookData.webhookId = response.id;
webhookData.secretKey = response.secretKey;
return true;
}
else {
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Failed to create webhook in EspoCRM: Invalid response');
}
}
catch (error) {
if (error.response && error.response.body) {
const errorMessage = error.response.body.message || error.message;
const statusCode = error.statusCode;
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `EspoCRM API error: ${errorMessage}. Status: ${statusCode}`);
}
throw error;
}
}
async webhookDelete() {
const webhookData = this.getWorkflowStaticData('node');
if (!webhookData.webhookId) {
return true;
}
const credentials = await this.getCredentials('espoCRMApi');
const options = {
method: 'DELETE',
url: `/Webhook/${webhookData.webhookId}`,
headers: {
'Accept': 'application/json',
},
};
if (credentials.authType === 'hmac' && credentials.secretKey) {
const hmacString = `DELETE /Webhook/${webhookData.webhookId}`;
const hmac = (0, crypto_1.createHmac)('sha256', credentials.secretKey);
hmac.update(hmacString);
const signature = hmac.digest('base64');
const authPart = Buffer.from(credentials.apiKey + ':').toString('base64') + signature;
options.headers['X-Hmac-Authorization'] = authPart;
}
else {
options.headers['X-Api-Key'] = credentials.apiKey;
}
try {
await this.helpers.httpRequest({
baseURL: `${credentials.baseUrl}/api/v1`,
...options,
});
delete webhookData.webhookId;
delete webhookData.secretKey;
return true;
}
catch (error) {
if (error.statusCode === 410 || error.statusCode === 404) {
delete webhookData.webhookId;
delete webhookData.secretKey;
return true;
}
if (error.response && error.response.body) {
const errorMessage = error.response.body.message || error.message;
const statusCode = error.statusCode;
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `EspoCRM API error: ${errorMessage}. Status: ${statusCode}`);
}
throw error;
}
}
async webhook() {
const webhookData = this.getWorkflowStaticData('node');
const bodyData = this.getBodyData();
const headerData = this.getHeaderData();
const verification = this.getNodeParameter('verification');
if (verification && webhookData.secretKey && webhookData.webhookId) {
const signature = headerData.signature || headerData['x-signature'];
if (!signature) {
return {
webhookResponse: {
body: { error: 'Signature missing' },
statusCode: 401,
},
};
}
try {
const payload = JSON.stringify(bodyData);
const calculatedSignature = Buffer.from(`${webhookData.webhookId}:${(0, crypto_1.createHmac)('sha256', webhookData.secretKey).update(payload).digest('hex')}`).toString('base64');
if (signature !== calculatedSignature) {
return {
webhookResponse: {
body: { error: 'Invalid signature' },
statusCode: 401,
},
};
}
}
catch (error) {
return {
webhookResponse: {
body: { error: 'Failed to verify signature' },
statusCode: 500,
},
};
}
}
if (Array.isArray(bodyData)) {
const returnData = [];
for (const item of bodyData) {
returnData.push({
json: item,
pairedItem: {
item: 0,
},
});
}
return {
workflowData: [
[
...returnData,
],
],
};
}
else {
return {
workflowData: [
[
{
json: bodyData,
pairedItem: {
item: 0,
},
},
],
],
};
}
}
}
exports.EspoCRMTrigger = EspoCRMTrigger;
//# sourceMappingURL=EspoCRMTrigger.node.js.map