UNPKG

n8n-nodes-mautic-advanced

Version:

Enhanced n8n node for Mautic with comprehensive API coverage including tags, campaigns, categories, and advanced contact management

170 lines (169 loc) 8.35 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.processResponseData = exports.getOptionalParam = exports.getRequiredParam = exports.handleApiError = exports.makePaginatedRequest = exports.makeApiRequest = void 0; const n8n_workflow_1 = require("n8n-workflow"); const GenericFunctions_1 = require("../GenericFunctions"); const authErrorHelpers_1 = require("./authErrorHelpers"); // Standardized API request wrapper with error handling async function makeApiRequest(context, method, endpoint, body = {}, query = {}, uri, headers) { try { return await GenericFunctions_1.mauticApiRequest.call(context, method, endpoint, body, query, uri, headers); } catch (error) { if (error instanceof n8n_workflow_1.NodeApiError || error instanceof n8n_workflow_1.NodeOperationError) { throw error; } throw new n8n_workflow_1.NodeApiError(context.getNode(), error); } } exports.makeApiRequest = makeApiRequest; function toOptionalPositiveInteger(value) { const numericValue = typeof value === 'number' ? value : typeof value === 'string' ? Number(value) : undefined; if (numericValue === undefined || !Number.isFinite(numericValue) || numericValue <= 0) { return undefined; } return Math.floor(numericValue); } function preparePaginatedQuery(query, explicitLimit) { const queryForPagination = { ...query }; const limit = explicitLimit ?? toOptionalPositiveInteger(queryForPagination.limit); delete queryForPagination.limit; return { query: queryForPagination, limit }; } // Standardized paginated API request wrapper async function makePaginatedRequest(context, resource, method, endpoint, body = {}, query = {}, limit) { const pagination = preparePaginatedQuery(query, limit); try { return await GenericFunctions_1.mauticApiRequestAllItems.call(context, resource, method, endpoint, body, pagination.query, pagination.limit); } catch (error) { if (error instanceof n8n_workflow_1.NodeApiError || error instanceof n8n_workflow_1.NodeOperationError) { throw error; } throw new n8n_workflow_1.NodeApiError(context.getNode(), error); } } exports.makePaginatedRequest = makePaginatedRequest; // Handle API errors with appropriate user-friendly messages function handleApiError(context, error, operation, resource) { if (error instanceof n8n_workflow_1.NodeOperationError) { throw error; } if ((0, authErrorHelpers_1.isInvalidGrantError)(error)) { throw new n8n_workflow_1.NodeOperationError(context.getNode(), authErrorHelpers_1.OAUTH_REFRESH_ERROR_MESSAGE, { itemIndex: 0 }); } if (error instanceof n8n_workflow_1.NodeApiError) { const httpCode = String(error.httpCode); if (httpCode === '404') { throw new n8n_workflow_1.NodeOperationError(context.getNode(), `${resource} not found during ${operation} operation.`, { itemIndex: 0 }); } if (httpCode === '401' || httpCode === '403') { throw new n8n_workflow_1.NodeOperationError(context.getNode(), `Permission denied for ${operation} ${resource}. Please check your API credentials.`, { itemIndex: 0 }); } if (httpCode === '400') { // Extract detailed validation errors from Mautic API response let errorMessage = `Invalid data provided for ${operation} ${resource}.`; try { const errorData = error.description; // Check if we have a direct error message from Mautic API if (typeof errorData === 'string' && errorData.trim()) { // Parse field-specific error messages like "field_name: error message" const fieldErrorMatch = errorData.match(/^([^:]+):\s*(.+)$/); if (fieldErrorMatch) { const fieldName = fieldErrorMatch[1].trim(); const errorMsg = fieldErrorMatch[2].trim(); errorMessage += ` Validation error:\n- ${fieldName}: ${errorMsg}\n`; } else { // If it doesn't match the field:message pattern, show the raw message errorMessage += ` Error: ${errorData}\n`; } } // Check for errors array (current Mautic API format) else if (errorData?.errors && Array.isArray(errorData.errors) && errorData.errors.length > 0) { const validationErrors = []; errorData.errors.forEach((err) => { if (err.details && typeof err.details === 'object') { // Extract field-specific validation messages Object.entries(err.details).forEach(([field, messages]) => { if (Array.isArray(messages)) { messages.forEach((msg) => { validationErrors.push(`- ${field}: ${msg}`); }); } }); } else if (err.message) { // Fallback to error message if no details validationErrors.push(`- ${err.message}`); } }); if (validationErrors.length > 0) { errorMessage += ` Validation errors:\n${validationErrors.join('\n')}\n`; } } // Check for deprecated error format (Mautic < 2.6.0) else if (errorData?.error?.details && typeof errorData.error.details === 'object') { const validationErrors = []; Object.entries(errorData.error.details).forEach(([field, messages]) => { if (Array.isArray(messages)) { messages.forEach((msg) => { validationErrors.push(`- ${field}: ${msg}`); }); } }); if (validationErrors.length > 0) { errorMessage += ` Validation errors:\n${validationErrors.join('\n')}\n`; } } } catch (parseError) { // If we can't parse the error details, just use the generic message } errorMessage += ' Please check your input parameters.'; throw new n8n_workflow_1.NodeOperationError(context.getNode(), errorMessage, { itemIndex: 0 }); } throw error; } throw new n8n_workflow_1.NodeOperationError(context.getNode(), `Failed to ${operation} ${resource}: ${error?.message || 'Unknown error'}`, { itemIndex: 0 }); } exports.handleApiError = handleApiError; // Extract and validate required parameter function getRequiredParam(context, paramName, itemIndex, errorMessage) { const value = context.getNodeParameter(paramName, itemIndex); if (value === undefined || value === null || value === '') { throw new n8n_workflow_1.NodeOperationError(context.getNode(), errorMessage || `Parameter '${paramName}' is required.`, { itemIndex }); } return value; } exports.getRequiredParam = getRequiredParam; // Extract optional parameter with default value function getOptionalParam(context, paramName, itemIndex, defaultValue) { try { return context.getNodeParameter(paramName, itemIndex, defaultValue); } catch { return defaultValue; } } exports.getOptionalParam = getOptionalParam; // Process response data based on simple/raw data options function processResponseData(responseData, options, simpleDataPath) { if (options.rawData === true) { return responseData; } if (options.rawData === false && simpleDataPath) { const pathParts = simpleDataPath.split('.'); let result = responseData; for (const part of pathParts) { result = result?.[part]; } return result; } return responseData; } exports.processResponseData = processResponseData;