84 lines
3.0 KiB
TypeScript
84 lines
3.0 KiB
TypeScript
import { webPageInspectionSchema } from "../../domain/browserObservationSchemas.js";
|
|
import { browserScenarioCaptureSchema } from "../../domain/browserScenarioCapture.js";
|
|
import { parseEvidence } from "../../domain/evidence.js";
|
|
import type {
|
|
CapturedWebScript,
|
|
WebScriptExportResult,
|
|
} from "../../domain/webScriptExport.js";
|
|
import { pageScripts } from "./PageScriptCapture.js";
|
|
import { scenarioScripts } from "./ScenarioScriptCapture.js";
|
|
|
|
/** Capture-specific parsing and source selection, independent of publication. */
|
|
export interface ScriptCaptureAdapter {
|
|
readonly operation: string;
|
|
readonly parse: (input: unknown) => SelectedScriptCapture | undefined;
|
|
}
|
|
|
|
/** Verified source records with the original capture coverage and limitations. */
|
|
export interface SelectedScriptCapture {
|
|
readonly kind: WebScriptExportResult["capture_kind"];
|
|
readonly completeness: WebScriptExportResult["capture_completeness"];
|
|
readonly scripts: readonly CapturedWebScript[];
|
|
readonly limitations: readonly string[];
|
|
}
|
|
|
|
/** Built-in adapters; add capture formats here without changing the publisher. */
|
|
export const SCRIPT_CAPTURE_ADAPTERS: readonly ScriptCaptureAdapter[] = [
|
|
{
|
|
operation: "inspect_web_page",
|
|
parse: (input) => {
|
|
const parsed = webPageInspectionSchema.safeParse(input);
|
|
return parsed.success
|
|
? {
|
|
kind: "page-inspection",
|
|
completeness: parsed.data.completeness,
|
|
scripts: pageScripts(parsed.data),
|
|
limitations: parsed.data.limitations,
|
|
}
|
|
: undefined;
|
|
},
|
|
},
|
|
{
|
|
operation: "capture_browser_scenario",
|
|
parse: (input) => {
|
|
const parsed = browserScenarioCaptureSchema.safeParse(input);
|
|
return parsed.success
|
|
? {
|
|
kind: "browser-scenario",
|
|
completeness: parsed.data.completeness,
|
|
scripts: scenarioScripts(parsed.data),
|
|
limitations: parsed.data.limitations,
|
|
}
|
|
: undefined;
|
|
},
|
|
},
|
|
];
|
|
|
|
/** Reject unsupported/malformed captures and tampered Evidence before writing. */
|
|
export const selectScriptCapture = (
|
|
raw: unknown,
|
|
adapters: readonly ScriptCaptureAdapter[] = SCRIPT_CAPTURE_ADAPTERS,
|
|
): SelectedScriptCapture & { readonly sourceEvidenceId: string | null } => {
|
|
if (
|
|
typeof raw === "object" &&
|
|
raw !== null &&
|
|
("normalized_result" in raw || "evidence_id" in raw)
|
|
) {
|
|
const evidence = parseEvidence(raw);
|
|
const selected = adapters
|
|
.find(({ operation }) => operation === evidence.operation)
|
|
?.parse(evidence.normalized_result);
|
|
if (selected !== undefined)
|
|
return { ...selected, sourceEvidenceId: evidence.evidence_id };
|
|
} else {
|
|
for (const adapter of adapters) {
|
|
const selected = adapter.parse(raw);
|
|
if (selected !== undefined)
|
|
return { ...selected, sourceEvidenceId: null };
|
|
}
|
|
}
|
|
throw new TypeError(
|
|
"Expected a valid inspect_web_page or capture_browser_scenario capture, with retained script sources or response bytes. Evidence envelopes must have a matching operation and semantic identifier.",
|
|
);
|
|
};
|