import type { PlatformProfile, PlatformProfileSummary } from "@rakazo/contracts"; import { PlatformProfileSchema } from "@rakazo/contracts"; export const PROFILE_STALE_DAYS = 90; export interface ProfileLoadError { file: string; message: string; } export interface ProfileSet { profiles: Map; errors: ProfileLoadError[]; } /** Parse raw JSON documents; invalid ones become errors and are skipped whole. */ export function parseProfiles(documents: Array<{ file: string; json: unknown }>): { profiles: PlatformProfile[]; errors: ProfileLoadError[]; } { const profiles: PlatformProfile[] = []; const errors: ProfileLoadError[] = []; const seen = new Set(); for (const document of documents) { const parsed = PlatformProfileSchema.safeParse(document.json); if (!parsed.success) { errors.push({ file: document.file, message: parsed.error.issues .map((issue) => `${issue.path.join(".") || "(root)"}: ${issue.message}`) .join("; "), }); continue; } if (seen.has(parsed.data.id)) { errors.push({ file: document.file, message: `duplicate profile id ${parsed.data.id}` }); continue; } seen.add(parsed.data.id); profiles.push(parsed.data); } return { profiles, errors }; } /** Private profiles override builtin ones with the same id. */ export function mergeProfiles( builtin: PlatformProfile[], privateProfiles: PlatformProfile[], ): ProfileSet { const profiles: ProfileSet["profiles"] = new Map(); for (const profile of builtin) profiles.set(profile.id, { profile, origin: "builtin" }); for (const profile of privateProfiles) profiles.set(profile.id, { profile, origin: "private" }); return { profiles, errors: [] }; } export function isProfileStale(profile: PlatformProfile, now: Date): boolean { const reviewed = Date.parse(`${profile.reviewedAt}T00:00:00Z`); return now.getTime() - reviewed > PROFILE_STALE_DAYS * 24 * 60 * 60 * 1000; } export function summarizeProfile( profile: PlatformProfile, origin: "builtin" | "private", now: Date, ): PlatformProfileSummary { return { id: profile.id, name: profile.name, kind: profile.kind, origin, unverified: profile.unverified, stale: isProfileStale(profile, now), aspectRatios: profile.video.aspectRatios, hardMinMs: profile.duration.hardMinMs, hardMaxMs: profile.duration.hardMaxMs, recommendedMs: profile.duration.recommended, }; }