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,105 @@
|
|
|
1
|
+
// memory_diff — capability `read`. Pure-function consumer of two
|
|
2
|
+
// `.heapsnapshot` files. No browser interaction.
|
|
3
|
+
//
|
|
4
|
+
// "Take a snapshot → do thing → take another snapshot → who grew?" is the
|
|
5
|
+
// canonical leak-detection workflow. The two snapshots are the existing
|
|
6
|
+
// `heap_snapshot` tool output. This tool diffs them: groups nodes by
|
|
7
|
+
// `${type}:${name}`, sums self_size per group, reports per-group deltas
|
|
8
|
+
// (sizeBefore / sizeAfter / deltaBytes / deltaPercent / type).
|
|
9
|
+
//
|
|
10
|
+
// Noise filter: groups with `|deltaBytes| < 1024` are dropped — sub-KB
|
|
11
|
+
// noise is rampant in V8 heaps and crowds the actionable signal.
|
|
12
|
+
//
|
|
13
|
+
// Reuses the snapshot parser from `src/page/heap.ts`.
|
|
14
|
+
import { resolve, sep } from "node:path";
|
|
15
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
16
|
+
import { parseHeapSnapshot } from "./heap.js";
|
|
17
|
+
const NOISE_FILTER_BYTES = 1024;
|
|
18
|
+
const MAX_GROWTH_ROWS = 100;
|
|
19
|
+
/** Workspace-rooted path helper — same shape as `resolvePerfTracePath`. */
|
|
20
|
+
export function resolveHeapPath(workspaceRoot, p, tool) {
|
|
21
|
+
const resolved = resolve(workspaceRoot, p);
|
|
22
|
+
if (resolved !== workspaceRoot && !resolved.startsWith(workspaceRoot + sep)) {
|
|
23
|
+
throw new Error(`${tool}: paths must resolve inside $BROWX_WORKSPACE — got "${p}".`);
|
|
24
|
+
}
|
|
25
|
+
return resolved;
|
|
26
|
+
}
|
|
27
|
+
/** Pure aggregator — group nodes by `${type}:${name}` and sum self_size.
|
|
28
|
+
* Exported for unit tests against tiny in-memory snapshot JSON values. */
|
|
29
|
+
export function aggregateNodeSizes(parsed) {
|
|
30
|
+
const out = new Map();
|
|
31
|
+
const total = parsed.nodes.length / parsed.nodeFieldCount;
|
|
32
|
+
for (let i = 0; i < total; i++) {
|
|
33
|
+
const base = i * parsed.nodeFieldCount;
|
|
34
|
+
const typeIdx = parsed.nodes[base + parsed.fieldIdx.nodeType] ?? 0;
|
|
35
|
+
const nameIdx = parsed.nodes[base + parsed.fieldIdx.nodeName] ?? 0;
|
|
36
|
+
const selfSize = parsed.nodes[base + parsed.fieldIdx.nodeSelfSize] ?? 0;
|
|
37
|
+
const type = parsed.nodeTypes[typeIdx] ?? "";
|
|
38
|
+
const name = parsed.strings[nameIdx] ?? "";
|
|
39
|
+
const display = type && name ? `${type}:${name}` : name || type || "<unknown>";
|
|
40
|
+
const slot = out.get(display);
|
|
41
|
+
if (slot)
|
|
42
|
+
slot.size += selfSize;
|
|
43
|
+
else
|
|
44
|
+
out.set(display, { type, name, size: selfSize });
|
|
45
|
+
}
|
|
46
|
+
return out;
|
|
47
|
+
}
|
|
48
|
+
/** Pure diff helper — given two aggregator maps, return the growth report.
|
|
49
|
+
* Exported for unit tests. */
|
|
50
|
+
export function diffSizeMaps(before, after) {
|
|
51
|
+
const keys = new Set();
|
|
52
|
+
for (const k of before.keys())
|
|
53
|
+
keys.add(k);
|
|
54
|
+
for (const k of after.keys())
|
|
55
|
+
keys.add(k);
|
|
56
|
+
const rows = [];
|
|
57
|
+
let totalGrowth = 0;
|
|
58
|
+
for (const k of keys) {
|
|
59
|
+
const b = before.get(k);
|
|
60
|
+
const a = after.get(k);
|
|
61
|
+
const sizeBefore = b?.size ?? 0;
|
|
62
|
+
const sizeAfter = a?.size ?? 0;
|
|
63
|
+
const deltaBytes = sizeAfter - sizeBefore;
|
|
64
|
+
if (Math.abs(deltaBytes) < NOISE_FILTER_BYTES)
|
|
65
|
+
continue;
|
|
66
|
+
const type = a?.type ?? b?.type ?? "";
|
|
67
|
+
const deltaPercent = sizeBefore === 0 ? "+inf" : Math.round((deltaBytes / sizeBefore) * 10000) / 100;
|
|
68
|
+
rows.push({
|
|
69
|
+
node: k,
|
|
70
|
+
type,
|
|
71
|
+
sizeBefore,
|
|
72
|
+
sizeAfter,
|
|
73
|
+
deltaBytes,
|
|
74
|
+
deltaPercent,
|
|
75
|
+
});
|
|
76
|
+
if (deltaBytes > 0)
|
|
77
|
+
totalGrowth += deltaBytes;
|
|
78
|
+
}
|
|
79
|
+
rows.sort((a, b) => b.deltaBytes - a.deltaBytes);
|
|
80
|
+
const top3 = rows.slice(0, 3).map((r) => ({
|
|
81
|
+
node: r.node,
|
|
82
|
+
deltaBytes: r.deltaBytes,
|
|
83
|
+
deltaPercent: r.deltaPercent,
|
|
84
|
+
}));
|
|
85
|
+
return {
|
|
86
|
+
retainerGrowth: rows.slice(0, MAX_GROWTH_ROWS),
|
|
87
|
+
summary: { totalGrowth, top3Growers: top3 },
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
/** Diff two heap snapshots at the given workspace-rooted paths. */
|
|
91
|
+
export function diffHeapSnapshots(workspaceRoot, beforePath, afterPath, tool = "memory_diff") {
|
|
92
|
+
const beforeResolved = resolveHeapPath(workspaceRoot, beforePath, tool);
|
|
93
|
+
const afterResolved = resolveHeapPath(workspaceRoot, afterPath, tool);
|
|
94
|
+
if (!existsSync(beforeResolved)) {
|
|
95
|
+
throw new Error(`${tool}: beforePath not found at "${beforeResolved}"`);
|
|
96
|
+
}
|
|
97
|
+
if (!existsSync(afterResolved)) {
|
|
98
|
+
throw new Error(`${tool}: afterPath not found at "${afterResolved}"`);
|
|
99
|
+
}
|
|
100
|
+
const beforeParsed = parseHeapSnapshot(readFileSync(beforeResolved, "utf8"));
|
|
101
|
+
const afterParsed = parseHeapSnapshot(readFileSync(afterResolved, "utf8"));
|
|
102
|
+
const beforeMap = aggregateNodeSizes(beforeParsed);
|
|
103
|
+
const afterMap = aggregateNodeSizes(afterParsed);
|
|
104
|
+
return diffSizeMaps(beforeMap, afterMap);
|
|
105
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { SecretRegistry } from "../util/secrets.js";
|
|
2
|
+
/** Apply the URL sanitiser (strips credentials / secret-shaped query
|
|
3
|
+
* params) then the per-session secrets-masking layer. Order matters:
|
|
4
|
+
* secrets-masking is literal substring; the URL sanitiser may already
|
|
5
|
+
* have stripped a credentialled query, but a real-value that landed in
|
|
6
|
+
* the path is still caught by the literal scan after. */
|
|
7
|
+
export declare function maskedUrl(url: string, secrets: SecretRegistry | null): string;
|
|
8
|
+
export declare function maskedText(text: string, secrets: SecretRegistry | null): string;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// Shared egress-masking helpers for the network/WebSocket capture modules.
|
|
2
|
+
// One chokepoint so the URL-sanitiser + per-session secrets-masking order is
|
|
3
|
+
// identical across the CDP (`network.ts`), Playwright (`network-playwright.ts`),
|
|
4
|
+
// and WebSocket (`network-ws.ts`) paths.
|
|
5
|
+
import { sanitizeUrl, sanitizeUrlsInText } from "../util/url-sanitizer.js";
|
|
6
|
+
/** Apply the URL sanitiser (strips credentials / secret-shaped query
|
|
7
|
+
* params) then the per-session secrets-masking layer. Order matters:
|
|
8
|
+
* secrets-masking is literal substring; the URL sanitiser may already
|
|
9
|
+
* have stripped a credentialled query, but a real-value that landed in
|
|
10
|
+
* the path is still caught by the literal scan after. */
|
|
11
|
+
export function maskedUrl(url, secrets) {
|
|
12
|
+
const u = sanitizeUrl(url);
|
|
13
|
+
return secrets ? secrets.applyMaskInText(u) : u;
|
|
14
|
+
}
|
|
15
|
+
export function maskedText(text, secrets) {
|
|
16
|
+
const t = sanitizeUrlsInText(text);
|
|
17
|
+
return secrets ? secrets.applyMaskInText(t) : t;
|
|
18
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import type { BrowserContext, Page } from "playwright-core";
|
|
2
|
+
import type { SecretRegistry } from "../util/secrets.js";
|
|
3
|
+
import { type MutationEntry, type NetworkEntry, type NetworkSummary } from "./network.js";
|
|
4
|
+
import { type WsFrame } from "./network-ws.js";
|
|
5
|
+
/** Action-window network tap on Playwright context events — the off-Chromium
|
|
6
|
+
* twin of `NetworkTap`. Same lifecycle (`open()` before dispatch, `close()`
|
|
7
|
+
* after settle) and same `{summary, requests, mutations}` return shape. */
|
|
8
|
+
export declare class PlaywrightNetworkTap {
|
|
9
|
+
private context;
|
|
10
|
+
private secrets;
|
|
11
|
+
private pending;
|
|
12
|
+
private finished;
|
|
13
|
+
private mutationPromises;
|
|
14
|
+
private listeners;
|
|
15
|
+
constructor(context: BrowserContext, secrets?: SecretRegistry | null);
|
|
16
|
+
open(): Promise<void>;
|
|
17
|
+
close(): Promise<{
|
|
18
|
+
summary: NetworkSummary;
|
|
19
|
+
requests: NetworkEntry[];
|
|
20
|
+
mutations: MutationEntry[];
|
|
21
|
+
}>;
|
|
22
|
+
}
|
|
23
|
+
/** Session-wide network ring on Playwright context events — the off-Chromium
|
|
24
|
+
* twin of `NetworkBuffer`. Same ring + `recent()` / `iter()` shape; additionally
|
|
25
|
+
* captures response bodies at response time into a bounded LRU so `network_body`
|
|
26
|
+
* can resolve a `requestId` after the fact (there is no off-Chromium analogue of
|
|
27
|
+
* CDP `Network.getResponseBody`'s lazy fetch). */
|
|
28
|
+
export declare class PlaywrightNetworkBuffer {
|
|
29
|
+
private context;
|
|
30
|
+
private cap;
|
|
31
|
+
/** how many recent response bodies to retain for `network_body`. Bounded so
|
|
32
|
+
* capturing every body doesn't grow unbounded (the doctrine: bound the
|
|
33
|
+
* buffer). Default 50 — the agent fetches a body right after the request. */
|
|
34
|
+
private bodyCap;
|
|
35
|
+
private maxBodyBytes;
|
|
36
|
+
private ring;
|
|
37
|
+
private ids;
|
|
38
|
+
/** captured bodies keyed by synthetic request id, bounded LRU. */
|
|
39
|
+
private bodies;
|
|
40
|
+
private enabled;
|
|
41
|
+
private secrets;
|
|
42
|
+
constructor(context: BrowserContext, cap?: number,
|
|
43
|
+
/** how many recent response bodies to retain for `network_body`. Bounded so
|
|
44
|
+
* capturing every body doesn't grow unbounded (the doctrine: bound the
|
|
45
|
+
* buffer). Default 50 — the agent fetches a body right after the request. */
|
|
46
|
+
bodyCap?: number, maxBodyBytes?: number);
|
|
47
|
+
setSecrets(secrets: SecretRegistry): void;
|
|
48
|
+
attach(): Promise<void>;
|
|
49
|
+
private captureBody;
|
|
50
|
+
private push;
|
|
51
|
+
/** Raw, read-only snapshot of the ring (asset_export iterates this). */
|
|
52
|
+
iter(): readonly NetworkEntry[];
|
|
53
|
+
/** Most-recent N entries; noise + beacons folded into `other`. */
|
|
54
|
+
recent(limit?: number): {
|
|
55
|
+
summary: NetworkSummary;
|
|
56
|
+
requests: NetworkEntry[];
|
|
57
|
+
};
|
|
58
|
+
/** Resolve a `requestId` to its captured body. Bytes were stored as a Buffer
|
|
59
|
+
* at response time; emit as utf-8 unless they aren't valid text, in which case
|
|
60
|
+
* base64 (matching the CDP `Network.getResponseBody` base64Encoded contract).
|
|
61
|
+
* Secrets masking is applied to text bodies (base64 passes through, same as
|
|
62
|
+
* the CDP path). */
|
|
63
|
+
fetchBody(requestId: string, secrets: SecretRegistry | null): Promise<{
|
|
64
|
+
ok: boolean;
|
|
65
|
+
body?: string;
|
|
66
|
+
base64Encoded?: boolean;
|
|
67
|
+
truncated?: boolean;
|
|
68
|
+
error?: string;
|
|
69
|
+
}>;
|
|
70
|
+
}
|
|
71
|
+
/** Session-wide WebSocket/SSE ring on Playwright events — the off-Chromium twin
|
|
72
|
+
* of `WsBuffer`. `page.on('websocket')` + `ws.on('framesent'|'framereceived')`
|
|
73
|
+
* are cross-browser. Server-Sent-Events are not exposed as a discrete Playwright
|
|
74
|
+
* event (they arrive as a long-lived `eventsource` response, not WS frames), so
|
|
75
|
+
* the SSE half degrades off Chromium — documented in the per-engine matrix. */
|
|
76
|
+
export declare class PlaywrightWsBuffer {
|
|
77
|
+
private page;
|
|
78
|
+
private cap;
|
|
79
|
+
private maxPayload;
|
|
80
|
+
private ring;
|
|
81
|
+
private enabled;
|
|
82
|
+
private secrets;
|
|
83
|
+
constructor(page: Page, cap?: number, maxPayload?: number);
|
|
84
|
+
setSecrets(secrets: SecretRegistry): void;
|
|
85
|
+
private trunc;
|
|
86
|
+
private push;
|
|
87
|
+
attach(): Promise<void>;
|
|
88
|
+
private frame;
|
|
89
|
+
/** Most-recent N frames, optionally filtered by a url substring. */
|
|
90
|
+
recent(limit?: number, urlPattern?: string): {
|
|
91
|
+
total: number;
|
|
92
|
+
frames: WsFrame[];
|
|
93
|
+
};
|
|
94
|
+
/** Frames since a timestamp — for the per-action `ActionResult` slice. */
|
|
95
|
+
since(ts: number, cap?: number): WsFrame[];
|
|
96
|
+
}
|
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
// Off-Chromium network/WebSocket capture — the Playwright-events twin of the
|
|
2
|
+
// CDP classes in `network.ts`.
|
|
3
|
+
//
|
|
4
|
+
// Firefox/WebKit have no CDP `Network.*` domain (Firefox removed CDP in v141),
|
|
5
|
+
// so the network slice rides Playwright's cross-browser context events instead:
|
|
6
|
+
// - `context.on('request')` → a pending request (mirrors requestWillBeSent)
|
|
7
|
+
// - `context.on('response')` → status arrived (mirrors responseReceived)
|
|
8
|
+
// - `context.on('requestfailed')` → load error (mirrors loadingFailed)
|
|
9
|
+
// - `context.on('requestfinished')`→ encoded byte size (mirrors loadingFinished)
|
|
10
|
+
// - `page.on('websocket')` + `ws.on('framesent'|'framereceived')` → WS frames
|
|
11
|
+
//
|
|
12
|
+
// These classes produce byte-identical egress shapes to the CDP ones (the same
|
|
13
|
+
// NetworkEntry / NetworkSummary / MutationEntry / WsFrame, the same noise-fold via
|
|
14
|
+
// `foldInteresting`, the same secrets masking), so every consumer above the seam
|
|
15
|
+
// is engine-blind. Playwright `Request` objects have no protocol id, so a
|
|
16
|
+
// monotonic synthetic id is minted per request and used as the `requestId` handle
|
|
17
|
+
// `network_body` resolves. Re-exported through `./network.js` so callers import
|
|
18
|
+
// the whole network surface from the one barrel, unchanged.
|
|
19
|
+
import { cdpTypeFromPlaywright, extractTopLevelKeys, foldInteresting, mutationWithoutShape, mutationWithShape, MAX_BODY_BYTES_TO_PARSE, MUTATION_METHODS, } from "./network.js";
|
|
20
|
+
import { sanitizeFrame } from "./network-ws.js";
|
|
21
|
+
let pwRequestSeq = 0;
|
|
22
|
+
function nextPwRequestId() {
|
|
23
|
+
return `pw-${(pwRequestSeq = (pwRequestSeq + 1) % Number.MAX_SAFE_INTEGER)}`;
|
|
24
|
+
}
|
|
25
|
+
/** Best-effort mutation-detail probe over a Playwright `Response` (the off-
|
|
26
|
+
* Chromium analogue of `probeMutation`). Reads the body via `response.body()`
|
|
27
|
+
* (cross-browser), extracts only the top-level JSON keys. Returns null on any
|
|
28
|
+
* failure so the caller filters nulls out, identical to the CDP probe. */
|
|
29
|
+
async function probeMutationPlaywright(response, detail) {
|
|
30
|
+
try {
|
|
31
|
+
const buf = await response.body();
|
|
32
|
+
if (buf.length > MAX_BODY_BYTES_TO_PARSE)
|
|
33
|
+
return mutationWithoutShape(detail);
|
|
34
|
+
const trimmed = buf.toString("utf-8").trim();
|
|
35
|
+
if (!trimmed)
|
|
36
|
+
return mutationWithoutShape(detail);
|
|
37
|
+
if (trimmed[0] !== "{" && trimmed[0] !== "[")
|
|
38
|
+
return mutationWithoutShape(detail);
|
|
39
|
+
const parsed = JSON.parse(trimmed);
|
|
40
|
+
return mutationWithShape(detail, extractTopLevelKeys(parsed));
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/** Action-window network tap on Playwright context events — the off-Chromium
|
|
47
|
+
* twin of `NetworkTap`. Same lifecycle (`open()` before dispatch, `close()`
|
|
48
|
+
* after settle) and same `{summary, requests, mutations}` return shape. */
|
|
49
|
+
export class PlaywrightNetworkTap {
|
|
50
|
+
context;
|
|
51
|
+
secrets;
|
|
52
|
+
pending = new Map();
|
|
53
|
+
finished = [];
|
|
54
|
+
mutationPromises = [];
|
|
55
|
+
listeners = [];
|
|
56
|
+
constructor(context, secrets = null) {
|
|
57
|
+
this.context = context;
|
|
58
|
+
this.secrets = secrets;
|
|
59
|
+
}
|
|
60
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
61
|
+
async open() {
|
|
62
|
+
this.pending.clear();
|
|
63
|
+
this.finished = [];
|
|
64
|
+
this.mutationPromises = [];
|
|
65
|
+
const onRequest = (req) => {
|
|
66
|
+
this.pending.set(req, {
|
|
67
|
+
method: req.method(),
|
|
68
|
+
url: req.url(),
|
|
69
|
+
type: cdpTypeFromPlaywright(req.resourceType()),
|
|
70
|
+
startedAt: Date.now(),
|
|
71
|
+
});
|
|
72
|
+
};
|
|
73
|
+
const onResponse = (res) => {
|
|
74
|
+
const req = res.request();
|
|
75
|
+
const r = this.pending.get(req);
|
|
76
|
+
if (!r)
|
|
77
|
+
return;
|
|
78
|
+
const ms = Date.now() - r.startedAt;
|
|
79
|
+
const status = res.status();
|
|
80
|
+
this.finished.push({ method: r.method, url: r.url, status, type: r.type, ms });
|
|
81
|
+
if (MUTATION_METHODS.has(r.method) && status >= 200 && status < 300) {
|
|
82
|
+
this.mutationPromises.push(probeMutationPlaywright(res, { method: r.method, url: r.url, status, durationMs: ms }));
|
|
83
|
+
}
|
|
84
|
+
this.pending.delete(req);
|
|
85
|
+
};
|
|
86
|
+
const onFailed = (req) => {
|
|
87
|
+
const r = this.pending.get(req);
|
|
88
|
+
if (!r)
|
|
89
|
+
return;
|
|
90
|
+
this.finished.push({
|
|
91
|
+
method: r.method,
|
|
92
|
+
url: r.url,
|
|
93
|
+
type: r.type,
|
|
94
|
+
failed: true,
|
|
95
|
+
ms: Date.now() - r.startedAt,
|
|
96
|
+
});
|
|
97
|
+
this.pending.delete(req);
|
|
98
|
+
};
|
|
99
|
+
this.context.on("request", onRequest);
|
|
100
|
+
this.context.on("response", onResponse);
|
|
101
|
+
this.context.on("requestfailed", onFailed);
|
|
102
|
+
this.listeners = [
|
|
103
|
+
() => this.context.off("request", onRequest),
|
|
104
|
+
() => this.context.off("response", onResponse),
|
|
105
|
+
() => this.context.off("requestfailed", onFailed),
|
|
106
|
+
];
|
|
107
|
+
}
|
|
108
|
+
async close() {
|
|
109
|
+
for (const off of this.listeners)
|
|
110
|
+
off();
|
|
111
|
+
this.listeners = [];
|
|
112
|
+
const { summary, requests } = foldInteresting(this.finished, this.secrets);
|
|
113
|
+
const mutationsRaw = (await Promise.all(this.mutationPromises)).filter((m) => m !== null);
|
|
114
|
+
const mutations = mutationsRaw.map((m) => {
|
|
115
|
+
const out = {
|
|
116
|
+
...m,
|
|
117
|
+
urlPattern: this.secrets ? this.secrets.applyMaskInText(m.urlPattern) : m.urlPattern,
|
|
118
|
+
};
|
|
119
|
+
if (m.responseShape && this.secrets) {
|
|
120
|
+
out.responseShape = m.responseShape.map((k) => this.secrets.applyMaskInText(k));
|
|
121
|
+
}
|
|
122
|
+
return out;
|
|
123
|
+
});
|
|
124
|
+
return { summary, requests, mutations };
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
/** Session-wide network ring on Playwright context events — the off-Chromium
|
|
128
|
+
* twin of `NetworkBuffer`. Same ring + `recent()` / `iter()` shape; additionally
|
|
129
|
+
* captures response bodies at response time into a bounded LRU so `network_body`
|
|
130
|
+
* can resolve a `requestId` after the fact (there is no off-Chromium analogue of
|
|
131
|
+
* CDP `Network.getResponseBody`'s lazy fetch). */
|
|
132
|
+
export class PlaywrightNetworkBuffer {
|
|
133
|
+
context;
|
|
134
|
+
cap;
|
|
135
|
+
bodyCap;
|
|
136
|
+
maxBodyBytes;
|
|
137
|
+
ring = [];
|
|
138
|
+
ids = new WeakMap();
|
|
139
|
+
/** captured bodies keyed by synthetic request id, bounded LRU. */
|
|
140
|
+
bodies = new Map();
|
|
141
|
+
enabled = false;
|
|
142
|
+
secrets = null;
|
|
143
|
+
constructor(context, cap = 500,
|
|
144
|
+
/** how many recent response bodies to retain for `network_body`. Bounded so
|
|
145
|
+
* capturing every body doesn't grow unbounded (the doctrine: bound the
|
|
146
|
+
* buffer). Default 50 — the agent fetches a body right after the request. */
|
|
147
|
+
bodyCap = 50, maxBodyBytes = 256_000) {
|
|
148
|
+
this.context = context;
|
|
149
|
+
this.cap = cap;
|
|
150
|
+
this.bodyCap = bodyCap;
|
|
151
|
+
this.maxBodyBytes = maxBodyBytes;
|
|
152
|
+
}
|
|
153
|
+
setSecrets(secrets) {
|
|
154
|
+
this.secrets = secrets;
|
|
155
|
+
}
|
|
156
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
157
|
+
async attach() {
|
|
158
|
+
if (this.enabled)
|
|
159
|
+
return;
|
|
160
|
+
this.enabled = true;
|
|
161
|
+
this.context.on("request", (req) => {
|
|
162
|
+
this.ids.set(req, nextPwRequestId());
|
|
163
|
+
});
|
|
164
|
+
this.context.on("response", (res) => {
|
|
165
|
+
const req = res.request();
|
|
166
|
+
const id = this.ids.get(req) ?? nextPwRequestId();
|
|
167
|
+
const entry = {
|
|
168
|
+
method: req.method(),
|
|
169
|
+
url: req.url(),
|
|
170
|
+
status: res.status(),
|
|
171
|
+
type: cdpTypeFromPlaywright(req.resourceType()),
|
|
172
|
+
ms: 0,
|
|
173
|
+
requestId: id,
|
|
174
|
+
};
|
|
175
|
+
const mime = res.headers()["content-type"];
|
|
176
|
+
if (mime)
|
|
177
|
+
entry.mimeType = mime;
|
|
178
|
+
this.push(entry);
|
|
179
|
+
// capture the body at response time (bounded) — bodies aren't fetchable
|
|
180
|
+
// after the fact off Chromium. Best-effort: a failed read leaves no cache
|
|
181
|
+
// entry and `network_body` reports "not available".
|
|
182
|
+
void this.captureBody(id, res);
|
|
183
|
+
});
|
|
184
|
+
this.context.on("requestfinished", (req) => {
|
|
185
|
+
const id = this.ids.get(req);
|
|
186
|
+
if (!id)
|
|
187
|
+
return;
|
|
188
|
+
const entry = this.ring.find((e) => e.requestId === id);
|
|
189
|
+
if (!entry)
|
|
190
|
+
return;
|
|
191
|
+
void req
|
|
192
|
+
.sizes()
|
|
193
|
+
.then((s) => {
|
|
194
|
+
if (typeof s.responseBodySize === "number" && s.responseBodySize >= 0)
|
|
195
|
+
entry.bytes = s.responseBodySize;
|
|
196
|
+
})
|
|
197
|
+
.catch(() => undefined);
|
|
198
|
+
});
|
|
199
|
+
this.context.on("requestfailed", (req) => {
|
|
200
|
+
const id = this.ids.get(req) ?? nextPwRequestId();
|
|
201
|
+
this.push({
|
|
202
|
+
method: req.method(),
|
|
203
|
+
url: req.url(),
|
|
204
|
+
type: cdpTypeFromPlaywright(req.resourceType()),
|
|
205
|
+
failed: true,
|
|
206
|
+
ms: 0,
|
|
207
|
+
requestId: id,
|
|
208
|
+
});
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
async captureBody(id, res) {
|
|
212
|
+
try {
|
|
213
|
+
const buf = await res.body();
|
|
214
|
+
const truncated = buf.length > this.maxBodyBytes;
|
|
215
|
+
const stored = truncated ? buf.subarray(0, this.maxBodyBytes) : buf;
|
|
216
|
+
this.bodies.set(id, { buf: stored, truncated });
|
|
217
|
+
// LRU eviction — keep the most recent `bodyCap` bodies.
|
|
218
|
+
if (this.bodies.size > this.bodyCap) {
|
|
219
|
+
const oldest = this.bodies.keys().next().value;
|
|
220
|
+
if (oldest !== undefined)
|
|
221
|
+
this.bodies.delete(oldest);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
catch {
|
|
225
|
+
/* body not retained (e.g. a redirect / no-body response) — best-effort */
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
push(entry) {
|
|
229
|
+
this.ring.push(entry);
|
|
230
|
+
if (this.ring.length > this.cap)
|
|
231
|
+
this.ring.shift();
|
|
232
|
+
}
|
|
233
|
+
/** Raw, read-only snapshot of the ring (asset_export iterates this). */
|
|
234
|
+
iter() {
|
|
235
|
+
return this.ring;
|
|
236
|
+
}
|
|
237
|
+
/** Most-recent N entries; noise + beacons folded into `other`. */
|
|
238
|
+
recent(limit = 50) {
|
|
239
|
+
return foldInteresting(this.ring.slice(-limit), this.secrets);
|
|
240
|
+
}
|
|
241
|
+
/** Resolve a `requestId` to its captured body. Bytes were stored as a Buffer
|
|
242
|
+
* at response time; emit as utf-8 unless they aren't valid text, in which case
|
|
243
|
+
* base64 (matching the CDP `Network.getResponseBody` base64Encoded contract).
|
|
244
|
+
* Secrets masking is applied to text bodies (base64 passes through, same as
|
|
245
|
+
* the CDP path). */
|
|
246
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
247
|
+
async fetchBody(requestId, secrets) {
|
|
248
|
+
const cached = this.bodies.get(requestId);
|
|
249
|
+
if (!cached) {
|
|
250
|
+
return {
|
|
251
|
+
ok: false,
|
|
252
|
+
error: `response body not available for "${requestId}" — off Chromium, bodies are captured at ` +
|
|
253
|
+
`response time into a bounded recent-window cache (no after-the-fact protocol fetch like CDP ` +
|
|
254
|
+
`Network.getResponseBody). Read the body right after the request, before ${this.bodyCap} newer ` +
|
|
255
|
+
`responses evict it; bodies aren't retained across navigations.`,
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
// Decide text-vs-base64: a body that round-trips through utf-8 cleanly is
|
|
259
|
+
// text; otherwise base64 (the agent decodes + re-masks on its side).
|
|
260
|
+
const utf8 = cached.buf.toString("utf-8");
|
|
261
|
+
const isText = Buffer.from(utf8, "utf-8").equals(cached.buf);
|
|
262
|
+
if (isText) {
|
|
263
|
+
const out = secrets ? secrets.applyMaskInText(utf8) : utf8;
|
|
264
|
+
return {
|
|
265
|
+
ok: true,
|
|
266
|
+
body: out,
|
|
267
|
+
base64Encoded: false,
|
|
268
|
+
...(cached.truncated ? { truncated: true } : {}),
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
return {
|
|
272
|
+
ok: true,
|
|
273
|
+
body: cached.buf.toString("base64"),
|
|
274
|
+
base64Encoded: true,
|
|
275
|
+
...(cached.truncated ? { truncated: true } : {}),
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
/** Session-wide WebSocket/SSE ring on Playwright events — the off-Chromium twin
|
|
280
|
+
* of `WsBuffer`. `page.on('websocket')` + `ws.on('framesent'|'framereceived')`
|
|
281
|
+
* are cross-browser. Server-Sent-Events are not exposed as a discrete Playwright
|
|
282
|
+
* event (they arrive as a long-lived `eventsource` response, not WS frames), so
|
|
283
|
+
* the SSE half degrades off Chromium — documented in the per-engine matrix. */
|
|
284
|
+
export class PlaywrightWsBuffer {
|
|
285
|
+
page;
|
|
286
|
+
cap;
|
|
287
|
+
maxPayload;
|
|
288
|
+
ring = [];
|
|
289
|
+
enabled = false;
|
|
290
|
+
secrets = null;
|
|
291
|
+
constructor(page, cap = 500, maxPayload = 2000) {
|
|
292
|
+
this.page = page;
|
|
293
|
+
this.cap = cap;
|
|
294
|
+
this.maxPayload = maxPayload;
|
|
295
|
+
}
|
|
296
|
+
setSecrets(secrets) {
|
|
297
|
+
this.secrets = secrets;
|
|
298
|
+
}
|
|
299
|
+
trunc(s) {
|
|
300
|
+
if (s.length <= this.maxPayload)
|
|
301
|
+
return { payload: s };
|
|
302
|
+
return { payload: s.slice(0, this.maxPayload), truncated: true };
|
|
303
|
+
}
|
|
304
|
+
push(f) {
|
|
305
|
+
this.ring.push(f);
|
|
306
|
+
if (this.ring.length > this.cap)
|
|
307
|
+
this.ring.shift();
|
|
308
|
+
}
|
|
309
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
310
|
+
async attach() {
|
|
311
|
+
if (this.enabled)
|
|
312
|
+
return;
|
|
313
|
+
this.enabled = true;
|
|
314
|
+
this.page.on("websocket", (ws) => {
|
|
315
|
+
const url = ws.url();
|
|
316
|
+
// Playwright surfaces text frames as strings and binary frames as Buffers.
|
|
317
|
+
// We only stringify; binary payloads become their utf-8 lossy form (the CDP
|
|
318
|
+
// path likewise carries `payloadData` as the protocol delivered it). Opcode
|
|
319
|
+
// 1 (text) / 2 (binary) is inferred from the payload runtime type.
|
|
320
|
+
ws.on("framesent", (data) => this.push(this.frame(url, "sent", data.payload)));
|
|
321
|
+
ws.on("framereceived", (data) => this.push(this.frame(url, "recv", data.payload)));
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
frame(url, dir, payload) {
|
|
325
|
+
const isText = typeof payload === "string";
|
|
326
|
+
const text = isText ? payload : payload.toString("utf-8");
|
|
327
|
+
return {
|
|
328
|
+
url,
|
|
329
|
+
dir,
|
|
330
|
+
kind: "ws",
|
|
331
|
+
opcode: isText ? 1 : 2,
|
|
332
|
+
...this.trunc(text),
|
|
333
|
+
ts: Date.now(),
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
/** Most-recent N frames, optionally filtered by a url substring. */
|
|
337
|
+
recent(limit = 50, urlPattern) {
|
|
338
|
+
let frames = this.ring;
|
|
339
|
+
if (urlPattern)
|
|
340
|
+
frames = frames.filter((f) => f.url.includes(urlPattern));
|
|
341
|
+
return {
|
|
342
|
+
total: frames.length,
|
|
343
|
+
frames: frames.slice(-limit).map((f) => sanitizeFrame(f, this.secrets)),
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
/** Frames since a timestamp — for the per-action `ActionResult` slice. */
|
|
347
|
+
since(ts, cap = 25) {
|
|
348
|
+
return this.ring
|
|
349
|
+
.filter((f) => f.ts >= ts)
|
|
350
|
+
.slice(-cap)
|
|
351
|
+
.map((f) => sanitizeFrame(f, this.secrets));
|
|
352
|
+
}
|
|
353
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { CDPSession, Page } from "playwright-core";
|
|
2
|
+
import { type NetworkSubstrate } from "./network-substrate.js";
|
|
3
|
+
/** The minimal session shape this selector needs — the optional CDP accessor
|
|
4
|
+
* (present only on chromium) + the engine tag + the page handle. The full
|
|
5
|
+
* BrowserSession satisfies it; the narrow shape keeps the engine/session
|
|
6
|
+
* interfaces out of this page-layer module. */
|
|
7
|
+
export interface NetworkSubstrateCapableSession {
|
|
8
|
+
readonly engine: string;
|
|
9
|
+
page(): Page;
|
|
10
|
+
cdp?(): CDPSession;
|
|
11
|
+
}
|
|
12
|
+
/** Build the NetworkSubstrate for a session. Chromium (CDP present) → the
|
|
13
|
+
* byte-identical CDP substrate; any engine without CDP → the Playwright context-
|
|
14
|
+
* event substrate. The presence of `cdp` is the capability signal — the same one
|
|
15
|
+
* `requireCdp` and `snapshotSubstrateFor` key on — so a future CDP-bearing engine
|
|
16
|
+
* routes to the CDP substrate automatically and a non-CDP one to the event path,
|
|
17
|
+
* with no edit here. */
|
|
18
|
+
export declare function networkSubstrateFor(session: NetworkSubstrateCapableSession): NetworkSubstrate;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// Network substrate selection — maps a live session to its NetworkSubstrate.
|
|
2
|
+
// This is the seam where the engine's network strategy is chosen: chromium (CDP)
|
|
3
|
+
// gets the verbatim CDP substrate (NetworkBuffer / WsBuffer / NetworkTap /
|
|
4
|
+
// fetchResponseBody); an engine with no CDP escape hatch (firefox / webkit) gets
|
|
5
|
+
// the Playwright context-event substrate. The choice is the engine's, declared
|
|
6
|
+
// by whether it exposes the raw-CDP handle — not an engine-name check scattered
|
|
7
|
+
// through the tools. Mirrors `snapshotSubstrateFor`.
|
|
8
|
+
//
|
|
9
|
+
// The session layer wires one substrate per entry at creation (server.ts) so the
|
|
10
|
+
// per-call path is a captured-handle delegate: the session buffers are attached
|
|
11
|
+
// once, and the per-action tap the action window mints is the same allocation the
|
|
12
|
+
// CDP path already made. No new per-action cost on chromium (the envelope is the
|
|
13
|
+
// hottest path, so the per-call delegate reuses the attached buffers rather than
|
|
14
|
+
// reallocating; measured).
|
|
15
|
+
import { CdpNetworkSubstrate, PlaywrightNetworkSubstrate, SafariNoopNetworkSubstrate, } from "./network-substrate.js";
|
|
16
|
+
/** Build the NetworkSubstrate for a session. Chromium (CDP present) → the
|
|
17
|
+
* byte-identical CDP substrate; any engine without CDP → the Playwright context-
|
|
18
|
+
* event substrate. The presence of `cdp` is the capability signal — the same one
|
|
19
|
+
* `requireCdp` and `snapshotSubstrateFor` key on — so a future CDP-bearing engine
|
|
20
|
+
* routes to the CDP substrate automatically and a non-CDP one to the event path,
|
|
21
|
+
* with no edit here. */
|
|
22
|
+
export function networkSubstrateFor(session) {
|
|
23
|
+
// Safari has no network substrate at all (no CDP tap, no BiDi network domain) —
|
|
24
|
+
// and no Playwright Page to feed the event path — so it gets the empty no-op
|
|
25
|
+
// substrate; the network tools are capability-gated. Handled before page().
|
|
26
|
+
if (session.engine === "safari")
|
|
27
|
+
return new SafariNoopNetworkSubstrate();
|
|
28
|
+
if (session.cdp)
|
|
29
|
+
return new CdpNetworkSubstrate(session.cdp());
|
|
30
|
+
const page = session.page();
|
|
31
|
+
return new PlaywrightNetworkSubstrate(page.context(), page, session.engine);
|
|
32
|
+
}
|