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
text/typescript
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