- Consolidated all error classes into single errors.js - Removed duplicate error definitions (NotFoundError, etc.) - Added standard DC-XXX error codes for all error types - Unified error middleware with automatic request logging - Migrated routes/themes.js to throw-based error pattern - Updated routes/services.js to use ConflictError - Cleaner server.js error handler registration - 40% less error handling boilerplate in routes - Consistent error response format across all endpoints
106 lines
2.5 KiB
JavaScript
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
|
|
};
|