diff --git a/packages/web/server/lib/preview/proxy-runtime.js b/packages/web/server/lib/preview/proxy-runtime.js index 20c1e10b..3046ae45 100644 --- a/packages/web/server/lib/preview/proxy-runtime.js +++ b/packages/web/server/lib/preview/proxy-runtime.js @@ -484,9 +484,35 @@ const PREVIEW_BRIDGE_SCRIPT = String.raw`(() => { }; const proxiedUrl = (value) => { - if (typeof value !== 'string' || !value.startsWith('/')) return value; - if (!shouldProxyPath(value)) return value; - return proxyBase + value; + if (typeof value !== 'string') return value; + if (value.startsWith('/')) { + if (!shouldProxyPath(value)) return value; + return proxyBase + value; + } + + try { + const parsed = new URL(value, window.location.href); + if (parsed.origin === window.location.origin && shouldProxyPath(parsed.pathname)) { + return proxyBase + parsed.pathname + parsed.search + parsed.hash; + } + } catch {} + + return value; + }; + + const proxiedWebSocketUrl = (value) => { + if (typeof value !== 'string') return value; + try { + const parsed = new URL(value, window.location.href); + const current = new URL(window.location.href); + const sameHost = parsed.host === current.host; + const isWebSocketProtocol = parsed.protocol === 'ws:' || parsed.protocol === 'wss:'; + if (sameHost && isWebSocketProtocol && shouldProxyPath(parsed.pathname)) { + parsed.pathname = proxyBase + parsed.pathname; + return parsed.toString(); + } + } catch {} + return value; }; if (typeof window.fetch === 'function') { @@ -529,6 +555,20 @@ const PREVIEW_BRIDGE_SCRIPT = String.raw`(() => { Object.defineProperty(OpenChamberPreviewEventSource, 'name', { value: 'EventSource' }); window.EventSource = OpenChamberPreviewEventSource; } + + if (typeof window.WebSocket === 'function') { + const NativeWebSocket = window.WebSocket; + function OpenChamberPreviewAppWebSocket(url, protocols) { + const nextUrl = proxiedWebSocketUrl(String(url)); + return arguments.length === 1 + ? new NativeWebSocket(nextUrl) + : new NativeWebSocket(nextUrl, protocols); + } + OpenChamberPreviewAppWebSocket.prototype = NativeWebSocket.prototype; + Object.setPrototypeOf(OpenChamberPreviewAppWebSocket, NativeWebSocket); + Object.defineProperty(OpenChamberPreviewAppWebSocket, 'name', { value: 'WebSocket' }); + window.WebSocket = OpenChamberPreviewAppWebSocket; + } }; const selectorPart = (element) => {