next-leak 0.1.2 → 0.1.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/README.md +13 -2
- package/dist/bootstrap.js +1 -1
- package/dist/{chunk-PF7KYD5N.js → chunk-6XYFBOL2.js} +12 -3
- package/dist/{chunk-WHC6S57X.js → chunk-ZFYIR423.js} +97 -70
- package/dist/cli.js +2 -2
- package/dist/{html-report-I4PNSLKY.js → html-report-26DU7JFW.js} +1 -1
- package/dist/index.js +2 -2
- package/dist/{issue-report-VQEUXP2E.js → issue-report-FUTEOHN5.js} +1 -1
- package/dist/runner.d.ts +18 -1
- package/package.json +13 -2
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
> Find out whether your Next.js app actually leaks memory — how much, on which route, and whose fault it is.
|
|
9
9
|
|
|
10
|
-
<img src="https://raw.githubusercontent.com/xabierlameiro/next-leak/main/docs/demo.svg" alt="next-leak finding a real Next.js memory leak (
|
|
10
|
+
<img src="https://raw.githubusercontent.com/xabierlameiro/next-leak/main/docs/demo.svg" alt="next-leak finding a real Next.js memory leak (43-second run, idle time compressed)" width="720">
|
|
11
11
|
|
|
12
12
|
```
|
|
13
13
|
$ npx next-leak . --quick
|
|
@@ -46,7 +46,18 @@ that installing it saves memory, but that what it points at is the real cause.
|
|
|
46
46
|
Across ~25 healthy routes on production applications (PPR, MDX, Auth.js,
|
|
47
47
|
Sentry, i18n), it reported **zero false positives**.
|
|
48
48
|
|
|
49
|
-
Your server's memory climbs
|
|
49
|
+
Your self-hosted Next.js server's memory climbs until Node gives up:
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Under Docker or Kubernetes you may not even get that: the process is `OOMKilled`,
|
|
56
|
+
the container exits with **code 137**, and the restart wipes the evidence before
|
|
57
|
+
you can look at it. Almost every report of this ends the same way — *"please
|
|
58
|
+
provide heap snapshots taken after forced GC"* — which almost nobody produces
|
|
59
|
+
correctly. `next-leak` runs that controlled measurement for you and answers with
|
|
60
|
+
evidence a maintainer would accept.
|
|
50
61
|
|
|
51
62
|
Three possible answers, all valuable:
|
|
52
63
|
|
package/dist/bootstrap.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
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
|
-
import "./chunk-
|
|
2
|
+
import "./chunk-6XYFBOL2.js";
|
|
3
3
|
|
|
4
4
|
// src/bootstrap.ts
|
|
5
5
|
import { mkdir, writeFile } from "fs/promises";
|
|
@@ -11,11 +11,20 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
|
|
|
11
11
|
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
12
12
|
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
13
13
|
});
|
|
14
|
-
var __esm = (fn, res) => function __init() {
|
|
15
|
-
|
|
14
|
+
var __esm = (fn, res, err) => function __init() {
|
|
15
|
+
if (err) throw err[0];
|
|
16
|
+
try {
|
|
17
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
18
|
+
} catch (e) {
|
|
19
|
+
throw err = [e], e;
|
|
20
|
+
}
|
|
16
21
|
};
|
|
17
22
|
var __commonJS = (cb, mod) => function __require2() {
|
|
18
|
-
|
|
23
|
+
try {
|
|
24
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
25
|
+
} catch (e) {
|
|
26
|
+
throw mod = 0, e;
|
|
27
|
+
}
|
|
19
28
|
};
|
|
20
29
|
var __export = (target, all) => {
|
|
21
30
|
for (var name in all)
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
__require,
|
|
12
12
|
__toCommonJS,
|
|
13
13
|
__toESM
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-6XYFBOL2.js";
|
|
15
15
|
|
|
16
16
|
// node_modules/.pnpm/fs-extra@4.0.3/node_modules/fs-extra/lib/util/assign.js
|
|
17
17
|
var require_assign = __commonJS({
|
|
@@ -92475,11 +92475,12 @@ function formatReport(report) {
|
|
|
92475
92475
|
for (const route of report.routes) {
|
|
92476
92476
|
lines.push(...routeLines(route));
|
|
92477
92477
|
}
|
|
92478
|
-
lines.push(
|
|
92479
|
-
|
|
92480
|
-
|
|
92481
|
-
|
|
92482
|
-
|
|
92478
|
+
lines.push(
|
|
92479
|
+
"",
|
|
92480
|
+
`snapshots and run.json: ${report.workDir}`,
|
|
92481
|
+
`report: ${report.bundle.htmlReport}`,
|
|
92482
|
+
...report.bundle.issues.map((issue) => `issue draft (${issue.route}): ${issue.file}`)
|
|
92483
|
+
);
|
|
92483
92484
|
const inconclusive = report.routes.filter(
|
|
92484
92485
|
(route) => route.status === "measured" && effectiveVerdict(route) === "inconclusive"
|
|
92485
92486
|
);
|
|
@@ -92582,7 +92583,7 @@ function classifySource(rawSource) {
|
|
|
92582
92583
|
}
|
|
92583
92584
|
const nodeModulesSplit = source.split("/node_modules/");
|
|
92584
92585
|
if (nodeModulesSplit.length > 1) {
|
|
92585
|
-
const tail = nodeModulesSplit
|
|
92586
|
+
const tail = nodeModulesSplit.at(-1) ?? "";
|
|
92586
92587
|
const segments = tail.split("/");
|
|
92587
92588
|
const packageName = (segments[0]?.startsWith("@") ? segments.slice(0, 2).join("/") : segments[0]) ?? null;
|
|
92588
92589
|
if (packageName === "next" || packageName === "react" || packageName === "react-dom") {
|
|
@@ -92890,6 +92891,16 @@ var routesManifestSchema = z3.looseObject({
|
|
|
92890
92891
|
});
|
|
92891
92892
|
var INTERNAL_PATHS = /* @__PURE__ */ new Set(["/_global-error", "/_not-found"]);
|
|
92892
92893
|
var INTERCEPTING_SEGMENT = /^(\(\.{1,3}\))+/;
|
|
92894
|
+
var STATIC_ASSET_PATHS = /* @__PURE__ */ new Set(["/favicon.ico"]);
|
|
92895
|
+
function unaddressableReason(routePath) {
|
|
92896
|
+
if (routePath.split("/").some((segment) => INTERCEPTING_SEGMENT.test(segment))) {
|
|
92897
|
+
return "intercepting route \u2014 only reachable via client navigation";
|
|
92898
|
+
}
|
|
92899
|
+
if (STATIC_ASSET_PATHS.has(routePath)) {
|
|
92900
|
+
return "static asset served by a generated handler \u2014 no user code to leak";
|
|
92901
|
+
}
|
|
92902
|
+
return void 0;
|
|
92903
|
+
}
|
|
92893
92904
|
function toRequestPath(manifestKey) {
|
|
92894
92905
|
let kind;
|
|
92895
92906
|
let withoutSuffix;
|
|
@@ -92927,14 +92938,12 @@ function discoverRoutes(appPaths) {
|
|
|
92927
92938
|
if (parsed === null || INTERNAL_PATHS.has(parsed.path) || routes.has(parsed.path)) {
|
|
92928
92939
|
continue;
|
|
92929
92940
|
}
|
|
92930
|
-
const
|
|
92941
|
+
const reason = unaddressableReason(parsed.path);
|
|
92931
92942
|
routes.set(parsed.path, {
|
|
92932
92943
|
path: parsed.path,
|
|
92933
92944
|
kind: parsed.kind,
|
|
92934
92945
|
dynamic: parsed.path.includes("["),
|
|
92935
|
-
...
|
|
92936
|
-
unaddressableReason: "intercepting route \u2014 only reachable via client navigation"
|
|
92937
|
-
}
|
|
92946
|
+
...reason !== void 0 && { unaddressableReason: reason }
|
|
92938
92947
|
});
|
|
92939
92948
|
}
|
|
92940
92949
|
return [...routes.values()].sort((a, b) => a.path.localeCompare(b.path));
|
|
@@ -93283,55 +93292,55 @@ Host: ${target.host}\r
|
|
|
93283
93292
|
errors: 0
|
|
93284
93293
|
};
|
|
93285
93294
|
let remaining = options.amount;
|
|
93295
|
+
const sendOne = () => new Promise((resolve) => {
|
|
93296
|
+
const socket = net.connect({ host: target.hostname, port });
|
|
93297
|
+
let settled = false;
|
|
93298
|
+
let responseStarted = false;
|
|
93299
|
+
let timer;
|
|
93300
|
+
const finish = () => {
|
|
93301
|
+
if (settled) {
|
|
93302
|
+
return;
|
|
93303
|
+
}
|
|
93304
|
+
settled = true;
|
|
93305
|
+
clearTimeout(timer);
|
|
93306
|
+
socket.destroy();
|
|
93307
|
+
resolve();
|
|
93308
|
+
};
|
|
93309
|
+
const giveUp = () => {
|
|
93310
|
+
if (!settled) {
|
|
93311
|
+
result.abandoned += 1;
|
|
93312
|
+
if (responseStarted) {
|
|
93313
|
+
result.abandonedMidStream += 1;
|
|
93314
|
+
}
|
|
93315
|
+
}
|
|
93316
|
+
finish();
|
|
93317
|
+
};
|
|
93318
|
+
socket.once("connect", () => {
|
|
93319
|
+
result.sent += 1;
|
|
93320
|
+
socket.write(request2);
|
|
93321
|
+
timer = setTimeout(giveUp, options.abandonAfterMs);
|
|
93322
|
+
timer.unref();
|
|
93323
|
+
});
|
|
93324
|
+
socket.on("data", () => {
|
|
93325
|
+
responseStarted = true;
|
|
93326
|
+
});
|
|
93327
|
+
socket.once("end", () => {
|
|
93328
|
+
if (!settled) {
|
|
93329
|
+
result.completed += 1;
|
|
93330
|
+
}
|
|
93331
|
+
finish();
|
|
93332
|
+
});
|
|
93333
|
+
socket.once("error", () => {
|
|
93334
|
+
if (!settled) {
|
|
93335
|
+
result.errors += 1;
|
|
93336
|
+
}
|
|
93337
|
+
finish();
|
|
93338
|
+
});
|
|
93339
|
+
});
|
|
93286
93340
|
const worker = async () => {
|
|
93287
93341
|
while (remaining > 0) {
|
|
93288
93342
|
remaining -= 1;
|
|
93289
|
-
await
|
|
93290
|
-
const socket = net.connect({ host: target.hostname, port });
|
|
93291
|
-
let settled = false;
|
|
93292
|
-
let responseStarted = false;
|
|
93293
|
-
let timer;
|
|
93294
|
-
const finish = () => {
|
|
93295
|
-
if (settled) {
|
|
93296
|
-
return;
|
|
93297
|
-
}
|
|
93298
|
-
settled = true;
|
|
93299
|
-
clearTimeout(timer);
|
|
93300
|
-
socket.destroy();
|
|
93301
|
-
resolve();
|
|
93302
|
-
};
|
|
93303
|
-
socket.once("connect", () => {
|
|
93304
|
-
result.sent += 1;
|
|
93305
|
-
socket.write(request2);
|
|
93306
|
-
timer = setTimeout(() => {
|
|
93307
|
-
if (!settled) {
|
|
93308
|
-
result.abandoned += 1;
|
|
93309
|
-
if (responseStarted) {
|
|
93310
|
-
result.abandonedMidStream += 1;
|
|
93311
|
-
}
|
|
93312
|
-
}
|
|
93313
|
-
finish();
|
|
93314
|
-
}, options.abandonAfterMs);
|
|
93315
|
-
timer.unref();
|
|
93316
|
-
});
|
|
93317
|
-
socket.on("data", () => {
|
|
93318
|
-
responseStarted = true;
|
|
93319
|
-
});
|
|
93320
|
-
socket.once("end", () => {
|
|
93321
|
-
if (!settled) {
|
|
93322
|
-
result.completed += 1;
|
|
93323
|
-
}
|
|
93324
|
-
clearTimeout(timer);
|
|
93325
|
-
finish();
|
|
93326
|
-
});
|
|
93327
|
-
socket.once("error", () => {
|
|
93328
|
-
if (!settled) {
|
|
93329
|
-
result.errors += 1;
|
|
93330
|
-
}
|
|
93331
|
-
clearTimeout(timer);
|
|
93332
|
-
finish();
|
|
93333
|
-
});
|
|
93334
|
-
});
|
|
93343
|
+
await sendOne();
|
|
93335
93344
|
}
|
|
93336
93345
|
};
|
|
93337
93346
|
await Promise.all(
|
|
@@ -93682,9 +93691,20 @@ import { createServer } from "net";
|
|
|
93682
93691
|
import path6 from "path";
|
|
93683
93692
|
var ESTIMATED_RPS = 250;
|
|
93684
93693
|
var PER_ROUTE_OVERHEAD_SECONDS = 10;
|
|
93685
|
-
|
|
93686
|
-
|
|
93687
|
-
|
|
93694
|
+
var MIN_SETTLE_SECONDS = 4;
|
|
93695
|
+
function estimateRun(routeCount, parameters) {
|
|
93696
|
+
const settleSeconds = Math.min(MIN_SETTLE_SECONDS, parameters.idleMs / 1e3);
|
|
93697
|
+
const slowPerRoute = parameters.warmupRequests / ESTIMATED_RPS + parameters.cycles * (parameters.loadRequests / ESTIMATED_RPS + parameters.idleMs / 1e3) + PER_ROUTE_OVERHEAD_SECONDS;
|
|
93698
|
+
const fastPerRoute = PER_ROUTE_OVERHEAD_SECONDS + parameters.cycles * settleSeconds;
|
|
93699
|
+
return {
|
|
93700
|
+
fastSeconds: Math.round(routeCount * fastPerRoute),
|
|
93701
|
+
slowSeconds: Math.round(routeCount * slowPerRoute)
|
|
93702
|
+
};
|
|
93703
|
+
}
|
|
93704
|
+
function formatEstimate(estimate) {
|
|
93705
|
+
const fast = formatDuration(estimate.fastSeconds);
|
|
93706
|
+
const slow = formatDuration(estimate.slowSeconds);
|
|
93707
|
+
return fast === slow ? `\u2248 ${slow}` : `\u2248 ${fast}\u2013${slow}`;
|
|
93688
93708
|
}
|
|
93689
93709
|
function formatDuration(seconds) {
|
|
93690
93710
|
if (seconds < 90) {
|
|
@@ -93732,7 +93752,7 @@ function rssTrend(memorySamples) {
|
|
|
93732
93752
|
return deltas.reduce((sum, delta) => sum + delta, 0) / deltas.length;
|
|
93733
93753
|
}
|
|
93734
93754
|
function routeSlug(route) {
|
|
93735
|
-
const sanitized = route.replaceAll(/[^a-zA-Z0-9-]+/g, "_").replace(/^_
|
|
93755
|
+
const sanitized = route.replaceAll(/[^a-zA-Z0-9-]+/g, "_").replace(/^_/, "").replace(/_$/, "");
|
|
93736
93756
|
if (route === "/") {
|
|
93737
93757
|
return "root";
|
|
93738
93758
|
}
|
|
@@ -93742,9 +93762,16 @@ function routeSlug(route) {
|
|
|
93742
93762
|
const digest = createHash3("sha1").update(route).digest("hex").slice(0, 6);
|
|
93743
93763
|
return sanitized === "" ? `route-${digest}` : `${sanitized}-${digest}`;
|
|
93744
93764
|
}
|
|
93765
|
+
function trimTrailingSlashes(value) {
|
|
93766
|
+
let end = value.length;
|
|
93767
|
+
while (end > 0 && value[end - 1] === "/") {
|
|
93768
|
+
end -= 1;
|
|
93769
|
+
}
|
|
93770
|
+
return value.slice(0, end);
|
|
93771
|
+
}
|
|
93745
93772
|
function filterRoutes(routes, selectors, progress) {
|
|
93746
93773
|
const matches = (routePath, selector) => {
|
|
93747
|
-
const normalized = selector
|
|
93774
|
+
const normalized = trimTrailingSlashes(selector);
|
|
93748
93775
|
if (normalized === "") {
|
|
93749
93776
|
return routePath === "/";
|
|
93750
93777
|
}
|
|
@@ -93822,8 +93849,8 @@ async function measureRoute(context, route, requestPath, index) {
|
|
|
93822
93849
|
};
|
|
93823
93850
|
}
|
|
93824
93851
|
async function writeEvidenceBundle(report, workDir) {
|
|
93825
|
-
const { renderHtmlReport } = await import("./html-report-
|
|
93826
|
-
const { renderIssueMarkdown } = await import("./issue-report-
|
|
93852
|
+
const { renderHtmlReport } = await import("./html-report-26DU7JFW.js");
|
|
93853
|
+
const { renderIssueMarkdown } = await import("./issue-report-FUTEOHN5.js");
|
|
93827
93854
|
for (const route of report.routes) {
|
|
93828
93855
|
if (route.status === "measured" && warrantsIssueDraft(route)) {
|
|
93829
93856
|
const file = path6.join(workDir, `ISSUE-${routeSlug(route.route)}.md`);
|
|
@@ -93872,15 +93899,15 @@ async function planRun(options, target, deps, progress) {
|
|
|
93872
93899
|
cycles: options.cycles ?? RITUAL_DEFAULTS.cycles,
|
|
93873
93900
|
idleMs: options.idleMs ?? RITUAL_DEFAULTS.idleMs
|
|
93874
93901
|
};
|
|
93875
|
-
const
|
|
93876
|
-
|
|
93877
|
-
|
|
93878
|
-
);
|
|
93902
|
+
const measurable = routes.filter(
|
|
93903
|
+
(route) => skipReason(route, resolveRoutePath(route.path, routeConfig)) === null
|
|
93904
|
+
).length;
|
|
93905
|
+
const estimate = estimateRun(measurable, parameters);
|
|
93879
93906
|
progress(
|
|
93880
|
-
`${routes.length} routes discovered \xB7
|
|
93907
|
+
`${routes.length} routes discovered` + (measurable === routes.length ? "" : ` \xB7 ${measurable} measurable`) + ` \xB7 estimated ${formatEstimate(estimate)}` + // Long default runs are where first-time users give up; point at the two
|
|
93881
93908
|
// ways out. Suppressed once load parameters were tuned by hand (or by
|
|
93882
93909
|
// --quick, which arrives here as explicit loadRequests/idleMs).
|
|
93883
|
-
(
|
|
93910
|
+
(estimate.slowSeconds > 15 * 60 && options.loadRequests === void 0 && options.idleMs === void 0 ? " \u2014 use --quick for the fast validated preset, or narrow with --routes" : "")
|
|
93884
93911
|
);
|
|
93885
93912
|
return { routes, routeConfig, registry, nextVersion, parameters };
|
|
93886
93913
|
}
|
package/dist/cli.js
CHANGED
|
@@ -9,9 +9,9 @@ import {
|
|
|
9
9
|
killActiveChildren,
|
|
10
10
|
parseCliArgs,
|
|
11
11
|
runMeasurement
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-ZFYIR423.js";
|
|
13
13
|
import "./chunk-2BQZCZ4Z.js";
|
|
14
|
-
import "./chunk-
|
|
14
|
+
import "./chunk-6XYFBOL2.js";
|
|
15
15
|
|
|
16
16
|
// src/cli.ts
|
|
17
17
|
import { spawn } from "child_process";
|
package/dist/index.js
CHANGED
|
@@ -40,7 +40,7 @@ import {
|
|
|
40
40
|
sourceIndexAt,
|
|
41
41
|
summarizeBaseline,
|
|
42
42
|
validateTarget
|
|
43
|
-
} from "./chunk-
|
|
43
|
+
} from "./chunk-ZFYIR423.js";
|
|
44
44
|
import {
|
|
45
45
|
renderHtmlReport
|
|
46
46
|
} from "./chunk-C3KH5Z2W.js";
|
|
@@ -48,7 +48,7 @@ import "./chunk-2BQZCZ4Z.js";
|
|
|
48
48
|
import {
|
|
49
49
|
renderIssueMarkdown
|
|
50
50
|
} from "./chunk-5ZYZW2BL.js";
|
|
51
|
-
import "./chunk-
|
|
51
|
+
import "./chunk-6XYFBOL2.js";
|
|
52
52
|
export {
|
|
53
53
|
LaunchError,
|
|
54
54
|
LoadError,
|
package/dist/runner.d.ts
CHANGED
|
@@ -96,7 +96,24 @@ export type RunOptions = {
|
|
|
96
96
|
signal?: AbortSignal;
|
|
97
97
|
onProgress?: (message: string) => void;
|
|
98
98
|
};
|
|
99
|
-
export
|
|
99
|
+
export type RunEstimate = {
|
|
100
|
+
/**
|
|
101
|
+
* Costs no run avoids: process launch, GC, snapshots and the minimum
|
|
102
|
+
* settle. Request-serving time is left out on purpose — throughput is the
|
|
103
|
+
* one term that swings 10x between a hello-world route and a real one, so a
|
|
104
|
+
* floor that guessed at it would not be a floor.
|
|
105
|
+
*/
|
|
106
|
+
fastSeconds: number;
|
|
107
|
+
/** Full idle window every cycle, at the lowest throughput ever measured. */
|
|
108
|
+
slowSeconds: number;
|
|
109
|
+
};
|
|
110
|
+
export declare function estimateRun(routeCount: number, parameters: RunParameters): RunEstimate;
|
|
111
|
+
/**
|
|
112
|
+
* A point estimate cannot be right across app weights: the adaptive idle ends
|
|
113
|
+
* as soon as the heap holds still, which on a small app is almost at once. A
|
|
114
|
+
* range says that out loud instead of quoting the worst case as the price.
|
|
115
|
+
*/
|
|
116
|
+
export declare function formatEstimate(estimate: RunEstimate): string;
|
|
100
117
|
export declare function formatDuration(seconds: number): string;
|
|
101
118
|
export type RunnerDeps = {
|
|
102
119
|
ritual: typeof runRitual;
|
package/package.json
CHANGED
|
@@ -1,12 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "next-leak",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
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",
|
|
7
|
+
"next.js",
|
|
7
8
|
"memory-leak",
|
|
9
|
+
"memory",
|
|
10
|
+
"oom",
|
|
11
|
+
"oomkilled",
|
|
12
|
+
"heap",
|
|
8
13
|
"heap-snapshot",
|
|
14
|
+
"profiling",
|
|
15
|
+
"performance",
|
|
16
|
+
"nodejs",
|
|
9
17
|
"diagnostics",
|
|
18
|
+
"debugging",
|
|
10
19
|
"cli"
|
|
11
20
|
],
|
|
12
21
|
"license": "MIT",
|
|
@@ -37,7 +46,9 @@
|
|
|
37
46
|
},
|
|
38
47
|
"pnpm": {
|
|
39
48
|
"overrides": {
|
|
40
|
-
"uuid": ">=11.1.1"
|
|
49
|
+
"uuid": ">=11.1.1",
|
|
50
|
+
"esbuild": ">=0.28.1",
|
|
51
|
+
"qs": ">=6.15.2"
|
|
41
52
|
}
|
|
42
53
|
},
|
|
43
54
|
"devDependencies": {
|