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
JavaScript
;
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;