feat(goto): add actions runner with locators and auto-batching - #877
feat(goto): add actions runner with locators and auto-batching#877Kikobeats wants to merge 4 commits into
Conversation
Execute a flat ordered actions list after navigation — P-selector locators, unified wait, request buffering, and capture collection — so callers can express click → wait → screenshot sequences. Co-authored-by: Cursor <cursoragent@cursor.com>
📝 WalkthroughWalkthroughThe PR adds browser action execution to ChangesBrowser action execution
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant goto
participant runActions
participant batchActions
participant handlers
participant page
goto->>runActions: execute configured actions
runActions->>batchActions: create ordered action waves
batchActions-->>runActions: return sequential and concurrent waves
runActions->>handlers: execute each action with context
handlers->>page: perform waits, interactions, or captures
page-->>runActions: return responses and capture buffers
runActions-->>goto: return action captures
Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Skip the redundant final capture when actions already produced screenshot/pdf buffers so mid-flow captures win. Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
Actionable comments posted: 11
🧹 Nitpick comments (7)
packages/goto/test/unit/actions/handlers.js (1)
28-32: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winAdd a query-string case to the glob test.
The current pattern has no
?. Add a case such as*/user?id=*matched againsthttps://api.example.com/user?id=1. That case fails with the currentglobToRegExpimplementation and pins the fix.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/goto/test/unit/actions/handlers.js` around lines 28 - 32, Add a query-string assertion to the “globToRegExp matches request patterns” test using a pattern like */user?id=* and a matching URL such as https://api.example.com/user?id=1, ensuring the test exercises and pins correct question-mark handling.packages/goto/src/actions/handlers.js (2)
62-69: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value
injectignoresaction.timeout.Every other handler clamps a per-action timeout. This handler forwards the shared budget only. Apply
clampTimeout(action.timeout, timeout)for consistency.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/goto/src/actions/handlers.js` around lines 62 - 69, The inject handler currently forwards only the shared timeout budget. Update inject to pass clampTimeout(action.timeout, timeout) to the inject call, preserving the existing styles, scripts, and modules forwarding.
87-89: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueReuse the already computed budget.
Line 76 assigns
budget = clampTimeout(action.timeout, timeout). Line 88 repeats the same call.♻️ Proposed refactor
if (action.timeout != null && action.timeout !== '') { - return setTimeout(clampTimeout(action.timeout, timeout)) + return setTimeout(budget) }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/goto/src/actions/handlers.js` around lines 87 - 89, Reuse the existing budget value computed in the action timeout handling instead of calling clampTimeout again; update the setTimeout call in the relevant handler to pass budget while preserving the current timeout guard.packages/goto/src/actions/index.js (1)
98-98: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueUse the existing import.
Line 5 already imports
batchActions. The inlinerequire('./batch')duplicates it.♻️ Proposed refactor
-module.exports = { runActions, batchActions: require('./batch').batchActions, handlers } +module.exports = { runActions, batchActions, handlers }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/goto/src/actions/index.js` at line 98, Update the module.exports declaration to reuse the existing batchActions import from line 5 instead of calling require('./batch').batchActions inline, while preserving the exported API and handlers.packages/goto/test/unit/actions/locator.js (1)
44-46: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd escaping cases for backslash and
).The suite covers a plain double quote only. Add cases for a value that contains a backslash and for text that contains
). Both are the inputs that break selector compilation today.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/goto/test/unit/actions/locator.js` around lines 44 - 46, Add test cases alongside “escape quotes double quotes” for escape(), covering inputs containing a backslash and containing “)”, and assert each produces the correctly escaped selector text.packages/goto/src/index.js (1)
529-530: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winSilently ignored options need a signal.
When
actionsis set, this branch dropswaitForSelector,waitForFunction,waitForTimeout,click,scroll,modules,scripts, andstyles. A caller that sends both sets receives no error and no log. Emit a debug log that names the ignored options, or reject the combination at the API layer.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/goto/src/index.js` around lines 529 - 530, Update the actions-handling branch in the main flow around waitForSelector so that when actions is set alongside any of waitForSelector, waitForFunction, waitForTimeout, click, scroll, modules, scripts, or styles, it emits a debug log naming the ignored options or rejects the combination at the API boundary; preserve existing behavior when no conflicting options are provided.packages/goto/src/actions/locator.js (1)
34-46: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueAlign the two locator checks on one predicate.
The
waitbranch uses truthiness. The default branch uses!= nulloverLOCATOR_KEYS. An action such as{ type: 'click', selector: '' }passeshasElementLocatorand then makestoSelectorthrowlocator: no strategy. Use the same emptiness rule in both branches.♻️ Proposed refactor
+const isSet = value => value != null && value !== '' + const hasElementLocator = action => { + const keys = action.type === 'wait' ? LOCATOR_KEYS.filter(key => key !== 'text') : LOCATOR_KEYS + return keys.some(key => isSet(action[key])) - if (action.type === 'wait') { - return Boolean( - action.selector || - action.role || - action.label || - action.placeholder || - action.testId || - action.alt - ) - } - return LOCATOR_KEYS.some(key => action[key] != null) }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/goto/src/actions/locator.js` around lines 34 - 46, Update hasElementLocator so both the wait branch and the LOCATOR_KEYS branch use the same truthiness-based predicate, ensuring empty locator values such as selector: '' are rejected before toSelector runs.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/goto/src/actions/batch.js`:
- Around line 9-13: Update batchKey and the runActions scheduling flow so pdf
and screenshot actions are not grouped into the same parallel capture wave on a
shared Puppeteer page. Ensure these actions execute sequentially, or use
isolated pages when allowing concurrency, while preserving existing batching for
safe action types.
In `@packages/goto/src/actions/handlers.js`:
- Around line 93-99: Update packages/goto/src/actions/handlers.js lines 93-99 in
scroll and lines 116-122 in screenshot: accept the context timeout in both
handlers, compute the clamped action budget once per handler with
clampTimeout(action.timeout, timeout), and pass it as the timeout option to
page.waitForSelector.
- Around line 119-121: Update the selector handling around page.$ so a missing
element handle is handled without calling boundingBox, and ensure any obtained
handle is disposed after use. Preserve setting opts.clip only when a valid
bounding box is returned.
- Around line 109-111: Restrict the evaluate action handled by evaluate so
untrusted action inputs cannot execute arbitrary page scripts through
page.evaluate. Reject or disallow the evaluate action type/property at the
action validation or dispatch boundary, while preserving existing handling for
approved action types.
- Around line 26-31: Update globToRegExp to escape ? along with all regex
metacharacters before translating glob wildcards, use a wildcard representation
that avoids super-linear backtracking, and reject patterns exceeding the
established safe length limit before constructing RegExp. Preserve anchored
full-pattern matching and ensure invalid caller-supplied patterns do not
propagate compilation errors through waitForResponse.
In `@packages/goto/src/actions/index.js`:
- Around line 81-96: Update waitMode to reuse the shared hasElementLocator
helper from locator.js for element classification instead of maintaining a
duplicate selector-key list. Preserve the existing text, request, timeout, and
unknown classifications.
- Around line 21-26: Bound responseBuffer in the action response handler near
runActions so it cannot grow without limit: retain only the latest fixed number
of responses, dropping the oldest entry when the cap is reached. Preserve the
existing response objects needed by wait request actions and keep
page.on('response', onResponse) behavior unchanged.
In `@packages/goto/src/actions/locator.js`:
- Line 5: Update the escape function to replace backslashes before escaping
double quotes, ensuring existing backslashes are preserved correctly in
generated P-selectors while retaining the current quote-escaping behavior.
- Line 19: Update the `action.text` interpolation in the locator action so the
value used inside `::-p-text()` is escaped as a string: escape backslashes
first, then escape closing parentheses. Preserve the existing behavior of
returning the P-selector when `action.text` is present.
In `@packages/goto/src/index.js`:
- Around line 524-528: Use a dedicated action-list budget when invoking
runActions in packages/goto/src/index.js at lines 524-528, rather than passing
timeouts.action/actionTimeout intended for individual setup calls. In
packages/goto/src/actions/index.js at lines 45-46, compute one shared deadline
when runActions starts and derive each action’s timeout from the remaining time,
preserving the overall action-list budget regardless of action count.
- Around line 516-522: Extend the pre-navigation CSP-bypass condition to also
cover the actions-enabled path identified by hasActions, ensuring
page.setBypassCSP(true) runs before navigation whenever inject actions may
execute. Keep the existing modules, scripts, and styles conditions unchanged,
and preserve the inject call’s current behavior.
---
Nitpick comments:
In `@packages/goto/src/actions/handlers.js`:
- Around line 62-69: The inject handler currently forwards only the shared
timeout budget. Update inject to pass clampTimeout(action.timeout, timeout) to
the inject call, preserving the existing styles, scripts, and modules
forwarding.
- Around line 87-89: Reuse the existing budget value computed in the action
timeout handling instead of calling clampTimeout again; update the setTimeout
call in the relevant handler to pass budget while preserving the current timeout
guard.
In `@packages/goto/src/actions/index.js`:
- Line 98: Update the module.exports declaration to reuse the existing
batchActions import from line 5 instead of calling
require('./batch').batchActions inline, while preserving the exported API and
handlers.
In `@packages/goto/src/actions/locator.js`:
- Around line 34-46: Update hasElementLocator so both the wait branch and the
LOCATOR_KEYS branch use the same truthiness-based predicate, ensuring empty
locator values such as selector: '' are rejected before toSelector runs.
In `@packages/goto/src/index.js`:
- Around line 529-530: Update the actions-handling branch in the main flow
around waitForSelector so that when actions is set alongside any of
waitForSelector, waitForFunction, waitForTimeout, click, scroll, modules,
scripts, or styles, it emits a debug log naming the ignored options or rejects
the combination at the API boundary; preserve existing behavior when no
conflicting options are provided.
In `@packages/goto/test/unit/actions/handlers.js`:
- Around line 28-32: Add a query-string assertion to the “globToRegExp matches
request patterns” test using a pattern like */user?id=* and a matching URL such
as https://api.example.com/user?id=1, ensuring the test exercises and pins
correct question-mark handling.
In `@packages/goto/test/unit/actions/locator.js`:
- Around line 44-46: Add test cases alongside “escape quotes double quotes” for
escape(), covering inputs containing a backslash and containing “)”, and assert
each produces the correctly escaped selector text.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: b1cbfa39-6e75-45c0-b4bd-166145e2f5fc
📒 Files selected for processing (8)
packages/goto/src/actions/batch.jspackages/goto/src/actions/handlers.jspackages/goto/src/actions/index.jspackages/goto/src/actions/locator.jspackages/goto/src/index.jspackages/goto/test/unit/actions/batch.jspackages/goto/test/unit/actions/handlers.jspackages/goto/test/unit/actions/locator.js
| async evaluate (page, action) { | ||
| await page.evaluate(action.expression) | ||
| }, |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Description: Locate validation of the `actions` payload and the `evaluate` action type.
set -euo pipefail
rg -n --type=js -C4 "\bactions\b" --glob '!**/node_modules/**' --glob '*schema*' --glob '*valid*' || true
rg -n --type=js -C4 "'evaluate'|\"evaluate\"" --glob '!**/node_modules/**' || trueRepository: microlinkhq/browserless
Length of output: 161
🏁 Script executed:
#!/bin/bash
set -u
printf 'Tracked JS files under packages/goto:\n'
git ls-files | grep '^packages/goto/.*\.js$' || true
printf '\nCandidate handler file:\n'
fd -a 'handlers\.js' . | sed 's#^\./##' | grep 'packages/goto' || true
if [ -f packages/goto/src/actions/handlers.js ]; then
echo
echo '--- packages/goto/src/actions/handlers.js ---'
cat -n packages/goto/src/actions/handlers.js
fi
printf '\nReferences to packages/goto/src/actions:\n'
rg -n -C 3 'packages/goto/src/actions|from[\"\']\.[^\"\']*actions|handleActions|actions' --glob '!**/node_modules/**' . || trueRepository: microlinkhq/browserless
Length of output: 6497
🏁 Script executed:
#!/bin/bash
set -u
printf '--- packages/goto/src/actions/batch.js ---\n'
cat -n packages/goto/src/actions/batch.js
printf '\n--- packages/goto/src/actions/index.js ---\n'
cat -n packages/goto/src/actions/index.js
printf '\n--- imports/usages of goto actions package ---\n'
rg -n -C 4 'goto[\\/].*go|goto[\\/].*action|actions\.go|from [\"\'][^.\"\']*/go[0-9a-z]*|[\\s,][\w/.-]*go[0-9a-z]*\b' --glob '!**/node_modules/**' . || true
printf '\n--- endpoint/schema references for goto actions ---\n'
rg -n -C 5 '"action(s)?|actions[|":]|evaluate expression|parse body|validate|z\.|Joi|ajv|schema' --glob '!**/node_modules/**' packages .github . 2>/dev/null | head -n 240 || trueRepository: microlinkhq/browserless
Length of output: 5079
🏁 Script executed:
#!/bin/bash
set -u
printf '--- packages/goto/src/actions/batch.js ---\n'
cat -n packages/goto/src/actions/batch.js
printf '\n--- packages/goto/src/actions/index.js ---\n'
cat -n packages/goto/src/actions/index.js
printf '\n--- imports/usages of goto actions package ---\n'
rg -n -C 4 'goto[\\/].*go|goto[\\/].*action|actions\.go|from ["'"'"'][^"'"'"'"]*/go[0-9a-z]*|[\\s,][\w/.-]*go[0-9a-z]*\b' --glob '!**/node_modules/**' . || true
printf '\n--- endpoint/schema references for goto actions ---\n'
rg -n -C 5 '"action(s)?|actions[|":]|evaluate expression|parse body|validate|z\.|Joi|ajv|schema' --glob '!**/node_modules/**' packages .github . 2>/dev/null | head -n 240 || trueRepository: microlinkhq/browserless
Length of output: 50382
🏁 Script executed:
#!/bin/bash
set -u
printf '--- packages/goto/src/index.js relevant sections ---\n'
wc -l packages/goto/src/index.js
sed -n '1,140p' packages/goto/src/index.js | cat -n
printf '\n--- packages/goto/src/index.js line 240-310 ---\n'
sed -n '240,310p' packages/goto/src/index.js | cat -n
printf '\n--- direct occurrences of runActions/runOne/exported goto options ---\n'
rg -n --type=js -C 3 'runActions|actions|evaluate|expression|page\.evaluate' packages/goto/src packages/browserless/src packages/browserless/test --glob '!**/node_modules/**' || true
printf '\n--- action/actionlist occurrences in goto package only ---\n'
rg -n -C 3 '"action|action:|actions\.|evaluate"\s*:|expression' packages/goto/src packages/goto/test packages/goto/README.md --glob '!**/node_modules/**' || trueRepository: microlinkhq/browserless
Length of output: 41271
Validate expression as trusted input before running evaluate actions.
action.type is only rejected for unknown handlers; action.expression is still passed directly to page.evaluate() in the page context. If actions is supplied through an HTTP/API layer, reject or disallow the evaluate action type/property so callers cannot run arbitrary page script against the loaded origin.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/goto/src/actions/handlers.js` around lines 109 - 111, Restrict the
evaluate action handled by evaluate so untrusted action inputs cannot execute
arbitrary page scripts through page.evaluate. Reject or disallow the evaluate
action type/property at the action validation or dispatch boundary, while
preserving existing handling for approved action types.
Address the Bugbot and CodeRabbit review on #877. Correctness: - `globToRegExp` escaped every metacharacter except `?`, so `*/user?id=*` compiled to an optional `r` and matched the wrong URLs; a leading `?` threw a SyntaxError out of `waitForResponse`. Escape per literal segment and bound the pattern at 512 chars, which also caps the `*a*a*a*` backtracking blowup. - `wait request` resolved from the earliest buffered response forever, so a second wait on the same pattern returned a stale hit. Matched responses are now consumed from the buffer on both the buffered and the live path. - `::-p-text()` interpolated raw text, and `escape` replaced quotes without escaping backslashes first. Both produced invalid P-selectors. - CSP bypass only ran for the top-level modules/scripts/styles options, so an `inject` action failed on any page sending a restrictive policy. Budget: - The action list ran on `timeouts.action` (1/11 of base, sized for a single setup call) applied per action, so a `10s` wait resolved in ~1.8s while total runtime grew with the action count. It now draws from `timeouts.actions` under one deadline computed when the run starts. - `scroll`, `screenshot`, `fill` and `click` passed no timeout to Puppeteer and fell back to its 30s default, outliving the request budget. Stability: - `pdf` toggles print media emulation on the shared page, so it can no longer batch beside `screenshot`; it is a barrier. - `screenshot` re-queried the element with `page.$` after waiting, which returns null on detach and leaked the handle. It reuses the waited handle and disposes it. - The response buffer retained every CDP handle for the whole run; capped at 100. Also drops the duplicated locator key list in `waitMode`, unifies the empty-value predicate across `toSelector`/`hasElementLocator`, and logs the legacy options ignored when `actions` is set. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RzXDbCyy485gcE6hdUmzV6
|
Addressed in 25108e0. Every finding from Bugbot and CodeRabbit, with the verdict per thread. Fixed — correctness
Fixed — budget
Fixed — stability
Fixed — quality
Not fixed
Tests: 32 passing in |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 25108e0. Configure here.
There was a problem hiding this comment.
♻️ Duplicate comments (1)
packages/goto/src/actions/handlers.js (1)
33-36: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick winReplace the backtracking glob regular expression.
The 512-character limit does not bound match complexity. Each
*becomes a greedy[\s\S]*, so a short pattern such as*a*a*a*a*zcan cause extensive backtracking on a long non-matching response URL.waitForResponsetests this predicate for buffered and live responses, which can block the Node.js event loop.Use a linear-time glob matcher based on sequential literal searches instead of
new RegExp. Preserve full-string matching and literal semantics. Add a regression case for repeated wildcards and a long non-match.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/goto/src/actions/handlers.js` around lines 33 - 36, Replace the regex construction in the response-matching handler with a linear-time sequential glob matcher that searches each escaped literal segment in order, while preserving wildcard behavior, full-string matching, and literal semantics. Ensure the matcher handles leading and trailing wildcards correctly and is used by waitForResponse for buffered and live responses. Add a regression test covering repeated wildcards against a long non-matching URL.Source: Linters/SAST tools
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Duplicate comments:
In `@packages/goto/src/actions/handlers.js`:
- Around line 33-36: Replace the regex construction in the response-matching
handler with a linear-time sequential glob matcher that searches each escaped
literal segment in order, while preserving wildcard behavior, full-string
matching, and literal semantics. Ensure the matcher handles leading and trailing
wildcards correctly and is used by waitForResponse for buffered and live
responses. Add a regression test covering repeated wildcards against a long
non-matching URL.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 60b83368-a56c-4beb-a827-7c9bbbd2c226
📒 Files selected for processing (9)
packages/goto/src/actions/batch.jspackages/goto/src/actions/handlers.jspackages/goto/src/actions/index.jspackages/goto/src/actions/locator.jspackages/goto/src/index.jspackages/goto/test/unit/actions/batch.jspackages/goto/test/unit/actions/handlers.jspackages/goto/test/unit/actions/index.jspackages/goto/test/unit/actions/locator.js
🚧 Files skipped from review as they are similar to previous changes (3)
- packages/goto/test/unit/actions/locator.js
- packages/goto/src/actions/locator.js
- packages/goto/src/actions/index.js
The shared deadline introduced in 25108e0 let `remaining()` reach 0 and passed that through as a timeout, which disables the cap on both sides it was meant to enforce: `run` only wraps in `pTimeout` when `timeout` is truthy, and Puppeteer reads 0 as "wait forever". A late action therefore ran uncapped — the opposite of the budget's intent. Fail the action instead: once the budget is gone there is no time left to run it in. Reported by Cursor Bugbot on #877. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RzXDbCyy485gcE6hdUmzV6
|
Fixed in 37d683c — good catch, and a real bug I introduced with the shared deadline. The failure is worse than "skips the timeout": a zero budget disables the cap on both layers it was supposed to enforce.
A late action would have run completely uncapped, the exact opposite of what the budget exists to do. The fix rejects the action instead of running it with a meaningless budget: once the deadline has passed there is no time left to run it in. This also tightened the shared-deadline test — two 33 unit tests passing. |

Summary
@browserless/gotoactions/runner:toSelectorP-selector compiler, unifiedwait, response buffer forwait request, auto-batching (inject+inject,screenshot+pdf), timeout clampactionsis present, skip legacy click/scroll/wait/inject path; returnactionCapturesfor mid-flow screenshot/pdf buffers@browserless/screenshot/@browserless/pdf: when actions include a capture step, skip the redundant final capture and return the last action bufferTest plan
ava 'test/unit/actions/**/*.js'(17 passing)Note
Medium Risk
Changes the main goto post-load path and screenshot/pdf output selection when
actionsis used; behavior is gated behind the new option and covered by unit tests, but it affects core browser automation flows.Overview
Adds a post-navigation
actionspipeline to@browserless/goto: ordered steps (click, fill, scroll, wait, inject, evaluate, screenshot, pdf) with P-selector locators, shared request-deadline timeouts, and auto-batching so consecutiveinjectorscreenshotwaves run in parallel whilepdfstays a barrier.When
actionsis set, legacyclick/scroll/waitFor*/ top-level inject options are skipped (logged as ignored);gotoreturnsactionCaptures(screenshot/pdf buffers).@browserless/screenshotand@browserless/pdfdetect capture actions and return the last action buffer instead of doing a second capture, and skip extra readiness/full-document prep when appropriate.Reviewed by Cursor Bugbot for commit 37d683c. Bugbot is set up for automated code reviews on this repo. Configure here.
Summary by CodeRabbit
New Features
Bug Fixes