import fs from "node:fs/promises"; import path from "node:path"; import { buildRegistryManifests, normalizeDb, validateRegistry } from "../../src/lib/validation.js"; import { INITIAL_DB } from "../../src/model/seed.js"; import { evidenceDir, manifestsDir, registryPath } from "../config.js"; async function ensureDirs() { await fs.mkdir(manifestsDir, { recursive: true }); await fs.mkdir(evidenceDir, { recursive: true }); } export async function loadRegistry() { await ensureDirs(); try { const raw = await fs.readFile(registryPath, "utf-8"); return normalizeDb(JSON.parse(raw)); } catch { return normalizeDb(INITIAL_DB); } } export async function writeRegistry(input) { await ensureDirs(); const normalized = normalizeDb(input); const validation = validateRegistry(normalized); if (!validation.isValid) { const error = new Error("Registry validation failed."); error.validation = validation; throw error; } await fs.writeFile(registryPath, JSON.stringify(normalized, null, 2), "utf-8"); const manifests = buildRegistryManifests(normalized); await fs.writeFile(path.join(manifestsDir, "evidence-manifest.json"), JSON.stringify(manifests.evidenceManifest, null, 2), "utf-8"); await fs.writeFile(path.join(manifestsDir, "auditor-pack-index.json"), JSON.stringify(manifests.auditorPackIndex, null, 2), "utf-8"); return { registry: normalized, validation, manifests }; } export async function resetRegistry() { return writeRegistry(INITIAL_DB); } export async function listEvidenceArtifacts() { await ensureDirs(); const names = await fs.readdir(evidenceDir).catch(() => []); const stats = await Promise.all( names .filter((name) => !name.startsWith(".")) .map(async (name) => { const fullPath = path.join(evidenceDir, name); const stat = await fs.stat(fullPath); return { filename: name, size: stat.size, modifiedAt: stat.mtime.toISOString(), path: fullPath, }; }) ); return stats.sort((a, b) => a.filename.localeCompare(b.filename)); } export async function writeEvidenceArtifact({ filename, contentBase64 }) { await ensureDirs(); if (!filename || typeof filename !== "string") throw new Error("filename is required."); if (!contentBase64 || typeof contentBase64 !== "string") throw new Error("contentBase64 is required."); const safeName = filename.replace(/[^a-zA-Z0-9._-]/g, "_"); const fullPath = path.join(evidenceDir, safeName); await fs.writeFile(fullPath, Buffer.from(contentBase64, "base64")); const stat = await fs.stat(fullPath); return { filename: safeName, size: stat.size, modifiedAt: stat.mtime.toISOString(), path: fullPath, }; }