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,251 @@
|
|
|
1
|
+
/// <reference lib="dom" />
|
|
2
|
+
// `element_export` — save a specific element subtree as a self-contained
|
|
3
|
+
// HTML snippet plus its rendered CSS + linked resources.
|
|
4
|
+
//
|
|
5
|
+
// Sibling to `page_archive` (src/page/archive.ts), scoped to one element
|
|
6
|
+
// subtree instead of the whole document. The use case is "extract this
|
|
7
|
+
// component / card / table — I want the markup, the styles that make it
|
|
8
|
+
// look like it does, and the images / fonts it pulls — to a directory I
|
|
9
|
+
// can grep / diff / re-open offline".
|
|
10
|
+
//
|
|
11
|
+
// Two formats, same shape as page_archive:
|
|
12
|
+
//
|
|
13
|
+
// - `directory` (default) — `<intoDir>/element.html` + `<intoDir>/assets/`
|
|
14
|
+
// with every fetched resource. Internal `[src]` / `[href]` /
|
|
15
|
+
// `background-image: url(...)` references in the element subtree are
|
|
16
|
+
// rewritten to relative `assets/<kind>/<file>` paths.
|
|
17
|
+
//
|
|
18
|
+
// - `single-file` — one HTML file at `<intoDir>` (a `.html` path) with
|
|
19
|
+
// every linked resource inlined as `data:` URIs and computed styles
|
|
20
|
+
// inlined per element. Same browser-engine soft-cap caveat as
|
|
21
|
+
// `page_archive` (~150 MB).
|
|
22
|
+
//
|
|
23
|
+
// Resource discovery walks **only the element subtree** (not the whole
|
|
24
|
+
// document) for `[src]`, `[href]`, and computed `background-image: url(...)`
|
|
25
|
+
// — same heuristics as `archive.ts`'s DISCOVERY_SCRIPT but scoped to a
|
|
26
|
+
// `Node` instead of `document`. Stylesheets are captured page-wide (a
|
|
27
|
+
// stylesheet matters even if its rules only target the subtree); inline
|
|
28
|
+
// `<style>` blocks from the page are likewise carried over. The pragmatic
|
|
29
|
+
// trade-off: more CSS than strictly needed, but the snippet renders
|
|
30
|
+
// faithfully without the agent having to compose style extraction.
|
|
31
|
+
//
|
|
32
|
+
// Secrets-masking interplay: same deliberate gap as `page_archive`. The
|
|
33
|
+
// exported file is a faithful capture of the rendered subtree; running the
|
|
34
|
+
// per-session egress masking layer over it would corrupt inline JSON / CSS
|
|
35
|
+
// / binary bytes. The `warnings[]` array always carries the caveat as its
|
|
36
|
+
// first entry.
|
|
37
|
+
import { resolve as resolvePath, dirname, join } from "node:path";
|
|
38
|
+
import { mkdirSync, writeFileSync, statSync } from "node:fs";
|
|
39
|
+
import { resolveWorkspacePath } from "../session/storage.js";
|
|
40
|
+
import { locatorFor } from "./locator.js";
|
|
41
|
+
import { SUBTREE_DISCOVERY_FN, buildFetchScript, assetFilename, subdirForKind, mimeFromKind, rewriteHtml, directorySize, wrapStandalone, } from "./element-export-discovery.js";
|
|
42
|
+
const DEFAULT_MAX_SIZE_MB = 50;
|
|
43
|
+
const SINGLE_FILE_SOFT_WARN_MB = 150;
|
|
44
|
+
const PER_RESOURCE_HARD_MB = 50;
|
|
45
|
+
/** Default output target when `intoDir` is omitted. Workspace-relative,
|
|
46
|
+
* namespaced under `elements/<sessionId>-<ISO>-<ref>` to match the
|
|
47
|
+
* archive subdir-per-artefact convention. */
|
|
48
|
+
export function defaultElementExportPath(sessionId, ref, format) {
|
|
49
|
+
const safeSession = sessionId.replace(/[^A-Za-z0-9._-]/g, "_") || "default";
|
|
50
|
+
const safeRef = ref.replace(/[^A-Za-z0-9._-]/g, "_") || "el";
|
|
51
|
+
const ts = new Date().toISOString().replace(/[:.]/g, "-");
|
|
52
|
+
const stem = `elements/${safeSession}-${ts}-${safeRef}`;
|
|
53
|
+
return format === "single-file" ? `${stem}.html` : stem;
|
|
54
|
+
}
|
|
55
|
+
const CSP_HINTS = ["connect-src", "refused to connect", "content security policy"];
|
|
56
|
+
/** Classify one fetched resource against the per-resource + total budget,
|
|
57
|
+
* mutating the running totals. Returns the (possibly budget-rejected) entry. */
|
|
58
|
+
function classifyFetched(f, maxBytes, phase) {
|
|
59
|
+
if (!f.r.ok) {
|
|
60
|
+
const err = (f.r.error ?? "").toLowerCase();
|
|
61
|
+
if (CSP_HINTS.some((h) => err.includes(h)))
|
|
62
|
+
phase.cspBlocked++;
|
|
63
|
+
return f;
|
|
64
|
+
}
|
|
65
|
+
const bytes = f.r.bytes ?? 0;
|
|
66
|
+
if (bytes > PER_RESOURCE_HARD_MB * 1024 * 1024) {
|
|
67
|
+
phase.perResourceOversize++;
|
|
68
|
+
return {
|
|
69
|
+
res: f.res,
|
|
70
|
+
r: { ok: false, error: `resource exceeded per-resource cap (${PER_RESOURCE_HARD_MB} MB)` },
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
if (phase.runningBytes + bytes > maxBytes) {
|
|
74
|
+
phase.budgetExhausted = true;
|
|
75
|
+
return { res: f.res, r: { ok: false, error: "size budget exhausted" } };
|
|
76
|
+
}
|
|
77
|
+
phase.runningBytes += bytes;
|
|
78
|
+
return f;
|
|
79
|
+
}
|
|
80
|
+
/** Fetch the discovered resources in bounded concurrency batches, applying the
|
|
81
|
+
* per-resource + total size budgets. Stops early once the budget is exhausted
|
|
82
|
+
* (the remaining resources are recorded as dropped). */
|
|
83
|
+
async function fetchElementResources(page, resources, maxBytes) {
|
|
84
|
+
const CONCURRENCY = 6;
|
|
85
|
+
const phase = {
|
|
86
|
+
fetched: [],
|
|
87
|
+
cspBlocked: 0,
|
|
88
|
+
perResourceOversize: 0,
|
|
89
|
+
runningBytes: 0,
|
|
90
|
+
budgetExhausted: false,
|
|
91
|
+
};
|
|
92
|
+
for (let i = 0; i < resources.length; i += CONCURRENCY) {
|
|
93
|
+
const settled = await Promise.all(resources.slice(i, i + CONCURRENCY).map(async (res) => {
|
|
94
|
+
try {
|
|
95
|
+
return { res, r: (await page.evaluate(buildFetchScript(res.url))) };
|
|
96
|
+
}
|
|
97
|
+
catch (e) {
|
|
98
|
+
return { res, r: { ok: false, error: e instanceof Error ? e.message : String(e) } };
|
|
99
|
+
}
|
|
100
|
+
}));
|
|
101
|
+
for (const f of settled)
|
|
102
|
+
phase.fetched.push(classifyFetched(f, maxBytes, phase));
|
|
103
|
+
if (phase.budgetExhausted) {
|
|
104
|
+
for (let j = i + CONCURRENCY; j < resources.length; j++) {
|
|
105
|
+
phase.fetched.push({
|
|
106
|
+
res: resources[j],
|
|
107
|
+
r: { ok: false, error: "size budget exhausted" },
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return phase;
|
|
114
|
+
}
|
|
115
|
+
/** Push the post-fetch budget/CSP warnings onto the result warnings. */
|
|
116
|
+
function appendFetchWarnings(phase, maxSizeMb, warnings) {
|
|
117
|
+
if (phase.cspBlocked > 0) {
|
|
118
|
+
warnings.push(`${phase.cspBlocked} resource(s) blocked by the page's Content-Security-Policy ` +
|
|
119
|
+
"(typically `connect-src`). Counted in droppedCount.");
|
|
120
|
+
}
|
|
121
|
+
if (phase.perResourceOversize > 0) {
|
|
122
|
+
warnings.push(`${phase.perResourceOversize} resource(s) exceeded the per-resource ${PER_RESOURCE_HARD_MB} MB cap and were dropped.`);
|
|
123
|
+
}
|
|
124
|
+
if (phase.budgetExhausted) {
|
|
125
|
+
warnings.push(`Export size cap (maxSizeMb=${maxSizeMb}) reached — remaining resources were dropped. ` +
|
|
126
|
+
"Raise `maxSizeMb` to capture more.");
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
/** Emit the multi-file directory export — each fetched asset written under
|
|
130
|
+
* `assets/<kind>/`, the HTML rewritten to point at the relative paths. */
|
|
131
|
+
function emitDirectory(resolved, discovered, fetched, runningBytes) {
|
|
132
|
+
// workspace-rooted (resolveWorkspacePath rejects any escape from BROWX_WORKSPACE).
|
|
133
|
+
mkdirSync(resolved, { recursive: true });
|
|
134
|
+
const assetsRoot = join(resolved, "assets");
|
|
135
|
+
mkdirSync(assetsRoot, { recursive: true });
|
|
136
|
+
let resourceCount = 0;
|
|
137
|
+
let droppedCount = 0;
|
|
138
|
+
const replacements = [];
|
|
139
|
+
for (const f of fetched) {
|
|
140
|
+
if (!f.r.ok || !f.r.base64) {
|
|
141
|
+
droppedCount++;
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
const subdir = subdirForKind(f.res.kind);
|
|
145
|
+
const dir = join(assetsRoot, subdir);
|
|
146
|
+
mkdirSync(dir, { recursive: true });
|
|
147
|
+
const filename = assetFilename(f.res.url, f.res.kind, f.r.contentType ?? "");
|
|
148
|
+
writeFileSync(join(dir, filename), Buffer.from(f.r.base64, "base64"));
|
|
149
|
+
replacements.push({ rawRef: f.res.rawRef, replacement: `assets/${subdir}/${filename}` });
|
|
150
|
+
resourceCount++;
|
|
151
|
+
}
|
|
152
|
+
const standalone = wrapStandalone(rewriteHtml(discovered.html, replacements), discovered.css, "");
|
|
153
|
+
writeFileSync(join(resolved, "element.html"), standalone, "utf8");
|
|
154
|
+
let sizeBytes;
|
|
155
|
+
try {
|
|
156
|
+
sizeBytes = directorySize(resolved);
|
|
157
|
+
}
|
|
158
|
+
catch {
|
|
159
|
+
sizeBytes = Buffer.byteLength(standalone, "utf8") + runningBytes;
|
|
160
|
+
}
|
|
161
|
+
return { resourceCount, droppedCount, sizeBytes };
|
|
162
|
+
}
|
|
163
|
+
/** Emit the single-file export — assets inlined as data: URIs in the HTML. */
|
|
164
|
+
function emitSingleFile(resolved, discovered, fetched, warnings) {
|
|
165
|
+
// workspace-rooted: dirname(resolved) is the parent of a BROWX_WORKSPACE-anchored path.
|
|
166
|
+
mkdirSync(dirname(resolved), { recursive: true });
|
|
167
|
+
let resourceCount = 0;
|
|
168
|
+
let droppedCount = 0;
|
|
169
|
+
const replacements = [];
|
|
170
|
+
for (const f of fetched) {
|
|
171
|
+
if (!f.r.ok || !f.r.base64) {
|
|
172
|
+
droppedCount++;
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
const mime = (f.r.contentType ?? "").split(";")[0].trim() || mimeFromKind(f.res.kind);
|
|
176
|
+
replacements.push({ rawRef: f.res.rawRef, replacement: `data:${mime};base64,${f.r.base64}` });
|
|
177
|
+
resourceCount++;
|
|
178
|
+
}
|
|
179
|
+
const standalone = wrapStandalone(rewriteHtml(discovered.html, replacements), discovered.css, "");
|
|
180
|
+
writeFileSync(resolved, standalone, "utf8");
|
|
181
|
+
const sizeBytes = statSync(resolved).size;
|
|
182
|
+
if (sizeBytes > SINGLE_FILE_SOFT_WARN_MB * 1024 * 1024) {
|
|
183
|
+
warnings.push(`single-file export is ${(sizeBytes / 1024 / 1024).toFixed(1)} MB. ` +
|
|
184
|
+
`Browsers commonly struggle past ~${SINGLE_FILE_SOFT_WARN_MB} MB — use \`format:"directory"\` for large subtrees.`);
|
|
185
|
+
}
|
|
186
|
+
return { resourceCount, droppedCount, sizeBytes };
|
|
187
|
+
}
|
|
188
|
+
/** Ensure the locator resolves to a real element; throws a clean message
|
|
189
|
+
* otherwise (count() is fast and avoids a confusing `evaluate` failure). */
|
|
190
|
+
async function assertResolves(locator, ref) {
|
|
191
|
+
let matchCount;
|
|
192
|
+
try {
|
|
193
|
+
matchCount = await locator.count();
|
|
194
|
+
}
|
|
195
|
+
catch (e) {
|
|
196
|
+
throw new Error(`element_export: ref "${ref}" did not resolve — ${e instanceof Error ? e.message : String(e)}`);
|
|
197
|
+
}
|
|
198
|
+
if (matchCount === 0) {
|
|
199
|
+
throw new Error(`element_export: ref "${ref}" did not match any element (re-snapshot the page or pass a fresh ref).`);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
export async function elementExport(page, locator, workspaceRoot, sessionId, args) {
|
|
203
|
+
const format = args.format ?? "directory";
|
|
204
|
+
const maxSizeMb = args.maxSizeMb ?? DEFAULT_MAX_SIZE_MB;
|
|
205
|
+
if (!(maxSizeMb > 0) || maxSizeMb > 10_000) {
|
|
206
|
+
throw new Error(`element_export: maxSizeMb must be in (0, 10000] — got ${maxSizeMb}.`);
|
|
207
|
+
}
|
|
208
|
+
const maxBytes = Math.floor(maxSizeMb * 1024 * 1024);
|
|
209
|
+
const relPath = args.intoDir ?? defaultElementExportPath(sessionId, args.ref, format);
|
|
210
|
+
const resolved = resolveWorkspacePath(workspaceRoot, relPath, "element_export");
|
|
211
|
+
await assertResolves(locator, args.ref);
|
|
212
|
+
// 1. Subtree discovery — outerHTML + page-wide CSS + linked resources.
|
|
213
|
+
const discovered = await locator.evaluate(SUBTREE_DISCOVERY_FN);
|
|
214
|
+
const warnings = [
|
|
215
|
+
"element_export output is UNMASKED — secrets-masking would corrupt the export (literal-substring substitution breaks inline JSON / CSS / binary bytes). Treat the export as sensitive material, same posture as page_archive / dump_storage_state.",
|
|
216
|
+
];
|
|
217
|
+
if (discovered.unreadableStylesheets > 0) {
|
|
218
|
+
warnings.push(`${discovered.unreadableStylesheets} stylesheet(s) were cross-origin without CORS and could not be read into the export. ` +
|
|
219
|
+
"Rules from those sheets that targeted the subtree won't appear in the captured CSS — the snippet may render differently than the source page.");
|
|
220
|
+
}
|
|
221
|
+
// 2. Fetch resources in bounded batches.
|
|
222
|
+
const phase = await fetchElementResources(page, discovered.resources, maxBytes);
|
|
223
|
+
appendFetchWarnings(phase, maxSizeMb, warnings);
|
|
224
|
+
// 3. Emit the export.
|
|
225
|
+
const emit = format === "directory"
|
|
226
|
+
? emitDirectory(resolved, discovered, phase.fetched, phase.runningBytes)
|
|
227
|
+
: emitSingleFile(resolved, discovered, phase.fetched, warnings);
|
|
228
|
+
return {
|
|
229
|
+
ok: true,
|
|
230
|
+
format,
|
|
231
|
+
ref: args.ref,
|
|
232
|
+
path: resolvePath(resolved),
|
|
233
|
+
sizeBytes: emit.sizeBytes,
|
|
234
|
+
resourceCount: emit.resourceCount,
|
|
235
|
+
droppedCount: emit.droppedCount,
|
|
236
|
+
warnings,
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Server-facing helper: resolve a ref through the registry, then call
|
|
241
|
+
* `elementExport`. Lives here so the server.ts call site is a one-liner.
|
|
242
|
+
*/
|
|
243
|
+
export async function elementExportFromRef(page, refs, workspaceRoot, sessionId, args) {
|
|
244
|
+
const locator = locatorFor(page, refs, { ref: args.ref });
|
|
245
|
+
const adapter = {
|
|
246
|
+
count: () => locator.count(),
|
|
247
|
+
evaluate: (fn) => locator.evaluate(fn),
|
|
248
|
+
};
|
|
249
|
+
const pageAdapter = { evaluate: (expr) => page.evaluate(expr) };
|
|
250
|
+
return elementExport(pageAdapter, adapter, workspaceRoot, sessionId, args);
|
|
251
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { BrowserContext, Page } from "playwright-core";
|
|
2
|
+
import type { SafariSessionHandle } from "../engine/index.js";
|
|
3
|
+
import type { ColorScheme, GeolocationCoords, ReducedMotion } from "../session/emulation.js";
|
|
4
|
+
/** The live mutation succeeded; the handler folds the engine state into its
|
|
5
|
+
* `deviceEmulation` bag and renders the standard `applied` envelope. */
|
|
6
|
+
export interface EmulationApplied {
|
|
7
|
+
kind: "applied";
|
|
8
|
+
}
|
|
9
|
+
/** An engine that has no live surface for this knob (Safari). The handler renders
|
|
10
|
+
* `error`/`hint` as the same failure envelope its `catch` produced pre-seam, with
|
|
11
|
+
* no `deviceEmulation` mutation — the override was never applied. */
|
|
12
|
+
export interface EmulationRefusal {
|
|
13
|
+
kind: "refusal";
|
|
14
|
+
error: string;
|
|
15
|
+
hint?: string;
|
|
16
|
+
}
|
|
17
|
+
export type EmulationResult = EmulationApplied | EmulationRefusal;
|
|
18
|
+
/** The live-emulation capability port. One instance wraps one session's engine
|
|
19
|
+
* handle; the methods carry no engine type, so the handlers above this seam are
|
|
20
|
+
* engine-blind. Mirrors the ActionSubstrate / CaptureSubstrate shape. `null`
|
|
21
|
+
* coords clears the geolocation override. */
|
|
22
|
+
export interface EmulationSubstrate {
|
|
23
|
+
readonly engine: string;
|
|
24
|
+
setGeolocation(coords: GeolocationCoords | null): Promise<EmulationResult>;
|
|
25
|
+
setColorScheme(scheme: ColorScheme): Promise<EmulationResult>;
|
|
26
|
+
setReducedMotion(motion: ReducedMotion): Promise<EmulationResult>;
|
|
27
|
+
}
|
|
28
|
+
/** Playwright engines — delegates each live mutation to the existing emulation
|
|
29
|
+
* appliers over the session's context/page (the `context`/`page` thunks capture
|
|
30
|
+
* the session entry, the same per-call access the handlers did before this seam).
|
|
31
|
+
* No behaviour change. */
|
|
32
|
+
export declare class PlaywrightEmulationSubstrate implements EmulationSubstrate {
|
|
33
|
+
private readonly context;
|
|
34
|
+
private readonly page;
|
|
35
|
+
readonly engine: string;
|
|
36
|
+
constructor(context: () => BrowserContext, page: () => Page, engine?: string);
|
|
37
|
+
setGeolocation(coords: GeolocationCoords | null): Promise<EmulationResult>;
|
|
38
|
+
setColorScheme(scheme: ColorScheme): Promise<EmulationResult>;
|
|
39
|
+
setReducedMotion(motion: ReducedMotion): Promise<EmulationResult>;
|
|
40
|
+
}
|
|
41
|
+
/** Safari — no live-emulation surface beyond viewport. safaridriver (WebDriver
|
|
42
|
+
* Classic) has no geolocation / `prefers-color-scheme` / `prefers-reduced-motion`
|
|
43
|
+
* mutator, so all three refuse cleanly here — the gating is in the adapter, not
|
|
44
|
+
* the handler. These handlers had NO Safari branch pre-seam (they threw at
|
|
45
|
+
* `page()` / `context()`); the structured refusal replaces that crash. */
|
|
46
|
+
export declare class SafariEmulationSubstrate implements EmulationSubstrate {
|
|
47
|
+
readonly engine = "safari";
|
|
48
|
+
constructor(_handle: SafariSessionHandle);
|
|
49
|
+
setGeolocation(): Promise<EmulationResult>;
|
|
50
|
+
setColorScheme(): Promise<EmulationResult>;
|
|
51
|
+
setReducedMotion(): Promise<EmulationResult>;
|
|
52
|
+
private refuse;
|
|
53
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
// The EmulationSubstrate interface — the engine-agnostic seam beneath the live
|
|
2
|
+
// device-emulation tools (`set_geolocation` / `set_color_scheme` /
|
|
3
|
+
// `set_reduced_motion`). It is the engine-agnostic emulation seam: a tool handler
|
|
4
|
+
// asks a substrate to mutate ONE live-emulation knob and gets back a universal
|
|
5
|
+
// result; an engine-specific implementation does the work. The handler never
|
|
6
|
+
// names Playwright, safaridriver, or an engine — it calls
|
|
7
|
+
// `emulationFor(e).setColorScheme(scheme)`, the same shape as
|
|
8
|
+
// `actionsFor(e).click(args)` / `captureFor(e).screenshot(req)`.
|
|
9
|
+
//
|
|
10
|
+
// Scope: ONLY the three cross-browser, live-mutator emulation primitives — the
|
|
11
|
+
// ones backed by a Playwright context/page mutator (`context.setGeolocation`,
|
|
12
|
+
// `page.emulateMedia`) that takes effect mid-session. The CDP-only primitives
|
|
13
|
+
// (`set_locale` / `set_timezone` / `set_user_agent`) stay engine-gated through
|
|
14
|
+
// `assertEngineSupports` (they need the raw-CDP escape hatch and have no live
|
|
15
|
+
// off-Chromium setter), and `set_viewport` lives in the ActionSubstrate — none
|
|
16
|
+
// of those are this port's concern.
|
|
17
|
+
//
|
|
18
|
+
// Dependency direction (architecture doctrine §1): tool handler →
|
|
19
|
+
// EmulationSubstrate (this interface) → implementation → Playwright | safaridriver.
|
|
20
|
+
// Two impls today:
|
|
21
|
+
// - PlaywrightEmulationSubstrate (chromium / firefox / webkit / android): wraps
|
|
22
|
+
// the existing `applyGeolocation` / `clearGeolocation` / `applyColorScheme` /
|
|
23
|
+
// `applyReducedMotion` over a Playwright context/page — byte-identical to the
|
|
24
|
+
// pre-seam handler, so the four engines' keystones stay green unchanged. The
|
|
25
|
+
// handler keeps the `deviceEmulation` state mutation + the geolocation-
|
|
26
|
+
// permission warning + the result envelope; the substrate only performs the
|
|
27
|
+
// live mutation.
|
|
28
|
+
// - SafariEmulationSubstrate (safari): safaridriver exposes no live-emulation
|
|
29
|
+
// surface beyond viewport, so all three refuse cleanly IN THE ADAPTER (the
|
|
30
|
+
// gating lives here, not as an `if (e.session.safari?.())` branch in the
|
|
31
|
+
// handlers — these handlers had no Safari branch and threw at `page()` /
|
|
32
|
+
// `context()` before this seam).
|
|
33
|
+
import { applyColorScheme, applyGeolocation, applyReducedMotion, clearGeolocation, } from "../session/emulation.js";
|
|
34
|
+
/** Playwright engines — delegates each live mutation to the existing emulation
|
|
35
|
+
* appliers over the session's context/page (the `context`/`page` thunks capture
|
|
36
|
+
* the session entry, the same per-call access the handlers did before this seam).
|
|
37
|
+
* No behaviour change. */
|
|
38
|
+
export class PlaywrightEmulationSubstrate {
|
|
39
|
+
context;
|
|
40
|
+
page;
|
|
41
|
+
engine;
|
|
42
|
+
constructor(context, page, engine = "chromium") {
|
|
43
|
+
this.context = context;
|
|
44
|
+
this.page = page;
|
|
45
|
+
this.engine = engine;
|
|
46
|
+
}
|
|
47
|
+
async setGeolocation(coords) {
|
|
48
|
+
if (coords === null)
|
|
49
|
+
await clearGeolocation(this.context());
|
|
50
|
+
else
|
|
51
|
+
await applyGeolocation(this.context(), coords);
|
|
52
|
+
return { kind: "applied" };
|
|
53
|
+
}
|
|
54
|
+
async setColorScheme(scheme) {
|
|
55
|
+
await applyColorScheme(this.page(), scheme);
|
|
56
|
+
return { kind: "applied" };
|
|
57
|
+
}
|
|
58
|
+
async setReducedMotion(motion) {
|
|
59
|
+
await applyReducedMotion(this.page(), motion);
|
|
60
|
+
return { kind: "applied" };
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/** Safari — no live-emulation surface beyond viewport. safaridriver (WebDriver
|
|
64
|
+
* Classic) has no geolocation / `prefers-color-scheme` / `prefers-reduced-motion`
|
|
65
|
+
* mutator, so all three refuse cleanly here — the gating is in the adapter, not
|
|
66
|
+
* the handler. These handlers had NO Safari branch pre-seam (they threw at
|
|
67
|
+
* `page()` / `context()`); the structured refusal replaces that crash. */
|
|
68
|
+
export class SafariEmulationSubstrate {
|
|
69
|
+
engine = "safari";
|
|
70
|
+
constructor(_handle) { }
|
|
71
|
+
setGeolocation() {
|
|
72
|
+
return Promise.resolve(this.refuse("set_geolocation"));
|
|
73
|
+
}
|
|
74
|
+
setColorScheme() {
|
|
75
|
+
return Promise.resolve(this.refuse("set_color_scheme"));
|
|
76
|
+
}
|
|
77
|
+
setReducedMotion() {
|
|
78
|
+
return Promise.resolve(this.refuse("set_reduced_motion"));
|
|
79
|
+
}
|
|
80
|
+
refuse(tool) {
|
|
81
|
+
return {
|
|
82
|
+
kind: "refusal",
|
|
83
|
+
error: `\`${tool}\` is not supported on the Safari engine — safaridriver exposes no live-emulation surface beyond viewport.`,
|
|
84
|
+
hint: "Use a chromium, firefox, or webkit session for live geolocation / colour-scheme / reduced-motion overrides.",
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { CDPSession, Page } from "playwright-core";
|
|
2
|
+
/** All fields optional. Empty object == reset. */
|
|
3
|
+
export interface NetworkEmulationInput {
|
|
4
|
+
offline?: boolean;
|
|
5
|
+
/** One-way latency in ms (CDP doubles it for round-trip). */
|
|
6
|
+
latencyMs?: number;
|
|
7
|
+
/** Max download throughput in bytes/sec. 0 / unset → unthrottled. */
|
|
8
|
+
downloadBps?: number;
|
|
9
|
+
/** Max upload throughput in bytes/sec. 0 / unset → unthrottled. */
|
|
10
|
+
uploadBps?: number;
|
|
11
|
+
/** 0..1 — passed straight through (CDP supports it; most chromium builds
|
|
12
|
+
* ignore it but it's documented as a hint). */
|
|
13
|
+
packetLoss?: number;
|
|
14
|
+
}
|
|
15
|
+
export interface CpuEmulationInput {
|
|
16
|
+
/** 1 = no throttle. 2 = 2× slowdown. 4–6 simulates a low-end device. */
|
|
17
|
+
throttleRate?: number;
|
|
18
|
+
}
|
|
19
|
+
export interface NetworkEmulationState {
|
|
20
|
+
offline: boolean;
|
|
21
|
+
latencyMs: number;
|
|
22
|
+
downloadBps: number;
|
|
23
|
+
uploadBps: number;
|
|
24
|
+
packetLoss?: number;
|
|
25
|
+
}
|
|
26
|
+
export interface CpuEmulationState {
|
|
27
|
+
throttleRate: number;
|
|
28
|
+
}
|
|
29
|
+
/** The "no override" defaults — both tools' "reset" calls collapse to this. */
|
|
30
|
+
export declare const DEFAULT_NETWORK: NetworkEmulationState;
|
|
31
|
+
export declare const DEFAULT_CPU: CpuEmulationState;
|
|
32
|
+
/** Per-session emulation cache + re-applier. One per SessionEntry. */
|
|
33
|
+
export declare class EmulationRegistry {
|
|
34
|
+
private network;
|
|
35
|
+
private cpu;
|
|
36
|
+
/** Re-apply hook installed once per page on first use. */
|
|
37
|
+
private reattachInstalled;
|
|
38
|
+
/** Apply network conditions and remember them. Returns the normalized state
|
|
39
|
+
* that's now active. */
|
|
40
|
+
applyNetwork(cdp: CDPSession, page: Page, input: NetworkEmulationInput): Promise<{
|
|
41
|
+
state: NetworkEmulationState;
|
|
42
|
+
reset: boolean;
|
|
43
|
+
}>;
|
|
44
|
+
/** Apply CPU throttling and remember it. */
|
|
45
|
+
applyCpu(cdp: CDPSession, page: Page, input: CpuEmulationInput): Promise<{
|
|
46
|
+
state: CpuEmulationState;
|
|
47
|
+
reset: boolean;
|
|
48
|
+
}>;
|
|
49
|
+
/** Reset both overrides — used by close/teardown paths if needed. */
|
|
50
|
+
resetAll(cdp: CDPSession): Promise<void>;
|
|
51
|
+
/** Test introspection: the currently-cached state, or undefined if not set. */
|
|
52
|
+
currentNetwork(): NetworkEmulationState | undefined;
|
|
53
|
+
currentCpu(): CpuEmulationState | undefined;
|
|
54
|
+
/** Defensive re-apply: CDP overrides are *usually* per-target and survive
|
|
55
|
+
* navigation, but cross-process renderer swaps + incognito teardowns can
|
|
56
|
+
* drop them. Re-push the cached state on every main-frame navigation. */
|
|
57
|
+
private installReattach;
|
|
58
|
+
private sendNetwork;
|
|
59
|
+
private sendCpu;
|
|
60
|
+
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
// Network + CPU emulation — capability `action`.
|
|
2
|
+
//
|
|
3
|
+
// Wraps two CDP primitives so flaky-mobile / offline / low-end-device repros
|
|
4
|
+
// stop requiring a real lab device:
|
|
5
|
+
// - Network.emulateNetworkConditions → `NetworkEmulation`
|
|
6
|
+
// - Emulation.setCPUThrottlingRate → `CpuEmulation`
|
|
7
|
+
//
|
|
8
|
+
// Both are per-target overrides; CDP keeps them applied for the lifetime of
|
|
9
|
+
// the *target*. But a renderer swap (cross-process navigation), a fresh page,
|
|
10
|
+
// or some incognito teardown corners can drop them — so we cache the active
|
|
11
|
+
// state per session and re-apply on `framenavigated` for the main frame.
|
|
12
|
+
// Plays cleanly with `route` / `route_queue`: the route handler's `delayMs`
|
|
13
|
+
// stacks ON TOP of the emulated latency, by design.
|
|
14
|
+
//
|
|
15
|
+
// Reset semantics:
|
|
16
|
+
// - `network_emulate({})` / `{offline:false}` (with no latency/bps/loss) →
|
|
17
|
+
// clears the override (offline=false, latency 0, bps -1, packetLoss 0).
|
|
18
|
+
// - `cpu_emulate({})` / `{throttleRate:1}` → clears the override (rate 1).
|
|
19
|
+
//
|
|
20
|
+
// BYOB note: overrides apply to the attached Chrome's page for as long as
|
|
21
|
+
// CDP holds them. After our session detaches, the human's DevTools Network /
|
|
22
|
+
// Performance panels may still show the throttled state until they reset it
|
|
23
|
+
// or close the page — surfaced as a `warning` on the result.
|
|
24
|
+
/** The "no override" defaults — both tools' "reset" calls collapse to this. */
|
|
25
|
+
export const DEFAULT_NETWORK = {
|
|
26
|
+
offline: false,
|
|
27
|
+
latencyMs: 0,
|
|
28
|
+
downloadBps: 0,
|
|
29
|
+
uploadBps: 0,
|
|
30
|
+
};
|
|
31
|
+
export const DEFAULT_CPU = { throttleRate: 1 };
|
|
32
|
+
const MAX_LATENCY_MS = 600_000;
|
|
33
|
+
const MAX_BPS = 10_000_000_000; // 10 GB/s — generous; really a sanity ceiling
|
|
34
|
+
const MAX_CPU_RATE = 100;
|
|
35
|
+
function clampNonNeg(n, max) {
|
|
36
|
+
if (n === undefined || n === null || !Number.isFinite(n) || n < 0)
|
|
37
|
+
return 0;
|
|
38
|
+
return Math.min(n, max);
|
|
39
|
+
}
|
|
40
|
+
function normalizeNetwork(input) {
|
|
41
|
+
const state = {
|
|
42
|
+
offline: input.offline === true,
|
|
43
|
+
latencyMs: clampNonNeg(input.latencyMs, MAX_LATENCY_MS),
|
|
44
|
+
downloadBps: clampNonNeg(input.downloadBps, MAX_BPS),
|
|
45
|
+
uploadBps: clampNonNeg(input.uploadBps, MAX_BPS),
|
|
46
|
+
};
|
|
47
|
+
if (input.packetLoss !== undefined) {
|
|
48
|
+
if (!Number.isFinite(input.packetLoss) || input.packetLoss < 0 || input.packetLoss > 1) {
|
|
49
|
+
throw new Error(`network_emulate: packetLoss must be between 0 and 1 (got ${input.packetLoss})`);
|
|
50
|
+
}
|
|
51
|
+
state.packetLoss = input.packetLoss;
|
|
52
|
+
}
|
|
53
|
+
return state;
|
|
54
|
+
}
|
|
55
|
+
function normalizeCpu(input) {
|
|
56
|
+
const r = input.throttleRate;
|
|
57
|
+
if (r === undefined || r === null)
|
|
58
|
+
return { throttleRate: 1 };
|
|
59
|
+
if (!Number.isFinite(r) || r < 1 || r > MAX_CPU_RATE) {
|
|
60
|
+
throw new Error(`cpu_emulate: throttleRate must be between 1 and ${MAX_CPU_RATE} (got ${r})`);
|
|
61
|
+
}
|
|
62
|
+
return { throttleRate: r };
|
|
63
|
+
}
|
|
64
|
+
function isNetworkReset(s) {
|
|
65
|
+
return (!s.offline &&
|
|
66
|
+
s.latencyMs === 0 &&
|
|
67
|
+
s.downloadBps === 0 &&
|
|
68
|
+
s.uploadBps === 0 &&
|
|
69
|
+
(s.packetLoss === undefined || s.packetLoss === 0));
|
|
70
|
+
}
|
|
71
|
+
function isCpuReset(s) {
|
|
72
|
+
return s.throttleRate === 1;
|
|
73
|
+
}
|
|
74
|
+
/** Per-session emulation cache + re-applier. One per SessionEntry. */
|
|
75
|
+
export class EmulationRegistry {
|
|
76
|
+
network;
|
|
77
|
+
cpu;
|
|
78
|
+
/** Re-apply hook installed once per page on first use. */
|
|
79
|
+
reattachInstalled = new WeakSet();
|
|
80
|
+
/** Apply network conditions and remember them. Returns the normalized state
|
|
81
|
+
* that's now active. */
|
|
82
|
+
async applyNetwork(cdp, page, input) {
|
|
83
|
+
const state = normalizeNetwork(input);
|
|
84
|
+
await this.sendNetwork(cdp, state);
|
|
85
|
+
this.network = state;
|
|
86
|
+
this.installReattach(page);
|
|
87
|
+
return { state, reset: isNetworkReset(state) };
|
|
88
|
+
}
|
|
89
|
+
/** Apply CPU throttling and remember it. */
|
|
90
|
+
async applyCpu(cdp, page, input) {
|
|
91
|
+
const state = normalizeCpu(input);
|
|
92
|
+
await this.sendCpu(cdp, state);
|
|
93
|
+
this.cpu = state;
|
|
94
|
+
this.installReattach(page);
|
|
95
|
+
return { state, reset: isCpuReset(state) };
|
|
96
|
+
}
|
|
97
|
+
/** Reset both overrides — used by close/teardown paths if needed. */
|
|
98
|
+
async resetAll(cdp) {
|
|
99
|
+
if (this.network && !isNetworkReset(this.network)) {
|
|
100
|
+
await this.sendNetwork(cdp, DEFAULT_NETWORK).catch(() => undefined);
|
|
101
|
+
}
|
|
102
|
+
if (this.cpu && !isCpuReset(this.cpu)) {
|
|
103
|
+
await this.sendCpu(cdp, DEFAULT_CPU).catch(() => undefined);
|
|
104
|
+
}
|
|
105
|
+
this.network = undefined;
|
|
106
|
+
this.cpu = undefined;
|
|
107
|
+
}
|
|
108
|
+
/** Test introspection: the currently-cached state, or undefined if not set. */
|
|
109
|
+
currentNetwork() {
|
|
110
|
+
return this.network;
|
|
111
|
+
}
|
|
112
|
+
currentCpu() {
|
|
113
|
+
return this.cpu;
|
|
114
|
+
}
|
|
115
|
+
/** Defensive re-apply: CDP overrides are *usually* per-target and survive
|
|
116
|
+
* navigation, but cross-process renderer swaps + incognito teardowns can
|
|
117
|
+
* drop them. Re-push the cached state on every main-frame navigation. */
|
|
118
|
+
installReattach(page) {
|
|
119
|
+
if (this.reattachInstalled.has(page))
|
|
120
|
+
return;
|
|
121
|
+
this.reattachInstalled.add(page);
|
|
122
|
+
const onNav = async (frame) => {
|
|
123
|
+
// main frame only
|
|
124
|
+
if (frame.parentFrame())
|
|
125
|
+
return;
|
|
126
|
+
try {
|
|
127
|
+
// re-acquire the CDP session via the page's context — the original
|
|
128
|
+
// session ref may be stale after a renderer swap.
|
|
129
|
+
const cdp = await page
|
|
130
|
+
.context()
|
|
131
|
+
.newCDPSession(page)
|
|
132
|
+
.catch(() => null);
|
|
133
|
+
if (!cdp)
|
|
134
|
+
return;
|
|
135
|
+
if (this.network && !isNetworkReset(this.network)) {
|
|
136
|
+
await this.sendNetwork(cdp, this.network).catch(() => undefined);
|
|
137
|
+
}
|
|
138
|
+
if (this.cpu && !isCpuReset(this.cpu)) {
|
|
139
|
+
await this.sendCpu(cdp, this.cpu).catch(() => undefined);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
// page may have closed mid-navigation; swallow
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
// playwright's framenavigated fires for every frame; we filter inside.
|
|
147
|
+
page.on("framenavigated", onNav);
|
|
148
|
+
}
|
|
149
|
+
async sendNetwork(cdp, s) {
|
|
150
|
+
// CDP wants -1 for "no throttle" on bps fields; map 0 → -1.
|
|
151
|
+
await cdp.send("Network.emulateNetworkConditions", {
|
|
152
|
+
offline: s.offline,
|
|
153
|
+
latency: s.latencyMs,
|
|
154
|
+
downloadThroughput: s.downloadBps > 0 ? s.downloadBps : -1,
|
|
155
|
+
uploadThroughput: s.uploadBps > 0 ? s.uploadBps : -1,
|
|
156
|
+
...(s.packetLoss !== undefined ? { packetLoss: s.packetLoss } : {}),
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
async sendCpu(cdp, s) {
|
|
160
|
+
await cdp.send("Emulation.setCPUThrottlingRate", { rate: s.throttleRate });
|
|
161
|
+
}
|
|
162
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { RecordedStep } from "./recording.js";
|
|
2
|
+
import type { DispatchedAction } from "./actionresult.js";
|
|
3
|
+
export interface LoweredStep {
|
|
4
|
+
/** Source lines for this step — each entry is one line in the emitted file
|
|
5
|
+
* (no trailing newlines). Always wrapped in the test body's indentation
|
|
6
|
+
* by the caller; the lines themselves are flush-left. */
|
|
7
|
+
lines: string[];
|
|
8
|
+
/** True when the step's selector was tier-5 / role-only / otherwise low-
|
|
9
|
+
* confidence at recording time. The caller surfaces this as a TODO
|
|
10
|
+
* comment above the lines. */
|
|
11
|
+
fragile: boolean;
|
|
12
|
+
/** Diagnostic — was this step lowered to a real Playwright call, or to a
|
|
13
|
+
* `// TODO:` placeholder because we don't know how to lower its action
|
|
14
|
+
* type? Drives the result's `unhandled` counter so the agent can see
|
|
15
|
+
* whether the export captured everything. */
|
|
16
|
+
handled: boolean;
|
|
17
|
+
}
|
|
18
|
+
export interface LowerResult {
|
|
19
|
+
/** Complete `.spec.ts` source. Always includes the `@playwright/test`
|
|
20
|
+
* import + a single `test(...)` shell, even when the trace is empty
|
|
21
|
+
* (the body is then just a `// No steps recorded.` placeholder). */
|
|
22
|
+
source: string;
|
|
23
|
+
/** Diagnostics for the caller. */
|
|
24
|
+
stats: {
|
|
25
|
+
steps: number;
|
|
26
|
+
handled: number;
|
|
27
|
+
unhandled: number;
|
|
28
|
+
fragile: number;
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
/** Lower a recorded trace to a Playwright spec source string. Pure; the
|
|
32
|
+
* caller decides whether to write it to disk. */
|
|
33
|
+
export declare function lowerTraceToSpec(flowName: string, steps: ReadonlyArray<RecordedStep>): LowerResult;
|
|
34
|
+
export declare function lowerStep(step: RecordedStep): LoweredStep;
|
|
35
|
+
/** Lower a recorded `selectorHint` into a Playwright locator expression
|
|
36
|
+
* rooted at the `page` identifier. Mirrors `parseSelectorHint` in
|
|
37
|
+
* `./locator.ts`. */
|
|
38
|
+
export declare function locatorExprFor(step: RecordedStep): string;
|
|
39
|
+
/** Pure; exported for unit tests. */
|
|
40
|
+
export declare function locatorExprFromHint(hint: string): string;
|
|
41
|
+
export declare function parseCheck(source: string): {
|
|
42
|
+
ok: true;
|
|
43
|
+
} | {
|
|
44
|
+
ok: false;
|
|
45
|
+
reason: string;
|
|
46
|
+
};
|
|
47
|
+
export type { RecordedStep, DispatchedAction };
|