Fix iOS connection loss: track WebSocket state and show reconnecting …#906
Fix iOS connection loss: track WebSocket state and show reconnecting …#906marcodejongh wants to merge 5 commits intomainfrom
Conversation
…overlay When iOS Safari backgrounds the app, the OS silently kills the WebSocket connection. Previously the UI stayed fully interactive while changes silently failed to sync. This adds real-time WebSocket connection state tracking via graphql-ws on.connected/on.closed callbacks, a visibilitychange handler to proactively detect dead sockets on iOS foreground return, and a "Reconnecting..." overlay on the queue control bar that blocks interaction until the connection recovers. https://claude.ai/code/session_016bdrJ2mAmjzSmZ2z6vWGN9
Claude Review✅ Ready to merge - Minor issues noted below, but nothing blocking. Issues
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 27d953fc2b
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| on: { | ||
| connected: () => { | ||
| if (DEBUG) console.log(`[GraphQL] Client #${clientId} connected (first: ${!hasConnectedOnce})`); | ||
| onConnectionStateChange?.(true); |
There was a problem hiding this comment.
Keep reconnect lock until state resync finishes
onConnectionStateChange(true) is emitted as soon as the WebSocket reconnects, before onReconnectCallback() completes its async joinSession/replay sync path. Because reconnect UI gating is derived from this connection flag (hasConnected && !isWebSocketConnected), the app exits reconnect mode and re-enables queue mutations while missed events may still be replaying. After a disconnect with sequence drift, users can act on stale queue state and have those actions race with or be overwritten by the delayed resync.
Useful? React with 👍 / 👎.
The on.connected callback was setting isWebSocketConnected=true immediately, before handleReconnect could finish its async joinSession/delta-sync path. This caused isReconnecting to become false prematurely, re-enabling queue mutations while stale state was still being replayed. Fix: onConnectionStateChange now receives an isReconnect flag. On reconnections, the persistent session defers setting isWebSocketConnected=true until handleReconnect's finally block, keeping the reconnecting overlay and viewOnlyMode active throughout the entire resync. Also adds iOS background connection loss documentation to docs/websocket-implementation.md (section 7 under Failure States). https://claude.ai/code/session_016bdrJ2mAmjzSmZ2z6vWGN9
Claude Review✅ Ready to merge - Minor issues noted below, but nothing blocking. Issues
Notes
|
- graphql-client.test.ts: Tests onConnectionStateChange callback fires with correct (connected, isReconnect) flags across initial connect, disconnect, and reconnection sequences. Verifies callback ordering (stateChange fires before onReconnect). - connection-state.test.ts: Tests isReconnecting derivation truth table, reconnect lock timing (isReconnecting stays true during resync), and visibilitychange debounce behavior (300ms delay, rapid-fire cancellation, hidden state ignored). https://claude.ai/code/session_016bdrJ2mAmjzSmZ2z6vWGN9
The full-page overlay blocked all user interaction. Replace it with a bottom-center Snackbar/Alert that shows "Reconnecting..." with a spinner and automatically disappears when the connection is re-established. Queue mutations are still prevented by viewOnlyMode during reconnection. https://claude.ai/code/session_016bdrJ2mAmjzSmZ2z6vWGN9
Claude Review✅ Ready to merge - Well-implemented iOS reconnection handling with proper state tracking, documentation, and tests. Minor issues:
Notes:
|
Claude Review✅ Ready to merge - Well-implemented iOS connection loss handling with comprehensive test coverage and updated documentation. No significant issues found. The implementation correctly:
|
…overlay
When iOS Safari backgrounds the app, the OS silently kills the WebSocket connection. Previously the UI stayed fully interactive while changes silently failed to sync. This adds real-time WebSocket connection state tracking via graphql-ws on.connected/on.closed callbacks, a visibilitychange handler to proactively detect dead sockets on iOS foreground return, and a "Reconnecting..." overlay on the queue control bar that blocks interaction until the connection recovers.
https://claude.ai/code/session_016bdrJ2mAmjzSmZ2z6vWGN9