UNPKG

tiny-server-essentials

Version:

A good utility toolkit to unify Express v5 and Socket.IO v4 into a seamless development experience with modular helpers, server wrappers, and WebSocket tools.

413 lines 18.4 kB
export default TinyExpress; export type Request = import("express").Request; export type HttpStatusCode = number; export type IPExtractor = (req: Request) => string[]; export type DomainValidator = (req: Request) => boolean; /** * Represents the structured data extracted from an HTTP Origin header. */ export type OriginData = { /** * - The raw Origin header value. */ raw: string | null; /** * - The protocol used (e.g., 'http' or 'https'). */ protocol?: string | undefined; /** * - The hostname extracted from the origin. */ hostname?: string | undefined; /** * - The port number (explicit or default based on protocol). */ port?: string | undefined; /** * - The full reconstructed URL from the origin. */ full?: string | undefined; /** * - Any parsing error encountered while processing the origin. */ error?: string | undefined; }; /** @typedef {import('express').Request} Request */ /** * @typedef {number} HttpStatusCode */ /** * @typedef {(req: Request) => string[]} IPExtractor */ /** * @typedef {(req: Request) => boolean} DomainValidator */ /** * Represents the structured data extracted from an HTTP Origin header. * * @typedef {Object} OriginData * @property {string|null} raw - The raw Origin header value. * @property {string} [protocol] - The protocol used (e.g., 'http' or 'https'). * @property {string} [hostname] - The hostname extracted from the origin. * @property {string} [port] - The port number (explicit or default based on protocol). * @property {string} [full] - The full reconstructed URL from the origin. * @property {string} [error] - Any parsing error encountered while processing the origin. */ /** * TinyExpress provides a simple wrapper and factory for Express v5, * offering utilities and enhanced middleware management. * * This class is ideal for quickly spinning up an Express app with * strongly-typed middleware and error-handling support. * * @class */ declare class TinyExpress { /** * Creates and initializes a new TinyExpress instance. * * This wrapper extends the base Express application with support for domain-based request validation, * automatic middleware injection, and customizable validator logic. * * When instantiated, the following behaviors are applied: * - Injects a middleware to validate incoming requests using the active domain validator (based on `#domainTypeChecker`). * If the validator does not exist or the domain is invalid, a 403 Forbidden error is triggered. * - Automatically registers the default loopback domains: `localhost`, `127.0.0.1`, and `::1`. * - Registers default domain validators for `x-forwarded-host`, `hostname`, and `host` headers. * * @constructor * @param {ExpressApp} [app=express()] - An optional existing Express application instance. * If not provided, a new instance is created using `express()`. */ constructor(app?: express.Application); root: express.Application; /** * Modifies a CSRF config option, only if the key exists and value is a string. * @param {string} key - Either "cookieName", "headerName", or "errMessage". * @param {string} value - The new value to assign. */ setCsrfOption(key: string, value: string): void; /** * Sets the refresh interval in milliseconds for CSRF tokens. * @param {number|null} ms - Must be a positive number or null to disable. */ setCsrfRefreshInterval(ms: number | null): void; /** * Returns a shallow copy of the current CSRF config. * @returns {{ * refreshCookieName: string; * cookieName: string; * headerName: string; * errMessage: string; * enabled: boolean; * refreshInterval: number|null * }} */ geCsrftOptions(): { refreshCookieName: string; cookieName: string; headerName: string; errMessage: string; enabled: boolean; refreshInterval: number | null; }; /** * Middleware to set a CSRF token cookie if it's not already set or expired. * @param {number} [bytes=24] - Number of bytes to generate for the CSRF token. * @param {{ * httpOnly?: boolean, * sameSite?: 'lax' | 'strict' | 'none', * secure?: boolean * }} [options={}] */ installCsrfToken(bytes?: number, { httpOnly, sameSite, secure }?: { httpOnly?: boolean; sameSite?: "lax" | "strict" | "none"; secure?: boolean; }): void; /** * Middleware to verify that the request contains a valid CSRF token in the header. * @returns {RequestHandler} */ verifyCsrfToken(): express.RequestHandler<import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any>>; /** * Returns the current TinyWeb instance. * * @returns {TinyWebInstance} The active Http server. */ getWeb(): TinyWebInstance; /** * Returns the current Http server instance. * * @returns {HttpServer | HttpsServer} The active Http server. */ getServer(): HttpServer | HttpsServer; /** * Returns the Express app instance. * * @returns {import('express').Application} Express application instance. */ getRoot(): import("express").Application; /** * Init instance. * * @param {TinyWebInstance|HttpServer|HttpsServer} [web=new TinyWebInstance()] - An instance of TinyWebInstance. * * @throws {Error} If `web` is not an instance of TinyWebInstance. */ init(web?: TinyWebInstance | HttpServer | HttpsServer): void; /** @type {TinyWebInstance} */ web: TinyWebInstance; /** * Parses the Origin header from an Express request and extracts structured information. * * @param {Request} req - The Express request object. * @returns {OriginData} An object containing detailed parts of the origin header. */ getOrigin(req: Request): OriginData; /** * Registers a new IP extractor under a specific key. * * Each extractor must be a function that receives an Express `Request` and returns a string (IP) or null. * The key `"DEFAULT"` is reserved and cannot be used directly. * * @param {string} key * @param {IPExtractor} callback * @throws {Error} If the key is invalid or already registered. */ addIpExtractor(key: string, callback: IPExtractor): void; /** * Removes a registered IP extractor. * * Cannot remove the extractor currently in use unless it's set to "DEFAULT". * * @param {string} key * @throws {Error} If the key is invalid or in use. */ removeIpExtractor(key: string): void; /** * Returns a shallow clone of the current extractors. * * @returns {{ [key: string]: IPExtractor }} */ getIpExtractors(): { [key: string]: IPExtractor; }; /** * Sets the currently active extractor key. * * @param {string} key * @throws {Error} If the key is not found. */ setActiveIpExtractor(key: string): void; /** * Returns the current extractor function based on the active key. * * @returns {IPExtractor} */ getActiveExtractor(): IPExtractor; /** * Extracts the IP address from a request using the active extractor. * @param {Request} req * @returns {string[]} */ extractIp(req: Request): string[]; /** * Registers a new domain validator under a specific key. * * Each validator must be a function that receives an Express `Request` object and returns a boolean. * The key `"ALL"` is reserved and cannot be used as a validator key. * * @param {string} key - The key name identifying the validator (e.g., 'host', 'x-forwarded-host'). * @param {DomainValidator} callback - The validation function to be added. * @throws {Error} If the key is not a string. * @throws {Error} If the key is "ALL". * @throws {Error} If the callback is not a function. * @throws {Error} If a validator with the same key already exists. */ addDomainValidator(key: string, callback: DomainValidator): void; /** * Removes a registered domain validator by its key. * * Cannot remove the validator currently being used by the domain type checker, * unless the type checker is set to "ALL". * * @param {string} key - The key name of the validator to remove. * @throws {Error} If the key is not a string. * @throws {Error} If no validator is found under the given key. * @throws {Error} If the validator is currently in use by the domain type checker. */ removeDomainValidator(key: string): void; /** * Returns a shallow clone of the current domain validators map. * * The returned object maps each key to its corresponding validation function. * * @returns {{ [key: string]: DomainValidator }} A cloned object of the validators. */ getDomainValidators(): { [key: string]: DomainValidator; }; /** * Sets the current domain validation strategy by key name. * * The provided key must exist in the registered domain validators, * or be the string `"ALL"` to enable all validators simultaneously (not recommended). * * @param {string} key - The key of the validator to use (e.g., 'hostname', 'x-forwarded-host'), or 'ALL'. * @throws {Error} If the key is not a string. * @throws {Error} If the key is not found among the validators and is not 'ALL'. */ setDomainTypeChecker(key: string): void; /** * Retrieves the HTTP status message for a given status code. * * @param {number|string} code - The HTTP status code to look up. * @returns {string} The corresponding HTTP status message. * @throws {Error} If the status code is not found. */ getHttpStatusMessage(code: number | string): string; /** * Checks whether a given HTTP status code is registered. * * @param {number|string} code - The HTTP status code to check. * @returns {boolean} `true` if the status code exists, otherwise `false`. */ hasHttpStatusMessage(code: number | string): boolean; /** * Adds a new HTTP status code and message to the list. * Does not allow overwriting existing codes. * * @param {number|string} code - The HTTP status code to add. * @param {string} message - The message associated with the code. * @throws {Error} If the code already exists. * @throws {Error} If the code is not a number or string. * @throws {Error} If the message is not a string. */ addHttpCode(code: number | string, message: string): void; /** * Sends an HTTP response with the given status code. * If a callback is provided, it will be called instead of sending an empty response. * * @param {import('express').Response} res - Express response object. * @param {number} code - HTTP status code to send. * * @returns {import('express').Response} The result of `res.send()` or the callback function. * * @example * appManager.send(res, 404); // Sends 404 Not Found with empty body */ sendHttpError(res: import("express").Response, code: number): import("express").Response; /** * Installs default error-handling middleware into the Express app instance. * * This includes: * - A catch-all 404 handler that throws a `HttpError` when no routes match. * - A global error handler that responds with a JSON-formatted error response, * including the stack trace in development environments. * * @param {Object} [options={}] * @param {string} [options.notFoundMsg='Page not found.'] * @param {function(HttpStatusCode, HttpError, Request, Response): any} [options.errNext] */ installErrors({ notFoundMsg, errNext, }?: { notFoundMsg?: string | undefined; errNext?: ((arg0: HttpStatusCode, arg1: createHttpError.HttpError<number>, arg2: Request, arg3: express.Response<any, Record<string, any>>) => any) | undefined; }): void; /** * Express middleware for basic HTTP authentication. * * Validates the `Authorization` header against provided login credentials. * If credentials match, the request proceeds to the next middleware. * Otherwise, responds with HTTP 401 Unauthorized. * * @param {Request} req - Express request object. * @param {Response} res - Express response object. * @param {NextFunction} next - Express next middleware function. * @param {Object} [options={}] - Optional configuration object. * @param {string} [options.login] - Expected username for authentication. * @param {string} [options.password] - Expected password for authentication. * @param {RequestHandler|null} [options.nextError] - Optional error handler middleware called on failed auth. * @param {(login: string, password: string) => boolean|Promise<boolean>} [options.validator] - Optional function to validate credentials. */ authRequest(req: Request, res: express.Response<any, Record<string, any>>, next: express.NextFunction, { login, password, nextError, validator }?: { login?: string | undefined; password?: string | undefined; nextError?: express.RequestHandler<import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any>> | null | undefined; validator?: ((login: string, password: string) => boolean | Promise<boolean>) | undefined; }): Promise<void>; /** * Sends a file response with appropriate headers. * * This function sends a file (as a Buffer) directly in the HTTP response, * setting standard headers such as Content-Type, Cache-Control, Last-Modified, and Content-Disposition. * * @param {Response} res - The HTTP response object to send the file through. * @param {Object} [options={}] - Configuration options for the file response. * @param {string} [options.contentType='text/plain'] - The MIME type of the file being sent. * @param {number} [options.fileMaxAge=0] - Max age in seconds for the Cache-Control header. * @param {Buffer} [options.file] - The file contents to send as a buffer. Required. * @param {Date | number | string | null} [options.lastModified] - The last modification time for the Last-Modified header. * @param {string | null} [options.fileName] - Optional file name for the Content-Disposition header. * @throws {Error} If required options are missing or invalid. * @beta */ sendFile(res: express.Response<any, Record<string, any>>, { contentType, fileMaxAge, file, lastModified, fileName }?: { contentType?: string | undefined; fileMaxAge?: number | undefined; file?: Buffer<ArrayBufferLike> | undefined; lastModified?: string | number | Date | null | undefined; fileName?: string | null | undefined; }): void; /** * Streams a file response with support for range headers (video/audio streaming). * * This function streams a file or provided readable stream to the client, supporting HTTP range requests. * It is useful for serving large media files where partial content responses are required. * * @param {Request} req - The HTTP request object, used to detect range headers. * @param {Response} res - The HTTP response object to stream the file through. * @param {Object} [options={}] - Configuration options for streaming. * @param {boolean} [options.rangeOnlyMode=false] - When enabled, prevents full file streaming and enforces HTTP Range-based partial responses only. * @param {string} [options.filePath] - The absolute file path to stream. Required if no stream is provided. * @param {ReadableStream} [options.stream] - A readable stream to use instead of reading from filePath. * @param {string} [options.contentType='application/octet-stream'] - The MIME type of the streamed content. * @param {number} [options.fileMaxAge=0] - Max age in seconds for the Cache-Control header. * @param {Date | number | string | null} [options.lastModified] - The last modification time for the Last-Modified header. * @param {string | null} [options.fileName] - Optional file name for the Content-Disposition header. * @beta */ streamFile(req: Request, res: express.Response<any, Record<string, any>>, { filePath, stream, contentType, fileMaxAge, lastModified, fileName, rangeOnlyMode, }?: { rangeOnlyMode?: boolean | undefined; filePath?: string | undefined; stream?: ReadableStream | undefined; contentType?: string | undefined; fileMaxAge?: number | undefined; lastModified?: string | number | Date | null | undefined; fileName?: string | null | undefined; }): Promise<void>; /** * Enables a lightweight test-only Express mode for serving static files and open API testing. * * This method sets up an unrestricted CORS environment and exposes a static folder, * allowing any origin to access the content and APIs freely. It also includes permissive * CORS headers and custom middleware headers for development diagnostics. * * ⚠️ **Do not use this in production!** * This mode disables all security measures and is intended **only** for local development, * debugging, or experimentation. All origins, headers, and methods are allowed without validation. * * @throws {Error} If the current environment is not "development". * @throws {TypeError} If `folder` is not a non-empty string. * * @param {string} folder - The path to the folder that will be served as static content. */ freeMode(folder: string): void; #private; } import express from 'express'; import TinyWebInstance from './TinyWebInstance.mjs'; import { Server as HttpServer } from 'http'; import { Server as HttpsServer } from 'https'; import createHttpError from 'http-errors'; import { Readable as ReadableStream } from 'stream'; //# sourceMappingURL=TinyExpress.d.mts.map