diff --git a/js/core/src/BlitConnection.ts b/js/core/src/BlitConnection.ts index 69e359ae..87d6a9ee 100644 --- a/js/core/src/BlitConnection.ts +++ b/js/core/src/BlitConnection.ts @@ -504,60 +504,6 @@ export class BlitConnection { this.transport.send(buildCloseMessage(session.ptyId)); } - /** - * Wait for `sessionId` to reach `state === "exited"` or `state === "closed"` - * and return the captured `exitStatus`. Resolves immediately if the session - * has already finished. Resolves with `{ exitStatus: null, timedOut: false }` - * if the session is unknown — the caller has nothing else to wait on. - * - * If `options.timeoutMs` is provided, races the wait against the timeout and - * resolves with `{ exitStatus: null, timedOut: true }` if it elapses first. - * - * Honours {@link EXIT_STATUS_UNKNOWN}: callers that want a conventional - * shell exit code should pass the returned `exitStatus` through - * {@link exitCodeFromStatus}. - */ - awaitSessionExit( - sessionId: SessionId, - options?: { readonly timeoutMs?: number }, - ): Promise<{ - readonly exitStatus: number | null; - readonly timedOut: boolean; - }> { - const current = this.sessionsById.get(sessionId); - if (!current || current.state === "exited" || current.state === "closed") { - return Promise.resolve({ - exitStatus: current?.exitStatus ?? null, - timedOut: false, - }); - } - return new Promise((resolve) => { - let unsubscribe: () => void = () => {}; - let timer: ReturnType | null = null; - const finish = (result: { - exitStatus: number | null; - timedOut: boolean; - }): void => { - if (timer !== null) clearTimeout(timer); - unsubscribe(); - resolve(result); - }; - if (options?.timeoutMs !== undefined) { - timer = setTimeout( - () => finish({ exitStatus: null, timedOut: true }), - options.timeoutMs, - ); - } - unsubscribe = this.subscribe(() => { - const session = this.sessionsById.get(sessionId); - if (!session) return; - if (session.state === "exited" || session.state === "closed") { - finish({ exitStatus: session.exitStatus, timedOut: false }); - } - }); - }); - } - restartSession(sessionId: SessionId): void { const session = this.sessionsById.get(sessionId); if ( diff --git a/js/core/src/__tests__/BlitConnection.test.ts b/js/core/src/__tests__/BlitConnection.test.ts index 53d9efcd..15aebed6 100644 --- a/js/core/src/__tests__/BlitConnection.test.ts +++ b/js/core/src/__tests__/BlitConnection.test.ts @@ -1,6 +1,5 @@ import { describe, it, expect, beforeEach, vi } from "vitest"; import { BlitConnection } from "../BlitConnection"; -import { EXIT_STATUS_UNKNOWN } from "../exit-status"; import { MockTransport } from "./mock-transport"; import type { BlitWasmModule } from "../TerminalStore"; import { @@ -337,87 +336,6 @@ describe("BlitConnection", () => { await promise; }); - // --- awaitSessionExit --- - - it("awaitSessionExit resolves on EXITED", async () => { - transport.pushCreated(3, ""); - const session = conn.getSnapshot().sessions[0]; - const promise = conn.awaitSessionExit(session.id); - transport.pushExited(3, 0); - await expect(promise).resolves.toEqual({ exitStatus: 0, timedOut: false }); - }); - - it("awaitSessionExit captures signal exit status", async () => { - transport.pushCreated(3, ""); - const session = conn.getSnapshot().sessions[0]; - const promise = conn.awaitSessionExit(session.id); - transport.pushExited(3, -15); - await expect(promise).resolves.toEqual({ - exitStatus: -15, - timedOut: false, - }); - }); - - it("awaitSessionExit resolves immediately when already exited", async () => { - transport.pushCreated(3, ""); - const session = conn.getSnapshot().sessions[0]; - transport.pushExited(3, 42); - await expect(conn.awaitSessionExit(session.id)).resolves.toEqual({ - exitStatus: 42, - timedOut: false, - }); - }); - - it("awaitSessionExit resolves on CLOSED without exitStatus", async () => { - transport.pushCreated(3, ""); - const session = conn.getSnapshot().sessions[0]; - const promise = conn.awaitSessionExit(session.id); - transport.pushClosed(3); - await expect(promise).resolves.toEqual({ - exitStatus: null, - timedOut: false, - }); - }); - - it("awaitSessionExit honours legacy EXITED frames as EXIT_STATUS_UNKNOWN", async () => { - transport.pushCreated(3, ""); - const session = conn.getSnapshot().sessions[0]; - const promise = conn.awaitSessionExit(session.id); - transport.pushExitedRaw(3); - await expect(promise).resolves.toEqual({ - exitStatus: EXIT_STATUS_UNKNOWN, - timedOut: false, - }); - }); - - it("awaitSessionExit times out and unsubscribes when the process keeps running", async () => { - transport.pushCreated(3, ""); - const session = conn.getSnapshot().sessions[0]; - vi.useFakeTimers(); - try { - const promise = conn.awaitSessionExit(session.id, { timeoutMs: 50 }); - vi.advanceTimersByTime(50); - await expect(promise).resolves.toEqual({ - exitStatus: null, - timedOut: true, - }); - // Late EXITED must not be observed by a discarded listener — if the - // subscription leaked, this would attempt to resolve the already-settled - // promise; we simply assert the snapshot still reflects the exit. - transport.pushExited(3, 7); - expect(conn.getSession(session.id)?.exitStatus).toBe(7); - } finally { - vi.useRealTimers(); - } - }); - - it("awaitSessionExit returns immediately for an unknown session", async () => { - await expect(conn.awaitSessionExit("missing-session-id")).resolves.toEqual({ - exitStatus: null, - timedOut: false, - }); - }); - // --- Send helpers --- it("sendInput sends INPUT with session ptyId", () => {