Files
dashcaddy/dashcaddy-api/src/utilities/errors.js
T
Hermes 7bc2a207f3 DC-005: Fix all 138 broken test paths after src/ refactor
After the DC-005 module reorganization (41 files moved into src/ subdirs),
138 test suites failed because the refactor script's path-rewrite logic
missed three categories:

1. Files inside src/ doing 'require("./src/...")' — should be 'require("../...")'
2. Files in src/X/Y/ doing 'require("../../../src/...")' — should be 'require("../../...")'
3. Test files in __tests__/ with leftover 'require("../../../src/...")' paths

Root cause: the original refactor script ran before all files were moved,
so it computed relative paths against stale filesystem state.

Result:
- 30/30 test suites pass
- 879/879 tests pass (was: 18/30 suites, 614/687 tests)

Also fixed:
- routes/apps/restore.js: wrong responses import path
- routes/*/*.js: '../../src/utilities/X' → '../src/utilities/X' (depth 2 routes)
2026-06-13 12:16:56 -07:00

106 lines
2.5 KiB
JavaScript

/**
* DashCaddy API Error Classes
* All errors inherit from AppError and provide consistent structure.
*/
class AppError extends Error {
constructor(message, statusCode = 500, code = null) {
super(message);
this.name = this.constructor.name;
this.statusCode = statusCode;
this.code = code || this.constructor.name.toUpperCase().replace(/ERROR$/, '_ERROR');
this.isOperational = true; // Distinguishes from programming errors
}
}
// 4xx Client Errors
class ValidationError extends AppError {
constructor(message, field = null) {
super(message, 400, 'DC-400');
this.field = field;
}
}
class AuthenticationError extends AppError {
constructor(message = 'Authentication required', requiresTotp = false) {
super(message, 401, 'DC-401');
this.requiresTotp = requiresTotp;
}
}
class ForbiddenError extends AppError {
constructor(message = 'Forbidden') {
super(message, 403, 'DC-403');
}
}
class NotFoundError extends AppError {
constructor(resource = 'Resource') {
super(`${resource} not found`, 404, 'DC-404');
this.resource = resource;
}
}
class ConflictError extends AppError {
constructor(message, conflictingResource = null) {
super(message, 409, 'DC-409');
this.conflictingResource = conflictingResource;
}
}
class RateLimitError extends AppError {
constructor(retryAfter = 60) {
super('Rate limit exceeded', 429, 'DC-429');
this.retryAfter = retryAfter;
}
}
// 5xx Server Errors
class DockerError extends AppError {
constructor(message, operation = null, details = {}) {
super(message, 500, 'DC-500-DOCKER');
this.operation = operation;
this.details = details;
}
}
class CaddyError extends AppError {
constructor(message, operation = null, details = {}) {
super(message, 502, 'DC-502-CADDY');
this.operation = operation;
this.details = details;
}
}
class DNSError extends AppError {
constructor(message, operation = null, details = {}) {
super(message, 502, 'DC-502-DNS');
this.operation = operation;
this.details = details;
}
}
class ServiceUnavailableError extends AppError {
constructor(service, retryAfter = null) {
super(`Service unavailable: ${service}`, 503, 'DC-503');
this.service = service;
this.retryAfter = retryAfter;
}
}
module.exports = {
AppError,
ValidationError,
AuthenticationError,
ForbiddenError,
NotFoundError,
ConflictError,
RateLimitError,
DockerError,
CaddyError,
DNSError,
ServiceUnavailableError
};