import { NextResponse } from 'next/server'; import type { NextRequest } from 'next/server'; import { getAppMode, isPublicRoute } from './lib/mode'; /** * Next.js middleware for route protection * * Features: * - Public routes are always accessible * - Protected routes require authentication * - Demo mode allows access to all routes * - Returns 401 for unauthenticated access to protected routes */ export function middleware(request: NextRequest) { const mode = getAppMode(); const { pathname } = request.nextUrl; // Always allow Next.js error routes (needed for build/prerender) if (pathname === '/404' || pathname === '/500' || pathname === '/_error') { return NextResponse.next(); } // Always allow static assets and API routes (API handles its own auth) // Also allow /media/ routes which are proxied to the API if ( pathname.startsWith('/_next/') || pathname.startsWith('/api/') || pathname.startsWith('/media/') || pathname.match(/\.(svg|png|jpg|jpeg|gif|webp|ico|css|js)$/) ) { return NextResponse.next(); } // Check for authentication cookie const cookies = request.cookies; const hasAuthCookie = cookies.has('gp_session'); // Public routes are always accessible if (isPublicRoute(pathname)) { // Special handling for auth routes - redirect authenticated users away const authRoutes = [ '/auth/login', '/auth/signup', '/auth/forgot-password', '/auth/reset-password', '/auth/iracing', '/auth/iracing/start', '/auth/iracing/callback', ]; if (authRoutes.includes(pathname) && hasAuthCookie) { // User is authenticated and trying to access auth page, redirect to dashboard return NextResponse.redirect(new URL('/dashboard', request.url)); } return NextResponse.next(); } // In demo/alpha mode, allow access if session cookie exists if (mode === 'alpha' && hasAuthCookie) { return NextResponse.next(); } // In demo/alpha mode without auth, redirect to login if (mode === 'alpha' && !hasAuthCookie) { const loginUrl = new URL('/auth/login', request.url); loginUrl.searchParams.set('returnTo', pathname); return NextResponse.redirect(loginUrl); } // In pre-launch mode, only public routes are accessible // Protected routes return 404 (non-disclosure) return new NextResponse(null, { status: 404, statusText: 'Not Found', }); } /** * Configure which routes the middleware should run on * Excludes Next.js internal routes and static assets */ export const config = { matcher: [ /* * Match all request paths except: * - _next/static (static files) * - _next/image (image optimization files) * - favicon.ico (favicon file) * - public folder files */ '/((?!_next/static|_next/image|_next/data|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp|mp4|webm|mov|avi)$).*)', ], };