fix: proxy absolute same-origin preview requests

Fixes Preview backend calls built from window.location.origin
Routes same-origin fetch, XHR, EventSource, and WebSocket requests through the preview proxy
Keeps local full-stack apps working inside the Preview panel
This commit is contained in:
Bohdan Triapitsyn
2026-05-15 14:44:35 +03:00
parent 72216f4276
commit b79a40adce
@@ -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) => {