mirror of
https://github.com/morluto/rea.git
synced 2026-11-03 05:16:16 +00:00
Keep each parsed script's observed frame after context destruction or ID reuse. Remove the later context lookup so record identity and deduplication use the same historical fact. Unknown and unauthorized frame mappings remain null. Validated event-to-record behavior with real local files and simulated CDP events, plus existing provider tests; no real Electron engine was exercised. Refs #3823. Co-authored-by: Liu Jie <maxazure@gmail.com>
101 lines
3.2 KiB
TypeScript
101 lines
3.2 KiB
TypeScript
import type {
|
|
ElectronPageInspection,
|
|
InspectElectronPageInput,
|
|
} from "../domain/javascript/electronObservation.js";
|
|
import { digestCanonicalValue } from "../domain/canonicalDigest.js";
|
|
import { createWebTextArtifact } from "../domain/webContentArtifact.js";
|
|
import type { CdpConnection } from "./CdpConnection.js";
|
|
import { CdpCaptureCompleteness } from "./CdpCaptureCompleteness.js";
|
|
import { requiredScriptSource } from "./CdpCaptureValues.js";
|
|
import type { ElectronScriptDraft } from "./CdpElectronScriptEvents.js";
|
|
import { authorizedElectronFile } from "./ElectronFileScope.js";
|
|
import { compareUnicodeCodePoints } from "../domain/unicodeCodePointOrder.js";
|
|
|
|
interface ElectronScriptCaptureInput {
|
|
readonly connection: CdpConnection;
|
|
readonly sessionId: string | undefined;
|
|
readonly signal?: AbortSignal;
|
|
readonly request: InspectElectronPageInput;
|
|
readonly scripts: readonly ElectronScriptDraft[];
|
|
readonly frameIds: ReadonlySet<string>;
|
|
readonly completeness: CdpCaptureCompleteness;
|
|
}
|
|
|
|
/** Normalize local script metadata and optionally approved source. */
|
|
export const captureElectronScripts = async (
|
|
input: ElectronScriptCaptureInput,
|
|
): Promise<ElectronPageInspection["scripts"]> => {
|
|
let total = 0;
|
|
const items: ElectronPageInspection["scripts"]["items"] = [];
|
|
const seen = new Set<string>();
|
|
for (const script of input.scripts) {
|
|
const path = await authorizedElectronFile(script.rawUrl);
|
|
if (path === undefined) {
|
|
input.completeness.exclude("scripts", "out_of_target_scope");
|
|
continue;
|
|
}
|
|
const identity = {
|
|
frame_id:
|
|
script.frameId !== null && input.frameIds.has(script.frameId)
|
|
? script.frameId
|
|
: null,
|
|
file_path: path,
|
|
cdp_hash: script.hash,
|
|
length: script.length,
|
|
is_module: script.isModule,
|
|
language: script.language,
|
|
};
|
|
const scriptKey = `electron_script_${digestCanonicalValue(identity, "CDP capture")}`;
|
|
if (seen.has(scriptKey)) continue;
|
|
seen.add(scriptKey);
|
|
total += 1;
|
|
const capturedSource = await captureScriptSource(input, script);
|
|
items.push({
|
|
script_key: scriptKey,
|
|
...identity,
|
|
source: capturedSource.source,
|
|
});
|
|
}
|
|
if (!input.request.include_script_sources)
|
|
input.completeness.exclude("script_sources", "not_approved", total);
|
|
return {
|
|
total,
|
|
items: items.sort((left, right) =>
|
|
compareUnicodeCodePoints(left.script_key, right.script_key),
|
|
),
|
|
};
|
|
};
|
|
|
|
type ElectronScriptSource =
|
|
ElectronPageInspection["scripts"]["items"][number]["source"];
|
|
|
|
const captureScriptSource = async (
|
|
input: ElectronScriptCaptureInput,
|
|
script: ElectronScriptDraft,
|
|
): Promise<{
|
|
readonly source: ElectronScriptSource;
|
|
}> => {
|
|
if (!input.request.include_script_sources)
|
|
return {
|
|
source: {
|
|
included: false,
|
|
reason: "source capture was not selected",
|
|
},
|
|
};
|
|
const text = requiredScriptSource(
|
|
await input.connection.send(
|
|
"Debugger.getScriptSource",
|
|
{ scriptId: script.scriptId },
|
|
input.sessionId,
|
|
input.signal,
|
|
),
|
|
"inspect_electron_page",
|
|
);
|
|
return {
|
|
source: {
|
|
included: true,
|
|
artifact: createWebTextArtifact(text, "text/javascript"),
|
|
},
|
|
};
|
|
};
|