import { cookies } from 'next/headers'; import { NextRequest, NextResponse } from 'next/server'; function getSafeRedirectUrl(targetPath: string, request: NextRequest): URL { const forwardedHost = request.headers.get('x-forwarded-host')?.split(',')[0].trim() ?? request.headers.get('host') ?? 'motorsignal.app'; const forwardedProto = request.headers.get('x-forwarded-proto')?.split(',')[0].trim() ?? (process.env.NODE_ENV === 'production' ? 'https' : 'http'); return new URL(targetPath, `${forwardedProto}://${forwardedHost}`); } export async function GET(request: NextRequest) { const cookieStore = await cookies(); const riderToken = cookieStore.get('motorsignal_access_token')?.value; if (!riderToken) { return NextResponse.redirect(getSafeRedirectUrl('/login?returnTo=/admin', request)); } const baseUrl = process.env.MOTORSIGNAL_API_BASE_URL ?? 'https://api.motorsignal.app'; try { const upstream = await fetch(`${baseUrl}/api/v1/ops/session/bootstrap`, { method: 'POST', headers: { authorization: `Bearer ${riderToken}`, accept: 'application/json', }, cache: 'no-store', }); if (upstream.ok) { const data = (await upstream.json()) as { ops_token?: string }; const opsToken = data.ops_token; if (opsToken) { const redirectUrl = getSafeRedirectUrl('/admin', request); const response = NextResponse.redirect(redirectUrl); const opsCookieOptions = { httpOnly: true, secure: true, sameSite: 'lax' as const, path: '/', maxAge: 60 * 60 * 8, }; response.cookies.set('__Host-motorsignal_ops', opsToken, opsCookieOptions); response.cookies.set('motorsignal_ops', opsToken, { ...opsCookieOptions, secure: process.env.NODE_ENV === 'production', }); return response; } } if (upstream.status === 403) { return NextResponse.redirect(getSafeRedirectUrl('/admin?error=forbidden', request)); } return NextResponse.redirect(getSafeRedirectUrl('/login?returnTo=/admin', request)); } catch { return NextResponse.redirect(getSafeRedirectUrl('/login?returnTo=/admin', request)); } } export async function POST(request: NextRequest) { const cookieStore = await cookies(); const riderToken = cookieStore.get('motorsignal_access_token')?.value; if (!riderToken) { return NextResponse.json({ detail: 'Rider authentication required.' }, { status: 401 }); } const baseUrl = process.env.MOTORSIGNAL_API_BASE_URL ?? 'https://api.motorsignal.app'; try { const upstream = await fetch(`${baseUrl}/api/v1/ops/session/bootstrap`, { method: 'POST', headers: { authorization: `Bearer ${riderToken}`, accept: 'application/json', }, cache: 'no-store', }); if (!upstream.ok) { const err = await upstream.json().catch(() => ({})); return NextResponse.json(err, { status: upstream.status }); } const data = (await upstream.json()) as { ops_token?: string }; const opsToken = data.ops_token; if (!opsToken) { return NextResponse.json({ detail: 'Failed to issue operations token.' }, { status: 500 }); } const response = NextResponse.json({ success: true }, { status: 200 }); const opsCookieOptions = { httpOnly: true, secure: true, sameSite: 'lax' as const, path: '/', maxAge: 60 * 60 * 8, }; response.cookies.set('__Host-motorsignal_ops', opsToken, opsCookieOptions); response.cookies.set('motorsignal_ops', opsToken, { ...opsCookieOptions, secure: process.env.NODE_ENV === 'production', }); return response; } catch { return NextResponse.json({ detail: 'Operations bootstrap unavailable.' }, { status: 503 }); } }