next-leak 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -4
- package/dist/abandon-load.d.ts +12 -2
- package/dist/{chunk-AMSDGT3Y.js → chunk-BXDUPN6Z.js} +54 -5
- package/dist/{chunk-22PBLCGO.js → chunk-EJ26OBZI.js} +7 -4
- package/dist/{chunk-6CJU5TVV.js → chunk-RS3AO7HB.js} +1 -1
- package/dist/cli.js +2 -2
- package/dist/confidence.d.ts +3 -0
- package/dist/{html-report-2UAOOZQO.js → html-report-TN7PYVU4.js} +2 -2
- package/dist/index.js +3 -3
- package/dist/ritual.d.ts +3 -1
- package/dist/route-config.d.ts +4 -0
- package/dist/runner.d.ts +11 -0
- package/package.json +6 -2
package/README.md
CHANGED
|
@@ -167,10 +167,19 @@ first try. When a run skips a route it prints the same fragment.
|
|
|
167
167
|
load-balancer timeouts and bots do. Some leaks only exist on that path
|
|
168
168
|
(`ServerResponse` retained after an early disconnect; the RSC tee branch in
|
|
169
169
|
[#94919](https://github.com/vercel/next.js/issues/94919)). The clock starts
|
|
170
|
-
at the **first byte of the response**,
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
170
|
+
at the **first byte of the response**, so the cut lands mid-stream however
|
|
171
|
+
long the route takes to answer. Small values are the point: `4` means "read
|
|
172
|
+
the first chunk, then vanish". Requests abandoned on purpose are not counted
|
|
173
|
+
as failures.
|
|
174
|
+
- **`abandonFrom`** moves that clock to the request itself
|
|
175
|
+
(`"abandonFrom": "request"`). Use it for the opposite experiment: a client
|
|
176
|
+
that is already gone before the server produces anything. On a route slower
|
|
177
|
+
than the deadline the default never cuts early — against the reproduction
|
|
178
|
+
for [#84648](https://github.com/vercel/next.js/issues/84648), whose upstream
|
|
179
|
+
answers in 400 ms while its load generator cuts at 60 ms, first-byte reached
|
|
180
|
+
7% of requests and `request` reached all of them. It stays opt-in because a
|
|
181
|
+
deadline armed on connect loses the race to the first byte on fast routes,
|
|
182
|
+
which measures the wrong path silently.
|
|
174
183
|
|
|
175
184
|
`run.json` records what every load phase actually did — requests sent,
|
|
176
185
|
2xx, abandoned — so a run can be audited instead of trusted.
|
package/dist/abandon-load.d.ts
CHANGED
|
@@ -1,9 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where the abandon deadline starts. `first-byte` puts the cut mid-stream
|
|
3
|
+
* whatever the route's latency; `request` puts it before the response exists,
|
|
4
|
+
* which is a different leak path and not reachable from the other origin.
|
|
5
|
+
*/
|
|
6
|
+
export type AbandonOrigin = "first-byte" | "request";
|
|
1
7
|
export type AbandonPhaseOptions = {
|
|
2
8
|
url: string;
|
|
3
9
|
amount: number;
|
|
4
10
|
connections: number;
|
|
5
|
-
/** Destroy the socket this many ms after the
|
|
11
|
+
/** Destroy the socket this many ms after the origin below. */
|
|
6
12
|
abandonAfterMs: number;
|
|
13
|
+
/** Defaults to `first-byte`. */
|
|
14
|
+
abandonFrom?: AbandonOrigin;
|
|
7
15
|
headers?: Record<string, string>;
|
|
8
16
|
};
|
|
9
17
|
export type AbandonPhaseResult = {
|
|
@@ -30,6 +38,8 @@ export type AbandonPhaseResult = {
|
|
|
30
38
|
* a client goes away mid-flight (closed tabs, load-balancer timeouts, bots).
|
|
31
39
|
*
|
|
32
40
|
* Raw sockets keep this honest: write the request, wait for the response to
|
|
33
|
-
* start, then wait `abandonAfterMs` and destroy the socket mid-stream.
|
|
41
|
+
* start, then wait `abandonAfterMs` and destroy the socket mid-stream. With
|
|
42
|
+
* `abandonFrom: "request"` the wait starts at the write instead, which is the
|
|
43
|
+
* only way to cut a route that has not begun answering yet.
|
|
34
44
|
*/
|
|
35
45
|
export declare function runAbandonPhase(options: AbandonPhaseOptions): Promise<AbandonPhaseResult>;
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
minGrowthFor,
|
|
8
8
|
resolveCycles,
|
|
9
9
|
warrantsIssueDraft
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-EJ26OBZI.js";
|
|
11
11
|
import {
|
|
12
12
|
assessPeakPressure,
|
|
13
13
|
describePeakPressure
|
|
@@ -92624,8 +92624,28 @@ var routeConfigSchema = z3.object({
|
|
|
92624
92624
|
* window, so a request-relative clock cuts before the stream starts and
|
|
92625
92625
|
* tests the wrong path entirely.
|
|
92626
92626
|
*/
|
|
92627
|
-
abandonAfterMs: z3.number().int().positive().optional()
|
|
92628
|
-
|
|
92627
|
+
abandonAfterMs: z3.number().int().positive().optional(),
|
|
92628
|
+
/**
|
|
92629
|
+
* Where the abandon deadline starts. `first-byte` is the default and the
|
|
92630
|
+
* semantics everything else assumes.
|
|
92631
|
+
*
|
|
92632
|
+
* `request` starts it when the request is written, which is the only way
|
|
92633
|
+
* to reach leaks that need the client already gone before the server
|
|
92634
|
+
* produces anything: against a route whose time-to-first-byte exceeds the
|
|
92635
|
+
* deadline, a first-byte clock never cuts early. Measured on the
|
|
92636
|
+
* vercel/next.js#84648 repro, whose upstream answers in 400 ms while its
|
|
92637
|
+
* own load generator cuts at 60 ms — the first-byte clock reached 7% of
|
|
92638
|
+
* requests there, none of them on the path the issue describes.
|
|
92639
|
+
*
|
|
92640
|
+
* Opt-in per route, never a default: armed on connect, the deadline loses
|
|
92641
|
+
* the race to the first byte on fast routes, which is how the earlier
|
|
92642
|
+
* version of this measured 2 mid-stream cuts out of ~1500 on #94919.
|
|
92643
|
+
*/
|
|
92644
|
+
abandonFrom: z3.enum(["first-byte", "request"]).optional()
|
|
92645
|
+
}).strict().refine((config) => config.abandonFrom === void 0 || config.abandonAfterMs !== void 0, {
|
|
92646
|
+
message: '"abandonFrom" configures nothing without "abandonAfterMs"',
|
|
92647
|
+
path: ["abandonFrom"]
|
|
92648
|
+
});
|
|
92629
92649
|
var RouteConfigError = class extends Error {
|
|
92630
92650
|
constructor(message) {
|
|
92631
92651
|
super(message);
|
|
@@ -92846,6 +92866,14 @@ function revalidationLines(route) {
|
|
|
92846
92866
|
` driven through ISR revalidation (revalidates every ${route.revalidatedEverySeconds}s; without it the load would serve the cache)`
|
|
92847
92867
|
];
|
|
92848
92868
|
}
|
|
92869
|
+
function abandonLines(route) {
|
|
92870
|
+
if (route.abandon === void 0) {
|
|
92871
|
+
return [];
|
|
92872
|
+
}
|
|
92873
|
+
return [
|
|
92874
|
+
route.abandon.from === "request" ? ` cut ${route.abandon.afterMs}ms after the request was sent, so the client is gone before the response starts` : ` cut ${route.abandon.afterMs}ms after the first byte, so the cut lands mid-stream`
|
|
92875
|
+
];
|
|
92876
|
+
}
|
|
92849
92877
|
function confidenceLines(route) {
|
|
92850
92878
|
const lines = [];
|
|
92851
92879
|
if (route.confidence.supersededVerdict !== void 0) {
|
|
@@ -92939,6 +92967,7 @@ function routeLines(route, parameters) {
|
|
|
92939
92967
|
route.growthPer1000Requests
|
|
92940
92968
|
)}) heap ${curve}${resolved}`,
|
|
92941
92969
|
...revalidationLines(route),
|
|
92970
|
+
...abandonLines(route),
|
|
92942
92971
|
...confidenceLines(route),
|
|
92943
92972
|
...memorySourceLines(route, verdict),
|
|
92944
92973
|
...peakPressureLines(route, parameters),
|
|
@@ -93735,6 +93764,7 @@ var FIRST_BYTE_BUDGET_MS = 5e3;
|
|
|
93735
93764
|
async function runAbandonPhase(options) {
|
|
93736
93765
|
const target = new URL(options.url);
|
|
93737
93766
|
const port = Number(target.port || 80);
|
|
93767
|
+
const fromRequest = options.abandonFrom === "request";
|
|
93738
93768
|
const headerLines = Object.entries(options.headers ?? {}).map(([name, value]) => `${name}: ${value}\r
|
|
93739
93769
|
`).join("");
|
|
93740
93770
|
const request2 = `GET ${target.pathname}${target.search} HTTP/1.1\r
|
|
@@ -93779,7 +93809,10 @@ Host: ${target.host}\r
|
|
|
93779
93809
|
socket.once("connect", () => {
|
|
93780
93810
|
result.sent += 1;
|
|
93781
93811
|
socket.write(request2);
|
|
93782
|
-
timer = setTimeout(
|
|
93812
|
+
timer = setTimeout(
|
|
93813
|
+
giveUp,
|
|
93814
|
+
fromRequest ? options.abandonAfterMs : FIRST_BYTE_BUDGET_MS
|
|
93815
|
+
);
|
|
93783
93816
|
timer.unref();
|
|
93784
93817
|
});
|
|
93785
93818
|
socket.on("data", () => {
|
|
@@ -93787,6 +93820,9 @@ Host: ${target.host}\r
|
|
|
93787
93820
|
return;
|
|
93788
93821
|
}
|
|
93789
93822
|
responseStarted = true;
|
|
93823
|
+
if (fromRequest) {
|
|
93824
|
+
return;
|
|
93825
|
+
}
|
|
93790
93826
|
clearTimeout(timer);
|
|
93791
93827
|
timer = setTimeout(giveUp, options.abandonAfterMs);
|
|
93792
93828
|
timer.unref();
|
|
@@ -93949,6 +93985,7 @@ async function runRitual(options, deps = defaultDeps) {
|
|
|
93949
93985
|
amount,
|
|
93950
93986
|
connections,
|
|
93951
93987
|
abandonAfterMs,
|
|
93988
|
+
...options.abandonFrom !== void 0 && { abandonFrom: options.abandonFrom },
|
|
93952
93989
|
...options.headers !== void 0 && { headers: options.headers }
|
|
93953
93990
|
});
|
|
93954
93991
|
loadOutcomes.push({
|
|
@@ -94330,6 +94367,9 @@ async function measureRoute(context, route, requestPath, index, pass = void 0) {
|
|
|
94330
94367
|
...headers !== void 0 && { headers },
|
|
94331
94368
|
...routeConfig.abandonAfterMs !== void 0 && {
|
|
94332
94369
|
abandonAfterMs: routeConfig.abandonAfterMs
|
|
94370
|
+
},
|
|
94371
|
+
...routeConfig.abandonFrom !== void 0 && {
|
|
94372
|
+
abandonFrom: routeConfig.abandonFrom
|
|
94333
94373
|
}
|
|
94334
94374
|
});
|
|
94335
94375
|
const confidence = assessConfidence({
|
|
@@ -94344,6 +94384,9 @@ async function measureRoute(context, route, requestPath, index, pass = void 0) {
|
|
|
94344
94384
|
warmupRequests: options.warmupRequests ?? RITUAL_DEFAULTS.warmupRequests,
|
|
94345
94385
|
...routeConfig.abandonAfterMs !== void 0 && {
|
|
94346
94386
|
abandonAfterMs: routeConfig.abandonAfterMs
|
|
94387
|
+
},
|
|
94388
|
+
...routeConfig.abandonFrom !== void 0 && {
|
|
94389
|
+
abandonFrom: routeConfig.abandonFrom
|
|
94347
94390
|
}
|
|
94348
94391
|
});
|
|
94349
94392
|
const verdict = confidence.supersededVerdict ?? result.trend.verdict;
|
|
@@ -94374,6 +94417,12 @@ async function measureRoute(context, route, requestPath, index, pass = void 0) {
|
|
|
94374
94417
|
unreclaimedSamples: result.unreclaimedSamples,
|
|
94375
94418
|
unreclaimedTrend: result.unreclaimedTrend,
|
|
94376
94419
|
requestsPerCycle: result.requestsPerCycle,
|
|
94420
|
+
...routeConfig.abandonAfterMs !== void 0 && {
|
|
94421
|
+
abandon: {
|
|
94422
|
+
afterMs: routeConfig.abandonAfterMs,
|
|
94423
|
+
from: routeConfig.abandonFrom ?? "first-byte"
|
|
94424
|
+
}
|
|
94425
|
+
},
|
|
94377
94426
|
timings: result.timings,
|
|
94378
94427
|
loadOutcomes: result.loadOutcomes,
|
|
94379
94428
|
settleOutcomes: result.settleOutcomes,
|
|
@@ -94389,7 +94438,7 @@ async function measureRoute(context, route, requestPath, index, pass = void 0) {
|
|
|
94389
94438
|
};
|
|
94390
94439
|
}
|
|
94391
94440
|
async function writeEvidenceBundle(report, workDir) {
|
|
94392
|
-
const { renderHtmlReport } = await import("./html-report-
|
|
94441
|
+
const { renderHtmlReport } = await import("./html-report-TN7PYVU4.js");
|
|
94393
94442
|
const { renderIssueMarkdown } = await import("./issue-report-HKA26WNV.js");
|
|
94394
94443
|
for (const route of report.routes) {
|
|
94395
94444
|
if (route.status === "measured" && warrantsIssueDraft(route)) {
|
|
@@ -113,7 +113,7 @@ function settleWarnings(outcomes) {
|
|
|
113
113
|
}
|
|
114
114
|
return warnings;
|
|
115
115
|
}
|
|
116
|
-
function abandonmentWarnings(outcome) {
|
|
116
|
+
function abandonmentWarnings(outcome, abandonFrom) {
|
|
117
117
|
const abandoned = outcome.abandoned ?? 0;
|
|
118
118
|
if (outcome.sent > 0 && abandoned < outcome.sent * ABANDON_EFFECTIVE_FLOOR) {
|
|
119
119
|
return [{
|
|
@@ -121,6 +121,9 @@ function abandonmentWarnings(outcome) {
|
|
|
121
121
|
detail: `${outcome.phase} disconnected early on only ${abandoned} of ${outcome.sent} requests (${pct(abandoned, outcome.sent)}) \u2014 the early-disconnect path was largely not exercised`
|
|
122
122
|
}];
|
|
123
123
|
}
|
|
124
|
+
if (abandonFrom === "request") {
|
|
125
|
+
return [];
|
|
126
|
+
}
|
|
124
127
|
const midStream = outcome.abandonedMidStream ?? 0;
|
|
125
128
|
if (abandoned > 0 && midStream < abandoned * MID_STREAM_FLOOR) {
|
|
126
129
|
return [{
|
|
@@ -130,11 +133,11 @@ function abandonmentWarnings(outcome) {
|
|
|
130
133
|
}
|
|
131
134
|
return [];
|
|
132
135
|
}
|
|
133
|
-
function loadWarnings(outcomes, abandonAfterMs) {
|
|
136
|
+
function loadWarnings(outcomes, abandonAfterMs, abandonFrom) {
|
|
134
137
|
const warnings = [];
|
|
135
138
|
for (const outcome of outcomes) {
|
|
136
139
|
if (abandonAfterMs !== void 0) {
|
|
137
|
-
warnings.push(...abandonmentWarnings(outcome));
|
|
140
|
+
warnings.push(...abandonmentWarnings(outcome, abandonFrom));
|
|
138
141
|
continue;
|
|
139
142
|
}
|
|
140
143
|
const landed = outcome.ok2xx ?? 0;
|
|
@@ -246,7 +249,7 @@ function assessConfidence(input) {
|
|
|
246
249
|
const minGrowth = input.minGrowthPerCycle ?? MIN_GROWTH_NOISE_FLOOR;
|
|
247
250
|
const warnings = [
|
|
248
251
|
...settleWarnings(input.settleOutcomes),
|
|
249
|
-
...loadWarnings(input.loadOutcomes, input.abandonAfterMs),
|
|
252
|
+
...loadWarnings(input.loadOutcomes, input.abandonAfterMs, input.abandonFrom),
|
|
250
253
|
...growthShapeWarnings(input.trend),
|
|
251
254
|
...noiseFloorWarnings(input.trend, minGrowth),
|
|
252
255
|
...thinEvidenceWarnings(input.trend, minGrowth),
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createRequire as __nextLeakCreateRequire } from 'node:module';import { fileURLToPath as __nextLeakFileURLToPath } from 'node:url';import { dirname as __nextLeakDirname } from 'node:path';const require = __nextLeakCreateRequire(import.meta.url);const __filename = __nextLeakFileURLToPath(import.meta.url);const __dirname = __nextLeakDirname(__filename);
|
|
2
2
|
import {
|
|
3
3
|
effectiveVerdict
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-EJ26OBZI.js";
|
|
5
5
|
import {
|
|
6
6
|
assessPeakPressure,
|
|
7
7
|
describePeakPressure
|
package/dist/cli.js
CHANGED
|
@@ -16,10 +16,10 @@ import {
|
|
|
16
16
|
runMeasurement,
|
|
17
17
|
unregisterChild,
|
|
18
18
|
validateTarget
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-BXDUPN6Z.js";
|
|
20
20
|
import {
|
|
21
21
|
classifyTrend
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-EJ26OBZI.js";
|
|
23
23
|
import "./chunk-XHPUAMJG.js";
|
|
24
24
|
import "./chunk-6XYFBOL2.js";
|
|
25
25
|
|
package/dist/confidence.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { AbandonOrigin } from "./abandon-load.js";
|
|
1
2
|
import type { HeapSample } from "./control-server.js";
|
|
2
3
|
import type { LoadOutcome, SettleOutcome } from "./ritual.js";
|
|
3
4
|
import { type TrendResult, type TrendVerdict } from "./trend.js";
|
|
@@ -41,6 +42,8 @@ export type ConfidenceInput = {
|
|
|
41
42
|
settleOutcomes: readonly SettleOutcome[];
|
|
42
43
|
/** Set when the run asked for early disconnects. */
|
|
43
44
|
abandonAfterMs?: number;
|
|
45
|
+
/** Which deadline origin those disconnects used. Defaults to `first-byte`. */
|
|
46
|
+
abandonFrom?: AbandonOrigin;
|
|
44
47
|
/** Threshold the verdict used, for the noise-floor check. */
|
|
45
48
|
minGrowthPerCycle?: number;
|
|
46
49
|
/** Post-GC samples, for the heap-ceiling check. */
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { createRequire as __nextLeakCreateRequire } from 'node:module';import { fileURLToPath as __nextLeakFileURLToPath } from 'node:url';import { dirname as __nextLeakDirname } from 'node:path';const require = __nextLeakCreateRequire(import.meta.url);const __filename = __nextLeakFileURLToPath(import.meta.url);const __dirname = __nextLeakDirname(__filename);
|
|
2
2
|
import {
|
|
3
3
|
renderHtmlReport
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import "./chunk-
|
|
4
|
+
} from "./chunk-RS3AO7HB.js";
|
|
5
|
+
import "./chunk-EJ26OBZI.js";
|
|
6
6
|
import "./chunk-XHPUAMJG.js";
|
|
7
7
|
import "./chunk-6XYFBOL2.js";
|
|
8
8
|
export {
|
package/dist/index.js
CHANGED
|
@@ -39,13 +39,13 @@ import {
|
|
|
39
39
|
sourceIndexAt,
|
|
40
40
|
summarizeBaseline,
|
|
41
41
|
validateTarget
|
|
42
|
-
} from "./chunk-
|
|
42
|
+
} from "./chunk-BXDUPN6Z.js";
|
|
43
43
|
import {
|
|
44
44
|
renderHtmlReport
|
|
45
|
-
} from "./chunk-
|
|
45
|
+
} from "./chunk-RS3AO7HB.js";
|
|
46
46
|
import {
|
|
47
47
|
classifyTrend
|
|
48
|
-
} from "./chunk-
|
|
48
|
+
} from "./chunk-EJ26OBZI.js";
|
|
49
49
|
import {
|
|
50
50
|
renderIssueMarkdown
|
|
51
51
|
} from "./chunk-WXAFXVWS.js";
|
package/dist/ritual.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { HeapSample } from "./control-server.js";
|
|
2
2
|
import { launchInstrumented } from "./launcher.js";
|
|
3
|
-
import { runAbandonPhase } from "./abandon-load.js";
|
|
3
|
+
import { runAbandonPhase, type AbandonOrigin } from "./abandon-load.js";
|
|
4
4
|
import { runLoadPhase } from "./load.js";
|
|
5
5
|
import { type TrendResult } from "./trend.js";
|
|
6
6
|
export type RitualOptions = {
|
|
@@ -24,6 +24,8 @@ export type RitualOptions = {
|
|
|
24
24
|
headers?: Record<string, string>;
|
|
25
25
|
/** Emulate clients that disconnect before the response arrives. */
|
|
26
26
|
abandonAfterMs?: number;
|
|
27
|
+
/** Where that deadline starts. Defaults to `first-byte`. */
|
|
28
|
+
abandonFrom?: AbandonOrigin;
|
|
27
29
|
};
|
|
28
30
|
export type PhaseTiming = {
|
|
29
31
|
phase: string;
|
package/dist/route-config.d.ts
CHANGED
|
@@ -5,6 +5,10 @@ declare const routeConfigSchema: z.ZodObject<{
|
|
|
5
5
|
headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
6
6
|
query: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
7
7
|
abandonAfterMs: z.ZodOptional<z.ZodNumber>;
|
|
8
|
+
abandonFrom: z.ZodOptional<z.ZodEnum<{
|
|
9
|
+
"first-byte": "first-byte";
|
|
10
|
+
request: "request";
|
|
11
|
+
}>>;
|
|
8
12
|
}, z.core.$strict>;
|
|
9
13
|
export type RouteConfig = z.infer<typeof routeConfigSchema>;
|
|
10
14
|
export declare class RouteConfigError extends Error {
|
package/dist/runner.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { AbandonOrigin } from "./abandon-load.js";
|
|
1
2
|
import { type AttributedDiff } from "./attribution.js";
|
|
2
3
|
import { type ConfidenceReport } from "./confidence.js";
|
|
3
4
|
import type { HeapSample } from "./control-server.js";
|
|
@@ -56,6 +57,16 @@ export type RouteReport = {
|
|
|
56
57
|
unreclaimedTrend: TrendResult;
|
|
57
58
|
/** Requests each cycle served — what the growth rates normalize by. */
|
|
58
59
|
requestsPerCycle: number;
|
|
60
|
+
/**
|
|
61
|
+
* The early-disconnect regime, when the route asked for one. Recorded
|
|
62
|
+
* because a curve measured with cuts landing mid-stream and one measured
|
|
63
|
+
* with cuts landing before the response are different experiments, and
|
|
64
|
+
* the counters alone do not say which was intended.
|
|
65
|
+
*/
|
|
66
|
+
abandon?: {
|
|
67
|
+
afterMs: number;
|
|
68
|
+
from: AbandonOrigin;
|
|
69
|
+
};
|
|
59
70
|
/**
|
|
60
71
|
* Distinct keys the load cycled through, when the route asked for a
|
|
61
72
|
* bounded set. A verdict about a cache depends on how many keys it saw,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "next-leak",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "Find out whether your Next.js app actually leaks memory — how much, on which route, and whose fault it is.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"nextjs",
|
|
@@ -49,7 +49,11 @@
|
|
|
49
49
|
"overrides": {
|
|
50
50
|
"uuid": ">=11.1.1",
|
|
51
51
|
"esbuild": ">=0.28.1",
|
|
52
|
-
"qs": ">=6.15.2"
|
|
52
|
+
"qs": ">=6.15.2",
|
|
53
|
+
"js-yaml": ">=4.3.1 <5",
|
|
54
|
+
"fast-uri": ">=3.1.5 <4",
|
|
55
|
+
"ip-address": ">=10.3.1 <11",
|
|
56
|
+
"postcss": ">=8.5.23 <9"
|
|
53
57
|
}
|
|
54
58
|
},
|
|
55
59
|
"devDependencies": {
|