stagehand 4.1.0a0.dev1499__tar.gz → 4.2.0__tar.gz
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.
- {stagehand-4.1.0a0.dev1499 → stagehand-4.2.0}/PKG-INFO +16 -2
- {stagehand-4.1.0a0.dev1499 → stagehand-4.2.0}/pyproject.toml +40 -8
- {stagehand-4.1.0a0.dev1499 → stagehand-4.2.0}/src/stagehand/__init__.py +15 -1
- {stagehand-4.1.0a0.dev1499 → stagehand-4.2.0}/src/stagehand/_extension/content-script.js +106 -91
- {stagehand-4.1.0a0.dev1499 → stagehand-4.2.0}/src/stagehand/_extension/manifest.json +1 -1
- {stagehand-4.1.0a0.dev1499 → stagehand-4.2.0}/src/stagehand/_extension/service-worker.js +2456 -1439
- {stagehand-4.1.0a0.dev1499 → stagehand-4.2.0}/src/stagehand/_generated/input_types.py +93 -11
- {stagehand-4.1.0a0.dev1499 → stagehand-4.2.0}/src/stagehand/_generated/models.py +150 -12
- {stagehand-4.1.0a0.dev1499 → stagehand-4.2.0}/src/stagehand/_generated/protocol_version.py +1 -1
- {stagehand-4.1.0a0.dev1499 → stagehand-4.2.0}/src/stagehand/_validation.py +3 -1
- {stagehand-4.1.0a0.dev1499 → stagehand-4.2.0}/src/stagehand/browser.py +51 -16
- {stagehand-4.1.0a0.dev1499 → stagehand-4.2.0}/src/stagehand/browserbase_session.py +40 -18
- {stagehand-4.1.0a0.dev1499 → stagehand-4.2.0}/src/stagehand/cdp_client.py +52 -12
- {stagehand-4.1.0a0.dev1499 → stagehand-4.2.0}/src/stagehand/client_models.py +18 -3
- {stagehand-4.1.0a0.dev1499 → stagehand-4.2.0}/src/stagehand/client_types.py +17 -0
- {stagehand-4.1.0a0.dev1499 → stagehand-4.2.0}/src/stagehand/locator.py +62 -33
- {stagehand-4.1.0a0.dev1499 → stagehand-4.2.0}/src/stagehand/page.py +128 -11
- {stagehand-4.1.0a0.dev1499 → stagehand-4.2.0}/src/stagehand/rpc_client.py +25 -5
- {stagehand-4.1.0a0.dev1499 → stagehand-4.2.0}/README.md +0 -0
- {stagehand-4.1.0a0.dev1499 → stagehand-4.2.0}/src/stagehand/_extension/blank.html +0 -0
- {stagehand-4.1.0a0.dev1499 → stagehand-4.2.0}/src/stagehand/_extension/offscreen/service-worker-heartbeat.html +0 -0
- {stagehand-4.1.0a0.dev1499 → stagehand-4.2.0}/src/stagehand/_extension/offscreen/service-worker-heartbeat.js +0 -0
- {stagehand-4.1.0a0.dev1499 → stagehand-4.2.0}/src/stagehand/_extension/wake-service-worker.html +0 -0
- {stagehand-4.1.0a0.dev1499 → stagehand-4.2.0}/src/stagehand/_extension/wake-service-worker.js +0 -0
- {stagehand-4.1.0a0.dev1499 → stagehand-4.2.0}/src/stagehand/_generated/__init__.py +0 -0
- {stagehand-4.1.0a0.dev1499 → stagehand-4.2.0}/src/stagehand/_sdk_identity.py +0 -0
- {stagehand-4.1.0a0.dev1499 → stagehand-4.2.0}/src/stagehand/browser_clipboard.py +0 -0
- {stagehand-4.1.0a0.dev1499 → stagehand-4.2.0}/src/stagehand/browser_context.py +0 -0
- {stagehand-4.1.0a0.dev1499 → stagehand-4.2.0}/src/stagehand/browserbase_services.py +0 -0
- {stagehand-4.1.0a0.dev1499 → stagehand-4.2.0}/src/stagehand/extension_assets.py +0 -0
- {stagehand-4.1.0a0.dev1499 → stagehand-4.2.0}/src/stagehand/file_upload.py +0 -0
- {stagehand-4.1.0a0.dev1499 → stagehand-4.2.0}/src/stagehand/py.typed +0 -0
- {stagehand-4.1.0a0.dev1499 → stagehand-4.2.0}/src/stagehand/response.py +0 -0
- {stagehand-4.1.0a0.dev1499 → stagehand-4.2.0}/src/stagehand/stagehand.py +0 -0
- {stagehand-4.1.0a0.dev1499 → stagehand-4.2.0}/src/stagehand/timeouts.py +0 -0
- {stagehand-4.1.0a0.dev1499 → stagehand-4.2.0}/src/stagehand/webmcp.py +0 -0
|
@@ -1,13 +1,27 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: stagehand
|
|
3
|
-
Version: 4.
|
|
3
|
+
Version: 4.2.0
|
|
4
4
|
Summary: Browserbase's SDK for building browser agents
|
|
5
|
-
Keywords: ai,browser,automation,web-scraping,testing
|
|
5
|
+
Keywords: ai,agent,ai-agent,browser,browser-agent,browser-automation,computer-use,headless,playwright,cdp,llm,automation,web-scraping,testing
|
|
6
6
|
Author: Browserbase
|
|
7
7
|
License-Expression: MIT
|
|
8
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Topic :: Internet :: WWW/HTTP :: Browsers
|
|
15
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
16
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
17
|
+
Classifier: Topic :: Software Development :: Testing
|
|
18
|
+
Classifier: Typing :: Typed
|
|
19
|
+
Classifier: Framework :: AsyncIO
|
|
8
20
|
Requires-Dist: browserbase>=1.15,<2
|
|
21
|
+
Requires-Dist: httpx>=0.23,<1
|
|
9
22
|
Requires-Dist: opentelemetry-api>=1.35,<2
|
|
10
23
|
Requires-Dist: pydantic>=2.12,<3
|
|
24
|
+
Requires-Dist: typing-extensions>=4.12,<5
|
|
11
25
|
Requires-Dist: websockets>=16.1.1
|
|
12
26
|
Requires-Python: >=3.11
|
|
13
27
|
Project-URL: Homepage, https://stagehand.dev
|
|
@@ -1,18 +1,49 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "stagehand"
|
|
3
|
-
version = "4.
|
|
3
|
+
version = "4.2.0"
|
|
4
4
|
description = "Browserbase's SDK for building browser agents"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.11"
|
|
7
7
|
dependencies = [
|
|
8
8
|
"browserbase>=1.15,<2",
|
|
9
|
+
"httpx>=0.23,<1",
|
|
9
10
|
"opentelemetry-api>=1.35,<2",
|
|
10
11
|
"pydantic>=2.12,<3",
|
|
12
|
+
"typing_extensions>=4.12,<5",
|
|
11
13
|
"websockets>=16.1.1",
|
|
12
14
|
]
|
|
13
15
|
license = "MIT"
|
|
14
16
|
authors = [{ name = "Browserbase" }]
|
|
15
|
-
keywords = [
|
|
17
|
+
keywords = [
|
|
18
|
+
"ai",
|
|
19
|
+
"agent",
|
|
20
|
+
"ai-agent",
|
|
21
|
+
"browser",
|
|
22
|
+
"browser-agent",
|
|
23
|
+
"browser-automation",
|
|
24
|
+
"computer-use",
|
|
25
|
+
"headless",
|
|
26
|
+
"playwright",
|
|
27
|
+
"cdp",
|
|
28
|
+
"llm",
|
|
29
|
+
"automation",
|
|
30
|
+
"web-scraping",
|
|
31
|
+
"testing",
|
|
32
|
+
]
|
|
33
|
+
classifiers = [
|
|
34
|
+
"Development Status :: 5 - Production/Stable",
|
|
35
|
+
"Intended Audience :: Developers",
|
|
36
|
+
"Operating System :: OS Independent",
|
|
37
|
+
"Programming Language :: Python :: 3",
|
|
38
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
39
|
+
"Programming Language :: Python :: 3.11",
|
|
40
|
+
"Topic :: Internet :: WWW/HTTP :: Browsers",
|
|
41
|
+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
42
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
43
|
+
"Topic :: Software Development :: Testing",
|
|
44
|
+
"Typing :: Typed",
|
|
45
|
+
"Framework :: AsyncIO",
|
|
46
|
+
]
|
|
16
47
|
|
|
17
48
|
[project.urls]
|
|
18
49
|
Homepage = "https://stagehand.dev"
|
|
@@ -39,12 +70,13 @@ select = ["ANN", "E", "F", "I", "PYI", "UP"]
|
|
|
39
70
|
[tool.ty.environment]
|
|
40
71
|
python-version = "3.11"
|
|
41
72
|
|
|
42
|
-
[tool.ty.src]
|
|
43
|
-
exclude = ["src/stagehand/_generated"]
|
|
44
|
-
|
|
45
73
|
[tool.ty.rules]
|
|
46
74
|
missing-type-argument = "error"
|
|
47
|
-
possibly-unresolved-reference = "
|
|
75
|
+
possibly-unresolved-reference = "error"
|
|
76
|
+
unsound-return-statement = "error"
|
|
77
|
+
dynamic-function-decorator-return = "error"
|
|
78
|
+
missing-override-decorator = "error"
|
|
79
|
+
unused-ignore-comment = "error"
|
|
48
80
|
|
|
49
81
|
[tool.pytest.ini_options]
|
|
50
82
|
asyncio_mode = "auto"
|
|
@@ -55,8 +87,8 @@ strict = true
|
|
|
55
87
|
dev = [
|
|
56
88
|
"datamodel-code-generator==0.68.1",
|
|
57
89
|
"openai>=2,<3",
|
|
58
|
-
"pytest==9.0.
|
|
90
|
+
"pytest==9.0.3",
|
|
59
91
|
"pytest-asyncio==1.3.0",
|
|
60
92
|
"ruff==0.15.7",
|
|
61
|
-
"ty==0.0.
|
|
93
|
+
"ty==0.0.82",
|
|
62
94
|
]
|
|
@@ -11,6 +11,7 @@ from ._generated.input_types import (
|
|
|
11
11
|
ModelConfig,
|
|
12
12
|
PageDragAndDropRoutePoint,
|
|
13
13
|
PageEventName,
|
|
14
|
+
PagePDFMargin,
|
|
14
15
|
PageScreenshotClip,
|
|
15
16
|
RgbaColor,
|
|
16
17
|
TelemetryConfig,
|
|
@@ -67,6 +68,7 @@ from .client_models import (
|
|
|
67
68
|
ExtractResult,
|
|
68
69
|
)
|
|
69
70
|
from .client_types import (
|
|
71
|
+
BrowserbaseClientOptions,
|
|
70
72
|
CacheOptions,
|
|
71
73
|
LLMGenerateCallback,
|
|
72
74
|
LLMGenerateInput,
|
|
@@ -75,7 +77,14 @@ from .client_types import (
|
|
|
75
77
|
)
|
|
76
78
|
from .file_upload import FileInput, FilePayload
|
|
77
79
|
from .locator import Locator
|
|
78
|
-
from .page import
|
|
80
|
+
from .page import (
|
|
81
|
+
CDPSubscription,
|
|
82
|
+
Page,
|
|
83
|
+
PageEventListener,
|
|
84
|
+
ToolsAddedListener,
|
|
85
|
+
ToolsRemovedListener,
|
|
86
|
+
WebMCPToolIdentity,
|
|
87
|
+
)
|
|
79
88
|
from .response import Response
|
|
80
89
|
from .stagehand import Stagehand
|
|
81
90
|
from .webmcp import (
|
|
@@ -94,6 +103,7 @@ __all__ = [
|
|
|
94
103
|
"BrowserClipboard",
|
|
95
104
|
"BrowserContext",
|
|
96
105
|
"BrowserbaseBrowserSettings",
|
|
106
|
+
"BrowserbaseClientOptions",
|
|
97
107
|
"BrowserbaseFetchResult",
|
|
98
108
|
"BrowserbaseProxyConfig",
|
|
99
109
|
"BrowserbaseRegion",
|
|
@@ -136,7 +146,11 @@ __all__ = [
|
|
|
136
146
|
"PageCDPEvent",
|
|
137
147
|
"PageDragAndDropRoutePoint",
|
|
138
148
|
"PageEventListener",
|
|
149
|
+
"ToolsAddedListener",
|
|
150
|
+
"ToolsRemovedListener",
|
|
151
|
+
"WebMCPToolIdentity",
|
|
139
152
|
"PageEventName",
|
|
153
|
+
"PagePDFMargin",
|
|
140
154
|
"PageScreenshotClip",
|
|
141
155
|
"ProtocolLocator",
|
|
142
156
|
"RgbaColor",
|
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
* - Attribute equality predicates (`[@attr='value']`, `[@attr="value"]`)
|
|
13
13
|
* - Attribute existence (`[@attr]`)
|
|
14
14
|
* - Attribute contains/starts-with (`contains(@attr,'v')`, `starts-with(@attr,'v')`)
|
|
15
|
-
* - Text equality/contains (`[text()='v']`, `[contains(text(),'v')]`, `[.='v']`)
|
|
15
|
+
* - Text equality/contains (`[text()='v']`, `[contains(text(),'v')]`, `[.='v']`),
|
|
16
|
+
* where `text()` reads direct child text nodes and `.` the whole subtree
|
|
16
17
|
* - normalize-space on text/attributes (`[normalize-space(text())='v']`)
|
|
17
18
|
* - Basic boolean predicates (`and`, `or`, `not(...)`)
|
|
18
19
|
* - Multiple predicates per step (`[@class='foo'][2]`)
|
|
@@ -159,11 +160,12 @@ function parseAtomicPredicate(input) {
|
|
|
159
160
|
value: normalizeAttrMatch[2] ?? normalizeAttrMatch[3] ?? "",
|
|
160
161
|
normalize: true
|
|
161
162
|
};
|
|
162
|
-
const normalizeTextMatch = input.match(new RegExp(`^normalize-space\\(\\s*(
|
|
163
|
+
const normalizeTextMatch = input.match(new RegExp(`^normalize-space\\(\\s*(text\\(\\)|\\.)\\s*\\)\\s*=\\s*${quoted}$`));
|
|
163
164
|
if (normalizeTextMatch) return {
|
|
164
165
|
type: "textEquals",
|
|
165
|
-
value: normalizeTextMatch[
|
|
166
|
-
normalize: true
|
|
166
|
+
value: normalizeTextMatch[2] ?? normalizeTextMatch[3] ?? "",
|
|
167
|
+
normalize: true,
|
|
168
|
+
source: textSource(normalizeTextMatch[1])
|
|
167
169
|
};
|
|
168
170
|
const attrEqualsMatch = input.match(new RegExp(`^@(${attrName})\\s*=\\s*${quoted}$`));
|
|
169
171
|
if (attrEqualsMatch) return {
|
|
@@ -188,15 +190,17 @@ function parseAtomicPredicate(input) {
|
|
|
188
190
|
name: attrStartsMatch[1],
|
|
189
191
|
value: attrStartsMatch[2] ?? attrStartsMatch[3] ?? ""
|
|
190
192
|
};
|
|
191
|
-
const textEqualsMatch = input.match(new RegExp(`^(
|
|
193
|
+
const textEqualsMatch = input.match(new RegExp(`^(text\\(\\)|\\.)\\s*=\\s*${quoted}$`));
|
|
192
194
|
if (textEqualsMatch) return {
|
|
193
195
|
type: "textEquals",
|
|
194
|
-
value: textEqualsMatch[
|
|
196
|
+
value: textEqualsMatch[2] ?? textEqualsMatch[3] ?? "",
|
|
197
|
+
source: textSource(textEqualsMatch[1])
|
|
195
198
|
};
|
|
196
|
-
const textContainsMatch = input.match(new RegExp(`^contains\\(\\s*(
|
|
199
|
+
const textContainsMatch = input.match(new RegExp(`^contains\\(\\s*(text\\(\\)|\\.)\\s*,\\s*${quoted}\\s*\\)$`));
|
|
197
200
|
if (textContainsMatch) return {
|
|
198
201
|
type: "textContains",
|
|
199
|
-
value: textContainsMatch[
|
|
202
|
+
value: textContainsMatch[2] ?? textContainsMatch[3] ?? "",
|
|
203
|
+
source: textSource(textContainsMatch[1])
|
|
200
204
|
};
|
|
201
205
|
if (valueMatch.test(input)) return null;
|
|
202
206
|
return null;
|
|
@@ -276,9 +280,23 @@ function hasBalancedParens(input) {
|
|
|
276
280
|
return depth === 0;
|
|
277
281
|
}
|
|
278
282
|
var normalizeSpace = (value) => value.replace(/\s+/g, " ").trim();
|
|
283
|
+
var TEXT_NODE = 3;
|
|
284
|
+
function textSource(token) {
|
|
285
|
+
return token === "text()" ? "text" : "self";
|
|
286
|
+
}
|
|
279
287
|
function textValue(element) {
|
|
280
288
|
return String(element.textContent ?? "");
|
|
281
289
|
}
|
|
290
|
+
/** The node-set `text()` selects: direct child text nodes, in document order. */
|
|
291
|
+
function childTextValues(element) {
|
|
292
|
+
const values = [];
|
|
293
|
+
for (const node of Array.from(element.childNodes)) if (node.nodeType === TEXT_NODE) values.push(String(node.nodeValue ?? ""));
|
|
294
|
+
return values;
|
|
295
|
+
}
|
|
296
|
+
/** `string(node-set)` is the string-value of its first node, or `""` when empty. */
|
|
297
|
+
function firstChildTextValue(element) {
|
|
298
|
+
return childTextValues(element)[0] ?? "";
|
|
299
|
+
}
|
|
282
300
|
function normalizeMaybe(value, normalize) {
|
|
283
301
|
return normalize ? normalizeSpace(value) : value;
|
|
284
302
|
}
|
|
@@ -303,8 +321,12 @@ function evaluatePredicate(element, predicate) {
|
|
|
303
321
|
if (attr === null) return false;
|
|
304
322
|
return normalizeMaybe(attr, predicate.normalize).startsWith(normalizeMaybe(predicate.value, predicate.normalize));
|
|
305
323
|
}
|
|
306
|
-
case "textEquals":
|
|
307
|
-
|
|
324
|
+
case "textEquals": {
|
|
325
|
+
const target = normalizeMaybe(predicate.value, predicate.normalize);
|
|
326
|
+
if (predicate.source === "text") return predicate.normalize ? normalizeSpace(firstChildTextValue(element)) === target : childTextValues(element).some((value) => value === target);
|
|
327
|
+
return normalizeMaybe(textValue(element), predicate.normalize) === target;
|
|
328
|
+
}
|
|
329
|
+
case "textContains": return normalizeMaybe(predicate.source === "text" ? firstChildTextValue(element) : textValue(element), predicate.normalize).includes(normalizeMaybe(predicate.value, predicate.normalize));
|
|
308
330
|
case "index": return true;
|
|
309
331
|
default: return true;
|
|
310
332
|
}
|
|
@@ -968,7 +990,7 @@ var checkState = (el, state) => {
|
|
|
968
990
|
/**
|
|
969
991
|
* Set up MutationObservers on all shadow roots to detect changes.
|
|
970
992
|
*/
|
|
971
|
-
var setupShadowObservers = (callback, observers) => {
|
|
993
|
+
var setupShadowObservers = (callback, observers, isSettled) => {
|
|
972
994
|
const seenRoots = /* @__PURE__ */ new WeakSet();
|
|
973
995
|
const observeShadowRoots = (node) => {
|
|
974
996
|
const shadowRoot = getOpenOrClosedShadowRoot(node);
|
|
@@ -978,6 +1000,7 @@ var setupShadowObservers = (callback, observers) => {
|
|
|
978
1000
|
callback();
|
|
979
1001
|
scan();
|
|
980
1002
|
});
|
|
1003
|
+
observers.push(shadowObserver);
|
|
981
1004
|
shadowObserver.observe(shadowRoot, {
|
|
982
1005
|
childList: true,
|
|
983
1006
|
subtree: true,
|
|
@@ -989,14 +1012,13 @@ var setupShadowObservers = (callback, observers) => {
|
|
|
989
1012
|
"disabled"
|
|
990
1013
|
]
|
|
991
1014
|
});
|
|
992
|
-
observers.push(shadowObserver);
|
|
993
1015
|
for (const child of Array.from(shadowRoot.children)) observeShadowRoots(child);
|
|
994
1016
|
}
|
|
995
1017
|
for (const child of Array.from(node.children)) observeShadowRoots(child);
|
|
996
1018
|
};
|
|
997
1019
|
const root = document.documentElement || document.body;
|
|
998
1020
|
const scan = () => {
|
|
999
|
-
if (root) observeShadowRoots(root);
|
|
1021
|
+
if (!isSettled() && root) observeShadowRoots(root);
|
|
1000
1022
|
};
|
|
1001
1023
|
scan();
|
|
1002
1024
|
return scan;
|
|
@@ -1007,106 +1029,99 @@ var setupShadowObservers = (callback, observers) => {
|
|
|
1007
1029
|
*
|
|
1008
1030
|
* @param selectorRaw - CSS selector or XPath expression to wait for
|
|
1009
1031
|
* @param stateRaw - Element state: 'attached' | 'detached' | 'visible' | 'hidden'
|
|
1010
|
-
* @param timeoutRaw - Maximum time to wait in milliseconds
|
|
1032
|
+
* @param timeoutRaw - Maximum time to wait in milliseconds; defaults to 30,000, zero is unlimited
|
|
1011
1033
|
* @param pierceShadowRaw - Whether to search inside shadow DOM
|
|
1012
|
-
* @returns
|
|
1034
|
+
* @returns A disposable handle whose promise resolves when the condition is met
|
|
1013
1035
|
*/
|
|
1014
|
-
function
|
|
1036
|
+
function createSelectorWait(selectorRaw, stateRaw, timeoutRaw, pierceShadowRaw) {
|
|
1015
1037
|
const selector = String(selectorRaw ?? "").trim();
|
|
1016
1038
|
const state = String(stateRaw ?? "visible") || "visible";
|
|
1017
|
-
const timeout = typeof timeoutRaw === "number" && timeoutRaw
|
|
1039
|
+
const timeout = typeof timeoutRaw === "number" && timeoutRaw >= 0 ? timeoutRaw : 3e4;
|
|
1018
1040
|
const pierceShadow = pierceShadowRaw !== false;
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
let domReadyHandler = null;
|
|
1041
|
+
let dispose = () => {};
|
|
1042
|
+
const promise = new Promise((resolve, reject) => {
|
|
1022
1043
|
let settled = false;
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
}
|
|
1028
|
-
};
|
|
1029
|
-
if (checkState(findElement(selector, pierceShadow), state)) {
|
|
1030
|
-
settled = true;
|
|
1031
|
-
resolve(true);
|
|
1032
|
-
return;
|
|
1033
|
-
}
|
|
1044
|
+
let timeoutId;
|
|
1045
|
+
let shadowScanInterval;
|
|
1046
|
+
let domReadyHandler;
|
|
1047
|
+
let rescanShadowRoots;
|
|
1034
1048
|
const observers = [];
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1049
|
+
const settle = (error) => {
|
|
1050
|
+
if (settled) return;
|
|
1051
|
+
settled = true;
|
|
1052
|
+
clearTimeout(timeoutId);
|
|
1053
|
+
clearInterval(shadowScanInterval);
|
|
1054
|
+
for (const observer of observers) observer.disconnect();
|
|
1055
|
+
observers.length = 0;
|
|
1056
|
+
rescanShadowRoots = void 0;
|
|
1043
1057
|
if (domReadyHandler) {
|
|
1044
1058
|
document.removeEventListener("DOMContentLoaded", domReadyHandler);
|
|
1045
|
-
domReadyHandler =
|
|
1059
|
+
domReadyHandler = void 0;
|
|
1046
1060
|
}
|
|
1061
|
+
if (error) reject(error);
|
|
1062
|
+
else resolve(true);
|
|
1047
1063
|
};
|
|
1064
|
+
dispose = () => settle(/* @__PURE__ */ new Error("Selector wait disposed"));
|
|
1048
1065
|
const check = () => {
|
|
1049
1066
|
if (settled) return;
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
resolve(true);
|
|
1067
|
+
try {
|
|
1068
|
+
if (checkState(findElement(selector, pierceShadow), state)) settle();
|
|
1069
|
+
} catch (error) {
|
|
1070
|
+
settle(error instanceof Error ? error : new Error(String(error)));
|
|
1055
1071
|
}
|
|
1056
1072
|
};
|
|
1057
|
-
|
|
1073
|
+
const setupObservers = () => {
|
|
1074
|
+
if (settled) return;
|
|
1075
|
+
const root = document.body || document.documentElement;
|
|
1076
|
+
if (!root) return;
|
|
1077
|
+
try {
|
|
1078
|
+
const mainObserver = new MutationObserver(() => {
|
|
1079
|
+
check();
|
|
1080
|
+
rescanShadowRoots?.();
|
|
1081
|
+
});
|
|
1082
|
+
observers.push(mainObserver);
|
|
1083
|
+
mainObserver.observe(root, {
|
|
1084
|
+
childList: true,
|
|
1085
|
+
subtree: true,
|
|
1086
|
+
attributes: true,
|
|
1087
|
+
attributeFilter: [
|
|
1088
|
+
"style",
|
|
1089
|
+
"class",
|
|
1090
|
+
"hidden",
|
|
1091
|
+
"disabled"
|
|
1092
|
+
]
|
|
1093
|
+
});
|
|
1094
|
+
if (pierceShadow) {
|
|
1095
|
+
rescanShadowRoots = setupShadowObservers(check, observers, () => settled);
|
|
1096
|
+
shadowScanInterval = setInterval(() => {
|
|
1097
|
+
rescanShadowRoots?.();
|
|
1098
|
+
check();
|
|
1099
|
+
}, 100);
|
|
1100
|
+
}
|
|
1101
|
+
} catch (error) {
|
|
1102
|
+
settle(error instanceof Error ? error : new Error(String(error)));
|
|
1103
|
+
}
|
|
1104
|
+
};
|
|
1105
|
+
check();
|
|
1106
|
+
if (settled) return;
|
|
1107
|
+
if (document.body || document.documentElement) setupObservers();
|
|
1108
|
+
else {
|
|
1058
1109
|
domReadyHandler = () => {
|
|
1110
|
+
if (settled) return;
|
|
1059
1111
|
document.removeEventListener("DOMContentLoaded", domReadyHandler);
|
|
1060
|
-
domReadyHandler =
|
|
1112
|
+
domReadyHandler = void 0;
|
|
1061
1113
|
check();
|
|
1062
1114
|
setupObservers();
|
|
1063
1115
|
};
|
|
1064
1116
|
document.addEventListener("DOMContentLoaded", domReadyHandler);
|
|
1065
|
-
timeoutId = setTimeout(() => {
|
|
1066
|
-
if (settled) return;
|
|
1067
|
-
settled = true;
|
|
1068
|
-
clearTimer();
|
|
1069
|
-
cleanup();
|
|
1070
|
-
reject(/* @__PURE__ */ new Error(`waitForSelector: Timeout ${timeout}ms exceeded waiting for "${selector}" to be ${state}`));
|
|
1071
|
-
}, timeout);
|
|
1072
|
-
return;
|
|
1073
1117
|
}
|
|
1074
|
-
|
|
1075
|
-
const root = document.body || document.documentElement;
|
|
1076
|
-
if (!root) return;
|
|
1077
|
-
const mainObserver = new MutationObserver(() => {
|
|
1078
|
-
check();
|
|
1079
|
-
rescanShadowRoots?.();
|
|
1080
|
-
});
|
|
1081
|
-
mainObserver.observe(root, {
|
|
1082
|
-
childList: true,
|
|
1083
|
-
subtree: true,
|
|
1084
|
-
attributes: true,
|
|
1085
|
-
attributeFilter: [
|
|
1086
|
-
"style",
|
|
1087
|
-
"class",
|
|
1088
|
-
"hidden",
|
|
1089
|
-
"disabled"
|
|
1090
|
-
]
|
|
1091
|
-
});
|
|
1092
|
-
observers.push(mainObserver);
|
|
1093
|
-
if (pierceShadow) {
|
|
1094
|
-
rescanShadowRoots = setupShadowObservers(check, observers);
|
|
1095
|
-
shadowScanInterval = setInterval(() => {
|
|
1096
|
-
rescanShadowRoots?.();
|
|
1097
|
-
check();
|
|
1098
|
-
}, 100);
|
|
1099
|
-
}
|
|
1100
|
-
};
|
|
1101
|
-
setupObservers();
|
|
1102
|
-
timeoutId = setTimeout(() => {
|
|
1103
|
-
if (settled) return;
|
|
1104
|
-
settled = true;
|
|
1105
|
-
clearTimer();
|
|
1106
|
-
cleanup();
|
|
1107
|
-
reject(/* @__PURE__ */ new Error(`waitForSelector: Timeout ${timeout}ms exceeded waiting for "${selector}" to be ${state}`));
|
|
1108
|
-
}, timeout);
|
|
1118
|
+
if (!settled && timeout > 0) timeoutId = setTimeout(() => settle(/* @__PURE__ */ new Error(`waitForSelector: Timeout ${timeout}ms exceeded waiting for "${selector}" to be ${state}`)), timeout);
|
|
1109
1119
|
});
|
|
1120
|
+
promise.catch(() => {});
|
|
1121
|
+
return {
|
|
1122
|
+
promise,
|
|
1123
|
+
dispose: () => dispose()
|
|
1124
|
+
};
|
|
1110
1125
|
}
|
|
1111
1126
|
//#endregion
|
|
1112
1127
|
//#region dom/locatorScripts/registry.ts
|
|
@@ -1120,7 +1135,7 @@ var locatorScripts = Object.freeze({
|
|
|
1120
1135
|
resolveCssSelector,
|
|
1121
1136
|
resolveTextSelector,
|
|
1122
1137
|
resolveXPathMainWorld,
|
|
1123
|
-
|
|
1138
|
+
createSelectorWait
|
|
1124
1139
|
});
|
|
1125
1140
|
//#endregion
|
|
1126
1141
|
//#region content-script.ts
|