|
1 | 1 | import { type NextRequest, NextResponse } from 'next/server' |
2 | 2 | import { deleteCopilotApiKeyQuerySchema } from '@/lib/api/contracts' |
3 | 3 | import { getSession } from '@/lib/auth' |
4 | | -import { TraceAttr } from '@/lib/copilot/generated/trace-attributes-v1' |
5 | | -import { fetchGo } from '@/lib/copilot/request/go/fetch' |
6 | | -import { getMothershipBaseURL } from '@/lib/copilot/server/agent-url' |
7 | | -import { env } from '@/lib/core/config/env' |
| 4 | +import { |
| 5 | + CopilotApiKeyError, |
| 6 | + deleteCopilotApiKey, |
| 7 | + listCopilotApiKeys, |
| 8 | +} from '@/lib/copilot/server/api-keys' |
8 | 9 | import { withRouteHandler } from '@/lib/core/utils/with-route-handler' |
9 | 10 |
|
10 | | -export const GET = withRouteHandler(async (request: NextRequest) => { |
11 | | - try { |
12 | | - const session = await getSession() |
13 | | - if (!session?.user?.id) { |
14 | | - return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }) |
15 | | - } |
16 | | - |
17 | | - const userId = session.user.id |
18 | | - const mothershipBaseURL = await getMothershipBaseURL({ userId }) |
19 | | - |
20 | | - const res = await fetchGo(`${mothershipBaseURL}/api/validate-key/get-api-keys`, { |
21 | | - method: 'POST', |
22 | | - headers: { |
23 | | - 'Content-Type': 'application/json', |
24 | | - ...(env.COPILOT_API_KEY ? { 'x-api-key': env.COPILOT_API_KEY } : {}), |
25 | | - }, |
26 | | - body: JSON.stringify({ userId }), |
27 | | - spanName: 'sim → go /api/validate-key/get-api-keys', |
28 | | - operation: 'get_api_keys', |
29 | | - attributes: { [TraceAttr.UserId]: userId }, |
30 | | - }) |
31 | | - |
32 | | - if (!res.ok) { |
33 | | - return NextResponse.json({ error: 'Failed to get keys' }, { status: res.status || 500 }) |
34 | | - } |
| 11 | +function errorResponse(error: unknown, fallback: string): NextResponse { |
| 12 | + const status = error instanceof CopilotApiKeyError ? error.upstreamStatus : undefined |
| 13 | + const message = error instanceof CopilotApiKeyError ? error.message : fallback |
| 14 | + return NextResponse.json({ error: message }, { status: status ?? 500 }) |
| 15 | +} |
35 | 16 |
|
36 | | - const apiKeys = (await res.json().catch(() => null)) as |
37 | | - | { id: string; apiKey: string; name?: string; createdAt?: string; lastUsed?: string }[] |
38 | | - | null |
39 | | - |
40 | | - if (!Array.isArray(apiKeys)) { |
41 | | - return NextResponse.json({ error: 'Invalid response from Sim Agent' }, { status: 500 }) |
42 | | - } |
43 | | - |
44 | | - const keys = apiKeys.map((k) => { |
45 | | - const value = typeof k.apiKey === 'string' ? k.apiKey : '' |
46 | | - const last6 = value.slice(-6) |
47 | | - const displayKey = `•••••${last6}` |
48 | | - return { |
49 | | - id: k.id, |
50 | | - displayKey, |
51 | | - name: k.name || null, |
52 | | - createdAt: k.createdAt || null, |
53 | | - lastUsed: k.lastUsed || null, |
54 | | - } |
55 | | - }) |
| 17 | +export const GET = withRouteHandler(async () => { |
| 18 | + const session = await getSession() |
| 19 | + if (!session?.user?.id) { |
| 20 | + return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }) |
| 21 | + } |
56 | 22 |
|
| 23 | + try { |
| 24 | + const keys = await listCopilotApiKeys(session.user.id) |
57 | 25 | return NextResponse.json({ keys }, { status: 200 }) |
58 | 26 | } catch (error) { |
59 | | - return NextResponse.json({ error: 'Failed to get keys' }, { status: 500 }) |
| 27 | + return errorResponse(error, 'Failed to get keys') |
60 | 28 | } |
61 | 29 | }) |
62 | 30 |
|
63 | 31 | export const DELETE = withRouteHandler(async (request: NextRequest) => { |
64 | | - try { |
65 | | - const session = await getSession() |
66 | | - if (!session?.user?.id) { |
67 | | - return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }) |
68 | | - } |
69 | | - |
70 | | - const userId = session.user.id |
71 | | - const mothershipBaseURL = await getMothershipBaseURL({ userId }) |
72 | | - const queryResult = deleteCopilotApiKeyQuerySchema.safeParse( |
73 | | - Object.fromEntries(new URL(request.url).searchParams) |
74 | | - ) |
75 | | - if (!queryResult.success) { |
76 | | - return NextResponse.json({ error: 'id is required' }, { status: 400 }) |
77 | | - } |
78 | | - const { id } = queryResult.data |
79 | | - |
80 | | - const res = await fetchGo(`${mothershipBaseURL}/api/validate-key/delete`, { |
81 | | - method: 'POST', |
82 | | - headers: { |
83 | | - 'Content-Type': 'application/json', |
84 | | - ...(env.COPILOT_API_KEY ? { 'x-api-key': env.COPILOT_API_KEY } : {}), |
85 | | - }, |
86 | | - body: JSON.stringify({ userId, apiKeyId: id }), |
87 | | - spanName: 'sim → go /api/validate-key/delete', |
88 | | - operation: 'delete_api_key', |
89 | | - attributes: { [TraceAttr.UserId]: userId, [TraceAttr.ApiKeyId]: id }, |
90 | | - }) |
91 | | - |
92 | | - if (!res.ok) { |
93 | | - return NextResponse.json({ error: 'Failed to delete key' }, { status: res.status || 500 }) |
94 | | - } |
| 32 | + const session = await getSession() |
| 33 | + if (!session?.user?.id) { |
| 34 | + return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }) |
| 35 | + } |
95 | 36 |
|
96 | | - const data = (await res.json().catch(() => null)) as { success?: boolean } | null |
97 | | - if (!data?.success) { |
98 | | - return NextResponse.json({ error: 'Invalid response from Sim Agent' }, { status: 500 }) |
99 | | - } |
| 37 | + const queryResult = deleteCopilotApiKeyQuerySchema.safeParse( |
| 38 | + Object.fromEntries(new URL(request.url).searchParams) |
| 39 | + ) |
| 40 | + if (!queryResult.success) { |
| 41 | + return NextResponse.json({ error: 'id is required' }, { status: 400 }) |
| 42 | + } |
100 | 43 |
|
| 44 | + try { |
| 45 | + await deleteCopilotApiKey(session.user.id, queryResult.data.id) |
101 | 46 | return NextResponse.json({ success: true }, { status: 200 }) |
102 | 47 | } catch (error) { |
103 | | - return NextResponse.json({ error: 'Failed to delete key' }, { status: 500 }) |
| 48 | + return errorResponse(error, 'Failed to delete key') |
104 | 49 | } |
105 | 50 | }) |
0 commit comments