/** * Platform-Domain SSOT (single source of truth) + derivations. * * ONE registry maps each platform → its canonical production URL (`defaultUrl`, * the load-bearing source) with an optional per-deploy `NEXT_PUBLIC_*_URL` * OVERRIDE. Everything else — the reverse host→platform resolver, the cookie * base-domain set (the cross-subdomain SSO mechanism), www/apex expansion, the * URL→host parse, preview detection — derives from this one table. * * EDGE-SAFE + PURE: no React/clsx/tailwind, no `server-only`, no `node:` * builtins, no `'use client'`. So it is legal in the Edge middleware * (`proxy.ts`), in `'use client'` providers, AND in `server-only` modules * (e.g. cookie-domain-server.ts) simultaneously. The ONLY non-pure export is * `getAllPlatformBaseDomains`, which reads `typeof window`/`process.env` to * preserve byte-identical cookie behavior. */ import type { PlatformName } from './types/platform'; export type PlatformDomainKey = PlatformName | 'openframe-dashboard'; export interface PlatformDomainEntry { /** Platform key (matches `PlatformName`, plus the forward-only `openframe-dashboard`). */ key: PlatformDomainKey; /** Canonical production URL — the LOAD-BEARING source of truth (today's hardcoded fallbacks). */ defaultUrl: string; /** `NEXT_PUBLIC_*_URL` per-deploy OVERRIDE. The `defaultUrl` covers it when unset. */ envVar: string; /** Legacy/secondary hosts that REVERSE-map to this key (no env var exists — NOT canonical). */ aliasHostnames?: string[]; /** Forward-only: no DB row, excluded from the reverse index + cookie set (e.g. the product-CTA dashboard). */ pseudo?: boolean; } export declare const PLATFORM_DOMAINS: readonly PlatformDomainEntry[]; /** The registry entry for a key (undefined for an unknown key). */ export declare function byKey(key: string): PlatformDomainEntry | undefined; /** * Ensure a URL string carries a scheme. Per-deploy `NEXT_PUBLIC_*_URL` overrides are * stored SCHEME-LESS (bare host, e.g. `www.openmsp.ai` / `hub.openframe.ai`) — the * canonical convention in the Vercel shared-env store. This normalizes them to a full * `https://` URL so every downstream consumer (`hostOf`/`new URL`, hrefs, the cookie * base-domain derivation, CSP) receives a parseable URL. Full-URL inputs (the registry * `defaultUrl`s, any scheme'd override) pass through unchanged. * * EXPORTED as the single owner of the scheme-normalization rule (next.config.mjs keeps a * byte-identical local copy ONLY because Next evaluates its config outside the TS module * graph and cannot import this — see the comment there). * * Handles a (theoretical) protocol-relative `//host` too: strips the leading slashes so it * doesn't become `https:////host` (empty-host → hostOf null → silent platform drop). */ export declare function ensureScheme(url: string): string; /** * Canonical production URL for a platform: env override wins, else the `defaultUrl`. * NEVER throws / undefined — the default guarantees a host (this is what keeps the * cookie base-domains, the reverse map, and CSP intact even with every override unset). * The result ALWAYS carries a scheme (`ensureScheme`), so the scheme-less env overrides * resolve to valid URLs. Unknown-key fallback preserves cn.ts's flamingo.run default. */ export declare function getPlatformProductionUrl(platform: string): string; /** Canonical URL→host parser: `.hostname` (PORT-STRIPPED, lowercased), null on parse failure. */ export declare function hostOf(value: string | null | undefined): string | null; /** Expand a host into its `www.`/apex pair. 3+-label and single-label hosts return `[host]`. */ export declare function expandWwwApex(host: string): string[]; /** Registrable base domain (`parts.slice(-2).join('.')`), dotless; undefined for <2-label. */ export declare function toRegistrableBaseDomain(host: string): string | undefined; /** An entry's alias hosts (single-owner reader). */ export declare function aliasHostsOf(key: string): string[]; /** * Reverse resolver: hostname → platform key (first-wins over registry order, non-pseudo only). * Guarantees openframe.ai / www.openframe.ai / hub.openframe.ai → openframe in every env. * Replaces the hub `PLATFORM_DOMAIN_MAP`. */ export declare function getPlatformByHostname(hostname: string): PlatformDomainKey | null; /** Env-form preview predicate (Vercel `VERCEL_ENV`). */ export declare function isPreviewEnv(): boolean; /** Host-form preview predicate (a `*.vercel.app` host). Dot-bounded suffix so a * malicious `foo.vercel.app.evil.com` is NOT treated as preview. */ export declare function isPreviewHost(hostname: string): boolean; /** * ALL unique cookie base domains (the cross-subdomain SSO mechanism). * * NON-PURE (the sole such export): reads `typeof window` + `process.env` to * preserve byte-identical cookie behavior. Keeps the original three branches: * 1. localhost / private IP → [] (host-only cookies) * 2. Vercel preview (env OR host) → ['.vercel.app','vercel.app'] * 3. production → for each non-pseudo platform, registrable base of its resolved * host, emitted as both `.base` and bare `base`. * * Because `getPlatformProductionUrl` always yields a host (override OR default), * `.flamingo.so` / `.flamingo.run` / `.openmsp.ai` / `.tmcg.miami` / `.openframe.ai` * are ALWAYS present → cross-hub SSO is byte-identical to today. */ export declare function getAllPlatformBaseDomains(): string[]; /** * Hosts that must NOT receive a `Domain=` cookie → the caller returns undefined (host-only): * localhost, loopback/private IPs, and any `*.vercel.app`. `vercel.app` is on the Public Suffix * List, so browsers SILENTLY drop `Set-Cookie: Domain=.vercel.app` — which broke the PKCE verifier * + session cookies on preview deploys. Host-only is sufficient there (the same preview host * round-trips the OAuth chain); production hosts (`.flamingo.so`/`.openmsp.ai`/…) fall through. */ export declare function isNonCookieableHost(hostname: string): boolean; /** * Match a hostname against a set of registrable base domains → the dotted cookie `Domain` * (`.flamingo.so`), or undefined when none contains the host. Accepts bases with or without a * leading dot and always returns the dotted form. Single owner for the match loop both resolvers ran. */ export declare function matchCookieDomain(hostname: string, baseDomains: string[]): string | undefined; //# sourceMappingURL=platform-domains.d.ts.map