mirror of
https://github.com/block/buzz.git
synced 2026-08-18 06:50:31 +02:00
The reconnect button had three compounding failure modes: 1. Instant false-fail during sign-in: the transport-recovery hook ran and exited in ~0.1s, but the tunnel liveness check passed while the Access layer was still blocked, so preconnect() hit the unreachable network and failed immediately — the user saw a 'failed' toast mid-login. 2. False-fail after actual reconnect: a single promise race with a 15s cap determined the verdict. preconnect() set keepAliveRequested=true so the background retry loop kept going and often succeeded right after the toast fired, leaving the user confused. 3. Spurious browser tab on transient blips: the hook ran unconditionally even when the transport was healthy and the disconnect was a network flap. New strategy — try-fast-first → escalate → poll-until-connected: - Phase 1 (fast path): attempt preconnect() with a 4s cap. Succeeds immediately for transient blips — no hook fires, no browser tab opens. - Phase 2 (escalation, hook-configured builds only): only if the fast path fails and relay_reconnect_hook_configured() returns true, run the transport-recovery hook. The hook returns quickly; any browser-based network sign-in it triggers runs asynchronously. - Phase 3 (poll-until-connected): retry preconnect() every 3s and watch the connection-state emitter. The moment the relay is reachable the next poll or emitter event declares success — no waiting for a timer. A 120s backstop fires a soft toast only; keepAliveRequested keeps the background loop alive. Extracts a RelayReconnectController singleton (plain TS, injected deps) so all three consumers — ConnectionBanner, useSidebarRelayConnectionCard, and ProfileStep — share one in-flight state via useSyncExternalStore-style subscribe. No double browser tabs; consistent 'Waiting for sign-in' state across surfaces. Cancellation token (generation counter) is checked after every await and inside every async continuation, closing the gap where a cancelled poll's .then() could still mutate state. Adds relay_reconnect_hook_configured Rust command (OSS-clean, bool) so the frontend skips escalation and 'Waiting for sign-in...' copy in OSS builds. e2eBridge returns false for this command in test environments. Tests rewritten to exercise the real RelayReconnectController class with injected fakes — no simulation helpers. Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>