route.ts
1 import { NextRequest, NextResponse } from 'next/server' 2 import { getWebWorkerUrl } from '@/lib/config' 3 import { parseRollupData } from '@/lib/rollup-parser' 4 5 export async function OPTIONS() { 6 return new NextResponse(null, { 7 status: 200, 8 headers: { 9 'Access-Control-Allow-Origin': '*', 10 'Access-Control-Allow-Methods': 'GET, OPTIONS', 11 'Access-Control-Allow-Headers': 'Content-Type', 12 'Access-Control-Max-Age': '86400', 13 }, 14 }) 15 } 16 17 export async function GET(request: NextRequest) { 18 const { searchParams } = new URL(request.url) 19 const query = searchParams.get('query') 20 const namespace = searchParams.get('namespace') 21 const raw = searchParams.get('raw') 22 23 if (raw === 'true') { 24 const response = await fetch(getWebWorkerUrl()) 25 if (!response.ok) { 26 return new Response('Rollup service unavailable', { status: 503 }) 27 } 28 return new Response(await response.text()) 29 } 30 31 const response = await fetch(getWebWorkerUrl(), { 32 method: 'GET', 33 headers: { 34 'User-Agent': 'Mozilla/5.0 (compatible; composable-scan)', 35 }, 36 }) 37 38 if (!response.ok) { 39 return NextResponse.json( 40 { error: 'Failed to fetch rollup worker data' }, 41 { status: response.status } 42 ) 43 } 44 45 if (namespace) { 46 const targetNamespace = parseInt(namespace) 47 if (isNaN(targetNamespace)) { 48 return NextResponse.json( 49 { error: 'Invalid namespace ID' }, 50 { status: 400 } 51 ) 52 } 53 54 const content = await response.text() 55 const rollupData = parseRollupData(content) 56 const rollupInfo = rollupData.find(rollup => rollup.namespace === targetNamespace) 57 58 if (rollupInfo) { 59 return NextResponse.json(rollupInfo, { 60 headers: { 61 'Access-Control-Allow-Origin': '*', 62 'Access-Control-Allow-Methods': 'GET', 63 'Access-Control-Allow-Headers': 'Content-Type', 64 }, 65 }) 66 } 67 68 return NextResponse.json( 69 { error: `No rollup found for namespace ${targetNamespace}` }, 70 { status: 404 } 71 ) 72 } 73 74 if (query) { 75 const searchTerm = decodeURIComponent(query).trim() 76 if (!searchTerm) { 77 return NextResponse.json({ error: 'Search term is required' }, { status: 400 }) 78 } 79 80 const reader = response.body?.getReader() 81 const isNumericSearch = /^\d+$/.test(searchTerm) 82 const searchPattern = isNumericSearch 83 ? new RegExp(`new k\\((${searchTerm}),"([^"]+)",new URL\\("([^"]+)"\\),new URL\\("([^"]+)"\\)\\)`) 84 : new RegExp(`new k\\(([^,]+),"(${searchTerm.toLowerCase()})",new URL\\("([^"]+)"\\),new URL\\("([^"]+)"\\)\\)`, 'i') 85 86 let buffer = '' 87 88 while (reader) { 89 const { done, value } = await reader.read() 90 if (done) break 91 92 buffer += new TextDecoder().decode(value) 93 const match = searchPattern.exec(buffer) 94 95 if (match) { 96 const [, namespace, name, website, scan] = match 97 return NextResponse.json({ 98 namespace: parseInt(namespace), 99 name, 100 website, 101 scan 102 }) 103 } 104 } 105 106 return NextResponse.json({ error: `No rollup found for "${searchTerm}"` }, { status: 404 }) 107 } 108 109 return NextResponse.json({ error: 'Query parameter required' }, { status: 400 }) 110 }