/** * Error handling utilities for consistent error management. * Provides centralized error handling logic across the application. */ /** * Error kind for categorizing errors */ export type ErrorKind = | 'render' | 'network' | 'validation' | 'authentication' | 'authorization' | 'notFound' | 'server' | 'unknown' /** * Error object with kind and message */ export type AppError = { kind: ErrorKind message: string details?: Record timestamp: number } /** * Create an error object with consistent structure */ export function createAppError( kind: ErrorKind, message: string, details?: Record ): AppError { return { kind, message, details, timestamp: Date.now(), } } /** * Extract error message from unknown error */ export function getErrorMessage(error: unknown): string { if (error instanceof Error) { return error.message } if (typeof error === 'string') { return error } if (typeof error === 'object' && error !== null && 'message' in error) { return String(error.message) } return 'An unknown error occurred' } /** * Extract error kind from error */ export function getErrorKind(error: unknown): ErrorKind { if (error instanceof Error) { const message = error.message.toLowerCase() if (message.includes('network')) return 'network' if (message.includes('validation') || message.includes('invalid')) return 'validation' if (message.includes('auth')) return 'authentication' if (message.includes('forbidden') || message.includes('unauthorized')) return 'authorization' if (message.includes('not found') || message.includes('404')) return 'notFound' if (message.includes('server') || message.includes('500')) return 'server' } return 'unknown' } /** * Format error for display */ export function formatError(error: AppError | Error | string): string { if (typeof error === 'string') { return error } if (error instanceof Error) { return error.message } return error.message } /** * Check if error is recoverable */ export function isRecoverableError(error: AppError | Error | string): boolean { if (typeof error === 'string') return false if (error instanceof Error) { const message = error.message.toLowerCase() return ['network', 'timeout', 'connection'].some((term) => message.includes(term)) } // error is AppError at this point return ['network', 'server'].includes((error as AppError).kind) } /** * Update error state consistently */ export function updateErrorState( state: T, setError: (error: null | { kind: string; message: string }) => void, error: unknown ): void { setError({ kind: 'render', message: getErrorMessage(error), }) } /** * Clear error state */ export function clearErrorState( state: T, setError: (error: null) => void ): void { setError(null) } /** * Handle error with consistent logging */ export function handleError( error: unknown, context?: Record ): AppError { const appError = createAppError( getErrorKind(error), getErrorMessage(error), context ) console.error('[Error]', appError, context) return appError } /** * Create error handler for async functions */ export function createErrorHandler( onError?: (error: AppError) => void ): (error: unknown) => T { return (error: unknown) => { const appError = handleError(error) onError?.(appError) throw error } }