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,46 @@
|
|
|
1
|
+
/** The minimal WebSocket surface this client uses — satisfied by Node 22's global
|
|
2
|
+
* `WebSocket` and by the test double. */
|
|
3
|
+
export interface WebSocketLike {
|
|
4
|
+
send(data: string): void;
|
|
5
|
+
close(): void;
|
|
6
|
+
addEventListener(type: "open" | "message" | "error" | "close", listener: (ev: {
|
|
7
|
+
data?: string;
|
|
8
|
+
}) => void): void;
|
|
9
|
+
}
|
|
10
|
+
export type WebSocketFactory = (url: string) => WebSocketLike;
|
|
11
|
+
/** A BiDi event payload (`{type:"event", method, params}`) dispatched to `on()`
|
|
12
|
+
* handlers — e.g. `log.entryAdded`, `browsingContext.load`. */
|
|
13
|
+
export type BidiEventHandler = (params: Record<string, unknown>) => void;
|
|
14
|
+
/** A BiDi command error (`{type:"error", error, message}`) surfaced as a
|
|
15
|
+
* structured throw — never a silent failure. */
|
|
16
|
+
export declare class BidiError extends Error {
|
|
17
|
+
readonly bidiError: string;
|
|
18
|
+
constructor(bidiError: string, message: string);
|
|
19
|
+
}
|
|
20
|
+
export declare class SafariBidiClient {
|
|
21
|
+
private readonly url;
|
|
22
|
+
private readonly wsFactory;
|
|
23
|
+
private readonly commandTimeoutMs;
|
|
24
|
+
private ws;
|
|
25
|
+
private nextId;
|
|
26
|
+
private readonly pending;
|
|
27
|
+
private readonly handlers;
|
|
28
|
+
constructor(opts: {
|
|
29
|
+
url: string;
|
|
30
|
+
wsFactory?: WebSocketFactory;
|
|
31
|
+
commandTimeoutMs?: number;
|
|
32
|
+
});
|
|
33
|
+
/** Open the socket. Resolves on `open`, rejects on a connect-time `error`. */
|
|
34
|
+
connect(): Promise<void>;
|
|
35
|
+
/** Send a BiDi command and await its correlated reply. Rejects with a
|
|
36
|
+
* `BidiError` on an error reply (e.g. `unknown command` for a module Safari
|
|
37
|
+
* does not implement) and on timeout. */
|
|
38
|
+
send(method: string, params?: Record<string, unknown>): Promise<unknown>;
|
|
39
|
+
/** Subscribe to BiDi events (`session.subscribe`). The corresponding `on()`
|
|
40
|
+
* handlers then fire as events arrive. */
|
|
41
|
+
subscribe(events: string[]): Promise<void>;
|
|
42
|
+
/** Register a handler for a BiDi event method (e.g. `log.entryAdded`). */
|
|
43
|
+
on(method: string, handler: BidiEventHandler): void;
|
|
44
|
+
close(): void;
|
|
45
|
+
private onMessage;
|
|
46
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
// SafariBidiClient — the WebDriver-BiDi WebSocket client beneath the
|
|
2
|
+
// SafaridriverHybridAdapter. This is the ADDITIVE half of the
|
|
3
|
+
// hybrid: live probing found
|
|
4
|
+
// Safari 26.5 opens a real BiDi socket ONLY behind the vendor cap
|
|
5
|
+
// `safari:experimentalWebSocketUrl:true`, and that socket serves a PARTIAL but
|
|
6
|
+
// real surface — `script` (evaluate/callFunction/getRealms/addPreloadScript),
|
|
7
|
+
// `browsingContext` navigation/lifecycle/setViewport/create/activate, and the
|
|
8
|
+
// events that fired (`browsingContext.navigation*`/`load`, `log.entryAdded`).
|
|
9
|
+
// It does NOT serve input/network/emulation/screenshot/locateNodes/storage — the
|
|
10
|
+
// adapter routes those through WebDriver Classic (SafariWebDriverClient) or gates
|
|
11
|
+
// them. Because the experimental cap can disappear in any Safari point release,
|
|
12
|
+
// this client is STRICTLY OPTIONAL: the adapter runs Classic-only when there is
|
|
13
|
+
// no ws:// URL, so nothing here is on the critical path.
|
|
14
|
+
//
|
|
15
|
+
// Node's global `WebSocket` (v22+) is the transport — no `ws` dependency, exactly
|
|
16
|
+
// as the probe used. The factory is injected (`WebSocketFactory`) so the
|
|
17
|
+
// request/response correlation + event dispatch unit-test without a real socket.
|
|
18
|
+
/** A BiDi command error (`{type:"error", error, message}`) surfaced as a
|
|
19
|
+
* structured throw — never a silent failure. */
|
|
20
|
+
export class BidiError extends Error {
|
|
21
|
+
bidiError;
|
|
22
|
+
constructor(bidiError, message) {
|
|
23
|
+
super(`safari-bidi: ${bidiError}: ${message}`);
|
|
24
|
+
this.name = "BidiError";
|
|
25
|
+
this.bidiError = bidiError;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
export class SafariBidiClient {
|
|
29
|
+
url;
|
|
30
|
+
wsFactory;
|
|
31
|
+
commandTimeoutMs;
|
|
32
|
+
ws;
|
|
33
|
+
nextId = 1;
|
|
34
|
+
pending = new Map();
|
|
35
|
+
handlers = new Map();
|
|
36
|
+
constructor(opts) {
|
|
37
|
+
this.url = opts.url;
|
|
38
|
+
// Node 22's global WebSocket is structurally a WebSocketLike.
|
|
39
|
+
this.wsFactory = opts.wsFactory ?? ((u) => new WebSocket(u));
|
|
40
|
+
this.commandTimeoutMs = opts.commandTimeoutMs ?? 10_000;
|
|
41
|
+
}
|
|
42
|
+
/** Open the socket. Resolves on `open`, rejects on a connect-time `error`. */
|
|
43
|
+
connect() {
|
|
44
|
+
return new Promise((resolve, reject) => {
|
|
45
|
+
const ws = this.wsFactory(this.url);
|
|
46
|
+
this.ws = ws;
|
|
47
|
+
ws.addEventListener("open", () => resolve());
|
|
48
|
+
ws.addEventListener("error", (ev) => reject(new Error(`safari-bidi: socket error ${describe(ev)}`)));
|
|
49
|
+
ws.addEventListener("message", (ev) => this.onMessage(ev.data));
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
/** Send a BiDi command and await its correlated reply. Rejects with a
|
|
53
|
+
* `BidiError` on an error reply (e.g. `unknown command` for a module Safari
|
|
54
|
+
* does not implement) and on timeout. */
|
|
55
|
+
send(method, params = {}) {
|
|
56
|
+
if (!this.ws)
|
|
57
|
+
return Promise.reject(new Error("safari-bidi: not connected"));
|
|
58
|
+
const id = this.nextId++;
|
|
59
|
+
const ws = this.ws;
|
|
60
|
+
return new Promise((resolve, reject) => {
|
|
61
|
+
const timer = setTimeout(() => {
|
|
62
|
+
this.pending.delete(id);
|
|
63
|
+
reject(new Error(`safari-bidi: command timed out after ${this.commandTimeoutMs}ms: ${method}`));
|
|
64
|
+
}, this.commandTimeoutMs);
|
|
65
|
+
this.pending.set(id, { resolve, reject, timer });
|
|
66
|
+
ws.send(JSON.stringify({ id, method, params }));
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
/** Subscribe to BiDi events (`session.subscribe`). The corresponding `on()`
|
|
70
|
+
* handlers then fire as events arrive. */
|
|
71
|
+
async subscribe(events) {
|
|
72
|
+
await this.send("session.subscribe", { events });
|
|
73
|
+
}
|
|
74
|
+
/** Register a handler for a BiDi event method (e.g. `log.entryAdded`). */
|
|
75
|
+
on(method, handler) {
|
|
76
|
+
let set = this.handlers.get(method);
|
|
77
|
+
if (!set) {
|
|
78
|
+
set = new Set();
|
|
79
|
+
this.handlers.set(method, set);
|
|
80
|
+
}
|
|
81
|
+
set.add(handler);
|
|
82
|
+
}
|
|
83
|
+
close() {
|
|
84
|
+
for (const { reject, timer } of this.pending.values()) {
|
|
85
|
+
clearTimeout(timer);
|
|
86
|
+
reject(new Error("safari-bidi: client closed"));
|
|
87
|
+
}
|
|
88
|
+
this.pending.clear();
|
|
89
|
+
this.ws?.close();
|
|
90
|
+
this.ws = undefined;
|
|
91
|
+
}
|
|
92
|
+
onMessage(data) {
|
|
93
|
+
if (data === undefined)
|
|
94
|
+
return;
|
|
95
|
+
let msg;
|
|
96
|
+
try {
|
|
97
|
+
msg = JSON.parse(data);
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
if (msg.type === "event" && msg.method) {
|
|
103
|
+
const set = this.handlers.get(msg.method);
|
|
104
|
+
if (set)
|
|
105
|
+
for (const h of set)
|
|
106
|
+
h(msg.params ?? {});
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
if (typeof msg.id === "number") {
|
|
110
|
+
const entry = this.pending.get(msg.id);
|
|
111
|
+
if (!entry)
|
|
112
|
+
return;
|
|
113
|
+
this.pending.delete(msg.id);
|
|
114
|
+
clearTimeout(entry.timer);
|
|
115
|
+
if (msg.type === "error") {
|
|
116
|
+
entry.reject(new BidiError(msg.error ?? "unknown error", msg.message ?? ""));
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
entry.resolve(msg.result);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
/** Best-effort description of a socket error event for the connect rejection. */
|
|
125
|
+
function describe(ev) {
|
|
126
|
+
if (ev && typeof ev === "object" && "message" in ev) {
|
|
127
|
+
return String(ev.message);
|
|
128
|
+
}
|
|
129
|
+
return "";
|
|
130
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/** Canonical safaridriver path (the symlink in /usr/bin resolves into the Safari
|
|
2
|
+
* cryptex). Overridable in tests via `SafariLaunchDeps.driverPath`. */
|
|
3
|
+
export declare const SAFARIDRIVER_PATH = "/usr/bin/safaridriver";
|
|
4
|
+
/** The minimal child-process surface the launcher owns. Satisfied by Node's
|
|
5
|
+
* `ChildProcess`; the test double records the kill. */
|
|
6
|
+
export interface ProcessLike {
|
|
7
|
+
readonly pid?: number;
|
|
8
|
+
kill(): boolean;
|
|
9
|
+
}
|
|
10
|
+
export type SpawnLike = (cmd: string, args: string[]) => ProcessLike;
|
|
11
|
+
/** Raised when Safari automation cannot run on this host at all — not macOS, or
|
|
12
|
+
* safaridriver is absent. Structured (no vague crash) per the doctrine, naming
|
|
13
|
+
* the fix. */
|
|
14
|
+
export declare class SafariUnavailableError extends Error {
|
|
15
|
+
constructor(reason: string);
|
|
16
|
+
}
|
|
17
|
+
/** Raised when safaridriver never reaches readiness within the poll window. */
|
|
18
|
+
export declare class SafariLaunchTimeoutError extends Error {
|
|
19
|
+
constructor(ms: number);
|
|
20
|
+
}
|
|
21
|
+
/** Injectable IO seams (defaults shell out / probe for real). */
|
|
22
|
+
export interface SafariLaunchDeps {
|
|
23
|
+
spawnImpl?: SpawnLike;
|
|
24
|
+
/** Resolve a free loopback port (defaults to adb.ts's `pickFreePort`). */
|
|
25
|
+
pickPort?: () => Promise<number>;
|
|
26
|
+
/** Probe whether a driver at `baseUrl` is ready (defaults to a real GET
|
|
27
|
+
* /status). Injected so the poll loop tests without a driver. */
|
|
28
|
+
probeReady?: (baseUrl: string) => Promise<boolean>;
|
|
29
|
+
/** Whether the safaridriver binary exists (defaults to a real `statSync`). */
|
|
30
|
+
binaryExists?: (path: string) => boolean;
|
|
31
|
+
/** The host platform (defaults to `process.platform`). */
|
|
32
|
+
platform?: NodeJS.Platform;
|
|
33
|
+
/** Override the driver path (tests). */
|
|
34
|
+
driverPath?: string;
|
|
35
|
+
/** Sleep between readiness polls (injected so tests don't wait). */
|
|
36
|
+
sleep?: (ms: number) => Promise<void>;
|
|
37
|
+
readinessTimeoutMs?: number;
|
|
38
|
+
pollIntervalMs?: number;
|
|
39
|
+
}
|
|
40
|
+
/** A running safaridriver. `baseUrl` is the WebDriver HTTP endpoint; `stop()`
|
|
41
|
+
* kills the process. */
|
|
42
|
+
export interface SafariDriverProcess {
|
|
43
|
+
baseUrl: string;
|
|
44
|
+
httpPort: number;
|
|
45
|
+
process: ProcessLike;
|
|
46
|
+
stop(): void;
|
|
47
|
+
}
|
|
48
|
+
/** Platform + binary precheck. Throws `SafariUnavailableError` off-macOS or when
|
|
49
|
+
* safaridriver is absent — the launch fast-fails with a clear reason rather than
|
|
50
|
+
* spawning a doomed process. */
|
|
51
|
+
export declare function assertSafariAvailable(deps?: SafariLaunchDeps): void;
|
|
52
|
+
/** Spawn safaridriver and poll it to readiness. Pre-checks availability, picks a
|
|
53
|
+
* free HTTP port (+ a BiDi port), spawns `safaridriver -p <http> --bidi <bidi>`,
|
|
54
|
+
* then polls GET /status until ready or the timeout — killing the process if it
|
|
55
|
+
* never comes up (no leaked driver). */
|
|
56
|
+
export declare function launchSafaridriver(deps?: SafariLaunchDeps): Promise<SafariDriverProcess>;
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
// safaridriver process lifecycle for the SafaridriverHybridAdapter
|
|
2
|
+
// — spawn the driver, poll it to readiness, and own its teardown. Split into a
|
|
3
|
+
// platform/binary precheck + the spawn/poll, with the IO seams (spawn, the
|
|
4
|
+
// readiness probe, the sleep) injected so the orchestration unit-tests WITHOUT a
|
|
5
|
+
// real safaridriver — the same discipline as adb.ts. The real IO path is covered
|
|
6
|
+
// by the Safari-gated keystone.
|
|
7
|
+
//
|
|
8
|
+
// safaridriver is macOS-only and ships inside the Safari cryptex
|
|
9
|
+
// (`/usr/bin/safaridriver` → `/System/Cryptexes/App/usr/bin/safaridriver`). It
|
|
10
|
+
// is launched as `safaridriver -p <httpPort> --bidi <bidiPort>`: the HTTP port
|
|
11
|
+
// serves WebDriver Classic + session creation; `--bidi` enables BiDi for hosted
|
|
12
|
+
// sessions (the actual ws:// socket is allocated dynamically and reported in the
|
|
13
|
+
// granted caps, NOT bound to the passed port value).
|
|
14
|
+
import { execFile } from "node:child_process";
|
|
15
|
+
import { statSync } from "node:fs";
|
|
16
|
+
import { SafariWebDriverClient } from "./webdriver-client.js";
|
|
17
|
+
/** Canonical safaridriver path (the symlink in /usr/bin resolves into the Safari
|
|
18
|
+
* cryptex). Overridable in tests via `SafariLaunchDeps.driverPath`. */
|
|
19
|
+
export const SAFARIDRIVER_PATH = "/usr/bin/safaridriver";
|
|
20
|
+
/** Raised when Safari automation cannot run on this host at all — not macOS, or
|
|
21
|
+
* safaridriver is absent. Structured (no vague crash) per the doctrine, naming
|
|
22
|
+
* the fix. */
|
|
23
|
+
export class SafariUnavailableError extends Error {
|
|
24
|
+
constructor(reason) {
|
|
25
|
+
super(`safari-unavailable: ${reason}. Real Safari automation needs macOS with safaridriver ` +
|
|
26
|
+
`(${SAFARIDRIVER_PATH}).`);
|
|
27
|
+
this.name = "SafariUnavailableError";
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/** Raised when safaridriver never reaches readiness within the poll window. */
|
|
31
|
+
export class SafariLaunchTimeoutError extends Error {
|
|
32
|
+
constructor(ms) {
|
|
33
|
+
super(`safari-launch-timeout: safaridriver did not become ready within ${ms}ms`);
|
|
34
|
+
this.name = "SafariLaunchTimeoutError";
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
function defaultBinaryExists(path) {
|
|
38
|
+
try {
|
|
39
|
+
statSync(path);
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
function defaultSpawn(cmd, args) {
|
|
47
|
+
// detached:false — the driver dies with the parent; stdio ignored (we talk to
|
|
48
|
+
// it over HTTP, not its stdout).
|
|
49
|
+
return execFile(cmd, args, () => undefined);
|
|
50
|
+
}
|
|
51
|
+
function defaultSleep(ms) {
|
|
52
|
+
return new Promise((r) => setTimeout(r, ms));
|
|
53
|
+
}
|
|
54
|
+
/** Platform + binary precheck. Throws `SafariUnavailableError` off-macOS or when
|
|
55
|
+
* safaridriver is absent — the launch fast-fails with a clear reason rather than
|
|
56
|
+
* spawning a doomed process. */
|
|
57
|
+
export function assertSafariAvailable(deps = {}) {
|
|
58
|
+
const platform = deps.platform ?? process.platform;
|
|
59
|
+
if (platform !== "darwin") {
|
|
60
|
+
throw new SafariUnavailableError(`host platform is "${platform}", not macOS`);
|
|
61
|
+
}
|
|
62
|
+
const driverPath = deps.driverPath ?? SAFARIDRIVER_PATH;
|
|
63
|
+
const exists = deps.binaryExists ?? defaultBinaryExists;
|
|
64
|
+
if (!exists(driverPath)) {
|
|
65
|
+
throw new SafariUnavailableError(`safaridriver not found at ${driverPath}`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/** Spawn safaridriver and poll it to readiness. Pre-checks availability, picks a
|
|
69
|
+
* free HTTP port (+ a BiDi port), spawns `safaridriver -p <http> --bidi <bidi>`,
|
|
70
|
+
* then polls GET /status until ready or the timeout — killing the process if it
|
|
71
|
+
* never comes up (no leaked driver). */
|
|
72
|
+
export async function launchSafaridriver(deps = {}) {
|
|
73
|
+
assertSafariAvailable(deps);
|
|
74
|
+
const { pickFreePort } = await import("../adb.js");
|
|
75
|
+
const pickPort = deps.pickPort ?? pickFreePort;
|
|
76
|
+
const spawnImpl = deps.spawnImpl ?? defaultSpawn;
|
|
77
|
+
const sleep = deps.sleep ?? defaultSleep;
|
|
78
|
+
const timeoutMs = deps.readinessTimeoutMs ?? 10_000;
|
|
79
|
+
const intervalMs = deps.pollIntervalMs ?? 150;
|
|
80
|
+
const driverPath = deps.driverPath ?? SAFARIDRIVER_PATH;
|
|
81
|
+
const httpPort = await pickPort();
|
|
82
|
+
const bidiPort = await pickPort();
|
|
83
|
+
const baseUrl = `http://127.0.0.1:${httpPort}`;
|
|
84
|
+
const probeReady = deps.probeReady ??
|
|
85
|
+
((url) => new SafariWebDriverClient({ baseUrl: url }).status().then((s) => s.ready));
|
|
86
|
+
const proc = spawnImpl(driverPath, ["-p", String(httpPort), "--bidi", String(bidiPort)]);
|
|
87
|
+
const stop = () => {
|
|
88
|
+
try {
|
|
89
|
+
proc.kill();
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
/* already dead */
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
const deadline = timeoutMs / intervalMs;
|
|
96
|
+
for (let attempt = 0; attempt < deadline; attempt++) {
|
|
97
|
+
if (await probeReady(baseUrl)) {
|
|
98
|
+
return { baseUrl, httpPort, process: proc, stop };
|
|
99
|
+
}
|
|
100
|
+
await sleep(intervalMs);
|
|
101
|
+
}
|
|
102
|
+
stop();
|
|
103
|
+
throw new SafariLaunchTimeoutError(timeoutMs);
|
|
104
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/** The subset of the global `fetch` signature this client uses. Injected so the
|
|
2
|
+
* unit tests pass a mock and the orchestration is exercised driver-free. */
|
|
3
|
+
export type FetchLike = (url: string, init: {
|
|
4
|
+
method: string;
|
|
5
|
+
headers: Record<string, string>;
|
|
6
|
+
body?: string;
|
|
7
|
+
}) => Promise<{
|
|
8
|
+
ok: boolean;
|
|
9
|
+
status: number;
|
|
10
|
+
json(): Promise<unknown>;
|
|
11
|
+
}>;
|
|
12
|
+
/** A WebDriver cookie (the fields the cookie tools round-trip). */
|
|
13
|
+
export interface WebDriverCookie {
|
|
14
|
+
name: string;
|
|
15
|
+
value: string;
|
|
16
|
+
domain?: string;
|
|
17
|
+
path?: string;
|
|
18
|
+
secure?: boolean;
|
|
19
|
+
httpOnly?: boolean;
|
|
20
|
+
expiry?: number;
|
|
21
|
+
sameSite?: "Lax" | "Strict" | "None";
|
|
22
|
+
}
|
|
23
|
+
/** The granted-capabilities shape this client cares about — `webSocketUrl` is a
|
|
24
|
+
* real `ws://` string ONLY when the session was created with
|
|
25
|
+
* `safari:experimentalWebSocketUrl:true` (otherwise it is a boolean placeholder
|
|
26
|
+
* and no BiDi socket exists — see reference 06). */
|
|
27
|
+
export interface NewSessionResult {
|
|
28
|
+
sessionId: string;
|
|
29
|
+
capabilities: Record<string, unknown>;
|
|
30
|
+
/** The BiDi WebSocket URL, present only when the experimental cap negotiated a
|
|
31
|
+
* real socket. A boolean or undefined means "no BiDi" — run Classic-only. */
|
|
32
|
+
webSocketUrl: string | undefined;
|
|
33
|
+
}
|
|
34
|
+
/** A WebDriver protocol error surfaced as a structured throw (never a vague
|
|
35
|
+
* mid-call failure — the doctrine's no-silent-failure rule). `error` is the W3C
|
|
36
|
+
* error code (e.g. `session not created`, `no such element`). */
|
|
37
|
+
export declare class WebDriverError extends Error {
|
|
38
|
+
readonly code: string;
|
|
39
|
+
readonly httpStatus: number;
|
|
40
|
+
constructor(code: string, message: string, httpStatus: number);
|
|
41
|
+
}
|
|
42
|
+
/** Whether a request body is an experimental-cap BiDi request (for the
|
|
43
|
+
* capability negotiation the adapter does at session create). */
|
|
44
|
+
export interface SessionCapabilities {
|
|
45
|
+
/** Request a BiDi socket. Pairs with `experimentalWebSocketUrl` on Safari. */
|
|
46
|
+
webSocketUrl?: boolean;
|
|
47
|
+
/** Safari vendor cap — REQUIRED to actually open a BiDi socket on Safari 26.5
|
|
48
|
+
* (plain `webSocketUrl:true` returns a boolean placeholder). */
|
|
49
|
+
experimentalWebSocketUrl?: boolean;
|
|
50
|
+
}
|
|
51
|
+
export declare class SafariWebDriverClient {
|
|
52
|
+
private readonly baseUrl;
|
|
53
|
+
private readonly fetchImpl;
|
|
54
|
+
constructor(opts: {
|
|
55
|
+
baseUrl: string;
|
|
56
|
+
fetchImpl?: FetchLike;
|
|
57
|
+
});
|
|
58
|
+
/** `GET /status` — readiness probe (used by the launch poll). Never throws on a
|
|
59
|
+
* protocol error; returns `{ready:false}` so the poll can retry. */
|
|
60
|
+
status(): Promise<{
|
|
61
|
+
ready: boolean;
|
|
62
|
+
message: string;
|
|
63
|
+
}>;
|
|
64
|
+
/** `POST /session` — create a session. On Safari, passing
|
|
65
|
+
* `{webSocketUrl:true, experimentalWebSocketUrl:true}` negotiates a real BiDi
|
|
66
|
+
* socket; the granted `webSocketUrl` is a `ws://` STRING when (and only when)
|
|
67
|
+
* the experimental cap took (reference 06). A boolean/absent value => no BiDi. */
|
|
68
|
+
newSession(caps?: SessionCapabilities): Promise<NewSessionResult>;
|
|
69
|
+
deleteSession(sessionId: string): Promise<void>;
|
|
70
|
+
navigate(sessionId: string, url: string): Promise<void>;
|
|
71
|
+
/** Current document URL — the Classic substitute for `page.url()` (which the
|
|
72
|
+
* Safari session cannot provide, having no Playwright Page). */
|
|
73
|
+
currentUrl(sessionId: string): Promise<string>;
|
|
74
|
+
/** Full-page screenshot as base64 PNG (Classic — BiDi captureScreenshot is
|
|
75
|
+
* absent on Safari 26.5). */
|
|
76
|
+
screenshot(sessionId: string): Promise<string>;
|
|
77
|
+
/** Find the first matching element; null when none (no-such-element is a normal
|
|
78
|
+
* "not found", not a protocol failure, so it is mapped to null). */
|
|
79
|
+
findElement(sessionId: string, using: string, value: string): Promise<string | null>;
|
|
80
|
+
findElements(sessionId: string, using: string, value: string): Promise<string[]>;
|
|
81
|
+
elementClick(sessionId: string, elementId: string): Promise<void>;
|
|
82
|
+
elementClear(sessionId: string, elementId: string): Promise<void>;
|
|
83
|
+
/** sendKeys. The W3C body carries both `text` and the legacy `value` array;
|
|
84
|
+
* safaridriver accepts `text`. */
|
|
85
|
+
elementValue(sessionId: string, elementId: string, text: string): Promise<void>;
|
|
86
|
+
elementText(sessionId: string, elementId: string): Promise<string>;
|
|
87
|
+
/** Get Element Property — the LIVE DOM property (e.g. an input's current
|
|
88
|
+
* `value`), as opposed to the static HTML attribute. Used to read back what a
|
|
89
|
+
* fill landed. Returns null when the property is absent. */
|
|
90
|
+
elementProperty(sessionId: string, elementId: string, name: string): Promise<string | null>;
|
|
91
|
+
getCookies(sessionId: string): Promise<WebDriverCookie[]>;
|
|
92
|
+
addCookie(sessionId: string, cookie: WebDriverCookie): Promise<void>;
|
|
93
|
+
/** `POST /execute/sync` — run page-context JS and return its value. This is the
|
|
94
|
+
* seam the Safari snapshot substrate ships browxai's DOM-walk PAGE_SCRIPT
|
|
95
|
+
* through (spike-confirmed identical to Playwright frame.evaluate —
|
|
96
|
+
* reference 07 §4). `script` is a function BODY; `args` map to `arguments`. */
|
|
97
|
+
executeScript(sessionId: string, script: string, args?: unknown[]): Promise<unknown>;
|
|
98
|
+
/** The single request primitive: POST/GET/DELETE a WebDriver endpoint, unwrap
|
|
99
|
+
* the `{value}` envelope, and turn an error envelope into a structured
|
|
100
|
+
* `WebDriverError`. */
|
|
101
|
+
private send;
|
|
102
|
+
}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
// SafariWebDriverClient — the WebDriver-Classic HTTP client beneath the
|
|
2
|
+
// SafaridriverHybridAdapter. Classic is the COMPLETE workhorse for
|
|
3
|
+
// real Safari: a live probe against the shipping safaridriver
|
|
4
|
+
// confirmed navigate / screenshot / findElement / element click+value+text /
|
|
5
|
+
// cookies / executeScript all work on the shipping safaridriver, whereas the
|
|
6
|
+
// experimental BiDi layer (SafariBidiClient) is the additive bidirectional half
|
|
7
|
+
// (console + nav events) and is gated behind a vendor cap. So the adapter leans
|
|
8
|
+
// on THIS client for the element/screenshot/cookie/exec surface and treats BiDi
|
|
9
|
+
// as strictly optional.
|
|
10
|
+
//
|
|
11
|
+
// This is pure `fetch` over loopback (safaridriver's REST endpoints), with the
|
|
12
|
+
// HTTP transport injected (`FetchLike`) so the orchestration unit-tests without a
|
|
13
|
+
// real driver — the same IO-seam discipline as adb.ts (AdbRunner/Fetcher). It
|
|
14
|
+
// implements ONLY the endpoints the adapter + the Safari snapshot/action seams
|
|
15
|
+
// actually call (interface segregation), not the whole WebDriver surface.
|
|
16
|
+
/** The W3C element-reference key — the property name a WebDriver server uses to
|
|
17
|
+
* carry an element handle in JSON. safaridriver returns this key (and also the
|
|
18
|
+
* legacy `ELEMENT`); we read either. */
|
|
19
|
+
const ELEMENT_KEY = "element-6066-11e4-a52e-4f735466cecf";
|
|
20
|
+
/** A WebDriver protocol error surfaced as a structured throw (never a vague
|
|
21
|
+
* mid-call failure — the doctrine's no-silent-failure rule). `error` is the W3C
|
|
22
|
+
* error code (e.g. `session not created`, `no such element`). */
|
|
23
|
+
export class WebDriverError extends Error {
|
|
24
|
+
code;
|
|
25
|
+
httpStatus;
|
|
26
|
+
constructor(code, message, httpStatus) {
|
|
27
|
+
super(`safari-webdriver: ${code}: ${message}`);
|
|
28
|
+
this.name = "WebDriverError";
|
|
29
|
+
this.code = code;
|
|
30
|
+
this.httpStatus = httpStatus;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
export class SafariWebDriverClient {
|
|
34
|
+
baseUrl;
|
|
35
|
+
fetchImpl;
|
|
36
|
+
constructor(opts) {
|
|
37
|
+
// Trim a trailing slash so path joins are unambiguous.
|
|
38
|
+
this.baseUrl = opts.baseUrl.replace(/\/$/, "");
|
|
39
|
+
// globalThis.fetch is structurally assignable to FetchLike (a looser shape).
|
|
40
|
+
this.fetchImpl = opts.fetchImpl ?? globalThis.fetch;
|
|
41
|
+
}
|
|
42
|
+
/** `GET /status` — readiness probe (used by the launch poll). Never throws on a
|
|
43
|
+
* protocol error; returns `{ready:false}` so the poll can retry. */
|
|
44
|
+
async status() {
|
|
45
|
+
try {
|
|
46
|
+
const value = (await this.send("GET", "/status"));
|
|
47
|
+
return { ready: value?.ready ?? false, message: value?.message ?? "" };
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return { ready: false, message: "unreachable" };
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/** `POST /session` — create a session. On Safari, passing
|
|
54
|
+
* `{webSocketUrl:true, experimentalWebSocketUrl:true}` negotiates a real BiDi
|
|
55
|
+
* socket; the granted `webSocketUrl` is a `ws://` STRING when (and only when)
|
|
56
|
+
* the experimental cap took (reference 06). A boolean/absent value => no BiDi. */
|
|
57
|
+
async newSession(caps = {}) {
|
|
58
|
+
const alwaysMatch = { browserName: "safari" };
|
|
59
|
+
if (caps.webSocketUrl)
|
|
60
|
+
alwaysMatch["webSocketUrl"] = true;
|
|
61
|
+
if (caps.experimentalWebSocketUrl)
|
|
62
|
+
alwaysMatch["safari:experimentalWebSocketUrl"] = true;
|
|
63
|
+
const value = (await this.send("POST", "/session", { capabilities: { alwaysMatch } }));
|
|
64
|
+
const granted = value.capabilities ?? {};
|
|
65
|
+
const ws = granted["webSocketUrl"];
|
|
66
|
+
return {
|
|
67
|
+
sessionId: value.sessionId,
|
|
68
|
+
capabilities: granted,
|
|
69
|
+
// ONLY a string ws:// URL counts as a live BiDi socket; the boolean
|
|
70
|
+
// placeholder (experimental cap off) means Classic-only.
|
|
71
|
+
webSocketUrl: typeof ws === "string" ? ws : undefined,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
async deleteSession(sessionId) {
|
|
75
|
+
await this.send("DELETE", `/session/${sessionId}`);
|
|
76
|
+
}
|
|
77
|
+
async navigate(sessionId, url) {
|
|
78
|
+
await this.send("POST", `/session/${sessionId}/url`, { url });
|
|
79
|
+
}
|
|
80
|
+
/** Current document URL — the Classic substitute for `page.url()` (which the
|
|
81
|
+
* Safari session cannot provide, having no Playwright Page). */
|
|
82
|
+
async currentUrl(sessionId) {
|
|
83
|
+
return (await this.send("GET", `/session/${sessionId}/url`));
|
|
84
|
+
}
|
|
85
|
+
/** Full-page screenshot as base64 PNG (Classic — BiDi captureScreenshot is
|
|
86
|
+
* absent on Safari 26.5). */
|
|
87
|
+
async screenshot(sessionId) {
|
|
88
|
+
return (await this.send("GET", `/session/${sessionId}/screenshot`));
|
|
89
|
+
}
|
|
90
|
+
/** Find the first matching element; null when none (no-such-element is a normal
|
|
91
|
+
* "not found", not a protocol failure, so it is mapped to null). */
|
|
92
|
+
async findElement(sessionId, using, value) {
|
|
93
|
+
try {
|
|
94
|
+
const v = (await this.send("POST", `/session/${sessionId}/element`, {
|
|
95
|
+
using,
|
|
96
|
+
value,
|
|
97
|
+
}));
|
|
98
|
+
return v[ELEMENT_KEY] ?? v["ELEMENT"] ?? null;
|
|
99
|
+
}
|
|
100
|
+
catch (err) {
|
|
101
|
+
if (err instanceof WebDriverError && err.code === "no such element")
|
|
102
|
+
return null;
|
|
103
|
+
throw err;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
async findElements(sessionId, using, value) {
|
|
107
|
+
const v = (await this.send("POST", `/session/${sessionId}/elements`, {
|
|
108
|
+
using,
|
|
109
|
+
value,
|
|
110
|
+
}));
|
|
111
|
+
return v.map((e) => e[ELEMENT_KEY] ?? e["ELEMENT"]).filter((id) => Boolean(id));
|
|
112
|
+
}
|
|
113
|
+
// Click the element via execute/sync rather than the W3C `/element/{id}/click`
|
|
114
|
+
// endpoint: on the shipping safaridriver the protocol Element Click does not
|
|
115
|
+
// reliably dispatch the page's `click` handlers (a button's `onclick` never
|
|
116
|
+
// fires), whereas a script-driven `arguments[0].click()` does — the same
|
|
117
|
+
// execute/sync seam the snapshot substrate is spike-confirmed on (reference 07).
|
|
118
|
+
// The resolved element id is passed as a web-element reference so the exact
|
|
119
|
+
// element this client found is the one clicked.
|
|
120
|
+
async elementClick(sessionId, elementId) {
|
|
121
|
+
await this.executeScript(sessionId, "arguments[0].click();", [{ [ELEMENT_KEY]: elementId }]);
|
|
122
|
+
}
|
|
123
|
+
async elementClear(sessionId, elementId) {
|
|
124
|
+
await this.send("POST", `/session/${sessionId}/element/${elementId}/clear`, {});
|
|
125
|
+
}
|
|
126
|
+
/** sendKeys. The W3C body carries both `text` and the legacy `value` array;
|
|
127
|
+
* safaridriver accepts `text`. */
|
|
128
|
+
async elementValue(sessionId, elementId, text) {
|
|
129
|
+
await this.send("POST", `/session/${sessionId}/element/${elementId}/value`, {
|
|
130
|
+
text,
|
|
131
|
+
value: text.split(""),
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
async elementText(sessionId, elementId) {
|
|
135
|
+
return (await this.send("GET", `/session/${sessionId}/element/${elementId}/text`));
|
|
136
|
+
}
|
|
137
|
+
/** Get Element Property — the LIVE DOM property (e.g. an input's current
|
|
138
|
+
* `value`), as opposed to the static HTML attribute. Used to read back what a
|
|
139
|
+
* fill landed. Returns null when the property is absent. */
|
|
140
|
+
async elementProperty(sessionId, elementId, name) {
|
|
141
|
+
const v = await this.send("GET", `/session/${sessionId}/element/${elementId}/property/${name}`);
|
|
142
|
+
return typeof v === "string" ? v : null;
|
|
143
|
+
}
|
|
144
|
+
async getCookies(sessionId) {
|
|
145
|
+
return (await this.send("GET", `/session/${sessionId}/cookie`));
|
|
146
|
+
}
|
|
147
|
+
async addCookie(sessionId, cookie) {
|
|
148
|
+
await this.send("POST", `/session/${sessionId}/cookie`, { cookie });
|
|
149
|
+
}
|
|
150
|
+
/** `POST /execute/sync` — run page-context JS and return its value. This is the
|
|
151
|
+
* seam the Safari snapshot substrate ships browxai's DOM-walk PAGE_SCRIPT
|
|
152
|
+
* through (spike-confirmed identical to Playwright frame.evaluate —
|
|
153
|
+
* reference 07 §4). `script` is a function BODY; `args` map to `arguments`. */
|
|
154
|
+
async executeScript(sessionId, script, args = []) {
|
|
155
|
+
return await this.send("POST", `/session/${sessionId}/execute/sync`, { script, args });
|
|
156
|
+
}
|
|
157
|
+
/** The single request primitive: POST/GET/DELETE a WebDriver endpoint, unwrap
|
|
158
|
+
* the `{value}` envelope, and turn an error envelope into a structured
|
|
159
|
+
* `WebDriverError`. */
|
|
160
|
+
async send(method, path, body) {
|
|
161
|
+
const res = await this.fetchImpl(`${this.baseUrl}${path}`, {
|
|
162
|
+
method,
|
|
163
|
+
headers: { "Content-Type": "application/json" },
|
|
164
|
+
...(body !== undefined ? { body: JSON.stringify(body) } : {}),
|
|
165
|
+
});
|
|
166
|
+
const payload = (await res.json());
|
|
167
|
+
const value = payload?.value;
|
|
168
|
+
// WebDriver signals errors with HTTP 4xx/5xx AND a `value.error` code.
|
|
169
|
+
if (!res.ok || (value && typeof value === "object" && "error" in value)) {
|
|
170
|
+
const v = (value ?? {});
|
|
171
|
+
throw new WebDriverError(v.error ?? `http ${res.status}`, v.message ?? "", res.status);
|
|
172
|
+
}
|
|
173
|
+
return value;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// Safari engine registration (RFC 0004 D1 + D5). Safari is the first
|
|
2
|
+
// non-Playwright, no-Page engine — real Safari.app over safaridriver. Its
|
|
3
|
+
// `EngineEntry` is what closes the Safari LSP leak: the engine declares no `page`
|
|
4
|
+
// sub-interface (capabilities.ts), supplies the Safari `SubstrateBundle` (every
|
|
5
|
+
// selector reads the Safari-native handle, never a Page/CDP), and its `postWire`
|
|
6
|
+
// attaches ONLY the BiDi console bridge — omitting every Playwright-only step. So
|
|
7
|
+
// the 17 scattered `sess.engine !== "safari"` guards have no reason to exist, and
|
|
8
|
+
// the `page()`-throws fallback in safari-session.ts is never reached on the
|
|
9
|
+
// relocated path.
|
|
10
|
+
import { log } from "../../util/logging.js";
|
|
11
|
+
import { registerEngine } from "../registry.js";
|
|
12
|
+
import { capabilitiesFor } from "../capabilities.js";
|
|
13
|
+
import { SafaridriverHybridAdapter } from "./safaridriver-hybrid.js";
|
|
14
|
+
import { buildSafariSession } from "../../session/safari-session.js";
|
|
15
|
+
import { safariSubstrateBundle } from "../../page/substrate-bundle-safari.js";
|
|
16
|
+
import { safariPostWire } from "../../session/safari-post-wire.js";
|
|
17
|
+
async function makeSafariAdapter(opts) {
|
|
18
|
+
const mode = opts.launchMode ?? "managed";
|
|
19
|
+
if (mode === "incognito") {
|
|
20
|
+
// safari runs ISOLATED automation windows via the default managed session
|
|
21
|
+
// (safaridriver already isolates each session). Incognito (a separate
|
|
22
|
+
// in-browser context) is a Playwright concept safaridriver has no equivalent
|
|
23
|
+
// for, so refuse rather than silently launch a managed window.
|
|
24
|
+
throw new Error("safari-incognito-not-supported: the safari engine runs isolated automation windows via the " +
|
|
25
|
+
"default managed session (safaridriver isolates each session by construction). Incognito (a " +
|
|
26
|
+
"separate browser context) is a Playwright concept safaridriver has no equivalent for. Open a " +
|
|
27
|
+
"managed session instead.");
|
|
28
|
+
}
|
|
29
|
+
if (mode === "byob") {
|
|
30
|
+
// safari cannot attach to a live browser at all — safaridriver hard-isolates
|
|
31
|
+
// each session into a clean ephemeral automation window. Surface the adapter's
|
|
32
|
+
// structured `safari-attach-not-supported`.
|
|
33
|
+
await new SafaridriverHybridAdapter().attach();
|
|
34
|
+
throw new Error("unreachable: safari attach always refuses");
|
|
35
|
+
}
|
|
36
|
+
// managed IS the safari model (no headless Safari, no separate-context
|
|
37
|
+
// incognito) — an isolated automation window over safaridriver, whose page()
|
|
38
|
+
// throws; Safari-capable tools route through session.safari().
|
|
39
|
+
const handle = await new SafaridriverHybridAdapter().launchManaged();
|
|
40
|
+
log.info("session.managed: safari session ready", {
|
|
41
|
+
sessionId: handle.sessionId,
|
|
42
|
+
hasBidi: handle.hasBidi,
|
|
43
|
+
});
|
|
44
|
+
return buildSafariSession(handle);
|
|
45
|
+
}
|
|
46
|
+
registerEngine({
|
|
47
|
+
kind: "safari",
|
|
48
|
+
capabilities: capabilitiesFor("safari"),
|
|
49
|
+
makeAdapter: makeSafariAdapter,
|
|
50
|
+
makeSubstrates: (deps) => safariSubstrateBundle(deps),
|
|
51
|
+
postWire: (entry, deps) => safariPostWire(entry, deps),
|
|
52
|
+
});
|