Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0138YqDj3ttfayRwuMKKrqVj
79 lines
2.5 KiB
TypeScript
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,
|
|
};
|
|
}
|