mirror of
https://github.com/morluto/rea.git
synced 2026-10-29 19:05:45 +00:00
* fix(browser): preserve source-map declaration uncertainty * style(tests): fix CI formatting * fix(browser): retain known source map differences * fix(web): bind map comparisons to script metadata * fix(browser): match source maps with partial script metadata Keep each script's observed hash and declaration constraints instead of dropping a metadata field for the whole URL group. * test(flutter): assert ABI selector refusals as structured issues MCP input validation reports the ABI path and the schema message separately. The old concatenated "abi: ..." sentence is no longer the delivered error. * fix(web): prove large source-map changes without factorial search Groups larger than eight scripts were reported as unexplained, so nine x.map declarations plus one omission compared as unknown against ten y.map declarations. Declaration counts reject impossible placements, and augmenting paths assign the rest without retrying identical scripts. * test(mcp): assert bundle path issues by field compare_bundles reports each relative path as an invalid_format issue instead of one joined diagnostic sentence. * fix(web): match repeated source-map scripts by count Identical declarations share one group, and a shared omission pool is counted once. A 2000-script self-compare no longer builds a dense assignment graph. --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com>
236 lines
6.8 KiB
TypeScript
236 lines
6.8 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
|
|
import { CdpCaptureEvents } from "../../../src/browser/CdpCaptureEvents.js";
|
|
import { inspectWebPageInputSchema } from "../../../src/domain/browserObservation.js";
|
|
import { CDP_CAPTURE_SCRIPT_METADATA_LIMITS } from "../../../src/browser/CdpCaptureEventTypes.js";
|
|
|
|
describe("CDP script metadata admission", () => {
|
|
it("retains an invalid source-map declaration as unknown", () => {
|
|
const events = captureEvents();
|
|
events.beginAuthorizedFrame("frame-1");
|
|
for (const [scriptId, sourceMapURL] of [
|
|
["bad", null],
|
|
["absent", undefined],
|
|
["empty", ""],
|
|
] as const) {
|
|
events.ingest({
|
|
method: "Debugger.scriptParsed",
|
|
params: {
|
|
scriptId,
|
|
url: "https://app.example/app.js",
|
|
sourceMapURL,
|
|
},
|
|
});
|
|
expect(events.scripts.get(scriptId)?.sourceMapUrl).toBeNull();
|
|
}
|
|
expect(events.completeness.snapshot().excluded).toContainEqual({
|
|
section: "source_maps",
|
|
reason: "invalid_protocol_value",
|
|
count: 1,
|
|
});
|
|
});
|
|
|
|
it("releases a replaced script ID's prior bytes and resets admission on a new document", () => {
|
|
const events = captureEvents();
|
|
const origin = "https://app.example";
|
|
events.beginAuthorizedFrame("frame-1");
|
|
const emit = (scriptId: string, bytes: number): void => {
|
|
events.ingest({
|
|
method: "Debugger.scriptParsed",
|
|
params: {
|
|
scriptId,
|
|
url: `${origin}/app.js`,
|
|
sourceMapURL: `/maps/${"x".repeat(bytes)}.map`,
|
|
},
|
|
});
|
|
};
|
|
|
|
emit("same-id", 3 * 1024 * 1024);
|
|
emit("same-id", 2 * 1024 * 1024);
|
|
emit("next-id", 1024 * 1024);
|
|
|
|
expect(events.scripts.get("same-id")?.sourceMapUrl).toContain(
|
|
"x".repeat(2 * 1024 * 1024),
|
|
);
|
|
expect(events.scripts.get("next-id")?.sourceMapUrl).toContain(
|
|
"x".repeat(1024 * 1024),
|
|
);
|
|
expect(events.retainedScriptMetadataBytes).toBeLessThanOrEqual(
|
|
CDP_CAPTURE_SCRIPT_METADATA_LIMITS.retainedBytes,
|
|
);
|
|
const normalizedAway = `./`.repeat(1_200_000) + "map.js.map";
|
|
events.ingest({
|
|
method: "Debugger.scriptParsed",
|
|
params: {
|
|
scriptId: "normalized-url",
|
|
url: `${origin}/app.js`,
|
|
sourceMapURL: normalizedAway,
|
|
},
|
|
});
|
|
expect(events.scripts.get("normalized-url")?.sourceMapUrl).toBe(
|
|
`${origin}/map.js.map`,
|
|
);
|
|
|
|
events.beginAuthorizedFrame("frame-2");
|
|
emit("new-document", 5 * 1024 * 1024);
|
|
emit("new-document", 1024 * 1024);
|
|
events.recordScriptMetadataBudgetExclusions();
|
|
expect(
|
|
events.completeness
|
|
.snapshot()
|
|
.excluded.find(
|
|
({ section, reason }) =>
|
|
section === "source_maps" && reason === "resource_budget_exhausted",
|
|
),
|
|
).toBeUndefined();
|
|
|
|
events.beginAuthorizedFrame("frame-3");
|
|
emit("new-document", 3 * 1024 * 1024);
|
|
expect(events.scripts.get("new-document")?.sourceMapUrl).toContain(
|
|
"x".repeat(3 * 1024 * 1024),
|
|
);
|
|
});
|
|
|
|
it("does not retain IDs for scripts rejected by byte or record limits", () => {
|
|
const events = captureEvents();
|
|
const origin = "https://app.example";
|
|
events.beginAuthorizedFrame("frame-1");
|
|
const emit = (scriptId: string): void => {
|
|
events.ingest({
|
|
method: "Debugger.scriptParsed",
|
|
params: { scriptId, url: `${origin}/app.js` },
|
|
});
|
|
};
|
|
|
|
emit("x".repeat(CDP_CAPTURE_SCRIPT_METADATA_LIMITS.retainedBytes + 1));
|
|
for (
|
|
let index = 0;
|
|
index < CDP_CAPTURE_SCRIPT_METADATA_LIMITS.scripts;
|
|
index += 1
|
|
)
|
|
emit(`script-${String(index)}`);
|
|
for (let index = 0; index < 10; index += 1)
|
|
emit(`rejected-${String(index)}`);
|
|
|
|
expect(events.scripts.size).toBe(
|
|
CDP_CAPTURE_SCRIPT_METADATA_LIMITS.scripts,
|
|
);
|
|
expect(events.scriptMetadataBudgetOmissionsById.size).toBe(0);
|
|
expect(events.rejectedScriptMetadataBudgetCount).toBe(11);
|
|
events.recordScriptMetadataBudgetExclusions();
|
|
expect(
|
|
events.completeness
|
|
.snapshot()
|
|
.excluded.find(
|
|
({ section, reason }) =>
|
|
section === "scripts" && reason === "resource_budget_exhausted",
|
|
),
|
|
).toEqual({
|
|
section: "scripts",
|
|
reason: "resource_budget_exhausted",
|
|
count: 11,
|
|
});
|
|
});
|
|
});
|
|
|
|
const captureEvents = (): CdpCaptureEvents =>
|
|
new CdpCaptureEvents(
|
|
inspectWebPageInputSchema.parse({
|
|
cdp_endpoint: "http://127.0.0.1:9222",
|
|
allowed_origins: ["https://app.example"],
|
|
target_id: "page",
|
|
observation_ms: 0,
|
|
}),
|
|
new Set(["https://app.example"]),
|
|
);
|
|
|
|
it.each([
|
|
{
|
|
name: "absent auxiliary data",
|
|
auxiliary: undefined,
|
|
frame: "frame-1",
|
|
invalid: false,
|
|
},
|
|
{
|
|
name: "conflicting frame",
|
|
auxiliary: { frameId: "other-frame" },
|
|
frame: null,
|
|
invalid: true,
|
|
},
|
|
{
|
|
name: "empty frame",
|
|
auxiliary: { frameId: "" },
|
|
frame: null,
|
|
invalid: true,
|
|
},
|
|
{
|
|
name: "null frame",
|
|
auxiliary: { frameId: null },
|
|
frame: null,
|
|
invalid: true,
|
|
},
|
|
{
|
|
name: "numeric frame",
|
|
auxiliary: { frameId: 7 },
|
|
frame: null,
|
|
invalid: true,
|
|
},
|
|
{
|
|
name: "malformed auxiliary data",
|
|
auxiliary: null,
|
|
frame: null,
|
|
invalid: true,
|
|
},
|
|
])(
|
|
"keeps script ownership uncertain for $name",
|
|
({ auxiliary, frame, invalid }) => {
|
|
const events = captureEvents();
|
|
events.beginAuthorizedFrame("frame-1");
|
|
events.ingest({
|
|
method: "Runtime.executionContextCreated",
|
|
params: { context: { id: 7, auxData: { frameId: "frame-1" } } },
|
|
});
|
|
events.ingest({
|
|
method: "Debugger.scriptParsed",
|
|
params: {
|
|
scriptId: "script",
|
|
url: "https://app.example/app.js",
|
|
executionContextId: 7,
|
|
...(auxiliary === undefined
|
|
? {}
|
|
: { executionContextAuxData: auxiliary }),
|
|
},
|
|
});
|
|
const script = events.scripts.get("script");
|
|
if (script === undefined)
|
|
throw new Error("Expected retained script metadata");
|
|
expect(script.frameId).toBe(frame);
|
|
expect(events.frameForScript(script, new Set(["frame-1"]))).toBe(frame);
|
|
expect(
|
|
events.completeness
|
|
.snapshot()
|
|
.excluded.filter(({ section }) => section === "scripts"),
|
|
).toEqual(
|
|
invalid
|
|
? [{ section: "scripts", reason: "invalid_protocol_value", count: 1 }]
|
|
: [],
|
|
);
|
|
},
|
|
);
|
|
|
|
it("rejects an empty script ID before retaining its metadata", () => {
|
|
const events = captureEvents();
|
|
events.beginAuthorizedFrame("frame-1");
|
|
events.ingest({
|
|
method: "Debugger.scriptParsed",
|
|
params: { scriptId: "", url: "https://app.example/app.js" },
|
|
});
|
|
expect(events.scripts.size).toBe(0);
|
|
expect(events.retainedScriptMetadataBytes).toBe(0);
|
|
expect(events.completeness.snapshot().excluded).toContainEqual({
|
|
section: "scripts",
|
|
reason: "invalid_protocol_value",
|
|
count: 1,
|
|
});
|
|
});
|