53 lines
1.7 KiB
TypeScript
53 lines
1.7 KiB
TypeScript
/**
|
|
* Manifest generation — deterministic, per SPIKE-04.
|
|
* Trace: SPIKE-04 §2, ARCH 10.2, IMPLEMENTATION-CONTRACT.md §15
|
|
*/
|
|
import type { FestivalManifest, SectionId } from "../src/data/festival-package/types.js";
|
|
import type { PipelineInput, SectionFile } from "./types.js";
|
|
|
|
export function buildManifest(
|
|
input: PipelineInput,
|
|
files: ReadonlyMap<string, SectionFile>,
|
|
totalBytes: number,
|
|
): FestivalManifest {
|
|
const counts = {
|
|
events: input.content.schedule.events.length,
|
|
pois: input.content.map.pois.length,
|
|
assets: input.content.assets.assets.length,
|
|
};
|
|
const sections: Record<
|
|
SectionId,
|
|
{ file: string; sha256: string; bytes: number; required: boolean }
|
|
> = {
|
|
emergency: entryFor(files, "emergency.json", true),
|
|
schedule: entryFor(files, "schedule.json", true),
|
|
map: entryFor(files, "map.json", true),
|
|
info: entryFor(files, "info.json", true),
|
|
assets: entryFor(files, "assets.json", true),
|
|
};
|
|
// Include optional sections if present in files and content has them (future)
|
|
// For now, only required 5.
|
|
const manifest: FestivalManifest = {
|
|
format: "lumen.package/1",
|
|
edition: input.edition,
|
|
packageVersion: input.packageVersion,
|
|
schemaVersion: input.schemaVersion,
|
|
generatedAt: input.generatedAt,
|
|
festival: { ...input.festival },
|
|
appCompatibility: { ...input.appCompatibility },
|
|
sections,
|
|
counts,
|
|
limits: { totalBytes },
|
|
};
|
|
return manifest;
|
|
}
|
|
|
|
function entryFor(
|
|
files: ReadonlyMap<string, SectionFile>,
|
|
file: string,
|
|
required: boolean,
|
|
): { file: string; sha256: string; bytes: number; required: boolean } {
|
|
const f = files.get(file);
|
|
if (!f) throw new Error(`manifest missing file ${file}`);
|
|
return { file, sha256: f.sha256, bytes: f.bytes, required };
|
|
}
|