// Tab lifecycle: clean up swarms and subscriptions when tabs close. // Depends on: state.js (tabSwarms, swarmRefCount), logs.js (log), native-messaging.js (send, subscribedTabs, dashboardTabs) browser.tabs.onRemoved.addListener((tabId) => { log('Tab closed:', tabId); const swarmIds = tabSwarms.get(tabId); if (swarmIds) { for (const swarmId of swarmIds) { const count = (swarmRefCount.get(swarmId) || 0) - 1; swarmRefCount.set(swarmId, count); log('Swarm', swarmId, 'refcount now:', count); if (count <= 0) { log('Last tab for swarm', swarmId, '- destroying'); send({ type: 'destroy', payload: { swarmId } }).catch(() => {}); swarmRefCount.delete(swarmId); } } tabSwarms.delete(tabId); } subscribedTabs.delete(tabId); dashboardTabs.delete(tabId); }); // Clean up subscription Sets when a tab navigates away. Without this, a tab // that subscribes and then navigates to a non-extension page stays in the Sets // until it is closed, causing silent sendMessage failures on every broadcast. browser.tabs.onUpdated.addListener((tabId, changeInfo) => { if (changeInfo.url) { subscribedTabs.delete(tabId); dashboardTabs.delete(tabId); } });