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,187 @@
|
|
|
1
|
+
// BYOB / CDP-attach primitives — the per-engine attach bodies the engine modules
|
|
2
|
+
// (adapters/<engine>.engine.ts) call from their `makeAdapter` byob branch. Split
|
|
3
|
+
// out of byob.ts so the engine-registration graph (register-engines → the engine
|
|
4
|
+
// modules → here) does NOT cycle back through `byob.ts`'s `openByobSession` (which
|
|
5
|
+
// imports the registry + register-engines for its mode dispatch). Every body here
|
|
6
|
+
// is verbatim from the pre-P1 `openByobSession` chromium/android branches.
|
|
7
|
+
//
|
|
8
|
+
// Off by default; the canonical entrypoint must opt in via BROWX_ATTACH_CDP=<loopback>.
|
|
9
|
+
// Loopback-only (127.0.0.1 / localhost / ::1) — refuses non-loopback hosts.
|
|
10
|
+
// Not-owned semantics: on close we detach the CDP session, but never close the
|
|
11
|
+
// browser or reset its storage — that's the consumer's Chrome, not ours.
|
|
12
|
+
import { log } from "../util/logging.js";
|
|
13
|
+
import { AndroidCdpAdapter, PlaywrightChromiumAdapter } from "../engine/index.js";
|
|
14
|
+
const LOOPBACK_HOSTS = new Set(["127.0.0.1", "localhost", "::1", "[::1]"]);
|
|
15
|
+
function assertLoopback(endpoint) {
|
|
16
|
+
let url;
|
|
17
|
+
try {
|
|
18
|
+
url = new URL(endpoint);
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
throw new Error(`BROWX_ATTACH_CDP: invalid URL "${endpoint}"`);
|
|
22
|
+
}
|
|
23
|
+
if (!LOOPBACK_HOSTS.has(url.hostname)) {
|
|
24
|
+
throw new Error(`BROWX_ATTACH_CDP: refusing non-loopback host "${url.hostname}". ` +
|
|
25
|
+
`Only 127.0.0.1, localhost, ::1 are allowed (CDP port is unauthenticated).`);
|
|
26
|
+
}
|
|
27
|
+
return url;
|
|
28
|
+
}
|
|
29
|
+
const ATTACH_WARNING = [
|
|
30
|
+
"================================================================",
|
|
31
|
+
" browxai is attaching to an EXTERNAL Chrome over CDP (BYOB).",
|
|
32
|
+
" This Chrome is treated as NOT-OWNED: on shutdown browxai detaches",
|
|
33
|
+
" but does NOT close the browser or reset its storage.",
|
|
34
|
+
"",
|
|
35
|
+
" Sharp edges (you accepted these by setting BROWX_ATTACH_CDP):",
|
|
36
|
+
" - The browser may have --disable-web-security (SOP off).",
|
|
37
|
+
" - The browser holds your real profile: every cookie, password,",
|
|
38
|
+
" and authed tab is in scope of any page the agent visits.",
|
|
39
|
+
" - The CDP port is unauthenticated; any local process can attach.",
|
|
40
|
+
"",
|
|
41
|
+
" Managed mode (the default) avoids all of the above. See docs/threat-model.md.",
|
|
42
|
+
"================================================================",
|
|
43
|
+
].join("\n");
|
|
44
|
+
// The attached page may pre-paint with zero metrics; ensure a usable viewport so
|
|
45
|
+
// the visible-rect bbox path (page/bbox.ts) doesn't intersect against
|
|
46
|
+
// `innerWidth=0 innerHeight=0` and produce `null + clipped: true` for every
|
|
47
|
+
// visible element. Read the *layout* viewport via CDP (authoritative regardless
|
|
48
|
+
// of `window.inner*`), cross-check the window dims, and install a 1280x800
|
|
49
|
+
// default only if BOTH read as zero. Shared by the desktop-CDP attach and the
|
|
50
|
+
// Android-over-adb attach — both ride a real CDPSession. Best-effort; a failure
|
|
51
|
+
// is non-fatal (bbox falls back to the un-clipped client rect).
|
|
52
|
+
async function ensureViewport(cdp) {
|
|
53
|
+
try {
|
|
54
|
+
const layout = (await cdp.send("Page.getLayoutMetrics").catch(() => null));
|
|
55
|
+
const lw = layout?.layoutViewport?.clientWidth ?? 0;
|
|
56
|
+
const lh = layout?.layoutViewport?.clientHeight ?? 0;
|
|
57
|
+
const { result } = (await cdp.send("Runtime.evaluate", {
|
|
58
|
+
expression: "({ w: window.innerWidth || 0, h: window.innerHeight || 0 })",
|
|
59
|
+
returnByValue: true,
|
|
60
|
+
}));
|
|
61
|
+
const v = result.value ?? { w: 0, h: 0 };
|
|
62
|
+
const goodLayout = lw > 0 && lh > 0;
|
|
63
|
+
const goodWindow = v.w > 0 && v.h > 0;
|
|
64
|
+
if (!goodLayout && !goodWindow) {
|
|
65
|
+
log.info("session.byob: attached page has zero viewport; setting 1280x800 default", {
|
|
66
|
+
layout: { lw, lh },
|
|
67
|
+
window: v,
|
|
68
|
+
});
|
|
69
|
+
await cdp
|
|
70
|
+
.send("Emulation.setDeviceMetricsOverride", {
|
|
71
|
+
width: 1280,
|
|
72
|
+
height: 800,
|
|
73
|
+
deviceScaleFactor: 0,
|
|
74
|
+
mobile: false,
|
|
75
|
+
})
|
|
76
|
+
.catch(() => undefined);
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
log.info("session.byob: attached page viewport ok", { layout: { lw, lh }, window: v });
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
/* not fatal — the bbox path falls back to un-clipped client rect when both probes fail */
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
const ANDROID_ATTACH_WARNING = [
|
|
87
|
+
"================================================================",
|
|
88
|
+
" browxai is attaching to your REAL Chrome-on-Android over adb + CDP.",
|
|
89
|
+
" This is the full-fidelity BYOB lane: the device's",
|
|
90
|
+
" Chrome is treated as NOT-OWNED — on shutdown browxai detaches and",
|
|
91
|
+
" removes the adb forward, but never closes the browser or resets its",
|
|
92
|
+
" storage. The phone holds your real profile: every cookie, password,",
|
|
93
|
+
" and authed tab is in scope of any page the agent visits.",
|
|
94
|
+
" Managed mode (the default) avoids all of the above. See docs/threat-model.md.",
|
|
95
|
+
"================================================================",
|
|
96
|
+
].join("\n");
|
|
97
|
+
/** Android BYOB — discover real Chrome-on-Android over adb + CDP and attach.
|
|
98
|
+
* Distinct from the desktop URL-attach path: the endpoint is DISCOVERED
|
|
99
|
+
* (adb forward → /json/version → wsUrl), not configured. The forwarded socket is
|
|
100
|
+
* loopback by construction (adb forwards to 127.0.0.1), so the same not-owned
|
|
101
|
+
* policy applies; close additionally removes the adb forward. Full CDP, so the
|
|
102
|
+
* session carries `cdp()` and the substrates pick the CDP path automatically. */
|
|
103
|
+
export async function openAndroidByobSession() {
|
|
104
|
+
log.warn(ANDROID_ATTACH_WARNING);
|
|
105
|
+
const adapter = new AndroidCdpAdapter();
|
|
106
|
+
const serial = process.env.BROWX_ANDROID_SERIAL?.trim() || undefined;
|
|
107
|
+
// Keep the handles object intact (don't destructure `removeForward` — it is the
|
|
108
|
+
// adapter's bound teardown, called below).
|
|
109
|
+
const handles = await adapter.attach({ serial });
|
|
110
|
+
const { page, cdp } = handles;
|
|
111
|
+
log.info("session.byob: attached to Chrome-on-Android", {
|
|
112
|
+
serial: handles.serial,
|
|
113
|
+
localPort: handles.localPort,
|
|
114
|
+
engine: "android",
|
|
115
|
+
});
|
|
116
|
+
await ensureViewport(cdp);
|
|
117
|
+
let closed = false;
|
|
118
|
+
return {
|
|
119
|
+
mode: "byob",
|
|
120
|
+
ownsBrowser: false,
|
|
121
|
+
engine: "android",
|
|
122
|
+
page: () => page,
|
|
123
|
+
// Android Chrome speaks full CDP — the eager session is always present.
|
|
124
|
+
cdp: () => cdp,
|
|
125
|
+
close: async () => {
|
|
126
|
+
if (closed)
|
|
127
|
+
return;
|
|
128
|
+
closed = true;
|
|
129
|
+
log.info("session.byob: detaching Chrome-on-Android (device stays open — not-owned)");
|
|
130
|
+
await cdp.detach().catch(() => undefined);
|
|
131
|
+
await handles.removeForward();
|
|
132
|
+
// Do NOT call browser.close() — not-owned (it's the user's phone Chrome).
|
|
133
|
+
},
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
/** Assert the BYOB attach endpoint is present + loopback, returning it as a
|
|
137
|
+
* string. The firefox / webkit engine modules call this before surfacing their
|
|
138
|
+
* structured attach refusal, preserving the EXACT pre-relocation order (the
|
|
139
|
+
* `!attachCdp` throw, then the loopback assertion, then the per-engine refusal).
|
|
140
|
+
* Shared so the loopback policy lives in one place. */
|
|
141
|
+
export function assertByobAttach(opts) {
|
|
142
|
+
if (!opts.attachCdp) {
|
|
143
|
+
throw new Error("session.byob: the CDP-attach lane requires BROWX_ATTACH_CDP (a loopback CDP endpoint). " +
|
|
144
|
+
'For the android engine use browserType:"android" (endpoint discovered over adb).');
|
|
145
|
+
}
|
|
146
|
+
return assertLoopback(opts.attachCdp).toString();
|
|
147
|
+
}
|
|
148
|
+
/** The Chromium CDP-attach (BYOB) lane — the desktop URL-attach path, extracted
|
|
149
|
+
* verbatim from the old `openByobSession` chromium body. Asserts the loopback
|
|
150
|
+
* endpoint, attaches over CDP, ensures a usable viewport, and builds the
|
|
151
|
+
* not-owned `BrowserSession`. The chromium engine module's `makeAdapter` byob
|
|
152
|
+
* branch calls this; firefox/webkit/safari surface their own structured attach
|
|
153
|
+
* refusals from their own engine modules, and android attaches over adb via
|
|
154
|
+
* `openAndroidByobSession` — so no engine-name branch survives here. */
|
|
155
|
+
export async function attachByobChromium(opts) {
|
|
156
|
+
if (!opts.attachCdp) {
|
|
157
|
+
throw new Error("session.byob: the CDP-attach lane requires BROWX_ATTACH_CDP (a loopback CDP endpoint). " +
|
|
158
|
+
'For the android engine use browserType:"android" (endpoint discovered over adb).');
|
|
159
|
+
}
|
|
160
|
+
const url = assertLoopback(opts.attachCdp);
|
|
161
|
+
log.warn(ATTACH_WARNING);
|
|
162
|
+
log.info("session.byob: attaching", {
|
|
163
|
+
endpoint: url.toString(),
|
|
164
|
+
owner: "external",
|
|
165
|
+
engine: "chromium",
|
|
166
|
+
});
|
|
167
|
+
const adapter = new PlaywrightChromiumAdapter();
|
|
168
|
+
const { page, cdp } = await adapter.attachOverCdp(url.toString());
|
|
169
|
+
await ensureViewport(cdp);
|
|
170
|
+
let closed = false;
|
|
171
|
+
return {
|
|
172
|
+
mode: "byob",
|
|
173
|
+
ownsBrowser: false,
|
|
174
|
+
engine: "chromium",
|
|
175
|
+
page: () => page,
|
|
176
|
+
// chromium always mints a CDP session; `cdp` is non-undefined here.
|
|
177
|
+
cdp: () => cdp,
|
|
178
|
+
close: async () => {
|
|
179
|
+
if (closed)
|
|
180
|
+
return;
|
|
181
|
+
closed = true;
|
|
182
|
+
log.info("session.byob: detaching (browser stays open — not-owned)");
|
|
183
|
+
await cdp.detach().catch(() => undefined);
|
|
184
|
+
// Do NOT call browser.close() / context.close() — not-owned.
|
|
185
|
+
},
|
|
186
|
+
};
|
|
187
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import "../engine/register-engines.js";
|
|
2
|
+
import type { BrowserSession, SessionOptions } from "./types.js";
|
|
3
|
+
export { attachByobChromium, openAndroidByobSession, assertByobAttach } from "./byob-attach.js";
|
|
4
|
+
/** BYOB / attach session — resolves the engine and hands off to the
|
|
5
|
+
* EngineRegistry's per-engine attach body. */
|
|
6
|
+
export declare function openByobSession(opts: SessionOptions & {
|
|
7
|
+
attachCdp?: string;
|
|
8
|
+
}): Promise<BrowserSession>;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// BYOB / attach session — the MODE-concern entry point. Post-RFC-0004-P1 this
|
|
2
|
+
// keeps only its mode concern: it resolves the engine and hands off to the
|
|
3
|
+
// EngineRegistry, whose `makeAdapter` owns the per-engine attach body (android
|
|
4
|
+
// over adb; chromium over CDP; firefox/webkit/safari structured refusals — all in
|
|
5
|
+
// adapters/<engine>.engine.ts). The `engine === "…"` dispatch chain that used to
|
|
6
|
+
// live here is now data-driven — byte-identical, only relocated.
|
|
7
|
+
//
|
|
8
|
+
// The attach PRIMITIVES (`attachByobChromium` / `openAndroidByobSession` /
|
|
9
|
+
// `assertByobAttach`) live in byob-attach.ts so the engine-registration graph does
|
|
10
|
+
// not cycle back through this module's `engineEntry` import; they are re-exported
|
|
11
|
+
// here for back-compat with existing importers.
|
|
12
|
+
import { engineEntry } from "../engine/registry.js";
|
|
13
|
+
import "../engine/register-engines.js";
|
|
14
|
+
export { attachByobChromium, openAndroidByobSession, assertByobAttach } from "./byob-attach.js";
|
|
15
|
+
/** BYOB / attach session — resolves the engine and hands off to the
|
|
16
|
+
* EngineRegistry's per-engine attach body. */
|
|
17
|
+
export async function openByobSession(opts) {
|
|
18
|
+
const engine = opts.browserType ?? "chromium";
|
|
19
|
+
return engineEntry(engine).makeAdapter({ ...opts, launchMode: "byob" });
|
|
20
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import type { Page } from "playwright-core";
|
|
2
|
+
/** Result envelope for a cache-entry body — text-like content lands as a
|
|
3
|
+
* string, anything binary-ish as base64 + the byte count. */
|
|
4
|
+
export type CacheEntryBody = {
|
|
5
|
+
kind: "text";
|
|
6
|
+
text: string;
|
|
7
|
+
contentType: string | null;
|
|
8
|
+
status: number;
|
|
9
|
+
headers: Record<string, string>;
|
|
10
|
+
} | {
|
|
11
|
+
kind: "binary";
|
|
12
|
+
contentBase64: string;
|
|
13
|
+
byteLength: number;
|
|
14
|
+
contentType: string | null;
|
|
15
|
+
status: number;
|
|
16
|
+
headers: Record<string, string>;
|
|
17
|
+
};
|
|
18
|
+
/** List every cache storage name visible to the current origin. */
|
|
19
|
+
export declare function cachesListStorages(page: Page, tool: string): Promise<{
|
|
20
|
+
names: string[];
|
|
21
|
+
origin: string;
|
|
22
|
+
}>;
|
|
23
|
+
/** List the entries in a single cache. Optional `urlPattern` is a
|
|
24
|
+
* substring match against each entry's `request.url` (case-sensitive
|
|
25
|
+
* — adopters that want regex can filter the result themselves). */
|
|
26
|
+
export declare function cachesList(page: Page, args: {
|
|
27
|
+
cacheName: string;
|
|
28
|
+
urlPattern?: string;
|
|
29
|
+
}, tool: string): Promise<{
|
|
30
|
+
entries: Array<{
|
|
31
|
+
url: string;
|
|
32
|
+
method: string;
|
|
33
|
+
}>;
|
|
34
|
+
origin: string;
|
|
35
|
+
cacheName: string;
|
|
36
|
+
}>;
|
|
37
|
+
/** Return the response body of a single entry. Text-like content types
|
|
38
|
+
* arrive as a UTF-8 string; everything else as base64. */
|
|
39
|
+
export declare function cachesGet(page: Page, args: {
|
|
40
|
+
cacheName: string;
|
|
41
|
+
url: string;
|
|
42
|
+
}, tool: string): Promise<{
|
|
43
|
+
found: false;
|
|
44
|
+
cacheName: string;
|
|
45
|
+
url: string;
|
|
46
|
+
origin: string;
|
|
47
|
+
} | (CacheEntryBody & {
|
|
48
|
+
found: true;
|
|
49
|
+
cacheName: string;
|
|
50
|
+
url: string;
|
|
51
|
+
origin: string;
|
|
52
|
+
})>;
|
|
53
|
+
/** Put an entry. `response.body` is either a UTF-8 string (default —
|
|
54
|
+
* same shape as the Cache API's `new Response(string)`) or base64 bytes
|
|
55
|
+
* via `{contentBase64: ...}`. Auto-opens (= creates) the cache storage. */
|
|
56
|
+
export declare function cachesPut(page: Page, args: {
|
|
57
|
+
cacheName: string;
|
|
58
|
+
url: string;
|
|
59
|
+
response: {
|
|
60
|
+
status?: number;
|
|
61
|
+
headers?: Record<string, string>;
|
|
62
|
+
body?: string;
|
|
63
|
+
contentBase64?: string;
|
|
64
|
+
};
|
|
65
|
+
}, tool: string): Promise<{
|
|
66
|
+
ok: true;
|
|
67
|
+
cacheName: string;
|
|
68
|
+
url: string;
|
|
69
|
+
origin: string;
|
|
70
|
+
}>;
|
|
71
|
+
/** Delete one entry. Returns `existed:true` if the entry was present. */
|
|
72
|
+
export declare function cachesDelete(page: Page, args: {
|
|
73
|
+
cacheName: string;
|
|
74
|
+
url: string;
|
|
75
|
+
}, tool: string): Promise<{
|
|
76
|
+
ok: true;
|
|
77
|
+
existed: boolean;
|
|
78
|
+
cacheName: string;
|
|
79
|
+
url: string;
|
|
80
|
+
origin: string;
|
|
81
|
+
}>;
|
|
82
|
+
/** Clear every entry from a cache (the cache storage itself remains). */
|
|
83
|
+
export declare function cachesClear(page: Page, args: {
|
|
84
|
+
cacheName: string;
|
|
85
|
+
}, tool: string): Promise<{
|
|
86
|
+
ok: true;
|
|
87
|
+
cleared: number;
|
|
88
|
+
cacheName: string;
|
|
89
|
+
origin: string;
|
|
90
|
+
}>;
|
|
91
|
+
/** Delete a cache storage entirely. Returns `existed:true` if the storage
|
|
92
|
+
* was present (idempotent for callers — repeat calls return `existed:false`). */
|
|
93
|
+
export declare function cachesDeleteStorage(page: Page, args: {
|
|
94
|
+
cacheName: string;
|
|
95
|
+
}, tool: string): Promise<{
|
|
96
|
+
ok: true;
|
|
97
|
+
existed: boolean;
|
|
98
|
+
cacheName: string;
|
|
99
|
+
origin: string;
|
|
100
|
+
}>;
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
// Cache API CRUD — storage-state surface extension.
|
|
2
|
+
//
|
|
3
|
+
// Sibling of cookies / localStorage / sessionStorage CRUD. Drives the W3C
|
|
4
|
+
// Cache API (`window.caches`) via `page.evaluate` — the same pattern the
|
|
5
|
+
// web-storage helpers in `storage.ts` use, and for the same reason: the
|
|
6
|
+
// Cache API is ORIGIN-SCOPED. The session MUST be navigated to the target
|
|
7
|
+
// origin before any of these tools work; on `about:blank` or a different
|
|
8
|
+
// origin the call rejects with a navigation hint.
|
|
9
|
+
//
|
|
10
|
+
// What's actually stored: each cache entry is keyed by a Request and
|
|
11
|
+
// carries a Response. The CRUD surface here treats the request side as a
|
|
12
|
+
// URL (the common shape Service Workers populate) and the response side
|
|
13
|
+
// as `{status, headers?, body}` with the body delivered as a UTF-8 string
|
|
14
|
+
// or base64 (auto-detected on the way out — text/* / application/json
|
|
15
|
+
// arrive as strings, anything else as `{contentBase64, byteLength}`).
|
|
16
|
+
//
|
|
17
|
+
// Capability split (server.ts):
|
|
18
|
+
// - reads (`caches_list_storages`, `caches_list`, `caches_get`) → `read`
|
|
19
|
+
// - writes (`caches_put`, `caches_delete`, `caches_clear`,
|
|
20
|
+
// `caches_delete_storage`) → `action`
|
|
21
|
+
//
|
|
22
|
+
// Tracker-ID hygiene: zero. Each cache entry is identified by its
|
|
23
|
+
// `(cacheName, url)` pair — the platform's native key. No synthetic IDs.
|
|
24
|
+
/** Storage object on `window.caches`. */
|
|
25
|
+
const CACHE_API = "caches";
|
|
26
|
+
/** Origin-scope guard — same posture as web-storage. The Cache API is
|
|
27
|
+
* defined on every secure context Chromium ships, but it's still origin-
|
|
28
|
+
* bound: `window.caches.open()` returns the cache for the page's origin,
|
|
29
|
+
* not a global store. Navigate first. */
|
|
30
|
+
function cacheOriginGuard(page, tool) {
|
|
31
|
+
let url;
|
|
32
|
+
try {
|
|
33
|
+
url = page.url();
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
url = "";
|
|
37
|
+
}
|
|
38
|
+
if (!url || url === "about:blank") {
|
|
39
|
+
throw new Error(`${tool}: Cache API is origin-scoped and the page is at "${url || "(unknown)"}". ` +
|
|
40
|
+
`Navigate the session to the target origin first.`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
// ---- reads -----------------------------------------------------------------
|
|
44
|
+
/** List every cache storage name visible to the current origin. */
|
|
45
|
+
export async function cachesListStorages(page, tool) {
|
|
46
|
+
cacheOriginGuard(page, tool);
|
|
47
|
+
const expr = `(async () => { if (typeof ${CACHE_API} === "undefined") return { names: [], origin: location.origin }; ` +
|
|
48
|
+
`var n = await ${CACHE_API}.keys(); ` +
|
|
49
|
+
`return { names: n, origin: location.origin }; })()`;
|
|
50
|
+
return await page.evaluate(expr);
|
|
51
|
+
}
|
|
52
|
+
/** List the entries in a single cache. Optional `urlPattern` is a
|
|
53
|
+
* substring match against each entry's `request.url` (case-sensitive
|
|
54
|
+
* — adopters that want regex can filter the result themselves). */
|
|
55
|
+
export async function cachesList(page, args, tool) {
|
|
56
|
+
if (!args.cacheName)
|
|
57
|
+
throw new Error(`${tool}: \`cacheName\` is required`);
|
|
58
|
+
cacheOriginGuard(page, tool);
|
|
59
|
+
const expr = `(async () => { ` +
|
|
60
|
+
`var c = await ${CACHE_API}.open(${JSON.stringify(args.cacheName)}); ` +
|
|
61
|
+
`var reqs = await c.keys(); ` +
|
|
62
|
+
`var pat = ${JSON.stringify(args.urlPattern ?? "")}; ` +
|
|
63
|
+
`var out = []; ` +
|
|
64
|
+
`for (var i = 0; i < reqs.length; i++) { ` +
|
|
65
|
+
` var r = reqs[i]; ` +
|
|
66
|
+
` if (pat && r.url.indexOf(pat) === -1) continue; ` +
|
|
67
|
+
` out.push({ url: r.url, method: r.method }); ` +
|
|
68
|
+
`} ` +
|
|
69
|
+
`return { entries: out, origin: location.origin, cacheName: ${JSON.stringify(args.cacheName)} }; })()`;
|
|
70
|
+
return await page.evaluate(expr);
|
|
71
|
+
}
|
|
72
|
+
/** Return the response body of a single entry. Text-like content types
|
|
73
|
+
* arrive as a UTF-8 string; everything else as base64. */
|
|
74
|
+
export async function cachesGet(page, args, tool) {
|
|
75
|
+
if (!args.cacheName)
|
|
76
|
+
throw new Error(`${tool}: \`cacheName\` is required`);
|
|
77
|
+
if (!args.url)
|
|
78
|
+
throw new Error(`${tool}: \`url\` is required`);
|
|
79
|
+
cacheOriginGuard(page, tool);
|
|
80
|
+
const expr = `(async () => { ` +
|
|
81
|
+
`var c = await ${CACHE_API}.open(${JSON.stringify(args.cacheName)}); ` +
|
|
82
|
+
`var res = await c.match(${JSON.stringify(args.url)}); ` +
|
|
83
|
+
`if (!res) return { found: false, cacheName: ${JSON.stringify(args.cacheName)}, url: ${JSON.stringify(args.url)}, origin: location.origin }; ` +
|
|
84
|
+
`var headers = {}; res.headers.forEach(function (v, k) { headers[k] = v; }); ` +
|
|
85
|
+
`var ct = res.headers.get("content-type"); ` +
|
|
86
|
+
`var isText = ct && /^(text\\/|application\\/(json|javascript|xml|x-www-form-urlencoded))|charset=/i.test(ct); ` +
|
|
87
|
+
`if (isText) { var t = await res.text(); return { found: true, kind: "text", text: t, contentType: ct, status: res.status, headers: headers, cacheName: ${JSON.stringify(args.cacheName)}, url: ${JSON.stringify(args.url)}, origin: location.origin }; } ` +
|
|
88
|
+
`var buf = await res.arrayBuffer(); ` +
|
|
89
|
+
`var bytes = new Uint8Array(buf); var bin = ""; ` +
|
|
90
|
+
`for (var i = 0; i < bytes.length; i++) bin += String.fromCharCode(bytes[i]); ` +
|
|
91
|
+
`var b64 = btoa(bin); ` +
|
|
92
|
+
`return { found: true, kind: "binary", contentBase64: b64, byteLength: bytes.length, contentType: ct, status: res.status, headers: headers, cacheName: ${JSON.stringify(args.cacheName)}, url: ${JSON.stringify(args.url)}, origin: location.origin }; })()`;
|
|
93
|
+
return await page.evaluate(expr);
|
|
94
|
+
}
|
|
95
|
+
// ---- writes ----------------------------------------------------------------
|
|
96
|
+
/** Put an entry. `response.body` is either a UTF-8 string (default —
|
|
97
|
+
* same shape as the Cache API's `new Response(string)`) or base64 bytes
|
|
98
|
+
* via `{contentBase64: ...}`. Auto-opens (= creates) the cache storage. */
|
|
99
|
+
export async function cachesPut(page, args, tool) {
|
|
100
|
+
if (!args.cacheName)
|
|
101
|
+
throw new Error(`${tool}: \`cacheName\` is required`);
|
|
102
|
+
if (!args.url)
|
|
103
|
+
throw new Error(`${tool}: \`url\` is required`);
|
|
104
|
+
if (!args.response)
|
|
105
|
+
throw new Error(`${tool}: \`response\` is required`);
|
|
106
|
+
if (args.response.body !== undefined && args.response.contentBase64 !== undefined) {
|
|
107
|
+
throw new Error(`${tool}: pass exactly one of \`response.body\` (string) or \`response.contentBase64\` — not both`);
|
|
108
|
+
}
|
|
109
|
+
cacheOriginGuard(page, tool);
|
|
110
|
+
const bodyArg = JSON.stringify({
|
|
111
|
+
body: args.response.body ?? null,
|
|
112
|
+
contentBase64: args.response.contentBase64 ?? null,
|
|
113
|
+
status: args.response.status ?? 200,
|
|
114
|
+
headers: args.response.headers ?? {},
|
|
115
|
+
});
|
|
116
|
+
const expr = `(async () => { ` +
|
|
117
|
+
`var spec = ${bodyArg}; ` +
|
|
118
|
+
`var c = await ${CACHE_API}.open(${JSON.stringify(args.cacheName)}); ` +
|
|
119
|
+
`var body; ` +
|
|
120
|
+
`if (spec.contentBase64 !== null) { ` +
|
|
121
|
+
` var bin = atob(spec.contentBase64); ` +
|
|
122
|
+
` var bytes = new Uint8Array(bin.length); ` +
|
|
123
|
+
` for (var i = 0; i < bin.length; i++) bytes[i] = bin.charCodeAt(i); ` +
|
|
124
|
+
` body = bytes; ` +
|
|
125
|
+
`} else if (spec.body !== null) { body = spec.body; } else { body = ""; } ` +
|
|
126
|
+
`var res = new Response(body, { status: spec.status, headers: spec.headers }); ` +
|
|
127
|
+
`await c.put(${JSON.stringify(args.url)}, res); ` +
|
|
128
|
+
`return { ok: true, cacheName: ${JSON.stringify(args.cacheName)}, url: ${JSON.stringify(args.url)}, origin: location.origin }; })()`;
|
|
129
|
+
return await page.evaluate(expr);
|
|
130
|
+
}
|
|
131
|
+
/** Delete one entry. Returns `existed:true` if the entry was present. */
|
|
132
|
+
export async function cachesDelete(page, args, tool) {
|
|
133
|
+
if (!args.cacheName)
|
|
134
|
+
throw new Error(`${tool}: \`cacheName\` is required`);
|
|
135
|
+
if (!args.url)
|
|
136
|
+
throw new Error(`${tool}: \`url\` is required`);
|
|
137
|
+
cacheOriginGuard(page, tool);
|
|
138
|
+
const expr = `(async () => { ` +
|
|
139
|
+
`var c = await ${CACHE_API}.open(${JSON.stringify(args.cacheName)}); ` +
|
|
140
|
+
`var existed = await c.delete(${JSON.stringify(args.url)}); ` +
|
|
141
|
+
`return { ok: true, existed: existed, cacheName: ${JSON.stringify(args.cacheName)}, url: ${JSON.stringify(args.url)}, origin: location.origin }; })()`;
|
|
142
|
+
return await page.evaluate(expr);
|
|
143
|
+
}
|
|
144
|
+
/** Clear every entry from a cache (the cache storage itself remains). */
|
|
145
|
+
export async function cachesClear(page, args, tool) {
|
|
146
|
+
if (!args.cacheName)
|
|
147
|
+
throw new Error(`${tool}: \`cacheName\` is required`);
|
|
148
|
+
cacheOriginGuard(page, tool);
|
|
149
|
+
const expr = `(async () => { ` +
|
|
150
|
+
`var c = await ${CACHE_API}.open(${JSON.stringify(args.cacheName)}); ` +
|
|
151
|
+
`var reqs = await c.keys(); ` +
|
|
152
|
+
`for (var i = 0; i < reqs.length; i++) await c.delete(reqs[i]); ` +
|
|
153
|
+
`return { ok: true, cleared: reqs.length, cacheName: ${JSON.stringify(args.cacheName)}, origin: location.origin }; })()`;
|
|
154
|
+
return await page.evaluate(expr);
|
|
155
|
+
}
|
|
156
|
+
/** Delete a cache storage entirely. Returns `existed:true` if the storage
|
|
157
|
+
* was present (idempotent for callers — repeat calls return `existed:false`). */
|
|
158
|
+
export async function cachesDeleteStorage(page, args, tool) {
|
|
159
|
+
if (!args.cacheName)
|
|
160
|
+
throw new Error(`${tool}: \`cacheName\` is required`);
|
|
161
|
+
cacheOriginGuard(page, tool);
|
|
162
|
+
const expr = `(async () => { ` +
|
|
163
|
+
`var existed = await ${CACHE_API}.delete(${JSON.stringify(args.cacheName)}); ` +
|
|
164
|
+
`return { ok: true, existed: existed, cacheName: ${JSON.stringify(args.cacheName)}, origin: location.origin }; })()`;
|
|
165
|
+
return await page.evaluate(expr);
|
|
166
|
+
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import type { BrowserContext, Page } from "playwright-core";
|
|
2
|
+
/** The three Web platform APIs browxai's device-emulation governs. */
|
|
3
|
+
export declare const SUPPORTED_DEVICE_APIS: readonly ["bluetooth", "usb", "hid"];
|
|
4
|
+
export type DeviceApi = (typeof SUPPORTED_DEVICE_APIS)[number];
|
|
5
|
+
/** Agent-supplied synthetic device entry. All three APIs share the union
|
|
6
|
+
* shape; the wrapper picks the fields relevant to its API (Bluetooth uses
|
|
7
|
+
* `name` + `id` + `services`; USB uses the vendor/product/class fields;
|
|
8
|
+
* HID uses `vendorId` + `productId` + `productName`). A single entry can
|
|
9
|
+
* carry every field — the page sees only what the spec exposes for its API. */
|
|
10
|
+
export interface SyntheticDevice {
|
|
11
|
+
/** Display name. Bluetooth uses this as `.name`; USB exposes it as
|
|
12
|
+
* `.productName`; HID as `.productName`. Default `"browxai-virtual"`. */
|
|
13
|
+
name?: string;
|
|
14
|
+
/** Bluetooth: stable device id (UUID-style string). Default
|
|
15
|
+
* `"browxai-<api>-<index>"`. */
|
|
16
|
+
id?: string;
|
|
17
|
+
/** USB / HID: 16-bit USB-IF vendor id. Default `0x0000`. */
|
|
18
|
+
vendorId?: number;
|
|
19
|
+
/** USB / HID: 16-bit product id. Default `0x0000`. */
|
|
20
|
+
productId?: number;
|
|
21
|
+
/** USB: human-readable manufacturer string. Default `"browxai virtual"`. */
|
|
22
|
+
manufacturerName?: string;
|
|
23
|
+
/** USB: serial number string. Default `"BROWX-VIRTUAL"`. */
|
|
24
|
+
serialNumber?: string;
|
|
25
|
+
/** USB: 8-bit device class (e.g. 0x03 = HID). Default 0xFF (vendor-
|
|
26
|
+
* specific). */
|
|
27
|
+
deviceClass?: number;
|
|
28
|
+
/** USB: 8-bit device subclass. Default 0x00. */
|
|
29
|
+
deviceSubclass?: number;
|
|
30
|
+
/** USB: 8-bit device protocol. Default 0x00. */
|
|
31
|
+
deviceProtocol?: number;
|
|
32
|
+
/** Bluetooth: GATT primary service UUIDs the device advertises. Default
|
|
33
|
+
* `[]`. The synthetic `gatt.getPrimaryService()` still rejects (no
|
|
34
|
+
* full GATT emulation in v1) — the list is exposed only via the
|
|
35
|
+
* picker-time filter match + on the resolved device's metadata for
|
|
36
|
+
* pages that introspect `device.uuids`-style fields. */
|
|
37
|
+
services?: string[];
|
|
38
|
+
/** HID: report descriptor's collection topology (output only — the
|
|
39
|
+
* agent describes what `collections[]` looks like). Default `[]`. */
|
|
40
|
+
collections?: unknown[];
|
|
41
|
+
}
|
|
42
|
+
/** Public, runtime-mutable per-API catalog. Empty list → next requestDevice
|
|
43
|
+
* rejects (Bluetooth/USB) or returns [] (HID). */
|
|
44
|
+
export interface DeviceCatalog {
|
|
45
|
+
devices: SyntheticDevice[];
|
|
46
|
+
}
|
|
47
|
+
/** One captured `requestDevice` call, surfaced on `device_requests`. */
|
|
48
|
+
export interface DeviceRequestRecord {
|
|
49
|
+
api: DeviceApi;
|
|
50
|
+
/** What the wrapper actually did:
|
|
51
|
+
* - `"resolved"` — catalog non-empty; picker resolved with a synthetic
|
|
52
|
+
* device (Bluetooth/USB) or device list (HID).
|
|
53
|
+
* - `"rejected"` — catalog empty for Bluetooth/USB; picker rejected
|
|
54
|
+
* with NotFoundError ("user dismissed").
|
|
55
|
+
* - `"empty"` — catalog empty for HID; picker resolved with []
|
|
56
|
+
* (the HID picker's user-dismissed shape).
|
|
57
|
+
* - `"refused"` — capability `device-emulation` was OFF at the time
|
|
58
|
+
* of the call; the wrapper let the native API run
|
|
59
|
+
* (which in headless Chromium rejects/returns empty
|
|
60
|
+
* anyway). Recorded so the read-side surfaces "the
|
|
61
|
+
* page asked but you didn't have the capability on". */
|
|
62
|
+
handledAs: "resolved" | "rejected" | "empty" | "refused";
|
|
63
|
+
/** Filter the page supplied in `requestDevice(options.filters[])` /
|
|
64
|
+
* `acceptAllDevices` / etc. — sliced down to a single JSON-safe shape
|
|
65
|
+
* the agent can read. Best-effort: shapes that exceed 4KB stringified
|
|
66
|
+
* are truncated with a `…` marker. */
|
|
67
|
+
filters?: unknown;
|
|
68
|
+
/** Count of devices returned to the page on this call. For Bluetooth/USB:
|
|
69
|
+
* always 0 or 1. For HID: 0..N. */
|
|
70
|
+
returned: number;
|
|
71
|
+
/** epoch ms — used by `device_requests({since?})` slice. */
|
|
72
|
+
ts: number;
|
|
73
|
+
}
|
|
74
|
+
/** Mutable per-session state. The page-side wrapper consults `catalog(api)`
|
|
75
|
+
* via the bridge binding on every `requestDevice` call, so a `set` call
|
|
76
|
+
* takes effect on the very next page-side request without a navigation. */
|
|
77
|
+
export declare class DeviceEmulationState {
|
|
78
|
+
/** Per-API catalog. Empty list (or absent entry) → wrapper falls into
|
|
79
|
+
* the user-dismissed-picker shape for that API. */
|
|
80
|
+
private catalogs;
|
|
81
|
+
/** Captured `requestDevice` calls — a bounded record ring (shared
|
|
82
|
+
* `PolicyRecordBuffer`; chatty pages can't grow this without bound,
|
|
83
|
+
* `device_requests` slices on `since`). */
|
|
84
|
+
private readonly records;
|
|
85
|
+
/** Contexts we've already installed the init-script + binding on.
|
|
86
|
+
* Idempotent install guard — BYOB reconnect / context rebuild MUST not
|
|
87
|
+
* double-wire. */
|
|
88
|
+
private wired;
|
|
89
|
+
/** True iff `device-emulation` capability was on at the time of attach.
|
|
90
|
+
* The page-side wrapper installs regardless (so a runtime capability
|
|
91
|
+
* toggle that adds the cap takes effect — though the canonical
|
|
92
|
+
* resolve-once-at-boot model means it doesn't), but the check binding
|
|
93
|
+
* short-circuits to `refused` when off. */
|
|
94
|
+
private enabledByCapability;
|
|
95
|
+
constructor(enabledByCapability: boolean, cap?: number);
|
|
96
|
+
/** Snapshot of one API's catalog. */
|
|
97
|
+
catalog(api: DeviceApi): DeviceCatalog;
|
|
98
|
+
/** Replace one API's catalog. `devices` may be empty (clears the catalog —
|
|
99
|
+
* next requestDevice rejects/empty). Returns the resolved catalog
|
|
100
|
+
* (echoed back so the tool's response shows what the wrapper will
|
|
101
|
+
* serve). */
|
|
102
|
+
set(api: DeviceApi, devices: SyntheticDevice[]): DeviceCatalog;
|
|
103
|
+
/** Append a request record. Caps the buffer at `cap`. */
|
|
104
|
+
record(rec: DeviceRequestRecord): void;
|
|
105
|
+
/** Slice records with `ts >= since`. Default since=0 returns all. */
|
|
106
|
+
since(since?: number): DeviceRequestRecord[];
|
|
107
|
+
/** Capability gate snapshot. The check binding consults this on every
|
|
108
|
+
* page-side request. */
|
|
109
|
+
capabilityEnabled(): boolean;
|
|
110
|
+
/** Has this context already been wired? Idempotent install guard. */
|
|
111
|
+
hasContext(c: BrowserContext): boolean;
|
|
112
|
+
/** Mark a context as wired. */
|
|
113
|
+
markContext(c: BrowserContext): void;
|
|
114
|
+
}
|
|
115
|
+
/** BYOB warning — the init-script wrappers patch every new document in the
|
|
116
|
+
* attached Chrome's session-isolated context; the patches do NOT escape
|
|
117
|
+
* the context, but the per-deployment posture (the operator's main Chrome
|
|
118
|
+
* running with `--remote-debugging-port`) magnifies the consequences of a
|
|
119
|
+
* page that the agent told "you have a hardware device". Surfaced when
|
|
120
|
+
* `open_session({mode:"attached"})` engages with `device-emulation` on. */
|
|
121
|
+
export declare const BYOB_DEVICE_EMU_WARNING: string;
|
|
122
|
+
/** Init script that wraps the three Web platform device-picker APIs. Each
|
|
123
|
+
* wrapper consults `window.__browx_device_check({api, filters?})` (the
|
|
124
|
+
* exposeBinding from the server side) on every page-side `requestDevice`
|
|
125
|
+
* call — the binding returns a `{decision, devices?}` envelope the wrapper
|
|
126
|
+
* unpacks into the API-specific shape the spec expects. Keep browser-only
|
|
127
|
+
* JS (no TS-only syntax). Re-injected on `framenavigated` (idempotent:
|
|
128
|
+
* guards on `window.__browx_device_emu_installed`). */
|
|
129
|
+
export declare const DEVICE_EMU_PAGE_SCRIPT = "(() => {\n if (window.__browx_device_emu_installed) return;\n window.__browx_device_emu_installed = true;\n\n function check(api, filters) {\n try {\n if (typeof window.__browx_device_check === \"function\") {\n return Promise.resolve(window.__browx_device_check(JSON.stringify({\n api: api,\n filters: filters == null ? null : safeFilters(filters),\n })));\n }\n } catch (_) {}\n // Binding missing \u2014 safe-by-default empty catalog so the page sees the\n // user-dismissed shape rather than a hung promise.\n return Promise.resolve(JSON.stringify({ decision: \"refused\", devices: [] }));\n }\n\n function safeFilters(f) {\n // Defensive shallow clone \u2014 page may pass non-serialisable garbage\n // (BigInt, function, circular). Best-effort.\n try { return JSON.parse(JSON.stringify(f)); } catch (_) { return null; }\n }\n\n function notFound(msg) {\n var e = new Error(msg || \"User cancelled the requestDevice() chooser.\");\n try { e.name = \"NotFoundError\"; } catch (_) {}\n return e;\n }\n\n function parseResponse(raw) {\n try {\n var r = typeof raw === \"string\" ? JSON.parse(raw) : (raw || {});\n var decision = r.decision;\n var devices = Array.isArray(r.devices) ? r.devices : [];\n return { decision: decision, devices: devices };\n } catch (_) {\n return { decision: \"refused\", devices: [] };\n }\n }\n\n // ---- Bluetooth -------------------------------------------------------\n // Synthesise the minimal BluetoothDevice + BluetoothRemoteGATTServer\n // surface modern BLE-onboarding flows touch: id / name / gatt.connect()\n // \u2192 stub server whose getPrimaryService() rejects (no GATT emulation in\n // v1). Pages that gate on \"we found a device\" pass; pages that go on to\n // exchange characteristic data do not.\n function syntheticBluetoothDevice(spec) {\n var name = spec.name || \"browxai-virtual\";\n var id = spec.id || \"browxai-bt-0\";\n var services = Array.isArray(spec.services) ? spec.services : [];\n var device;\n var gatt = {\n get connected() { return gatt.__connected; },\n __connected: false,\n device: null, // set after device is created (circular ref)\n connect: function () {\n gatt.__connected = true;\n return Promise.resolve(gatt);\n },\n disconnect: function () { gatt.__connected = false; },\n getPrimaryService: function () {\n return Promise.reject(notFound(\"GATT service emulation not supported in browxai v1\"));\n },\n getPrimaryServices: function () {\n return Promise.reject(notFound(\"GATT service emulation not supported in browxai v1\"));\n },\n };\n device = {\n id: id,\n name: name,\n uuids: services,\n gatt: gatt,\n // EventTarget stubs \u2014 pages sometimes attach gattserverdisconnected;\n // we accept and ignore.\n addEventListener: function () {},\n removeEventListener: function () {},\n dispatchEvent: function () { return true; },\n watchAdvertisements: function () { return Promise.resolve(undefined); },\n unwatchAdvertisements: function () {},\n get watchingAdvertisements() { return false; },\n // forget() \u2014 modern API for revoking the permission; resolves no-op.\n forget: function () { return Promise.resolve(undefined); },\n };\n gatt.device = device;\n return device;\n }\n try {\n var bt = navigator.bluetooth;\n if (bt && typeof bt.requestDevice === \"function\") {\n // Replace the entire requestDevice; we intentionally do NOT call\n // through to the native API even when the agent didn't stage a\n // catalog \u2014 calling through on a headless Chromium often hangs the\n // promise indefinitely (no picker UI to dismiss).\n Object.defineProperty(bt, \"requestDevice\", {\n configurable: true,\n writable: true,\n value: function (options) {\n var filters = options || null;\n return check(\"bluetooth\", filters).then(function (raw) {\n var r = parseResponse(raw);\n if (!r.devices.length) {\n throw notFound();\n }\n return syntheticBluetoothDevice(r.devices[0]);\n });\n },\n });\n // getDevices \u2014 read-side: pre-paired devices. v1 returns the live\n // catalog so a page polling for an already-paired device sees one.\n if (typeof bt.getDevices === \"function\") {\n Object.defineProperty(bt, \"getDevices\", {\n configurable: true,\n writable: true,\n value: function () {\n return check(\"bluetooth\", null).then(function (raw) {\n var r = parseResponse(raw);\n return r.devices.map(syntheticBluetoothDevice);\n });\n },\n });\n }\n }\n } catch (_) {}\n\n // ---- WebUSB ----------------------------------------------------------\n // USBDevice synthesises the picker-resolve surface + stub\n // open/close/selectConfiguration; transferIn/transferOut resolve with\n // zero-byte responses so a page sequence doesn't reject mid-flight, but\n // there's no actual data flow.\n function syntheticUSBDevice(spec) {\n var name = spec.name || \"browxai-virtual\";\n return {\n vendorId: spec.vendorId || 0,\n productId: spec.productId || 0,\n productName: name,\n manufacturerName: spec.manufacturerName || \"browxai virtual\",\n serialNumber: spec.serialNumber || \"BROWX-VIRTUAL\",\n deviceClass: spec.deviceClass != null ? spec.deviceClass : 0xFF,\n deviceSubclass: spec.deviceSubclass || 0,\n deviceProtocol: spec.deviceProtocol || 0,\n usbVersionMajor: 2,\n usbVersionMinor: 0,\n usbVersionSubminor: 0,\n deviceVersionMajor: 1,\n deviceVersionMinor: 0,\n deviceVersionSubminor: 0,\n configuration: null,\n configurations: [],\n opened: false,\n open: function () { this.opened = true; return Promise.resolve(undefined); },\n close: function () { this.opened = false; return Promise.resolve(undefined); },\n selectConfiguration: function () { return Promise.resolve(undefined); },\n claimInterface: function () { return Promise.resolve(undefined); },\n releaseInterface: function () { return Promise.resolve(undefined); },\n selectAlternateInterface: function () { return Promise.resolve(undefined); },\n controlTransferIn: function () { return Promise.resolve({ data: new DataView(new ArrayBuffer(0)), status: \"ok\" }); },\n controlTransferOut: function () { return Promise.resolve({ bytesWritten: 0, status: \"ok\" }); },\n clearHalt: function () { return Promise.resolve(undefined); },\n transferIn: function () { return Promise.resolve({ data: new DataView(new ArrayBuffer(0)), status: \"ok\" }); },\n transferOut: function () { return Promise.resolve({ bytesWritten: 0, status: \"ok\" }); },\n isochronousTransferIn: function () { return Promise.resolve({ data: new DataView(new ArrayBuffer(0)), packets: [] }); },\n isochronousTransferOut: function () { return Promise.resolve({ packets: [] }); },\n reset: function () { return Promise.resolve(undefined); },\n forget: function () { return Promise.resolve(undefined); },\n };\n }\n try {\n var usb = navigator.usb;\n if (usb && typeof usb.requestDevice === \"function\") {\n Object.defineProperty(usb, \"requestDevice\", {\n configurable: true,\n writable: true,\n value: function (options) {\n var filters = options || null;\n return check(\"usb\", filters).then(function (raw) {\n var r = parseResponse(raw);\n if (!r.devices.length) {\n throw notFound();\n }\n return syntheticUSBDevice(r.devices[0]);\n });\n },\n });\n if (typeof usb.getDevices === \"function\") {\n Object.defineProperty(usb, \"getDevices\", {\n configurable: true,\n writable: true,\n value: function () {\n return check(\"usb\", null).then(function (raw) {\n var r = parseResponse(raw);\n return r.devices.map(syntheticUSBDevice);\n });\n },\n });\n }\n }\n } catch (_) {}\n\n // ---- WebHID ----------------------------------------------------------\n // HIDDevice differs from USB in two ways the wrapper preserves:\n // - requestDevice resolves to an Array<HIDDevice>, NOT a single\n // device (even when only one match \u2014 see W3C spec).\n // - Empty result is the user-dismissed shape, NOT a rejection.\n function syntheticHIDDevice(spec) {\n var name = spec.name || \"browxai-virtual\";\n return {\n opened: false,\n vendorId: spec.vendorId || 0,\n productId: spec.productId || 0,\n productName: name,\n collections: Array.isArray(spec.collections) ? spec.collections : [],\n open: function () { this.opened = true; return Promise.resolve(undefined); },\n close: function () { this.opened = false; return Promise.resolve(undefined); },\n forget: function () { return Promise.resolve(undefined); },\n sendReport: function () { return Promise.resolve(undefined); },\n sendFeatureReport: function () { return Promise.resolve(undefined); },\n receiveFeatureReport: function () { return Promise.resolve(new DataView(new ArrayBuffer(0))); },\n addEventListener: function () {},\n removeEventListener: function () {},\n dispatchEvent: function () { return true; },\n oninputreport: null,\n };\n }\n try {\n var hid = navigator.hid;\n if (hid && typeof hid.requestDevice === \"function\") {\n Object.defineProperty(hid, \"requestDevice\", {\n configurable: true,\n writable: true,\n value: function (options) {\n var filters = options || null;\n return check(\"hid\", filters).then(function (raw) {\n var r = parseResponse(raw);\n return r.devices.map(syntheticHIDDevice);\n });\n },\n });\n if (typeof hid.getDevices === \"function\") {\n Object.defineProperty(hid, \"getDevices\", {\n configurable: true,\n writable: true,\n value: function () {\n return check(\"hid\", null).then(function (raw) {\n var r = parseResponse(raw);\n return r.devices.map(syntheticHIDDevice);\n });\n },\n });\n }\n }\n } catch (_) {}\n})();";
|
|
130
|
+
/** Server-side wire-up. Installs:
|
|
131
|
+
* - `__browx_device_check` exposeBinding: page-side `requestDevice` calls
|
|
132
|
+
* route here; we read the catalog for the requested API, record the
|
|
133
|
+
* call, and return `{decision, devices}`. `decision` is informational
|
|
134
|
+
* (the page-side wrapper consults `devices.length` to pick the
|
|
135
|
+
* spec-correct empty-result shape per API).
|
|
136
|
+
* - The page-side init script (re-injected by Playwright on every new
|
|
137
|
+
* document).
|
|
138
|
+
*
|
|
139
|
+
* Idempotent on the same context. Errors during install are logged and
|
|
140
|
+
* swallowed — the page-side wrapper falls back to "decision: refused,
|
|
141
|
+
* devices: []" when the binding is missing, so a page calling
|
|
142
|
+
* requestDevice never deadlocks.
|
|
143
|
+
*/
|
|
144
|
+
export declare function attachDeviceEmulation(context: BrowserContext, state: DeviceEmulationState): Promise<void>;
|
|
145
|
+
/** Re-apply the init script to an existing page (no-op when the page-side
|
|
146
|
+
* guard is already set). Used by callers that opened pages BEFORE the
|
|
147
|
+
* attach engaged (rare). Public for tests; production callers go through
|
|
148
|
+
* `attachDeviceEmulation` which handles existing pages too. */
|
|
149
|
+
export declare function reinjectDeviceEmuOnPage(page: Page): Promise<void>;
|