// ABOUTME: Authentication middleware wrapper for protected API routes. // ABOUTME: Provides withAuth HOF that validates session and injects user context. import { cookies } from "next/headers"; import type { NextRequest } from "next/server"; import { NextResponse } from "next/server"; import type { User } from "@/types"; import { logger } from "./logger"; import { createPocketBaseClient, getCurrentUser, isAuthenticated, loadAuthFromCookies, } from "./pocketbase"; /** * Route handler function type that receives the authenticated user. */ export type AuthenticatedHandler = ( request: NextRequest, user: User, context?: { params?: T }, ) => Promise; /** * Higher-order function that wraps an API route handler with authentication. * Loads auth from cookies, validates the session, and passes the user to the handler. * * @param handler - The route handler that requires authentication * @returns A wrapped handler that checks auth before calling the original handler * * @example * ```ts * export const GET = withAuth(async (request, user) => { * return NextResponse.json({ email: user.email }); * }); * ``` */ export function withAuth( handler: AuthenticatedHandler, ): (request: NextRequest, context?: { params?: T }) => Promise { return async ( request: NextRequest, context?: { params?: T }, ): Promise => { try { // Create a fresh PocketBase client for this request const pb = createPocketBaseClient(); // Load auth state from cookies const cookieStore = await cookies(); loadAuthFromCookies(pb, cookieStore); // Check if the user is authenticated if (!isAuthenticated(pb)) { logger.warn({ reason: "not_authenticated" }, "Auth failure"); return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); } // Get the current user const user = getCurrentUser(pb); if (!user) { logger.warn({ reason: "user_not_found" }, "Auth failure"); return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); } // Call the original handler with the user context return await handler(request, user, context); } catch (error) { logger.error({ err: error }, "Auth middleware error"); return NextResponse.json( { error: "Internal server error" }, { status: 500 }, ); } }; }