@predicatelabs/sdk 0.99.9
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/LICENSE +24 -0
- package/README.md +252 -0
- package/dist/actions.d.ts +185 -0
- package/dist/actions.d.ts.map +1 -0
- package/dist/actions.js +1120 -0
- package/dist/actions.js.map +1 -0
- package/dist/agent-runtime.d.ts +352 -0
- package/dist/agent-runtime.d.ts.map +1 -0
- package/dist/agent-runtime.js +1170 -0
- package/dist/agent-runtime.js.map +1 -0
- package/dist/agent.d.ts +164 -0
- package/dist/agent.d.ts.map +1 -0
- package/dist/agent.js +408 -0
- package/dist/agent.js.map +1 -0
- package/dist/asserts/expect.d.ts +159 -0
- package/dist/asserts/expect.d.ts.map +1 -0
- package/dist/asserts/expect.js +547 -0
- package/dist/asserts/expect.js.map +1 -0
- package/dist/asserts/index.d.ts +58 -0
- package/dist/asserts/index.d.ts.map +1 -0
- package/dist/asserts/index.js +70 -0
- package/dist/asserts/index.js.map +1 -0
- package/dist/asserts/query.d.ts +199 -0
- package/dist/asserts/query.d.ts.map +1 -0
- package/dist/asserts/query.js +288 -0
- package/dist/asserts/query.js.map +1 -0
- package/dist/backends/actions.d.ts +119 -0
- package/dist/backends/actions.d.ts.map +1 -0
- package/dist/backends/actions.js +291 -0
- package/dist/backends/actions.js.map +1 -0
- package/dist/backends/browser-use-adapter.d.ts +131 -0
- package/dist/backends/browser-use-adapter.d.ts.map +1 -0
- package/dist/backends/browser-use-adapter.js +219 -0
- package/dist/backends/browser-use-adapter.js.map +1 -0
- package/dist/backends/cdp-backend.d.ts +66 -0
- package/dist/backends/cdp-backend.d.ts.map +1 -0
- package/dist/backends/cdp-backend.js +273 -0
- package/dist/backends/cdp-backend.js.map +1 -0
- package/dist/backends/index.d.ts +80 -0
- package/dist/backends/index.d.ts.map +1 -0
- package/dist/backends/index.js +101 -0
- package/dist/backends/index.js.map +1 -0
- package/dist/backends/protocol.d.ts +156 -0
- package/dist/backends/protocol.d.ts.map +1 -0
- package/dist/backends/protocol.js +16 -0
- package/dist/backends/protocol.js.map +1 -0
- package/dist/backends/sentience-context.d.ts +143 -0
- package/dist/backends/sentience-context.d.ts.map +1 -0
- package/dist/backends/sentience-context.js +359 -0
- package/dist/backends/sentience-context.js.map +1 -0
- package/dist/backends/snapshot.d.ts +188 -0
- package/dist/backends/snapshot.d.ts.map +1 -0
- package/dist/backends/snapshot.js +360 -0
- package/dist/backends/snapshot.js.map +1 -0
- package/dist/browser.d.ts +154 -0
- package/dist/browser.d.ts.map +1 -0
- package/dist/browser.js +920 -0
- package/dist/browser.js.map +1 -0
- package/dist/canonicalization.d.ts +126 -0
- package/dist/canonicalization.d.ts.map +1 -0
- package/dist/canonicalization.js +161 -0
- package/dist/canonicalization.js.map +1 -0
- package/dist/captcha/strategies.d.ts +12 -0
- package/dist/captcha/strategies.d.ts.map +1 -0
- package/dist/captcha/strategies.js +43 -0
- package/dist/captcha/strategies.js.map +1 -0
- package/dist/captcha/types.d.ts +45 -0
- package/dist/captcha/types.d.ts.map +1 -0
- package/dist/captcha/types.js +12 -0
- package/dist/captcha/types.js.map +1 -0
- package/dist/cli.d.ts +5 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +422 -0
- package/dist/cli.js.map +1 -0
- package/dist/conversational-agent.d.ts +123 -0
- package/dist/conversational-agent.d.ts.map +1 -0
- package/dist/conversational-agent.js +341 -0
- package/dist/conversational-agent.js.map +1 -0
- package/dist/cursor-policy.d.ts +41 -0
- package/dist/cursor-policy.d.ts.map +1 -0
- package/dist/cursor-policy.js +81 -0
- package/dist/cursor-policy.js.map +1 -0
- package/dist/debugger.d.ts +28 -0
- package/dist/debugger.d.ts.map +1 -0
- package/dist/debugger.js +107 -0
- package/dist/debugger.js.map +1 -0
- package/dist/expect.d.ts +16 -0
- package/dist/expect.d.ts.map +1 -0
- package/dist/expect.js +67 -0
- package/dist/expect.js.map +1 -0
- package/dist/failure-artifacts.d.ts +95 -0
- package/dist/failure-artifacts.d.ts.map +1 -0
- package/dist/failure-artifacts.js +805 -0
- package/dist/failure-artifacts.js.map +1 -0
- package/dist/generator.d.ts +16 -0
- package/dist/generator.d.ts.map +1 -0
- package/dist/generator.js +205 -0
- package/dist/generator.js.map +1 -0
- package/dist/index.d.ts +37 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +160 -0
- package/dist/index.js.map +1 -0
- package/dist/inspector.d.ts +13 -0
- package/dist/inspector.d.ts.map +1 -0
- package/dist/inspector.js +153 -0
- package/dist/inspector.js.map +1 -0
- package/dist/llm-provider.d.ts +144 -0
- package/dist/llm-provider.d.ts.map +1 -0
- package/dist/llm-provider.js +460 -0
- package/dist/llm-provider.js.map +1 -0
- package/dist/ordinal.d.ts +90 -0
- package/dist/ordinal.d.ts.map +1 -0
- package/dist/ordinal.js +249 -0
- package/dist/ordinal.js.map +1 -0
- package/dist/overlay.d.ts +63 -0
- package/dist/overlay.d.ts.map +1 -0
- package/dist/overlay.js +102 -0
- package/dist/overlay.js.map +1 -0
- package/dist/protocols/browser-protocol.d.ts +79 -0
- package/dist/protocols/browser-protocol.d.ts.map +1 -0
- package/dist/protocols/browser-protocol.js +9 -0
- package/dist/protocols/browser-protocol.js.map +1 -0
- package/dist/query.d.ts +66 -0
- package/dist/query.d.ts.map +1 -0
- package/dist/query.js +482 -0
- package/dist/query.js.map +1 -0
- package/dist/read.d.ts +47 -0
- package/dist/read.d.ts.map +1 -0
- package/dist/read.js +128 -0
- package/dist/read.js.map +1 -0
- package/dist/recorder.d.ts +44 -0
- package/dist/recorder.d.ts.map +1 -0
- package/dist/recorder.js +262 -0
- package/dist/recorder.js.map +1 -0
- package/dist/runtime-agent.d.ts +72 -0
- package/dist/runtime-agent.d.ts.map +1 -0
- package/dist/runtime-agent.js +357 -0
- package/dist/runtime-agent.js.map +1 -0
- package/dist/screenshot.d.ts +17 -0
- package/dist/screenshot.d.ts.map +1 -0
- package/dist/screenshot.js +40 -0
- package/dist/screenshot.js.map +1 -0
- package/dist/snapshot-diff.d.ts +23 -0
- package/dist/snapshot-diff.d.ts.map +1 -0
- package/dist/snapshot-diff.js +119 -0
- package/dist/snapshot-diff.js.map +1 -0
- package/dist/snapshot.d.ts +47 -0
- package/dist/snapshot.d.ts.map +1 -0
- package/dist/snapshot.js +358 -0
- package/dist/snapshot.js.map +1 -0
- package/dist/textSearch.d.ts +64 -0
- package/dist/textSearch.d.ts.map +1 -0
- package/dist/textSearch.js +113 -0
- package/dist/textSearch.js.map +1 -0
- package/dist/tools/context.d.ts +18 -0
- package/dist/tools/context.d.ts.map +1 -0
- package/dist/tools/context.js +40 -0
- package/dist/tools/context.js.map +1 -0
- package/dist/tools/defaults.d.ts +5 -0
- package/dist/tools/defaults.d.ts.map +1 -0
- package/dist/tools/defaults.js +368 -0
- package/dist/tools/defaults.js.map +1 -0
- package/dist/tools/filesystem.d.ts +12 -0
- package/dist/tools/filesystem.d.ts.map +1 -0
- package/dist/tools/filesystem.js +137 -0
- package/dist/tools/filesystem.js.map +1 -0
- package/dist/tools/index.d.ts +5 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +15 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/registry.d.ts +38 -0
- package/dist/tools/registry.d.ts.map +1 -0
- package/dist/tools/registry.js +100 -0
- package/dist/tools/registry.js.map +1 -0
- package/dist/tracing/cloud-sink.d.ts +189 -0
- package/dist/tracing/cloud-sink.d.ts.map +1 -0
- package/dist/tracing/cloud-sink.js +1067 -0
- package/dist/tracing/cloud-sink.js.map +1 -0
- package/dist/tracing/index-schema.d.ts +231 -0
- package/dist/tracing/index-schema.d.ts.map +1 -0
- package/dist/tracing/index-schema.js +235 -0
- package/dist/tracing/index-schema.js.map +1 -0
- package/dist/tracing/index.d.ts +12 -0
- package/dist/tracing/index.d.ts.map +1 -0
- package/dist/tracing/index.js +28 -0
- package/dist/tracing/index.js.map +1 -0
- package/dist/tracing/indexer.d.ts +20 -0
- package/dist/tracing/indexer.d.ts.map +1 -0
- package/dist/tracing/indexer.js +347 -0
- package/dist/tracing/indexer.js.map +1 -0
- package/dist/tracing/jsonl-sink.d.ts +51 -0
- package/dist/tracing/jsonl-sink.d.ts.map +1 -0
- package/dist/tracing/jsonl-sink.js +329 -0
- package/dist/tracing/jsonl-sink.js.map +1 -0
- package/dist/tracing/sink.d.ts +25 -0
- package/dist/tracing/sink.d.ts.map +1 -0
- package/dist/tracing/sink.js +15 -0
- package/dist/tracing/sink.js.map +1 -0
- package/dist/tracing/tracer-factory.d.ts +102 -0
- package/dist/tracing/tracer-factory.d.ts.map +1 -0
- package/dist/tracing/tracer-factory.js +375 -0
- package/dist/tracing/tracer-factory.js.map +1 -0
- package/dist/tracing/tracer.d.ts +140 -0
- package/dist/tracing/tracer.d.ts.map +1 -0
- package/dist/tracing/tracer.js +336 -0
- package/dist/tracing/tracer.js.map +1 -0
- package/dist/tracing/types.d.ts +203 -0
- package/dist/tracing/types.d.ts.map +1 -0
- package/dist/tracing/types.js +8 -0
- package/dist/tracing/types.js.map +1 -0
- package/dist/types.d.ts +422 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/action-executor.d.ts +25 -0
- package/dist/utils/action-executor.d.ts.map +1 -0
- package/dist/utils/action-executor.js +121 -0
- package/dist/utils/action-executor.js.map +1 -0
- package/dist/utils/browser-evaluator.d.ts +76 -0
- package/dist/utils/browser-evaluator.d.ts.map +1 -0
- package/dist/utils/browser-evaluator.js +130 -0
- package/dist/utils/browser-evaluator.js.map +1 -0
- package/dist/utils/browser.d.ts +30 -0
- package/dist/utils/browser.d.ts.map +1 -0
- package/dist/utils/browser.js +75 -0
- package/dist/utils/browser.js.map +1 -0
- package/dist/utils/element-filter.d.ts +76 -0
- package/dist/utils/element-filter.d.ts.map +1 -0
- package/dist/utils/element-filter.js +195 -0
- package/dist/utils/element-filter.js.map +1 -0
- package/dist/utils/grid-utils.d.ts +37 -0
- package/dist/utils/grid-utils.d.ts.map +1 -0
- package/dist/utils/grid-utils.js +283 -0
- package/dist/utils/grid-utils.js.map +1 -0
- package/dist/utils/llm-interaction-handler.d.ts +41 -0
- package/dist/utils/llm-interaction-handler.d.ts.map +1 -0
- package/dist/utils/llm-interaction-handler.js +171 -0
- package/dist/utils/llm-interaction-handler.js.map +1 -0
- package/dist/utils/llm-response-builder.d.ts +56 -0
- package/dist/utils/llm-response-builder.d.ts.map +1 -0
- package/dist/utils/llm-response-builder.js +130 -0
- package/dist/utils/llm-response-builder.js.map +1 -0
- package/dist/utils/selector-utils.d.ts +12 -0
- package/dist/utils/selector-utils.d.ts.map +1 -0
- package/dist/utils/selector-utils.js +32 -0
- package/dist/utils/selector-utils.js.map +1 -0
- package/dist/utils/snapshot-event-builder.d.ts +28 -0
- package/dist/utils/snapshot-event-builder.d.ts.map +1 -0
- package/dist/utils/snapshot-event-builder.js +88 -0
- package/dist/utils/snapshot-event-builder.js.map +1 -0
- package/dist/utils/snapshot-processor.d.ts +27 -0
- package/dist/utils/snapshot-processor.d.ts.map +1 -0
- package/dist/utils/snapshot-processor.js +47 -0
- package/dist/utils/snapshot-processor.js.map +1 -0
- package/dist/utils/trace-event-builder.d.ts +122 -0
- package/dist/utils/trace-event-builder.d.ts.map +1 -0
- package/dist/utils/trace-event-builder.js +365 -0
- package/dist/utils/trace-event-builder.js.map +1 -0
- package/dist/utils/trace-file-manager.d.ts +70 -0
- package/dist/utils/trace-file-manager.d.ts.map +1 -0
- package/dist/utils/trace-file-manager.js +194 -0
- package/dist/utils/trace-file-manager.js.map +1 -0
- package/dist/utils/zod.d.ts +5 -0
- package/dist/utils/zod.d.ts.map +1 -0
- package/dist/utils/zod.js +80 -0
- package/dist/utils/zod.js.map +1 -0
- package/dist/utils.d.ts +8 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +13 -0
- package/dist/utils.js.map +1 -0
- package/dist/verification.d.ts +194 -0
- package/dist/verification.d.ts.map +1 -0
- package/dist/verification.js +530 -0
- package/dist/verification.js.map +1 -0
- package/dist/vision-executor.d.ts +18 -0
- package/dist/vision-executor.d.ts.map +1 -0
- package/dist/vision-executor.js +60 -0
- package/dist/vision-executor.js.map +1 -0
- package/dist/visual-agent.d.ts +120 -0
- package/dist/visual-agent.d.ts.map +1 -0
- package/dist/visual-agent.js +796 -0
- package/dist/visual-agent.js.map +1 -0
- package/dist/wait.d.ts +35 -0
- package/dist/wait.d.ts.map +1 -0
- package/dist/wait.js +76 -0
- package/dist/wait.js.map +1 -0
- package/package.json +94 -0
- package/spec/README.md +72 -0
- package/spec/SNAPSHOT_V1.md +208 -0
- package/spec/sdk-types.md +259 -0
- package/spec/snapshot.schema.json +148 -0
- package/src/extension/background.js +104 -0
- package/src/extension/content.js +162 -0
- package/src/extension/injected_api.js +1399 -0
- package/src/extension/manifest.json +36 -0
- package/src/extension/pkg/README.md +1340 -0
- package/src/extension/pkg/package.json +15 -0
- package/src/extension/pkg/sentience_core.d.ts +51 -0
- package/src/extension/pkg/sentience_core.js +371 -0
- package/src/extension/pkg/sentience_core_bg.wasm +0 -0
- package/src/extension/pkg/sentience_core_bg.wasm.d.ts +10 -0
- package/src/extension/release.json +116 -0
|
@@ -0,0 +1,1399 @@
|
|
|
1
|
+
!function() {
|
|
2
|
+
"use strict";
|
|
3
|
+
function getAllElements(root = document) {
|
|
4
|
+
const elements = [], filter = {
|
|
5
|
+
acceptNode: node => [ "SCRIPT", "STYLE", "NOSCRIPT", "META", "LINK", "HEAD" ].includes(node.tagName) || node.parentNode && "SVG" === node.parentNode.tagName && "SVG" !== node.tagName ? NodeFilter.FILTER_REJECT : NodeFilter.FILTER_ACCEPT
|
|
6
|
+
}, walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT, filter);
|
|
7
|
+
for (;walker.nextNode(); ) {
|
|
8
|
+
const node = walker.currentNode;
|
|
9
|
+
node.isConnected && (elements.push(node), node.shadowRoot && elements.push(...getAllElements(node.shadowRoot)));
|
|
10
|
+
}
|
|
11
|
+
return elements;
|
|
12
|
+
}
|
|
13
|
+
const CAPTCHA_TEXT_KEYWORDS = [ "verify you are human", "captcha", "human verification", "unusual traffic", "are you a robot", "security check", "prove you are human", "bot detection", "automated access" ], CAPTCHA_URL_HINTS = [ "captcha", "challenge", "verify" ], CAPTCHA_IFRAME_HINTS = {
|
|
14
|
+
recaptcha: [ "recaptcha", "google.com/recaptcha" ],
|
|
15
|
+
hcaptcha: [ "hcaptcha.com" ],
|
|
16
|
+
turnstile: [ "challenges.cloudflare.com", "turnstile" ],
|
|
17
|
+
arkose: [ "arkoselabs.com", "funcaptcha.com", "client-api.arkoselabs.com" ],
|
|
18
|
+
awswaf: [ "amazonaws.com/captcha", "awswaf.com" ]
|
|
19
|
+
}, CAPTCHA_SCRIPT_HINTS = {
|
|
20
|
+
recaptcha: [ "recaptcha" ],
|
|
21
|
+
hcaptcha: [ "hcaptcha" ],
|
|
22
|
+
turnstile: [ "turnstile", "challenges.cloudflare.com" ],
|
|
23
|
+
arkose: [ "arkoselabs", "funcaptcha" ],
|
|
24
|
+
awswaf: [ "captcha.awswaf", "awswaf-captcha" ]
|
|
25
|
+
}, CAPTCHA_CONTAINER_SELECTORS = [ {
|
|
26
|
+
selector: ".g-recaptcha",
|
|
27
|
+
provider: "recaptcha"
|
|
28
|
+
}, {
|
|
29
|
+
selector: "#g-recaptcha",
|
|
30
|
+
provider: "recaptcha"
|
|
31
|
+
}, {
|
|
32
|
+
selector: ".recaptcha-checkbox-border",
|
|
33
|
+
provider: "recaptcha"
|
|
34
|
+
}, {
|
|
35
|
+
selector: "#recaptcha-anchor-label",
|
|
36
|
+
provider: "recaptcha"
|
|
37
|
+
}, {
|
|
38
|
+
selector: '[class*="recaptcha" i]',
|
|
39
|
+
provider: "recaptcha"
|
|
40
|
+
}, {
|
|
41
|
+
selector: '[id*="recaptcha" i]',
|
|
42
|
+
provider: "recaptcha"
|
|
43
|
+
}, {
|
|
44
|
+
selector: "[data-sitekey]",
|
|
45
|
+
provider: "unknown"
|
|
46
|
+
}, {
|
|
47
|
+
selector: 'iframe[title*="recaptcha" i]',
|
|
48
|
+
provider: "recaptcha"
|
|
49
|
+
}, {
|
|
50
|
+
selector: ".h-captcha",
|
|
51
|
+
provider: "hcaptcha"
|
|
52
|
+
}, {
|
|
53
|
+
selector: "#h-captcha",
|
|
54
|
+
provider: "hcaptcha"
|
|
55
|
+
}, {
|
|
56
|
+
selector: 'iframe[title*="hcaptcha" i]',
|
|
57
|
+
provider: "hcaptcha"
|
|
58
|
+
}, {
|
|
59
|
+
selector: ".cf-turnstile",
|
|
60
|
+
provider: "turnstile"
|
|
61
|
+
}, {
|
|
62
|
+
selector: "[data-cf-turnstile-sitekey]",
|
|
63
|
+
provider: "turnstile"
|
|
64
|
+
}, {
|
|
65
|
+
selector: 'iframe[src*="challenges.cloudflare.com"]',
|
|
66
|
+
provider: "turnstile"
|
|
67
|
+
}, {
|
|
68
|
+
selector: "#FunCaptcha",
|
|
69
|
+
provider: "arkose"
|
|
70
|
+
}, {
|
|
71
|
+
selector: ".funcaptcha",
|
|
72
|
+
provider: "arkose"
|
|
73
|
+
}, {
|
|
74
|
+
selector: "[data-arkose-public-key]",
|
|
75
|
+
provider: "arkose"
|
|
76
|
+
}, {
|
|
77
|
+
selector: 'iframe[src*="arkoselabs"]',
|
|
78
|
+
provider: "arkose"
|
|
79
|
+
}, {
|
|
80
|
+
selector: "#captcha-container",
|
|
81
|
+
provider: "awswaf"
|
|
82
|
+
}, {
|
|
83
|
+
selector: "[data-awswaf-captcha]",
|
|
84
|
+
provider: "awswaf"
|
|
85
|
+
}, {
|
|
86
|
+
selector: 'iframe[title*="captcha" i]',
|
|
87
|
+
provider: "unknown"
|
|
88
|
+
}, {
|
|
89
|
+
selector: '[class*="captcha" i]',
|
|
90
|
+
provider: "unknown"
|
|
91
|
+
}, {
|
|
92
|
+
selector: '[id*="captcha" i]',
|
|
93
|
+
provider: "unknown"
|
|
94
|
+
} ];
|
|
95
|
+
function addEvidence(list, value) {
|
|
96
|
+
value && (list.length >= 5 || list.push(value));
|
|
97
|
+
}
|
|
98
|
+
function truncateText(text, maxLen) {
|
|
99
|
+
return text ? text.length <= maxLen ? text : text.slice(0, maxLen) : "";
|
|
100
|
+
}
|
|
101
|
+
function matchHints(value, hints) {
|
|
102
|
+
const lower = String(value || "").toLowerCase();
|
|
103
|
+
return !!lower && hints.some(hint => lower.includes(hint));
|
|
104
|
+
}
|
|
105
|
+
function detectCaptcha() {
|
|
106
|
+
function isVisibleElement(el) {
|
|
107
|
+
try {
|
|
108
|
+
if (!el) return !1;
|
|
109
|
+
const style = window.getComputedStyle(el);
|
|
110
|
+
if ("none" === style.display || "hidden" === style.visibility) return !1;
|
|
111
|
+
const opacity = parseFloat(style.opacity || "1");
|
|
112
|
+
if (!Number.isNaN(opacity) && opacity <= .01) return !1;
|
|
113
|
+
if (!el.getClientRects || 0 === el.getClientRects().length) return !1;
|
|
114
|
+
const rect = el.getBoundingClientRect();
|
|
115
|
+
if (rect.width < 8 || rect.height < 8) return !1;
|
|
116
|
+
const vw = window.innerWidth || document.documentElement.clientWidth || 0, vh = window.innerHeight || document.documentElement.clientHeight || 0;
|
|
117
|
+
return !(vw && vh && (rect.bottom <= 0 || rect.right <= 0 || rect.top >= vh || rect.left >= vw));
|
|
118
|
+
} catch (e) {
|
|
119
|
+
return !1;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
const evidence = {
|
|
123
|
+
text_hits: [],
|
|
124
|
+
selector_hits: [],
|
|
125
|
+
iframe_src_hits: [],
|
|
126
|
+
url_hits: []
|
|
127
|
+
};
|
|
128
|
+
let hasIframeHit = !1, hasContainerHit = !1, hasScriptHit = !1, hasKeywordHit = !1, hasUrlHit = !1;
|
|
129
|
+
const providerSignals = {
|
|
130
|
+
recaptcha: 0,
|
|
131
|
+
hcaptcha: 0,
|
|
132
|
+
turnstile: 0,
|
|
133
|
+
arkose: 0,
|
|
134
|
+
awswaf: 0
|
|
135
|
+
};
|
|
136
|
+
try {
|
|
137
|
+
const iframes = document.querySelectorAll("iframe");
|
|
138
|
+
for (const iframe of iframes) {
|
|
139
|
+
const src = iframe.getAttribute("src") || "", title = iframe.getAttribute("title") || "";
|
|
140
|
+
if (src) for (const [provider, hints] of Object.entries(CAPTCHA_IFRAME_HINTS)) matchHints(src, hints) && (addEvidence(evidence.iframe_src_hits, truncateText(src, 120)),
|
|
141
|
+
isVisibleElement(iframe) && (hasIframeHit = !0, providerSignals[provider] += 1));
|
|
142
|
+
if (title && matchHints(title, [ "captcha", "recaptcha" ]) && (addEvidence(evidence.selector_hits, 'iframe[title*="captcha"]'),
|
|
143
|
+
isVisibleElement(iframe) && (hasContainerHit = !0)), evidence.iframe_src_hits.length >= 5) break;
|
|
144
|
+
}
|
|
145
|
+
} catch (e) {}
|
|
146
|
+
try {
|
|
147
|
+
const scripts = document.querySelectorAll("script[src]");
|
|
148
|
+
for (const script of scripts) {
|
|
149
|
+
const src = script.getAttribute("src") || "";
|
|
150
|
+
if (src) {
|
|
151
|
+
for (const [provider, hints] of Object.entries(CAPTCHA_SCRIPT_HINTS)) matchHints(src, hints) && (hasScriptHit = !0,
|
|
152
|
+
providerSignals[provider] += 1, addEvidence(evidence.selector_hits, `script[src*="${hints[0]}"]`));
|
|
153
|
+
if (evidence.selector_hits.length >= 5) break;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
} catch (e) {}
|
|
157
|
+
for (const {selector: selector, provider: provider} of CAPTCHA_CONTAINER_SELECTORS) try {
|
|
158
|
+
const hit = document.querySelector(selector);
|
|
159
|
+
hit && (addEvidence(evidence.selector_hits, selector), isVisibleElement(hit) && (hasContainerHit = !0,
|
|
160
|
+
"unknown" !== provider && (providerSignals[provider] += 1)));
|
|
161
|
+
} catch (e) {}
|
|
162
|
+
const textSnippet = function() {
|
|
163
|
+
try {
|
|
164
|
+
const candidates = document.querySelectorAll("h1, h2, h3, h4, p, label, button, form, div, span");
|
|
165
|
+
let combined = "", count = 0;
|
|
166
|
+
for (const node of candidates) {
|
|
167
|
+
if (count >= 30 || combined.length >= 2e3) break;
|
|
168
|
+
if (!node || "string" != typeof node.innerText) continue;
|
|
169
|
+
if (!node.offsetWidth && !node.offsetHeight && !node.getClientRects().length) continue;
|
|
170
|
+
const text = node.innerText.replace(/\s+/g, " ").trim();
|
|
171
|
+
text && (combined += `${text} `, count += 1);
|
|
172
|
+
}
|
|
173
|
+
if (combined = combined.trim(), combined) return truncateText(combined, 2e3);
|
|
174
|
+
} catch (e) {}
|
|
175
|
+
try {
|
|
176
|
+
let bodyText = document.body?.innerText || "";
|
|
177
|
+
return !bodyText && document.body?.textContent && (bodyText = document.body.textContent),
|
|
178
|
+
truncateText(bodyText.replace(/\s+/g, " ").trim(), 2e3);
|
|
179
|
+
} catch (e) {
|
|
180
|
+
return "";
|
|
181
|
+
}
|
|
182
|
+
}();
|
|
183
|
+
if (textSnippet) {
|
|
184
|
+
const lowerText = textSnippet.toLowerCase();
|
|
185
|
+
for (const keyword of CAPTCHA_TEXT_KEYWORDS) lowerText.includes(keyword) && (hasKeywordHit = !0,
|
|
186
|
+
addEvidence(evidence.text_hits, keyword));
|
|
187
|
+
}
|
|
188
|
+
try {
|
|
189
|
+
const lowerUrl = (window.location?.href || "").toLowerCase();
|
|
190
|
+
for (const hint of CAPTCHA_URL_HINTS) lowerUrl.includes(hint) && (hasUrlHit = !0,
|
|
191
|
+
addEvidence(evidence.url_hits, hint));
|
|
192
|
+
} catch (e) {}
|
|
193
|
+
let confidence = 0;
|
|
194
|
+
hasIframeHit && (confidence += .7), hasContainerHit && (confidence += .5), hasScriptHit && (confidence += .5),
|
|
195
|
+
hasKeywordHit && (confidence += .3), hasUrlHit && (confidence += .2), confidence = Math.min(1, confidence),
|
|
196
|
+
hasIframeHit && (confidence = Math.max(confidence, .8)), !hasKeywordHit || hasIframeHit || hasContainerHit || hasScriptHit || hasUrlHit || (confidence = Math.min(confidence, .4));
|
|
197
|
+
const detected = confidence >= .7;
|
|
198
|
+
let providerHint = null;
|
|
199
|
+
return providerSignals.recaptcha > 0 ? providerHint = "recaptcha" : providerSignals.hcaptcha > 0 ? providerHint = "hcaptcha" : providerSignals.turnstile > 0 ? providerHint = "turnstile" : providerSignals.arkose > 0 ? providerHint = "arkose" : providerSignals.awswaf > 0 ? providerHint = "awswaf" : detected && (providerHint = "unknown"),
|
|
200
|
+
{
|
|
201
|
+
detected: detected,
|
|
202
|
+
provider_hint: providerHint,
|
|
203
|
+
confidence: confidence,
|
|
204
|
+
evidence: evidence
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
const DEFAULT_INFERENCE_CONFIG = {
|
|
208
|
+
allowedTags: [ "label", "span", "div" ],
|
|
209
|
+
allowedRoles: [],
|
|
210
|
+
allowedClassPatterns: [],
|
|
211
|
+
maxParentDepth: 2,
|
|
212
|
+
maxSiblingDistance: 1,
|
|
213
|
+
requireSameContainer: !0,
|
|
214
|
+
containerTags: [ "form", "fieldset", "div" ],
|
|
215
|
+
methods: {
|
|
216
|
+
explicitLabel: !0,
|
|
217
|
+
ariaLabelledby: !0,
|
|
218
|
+
parentTraversal: !0,
|
|
219
|
+
siblingProximity: !0
|
|
220
|
+
}
|
|
221
|
+
};
|
|
222
|
+
function isInferenceSource(el, config) {
|
|
223
|
+
if (!el || !el.tagName) return !1;
|
|
224
|
+
const tag = el.tagName.toLowerCase(), role = el.getAttribute ? el.getAttribute("role") : "", className = ((el.className || "") + "").toLowerCase();
|
|
225
|
+
if (config.allowedTags.includes(tag)) return !0;
|
|
226
|
+
if (config.allowedRoles.length > 0 && role && config.allowedRoles.includes(role)) return !0;
|
|
227
|
+
if (config.allowedClassPatterns.length > 0) for (const pattern of config.allowedClassPatterns) if (className.includes(pattern.toLowerCase())) return !0;
|
|
228
|
+
return !1;
|
|
229
|
+
}
|
|
230
|
+
function isInSameValidContainer(element, candidate, limits) {
|
|
231
|
+
if (!element || !candidate) return !1;
|
|
232
|
+
if (limits.requireSameContainer) {
|
|
233
|
+
const commonParent = function(el1, el2) {
|
|
234
|
+
if (!el1 || !el2) return null;
|
|
235
|
+
const doc = "undefined" != typeof global && global.document || "undefined" != typeof window && window.document || "undefined" != typeof document && document || null, parents1 = [];
|
|
236
|
+
let current = el1;
|
|
237
|
+
for (;current && (parents1.push(current), current.parentElement) && (!doc || current !== doc.body && current !== doc.documentElement); ) current = current.parentElement;
|
|
238
|
+
for (current = el2; current; ) {
|
|
239
|
+
if (-1 !== parents1.indexOf(current)) return current;
|
|
240
|
+
if (!current.parentElement) break;
|
|
241
|
+
if (doc && (current === doc.body || current === doc.documentElement)) break;
|
|
242
|
+
current = current.parentElement;
|
|
243
|
+
}
|
|
244
|
+
return null;
|
|
245
|
+
}(element, candidate);
|
|
246
|
+
if (!commonParent) return !1;
|
|
247
|
+
if (!function(el, validTags) {
|
|
248
|
+
if (!el || !el.tagName) return !1;
|
|
249
|
+
const tag = el.tagName.toLowerCase();
|
|
250
|
+
let className = "";
|
|
251
|
+
try {
|
|
252
|
+
className = (el.className || "") + "";
|
|
253
|
+
} catch (e) {
|
|
254
|
+
className = "";
|
|
255
|
+
}
|
|
256
|
+
return validTags.includes(tag) || className.toLowerCase().includes("form") || className.toLowerCase().includes("field");
|
|
257
|
+
}(commonParent, limits.containerTags)) return !1;
|
|
258
|
+
}
|
|
259
|
+
return !0;
|
|
260
|
+
}
|
|
261
|
+
function getInferredLabel(el, options = {}) {
|
|
262
|
+
if (!el) return null;
|
|
263
|
+
const {enableInference: enableInference = !0, inferenceConfig: inferenceConfig = {}} = options;
|
|
264
|
+
if (!enableInference) return null;
|
|
265
|
+
const ariaLabel = el.getAttribute ? el.getAttribute("aria-label") : null, hasAriaLabel = ariaLabel && ariaLabel.trim(), hasInputValue = "INPUT" === el.tagName && (el.value || el.placeholder), hasImgAlt = "IMG" === el.tagName && el.alt;
|
|
266
|
+
let innerTextValue = "";
|
|
267
|
+
try {
|
|
268
|
+
innerTextValue = el.innerText || "";
|
|
269
|
+
} catch (e) {
|
|
270
|
+
innerTextValue = "";
|
|
271
|
+
}
|
|
272
|
+
const hasInnerText = "INPUT" !== el.tagName && "IMG" !== el.tagName && innerTextValue && innerTextValue.trim();
|
|
273
|
+
if (hasAriaLabel || hasInputValue || hasImgAlt || hasInnerText) return null;
|
|
274
|
+
const config = function(userConfig = {}) {
|
|
275
|
+
return {
|
|
276
|
+
...DEFAULT_INFERENCE_CONFIG,
|
|
277
|
+
...userConfig,
|
|
278
|
+
methods: {
|
|
279
|
+
...DEFAULT_INFERENCE_CONFIG.methods,
|
|
280
|
+
...userConfig.methods || {}
|
|
281
|
+
}
|
|
282
|
+
};
|
|
283
|
+
}(inferenceConfig);
|
|
284
|
+
if (config.methods.explicitLabel && el.labels && el.labels.length > 0) {
|
|
285
|
+
const label = el.labels[0];
|
|
286
|
+
if (isInferenceSource(label, config)) {
|
|
287
|
+
const text = (label.innerText || "").trim();
|
|
288
|
+
if (text) return {
|
|
289
|
+
text: text,
|
|
290
|
+
source: "explicit_label"
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
if (config.methods.ariaLabelledby && el.hasAttribute && el.hasAttribute("aria-labelledby")) {
|
|
295
|
+
const labelIdsAttr = el.getAttribute("aria-labelledby");
|
|
296
|
+
if (labelIdsAttr) {
|
|
297
|
+
const labelIds = labelIdsAttr.split(/\s+/).filter(id => id.trim()), labelTexts = [], doc = (() => "undefined" != typeof global && global.document ? global.document : "undefined" != typeof window && window.document ? window.document : "undefined" != typeof document ? document : null)();
|
|
298
|
+
if (doc && doc.getElementById) for (const labelId of labelIds) {
|
|
299
|
+
if (!labelId.trim()) continue;
|
|
300
|
+
let labelEl = null;
|
|
301
|
+
try {
|
|
302
|
+
labelEl = doc.getElementById(labelId);
|
|
303
|
+
} catch (e) {
|
|
304
|
+
continue;
|
|
305
|
+
}
|
|
306
|
+
if (labelEl) {
|
|
307
|
+
let text = "";
|
|
308
|
+
try {
|
|
309
|
+
if (text = (labelEl.innerText || "").trim(), !text && labelEl.textContent && (text = labelEl.textContent.trim()),
|
|
310
|
+
!text && labelEl.getAttribute) {
|
|
311
|
+
const ariaLabel = labelEl.getAttribute("aria-label");
|
|
312
|
+
ariaLabel && (text = ariaLabel.trim());
|
|
313
|
+
}
|
|
314
|
+
} catch (e) {
|
|
315
|
+
continue;
|
|
316
|
+
}
|
|
317
|
+
text && labelTexts.push(text);
|
|
318
|
+
}
|
|
319
|
+
} else ;
|
|
320
|
+
if (labelTexts.length > 0) return {
|
|
321
|
+
text: labelTexts.join(" "),
|
|
322
|
+
source: "aria_labelledby"
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
if (config.methods.parentTraversal) {
|
|
327
|
+
let parent = el.parentElement, depth = 0;
|
|
328
|
+
for (;parent && depth < config.maxParentDepth; ) {
|
|
329
|
+
if (isInferenceSource(parent, config)) {
|
|
330
|
+
const text = (parent.innerText || "").trim();
|
|
331
|
+
if (text) return {
|
|
332
|
+
text: text,
|
|
333
|
+
source: "parent_label"
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
parent = parent.parentElement, depth++;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
if (config.methods.siblingProximity) {
|
|
340
|
+
const prev = el.previousElementSibling;
|
|
341
|
+
if (prev && isInferenceSource(prev, config) && isInSameValidContainer(el, prev, {
|
|
342
|
+
requireSameContainer: config.requireSameContainer,
|
|
343
|
+
containerTags: config.containerTags
|
|
344
|
+
})) {
|
|
345
|
+
const text = (prev.innerText || "").trim();
|
|
346
|
+
if (text) return {
|
|
347
|
+
text: text,
|
|
348
|
+
source: "sibling_label"
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
return null;
|
|
353
|
+
}
|
|
354
|
+
function normalizeNearbyText(text) {
|
|
355
|
+
return text ? text.replace(/\s+/g, " ").trim() : "";
|
|
356
|
+
}
|
|
357
|
+
function isInteractableElement(el) {
|
|
358
|
+
if (!el || !el.tagName) return !1;
|
|
359
|
+
const tag = el.tagName.toLowerCase(), role = el.getAttribute ? el.getAttribute("role") : null, hasTabIndex = !!el.hasAttribute && el.hasAttribute("tabindex"), hasHref = "A" === el.tagName && !!el.hasAttribute && el.hasAttribute("href");
|
|
360
|
+
if ([ "button", "input", "textarea", "select", "option", "details", "summary", "a" ].includes(tag)) return !("a" === tag && !hasHref);
|
|
361
|
+
if (role && [ "button", "link", "tab", "menuitem", "checkbox", "radio", "switch", "slider", "combobox", "textbox", "searchbox", "spinbutton" ].includes(role.toLowerCase())) return !0;
|
|
362
|
+
if (hasTabIndex) return !0;
|
|
363
|
+
if (el.onclick || el.onkeydown || el.onkeypress || el.onkeyup) return !0;
|
|
364
|
+
if (el.getAttribute) {
|
|
365
|
+
if (el.getAttribute("onclick") || el.getAttribute("onkeydown") || el.getAttribute("onkeypress") || el.getAttribute("onkeyup")) return !0;
|
|
366
|
+
}
|
|
367
|
+
return !1;
|
|
368
|
+
}
|
|
369
|
+
function getText(el) {
|
|
370
|
+
if (el.getAttribute("aria-label")) return el.getAttribute("aria-label");
|
|
371
|
+
if ("INPUT" === el.tagName) {
|
|
372
|
+
const t = el.getAttribute && el.getAttribute("type") || el.type || "";
|
|
373
|
+
return "password" === String(t).toLowerCase() ? el.placeholder || "" : el.value || el.placeholder || "";
|
|
374
|
+
}
|
|
375
|
+
return "IMG" === el.tagName ? el.alt || "" : (el.innerText || "").replace(/\s+/g, " ").trim().substring(0, 100);
|
|
376
|
+
}
|
|
377
|
+
function getClassName(el) {
|
|
378
|
+
if (!el || !el.className) return "";
|
|
379
|
+
if ("string" == typeof el.className) return el.className;
|
|
380
|
+
if ("object" == typeof el.className) {
|
|
381
|
+
if ("baseVal" in el.className && "string" == typeof el.className.baseVal) return el.className.baseVal;
|
|
382
|
+
if ("animVal" in el.className && "string" == typeof el.className.animVal) return el.className.animVal;
|
|
383
|
+
try {
|
|
384
|
+
return String(el.className);
|
|
385
|
+
} catch (e) {
|
|
386
|
+
return "";
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
return "";
|
|
390
|
+
}
|
|
391
|
+
function toSafeString(value) {
|
|
392
|
+
if (null == value) return null;
|
|
393
|
+
if ("string" == typeof value) return value;
|
|
394
|
+
if ("object" == typeof value) {
|
|
395
|
+
if ("baseVal" in value && "string" == typeof value.baseVal) return value.baseVal;
|
|
396
|
+
if ("animVal" in value && "string" == typeof value.animVal) return value.animVal;
|
|
397
|
+
try {
|
|
398
|
+
return String(value);
|
|
399
|
+
} catch (e) {
|
|
400
|
+
return null;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
try {
|
|
404
|
+
return String(value);
|
|
405
|
+
} catch (e) {
|
|
406
|
+
return null;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
function getSVGColor(el) {
|
|
410
|
+
if (!el || "SVG" !== el.tagName) return null;
|
|
411
|
+
const style = window.getComputedStyle(el), fill = style.fill;
|
|
412
|
+
if (fill && "none" !== fill && "transparent" !== fill && "rgba(0, 0, 0, 0)" !== fill) {
|
|
413
|
+
const rgbaMatch = fill.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*([\d.]+))?\)/);
|
|
414
|
+
if (rgbaMatch) {
|
|
415
|
+
if ((rgbaMatch[4] ? parseFloat(rgbaMatch[4]) : 1) >= .9) return `rgb(${rgbaMatch[1]}, ${rgbaMatch[2]}, ${rgbaMatch[3]})`;
|
|
416
|
+
} else if (fill.startsWith("rgb(")) return fill;
|
|
417
|
+
}
|
|
418
|
+
const stroke = style.stroke;
|
|
419
|
+
if (stroke && "none" !== stroke && "transparent" !== stroke && "rgba(0, 0, 0, 0)" !== stroke) {
|
|
420
|
+
const rgbaMatch = stroke.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*([\d.]+))?\)/);
|
|
421
|
+
if (rgbaMatch) {
|
|
422
|
+
if ((rgbaMatch[4] ? parseFloat(rgbaMatch[4]) : 1) >= .9) return `rgb(${rgbaMatch[1]}, ${rgbaMatch[2]}, ${rgbaMatch[3]})`;
|
|
423
|
+
} else if (stroke.startsWith("rgb(")) return stroke;
|
|
424
|
+
}
|
|
425
|
+
return null;
|
|
426
|
+
}
|
|
427
|
+
function getRawHTML(root) {
|
|
428
|
+
const sourceRoot = root || document.body, clone = sourceRoot.cloneNode(!0), unwantedTags = [ "script", "style", "noscript", "iframe", "svg" ], unwantedTagSet = new Set(unwantedTags);
|
|
429
|
+
function getChildIndex(node) {
|
|
430
|
+
let index = 0, sibling = node;
|
|
431
|
+
for (;sibling = sibling.previousElementSibling; ) index++;
|
|
432
|
+
return index;
|
|
433
|
+
}
|
|
434
|
+
function getElementPath(node, root) {
|
|
435
|
+
const path = [];
|
|
436
|
+
let current = node;
|
|
437
|
+
for (;current && current !== root && current.parentElement; ) path.unshift(getChildIndex(current)),
|
|
438
|
+
current = current.parentElement;
|
|
439
|
+
return path;
|
|
440
|
+
}
|
|
441
|
+
const invisiblePaths = [], walker = document.createTreeWalker(sourceRoot, NodeFilter.SHOW_ELEMENT, null, !1);
|
|
442
|
+
let node;
|
|
443
|
+
for (;node = walker.nextNode(); ) {
|
|
444
|
+
const tag = node.tagName.toLowerCase();
|
|
445
|
+
if ("head" === tag || "title" === tag) continue;
|
|
446
|
+
if (unwantedTagSet.has(tag)) continue;
|
|
447
|
+
const style = window.getComputedStyle(node);
|
|
448
|
+
"none" !== style.display && "hidden" !== style.visibility || invisiblePaths.push(getElementPath(node, sourceRoot));
|
|
449
|
+
}
|
|
450
|
+
invisiblePaths.sort((a, b) => {
|
|
451
|
+
if (a.length !== b.length) return b.length - a.length;
|
|
452
|
+
for (let i = a.length - 1; i >= 0; i--) if (a[i] !== b[i]) return b[i] - a[i];
|
|
453
|
+
return 0;
|
|
454
|
+
}), invisiblePaths.forEach(path => {
|
|
455
|
+
const el = function(root, path) {
|
|
456
|
+
let current = root;
|
|
457
|
+
for (const index of path) {
|
|
458
|
+
if (!current || !current.children || index >= current.children.length) return null;
|
|
459
|
+
current = current.children[index];
|
|
460
|
+
}
|
|
461
|
+
return current;
|
|
462
|
+
}(clone, path);
|
|
463
|
+
el && el.parentNode && el.parentNode.removeChild(el);
|
|
464
|
+
}), unwantedTags.forEach(tag => {
|
|
465
|
+
clone.querySelectorAll(tag).forEach(el => {
|
|
466
|
+
el.parentNode && el.parentNode.removeChild(el);
|
|
467
|
+
});
|
|
468
|
+
});
|
|
469
|
+
clone.querySelectorAll("a[href]").forEach(link => {
|
|
470
|
+
const href = link.getAttribute("href");
|
|
471
|
+
if (href && !href.startsWith("http://") && !href.startsWith("https://") && !href.startsWith("#")) try {
|
|
472
|
+
link.setAttribute("href", new URL(href, document.baseURI).href);
|
|
473
|
+
} catch (e) {}
|
|
474
|
+
});
|
|
475
|
+
return clone.querySelectorAll("img[src]").forEach(img => {
|
|
476
|
+
const src = img.getAttribute("src");
|
|
477
|
+
if (src && !src.startsWith("http://") && !src.startsWith("https://") && !src.startsWith("data:")) try {
|
|
478
|
+
img.setAttribute("src", new URL(src, document.baseURI).href);
|
|
479
|
+
} catch (e) {}
|
|
480
|
+
}), clone.innerHTML;
|
|
481
|
+
}
|
|
482
|
+
function cleanElement(obj) {
|
|
483
|
+
if (Array.isArray(obj)) return obj.map(cleanElement);
|
|
484
|
+
if (null !== obj && "object" == typeof obj) {
|
|
485
|
+
const cleaned = {};
|
|
486
|
+
for (const [key, value] of Object.entries(obj)) if (null != value) if ("object" == typeof value) {
|
|
487
|
+
const deepClean = cleanElement(value);
|
|
488
|
+
Object.keys(deepClean).length > 0 && (cleaned[key] = deepClean);
|
|
489
|
+
} else cleaned[key] = value;
|
|
490
|
+
return cleaned;
|
|
491
|
+
}
|
|
492
|
+
return obj;
|
|
493
|
+
}
|
|
494
|
+
async function snapshot(options = {}) {
|
|
495
|
+
try {
|
|
496
|
+
!1 !== options.waitForStability && await async function(options = {}) {
|
|
497
|
+
const {minNodeCount: minNodeCount = 500, quietPeriod: quietPeriod = 200, maxWait: maxWait = 5e3} = options, startTime = Date.now();
|
|
498
|
+
try {
|
|
499
|
+
window.__sentience_lastMutationTs = performance.now();
|
|
500
|
+
} catch (e) {}
|
|
501
|
+
return new Promise(resolve => {
|
|
502
|
+
if (document.querySelectorAll("*").length >= minNodeCount) {
|
|
503
|
+
let lastChange = Date.now();
|
|
504
|
+
const observer = new MutationObserver(() => {
|
|
505
|
+
lastChange = Date.now();
|
|
506
|
+
try {
|
|
507
|
+
window.__sentience_lastMutationTs = performance.now();
|
|
508
|
+
} catch (e) {}
|
|
509
|
+
});
|
|
510
|
+
observer.observe(document.body, {
|
|
511
|
+
childList: !0,
|
|
512
|
+
subtree: !0,
|
|
513
|
+
attributes: !1
|
|
514
|
+
});
|
|
515
|
+
const checkStable = () => {
|
|
516
|
+
const timeSinceLastChange = Date.now() - lastChange, totalWait = Date.now() - startTime;
|
|
517
|
+
timeSinceLastChange >= quietPeriod || totalWait >= maxWait ? (observer.disconnect(),
|
|
518
|
+
resolve()) : setTimeout(checkStable, 50);
|
|
519
|
+
};
|
|
520
|
+
checkStable();
|
|
521
|
+
} else {
|
|
522
|
+
const observer = new MutationObserver(() => {
|
|
523
|
+
const currentCount = document.querySelectorAll("*").length, totalWait = Date.now() - startTime;
|
|
524
|
+
try {
|
|
525
|
+
window.__sentience_lastMutationTs = performance.now();
|
|
526
|
+
} catch (e) {}
|
|
527
|
+
if (currentCount >= minNodeCount) {
|
|
528
|
+
observer.disconnect();
|
|
529
|
+
let lastChange = Date.now();
|
|
530
|
+
const quietObserver = new MutationObserver(() => {
|
|
531
|
+
lastChange = Date.now();
|
|
532
|
+
try {
|
|
533
|
+
window.__sentience_lastMutationTs = performance.now();
|
|
534
|
+
} catch (e) {}
|
|
535
|
+
});
|
|
536
|
+
quietObserver.observe(document.body, {
|
|
537
|
+
childList: !0,
|
|
538
|
+
subtree: !0,
|
|
539
|
+
attributes: !1
|
|
540
|
+
});
|
|
541
|
+
const checkQuiet = () => {
|
|
542
|
+
const timeSinceLastChange = Date.now() - lastChange, totalWait = Date.now() - startTime;
|
|
543
|
+
timeSinceLastChange >= quietPeriod || totalWait >= maxWait ? (quietObserver.disconnect(),
|
|
544
|
+
resolve()) : setTimeout(checkQuiet, 50);
|
|
545
|
+
};
|
|
546
|
+
checkQuiet();
|
|
547
|
+
} else totalWait >= maxWait && (observer.disconnect(), resolve());
|
|
548
|
+
});
|
|
549
|
+
observer.observe(document.body, {
|
|
550
|
+
childList: !0,
|
|
551
|
+
subtree: !0,
|
|
552
|
+
attributes: !1
|
|
553
|
+
}), setTimeout(() => {
|
|
554
|
+
observer.disconnect(), resolve();
|
|
555
|
+
}, maxWait);
|
|
556
|
+
}
|
|
557
|
+
});
|
|
558
|
+
}(options.waitForStability || {});
|
|
559
|
+
const rawData = [];
|
|
560
|
+
window.sentience_registry = [];
|
|
561
|
+
const nodes = getAllElements(), parseAriaInt = (el, attr) => {
|
|
562
|
+
try {
|
|
563
|
+
const raw = el.getAttribute ? el.getAttribute(attr) : null;
|
|
564
|
+
if (!raw) return null;
|
|
565
|
+
const n = parseInt(String(raw), 10);
|
|
566
|
+
return Number.isFinite(n) ? n : null;
|
|
567
|
+
} catch (e) {
|
|
568
|
+
return null;
|
|
569
|
+
}
|
|
570
|
+
}, safeKeyPart = (s, maxLen = 48) => String(s || "").replace(/\s+/g, " ").trim().slice(0, maxLen) || null, buildContainerKey = container => {
|
|
571
|
+
try {
|
|
572
|
+
const tag = container.tagName ? container.tagName.toLowerCase() : "div", role = container.getAttribute ? container.getAttribute("role") : null, id = container.id ? `#${safeKeyPart(container.id, 32)}` : null, cls = (() => {
|
|
573
|
+
if (!container.className) return null;
|
|
574
|
+
const parts = String(container.className).split(/\s+/).filter(Boolean).slice(0, 2);
|
|
575
|
+
return parts.length ? `.${safeKeyPart(parts.join("."), 48)}` : null;
|
|
576
|
+
})(), ariaLabel = container.getAttribute && container.getAttribute("aria-label") ? `aria=${safeKeyPart(container.getAttribute("aria-label"), 40)}` : null, parts = [ safeKeyPart(tag, 16), role ? `role=${safeKeyPart(role, 24)}` : null, id, cls, ariaLabel ].filter(Boolean);
|
|
577
|
+
return parts.length ? parts.join("|") : null;
|
|
578
|
+
} catch (e) {
|
|
579
|
+
return null;
|
|
580
|
+
}
|
|
581
|
+
}, computeContainerInfo = el => {
|
|
582
|
+
try {
|
|
583
|
+
if (!("A" === el.tagName && (el.getAttribute("href") || el.href) || "BUTTON" === el.tagName || el.getAttribute && ("link" === el.getAttribute("role") || "button" === el.getAttribute("role")) || isInteractableElement(el))) return null;
|
|
584
|
+
const candidates = [];
|
|
585
|
+
let node = el;
|
|
586
|
+
for (let depth = 0; depth < 6 && node && node.parentElement; depth++) {
|
|
587
|
+
const p = node.parentElement, tag = p.tagName ? p.tagName.toLowerCase() : "", role = p.getAttribute ? p.getAttribute("role") : null, isExplicit = "ul" === tag || "ol" === tag || "table" === tag || "tbody" === tag || "list" === role || "feed" === role || "grid" === role || "table" === role, childCount = p.children ? p.children.length : 0;
|
|
588
|
+
(isExplicit || childCount >= 6) && candidates.push({
|
|
589
|
+
p: p,
|
|
590
|
+
depth: depth,
|
|
591
|
+
tag: tag,
|
|
592
|
+
role: role,
|
|
593
|
+
childCount: childCount
|
|
594
|
+
}), node = p;
|
|
595
|
+
}
|
|
596
|
+
if (!candidates.length) return null;
|
|
597
|
+
const pickItemNodes = (container, tag, role) => {
|
|
598
|
+
if ("ul" === tag || "ol" === tag || "list" === role) {
|
|
599
|
+
const lis = Array.from(container.children || []).filter(c => c && "LI" === c.tagName), filtered = lis.filter(li => {
|
|
600
|
+
if (!li || !li.querySelector) return !1;
|
|
601
|
+
const a = li.querySelector("a[href]");
|
|
602
|
+
if (!a) return !1;
|
|
603
|
+
return (a.textContent || "").replace(/\s+/g, " ").trim().length >= 8;
|
|
604
|
+
});
|
|
605
|
+
return filtered.length ? filtered : lis;
|
|
606
|
+
}
|
|
607
|
+
if ("table" === tag || "tbody" === tag || "table" === role || "grid" === role) {
|
|
608
|
+
const rows = Array.from(container.children || []).filter(c => c && "TR" === c.tagName), allRows = rows.length ? rows : Array.from(container.querySelectorAll("tr")), filtered = allRows.filter(tr => {
|
|
609
|
+
if (!tr || !tr.querySelector) return !1;
|
|
610
|
+
const links = Array.from(tr.querySelectorAll("a[href]"));
|
|
611
|
+
let bestLen = 0;
|
|
612
|
+
for (const a of links) {
|
|
613
|
+
const t = (a.textContent || "").replace(/\s+/g, " ").trim();
|
|
614
|
+
t.length > bestLen && (bestLen = t.length);
|
|
615
|
+
}
|
|
616
|
+
return bestLen >= 12;
|
|
617
|
+
});
|
|
618
|
+
return filtered.length ? filtered : allRows;
|
|
619
|
+
}
|
|
620
|
+
const kids = Array.from(container.children || []), items = kids.filter(c => {
|
|
621
|
+
if (!c || !c.querySelector) return !1;
|
|
622
|
+
if (!c.querySelector('a[href],button,[role="link"],[role="button"]')) return !1;
|
|
623
|
+
return (c.textContent || "").replace(/\s+/g, " ").trim().length >= 8;
|
|
624
|
+
});
|
|
625
|
+
return items.length ? items : kids;
|
|
626
|
+
};
|
|
627
|
+
let best = null;
|
|
628
|
+
for (const c of candidates) {
|
|
629
|
+
const items = pickItemNodes(c.p, c.tag, c.role), size = items.length || 0;
|
|
630
|
+
if (size < 4) continue;
|
|
631
|
+
let itemIndex = null;
|
|
632
|
+
for (let i = 0; i < items.length; i++) {
|
|
633
|
+
const it = items[i];
|
|
634
|
+
if (it && (it === el || it.contains(el))) {
|
|
635
|
+
itemIndex = i;
|
|
636
|
+
break;
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
if (null === itemIndex) continue;
|
|
640
|
+
const score = size + ("ul" === c.tag || "ol" === c.tag || "table" === c.tag || c.role ? 2 : 0) - .4 * c.depth;
|
|
641
|
+
(!best || score > best.score) && (best = {
|
|
642
|
+
key: buildContainerKey(c.p),
|
|
643
|
+
index: itemIndex,
|
|
644
|
+
size: size,
|
|
645
|
+
score: score
|
|
646
|
+
});
|
|
647
|
+
}
|
|
648
|
+
return best && best.key ? {
|
|
649
|
+
container_key: best.key,
|
|
650
|
+
index_in_container: best.index,
|
|
651
|
+
container_item_count: best.size
|
|
652
|
+
} : null;
|
|
653
|
+
} catch (e) {
|
|
654
|
+
return null;
|
|
655
|
+
}
|
|
656
|
+
};
|
|
657
|
+
nodes.forEach((el, idx) => {
|
|
658
|
+
if (!el.getBoundingClientRect) return;
|
|
659
|
+
const rect = el.getBoundingClientRect();
|
|
660
|
+
if (rect.width < 5 || rect.height < 5) return;
|
|
661
|
+
const tagName = el.tagName.toLowerCase();
|
|
662
|
+
if ("span" === tagName) {
|
|
663
|
+
if (el.closest("a")) return;
|
|
664
|
+
const childLink = el.querySelector("a[href]");
|
|
665
|
+
if (childLink && childLink.href) return;
|
|
666
|
+
options.debug && el.className && el.className.includes("titleline");
|
|
667
|
+
}
|
|
668
|
+
window.sentience_registry[idx] = el;
|
|
669
|
+
const inputType = "input" === tagName ? toSafeString(el.getAttribute && el.getAttribute("type") || el.type || null) : null, isPasswordInput = inputType && "password" === inputType.toLowerCase(), semanticText = function(el, options = {}) {
|
|
670
|
+
if (!el) return {
|
|
671
|
+
text: "",
|
|
672
|
+
source: null
|
|
673
|
+
};
|
|
674
|
+
const explicitAriaLabel = el.getAttribute ? el.getAttribute("aria-label") : null;
|
|
675
|
+
if (explicitAriaLabel && explicitAriaLabel.trim()) return {
|
|
676
|
+
text: explicitAriaLabel.trim(),
|
|
677
|
+
source: "explicit_aria_label"
|
|
678
|
+
};
|
|
679
|
+
if ("INPUT" === el.tagName) {
|
|
680
|
+
const t = el.getAttribute && el.getAttribute("type") || el.type || "", isPassword = "password" === String(t).toLowerCase(), value = (isPassword ? el.placeholder || "" : el.value || el.placeholder || "").trim();
|
|
681
|
+
if (value) return {
|
|
682
|
+
text: value,
|
|
683
|
+
source: isPassword ? "input_placeholder" : "input_value"
|
|
684
|
+
};
|
|
685
|
+
}
|
|
686
|
+
if ("IMG" === el.tagName) {
|
|
687
|
+
const alt = (el.alt || "").trim();
|
|
688
|
+
if (alt) return {
|
|
689
|
+
text: alt,
|
|
690
|
+
source: "img_alt"
|
|
691
|
+
};
|
|
692
|
+
}
|
|
693
|
+
const innerText = (el.innerText || "").trim();
|
|
694
|
+
if (innerText) return {
|
|
695
|
+
text: innerText.substring(0, 100),
|
|
696
|
+
source: "inner_text"
|
|
697
|
+
};
|
|
698
|
+
const inferred = getInferredLabel(el, {
|
|
699
|
+
enableInference: !1 !== options.enableInference,
|
|
700
|
+
inferenceConfig: options.inferenceConfig
|
|
701
|
+
});
|
|
702
|
+
return inferred || {
|
|
703
|
+
text: "",
|
|
704
|
+
source: null
|
|
705
|
+
};
|
|
706
|
+
}(el, {
|
|
707
|
+
enableInference: !1 !== options.enableInference,
|
|
708
|
+
inferenceConfig: options.inferenceConfig
|
|
709
|
+
}), textVal = semanticText.text || getText(el), inferredRole = function(el, options = {}) {
|
|
710
|
+
const {enableInference: enableInference = !0} = options;
|
|
711
|
+
if (!enableInference) return null;
|
|
712
|
+
if (!isInteractableElement(el)) return null;
|
|
713
|
+
const hasAriaLabel = el.getAttribute ? el.getAttribute("aria-label") : null, hasExplicitRole = el.getAttribute ? el.getAttribute("role") : null;
|
|
714
|
+
if (hasAriaLabel || hasExplicitRole) return null;
|
|
715
|
+
const tag = el.tagName.toLowerCase();
|
|
716
|
+
return [ "button", "a", "input", "textarea", "select", "option" ].includes(tag) ? null : el.onclick || el.getAttribute && el.getAttribute("onclick") || el.onkeydown || el.onkeypress || el.onkeyup || el.getAttribute && (el.getAttribute("onkeydown") || el.getAttribute("onkeypress") || el.getAttribute("onkeyup")) || el.hasAttribute && el.hasAttribute("tabindex") && ("div" === tag || "span" === tag) ? "button" : null;
|
|
717
|
+
}(el, {
|
|
718
|
+
enableInference: !1 !== options.enableInference,
|
|
719
|
+
inferenceConfig: options.inferenceConfig
|
|
720
|
+
}), inView = function(rect) {
|
|
721
|
+
return rect.top < window.innerHeight && rect.bottom > 0 && rect.left < window.innerWidth && rect.right > 0;
|
|
722
|
+
}(rect), style = window.getComputedStyle(el), occluded = !!inView && function(el, rect, style) {
|
|
723
|
+
const zIndex = parseInt(style.zIndex, 10);
|
|
724
|
+
if ("static" === style.position && (isNaN(zIndex) || zIndex <= 10)) return !1;
|
|
725
|
+
const cx = rect.x + rect.width / 2, cy = rect.y + rect.height / 2;
|
|
726
|
+
if (cx < 0 || cx > window.innerWidth || cy < 0 || cy > window.innerHeight) return !1;
|
|
727
|
+
const topEl = document.elementFromPoint(cx, cy);
|
|
728
|
+
return !!topEl && !(el === topEl || el.contains(topEl) || topEl.contains(el));
|
|
729
|
+
}(el, rect, style), effectiveBgColor = function(el) {
|
|
730
|
+
if (!el) return null;
|
|
731
|
+
if ("SVG" === el.tagName) {
|
|
732
|
+
const svgColor = getSVGColor(el);
|
|
733
|
+
if (svgColor) return svgColor;
|
|
734
|
+
}
|
|
735
|
+
let current = el, depth = 0;
|
|
736
|
+
for (;current && depth < 10; ) {
|
|
737
|
+
const style = window.getComputedStyle(current);
|
|
738
|
+
if ("SVG" === current.tagName) {
|
|
739
|
+
const svgColor = getSVGColor(current);
|
|
740
|
+
if (svgColor) return svgColor;
|
|
741
|
+
}
|
|
742
|
+
const bgColor = style.backgroundColor;
|
|
743
|
+
if (bgColor && "transparent" !== bgColor && "rgba(0, 0, 0, 0)" !== bgColor) {
|
|
744
|
+
const rgbaMatch = bgColor.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*([\d.]+))?\)/);
|
|
745
|
+
if (!rgbaMatch) return bgColor.startsWith("rgb("), bgColor;
|
|
746
|
+
if ((rgbaMatch[4] ? parseFloat(rgbaMatch[4]) : 1) >= .9) return `rgb(${rgbaMatch[1]}, ${rgbaMatch[2]}, ${rgbaMatch[3]})`;
|
|
747
|
+
}
|
|
748
|
+
current = current.parentElement, depth++;
|
|
749
|
+
}
|
|
750
|
+
return null;
|
|
751
|
+
}(el);
|
|
752
|
+
let safeValue = null, valueRedacted = null;
|
|
753
|
+
try {
|
|
754
|
+
if (void 0 !== el.value || el.getAttribute && null !== el.getAttribute("value")) if (isPasswordInput) safeValue = null,
|
|
755
|
+
valueRedacted = "true"; else {
|
|
756
|
+
const rawValue = void 0 !== el.value ? String(el.value) : String(el.getAttribute("value"));
|
|
757
|
+
safeValue = rawValue.length > 200 ? rawValue.substring(0, 200) : rawValue, valueRedacted = "false";
|
|
758
|
+
}
|
|
759
|
+
} catch (e) {}
|
|
760
|
+
const accessibleName = toSafeString(function(el) {
|
|
761
|
+
if (!el || !el.getAttribute) return "";
|
|
762
|
+
const ariaLabel = el.getAttribute("aria-label");
|
|
763
|
+
if (ariaLabel && ariaLabel.trim()) return ariaLabel.trim().substring(0, 200);
|
|
764
|
+
const labelledBy = el.getAttribute("aria-labelledby");
|
|
765
|
+
if (labelledBy && labelledBy.trim()) {
|
|
766
|
+
const ids = labelledBy.split(/\s+/).filter(id => id.trim()), texts = [];
|
|
767
|
+
for (const id of ids) try {
|
|
768
|
+
const ref = document.getElementById(id);
|
|
769
|
+
if (!ref) continue;
|
|
770
|
+
const txt = (ref.innerText || ref.textContent || ref.getAttribute?.("aria-label") || "").toString().trim();
|
|
771
|
+
txt && texts.push(txt);
|
|
772
|
+
} catch (e) {}
|
|
773
|
+
if (texts.length > 0) return texts.join(" ").substring(0, 200);
|
|
774
|
+
}
|
|
775
|
+
try {
|
|
776
|
+
if (el.labels && el.labels.length > 0) {
|
|
777
|
+
const t = (el.labels[0].innerText || el.labels[0].textContent || "").toString().trim();
|
|
778
|
+
if (t) return t.substring(0, 200);
|
|
779
|
+
}
|
|
780
|
+
} catch (e) {}
|
|
781
|
+
try {
|
|
782
|
+
const parentLabel = el.closest && el.closest("label");
|
|
783
|
+
if (parentLabel) {
|
|
784
|
+
const t = (parentLabel.innerText || parentLabel.textContent || "").toString().trim();
|
|
785
|
+
if (t) return t.substring(0, 200);
|
|
786
|
+
}
|
|
787
|
+
} catch (e) {}
|
|
788
|
+
const tag = (el.tagName || "").toUpperCase();
|
|
789
|
+
if ("INPUT" === tag || "TEXTAREA" === tag) {
|
|
790
|
+
const ph = (el.getAttribute("placeholder") || "").toString().trim();
|
|
791
|
+
if (ph) return ph.substring(0, 200);
|
|
792
|
+
}
|
|
793
|
+
const title = el.getAttribute("title");
|
|
794
|
+
return title && title.trim() ? title.trim().substring(0, 200) : "";
|
|
795
|
+
}(el) || null), nearbyText = isInteractableElement(el) ? function(el, options = {}) {
|
|
796
|
+
if (!el) return null;
|
|
797
|
+
const maxLen = "number" == typeof options.maxLen ? options.maxLen : 80, ownText = normalizeNearbyText(el.innerText || ""), candidates = [], collect = node => {
|
|
798
|
+
if (!node) return;
|
|
799
|
+
let text = "";
|
|
800
|
+
try {
|
|
801
|
+
text = normalizeNearbyText(node.innerText || node.textContent || "");
|
|
802
|
+
} catch (e) {
|
|
803
|
+
text = "";
|
|
804
|
+
}
|
|
805
|
+
text && text !== ownText && candidates.push(text);
|
|
806
|
+
};
|
|
807
|
+
if (collect(el.previousElementSibling), collect(el.nextElementSibling), 0 === candidates.length && el.parentElement) {
|
|
808
|
+
let parentText = "";
|
|
809
|
+
try {
|
|
810
|
+
parentText = normalizeNearbyText(el.parentElement.innerText || "");
|
|
811
|
+
} catch (e) {
|
|
812
|
+
parentText = "";
|
|
813
|
+
}
|
|
814
|
+
parentText && parentText !== ownText && parentText.length <= 120 && candidates.push(parentText);
|
|
815
|
+
}
|
|
816
|
+
if (0 === candidates.length) return null;
|
|
817
|
+
let text = candidates[0];
|
|
818
|
+
return text.length > maxLen && (text = text.slice(0, maxLen).trim()), text || null;
|
|
819
|
+
}(el, {
|
|
820
|
+
maxLen: 80
|
|
821
|
+
}) : null, containerInfo = computeContainerInfo(el);
|
|
822
|
+
rawData.push({
|
|
823
|
+
id: idx,
|
|
824
|
+
tag: tagName,
|
|
825
|
+
rect: {
|
|
826
|
+
x: rect.x,
|
|
827
|
+
y: rect.y,
|
|
828
|
+
width: rect.width,
|
|
829
|
+
height: rect.height
|
|
830
|
+
},
|
|
831
|
+
styles: {
|
|
832
|
+
display: toSafeString(style.display),
|
|
833
|
+
visibility: toSafeString(style.visibility),
|
|
834
|
+
opacity: toSafeString(style.opacity),
|
|
835
|
+
z_index: toSafeString(style.zIndex || "auto"),
|
|
836
|
+
position: toSafeString(style.position),
|
|
837
|
+
bg_color: toSafeString(effectiveBgColor || style.backgroundColor),
|
|
838
|
+
color: toSafeString(style.color),
|
|
839
|
+
cursor: toSafeString(style.cursor),
|
|
840
|
+
font_weight: toSafeString(style.fontWeight),
|
|
841
|
+
font_size: toSafeString(style.fontSize)
|
|
842
|
+
},
|
|
843
|
+
attributes: {
|
|
844
|
+
role: toSafeString(el.getAttribute("role")),
|
|
845
|
+
type_: toSafeString(el.getAttribute("type")),
|
|
846
|
+
input_type: inputType,
|
|
847
|
+
aria_label: "explicit_aria_label" === semanticText?.source ? semanticText.text : toSafeString(el.getAttribute("aria-label")),
|
|
848
|
+
name: accessibleName,
|
|
849
|
+
inferred_label: semanticText?.source && ![ "explicit_aria_label", "input_value", "img_alt", "inner_text" ].includes(semanticText.source) ? toSafeString(semanticText.text) : null,
|
|
850
|
+
label_source: semanticText?.source || null,
|
|
851
|
+
inferred_role: inferredRole ? toSafeString(inferredRole) : null,
|
|
852
|
+
nearby_text: toSafeString(nearbyText),
|
|
853
|
+
href: toSafeString(el.href || el.getAttribute("href") || el.closest && el.closest("a")?.href || null),
|
|
854
|
+
class: toSafeString(getClassName(el)),
|
|
855
|
+
value: null !== safeValue ? toSafeString(safeValue) : null,
|
|
856
|
+
value_redacted: valueRedacted,
|
|
857
|
+
checked: void 0 !== el.checked ? String(el.checked) : null,
|
|
858
|
+
disabled: void 0 !== el.disabled ? String(el.disabled) : null,
|
|
859
|
+
aria_checked: toSafeString(el.getAttribute("aria-checked")),
|
|
860
|
+
aria_disabled: toSafeString(el.getAttribute("aria-disabled")),
|
|
861
|
+
aria_expanded: toSafeString(el.getAttribute("aria-expanded")),
|
|
862
|
+
aria_posinset: parseAriaInt(el, "aria-posinset"),
|
|
863
|
+
aria_setsize: parseAriaInt(el, "aria-setsize"),
|
|
864
|
+
aria_rowindex: parseAriaInt(el, "aria-rowindex"),
|
|
865
|
+
aria_colindex: parseAriaInt(el, "aria-colindex")
|
|
866
|
+
},
|
|
867
|
+
container_key: containerInfo ? containerInfo.container_key : null,
|
|
868
|
+
index_in_container: containerInfo ? containerInfo.index_in_container : null,
|
|
869
|
+
container_item_count: containerInfo ? containerInfo.container_item_count : null,
|
|
870
|
+
text: toSafeString(textVal),
|
|
871
|
+
in_viewport: inView,
|
|
872
|
+
is_occluded: occluded,
|
|
873
|
+
scroll_y: window.scrollY
|
|
874
|
+
});
|
|
875
|
+
});
|
|
876
|
+
const allRawElements = [ ...rawData ];
|
|
877
|
+
let totalIframeElements = 0;
|
|
878
|
+
if (!1 !== options.collectIframes) try {
|
|
879
|
+
const iframeSnapshots = await async function(options = {}) {
|
|
880
|
+
const iframeData = new Map, iframes = Array.from(document.querySelectorAll("iframe"));
|
|
881
|
+
if (0 === iframes.length) return iframeData;
|
|
882
|
+
const iframePromises = iframes.map((iframe, idx) => {
|
|
883
|
+
const src = iframe.src || "";
|
|
884
|
+
return src.includes("doubleclick") || src.includes("googleadservices") || src.includes("ads system") ? Promise.resolve(null) : new Promise(resolve => {
|
|
885
|
+
const requestId = `iframe-${idx}-${Date.now()}`, timeout = setTimeout(() => {
|
|
886
|
+
resolve(null);
|
|
887
|
+
}, 5e3), listener = event => {
|
|
888
|
+
"SENTIENCE_IFRAME_SNAPSHOT_RESPONSE" === event.data?.type && event.data, "SENTIENCE_IFRAME_SNAPSHOT_RESPONSE" === event.data?.type && event.data?.requestId === requestId && (clearTimeout(timeout),
|
|
889
|
+
window.removeEventListener("message", listener), event.data.error ? resolve(null) : (event.data.snapshot,
|
|
890
|
+
resolve({
|
|
891
|
+
iframe: iframe,
|
|
892
|
+
data: event.data.snapshot,
|
|
893
|
+
error: null
|
|
894
|
+
})));
|
|
895
|
+
};
|
|
896
|
+
window.addEventListener("message", listener);
|
|
897
|
+
try {
|
|
898
|
+
iframe.contentWindow ? iframe.contentWindow.postMessage({
|
|
899
|
+
type: "SENTIENCE_IFRAME_SNAPSHOT_REQUEST",
|
|
900
|
+
requestId: requestId,
|
|
901
|
+
options: {
|
|
902
|
+
...options,
|
|
903
|
+
collectIframes: !0
|
|
904
|
+
}
|
|
905
|
+
}, "*") : (clearTimeout(timeout), window.removeEventListener("message", listener),
|
|
906
|
+
resolve(null));
|
|
907
|
+
} catch (error) {
|
|
908
|
+
clearTimeout(timeout), window.removeEventListener("message", listener), resolve(null);
|
|
909
|
+
}
|
|
910
|
+
});
|
|
911
|
+
});
|
|
912
|
+
return (await Promise.all(iframePromises)).forEach((result, idx) => {
|
|
913
|
+
result && result.data && !result.error ? iframeData.set(iframes[idx], result.data) : result && result.error;
|
|
914
|
+
}), iframeData;
|
|
915
|
+
}(options);
|
|
916
|
+
iframeSnapshots.size > 0 && iframeSnapshots.forEach((iframeSnapshot, iframeEl) => {
|
|
917
|
+
if (iframeSnapshot && iframeSnapshot.raw_elements) {
|
|
918
|
+
iframeSnapshot.raw_elements.length;
|
|
919
|
+
const iframeRect = iframeEl.getBoundingClientRect(), offset = {
|
|
920
|
+
x: iframeRect.x,
|
|
921
|
+
y: iframeRect.y
|
|
922
|
+
}, iframeSrc = iframeEl.src || iframeEl.getAttribute("src") || "";
|
|
923
|
+
let isSameOrigin = !1;
|
|
924
|
+
try {
|
|
925
|
+
isSameOrigin = null !== iframeEl.contentWindow;
|
|
926
|
+
} catch (e) {
|
|
927
|
+
isSameOrigin = !1;
|
|
928
|
+
}
|
|
929
|
+
const adjustedElements = iframeSnapshot.raw_elements.map(el => {
|
|
930
|
+
const adjusted = {
|
|
931
|
+
...el
|
|
932
|
+
};
|
|
933
|
+
return adjusted.rect && (adjusted.rect = {
|
|
934
|
+
...adjusted.rect,
|
|
935
|
+
x: adjusted.rect.x + offset.x,
|
|
936
|
+
y: adjusted.rect.y + offset.y
|
|
937
|
+
}), adjusted.iframe_context = {
|
|
938
|
+
src: iframeSrc,
|
|
939
|
+
is_same_origin: isSameOrigin
|
|
940
|
+
}, adjusted;
|
|
941
|
+
});
|
|
942
|
+
allRawElements.push(...adjustedElements), totalIframeElements += adjustedElements.length;
|
|
943
|
+
}
|
|
944
|
+
});
|
|
945
|
+
} catch (error) {}
|
|
946
|
+
const fallbackElementsFromRaw = raw => (raw || []).map(r => {
|
|
947
|
+
const rect = r && r.rect || {
|
|
948
|
+
x: 0,
|
|
949
|
+
y: 0,
|
|
950
|
+
width: 0,
|
|
951
|
+
height: 0
|
|
952
|
+
}, attrs = r && r.attributes || {}, role = attrs.role || r && (r.inferred_role || r.inferredRole) || (r && "a" === r.tag ? "link" : "generic"), href = attrs.href || r && r.href || null, isClickable = "link" === role || "button" === role || "textbox" === role || "checkbox" === role || "radio" === role || "combobox" === role || !!href;
|
|
953
|
+
return {
|
|
954
|
+
id: Number(r && r.id || 0),
|
|
955
|
+
role: String(role || "generic"),
|
|
956
|
+
text: r && (r.text || r.semantic_text || r.semanticText) || null,
|
|
957
|
+
importance: 1,
|
|
958
|
+
bbox: {
|
|
959
|
+
x: Number(rect.x || 0),
|
|
960
|
+
y: Number(rect.y || 0),
|
|
961
|
+
width: Number(rect.width || 0),
|
|
962
|
+
height: Number(rect.height || 0)
|
|
963
|
+
},
|
|
964
|
+
visual_cues: {
|
|
965
|
+
is_primary: !1,
|
|
966
|
+
is_clickable: !!isClickable
|
|
967
|
+
},
|
|
968
|
+
in_viewport: !0,
|
|
969
|
+
is_occluded: !(!r || !r.occluded && !r.is_occluded),
|
|
970
|
+
z_index: 0,
|
|
971
|
+
name: attrs.aria_label || attrs.ariaLabel || null,
|
|
972
|
+
value: r && r.value || null,
|
|
973
|
+
input_type: attrs.type_ || attrs.type || null,
|
|
974
|
+
checked: "boolean" == typeof (r && r.checked) ? r.checked : null,
|
|
975
|
+
disabled: "boolean" == typeof (r && r.disabled) ? r.disabled : null,
|
|
976
|
+
expanded: "boolean" == typeof (r && r.expanded) ? r.expanded : null
|
|
977
|
+
};
|
|
978
|
+
});
|
|
979
|
+
let processed = null;
|
|
980
|
+
try {
|
|
981
|
+
processed = await function(rawData, options) {
|
|
982
|
+
return new Promise((resolve, reject) => {
|
|
983
|
+
const requestId = Math.random().toString(36).substring(7);
|
|
984
|
+
let resolved = !1;
|
|
985
|
+
const timeout = setTimeout(() => {
|
|
986
|
+
resolved || (resolved = !0, window.removeEventListener("message", listener), reject(new Error("WASM processing timeout - extension may be unresponsive. Try reloading the extension.")));
|
|
987
|
+
}, 25e3), listener = e => {
|
|
988
|
+
if ("SENTIENCE_SNAPSHOT_RESULT" === e.data.type && e.data.requestId === requestId) {
|
|
989
|
+
if (resolved) return;
|
|
990
|
+
resolved = !0, clearTimeout(timeout), window.removeEventListener("message", listener),
|
|
991
|
+
e.data.error ? reject(new Error(e.data.error)) : resolve({
|
|
992
|
+
elements: e.data.elements,
|
|
993
|
+
raw_elements: e.data.raw_elements,
|
|
994
|
+
duration: e.data.duration
|
|
995
|
+
});
|
|
996
|
+
}
|
|
997
|
+
};
|
|
998
|
+
window.addEventListener("message", listener);
|
|
999
|
+
try {
|
|
1000
|
+
window.postMessage({
|
|
1001
|
+
type: "SENTIENCE_SNAPSHOT_REQUEST",
|
|
1002
|
+
requestId: requestId,
|
|
1003
|
+
rawData: rawData,
|
|
1004
|
+
options: options
|
|
1005
|
+
}, "*");
|
|
1006
|
+
} catch (error) {
|
|
1007
|
+
resolved || (resolved = !0, clearTimeout(timeout), window.removeEventListener("message", listener),
|
|
1008
|
+
reject(new Error(`Failed to send snapshot request: ${error.message}`)));
|
|
1009
|
+
}
|
|
1010
|
+
});
|
|
1011
|
+
}(allRawElements, options);
|
|
1012
|
+
} catch (error) {
|
|
1013
|
+
processed = {
|
|
1014
|
+
elements: fallbackElementsFromRaw(allRawElements),
|
|
1015
|
+
raw_elements: allRawElements,
|
|
1016
|
+
duration: null
|
|
1017
|
+
};
|
|
1018
|
+
}
|
|
1019
|
+
processed && processed.elements || (processed = {
|
|
1020
|
+
elements: fallbackElementsFromRaw(allRawElements),
|
|
1021
|
+
raw_elements: allRawElements,
|
|
1022
|
+
duration: null
|
|
1023
|
+
});
|
|
1024
|
+
let screenshot = null;
|
|
1025
|
+
options.screenshot && (screenshot = await function(options) {
|
|
1026
|
+
return new Promise(resolve => {
|
|
1027
|
+
const requestId = Math.random().toString(36).substring(7), listener = e => {
|
|
1028
|
+
"SENTIENCE_SCREENSHOT_RESULT" === e.data.type && e.data.requestId === requestId && (window.removeEventListener("message", listener),
|
|
1029
|
+
resolve(e.data.screenshot));
|
|
1030
|
+
};
|
|
1031
|
+
window.addEventListener("message", listener), window.postMessage({
|
|
1032
|
+
type: "SENTIENCE_SCREENSHOT_REQUEST",
|
|
1033
|
+
requestId: requestId,
|
|
1034
|
+
options: options
|
|
1035
|
+
}, "*"), setTimeout(() => {
|
|
1036
|
+
window.removeEventListener("message", listener), resolve(null);
|
|
1037
|
+
}, 1e4);
|
|
1038
|
+
});
|
|
1039
|
+
}(options.screenshot));
|
|
1040
|
+
const cleanedElements = cleanElement(processed.elements), cleanedRawElements = cleanElement(processed.raw_elements);
|
|
1041
|
+
cleanedElements.length, cleanedRawElements.length;
|
|
1042
|
+
let diagnostics;
|
|
1043
|
+
try {
|
|
1044
|
+
const lastMutationTs = window.__sentience_lastMutationTs, now = performance.now(), quietMs = "number" == typeof lastMutationTs && Number.isFinite(lastMutationTs) ? Math.max(0, now - lastMutationTs) : null, nodeCount = document.querySelectorAll("*").length;
|
|
1045
|
+
let requiresVision = !1, requiresVisionReason = null;
|
|
1046
|
+
const canvasCount = document.getElementsByTagName("canvas").length;
|
|
1047
|
+
canvasCount > 0 && (requiresVision = !0, requiresVisionReason = `canvas:${canvasCount}`),
|
|
1048
|
+
diagnostics = {
|
|
1049
|
+
metrics: {
|
|
1050
|
+
ready_state: document.readyState || null,
|
|
1051
|
+
quiet_ms: quietMs,
|
|
1052
|
+
node_count: nodeCount
|
|
1053
|
+
},
|
|
1054
|
+
captcha: detectCaptcha(),
|
|
1055
|
+
requires_vision: requiresVision,
|
|
1056
|
+
requires_vision_reason: requiresVisionReason
|
|
1057
|
+
};
|
|
1058
|
+
} catch (e) {}
|
|
1059
|
+
return {
|
|
1060
|
+
status: "success",
|
|
1061
|
+
url: window.location.href,
|
|
1062
|
+
viewport: {
|
|
1063
|
+
width: window.innerWidth,
|
|
1064
|
+
height: window.innerHeight
|
|
1065
|
+
},
|
|
1066
|
+
elements: cleanedElements,
|
|
1067
|
+
raw_elements: cleanedRawElements,
|
|
1068
|
+
screenshot: screenshot,
|
|
1069
|
+
diagnostics: diagnostics
|
|
1070
|
+
};
|
|
1071
|
+
} catch (error) {
|
|
1072
|
+
return {
|
|
1073
|
+
status: "error",
|
|
1074
|
+
error: error.message || "Unknown error",
|
|
1075
|
+
stack: error.stack
|
|
1076
|
+
};
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
function read(options = {}) {
|
|
1080
|
+
const format = options.format || "raw";
|
|
1081
|
+
let content;
|
|
1082
|
+
return content = "raw" === format ? getRawHTML(document.body) : "markdown" === format ? function(root) {
|
|
1083
|
+
const rawHTML = getRawHTML(root), tempDiv = document.createElement("div");
|
|
1084
|
+
tempDiv.innerHTML = rawHTML;
|
|
1085
|
+
let markdown = "", insideLink = !1;
|
|
1086
|
+
return function walk(node) {
|
|
1087
|
+
if (node.nodeType === Node.TEXT_NODE) {
|
|
1088
|
+
const text = node.textContent.replace(/[\r\n]+/g, " ").replace(/\s+/g, " ");
|
|
1089
|
+
return void (text.trim() && (markdown += text));
|
|
1090
|
+
}
|
|
1091
|
+
if (node.nodeType !== Node.ELEMENT_NODE) return;
|
|
1092
|
+
const tag = node.tagName.toLowerCase();
|
|
1093
|
+
if ("h1" === tag && (markdown += "\n# "), "h2" === tag && (markdown += "\n## "),
|
|
1094
|
+
"h3" === tag && (markdown += "\n### "), "li" === tag && (markdown += "\n- "), insideLink || "p" !== tag && "div" !== tag && "br" !== tag || (markdown += "\n"),
|
|
1095
|
+
"strong" !== tag && "b" !== tag || (markdown += "**"), "em" !== tag && "i" !== tag || (markdown += "_"),
|
|
1096
|
+
"a" === tag && (markdown += "[", insideLink = !0), node.shadowRoot ? Array.from(node.shadowRoot.childNodes).forEach(walk) : node.childNodes.forEach(walk),
|
|
1097
|
+
"a" === tag) {
|
|
1098
|
+
const href = node.getAttribute("href");
|
|
1099
|
+
markdown += href ? `](${href})` : "]", insideLink = !1;
|
|
1100
|
+
}
|
|
1101
|
+
"strong" !== tag && "b" !== tag || (markdown += "**"), "em" !== tag && "i" !== tag || (markdown += "_"),
|
|
1102
|
+
insideLink || "h1" !== tag && "h2" !== tag && "h3" !== tag && "p" !== tag && "div" !== tag || (markdown += "\n");
|
|
1103
|
+
}(tempDiv), markdown.replace(/\n{3,}/g, "\n\n").trim();
|
|
1104
|
+
}(document.body) : function(root) {
|
|
1105
|
+
let text = "";
|
|
1106
|
+
return function walk(node) {
|
|
1107
|
+
if (node.nodeType !== Node.TEXT_NODE) {
|
|
1108
|
+
if (node.nodeType === Node.ELEMENT_NODE) {
|
|
1109
|
+
const tag = node.tagName.toLowerCase();
|
|
1110
|
+
if ([ "nav", "footer", "header", "script", "style", "noscript", "iframe", "svg" ].includes(tag)) return;
|
|
1111
|
+
const style = window.getComputedStyle(node);
|
|
1112
|
+
if ("none" === style.display || "hidden" === style.visibility) return;
|
|
1113
|
+
const isBlock = "block" === style.display || "flex" === style.display || "P" === node.tagName || "DIV" === node.tagName;
|
|
1114
|
+
isBlock && (text += " "), node.shadowRoot ? Array.from(node.shadowRoot.childNodes).forEach(walk) : node.childNodes.forEach(walk),
|
|
1115
|
+
isBlock && (text += "\n");
|
|
1116
|
+
}
|
|
1117
|
+
} else text += node.textContent;
|
|
1118
|
+
}(root || document.body), text.replace(/\n{3,}/g, "\n\n").trim();
|
|
1119
|
+
}(document.body), {
|
|
1120
|
+
status: "success",
|
|
1121
|
+
url: window.location.href,
|
|
1122
|
+
format: format,
|
|
1123
|
+
content: content,
|
|
1124
|
+
length: content.length
|
|
1125
|
+
};
|
|
1126
|
+
}
|
|
1127
|
+
function findTextRect(options = {}) {
|
|
1128
|
+
const {text: text, containerElement: containerElement = document.body, caseSensitive: caseSensitive = !1, wholeWord: wholeWord = !1, maxResults: maxResults = 10} = options;
|
|
1129
|
+
if (!text || 0 === text.trim().length) return {
|
|
1130
|
+
status: "error",
|
|
1131
|
+
error: "Text parameter is required"
|
|
1132
|
+
};
|
|
1133
|
+
const results = [], searchText = caseSensitive ? text : text.toLowerCase();
|
|
1134
|
+
function findInTextNode(textNode) {
|
|
1135
|
+
const nodeText = textNode.nodeValue, searchableText = caseSensitive ? nodeText : nodeText.toLowerCase();
|
|
1136
|
+
let startIndex = 0;
|
|
1137
|
+
for (;startIndex < nodeText.length && results.length < maxResults; ) {
|
|
1138
|
+
const foundIndex = searchableText.indexOf(searchText, startIndex);
|
|
1139
|
+
if (-1 === foundIndex) break;
|
|
1140
|
+
if (wholeWord) {
|
|
1141
|
+
const before = foundIndex > 0 ? nodeText[foundIndex - 1] : " ", after = foundIndex + text.length < nodeText.length ? nodeText[foundIndex + text.length] : " ";
|
|
1142
|
+
if (!/\s/.test(before) || !/\s/.test(after)) {
|
|
1143
|
+
startIndex = foundIndex + 1;
|
|
1144
|
+
continue;
|
|
1145
|
+
}
|
|
1146
|
+
}
|
|
1147
|
+
try {
|
|
1148
|
+
const range = document.createRange();
|
|
1149
|
+
range.setStart(textNode, foundIndex), range.setEnd(textNode, foundIndex + text.length);
|
|
1150
|
+
const rect = range.getBoundingClientRect();
|
|
1151
|
+
rect.width > 0 && rect.height > 0 && results.push({
|
|
1152
|
+
text: nodeText.substring(foundIndex, foundIndex + text.length),
|
|
1153
|
+
rect: {
|
|
1154
|
+
x: rect.left + window.scrollX,
|
|
1155
|
+
y: rect.top + window.scrollY,
|
|
1156
|
+
width: rect.width,
|
|
1157
|
+
height: rect.height,
|
|
1158
|
+
left: rect.left + window.scrollX,
|
|
1159
|
+
top: rect.top + window.scrollY,
|
|
1160
|
+
right: rect.right + window.scrollX,
|
|
1161
|
+
bottom: rect.bottom + window.scrollY
|
|
1162
|
+
},
|
|
1163
|
+
viewport_rect: {
|
|
1164
|
+
x: rect.left,
|
|
1165
|
+
y: rect.top,
|
|
1166
|
+
width: rect.width,
|
|
1167
|
+
height: rect.height
|
|
1168
|
+
},
|
|
1169
|
+
context: {
|
|
1170
|
+
before: nodeText.substring(Math.max(0, foundIndex - 20), foundIndex),
|
|
1171
|
+
after: nodeText.substring(foundIndex + text.length, Math.min(nodeText.length, foundIndex + text.length + 20))
|
|
1172
|
+
},
|
|
1173
|
+
in_viewport: rect.top >= 0 && rect.left >= 0 && rect.bottom <= window.innerHeight && rect.right <= window.innerWidth
|
|
1174
|
+
});
|
|
1175
|
+
} catch (e) {}
|
|
1176
|
+
startIndex = foundIndex + 1;
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1179
|
+
const walker = document.createTreeWalker(containerElement, NodeFilter.SHOW_TEXT, {
|
|
1180
|
+
acceptNode(node) {
|
|
1181
|
+
const parent = node.parentElement;
|
|
1182
|
+
if (!parent) return NodeFilter.FILTER_REJECT;
|
|
1183
|
+
const tagName = parent.tagName.toLowerCase();
|
|
1184
|
+
if ("script" === tagName || "style" === tagName || "noscript" === tagName) return NodeFilter.FILTER_REJECT;
|
|
1185
|
+
if (!node.nodeValue || 0 === node.nodeValue.trim().length) return NodeFilter.FILTER_REJECT;
|
|
1186
|
+
const computedStyle = window.getComputedStyle(parent);
|
|
1187
|
+
return "none" === computedStyle.display || "hidden" === computedStyle.visibility || "0" === computedStyle.opacity ? NodeFilter.FILTER_REJECT : NodeFilter.FILTER_ACCEPT;
|
|
1188
|
+
}
|
|
1189
|
+
});
|
|
1190
|
+
let currentNode;
|
|
1191
|
+
for (;(currentNode = walker.nextNode()) && results.length < maxResults; ) findInTextNode(currentNode);
|
|
1192
|
+
return {
|
|
1193
|
+
status: "success",
|
|
1194
|
+
query: text,
|
|
1195
|
+
case_sensitive: caseSensitive,
|
|
1196
|
+
whole_word: wholeWord,
|
|
1197
|
+
matches: results.length,
|
|
1198
|
+
results: results,
|
|
1199
|
+
viewport: {
|
|
1200
|
+
width: window.innerWidth,
|
|
1201
|
+
height: window.innerHeight,
|
|
1202
|
+
scroll_x: window.scrollX,
|
|
1203
|
+
scroll_y: window.scrollY
|
|
1204
|
+
}
|
|
1205
|
+
};
|
|
1206
|
+
}
|
|
1207
|
+
function click(id) {
|
|
1208
|
+
const el = window.sentience_registry[id];
|
|
1209
|
+
return !!el && (el.click(), el.focus(), !0);
|
|
1210
|
+
}
|
|
1211
|
+
function startRecording(options = {}) {
|
|
1212
|
+
const {highlightColor: highlightColor = "#ff0000", successColor: successColor = "#00ff00", autoDisableTimeout: autoDisableTimeout = 18e5, keyboardShortcut: keyboardShortcut = "Ctrl+Shift+I"} = options;
|
|
1213
|
+
if (!window.sentience_registry || 0 === window.sentience_registry.length) return alert("Registry empty. Run `await window.sentience.snapshot()` first!"),
|
|
1214
|
+
() => {};
|
|
1215
|
+
window.sentience_registry_map = new Map, window.sentience_registry.forEach((el, idx) => {
|
|
1216
|
+
el && window.sentience_registry_map.set(el, idx);
|
|
1217
|
+
});
|
|
1218
|
+
let highlightBox = document.getElementById("sentience-highlight-box");
|
|
1219
|
+
highlightBox || (highlightBox = document.createElement("div"), highlightBox.id = "sentience-highlight-box",
|
|
1220
|
+
highlightBox.style.cssText = `\n position: fixed;\n pointer-events: none;\n z-index: 2147483647;\n border: 2px solid ${highlightColor};\n background: rgba(255, 0, 0, 0.1);\n display: none;\n transition: all 0.1s ease;\n box-sizing: border-box;\n `,
|
|
1221
|
+
document.body.appendChild(highlightBox));
|
|
1222
|
+
let recordingIndicator = document.getElementById("sentience-recording-indicator");
|
|
1223
|
+
recordingIndicator || (recordingIndicator = document.createElement("div"), recordingIndicator.id = "sentience-recording-indicator",
|
|
1224
|
+
recordingIndicator.style.cssText = `\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n height: 3px;\n background: ${highlightColor};\n z-index: 2147483646;\n pointer-events: none;\n `,
|
|
1225
|
+
document.body.appendChild(recordingIndicator)), recordingIndicator.style.display = "block";
|
|
1226
|
+
const mouseOverHandler = e => {
|
|
1227
|
+
const el = e.target;
|
|
1228
|
+
if (!el || el === highlightBox || el === recordingIndicator) return;
|
|
1229
|
+
const rect = el.getBoundingClientRect();
|
|
1230
|
+
highlightBox.style.display = "block", highlightBox.style.top = rect.top + window.scrollY + "px",
|
|
1231
|
+
highlightBox.style.left = rect.left + window.scrollX + "px", highlightBox.style.width = rect.width + "px",
|
|
1232
|
+
highlightBox.style.height = rect.height + "px";
|
|
1233
|
+
}, clickHandler = e => {
|
|
1234
|
+
e.preventDefault(), e.stopPropagation();
|
|
1235
|
+
const el = e.target;
|
|
1236
|
+
if (!el || el === highlightBox || el === recordingIndicator) return;
|
|
1237
|
+
const sentienceId = window.sentience_registry_map.get(el);
|
|
1238
|
+
if (void 0 === sentienceId) return void alert("Element not in registry. Run `await window.sentience.snapshot()` first!");
|
|
1239
|
+
const rawData = function(el) {
|
|
1240
|
+
const style = window.getComputedStyle(el), rect = el.getBoundingClientRect();
|
|
1241
|
+
return {
|
|
1242
|
+
tag: el.tagName,
|
|
1243
|
+
rect: {
|
|
1244
|
+
x: Math.round(rect.x),
|
|
1245
|
+
y: Math.round(rect.y),
|
|
1246
|
+
width: Math.round(rect.width),
|
|
1247
|
+
height: Math.round(rect.height)
|
|
1248
|
+
},
|
|
1249
|
+
styles: {
|
|
1250
|
+
cursor: style.cursor || null,
|
|
1251
|
+
backgroundColor: style.backgroundColor || null,
|
|
1252
|
+
color: style.color || null,
|
|
1253
|
+
fontWeight: style.fontWeight || null,
|
|
1254
|
+
fontSize: style.fontSize || null,
|
|
1255
|
+
display: style.display || null,
|
|
1256
|
+
position: style.position || null,
|
|
1257
|
+
zIndex: style.zIndex || null,
|
|
1258
|
+
opacity: style.opacity || null,
|
|
1259
|
+
visibility: style.visibility || null
|
|
1260
|
+
},
|
|
1261
|
+
attributes: {
|
|
1262
|
+
role: el.getAttribute("role") || null,
|
|
1263
|
+
type: el.getAttribute("type") || null,
|
|
1264
|
+
ariaLabel: el.getAttribute("aria-label") || null,
|
|
1265
|
+
id: el.id || null,
|
|
1266
|
+
className: el.className || null
|
|
1267
|
+
}
|
|
1268
|
+
};
|
|
1269
|
+
}(el), selector = function(el) {
|
|
1270
|
+
if (!el || !el.tagName) return "";
|
|
1271
|
+
if (el.id) return `#${el.id}`;
|
|
1272
|
+
for (const attr of el.attributes) if (attr.name.startsWith("data-") || "aria-label" === attr.name) {
|
|
1273
|
+
const value = attr.value ? attr.value.replace(/"/g, '\\"') : "";
|
|
1274
|
+
return `${el.tagName.toLowerCase()}[${attr.name}="${value}"]`;
|
|
1275
|
+
}
|
|
1276
|
+
const path = [];
|
|
1277
|
+
let current = el;
|
|
1278
|
+
for (;current && current !== document.body && current !== document.documentElement; ) {
|
|
1279
|
+
let selector = current.tagName.toLowerCase();
|
|
1280
|
+
if (current.id) {
|
|
1281
|
+
selector = `#${current.id}`, path.unshift(selector);
|
|
1282
|
+
break;
|
|
1283
|
+
}
|
|
1284
|
+
if (current.className && "string" == typeof current.className) {
|
|
1285
|
+
const classes = current.className.trim().split(/\s+/).filter(c => c);
|
|
1286
|
+
classes.length > 0 && (selector += `.${classes[0]}`);
|
|
1287
|
+
}
|
|
1288
|
+
if (current.parentElement) {
|
|
1289
|
+
const sameTagSiblings = Array.from(current.parentElement.children).filter(s => s.tagName === current.tagName), index = sameTagSiblings.indexOf(current);
|
|
1290
|
+
(index > 0 || sameTagSiblings.length > 1) && (selector += `:nth-of-type(${index + 1})`);
|
|
1291
|
+
}
|
|
1292
|
+
path.unshift(selector), current = current.parentElement;
|
|
1293
|
+
}
|
|
1294
|
+
return path.join(" > ") || el.tagName.toLowerCase();
|
|
1295
|
+
}(el), role = el.getAttribute("role") || el.tagName.toLowerCase(), text = getText(el), snippet = {
|
|
1296
|
+
task: `Interact with ${text.substring(0, 20)}${text.length > 20 ? "..." : ""}`,
|
|
1297
|
+
url: window.location.href,
|
|
1298
|
+
timestamp: (new Date).toISOString(),
|
|
1299
|
+
target_criteria: {
|
|
1300
|
+
id: sentienceId,
|
|
1301
|
+
selector: selector,
|
|
1302
|
+
role: role,
|
|
1303
|
+
text: text.substring(0, 50)
|
|
1304
|
+
},
|
|
1305
|
+
debug_snapshot: rawData
|
|
1306
|
+
}, jsonString = JSON.stringify(snippet, null, 2);
|
|
1307
|
+
navigator.clipboard.writeText(jsonString).then(() => {
|
|
1308
|
+
highlightBox.style.border = `2px solid ${successColor}`, highlightBox.style.background = "rgba(0, 255, 0, 0.2)",
|
|
1309
|
+
setTimeout(() => {
|
|
1310
|
+
highlightBox.style.border = `2px solid ${highlightColor}`, highlightBox.style.background = "rgba(255, 0, 0, 0.1)";
|
|
1311
|
+
}, 500);
|
|
1312
|
+
}).catch(err => {
|
|
1313
|
+
alert("Failed to copy to clipboard. Check console for JSON.");
|
|
1314
|
+
});
|
|
1315
|
+
};
|
|
1316
|
+
let timeoutId = null;
|
|
1317
|
+
const stopRecording = () => {
|
|
1318
|
+
document.removeEventListener("mouseover", mouseOverHandler, !0), document.removeEventListener("click", clickHandler, !0),
|
|
1319
|
+
document.removeEventListener("keydown", keyboardHandler, !0), timeoutId && (clearTimeout(timeoutId),
|
|
1320
|
+
timeoutId = null), highlightBox && (highlightBox.style.display = "none"), recordingIndicator && (recordingIndicator.style.display = "none"),
|
|
1321
|
+
window.sentience_registry_map && window.sentience_registry_map.clear(), window.sentience_stopRecording === stopRecording && delete window.sentience_stopRecording;
|
|
1322
|
+
}, keyboardHandler = e => {
|
|
1323
|
+
(e.ctrlKey || e.metaKey) && e.shiftKey && "I" === e.key && (e.preventDefault(),
|
|
1324
|
+
stopRecording());
|
|
1325
|
+
};
|
|
1326
|
+
return document.addEventListener("mouseover", mouseOverHandler, !0), document.addEventListener("click", clickHandler, !0),
|
|
1327
|
+
document.addEventListener("keydown", keyboardHandler, !0), autoDisableTimeout > 0 && (timeoutId = setTimeout(() => {
|
|
1328
|
+
stopRecording();
|
|
1329
|
+
}, autoDisableTimeout)), window.sentience_stopRecording = stopRecording, stopRecording;
|
|
1330
|
+
}
|
|
1331
|
+
function showOverlay(elements, targetElementId = null) {
|
|
1332
|
+
if (!elements || "object" != typeof elements || "number" != typeof elements.length) return;
|
|
1333
|
+
const elementsArray = Array.isArray(elements) ? elements : Array.from(elements);
|
|
1334
|
+
window.postMessage({
|
|
1335
|
+
type: "SENTIENCE_SHOW_OVERLAY",
|
|
1336
|
+
elements: elementsArray,
|
|
1337
|
+
targetElementId: targetElementId,
|
|
1338
|
+
timestamp: Date.now()
|
|
1339
|
+
}, "*");
|
|
1340
|
+
}
|
|
1341
|
+
function showGrid(grids, targetGridId = null) {
|
|
1342
|
+
if (!grids || "object" != typeof grids || "number" != typeof grids.length) return;
|
|
1343
|
+
const gridsArray = Array.isArray(grids) ? grids : Array.from(grids);
|
|
1344
|
+
window.postMessage({
|
|
1345
|
+
type: "SENTIENCE_SHOW_GRID_OVERLAY",
|
|
1346
|
+
grids: gridsArray,
|
|
1347
|
+
targetGridId: targetGridId,
|
|
1348
|
+
timestamp: Date.now()
|
|
1349
|
+
}, "*");
|
|
1350
|
+
}
|
|
1351
|
+
function clearOverlay() {
|
|
1352
|
+
window.postMessage({
|
|
1353
|
+
type: "SENTIENCE_CLEAR_OVERLAY"
|
|
1354
|
+
}, "*");
|
|
1355
|
+
}
|
|
1356
|
+
(async () => {
|
|
1357
|
+
const getExtensionId = () => document.documentElement.dataset.sentienceExtensionId;
|
|
1358
|
+
let extId = getExtensionId();
|
|
1359
|
+
extId || await new Promise(resolve => {
|
|
1360
|
+
const check = setInterval(() => {
|
|
1361
|
+
extId = getExtensionId(), extId && (clearInterval(check), resolve());
|
|
1362
|
+
}, 50);
|
|
1363
|
+
setTimeout(() => resolve(), 5e3);
|
|
1364
|
+
}), extId && (window.sentience_registry = [], window.sentience = {
|
|
1365
|
+
snapshot: snapshot,
|
|
1366
|
+
read: read,
|
|
1367
|
+
findTextRect: findTextRect,
|
|
1368
|
+
click: click,
|
|
1369
|
+
startRecording: startRecording,
|
|
1370
|
+
showOverlay: showOverlay,
|
|
1371
|
+
showGrid: showGrid,
|
|
1372
|
+
clearOverlay: clearOverlay
|
|
1373
|
+
}, window.sentience_iframe_handler_setup || (window.addEventListener("message", async event => {
|
|
1374
|
+
if ("SENTIENCE_IFRAME_SNAPSHOT_REQUEST" === event.data?.type) {
|
|
1375
|
+
const {requestId: requestId, options: options} = event.data;
|
|
1376
|
+
try {
|
|
1377
|
+
const snapshotOptions = {
|
|
1378
|
+
...options,
|
|
1379
|
+
collectIframes: !0,
|
|
1380
|
+
waitForStability: (options.waitForStability, !1)
|
|
1381
|
+
}, snapshot = await window.sentience.snapshot(snapshotOptions);
|
|
1382
|
+
event.source && event.source.postMessage && event.source.postMessage({
|
|
1383
|
+
type: "SENTIENCE_IFRAME_SNAPSHOT_RESPONSE",
|
|
1384
|
+
requestId: requestId,
|
|
1385
|
+
snapshot: snapshot,
|
|
1386
|
+
error: null
|
|
1387
|
+
}, "*");
|
|
1388
|
+
} catch (error) {
|
|
1389
|
+
event.source && event.source.postMessage && event.source.postMessage({
|
|
1390
|
+
type: "SENTIENCE_IFRAME_SNAPSHOT_RESPONSE",
|
|
1391
|
+
requestId: requestId,
|
|
1392
|
+
snapshot: null,
|
|
1393
|
+
error: error.message
|
|
1394
|
+
}, "*");
|
|
1395
|
+
}
|
|
1396
|
+
}
|
|
1397
|
+
}), window.sentience_iframe_handler_setup = !0));
|
|
1398
|
+
})();
|
|
1399
|
+
}();
|