export const PROJECT_HEALTH_MAX_AGE_MS = 15 * 60 * 1000; export interface ProjectHealthCheck { status: number | null; contentType: string | null; checkedAt: string; finalUrl?: string; latencyMs?: number; error?: string; } export interface ProjectHealthSnapshot { checkedAt: string; projects: Record; } interface ProjectLike { id: string; featured?: boolean; } function isFresh(checkedAt: string, now: Date) { const timestamp = Date.parse(checkedAt); return ( Number.isFinite(timestamp) && now.getTime() - timestamp <= PROJECT_HEALTH_MAX_AGE_MS ); } export function isCurrentLiveCheck( check: ProjectHealthCheck | undefined, now = new Date(), ) { return Boolean( check && check.status === 200 && check.contentType?.toLowerCase().startsWith("text/html") && isFresh(check.checkedAt, now), ); } export function filterLiveProjects( projects: T[], snapshot: ProjectHealthSnapshot | null, now = new Date(), ) { if (!snapshot || !isFresh(snapshot.checkedAt, now)) { return [] as T[]; } return projects.filter( (project) => project.featured !== false && isCurrentLiveCheck(snapshot.projects[project.id], now), ); } interface ProjectDemo { id: string; demoUrl: string; } interface HealthResponse { status: number; url: string; headers: { get(name: string): string | null }; body?: { cancel?: () => unknown } | null; } type HealthFetcher = (url: string, init: RequestInit) => Promise; export async function createProjectHealthSnapshot( projects: ProjectDemo[], fetcher: HealthFetcher = (url, init) => fetch(url, init), now = new Date(), ): Promise { const checkedAt = now.toISOString(); const checks = await Promise.all( projects.map(async (project) => { try { const response = await fetcher(project.demoUrl, { redirect: "follow", signal: AbortSignal.timeout(10_000), headers: { "user-agent": "evandro-project-health/1.0" }, }); await response.body?.cancel?.(); return [ project.id, { status: response.status, contentType: response.headers.get("content-type"), checkedAt, finalUrl: response.url, }, ] as const; } catch (error) { return [ project.id, { status: null, contentType: null, checkedAt, error: error instanceof Error ? error.message : "Health check failed", }, ] as const; } }), ); return { checkedAt, projects: Object.fromEntries(checks) }; }