| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162 |
- 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]" }
- );
|