// / // * Next.js 16 Proxy(原 `middleware.ts`) // * // * 行为(鉴权路由统一在此处理,业务层组件不再做 auth-driven 跳转): // * - 已登录(NextAuth `next-auth.session-token` cookie 存在)访问 `/splash` 或 `/auth` // * → 308 重定向到 `/chat` // * - 未登录(cookie 缺失)访问 `/chat` 或 `/sidebar` // * → 308 重定向到 `/splash`(首界面) // * - 其他情况透传(`NextResponse.next()`) // * // * 重要约束: // * - 不做自定义 cookie 持久化:统一用 NextAuth 内置 `next-auth.session-token` / // * `__Secure-next-auth.session-token`(v5 默认 httpOnly + secure)作信号。 // * - 真正的鉴权门在 Client 侧 `useSession()`(next-auth/react),用于 UI 状态。 // * - 路由跳转(唯一鉴权跳转点)由本 proxy 集中处理。 // * - 副作用:邮箱登录用户(不走 NextAuth)不会被本 proxy 识别为已登录。 // * 邮箱登录在后续轮次若要恢复 proxy 行为,需引入 NextAuth EmailProvider 或独立 // * email-session 体系。 // * // * Next 16 重要变更(参见 `node_modules/next/dist/docs/01-app/03-api-reference/03-file-conventions/proxy.md`): // * - 文件从 `middleware.ts` 重命名为 `proxy.ts`;`middleware` 仍可用但已 deprecated。 // * - 默认 Node.js runtime;不支持 `runtime` 配置(设置会抛错)。 // * - 函数导出名建议为 `proxy`(可默认导出)。 // * // * 用 `src/` 时 proxy 必须放在 `src/` 内(参见 `src-folder.md`)。 // */ // import { NextResponse } from "next/server"; // import type { NextRequest } from "next/server"; // import { Logger } from "@/utils/logger"; // import { // AUTH_ONLY_ROUTES, // PROTECTED_ROUTES, // ROUTES, // } from "@/router/routes"; // / NextAuth 内置 session cookie 名(v5 默认 httpOnly) */ // const SESSION_COOKIE_NAMES = [ // "next-auth.session-token", // "__Secure-next-auth.session-token", // ]; // / proxy 入口日志(Node.js runtime 跑,pino 兼容)—— 排查 / 监控路由用 */ // const log = new Logger("Proxy"); // function isAuthOnlyRoute(pathname: string): boolean { // return (AUTH_ONLY_ROUTES as readonly string[]).includes(pathname); // } // function isProtectedRoute(pathname: string): boolean { // return (PROTECTED_ROUTES as readonly string[]).includes(pathname); // } // / // * Proxy 入口 // */ // export function proxy(request: NextRequest) { // const { pathname } = request.nextUrl; // // 检查 NextAuth session cookie 存在性 // const hasSession = SESSION_COOKIE_NAMES.some( // (name) => Boolean(request.cookies.get(name)?.value), // ); // // 已登录访问未登录专属页 → /chat // if (hasSession && isAuthOnlyRoute(pathname)) { // log.info( // { pathname, target: ROUTES.chat, reason: "logged-in → auth-only" }, // "[proxy] redirect", // ); // const url = request.nextUrl.clone(); // url.pathname = ROUTES.chat; // return NextResponse.redirect(url, 308); // } // // 未登录访问登录态专属页 → /splash(首界面) // if (!hasSession && isProtectedRoute(pathname)) { // log.info( // { pathname, target: ROUTES.splash, reason: "not-logged-in → protected" }, // "[proxy] redirect", // ); // const url = request.nextUrl.clone(); // url.pathname = ROUTES.splash; // return NextResponse.redirect(url, 308); // } // return NextResponse.next(); // } // / // * 匹配器:排除 API、Next 静态资源、图标与常见静态文件扩展名。 // * 不排除 `_next/data`,因为 proxy 文档明确说明"即使在排除列表中 proxy 仍会跑" // * (安全兜底)。 // */ // export const config = { // matcher: [ // "/((?!api|_next/static|_next/image|_next/data|favicon.ico|icons|.*\\.(?:png|jpg|jpeg|gif|svg|webp|ico|css|js|woff2?|ttf|otf)$).*)", // ], // };