| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798 |
- /**
- * PDF URL helpers for the Explorer (RHL-023).
- *
- * Why this file exists:
- * - The PDF endpoint is a binary stream and must NOT be called via apiClient (JSON-centric).
- * - We want centralized, testable URL construction for:
- * GET /api/files/:branch/:year/:month/:day/:filename
- *
- * Design goals:
- * - Pure functions (no React, no window, no Next runtime).
- * - Defensive encoding for filename (spaces, #, unicode, etc.).
- * - Minimal, predictable behavior.
- */
- /**
- * Ensure a required string input is present and not empty/whitespace.
- *
- * Note:
- * - We validate emptiness using trim(), but we may return the original value
- * to avoid mutating semantics (important for filenames).
- *
- * @param {string} name
- * @param {unknown} value
- * @returns {string}
- */
- function requireNonEmptyString(name, value) {
- if (typeof value !== "string") {
- throw new Error(`Route segment "${name}" must be a string`);
- }
- if (!value.trim()) {
- throw new Error(`Route segment "${name}" must not be empty`);
- }
- return value;
- }
- /**
- * Encode a standard route segment (branch/year/month/day).
- * - We normalize by trimming.
- *
- * @param {string} name
- * @param {unknown} value
- * @returns {string}
- */
- function encodeSegment(name, value) {
- return encodeURIComponent(requireNonEmptyString(name, value).trim());
- }
- /**
- * Encode a filename segment.
- * - We do NOT trim the filename (filenames are filesystem-exact).
- * - We still validate that it isn't empty/whitespace.
- *
- * @param {unknown} value
- * @returns {string}
- */
- function encodeFilename(value) {
- return encodeURIComponent(requireNonEmptyString("filename", value));
- }
- /**
- * Build the PDF stream URL (inline by default).
- *
- * @param {{
- * branch: string,
- * year: string,
- * month: string,
- * day: string,
- * filename: string
- * }} input
- * @returns {string}
- */
- export function buildPdfUrl({ branch, year, month, day, filename }) {
- const b = encodeSegment("branch", branch);
- const y = encodeSegment("year", year);
- const m = encodeSegment("month", month);
- const d = encodeSegment("day", day);
- const f = encodeFilename(filename);
- return `/api/files/${b}/${y}/${m}/${d}/${f}`;
- }
- /**
- * Build the PDF download URL (forces Content-Disposition: attachment).
- *
- * @param {{
- * branch: string,
- * year: string,
- * month: string,
- * day: string,
- * filename: string
- * }} input
- * @returns {string}
- */
- export function buildPdfDownloadUrl(input) {
- return `${buildPdfUrl(input)}?download=1`;
- }
|