Files
Yanwu e60412f5fd feat(view): heartbeat ping + idle timeout + visibility-based disconnect (#226)
* feat(view): heartbeat ping + idle timeout + visibility-based disconnect

- Send OpPing (0x08) heartbeat every 5s (active) / 10s (idle)
- Visibility change: hidden starts 30s idle countdown, visible cancels
- cleanup(reason): distinct overlay messages for user/idle/network disconnect
- Start heartbeat on DataChannel open, stop on cleanup

* fix(view): use polling instead of setTimeout for idle timeout in hidden tabs

Browsers throttle setTimeout in hidden tabs to >=1 minute (Chrome).
The 30s idle timeout was never firing because the timer was delayed.

Fix: record hiddenSince timestamp on visibilitychange, check elapsed
time on each heartbeat interval tick instead of relying on setTimeout.

* fix(view): fire-and-forget stream.close to prevent disconnect from hanging

disconnect() was awaiting invoke('stream.close') which could hang if
the server is slow or the connection is degraded. This blocked cleanup()
from running, so the UI stayed in 'connected' state and heartbeat
continued indefinitely.

Fix: fire stream.close without awaiting, then immediately cleanup.
2026-05-24 13:40:00 +08:00
..