UNPKG

pms-analysis-reports-mcp-server

Version:

PMS analysis reports server handling maintenance reports, equipment analysis, compliance tracking, and performance metrics with ERP access for data extraction

239 lines 9.32 kB
import { logger } from "../utils/logger.js"; import { SanitizationMiddleware } from "./sanitization-middleware.js"; export var ErrorCodes; (function (ErrorCodes) { ErrorCodes["VALIDATION_ERROR"] = "VALIDATION_ERROR"; ErrorCodes["AUTHENTICATION_ERROR"] = "AUTHENTICATION_ERROR"; ErrorCodes["AUTHORIZATION_ERROR"] = "AUTHORIZATION_ERROR"; ErrorCodes["RESOURCE_NOT_FOUND"] = "RESOURCE_NOT_FOUND"; ErrorCodes["DATABASE_ERROR"] = "DATABASE_ERROR"; ErrorCodes["EXTERNAL_API_ERROR"] = "EXTERNAL_API_ERROR"; ErrorCodes["RATE_LIMIT_EXCEEDED"] = "RATE_LIMIT_EXCEEDED"; ErrorCodes["INTERNAL_ERROR"] = "INTERNAL_ERROR"; ErrorCodes["INVALID_INPUT"] = "INVALID_INPUT"; ErrorCodes["TIMEOUT_ERROR"] = "TIMEOUT_ERROR"; })(ErrorCodes || (ErrorCodes = {})); export class ErrorHandler { // Central error processing method static handleError(error, context = {}) { const timestamp = new Date(); const requestId = context.requestId || this.generateRequestId(); // Log the full error for debugging (with sanitization) const sanitizedContext = SanitizationMiddleware.sanitizeForLogging(context); logger.error('Error occurred', { error: { message: error.message, stack: error.stack, name: error.name }, context: sanitizedContext, requestId, timestamp }); // Determine error type and create standardized response const standardError = this.categorizeError(error, context); standardError.timestamp = timestamp; standardError.requestId = requestId; return standardError; } // Categorize errors and return appropriate user-facing messages static categorizeError(error, context) { // MongoDB errors if (error.name === 'MongoError' || error.name === 'MongoServerError') { return { code: ErrorCodes.DATABASE_ERROR, message: 'Database operation failed. Please try again later.', timestamp: new Date() }; } // Validation errors if (error.name === 'ValidationError' || error.code === 'VALIDATION_ERROR') { return { code: ErrorCodes.VALIDATION_ERROR, message: 'Invalid input provided. Please check your parameters.', details: error.details ? SanitizationMiddleware.sanitizeForLogging(error.details) : undefined, timestamp: new Date() }; } // Network/timeout errors if (error.code === 'ECONNRESET' || error.code === 'ETIMEDOUT' || error.name === 'TimeoutError') { return { code: ErrorCodes.TIMEOUT_ERROR, message: 'Request timed out. Please try again.', timestamp: new Date() }; } // External API errors if (error.response && error.response.status) { const status = error.response.status; if (status === 429) { return { code: ErrorCodes.RATE_LIMIT_EXCEEDED, message: 'Rate limit exceeded. Please wait before making another request.', timestamp: new Date() }; } else if (status === 404) { return { code: ErrorCodes.RESOURCE_NOT_FOUND, message: 'Requested resource not found.', timestamp: new Date() }; } else if (status >= 500) { return { code: ErrorCodes.EXTERNAL_API_ERROR, message: 'External service unavailable. Please try again later.', timestamp: new Date() }; } } // Authentication/Authorization errors if (error.name === 'UnauthorizedError' || error.status === 401) { return { code: ErrorCodes.AUTHENTICATION_ERROR, message: 'Authentication required.', timestamp: new Date() }; } if (error.name === 'ForbiddenError' || error.status === 403) { return { code: ErrorCodes.AUTHORIZATION_ERROR, message: 'Access denied.', timestamp: new Date() }; } // Default to internal error return { code: ErrorCodes.INTERNAL_ERROR, message: 'An internal error occurred. Please try again later.', timestamp: new Date() }; } // Handle validation errors specifically static handleValidationError(errors, context = {}) { const sanitizedErrors = errors.map(error => ({ field: error.field, message: SanitizationMiddleware.sanitizeErrorMessage(error.message) })); logger.warn('Validation failed', { errors: sanitizedErrors, context: SanitizationMiddleware.sanitizeForLogging(context), requestId: context.requestId }); return { code: ErrorCodes.VALIDATION_ERROR, message: 'Input validation failed.', details: sanitizedErrors, timestamp: new Date(), requestId: context.requestId }; } // Handle database connection errors static handleDatabaseError(error, operation, context = {}) { logger.error(`Database error during ${operation}`, { error: { message: error.message, code: error.code, name: error.name }, operation, context: SanitizationMiddleware.sanitizeForLogging(context) }); return { code: ErrorCodes.DATABASE_ERROR, message: 'Database operation failed. Please try again later.', timestamp: new Date(), requestId: context.requestId }; } // Handle external API errors static handleExternalAPIError(error, apiName, context = {}) { const status = error.response?.status; const statusText = error.response?.statusText; logger.error(`External API error - ${apiName}`, { error: { message: error.message, status, statusText }, apiName, context: SanitizationMiddleware.sanitizeForLogging(context) }); if (status === 429) { return { code: ErrorCodes.RATE_LIMIT_EXCEEDED, message: `${apiName} rate limit exceeded. Please wait before retrying.`, timestamp: new Date(), requestId: context.requestId }; } return { code: ErrorCodes.EXTERNAL_API_ERROR, message: `${apiName} service unavailable. Please try again later.`, timestamp: new Date(), requestId: context.requestId }; } // Generate unique request ID for tracking static generateRequestId() { return `req_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`; } // Create a safe error response for tool execution static createToolErrorResponse(error, toolName, args = {}) { const context = { toolName, arguments: args, timestamp: new Date() }; const standardError = this.handleError(error, context); return { success: false, error: { code: standardError.code, message: standardError.message, timestamp: standardError.timestamp, requestId: standardError.requestId }, data: null }; } // Graceful error handling with fallback static async safeExecute(operation, fallbackValue, context = {}) { try { return await operation(); } catch (error) { this.handleError(error, context); return fallbackValue; } } // Error recovery with retry logic static async executeWithRetry(operation, maxRetries = 3, delayMs = 1000, context = {}) { let lastError; for (let attempt = 1; attempt <= maxRetries; attempt++) { try { return await operation(); } catch (error) { lastError = error; if (attempt === maxRetries) { break; } // Log retry attempt logger.warn(`Retry attempt ${attempt}/${maxRetries}`, { error: error.message, context: SanitizationMiddleware.sanitizeForLogging(context) }); // Wait before retry await new Promise(resolve => setTimeout(resolve, delayMs * attempt)); } } const errorToThrow = lastError || new Error('Unknown error'); const standardError = this.handleError(errorToThrow, context); const error = new Error(standardError.message); error.code = standardError.code; throw error; } } //# sourceMappingURL=error-handler.js.map