- Add GET/PUT /api/settings for encrypted LLM configuration - SettingsResponse with masked key display - SettingsUpdate validation with optional fields - Defaults: llmBaseUrl "https://openrouter.ai/api/v1", llmModel "anthropic/claude-sonnet-4.5" - Encrypted storage with AES-256-GCM for llm_key - getSetting() export for future route groups - Comprehensive test coverage: defaults, updates, masking, encryption at rest, validation Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
23 lines
813 B
TypeScript
23 lines
813 B
TypeScript
import { z } from "zod";
|
|
|
|
export const HealthResponse = z.object({ ok: z.literal(true) });
|
|
export type HealthResponse = z.infer<typeof HealthResponse>;
|
|
|
|
export const PasswordBody = z.object({ password: z.string().min(8).max(200) });
|
|
export const MeResponse = z.object({ needsSetup: z.boolean(), authenticated: z.boolean() });
|
|
export type MeResponse = z.infer<typeof MeResponse>;
|
|
|
|
export const SettingsResponse = z.object({
|
|
llmBaseUrl: z.string(),
|
|
llmModel: z.string(),
|
|
llmKeyMasked: z.string().nullable(),
|
|
});
|
|
export type SettingsResponse = z.infer<typeof SettingsResponse>;
|
|
|
|
export const SettingsUpdate = z.object({
|
|
llmBaseUrl: z.string().url().optional(),
|
|
llmModel: z.string().min(1).optional(),
|
|
llmKey: z.string().min(1).optional(),
|
|
});
|
|
export type SettingsUpdate = z.infer<typeof SettingsUpdate>;
|