import type { MiddlewareHandler } from "hono"; import { hasAdminRole } from "@/shared/role"; import type { AppBindings, AppContext, AppSession } from "@/worker/hono"; import { HttpError } from "@/worker/http"; // The `assertNotBanned` predicate inside `makeAuth`'s `hooks.before` // fires for every cookie-session route, including this server-side // `auth.api.getSession()` call. A banned user's session lookup throws // `APIError(FORBIDDEN, code=BANNED_USER)`; the APIError → HttpError // conversion in `app.onError` (`worker/index.ts`) reshapes it before // the client sees the response. const loadSession = async (c: AppContext, message = "Sign in first."): Promise => { const session = await c.var.auth.api.getSession({ headers: c.req.raw.headers }); if (!session) { throw new HttpError(401, "unauthorized", message); } c.set("session", session); return session; }; export const requireUser: MiddlewareHandler = async (c, next) => { await loadSession(c); await next(); }; export const requireAdmin: MiddlewareHandler = async (c, next) => { const session = await loadSession(c, "Sign in required."); if (!hasAdminRole(session.user.role)) { throw new HttpError(403, "forbidden", "Admin role required."); } await next(); }; // Handlers that depend on a session pull it directly from `c.var.session` // after `requireUser` / `requireAdmin` has run upstream. The non-null // assertion is safe at the gated callsite; if a future refactor drops // the gate, TypeScript flags the missing variable type. export const requireSession = (c: AppContext): AppSession => { const session = c.var.session; if (!session) { throw new HttpError(401, "unauthorized", "Sign in required."); } return session; };