exstack
Version:
A utility library designed to simplify and enhance express.js applications.
672 lines (671 loc) • 21.5 kB
text/typescript
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 };