stagehand 4.2.0a0.dev1540__tar.gz → 4.2.0a0.dev1543__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.dev1540 → stagehand-4.2.0a0.dev1543}/PKG-INFO +1 -1
- {stagehand-4.2.0a0.dev1540 → stagehand-4.2.0a0.dev1543}/pyproject.toml +1 -1
- {stagehand-4.2.0a0.dev1540 → stagehand-4.2.0a0.dev1543}/src/stagehand/__init__.py +2 -0
- {stagehand-4.2.0a0.dev1540 → stagehand-4.2.0a0.dev1543}/src/stagehand/_extension/content-script.js +32 -10
- {stagehand-4.2.0a0.dev1540 → stagehand-4.2.0a0.dev1543}/src/stagehand/_extension/service-worker.js +91 -19
- {stagehand-4.2.0a0.dev1540 → stagehand-4.2.0a0.dev1543}/src/stagehand/_generated/input_types.py +33 -0
- {stagehand-4.2.0a0.dev1540 → stagehand-4.2.0a0.dev1543}/src/stagehand/_generated/models.py +55 -0
- {stagehand-4.2.0a0.dev1540 → stagehand-4.2.0a0.dev1543}/src/stagehand/_generated/protocol_version.py +1 -1
- {stagehand-4.2.0a0.dev1540 → stagehand-4.2.0a0.dev1543}/src/stagehand/page.py +52 -0
- {stagehand-4.2.0a0.dev1540 → stagehand-4.2.0a0.dev1543}/src/stagehand/rpc_client.py +10 -3
- {stagehand-4.2.0a0.dev1540 → stagehand-4.2.0a0.dev1543}/README.md +0 -0
- {stagehand-4.2.0a0.dev1540 → stagehand-4.2.0a0.dev1543}/src/stagehand/_extension/blank.html +0 -0
- {stagehand-4.2.0a0.dev1540 → stagehand-4.2.0a0.dev1543}/src/stagehand/_extension/manifest.json +0 -0
- {stagehand-4.2.0a0.dev1540 → stagehand-4.2.0a0.dev1543}/src/stagehand/_extension/offscreen/service-worker-heartbeat.html +0 -0
- {stagehand-4.2.0a0.dev1540 → stagehand-4.2.0a0.dev1543}/src/stagehand/_extension/offscreen/service-worker-heartbeat.js +0 -0
- {stagehand-4.2.0a0.dev1540 → stagehand-4.2.0a0.dev1543}/src/stagehand/_extension/wake-service-worker.html +0 -0
- {stagehand-4.2.0a0.dev1540 → stagehand-4.2.0a0.dev1543}/src/stagehand/_extension/wake-service-worker.js +0 -0
- {stagehand-4.2.0a0.dev1540 → stagehand-4.2.0a0.dev1543}/src/stagehand/_generated/__init__.py +0 -0
- {stagehand-4.2.0a0.dev1540 → stagehand-4.2.0a0.dev1543}/src/stagehand/_sdk_identity.py +0 -0
- {stagehand-4.2.0a0.dev1540 → stagehand-4.2.0a0.dev1543}/src/stagehand/_validation.py +0 -0
- {stagehand-4.2.0a0.dev1540 → stagehand-4.2.0a0.dev1543}/src/stagehand/browser.py +0 -0
- {stagehand-4.2.0a0.dev1540 → stagehand-4.2.0a0.dev1543}/src/stagehand/browser_clipboard.py +0 -0
- {stagehand-4.2.0a0.dev1540 → stagehand-4.2.0a0.dev1543}/src/stagehand/browser_context.py +0 -0
- {stagehand-4.2.0a0.dev1540 → stagehand-4.2.0a0.dev1543}/src/stagehand/browserbase_services.py +0 -0
- {stagehand-4.2.0a0.dev1540 → stagehand-4.2.0a0.dev1543}/src/stagehand/browserbase_session.py +0 -0
- {stagehand-4.2.0a0.dev1540 → stagehand-4.2.0a0.dev1543}/src/stagehand/cdp_client.py +0 -0
- {stagehand-4.2.0a0.dev1540 → stagehand-4.2.0a0.dev1543}/src/stagehand/client_models.py +0 -0
- {stagehand-4.2.0a0.dev1540 → stagehand-4.2.0a0.dev1543}/src/stagehand/client_types.py +0 -0
- {stagehand-4.2.0a0.dev1540 → stagehand-4.2.0a0.dev1543}/src/stagehand/extension_assets.py +0 -0
- {stagehand-4.2.0a0.dev1540 → stagehand-4.2.0a0.dev1543}/src/stagehand/file_upload.py +0 -0
- {stagehand-4.2.0a0.dev1540 → stagehand-4.2.0a0.dev1543}/src/stagehand/locator.py +0 -0
- {stagehand-4.2.0a0.dev1540 → stagehand-4.2.0a0.dev1543}/src/stagehand/py.typed +0 -0
- {stagehand-4.2.0a0.dev1540 → stagehand-4.2.0a0.dev1543}/src/stagehand/response.py +0 -0
- {stagehand-4.2.0a0.dev1540 → stagehand-4.2.0a0.dev1543}/src/stagehand/stagehand.py +0 -0
- {stagehand-4.2.0a0.dev1540 → stagehand-4.2.0a0.dev1543}/src/stagehand/timeouts.py +0 -0
- {stagehand-4.2.0a0.dev1540 → stagehand-4.2.0a0.dev1543}/src/stagehand/webmcp.py +0 -0
|
@@ -11,6 +11,7 @@ from ._generated.input_types import (
|
|
|
11
11
|
ModelConfig,
|
|
12
12
|
PageDragAndDropRoutePoint,
|
|
13
13
|
PageEventName,
|
|
14
|
+
PagePDFMargin,
|
|
14
15
|
PageScreenshotClip,
|
|
15
16
|
RgbaColor,
|
|
16
17
|
TelemetryConfig,
|
|
@@ -147,6 +148,7 @@ __all__ = [
|
|
|
147
148
|
"ToolsRemovedListener",
|
|
148
149
|
"WebMCPToolIdentity",
|
|
149
150
|
"PageEventName",
|
|
151
|
+
"PagePDFMargin",
|
|
150
152
|
"PageScreenshotClip",
|
|
151
153
|
"ProtocolLocator",
|
|
152
154
|
"RgbaColor",
|
{stagehand-4.2.0a0.dev1540 → stagehand-4.2.0a0.dev1543}/src/stagehand/_extension/content-script.js
RENAMED
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
* - Attribute equality predicates (`[@attr='value']`, `[@attr="value"]`)
|
|
13
13
|
* - Attribute existence (`[@attr]`)
|
|
14
14
|
* - Attribute contains/starts-with (`contains(@attr,'v')`, `starts-with(@attr,'v')`)
|
|
15
|
-
* - Text equality/contains (`[text()='v']`, `[contains(text(),'v')]`, `[.='v']`)
|
|
15
|
+
* - Text equality/contains (`[text()='v']`, `[contains(text(),'v')]`, `[.='v']`),
|
|
16
|
+
* where `text()` reads direct child text nodes and `.` the whole subtree
|
|
16
17
|
* - normalize-space on text/attributes (`[normalize-space(text())='v']`)
|
|
17
18
|
* - Basic boolean predicates (`and`, `or`, `not(...)`)
|
|
18
19
|
* - Multiple predicates per step (`[@class='foo'][2]`)
|
|
@@ -159,11 +160,12 @@ function parseAtomicPredicate(input) {
|
|
|
159
160
|
value: normalizeAttrMatch[2] ?? normalizeAttrMatch[3] ?? "",
|
|
160
161
|
normalize: true
|
|
161
162
|
};
|
|
162
|
-
const normalizeTextMatch = input.match(new RegExp(`^normalize-space\\(\\s*(
|
|
163
|
+
const normalizeTextMatch = input.match(new RegExp(`^normalize-space\\(\\s*(text\\(\\)|\\.)\\s*\\)\\s*=\\s*${quoted}$`));
|
|
163
164
|
if (normalizeTextMatch) return {
|
|
164
165
|
type: "textEquals",
|
|
165
|
-
value: normalizeTextMatch[
|
|
166
|
-
normalize: true
|
|
166
|
+
value: normalizeTextMatch[2] ?? normalizeTextMatch[3] ?? "",
|
|
167
|
+
normalize: true,
|
|
168
|
+
source: textSource(normalizeTextMatch[1])
|
|
167
169
|
};
|
|
168
170
|
const attrEqualsMatch = input.match(new RegExp(`^@(${attrName})\\s*=\\s*${quoted}$`));
|
|
169
171
|
if (attrEqualsMatch) return {
|
|
@@ -188,15 +190,17 @@ function parseAtomicPredicate(input) {
|
|
|
188
190
|
name: attrStartsMatch[1],
|
|
189
191
|
value: attrStartsMatch[2] ?? attrStartsMatch[3] ?? ""
|
|
190
192
|
};
|
|
191
|
-
const textEqualsMatch = input.match(new RegExp(`^(
|
|
193
|
+
const textEqualsMatch = input.match(new RegExp(`^(text\\(\\)|\\.)\\s*=\\s*${quoted}$`));
|
|
192
194
|
if (textEqualsMatch) return {
|
|
193
195
|
type: "textEquals",
|
|
194
|
-
value: textEqualsMatch[
|
|
196
|
+
value: textEqualsMatch[2] ?? textEqualsMatch[3] ?? "",
|
|
197
|
+
source: textSource(textEqualsMatch[1])
|
|
195
198
|
};
|
|
196
|
-
const textContainsMatch = input.match(new RegExp(`^contains\\(\\s*(
|
|
199
|
+
const textContainsMatch = input.match(new RegExp(`^contains\\(\\s*(text\\(\\)|\\.)\\s*,\\s*${quoted}\\s*\\)$`));
|
|
197
200
|
if (textContainsMatch) return {
|
|
198
201
|
type: "textContains",
|
|
199
|
-
value: textContainsMatch[
|
|
202
|
+
value: textContainsMatch[2] ?? textContainsMatch[3] ?? "",
|
|
203
|
+
source: textSource(textContainsMatch[1])
|
|
200
204
|
};
|
|
201
205
|
if (valueMatch.test(input)) return null;
|
|
202
206
|
return null;
|
|
@@ -276,9 +280,23 @@ function hasBalancedParens(input) {
|
|
|
276
280
|
return depth === 0;
|
|
277
281
|
}
|
|
278
282
|
var normalizeSpace = (value) => value.replace(/\s+/g, " ").trim();
|
|
283
|
+
var TEXT_NODE = 3;
|
|
284
|
+
function textSource(token) {
|
|
285
|
+
return token === "text()" ? "text" : "self";
|
|
286
|
+
}
|
|
279
287
|
function textValue(element) {
|
|
280
288
|
return String(element.textContent ?? "");
|
|
281
289
|
}
|
|
290
|
+
/** The node-set `text()` selects: direct child text nodes, in document order. */
|
|
291
|
+
function childTextValues(element) {
|
|
292
|
+
const values = [];
|
|
293
|
+
for (const node of Array.from(element.childNodes)) if (node.nodeType === TEXT_NODE) values.push(String(node.nodeValue ?? ""));
|
|
294
|
+
return values;
|
|
295
|
+
}
|
|
296
|
+
/** `string(node-set)` is the string-value of its first node, or `""` when empty. */
|
|
297
|
+
function firstChildTextValue(element) {
|
|
298
|
+
return childTextValues(element)[0] ?? "";
|
|
299
|
+
}
|
|
282
300
|
function normalizeMaybe(value, normalize) {
|
|
283
301
|
return normalize ? normalizeSpace(value) : value;
|
|
284
302
|
}
|
|
@@ -303,8 +321,12 @@ function evaluatePredicate(element, predicate) {
|
|
|
303
321
|
if (attr === null) return false;
|
|
304
322
|
return normalizeMaybe(attr, predicate.normalize).startsWith(normalizeMaybe(predicate.value, predicate.normalize));
|
|
305
323
|
}
|
|
306
|
-
case "textEquals":
|
|
307
|
-
|
|
324
|
+
case "textEquals": {
|
|
325
|
+
const target = normalizeMaybe(predicate.value, predicate.normalize);
|
|
326
|
+
if (predicate.source === "text") return predicate.normalize ? normalizeSpace(firstChildTextValue(element)) === target : childTextValues(element).some((value) => value === target);
|
|
327
|
+
return normalizeMaybe(textValue(element), predicate.normalize) === target;
|
|
328
|
+
}
|
|
329
|
+
case "textContains": return normalizeMaybe(predicate.source === "text" ? firstChildTextValue(element) : textValue(element), predicate.normalize).includes(normalizeMaybe(predicate.value, predicate.normalize));
|
|
308
330
|
case "index": return true;
|
|
309
331
|
default: return true;
|
|
310
332
|
}
|
{stagehand-4.2.0a0.dev1540 → stagehand-4.2.0a0.dev1543}/src/stagehand/_extension/service-worker.js
RENAMED
|
@@ -7305,6 +7305,10 @@ var defaultOpaqueKeys = /* @__PURE__ */ new Set([
|
|
|
7305
7305
|
"data",
|
|
7306
7306
|
"userMetadata"
|
|
7307
7307
|
]);
|
|
7308
|
+
var apiAcronymWireKeys = {
|
|
7309
|
+
base_url: "base_URL",
|
|
7310
|
+
prefer_css_page_size: "prefer_CSS_page_size"
|
|
7311
|
+
};
|
|
7308
7312
|
function wireSchema(schema, options = {}) {
|
|
7309
7313
|
return preprocess((value) => isCaseable(value) ? camelcaseKeys(preserveApiAcronyms(value, options.opaqueKeys), {
|
|
7310
7314
|
deep: true,
|
|
@@ -7347,7 +7351,7 @@ function preserveApiAcronyms(value, additionalOpaqueKeys = []) {
|
|
|
7347
7351
|
function visit(entry) {
|
|
7348
7352
|
if (Array.isArray(entry)) return entry.map(visit);
|
|
7349
7353
|
if (!isRecord$1(entry)) return entry;
|
|
7350
|
-
return Object.fromEntries(Object.entries(entry).map(([key, child]) => [key
|
|
7354
|
+
return Object.fromEntries(Object.entries(entry).map(([key, child]) => [Object.hasOwn(apiAcronymWireKeys, key) ? apiAcronymWireKeys[key] : key, opaqueKeys.has(key) ? child : visit(child)]));
|
|
7351
7355
|
}
|
|
7352
7356
|
return visit(value);
|
|
7353
7357
|
}
|
|
@@ -7359,7 +7363,7 @@ function isRecord$1(value) {
|
|
|
7359
7363
|
}
|
|
7360
7364
|
var package_default$1 = {
|
|
7361
7365
|
name: "@browserbasehq/stagehand-protocol",
|
|
7362
|
-
version: "2.1.0-alpha-
|
|
7366
|
+
version: "2.1.0-alpha-34edfa38d6c33b30b07b4dd813f9c943f8e6689f",
|
|
7363
7367
|
"private": true,
|
|
7364
7368
|
type: "module",
|
|
7365
7369
|
exports: {
|
|
@@ -8618,6 +8622,29 @@ var PageScreenshotOptionsSchema = strictObject({
|
|
|
8618
8622
|
path: ["quality"]
|
|
8619
8623
|
}).meta({ id: "PageScreenshotOptions" });
|
|
8620
8624
|
var PageScreenshotParamsSchema = PageIdParamsSchema.extend({ options: PageScreenshotOptionsSchema.optional() }).meta({ id: "PageScreenshotParams" });
|
|
8625
|
+
var PagePDFMarginSchema = strictObject({
|
|
8626
|
+
top: number$1().nonnegative().optional(),
|
|
8627
|
+
bottom: number$1().nonnegative().optional(),
|
|
8628
|
+
left: number$1().nonnegative().optional(),
|
|
8629
|
+
right: number$1().nonnegative().optional()
|
|
8630
|
+
}).meta({ id: "PagePDFMargin" });
|
|
8631
|
+
var PagePDFOptionsSchema = strictObject({
|
|
8632
|
+
landscape: boolean().optional(),
|
|
8633
|
+
displayHeaderFooter: boolean().optional(),
|
|
8634
|
+
printBackground: boolean().optional(),
|
|
8635
|
+
scale: number$1().min(.1).max(2).optional(),
|
|
8636
|
+
width: number$1().positive().optional(),
|
|
8637
|
+
height: number$1().positive().optional(),
|
|
8638
|
+
margin: PagePDFMarginSchema.optional(),
|
|
8639
|
+
pageRanges: string().optional(),
|
|
8640
|
+
headerTemplate: string().optional(),
|
|
8641
|
+
footerTemplate: string().optional(),
|
|
8642
|
+
preferCSSPageSize: boolean().optional(),
|
|
8643
|
+
tagged: boolean().optional(),
|
|
8644
|
+
outline: boolean().optional(),
|
|
8645
|
+
timeout: number$1().nonnegative().max(2147473647).optional()
|
|
8646
|
+
}).meta({ id: "PagePDFOptions" });
|
|
8647
|
+
var PagePDFParamsSchema = PageIdParamsSchema.extend({ options: PagePDFOptionsSchema.optional() }).meta({ id: "PagePDFParams" });
|
|
8621
8648
|
var PageSnapshotParamsSchema = PageIdParamsSchema.extend({ options: PageSnapshotOptionsSchema.optional() }).meta({ id: "PageSnapshotParams" });
|
|
8622
8649
|
var PageSetViewportSizeParamsSchema = PageIdParamsSchema.extend({
|
|
8623
8650
|
width: number$1().int().positive(),
|
|
@@ -8698,6 +8725,7 @@ var PageTitleResultSchema = string().meta({ id: "PageTitleResult" });
|
|
|
8698
8725
|
var PageCloseResultSchema = strictObject({ closed: literal(true) }).meta({ id: "PageCloseResult" });
|
|
8699
8726
|
var PageEvaluateResultSchema = strictObject({ value: json$1() }).meta({ id: "PageEvaluateResult" });
|
|
8700
8727
|
var PageScreenshotResultSchema = strictObject({ data: base64().meta({ format: "byte" }) }).meta({ id: "PageScreenshotResult" });
|
|
8728
|
+
var PagePDFResultSchema = strictObject({ data: base64().meta({ format: "byte" }) }).meta({ id: "PagePDFResult" });
|
|
8701
8729
|
var PageWaitForSelectorResultSchema = strictObject({ matched: boolean() }).meta({ id: "PageWaitForSelectorResult" });
|
|
8702
8730
|
var LocatorClickResultSchema = strictObject({ clicked: literal(true) }).meta({ id: "LocatorClickResult" });
|
|
8703
8731
|
var LocatorFillResultSchema = strictObject({ filled: literal(true) }).meta({ id: "LocatorFillResult" });
|
|
@@ -8977,6 +9005,11 @@ var StagehandMethods = {
|
|
|
8977
9005
|
params: PageScreenshotParamsSchema,
|
|
8978
9006
|
result: PageScreenshotResultSchema
|
|
8979
9007
|
},
|
|
9008
|
+
pagePDF: {
|
|
9009
|
+
name: "page.pdf",
|
|
9010
|
+
params: PagePDFParamsSchema,
|
|
9011
|
+
result: PagePDFResultSchema
|
|
9012
|
+
},
|
|
8980
9013
|
pageSnapshot: {
|
|
8981
9014
|
name: "page.snapshot",
|
|
8982
9015
|
params: PageSnapshotParamsSchema,
|
|
@@ -12323,24 +12356,20 @@ var Page$1 = class {
|
|
|
12323
12356
|
}
|
|
12324
12357
|
async screenshot(options) {
|
|
12325
12358
|
const { path, mask, ...screenshotOptions } = options ?? {};
|
|
12326
|
-
|
|
12359
|
+
return await decodeCaptureResult((await this.rpcClient.send(StagehandMethods.pageScreenshot, {
|
|
12327
12360
|
pageId: this.pageId,
|
|
12328
12361
|
options: {
|
|
12329
12362
|
...screenshotOptions,
|
|
12330
12363
|
...mask ? { mask: mask.map((locator) => locator.descriptor) } : {}
|
|
12331
12364
|
}
|
|
12332
|
-
})).data, "
|
|
12333
|
-
|
|
12334
|
-
|
|
12335
|
-
|
|
12336
|
-
|
|
12337
|
-
|
|
12338
|
-
|
|
12339
|
-
|
|
12340
|
-
});
|
|
12341
|
-
await writeFile(path, bytes);
|
|
12342
|
-
}
|
|
12343
|
-
return bytes;
|
|
12365
|
+
})).data, "screenshot", path);
|
|
12366
|
+
}
|
|
12367
|
+
async pdf(options) {
|
|
12368
|
+
const { path, ...pdfOptions } = options ?? {};
|
|
12369
|
+
return await decodeCaptureResult((await this.rpcClient.send(StagehandMethods.pagePDF, {
|
|
12370
|
+
pageId: this.pageId,
|
|
12371
|
+
options: pdfOptions
|
|
12372
|
+
})).data, "pdf", path);
|
|
12344
12373
|
}
|
|
12345
12374
|
async snapshot(options) {
|
|
12346
12375
|
return await this.rpcClient.send(StagehandMethods.pageSnapshot, {
|
|
@@ -12371,6 +12400,20 @@ var Page$1 = class {
|
|
|
12371
12400
|
});
|
|
12372
12401
|
}
|
|
12373
12402
|
};
|
|
12403
|
+
async function decodeCaptureResult(data, method, path) {
|
|
12404
|
+
const bytes = decodeBase64(data, `page.${method}`);
|
|
12405
|
+
if (path !== void 0) {
|
|
12406
|
+
const moduleName = "node:fs/promises";
|
|
12407
|
+
const { writeFile } = await __vitePreload(() => import(
|
|
12408
|
+
/* @vite-ignore */
|
|
12409
|
+
moduleName
|
|
12410
|
+
), []).catch(() => {
|
|
12411
|
+
throw new TypeError(`page.${method}(): path is only supported in Node.js; omit path to receive ${method === "pdf" ? "PDF" : "screenshot"} bytes`);
|
|
12412
|
+
});
|
|
12413
|
+
await writeFile(path, bytes);
|
|
12414
|
+
}
|
|
12415
|
+
return bytes;
|
|
12416
|
+
}
|
|
12374
12417
|
function reportPageEventListenerError(error) {
|
|
12375
12418
|
process.emitWarning(error instanceof Error ? error.message : String(error), { code: "STAGEHAND_PAGE_EVENT_LISTENER_ERROR" });
|
|
12376
12419
|
}
|
|
@@ -12931,6 +12974,10 @@ function createPageController(runtime) {
|
|
|
12931
12974
|
logger.debug("page.screenshot", {});
|
|
12932
12975
|
return runtime.pageScreenshot(params);
|
|
12933
12976
|
}
|
|
12977
|
+
async function pdf(params, { logger }) {
|
|
12978
|
+
logger.debug("page.pdf", {});
|
|
12979
|
+
return runtime.pagePDF(params);
|
|
12980
|
+
}
|
|
12934
12981
|
async function snapshot(params, { logger }) {
|
|
12935
12982
|
logger.debug("page.snapshot", {});
|
|
12936
12983
|
return runtime.pageSnapshot(params);
|
|
@@ -12990,6 +13037,7 @@ function createPageController(runtime) {
|
|
|
12990
13037
|
waitForTimeout,
|
|
12991
13038
|
waitForSelector,
|
|
12992
13039
|
screenshot,
|
|
13040
|
+
pdf,
|
|
12993
13041
|
snapshot,
|
|
12994
13042
|
webMCPTools,
|
|
12995
13043
|
webMCPInvokeTool,
|
|
@@ -16290,7 +16338,7 @@ function resolveMaskRect(maskToken) {
|
|
|
16290
16338
|
//#region understudy/screenshotUtils.ts
|
|
16291
16339
|
var screenshotQueues = /* @__PURE__ */ new WeakMap();
|
|
16292
16340
|
/** Serialize page mutations, or the browser-wide activation/capture critical section. */
|
|
16293
|
-
async function withScreenshotLock(owner, capture, timeout) {
|
|
16341
|
+
async function withScreenshotLock(owner, capture, timeout, operation = "screenshot") {
|
|
16294
16342
|
const queue = screenshotQueues.get(owner) ?? {
|
|
16295
16343
|
tail: Promise.resolve(),
|
|
16296
16344
|
blocked: new AbortController()
|
|
@@ -16299,8 +16347,9 @@ async function withScreenshotLock(owner, capture, timeout) {
|
|
|
16299
16347
|
const controller = new AbortController();
|
|
16300
16348
|
let started = false;
|
|
16301
16349
|
const timer = typeof timeout === "number" && Number.isFinite(timeout) && timeout > 0 ? setTimeout(() => {
|
|
16302
|
-
|
|
16303
|
-
|
|
16350
|
+
const error = new TimeoutError(operation, timeout);
|
|
16351
|
+
controller.abort(error);
|
|
16352
|
+
if (started) queue.blocked.abort(new Error(`A previous capture is still recovering: ${error.message}`, { cause: error }));
|
|
16304
16353
|
}, Math.min(timeout, 2147483647)) : void 0;
|
|
16305
16354
|
const pending = queue.tail.then(() => {
|
|
16306
16355
|
queue.blocked.signal.throwIfAborted();
|
|
@@ -51568,6 +51617,7 @@ var RPCRouter = class {
|
|
|
51568
51617
|
case "page.wait_for_timeout": return this.pageController.waitForTimeout(parseParams(StagehandMethods.pageWaitForTimeout, request.params), context);
|
|
51569
51618
|
case "page.wait_for_selector": return this.pageController.waitForSelector(parseParams(StagehandMethods.pageWaitForSelector, request.params), context);
|
|
51570
51619
|
case "page.screenshot": return this.pageController.screenshot(parseParams(StagehandMethods.pageScreenshot, request.params), context);
|
|
51620
|
+
case "page.pdf": return this.pageController.pdf(parseParams(StagehandMethods.pagePDF, request.params), context);
|
|
51571
51621
|
case "page.snapshot": return this.pageController.snapshot(parseParams(StagehandMethods.pageSnapshot, request.params), context);
|
|
51572
51622
|
case "page.webmcp_tools": return this.pageController.webMCPTools(parseParams(StagehandMethods.pageWebMCPTools, request.params), context);
|
|
51573
51623
|
case "page.webmcp_invoke_tool": return this.pageController.webMCPInvokeTool(parseParams(StagehandMethods.pageWebMCPInvokeTool, request.params), context);
|
|
@@ -53961,7 +54011,7 @@ var WebTracerProvider = class extends BasicTracerProvider {
|
|
|
53961
54011
|
};
|
|
53962
54012
|
var package_default = {
|
|
53963
54013
|
name: "@browserbasehq/stagehand-extension",
|
|
53964
|
-
version: "1.1.0-alpha-
|
|
54014
|
+
version: "1.1.0-alpha-34edfa38d6c33b30b07b4dd813f9c943f8e6689f",
|
|
53965
54015
|
"private": true,
|
|
53966
54016
|
type: "module",
|
|
53967
54017
|
scripts: {
|
|
@@ -56387,6 +56437,25 @@ var Page = class Page {
|
|
|
56387
56437
|
};
|
|
56388
56438
|
return await withScreenshotLock(this, exec, opts.timeout);
|
|
56389
56439
|
}
|
|
56440
|
+
/** Keep the PDF base64-encoded for transport; SDKs decode it to bytes. */
|
|
56441
|
+
async pdf(options) {
|
|
56442
|
+
const { timeout = 3e4, width, height, margin, tagged = false, outline = false, ...printOptions } = options ?? {};
|
|
56443
|
+
return await withScreenshotLock(this, async () => {
|
|
56444
|
+
const { data } = await this.mainSession.send("Page.printToPDF", {
|
|
56445
|
+
...printOptions,
|
|
56446
|
+
paperWidth: width,
|
|
56447
|
+
paperHeight: height,
|
|
56448
|
+
marginTop: margin?.top ?? 0,
|
|
56449
|
+
marginBottom: margin?.bottom ?? 0,
|
|
56450
|
+
marginLeft: margin?.left ?? 0,
|
|
56451
|
+
marginRight: margin?.right ?? 0,
|
|
56452
|
+
generateTaggedPDF: tagged,
|
|
56453
|
+
generateDocumentOutline: outline,
|
|
56454
|
+
transferMode: "ReturnAsBase64"
|
|
56455
|
+
});
|
|
56456
|
+
return { data };
|
|
56457
|
+
}, timeout, "pdf");
|
|
56458
|
+
}
|
|
56390
56459
|
/**
|
|
56391
56460
|
* specifies additional HTTP headers to be included in every request sent by
|
|
56392
56461
|
* the root CDP session of the page, and all of its child CDP sessions.
|
|
@@ -57659,6 +57728,9 @@ var StagehandRuntime = class {
|
|
|
57659
57728
|
}
|
|
57660
57729
|
return { data: bytesToBase64(await page.screenshot(options)) };
|
|
57661
57730
|
}
|
|
57731
|
+
async pagePDF(params) {
|
|
57732
|
+
return await this.resolvePage(params.pageId).pdf(params.options);
|
|
57733
|
+
}
|
|
57662
57734
|
async pageSnapshot(params) {
|
|
57663
57735
|
return await this.resolvePage(params.pageId).snapshot(params.options);
|
|
57664
57736
|
}
|
{stagehand-4.2.0a0.dev1540 → stagehand-4.2.0a0.dev1543}/src/stagehand/_generated/input_types.py
RENAMED
|
@@ -781,6 +781,39 @@ class PageOffParams(TypedDict):
|
|
|
781
781
|
subscription_id: str
|
|
782
782
|
|
|
783
783
|
|
|
784
|
+
class PagePDFMargin(TypedDict):
|
|
785
|
+
top: NotRequired[float]
|
|
786
|
+
bottom: NotRequired[float]
|
|
787
|
+
left: NotRequired[float]
|
|
788
|
+
right: NotRequired[float]
|
|
789
|
+
|
|
790
|
+
|
|
791
|
+
class PagePDFOptions(TypedDict):
|
|
792
|
+
landscape: NotRequired[bool]
|
|
793
|
+
display_header_footer: NotRequired[bool]
|
|
794
|
+
print_background: NotRequired[bool]
|
|
795
|
+
scale: NotRequired[float]
|
|
796
|
+
width: NotRequired[float]
|
|
797
|
+
height: NotRequired[float]
|
|
798
|
+
margin: NotRequired[PagePDFMargin]
|
|
799
|
+
page_ranges: NotRequired[str]
|
|
800
|
+
header_template: NotRequired[str]
|
|
801
|
+
footer_template: NotRequired[str]
|
|
802
|
+
prefer_css_page_size: NotRequired[bool]
|
|
803
|
+
tagged: NotRequired[bool]
|
|
804
|
+
outline: NotRequired[bool]
|
|
805
|
+
timeout: NotRequired[float]
|
|
806
|
+
|
|
807
|
+
|
|
808
|
+
class PagePDFParams(TypedDict):
|
|
809
|
+
page_id: str
|
|
810
|
+
options: NotRequired[PagePDFOptions]
|
|
811
|
+
|
|
812
|
+
|
|
813
|
+
class PagePDFResult(TypedDict):
|
|
814
|
+
data: str
|
|
815
|
+
|
|
816
|
+
|
|
784
817
|
class PageRef(TypedDict):
|
|
785
818
|
page_id: str
|
|
786
819
|
url: NotRequired[str]
|
|
@@ -1677,6 +1677,61 @@ class PageOnParams(WireModel):
|
|
|
1677
1677
|
event: PageSubscriptionEventName
|
|
1678
1678
|
|
|
1679
1679
|
|
|
1680
|
+
class PagePDFMargin(WireModel):
|
|
1681
|
+
model_config = ConfigDict(
|
|
1682
|
+
extra="forbid",
|
|
1683
|
+
validate_by_name=True,
|
|
1684
|
+
)
|
|
1685
|
+
top: Annotated[Optional[StrictFloat], Field(ge=0.0)] = None
|
|
1686
|
+
bottom: Annotated[Optional[StrictFloat], Field(ge=0.0)] = None
|
|
1687
|
+
left: Annotated[Optional[StrictFloat], Field(ge=0.0)] = None
|
|
1688
|
+
right: Annotated[Optional[StrictFloat], Field(ge=0.0)] = None
|
|
1689
|
+
|
|
1690
|
+
|
|
1691
|
+
class PagePDFOptions(WireModel):
|
|
1692
|
+
model_config = ConfigDict(
|
|
1693
|
+
extra="forbid",
|
|
1694
|
+
validate_by_name=True,
|
|
1695
|
+
)
|
|
1696
|
+
landscape: Optional[StrictBool] = None
|
|
1697
|
+
display_header_footer: Optional[StrictBool] = None
|
|
1698
|
+
print_background: Optional[StrictBool] = None
|
|
1699
|
+
scale: Annotated[Optional[StrictFloat], Field(ge=0.1, le=2.0)] = None
|
|
1700
|
+
width: Annotated[Optional[StrictFloat], Field(gt=0.0)] = None
|
|
1701
|
+
height: Annotated[Optional[StrictFloat], Field(gt=0.0)] = None
|
|
1702
|
+
margin: Optional[PagePDFMargin] = None
|
|
1703
|
+
page_ranges: Optional[StrictStr] = None
|
|
1704
|
+
header_template: Optional[StrictStr] = None
|
|
1705
|
+
footer_template: Optional[StrictStr] = None
|
|
1706
|
+
prefer_css_page_size: Optional[StrictBool] = None
|
|
1707
|
+
tagged: Optional[StrictBool] = None
|
|
1708
|
+
outline: Optional[StrictBool] = None
|
|
1709
|
+
timeout: Annotated[Optional[StrictFloat], Field(ge=0.0, le=2147473647.0)] = None
|
|
1710
|
+
|
|
1711
|
+
|
|
1712
|
+
class PagePDFParams(WireModel):
|
|
1713
|
+
model_config = ConfigDict(
|
|
1714
|
+
extra="forbid",
|
|
1715
|
+
validate_by_name=True,
|
|
1716
|
+
)
|
|
1717
|
+
page_id: StrictStr
|
|
1718
|
+
options: Optional[PagePDFOptions] = None
|
|
1719
|
+
|
|
1720
|
+
|
|
1721
|
+
class PagePDFResult(WireModel):
|
|
1722
|
+
model_config = ConfigDict(
|
|
1723
|
+
extra="forbid",
|
|
1724
|
+
validate_by_name=True,
|
|
1725
|
+
)
|
|
1726
|
+
data: Annotated[
|
|
1727
|
+
StrictStr,
|
|
1728
|
+
Field(
|
|
1729
|
+
json_schema_extra={"contentEncoding": "base64"},
|
|
1730
|
+
pattern="^$|^(?:[0-9a-zA-Z+/]{4})*(?:(?:[0-9a-zA-Z+/]{2}==)|(?:[0-9a-zA-Z+/]{3}=))?$",
|
|
1731
|
+
),
|
|
1732
|
+
]
|
|
1733
|
+
|
|
1734
|
+
|
|
1680
1735
|
class PageRef(WireModel):
|
|
1681
1736
|
model_config = ConfigDict(
|
|
1682
1737
|
extra="forbid",
|
{stagehand-4.2.0a0.dev1540 → stagehand-4.2.0a0.dev1543}/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-34edfa38d6c33b30b07b4dd813f9c943f8e6689f'
|
|
@@ -14,6 +14,7 @@ from pydantic import JsonValue, TypeAdapter
|
|
|
14
14
|
from ._generated.input_types import (
|
|
15
15
|
PageDragAndDropRoutePoint,
|
|
16
16
|
PageEventName,
|
|
17
|
+
PagePDFMargin,
|
|
17
18
|
PageScreenshotClip,
|
|
18
19
|
PageSubscriptionEventName,
|
|
19
20
|
)
|
|
@@ -44,6 +45,9 @@ from ._generated.models import (
|
|
|
44
45
|
PageNavigationResult,
|
|
45
46
|
PageOffParams,
|
|
46
47
|
PageOnParams,
|
|
48
|
+
PagePDFOptions,
|
|
49
|
+
PagePDFParams,
|
|
50
|
+
PagePDFResult,
|
|
47
51
|
PageRef,
|
|
48
52
|
PageReloadOptions,
|
|
49
53
|
PageReloadParams,
|
|
@@ -613,6 +617,54 @@ class Page:
|
|
|
613
617
|
Path(path).write_bytes(data)
|
|
614
618
|
return data
|
|
615
619
|
|
|
620
|
+
async def pdf(
|
|
621
|
+
self,
|
|
622
|
+
*,
|
|
623
|
+
landscape: bool | None = None,
|
|
624
|
+
display_header_footer: bool | None = None,
|
|
625
|
+
print_background: bool | None = None,
|
|
626
|
+
scale: float | None = None,
|
|
627
|
+
width: float | None = None,
|
|
628
|
+
height: float | None = None,
|
|
629
|
+
margin: PagePDFMargin | None = None,
|
|
630
|
+
page_ranges: str | None = None,
|
|
631
|
+
header_template: str | None = None,
|
|
632
|
+
footer_template: str | None = None,
|
|
633
|
+
prefer_css_page_size: bool | None = None,
|
|
634
|
+
tagged: bool | None = None,
|
|
635
|
+
outline: bool | None = None,
|
|
636
|
+
timeout: float | None = None,
|
|
637
|
+
path: str | Path | None = None,
|
|
638
|
+
) -> bytes:
|
|
639
|
+
params = PagePDFParams(page_id=self.page_id)
|
|
640
|
+
options = PagePDFOptions.model_validate({
|
|
641
|
+
name: value
|
|
642
|
+
for name, value in (
|
|
643
|
+
("landscape", landscape),
|
|
644
|
+
("display_header_footer", display_header_footer),
|
|
645
|
+
("print_background", print_background),
|
|
646
|
+
("scale", scale),
|
|
647
|
+
("width", width),
|
|
648
|
+
("height", height),
|
|
649
|
+
("margin", margin),
|
|
650
|
+
("page_ranges", page_ranges),
|
|
651
|
+
("header_template", header_template),
|
|
652
|
+
("footer_template", footer_template),
|
|
653
|
+
("prefer_css_page_size", prefer_css_page_size),
|
|
654
|
+
("tagged", tagged),
|
|
655
|
+
("outline", outline),
|
|
656
|
+
("timeout", timeout),
|
|
657
|
+
)
|
|
658
|
+
if value is not None
|
|
659
|
+
})
|
|
660
|
+
if options.model_fields_set:
|
|
661
|
+
params.options = options
|
|
662
|
+
result = await self._rpc_client.send("page.pdf", params, PagePDFResult)
|
|
663
|
+
data = base64.b64decode(result.data, validate=True)
|
|
664
|
+
if path is not None:
|
|
665
|
+
Path(path).write_bytes(data)
|
|
666
|
+
return data
|
|
667
|
+
|
|
616
668
|
async def snapshot(self, *, include_iframes: bool | None = None) -> SnapshotResult:
|
|
617
669
|
params = PageSnapshotParams(page_id=self.page_id)
|
|
618
670
|
if include_iframes is not None:
|
|
@@ -29,6 +29,7 @@ _DEFAULT_OPERATION_TIMEOUT_MS = {
|
|
|
29
29
|
"page.go_forward": 15_000,
|
|
30
30
|
"page.wait_for_load_state": 15_000,
|
|
31
31
|
"page.wait_for_selector": 30_000,
|
|
32
|
+
"page.pdf": 30_000,
|
|
32
33
|
"page.webmcp_tools": 1_000,
|
|
33
34
|
}
|
|
34
35
|
_UNBOUNDED_BY_DEFAULT_METHODS = {
|
|
@@ -207,7 +208,8 @@ class RPCClient:
|
|
|
207
208
|
tracestate=trace_context.get("tracestate"),
|
|
208
209
|
)
|
|
209
210
|
|
|
210
|
-
|
|
211
|
+
response_timeout_seconds = _rpc_response_timeout_seconds(method, parsed_params)
|
|
212
|
+
response_timeout = asyncio.timeout(response_timeout_seconds)
|
|
211
213
|
try:
|
|
212
214
|
try:
|
|
213
215
|
async with response_timeout:
|
|
@@ -219,8 +221,10 @@ class RPCClient:
|
|
|
219
221
|
)
|
|
220
222
|
return await response
|
|
221
223
|
except TimeoutError as error:
|
|
222
|
-
if response_timeout.expired():
|
|
223
|
-
raise TimeoutError(
|
|
224
|
+
if response_timeout.expired() and response_timeout_seconds is not None:
|
|
225
|
+
raise TimeoutError(
|
|
226
|
+
f"RPC response timed out after {response_timeout_seconds:g}s: {method}"
|
|
227
|
+
) from error
|
|
224
228
|
raise
|
|
225
229
|
finally:
|
|
226
230
|
self._pending.pop(request_id, None)
|
|
@@ -543,6 +547,7 @@ def _rpc_response_timeout_seconds(method: str, params: BaseModel) -> float | Non
|
|
|
543
547
|
"page.go_back",
|
|
544
548
|
"page.go_forward",
|
|
545
549
|
"page.screenshot",
|
|
550
|
+
"page.pdf",
|
|
546
551
|
"page.wait_for_selector",
|
|
547
552
|
"page.webmcp_tools",
|
|
548
553
|
"page.webmcp_invocation_result",
|
|
@@ -554,6 +559,8 @@ def _rpc_response_timeout_seconds(method: str, params: BaseModel) -> float | Non
|
|
|
554
559
|
operation_timeout_ms = _numeric_property(params, "ms")
|
|
555
560
|
|
|
556
561
|
if operation_timeout_ms is not None:
|
|
562
|
+
if method == "page.pdf" and operation_timeout_ms == 0:
|
|
563
|
+
return None
|
|
557
564
|
return (_RPC_RESPONSE_GRACE_MS + max(0, operation_timeout_ms)) / 1_000
|
|
558
565
|
|
|
559
566
|
if (default_timeout_ms := _DEFAULT_OPERATION_TIMEOUT_MS.get(method)) is not None:
|
|
File without changes
|
|
File without changes
|
{stagehand-4.2.0a0.dev1540 → stagehand-4.2.0a0.dev1543}/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.dev1540 → stagehand-4.2.0a0.dev1543}/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.dev1540 → stagehand-4.2.0a0.dev1543}/src/stagehand/browserbase_services.py
RENAMED
|
File without changes
|
{stagehand-4.2.0a0.dev1540 → stagehand-4.2.0a0.dev1543}/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
|