diff --git a/src/ui/lib/database-transfer-url.ts b/src/ui/lib/database-transfer-url.ts index c7394bd30..db19cac1d 100644 --- a/src/ui/lib/database-transfer-url.ts +++ b/src/ui/lib/database-transfer-url.ts @@ -20,7 +20,9 @@ export function getDatabaseTransferUrl( return `${serverUrl.replace(/\/$/, "")}/database/${operation}`; } - const development = location.port === "5173"; + // Vite moves off 5173 when another dev server holds it. + const development = + process.env.NODE_ENV === "development" || location.port === "5173"; if (development) { return `http://localhost:30001/database/${operation}`; diff --git a/src/ui/lib/plugin-transport.ts b/src/ui/lib/plugin-transport.ts index 2df0aea2c..501bd4b64 100644 --- a/src/ui/lib/plugin-transport.ts +++ b/src/ui/lib/plugin-transport.ts @@ -175,11 +175,10 @@ export async function pluginWsUrl( const protocols = websocketAuthProtocols(token); // Dev without a configured API host goes through Vite's proxy, which is - // reached on the page's own origin rather than the backend port. + // reached on the page's own origin rather than the backend port. Vite moves + // to another port when 5173 is taken, so the port says nothing here. const devProxy = - process.env.NODE_ENV === "development" && - !import.meta.env.VITE_API_HOST && - (window.location.port === "3000" || window.location.port === "5173"); + process.env.NODE_ENV === "development" && !import.meta.env.VITE_API_HOST; const wsProtocol = window.location.protocol === "https:" ? "wss" : "ws"; diff --git a/src/ui/tests/lib/plugin-transport.test.ts b/src/ui/tests/lib/plugin-transport.test.ts index 15f665d3c..86c31281e 100644 --- a/src/ui/tests/lib/plugin-transport.test.ts +++ b/src/ui/tests/lib/plugin-transport.test.ts @@ -111,6 +111,21 @@ describe("pluginWsUrl in the browser", () => { expect(target?.protocols).toEqual(["termix.jwt.ticket-1"]); }); + it("goes through the Vite proxy in dev on any port", async () => { + vi.stubEnv("NODE_ENV", "development"); + try { + fetchMock.mockResolvedValueOnce( + new Response(JSON.stringify({ ticket: "ticket-1" })), + ); + const target = await pluginWsUrl("ssh-terminal", "/terminal"); + expect(target?.url).toBe( + `ws://${window.location.host}/__termix_api/30001/plugin-ws/ssh-terminal/terminal`, + ); + } finally { + vi.unstubAllEnvs(); + } + }); + it("falls back to the cookie alone for a guest", async () => { fetchMock.mockResolvedValueOnce(new Response("{}", { status: 401 }));