import { NextRequest, NextResponse } from "next/server"; import { extractSubdomain, isReservedSubdomain } from "@micprotocol/shared-types"; const publicRoutes = [ "/", "/about", "/pricing", "/privacy", "/terms", "/cookies", "/data-protection", "/security", "/acceptable-use", "/dpa", "/network", "/join-network", "/tickets", ]; function isPublicRoute(pathname: string): boolean { // Check exact matches if (publicRoutes.includes(pathname)) return true; // Check prefix matches for auth and api endpoints const prefixes = [ "/in", "/login", "/register", "/sign-in", "/sign-up", "/forgot-password", "/reset-password", "/verify-email", "/api", "/tickets", ]; if (prefixes.some((p) => pathname.startsWith(p))) return true; return false; } export function middleware(request: NextRequest) { const { pathname } = request.nextUrl; const host = request.headers.get("host") || ""; const subdomain = extractSubdomain(host); const requestHeaders = new Headers(request.headers); if (subdomain && !isReservedSubdomain(subdomain)) { requestHeaders.set("x-subdomain", subdomain); } if (isPublicRoute(pathname)) { return NextResponse.next({ request: { headers: requestHeaders, }, }); } // Check for session cookie (Better Auth sets "better-auth.session_token") const sessionCookie = request.cookies.get("better-auth.session_token")?.value || request.cookies.get("__Secure-better-auth.session_token")?.value; if (!sessionCookie) { const loginUrl = new URL("/login", request.url); loginUrl.searchParams.set("callbackUrl", pathname); return NextResponse.redirect(loginUrl); } return NextResponse.next({ request: { headers: requestHeaders, }, }); } export const config = { matcher: [ "/((?!_next|[^?]*\\.(?:html?|css|js(?!on)|jpg|jpeg|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)", "/(api|trpc)(.*)", ], };