firewalla-mcp-server
Version:
Model Context Protocol (MCP) server for Firewalla MSP API - Provides real-time network monitoring, security analysis, and firewall management through 28 specialized tools compatible with any MCP client
324 lines • 11.5 kB
JavaScript
/**
* Error Formatter for Firewalla MCP Server
* Provides user-friendly error message formatting and grouping
*/
export class ErrorFormatter {
/**
* Format a single detailed error
*/
static formatError(error, context) {
const errorType = error.errorType || 'syntax';
return {
title: this.getErrorTitle(errorType),
message: this.enhanceErrorMessage(error),
suggestion: error.suggestion,
code: this.generateErrorCode(error),
help: this.getHelpLink(errorType),
context: context || error.context,
severity: this.getErrorSeverity(errorType)
};
}
/**
* Format multiple errors into a comprehensive report
*/
static formatMultipleErrors(errors, context) {
const grouped = this.groupErrorsByType(errors);
const formattedGroups = {};
// Format each group
Object.entries(grouped).forEach(([type, typeErrors]) => {
formattedGroups[type] = typeErrors.map(error => this.formatError(error, context));
});
const quickFixes = this.generateQuickFixes(errors);
const documentation = this.getRelevantDocumentation(errors);
const severity = this.calculateOverallSeverity(errors);
return {
summary: this.generateErrorSummary(errors),
errors: formattedGroups,
quickFixes,
documentation,
severity
};
}
/**
* Generate a user-friendly error summary
*/
static generateErrorSummary(errors) {
const totalErrors = errors.length;
const errorTypes = [...new Set(errors.map(e => e.errorType))];
if (totalErrors === 1) {
const error = errors[0];
return `Found 1 ${error.errorType} error in your query`;
}
if (errorTypes.length === 1) {
return `Found ${totalErrors} ${errorTypes[0]} errors in your query`;
}
const typeBreakdown = errorTypes.map(type => {
const count = errors.filter(e => e.errorType === type).length;
return `${count} ${type}`;
}).join(', ');
return `Found ${totalErrors} errors: ${typeBreakdown}`;
}
/**
* Group errors by type for better organization
*/
static groupErrorsByType(errors) {
const grouped = {};
errors.forEach(error => {
const type = error.errorType || 'syntax';
if (!grouped[type]) {
grouped[type] = [];
}
grouped[type].push(error);
});
return grouped;
}
/**
* Generate quick fixes from errors
*/
static generateQuickFixes(errors) {
const fixes = [];
errors.forEach(error => {
// Field name fixes
if (error.errorType === 'field' && error.suggestion?.includes('Did you mean')) {
const fieldMatch = error.suggestion.match(/Did you mean '([^']+)'/);
const originalMatch = error.message.match(/Field '([^']+)'/);
if (fieldMatch && originalMatch) {
fixes.push({
description: error.suggestion,
action: 'replace_field',
original: originalMatch[1],
replacement: fieldMatch[1]
});
}
}
// Syntax fixes
if (error.errorType === 'syntax') {
if (error.message.includes('colon')) {
fixes.push({
description: 'Add missing colon in field query',
action: 'fix_syntax',
position: error.position
});
}
if (error.message.includes('parenthesis')) {
fixes.push({
description: 'Fix parentheses matching',
action: 'fix_syntax',
position: error.position
});
}
if (error.message.includes('quote')) {
fixes.push({
description: 'Fix quote matching',
action: 'add_quotes',
position: error.position
});
}
}
// Operator fixes
if (error.errorType === 'operator' && error.suggestion) {
if (error.suggestion.includes('Use :') || error.suggestion.includes('Try using:')) {
fixes.push({
description: 'Use compatible operator',
action: 'change_operator',
original: this.extractOperatorFromMessage(error.message),
replacement: ':'
});
}
}
});
// Remove duplicates
return fixes.filter((fix, index, array) => array.findIndex(f => f.action === fix.action &&
f.original === fix.original &&
f.replacement === fix.replacement) === index);
}
/**
* Get relevant documentation links
*/
static getRelevantDocumentation(errors) {
const errorTypes = [...new Set(errors.map(e => e.errorType))];
const documentation = [];
errorTypes.forEach(type => {
const link = this.HELP_LINKS[type];
if (link) {
documentation.push(link);
}
});
// Add general documentation
if (documentation.length === 0 || errors.length > 3) {
documentation.push({
title: 'Complete Documentation',
url: 'docs/field-syntax-requirements.md',
description: 'Comprehensive guide to all query syntax and validation rules'
});
}
return documentation;
}
/**
* Calculate overall severity
*/
static calculateOverallSeverity(errors) {
if (errors.length >= 5) {
return 'high';
}
if (errors.length >= 2) {
return 'medium';
}
const hasSyntaxErrors = errors.some(e => e.errorType === 'syntax');
if (hasSyntaxErrors) {
return 'medium';
}
return 'low';
}
/**
* Enhance error message with additional context
*/
static enhanceErrorMessage(error) {
let { message } = error;
// Add position information if available
if (error.position !== undefined) {
message = `${message} (at position ${error.position})`;
}
// Add context if available
if (error.context && !message.includes(error.context)) {
message = `${message}\nContext: ${error.context}`;
}
return message;
}
/**
* Get error title by type
*/
static getErrorTitle(errorType) {
return this.ERROR_TITLES[errorType] || 'Query Error';
}
/**
* Generate error code
*/
static generateErrorCode(error) {
const baseCode = this.ERROR_CODES[error.errorType] || 'UNKNOWN_ERR';
const hash = this.simpleHash(error.message);
return `${baseCode}_${hash}`;
}
/**
* Get help link for error type
*/
static getHelpLink(errorType) {
const link = this.HELP_LINKS[errorType];
return link ? link.url : 'docs/field-syntax-requirements.md';
}
/**
* Get error severity
*/
static getErrorSeverity(errorType) {
switch (errorType) {
case 'syntax':
return 'error';
case 'semantic':
return 'error';
case 'field':
return 'warning';
case 'operator':
return 'warning';
default:
return 'error';
}
}
/**
* Extract operator from error message
*/
static extractOperatorFromMessage(message) {
const operatorMatch = message.match(/operator '([^']+)'/);
return operatorMatch ? operatorMatch[1] : '';
}
/**
* Simple hash function for error codes
*/
static simpleHash(str) {
let hash = 0;
for (let i = 0; i < str.length; i++) {
const char = str.charCodeAt(i);
hash = ((hash << 5) - hash) + char;
hash = hash & hash; // Convert to 32bit integer
}
return Math.abs(hash).toString(16).substring(0, 4).toUpperCase();
}
/**
* Format error report as text for console output
*/
static formatReportAsText(report) {
const lines = [];
lines.push(`❌ ${report.summary}`);
lines.push('');
// Add errors by type
Object.entries(report.errors).forEach(([type, typeErrors]) => {
if (typeErrors.length > 0) {
lines.push(`📋 ${this.ERROR_TITLES[type] || type.toUpperCase()} ERRORS:`);
typeErrors.forEach((error, index) => {
lines.push(` ${index + 1}. ${error.message}`);
if (error.suggestion) {
lines.push(` 💡 ${error.suggestion}`);
}
if (error.context) {
lines.push(` 📍 ${error.context}`);
}
});
lines.push('');
}
});
// Add quick fixes
if (report.quickFixes.length > 0) {
lines.push('🔧 QUICK FIXES:');
report.quickFixes.forEach((fix, index) => {
lines.push(` ${index + 1}. ${fix.description}`);
if (fix.original && fix.replacement) {
lines.push(` Replace: "${fix.original}" → "${fix.replacement}"`);
}
});
lines.push('');
}
// Add documentation links
if (report.documentation.length > 0) {
lines.push('📚 HELPFUL DOCUMENTATION:');
report.documentation.forEach((doc, index) => {
lines.push(` ${index + 1}. ${doc.title}: ${doc.url}`);
lines.push(` ${doc.description}`);
});
}
return lines.join('\n');
}
}
ErrorFormatter.ERROR_TITLES = {
'syntax': 'Syntax Error',
'semantic': 'Query Logic Error',
'field': 'Field Error',
'operator': 'Operator Error'
};
ErrorFormatter.ERROR_CODES = {
'syntax': 'SYNTAX_ERR',
'semantic': 'LOGIC_ERR',
'field': 'FIELD_ERR',
'operator': 'OPERATOR_ERR'
};
ErrorFormatter.HELP_LINKS = {
'syntax': {
title: 'Query Syntax Guide',
url: 'docs/field-syntax-specification.md',
description: 'Learn the correct syntax for search queries'
},
'field': {
title: 'Field Reference',
url: 'docs/field-syntax-requirements.md',
description: 'Complete list of available fields by entity type'
},
'operator': {
title: 'Operator Guide',
url: 'docs/field-syntax-specification.md#query-syntax-operators',
description: 'Available operators and their usage'
},
'semantic': {
title: 'Advanced Query Examples',
url: 'docs/field-syntax-specification.md#tool-specific-syntax-examples',
description: 'Examples of complex query patterns'
}
};
//# sourceMappingURL=error-formatter.js.map