Files
portifolio-evandrodevbr/lib/portfolio-data.server.ts
Evandro Fonseca Junior e80f73d075 feat(cases): mídia no topo, títulos de busca curtos e CreativeWork
Case com mídia ao lado do título e play acessível; problema de cada cliente reescrito com base nos dados; serviços relacionados em 2 cards; FAQ antes do próximo passo e bloco 'Onde já apliquei isso'; Apolo citada em IoT e arquitetura. metaTitle até 43 caracteres e descrições até 155 com teste; JSON-LD CreativeWork; imagens de compartilhamento abaixo de 100 KB; 404 e robots corrigidos; server-only nos módulos com node:.
2026-10-14 14:15:25 -03:00

72 lines
2.1 KiB
TypeScript

import "server-only";
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<ProjectHealthSnapshot | null> {
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<PortfolioProjectView[]> {
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);
}
}