const DEFAULT_PUBLIC_APP_URL = 'https://sc.jiansun.vip' const LEGACY_PUBLIC_APP_ORIGINS = ['https://3d.yydd.ai'] function isPrivateOrLocalHost(hostname: string): boolean { const lower = hostname.toLowerCase() if (lower === 'localhost' || lower === '127.0.0.1' || lower === '::1') { return true } return /^192\.168\.|^10\.|^172\.(1[6-9]|2[0-9]|3[01])\./.test(lower) } function normalizeOrigin(value?: string | null): string | null { if (!value) return null const trimmed = value.trim() if (!trimmed) return null try { const parsed = new URL(trimmed.match(/^https?:\/\//i) ? trimmed : `https://${trimmed}`) if (isPrivateOrLocalHost(parsed.hostname)) { return null } return parsed.origin } catch { return null } } export function getPublicAppOrigin(): string { const candidates = [ process.env.NEXT_PUBLIC_APP_PUBLIC_URL, process.env.APP_PUBLIC_URL, process.env.NEXTAUTH_URL, DEFAULT_PUBLIC_APP_URL, ] for (const candidate of candidates) { const normalized = normalizeOrigin(candidate) if (normalized) { return normalized } } return DEFAULT_PUBLIC_APP_URL } export function buildPublicMaterialShareUrl(materialId: string): string { return `${getPublicAppOrigin()}/share/${encodeURIComponent(materialId)}` } export function getAllowedPublicAppOrigins(): string[] { return Array.from(new Set([getPublicAppOrigin(), ...LEGACY_PUBLIC_APP_ORIGINS])) }