import { listBranches } from "@/lib/storage"; import { getSession } from "@/lib/auth/session"; import { filterBranchesForSession } from "@/lib/auth/permissions"; import { withErrorHandling, json, unauthorized, ApiError, } from "@/lib/api/errors"; /** * Next.js Route Handler caching configuration (RHL-006): * * We force this route to execute dynamically on every request. * * Reasons: * - NAS contents can change at any time (new scans). * - Auth/RBAC-protected responses must not be cached/shared across users. * - We rely on a small storage-layer TTL micro-cache instead of Next route caching. */ export const dynamic = "force-dynamic"; /** * GET /api/branches * * Returns the list of branches (e.g. ["NL01", "NL02", ...]) based on the * directory names under NAS_ROOT_PATH. * * RBAC: * - 401 if no session * - branch role: only returns its own branch * - admin/dev: returns all branches * * Happy-path response must remain unchanged: * { "branches": ["NL01", ...] } */ export const GET = withErrorHandling( async function GET() { const session = await getSession(); if (!session) { throw unauthorized("AUTH_UNAUTHENTICATED", "Unauthorized"); } try { const branches = await listBranches(); const visibleBranches = filterBranchesForSession(session, branches); return json({ branches: visibleBranches }, 200); } catch (err) { // Treat any storage read failures as internal server errors. // We do NOT expose filesystem error messages to the client. throw new ApiError({ status: 500, code: "FS_STORAGE_ERROR", message: "Internal server error", cause: err, }); } }, { logPrefix: "[api/branches]" } );