import { type NextRequest, NextResponse } from 'next/server'; import { createDb, skillQueries, sql } from '@skillhub/db'; import { requireAdmin } from '@/lib/admin-auth'; import { withRateLimit, createRateLimitResponse, createRateLimitHeaders } from '@/lib/rate-limit'; const db = createDb(); /** * GET /api/review/diagnose?id=owner/repo/skill-name * Returns which review pipeline filters a skill passes/fails. * Calls the actual PostgreSQL raw_content_passes_prefilter function to detect * discrepancies between JS approximation and SQL reality (e.g. invalid UTF-8). * Admin-only endpoint for debugging why skills don't appear in pending list. */ export async function GET(request: NextRequest) { const rateLimitResult = await withRateLimit(request, 'anonymous'); if (!rateLimitResult.allowed) { return createRateLimitResponse(rateLimitResult); } const adminCheck = await requireAdmin(request); if (!adminCheck.authorized) { return adminCheck.response; } try { const { searchParams } = new URL(request.url); const skillId = searchParams.get('id'); if (!skillId) { return NextResponse.json({ error: 'Missing id parameter' }, { status: 400 }); } const skill = await skillQueries.getById(db, skillId); if (!skill) { return NextResponse.json({ error: 'Skill not found', id: skillId }, { status: 404 }); } // Call the ACTUAL PostgreSQL function to check prefilter // This catches UTF-8 issues that the JS approximation misses let sqlPrefilterPass = false; try { const result = await db.execute( sql`SELECT raw_content_passes_prefilter(raw_content) AS passes FROM skills WHERE id = ${skillId}` ); const row = [...result][0] as { passes?: boolean } | undefined; sqlPrefilterPass = row?.passes === true; } catch { sqlPrefilterPass = false; } // JS approximation for comparison const rawContent = skill.rawContent ?? ''; const contentLength = Buffer.byteLength(rawContent, 'utf8'); const hasGeneratedComment = rawContent.includes('