diff --git a/src/server/api/providers.ts b/src/server/api/providers.ts index 82247cc4..cdbc673b 100644 --- a/src/server/api/providers.ts +++ b/src/server/api/providers.ts @@ -1,30 +1,29 @@ /** * Providers REST API * - * GET /api/providers — 列出所有 provider - * GET /api/providers/:id — 获取单个 provider - * POST /api/providers — 添加 provider - * PUT /api/providers/:id — 更新 provider - * DELETE /api/providers/:id — 删除 provider - * POST /api/providers/:id/activate — 激活 provider - * POST /api/providers/:id/test — 测试已保存 provider - * POST /api/providers/test — 测试未保存的配置 + * GET /api/providers — list all saved providers + activeId + * GET /api/providers/presets — list available presets + * POST /api/providers — add a provider + * PUT /api/providers/:id — update a provider + * DELETE /api/providers/:id — delete a provider + * POST /api/providers/:id/activate — activate a saved provider + * POST /api/providers/official — activate official (clear env) + * POST /api/providers/:id/test — test a saved provider + * POST /api/providers/test — test unsaved config */ import { z } from 'zod' import { ProviderService } from '../services/providerService.js' +import { PROVIDER_PRESETS } from '../config/providerPresets.js' import { CreateProviderSchema, UpdateProviderSchema, TestProviderSchema, - ActivateProviderSchema, } from '../types/provider.js' import { ApiError, errorResponse } from '../middleware/errorHandler.js' const providerService = new ProviderService() -// ─── Sanitization ───────────────────────────────────────────────────────────── - function maskApiKey(key: string): string { if (key.length <= 8) return '****' return key.slice(0, 4) + '****' + key.slice(-4) @@ -37,27 +36,36 @@ function sanitizeProvider(provider: Record): Record { try { - const id = segments[2] // provider ID or 'test' - const action = segments[3] // 'activate' | 'test' | undefined + const id = segments[2] + const action = segments[3] - // ── POST /api/providers/test (test unsaved configuration) ────────── + // POST /api/providers/test if (id === 'test' && req.method === 'POST') { return await handleTestUnsaved(req) } - // ── /api/providers (no ID) ──────────────────────────────────────── + // GET /api/providers/presets + if (id === 'presets' && req.method === 'GET') { + return Response.json({ presets: PROVIDER_PRESETS }) + } + + // POST /api/providers/official + if (id === 'official' && req.method === 'POST') { + await providerService.activateOfficial() + return Response.json({ ok: true }) + } + + // /api/providers (no ID) if (!id) { if (req.method === 'GET') { - const providers = await providerService.listProviders() - return Response.json({ providers: providers.map(sanitizeProvider) }) + const { providers, activeId } = await providerService.listProviders() + return Response.json({ providers: providers.map(sanitizeProvider), activeId }) } if (req.method === 'POST') { return await handleCreate(req) @@ -65,20 +73,21 @@ export async function handleProvidersApi( throw methodNotAllowed(req.method) } - // ── /api/providers/:id/activate ─────────────────────────────────── + // /api/providers/:id/activate if (action === 'activate') { if (req.method !== 'POST') throw methodNotAllowed(req.method) - return await handleActivate(req, id) + await providerService.activateProvider(id) + return Response.json({ ok: true }) } - // ── /api/providers/:id/test ─────────────────────────────────────── + // /api/providers/:id/test if (action === 'test') { if (req.method !== 'POST') throw methodNotAllowed(req.method) const result = await providerService.testProvider(id) return Response.json({ result }) } - // ── /api/providers/:id (no action) ──────────────────────────────── + // /api/providers/:id if (req.method === 'GET') { const provider = await providerService.getProvider(id) return Response.json({ provider: sanitizeProvider(provider) }) @@ -97,8 +106,6 @@ export async function handleProvidersApi( } } -// ─── Handlers ───────────────────────────────────────────────────────────────── - async function handleCreate(req: Request): Promise { const body = await parseJsonBody(req) try { @@ -106,9 +113,7 @@ async function handleCreate(req: Request): Promise { const provider = await providerService.addProvider(input) return Response.json({ provider }, { status: 201 }) } catch (err) { - if (err instanceof z.ZodError) { - throw ApiError.badRequest(err.issues.map((i) => i.message).join('; ')) - } + if (err instanceof z.ZodError) throw ApiError.badRequest(err.issues.map((i) => i.message).join('; ')) throw err } } @@ -120,23 +125,7 @@ async function handleUpdate(req: Request, id: string): Promise { const provider = await providerService.updateProvider(id, input) return Response.json({ provider }) } catch (err) { - if (err instanceof z.ZodError) { - throw ApiError.badRequest(err.issues.map((i) => i.message).join('; ')) - } - throw err - } -} - -async function handleActivate(req: Request, id: string): Promise { - const body = await parseJsonBody(req) - try { - const input = ActivateProviderSchema.parse(body) - await providerService.activateProvider(id, input.modelId) - return Response.json({ ok: true }) - } catch (err) { - if (err instanceof z.ZodError) { - throw ApiError.badRequest(err.issues.map((i) => i.message).join('; ')) - } + if (err instanceof z.ZodError) throw ApiError.badRequest(err.issues.map((i) => i.message).join('; ')) throw err } } @@ -148,15 +137,11 @@ async function handleTestUnsaved(req: Request): Promise { const result = await providerService.testProviderConfig(input) return Response.json({ result }) } catch (err) { - if (err instanceof z.ZodError) { - throw ApiError.badRequest(err.issues.map((i) => i.message).join('; ')) - } + if (err instanceof z.ZodError) throw ApiError.badRequest(err.issues.map((i) => i.message).join('; ')) throw err } } -// ─── Helpers ────────────────────────────────────────────────────────────────── - async function parseJsonBody(req: Request): Promise> { try { return (await req.json()) as Record