import path from "node:path"; import { HttpError } from "./errors"; /** The portfolio checkout. In Docker it is bind-mounted at /repo; for local * `npm run dev` it defaults to the sibling ../portfolio folder. */ export const REPO_DIR = path.resolve(/*turbopackIgnore: true*/ process.env.REPO_DIR ?? path.join(/*turbopackIgnore: true*/ process.cwd(), "..", "portfolio") ); /** Repo-relative paths the manager owns. Publishing commits only these. */ export const POSTS_REL = "data/blog-posts.json"; export const IMG_REL = "public/img/blog"; export const POSTS_FILE = path.join(REPO_DIR, POSTS_REL); export const PUBLIC_DIR = path.join(REPO_DIR, "public"); export const IMG_ROOT = path.join(REPO_DIR, IMG_REL); /** path.resolve(root, ...segments), refusing anything that escapes root. */ export function safeJoin(root: string, ...segments: string[]): string { const resolved = path.resolve(/*turbopackIgnore: true*/ root, ...segments); const rel = path.relative(root, resolved); if (rel.startsWith("..") || path.isAbsolute(rel)) { throw new HttpError(400, "path escapes its root"); } return resolved; }