route.ts
1 import { NextResponse } from 'next/server' 2 import { z } from 'zod' 3 4 import { listPendingApprovals, submitDecision } from '@/lib/server/approvals' 5 import { safeParseBody } from '@/lib/server/safe-parse-body' 6 import { loadApprovals } from '@/lib/server/storage' 7 import { errorMessage } from '@/lib/shared-utils' 8 import type { ApprovalCategory } from '@/types' 9 10 export const dynamic = 'force-dynamic' 11 12 const ALLOWED_CATEGORIES: ApprovalCategory[] = [ 13 'human_loop', 'tool_access', 'extension_scaffold', 'extension_install', 14 'task_tool', 'connector_sender', 'agent_create', 'budget_change', 'delegation_enable', 15 ] 16 17 const ApprovalDecisionSchema = z.object({ 18 id: z.string().min(1, 'id is required'), 19 approved: z.boolean(), 20 }) 21 22 export async function GET(req: Request) { 23 const { searchParams } = new URL(req.url) 24 const categoryParam = searchParams.get('category') as ApprovalCategory | null 25 const category = categoryParam && ALLOWED_CATEGORIES.includes(categoryParam) 26 ? categoryParam 27 : undefined 28 return NextResponse.json(listPendingApprovals(category)) 29 } 30 31 export async function POST(req: Request) { 32 const { data: body, error } = await safeParseBody(req, ApprovalDecisionSchema) 33 if (error) return error 34 35 try { 36 const approval = loadApprovals()[body.id] 37 if (!approval) { 38 return NextResponse.json({ error: 'approval not found' }, { status: 404 }) 39 } 40 await submitDecision(body.id, body.approved) 41 return NextResponse.json({ ok: true }) 42 } catch (err: unknown) { 43 return NextResponse.json({ error: errorMessage(err) }, { status: 500 }) 44 } 45 }