diff --git a/src/router/index.ts b/src/router/index.ts index 4e5e10f9..a700b2fb 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -1,14 +1,14 @@ -/** - * Router 公共导出 - * - * 集中管理: - * - 路由常量(ROUTES、ROUTE_BUILDERS、AUTH_ONLY_ROUTES、PUBLIC_ROUTES、ALL_STATIC_ROUTES) - * - Next.js 16 Proxy(CDN 端鉴权重定向) - * - * 业务层导入示例: - * ```ts - * import { ROUTES, AUTH_ONLY_ROUTES, type Route } from "@/router"; - * ``` - */ -export * from "./routes"; -export { proxy, config as proxyConfig } from "./proxy"; +// /** +// * Router 公共导出 +// * +// * 集中管理: +// * - 路由常量(ROUTES、ROUTE_BUILDERS、AUTH_ONLY_ROUTES、PUBLIC_ROUTES、ALL_STATIC_ROUTES) +// * - Next.js 16 Proxy(CDN 端鉴权重定向) +// * +// * 业务层导入示例: +// * ```ts +// * import { ROUTES, AUTH_ONLY_ROUTES, type Route } from "@/router"; +// * ``` +// */ +// export * from "./routes"; +// export { proxy, config as proxyConfig } from "./proxy"; diff --git a/src/router/proxy.ts b/src/router/proxy.ts index 07d46c3d..a319b450 100644 --- a/src/router/proxy.ts +++ b/src/router/proxy.ts @@ -1,101 +1,101 @@ -/** - * 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`)。 - */ +// /** +// * 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 { NextResponse } from "next/server"; +// import type { NextRequest } from "next/server"; -import { Logger } from "@/utils/logger"; +// import { Logger } from "@/utils/logger"; -import { - AUTH_ONLY_ROUTES, - PROTECTED_ROUTES, - ROUTES, -} from "@/router/routes"; +// 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", -]; +// /** 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"); +// /** 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 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); -} +// function isProtectedRoute(pathname: string): boolean { +// return (PROTECTED_ROUTES as readonly string[]).includes(pathname); +// } -/** - * Proxy 入口 - */ -export function proxy(request: NextRequest) { - const { pathname } = request.nextUrl; +// /** +// * 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), - ); +// // 检查 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); - } +// // 已登录访问未登录专属页 → /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); - } +// // 未登录访问登录态专属页 → /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(); -} +// 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)$).*)", - ], -}; +// /** +// * 匹配器:排除 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)$).*)", +// ], +// }; diff --git a/src/router/routes.ts b/src/router/routes.ts index 9eb605d2..f1f3ad93 100644 --- a/src/router/routes.ts +++ b/src/router/routes.ts @@ -8,6 +8,10 @@ * - `as const` 让每个值都是字符串字面量类型,可用于 `PageProps<'/literal'>`。 * - 不导出 Client-only 模块(`use-auth-gate` 走独立路径导入),保证 Server bundle 不被污染。 * - 动态深链通过 `ROUTE_BUILDERS` 函数生成,避免手拼字符串。 + * + * 注意:proxy 路由跳转逻辑(2026-06-15 迁出),但本文件的**类型化常量**仍在 + * 被 9 个组件(auth-screen / chat-header / quota-dialog / DeepLinkPersist / + * error / not-found / page / sidebar-screen / splash-screen)使用 —— **不能**整体注释。 */ /** 静态路由字面量 */