stagehand 4.2.0a0.dev1560__tar.gz → 4.2.0a0.dev1562__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.2.0a0.dev1560 → stagehand-4.2.0a0.dev1562}/PKG-INFO +1 -1
- {stagehand-4.2.0a0.dev1560 → stagehand-4.2.0a0.dev1562}/pyproject.toml +1 -1
- {stagehand-4.2.0a0.dev1560 → stagehand-4.2.0a0.dev1562}/src/stagehand/_extension/service-worker.js +187 -128
- {stagehand-4.2.0a0.dev1560 → stagehand-4.2.0a0.dev1562}/src/stagehand/_generated/input_types.py +1 -0
- {stagehand-4.2.0a0.dev1560 → stagehand-4.2.0a0.dev1562}/src/stagehand/_generated/models.py +2 -0
- {stagehand-4.2.0a0.dev1560 → stagehand-4.2.0a0.dev1562}/src/stagehand/_generated/protocol_version.py +1 -1
- {stagehand-4.2.0a0.dev1560 → stagehand-4.2.0a0.dev1562}/src/stagehand/page.py +10 -3
- {stagehand-4.2.0a0.dev1560 → stagehand-4.2.0a0.dev1562}/src/stagehand/rpc_client.py +3 -2
- {stagehand-4.2.0a0.dev1560 → stagehand-4.2.0a0.dev1562}/README.md +0 -0
- {stagehand-4.2.0a0.dev1560 → stagehand-4.2.0a0.dev1562}/src/stagehand/__init__.py +0 -0
- {stagehand-4.2.0a0.dev1560 → stagehand-4.2.0a0.dev1562}/src/stagehand/_extension/blank.html +0 -0
- {stagehand-4.2.0a0.dev1560 → stagehand-4.2.0a0.dev1562}/src/stagehand/_extension/content-script.js +0 -0
- {stagehand-4.2.0a0.dev1560 → stagehand-4.2.0a0.dev1562}/src/stagehand/_extension/manifest.json +0 -0
- {stagehand-4.2.0a0.dev1560 → stagehand-4.2.0a0.dev1562}/src/stagehand/_extension/offscreen/service-worker-heartbeat.html +0 -0
- {stagehand-4.2.0a0.dev1560 → stagehand-4.2.0a0.dev1562}/src/stagehand/_extension/offscreen/service-worker-heartbeat.js +0 -0
- {stagehand-4.2.0a0.dev1560 → stagehand-4.2.0a0.dev1562}/src/stagehand/_extension/wake-service-worker.html +0 -0
- {stagehand-4.2.0a0.dev1560 → stagehand-4.2.0a0.dev1562}/src/stagehand/_extension/wake-service-worker.js +0 -0
- {stagehand-4.2.0a0.dev1560 → stagehand-4.2.0a0.dev1562}/src/stagehand/_generated/__init__.py +0 -0
- {stagehand-4.2.0a0.dev1560 → stagehand-4.2.0a0.dev1562}/src/stagehand/_sdk_identity.py +0 -0
- {stagehand-4.2.0a0.dev1560 → stagehand-4.2.0a0.dev1562}/src/stagehand/_validation.py +0 -0
- {stagehand-4.2.0a0.dev1560 → stagehand-4.2.0a0.dev1562}/src/stagehand/browser.py +0 -0
- {stagehand-4.2.0a0.dev1560 → stagehand-4.2.0a0.dev1562}/src/stagehand/browser_clipboard.py +0 -0
- {stagehand-4.2.0a0.dev1560 → stagehand-4.2.0a0.dev1562}/src/stagehand/browser_context.py +0 -0
- {stagehand-4.2.0a0.dev1560 → stagehand-4.2.0a0.dev1562}/src/stagehand/browserbase_services.py +0 -0
- {stagehand-4.2.0a0.dev1560 → stagehand-4.2.0a0.dev1562}/src/stagehand/browserbase_session.py +0 -0
- {stagehand-4.2.0a0.dev1560 → stagehand-4.2.0a0.dev1562}/src/stagehand/cdp_client.py +0 -0
- {stagehand-4.2.0a0.dev1560 → stagehand-4.2.0a0.dev1562}/src/stagehand/client_models.py +0 -0
- {stagehand-4.2.0a0.dev1560 → stagehand-4.2.0a0.dev1562}/src/stagehand/client_types.py +0 -0
- {stagehand-4.2.0a0.dev1560 → stagehand-4.2.0a0.dev1562}/src/stagehand/extension_assets.py +0 -0
- {stagehand-4.2.0a0.dev1560 → stagehand-4.2.0a0.dev1562}/src/stagehand/file_upload.py +0 -0
- {stagehand-4.2.0a0.dev1560 → stagehand-4.2.0a0.dev1562}/src/stagehand/locator.py +0 -0
- {stagehand-4.2.0a0.dev1560 → stagehand-4.2.0a0.dev1562}/src/stagehand/py.typed +0 -0
- {stagehand-4.2.0a0.dev1560 → stagehand-4.2.0a0.dev1562}/src/stagehand/response.py +0 -0
- {stagehand-4.2.0a0.dev1560 → stagehand-4.2.0a0.dev1562}/src/stagehand/stagehand.py +0 -0
- {stagehand-4.2.0a0.dev1560 → stagehand-4.2.0a0.dev1562}/src/stagehand/timeouts.py +0 -0
- {stagehand-4.2.0a0.dev1560 → stagehand-4.2.0a0.dev1562}/src/stagehand/webmcp.py +0 -0
{stagehand-4.2.0a0.dev1560 → stagehand-4.2.0a0.dev1562}/src/stagehand/_extension/service-worker.js
RENAMED
|
@@ -7363,7 +7363,7 @@ function isRecord$1(value) {
|
|
|
7363
7363
|
}
|
|
7364
7364
|
var package_default$1 = {
|
|
7365
7365
|
name: "@browserbasehq/stagehand-protocol",
|
|
7366
|
-
version: "2.1.0-alpha-
|
|
7366
|
+
version: "2.1.0-alpha-666b6fa32b003420a4a9e641dc47ee4c9a531eff",
|
|
7367
7367
|
"private": true,
|
|
7368
7368
|
type: "module",
|
|
7369
7369
|
exports: {
|
|
@@ -8324,7 +8324,10 @@ var SnapshotResultSchema = strictObject({
|
|
|
8324
8324
|
xpathMap: record(string(), string()),
|
|
8325
8325
|
urlMap: record(string(), string())
|
|
8326
8326
|
}).meta({ id: "SnapshotResult" });
|
|
8327
|
-
var PageSnapshotOptionsSchema = strictObject({
|
|
8327
|
+
var PageSnapshotOptionsSchema = strictObject({
|
|
8328
|
+
timeout: number$1().nonnegative().optional().describe("Milliseconds for the whole snapshot call. Defaults to 20000. Zero disables the timeout."),
|
|
8329
|
+
includeIframes: boolean().optional()
|
|
8330
|
+
}).meta({ id: "PageSnapshotOptions" });
|
|
8328
8331
|
var PageRefSchema = strictObject({
|
|
8329
8332
|
pageId: string(),
|
|
8330
8333
|
url: string().optional(),
|
|
@@ -14073,9 +14076,10 @@ var ExecutionContextRegistry = class {
|
|
|
14073
14076
|
return this.fallbackByFrame.get(session)?.get(frameId) ?? null;
|
|
14074
14077
|
}
|
|
14075
14078
|
/** With progress, timeout limits each extension probe, not the whole wait.
|
|
14076
|
-
*
|
|
14079
|
+
* Callers that handle failure themselves can disable retries without losing
|
|
14080
|
+
* the caller's deadline. Without progress, readiness makes a single attempt.
|
|
14077
14081
|
*/
|
|
14078
|
-
async waitForLocatorWorld(session, frameId, timeout = 1e3, progress,
|
|
14082
|
+
async waitForLocatorWorld(session, frameId, timeout = 1e3, progress, { readinessRetries = "until-deadline" } = {}) {
|
|
14079
14083
|
while (true) {
|
|
14080
14084
|
progress?.throwIfStopped();
|
|
14081
14085
|
const extensionContextId = this.getExtensionWorld(session, frameId);
|
|
@@ -14088,7 +14092,7 @@ var ExecutionContextRegistry = class {
|
|
|
14088
14092
|
progress?.throwIfStopped();
|
|
14089
14093
|
if (progress && isCdpClosedError(extensionError)) throw extensionError;
|
|
14090
14094
|
if (await this.isFallbackEligible(session, frameId, progress)) return this.fallbackWorld(await runLocatorStep(progress, "installing locator helpers", () => this.createFallbackWorld(session, frameId)));
|
|
14091
|
-
if (!progress ||
|
|
14095
|
+
if (!progress || readinessRetries === "none") throw extensionError;
|
|
14092
14096
|
}
|
|
14093
14097
|
}
|
|
14094
14098
|
}
|
|
@@ -14389,8 +14393,9 @@ function buildLocatorInvocation(name, args) {
|
|
|
14389
14393
|
//#endregion
|
|
14390
14394
|
//#region understudy/selectorResolver.ts
|
|
14391
14395
|
var FrameSelectorResolver = class {
|
|
14392
|
-
constructor(frame) {
|
|
14396
|
+
constructor(frame, readinessOptions = {}) {
|
|
14393
14397
|
this.frame = frame;
|
|
14398
|
+
this.readinessOptions = readinessOptions;
|
|
14394
14399
|
}
|
|
14395
14400
|
static parseSelector(raw) {
|
|
14396
14401
|
const trimmed = raw.trim();
|
|
@@ -14466,7 +14471,7 @@ var FrameSelectorResolver = class {
|
|
|
14466
14471
|
async resolveElements(helper, value, limit, progress) {
|
|
14467
14472
|
progress?.throwIfStopped();
|
|
14468
14473
|
if (limit <= 0) return [];
|
|
14469
|
-
const { contextId } = await executionContexts.waitForLocatorWorld(this.frame.session, this.frame.frameId, 1e3, progress);
|
|
14474
|
+
const { contextId } = await executionContexts.waitForLocatorWorld(this.frame.session, this.frame.frameId, 1e3, progress, this.readinessOptions);
|
|
14470
14475
|
const results = [];
|
|
14471
14476
|
try {
|
|
14472
14477
|
for (let index = 0; index < limit; index += 1) {
|
|
@@ -14488,13 +14493,13 @@ var FrameSelectorResolver = class {
|
|
|
14488
14493
|
}
|
|
14489
14494
|
async countCss(selector, progress) {
|
|
14490
14495
|
const session = this.frame.session;
|
|
14491
|
-
const { contextId } = await executionContexts.waitForLocatorWorld(session, this.frame.frameId, 1e3, progress);
|
|
14496
|
+
const { contextId } = await executionContexts.waitForLocatorWorld(session, this.frame.frameId, 1e3, progress, this.readinessOptions);
|
|
14492
14497
|
const primaryExpr = buildLocatorInvocation("countCssMatchesPrimary", [JSON.stringify(selector)]);
|
|
14493
14498
|
return this.evaluateCount(primaryExpr, contextId, progress);
|
|
14494
14499
|
}
|
|
14495
14500
|
async countText(value, progress) {
|
|
14496
14501
|
const session = this.frame.session;
|
|
14497
|
-
const { contextId: ctxId } = await executionContexts.waitForLocatorWorld(session, this.frame.frameId, 1e3, progress);
|
|
14502
|
+
const { contextId: ctxId } = await executionContexts.waitForLocatorWorld(session, this.frame.frameId, 1e3, progress, this.readinessOptions);
|
|
14498
14503
|
const expr = buildLocatorInvocation("countTextMatches", [JSON.stringify(value)]);
|
|
14499
14504
|
try {
|
|
14500
14505
|
const evalRes = await runLocatorStep(progress, "counting elements", () => session.send("Runtime.evaluate", {
|
|
@@ -14525,7 +14530,7 @@ var FrameSelectorResolver = class {
|
|
|
14525
14530
|
}
|
|
14526
14531
|
async countXPath(value, progress) {
|
|
14527
14532
|
const session = this.frame.session;
|
|
14528
|
-
const { contextId: ctxId } = await executionContexts.waitForLocatorWorld(session, this.frame.frameId, 1e3, progress);
|
|
14533
|
+
const { contextId: ctxId } = await executionContexts.waitForLocatorWorld(session, this.frame.frameId, 1e3, progress, this.readinessOptions);
|
|
14529
14534
|
const expr = buildLocatorInvocation("countXPathMatchesMainWorld", [JSON.stringify(value)]);
|
|
14530
14535
|
try {
|
|
14531
14536
|
const evalRes = await runLocatorStep(progress, "counting elements", () => session.send("Runtime.evaluate", {
|
|
@@ -15533,7 +15538,7 @@ async function ensureChildFrameReady(page, childFrameId, budgetMs, progress) {
|
|
|
15533
15538
|
const remaining = progress?.remainingMs() ?? deadline - Date.now();
|
|
15534
15539
|
if (remaining <= 0) break;
|
|
15535
15540
|
try {
|
|
15536
|
-
await executionContexts.waitForLocatorWorld(session, childFrameId, Math.min(remaining, LOCATOR_WORLD_ATTEMPT_TIMEOUT_MS), progress,
|
|
15541
|
+
await executionContexts.waitForLocatorWorld(session, childFrameId, Math.min(remaining, LOCATOR_WORLD_ATTEMPT_TIMEOUT_MS), progress, { readinessRetries: "none" });
|
|
15537
15542
|
progress?.throwIfStopped();
|
|
15538
15543
|
if (page.getSessionForFrame(childFrameId) === session) return;
|
|
15539
15544
|
} catch (error) {
|
|
@@ -15638,7 +15643,8 @@ var IFRAME_STEP_RE = /^i?frame(?:\[\d+])?$/i;
|
|
|
15638
15643
|
* - the tail XPath (within the target frame)
|
|
15639
15644
|
* - the absolute XPath prefix up to the iframe element hosting that frame
|
|
15640
15645
|
*/
|
|
15641
|
-
async function resolveFocusFrameAndTail(page, absoluteXPath, parentByFrame, rootId) {
|
|
15646
|
+
async function resolveFocusFrameAndTail(page, absoluteXPath, parentByFrame, rootId, progress) {
|
|
15647
|
+
progress?.throwIfStopped();
|
|
15642
15648
|
const steps = parseXPathToSteps(absoluteXPath);
|
|
15643
15649
|
let ctxFrameId = rootId;
|
|
15644
15650
|
let buf = [];
|
|
@@ -15647,33 +15653,36 @@ async function resolveFocusFrameAndTail(page, absoluteXPath, parentByFrame, root
|
|
|
15647
15653
|
if (!buf.length) return;
|
|
15648
15654
|
const selectorForIframe = buildXPathFromSteps$1(buf);
|
|
15649
15655
|
const parentSess = page.getSessionForFrame(ctxFrameId);
|
|
15650
|
-
const objectId = await resolveObjectIdForXPath(parentSess, selectorForIframe, ctxFrameId);
|
|
15656
|
+
const objectId = await resolveObjectIdForXPath(parentSess, selectorForIframe, ctxFrameId, 0, progress);
|
|
15651
15657
|
if (!objectId) throw iframeResolutionError(selectorForIframe, "Failed to resolve iframe element by XPath");
|
|
15652
15658
|
try {
|
|
15653
|
-
await parentSess.send("DOM.enable").catch(() => {});
|
|
15654
|
-
const iframeBackendNodeId = (await parentSess.send("DOM.describeNode", { objectId })).node.backendNodeId;
|
|
15659
|
+
await runLocatorStep(progress, "enabling DOM", () => parentSess.send("DOM.enable").catch(() => {}));
|
|
15660
|
+
const iframeBackendNodeId = (await runLocatorStep(progress, "reading snapshot iframe", () => parentSess.send("DOM.describeNode", { objectId }))).node.backendNodeId;
|
|
15655
15661
|
let childFrameId;
|
|
15656
15662
|
for (const fid of listChildrenOf(parentByFrame, ctxFrameId)) try {
|
|
15657
|
-
const { backendNodeId } = await parentSess.send("DOM.getFrameOwner", { frameId: fid });
|
|
15663
|
+
const { backendNodeId } = await runLocatorStep(progress, "finding snapshot iframe owner", () => parentSess.send("DOM.getFrameOwner", { frameId: fid }));
|
|
15658
15664
|
if (backendNodeId === iframeBackendNodeId) {
|
|
15659
15665
|
childFrameId = fid;
|
|
15660
15666
|
break;
|
|
15661
15667
|
}
|
|
15662
15668
|
} catch {
|
|
15669
|
+
progress?.throwIfStopped();
|
|
15663
15670
|
continue;
|
|
15664
15671
|
}
|
|
15665
15672
|
if (!childFrameId) throw iframeResolutionError(selectorForIframe, "Could not map iframe to child frameId");
|
|
15666
15673
|
absPrefix = prefixXPath(absPrefix || "/", selectorForIframe);
|
|
15667
15674
|
ctxFrameId = childFrameId;
|
|
15668
15675
|
} finally {
|
|
15669
|
-
await parentSess
|
|
15676
|
+
await releaseSnapshotObject(parentSess, objectId, progress);
|
|
15670
15677
|
}
|
|
15671
15678
|
buf = [];
|
|
15672
15679
|
};
|
|
15673
15680
|
for (const st of steps) {
|
|
15681
|
+
progress?.throwIfStopped();
|
|
15674
15682
|
buf.push(st);
|
|
15675
15683
|
if (IFRAME_STEP_RE.test(st.name)) await flushIntoChild();
|
|
15676
15684
|
}
|
|
15685
|
+
progress?.throwIfStopped();
|
|
15677
15686
|
const tailXPath = buildXPathFromSteps$1(buf);
|
|
15678
15687
|
return {
|
|
15679
15688
|
targetFrameId: ctxFrameId,
|
|
@@ -15682,33 +15691,36 @@ async function resolveFocusFrameAndTail(page, absoluteXPath, parentByFrame, root
|
|
|
15682
15691
|
};
|
|
15683
15692
|
}
|
|
15684
15693
|
/** Resolve focus frame and tail CSS selector using '>>' to hop iframes. */
|
|
15685
|
-
async function resolveCssFocusFrameAndTail(page, rawSelector, parentByFrame, rootId) {
|
|
15694
|
+
async function resolveCssFocusFrameAndTail(page, rawSelector, parentByFrame, rootId, progress) {
|
|
15695
|
+
progress?.throwIfStopped();
|
|
15686
15696
|
const parts = rawSelector.split(">>").map((s) => s.trim()).filter(Boolean);
|
|
15687
15697
|
let ctxFrameId = rootId;
|
|
15688
15698
|
const absPrefix = "";
|
|
15689
15699
|
for (let i = 0; i < Math.max(0, parts.length - 1); i++) {
|
|
15690
15700
|
const parentSess = page.getSessionForFrame(ctxFrameId);
|
|
15691
|
-
const objectId = await resolveObjectIdForCss(parentSess, parts[i], ctxFrameId);
|
|
15701
|
+
const objectId = await resolveObjectIdForCss(parentSess, parts[i], ctxFrameId, 0, progress);
|
|
15692
15702
|
if (!objectId) throw iframeResolutionError(parts[i], "Failed to resolve iframe via CSS hop");
|
|
15693
15703
|
try {
|
|
15694
|
-
await parentSess.send("DOM.enable").catch(() => {});
|
|
15695
|
-
const iframeBackendNodeId = (await parentSess.send("DOM.describeNode", { objectId })).node.backendNodeId;
|
|
15704
|
+
await runLocatorStep(progress, "enabling DOM", () => parentSess.send("DOM.enable").catch(() => {}));
|
|
15705
|
+
const iframeBackendNodeId = (await runLocatorStep(progress, "reading snapshot iframe", () => parentSess.send("DOM.describeNode", { objectId }))).node.backendNodeId;
|
|
15696
15706
|
let childFrameId;
|
|
15697
15707
|
for (const fid of listChildrenOf(parentByFrame, ctxFrameId)) try {
|
|
15698
|
-
const { backendNodeId } = await parentSess.send("DOM.getFrameOwner", { frameId: fid });
|
|
15708
|
+
const { backendNodeId } = await runLocatorStep(progress, "finding snapshot iframe owner", () => parentSess.send("DOM.getFrameOwner", { frameId: fid }));
|
|
15699
15709
|
if (backendNodeId === iframeBackendNodeId) {
|
|
15700
15710
|
childFrameId = fid;
|
|
15701
15711
|
break;
|
|
15702
15712
|
}
|
|
15703
15713
|
} catch {
|
|
15714
|
+
progress?.throwIfStopped();
|
|
15704
15715
|
continue;
|
|
15705
15716
|
}
|
|
15706
15717
|
if (!childFrameId) throw iframeResolutionError(parts[i], "Could not map CSS iframe hop to child frameId");
|
|
15707
15718
|
ctxFrameId = childFrameId;
|
|
15708
15719
|
} finally {
|
|
15709
|
-
await parentSess
|
|
15720
|
+
await releaseSnapshotObject(parentSess, objectId, progress);
|
|
15710
15721
|
}
|
|
15711
15722
|
}
|
|
15723
|
+
progress?.throwIfStopped();
|
|
15712
15724
|
const tailSelector = parts[parts.length - 1] ?? "*";
|
|
15713
15725
|
return {
|
|
15714
15726
|
targetFrameId: ctxFrameId,
|
|
@@ -15720,35 +15732,36 @@ function iframeResolutionError(frameUrl, message) {
|
|
|
15720
15732
|
return /* @__PURE__ */ new Error(`Unable to resolve frameId for iframe with URL: ${frameUrl} Full error: ${message}`);
|
|
15721
15733
|
}
|
|
15722
15734
|
/** Resolve an XPath to a Runtime remoteObjectId in the given CDP session. */
|
|
15723
|
-
async function resolveObjectIdForXPath(session, xpath, frameId, index = 0) {
|
|
15724
|
-
|
|
15725
|
-
|
|
15726
|
-
|
|
15727
|
-
|
|
15728
|
-
|
|
15735
|
+
async function resolveObjectIdForXPath(session, xpath, frameId, index = 0, progress) {
|
|
15736
|
+
return resolveObjectId(session, buildLocatorInvocation("resolveXPathMainWorld", [JSON.stringify(xpath), JSON.stringify(index)]), frameId, progress);
|
|
15737
|
+
}
|
|
15738
|
+
/** Resolve a CSS selector (supports '>>' within the same frame only) to a Runtime objectId. */
|
|
15739
|
+
async function resolveObjectIdForCss(session, selector, frameId, index = 0, progress) {
|
|
15740
|
+
return resolveObjectId(session, buildLocatorInvocation("resolveCssSelector", [JSON.stringify(selector), JSON.stringify(index)]), frameId, progress);
|
|
15741
|
+
}
|
|
15742
|
+
async function resolveObjectId(session, expression, frameId, progress) {
|
|
15743
|
+
progress?.throwIfStopped();
|
|
15744
|
+
const contextId = frameId ? (await executionContexts.waitForLocatorWorld(session, frameId, 800, progress, { readinessRetries: "none" })).contextId : void 0;
|
|
15745
|
+
const release = (response) => releaseSnapshotObject(session, response.result?.objectId, progress);
|
|
15746
|
+
const response = await runLocatorStep(progress, "resolving snapshot focus", () => session.send("Runtime.evaluate", {
|
|
15747
|
+
expression,
|
|
15729
15748
|
returnByValue: false,
|
|
15730
15749
|
contextId,
|
|
15731
15750
|
awaitPromise: true
|
|
15732
|
-
});
|
|
15733
|
-
if (exceptionDetails)
|
|
15734
|
-
|
|
15751
|
+
}), release);
|
|
15752
|
+
if (response.exceptionDetails) {
|
|
15753
|
+
await release(response);
|
|
15754
|
+
progress?.throwIfStopped();
|
|
15755
|
+
return null;
|
|
15756
|
+
}
|
|
15757
|
+
return response.result?.objectId ?? null;
|
|
15735
15758
|
}
|
|
15736
|
-
/**
|
|
15737
|
-
async function
|
|
15738
|
-
|
|
15739
|
-
|
|
15740
|
-
|
|
15741
|
-
|
|
15742
|
-
const { result, exceptionDetails } = await session.send("Runtime.evaluate", {
|
|
15743
|
-
expression,
|
|
15744
|
-
returnByValue: false,
|
|
15745
|
-
contextId,
|
|
15746
|
-
awaitPromise: true
|
|
15747
|
-
});
|
|
15748
|
-
if (exceptionDetails) return null;
|
|
15749
|
-
return result?.objectId ?? null;
|
|
15750
|
-
};
|
|
15751
|
-
return evaluate(expression);
|
|
15759
|
+
/** Release snapshot references even after expiry, without replacing the read error. */
|
|
15760
|
+
async function releaseSnapshotObject(session, objectId, progress) {
|
|
15761
|
+
if (!objectId) return;
|
|
15762
|
+
const release = () => session.send("Runtime.releaseObject", { objectId }).catch(() => {});
|
|
15763
|
+
if (progress) await progress.cleanup(release);
|
|
15764
|
+
else await release();
|
|
15752
15765
|
}
|
|
15753
15766
|
function listChildrenOf(parentByFrame, parentId) {
|
|
15754
15767
|
const out = [];
|
|
@@ -17307,31 +17320,33 @@ function normaliseSpaces(s) {
|
|
|
17307
17320
|
* Fetch and prune the accessibility tree for a frame, optionally scoping the
|
|
17308
17321
|
* output to a selector root for faster targeted snapshots.
|
|
17309
17322
|
*/
|
|
17310
|
-
async function a11yForFrame(session, frameId, opts) {
|
|
17311
|
-
await session.send("Accessibility.enable").catch(() => {});
|
|
17312
|
-
await session.send("Runtime.enable").catch(() => {});
|
|
17313
|
-
await session.send("DOM.enable").catch(() => {});
|
|
17323
|
+
async function a11yForFrame(session, frameId, opts, progress) {
|
|
17324
|
+
await runLocatorStep(progress, "enabling Accessibility", () => session.send("Accessibility.enable").catch(() => {}));
|
|
17325
|
+
await runLocatorStep(progress, "enabling Runtime", () => session.send("Runtime.enable").catch(() => {}));
|
|
17326
|
+
await runLocatorStep(progress, "enabling DOM", () => session.send("DOM.enable").catch(() => {}));
|
|
17314
17327
|
let nodes = [];
|
|
17315
17328
|
try {
|
|
17316
17329
|
const params = frameId ? { frameId } : {};
|
|
17317
|
-
({nodes} = await session.send("Accessibility.getFullAXTree", params));
|
|
17330
|
+
({nodes} = await runLocatorStep(progress, "reading snapshot accessibility tree", () => session.send("Accessibility.getFullAXTree", params)));
|
|
17318
17331
|
} catch (e) {
|
|
17332
|
+
progress?.throwIfStopped();
|
|
17319
17333
|
const msg = String(e?.message ?? e ?? "");
|
|
17320
17334
|
if (!(msg.includes("Frame with the given") || msg.includes("does not belong to the target") || msg.includes("is not found")) || !frameId) throw e;
|
|
17321
|
-
({nodes} = await session.send("Accessibility.getFullAXTree"));
|
|
17335
|
+
({nodes} = await runLocatorStep(progress, "reading snapshot accessibility tree", () => session.send("Accessibility.getFullAXTree")));
|
|
17322
17336
|
}
|
|
17323
17337
|
let scopeApplied = false;
|
|
17324
|
-
const
|
|
17338
|
+
const nodesForOutline = await (async () => {
|
|
17325
17339
|
const locator = opts.focusLocator;
|
|
17326
17340
|
if (!locator) return nodes;
|
|
17327
17341
|
const sel = locator.selector.trim();
|
|
17328
17342
|
if (!sel) return nodes;
|
|
17343
|
+
let objectId = null;
|
|
17329
17344
|
try {
|
|
17330
17345
|
const looksLikeXPath = /^xpath=/i.test(sel) || sel.startsWith("/");
|
|
17331
17346
|
const nth = locator.nth ?? 0;
|
|
17332
|
-
|
|
17347
|
+
objectId = looksLikeXPath ? await resolveObjectIdForXPath(session, sel, frameId, nth, progress) : await resolveObjectIdForCss(session, sel, frameId, nth, progress);
|
|
17333
17348
|
if (!objectId) return nodes;
|
|
17334
|
-
const be = (await session.send("DOM.describeNode", { objectId })).node?.backendNodeId;
|
|
17349
|
+
const be = (await runLocatorStep(progress, "reading snapshot focus", () => session.send("DOM.describeNode", { objectId }))).node?.backendNodeId;
|
|
17335
17350
|
if (typeof be !== "number") return nodes;
|
|
17336
17351
|
const target = nodes.find((n) => n.backendDOMNodeId === be);
|
|
17337
17352
|
if (!target) return nodes;
|
|
@@ -17352,9 +17367,14 @@ async function a11yForFrame(session, frameId, opts) {
|
|
|
17352
17367
|
parentId: void 0
|
|
17353
17368
|
} : n);
|
|
17354
17369
|
} catch {
|
|
17370
|
+
progress?.throwIfStopped();
|
|
17355
17371
|
return nodes;
|
|
17372
|
+
} finally {
|
|
17373
|
+
await releaseSnapshotObject(session, objectId ?? void 0, progress);
|
|
17356
17374
|
}
|
|
17357
|
-
})()
|
|
17375
|
+
})();
|
|
17376
|
+
progress?.throwIfStopped();
|
|
17377
|
+
const filteredNodes = nodesForOutline.filter((node) => {
|
|
17358
17378
|
const be = node.backendDOMNodeId;
|
|
17359
17379
|
return typeof be !== "number" || !opts.isIgnoredBackendNode?.(be);
|
|
17360
17380
|
});
|
|
@@ -17368,6 +17388,7 @@ async function a11yForFrame(session, frameId, opts) {
|
|
|
17368
17388
|
urlMap[enc] = url;
|
|
17369
17389
|
}
|
|
17370
17390
|
const { tree } = await buildHierarchicalTree(decorateRoles(filteredNodes, opts), opts);
|
|
17391
|
+
progress?.throwIfStopped();
|
|
17371
17392
|
return {
|
|
17372
17393
|
outline: tree.map((n) => formatTreeLine(n)).join("\n").trimEnd(),
|
|
17373
17394
|
urlMap,
|
|
@@ -17529,11 +17550,12 @@ function collectDomTraversalTargets(node) {
|
|
|
17529
17550
|
* Rehydrate a truncated DOM tree by repeatedly calling DOM.describeNode with
|
|
17530
17551
|
* decreasing depths. Any non-CBOR failure is surfaced directly.
|
|
17531
17552
|
*/
|
|
17532
|
-
async function hydrateDomTree(session, root, pierce) {
|
|
17553
|
+
async function hydrateDomTree(session, root, pierce, progress) {
|
|
17533
17554
|
const stack = [root];
|
|
17534
17555
|
const expandedNodeIds = /* @__PURE__ */ new Set();
|
|
17535
17556
|
const expandedBackendIds = /* @__PURE__ */ new Set();
|
|
17536
17557
|
while (stack.length) {
|
|
17558
|
+
progress?.throwIfStopped();
|
|
17537
17559
|
const node = stack.pop();
|
|
17538
17560
|
const nodeId = typeof node.nodeId === "number" && node.nodeId > 0 ? node.nodeId : void 0;
|
|
17539
17561
|
const backendId = typeof node.backendNodeId === "number" && node.backendNodeId > 0 ? node.backendNodeId : void 0;
|
|
@@ -17547,11 +17569,11 @@ async function hydrateDomTree(session, root, pierce) {
|
|
|
17547
17569
|
let expanded = false;
|
|
17548
17570
|
let lastRetryError;
|
|
17549
17571
|
for (const depth of DESCRIBE_DEPTH_ATTEMPTS) try {
|
|
17550
|
-
const described = await session.send("DOM.describeNode", {
|
|
17572
|
+
const described = await runLocatorStep(progress, "expanding snapshot DOM", () => session.send("DOM.describeNode", {
|
|
17551
17573
|
...describeParamsBase,
|
|
17552
17574
|
depth,
|
|
17553
17575
|
pierce
|
|
17554
|
-
});
|
|
17576
|
+
}));
|
|
17555
17577
|
mergeDomNodes(node, described.node);
|
|
17556
17578
|
if (!nodeId && described.node.nodeId && described.node.nodeId > 0) {
|
|
17557
17579
|
node.nodeId = described.node.nodeId;
|
|
@@ -17560,6 +17582,7 @@ async function hydrateDomTree(session, root, pierce) {
|
|
|
17560
17582
|
expanded = true;
|
|
17561
17583
|
break;
|
|
17562
17584
|
} catch (err) {
|
|
17585
|
+
progress?.throwIfStopped();
|
|
17563
17586
|
if (isCborStackError(err instanceof Error ? err.message : String(err))) {
|
|
17564
17587
|
lastRetryError = err;
|
|
17565
17588
|
continue;
|
|
@@ -17579,16 +17602,17 @@ async function hydrateDomTree(session, root, pierce) {
|
|
|
17579
17602
|
* complaining. When a shallower snapshot is returned we hydrate the missing
|
|
17580
17603
|
* branches so downstream DOM traversals see the full tree shape.
|
|
17581
17604
|
*/
|
|
17582
|
-
async function getDomTreeWithFallback(session, pierce) {
|
|
17605
|
+
async function getDomTreeWithFallback(session, pierce, progress) {
|
|
17583
17606
|
let lastRetryError;
|
|
17584
17607
|
for (const depth of DOM_DEPTH_ATTEMPTS) try {
|
|
17585
|
-
const { root } = await session.send("DOM.getDocument", {
|
|
17608
|
+
const { root } = await runLocatorStep(progress, "reading snapshot DOM", () => session.send("DOM.getDocument", {
|
|
17586
17609
|
depth,
|
|
17587
17610
|
pierce
|
|
17588
|
-
});
|
|
17589
|
-
if (depth !== -1) await hydrateDomTree(session, root, pierce);
|
|
17611
|
+
}));
|
|
17612
|
+
if (depth !== -1) await hydrateDomTree(session, root, pierce, progress);
|
|
17590
17613
|
return root;
|
|
17591
17614
|
} catch (err) {
|
|
17615
|
+
progress?.throwIfStopped();
|
|
17592
17616
|
if (isCborStackError(err instanceof Error ? err.message : String(err))) {
|
|
17593
17617
|
lastRetryError = err;
|
|
17594
17618
|
continue;
|
|
@@ -17602,17 +17626,19 @@ async function getDomTreeWithFallback(session, pierce) {
|
|
|
17602
17626
|
* Build tag name and XPath maps for a single frame session.
|
|
17603
17627
|
* EncodedId is produced by a frame-aware encoder provided by the caller.
|
|
17604
17628
|
*/
|
|
17605
|
-
async function domMapsForSession(session, frameId, pierce, encode, attemptOwnerLookup = true) {
|
|
17606
|
-
await session.send("DOM.enable").catch(() => {});
|
|
17607
|
-
const root = await getDomTreeWithFallback(session, pierce);
|
|
17629
|
+
async function domMapsForSession(session, frameId, pierce, encode, attemptOwnerLookup = true, progress) {
|
|
17630
|
+
await runLocatorStep(progress, "enabling DOM", () => session.send("DOM.enable").catch(() => {}));
|
|
17631
|
+
const root = await getDomTreeWithFallback(session, pierce, progress);
|
|
17608
17632
|
let startNode = root;
|
|
17609
17633
|
if (attemptOwnerLookup) try {
|
|
17610
|
-
const ownerBackendId = (await session.send("DOM.getFrameOwner", { frameId })).backendNodeId;
|
|
17634
|
+
const ownerBackendId = (await runLocatorStep(progress, "finding snapshot iframe owner", () => session.send("DOM.getFrameOwner", { frameId }))).backendNodeId;
|
|
17611
17635
|
if (typeof ownerBackendId === "number") {
|
|
17612
17636
|
const ownerEl = findNodeByBackendId(root, ownerBackendId);
|
|
17613
17637
|
if (ownerEl?.contentDocument) startNode = ownerEl.contentDocument;
|
|
17614
17638
|
}
|
|
17615
|
-
} catch {
|
|
17639
|
+
} catch {
|
|
17640
|
+
progress?.throwIfStopped();
|
|
17641
|
+
}
|
|
17616
17642
|
const tagNameMap = {};
|
|
17617
17643
|
const xpathMap = {};
|
|
17618
17644
|
const scrollableMap = {};
|
|
@@ -17621,6 +17647,7 @@ async function domMapsForSession(session, frameId, pierce, encode, attemptOwnerL
|
|
|
17621
17647
|
xpath: ""
|
|
17622
17648
|
}];
|
|
17623
17649
|
while (stack.length) {
|
|
17650
|
+
progress?.throwIfStopped();
|
|
17624
17651
|
const { node, xpath } = stack.pop();
|
|
17625
17652
|
if (node.backendNodeId) {
|
|
17626
17653
|
const encId = encode(frameId, node.backendNodeId);
|
|
@@ -17645,6 +17672,7 @@ async function domMapsForSession(session, frameId, pierce, encode, attemptOwnerL
|
|
|
17645
17672
|
xpath: joinXPath(xpath, "//")
|
|
17646
17673
|
});
|
|
17647
17674
|
}
|
|
17675
|
+
progress?.throwIfStopped();
|
|
17648
17676
|
return {
|
|
17649
17677
|
tagNameMap,
|
|
17650
17678
|
xpathMap,
|
|
@@ -17656,9 +17684,9 @@ async function domMapsForSession(session, frameId, pierce, encode, attemptOwnerL
|
|
|
17656
17684
|
* Once the index is cached, per-frame slices are derived without extra DOM
|
|
17657
17685
|
* calls, which keeps snapshot capture linear in the number of frames.
|
|
17658
17686
|
*/
|
|
17659
|
-
async function buildSessionDomIndex(session, pierce) {
|
|
17660
|
-
await session.send("DOM.enable").catch(() => {});
|
|
17661
|
-
const root = await getDomTreeWithFallback(session, true);
|
|
17687
|
+
async function buildSessionDomIndex(session, pierce, progress) {
|
|
17688
|
+
await runLocatorStep(progress, "enabling DOM", () => session.send("DOM.enable").catch(() => {}));
|
|
17689
|
+
const root = await getDomTreeWithFallback(session, true, progress);
|
|
17662
17690
|
const absByBe = /* @__PURE__ */ new Map();
|
|
17663
17691
|
const tagByBe = /* @__PURE__ */ new Map();
|
|
17664
17692
|
const scrollByBe = /* @__PURE__ */ new Map();
|
|
@@ -17675,6 +17703,7 @@ async function buildSessionDomIndex(session, pierce) {
|
|
|
17675
17703
|
}];
|
|
17676
17704
|
let dfsIndex = 0;
|
|
17677
17705
|
while (stack.length) {
|
|
17706
|
+
progress?.throwIfStopped();
|
|
17678
17707
|
const { node, xp, docRootBe, phase } = stack.pop();
|
|
17679
17708
|
if (phase === "exit") {
|
|
17680
17709
|
if (node.backendNodeId) exitByBe.set(node.backendNodeId, dfsIndex++);
|
|
@@ -17724,6 +17753,7 @@ async function buildSessionDomIndex(session, pierce) {
|
|
|
17724
17753
|
});
|
|
17725
17754
|
}
|
|
17726
17755
|
}
|
|
17756
|
+
progress?.throwIfStopped();
|
|
17727
17757
|
return {
|
|
17728
17758
|
rootBackend: rootBe,
|
|
17729
17759
|
absByBe,
|
|
@@ -17820,7 +17850,8 @@ var toWellFormed = (value) => value.toWellFormed();
|
|
|
17820
17850
|
*
|
|
17821
17851
|
* Each numbered block below references the step above for easier debugging.
|
|
17822
17852
|
*/
|
|
17823
|
-
async function captureHybridSnapshot(page, options, logger = page.logger) {
|
|
17853
|
+
async function captureHybridSnapshot(page, options, progress, logger = page.logger) {
|
|
17854
|
+
progress.throwIfStopped();
|
|
17824
17855
|
const pierce = options?.pierceShadow ?? true;
|
|
17825
17856
|
const includeIframes = options?.includeIframes !== false;
|
|
17826
17857
|
const hasIgnoreLocators = (options?.ignoreLocators?.length ?? 0) > 0;
|
|
@@ -17828,17 +17859,18 @@ async function captureHybridSnapshot(page, options, logger = page.logger) {
|
|
|
17828
17859
|
const framesInScope = includeIframes ? [...context.frames] : [context.rootId];
|
|
17829
17860
|
if (!framesInScope.includes(context.rootId)) framesInScope.unshift(context.rootId);
|
|
17830
17861
|
if (!hasIgnoreLocators) {
|
|
17831
|
-
const scopedSnapshot = await tryScopedSnapshot(page, options, context, pierce, /* @__PURE__ */ new Map(), /* @__PURE__ */ new Map(), logger);
|
|
17862
|
+
const scopedSnapshot = await tryScopedSnapshot(page, options, context, pierce, /* @__PURE__ */ new Map(), /* @__PURE__ */ new Map(), logger, progress);
|
|
17832
17863
|
if (scopedSnapshot) return scopedSnapshot;
|
|
17833
17864
|
}
|
|
17834
|
-
const sessionToIndex = await buildSessionIndexes(page, framesInScope, pierce);
|
|
17835
|
-
const exclusionIntervalsByFrame = await buildFrameExclusionIntervals(page, context, sessionToIndex, await resolveIgnoredNodes(page, options?.ignoreLocators, context, sessionToIndex));
|
|
17865
|
+
const sessionToIndex = await buildSessionIndexes(page, framesInScope, pierce, progress);
|
|
17866
|
+
const exclusionIntervalsByFrame = await buildFrameExclusionIntervals(page, context, sessionToIndex, await resolveIgnoredNodes(page, options?.ignoreLocators, context, sessionToIndex, progress), progress);
|
|
17836
17867
|
if (hasIgnoreLocators) {
|
|
17837
|
-
const scopedSnapshot = await tryScopedSnapshot(page, options, context, pierce, sessionToIndex, exclusionIntervalsByFrame, logger);
|
|
17868
|
+
const scopedSnapshot = await tryScopedSnapshot(page, options, context, pierce, sessionToIndex, exclusionIntervalsByFrame, logger, progress);
|
|
17838
17869
|
if (scopedSnapshot) return scopedSnapshot;
|
|
17839
17870
|
}
|
|
17840
|
-
const { perFrameMaps, perFrameOutlines } = await collectPerFrameMaps(page, context, sessionToIndex, options, pierce, framesInScope, exclusionIntervalsByFrame);
|
|
17841
|
-
const { absPrefix, iframeHostEncByChild } = await computeFramePrefixes(page, context, perFrameMaps, framesInScope);
|
|
17871
|
+
const { perFrameMaps, perFrameOutlines } = await collectPerFrameMaps(page, context, sessionToIndex, options, pierce, framesInScope, exclusionIntervalsByFrame, progress);
|
|
17872
|
+
const { absPrefix, iframeHostEncByChild } = await computeFramePrefixes(page, context, perFrameMaps, framesInScope, progress);
|
|
17873
|
+
progress.throwIfStopped();
|
|
17842
17874
|
return mergeFramesIntoSnapshot(context, perFrameMaps, perFrameOutlines, absPrefix, iframeHostEncByChild, framesInScope);
|
|
17843
17875
|
}
|
|
17844
17876
|
/**
|
|
@@ -17869,7 +17901,8 @@ function buildFrameContext(page) {
|
|
|
17869
17901
|
* Returns `null` when scoping fails (e.g., locator miss) so the caller can
|
|
17870
17902
|
* fall back to the full multi-frame snapshot.
|
|
17871
17903
|
*/
|
|
17872
|
-
async function tryScopedSnapshot(page, options, context, pierce, sessionToIndex, exclusionIntervalsByFrame, logger) {
|
|
17904
|
+
async function tryScopedSnapshot(page, options, context, pierce, sessionToIndex, exclusionIntervalsByFrame, logger, progress) {
|
|
17905
|
+
progress?.throwIfStopped();
|
|
17873
17906
|
const focusLocator = options?.focusLocator;
|
|
17874
17907
|
if (!focusLocator) return null;
|
|
17875
17908
|
const requestedFocus = focusLocator.selector.trim();
|
|
@@ -17883,12 +17916,12 @@ async function tryScopedSnapshot(page, options, context, pierce, sessionToIndex,
|
|
|
17883
17916
|
let tailSelector;
|
|
17884
17917
|
let absPrefix;
|
|
17885
17918
|
if (/^xpath=/i.test(requestedFocus) || requestedFocus.startsWith("/")) {
|
|
17886
|
-
const hit = await resolveFocusFrameAndTail(page, normalizeXPath(requestedFocus), context.parentByFrame, context.rootId);
|
|
17919
|
+
const hit = await resolveFocusFrameAndTail(page, normalizeXPath(requestedFocus), context.parentByFrame, context.rootId, progress);
|
|
17887
17920
|
targetFrameId = hit.targetFrameId;
|
|
17888
17921
|
tailSelector = hit.tailXPath || void 0;
|
|
17889
17922
|
absPrefix = hit.absPrefix;
|
|
17890
17923
|
} else {
|
|
17891
|
-
const cssHit = await resolveCssFocusFrameAndTail(page, requestedFocus, context.parentByFrame, context.rootId);
|
|
17924
|
+
const cssHit = await resolveCssFocusFrameAndTail(page, requestedFocus, context.parentByFrame, context.rootId, progress);
|
|
17892
17925
|
targetFrameId = cssHit.targetFrameId;
|
|
17893
17926
|
tailSelector = cssHit.tailSelector || void 0;
|
|
17894
17927
|
absPrefix = cssHit.absPrefix;
|
|
@@ -17896,7 +17929,7 @@ async function tryScopedSnapshot(page, options, context, pierce, sessionToIndex,
|
|
|
17896
17929
|
const owningSess = ownerSession(page, targetFrameId);
|
|
17897
17930
|
const parentId = context.parentByFrame.get(targetFrameId);
|
|
17898
17931
|
const sameSessionAsParent = !!parentId && ownerSession(page, parentId) === ownerSession(page, targetFrameId);
|
|
17899
|
-
const { tagNameMap, xpathMap, scrollableMap } = await domMapsForSession(owningSess, targetFrameId, pierce, (fid, be) => `${page.getOrdinal(fid)}-${be}`, sameSessionAsParent);
|
|
17932
|
+
const { tagNameMap, xpathMap, scrollableMap } = await domMapsForSession(owningSess, targetFrameId, pierce, (fid, be) => `${page.getOrdinal(fid)}-${be}`, sameSessionAsParent, progress);
|
|
17900
17933
|
const { outline, urlMap, scopeApplied } = await a11yForFrame(owningSess, targetFrameId, {
|
|
17901
17934
|
focusLocator: tailSelector ? {
|
|
17902
17935
|
selector: tailSelector,
|
|
@@ -17906,7 +17939,7 @@ async function tryScopedSnapshot(page, options, context, pierce, sessionToIndex,
|
|
|
17906
17939
|
tagNameMap,
|
|
17907
17940
|
scrollableMap,
|
|
17908
17941
|
encode: (backendNodeId) => `${page.getOrdinal(targetFrameId)}-${backendNodeId}`
|
|
17909
|
-
});
|
|
17942
|
+
}, progress);
|
|
17910
17943
|
const scopedXpathMap = {};
|
|
17911
17944
|
const isIgnoredBackendNode = makeIsIgnoredBackendNode(targetFrameId, ownerSessionIndexForFrame(page, targetFrameId, sessionToIndex), exclusionIntervalsByFrame);
|
|
17912
17945
|
const abs = absPrefix ?? "";
|
|
@@ -17936,6 +17969,7 @@ async function tryScopedSnapshot(page, options, context, pierce, sessionToIndex,
|
|
|
17936
17969
|
if (scopeApplied) return snapshot;
|
|
17937
17970
|
logScopeFallback();
|
|
17938
17971
|
} catch {
|
|
17972
|
+
progress?.throwIfStopped();
|
|
17939
17973
|
logScopeFallback();
|
|
17940
17974
|
}
|
|
17941
17975
|
return null;
|
|
@@ -17945,16 +17979,18 @@ async function tryScopedSnapshot(page, options, context, pierce, sessionToIndex,
|
|
|
17945
17979
|
* result so per-frame slices can share the structure. We key by session id
|
|
17946
17980
|
* because same process iframes live inside the same session.
|
|
17947
17981
|
*/
|
|
17948
|
-
async function buildSessionIndexes(page, frames, pierce) {
|
|
17982
|
+
async function buildSessionIndexes(page, frames, pierce, progress) {
|
|
17949
17983
|
const sessionToIndex = /* @__PURE__ */ new Map();
|
|
17950
17984
|
const sessionById = /* @__PURE__ */ new Map();
|
|
17951
17985
|
for (const frameId of frames) {
|
|
17986
|
+
progress?.throwIfStopped();
|
|
17952
17987
|
const sess = ownerSession(page, frameId);
|
|
17953
17988
|
const sid = sess.id ?? "root";
|
|
17954
17989
|
if (!sessionById.has(sid)) sessionById.set(sid, sess);
|
|
17955
17990
|
}
|
|
17956
17991
|
for (const [sid, sess] of sessionById.entries()) {
|
|
17957
|
-
|
|
17992
|
+
progress?.throwIfStopped();
|
|
17993
|
+
const idx = await buildSessionDomIndex(sess, pierce, progress);
|
|
17958
17994
|
sessionToIndex.set(sid, idx);
|
|
17959
17995
|
}
|
|
17960
17996
|
return sessionToIndex;
|
|
@@ -17967,20 +18003,21 @@ async function buildSessionIndexes(page, frames, pierce) {
|
|
|
17967
18003
|
* - collects tag/xpath/scrollability maps for DOM-based lookups
|
|
17968
18004
|
* - fetches its AX tree to produce outlines and URL maps
|
|
17969
18005
|
*/
|
|
17970
|
-
async function collectPerFrameMaps(page, context, sessionToIndex, options, pierce, frameIds, exclusionIntervalsByFrame) {
|
|
18006
|
+
async function collectPerFrameMaps(page, context, sessionToIndex, options, pierce, frameIds, exclusionIntervalsByFrame, progress) {
|
|
17971
18007
|
const perFrameMaps = /* @__PURE__ */ new Map();
|
|
17972
18008
|
const perFrameOutlines = [];
|
|
17973
18009
|
for (const frameId of frameIds) {
|
|
18010
|
+
progress?.throwIfStopped();
|
|
17974
18011
|
const sess = ownerSession(page, frameId);
|
|
17975
18012
|
const sid = sess.id ?? "root";
|
|
17976
18013
|
let idx = sessionToIndex.get(sid);
|
|
17977
18014
|
if (!idx) {
|
|
17978
|
-
idx = await buildSessionDomIndex(sess, pierce);
|
|
18015
|
+
idx = await buildSessionDomIndex(sess, pierce, progress);
|
|
17979
18016
|
sessionToIndex.set(sid, idx);
|
|
17980
18017
|
}
|
|
17981
18018
|
const parentId = context.parentByFrame.get(frameId);
|
|
17982
18019
|
const sameSessionAsParent = !!parentId && ownerSession(page, parentId) === sess;
|
|
17983
|
-
const docRootBe = await resolveFrameDocRootBackendId(page, frameId, idx, sameSessionAsParent);
|
|
18020
|
+
const docRootBe = await resolveFrameDocRootBackendId(page, frameId, idx, sameSessionAsParent, progress);
|
|
17984
18021
|
if (docRootBe === void 0) continue;
|
|
17985
18022
|
const tagNameMap = {};
|
|
17986
18023
|
const xpathMap = {};
|
|
@@ -18004,7 +18041,7 @@ async function collectPerFrameMaps(page, context, sessionToIndex, options, pierc
|
|
|
18004
18041
|
tagNameMap,
|
|
18005
18042
|
scrollableMap,
|
|
18006
18043
|
encode: (backendNodeId) => `${page.getOrdinal(frameId)}-${backendNodeId}`
|
|
18007
|
-
});
|
|
18044
|
+
}, progress);
|
|
18008
18045
|
perFrameOutlines.push({
|
|
18009
18046
|
frameId,
|
|
18010
18047
|
outline
|
|
@@ -18021,38 +18058,40 @@ async function collectPerFrameMaps(page, context, sessionToIndex, options, pierc
|
|
|
18021
18058
|
perFrameOutlines
|
|
18022
18059
|
};
|
|
18023
18060
|
}
|
|
18024
|
-
async function resolveIgnoredNodes(page, ignoreLocators, context, sessionToIndex) {
|
|
18061
|
+
async function resolveIgnoredNodes(page, ignoreLocators, context, sessionToIndex, progress) {
|
|
18025
18062
|
const ignoredNodesByFrame = /* @__PURE__ */ new Map();
|
|
18026
18063
|
for (const locator of ignoreLocators ?? []) {
|
|
18064
|
+
progress?.throwIfStopped();
|
|
18027
18065
|
const selector = locator.selector.trim();
|
|
18028
18066
|
if (!selector) continue;
|
|
18029
18067
|
try {
|
|
18030
18068
|
const resolved = await resolveIgnoredNodesForLocator(page, {
|
|
18031
18069
|
...locator,
|
|
18032
18070
|
selector
|
|
18033
|
-
}, context, sessionToIndex);
|
|
18071
|
+
}, context, sessionToIndex, progress);
|
|
18034
18072
|
for (const match of resolved) {
|
|
18035
18073
|
const nodes = ignoredNodesByFrame.get(match.frameId) ?? /* @__PURE__ */ new Set();
|
|
18036
18074
|
nodes.add(match.backendNodeId);
|
|
18037
18075
|
ignoredNodesByFrame.set(match.frameId, nodes);
|
|
18038
18076
|
}
|
|
18039
18077
|
} catch {
|
|
18078
|
+
progress?.throwIfStopped();
|
|
18040
18079
|
continue;
|
|
18041
18080
|
}
|
|
18042
18081
|
}
|
|
18043
18082
|
return ignoredNodesByFrame;
|
|
18044
18083
|
}
|
|
18045
|
-
async function resolveIgnoredNodesForLocator(page, locator, context, sessionToIndex) {
|
|
18084
|
+
async function resolveIgnoredNodesForLocator(page, locator, context, sessionToIndex, progress) {
|
|
18046
18085
|
const selector = locator.selector;
|
|
18047
18086
|
if (/^xpath=/i.test(selector) || selector.startsWith("/")) {
|
|
18048
|
-
const hit = await resolveFocusFrameAndTail(page, normalizeXPath(selector), context.parentByFrame, context.rootId);
|
|
18087
|
+
const hit = await resolveFocusFrameAndTail(page, normalizeXPath(selector), context.parentByFrame, context.rootId, progress);
|
|
18049
18088
|
const targetFrameId = hit.targetFrameId;
|
|
18050
18089
|
const tailXPath = hit.tailXPath || "/";
|
|
18051
18090
|
if (tailXPath === "/") {
|
|
18052
18091
|
const idx = ownerSessionIndexForFrame(page, targetFrameId, sessionToIndex);
|
|
18053
18092
|
if (!idx) return [];
|
|
18054
18093
|
const parentId = context.parentByFrame.get(targetFrameId);
|
|
18055
|
-
const backendNodeId = await resolveFrameDocRootBackendId(page, targetFrameId, idx, !!parentId && ownerSession(page, parentId) === ownerSession(page, targetFrameId));
|
|
18094
|
+
const backendNodeId = await resolveFrameDocRootBackendId(page, targetFrameId, idx, !!parentId && ownerSession(page, parentId) === ownerSession(page, targetFrameId), progress);
|
|
18056
18095
|
if (backendNodeId === void 0) return [];
|
|
18057
18096
|
return [{
|
|
18058
18097
|
frameId: targetFrameId,
|
|
@@ -18062,41 +18101,44 @@ async function resolveIgnoredNodesForLocator(page, locator, context, sessionToIn
|
|
|
18062
18101
|
return resolveIgnoredNodesInFrame(page, targetFrameId, {
|
|
18063
18102
|
kind: "xpath",
|
|
18064
18103
|
value: tailXPath
|
|
18065
|
-
}, locator.nth);
|
|
18104
|
+
}, locator.nth, progress);
|
|
18066
18105
|
}
|
|
18067
|
-
const hit = await resolveCssFocusFrameAndTail(page, selector, context.parentByFrame, context.rootId);
|
|
18106
|
+
const hit = await resolveCssFocusFrameAndTail(page, selector, context.parentByFrame, context.rootId, progress);
|
|
18068
18107
|
const targetFrameId = hit.targetFrameId;
|
|
18069
18108
|
return resolveIgnoredNodesInFrame(page, targetFrameId, {
|
|
18070
18109
|
kind: "css",
|
|
18071
18110
|
value: hit.tailSelector || selector
|
|
18072
|
-
}, locator.nth);
|
|
18111
|
+
}, locator.nth, progress);
|
|
18073
18112
|
}
|
|
18074
|
-
async function resolveIgnoredNodesInFrame(page, frameId, query, nth) {
|
|
18113
|
+
async function resolveIgnoredNodesInFrame(page, frameId, query, nth, progress) {
|
|
18075
18114
|
const session = ownerSession(page, frameId);
|
|
18076
|
-
const resolver = new FrameSelectorResolver(new Frame(session, frameId, "", false, page.logger));
|
|
18077
|
-
const resolvedNodes = nth === void 0 ? await resolver.resolveAll(query) : [await resolver.resolveAtIndex(query, nth)].filter((node) => !!node);
|
|
18115
|
+
const resolver = new FrameSelectorResolver(new Frame(session, frameId, "", false, page.logger), { readinessRetries: "none" });
|
|
18116
|
+
const resolvedNodes = nth === void 0 ? await resolver.resolveAll(query, {}, progress) : [await resolver.resolveAtIndex(query, nth, progress)].filter((node) => !!node);
|
|
18078
18117
|
if (!resolvedNodes.length) return [];
|
|
18079
|
-
return (await describeResolvedNodes(session, resolvedNodes)).map((backendNodeId) => ({
|
|
18118
|
+
return (await describeResolvedNodes(session, resolvedNodes, progress)).map((backendNodeId) => ({
|
|
18080
18119
|
frameId,
|
|
18081
18120
|
backendNodeId
|
|
18082
18121
|
}));
|
|
18083
18122
|
}
|
|
18084
|
-
async function describeResolvedNodes(session, resolvedNodes) {
|
|
18123
|
+
async function describeResolvedNodes(session, resolvedNodes, progress) {
|
|
18085
18124
|
const backendNodeIds = /* @__PURE__ */ new Set();
|
|
18086
18125
|
try {
|
|
18087
18126
|
for (const resolvedNode of resolvedNodes) {
|
|
18088
|
-
const backendNodeId = (await session.send("DOM.describeNode", { objectId: resolvedNode.objectId })).node.backendNodeId;
|
|
18127
|
+
const backendNodeId = (await runLocatorStep(progress, "reading ignored snapshot nodes", () => session.send("DOM.describeNode", { objectId: resolvedNode.objectId }))).node.backendNodeId;
|
|
18089
18128
|
if (typeof backendNodeId === "number") backendNodeIds.add(backendNodeId);
|
|
18090
18129
|
}
|
|
18091
18130
|
} finally {
|
|
18092
|
-
|
|
18131
|
+
const release = () => Promise.all(resolvedNodes.map((resolvedNode) => session.send("Runtime.releaseObject", { objectId: resolvedNode.objectId }).catch(() => {})));
|
|
18132
|
+
if (progress) await progress.cleanup(release);
|
|
18133
|
+
else await release();
|
|
18093
18134
|
}
|
|
18135
|
+
progress?.throwIfStopped();
|
|
18094
18136
|
return [...backendNodeIds];
|
|
18095
18137
|
}
|
|
18096
|
-
async function buildFrameExclusionIntervals(page, context, sessionToIndex, ignoredNodesByFrame) {
|
|
18138
|
+
async function buildFrameExclusionIntervals(page, context, sessionToIndex, ignoredNodesByFrame, progress) {
|
|
18097
18139
|
const intervalsByFrame = /* @__PURE__ */ new Map();
|
|
18098
18140
|
if (!ignoredNodesByFrame.size) return intervalsByFrame;
|
|
18099
|
-
const childFramesByParent = await resolveChildFramesByParent(page, context);
|
|
18141
|
+
const childFramesByParent = await resolveChildFramesByParent(page, context, progress);
|
|
18100
18142
|
const excludedFrames = /* @__PURE__ */ new Set();
|
|
18101
18143
|
const pushInterval = (frameId, start, end) => {
|
|
18102
18144
|
const intervals = intervalsByFrame.get(frameId) ?? [];
|
|
@@ -18107,12 +18149,13 @@ async function buildFrameExclusionIntervals(page, context, sessionToIndex, ignor
|
|
|
18107
18149
|
intervalsByFrame.set(frameId, intervals);
|
|
18108
18150
|
};
|
|
18109
18151
|
const excludeFrameSubtree = async (frameId) => {
|
|
18152
|
+
progress?.throwIfStopped();
|
|
18110
18153
|
if (excludedFrames.has(frameId)) return;
|
|
18111
18154
|
excludedFrames.add(frameId);
|
|
18112
18155
|
const idx = ownerSessionIndexForFrame(page, frameId, sessionToIndex);
|
|
18113
18156
|
if (!idx) return;
|
|
18114
18157
|
const parentId = context.parentByFrame.get(frameId);
|
|
18115
|
-
const docRootBe = await resolveFrameDocRootBackendId(page, frameId, idx, !!parentId && ownerSession(page, parentId) === ownerSession(page, frameId));
|
|
18158
|
+
const docRootBe = await resolveFrameDocRootBackendId(page, frameId, idx, !!parentId && ownerSession(page, parentId) === ownerSession(page, frameId), progress);
|
|
18116
18159
|
if (docRootBe !== void 0) {
|
|
18117
18160
|
const start = idx.enterByBe.get(docRootBe);
|
|
18118
18161
|
const end = idx.exitByBe.get(docRootBe);
|
|
@@ -18121,6 +18164,7 @@ async function buildFrameExclusionIntervals(page, context, sessionToIndex, ignor
|
|
|
18121
18164
|
for (const childFrameId of listChildrenOf(context.parentByFrame, frameId)) await excludeFrameSubtree(childFrameId);
|
|
18122
18165
|
};
|
|
18123
18166
|
const excludeIgnoredNode = async (frameId, backendNodeId) => {
|
|
18167
|
+
progress?.throwIfStopped();
|
|
18124
18168
|
const idx = ownerSessionIndexForFrame(page, frameId, sessionToIndex);
|
|
18125
18169
|
if (!idx) return;
|
|
18126
18170
|
const start = idx.enterByBe.get(backendNodeId);
|
|
@@ -18150,15 +18194,16 @@ async function buildFrameExclusionIntervals(page, context, sessionToIndex, ignor
|
|
|
18150
18194
|
}
|
|
18151
18195
|
return intervalsByFrame;
|
|
18152
18196
|
}
|
|
18153
|
-
async function resolveChildFramesByParent(page, context) {
|
|
18197
|
+
async function resolveChildFramesByParent(page, context, progress) {
|
|
18154
18198
|
const childFramesByParent = /* @__PURE__ */ new Map();
|
|
18155
18199
|
for (const frameId of context.frames) {
|
|
18200
|
+
progress?.throwIfStopped();
|
|
18156
18201
|
const parentId = context.parentByFrame.get(frameId);
|
|
18157
18202
|
if (!parentId) continue;
|
|
18158
18203
|
const session = parentSession(page, context.parentByFrame, frameId);
|
|
18159
18204
|
if (!session) continue;
|
|
18160
18205
|
try {
|
|
18161
|
-
const { backendNodeId } = await session.send("DOM.getFrameOwner", { frameId });
|
|
18206
|
+
const { backendNodeId } = await runLocatorStep(progress, "finding snapshot iframe owner", () => session.send("DOM.getFrameOwner", { frameId }));
|
|
18162
18207
|
if (typeof backendNodeId !== "number") continue;
|
|
18163
18208
|
const childFrames = childFramesByParent.get(parentId) ?? [];
|
|
18164
18209
|
childFrames.push({
|
|
@@ -18167,6 +18212,7 @@ async function resolveChildFramesByParent(page, context) {
|
|
|
18167
18212
|
});
|
|
18168
18213
|
childFramesByParent.set(parentId, childFrames);
|
|
18169
18214
|
} catch {
|
|
18215
|
+
progress?.throwIfStopped();
|
|
18170
18216
|
continue;
|
|
18171
18217
|
}
|
|
18172
18218
|
}
|
|
@@ -18201,23 +18247,26 @@ function ownerSessionIndexForFrame(page, frameId, sessionToIndex) {
|
|
|
18201
18247
|
const session = ownerSession(page, frameId);
|
|
18202
18248
|
return sessionToIndex.get(session.id ?? "root");
|
|
18203
18249
|
}
|
|
18204
|
-
async function resolveFrameDocRootBackendId(page, frameId, idx, sameSessionAsParent) {
|
|
18250
|
+
async function resolveFrameDocRootBackendId(page, frameId, idx, sameSessionAsParent, progress) {
|
|
18251
|
+
progress?.throwIfStopped();
|
|
18205
18252
|
if (!sameSessionAsParent) return idx.rootBackend;
|
|
18206
18253
|
const session = ownerSession(page, frameId);
|
|
18207
18254
|
try {
|
|
18208
|
-
const { backendNodeId } = await session.send("DOM.getFrameOwner", { frameId });
|
|
18255
|
+
const { backendNodeId } = await runLocatorStep(progress, "finding snapshot iframe owner", () => session.send("DOM.getFrameOwner", { frameId }));
|
|
18209
18256
|
if (typeof backendNodeId === "number") {
|
|
18210
18257
|
const docRootBe = idx.contentDocRootByIframe.get(backendNodeId);
|
|
18211
18258
|
if (typeof docRootBe === "number") return docRootBe;
|
|
18212
18259
|
}
|
|
18213
|
-
} catch {
|
|
18260
|
+
} catch {
|
|
18261
|
+
progress?.throwIfStopped();
|
|
18262
|
+
}
|
|
18214
18263
|
}
|
|
18215
18264
|
/**
|
|
18216
18265
|
* Step 4 – walk the frame tree (parent-first) to compute absolute prefixes for
|
|
18217
18266
|
* every frame. The prefix is the absolute XPath of the iframe element hosting
|
|
18218
18267
|
* the frame, so we can later convert relative XPaths into cross-frame ones.
|
|
18219
18268
|
*/
|
|
18220
|
-
async function computeFramePrefixes(page, context, perFrameMaps, frameIds) {
|
|
18269
|
+
async function computeFramePrefixes(page, context, perFrameMaps, frameIds, progress) {
|
|
18221
18270
|
const absPrefix = /* @__PURE__ */ new Map();
|
|
18222
18271
|
const iframeHostEncByChild = /* @__PURE__ */ new Map();
|
|
18223
18272
|
absPrefix.set(context.rootId, "");
|
|
@@ -18225,6 +18274,7 @@ async function computeFramePrefixes(page, context, perFrameMaps, frameIds) {
|
|
|
18225
18274
|
const queue = [];
|
|
18226
18275
|
if (included.has(context.rootId)) queue.push(context.rootId);
|
|
18227
18276
|
while (queue.length) {
|
|
18277
|
+
progress?.throwIfStopped();
|
|
18228
18278
|
const parent = queue.shift();
|
|
18229
18279
|
const parentAbs = absPrefix.get(parent);
|
|
18230
18280
|
for (const child of context.frames) {
|
|
@@ -18234,9 +18284,10 @@ async function computeFramePrefixes(page, context, perFrameMaps, frameIds) {
|
|
|
18234
18284
|
const parentSess = parentSession(page, context.parentByFrame, child);
|
|
18235
18285
|
const ownerBackendNodeId = await (async () => {
|
|
18236
18286
|
try {
|
|
18237
|
-
const { backendNodeId } = await parentSess.send("DOM.getFrameOwner", { frameId: child });
|
|
18287
|
+
const { backendNodeId } = await runLocatorStep(progress, "finding snapshot iframe owner", () => parentSess.send("DOM.getFrameOwner", { frameId: child }));
|
|
18238
18288
|
return backendNodeId;
|
|
18239
18289
|
} catch {
|
|
18290
|
+
progress?.throwIfStopped();
|
|
18240
18291
|
return;
|
|
18241
18292
|
}
|
|
18242
18293
|
})();
|
|
@@ -54319,7 +54370,7 @@ var WebTracerProvider = class extends BasicTracerProvider {
|
|
|
54319
54370
|
};
|
|
54320
54371
|
var package_default = {
|
|
54321
54372
|
name: "@browserbasehq/stagehand-extension",
|
|
54322
|
-
version: "1.1.0-alpha-
|
|
54373
|
+
version: "1.1.0-alpha-666b6fa32b003420a4a9e641dc47ee4c9a531eff",
|
|
54323
54374
|
"private": true,
|
|
54324
54375
|
type: "module",
|
|
54325
54376
|
scripts: {
|
|
@@ -57623,19 +57674,27 @@ var Page = class Page {
|
|
|
57623
57674
|
throw error;
|
|
57624
57675
|
}
|
|
57625
57676
|
}
|
|
57626
|
-
async captureSnapshot(options) {
|
|
57627
|
-
return await
|
|
57677
|
+
async captureSnapshot(options, parentProgress) {
|
|
57678
|
+
return await runWithProgress(parentProgress ?? {
|
|
57679
|
+
name: "snapshot",
|
|
57680
|
+
timeout: 0
|
|
57681
|
+
}, (progress) => captureHybridSnapshot(this, options, progress, this.logger));
|
|
57628
57682
|
}
|
|
57629
|
-
async snapshot(options) {
|
|
57630
|
-
|
|
57631
|
-
|
|
57632
|
-
|
|
57683
|
+
async snapshot(options, parentProgress) {
|
|
57684
|
+
return await runWithProgress(parentProgress ?? {
|
|
57685
|
+
name: "snapshot",
|
|
57686
|
+
timeout: options?.timeout ?? 2e4
|
|
57687
|
+
}, async (progress) => {
|
|
57688
|
+
const { combinedTree, combinedXpathMap, combinedUrlMap } = await this.captureSnapshot({
|
|
57689
|
+
pierceShadow: true,
|
|
57690
|
+
includeIframes: options?.includeIframes
|
|
57691
|
+
}, progress);
|
|
57692
|
+
return {
|
|
57693
|
+
formattedTree: combinedTree,
|
|
57694
|
+
xpathMap: combinedXpathMap,
|
|
57695
|
+
urlMap: combinedUrlMap
|
|
57696
|
+
};
|
|
57633
57697
|
});
|
|
57634
|
-
return {
|
|
57635
|
-
formattedTree: combinedTree,
|
|
57636
|
-
xpathMap: combinedXpathMap,
|
|
57637
|
-
urlMap: combinedUrlMap
|
|
57638
|
-
};
|
|
57639
57698
|
}
|
|
57640
57699
|
/** Press a key down without releasing it */
|
|
57641
57700
|
async keyDown(key) {
|
|
@@ -1899,6 +1899,8 @@ class PageSnapshotOptions(WireModel):
|
|
|
1899
1899
|
extra="forbid",
|
|
1900
1900
|
validate_by_name=True,
|
|
1901
1901
|
)
|
|
1902
|
+
timeout: Annotated[Optional[StrictFloat], Field(ge=0.0)] = None
|
|
1903
|
+
"""Milliseconds for the whole snapshot call. Defaults to 20000. Zero disables the timeout."""
|
|
1902
1904
|
include_iframes: Optional[StrictBool] = None
|
|
1903
1905
|
|
|
1904
1906
|
|
{stagehand-4.2.0a0.dev1560 → stagehand-4.2.0a0.dev1562}/src/stagehand/_generated/protocol_version.py
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
"""Generated from packages/protocol/package.json. Do not edit."""
|
|
2
2
|
|
|
3
3
|
PROTOCOL_SEMVER_PATTERN = '^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[A-Za-z-][0-9A-Za-z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[A-Za-z-][0-9A-Za-z-]*))*))?(?:\\+([0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*))?$'
|
|
4
|
-
STAGEHAND_PROTOCOL_VERSION = '2.1.0-alpha-
|
|
4
|
+
STAGEHAND_PROTOCOL_VERSION = '2.1.0-alpha-666b6fa32b003420a4a9e641dc47ee4c9a531eff'
|
|
@@ -665,10 +665,17 @@ class Page:
|
|
|
665
665
|
Path(path).write_bytes(data)
|
|
666
666
|
return data
|
|
667
667
|
|
|
668
|
-
async def snapshot(
|
|
668
|
+
async def snapshot(
|
|
669
|
+
self, *, include_iframes: bool | None = None, timeout: float | None = None
|
|
670
|
+
) -> SnapshotResult:
|
|
669
671
|
params = PageSnapshotParams(page_id=self.page_id)
|
|
670
|
-
|
|
671
|
-
|
|
672
|
+
options = PageSnapshotOptions.model_validate({
|
|
673
|
+
key: value
|
|
674
|
+
for key, value in {"include_iframes": include_iframes, "timeout": timeout}.items()
|
|
675
|
+
if value is not None
|
|
676
|
+
})
|
|
677
|
+
if options.model_fields_set:
|
|
678
|
+
params.options = options
|
|
672
679
|
return await self._rpc_client.send("page.snapshot", params, SnapshotResult)
|
|
673
680
|
|
|
674
681
|
async def tools(self, *, timeout: float | None = None) -> list[WebMCPTool]:
|
|
@@ -31,6 +31,7 @@ _DEFAULT_OPERATION_TIMEOUT_MS = {
|
|
|
31
31
|
"page.wait_for_load_state": 15_000,
|
|
32
32
|
"page.wait_for_selector": 30_000,
|
|
33
33
|
"page.pdf": 30_000,
|
|
34
|
+
"page.snapshot": 20_000,
|
|
34
35
|
"page.webmcp_tools": 1_000,
|
|
35
36
|
}
|
|
36
37
|
_UNBOUNDED_BY_DEFAULT_METHODS = {
|
|
@@ -56,7 +57,6 @@ _UNBOUNDED_BY_DEFAULT_METHODS = {
|
|
|
56
57
|
"page.close",
|
|
57
58
|
"page.evaluate",
|
|
58
59
|
"page.screenshot",
|
|
59
|
-
"page.snapshot",
|
|
60
60
|
"page.webmcp_invocation_result",
|
|
61
61
|
}
|
|
62
62
|
|
|
@@ -557,6 +557,7 @@ def _rpc_response_timeout_seconds(method: str, params: BaseModel) -> float | Non
|
|
|
557
557
|
"page.go_forward",
|
|
558
558
|
"page.screenshot",
|
|
559
559
|
"page.pdf",
|
|
560
|
+
"page.snapshot",
|
|
560
561
|
"page.wait_for_selector",
|
|
561
562
|
"page.webmcp_tools",
|
|
562
563
|
"page.webmcp_invocation_result",
|
|
@@ -568,7 +569,7 @@ def _rpc_response_timeout_seconds(method: str, params: BaseModel) -> float | Non
|
|
|
568
569
|
operation_timeout_ms = _numeric_property(params, "ms")
|
|
569
570
|
|
|
570
571
|
if operation_timeout_ms is not None:
|
|
571
|
-
if method
|
|
572
|
+
if method in {"page.pdf", "page.snapshot"} and operation_timeout_ms == 0:
|
|
572
573
|
return None
|
|
573
574
|
return (_RPC_RESPONSE_GRACE_MS + max(0, operation_timeout_ms)) / 1_000
|
|
574
575
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{stagehand-4.2.0a0.dev1560 → stagehand-4.2.0a0.dev1562}/src/stagehand/_extension/content-script.js
RENAMED
|
File without changes
|
{stagehand-4.2.0a0.dev1560 → stagehand-4.2.0a0.dev1562}/src/stagehand/_extension/manifest.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{stagehand-4.2.0a0.dev1560 → stagehand-4.2.0a0.dev1562}/src/stagehand/_generated/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{stagehand-4.2.0a0.dev1560 → stagehand-4.2.0a0.dev1562}/src/stagehand/browserbase_services.py
RENAMED
|
File without changes
|
{stagehand-4.2.0a0.dev1560 → stagehand-4.2.0a0.dev1562}/src/stagehand/browserbase_session.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|