2026-10-03 17:34:04 +00:00

79 lines
2.5 KiB
TypeScript

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<string, { profile: PlatformProfile; origin: "builtin" | "private" }>;
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<string>();
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,
};
}