| |
| |
| |
|
|
|
|
| import type { ErrorResponse } from '../types'
|
|
|
| |
| |
|
|
| export class AppError extends Error {
|
| public readonly statusCode: number
|
| public readonly isOperational: boolean
|
| public readonly details?: any
|
|
|
| constructor(
|
| message: string,
|
| statusCode: number = 500,
|
| isOperational: boolean = true,
|
| details?: any
|
| ) {
|
| super(message)
|
| this.statusCode = statusCode
|
| this.isOperational = isOperational
|
| this.details = details
|
|
|
|
|
| Object.setPrototypeOf(this, new.target.prototype)
|
| Error.captureStackTrace(this)
|
| }
|
|
|
| |
| |
|
|
| toJSON(): ErrorResponse {
|
| return {
|
| error: this.message,
|
| details: this.details,
|
| statusCode: this.statusCode
|
| }
|
| }
|
| }
|
|
|
| |
| |
|
|
| export class ValidationError extends AppError {
|
| constructor(message: string, details?: any) {
|
| super(message, 400, true, details)
|
| this.name = 'ValidationError'
|
| }
|
| }
|
|
|
| |
| |
|
|
| export class NotFoundError extends AppError {
|
| constructor(message: string = 'Resource not found', details?: any) {
|
| super(message, 404, true, details)
|
| this.name = 'NotFoundError'
|
| }
|
| }
|
|
|
| |
| |
|
|
| export class AuthenticationError extends AppError {
|
| constructor(message: string = 'Authentication required', details?: any) {
|
| super(message, 401, true, details)
|
| this.name = 'AuthenticationError'
|
| }
|
| }
|
|
|
| |
| |
|
|
| export class ForbiddenError extends AppError {
|
| constructor(message: string = 'Access forbidden', details?: any) {
|
| super(message, 403, true, details)
|
| this.name = 'ForbiddenError'
|
| }
|
| }
|
|
|
| |
| |
|
|
| export class ConflictError extends AppError {
|
| constructor(message: string, details?: any) {
|
| super(message, 409, true, details)
|
| this.name = 'ConflictError'
|
| }
|
| }
|
|
|
| |
| |
|
|
| export class InternalError extends AppError {
|
| constructor(message: string = 'Internal server error', details?: any) {
|
| super(message, 500, false, details)
|
| this.name = 'InternalError'
|
| }
|
| }
|
|
|
| |
| |
|
|
| export class ServiceUnavailableError extends AppError {
|
| constructor(message: string = 'Service temporarily unavailable', details?: any) {
|
| super(message, 503, true, details)
|
| this.name = 'ServiceUnavailableError'
|
| }
|
| }
|
|
|
| |
| |
|
|
| export class TimeoutError extends AppError {
|
| constructor(message: string = 'Request timeout', details?: any) {
|
| super(message, 504, true, details)
|
| this.name = 'TimeoutError'
|
| }
|
| }
|
|
|
| |
| |
|
|
| export class JobCancelledError extends AppError {
|
| constructor(message: string = 'Job cancelled', details?: any) {
|
| super(message, 499, true, details)
|
| this.name = 'JobCancelledError'
|
| }
|
| }
|
|
|
| |
| |
|
|
| export function isAppError(error: any): error is AppError {
|
| return error instanceof AppError
|
| }
|
|
|
| |
| |
|
|
| export function isOperationalError(error: any): boolean {
|
| if (isAppError(error)) {
|
| return error.isOperational
|
| }
|
| return false
|
| }
|
|
|
| |
| |
|
|
| export function formatError(error: any): ErrorResponse {
|
| if (isAppError(error)) {
|
| return error.toJSON()
|
| }
|
|
|
|
|
| if (error.name === 'ZodError') {
|
| return {
|
| error: 'Validation failed',
|
| details: error.errors,
|
| statusCode: 400
|
| }
|
| }
|
|
|
|
|
| return {
|
| error: error.message || 'Internal server error',
|
| statusCode: 500
|
| }
|
| }
|
|
|
| |
| |
|
|
| export function getStatusCode(error: any): number {
|
| if (isAppError(error)) {
|
| return error.statusCode
|
| }
|
| if (error.name === 'ZodError') {
|
| return 400
|
| }
|
| return 500
|
| } |