import { type ErrorStatus, isClientErrorStatus, Status, STATUS_TEXT,} from "./http_status.ts";
const ERROR_STATUS_MAP = { "BadRequest": 400, "Unauthorized": 401, "PaymentRequired": 402, "Forbidden": 403, "NotFound": 404, "MethodNotAllowed": 405, "NotAcceptable": 406, "ProxyAuthRequired": 407, "RequestTimeout": 408, "Conflict": 409, "Gone": 410, "LengthRequired": 411, "PreconditionFailed": 412, "RequestEntityTooLarge": 413, "RequestURITooLong": 414, "UnsupportedMediaType": 415, "RequestedRangeNotSatisfiable": 416, "ExpectationFailed": 417, "Teapot": 418, "MisdirectedRequest": 421, "UnprocessableEntity": 422, "Locked": 423, "FailedDependency": 424, "UpgradeRequired": 426, "PreconditionRequired": 428, "TooManyRequests": 429, "RequestHeaderFieldsTooLarge": 431, "UnavailableForLegalReasons": 451, "InternalServerError": 500, "NotImplemented": 501, "BadGateway": 502, "ServiceUnavailable": 503, "GatewayTimeout": 504, "HTTPVersionNotSupported": 505, "VariantAlsoNegotiates": 506, "InsufficientStorage": 507, "LoopDetected": 508, "NotExtended": 510, "NetworkAuthenticationRequired": 511,} as const;
export type ErrorStatusKeys = keyof typeof ERROR_STATUS_MAP;
export interface HttpErrorOptions extends ErrorOptions { expose?: boolean; headers?: HeadersInit;}
export class HttpError extends Error { #status: ErrorStatus = Status.InternalServerError; #expose: boolean; #headers?: Headers; constructor( message = "Http Error", options?: HttpErrorOptions, ) { super(message, options); this.#expose = options?.expose === undefined ? isClientErrorStatus(this.status) : options.expose; if (options?.headers) { this.#headers = new Headers(options.headers); } } get expose(): boolean { return this.#expose; } get headers(): Headers | undefined { return this.#headers; } get status(): ErrorStatus { return this.#status; }}
function createHttpErrorConstructor(status: ErrorStatus): typeof HttpError { const name = `${Status[status]}Error`; const ErrorCtor = class extends HttpError { constructor( message = STATUS_TEXT[status], options?: HttpErrorOptions, ) { super(message, options); Object.defineProperty(this, "name", { configurable: true, enumerable: false, value: name, writable: true, }); }
override get status() { return status; } }; return ErrorCtor;}
export const errors: Record<ErrorStatusKeys, typeof HttpError> = {} as Record< ErrorStatusKeys, typeof HttpError>;
for (const [key, value] of Object.entries(ERROR_STATUS_MAP)) { errors[key as ErrorStatusKeys] = createHttpErrorConstructor(value);}
export function createHttpError( status: ErrorStatus = Status.InternalServerError, message?: string, options?: HttpErrorOptions,): HttpError { return new errors[Status[status] as ErrorStatusKeys](message, options);}
export function isHttpError(value: unknown): value is HttpError { return value instanceof HttpError;}