diff --git a/src/browser/CdpCaptureEventHandlers.ts b/src/browser/CdpCaptureEventHandlers.ts index 9519cd785b..bf0d36d4dc 100644 --- a/src/browser/CdpCaptureEventHandlers.ts +++ b/src/browser/CdpCaptureEventHandlers.ts @@ -89,7 +89,6 @@ export const handleScriptParsed = ( url: sanitized.url, origin: sanitized.origin, ...scriptMetadataValues(params), - language: cdpStringValue(params.scriptLanguage) ?? null, executionContextKey: executionContext, frameId: executionContext === null diff --git a/src/browser/CdpCaptureValues.ts b/src/browser/CdpCaptureValues.ts index c5010c6b6f..713df21e42 100644 --- a/src/browser/CdpCaptureValues.ts +++ b/src/browser/CdpCaptureValues.ts @@ -49,6 +49,7 @@ export const scriptMetadataValues = ( readonly hash: string | null; readonly length: number | null; readonly isModule: boolean | null; + readonly language: string | null; } => { const length = numberValue(value?.length); return { @@ -58,6 +59,7 @@ export const scriptMetadataValues = ( ? length : null, isModule: typeof value?.isModule === "boolean" ? value.isModule : null, + language: cdpStringValue(value?.scriptLanguage) ?? null, }; }; diff --git a/src/browser/CdpElectronScriptEvents.ts b/src/browser/CdpElectronScriptEvents.ts index a7d2e907df..ea5181c22d 100644 --- a/src/browser/CdpElectronScriptEvents.ts +++ b/src/browser/CdpElectronScriptEvents.ts @@ -55,7 +55,6 @@ export const ingestElectronScriptEvent = (input: { scriptId, rawUrl, ...scriptMetadataValues(value), - language: cdpStringValue(value?.scriptLanguage) ?? null, frameId: contextKey === null ? null diff --git a/src/domain/browserObservationSchemas.ts b/src/domain/browserObservationSchemas.ts index 6c643ec8b0..138acafb72 100644 --- a/src/domain/browserObservationSchemas.ts +++ b/src/domain/browserObservationSchemas.ts @@ -1,9 +1,13 @@ import { z } from "zod"; import { browserCompletenessSchema } from "./browserCompleteness.js"; -import { webTextArtifactSchema } from "./webContentArtifact.js"; +import { + cdpDomNodeSchema, + cdpScriptSourceSchema, + cdpScriptMetadataSchema, +} from "./cdpObservationSchemas.js"; import { jsonShapeSchema } from "./jsonShape.js"; -import { prefixedDigestSchema } from "./../domain/digests.js"; +import { prefixedDigestSchema } from "./digests.js"; /** Shared CDP/browser version identity carried on observation Evidence. */ export const browserVersionSchema = z.object({ @@ -47,14 +51,6 @@ const browserFrameSchema = z.object({ url: z.string(), origin: z.string().nullable(), }); -const browserDomNodeSchema = z.object({ - index: z.number().int().min(0), - parent_index: z.number().int().min(-1), - node_type: z.number().int().min(0), - node_name: z.string(), - node_value_length: z.number().int().min(0), - attribute_names: z.array(z.string()), -}); const browserAxNodeSchema = z.object({ node_id: z.string(), parent_id: z.string().nullable(), @@ -71,13 +67,6 @@ const browserAxNodeSchema = z.object({ ) .default([]), }); -const browserScriptSourceSchema = z.discriminatedUnion("included", [ - z.object({ included: z.literal(false), reason: z.string() }), - z.object({ - included: z.literal(true), - artifact: webTextArtifactSchema, - }), -]); const browserResourceReconciliationSchema = z.discriminatedUnion("status", [ z.object({ status: z.literal("exact"), resource_key: z.string() }), z.object({ @@ -94,26 +83,10 @@ const browserScriptSchema = z.object({ frame_id: z.string().nullable().default(null), url: z.string(), origin: z.string().nullable(), - cdp_hash: z - .string() - .nullable() - .describe("Producer-reported script hash; null when unavailable."), - length: z - .number() - .int() - .min(0) - .nullable() - .describe("Producer-reported script length; null when unavailable."), - is_module: z - .boolean() - .nullable() - .describe( - "Producer-reported module classification; null when unavailable.", - ), - language: z.string().nullable(), + ...cdpScriptMetadataSchema.shape, source_map_url: z.string().nullable(), resource_reconciliation: browserResourceReconciliationSchema, - source: browserScriptSourceSchema, + source: cdpScriptSourceSchema, }); const browserResourceSchema = z.object({ resource_key: prefixedDigestSchema("res"), @@ -297,7 +270,7 @@ export const webPageInspectionSchema = z.object({ frames: z.array(browserFrameSchema), dom: z.object({ total_nodes: z.number().int().min(0), - nodes: z.array(browserDomNodeSchema), + nodes: z.array(cdpDomNodeSchema), }), accessibility: z.object({ total_nodes: z.number().int().min(0), diff --git a/src/domain/cdpObservationSchemas.ts b/src/domain/cdpObservationSchemas.ts new file mode 100644 index 0000000000..839af85b2b --- /dev/null +++ b/src/domain/cdpObservationSchemas.ts @@ -0,0 +1,42 @@ +import { z } from "zod"; +import { webTextArtifactSchema } from "./webContentArtifact.js"; + +/** Structural DOM facts shared by passive web and Electron observations. */ +export const cdpDomNodeSchema = z.object({ + index: z.number().int().min(0), + parent_index: z.number().int().min(-1), + node_type: z.number().int().min(0), + node_name: z.string(), + node_value_length: z.number().int().min(0), + attribute_names: z.array(z.string()), +}); + +/** Captured text or an explicit reason why source is unavailable. */ +export const cdpScriptSourceSchema = z.discriminatedUnion("included", [ + z.object({ included: z.literal(false), reason: z.string() }), + z.object({ + included: z.literal(true), + artifact: webTextArtifactSchema, + }), +]); + +/** Producer script declarations; unavailable facts remain null. */ +export const cdpScriptMetadataSchema = z.object({ + cdp_hash: z + .string() + .nullable() + .describe("Producer-reported script hash; null when unavailable."), + length: z + .number() + .int() + .min(0) + .nullable() + .describe("Producer-reported script length; null when unavailable."), + is_module: z + .boolean() + .nullable() + .describe( + "Producer-reported module classification; null when unavailable.", + ), + language: z.string().nullable(), +}); diff --git a/src/domain/javascript/electronObservation.ts b/src/domain/javascript/electronObservation.ts index a5d7e21d27..ada76e98e8 100644 --- a/src/domain/javascript/electronObservation.ts +++ b/src/domain/javascript/electronObservation.ts @@ -4,7 +4,11 @@ import { webRuntimeCommandTimeoutSchema } from "../browserDeadline.js"; import { browserCompletenessSchema } from "../browserCompleteness.js"; import { browserEndpointSchema } from "../browserObservation.js"; import { browserVersionSchema } from "../browserObservationSchemas.js"; -import { webTextArtifactSchema } from "../webContentArtifact.js"; +import { + cdpDomNodeSchema, + cdpScriptSourceSchema, + cdpScriptMetadataSchema, +} from "../cdpObservationSchemas.js"; import { prefixedDigestSchema } from "../digests.js"; const approvedElectronInput = { @@ -65,11 +69,6 @@ export const electronTargetListSchema = z.object({ }); export type ElectronTargetList = z.infer; -const electronSourceSchema = z.discriminatedUnion("included", [ - z.object({ included: z.literal(false), reason: z.string() }), - z.object({ included: z.literal(true), artifact: webTextArtifactSchema }), -]); - /** Provider-neutral passive Electron file-page structure and script inventory. */ export const electronPageInspectionSchema = z.object({ browser: browserVersionSchema, @@ -89,16 +88,7 @@ export const electronPageInspectionSchema = z.object({ ), dom: z.object({ total_nodes: z.number().int().min(0), - nodes: z.array( - z.object({ - index: z.number().int().min(0), - parent_index: z.number().int().min(-1), - node_type: z.number().int().min(0), - node_name: z.string(), - node_value_length: z.number().int().min(0), - attribute_names: z.array(z.string()), - }), - ), + nodes: z.array(cdpDomNodeSchema), }), scripts: z.object({ total: z.number().int().min(0), @@ -107,24 +97,8 @@ export const electronPageInspectionSchema = z.object({ script_key: prefixedDigestSchema("electron_script"), frame_id: z.string().nullable().default(null), file_path: z.string(), - cdp_hash: z - .string() - .nullable() - .describe("Producer-reported script hash; null when unavailable."), - length: z - .number() - .int() - .min(0) - .nullable() - .describe("Producer-reported script length; null when unavailable."), - is_module: z - .boolean() - .nullable() - .describe( - "Producer-reported module classification; null when unavailable.", - ), - language: z.string().nullable(), - source: electronSourceSchema, + ...cdpScriptMetadataSchema.shape, + source: cdpScriptSourceSchema, }), ), }),