import { NextResponse, type NextRequest } from "next/server"; import { hasSessionCookie } from "@/lib/auth/cookie"; // Only whether the session cookie is there, no database: a request without it // goes to /login. Whether the session is valid, whose it is and whether it may // open Admin, the page checks (lib/auth/session.ts). /login does not bounce a // signed-in visitor from here: with a stale cookie, /login -> / -> /login // would loop; the login page checks the real session. export function proxy(request: NextRequest) { const { pathname } = request.nextUrl; // /aderisci: how to join; /gruppo: the group's public page, for people // who have no account yet. if ( pathname === "/login" || pathname.startsWith("/login/") || pathname === "/aderisci" || pathname === "/gruppo" || hasSessionCookie(request.cookies) ) { return NextResponse.next(); } // The home without a session: /gruppo, which sends on to /login when the // group has no public page (the proxy never reads the database). return NextResponse.redirect(new URL(pathname === "/" ? "/gruppo" : "/login", request.url)); } // api/auth is Better Auth (its own allowlist), api/stripe/webhook is called by // Stripe and authenticated by its signature, api/health is a public liveness // check that returns no data, api/instance-stats answers only a request signed // with INSTANCE_STATS_SECRET (404 otherwise), api/unsubscribe acts only on a // token signed with AUTH_SECRET (one-click unsubscribe from a notification email). The uploaded logo // (/brand/logo-*.png|jpg|webp) passes by its extension. mail/ holds the email // logo (lib/email/layout.ts), which a mail client fetches with no session. The web app manifest is fetched by the browser without // cookies: behind the redirect the app could not be installed. export const config = { matcher: [ "/((?!api/auth|api/stripe/webhook|api/health$|api/instance-stats$|api/unsubscribe$|mail/|manifest.webmanifest$|_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)", ], };