UNPKG

exstack

Version:

A utility library designed to simplify and enhance express.js applications.

672 lines (671 loc) 21.5 kB
import { ErrorRequestHandler, NextFunction, Request, RequestHandler, Response, Router } from "express"; //#region src/status.d.ts /** * Enum representing HTTP status codes. * * @publicApi http-status code */ declare const HttpStatus: Readonly<{ CONTINUE: 100; SWITCHING_PROTOCOLS: 101; PROCESSING: 102; EARLY_HINTS: 103; OK: 200; CREATED: 201; ACCEPTED: 202; NON_AUTHORITATIVE_INFORMATION: 203; NO_CONTENT: 204; RESET_CONTENT: 205; PARTIAL_CONTENT: 206; MULTI_STATUS: 207; ALREADY_REPORTED: 208; IM_USED: 226; MULTIPLE_CHOICES: 300; MOVED_PERMANENTLY: 301; FOUND: 302; SEE_OTHER: 303; NOT_MODIFIED: 304; USE_PROXY: 305; UNUSED: 306; TEMPORARY_REDIRECT: 307; PERMANENT_REDIRECT: 308; BAD_REQUEST: 400; UNAUTHORIZED: 401; PAYMENT_REQUIRED: 402; FORBIDDEN: 403; NOT_FOUND: 404; METHOD_NOT_ALLOWED: 405; NOT_ACCEPTABLE: 406; PROXY_AUTHENTICATION_REQUIRED: 407; REQUEST_TIMEOUT: 408; CONFLICT: 409; GONE: 410; LENGTH_REQUIRED: 411; PRECONDITION_FAILED: 412; PAYLOAD_TOO_LARGE: 413; URI_TOO_LONG: 414; UNSUPPORTED_MEDIA_TYPE: 415; REQUESTED_RANGE_NOT_SATISFIABLE: 416; EXPECTATION_FAILED: 417; IM_A_TEAPOT: 418; MISDIRECTED_REQUEST: 421; UNPROCESSABLE_ENTITY: 422; LOCKED: 423; FAILED_DEPENDENCY: 424; TOO_EARLY: 425; UPGRADE_REQUIRED: 426; PRECONDITION_REQUIRED: 428; TOO_MANY_REQUESTS: 429; REQUEST_HEADER_FIELDS_TOO_LARGE: 431; UNAVAILABLE_FOR_LEGAL_REASONS: 451; INTERNAL_SERVER_ERROR: 500; NOT_IMPLEMENTED: 501; BAD_GATEWAY: 502; SERVICE_UNAVAILABLE: 503; GATEWAY_TIMEOUT: 504; HTTP_VERSION_NOT_SUPPORTED: 505; VARIANT_ALSO_NEGOTIATES: 506; INSUFFICIENT_STORAGE: 507; LOOP_DETECTED: 508; BANDWIDTH_LIMIT_EXCEEDED: 509; NOT_EXTENDED: 510; NETWORK_AUTHENTICATION_REQUIRED: 511; }>; //#endregion //#region src/types.d.ts type ValueOf<T> = T[keyof T]; type NumberOf<K> = Extract<K, number>; type HttpStatusCode = NumberOf<ValueOf<typeof HttpStatus>>; /** Informational & Success (1xx–2xx) */ type SuccessStatusCode = 100 | 101 | 102 | 103 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 226; /** Redirect (3xx) */ type RedirectStatusCode = 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308; /** Server Error (5xx) */ type ServerErrorStatusCode = 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511; /** * Client Error (4xx) * * Automatically derived by excluding all known 1xx, 2xx, 3xx, and 5xx codes. */ type ClientErrorStatusCode = Exclude<HttpStatusCode, SuccessStatusCode | RedirectStatusCode | ServerErrorStatusCode>; /** * Represents a standard Express-style route handler. * * @remarks * The handler may return: * - a plain value (string, object, etc.) * - an instance of {@link ApiRes} * - a `Promise` resolving to one of those values. * * The framework will automatically detect and send the result. */ type Handler = (req: Request, res: Response, next: NextFunction) => unknown | Promise<unknown>; //#endregion //#region src/helps/api-res.d.ts type Status$1 = Exclude<HttpStatusCode, ClientErrorStatusCode | ServerErrorStatusCode | RedirectStatusCode>; /** The structure of the HTTP response body. */ type HttpResBody = { result: any; status: number; message: string; }; /** ApiRes class for standardizing API responses. */ declare class ApiRes { private result; private status; private message; constructor(result?: any, status?: Status$1, message?: string); /** * Returns the Body (JSON) representation of the response. * @returns The Body (JSON) representation of the response * * @example * new ApiRes('Hello World', 200).body; */ get body(): HttpResBody; /** Set message (chainable) */ msg: (message: string) => ApiRes; /** Set result/data (chainable) */ data: (result: any) => ApiRes; /** * Send the json of HTTP response. * @param {Response} res - The Express response object. * * @example * new ApiRes('Hello World', 200).toJson(res); */ toJson: (res?: Response) => void; /** Clone self with a different status */ static status: (code: Status$1) => ApiRes; /** Creates an OK (200) response. */ static ok: (result: any, message?: string) => ApiRes; /** Creates a Created (201) response. */ static created: (result: any, message?: string) => ApiRes; /** Creates a paginated OK (200) response. */ static paginated: (data: any, meta: object, message?: string) => ApiRes; } //#endregion //#region src/helps/errors.d.ts type Message = string | string[]; type Status = ServerErrorStatusCode | ClientErrorStatusCode; type HttpErrorBody = { meta?: Record<string, unknown> | null; status: Status; message: Message; code?: string | null; error: string; }; /** * Base class for handling HTTP errors. * @extends {Error} */ declare class HttpError extends Error { readonly status: Status; readonly options: Pick<HttpErrorBody, 'message' | 'meta' | 'code'> & { cause?: unknown; }; /** * Creates an instance of `HTTPException`. * @param status - HTTP status code for the exception. Defaults to 500. * @param options - Additional options for the exception. */ constructor(status: Status | undefined, options: Pick<HttpErrorBody, 'message' | 'meta' | 'code'> & { cause?: unknown; }); /** * Check if the given error is an instance of HttpError. * @param {unknown} value - The error to check. * @returns {boolean} - True if the error is an instance of HttpError, false otherwise. * * @example * if (HttpError.isHttpError(error)) { * // Handle the HttpError * } */ static isHttpError: (value: unknown) => value is HttpError; /** * Convert the HttpError instance to a Body object. * @example * const errorBody = new HttpError(404, {message: 'Not Found'}).body; */ get body(): HttpErrorBody; /** * Send the json of the error in an HTTP response. * @param {Response} res - The Express response object. * * @example * new HttpError(404, {message: 'Not Found'}).toJson(res); */ toJson: (res: Response) => void; } /** * Utility function to create custom error classes. * @param status - HTTP status code. * @returns - A new error class. * @example * const NotFoundError = createHttpErrorClass(HttpStatus.NOT_FOUND); */ declare const createHttpErrorClass: (status: Status) => { new (message: Message, options?: { cause?: unknown; code?: string | null; meta?: Record<string, unknown> | null; }): { readonly status: Status; readonly options: Pick<HttpErrorBody, "message" | "meta" | "code"> & { cause?: unknown; }; /** * Convert the HttpError instance to a Body object. * @example * const errorBody = new HttpError(404, {message: 'Not Found'}).body; */ get body(): HttpErrorBody; /** * Send the json of the error in an HTTP response. * @param {Response} res - The Express response object. * * @example * new HttpError(404, {message: 'Not Found'}).toJson(res); */ toJson: (res: Response) => void; name: string; message: string; stack?: string; cause?: unknown; }; /** * Check if the given error is an instance of HttpError. * @param {unknown} value - The error to check. * @returns {boolean} - True if the error is an instance of HttpError, false otherwise. * * @example * if (HttpError.isHttpError(error)) { * // Handle the HttpError * } */ isHttpError: (value: unknown) => value is HttpError; isError(error: unknown): error is Error; captureStackTrace(targetObject: object, constructorOpt?: Function): void; prepareStackTrace(err: Error, stackTraces: NodeJS.CallSite[]): any; stackTraceLimit: number; }; /** * Represents a Bad Request HTTP error (400). * @extends {HttpError} */ declare const BadRequestError: { new (message: Message, options?: { cause?: unknown; code?: string | null; meta?: Record<string, unknown> | null; }): { readonly status: Status; readonly options: Pick<HttpErrorBody, "message" | "meta" | "code"> & { cause?: unknown; }; /** * Convert the HttpError instance to a Body object. * @example * const errorBody = new HttpError(404, {message: 'Not Found'}).body; */ get body(): HttpErrorBody; /** * Send the json of the error in an HTTP response. * @param {Response} res - The Express response object. * * @example * new HttpError(404, {message: 'Not Found'}).toJson(res); */ toJson: (res: Response) => void; name: string; message: string; stack?: string; cause?: unknown; }; /** * Check if the given error is an instance of HttpError. * @param {unknown} value - The error to check. * @returns {boolean} - True if the error is an instance of HttpError, false otherwise. * * @example * if (HttpError.isHttpError(error)) { * // Handle the HttpError * } */ isHttpError: (value: unknown) => value is HttpError; isError(error: unknown): error is Error; captureStackTrace(targetObject: object, constructorOpt?: Function): void; prepareStackTrace(err: Error, stackTraces: NodeJS.CallSite[]): any; stackTraceLimit: number; }; /** * Represents a Conflict HTTP error (409). * @extends {HttpError} */ declare const ConflictError: { new (message: Message, options?: { cause?: unknown; code?: string | null; meta?: Record<string, unknown> | null; }): { readonly status: Status; readonly options: Pick<HttpErrorBody, "message" | "meta" | "code"> & { cause?: unknown; }; /** * Convert the HttpError instance to a Body object. * @example * const errorBody = new HttpError(404, {message: 'Not Found'}).body; */ get body(): HttpErrorBody; /** * Send the json of the error in an HTTP response. * @param {Response} res - The Express response object. * * @example * new HttpError(404, {message: 'Not Found'}).toJson(res); */ toJson: (res: Response) => void; name: string; message: string; stack?: string; cause?: unknown; }; /** * Check if the given error is an instance of HttpError. * @param {unknown} value - The error to check. * @returns {boolean} - True if the error is an instance of HttpError, false otherwise. * * @example * if (HttpError.isHttpError(error)) { * // Handle the HttpError * } */ isHttpError: (value: unknown) => value is HttpError; isError(error: unknown): error is Error; captureStackTrace(targetObject: object, constructorOpt?: Function): void; prepareStackTrace(err: Error, stackTraces: NodeJS.CallSite[]): any; stackTraceLimit: number; }; /** * Represents a Forbidden HTTP error (403). * @extends {HttpError} */ declare const ForbiddenError: { new (message: Message, options?: { cause?: unknown; code?: string | null; meta?: Record<string, unknown> | null; }): { readonly status: Status; readonly options: Pick<HttpErrorBody, "message" | "meta" | "code"> & { cause?: unknown; }; /** * Convert the HttpError instance to a Body object. * @example * const errorBody = new HttpError(404, {message: 'Not Found'}).body; */ get body(): HttpErrorBody; /** * Send the json of the error in an HTTP response. * @param {Response} res - The Express response object. * * @example * new HttpError(404, {message: 'Not Found'}).toJson(res); */ toJson: (res: Response) => void; name: string; message: string; stack?: string; cause?: unknown; }; /** * Check if the given error is an instance of HttpError. * @param {unknown} value - The error to check. * @returns {boolean} - True if the error is an instance of HttpError, false otherwise. * * @example * if (HttpError.isHttpError(error)) { * // Handle the HttpError * } */ isHttpError: (value: unknown) => value is HttpError; isError(error: unknown): error is Error; captureStackTrace(targetObject: object, constructorOpt?: Function): void; prepareStackTrace(err: Error, stackTraces: NodeJS.CallSite[]): any; stackTraceLimit: number; }; /** * Represents a Not Found HTTP error (404). * @extends {HttpError} */ declare const NotFoundError: { new (message: Message, options?: { cause?: unknown; code?: string | null; meta?: Record<string, unknown> | null; }): { readonly status: Status; readonly options: Pick<HttpErrorBody, "message" | "meta" | "code"> & { cause?: unknown; }; /** * Convert the HttpError instance to a Body object. * @example * const errorBody = new HttpError(404, {message: 'Not Found'}).body; */ get body(): HttpErrorBody; /** * Send the json of the error in an HTTP response. * @param {Response} res - The Express response object. * * @example * new HttpError(404, {message: 'Not Found'}).toJson(res); */ toJson: (res: Response) => void; name: string; message: string; stack?: string; cause?: unknown; }; /** * Check if the given error is an instance of HttpError. * @param {unknown} value - The error to check. * @returns {boolean} - True if the error is an instance of HttpError, false otherwise. * * @example * if (HttpError.isHttpError(error)) { * // Handle the HttpError * } */ isHttpError: (value: unknown) => value is HttpError; isError(error: unknown): error is Error; captureStackTrace(targetObject: object, constructorOpt?: Function): void; prepareStackTrace(err: Error, stackTraces: NodeJS.CallSite[]): any; stackTraceLimit: number; }; /** * Represents an UnAuthorized HTTP error (401). * @extends {HttpError} */ declare const UnAuthorizedError: { new (message: Message, options?: { cause?: unknown; code?: string | null; meta?: Record<string, unknown> | null; }): { readonly status: Status; readonly options: Pick<HttpErrorBody, "message" | "meta" | "code"> & { cause?: unknown; }; /** * Convert the HttpError instance to a Body object. * @example * const errorBody = new HttpError(404, {message: 'Not Found'}).body; */ get body(): HttpErrorBody; /** * Send the json of the error in an HTTP response. * @param {Response} res - The Express response object. * * @example * new HttpError(404, {message: 'Not Found'}).toJson(res); */ toJson: (res: Response) => void; name: string; message: string; stack?: string; cause?: unknown; }; /** * Check if the given error is an instance of HttpError. * @param {unknown} value - The error to check. * @returns {boolean} - True if the error is an instance of HttpError, false otherwise. * * @example * if (HttpError.isHttpError(error)) { * // Handle the HttpError * } */ isHttpError: (value: unknown) => value is HttpError; isError(error: unknown): error is Error; captureStackTrace(targetObject: object, constructorOpt?: Function): void; prepareStackTrace(err: Error, stackTraces: NodeJS.CallSite[]): any; stackTraceLimit: number; }; /** * Represents an Internal Server Error HTTP error (500). * @extends {HttpError} */ declare const InternalServerError: { new (message: Message, options?: { cause?: unknown; code?: string | null; meta?: Record<string, unknown> | null; }): { readonly status: Status; readonly options: Pick<HttpErrorBody, "message" | "meta" | "code"> & { cause?: unknown; }; /** * Convert the HttpError instance to a Body object. * @example * const errorBody = new HttpError(404, {message: 'Not Found'}).body; */ get body(): HttpErrorBody; /** * Send the json of the error in an HTTP response. * @param {Response} res - The Express response object. * * @example * new HttpError(404, {message: 'Not Found'}).toJson(res); */ toJson: (res: Response) => void; name: string; message: string; stack?: string; cause?: unknown; }; /** * Check if the given error is an instance of HttpError. * @param {unknown} value - The error to check. * @returns {boolean} - True if the error is an instance of HttpError, false otherwise. * * @example * if (HttpError.isHttpError(error)) { * // Handle the HttpError * } */ isHttpError: (value: unknown) => value is HttpError; isError(error: unknown): error is Error; captureStackTrace(targetObject: object, constructorOpt?: Function): void; prepareStackTrace(err: Error, stackTraces: NodeJS.CallSite[]): any; stackTraceLimit: number; }; /** * Represents an Content Too Larger Error HTTP error (413). * @extends {HttpError} */ declare const ContentTooLargeError: { new (message: Message, options?: { cause?: unknown; code?: string | null; meta?: Record<string, unknown> | null; }): { readonly status: Status; readonly options: Pick<HttpErrorBody, "message" | "meta" | "code"> & { cause?: unknown; }; /** * Convert the HttpError instance to a Body object. * @example * const errorBody = new HttpError(404, {message: 'Not Found'}).body; */ get body(): HttpErrorBody; /** * Send the json of the error in an HTTP response. * @param {Response} res - The Express response object. * * @example * new HttpError(404, {message: 'Not Found'}).toJson(res); */ toJson: (res: Response) => void; name: string; message: string; stack?: string; cause?: unknown; }; /** * Check if the given error is an instance of HttpError. * @param {unknown} value - The error to check. * @returns {boolean} - True if the error is an instance of HttpError, false otherwise. * * @example * if (HttpError.isHttpError(error)) { * // Handle the HttpError * } */ isHttpError: (value: unknown) => value is HttpError; isError(error: unknown): error is Error; captureStackTrace(targetObject: object, constructorOpt?: Function): void; prepareStackTrace(err: Error, stackTraces: NodeJS.CallSite[]): any; stackTraceLimit: number; }; //#endregion //#region src/helps/handler.d.ts /** * Sends the result from a route handler to the client. * * - If `result` is an {@link ApiRes}, calls its `.toJson(res)` method. * - Otherwise, sends it directly (unless it *is* the response object itself). * * @param result - The value returned by a route handler. * @param res - The Express response object. */ declare const handleResult: (result: unknown, res: Response) => void; /** * Wraps a route handler (sync or async) and automatically: * - Invokes the handler with `(req, res, next)` * - Catches synchronous and asynchronous errors * - Passes any returned value into {@link handleResult} * * @param callback - A function that handles a request, returning a value or `Promise`. * @returns An Express-compatible request handler. * * @example * app.get('/ping', handler(async () => ApiRes.ok({ alive: true }).msg('Pong'))); * * @example * app.post('/login', handler(async (req, res) => { * const { username, password } = req.body; * return new ApiRes(200, { user: username }); * })); */ declare const handler: (callback: Handler) => (req: Request, res: Response, next: NextFunction) => Promise<void>; //#endregion //#region src/middle/x-powered.d.ts /** * Middleware to customize or override the `X-Powered-By` HTTP header. * Often used for branding or hiding technology stack. * * @param name - Value to be set for the `X-Powered-By` header */ declare const poweredBy: (name: string) => RequestHandler; //#endregion //#region src/middle/error-handler.d.ts /** * Express middleware to handle `HttpError` and unknown errors. * * - Sends JSON response for `HttpError` instances. * - Logs unknown errors and sends generic error response. * - Includes detailed error info in development (`isDev`). * * @param {Boolean} [isDev = true] - Flag to indicate if the environment is development. * @param {(error: unknown) => void} [logger = console.error] - Function to log errors. * @returns {ErrorRequestHandler} - Middleware for handling errors. * * @example * // Basic usage with default options: * app.use(errorHandler(process.env.NODE_ENV !== 'production')); * // Custom usage with a logging function in production mode: * app.use(errorHandler(conf.isDev, logger.error)); */ declare const errorHandler: (isDev?: boolean, logger?: (error: unknown) => void) => ErrorRequestHandler; /** * Middleware to handle 404 Not Found errors. * * This function creates an Express router that catches all requests to * undefined routes and returns a JSON response with a 404 error. * * @param {string} [path='*'] - The route pattern to match (default: '*'). * @returns {Router} Express router instance handling 404 errors. * * @example * app.use(notFound("*")) // v4 * app.use(notFound("*splat")) // v5 */ declare const notFound: (path: string) => Router; //#endregion export { ApiRes, BadRequestError, type ClientErrorStatusCode, ConflictError, ContentTooLargeError, ForbiddenError, type Handler, HttpError, HttpErrorBody, HttpResBody, HttpStatus, type HttpStatusCode, InternalServerError, NotFoundError, type RedirectStatusCode, type ServerErrorStatusCode, type SuccessStatusCode, UnAuthorizedError, createHttpErrorClass, errorHandler, handleResult, handler, notFound, poweredBy };