import * as fs from "node:fs"; import path from "node:path"; import { appendForwardSlash, prependForwardSlash } from "@astrojs/internal-helpers/path"; import colors from "piccolore"; import { notFoundTemplate, subpathNotUsedTemplate } from "../template/4xx.js"; import { writeHtmlResponse } from "./response.js"; function resolveDevRoot(base, site) { const effectiveBase = base || "/"; const siteUrl = site ? new URL(effectiveBase, site) : void 0; const devRootURL = new URL(effectiveBase, "http://localhost"); const devRoot = siteUrl ? siteUrl.pathname : devRootURL.pathname; const devRootReplacement = devRoot.endsWith("/") ? "/" : ""; return { devRoot, devRootReplacement }; } function evaluateBaseRewrite(url, pathname, acceptHeader, devRoot, devRootReplacement) { if (pathname.startsWith(devRoot)) { let newUrl = url.replace(devRoot, devRootReplacement); if (!newUrl.startsWith("/")) newUrl = prependForwardSlash(newUrl); return { action: "rewrite", newUrl }; } if (pathname === "/" || pathname === "/index.html") { return { action: "not-found-subpath", pathname, devRoot }; } if (acceptHeader?.includes("text/html")) { return { action: "not-found", pathname }; } return { action: "check-public" }; } function baseMiddleware(settings, logger) { const { config } = settings; const { devRoot, devRootReplacement } = resolveDevRoot(config.base, config.site); return function devBaseMiddleware(req, res, next) { const url = req.url; let pathname; try { pathname = decodeURI(new URL(url, "http://localhost").pathname); } catch (e) { return next(e); } const decision = evaluateBaseRewrite( url, pathname, req.headers.accept, devRoot, devRootReplacement ); switch (decision.action) { case "rewrite": req.url = decision.newUrl; return next(); case "not-found-subpath": { const html = subpathNotUsedTemplate(decision.devRoot, decision.pathname); return writeHtmlResponse(res, 404, html); } case "not-found": { const html = notFoundTemplate(decision.pathname); return writeHtmlResponse(res, 404, html); } case "check-public": { const publicPath = new URL("." + req.url, config.publicDir); fs.stat(publicPath, (_err, stats) => { if (stats) { const publicDir = appendForwardSlash( path.posix.relative(config.root.pathname, config.publicDir.pathname) ); const devRootURL = new URL(devRoot, "http://localhost"); const expectedLocation = new URL(devRootURL.pathname + url, devRootURL).pathname; logger.error( "router", `Request URLs for ${colors.bold( publicDir )} assets must also include your base. "${expectedLocation}" expected, but received "${url}".` ); const html = subpathNotUsedTemplate(devRoot, pathname); return writeHtmlResponse(res, 404, html); } else { next(); } }); } } }; } export { baseMiddleware, evaluateBaseRewrite, resolveDevRoot };