← back to Govarbitrage
src/lib/current-user.ts
38 lines
import { cookies } from "next/headers";
import { SESSION_COOKIE, verifySession, type SessionPayload } from "./session";
/** Read + verify the session for the current request (server components / routes). */
export async function getCurrentUser(): Promise<SessionPayload | null> {
const store = await cookies();
const token = store.get(SESSION_COOKIE)?.value;
if (!token) return null;
return verifySession(token);
}
export type Role = "ADMIN" | "ANALYST" | "VIEWER";
const RANK: Record<Role, number> = { VIEWER: 0, ANALYST: 1, ADMIN: 2 };
/** True if the user's role meets or exceeds the required role. */
export function hasRole(user: SessionPayload | null, required: Role): boolean {
if (!user) return false;
return (RANK[(user.role as Role) ?? "VIEWER"] ?? 0) >= RANK[required];
}
/**
* Resolve the current request's subscription tier from the DB (not the JWT — a
* subscription can change mid-session). Unauthenticated → FREE. ADMIN → PREMIUM
* (Steve always sees everything). Imported lazily to keep this edge-safe module light.
*/
export async function getCurrentTier(): Promise<import("@prisma/client").Tier> {
const user = await getCurrentUser();
if (!user) return "FREE";
if (user.role === "ADMIN") return "PREMIUM";
// The synthetic fleet-SSO session is Steve arriving via the fleet login — an
// internal operator, so show full data (money-math). It is still only ANALYST,
// so the ADMIN-gated credential surface stays closed.
if (user.sub === "fleet-sso") return "PREMIUM";
const { prisma } = await import("./db");
const row = await prisma.user.findUnique({ where: { id: user.sub }, select: { tier: true } });
return row?.tier ?? "FREE";
}