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,545 @@
|
|
|
1
|
+
// Per-session Web Bluetooth / WebUSB / WebHID device emulation. Sibling of
|
|
2
|
+
// `permission` / `notification` / `fs-picker` — but a posture step further:
|
|
3
|
+
// where those modules govern access to APIs the browser already exposes,
|
|
4
|
+
// this one synthesises *responses* for three powerful platform APIs whose
|
|
5
|
+
// real semantics talk to physical devices the agent doesn't have. The use
|
|
6
|
+
// case is letting agents drive a page that gates a flow behind a Web
|
|
7
|
+
// Bluetooth / WebUSB / WebHID device picker without owning the hardware —
|
|
8
|
+
// the page believes it found and connected to a device because the
|
|
9
|
+
// init-script-wrapped `navigator.bluetooth.requestDevice()` /
|
|
10
|
+
// `navigator.usb.requestDevice()` / `navigator.hid.requestDevice()` resolve
|
|
11
|
+
// with synthetic objects matching the W3C shapes.
|
|
12
|
+
//
|
|
13
|
+
// Why this is its own capability (`device-emulation`, off-by-default):
|
|
14
|
+
// The wrappers tell the page it has access to physical devices that don't
|
|
15
|
+
// exist. A page that scans, names, and pairs against a Bluetooth heart-rate
|
|
16
|
+
// monitor will believe one is present. That's a posture-broadening change
|
|
17
|
+
// distinct from the surrounding policies — those say "the page CAN'T do X
|
|
18
|
+
// (and we record it)"; this one says "the page CAN do X (and we lie about
|
|
19
|
+
// what it found)". Off by default and loud-warned at boot, same posture
|
|
20
|
+
// class as `eval` / `network-body` / `secrets` / `extensions`.
|
|
21
|
+
//
|
|
22
|
+
// What the wrappers cover (v1 scope):
|
|
23
|
+
// - `navigator.bluetooth.requestDevice(options)` →
|
|
24
|
+
// resolves to a synthetic BluetoothDevice (`{ id, name, gatt }`); empty
|
|
25
|
+
// catalog rejects with `NotFoundError` ("User cancelled the requestDevice
|
|
26
|
+
// chooser") — same as the real picker when the human dismisses it.
|
|
27
|
+
// - `navigator.usb.requestDevice(options)` →
|
|
28
|
+
// resolves to a synthetic USBDevice (`{ vendorId, productId, productName,
|
|
29
|
+
// manufacturerName, serialNumber, deviceClass, … }`); empty catalog
|
|
30
|
+
// rejects with `NotFoundError`.
|
|
31
|
+
// - `navigator.hid.requestDevice(options)` →
|
|
32
|
+
// resolves to an Array<HIDDevice> (the HID API is multi-result by
|
|
33
|
+
// construction); empty catalog resolves with `[]` (real HID picker
|
|
34
|
+
// returns `[]` when the user picks nothing).
|
|
35
|
+
//
|
|
36
|
+
// The page-side requestDevice CATALOG (the synthetic device list) is set by
|
|
37
|
+
// the three tools (`emulate_bluetooth` / `emulate_usb` / `emulate_hid`).
|
|
38
|
+
// Calling with `{}` (no `devices`) clears the catalog — the next
|
|
39
|
+
// `requestDevice` rejects (Bluetooth/USB) or returns `[]` (HID), same as a
|
|
40
|
+
// human dismissing the picker. Calling with `{devices:[…]}` installs a new
|
|
41
|
+
// catalog — the next `requestDevice` resolves with the matching synthetic
|
|
42
|
+
// device. The pattern intentionally mirrors `fs_picker_respond`'s "stage
|
|
43
|
+
// the agent-supplied response, let the page's own action trigger the API
|
|
44
|
+
// call" model — the agent doesn't drive a tool when the page calls
|
|
45
|
+
// `requestDevice`; the page does, and the wrapper consults the catalog.
|
|
46
|
+
//
|
|
47
|
+
// What the wrappers DELIBERATELY do not cover (v1):
|
|
48
|
+
// - GATT service emulation for Bluetooth. The synthetic `BluetoothDevice`
|
|
49
|
+
// carries a stub `gatt` with `connect()` resolving to a stub server
|
|
50
|
+
// whose `getPrimaryService()` rejects with `NotFoundError`. A page that
|
|
51
|
+
// only needs the device-picker step to clear (a common pattern in BLE-
|
|
52
|
+
// onboarding flows) works as-is; a page that then exchanges
|
|
53
|
+
// characteristic reads/writes does not. Surfaced as deferred follow-up.
|
|
54
|
+
// - WebUSB transfer endpoints. `USBDevice.open()` / `selectConfiguration()`
|
|
55
|
+
// / `transferIn()` / `transferOut()` are stubs that resolve with empty/
|
|
56
|
+
// zero-byte results. Same justification: enough for picker-clearing.
|
|
57
|
+
// - HID input/output reports. `HIDDevice.open()` resolves; `sendReport()`
|
|
58
|
+
// resolves; `oninputreport` never fires (no synthetic device traffic).
|
|
59
|
+
// - Permission-style `getDevices()` enumeration (the W3C API has a
|
|
60
|
+
// post-permission read-side: `navigator.bluetooth.getDevices()`,
|
|
61
|
+
// `navigator.usb.getDevices()`, `navigator.hid.getDevices()`). v1
|
|
62
|
+
// wraps requestDevice only; getDevices returns the native value (which
|
|
63
|
+
// is `[]` on a Chromium without any granted devices). Surfaced as
|
|
64
|
+
// deferred follow-up.
|
|
65
|
+
//
|
|
66
|
+
// Per-action capture. Every page-side `requestDevice` call is appended to a
|
|
67
|
+
// buffer with a timestamp + the API + the agent-facing outcome (`resolved`
|
|
68
|
+
// / `rejected` / `empty`). `device_requests({session})` is the read-side
|
|
69
|
+
// view — separate from `ActionResult`'s policy-failure flips because
|
|
70
|
+
// `device-emulation` is an opt-in capability (you don't get a no-op-flips-
|
|
71
|
+
// ActionResult.ok footgun from a capability you explicitly enabled).
|
|
72
|
+
import { log } from "../util/logging.js";
|
|
73
|
+
import { PolicyRecordBuffer } from "./policy-buffer.js";
|
|
74
|
+
/** The three Web platform APIs browxai's device-emulation governs. */
|
|
75
|
+
export const SUPPORTED_DEVICE_APIS = ["bluetooth", "usb", "hid"];
|
|
76
|
+
/** Mutable per-session state. The page-side wrapper consults `catalog(api)`
|
|
77
|
+
* via the bridge binding on every `requestDevice` call, so a `set` call
|
|
78
|
+
* takes effect on the very next page-side request without a navigation. */
|
|
79
|
+
export class DeviceEmulationState {
|
|
80
|
+
/** Per-API catalog. Empty list (or absent entry) → wrapper falls into
|
|
81
|
+
* the user-dismissed-picker shape for that API. */
|
|
82
|
+
catalogs = {
|
|
83
|
+
bluetooth: { devices: [] },
|
|
84
|
+
usb: { devices: [] },
|
|
85
|
+
hid: { devices: [] },
|
|
86
|
+
};
|
|
87
|
+
/** Captured `requestDevice` calls — a bounded record ring (shared
|
|
88
|
+
* `PolicyRecordBuffer`; chatty pages can't grow this without bound,
|
|
89
|
+
* `device_requests` slices on `since`). */
|
|
90
|
+
records;
|
|
91
|
+
/** Contexts we've already installed the init-script + binding on.
|
|
92
|
+
* Idempotent install guard — BYOB reconnect / context rebuild MUST not
|
|
93
|
+
* double-wire. */
|
|
94
|
+
wired = new WeakSet();
|
|
95
|
+
/** True iff `device-emulation` capability was on at the time of attach.
|
|
96
|
+
* The page-side wrapper installs regardless (so a runtime capability
|
|
97
|
+
* toggle that adds the cap takes effect — though the canonical
|
|
98
|
+
* resolve-once-at-boot model means it doesn't), but the check binding
|
|
99
|
+
* short-circuits to `refused` when off. */
|
|
100
|
+
enabledByCapability;
|
|
101
|
+
constructor(enabledByCapability, cap = 200) {
|
|
102
|
+
this.enabledByCapability = enabledByCapability;
|
|
103
|
+
this.records = new PolicyRecordBuffer(cap);
|
|
104
|
+
}
|
|
105
|
+
/** Snapshot of one API's catalog. */
|
|
106
|
+
catalog(api) {
|
|
107
|
+
return { devices: [...this.catalogs[api].devices] };
|
|
108
|
+
}
|
|
109
|
+
/** Replace one API's catalog. `devices` may be empty (clears the catalog —
|
|
110
|
+
* next requestDevice rejects/empty). Returns the resolved catalog
|
|
111
|
+
* (echoed back so the tool's response shows what the wrapper will
|
|
112
|
+
* serve). */
|
|
113
|
+
set(api, devices) {
|
|
114
|
+
if (!Array.isArray(devices)) {
|
|
115
|
+
throw new Error(`emulate_${api}: \`devices\` must be an array (pass [] to clear the catalog)`);
|
|
116
|
+
}
|
|
117
|
+
// Normalise each entry: every field is optional on the agent side, but
|
|
118
|
+
// the page-side script needs deterministic defaults to compose a
|
|
119
|
+
// synthetic device object the page won't trip on.
|
|
120
|
+
this.catalogs[api] = {
|
|
121
|
+
devices: devices.map((d, i) => normaliseDevice(api, d, i)),
|
|
122
|
+
};
|
|
123
|
+
return this.catalog(api);
|
|
124
|
+
}
|
|
125
|
+
/** Append a request record. Caps the buffer at `cap`. */
|
|
126
|
+
record(rec) {
|
|
127
|
+
this.records.record(rec);
|
|
128
|
+
}
|
|
129
|
+
/** Slice records with `ts >= since`. Default since=0 returns all. */
|
|
130
|
+
since(since = 0) {
|
|
131
|
+
return this.records.since(since);
|
|
132
|
+
}
|
|
133
|
+
/** Capability gate snapshot. The check binding consults this on every
|
|
134
|
+
* page-side request. */
|
|
135
|
+
capabilityEnabled() {
|
|
136
|
+
return this.enabledByCapability;
|
|
137
|
+
}
|
|
138
|
+
/** Has this context already been wired? Idempotent install guard. */
|
|
139
|
+
hasContext(c) {
|
|
140
|
+
return this.wired.has(c);
|
|
141
|
+
}
|
|
142
|
+
/** Mark a context as wired. */
|
|
143
|
+
markContext(c) {
|
|
144
|
+
this.wired.add(c);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
/** Default field values per API. Each tool call defaults missing fields so
|
|
148
|
+
* the page sees a complete synthetic device shape regardless of how
|
|
149
|
+
* sparsely the agent populated it. */
|
|
150
|
+
function normaliseDevice(api, d, index) {
|
|
151
|
+
const out = {
|
|
152
|
+
name: d.name ?? "browxai-virtual",
|
|
153
|
+
id: d.id ?? `browxai-${api}-${index}`,
|
|
154
|
+
vendorId: d.vendorId ?? 0x0000,
|
|
155
|
+
productId: d.productId ?? 0x0000,
|
|
156
|
+
manufacturerName: d.manufacturerName ?? "browxai virtual",
|
|
157
|
+
serialNumber: d.serialNumber ?? "BROWX-VIRTUAL",
|
|
158
|
+
deviceClass: d.deviceClass ?? 0xff,
|
|
159
|
+
deviceSubclass: d.deviceSubclass ?? 0x00,
|
|
160
|
+
deviceProtocol: d.deviceProtocol ?? 0x00,
|
|
161
|
+
services: d.services ?? [],
|
|
162
|
+
collections: d.collections ?? [],
|
|
163
|
+
};
|
|
164
|
+
return out;
|
|
165
|
+
}
|
|
166
|
+
/** Capture-safe stringify with a 4KB ceiling. Filters from a Web Bluetooth
|
|
167
|
+
* `requestDevice` call are typically a few hundred bytes (filter array
|
|
168
|
+
* with a couple of service UUIDs); we truncate aggressively only to defend
|
|
169
|
+
* the buffer from a chatty page composing absurd filters. */
|
|
170
|
+
function safeFilters(raw) {
|
|
171
|
+
try {
|
|
172
|
+
const s = JSON.stringify(raw);
|
|
173
|
+
if (s.length <= 4096)
|
|
174
|
+
return raw;
|
|
175
|
+
return JSON.parse(s.slice(0, 4096) + '"…"}'); // best-effort
|
|
176
|
+
}
|
|
177
|
+
catch {
|
|
178
|
+
return undefined;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
/** BYOB warning — the init-script wrappers patch every new document in the
|
|
182
|
+
* attached Chrome's session-isolated context; the patches do NOT escape
|
|
183
|
+
* the context, but the per-deployment posture (the operator's main Chrome
|
|
184
|
+
* running with `--remote-debugging-port`) magnifies the consequences of a
|
|
185
|
+
* page that the agent told "you have a hardware device". Surfaced when
|
|
186
|
+
* `open_session({mode:"attached"})` engages with `device-emulation` on. */
|
|
187
|
+
export const BYOB_DEVICE_EMU_WARNING = "BYOB caveat: device-emulation wrappers patch `navigator.bluetooth` / `navigator.usb` / `navigator.hid` " +
|
|
188
|
+
"on an attached (not-owned) Chrome session. The wrappers are scoped to the context browxai opened, " +
|
|
189
|
+
"but the operator's main Chrome shares the same browser binary; treat any page reached during the " +
|
|
190
|
+
"session as having believed the synthetic catalog while it was set. Clearing the catalog (`emulate_*({devices:[]})`) " +
|
|
191
|
+
"restores the user-dismissed-picker shape on the next requestDevice; the wrapper itself stays installed " +
|
|
192
|
+
"for the life of the context.";
|
|
193
|
+
/** Init script that wraps the three Web platform device-picker APIs. Each
|
|
194
|
+
* wrapper consults `window.__browx_device_check({api, filters?})` (the
|
|
195
|
+
* exposeBinding from the server side) on every page-side `requestDevice`
|
|
196
|
+
* call — the binding returns a `{decision, devices?}` envelope the wrapper
|
|
197
|
+
* unpacks into the API-specific shape the spec expects. Keep browser-only
|
|
198
|
+
* JS (no TS-only syntax). Re-injected on `framenavigated` (idempotent:
|
|
199
|
+
* guards on `window.__browx_device_emu_installed`). */
|
|
200
|
+
export const DEVICE_EMU_PAGE_SCRIPT = `(() => {
|
|
201
|
+
if (window.__browx_device_emu_installed) return;
|
|
202
|
+
window.__browx_device_emu_installed = true;
|
|
203
|
+
|
|
204
|
+
function check(api, filters) {
|
|
205
|
+
try {
|
|
206
|
+
if (typeof window.__browx_device_check === "function") {
|
|
207
|
+
return Promise.resolve(window.__browx_device_check(JSON.stringify({
|
|
208
|
+
api: api,
|
|
209
|
+
filters: filters == null ? null : safeFilters(filters),
|
|
210
|
+
})));
|
|
211
|
+
}
|
|
212
|
+
} catch (_) {}
|
|
213
|
+
// Binding missing — safe-by-default empty catalog so the page sees the
|
|
214
|
+
// user-dismissed shape rather than a hung promise.
|
|
215
|
+
return Promise.resolve(JSON.stringify({ decision: "refused", devices: [] }));
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function safeFilters(f) {
|
|
219
|
+
// Defensive shallow clone — page may pass non-serialisable garbage
|
|
220
|
+
// (BigInt, function, circular). Best-effort.
|
|
221
|
+
try { return JSON.parse(JSON.stringify(f)); } catch (_) { return null; }
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function notFound(msg) {
|
|
225
|
+
var e = new Error(msg || "User cancelled the requestDevice() chooser.");
|
|
226
|
+
try { e.name = "NotFoundError"; } catch (_) {}
|
|
227
|
+
return e;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function parseResponse(raw) {
|
|
231
|
+
try {
|
|
232
|
+
var r = typeof raw === "string" ? JSON.parse(raw) : (raw || {});
|
|
233
|
+
var decision = r.decision;
|
|
234
|
+
var devices = Array.isArray(r.devices) ? r.devices : [];
|
|
235
|
+
return { decision: decision, devices: devices };
|
|
236
|
+
} catch (_) {
|
|
237
|
+
return { decision: "refused", devices: [] };
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// ---- Bluetooth -------------------------------------------------------
|
|
242
|
+
// Synthesise the minimal BluetoothDevice + BluetoothRemoteGATTServer
|
|
243
|
+
// surface modern BLE-onboarding flows touch: id / name / gatt.connect()
|
|
244
|
+
// → stub server whose getPrimaryService() rejects (no GATT emulation in
|
|
245
|
+
// v1). Pages that gate on "we found a device" pass; pages that go on to
|
|
246
|
+
// exchange characteristic data do not.
|
|
247
|
+
function syntheticBluetoothDevice(spec) {
|
|
248
|
+
var name = spec.name || "browxai-virtual";
|
|
249
|
+
var id = spec.id || "browxai-bt-0";
|
|
250
|
+
var services = Array.isArray(spec.services) ? spec.services : [];
|
|
251
|
+
var device;
|
|
252
|
+
var gatt = {
|
|
253
|
+
get connected() { return gatt.__connected; },
|
|
254
|
+
__connected: false,
|
|
255
|
+
device: null, // set after device is created (circular ref)
|
|
256
|
+
connect: function () {
|
|
257
|
+
gatt.__connected = true;
|
|
258
|
+
return Promise.resolve(gatt);
|
|
259
|
+
},
|
|
260
|
+
disconnect: function () { gatt.__connected = false; },
|
|
261
|
+
getPrimaryService: function () {
|
|
262
|
+
return Promise.reject(notFound("GATT service emulation not supported in browxai v1"));
|
|
263
|
+
},
|
|
264
|
+
getPrimaryServices: function () {
|
|
265
|
+
return Promise.reject(notFound("GATT service emulation not supported in browxai v1"));
|
|
266
|
+
},
|
|
267
|
+
};
|
|
268
|
+
device = {
|
|
269
|
+
id: id,
|
|
270
|
+
name: name,
|
|
271
|
+
uuids: services,
|
|
272
|
+
gatt: gatt,
|
|
273
|
+
// EventTarget stubs — pages sometimes attach gattserverdisconnected;
|
|
274
|
+
// we accept and ignore.
|
|
275
|
+
addEventListener: function () {},
|
|
276
|
+
removeEventListener: function () {},
|
|
277
|
+
dispatchEvent: function () { return true; },
|
|
278
|
+
watchAdvertisements: function () { return Promise.resolve(undefined); },
|
|
279
|
+
unwatchAdvertisements: function () {},
|
|
280
|
+
get watchingAdvertisements() { return false; },
|
|
281
|
+
// forget() — modern API for revoking the permission; resolves no-op.
|
|
282
|
+
forget: function () { return Promise.resolve(undefined); },
|
|
283
|
+
};
|
|
284
|
+
gatt.device = device;
|
|
285
|
+
return device;
|
|
286
|
+
}
|
|
287
|
+
try {
|
|
288
|
+
var bt = navigator.bluetooth;
|
|
289
|
+
if (bt && typeof bt.requestDevice === "function") {
|
|
290
|
+
// Replace the entire requestDevice; we intentionally do NOT call
|
|
291
|
+
// through to the native API even when the agent didn't stage a
|
|
292
|
+
// catalog — calling through on a headless Chromium often hangs the
|
|
293
|
+
// promise indefinitely (no picker UI to dismiss).
|
|
294
|
+
Object.defineProperty(bt, "requestDevice", {
|
|
295
|
+
configurable: true,
|
|
296
|
+
writable: true,
|
|
297
|
+
value: function (options) {
|
|
298
|
+
var filters = options || null;
|
|
299
|
+
return check("bluetooth", filters).then(function (raw) {
|
|
300
|
+
var r = parseResponse(raw);
|
|
301
|
+
if (!r.devices.length) {
|
|
302
|
+
throw notFound();
|
|
303
|
+
}
|
|
304
|
+
return syntheticBluetoothDevice(r.devices[0]);
|
|
305
|
+
});
|
|
306
|
+
},
|
|
307
|
+
});
|
|
308
|
+
// getDevices — read-side: pre-paired devices. v1 returns the live
|
|
309
|
+
// catalog so a page polling for an already-paired device sees one.
|
|
310
|
+
if (typeof bt.getDevices === "function") {
|
|
311
|
+
Object.defineProperty(bt, "getDevices", {
|
|
312
|
+
configurable: true,
|
|
313
|
+
writable: true,
|
|
314
|
+
value: function () {
|
|
315
|
+
return check("bluetooth", null).then(function (raw) {
|
|
316
|
+
var r = parseResponse(raw);
|
|
317
|
+
return r.devices.map(syntheticBluetoothDevice);
|
|
318
|
+
});
|
|
319
|
+
},
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
} catch (_) {}
|
|
324
|
+
|
|
325
|
+
// ---- WebUSB ----------------------------------------------------------
|
|
326
|
+
// USBDevice synthesises the picker-resolve surface + stub
|
|
327
|
+
// open/close/selectConfiguration; transferIn/transferOut resolve with
|
|
328
|
+
// zero-byte responses so a page sequence doesn't reject mid-flight, but
|
|
329
|
+
// there's no actual data flow.
|
|
330
|
+
function syntheticUSBDevice(spec) {
|
|
331
|
+
var name = spec.name || "browxai-virtual";
|
|
332
|
+
return {
|
|
333
|
+
vendorId: spec.vendorId || 0,
|
|
334
|
+
productId: spec.productId || 0,
|
|
335
|
+
productName: name,
|
|
336
|
+
manufacturerName: spec.manufacturerName || "browxai virtual",
|
|
337
|
+
serialNumber: spec.serialNumber || "BROWX-VIRTUAL",
|
|
338
|
+
deviceClass: spec.deviceClass != null ? spec.deviceClass : 0xFF,
|
|
339
|
+
deviceSubclass: spec.deviceSubclass || 0,
|
|
340
|
+
deviceProtocol: spec.deviceProtocol || 0,
|
|
341
|
+
usbVersionMajor: 2,
|
|
342
|
+
usbVersionMinor: 0,
|
|
343
|
+
usbVersionSubminor: 0,
|
|
344
|
+
deviceVersionMajor: 1,
|
|
345
|
+
deviceVersionMinor: 0,
|
|
346
|
+
deviceVersionSubminor: 0,
|
|
347
|
+
configuration: null,
|
|
348
|
+
configurations: [],
|
|
349
|
+
opened: false,
|
|
350
|
+
open: function () { this.opened = true; return Promise.resolve(undefined); },
|
|
351
|
+
close: function () { this.opened = false; return Promise.resolve(undefined); },
|
|
352
|
+
selectConfiguration: function () { return Promise.resolve(undefined); },
|
|
353
|
+
claimInterface: function () { return Promise.resolve(undefined); },
|
|
354
|
+
releaseInterface: function () { return Promise.resolve(undefined); },
|
|
355
|
+
selectAlternateInterface: function () { return Promise.resolve(undefined); },
|
|
356
|
+
controlTransferIn: function () { return Promise.resolve({ data: new DataView(new ArrayBuffer(0)), status: "ok" }); },
|
|
357
|
+
controlTransferOut: function () { return Promise.resolve({ bytesWritten: 0, status: "ok" }); },
|
|
358
|
+
clearHalt: function () { return Promise.resolve(undefined); },
|
|
359
|
+
transferIn: function () { return Promise.resolve({ data: new DataView(new ArrayBuffer(0)), status: "ok" }); },
|
|
360
|
+
transferOut: function () { return Promise.resolve({ bytesWritten: 0, status: "ok" }); },
|
|
361
|
+
isochronousTransferIn: function () { return Promise.resolve({ data: new DataView(new ArrayBuffer(0)), packets: [] }); },
|
|
362
|
+
isochronousTransferOut: function () { return Promise.resolve({ packets: [] }); },
|
|
363
|
+
reset: function () { return Promise.resolve(undefined); },
|
|
364
|
+
forget: function () { return Promise.resolve(undefined); },
|
|
365
|
+
};
|
|
366
|
+
}
|
|
367
|
+
try {
|
|
368
|
+
var usb = navigator.usb;
|
|
369
|
+
if (usb && typeof usb.requestDevice === "function") {
|
|
370
|
+
Object.defineProperty(usb, "requestDevice", {
|
|
371
|
+
configurable: true,
|
|
372
|
+
writable: true,
|
|
373
|
+
value: function (options) {
|
|
374
|
+
var filters = options || null;
|
|
375
|
+
return check("usb", filters).then(function (raw) {
|
|
376
|
+
var r = parseResponse(raw);
|
|
377
|
+
if (!r.devices.length) {
|
|
378
|
+
throw notFound();
|
|
379
|
+
}
|
|
380
|
+
return syntheticUSBDevice(r.devices[0]);
|
|
381
|
+
});
|
|
382
|
+
},
|
|
383
|
+
});
|
|
384
|
+
if (typeof usb.getDevices === "function") {
|
|
385
|
+
Object.defineProperty(usb, "getDevices", {
|
|
386
|
+
configurable: true,
|
|
387
|
+
writable: true,
|
|
388
|
+
value: function () {
|
|
389
|
+
return check("usb", null).then(function (raw) {
|
|
390
|
+
var r = parseResponse(raw);
|
|
391
|
+
return r.devices.map(syntheticUSBDevice);
|
|
392
|
+
});
|
|
393
|
+
},
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
} catch (_) {}
|
|
398
|
+
|
|
399
|
+
// ---- WebHID ----------------------------------------------------------
|
|
400
|
+
// HIDDevice differs from USB in two ways the wrapper preserves:
|
|
401
|
+
// - requestDevice resolves to an Array<HIDDevice>, NOT a single
|
|
402
|
+
// device (even when only one match — see W3C spec).
|
|
403
|
+
// - Empty result is the user-dismissed shape, NOT a rejection.
|
|
404
|
+
function syntheticHIDDevice(spec) {
|
|
405
|
+
var name = spec.name || "browxai-virtual";
|
|
406
|
+
return {
|
|
407
|
+
opened: false,
|
|
408
|
+
vendorId: spec.vendorId || 0,
|
|
409
|
+
productId: spec.productId || 0,
|
|
410
|
+
productName: name,
|
|
411
|
+
collections: Array.isArray(spec.collections) ? spec.collections : [],
|
|
412
|
+
open: function () { this.opened = true; return Promise.resolve(undefined); },
|
|
413
|
+
close: function () { this.opened = false; return Promise.resolve(undefined); },
|
|
414
|
+
forget: function () { return Promise.resolve(undefined); },
|
|
415
|
+
sendReport: function () { return Promise.resolve(undefined); },
|
|
416
|
+
sendFeatureReport: function () { return Promise.resolve(undefined); },
|
|
417
|
+
receiveFeatureReport: function () { return Promise.resolve(new DataView(new ArrayBuffer(0))); },
|
|
418
|
+
addEventListener: function () {},
|
|
419
|
+
removeEventListener: function () {},
|
|
420
|
+
dispatchEvent: function () { return true; },
|
|
421
|
+
oninputreport: null,
|
|
422
|
+
};
|
|
423
|
+
}
|
|
424
|
+
try {
|
|
425
|
+
var hid = navigator.hid;
|
|
426
|
+
if (hid && typeof hid.requestDevice === "function") {
|
|
427
|
+
Object.defineProperty(hid, "requestDevice", {
|
|
428
|
+
configurable: true,
|
|
429
|
+
writable: true,
|
|
430
|
+
value: function (options) {
|
|
431
|
+
var filters = options || null;
|
|
432
|
+
return check("hid", filters).then(function (raw) {
|
|
433
|
+
var r = parseResponse(raw);
|
|
434
|
+
return r.devices.map(syntheticHIDDevice);
|
|
435
|
+
});
|
|
436
|
+
},
|
|
437
|
+
});
|
|
438
|
+
if (typeof hid.getDevices === "function") {
|
|
439
|
+
Object.defineProperty(hid, "getDevices", {
|
|
440
|
+
configurable: true,
|
|
441
|
+
writable: true,
|
|
442
|
+
value: function () {
|
|
443
|
+
return check("hid", null).then(function (raw) {
|
|
444
|
+
var r = parseResponse(raw);
|
|
445
|
+
return r.devices.map(syntheticHIDDevice);
|
|
446
|
+
});
|
|
447
|
+
},
|
|
448
|
+
});
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
} catch (_) {}
|
|
452
|
+
})();`;
|
|
453
|
+
/** Server-side wire-up. Installs:
|
|
454
|
+
* - `__browx_device_check` exposeBinding: page-side `requestDevice` calls
|
|
455
|
+
* route here; we read the catalog for the requested API, record the
|
|
456
|
+
* call, and return `{decision, devices}`. `decision` is informational
|
|
457
|
+
* (the page-side wrapper consults `devices.length` to pick the
|
|
458
|
+
* spec-correct empty-result shape per API).
|
|
459
|
+
* - The page-side init script (re-injected by Playwright on every new
|
|
460
|
+
* document).
|
|
461
|
+
*
|
|
462
|
+
* Idempotent on the same context. Errors during install are logged and
|
|
463
|
+
* swallowed — the page-side wrapper falls back to "decision: refused,
|
|
464
|
+
* devices: []" when the binding is missing, so a page calling
|
|
465
|
+
* requestDevice never deadlocks.
|
|
466
|
+
*/
|
|
467
|
+
export async function attachDeviceEmulation(context, state) {
|
|
468
|
+
if (state.hasContext(context))
|
|
469
|
+
return;
|
|
470
|
+
state.markContext(context);
|
|
471
|
+
try {
|
|
472
|
+
await context.exposeBinding("__browx_device_check", (_source, payload) => {
|
|
473
|
+
try {
|
|
474
|
+
const o = JSON.parse(payload);
|
|
475
|
+
const api = o.api;
|
|
476
|
+
if (!SUPPORTED_DEVICE_APIS.includes(api)) {
|
|
477
|
+
return JSON.stringify({ decision: "refused", devices: [] });
|
|
478
|
+
}
|
|
479
|
+
const ts = Date.now();
|
|
480
|
+
const filters = safeFilters(o.filters ?? null);
|
|
481
|
+
// Capability is off → refuse: page-side wrapper still resolves
|
|
482
|
+
// to the user-dismissed shape (Bluetooth/USB reject; HID returns
|
|
483
|
+
// []), but we record the call so `device_requests` shows "the
|
|
484
|
+
// page asked for hardware and you didn't have the capability on".
|
|
485
|
+
if (!state.capabilityEnabled()) {
|
|
486
|
+
state.record({
|
|
487
|
+
api,
|
|
488
|
+
handledAs: "refused",
|
|
489
|
+
returned: 0,
|
|
490
|
+
ts,
|
|
491
|
+
...(filters !== undefined && filters !== null ? { filters } : {}),
|
|
492
|
+
});
|
|
493
|
+
return JSON.stringify({ decision: "refused", devices: [] });
|
|
494
|
+
}
|
|
495
|
+
const cat = state.catalog(api);
|
|
496
|
+
const devices = cat.devices;
|
|
497
|
+
const handledAs = devices.length > 0 ? "resolved" : api === "hid" ? "empty" : "rejected";
|
|
498
|
+
const returned = api === "hid" ? devices.length : devices.length > 0 ? 1 : 0;
|
|
499
|
+
state.record({
|
|
500
|
+
api,
|
|
501
|
+
handledAs,
|
|
502
|
+
returned,
|
|
503
|
+
ts,
|
|
504
|
+
...(filters !== undefined && filters !== null ? { filters } : {}),
|
|
505
|
+
});
|
|
506
|
+
// Bluetooth/USB are single-result picker APIs: the page-side
|
|
507
|
+
// wrapper expects to find devices[0] in the response and rejects
|
|
508
|
+
// when the list is empty. HID is multi-result: empty resolves
|
|
509
|
+
// with []. We pass the catalog verbatim; the wrapper knows the
|
|
510
|
+
// shape.
|
|
511
|
+
const responseDevices = api === "hid" ? devices : devices.slice(0, 1);
|
|
512
|
+
return JSON.stringify({ decision: handledAs, devices: responseDevices });
|
|
513
|
+
}
|
|
514
|
+
catch (err) {
|
|
515
|
+
log.warn("session.device-emu: check handler error", {
|
|
516
|
+
error: err instanceof Error ? err.message : String(err),
|
|
517
|
+
});
|
|
518
|
+
return JSON.stringify({ decision: "refused", devices: [] });
|
|
519
|
+
}
|
|
520
|
+
});
|
|
521
|
+
}
|
|
522
|
+
catch (err) {
|
|
523
|
+
log.warn("session.device-emu: exposeBinding install failed; page-side wrapper falls back to refused", {
|
|
524
|
+
error: err instanceof Error ? err.message : String(err),
|
|
525
|
+
});
|
|
526
|
+
}
|
|
527
|
+
try {
|
|
528
|
+
await context.addInitScript({ content: DEVICE_EMU_PAGE_SCRIPT });
|
|
529
|
+
for (const page of context.pages()) {
|
|
530
|
+
await page.evaluate(DEVICE_EMU_PAGE_SCRIPT).catch(() => undefined);
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
catch (err) {
|
|
534
|
+
log.warn("session.device-emu: addInitScript failed", {
|
|
535
|
+
error: err instanceof Error ? err.message : String(err),
|
|
536
|
+
});
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
/** Re-apply the init script to an existing page (no-op when the page-side
|
|
540
|
+
* guard is already set). Used by callers that opened pages BEFORE the
|
|
541
|
+
* attach engaged (rare). Public for tests; production callers go through
|
|
542
|
+
* `attachDeviceEmulation` which handles existing pages too. */
|
|
543
|
+
export async function reinjectDeviceEmuOnPage(page) {
|
|
544
|
+
await page.evaluate(DEVICE_EMU_PAGE_SCRIPT).catch(() => undefined);
|
|
545
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { DeviceConfig } from "./types.js";
|
|
2
|
+
export interface DeviceSpec {
|
|
3
|
+
device?: string;
|
|
4
|
+
viewport?: {
|
|
5
|
+
width: number;
|
|
6
|
+
height: number;
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
export declare class UnknownDeviceError extends Error {
|
|
10
|
+
constructor(name: string, sample: string[]);
|
|
11
|
+
}
|
|
12
|
+
/** Resolve a spec into a DeviceConfig, or undefined when nothing was asked for.
|
|
13
|
+
* Throws UnknownDeviceError for an unrecognised preset name. */
|
|
14
|
+
export declare function resolveDevice(spec: DeviceSpec | undefined): DeviceConfig | undefined;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// resolve a device/viewport spec into a DeviceConfig.
|
|
2
|
+
//
|
|
3
|
+
// Two inputs, either or both:
|
|
4
|
+
// - `device`: a Playwright built-in device preset name ("iPhone 14",
|
|
5
|
+
// "Pixel 7", "Desktop Chrome", …) → viewport + DPR + isMobile + hasTouch
|
|
6
|
+
// + userAgent.
|
|
7
|
+
// - `viewport`: explicit { width, height } — overrides the preset's viewport
|
|
8
|
+
// (lets you pin a custom size while keeping a preset's mobile/touch/UA).
|
|
9
|
+
//
|
|
10
|
+
// Pure + dependency-light: `devices` is a static table from playwright-core.
|
|
11
|
+
import { devices } from "playwright-core";
|
|
12
|
+
export class UnknownDeviceError extends Error {
|
|
13
|
+
constructor(name, sample) {
|
|
14
|
+
super(`unknown device preset "${name}". Examples: ${sample.join(", ")}. ` +
|
|
15
|
+
`Any Playwright device name works (see playwright devices registry).`);
|
|
16
|
+
this.name = "UnknownDeviceError";
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
/** Resolve a spec into a DeviceConfig, or undefined when nothing was asked for.
|
|
20
|
+
* Throws UnknownDeviceError for an unrecognised preset name. */
|
|
21
|
+
export function resolveDevice(spec) {
|
|
22
|
+
if (!spec || (!spec.device && !spec.viewport))
|
|
23
|
+
return undefined;
|
|
24
|
+
let cfg = {};
|
|
25
|
+
if (spec.device) {
|
|
26
|
+
const preset = devices[spec.device];
|
|
27
|
+
if (!preset) {
|
|
28
|
+
const sample = Object.keys(devices)
|
|
29
|
+
.filter((n) => /iPhone 1[34]|Pixel 7|Desktop Chrome/.test(n))
|
|
30
|
+
.slice(0, 4);
|
|
31
|
+
throw new UnknownDeviceError(spec.device, sample.length ? sample : Object.keys(devices).slice(0, 4));
|
|
32
|
+
}
|
|
33
|
+
cfg = {
|
|
34
|
+
viewport: preset.viewport,
|
|
35
|
+
deviceScaleFactor: preset.deviceScaleFactor,
|
|
36
|
+
isMobile: preset.isMobile,
|
|
37
|
+
hasTouch: preset.hasTouch,
|
|
38
|
+
userAgent: preset.userAgent,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
if (spec.viewport)
|
|
42
|
+
cfg = { ...cfg, viewport: spec.viewport };
|
|
43
|
+
return cfg;
|
|
44
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { BrowserContext, Page } from "playwright-core";
|
|
2
|
+
export type DialogMode = "accept" | "dismiss" | "raise" | "accept-prompt-with";
|
|
3
|
+
/** Public, runtime-mutable shape. `mode:"accept-prompt-with"` requires `text`. */
|
|
4
|
+
export interface DialogPolicy {
|
|
5
|
+
mode: DialogMode;
|
|
6
|
+
/** Required for `accept-prompt-with`. Used as the answer for prompts;
|
|
7
|
+
* alert/confirm still accept (no answer needed). */
|
|
8
|
+
text?: string;
|
|
9
|
+
}
|
|
10
|
+
/** One captured dialog event, exposed on `ActionResult.dialogs[]`. */
|
|
11
|
+
export interface DialogRecord {
|
|
12
|
+
kind: "alert" | "confirm" | "prompt" | "beforeunload";
|
|
13
|
+
message: string;
|
|
14
|
+
defaultValue?: string;
|
|
15
|
+
/** What the server actually did. `"raised"` means we dismissed it
|
|
16
|
+
* server-side (to unblock the page) AND the policy was `raise`, so the
|
|
17
|
+
* action will be marked failed. */
|
|
18
|
+
handledAs: "accepted" | "dismissed" | "raised";
|
|
19
|
+
/** epoch ms — used by the action-window slice. */
|
|
20
|
+
ts: number;
|
|
21
|
+
}
|
|
22
|
+
/** Hint emitted on `ActionResult.failure.hint` when `raise` mode fired.
|
|
23
|
+
* Stable, agent-facing string — referenced in docs/tool-reference.md. */
|
|
24
|
+
export declare const UNHANDLED_DIALOG_HINT: string;
|
|
25
|
+
/** Mutable per-session state. The handler reads `current()` on every fire,
|
|
26
|
+
* so a `set_dialog_policy` call takes effect on the very next dialog. */
|
|
27
|
+
export declare class DialogPolicyState {
|
|
28
|
+
private policy;
|
|
29
|
+
/** Bounded record ring (shared `PolicyRecordBuffer` — the hard cap so a chatty
|
|
30
|
+
* page can't grow this without bound; the per-action slice is the only
|
|
31
|
+
* consumer, older records are noise). */
|
|
32
|
+
private readonly records;
|
|
33
|
+
/** Pages we've already installed the handler on. Lets the
|
|
34
|
+
* `context.on('page')` wiring be idempotent — re-attaching to an existing
|
|
35
|
+
* page (BYOB reconnect, profile-restore) doesn't double-fire. */
|
|
36
|
+
private wired;
|
|
37
|
+
constructor(initial?: DialogPolicy, cap?: number);
|
|
38
|
+
current(): DialogPolicy;
|
|
39
|
+
set(next: DialogPolicy): DialogPolicy;
|
|
40
|
+
/** Append a dialog record. Caps the buffer at `cap`. */
|
|
41
|
+
record(rec: DialogRecord): void;
|
|
42
|
+
/** Slice records with `ts >= since`. Used by the action-window. */
|
|
43
|
+
since(since: number): DialogRecord[];
|
|
44
|
+
/** True if any record in `[since, now]` was handled in `raise` mode.
|
|
45
|
+
* When true, the action-window flips the result to `ok:false`. */
|
|
46
|
+
raisedSince(since: number): boolean;
|
|
47
|
+
/** Has this page already been wired? Idempotent install guard. */
|
|
48
|
+
hasPage(p: Page): boolean;
|
|
49
|
+
/** Mark a page as wired. */
|
|
50
|
+
markPage(p: Page): void;
|
|
51
|
+
}
|
|
52
|
+
/** Parse the spec's compact string form (`"accept-prompt-with:<text>"`) into
|
|
53
|
+
* the runtime `DialogPolicy` shape. Idempotent — also accepts the object form. */
|
|
54
|
+
export declare function parseDialogPolicyArg(v: string | DialogPolicy | undefined): DialogPolicy;
|
|
55
|
+
/** Install the `page.on('dialog')` handler on a single page if not already
|
|
56
|
+
* wired. Safe to call repeatedly; no-op when the page is already known. */
|
|
57
|
+
export declare function installDialogHandler(page: Page, state: DialogPolicyState): void;
|
|
58
|
+
/** Wire the dialog handler into every page in a context, plus a `context.on(
|
|
59
|
+
* 'page')` listener that wires future pages. Call once per session-creation;
|
|
60
|
+
* the `context.on('page')` install is idempotent because `installDialogHandler`
|
|
61
|
+
* short-circuits already-wired pages. */
|
|
62
|
+
export declare function attachDialogPolicy(context: BrowserContext, state: DialogPolicyState): void;
|