import { HttpException } from '@nestjs/common'; import { Prisma } from '../../generated/prisma/client'; import { AppError } from './app-error'; import type { ErrorCode } from './error-catalog'; export function classifyError(error: unknown): AppError { if (error instanceof AppError) return error; if (error instanceof Prisma.PrismaClientKnownRequestError) { const codes: Record = { P2002: 'RECORD_CONFLICT', P2003: 'REFERENCE_INVALID', P2004: 'DATA_CONSTRAINT', P2025: 'RECORD_NOT_FOUND', P2024: 'DATABASE_BUSY', P2028: 'DATABASE_BUSY', P2034: 'TRANSACTION_CONFLICT', }; return new AppError(codes[error.code] ?? 'INTERNAL_FAILURE', error.code); } if (error instanceof Prisma.PrismaClientInitializationError) return new AppError('DATABASE_BUSY'); if (error instanceof HttpException) { const codes: Record = { 400: 'REQUEST_MALFORMED', 401: 'AUTH_REQUIRED', 403: 'ACCESS_DENIED', 404: 'ROUTE_NOT_FOUND', 413: 'REQUEST_TOO_LARGE', 429: 'RATE_LIMITED', 503: 'DATABASE_BUSY', }; return new AppError(codes[error.getStatus()] ?? 'INTERNAL_FAILURE'); } // Express parser errors are not Nest HttpExceptions. if (typeof error === 'object' && error !== null && 'type' in error) { if (error.type === 'entity.too.large') return new AppError('REQUEST_TOO_LARGE'); if (error.type === 'entity.parse.failed') return new AppError('REQUEST_MALFORMED'); } return new AppError('INTERNAL_FAILURE'); }