ai-chatbot/analysis/qiaodou-extract/analyze_bundle.js
Your Name be5b9aef12
Some checks failed
Lint / build (20) (push) Has been cancelled
Playwright Tests / test (push) Has been cancelled
chore: sync latest workspace changes
2026-04-05 02:08:26 +08:00

182 lines
5.2 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const fs = require("node:fs");
const path = require("node:path");
const vm = require("node:vm");
const INPUT = "/Users/lanmu/Desktop/ai-chatbot-main/analysis/qiaodou-extract/extracted/assets/index-m-NWkaV-.js";
const OUTPUT_JSON = "/Users/lanmu/Desktop/ai-chatbot-main/analysis/qiaodou-extract/bundle-intel.json";
const source = fs.readFileSync(INPUT, "utf8");
function unique(values) {
return Array.from(new Set(values));
}
function safeEvalObjectLiteral(literal) {
return vm.runInNewContext(`(${literal})`, Object.create(null), {
timeout: 1000,
});
}
function extractBetween(startMarker, endMarker) {
const start = source.indexOf(startMarker);
if (start < 0) return null;
const from = start + startMarker.length;
const end = source.indexOf(endMarker, from);
if (end < 0) return null;
return source.slice(from, end);
}
function normalizeUrl(url) {
return String(url || "").replace(/[.,;]+$/, "").trim();
}
function isLikelyAppRelevantUrl(url) {
if (!url || url === "http://" || url === "https://") return false;
return !(
url.includes("w3.org/") ||
url.includes("apache.org/") ||
url.includes("reactjs.org/") ||
url.includes("github.com/") ||
url.includes("raw.github.com/") ||
url.includes("developer.mozilla.org/") ||
url.includes("feross.org") ||
url.includes("stuk.github.io/") ||
url.includes("stuartk.com/jszip")
);
}
const storageKeys = unique(
Array.from(source.matchAll(/qiaodoumayi_[A-Za-z0-9_]+/g)).map((match) => match[0])
).sort();
const tauriCommands = unique(
Array.from(source.matchAll(/yn\("([a-zA-Z0-9_:-]+)"/g)).map((match) => match[1])
).sort();
const requireHints = unique(
Array.from(source.matchAll(/\.\.\/[A-Za-z0-9_./-]+/g)).map((match) => match[0])
).sort();
const allUrls = unique(
Array.from(source.matchAll(/https?:\/\/[^\s"'`\\)<>,]+/g)).map((match) => normalizeUrl(match[0]))
).sort();
const appRelevantUrls = allUrls.filter(isLikelyAppRelevantUrl);
const domains = unique(
appRelevantUrls
.map((url) => {
try {
return new URL(url).host;
} catch {
return null;
}
})
.filter(Boolean)
).sort();
let quickConnectConfig = {};
const quickConnectLiteral = extractBetween("DV=", ";function npe");
if (quickConnectLiteral) {
quickConnectConfig = safeEvalObjectLiteral(quickConnectLiteral);
}
let nodeLabelMap = {};
const nodeLabelMatch = source.match(/function Rm\(e\)\{return(\{[\s\S]*?\})\[e\]\|\|"节点"\}/);
if (nodeLabelMatch) {
nodeLabelMap = safeEvalObjectLiteral(nodeLabelMatch[1]);
}
const nodeSizeMap = {};
const nodeSizeMatch = source.match(/function jO\(e\)\{switch\(e\)\{([\s\S]*?)default:return\{w:(\d+),h:(\d+)\}\}\}/);
if (nodeSizeMatch) {
const body = nodeSizeMatch[1];
const defaultSize = { w: Number(nodeSizeMatch[2]), h: Number(nodeSizeMatch[3]) };
nodeSizeMap.default = defaultSize;
const groupedCases = body.matchAll(/((?:case"[^"]+":)+)return\{w:(\d+),h:(\d+)\}/g);
for (const groupedCase of groupedCases) {
const labels = Array.from(groupedCase[1].matchAll(/case"([^"]+)":/g)).map((match) => match[1]);
const size = { w: Number(groupedCase[2]), h: Number(groupedCase[3]) };
for (const label of labels) {
nodeSizeMap[label] = size;
}
}
}
const quickConnectTypes = Object.keys(quickConnectConfig);
const nodeTypes = unique([
...Object.keys(nodeLabelMap),
...Object.keys(nodeSizeMap).filter((key) => key !== "default"),
...quickConnectTypes,
...quickConnectTypes.flatMap((type) =>
(quickConnectConfig[type]?.output || []).map((item) => item.type)
),
]).sort();
const nodeCatalog = nodeTypes.map((type) => ({
type,
label: nodeLabelMap[type] || null,
size: nodeSizeMap[type] || nodeSizeMap.default || null,
quickConnectOutputs: (quickConnectConfig[type]?.output || []).map((item) => ({
type: item.type,
label: item.label,
})),
}));
const indexedDb = {
databaseName: source.includes('"qiaodoumayi_projects"') ? "qiaodoumayi_projects" : null,
version: source.includes('qiaodoumayi_projects",Ioe=2') ? 2 : null,
stores: unique(
Array.from(source.matchAll(/"(project_meta|project_payload|project_assets)"/g)).map(
(match) => match[1]
)
),
};
const snippets = {};
for (const term of [
"qiaodoumayi_seedance_moderation_url",
"download_file_bypass_cors",
"start_local_server",
"qiaodoumayi_projects",
"qiaodoumayi_script_projects",
"qiaodoumayi_saved_skills",
"qiaodoumayi_characters",
"https://ai.comfly.chat/sora/v1/characters",
"https://www.runninghub.cn",
]) {
const index = source.indexOf(term);
snippets[term] =
index >= 0
? {
index,
preview: source.slice(Math.max(0, index - 180), Math.min(source.length, index + 260)),
}
: null;
}
const result = {
input: INPUT,
stats: {
bytes: Buffer.byteLength(source, "utf8"),
lines: source.split("\n").length,
hasSourceMap: /sourceMappingURL/.test(source),
},
storageKeys,
tauriCommands,
requireHints,
urls: {
appRelevant: appRelevantUrls,
all: allUrls,
domains,
},
indexedDb,
quickConnectConfig,
nodeLabelMap,
nodeSizeMap,
nodeCatalog,
snippets,
};
fs.writeFileSync(OUTPUT_JSON, `${JSON.stringify(result, null, 2)}\n`);
console.log(`Wrote ${OUTPUT_JSON}`);