stagehand 4.2.0a0.dev1590__tar.gz → 4.2.0a0.dev1591__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.
Files changed (36) hide show
  1. {stagehand-4.2.0a0.dev1590 → stagehand-4.2.0a0.dev1591}/PKG-INFO +1 -1
  2. {stagehand-4.2.0a0.dev1590 → stagehand-4.2.0a0.dev1591}/pyproject.toml +1 -1
  3. {stagehand-4.2.0a0.dev1590 → stagehand-4.2.0a0.dev1591}/src/stagehand/_extension/content-script.js +74 -81
  4. {stagehand-4.2.0a0.dev1590 → stagehand-4.2.0a0.dev1591}/src/stagehand/_extension/service-worker.js +86 -36
  5. {stagehand-4.2.0a0.dev1590 → stagehand-4.2.0a0.dev1591}/src/stagehand/_generated/protocol_version.py +1 -1
  6. {stagehand-4.2.0a0.dev1590 → stagehand-4.2.0a0.dev1591}/src/stagehand/rpc_client.py +4 -1
  7. {stagehand-4.2.0a0.dev1590 → stagehand-4.2.0a0.dev1591}/README.md +0 -0
  8. {stagehand-4.2.0a0.dev1590 → stagehand-4.2.0a0.dev1591}/src/stagehand/__init__.py +0 -0
  9. {stagehand-4.2.0a0.dev1590 → stagehand-4.2.0a0.dev1591}/src/stagehand/_extension/blank.html +0 -0
  10. {stagehand-4.2.0a0.dev1590 → stagehand-4.2.0a0.dev1591}/src/stagehand/_extension/manifest.json +0 -0
  11. {stagehand-4.2.0a0.dev1590 → stagehand-4.2.0a0.dev1591}/src/stagehand/_extension/offscreen/service-worker-heartbeat.html +0 -0
  12. {stagehand-4.2.0a0.dev1590 → stagehand-4.2.0a0.dev1591}/src/stagehand/_extension/offscreen/service-worker-heartbeat.js +0 -0
  13. {stagehand-4.2.0a0.dev1590 → stagehand-4.2.0a0.dev1591}/src/stagehand/_extension/wake-service-worker.html +0 -0
  14. {stagehand-4.2.0a0.dev1590 → stagehand-4.2.0a0.dev1591}/src/stagehand/_extension/wake-service-worker.js +0 -0
  15. {stagehand-4.2.0a0.dev1590 → stagehand-4.2.0a0.dev1591}/src/stagehand/_generated/__init__.py +0 -0
  16. {stagehand-4.2.0a0.dev1590 → stagehand-4.2.0a0.dev1591}/src/stagehand/_generated/input_types.py +0 -0
  17. {stagehand-4.2.0a0.dev1590 → stagehand-4.2.0a0.dev1591}/src/stagehand/_generated/models.py +0 -0
  18. {stagehand-4.2.0a0.dev1590 → stagehand-4.2.0a0.dev1591}/src/stagehand/_sdk_identity.py +0 -0
  19. {stagehand-4.2.0a0.dev1590 → stagehand-4.2.0a0.dev1591}/src/stagehand/_validation.py +0 -0
  20. {stagehand-4.2.0a0.dev1590 → stagehand-4.2.0a0.dev1591}/src/stagehand/browser.py +0 -0
  21. {stagehand-4.2.0a0.dev1590 → stagehand-4.2.0a0.dev1591}/src/stagehand/browser_clipboard.py +0 -0
  22. {stagehand-4.2.0a0.dev1590 → stagehand-4.2.0a0.dev1591}/src/stagehand/browser_context.py +0 -0
  23. {stagehand-4.2.0a0.dev1590 → stagehand-4.2.0a0.dev1591}/src/stagehand/browserbase_services.py +0 -0
  24. {stagehand-4.2.0a0.dev1590 → stagehand-4.2.0a0.dev1591}/src/stagehand/browserbase_session.py +0 -0
  25. {stagehand-4.2.0a0.dev1590 → stagehand-4.2.0a0.dev1591}/src/stagehand/cdp_client.py +0 -0
  26. {stagehand-4.2.0a0.dev1590 → stagehand-4.2.0a0.dev1591}/src/stagehand/client_models.py +0 -0
  27. {stagehand-4.2.0a0.dev1590 → stagehand-4.2.0a0.dev1591}/src/stagehand/client_types.py +0 -0
  28. {stagehand-4.2.0a0.dev1590 → stagehand-4.2.0a0.dev1591}/src/stagehand/extension_assets.py +0 -0
  29. {stagehand-4.2.0a0.dev1590 → stagehand-4.2.0a0.dev1591}/src/stagehand/file_upload.py +0 -0
  30. {stagehand-4.2.0a0.dev1590 → stagehand-4.2.0a0.dev1591}/src/stagehand/locator.py +0 -0
  31. {stagehand-4.2.0a0.dev1590 → stagehand-4.2.0a0.dev1591}/src/stagehand/page.py +0 -0
  32. {stagehand-4.2.0a0.dev1590 → stagehand-4.2.0a0.dev1591}/src/stagehand/py.typed +0 -0
  33. {stagehand-4.2.0a0.dev1590 → stagehand-4.2.0a0.dev1591}/src/stagehand/response.py +0 -0
  34. {stagehand-4.2.0a0.dev1590 → stagehand-4.2.0a0.dev1591}/src/stagehand/stagehand.py +0 -0
  35. {stagehand-4.2.0a0.dev1590 → stagehand-4.2.0a0.dev1591}/src/stagehand/timeouts.py +0 -0
  36. {stagehand-4.2.0a0.dev1590 → stagehand-4.2.0a0.dev1591}/src/stagehand/webmcp.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: stagehand
3
- Version: 4.2.0a0.dev1590
3
+ Version: 4.2.0a0.dev1591
4
4
  Summary: Browserbase's SDK for building browser agents
5
5
  Keywords: ai,agent,ai-agent,browser,browser-agent,browser-automation,computer-use,headless,playwright,cdp,llm,automation,web-scraping,testing
6
6
  Author: Browserbase
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "stagehand"
3
- version = "4.2.0a0.dev1590"
3
+ version = "4.2.0a0.dev1591"
4
4
  description = "Browserbase's SDK for building browser agents"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -990,7 +990,7 @@ var checkState = (el, state) => {
990
990
  /**
991
991
  * Set up MutationObservers on all shadow roots to detect changes.
992
992
  */
993
- var setupShadowObservers = (callback, observers) => {
993
+ var setupShadowObservers = (callback, observers, isSettled) => {
994
994
  const seenRoots = /* @__PURE__ */ new WeakSet();
995
995
  const observeShadowRoots = (node) => {
996
996
  const shadowRoot = getOpenOrClosedShadowRoot(node);
@@ -1000,6 +1000,7 @@ var setupShadowObservers = (callback, observers) => {
1000
1000
  callback();
1001
1001
  scan();
1002
1002
  });
1003
+ observers.push(shadowObserver);
1003
1004
  shadowObserver.observe(shadowRoot, {
1004
1005
  childList: true,
1005
1006
  subtree: true,
@@ -1011,14 +1012,13 @@ var setupShadowObservers = (callback, observers) => {
1011
1012
  "disabled"
1012
1013
  ]
1013
1014
  });
1014
- observers.push(shadowObserver);
1015
1015
  for (const child of Array.from(shadowRoot.children)) observeShadowRoots(child);
1016
1016
  }
1017
1017
  for (const child of Array.from(node.children)) observeShadowRoots(child);
1018
1018
  };
1019
1019
  const root = document.documentElement || document.body;
1020
1020
  const scan = () => {
1021
- if (root) observeShadowRoots(root);
1021
+ if (!isSettled() && root) observeShadowRoots(root);
1022
1022
  };
1023
1023
  scan();
1024
1024
  return scan;
@@ -1029,106 +1029,99 @@ var setupShadowObservers = (callback, observers) => {
1029
1029
  *
1030
1030
  * @param selectorRaw - CSS selector or XPath expression to wait for
1031
1031
  * @param stateRaw - Element state: 'attached' | 'detached' | 'visible' | 'hidden'
1032
- * @param timeoutRaw - Maximum time to wait in milliseconds
1032
+ * @param timeoutRaw - Maximum time to wait in milliseconds; defaults to 30,000, zero is unlimited
1033
1033
  * @param pierceShadowRaw - Whether to search inside shadow DOM
1034
- * @returns Promise that resolves to true when condition is met, or rejects on timeout
1034
+ * @returns A disposable handle whose promise resolves when the condition is met
1035
1035
  */
1036
- function waitForSelector(selectorRaw, stateRaw, timeoutRaw, pierceShadowRaw) {
1036
+ function createSelectorWait(selectorRaw, stateRaw, timeoutRaw, pierceShadowRaw) {
1037
1037
  const selector = String(selectorRaw ?? "").trim();
1038
1038
  const state = String(stateRaw ?? "visible") || "visible";
1039
- const timeout = typeof timeoutRaw === "number" && timeoutRaw > 0 ? timeoutRaw : 3e4;
1039
+ const timeout = typeof timeoutRaw === "number" && timeoutRaw >= 0 ? timeoutRaw : 3e4;
1040
1040
  const pierceShadow = pierceShadowRaw !== false;
1041
- return new Promise((resolve, reject) => {
1042
- let timeoutId = null;
1043
- let domReadyHandler = null;
1041
+ let dispose = () => {};
1042
+ const promise = new Promise((resolve, reject) => {
1044
1043
  let settled = false;
1045
- const clearTimer = () => {
1046
- if (timeoutId !== null) {
1047
- clearTimeout(timeoutId);
1048
- timeoutId = null;
1049
- }
1050
- };
1051
- if (checkState(findElement(selector, pierceShadow), state)) {
1052
- settled = true;
1053
- resolve(true);
1054
- return;
1055
- }
1044
+ let timeoutId;
1045
+ let shadowScanInterval;
1046
+ let domReadyHandler;
1047
+ let rescanShadowRoots;
1056
1048
  const observers = [];
1057
- let shadowScanInterval = null;
1058
- let rescanShadowRoots = null;
1059
- const cleanup = () => {
1060
- for (const obs of observers) obs.disconnect();
1061
- if (shadowScanInterval !== null) {
1062
- clearInterval(shadowScanInterval);
1063
- shadowScanInterval = null;
1064
- }
1049
+ const settle = (error) => {
1050
+ if (settled) return;
1051
+ settled = true;
1052
+ clearTimeout(timeoutId);
1053
+ clearInterval(shadowScanInterval);
1054
+ for (const observer of observers) observer.disconnect();
1055
+ observers.length = 0;
1056
+ rescanShadowRoots = void 0;
1065
1057
  if (domReadyHandler) {
1066
1058
  document.removeEventListener("DOMContentLoaded", domReadyHandler);
1067
- domReadyHandler = null;
1059
+ domReadyHandler = void 0;
1068
1060
  }
1061
+ if (error) reject(error);
1062
+ else resolve(true);
1069
1063
  };
1064
+ dispose = () => settle(/* @__PURE__ */ new Error("Selector wait disposed"));
1070
1065
  const check = () => {
1071
1066
  if (settled) return;
1072
- if (checkState(findElement(selector, pierceShadow), state)) {
1073
- settled = true;
1074
- clearTimer();
1075
- cleanup();
1076
- resolve(true);
1067
+ try {
1068
+ if (checkState(findElement(selector, pierceShadow), state)) settle();
1069
+ } catch (error) {
1070
+ settle(error instanceof Error ? error : new Error(String(error)));
1077
1071
  }
1078
1072
  };
1079
- if (!(document.body || document.documentElement)) {
1073
+ const setupObservers = () => {
1074
+ if (settled) return;
1075
+ const root = document.body || document.documentElement;
1076
+ if (!root) return;
1077
+ try {
1078
+ const mainObserver = new MutationObserver(() => {
1079
+ check();
1080
+ rescanShadowRoots?.();
1081
+ });
1082
+ observers.push(mainObserver);
1083
+ mainObserver.observe(root, {
1084
+ childList: true,
1085
+ subtree: true,
1086
+ attributes: true,
1087
+ attributeFilter: [
1088
+ "style",
1089
+ "class",
1090
+ "hidden",
1091
+ "disabled"
1092
+ ]
1093
+ });
1094
+ if (pierceShadow) {
1095
+ rescanShadowRoots = setupShadowObservers(check, observers, () => settled);
1096
+ shadowScanInterval = setInterval(() => {
1097
+ rescanShadowRoots?.();
1098
+ check();
1099
+ }, 100);
1100
+ }
1101
+ } catch (error) {
1102
+ settle(error instanceof Error ? error : new Error(String(error)));
1103
+ }
1104
+ };
1105
+ check();
1106
+ if (settled) return;
1107
+ if (document.body || document.documentElement) setupObservers();
1108
+ else {
1080
1109
  domReadyHandler = () => {
1110
+ if (settled) return;
1081
1111
  document.removeEventListener("DOMContentLoaded", domReadyHandler);
1082
- domReadyHandler = null;
1112
+ domReadyHandler = void 0;
1083
1113
  check();
1084
1114
  setupObservers();
1085
1115
  };
1086
1116
  document.addEventListener("DOMContentLoaded", domReadyHandler);
1087
- timeoutId = setTimeout(() => {
1088
- if (settled) return;
1089
- settled = true;
1090
- clearTimer();
1091
- cleanup();
1092
- reject(/* @__PURE__ */ new Error(`waitForSelector: Timeout ${timeout}ms exceeded waiting for "${selector}" to be ${state}`));
1093
- }, timeout);
1094
- return;
1095
1117
  }
1096
- const setupObservers = () => {
1097
- const root = document.body || document.documentElement;
1098
- if (!root) return;
1099
- const mainObserver = new MutationObserver(() => {
1100
- check();
1101
- rescanShadowRoots?.();
1102
- });
1103
- mainObserver.observe(root, {
1104
- childList: true,
1105
- subtree: true,
1106
- attributes: true,
1107
- attributeFilter: [
1108
- "style",
1109
- "class",
1110
- "hidden",
1111
- "disabled"
1112
- ]
1113
- });
1114
- observers.push(mainObserver);
1115
- if (pierceShadow) {
1116
- rescanShadowRoots = setupShadowObservers(check, observers);
1117
- shadowScanInterval = setInterval(() => {
1118
- rescanShadowRoots?.();
1119
- check();
1120
- }, 100);
1121
- }
1122
- };
1123
- setupObservers();
1124
- timeoutId = setTimeout(() => {
1125
- if (settled) return;
1126
- settled = true;
1127
- clearTimer();
1128
- cleanup();
1129
- reject(/* @__PURE__ */ new Error(`waitForSelector: Timeout ${timeout}ms exceeded waiting for "${selector}" to be ${state}`));
1130
- }, timeout);
1118
+ if (!settled && timeout > 0) timeoutId = setTimeout(() => settle(/* @__PURE__ */ new Error(`waitForSelector: Timeout ${timeout}ms exceeded waiting for "${selector}" to be ${state}`)), timeout);
1131
1119
  });
1120
+ promise.catch(() => {});
1121
+ return {
1122
+ promise,
1123
+ dispose: () => dispose()
1124
+ };
1132
1125
  }
1133
1126
  //#endregion
1134
1127
  //#region dom/locatorScripts/registry.ts
@@ -1142,7 +1135,7 @@ var locatorScripts = Object.freeze({
1142
1135
  resolveCssSelector,
1143
1136
  resolveTextSelector,
1144
1137
  resolveXPathMainWorld,
1145
- waitForSelector
1138
+ createSelectorWait
1146
1139
  });
1147
1140
  //#endregion
1148
1141
  //#region content-script.ts
@@ -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-535b80d78b84a5ad3ead386d5399029bb873b80e",
7366
+ version: "2.1.0-alpha-7d8dcef8765f0a9dce498e1cc9d68c6b91ac3892",
7367
7367
  "private": true,
7368
7368
  type: "module",
7369
7369
  exports: {
@@ -17071,33 +17071,82 @@ var Frame = class {
17071
17071
  return res.result.value;
17072
17072
  }
17073
17073
  /** Evaluate an internal expression in Stagehand's selected locator world. */
17074
- async evaluateInLocatorWorld(expression, progress) {
17074
+ async evaluateInLocatorWorld(buildExpression, progress) {
17075
+ const response = await this.evaluateLocatorExpression(buildExpression, { progress });
17076
+ if (response.exceptionDetails) throw new Error(response.exceptionDetails.text ?? "Locator-world evaluation failed");
17077
+ return response.result.value;
17078
+ }
17079
+ /** Own a disposable browser wait, including a handle delivered after expiry. */
17080
+ async waitInLocatorWorld(buildExpression, progress) {
17081
+ const dispose = (objectId) => Promise.all([progress.cleanup(() => this.session.send("Runtime.callFunctionOn", {
17082
+ objectId,
17083
+ functionDeclaration: "function() { this.dispose(); }",
17084
+ returnByValue: true
17085
+ })), progress.cleanup(() => this.session.send("Runtime.releaseObject", { objectId }))]);
17086
+ for (let attempt = 0;; attempt++) {
17087
+ progress.throwIfStopped();
17088
+ const response = await this.evaluateLocatorExpression(buildExpression, {
17089
+ progress,
17090
+ returnByValue: false,
17091
+ awaitPromise: false,
17092
+ onLateResult: async (late) => {
17093
+ if (late.result.objectId) await dispose(late.result.objectId);
17094
+ }
17095
+ });
17096
+ const objectId = response.result.objectId;
17097
+ let completed = false;
17098
+ try {
17099
+ if (response.exceptionDetails || !objectId) throw new Error(response.exceptionDetails?.exception?.description ?? response.exceptionDetails?.text ?? "Selector wait handle was not returned");
17100
+ let result;
17101
+ try {
17102
+ result = await progress.run("waiting for selector", () => this.session.send("Runtime.callFunctionOn", {
17103
+ objectId,
17104
+ functionDeclaration: "function() { return this.promise; }",
17105
+ awaitPromise: true,
17106
+ returnByValue: true
17107
+ }));
17108
+ } catch (error) {
17109
+ progress.throwIfStopped();
17110
+ const message = error instanceof Error ? error.message : String(error);
17111
+ if (attempt !== 0 || !message.includes("Cannot find context with specified id")) throw error;
17112
+ executionContexts.unregisterLocatorContext(this.session, response.contextId);
17113
+ continue;
17114
+ }
17115
+ if (result.exceptionDetails) throw new Error(result.exceptionDetails.exception?.description ?? result.exceptionDetails.text ?? "Selector wait failed");
17116
+ completed = true;
17117
+ return result.result.value;
17118
+ } finally {
17119
+ if (objectId) if (completed) progress.cleanup(() => this.session.send("Runtime.releaseObject", { objectId }));
17120
+ else await dispose(objectId);
17121
+ }
17122
+ }
17123
+ }
17124
+ async evaluateLocatorExpression(buildExpression, options) {
17125
+ const { progress } = options;
17075
17126
  await runLocatorStep(progress, "enabling runtime", () => this.session.send("Runtime.enable").catch((error) => {
17076
17127
  if (progress && isCdpClosedError(error)) throw error;
17077
17128
  }));
17078
17129
  let locatorWorld = await executionContexts.waitForLocatorWorld(this.session, this.frameId, 1e3, progress);
17130
+ const evaluate = () => runLocatorStep(progress, "evaluating locator helper", () => this.session.send("Runtime.evaluate", {
17131
+ expression: buildExpression(),
17132
+ contextId: locatorWorld.contextId,
17133
+ awaitPromise: options.awaitPromise ?? true,
17134
+ returnByValue: options.returnByValue ?? true
17135
+ }), options.onLateResult);
17079
17136
  let response;
17080
17137
  try {
17081
- response = await runLocatorStep(progress, "evaluating locator helper", () => this.session.send("Runtime.evaluate", {
17082
- expression,
17083
- contextId: locatorWorld.contextId,
17084
- awaitPromise: true,
17085
- returnByValue: true
17086
- }));
17138
+ response = await evaluate();
17087
17139
  } catch (error) {
17088
17140
  progress?.throwIfStopped();
17089
17141
  if (!(error instanceof Error ? error.message : String(error)).includes("Cannot find context with specified id")) throw error;
17090
17142
  executionContexts.unregisterLocatorContext(this.session, locatorWorld.contextId);
17091
17143
  locatorWorld = await executionContexts.waitForLocatorWorld(this.session, this.frameId, 1e3, progress);
17092
- response = await runLocatorStep(progress, "evaluating locator helper", () => this.session.send("Runtime.evaluate", {
17093
- expression,
17094
- contextId: locatorWorld.contextId,
17095
- awaitPromise: true,
17096
- returnByValue: true
17097
- }));
17144
+ response = await evaluate();
17098
17145
  }
17099
- if (response.exceptionDetails) throw new Error(response.exceptionDetails.text ?? "Locator-world evaluation failed");
17100
- return response.result.value;
17146
+ return {
17147
+ ...response,
17148
+ contextId: locatorWorld.contextId
17149
+ };
17101
17150
  }
17102
17151
  /** Page.captureScreenshot (frame-scoped session) */
17103
17152
  async screenshot(options, progress) {
@@ -54394,7 +54443,7 @@ var WebTracerProvider = class extends BasicTracerProvider {
54394
54443
  };
54395
54444
  var package_default = {
54396
54445
  name: "@browserbasehq/stagehand-extension",
54397
- version: "1.1.0-alpha-535b80d78b84a5ad3ead386d5399029bb873b80e",
54446
+ version: "1.1.0-alpha-7d8dcef8765f0a9dce498e1cc9d68c6b91ac3892",
54398
54447
  "private": true,
54399
54448
  type: "module",
54400
54449
  scripts: {
@@ -56333,7 +56382,7 @@ var Page = class Page {
56333
56382
  this.initScripts.push(source);
56334
56383
  }
56335
56384
  async ensureCursorScript() {
56336
- await this.mainFrameWrapper.evaluateInLocatorWorld("globalThis.__stagehandLocatorScripts.installCursorOverlay()").catch(() => {});
56385
+ await this.mainFrameWrapper.evaluateInLocatorWorld(() => "globalThis.__stagehandLocatorScripts.installCursorOverlay()").catch(() => {});
56337
56386
  }
56338
56387
  async enableCursorOverlay() {
56339
56388
  if (this.cursorEnabled) return;
@@ -56343,7 +56392,7 @@ var Page = class Page {
56343
56392
  async updateCursor(x, y, progress) {
56344
56393
  if (!this.cursorEnabled) return;
56345
56394
  try {
56346
- await this.mainFrameWrapper.evaluateInLocatorWorld(`globalThis.__stagehandLocatorScripts.moveCursorOverlay(${Math.round(x)}, ${Math.round(y)})`, progress);
56395
+ await this.mainFrameWrapper.evaluateInLocatorWorld(() => `globalThis.__stagehandLocatorScripts.moveCursorOverlay(${Math.round(x)}, ${Math.round(y)})`, progress);
56347
56396
  } catch {
56348
56397
  progress?.throwIfStopped();
56349
56398
  }
@@ -57356,27 +57405,28 @@ var Page = class Page {
57356
57405
  * @param selector CSS selector to wait for (supports '>>' for iframe hops)
57357
57406
  * @param options
57358
57407
  * @param options.state Element state to wait for: 'attached' | 'detached' | 'visible' | 'hidden' (default: 'visible')
57359
- * @param options.timeout Maximum time to wait in milliseconds (default: 30000)
57408
+ * @param options.timeout Maximum time to wait in milliseconds (default: 30000; zero is unlimited)
57360
57409
  * @param options.pierceShadow Whether to search inside shadow DOM (default: true)
57361
57410
  * @returns True when the condition is met
57362
57411
  * @throws Error if timeout is reached before the condition is met
57363
57412
  */
57364
- async waitForSelector(selector, options) {
57365
- const timeout = options?.timeout ?? 3e4;
57366
- const state = options?.state ?? "visible";
57367
- const pierceShadow = options?.pierceShadow ?? true;
57368
- const startTime = Date.now();
57369
- const root = this.mainFrameWrapper;
57370
- const { frame: targetFrame, selector: finalSelector } = await resolveLocatorTarget(this, root, selector);
57371
- const elapsed = Date.now() - startTime;
57372
- const remainingTimeout = Math.max(0, timeout - elapsed);
57373
- const expression = buildLocatorInvocation("waitForSelector", [
57374
- JSON.stringify(finalSelector),
57375
- JSON.stringify(state),
57376
- String(remainingTimeout),
57377
- String(pierceShadow)
57378
- ]);
57379
- return targetFrame.evaluateInLocatorWorld(expression);
57413
+ async waitForSelector(selector, options, parentProgress) {
57414
+ return runWithProgress(parentProgress ?? {
57415
+ name: "waitForSelector",
57416
+ timeout: options?.timeout ?? 3e4
57417
+ }, async (progress) => {
57418
+ const { frame: targetFrame, selector: finalSelector } = await resolveLocatorTarget(this, this.mainFrameWrapper, selector, progress);
57419
+ return targetFrame.waitInLocatorWorld(() => {
57420
+ const remaining = progress.remainingMs();
57421
+ progress.throwIfStopped();
57422
+ return buildLocatorInvocation("createSelectorWait", [
57423
+ JSON.stringify(finalSelector),
57424
+ JSON.stringify(options?.state ?? "visible"),
57425
+ String(remaining === Infinity ? 0 : Math.ceil(remaining)),
57426
+ String(options?.pierceShadow ?? true)
57427
+ ]);
57428
+ }, progress);
57429
+ });
57380
57430
  }
57381
57431
  /** Internal batch evaluation; page.evaluate continues to use the main world unchanged. */
57382
57432
  async evaluateWithShadowRoots(functionSource) {
@@ -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-535b80d78b84a5ad3ead386d5399029bb873b80e'
4
+ STAGEHAND_PROTOCOL_VERSION = '2.1.0-alpha-7d8dcef8765f0a9dce498e1cc9d68c6b91ac3892'
@@ -569,7 +569,10 @@ def _rpc_response_timeout_seconds(method: str, params: BaseModel) -> float | Non
569
569
  operation_timeout_ms = _numeric_property(params, "ms")
570
570
 
571
571
  if operation_timeout_ms is not None:
572
- if method in {"page.pdf", "page.snapshot"} and operation_timeout_ms == 0:
572
+ if (
573
+ method in {"page.pdf", "page.snapshot", "page.wait_for_selector"}
574
+ and operation_timeout_ms == 0
575
+ ):
573
576
  return None
574
577
  return (_RPC_RESPONSE_GRACE_MS + max(0, operation_timeout_ms)) / 1_000
575
578