@opentabs-dev/browser-extension 0.0.34 → 0.0.35
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/background-message-handlers.d.ts.map +1 -1
- package/dist/background-message-handlers.js +13 -4
- package/dist/background-message-handlers.js.map +1 -1
- package/dist/background.js +231 -114
- package/dist/background.js.map +1 -1
- package/dist/browser-commands/cookie-commands.js +2 -2
- package/dist/browser-commands/cookie-commands.js.map +1 -1
- package/dist/browser-commands/extension-commands.d.ts.map +1 -1
- package/dist/browser-commands/extension-commands.js +37 -19
- package/dist/browser-commands/extension-commands.js.map +1 -1
- package/dist/browser-commands/index.d.ts +1 -1
- package/dist/browser-commands/index.d.ts.map +1 -1
- package/dist/browser-commands/index.js +1 -1
- package/dist/browser-commands/index.js.map +1 -1
- package/dist/browser-commands/interaction-commands.d.ts.map +1 -1
- package/dist/browser-commands/interaction-commands.js +5 -1
- package/dist/browser-commands/interaction-commands.js.map +1 -1
- package/dist/browser-commands/network-commands.d.ts +1 -0
- package/dist/browser-commands/network-commands.d.ts.map +1 -1
- package/dist/browser-commands/network-commands.js +16 -2
- package/dist/browser-commands/network-commands.js.map +1 -1
- package/dist/browser-commands/tab-commands.js +1 -1
- package/dist/browser-commands/tab-commands.js.map +1 -1
- package/dist/confirmation-badge.d.ts +16 -4
- package/dist/confirmation-badge.d.ts.map +1 -1
- package/dist/confirmation-badge.js +72 -7
- package/dist/confirmation-badge.js.map +1 -1
- package/dist/iife-injection.d.ts +1 -6
- package/dist/iife-injection.d.ts.map +1 -1
- package/dist/iife-injection.js +9 -34
- package/dist/iife-injection.js.map +1 -1
- package/dist/known-methods.d.ts +2 -2
- package/dist/known-methods.d.ts.map +1 -1
- package/dist/known-methods.js +1 -0
- package/dist/known-methods.js.map +1 -1
- package/dist/message-router.d.ts.map +1 -1
- package/dist/message-router.js +2 -1
- package/dist/message-router.js.map +1 -1
- package/dist/network-capture.d.ts +14 -1
- package/dist/network-capture.d.ts.map +1 -1
- package/dist/network-capture.js +103 -4
- package/dist/network-capture.js.map +1 -1
- package/dist/offscreen/index.d.ts +1 -1
- package/dist/offscreen/index.js +26 -30
- package/dist/offscreen/index.js.map +1 -1
- package/dist/offscreen/ws-utils.d.ts +8 -0
- package/dist/offscreen/ws-utils.d.ts.map +1 -0
- package/dist/offscreen/ws-utils.js +30 -0
- package/dist/offscreen/ws-utils.js.map +1 -0
- package/dist/rate-limiter.d.ts +2 -0
- package/dist/rate-limiter.d.ts.map +1 -1
- package/dist/rate-limiter.js +6 -0
- package/dist/rate-limiter.js.map +1 -1
- package/dist/sanitize-svg.d.ts +1 -1
- package/dist/sanitize-svg.js +1 -1
- package/dist/side-panel/App.d.ts.map +1 -1
- package/dist/side-panel/App.js +16 -2
- package/dist/side-panel/App.js.map +1 -1
- package/dist/side-panel/components/ConfirmationDialog.d.ts +8 -1
- package/dist/side-panel/components/ConfirmationDialog.d.ts.map +1 -1
- package/dist/side-panel/components/ConfirmationDialog.js +16 -8
- package/dist/side-panel/components/ConfirmationDialog.js.map +1 -1
- package/dist/side-panel/components/PluginCard.d.ts.map +1 -1
- package/dist/side-panel/components/PluginCard.js +2 -1
- package/dist/side-panel/components/PluginCard.js.map +1 -1
- package/dist/side-panel/constants.d.ts +2 -0
- package/dist/side-panel/constants.d.ts.map +1 -1
- package/dist/side-panel/constants.js +2 -0
- package/dist/side-panel/constants.js.map +1 -1
- package/dist/side-panel/hooks/useServerNotifications.d.ts.map +1 -1
- package/dist/side-panel/hooks/useServerNotifications.js +27 -3
- package/dist/side-panel/hooks/useServerNotifications.js.map +1 -1
- package/dist/side-panel/side-panel.js +4328 -4111
- package/dist/side-panel/styles.css +1 -1
- package/dist/side-panel-toggle.d.ts.map +1 -1
- package/dist/side-panel-toggle.js +21 -6
- package/dist/side-panel-toggle.js.map +1 -1
- package/dist/tab-state.d.ts.map +1 -1
- package/dist/tab-state.js +14 -4
- package/dist/tab-state.js.map +1 -1
- package/package.json +17 -17
package/dist/background.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
// dist/
|
|
1
|
+
// dist/background.js
|
|
2
2
|
var pendingConfirmationCount = 0;
|
|
3
|
+
var confirmationTimeouts = /* @__PURE__ */ new Map();
|
|
4
|
+
var CONFIRMATION_BACKGROUND_TIMEOUT_BUFFER_MS = 2e3;
|
|
5
|
+
var CONFIRMATION_FALLBACK_TIMEOUT_MS = 3e4;
|
|
3
6
|
var updateConfirmationBadge = () => {
|
|
4
7
|
if (pendingConfirmationCount > 0) {
|
|
5
8
|
chrome.action.setBadgeText({ text: String(pendingConfirmationCount) }).catch(() => {
|
|
@@ -12,11 +15,24 @@ var updateConfirmationBadge = () => {
|
|
|
12
15
|
}
|
|
13
16
|
};
|
|
14
17
|
var notifyConfirmationRequest = (params) => {
|
|
15
|
-
pendingConfirmationCount++;
|
|
16
|
-
updateConfirmationBadge();
|
|
17
18
|
const tool = typeof params.tool === "string" ? params.tool : "unknown tool";
|
|
18
19
|
const domain = typeof params.domain === "string" ? params.domain : "unknown domain";
|
|
19
|
-
|
|
20
|
+
const id = typeof params.id === "string" ? params.id : String(Date.now());
|
|
21
|
+
const timeoutMs = typeof params.timeoutMs === "number" ? params.timeoutMs : 0;
|
|
22
|
+
const existingTimeoutId = confirmationTimeouts.get(id);
|
|
23
|
+
if (existingTimeoutId !== void 0) {
|
|
24
|
+
clearTimeout(existingTimeoutId);
|
|
25
|
+
} else {
|
|
26
|
+
pendingConfirmationCount++;
|
|
27
|
+
updateConfirmationBadge();
|
|
28
|
+
}
|
|
29
|
+
const effectiveTimeoutMs = timeoutMs > 0 ? timeoutMs : CONFIRMATION_FALLBACK_TIMEOUT_MS;
|
|
30
|
+
const bgTimeoutId = setTimeout(() => {
|
|
31
|
+
confirmationTimeouts.delete(id);
|
|
32
|
+
clearConfirmationBadge(id);
|
|
33
|
+
}, effectiveTimeoutMs + CONFIRMATION_BACKGROUND_TIMEOUT_BUFFER_MS);
|
|
34
|
+
confirmationTimeouts.set(id, bgTimeoutId);
|
|
35
|
+
chrome.notifications.create(`opentabs-confirm-${id}`, {
|
|
20
36
|
type: "basic",
|
|
21
37
|
iconUrl: chrome.runtime.getURL("icons/icon-128.png"),
|
|
22
38
|
title: "OpenTabs: Approval Required",
|
|
@@ -26,11 +42,28 @@ var notifyConfirmationRequest = (params) => {
|
|
|
26
42
|
}).catch(() => {
|
|
27
43
|
});
|
|
28
44
|
};
|
|
29
|
-
var clearConfirmationBadge = () => {
|
|
45
|
+
var clearConfirmationBadge = (id) => {
|
|
46
|
+
if (id !== void 0) {
|
|
47
|
+
chrome.notifications.clear(`opentabs-confirm-${id}`).catch(() => {
|
|
48
|
+
});
|
|
49
|
+
}
|
|
30
50
|
pendingConfirmationCount = Math.max(0, pendingConfirmationCount - 1);
|
|
31
51
|
updateConfirmationBadge();
|
|
32
52
|
};
|
|
53
|
+
var clearConfirmationBackgroundTimeout = (id) => {
|
|
54
|
+
const timeoutId = confirmationTimeouts.get(id);
|
|
55
|
+
if (timeoutId !== void 0) {
|
|
56
|
+
clearTimeout(timeoutId);
|
|
57
|
+
confirmationTimeouts.delete(id);
|
|
58
|
+
}
|
|
59
|
+
};
|
|
33
60
|
var clearAllConfirmationBadges = () => {
|
|
61
|
+
for (const [id, timeoutId] of confirmationTimeouts.entries()) {
|
|
62
|
+
clearTimeout(timeoutId);
|
|
63
|
+
chrome.notifications.clear(`opentabs-confirm-${id}`).catch(() => {
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
confirmationTimeouts.clear();
|
|
34
67
|
pendingConfirmationCount = 0;
|
|
35
68
|
updateConfirmationBadge();
|
|
36
69
|
};
|
|
@@ -49,8 +82,6 @@ var initConfirmationBadge = () => {
|
|
|
49
82
|
}
|
|
50
83
|
});
|
|
51
84
|
};
|
|
52
|
-
|
|
53
|
-
// dist/constants.js
|
|
54
85
|
var KEEPALIVE_ALARM = "opentabs-keepalive";
|
|
55
86
|
var KEEPALIVE_INTERVAL_MINUTES = 0.5;
|
|
56
87
|
var PLUGINS_META_KEY = "plugins_meta";
|
|
@@ -78,15 +109,11 @@ var DEFAULT_LOG_LIMIT = 100;
|
|
|
78
109
|
var VALID_PLUGIN_NAME = /^[a-z0-9]+(-[a-z0-9]+)*$/;
|
|
79
110
|
var isValidPluginName = (name) => VALID_PLUGIN_NAME.test(name);
|
|
80
111
|
var buildWsUrl = (port) => `ws://localhost:${port}/ws`;
|
|
81
|
-
|
|
82
|
-
// dist/json-rpc-errors.js
|
|
83
112
|
var JSONRPC_METHOD_NOT_FOUND = -32601;
|
|
84
113
|
var JSONRPC_INVALID_PARAMS = -32602;
|
|
85
114
|
var JSONRPC_INTERNAL_ERROR = -32603;
|
|
86
115
|
var JSONRPC_NO_USABLE_TAB = -32001;
|
|
87
116
|
var JSONRPC_ADAPTER_NOT_READY = -32002;
|
|
88
|
-
|
|
89
|
-
// dist/messaging.js
|
|
90
117
|
var sendToServer = (data) => {
|
|
91
118
|
const method = data.method ?? "unknown";
|
|
92
119
|
chrome.runtime.sendMessage({ type: "ws:send", data }).catch((err2) => {
|
|
@@ -120,8 +147,6 @@ var sendTabStateNotification = (pluginName, stateInfo) => {
|
|
|
120
147
|
}
|
|
121
148
|
});
|
|
122
149
|
};
|
|
123
|
-
|
|
124
|
-
// dist/sanitize-error.js
|
|
125
150
|
var MAX_LENGTH = 500;
|
|
126
151
|
var sanitizeErrorMessage = (message) => {
|
|
127
152
|
let sanitized = message.replace(/[a-z]:[/\\][^\s,;)}\]]+/gi, "[PATH]").replace(/\/[a-z0-9._-]+(?:\/[a-z0-9._-]+)+/gi, "[PATH]").replace(/https?:\/\/[^\s,;)}\]]+/gi, "[URL]").replace(/localhost:\d+/gi, "[LOCALHOST]").replace(/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/g, "[IP]");
|
|
@@ -130,11 +155,7 @@ var sanitizeErrorMessage = (message) => {
|
|
|
130
155
|
}
|
|
131
156
|
return sanitized;
|
|
132
157
|
};
|
|
133
|
-
|
|
134
|
-
// ../shared/dist/error.js
|
|
135
158
|
var toErrorMessage = (err2) => err2 instanceof Error ? err2.message : String(err2);
|
|
136
|
-
|
|
137
|
-
// ../shared/dist/index.js
|
|
138
159
|
var BLOCKED_URL_SCHEMES = [
|
|
139
160
|
"javascript:",
|
|
140
161
|
"data:",
|
|
@@ -151,8 +172,6 @@ var isBlockedUrlScheme = (url) => {
|
|
|
151
172
|
return true;
|
|
152
173
|
}
|
|
153
174
|
};
|
|
154
|
-
|
|
155
|
-
// dist/browser-commands/helpers.js
|
|
156
175
|
var requireTabId = (params, id) => {
|
|
157
176
|
const tabId = params.tabId;
|
|
158
177
|
if (typeof tabId !== "number") {
|
|
@@ -245,8 +264,6 @@ var sendValidationError = (id, message) => {
|
|
|
245
264
|
var sendSuccessResult = (id, result) => {
|
|
246
265
|
sendToServer({ jsonrpc: "2.0", result, id });
|
|
247
266
|
};
|
|
248
|
-
|
|
249
|
-
// dist/browser-commands/content-commands.js
|
|
250
267
|
var handleBrowserGetTabContent = async (params, id) => {
|
|
251
268
|
try {
|
|
252
269
|
const tabId = requireTabId(params, id);
|
|
@@ -385,8 +402,6 @@ var handleBrowserScreenshotTab = async (params, id) => {
|
|
|
385
402
|
sendErrorResult(id, err2);
|
|
386
403
|
}
|
|
387
404
|
};
|
|
388
|
-
|
|
389
|
-
// dist/browser-commands/cookie-commands.js
|
|
390
405
|
var handleBrowserGetCookies = async (params, id) => {
|
|
391
406
|
try {
|
|
392
407
|
const url = requireUrl(params, id);
|
|
@@ -465,14 +480,12 @@ var handleBrowserDeleteCookies = async (params, id) => {
|
|
|
465
480
|
const name = requireStringParam(params, "name", id);
|
|
466
481
|
if (name === null)
|
|
467
482
|
return;
|
|
468
|
-
await chrome.cookies.remove({ url, name });
|
|
469
|
-
sendSuccessResult(id, { deleted:
|
|
483
|
+
const result = await chrome.cookies.remove({ url, name });
|
|
484
|
+
sendSuccessResult(id, { deleted: result !== null, name, url });
|
|
470
485
|
} catch (err2) {
|
|
471
486
|
sendErrorResult(id, err2);
|
|
472
487
|
}
|
|
473
488
|
};
|
|
474
|
-
|
|
475
|
-
// dist/log-collector.js
|
|
476
489
|
var MAX_MESSAGE_LENGTH = 2e3;
|
|
477
490
|
var DEFAULT_MAX_ENTRIES = 500;
|
|
478
491
|
var formatArg = (arg) => {
|
|
@@ -559,12 +572,10 @@ var installLogCollector = (source, maxEntries) => {
|
|
|
559
572
|
}
|
|
560
573
|
return collector;
|
|
561
574
|
};
|
|
562
|
-
|
|
563
|
-
// dist/background-log-state.js
|
|
564
575
|
var bgLogCollector = installLogCollector("background");
|
|
565
|
-
|
|
566
|
-
// dist/network-capture.js
|
|
567
576
|
var MAX_BODY_LENGTH = 102400;
|
|
577
|
+
var PENDING_REQUEST_TTL_MS = 6e4;
|
|
578
|
+
var PRUNE_INTERVAL_MS = 3e4;
|
|
568
579
|
var SENSITIVE_HEADERS = /* @__PURE__ */ new Set([
|
|
569
580
|
"authorization",
|
|
570
581
|
"cookie",
|
|
@@ -652,6 +663,17 @@ chrome.debugger.onEvent.addListener((source, method, params) => {
|
|
|
652
663
|
const request = paramsRecord?.request;
|
|
653
664
|
if (!requestId || !request)
|
|
654
665
|
return;
|
|
666
|
+
const now = Date.now();
|
|
667
|
+
for (const [id, pending] of state.pendingRequests) {
|
|
668
|
+
if (pending.timestamp !== void 0 && now - pending.timestamp > PENDING_REQUEST_TTL_MS) {
|
|
669
|
+
state.pendingRequests.delete(id);
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
for (const [id, req] of state.requestIdToRequest) {
|
|
673
|
+
if (now - req.timestamp > PENDING_REQUEST_TTL_MS) {
|
|
674
|
+
state.requestIdToRequest.delete(id);
|
|
675
|
+
}
|
|
676
|
+
}
|
|
655
677
|
const url = stringProp(request, "url", "");
|
|
656
678
|
if (state.urlFilter && !url.includes(state.urlFilter))
|
|
657
679
|
return;
|
|
@@ -727,15 +749,21 @@ chrome.debugger.onEvent.addListener((source, method, params) => {
|
|
|
727
749
|
const responseData = result;
|
|
728
750
|
if (typeof responseData.body !== "string")
|
|
729
751
|
return;
|
|
752
|
+
if (!state.requests.includes(request))
|
|
753
|
+
return;
|
|
730
754
|
const body = responseData.base64Encoded ? new TextDecoder().decode(Uint8Array.from(atob(responseData.body), (c) => c.charCodeAt(0))) : responseData.body;
|
|
731
755
|
request.responseBody = truncateBody(body);
|
|
732
756
|
});
|
|
733
757
|
} else if (method === "Network.webSocketCreated") {
|
|
734
758
|
const url = paramsRecord?.url;
|
|
759
|
+
const requestId = paramsRecord?.requestId;
|
|
735
760
|
if (!url)
|
|
736
761
|
return;
|
|
737
762
|
if (state.urlFilter && !url.includes(state.urlFilter))
|
|
738
763
|
return;
|
|
764
|
+
if (requestId) {
|
|
765
|
+
state.wsFramesByRequestId.set(requestId, url);
|
|
766
|
+
}
|
|
739
767
|
const completed = {
|
|
740
768
|
url,
|
|
741
769
|
method: "GET",
|
|
@@ -748,6 +776,27 @@ chrome.debugger.onEvent.addListener((source, method, params) => {
|
|
|
748
776
|
evictOldestRequest(state);
|
|
749
777
|
}
|
|
750
778
|
state.requests.push(completed);
|
|
779
|
+
} else if (method === "Network.webSocketFrameSent" || method === "Network.webSocketFrameReceived") {
|
|
780
|
+
const requestId = paramsRecord?.requestId;
|
|
781
|
+
const response = paramsRecord?.response;
|
|
782
|
+
if (!requestId || !response)
|
|
783
|
+
return;
|
|
784
|
+
const url = state.wsFramesByRequestId.get(requestId);
|
|
785
|
+
if (!url)
|
|
786
|
+
return;
|
|
787
|
+
const opcode = typeof response.opcode === "number" ? response.opcode : 1;
|
|
788
|
+
const payloadData = typeof response.payloadData === "string" ? response.payloadData : "";
|
|
789
|
+
const direction = method === "Network.webSocketFrameSent" ? "sent" : "received";
|
|
790
|
+
const data = truncateBody(payloadData);
|
|
791
|
+
if (state.wsFrames.length >= state.maxWsFrames) {
|
|
792
|
+
state.wsFrames.shift();
|
|
793
|
+
}
|
|
794
|
+
state.wsFrames.push({ url, direction, data, opcode, timestamp: Date.now() });
|
|
795
|
+
} else if (method === "Network.webSocketClosed") {
|
|
796
|
+
const requestId = paramsRecord?.requestId;
|
|
797
|
+
if (requestId) {
|
|
798
|
+
state.wsFramesByRequestId.delete(requestId);
|
|
799
|
+
}
|
|
751
800
|
} else if (method === "Runtime.consoleAPICalled") {
|
|
752
801
|
const type = paramsRecord?.type;
|
|
753
802
|
const args = paramsRecord?.args;
|
|
@@ -774,13 +823,24 @@ chrome.debugger.onEvent.addListener((source, method, params) => {
|
|
|
774
823
|
}
|
|
775
824
|
});
|
|
776
825
|
chrome.tabs.onRemoved.addListener((tabId) => {
|
|
777
|
-
|
|
826
|
+
const state = captures.get(tabId);
|
|
827
|
+
if (state) {
|
|
828
|
+
clearInterval(state.pruneIntervalId);
|
|
778
829
|
void chrome.debugger.detach({ tabId }).catch(() => {
|
|
779
830
|
});
|
|
780
831
|
captures.delete(tabId);
|
|
781
832
|
}
|
|
782
833
|
});
|
|
783
|
-
|
|
834
|
+
chrome.debugger.onDetach.addListener((source, _reason) => {
|
|
835
|
+
const tabId = source.tabId;
|
|
836
|
+
if (tabId !== void 0) {
|
|
837
|
+
const state = captures.get(tabId);
|
|
838
|
+
if (state)
|
|
839
|
+
clearInterval(state.pruneIntervalId);
|
|
840
|
+
captures.delete(tabId);
|
|
841
|
+
}
|
|
842
|
+
});
|
|
843
|
+
var startCapture = async (tabId, maxRequests = 100, urlFilter, maxConsoleLogs = 500, maxWsFrames = 200) => {
|
|
784
844
|
if (captures.has(tabId)) {
|
|
785
845
|
throw new Error(`Network capture already active for tab ${tabId}. Call stopCapture first.`);
|
|
786
846
|
}
|
|
@@ -797,20 +857,39 @@ var startCapture = async (tabId, maxRequests = 100, urlFilter, maxConsoleLogs =
|
|
|
797
857
|
});
|
|
798
858
|
throw err2;
|
|
799
859
|
}
|
|
800
|
-
|
|
860
|
+
const captureState = {
|
|
801
861
|
requests: [],
|
|
802
862
|
consoleLogs: [],
|
|
863
|
+
wsFrames: [],
|
|
803
864
|
maxRequests,
|
|
804
865
|
maxConsoleLogs,
|
|
866
|
+
maxWsFrames,
|
|
805
867
|
urlFilter,
|
|
806
868
|
pendingRequests: /* @__PURE__ */ new Map(),
|
|
807
|
-
requestIdToRequest: /* @__PURE__ */ new Map()
|
|
808
|
-
|
|
869
|
+
requestIdToRequest: /* @__PURE__ */ new Map(),
|
|
870
|
+
wsFramesByRequestId: /* @__PURE__ */ new Map()
|
|
871
|
+
};
|
|
872
|
+
captureState.pruneIntervalId = setInterval(() => {
|
|
873
|
+
const now = Date.now();
|
|
874
|
+
for (const [id, pending] of captureState.pendingRequests) {
|
|
875
|
+
if (pending.timestamp !== void 0 && now - pending.timestamp > PENDING_REQUEST_TTL_MS) {
|
|
876
|
+
captureState.pendingRequests.delete(id);
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
for (const [id, req] of captureState.requestIdToRequest) {
|
|
880
|
+
if (now - req.timestamp > PENDING_REQUEST_TTL_MS) {
|
|
881
|
+
captureState.requestIdToRequest.delete(id);
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
}, PRUNE_INTERVAL_MS);
|
|
885
|
+
captures.set(tabId, captureState);
|
|
809
886
|
};
|
|
810
887
|
var stopCapture = (tabId) => {
|
|
811
888
|
const state = captures.get(tabId);
|
|
812
889
|
if (!state)
|
|
813
890
|
return;
|
|
891
|
+
clearInterval(state.pruneIntervalId);
|
|
892
|
+
state.wsFramesByRequestId.clear();
|
|
814
893
|
void chrome.debugger.detach({ tabId }).catch(() => {
|
|
815
894
|
});
|
|
816
895
|
captures.delete(tabId);
|
|
@@ -827,6 +906,7 @@ var getRequests = (tabId, clear = false) => {
|
|
|
827
906
|
if (clear) {
|
|
828
907
|
state.requests = [];
|
|
829
908
|
state.requestIdToRequest.clear();
|
|
909
|
+
state.pendingRequests.clear();
|
|
830
910
|
}
|
|
831
911
|
return requests;
|
|
832
912
|
};
|
|
@@ -850,13 +930,22 @@ var clearConsoleLogs = (tabId) => {
|
|
|
850
930
|
state.consoleLogs = [];
|
|
851
931
|
}
|
|
852
932
|
};
|
|
933
|
+
var getWsFrames = (tabId, clear = false) => {
|
|
934
|
+
const state = captures.get(tabId);
|
|
935
|
+
if (!state)
|
|
936
|
+
return [];
|
|
937
|
+
const frames = [...state.wsFrames];
|
|
938
|
+
if (clear) {
|
|
939
|
+
state.wsFrames = [];
|
|
940
|
+
state.wsFramesByRequestId.clear();
|
|
941
|
+
}
|
|
942
|
+
return frames;
|
|
943
|
+
};
|
|
853
944
|
var getActiveCapturesSummary = () => Array.from(captures.entries()).map(([tabId, state]) => ({
|
|
854
945
|
tabId,
|
|
855
946
|
requestCount: state.requests.length,
|
|
856
947
|
isCapturing: true
|
|
857
948
|
}));
|
|
858
|
-
|
|
859
|
-
// dist/plugin-storage.js
|
|
860
949
|
var metaCache = null;
|
|
861
950
|
var writeMutex = Promise.resolve();
|
|
862
951
|
var serialize = (fn) => {
|
|
@@ -933,8 +1022,6 @@ var getPluginMeta = async (pluginName) => {
|
|
|
933
1022
|
var invalidatePluginCache = () => {
|
|
934
1023
|
metaCache = null;
|
|
935
1024
|
};
|
|
936
|
-
|
|
937
|
-
// dist/tab-matching.js
|
|
938
1025
|
var urlMatchesPatterns = (url, patterns) => {
|
|
939
1026
|
for (const pattern of patterns) {
|
|
940
1027
|
if (matchPattern(url, pattern))
|
|
@@ -1025,17 +1112,21 @@ var findAllMatchingTabs = async (plugin) => {
|
|
|
1025
1112
|
};
|
|
1026
1113
|
return allMatches.slice().sort((a, b) => rank(b) - rank(a));
|
|
1027
1114
|
};
|
|
1028
|
-
|
|
1029
|
-
// dist/tab-state.js
|
|
1030
1115
|
var lastKnownState = /* @__PURE__ */ new Map();
|
|
1031
1116
|
var pluginLocks = /* @__PURE__ */ new Map();
|
|
1032
1117
|
var withPluginLock = (pluginName, fn) => {
|
|
1033
1118
|
const prev = pluginLocks.get(pluginName) ?? Promise.resolve();
|
|
1034
|
-
const
|
|
1035
|
-
|
|
1119
|
+
const operation = prev.then(fn);
|
|
1120
|
+
const lock = operation.catch((err2) => {
|
|
1036
1121
|
console.warn("[opentabs] tab state operation failed for plugin", pluginName, ":", err2);
|
|
1037
|
-
})
|
|
1038
|
-
|
|
1122
|
+
});
|
|
1123
|
+
pluginLocks.set(pluginName, lock);
|
|
1124
|
+
void lock.then(() => {
|
|
1125
|
+
if (pluginLocks.get(pluginName) === lock) {
|
|
1126
|
+
pluginLocks.set(pluginName, Promise.resolve());
|
|
1127
|
+
}
|
|
1128
|
+
});
|
|
1129
|
+
return operation;
|
|
1039
1130
|
};
|
|
1040
1131
|
var probeTabReadiness = async (tabId, pluginName) => {
|
|
1041
1132
|
let timerId;
|
|
@@ -1201,8 +1292,6 @@ var checkTabChanged = async (changedTabId, changeInfo) => {
|
|
|
1201
1292
|
return;
|
|
1202
1293
|
await notifyAffectedPlugins(affectedPlugins);
|
|
1203
1294
|
};
|
|
1204
|
-
|
|
1205
|
-
// dist/browser-commands/extension-commands.js
|
|
1206
1295
|
var handleExtensionGetState = async (id) => {
|
|
1207
1296
|
try {
|
|
1208
1297
|
const sessionData = await chrome.storage.session.get(WS_CONNECTED_KEY).catch(() => ({}));
|
|
@@ -1294,10 +1383,18 @@ var handleExtensionGetLogs = async (params, id) => {
|
|
|
1294
1383
|
};
|
|
1295
1384
|
var handleExtensionGetSidePanel = async (id) => {
|
|
1296
1385
|
try {
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1386
|
+
let timeoutId;
|
|
1387
|
+
let sidePanelResult;
|
|
1388
|
+
try {
|
|
1389
|
+
sidePanelResult = await Promise.race([
|
|
1390
|
+
chrome.runtime.sendMessage({ type: "sp:getState" }).then((raw) => raw),
|
|
1391
|
+
new Promise((resolve) => {
|
|
1392
|
+
timeoutId = setTimeout(() => resolve(null), SIDE_PANEL_TIMEOUT_MS);
|
|
1393
|
+
})
|
|
1394
|
+
]);
|
|
1395
|
+
} finally {
|
|
1396
|
+
clearTimeout(timeoutId);
|
|
1397
|
+
}
|
|
1301
1398
|
if (!sidePanelResult || typeof sidePanelResult !== "object") {
|
|
1302
1399
|
sendSuccessResult(id, { open: false });
|
|
1303
1400
|
return;
|
|
@@ -1376,21 +1473,29 @@ var handleExtensionCheckAdapter = async (params, id) => {
|
|
|
1376
1473
|
}
|
|
1377
1474
|
let isReady = false;
|
|
1378
1475
|
try {
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1476
|
+
let isReadyTimeoutId;
|
|
1477
|
+
let readyResults;
|
|
1478
|
+
try {
|
|
1479
|
+
readyResults = await Promise.race([
|
|
1480
|
+
chrome.scripting.executeScript({
|
|
1481
|
+
target: { tabId },
|
|
1482
|
+
world: "MAIN",
|
|
1483
|
+
func: async (pName) => {
|
|
1484
|
+
const ot = globalThis.__openTabs;
|
|
1485
|
+
const adapter = ot?.adapters?.[pName];
|
|
1486
|
+
if (!adapter || typeof adapter.isReady !== "function")
|
|
1487
|
+
return false;
|
|
1488
|
+
return await adapter.isReady();
|
|
1489
|
+
},
|
|
1490
|
+
args: [pluginName]
|
|
1491
|
+
}),
|
|
1492
|
+
new Promise((resolve) => {
|
|
1493
|
+
isReadyTimeoutId = setTimeout(() => resolve(null), IS_READY_TIMEOUT_MS);
|
|
1494
|
+
})
|
|
1495
|
+
]);
|
|
1496
|
+
} finally {
|
|
1497
|
+
clearTimeout(isReadyTimeoutId);
|
|
1498
|
+
}
|
|
1394
1499
|
if (readyResults !== null) {
|
|
1395
1500
|
const readyResult = readyResults[0];
|
|
1396
1501
|
isReady = readyResult?.result === true;
|
|
@@ -1524,8 +1629,6 @@ var handleBrowserExecuteScript = async (params, id) => {
|
|
|
1524
1629
|
sendErrorResult(id, err2);
|
|
1525
1630
|
}
|
|
1526
1631
|
};
|
|
1527
|
-
|
|
1528
|
-
// dist/browser-commands/resource-commands.js
|
|
1529
1632
|
var TEXT_MIME_PREFIXES = ["text/"];
|
|
1530
1633
|
var TEXT_MIME_EXACT = /* @__PURE__ */ new Set([
|
|
1531
1634
|
"application/javascript",
|
|
@@ -1651,8 +1754,6 @@ var handleBrowserGetResourceContent = async (params, id) => {
|
|
|
1651
1754
|
sendErrorResult(id, err2);
|
|
1652
1755
|
}
|
|
1653
1756
|
};
|
|
1654
|
-
|
|
1655
|
-
// dist/browser-commands/interaction-commands.js
|
|
1656
1757
|
var handleBrowserClickElement = async (params, id) => {
|
|
1657
1758
|
try {
|
|
1658
1759
|
const tabId = requireTabId(params, id);
|
|
@@ -1827,7 +1928,8 @@ var handleBrowserWaitForElement = async (params, id) => {
|
|
|
1827
1928
|
const el = document.querySelector(sel);
|
|
1828
1929
|
if (el) {
|
|
1829
1930
|
const htmlEl = el;
|
|
1830
|
-
const
|
|
1931
|
+
const style = getComputedStyle(htmlEl);
|
|
1932
|
+
const isVisible = !vis || style.display !== "none" && style.visibility !== "hidden" && (htmlEl.offsetParent !== null || style.position === "fixed" || style.position === "sticky");
|
|
1831
1933
|
if (isVisible) {
|
|
1832
1934
|
clearInterval(poll);
|
|
1833
1935
|
resolve({
|
|
@@ -1972,8 +2074,6 @@ var handleBrowserHandleDialog = async (params, id) => {
|
|
|
1972
2074
|
sendErrorResult(id, err2);
|
|
1973
2075
|
}
|
|
1974
2076
|
};
|
|
1975
|
-
|
|
1976
|
-
// dist/browser-commands/key-press-command.js
|
|
1977
2077
|
var handleBrowserPressKey = async (params, id) => {
|
|
1978
2078
|
try {
|
|
1979
2079
|
const tabId = requireTabId(params, id);
|
|
@@ -2105,8 +2205,6 @@ var handleBrowserPressKey = async (params, id) => {
|
|
|
2105
2205
|
sendErrorResult(id, err2);
|
|
2106
2206
|
}
|
|
2107
2207
|
};
|
|
2108
|
-
|
|
2109
|
-
// dist/browser-commands/scroll-command.js
|
|
2110
2208
|
var handleBrowserScroll = async (params, id) => {
|
|
2111
2209
|
try {
|
|
2112
2210
|
const tabId = requireTabId(params, id);
|
|
@@ -2220,8 +2318,6 @@ var handleBrowserScroll = async (params, id) => {
|
|
|
2220
2318
|
sendErrorResult(id, err2);
|
|
2221
2319
|
}
|
|
2222
2320
|
};
|
|
2223
|
-
|
|
2224
|
-
// dist/browser-commands/network-commands.js
|
|
2225
2321
|
var handleBrowserEnableNetworkCapture = async (params, id) => {
|
|
2226
2322
|
try {
|
|
2227
2323
|
const tabId = requireTabId(params, id);
|
|
@@ -2230,7 +2326,8 @@ var handleBrowserEnableNetworkCapture = async (params, id) => {
|
|
|
2230
2326
|
const maxRequests = typeof params.maxRequests === "number" ? params.maxRequests : 100;
|
|
2231
2327
|
const urlFilter = typeof params.urlFilter === "string" ? params.urlFilter : void 0;
|
|
2232
2328
|
const maxConsoleLogs = typeof params.maxConsoleLogs === "number" ? params.maxConsoleLogs : 500;
|
|
2233
|
-
|
|
2329
|
+
const maxWsFrames = typeof params.maxWsFrames === "number" ? params.maxWsFrames : 200;
|
|
2330
|
+
await startCapture(tabId, maxRequests, urlFilter, maxConsoleLogs, maxWsFrames);
|
|
2234
2331
|
sendSuccessResult(id, { enabled: true, tabId });
|
|
2235
2332
|
} catch (err2) {
|
|
2236
2333
|
sendErrorResult(id, err2);
|
|
@@ -2283,8 +2380,18 @@ var handleBrowserClearConsoleLogs = (params, id) => {
|
|
|
2283
2380
|
sendErrorResult(id, err2);
|
|
2284
2381
|
}
|
|
2285
2382
|
};
|
|
2286
|
-
|
|
2287
|
-
|
|
2383
|
+
var handleBrowserGetWebSocketFrames = (params, id) => {
|
|
2384
|
+
try {
|
|
2385
|
+
const tabId = requireTabId(params, id);
|
|
2386
|
+
if (tabId === null)
|
|
2387
|
+
return;
|
|
2388
|
+
const clear = typeof params.clear === "boolean" ? params.clear : false;
|
|
2389
|
+
const frames = getWsFrames(tabId, clear);
|
|
2390
|
+
sendSuccessResult(id, { frames });
|
|
2391
|
+
} catch (err2) {
|
|
2392
|
+
sendErrorResult(id, err2);
|
|
2393
|
+
}
|
|
2394
|
+
};
|
|
2288
2395
|
var handleBrowserListTabs = async (id) => {
|
|
2289
2396
|
try {
|
|
2290
2397
|
const tabs = await chrome.tabs.query({});
|
|
@@ -2331,7 +2438,7 @@ var handleBrowserNavigateTab = async (params, id) => {
|
|
|
2331
2438
|
if (url === null)
|
|
2332
2439
|
return;
|
|
2333
2440
|
const tab = await chrome.tabs.update(tabId, { url });
|
|
2334
|
-
sendSuccessResult(id, { id: tab?.id ?? tabId, title: tab?.title ?? "", url
|
|
2441
|
+
sendSuccessResult(id, { id: tab?.id ?? tabId, title: tab?.title ?? "", url });
|
|
2335
2442
|
} catch (err2) {
|
|
2336
2443
|
sendErrorResult(id, err2);
|
|
2337
2444
|
}
|
|
@@ -2372,8 +2479,6 @@ var handleBrowserGetTabInfo = async (params, id) => {
|
|
|
2372
2479
|
sendErrorResult(id, err2);
|
|
2373
2480
|
}
|
|
2374
2481
|
};
|
|
2375
|
-
|
|
2376
|
-
// dist/iife-injection.js
|
|
2377
2482
|
var RESERVED_NAMES = /* @__PURE__ */ new Set(["system", "browser", "opentabs", "extension", "config", "plugin", "tool", "mcp"]);
|
|
2378
2483
|
var isSafePluginName = (name) => isValidPluginName(name) && !RESERVED_NAMES.has(name);
|
|
2379
2484
|
var isAdapterPresent = async (tabId, pluginName) => {
|
|
@@ -2449,8 +2554,10 @@ var injectLogRelay = async (tabId) => {
|
|
|
2449
2554
|
const win = window;
|
|
2450
2555
|
if (win[guard]) {
|
|
2451
2556
|
const nonceSet = win.__opentabs_log_nonces;
|
|
2452
|
-
if (nonceSet)
|
|
2557
|
+
if (nonceSet) {
|
|
2558
|
+
nonceSet.clear();
|
|
2453
2559
|
nonceSet.add(n);
|
|
2560
|
+
}
|
|
2454
2561
|
return;
|
|
2455
2562
|
}
|
|
2456
2563
|
win[guard] = true;
|
|
@@ -2683,8 +2790,6 @@ var reinjectStoredPlugins = async () => {
|
|
|
2683
2790
|
}
|
|
2684
2791
|
}
|
|
2685
2792
|
};
|
|
2686
|
-
|
|
2687
|
-
// dist/rate-limiter.js
|
|
2688
2793
|
var METHOD_LIMITS = /* @__PURE__ */ new Map([
|
|
2689
2794
|
// Expensive operations — tight limits
|
|
2690
2795
|
["browser.screenshotTab", { maxRequests: 2, windowMs: 1e3 }],
|
|
@@ -2702,6 +2807,9 @@ var checkRateLimit = (method, now = Date.now()) => {
|
|
|
2702
2807
|
const config = METHOD_LIMITS.get(method) ?? DEFAULT_LIMIT;
|
|
2703
2808
|
const cutoff = now - config.windowMs;
|
|
2704
2809
|
const timestamps = (methodTimestamps.get(method) ?? []).filter((t) => t > cutoff);
|
|
2810
|
+
if (timestamps.length === 0) {
|
|
2811
|
+
methodTimestamps.delete(method);
|
|
2812
|
+
}
|
|
2705
2813
|
if (timestamps.length >= config.maxRequests) {
|
|
2706
2814
|
methodTimestamps.set(method, timestamps);
|
|
2707
2815
|
return false;
|
|
@@ -2710,8 +2818,6 @@ var checkRateLimit = (method, now = Date.now()) => {
|
|
|
2710
2818
|
methodTimestamps.set(method, timestamps);
|
|
2711
2819
|
return true;
|
|
2712
2820
|
};
|
|
2713
|
-
|
|
2714
|
-
// dist/dispatch-helpers.js
|
|
2715
2821
|
var isAdapterNotReady = (result) => result.type === "error" && result.code === JSONRPC_ADAPTER_NOT_READY;
|
|
2716
2822
|
var resolvePlugin = async (pluginName, id) => {
|
|
2717
2823
|
const plugin = await getPluginMeta(pluginName);
|
|
@@ -2818,8 +2924,6 @@ var dispatchWithTabFallback = async (config) => {
|
|
|
2818
2924
|
});
|
|
2819
2925
|
}
|
|
2820
2926
|
};
|
|
2821
|
-
|
|
2822
|
-
// dist/resource-prompt-dispatch.js
|
|
2823
2927
|
var executeResourceReadOnTab = async (tabId, pluginName, resourceUri) => {
|
|
2824
2928
|
const scriptPromise = chrome.scripting.executeScript({
|
|
2825
2929
|
target: { tabId },
|
|
@@ -2986,8 +3090,6 @@ var handlePromptGet = async (params, id) => {
|
|
|
2986
3090
|
executeOnTab: (tabId) => executePromptGetOnTab(tabId, pluginName, promptName, promptArgs)
|
|
2987
3091
|
});
|
|
2988
3092
|
};
|
|
2989
|
-
|
|
2990
|
-
// dist/tool-dispatch.js
|
|
2991
3093
|
var progressCallbacks = /* @__PURE__ */ new Map();
|
|
2992
3094
|
var notifyDispatchProgress = (dispatchId) => {
|
|
2993
3095
|
const cb = progressCallbacks.get(dispatchId);
|
|
@@ -3245,8 +3347,6 @@ var handleToolDispatch = async (params, id) => {
|
|
|
3245
3347
|
}
|
|
3246
3348
|
});
|
|
3247
3349
|
};
|
|
3248
|
-
|
|
3249
|
-
// dist/message-router.js
|
|
3250
3350
|
var wrapAsync = (method, fn) => (params, id) => {
|
|
3251
3351
|
if (id !== void 0) {
|
|
3252
3352
|
fn(params, id).catch((err2) => console.warn(`[opentabs] ${method} handler failed:`, err2));
|
|
@@ -3455,6 +3555,7 @@ var methodHandlers = /* @__PURE__ */ new Map([
|
|
|
3455
3555
|
["browser.deleteCookies", wrapAsync("browser.deleteCookies", handleBrowserDeleteCookies)],
|
|
3456
3556
|
["browser.enableNetworkCapture", wrapAsync("browser.enableNetworkCapture", handleBrowserEnableNetworkCapture)],
|
|
3457
3557
|
["browser.getNetworkRequests", wrapSync("browser.getNetworkRequests", handleBrowserGetNetworkRequests)],
|
|
3558
|
+
["browser.getWebSocketFrames", wrapSync("browser.getWebSocketFrames", handleBrowserGetWebSocketFrames)],
|
|
3458
3559
|
["browser.disableNetworkCapture", wrapSync("browser.disableNetworkCapture", handleBrowserDisableNetworkCapture)],
|
|
3459
3560
|
["browser.getConsoleLogs", wrapSync("browser.getConsoleLogs", handleBrowserGetConsoleLogs)],
|
|
3460
3561
|
["browser.clearConsoleLogs", wrapSync("browser.clearConsoleLogs", handleBrowserClearConsoleLogs)],
|
|
@@ -3512,8 +3613,6 @@ var handleServerMessage = (message) => {
|
|
|
3512
3613
|
}
|
|
3513
3614
|
};
|
|
3514
3615
|
var methodHandlerNames = Array.from(methodHandlers.keys());
|
|
3515
|
-
|
|
3516
|
-
// dist/background-message-handlers.js
|
|
3517
3616
|
var wsConnected = false;
|
|
3518
3617
|
var lastDisconnectReason;
|
|
3519
3618
|
var restoreWsConnectedState = () => {
|
|
@@ -3623,11 +3722,20 @@ var handleSpConfirmationResponse = (message, sendResponse) => {
|
|
|
3623
3722
|
params: message.data
|
|
3624
3723
|
});
|
|
3625
3724
|
}
|
|
3626
|
-
|
|
3725
|
+
const data = message.data;
|
|
3726
|
+
const id = typeof data?.id === "string" ? data.id : void 0;
|
|
3727
|
+
if (id !== void 0) {
|
|
3728
|
+
clearConfirmationBackgroundTimeout(id);
|
|
3729
|
+
}
|
|
3730
|
+
clearConfirmationBadge(id);
|
|
3627
3731
|
sendResponse({ ok: true });
|
|
3628
3732
|
};
|
|
3629
|
-
var handleSpConfirmationTimeout = (
|
|
3630
|
-
|
|
3733
|
+
var handleSpConfirmationTimeout = (message, sendResponse) => {
|
|
3734
|
+
const id = typeof message.id === "string" ? message.id : void 0;
|
|
3735
|
+
if (id !== void 0) {
|
|
3736
|
+
clearConfirmationBackgroundTimeout(id);
|
|
3737
|
+
}
|
|
3738
|
+
clearConfirmationBadge(id);
|
|
3631
3739
|
sendResponse({ ok: true });
|
|
3632
3740
|
};
|
|
3633
3741
|
var handlePortChanged = (message, sendResponse) => {
|
|
@@ -3670,8 +3778,6 @@ var initBackgroundMessageHandlers = () => {
|
|
|
3670
3778
|
});
|
|
3671
3779
|
};
|
|
3672
3780
|
var backgroundHandlerNames = [...backgroundHandlers.keys()];
|
|
3673
|
-
|
|
3674
|
-
// dist/side-panel-toggle.js
|
|
3675
3781
|
var openWindows = /* @__PURE__ */ new Set();
|
|
3676
3782
|
var initSidePanelToggle = () => {
|
|
3677
3783
|
chrome.sidePanel.setPanelBehavior({ openPanelOnActionClick: false }).catch(() => {
|
|
@@ -3684,19 +3790,30 @@ var initSidePanelToggle = () => {
|
|
|
3684
3790
|
chrome.sidePanel.onClosed.addListener(({ windowId }) => {
|
|
3685
3791
|
openWindows.delete(windowId);
|
|
3686
3792
|
});
|
|
3793
|
+
chrome.windows.onRemoved.addListener((windowId) => {
|
|
3794
|
+
openWindows.delete(windowId);
|
|
3795
|
+
});
|
|
3687
3796
|
}
|
|
3688
3797
|
chrome.action.onClicked.addListener(({ windowId }) => {
|
|
3689
|
-
|
|
3690
|
-
|
|
3691
|
-
|
|
3692
|
-
|
|
3693
|
-
|
|
3694
|
-
|
|
3695
|
-
|
|
3798
|
+
void (async () => {
|
|
3799
|
+
if (canToggle && openWindows.has(windowId)) {
|
|
3800
|
+
try {
|
|
3801
|
+
await chrome.windows.get(windowId);
|
|
3802
|
+
} catch {
|
|
3803
|
+
openWindows.delete(windowId);
|
|
3804
|
+
await chrome.sidePanel.open({ windowId }).catch(() => {
|
|
3805
|
+
});
|
|
3806
|
+
return;
|
|
3807
|
+
}
|
|
3808
|
+
chrome.sidePanel.close({ windowId }).catch(() => {
|
|
3809
|
+
});
|
|
3810
|
+
} else {
|
|
3811
|
+
chrome.sidePanel.open({ windowId }).catch(() => {
|
|
3812
|
+
});
|
|
3813
|
+
}
|
|
3814
|
+
})();
|
|
3696
3815
|
});
|
|
3697
3816
|
};
|
|
3698
|
-
|
|
3699
|
-
// dist/background.js
|
|
3700
3817
|
initSidePanelToggle();
|
|
3701
3818
|
restoreWsConnectedState();
|
|
3702
3819
|
var creatingOffscreen = null;
|
|
@@ -3752,14 +3869,14 @@ chrome.runtime.onInstalled.addListener(() => {
|
|
|
3752
3869
|
await ensureOffscreenDocument();
|
|
3753
3870
|
await setupKeepaliveAlarm();
|
|
3754
3871
|
await reinjectStoredPlugins();
|
|
3755
|
-
})();
|
|
3872
|
+
})().catch((err2) => console.warn("[opentabs] onInstalled failed:", err2));
|
|
3756
3873
|
});
|
|
3757
3874
|
chrome.runtime.onStartup.addListener(() => {
|
|
3758
3875
|
void (async () => {
|
|
3759
3876
|
await ensureOffscreenDocument();
|
|
3760
3877
|
await setupKeepaliveAlarm();
|
|
3761
3878
|
await reinjectStoredPlugins();
|
|
3762
|
-
})();
|
|
3879
|
+
})().catch((err2) => console.warn("[opentabs] onStartup failed:", err2));
|
|
3763
3880
|
});
|
|
3764
3881
|
ensureOffscreenDocument().catch((err2) => console.warn("[opentabs] offscreen creation failed:", err2));
|
|
3765
3882
|
setupKeepaliveAlarm().catch((err2) => console.warn("[opentabs] keepalive alarm failed:", err2));
|
|
@@ -3769,7 +3886,7 @@ chrome.storage.onChanged.addListener((changes, area) => {
|
|
|
3769
3886
|
if (area !== "local")
|
|
3770
3887
|
return;
|
|
3771
3888
|
const portChange = changes[SERVER_PORT_KEY];
|
|
3772
|
-
if (typeof portChange?.newValue === "number" && portChange.newValue
|
|
3889
|
+
if (typeof portChange?.newValue === "number" && Number.isInteger(portChange.newValue) && portChange.newValue >= 1 && portChange.newValue <= 65535) {
|
|
3773
3890
|
const newUrl = buildWsUrl(portChange.newValue);
|
|
3774
3891
|
chrome.runtime.sendMessage({ type: "ws:setUrl", url: newUrl }).catch(() => {
|
|
3775
3892
|
});
|