From 904602e07e6b99aaf18cc85ee191686d0430506d Mon Sep 17 00:00:00 2001 From: Mircea Hasegan Date: Fri, 3 Oct 2025 19:52:31 +0200 Subject: [PATCH] fix(extension): add window focus change detection to lace tab activity check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. The Service Worker (SW) exposes an observable isLaceTabActive$, which reports changes when: • a window is closed • a tab is updated (URL changes) • a tab is activated (user switches tabs) 2. The UI subscribes to this observable. 3. After ~30 seconds of inactivity, Chrome suspends the SW due to lack of focus. 4. When the UI resubscribes to isLaceTabActive$ after the SW was suspended: • The observable restarts with its startWith value (false). • Because the SW was suspended, no tab events (from step 1) have fired, so nothing updates the observable. • As a result, the UI keeps seeing false and shows “Blockchain out of sync.” 5. Returning to the tab does not fix the issue because no event is triggered to flip isLaceTabActive$ back to true. 6. Clicking the menus works because trigger navigation changes so the tab.onUpdated event fires, which updates isLaceTabActive$ to true. ⸻ Solution • The SW should also monitor the windowFocusChanged$ event. • When the window regains focus, the event will fire, the observable emits true if the tab is still open which tells the UI it is safe to resume communication. --- .../lib/scripts/background/session/is-lace-tab-active.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/apps/browser-extension-wallet/src/lib/scripts/background/session/is-lace-tab-active.ts b/apps/browser-extension-wallet/src/lib/scripts/background/session/is-lace-tab-active.ts index 00c8b13f2f..dda2d83d63 100644 --- a/apps/browser-extension-wallet/src/lib/scripts/background/session/is-lace-tab-active.ts +++ b/apps/browser-extension-wallet/src/lib/scripts/background/session/is-lace-tab-active.ts @@ -8,6 +8,12 @@ const windowRemoved$ = fromEventPattern( (handler) => windows.onRemoved.addListener(handler), (handler) => windows.onRemoved.removeListener(handler) ); + +const windowFocusChanged$ = fromEventPattern( + (handler) => windows.onFocusChanged.addListener(handler), + (handler) => windows.onFocusChanged.removeListener(handler) +); + const tabUpdated$ = fromEventPattern( (handler) => tabs.onUpdated.addListener(handler), (handler) => tabs.onUpdated.removeListener(handler), @@ -30,7 +36,7 @@ const getExtensionTabUrlPattern = () => { return `${url.origin}/*`; }; -export const isLaceTabActive$ = merge(windowRemoved$, tabUpdated$, tabActivated$).pipe( +export const isLaceTabActive$ = merge(windowRemoved$, tabUpdated$, tabActivated$, windowFocusChanged$).pipe( switchMap(() => from( catchAndBrandExtensionApiError(