Skip to content

fix(extension): use offscreen document for persistent WebSocket connection#569

Open
lyfuci wants to merge 3 commits intojackwener:mainfrom
lyfuci:fix/extension-offscreen-persistent-websocket
Open

fix(extension): use offscreen document for persistent WebSocket connection#569
lyfuci wants to merge 3 commits intojackwener:mainfrom
lyfuci:fix/extension-offscreen-persistent-websocket

Conversation

@lyfuci
Copy link
Copy Markdown

@lyfuci lyfuci commented Mar 28, 2026

Problem

Chrome MV3 Service Workers are suspended by the browser after a short idle period (~30s). When this happens, the WebSocket connection to the opencli daemon drops silently. Although a keepalive alarm fires every ~24s to wake the SW and call connect(), there is a gap window where:

  1. SW is suspended → WS drops
  2. Alarm fires → SW wakes → reconnects
  3. During that gap, any CLI command gets "Extension not connected"

Users experience this as the extension randomly disconnecting, requiring them to manually click the extension icon to wake it.

Root Cause

The WebSocket connection lives inside the Service Worker. Chrome's MV3 Service Worker lifecycle does not support persistent connections — it is designed to be ephemeral.

Fix

Move the WebSocket connection into a chrome.offscreen document. Offscreen documents have a stable lifetime tied to the browser window (not the SW), so the connection survives SW sleep/wake cycles.

The Service Worker becomes a thin relay layer:

  • Receives commands from the daemon CLI
  • Forwards them to the offscreen document via chrome.runtime.sendMessage
  • Offscreen executes them and sends results back

Changes

File Change
extension/src/offscreen.ts ✨ New — WebSocket host with auto-reconnect logic
extension/offscreen.html ✨ New — Offscreen document HTML entry point
extension/src/background.ts 🔧 Refactored — SW delegates WS ops to offscreen
extension/manifest.json 🔧 Added offscreen permission
extension/vite.config.ts 🔧 Added offscreen build entry

Testing

Tested on Linux (Chrome 144) with the browser idle for 2+ hours. Extension remained connected throughout — no manual reconnection required.

opencli doctor
[OK] Daemon: running on port 19825
[OK] Extension: connected (v1.5.5)
[OK] Connectivity: connected in 0.2s

Previously this would show [MISSING] Extension: not connected after Chrome suspended the SW.

lyfuci and others added 3 commits March 29, 2026 07:01
…ction

Chrome MV3 Service Workers are suspended by the browser when idle,
causing the WebSocket connection to the daemon to drop silently.
The existing keepalive alarm re-connects after wake, but there is a
window where commands fail and the CLI reports 'not connected'.

Fix: move the WebSocket into a chrome.offscreen document whose lifetime
is tied to the browser window, not the Service Worker. The SW becomes a
thin message-relay layer; the offscreen document owns the connection.

Changes:
- extension/src/offscreen.ts (new): WebSocket host with auto-reconnect
- extension/offscreen.html (new): offscreen document entry point
- extension/src/background.ts: delegate WS ops to offscreen via messages
- extension/manifest.json: add 'offscreen' permission
- extension/vite.config.ts: add offscreen as a build entry

Tested: extension stays connected after >2h with Chrome idle / SW
suspended on Linux.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants