/** * Provider Schema Validation — Phase 7.2 * * Zod schemas for provider constant validation. * Validates provider category maps * at module load time to catch configuration drift early. * * @module shared/validation/providerSchema */ import { z } from "zod"; const SERVICE_KIND_VALUES = [ "llm", "embedding", "image", "imageToText", "tts", "stt", "webSearch", "webFetch", "video", "music", ] as const; export const ProviderSchema = z.object({ id: z.string().min(1), alias: z.string().min(1).optional(), name: z.string().min(1), icon: z.string().min(1), color: z.string().regex(/^#[0-9A-Fa-f]{6}$/, "Must be a valid hex color (#RRGGBB)"), textIcon: z.string().optional(), website: z.string().url().optional(), passthroughModels: z.boolean().optional(), subscriptionRisk: z.boolean().optional(), riskNoticeVariant: z.enum(["oauth", "webCookie", "deprecated", "embedded-service"]).optional(), isEmbeddedService: z.boolean().optional(), deprecated: z.boolean().optional(), deprecationReason: z.string().optional(), hasFree: z.boolean().optional(), freeNote: z.string().optional(), authHint: z.string().optional(), apiHint: z.string().optional(), serviceKinds: z.array(z.enum(SERVICE_KIND_VALUES)).optional(), }); export const ProvidersMapSchema = z.record(z.string(), ProviderSchema); /** * Validate a providers map, throwing a descriptive error on failure. * @param {Record} map - The providers map to validate * @param {string} name - Name of the map for error messages */ export function validateProviders(map: Record, name: string): void { const result = ProvidersMapSchema.safeParse(map); if (!result.success) { const issues = result.error.issues.map((i) => ` ${i.path.join(".")}: ${i.message}`).join("\n"); console.error(`[PROVIDER VALIDATION] ${name} has invalid entries:\n${issues}`); throw new Error(`Provider validation failed for ${name}`); } }