@traien/n8n-nodes-espocrm
Version:
n8n integration with EspoCRM
226 lines • 10.9 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.espoApiRequest = espoApiRequest;
exports.espoApiRequestAllItems = espoApiRequestAllItems;
exports.espoApiRequestBinary = espoApiRequestBinary;
const n8n_workflow_1 = require("n8n-workflow");
const crypto = __importStar(require("crypto"));
function resolveBaseUrl(rawUrl) {
if (!rawUrl || rawUrl.trim() === '') {
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'EspoCRM credentials must include a Base URL such as "https://example.espocrm.com". Please check your EspoCRM API credentials configuration.');
}
const trimmed = rawUrl.trim();
if (trimmed.includes(' ') || trimmed.includes('\n') || trimmed.includes('\t')) {
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Invalid EspoCRM Base URL "${rawUrl}" - contains whitespace. Please remove any spaces, tabs, or newlines.`);
}
const withProtocol = /^https?:\/\//i.test(trimmed) ? trimmed : `https://${trimmed}`;
try {
const parsed = new URL(withProtocol);
const sanitizedPath = parsed.pathname.replace(/\/$/, '');
return `${parsed.origin}${sanitizedPath}`;
}
catch (error) {
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Invalid EspoCRM Base URL "${rawUrl}". Please include the protocol (e.g. https://your-instance.espocrm.com) and ensure the URL is properly formatted.`);
}
}
function joinUrl(base, path) {
if (!path) {
return base;
}
if (/^https?:\/\//i.test(path)) {
return path;
}
const normalizedBase = base.endsWith('/') ? base : `${base}/`;
const normalizedPath = path.replace(/^\/+/, '');
return `${normalizedBase}${normalizedPath}`;
}
async function espoApiRequest(method, endpoint, body = {}, qs = {}, uri, headers = {}) {
var _a, _b;
const credentials = await this.getCredentials('espoCRMApi');
if (!endpoint || typeof endpoint !== 'string') {
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Invalid endpoint parameter: "${endpoint}" (type: ${typeof endpoint})`);
}
if (endpoint.includes(' ') || endpoint.includes('\n') || endpoint.includes('\t')) {
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Endpoint contains whitespace: "${endpoint}". This will cause URL construction to fail.`);
}
const baseUrl = resolveBaseUrl.call(this, credentials.baseUrl);
const apiBaseUrl = `${baseUrl.replace(/\/$/, '')}/api/v1`;
const targetUrl = joinUrl(apiBaseUrl, uri !== null && uri !== void 0 ? uri : endpoint);
try {
new URL(targetUrl);
}
catch (error) {
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Invalid EspoCRM URL constructed. Final URL: ${targetUrl}. Please double-check the Base URL in your credentials and ensure entity/record IDs do not contain invalid characters.`);
}
const options = {
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
...headers,
},
method,
body: Object.keys(body).length === 0 ? undefined : body,
url: targetUrl,
qs,
};
if (credentials.authType === 'hmac' && credentials.secretKey) {
const hmacString = method + ' ' + endpoint;
const hmac = crypto.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(options);
return response;
}
catch (error) {
const err = error;
let friendlyMessage = `EspoCRM API request failed: ${method} ${endpoint}. ${(_a = err === null || err === void 0 ? void 0 : err.message) !== null && _a !== void 0 ? _a : ''}`;
if ((err === null || err === void 0 ? void 0 : err.code) === 'ERR_INVALID_URL' || /Invalid URL/i.test((_b = err === null || err === void 0 ? void 0 : err.message) !== null && _b !== void 0 ? _b : '')) {
friendlyMessage = `Invalid URL generated for EspoCRM request. Check your EspoCRM Base URL credential and ensure entity/record IDs do not contain invalid characters.`;
}
else if (err === null || err === void 0 ? void 0 : err.response) {
const errorMessage = (err.response.body && err.response.body.message) || err.message;
const statusCode = err.statusCode;
const statusReason = (err.response.headers && err.response.headers['x-status-reason']) || '';
friendlyMessage = `EspoCRM API error: ${method} ${endpoint}. Status: ${statusCode}${statusReason ? `. Reason: ${statusReason}` : ''}. ${errorMessage}`;
}
throw new n8n_workflow_1.NodeOperationError(this.getNode(), friendlyMessage);
}
}
async function espoApiRequestAllItems(method, endpoint, body = {}, qs = {}) {
const returnData = [];
let responseData;
qs.maxSize = 100;
qs.offset = 0;
do {
responseData = await espoApiRequest.call(this, method, endpoint, body, qs);
returnData.push.apply(returnData, responseData.list);
qs.offset = returnData.length;
} while (responseData.total !== undefined &&
responseData.list.length > 0 &&
returnData.length < responseData.total);
return returnData;
}
async function espoApiRequestBinary(method, endpoint, qs = {}, uri, headers = {}) {
var _a, _b, _c;
const credentials = await this.getCredentials('espoCRMApi');
const baseUrl = resolveBaseUrl.call(this, credentials.baseUrl);
const apiBaseUrl = `${baseUrl.replace(/\/$/, '')}/api/v1`;
const targetUrl = joinUrl(apiBaseUrl, uri !== null && uri !== void 0 ? uri : endpoint);
try {
new URL(targetUrl);
}
catch (error) {
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Invalid EspoCRM URL constructed. Final URL: ${targetUrl}. Please double-check the Base URL in your credentials and ensure entity/record IDs do not contain invalid characters.`);
}
const options = {
headers: {
'Accept': 'application/octet-stream,*/*',
...headers,
},
method,
url: targetUrl,
qs,
encoding: null,
};
if (credentials.authType === 'hmac' && credentials.secretKey) {
const hmacString = method + ' ' + endpoint;
const hmac = crypto.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({
...options,
returnFullResponse: true,
});
const resAny = response;
let body = (_a = resAny.body) !== null && _a !== void 0 ? _a : resAny.data;
let buffer;
if (Buffer.isBuffer(body)) {
buffer = body;
}
else if (body && typeof body.on === 'function') {
buffer = await new Promise((resolve, reject) => {
const chunks = [];
body.on('data', (chunk) => chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)));
body.on('end', () => resolve(Buffer.concat(chunks)));
body.on('error', (err) => reject(err));
});
}
else if (typeof body === 'string') {
buffer = Buffer.from(body);
}
else if (body == null) {
buffer = Buffer.alloc(0);
}
else {
try {
buffer = Buffer.from(body);
}
catch {
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Unexpected binary response type from EspoCRM');
}
}
return { data: buffer, headers: (response.headers || {}) };
}
catch (error) {
const err = error;
let friendlyMessage = `EspoCRM API binary request failed: ${method} ${endpoint}. ${(_b = err === null || err === void 0 ? void 0 : err.message) !== null && _b !== void 0 ? _b : ''}`;
if ((err === null || err === void 0 ? void 0 : err.code) === 'ERR_INVALID_URL' || /Invalid URL/i.test((_c = err === null || err === void 0 ? void 0 : err.message) !== null && _c !== void 0 ? _c : '')) {
friendlyMessage = `Invalid URL generated for EspoCRM binary request. Check your EspoCRM Base URL credential and ensure entity/record IDs do not contain invalid characters.`;
}
else if (err === null || err === void 0 ? void 0 : err.response) {
const errorMessage = (err.response.body && err.response.body.message) || err.message;
const statusCode = err.statusCode;
const statusReason = (err.response.headers && err.response.headers['x-status-reason']) || '';
friendlyMessage = `EspoCRM API binary error: ${method} ${endpoint}. Status: ${statusCode}${statusReason ? `. Reason: ${statusReason}` : ''}. ${errorMessage}`;
}
throw new n8n_workflow_1.NodeOperationError(this.getNode(), friendlyMessage);
}
}
//# sourceMappingURL=GenericFunctions.js.map