// Small helper to resolve the Chat WebSocket URL from env or sensible defaults export function getChatWsUrl() { // Prefer explicit env var const override = (typeof window !== 'undefined' && window.localStorage) ? window.localStorage.getItem('chatWsOverride') : ''; if (override && typeof override === 'string' && override.trim()) { return override.trim(); } const envUrl = import.meta?.env?.VITE_CHAT_WS_URL; if (envUrl && typeof envUrl === 'string' && envUrl.trim()) { return envUrl.trim(); } // Fallback: use current origin host with ws/wss and default port/path if provided by backend const isHttps = typeof window !== 'undefined' && window.location.protocol === 'https:'; const proto = isHttps ? 'wss' : 'ws'; // If a reverse proxy exposes the chat at a path, you can change '/chat' here. const host = typeof window !== 'undefined' ? window.location.hostname : 'localhost'; const port = (typeof window !== 'undefined' && window.location.port) ? `:${window.location.port}` : ''; // On localhost, prefer dedicated chat port 1235 by default // Prefer IPv4 for localhost to avoid browsers resolving to ::1 (IPv6) where the server may not listen if (host === 'localhost' || host === '127.0.0.1' || host === '::1' || host === '[::1]') { return `${proto}://127.0.0.1:1235`; } // Default to same origin (no hardcoded chat port). Adjust via VITE_CHAT_WS_URL if needed. const defaultUrl = `${proto}://${host}${port}`; return defaultUrl; } // Provide a list of candidate WS URLs to try, in order of likelihood. export function getChatWsCandidates() { const override = (typeof window !== 'undefined' && window.localStorage) ? window.localStorage.getItem('chatWsOverride') : ''; if (override && typeof override === 'string' && override.trim()) { return [override.trim()]; } const envUrl = import.meta?.env?.VITE_CHAT_WS_URL; if (envUrl && typeof envUrl === 'string' && envUrl.trim()) { return [envUrl.trim()]; } const isHttps = typeof window !== 'undefined' && window.location.protocol === 'https:'; const proto = isHttps ? 'wss' : 'ws'; const host = typeof window !== 'undefined' ? window.location.hostname : 'localhost'; const port = (typeof window !== 'undefined' && window.location.port) ? `:${window.location.port}` : ''; const candidates = []; // Common local setups: include IPv4 and IPv6 loopback variants (root only) if (host === 'localhost' || host === '127.0.0.1' || host === '::1' || host === '[::1]') { // Prefer IPv6 loopback first when available const localHosts = ['[::1]', '127.0.0.1', 'localhost']; for (const h of localHosts) { const base = `${proto}://${h}:1235`; candidates.push(base); candidates.push(`${base}/`); } } // Same-origin root and common WS paths const sameOriginBases = [`${proto}://${host}${port}`]; // If localhost-ish, also try 127.0.0.1 for same-origin port if ((host === 'localhost' || host === '::1' || host === '[::1]') && port) { sameOriginBases.push(`${proto}://[::1]${port}`); sameOriginBases.push(`${proto}://127.0.0.1${port}`); } for (const base of sameOriginBases) { candidates.push(base); candidates.push(`${base}/`); } return candidates; } // Return optional subprotocols for the WebSocket handshake. export function getChatWsProtocols() { try { const ls = (typeof window !== 'undefined' && window.localStorage) ? window.localStorage.getItem('chatWsProtocols') : ''; if (ls && ls.trim()) { // Accept JSON array or comma-separated if (ls.trim().startsWith('[')) return JSON.parse(ls); return ls.split(',').map(s => s.trim()).filter(Boolean); } } catch (_) {} const env = import.meta?.env?.VITE_CHAT_WS_PROTOCOLS; if (env && typeof env === 'string' && env.trim()) { try { if (env.trim().startsWith('[')) return JSON.parse(env); } catch (_) {} return env.split(',').map(s => s.trim()).filter(Boolean); } // Default to the 'chat' subprotocol so the server can gate connections accordingly return ['chat']; }