OverviewFilesCommitsIssuesDocsReleasesPeers

hyper-booking / lib / errors.js

84 lines · javascript ref:
/**
 * Error Classes for hyper-booking
 * Adapted from hypernote/pear-git pattern.
 */

export class AppError extends Error {
  constructor (message, code, status = 500) {
    super(message)
    this.name = 'AppError'
    this.code = code
    this.status = status
    this.timestamp = Date.now()
    if (Error.captureStackTrace) {
      Error.captureStackTrace(this, this.constructor)
    }
  }

  toJSON () {
    return { error: this.message, code: this.code, status: this.status }
  }
}

export class NotFoundError extends AppError {
  constructor (message = 'Not found', resource = null) {
    super(message, 'NOT_FOUND', 404)
    this.name = 'NotFoundError'
    this.resource = resource
  }

  toJSON () {
    return { ...super.toJSON(), resource: this.resource }
  }
}

export class ForbiddenError extends AppError {
  constructor (message = 'Forbidden', requiredPermission = null) {
    super(message, 'FORBIDDEN', 403)
    this.name = 'ForbiddenError'
    this.requiredPermission = requiredPermission
  }
}

export class UnauthorizedError extends AppError {
  constructor (message = 'Authentication required') {
    super(message, 'UNAUTHORIZED', 401)
    this.name = 'UnauthorizedError'
  }
}

export class ValidationError extends AppError {
  constructor (message, field = null) {
    super(message, 'VALIDATION_ERROR', 400)
    this.name = 'ValidationError'
    this.field = field
  }
}

export class ConflictError extends AppError {
  constructor (message = 'Resource conflict') {
    super(message, 'CONFLICT', 409)
    this.name = 'ConflictError'
  }
}

export class RateLimitError extends AppError {
  constructor (message = 'Rate limit exceeded', retryAfter = null) {
    super(message, 'RATE_LIMIT', 429)
    this.name = 'RateLimitError'
    this.retryAfter = retryAfter
  }
}

export function isAppError (err) {
  return err instanceof AppError
}

export function wrapError (err, defaultMessage = 'An error occurred') {
  if (err instanceof AppError) return err
  const wrapped = new AppError(err.message || defaultMessage, 'INTERNAL_ERROR', 500)
  wrapped.originalError = err
  wrapped.stack = err.stack
  return wrapped
}