216 lines
7.1 KiB
JavaScript
216 lines
7.1 KiB
JavaScript
/**
|
|
* Centralized error handling for tools
|
|
* Provides consistent error responses and logging
|
|
*/
|
|
|
|
/**
|
|
* Handle and format tool errors
|
|
* @param {Error|string} error - The error object or message
|
|
* @param {string} context - Context where the error occurred (e.g., "save_module", "create_record")
|
|
* @param {Object} additionalInfo - Additional information to include in response
|
|
* @returns {Object} Formatted error response
|
|
*/
|
|
export function handleToolError(error, context = "unknown", additionalInfo = {}) {
|
|
// Log error to console
|
|
console.error(`[Tool Error - ${context}]`, error instanceof Error ? error.message : error);
|
|
if (error instanceof Error && error.stack) {
|
|
console.error(`Stack:`, error.stack);
|
|
}
|
|
|
|
// Extract error message
|
|
let errorMessage = error instanceof Error ? error.message : String(error);
|
|
let errorCode = "UNKNOWN_ERROR";
|
|
let statusCode = 500;
|
|
|
|
// Handle specific error types
|
|
if (error.response) {
|
|
// Axios error with response
|
|
statusCode = error.response.status || 500;
|
|
errorMessage = error.response.data?.message ||
|
|
error.response.data?.error ||
|
|
errorMessage;
|
|
errorCode = `HTTP_${statusCode}`;
|
|
} else if (error.code) {
|
|
// Error with code (like ENOTFOUND, ECONNREFUSED, etc.)
|
|
errorCode = error.code;
|
|
errorMessage = `${error.code}: ${errorMessage}`;
|
|
}
|
|
|
|
// Return formatted error response
|
|
return {
|
|
content: [{
|
|
type: "text",
|
|
text: JSON.stringify({
|
|
success: false,
|
|
error: {
|
|
code: errorCode,
|
|
message: errorMessage,
|
|
context: context,
|
|
...additionalInfo
|
|
}
|
|
}, null, 2)
|
|
}],
|
|
isError: true
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Handle API response errors (when response contains error indication)
|
|
* @param {Object} data - Response data from API
|
|
* @param {string} context - Context where error occurred
|
|
* @returns {Object|null} Error response or null if no error
|
|
*/
|
|
export function handleApiResponse(data, context = "unknown") {
|
|
// Check for common error patterns in Acai CMS responses
|
|
/*if (!data) {
|
|
return handleToolError("Empty response from API", context, { details: "API returned null or undefined" });
|
|
}*/
|
|
|
|
// PHP/Acai error responses typically have error field or PHPSyntax errors
|
|
if (data.error || data.Error) {
|
|
return handleToolError(data.error || data.Error, context, { details: data });
|
|
}
|
|
|
|
if (data.PHPSyntax) {
|
|
return handleToolError(`PHP Syntax Error: ${data.PHPSyntax}`, context, { details: data });
|
|
}
|
|
|
|
// If it's a string response with error indicators
|
|
if (typeof data === 'string' && data.trim().length > 0) {
|
|
// Check for common error patterns
|
|
if (data.toLowerCase().includes('error') ||
|
|
data.toLowerCase().includes('fatal') ||
|
|
data.toLowerCase().includes('undefined') ||
|
|
data.toLowerCase().includes('syntax')) {
|
|
return handleToolError(data, context, { details: "API returned error string" });
|
|
}
|
|
}
|
|
|
|
// If success field exists and is false
|
|
if (data.success === false) {
|
|
return handleToolError(data.message || "API returned success: false", context, { details: data });
|
|
}
|
|
|
|
// No error detected
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Validate required parameters
|
|
* @param {Object} params - Parameters object
|
|
* @param {string[]} requiredFields - Array of required field names
|
|
* @param {string} context - Context where validation occurs
|
|
* @returns {Object|null} Error response or null if all valid
|
|
*/
|
|
export function validateRequired(params, requiredFields, context = "unknown") {
|
|
const missingFields = [];
|
|
|
|
requiredFields.forEach(field => {
|
|
const value = params[field];
|
|
if (value === null || value === undefined ||
|
|
(typeof value === 'string' && value.trim() === '')) {
|
|
missingFields.push(field);
|
|
}
|
|
});
|
|
|
|
if (missingFields.length > 0) {
|
|
return handleToolError(
|
|
`Missing required parameters: ${missingFields.join(', ')}`,
|
|
context,
|
|
{ requiredFields, missingFields }
|
|
);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Validate parameter types
|
|
* @param {Object} params - Parameters object
|
|
* @param {Object} schema - Schema of expected types {fieldName: 'string'|'number'|'boolean'|'array'|'object'}
|
|
* @param {string} context - Context where validation occurs
|
|
* @returns {Object|null} Error response or null if all valid
|
|
*/
|
|
export function validateTypes(params, schema, context = "unknown") {
|
|
const typeErrors = [];
|
|
|
|
for (const [field, expectedType] of Object.entries(schema)) {
|
|
const value = params[field];
|
|
|
|
if (value === null || value === undefined) {
|
|
continue; // Skip optional fields that are not provided
|
|
}
|
|
|
|
let actualType = typeof value;
|
|
if (Array.isArray(value)) actualType = 'array';
|
|
if (value instanceof Date) actualType = 'date';
|
|
|
|
if (actualType !== expectedType) {
|
|
typeErrors.push(`${field}: expected ${expectedType}, got ${actualType}`);
|
|
}
|
|
}
|
|
|
|
if (typeErrors.length > 0) {
|
|
return handleToolError(
|
|
`Type validation failed: ${typeErrors.join('; ')}`,
|
|
context,
|
|
{ typeErrors }
|
|
);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Safely parse JSON with error handling
|
|
* @param {string} jsonString - JSON string to parse
|
|
* @param {string} context - Context where parsing occurs
|
|
* @returns {Object} Parsed object or error response object
|
|
*/
|
|
export function safeJsonParse(jsonString, context = "unknown") {
|
|
try {
|
|
return { success: true, data: JSON.parse(jsonString) };
|
|
} catch (error) {
|
|
return {
|
|
success: false,
|
|
error: handleToolError(error, `${context} - JSON parsing`, { input: jsonString.substring(0, 100) })
|
|
};
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create a validation middleware for tools
|
|
* @param {string[]} requiredFields - Required parameter names
|
|
* @param {Object} typeSchema - Type validation schema
|
|
* @returns {Function} Middleware function
|
|
*/
|
|
export function createValidator(requiredFields = [], typeSchema = {}) {
|
|
return function validateInput(params, context = "unknown") {
|
|
// Check required fields
|
|
const requiredError = validateRequired(params, requiredFields, context);
|
|
if (requiredError) return requiredError;
|
|
|
|
// Check types
|
|
const typeError = validateTypes(params, typeSchema, context);
|
|
if (typeError) return typeError;
|
|
|
|
return null; // No errors
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Wrap a tool handler with automatic error handling
|
|
* @param {Function} handler - The tool handler function
|
|
* @param {string} toolName - Name of the tool for logging
|
|
* @returns {Function} Wrapped handler
|
|
*/
|
|
export function withErrorHandling(handler, toolName = "unknown") {
|
|
return async (params, extra) => {
|
|
try {
|
|
return await handler(params, extra);
|
|
} catch (error) {
|
|
return handleToolError(error, toolName);
|
|
}
|
|
};
|
|
}
|