stagehand 4.2.0a0.dev1556__tar.gz → 4.2.0a0.dev1558__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.dev1556 → stagehand-4.2.0a0.dev1558}/PKG-INFO +1 -1
- {stagehand-4.2.0a0.dev1556 → stagehand-4.2.0a0.dev1558}/pyproject.toml +1 -1
- {stagehand-4.2.0a0.dev1556 → stagehand-4.2.0a0.dev1558}/src/stagehand/_extension/service-worker.js +472 -462
- {stagehand-4.2.0a0.dev1556 → stagehand-4.2.0a0.dev1558}/src/stagehand/_generated/protocol_version.py +1 -1
- {stagehand-4.2.0a0.dev1556 → stagehand-4.2.0a0.dev1558}/README.md +0 -0
- {stagehand-4.2.0a0.dev1556 → stagehand-4.2.0a0.dev1558}/src/stagehand/__init__.py +0 -0
- {stagehand-4.2.0a0.dev1556 → stagehand-4.2.0a0.dev1558}/src/stagehand/_extension/blank.html +0 -0
- {stagehand-4.2.0a0.dev1556 → stagehand-4.2.0a0.dev1558}/src/stagehand/_extension/content-script.js +0 -0
- {stagehand-4.2.0a0.dev1556 → stagehand-4.2.0a0.dev1558}/src/stagehand/_extension/manifest.json +0 -0
- {stagehand-4.2.0a0.dev1556 → stagehand-4.2.0a0.dev1558}/src/stagehand/_extension/offscreen/service-worker-heartbeat.html +0 -0
- {stagehand-4.2.0a0.dev1556 → stagehand-4.2.0a0.dev1558}/src/stagehand/_extension/offscreen/service-worker-heartbeat.js +0 -0
- {stagehand-4.2.0a0.dev1556 → stagehand-4.2.0a0.dev1558}/src/stagehand/_extension/wake-service-worker.html +0 -0
- {stagehand-4.2.0a0.dev1556 → stagehand-4.2.0a0.dev1558}/src/stagehand/_extension/wake-service-worker.js +0 -0
- {stagehand-4.2.0a0.dev1556 → stagehand-4.2.0a0.dev1558}/src/stagehand/_generated/__init__.py +0 -0
- {stagehand-4.2.0a0.dev1556 → stagehand-4.2.0a0.dev1558}/src/stagehand/_generated/input_types.py +0 -0
- {stagehand-4.2.0a0.dev1556 → stagehand-4.2.0a0.dev1558}/src/stagehand/_generated/models.py +0 -0
- {stagehand-4.2.0a0.dev1556 → stagehand-4.2.0a0.dev1558}/src/stagehand/_sdk_identity.py +0 -0
- {stagehand-4.2.0a0.dev1556 → stagehand-4.2.0a0.dev1558}/src/stagehand/_validation.py +0 -0
- {stagehand-4.2.0a0.dev1556 → stagehand-4.2.0a0.dev1558}/src/stagehand/browser.py +0 -0
- {stagehand-4.2.0a0.dev1556 → stagehand-4.2.0a0.dev1558}/src/stagehand/browser_clipboard.py +0 -0
- {stagehand-4.2.0a0.dev1556 → stagehand-4.2.0a0.dev1558}/src/stagehand/browser_context.py +0 -0
- {stagehand-4.2.0a0.dev1556 → stagehand-4.2.0a0.dev1558}/src/stagehand/browserbase_services.py +0 -0
- {stagehand-4.2.0a0.dev1556 → stagehand-4.2.0a0.dev1558}/src/stagehand/browserbase_session.py +0 -0
- {stagehand-4.2.0a0.dev1556 → stagehand-4.2.0a0.dev1558}/src/stagehand/cdp_client.py +0 -0
- {stagehand-4.2.0a0.dev1556 → stagehand-4.2.0a0.dev1558}/src/stagehand/client_models.py +0 -0
- {stagehand-4.2.0a0.dev1556 → stagehand-4.2.0a0.dev1558}/src/stagehand/client_types.py +0 -0
- {stagehand-4.2.0a0.dev1556 → stagehand-4.2.0a0.dev1558}/src/stagehand/extension_assets.py +0 -0
- {stagehand-4.2.0a0.dev1556 → stagehand-4.2.0a0.dev1558}/src/stagehand/file_upload.py +0 -0
- {stagehand-4.2.0a0.dev1556 → stagehand-4.2.0a0.dev1558}/src/stagehand/locator.py +0 -0
- {stagehand-4.2.0a0.dev1556 → stagehand-4.2.0a0.dev1558}/src/stagehand/page.py +0 -0
- {stagehand-4.2.0a0.dev1556 → stagehand-4.2.0a0.dev1558}/src/stagehand/py.typed +0 -0
- {stagehand-4.2.0a0.dev1556 → stagehand-4.2.0a0.dev1558}/src/stagehand/response.py +0 -0
- {stagehand-4.2.0a0.dev1556 → stagehand-4.2.0a0.dev1558}/src/stagehand/rpc_client.py +0 -0
- {stagehand-4.2.0a0.dev1556 → stagehand-4.2.0a0.dev1558}/src/stagehand/stagehand.py +0 -0
- {stagehand-4.2.0a0.dev1556 → stagehand-4.2.0a0.dev1558}/src/stagehand/timeouts.py +0 -0
- {stagehand-4.2.0a0.dev1556 → stagehand-4.2.0a0.dev1558}/src/stagehand/webmcp.py +0 -0
{stagehand-4.2.0a0.dev1556 → stagehand-4.2.0a0.dev1558}/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-173fe1ff6dae5dcadf512a16a41770e16f453330",
|
|
7367
7367
|
"private": true,
|
|
7368
7368
|
type: "module",
|
|
7369
7369
|
exports: {
|
|
@@ -15331,16 +15331,16 @@ var Locator = class Locator {
|
|
|
15331
15331
|
* Resolve all matching nodes for this locator.
|
|
15332
15332
|
* If the locator is narrowed via nth(), only that index is returned.
|
|
15333
15333
|
*/
|
|
15334
|
-
async resolveNodesForMask() {
|
|
15334
|
+
async resolveNodesForMask(progress) {
|
|
15335
15335
|
const session = this.frame.session;
|
|
15336
|
-
await session.send("Runtime.enable");
|
|
15337
|
-
await session.send("DOM.enable");
|
|
15336
|
+
await progress.run("enabling runtime", () => session.send("Runtime.enable"));
|
|
15337
|
+
await progress.run("enabling DOM", () => session.send("DOM.enable"));
|
|
15338
15338
|
if (this.nthIndex >= 0) {
|
|
15339
|
-
const resolved = await this.selectorResolver.resolveAtIndex(this.selectorQuery, this.nthIndex);
|
|
15339
|
+
const resolved = await this.selectorResolver.resolveAtIndex(this.selectorQuery, this.nthIndex, progress);
|
|
15340
15340
|
if (!resolved) throw new Error(`Could not find an element for the given xPath(s): ${this.selector}`);
|
|
15341
15341
|
return [resolved];
|
|
15342
15342
|
}
|
|
15343
|
-
const resolved = await this.selectorResolver.resolveAll(this.selectorQuery);
|
|
15343
|
+
const resolved = await this.selectorResolver.resolveAll(this.selectorQuery, {}, progress);
|
|
15344
15344
|
if (!resolved.length) throw new Error(`Could not find an element for the given xPath(s): ${this.selector}`);
|
|
15345
15345
|
return resolved;
|
|
15346
15346
|
}
|
|
@@ -16930,419 +16930,6 @@ async function act$1(params) {
|
|
|
16930
16930
|
};
|
|
16931
16931
|
}
|
|
16932
16932
|
//#endregion
|
|
16933
|
-
//#region dom/screenshotScripts/resolveMaskRect.ts
|
|
16934
|
-
function resolveMaskRect(maskToken) {
|
|
16935
|
-
function safeClosest(el, selector) {
|
|
16936
|
-
try {
|
|
16937
|
-
return el && typeof el.closest === "function" ? el.closest(selector) : null;
|
|
16938
|
-
} catch {
|
|
16939
|
-
return null;
|
|
16940
|
-
}
|
|
16941
|
-
}
|
|
16942
|
-
function safeMatches(el, selector) {
|
|
16943
|
-
try {
|
|
16944
|
-
return !!el && typeof el.matches === "function" && el.matches(selector);
|
|
16945
|
-
} catch {
|
|
16946
|
-
return false;
|
|
16947
|
-
}
|
|
16948
|
-
}
|
|
16949
|
-
function findTopLayerRoot(el) {
|
|
16950
|
-
const dialog = safeClosest(el, "dialog[open]");
|
|
16951
|
-
if (dialog) return dialog;
|
|
16952
|
-
const popover = safeClosest(el, "[popover]");
|
|
16953
|
-
if (popover && safeMatches(popover, ":popover-open")) return popover;
|
|
16954
|
-
return null;
|
|
16955
|
-
}
|
|
16956
|
-
if (!this || typeof this.getBoundingClientRect !== "function") return null;
|
|
16957
|
-
const rect = this.getBoundingClientRect();
|
|
16958
|
-
if (!rect) return null;
|
|
16959
|
-
const style = window.getComputedStyle(this);
|
|
16960
|
-
if (!style) return null;
|
|
16961
|
-
if (style.visibility === "hidden" || style.display === "none") return null;
|
|
16962
|
-
if (rect.width <= 0 || rect.height <= 0) return null;
|
|
16963
|
-
const root = findTopLayerRoot(this);
|
|
16964
|
-
if (root) {
|
|
16965
|
-
const rootRect = root.getBoundingClientRect();
|
|
16966
|
-
const rootClientLeft = root.clientLeft || 0;
|
|
16967
|
-
const rootClientTop = root.clientTop || 0;
|
|
16968
|
-
const rootScrollLeft = root.scrollLeft || 0;
|
|
16969
|
-
const rootScrollTop = root.scrollTop || 0;
|
|
16970
|
-
let localRect = {
|
|
16971
|
-
x: rect.left - rootRect.left - rootClientLeft + rootScrollLeft,
|
|
16972
|
-
y: rect.top - rootRect.top - rootClientTop + rootScrollTop,
|
|
16973
|
-
width: rect.width,
|
|
16974
|
-
height: rect.height
|
|
16975
|
-
};
|
|
16976
|
-
try {
|
|
16977
|
-
const rootElement = root;
|
|
16978
|
-
const transformProperties = [
|
|
16979
|
-
"transform",
|
|
16980
|
-
"translate",
|
|
16981
|
-
"rotate",
|
|
16982
|
-
"scale"
|
|
16983
|
-
];
|
|
16984
|
-
const previous = transformProperties.map((property) => ({
|
|
16985
|
-
property,
|
|
16986
|
-
value: rootElement.style.getPropertyValue(property),
|
|
16987
|
-
priority: rootElement.style.getPropertyPriority(property)
|
|
16988
|
-
}));
|
|
16989
|
-
const previousTransition = {
|
|
16990
|
-
value: rootElement.style.getPropertyValue("transition"),
|
|
16991
|
-
priority: rootElement.style.getPropertyPriority("transition")
|
|
16992
|
-
};
|
|
16993
|
-
const previousWillChange = {
|
|
16994
|
-
value: rootElement.style.getPropertyValue("will-change"),
|
|
16995
|
-
priority: rootElement.style.getPropertyPriority("will-change")
|
|
16996
|
-
};
|
|
16997
|
-
try {
|
|
16998
|
-
rootElement.style.setProperty("transition", "none", "important");
|
|
16999
|
-
rootElement.style.setProperty("will-change", "transform", "important");
|
|
17000
|
-
root.getBoundingClientRect();
|
|
17001
|
-
for (const property of transformProperties) rootElement.style.setProperty(property, "none", "important");
|
|
17002
|
-
const untransformedRootRect = root.getBoundingClientRect();
|
|
17003
|
-
const untransformedTargetRect = this.getBoundingClientRect();
|
|
17004
|
-
if (untransformedTargetRect.width > 0 && untransformedTargetRect.height > 0 && Number.isFinite(untransformedRootRect.left) && Number.isFinite(untransformedRootRect.top)) {
|
|
17005
|
-
const maskBleed = 3;
|
|
17006
|
-
localRect = {
|
|
17007
|
-
x: untransformedTargetRect.left - untransformedRootRect.left - rootClientLeft + rootScrollLeft - maskBleed,
|
|
17008
|
-
y: untransformedTargetRect.top - untransformedRootRect.top - rootClientTop + rootScrollTop - maskBleed,
|
|
17009
|
-
width: untransformedTargetRect.width + maskBleed * 2,
|
|
17010
|
-
height: untransformedTargetRect.height + maskBleed * 2
|
|
17011
|
-
};
|
|
17012
|
-
}
|
|
17013
|
-
} finally {
|
|
17014
|
-
for (const { property, value, priority } of previous) if (value) rootElement.style.setProperty(property, value, priority);
|
|
17015
|
-
else rootElement.style.removeProperty(property);
|
|
17016
|
-
if (previousWillChange.value) rootElement.style.setProperty("will-change", previousWillChange.value, previousWillChange.priority);
|
|
17017
|
-
else rootElement.style.removeProperty("will-change");
|
|
17018
|
-
root.getBoundingClientRect();
|
|
17019
|
-
if (previousTransition.value) rootElement.style.setProperty("transition", previousTransition.value, previousTransition.priority);
|
|
17020
|
-
else rootElement.style.removeProperty("transition");
|
|
17021
|
-
}
|
|
17022
|
-
} catch {}
|
|
17023
|
-
let rootToken = null;
|
|
17024
|
-
if (maskToken) try {
|
|
17025
|
-
const existing = root.getAttribute("data-stagehand-mask-root");
|
|
17026
|
-
if (existing && existing.startsWith(maskToken)) rootToken = existing;
|
|
17027
|
-
else {
|
|
17028
|
-
rootToken = maskToken + "_root_" + Math.random().toString(36).slice(2);
|
|
17029
|
-
root.setAttribute("data-stagehand-mask-root", rootToken);
|
|
17030
|
-
}
|
|
17031
|
-
} catch {
|
|
17032
|
-
rootToken = null;
|
|
17033
|
-
}
|
|
17034
|
-
return {
|
|
17035
|
-
...localRect,
|
|
17036
|
-
rootToken,
|
|
17037
|
-
position: style.position === "fixed" ? "fixed" : "absolute"
|
|
17038
|
-
};
|
|
17039
|
-
}
|
|
17040
|
-
return {
|
|
17041
|
-
x: rect.left + window.scrollX,
|
|
17042
|
-
y: rect.top + window.scrollY,
|
|
17043
|
-
width: rect.width,
|
|
17044
|
-
height: rect.height,
|
|
17045
|
-
rootToken: null
|
|
17046
|
-
};
|
|
17047
|
-
}
|
|
17048
|
-
//#endregion
|
|
17049
|
-
//#region understudy/screenshotUtils.ts
|
|
17050
|
-
var screenshotQueues = /* @__PURE__ */ new WeakMap();
|
|
17051
|
-
/** Serialize page mutations, or the browser-wide activation/capture critical section. */
|
|
17052
|
-
async function withScreenshotLock(owner, capture, timeout, operation = "screenshot") {
|
|
17053
|
-
const queue = screenshotQueues.get(owner) ?? {
|
|
17054
|
-
tail: Promise.resolve(),
|
|
17055
|
-
blocked: new AbortController()
|
|
17056
|
-
};
|
|
17057
|
-
queue.blocked.signal.throwIfAborted();
|
|
17058
|
-
const controller = new AbortController();
|
|
17059
|
-
let started = false;
|
|
17060
|
-
const timer = typeof timeout === "number" && Number.isFinite(timeout) && timeout > 0 ? setTimeout(() => {
|
|
17061
|
-
const error = new TimeoutError(operation, timeout);
|
|
17062
|
-
controller.abort(error);
|
|
17063
|
-
if (started) queue.blocked.abort(new Error(`A previous capture is still recovering: ${error.message}`, { cause: error }));
|
|
17064
|
-
}, Math.min(timeout, 2147483647)) : void 0;
|
|
17065
|
-
const pending = queue.tail.then(() => {
|
|
17066
|
-
queue.blocked.signal.throwIfAborted();
|
|
17067
|
-
controller.signal.throwIfAborted();
|
|
17068
|
-
started = true;
|
|
17069
|
-
return capture(controller.signal);
|
|
17070
|
-
});
|
|
17071
|
-
const released = pending.then(() => {}, () => {});
|
|
17072
|
-
queue.tail = released;
|
|
17073
|
-
screenshotQueues.set(owner, queue);
|
|
17074
|
-
try {
|
|
17075
|
-
return await waitForScreenshot(waitForScreenshot(pending, queue.blocked.signal), controller.signal);
|
|
17076
|
-
} finally {
|
|
17077
|
-
if (timer !== void 0) clearTimeout(timer);
|
|
17078
|
-
released.then(() => {
|
|
17079
|
-
if (queue.tail === released) screenshotQueues.delete(owner);
|
|
17080
|
-
});
|
|
17081
|
-
}
|
|
17082
|
-
}
|
|
17083
|
-
/** Stop waiting for a stalled CDP capture; its eventual response cannot resume cleanup. */
|
|
17084
|
-
async function waitForScreenshot(pending, signal) {
|
|
17085
|
-
if (!signal) return await pending;
|
|
17086
|
-
return await new Promise((resolve, reject) => {
|
|
17087
|
-
const onAbort = () => {
|
|
17088
|
-
signal.removeEventListener("abort", onAbort);
|
|
17089
|
-
reject(signal.reason);
|
|
17090
|
-
};
|
|
17091
|
-
if (signal.aborted) onAbort();
|
|
17092
|
-
else signal.addEventListener("abort", onAbort, { once: true });
|
|
17093
|
-
pending.then((value) => {
|
|
17094
|
-
signal.removeEventListener("abort", onAbort);
|
|
17095
|
-
resolve(value);
|
|
17096
|
-
}, (error) => {
|
|
17097
|
-
signal.removeEventListener("abort", onAbort);
|
|
17098
|
-
reject(error);
|
|
17099
|
-
});
|
|
17100
|
-
});
|
|
17101
|
-
}
|
|
17102
|
-
function collectFramesForScreenshot(page) {
|
|
17103
|
-
const seen = /* @__PURE__ */ new Map();
|
|
17104
|
-
const main = page.mainFrame();
|
|
17105
|
-
seen.set(main.frameId, main);
|
|
17106
|
-
for (const frame of page.frames()) seen.set(frame.frameId, frame);
|
|
17107
|
-
return Array.from(seen.values());
|
|
17108
|
-
}
|
|
17109
|
-
function normalizeScreenshotClip(clip) {
|
|
17110
|
-
const x = Number(clip.x);
|
|
17111
|
-
const y = Number(clip.y);
|
|
17112
|
-
const width = Number(clip.width);
|
|
17113
|
-
const height = Number(clip.height);
|
|
17114
|
-
for (const [key, value] of Object.entries({
|
|
17115
|
-
x,
|
|
17116
|
-
y,
|
|
17117
|
-
width,
|
|
17118
|
-
height
|
|
17119
|
-
})) if (!Number.isFinite(value)) throw new RangeError(`screenshot: clip.${key} must be a finite number`);
|
|
17120
|
-
if (width <= 0 || height <= 0) throw new RangeError("screenshot: clip width/height must be positive");
|
|
17121
|
-
return {
|
|
17122
|
-
x,
|
|
17123
|
-
y,
|
|
17124
|
-
width,
|
|
17125
|
-
height
|
|
17126
|
-
};
|
|
17127
|
-
}
|
|
17128
|
-
async function computeScreenshotScale(page, mode) {
|
|
17129
|
-
if (mode !== "css") return void 0;
|
|
17130
|
-
try {
|
|
17131
|
-
const dpr = await page.mainFrame().evaluate(() => {
|
|
17132
|
-
const ratio = Number(window.devicePixelRatio || 1);
|
|
17133
|
-
return Number.isFinite(ratio) && ratio > 0 ? ratio : 1;
|
|
17134
|
-
}).catch(() => 1);
|
|
17135
|
-
return Math.min(2, Math.max(.1, 1 / (Number.isFinite(dpr) && dpr > 0 ? dpr : 1)));
|
|
17136
|
-
} catch {
|
|
17137
|
-
return 1;
|
|
17138
|
-
}
|
|
17139
|
-
}
|
|
17140
|
-
async function setTransparentBackground(session) {
|
|
17141
|
-
await session.send("Emulation.setDefaultBackgroundColorOverride", { color: {
|
|
17142
|
-
r: 0,
|
|
17143
|
-
g: 0,
|
|
17144
|
-
b: 0,
|
|
17145
|
-
a: 0
|
|
17146
|
-
} }).catch(() => {});
|
|
17147
|
-
return async () => {
|
|
17148
|
-
await session.send("Emulation.setDefaultBackgroundColorOverride", {}).catch(() => {});
|
|
17149
|
-
};
|
|
17150
|
-
}
|
|
17151
|
-
async function applyStyleToFrames(frames, css, label) {
|
|
17152
|
-
const trimmed = css.trim();
|
|
17153
|
-
if (!trimmed) return async () => {};
|
|
17154
|
-
const token = `__v3_style_${label}_${Date.now()}_${Math.random().toString(36).slice(2)}`;
|
|
17155
|
-
await Promise.all(frames.map((frame) => frame.evaluate(({ css, token }) => {
|
|
17156
|
-
try {
|
|
17157
|
-
const doc = document;
|
|
17158
|
-
if (!doc) return;
|
|
17159
|
-
const style = doc.createElement("style");
|
|
17160
|
-
style.setAttribute("data-stagehand-style", token);
|
|
17161
|
-
style.textContent = css;
|
|
17162
|
-
(doc.head || doc.documentElement || doc.body)?.appendChild(style);
|
|
17163
|
-
} catch {}
|
|
17164
|
-
}, {
|
|
17165
|
-
css: trimmed,
|
|
17166
|
-
token
|
|
17167
|
-
}).catch(() => {})));
|
|
17168
|
-
return async () => {
|
|
17169
|
-
await Promise.all(frames.map((frame) => frame.evaluate((token) => {
|
|
17170
|
-
try {
|
|
17171
|
-
const doc = document;
|
|
17172
|
-
if (!doc) return;
|
|
17173
|
-
doc.querySelectorAll(`[data-stagehand-style="${token}"]`).forEach((node) => node.remove());
|
|
17174
|
-
} catch {}
|
|
17175
|
-
}, token).catch(() => {})));
|
|
17176
|
-
};
|
|
17177
|
-
}
|
|
17178
|
-
async function disableAnimations(frames) {
|
|
17179
|
-
const cleanup = await applyStyleToFrames(frames, `
|
|
17180
|
-
*,
|
|
17181
|
-
*::before,
|
|
17182
|
-
*::after {
|
|
17183
|
-
animation-delay: 0s !important;
|
|
17184
|
-
animation-duration: 0s !important;
|
|
17185
|
-
animation-iteration-count: 1 !important;
|
|
17186
|
-
animation-play-state: paused !important;
|
|
17187
|
-
transition-property: none !important;
|
|
17188
|
-
transition-duration: 0s !important;
|
|
17189
|
-
transition-delay: 0s !important;
|
|
17190
|
-
}`, "animations");
|
|
17191
|
-
await Promise.all(frames.map((frame) => frame.evaluate(() => {
|
|
17192
|
-
try {
|
|
17193
|
-
const animations = typeof document.getAnimations === "function" ? document.getAnimations() : [];
|
|
17194
|
-
for (const animation of animations) try {
|
|
17195
|
-
const details = animation.effect?.getComputedTiming?.();
|
|
17196
|
-
if (details && details.iterations !== Infinity) animation.finish?.();
|
|
17197
|
-
else animation.cancel?.();
|
|
17198
|
-
} catch {
|
|
17199
|
-
animation.cancel?.();
|
|
17200
|
-
}
|
|
17201
|
-
} catch {}
|
|
17202
|
-
}).catch(() => {})));
|
|
17203
|
-
return cleanup;
|
|
17204
|
-
}
|
|
17205
|
-
async function hideCaret(frames) {
|
|
17206
|
-
return applyStyleToFrames(frames, `
|
|
17207
|
-
input,
|
|
17208
|
-
textarea,
|
|
17209
|
-
[contenteditable],
|
|
17210
|
-
[contenteditable=""],
|
|
17211
|
-
[contenteditable="true"],
|
|
17212
|
-
[contenteditable="plaintext-only"],
|
|
17213
|
-
*:focus {
|
|
17214
|
-
caret-color: transparent !important;
|
|
17215
|
-
}`, "caret");
|
|
17216
|
-
}
|
|
17217
|
-
async function applyMaskOverlays(locators, color) {
|
|
17218
|
-
const rectsByFrame = /* @__PURE__ */ new Map();
|
|
17219
|
-
const token = `__v3_mask_${Date.now()}_${Math.random().toString(36).slice(2)}`;
|
|
17220
|
-
for (const locator of locators) try {
|
|
17221
|
-
const info = await resolveMaskRects("real" in locator ? await locator.real() : locator, token);
|
|
17222
|
-
if (!info) continue;
|
|
17223
|
-
const entry = rectsByFrame.get(info.frame) ?? {
|
|
17224
|
-
rects: [],
|
|
17225
|
-
rootTokens: /* @__PURE__ */ new Set()
|
|
17226
|
-
};
|
|
17227
|
-
entry.rects.push(...info.rects);
|
|
17228
|
-
for (const rect of info.rects) if (rect.rootToken) entry.rootTokens.add(rect.rootToken);
|
|
17229
|
-
rectsByFrame.set(info.frame, entry);
|
|
17230
|
-
} catch {}
|
|
17231
|
-
if (rectsByFrame.size === 0) return async () => {};
|
|
17232
|
-
await Promise.all(Array.from(rectsByFrame.entries()).map(([frame, { rects }]) => frame.evaluate(({ rects, color, token }) => {
|
|
17233
|
-
try {
|
|
17234
|
-
const doc = document;
|
|
17235
|
-
if (!doc) return;
|
|
17236
|
-
for (const rect of rects) {
|
|
17237
|
-
const defaultRoot = doc.documentElement || doc.body;
|
|
17238
|
-
if (!defaultRoot) return;
|
|
17239
|
-
const root = rect.rootToken ? doc.querySelector(`[data-stagehand-mask-root="${rect.rootToken}"]`) || defaultRoot : defaultRoot;
|
|
17240
|
-
if (!root) continue;
|
|
17241
|
-
if (rect.rootToken) try {
|
|
17242
|
-
const style = window.getComputedStyle(root);
|
|
17243
|
-
if (style && style.position === "static") {
|
|
17244
|
-
const rootEl = root;
|
|
17245
|
-
if (!rootEl.hasAttribute("data-stagehand-mask-root-pos")) rootEl.setAttribute("data-stagehand-mask-root-pos", rootEl.style.position || "");
|
|
17246
|
-
rootEl.style.position = "relative";
|
|
17247
|
-
}
|
|
17248
|
-
} catch {}
|
|
17249
|
-
const el = doc.createElement("div");
|
|
17250
|
-
el.setAttribute("data-stagehand-mask", token);
|
|
17251
|
-
el.style.position = rect.position ?? "absolute";
|
|
17252
|
-
el.style.left = `${rect.x}px`;
|
|
17253
|
-
el.style.top = `${rect.y}px`;
|
|
17254
|
-
el.style.width = `${rect.width}px`;
|
|
17255
|
-
el.style.height = `${rect.height}px`;
|
|
17256
|
-
el.style.backgroundColor = color;
|
|
17257
|
-
el.style.pointerEvents = "none";
|
|
17258
|
-
el.style.zIndex = "2147483647";
|
|
17259
|
-
el.style.opacity = "1";
|
|
17260
|
-
el.style.mixBlendMode = "normal";
|
|
17261
|
-
root.appendChild(el);
|
|
17262
|
-
}
|
|
17263
|
-
} catch {}
|
|
17264
|
-
}, {
|
|
17265
|
-
rects,
|
|
17266
|
-
color,
|
|
17267
|
-
token
|
|
17268
|
-
}).catch(() => {})));
|
|
17269
|
-
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
17270
|
-
return async () => {
|
|
17271
|
-
await Promise.all(Array.from(rectsByFrame.entries()).map(([frame, { rootTokens }]) => frame.evaluate(({ token, rootTokens }) => {
|
|
17272
|
-
try {
|
|
17273
|
-
const doc = document;
|
|
17274
|
-
if (!doc) return;
|
|
17275
|
-
doc.querySelectorAll(`[data-stagehand-mask="${token}"]`).forEach((node) => node.remove());
|
|
17276
|
-
for (const rootToken of rootTokens) {
|
|
17277
|
-
const root = doc.querySelector(`[data-stagehand-mask-root="${rootToken}"]`);
|
|
17278
|
-
if (!root) continue;
|
|
17279
|
-
const prev = root.getAttribute("data-stagehand-mask-root-pos");
|
|
17280
|
-
if (prev !== null) {
|
|
17281
|
-
root.style.position = prev;
|
|
17282
|
-
root.removeAttribute("data-stagehand-mask-root-pos");
|
|
17283
|
-
}
|
|
17284
|
-
root.removeAttribute("data-stagehand-mask-root");
|
|
17285
|
-
}
|
|
17286
|
-
} catch {}
|
|
17287
|
-
}, {
|
|
17288
|
-
token,
|
|
17289
|
-
rootTokens: Array.from(rootTokens)
|
|
17290
|
-
}).catch(() => {})));
|
|
17291
|
-
};
|
|
17292
|
-
}
|
|
17293
|
-
async function resolveMaskRects(locator, maskToken) {
|
|
17294
|
-
const frame = locator.getFrame();
|
|
17295
|
-
const session = frame.session;
|
|
17296
|
-
try {
|
|
17297
|
-
const resolved = await locator.resolveNodesForMask();
|
|
17298
|
-
const rects = [];
|
|
17299
|
-
for (const { objectId } of resolved) try {
|
|
17300
|
-
const rect = await resolveMaskRectForObject(session, objectId, maskToken);
|
|
17301
|
-
if (rect) rects.push(rect);
|
|
17302
|
-
} catch {} finally {
|
|
17303
|
-
await session.send("Runtime.releaseObject", { objectId }).catch(() => {});
|
|
17304
|
-
}
|
|
17305
|
-
if (!rects.length) return null;
|
|
17306
|
-
return {
|
|
17307
|
-
frame,
|
|
17308
|
-
rects
|
|
17309
|
-
};
|
|
17310
|
-
} catch {
|
|
17311
|
-
return null;
|
|
17312
|
-
}
|
|
17313
|
-
}
|
|
17314
|
-
async function resolveMaskRectForObject(session, objectId, maskToken) {
|
|
17315
|
-
const result = await session.send("Runtime.callFunctionOn", {
|
|
17316
|
-
objectId,
|
|
17317
|
-
functionDeclaration: resolveMaskRect.toString(),
|
|
17318
|
-
arguments: [{ value: maskToken }],
|
|
17319
|
-
returnByValue: true
|
|
17320
|
-
});
|
|
17321
|
-
if (result.exceptionDetails) return null;
|
|
17322
|
-
const rect = result.result.value;
|
|
17323
|
-
if (!rect) return null;
|
|
17324
|
-
const { x, y, width, height } = rect;
|
|
17325
|
-
if (!Number.isFinite(x) || !Number.isFinite(y) || !Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0) return null;
|
|
17326
|
-
return {
|
|
17327
|
-
x,
|
|
17328
|
-
y,
|
|
17329
|
-
width,
|
|
17330
|
-
height,
|
|
17331
|
-
rootToken: rect.rootToken && typeof rect.rootToken === "string" ? rect.rootToken : void 0,
|
|
17332
|
-
position: rect.position === "fixed" ? "fixed" : "absolute"
|
|
17333
|
-
};
|
|
17334
|
-
}
|
|
17335
|
-
async function runScreenshotCleanups(cleanups) {
|
|
17336
|
-
for (let i = cleanups.length - 1; i >= 0; i -= 1) {
|
|
17337
|
-
const fn = cleanups[i];
|
|
17338
|
-
if (!fn) continue;
|
|
17339
|
-
try {
|
|
17340
|
-
const result = fn();
|
|
17341
|
-
if (result && typeof result.then === "function") await result;
|
|
17342
|
-
} catch {}
|
|
17343
|
-
}
|
|
17344
|
-
}
|
|
17345
|
-
//#endregion
|
|
17346
16933
|
//#region understudy/frame.ts
|
|
17347
16934
|
function base64ToBytes$1(base64) {
|
|
17348
16935
|
const binary = globalThis.atob(base64);
|
|
@@ -17422,10 +17009,13 @@ var Frame = class Frame {
|
|
|
17422
17009
|
* Evaluate a function or expression in this frame's main world.
|
|
17423
17010
|
* - If a string is provided, treated as a JS expression.
|
|
17424
17011
|
* - If a function is provided, it is stringified and invoked with the optional argument.
|
|
17012
|
+
* Progress guards dispatch, but issued evaluations are awaited so screenshot
|
|
17013
|
+
* restoration cannot run before a late page mutation finishes.
|
|
17425
17014
|
*/
|
|
17426
|
-
async evaluate(pageFunctionOrExpression, arg) {
|
|
17015
|
+
async evaluate(pageFunctionOrExpression, arg, progress) {
|
|
17016
|
+
progress?.throwIfStopped();
|
|
17427
17017
|
await this.session.send("Runtime.enable").catch(() => {});
|
|
17428
|
-
const contextId = await this.getMainWorldExecutionContextId();
|
|
17018
|
+
const contextId = await this.getMainWorldExecutionContextId(progress);
|
|
17429
17019
|
const isString = typeof pageFunctionOrExpression === "string";
|
|
17430
17020
|
let expression;
|
|
17431
17021
|
if (isString) expression = String(pageFunctionOrExpression);
|
|
@@ -17441,6 +17031,7 @@ var Frame = class Frame {
|
|
|
17441
17031
|
})()`;
|
|
17442
17032
|
let res;
|
|
17443
17033
|
try {
|
|
17034
|
+
progress?.throwIfStopped();
|
|
17444
17035
|
res = await this.session.send("Runtime.evaluate", {
|
|
17445
17036
|
expression,
|
|
17446
17037
|
contextId,
|
|
@@ -17449,7 +17040,8 @@ var Frame = class Frame {
|
|
|
17449
17040
|
});
|
|
17450
17041
|
} catch (error) {
|
|
17451
17042
|
if (!(error instanceof Error ? error.message : String(error)).includes("Cannot find context with specified id")) throw error;
|
|
17452
|
-
const freshContextId = await this.getMainWorldExecutionContextId();
|
|
17043
|
+
const freshContextId = await this.getMainWorldExecutionContextId(progress);
|
|
17044
|
+
progress?.throwIfStopped();
|
|
17453
17045
|
res = await this.session.send("Runtime.evaluate", {
|
|
17454
17046
|
expression,
|
|
17455
17047
|
contextId: freshContextId,
|
|
@@ -17490,10 +17082,9 @@ var Frame = class Frame {
|
|
|
17490
17082
|
return response.result.value;
|
|
17491
17083
|
}
|
|
17492
17084
|
/** Page.captureScreenshot (frame-scoped session) */
|
|
17493
|
-
async screenshot(options) {
|
|
17494
|
-
|
|
17495
|
-
|
|
17496
|
-
await waitForScreenshot(this.session.send("Page.enable"), signal);
|
|
17085
|
+
async screenshot(options, progress) {
|
|
17086
|
+
progress.throwIfStopped();
|
|
17087
|
+
await this.session.send("Page.enable");
|
|
17497
17088
|
const format = options?.type ?? "png";
|
|
17498
17089
|
const params = {
|
|
17499
17090
|
format,
|
|
@@ -17514,8 +17105,11 @@ var Frame = class Frame {
|
|
|
17514
17105
|
const q = Math.round(options.quality);
|
|
17515
17106
|
params.quality = Math.min(100, Math.max(0, q));
|
|
17516
17107
|
}
|
|
17517
|
-
|
|
17518
|
-
|
|
17108
|
+
progress.throwIfStopped();
|
|
17109
|
+
await this.session.send("Page.bringToFront");
|
|
17110
|
+
progress.throwIfStopped();
|
|
17111
|
+
const { data } = await this.session.send("Page.captureScreenshot", params);
|
|
17112
|
+
progress.throwIfStopped();
|
|
17519
17113
|
return base64ToBytes$1(data);
|
|
17520
17114
|
}
|
|
17521
17115
|
/** Child frames via Page.getFrameTree */
|
|
@@ -17566,8 +17160,8 @@ var Frame = class Frame {
|
|
|
17566
17160
|
return new Locator(this, selector, options);
|
|
17567
17161
|
}
|
|
17568
17162
|
/** Resolve the main-world execution context id for this frame. */
|
|
17569
|
-
async getMainWorldExecutionContextId() {
|
|
17570
|
-
return executionContexts.waitForMainWorld(this.session, this.frameId, 1e3);
|
|
17163
|
+
async getMainWorldExecutionContextId(progress) {
|
|
17164
|
+
return executionContexts.waitForMainWorld(this.session, this.frameId, 1e3, progress);
|
|
17571
17165
|
}
|
|
17572
17166
|
async getExtensionWorldExecutionContextId() {
|
|
17573
17167
|
return executionContexts.waitForExtensionWorld(this.session, this.frameId, 1e3);
|
|
@@ -54725,7 +54319,7 @@ var WebTracerProvider = class extends BasicTracerProvider {
|
|
|
54725
54319
|
};
|
|
54726
54320
|
var package_default = {
|
|
54727
54321
|
name: "@browserbasehq/stagehand-extension",
|
|
54728
|
-
version: "1.1.0-alpha-
|
|
54322
|
+
version: "1.1.0-alpha-173fe1ff6dae5dcadf512a16a41770e16f453330",
|
|
54729
54323
|
"private": true,
|
|
54730
54324
|
type: "module",
|
|
54731
54325
|
scripts: {
|
|
@@ -56120,6 +55714,423 @@ async function normalizeInitScriptSource(script, arg, caller = DEFAULT_CALLER) {
|
|
|
56120
55714
|
throw new TypeError(`${caller}: provide a string, function, or an object with content.`);
|
|
56121
55715
|
}
|
|
56122
55716
|
//#endregion
|
|
55717
|
+
//#region dom/screenshotScripts/resolveMaskRect.ts
|
|
55718
|
+
function resolveMaskRect(maskToken) {
|
|
55719
|
+
function safeClosest(el, selector) {
|
|
55720
|
+
try {
|
|
55721
|
+
return el && typeof el.closest === "function" ? el.closest(selector) : null;
|
|
55722
|
+
} catch {
|
|
55723
|
+
return null;
|
|
55724
|
+
}
|
|
55725
|
+
}
|
|
55726
|
+
function safeMatches(el, selector) {
|
|
55727
|
+
try {
|
|
55728
|
+
return !!el && typeof el.matches === "function" && el.matches(selector);
|
|
55729
|
+
} catch {
|
|
55730
|
+
return false;
|
|
55731
|
+
}
|
|
55732
|
+
}
|
|
55733
|
+
function findTopLayerRoot(el) {
|
|
55734
|
+
const dialog = safeClosest(el, "dialog[open]");
|
|
55735
|
+
if (dialog) return dialog;
|
|
55736
|
+
const popover = safeClosest(el, "[popover]");
|
|
55737
|
+
if (popover && safeMatches(popover, ":popover-open")) return popover;
|
|
55738
|
+
return null;
|
|
55739
|
+
}
|
|
55740
|
+
if (!this || typeof this.getBoundingClientRect !== "function") return null;
|
|
55741
|
+
const rect = this.getBoundingClientRect();
|
|
55742
|
+
if (!rect) return null;
|
|
55743
|
+
const style = window.getComputedStyle(this);
|
|
55744
|
+
if (!style) return null;
|
|
55745
|
+
if (style.visibility === "hidden" || style.display === "none") return null;
|
|
55746
|
+
if (rect.width <= 0 || rect.height <= 0) return null;
|
|
55747
|
+
const root = findTopLayerRoot(this);
|
|
55748
|
+
if (root) {
|
|
55749
|
+
const rootRect = root.getBoundingClientRect();
|
|
55750
|
+
const rootClientLeft = root.clientLeft || 0;
|
|
55751
|
+
const rootClientTop = root.clientTop || 0;
|
|
55752
|
+
const rootScrollLeft = root.scrollLeft || 0;
|
|
55753
|
+
const rootScrollTop = root.scrollTop || 0;
|
|
55754
|
+
let localRect = {
|
|
55755
|
+
x: rect.left - rootRect.left - rootClientLeft + rootScrollLeft,
|
|
55756
|
+
y: rect.top - rootRect.top - rootClientTop + rootScrollTop,
|
|
55757
|
+
width: rect.width,
|
|
55758
|
+
height: rect.height
|
|
55759
|
+
};
|
|
55760
|
+
try {
|
|
55761
|
+
const rootElement = root;
|
|
55762
|
+
const transformProperties = [
|
|
55763
|
+
"transform",
|
|
55764
|
+
"translate",
|
|
55765
|
+
"rotate",
|
|
55766
|
+
"scale"
|
|
55767
|
+
];
|
|
55768
|
+
const previous = transformProperties.map((property) => ({
|
|
55769
|
+
property,
|
|
55770
|
+
value: rootElement.style.getPropertyValue(property),
|
|
55771
|
+
priority: rootElement.style.getPropertyPriority(property)
|
|
55772
|
+
}));
|
|
55773
|
+
const previousTransition = {
|
|
55774
|
+
value: rootElement.style.getPropertyValue("transition"),
|
|
55775
|
+
priority: rootElement.style.getPropertyPriority("transition")
|
|
55776
|
+
};
|
|
55777
|
+
const previousWillChange = {
|
|
55778
|
+
value: rootElement.style.getPropertyValue("will-change"),
|
|
55779
|
+
priority: rootElement.style.getPropertyPriority("will-change")
|
|
55780
|
+
};
|
|
55781
|
+
try {
|
|
55782
|
+
rootElement.style.setProperty("transition", "none", "important");
|
|
55783
|
+
rootElement.style.setProperty("will-change", "transform", "important");
|
|
55784
|
+
root.getBoundingClientRect();
|
|
55785
|
+
for (const property of transformProperties) rootElement.style.setProperty(property, "none", "important");
|
|
55786
|
+
const untransformedRootRect = root.getBoundingClientRect();
|
|
55787
|
+
const untransformedTargetRect = this.getBoundingClientRect();
|
|
55788
|
+
if (untransformedTargetRect.width > 0 && untransformedTargetRect.height > 0 && Number.isFinite(untransformedRootRect.left) && Number.isFinite(untransformedRootRect.top)) {
|
|
55789
|
+
const maskBleed = 3;
|
|
55790
|
+
localRect = {
|
|
55791
|
+
x: untransformedTargetRect.left - untransformedRootRect.left - rootClientLeft + rootScrollLeft - maskBleed,
|
|
55792
|
+
y: untransformedTargetRect.top - untransformedRootRect.top - rootClientTop + rootScrollTop - maskBleed,
|
|
55793
|
+
width: untransformedTargetRect.width + maskBleed * 2,
|
|
55794
|
+
height: untransformedTargetRect.height + maskBleed * 2
|
|
55795
|
+
};
|
|
55796
|
+
}
|
|
55797
|
+
} finally {
|
|
55798
|
+
for (const { property, value, priority } of previous) if (value) rootElement.style.setProperty(property, value, priority);
|
|
55799
|
+
else rootElement.style.removeProperty(property);
|
|
55800
|
+
if (previousWillChange.value) rootElement.style.setProperty("will-change", previousWillChange.value, previousWillChange.priority);
|
|
55801
|
+
else rootElement.style.removeProperty("will-change");
|
|
55802
|
+
root.getBoundingClientRect();
|
|
55803
|
+
if (previousTransition.value) rootElement.style.setProperty("transition", previousTransition.value, previousTransition.priority);
|
|
55804
|
+
else rootElement.style.removeProperty("transition");
|
|
55805
|
+
}
|
|
55806
|
+
} catch {}
|
|
55807
|
+
let rootToken = null;
|
|
55808
|
+
if (maskToken) try {
|
|
55809
|
+
const existing = root.getAttribute("data-stagehand-mask-root");
|
|
55810
|
+
if (existing && existing.startsWith(maskToken)) rootToken = existing;
|
|
55811
|
+
else {
|
|
55812
|
+
rootToken = maskToken + "_root_" + Math.random().toString(36).slice(2);
|
|
55813
|
+
root.setAttribute("data-stagehand-mask-root", rootToken);
|
|
55814
|
+
}
|
|
55815
|
+
} catch {
|
|
55816
|
+
rootToken = null;
|
|
55817
|
+
}
|
|
55818
|
+
return {
|
|
55819
|
+
...localRect,
|
|
55820
|
+
rootToken,
|
|
55821
|
+
position: style.position === "fixed" ? "fixed" : "absolute"
|
|
55822
|
+
};
|
|
55823
|
+
}
|
|
55824
|
+
return {
|
|
55825
|
+
x: rect.left + window.scrollX,
|
|
55826
|
+
y: rect.top + window.scrollY,
|
|
55827
|
+
width: rect.width,
|
|
55828
|
+
height: rect.height,
|
|
55829
|
+
rootToken: null
|
|
55830
|
+
};
|
|
55831
|
+
}
|
|
55832
|
+
//#endregion
|
|
55833
|
+
//#region understudy/screenshotUtils.ts
|
|
55834
|
+
var screenshotQueues = /* @__PURE__ */ new WeakMap();
|
|
55835
|
+
/** Serialize page mutations, or the browser-wide activation/capture critical section. */
|
|
55836
|
+
async function withScreenshotLock(owner, capture, progress) {
|
|
55837
|
+
progress.throwIfStopped();
|
|
55838
|
+
const queue = screenshotQueues.get(owner) ?? {
|
|
55839
|
+
tail: Promise.resolve(),
|
|
55840
|
+
blocked: new AbortController()
|
|
55841
|
+
};
|
|
55842
|
+
queue.blocked.signal.throwIfAborted();
|
|
55843
|
+
let started = false;
|
|
55844
|
+
const onAbort = () => {
|
|
55845
|
+
if (started) {
|
|
55846
|
+
const error = progress.signal.reason;
|
|
55847
|
+
queue.blocked.abort(new Error(`A previous capture is still recovering: ${error.message}`, { cause: error }));
|
|
55848
|
+
}
|
|
55849
|
+
};
|
|
55850
|
+
progress.signal.addEventListener("abort", onAbort, { once: true });
|
|
55851
|
+
const previous = queue.tail;
|
|
55852
|
+
const pending = waitForScreenshot(previous, AbortSignal.any([queue.blocked.signal, progress.signal])).then(async () => {
|
|
55853
|
+
queue.blocked.signal.throwIfAborted();
|
|
55854
|
+
progress.throwIfStopped();
|
|
55855
|
+
started = true;
|
|
55856
|
+
try {
|
|
55857
|
+
return await capture();
|
|
55858
|
+
} finally {
|
|
55859
|
+
started = false;
|
|
55860
|
+
}
|
|
55861
|
+
});
|
|
55862
|
+
const settled = pending.then(() => {}, () => {});
|
|
55863
|
+
const released = Promise.all([previous, settled]).then(() => {});
|
|
55864
|
+
queue.tail = released;
|
|
55865
|
+
screenshotQueues.set(owner, queue);
|
|
55866
|
+
try {
|
|
55867
|
+
return await pending;
|
|
55868
|
+
} finally {
|
|
55869
|
+
progress.signal.removeEventListener("abort", onAbort);
|
|
55870
|
+
released.then(() => {
|
|
55871
|
+
if (queue.tail === released) screenshotQueues.delete(owner);
|
|
55872
|
+
});
|
|
55873
|
+
}
|
|
55874
|
+
}
|
|
55875
|
+
/** Bound a wait by an operation or queue recovery signal. */
|
|
55876
|
+
async function waitForScreenshot(pending, signal) {
|
|
55877
|
+
if (!signal) return await pending;
|
|
55878
|
+
return await new Promise((resolve, reject) => {
|
|
55879
|
+
const onAbort = () => {
|
|
55880
|
+
signal.removeEventListener("abort", onAbort);
|
|
55881
|
+
reject(signal.reason);
|
|
55882
|
+
};
|
|
55883
|
+
if (signal.aborted) onAbort();
|
|
55884
|
+
else signal.addEventListener("abort", onAbort, { once: true });
|
|
55885
|
+
pending.then((value) => {
|
|
55886
|
+
signal.removeEventListener("abort", onAbort);
|
|
55887
|
+
resolve(value);
|
|
55888
|
+
}, (error) => {
|
|
55889
|
+
signal.removeEventListener("abort", onAbort);
|
|
55890
|
+
reject(error);
|
|
55891
|
+
});
|
|
55892
|
+
});
|
|
55893
|
+
}
|
|
55894
|
+
function collectFramesForScreenshot(page) {
|
|
55895
|
+
const seen = /* @__PURE__ */ new Map();
|
|
55896
|
+
const main = page.mainFrame();
|
|
55897
|
+
seen.set(main.frameId, main);
|
|
55898
|
+
for (const frame of page.frames()) seen.set(frame.frameId, frame);
|
|
55899
|
+
return Array.from(seen.values());
|
|
55900
|
+
}
|
|
55901
|
+
function normalizeScreenshotClip(clip) {
|
|
55902
|
+
const x = Number(clip.x);
|
|
55903
|
+
const y = Number(clip.y);
|
|
55904
|
+
const width = Number(clip.width);
|
|
55905
|
+
const height = Number(clip.height);
|
|
55906
|
+
for (const [key, value] of Object.entries({
|
|
55907
|
+
x,
|
|
55908
|
+
y,
|
|
55909
|
+
width,
|
|
55910
|
+
height
|
|
55911
|
+
})) if (!Number.isFinite(value)) throw new RangeError(`screenshot: clip.${key} must be a finite number`);
|
|
55912
|
+
if (width <= 0 || height <= 0) throw new RangeError("screenshot: clip width/height must be positive");
|
|
55913
|
+
return {
|
|
55914
|
+
x,
|
|
55915
|
+
y,
|
|
55916
|
+
width,
|
|
55917
|
+
height
|
|
55918
|
+
};
|
|
55919
|
+
}
|
|
55920
|
+
async function computeScreenshotScale(page, mode, progress) {
|
|
55921
|
+
if (mode !== "css") return void 0;
|
|
55922
|
+
const dpr = await page.mainFrame().evaluate(() => {
|
|
55923
|
+
const ratio = Number(window.devicePixelRatio || 1);
|
|
55924
|
+
return Number.isFinite(ratio) && ratio > 0 ? ratio : 1;
|
|
55925
|
+
}, void 0, progress).catch(() => {
|
|
55926
|
+
progress.throwIfStopped();
|
|
55927
|
+
return 1;
|
|
55928
|
+
});
|
|
55929
|
+
progress.throwIfStopped();
|
|
55930
|
+
return Math.min(2, Math.max(.1, 1 / (Number.isFinite(dpr) && dpr > 0 ? dpr : 1)));
|
|
55931
|
+
}
|
|
55932
|
+
async function setTransparentBackground(session, progress, cleanups) {
|
|
55933
|
+
progress.throwIfStopped();
|
|
55934
|
+
cleanups.push(async () => {
|
|
55935
|
+
await session.send("Emulation.setDefaultBackgroundColorOverride", {}).catch(() => {});
|
|
55936
|
+
});
|
|
55937
|
+
await session.send("Emulation.setDefaultBackgroundColorOverride", { color: {
|
|
55938
|
+
r: 0,
|
|
55939
|
+
g: 0,
|
|
55940
|
+
b: 0,
|
|
55941
|
+
a: 0
|
|
55942
|
+
} }).catch(() => {});
|
|
55943
|
+
progress.throwIfStopped();
|
|
55944
|
+
}
|
|
55945
|
+
async function applyStyleToFrames(frames, css, label, progress, cleanups) {
|
|
55946
|
+
const trimmed = css.trim();
|
|
55947
|
+
if (!trimmed) return;
|
|
55948
|
+
const token = `__v3_style_${label}_${Date.now()}_${Math.random().toString(36).slice(2)}`;
|
|
55949
|
+
cleanups.push(async () => {
|
|
55950
|
+
await Promise.all(frames.map((frame) => frame.evaluate((token) => {
|
|
55951
|
+
try {
|
|
55952
|
+
const doc = document;
|
|
55953
|
+
if (!doc) return;
|
|
55954
|
+
doc.querySelectorAll(`[data-stagehand-style="${token}"]`).forEach((node) => node.remove());
|
|
55955
|
+
} catch {}
|
|
55956
|
+
}, token).catch(() => {})));
|
|
55957
|
+
});
|
|
55958
|
+
await Promise.all(frames.map((frame) => frame.evaluate(({ css, token }) => {
|
|
55959
|
+
try {
|
|
55960
|
+
const doc = document;
|
|
55961
|
+
if (!doc) return;
|
|
55962
|
+
const style = doc.createElement("style");
|
|
55963
|
+
style.setAttribute("data-stagehand-style", token);
|
|
55964
|
+
style.textContent = css;
|
|
55965
|
+
(doc.head || doc.documentElement || doc.body)?.appendChild(style);
|
|
55966
|
+
} catch {}
|
|
55967
|
+
}, {
|
|
55968
|
+
css: trimmed,
|
|
55969
|
+
token
|
|
55970
|
+
}, progress).catch(() => {})));
|
|
55971
|
+
progress.throwIfStopped();
|
|
55972
|
+
}
|
|
55973
|
+
async function disableAnimations(frames, progress, cleanups) {
|
|
55974
|
+
await applyStyleToFrames(frames, `
|
|
55975
|
+
*,
|
|
55976
|
+
*::before,
|
|
55977
|
+
*::after {
|
|
55978
|
+
animation-delay: 0s !important;
|
|
55979
|
+
animation-duration: 0s !important;
|
|
55980
|
+
animation-iteration-count: 1 !important;
|
|
55981
|
+
animation-play-state: paused !important;
|
|
55982
|
+
transition-property: none !important;
|
|
55983
|
+
transition-duration: 0s !important;
|
|
55984
|
+
transition-delay: 0s !important;
|
|
55985
|
+
}`, "animations", progress, cleanups);
|
|
55986
|
+
await Promise.all(frames.map((frame) => frame.evaluate(() => {
|
|
55987
|
+
try {
|
|
55988
|
+
const animations = typeof document.getAnimations === "function" ? document.getAnimations() : [];
|
|
55989
|
+
for (const animation of animations) try {
|
|
55990
|
+
const details = animation.effect?.getComputedTiming?.();
|
|
55991
|
+
if (details && details.iterations !== Infinity) animation.finish?.();
|
|
55992
|
+
else animation.cancel?.();
|
|
55993
|
+
} catch {
|
|
55994
|
+
animation.cancel?.();
|
|
55995
|
+
}
|
|
55996
|
+
} catch {}
|
|
55997
|
+
}, void 0, progress).catch(() => {})));
|
|
55998
|
+
progress.throwIfStopped();
|
|
55999
|
+
}
|
|
56000
|
+
async function hideCaret(frames, progress, cleanups) {
|
|
56001
|
+
return applyStyleToFrames(frames, `
|
|
56002
|
+
input,
|
|
56003
|
+
textarea,
|
|
56004
|
+
[contenteditable],
|
|
56005
|
+
[contenteditable=""],
|
|
56006
|
+
[contenteditable="true"],
|
|
56007
|
+
[contenteditable="plaintext-only"],
|
|
56008
|
+
*:focus {
|
|
56009
|
+
caret-color: transparent !important;
|
|
56010
|
+
}`, "caret", progress, cleanups);
|
|
56011
|
+
}
|
|
56012
|
+
async function applyMaskOverlays(locators, color, progress, cleanups) {
|
|
56013
|
+
const rectsByFrame = /* @__PURE__ */ new Map();
|
|
56014
|
+
const token = `__v3_mask_${Date.now()}_${Math.random().toString(36).slice(2)}`;
|
|
56015
|
+
cleanups.push(async () => {
|
|
56016
|
+
await Promise.all(Array.from(rectsByFrame.keys()).map((frame) => frame.evaluate((token) => {
|
|
56017
|
+
try {
|
|
56018
|
+
const doc = document;
|
|
56019
|
+
if (!doc) return;
|
|
56020
|
+
doc.querySelectorAll(`[data-stagehand-mask="${token}"]`).forEach((node) => node.remove());
|
|
56021
|
+
const roots = doc.querySelectorAll(`[data-stagehand-mask-root^="${token}"]`);
|
|
56022
|
+
for (const root of roots) {
|
|
56023
|
+
const prev = root.getAttribute("data-stagehand-mask-root-pos");
|
|
56024
|
+
if (prev !== null) {
|
|
56025
|
+
root.style.position = prev;
|
|
56026
|
+
root.removeAttribute("data-stagehand-mask-root-pos");
|
|
56027
|
+
}
|
|
56028
|
+
root.removeAttribute("data-stagehand-mask-root");
|
|
56029
|
+
}
|
|
56030
|
+
} catch {}
|
|
56031
|
+
}, token).catch(() => {})));
|
|
56032
|
+
});
|
|
56033
|
+
for (const locator of locators) try {
|
|
56034
|
+
progress.throwIfStopped();
|
|
56035
|
+
const resolved = "real" in locator ? await locator.real(progress) : locator;
|
|
56036
|
+
const frame = resolved.getFrame();
|
|
56037
|
+
const rects = rectsByFrame.get(frame) ?? [];
|
|
56038
|
+
rectsByFrame.set(frame, rects);
|
|
56039
|
+
rects.push(...await resolveMaskRects(resolved, token, progress));
|
|
56040
|
+
} catch {
|
|
56041
|
+
progress.throwIfStopped();
|
|
56042
|
+
}
|
|
56043
|
+
if ([...rectsByFrame.values()].every((rects) => rects.length === 0)) return;
|
|
56044
|
+
await Promise.all(Array.from(rectsByFrame.entries()).map(([frame, rects]) => frame.evaluate(({ rects, color, token }) => {
|
|
56045
|
+
try {
|
|
56046
|
+
const doc = document;
|
|
56047
|
+
if (!doc) return;
|
|
56048
|
+
for (const rect of rects) {
|
|
56049
|
+
const defaultRoot = doc.documentElement || doc.body;
|
|
56050
|
+
if (!defaultRoot) return;
|
|
56051
|
+
const root = rect.rootToken ? doc.querySelector(`[data-stagehand-mask-root="${rect.rootToken}"]`) || defaultRoot : defaultRoot;
|
|
56052
|
+
if (!root) continue;
|
|
56053
|
+
if (rect.rootToken) try {
|
|
56054
|
+
const style = window.getComputedStyle(root);
|
|
56055
|
+
if (style && style.position === "static") {
|
|
56056
|
+
const rootEl = root;
|
|
56057
|
+
if (!rootEl.hasAttribute("data-stagehand-mask-root-pos")) rootEl.setAttribute("data-stagehand-mask-root-pos", rootEl.style.position || "");
|
|
56058
|
+
rootEl.style.position = "relative";
|
|
56059
|
+
}
|
|
56060
|
+
} catch {}
|
|
56061
|
+
const el = doc.createElement("div");
|
|
56062
|
+
el.setAttribute("data-stagehand-mask", token);
|
|
56063
|
+
el.style.position = rect.position ?? "absolute";
|
|
56064
|
+
el.style.left = `${rect.x}px`;
|
|
56065
|
+
el.style.top = `${rect.y}px`;
|
|
56066
|
+
el.style.width = `${rect.width}px`;
|
|
56067
|
+
el.style.height = `${rect.height}px`;
|
|
56068
|
+
el.style.backgroundColor = color;
|
|
56069
|
+
el.style.pointerEvents = "none";
|
|
56070
|
+
el.style.zIndex = "2147483647";
|
|
56071
|
+
el.style.opacity = "1";
|
|
56072
|
+
el.style.mixBlendMode = "normal";
|
|
56073
|
+
root.appendChild(el);
|
|
56074
|
+
}
|
|
56075
|
+
} catch {}
|
|
56076
|
+
}, {
|
|
56077
|
+
rects,
|
|
56078
|
+
color,
|
|
56079
|
+
token
|
|
56080
|
+
}, progress).catch(() => {})));
|
|
56081
|
+
await progress.delay(100);
|
|
56082
|
+
}
|
|
56083
|
+
async function resolveMaskRects(locator, maskToken, progress) {
|
|
56084
|
+
const session = locator.getFrame().session;
|
|
56085
|
+
const resolved = await locator.resolveNodesForMask(progress);
|
|
56086
|
+
const rects = [];
|
|
56087
|
+
try {
|
|
56088
|
+
for (const { objectId } of resolved) {
|
|
56089
|
+
progress.throwIfStopped();
|
|
56090
|
+
try {
|
|
56091
|
+
const rect = await resolveMaskRectForObject(session, objectId, maskToken);
|
|
56092
|
+
if (rect) rects.push(rect);
|
|
56093
|
+
} catch {
|
|
56094
|
+
progress.throwIfStopped();
|
|
56095
|
+
}
|
|
56096
|
+
}
|
|
56097
|
+
return rects;
|
|
56098
|
+
} finally {
|
|
56099
|
+
await Promise.all(resolved.map(({ objectId }) => session.send("Runtime.releaseObject", { objectId }).catch(() => {})));
|
|
56100
|
+
}
|
|
56101
|
+
}
|
|
56102
|
+
async function resolveMaskRectForObject(session, objectId, maskToken) {
|
|
56103
|
+
const result = await session.send("Runtime.callFunctionOn", {
|
|
56104
|
+
objectId,
|
|
56105
|
+
functionDeclaration: resolveMaskRect.toString(),
|
|
56106
|
+
arguments: [{ value: maskToken }],
|
|
56107
|
+
returnByValue: true
|
|
56108
|
+
});
|
|
56109
|
+
if (result.exceptionDetails) return null;
|
|
56110
|
+
const rect = result.result.value;
|
|
56111
|
+
if (!rect) return null;
|
|
56112
|
+
const { x, y, width, height } = rect;
|
|
56113
|
+
if (!Number.isFinite(x) || !Number.isFinite(y) || !Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0) return null;
|
|
56114
|
+
return {
|
|
56115
|
+
x,
|
|
56116
|
+
y,
|
|
56117
|
+
width,
|
|
56118
|
+
height,
|
|
56119
|
+
rootToken: rect.rootToken && typeof rect.rootToken === "string" ? rect.rootToken : void 0,
|
|
56120
|
+
position: rect.position === "fixed" ? "fixed" : "absolute"
|
|
56121
|
+
};
|
|
56122
|
+
}
|
|
56123
|
+
async function runScreenshotCleanups(cleanups) {
|
|
56124
|
+
for (let i = cleanups.length - 1; i >= 0; i -= 1) {
|
|
56125
|
+
const fn = cleanups[i];
|
|
56126
|
+
if (!fn) continue;
|
|
56127
|
+
try {
|
|
56128
|
+
const result = fn();
|
|
56129
|
+
if (result && typeof result.then === "function") await result;
|
|
56130
|
+
} catch {}
|
|
56131
|
+
}
|
|
56132
|
+
}
|
|
56133
|
+
//#endregion
|
|
56123
56134
|
//#region understudy/page.ts
|
|
56124
56135
|
/**
|
|
56125
56136
|
* Page
|
|
@@ -57101,7 +57112,7 @@ var Page = class Page {
|
|
|
57101
57112
|
* timeout error is thrown.
|
|
57102
57113
|
* @param options.type Image format (`"png"` by default).
|
|
57103
57114
|
*/
|
|
57104
|
-
async screenshot(options) {
|
|
57115
|
+
async screenshot(options, parentProgress) {
|
|
57105
57116
|
const opts = options ?? {};
|
|
57106
57117
|
const type = opts.type ?? "png";
|
|
57107
57118
|
if (type !== "png" && type !== "jpeg") throw new TypeError("screenshot: unsupported image type");
|
|
@@ -57114,47 +57125,46 @@ var Page = class Page {
|
|
|
57114
57125
|
const clip = opts.clip ? normalizeScreenshotClip(opts.clip) : void 0;
|
|
57115
57126
|
const maskLocators = opts.mask ?? [];
|
|
57116
57127
|
const cleanupTasks = [];
|
|
57117
|
-
|
|
57128
|
+
let failure;
|
|
57129
|
+
const exec = async (progress) => {
|
|
57118
57130
|
try {
|
|
57119
|
-
const captureScale = await
|
|
57120
|
-
if (opts.omitBackground)
|
|
57121
|
-
|
|
57122
|
-
|
|
57123
|
-
|
|
57124
|
-
if (
|
|
57125
|
-
|
|
57126
|
-
cleanupTasks.push(await disableAnimations(frames));
|
|
57127
|
-
}
|
|
57128
|
-
if (caretMode === "hide") {
|
|
57129
|
-
signal.throwIfAborted();
|
|
57130
|
-
cleanupTasks.push(await hideCaret(frames));
|
|
57131
|
-
}
|
|
57132
|
-
if (opts.style && opts.style.trim()) {
|
|
57133
|
-
signal.throwIfAborted();
|
|
57134
|
-
cleanupTasks.push(await applyStyleToFrames(frames, opts.style, "custom"));
|
|
57135
|
-
}
|
|
57136
|
-
if (maskLocators.length > 0) {
|
|
57137
|
-
signal.throwIfAborted();
|
|
57138
|
-
cleanupTasks.push(await applyMaskOverlays(maskLocators, opts.maskColor ?? "#FF00FF"));
|
|
57139
|
-
}
|
|
57140
|
-
return await waitForScreenshot(withScreenshotLock(this.conn, () => this.mainFrameWrapper.screenshot({
|
|
57131
|
+
const captureScale = await computeScreenshotScale(this, scaleMode, progress);
|
|
57132
|
+
if (opts.omitBackground) await setTransparentBackground(this.mainSession, progress, cleanupTasks);
|
|
57133
|
+
if (animationsMode === "disabled") await disableAnimations(frames, progress, cleanupTasks);
|
|
57134
|
+
if (caretMode === "hide") await hideCaret(frames, progress, cleanupTasks);
|
|
57135
|
+
if (opts.style && opts.style.trim()) await applyStyleToFrames(frames, opts.style, "custom", progress, cleanupTasks);
|
|
57136
|
+
if (maskLocators.length > 0) await applyMaskOverlays(maskLocators, opts.maskColor ?? "#FF00FF", progress, cleanupTasks);
|
|
57137
|
+
return await withScreenshotLock(this.conn, () => this.mainFrameWrapper.screenshot({
|
|
57141
57138
|
fullPage: opts.fullPage,
|
|
57142
57139
|
clip,
|
|
57143
57140
|
type,
|
|
57144
57141
|
quality: type === "jpeg" ? opts.quality : void 0,
|
|
57145
|
-
scale: captureScale
|
|
57146
|
-
|
|
57147
|
-
|
|
57142
|
+
scale: captureScale
|
|
57143
|
+
}, progress), progress);
|
|
57144
|
+
} catch (error) {
|
|
57145
|
+
progress.throwIfStopped();
|
|
57146
|
+
failure = { error };
|
|
57147
|
+
throw error;
|
|
57148
57148
|
} finally {
|
|
57149
57149
|
await runScreenshotCleanups(cleanupTasks);
|
|
57150
57150
|
}
|
|
57151
57151
|
};
|
|
57152
|
-
|
|
57152
|
+
try {
|
|
57153
|
+
return await runWithProgress(parentProgress ?? {
|
|
57154
|
+
name: "screenshot",
|
|
57155
|
+
timeout: opts.timeout ?? 0
|
|
57156
|
+
}, (progress) => withScreenshotLock(this, () => exec(progress), progress));
|
|
57157
|
+
} catch (error) {
|
|
57158
|
+
throw failure ? failure.error : error;
|
|
57159
|
+
}
|
|
57153
57160
|
}
|
|
57154
57161
|
/** Keep the PDF base64-encoded for transport; SDKs decode it to bytes. */
|
|
57155
|
-
async pdf(options) {
|
|
57162
|
+
async pdf(options, parentProgress) {
|
|
57156
57163
|
const { timeout = 3e4, width, height, margin, tagged = false, outline = false, ...printOptions } = options ?? {};
|
|
57157
|
-
return await
|
|
57164
|
+
return await runWithProgress(parentProgress ?? {
|
|
57165
|
+
name: "pdf",
|
|
57166
|
+
timeout
|
|
57167
|
+
}, (progress) => withScreenshotLock(this, async () => {
|
|
57158
57168
|
const { data } = await this.mainSession.send("Page.printToPDF", {
|
|
57159
57169
|
...printOptions,
|
|
57160
57170
|
paperWidth: width,
|
|
@@ -57168,7 +57178,7 @@ var Page = class Page {
|
|
|
57168
57178
|
transferMode: "ReturnAsBase64"
|
|
57169
57179
|
});
|
|
57170
57180
|
return { data };
|
|
57171
|
-
},
|
|
57181
|
+
}, progress));
|
|
57172
57182
|
}
|
|
57173
57183
|
/**
|
|
57174
57184
|
* specifies additional HTTP headers to be included in every request sent by
|
{stagehand-4.2.0a0.dev1556 → stagehand-4.2.0a0.dev1558}/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-173fe1ff6dae5dcadf512a16a41770e16f453330'
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{stagehand-4.2.0a0.dev1556 → stagehand-4.2.0a0.dev1558}/src/stagehand/_extension/content-script.js
RENAMED
|
File without changes
|
{stagehand-4.2.0a0.dev1556 → stagehand-4.2.0a0.dev1558}/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.dev1556 → stagehand-4.2.0a0.dev1558}/src/stagehand/_generated/__init__.py
RENAMED
|
File without changes
|
{stagehand-4.2.0a0.dev1556 → stagehand-4.2.0a0.dev1558}/src/stagehand/_generated/input_types.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{stagehand-4.2.0a0.dev1556 → stagehand-4.2.0a0.dev1558}/src/stagehand/browserbase_services.py
RENAMED
|
File without changes
|
{stagehand-4.2.0a0.dev1556 → stagehand-4.2.0a0.dev1558}/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
|
|
File without changes
|
|
File without changes
|