@opentabs-dev/browser-extension 0.0.34 → 0.0.36
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 +17 -6
- package/dist/background-message-handlers.js.map +1 -1
- package/dist/background.js +339 -103
- 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 +2 -0
- package/dist/browser-commands/extension-commands.d.ts.map +1 -1
- package/dist/browser-commands/extension-commands.js +75 -43
- 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 +24 -14
- 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 +26 -4
- package/dist/confirmation-badge.d.ts.map +1 -1
- package/dist/confirmation-badge.js +108 -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 +167 -23
- package/dist/network-capture.js.map +1 -1
- package/dist/offscreen/index.d.ts +1 -1
- package/dist/offscreen/index.js +41 -24
- 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 +10 -2
- 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 +4336 -4112
- 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,9 @@
|
|
|
1
1
|
// dist/confirmation-badge.js
|
|
2
2
|
var pendingConfirmationCount = 0;
|
|
3
|
+
var confirmationTimeouts = /* @__PURE__ */ new Map();
|
|
4
|
+
var clearedConfirmationIds = /* @__PURE__ */ new Set();
|
|
5
|
+
var CONFIRMATION_BACKGROUND_TIMEOUT_BUFFER_MS = 2e3;
|
|
6
|
+
var CONFIRMATION_FALLBACK_TIMEOUT_MS = 3e4;
|
|
3
7
|
var updateConfirmationBadge = () => {
|
|
4
8
|
if (pendingConfirmationCount > 0) {
|
|
5
9
|
chrome.action.setBadgeText({ text: String(pendingConfirmationCount) }).catch(() => {
|
|
@@ -12,11 +16,26 @@ var updateConfirmationBadge = () => {
|
|
|
12
16
|
}
|
|
13
17
|
};
|
|
14
18
|
var notifyConfirmationRequest = (params) => {
|
|
15
|
-
pendingConfirmationCount++;
|
|
16
|
-
updateConfirmationBadge();
|
|
17
19
|
const tool = typeof params.tool === "string" ? params.tool : "unknown tool";
|
|
18
20
|
const domain = typeof params.domain === "string" ? params.domain : "unknown domain";
|
|
19
|
-
|
|
21
|
+
const id = typeof params.id === "string" ? params.id : String(Date.now());
|
|
22
|
+
const timeoutMs = typeof params.timeoutMs === "number" ? params.timeoutMs : 0;
|
|
23
|
+
const existingTimeoutId = confirmationTimeouts.get(id);
|
|
24
|
+
if (existingTimeoutId !== void 0) {
|
|
25
|
+
clearTimeout(existingTimeoutId);
|
|
26
|
+
} else {
|
|
27
|
+
clearedConfirmationIds.delete(id);
|
|
28
|
+
pendingConfirmationCount++;
|
|
29
|
+
updateConfirmationBadge();
|
|
30
|
+
}
|
|
31
|
+
const effectiveTimeoutMs = timeoutMs > 0 ? timeoutMs : CONFIRMATION_FALLBACK_TIMEOUT_MS;
|
|
32
|
+
const bgTimeoutId = setTimeout(() => {
|
|
33
|
+
confirmationTimeouts.delete(id);
|
|
34
|
+
clearConfirmationBadge(id);
|
|
35
|
+
clearedConfirmationIds.delete(id);
|
|
36
|
+
}, effectiveTimeoutMs + CONFIRMATION_BACKGROUND_TIMEOUT_BUFFER_MS);
|
|
37
|
+
confirmationTimeouts.set(id, bgTimeoutId);
|
|
38
|
+
chrome.notifications.create(`opentabs-confirm-${id}`, {
|
|
20
39
|
type: "basic",
|
|
21
40
|
iconUrl: chrome.runtime.getURL("icons/icon-128.png"),
|
|
22
41
|
title: "OpenTabs: Approval Required",
|
|
@@ -26,11 +45,37 @@ var notifyConfirmationRequest = (params) => {
|
|
|
26
45
|
}).catch(() => {
|
|
27
46
|
});
|
|
28
47
|
};
|
|
29
|
-
var clearConfirmationBadge = () => {
|
|
48
|
+
var clearConfirmationBadge = (id) => {
|
|
49
|
+
if (id !== void 0) {
|
|
50
|
+
if (clearedConfirmationIds.has(id)) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
clearedConfirmationIds.add(id);
|
|
54
|
+
chrome.notifications.clear(`opentabs-confirm-${id}`).catch(() => {
|
|
55
|
+
});
|
|
56
|
+
}
|
|
30
57
|
pendingConfirmationCount = Math.max(0, pendingConfirmationCount - 1);
|
|
31
58
|
updateConfirmationBadge();
|
|
59
|
+
if (id !== void 0 && !confirmationTimeouts.has(id)) {
|
|
60
|
+
clearedConfirmationIds.delete(id);
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
var clearConfirmationBackgroundTimeout = (id) => {
|
|
64
|
+
const timeoutId = confirmationTimeouts.get(id);
|
|
65
|
+
if (timeoutId !== void 0) {
|
|
66
|
+
clearTimeout(timeoutId);
|
|
67
|
+
confirmationTimeouts.delete(id);
|
|
68
|
+
clearedConfirmationIds.delete(id);
|
|
69
|
+
}
|
|
32
70
|
};
|
|
33
71
|
var clearAllConfirmationBadges = () => {
|
|
72
|
+
for (const [id, timeoutId] of confirmationTimeouts.entries()) {
|
|
73
|
+
clearTimeout(timeoutId);
|
|
74
|
+
chrome.notifications.clear(`opentabs-confirm-${id}`).catch(() => {
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
confirmationTimeouts.clear();
|
|
78
|
+
clearedConfirmationIds.clear();
|
|
34
79
|
pendingConfirmationCount = 0;
|
|
35
80
|
updateConfirmationBadge();
|
|
36
81
|
};
|
|
@@ -465,8 +510,8 @@ var handleBrowserDeleteCookies = async (params, id) => {
|
|
|
465
510
|
const name = requireStringParam(params, "name", id);
|
|
466
511
|
if (name === null)
|
|
467
512
|
return;
|
|
468
|
-
await chrome.cookies.remove({ url, name });
|
|
469
|
-
sendSuccessResult(id, { deleted:
|
|
513
|
+
const result = await chrome.cookies.remove({ url, name });
|
|
514
|
+
sendSuccessResult(id, { deleted: result !== null, name, url });
|
|
470
515
|
} catch (err2) {
|
|
471
516
|
sendErrorResult(id, err2);
|
|
472
517
|
}
|
|
@@ -565,6 +610,9 @@ var bgLogCollector = installLogCollector("background");
|
|
|
565
610
|
|
|
566
611
|
// dist/network-capture.js
|
|
567
612
|
var MAX_BODY_LENGTH = 102400;
|
|
613
|
+
var PENDING_REQUEST_TTL_MS = 6e4;
|
|
614
|
+
var PRUNE_INTERVAL_MS = 3e4;
|
|
615
|
+
var WS_TTL_MS = 5 * 6e4;
|
|
568
616
|
var SENSITIVE_HEADERS = /* @__PURE__ */ new Set([
|
|
569
617
|
"authorization",
|
|
570
618
|
"cookie",
|
|
@@ -596,6 +644,7 @@ var scrubHeaders = (headers) => {
|
|
|
596
644
|
return scrubbed;
|
|
597
645
|
};
|
|
598
646
|
var captures = /* @__PURE__ */ new Map();
|
|
647
|
+
var pendingCaptures = /* @__PURE__ */ new Map();
|
|
599
648
|
var headersToRecord = (raw) => {
|
|
600
649
|
if (!raw)
|
|
601
650
|
return void 0;
|
|
@@ -652,6 +701,23 @@ chrome.debugger.onEvent.addListener((source, method, params) => {
|
|
|
652
701
|
const request = paramsRecord?.request;
|
|
653
702
|
if (!requestId || !request)
|
|
654
703
|
return;
|
|
704
|
+
const now = Date.now();
|
|
705
|
+
for (const [id, pending] of state.pendingRequests) {
|
|
706
|
+
if (pending.timestamp !== void 0 && now - pending.timestamp > PENDING_REQUEST_TTL_MS) {
|
|
707
|
+
state.pendingRequests.delete(id);
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
for (const [id, req] of state.requestIdToRequest) {
|
|
711
|
+
if (now - req.timestamp > PENDING_REQUEST_TTL_MS) {
|
|
712
|
+
state.requestIdToRequest.delete(id);
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
for (const [id, createdAt] of state.wsCreatedAt) {
|
|
716
|
+
if (now - createdAt > WS_TTL_MS) {
|
|
717
|
+
state.wsFramesByRequestId.delete(id);
|
|
718
|
+
state.wsCreatedAt.delete(id);
|
|
719
|
+
}
|
|
720
|
+
}
|
|
655
721
|
const url = stringProp(request, "url", "");
|
|
656
722
|
if (state.urlFilter && !url.includes(state.urlFilter))
|
|
657
723
|
return;
|
|
@@ -727,15 +793,22 @@ chrome.debugger.onEvent.addListener((source, method, params) => {
|
|
|
727
793
|
const responseData = result;
|
|
728
794
|
if (typeof responseData.body !== "string")
|
|
729
795
|
return;
|
|
796
|
+
if (!state.requests.includes(request))
|
|
797
|
+
return;
|
|
730
798
|
const body = responseData.base64Encoded ? new TextDecoder().decode(Uint8Array.from(atob(responseData.body), (c) => c.charCodeAt(0))) : responseData.body;
|
|
731
799
|
request.responseBody = truncateBody(body);
|
|
732
800
|
});
|
|
733
801
|
} else if (method === "Network.webSocketCreated") {
|
|
734
802
|
const url = paramsRecord?.url;
|
|
803
|
+
const requestId = paramsRecord?.requestId;
|
|
735
804
|
if (!url)
|
|
736
805
|
return;
|
|
737
806
|
if (state.urlFilter && !url.includes(state.urlFilter))
|
|
738
807
|
return;
|
|
808
|
+
if (requestId) {
|
|
809
|
+
state.wsFramesByRequestId.set(requestId, url);
|
|
810
|
+
state.wsCreatedAt.set(requestId, Date.now());
|
|
811
|
+
}
|
|
739
812
|
const completed = {
|
|
740
813
|
url,
|
|
741
814
|
method: "GET",
|
|
@@ -748,6 +821,28 @@ chrome.debugger.onEvent.addListener((source, method, params) => {
|
|
|
748
821
|
evictOldestRequest(state);
|
|
749
822
|
}
|
|
750
823
|
state.requests.push(completed);
|
|
824
|
+
} else if (method === "Network.webSocketFrameSent" || method === "Network.webSocketFrameReceived") {
|
|
825
|
+
const requestId = paramsRecord?.requestId;
|
|
826
|
+
const response = paramsRecord?.response;
|
|
827
|
+
if (!requestId || !response)
|
|
828
|
+
return;
|
|
829
|
+
const url = state.wsFramesByRequestId.get(requestId);
|
|
830
|
+
if (!url)
|
|
831
|
+
return;
|
|
832
|
+
const opcode = typeof response.opcode === "number" ? response.opcode : 1;
|
|
833
|
+
const payloadData = typeof response.payloadData === "string" ? response.payloadData : "";
|
|
834
|
+
const direction = method === "Network.webSocketFrameSent" ? "sent" : "received";
|
|
835
|
+
const data = truncateBody(payloadData);
|
|
836
|
+
if (state.wsFrames.length >= state.maxWsFrames) {
|
|
837
|
+
state.wsFrames.shift();
|
|
838
|
+
}
|
|
839
|
+
state.wsFrames.push({ url, direction, data, opcode, timestamp: Date.now() });
|
|
840
|
+
} else if (method === "Network.webSocketClosed") {
|
|
841
|
+
const requestId = paramsRecord?.requestId;
|
|
842
|
+
if (requestId) {
|
|
843
|
+
state.wsFramesByRequestId.delete(requestId);
|
|
844
|
+
state.wsCreatedAt.delete(requestId);
|
|
845
|
+
}
|
|
751
846
|
} else if (method === "Runtime.consoleAPICalled") {
|
|
752
847
|
const type = paramsRecord?.type;
|
|
753
848
|
const args = paramsRecord?.args;
|
|
@@ -774,43 +869,93 @@ chrome.debugger.onEvent.addListener((source, method, params) => {
|
|
|
774
869
|
}
|
|
775
870
|
});
|
|
776
871
|
chrome.tabs.onRemoved.addListener((tabId) => {
|
|
777
|
-
|
|
872
|
+
const state = captures.get(tabId);
|
|
873
|
+
if (state) {
|
|
874
|
+
clearInterval(state.pruneIntervalId);
|
|
778
875
|
void chrome.debugger.detach({ tabId }).catch(() => {
|
|
779
876
|
});
|
|
780
877
|
captures.delete(tabId);
|
|
781
878
|
}
|
|
782
879
|
});
|
|
783
|
-
|
|
880
|
+
chrome.debugger.onDetach.addListener((source, _reason) => {
|
|
881
|
+
const tabId = source.tabId;
|
|
882
|
+
if (tabId !== void 0) {
|
|
883
|
+
const state = captures.get(tabId);
|
|
884
|
+
if (state)
|
|
885
|
+
clearInterval(state.pruneIntervalId);
|
|
886
|
+
captures.delete(tabId);
|
|
887
|
+
}
|
|
888
|
+
});
|
|
889
|
+
var startCapture = async (tabId, maxRequests = 100, urlFilter, maxConsoleLogs = 500, maxWsFrames = 200) => {
|
|
890
|
+
const inFlightCapture = pendingCaptures.get(tabId);
|
|
891
|
+
if (inFlightCapture) {
|
|
892
|
+
return inFlightCapture;
|
|
893
|
+
}
|
|
784
894
|
if (captures.has(tabId)) {
|
|
785
895
|
throw new Error(`Network capture already active for tab ${tabId}. Call stopCapture first.`);
|
|
786
896
|
}
|
|
897
|
+
const capturePromise = (async () => {
|
|
898
|
+
try {
|
|
899
|
+
await chrome.debugger.attach({ tabId }, CDP_VERSION);
|
|
900
|
+
} catch (err2) {
|
|
901
|
+
throw new Error(`Failed to attach debugger to tab ${tabId}: ${toErrorMessage(err2)}. Another debugger (e.g., DevTools) may already be attached.`);
|
|
902
|
+
}
|
|
903
|
+
try {
|
|
904
|
+
await chrome.debugger.sendCommand({ tabId }, "Network.enable");
|
|
905
|
+
await chrome.debugger.sendCommand({ tabId }, "Runtime.enable");
|
|
906
|
+
} catch (err2) {
|
|
907
|
+
await chrome.debugger.detach({ tabId }).catch(() => {
|
|
908
|
+
});
|
|
909
|
+
throw err2;
|
|
910
|
+
}
|
|
911
|
+
const captureState = {
|
|
912
|
+
requests: [],
|
|
913
|
+
consoleLogs: [],
|
|
914
|
+
wsFrames: [],
|
|
915
|
+
maxRequests,
|
|
916
|
+
maxConsoleLogs,
|
|
917
|
+
maxWsFrames,
|
|
918
|
+
urlFilter,
|
|
919
|
+
pendingRequests: /* @__PURE__ */ new Map(),
|
|
920
|
+
requestIdToRequest: /* @__PURE__ */ new Map(),
|
|
921
|
+
wsFramesByRequestId: /* @__PURE__ */ new Map(),
|
|
922
|
+
wsCreatedAt: /* @__PURE__ */ new Map()
|
|
923
|
+
};
|
|
924
|
+
captureState.pruneIntervalId = setInterval(() => {
|
|
925
|
+
const now = Date.now();
|
|
926
|
+
for (const [id, pendingReq] of captureState.pendingRequests) {
|
|
927
|
+
if (pendingReq.timestamp !== void 0 && now - pendingReq.timestamp > PENDING_REQUEST_TTL_MS) {
|
|
928
|
+
captureState.pendingRequests.delete(id);
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
for (const [id, req] of captureState.requestIdToRequest) {
|
|
932
|
+
if (now - req.timestamp > PENDING_REQUEST_TTL_MS) {
|
|
933
|
+
captureState.requestIdToRequest.delete(id);
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
for (const [id, createdAt] of captureState.wsCreatedAt) {
|
|
937
|
+
if (now - createdAt > WS_TTL_MS) {
|
|
938
|
+
captureState.wsFramesByRequestId.delete(id);
|
|
939
|
+
captureState.wsCreatedAt.delete(id);
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
}, PRUNE_INTERVAL_MS);
|
|
943
|
+
captures.set(tabId, captureState);
|
|
944
|
+
})();
|
|
945
|
+
pendingCaptures.set(tabId, capturePromise);
|
|
787
946
|
try {
|
|
788
|
-
await
|
|
789
|
-
}
|
|
790
|
-
|
|
947
|
+
await capturePromise;
|
|
948
|
+
} finally {
|
|
949
|
+
pendingCaptures.delete(tabId);
|
|
791
950
|
}
|
|
792
|
-
try {
|
|
793
|
-
await chrome.debugger.sendCommand({ tabId }, "Network.enable");
|
|
794
|
-
await chrome.debugger.sendCommand({ tabId }, "Runtime.enable");
|
|
795
|
-
} catch (err2) {
|
|
796
|
-
await chrome.debugger.detach({ tabId }).catch(() => {
|
|
797
|
-
});
|
|
798
|
-
throw err2;
|
|
799
|
-
}
|
|
800
|
-
captures.set(tabId, {
|
|
801
|
-
requests: [],
|
|
802
|
-
consoleLogs: [],
|
|
803
|
-
maxRequests,
|
|
804
|
-
maxConsoleLogs,
|
|
805
|
-
urlFilter,
|
|
806
|
-
pendingRequests: /* @__PURE__ */ new Map(),
|
|
807
|
-
requestIdToRequest: /* @__PURE__ */ new Map()
|
|
808
|
-
});
|
|
809
951
|
};
|
|
810
952
|
var stopCapture = (tabId) => {
|
|
811
953
|
const state = captures.get(tabId);
|
|
812
954
|
if (!state)
|
|
813
955
|
return;
|
|
956
|
+
clearInterval(state.pruneIntervalId);
|
|
957
|
+
state.wsFramesByRequestId.clear();
|
|
958
|
+
state.wsCreatedAt.clear();
|
|
814
959
|
void chrome.debugger.detach({ tabId }).catch(() => {
|
|
815
960
|
});
|
|
816
961
|
captures.delete(tabId);
|
|
@@ -850,6 +995,16 @@ var clearConsoleLogs = (tabId) => {
|
|
|
850
995
|
state.consoleLogs = [];
|
|
851
996
|
}
|
|
852
997
|
};
|
|
998
|
+
var getWsFrames = (tabId, clear = false) => {
|
|
999
|
+
const state = captures.get(tabId);
|
|
1000
|
+
if (!state)
|
|
1001
|
+
return [];
|
|
1002
|
+
const frames = [...state.wsFrames];
|
|
1003
|
+
if (clear) {
|
|
1004
|
+
state.wsFrames = [];
|
|
1005
|
+
}
|
|
1006
|
+
return frames;
|
|
1007
|
+
};
|
|
853
1008
|
var getActiveCapturesSummary = () => Array.from(captures.entries()).map(([tabId, state]) => ({
|
|
854
1009
|
tabId,
|
|
855
1010
|
requestCount: state.requests.length,
|
|
@@ -1031,11 +1186,17 @@ var lastKnownState = /* @__PURE__ */ new Map();
|
|
|
1031
1186
|
var pluginLocks = /* @__PURE__ */ new Map();
|
|
1032
1187
|
var withPluginLock = (pluginName, fn) => {
|
|
1033
1188
|
const prev = pluginLocks.get(pluginName) ?? Promise.resolve();
|
|
1034
|
-
const
|
|
1035
|
-
|
|
1189
|
+
const operation = prev.then(fn);
|
|
1190
|
+
const lock = operation.catch((err2) => {
|
|
1036
1191
|
console.warn("[opentabs] tab state operation failed for plugin", pluginName, ":", err2);
|
|
1037
|
-
})
|
|
1038
|
-
|
|
1192
|
+
});
|
|
1193
|
+
pluginLocks.set(pluginName, lock);
|
|
1194
|
+
void lock.then(() => {
|
|
1195
|
+
if (pluginLocks.get(pluginName) === lock) {
|
|
1196
|
+
pluginLocks.set(pluginName, Promise.resolve());
|
|
1197
|
+
}
|
|
1198
|
+
});
|
|
1199
|
+
return operation;
|
|
1039
1200
|
};
|
|
1040
1201
|
var probeTabReadiness = async (tabId, pluginName) => {
|
|
1041
1202
|
let timerId;
|
|
@@ -1294,10 +1455,18 @@ var handleExtensionGetLogs = async (params, id) => {
|
|
|
1294
1455
|
};
|
|
1295
1456
|
var handleExtensionGetSidePanel = async (id) => {
|
|
1296
1457
|
try {
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1458
|
+
let timeoutId;
|
|
1459
|
+
let sidePanelResult;
|
|
1460
|
+
try {
|
|
1461
|
+
sidePanelResult = await Promise.race([
|
|
1462
|
+
chrome.runtime.sendMessage({ type: "sp:getState" }).then((raw) => raw),
|
|
1463
|
+
new Promise((resolve) => {
|
|
1464
|
+
timeoutId = setTimeout(() => resolve(null), SIDE_PANEL_TIMEOUT_MS);
|
|
1465
|
+
})
|
|
1466
|
+
]);
|
|
1467
|
+
} finally {
|
|
1468
|
+
clearTimeout(timeoutId);
|
|
1469
|
+
}
|
|
1301
1470
|
if (!sidePanelResult || typeof sidePanelResult !== "object") {
|
|
1302
1471
|
sendSuccessResult(id, { open: false });
|
|
1303
1472
|
return;
|
|
@@ -1376,21 +1545,29 @@ var handleExtensionCheckAdapter = async (params, id) => {
|
|
|
1376
1545
|
}
|
|
1377
1546
|
let isReady = false;
|
|
1378
1547
|
try {
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1548
|
+
let isReadyTimeoutId;
|
|
1549
|
+
let readyResults;
|
|
1550
|
+
try {
|
|
1551
|
+
readyResults = await Promise.race([
|
|
1552
|
+
chrome.scripting.executeScript({
|
|
1553
|
+
target: { tabId },
|
|
1554
|
+
world: "MAIN",
|
|
1555
|
+
func: async (pName) => {
|
|
1556
|
+
const ot = globalThis.__openTabs;
|
|
1557
|
+
const adapter = ot?.adapters?.[pName];
|
|
1558
|
+
if (!adapter || typeof adapter.isReady !== "function")
|
|
1559
|
+
return false;
|
|
1560
|
+
return await adapter.isReady();
|
|
1561
|
+
},
|
|
1562
|
+
args: [pluginName]
|
|
1563
|
+
}),
|
|
1564
|
+
new Promise((resolve) => {
|
|
1565
|
+
isReadyTimeoutId = setTimeout(() => resolve(null), IS_READY_TIMEOUT_MS);
|
|
1566
|
+
})
|
|
1567
|
+
]);
|
|
1568
|
+
} finally {
|
|
1569
|
+
clearTimeout(isReadyTimeoutId);
|
|
1570
|
+
}
|
|
1394
1571
|
if (readyResults !== null) {
|
|
1395
1572
|
const readyResult = readyResults[0];
|
|
1396
1573
|
isReady = readyResult?.result === true;
|
|
@@ -1446,7 +1623,11 @@ var handleBrowserExecuteScript = async (params, id) => {
|
|
|
1446
1623
|
sendValidationError(id, "Invalid execFile format");
|
|
1447
1624
|
return;
|
|
1448
1625
|
}
|
|
1626
|
+
const execUuid = execFile.replace(/^__exec-/, "").replace(/\.js$/, "");
|
|
1627
|
+
const resultKey = `__execResult_${execUuid}`;
|
|
1628
|
+
const asyncKey = `__execAsync_${execUuid}`;
|
|
1449
1629
|
let timeoutId;
|
|
1630
|
+
const cancelled = { value: false };
|
|
1450
1631
|
const injectPromise = (async () => {
|
|
1451
1632
|
await chrome.scripting.executeScript({
|
|
1452
1633
|
target: { tabId },
|
|
@@ -1455,15 +1636,17 @@ var handleBrowserExecuteScript = async (params, id) => {
|
|
|
1455
1636
|
});
|
|
1456
1637
|
let elapsed = 0;
|
|
1457
1638
|
while (elapsed <= EXEC_MAX_ASYNC_WAIT_MS) {
|
|
1639
|
+
if (cancelled.value)
|
|
1640
|
+
return;
|
|
1458
1641
|
const results = await chrome.scripting.executeScript({
|
|
1459
1642
|
target: { tabId },
|
|
1460
1643
|
world: "MAIN",
|
|
1461
|
-
func: (truncLimit) => {
|
|
1644
|
+
func: (truncLimit, rKey, aKey) => {
|
|
1462
1645
|
const ot = globalThis.__openTabs;
|
|
1463
1646
|
if (!ot)
|
|
1464
1647
|
return { pending: false, result: { error: "__openTabs not found" } };
|
|
1465
|
-
const result2 = ot
|
|
1466
|
-
const isAsync = ot
|
|
1648
|
+
const result2 = ot[rKey];
|
|
1649
|
+
const isAsync = ot[aKey] === true;
|
|
1467
1650
|
if (result2 && ("value" in result2 || "error" in result2)) {
|
|
1468
1651
|
const captured = { ...result2 };
|
|
1469
1652
|
if (captured.value === void 0)
|
|
@@ -1476,15 +1659,15 @@ var handleBrowserExecuteScript = async (params, id) => {
|
|
|
1476
1659
|
captured.value = String(captured.value);
|
|
1477
1660
|
}
|
|
1478
1661
|
}
|
|
1479
|
-
|
|
1480
|
-
|
|
1662
|
+
Reflect.deleteProperty(ot, rKey);
|
|
1663
|
+
Reflect.deleteProperty(ot, aKey);
|
|
1481
1664
|
return { pending: false, result: captured };
|
|
1482
1665
|
}
|
|
1483
1666
|
if (isAsync)
|
|
1484
1667
|
return { pending: true };
|
|
1485
1668
|
return { pending: false, result: { error: "No result captured" } };
|
|
1486
1669
|
},
|
|
1487
|
-
args: [EXEC_RESULT_TRUNCATION_LIMIT]
|
|
1670
|
+
args: [EXEC_RESULT_TRUNCATION_LIMIT, resultKey, asyncKey]
|
|
1488
1671
|
});
|
|
1489
1672
|
const first = results[0];
|
|
1490
1673
|
const data = first?.result;
|
|
@@ -1494,18 +1677,21 @@ var handleBrowserExecuteScript = async (params, id) => {
|
|
|
1494
1677
|
await new Promise((resolve) => setTimeout(resolve, EXEC_POLL_INTERVAL_MS));
|
|
1495
1678
|
elapsed += EXEC_POLL_INTERVAL_MS;
|
|
1496
1679
|
}
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1680
|
+
if (!cancelled.value) {
|
|
1681
|
+
await chrome.scripting.executeScript({
|
|
1682
|
+
target: { tabId },
|
|
1683
|
+
world: "MAIN",
|
|
1684
|
+
func: (rKey, aKey) => {
|
|
1685
|
+
const ot = globalThis.__openTabs;
|
|
1686
|
+
if (ot) {
|
|
1687
|
+
Reflect.deleteProperty(ot, rKey);
|
|
1688
|
+
Reflect.deleteProperty(ot, aKey);
|
|
1689
|
+
}
|
|
1690
|
+
},
|
|
1691
|
+
args: [resultKey, asyncKey]
|
|
1692
|
+
}).catch(() => {
|
|
1693
|
+
});
|
|
1694
|
+
}
|
|
1509
1695
|
return { value: { error: `Async code did not resolve within ${EXEC_MAX_ASYNC_WAIT_MS}ms` } };
|
|
1510
1696
|
})();
|
|
1511
1697
|
const timeoutPromise = new Promise((_resolve, reject) => {
|
|
@@ -1518,6 +1704,7 @@ var handleBrowserExecuteScript = async (params, id) => {
|
|
|
1518
1704
|
result = await Promise.race([injectPromise, timeoutPromise]);
|
|
1519
1705
|
} finally {
|
|
1520
1706
|
clearTimeout(timeoutId);
|
|
1707
|
+
cancelled.value = true;
|
|
1521
1708
|
}
|
|
1522
1709
|
sendSuccessResult(id, result);
|
|
1523
1710
|
} catch (err2) {
|
|
@@ -1824,24 +2011,30 @@ var handleBrowserWaitForElement = async (params, id) => {
|
|
|
1824
2011
|
func: (sel, tmo, vis, maxPreview, pollMs) => new Promise((resolve) => {
|
|
1825
2012
|
let elapsed = 0;
|
|
1826
2013
|
const poll = setInterval(() => {
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
2014
|
+
try {
|
|
2015
|
+
const el = document.querySelector(sel);
|
|
2016
|
+
if (el) {
|
|
2017
|
+
const htmlEl = el;
|
|
2018
|
+
const style = getComputedStyle(htmlEl);
|
|
2019
|
+
const isVisible = !vis || style.display !== "none" && style.visibility !== "hidden" && (htmlEl.offsetParent !== null || style.position === "fixed" || style.position === "sticky");
|
|
2020
|
+
if (isVisible) {
|
|
2021
|
+
clearInterval(poll);
|
|
2022
|
+
resolve({
|
|
2023
|
+
found: true,
|
|
2024
|
+
tagName: el.tagName.toLowerCase(),
|
|
2025
|
+
text: (el.textContent || "").trim().slice(0, maxPreview)
|
|
2026
|
+
});
|
|
2027
|
+
return;
|
|
2028
|
+
}
|
|
2029
|
+
}
|
|
2030
|
+
elapsed += pollMs;
|
|
2031
|
+
if (elapsed >= tmo) {
|
|
1832
2032
|
clearInterval(poll);
|
|
1833
|
-
resolve({
|
|
1834
|
-
found: true,
|
|
1835
|
-
tagName: el.tagName.toLowerCase(),
|
|
1836
|
-
text: (el.textContent || "").trim().slice(0, maxPreview)
|
|
1837
|
-
});
|
|
1838
|
-
return;
|
|
2033
|
+
resolve({ error: `Timeout waiting for element: ${sel} (${tmo}ms)` });
|
|
1839
2034
|
}
|
|
1840
|
-
}
|
|
1841
|
-
elapsed += pollMs;
|
|
1842
|
-
if (elapsed >= tmo) {
|
|
2035
|
+
} catch (err2) {
|
|
1843
2036
|
clearInterval(poll);
|
|
1844
|
-
resolve({ error: `
|
|
2037
|
+
resolve({ error: `Error checking element: ${err2 instanceof Error ? err2.message : String(err2)}` });
|
|
1845
2038
|
}
|
|
1846
2039
|
}, pollMs);
|
|
1847
2040
|
}),
|
|
@@ -2230,7 +2423,8 @@ var handleBrowserEnableNetworkCapture = async (params, id) => {
|
|
|
2230
2423
|
const maxRequests = typeof params.maxRequests === "number" ? params.maxRequests : 100;
|
|
2231
2424
|
const urlFilter = typeof params.urlFilter === "string" ? params.urlFilter : void 0;
|
|
2232
2425
|
const maxConsoleLogs = typeof params.maxConsoleLogs === "number" ? params.maxConsoleLogs : 500;
|
|
2233
|
-
|
|
2426
|
+
const maxWsFrames = typeof params.maxWsFrames === "number" ? params.maxWsFrames : 200;
|
|
2427
|
+
await startCapture(tabId, maxRequests, urlFilter, maxConsoleLogs, maxWsFrames);
|
|
2234
2428
|
sendSuccessResult(id, { enabled: true, tabId });
|
|
2235
2429
|
} catch (err2) {
|
|
2236
2430
|
sendErrorResult(id, err2);
|
|
@@ -2283,6 +2477,18 @@ var handleBrowserClearConsoleLogs = (params, id) => {
|
|
|
2283
2477
|
sendErrorResult(id, err2);
|
|
2284
2478
|
}
|
|
2285
2479
|
};
|
|
2480
|
+
var handleBrowserGetWebSocketFrames = (params, id) => {
|
|
2481
|
+
try {
|
|
2482
|
+
const tabId = requireTabId(params, id);
|
|
2483
|
+
if (tabId === null)
|
|
2484
|
+
return;
|
|
2485
|
+
const clear = typeof params.clear === "boolean" ? params.clear : false;
|
|
2486
|
+
const frames = getWsFrames(tabId, clear);
|
|
2487
|
+
sendSuccessResult(id, { frames });
|
|
2488
|
+
} catch (err2) {
|
|
2489
|
+
sendErrorResult(id, err2);
|
|
2490
|
+
}
|
|
2491
|
+
};
|
|
2286
2492
|
|
|
2287
2493
|
// dist/browser-commands/tab-commands.js
|
|
2288
2494
|
var handleBrowserListTabs = async (id) => {
|
|
@@ -2331,7 +2537,7 @@ var handleBrowserNavigateTab = async (params, id) => {
|
|
|
2331
2537
|
if (url === null)
|
|
2332
2538
|
return;
|
|
2333
2539
|
const tab = await chrome.tabs.update(tabId, { url });
|
|
2334
|
-
sendSuccessResult(id, { id: tab?.id ?? tabId, title: tab?.title ?? "", url
|
|
2540
|
+
sendSuccessResult(id, { id: tab?.id ?? tabId, title: tab?.title ?? "", url });
|
|
2335
2541
|
} catch (err2) {
|
|
2336
2542
|
sendErrorResult(id, err2);
|
|
2337
2543
|
}
|
|
@@ -2449,8 +2655,10 @@ var injectLogRelay = async (tabId) => {
|
|
|
2449
2655
|
const win = window;
|
|
2450
2656
|
if (win[guard]) {
|
|
2451
2657
|
const nonceSet = win.__opentabs_log_nonces;
|
|
2452
|
-
if (nonceSet)
|
|
2658
|
+
if (nonceSet) {
|
|
2659
|
+
nonceSet.clear();
|
|
2453
2660
|
nonceSet.add(n);
|
|
2661
|
+
}
|
|
2454
2662
|
return;
|
|
2455
2663
|
}
|
|
2456
2664
|
win[guard] = true;
|
|
@@ -2702,6 +2910,9 @@ var checkRateLimit = (method, now = Date.now()) => {
|
|
|
2702
2910
|
const config = METHOD_LIMITS.get(method) ?? DEFAULT_LIMIT;
|
|
2703
2911
|
const cutoff = now - config.windowMs;
|
|
2704
2912
|
const timestamps = (methodTimestamps.get(method) ?? []).filter((t) => t > cutoff);
|
|
2913
|
+
if (timestamps.length === 0) {
|
|
2914
|
+
methodTimestamps.delete(method);
|
|
2915
|
+
}
|
|
2705
2916
|
if (timestamps.length >= config.maxRequests) {
|
|
2706
2917
|
methodTimestamps.set(method, timestamps);
|
|
2707
2918
|
return false;
|
|
@@ -3455,6 +3666,7 @@ var methodHandlers = /* @__PURE__ */ new Map([
|
|
|
3455
3666
|
["browser.deleteCookies", wrapAsync("browser.deleteCookies", handleBrowserDeleteCookies)],
|
|
3456
3667
|
["browser.enableNetworkCapture", wrapAsync("browser.enableNetworkCapture", handleBrowserEnableNetworkCapture)],
|
|
3457
3668
|
["browser.getNetworkRequests", wrapSync("browser.getNetworkRequests", handleBrowserGetNetworkRequests)],
|
|
3669
|
+
["browser.getWebSocketFrames", wrapSync("browser.getWebSocketFrames", handleBrowserGetWebSocketFrames)],
|
|
3458
3670
|
["browser.disableNetworkCapture", wrapSync("browser.disableNetworkCapture", handleBrowserDisableNetworkCapture)],
|
|
3459
3671
|
["browser.getConsoleLogs", wrapSync("browser.getConsoleLogs", handleBrowserGetConsoleLogs)],
|
|
3460
3672
|
["browser.clearConsoleLogs", wrapSync("browser.clearConsoleLogs", handleBrowserClearConsoleLogs)],
|
|
@@ -3540,7 +3752,6 @@ var handleOffscreenGetUrl = (_message, sendResponse) => {
|
|
|
3540
3752
|
});
|
|
3541
3753
|
};
|
|
3542
3754
|
var handleWsState = (message, sendResponse) => {
|
|
3543
|
-
const wasConnected = wsConnected;
|
|
3544
3755
|
const nowConnected = message.connected;
|
|
3545
3756
|
persistWsConnected(nowConnected);
|
|
3546
3757
|
lastDisconnectReason = nowConnected ? void 0 : message.disconnectReason;
|
|
@@ -3551,7 +3762,7 @@ var handleWsState = (message, sendResponse) => {
|
|
|
3551
3762
|
disconnectReason: lastDisconnectReason
|
|
3552
3763
|
}
|
|
3553
3764
|
});
|
|
3554
|
-
if (!nowConnected
|
|
3765
|
+
if (!nowConnected) {
|
|
3555
3766
|
clearTabStateCache();
|
|
3556
3767
|
clearAllConfirmationBadges();
|
|
3557
3768
|
}
|
|
@@ -3623,11 +3834,20 @@ var handleSpConfirmationResponse = (message, sendResponse) => {
|
|
|
3623
3834
|
params: message.data
|
|
3624
3835
|
});
|
|
3625
3836
|
}
|
|
3626
|
-
|
|
3837
|
+
const data = message.data;
|
|
3838
|
+
const id = typeof data?.id === "string" ? data.id : void 0;
|
|
3839
|
+
if (id !== void 0) {
|
|
3840
|
+
clearConfirmationBackgroundTimeout(id);
|
|
3841
|
+
}
|
|
3842
|
+
clearConfirmationBadge(id);
|
|
3627
3843
|
sendResponse({ ok: true });
|
|
3628
3844
|
};
|
|
3629
|
-
var handleSpConfirmationTimeout = (
|
|
3630
|
-
|
|
3845
|
+
var handleSpConfirmationTimeout = (message, sendResponse) => {
|
|
3846
|
+
const id = typeof message.id === "string" ? message.id : void 0;
|
|
3847
|
+
if (id !== void 0) {
|
|
3848
|
+
clearConfirmationBackgroundTimeout(id);
|
|
3849
|
+
}
|
|
3850
|
+
clearConfirmationBadge(id);
|
|
3631
3851
|
sendResponse({ ok: true });
|
|
3632
3852
|
};
|
|
3633
3853
|
var handlePortChanged = (message, sendResponse) => {
|
|
@@ -3653,7 +3873,10 @@ var EXTENSION_ONLY_TYPES = /* @__PURE__ */ new Set([
|
|
|
3653
3873
|
"ws:message",
|
|
3654
3874
|
"bg:send",
|
|
3655
3875
|
"bg:getConnectionState",
|
|
3656
|
-
"offscreen:getLogs"
|
|
3876
|
+
"offscreen:getLogs",
|
|
3877
|
+
"sp:confirmationResponse",
|
|
3878
|
+
"sp:confirmationTimeout",
|
|
3879
|
+
"port-changed"
|
|
3657
3880
|
]);
|
|
3658
3881
|
var initBackgroundMessageHandlers = () => {
|
|
3659
3882
|
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
|
|
@@ -3684,15 +3907,28 @@ var initSidePanelToggle = () => {
|
|
|
3684
3907
|
chrome.sidePanel.onClosed.addListener(({ windowId }) => {
|
|
3685
3908
|
openWindows.delete(windowId);
|
|
3686
3909
|
});
|
|
3910
|
+
chrome.windows.onRemoved.addListener((windowId) => {
|
|
3911
|
+
openWindows.delete(windowId);
|
|
3912
|
+
});
|
|
3687
3913
|
}
|
|
3688
3914
|
chrome.action.onClicked.addListener(({ windowId }) => {
|
|
3689
|
-
|
|
3690
|
-
|
|
3691
|
-
|
|
3692
|
-
|
|
3693
|
-
|
|
3694
|
-
|
|
3695
|
-
|
|
3915
|
+
void (async () => {
|
|
3916
|
+
if (canToggle && openWindows.has(windowId)) {
|
|
3917
|
+
try {
|
|
3918
|
+
await chrome.windows.get(windowId);
|
|
3919
|
+
} catch {
|
|
3920
|
+
openWindows.delete(windowId);
|
|
3921
|
+
await chrome.sidePanel.open({ windowId }).catch(() => {
|
|
3922
|
+
});
|
|
3923
|
+
return;
|
|
3924
|
+
}
|
|
3925
|
+
chrome.sidePanel.close({ windowId }).catch(() => {
|
|
3926
|
+
});
|
|
3927
|
+
} else {
|
|
3928
|
+
chrome.sidePanel.open({ windowId }).catch(() => {
|
|
3929
|
+
});
|
|
3930
|
+
}
|
|
3931
|
+
})();
|
|
3696
3932
|
});
|
|
3697
3933
|
};
|
|
3698
3934
|
|
|
@@ -3752,14 +3988,14 @@ chrome.runtime.onInstalled.addListener(() => {
|
|
|
3752
3988
|
await ensureOffscreenDocument();
|
|
3753
3989
|
await setupKeepaliveAlarm();
|
|
3754
3990
|
await reinjectStoredPlugins();
|
|
3755
|
-
})();
|
|
3991
|
+
})().catch((err2) => console.warn("[opentabs] onInstalled failed:", err2));
|
|
3756
3992
|
});
|
|
3757
3993
|
chrome.runtime.onStartup.addListener(() => {
|
|
3758
3994
|
void (async () => {
|
|
3759
3995
|
await ensureOffscreenDocument();
|
|
3760
3996
|
await setupKeepaliveAlarm();
|
|
3761
3997
|
await reinjectStoredPlugins();
|
|
3762
|
-
})();
|
|
3998
|
+
})().catch((err2) => console.warn("[opentabs] onStartup failed:", err2));
|
|
3763
3999
|
});
|
|
3764
4000
|
ensureOffscreenDocument().catch((err2) => console.warn("[opentabs] offscreen creation failed:", err2));
|
|
3765
4001
|
setupKeepaliveAlarm().catch((err2) => console.warn("[opentabs] keepalive alarm failed:", err2));
|
|
@@ -3769,7 +4005,7 @@ chrome.storage.onChanged.addListener((changes, area) => {
|
|
|
3769
4005
|
if (area !== "local")
|
|
3770
4006
|
return;
|
|
3771
4007
|
const portChange = changes[SERVER_PORT_KEY];
|
|
3772
|
-
if (typeof portChange?.newValue === "number" && portChange.newValue
|
|
4008
|
+
if (typeof portChange?.newValue === "number" && Number.isInteger(portChange.newValue) && portChange.newValue >= 1 && portChange.newValue <= 65535) {
|
|
3773
4009
|
const newUrl = buildWsUrl(portChange.newValue);
|
|
3774
4010
|
chrome.runtime.sendMessage({ type: "ws:setUrl", url: newUrl }).catch(() => {
|
|
3775
4011
|
});
|