import type { GLBExportReport } from "./glb-export"; import type { SceneSnapshotIR } from "./scene-ir"; export const GLB_LOSS_REPORT_SCHEMA_VERSION = 1 as const; export interface GLBLossReport { schemaVersion: typeof GLB_LOSS_REPORT_SCHEMA_VERSION; operation: "GLB_EXPORT_LOSS_REPORT"; sceneId: string; sourceRevision: number; canExport: boolean; errorCount: number; warningCount: number; losses: Array<{ code: string; severity: "warning" | "error"; message: string; id: string | null; }>; surface: { nodeCount: number; meshCount: number; materialCount: number; imageCount: number; animationCount: number; nonMeshCount: number; }; } /** Convert the exporter result into a stable, machine-consumable loss report. */ export function createGLBLossReport(snapshot: SceneSnapshotIR, report: GLBExportReport): GLBLossReport { const losses = report.warnings .map((warning) => ({ code: warning.code, severity: warning.severity, message: warning.message, id: warning.id ?? null, })) .sort((left, right) => left.code.localeCompare(right.code) || left.severity.localeCompare(right.severity) || (left.id ?? "").localeCompare(right.id ?? "") || left.message.localeCompare(right.message), ); return { schemaVersion: GLB_LOSS_REPORT_SCHEMA_VERSION, operation: "GLB_EXPORT_LOSS_REPORT", sceneId: snapshot.sceneId, sourceRevision: snapshot.revision, canExport: report.canExport, errorCount: losses.filter((loss) => loss.severity === "error").length, warningCount: losses.filter((loss) => loss.severity === "warning").length, losses, surface: { nodeCount: snapshot.nodes.length, meshCount: snapshot.meshes.length, materialCount: snapshot.materials.length, imageCount: snapshot.images.length, animationCount: snapshot.animations.length, nonMeshCount: snapshot.nonMeshData?.length ?? 0, }, }; }