From 5f19dcc93f1cc68f7a1a0900abe8a726ba7f8272 Mon Sep 17 00:00:00 2001 From: Hare Date: Tue, 29 Sep 2026 15:38:12 +0900 Subject: [PATCH] fix: use browser-safe WebSocket close code --- .../src/lib/workspace/multiplexer.browser.spec.ts | 9 ++++++++- web/workspace/src/lib/workspace/multiplexer.ts | 3 ++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/web/workspace/src/lib/workspace/multiplexer.browser.spec.ts b/web/workspace/src/lib/workspace/multiplexer.browser.spec.ts index 23eaa7a5d..77ab8f56d 100644 --- a/web/workspace/src/lib/workspace/multiplexer.browser.spec.ts +++ b/web/workspace/src/lib/workspace/multiplexer.browser.spec.ts @@ -32,6 +32,13 @@ class FakeWebSocket { } close(code?: number, reason?: string): void { + if ( + code !== undefined && + code !== 1000 && + (code < 3000 || code > 4999) + ) { + throw new DOMException('Invalid WebSocket close code', 'InvalidAccessError'); + } this.closes.push([code, reason]); if (this.readyState === FakeWebSocket.CLOSED) return; this.readyState = FakeWebSocket.CLOSED; @@ -91,7 +98,7 @@ test('invalid inbound frame closes before dispatch and reconnects for a fresh sn ); expect(onFrame).not.toHaveBeenCalled(); - expect(first.closes).toEqual([[1002, 'Invalid workspace protocol frame']]); + expect(first.closes).toEqual([[4002, 'Invalid workspace protocol frame']]); expect(onStatus).toHaveBeenLastCalledWith('closed', 'Workspace protocol frame rejected'); expect(JSON.stringify(onStatus.mock.calls)).not.toContain('untrusted detail'); diff --git a/web/workspace/src/lib/workspace/multiplexer.ts b/web/workspace/src/lib/workspace/multiplexer.ts index a1ca52865..453aaf9d5 100644 --- a/web/workspace/src/lib/workspace/multiplexer.ts +++ b/web/workspace/src/lib/workspace/multiplexer.ts @@ -30,6 +30,7 @@ export type WorkspaceMultiplexerSubscription = { }; const multiplexers = new Map(); +const INVALID_PROTOCOL_CLOSE_CODE = 4002; let nextMultiplexerSequence = 0; function nextMultiplexerId(kind: 'client' | 'request'): string { @@ -205,7 +206,7 @@ export class WorkspaceMultiplexer { #rejectInboundFrame(): void { this.#disconnectMessage = 'Workspace protocol frame rejected'; - this.#socket?.close(1002, 'Invalid workspace protocol frame'); + this.#socket?.close(INVALID_PROTOCOL_CLOSE_CODE, 'Invalid workspace protocol frame'); } #sendWorkerMethod(clientId: string, method: Method): void {