browxai 0.7.0
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.
- package/LICENSE +21 -0
- package/README.md +139 -0
- package/THIRD_PARTY_NOTICES.md +45 -0
- package/dist/cli/chrome.d.ts +1 -0
- package/dist/cli/chrome.js +130 -0
- package/dist/cli/command-registry.d.ts +15 -0
- package/dist/cli/command-registry.js +35 -0
- package/dist/cli/doctor-plugins.d.ts +18 -0
- package/dist/cli/doctor-plugins.js +338 -0
- package/dist/cli/doctor.d.ts +9 -0
- package/dist/cli/doctor.js +407 -0
- package/dist/cli/init.d.ts +1 -0
- package/dist/cli/init.js +200 -0
- package/dist/cli/register-commands.d.ts +1 -0
- package/dist/cli/register-commands.js +22 -0
- package/dist/cli/serve.d.ts +14 -0
- package/dist/cli/serve.js +151 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.js +129 -0
- package/dist/engine/adapters/adb.d.ts +72 -0
- package/dist/engine/adapters/adb.js +200 -0
- package/dist/engine/adapters/android-cdp.d.ts +54 -0
- package/dist/engine/adapters/android-cdp.js +110 -0
- package/dist/engine/adapters/android.engine.d.ts +1 -0
- package/dist/engine/adapters/android.engine.js +31 -0
- package/dist/engine/adapters/chromium.engine.d.ts +1 -0
- package/dist/engine/adapters/chromium.engine.js +44 -0
- package/dist/engine/adapters/firefox.engine.d.ts +1 -0
- package/dist/engine/adapters/firefox.engine.js +43 -0
- package/dist/engine/adapters/playwright-chromium.d.ts +43 -0
- package/dist/engine/adapters/playwright-chromium.js +56 -0
- package/dist/engine/adapters/playwright-firefox.d.ts +52 -0
- package/dist/engine/adapters/playwright-firefox.js +97 -0
- package/dist/engine/adapters/playwright-webkit.d.ts +40 -0
- package/dist/engine/adapters/playwright-webkit.js +79 -0
- package/dist/engine/adapters/safari/bidi-client.d.ts +46 -0
- package/dist/engine/adapters/safari/bidi-client.js +130 -0
- package/dist/engine/adapters/safari/launch.d.ts +56 -0
- package/dist/engine/adapters/safari/launch.js +104 -0
- package/dist/engine/adapters/safari/webdriver-client.d.ts +102 -0
- package/dist/engine/adapters/safari/webdriver-client.js +175 -0
- package/dist/engine/adapters/safari.engine.d.ts +1 -0
- package/dist/engine/adapters/safari.engine.js +52 -0
- package/dist/engine/adapters/safaridriver-hybrid.d.ts +56 -0
- package/dist/engine/adapters/safaridriver-hybrid.js +127 -0
- package/dist/engine/adapters/webkit.engine.d.ts +1 -0
- package/dist/engine/adapters/webkit.engine.js +47 -0
- package/dist/engine/capabilities.d.ts +53 -0
- package/dist/engine/capabilities.js +122 -0
- package/dist/engine/capability-registry.d.ts +9 -0
- package/dist/engine/capability-registry.js +20 -0
- package/dist/engine/index.d.ts +18 -0
- package/dist/engine/index.js +14 -0
- package/dist/engine/register-engines.d.ts +5 -0
- package/dist/engine/register-engines.js +16 -0
- package/dist/engine/registry.d.ts +145 -0
- package/dist/engine/registry.js +67 -0
- package/dist/engine/select.d.ts +48 -0
- package/dist/engine/select.js +128 -0
- package/dist/engine/session-cdp.d.ts +13 -0
- package/dist/engine/session-cdp.js +22 -0
- package/dist/engine/tool-gate.d.ts +19 -0
- package/dist/engine/tool-gate.js +226 -0
- package/dist/engine/types.d.ts +71 -0
- package/dist/engine/types.js +16 -0
- package/dist/helper/bridge.d.ts +48 -0
- package/dist/helper/bridge.js +200 -0
- package/dist/helper/browx-page.d.ts +1 -0
- package/dist/helper/browx-page.js +47 -0
- package/dist/helper/overlay-hide.d.ts +9 -0
- package/dist/helper/overlay-hide.js +49 -0
- package/dist/helper/stealth.d.ts +10 -0
- package/dist/helper/stealth.js +88 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +15 -0
- package/dist/page/a11y.d.ts +81 -0
- package/dist/page/a11y.js +219 -0
- package/dist/page/action-substrate.d.ts +64 -0
- package/dist/page/action-substrate.js +118 -0
- package/dist/page/actionresult-blocks.d.ts +99 -0
- package/dist/page/actionresult-blocks.js +144 -0
- package/dist/page/actionresult-shape.d.ts +48 -0
- package/dist/page/actionresult-shape.js +155 -0
- package/dist/page/actionresult-types.d.ts +368 -0
- package/dist/page/actionresult-types.js +4 -0
- package/dist/page/actionresult.d.ts +4 -0
- package/dist/page/actionresult.js +299 -0
- package/dist/page/actions-probe.d.ts +32 -0
- package/dist/page/actions-probe.js +294 -0
- package/dist/page/actions-scroll.d.ts +40 -0
- package/dist/page/actions-scroll.js +53 -0
- package/dist/page/actions.d.ts +132 -0
- package/dist/page/actions.js +453 -0
- package/dist/page/archive-assets.d.ts +39 -0
- package/dist/page/archive-assets.js +187 -0
- package/dist/page/archive.d.ts +47 -0
- package/dist/page/archive.js +349 -0
- package/dist/page/asset-export.d.ts +122 -0
- package/dist/page/asset-export.js +376 -0
- package/dist/page/await_network.d.ts +16 -0
- package/dist/page/await_network.js +23 -0
- package/dist/page/bbox.d.ts +37 -0
- package/dist/page/bbox.js +115 -0
- package/dist/page/canvas-capture.d.ts +82 -0
- package/dist/page/canvas-capture.js +257 -0
- package/dist/page/canvas-diff.d.ts +51 -0
- package/dist/page/canvas-diff.js +131 -0
- package/dist/page/canvas-gesture.d.ts +53 -0
- package/dist/page/canvas-gesture.js +167 -0
- package/dist/page/canvas-transform.d.ts +96 -0
- package/dist/page/canvas-transform.js +150 -0
- package/dist/page/canvas.d.ts +8 -0
- package/dist/page/canvas.js +50 -0
- package/dist/page/capture-substrate.d.ts +111 -0
- package/dist/page/capture-substrate.js +139 -0
- package/dist/page/clipboard.d.ts +25 -0
- package/dist/page/clipboard.js +50 -0
- package/dist/page/clock.d.ts +36 -0
- package/dist/page/clock.js +167 -0
- package/dist/page/compose.d.ts +55 -0
- package/dist/page/compose.js +169 -0
- package/dist/page/console.d.ts +39 -0
- package/dist/page/console.js +73 -0
- package/dist/page/coverage.d.ts +97 -0
- package/dist/page/coverage.js +280 -0
- package/dist/page/dom-export.d.ts +41 -0
- package/dist/page/dom-export.js +193 -0
- package/dist/page/dom-walk.d.ts +91 -0
- package/dist/page/dom-walk.js +267 -0
- package/dist/page/dom_diff.d.ts +48 -0
- package/dist/page/dom_diff.js +121 -0
- package/dist/page/downloads.d.ts +80 -0
- package/dist/page/downloads.js +244 -0
- package/dist/page/drop-files.d.ts +78 -0
- package/dist/page/drop-files.js +310 -0
- package/dist/page/element-export-discovery.d.ts +64 -0
- package/dist/page/element-export-discovery.js +346 -0
- package/dist/page/element-export.d.ts +46 -0
- package/dist/page/element-export.js +251 -0
- package/dist/page/emulation-substrate.d.ts +53 -0
- package/dist/page/emulation-substrate.js +87 -0
- package/dist/page/emulation.d.ts +60 -0
- package/dist/page/emulation.js +162 -0
- package/dist/page/export-playwright-script.d.ts +47 -0
- package/dist/page/export-playwright-script.js +304 -0
- package/dist/page/extract-resolve.d.ts +22 -0
- package/dist/page/extract-resolve.js +341 -0
- package/dist/page/extract-schema.d.ts +20 -0
- package/dist/page/extract-schema.js +200 -0
- package/dist/page/extract-types.d.ts +127 -0
- package/dist/page/extract-types.js +8 -0
- package/dist/page/extract-warnings.d.ts +8 -0
- package/dist/page/extract-warnings.js +56 -0
- package/dist/page/extract.d.ts +9 -0
- package/dist/page/extract.js +174 -0
- package/dist/page/fill-form.d.ts +58 -0
- package/dist/page/fill-form.js +261 -0
- package/dist/page/find.d.ts +158 -0
- package/dist/page/find.js +470 -0
- package/dist/page/frames.d.ts +45 -0
- package/dist/page/frames.js +133 -0
- package/dist/page/generate-locator.d.ts +57 -0
- package/dist/page/generate-locator.js +136 -0
- package/dist/page/gestures.d.ts +128 -0
- package/dist/page/gestures.js +198 -0
- package/dist/page/har.d.ts +91 -0
- package/dist/page/har.js +174 -0
- package/dist/page/heap.d.ts +97 -0
- package/dist/page/heap.js +285 -0
- package/dist/page/inspect.d.ts +34 -0
- package/dist/page/inspect.js +75 -0
- package/dist/page/layout-thrash.d.ts +34 -0
- package/dist/page/layout-thrash.js +232 -0
- package/dist/page/learning.d.ts +21 -0
- package/dist/page/learning.js +84 -0
- package/dist/page/locator.d.ts +54 -0
- package/dist/page/locator.js +142 -0
- package/dist/page/memory-diff.d.ts +48 -0
- package/dist/page/memory-diff.js +105 -0
- package/dist/page/network-mask.d.ts +8 -0
- package/dist/page/network-mask.js +18 -0
- package/dist/page/network-playwright.d.ts +96 -0
- package/dist/page/network-playwright.js +353 -0
- package/dist/page/network-substrate-select.d.ts +18 -0
- package/dist/page/network-substrate-select.js +32 -0
- package/dist/page/network-substrate.d.ts +109 -0
- package/dist/page/network-substrate.js +161 -0
- package/dist/page/network-ws.d.ts +46 -0
- package/dist/page/network-ws.js +113 -0
- package/dist/page/network.d.ts +194 -0
- package/dist/page/network.js +415 -0
- package/dist/page/overflow-detect.d.ts +102 -0
- package/dist/page/overflow-detect.js +449 -0
- package/dist/page/pdf.d.ts +69 -0
- package/dist/page/pdf.js +109 -0
- package/dist/page/perf-audit-analysers.d.ts +40 -0
- package/dist/page/perf-audit-analysers.js +369 -0
- package/dist/page/perf-audit-runner.d.ts +20 -0
- package/dist/page/perf-audit-runner.js +195 -0
- package/dist/page/perf-audit-types.d.ts +41 -0
- package/dist/page/perf-audit-types.js +5 -0
- package/dist/page/perf-audit.d.ts +37 -0
- package/dist/page/perf-audit.js +377 -0
- package/dist/page/perf.d.ts +127 -0
- package/dist/page/perf.js +373 -0
- package/dist/page/plan.d.ts +192 -0
- package/dist/page/plan.js +308 -0
- package/dist/page/point_probe.d.ts +46 -0
- package/dist/page/point_probe.js +99 -0
- package/dist/page/recording.d.ts +67 -0
- package/dist/page/recording.js +172 -0
- package/dist/page/refs.d.ts +92 -0
- package/dist/page/refs.js +134 -0
- package/dist/page/regions.d.ts +23 -0
- package/dist/page/regions.js +32 -0
- package/dist/page/routes.d.ts +40 -0
- package/dist/page/routes.js +87 -0
- package/dist/page/safari-actions.d.ts +12 -0
- package/dist/page/safari-actions.js +144 -0
- package/dist/page/sample.d.ts +64 -0
- package/dist/page/sample.js +216 -0
- package/dist/page/screenshot-on.d.ts +51 -0
- package/dist/page/screenshot-on.js +150 -0
- package/dist/page/screenshot-save.d.ts +36 -0
- package/dist/page/screenshot-save.js +53 -0
- package/dist/page/screenshot-schedule.d.ts +50 -0
- package/dist/page/screenshot-schedule.js +155 -0
- package/dist/page/script-substrate.d.ts +32 -0
- package/dist/page/script-substrate.js +47 -0
- package/dist/page/seed-random.d.ts +45 -0
- package/dist/page/seed-random.js +144 -0
- package/dist/page/set-of-marks.d.ts +96 -0
- package/dist/page/set-of-marks.js +245 -0
- package/dist/page/shadow.d.ts +136 -0
- package/dist/page/shadow.js +400 -0
- package/dist/page/shortcut.d.ts +50 -0
- package/dist/page/shortcut.js +147 -0
- package/dist/page/snapshot-substrate-safari.d.ts +30 -0
- package/dist/page/snapshot-substrate-safari.js +84 -0
- package/dist/page/snapshot-substrate-select.d.ts +24 -0
- package/dist/page/snapshot-substrate-select.js +34 -0
- package/dist/page/snapshot-substrate.d.ts +58 -0
- package/dist/page/snapshot-substrate.js +135 -0
- package/dist/page/snapshot.d.ts +24 -0
- package/dist/page/snapshot.js +162 -0
- package/dist/page/solve-captcha.d.ts +76 -0
- package/dist/page/solve-captcha.js +286 -0
- package/dist/page/storage-substrate-types.d.ts +221 -0
- package/dist/page/storage-substrate-types.js +6 -0
- package/dist/page/storage-substrate.d.ts +215 -0
- package/dist/page/storage-substrate.js +280 -0
- package/dist/page/structural.d.ts +9 -0
- package/dist/page/structural.js +152 -0
- package/dist/page/substrate-bundle-safari.d.ts +8 -0
- package/dist/page/substrate-bundle-safari.js +42 -0
- package/dist/page/substrate-bundle.d.ts +6 -0
- package/dist/page/substrate-bundle.js +53 -0
- package/dist/page/text_search.d.ts +44 -0
- package/dist/page/text_search.js +90 -0
- package/dist/page/upload.d.ts +28 -0
- package/dist/page/upload.js +62 -0
- package/dist/page/verify.d.ts +63 -0
- package/dist/page/verify.js +451 -0
- package/dist/page/video.d.ts +115 -0
- package/dist/page/video.js +169 -0
- package/dist/page/visibility.d.ts +22 -0
- package/dist/page/visibility.js +94 -0
- package/dist/page/watch.d.ts +29 -0
- package/dist/page/watch.js +99 -0
- package/dist/page/workers.d.ts +126 -0
- package/dist/page/workers.js +490 -0
- package/dist/page/ws-interactive.d.ts +82 -0
- package/dist/page/ws-interactive.js +318 -0
- package/dist/plugin/cli.d.ts +45 -0
- package/dist/plugin/cli.js +496 -0
- package/dist/plugin/command-registry.d.ts +9 -0
- package/dist/plugin/command-registry.js +23 -0
- package/dist/plugin/depgraph.d.ts +37 -0
- package/dist/plugin/depgraph.js +186 -0
- package/dist/plugin/manifest.d.ts +182 -0
- package/dist/plugin/manifest.js +219 -0
- package/dist/plugin/package-manager.d.ts +22 -0
- package/dist/plugin/package-manager.js +40 -0
- package/dist/plugin/resolver.d.ts +85 -0
- package/dist/plugin/resolver.js +166 -0
- package/dist/plugin/runtime.d.ts +77 -0
- package/dist/plugin/runtime.js +402 -0
- package/dist/plugin/types.d.ts +113 -0
- package/dist/plugin/types.js +4 -0
- package/dist/policy/confirm.d.ts +76 -0
- package/dist/policy/confirm.js +162 -0
- package/dist/policy/origin.d.ts +17 -0
- package/dist/policy/origin.js +79 -0
- package/dist/sdk/client.d.ts +21 -0
- package/dist/sdk/client.js +174 -0
- package/dist/sdk/index.d.ts +32 -0
- package/dist/sdk/index.js +61 -0
- package/dist/sdk/plugin-types.d.ts +33 -0
- package/dist/sdk/plugin-types.js +22 -0
- package/dist/sdk/registry.d.ts +17 -0
- package/dist/sdk/registry.js +94 -0
- package/dist/sdk/socket-transport.d.ts +20 -0
- package/dist/sdk/socket-transport.js +90 -0
- package/dist/sdk/tool-types.d.ts +634 -0
- package/dist/sdk/tool-types.js +28 -0
- package/dist/sdk/transport-in-process.d.ts +21 -0
- package/dist/sdk/transport-in-process.js +44 -0
- package/dist/sdk/transport-registry.d.ts +19 -0
- package/dist/sdk/transport-registry.js +31 -0
- package/dist/sdk/transport-socket.d.ts +12 -0
- package/dist/sdk/transport-socket.js +77 -0
- package/dist/sdk/transport-stdio-child.d.ts +10 -0
- package/dist/sdk/transport-stdio-child.js +47 -0
- package/dist/sdk/transport.d.ts +10 -0
- package/dist/sdk/transport.js +35 -0
- package/dist/sdk/types.d.ts +176 -0
- package/dist/sdk/types.js +10 -0
- package/dist/server.d.ts +33 -0
- package/dist/server.js +327 -0
- package/dist/session/artifacts.d.ts +52 -0
- package/dist/session/artifacts.js +177 -0
- package/dist/session/byob-attach.d.ts +26 -0
- package/dist/session/byob-attach.js +187 -0
- package/dist/session/byob.d.ts +8 -0
- package/dist/session/byob.js +20 -0
- package/dist/session/cache-storage.d.ts +100 -0
- package/dist/session/cache-storage.js +166 -0
- package/dist/session/device-emu.d.ts +149 -0
- package/dist/session/device-emu.js +545 -0
- package/dist/session/device.d.ts +14 -0
- package/dist/session/device.js +44 -0
- package/dist/session/dialog.d.ts +62 -0
- package/dist/session/dialog.js +164 -0
- package/dist/session/emulation.d.ts +69 -0
- package/dist/session/emulation.js +168 -0
- package/dist/session/extensions.d.ts +113 -0
- package/dist/session/extensions.js +237 -0
- package/dist/session/fs-picker.d.ts +144 -0
- package/dist/session/fs-picker.js +666 -0
- package/dist/session/idb-storage.d.ts +86 -0
- package/dist/session/idb-storage.js +229 -0
- package/dist/session/incognito.d.ts +3 -0
- package/dist/session/incognito.js +20 -0
- package/dist/session/launch-options.d.ts +41 -0
- package/dist/session/launch-options.js +200 -0
- package/dist/session/managed.d.ts +3 -0
- package/dist/session/managed.js +16 -0
- package/dist/session/metrics.d.ts +45 -0
- package/dist/session/metrics.js +75 -0
- package/dist/session/notification.d.ts +122 -0
- package/dist/session/notification.js +426 -0
- package/dist/session/permission.d.ts +144 -0
- package/dist/session/permission.js +600 -0
- package/dist/session/playwright-post-wire.d.ts +8 -0
- package/dist/session/playwright-post-wire.js +148 -0
- package/dist/session/policy-buffer.d.ts +21 -0
- package/dist/session/policy-buffer.js +47 -0
- package/dist/session/profile-snapshot.d.ts +11 -0
- package/dist/session/profile-snapshot.js +53 -0
- package/dist/session/registry.d.ts +365 -0
- package/dist/session/registry.js +98 -0
- package/dist/session/safari-post-wire.d.ts +8 -0
- package/dist/session/safari-post-wire.js +28 -0
- package/dist/session/safari-session.d.ts +10 -0
- package/dist/session/safari-session.js +39 -0
- package/dist/session/storage.d.ts +148 -0
- package/dist/session/storage.js +350 -0
- package/dist/session/types.d.ts +113 -0
- package/dist/session/types.js +5 -0
- package/dist/session/wedge.d.ts +15 -0
- package/dist/session/wedge.js +41 -0
- package/dist/tools/action-core-tools.d.ts +13 -0
- package/dist/tools/action-core-tools.js +156 -0
- package/dist/tools/action-form-tools.d.ts +12 -0
- package/dist/tools/action-form-tools.js +179 -0
- package/dist/tools/action-gesture-tools.d.ts +9 -0
- package/dist/tools/action-gesture-tools.js +115 -0
- package/dist/tools/action-history-tools.d.ts +8 -0
- package/dist/tools/action-history-tools.js +67 -0
- package/dist/tools/action-tool.d.ts +42 -0
- package/dist/tools/action-tool.js +58 -0
- package/dist/tools/action-tools.d.ts +20 -0
- package/dist/tools/action-tools.js +28 -0
- package/dist/tools/batch-act-tools.d.ts +10 -0
- package/dist/tools/batch-act-tools.js +276 -0
- package/dist/tools/batch-human-tools.d.ts +8 -0
- package/dist/tools/batch-human-tools.js +148 -0
- package/dist/tools/canvas-tools.d.ts +40 -0
- package/dist/tools/canvas-tools.js +368 -0
- package/dist/tools/capture-report-diagnostics-tools.d.ts +7 -0
- package/dist/tools/capture-report-diagnostics-tools.js +318 -0
- package/dist/tools/capture-report-element-export-tools.d.ts +8 -0
- package/dist/tools/capture-report-element-export-tools.js +197 -0
- package/dist/tools/capture-report-export-tools.d.ts +8 -0
- package/dist/tools/capture-report-export-tools.js +246 -0
- package/dist/tools/capture-report-marks-tools.d.ts +9 -0
- package/dist/tools/capture-report-marks-tools.js +221 -0
- package/dist/tools/capture-report-upload-tools.d.ts +8 -0
- package/dist/tools/capture-report-upload-tools.js +277 -0
- package/dist/tools/config-approval-tools.d.ts +8 -0
- package/dist/tools/config-approval-tools.js +166 -0
- package/dist/tools/deep-coverage-tools.d.ts +8 -0
- package/dist/tools/deep-coverage-tools.js +325 -0
- package/dist/tools/deep-determinism-tools.d.ts +8 -0
- package/dist/tools/deep-determinism-tools.js +276 -0
- package/dist/tools/deep-perf-tools.d.ts +19 -0
- package/dist/tools/deep-perf-tools.js +324 -0
- package/dist/tools/device-emulation-tools.d.ts +9 -0
- package/dist/tools/device-emulation-tools.js +137 -0
- package/dist/tools/extensions-batch-tools.d.ts +18 -0
- package/dist/tools/extensions-batch-tools.js +24 -0
- package/dist/tools/extensions-rebuild.d.ts +22 -0
- package/dist/tools/extensions-rebuild.js +208 -0
- package/dist/tools/extensions-tools.d.ts +2 -0
- package/dist/tools/extensions-tools.js +331 -0
- package/dist/tools/forms-fill-tools.d.ts +8 -0
- package/dist/tools/forms-fill-tools.js +109 -0
- package/dist/tools/forms-plan-tools.d.ts +7 -0
- package/dist/tools/forms-plan-tools.js +159 -0
- package/dist/tools/forms-recording-mode-tools.d.ts +8 -0
- package/dist/tools/forms-recording-mode-tools.js +71 -0
- package/dist/tools/forms-recording-tools.d.ts +14 -0
- package/dist/tools/forms-recording-tools.js +22 -0
- package/dist/tools/forms-refs-tools.d.ts +8 -0
- package/dist/tools/forms-refs-tools.js +90 -0
- package/dist/tools/gesture-coord-tools.d.ts +8 -0
- package/dist/tools/gesture-coord-tools.js +168 -0
- package/dist/tools/gesture-emulation-tools.d.ts +8 -0
- package/dist/tools/gesture-emulation-tools.js +135 -0
- package/dist/tools/gesture-network-tools.d.ts +17 -0
- package/dist/tools/gesture-network-tools.js +27 -0
- package/dist/tools/gesture-route-tools.d.ts +8 -0
- package/dist/tools/gesture-route-tools.js +142 -0
- package/dist/tools/gesture-websocket-tools.d.ts +8 -0
- package/dist/tools/gesture-websocket-tools.js +122 -0
- package/dist/tools/gesture-worker-tools.d.ts +9 -0
- package/dist/tools/gesture-worker-tools.js +200 -0
- package/dist/tools/host-build.d.ts +76 -0
- package/dist/tools/host-build.js +516 -0
- package/dist/tools/host.d.ts +287 -0
- package/dist/tools/host.js +1 -0
- package/dist/tools/input-tools.d.ts +10 -0
- package/dist/tools/input-tools.js +176 -0
- package/dist/tools/live-emulation-tools.d.ts +9 -0
- package/dist/tools/live-emulation-tools.js +353 -0
- package/dist/tools/plugin-runtime.d.ts +36 -0
- package/dist/tools/plugin-runtime.js +274 -0
- package/dist/tools/read-observe-buffer-tools.d.ts +9 -0
- package/dist/tools/read-observe-buffer-tools.js +385 -0
- package/dist/tools/read-observe-capture-tools.d.ts +12 -0
- package/dist/tools/read-observe-capture-tools.js +376 -0
- package/dist/tools/read-observe-dom-tools.d.ts +8 -0
- package/dist/tools/read-observe-dom-tools.js +308 -0
- package/dist/tools/read-observe-extract-tools.d.ts +8 -0
- package/dist/tools/read-observe-extract-tools.js +232 -0
- package/dist/tools/read-observe-verify-tools.d.ts +8 -0
- package/dist/tools/read-observe-verify-tools.js +316 -0
- package/dist/tools/schemas.d.ts +29 -0
- package/dist/tools/schemas.js +58 -0
- package/dist/tools/secrets-captcha-tools.d.ts +9 -0
- package/dist/tools/secrets-captcha-tools.js +231 -0
- package/dist/tools/session-dialog-permission-tools.d.ts +9 -0
- package/dist/tools/session-dialog-permission-tools.js +287 -0
- package/dist/tools/session-lifecycle-tools.d.ts +8 -0
- package/dist/tools/session-lifecycle-tools.js +314 -0
- package/dist/tools/session-notification-device-tools.d.ts +9 -0
- package/dist/tools/session-notification-device-tools.js +156 -0
- package/dist/tools/session-policy-tools.d.ts +16 -0
- package/dist/tools/session-policy-tools.js +22 -0
- package/dist/tools/session-registry.d.ts +28 -0
- package/dist/tools/session-registry.js +427 -0
- package/dist/tools/storage-artifact-har-video-tools.d.ts +8 -0
- package/dist/tools/storage-artifact-har-video-tools.js +311 -0
- package/dist/tools/storage-cache-idb-tools.d.ts +8 -0
- package/dist/tools/storage-cache-idb-tools.js +347 -0
- package/dist/tools/storage-state-cookies-tools.d.ts +8 -0
- package/dist/tools/storage-state-cookies-tools.js +223 -0
- package/dist/tools/storage-tools.d.ts +17 -0
- package/dist/tools/storage-tools.js +25 -0
- package/dist/tools/storage-web-auth-tools.d.ts +10 -0
- package/dist/tools/storage-web-auth-tools.js +230 -0
- package/dist/tools/tool-metadata.d.ts +8 -0
- package/dist/tools/tool-metadata.js +185 -0
- package/dist/util/batch.d.ts +83 -0
- package/dist/util/batch.js +191 -0
- package/dist/util/capabilities.d.ts +504 -0
- package/dist/util/capabilities.js +254 -0
- package/dist/util/config-store.d.ts +103 -0
- package/dist/util/config-store.js +206 -0
- package/dist/util/config.d.ts +11 -0
- package/dist/util/config.js +28 -0
- package/dist/util/credentials.d.ts +136 -0
- package/dist/util/credentials.js +622 -0
- package/dist/util/deadline.d.ts +22 -0
- package/dist/util/deadline.js +62 -0
- package/dist/util/diagnostics.d.ts +161 -0
- package/dist/util/diagnostics.js +579 -0
- package/dist/util/egress-sanitiser.d.ts +29 -0
- package/dist/util/egress-sanitiser.js +52 -0
- package/dist/util/failure.d.ts +8 -0
- package/dist/util/failure.js +50 -0
- package/dist/util/flake-check.d.ts +109 -0
- package/dist/util/flake-check.js +342 -0
- package/dist/util/invariant.d.ts +25 -0
- package/dist/util/invariant.js +66 -0
- package/dist/util/logging.d.ts +6 -0
- package/dist/util/logging.js +12 -0
- package/dist/util/predicates.d.ts +62 -0
- package/dist/util/predicates.js +340 -0
- package/dist/util/secrets.d.ts +104 -0
- package/dist/util/secrets.js +219 -0
- package/dist/util/tokens.d.ts +6 -0
- package/dist/util/tokens.js +24 -0
- package/dist/util/url-sanitizer.d.ts +19 -0
- package/dist/util/url-sanitizer.js +70 -0
- package/dist/util/version.d.ts +2 -0
- package/dist/util/version.js +21 -0
- package/dist/util/workspace.d.ts +7 -0
- package/dist/util/workspace.js +22 -0
- package/package.json +120 -0
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
// Safari action helpers. Safari has no Playwright Page, so the Playwright action
|
|
2
|
+
// core (actions.ts → runInActionWindow → ctx.page) cannot run — `ctxFor(e)` throws
|
|
3
|
+
// at context construction. The curated subset that works on Safari is routed here
|
|
4
|
+
// instead, driving the Safari-native WebDriver Classic client (element find →
|
|
5
|
+
// click / clear / sendKeys, navigation) and returning the same `ActionResult`
|
|
6
|
+
// shape so the tool surface stays engine-blind.
|
|
7
|
+
//
|
|
8
|
+
// A ref or a css `selector` resolves to a WebDriver element by CSS: a ref is
|
|
9
|
+
// turned into the most stable selector its snapshot locator carries (a
|
|
10
|
+
// `[data-testid=…]`-style attribute when present, else the structural css path).
|
|
11
|
+
// `coords` and role/name-only refs are not addressable this way and are refused.
|
|
12
|
+
// The action envelope's structure / console / network deltas are NOT captured on
|
|
13
|
+
// Safari (it has no protocol-level taps) — surfaced as an honest warning, never
|
|
14
|
+
// fabricated.
|
|
15
|
+
const EMPTY_NETWORK = { summary: { total: 0, byType: {}, failed: 0 } };
|
|
16
|
+
const ENVELOPE_NOTE = "Safari is driven over WebDriver: the action envelope's structure / console / network deltas are " +
|
|
17
|
+
"not captured on the Safari engine. Read page state with `snapshot` after an action.";
|
|
18
|
+
/** W3C WebDriver key codes for the named keys `press` accepts. A bare single
|
|
19
|
+
* character is sent as-is; anything else falls back to the literal string. */
|
|
20
|
+
const WEBDRIVER_KEYS = {
|
|
21
|
+
Enter: "\uE007",
|
|
22
|
+
Tab: "\uE004",
|
|
23
|
+
Escape: "\uE00C",
|
|
24
|
+
Backspace: "\uE003",
|
|
25
|
+
Delete: "\uE017",
|
|
26
|
+
Space: "\uE00D",
|
|
27
|
+
ArrowUp: "\uE013",
|
|
28
|
+
ArrowDown: "\uE015",
|
|
29
|
+
ArrowLeft: "\uE012",
|
|
30
|
+
ArrowRight: "\uE014",
|
|
31
|
+
};
|
|
32
|
+
function descriptorFor(type, target) {
|
|
33
|
+
if (target.ref)
|
|
34
|
+
return { type, ref: target.ref };
|
|
35
|
+
if (target.selector)
|
|
36
|
+
return { type, selector: target.selector };
|
|
37
|
+
return { type };
|
|
38
|
+
}
|
|
39
|
+
function result(action, ok, extra = {}) {
|
|
40
|
+
return {
|
|
41
|
+
ok,
|
|
42
|
+
action,
|
|
43
|
+
navigation: { changed: false, from: "", to: "", kind: null },
|
|
44
|
+
structure: { appeared: [], removed: [], newTabs: [] },
|
|
45
|
+
console: { errors: [], warnings: 0 },
|
|
46
|
+
pageErrors: [],
|
|
47
|
+
network: EMPTY_NETWORK,
|
|
48
|
+
tokensEstimate: 0,
|
|
49
|
+
warnings: extra.warnings ?? [ENVELOPE_NOTE],
|
|
50
|
+
...(extra.element ? { element: extra.element } : {}),
|
|
51
|
+
...(extra.error ? { error: extra.error } : {}),
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
/** Resolve an action target to a CSS selector the WebDriver `findElement` can use,
|
|
55
|
+
* or null when the target is not addressable on Safari (coords, or a ref whose
|
|
56
|
+
* snapshot locator carries neither a test attribute nor a css path). */
|
|
57
|
+
function selectorForTarget(refs, target) {
|
|
58
|
+
if (target.selector)
|
|
59
|
+
return target.selector;
|
|
60
|
+
if (!target.ref)
|
|
61
|
+
return null;
|
|
62
|
+
const loc = refs.locatorOf(target.ref);
|
|
63
|
+
if (!loc)
|
|
64
|
+
return null;
|
|
65
|
+
if (loc.testId && loc.testIdAttr)
|
|
66
|
+
return `[${loc.testIdAttr}="${loc.testId.replace(/(["\\])/g, "\\$1")}"]`;
|
|
67
|
+
return loc.cssPath ?? null;
|
|
68
|
+
}
|
|
69
|
+
function unaddressable(action) {
|
|
70
|
+
return result(action, false, {
|
|
71
|
+
error: "this target is not addressable on the Safari engine — pass a `ref` (from snapshot/find) whose " +
|
|
72
|
+
"element carries a test attribute or css path, or a css `selector`. `coords` are not supported.",
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
/** A clean refusal for an action family outside Safari's curated subset (hover,
|
|
76
|
+
* select, scroll, …). Keeps the gating in the adapter rather than the handler,
|
|
77
|
+
* so the tool surface stays engine-blind. */
|
|
78
|
+
export function safariUnsupportedAction(type) {
|
|
79
|
+
return result({ type }, false, {
|
|
80
|
+
error: `\`${type}\` is not supported on the Safari engine — the curated subset is navigate / click / ` +
|
|
81
|
+
`fill / press / snapshot / find / screenshot / cookies. Use a chromium, firefox, or webkit ` +
|
|
82
|
+
`session for the rest.`,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
async function resolveElement(handle, selector) {
|
|
86
|
+
return handle.webDriver.findElement(handle.sessionId, "css selector", selector);
|
|
87
|
+
}
|
|
88
|
+
export async function safariNavigate(handle, url) {
|
|
89
|
+
const wd = handle.webDriver;
|
|
90
|
+
const from = await wd.currentUrl(handle.sessionId).catch(() => "");
|
|
91
|
+
await wd.navigate(handle.sessionId, url);
|
|
92
|
+
const to = await wd.currentUrl(handle.sessionId).catch(() => url);
|
|
93
|
+
const changed = from !== to;
|
|
94
|
+
return {
|
|
95
|
+
ok: true,
|
|
96
|
+
action: { type: "navigate", url },
|
|
97
|
+
navigation: { changed, from, to, kind: changed ? "full_load" : null },
|
|
98
|
+
structure: { appeared: [], removed: [], newTabs: [] },
|
|
99
|
+
console: { errors: [], warnings: 0 },
|
|
100
|
+
pageErrors: [],
|
|
101
|
+
network: EMPTY_NETWORK,
|
|
102
|
+
tokensEstimate: 0,
|
|
103
|
+
warnings: [ENVELOPE_NOTE],
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
export async function safariClick(handle, refs, target) {
|
|
107
|
+
const descriptor = descriptorFor("click", target);
|
|
108
|
+
const selector = selectorForTarget(refs, target);
|
|
109
|
+
if (!selector)
|
|
110
|
+
return unaddressable(descriptor);
|
|
111
|
+
const el = await resolveElement(handle, selector);
|
|
112
|
+
if (!el)
|
|
113
|
+
return result(descriptor, false, { error: `no element matches "${selector}"` });
|
|
114
|
+
await handle.webDriver.elementClick(handle.sessionId, el);
|
|
115
|
+
return result(descriptor, true, { element: { ref: target.ref, stillAttached: true } });
|
|
116
|
+
}
|
|
117
|
+
export async function safariFill(handle, refs, target, value) {
|
|
118
|
+
const descriptor = { ...descriptorFor("fill", target), value };
|
|
119
|
+
const selector = selectorForTarget(refs, target);
|
|
120
|
+
if (!selector)
|
|
121
|
+
return unaddressable(descriptor);
|
|
122
|
+
const el = await resolveElement(handle, selector);
|
|
123
|
+
if (!el)
|
|
124
|
+
return result(descriptor, false, { error: `no element matches "${selector}"` });
|
|
125
|
+
await handle.webDriver.elementClear(handle.sessionId, el);
|
|
126
|
+
await handle.webDriver.elementValue(handle.sessionId, el, value);
|
|
127
|
+
const landed = await handle.webDriver
|
|
128
|
+
.elementProperty(handle.sessionId, el, "value")
|
|
129
|
+
.catch(() => null);
|
|
130
|
+
return result(descriptor, true, {
|
|
131
|
+
element: { ref: target.ref, stillAttached: true, value: landed ?? value },
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
export async function safariPress(handle, refs, target, key) {
|
|
135
|
+
const descriptor = { ...descriptorFor("press", target), value: key };
|
|
136
|
+
const selector = selectorForTarget(refs, target);
|
|
137
|
+
if (!selector)
|
|
138
|
+
return unaddressable(descriptor);
|
|
139
|
+
const el = await resolveElement(handle, selector);
|
|
140
|
+
if (!el)
|
|
141
|
+
return result(descriptor, false, { error: `no element matches "${selector}"` });
|
|
142
|
+
await handle.webDriver.elementValue(handle.sessionId, el, WEBDRIVER_KEYS[key] ?? key);
|
|
143
|
+
return result(descriptor, true, { element: { ref: target.ref, stillAttached: true } });
|
|
144
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { Page } from "playwright-core";
|
|
2
|
+
import { type ActionTarget } from "./locator.js";
|
|
3
|
+
import type { RefRegistry } from "./refs.js";
|
|
4
|
+
export declare const ELEMENT_METRICS: readonly ["scrollTop", "scrollLeft", "scrollHeight", "scrollWidth", "clientWidth", "clientHeight", "bboxX", "bboxY", "bboxWidth", "bboxHeight"];
|
|
5
|
+
export type Metric = (typeof ELEMENT_METRICS)[number];
|
|
6
|
+
/** Above this collected-point count, an unset `summary` auto-omits the full
|
|
7
|
+
* series (a raf window of a few seconds is hundreds of points; the agent
|
|
8
|
+
* almost always wants only the reduced signal, and the raw series balloons
|
|
9
|
+
* the tool-result token cost). Explicit `summary:false` opts back in. */
|
|
10
|
+
export declare const AUTO_SUMMARY_THRESHOLD = 300;
|
|
11
|
+
/** Tri-state series-omission policy (pure, unit-tested):
|
|
12
|
+
* - `summary === true` → always omit the series (caller asked for reduced).
|
|
13
|
+
* - `summary === false` → always include it (caller opted into the raw set).
|
|
14
|
+
* - `summary` unset → auto-omit only when the series is large. */
|
|
15
|
+
export declare function shouldOmitSeries(summary: boolean | undefined, count: number): boolean;
|
|
16
|
+
export interface SampleArgs {
|
|
17
|
+
target?: ActionTarget;
|
|
18
|
+
metric: Metric;
|
|
19
|
+
durationMs: number;
|
|
20
|
+
everyFrame?: boolean;
|
|
21
|
+
intervalMs?: number;
|
|
22
|
+
/** Series-omission control (the `summary` is *always* returned regardless).
|
|
23
|
+
* `true` → omit the full `series`; `false` → always include it; unset →
|
|
24
|
+
* auto-omit only for large windows (> AUTO_SUMMARY_THRESHOLD points), with
|
|
25
|
+
* `autoSummarised: true` on the result. Pure server-side reduction of the
|
|
26
|
+
* already-collected fixed-metric series — no agent JS, no eval surface. */
|
|
27
|
+
summary?: boolean;
|
|
28
|
+
}
|
|
29
|
+
export interface SampleSummary {
|
|
30
|
+
count: number;
|
|
31
|
+
min: number;
|
|
32
|
+
max: number;
|
|
33
|
+
first: number;
|
|
34
|
+
last: number;
|
|
35
|
+
/** Distinct sampled values (catches "did it move at all?"). */
|
|
36
|
+
distinctCount: number;
|
|
37
|
+
/** tMs of the first sample whose value differed from `first`; null if flat. */
|
|
38
|
+
firstChangeTMs: number | null;
|
|
39
|
+
}
|
|
40
|
+
export interface SampleResult {
|
|
41
|
+
metric: Metric;
|
|
42
|
+
scope: "element" | "window";
|
|
43
|
+
durationMs: number;
|
|
44
|
+
mode: "raf" | "interval";
|
|
45
|
+
intervalMs?: number;
|
|
46
|
+
count: number;
|
|
47
|
+
/** Present unless `summary` was requested. */
|
|
48
|
+
series?: Array<{
|
|
49
|
+
tMs: number;
|
|
50
|
+
value: number;
|
|
51
|
+
}>;
|
|
52
|
+
/** Always present (cheap) — the reduced signal. */
|
|
53
|
+
summary?: SampleSummary;
|
|
54
|
+
/** true when the series was dropped by the auto-large-window policy (caller
|
|
55
|
+
* didn't set `summary`). Re-request with `summary:false` for the raw set. */
|
|
56
|
+
autoSummarised?: boolean;
|
|
57
|
+
truncated?: boolean;
|
|
58
|
+
}
|
|
59
|
+
/** Pure reduction of a collected series. Exported for unit tests. */
|
|
60
|
+
export declare function summariseSeries(series: Array<{
|
|
61
|
+
tMs: number;
|
|
62
|
+
value: number;
|
|
63
|
+
}>): SampleSummary;
|
|
64
|
+
export declare function sampleMetric(page: Page, refs: RefRegistry, args: SampleArgs): Promise<SampleResult>;
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
// bounded frame-aligned metric sampler.
|
|
2
|
+
//
|
|
3
|
+
// Jank / CLS / scroll-drift QA needs "sample this DOM metric every animation
|
|
4
|
+
// frame for N ms and return the series". The metric is a **fixed enum** — the
|
|
5
|
+
// agent supplies NO JavaScript (that would re-open the loophole closes;
|
|
6
|
+
// arbitrary JS stays `eval_js`, gated behind the `eval` capability). browxai
|
|
7
|
+
// supplies the fixed in-page rAF / interval loop.
|
|
8
|
+
import { locatorFor } from "./locator.js";
|
|
9
|
+
export const ELEMENT_METRICS = [
|
|
10
|
+
"scrollTop",
|
|
11
|
+
"scrollLeft",
|
|
12
|
+
"scrollHeight",
|
|
13
|
+
"scrollWidth",
|
|
14
|
+
"clientWidth",
|
|
15
|
+
"clientHeight",
|
|
16
|
+
"bboxX",
|
|
17
|
+
"bboxY",
|
|
18
|
+
"bboxWidth",
|
|
19
|
+
"bboxHeight",
|
|
20
|
+
];
|
|
21
|
+
const BBOX_METRICS = new Set(["bboxX", "bboxY", "bboxWidth", "bboxHeight"]);
|
|
22
|
+
const MAX_DURATION_MS = 30_000;
|
|
23
|
+
const MAX_SERIES = 2000;
|
|
24
|
+
/** Above this collected-point count, an unset `summary` auto-omits the full
|
|
25
|
+
* series (a raf window of a few seconds is hundreds of points; the agent
|
|
26
|
+
* almost always wants only the reduced signal, and the raw series balloons
|
|
27
|
+
* the tool-result token cost). Explicit `summary:false` opts back in. */
|
|
28
|
+
export const AUTO_SUMMARY_THRESHOLD = 300;
|
|
29
|
+
/** Tri-state series-omission policy (pure, unit-tested):
|
|
30
|
+
* - `summary === true` → always omit the series (caller asked for reduced).
|
|
31
|
+
* - `summary === false` → always include it (caller opted into the raw set).
|
|
32
|
+
* - `summary` unset → auto-omit only when the series is large. */
|
|
33
|
+
export function shouldOmitSeries(summary, count) {
|
|
34
|
+
if (summary === true)
|
|
35
|
+
return true;
|
|
36
|
+
if (summary === false)
|
|
37
|
+
return false;
|
|
38
|
+
return count > AUTO_SUMMARY_THRESHOLD;
|
|
39
|
+
}
|
|
40
|
+
/** Pure reduction of a collected series. Exported for unit tests. */
|
|
41
|
+
export function summariseSeries(series) {
|
|
42
|
+
if (series.length === 0) {
|
|
43
|
+
return {
|
|
44
|
+
count: 0,
|
|
45
|
+
min: NaN,
|
|
46
|
+
max: NaN,
|
|
47
|
+
first: NaN,
|
|
48
|
+
last: NaN,
|
|
49
|
+
distinctCount: 0,
|
|
50
|
+
firstChangeTMs: null,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
const first = series[0].value;
|
|
54
|
+
let min = first;
|
|
55
|
+
let max = first;
|
|
56
|
+
let firstChangeTMs = null;
|
|
57
|
+
const distinct = new Set();
|
|
58
|
+
for (const p of series) {
|
|
59
|
+
if (p.value < min)
|
|
60
|
+
min = p.value;
|
|
61
|
+
if (p.value > max)
|
|
62
|
+
max = p.value;
|
|
63
|
+
distinct.add(p.value);
|
|
64
|
+
if (firstChangeTMs === null && p.value !== first)
|
|
65
|
+
firstChangeTMs = p.tMs;
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
count: series.length,
|
|
69
|
+
min,
|
|
70
|
+
max,
|
|
71
|
+
first,
|
|
72
|
+
last: series[series.length - 1].value,
|
|
73
|
+
distinctCount: distinct.size,
|
|
74
|
+
firstChangeTMs,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
// Both samplers are self-contained (no closure / outer refs) so Playwright can
|
|
78
|
+
// stringify and run them in-page. They differ only in arg shape:
|
|
79
|
+
// loc.evaluate(fn, arg) → fn(element, arg)
|
|
80
|
+
// page.evaluate(fn, arg) → fn(arg)
|
|
81
|
+
// The metric/loop logic is intentionally duplicated rather than shared via a
|
|
82
|
+
// closure (which wouldn't survive serialization).
|
|
83
|
+
/** Element sampler — runs as `loc.evaluate(elementSampler, params)`. */
|
|
84
|
+
function elementSampler(el, p) {
|
|
85
|
+
const read = () => {
|
|
86
|
+
switch (p.metric) {
|
|
87
|
+
case "scrollTop":
|
|
88
|
+
return el.scrollTop;
|
|
89
|
+
case "scrollLeft":
|
|
90
|
+
return el.scrollLeft;
|
|
91
|
+
case "scrollHeight":
|
|
92
|
+
return el.scrollHeight;
|
|
93
|
+
case "scrollWidth":
|
|
94
|
+
return el.scrollWidth;
|
|
95
|
+
case "clientWidth":
|
|
96
|
+
return el.clientWidth;
|
|
97
|
+
case "clientHeight":
|
|
98
|
+
return el.clientHeight;
|
|
99
|
+
default: {
|
|
100
|
+
const r = el.getBoundingClientRect();
|
|
101
|
+
return p.metric === "bboxX"
|
|
102
|
+
? r.x
|
|
103
|
+
: p.metric === "bboxY"
|
|
104
|
+
? r.y
|
|
105
|
+
: p.metric === "bboxWidth"
|
|
106
|
+
? r.width
|
|
107
|
+
: r.height;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
return new Promise((resolve) => {
|
|
112
|
+
const series = [];
|
|
113
|
+
const clock = () => globalThis.performance && globalThis.performance.now
|
|
114
|
+
? globalThis.performance.now()
|
|
115
|
+
: Date.now();
|
|
116
|
+
const t0 = clock();
|
|
117
|
+
const tick = () => {
|
|
118
|
+
if (series.length < p.maxSeries)
|
|
119
|
+
series.push({ tMs: Math.round(clock() - t0), value: read() });
|
|
120
|
+
if (clock() - t0 >= p.durationMs || series.length >= p.maxSeries) {
|
|
121
|
+
resolve(series);
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
if (p.everyFrame && globalThis.requestAnimationFrame)
|
|
125
|
+
globalThis.requestAnimationFrame(tick);
|
|
126
|
+
else
|
|
127
|
+
globalThis.setTimeout(tick, p.intervalMs);
|
|
128
|
+
};
|
|
129
|
+
tick();
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
/** Window/document sampler — runs as `page.evaluate(windowSampler, params)`. */
|
|
133
|
+
function windowSampler(p) {
|
|
134
|
+
const read = () => {
|
|
135
|
+
const s = globalThis.document.scrollingElement || globalThis.document.documentElement;
|
|
136
|
+
switch (p.metric) {
|
|
137
|
+
case "scrollTop":
|
|
138
|
+
return globalThis.scrollY ?? s.scrollTop ?? 0;
|
|
139
|
+
case "scrollLeft":
|
|
140
|
+
return globalThis.scrollX ?? s.scrollLeft ?? 0;
|
|
141
|
+
case "scrollHeight":
|
|
142
|
+
return s.scrollHeight;
|
|
143
|
+
case "scrollWidth":
|
|
144
|
+
return s.scrollWidth;
|
|
145
|
+
case "clientWidth":
|
|
146
|
+
return s.clientWidth;
|
|
147
|
+
case "clientHeight":
|
|
148
|
+
return s.clientHeight;
|
|
149
|
+
default:
|
|
150
|
+
return NaN; // bbox* rejected before we get here
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
return new Promise((resolve) => {
|
|
154
|
+
const series = [];
|
|
155
|
+
const clock = () => globalThis.performance && globalThis.performance.now
|
|
156
|
+
? globalThis.performance.now()
|
|
157
|
+
: Date.now();
|
|
158
|
+
const t0 = clock();
|
|
159
|
+
const tick = () => {
|
|
160
|
+
if (series.length < p.maxSeries)
|
|
161
|
+
series.push({ tMs: Math.round(clock() - t0), value: read() });
|
|
162
|
+
if (clock() - t0 >= p.durationMs || series.length >= p.maxSeries) {
|
|
163
|
+
resolve(series);
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
if (p.everyFrame && globalThis.requestAnimationFrame)
|
|
167
|
+
globalThis.requestAnimationFrame(tick);
|
|
168
|
+
else
|
|
169
|
+
globalThis.setTimeout(tick, p.intervalMs);
|
|
170
|
+
};
|
|
171
|
+
tick();
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
export async function sampleMetric(page, refs, args) {
|
|
175
|
+
const durationMs = Math.min(Math.max(args.durationMs, 1), MAX_DURATION_MS);
|
|
176
|
+
const everyFrame = args.everyFrame ?? false;
|
|
177
|
+
const intervalMs = Math.max(args.intervalMs ?? 100, 16);
|
|
178
|
+
const scope = args.target ? "element" : "window";
|
|
179
|
+
if (!args.target && BBOX_METRICS.has(args.metric)) {
|
|
180
|
+
throw new Error(`sample: metric "${args.metric}" needs a target element (bbox* is meaningless for the window)`);
|
|
181
|
+
}
|
|
182
|
+
const params = { metric: args.metric, durationMs, everyFrame, intervalMs, maxSeries: MAX_SERIES };
|
|
183
|
+
let series;
|
|
184
|
+
if (args.target) {
|
|
185
|
+
let loc;
|
|
186
|
+
try {
|
|
187
|
+
loc = locatorFor(page, refs, args.target);
|
|
188
|
+
}
|
|
189
|
+
catch (e) {
|
|
190
|
+
throw new Error(`sample: ${e instanceof Error ? e.message : String(e)}`);
|
|
191
|
+
}
|
|
192
|
+
series = await loc.evaluate(elementSampler, params);
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
series = await page.evaluate(windowSampler, params);
|
|
196
|
+
}
|
|
197
|
+
// `summary` is always cheap to compute and included. The full `series` is
|
|
198
|
+
// omitted when the caller asked for `summary:true` OR (caller unset) the
|
|
199
|
+
// window is large — long high-rate windows serialise huge and the agent
|
|
200
|
+
// usually just needs the signal: did it move, bounds, when it first changed.
|
|
201
|
+
const summary = summariseSeries(series);
|
|
202
|
+
const omitSeries = shouldOmitSeries(args.summary, series.length);
|
|
203
|
+
const autoSummarised = omitSeries && args.summary === undefined;
|
|
204
|
+
return {
|
|
205
|
+
metric: args.metric,
|
|
206
|
+
scope,
|
|
207
|
+
durationMs,
|
|
208
|
+
mode: everyFrame ? "raf" : "interval",
|
|
209
|
+
...(everyFrame ? {} : { intervalMs }),
|
|
210
|
+
count: series.length,
|
|
211
|
+
...(omitSeries ? {} : { series }),
|
|
212
|
+
summary,
|
|
213
|
+
...(autoSummarised ? { autoSummarised: true } : {}),
|
|
214
|
+
...(series.length >= MAX_SERIES ? { truncated: true } : {}),
|
|
215
|
+
};
|
|
216
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
export declare const TRIGGERS: readonly ["navigation", "console-error", "network-mutation", "dialog"];
|
|
2
|
+
export type Trigger = (typeof TRIGGERS)[number];
|
|
3
|
+
/** Max captures per `screenshot_on` window. The window is already bounded by
|
|
4
|
+
* `durationMs`; this cap prevents an event-storm trigger (e.g. console-error
|
|
5
|
+
* fired every animation frame) from filling disk with thousands of frames in
|
|
6
|
+
* a multi-second window. Surfaced as a `warnings[]` entry when reached. */
|
|
7
|
+
export declare const MAX_TRIGGERS_PER_WINDOW = 50;
|
|
8
|
+
export declare const MIN_DURATION_MS = 1;
|
|
9
|
+
export declare const MAX_DURATION_MS = 600000;
|
|
10
|
+
export interface ScreenshotOnArgs {
|
|
11
|
+
trigger: Trigger;
|
|
12
|
+
/** Observation window length (ms). Required — the trigger is armed for
|
|
13
|
+
* exactly this long. */
|
|
14
|
+
durationMs: number;
|
|
15
|
+
/** Workspace-rooted output directory. The server handler defaults this. */
|
|
16
|
+
intoDir: string;
|
|
17
|
+
/** `"png"` (default) or `"jpeg"`. */
|
|
18
|
+
format?: "png" | "jpeg";
|
|
19
|
+
}
|
|
20
|
+
export interface ScreenshotOnResult {
|
|
21
|
+
intoDir: string;
|
|
22
|
+
trigger: Trigger;
|
|
23
|
+
/** Per-capture offset (ms from window start). */
|
|
24
|
+
capturedAt: number[];
|
|
25
|
+
/** Absolute paths to written files (same length as `capturedAt`). */
|
|
26
|
+
paths: string[];
|
|
27
|
+
warnings: string[];
|
|
28
|
+
}
|
|
29
|
+
export declare function validateOnArgs(args: ScreenshotOnArgs): void;
|
|
30
|
+
export type SnapFn = () => Promise<Buffer>;
|
|
31
|
+
/** Subscribe-once handle returned by a trigger source. The controller passes
|
|
32
|
+
* in a callback fired on every trigger event; the source returns a disposer
|
|
33
|
+
* it MUST call exactly once when the window closes (no listener leaks). */
|
|
34
|
+
export type TriggerDisposer = () => void;
|
|
35
|
+
export interface TriggerSource {
|
|
36
|
+
/** Subscribe to `trigger` events. Returns a disposer the controller calls
|
|
37
|
+
* on window close (success or wedge). */
|
|
38
|
+
subscribe(trigger: Trigger, onFire: () => void): TriggerDisposer;
|
|
39
|
+
}
|
|
40
|
+
/** Injectable timing seam. */
|
|
41
|
+
export interface OnClock {
|
|
42
|
+
now(): number;
|
|
43
|
+
/** Returns a promise that resolves after `ms`. Cancellable via the returned
|
|
44
|
+
* disposer (used to short-circuit when the per-window cap is hit). */
|
|
45
|
+
setTimeout(fn: () => void, ms: number): () => void;
|
|
46
|
+
}
|
|
47
|
+
export declare function runScreenshotOn(snap: SnapFn, source: TriggerSource, args: ScreenshotOnArgs, workspaceRoot: string, clock?: OnClock): Promise<ScreenshotOnResult>;
|
|
48
|
+
/** Default `intoDir` shape — `screenshots/<sessionId>-<isoTs>/`. Same shape
|
|
49
|
+
* `screenshot_schedule` uses; the MCP handler joins it against
|
|
50
|
+
* `$BROWX_WORKSPACE` via `resolveWorkspacePath`. */
|
|
51
|
+
export declare function defaultOnDir(sessionId: string, now?: Date): string;
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
// `screenshot_on` — event-driven screenshot capture. Arm a trigger over a
|
|
2
|
+
// bounded observation window; snap a screenshot every time the trigger
|
|
3
|
+
// fires; return when the window closes (or the per-window cap is hit).
|
|
4
|
+
//
|
|
5
|
+
// Sibling of `screenshot_schedule` (periodic cadence): both share the
|
|
6
|
+
// workspace-rooted disk-write contract and the `file-io` capability gate.
|
|
7
|
+
//
|
|
8
|
+
// Anti-wedge: the call is bounded by `durationMs` (required); the per-window
|
|
9
|
+
// capture cap (`MAX_TRIGGERS_PER_WINDOW`) prevents runaway in event storms
|
|
10
|
+
// (e.g. a console-error-on-every-frame loop). The outer MCP handler wraps
|
|
11
|
+
// the controller in `withDeadline` against the action-timeout.
|
|
12
|
+
//
|
|
13
|
+
// Trigger surface is fixed:
|
|
14
|
+
// - `navigation` → page `framenavigated` (main-frame only)
|
|
15
|
+
// - `console-error` → page `console` type === "error" OR `pageerror`
|
|
16
|
+
// - `network-mutation` → CDP `Network.responseReceived` for a write-shaped
|
|
17
|
+
// method (POST/PUT/PATCH/DELETE) with 2xx status
|
|
18
|
+
// - `dialog` → page `dialog` (alert/confirm/prompt/beforeunload)
|
|
19
|
+
//
|
|
20
|
+
// Trigger sources are injectable so the controller stays browser-agnostic for
|
|
21
|
+
// unit tests. The real wiring (in server.ts) hooks into Playwright's `Page`
|
|
22
|
+
// event API + the per-session `CDPSession`.
|
|
23
|
+
import { mkdirSync, writeFileSync } from "node:fs";
|
|
24
|
+
import { join, resolve as resolvePath } from "node:path";
|
|
25
|
+
import { resolveWorkspacePath } from "../session/storage.js";
|
|
26
|
+
export const TRIGGERS = ["navigation", "console-error", "network-mutation", "dialog"];
|
|
27
|
+
/** Max captures per `screenshot_on` window. The window is already bounded by
|
|
28
|
+
* `durationMs`; this cap prevents an event-storm trigger (e.g. console-error
|
|
29
|
+
* fired every animation frame) from filling disk with thousands of frames in
|
|
30
|
+
* a multi-second window. Surfaced as a `warnings[]` entry when reached. */
|
|
31
|
+
export const MAX_TRIGGERS_PER_WINDOW = 50;
|
|
32
|
+
export const MIN_DURATION_MS = 1;
|
|
33
|
+
export const MAX_DURATION_MS = 600_000; // 10 minutes
|
|
34
|
+
export function validateOnArgs(args) {
|
|
35
|
+
if (!TRIGGERS.includes(args.trigger)) {
|
|
36
|
+
throw new Error(`screenshot_on: \`trigger\` must be one of [${TRIGGERS.join(", ")}] — got "${args.trigger}"`);
|
|
37
|
+
}
|
|
38
|
+
if (!Number.isFinite(args.durationMs) ||
|
|
39
|
+
args.durationMs < MIN_DURATION_MS ||
|
|
40
|
+
args.durationMs > MAX_DURATION_MS) {
|
|
41
|
+
throw new Error(`screenshot_on: \`durationMs\` must be in [${MIN_DURATION_MS}, ${MAX_DURATION_MS}] — got ${args.durationMs}`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
const REAL_CLOCK = {
|
|
45
|
+
now: () => Date.now(),
|
|
46
|
+
setTimeout: (fn, ms) => {
|
|
47
|
+
const handle = setTimeout(fn, Math.max(0, ms));
|
|
48
|
+
return () => clearTimeout(handle);
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
/** Trigger handler: capture one frame per visible state. Drops overlapping fires
|
|
52
|
+
* (a single screenshot per state is the useful unit), ends the window on the
|
|
53
|
+
* per-window cap, else fires a fire-and-forget snap that writes the PNG. */
|
|
54
|
+
function onScreenshotFire(st) {
|
|
55
|
+
if (st.capHit || st.snapping)
|
|
56
|
+
return;
|
|
57
|
+
if (st.paths.length >= MAX_TRIGGERS_PER_WINDOW) {
|
|
58
|
+
st.capHit = true;
|
|
59
|
+
st.warnings.push(`reached MAX_TRIGGERS_PER_WINDOW=${MAX_TRIGGERS_PER_WINDOW} for trigger "${st.trigger}"; window stopped early`);
|
|
60
|
+
st.endWindow();
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
st.snapping = true;
|
|
64
|
+
const t = st.clock.now();
|
|
65
|
+
st.snap()
|
|
66
|
+
.then((buf) => {
|
|
67
|
+
const ts = t - st.tStart;
|
|
68
|
+
const name = `${String(st.i++).padStart(4, "0")}-${ts}.${st.ext}`;
|
|
69
|
+
// $BROWX_WORKSPACE-rooted by construction (resolveWorkspacePath in caller).
|
|
70
|
+
const p = join(st.resolvedDir, name);
|
|
71
|
+
writeFileSync(p, buf);
|
|
72
|
+
st.paths.push(p);
|
|
73
|
+
st.capturedAt.push(ts);
|
|
74
|
+
})
|
|
75
|
+
.catch((err) => {
|
|
76
|
+
st.warnings.push(`capture on "${st.trigger}" at +${st.clock.now() - st.tStart}ms: ${err instanceof Error ? err.message : String(err)}`);
|
|
77
|
+
})
|
|
78
|
+
.finally(() => {
|
|
79
|
+
st.snapping = false;
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
export async function runScreenshotOn(snap, source, args, workspaceRoot, clock = REAL_CLOCK) {
|
|
83
|
+
validateOnArgs(args);
|
|
84
|
+
// Resolve + create the target dir under $BROWX_WORKSPACE.
|
|
85
|
+
// `resolveWorkspacePath` rejects path escapes before any byte hits disk.
|
|
86
|
+
const resolvedDir = resolveWorkspacePath(workspaceRoot, args.intoDir, "screenshot_on");
|
|
87
|
+
mkdirSync(resolvedDir, { recursive: true });
|
|
88
|
+
const fmt = args.format ?? "png";
|
|
89
|
+
const ext = fmt === "jpeg" ? "jpg" : "png";
|
|
90
|
+
const paths = [];
|
|
91
|
+
const capturedAt = [];
|
|
92
|
+
const warnings = [];
|
|
93
|
+
// Resolver for the window's natural end. The trigger source can also push us
|
|
94
|
+
// to early-finish when the per-window cap is hit.
|
|
95
|
+
let resolveWindow = () => undefined;
|
|
96
|
+
const windowDone = new Promise((r) => {
|
|
97
|
+
resolveWindow = r;
|
|
98
|
+
});
|
|
99
|
+
const cancelTimer = clock.setTimeout(() => resolveWindow(), args.durationMs);
|
|
100
|
+
const st = {
|
|
101
|
+
paths,
|
|
102
|
+
capturedAt,
|
|
103
|
+
warnings,
|
|
104
|
+
i: 0,
|
|
105
|
+
capHit: false,
|
|
106
|
+
snapping: false,
|
|
107
|
+
tStart: clock.now(),
|
|
108
|
+
resolvedDir,
|
|
109
|
+
ext,
|
|
110
|
+
snap,
|
|
111
|
+
clock,
|
|
112
|
+
trigger: args.trigger,
|
|
113
|
+
endWindow: () => {
|
|
114
|
+
cancelTimer();
|
|
115
|
+
resolveWindow();
|
|
116
|
+
},
|
|
117
|
+
};
|
|
118
|
+
const dispose = source.subscribe(args.trigger, () => onScreenshotFire(st));
|
|
119
|
+
try {
|
|
120
|
+
await windowDone;
|
|
121
|
+
}
|
|
122
|
+
finally {
|
|
123
|
+
dispose();
|
|
124
|
+
cancelTimer();
|
|
125
|
+
}
|
|
126
|
+
// A snap may still be in flight when the timer fires — drain briefly so the
|
|
127
|
+
// final capture lands. Bounded so a wedged snap can't extend the window; the
|
|
128
|
+
// outer `withDeadline` is the ultimate ceiling.
|
|
129
|
+
const drainDeadline = clock.now() + 250;
|
|
130
|
+
while (st.snapping && clock.now() < drainDeadline) {
|
|
131
|
+
await new Promise((r) => setTimeout(r, 10));
|
|
132
|
+
}
|
|
133
|
+
if (st.snapping) {
|
|
134
|
+
warnings.push(`screenshot_on: final capture did not settle within 250ms drain window — result may omit one frame`);
|
|
135
|
+
}
|
|
136
|
+
return {
|
|
137
|
+
intoDir: resolvePath(resolvedDir),
|
|
138
|
+
trigger: args.trigger,
|
|
139
|
+
capturedAt,
|
|
140
|
+
paths,
|
|
141
|
+
warnings,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
/** Default `intoDir` shape — `screenshots/<sessionId>-<isoTs>/`. Same shape
|
|
145
|
+
* `screenshot_schedule` uses; the MCP handler joins it against
|
|
146
|
+
* `$BROWX_WORKSPACE` via `resolveWorkspacePath`. */
|
|
147
|
+
export function defaultOnDir(sessionId, now = new Date()) {
|
|
148
|
+
const ts = now.toISOString().replace(/[:.]/g, "-");
|
|
149
|
+
return `screenshots/${sessionId}-${ts}`;
|
|
150
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/** Image format the bytes were encoded as. Matches the existing tool surface
|
|
2
|
+
* (`png` / `jpeg`); kept narrow so the result is self-describing without
|
|
3
|
+
* the caller having to remember what they asked for. */
|
|
4
|
+
export type ScreenshotFormat = "png" | "jpeg";
|
|
5
|
+
export interface ScreenshotSaveArgs {
|
|
6
|
+
/** Workspace-rooted file path. Resolved inside `$BROWX_WORKSPACE` — a path
|
|
7
|
+
* escaping the workspace is rejected up-front (same chokepoint
|
|
8
|
+
* `pdf_save` / `start_har` / `dump_storage_state` use). */
|
|
9
|
+
path: string;
|
|
10
|
+
/** Format the bytes are encoded as — recorded on the result so the caller
|
|
11
|
+
* doesn't have to re-derive it from a file extension. */
|
|
12
|
+
format: ScreenshotFormat;
|
|
13
|
+
/** Whether the bytes were captured with `fullPage:true`. Recorded on the
|
|
14
|
+
* result for trace / debug visibility. */
|
|
15
|
+
fullPage: boolean;
|
|
16
|
+
}
|
|
17
|
+
export interface ScreenshotSaveResult {
|
|
18
|
+
ok: true;
|
|
19
|
+
/** Absolute, workspace-rooted path the bytes were written to. */
|
|
20
|
+
path: string;
|
|
21
|
+
/** Final on-disk size, in bytes. */
|
|
22
|
+
bytes: number;
|
|
23
|
+
/** Format the bytes were encoded as. */
|
|
24
|
+
format: ScreenshotFormat;
|
|
25
|
+
/** Whether the capture was full-page (vs viewport / element-scoped). */
|
|
26
|
+
fullPage: boolean;
|
|
27
|
+
}
|
|
28
|
+
/** Write screenshot bytes to a workspace-rooted path. The caller has already
|
|
29
|
+
* encoded the buffer (via Playwright `page.screenshot()` /
|
|
30
|
+
* `locator.screenshot()`); this layer resolves the path safely, ensures the
|
|
31
|
+
* parent directory exists, and writes the bytes synchronously.
|
|
32
|
+
*
|
|
33
|
+
* Throws on:
|
|
34
|
+
* - `path` escaping `$BROWX_WORKSPACE` (via `resolveWorkspacePath`).
|
|
35
|
+
* - Underlying `writeFileSync` failure (re-thrown with original message). */
|
|
36
|
+
export declare function screenshotSave(buf: Buffer, workspaceRoot: string, args: ScreenshotSaveArgs): ScreenshotSaveResult;
|