fix(extension): probe daemon before WebSocket to eliminate console noise#534
Merged
jackwener merged 3 commits intojackwener:mainfrom Mar 28, 2026
Merged
Conversation
…onsole noise When the daemon is offline, `new WebSocket()` logs uncatchable ERR_CONNECTION_REFUSED errors to Chrome's extension error page. Add `probeAndConnect()` that checks daemon reachability with a silent `fetch(HEAD)` before attempting WebSocket connection. All three auto-connect paths (initialize, keepalive alarm, eager reconnect) now go through the probe, eliminating the error noise entirely. Closes jackwener#505
Instead of a separate probeAndConnect() wrapper that all call sites had
to remember to use, bake the HTTP probe directly into connect() itself.
This makes the guard impossible to accidentally skip when adding new
connection paths in the future.
Also adds a dedicated GET /ping endpoint to the daemon (no X-OpenCLI
header required) so the probe has a clear semantic contract instead of
relying on a 403 side-effect from the root path.
- daemon: GET /ping → 200 {ok:true}, no auth needed, placed before the
X-OpenCLI header check; only chrome-extension:// and no-origin
requests reach it (origin check is still enforced above)
- background: connect() is now async; probes /ping with a 1 s timeout
before new WebSocket(); all call sites (initialize, keepalive alarm,
scheduleReconnect) remain unchanged
- probeAndConnect() removed — no longer needed
- protocol.ts: replace DAEMON_HTTP_URL with DAEMON_PING_URL (clearer semantics, single source of truth for the health-check URL) - background.ts: import DAEMON_PING_URL from protocol instead of defining a local constant; check res.ok so an unexpected non-200 response doesn't fall through to WebSocket; annotate all fire-and- forget connect() call sites with `void` to make intent explicit - daemon.ts: add security comment on /ping documenting the timing side-channel tradeoff (loopback-only, accepted risk)
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
When the daemon is offline, the extension's keepalive alarm repeatedly calls
new WebSocket(), which logs uncatchableERR_CONNECTION_REFUSEDerrors to Chrome's extension error page. Over time this fills the page with thousands of red errors, alarming users (#505).This PR adds a
probeAndConnect()function that checks daemon reachability viafetch(HEAD)before attempting WebSocket connection.fetch()failures are silently catchable, so no Chrome error is logged.All three auto-connect paths now go through the probe:
initialize()(extension startup)Related issue: #505
Type of Change
Checklist
Verification
Tested with Node.js
fetch()to confirm behavior:fetch(HEAD)throwsECONNREFUSED→ caught silently →connect()skipped → no Chrome errorfetch(HEAD)returns 403 (no X-OpenCLI header) → fetch resolves normally →connect()proceeds → WebSocket connects