import { readFile } from "node:fs/promises"; import { resolve } from "node:path"; import { getFeaturedProjects, type PortfolioProjectView, portfolio, } from "./portfolio-data"; import { createProjectHealthSnapshot, PROJECT_HEALTH_MAX_AGE_MS, type ProjectHealthSnapshot, } from "./project-health"; // Só no servidor: lê o arquivo de saúde das demonstrações (node:fs). lib/portfolio-data.ts fica sem Node, // porque lib/site-content.ts e lib/proof.ts o importam e componentes de cliente chegam a eles. function isSnapshotFresh( snapshot: ProjectHealthSnapshot | null, now = new Date(), ) { if (!snapshot) return false; const checkedAt = Date.parse(snapshot.checkedAt); return ( Number.isFinite(checkedAt) && now.getTime() - checkedAt <= PROJECT_HEALTH_MAX_AGE_MS ); } export async function loadProjectHealthSnapshot(): Promise { try { const path = resolve(process.cwd(), "data/project-health.json"); return JSON.parse(await readFile(path, "utf8")) as ProjectHealthSnapshot; } catch { return null; } } export async function loadFeaturedProjects(): Promise { const snapshot = await loadProjectHealthSnapshot(); if (process.env.NODE_ENV !== "development" || isSnapshotFresh(snapshot)) { return getFeaturedProjects(snapshot); } const projectDemos = portfolio.projects.reduce< Array<{ id: string; demoUrl: string }> >((demos, project) => { if (project.demoUrl) demos.push({ id: project.id, demoUrl: project.demoUrl }); return demos; }, []); try { const refreshed = await createProjectHealthSnapshot(projectDemos); const projects = { ...refreshed.projects }; for (const [id, check] of Object.entries(projects)) { if (!check.error && check.status !== null) continue; const previous = snapshot?.projects[id]; if (previous && !previous.error && previous.status !== null) { projects[id] = previous; } else { delete projects[id]; } } return getFeaturedProjects({ ...refreshed, projects }); } catch { return getFeaturedProjects(snapshot); } }