Files
HiveGrid-Wireframes/hivegrid-cloud/server/host-routing-runtime.ts
T

86 lines
3.0 KiB
TypeScript

import { getCanonicalHostRedirectUrl, getHostAwareInternalUrlPath, getHostRoutingContextFromRequest } from "../apps/web/app/utils/app/HostRouting.server";
export type HostRoutingRuntimeDecision =
| { type: "redirect"; status: 308; location: string }
| { type: "reject"; status: 404 }
| { type: "dispatch"; target: "api" | "web"; request: Request };
const internalWebApiProxyHeader = "x-toolctrl-internal-web-api-proxy";
export function getHostRoutingRuntimeDecision(request: Request): HostRoutingRuntimeDecision {
const context = getHostRoutingContextFromRequest(request);
if (isInternalWebApiProxyRequest(request, context)) {
const requestUrl = new URL(request.url);
const rewrittenRequest = rewriteRequestUrl(request, `${requestUrl.pathname}${requestUrl.search}${requestUrl.hash}`);
return {
type: "dispatch",
target: "web",
request: rewrittenRequest,
};
}
if (isRemovedLegacyRoute(request, context)) {
return {
type: "reject",
status: 404,
};
}
const canonicalRedirectUrl = getCanonicalHostRedirectUrl(request);
if (canonicalRedirectUrl) {
return {
type: "redirect",
status: 308,
location: canonicalRedirectUrl,
};
}
const rewrittenRequest = rewriteRequestUrl(request, getRuntimeInternalUrlPath(request, context));
return {
type: "dispatch",
target: context === "api" ? "api" : "web",
request: rewrittenRequest,
};
}
function isInternalWebApiProxyRequest(request: Request, context: ReturnType<typeof getHostRoutingContextFromRequest>) {
if (context !== "app" || request.headers.get(internalWebApiProxyHeader) !== "1") {
return false;
}
const pathname = new URL(request.url).pathname;
return pathname === "/internal/api/usage" || pathname === "/internal/api/stripe.webhooks" || pathname.startsWith("/internal/api/workflows/");
}
function isRemovedLegacyRoute(request: Request, context: ReturnType<typeof getHostRoutingContextFromRequest>) {
const pathname = new URL(request.url).pathname.replace(/\/+$/g, "") || "/";
const isLegacyApiV1Route = pathname === "/api/v1" || pathname.startsWith("/api/v1/");
const isAdminApiSectionRoute = context === "admin" && (pathname === "/api" || pathname.startsWith("/api/")) && !isLegacyApiV1Route;
return (
pathname === "/app" ||
pathname.startsWith("/app/") ||
pathname === "/admin" ||
pathname.startsWith("/admin/") ||
(!isAdminApiSectionRoute && (pathname === "/api" || (pathname.startsWith("/api/") && !isLegacyApiV1Route)))
);
}
function getRuntimeInternalUrlPath(request: Request, context: ReturnType<typeof getHostRoutingContextFromRequest>) {
if (context === "app") {
const url = new URL(request.url);
return `${url.pathname}${url.search}${url.hash}`;
}
return getHostAwareInternalUrlPath(request);
}
function rewriteRequestUrl(request: Request, internalUrlPath: string) {
const url = new URL(request.url);
url.pathname = "/";
url.search = "";
url.hash = "";
const rewrittenUrl = new URL(internalUrlPath, url);
return new Request(rewrittenUrl, request);
}