UNPKG

n8n-nodes-close-crm

Version:

N8N community node for Close CRM integration with comprehensive lead, opportunity, task, note, call management, and enhanced triggers for workflow automation

172 lines (171 loc) 7.39 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.closeApiRequest = closeApiRequest; exports.closeApiRequestAllItems = closeApiRequestAllItems; exports.convertPlainTextToHTML = convertPlainTextToHTML; const n8n_workflow_1 = require("n8n-workflow"); const n8n_workflow_2 = require("n8n-workflow"); async function closeApiRequest(method, resource, body = {}, qs = {}, option = {}) { var _a, _b, _c; const options = { headers: { 'Content-Type': 'application/json', }, method, qs, body, url: `https://api.close.com/api/v1${resource}`, json: true, }; // For PUT/PATCH requests, always send a body (at least empty JSON {}) // For other methods, delete empty body if (Object.keys(body).length === 0 && method !== 'PUT' && method !== 'PATCH') { delete options.body; } if (Object.keys(option).length !== 0) { Object.assign(options, option); } const credentials = await this.getCredentials('closeApi'); if (!credentials || !credentials.apiKey) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Close API credentials are missing or invalid'); } options.auth = { username: credentials.apiKey, password: '', }; try { return await this.helpers.httpRequest(options); } catch (error) { if (error.response) { const statusCode = error.response.status; const errorMessage = ((_a = error.response.data) === null || _a === void 0 ? void 0 : _a.error) || ((_b = error.response.data) === null || _b === void 0 ? void 0 : _b.message) || error.message; const errorDetails = ((_c = error.response.data) === null || _c === void 0 ? void 0 : _c.errors) || error.response.data; switch (statusCode) { case 400: throw new n8n_workflow_2.NodeApiError(this.getNode(), { message: `Bad Request: ${errorMessage}`, description: `The request was invalid. Details: ${JSON.stringify(errorDetails, null, 2)}\n\nRequest: ${method} ${resource}\nBody: ${JSON.stringify(body, null, 2)}`, }); case 401: throw new n8n_workflow_2.NodeApiError(this.getNode(), { message: 'Invalid API key. Please check your Close CRM credentials.', description: 'The API key provided is not valid or has expired.', }); case 403: throw new n8n_workflow_2.NodeApiError(this.getNode(), { message: 'Access forbidden. Your API key does not have permission for this operation.', description: 'Check that your Close account has the necessary permissions.', }); case 404: throw new n8n_workflow_2.NodeApiError(this.getNode(), { message: 'Resource not found.', description: 'The requested resource does not exist or may have been deleted.', }); case 429: throw new n8n_workflow_2.NodeApiError(this.getNode(), { message: 'Rate limit exceeded. Please try again later.', description: 'You have made too many requests. Please wait before trying again.', }); case 500: throw new n8n_workflow_2.NodeApiError(this.getNode(), { message: 'Close CRM server error. Please try again later.', description: "There was an internal server error on Close CRM's side.", }); default: throw new n8n_workflow_2.NodeApiError(this.getNode(), { message: `Close CRM API error (${statusCode}): ${errorMessage}`, description: 'An unexpected error occurred while communicating with Close CRM.', }); } } throw new n8n_workflow_2.NodeApiError(this.getNode(), error); } } async function closeApiRequestAllItems(propertyName, method, endpoint, body = {}, query = {}) { const returnData = []; let responseData; query._limit = 100; query._skip = 0; do { responseData = await closeApiRequest.call(this, method, endpoint, body, query); query._skip = returnData.length; returnData.push.apply(returnData, responseData[propertyName]); } while (responseData.has_more !== false); return returnData; } /** * Convert plain text with newlines to proper HTML format required by Close CRM * Close CRM expects rich text fields to have proper HTML structure with <p> tags */ /** * Convert plain text with newlines to proper HTML format required by Close CRM * Close CRM expects rich text fields to have proper HTML structure with <p> tags */ function convertPlainTextToHTML(text) { // If the text is already HTML with body tags, return as-is if (text.includes('<body>') || text.includes('<body ')) { return text; } // Split by lines first to analyze the structure const lines = text.split('\n'); const result = []; let i = 0; while (i < lines.length) { const line = lines[i]; const trimmed = line.trim(); // Skip empty lines if (!trimmed) { i++; continue; } // Check if this line starts a list if (trimmed.startsWith('-') || trimmed.startsWith('*')) { // Collect consecutive list items const listItems = []; while (i < lines.length) { const currentLine = lines[i].trim(); if (!currentLine) { i++; break; // Empty line ends the list } if (currentLine.startsWith('-') || currentLine.startsWith('*')) { // Remove the leading - or * and any whitespace const content = currentLine.replace(/^[-*]\s*/, ''); listItems.push(`<li>${content}</li>`); i++; } else { // Non-list line ends the list break; } } if (listItems.length > 0) { result.push(`<ul>${listItems.join('')}</ul>`); } } else { // Regular paragraph - collect lines until empty line or list const paragraphLines = [trimmed]; i++; while (i < lines.length) { const nextLine = lines[i]; const nextTrimmed = nextLine.trim(); // Empty line ends paragraph if (!nextTrimmed) { i++; break; } // List item ends paragraph if (nextTrimmed.startsWith('-') || nextTrimmed.startsWith('*')) { break; } paragraphLines.push(nextTrimmed); i++; } result.push(`<p>${paragraphLines.join('<br>')}</p>`); } } // Wrap in body tags return `<body>${result.join('')}</body>`; }