loadscope 0.0.0-stage → 0.1.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/dist/index.js ADDED
@@ -0,0 +1,87 @@
1
+ import {
2
+ LiveDashboard,
3
+ buildAiDiagnosticPrompt,
4
+ compareRuns,
5
+ executeClosedModel,
6
+ executeMultiThreaded,
7
+ executeOpenModel,
8
+ extractFromResponse,
9
+ fetchAiDiagnostic,
10
+ formatBreakpointCsvReport,
11
+ formatBreakpointJsonReport,
12
+ formatBreakpointTerminalReport,
13
+ formatComparisonCsvReport,
14
+ formatComparisonJsonReport,
15
+ formatComparisonTerminalReport,
16
+ formatCsvReport,
17
+ formatJsonReport,
18
+ formatScenarioTerminalReport,
19
+ formatStepRow,
20
+ formatTerminalReport,
21
+ generateGithubStepSummary,
22
+ generateHtmlReport,
23
+ generatePdfReport,
24
+ interpolateVariables,
25
+ loadBaseline,
26
+ parseScenario,
27
+ printBreakpointTerminalReport,
28
+ printComparisonTerminalReport,
29
+ printScenarioTerminalReport,
30
+ printTerminalReport,
31
+ renderHtmlReport,
32
+ run,
33
+ runBreakingPoint,
34
+ runScenario,
35
+ saveBaseline,
36
+ writeGithubStepSummary
37
+ } from "./chunk-OFND2NUO.js";
38
+ import {
39
+ ArrivalScheduler,
40
+ Histogram,
41
+ computeQueueDelay,
42
+ extractDistribution,
43
+ recordWithCorrection
44
+ } from "./chunk-7L4SENK7.js";
45
+ export {
46
+ ArrivalScheduler,
47
+ Histogram,
48
+ LiveDashboard,
49
+ buildAiDiagnosticPrompt,
50
+ compareRuns,
51
+ computeQueueDelay,
52
+ executeClosedModel,
53
+ executeMultiThreaded,
54
+ executeOpenModel,
55
+ extractDistribution,
56
+ extractFromResponse,
57
+ fetchAiDiagnostic,
58
+ formatBreakpointCsvReport,
59
+ formatBreakpointJsonReport,
60
+ formatBreakpointTerminalReport,
61
+ formatComparisonCsvReport,
62
+ formatComparisonJsonReport,
63
+ formatComparisonTerminalReport,
64
+ formatCsvReport,
65
+ formatJsonReport,
66
+ formatScenarioTerminalReport,
67
+ formatStepRow,
68
+ formatTerminalReport,
69
+ generateGithubStepSummary,
70
+ generateHtmlReport,
71
+ generatePdfReport,
72
+ interpolateVariables,
73
+ loadBaseline,
74
+ parseScenario,
75
+ printBreakpointTerminalReport,
76
+ printComparisonTerminalReport,
77
+ printScenarioTerminalReport,
78
+ printTerminalReport,
79
+ recordWithCorrection,
80
+ renderHtmlReport,
81
+ run,
82
+ runBreakingPoint,
83
+ runScenario,
84
+ saveBaseline,
85
+ writeGithubStepSummary
86
+ };
87
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,2 @@
1
+
2
+ export { }
package/dist/worker.js ADDED
@@ -0,0 +1,199 @@
1
+ import {
2
+ ArrivalScheduler,
3
+ Histogram,
4
+ recordWithCorrection
5
+ } from "./chunk-7L4SENK7.js";
6
+
7
+ // src/core/worker.ts
8
+ import { parentPort, workerData } from "worker_threads";
9
+ import { Pool } from "undici";
10
+ import { monitorEventLoopDelay } from "perf_hooks";
11
+ async function runWorker() {
12
+ const data = workerData;
13
+ if (!data || !parentPort) return;
14
+ const urlObj = new URL(data.url);
15
+ const pool = new Pool(urlObj.origin, {
16
+ connections: Math.max(1, data.concurrency),
17
+ pipelining: 1,
18
+ keepAliveTimeout: 3e4,
19
+ keepAliveMaxTimeout: 6e4
20
+ });
21
+ const histogram = new Histogram();
22
+ const serviceHistogram = new Histogram();
23
+ const ttfbHistogram = new Histogram();
24
+ let currentSecondHistogram = new Histogram();
25
+ const statusCodes = {};
26
+ const errorsByType = {};
27
+ let networkErrors = 0;
28
+ let httpErrors = 0;
29
+ let dispatched = 0;
30
+ const timeoutMs = Math.max(1, Math.floor(data.timeout * 1e3));
31
+ const reqPath = urlObj.pathname + urlObj.search;
32
+ const reqMethod = data.method;
33
+ const loopDelay = monitorEventLoopDelay({ resolution: 20 });
34
+ loopDelay.enable();
35
+ let stopped = false;
36
+ const abortController = new AbortController();
37
+ const expectedIntervalUs = data.rate && data.rate > 0 ? 1 / data.rate * 1e6 : 0;
38
+ async function dispatchRequest(intendedNs, recordStats) {
39
+ if (recordStats) dispatched++;
40
+ const dispatchNs = process.hrtime.bigint();
41
+ try {
42
+ const response = await pool.request({
43
+ path: reqPath,
44
+ method: reqMethod,
45
+ headers: data.headers,
46
+ body: data.body,
47
+ headersTimeout: timeoutMs,
48
+ bodyTimeout: timeoutMs,
49
+ signal: abortController.signal
50
+ });
51
+ const headersNs = process.hrtime.bigint();
52
+ const ttfbUs = Math.max(0, Number(headersNs - dispatchNs) / 1e3);
53
+ await response.body.dump({ limit: 10 * 1024 * 1024 });
54
+ const completionNs = process.hrtime.bigint();
55
+ const serviceUs = Math.max(0, Number(completionNs - dispatchNs) / 1e3);
56
+ const honestResponseUs = Math.max(0, Number(completionNs - intendedNs) / 1e3);
57
+ const code = response.statusCode;
58
+ if (recordStats) {
59
+ if (data.honest && expectedIntervalUs > 0) {
60
+ recordWithCorrection(histogram, honestResponseUs, expectedIntervalUs);
61
+ recordWithCorrection(serviceHistogram, serviceUs, expectedIntervalUs);
62
+ } else {
63
+ histogram.record(honestResponseUs);
64
+ serviceHistogram.record(serviceUs);
65
+ }
66
+ ttfbHistogram.record(ttfbUs);
67
+ currentSecondHistogram.record(honestResponseUs);
68
+ statusCodes[code] = (statusCodes[code] || 0) + 1;
69
+ if (code >= 400) {
70
+ httpErrors++;
71
+ }
72
+ }
73
+ } catch (err) {
74
+ const completionNs = process.hrtime.bigint();
75
+ const serviceUs = Math.max(0, Number(completionNs - dispatchNs) / 1e3);
76
+ const honestResponseUs = Math.max(0, Number(completionNs - intendedNs) / 1e3);
77
+ if (recordStats) {
78
+ networkErrors++;
79
+ histogram.record(honestResponseUs);
80
+ serviceHistogram.record(serviceUs);
81
+ currentSecondHistogram.record(honestResponseUs);
82
+ const errorObj = err;
83
+ const codeKey = errorObj.code || errorObj.name || "NETWORK_ERROR";
84
+ errorsByType[codeKey] = (errorsByType[codeKey] || 0) + 1;
85
+ }
86
+ }
87
+ }
88
+ if (data.warmup > 0) {
89
+ const warmupEndNs = process.hrtime.bigint() + BigInt(Math.floor(data.warmup * 1e9));
90
+ let warmupStopped = false;
91
+ const warmupWorkers = Array.from({ length: Math.max(1, data.concurrency) }, async () => {
92
+ while (!warmupStopped && !stopped) {
93
+ if (process.hrtime.bigint() >= warmupEndNs) {
94
+ warmupStopped = true;
95
+ break;
96
+ }
97
+ await dispatchRequest(process.hrtime.bigint(), false);
98
+ }
99
+ });
100
+ await Promise.all(warmupWorkers);
101
+ }
102
+ const durationNs = BigInt(Math.floor(data.duration * 1e9));
103
+ const startNs = process.hrtime.bigint();
104
+ const endNs = startNs + durationNs;
105
+ const hardDeadlineTimer = setTimeout(() => {
106
+ stopped = true;
107
+ abortController.abort();
108
+ }, Math.ceil(data.duration * 1e3) + 300);
109
+ let lastSecond = 0;
110
+ const tickTimer = setInterval(() => {
111
+ const elapsedSec = Math.floor(Number(process.hrtime.bigint() - startNs) / 1e9);
112
+ if (elapsedSec > lastSecond) {
113
+ lastSecond = elapsedSec;
114
+ const tickMsg = {
115
+ type: "tick",
116
+ workerIndex: data.workerIndex,
117
+ elapsedSec,
118
+ dispatched,
119
+ networkErrors,
120
+ httpErrors,
121
+ statusCodes: { ...statusCodes },
122
+ errorsByType: { ...errorsByType },
123
+ windowSnapshot: currentSecondHistogram.toSnapshot(),
124
+ cumulativeSnapshot: histogram.toSnapshot(),
125
+ serviceTimeSnapshot: serviceHistogram.toSnapshot(),
126
+ ttfbSnapshot: ttfbHistogram.toSnapshot(),
127
+ loopLagMs: loopDelay.percentile(99) / 1e6
128
+ };
129
+ parentPort?.postMessage(tickMsg);
130
+ currentSecondHistogram = new Histogram();
131
+ }
132
+ }, 1e3);
133
+ if (data.mode === "open" && data.rate && data.rate > 0) {
134
+ const scheduler = new ArrivalScheduler(data.rate, data.distribution ?? "uniform", startNs);
135
+ const pendingPromises = /* @__PURE__ */ new Set();
136
+ while (!stopped) {
137
+ const nowNs = process.hrtime.bigint();
138
+ if (nowNs >= endNs) {
139
+ stopped = true;
140
+ break;
141
+ }
142
+ const intendedNs = scheduler.nextArrivalNs();
143
+ await scheduler.waitUntil(intendedNs);
144
+ const p = dispatchRequest(intendedNs, true);
145
+ pendingPromises.add(p);
146
+ p.finally(() => pendingPromises.delete(p));
147
+ if (pendingPromises.size > Math.max(10, data.concurrency * 2)) {
148
+ await Promise.race(pendingPromises);
149
+ }
150
+ }
151
+ await Promise.allSettled(Array.from(pendingPromises));
152
+ } else {
153
+ async function workerLoop(idx) {
154
+ if (data.rampUp > 0) {
155
+ const delayMs = idx / data.concurrency * data.rampUp * 1e3;
156
+ if (delayMs > 0) {
157
+ await new Promise((r) => setTimeout(r, delayMs));
158
+ }
159
+ }
160
+ while (!stopped) {
161
+ if (process.hrtime.bigint() >= endNs) {
162
+ stopped = true;
163
+ break;
164
+ }
165
+ await dispatchRequest(process.hrtime.bigint(), true);
166
+ }
167
+ }
168
+ const workers = Array.from({ length: Math.max(1, data.concurrency) }, (_, i) => workerLoop(i));
169
+ await Promise.all(workers);
170
+ }
171
+ clearTimeout(hardDeadlineTimer);
172
+ clearInterval(tickTimer);
173
+ loopDelay.disable();
174
+ await pool.close();
175
+ const doneMsg = {
176
+ type: "done",
177
+ workerIndex: data.workerIndex,
178
+ dispatched,
179
+ networkErrors,
180
+ httpErrors,
181
+ statusCodes,
182
+ errorsByType,
183
+ finalSnapshot: histogram.toSnapshot(),
184
+ serviceTimeSnapshot: serviceHistogram.toSnapshot(),
185
+ ttfbSnapshot: ttfbHistogram.toSnapshot(),
186
+ loopLagMaxMs: loopDelay.max / 1e6,
187
+ loopLagP99Ms: loopDelay.percentile(99) / 1e6
188
+ };
189
+ parentPort?.postMessage(doneMsg);
190
+ }
191
+ runWorker().catch((err) => {
192
+ const errorMsg = err instanceof Error ? err.stack || err.message : String(err);
193
+ parentPort?.postMessage({
194
+ type: "error",
195
+ workerIndex: workerData?.workerIndex ?? -1,
196
+ error: errorMsg
197
+ });
198
+ });
199
+ //# sourceMappingURL=worker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/worker.ts"],"sourcesContent":["import { parentPort, workerData } from \"node:worker_threads\";\r\nimport { Pool } from \"undici\";\r\nimport { monitorEventLoopDelay } from \"node:perf_hooks\";\r\nimport { Histogram } from \"../stats/histogram.js\";\r\nimport { recordWithCorrection } from \"../stats/co-corrector.js\";\r\nimport { ArrivalScheduler } from \"./scheduler.js\";\r\nimport type { WorkerInitData, WorkerTickMessage, WorkerDoneMessage } from \"../types.js\";\r\n\r\nasync function runWorker(): Promise<void> {\r\n const data = workerData as WorkerInitData;\r\n if (!data || !parentPort) return;\r\n\r\n const urlObj = new URL(data.url);\r\n const pool = new Pool(urlObj.origin, {\r\n connections: Math.max(1, data.concurrency),\r\n pipelining: 1,\r\n keepAliveTimeout: 30_000,\r\n keepAliveMaxTimeout: 60_000,\r\n });\r\n\r\n const histogram = new Histogram(); // Honest response time\r\n const serviceHistogram = new Histogram(); // Server service time\r\n const ttfbHistogram = new Histogram(); // TTFB\r\n let currentSecondHistogram = new Histogram();\r\n const statusCodes: Record<number, number> = {};\r\n const errorsByType: Record<string, number> = {};\r\n\r\n let networkErrors = 0;\r\n let httpErrors = 0;\r\n let dispatched = 0;\r\n\r\n const timeoutMs = Math.max(1, Math.floor(data.timeout * 1000));\r\n const reqPath = urlObj.pathname + urlObj.search;\r\n const reqMethod = data.method as \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\" | \"HEAD\" | \"OPTIONS\";\r\n\r\n const loopDelay = monitorEventLoopDelay({ resolution: 20 });\r\n loopDelay.enable();\r\n\r\n let stopped = false;\r\n const abortController = new AbortController();\r\n\r\n const expectedIntervalUs = data.rate && data.rate > 0 ? (1 / data.rate) * 1_000_000 : 0;\r\n\r\n async function dispatchRequest(intendedNs: bigint, recordStats: boolean): Promise<void> {\r\n if (recordStats) dispatched++;\r\n const dispatchNs = process.hrtime.bigint();\r\n\r\n try {\r\n const response = await pool.request({\r\n path: reqPath,\r\n method: reqMethod,\r\n headers: data.headers,\r\n body: data.body,\r\n headersTimeout: timeoutMs,\r\n bodyTimeout: timeoutMs,\r\n signal: abortController.signal,\r\n });\r\n\r\n const headersNs = process.hrtime.bigint();\r\n const ttfbUs = Math.max(0, Number(headersNs - dispatchNs) / 1000);\r\n\r\n await response.body.dump({ limit: 10 * 1024 * 1024 });\r\n\r\n const completionNs = process.hrtime.bigint();\r\n const serviceUs = Math.max(0, Number(completionNs - dispatchNs) / 1000);\r\n const honestResponseUs = Math.max(0, Number(completionNs - intendedNs) / 1000);\r\n const code = response.statusCode;\r\n\r\n if (recordStats) {\r\n if (data.honest && expectedIntervalUs > 0) {\r\n recordWithCorrection(histogram, honestResponseUs, expectedIntervalUs);\r\n recordWithCorrection(serviceHistogram, serviceUs, expectedIntervalUs);\r\n } else {\r\n histogram.record(honestResponseUs);\r\n serviceHistogram.record(serviceUs);\r\n }\r\n\r\n ttfbHistogram.record(ttfbUs);\r\n currentSecondHistogram.record(honestResponseUs);\r\n statusCodes[code] = (statusCodes[code] || 0) + 1;\r\n if (code >= 400) {\r\n httpErrors++;\r\n }\r\n }\r\n } catch (err: unknown) {\r\n const completionNs = process.hrtime.bigint();\r\n const serviceUs = Math.max(0, Number(completionNs - dispatchNs) / 1000);\r\n const honestResponseUs = Math.max(0, Number(completionNs - intendedNs) / 1000);\r\n\r\n if (recordStats) {\r\n networkErrors++;\r\n histogram.record(honestResponseUs);\r\n serviceHistogram.record(serviceUs);\r\n currentSecondHistogram.record(honestResponseUs);\r\n\r\n const errorObj = err as { code?: string; name?: string };\r\n const codeKey = errorObj.code || errorObj.name || \"NETWORK_ERROR\";\r\n errorsByType[codeKey] = (errorsByType[codeKey] || 0) + 1;\r\n }\r\n }\r\n }\r\n\r\n // Optional Warmup Phase\r\n if (data.warmup > 0) {\r\n const warmupEndNs = process.hrtime.bigint() + BigInt(Math.floor(data.warmup * 1_000_000_000));\r\n let warmupStopped = false;\r\n\r\n const warmupWorkers = Array.from({ length: Math.max(1, data.concurrency) }, async () => {\r\n while (!warmupStopped && !stopped) {\r\n if (process.hrtime.bigint() >= warmupEndNs) {\r\n warmupStopped = true;\r\n break;\r\n }\r\n await dispatchRequest(process.hrtime.bigint(), false);\r\n }\r\n });\r\n\r\n await Promise.all(warmupWorkers);\r\n }\r\n\r\n // Measurement Phase\r\n const durationNs = BigInt(Math.floor(data.duration * 1_000_000_000));\r\n const startNs = process.hrtime.bigint();\r\n const endNs = startNs + durationNs;\r\n\r\n const hardDeadlineTimer = setTimeout(() => {\r\n stopped = true;\r\n abortController.abort();\r\n }, Math.ceil(data.duration * 1000) + 300);\r\n\r\n let lastSecond = 0;\r\n const tickTimer = setInterval(() => {\r\n const elapsedSec = Math.floor(Number(process.hrtime.bigint() - startNs) / 1_000_000_000);\r\n if (elapsedSec > lastSecond) {\r\n lastSecond = elapsedSec;\r\n const tickMsg: WorkerTickMessage = {\r\n type: \"tick\",\r\n workerIndex: data.workerIndex,\r\n elapsedSec,\r\n dispatched,\r\n networkErrors,\r\n httpErrors,\r\n statusCodes: { ...statusCodes },\r\n errorsByType: { ...errorsByType },\r\n windowSnapshot: currentSecondHistogram.toSnapshot(),\r\n cumulativeSnapshot: histogram.toSnapshot(),\r\n serviceTimeSnapshot: serviceHistogram.toSnapshot(),\r\n ttfbSnapshot: ttfbHistogram.toSnapshot(),\r\n loopLagMs: loopDelay.percentile(99) / 1_000_000,\r\n };\r\n parentPort?.postMessage(tickMsg);\r\n currentSecondHistogram = new Histogram();\r\n }\r\n }, 1000);\r\n\r\n // Execution: Closed concurrency vs Open arrival rate\r\n if (data.mode === \"open\" && data.rate && data.rate > 0) {\r\n const scheduler = new ArrivalScheduler(data.rate, data.distribution ?? \"uniform\", startNs);\r\n const pendingPromises: Set<Promise<void>> = new Set();\r\n\r\n while (!stopped) {\r\n const nowNs = process.hrtime.bigint();\r\n if (nowNs >= endNs) {\r\n stopped = true;\r\n break;\r\n }\r\n\r\n const intendedNs = scheduler.nextArrivalNs();\r\n await scheduler.waitUntil(intendedNs);\r\n\r\n const p = dispatchRequest(intendedNs, true);\r\n pendingPromises.add(p);\r\n p.finally(() => pendingPromises.delete(p));\r\n\r\n if (pendingPromises.size > Math.max(10, data.concurrency * 2)) {\r\n await Promise.race(pendingPromises);\r\n }\r\n }\r\n\r\n await Promise.allSettled(Array.from(pendingPromises));\r\n } else {\r\n // Closed concurrency loop\r\n async function workerLoop(idx: number): Promise<void> {\r\n if (data.rampUp > 0) {\r\n const delayMs = (idx / data.concurrency) * data.rampUp * 1000;\r\n if (delayMs > 0) {\r\n await new Promise((r) => setTimeout(r, delayMs));\r\n }\r\n }\r\n\r\n while (!stopped) {\r\n if (process.hrtime.bigint() >= endNs) {\r\n stopped = true;\r\n break;\r\n }\r\n await dispatchRequest(process.hrtime.bigint(), true);\r\n }\r\n }\r\n\r\n const workers = Array.from({ length: Math.max(1, data.concurrency) }, (_, i) => workerLoop(i));\r\n await Promise.all(workers);\r\n }\r\n\r\n clearTimeout(hardDeadlineTimer);\r\n clearInterval(tickTimer);\r\n loopDelay.disable();\r\n await pool.close();\r\n\r\n const doneMsg: WorkerDoneMessage = {\r\n type: \"done\",\r\n workerIndex: data.workerIndex,\r\n dispatched,\r\n networkErrors,\r\n httpErrors,\r\n statusCodes,\r\n errorsByType,\r\n finalSnapshot: histogram.toSnapshot(),\r\n serviceTimeSnapshot: serviceHistogram.toSnapshot(),\r\n ttfbSnapshot: ttfbHistogram.toSnapshot(),\r\n loopLagMaxMs: loopDelay.max / 1_000_000,\r\n loopLagP99Ms: loopDelay.percentile(99) / 1_000_000,\r\n };\r\n parentPort?.postMessage(doneMsg);\r\n}\r\n\r\nrunWorker().catch((err) => {\r\n const errorMsg = err instanceof Error ? err.stack || err.message : String(err);\r\n parentPort?.postMessage({\r\n type: \"error\",\r\n workerIndex: (workerData as WorkerInitData)?.workerIndex ?? -1,\r\n error: errorMsg,\r\n });\r\n});\r\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,67 @@
1
- {
2
- "name": "loadscope",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
1
+ {
2
+ "name": "loadscope",
3
+ "version": "0.1.0",
4
+ "description": "A high-performance HTTP load tester with automated breaking-point finder, Coordinated Omission correction, CI regression gate, and zero-browser PDF/HTML reports",
5
+ "type": "module",
6
+ "bin": {
7
+ "loadscope": "dist/cli.js"
8
+ },
9
+ "main": "dist/index.js",
10
+ "types": "dist/index.d.ts",
11
+ "files": [
12
+ "dist",
13
+ "README.md",
14
+ "LICENSE"
15
+ ],
16
+ "keywords": [
17
+ "load-testing",
18
+ "benchmark",
19
+ "performance",
20
+ "breaking-point",
21
+ "coordinated-omission",
22
+ "http",
23
+ "stress-testing",
24
+ "ci-cd",
25
+ "regression-testing",
26
+ "pdf-report"
27
+ ],
28
+ "author": "Shaik Afrid",
29
+ "repository": {
30
+ "type": "git",
31
+ "url": "git+https://github.com/shaikafridd/loadscope.git"
32
+ },
33
+ "bugs": {
34
+ "url": "https://github.com/shaikafridd/loadscope/issues"
35
+ },
36
+ "homepage": "https://github.com/shaikafridd/loadscope#readme",
37
+ "license": "MIT",
38
+ "engines": {
39
+ "node": ">=20"
40
+ },
41
+ "scripts": {
42
+ "build": "tsup",
43
+ "test": "vitest run",
44
+ "test:watch": "vitest",
45
+ "test-server": "node --loader tsx test-server/index.ts",
46
+ "prepublishOnly": "npm run build && npm test"
47
+ },
48
+ "dependencies": {
49
+ "commander": "^12.1.0",
50
+ "log-update": "^6.0.0",
51
+ "pdfkit": "^0.15.0",
52
+ "picocolors": "^1.1.0",
53
+ "undici": "^6.19.0",
54
+ "yaml": "^2.4.0",
55
+ "zod": "^3.23.0"
56
+ },
57
+ "devDependencies": {
58
+ "@types/node": "^22.0.0",
59
+ "@types/pdfkit": "^0.13.0",
60
+ "hdr-histogram-js": "^3.0.0",
61
+ "pdf-parse": "^1.1.1",
62
+ "tsup": "^8.0.0",
63
+ "tsx": "^4.19.0",
64
+ "typescript": "^5.4.0",
65
+ "vitest": "^2.0.0"
66
+ }
67
+ }