refactor: move ROUTES from @/lib/routes to @/router/routes
This commit is contained in:
@@ -0,0 +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";
|
||||
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* Next.js 16 Proxy(原 `middleware.ts`)
|
||||
*
|
||||
* 行为:
|
||||
* - 当请求携带 NextAuth `next-auth.session-token` cookie 且命中 `/splash` 或 `/auth`
|
||||
* 时,308 重定向到 `/chat`。
|
||||
* - 其他情况透传(`NextResponse.next()`)。
|
||||
*
|
||||
* 重要约束:
|
||||
* - **不**对 `/chat` 做反向重定向:游客态是合法用户。
|
||||
* - NextAuth 的 session cookie 由 `src/lib/auth/config.ts` 集中管理;本 proxy 仅做
|
||||
* CDN 友好的"乐观"快路径。
|
||||
* - 真正的鉴权门在 Client 侧 `useAuthGate()`(用 `useSession()`)。
|
||||
*
|
||||
* 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 {
|
||||
AUTH_ONLY_ROUTES,
|
||||
ROUTES,
|
||||
type StaticRoute,
|
||||
} from "@/router/routes";
|
||||
|
||||
const SESSION_COOKIE_NAMES = [
|
||||
"next-auth.session-token",
|
||||
"__Secure-next-auth.session-token",
|
||||
];
|
||||
|
||||
function isAuthOnlyRoute(pathname: string): pathname is StaticRoute {
|
||||
return (AUTH_ONLY_ROUTES as readonly string[]).includes(pathname);
|
||||
}
|
||||
|
||||
/**
|
||||
* Proxy 入口
|
||||
*/
|
||||
export function proxy(request: NextRequest) {
|
||||
const { pathname } = request.nextUrl;
|
||||
|
||||
// 检查 NextAuth session cookie 存在性(cookie value 存在即认为已登录)
|
||||
const hasSession = SESSION_COOKIE_NAMES.some(
|
||||
(name) => Boolean(request.cookies.get(name)?.value),
|
||||
);
|
||||
|
||||
if (hasSession && isAuthOnlyRoute(pathname)) {
|
||||
const url = request.nextUrl.clone();
|
||||
url.pathname = ROUTES.chat;
|
||||
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)$).*)",
|
||||
],
|
||||
};
|
||||
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* 类型化路由常量
|
||||
*
|
||||
* 集中管理应用中使用的路由路径,与 Flutter `lib/router/app_router.dart` 的
|
||||
* `AppRoutes` 一一对应。被服务端组件、客户端组件、`src/proxy.ts` 三端共用。
|
||||
*
|
||||
* 关键设计:
|
||||
* - `as const` 让每个值都是字符串字面量类型,可用于 `PageProps<'/literal'>`。
|
||||
* - 不导出 Client-only 模块(`use-auth-gate` 走独立路径导入),保证 Server bundle 不被污染。
|
||||
* - 动态深链通过 `ROUTE_BUILDERS` 函数生成,避免手拼字符串。
|
||||
*/
|
||||
|
||||
/** 静态路由字面量 */
|
||||
export const ROUTES = {
|
||||
root: "/",
|
||||
splash: "/splash",
|
||||
chat: "/chat",
|
||||
auth: "/auth",
|
||||
sidebar: "/sidebar",
|
||||
} as const;
|
||||
|
||||
export type StaticRoute = (typeof ROUTES)[keyof typeof ROUTES];
|
||||
|
||||
/** 动态深链构造器 */
|
||||
export const ROUTE_BUILDERS = {
|
||||
chatDeviceId: (deviceId: string): `/chat/deviceid/${string}` =>
|
||||
`/chat/deviceid/${encodeURIComponent(deviceId)}` as const,
|
||||
} as const;
|
||||
|
||||
/** 仅未登录态可见的路由(命中后已登录用户应跳走) */
|
||||
export const AUTH_ONLY_ROUTES: readonly StaticRoute[] = [
|
||||
ROUTES.splash,
|
||||
ROUTES.auth,
|
||||
] as const;
|
||||
|
||||
/** 公开路由(游客态也允许访问) */
|
||||
export const PUBLIC_ROUTES: readonly StaticRoute[] = [
|
||||
ROUTES.chat,
|
||||
ROUTES.sidebar,
|
||||
] as const;
|
||||
|
||||
/** 所有静态路由,供 `proxy.ts` matcher 与未来 sitemap 使用 */
|
||||
export const ALL_STATIC_ROUTES: readonly StaticRoute[] = [
|
||||
ROUTES.splash,
|
||||
ROUTES.chat,
|
||||
ROUTES.auth,
|
||||
ROUTES.sidebar,
|
||||
] as const;
|
||||
|
||||
/** 联合路由类型,包含静态路由与已知动态路由 */
|
||||
export type Route = StaticRoute | `/chat/deviceid/${string}`;
|
||||
Reference in New Issue
Block a user