export type TenantScopedManual = { sourceDomain?: string siteVisibility?: string[] } function stripProtocolAndPath(input: string) { const firstHost = input.split(",")[0] || "" return firstHost .trim() .toLowerCase() .replace(/^https?:\/\//, "") .replace(/^\/\//, "") .replace(/\/.*$/, "") .replace(/:\d+$/, "") .replace(/\.$/, "") } export function canonicalizeTenantDomain( input: string | null | undefined ): string { if (!input) { return "" } return stripProtocolAndPath(input) } export function tenantDomainVariants(domain: string): string[] { const canonical = canonicalizeTenantDomain(domain) if (!canonical) { return [] } if (canonical.startsWith("www.")) { return [canonical, canonical.replace(/^www\./, "")] } return [canonical, `www.${canonical}`] } export function manualVisibleForTenant( manual: TenantScopedManual, domain: string ): boolean { const variants = new Set(tenantDomainVariants(domain)) if (variants.size === 0) { return false } const sourceDomain = canonicalizeTenantDomain(manual.sourceDomain) if (sourceDomain && variants.has(sourceDomain)) { return true } const visibility = Array.isArray(manual.siteVisibility) ? manual.siteVisibility .map((entry) => canonicalizeTenantDomain(entry)) .filter(Boolean) : [] if (visibility.some((entry) => variants.has(entry))) { return true } return false } export function resolveManualsTenantDomain(params: { requestHost?: string | null envSiteDomain?: string | null envTenantDomain?: string | null }) { return ( canonicalizeTenantDomain(params.requestHost) || canonicalizeTenantDomain(params.envTenantDomain) || canonicalizeTenantDomain(params.envSiteDomain) ) }