@weavetab/mcp 2.5.0 → 2.5.1
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/AGENTS.md +49 -49
- package/ARCHITECTURE.md +590 -590
- package/LICENSE +216 -216
- package/README.md +269 -269
- package/SECURITY.md +207 -207
- package/TROUBLESHOOTING.md +373 -365
- package/dist/anticaptcha/detector.js +395 -395
- package/dist/anticaptcha/solver.js +130 -130
- package/dist/cdp/bridge.js +73 -73
- package/dist/cdp/connector.js +46 -22
- package/dist/cdp/extension.js +34 -34
- package/dist/cdp/helpers.js +174 -174
- package/dist/cdp/pruner.js +195 -195
- package/dist/cdp/ref_cache.js +66 -66
- package/dist/cdp/security.js +10 -10
- package/dist/cdp/verify.js +57 -57
- package/dist/cdp/walker.js +563 -525
- package/dist/cli/plugin.js +26 -3
- package/dist/config/loader.d.ts +0 -3
- package/dist/config/loader.js +0 -9
- package/dist/index.js +0 -4
- package/dist/intelligence/intent.js +81 -81
- package/dist/intelligence/sessionMemory.js +2 -2
- package/dist/overlay/ghost.js +22 -22
- package/dist/overlay/injector.js +89 -89
- package/dist/plugin/extension_bridge.js +54 -54
- package/dist/plugin/interface.d.ts +7 -0
- package/dist/plugin/loader.js +3 -4
- package/dist/plugin/schema.d.ts +11 -0
- package/dist/plugin/schema.js +59 -0
- package/dist/security/guard.js +18 -18
- package/dist/sensors/actionability.js +167 -167
- package/dist/sensors/guard.js +29 -29
- package/dist/sensors/network.js +15 -17
- package/dist/server.d.ts +1 -1
- package/dist/server.js +173 -144
- package/dist/state/delta.js +6 -7
- package/dist/tools/automation.js +85 -85
- package/dist/tools/canvas.js +48 -25
- package/dist/tools/checkpoint.js +94 -35
- package/dist/tools/click.js +52 -41
- package/dist/tools/clipboard.js +80 -74
- package/dist/tools/design_extract.js +441 -441
- package/dist/tools/dialog.js +13 -13
- package/dist/tools/emulation.d.ts +2 -0
- package/dist/tools/emulation.js +7 -0
- package/dist/tools/fill.js +344 -347
- package/dist/tools/find.js +78 -52
- package/dist/tools/highlight.js +67 -67
- package/dist/tools/inspect.js +54 -25
- package/dist/tools/key.js +42 -35
- package/dist/tools/navigate.d.ts +1 -1
- package/dist/tools/navigate.js +35 -35
- package/dist/tools/office/parse.js +62 -18
- package/dist/tools/pdf.d.ts +9 -0
- package/dist/tools/pdf.js +7 -4
- package/dist/tools/performance.d.ts +11 -4
- package/dist/tools/performance.js +94 -42
- package/dist/tools/performance_test.d.ts +2 -2
- package/dist/tools/performance_test.js +69 -69
- package/dist/tools/pointer.js +116 -116
- package/dist/tools/read.js +99 -67
- package/dist/tools/recording.js +9 -0
- package/dist/tools/scrape.js +146 -146
- package/dist/tools/screenshot.d.ts +2 -0
- package/dist/tools/screenshot.js +46 -4
- package/dist/tools/scroll.d.ts +3 -1
- package/dist/tools/scroll.js +13 -15
- package/dist/tools/select.d.ts +3 -0
- package/dist/tools/select.js +131 -124
- package/dist/tools/snapshot.js +8 -6
- package/dist/tools/storage.d.ts +5 -1
- package/dist/tools/storage.js +16 -0
- package/dist/tools/tabs.d.ts +7 -5
- package/dist/tools/tabs.js +79 -26
- package/dist/tools/thought.js +8 -8
- package/dist/tools/type.js +274 -274
- package/dist/tools/type_secret.js +23 -23
- package/dist/tools/upload.js +3 -3
- package/dist/tools/video_compiler.js +9 -0
- package/dist/tools/wait.js +35 -35
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/docs/DOCUMENTATION.md +583 -585
- package/docs/PLUGINS.md +139 -121
- package/docs/TOOLS.md +3 -4
- package/docs/architecture/blind-injection.md +83 -83
- package/docs/architecture/overview.md +49 -49
- package/docs/architecture/security.md +36 -36
- package/docs/architecture/transport.md +37 -37
- package/docs/cli/cli-commands.md +50 -50
- package/docs/cli/cli-flags.md +28 -28
- package/docs/cli/cli-scripting.md +35 -35
- package/docs/configuration/config-locations.md +23 -23
- package/docs/configuration/configuration.md +39 -27
- package/docs/configuration/env-variables.md +19 -19
- package/docs/configuration/folders.md +62 -55
- package/docs/desktop-automation/electron-apps.md +225 -214
- package/docs/get-started/installation.md +1 -1
- package/docs/get-started/introduction.md +60 -60
- package/docs/get-started/quickstart.md +2 -2
- package/docs/get-started/setup-wizard.md +27 -27
- package/docs/intelligence/site-profiles.md +151 -151
- package/docs/tools/tools.md +582 -631
- package/docs/troubleshooting/trouble-browser.md +27 -27
- package/docs/troubleshooting/trouble-loop.md +31 -31
- package/ext-dist/background.js +415 -415
- package/ext-dist/content.js +2527 -2527
- package/ext-dist/dashboard.html +583 -583
- package/ext-dist/hud/hud.js +3 -3
- package/ext-dist/hud/index.html +20 -20
- package/ext-dist/manifest.json +73 -73
- package/ext-dist/styles.css +223 -223
- package/mcp.json +796 -805
- package/package.json +118 -118
- package/server.json +23 -23
- package/dist/cdp/walker.test.d.ts +0 -2
- package/dist/cdp/walker.test.js +0 -172
- package/dist/intelligence/sessionMemory.test.d.ts +0 -2
- package/dist/intelligence/sessionMemory.test.js +0 -62
- package/dist/intelligence/trail.test.d.ts +0 -2
- package/dist/intelligence/trail.test.js +0 -110
- package/dist/state/cache.test.d.ts +0 -2
- package/dist/state/cache.test.js +0 -76
- package/dist/state/delta.test.d.ts +0 -2
- package/dist/state/delta.test.js +0 -279
- package/dist/state/groups.d.ts +0 -15
- package/dist/state/groups.js +0 -80
- package/dist/tools/accessibility.d.ts +0 -14
- package/dist/tools/accessibility.js +0 -32
- package/dist/tools/ask.d.ts +0 -14
- package/dist/tools/ask.js +0 -49
- package/dist/tools/click_and_wait.d.ts +0 -33
- package/dist/tools/click_and_wait.js +0 -149
- package/dist/tools/drag.d.ts +0 -15
- package/dist/tools/drag.js +0 -29
- package/dist/tools/geo.d.ts +0 -19
- package/dist/tools/geo.js +0 -29
- package/dist/tools/github/analyze.d.ts +0 -4
- package/dist/tools/github/analyze.js +0 -113
- package/dist/tools/github/cache.d.ts +0 -21
- package/dist/tools/github/cache.js +0 -28
- package/dist/tools/github/index.d.ts +0 -19
- package/dist/tools/github/index.js +0 -40
- package/dist/tools/github/issues.d.ts +0 -9
- package/dist/tools/github/issues.js +0 -88
- package/dist/tools/github/pr.d.ts +0 -5
- package/dist/tools/github/pr.js +0 -88
- package/dist/tools/github/rateLimiter.d.ts +0 -4
- package/dist/tools/github/rateLimiter.js +0 -46
- package/dist/tools/github/read.d.ts +0 -34
- package/dist/tools/github/read.js +0 -74
- package/dist/tools/github/repoContext.d.ts +0 -20
- package/dist/tools/github/repoContext.js +0 -129
- package/dist/tools/hover.d.ts +0 -19
- package/dist/tools/hover.js +0 -57
- package/dist/tools/integration.test.d.ts +0 -2
- package/dist/tools/integration.test.js +0 -96
- package/dist/tools/macro_compiler.d.ts +0 -7
- package/dist/tools/macro_compiler.js +0 -82
- package/dist/tools/mouse.d.ts +0 -21
- package/dist/tools/mouse.js +0 -62
- package/dist/tools/response.d.ts +0 -129
- package/dist/tools/response.js +0 -5
- package/dist/tools/wait_for.d.ts +0 -23
- package/dist/tools/wait_for.js +0 -30
- package/dist/tools/windows.d.ts +0 -22
- package/dist/tools/windows.js +0 -57
|
@@ -43,51 +43,51 @@ export class PluginExtensionBridge {
|
|
|
43
43
|
const safeText = JSON.stringify(text);
|
|
44
44
|
try {
|
|
45
45
|
await session.Runtime.evaluate({
|
|
46
|
-
expression: `(function() {
|
|
47
|
-
var existing = document.getElementById('__wt_plugin_thought_${this.pluginName}');
|
|
48
|
-
if (existing) existing.remove();
|
|
49
|
-
|
|
50
|
-
var bubble = document.createElement('div');
|
|
51
|
-
bubble.id = '__wt_plugin_thought_${this.pluginName}';
|
|
52
|
-
bubble.className = 'wt-bubble';
|
|
53
|
-
bubble.setAttribute('data-wt-internal', 'true');
|
|
54
|
-
bubble.style.cssText = [
|
|
55
|
-
'position: fixed',
|
|
56
|
-
'bottom: 24px',
|
|
57
|
-
'right: 24px',
|
|
58
|
-
'background: linear-gradient(135deg, rgba(17, 24, 39, 0.95), rgba(30, 41, 59, 0.95))',
|
|
59
|
-
'color: #f8fafc',
|
|
60
|
-
'padding: 12px 18px',
|
|
61
|
-
'border-radius: 12px',
|
|
62
|
-
'font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
|
63
|
-
'font-size: 13px',
|
|
64
|
-
'font-weight: 500',
|
|
65
|
-
'box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(255, 255, 255, 0.1)',
|
|
66
|
-
'z-index: 2147483647',
|
|
67
|
-
'backdrop-filter: blur(8px)',
|
|
68
|
-
'pointer-events: none',
|
|
69
|
-
'animation: wtThoughtFade 0.25s cubic-bezier(0.16, 1, 0.3, 1)',
|
|
70
|
-
'display: flex',
|
|
71
|
-
'align-items: center',
|
|
72
|
-
'gap: 8px'
|
|
73
|
-
].join(';');
|
|
74
|
-
|
|
75
|
-
var icon = document.createElement('span');
|
|
76
|
-
icon.textContent = '✨';
|
|
77
|
-
var textSpan = document.createElement('span');
|
|
78
|
-
textSpan.textContent = ${safeText};
|
|
79
|
-
|
|
80
|
-
bubble.appendChild(icon);
|
|
81
|
-
bubble.appendChild(textSpan);
|
|
82
|
-
document.body.appendChild(bubble);
|
|
83
|
-
|
|
84
|
-
setTimeout(function() {
|
|
85
|
-
if (bubble && bubble.parentNode) {
|
|
86
|
-
bubble.style.opacity = '0';
|
|
87
|
-
bubble.style.transition = 'opacity 0.3s ease';
|
|
88
|
-
setTimeout(function() { bubble.remove(); }, 300);
|
|
89
|
-
}
|
|
90
|
-
}, ${duration});
|
|
46
|
+
expression: `(function() {
|
|
47
|
+
var existing = document.getElementById('__wt_plugin_thought_${this.pluginName}');
|
|
48
|
+
if (existing) existing.remove();
|
|
49
|
+
|
|
50
|
+
var bubble = document.createElement('div');
|
|
51
|
+
bubble.id = '__wt_plugin_thought_${this.pluginName}';
|
|
52
|
+
bubble.className = 'wt-bubble';
|
|
53
|
+
bubble.setAttribute('data-wt-internal', 'true');
|
|
54
|
+
bubble.style.cssText = [
|
|
55
|
+
'position: fixed',
|
|
56
|
+
'bottom: 24px',
|
|
57
|
+
'right: 24px',
|
|
58
|
+
'background: linear-gradient(135deg, rgba(17, 24, 39, 0.95), rgba(30, 41, 59, 0.95))',
|
|
59
|
+
'color: #f8fafc',
|
|
60
|
+
'padding: 12px 18px',
|
|
61
|
+
'border-radius: 12px',
|
|
62
|
+
'font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
|
63
|
+
'font-size: 13px',
|
|
64
|
+
'font-weight: 500',
|
|
65
|
+
'box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(255, 255, 255, 0.1)',
|
|
66
|
+
'z-index: 2147483647',
|
|
67
|
+
'backdrop-filter: blur(8px)',
|
|
68
|
+
'pointer-events: none',
|
|
69
|
+
'animation: wtThoughtFade 0.25s cubic-bezier(0.16, 1, 0.3, 1)',
|
|
70
|
+
'display: flex',
|
|
71
|
+
'align-items: center',
|
|
72
|
+
'gap: 8px'
|
|
73
|
+
].join(';');
|
|
74
|
+
|
|
75
|
+
var icon = document.createElement('span');
|
|
76
|
+
icon.textContent = '✨';
|
|
77
|
+
var textSpan = document.createElement('span');
|
|
78
|
+
textSpan.textContent = ${safeText};
|
|
79
|
+
|
|
80
|
+
bubble.appendChild(icon);
|
|
81
|
+
bubble.appendChild(textSpan);
|
|
82
|
+
document.body.appendChild(bubble);
|
|
83
|
+
|
|
84
|
+
setTimeout(function() {
|
|
85
|
+
if (bubble && bubble.parentNode) {
|
|
86
|
+
bubble.style.opacity = '0';
|
|
87
|
+
bubble.style.transition = 'opacity 0.3s ease';
|
|
88
|
+
setTimeout(function() { bubble.remove(); }, 300);
|
|
89
|
+
}
|
|
90
|
+
}, ${duration});
|
|
91
91
|
})()`,
|
|
92
92
|
returnByValue: false,
|
|
93
93
|
});
|
|
@@ -101,9 +101,9 @@ export class PluginExtensionBridge {
|
|
|
101
101
|
return;
|
|
102
102
|
try {
|
|
103
103
|
await session.Runtime.evaluate({
|
|
104
|
-
expression: `(function() {
|
|
105
|
-
var existing = document.getElementById('__wt_plugin_thought_${this.pluginName}');
|
|
106
|
-
if (existing) existing.remove();
|
|
104
|
+
expression: `(function() {
|
|
105
|
+
var existing = document.getElementById('__wt_plugin_thought_${this.pluginName}');
|
|
106
|
+
if (existing) existing.remove();
|
|
107
107
|
})()`,
|
|
108
108
|
returnByValue: false,
|
|
109
109
|
});
|
|
@@ -118,12 +118,12 @@ export class PluginExtensionBridge {
|
|
|
118
118
|
return;
|
|
119
119
|
const safeCss = JSON.stringify(css);
|
|
120
120
|
await session.Runtime.evaluate({
|
|
121
|
-
expression: `(function() {
|
|
122
|
-
var styleId = '__wt_plugin_styles_${this.pluginName}';
|
|
123
|
-
var style = document.getElementById(styleId) || document.createElement('style');
|
|
124
|
-
style.id = styleId;
|
|
125
|
-
style.textContent = ${safeCss};
|
|
126
|
-
if (!style.parentNode) document.head.appendChild(style);
|
|
121
|
+
expression: `(function() {
|
|
122
|
+
var styleId = '__wt_plugin_styles_${this.pluginName}';
|
|
123
|
+
var style = document.getElementById(styleId) || document.createElement('style');
|
|
124
|
+
style.id = styleId;
|
|
125
|
+
style.textContent = ${safeCss};
|
|
126
|
+
if (!style.parentNode) document.head.appendChild(style);
|
|
127
127
|
})()`,
|
|
128
128
|
returnByValue: false,
|
|
129
129
|
});
|
|
@@ -7,6 +7,11 @@ export interface WeavetabToolDefinition {
|
|
|
7
7
|
name: string;
|
|
8
8
|
description: string;
|
|
9
9
|
schema: Record<string, z.ZodType<any>>;
|
|
10
|
+
/**
|
|
11
|
+
* When `false`, the host does NOT establish a browser/CDP session before
|
|
12
|
+
* invoking this tool. Use for API-only tools. Defaults to `true`.
|
|
13
|
+
*/
|
|
14
|
+
requiresSession?: boolean;
|
|
10
15
|
handler: (args: Record<string, any>, session: CDP.Client, config: Config) => Promise<Record<string, any>>;
|
|
11
16
|
}
|
|
12
17
|
export interface WeavetabToolOverride {
|
|
@@ -146,6 +151,8 @@ export interface WeavetabPluginTool<TArgs = any> {
|
|
|
146
151
|
schema?: Record<string, any> | Record<string, z.ZodType<any>>;
|
|
147
152
|
inputSchema?: Record<string, any>;
|
|
148
153
|
parameters?: Record<string, any>;
|
|
154
|
+
/** See {@link WeavetabToolDefinition.requiresSession}. Defaults to `true`. */
|
|
155
|
+
requiresSession?: boolean;
|
|
149
156
|
handler: (args: TArgs, session?: any, config?: any) => Promise<any>;
|
|
150
157
|
}
|
|
151
158
|
export interface DOMMutationDelta {
|
package/dist/plugin/loader.js
CHANGED
|
@@ -17,7 +17,6 @@ function getNodeModulesDirs(customDir) {
|
|
|
17
17
|
join(cwd, "MCP", "node_modules"),
|
|
18
18
|
join(cwd, "..", "node_modules"),
|
|
19
19
|
join(os.homedir(), ".weavetab", "plugins", "node_modules"),
|
|
20
|
-
join(os.homedir(), ".weavetab-system", "plugins", "node_modules"),
|
|
21
20
|
];
|
|
22
21
|
return Array.from(new Set(dirs.filter((d) => existsSync(d))));
|
|
23
22
|
}
|
|
@@ -152,7 +151,7 @@ export function listInstalledPlugins(pluginDir) {
|
|
|
152
151
|
if (!entry.isDirectory() && !entry.isSymbolicLink())
|
|
153
152
|
continue;
|
|
154
153
|
if (entry.name.startsWith("@")) {
|
|
155
|
-
// Scoped packages (@weavetab/plugin-xyz, @scope/xyz, @
|
|
154
|
+
// Scoped packages (@weavetab/plugin-xyz, @scope/xyz, @acme/weavetab-plugin)
|
|
156
155
|
const scopeDir = join(modulesDir, entry.name);
|
|
157
156
|
try {
|
|
158
157
|
const scopeEntries = readdirSync(scopeDir, { withFileTypes: true });
|
|
@@ -419,7 +418,7 @@ export function discoverPlugins(pluginDir) {
|
|
|
419
418
|
if (!entry.isDirectory() && !entry.isSymbolicLink())
|
|
420
419
|
continue;
|
|
421
420
|
if (entry.name.startsWith("@")) {
|
|
422
|
-
// Scoped package directory (e.g. @weavetab, @
|
|
421
|
+
// Scoped package directory (e.g. @weavetab, @acme, @mycompany)
|
|
423
422
|
const scopeDir = join(modulesDir, entry.name);
|
|
424
423
|
try {
|
|
425
424
|
const scopeEntries = readdirSync(scopeDir, { withFileTypes: true });
|
|
@@ -436,7 +435,7 @@ export function discoverPlugins(pluginDir) {
|
|
|
436
435
|
catch { /* scope dir unreadable */ }
|
|
437
436
|
}
|
|
438
437
|
else {
|
|
439
|
-
// Top-level package — any name works: wt-
|
|
438
|
+
// Top-level package — any name works: my-plugin, wt-github, custom-plugin, etc.
|
|
440
439
|
const plugin = tryLoadPlugin(join(modulesDir, entry.name));
|
|
441
440
|
if (plugin && !seenPluginNames.has(plugin.name)) {
|
|
442
441
|
seenPluginNames.add(plugin.name);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Weavetab by fy2ne
|
|
3
|
+
* @file schema.ts — Plugin tool schema normalizer.
|
|
4
|
+
*
|
|
5
|
+
* Converts a plugin-provided tool schema into a Zod raw shape accepted by
|
|
6
|
+
* `McpServer.tool()`. Supports the three shapes plugin authors may provide:
|
|
7
|
+
* 1. Zod raw shape — { field: z.string() } (preferred)
|
|
8
|
+
* 2. Zod object schema — z.object({ field: z.string() })
|
|
9
|
+
* 3. Plain JSON Schema — { type: "object", properties: { field: { type: "string" } } }
|
|
10
|
+
*/
|
|
11
|
+
export declare function toPluginInputShape(schema: any): Record<string, any>;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Weavetab by fy2ne
|
|
3
|
+
* @file schema.ts — Plugin tool schema normalizer.
|
|
4
|
+
*
|
|
5
|
+
* Converts a plugin-provided tool schema into a Zod raw shape accepted by
|
|
6
|
+
* `McpServer.tool()`. Supports the three shapes plugin authors may provide:
|
|
7
|
+
* 1. Zod raw shape — { field: z.string() } (preferred)
|
|
8
|
+
* 2. Zod object schema — z.object({ field: z.string() })
|
|
9
|
+
* 3. Plain JSON Schema — { type: "object", properties: { field: { type: "string" } } }
|
|
10
|
+
*/
|
|
11
|
+
import { z } from "zod";
|
|
12
|
+
export function toPluginInputShape(schema) {
|
|
13
|
+
if (!schema || typeof schema !== "object")
|
|
14
|
+
return {};
|
|
15
|
+
// A Zod object/schema instance (e.g. z.object({...})) — use its shape.
|
|
16
|
+
if (schema._def || schema._zod) {
|
|
17
|
+
const shape = typeof schema.shape === "function" ? schema.shape() : schema.shape;
|
|
18
|
+
return shape && typeof shape === "object" ? shape : {};
|
|
19
|
+
}
|
|
20
|
+
// A raw shape: an object whose values are Zod schemas.
|
|
21
|
+
const values = Object.values(schema);
|
|
22
|
+
if (values.some((v) => v && typeof v === "object" && (v._def || v._zod || typeof v.parse === "function"))) {
|
|
23
|
+
return schema;
|
|
24
|
+
}
|
|
25
|
+
// A plain JSON Schema object — convert its properties into a Zod raw shape.
|
|
26
|
+
if (schema.properties && typeof schema.properties === "object") {
|
|
27
|
+
const required = Array.isArray(schema.required) ? schema.required : [];
|
|
28
|
+
const shape = {};
|
|
29
|
+
for (const [key, prop] of Object.entries(schema.properties)) {
|
|
30
|
+
let field;
|
|
31
|
+
switch (prop?.type) {
|
|
32
|
+
case "number":
|
|
33
|
+
case "integer":
|
|
34
|
+
field = z.number();
|
|
35
|
+
break;
|
|
36
|
+
case "boolean":
|
|
37
|
+
field = z.boolean();
|
|
38
|
+
break;
|
|
39
|
+
case "array":
|
|
40
|
+
field = z.array(z.any());
|
|
41
|
+
break;
|
|
42
|
+
case "object":
|
|
43
|
+
field = z.record(z.string(), z.any());
|
|
44
|
+
break;
|
|
45
|
+
default:
|
|
46
|
+
field = z.string();
|
|
47
|
+
}
|
|
48
|
+
if (typeof prop?.description === "string")
|
|
49
|
+
field = field.describe(prop.description);
|
|
50
|
+
if (prop?.default !== undefined)
|
|
51
|
+
field = field.default(prop.default);
|
|
52
|
+
if (!required.includes(key))
|
|
53
|
+
field = field.optional();
|
|
54
|
+
shape[key] = field;
|
|
55
|
+
}
|
|
56
|
+
return shape;
|
|
57
|
+
}
|
|
58
|
+
return {};
|
|
59
|
+
}
|
package/dist/security/guard.js
CHANGED
|
@@ -4,24 +4,24 @@ export function assertNotRoot() {
|
|
|
4
4
|
throw new Error("[!] Weave failed: Running as root is not allowed. Start Weavetab as a normal user.");
|
|
5
5
|
}
|
|
6
6
|
}
|
|
7
|
-
const STORAGE_BLOCK_SCRIPT = `
|
|
8
|
-
(function() {
|
|
9
|
-
// Only block cookie WRITES for known tracking domains, not reads.
|
|
10
|
-
// Fully blocking storage breaks site rendering (GitHub, etc.)
|
|
11
|
-
var _origCookieDesc = Object.getOwnPropertyDescriptor(document, 'cookie');
|
|
12
|
-
if (_origCookieDesc) {
|
|
13
|
-
Object.defineProperty(document, 'cookie', {
|
|
14
|
-
get: function() { return _origCookieDesc.get.call(document); },
|
|
15
|
-
set: function(v) {
|
|
16
|
-
// Block cookies from known trackers
|
|
17
|
-
if (/(_ga|_gid|_fbp|_fbc|__utm|fr|_gcl)/.test(v)) return;
|
|
18
|
-
_origCookieDesc.set.call(document, v);
|
|
19
|
-
},
|
|
20
|
-
configurable: true
|
|
21
|
-
});
|
|
22
|
-
}
|
|
23
|
-
// Do NOT block localStorage/sessionStorage — sites need them to render
|
|
24
|
-
})();
|
|
7
|
+
const STORAGE_BLOCK_SCRIPT = `
|
|
8
|
+
(function() {
|
|
9
|
+
// Only block cookie WRITES for known tracking domains, not reads.
|
|
10
|
+
// Fully blocking storage breaks site rendering (GitHub, etc.)
|
|
11
|
+
var _origCookieDesc = Object.getOwnPropertyDescriptor(document, 'cookie');
|
|
12
|
+
if (_origCookieDesc) {
|
|
13
|
+
Object.defineProperty(document, 'cookie', {
|
|
14
|
+
get: function() { return _origCookieDesc.get.call(document); },
|
|
15
|
+
set: function(v) {
|
|
16
|
+
// Block cookies from known trackers
|
|
17
|
+
if (/(_ga|_gid|_fbp|_fbc|__utm|fr|_gcl)/.test(v)) return;
|
|
18
|
+
_origCookieDesc.set.call(document, v);
|
|
19
|
+
},
|
|
20
|
+
configurable: true
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
// Do NOT block localStorage/sessionStorage — sites need them to render
|
|
24
|
+
})();
|
|
25
25
|
`;
|
|
26
26
|
export async function blockStorageAccess(session) {
|
|
27
27
|
await session.Page.addScriptToEvaluateOnNewDocument({
|
|
@@ -48,137 +48,137 @@ function buildPageExpression(selector, scrollOptions, fingerprint, stabilityMs)
|
|
|
48
48
|
const selectorLiteral = JSON.stringify(selector);
|
|
49
49
|
const scrollLiteral = scrollOptions ? JSON.stringify(scrollOptions) : "null";
|
|
50
50
|
const fingerprintLiteral = fingerprint ? JSON.stringify(fingerprint) : "null";
|
|
51
|
-
return `(async function() {
|
|
52
|
-
// ── Helper: is this node owned by WeaveTab? ────────────────────────────
|
|
53
|
-
function isWtOwned(el) {
|
|
54
|
-
if (!el) return false;
|
|
55
|
-
// Attribute-based markers: data-wt-ignore and data-wt-internal both signal
|
|
56
|
-
// WeaveTab-owned UI that must not block page interactions.
|
|
57
|
-
if (el.getAttribute && (
|
|
58
|
-
el.getAttribute('data-wt-ignore') !== null ||
|
|
59
|
-
el.getAttribute('data-wt-internal') !== null ||
|
|
60
|
-
el.getAttribute('data-wt-overlay') !== null
|
|
61
|
-
)) return true;
|
|
62
|
-
const wtIds = ['Weavetab-hud', '__Weavetab_controlled_indicator', 'wt-main-container', 'wt-system-icon', 'wt-f3-host', 'Weavetab-root'];
|
|
63
|
-
if (el.id && wtIds.includes(el.id)) return true;
|
|
64
|
-
if (el.closest) {
|
|
65
|
-
if (el.closest('[data-wt-ignore],[data-wt-internal],[data-wt-overlay]')) return true;
|
|
66
|
-
if (wtIds.some(id => el.closest('#' + id))) return true;
|
|
67
|
-
}
|
|
68
|
-
return false;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// ── Step 1: Resolve element ────────────────────────────────────────────
|
|
72
|
-
let el = document.querySelector(${selectorLiteral});
|
|
73
|
-
if (!el && window.__Weavetab_shadowQuery) {
|
|
74
|
-
el = window.__Weavetab_shadowQuery(${selectorLiteral});
|
|
75
|
-
}
|
|
76
|
-
if (!el) return { status: 'NOT_FOUND' };
|
|
77
|
-
|
|
78
|
-
// ── Step 2: Fingerprint check ──────────────────────────────────────────
|
|
79
|
-
const fp = ${fingerprintLiteral};
|
|
80
|
-
if (fp) {
|
|
81
|
-
if (fp.tag && el.tagName.toLowerCase() !== fp.tag.toLowerCase())
|
|
82
|
-
return { status: 'FINGERPRINT_MISMATCH' };
|
|
83
|
-
if (fp.role && el.getAttribute('role') !== fp.role)
|
|
84
|
-
return { status: 'FINGERPRINT_MISMATCH' };
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// ── Step 3: Basic visibility ───────────────────────────────────────────
|
|
88
|
-
// Use checkVisibility() (Chrome 105+) as the most reliable single check.
|
|
89
|
-
// Falls back to manual computed-style + rect checks for older runtimes.
|
|
90
|
-
if (typeof el.checkVisibility === 'function') {
|
|
91
|
-
if (!el.checkVisibility({ checkOpacity: true, checkVisibilityCSS: true }))
|
|
92
|
-
return { status: 'INVISIBLE' };
|
|
93
|
-
} else {
|
|
94
|
-
const cs = window.getComputedStyle(el);
|
|
95
|
-
if (cs.display === 'none' || cs.visibility === 'hidden' || cs.opacity === '0')
|
|
96
|
-
return { status: 'INVISIBLE' };
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
let rect = el.getBoundingClientRect();
|
|
100
|
-
if (rect.width === 0 || rect.height === 0) return { status: 'INVISIBLE' };
|
|
101
|
-
// Off-screen by more than 2× viewport dimension in any direction
|
|
102
|
-
if (rect.right < -window.innerWidth || rect.bottom < -window.innerHeight ||
|
|
103
|
-
rect.left > 2 * window.innerWidth || rect.top > 2 * window.innerHeight)
|
|
104
|
-
return { status: 'INVISIBLE' };
|
|
105
|
-
|
|
106
|
-
// ── Step 4: Scroll into view (using provided alignment) ────────────────
|
|
107
|
-
const scrollOpts = ${scrollLiteral};
|
|
108
|
-
if (scrollOpts) {
|
|
109
|
-
el.scrollIntoView(scrollOpts);
|
|
110
|
-
await new Promise(r => setTimeout(r, 120));
|
|
111
|
-
} else if (rect.top < 0 || rect.bottom > window.innerHeight ||
|
|
112
|
-
rect.left < 0 || rect.right > window.innerWidth) {
|
|
113
|
-
el.scrollIntoView({ block: 'nearest', inline: 'nearest' });
|
|
114
|
-
await new Promise(r => setTimeout(r, 120));
|
|
115
|
-
}
|
|
116
|
-
rect = el.getBoundingClientRect();
|
|
117
|
-
|
|
118
|
-
// ── Step 5: RAF-stability gate ─────────────────────────────────────────
|
|
119
|
-
const stabilityDeadline = Date.now() + ${stabilityMs};
|
|
120
|
-
let prevRect = el.getBoundingClientRect();
|
|
121
|
-
let stable = false;
|
|
122
|
-
while (Date.now() < stabilityDeadline) {
|
|
123
|
-
await new Promise(r => requestAnimationFrame(r));
|
|
124
|
-
const cur = el.getBoundingClientRect();
|
|
125
|
-
if (
|
|
126
|
-
Math.abs(cur.x - prevRect.x) < 0.5 &&
|
|
127
|
-
Math.abs(cur.y - prevRect.y) < 0.5 &&
|
|
128
|
-
Math.abs(cur.width - prevRect.width) < 0.5 &&
|
|
129
|
-
Math.abs(cur.height - prevRect.height) < 0.5
|
|
130
|
-
) {
|
|
131
|
-
stable = true;
|
|
132
|
-
break;
|
|
133
|
-
}
|
|
134
|
-
prevRect = cur;
|
|
135
|
-
}
|
|
136
|
-
if (!stable) return { status: 'UNSTABLE' };
|
|
137
|
-
rect = el.getBoundingClientRect();
|
|
138
|
-
|
|
139
|
-
// ── Step 6: Compute click centre (clamped to viewport) ─────────────────
|
|
140
|
-
const cx = Math.round(Math.min(Math.max(rect.left + rect.width / 2, 0), window.innerWidth - 1));
|
|
141
|
-
const cy = Math.round(Math.min(Math.max(rect.top + rect.height / 2, 0), window.innerHeight - 1));
|
|
142
|
-
|
|
143
|
-
// ── Step 7: Strict hit-target check ───────────────────────────────────
|
|
144
|
-
// elementsFromPoint returns the full composited stack, topmost first.
|
|
145
|
-
const stack = document.elementsFromPoint(cx, cy);
|
|
146
|
-
if (!stack || stack.length === 0) return { status: 'ACTIONABLE', x: cx, y: cy };
|
|
147
|
-
|
|
148
|
-
// Walk from the topmost element. Anything that is WeaveTab-owned is
|
|
149
|
-
// transparent — skip it. The first non-WT element must be el or its descendant.
|
|
150
|
-
let blocker = null;
|
|
151
|
-
for (const hit of stack) {
|
|
152
|
-
if (isWtOwned(hit)) continue; // WeaveTab transparency
|
|
153
|
-
blocker = hit;
|
|
154
|
-
break;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
if (!blocker || blocker === el || el.contains(blocker)) {
|
|
158
|
-
return { status: 'ACTIONABLE', x: cx, y: cy };
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
// Check composed tree (shadow DOM + slots)
|
|
162
|
-
let ancestor = blocker;
|
|
163
|
-
while (ancestor) {
|
|
164
|
-
if (ancestor === el) return { status: 'ACTIONABLE', x: cx, y: cy };
|
|
165
|
-
ancestor = ancestor.assignedSlot || ancestor.parentElement ||
|
|
166
|
-
(ancestor.getRootNode && ancestor.getRootNode({ composed: true }) !== ancestor
|
|
167
|
-
? ancestor.getRootNode({ composed: true }).host : null);
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
return {
|
|
171
|
-
status: 'OCCLUDED',
|
|
172
|
-
x: cx, y: cy,
|
|
173
|
-
occludedBy: {
|
|
174
|
-
tag: blocker.tagName.toLowerCase(),
|
|
175
|
-
id: blocker.id || '',
|
|
176
|
-
className: (blocker.className && typeof blocker.className === 'string')
|
|
177
|
-
? blocker.className.slice(0, 60) : '',
|
|
178
|
-
ariaLabel: blocker.getAttribute('aria-label') || blocker.getAttribute('title') || null,
|
|
179
|
-
isWeavetabOwned: isWtOwned(blocker)
|
|
180
|
-
}
|
|
181
|
-
};
|
|
51
|
+
return `(async function() {
|
|
52
|
+
// ── Helper: is this node owned by WeaveTab? ────────────────────────────
|
|
53
|
+
function isWtOwned(el) {
|
|
54
|
+
if (!el) return false;
|
|
55
|
+
// Attribute-based markers: data-wt-ignore and data-wt-internal both signal
|
|
56
|
+
// WeaveTab-owned UI that must not block page interactions.
|
|
57
|
+
if (el.getAttribute && (
|
|
58
|
+
el.getAttribute('data-wt-ignore') !== null ||
|
|
59
|
+
el.getAttribute('data-wt-internal') !== null ||
|
|
60
|
+
el.getAttribute('data-wt-overlay') !== null
|
|
61
|
+
)) return true;
|
|
62
|
+
const wtIds = ['Weavetab-hud', '__Weavetab_controlled_indicator', 'wt-main-container', 'wt-system-icon', 'wt-f3-host', 'Weavetab-root'];
|
|
63
|
+
if (el.id && wtIds.includes(el.id)) return true;
|
|
64
|
+
if (el.closest) {
|
|
65
|
+
if (el.closest('[data-wt-ignore],[data-wt-internal],[data-wt-overlay]')) return true;
|
|
66
|
+
if (wtIds.some(id => el.closest('#' + id))) return true;
|
|
67
|
+
}
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// ── Step 1: Resolve element ────────────────────────────────────────────
|
|
72
|
+
let el = document.querySelector(${selectorLiteral});
|
|
73
|
+
if (!el && window.__Weavetab_shadowQuery) {
|
|
74
|
+
el = window.__Weavetab_shadowQuery(${selectorLiteral});
|
|
75
|
+
}
|
|
76
|
+
if (!el) return { status: 'NOT_FOUND' };
|
|
77
|
+
|
|
78
|
+
// ── Step 2: Fingerprint check ──────────────────────────────────────────
|
|
79
|
+
const fp = ${fingerprintLiteral};
|
|
80
|
+
if (fp) {
|
|
81
|
+
if (fp.tag && el.tagName.toLowerCase() !== fp.tag.toLowerCase())
|
|
82
|
+
return { status: 'FINGERPRINT_MISMATCH' };
|
|
83
|
+
if (fp.role && el.getAttribute('role') !== fp.role)
|
|
84
|
+
return { status: 'FINGERPRINT_MISMATCH' };
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// ── Step 3: Basic visibility ───────────────────────────────────────────
|
|
88
|
+
// Use checkVisibility() (Chrome 105+) as the most reliable single check.
|
|
89
|
+
// Falls back to manual computed-style + rect checks for older runtimes.
|
|
90
|
+
if (typeof el.checkVisibility === 'function') {
|
|
91
|
+
if (!el.checkVisibility({ checkOpacity: true, checkVisibilityCSS: true }))
|
|
92
|
+
return { status: 'INVISIBLE' };
|
|
93
|
+
} else {
|
|
94
|
+
const cs = window.getComputedStyle(el);
|
|
95
|
+
if (cs.display === 'none' || cs.visibility === 'hidden' || cs.opacity === '0')
|
|
96
|
+
return { status: 'INVISIBLE' };
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
let rect = el.getBoundingClientRect();
|
|
100
|
+
if (rect.width === 0 || rect.height === 0) return { status: 'INVISIBLE' };
|
|
101
|
+
// Off-screen by more than 2× viewport dimension in any direction
|
|
102
|
+
if (rect.right < -window.innerWidth || rect.bottom < -window.innerHeight ||
|
|
103
|
+
rect.left > 2 * window.innerWidth || rect.top > 2 * window.innerHeight)
|
|
104
|
+
return { status: 'INVISIBLE' };
|
|
105
|
+
|
|
106
|
+
// ── Step 4: Scroll into view (using provided alignment) ────────────────
|
|
107
|
+
const scrollOpts = ${scrollLiteral};
|
|
108
|
+
if (scrollOpts) {
|
|
109
|
+
el.scrollIntoView(scrollOpts);
|
|
110
|
+
await new Promise(r => setTimeout(r, 120));
|
|
111
|
+
} else if (rect.top < 0 || rect.bottom > window.innerHeight ||
|
|
112
|
+
rect.left < 0 || rect.right > window.innerWidth) {
|
|
113
|
+
el.scrollIntoView({ block: 'nearest', inline: 'nearest' });
|
|
114
|
+
await new Promise(r => setTimeout(r, 120));
|
|
115
|
+
}
|
|
116
|
+
rect = el.getBoundingClientRect();
|
|
117
|
+
|
|
118
|
+
// ── Step 5: RAF-stability gate ─────────────────────────────────────────
|
|
119
|
+
const stabilityDeadline = Date.now() + ${stabilityMs};
|
|
120
|
+
let prevRect = el.getBoundingClientRect();
|
|
121
|
+
let stable = false;
|
|
122
|
+
while (Date.now() < stabilityDeadline) {
|
|
123
|
+
await new Promise(r => requestAnimationFrame(r));
|
|
124
|
+
const cur = el.getBoundingClientRect();
|
|
125
|
+
if (
|
|
126
|
+
Math.abs(cur.x - prevRect.x) < 0.5 &&
|
|
127
|
+
Math.abs(cur.y - prevRect.y) < 0.5 &&
|
|
128
|
+
Math.abs(cur.width - prevRect.width) < 0.5 &&
|
|
129
|
+
Math.abs(cur.height - prevRect.height) < 0.5
|
|
130
|
+
) {
|
|
131
|
+
stable = true;
|
|
132
|
+
break;
|
|
133
|
+
}
|
|
134
|
+
prevRect = cur;
|
|
135
|
+
}
|
|
136
|
+
if (!stable) return { status: 'UNSTABLE' };
|
|
137
|
+
rect = el.getBoundingClientRect();
|
|
138
|
+
|
|
139
|
+
// ── Step 6: Compute click centre (clamped to viewport) ─────────────────
|
|
140
|
+
const cx = Math.round(Math.min(Math.max(rect.left + rect.width / 2, 0), window.innerWidth - 1));
|
|
141
|
+
const cy = Math.round(Math.min(Math.max(rect.top + rect.height / 2, 0), window.innerHeight - 1));
|
|
142
|
+
|
|
143
|
+
// ── Step 7: Strict hit-target check ───────────────────────────────────
|
|
144
|
+
// elementsFromPoint returns the full composited stack, topmost first.
|
|
145
|
+
const stack = document.elementsFromPoint(cx, cy);
|
|
146
|
+
if (!stack || stack.length === 0) return { status: 'ACTIONABLE', x: cx, y: cy };
|
|
147
|
+
|
|
148
|
+
// Walk from the topmost element. Anything that is WeaveTab-owned is
|
|
149
|
+
// transparent — skip it. The first non-WT element must be el or its descendant.
|
|
150
|
+
let blocker = null;
|
|
151
|
+
for (const hit of stack) {
|
|
152
|
+
if (isWtOwned(hit)) continue; // WeaveTab transparency
|
|
153
|
+
blocker = hit;
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (!blocker || blocker === el || el.contains(blocker)) {
|
|
158
|
+
return { status: 'ACTIONABLE', x: cx, y: cy };
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Check composed tree (shadow DOM + slots)
|
|
162
|
+
let ancestor = blocker;
|
|
163
|
+
while (ancestor) {
|
|
164
|
+
if (ancestor === el) return { status: 'ACTIONABLE', x: cx, y: cy };
|
|
165
|
+
ancestor = ancestor.assignedSlot || ancestor.parentElement ||
|
|
166
|
+
(ancestor.getRootNode && ancestor.getRootNode({ composed: true }) !== ancestor
|
|
167
|
+
? ancestor.getRootNode({ composed: true }).host : null);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return {
|
|
171
|
+
status: 'OCCLUDED',
|
|
172
|
+
x: cx, y: cy,
|
|
173
|
+
occludedBy: {
|
|
174
|
+
tag: blocker.tagName.toLowerCase(),
|
|
175
|
+
id: blocker.id || '',
|
|
176
|
+
className: (blocker.className && typeof blocker.className === 'string')
|
|
177
|
+
? blocker.className.slice(0, 60) : '',
|
|
178
|
+
ariaLabel: blocker.getAttribute('aria-label') || blocker.getAttribute('title') || null,
|
|
179
|
+
isWeavetabOwned: isWtOwned(blocker)
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
182
|
})()`;
|
|
183
183
|
}
|
|
184
184
|
// ── Main export ───────────────────────────────────────────────────────────────
|
|
@@ -255,42 +255,42 @@ export async function verifyActionability(session, selector, opts = {}) {
|
|
|
255
255
|
* Used for lightweight pre-dispatch validation inside click.ts.
|
|
256
256
|
*/
|
|
257
257
|
export async function quickHitCheck(session, x, y, selectorOfTarget) {
|
|
258
|
-
const expr = `(function() {
|
|
259
|
-
function isWtOwned(el) {
|
|
260
|
-
if (!el) return false;
|
|
261
|
-
if (el.getAttribute && (
|
|
262
|
-
el.getAttribute('data-wt-ignore') !== null ||
|
|
263
|
-
el.getAttribute('data-wt-internal') !== null ||
|
|
264
|
-
el.getAttribute('data-wt-overlay') !== null
|
|
265
|
-
)) return true;
|
|
266
|
-
const ids = ['Weavetab-hud','__Weavetab_controlled_indicator','wt-main-container','wt-system-icon','wt-f3-host','Weavetab-root'];
|
|
267
|
-
if (el.id && ids.includes(el.id)) return true;
|
|
268
|
-
return !!(el.closest && (el.closest('[data-wt-ignore],[data-wt-internal],[data-wt-overlay]') || ids.some(id => el.closest('#' + id))));
|
|
269
|
-
}
|
|
270
|
-
const target = document.querySelector(${JSON.stringify(selectorOfTarget)})
|
|
271
|
-
|| (window.__Weavetab_shadowQuery ? window.__Weavetab_shadowQuery(${JSON.stringify(selectorOfTarget)}) : null);
|
|
272
|
-
const stack = document.elementsFromPoint(${x}, ${y});
|
|
273
|
-
if (!stack || !stack.length) return { clear: true };
|
|
274
|
-
for (const hit of stack) {
|
|
275
|
-
if (isWtOwned(hit)) continue;
|
|
276
|
-
if (!target || hit === target || target.contains(hit)) return { clear: true };
|
|
277
|
-
// Walk composed tree for shadow DOM
|
|
278
|
-
let ancestor = hit;
|
|
279
|
-
while (ancestor) {
|
|
280
|
-
if (ancestor === target) return { clear: true };
|
|
281
|
-
ancestor = ancestor.assignedSlot || ancestor.parentElement ||
|
|
282
|
-
(ancestor.getRootNode && ancestor.getRootNode({composed:true}) !== ancestor
|
|
283
|
-
? ancestor.getRootNode({composed:true}).host : null);
|
|
284
|
-
}
|
|
285
|
-
return {
|
|
286
|
-
clear: false,
|
|
287
|
-
blockerDescription: hit.tagName.toLowerCase() +
|
|
288
|
-
(hit.id ? '#' + hit.id : '') +
|
|
289
|
-
(hit.className && typeof hit.className === 'string' ? '.' + hit.className.split(' ')[0] : '') +
|
|
290
|
-
' intercepts pointer events'
|
|
291
|
-
};
|
|
292
|
-
}
|
|
293
|
-
return { clear: true };
|
|
258
|
+
const expr = `(function() {
|
|
259
|
+
function isWtOwned(el) {
|
|
260
|
+
if (!el) return false;
|
|
261
|
+
if (el.getAttribute && (
|
|
262
|
+
el.getAttribute('data-wt-ignore') !== null ||
|
|
263
|
+
el.getAttribute('data-wt-internal') !== null ||
|
|
264
|
+
el.getAttribute('data-wt-overlay') !== null
|
|
265
|
+
)) return true;
|
|
266
|
+
const ids = ['Weavetab-hud','__Weavetab_controlled_indicator','wt-main-container','wt-system-icon','wt-f3-host','Weavetab-root'];
|
|
267
|
+
if (el.id && ids.includes(el.id)) return true;
|
|
268
|
+
return !!(el.closest && (el.closest('[data-wt-ignore],[data-wt-internal],[data-wt-overlay]') || ids.some(id => el.closest('#' + id))));
|
|
269
|
+
}
|
|
270
|
+
const target = document.querySelector(${JSON.stringify(selectorOfTarget)})
|
|
271
|
+
|| (window.__Weavetab_shadowQuery ? window.__Weavetab_shadowQuery(${JSON.stringify(selectorOfTarget)}) : null);
|
|
272
|
+
const stack = document.elementsFromPoint(${x}, ${y});
|
|
273
|
+
if (!stack || !stack.length) return { clear: true };
|
|
274
|
+
for (const hit of stack) {
|
|
275
|
+
if (isWtOwned(hit)) continue;
|
|
276
|
+
if (!target || hit === target || target.contains(hit)) return { clear: true };
|
|
277
|
+
// Walk composed tree for shadow DOM
|
|
278
|
+
let ancestor = hit;
|
|
279
|
+
while (ancestor) {
|
|
280
|
+
if (ancestor === target) return { clear: true };
|
|
281
|
+
ancestor = ancestor.assignedSlot || ancestor.parentElement ||
|
|
282
|
+
(ancestor.getRootNode && ancestor.getRootNode({composed:true}) !== ancestor
|
|
283
|
+
? ancestor.getRootNode({composed:true}).host : null);
|
|
284
|
+
}
|
|
285
|
+
return {
|
|
286
|
+
clear: false,
|
|
287
|
+
blockerDescription: hit.tagName.toLowerCase() +
|
|
288
|
+
(hit.id ? '#' + hit.id : '') +
|
|
289
|
+
(hit.className && typeof hit.className === 'string' ? '.' + hit.className.split(' ')[0] : '') +
|
|
290
|
+
' intercepts pointer events'
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
return { clear: true };
|
|
294
294
|
})()`;
|
|
295
295
|
try {
|
|
296
296
|
const { result } = await session.Runtime.evaluate({ expression: expr, returnByValue: true });
|