import defu from "defu"; import { createError, eventHandler, proxyRequest, sendRedirect, setHeaders } from "h3"; import { createRouter as createRadixRouter, toRouteMatcher } from "radix3"; import { getQuery, joinURL, withQuery, withoutBase } from "ufo"; import { useRuntimeConfig } from "./config.mjs"; import { isPathInScope, isTargetInScope, resolveRedirectTarget } from "./route-rules-utils.mjs"; const config = useRuntimeConfig(); const _routeRulesMatcher = toRouteMatcher( createRadixRouter({ routes: config.nitro.routeRules }) ); export function createRouteRulesHandler(ctx) { return eventHandler((event) => { const routeRules = getRouteRules(event); if (routeRules.headers) { setHeaders(event, routeRules.headers); } if (routeRules.redirect) { const target = resolveRedirectTarget( event.path, routeRules.redirect.to, routeRules.redirect._redirectStripBase ); if (target === void 0) { throw createError({ statusCode: 400 }); } return sendRedirect(event, target, routeRules.redirect.statusCode); } if (routeRules.proxy) { const target = resolveRuleTarget( event, routeRules.proxy.to, routeRules.proxy._proxyStripBase ); return proxyRequest(event, target, { fetch: ctx.localFetch, ...routeRules.proxy }); } }); } function resolveRuleTarget(event, to, stripBase) { if (!to.endsWith("/**")) { if (event.path.includes("?")) { return withQuery(to, getQuery(event.path)); } return to; } const targetBase = to.slice(0, -3); let targetPath = event.path; if (stripBase) { if (!isPathInScope(event.path.split("?")[0], stripBase)) { throw createError({ statusCode: 400 }); } targetPath = withoutBase(targetPath, stripBase); } else if (targetPath.startsWith("//")) { targetPath = targetPath.replace(/^\/+/, "/"); } const target = joinURL(targetBase, targetPath); if (!isTargetInScope(target, targetBase)) { throw createError({ statusCode: 400 }); } return target; } export function getRouteRules(event) { event.context._nitro = event.context._nitro || {}; if (!event.context._nitro.routeRules) { event.context._nitro.routeRules = getRouteRulesForPath( withoutBase(event.path.split("?")[0], useRuntimeConfig().app.baseURL) ); } return event.context._nitro.routeRules; } export function getRouteRulesForPath(path) { return defu({}, ..._routeRulesMatcher.matchAll(path).reverse()); }