next-leak 0.4.1 → 0.4.3
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/dist/{chunk-FFCY6POI.js → chunk-2FZXZLZW.js} +2 -0
- package/dist/{chunk-OJIXF7RP.js → chunk-EQ2DV2YO.js} +96 -26
- package/dist/{chunk-BTWQYJOW.js → chunk-NNDGXIGQ.js} +1 -1
- package/dist/cli.js +2 -2
- package/dist/confidence.d.ts +6 -0
- package/dist/control-client.d.ts +4 -0
- package/dist/{html-report-76DP5ADD.js → html-report-X2LUOZRH.js} +2 -2
- package/dist/index.js +3 -3
- package/dist/ritual.d.ts +3 -0
- package/dist/runner.d.ts +0 -5
- package/package.json +1 -1
|
@@ -68,6 +68,7 @@ function classifyMemoryTrend(heapSamples, externalSamples, options = {}) {
|
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
// src/confidence.ts
|
|
71
|
+
var resolveCycles = (cycles) => Math.max(cycles * 2, 6);
|
|
71
72
|
function effectiveVerdict(report) {
|
|
72
73
|
return report.confidence.supersededVerdict ?? report.trend.verdict;
|
|
73
74
|
}
|
|
@@ -235,6 +236,7 @@ export {
|
|
|
235
236
|
minGrowthFor,
|
|
236
237
|
classifyTrend,
|
|
237
238
|
classifyMemoryTrend,
|
|
239
|
+
resolveCycles,
|
|
238
240
|
effectiveVerdict,
|
|
239
241
|
warrantsIssueDraft,
|
|
240
242
|
assessConfidence
|
|
@@ -5,8 +5,9 @@ import {
|
|
|
5
5
|
classifyTrend,
|
|
6
6
|
effectiveVerdict,
|
|
7
7
|
minGrowthFor,
|
|
8
|
+
resolveCycles,
|
|
8
9
|
warrantsIssueDraft
|
|
9
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-2FZXZLZW.js";
|
|
10
11
|
import {
|
|
11
12
|
assessPeakPressure,
|
|
12
13
|
describePeakPressure
|
|
@@ -3656,10 +3657,10 @@ var require_ansi_styles = __commonJS({
|
|
|
3656
3657
|
};
|
|
3657
3658
|
var ansi2ansi = (n) => n;
|
|
3658
3659
|
var rgb2rgb = (r, g, b) => [r, g, b];
|
|
3659
|
-
var setLazyProperty = (object, property,
|
|
3660
|
+
var setLazyProperty = (object, property, get2) => {
|
|
3660
3661
|
Object.defineProperty(object, property, {
|
|
3661
3662
|
get: () => {
|
|
3662
|
-
const value =
|
|
3663
|
+
const value = get2();
|
|
3663
3664
|
Object.defineProperty(object, property, {
|
|
3664
3665
|
value,
|
|
3665
3666
|
enumerable: true,
|
|
@@ -36042,18 +36043,18 @@ var require_gen_mapping_umd = __commonJS({
|
|
|
36042
36043
|
function cast(set) {
|
|
36043
36044
|
return set;
|
|
36044
36045
|
}
|
|
36045
|
-
function
|
|
36046
|
+
function get2(setarr, key) {
|
|
36046
36047
|
return cast(setarr)._indexes[key];
|
|
36047
36048
|
}
|
|
36048
36049
|
function put(setarr, key) {
|
|
36049
|
-
const index =
|
|
36050
|
+
const index = get2(setarr, key);
|
|
36050
36051
|
if (index !== void 0) return index;
|
|
36051
36052
|
const { array, _indexes: indexes } = cast(setarr);
|
|
36052
36053
|
const length = array.push(key);
|
|
36053
36054
|
return indexes[key] = length - 1;
|
|
36054
36055
|
}
|
|
36055
36056
|
function remove(setarr, key) {
|
|
36056
|
-
const index =
|
|
36057
|
+
const index = get2(setarr, key);
|
|
36057
36058
|
if (index === void 0) return;
|
|
36058
36059
|
const { array, _indexes: indexes } = cast(setarr);
|
|
36059
36060
|
for (let i = index + 1; i < array.length; i++) {
|
|
@@ -60211,7 +60212,7 @@ var require_family = __commonJS({
|
|
|
60211
60212
|
});
|
|
60212
60213
|
exports2._getKey = _getKey;
|
|
60213
60214
|
exports2._getPattern = _getPattern;
|
|
60214
|
-
exports2.get =
|
|
60215
|
+
exports2.get = get2;
|
|
60215
60216
|
exports2.getAllNextSiblings = getAllNextSiblings;
|
|
60216
60217
|
exports2.getAllPrevSiblings = getAllPrevSiblings;
|
|
60217
60218
|
exports2.getAssignmentIdentifiers = getAssignmentIdentifiers;
|
|
@@ -60442,7 +60443,7 @@ var require_family = __commonJS({
|
|
|
60442
60443
|
}
|
|
60443
60444
|
return siblings;
|
|
60444
60445
|
}
|
|
60445
|
-
function
|
|
60446
|
+
function get2(key, context = true) {
|
|
60446
60447
|
if (context === true) context = this.context;
|
|
60447
60448
|
const parts = key.split(".");
|
|
60448
60449
|
if (parts.length === 1) {
|
|
@@ -65956,7 +65957,7 @@ var require_dist5 = __commonJS({
|
|
|
65956
65957
|
var pathVar = getPathVar(env, platform);
|
|
65957
65958
|
var separator = getSeparator(platform);
|
|
65958
65959
|
var originalPath = env[pathVar];
|
|
65959
|
-
return { push, unshift, get, restore };
|
|
65960
|
+
return { push, unshift, get: get2, restore };
|
|
65960
65961
|
function push() {
|
|
65961
65962
|
for (var _len = arguments.length, paths = Array(_len), _key = 0; _key < _len; _key++) {
|
|
65962
65963
|
paths[_key] = arguments[_key];
|
|
@@ -65969,12 +65970,12 @@ var require_dist5 = __commonJS({
|
|
|
65969
65970
|
}
|
|
65970
65971
|
return change(false, paths);
|
|
65971
65972
|
}
|
|
65972
|
-
function
|
|
65973
|
+
function get2() {
|
|
65973
65974
|
return env[pathVar];
|
|
65974
65975
|
}
|
|
65975
65976
|
function restore() {
|
|
65976
65977
|
env[pathVar] = originalPath;
|
|
65977
|
-
return
|
|
65978
|
+
return get2();
|
|
65978
65979
|
}
|
|
65979
65980
|
function change(append, paths) {
|
|
65980
65981
|
if (!append) {
|
|
@@ -65985,7 +65986,7 @@ var require_dist5 = __commonJS({
|
|
|
65985
65986
|
addExistingPath(pathArray, env[pathVar], append);
|
|
65986
65987
|
env[pathVar] = pathArray.join(separator);
|
|
65987
65988
|
});
|
|
65988
|
-
return
|
|
65989
|
+
return get2();
|
|
65989
65990
|
}
|
|
65990
65991
|
}
|
|
65991
65992
|
function getPathArray(pathToAdd) {
|
|
@@ -86349,7 +86350,7 @@ var require_form_data = __commonJS({
|
|
|
86349
86350
|
var CombinedStream = require_combined_stream();
|
|
86350
86351
|
var util = __require("util");
|
|
86351
86352
|
var path7 = __require("path");
|
|
86352
|
-
var
|
|
86353
|
+
var http2 = __require("http");
|
|
86353
86354
|
var https = __require("https");
|
|
86354
86355
|
var parseUrl = __require("url").parse;
|
|
86355
86356
|
var fs = __require("fs");
|
|
@@ -86624,7 +86625,7 @@ var require_form_data = __commonJS({
|
|
|
86624
86625
|
if (options.protocol === "https:") {
|
|
86625
86626
|
request2 = https.request(options);
|
|
86626
86627
|
} else {
|
|
86627
|
-
request2 =
|
|
86628
|
+
request2 = http2.request(options);
|
|
86628
86629
|
}
|
|
86629
86630
|
this.getLength(function(err, length) {
|
|
86630
86631
|
if (err && err !== "Unknown stream") {
|
|
@@ -92487,7 +92488,7 @@ function formatReport(report) {
|
|
|
92487
92488
|
);
|
|
92488
92489
|
if (inconclusive.length > 0) {
|
|
92489
92490
|
const routeList = inconclusive.map((route) => route.route).join(",");
|
|
92490
|
-
const moreCycles =
|
|
92491
|
+
const moreCycles = resolveCycles(report.parameters.cycles);
|
|
92491
92492
|
lines.push(
|
|
92492
92493
|
"",
|
|
92493
92494
|
"hint: inconclusive means sustained sub-threshold growth \u2014 measure longer to resolve it:",
|
|
@@ -93238,6 +93239,7 @@ async function runLoadPhase(options) {
|
|
|
93238
93239
|
import { mkdir } from "fs/promises";
|
|
93239
93240
|
|
|
93240
93241
|
// src/control-client.ts
|
|
93242
|
+
import http from "http";
|
|
93241
93243
|
import { z as z5 } from "zod";
|
|
93242
93244
|
var sampleSchema = z5.object({
|
|
93243
93245
|
gcExposed: z5.boolean(),
|
|
@@ -93253,12 +93255,70 @@ var ControlError = class extends Error {
|
|
|
93253
93255
|
this.name = "ControlError";
|
|
93254
93256
|
}
|
|
93255
93257
|
};
|
|
93256
|
-
|
|
93257
|
-
|
|
93258
|
-
|
|
93258
|
+
var DEADLINES_MS = {
|
|
93259
|
+
"/mem": 3e4,
|
|
93260
|
+
"/gc": 18e4,
|
|
93261
|
+
"/snapshot": 18e5
|
|
93262
|
+
};
|
|
93263
|
+
var DEFAULT_DEADLINE_MS = 3e4;
|
|
93264
|
+
function deadlineFor(pathname) {
|
|
93265
|
+
const operation = pathname.split("?")[0] ?? pathname;
|
|
93266
|
+
return DEADLINES_MS[operation] ?? DEFAULT_DEADLINE_MS;
|
|
93267
|
+
}
|
|
93268
|
+
function get(port, pathname, deadlineMs) {
|
|
93269
|
+
return new Promise((resolve, reject) => {
|
|
93270
|
+
let settled = false;
|
|
93271
|
+
const settle = (outcome) => {
|
|
93272
|
+
if (settled) {
|
|
93273
|
+
return;
|
|
93274
|
+
}
|
|
93275
|
+
settled = true;
|
|
93276
|
+
clearTimeout(timer);
|
|
93277
|
+
if ("ok" in outcome) {
|
|
93278
|
+
resolve(outcome.ok);
|
|
93279
|
+
} else {
|
|
93280
|
+
reject(outcome.error);
|
|
93281
|
+
}
|
|
93282
|
+
};
|
|
93283
|
+
const request2 = http.get({ host: "127.0.0.1", port, path: pathname }, (response) => {
|
|
93284
|
+
const chunks = [];
|
|
93285
|
+
response.on("data", (chunk) => chunks.push(chunk));
|
|
93286
|
+
response.once(
|
|
93287
|
+
"end",
|
|
93288
|
+
() => settle({
|
|
93289
|
+
ok: { status: response.statusCode ?? 0, body: Buffer.concat(chunks).toString("utf8") }
|
|
93290
|
+
})
|
|
93291
|
+
);
|
|
93292
|
+
});
|
|
93293
|
+
const timer = setTimeout(() => {
|
|
93294
|
+
settle({
|
|
93295
|
+
error: new ControlError(
|
|
93296
|
+
`control channel ${pathname} on port ${port} did not answer within ${Math.round(deadlineMs / 1e3)}s \u2014 the measured process is wedged, or this snapshot is larger than anything this tool has been validated on`
|
|
93297
|
+
)
|
|
93298
|
+
});
|
|
93299
|
+
request2.destroy();
|
|
93300
|
+
}, deadlineMs);
|
|
93301
|
+
timer.unref();
|
|
93302
|
+
request2.once(
|
|
93303
|
+
"error",
|
|
93304
|
+
(cause) => settle({
|
|
93305
|
+
error: new ControlError(
|
|
93306
|
+
`control channel ${pathname} on port ${port} did not answer (${cause.message}) \u2014 the measured process is gone or its event loop is blocked`
|
|
93307
|
+
)
|
|
93308
|
+
})
|
|
93309
|
+
);
|
|
93310
|
+
});
|
|
93311
|
+
}
|
|
93312
|
+
async function request(port, pathname, deadlineMs = deadlineFor(pathname)) {
|
|
93313
|
+
const response = await get(port, pathname, deadlineMs);
|
|
93314
|
+
if (response.status !== 200) {
|
|
93259
93315
|
throw new ControlError(`control channel ${pathname} responded ${response.status}`);
|
|
93260
93316
|
}
|
|
93261
|
-
|
|
93317
|
+
try {
|
|
93318
|
+
return JSON.parse(response.body);
|
|
93319
|
+
} catch {
|
|
93320
|
+
throw new ControlError(`control channel ${pathname} answered with malformed JSON`);
|
|
93321
|
+
}
|
|
93262
93322
|
}
|
|
93263
93323
|
async function requestGc(port) {
|
|
93264
93324
|
const sample = sampleSchema.parse(await request(port, "/gc"));
|
|
@@ -93436,6 +93496,7 @@ async function waitUntilSettled(controlPort, maxIdleMs, deps) {
|
|
|
93436
93496
|
var defaultDeps = {
|
|
93437
93497
|
launch: launchInstrumented,
|
|
93438
93498
|
load: runLoadPhase,
|
|
93499
|
+
abandon: runAbandonPhase,
|
|
93439
93500
|
sleep: (ms) => new Promise((resolve) => setTimeout(resolve, ms)),
|
|
93440
93501
|
readMemory: requestMemory
|
|
93441
93502
|
};
|
|
@@ -93494,7 +93555,7 @@ async function runRitual(options, deps = defaultDeps) {
|
|
|
93494
93555
|
});
|
|
93495
93556
|
return;
|
|
93496
93557
|
}
|
|
93497
|
-
const outcome = await
|
|
93558
|
+
const outcome = await deps.abandon({
|
|
93498
93559
|
url: `http://127.0.0.1:${app.appPort}${options.route}`,
|
|
93499
93560
|
amount,
|
|
93500
93561
|
connections,
|
|
@@ -93936,7 +93997,7 @@ async function measureRoute(context, route, requestPath, index, pass = void 0) {
|
|
|
93936
93997
|
};
|
|
93937
93998
|
}
|
|
93938
93999
|
async function writeEvidenceBundle(report, workDir) {
|
|
93939
|
-
const { renderHtmlReport } = await import("./html-report-
|
|
94000
|
+
const { renderHtmlReport } = await import("./html-report-X2LUOZRH.js");
|
|
93940
94001
|
const { renderIssueMarkdown } = await import("./issue-report-HKA26WNV.js");
|
|
93941
94002
|
for (const route of report.routes) {
|
|
93942
94003
|
if (route.status === "measured" && warrantsIssueDraft(route)) {
|
|
@@ -93947,7 +94008,6 @@ async function writeEvidenceBundle(report, workDir) {
|
|
|
93947
94008
|
}
|
|
93948
94009
|
await writeFile(report.bundle.htmlReport, renderHtmlReport(report));
|
|
93949
94010
|
}
|
|
93950
|
-
var resolveCycles = (cycles) => Math.max(cycles * 2, 6);
|
|
93951
94011
|
async function routeReportFor(context, route, index, total) {
|
|
93952
94012
|
const { routeConfig, progress } = context;
|
|
93953
94013
|
const label = `${route.path} (${index + 1}/${total})`;
|
|
@@ -93964,12 +94024,22 @@ async function routeReportFor(context, route, index, total) {
|
|
|
93964
94024
|
if (first.status !== "measured" || context.options.resolveInconclusive === false || effectiveVerdict(first) !== "inconclusive") {
|
|
93965
94025
|
return first;
|
|
93966
94026
|
}
|
|
94027
|
+
if (context.options.signal?.aborted === true) {
|
|
94028
|
+
return first;
|
|
94029
|
+
}
|
|
93967
94030
|
const cycles = resolveCycles(context.options.cycles ?? RITUAL_DEFAULTS.cycles);
|
|
93968
94031
|
progress(`re-measuring ${route.path} with ${cycles} cycles: the first pass could not call it`);
|
|
93969
|
-
|
|
93970
|
-
|
|
93971
|
-
|
|
93972
|
-
|
|
94032
|
+
try {
|
|
94033
|
+
return await measureRoute(context, route, requestPath, index, {
|
|
94034
|
+
cycles,
|
|
94035
|
+
dirSuffix: "-resolve"
|
|
94036
|
+
});
|
|
94037
|
+
} catch (cause) {
|
|
94038
|
+
progress(
|
|
94039
|
+
`re-measurement of ${route.path} failed (${cause instanceof Error ? cause.message : String(cause)}) \u2014 keeping the first pass`
|
|
94040
|
+
);
|
|
94041
|
+
return first;
|
|
94042
|
+
}
|
|
93973
94043
|
} catch (cause) {
|
|
93974
94044
|
const failure = cause instanceof Error ? cause.message : String(cause);
|
|
93975
94045
|
progress(`failed ${label}: ${failure}`);
|
|
@@ -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-2FZXZLZW.js";
|
|
5
5
|
import {
|
|
6
6
|
assessPeakPressure,
|
|
7
7
|
describePeakPressure
|
package/dist/cli.js
CHANGED
|
@@ -9,8 +9,8 @@ import {
|
|
|
9
9
|
killActiveChildren,
|
|
10
10
|
parseCliArgs,
|
|
11
11
|
runMeasurement
|
|
12
|
-
} from "./chunk-
|
|
13
|
-
import "./chunk-
|
|
12
|
+
} from "./chunk-EQ2DV2YO.js";
|
|
13
|
+
import "./chunk-2FZXZLZW.js";
|
|
14
14
|
import "./chunk-XHPUAMJG.js";
|
|
15
15
|
import "./chunk-6XYFBOL2.js";
|
|
16
16
|
|
package/dist/confidence.d.ts
CHANGED
|
@@ -45,6 +45,12 @@ export type ConfidenceInput = {
|
|
|
45
45
|
/** Old-space cap the measured process ran under (MB). */
|
|
46
46
|
maxOldSpaceMb?: number;
|
|
47
47
|
};
|
|
48
|
+
/**
|
|
49
|
+
* Cycles a re-measurement uses when a verdict came back `inconclusive` — the
|
|
50
|
+
* same figure the report's manual re-run hint prints. One definition, imported
|
|
51
|
+
* by both, so the tool can never recommend one number and use another.
|
|
52
|
+
*/
|
|
53
|
+
export declare const resolveCycles: (cycles: number) => number;
|
|
48
54
|
/**
|
|
49
55
|
* The verdict a route's evidence actually supports.
|
|
50
56
|
*
|
package/dist/control-client.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { HeapSample } from "./control-server.js";
|
|
2
|
+
declare function request(port: number, pathname: string, deadlineMs?: number): Promise<unknown>;
|
|
2
3
|
/** Forces GC in the measured process and returns a settled memory sample. */
|
|
3
4
|
export declare function requestGc(port: number): Promise<HeapSample>;
|
|
4
5
|
/**
|
|
@@ -11,3 +12,6 @@ export declare function requestSnapshot(port: number, name: string): Promise<{
|
|
|
11
12
|
file: string;
|
|
12
13
|
sample: HeapSample;
|
|
13
14
|
}>;
|
|
15
|
+
/** Test seam: the production deadlines would make a hung-server test take minutes. */
|
|
16
|
+
export declare const requestWithDeadline: typeof request;
|
|
17
|
+
export {};
|
|
@@ -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-NNDGXIGQ.js";
|
|
5
|
+
import "./chunk-2FZXZLZW.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-EQ2DV2YO.js";
|
|
43
43
|
import {
|
|
44
44
|
renderHtmlReport
|
|
45
|
-
} from "./chunk-
|
|
45
|
+
} from "./chunk-NNDGXIGQ.js";
|
|
46
46
|
import {
|
|
47
47
|
classifyTrend
|
|
48
|
-
} from "./chunk-
|
|
48
|
+
} from "./chunk-2FZXZLZW.js";
|
|
49
49
|
import {
|
|
50
50
|
renderIssueMarkdown
|
|
51
51
|
} from "./chunk-WXAFXVWS.js";
|
package/dist/ritual.d.ts
CHANGED
|
@@ -1,5 +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
4
|
import { runLoadPhase } from "./load.js";
|
|
4
5
|
import { type TrendResult } from "./trend.js";
|
|
5
6
|
export type RitualOptions = {
|
|
@@ -103,6 +104,8 @@ export type RitualResult = {
|
|
|
103
104
|
export type RitualDeps = {
|
|
104
105
|
launch: typeof launchInstrumented;
|
|
105
106
|
load: typeof runLoadPhase;
|
|
107
|
+
/** Early-disconnect load; a seam like `load`, for the same reasons. */
|
|
108
|
+
abandon: typeof runAbandonPhase;
|
|
106
109
|
sleep: (ms: number) => Promise<void>;
|
|
107
110
|
/** GC-free read, polled while the app is under load. */
|
|
108
111
|
readMemory: (port: number) => Promise<HeapSample>;
|
package/dist/runner.d.ts
CHANGED
|
@@ -153,11 +153,6 @@ export type RunnerDeps = {
|
|
|
153
153
|
};
|
|
154
154
|
export declare function freePort(): Promise<number>;
|
|
155
155
|
export declare function routeSlug(route: string): string;
|
|
156
|
-
/**
|
|
157
|
-
* Cycles a second pass uses — the same figure the report recommends for a
|
|
158
|
-
* manual re-run, so the tool follows its own advice.
|
|
159
|
-
*/
|
|
160
|
-
export declare const resolveCycles: (cycles: number) => number;
|
|
161
156
|
/**
|
|
162
157
|
* Full measurement run: validate the target, discover routes, run the ritual
|
|
163
158
|
* per route in a fresh process, diff snapshots for non-stable verdicts, and
|