Files
CyberStrikeAI/plugins/browser-extension/cyberstrikeai-browser-extension/background/service-worker.js
T
2026-07-08 13:51:05 +08:00

144 lines
3.8 KiB
JavaScript

/* global chrome, CSAI_LIMITS, shouldCaptureEntry */
importScripts('../lib/constants.js', '../lib/capture.js');
/** Background hub: per-tab capture queue + panel subscriptions. */
const capturesByTab = new Map();
const portsByTab = new Map();
const filterApiByTab = new Map();
let captureEnabled = true;
function getCaptures(tabId) {
if (!capturesByTab.has(tabId)) capturesByTab.set(tabId, []);
return capturesByTab.get(tabId);
}
function trimCaptures(list) {
if (list.length > CSAI_LIMITS.MAX_CAPTURED) {
list.length = CSAI_LIMITS.MAX_CAPTURED;
}
}
function broadcastTab(tabId, message) {
const ports = portsByTab.get(tabId);
if (!ports) return;
for (const port of ports) {
try {
port.postMessage(message);
} catch (_) {
ports.delete(port);
}
}
}
function cleanupOldTabs(activeTabId) {
if (capturesByTab.size <= CSAI_LIMITS.MAX_TAB_CAPTURES) return;
for (const tabId of capturesByTab.keys()) {
if (tabId !== activeTabId) {
capturesByTab.delete(tabId);
portsByTab.delete(tabId);
filterApiByTab.delete(tabId);
}
if (capturesByTab.size <= CSAI_LIMITS.MAX_TAB_CAPTURES) break;
}
}
chrome.runtime.onConnect.addListener((port) => {
if (port.name !== 'cyberstrike-panel') return;
port.onDisconnect.addListener(() => {
for (const [tabId, set] of portsByTab.entries()) {
set.delete(port);
if (set.size === 0) portsByTab.delete(tabId);
}
});
port.onMessage.addListener((msg) => {
if (!msg || msg.type !== 'subscribe') return;
const tabId = msg.tabId;
if (tabId == null) return;
if (!portsByTab.has(tabId)) portsByTab.set(tabId, new Set());
portsByTab.get(tabId).add(port);
if (typeof msg.filterApiOnly === 'boolean') {
filterApiByTab.set(tabId, msg.filterApiOnly);
}
port.postMessage({ type: 'list', entries: getCaptures(tabId) });
cleanupOldTabs(tabId);
});
});
chrome.runtime.onMessage.addListener((msg, _sender, sendResponse) => {
if (!msg || !msg.type) return false;
if (msg.type === 'capture-entry') {
const tabId = msg.tabId;
if (tabId == null) return false;
if (!captureEnabled) {
sendResponse({ ok: true, skipped: true });
return false;
}
const filterApi = filterApiByTab.has(tabId) ? filterApiByTab.get(tabId) : true;
const entry = msg.entry;
if (!shouldCaptureEntry(entry, filterApi)) {
sendResponse({ ok: true, skipped: true });
return false;
}
const list = getCaptures(tabId);
list.unshift(entry);
trimCaptures(list);
broadcastTab(tabId, { type: 'entry', entry });
sendResponse({ ok: true });
return false;
}
if (msg.type === 'clear-captures') {
const tabId = msg.tabId;
if (tabId != null) {
capturesByTab.set(tabId, []);
broadcastTab(tabId, { type: 'list', entries: [] });
}
sendResponse({ ok: true });
return false;
}
if (msg.type === 'set-filter-api') {
const tabId = msg.tabId;
if (tabId != null && typeof msg.filterApiOnly === 'boolean') {
filterApiByTab.set(tabId, msg.filterApiOnly);
}
sendResponse({ ok: true });
return false;
}
if (msg.type === 'set-capture-enabled') {
if (typeof msg.enabled === 'boolean') {
captureEnabled = msg.enabled;
}
sendResponse({ ok: true });
return false;
}
if (msg.type === 'get-latest-api') {
const tabId = msg.tabId;
const list = getCaptures(tabId);
const latest = list.find((e) => {
const rt = (e.resourceType || '').toLowerCase();
return rt === 'xhr' || rt === 'fetch';
});
sendResponse({ entry: latest || null });
return false;
}
return false;
});
chrome.runtime.onInstalled.addListener(() => {
if (chrome.contextMenus && chrome.contextMenus.removeAll) {
chrome.contextMenus.removeAll();
}
});