Files
rea/src/browser/CdpElectronScriptEvents.ts
T
morlutoandLiu Jie 6b991d3aa7 fix(electron): snapshot script frame identity at ingestion
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>
2026-10-16 05:43:24 +08:00

84 lines
2.8 KiB
TypeScript

import type { CdpEvent } from "./CdpConnection.js";
import { CdpCaptureCompleteness } from "./CdpCaptureCompleteness.js";
import {
numberValue,
recordValue,
scriptMetadataValues,
cdpStringValue,
} from "./CdpCaptureValues.js";
export interface ElectronScriptDraft {
readonly scriptId: string;
readonly rawUrl: string;
readonly hash: string | null;
readonly length: number | null;
readonly isModule: boolean | null;
readonly language: string | null;
readonly frameId: string | null;
}
/** Retain script/frame metadata from passive Electron events. */
export const ingestElectronScriptEvent = (input: {
readonly event: CdpEvent;
readonly scripts: ElectronScriptDraft[];
readonly executionContextFrames: Map<string, string>;
readonly completeness: CdpCaptureCompleteness;
}): void => {
if (input.event.method === "Runtime.executionContextsCleared") {
input.executionContextFrames.clear();
return;
}
if (input.event.method === "Runtime.executionContextDestroyed") {
const parameters = recordValue(input.event.params);
const key = executionContextKey(parameters?.executionContextId);
if (key !== null) input.executionContextFrames.delete(key);
return;
}
if (input.event.method === "Runtime.executionContextCreated") {
retainExecutionContext(input.event, input.executionContextFrames);
return;
}
if (input.event.method !== "Debugger.scriptParsed") return;
const value = recordValue(input.event.params);
const scriptId = cdpStringValue(value?.scriptId);
const rawUrl = cdpStringValue(value?.url);
if (scriptId === undefined) {
input.completeness.exclude("scripts", "invalid_protocol_value");
return;
}
if (rawUrl === undefined || rawUrl === "") {
input.completeness.exclude("scripts", "unattributed_origin");
return;
}
const contextKey = executionContextKey(value?.executionContextId);
input.scripts.push({
scriptId,
rawUrl,
...scriptMetadataValues(value),
language: cdpStringValue(value?.scriptLanguage) ?? null,
frameId:
contextKey === null
? null
: (input.executionContextFrames.get(contextKey) ?? null),
});
};
const retainExecutionContext = (
event: CdpEvent,
frames: Map<string, string>,
): void => {
const parameters = recordValue(event.params);
const runtimeContext = recordValue(parameters?.context);
const contextKey = executionContextKey(runtimeContext?.id);
const frameId = cdpStringValue(recordValue(runtimeContext?.auxData)?.frameId);
if (contextKey === null || frameId === undefined) return;
frames.set(contextKey, frameId);
};
const executionContextKey = (value: unknown): string | null => {
const identifier = numberValue(value);
return identifier !== undefined && Number.isSafeInteger(identifier)
? String(identifier)
: null;
};