import { cookies, headers } from "next/headers" import { redirect } from "next/navigation" import { env } from "@/lib/env" import { isAdmin, isStaff } from "@/lib/authz" import { auth } from "@/lib/auth" type ServerSession = { session: { id: string expiresAt: number } user: { id: string name: string email: string role: string tenantId: string | null avatarUrl: string | null machinePersona: string | null } } async function serializeCookies() { const store = await cookies() return store.getAll().map((cookie) => `${cookie.name}=${cookie.value}`).join("; ") } async function buildRequest() { const cookieHeader = await serializeCookies() const headerList = await headers() const userAgent = headerList.get("user-agent") ?? "" const ip = headerList.get("x-forwarded-for") || headerList.get("x-real-ip") || headerList.get("cf-connecting-ip") || headerList.get("x-client-ip") || undefined // Evitar fallback para localhost em produção: tenta BETTER_AUTH_URL, // depois NEXT_PUBLIC_APP_URL e, por fim, o host do próprio request. const forwardedProto = headerList.get("x-forwarded-proto") const forwardedHost = headerList.get("x-forwarded-host") ?? headerList.get("host") const requestOrigin = forwardedProto && forwardedHost ? `${forwardedProto}://${forwardedHost}` : undefined const baseUrl = env.BETTER_AUTH_URL || env.NEXT_PUBLIC_APP_URL || requestOrigin || "http://localhost:3000" return new Request(baseUrl, { headers: { cookie: cookieHeader, "user-agent": userAgent, ...(ip ? { "x-forwarded-for": ip } : {}), }, }) } export async function getServerSession(): Promise { try { // Dev-only bypass to simplify local dashboard access when auth is misconfigured. if (process.env.NODE_ENV !== "production" && process.env.DEV_BYPASS_AUTH === "1") { return { session: { id: "dev-session", expiresAt: Date.now() + 1000 * 60 * 60, }, user: { id: "dev-user", name: "Dev Admin", email: "admin@sistema.dev", role: "admin", tenantId: "tenant-atlas", avatarUrl: null, machinePersona: null, }, } } const request = await buildRequest() const session = await auth.api.getSession({ headers: request.headers, request, }) if (!session) return null const expiresValue = session.session.expiresAt const expiresAt = expiresValue instanceof Date ? expiresValue.getTime() : typeof expiresValue === "number" ? expiresValue : expiresValue ? new Date(expiresValue).getTime() : Date.now() return { session: { id: session.session.id, expiresAt, }, user: { id: session.user.id, name: session.user.name, email: session.user.email, role: (session.user as { role?: string }).role ?? "agent", tenantId: (session.user as { tenantId?: string | null }).tenantId ?? null, avatarUrl: (session.user as { avatarUrl?: string | null }).avatarUrl ?? null, machinePersona: (session.user as { machinePersona?: string | null }).machinePersona ?? null, }, } } catch (error) { console.error("Failed to read Better Auth session", error) return null } } export async function assertAuthenticatedSession() { const session = await getServerSession() return session?.user ? session : null } export async function requireAuthenticatedSession() { const session = await assertAuthenticatedSession() if (!session) { redirect("/login") } return session } export async function assertStaffSession() { const session = await assertAuthenticatedSession() if (!session) return null if (!isStaff(session.user.role)) { return null } return session } export async function requireStaffSession() { const session = await assertStaffSession() if (!session) { redirect("/portal") } return session } export async function assertAdminSession() { const session = await assertAuthenticatedSession() if (!session) return null if (!isAdmin(session.user.role)) { return null } return session } export async function requireAdminSession() { const session = await assertAdminSession() if (!session) { redirect("/dashboard") } return session }