blaze-performance-tester 3.1.60 → 3.1.61
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/bin.js +2 -0
- package/dist/cli.js +286 -296
- package/dist/index.win32-x64-msvc.node +0 -0
- package/package.json +6 -8
package/bin.js
ADDED
package/dist/cli.js
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
#!/usr/bin/env node
|
|
1
|
+
#!/usr/bin/env ts-node
|
|
3
2
|
|
|
4
3
|
// cli.ts
|
|
5
|
-
import { Command } from "commander";
|
|
6
|
-
import chalk from "chalk";
|
|
7
4
|
import { createRequire } from "module";
|
|
8
5
|
import * as path from "path";
|
|
9
6
|
import { fileURLToPath } from "url";
|
|
@@ -137,7 +134,8 @@ var blazeCore;
|
|
|
137
134
|
try {
|
|
138
135
|
blazeCore = require2(nativeBindingPath);
|
|
139
136
|
} catch (e) {
|
|
140
|
-
console.error(
|
|
137
|
+
console.error(`\u274C Failed to load native C++ bindings from ${nativeBindingPath}`);
|
|
138
|
+
process.exit(1);
|
|
141
139
|
}
|
|
142
140
|
var mathUtils = {
|
|
143
141
|
mean: (arr) => arr.length === 0 ? 0 : arr.reduce((p, c) => p + c, 0) / arr.length,
|
|
@@ -153,46 +151,6 @@ var mathUtils = {
|
|
|
153
151
|
return sorted[Math.max(0, index)];
|
|
154
152
|
}
|
|
155
153
|
};
|
|
156
|
-
function getMockRegionalData() {
|
|
157
|
-
return [
|
|
158
|
-
{ zone: "us-east-1", location: "N. Virginia", latencyAvg: 24, p99: 68, errorRate: 0.02, status: "optimal" },
|
|
159
|
-
{ zone: "eu-central-1", location: "Frankfurt", latencyAvg: 42, p99: 115, errorRate: 0.14, status: "stable" },
|
|
160
|
-
{ zone: "ap-south-1", location: "Mumbai", latencyAvg: 88, p99: 210, errorRate: 0.85, status: "elevated" },
|
|
161
|
-
{ zone: "ap-northeast-1", location: "Tokyo", latencyAvg: 55, p99: 130, errorRate: 0.05, status: "stable" },
|
|
162
|
-
{ zone: "sa-east-1", location: "S\xE3o Paulo", latencyAvg: 112, p99: 285, errorRate: 1.2, status: "critical" }
|
|
163
|
-
];
|
|
164
|
-
}
|
|
165
|
-
function renderStatusBadge(status) {
|
|
166
|
-
switch (status) {
|
|
167
|
-
case "optimal":
|
|
168
|
-
return chalk.green("\u{1F7E2} OPTIMAL");
|
|
169
|
-
case "stable":
|
|
170
|
-
return chalk.green("\u{1F7E2} STABLE");
|
|
171
|
-
case "elevated":
|
|
172
|
-
return chalk.yellow("\u{1F7E1} ELEVATED");
|
|
173
|
-
case "critical":
|
|
174
|
-
return chalk.red("\u{1F534} CRITICAL");
|
|
175
|
-
default:
|
|
176
|
-
return chalk.gray("\u26AA UNKNOWN");
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
function renderGeographicHeatmap(regions) {
|
|
180
|
-
console.log(chalk.bold.cyan("\n============================================================"));
|
|
181
|
-
console.log(chalk.bold.cyan(" BLAZE: GEOGRAPHIC LATENCY HEATMAP & MATRIX "));
|
|
182
|
-
console.log(chalk.bold.cyan("============================================================\n"));
|
|
183
|
-
console.log(
|
|
184
|
-
`${chalk.bold("Zone".padEnd(16))} | ${chalk.bold("Location".padEnd(14))} | ${chalk.bold("Avg (ms)".padEnd(10))} | ${chalk.bold("P99 (ms)".padEnd(10))} | ${chalk.bold("Error Rate".padEnd(12))} | ${chalk.bold("Status")}`
|
|
185
|
-
);
|
|
186
|
-
console.log("-".repeat(78));
|
|
187
|
-
for (const r of regions) {
|
|
188
|
-
const errorColor = r.errorRate > 1 ? chalk.red : r.errorRate > 0.5 ? chalk.yellow : chalk.green;
|
|
189
|
-
const latencyColor = r.latencyAvg > 100 ? chalk.yellow : chalk.white;
|
|
190
|
-
console.log(
|
|
191
|
-
`${r.zone.padEnd(16)} | ${r.location.padEnd(14)} | ${latencyColor(String(r.latencyAvg).padEnd(10))} | ${String(r.p99).padEnd(10)} | ${errorColor(`${r.errorRate.toFixed(2)}%`).padEnd(20)} | ${renderStatusBadge(r.status)}`
|
|
192
|
-
);
|
|
193
|
-
}
|
|
194
|
-
console.log("\n");
|
|
195
|
-
}
|
|
196
154
|
function getLoadMultiplier(elapsedMs, rampUpMs, steadyMs, rampDownMs) {
|
|
197
155
|
const totalDurationMs = rampUpMs + steadyMs + rampDownMs;
|
|
198
156
|
if (elapsedMs < rampUpMs && rampUpMs > 0) {
|
|
@@ -210,64 +168,20 @@ function loadBaselineData(filePath) {
|
|
|
210
168
|
try {
|
|
211
169
|
const resolved = path.resolve(filePath);
|
|
212
170
|
if (fs.existsSync(resolved)) {
|
|
213
|
-
console.log(
|
|
171
|
+
console.log(`\u{1F4C1} Loaded baseline comparison telemetry from: ${resolved}`);
|
|
214
172
|
return JSON.parse(fs.readFileSync(resolved, "utf-8"));
|
|
215
173
|
}
|
|
216
174
|
} catch (e) {
|
|
217
|
-
console.error(
|
|
175
|
+
console.error(`\u274C Failed to parse baseline telemetry file: ${e}`);
|
|
218
176
|
}
|
|
219
177
|
return null;
|
|
220
178
|
}
|
|
221
|
-
function calculateSeoImpactMetrics(avgLatencyMs) {
|
|
222
|
-
const baseLineOptimalMs = 200;
|
|
223
|
-
if (avgLatencyMs <= baseLineOptimalMs) {
|
|
224
|
-
return { trafficLoss: 0, status: "Excellent", crawlPenalty: "None", color: "#10b981" };
|
|
225
|
-
}
|
|
226
|
-
const delayFactor = avgLatencyMs - baseLineOptimalMs;
|
|
227
|
-
const trafficLoss = Math.min(94, Math.floor(delayFactor / 1200 * 100));
|
|
228
|
-
let status = "Healthy";
|
|
229
|
-
let crawlPenalty = "Minimal impact on indexing rates.";
|
|
230
|
-
let color = "#10b981";
|
|
231
|
-
if (trafficLoss >= 50) {
|
|
232
|
-
status = "Critical Exposure";
|
|
233
|
-
crawlPenalty = "Severe penalty. Googlebot will heavily restrict crawl budgets due to timeout risks.";
|
|
234
|
-
color = "#ef4444";
|
|
235
|
-
} else if (trafficLoss >= 20) {
|
|
236
|
-
status = "Moderate Danger";
|
|
237
|
-
crawlPenalty = "Delayed indexation. Core Web Vital thresholds are officially breached.";
|
|
238
|
-
color = "#f97316";
|
|
239
|
-
} else if (trafficLoss > 5) {
|
|
240
|
-
status = "Minor Impact";
|
|
241
|
-
crawlPenalty = "Slightly elevated bounce trends could impact highly volatile rankings.";
|
|
242
|
-
color = "#eab308";
|
|
243
|
-
}
|
|
244
|
-
return { trafficLoss, status, crawlPenalty, color };
|
|
245
|
-
}
|
|
246
|
-
function computeHealthScoreValue(apdex, errorRate, p95Latency, maxAllowedLatency) {
|
|
247
|
-
const apdexComponent = apdex * 50;
|
|
248
|
-
const errorComponent = Math.max(0, 1 - errorRate) * 30;
|
|
249
|
-
const latencyRatio = p95Latency / maxAllowedLatency;
|
|
250
|
-
const latencyComponent = Math.max(0, 1 - Math.min(1, latencyRatio)) * 20;
|
|
251
|
-
return Math.min(100, Math.max(0, Math.round(apdexComponent + errorComponent + latencyComponent)));
|
|
252
|
-
}
|
|
253
|
-
function getFallbackClusterLogs() {
|
|
254
|
-
const logs = [];
|
|
255
|
-
const add = (msg, count) => {
|
|
256
|
-
for (let i = 0; i < count; i++) logs.push(`[2026-07-08T12:08:18.000Z] ${msg}`);
|
|
257
|
-
};
|
|
258
|
-
add("JsonWebTokenError: jwt expired at JMT.verify (\\app\\node_modules\\jsonwebtoken\\index.js:5)", 37);
|
|
259
|
-
add("Error: ECONNREFUSED 127.0.0.1:5432 at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1)", 33);
|
|
260
|
-
add("TypeError: Cannot read properties of undefined (reading 'config_id') at Object.execute (\\app\\dist\\handler.js:42:19)", 31);
|
|
261
|
-
add("HTTP/1.1 504 Gateway Timeout on POST /api/v1/checkout - upstream socket drop after 15000ms", 25);
|
|
262
|
-
add("HTTP/1.1 504 Gateway Timeout on POST /api/v1/checkout - upstream socket drop after 30000ms", 19);
|
|
263
|
-
return logs;
|
|
264
|
-
}
|
|
265
179
|
async function generateGeminiRCA(history, finalSummary, errorLogs) {
|
|
266
180
|
const apiKey = process.env.GEMINI_API_KEY;
|
|
267
181
|
if (!apiKey) {
|
|
268
182
|
return `<span style="color: #ef4444;">\u26A0\uFE0F Gemini API Key missing. Export GEMINI_API_KEY to enable automated 2.5 Flash RCA analysis.</span>`;
|
|
269
183
|
}
|
|
270
|
-
console.log(
|
|
184
|
+
console.log("\u{1F9E0} Querying Gemini 2.5 Flash for Advanced Root Cause Analysis...");
|
|
271
185
|
const formattedHistory = history.map(
|
|
272
186
|
(h) => `Threads: ${h.threads} VUs | Throughput: ${h.throughput.toFixed(1)} req/s | Avg Latency: ${h.avgLatency.toFixed(1)}ms | Errors: ${(h.errorRate * 100).toFixed(2)}% | Apdex: ${h.apdex.toFixed(2)}`
|
|
273
187
|
).join("\n");
|
|
@@ -323,97 +237,127 @@ CRITICAL: Return ONLY plain paragraph text. Do not use markdown headers (###). I
|
|
|
323
237
|
}
|
|
324
238
|
return candidateText.replace(/\*\*(.*?)\*\*/g, "<strong>$1</strong>").replace(/\n/g, "<br>");
|
|
325
239
|
} catch (error) {
|
|
326
|
-
console.error(
|
|
240
|
+
console.error("\u274C Gemini API processing breakdown failure:", error);
|
|
327
241
|
return `<span style="color: #f87171;">Failed to generate AI diagnosis framework: ${error.message || error}</span>`;
|
|
328
242
|
}
|
|
329
243
|
}
|
|
330
|
-
function
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
const
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
let statusCode = 200;
|
|
351
|
-
if (isError) {
|
|
352
|
-
const targetResponseCodes = [400, 401, 403, 404, 429, 500, 502, 503, 504];
|
|
353
|
-
statusCode = targetResponseCodes[Math.floor(Math.random() * targetResponseCodes.length)];
|
|
354
|
-
errorMessage = errorPool[Math.floor(Math.random() * errorPool.length)];
|
|
244
|
+
async function executeTestPipeline(config) {
|
|
245
|
+
if (!blazeCore || typeof blazeCore.runCorrelatedTransaction !== "function") {
|
|
246
|
+
console.error("\u274C Error: runCorrelatedTransaction function is missing from the compiled binary bindings.");
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
const transactionalScenario = [
|
|
250
|
+
{
|
|
251
|
+
name: "Fetch Target Anti-Forgery Nonce",
|
|
252
|
+
url: "https://httpbin.org/json",
|
|
253
|
+
method: "GET",
|
|
254
|
+
body: null
|
|
255
|
+
},
|
|
256
|
+
{
|
|
257
|
+
name: "Perform Contextual Post Action",
|
|
258
|
+
url: "https://httpbin.org/post?verification=${csrf_token}",
|
|
259
|
+
method: "POST",
|
|
260
|
+
body: JSON.stringify({
|
|
261
|
+
data: "performance_payload",
|
|
262
|
+
security_token: "${csrf_token}"
|
|
263
|
+
})
|
|
355
264
|
}
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
265
|
+
];
|
|
266
|
+
console.log(`Launching automated script transaction analysis for: ${config.targetScript}`);
|
|
267
|
+
const sanitizedSteps = transactionalScenario.map((step) => ({
|
|
268
|
+
...step,
|
|
269
|
+
body: typeof step.body === "string" ? step.body : step.body ? JSON.stringify(step.body) : ""
|
|
270
|
+
}));
|
|
271
|
+
const success = await blazeCore.runCorrelatedTransaction(sanitizedSteps);
|
|
272
|
+
if (success) {
|
|
273
|
+
console.log("Pipeline run complete. Parameter tracking successfully mitigated breaking changes.");
|
|
365
274
|
}
|
|
366
|
-
return data.sort((a, b) => a.timestampMs - b.timestampMs);
|
|
367
275
|
}
|
|
368
|
-
function
|
|
369
|
-
const
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
const
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
276
|
+
async function main() {
|
|
277
|
+
const args = process.argv.slice(2);
|
|
278
|
+
if (args.length === 0 || args.includes("--help") || args.includes("-h")) {
|
|
279
|
+
printUsage();
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
const config = parseArguments(args);
|
|
283
|
+
if (config.isCorrelate) {
|
|
284
|
+
await executeTestPipeline(config);
|
|
285
|
+
}
|
|
286
|
+
if (config.isAgentic) {
|
|
287
|
+
await runIntelligentAgenticStressTest(config);
|
|
288
|
+
} else {
|
|
289
|
+
await runStandardStressTest(config);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
function parseArguments(args) {
|
|
293
|
+
const targetScript = path.resolve(args[0] || ".");
|
|
294
|
+
const isAgentic = args.includes("--agentic");
|
|
295
|
+
const isCorrelate = args.includes("--correlate");
|
|
296
|
+
const isSeo = args.includes("--seo");
|
|
297
|
+
const clusterLogs = !args.includes("--no-cluster-logs");
|
|
298
|
+
let threads = 10;
|
|
299
|
+
let durationSec = 10;
|
|
300
|
+
let rampUpSec = 0;
|
|
301
|
+
let rampDownSec = 0;
|
|
302
|
+
let targetApdex = 0.85;
|
|
303
|
+
let targetErrorRate = 0.01;
|
|
304
|
+
let maxThreads = 300;
|
|
305
|
+
let maxAllowedLatencyMs = 800;
|
|
306
|
+
let outputHtml = "blaze-dashboard.html";
|
|
307
|
+
let baselinePath = null;
|
|
308
|
+
const threadsIdx = args.indexOf("--threads");
|
|
309
|
+
if (threadsIdx !== -1) threads = parseInt(args[threadsIdx + 1], 10);
|
|
310
|
+
const durationIdx = args.indexOf("--duration");
|
|
311
|
+
if (durationIdx !== -1) durationSec = parseInt(args[durationIdx + 1], 10);
|
|
312
|
+
const rampUpIdx = args.indexOf("--ramp-up");
|
|
313
|
+
if (rampUpIdx !== -1) rampUpSec = parseInt(args[rampUpIdx + 1], 10);
|
|
314
|
+
const rampDownIdx = args.indexOf("--ramp-down");
|
|
315
|
+
if (rampDownIdx !== -1) rampDownSec = parseInt(args[rampDownIdx + 1], 10);
|
|
316
|
+
const apdexIdx = args.indexOf("--target-apdex");
|
|
317
|
+
if (apdexIdx !== -1) targetApdex = parseFloat(apdexIdx + 1);
|
|
318
|
+
const errorIdx = args.indexOf("--target-error");
|
|
319
|
+
if (errorIdx !== -1) targetErrorRate = parseFloat(args[errorIdx + 1]);
|
|
320
|
+
const maxThreadsIdx = args.indexOf("--max-threads");
|
|
321
|
+
if (maxThreadsIdx !== -1) maxThreads = parseInt(args[maxThreadsIdx + 1], 10);
|
|
322
|
+
const outputIdx = args.indexOf("--output");
|
|
323
|
+
if (outputIdx !== -1) outputHtml = args[outputIdx + 1];
|
|
324
|
+
const baselineIdx = args.indexOf("--baseline");
|
|
325
|
+
if (baselineIdx !== -1) baselinePath = args[baselineIdx + 1];
|
|
326
|
+
const positionalNums = args.slice(1).filter((arg) => !arg.startsWith("-")).map(Number).filter((n) => !isNaN(n));
|
|
327
|
+
if (positionalNums.length > 0 && threadsIdx === -1 && !isAgentic) threads = positionalNums[0];
|
|
328
|
+
if (positionalNums.length > 1 && durationIdx === -1 && !isAgentic) durationSec = positionalNums[1];
|
|
329
|
+
if (positionalNums.length > 2 && errorIdx === -1 && !isAgentic) targetErrorRate = positionalNums[2] / 100;
|
|
330
|
+
if (isAgentic) {
|
|
331
|
+
const agenticIdx = args.indexOf("--agentic");
|
|
332
|
+
const trailingArgs = args.slice(agenticIdx + 1).filter((arg) => !arg.startsWith("--"));
|
|
333
|
+
if (trailingArgs[0]) maxThreads = parseInt(trailingArgs[0], 10);
|
|
334
|
+
if (trailingArgs[1]) {
|
|
335
|
+
let rawLatency = parseFloat(trailingArgs[1]);
|
|
336
|
+
if (rawLatency < 50) {
|
|
337
|
+
maxAllowedLatencyMs = rawLatency * 1e3;
|
|
338
|
+
} else {
|
|
339
|
+
maxAllowedLatencyMs = rawLatency;
|
|
340
|
+
}
|
|
389
341
|
}
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
const errorRate = totalRequests === 0 ? 0 : errorCount / totalRequests;
|
|
393
|
-
const T = 50;
|
|
394
|
-
const satisfied = requests.filter((r) => r.durationMs <= T && r.statusCode < 400).length;
|
|
395
|
-
const tolerating = requests.filter((r) => r.durationMs > T && r.durationMs <= T * 4 && r.statusCode < 400).length;
|
|
396
|
-
const apdexScore = totalRequests === 0 ? 0 : (satisfied + tolerating / 2) / totalRequests;
|
|
397
|
-
const bandwidthMb = totalRequests * 1.2 / durationSec / 10;
|
|
342
|
+
if (trailingArgs[2]) targetErrorRate = parseFloat(trailingArgs[2]) / 100;
|
|
343
|
+
}
|
|
398
344
|
return {
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
bandwidthMb,
|
|
416
|
-
codeCounts
|
|
345
|
+
targetScript,
|
|
346
|
+
isAgentic,
|
|
347
|
+
isCorrelate,
|
|
348
|
+
isSeo,
|
|
349
|
+
clusterLogs,
|
|
350
|
+
threads,
|
|
351
|
+
durationSec,
|
|
352
|
+
rampUpSec,
|
|
353
|
+
rampDownSec,
|
|
354
|
+
targetApdex,
|
|
355
|
+
targetErrorRate,
|
|
356
|
+
maxThreads,
|
|
357
|
+
stepSize: 15,
|
|
358
|
+
maxAllowedLatencyMs,
|
|
359
|
+
outputHtml,
|
|
360
|
+
baselinePath
|
|
417
361
|
};
|
|
418
362
|
}
|
|
419
363
|
async function runBlazeCoreEngine(config) {
|
|
@@ -437,62 +381,40 @@ async function runBlazeCoreEngine(config) {
|
|
|
437
381
|
}, 1e3);
|
|
438
382
|
});
|
|
439
383
|
}
|
|
440
|
-
function
|
|
441
|
-
const
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
console.log(`-----------------------------------------------------------------------------------------`);
|
|
445
|
-
console.log(`| ${pad(threads, 7)} | ${pad(m.totalRequests, 9)} | ${pad(m.avgLatencyMs.toFixed(1) + "ms", 11)} | ${pad(m.p95LatencyMs.toFixed(1) + "ms", 11)} | ${pad(m.requestsPerSecond.toFixed(0) + "/s", 10)} | ${pad((m.errorRate * 100).toFixed(2) + "%", 10)} | ${pad(m.apdexScore.toFixed(2), 9)} |`);
|
|
446
|
-
console.log(`-----------------------------------------------------------------------------------------`);
|
|
447
|
-
}
|
|
448
|
-
function generateFinalAgentReport(history, score) {
|
|
449
|
-
if (history.length === 0) return;
|
|
450
|
-
const peakThroughput = Math.max(...history.map((h) => h.throughput));
|
|
451
|
-
const cleanRuns = history.filter((h) => h.apdex >= 0.85 && h.errorRate <= 0.01);
|
|
452
|
-
const maxSafeThreads = cleanRuns.length > 0 ? cleanRuns[cleanRuns.length - 1].threads : history[0].threads;
|
|
453
|
-
console.log(chalk.bold.green("\n======================================================="));
|
|
454
|
-
console.log(chalk.bold.cyan("\u{1F9E0} INTELLIGENT AUTONOMOUS LOAD AGENT FINAL REPORT"));
|
|
455
|
-
console.log(chalk.bold.green("======================================================="));
|
|
456
|
-
console.log(`\u{1F7E2} Unified Blaze Health Score : ${score}/100`);
|
|
457
|
-
console.log(`\u{1F3C6} Recommended Max Safe Concurrency : ${maxSafeThreads} allocation threads`);
|
|
458
|
-
console.log(`\u{1F4A5} Infrastructure Failure Boundary : ${history[history.length - 1].threads} concurrency allocation`);
|
|
459
|
-
console.log(`\u26A1 Peak Achieved Cluster Velocity : ${peakThroughput.toFixed(0)} req/sec`);
|
|
460
|
-
console.log(chalk.bold.green("=======================================================\n"));
|
|
461
|
-
}
|
|
462
|
-
async function executeTestPipeline(config) {
|
|
463
|
-
if (!blazeCore || typeof blazeCore.runCorrelatedTransaction !== "function") {
|
|
464
|
-
console.error(chalk.red("\u274C Error: runCorrelatedTransaction function is missing from the compiled binary bindings."));
|
|
465
|
-
return;
|
|
384
|
+
function calculateSeoImpactMetrics(avgLatencyMs) {
|
|
385
|
+
const baseLineOptimalMs = 200;
|
|
386
|
+
if (avgLatencyMs <= baseLineOptimalMs) {
|
|
387
|
+
return { trafficLoss: 0, status: "Excellent", crawlPenalty: "None", color: "#10b981" };
|
|
466
388
|
}
|
|
467
|
-
const
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
console.log(chalk.blue(`Launching automated script transaction analysis for: ${config.targetScript}`));
|
|
485
|
-
const sanitizedSteps = transactionalScenario.map((step) => ({
|
|
486
|
-
...step,
|
|
487
|
-
body: typeof step.body === "string" ? step.body : step.body ? JSON.stringify(step.body) : ""
|
|
488
|
-
}));
|
|
489
|
-
const success = await blazeCore.runCorrelatedTransaction(sanitizedSteps);
|
|
490
|
-
if (success) {
|
|
491
|
-
console.log(chalk.green("Pipeline run complete. Parameter tracking successfully mitigated breaking changes."));
|
|
389
|
+
const delayFactor = avgLatencyMs - baseLineOptimalMs;
|
|
390
|
+
const trafficLoss = Math.min(94, Math.floor(delayFactor / 1200 * 100));
|
|
391
|
+
let status = "Healthy";
|
|
392
|
+
let crawlPenalty = "Minimal impact on indexing rates.";
|
|
393
|
+
let color = "#10b981";
|
|
394
|
+
if (trafficLoss >= 50) {
|
|
395
|
+
status = "Critical Exposure";
|
|
396
|
+
crawlPenalty = "Severe penalty. Googlebot will heavily restrict crawl budgets due to timeout risks.";
|
|
397
|
+
color = "#ef4444";
|
|
398
|
+
} else if (trafficLoss >= 20) {
|
|
399
|
+
status = "Moderate Danger";
|
|
400
|
+
crawlPenalty = "Delayed indexation. Core Web Vital thresholds are officially breached.";
|
|
401
|
+
color = "#f97316";
|
|
402
|
+
} else if (trafficLoss > 5) {
|
|
403
|
+
status = "Minor Impact";
|
|
404
|
+
crawlPenalty = "Slightly elevated bounce trends could impact highly volatile rankings.";
|
|
405
|
+
color = "#eab308";
|
|
492
406
|
}
|
|
407
|
+
return { trafficLoss, status, crawlPenalty, color };
|
|
408
|
+
}
|
|
409
|
+
function computeHealthScoreValue(apdex, errorRate, p95Latency, maxAllowedLatency) {
|
|
410
|
+
const apdexComponent = apdex * 50;
|
|
411
|
+
const errorComponent = Math.max(0, 1 - errorRate) * 30;
|
|
412
|
+
const latencyRatio = p95Latency / maxAllowedLatency;
|
|
413
|
+
const latencyComponent = Math.max(0, 1 - Math.min(1, latencyRatio)) * 20;
|
|
414
|
+
return Math.min(100, Math.max(0, Math.round(apdexComponent + errorComponent + latencyComponent)));
|
|
493
415
|
}
|
|
494
416
|
async function runIntelligentAgenticStressTest(config) {
|
|
495
|
-
console.log(
|
|
417
|
+
console.log("\u{1F680} Initializing Intelligent Autonomous Load Agent...");
|
|
496
418
|
const history = [];
|
|
497
419
|
let aggregateErrorLogs = [];
|
|
498
420
|
let lastRawRequests = [];
|
|
@@ -506,7 +428,7 @@ async function runIntelligentAgenticStressTest(config) {
|
|
|
506
428
|
let verdictReason = "The system successfully scaled and remained stable within parameters up to maximum configured capacity allocations.";
|
|
507
429
|
let saturationKneePoint = null;
|
|
508
430
|
while (currentThreads <= config.maxThreads && isStable) {
|
|
509
|
-
console.log(
|
|
431
|
+
console.log(`\u{1F916} [Agent Decision]: Testing execution tier at ${currentThreads} concurrent threads...`);
|
|
510
432
|
const { metrics, rawErrors, rawRequests } = await runBlazeCoreEngine({ ...config, threads: currentThreads });
|
|
511
433
|
if (config.clusterLogs) {
|
|
512
434
|
aggregateErrorLogs = aggregateErrorLogs.concat(rawErrors);
|
|
@@ -599,7 +521,7 @@ async function runIntelligentAgenticStressTest(config) {
|
|
|
599
521
|
if (config.isSeo) {
|
|
600
522
|
const finalLat = finalState.avgLatency || finalSummaryCards.ttfb;
|
|
601
523
|
const seo = calculateSeoImpactMetrics(finalLat);
|
|
602
|
-
console.log(
|
|
524
|
+
console.log(`\u{1F50E} [SEO Impact Report]: Target latency under stress (${finalLat.toFixed(1)}ms) triggers a predicted Search Visibility Loss of -${seo.trafficLoss}% [Status: ${seo.status}].`);
|
|
603
525
|
}
|
|
604
526
|
const breakdownRates = {};
|
|
605
527
|
Object.keys(globalCodeCounts).forEach((codeStr) => {
|
|
@@ -610,11 +532,11 @@ async function runIntelligentAgenticStressTest(config) {
|
|
|
610
532
|
exportHtmlDashboard(history, config, verdictReason, semanticReport, { total1xx, total2xx, total3xx, total4xx, total5xx, breakdownRates }, finalSummaryCards, lastRawRequests, geminiAnalysisHtml, baselineData);
|
|
611
533
|
}
|
|
612
534
|
async function runStandardStressTest(config) {
|
|
613
|
-
console.log(
|
|
535
|
+
console.log(`\u{1F3CB}\uFE0F Running Standard Stress Test [Threads: ${config.threads} | Duration: ${config.durationSec}s | RampUp: ${config.rampUpSec}s | RampDown: ${config.rampDownSec}s]`);
|
|
614
536
|
const { metrics, rawErrors, rawRequests } = await runBlazeCoreEngine(config);
|
|
615
537
|
printMatrixDashboard(metrics, config.threads);
|
|
616
538
|
const healthScore = computeHealthScoreValue(metrics.apdexScore, metrics.errorRate, metrics.p95LatencyMs, config.maxAllowedLatencyMs);
|
|
617
|
-
console.log(
|
|
539
|
+
console.log(`\u{1F49A} Unified Blaze Health Score: ${healthScore}/100`);
|
|
618
540
|
const history = [{
|
|
619
541
|
threads: config.threads,
|
|
620
542
|
avgLatency: metrics.avgLatencyMs,
|
|
@@ -651,7 +573,7 @@ async function runStandardStressTest(config) {
|
|
|
651
573
|
const geminiAnalysisHtml = await generateGeminiRCA(history, finalSummaryCards, rawErrors.length > 0 ? rawErrors : getFallbackClusterLogs());
|
|
652
574
|
if (config.isSeo) {
|
|
653
575
|
const seo = calculateSeoImpactMetrics(metrics.avgLatencyMs);
|
|
654
|
-
console.log(
|
|
576
|
+
console.log(`\u{1F50E} [SEO Impact Report]: Target latency (${metrics.avgLatencyMs.toFixed(1)}ms) triggers a predicted Search Visibility Loss of -${seo.trafficLoss}% [Status: ${seo.status}].`);
|
|
655
577
|
}
|
|
656
578
|
const breakdownRates = {};
|
|
657
579
|
Object.keys(metrics.codeCounts).forEach((codeStr) => {
|
|
@@ -668,6 +590,129 @@ async function runStandardStressTest(config) {
|
|
|
668
590
|
breakdownRates
|
|
669
591
|
}, finalSummaryCards, rawRequests, geminiAnalysisHtml, baselineData);
|
|
670
592
|
}
|
|
593
|
+
function getFallbackClusterLogs() {
|
|
594
|
+
const logs = [];
|
|
595
|
+
const add = (msg, count) => {
|
|
596
|
+
for (let i = 0; i < count; i++) logs.push(`[2026-07-08T12:08:18.000Z] ${msg}`);
|
|
597
|
+
};
|
|
598
|
+
add("JsonWebTokenError: jwt expired at JMT.verify (\\app\\node_modules\\jsonwebtoken\\index.js:5)", 37);
|
|
599
|
+
add("Error: ECONNREFUSED 127.0.0.1:5432 at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1)", 33);
|
|
600
|
+
add("TypeError: Cannot read properties of undefined (reading 'config_id') at Object.execute (\\app\\dist\\handler.js:42:19)", 31);
|
|
601
|
+
add("HTTP/1.1 504 Gateway Timeout on POST /api/v1/checkout - upstream socket drop after 15000ms", 25);
|
|
602
|
+
add("HTTP/1.1 504 Gateway Timeout on POST /api/v1/checkout - upstream socket drop after 30000ms", 19);
|
|
603
|
+
return logs;
|
|
604
|
+
}
|
|
605
|
+
function generateSimulationData(threads, durationSec, maxAllowedLatencyMs, rampUpSec = 0, rampDownSec = 0) {
|
|
606
|
+
const data = [];
|
|
607
|
+
const totalRequests = Math.max(15, threads * durationSec * 30);
|
|
608
|
+
const startTime = Date.now();
|
|
609
|
+
const rampUpMs = rampUpSec * 1e3;
|
|
610
|
+
const steadyMs = durationSec * 1e3;
|
|
611
|
+
const rampDownMs = rampDownSec * 1e3;
|
|
612
|
+
const totalTestMs = rampUpMs + steadyMs + rampDownMs;
|
|
613
|
+
const targetThresholdBreak = Math.max(5, Math.floor(maxAllowedLatencyMs * 0.05));
|
|
614
|
+
const errorPool = getFallbackClusterLogs();
|
|
615
|
+
for (let i = 0; i < totalRequests; i++) {
|
|
616
|
+
const offsetMs = Math.random() * totalTestMs;
|
|
617
|
+
const loadFactor = getLoadMultiplier(offsetMs, rampUpMs, steadyMs, rampDownMs);
|
|
618
|
+
if (loadFactor <= 0) continue;
|
|
619
|
+
const effectiveThreads = Math.max(1, threads * loadFactor);
|
|
620
|
+
const isBreached = effectiveThreads > targetThresholdBreak;
|
|
621
|
+
const stressFactor = isBreached ? Math.pow(effectiveThreads / targetThresholdBreak, 1.5) : 1;
|
|
622
|
+
const isError = Math.random() < (isBreached ? 0.05 : 1e-3);
|
|
623
|
+
const baseLatency = (25 + Math.random() * 35) * stressFactor;
|
|
624
|
+
let errorMessage;
|
|
625
|
+
let statusCode = 200;
|
|
626
|
+
if (isError) {
|
|
627
|
+
const targetResponseCodes = [400, 401, 403, 404, 429, 500, 502, 503, 504];
|
|
628
|
+
statusCode = targetResponseCodes[Math.floor(Math.random() * targetResponseCodes.length)];
|
|
629
|
+
errorMessage = errorPool[Math.floor(Math.random() * errorPool.length)];
|
|
630
|
+
}
|
|
631
|
+
data.push({
|
|
632
|
+
durationMs: isError ? baseLatency * 0.1 : baseLatency,
|
|
633
|
+
timestampMs: startTime + offsetMs,
|
|
634
|
+
dnsTimeMs: 1 + Math.random() * 0.9,
|
|
635
|
+
tcpTimeMs: 4 + Math.random() * 1.5,
|
|
636
|
+
tlsTimeMs: 6 + Math.random() * 1.8,
|
|
637
|
+
statusCode,
|
|
638
|
+
errorMessage
|
|
639
|
+
});
|
|
640
|
+
}
|
|
641
|
+
return data.sort((a, b) => a.timestampMs - b.timestampMs);
|
|
642
|
+
}
|
|
643
|
+
function processMetricsTelemetry(requests, durationSec) {
|
|
644
|
+
const totalRequests = requests.length;
|
|
645
|
+
const durations = requests.map((r) => r.durationMs);
|
|
646
|
+
const avgLatencyMs = mathUtils.mean(durations);
|
|
647
|
+
const stdDevMs = mathUtils.stdDev(durations, avgLatencyMs);
|
|
648
|
+
const p95LatencyMs = mathUtils.percentile(durations, 95);
|
|
649
|
+
const avgDnsMs = mathUtils.mean(requests.map((r) => r.dnsTimeMs || 0));
|
|
650
|
+
const avgTcpMs = mathUtils.mean(requests.map((r) => r.tcpTimeMs || 0));
|
|
651
|
+
const avgTlsMs = mathUtils.mean(requests.map((r) => r.tlsTimeMs || 0));
|
|
652
|
+
const avgTtfbMs = avgDnsMs + avgTcpMs + avgTlsMs + avgLatencyMs * 0.3;
|
|
653
|
+
let c1xx = 0, c2xx = 0, c3xx = 0, c4xx = 0, c5xx = 0;
|
|
654
|
+
const codeCounts = { 400: 0, 401: 0, 403: 0, 404: 0, 429: 0, 500: 0, 502: 0, 503: 0, 504: 0 };
|
|
655
|
+
[400, 401, 403, 404, 429, 500, 502, 503, 504].forEach((c) => codeCounts[c] = 0);
|
|
656
|
+
requests.forEach((r) => {
|
|
657
|
+
if (r.statusCode >= 100 && r.statusCode < 200) c1xx++;
|
|
658
|
+
else if (r.statusCode >= 200 && r.statusCode < 300) c2xx++;
|
|
659
|
+
else if (r.statusCode >= 300 && r.statusCode < 400) c3xx++;
|
|
660
|
+
else if (r.statusCode >= 400 && r.statusCode < 500) c4xx++;
|
|
661
|
+
else if (r.statusCode >= 500) c5xx++;
|
|
662
|
+
if (r.statusCode in codeCounts) {
|
|
663
|
+
codeCounts[r.statusCode]++;
|
|
664
|
+
}
|
|
665
|
+
});
|
|
666
|
+
const errorCount = c4xx + c5xx;
|
|
667
|
+
const errorRate = totalRequests === 0 ? 0 : errorCount / totalRequests;
|
|
668
|
+
const T = 50;
|
|
669
|
+
const satisfied = requests.filter((r) => r.durationMs <= T && r.statusCode < 400).length;
|
|
670
|
+
const tolerating = requests.filter((r) => r.durationMs > T && r.durationMs <= T * 4 && r.statusCode < 400).length;
|
|
671
|
+
const apdexScore = totalRequests === 0 ? 0 : (satisfied + tolerating / 2) / totalRequests;
|
|
672
|
+
const bandwidthMb = totalRequests * 1.2 / durationSec / 10;
|
|
673
|
+
return {
|
|
674
|
+
totalRequests,
|
|
675
|
+
requestsPerSecond: totalRequests / durationSec,
|
|
676
|
+
avgLatencyMs,
|
|
677
|
+
stdDevMs,
|
|
678
|
+
p95LatencyMs,
|
|
679
|
+
errorRate,
|
|
680
|
+
apdexScore,
|
|
681
|
+
c1xx,
|
|
682
|
+
c2xx,
|
|
683
|
+
c3xx,
|
|
684
|
+
c4xx,
|
|
685
|
+
c5xx,
|
|
686
|
+
avgDnsMs,
|
|
687
|
+
avgTcpMs,
|
|
688
|
+
avgTlsMs,
|
|
689
|
+
avgTtfbMs,
|
|
690
|
+
bandwidthMb,
|
|
691
|
+
codeCounts
|
|
692
|
+
};
|
|
693
|
+
}
|
|
694
|
+
function printMatrixDashboard(m, threads) {
|
|
695
|
+
const pad = (val, size) => String(val).padEnd(size).substring(0, size);
|
|
696
|
+
console.log(`-----------------------------------------------------------------------------------------`);
|
|
697
|
+
console.log(`| Threads | Samples | Avg Latency | P95 Latency | Throughput | Error Rate | Apdex |`);
|
|
698
|
+
console.log(`-----------------------------------------------------------------------------------------`);
|
|
699
|
+
console.log(`| ${pad(threads, 7)} | ${pad(m.totalRequests, 9)} | ${pad(m.avgLatencyMs.toFixed(1) + "ms", 11)} | ${pad(m.p95LatencyMs.toFixed(1) + "ms", 11)} | ${pad(m.requestsPerSecond.toFixed(0) + "/s", 10)} | ${pad((m.errorRate * 100).toFixed(2) + "%", 10)} | ${pad(m.apdexScore.toFixed(2), 9)} |`);
|
|
700
|
+
console.log(`-----------------------------------------------------------------------------------------`);
|
|
701
|
+
}
|
|
702
|
+
function generateFinalAgentReport(history, score) {
|
|
703
|
+
if (history.length === 0) return;
|
|
704
|
+
const peakThroughput = Math.max(...history.map((h) => h.throughput));
|
|
705
|
+
const cleanRuns = history.filter((h) => h.apdex >= 0.85 && h.errorRate <= 0.01);
|
|
706
|
+
const maxSafeThreads = cleanRuns.length > 0 ? cleanRuns[cleanRuns.length - 1].threads : history[0].threads;
|
|
707
|
+
console.log("\n=======================================================");
|
|
708
|
+
console.log("\u{1F9E0} INTELLIGENT AUTONOMOUS LOAD AGENT FINAL REPORT");
|
|
709
|
+
console.log("=======================================================");
|
|
710
|
+
console.log(`\u{1F49A} Unified Blaze Health Score : ${score}/100`);
|
|
711
|
+
console.log(`\u{1F3C6} Recommended Max Safe Concurrency : ${maxSafeThreads} allocation threads`);
|
|
712
|
+
console.log(`\u{1F4A5} Infrastructure Failure Boundary : ${history[history.length - 1].threads} concurrency allocation`);
|
|
713
|
+
console.log(`\u26A1 Peak Achieved Cluster Velocity : ${peakThroughput.toFixed(0)} req/sec`);
|
|
714
|
+
console.log("=======================================================\n");
|
|
715
|
+
}
|
|
671
716
|
function exportHtmlDashboard(history, config, verdictReason, semanticReport, responseMatrix, cards, rawRequests = [], geminiAnalysisHtml = "", baselineData = null) {
|
|
672
717
|
const summaryArtifactPath = config.outputHtml.replace(/\.html$/, "-summary.json");
|
|
673
718
|
try {
|
|
@@ -1158,7 +1203,7 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
1158
1203
|
const feedback = document.getElementById('nlpQueryFeedback');
|
|
1159
1204
|
|
|
1160
1205
|
let filterFn = (row, data) => true;
|
|
1161
|
-
const numMatch = q.match(/(
|
|
1206
|
+
const numMatch = q.match(/(d+(?:.d+)?)/);
|
|
1162
1207
|
const targetNum = numMatch ? parseFloat(numMatch[1]) : null;
|
|
1163
1208
|
|
|
1164
1209
|
const isGreater = q.includes('>') || q.includes('greater') || q.includes('above') || q.includes('more');
|
|
@@ -1386,69 +1431,14 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
1386
1431
|
</script></body></html>`;
|
|
1387
1432
|
try {
|
|
1388
1433
|
fs.writeFileSync(config.outputHtml, htmlContent, "utf-8");
|
|
1389
|
-
console.log(
|
|
1434
|
+
console.log(`\u{1F4CA} Standalone Dashboard exported successfully to: ${path.resolve(config.outputHtml)}`);
|
|
1390
1435
|
} catch (err) {
|
|
1391
|
-
console.error(
|
|
1436
|
+
console.error(`\u274C Failed to write HTML output dashboard: ${err}`);
|
|
1392
1437
|
}
|
|
1393
1438
|
}
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
const parsedRampDown = parseInt(options.rampDown, 10) || 0;
|
|
1401
|
-
const parsedApdex = parseFloat(options.targetApdex);
|
|
1402
|
-
const parsedError = parseFloat(options.targetError);
|
|
1403
|
-
const parsedMaxThreads = parseInt(options.maxThreads, 10);
|
|
1404
|
-
const parsedMaxLatencyRaw = parseFloat(options.maxAllowedLatency || "800");
|
|
1405
|
-
const parsedMaxLatency = parsedMaxLatencyRaw < 50 ? parsedMaxLatencyRaw * 1e3 : parsedMaxLatencyRaw;
|
|
1406
|
-
const config = {
|
|
1407
|
-
targetScript: path.resolve(script || "."),
|
|
1408
|
-
isAgentic: !!options.agentic,
|
|
1409
|
-
isCorrelate: !!options.correlate,
|
|
1410
|
-
isSeo: !!options.seo,
|
|
1411
|
-
clusterLogs: options.clusterLogs !== false,
|
|
1412
|
-
threads: parsedThreads,
|
|
1413
|
-
durationSec: parsedDuration,
|
|
1414
|
-
rampUpSec: parsedRampUp,
|
|
1415
|
-
rampDownSec: parsedRampDown,
|
|
1416
|
-
targetApdex: parsedApdex,
|
|
1417
|
-
targetErrorRate: parsedError,
|
|
1418
|
-
maxThreads: parsedMaxThreads,
|
|
1419
|
-
stepSize: 15,
|
|
1420
|
-
maxAllowedLatencyMs: parsedMaxLatency,
|
|
1421
|
-
outputHtml: options.output,
|
|
1422
|
-
baselinePath: options.baseline || null
|
|
1423
|
-
};
|
|
1424
|
-
if (options.regions) {
|
|
1425
|
-
console.log(chalk.blue(`
|
|
1426
|
-
Initializing Blaze load test simulation against ${chalk.bold(options.url)}...`));
|
|
1427
|
-
console.log(chalk.gray(`Target regions: ${options.regions}`));
|
|
1428
|
-
console.log(chalk.gray(`Duration: ${options.duration}s
|
|
1429
|
-
`));
|
|
1430
|
-
await new Promise((resolve2) => {
|
|
1431
|
-
setTimeout(() => {
|
|
1432
|
-
const allRegions = getMockRegionalData();
|
|
1433
|
-
const requestedZones = options.regions.split(",").map((z) => z.trim());
|
|
1434
|
-
const filteredRegions = allRegions.filter((r) => requestedZones.includes(r.zone));
|
|
1435
|
-
renderGeographicHeatmap(filteredRegions.length > 0 ? filteredRegions : allRegions);
|
|
1436
|
-
console.log(chalk.gray(`Executing localized system stress verification pipelines...
|
|
1437
|
-
`));
|
|
1438
|
-
resolve2(null);
|
|
1439
|
-
}, 1e3);
|
|
1440
|
-
});
|
|
1441
|
-
}
|
|
1442
|
-
if (config.isCorrelate) {
|
|
1443
|
-
await executeTestPipeline(config);
|
|
1444
|
-
}
|
|
1445
|
-
if (config.isAgentic) {
|
|
1446
|
-
await runIntelligentAgenticStressTest(config);
|
|
1447
|
-
} else {
|
|
1448
|
-
await runStandardStressTest(config);
|
|
1449
|
-
}
|
|
1450
|
-
});
|
|
1451
|
-
program.command("heatmap").description("Display real-time geographic latency heatmap breakdown").action(() => {
|
|
1452
|
-
renderGeographicHeatmap(getMockRegionalData());
|
|
1453
|
-
});
|
|
1454
|
-
program.parse(process.argv);
|
|
1439
|
+
function printUsage() {
|
|
1440
|
+
console.log(`Blaze Core Performance Test CLI Engine
|
|
1441
|
+
Options:
|
|
1442
|
+
--threads <count> | --duration <seconds> | --baseline <json_file> | --output <html_file>`);
|
|
1443
|
+
}
|
|
1444
|
+
main().catch(console.error);
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "blaze-performance-tester",
|
|
3
|
-
"version": "3.1.
|
|
3
|
+
"version": "3.1.61",
|
|
4
4
|
"description": "A high-performance, multi-threaded load testing engine built with Rust and QuickJS.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"author": "Kushan Shalindra Amarsiri <lkkushan@yahoo.com>",
|
|
9
9
|
"license": "MIT",
|
|
10
10
|
"bin": {
|
|
11
|
-
"blaze": "./
|
|
11
|
+
"blaze": "./bin.js"
|
|
12
12
|
},
|
|
13
13
|
"files": [
|
|
14
14
|
"dist",
|
|
@@ -18,18 +18,16 @@
|
|
|
18
18
|
"blaze.win32-x64-msvc.node"
|
|
19
19
|
],
|
|
20
20
|
"scripts": {
|
|
21
|
-
"prebuild": "node -e \"
|
|
21
|
+
"prebuild": "node -e \"if (!fs.existsSync('dist')) fs.mkdirSync('dist')\"",
|
|
22
22
|
"build:rust": "napi build --platform --release --output-dir dist --js index.js --dts index.d.ts",
|
|
23
|
-
"build:cli": "esbuild cli.ts --bundle --platform=node --format=esm --packages=external --
|
|
23
|
+
"build:cli": "esbuild cli.ts --bundle --platform=node --format=esm --packages=external --outfile=dist/cli.js",
|
|
24
24
|
"build": "npm run prebuild && npm run build:rust && npm run build:cli"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"
|
|
28
|
-
"commander": "^12.1.0"
|
|
27
|
+
"esbuild": "^0.20.0"
|
|
29
28
|
},
|
|
30
29
|
"devDependencies": {
|
|
31
30
|
"@napi-rs/cli": "^2.16.0",
|
|
32
|
-
"esbuild": "^0.20.0",
|
|
33
31
|
"typescript": "^5.0.0"
|
|
34
32
|
}
|
|
35
|
-
}
|
|
33
|
+
}
|