Files
HiveGrid-Wireframes/03 Quellen und Referenzen/hivegrid-cloud/server/react-router-manifest-dispatch.ts
T

79 lines
3.2 KiB
TypeScript

import type { WebRuntimeSurface } from "@hivegrid/config";
export type ReactRouterManifestDispatchDecision = { type: "dispatch"; request: Request } | { type: "reject"; status: 404 };
const portalInternalNamespace = "/__portal";
const portalTenantHeader = "x-hivegrid-portal-tenant";
const portalCustomHostHeader = "x-hivegrid-portal-custom-host";
const portalTenantSlugPattern = /^[a-z0-9][a-z0-9-]{1,62}$/;
const operationalPaths = new Set(["/healthz", "/readyz", "/healthcheck", "/api/metrics"]);
const portalFrameworkPaths = new Set(["/__manifest"]);
/**
* Crosses the final trust boundary between host routing and the selected
* React Router manifest. Portal requests must arrive in the reserved internal
* namespace with a matching trusted tenant header. The namespace is removed
* before route matching so SSR and browser hydration both see the public URL.
*/
export function prepareReactRouterManifestRequest(request: Request, runtimeSurface: WebRuntimeSurface): ReactRouterManifestDispatchDecision {
const url = new URL(request.url);
if (runtimeSurface === "core" || runtimeSurface === "admin") {
if (isPortalInternalPath(url.pathname) || request.headers.has(portalTenantHeader)) {
return { type: "reject", status: 404 };
}
return { type: "dispatch", request };
}
if (operationalPaths.has(url.pathname)) {
if (request.headers.has(portalTenantHeader)) {
return { type: "reject", status: 404 };
}
return { type: "dispatch", request };
}
if (portalFrameworkPaths.has(url.pathname)) {
return { type: "dispatch", request };
}
if (!url.pathname.startsWith(`${portalInternalNamespace}/`)) {
return { type: "reject", status: 404 };
}
const publicPathname = url.pathname.slice(portalInternalNamespace.length);
const rawTenantSegment = publicPathname.slice(1).split("/", 1)[0] ?? "";
const tenantSlug = rawTenantSegment.replace(/\.data$/, "");
const trustedTenantSlug = request.headers.get(portalTenantHeader);
if (!trustedTenantSlug || trustedTenantSlug !== tenantSlug || !portalTenantSlugPattern.test(tenantSlug)) {
return { type: "reject", status: 404 };
}
const customHostPathname = request.headers.has(portalCustomHostHeader) ? stripTrustedTenantFromCustomHostPath(publicPathname, tenantSlug) : null;
if (request.headers.has(portalCustomHostHeader) && !customHostPathname) {
return { type: "reject", status: 404 };
}
url.pathname = customHostPathname ?? publicPathname;
const init: RequestInit & { duplex?: "half" } = {
method: request.method,
headers: request.headers,
signal: request.signal,
};
if (request.method !== "GET" && request.method !== "HEAD") {
init.body = request.body;
init.duplex = "half";
}
return { type: "dispatch", request: new Request(url, init) };
}
function stripTrustedTenantFromCustomHostPath(pathname: string, tenantSlug: string): string | null {
const tenantPrefix = `/${tenantSlug}`;
if (pathname === tenantPrefix) return "/";
if (pathname === `${tenantPrefix}.data`) return "/.data";
if (pathname.startsWith(`${tenantPrefix}/`)) return pathname.slice(tenantPrefix.length);
return null;
}
function isPortalInternalPath(pathname: string) {
return pathname === portalInternalNamespace || pathname.startsWith(`${portalInternalNamespace}/`);
}