import { existsSync } from 'node:fs'; import { mkdir, readFile } from 'node:fs/promises'; import { dirname, join } from 'node:path'; import { writeTextFileAtomic } from './atomic-write.js'; import { cinemaArtifactsDirFor } from './cinema-store.js'; import { validateCinemaPreflightReport, type CinemaPreflightReportArtifact } from './cinema-preflight.js'; import { stableCinemaJson } from './cinema-shot-compiler.js'; export function cinemaPreflightReportPathFor(root: string, report: CinemaPreflightReportArtifact): string { return join(cinemaArtifactsDirFor(root, report.projectSlug), 'preflight', `${report.contentHash.slice('sha256:'.length)}.json`); } export async function writeCinemaPreflightReport(root: string, report: CinemaPreflightReportArtifact): Promise { const validation = validateCinemaPreflightReport(report); if (!validation.ok) throw new Error(`Cinema preflight report failed validation: ${validation.issues.map((issue) => `${issue.path}: ${issue.message}`).join('; ')}`); const path = cinemaPreflightReportPathFor(root, report); await mkdir(dirname(path), { recursive: true }); if (existsSync(path)) { const existing = JSON.parse(await readFile(path, 'utf8')) as CinemaPreflightReportArtifact; if (stableCinemaJson(existing) !== stableCinemaJson(report)) throw new Error(`Cinema preflight report hash collision at ${path}`); return path; } await writeTextFileAtomic(path, `${JSON.stringify(report, null, 2)}\n`); return path; }