@stacksjs/error-handling
Version:
Type safe error handling.
1 lines • 3.76 kB
JavaScript
import{createErrorHandler,HTTP_ERRORS,renderProductionErrorPage}from"./error-page";export class HttpError extends Error{status;details;constructor(status,message,details){super(message);this.status=status;this.name=httpStatusName(status);if(details!==void 0)this.details=details}}function httpStatusName(status){switch(status){case 400:return"Bad Request";case 401:return"Unauthorized";case 402:return"Payment Required";case 403:return"Forbidden";case 404:return"Not Found";case 405:return"Method Not Allowed";case 408:return"Request Timeout";case 409:return"Conflict";case 410:return"Gone";case 413:return"Payload Too Large";case 415:return"Unsupported Media Type";case 422:return"Unprocessable Entity";case 423:return"Locked";case 425:return"Too Early";case 426:return"Upgrade Required";case 428:return"Precondition Required";case 429:return"Too Many Requests";case 431:return"Request Header Fields Too Large";case 451:return"Unavailable For Legal Reasons";case 500:return"Internal Server Error";case 501:return"Not Implemented";case 502:return"Bad Gateway";case 503:return"Service Unavailable";case 504:return"Gateway Timeout";case 507:return"Insufficient Storage";case 508:return"Loop Detected";case 511:return"Network Authentication Required";default:return status>=400&&status<500?"Client Error":"Server Error"}}export class HttpErrorHandler{handler=createErrorHandler();isDevelopment;constructor(options){this.isDevelopment=options?.isDevelopment??!0;if(options?.config)this.handler=createErrorHandler(options.config);this.handler.setFramework("Stacks")}setRequest(request){this.handler.setRequest(request);return this}setRouting(routing){this.handler.setRouting(routing);return this}addQuery(query,time,connection){this.handler.addQuery(query,time,connection);return this}async handle(error,status=500){if(this.isDevelopment)return this.handler.handleError(error,status);return new Response(renderProductionErrorPage(status),{status,headers:{"Content-Type":"text/html; charset=utf-8"}})}notFound(message){const error=new HttpError(404,message||"The requested resource could not be found.");return this.handle(error,404)}serverError(error){return this.handle(error,500)}forbidden(message){const error=new HttpError(403,message||"You do not have permission to access this resource.");return this.handle(error,403)}unauthorized(message){const error=new HttpError(401,message||"Authentication is required to access this resource.");return this.handle(error,401)}badRequest(message){const error=new HttpError(400,message||"The request was malformed or invalid.");return this.handle(error,400)}validationError(message){const error=new HttpError(422,message||"The request was well-formed but could not be processed.");return this.handle(error,422)}tooManyRequests(message){const error=new HttpError(429,message||"You have exceeded the rate limit.");return this.handle(error,429)}serviceUnavailable(message){const error=new HttpError(503,message||"The service is temporarily unavailable.");return this.handle(error,503)}}export function createHttpErrorHandler(options){return new HttpErrorHandler(options)}export async function renderHttpError(error,request,options){const handler=createHttpErrorHandler({isDevelopment:options?.isDevelopment,config:options?.config});if(request)handler.setRequest(request);return handler.handle(error,options?.status)}export function errorMiddleware(options){const handler=createHttpErrorHandler(options);return async(error,request)=>{handler.setRequest(request);let status=500;if(error instanceof HttpError)status=error.status;else if("status"in error&&typeof error.status==="number")status=error.status;else if("statusCode"in error&&typeof error.statusCode==="number")status=error.statusCode;return handler.handle(error,status)}}