import Server from './../Server.js'; import { RouterConfig } from '../../Router.js'; /** * Represents a Proxy class that handles routing and server functionality. */ export default class Proxy { /** * A boolean flag indicating whether the process is currently stopping or not. */ private stopping; /** * The configuration object for the router. */ private readonly config; /** * The logger instance for structured logging. * @readonly * @type {Logger} */ private readonly logger; /** * The Express application instance for the server. * @readonly * @type {express.Express} */ private readonly app; /** * The handler function for serverless events in the Server class. * @param {ServerlessEvent} event - The serverless event object. * @returns None */ private readonly serverlessHandler; /** * Route resolver used to identify per-route rate limit configuration. * @private * @readonly */ private readonly routeResolver; /** * Represents a listener for an HTTP server. * @private * @type {HTTPServer} */ private listener; /** * Shared Redis client resolved from the WAPI cache configuration when * rate limiting is configured to use Redis. * @private */ private rateLimitRedisClient?; /** * Constructs a new instance of the Router class. * @param {RouterConfig} config - The configuration object for the router. * @param {Server['handleServerlessEvent']} serverlessHandler - The handler function for serverless events. * @returns None */ constructor(config: RouterConfig, serverlessHandler: Server['handleServerlessEvent']); /** * Loads the necessary components and initializes the application. * @returns None */ load(): Promise; /** * Initializes global rate limiting and resolves any shared Redis client * required by the configured store. * @returns {Promise} * @private */ private initializeRateLimiting; /** * Unloads the current module, stopping any active listeners. * @param {any} [err] - Optional error object to pass to the stopListeners method. * @returns {Promise} - A promise that resolves once the listeners have been stopped. */ unload(err?: any): Promise; /** * Starts the listeners for the proxy server. * @returns {Promise} A promise that resolves when the listeners have started. */ private startListeners; /** * Stops the listeners and exits the process. * @param {any} [err] - Optional error object. * @returns {Promise} - A promise that resolves when the listeners are stopped and the process is exited. */ private stopListeners; /** * Installs the routes for the proxy server. * @returns None */ private installRoutes; /** * Creates rate limiting middleware from a per-route {@link RateLimitConfig}, * inheriting the global Redis store configuration when available so all * rate-limit counters share the same Redis connection. * @param {RateLimitConfig} config - The per-route rate limit configuration * @returns {express.RequestHandler} Express middleware for rate limiting * @private */ private createRouteRateLimitMiddleware; /** * Creates rate limiting middleware based on the provided configuration. * @param {GlobalRateLimitConfig} config - The rate limit configuration * @returns {express.RequestHandler} Express middleware for rate limiting * @private */ private createRateLimitMiddleware; /** * Creates the appropriate store for rate limiting based on configuration. * * Cluster mode note: `rate-limit-redis` v4 uses EVALSHA (Lua script). In cluster * mode a plain `SCRIPT LOAD` only reaches one master node, so any subsequent * EVALSHA that routes to a different node gets a NOSCRIPT error — and if the * SHA1 is still `undefined` at the time of the call (async loading race) the * Redis encoder crashes with `Cannot read properties of undefined (reading 'length')`. * We detect a cluster client and broadcast SCRIPT LOAD to every master node so * the script is resident everywhere before the first EVALSHA arrives. * * @param {GlobalRateLimitConfig} config - The rate limit configuration * @returns {RedisStore | undefined} Redis store if configured, undefined for in-memory * @private */ private createRateLimitStore; }