mirror of
https://github.com/morluto/rea.git
synced 2026-11-03 05:16:16 +00:00
refactor(javascript): group domain semantics and contracts (#907)
This commit is contained in:
1 parent
d5f28fb29c
commit
f6a58f1062
253 files changed
+432
-410
No files matched your search
@@ -0,0 +1,283 @@
|
||||
import { z } from "zod";
|
||||
|
||||
import { compareCodePoints } from "../canonicalOrdering.js";
|
||||
import { evidenceSchema } from "../evidence.js";
|
||||
import { javascriptRuntimeUnresolvedLocationSchema } from "./javascriptRuntimeObservation.js";
|
||||
import { javascriptApplicationGraphSchema } from "./javascriptApplicationGraph.js";
|
||||
import { digestSchema } from "../digests.js";
|
||||
import { prefixedDigestSchema } from "../digests.js";
|
||||
|
||||
const evidenceIdSchema = prefixedDigestSchema("ev");
|
||||
const nodeIdSchema = prefixedDigestSchema("jag_node");
|
||||
const boundedTextSchema = z.string().min(1);
|
||||
const safePrefixSchema = z
|
||||
.string()
|
||||
.refine(
|
||||
(value) =>
|
||||
value === "" ||
|
||||
(!value.startsWith("/") &&
|
||||
!value.includes("\\") &&
|
||||
value.split("/").every((part) => !["", ".", ".."].includes(part))),
|
||||
"Artifact prefix must be empty or a safe relative POSIX path",
|
||||
);
|
||||
|
||||
const runtimeFileMappingSchema = z.strictObject({
|
||||
kind: z.literal("file-root"),
|
||||
root: z.string().min(1),
|
||||
artifact_prefix: safePrefixSchema.default(""),
|
||||
});
|
||||
|
||||
const runtimeUrlMappingSchema = z.strictObject({
|
||||
kind: z.literal("url-prefix"),
|
||||
prefix: z
|
||||
.string()
|
||||
.min(1)
|
||||
.refine(
|
||||
(value) => normalizeRuntimeUrlPrefix(value) !== null,
|
||||
"Runtime URL prefix must be HTTP(S) without credentials, query, or fragment",
|
||||
)
|
||||
.overwrite((value) => normalizeRuntimeUrlPrefix(value) ?? value),
|
||||
artifact_prefix: safePrefixSchema.default(""),
|
||||
});
|
||||
|
||||
const normalizeRuntimeUrlPrefix = (value: string): string | null => {
|
||||
let url: URL;
|
||||
try {
|
||||
url = new URL(value);
|
||||
} catch (cause: unknown) {
|
||||
// Invalid input is represented by the null return.
|
||||
void cause;
|
||||
return null;
|
||||
}
|
||||
if (
|
||||
!["http:", "https:"].includes(url.protocol) ||
|
||||
url.username !== "" ||
|
||||
url.password !== "" ||
|
||||
url.search !== "" ||
|
||||
url.hash !== ""
|
||||
)
|
||||
return null;
|
||||
if (!url.pathname.endsWith("/")) url.pathname += "/";
|
||||
return url.href;
|
||||
};
|
||||
|
||||
/** Caller-declared translation from an authorized runtime location to a layer. */
|
||||
const runtimeLocationMappingSchema = z.discriminatedUnion("kind", [
|
||||
runtimeFileMappingSchema,
|
||||
runtimeUrlMappingSchema,
|
||||
]);
|
||||
type RuntimeLocationMapping = z.infer<typeof runtimeLocationMappingSchema>;
|
||||
|
||||
const staticLayerSchema = z.strictObject({
|
||||
role: z.enum(["application", "cache", "assets"]).default("application"),
|
||||
analysis: evidenceSchema,
|
||||
runtime_mappings: z
|
||||
.array(runtimeLocationMappingSchema)
|
||||
.overwrite(normalizeRuntimeMappings)
|
||||
.default([]),
|
||||
});
|
||||
|
||||
function normalizeRuntimeMappings(
|
||||
mappings: RuntimeLocationMapping[],
|
||||
): RuntimeLocationMapping[] {
|
||||
return [
|
||||
...new Map(
|
||||
mappings.map((mapping) => [runtimeMappingKey(mapping), mapping]),
|
||||
).values(),
|
||||
].sort((left, right) =>
|
||||
compareCodePoints(runtimeMappingKey(left), runtimeMappingKey(right)),
|
||||
);
|
||||
}
|
||||
|
||||
function runtimeMappingKey(mapping: RuntimeLocationMapping): string {
|
||||
return mapping.kind === "file-root"
|
||||
? `file-root\0${mapping.root}\0${mapping.artifact_prefix}`
|
||||
: `url-prefix\0${mapping.prefix}\0${mapping.artifact_prefix}`;
|
||||
}
|
||||
|
||||
/** Evidence-backed static layers and passive captures to reconcile. */
|
||||
export const reconcileJavaScriptRuntimeInputSchema = z
|
||||
.strictObject({
|
||||
static_layers: z.array(staticLayerSchema).min(1),
|
||||
runtime_observations: z.array(evidenceSchema).min(1),
|
||||
})
|
||||
.superRefine((input, context) => {
|
||||
if (
|
||||
input.static_layers.filter(({ role }) => role === "application")
|
||||
.length !== 1
|
||||
)
|
||||
context.addIssue({
|
||||
code: "custom",
|
||||
path: ["static_layers"],
|
||||
message: "Exactly one application static layer is required",
|
||||
});
|
||||
const staticIds = input.static_layers.map(
|
||||
({ analysis }) => analysis.evidence_id,
|
||||
);
|
||||
if (new Set(staticIds).size !== staticIds.length)
|
||||
context.addIssue({
|
||||
code: "custom",
|
||||
path: ["static_layers"],
|
||||
message: "Static layer Evidence must be unique",
|
||||
});
|
||||
const runtimeIds = input.runtime_observations.map(
|
||||
({ evidence_id: id }) => id,
|
||||
);
|
||||
if (new Set(runtimeIds).size !== runtimeIds.length)
|
||||
context.addIssue({
|
||||
code: "custom",
|
||||
path: ["runtime_observations"],
|
||||
message: "Runtime observation Evidence must be unique",
|
||||
});
|
||||
});
|
||||
|
||||
const layerSummarySchema = z.strictObject({
|
||||
layer_id: prefixedDigestSchema("jrl"),
|
||||
role: z.enum(["application", "cache", "assets"]),
|
||||
evidence_id: evidenceIdSchema,
|
||||
graph_id: prefixedDigestSchema("jag"),
|
||||
root_artifact_sha256: digestSchema,
|
||||
input_path: z.string().min(1),
|
||||
format: z.enum(["asar", "directory"]),
|
||||
runtime_mappings: z.array(runtimeLocationMappingSchema),
|
||||
});
|
||||
|
||||
const captureSummarySchema = z.strictObject({
|
||||
evidence_id: evidenceIdSchema,
|
||||
capture_sha256: digestSchema,
|
||||
kind: z.enum(["browser", "electron", "v8-inspector", "electron-active"]),
|
||||
target_node_id: nodeIdSchema,
|
||||
target_key: boundedTextSchema,
|
||||
target_location: z
|
||||
.string()
|
||||
.min(1)
|
||||
.or(javascriptRuntimeUnresolvedLocationSchema),
|
||||
frames: z.number().int().min(0),
|
||||
scripts: z.number().int().min(0),
|
||||
workers: z.number().int().min(0),
|
||||
scripts_complete_within_scope: z.boolean(),
|
||||
});
|
||||
|
||||
const reconciliationReasonSchema = z.enum([
|
||||
"content-and-location-match",
|
||||
"unique-content-match",
|
||||
"unique-location-match",
|
||||
"ambiguous-static-candidates",
|
||||
"captured-content-disagrees-with-static-location",
|
||||
"no-static-content-match",
|
||||
"no-authorized-location-mapping",
|
||||
"runtime-location-unresolved",
|
||||
"runtime-frame-unattributed",
|
||||
"static-or-runtime-coverage-incomplete",
|
||||
"reconciliation-limit-reached",
|
||||
]);
|
||||
|
||||
const reconciliationItemShape = {
|
||||
reconciliation_id: prefixedDigestSchema("jrr_item"),
|
||||
entity_kind: z.enum(["target", "frame", "script", "worker"]),
|
||||
runtime_evidence_id: evidenceIdSchema,
|
||||
runtime_node_id: nodeIdSchema,
|
||||
basis: z.enum([
|
||||
"content-and-location",
|
||||
"content-sha256",
|
||||
"module-source-sha256",
|
||||
"artifact-path",
|
||||
"operator-file-mapping",
|
||||
"operator-url-mapping",
|
||||
"none",
|
||||
]),
|
||||
confidence: z.enum(["exact", "high", "medium", "low", "unknown"]),
|
||||
reason: reconciliationReasonSchema,
|
||||
candidate_static_count: z.number().int().min(0),
|
||||
candidate_static_nodes: z.array(
|
||||
z.strictObject({
|
||||
static_layer_id: prefixedDigestSchema("jrl"),
|
||||
static_node_id: nodeIdSchema,
|
||||
}),
|
||||
),
|
||||
};
|
||||
const reconciliationItemSchema = z.union([
|
||||
z.strictObject({
|
||||
...reconciliationItemShape,
|
||||
static_layer_id: prefixedDigestSchema("jrl"),
|
||||
static_node_id: nodeIdSchema,
|
||||
status: z.literal("matched"),
|
||||
}),
|
||||
z.strictObject({
|
||||
...reconciliationItemShape,
|
||||
static_layer_id: z.null(),
|
||||
static_node_id: z.null(),
|
||||
status: z.enum(["ambiguous", "unmatched", "unknown"]),
|
||||
}),
|
||||
]);
|
||||
|
||||
const staticLoadStateSchema = z.strictObject({
|
||||
static_layer_id: prefixedDigestSchema("jrl"),
|
||||
static_node_id: nodeIdSchema,
|
||||
kind: z.enum(["javascript-asset", "javascript-chunk", "javascript-module"]),
|
||||
status: z.enum([
|
||||
"loaded",
|
||||
"resident-in-loaded-asset",
|
||||
"not-observed-in-capture",
|
||||
"unknown",
|
||||
]),
|
||||
runtime_node_ids: z.array(nodeIdSchema),
|
||||
reason: z.enum([
|
||||
"runtime-script-correspondence",
|
||||
"containing-asset-was-loaded",
|
||||
"not-observed-in-bounded-capture",
|
||||
"layer-outside-runtime-scope",
|
||||
"static-or-runtime-coverage-incomplete",
|
||||
]),
|
||||
});
|
||||
|
||||
/** Deterministic static/passive-runtime reconciliation with a combined JAG. */
|
||||
export const javascriptRuntimeReconciliationResultSchema = z.strictObject({
|
||||
reconciliation_id: prefixedDigestSchema("jrr"),
|
||||
static_layers: z.array(layerSummarySchema).min(1),
|
||||
runtime_captures: z.array(captureSummarySchema).min(1),
|
||||
graph: javascriptApplicationGraphSchema,
|
||||
summary: z.strictObject({
|
||||
runtime_targets: z.number().int().min(0),
|
||||
runtime_frames: z.number().int().min(0),
|
||||
runtime_scripts: z.number().int().min(0),
|
||||
runtime_workers: z.number().int().min(0),
|
||||
matched: z.number().int().min(0),
|
||||
ambiguous: z.number().int().min(0),
|
||||
unmatched: z.number().int().min(0),
|
||||
unknown: z.number().int().min(0),
|
||||
static_loaded: z.number().int().min(0),
|
||||
static_resident: z.number().int().min(0),
|
||||
static_not_observed: z.number().int().min(0),
|
||||
static_unknown: z.number().int().min(0),
|
||||
}),
|
||||
reconciliations: z.array(reconciliationItemSchema),
|
||||
static_load_states: z.array(staticLoadStateSchema),
|
||||
source_map_authority: z.strictObject({
|
||||
used_for_primary_matching: z.literal(false),
|
||||
static_layer_count: z.number().int().min(0),
|
||||
runtime_script_declarations: z.number().int().min(0),
|
||||
limitation: boundedTextSchema,
|
||||
}),
|
||||
coverage: z.strictObject({
|
||||
status: z.enum(["complete-within-inputs", "partial", "truncated"]),
|
||||
truncated: z.boolean(),
|
||||
omitted_runtime_entities: z.number().int().min(0),
|
||||
omitted_reconciliation_items: z.number().int().min(0),
|
||||
omitted_static_load_states: z.number().int().min(0),
|
||||
omitted_graph_items: z.number().int().min(0),
|
||||
}),
|
||||
evidence_links: z.array(evidenceIdSchema).min(2),
|
||||
limitations: z.array(boundedTextSchema),
|
||||
});
|
||||
|
||||
export type ReconcileJavaScriptRuntimeInput = z.infer<
|
||||
typeof reconcileJavaScriptRuntimeInputSchema
|
||||
>;
|
||||
export type JavaScriptRuntimeReconciliationResult = z.infer<
|
||||
typeof javascriptRuntimeReconciliationResultSchema
|
||||
>;
|
||||
export type JavaScriptRuntimeReconciliationItem = z.infer<
|
||||
typeof reconciliationItemSchema
|
||||
>;
|
||||
export type JavaScriptStaticLoadState = z.infer<typeof staticLoadStateSchema>;
|
||||
Reference in new issue
Block a user