@opentabs-dev/browser-extension 0.0.64 → 0.0.66
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 +5 -1
- package/dist/background-message-handlers.d.ts.map +1 -1
- package/dist/background-message-handlers.js +76 -2
- package/dist/background-message-handlers.js.map +1 -1
- package/dist/background.js +263 -140
- package/dist/browser-commands/interaction-commands.d.ts +2 -0
- package/dist/browser-commands/interaction-commands.d.ts.map +1 -1
- package/dist/browser-commands/interaction-commands.js +26 -3
- package/dist/browser-commands/interaction-commands.js.map +1 -1
- package/dist/browser-commands/key-press-command.d.ts +6 -0
- package/dist/browser-commands/key-press-command.d.ts.map +1 -1
- package/dist/browser-commands/key-press-command.js +137 -118
- package/dist/browser-commands/key-press-command.js.map +1 -1
- package/dist/dispatch-helpers.js +2 -2
- package/dist/dispatch-helpers.js.map +1 -1
- package/dist/extension-messages.d.ts +13 -1
- package/dist/extension-messages.d.ts.map +1 -1
- package/dist/iife-injection.d.ts +5 -4
- package/dist/iife-injection.d.ts.map +1 -1
- package/dist/iife-injection.js +21 -12
- package/dist/iife-injection.js.map +1 -1
- package/dist/message-router.d.ts +2 -0
- package/dist/message-router.d.ts.map +1 -1
- package/dist/message-router.js +16 -4
- package/dist/message-router.js.map +1 -1
- package/dist/offscreen/index.js +1 -0
- package/dist/offscreen/index.js.map +1 -1
- package/dist/side-panel/App.d.ts.map +1 -1
- package/dist/side-panel/App.js +22 -2
- package/dist/side-panel/App.js.map +1 -1
- package/dist/side-panel/bridge.d.ts +10 -1
- package/dist/side-panel/bridge.d.ts.map +1 -1
- package/dist/side-panel/bridge.js +5 -1
- package/dist/side-panel/bridge.js.map +1 -1
- package/dist/side-panel/components/FailedPluginCard.d.ts +6 -2
- package/dist/side-panel/components/FailedPluginCard.d.ts.map +1 -1
- package/dist/side-panel/components/FailedPluginCard.js +11 -3
- package/dist/side-panel/components/FailedPluginCard.js.map +1 -1
- package/dist/side-panel/components/PluginCard.d.ts.map +1 -1
- package/dist/side-panel/components/PluginCard.js +15 -2
- package/dist/side-panel/components/PluginCard.js.map +1 -1
- package/dist/side-panel/components/PluginList.d.ts +3 -1
- package/dist/side-panel/components/PluginList.d.ts.map +1 -1
- package/dist/side-panel/components/PluginList.js +2 -2
- package/dist/side-panel/components/PluginList.js.map +1 -1
- package/dist/side-panel/components/PluginMenu.d.ts.map +1 -1
- package/dist/side-panel/components/PluginMenu.js +2 -2
- package/dist/side-panel/components/PluginMenu.js.map +1 -1
- package/dist/side-panel/side-panel.js +763 -513
- package/dist/side-panel/styles.css +1 -1
- package/dist/tab-matching.d.ts +5 -3
- package/dist/tab-matching.d.ts.map +1 -1
- package/dist/tab-matching.js +27 -9
- package/dist/tab-matching.js.map +1 -1
- package/dist/tab-state.js +2 -2
- package/dist/tab-state.js.map +1 -1
- package/manifest.json +1 -1
- package/package.json +1 -1
package/dist/background.js
CHANGED
|
@@ -1157,12 +1157,23 @@ var invalidatePluginCache = () => {
|
|
|
1157
1157
|
};
|
|
1158
1158
|
|
|
1159
1159
|
// dist/tab-matching.js
|
|
1160
|
-
var urlMatchesPatterns = (url, patterns) => {
|
|
1160
|
+
var urlMatchesPatterns = (url, patterns, excludePatterns) => {
|
|
1161
|
+
let matched = false;
|
|
1161
1162
|
for (const pattern of patterns) {
|
|
1162
|
-
if (matchPattern(url, pattern))
|
|
1163
|
-
|
|
1163
|
+
if (matchPattern(url, pattern)) {
|
|
1164
|
+
matched = true;
|
|
1165
|
+
break;
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1168
|
+
if (!matched)
|
|
1169
|
+
return false;
|
|
1170
|
+
if (excludePatterns) {
|
|
1171
|
+
for (const pattern of excludePatterns) {
|
|
1172
|
+
if (matchPattern(url, pattern))
|
|
1173
|
+
return false;
|
|
1174
|
+
}
|
|
1164
1175
|
}
|
|
1165
|
-
return
|
|
1176
|
+
return true;
|
|
1166
1177
|
};
|
|
1167
1178
|
var matchPattern = (url, pattern) => {
|
|
1168
1179
|
const matchResult = pattern.match(/^(\*|https?|ftp):\/\/(.+?)(\/.*)$/);
|
|
@@ -1227,8 +1238,10 @@ var findAllMatchingTabs = async (plugin) => {
|
|
|
1227
1238
|
}
|
|
1228
1239
|
}
|
|
1229
1240
|
}
|
|
1230
|
-
|
|
1231
|
-
|
|
1241
|
+
const excludePatterns = plugin.excludePatterns ?? [];
|
|
1242
|
+
const filtered = excludePatterns.length > 0 ? allMatches.filter((tab) => !tab.url || !urlMatchesPatterns(tab.url, excludePatterns)) : allMatches;
|
|
1243
|
+
if (filtered.length <= 1)
|
|
1244
|
+
return filtered;
|
|
1232
1245
|
let focusedWindowId;
|
|
1233
1246
|
try {
|
|
1234
1247
|
const focusedWindow = await chrome.windows.getLastFocused();
|
|
@@ -1245,7 +1258,7 @@ var findAllMatchingTabs = async (plugin) => {
|
|
|
1245
1258
|
return 1;
|
|
1246
1259
|
return 0;
|
|
1247
1260
|
};
|
|
1248
|
-
return
|
|
1261
|
+
return filtered.slice().sort((a, b) => rank(b) - rank(a));
|
|
1249
1262
|
};
|
|
1250
1263
|
|
|
1251
1264
|
// dist/tab-state.js
|
|
@@ -1483,7 +1496,7 @@ var checkTabChanged = async (changedTabId, changeInfo) => {
|
|
|
1483
1496
|
if (changeInfo.url) {
|
|
1484
1497
|
const changedUrl = changeInfo.url;
|
|
1485
1498
|
affectedPlugins = plugins.filter((p) => {
|
|
1486
|
-
if (urlMatchesPatterns(changedUrl, p.urlPatterns))
|
|
1499
|
+
if (urlMatchesPatterns(changedUrl, p.urlPatterns, p.excludePatterns))
|
|
1487
1500
|
return true;
|
|
1488
1501
|
const cached = lastKnownState.get(p.name);
|
|
1489
1502
|
return cached !== void 0 && getAggregateState(cached) !== "closed";
|
|
@@ -1499,7 +1512,7 @@ var checkTabChanged = async (changedTabId, changeInfo) => {
|
|
|
1499
1512
|
if (!tabUrl)
|
|
1500
1513
|
return;
|
|
1501
1514
|
affectedPlugins = plugins.filter((p) => {
|
|
1502
|
-
if (urlMatchesPatterns(tabUrl, p.urlPatterns))
|
|
1515
|
+
if (urlMatchesPatterns(tabUrl, p.urlPatterns, p.excludePatterns))
|
|
1503
1516
|
return true;
|
|
1504
1517
|
const cached = lastKnownState.get(p.name);
|
|
1505
1518
|
return cached !== void 0 && getAggregateState(cached) !== "closed";
|
|
@@ -2075,11 +2088,12 @@ var handleBrowserClickElement = async (params, id) => {
|
|
|
2075
2088
|
const el = document.querySelector(sel);
|
|
2076
2089
|
if (!el)
|
|
2077
2090
|
return { error: `Element not found: ${sel}` };
|
|
2078
|
-
el.
|
|
2091
|
+
const rect = el.getBoundingClientRect();
|
|
2079
2092
|
return {
|
|
2080
|
-
clicked: true,
|
|
2081
2093
|
tagName: el.tagName.toLowerCase(),
|
|
2082
|
-
text: (el.textContent || "").trim().slice(0, maxPreview)
|
|
2094
|
+
text: (el.textContent || "").trim().slice(0, maxPreview),
|
|
2095
|
+
x: rect.left + rect.width / 2,
|
|
2096
|
+
y: rect.top + rect.height / 2
|
|
2083
2097
|
};
|
|
2084
2098
|
},
|
|
2085
2099
|
args: [selector, TEXT_PREVIEW_MAX_LENGTH]
|
|
@@ -2087,7 +2101,27 @@ var handleBrowserClickElement = async (params, id) => {
|
|
|
2087
2101
|
const result = extractScriptResult(results, id);
|
|
2088
2102
|
if (!result)
|
|
2089
2103
|
return;
|
|
2090
|
-
|
|
2104
|
+
const x = result.x;
|
|
2105
|
+
const y = result.y;
|
|
2106
|
+
await withDebugger(tabId, async () => {
|
|
2107
|
+
await chrome.debugger.sendCommand({ tabId }, "Input.dispatchMouseEvent", {
|
|
2108
|
+
type: "mousePressed",
|
|
2109
|
+
x,
|
|
2110
|
+
y,
|
|
2111
|
+
button: "left",
|
|
2112
|
+
buttons: 1,
|
|
2113
|
+
clickCount: 1
|
|
2114
|
+
});
|
|
2115
|
+
await chrome.debugger.sendCommand({ tabId }, "Input.dispatchMouseEvent", {
|
|
2116
|
+
type: "mouseReleased",
|
|
2117
|
+
x,
|
|
2118
|
+
y,
|
|
2119
|
+
button: "left",
|
|
2120
|
+
buttons: 0,
|
|
2121
|
+
clickCount: 1
|
|
2122
|
+
});
|
|
2123
|
+
});
|
|
2124
|
+
sendSuccessResult(id, { clicked: true, tagName: result.tagName, text: result.text });
|
|
2091
2125
|
} catch (err2) {
|
|
2092
2126
|
sendErrorResult(id, err2);
|
|
2093
2127
|
}
|
|
@@ -2428,6 +2462,57 @@ var UNSHIFTED_PUNCTUATION_CODES = {
|
|
|
2428
2462
|
"/": "Slash",
|
|
2429
2463
|
"`": "Backquote"
|
|
2430
2464
|
};
|
|
2465
|
+
var NAMED_KEY_CODES = {
|
|
2466
|
+
Enter: 13,
|
|
2467
|
+
Escape: 27,
|
|
2468
|
+
Tab: 9,
|
|
2469
|
+
Backspace: 8,
|
|
2470
|
+
Delete: 46,
|
|
2471
|
+
ArrowUp: 38,
|
|
2472
|
+
ArrowDown: 40,
|
|
2473
|
+
ArrowLeft: 37,
|
|
2474
|
+
ArrowRight: 39,
|
|
2475
|
+
Home: 36,
|
|
2476
|
+
End: 35,
|
|
2477
|
+
PageUp: 33,
|
|
2478
|
+
PageDown: 34,
|
|
2479
|
+
" ": 32,
|
|
2480
|
+
F1: 112,
|
|
2481
|
+
F2: 113,
|
|
2482
|
+
F3: 114,
|
|
2483
|
+
F4: 115,
|
|
2484
|
+
F5: 116,
|
|
2485
|
+
F6: 117,
|
|
2486
|
+
F7: 118,
|
|
2487
|
+
F8: 119,
|
|
2488
|
+
F9: 120,
|
|
2489
|
+
F10: 121,
|
|
2490
|
+
F11: 122,
|
|
2491
|
+
F12: 123,
|
|
2492
|
+
Insert: 45
|
|
2493
|
+
};
|
|
2494
|
+
var deriveCode = (key) => {
|
|
2495
|
+
if (key.length === 1) {
|
|
2496
|
+
const upper = key.toUpperCase();
|
|
2497
|
+
if (upper >= "A" && upper <= "Z")
|
|
2498
|
+
return `Key${upper}`;
|
|
2499
|
+
if (key >= "0" && key <= "9")
|
|
2500
|
+
return `Digit${key}`;
|
|
2501
|
+
if (key === " ")
|
|
2502
|
+
return "Space";
|
|
2503
|
+
return SHIFTED_PUNCTUATION_CODES[key] ?? UNSHIFTED_PUNCTUATION_CODES[key] ?? key;
|
|
2504
|
+
}
|
|
2505
|
+
return key;
|
|
2506
|
+
};
|
|
2507
|
+
var getVirtualKeyCode = (key) => {
|
|
2508
|
+
if (NAMED_KEY_CODES[key] !== void 0)
|
|
2509
|
+
return NAMED_KEY_CODES[key];
|
|
2510
|
+
if (key.length === 1)
|
|
2511
|
+
return key.toUpperCase().charCodeAt(0);
|
|
2512
|
+
return 0;
|
|
2513
|
+
};
|
|
2514
|
+
var buildModifiers = (shift, ctrl, alt, meta) => (alt ? 1 : 0) | (ctrl ? 2 : 0) | (meta ? 4 : 0) | (shift ? 8 : 0);
|
|
2515
|
+
var isPrintableKeyPress = (key, ctrl, meta) => key.length === 1 && !ctrl && !meta;
|
|
2431
2516
|
var handleBrowserPressKey = async (params, id) => {
|
|
2432
2517
|
try {
|
|
2433
2518
|
const tabId = requireTabId(params, id);
|
|
@@ -2442,119 +2527,79 @@ var handleBrowserPressKey = async (params, id) => {
|
|
|
2442
2527
|
const ctrlKey = modifiers.ctrl === true;
|
|
2443
2528
|
const altKey = modifiers.alt === true;
|
|
2444
2529
|
const metaKey = modifiers.meta === true;
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
if (!
|
|
2530
|
+
let focusTarget;
|
|
2531
|
+
if (selector) {
|
|
2532
|
+
const focusResults = await chrome.scripting.executeScript({
|
|
2533
|
+
target: { tabId },
|
|
2534
|
+
world: "MAIN",
|
|
2535
|
+
func: (sel) => {
|
|
2536
|
+
const el = document.querySelector(sel);
|
|
2537
|
+
if (!el)
|
|
2453
2538
|
return { error: `Element not found: ${sel}` };
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
};
|
|
2487
|
-
const getKeyCode = (k2) => {
|
|
2488
|
-
if (KEY_CODES[k2] !== void 0)
|
|
2489
|
-
return KEY_CODES[k2];
|
|
2490
|
-
if (k2.length === 1)
|
|
2491
|
-
return k2.toUpperCase().charCodeAt(0);
|
|
2492
|
-
return 0;
|
|
2493
|
-
};
|
|
2494
|
-
const code = deriveCode(k);
|
|
2495
|
-
const keyCode = getKeyCode(k);
|
|
2496
|
-
const isPrintable = k.length === 1;
|
|
2497
|
-
const eventInit = {
|
|
2498
|
-
key: k,
|
|
2539
|
+
el.focus();
|
|
2540
|
+
return {
|
|
2541
|
+
tagName: el.tagName.toLowerCase(),
|
|
2542
|
+
id: el.id || void 0
|
|
2543
|
+
};
|
|
2544
|
+
},
|
|
2545
|
+
args: [selector]
|
|
2546
|
+
});
|
|
2547
|
+
const focusResult = extractScriptResult(focusResults, id);
|
|
2548
|
+
if (!focusResult)
|
|
2549
|
+
return;
|
|
2550
|
+
focusTarget = { tagName: focusResult.tagName, id: focusResult.id };
|
|
2551
|
+
}
|
|
2552
|
+
const code = deriveCode(key);
|
|
2553
|
+
const windowsVirtualKeyCode = getVirtualKeyCode(key);
|
|
2554
|
+
const cdpModifiers = buildModifiers(shiftKey, ctrlKey, altKey, metaKey);
|
|
2555
|
+
const printable = isPrintableKeyPress(key, ctrlKey, metaKey);
|
|
2556
|
+
const text = printable ? key : key === "Enter" ? "\r" : key === "Tab" ? " " : "";
|
|
2557
|
+
await withDebugger(tabId, async () => {
|
|
2558
|
+
await chrome.debugger.sendCommand({ tabId }, "Input.dispatchKeyEvent", {
|
|
2559
|
+
type: printable ? "keyDown" : "rawKeyDown",
|
|
2560
|
+
modifiers: cdpModifiers,
|
|
2561
|
+
windowsVirtualKeyCode,
|
|
2562
|
+
code,
|
|
2563
|
+
key,
|
|
2564
|
+
text: printable ? text : ""
|
|
2565
|
+
});
|
|
2566
|
+
if (printable) {
|
|
2567
|
+
await chrome.debugger.sendCommand({ tabId }, "Input.dispatchKeyEvent", {
|
|
2568
|
+
type: "char",
|
|
2569
|
+
modifiers: cdpModifiers,
|
|
2570
|
+
windowsVirtualKeyCode: key.charCodeAt(0),
|
|
2499
2571
|
code,
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
target.dispatchEvent(new KeyboardEvent("keypress", eventInit));
|
|
2512
|
-
}
|
|
2513
|
-
target.dispatchEvent(new KeyboardEvent("keyup", eventInit));
|
|
2514
|
-
if (isPrintable) {
|
|
2515
|
-
const tag = target.tagName.toLowerCase();
|
|
2516
|
-
const isEditable = tag === "input" || tag === "textarea" || target.isContentEditable;
|
|
2517
|
-
if (isEditable) {
|
|
2518
|
-
if (tag === "input" || tag === "textarea") {
|
|
2519
|
-
const input = target;
|
|
2520
|
-
const start = input.selectionStart ?? input.value.length;
|
|
2521
|
-
const end = input.selectionEnd ?? start;
|
|
2522
|
-
input.value = input.value.slice(0, start) + k + input.value.slice(end);
|
|
2523
|
-
input.selectionStart = input.selectionEnd = start + 1;
|
|
2524
|
-
} else {
|
|
2525
|
-
const selection = window.getSelection();
|
|
2526
|
-
if (selection && selection.rangeCount > 0) {
|
|
2527
|
-
const range = selection.getRangeAt(0);
|
|
2528
|
-
range.deleteContents();
|
|
2529
|
-
range.insertNode(document.createTextNode(k));
|
|
2530
|
-
range.collapse(false);
|
|
2531
|
-
selection.removeAllRanges();
|
|
2532
|
-
selection.addRange(range);
|
|
2533
|
-
}
|
|
2534
|
-
}
|
|
2535
|
-
target.dispatchEvent(new InputEvent("input", {
|
|
2536
|
-
bubbles: true,
|
|
2537
|
-
cancelable: true,
|
|
2538
|
-
inputType: "insertText",
|
|
2539
|
-
data: k
|
|
2540
|
-
}));
|
|
2541
|
-
}
|
|
2542
|
-
}
|
|
2543
|
-
return {
|
|
2544
|
-
pressed: true,
|
|
2545
|
-
key: k,
|
|
2546
|
-
target: {
|
|
2547
|
-
tagName: target.tagName.toLowerCase(),
|
|
2548
|
-
id: target.id || void 0
|
|
2549
|
-
}
|
|
2550
|
-
};
|
|
2551
|
-
},
|
|
2552
|
-
args: [key, selector, shiftKey, ctrlKey, altKey, metaKey, SHIFTED_PUNCTUATION_CODES, UNSHIFTED_PUNCTUATION_CODES]
|
|
2572
|
+
key,
|
|
2573
|
+
text
|
|
2574
|
+
});
|
|
2575
|
+
}
|
|
2576
|
+
await chrome.debugger.sendCommand({ tabId }, "Input.dispatchKeyEvent", {
|
|
2577
|
+
type: "keyUp",
|
|
2578
|
+
modifiers: cdpModifiers,
|
|
2579
|
+
windowsVirtualKeyCode,
|
|
2580
|
+
code,
|
|
2581
|
+
key
|
|
2582
|
+
});
|
|
2553
2583
|
});
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2584
|
+
if (!focusTarget) {
|
|
2585
|
+
const activeResults = await chrome.scripting.executeScript({
|
|
2586
|
+
target: { tabId },
|
|
2587
|
+
world: "MAIN",
|
|
2588
|
+
func: () => {
|
|
2589
|
+
const el = document.activeElement ?? document.body;
|
|
2590
|
+
return {
|
|
2591
|
+
tagName: el.tagName.toLowerCase(),
|
|
2592
|
+
id: el.id || void 0
|
|
2593
|
+
};
|
|
2594
|
+
},
|
|
2595
|
+
args: []
|
|
2596
|
+
});
|
|
2597
|
+
const activeResult = extractScriptResult(activeResults, id);
|
|
2598
|
+
if (!activeResult)
|
|
2599
|
+
return;
|
|
2600
|
+
focusTarget = { tagName: activeResult.tagName, id: activeResult.id };
|
|
2601
|
+
}
|
|
2602
|
+
sendSuccessResult(id, { pressed: true, key, target: focusTarget });
|
|
2558
2603
|
} catch (err2) {
|
|
2559
2604
|
sendErrorResult(id, err2);
|
|
2560
2605
|
}
|
|
@@ -2967,21 +3012,26 @@ var injectAdapterFile = async (tabId, pluginName, adapterHash, adapterFilePath)
|
|
|
2967
3012
|
}
|
|
2968
3013
|
}
|
|
2969
3014
|
};
|
|
2970
|
-
var queryMatchingTabIds = async (urlPatterns) => {
|
|
2971
|
-
const
|
|
3015
|
+
var queryMatchingTabIds = async (urlPatterns, excludePatterns) => {
|
|
3016
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3017
|
+
const ids = [];
|
|
2972
3018
|
for (const pattern of urlPatterns) {
|
|
2973
3019
|
try {
|
|
2974
3020
|
const tabs = await chrome.tabs.query({ url: pattern });
|
|
2975
3021
|
for (const tab of tabs) {
|
|
2976
|
-
if (tab.id !== void 0) {
|
|
2977
|
-
|
|
3022
|
+
if (tab.id !== void 0 && !seen.has(tab.id)) {
|
|
3023
|
+
if (excludePatterns && excludePatterns.length > 0 && tab.url && urlMatchesPatterns(tab.url, excludePatterns)) {
|
|
3024
|
+
continue;
|
|
3025
|
+
}
|
|
3026
|
+
seen.add(tab.id);
|
|
3027
|
+
ids.push(tab.id);
|
|
2978
3028
|
}
|
|
2979
3029
|
}
|
|
2980
3030
|
} catch (err2) {
|
|
2981
3031
|
console.warn(`[opentabs] chrome.tabs.query failed for pattern ${pattern}:`, err2);
|
|
2982
3032
|
}
|
|
2983
3033
|
}
|
|
2984
|
-
return
|
|
3034
|
+
return ids;
|
|
2985
3035
|
};
|
|
2986
3036
|
var prepareForReinjection = async (tabId) => {
|
|
2987
3037
|
await chrome.scripting.executeScript({
|
|
@@ -3014,12 +3064,12 @@ var prepareForReinjection = async (tabId) => {
|
|
|
3014
3064
|
console.warn(`[opentabs] prepareForReinjection failed:`, err2);
|
|
3015
3065
|
});
|
|
3016
3066
|
};
|
|
3017
|
-
var injectPluginIntoMatchingTabs = async (pluginName, urlPatterns, forceReinject = false, adapterHash, adapterFile, skipIfHashMatches) => {
|
|
3067
|
+
var injectPluginIntoMatchingTabs = async (pluginName, urlPatterns, forceReinject = false, adapterHash, adapterFile, skipIfHashMatches, excludePatterns) => {
|
|
3018
3068
|
if (!isSafePluginName(pluginName)) {
|
|
3019
3069
|
console.warn(`[opentabs] Skipping injection for unsafe plugin name: ${pluginName}`);
|
|
3020
3070
|
return [];
|
|
3021
3071
|
}
|
|
3022
|
-
const tabIds = await queryMatchingTabIds(urlPatterns);
|
|
3072
|
+
const tabIds = await queryMatchingTabIds(urlPatterns, excludePatterns);
|
|
3023
3073
|
const results = await Promise.allSettled(tabIds.map(async (tabId) => {
|
|
3024
3074
|
if (!forceReinject && await isAdapterPresent(tabId, pluginName)) {
|
|
3025
3075
|
return tabId;
|
|
@@ -3049,7 +3099,7 @@ var injectPluginsIntoTab = async (tabId, tabUrl) => {
|
|
|
3049
3099
|
const plugins = Object.values(index);
|
|
3050
3100
|
if (plugins.length === 0)
|
|
3051
3101
|
return;
|
|
3052
|
-
const matching = plugins.filter((p) => isSafePluginName(p.name) && urlMatchesPatterns(tabUrl, p.urlPatterns));
|
|
3102
|
+
const matching = plugins.filter((p) => isSafePluginName(p.name) && urlMatchesPatterns(tabUrl, p.urlPatterns, p.excludePatterns));
|
|
3053
3103
|
if (matching.length === 0)
|
|
3054
3104
|
return;
|
|
3055
3105
|
const presenceResults = await Promise.allSettled(matching.map(async (plugin) => ({
|
|
@@ -3067,12 +3117,12 @@ var injectPluginsIntoTab = async (tabId, tabUrl) => {
|
|
|
3067
3117
|
}
|
|
3068
3118
|
}));
|
|
3069
3119
|
};
|
|
3070
|
-
var cleanupAdaptersInMatchingTabs = async (pluginName, urlPatterns) => {
|
|
3120
|
+
var cleanupAdaptersInMatchingTabs = async (pluginName, urlPatterns, excludePatterns) => {
|
|
3071
3121
|
if (!isSafePluginName(pluginName)) {
|
|
3072
3122
|
console.warn(`[opentabs] Skipping cleanup for unsafe plugin name: ${pluginName}`);
|
|
3073
3123
|
return;
|
|
3074
3124
|
}
|
|
3075
|
-
const tabIds = await queryMatchingTabIds(urlPatterns);
|
|
3125
|
+
const tabIds = await queryMatchingTabIds(urlPatterns, excludePatterns);
|
|
3076
3126
|
await Promise.allSettled(tabIds.map(async (tabId) => {
|
|
3077
3127
|
try {
|
|
3078
3128
|
await chrome.scripting.executeScript({
|
|
@@ -3120,7 +3170,7 @@ var reinjectStoredPlugins = async () => {
|
|
|
3120
3170
|
const plugins = Object.values(index);
|
|
3121
3171
|
if (plugins.length === 0)
|
|
3122
3172
|
return;
|
|
3123
|
-
const results = await Promise.allSettled(plugins.map((plugin) => injectPluginIntoMatchingTabs(plugin.name, plugin.urlPatterns, false, plugin.adapterHash, plugin.adapterFile)));
|
|
3173
|
+
const results = await Promise.allSettled(plugins.map((plugin) => injectPluginIntoMatchingTabs(plugin.name, plugin.urlPatterns, false, plugin.adapterHash, plugin.adapterFile, void 0, plugin.excludePatterns)));
|
|
3124
3174
|
for (let i = 0; i < results.length; i++) {
|
|
3125
3175
|
const result = results[i];
|
|
3126
3176
|
if (result && result.status === "rejected") {
|
|
@@ -3417,7 +3467,7 @@ var dispatchWithTabFallback = async (config) => {
|
|
|
3417
3467
|
continue;
|
|
3418
3468
|
try {
|
|
3419
3469
|
const currentTab = await chrome.tabs.get(tab.id);
|
|
3420
|
-
if (!currentTab.url || !urlMatchesPatterns(currentTab.url, plugin.urlPatterns)) {
|
|
3470
|
+
if (!currentTab.url || !urlMatchesPatterns(currentTab.url, plugin.urlPatterns, plugin.excludePatterns)) {
|
|
3421
3471
|
firstError ??= { code: JSONRPC_NO_USABLE_TAB, message: "Tab navigated away from matching URL" };
|
|
3422
3472
|
continue;
|
|
3423
3473
|
}
|
|
@@ -3489,7 +3539,7 @@ var dispatchToTargetedTab = async (config) => {
|
|
|
3489
3539
|
});
|
|
3490
3540
|
return;
|
|
3491
3541
|
}
|
|
3492
|
-
if (!tab.url || !urlMatchesPatterns(tab.url, plugin.urlPatterns)) {
|
|
3542
|
+
if (!tab.url || !urlMatchesPatterns(tab.url, plugin.urlPatterns, plugin.excludePatterns)) {
|
|
3493
3543
|
sendToServer({
|
|
3494
3544
|
jsonrpc: "2.0",
|
|
3495
3545
|
error: {
|
|
@@ -3824,6 +3874,8 @@ var toPluginMeta = (p) => ({
|
|
|
3824
3874
|
version: p.version,
|
|
3825
3875
|
displayName: p.displayName,
|
|
3826
3876
|
urlPatterns: p.urlPatterns,
|
|
3877
|
+
excludePatterns: p.excludePatterns.length > 0 ? p.excludePatterns : void 0,
|
|
3878
|
+
homepage: p.homepage,
|
|
3827
3879
|
permission: p.permission,
|
|
3828
3880
|
sourcePath: p.sourcePath,
|
|
3829
3881
|
adapterHash: p.adapterHash,
|
|
@@ -3849,6 +3901,8 @@ var validatePluginPayload = (raw) => {
|
|
|
3849
3901
|
return null;
|
|
3850
3902
|
}
|
|
3851
3903
|
const urlPatterns = Array.isArray(obj.urlPatterns) ? obj.urlPatterns.filter((p) => typeof p === "string") : [];
|
|
3904
|
+
const excludePatterns = Array.isArray(obj.excludePatterns) ? obj.excludePatterns.filter((p) => typeof p === "string") : [];
|
|
3905
|
+
const homepage = typeof obj.homepage === "string" && obj.homepage.length > 0 ? obj.homepage : void 0;
|
|
3852
3906
|
const tools = Array.isArray(obj.tools) ? obj.tools.filter((t) => typeof t === "object" && t !== null && typeof t.name === "string" && typeof t.description === "string").map((t) => {
|
|
3853
3907
|
if (t.permission !== "off" && t.permission !== "ask" && t.permission !== "auto") {
|
|
3854
3908
|
console.warn(`[opentabs] Tool "${t.name}" in plugin "${obj.name}" has invalid "permission" field \u2014 defaulting to permission='off'. This is a server-side bug.`);
|
|
@@ -3868,6 +3922,8 @@ var validatePluginPayload = (raw) => {
|
|
|
3868
3922
|
version: typeof obj.version === "string" ? obj.version : "0.0.0",
|
|
3869
3923
|
displayName: typeof obj.displayName === "string" ? obj.displayName : obj.name,
|
|
3870
3924
|
urlPatterns,
|
|
3925
|
+
excludePatterns,
|
|
3926
|
+
homepage,
|
|
3871
3927
|
permission: obj.permission === "off" || obj.permission === "ask" || obj.permission === "auto" ? obj.permission : "off",
|
|
3872
3928
|
sourcePath: typeof obj.sourcePath === "string" ? obj.sourcePath : void 0,
|
|
3873
3929
|
adapterHash: typeof obj.adapterHash === "string" ? obj.adapterHash : void 0,
|
|
@@ -3915,7 +3971,7 @@ var handleSyncFull = async (params) => {
|
|
|
3915
3971
|
await Promise.allSettled(removedNames.map((name) => {
|
|
3916
3972
|
const meta = existingMeta[name];
|
|
3917
3973
|
if (meta)
|
|
3918
|
-
return cleanupAdaptersInMatchingTabs(name, meta.urlPatterns);
|
|
3974
|
+
return cleanupAdaptersInMatchingTabs(name, meta.urlPatterns, meta.excludePatterns);
|
|
3919
3975
|
return Promise.resolve();
|
|
3920
3976
|
}));
|
|
3921
3977
|
await removePluginsBatch(removedNames);
|
|
@@ -3924,7 +3980,7 @@ var handleSyncFull = async (params) => {
|
|
|
3924
3980
|
}
|
|
3925
3981
|
const metas = uniquePlugins.map(toPluginMeta);
|
|
3926
3982
|
await storePluginsBatch(metas);
|
|
3927
|
-
const injectionResults = await Promise.allSettled(metas.map((meta) => injectPluginIntoMatchingTabs(meta.name, meta.urlPatterns, true, meta.adapterHash, meta.adapterFile, meta.adapterHash)));
|
|
3983
|
+
const injectionResults = await Promise.allSettled(metas.map((meta) => injectPluginIntoMatchingTabs(meta.name, meta.urlPatterns, true, meta.adapterHash, meta.adapterFile, meta.adapterHash, meta.excludePatterns)));
|
|
3928
3984
|
for (const result of injectionResults) {
|
|
3929
3985
|
if (result.status === "rejected") {
|
|
3930
3986
|
console.warn("[opentabs] Plugin injection failed during sync.full:", result.reason);
|
|
@@ -3946,6 +4002,8 @@ var handleSyncFull = async (params) => {
|
|
|
3946
4002
|
source: raw?.source === "npm" || raw?.source === "local" ? raw.source : "local",
|
|
3947
4003
|
tabState: "closed",
|
|
3948
4004
|
urlPatterns: p.urlPatterns,
|
|
4005
|
+
...p.excludePatterns.length > 0 ? { excludePatterns: p.excludePatterns } : {},
|
|
4006
|
+
...p.homepage ? { homepage: p.homepage } : {},
|
|
3949
4007
|
tools: p.tools,
|
|
3950
4008
|
reviewed: raw?.reviewed === true,
|
|
3951
4009
|
iconSvg: p.iconSvg,
|
|
@@ -3989,7 +4047,7 @@ var handlePluginUpdate = async (params) => {
|
|
|
3989
4047
|
return;
|
|
3990
4048
|
const meta = toPluginMeta(validated);
|
|
3991
4049
|
await storePluginsBatch([meta]);
|
|
3992
|
-
await injectPluginIntoMatchingTabs(meta.name, meta.urlPatterns, true, meta.adapterHash, meta.adapterFile);
|
|
4050
|
+
await injectPluginIntoMatchingTabs(meta.name, meta.urlPatterns, true, meta.adapterHash, meta.adapterFile, void 0, meta.excludePatterns);
|
|
3993
4051
|
const newState = await computePluginTabState(meta);
|
|
3994
4052
|
await updateLastKnownState(meta.name, newState);
|
|
3995
4053
|
sendTabStateNotification(meta.name, newState);
|
|
@@ -4002,6 +4060,8 @@ var handlePluginUpdate = async (params) => {
|
|
|
4002
4060
|
source: params.source === "npm" || params.source === "local" ? params.source : "local",
|
|
4003
4061
|
tabState: newState.state,
|
|
4004
4062
|
urlPatterns: validated.urlPatterns,
|
|
4063
|
+
...validated.excludePatterns.length > 0 ? { excludePatterns: validated.excludePatterns } : {},
|
|
4064
|
+
...validated.homepage ? { homepage: validated.homepage } : {},
|
|
4005
4065
|
tools: validated.tools,
|
|
4006
4066
|
reviewed: params.reviewed === true,
|
|
4007
4067
|
iconSvg: validated.iconSvg,
|
|
@@ -4045,7 +4105,7 @@ var handlePluginUninstall = async (params, id) => {
|
|
|
4045
4105
|
const pluginMeta = meta[pluginName];
|
|
4046
4106
|
if (pluginMeta) {
|
|
4047
4107
|
try {
|
|
4048
|
-
await cleanupAdaptersInMatchingTabs(pluginName, pluginMeta.urlPatterns);
|
|
4108
|
+
await cleanupAdaptersInMatchingTabs(pluginName, pluginMeta.urlPatterns, pluginMeta.excludePatterns);
|
|
4049
4109
|
} catch (err2) {
|
|
4050
4110
|
console.warn(`[opentabs] Failed to clean up adapters for ${pluginName}:`, err2);
|
|
4051
4111
|
}
|
|
@@ -4266,11 +4326,14 @@ var handleBgGetFullState = (_message, sendResponse) => {
|
|
|
4266
4326
|
const plugins = Object.values(metaIndex).map((meta) => {
|
|
4267
4327
|
const serverPlugin = serverPluginMap.get(meta.name);
|
|
4268
4328
|
let tabState = "closed";
|
|
4329
|
+
let tabs;
|
|
4269
4330
|
const serialized = tabStates.get(meta.name);
|
|
4270
4331
|
if (serialized) {
|
|
4271
4332
|
try {
|
|
4272
4333
|
const parsed = JSON.parse(serialized);
|
|
4273
4334
|
tabState = parsed.state;
|
|
4335
|
+
if (parsed.tabs.length > 0)
|
|
4336
|
+
tabs = parsed.tabs;
|
|
4274
4337
|
} catch {
|
|
4275
4338
|
}
|
|
4276
4339
|
}
|
|
@@ -4287,6 +4350,7 @@ var handleBgGetFullState = (_message, sendResponse) => {
|
|
|
4287
4350
|
permission: serverPlugin?.permission ?? meta.permission,
|
|
4288
4351
|
tools,
|
|
4289
4352
|
tabState,
|
|
4353
|
+
tabs,
|
|
4290
4354
|
source: serverPlugin?.source ?? "local",
|
|
4291
4355
|
reviewed: serverPlugin?.reviewed ?? false,
|
|
4292
4356
|
sdkVersion: serverPlugin?.sdkVersion,
|
|
@@ -4555,6 +4619,14 @@ var handleBgRemovePlugin = (message, sendResponse) => {
|
|
|
4555
4619
|
sendResponse({ error: err2 instanceof Error ? err2.message : String(err2) });
|
|
4556
4620
|
});
|
|
4557
4621
|
};
|
|
4622
|
+
var handleBgRemoveFailedPlugin = (message, sendResponse) => {
|
|
4623
|
+
const specifier = message.specifier;
|
|
4624
|
+
sendServerRequest("plugin.removeBySpecifier", { specifier }).then((result) => {
|
|
4625
|
+
sendResponse(result);
|
|
4626
|
+
}).catch((err2) => {
|
|
4627
|
+
sendResponse({ error: err2 instanceof Error ? err2.message : String(err2) });
|
|
4628
|
+
});
|
|
4629
|
+
};
|
|
4558
4630
|
var handleBgUpdatePlugin = (message, sendResponse) => {
|
|
4559
4631
|
const name = message.name;
|
|
4560
4632
|
sendServerRequest("plugin.updateFromRegistry", { name }).then((result) => {
|
|
@@ -4568,6 +4640,53 @@ var handlePortChanged = (message, sendResponse) => {
|
|
|
4568
4640
|
});
|
|
4569
4641
|
sendResponse({ ok: true });
|
|
4570
4642
|
};
|
|
4643
|
+
var lastFocusedTabId = /* @__PURE__ */ new Map();
|
|
4644
|
+
var pickNextTab = (sorted, pluginName) => {
|
|
4645
|
+
if (sorted.length === 0)
|
|
4646
|
+
return void 0;
|
|
4647
|
+
const lastId = lastFocusedTabId.get(pluginName);
|
|
4648
|
+
if (lastId === void 0) {
|
|
4649
|
+
return sorted.find((t) => !t.tab.active) ?? sorted[0];
|
|
4650
|
+
}
|
|
4651
|
+
const lastIdx = sorted.findIndex((t) => t.id === lastId);
|
|
4652
|
+
const nextIdx = (lastIdx + 1) % sorted.length;
|
|
4653
|
+
return sorted[nextIdx];
|
|
4654
|
+
};
|
|
4655
|
+
var handleBgOpenPluginTab = (message, sendResponse) => {
|
|
4656
|
+
const pluginName = message.pluginName;
|
|
4657
|
+
if (!pluginName) {
|
|
4658
|
+
sendResponse({ opened: false });
|
|
4659
|
+
return;
|
|
4660
|
+
}
|
|
4661
|
+
(async () => {
|
|
4662
|
+
const meta = await getPluginMeta(pluginName);
|
|
4663
|
+
if (!meta)
|
|
4664
|
+
return { opened: false };
|
|
4665
|
+
const tabs = await findAllMatchingTabs(meta);
|
|
4666
|
+
if (tabs.length > 0) {
|
|
4667
|
+
const withIds = [];
|
|
4668
|
+
for (const tab of tabs) {
|
|
4669
|
+
if (tab.id !== void 0)
|
|
4670
|
+
withIds.push({ tab, id: tab.id });
|
|
4671
|
+
}
|
|
4672
|
+
withIds.sort((a, b) => a.id - b.id);
|
|
4673
|
+
const pick = pickNextTab(withIds, pluginName);
|
|
4674
|
+
if (pick) {
|
|
4675
|
+
lastFocusedTabId.set(pluginName, pick.id);
|
|
4676
|
+
await chrome.tabs.update(pick.id, { active: true });
|
|
4677
|
+
if (pick.tab.windowId !== void 0) {
|
|
4678
|
+
await chrome.windows.update(pick.tab.windowId, { focused: true });
|
|
4679
|
+
}
|
|
4680
|
+
return { opened: true, tabId: pick.id };
|
|
4681
|
+
}
|
|
4682
|
+
}
|
|
4683
|
+
if (meta.homepage) {
|
|
4684
|
+
const newTab = await chrome.tabs.create({ url: meta.homepage });
|
|
4685
|
+
return { opened: true, tabId: newTab.id };
|
|
4686
|
+
}
|
|
4687
|
+
return { opened: false };
|
|
4688
|
+
})().then((result) => sendResponse(result)).catch(() => sendResponse({ opened: false }));
|
|
4689
|
+
};
|
|
4571
4690
|
var backgroundHandlers = /* @__PURE__ */ new Map([
|
|
4572
4691
|
["offscreen:getUrl", handleOffscreenGetUrl],
|
|
4573
4692
|
["ws:state", handleWsState],
|
|
@@ -4580,7 +4699,9 @@ var backgroundHandlers = /* @__PURE__ */ new Map([
|
|
|
4580
4699
|
["bg:searchPlugins", handleBgSearchPlugins],
|
|
4581
4700
|
["bg:installPlugin", handleBgInstallPlugin],
|
|
4582
4701
|
["bg:removePlugin", handleBgRemovePlugin],
|
|
4702
|
+
["bg:removeFailedPlugin", handleBgRemoveFailedPlugin],
|
|
4583
4703
|
["bg:updatePlugin", handleBgUpdatePlugin],
|
|
4704
|
+
["bg:openPluginTab", handleBgOpenPluginTab],
|
|
4584
4705
|
["plugin:logs", handlePluginLogs],
|
|
4585
4706
|
["tool:progress", handleToolProgress],
|
|
4586
4707
|
["sp:confirmationResponse", handleSpConfirmationResponse],
|
|
@@ -4598,7 +4719,9 @@ var EXTENSION_ONLY_TYPES = /* @__PURE__ */ new Set([
|
|
|
4598
4719
|
"bg:searchPlugins",
|
|
4599
4720
|
"bg:installPlugin",
|
|
4600
4721
|
"bg:removePlugin",
|
|
4722
|
+
"bg:removeFailedPlugin",
|
|
4601
4723
|
"bg:updatePlugin",
|
|
4724
|
+
"bg:openPluginTab",
|
|
4602
4725
|
"offscreen:getLogs",
|
|
4603
4726
|
"sp:confirmationResponse",
|
|
4604
4727
|
"port-changed"
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Clicks a DOM element matched by a CSS selector in a tab's page context.
|
|
3
|
+
* Resolves the element's bounding rect via scripting, then dispatches trusted
|
|
4
|
+
* (isTrusted: true) mouse events at the element center via CDP Input.dispatchMouseEvent.
|
|
3
5
|
* @param params - Expects `{ tabId: number, selector: string }`.
|
|
4
6
|
* @returns `{ clicked, tagName, text }` describing the clicked element.
|
|
5
7
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"interaction-commands.d.ts","sourceRoot":"","sources":["../../src/browser-commands/interaction-commands.ts"],"names":[],"mappings":"AAmBA
|
|
1
|
+
{"version":3,"file":"interaction-commands.d.ts","sourceRoot":"","sources":["../../src/browser-commands/interaction-commands.ts"],"names":[],"mappings":"AAmBA;;;;;;GAMG;AACH,eAAO,MAAM,yBAAyB,GACpC,QAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,IAAI,MAAM,GAAG,MAAM,KAClB,OAAO,CAAC,IAAI,CAoDd,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,GAAU,QAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,MAAM,GAAG,MAAM,KAAG,OAAO,CAAC,IAAI,CA2D9G,CAAC;AAEF,eAAO,MAAM,yBAAyB,GACpC,QAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,IAAI,MAAM,GAAG,MAAM,KAClB,OAAO,CAAC,IAAI,CAuDd,CAAC;AAEF,eAAO,MAAM,2BAA2B,GACtC,QAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,IAAI,MAAM,GAAG,MAAM,KAClB,OAAO,CAAC,IAAI,CAwDd,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,0BAA0B,GACrC,QAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,IAAI,MAAM,GAAG,MAAM,KAClB,OAAO,CAAC,IAAI,CAkCd,CAAC;AAEF,eAAO,MAAM,yBAAyB,GACpC,QAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,IAAI,MAAM,GAAG,MAAM,KAClB,OAAO,CAAC,IAAI,CAwDd,CAAC;AAEF,eAAO,MAAM,yBAAyB,GACpC,QAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,IAAI,MAAM,GAAG,MAAM,KAClB,OAAO,CAAC,IAAI,CAkCd,CAAC"}
|