import fs from "node:fs"; import path from "node:path"; export type SavedModelConfig = { baseUrl?: string; model?: string; apiKey?: string; enabled?: boolean; updatedAt?: string; }; type ConfigFile = { version: 1; models: Record; }; export type SaveModelConfigInput = { baseUrl?: string; model?: string; apiKey?: string; enabled?: boolean; clearApiKey?: boolean; }; const defaultConfigPath = () => path.resolve(process.cwd(), process.env.MODEL_CONFIG_PATH?.trim() || ".face-to-api/model-configs.json"); let cache: ConfigFile | undefined; const emptyStore = (): ConfigFile => ({ version: 1, models: {} }); const readStore = (): ConfigFile => { if (cache) { return cache; } const filePath = defaultConfigPath(); if (!fs.existsSync(filePath)) { cache = emptyStore(); return cache; } try { const parsed = JSON.parse(fs.readFileSync(filePath, "utf-8")) as ConfigFile; cache = { version: 1, models: parsed.models ?? {} }; return cache; } catch { cache = emptyStore(); return cache; } }; const writeStore = (store: ConfigFile) => { const filePath = defaultConfigPath(); fs.mkdirSync(path.dirname(filePath), { recursive: true }); fs.writeFileSync(filePath, `${JSON.stringify(store, null, 2)}\n`); cache = store; }; const trimOrUndefined = (value?: string) => { const trimmed = value?.trim(); return trimmed ? trimmed : undefined; }; export const getSavedModelConfig = (modelId: string): SavedModelConfig | undefined => { const saved = readStore().models[modelId]; return saved ? { ...saved } : undefined; }; export const saveModelConfig = (modelId: string, input: SaveModelConfigInput) => { const store = readStore(); const existing = store.models[modelId] ?? {}; const next: SavedModelConfig = { ...existing }; const baseUrl = trimOrUndefined(input.baseUrl); const model = trimOrUndefined(input.model); const apiKey = trimOrUndefined(input.apiKey); if (input.baseUrl !== undefined) { if (baseUrl) { next.baseUrl = baseUrl; } else { delete next.baseUrl; } } if (input.model !== undefined) { if (model) { next.model = model; } else { delete next.model; } } if (input.clearApiKey) { delete next.apiKey; } else if (apiKey) { next.apiKey = apiKey; } if (input.enabled !== undefined) { next.enabled = input.enabled; } next.updatedAt = new Date().toISOString(); store.models[modelId] = next; writeStore(store); return { ...next }; }; export const maskApiKey = (apiKey?: string) => { if (!apiKey) { return ""; } const tail = apiKey.slice(-4); return `•••• ${tail}`; };