/** * DSS Error Handler - Immune System Antibodies * * The DSS Organism's immune system uses these antibodies to detect and report threats. * Converts technical errors into human-friendly, actionable treatment plans. * Integrates with the messaging system for structured error reporting. * * Biological Framework: These error messages use organism metaphors to make * issues intuitive. See docs/DSS_ORGANISM_GUIDE.md for the full framework. * * @module error-handler */ import { notifyError, ErrorCode } from './messaging.js'; /** * Error message templates with organism metaphors * * These messages use biological language from the DSS Organism Framework. * Each error is framed as a symptom the immune system detected, with * a diagnosis and treatment plan. */ const errorMessages = { // Figma API Errors - Sensory System Issues figma_403: { title: '🛡️ IMMUNE ALERT: Sensory Input Blocked', message: 'The DSS sensory organs cannot perceive the Figma file. Your access credentials lack permission.', actions: [ 'Verify your Figma authentication token in Settings (nervous system communication)', 'Confirm you have access to this file in Figma (sensory perception)', 'Check if the file still exists (organism awareness)', ], code: ErrorCode.FIGMA_API_ERROR, }, figma_404: { title: '🛡️ IMMUNE ALERT: Sensory Target Lost', message: 'The Figma file the DSS sensory organs were trying to perceive doesn\'t exist or is inaccessible.', actions: [ 'Double-check your Figma file key in Settings (sensory focus)', 'Verify the file hasn\'t been deleted in Figma', 'Confirm you have access to the file in Figma (sensory perception)', ], code: ErrorCode.FIGMA_API_ERROR, }, figma_401: { title: '🔌 NERVOUS SYSTEM ALERT: Authentication Expired', message: 'The DSS nervous system\'s authentication with Figma has failed. Your sensory input token is invalid or expired.', actions: [ 'Refresh your Figma authentication token in Settings (nervous system repair)', 'Get a fresh token from figma.com/settings (Account → Personal Access Tokens)', 'Ensure you copied the full token without truncation', ], code: ErrorCode.FIGMA_CONNECTION_FAILED, }, figma_429: { title: '⚡ METABOLISM ALERT: Sensory Overload', message: 'The DSS is sensing too quickly. Figma\'s rate limits have been triggered.', actions: [ 'Let the organism rest for 1-2 minutes before sensing again', 'Reduce how frequently the sensory system extracts data', ], code: ErrorCode.FIGMA_API_ERROR, }, figma_500: { title: '🔌 EXTERNAL SYSTEM ALERT: Figma Organism Stressed', message: 'Figma\'s servers are experiencing stress. This is external to DSS.', actions: [ 'Wait while the external organism recovers', 'Check Figma health: status.figma.com', ], code: ErrorCode.FIGMA_API_ERROR, }, figma_demo: { title: '🛡️ IMMUNE ALERT: Invalid Sensory Configuration', message: 'The sensory organs are configured to look at "demo" which doesn\'t exist in Figma.', actions: [ 'Update Settings with your real Figma file key (configure sensory input)', 'Find your file key in the Figma URL: figma.com/file/[FILE_KEY]/...', 'Use the Figma file selector in Settings', ], code: ErrorCode.FIGMA_INVALID_KEY, }, // API Connection Errors - Nervous System / Heart Issues api_network: { title: '❤️ CRITICAL: Heart Not Responding', message: 'The DSS nervous system cannot reach the heart (server). The organism is not responding.', actions: [ 'Verify the heart is beating: curl http://localhost:3456/health', 'Restart the heart: cd tools/api && python3 -m uvicorn server:app --port 3456', 'Check your network connection to the organism', ], code: ErrorCode.SYSTEM_NETWORK, }, api_timeout: { title: '⚡ METABOLISM ALERT: Organism Overloaded', message: 'The DSS organism took too long to respond. The heart may be stressed or metabolism sluggish.', actions: [ 'Let the organism rest and try again shortly', 'Check the heart\'s logs for signs of stress: tail -f /tmp/dss-demo.log', 'Reduce metabolic load (try processing smaller batches)', ], code: ErrorCode.API_TIMEOUT, }, api_500: { title: '🧠 BRAIN ALERT: Critical Processing Error', message: 'The DSS brain encountered a fatal error while processing your request.', actions: [ 'Examine the brain\'s thoughts in the logs: tail -f /tmp/dss-demo.log', 'Retry the operation to see if it recovers', 'Report the issue if the organism keeps failing', ], code: ErrorCode.API_SERVER_ERROR, }, // Validation Errors - Immune System / Genetics validation_missing_field: { title: '🛡️ IMMUNE ALERT: DNA Incomplete', message: 'The genetic code (configuration) is missing essential information. The organism cannot proceed.', actions: [ 'Fill in all fields marked as required (complete the genetic code)', 'Ensure each input field contains valid information', ], code: ErrorCode.VALIDATION_MISSING_FIELD, }, validation_invalid_format: { title: '🛡️ IMMUNE ALERT: Genetic Mutation Detected', message: 'One or more genetic sequences (configuration values) have an invalid format.', actions: [ 'Verify URLs start with http:// or https:// (correct genetic sequence)', 'Check email addresses follow standard format (valid genetic code)', 'Ensure file keys contain only letters, numbers, and hyphens (genetic pattern match)', ], code: ErrorCode.VALIDATION_INVALID_FORMAT, }, // Generic fallback unknown: { title: '🧬 ORGANISM ALERT: Unexplained Symptom', message: 'The DSS organism experienced an unexpected problem. The root cause is unclear.', actions: [ 'Try the operation again (organism may self-heal)', 'Refresh if the issue persists (restart vitals)', 'Check browser console for clues about the organism\'s condition', ], code: ErrorCode.SYSTEM_UNEXPECTED, }, }; /** * Parse error and return user-friendly message * @param {Error} error - The error to parse * @param {Object} context - Additional context (operation, endpoint, etc.) * @returns {Object} Parsed error with user-friendly message */ export function parseError(error, context = {}) { const errorStr = error.message || String(error); // Figma API Errors if (context.service === 'figma' || errorStr.includes('figma.com')) { // Demo file key if (context.fileKey === 'demo' || errorStr.includes('/demo/')) { return errorMessages.figma_demo; } // HTTP status codes if (errorStr.includes('403')) { return errorMessages.figma_403; } if (errorStr.includes('404')) { return errorMessages.figma_404; } if (errorStr.includes('401')) { return errorMessages.figma_401; } if (errorStr.includes('429')) { return errorMessages.figma_429; } if (errorStr.includes('500') || errorStr.includes('502') || errorStr.includes('503')) { return errorMessages.figma_500; } } // Network Errors if (errorStr.includes('NetworkError') || errorStr.includes('Failed to fetch')) { return errorMessages.api_network; } // Timeout Errors if (errorStr.includes('timeout') || errorStr.includes('Timeout')) { return errorMessages.api_timeout; } // API Server Errors if (errorStr.includes('500') || errorStr.includes('Internal Server Error')) { return errorMessages.api_500; } // Validation Errors if (errorStr.includes('required') || errorStr.includes('missing')) { return errorMessages.validation_missing_field; } if (errorStr.includes('invalid') || errorStr.includes('format')) { return errorMessages.validation_invalid_format; } // Fallback return errorMessages.unknown; } /** * Format user-friendly error message * @param {Object} parsedError - Parsed error from parseError() * @returns {string} Formatted message */ export function formatErrorMessage(parsedError) { let message = `${parsedError.title}\n\n${parsedError.message}`; if (parsedError.actions && parsedError.actions.length > 0) { message += '\n\nWhat to do:\n'; parsedError.actions.forEach((action, index) => { message += `${index + 1}. ${action}\n`; }); } return message.trim(); } /** * Handle error and notify user with friendly message * @param {Error} error - The error to handle * @param {Object} context - Additional context * @param {string} context.operation - What operation failed (e.g., "extract tokens") * @param {string} context.service - Which service (e.g., "figma") * @param {string} context.fileKey - Figma file key if applicable */ export function handleError(error, context = {}) { const parsed = parseError(error, context); // Create user-friendly message let userMessage = parsed.title; if (parsed.actions && parsed.actions.length > 0) { userMessage += '. ' + parsed.actions[0]; // Show first action in notification } // Notify user with structured error notifyError(userMessage, parsed.code, { operation: context.operation, service: context.service, originalError: error.message, actions: parsed.actions, }); // Log full details to console for debugging console.group(`🔴 ${parsed.title}`); console.log('Message:', parsed.message); if (parsed.actions) { console.log('Actions:', parsed.actions); } console.log('Context:', context); console.log('Original Error:', error); console.groupEnd(); return parsed; } /** * Try-catch wrapper with automatic error handling * @param {Function} fn - Async function to execute * @param {Object} context - Error context * @returns {Promise<*>} Result of function or null on error */ export async function tryWithErrorHandling(fn, context = {}) { try { return await fn(); } catch (error) { handleError(error, context); return null; } } /** * Get user-friendly HTTP status message using organism metaphors * @param {number} status - HTTP status code * @returns {string} User-friendly message with biological context */ export function getStatusMessage(status) { const messages = { 400: '🛡️ Genetic Code Invalid - the DNA sequence doesn\'t compile', 401: '🔐 Authentication Failed - the nervous system can\'t verify identity', 403: '🚫 Access Forbidden - immune system rejected this organism', 404: '👻 Target Lost - sensory organs can\'t perceive the resource', 429: '⚡ Metabolism Overloaded - organism sensing too quickly', 500: '🧠 Brain Error - critical neural processing failure', 502: '💀 Organism Unresponsive - the heart has stopped beating', 503: '🏥 Organism In Recovery - temporarily unable to metabolize requests', }; return messages[status] || `🔴 Unknown Organism State - HTTP ${status}`; } export default { parseError, formatErrorMessage, handleError, tryWithErrorHandling, getStatusMessage, };