UNPKG

breathe-api

Version:

Model Context Protocol server for Breathe HR APIs with Swagger/OpenAPI support - also works with custom APIs

187 lines 6.88 kB
export class BaseError extends Error { code; context; suggestions; timestamp; isRetryable; constructor(message, code, context = {}, suggestions = [], isRetryable = false) { super(message); this.name = this.constructor.name; this.code = code; this.context = context; this.suggestions = suggestions; this.timestamp = new Date(); this.isRetryable = isRetryable; if (Error.captureStackTrace) { Error.captureStackTrace(this, this.constructor); } } getUserMessage() { let message = this.message; if (this.suggestions.length > 0) { message += '\n\nSuggestions:'; this.suggestions.forEach((suggestion, index) => { message += `\n${index + 1}. ${suggestion.message}`; if (suggestion.action) { message += ` (${suggestion.action})`; } }); } return message; } toJSON() { return { name: this.name, code: this.code, message: this.message, context: this.context, suggestions: this.suggestions, timestamp: this.timestamp, isRetryable: this.isRetryable, stack: this.stack, }; } } export class ApiError extends BaseError { statusCode; response; constructor(message, statusCode, response, context = {}, suggestions = []) { const code = `API_ERROR_${statusCode || 'UNKNOWN'}`; const isRetryable = statusCode ? [408, 429, 500, 502, 503, 504].includes(statusCode) : false; super(message, code, { ...context, statusCode, response }, suggestions, isRetryable); this.statusCode = statusCode; this.response = response; } static fromAxiosError(error) { const statusCode = error.response?.status; const response = error.response?.data; const url = error.config?.url; let message = error.message; const suggestions = []; switch (statusCode) { case 401: message = `Authentication failed for ${url}`; suggestions.push({ message: 'Check your API credentials', action: 'Verify BREATHE_API_USERNAME and BREATHE_API_PASSWORD environment variables', }); break; case 403: message = `Access forbidden for ${url}`; suggestions.push({ message: 'Ensure your API user has the necessary permissions', action: 'Contact your Breathe HR administrator', }); break; case 404: message = `Resource not found: ${url}`; suggestions.push({ message: 'Verify the API endpoint URL is correct', action: 'Check the API documentation for the correct endpoint', }); break; case 429: message = `Rate limit exceeded for ${url}`; suggestions.push({ message: 'Wait before retrying', action: 'Implement exponential backoff or reduce request frequency', }); break; case 500: case 502: case 503: message = `Server error from ${url}`; suggestions.push({ message: 'The API server is experiencing issues', action: 'Try again in a few moments', }); break; } return new ApiError(message, statusCode, response, { url, method: error.config?.method, headers: error.config?.headers, }, suggestions); } } export class ValidationError extends BaseError { field; value; constructor(message, field, value, suggestions = []) { super(message, 'VALIDATION_ERROR', { field, value }, suggestions, false); this.field = field; this.value = value; } } export class ConfigurationError extends BaseError { constructor(message, configKey, suggestions = []) { super(message, 'CONFIGURATION_ERROR', { configKey }, suggestions, false); } } export class SwaggerParseError extends BaseError { constructor(message, swaggerUrl, parseError, suggestions = []) { if (suggestions.length === 0) { suggestions.push({ message: 'Ensure the Swagger/OpenAPI specification is valid', action: 'Validate the spec at https://editor.swagger.io', }); } super(message, 'SWAGGER_PARSE_ERROR', { swaggerUrl, parseError }, suggestions, true); } } export class CodeGenerationError extends BaseError { constructor(message, platform, context = {}, suggestions = []) { super(message, 'CODE_GENERATION_ERROR', { ...context, platform }, suggestions, false); } } export class TimeoutError extends BaseError { constructor(message, operation, timeoutMs, suggestions = []) { if (suggestions.length === 0) { suggestions.push({ message: 'The operation took too long to complete', action: 'Try again or increase the timeout limit', }); } super(message, 'TIMEOUT_ERROR', { operation, timeoutMs }, suggestions, true); } } export class CircuitBreakerError extends BaseError { constructor(message, service, failureCount, suggestions = []) { if (suggestions.length === 0) { suggestions.push({ message: `The ${service} service is temporarily unavailable due to repeated failures`, action: 'Wait a few minutes before trying again', }); } super(message, 'CIRCUIT_BREAKER_OPEN', { service, failureCount }, suggestions, true); } } export function wrapError(error, context = {}, suggestions = []) { if (error instanceof BaseError) { Object.assign(error.context, context); error.suggestions.push(...suggestions); return error; } if (error instanceof Error) { return new BaseError(error.message, 'WRAPPED_ERROR', { ...context, originalError: error.name }, suggestions, false); } return new BaseError(String(error), 'UNKNOWN_ERROR', context, suggestions, false); } export function formatErrorForMcp(error) { if (error instanceof BaseError) { return { message: error.getUserMessage(), code: error.code, context: error.context, }; } if (error instanceof Error) { return { message: error.message, }; } return { message: String(error), }; } //# sourceMappingURL=errors.js.map