refactor(web): rewire attach.ts to same-origin broker endpoint (NAP-241)
ci / rust (push) Failing after 8m45s
ci / rust (push) Failing after 8m45s
Browser now opens ws://{host}/api/attach/:id directly — maestro-web
reverse-proxies it to the home daemon's broker, which short-circuits to
the local PTY (NAP-243) or, once NAP-247 lands, brokers to a peer over T2.
Drops the old getConnectInfo + daemon_url path: the browser no longer
knows or cares which daemon owns a session. ConnectInfo type and the
helper are gone.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
+1
-16
@@ -1,11 +1,4 @@
|
||||
import type {
|
||||
ApiError,
|
||||
ConnectInfo,
|
||||
CreateSessionRequest,
|
||||
DaemonInfo,
|
||||
Session,
|
||||
Uuid,
|
||||
} from "./types.js";
|
||||
import type { ApiError, CreateSessionRequest, DaemonInfo, Session, Uuid } from "./types.js";
|
||||
|
||||
async function jsonOrError<T>(res: Response): Promise<T> {
|
||||
if (res.ok) {
|
||||
@@ -50,14 +43,6 @@ export async function killSession(id: Uuid): Promise<void> {
|
||||
);
|
||||
}
|
||||
|
||||
export async function getConnectInfo(id: Uuid): Promise<ConnectInfo> {
|
||||
return jsonOrError(
|
||||
await fetch(`/api/sessions/${encodeURIComponent(id)}/connect-info`, {
|
||||
credentials: "same-origin",
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
export function eventsWsUrl(): string {
|
||||
const proto = location.protocol === "https:" ? "wss:" : "ws:";
|
||||
return `${proto}//${location.host}/api/events`;
|
||||
|
||||
+11
-23
@@ -2,7 +2,6 @@ import { FitAddon } from "@xterm/addon-fit";
|
||||
import { Terminal } from "@xterm/xterm";
|
||||
import "@xterm/xterm/css/xterm.css";
|
||||
|
||||
import { getConnectInfo } from "./api.js";
|
||||
import type { ClientControl, Uuid } from "./types.js";
|
||||
|
||||
interface AttachHandle {
|
||||
@@ -13,16 +12,15 @@ function statusMessage(host: HTMLElement, kind: "info" | "error", text: string):
|
||||
host.innerHTML = `<div class="attach-status status-${kind}">${text}</div>`;
|
||||
}
|
||||
|
||||
function streamUrl(daemonUrl: string, sessionId: Uuid, jwt: string): string {
|
||||
let base = daemonUrl;
|
||||
// Allow operators to give an http(s) URL; convert to ws(s).
|
||||
if (base.startsWith("http://")) base = "ws://" + base.slice("http://".length);
|
||||
else if (base.startsWith("https://")) base = "wss://" + base.slice("https://".length);
|
||||
// Trim trailing slash.
|
||||
base = base.replace(/\/+$/, "");
|
||||
const encId = encodeURIComponent(sessionId);
|
||||
const encJwt = encodeURIComponent(jwt);
|
||||
return `${base}/sessions/${encId}/stream?token=${encJwt}`;
|
||||
/**
|
||||
* Same-origin broker URL. The browser loads from `maestro-web`, which
|
||||
* reverse-proxies this WebSocket to the co-located daemon's
|
||||
* `/api/attach/:id` broker endpoint. The daemon short-circuits to the local
|
||||
* PTY when it owns the session; cross-daemon brokering lands with NAP-247.
|
||||
*/
|
||||
function brokerStreamUrl(sessionId: Uuid): string {
|
||||
const proto = location.protocol === "https:" ? "wss:" : "ws:";
|
||||
return `${proto}//${location.host}/api/attach/${encodeURIComponent(sessionId)}`;
|
||||
}
|
||||
|
||||
export async function renderAttach(
|
||||
@@ -51,16 +49,7 @@ export async function renderAttach(
|
||||
stateEl.dataset.state = kind;
|
||||
};
|
||||
|
||||
statusMessage(body, "info", "Fetching connect info…");
|
||||
|
||||
let connect;
|
||||
try {
|
||||
connect = await getConnectInfo(sessionId);
|
||||
} catch (e) {
|
||||
setState("error", "error");
|
||||
statusMessage(body, "error", `Failed to get connect info: ${(e as Error).message}`);
|
||||
return { dispose: () => {} };
|
||||
}
|
||||
statusMessage(body, "info", "Connecting…");
|
||||
|
||||
body.innerHTML = "";
|
||||
|
||||
@@ -91,8 +80,7 @@ export async function renderAttach(
|
||||
};
|
||||
tryFit();
|
||||
|
||||
const wsUrl = streamUrl(connect.daemon_url, sessionId, connect.jwt);
|
||||
const ws = new WebSocket(wsUrl);
|
||||
const ws = new WebSocket(brokerStreamUrl(sessionId));
|
||||
ws.binaryType = "arraybuffer";
|
||||
|
||||
const sendControl = (msg: ClientControl) => {
|
||||
|
||||
@@ -24,11 +24,6 @@ export interface DaemonInfo {
|
||||
daemon_url: string;
|
||||
}
|
||||
|
||||
export interface ConnectInfo {
|
||||
daemon_url: string;
|
||||
jwt: string;
|
||||
}
|
||||
|
||||
export interface WorktreeSpec {
|
||||
base_repo: string;
|
||||
branch: string;
|
||||
|
||||
Reference in New Issue
Block a user