Skip to content

fix(extension): popup shows live connection state instead of stale expiresAt#32

Merged
dimdasci merged 3 commits into
mainfrom
fix/popup-pairing-status-31
Jun 24, 2026
Merged

fix(extension): popup shows live connection state instead of stale expiresAt#32
dimdasci merged 3 commits into
mainfrom
fix/popup-pairing-status-31

Conversation

@dimdasci

Copy link
Copy Markdown
Owner

Summary

Fixes #31 — Extension popup shows "Not paired" after ~5 minutes while the WebSocket connection is active.

Root Cause

The popup checked bootstrap.expiresAt > Date.now() to determine pairing status. Since expiresAt equals issuedAt + 5min (the pairing code claim window TTL, not the session validity), the popup falsely showed "Not paired" after 5 minutes.

The background ws-client correctly ignores expiresAt — connection lifetime is governed by the daemon's active extension token.

Fix

The popup now queries the background service worker for live WebSocket badge state via chrome.runtime.sendMessage({ type: "status.query" }):

Badge state Bootstrap present Display
connected any ● Paired with local daemon (green)
connecting any ● Connecting… (muted)
disconnected / error yes ● Disconnected (muted)
disconnected / error / null no ● Not paired (muted)

Falls back to bootstrap-presence heuristic when the SW is unreachable.

Changes

File Change
extension/src/entrypoints/background.ts Added status.query message handler returning client.getState()
extension/src/entrypoints/popup/main.ts Replaced expiresAt check with live SW query; refactored getConnectionStatusViewModel(liveState, hasBootstrap)
extension/src/entrypoints/popup/__tests__/presentation.test.ts Updated view-model tests for new signature
extension/src/entrypoints/popup/__tests__/initialize.test.ts New: initializePopup integration test with DI
extension/src/background/__tests__/status-query.test.ts New: handler contract tests

Verification

  • pnpm check passes (typecheck, format, lint, arch, deadcode)
  • pnpm test — 887 tests pass across all workspaces
  • Extension: 26 test files, 206 tests (10 new)

Version

Bumped to 0.9.2.

dimdasci added 3 commits June 23, 2026 22:48
…piresAt

The popup's connection-status display was checking bootstrap.expiresAt > now
to determine pairing status. Since expiresAt equals issuedAt + 5min (the
pairing code's claim window TTL), the popup falsely showed 'Not paired'
after 5 minutes — even while the WebSocket connection remained active.

The background ws-client correctly ignores expiresAt (connection lifetime is
governed by the daemon's active extension token, not the bootstrap envelope
freshness).

Fix: the popup now queries the background service worker for live WebSocket
badge state via chrome.runtime.sendMessage({ type: 'status.query' }) and
uses the response to drive the status display:

  - connected → 'Paired with local daemon' (green)
  - connecting → 'Connecting…' (muted)
  - disconnected/error + has token → 'Disconnected' (muted)
  - no token → 'Not paired' (muted)

Falls back to bootstrap-presence heuristic when the SW is unreachable.

Closes #31
…Popup

- status-query.test.ts: verifies message matching, response shape, all
  badge states, and non-matching message passthrough.
- initialize.test.ts: exercises initializePopup with injected deps and
  minimal DOM mocks — covers all state×bootstrap combinations plus
  storage failure graceful degradation.
@dimdasci
dimdasci merged commit 199a9da into main Jun 24, 2026
5 checks passed
@dimdasci
dimdasci deleted the fix/popup-pairing-status-31 branch June 24, 2026 10:15
@sonarqubecloud

Copy link
Copy Markdown

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.

Bug: Extension popup shows 'Not paired' while WebSocket connection is active

1 participant