/** * CORS Configuration Helper * * Single source of truth for all CORS origin checks. * Merges origins from: * 1. APP_URL environment variable (always included) * 2. Core config (api.cors.allowedOrigins) * 3. Theme extensions (api.cors.additionalOrigins) * 4. Runtime env var (CORS_ADDITIONAL_ORIGINS) */ import type { ApplicationConfig } from '../config/config-types'; /** * Supported environments for CORS configuration * - development: Local development * - production: Production deployment * - staging: Pre-production testing * - qa: QA testing environment */ export type CorsEnvironment = 'development' | 'production' | 'staging' | 'qa'; /** * Normalize an origin URL by removing trailing slashes and converting to lowercase * * Browsers send Origin headers without trailing slashes (e.g., "http://localhost:8081") * but environment variables like NEXT_PUBLIC_APP_URL may include them. * This ensures consistent comparison for CORS validation. * * Also normalizes scheme and host to lowercase per RFC 3986. * * @param origin - Origin URL that may have trailing slash * @returns Normalized origin URL, or empty string if input is invalid * * @example * ```ts * normalizeOrigin('http://localhost:3000/') // 'http://localhost:3000' * normalizeOrigin('http://localhost:3000') // 'http://localhost:3000' * normalizeOrigin('https://app.com///') // 'https://app.com' * normalizeOrigin('HTTP://LOCALHOST:3000') // 'http://localhost:3000' * normalizeOrigin('') // '' * normalizeOrigin(null as any) // '' * ``` */ export declare function normalizeOrigin(origin: string): string; /** * Normalize environment string to a valid CorsEnvironment * Maps staging/qa to use development origins, unknown environments default to development * * @param env - Raw environment string * @returns Normalized environment key for config lookup */ export declare function normalizeCorsEnvironment(env: string): 'development' | 'production'; /** * Get merged CORS origins from config + theme + env vars * Single source of truth for all CORS origin checks * * @param config - Application configuration (merged core + theme) * @param env - Environment ('development', 'production', 'staging', 'qa') * @returns Array of allowed origins (deduplicated) * * @example * ```ts * import { getCorsOrigins } from '@/lib/utils/cors' * import { APP_CONFIG_MERGED } from '@/lib/config' * * const allowedOrigins = getCorsOrigins(APP_CONFIG_MERGED) * if (allowedOrigins.includes(requestOrigin)) { * // Origin is allowed * } * ``` */ export declare function getCorsOrigins(config: ApplicationConfig, env?: string): string[]; /** * Check whether a request origin is allowed, supporting wildcard-pattern entries * in the allow-list. A `*` in an entry matches exactly ONE host label (no dots), * so `https://*.example.app` matches `https://tenant.example.app` but NOT * `https://a.b.example.app`, `https://example.app`, or look-alikes like * `https://evil-example.app`. Entries without `*` are matched exactly. * * Returns the CONCRETE request origin to echo back (never the pattern or `*`) so * credentialed responses — which cannot use `*` for Access-Control-Allow-Origin — * send a valid concrete origin; returns null when nothing matches. * * Why wildcards: multi-tenant apps serve dynamic per-tenant subdomains that can't * be enumerated in config. A single `https://*.` entry lets a session on * the apex be recognized cross-subdomain without listing every tenant origin. * * @param requestOrigin - The (already normalized) incoming Origin to validate. * @param allowedOrigins - The allow-list from getCorsOrigins() (may contain patterns). * @returns The origin to echo (the requestOrigin on match), or null on no match. */ export declare function isOriginAllowed(requestOrigin: string, allowedOrigins: string[]): string | null; //# sourceMappingURL=cors.d.ts.map