test(web): cover direct terminal websocket URL selection
This commit is contained in:
parent
40055eb0d1
commit
06011be6f0
|
|
@ -21,6 +21,40 @@ interface DirectTerminalProps {
|
|||
height?: string;
|
||||
}
|
||||
|
||||
interface DirectTerminalLocation {
|
||||
protocol: string;
|
||||
hostname: string;
|
||||
host: string;
|
||||
port: string;
|
||||
}
|
||||
|
||||
interface DirectTerminalWsUrlOptions {
|
||||
location: DirectTerminalLocation;
|
||||
sessionId: string;
|
||||
proxyWsPath?: string;
|
||||
directTerminalPort?: string;
|
||||
}
|
||||
|
||||
export function buildDirectTerminalWsUrl({
|
||||
location,
|
||||
sessionId,
|
||||
proxyWsPath,
|
||||
directTerminalPort,
|
||||
}: DirectTerminalWsUrlOptions): string {
|
||||
const protocol = location.protocol === "https:" ? "wss:" : "ws:";
|
||||
if (proxyWsPath) {
|
||||
// Path-based proxy uses host so non-standard ports are preserved.
|
||||
return `${protocol}//${location.host}${proxyWsPath}?session=${encodeURIComponent(sessionId)}`;
|
||||
}
|
||||
|
||||
if (location.port === "" || location.port === "443" || location.port === "80") {
|
||||
return `${protocol}//${location.hostname}/ao-terminal-ws?session=${encodeURIComponent(sessionId)}`;
|
||||
}
|
||||
|
||||
const port = directTerminalPort ?? "14801";
|
||||
return `${protocol}//${location.hostname}:${port}/ws?session=${encodeURIComponent(sessionId)}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Direct xterm.js terminal with native WebSocket connection.
|
||||
* Implements Extended Device Attributes (XDA) handler to enable
|
||||
|
|
@ -186,22 +220,12 @@ export function DirectTerminal({
|
|||
// WebSocket URL (stable across reconnects)
|
||||
// When accessed via reverse proxy (HTTPS on standard port), use path-based
|
||||
// WebSocket endpoint instead of direct port access.
|
||||
const protocol = window.location.protocol === "https:" ? "wss:" : "ws:";
|
||||
const hostname = window.location.hostname;
|
||||
const host = window.location.host;
|
||||
const proxyWsPath = process.env.NEXT_PUBLIC_TERMINAL_WS_PATH;
|
||||
let wsUrl: string;
|
||||
if (proxyWsPath) {
|
||||
// Path-based proxy (e.g. /ao-terminal-ws)
|
||||
wsUrl = `${protocol}//${host}${proxyWsPath}?session=${encodeURIComponent(sessionId)}`;
|
||||
} else if (window.location.port === "" || window.location.port === "443" || window.location.port === "80") {
|
||||
// Behind reverse proxy on standard port — use path-based endpoint
|
||||
wsUrl = `${protocol}//${hostname}/ao-terminal-ws?session=${encodeURIComponent(sessionId)}`;
|
||||
} else {
|
||||
// Direct access (dev mode) — use direct port
|
||||
const port = process.env.NEXT_PUBLIC_DIRECT_TERMINAL_PORT ?? "14801";
|
||||
wsUrl = `${protocol}//${hostname}:${port}/ws?session=${encodeURIComponent(sessionId)}`;
|
||||
}
|
||||
const wsUrl = buildDirectTerminalWsUrl({
|
||||
location: window.location,
|
||||
sessionId,
|
||||
proxyWsPath: process.env.NEXT_PUBLIC_TERMINAL_WS_PATH,
|
||||
directTerminalPort: process.env.NEXT_PUBLIC_DIRECT_TERMINAL_PORT,
|
||||
});
|
||||
|
||||
// ── Preserve selection while terminal receives output ────────
|
||||
// xterm.js clears the selection on every terminal.write(). We
|
||||
|
|
|
|||
|
|
@ -0,0 +1,63 @@
|
|||
import { describe, it, expect } from "vitest";
|
||||
import { buildDirectTerminalWsUrl } from "@/components/DirectTerminal";
|
||||
|
||||
describe("buildDirectTerminalWsUrl", () => {
|
||||
it("keeps non-standard port when proxy path override is set", () => {
|
||||
const wsUrl = buildDirectTerminalWsUrl({
|
||||
location: {
|
||||
protocol: "https:",
|
||||
hostname: "example.com",
|
||||
host: "example.com:8443",
|
||||
port: "8443",
|
||||
},
|
||||
sessionId: "session-1",
|
||||
proxyWsPath: "/ao-terminal-ws",
|
||||
});
|
||||
|
||||
expect(wsUrl).toBe("wss://example.com:8443/ao-terminal-ws?session=session-1");
|
||||
});
|
||||
|
||||
it("uses proxy path without port when default port is used", () => {
|
||||
const wsUrl = buildDirectTerminalWsUrl({
|
||||
location: {
|
||||
protocol: "https:",
|
||||
hostname: "example.com",
|
||||
host: "example.com",
|
||||
port: "",
|
||||
},
|
||||
sessionId: "session-2",
|
||||
proxyWsPath: "/ao-terminal-ws",
|
||||
});
|
||||
|
||||
expect(wsUrl).toBe("wss://example.com/ao-terminal-ws?session=session-2");
|
||||
});
|
||||
|
||||
it("uses default path-based endpoint on standard ports when no proxy override is set", () => {
|
||||
const wsUrl = buildDirectTerminalWsUrl({
|
||||
location: {
|
||||
protocol: "https:",
|
||||
hostname: "example.com",
|
||||
host: "example.com",
|
||||
port: "443",
|
||||
},
|
||||
sessionId: "session-3",
|
||||
});
|
||||
|
||||
expect(wsUrl).toBe("wss://example.com/ao-terminal-ws?session=session-3");
|
||||
});
|
||||
|
||||
it("uses direct terminal port on non-standard ports when no proxy override is set", () => {
|
||||
const wsUrl = buildDirectTerminalWsUrl({
|
||||
location: {
|
||||
protocol: "http:",
|
||||
hostname: "localhost",
|
||||
host: "localhost:3000",
|
||||
port: "3000",
|
||||
},
|
||||
sessionId: "session-4",
|
||||
directTerminalPort: "14888",
|
||||
});
|
||||
|
||||
expect(wsUrl).toBe("ws://localhost:14888/ws?session=session-4");
|
||||
});
|
||||
});
|
||||
Loading…
Reference in New Issue