fix(host-control-mode): reconcile desync state on content reinjection

Fixes a split-brain where a guest who chose "watch on my own" and then reloaded
the video page would appear stuck as "Solo" to the host while actually being
back in sync.

Root cause: background persists hcmDesynced (survives SW restart) and attaches
it to content-driven heartbeats, but a freshly injected content script started
with hcmDesynced=false and GET_CONTROL_MODE never returned the desync state — so
content re-applied host commands (synced) while background kept relaying
desynced=true to the host.

Fix: GET_CONTROL_MODE now also returns desynced; content adopts it on init
(re-shows the badge) and also adopts hostPeerId so later host-change resets work.
Desync now survives a page reload consistently on both sides, as intended.

Verified the full path: background.js heartbeat (1555 omits / 2018 attaches),
reset paths, CONTENT_BOOT and keepAlive-disconnect (neither reset it), content
sendHeartbeat on inject.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
KoalaDev
2026-06-26 15:45:33 +02:00
parent 5863991bfb
commit 2928393b4c
2 changed files with 12 additions and 2 deletions
+5 -2
View File
@@ -1705,8 +1705,11 @@ async function handleAsyncMessage(message, sender, sendResponse) {
emit(EVENTS.SET_CONTROL_MODE, { controlMode: mode });
sendResponse({ status: 'ok' });
} else if (message.type === 'GET_CONTROL_MODE') {
// content.js asks for current mode/role (e.g. injected after ROOM_DATA).
sendResponse({ controlMode, hostPeerId, amHost: amHost() });
// content.js asks for current mode/role on (re)injection. Include the
// persisted desync state so a page reload re-adopts it — otherwise a fresh
// content script would start synced while background keeps relaying us as
// "Solo" to the host (stale-badge split-brain).
sendResponse({ controlMode, hostPeerId, amHost: amHost(), desynced: hcmDesynced });
} else if (message.type === 'REQUEST_HOST_SYNC') {
// content.js resync: hand back the host's extrapolated current position.
sendResponse({ target: getHostSyncTarget() });
+7
View File
@@ -1435,6 +1435,13 @@
if (chrome.runtime.lastError || !res) return;
hcmControlMode = res.controlMode || 'everyone';
hcmAmHost = !!res.amHost;
hcmHostPeerId = res.hostPeerId || null;
// Re-adopt persisted desync after a page reload so we don't start synced
// while background still relays us as "Solo" to the host (split-brain).
if (res.desynced && !hcmDesynced) {
hcmDesynced = true;
hcmShowBadge();
}
});
})();