export type TrendVerdict = "leak" | "stable" | "inconclusive" | "saturating" | "pressure"; export type TrendResult = { verdict: TrendVerdict; /** Mean retained-heap growth per cycle (bytes) over the analyzed window. */ growthPerCycle: number; /** Per-cycle deltas (bytes) after dropping the warm-up cycle. */ deltas: number[]; /** * Which memory produced the verdict. A Node process can leak in three * places and only one of them is the JS heap: `external`/`arrayBuffers` * hold fetch bodies, streams and Buffers, and can OOM a process while the * heap stays flat (vercel/next.js#92287 reports 4.3 GB of arrayBuffers * against a healthy heap). Reporting the heap alone would call that * "stable". */ source?: "heap" | "external"; /** * Whether the load was driving a cache with keys it had never seen. * * Present so consumers can say what a verdict rests on: growth measured * while forcing a route to re-render for every request has an explanation * that growth on an uncached route does not. It never moves a threshold — * the same samples produce the same verdict either way. */ cacheDriven?: true; }; export type TrendOptions = { /** * Minimum per-cycle growth (bytes) considered leak-like. Defaults to the * noise floor alone — callers that know how much traffic ran should pass * `minGrowthFor(requestsPerCycle)` instead. */ minGrowthPerCycle?: number; /** * The route is a cache being driven with keys it has not served before, so * part of any growth is the store filling up rather than memory going * missing. Carried into the result for disclosure; deliberately not used to * move any threshold, because lowering the gate for cached routes would * hide the real leaks that live in them. */ cacheDriven?: boolean; }; /** * Smallest per-cycle growth distinguishable from measurement noise. * * This is a property of the *instrument*, not of the leak: post-GC samples * jitter by roughly this much regardless of how much traffic ran, so no amount * of load makes growth below it meaningful. */ export declare const MIN_GROWTH_NOISE_FLOOR: number; /** * Growth rate that counts as leak-like, per 1000 requests. * * This is a property of the *leak*: a route that retains memory per request * grows in proportion to the traffic it served, so the gate has to scale with * it. 51.2 KiB is the rate that leaves the default profile (5000 requests per * cycle) on exactly the 256 KiB gate this tool was validated against. */ export declare const MIN_GROWTH_PER_1000_REQUESTS: number; /** * The gate a per-cycle delta must clear to count as growth. * * `max` rather than a sum, because the two terms bound different things: the * floor is what the instrument can resolve, the rate is what the leak should * produce. Below ~5000 requests per cycle the floor dominates and the run is * noise-limited — which is a real limit of measuring less traffic, not a * threshold that can be lowered. * * Without this, the verdict silently depended on `--requests`: the same route * leaking 100 KiB per 1000 requests printed the same headline in every mode * but came out `stable` at 2000 requests per cycle and `leak` at 5000. */ export declare function minGrowthFor(requestsPerCycle: number): number; /** * Classifies a series of post-GC retained-heap samples — baseline first, then * one sample per load cycle — as leaking or stable. * * The baseline→cycle-1 delta is excluded from the verdict: measurements on * healthy routes show it is dominated by one-time engine warm-up (JIT code, * lazy caches) even after an HTTP-level warm-up phase. A leak must keep * growing across the remaining cycles; warm-up flattens out. * * Measurement context travels with the result but never into the decision: * the same samples must produce the same verdict whether or not the route was * a cache being driven. */ export declare function classifyTrend(samples: readonly number[], options?: TrendOptions): TrendResult; /** * Verdict over both the JS heap and external memory, taking the worse of the * two. External memory (`external`, which includes `arrayBuffers`) holds * fetch bodies, streams and Buffers; a process can be killed by OOM with a * perfectly flat heap, so judging the heap alone answers the wrong question. */ export declare function classifyMemoryTrend(heapSamples: readonly number[], externalSamples: readonly number[], options?: TrendOptions): TrendResult;