import { NextRequest, NextResponse } from "next/server"; // Cookie name mirrors internal/api/server.go's sessionCookieName constant. const SESSION_COOKIE = "archivdms_session"; // Routes that must stay reachable without a session cookie. // // "/public" covers BOTH the human-facing external share page // (/public/share/[token]) AND the /public/api/* proxy that next.config.ts // rewrites to the backend's unauthenticated /public/* endpoints. Without this // exemption the share link would bounce to /login and be useless. const PUBLIC_PATHS = ["/login", "/public"]; /** * Fast UX gate: only checks whether the session cookie is present, not * whether the JWT inside it is still valid. Real validation happens on * every backend API call (internal/api/server.go authMiddleware) — this * middleware exists purely to avoid a flash of protected UI before a * redirect to /login when there's obviously no session at all. */ export function middleware(request: NextRequest) { const { pathname } = request.nextUrl; const isPublic = PUBLIC_PATHS.some( (p) => pathname === p || pathname.startsWith(`${p}/`) ); const hasSession = Boolean(request.cookies.get(SESSION_COOKIE)?.value); if (!hasSession && !isPublic) { const loginUrl = new URL("/login", request.url); loginUrl.searchParams.set("next", pathname); return NextResponse.redirect(loginUrl); } if (hasSession && pathname === "/login") { return NextResponse.redirect(new URL("/documents", request.url)); } return NextResponse.next(); } export const config = { matcher: [ // Only guard page navigations. /api/* is excluded on purpose: those // requests are rewritten straight through to the Go backend (see // next.config.ts), which does its own full JWT validation via // authMiddleware — gating them here as well would just break // unauthenticated calls like POST /api/auth/login. "/((?!api|_next/static|_next/image|favicon.ico|.*\\.(?:png|jpg|jpeg|svg|webp|ico)$).*)", ], };