|
|
/**
|
|
|
* 分析已有 Flock HAR / network JSON(无需再开浏览器)
|
|
|
*
|
|
|
* 用法:
|
|
|
* npm run analyze:flock-har -- .rpa/flock-network-poc/flock-xxxx.har
|
|
|
* npm run analyze:flock-har -- .rpa/flock-network-poc/flock-xxxx-network.json
|
|
|
*/
|
|
|
import fs from "node:fs";
|
|
|
import path from "node:path";
|
|
|
import {
|
|
|
analyzeFlockHarEntries,
|
|
|
analyzeFlockNetworkLog,
|
|
|
mergeAndDedupeCandidates,
|
|
|
summarizeFlockHosts,
|
|
|
verdictFromCandidates,
|
|
|
type FlockHarFile,
|
|
|
type FlockNetworkLogEntry,
|
|
|
} from "@/lib/flock/har-analyze";
|
|
|
|
|
|
function main(): void {
|
|
|
const target = process.argv[2];
|
|
|
if (!target) {
|
|
|
console.error(
|
|
|
"用法: npm run analyze:flock-har -- <path-to.har|*-network.json>",
|
|
|
);
|
|
|
process.exit(2);
|
|
|
}
|
|
|
const abs = path.isAbsolute(target) ? target : path.join(process.cwd(), target);
|
|
|
if (!fs.existsSync(abs)) {
|
|
|
console.error(`文件不存在: ${abs}`);
|
|
|
process.exit(1);
|
|
|
}
|
|
|
|
|
|
const raw = fs.readFileSync(abs, "utf8");
|
|
|
const parsed = JSON.parse(raw) as unknown;
|
|
|
let candidates;
|
|
|
let hosts: Array<{ host: string; count: number; methods: string[] }> = [];
|
|
|
|
|
|
if (Array.isArray(parsed)) {
|
|
|
candidates = analyzeFlockNetworkLog(parsed as FlockNetworkLogEntry[]);
|
|
|
} else if (
|
|
|
parsed &&
|
|
|
typeof parsed === "object" &&
|
|
|
"log" in (parsed as object)
|
|
|
) {
|
|
|
const har = parsed as FlockHarFile;
|
|
|
const entries = har.log?.entries ?? [];
|
|
|
candidates = analyzeFlockHarEntries(entries);
|
|
|
hosts = summarizeFlockHosts(entries);
|
|
|
} else if (
|
|
|
parsed &&
|
|
|
typeof parsed === "object" &&
|
|
|
Array.isArray((parsed as { candidates?: unknown }).candidates)
|
|
|
) {
|
|
|
console.log("输入已是 summary JSON,直接打印 candidates");
|
|
|
console.log(JSON.stringify(parsed, null, 2));
|
|
|
return;
|
|
|
} else {
|
|
|
console.error("无法识别为 HAR 或 network-log JSON");
|
|
|
process.exit(1);
|
|
|
}
|
|
|
|
|
|
const merged = mergeAndDedupeCandidates([candidates]);
|
|
|
const verdict = verdictFromCandidates(merged);
|
|
|
console.log(`verdict=${verdict} candidates=${merged.length}`);
|
|
|
if (hosts.length) {
|
|
|
console.log("hosts:");
|
|
|
for (const h of hosts.slice(0, 15)) {
|
|
|
console.log(` ${h.host} ×${h.count} ${h.methods.join(",")}`);
|
|
|
}
|
|
|
}
|
|
|
for (const c of merged.slice(0, 12)) {
|
|
|
console.log(`[${c.score}] ${c.method} ${c.status} ${c.urlWithoutQuery}`);
|
|
|
if (c.responsePreview) {
|
|
|
console.log(` resp: ${c.responsePreview.slice(0, 200)}`);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
main();
|