/** * Subdomain-aware URL helpers for rSpace navigation. * * Canonical URL pattern: {space}.rspace.online/{moduleId} * Bare domain pattern: rspace.online/{moduleId} (implicitly demo space) * Fallback (localhost): /{space}/{moduleId} */ const RESERVED_SUBDOMAINS = ["www", "rspace", "create", "new", "start", "auth"]; /** Detect if the current page is on a {space}.rspace.online subdomain */ export function isSubdomain(): boolean { const parts = window.location.host.split(":")[0].split("."); return ( parts.length >= 3 && parts.slice(-2).join(".") === "rspace.online" && !RESERVED_SUBDOMAINS.includes(parts[0]) ); } /** Detect if the current page is on the bare rspace.online domain (no subdomain) */ export function isBareDomain(): boolean { const host = window.location.host.split(":")[0]; return host === "rspace.online" || host === "www.rspace.online"; } /** Get the current space from subdomain or path */ export function getCurrentSpace(): string { if (isSubdomain()) { return window.location.host.split(":")[0].split(".")[0]; } // Bare domain: space is implicit (demo by default, until auto-provision) if (isBareDomain()) { return "demo"; } // Path-based (localhost): /{space}/{moduleId} const pathParts = window.location.pathname.split("/").filter(Boolean); return pathParts[0] || "demo"; } /** Get the current module from the path (works for subdomain, bare domain, and path routing) */ export function getCurrentModule(): string { const parts = window.location.pathname.split("/").filter(Boolean); if (isSubdomain()) { return parts[0] || "rspace"; } // Bare domain: path is /{moduleId} if (isBareDomain()) { return parts[0] || "rspace"; } // Path-based (localhost): /{space}/{moduleId} return parts[1] || "rspace"; } /** * Generate a navigation URL for a given space + module. * * On subdomains: same-space links use /{moduleId}, cross-space links * switch the subdomain to {newSpace}.rspace.online/{moduleId}. * On bare domain (rspace.online): stays on bare domain as /{moduleId} * for default (demo) space, subdomain for explicit spaces. * On localhost: uses /{space}/{moduleId}. */ export function rspaceNavUrl(space: string, moduleId: string): string { const hostParts = window.location.host.split(":")[0].split("."); const onSubdomain = hostParts.length >= 3 && hostParts.slice(-2).join(".") === "rspace.online" && !RESERVED_SUBDOMAINS.includes(hostParts[0]); if (onSubdomain) { // Same space → just change the path if (hostParts[0] === space) { return `/${moduleId}`; } // Different space → switch subdomain const baseDomain = hostParts.slice(-2).join("."); return `${window.location.protocol}//${space}.${baseDomain}/${moduleId}`; } // Bare domain (rspace.online) if (isBareDomain()) { // Default space → stay on bare domain: /{moduleId} if (space === "demo") { return `/${moduleId}`; } // Explicit space → switch to subdomain return `${window.location.protocol}//${space}.rspace.online/${moduleId}`; } // Localhost/dev return `/${space}/${moduleId}`; }