// Server-side session resolution for Next.js App Router server components // and route handlers. Reads the yominoki_session cookie, verifies it, and // maps the AT Protocol DID to an internal users.id. import { cache } from "react" import { cookies } from "next/headers" import { COOKIE_NAME, verify, type AppSession } from "@yominoki/atproto" import { getUserIdByDid, upsertUserByDid } from "@yominoki/db/queries/users" import { env } from "./env" import { getOps } from "./db" export const getSession = cache(async (): Promise => { if (env.devUserDid) return { did: env.devUserDid } const jar = await cookies() const jwt = jar.get(COOKIE_NAME)?.value if (!jwt) return null // jose throws on malformed/tampered/expired tokens — treat any // verification failure as no-session so a bad cookie doesn't 500 // the server component (DoS vector for unauthenticated requests). try { return await verify(jwt, env.appCookieKey) } catch { return null } }) export async function resolveUserId(): Promise { const session = await getSession() if (!session) return null // In the dev bypass, upsert the users row on first lookup so a fresh // database doesn't gate every page after the cookie is faked. Real OAuth // sign-ins go through the callback route which upserts there. if (env.devUserDid && session.did === env.devUserDid) { return upsertUserByDid(getOps(), session.did) } return getUserIdByDid(getOps(), session.did) }