UNPKG

logicloom-nextjs-starter

Version:

A production-ready Next.js starter template with authentication, i18n, dark mode, and modern patterns

229 lines (208 loc) 6.42 kB
import { AxiosError } from "axios"; import { z } from "zod"; export interface ApiError { message: string; code?: string; field?: string; details?: any; } export class AppError extends Error { code: string; statusCode: number; details?: any; constructor( message: string, code: string = "UNKNOWN_ERROR", statusCode: number = 500, details?: any ) { super(message); this.name = "AppError"; this.code = code; this.statusCode = statusCode; this.details = details; } } export const errorHandler = { // Handle Axios errors handleAxiosError: (error: unknown): AppError => { if (error instanceof AxiosError) { const status = error.response?.status; const data = error.response?.data; // Network error if (!error.response) { return new AppError( "Network error - Cannot connect to server", "NETWORK_ERROR", 0, { originalError: error.message } ); } // Server returned error switch (status) { case 400: return new AppError( data?.message || "Invalid request", "BAD_REQUEST", 400, data ); case 401: return new AppError( data?.message || "Authentication failed", "UNAUTHORIZED", 401, data ); case 403: return new AppError( data?.message || "Access denied", "FORBIDDEN", 403, data ); case 404: return new AppError( data?.message || "Resource not found", "NOT_FOUND", 404, data ); case 409: return new AppError( data?.message || "Conflict - Resource already exists", "CONFLICT", 409, data ); case 422: return new AppError( data?.message || "Validation failed", "VALIDATION_ERROR", 422, data ); case 429: return new AppError( "Too many requests - Please try again later", "RATE_LIMIT", 429, data ); case 500: return new AppError( data?.message || "Server error - Please try again", "SERVER_ERROR", 500, data ); default: return new AppError( data?.message || "An error occurred", "UNKNOWN_ERROR", status || 500, data ); } } // Generic error return new AppError( error instanceof Error ? error.message : "An unknown error occurred", "UNKNOWN_ERROR", 500 ); }, // Handle Zod validation errors handleZodError: (error: z.ZodError): AppError => { const errors = error.issues.map((issue) => ({ field: issue.path.join("."), message: issue.message, code: issue.code, })); return new AppError("Validation failed", "VALIDATION_ERROR", 400, { errors }); }, // Get user-friendly error message getUserMessage: (error: unknown): string => { if (error instanceof AppError) { return error.message; } if (error instanceof AxiosError) { const appError = errorHandler.handleAxiosError(error); return appError.message; } if (error instanceof z.ZodError) { const appError = errorHandler.handleZodError(error); return appError.details.errors[0]?.message || "Validation failed"; } if (error instanceof Error) { return error.message; } return "An unexpected error occurred"; }, // Log error details (for debugging) logError: (error: unknown, context?: string) => { try { const errorTitle = `❌ Error ${context ? `in ${context}` : ""}`; // Use console.group if available, otherwise just log title if (typeof console.group === "function") { console.group(errorTitle); } else { console.error(errorTitle); } if (error instanceof AppError) { console.error("Code:", error.code); console.error("Status:", error.statusCode); console.error("Message:", error.message); if (error.details) { try { console.error("Details:", JSON.stringify(error.details, null, 2)); } catch { console.error("Details:", "[Could not stringify]"); } } } else if (error instanceof AxiosError) { console.error("Type: Axios Error"); console.error("Status:", error.response?.status || "No status"); console.error("Message:", error.message || "No message"); if (error.response?.data) { try { console.error("Response:", JSON.stringify(error.response.data)); } catch { console.error("Response:", "[Could not stringify response]"); } } if (error.config) { console.error("Config:", { url: error.config.url || "unknown", method: error.config.method || "unknown", }); } } else if (error instanceof z.ZodError) { console.error("Type: Validation Error"); try { console.error("Issues:", JSON.stringify(error.issues, null, 2)); } catch { console.error("Issues:", "[Could not stringify issues]"); } } else if (error instanceof Error) { console.error("Type: Error"); console.error("Message:", error.message); console.error("Stack:", error.stack || "No stack trace"); } else { console.error("Type: Unknown Error"); try { console.error("Error:", JSON.stringify(error)); } catch { console.error("Error:", String(error)); } } if (typeof console.groupEnd === "function") { console.groupEnd(); } } catch (logError) { // Fallback if logging itself fails console.error("Failed to log error:", logError); console.error("Original error:", error); } }, };