From f4f48f7293a0ab59bcd0ab07214dba45a1c4654c Mon Sep 17 00:00:00 2001 From: AI Directory Platform Date: Wed, 9 Sep 2026 09:24:28 +0000 Subject: [PATCH] =?UTF-8?q?fix:=20=E8=AF=84=E8=AE=BA=E6=B5=81=E7=A8=8B?= =?UTF-8?q?=E4=B8=A4=E4=B8=AA=E6=96=AD=E7=82=B9=EF=BC=88mock=20=E7=99=BB?= =?UTF-8?q?=E5=BD=95=20cookie=20=E9=80=8F=E4=BC=A0=20+=20=E8=AF=84?= =?UTF-8?q?=E8=AE=BA=E5=90=8E=20ISR=20=E7=BC=93=E5=AD=98=E5=A4=B1=E6=95=88?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - mock-social 500:route handler 里 headers() 不可写,session cookie 无法落浏览器。 改为 auth.api.signInEmail({ asResponse: true }) 并把 Set-Cookie 显式透传给响应。 浏览器验证:mock 登录后有 session cookie,get-session 返回演示用户。 - 评论提交后详情页仍显示旧评分(ISR 1h):submitReview/deleteMyReview/setReviewStatus 增加 revalidatePath(tools/[slug] + rankings + 首页)。 浏览器验证:提交评论后 'Based on N reviews' 即时 2→3。 - 全链路回归:登录→写评论(星级/正文/优缺点)→提交出现→聚合更新→Helpful 计数 全部 PASS --- packages/core/src/features/reviews/actions.ts | 5 +++ .../src/pages/api/auth/mock-social/route.ts | 42 +++++++++++++------ 2 files changed, 35 insertions(+), 12 deletions(-) diff --git a/packages/core/src/features/reviews/actions.ts b/packages/core/src/features/reviews/actions.ts index 63b7e17..9b7c480 100644 --- a/packages/core/src/features/reviews/actions.ts +++ b/packages/core/src/features/reviews/actions.ts @@ -134,7 +134,10 @@ export async function submitReview( metadata: { rating: data.rating }, }); + // 失效详情页 ISR 缓存(评分/评论数即时反映)+ 榜单页 revalidatePath("/[locale]/tools/[slug]", "page"); + revalidatePath("/[locale]/rankings", "page"); + revalidatePath("/[locale]", "page"); return { success: true, reviewId }; } @@ -314,6 +317,7 @@ export async function deleteMyReview(toolId: string) { .where(and(eq(review.userId, user.id), eq(review.toolId, toolId))); await recalcToolRating(toolId); revalidatePath("/[locale]/tools/[slug]", "page"); + revalidatePath("/[locale]/rankings", "page"); return { success: true as const }; } @@ -335,6 +339,7 @@ export async function setReviewStatus(reviewId: string, status: ReviewStatus) { if (row) { await recalcToolRating(row.toolId); revalidatePath("/[locale]/tools/[slug]", "page"); + revalidatePath("/[locale]/rankings", "page"); } return { success: true }; } diff --git a/packages/core/src/pages/api/auth/mock-social/route.ts b/packages/core/src/pages/api/auth/mock-social/route.ts index cca8f0e..9f4eb40 100644 --- a/packages/core/src/pages/api/auth/mock-social/route.ts +++ b/packages/core/src/pages/api/auth/mock-social/route.ts @@ -1,20 +1,19 @@ import { NextRequest, NextResponse } from "next/server"; -import { headers } from "next/headers"; import { auth } from "@/lib/auth"; import { db } from "@/lib/db"; import { user, account } from "@/lib/db/schema"; import { eq } from "drizzle-orm"; +import { nanoid } from "nanoid"; import { hashPassword } from "better-auth/crypto"; /** * POST /api/auth/mock-social { provider: "google" | "github" } * 说明:开发/演示环境的第三方登录 Mock。 - * 未配置真实 OAuth 凭据时,前端显示第三方按钮,点击走此端点: - * 直接创建(或复用)对应 provider 的演示用户并建立 session —— 一键登录。 - * 生产环境配置了 AUTH_GOOGLE_ID / AUTH_GITHUB_ID 后此端点自动禁用(403)。 + * - 未配置真实 OAuth 凭据时启用;生产配置 AUTH_GOOGLE_ID/AUTH_GITHUB_ID 后自动 403。 + * - 复用/创建对应 provider 的演示用户,然后通过 better-auth 的 signInEmail 建立 session, + * 并把 Set-Cookie 头显式透传给浏览器(route handler 里 headers() 不可写,必须走 response)。 */ export async function POST(req: NextRequest) { - // 双保险:配置了真实凭据时拒绝 mock if (process.env.AUTH_GOOGLE_ID || process.env.AUTH_GITHUB_ID) { return NextResponse.json({ error: "MOCK_DISABLED" }, { status: 403 }); } @@ -27,7 +26,6 @@ export async function POST(req: NextRequest) { const email = `${provider}-user@demo.dev`; const name = provider === "google" ? "Google Demo User" : "GitHub Demo User"; - // 复用或创建演示用户 let [u] = await db.select().from(user).where(eq(user.email, email)).limit(1); if (!u) { [u] = await db @@ -42,11 +40,10 @@ export async function POST(req: NextRequest) { .returning(); } - // 确保 credential 密码存在(一键登录用) await db .insert(account) .values({ - id: `acc_mock_${provider}`, + id: nanoid(), accountId: u.id, providerId: "credential", userId: u.id, @@ -54,11 +51,32 @@ export async function POST(req: NextRequest) { }) .onConflictDoNothing(); - // 建立 session - const session = await auth.api.signInEmail({ + // 用一个模拟请求头调用 signInEmail;返回的 set-cookie 需要透传 + const requestHeaders = new Headers(req.headers); + requestHeaders.set("cookie", req.headers.get("cookie") || ""); + + const res = await auth.api.signInEmail({ body: { email, password: "password123" }, - headers: await headers(), + headers: requestHeaders, + asResponse: true, }); - return NextResponse.json({ ok: true, user: session?.user ?? null }); + if (!res.ok) { + const text = await res.text(); + return NextResponse.json( + { error: "MOCK_SIGNIN_FAILED", detail: text.slice(0, 200) }, + { status: 500 } + ); + } + + const body = await res.json(); + const out = NextResponse.json({ ok: true, user: body.user ?? null }); + + // 透传全部 Set-Cookie(session token) + const setCookies = res.headers.getSetCookie?.() ?? []; + for (const c of setCookies) { + out.headers.append("set-cookie", c); + } + + return out; }