// Host → tenant slug parser for the portal middleware. // // In dev we serve at .localhost:3000 (e.g. acme.localhost:3000). In // prod we serve at .breakpilot.com. Backstage lives at the apex — // no subdomain — and resolves to a fixed `__backstage__` slug. export type HostMatch = | { kind: "tenant"; slug: string } | { kind: "backstage" } | { kind: "apex" } | { kind: "unknown" }; // Longest-first so `stage.breakpilot.com` is matched before `breakpilot.com`. const APEX_HOSTS = ["stage.breakpilot.com", "breakpilot.com", "localhost"]; const APEX_SET = new Set(APEX_HOSTS); export function parseHost(host: string | null | undefined): HostMatch { if (!host) return { kind: "unknown" }; const hostNoPort = host.split(":")[0].toLowerCase(); if (APEX_SET.has(hostNoPort)) return { kind: "apex" }; // Strip the known apex suffix to extract the subdomain. for (const apex of APEX_HOSTS) { const suffix = `.${apex}`; if (hostNoPort.endsWith(suffix)) { const sub = hostNoPort.slice(0, -suffix.length); if (!sub) return { kind: "apex" }; // Backstage is reserved. if (sub === "backstage") return { kind: "backstage" }; // Slugs are [a-z0-9-]{2,40} per the tenant-registry schema check. if (/^[a-z0-9-]{2,40}$/.test(sub)) { return { kind: "tenant", slug: sub }; } return { kind: "unknown" }; } } return { kind: "unknown" }; }