import { NotFoundError, ConflictError } from "@cfdm/db"; import { ValidationError } from "@cfdm/shared"; export type ErrorCode = | "NOT_FOUND" | "VALIDATION_ERROR" | "UNAUTHORIZED" | "FORBIDDEN" | "CONFLICT" | "CLOUDFLARE_ERROR" | "DNS_UPDATE_FAILED" | "HEALTHCHECK_CREATE_FAILED" | "ZONE_NOT_FOUND" | "INVALID_IP" | "INVALID_HOSTNAME" | "RATE_LIMITED" | "CLOUDFLARE_AUTH_FAILED" | "SYNC_FAILED" | "INTERNAL_ERROR"; export class AppError extends Error { constructor( public readonly code: ErrorCode, message: string, public readonly statusCode: number, ) { super(message); this.name = "AppError"; } static notFound(message: string) { return new AppError("NOT_FOUND", message, 404); } static validation(message: string) { return new AppError("VALIDATION_ERROR", message, 400); } static unauthorized() { return new AppError("UNAUTHORIZED", "unauthorized", 401); } static forbidden(message = "forbidden") { return new AppError("FORBIDDEN", message, 403); } static conflict(message: string) { return new AppError("CONFLICT", message, 409); } static cloudflare(message: string) { return new AppError("CLOUDFLARE_ERROR", message, 502); } static dnsUpdateFailed(message: string) { return new AppError( "DNS_UPDATE_FAILED", message, 502, ); } static healthcheckCreateFailed(message: string) { return new AppError("HEALTHCHECK_CREATE_FAILED", message, 502); } static zoneNotFound(message = "зона Cloudflare не найдена") { return new AppError("ZONE_NOT_FOUND", message, 404); } static invalidIp(message = "Некорректный IP-адрес") { return new AppError("INVALID_IP", message, 400); } static invalidHostname(message = "Некорректное имя хоста") { return new AppError("INVALID_HOSTNAME", message, 400); } static rateLimited(message = "Cloudflare временно ограничил запросы. Повторите попытку.") { return new AppError("RATE_LIMITED", message, 429); } static cloudflareAuthFailed(message = "Cloudflare отклонил токен доступа") { return new AppError("CLOUDFLARE_AUTH_FAILED", message, 401); } static syncFailed(message: string) { return new AppError("SYNC_FAILED", message, 502); } static internal(message: string) { return new AppError("INTERNAL_ERROR", message, 500); } } export function toAppError(err: unknown): AppError { if (err instanceof AppError) return err; if (err instanceof NotFoundError) return AppError.notFound(err.message); if (err instanceof ConflictError) return AppError.conflict(err.message); if (err instanceof ValidationError) return AppError.validation(err.message); if (err instanceof Error) return AppError.internal(err.message); return AppError.internal(String(err)); } export function errorBody(err: AppError) { return { error: { code: err.code, message: err.message, }, }; }