mirror of
https://github.com/morluto/rea
synced 2026-10-27 14:42:18 -04:00
141 lines
4.6 KiB
TypeScript
141 lines
4.6 KiB
TypeScript
import { z } from "zod";
|
|
|
|
import {
|
|
hasCompleteInventoryCoverage,
|
|
type ParsedInventorySet,
|
|
} from "./artifactInventoryEvidence.js";
|
|
import { evidenceSchema, type Evidence } from "./evidence.js";
|
|
import { digestSchema } from "./digests.js";
|
|
import { prefixedDigestSchema } from "./digests.js";
|
|
|
|
/** Evidence-scoped identifier schemas shared by application graph projections. */
|
|
export const projectionEvidenceIdSchema = prefixedDigestSchema("ev");
|
|
export const projectionPathSchema = z.string().min(1);
|
|
|
|
/** Inventory pages accepted by every application graph projection. */
|
|
export const applicationInventoryProjectionInputSchema = z.strictObject({
|
|
inventory_evidence: z.array(evidenceSchema).min(1),
|
|
});
|
|
|
|
/** One authenticated inventory entry retained by application graph projections. */
|
|
export const projectedComponentSchema = z.strictObject({
|
|
path: projectionPathSchema,
|
|
artifact_id: prefixedDigestSchema("art"),
|
|
sha256: digestSchema,
|
|
format: z.string().min(1),
|
|
});
|
|
|
|
/** Inventoried paths whose content identity is unavailable, retained as unknown. */
|
|
export const unavailableComponentSchema = z.strictObject({
|
|
path: projectionPathSchema,
|
|
artifact_id: z.null(),
|
|
sha256: z.null(),
|
|
format: z.string().min(1),
|
|
encrypted: z.boolean(),
|
|
limitations: z.array(z.string()),
|
|
});
|
|
|
|
export type ProjectedComponent = z.infer<typeof projectedComponentSchema>;
|
|
|
|
/** A projection and the authenticated source Evidence used to derive it. */
|
|
export interface MobileApplicationProjectionWithSources<Projection> {
|
|
readonly projection: Projection;
|
|
readonly sources: readonly Evidence[];
|
|
}
|
|
|
|
/** Path-pair hypotheses connecting managed content to a native library. */
|
|
export const projectedBridgeCandidateSchema = <
|
|
Basis extends readonly [string, ...string[]],
|
|
>(
|
|
basis: Basis,
|
|
) =>
|
|
z.strictObject({
|
|
managed_path: projectionPathSchema,
|
|
native_path: projectionPathSchema,
|
|
basis: z.enum(basis),
|
|
});
|
|
|
|
/** Coverage status combining inventory completeness with a projection budget. */
|
|
export const projectionCoverage = (
|
|
inventory: ParsedInventorySet["inventory"],
|
|
budgetComplete: boolean,
|
|
): {
|
|
status: "complete-within-inventory" | "partial";
|
|
/** True when all manifest graph-member counts are present, independent of source coverage. */
|
|
inventory_complete: boolean;
|
|
} => ({
|
|
status:
|
|
hasCompleteInventoryCoverage(inventory, "container-entries") &&
|
|
budgetComplete
|
|
? ("complete-within-inventory" as const)
|
|
: ("partial" as const),
|
|
inventory_complete: inventory.complete,
|
|
});
|
|
|
|
/** One occurrence, preserving entry kind and either authenticated or unavailable content. */
|
|
export type ProjectedInventoryEntry = {
|
|
readonly path: string;
|
|
readonly kind: ParsedInventorySet["inventory"]["occurrences"][number]["entry_kind"];
|
|
} & (
|
|
| { readonly component: ProjectedComponent; readonly unavailable: undefined }
|
|
| {
|
|
readonly component: undefined;
|
|
readonly unavailable: z.infer<typeof unavailableComponentSchema>;
|
|
}
|
|
);
|
|
|
|
/** Interpret identity once, before application-specific attribution and classification. */
|
|
export const projectedInventoryEntries = (
|
|
inventory: ParsedInventorySet["inventory"],
|
|
): ProjectedInventoryEntry[] => {
|
|
const nodes = new Map(
|
|
inventory.nodes.map((node) => [node.artifact_id, node]),
|
|
);
|
|
return inventory.occurrences
|
|
.filter(({ logical_path }) => logical_path !== ".")
|
|
.map((occurrence): ProjectedInventoryEntry => {
|
|
const path = occurrence.logical_path;
|
|
const kind = occurrence.entry_kind;
|
|
if (occurrence.artifact_id === null)
|
|
return {
|
|
path,
|
|
kind,
|
|
component: undefined,
|
|
unavailable: {
|
|
path,
|
|
artifact_id: null,
|
|
sha256: null,
|
|
format: occurrence.artifact_format,
|
|
encrypted: occurrence.encrypted,
|
|
limitations: occurrence.limitations,
|
|
},
|
|
};
|
|
const node = nodes.get(occurrence.artifact_id);
|
|
if (node === undefined)
|
|
throw new TypeError(
|
|
"Application projection occurrence has no artifact node",
|
|
);
|
|
return {
|
|
path,
|
|
kind,
|
|
component: {
|
|
path,
|
|
artifact_id: node.artifact_id,
|
|
sha256: node.sha256,
|
|
format: occurrence.artifact_format,
|
|
},
|
|
unavailable: undefined,
|
|
};
|
|
});
|
|
};
|
|
|
|
/** Directory trees and links retain inventory identity but are not file components. */
|
|
export const projectedFileComponents = (
|
|
entries: readonly ProjectedInventoryEntry[],
|
|
): ProjectedComponent[] =>
|
|
entries.flatMap(({ kind, component }) =>
|
|
(kind === "file" || kind === "slice") && component !== undefined
|
|
? [component]
|
|
: [],
|
|
);
|