import { clerkMiddleware, createRouteMatcher } from "@clerk/nextjs/server"; import { validateEnv } from "./lib/env"; import log from "./lib/logger"; // Validate environment variables on server startup try { validateEnv(); log.info("Environment validation passed"); } catch (error) { log.error("Environment validation failed", error); // Re-throw to prevent server from starting with invalid config throw error; } // Define routes that should be publicly accessible (no auth required) const isPublicRoute = createRouteMatcher([ "/sign-in(.*)", "/sign-up(.*)", "/api/webhooks(.*)", "/api/health(.*)", ]); // Define API routes that need auth but should be handled in the route itself // This prevents auth.protect() from blocking before the route handler runs const isApiRoute = createRouteMatcher(["/api/(.*)"]); export default clerkMiddleware(async (auth, req) => { // Log for debugging const authHeader = req.headers.get("authorization"); if (authHeader) { log.debug("Authorization header present", { preview: authHeader.substring(0, 20) + "...", }); } // Don't protect public routes if (isPublicRoute(req)) { log.debug("Public route, skipping auth"); return; } // For API routes, let the route handler check auth // This allows API routes to handle both web sessions and mobile Bearer tokens if (isApiRoute(req)) { log.debug("API route, auth will be checked in handler"); return; } // For all other routes (web pages), enforce authentication log.debug("Protected route, requiring auth"); await auth.protect(); }); export const config = { matcher: [ // Skip Next.js internals and all static files, unless found in search params "/((?!_next|[^?]*\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)", // Always run for API routes "/(api|trpc)(.*)", ], };