From fe5153c4e55f0e0edd436f22833bbfbac8950f2a Mon Sep 17 00:00:00 2001 From: Christopher Mayor Date: Mon, 27 Apr 2026 12:27:25 -0700 Subject: [PATCH] fix #12: bypass auth.api.getSession() Drizzle queryWithCache bug Manually parse session token from cookie and query sessions/users tables via db.select() (regular query builder) instead of using auth.api.getSession() which triggers Drizzle 0.45.2 queryWithCache internal error when called from non-route-handler async context. --- src/app/api/compare/route.ts | 40 ++++++++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/src/app/api/compare/route.ts b/src/app/api/compare/route.ts index 75e8dbc..cb995df 100644 --- a/src/app/api/compare/route.ts +++ b/src/app/api/compare/route.ts @@ -2,10 +2,9 @@ import { runResearch } from "@/lib/llm"; import type { ComparisonRequest } from "@/lib/llm/types"; import type { ComparisonData } from "@/lib/types"; import { db } from "@/lib/db"; -import { comparisons, comparisonItems } from "@/lib/db/schema"; -import { eq } from "drizzle-orm"; +import { comparisons, comparisonItems, sessions, users } from "@/lib/db/schema"; +import { eq, and, gt } from "drizzle-orm"; import { createId } from "@paralleldrive/cuid2"; -import { auth } from "@/lib/auth"; function serializeSSE(event: string, data: unknown): string { return `event: ${event}\ndata: ${JSON.stringify(data)}\n\n`; @@ -24,11 +23,40 @@ function slugify(text: string): string { // const ratelimit = new Ratelimit({ redis, limiter: slidingWindow(5, "1m") }) export async function POST(request: Request) { - const session = await auth.api.getSession({ headers: request.headers }); - if (!session?.user) { + // Bypass auth.api.getSession() — Drizzle queryWithCache bug (#12) + // Manually parse session token from cookie and query sessions table directly + const cookieHeader = request.headers.get("cookie") ?? ""; + const tokenMatch = cookieHeader + .split(";") + .find((c) => c.trim().startsWith("better-auth.session_token=")); + const token = tokenMatch?.split("=")?.[1]?.trim(); + + if (!token) { return Response.json({ error: "Authentication required" }, { status: 401 }); } + const sessionRows = await db + .select() + .from(sessions) + .where(and(eq(sessions.token, token), gt(sessions.expiresAt, new Date()))) + .limit(1); + + if (!sessionRows.length) { + return Response.json({ error: "Authentication required" }, { status: 401 }); + } + + const userRows = await db + .select() + .from(users) + .where(eq(users.id, sessionRows[0].userId)) + .limit(1); + + if (!userRows.length) { + return Response.json({ error: "Authentication required" }, { status: 401 }); + } + + const userId = userRows[0].id; + const body: { query?: string; items?: string[]; dimensions?: string[] } = await request.json(); const { query, items, dimensions } = body; @@ -60,7 +88,7 @@ export async function POST(request: Request) { await db.insert(comparisons).values({ id, - userId: session.user.id, + userId: userId, title, query: query ?? title, slug,