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,169 @@
|
|
|
1
|
+
// Session video recording — Playwright's native `recordVideo` context option.
|
|
2
|
+
//
|
|
3
|
+
// Strategy. Playwright's video recorder is wired at context creation and
|
|
4
|
+
// finalized when the context closes — same constraint shape as the native
|
|
5
|
+
// `recordHar` path (see src/page/har.ts). There is NO public mid-session
|
|
6
|
+
// flush; the .webm on disk is written only when the page / context closes.
|
|
7
|
+
// We honour that:
|
|
8
|
+
//
|
|
9
|
+
// - `open_session({recordVideo: {path?, size?}})` resolves the user-facing
|
|
10
|
+
// target path (workspace-rooted; default
|
|
11
|
+
// `<workspace>/videos/<sessionId>-<ISO>.webm`), then wires Playwright's
|
|
12
|
+
// `recordVideo` against a staging directory under `videos/.staging/...`.
|
|
13
|
+
// Playwright auto-names the file in the dir (an opaque GUID) — on
|
|
14
|
+
// `close_session` we resolve that to the deterministic target path via
|
|
15
|
+
// `page.video().saveAs(target)`.
|
|
16
|
+
// - `stop_video({session?})` mirrors `stop_har` in the `nativeRecord:true`
|
|
17
|
+
// posture: Playwright doesn't expose a mid-context stop, so the tool
|
|
18
|
+
// surfaces the constraint instead of silently lying. The recorder state
|
|
19
|
+
// is marked `pendingFinalize:true` and the video will land at the target
|
|
20
|
+
// path when `close_session` runs.
|
|
21
|
+
// - `get_video({session?, format?})` reads the finalized file off disk:
|
|
22
|
+
// `format: "path"` (default) returns the absolute path; `format: "bytes"`
|
|
23
|
+
// inlines as base64 when under the inline cap, else returns the path
|
|
24
|
+
// with a `tooLargeToInline:true` hint. A get-before-stop call surfaces a
|
|
25
|
+
// structured error pointing at `close_session` (the file isn't on disk
|
|
26
|
+
// yet — Playwright constraint).
|
|
27
|
+
//
|
|
28
|
+
// Workspace-rooted by construction. Every path runs through
|
|
29
|
+
// `resolveWorkspacePath` (same helper as HAR / storage-state / pdf_save).
|
|
30
|
+
// Path traversal outside `$BROWX_WORKSPACE` is rejected.
|
|
31
|
+
//
|
|
32
|
+
// BYOB / attached. Mirror of HAR + pdf_save: the consumer's Chrome is
|
|
33
|
+
// not-owned and we don't wire context-creation primitives on it. The tool
|
|
34
|
+
// layer refuses cleanly with a structured error (see `assertVideoSupported`).
|
|
35
|
+
import { existsSync, mkdirSync, readFileSync, statSync } from "node:fs";
|
|
36
|
+
import { dirname } from "node:path";
|
|
37
|
+
import { resolveWorkspacePath } from "../session/storage.js";
|
|
38
|
+
/** Maximum size (in bytes) at which a finalized video is returned inline as
|
|
39
|
+
* base64 (`format:"bytes"`) rather than only by path. Conservative cap —
|
|
40
|
+
* video bytes balloon fast; agents that hit it should rely on the path. */
|
|
41
|
+
export const VIDEO_INLINE_CAP_BYTES = 1024 * 1024; // 1 MiB
|
|
42
|
+
export function newVideoRecorderState() {
|
|
43
|
+
return { active: false, finalized: false, pendingFinalize: false };
|
|
44
|
+
}
|
|
45
|
+
/** Refuse video on session modes Playwright's `recordVideo` doesn't support
|
|
46
|
+
* cleanly. BYOB (`attached`) is the only refusal: we don't wire
|
|
47
|
+
* context-creation primitives on the consumer's Chrome, mirroring the
|
|
48
|
+
* `pdf_save` / `recordHar` posture. Managed `persistent` and `incognito`
|
|
49
|
+
* sessions are both supported (headed and headless). */
|
|
50
|
+
export function assertVideoSupported(ctx) {
|
|
51
|
+
if (ctx.mode === "attached") {
|
|
52
|
+
return {
|
|
53
|
+
error: "video recording: not supported on attached / BYOB sessions — " +
|
|
54
|
+
"Playwright's `recordVideo` is a context-creation primitive and " +
|
|
55
|
+
"we don't mutate the consumer's Chrome (not-owned).",
|
|
56
|
+
hint: 'open a managed session (open_session({mode:"persistent"}) or ' +
|
|
57
|
+
'{mode:"incognito"}) with {recordVideo:{...}} and drive that.',
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
/** Default video filename for an auto-named recording. ISO timestamp with
|
|
63
|
+
* `:` / `.` mapped to `-` so the name is filesystem-safe on every platform. */
|
|
64
|
+
export function defaultVideoFilename(sessionId, now = new Date()) {
|
|
65
|
+
const iso = now.toISOString().replace(/[:.]/g, "-");
|
|
66
|
+
const safeId = sessionId.replace(/[^A-Za-z0-9._-]/g, "_");
|
|
67
|
+
return `${safeId}-${iso}.webm`;
|
|
68
|
+
}
|
|
69
|
+
/** Resolve an explicit user-supplied path (workspace-escape rejected) OR
|
|
70
|
+
* build the default `<workspace>/videos/<auto>.webm` path. Creates the
|
|
71
|
+
* parent dir on demand — still under the workspace root by construction. */
|
|
72
|
+
export function resolveVideoTargetPath(workspaceRoot, sessionId, userPath, tool) {
|
|
73
|
+
const resolved = userPath
|
|
74
|
+
? resolveWorkspacePath(workspaceRoot, userPath, tool)
|
|
75
|
+
: resolveWorkspacePath(workspaceRoot, `videos/${defaultVideoFilename(sessionId)}`, tool);
|
|
76
|
+
// `resolved` is workspace-rooted by construction (resolveWorkspacePath
|
|
77
|
+
// rejects any escape from `workspaceRoot`); `dirname(resolved)` is
|
|
78
|
+
// workspace-rooted too — the mkdirSync below never touches cwd.
|
|
79
|
+
// BROWX_WORKSPACE-derived.
|
|
80
|
+
const parent = dirname(resolved);
|
|
81
|
+
if (parent && parent !== resolved && !existsSync(parent)) {
|
|
82
|
+
mkdirSync(parent, { recursive: true });
|
|
83
|
+
}
|
|
84
|
+
return resolved;
|
|
85
|
+
}
|
|
86
|
+
/** Resolve + create the staging directory Playwright writes its auto-named
|
|
87
|
+
* .webm into. One staging dir per session, under
|
|
88
|
+
* `<workspace>/videos/.staging/<sessionId>-<ISO>/`. Workspace-rooted by
|
|
89
|
+
* construction (resolveWorkspacePath rejects escape). */
|
|
90
|
+
export function resolveVideoStagingDir(workspaceRoot, sessionId, now = new Date()) {
|
|
91
|
+
const iso = now.toISOString().replace(/[:.]/g, "-");
|
|
92
|
+
const safeId = sessionId.replace(/[^A-Za-z0-9._-]/g, "_");
|
|
93
|
+
const stagingRel = `videos/.staging/${safeId}-${iso}`;
|
|
94
|
+
// resolveWorkspacePath rejects any escape from `workspaceRoot` — the
|
|
95
|
+
// resolved staging dir is BROWX_WORKSPACE-rooted by construction; the
|
|
96
|
+
// mkdirSync below never touches cwd.
|
|
97
|
+
const resolved = resolveWorkspacePath(workspaceRoot, stagingRel, "open_session");
|
|
98
|
+
if (!existsSync(resolved))
|
|
99
|
+
mkdirSync(resolved, { recursive: true });
|
|
100
|
+
return resolved;
|
|
101
|
+
}
|
|
102
|
+
/** Build the Playwright `recordVideo` option for `open_session({recordVideo})`.
|
|
103
|
+
* The caller passes this into `browser.newContext({recordVideo})` /
|
|
104
|
+
* `chromium.launchPersistentContext({recordVideo})`. Returns both the
|
|
105
|
+
* Playwright-shaped option AND the resolved target path + staging dir so the
|
|
106
|
+
* registry can persist them on `VideoRecorderState`. */
|
|
107
|
+
export function buildRecordVideoOption(workspaceRoot, sessionId, cfg) {
|
|
108
|
+
const targetPath = resolveVideoTargetPath(workspaceRoot, sessionId, cfg.path, "open_session");
|
|
109
|
+
const stagingDir = resolveVideoStagingDir(workspaceRoot, sessionId);
|
|
110
|
+
const recordVideo = {
|
|
111
|
+
dir: stagingDir,
|
|
112
|
+
};
|
|
113
|
+
if (cfg.size)
|
|
114
|
+
recordVideo.size = cfg.size;
|
|
115
|
+
return { targetPath, stagingDir, size: cfg.size, recordVideo };
|
|
116
|
+
}
|
|
117
|
+
/** Mark the recorder as `pendingFinalize` — the agent has signalled they
|
|
118
|
+
* want the recording stopped. The actual flush happens on `close_session`
|
|
119
|
+
* (Playwright finalizes the .webm only when the context closes). Mirrors
|
|
120
|
+
* the `stop_har` shape for the `nativeRecord:true` posture. */
|
|
121
|
+
export function stopVideo(state) {
|
|
122
|
+
if (!state.active) {
|
|
123
|
+
return { wasActive: false, pendingFinalize: false, finalized: state.finalized };
|
|
124
|
+
}
|
|
125
|
+
state.pendingFinalize = true;
|
|
126
|
+
return {
|
|
127
|
+
wasActive: true,
|
|
128
|
+
targetPath: state.targetPath,
|
|
129
|
+
pendingFinalize: true,
|
|
130
|
+
finalized: state.finalized,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
/** Finalize the recording on session teardown. Calls `page.video().saveAs()`
|
|
134
|
+
* with the deterministic target path — Playwright waits for the page to
|
|
135
|
+
* close and the video to be fully written before resolving. Best-effort:
|
|
136
|
+
* errors here MUST NOT block session teardown (mirrors the `perf` /
|
|
137
|
+
* `artifacts` cleanup posture in the registry teardown). */
|
|
138
|
+
export async function finalizeVideoOnClose(page, state) {
|
|
139
|
+
if (!state.active || !state.targetPath)
|
|
140
|
+
return;
|
|
141
|
+
const video = page.video();
|
|
142
|
+
if (!video) {
|
|
143
|
+
// recordVideo was wired but the page reports no video — best-effort.
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
try {
|
|
147
|
+
await video.saveAs(state.targetPath);
|
|
148
|
+
state.finalized = true;
|
|
149
|
+
}
|
|
150
|
+
catch {
|
|
151
|
+
/* best-effort — teardown never blocks on this */
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
/** Read a finalized video file. `format: "bytes"` inlines as base64 when
|
|
155
|
+
* under the cap; `format: "path"` (or over-cap) returns only the path. */
|
|
156
|
+
export function readVideoIfReady(path, format = "path", capBytes = VIDEO_INLINE_CAP_BYTES) {
|
|
157
|
+
if (!existsSync(path)) {
|
|
158
|
+
return { exists: false, path };
|
|
159
|
+
}
|
|
160
|
+
const st = statSync(path);
|
|
161
|
+
if (format === "path") {
|
|
162
|
+
return { exists: true, path, bytes: st.size };
|
|
163
|
+
}
|
|
164
|
+
if (st.size > capBytes) {
|
|
165
|
+
return { exists: true, path, bytes: st.size, tooLargeToInline: true };
|
|
166
|
+
}
|
|
167
|
+
const buf = readFileSync(path);
|
|
168
|
+
return { exists: true, path, bytes: st.size, inlineBase64: buf.toString("base64") };
|
|
169
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { BrowserContext, Page } from "playwright-core";
|
|
2
|
+
export type VisibilityState = "background" | "foreground";
|
|
3
|
+
export interface VisibilityResult {
|
|
4
|
+
ok: boolean;
|
|
5
|
+
state: VisibilityState;
|
|
6
|
+
/** true when a real scratch-page background swap was applied (the driven
|
|
7
|
+
* page is genuinely not the front tab), false when only the synthetic
|
|
8
|
+
* visibility flip was possible. */
|
|
9
|
+
realBackgrounding: boolean;
|
|
10
|
+
/** present on a `background` call with `holdMs`: how long the page was held
|
|
11
|
+
* hidden before auto-foregrounding. */
|
|
12
|
+
heldMs?: number;
|
|
13
|
+
note?: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Drive the tab's visibility. `background` with `holdMs` is the headline
|
|
17
|
+
* primitive: background the page, hold it hidden for `holdMs` (real throttling
|
|
18
|
+
* in effect where the browser honours it), then auto-foreground — so the
|
|
19
|
+
* background→return transition that triggers the bug is reproducible in one
|
|
20
|
+
* call. `holdMs` is ignored for `foreground`.
|
|
21
|
+
*/
|
|
22
|
+
export declare function setTabVisibility(page: Page, context: BrowserContext, state: VisibilityState, holdMs?: number): Promise<VisibilityResult>;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
// Tab background / foreground control.
|
|
2
|
+
//
|
|
3
|
+
// A whole class of real bugs only reproduces when the tab is *backgrounded*
|
|
4
|
+
// during a transition: the browser throttles `setTimeout`, pauses
|
|
5
|
+
// `requestAnimationFrame` (framework enter/animation hooks never fire), and on
|
|
6
|
+
// return a `visibilitychange`/focus handler replays stale state. browxai
|
|
7
|
+
// otherwise keeps the driven tab foreground, so agentic QA scores these flows
|
|
8
|
+
// PASS while they are broken.
|
|
9
|
+
//
|
|
10
|
+
// Two levers, applied together:
|
|
11
|
+
// 1. Synthetic: server-injected *fixed* script (not agent JS — same posture
|
|
12
|
+
// as the sampler / overlay-hide) overrides `document.visibilityState` /
|
|
13
|
+
// `document.hidden` and dispatches `visibilitychange`. This deterministic
|
|
14
|
+
// across managed/incognito/attached/headless, and covers the large
|
|
15
|
+
// on-focus-refetch / visibilitychange-handler / realtime-replay subset.
|
|
16
|
+
// 2. Real best-effort: bring a blank scratch page in the same context to the
|
|
17
|
+
// front so Chromium actually treats the driven page as hidden (real
|
|
18
|
+
// timer/rAF throttling). Headless Chromium may not throttle even when
|
|
19
|
+
// backgrounded — so this is best-effort and reported as such, never
|
|
20
|
+
// silently assumed (cf. the documented headless gaps).
|
|
21
|
+
const SCRATCH_URL = "about:blank";
|
|
22
|
+
// Fixed in-page scripts. `configurable: true` so the two states can be
|
|
23
|
+
// re-applied across calls. No agent-supplied code path.
|
|
24
|
+
const HIDE = `(() => {
|
|
25
|
+
Object.defineProperty(document, 'visibilityState', { configurable: true, get: () => 'hidden' });
|
|
26
|
+
Object.defineProperty(document, 'hidden', { configurable: true, get: () => true });
|
|
27
|
+
document.dispatchEvent(new Event('visibilitychange'));
|
|
28
|
+
window.dispatchEvent(new Event('blur'));
|
|
29
|
+
})()`;
|
|
30
|
+
const SHOW = `(() => {
|
|
31
|
+
Object.defineProperty(document, 'visibilityState', { configurable: true, get: () => 'visible' });
|
|
32
|
+
Object.defineProperty(document, 'hidden', { configurable: true, get: () => false });
|
|
33
|
+
document.dispatchEvent(new Event('visibilitychange'));
|
|
34
|
+
window.dispatchEvent(new Event('focus'));
|
|
35
|
+
})()`;
|
|
36
|
+
/** Reuse-or-create a blank scratch page for this context (used to actually
|
|
37
|
+
* background the driven page by taking front focus away from it). */
|
|
38
|
+
async function scratchPage(context, driven) {
|
|
39
|
+
try {
|
|
40
|
+
const existing = context.pages().find((p) => p !== driven && p.url() === SCRATCH_URL);
|
|
41
|
+
if (existing)
|
|
42
|
+
return existing;
|
|
43
|
+
const p = await context.newPage();
|
|
44
|
+
await p.goto(SCRATCH_URL).catch(() => undefined);
|
|
45
|
+
return p;
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Drive the tab's visibility. `background` with `holdMs` is the headline
|
|
53
|
+
* primitive: background the page, hold it hidden for `holdMs` (real throttling
|
|
54
|
+
* in effect where the browser honours it), then auto-foreground — so the
|
|
55
|
+
* background→return transition that triggers the bug is reproducible in one
|
|
56
|
+
* call. `holdMs` is ignored for `foreground`.
|
|
57
|
+
*/
|
|
58
|
+
export async function setTabVisibility(page, context, state, holdMs) {
|
|
59
|
+
if (state === "foreground") {
|
|
60
|
+
await page.evaluate(SHOW).catch(() => undefined);
|
|
61
|
+
await page.bringToFront().catch(() => undefined);
|
|
62
|
+
return { ok: true, state, realBackgrounding: false };
|
|
63
|
+
}
|
|
64
|
+
// background
|
|
65
|
+
const scratch = await scratchPage(context, page);
|
|
66
|
+
let realBackgrounding = false;
|
|
67
|
+
if (scratch) {
|
|
68
|
+
await scratch.bringToFront().catch(() => undefined);
|
|
69
|
+
realBackgrounding = true;
|
|
70
|
+
}
|
|
71
|
+
await page.evaluate(HIDE).catch(() => undefined);
|
|
72
|
+
if (holdMs !== undefined && holdMs > 0) {
|
|
73
|
+
await new Promise((r) => setTimeout(r, holdMs));
|
|
74
|
+
await page.evaluate(SHOW).catch(() => undefined);
|
|
75
|
+
await page.bringToFront().catch(() => undefined);
|
|
76
|
+
return {
|
|
77
|
+
ok: true,
|
|
78
|
+
state: "foreground",
|
|
79
|
+
realBackgrounding,
|
|
80
|
+
heldMs: holdMs,
|
|
81
|
+
note: realBackgrounding
|
|
82
|
+
? "backgrounded for the hold window (real front-tab swap + synthetic visibilitychange), then auto-foregrounded; timer/rAF throttling is best-effort and may not occur under headless"
|
|
83
|
+
: "synthetic visibilitychange only (no second page could be created to take front focus); on-focus/visibilitychange handlers fire but real timer throttling is not simulated",
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
return {
|
|
87
|
+
ok: true,
|
|
88
|
+
state,
|
|
89
|
+
realBackgrounding,
|
|
90
|
+
note: realBackgrounding
|
|
91
|
+
? "page backgrounded (front-tab swap + synthetic visibilitychange); call tab_visibility({state:'foreground'}) to return. Real timer/rAF throttling is best-effort under headless."
|
|
92
|
+
: "synthetic visibilitychange only; real timer throttling not simulated",
|
|
93
|
+
};
|
|
94
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { type NetworkEntry, type NetworkSummary, type WsFrame } from "./network.js";
|
|
2
|
+
import type { ActionContext } from "./actionresult.js";
|
|
3
|
+
export interface WatchedRegion {
|
|
4
|
+
role: string;
|
|
5
|
+
name?: string;
|
|
6
|
+
ref: string;
|
|
7
|
+
appearedAtMs: number;
|
|
8
|
+
/** ms offset when it vanished, or null if still present at window end. */
|
|
9
|
+
disappearedAtMs: number | null;
|
|
10
|
+
}
|
|
11
|
+
export interface WatchResult {
|
|
12
|
+
durationMs: number;
|
|
13
|
+
samples: number;
|
|
14
|
+
regions: WatchedRegion[];
|
|
15
|
+
console: {
|
|
16
|
+
errors: string[];
|
|
17
|
+
warnings: number;
|
|
18
|
+
pageErrors: string[];
|
|
19
|
+
};
|
|
20
|
+
network: {
|
|
21
|
+
summary: NetworkSummary;
|
|
22
|
+
requests: NetworkEntry[];
|
|
23
|
+
};
|
|
24
|
+
wsFrames: WsFrame[];
|
|
25
|
+
}
|
|
26
|
+
export declare function watchWindow(ctx: ActionContext, opts: {
|
|
27
|
+
durationMs: number;
|
|
28
|
+
sampleMs?: number;
|
|
29
|
+
}): Promise<WatchResult>;
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
// timed observation window with no driving action.
|
|
2
|
+
//
|
|
3
|
+
// `ActionResult`'s structure diff is endpoint-only (pre vs post) — a *transient*
|
|
4
|
+
// element that appears AND disappears inside the window is invisible to it.
|
|
5
|
+
// `watch` samples the top-level regions across the window, so double-fire /
|
|
6
|
+
// missing-broadcast / flash-of-content classes are caught: each region gets
|
|
7
|
+
// `appearedAtMs` and `disappearedAtMs` (null = still present at the end).
|
|
8
|
+
//
|
|
9
|
+
// Console / network / WS are time-stamped buffers already — sliced over the
|
|
10
|
+
// same window.
|
|
11
|
+
import { walk } from "./a11y.js";
|
|
12
|
+
/** Roles that signal a page-level transient/notification surface. */
|
|
13
|
+
const WATCHED_ROLES = new Set([
|
|
14
|
+
"dialog",
|
|
15
|
+
"alertdialog",
|
|
16
|
+
"alert",
|
|
17
|
+
"status",
|
|
18
|
+
"banner",
|
|
19
|
+
"tooltip",
|
|
20
|
+
"log",
|
|
21
|
+
"marquee",
|
|
22
|
+
"timer",
|
|
23
|
+
]);
|
|
24
|
+
const MAX_DURATION_MS = 60_000;
|
|
25
|
+
const DEFAULT_SAMPLE_MS = 250;
|
|
26
|
+
export async function watchWindow(ctx, opts) {
|
|
27
|
+
const durationMs = Math.min(Math.max(opts.durationMs, 1), MAX_DURATION_MS);
|
|
28
|
+
const sampleMs = Math.max(opts.sampleMs ?? DEFAULT_SAMPLE_MS, 50);
|
|
29
|
+
const tStart = Date.now();
|
|
30
|
+
// Thread the session's secrets registry (when capability `secrets` is
|
|
31
|
+
// active and the registry exists on the action context) so the network
|
|
32
|
+
// tap's literal-value sanitisation runs over URLs / mutation
|
|
33
|
+
// responseShape keys during the watch window — same chokepoint the
|
|
34
|
+
// action-window tap uses.
|
|
35
|
+
// The per-action network tap comes from the engine's substrate:
|
|
36
|
+
// chromium → the CDP NetworkTap; firefox/webkit → the Playwright context-event
|
|
37
|
+
// tap. Same close shape on every engine, so the watch result is engine-blind.
|
|
38
|
+
const net = ctx.network ? ctx.network.openActionTap() : null;
|
|
39
|
+
if (net)
|
|
40
|
+
await net.open();
|
|
41
|
+
// ref → tracking record across samples.
|
|
42
|
+
const seen = new Map();
|
|
43
|
+
let samples = 0;
|
|
44
|
+
const sampleOnce = async () => {
|
|
45
|
+
const tree = await ctx.snapshot.a11yTree(ctx.refs, ctx.testAttributes).catch(() => null);
|
|
46
|
+
if (!tree)
|
|
47
|
+
return;
|
|
48
|
+
const nowMs = Date.now() - tStart;
|
|
49
|
+
samples++;
|
|
50
|
+
for (const { node } of walk(tree)) {
|
|
51
|
+
if (!WATCHED_ROLES.has(node.role))
|
|
52
|
+
continue;
|
|
53
|
+
const rec = seen.get(node.ref);
|
|
54
|
+
if (rec) {
|
|
55
|
+
rec.lastMs = nowMs;
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
seen.set(node.ref, { role: node.role, name: node.name, firstMs: nowMs, lastMs: nowMs });
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
await sampleOnce();
|
|
63
|
+
while (Date.now() - tStart < durationMs) {
|
|
64
|
+
await new Promise((r) => setTimeout(r, sampleMs));
|
|
65
|
+
await sampleOnce();
|
|
66
|
+
}
|
|
67
|
+
const endMs = Date.now() - tStart;
|
|
68
|
+
const network = net
|
|
69
|
+
? await net.close()
|
|
70
|
+
: { summary: { total: 0, byType: {}, failed: 0 }, requests: [] };
|
|
71
|
+
const errors = ctx.console.errorsSince(tStart);
|
|
72
|
+
const pageErrors = ctx.console.pageErrorsSince(tStart);
|
|
73
|
+
const warnings = ctx.console.warningCountSince(tStart);
|
|
74
|
+
const wsFrames = ctx.ws ? ctx.ws.since(tStart, 100) : [];
|
|
75
|
+
// A region "disappeared" if its last sighting was more than ~1.5 sample
|
|
76
|
+
// intervals before the final sample (i.e. it wasn't in the last sample).
|
|
77
|
+
const staleCut = endMs - sampleMs * 1.5;
|
|
78
|
+
const regions = [...seen.values()].map((r) => ({
|
|
79
|
+
role: r.role,
|
|
80
|
+
name: r.name,
|
|
81
|
+
ref: "",
|
|
82
|
+
appearedAtMs: r.firstMs,
|
|
83
|
+
disappearedAtMs: r.lastMs < staleCut ? r.lastMs : null,
|
|
84
|
+
}));
|
|
85
|
+
// attach refs back (Map key is the ref)
|
|
86
|
+
let i = 0;
|
|
87
|
+
for (const ref of seen.keys()) {
|
|
88
|
+
regions[i].ref = ref;
|
|
89
|
+
i++;
|
|
90
|
+
}
|
|
91
|
+
return {
|
|
92
|
+
durationMs,
|
|
93
|
+
samples,
|
|
94
|
+
regions,
|
|
95
|
+
console: { errors, warnings, pageErrors },
|
|
96
|
+
network: { summary: network.summary, requests: network.requests },
|
|
97
|
+
wsFrames,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import type { CDPSession, Page } from "playwright-core";
|
|
2
|
+
export type WorkerType = "web" | "service";
|
|
3
|
+
export type WorkerFilter = WorkerType | "all";
|
|
4
|
+
export interface WorkerListing {
|
|
5
|
+
workerId: string;
|
|
6
|
+
type: WorkerType;
|
|
7
|
+
url: string;
|
|
8
|
+
/** Best-effort state. Web workers: always `"running"` (browser doesn't
|
|
9
|
+
* expose lifecycle once they're constructed). Service workers: the CDP
|
|
10
|
+
* `running_status` (`stopped` / `starting` / `running` / `stopping`). */
|
|
11
|
+
state?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface WorkerMessage {
|
|
14
|
+
workerId: string;
|
|
15
|
+
/** Always serialised to a string for the ring; structured-clone payloads
|
|
16
|
+
* are `JSON.stringify`d on the page side (and silently truncated to the
|
|
17
|
+
* payload cap). Binary `MessagePort`s are not transferred. */
|
|
18
|
+
data: string;
|
|
19
|
+
/** epoch ms — fixed on receipt. */
|
|
20
|
+
at: number;
|
|
21
|
+
}
|
|
22
|
+
export interface SwFetchInterceptSpec {
|
|
23
|
+
/** Glob matched against the intercepted request URL. Same shape as
|
|
24
|
+
* `route` / `ws_intercept`. `*` = single path segment, `**` = any. */
|
|
25
|
+
pattern: string;
|
|
26
|
+
/** Canned response. `body` defaults to `""`. `contentType` defaults
|
|
27
|
+
* to `application/json`. `status` defaults to `200`. */
|
|
28
|
+
response: {
|
|
29
|
+
status?: number;
|
|
30
|
+
body?: string;
|
|
31
|
+
contentType?: string;
|
|
32
|
+
headers?: Record<string, string>;
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
export declare const WORKERS_PAGE_SCRIPT = "(() => {\n if (window.__browxWorkers) return;\n var NativeWorker = window.Worker;\n if (!NativeWorker) return;\n var nativePost = NativeWorker.prototype.postMessage;\n var workers = new Map(); // wwId -> Worker\n var messages = []; // {workerId, data, at} ring (capped at 500)\n var MAX = 500;\n var nextId = 1;\n\n function recordMessage(id, payload) {\n var data;\n try {\n data = typeof payload === \"string\" ? payload : JSON.stringify(payload);\n } catch (_) {\n data = \"[unserialisable]\";\n }\n if (data && data.length > 4000) data = data.slice(0, 4000) + \"\u2026\";\n messages.push({ workerId: id, data: data, at: Date.now() });\n if (messages.length > MAX) messages.splice(0, messages.length - MAX);\n }\n\n function Wrapped(scriptURL, opts) {\n var w = arguments.length > 1 ? new NativeWorker(scriptURL, opts) : new NativeWorker(scriptURL);\n var id = \"ww-\" + (nextId++);\n workers.set(id, w);\n try { w.__browxId = id; } catch (_) {}\n // Mirror every message-from-worker into the ring. We use addEventListener\n // (not onmessage) so we don't fight with app-side onmessage handlers.\n try {\n w.addEventListener(\"message\", function (ev) { recordMessage(id, ev.data); });\n } catch (_) {}\n return w;\n }\n Wrapped.prototype = NativeWorker.prototype;\n try { Object.defineProperty(Wrapped, \"name\", { value: \"Worker\" }); } catch (_) {}\n window.Worker = Wrapped;\n\n window.__browxWorkers = {\n list: function () {\n var out = [];\n workers.forEach(function (w, id) {\n // We can't get the scriptURL back from a Worker after construction\n // in all browsers \u2014 fall back to the recorded url if we tracked it,\n // else the empty string. (Chromium DOES expose it via internal slot\n // but not via any public API; we track it at construction via the\n // initial scriptURL argument \u2014 see __browxWorkers._urls.\n var url = (window.__browxWorkers._urls && window.__browxWorkers._urls.get(id)) || \"\";\n out.push({ workerId: id, url: url });\n });\n return out;\n },\n _urls: new Map(),\n post: function (id, msg) {\n var w = workers.get(id);\n if (!w) return { ok: false, error: \"no worker with id \" + id };\n try {\n nativePost.call(w, msg);\n return { ok: true };\n } catch (e) {\n return { ok: false, error: e && e.message ? e.message : String(e) };\n }\n },\n drain: function (id) {\n var out;\n if (id) {\n out = [];\n var kept = [];\n for (var i = 0; i < messages.length; i++) {\n if (messages[i].workerId === id) out.push(messages[i]);\n else kept.push(messages[i]);\n }\n messages = kept;\n } else {\n out = messages.slice();\n messages.length = 0;\n }\n return out;\n },\n };\n\n // Track scriptURL at construction. We can't get it post-hoc on most engines.\n var origWrapped = Wrapped;\n window.Worker = function (scriptURL, opts) {\n var w = arguments.length > 1 ? origWrapped(scriptURL, opts) : origWrapped(scriptURL);\n try {\n var id = w.__browxId;\n if (id) {\n var url = \"\";\n try { url = String(scriptURL && scriptURL.href ? scriptURL.href : scriptURL || \"\"); } catch (_) {}\n window.__browxWorkers._urls.set(id, url);\n }\n } catch (_) {}\n return w;\n };\n window.Worker.prototype = NativeWorker.prototype;\n try { Object.defineProperty(window.Worker, \"name\", { value: \"Worker\" }); } catch (_) {}\n})();";
|
|
36
|
+
interface BrowxWorkersApi {
|
|
37
|
+
list(): Array<{
|
|
38
|
+
workerId: string;
|
|
39
|
+
url: string;
|
|
40
|
+
}>;
|
|
41
|
+
post(id: string, msg: string): {
|
|
42
|
+
ok: boolean;
|
|
43
|
+
error?: string;
|
|
44
|
+
};
|
|
45
|
+
drain(id?: string): Array<{
|
|
46
|
+
workerId: string;
|
|
47
|
+
data: string;
|
|
48
|
+
at: number;
|
|
49
|
+
}>;
|
|
50
|
+
}
|
|
51
|
+
declare global {
|
|
52
|
+
var __browxWorkers: BrowxWorkersApi | undefined;
|
|
53
|
+
}
|
|
54
|
+
export declare class WorkersRegistry {
|
|
55
|
+
/** SW attachments keyed by CDP sessionId. */
|
|
56
|
+
private swAttached;
|
|
57
|
+
/** Stable monotonic id for the SW listing — `sw-1`, `sw-2`, …. Keyed by
|
|
58
|
+
* CDP sessionId so the id survives status transitions on the same SW. */
|
|
59
|
+
private swIdBySession;
|
|
60
|
+
private nextSwId;
|
|
61
|
+
/** Active fetch interceptors. Re-add of the same pattern replaces. */
|
|
62
|
+
private fetchInterceptors;
|
|
63
|
+
/** Server-side ring of FROM-SW messages (we relay these via a CDP
|
|
64
|
+
* `Runtime.bindingCalled` shuttle on each SW session). */
|
|
65
|
+
private swMessages;
|
|
66
|
+
/** True once the page-side wrapper has been installed. */
|
|
67
|
+
private pageInstalled;
|
|
68
|
+
/** True once we've called `ServiceWorker.enable` + wired the auto-attach
|
|
69
|
+
* on the top-level CDP session. */
|
|
70
|
+
private swEnabled;
|
|
71
|
+
/** Detach functions for cleanup. */
|
|
72
|
+
private detachers;
|
|
73
|
+
/** Install the page-side `Worker` wrapper. Idempotent. Called eagerly at
|
|
74
|
+
* session creation (under capability `read`) so workers opened by the
|
|
75
|
+
* initial document are seen — same posture as `WsInteractiveRegistry`. */
|
|
76
|
+
installPageWrapper(page: Page): Promise<void>;
|
|
77
|
+
/** Enable the CDP ServiceWorker domain on the session's top-level CDP and
|
|
78
|
+
* wire `Target.setAutoAttach` so newly-registered SWs auto-attach as child
|
|
79
|
+
* sessions. Idempotent. */
|
|
80
|
+
/** Register a CDP event handler + push its detacher onto `this.detachers`.
|
|
81
|
+
* The event name is dynamic here, so the strongly-typed per-event `on`/`off`
|
|
82
|
+
* overloads are bridged through a single untyped seam. */
|
|
83
|
+
private onCdp;
|
|
84
|
+
/** `ServiceWorker.workerVersionUpdated` — refresh url/status on the matching
|
|
85
|
+
* attachment(s). */
|
|
86
|
+
private registerVersionUpdated;
|
|
87
|
+
/** `Target.attachedToTarget` / `detachedFromTarget` — track the SW attachment
|
|
88
|
+
* map, arming any already-armed fetch interceptors on a new SW. */
|
|
89
|
+
private registerAttachDetach;
|
|
90
|
+
/** `Fetch.requestPaused` (TOP session; flatten routes child events up by
|
|
91
|
+
* `sessionId`) — fulfill against a matching interceptor, else continue. */
|
|
92
|
+
private registerRequestPaused;
|
|
93
|
+
private handleRequestPaused;
|
|
94
|
+
installSwListener(cdp: CDPSession): Promise<void>;
|
|
95
|
+
private applyFetchEnable;
|
|
96
|
+
list(page: Page, cdp: CDPSession, filter?: WorkerFilter): Promise<WorkerListing[]>;
|
|
97
|
+
sendMessage(page: Page, cdp: CDPSession, args: {
|
|
98
|
+
workerId: string;
|
|
99
|
+
message: string;
|
|
100
|
+
}): Promise<{
|
|
101
|
+
ok: boolean;
|
|
102
|
+
workerId: string;
|
|
103
|
+
error?: string;
|
|
104
|
+
}>;
|
|
105
|
+
readMessages(page: Page, args: {
|
|
106
|
+
workerId?: string;
|
|
107
|
+
}): Promise<WorkerMessage[]>;
|
|
108
|
+
addFetchIntercept(cdp: CDPSession, spec: SwFetchInterceptSpec): Promise<{
|
|
109
|
+
key: string;
|
|
110
|
+
active: string[];
|
|
111
|
+
}>;
|
|
112
|
+
removeFetchIntercept(cdp: CDPSession, sel: {
|
|
113
|
+
pattern?: string;
|
|
114
|
+
}): Promise<{
|
|
115
|
+
removed: string[];
|
|
116
|
+
active: string[];
|
|
117
|
+
}>;
|
|
118
|
+
listFetchIntercepts(): string[];
|
|
119
|
+
/** Append a FROM-SW message to the server-side ring. Currently unused by
|
|
120
|
+
* the production path (the SW side message-relay is left as a future
|
|
121
|
+
* follow-up — see report); kept for symmetry + future use. */
|
|
122
|
+
recordSwMessage(workerId: string, data: string): void;
|
|
123
|
+
/** Release all CDP listeners. Called from the session teardown. */
|
|
124
|
+
dispose(): void;
|
|
125
|
+
}
|
|
126
|
+
export {};
|