rea/scripts/lib/catalog-schemas.mjs

205 lines
5.3 KiB
JavaScript

import { z } from "zod";
const valuesAt = (node, path) => {
if (typeof node !== "object" || node === null) return [];
if ("anyOf" in node && Array.isArray(node.anyOf))
return node.anyOf.flatMap((alternative) => valuesAt(alternative, path));
if (path.length === 0)
return "const" in node &&
(typeof node.const === "number" || typeof node.const === "string")
? [node.const]
: [];
if (
!("properties" in node) ||
typeof node.properties !== "object" ||
node.properties === null
)
return [];
const [segment, ...remaining] = path;
return segment !== undefined && segment in node.properties
? valuesAt(node.properties[segment], remaining)
: [];
};
const versionAt = (schema, path) => {
const versions = [
...new Set(valuesAt(z.toJSONSchema(schema), path).map(String)),
];
if (versions.length !== 1)
throw new Error(
`Schema version path ${path.join(".")} has ${String(versions.length)} constant values`,
);
const version = versions[0];
if (version === undefined) throw new Error("Schema version disappeared");
return /^\d+$/u.test(version) ? Number(version) : version;
};
const durableSchemaDefinitions = (sources) => [
[
"analysis_snapshot",
sources.analysisSnapshot.analysisSnapshotSchema,
["snapshot_version"],
],
[
"artifact_graph",
sources.artifactGraph.artifactInventoryResultSchema,
["manifest", "schema_version"],
],
[
"artifact_extraction",
sources.artifactGraph.artifactExtractionResultSchema,
["extraction_manifest", "schema_version"],
],
["evidence", sources.evidence.evidenceSchema, ["schema_version"]],
[
"evidence_bundle",
sources.evidenceBundle.evidenceBundleSchema,
["bundle_version"],
],
[
"investigation_run",
sources.investigationWorkspace.investigationRunSchema,
["schema_version"],
],
[
"investigation_run_summary",
sources.investigationWorkspace.investigationRunSummarySchema,
["schema_version"],
],
[
"investigation_workspace",
sources.investigationWorkspace.investigationWorkspaceSchema,
["workspace_version"],
],
[
"javascript_application_graph",
sources.javascriptApplicationGraph.javascriptApplicationGraphSchema,
["schema_version"],
],
[
"javascript_application_version_comparison",
sources.javascriptVersionComparison
.applicationVersionComparisonResultSchema,
["schema_version"],
],
[
"javascript_feature_trace",
sources.javascriptFeatureTrace.applicationFeatureTraceResultSchema,
["schema_version"],
],
[
"process_capture",
sources.processCapture.processCaptureSchema,
["schema_version"],
],
[
"reconstruction_verification",
sources.reconstructionVerification.reconstructionSpecificationSchema,
["schema_version"],
],
[
"residual_unknown",
sources.residualUnknown.residualUnknownSchema,
["registry_version"],
],
];
const observationSchemaDefinitions = (sources) => [
[
"managed_artifact_inspection",
sources.managedArtifact.managedArtifactInspectionSchema,
["schema_version"],
],
[
"managed_member_inspection",
sources.managedArtifact.managedMemberInspectionSchema,
["schema_version"],
],
[
"managed_native_boundary_inspection",
sources.managedArtifact.managedNativeBoundaryInspectionSchema,
["schema_version"],
],
[
"managed_member_comparison",
sources.managedComparison.managedMemberComparisonResultSchema,
["schema_version"],
],
[
"managed_native_verification",
sources.managedNativeVerification.managedNativeVerificationResultSchema,
["schema_version"],
],
[
"browser_target_list",
sources.browserObservation.browserTargetListSchema,
["schema_version"],
],
[
"electron_page_inspection",
sources.electronObservation.electronPageInspectionSchema,
["schema_version"],
],
[
"electron_target_list",
sources.electronObservation.electronTargetListSchema,
["schema_version"],
],
[
"javascript_application_analysis",
sources.javascriptApplicationAnalysis
.javascriptApplicationAnalysisResultSchema,
["schema_version"],
],
[
"web_bundle_analysis",
sources.webBundleAnalysis.webBundleAnalysisSchema,
["schema_version"],
],
[
"web_capture_diff",
sources.webCaptureDiff.webCaptureDiffSchema,
["schema_version"],
],
[
"web_mcp_discovery",
sources.webMcpDiscovery.webMcpDiscoverySchema,
["schema_version"],
],
[
"web_observation_session",
sources.browserSession.webObservationSessionSchema,
["schema_version"],
],
[
"web_page_inspection",
sources.browserObservation.webPageInspectionSchema,
["schema_version"],
],
[
"web_screenshot",
sources.webScreenshot.webScreenshotSchema,
["schema_version"],
],
[
"web_screenshot_diff",
sources.webScreenshot.webScreenshotDiffSchema,
["schema_version"],
],
];
/** Derive the catalog of durable and observation schema versions. */
export const schemaCatalog = (sources) =>
[
...durableSchemaDefinitions(sources),
...observationSchemaDefinitions(sources),
]
.map(([id, schema, path]) => {
try {
return { id, version: versionAt(schema, path) };
} catch (cause) {
throw new Error(`Could not derive ${id} schema version`, { cause });
}
})
.sort((left, right) => left.id.localeCompare(right.id));