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,156 @@
|
|
|
1
|
+
import { estimateTokens } from "../util/tokens.js";
|
|
2
|
+
import { readPermissionStates, SUPPORTED_PERMISSIONS, } from "../session/permission.js";
|
|
3
|
+
import { propagateSyncDecision as propagateNotificationSyncDecision, } from "../session/notification.js";
|
|
4
|
+
import { SUPPORTED_DEVICE_APIS } from "../session/device-emu.js";
|
|
5
|
+
import { SESSION_ARG } from "./schemas.js";
|
|
6
|
+
/**
|
|
7
|
+
* Permission-state read + notification policy + device-request read tools:
|
|
8
|
+
* permission_state / set_notification_policy / device_requests. Split out of
|
|
9
|
+
* `session-policy-tools` by cohesive family (RFC 0004 P3 / D3 SRP); registered
|
|
10
|
+
* through the shared `ToolHost` seam in the same source order. The host owns the
|
|
11
|
+
* closures (register / gate / entry).
|
|
12
|
+
*/
|
|
13
|
+
export function registerSessionNotificationDeviceTools(host) {
|
|
14
|
+
const { z, register, gateCheck, entryFor } = host;
|
|
15
|
+
register("permission_state", {
|
|
16
|
+
capability: "read",
|
|
17
|
+
description: 'Read the current permission state(s) for an origin via the W3C Permissions API (`navigator.permissions.query` — which reflects the CDP-applied baseline). Returns `{ [permission]: "granted" | "denied" | "prompt" | "unknown" }` per requested name. Defaults the `origin` to the current page\'s origin when omitted. Read-only — does not mutate state. Supported permission names (v1): ' +
|
|
18
|
+
SUPPORTED_PERMISSIONS.join(", ") +
|
|
19
|
+
". Sibling of `set_permission_policy`.",
|
|
20
|
+
inputSchema: {
|
|
21
|
+
permissions: z
|
|
22
|
+
.array(z.string())
|
|
23
|
+
.min(1)
|
|
24
|
+
.describe('Canonical permission names to query — see tool description for the supported set. Unknown names map to `"unknown"` in the result.'),
|
|
25
|
+
origin: z
|
|
26
|
+
.string()
|
|
27
|
+
.optional()
|
|
28
|
+
.describe('Origin to query (e.g. "https://example.com"). Omit to use the current page\'s origin.'),
|
|
29
|
+
...SESSION_ARG,
|
|
30
|
+
},
|
|
31
|
+
}, async ({ permissions, origin, session }) => {
|
|
32
|
+
const g = gateCheck("permission_state");
|
|
33
|
+
if (g)
|
|
34
|
+
return g;
|
|
35
|
+
const e = await entryFor(session);
|
|
36
|
+
try {
|
|
37
|
+
const supported = permissions.filter((p) => SUPPORTED_PERMISSIONS.includes(p));
|
|
38
|
+
const states = await readPermissionStates(e.session.page().context(), e.session.page(), supported, origin);
|
|
39
|
+
const out = { ...states };
|
|
40
|
+
for (const p of permissions) {
|
|
41
|
+
if (!(p in out))
|
|
42
|
+
out[p] = "unknown";
|
|
43
|
+
}
|
|
44
|
+
const body = {
|
|
45
|
+
ok: true,
|
|
46
|
+
session: e.id,
|
|
47
|
+
origin: origin ??
|
|
48
|
+
(() => {
|
|
49
|
+
try {
|
|
50
|
+
return new URL(e.session.page().url()).origin;
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
})(),
|
|
56
|
+
states: out,
|
|
57
|
+
tokensEstimate: estimateTokens(JSON.stringify(out)),
|
|
58
|
+
};
|
|
59
|
+
return { content: [{ type: "text", text: JSON.stringify(body, null, 2) }] };
|
|
60
|
+
}
|
|
61
|
+
catch (err) {
|
|
62
|
+
return {
|
|
63
|
+
content: [
|
|
64
|
+
{
|
|
65
|
+
type: "text",
|
|
66
|
+
text: JSON.stringify({ ok: false, error: err instanceof Error ? err.message : String(err) }, null, 2),
|
|
67
|
+
},
|
|
68
|
+
],
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
register("set_notification_policy", {
|
|
73
|
+
capability: "action",
|
|
74
|
+
description: "Mutate the session's notification policy at runtime. Governs `new Notification(title, opts)` *constructor* calls — the page actually attempting to display a notification. Distinct from `set_permission_policy` (which gates `Notification.requestPermission` and the `Notification.permission` state); the two policies compose. Modes:\n" +
|
|
75
|
+
' - "allow" — DEFAULT (browser default). Constructor proceeds; the OS displays per its own settings. Every call is still captured on `ActionResult.notifications[]` for observability.\n' +
|
|
76
|
+
' - "deny" — Constructor throws `NotAllowedError` (the same exception the browser raises when permission is denied). Use to suppress OS notifications while still observing what the page would have shown.\n' +
|
|
77
|
+
' - "raise" — Constructor throws AND RECORDS; the next ActionResult flips `ok:false` with `failure:{source:"app", hint:"unhandled notification — set notificationPolicy"}`. Useful when notifications should be a hard signal that the action triggered an unexpected user-facing event.\n' +
|
|
78
|
+
' - "ask-human" — server blocks on `__browx.confirm(true|false)` (the `await_human({kind:"confirm"})` mechanism), then resolves to allow/deny per the human\'s answer. The constructor returns a stub synchronously (the spec requires a sync return); the real OS notification fires once the human-decision resolves.\n' +
|
|
79
|
+
"Persists across navigation: the init-script is re-injected on every new document within the session. Returns the resolved policy. Captured calls surface on `ActionResult.notifications[] = [{title, body?, icon?, tag?, timestamp, origin?, handledAs}]`.",
|
|
80
|
+
inputSchema: {
|
|
81
|
+
mode: z
|
|
82
|
+
.enum(["allow", "deny", "raise", "ask-human"])
|
|
83
|
+
.describe("Policy mode — see tool description."),
|
|
84
|
+
...SESSION_ARG,
|
|
85
|
+
},
|
|
86
|
+
}, async (args) => {
|
|
87
|
+
const g = gateCheck("set_notification_policy");
|
|
88
|
+
if (g)
|
|
89
|
+
return g;
|
|
90
|
+
const e = await entryFor(args.session);
|
|
91
|
+
try {
|
|
92
|
+
const next = { mode: args.mode };
|
|
93
|
+
const resolved = e.notification.set(next);
|
|
94
|
+
// Push the new sync-decision hint to every live page so the
|
|
95
|
+
// constructor's throw timing tracks the policy without a reload.
|
|
96
|
+
await propagateNotificationSyncDecision(e.session.page().context(), e.notification).catch(() => undefined);
|
|
97
|
+
const tokensEstimate = estimateTokens(JSON.stringify(resolved));
|
|
98
|
+
const body = { ok: true, session: e.id, policy: resolved, tokensEstimate };
|
|
99
|
+
return { content: [{ type: "text", text: JSON.stringify(body, null, 2) }] };
|
|
100
|
+
}
|
|
101
|
+
catch (err) {
|
|
102
|
+
return {
|
|
103
|
+
content: [
|
|
104
|
+
{
|
|
105
|
+
type: "text",
|
|
106
|
+
text: JSON.stringify({ ok: false, error: err instanceof Error ? err.message : String(err) }, null, 2),
|
|
107
|
+
},
|
|
108
|
+
],
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
register("device_requests", {
|
|
113
|
+
capability: "device-emulation",
|
|
114
|
+
description: 'Read-side companion to `emulate_bluetooth` / `emulate_usb` / `emulate_hid`. Returns the buffer of `requestDevice()` calls the page has made on this session — one entry per page-side call, each with `{api, handledAs, returned, filters?, ts}`. Useful for diagnosing "did the page even ask?" when a flow gated on hardware appears stuck. `handledAs`:\n' +
|
|
115
|
+
' - `"resolved"` — catalog non-empty; picker resolved with the synthetic device (Bluetooth/USB) or device list (HID).\n' +
|
|
116
|
+
' - `"rejected"` — catalog empty for Bluetooth/USB; picker rejected with `NotFoundError` (user-dismissed shape).\n' +
|
|
117
|
+
' - `"empty"` — catalog empty for HID; picker resolved with `[]` (HID\'s user-dismissed shape).\n' +
|
|
118
|
+
' - `"refused"` — capability `device-emulation` was OFF at the time of the call; the wrapper short-circuited. Recorded so the read surfaces "the page asked for hardware and you didn\'t have the capability on".\n' +
|
|
119
|
+
"**Gated behind the off-by-default `device-emulation` capability** — a server without the capability can't even read whether the page tried to ask (same posture class as `eval` / `network-body` / `secrets`). Read-only — does not mutate state.",
|
|
120
|
+
inputSchema: {
|
|
121
|
+
since: z
|
|
122
|
+
.number()
|
|
123
|
+
.int()
|
|
124
|
+
.nonnegative()
|
|
125
|
+
.optional()
|
|
126
|
+
.describe("epoch ms — return only records with `ts >= since`. Default 0 (return everything in the buffer)."),
|
|
127
|
+
...SESSION_ARG,
|
|
128
|
+
},
|
|
129
|
+
}, async ({ since, session }) => {
|
|
130
|
+
const g = gateCheck("device_requests");
|
|
131
|
+
if (g)
|
|
132
|
+
return g;
|
|
133
|
+
const e = await entryFor(session);
|
|
134
|
+
try {
|
|
135
|
+
const records = e.webDeviceEmulation.since(typeof since === "number" ? since : 0);
|
|
136
|
+
const body = {
|
|
137
|
+
ok: true,
|
|
138
|
+
session: e.id,
|
|
139
|
+
supportedApis: [...SUPPORTED_DEVICE_APIS],
|
|
140
|
+
requests: records,
|
|
141
|
+
};
|
|
142
|
+
body.tokensEstimate = estimateTokens(JSON.stringify(body));
|
|
143
|
+
return { content: [{ type: "text", text: JSON.stringify(body, null, 2) }] };
|
|
144
|
+
}
|
|
145
|
+
catch (err) {
|
|
146
|
+
return {
|
|
147
|
+
content: [
|
|
148
|
+
{
|
|
149
|
+
type: "text",
|
|
150
|
+
text: JSON.stringify({ ok: false, error: err instanceof Error ? err.message : String(err) }, null, 2),
|
|
151
|
+
},
|
|
152
|
+
],
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ToolHost } from "./host.js";
|
|
2
|
+
/**
|
|
3
|
+
* Session lifecycle + per-session policy tools — open / close / list sessions and
|
|
4
|
+
* the runtime policy mutators a session is driven with: dialog, permission,
|
|
5
|
+
* file-system-picker, and notification policies, plus the permission-state read
|
|
6
|
+
* and the device-request read companion.
|
|
7
|
+
*
|
|
8
|
+
* RFC 0004 P3 / D3 (SRP): the registrations were split by cohesive family into
|
|
9
|
+
* three sibling modules (lifecycle / dialog-permission-fs-picker /
|
|
10
|
+
* notification-device). This module stays the single entry point `server.ts` +
|
|
11
|
+
* `tool-metadata.ts` call, and invokes each family in the EXACT prior source order
|
|
12
|
+
* so the registered-name set + the derived maps stay byte-identical. The host owns
|
|
13
|
+
* the closures (register / gate / entry / registry / workspace); the family
|
|
14
|
+
* modules own the registrations.
|
|
15
|
+
*/
|
|
16
|
+
export declare function registerSessionPolicyTools(host: ToolHost): void;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { registerSessionLifecycleTools } from "./session-lifecycle-tools.js";
|
|
2
|
+
import { registerSessionDialogPermissionTools } from "./session-dialog-permission-tools.js";
|
|
3
|
+
import { registerSessionNotificationDeviceTools } from "./session-notification-device-tools.js";
|
|
4
|
+
/**
|
|
5
|
+
* Session lifecycle + per-session policy tools — open / close / list sessions and
|
|
6
|
+
* the runtime policy mutators a session is driven with: dialog, permission,
|
|
7
|
+
* file-system-picker, and notification policies, plus the permission-state read
|
|
8
|
+
* and the device-request read companion.
|
|
9
|
+
*
|
|
10
|
+
* RFC 0004 P3 / D3 (SRP): the registrations were split by cohesive family into
|
|
11
|
+
* three sibling modules (lifecycle / dialog-permission-fs-picker /
|
|
12
|
+
* notification-device). This module stays the single entry point `server.ts` +
|
|
13
|
+
* `tool-metadata.ts` call, and invokes each family in the EXACT prior source order
|
|
14
|
+
* so the registered-name set + the derived maps stay byte-identical. The host owns
|
|
15
|
+
* the closures (register / gate / entry / registry / workspace); the family
|
|
16
|
+
* modules own the registrations.
|
|
17
|
+
*/
|
|
18
|
+
export function registerSessionPolicyTools(host) {
|
|
19
|
+
registerSessionLifecycleTools(host);
|
|
20
|
+
registerSessionDialogPermissionTools(host);
|
|
21
|
+
registerSessionNotificationDeviceTools(host);
|
|
22
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { type EngineKind } from "../engine/index.js";
|
|
2
|
+
import "../engine/register-engines.js";
|
|
3
|
+
import { SessionRegistry, type SessionMode } from "../session/registry.js";
|
|
4
|
+
import type { CapabilityConfig } from "../util/capabilities.js";
|
|
5
|
+
import type { ConfigStore, ResolvedConfig } from "../util/config-store.js";
|
|
6
|
+
import type { Workspace } from "../util/workspace.js";
|
|
7
|
+
import type { StartOptions } from "../server.js";
|
|
8
|
+
/** The createServer-owned locals the SessionRegistry factory + teardown close
|
|
9
|
+
* over. Bundled here so the construction expression moves verbatim — every
|
|
10
|
+
* callback body references these exactly as it did inline in `createServer`. */
|
|
11
|
+
export interface SessionRegistryDeps {
|
|
12
|
+
opts: StartOptions;
|
|
13
|
+
resolvedConfig: ResolvedConfig;
|
|
14
|
+
configStore: ConfigStore;
|
|
15
|
+
caps: CapabilityConfig;
|
|
16
|
+
workspace: Workspace;
|
|
17
|
+
serverEngine: EngineKind;
|
|
18
|
+
serverDefaultMode: SessionMode;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Build the per-session `SessionRegistry` — the composition root's session
|
|
22
|
+
* factory + teardown pair. Moved out of `createServer` verbatim: the "default"
|
|
23
|
+
* session is still created lazily on the first browser-touching tool call, and
|
|
24
|
+
* every factory/teardown body is byte-identical to the inline version. The
|
|
25
|
+
* createServer locals each callback references (config, caps, workspace, …)
|
|
26
|
+
* arrive through `deps`.
|
|
27
|
+
*/
|
|
28
|
+
export declare function buildSessionRegistry(deps: SessionRegistryDeps): SessionRegistry;
|
|
@@ -0,0 +1,427 @@
|
|
|
1
|
+
import { openManagedSession } from "../session/managed.js";
|
|
2
|
+
import { openByobSession } from "../session/byob.js";
|
|
3
|
+
import { requireCdp } from "../engine/index.js";
|
|
4
|
+
import { engineEntry, byobAttachNeedsEndpoint, } from "../engine/registry.js";
|
|
5
|
+
import "../engine/register-engines.js";
|
|
6
|
+
import { openIncognitoSession } from "../session/incognito.js";
|
|
7
|
+
import { resolveDevice } from "../session/device.js";
|
|
8
|
+
import { newEmulationState } from "../session/emulation.js";
|
|
9
|
+
import { SessionRegistry, DEFAULT_SESSION_ID, } from "../session/registry.js";
|
|
10
|
+
import { newExtensionRegistry } from "../session/extensions.js";
|
|
11
|
+
import { WedgeTracker } from "../session/wedge.js";
|
|
12
|
+
import { SessionMetrics } from "../session/metrics.js";
|
|
13
|
+
import { DialogPolicyState } from "../session/dialog.js";
|
|
14
|
+
import { PermissionPolicyState } from "../session/permission.js";
|
|
15
|
+
import { NotificationPolicyState } from "../session/notification.js";
|
|
16
|
+
import { FsPickerPolicyState } from "../session/fs-picker.js";
|
|
17
|
+
import { DeviceEmulationState as WebDeviceEmulationState } from "../session/device-emu.js";
|
|
18
|
+
import { RefRegistry } from "../page/refs.js";
|
|
19
|
+
import { FrameRegistry } from "../page/frames.js";
|
|
20
|
+
import { RouteRegistry } from "../page/routes.js";
|
|
21
|
+
import { WsInteractiveRegistry } from "../page/ws-interactive.js";
|
|
22
|
+
import { WorkersRegistry } from "../page/workers.js";
|
|
23
|
+
import { EmulationRegistry } from "../page/emulation.js";
|
|
24
|
+
import { ClockRegistry } from "../page/clock.js";
|
|
25
|
+
import { SeededRandomRegistry } from "../page/seed-random.js";
|
|
26
|
+
import { PerfTracingState } from "../page/perf.js";
|
|
27
|
+
import { CoverageTrackerState } from "../page/coverage.js";
|
|
28
|
+
import { RegionRegistry } from "../page/regions.js";
|
|
29
|
+
import { DownloadsRegistry } from "../page/downloads.js";
|
|
30
|
+
import { ArtifactsRegistry } from "../session/artifacts.js";
|
|
31
|
+
import { readStorageStateFile, authLoad } from "../session/storage.js";
|
|
32
|
+
import { SecretRegistry } from "../util/secrets.js";
|
|
33
|
+
import { ClipboardBuffer } from "../page/clipboard.js";
|
|
34
|
+
import { ConsoleBuffer } from "../page/console.js";
|
|
35
|
+
import { newHarRecorderState, buildRecordHarOption, applyHarReplay, resolveHarReplayPaths, } from "../page/har.js";
|
|
36
|
+
import { newVideoRecorderState, buildRecordVideoOption, finalizeVideoOnClose, } from "../page/video.js";
|
|
37
|
+
import { BrowxBridge } from "../helper/bridge.js";
|
|
38
|
+
import { Recorder } from "../page/recording.js";
|
|
39
|
+
import { FeedbackMemory } from "../page/learning.js";
|
|
40
|
+
import { log } from "../util/logging.js";
|
|
41
|
+
/**
|
|
42
|
+
* Build the per-session `SessionRegistry` — the composition root's session
|
|
43
|
+
* factory + teardown pair. Moved out of `createServer` verbatim: the "default"
|
|
44
|
+
* session is still created lazily on the first browser-touching tool call, and
|
|
45
|
+
* every factory/teardown body is byte-identical to the inline version. The
|
|
46
|
+
* createServer locals each callback references (config, caps, workspace, …)
|
|
47
|
+
* arrive through `deps`.
|
|
48
|
+
*/
|
|
49
|
+
export function buildSessionRegistry(deps) {
|
|
50
|
+
const { opts, resolvedConfig, configStore, caps, workspace, serverEngine, serverDefaultMode } = deps;
|
|
51
|
+
// This server's OWN post-wire deps (caps / configStore / workspace) — threaded
|
|
52
|
+
// explicitly into `engineEntry(...).postWire(entry, serverPostWireDeps)` per
|
|
53
|
+
// session, never a module-global. A module-global would let a SECOND server in
|
|
54
|
+
// the same process (the in-process SDK transport composes one server per
|
|
55
|
+
// transport) overwrite this server's caps gate + workspace sandbox-root, so its
|
|
56
|
+
// post-wire could install another server's action-gated wrappers / stealth
|
|
57
|
+
// scripts on THIS server's sessions. The closure-owned local makes that
|
|
58
|
+
// impossible: every session this registry opens wires with exactly these deps.
|
|
59
|
+
const serverPostWireDeps = { caps, configStore, workspace };
|
|
60
|
+
// The substrate deps the registry needs to resolve a session's snapshot/network
|
|
61
|
+
// substrates. The registry only ever reads the bundle's `snapshot`/`network`
|
|
62
|
+
// selectors (the action/capture selectors — the only ones that consult
|
|
63
|
+
// ctxFor/describeTarget/save — are resolved in host-build's `substratesFor`, which
|
|
64
|
+
// owns those host locals). snapshot/network read only `e.session`, so the action/
|
|
65
|
+
// capture deps here are deliberately unreachable on this path; making them throw
|
|
66
|
+
// documents that the registry must never drive an action/capture substrate.
|
|
67
|
+
const registrySubstrateDeps = {
|
|
68
|
+
ctxFor: () => {
|
|
69
|
+
throw new Error("session-registry: ctxFor must not be reached — the registry resolves only the " +
|
|
70
|
+
"snapshot/network substrates (action/capture are host-build's concern).");
|
|
71
|
+
},
|
|
72
|
+
describeTarget: () => {
|
|
73
|
+
throw new Error("session-registry: describeTarget must not be reached (capture is host-build's concern).");
|
|
74
|
+
},
|
|
75
|
+
save: () => {
|
|
76
|
+
throw new Error("session-registry: save must not be reached (capture is host-build's concern).");
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
return new SessionRegistry(async (id, spec) => {
|
|
80
|
+
const headless = opts.headless ?? resolvedConfig.headless;
|
|
81
|
+
const mode = spec?.mode ?? serverDefaultMode;
|
|
82
|
+
// resolve the gated web-security flag *fresh* per session so a
|
|
83
|
+
// `set_config({disableWebSecurity})` takes effect on the next
|
|
84
|
+
// open_session without a server restart. Off by default.
|
|
85
|
+
const disableWebSecurity = configStore.resolve().disableWebSecurity === true;
|
|
86
|
+
// resolve device/viewport — spec overrides config-store defaults.
|
|
87
|
+
const device = resolveDevice({
|
|
88
|
+
device: spec?.device ?? resolvedConfig.defaultDevice,
|
|
89
|
+
viewport: spec?.viewport ?? resolvedConfig.defaultViewport,
|
|
90
|
+
});
|
|
91
|
+
// Resolve creation-time storageState (inline blob, workspace path, OR
|
|
92
|
+
// named slot). Mutually exclusive. `attached`/BYOB sessions ignore it
|
|
93
|
+
// (not-owned: we don't seed someone else's Chrome).
|
|
94
|
+
let creationStorageState;
|
|
95
|
+
if (spec?.storageState !== undefined && spec?.authState !== undefined) {
|
|
96
|
+
throw new Error(`session "${id}": pass exactly one of \`storageState\` or \`authState\` (not both)`);
|
|
97
|
+
}
|
|
98
|
+
if (spec?.authState !== undefined) {
|
|
99
|
+
creationStorageState = authLoad(workspace.root, spec.authState);
|
|
100
|
+
}
|
|
101
|
+
else if (typeof spec?.storageState === "string") {
|
|
102
|
+
creationStorageState = readStorageStateFile(workspace.root, spec.storageState, "open_session");
|
|
103
|
+
}
|
|
104
|
+
else if (spec?.storageState) {
|
|
105
|
+
creationStorageState = spec.storageState;
|
|
106
|
+
}
|
|
107
|
+
// Resolve HAR recording config (native context-creation primitive). The
|
|
108
|
+
// path is workspace-rooted by construction (resolveWorkspacePath rejects
|
|
109
|
+
// escape) and the parent dir is created up-front. Ignored on attached
|
|
110
|
+
// (we don't mutate the consumer's Chrome).
|
|
111
|
+
let creationRecordHar;
|
|
112
|
+
let creationRecordHarResolved;
|
|
113
|
+
if (spec?.har) {
|
|
114
|
+
const built = buildRecordHarOption(workspace.root, id, spec.har);
|
|
115
|
+
creationRecordHar = built.recordHar;
|
|
116
|
+
creationRecordHarResolved = { path: built.path, mode: built.mode, content: built.content };
|
|
117
|
+
}
|
|
118
|
+
// Resolve replay HAR paths (workspace-escape rejected; missing file
|
|
119
|
+
// errors loudly so a typo doesn't silently fall back to live network).
|
|
120
|
+
let creationReplayHars;
|
|
121
|
+
if (spec?.hars && spec.hars.length) {
|
|
122
|
+
creationReplayHars = resolveHarReplayPaths(workspace.root, spec.hars, "open_session");
|
|
123
|
+
}
|
|
124
|
+
// Resolve video recording config (native context-creation primitive).
|
|
125
|
+
// The target path is workspace-rooted by construction; the staging dir
|
|
126
|
+
// (where Playwright auto-names the file) is also under the workspace.
|
|
127
|
+
// Ignored on attached (we don't mutate the consumer's Chrome).
|
|
128
|
+
let creationRecordVideo;
|
|
129
|
+
let creationRecordVideoResolved;
|
|
130
|
+
if (spec?.recordVideo) {
|
|
131
|
+
const built = buildRecordVideoOption(workspace.root, id, spec.recordVideo);
|
|
132
|
+
creationRecordVideo = built.recordVideo;
|
|
133
|
+
creationRecordVideoResolved = {
|
|
134
|
+
targetPath: built.targetPath,
|
|
135
|
+
stagingDir: built.stagingDir,
|
|
136
|
+
size: built.size,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
let sess;
|
|
140
|
+
if (mode === "attached") {
|
|
141
|
+
// android attach is endpoint-DISCOVERED over adb — it does NOT need
|
|
142
|
+
// BROWX_ATTACH_CDP; the desktop CDP-attach lane still requires it. The
|
|
143
|
+
// android-specific fact lives in the engine layer (`byobAttachNeedsEndpoint`),
|
|
144
|
+
// so this precondition stays engine-agnostic (no `=== "android"` literal).
|
|
145
|
+
if (byobAttachNeedsEndpoint(serverEngine) && !opts.attachCdp) {
|
|
146
|
+
throw new Error(`session "${id}": mode "attached" requires the server to be started with BROWX_ATTACH_CDP (per-session attach isn't supported yet)`);
|
|
147
|
+
}
|
|
148
|
+
if (creationStorageState) {
|
|
149
|
+
log.warn(`session "${id}": ignoring storageState/authState for attached/BYOB session — ` +
|
|
150
|
+
"the consumer's Chrome is not-owned and we don't seed it. Use inject_storage_state " +
|
|
151
|
+
"explicitly if you really mean to overwrite the attached browser's state.");
|
|
152
|
+
}
|
|
153
|
+
if (creationRecordHar) {
|
|
154
|
+
log.warn(`session "${id}": ignoring \`har\` recording for attached/BYOB session — ` +
|
|
155
|
+
"the consumer's Chrome is not-owned and we don't wire context-creation primitives on it. " +
|
|
156
|
+
"Use `start_har` post-attach if you really want HAR on a BYOB session " +
|
|
157
|
+
"(it routes via runtime `routeFromHAR`, with the same finalize-on-context-close caveat).");
|
|
158
|
+
creationRecordHar = undefined;
|
|
159
|
+
creationRecordHarResolved = undefined;
|
|
160
|
+
}
|
|
161
|
+
if (creationRecordVideo) {
|
|
162
|
+
// Hard refusal: video has no runtime fallback (Playwright doesn't
|
|
163
|
+
// expose mid-context video start), so a silent ignore would leave
|
|
164
|
+
// the agent expecting a .webm that never lands. Surface it loudly.
|
|
165
|
+
throw new Error(`session "${id}": \`recordVideo\` is not supported on attached / BYOB sessions — ` +
|
|
166
|
+
"Playwright's `recordVideo` is a context-creation primitive and we don't " +
|
|
167
|
+
"wire context-creation primitives on the consumer's Chrome (not-owned). " +
|
|
168
|
+
'Open a managed session (open_session({mode:"persistent"}) or {mode:"incognito"}) ' +
|
|
169
|
+
"with {recordVideo:{...}} to record.");
|
|
170
|
+
}
|
|
171
|
+
// Attached Chrome is not-owned: device emulation is best-effort
|
|
172
|
+
// (viewport via Emulation in byob.ts); isMobile/touch/UA can't be
|
|
173
|
+
// retro-applied to an existing context.
|
|
174
|
+
sess = await openByobSession({
|
|
175
|
+
attachCdp: opts.attachCdp,
|
|
176
|
+
headless,
|
|
177
|
+
browserType: serverEngine,
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
else if (mode === "incognito") {
|
|
181
|
+
sess = await openIncognitoSession({
|
|
182
|
+
headless,
|
|
183
|
+
device,
|
|
184
|
+
disableWebSecurity,
|
|
185
|
+
storageState: creationStorageState,
|
|
186
|
+
recordHar: creationRecordHar,
|
|
187
|
+
recordVideo: creationRecordVideo,
|
|
188
|
+
browserType: serverEngine,
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
else {
|
|
192
|
+
// persistent: the default session keeps the legacy single `profile`
|
|
193
|
+
// dir for back-compat; named/explicit profiles get their own dir so
|
|
194
|
+
// sessions don't share a cookie jar on disk.
|
|
195
|
+
const profileDir = id === DEFAULT_SESSION_ID && !spec?.profile
|
|
196
|
+
? workspace.sub("profile")
|
|
197
|
+
: workspace.sub(`profiles/${spec?.profile ?? id}`);
|
|
198
|
+
// first launch — no extensions registered yet (the registry is
|
|
199
|
+
// mutated by the `extensions_*` tools post-creation, and a rebuild
|
|
200
|
+
// path materialises the list into launch flags then).
|
|
201
|
+
sess = await openManagedSession({
|
|
202
|
+
headless,
|
|
203
|
+
profileDir,
|
|
204
|
+
device,
|
|
205
|
+
disableWebSecurity,
|
|
206
|
+
storageState: creationStorageState,
|
|
207
|
+
recordHar: creationRecordHar,
|
|
208
|
+
recordVideo: creationRecordVideo,
|
|
209
|
+
browserType: serverEngine,
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
// Initialise HAR recorder state. If `recordHar` was wired at context
|
|
213
|
+
// creation, mark the recorder `active + nativeRecord:true` so
|
|
214
|
+
// `start_har` / `stop_har` can refuse cleanly (the native path can't be
|
|
215
|
+
// toggled mid-session — Playwright finalizes it on context.close()).
|
|
216
|
+
const harState = newHarRecorderState();
|
|
217
|
+
// The per-engine substrate bundle — the EngineRegistry resolves it once per
|
|
218
|
+
// session (RFC 0004 D1). The seven selectors (actions/capture/storage/script/
|
|
219
|
+
// emulation/snapshot/network) are the engine's own concern; here we use the
|
|
220
|
+
// snapshot/network pair to wire the session's substrates. A `{ session }`
|
|
221
|
+
// partial is enough for those two (they read only `e.session`); the substrate
|
|
222
|
+
// deps are this server's own (action/capture deps unreachable on this path).
|
|
223
|
+
const substrates = engineEntry(sess.engine).makeSubstrates(registrySubstrateDeps);
|
|
224
|
+
const substrateSeed = { session: sess };
|
|
225
|
+
// safari is the first non-Playwright engine: it has no Playwright Page, no
|
|
226
|
+
// Playwright BrowserContext. The few creation-config steps below that need
|
|
227
|
+
// the per-session creation locals (HAR/video state init, HAR replay) stay in
|
|
228
|
+
// the factory, keyed on the engine's Playwright-Page capability (`!sess.safari`
|
|
229
|
+
// — a capability check, not an engine-name branch). The full post-creation
|
|
230
|
+
// attach set (console / bridge / dialog / permission / notification /
|
|
231
|
+
// fs-picker / downloads / overlay / stealth / device-emulation / ws-interactive
|
|
232
|
+
// / workers) has been RELOCATED into the engine's `postWire` (called after the
|
|
233
|
+
// entry is assembled), so the 17 scattered `!== "safari"` guards collapse into
|
|
234
|
+
// one engine-agnostic call — byte-identical, only owned by the engine now.
|
|
235
|
+
const hasPlaywrightPage = !sess.safari;
|
|
236
|
+
if (creationRecordHarResolved && hasPlaywrightPage) {
|
|
237
|
+
harState.active = true;
|
|
238
|
+
harState.nativeRecord = true;
|
|
239
|
+
harState.path = creationRecordHarResolved.path;
|
|
240
|
+
harState.mode = creationRecordHarResolved.mode;
|
|
241
|
+
harState.content = creationRecordHarResolved.content;
|
|
242
|
+
harState.startedAt = Date.now();
|
|
243
|
+
}
|
|
244
|
+
// Initialise video recorder state. If `recordVideo` was wired at
|
|
245
|
+
// context creation, mark the recorder active so `stop_video` /
|
|
246
|
+
// `get_video` can refer to the reserved target path. The .webm is
|
|
247
|
+
// finalized when the context closes (Playwright constraint) —
|
|
248
|
+
// teardown calls `page.video().saveAs(targetPath)`.
|
|
249
|
+
const videoState = newVideoRecorderState();
|
|
250
|
+
if (creationRecordVideoResolved && hasPlaywrightPage) {
|
|
251
|
+
videoState.active = true;
|
|
252
|
+
videoState.targetPath = creationRecordVideoResolved.targetPath;
|
|
253
|
+
videoState.stagingDir = creationRecordVideoResolved.stagingDir;
|
|
254
|
+
videoState.size = creationRecordVideoResolved.size;
|
|
255
|
+
videoState.startedAt = Date.now();
|
|
256
|
+
}
|
|
257
|
+
// Apply HAR replay file(s) post-create. `routeFromHAR` is wired with
|
|
258
|
+
// `notFound:"fallback"` so a request not in the archive falls through
|
|
259
|
+
// to live network — the safer default. Replay is honoured on every
|
|
260
|
+
// session mode (incl. attached: the consumer's Chrome receives the
|
|
261
|
+
// route handler scoped to its context; warning emitted up-stream).
|
|
262
|
+
if (creationReplayHars && creationReplayHars.length && hasPlaywrightPage) {
|
|
263
|
+
await applyHarReplay(sess.page().context(), creationReplayHars);
|
|
264
|
+
}
|
|
265
|
+
// per-session console buffer. The page/BiDi attach is the engine's job —
|
|
266
|
+
// it runs in `postWire` (Playwright: `console.attach(page)`; Safari: the
|
|
267
|
+
// BiDi `log.entryAdded` bridge), so the buffer is built here and wired below.
|
|
268
|
+
const consoleBuf = new ConsoleBuffer();
|
|
269
|
+
// The network/WS substrate is selected by engine capability via the bundle:
|
|
270
|
+
// chromium (CDP present) gets the verbatim CDP NetworkBuffer/WsBuffer/tap;
|
|
271
|
+
// firefox/webkit get the Playwright context-event buffers; safari the no-op.
|
|
272
|
+
// The session-wide rings attach once here; the action window mints its
|
|
273
|
+
// per-action tap from the substrate and `network_body` fetches through it —
|
|
274
|
+
// so the network tools + the envelope's network slice run on every engine.
|
|
275
|
+
const networkSub = substrates.network(substrateSeed);
|
|
276
|
+
await networkSub.attach();
|
|
277
|
+
const networkBuf = networkSub.http;
|
|
278
|
+
const wsBuf = networkSub.ws;
|
|
279
|
+
// per-session secrets registry. Empty until `register_secret` is
|
|
280
|
+
// called; the egress sinks below all reference this same instance so
|
|
281
|
+
// a later register-call lights up masking globally for the session.
|
|
282
|
+
const secretsReg = new SecretRegistry();
|
|
283
|
+
consoleBuf.setSecrets(secretsReg);
|
|
284
|
+
networkSub.setSecrets(secretsReg);
|
|
285
|
+
const br = new BrowxBridge();
|
|
286
|
+
// dialog / permission / notification / fs-picker policy STATES are built
|
|
287
|
+
// here from the spec (the string parsing happened at the open_session tool
|
|
288
|
+
// layer); their per-context ATTACH lives in the engine's `postWire`.
|
|
289
|
+
const dialogState = new DialogPolicyState(spec?.dialogPolicy ?? { mode: "raise" });
|
|
290
|
+
const permissionState = new PermissionPolicyState(spec?.permissionPolicy ?? { mode: "raise" });
|
|
291
|
+
const notificationState = new NotificationPolicyState(spec?.notificationPolicy ?? { mode: "allow" });
|
|
292
|
+
const fsPickerState = new FsPickerPolicyState(spec?.fsPickerPolicy ?? { mode: "raise" });
|
|
293
|
+
// Per-session download capture. Storage dir is workspace-rooted +
|
|
294
|
+
// per-session — kept off the public profile dir so cleaning up captured
|
|
295
|
+
// artefacts is a single rmdir without touching the profile. The
|
|
296
|
+
// registry is off by default; the `downloads_capture` MCP tool toggles
|
|
297
|
+
// it. The context listener attach lives in the engine's `postWire`.
|
|
298
|
+
const downloadsDir = workspace.sub(`.downloads/${id}`);
|
|
299
|
+
const downloadsReg = new DownloadsRegistry(downloadsDir);
|
|
300
|
+
// Per-session artifact KV. Storage dir is workspace-rooted +
|
|
301
|
+
// per-session; the dir itself is created lazily on first save, and
|
|
302
|
+
// wiped on session teardown (see `teardown` below). Capacity-bounded
|
|
303
|
+
// — 200 entries / 50 MiB, oldest-write evicted.
|
|
304
|
+
const artifactsDir = workspace.sub(`.artifacts/${id}`);
|
|
305
|
+
const artifactsReg = new ArtifactsRegistry(artifactsDir);
|
|
306
|
+
// Fresh per-primitive device-emulation state (locale, timezone,
|
|
307
|
+
// geolocation, colour scheme, reduced motion, user-agent, permissions).
|
|
308
|
+
// Re-applied on every new page in this context so a mid-session-opened
|
|
309
|
+
// tab inherits the overrides — the page-event re-apply attach lives in the
|
|
310
|
+
// engine's `postWire`.
|
|
311
|
+
const deviceEmulation = newEmulationState();
|
|
312
|
+
// Per-session Web Bluetooth / WebUSB / WebHID synthetic-device catalogs
|
|
313
|
+
// (capability `device-emulation`). The init-script wrappers install in
|
|
314
|
+
// `postWire`; the catalog is off by default until the emulate_* tools
|
|
315
|
+
// populate it.
|
|
316
|
+
const webDeviceEmulation = new WebDeviceEmulationState(caps.enabled.has("device-emulation"));
|
|
317
|
+
const entry = {
|
|
318
|
+
id,
|
|
319
|
+
mode,
|
|
320
|
+
session: sess,
|
|
321
|
+
refs: new RefRegistry(),
|
|
322
|
+
// Engine-agnostic snapshot/a11y substrate, resolved from the engine's
|
|
323
|
+
// bundle (chromium → the verbatim CDP substrate; firefox/webkit → the
|
|
324
|
+
// page-side walker; safari → the WebDriver-Classic DOM-walk). Selected by
|
|
325
|
+
// the engine's capability, never an engine-name check. Captured once here
|
|
326
|
+
// so the hot snapshot/find path is a direct delegate, no per-call allocation.
|
|
327
|
+
snapshotSubstrate: substrates.snapshot(substrateSeed),
|
|
328
|
+
// Engine-agnostic network substrate (also from the bundle). `network` / `ws`
|
|
329
|
+
// below ARE this substrate's session-wide rings; the action window mints its
|
|
330
|
+
// per-action tap from it. Captured once here so the hot envelope path is a
|
|
331
|
+
// captured-handle delegate.
|
|
332
|
+
networkSubstrate: networkSub,
|
|
333
|
+
frames: new FrameRegistry(),
|
|
334
|
+
console: consoleBuf,
|
|
335
|
+
network: networkBuf,
|
|
336
|
+
ws: wsBuf,
|
|
337
|
+
bridge: br,
|
|
338
|
+
recorder: new Recorder(),
|
|
339
|
+
feedback: new FeedbackMemory(),
|
|
340
|
+
clipboard: new ClipboardBuffer(),
|
|
341
|
+
routes: new RouteRegistry(),
|
|
342
|
+
// The page-side WS-interactive + workers wrappers install EAGERLY — but
|
|
343
|
+
// that install is a Playwright-Page concern, so it has moved into the
|
|
344
|
+
// engine's `postWire` (capability-gated on `action` / `read`). Here we
|
|
345
|
+
// build the empty registries; `postWire` installs the page wrappers before
|
|
346
|
+
// the session is handed to a tool call (byte-identical eager-install timing).
|
|
347
|
+
wsInteractive: new WsInteractiveRegistry(),
|
|
348
|
+
workers: new WorkersRegistry(),
|
|
349
|
+
regions: new RegionRegistry(),
|
|
350
|
+
emulation: new EmulationRegistry(),
|
|
351
|
+
clock: new ClockRegistry(),
|
|
352
|
+
seededRandom: new SeededRandomRegistry(),
|
|
353
|
+
perf: new PerfTracingState(),
|
|
354
|
+
coverage: new CoverageTrackerState(),
|
|
355
|
+
wedge: new WedgeTracker(),
|
|
356
|
+
metrics: new SessionMetrics(),
|
|
357
|
+
dialog: dialogState,
|
|
358
|
+
permission: permissionState,
|
|
359
|
+
notification: notificationState,
|
|
360
|
+
fsPicker: fsPickerState,
|
|
361
|
+
deviceEmulation,
|
|
362
|
+
webDeviceEmulation,
|
|
363
|
+
har: harState,
|
|
364
|
+
video: videoState,
|
|
365
|
+
secrets: secretsReg,
|
|
366
|
+
extensions: newExtensionRegistry(),
|
|
367
|
+
downloads: downloadsReg,
|
|
368
|
+
artifacts: artifactsReg,
|
|
369
|
+
...(mode === "persistent" ? { launchProfile: spec?.profile ?? id } : {}),
|
|
370
|
+
openedAt: Date.now(),
|
|
371
|
+
lastActivityAt: Date.now(),
|
|
372
|
+
};
|
|
373
|
+
// Post-creation wiring — the engine owns its own bookkeeping (RFC 0004 D1).
|
|
374
|
+
// The four Playwright engines attach the full console/bridge/policy/download/
|
|
375
|
+
// stealth/device-emulation/ws-interactive/workers set + await it; safari
|
|
376
|
+
// attaches only its BiDi console bridge; a no-Page engine attaches nothing.
|
|
377
|
+
// This is the one call the 17 scattered `!== "safari"` guards collapsed into.
|
|
378
|
+
// The per-server deps are passed explicitly (never a module-global) so a
|
|
379
|
+
// second server in this process can never wire THIS session with its caps or
|
|
380
|
+
// sandbox root.
|
|
381
|
+
await engineEntry(sess.engine).postWire(entry, serverPostWireDeps);
|
|
382
|
+
return entry;
|
|
383
|
+
}, async (e) => {
|
|
384
|
+
// Stop any in-flight perf trace BEFORE closing CDP — otherwise the
|
|
385
|
+
// attached Chrome (BYOB) keeps the trace buffer pinned. Best-effort:
|
|
386
|
+
// a stuck Tracing.end won't block teardown (perf state bounds the wait).
|
|
387
|
+
// Keyed on the Playwright-Page capability (`!e.session.safari`), not an
|
|
388
|
+
// engine-name branch — Safari has no CDP, so `requireCdp` would refuse.
|
|
389
|
+
const teardownHasCdp = !e.session.safari;
|
|
390
|
+
if (teardownHasCdp)
|
|
391
|
+
await e.perf.closeIfRunning(requireCdp(e.session)).catch(() => undefined);
|
|
392
|
+
// also release any in-flight Profiler/CSS coverage on
|
|
393
|
+
// the attached target so a BYOB Chrome doesn't keep coverage state
|
|
394
|
+
// pinned past detach.
|
|
395
|
+
if (teardownHasCdp)
|
|
396
|
+
await e.coverage.closeIfRunning(requireCdp(e.session)).catch(() => undefined);
|
|
397
|
+
// workers registry CDP listeners. Detach before CDP closes
|
|
398
|
+
// so we don't race the parent session shutdown.
|
|
399
|
+
try {
|
|
400
|
+
e.workers.dispose();
|
|
401
|
+
}
|
|
402
|
+
catch {
|
|
403
|
+
/* best-effort */
|
|
404
|
+
}
|
|
405
|
+
await e.bridge.detach().catch(() => undefined);
|
|
406
|
+
// Capture page reference BEFORE close — `page.video()` resolves the
|
|
407
|
+
// Video handle, but the actual .webm is only flushed by the underlying
|
|
408
|
+
// context.close() that `e.session.close()` triggers. `video.saveAs()`
|
|
409
|
+
// (called inside finalizeVideoOnClose) blocks until the page is closed
|
|
410
|
+
// AND the recording is fully written, so the order is: grab page →
|
|
411
|
+
// close context → saveAs to deterministic target path.
|
|
412
|
+
const videoPage = e.video.active ? e.session.page() : undefined;
|
|
413
|
+
await e.session.close().catch(() => undefined);
|
|
414
|
+
if (videoPage) {
|
|
415
|
+
await finalizeVideoOnClose(videoPage, e.video).catch(() => undefined);
|
|
416
|
+
}
|
|
417
|
+
// Clear session-scoped artifacts on teardown. Best-effort: a stuck
|
|
418
|
+
// rm won't block teardown. Sessions that never wrote an artifact
|
|
419
|
+
// never create the dir, so this is a no-op for them.
|
|
420
|
+
try {
|
|
421
|
+
e.artifacts.clear();
|
|
422
|
+
}
|
|
423
|
+
catch {
|
|
424
|
+
/* best-effort */
|
|
425
|
+
}
|
|
426
|
+
});
|
|
427
|
+
}
|