export const dynamic = 'force-dynamic' import { NextResponse } from 'next/server' import { Agent } from 'undici' const ORGP_BASE = 'https://transport.orgp.spb.ru' // ORGP TLS chain fails default verification in Node — match curl -k behaviour. const insecureAgent = new Agent({ connect: { rejectUnauthorized: false } }) export async function GET(req: Request) { const { searchParams } = new URL(req.url) const stopId = searchParams.get('stopId') if (!stopId || !/^\d+$/.test(stopId)) { return NextResponse.json({ error: 'stopId required (digits)' }, { status: 400 }) } const body = new URLSearchParams({ sEcho: '1', iColumns: '5', sColumns: 'index,routeNumber,timeToArrive,parkNumber,wheelchair', iDisplayStart: '0', iDisplayLength: '-1', sNames: 'index,routeNumber,timeToArrive,parkNumber,wheelchair', }) try { const upstream = await fetch( `${ORGP_BASE}/Portal/transport/stop/${encodeURIComponent(stopId)}/arriving`, { method: 'POST', headers: { 'X-Requested-With': 'XMLHttpRequest', 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', 'Accept': 'application/json, text/javascript, */*; q=0.01', }, body: body.toString(), cache: 'no-store', // @ts-ignore — undici dispatcher option at runtime dispatcher: insecureAgent, } ) if (!upstream.ok) { return NextResponse.json( { error: `upstream_${upstream.status}`, arrivals: [] }, { status: 502 } ) } const data = await upstream.json() const arrivals = Array.isArray(data?.aaData) ? data.aaData.map((row: any[]) => ({ route: String(row[1] ?? ''), minutes: Number(row[2] ?? 0), park: String(row[3] ?? ''), wheelchair: Boolean(row[4]), })) : [] return NextResponse.json({ stopId, arrivals, fetchedAt: new Date().toISOString(), }) } catch (e: any) { return NextResponse.json( { error: e?.message || 'fetch_failed', arrivals: [] }, { status: 502 } ) } }