#22571: fix(browser): complete extension relay handshake on connect.challenge
channel: msteams
size: S
Cluster:
Chrome Extension Enhancements
## Summary
Fixes Chrome extension relay sessions getting stuck at badge `…` by implementing the required gateway handshake flow in the bundled extension background worker.
Closes #22553
## Root cause
Gateway now emits a pre-connect `connect.challenge` event. The extension websocket client did not handle that event and never sent a `connect` request, so the relay session never became authenticated/ready.
## What changed
- Handle `type=event,event=connect.challenge` in `assets/chrome-extension/background.js`
- Send a proper gateway `connect` request from the extension with token auth and client metadata
- Wait for successful `connect` response before considering relay setup complete
- Ensure message listener is bound early so the first challenge frame cannot be missed
- Cleanly reject pending handshake promise on disconnect/timeouts
## Validation
- `node --check assets/chrome-extension/background.js`
## AI assistance
AI-assisted; change reviewed and validated locally.
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
Implemented the required gateway handshake flow to fix Chrome extension relay sessions getting stuck at the connecting badge (`…`). The extension now properly handles the `connect.challenge` event sent by the gateway server and responds with a `connect` request containing authentication credentials and client metadata. The message handler is bound early (before WebSocket open) to prevent race conditions where the challenge could be missed, and the connection waits for successful handshake completion before proceeding with relay operations.
- Added state variables to track handshake progress (`relayGatewayToken`, `relayConnectRequestId`, `relayConnectResolve/Reject`, `relayConnectTimer`, `relayChallengeSeen`)
- Implemented `waitForGatewayConnect()` to create a promise-based handshake with 8-second timeout
- Added `ensureGatewayHandshakeStarted()` to send the `connect` request with proper protocol parameters
- Handle `connect.challenge` event and successful/failed `connect` responses in `onRelayMessage`
- Clean up handshake state on disconnect/errors via `clearRelayConnectState()`
- Bound `ws.onmessage` before the WebSocket opens to prevent missing the initial challenge event
<h3>Confidence Score: 5/5</h3>
- Safe to merge - addresses a critical bug with proper error handling and timeout protection
- Implementation correctly follows the gateway protocol as documented and matches patterns from the TypeScript client. The handshake flow includes proper timeout handling (8s), early message binding to prevent race conditions, clean state management on errors/disconnects, and appropriate promise-based async flow. The fix directly addresses the reported issue and includes validation.
- No files require special attention
<sub>Last reviewed commit: 6d012ed</sub>
<!-- greptile_other_comments_section -->
<!-- /greptile_comment -->
Most Similar PRs
#17588: fix(relay): survive WS disconnects and MV3 worker restarts
by Unayung · 2026-02-15
80.2%
#22252: fix(chrome-extension): connection validation and clarify relay port...
by krizpoon · 2026-02-20
79.7%
#20688: fix(browser): allow extension reconnect when stale websocket linger...
by HOYALIM · 2026-02-19
79.2%
#21314: feat: enhance browser relay with custom naming and diagnostic tools
by kelvinCB · 2026-02-19
78.9%
#16060: fix(browser): require relay auth token for /extension WebSocket and...
by coygeek · 2026-02-14
77.9%
#15817: fix(chrome-relay): auto-reconnect, MV3 persistence, and keepalive
by derrickburns · 2026-02-13
77.5%
#19766: fix: Chrome relay extension auto-reattach after SPA navigation
by nishantkabra77 · 2026-02-18
76.8%
#21277: fix(browser): dedupe concurrent relay init and await shared startup...
by HOYALIM · 2026-02-19
76.1%
#9178: Fix: GatewayClient queueConnect() setTimeout never fires
by vishaltandale00 · 2026-02-04
75.9%
#10390: fix(chrome-relay): sticky attach + auto-restore after disconnects
by Mokoby · 2026-02-06
75.7%