feat: version topology graph metadata

This commit is contained in:
赵义仑
2026-06-16 19:00:39 +08:00
parent 5ea50e7288
commit 1324f1882c
5 changed files with 228 additions and 30 deletions

View File

@@ -4,6 +4,7 @@ import { pathToFileURL } from "node:url";
import { chromium, type Browser, type BrowserContext, type Page, type Response } from "playwright";
import { shortHash } from "./hash.js";
import { resolveLocator } from "./locator.js";
import { buildEmptyGraph, defaultViewport } from "./metadata.js";
import { isLowRiskClickable, classifyClickRisk } from "./risk.js";
import { snapshotPage } from "./snapshot.js";
import type { ActionEdge, EffectRecord, TopologyGraph } from "./types.js";
@@ -24,18 +25,14 @@ export async function scanUrl(options: EngineOptions): Promise<TopologyGraph> {
await page.goto(toNavigableUrl(options.url), { waitUntil: "domcontentloaded" });
await page.waitForLoadState("networkidle").catch(() => undefined);
const snapshot = await snapshotPage(page);
const graph: TopologyGraph = {
schemaVersion: "0.1",
metadata: {
entryUrl: page.url(),
generatedAt: new Date().toISOString(),
engineVersion: "0.1.0",
mode: "scan",
},
states: [snapshot.state],
elements: snapshot.elements,
edges: [],
};
const graph = buildEmptyGraph({
inputUrl: options.url,
entryUrl: page.url(),
mode: "scan",
storageState: options.storageState,
});
graph.states.push(snapshot.state);
graph.elements.push(...snapshot.elements);
await maybeWriteGraph(graph, options.out);
await context.close();
return graph;
@@ -54,18 +51,14 @@ export async function exploreUrl(options: EngineOptions): Promise<TopologyGraph>
await page.waitForLoadState("networkidle").catch(() => undefined);
const entrySnapshot = await snapshotPage(page);
const graph: TopologyGraph = {
schemaVersion: "0.1",
metadata: {
entryUrl: page.url(),
generatedAt: new Date().toISOString(),
engineVersion: "0.1.0",
mode: "explore",
},
states: [entrySnapshot.state],
elements: [...entrySnapshot.elements],
edges: [],
};
const graph = buildEmptyGraph({
inputUrl: options.url,
entryUrl: page.url(),
mode: "explore",
storageState: options.storageState,
});
graph.states.push(entrySnapshot.state);
graph.elements.push(...entrySnapshot.elements);
const candidates = entrySnapshot.elements.filter(isLowRiskClickable).slice(0, options.maxActions ?? 10);
await page.close();
@@ -132,7 +125,8 @@ export async function exploreUrl(options: EngineOptions): Promise<TopologyGraph>
async function newContext(browser: Browser, options: EngineOptions): Promise<BrowserContext> {
return browser.newContext({
storageState: options.storageState,
viewport: { width: 1440, height: 1000 },
viewport: defaultViewport(),
locale: "en-US",
});
}
@@ -186,4 +180,3 @@ function upsertById<T extends Record<K, string>, K extends keyof T>(items: T[],
next[index] = item;
return next;
}