diff --git a/client/src/components/Terminal.tsx b/client/src/components/Terminal.tsx index 9ea1059..eda7d1f 100644 --- a/client/src/components/Terminal.tsx +++ b/client/src/components/Terminal.tsx @@ -83,9 +83,19 @@ export function Terminal({ sessionId, color, nodeId }: TerminalProps) { xtermRef.current = term; fitAddonRef.current = fitAddon; - // Connect WebSocket with small delay to allow session to be ready + // Connect WebSocket with small delay to allow session to be ready. + // Always mirror the page's protocol (ws for http, wss for https) so the + // browser never blocks the connection under its mixed-content policy. + // In dev, Vite's proxy can't relay Bun's WebSocket upgrade response, so connect + // directly to the backend's host/port; the default dev page is served over plain + // HTTP, yielding ws://. (Serving the dev page over HTTPS requires the backend to + // be reachable over TLS, since the browser forbids ws:// from an https:// origin.) + // In production (single-server) the backend serves the client itself, so reuse + // the current host. const protocol = window.location.protocol === "https:" ? "wss:" : "ws:"; - const wsUrl = `${protocol}//${window.location.host}/ws?sessionId=${sessionId}`; + const wsUrl = import.meta.env.DEV + ? `${protocol}//${window.location.hostname}:${import.meta.env.VITE_BACKEND_PORT ?? 6968}/ws?sessionId=${sessionId}` + : `${protocol}//${window.location.host}/ws?sessionId=${sessionId}`; let ws: WebSocket | null = null; let isFirstMessage = true; diff --git a/client/vite.config.ts b/client/vite.config.ts index 7bd0bd4..d09d6a7 100644 --- a/client/vite.config.ts +++ b/client/vite.config.ts @@ -10,10 +10,9 @@ export default defineConfig({ target: "http://localhost:6968", changeOrigin: true, }, - "/ws": { - target: "ws://localhost:6968", - ws: true, - }, + // NOTE: /ws is intentionally not proxied. Vite's http-proxy cannot relay + // Bun.serve's WebSocket upgrade response, so the client connects directly + // to the backend in dev (see Terminal.tsx). }, }, build: {