fix #12: remove all auth.api.getSession() calls

- middleware.ts: cookie-presence check only (Edge Runtime can't use DB),
  skip auth for API routes entirely
- compare/route.ts: manual session token parsing + db.select() queries
- user/comparisons/route.ts: same manual auth bypass
- user/stats/route.ts: same manual auth bypass

Root cause: Drizzle 0.45.2 queryWithCache bug triggers when
auth.api.getSession() is called from non-route-handler contexts.
Bypass entirely with direct db.select() on sessions/users tables.
This commit is contained in:
Christopher Mayor
2026-04-27 12:31:36 -07:00
parent fe5153c4e5
commit 371755c241
3 changed files with 77 additions and 20 deletions

View File

@@ -1,22 +1,46 @@
import { db } from "@/lib/db";
import { comparisons, comparisonItems } from "@/lib/db/schema";
import { eq, desc, sql, inArray } from "drizzle-orm";
import { auth } from "@/lib/auth";
import { comparisons, comparisonItems, sessions, users } from "@/lib/db/schema";
import { eq, desc, sql, inArray, and, gt } from "drizzle-orm";
import { headers } from "next/headers";
export async function GET(request: Request) {
const session = await auth.api.getSession({ headers: await headers() });
if (!session?.user) {
// Bypass auth.api.getSession() — Drizzle queryWithCache bug (#12)
const hdrs = await headers();
const cookieHeader = hdrs.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: "Unauthorized" }, { 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: "Unauthorized" }, { 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: "Unauthorized" }, { status: 401 });
}
const userId = userRows[0].id;
const { searchParams } = new URL(request.url);
const page = Math.max(1, Number(searchParams.get("page")) || 1);
const limit = Math.min(100, Math.max(1, Number(searchParams.get("limit")) || 20));
const offset = (page - 1) * limit;
const where = eq(comparisons.userId, session.user.id);
const where = eq(comparisons.userId, userId);
const [result, countResult] = await Promise.all([
db

View File

@@ -1,23 +1,47 @@
import { db } from "@/lib/db";
import { comparisons } from "@/lib/db/schema";
import { eq, sql } from "drizzle-orm";
import { auth } from "@/lib/auth";
import { comparisons, sessions, users } from "@/lib/db/schema";
import { eq, sql, and, gt } from "drizzle-orm";
import { headers } from "next/headers";
export async function GET() {
const session = await auth.api.getSession({ headers: await headers() });
if (!session?.user) {
// Bypass auth.api.getSession() — Drizzle queryWithCache bug (#12)
const hdrs = await headers();
const cookieHeader = hdrs.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: "Unauthorized" }, { 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: "Unauthorized" }, { 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: "Unauthorized" }, { status: 401 });
}
const userId = userRows[0].id;
const result = await db
.select({
totalComparisons: sql<number>`count(*)`,
totalViews: sql<number>`coalesce(sum(${comparisons.viewCount}), 0)`,
})
.from(comparisons)
.where(eq(comparisons.userId, session.user.id));
.where(eq(comparisons.userId, userId));
return Response.json(result[0]);
}