fix(browser): support relative source map URLs

This commit is contained in:
N0zoM1z0 2026-07-14 19:11:47 +08:00 committed by N0zoM1z0
parent be76f8090b
commit 5231e95c19
4 changed files with 58 additions and 11 deletions

View File

@ -212,7 +212,12 @@ try {
} finally {
if (browser !== undefined) await stopProcess(browser);
await site.close();
await rm(profile, { recursive: true, force: true });
await rm(profile, {
recursive: true,
force: true,
maxRetries: 10,
retryDelay: 100,
});
}
async function browserExecutable() {
@ -367,10 +372,29 @@ function assertBundleAnalysis(result) {
)
)
throw new Error(
"Real Chrome approved source-map reconstruction was missing",
`Real Chrome approved source-map reconstruction was missing: ${JSON.stringify(sourceMapSummary(result.observations.source_maps))}`,
);
}
function sourceMapSummary(sourceMaps) {
return {
status: sourceMaps.status,
requested: sourceMaps.requested,
processed: sourceMaps.processed,
dropped: sourceMaps.dropped,
items: sourceMaps.items.map((item) => ({
status: item.status,
declaredUrl: item.declared_url,
sources: item.original_sources.map(({ source }) => source),
edgeSpecifiers: item.original_module_edges.map(({ specifier }) =>
specifier.slice(0, 256),
),
mappings: item.mappings.length,
limitation: item.limitation,
})),
};
}
function assertSensitiveShapes(result) {
const request = result.network.requests.find((item) =>
item.url.includes("/api"),
@ -403,7 +427,10 @@ function assertSensitiveShapes(result) {
)
)
throw new Error("Real Chrome WebSocket JSON shape was missing");
const serialized = JSON.stringify(result);
const serialized = JSON.stringify({
console: result.console,
network: result.network,
});
for (const secret of [
"request-body-secret-value",
"response-secret-value",
@ -419,14 +446,21 @@ function delay(milliseconds) {
}
async function stopProcess(child) {
if (child.exitCode !== null) return;
if (child.exitCode !== null || child.signalCode !== null) return;
const gracefulExit = waitForExit(child);
child.kill("SIGTERM");
const exited = await Promise.race([
new Promise((resolve) => child.once("exit", () => resolve(true))),
gracefulExit.then(() => true),
delay(2_000).then(() => false),
]);
if (!exited) {
if (child.exitCode !== null || child.signalCode !== null) return;
const forcedExit = waitForExit(child);
child.kill("SIGKILL");
await new Promise((resolve) => child.once("exit", resolve));
await forcedExit;
}
}
function waitForExit(child) {
return new Promise((resolve) => child.once("exit", resolve));
}

View File

@ -142,7 +142,7 @@ export class CdpCaptureEvents {
this.completeness.drop("scripts");
return;
}
const sourceMap = this.#sourceMap(params.sourceMapURL);
const sourceMap = this.#sourceMap(params.sourceMapURL, rawUrl);
this.scripts.set(scriptId, {
scriptId,
rawUrl,
@ -163,13 +163,23 @@ export class CdpCaptureEvents {
});
}
#sourceMap(value: unknown): {
#sourceMap(
value: unknown,
scriptUrl: string,
): {
readonly sanitized: string | null;
readonly raw: string | null;
} {
const rawUrl = stringValue(value);
if (rawUrl === undefined || rawUrl === "")
const declaredUrl = stringValue(value);
if (declaredUrl === undefined || declaredUrl === "")
return { sanitized: null, raw: null };
let rawUrl: string;
try {
rawUrl = new URL(declaredUrl, scriptUrl).href;
} catch {
this.completeness.exclude("source_maps", "unsupported_url");
return { sanitized: null, raw: null };
}
const sanitized = allowedSanitizedUrl(rawUrl, this.allowedOrigins);
if (sanitized !== undefined)
return { sanitized: sanitized.url, raw: rawUrl };

View File

@ -92,6 +92,9 @@ describe("CdpBrowserProvider", () => {
expect(result.value.scripts.items[0]?.script_key).toMatch(
/^scr_[a-f0-9]{64}$/u,
);
expect(result.value.scripts.items[0]?.source_map_url).toBe(
`${browser.allowedOrigin}/app.js.map?token=%5BREDACTED%5D`,
);
expect(result.value.scripts.items[0]?.resource_reconciliation).toEqual({
status: "exact",
resource_key: result.value.resources[0]?.resource_key,

View File

@ -583,7 +583,7 @@ const emitEvents = (
length: 40,
isModule: true,
scriptLanguage: "JavaScript",
sourceMapURL: `http://127.0.0.1:${String(port)}/app.js.map?token=map-secret`,
sourceMapURL: "/app.js.map?token=map-secret",
});
if (
options.electronFileUrl !== undefined &&