/ src / app / api / rollup / route.ts
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  }