import { listFiles } from "@/lib/storage"; import { getSession } from "@/lib/auth/session"; import { canAccessBranch } from "@/lib/auth/permissions"; import { withErrorHandling, json, badRequest, unauthorized, forbidden, } from "@/lib/api/errors"; import { mapStorageReadError } from "@/lib/api/storageErrors"; /** * 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/files?branch=&year=&month=&day= * * Happy-path response must remain unchanged: * { "branch":"NL01", "year":"2024", "month":"10", "day":"23", "files":[...] } */ export const GET = withErrorHandling( async function GET(request) { const session = await getSession(); if (!session) { throw unauthorized("AUTH_UNAUTHENTICATED", "Unauthorized"); } const { searchParams } = new URL(request.url); // Query params are required for this endpoint. const branch = searchParams.get("branch"); const year = searchParams.get("year"); const month = searchParams.get("month"); const day = searchParams.get("day"); const missing = []; if (!branch) missing.push("branch"); if (!year) missing.push("year"); if (!month) missing.push("month"); if (!day) missing.push("day"); if (missing.length > 0) { throw badRequest( "VALIDATION_MISSING_QUERY", "Missing required query parameter(s)", { params: missing } ); } if (!canAccessBranch(session, branch)) { throw forbidden("AUTH_FORBIDDEN_BRANCH", "Forbidden"); } try { const files = await listFiles(branch, year, month, day); return json({ branch, year, month, day, files }, 200); } catch (err) { throw await mapStorageReadError(err, { details: { branch, year, month, day }, }); } }, { logPrefix: "[api/files]" } );