86 lines
2.5 KiB
JavaScript
86 lines
2.5 KiB
JavaScript
|
|
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());
|
||
|
|
}
|