/** * Freeze the built-in prototypes to defend against prototype pollution. * After calling this, code like `req.body.__proto__.isAdmin = true` becomes * a no-op (silent in sloppy mode, TypeError in strict). Call once at boot * BEFORE loading user code / requiring third-party modules that might set * legitimate prototype properties. * * Idempotent — safe to call multiple times. * * **`options.exclude`** lets callers opt specific defaults out. In * practice `Date.prototype` and `RegExp.prototype` are the ones that * legitimate polyfills (Temporal shims, some ORMs' custom serialisers) * patch after boot, so those are the usual candidates — * `freezePrototypes({ exclude: ['Date', 'RegExp'] })`. Every other * default should stay frozen unless you know why you're loosening it. * * @param {{ additional?: object[], exclude?: string[] }} [options] * `additional`: extra objects to freeze (e.g. custom global classes). * `exclude`: constructor names to drop from the default freeze list * (`'Date'`, `'RegExp'`, …). Silently ignored for names * not in the defaults. * @returns {number} Count of prototypes frozen. */ export function freezePrototypes(options?: { additional?: object[]; exclude?: string[]; }): number; /** * Race a promise against a timeout. Throws `SecurityError` with * `REQUEST_TIMEOUT` when the deadline hits before the promise settles. * The underlying promise keeps running — cancellation of Node primitives * (setTimeout, fs) needs an AbortController, which this helper doesn't * own. Caller passes one in via `options.signal` if it matters. * * @template T * @param {Promise} promise * @param {number} ms * @param {{ label?: string, signal?: AbortSignal }} [options] * @returns {Promise} */ export function timeout(promise: Promise, ms: number, options?: { label?: string; signal?: AbortSignal; }): Promise; /** * Body-size guard. Given a claimed content length, returns whether the * request may proceed. Middleware should also enforce the limit while * reading the body (a lying Content-Length is still an attack surface). * * @param {number | string | undefined | null} contentLength * @param {number} maxBytes * @returns {{ ok: boolean, reason?: 'missing' | 'invalid' | 'too-large' }} */ export function bodyLimit(contentLength: number | string | undefined | null, maxBytes: number): { ok: boolean; reason?: "missing" | "invalid" | "too-large"; }; /** * @typedef {object} HoneypotOptions * @property {string} [fieldName='website'] * Common decoys: `website`, `email_address_confirm`, `phone2`. * @property {boolean} [caseInsensitive=false] */ /** * Honeypot check. Modern spam bots blindly fill every form field; a hidden * field left empty by the browser is a strong bot signal when it comes * back with content. Returns `true` when the request looks like a bot. * * @param {Record | undefined | null} body * @param {HoneypotOptions} [options] * @returns {boolean} */ export function honeypot(body: Record | undefined | null, options?: HoneypotOptions): boolean; export type HoneypotOptions = { /** * Common decoys: `website`, `email_address_confirm`, `phone2`. */ fieldName?: string | undefined; caseInsensitive?: boolean | undefined; };