ThreadCount Community edition
Uniform stock management for healthcare linen rooms. Licensed under the GNU AGPL v3.
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
import type { Metadata } from "next";
|
||||
import { headers } from "next/headers";
|
||||
import { notFound } from "next/navigation";
|
||||
|
||||
/* The operations console lives under /ops and is served only on ops.threadcount.tech.
|
||||
*
|
||||
* proxy.ts already refuses /ops on every other hostname, but the proxy is not the only guard: a
|
||||
* matcher change can silently remove its coverage, so the host is checked here again, from the
|
||||
* request headers, before anything under this layout renders. Same comparison as the proxy —
|
||||
* exact, lower-cased, port-stripped, never `includes`.
|
||||
*
|
||||
* Every page under here is dynamic. ISR is not keyed by host, so a cached ops page could be
|
||||
* served on threadcount.tech; `force-dynamic` on the layout keeps the whole subtree out of the
|
||||
* prerender cache. */
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: { default: "ThreadCount ops", template: "%s — ThreadCount ops" },
|
||||
robots: { index: false, follow: false },
|
||||
};
|
||||
|
||||
const OPS_HOST = "ops.threadcount.tech";
|
||||
|
||||
export default async function OpsLayout({ children }: { children: React.ReactNode }) {
|
||||
const h = await headers();
|
||||
const host = (h.get("x-forwarded-host") ?? h.get("host") ?? "").split(":")[0].toLowerCase();
|
||||
if (host !== OPS_HOST) notFound();
|
||||
return <div className="tc-ops" role="main">{children}</div>;
|
||||
}
|
||||
Reference in New Issue
Block a user