@monoes/monobrowse 1.0.11 → 1.0.13
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/dist/src/__tests__/adapters.test.js +5 -2
- package/dist/src/__tests__/adapters.test.js.map +1 -1
- package/dist/src/__tests__/batch-eval-parsing.test.js +4 -2
- package/dist/src/__tests__/batch-eval-parsing.test.js.map +1 -1
- package/dist/src/__tests__/box-model.test.js +9 -5
- package/dist/src/__tests__/box-model.test.js.map +1 -1
- package/dist/src/__tests__/browser-launch.test.d.ts +10 -0
- package/dist/src/__tests__/browser-launch.test.d.ts.map +1 -1
- package/dist/src/__tests__/browser-launch.test.js +17 -10
- package/dist/src/__tests__/browser-launch.test.js.map +1 -1
- package/dist/src/__tests__/cdp-client.test.js +9 -3
- package/dist/src/__tests__/cdp-client.test.js.map +1 -1
- package/dist/src/__tests__/close-browser.test.d.ts +13 -0
- package/dist/src/__tests__/close-browser.test.d.ts.map +1 -1
- package/dist/src/__tests__/close-browser.test.js +5 -5
- package/dist/src/__tests__/close-browser.test.js.map +1 -1
- package/dist/src/__tests__/console-log.test.js +17 -6
- package/dist/src/__tests__/console-log.test.js.map +1 -1
- package/dist/src/__tests__/find.test.js +26 -6
- package/dist/src/__tests__/find.test.js.map +1 -1
- package/dist/src/__tests__/frame-command.test.js +9 -3
- package/dist/src/__tests__/frame-command.test.js.map +1 -1
- package/dist/src/__tests__/open-url-navigate-error.test.js +1 -3
- package/dist/src/__tests__/open-url-navigate-error.test.js.map +1 -1
- package/dist/src/__tests__/output.test.js +1 -1
- package/dist/src/__tests__/output.test.js.map +1 -1
- package/dist/src/__tests__/profiler-heap.test.d.ts +2 -0
- package/dist/src/__tests__/profiler-heap.test.d.ts.map +1 -0
- package/dist/src/__tests__/profiler-heap.test.js +154 -0
- package/dist/src/__tests__/profiler-heap.test.js.map +1 -0
- package/dist/src/__tests__/reap-idle-browser.test.d.ts +15 -0
- package/dist/src/__tests__/reap-idle-browser.test.d.ts.map +1 -0
- package/dist/src/__tests__/reap-idle-browser.test.js +238 -0
- package/dist/src/__tests__/reap-idle-browser.test.js.map +1 -0
- package/dist/src/__tests__/ref-cache.test.js +18 -10
- package/dist/src/__tests__/ref-cache.test.js.map +1 -1
- package/dist/src/__tests__/report-a11y.test.d.ts +2 -0
- package/dist/src/__tests__/report-a11y.test.d.ts.map +1 -0
- package/dist/src/__tests__/report-a11y.test.js +147 -0
- package/dist/src/__tests__/report-a11y.test.js.map +1 -0
- package/dist/src/__tests__/report-analyze.test.d.ts +2 -0
- package/dist/src/__tests__/report-analyze.test.d.ts.map +1 -0
- package/dist/src/__tests__/report-analyze.test.js +157 -0
- package/dist/src/__tests__/report-analyze.test.js.map +1 -0
- package/dist/src/__tests__/report-budget.test.d.ts +2 -0
- package/dist/src/__tests__/report-budget.test.d.ts.map +1 -0
- package/dist/src/__tests__/report-budget.test.js +80 -0
- package/dist/src/__tests__/report-budget.test.js.map +1 -0
- package/dist/src/__tests__/report-diff.test.d.ts +2 -0
- package/dist/src/__tests__/report-diff.test.d.ts.map +1 -0
- package/dist/src/__tests__/report-diff.test.js +231 -0
- package/dist/src/__tests__/report-diff.test.js.map +1 -0
- package/dist/src/__tests__/report-evidence.test.d.ts +2 -0
- package/dist/src/__tests__/report-evidence.test.d.ts.map +1 -0
- package/dist/src/__tests__/report-evidence.test.js +214 -0
- package/dist/src/__tests__/report-evidence.test.js.map +1 -0
- package/dist/src/__tests__/report-flake.test.d.ts +2 -0
- package/dist/src/__tests__/report-flake.test.d.ts.map +1 -0
- package/dist/src/__tests__/report-flake.test.js +182 -0
- package/dist/src/__tests__/report-flake.test.js.map +1 -0
- package/dist/src/__tests__/report-history.test.d.ts +2 -0
- package/dist/src/__tests__/report-history.test.d.ts.map +1 -0
- package/dist/src/__tests__/report-history.test.js +229 -0
- package/dist/src/__tests__/report-history.test.js.map +1 -0
- package/dist/src/__tests__/report-output.test.d.ts +2 -0
- package/dist/src/__tests__/report-output.test.d.ts.map +1 -0
- package/dist/src/__tests__/report-output.test.js +169 -0
- package/dist/src/__tests__/report-output.test.js.map +1 -0
- package/dist/src/__tests__/report-png.test.d.ts +2 -0
- package/dist/src/__tests__/report-png.test.d.ts.map +1 -0
- package/dist/src/__tests__/report-png.test.js +84 -0
- package/dist/src/__tests__/report-png.test.js.map +1 -0
- package/dist/src/__tests__/report-render-extras.test.d.ts +2 -0
- package/dist/src/__tests__/report-render-extras.test.d.ts.map +1 -0
- package/dist/src/__tests__/report-render-extras.test.js +285 -0
- package/dist/src/__tests__/report-render-extras.test.js.map +1 -0
- package/dist/src/__tests__/report-render.test.d.ts +2 -0
- package/dist/src/__tests__/report-render.test.d.ts.map +1 -0
- package/dist/src/__tests__/report-render.test.js +143 -0
- package/dist/src/__tests__/report-render.test.js.map +1 -0
- package/dist/src/__tests__/report-run.test.d.ts +2 -0
- package/dist/src/__tests__/report-run.test.d.ts.map +1 -0
- package/dist/src/__tests__/report-run.test.js +234 -0
- package/dist/src/__tests__/report-run.test.js.map +1 -0
- package/dist/src/__tests__/session-state.test.d.ts +8 -0
- package/dist/src/__tests__/session-state.test.d.ts.map +1 -1
- package/dist/src/__tests__/session-state.test.js +10 -10
- package/dist/src/__tests__/session-state.test.js.map +1 -1
- package/dist/src/__tests__/snapshot.test.js +44 -14
- package/dist/src/__tests__/snapshot.test.js.map +1 -1
- package/dist/src/__tests__/storage-eval.test.js +14 -6
- package/dist/src/__tests__/storage-eval.test.js.map +1 -1
- package/dist/src/__tests__/tabs.test.js +25 -9
- package/dist/src/__tests__/tabs.test.js.map +1 -1
- package/dist/src/browser/action-builder/analyzer.d.ts +1 -1
- package/dist/src/browser/action-builder/analyzer.d.ts.map +1 -1
- package/dist/src/browser/action-builder/analyzer.js +25 -9
- package/dist/src/browser/action-builder/analyzer.js.map +1 -1
- package/dist/src/browser/action-builder/types.d.ts.map +1 -1
- package/dist/src/browser/actions.d.ts +1 -1
- package/dist/src/browser/actions.d.ts.map +1 -1
- package/dist/src/browser/actions.js +16 -6
- package/dist/src/browser/actions.js.map +1 -1
- package/dist/src/browser/adapters/gemini.d.ts.map +1 -1
- package/dist/src/browser/adapters/gemini.js.map +1 -1
- package/dist/src/browser/adapters/google.d.ts.map +1 -1
- package/dist/src/browser/adapters/google.js.map +1 -1
- package/dist/src/browser/adapters/index.d.ts.map +1 -1
- package/dist/src/browser/adapters/index.js +3 -3
- package/dist/src/browser/adapters/index.js.map +1 -1
- package/dist/src/browser/adapters/instagram.d.ts.map +1 -1
- package/dist/src/browser/adapters/instagram.js.map +1 -1
- package/dist/src/browser/adapters/linkedin.d.ts.map +1 -1
- package/dist/src/browser/adapters/linkedin.js.map +1 -1
- package/dist/src/browser/adapters/microsoft.d.ts.map +1 -1
- package/dist/src/browser/adapters/microsoft.js.map +1 -1
- package/dist/src/browser/adapters/x.d.ts.map +1 -1
- package/dist/src/browser/adapters/x.js.map +1 -1
- package/dist/src/browser/browser.d.ts +30 -0
- package/dist/src/browser/browser.d.ts.map +1 -1
- package/dist/src/browser/browser.js +122 -15
- package/dist/src/browser/browser.js.map +1 -1
- package/dist/src/browser/cdp.d.ts.map +1 -1
- package/dist/src/browser/cdp.js +21 -8
- package/dist/src/browser/cdp.js.map +1 -1
- package/dist/src/browser/console-log.d.ts.map +1 -1
- package/dist/src/browser/console-log.js +2 -2
- package/dist/src/browser/console-log.js.map +1 -1
- package/dist/src/browser/dashboard/server.d.ts.map +1 -1
- package/dist/src/browser/dashboard/server.js +29 -19
- package/dist/src/browser/dashboard/server.js.map +1 -1
- package/dist/src/browser/dashboard/ui.html +153 -165
- package/dist/src/browser/dialog.d.ts.map +1 -1
- package/dist/src/browser/dialog.js +3 -1
- package/dist/src/browser/dialog.js.map +1 -1
- package/dist/src/browser/emulation.d.ts.map +1 -1
- package/dist/src/browser/emulation.js +21 -6
- package/dist/src/browser/emulation.js.map +1 -1
- package/dist/src/browser/find.d.ts +4 -4
- package/dist/src/browser/find.d.ts.map +1 -1
- package/dist/src/browser/find.js +14 -6
- package/dist/src/browser/find.js.map +1 -1
- package/dist/src/browser/har.d.ts.map +1 -1
- package/dist/src/browser/har.js +14 -7
- package/dist/src/browser/har.js.map +1 -1
- package/dist/src/browser/index.d.ts +17 -16
- package/dist/src/browser/index.d.ts.map +1 -1
- package/dist/src/browser/index.js +17 -16
- package/dist/src/browser/index.js.map +1 -1
- package/dist/src/browser/network.d.ts.map +1 -1
- package/dist/src/browser/network.js +14 -4
- package/dist/src/browser/network.js.map +1 -1
- package/dist/src/browser/pdf.d.ts.map +1 -1
- package/dist/src/browser/pdf.js +3 -3
- package/dist/src/browser/pdf.js.map +1 -1
- package/dist/src/browser/profiler.d.ts.map +1 -1
- package/dist/src/browser/profiler.js +22 -20
- package/dist/src/browser/profiler.js.map +1 -1
- package/dist/src/browser/record.d.ts +1 -1
- package/dist/src/browser/record.d.ts.map +1 -1
- package/dist/src/browser/record.js +18 -7
- package/dist/src/browser/record.js.map +1 -1
- package/dist/src/browser/ref-cache.d.ts.map +1 -1
- package/dist/src/browser/ref-cache.js +9 -4
- package/dist/src/browser/ref-cache.js.map +1 -1
- package/dist/src/browser/screenshot.d.ts.map +1 -1
- package/dist/src/browser/screenshot.js +11 -7
- package/dist/src/browser/screenshot.js.map +1 -1
- package/dist/src/browser/session.d.ts +1 -1
- package/dist/src/browser/session.d.ts.map +1 -1
- package/dist/src/browser/session.js +27 -8
- package/dist/src/browser/session.js.map +1 -1
- package/dist/src/browser/snapshot.d.ts +1 -1
- package/dist/src/browser/snapshot.d.ts.map +1 -1
- package/dist/src/browser/snapshot.js +8 -4
- package/dist/src/browser/snapshot.js.map +1 -1
- package/dist/src/browser/storage.d.ts.map +1 -1
- package/dist/src/browser/storage.js.map +1 -1
- package/dist/src/browser/tabs.d.ts.map +1 -1
- package/dist/src/browser/tabs.js +9 -3
- package/dist/src/browser/tabs.js.map +1 -1
- package/dist/src/browser/trace.d.ts.map +1 -1
- package/dist/src/browser/trace.js +3 -3
- package/dist/src/browser/trace.js.map +1 -1
- package/dist/src/browser/types.d.ts.map +1 -1
- package/dist/src/browser/types.js +23 -4
- package/dist/src/browser/types.js.map +1 -1
- package/dist/src/browser/vitals.d.ts.map +1 -1
- package/dist/src/browser/vitals.js +1 -1
- package/dist/src/browser/vitals.js.map +1 -1
- package/dist/src/browser/wait.d.ts.map +1 -1
- package/dist/src/browser/wait.js +11 -5
- package/dist/src/browser/wait.js.map +1 -1
- package/dist/src/cli/action.d.ts.map +1 -1
- package/dist/src/cli/action.js +14 -11
- package/dist/src/cli/action.js.map +1 -1
- package/dist/src/cli/commands.d.ts.map +1 -1
- package/dist/src/cli/commands.js +707 -159
- package/dist/src/cli/commands.js.map +1 -1
- package/dist/src/cli/output.js +5 -5
- package/dist/src/cli/output.js.map +1 -1
- package/dist/src/cli/platform.d.ts.map +1 -1
- package/dist/src/cli/platform.js +15 -11
- package/dist/src/cli/platform.js.map +1 -1
- package/dist/src/cli/types.d.ts +1 -1
- package/dist/src/cli/types.d.ts.map +1 -1
- package/dist/src/cli.js +21 -9
- package/dist/src/cli.js.map +1 -1
- package/dist/src/index.d.ts +2 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +2 -2
- package/dist/src/index.js.map +1 -1
- package/dist/src/report/a11y.d.ts +52 -0
- package/dist/src/report/a11y.d.ts.map +1 -0
- package/dist/src/report/a11y.js +231 -0
- package/dist/src/report/a11y.js.map +1 -0
- package/dist/src/report/analyze.d.ts +20 -0
- package/dist/src/report/analyze.d.ts.map +1 -0
- package/dist/src/report/analyze.js +136 -0
- package/dist/src/report/analyze.js.map +1 -0
- package/dist/src/report/budget.d.ts +27 -0
- package/dist/src/report/budget.d.ts.map +1 -0
- package/dist/src/report/budget.js +143 -0
- package/dist/src/report/budget.js.map +1 -0
- package/dist/src/report/collect-a11y.d.ts +25 -0
- package/dist/src/report/collect-a11y.d.ts.map +1 -0
- package/dist/src/report/collect-a11y.js +154 -0
- package/dist/src/report/collect-a11y.js.map +1 -0
- package/dist/src/report/collect.d.ts +45 -0
- package/dist/src/report/collect.d.ts.map +1 -0
- package/dist/src/report/collect.js +275 -0
- package/dist/src/report/collect.js.map +1 -0
- package/dist/src/report/evidence.d.ts +80 -0
- package/dist/src/report/evidence.d.ts.map +1 -0
- package/dist/src/report/evidence.js +279 -0
- package/dist/src/report/evidence.js.map +1 -0
- package/dist/src/report/flake.d.ts +88 -0
- package/dist/src/report/flake.d.ts.map +1 -0
- package/dist/src/report/flake.js +232 -0
- package/dist/src/report/flake.js.map +1 -0
- package/dist/src/report/history.d.ts +85 -0
- package/dist/src/report/history.d.ts.map +1 -0
- package/dist/src/report/history.js +176 -0
- package/dist/src/report/history.js.map +1 -0
- package/dist/src/report/index.d.ts +102 -0
- package/dist/src/report/index.d.ts.map +1 -0
- package/dist/src/report/index.js +216 -0
- package/dist/src/report/index.js.map +1 -0
- package/dist/src/report/pixel-diff.d.ts +30 -0
- package/dist/src/report/pixel-diff.d.ts.map +1 -0
- package/dist/src/report/pixel-diff.js +175 -0
- package/dist/src/report/pixel-diff.js.map +1 -0
- package/dist/src/report/png.d.ts +28 -0
- package/dist/src/report/png.d.ts.map +1 -0
- package/dist/src/report/png.js +259 -0
- package/dist/src/report/png.js.map +1 -0
- package/dist/src/report/render-evidence.d.ts +16 -0
- package/dist/src/report/render-evidence.d.ts.map +1 -0
- package/dist/src/report/render-evidence.js +174 -0
- package/dist/src/report/render-evidence.js.map +1 -0
- package/dist/src/report/render-trend.d.ts +16 -0
- package/dist/src/report/render-trend.d.ts.map +1 -0
- package/dist/src/report/render-trend.js +194 -0
- package/dist/src/report/render-trend.js.map +1 -0
- package/dist/src/report/render.d.ts +21 -0
- package/dist/src/report/render.d.ts.map +1 -0
- package/dist/src/report/render.js +286 -0
- package/dist/src/report/render.js.map +1 -0
- package/dist/src/report/run-diff.d.ts +18 -0
- package/dist/src/report/run-diff.d.ts.map +1 -0
- package/dist/src/report/run-diff.js +51 -0
- package/dist/src/report/run-diff.js.map +1 -0
- package/dist/src/report/structure.d.ts +41 -0
- package/dist/src/report/structure.d.ts.map +1 -0
- package/dist/src/report/structure.js +210 -0
- package/dist/src/report/structure.js.map +1 -0
- package/dist/src/report/trend.d.ts +26 -0
- package/dist/src/report/trend.d.ts.map +1 -0
- package/dist/src/report/trend.js +164 -0
- package/dist/src/report/trend.js.map +1 -0
- package/dist/src/report/types.d.ts +320 -0
- package/dist/src/report/types.d.ts.map +1 -0
- package/dist/src/report/types.js +11 -0
- package/dist/src/report/types.js.map +1 -0
- package/dist/src/report/util.d.ts +17 -0
- package/dist/src/report/util.d.ts.map +1 -0
- package/dist/src/report/util.js +45 -0
- package/dist/src/report/util.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/__tests__/adapters.test.ts +15 -8
- package/src/__tests__/batch-eval-parsing.test.ts +4 -2
- package/src/__tests__/box-model.test.ts +9 -5
- package/src/__tests__/browser-launch.test.ts +26 -15
- package/src/__tests__/cdp-client.test.ts +25 -9
- package/src/__tests__/close-browser.test.ts +11 -6
- package/src/__tests__/console-log.test.ts +36 -13
- package/src/__tests__/find.test.ts +58 -20
- package/src/__tests__/frame-command.test.ts +12 -6
- package/src/__tests__/open-url-navigate-error.test.ts +2 -4
- package/src/__tests__/output.test.ts +1 -1
- package/src/__tests__/profiler-heap.test.ts +191 -0
- package/src/__tests__/reap-idle-browser.test.ts +276 -0
- package/src/__tests__/ref-cache.test.ts +25 -12
- package/src/__tests__/report-a11y.test.ts +180 -0
- package/src/__tests__/report-analyze.test.ts +202 -0
- package/src/__tests__/report-budget.test.ts +92 -0
- package/src/__tests__/report-diff.test.ts +272 -0
- package/src/__tests__/report-evidence.test.ts +276 -0
- package/src/__tests__/report-flake.test.ts +214 -0
- package/src/__tests__/report-history.test.ts +293 -0
- package/src/__tests__/report-output.test.ts +210 -0
- package/src/__tests__/report-png.test.ts +95 -0
- package/src/__tests__/report-render-extras.test.ts +315 -0
- package/src/__tests__/report-render.test.ts +175 -0
- package/src/__tests__/report-run.test.ts +264 -0
- package/src/__tests__/session-state.test.ts +40 -28
- package/src/__tests__/snapshot.test.ts +60 -21
- package/src/__tests__/storage-eval.test.ts +30 -16
- package/src/__tests__/tabs.test.ts +26 -10
- package/src/browser/action-builder/analyzer.ts +39 -15
- package/src/browser/action-builder/types.ts +45 -8
- package/src/browser/actions.ts +288 -123
- package/src/browser/adapters/gemini.ts +7 -3
- package/src/browser/adapters/google.ts +5 -3
- package/src/browser/adapters/index.ts +5 -4
- package/src/browser/adapters/instagram.ts +4 -2
- package/src/browser/adapters/linkedin.ts +4 -2
- package/src/browser/adapters/microsoft.ts +9 -5
- package/src/browser/adapters/x.ts +7 -3
- package/src/browser/browser.ts +188 -42
- package/src/browser/cdp.ts +43 -11
- package/src/browser/console-log.ts +24 -7
- package/src/browser/dashboard/server.ts +44 -25
- package/src/browser/dashboard/ui.html +153 -165
- package/src/browser/dialog.ts +25 -8
- package/src/browser/emulation.ts +86 -36
- package/src/browser/find.ts +110 -47
- package/src/browser/har.ts +58 -26
- package/src/browser/index.ts +17 -16
- package/src/browser/network.ts +147 -46
- package/src/browser/pdf.ts +4 -4
- package/src/browser/profiler.ts +39 -19
- package/src/browser/record.ts +38 -19
- package/src/browser/ref-cache.ts +38 -17
- package/src/browser/screenshot.ts +58 -32
- package/src/browser/session.ts +51 -18
- package/src/browser/snapshot.ts +34 -20
- package/src/browser/storage.ts +73 -17
- package/src/browser/tabs.ts +29 -17
- package/src/browser/trace.ts +14 -10
- package/src/browser/types.ts +23 -4
- package/src/browser/vitals.ts +33 -16
- package/src/browser/wait.ts +47 -21
- package/src/cli/action.ts +52 -21
- package/src/cli/commands.ts +1365 -385
- package/src/cli/output.ts +5 -5
- package/src/cli/platform.ts +44 -23
- package/src/cli/types.ts +1 -1
- package/src/cli.ts +34 -18
- package/src/index.ts +2 -2
- package/src/report/a11y.ts +242 -0
- package/src/report/analyze.ts +181 -0
- package/src/report/budget.ts +155 -0
- package/src/report/collect-a11y.ts +200 -0
- package/src/report/collect.ts +408 -0
- package/src/report/evidence.ts +379 -0
- package/src/report/flake.ts +303 -0
- package/src/report/history.ts +219 -0
- package/src/report/index.ts +307 -0
- package/src/report/pixel-diff.ts +197 -0
- package/src/report/png.ts +290 -0
- package/src/report/render-evidence.ts +194 -0
- package/src/report/render-trend.ts +225 -0
- package/src/report/render.ts +314 -0
- package/src/report/run-diff.ts +63 -0
- package/src/report/structure.ts +212 -0
- package/src/report/trend.ts +189 -0
- package/src/report/types.ts +356 -0
- package/src/report/util.ts +48 -0
package/src/browser/dialog.ts
CHANGED
|
@@ -9,7 +9,11 @@ export interface DialogInfo {
|
|
|
9
9
|
const _pendingDialogs = new Map<string, DialogInfo | null>();
|
|
10
10
|
const _dialogListeners = new Map<string, Array<() => void>>();
|
|
11
11
|
|
|
12
|
-
export function setupDialogAutoHandling(
|
|
12
|
+
export function setupDialogAutoHandling(
|
|
13
|
+
client: CdpClient,
|
|
14
|
+
sessionId: string,
|
|
15
|
+
autoAccept = true,
|
|
16
|
+
): void {
|
|
13
17
|
if (_pendingDialogs.has(sessionId)) return;
|
|
14
18
|
_pendingDialogs.set(sessionId, null);
|
|
15
19
|
|
|
@@ -27,7 +31,9 @@ export function setupDialogAutoHandling(client: CdpClient, sessionId: string, au
|
|
|
27
31
|
if (autoAccept) {
|
|
28
32
|
try {
|
|
29
33
|
await client.send('Page.handleJavaScriptDialog', { accept: true }, sessionId);
|
|
30
|
-
} catch {
|
|
34
|
+
} catch {
|
|
35
|
+
/* dialog may have already been dismissed */
|
|
36
|
+
}
|
|
31
37
|
_pendingDialogs.set(sessionId, null);
|
|
32
38
|
}
|
|
33
39
|
});
|
|
@@ -41,15 +47,26 @@ export function setupDialogAutoHandling(client: CdpClient, sessionId: string, au
|
|
|
41
47
|
|
|
42
48
|
export function teardownDialogHandling(sessionId: string): void {
|
|
43
49
|
const offs = _dialogListeners.get(sessionId);
|
|
44
|
-
if (offs) {
|
|
50
|
+
if (offs) {
|
|
51
|
+
for (const off of offs) off();
|
|
52
|
+
_dialogListeners.delete(sessionId);
|
|
53
|
+
}
|
|
45
54
|
_pendingDialogs.delete(sessionId);
|
|
46
55
|
}
|
|
47
56
|
|
|
48
|
-
export async function acceptDialog(
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
57
|
+
export async function acceptDialog(
|
|
58
|
+
client: CdpClient,
|
|
59
|
+
sessionId: string,
|
|
60
|
+
text?: string,
|
|
61
|
+
): Promise<void> {
|
|
62
|
+
await client.send(
|
|
63
|
+
'Page.handleJavaScriptDialog',
|
|
64
|
+
{
|
|
65
|
+
accept: true,
|
|
66
|
+
promptText: text,
|
|
67
|
+
},
|
|
68
|
+
sessionId,
|
|
69
|
+
);
|
|
53
70
|
_pendingDialogs.set(sessionId, null);
|
|
54
71
|
}
|
|
55
72
|
|
package/src/browser/emulation.ts
CHANGED
|
@@ -10,39 +10,69 @@ export interface DeviceProfile {
|
|
|
10
10
|
|
|
11
11
|
const DEVICES: Record<string, DeviceProfile> = {
|
|
12
12
|
'iPhone 14': {
|
|
13
|
-
width: 390,
|
|
14
|
-
|
|
13
|
+
width: 390,
|
|
14
|
+
height: 844,
|
|
15
|
+
deviceScaleFactor: 3,
|
|
16
|
+
mobile: true,
|
|
17
|
+
userAgent:
|
|
18
|
+
'Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Mobile/15E148 Safari/604.1',
|
|
15
19
|
},
|
|
16
20
|
'iPhone SE': {
|
|
17
|
-
width: 375,
|
|
18
|
-
|
|
21
|
+
width: 375,
|
|
22
|
+
height: 667,
|
|
23
|
+
deviceScaleFactor: 2,
|
|
24
|
+
mobile: true,
|
|
25
|
+
userAgent:
|
|
26
|
+
'Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Mobile/15E148 Safari/604.1',
|
|
19
27
|
},
|
|
20
|
-
|
|
21
|
-
width: 768,
|
|
22
|
-
|
|
28
|
+
iPad: {
|
|
29
|
+
width: 768,
|
|
30
|
+
height: 1024,
|
|
31
|
+
deviceScaleFactor: 2,
|
|
32
|
+
mobile: true,
|
|
33
|
+
userAgent:
|
|
34
|
+
'Mozilla/5.0 (iPad; CPU OS 15_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Mobile/15E148 Safari/604.1',
|
|
23
35
|
},
|
|
24
36
|
'Galaxy S21': {
|
|
25
|
-
width: 360,
|
|
26
|
-
|
|
37
|
+
width: 360,
|
|
38
|
+
height: 800,
|
|
39
|
+
deviceScaleFactor: 3,
|
|
40
|
+
mobile: true,
|
|
41
|
+
userAgent:
|
|
42
|
+
'Mozilla/5.0 (Linux; Android 11; SM-G991B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.101 Mobile Safari/537.36',
|
|
27
43
|
},
|
|
28
44
|
'Pixel 5': {
|
|
29
|
-
width: 393,
|
|
30
|
-
|
|
45
|
+
width: 393,
|
|
46
|
+
height: 851,
|
|
47
|
+
deviceScaleFactor: 2.75,
|
|
48
|
+
mobile: true,
|
|
49
|
+
userAgent:
|
|
50
|
+
'Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.101 Mobile Safari/537.36',
|
|
31
51
|
},
|
|
32
52
|
};
|
|
33
53
|
|
|
34
|
-
export async function emulateDevice(
|
|
54
|
+
export async function emulateDevice(
|
|
55
|
+
client: CdpClient,
|
|
56
|
+
sessionId: string,
|
|
57
|
+
deviceName: string,
|
|
58
|
+
): Promise<void> {
|
|
35
59
|
const device = DEVICES[deviceName];
|
|
36
60
|
if (!device) {
|
|
37
|
-
throw new Error(
|
|
61
|
+
throw new Error(
|
|
62
|
+
`Unknown device: "${deviceName}". Available: ${Object.keys(DEVICES).join(', ')}`,
|
|
63
|
+
);
|
|
38
64
|
}
|
|
39
65
|
|
|
40
|
-
await client.send(
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
66
|
+
await client.send(
|
|
67
|
+
'Emulation.setDeviceMetricsOverride',
|
|
68
|
+
{
|
|
69
|
+
width: device.width,
|
|
70
|
+
height: device.height,
|
|
71
|
+
deviceScaleFactor: device.deviceScaleFactor,
|
|
72
|
+
mobile: device.mobile,
|
|
73
|
+
},
|
|
74
|
+
sessionId,
|
|
75
|
+
);
|
|
46
76
|
|
|
47
77
|
await client.send('Emulation.setUserAgentOverride', { userAgent: device.userAgent }, sessionId);
|
|
48
78
|
await client.send('Emulation.setTouchEmulationEnabled', { enabled: device.mobile }, sessionId);
|
|
@@ -53,40 +83,60 @@ export async function setGeolocation(
|
|
|
53
83
|
sessionId: string,
|
|
54
84
|
latitude: number,
|
|
55
85
|
longitude: number,
|
|
56
|
-
accuracy = 100
|
|
86
|
+
accuracy = 100,
|
|
57
87
|
): Promise<void> {
|
|
58
|
-
await client.send(
|
|
88
|
+
await client.send(
|
|
89
|
+
'Emulation.setGeolocationOverride',
|
|
90
|
+
{ latitude, longitude, accuracy },
|
|
91
|
+
sessionId,
|
|
92
|
+
);
|
|
59
93
|
}
|
|
60
94
|
|
|
61
|
-
export async function setOfflineMode(
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
95
|
+
export async function setOfflineMode(
|
|
96
|
+
client: CdpClient,
|
|
97
|
+
sessionId: string,
|
|
98
|
+
offline: boolean,
|
|
99
|
+
): Promise<void> {
|
|
100
|
+
await client.send(
|
|
101
|
+
'Network.emulateNetworkConditions',
|
|
102
|
+
{
|
|
103
|
+
offline,
|
|
104
|
+
latency: 0,
|
|
105
|
+
downloadThroughput: -1,
|
|
106
|
+
uploadThroughput: -1,
|
|
107
|
+
},
|
|
108
|
+
sessionId,
|
|
109
|
+
);
|
|
68
110
|
}
|
|
69
111
|
|
|
70
112
|
export async function setColorScheme(
|
|
71
113
|
client: CdpClient,
|
|
72
114
|
sessionId: string,
|
|
73
|
-
scheme: 'dark' | 'light' | 'no-preference'
|
|
115
|
+
scheme: 'dark' | 'light' | 'no-preference',
|
|
74
116
|
): Promise<void> {
|
|
75
|
-
await client.send(
|
|
76
|
-
|
|
77
|
-
|
|
117
|
+
await client.send(
|
|
118
|
+
'Emulation.setEmulatedMedia',
|
|
119
|
+
{
|
|
120
|
+
features: [{ name: 'prefers-color-scheme', value: scheme }],
|
|
121
|
+
},
|
|
122
|
+
sessionId,
|
|
123
|
+
);
|
|
78
124
|
}
|
|
79
125
|
|
|
80
126
|
export async function setBasicAuth(
|
|
81
127
|
client: CdpClient,
|
|
82
128
|
sessionId: string,
|
|
83
129
|
username: string,
|
|
84
|
-
password: string
|
|
130
|
+
password: string,
|
|
85
131
|
): Promise<void> {
|
|
86
132
|
const encoded = Buffer.from(`${username}:${password}`).toString('base64');
|
|
87
|
-
await client.send(
|
|
88
|
-
|
|
89
|
-
|
|
133
|
+
await client.send(
|
|
134
|
+
'Network.setExtraHTTPHeaders',
|
|
135
|
+
{
|
|
136
|
+
headers: { Authorization: `Basic ${encoded}` },
|
|
137
|
+
},
|
|
138
|
+
sessionId,
|
|
139
|
+
);
|
|
90
140
|
}
|
|
91
141
|
|
|
92
142
|
export function listDevices(): string[] {
|
package/src/browser/find.ts
CHANGED
|
@@ -1,9 +1,17 @@
|
|
|
1
|
-
import type { CdpClient } from './cdp.js';
|
|
2
|
-
import type { ElementRef } from './types.js';
|
|
3
1
|
import { evaluateJs } from './actions.js';
|
|
2
|
+
import type { CdpClient } from './cdp.js';
|
|
4
3
|
import { getObjectIdForRef } from './snapshot.js';
|
|
4
|
+
import type { ElementRef } from './types.js';
|
|
5
5
|
|
|
6
|
-
export type FindAction =
|
|
6
|
+
export type FindAction =
|
|
7
|
+
| 'click'
|
|
8
|
+
| 'fill'
|
|
9
|
+
| 'type'
|
|
10
|
+
| 'hover'
|
|
11
|
+
| 'focus'
|
|
12
|
+
| 'check'
|
|
13
|
+
| 'uncheck'
|
|
14
|
+
| 'text';
|
|
7
15
|
|
|
8
16
|
export interface FindOptions {
|
|
9
17
|
name?: string;
|
|
@@ -18,7 +26,7 @@ export async function findBySelector(
|
|
|
18
26
|
sessionId: string,
|
|
19
27
|
refs: Map<string, ElementRef>,
|
|
20
28
|
selector: string,
|
|
21
|
-
options: FindOptions = {}
|
|
29
|
+
options: FindOptions = {},
|
|
22
30
|
): Promise<ElementRef | null> {
|
|
23
31
|
if (options.nth !== undefined && options.nth < 1) {
|
|
24
32
|
throw new Error(`nth must be >= 1 (received ${options.nth})`);
|
|
@@ -29,14 +37,20 @@ export async function findBySelector(
|
|
|
29
37
|
let targetNodeId: number;
|
|
30
38
|
if (options.nth !== undefined || options.last) {
|
|
31
39
|
const result = await client.send<{ nodeIds: number[] }>(
|
|
32
|
-
'DOM.querySelectorAll',
|
|
40
|
+
'DOM.querySelectorAll',
|
|
41
|
+
{ nodeId: doc.root.nodeId, selector },
|
|
42
|
+
sessionId,
|
|
33
43
|
);
|
|
34
44
|
const nodeIds = result.nodeIds ?? [];
|
|
35
45
|
if (nodeIds.length === 0) return null;
|
|
36
|
-
targetNodeId = options.last
|
|
46
|
+
targetNodeId = options.last
|
|
47
|
+
? nodeIds[nodeIds.length - 1]
|
|
48
|
+
: (nodeIds[(options.nth ?? 1) - 1] ?? 0);
|
|
37
49
|
} else {
|
|
38
50
|
const result = await client.send<{ nodeId: number }>(
|
|
39
|
-
'DOM.querySelector',
|
|
51
|
+
'DOM.querySelector',
|
|
52
|
+
{ nodeId: doc.root.nodeId, selector },
|
|
53
|
+
sessionId,
|
|
40
54
|
);
|
|
41
55
|
targetNodeId = result.nodeId ?? 0;
|
|
42
56
|
}
|
|
@@ -44,7 +58,9 @@ export async function findBySelector(
|
|
|
44
58
|
if (!targetNodeId) return null;
|
|
45
59
|
|
|
46
60
|
const desc = await client.send<{ node: { backendNodeId: number } }>(
|
|
47
|
-
'DOM.describeNode',
|
|
61
|
+
'DOM.describeNode',
|
|
62
|
+
{ nodeId: targetNodeId },
|
|
63
|
+
sessionId,
|
|
48
64
|
);
|
|
49
65
|
const backendDOMNodeId = desc.node?.backendNodeId;
|
|
50
66
|
if (!backendDOMNodeId) return null;
|
|
@@ -54,7 +70,13 @@ export async function findBySelector(
|
|
|
54
70
|
if (existing) return existing;
|
|
55
71
|
|
|
56
72
|
// Synthetic ref for elements not represented in the AX tree — insert into refs so it can be used in subsequent commands
|
|
57
|
-
const syntheticRef: ElementRef = {
|
|
73
|
+
const syntheticRef: ElementRef = {
|
|
74
|
+
ref: `sel-${backendDOMNodeId}`,
|
|
75
|
+
role: 'generic',
|
|
76
|
+
name: selector,
|
|
77
|
+
nodeId: targetNodeId,
|
|
78
|
+
backendDOMNodeId,
|
|
79
|
+
};
|
|
58
80
|
refs.set(syntheticRef.ref, syntheticRef);
|
|
59
81
|
return syntheticRef;
|
|
60
82
|
} catch (err: unknown) {
|
|
@@ -65,11 +87,11 @@ export async function findBySelector(
|
|
|
65
87
|
}
|
|
66
88
|
|
|
67
89
|
export async function findByRole(
|
|
68
|
-
|
|
69
|
-
|
|
90
|
+
_client: CdpClient,
|
|
91
|
+
_sessionId: string,
|
|
70
92
|
refs: Map<string, ElementRef>,
|
|
71
93
|
role: string,
|
|
72
|
-
options: FindOptions = {}
|
|
94
|
+
options: FindOptions = {},
|
|
73
95
|
): Promise<ElementRef | null> {
|
|
74
96
|
if (options.nth !== undefined && options.nth < 1) {
|
|
75
97
|
throw new Error(`nth must be >= 1 (received ${options.nth})`);
|
|
@@ -92,18 +114,18 @@ export async function findByRole(
|
|
|
92
114
|
}
|
|
93
115
|
|
|
94
116
|
export async function findByText(
|
|
95
|
-
|
|
96
|
-
|
|
117
|
+
_client: CdpClient,
|
|
118
|
+
_sessionId: string,
|
|
97
119
|
refs: Map<string, ElementRef>,
|
|
98
120
|
text: string,
|
|
99
|
-
options: FindOptions = {}
|
|
121
|
+
options: FindOptions = {},
|
|
100
122
|
): Promise<ElementRef | null> {
|
|
101
123
|
if (options.nth !== undefined && options.nth < 1) {
|
|
102
124
|
throw new Error(`nth must be >= 1 (received ${options.nth})`);
|
|
103
125
|
}
|
|
104
126
|
const lower = text.toLowerCase();
|
|
105
127
|
const candidates = [...refs.values()].filter((r) =>
|
|
106
|
-
options.exact ? r.name.toLowerCase() === lower : r.name.toLowerCase().includes(lower)
|
|
128
|
+
options.exact ? r.name.toLowerCase() === lower : r.name.toLowerCase().includes(lower),
|
|
107
129
|
);
|
|
108
130
|
if (options.nth !== undefined) return candidates[options.nth - 1] ?? null;
|
|
109
131
|
if (options.last) return candidates[candidates.length - 1] ?? null;
|
|
@@ -115,17 +137,17 @@ export async function findByLabel(
|
|
|
115
137
|
sessionId: string,
|
|
116
138
|
refs: Map<string, ElementRef>,
|
|
117
139
|
label: string,
|
|
118
|
-
options: FindOptions = {}
|
|
140
|
+
options: FindOptions = {},
|
|
119
141
|
): Promise<ElementRef | null> {
|
|
120
142
|
return findByText(client, sessionId, refs, label, options);
|
|
121
143
|
}
|
|
122
144
|
|
|
123
145
|
export async function findByPlaceholder(
|
|
124
|
-
|
|
125
|
-
|
|
146
|
+
_client: CdpClient,
|
|
147
|
+
_sessionId: string,
|
|
126
148
|
refs: Map<string, ElementRef>,
|
|
127
149
|
placeholder: string,
|
|
128
|
-
options: FindOptions = {}
|
|
150
|
+
options: FindOptions = {},
|
|
129
151
|
): Promise<ElementRef | null> {
|
|
130
152
|
if (options.nth !== undefined && options.nth < 1) {
|
|
131
153
|
throw new Error(`nth must be >= 1 (received ${options.nth})`);
|
|
@@ -143,7 +165,7 @@ export async function findByPlaceholder(
|
|
|
143
165
|
export async function findByTestId(
|
|
144
166
|
client: CdpClient,
|
|
145
167
|
sessionId: string,
|
|
146
|
-
testId: string
|
|
168
|
+
testId: string,
|
|
147
169
|
): Promise<string | null> {
|
|
148
170
|
const escapedId = testId.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
|
|
149
171
|
const selectors = [
|
|
@@ -152,18 +174,28 @@ export async function findByTestId(
|
|
|
152
174
|
`[data-test="${escapedId}"]`,
|
|
153
175
|
];
|
|
154
176
|
for (const sel of selectors) {
|
|
155
|
-
const result = await evaluateJs(
|
|
177
|
+
const result = await evaluateJs(
|
|
178
|
+
client,
|
|
179
|
+
sessionId,
|
|
180
|
+
`!!document.querySelector(${JSON.stringify(sel)})`,
|
|
181
|
+
);
|
|
156
182
|
if (result) return sel;
|
|
157
183
|
}
|
|
158
184
|
return null;
|
|
159
185
|
}
|
|
160
186
|
|
|
161
|
-
export async function isVisible(
|
|
187
|
+
export async function isVisible(
|
|
188
|
+
client: CdpClient,
|
|
189
|
+
sessionId: string,
|
|
190
|
+
ref: ElementRef,
|
|
191
|
+
): Promise<boolean> {
|
|
162
192
|
const objectId = await getObjectIdForRef(client, sessionId, ref);
|
|
163
193
|
if (!objectId) return false;
|
|
164
194
|
|
|
165
|
-
const result = await client.send<{ result: { value?: boolean } }>(
|
|
166
|
-
|
|
195
|
+
const result = await client.send<{ result: { value?: boolean } }>(
|
|
196
|
+
'Runtime.callFunctionOn',
|
|
197
|
+
{
|
|
198
|
+
functionDeclaration: `function() {
|
|
167
199
|
const rect = this.getBoundingClientRect();
|
|
168
200
|
const style = window.getComputedStyle(this);
|
|
169
201
|
return rect.width > 0 && rect.height > 0 &&
|
|
@@ -171,45 +203,74 @@ export async function isVisible(client: CdpClient, sessionId: string, ref: Eleme
|
|
|
171
203
|
style.visibility !== 'hidden' &&
|
|
172
204
|
style.opacity !== '0';
|
|
173
205
|
}`,
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
206
|
+
objectId,
|
|
207
|
+
returnByValue: true,
|
|
208
|
+
},
|
|
209
|
+
sessionId,
|
|
210
|
+
);
|
|
177
211
|
return result.result?.value ?? false;
|
|
178
212
|
}
|
|
179
213
|
|
|
180
|
-
export async function isEnabled(
|
|
214
|
+
export async function isEnabled(
|
|
215
|
+
_client: CdpClient,
|
|
216
|
+
_sessionId: string,
|
|
217
|
+
ref: ElementRef,
|
|
218
|
+
): Promise<boolean> {
|
|
181
219
|
return !ref.disabled;
|
|
182
220
|
}
|
|
183
221
|
|
|
184
|
-
export async function isChecked(
|
|
222
|
+
export async function isChecked(
|
|
223
|
+
client: CdpClient,
|
|
224
|
+
sessionId: string,
|
|
225
|
+
ref: ElementRef,
|
|
226
|
+
): Promise<boolean> {
|
|
185
227
|
const objectId = await getObjectIdForRef(client, sessionId, ref);
|
|
186
228
|
if (!objectId) return false;
|
|
187
229
|
|
|
188
|
-
const result = await client.send<{ result: { value?: boolean } }>(
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
230
|
+
const result = await client.send<{ result: { value?: boolean } }>(
|
|
231
|
+
'Runtime.callFunctionOn',
|
|
232
|
+
{
|
|
233
|
+
functionDeclaration: 'function() { return !!this.checked; }',
|
|
234
|
+
objectId,
|
|
235
|
+
returnByValue: true,
|
|
236
|
+
},
|
|
237
|
+
sessionId,
|
|
238
|
+
);
|
|
193
239
|
return result.result?.value ?? false;
|
|
194
240
|
}
|
|
195
241
|
|
|
196
|
-
export async function scrollIntoView(
|
|
242
|
+
export async function scrollIntoView(
|
|
243
|
+
client: CdpClient,
|
|
244
|
+
sessionId: string,
|
|
245
|
+
ref: ElementRef,
|
|
246
|
+
): Promise<void> {
|
|
197
247
|
const objectId = await getObjectIdForRef(client, sessionId, ref);
|
|
198
248
|
if (!objectId) throw new Error(`Cannot scroll: ref @${ref.ref} not found in DOM`);
|
|
199
249
|
|
|
200
|
-
await client.send(
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
250
|
+
await client.send(
|
|
251
|
+
'Runtime.callFunctionOn',
|
|
252
|
+
{
|
|
253
|
+
functionDeclaration:
|
|
254
|
+
'function() { this.scrollIntoView({ behavior: "smooth", block: "center" }); }',
|
|
255
|
+
objectId,
|
|
256
|
+
returnByValue: true,
|
|
257
|
+
},
|
|
258
|
+
sessionId,
|
|
259
|
+
);
|
|
205
260
|
}
|
|
206
261
|
|
|
207
|
-
export async function highlightElement(
|
|
262
|
+
export async function highlightElement(
|
|
263
|
+
client: CdpClient,
|
|
264
|
+
sessionId: string,
|
|
265
|
+
ref: ElementRef,
|
|
266
|
+
): Promise<void> {
|
|
208
267
|
const objectId = await getObjectIdForRef(client, sessionId, ref);
|
|
209
268
|
if (!objectId) return;
|
|
210
269
|
|
|
211
|
-
await client.send(
|
|
212
|
-
|
|
270
|
+
await client.send(
|
|
271
|
+
'Runtime.callFunctionOn',
|
|
272
|
+
{
|
|
273
|
+
functionDeclaration: `function() {
|
|
213
274
|
const prev = this.style.outline;
|
|
214
275
|
const prevBg = this.style.backgroundColor;
|
|
215
276
|
this.style.outline = '3px solid #ff5722';
|
|
@@ -219,7 +280,9 @@ export async function highlightElement(client: CdpClient, sessionId: string, ref
|
|
|
219
280
|
this.style.backgroundColor = prevBg;
|
|
220
281
|
}, 2000);
|
|
221
282
|
}`,
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
283
|
+
objectId,
|
|
284
|
+
returnByValue: true,
|
|
285
|
+
},
|
|
286
|
+
sessionId,
|
|
287
|
+
);
|
|
225
288
|
}
|
package/src/browser/har.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import { writeFile } from 'node:fs/promises';
|
|
2
|
+
import { homedir, tmpdir } from 'node:os';
|
|
3
|
+
import { isAbsolute, join, relative, resolve } from 'node:path';
|
|
1
4
|
import type { CdpClient } from './cdp.js';
|
|
2
|
-
import { writeFile } from 'fs/promises';
|
|
3
|
-
import { join, resolve, relative, isAbsolute } from 'path';
|
|
4
|
-
import { tmpdir, homedir } from 'os';
|
|
5
5
|
|
|
6
6
|
interface HarRequest {
|
|
7
7
|
id: string;
|
|
@@ -24,14 +24,17 @@ interface HarRequest {
|
|
|
24
24
|
const MAX_CONCURRENT_SESSIONS = 100;
|
|
25
25
|
const MAX_REQUESTS_PER_SESSION = 5_000;
|
|
26
26
|
|
|
27
|
-
const _sessions = new Map<
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
27
|
+
const _sessions = new Map<
|
|
28
|
+
string,
|
|
29
|
+
{
|
|
30
|
+
requests: Map<string, Partial<HarRequest>>;
|
|
31
|
+
offReq: () => void;
|
|
32
|
+
offResp: () => void;
|
|
33
|
+
offFinished: () => void;
|
|
34
|
+
startTime: number;
|
|
35
|
+
startWallMs: number;
|
|
36
|
+
}
|
|
37
|
+
>();
|
|
35
38
|
|
|
36
39
|
/** Validate output path is within cwd or home dir to prevent path traversal. */
|
|
37
40
|
function safeOutputPath(p: string): string {
|
|
@@ -40,8 +43,10 @@ function safeOutputPath(p: string): string {
|
|
|
40
43
|
const home = homedir();
|
|
41
44
|
const relCwd = relative(cwd, resolved);
|
|
42
45
|
const relHome = relative(home, resolved);
|
|
43
|
-
if (
|
|
44
|
-
|
|
46
|
+
if (
|
|
47
|
+
(!relCwd.startsWith('..') && !isAbsolute(relCwd)) ||
|
|
48
|
+
(!relHome.startsWith('..') && !isAbsolute(relHome))
|
|
49
|
+
) {
|
|
45
50
|
return resolved;
|
|
46
51
|
}
|
|
47
52
|
// Reject out-of-scope paths — fall back to tmpdir
|
|
@@ -51,7 +56,9 @@ function safeOutputPath(p: string): string {
|
|
|
51
56
|
export async function startHarRecording(client: CdpClient, sessionId: string): Promise<void> {
|
|
52
57
|
if (_sessions.has(sessionId)) throw new Error('HAR recording already in progress');
|
|
53
58
|
if (_sessions.size >= MAX_CONCURRENT_SESSIONS) {
|
|
54
|
-
throw new Error(
|
|
59
|
+
throw new Error(
|
|
60
|
+
`HAR recording limit reached (max ${MAX_CONCURRENT_SESSIONS} concurrent sessions)`,
|
|
61
|
+
);
|
|
55
62
|
}
|
|
56
63
|
|
|
57
64
|
const requests = new Map<string, Partial<HarRequest>>();
|
|
@@ -68,7 +75,11 @@ export async function startHarRecording(client: CdpClient, sessionId: string): P
|
|
|
68
75
|
if (sid !== sessionId) return;
|
|
69
76
|
// Cap to prevent unbounded memory growth on high-traffic pages
|
|
70
77
|
if (requests.size >= MAX_REQUESTS_PER_SESSION) return;
|
|
71
|
-
const p = params as {
|
|
78
|
+
const p = params as {
|
|
79
|
+
requestId: string;
|
|
80
|
+
request: { url: string; method: string; headers: Record<string, string> };
|
|
81
|
+
timestamp: number;
|
|
82
|
+
};
|
|
72
83
|
requests.set(p.requestId, {
|
|
73
84
|
id: p.requestId,
|
|
74
85
|
url: p.request.url,
|
|
@@ -81,7 +92,19 @@ export async function startHarRecording(client: CdpClient, sessionId: string): P
|
|
|
81
92
|
|
|
82
93
|
const offResp = client.on('Network.responseReceived', (params, sid) => {
|
|
83
94
|
if (sid !== sessionId) return;
|
|
84
|
-
const p = params as {
|
|
95
|
+
const p = params as {
|
|
96
|
+
requestId: string;
|
|
97
|
+
response: {
|
|
98
|
+
url: string;
|
|
99
|
+
status: number;
|
|
100
|
+
statusText: string;
|
|
101
|
+
mimeType: string;
|
|
102
|
+
headers: Record<string, string>;
|
|
103
|
+
fromDiskCache: boolean;
|
|
104
|
+
fromServiceWorker: boolean;
|
|
105
|
+
};
|
|
106
|
+
timestamp: number;
|
|
107
|
+
};
|
|
85
108
|
const entry = requests.get(p.requestId);
|
|
86
109
|
if (entry) {
|
|
87
110
|
entry.status = p.response.status;
|
|
@@ -110,7 +133,7 @@ export async function stopHarRecording(
|
|
|
110
133
|
client: CdpClient,
|
|
111
134
|
sessionId: string,
|
|
112
135
|
outputPath?: string,
|
|
113
|
-
captureResponseBodies = false
|
|
136
|
+
captureResponseBodies = false,
|
|
114
137
|
): Promise<string> {
|
|
115
138
|
const state = _sessions.get(sessionId);
|
|
116
139
|
if (!state) throw new Error('No active HAR recording for this session');
|
|
@@ -125,7 +148,9 @@ export async function stopHarRecording(
|
|
|
125
148
|
for (const [reqId, entry] of state.requests.entries()) {
|
|
126
149
|
try {
|
|
127
150
|
const body = await client.send<{ body: string; base64Encoded: boolean }>(
|
|
128
|
-
'Network.getResponseBody',
|
|
151
|
+
'Network.getResponseBody',
|
|
152
|
+
{ requestId: reqId },
|
|
153
|
+
sessionId,
|
|
129
154
|
);
|
|
130
155
|
entry.responseBody = body.body;
|
|
131
156
|
entry.bodyEncoding = body.base64Encoded ? 'base64' : undefined;
|
|
@@ -139,7 +164,9 @@ export async function stopHarRecording(
|
|
|
139
164
|
}
|
|
140
165
|
|
|
141
166
|
const har = buildHar(Array.from(state.requests.values()), state.startTime);
|
|
142
|
-
const safePath = outputPath
|
|
167
|
+
const safePath = outputPath
|
|
168
|
+
? safeOutputPath(outputPath)
|
|
169
|
+
: join(tmpdir(), `monomind-har-${Date.now()}.har`);
|
|
143
170
|
await writeFile(safePath, JSON.stringify(har, null, 2));
|
|
144
171
|
return safePath;
|
|
145
172
|
}
|
|
@@ -159,12 +186,14 @@ function buildHar(entries: Partial<HarRequest>[], startTime: number) {
|
|
|
159
186
|
log: {
|
|
160
187
|
version: '1.2',
|
|
161
188
|
creator: { name: 'monomind browse', version: '1.0.0' },
|
|
162
|
-
pages: [
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
189
|
+
pages: [
|
|
190
|
+
{
|
|
191
|
+
startedDateTime: new Date(startTime).toISOString(),
|
|
192
|
+
id: 'page_1',
|
|
193
|
+
title: '',
|
|
194
|
+
pageTimings: {},
|
|
195
|
+
},
|
|
196
|
+
],
|
|
168
197
|
entries: entries.map((e) => ({
|
|
169
198
|
startedDateTime: new Date(e.startTime ?? startTime).toISOString(),
|
|
170
199
|
time: (e.endTime ?? e.startTime ?? startTime) - (e.startTime ?? startTime),
|
|
@@ -183,7 +212,10 @@ function buildHar(entries: Partial<HarRequest>[], startTime: number) {
|
|
|
183
212
|
statusText: e.statusText ?? '',
|
|
184
213
|
httpVersion: 'HTTP/1.1',
|
|
185
214
|
cookies: [],
|
|
186
|
-
headers: Object.entries(e.responseHeaders ?? {}).map(([name, value]) => ({
|
|
215
|
+
headers: Object.entries(e.responseHeaders ?? {}).map(([name, value]) => ({
|
|
216
|
+
name,
|
|
217
|
+
value,
|
|
218
|
+
})),
|
|
187
219
|
content: {
|
|
188
220
|
size: e.size ?? -1,
|
|
189
221
|
mimeType: e.mimeType ?? 'application/octet-stream',
|