opendevbrowser 0.0.17 → 0.0.19
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/README.md +172 -73
- package/dist/annotate/agent-inbox-store.d.ts +58 -0
- package/dist/annotate/agent-inbox-store.d.ts.map +1 -0
- package/dist/annotate/agent-inbox.d.ts +25 -0
- package/dist/annotate/agent-inbox.d.ts.map +1 -0
- package/dist/annotate/direct-annotator.d.ts.map +1 -1
- package/dist/annotate/timeout-messages.d.ts +4 -0
- package/dist/annotate/timeout-messages.d.ts.map +1 -0
- package/dist/automation/coordinator.d.ts +55 -0
- package/dist/automation/coordinator.d.ts.map +1 -0
- package/dist/browser/annotation-manager.d.ts +4 -1
- package/dist/browser/annotation-manager.d.ts.map +1 -1
- package/dist/browser/browser-manager.d.ts +147 -47
- package/dist/browser/browser-manager.d.ts.map +1 -1
- package/dist/browser/canvas-client.d.ts +1 -0
- package/dist/browser/canvas-client.d.ts.map +1 -1
- package/dist/browser/canvas-code-sync-manager.d.ts +9 -1
- package/dist/browser/canvas-code-sync-manager.d.ts.map +1 -1
- package/dist/browser/canvas-manager.d.ts +29 -1
- package/dist/browser/canvas-manager.d.ts.map +1 -1
- package/dist/browser/global-challenge-coordinator.d.ts +27 -0
- package/dist/browser/global-challenge-coordinator.d.ts.map +1 -0
- package/dist/browser/manager-types.d.ts +167 -1
- package/dist/browser/manager-types.d.ts.map +1 -1
- package/dist/browser/ops-browser-manager.d.ts +103 -3
- package/dist/browser/ops-browser-manager.d.ts.map +1 -1
- package/dist/browser/ops-client.d.ts +17 -1
- package/dist/browser/ops-client.d.ts.map +1 -1
- package/dist/browser/playwright-runtime.d.ts +4 -0
- package/dist/browser/playwright-runtime.d.ts.map +1 -0
- package/dist/browser/review-surface.d.ts +9 -0
- package/dist/browser/review-surface.d.ts.map +1 -0
- package/dist/browser/screencast-recorder.d.ts +57 -0
- package/dist/browser/screencast-recorder.d.ts.map +1 -0
- package/dist/browser/session-inspector.d.ts +71 -0
- package/dist/browser/session-inspector.d.ts.map +1 -0
- package/dist/browser/session-store.d.ts +5 -1
- package/dist/browser/session-store.d.ts.map +1 -1
- package/dist/browser/system-chrome-cookies.d.ts +46 -0
- package/dist/browser/system-chrome-cookies.d.ts.map +1 -0
- package/dist/browser/target-manager.d.ts +1 -0
- package/dist/browser/target-manager.d.ts.map +1 -1
- package/dist/cache/chrome-locator.d.ts.map +1 -1
- package/dist/cache/chrome-user-data.d.ts +17 -0
- package/dist/cache/chrome-user-data.d.ts.map +1 -0
- package/dist/canvas/adapter-plugins/loader.d.ts +13 -0
- package/dist/canvas/adapter-plugins/loader.d.ts.map +1 -0
- package/dist/canvas/adapter-plugins/manifest.d.ts +146 -0
- package/dist/canvas/adapter-plugins/manifest.d.ts.map +1 -0
- package/dist/canvas/adapter-plugins/types.d.ts +83 -0
- package/dist/canvas/adapter-plugins/types.d.ts.map +1 -0
- package/dist/canvas/adapter-plugins/validator.d.ts +10 -0
- package/dist/canvas/adapter-plugins/validator.d.ts.map +1 -0
- package/dist/canvas/code-sync/apply-tsx.d.ts +3 -1
- package/dist/canvas/code-sync/apply-tsx.d.ts.map +1 -1
- package/dist/canvas/code-sync/import.d.ts +1 -0
- package/dist/canvas/code-sync/import.d.ts.map +1 -1
- package/dist/canvas/code-sync/manifest.d.ts +2 -1
- package/dist/canvas/code-sync/manifest.d.ts.map +1 -1
- package/dist/canvas/code-sync/tsx-adapter.d.ts.map +1 -1
- package/dist/canvas/code-sync/types.d.ts +102 -10
- package/dist/canvas/code-sync/types.d.ts.map +1 -1
- package/dist/canvas/document-store.d.ts +11 -1
- package/dist/canvas/document-store.d.ts.map +1 -1
- package/dist/canvas/export.d.ts.map +1 -1
- package/dist/canvas/framework-adapters/custom-elements-v1.d.ts +3 -0
- package/dist/canvas/framework-adapters/custom-elements-v1.d.ts.map +1 -0
- package/dist/canvas/framework-adapters/html-static-v1.d.ts +3 -0
- package/dist/canvas/framework-adapters/html-static-v1.d.ts.map +1 -0
- package/dist/canvas/framework-adapters/markup.d.ts +9 -0
- package/dist/canvas/framework-adapters/markup.d.ts.map +1 -0
- package/dist/canvas/framework-adapters/react-tsx-v2.d.ts +3 -0
- package/dist/canvas/framework-adapters/react-tsx-v2.d.ts.map +1 -0
- package/dist/canvas/framework-adapters/registry.d.ts +12 -0
- package/dist/canvas/framework-adapters/registry.d.ts.map +1 -0
- package/dist/canvas/framework-adapters/svelte-sfc-v1.d.ts +3 -0
- package/dist/canvas/framework-adapters/svelte-sfc-v1.d.ts.map +1 -0
- package/dist/canvas/framework-adapters/types.d.ts +57 -0
- package/dist/canvas/framework-adapters/types.d.ts.map +1 -0
- package/dist/canvas/framework-adapters/vue-sfc-v1.d.ts +3 -0
- package/dist/canvas/framework-adapters/vue-sfc-v1.d.ts.map +1 -0
- package/dist/canvas/kits/catalog.d.ts +5 -0
- package/dist/canvas/kits/catalog.d.ts.map +1 -0
- package/dist/canvas/library-adapters/react/index.d.ts +3 -0
- package/dist/canvas/library-adapters/react/index.d.ts.map +1 -0
- package/dist/canvas/library-adapters/registry.d.ts +11 -0
- package/dist/canvas/library-adapters/registry.d.ts.map +1 -0
- package/dist/canvas/library-adapters/types.d.ts +43 -0
- package/dist/canvas/library-adapters/types.d.ts.map +1 -0
- package/dist/canvas/repo-store.d.ts +2 -0
- package/dist/canvas/repo-store.d.ts.map +1 -1
- package/dist/canvas/starters/catalog.d.ts +34 -0
- package/dist/canvas/starters/catalog.d.ts.map +1 -0
- package/dist/canvas/token-references.d.ts +22 -0
- package/dist/canvas/token-references.d.ts.map +1 -0
- package/dist/canvas/types.d.ts +345 -6
- package/dist/canvas/types.d.ts.map +1 -1
- package/dist/challenges/action-loop.d.ts +13 -0
- package/dist/challenges/action-loop.d.ts.map +1 -0
- package/dist/challenges/capability-matrix.d.ts +3 -0
- package/dist/challenges/capability-matrix.d.ts.map +1 -0
- package/dist/challenges/evidence-bundle.d.ts +48 -0
- package/dist/challenges/evidence-bundle.d.ts.map +1 -0
- package/dist/challenges/governed-adapter-gateway.d.ts +4 -0
- package/dist/challenges/governed-adapter-gateway.d.ts.map +1 -0
- package/dist/challenges/human-yield-gate.d.ts +20 -0
- package/dist/challenges/human-yield-gate.d.ts.map +1 -0
- package/dist/challenges/index.d.ts +15 -0
- package/dist/challenges/index.d.ts.map +1 -0
- package/dist/challenges/interpreter.d.ts +3 -0
- package/dist/challenges/interpreter.d.ts.map +1 -0
- package/dist/challenges/optional-computer-use-bridge.d.ts +9 -0
- package/dist/challenges/optional-computer-use-bridge.d.ts.map +1 -0
- package/dist/challenges/orchestrator.d.ts +32 -0
- package/dist/challenges/orchestrator.d.ts.map +1 -0
- package/dist/challenges/outcome-recorder.d.ts +8 -0
- package/dist/challenges/outcome-recorder.d.ts.map +1 -0
- package/dist/challenges/owned-environment-lane.d.ts +3 -0
- package/dist/challenges/owned-environment-lane.d.ts.map +1 -0
- package/dist/challenges/policy-gate.d.ts +9 -0
- package/dist/challenges/policy-gate.d.ts.map +1 -0
- package/dist/challenges/sanctioned-identity-lane.d.ts +3 -0
- package/dist/challenges/sanctioned-identity-lane.d.ts.map +1 -0
- package/dist/challenges/service-adapter-lane.d.ts +3 -0
- package/dist/challenges/service-adapter-lane.d.ts.map +1 -0
- package/dist/challenges/strategy-selector.d.ts +10 -0
- package/dist/challenges/strategy-selector.d.ts.map +1 -0
- package/dist/challenges/types.d.ts +277 -0
- package/dist/challenges/types.d.ts.map +1 -0
- package/dist/challenges/verification-gate.d.ts +15 -0
- package/dist/challenges/verification-gate.d.ts.map +1 -0
- package/dist/chunk-5FZQJRBQ.js +15256 -0
- package/dist/chunk-5FZQJRBQ.js.map +1 -0
- package/dist/chunk-W4IHGDXV.js +33519 -0
- package/dist/chunk-W4IHGDXV.js.map +1 -0
- package/dist/chunk-YBQECXZX.js +409 -0
- package/dist/chunk-YBQECXZX.js.map +1 -0
- package/dist/cli/args.d.ts +4 -4
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/commands/artifacts.d.ts.map +1 -1
- package/dist/cli/commands/canvas.d.ts +7 -7
- package/dist/cli/commands/canvas.d.ts.map +1 -1
- package/dist/cli/commands/daemon.d.ts +7 -0
- package/dist/cli/commands/daemon.d.ts.map +1 -1
- package/dist/cli/commands/desktop/accessibility-snapshot.d.ts +3 -0
- package/dist/cli/commands/desktop/accessibility-snapshot.d.ts.map +1 -0
- package/dist/cli/commands/desktop/active-window.d.ts +3 -0
- package/dist/cli/commands/desktop/active-window.d.ts.map +1 -0
- package/dist/cli/commands/desktop/capture-desktop.d.ts +3 -0
- package/dist/cli/commands/desktop/capture-desktop.d.ts.map +1 -0
- package/dist/cli/commands/desktop/capture-window.d.ts +3 -0
- package/dist/cli/commands/desktop/capture-window.d.ts.map +1 -0
- package/dist/cli/commands/desktop/shared.d.ts +19 -0
- package/dist/cli/commands/desktop/shared.d.ts.map +1 -0
- package/dist/cli/commands/desktop/status.d.ts +3 -0
- package/dist/cli/commands/desktop/status.d.ts.map +1 -0
- package/dist/cli/commands/desktop/windows.d.ts +3 -0
- package/dist/cli/commands/desktop/windows.d.ts.map +1 -0
- package/dist/cli/commands/devtools/dialog.d.ts +19 -0
- package/dist/cli/commands/devtools/dialog.d.ts.map +1 -0
- package/dist/cli/commands/devtools/screencast-start.d.ts +20 -0
- package/dist/cli/commands/devtools/screencast-start.d.ts.map +1 -0
- package/dist/cli/commands/devtools/screencast-stop.d.ts +17 -0
- package/dist/cli/commands/devtools/screencast-stop.d.ts.map +1 -0
- package/dist/cli/commands/devtools/screenshot.d.ts +2 -0
- package/dist/cli/commands/devtools/screenshot.d.ts.map +1 -1
- package/dist/cli/commands/interact/click.d.ts.map +1 -1
- package/dist/cli/commands/interact/pointer-down.d.ts +7 -0
- package/dist/cli/commands/interact/pointer-down.d.ts.map +1 -0
- package/dist/cli/commands/interact/pointer-drag.d.ts +7 -0
- package/dist/cli/commands/interact/pointer-drag.d.ts.map +1 -0
- package/dist/cli/commands/interact/pointer-move.d.ts +7 -0
- package/dist/cli/commands/interact/pointer-move.d.ts.map +1 -0
- package/dist/cli/commands/interact/pointer-shared.d.ts +6 -0
- package/dist/cli/commands/interact/pointer-shared.d.ts.map +1 -0
- package/dist/cli/commands/interact/pointer-up.d.ts +7 -0
- package/dist/cli/commands/interact/pointer-up.d.ts.map +1 -0
- package/dist/cli/commands/interact/upload.d.ts +18 -0
- package/dist/cli/commands/interact/upload.d.ts.map +1 -0
- package/dist/cli/commands/macro-resolve.d.ts +2 -0
- package/dist/cli/commands/macro-resolve.d.ts.map +1 -1
- package/dist/cli/commands/native.d.ts +10 -7
- package/dist/cli/commands/native.d.ts.map +1 -1
- package/dist/cli/commands/nav/review.d.ts +7 -0
- package/dist/cli/commands/nav/review.d.ts.map +1 -0
- package/dist/cli/commands/nav/snapshot.d.ts.map +1 -1
- package/dist/cli/commands/pages/open.d.ts.map +1 -1
- package/dist/cli/commands/product-video.d.ts +2 -0
- package/dist/cli/commands/product-video.d.ts.map +1 -1
- package/dist/cli/commands/research.d.ts +3 -0
- package/dist/cli/commands/research.d.ts.map +1 -1
- package/dist/cli/commands/run.d.ts +14 -0
- package/dist/cli/commands/run.d.ts.map +1 -1
- package/dist/cli/commands/serve.d.ts +1 -26
- package/dist/cli/commands/serve.d.ts.map +1 -1
- package/dist/cli/commands/session/connect.d.ts.map +1 -1
- package/dist/cli/commands/session/disconnect.d.ts.map +1 -1
- package/dist/cli/commands/session/inspector.d.ts +21 -0
- package/dist/cli/commands/session/inspector.d.ts.map +1 -0
- package/dist/cli/commands/session/launch.d.ts.map +1 -1
- package/dist/cli/commands/shopping.d.ts +5 -0
- package/dist/cli/commands/shopping.d.ts.map +1 -1
- package/dist/cli/commands/status.d.ts +2 -14
- package/dist/cli/commands/status.d.ts.map +1 -1
- package/dist/cli/commands/targets/new.d.ts.map +1 -1
- package/dist/cli/daemon-autostart.d.ts +11 -0
- package/dist/cli/daemon-autostart.d.ts.map +1 -1
- package/dist/cli/daemon-client.d.ts +3 -0
- package/dist/cli/daemon-client.d.ts.map +1 -1
- package/dist/cli/daemon-commands.d.ts.map +1 -1
- package/dist/cli/daemon-state.d.ts +16 -0
- package/dist/cli/daemon-state.d.ts.map +1 -1
- package/dist/cli/daemon-status.d.ts +7 -2
- package/dist/cli/daemon-status.d.ts.map +1 -1
- package/dist/cli/daemon.d.ts +1 -0
- package/dist/cli/daemon.d.ts.map +1 -1
- package/dist/cli/help.d.ts +15 -4
- package/dist/cli/help.d.ts.map +1 -1
- package/dist/cli/index.js +2476 -1036
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/install-autostart-output.d.ts +6 -0
- package/dist/cli/install-autostart-output.d.ts.map +1 -0
- package/dist/cli/install-autostart-reconciliation.d.ts +23 -0
- package/dist/cli/install-autostart-reconciliation.d.ts.map +1 -0
- package/dist/cli/installers/skills.d.ts +42 -6
- package/dist/cli/installers/skills.d.ts.map +1 -1
- package/dist/cli/output.d.ts +3 -0
- package/dist/cli/output.d.ts.map +1 -1
- package/dist/cli/remote-desktop-runtime.d.ts +15 -0
- package/dist/cli/remote-desktop-runtime.d.ts.map +1 -0
- package/dist/cli/remote-manager.d.ts +24 -2
- package/dist/cli/remote-manager.d.ts.map +1 -1
- package/dist/cli/transport-timeouts.d.ts +8 -0
- package/dist/cli/transport-timeouts.d.ts.map +1 -0
- package/dist/cli/utils/http.d.ts +9 -0
- package/dist/cli/utils/http.d.ts.map +1 -1
- package/dist/cli/utils/parse.d.ts +2 -0
- package/dist/cli/utils/parse.d.ts.map +1 -1
- package/dist/cli/utils/skills.d.ts +1 -2
- package/dist/cli/utils/skills.d.ts.map +1 -1
- package/dist/cli/utils/workflow-message.d.ts +2 -0
- package/dist/cli/utils/workflow-message.d.ts.map +1 -0
- package/dist/config.d.ts +47 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/core/bootstrap.d.ts.map +1 -1
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/logging.d.ts +3 -1
- package/dist/core/logging.d.ts.map +1 -1
- package/dist/core/runtime-assemblies.d.ts +22 -0
- package/dist/core/runtime-assemblies.d.ts.map +1 -0
- package/dist/core/types.d.ts +15 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/desktop/audit.d.ts +37 -0
- package/dist/desktop/audit.d.ts.map +1 -0
- package/dist/desktop/errors.d.ts +7 -0
- package/dist/desktop/errors.d.ts.map +1 -0
- package/dist/desktop/index.d.ts +6 -0
- package/dist/desktop/index.d.ts.map +1 -0
- package/dist/desktop/runtime.d.ts +26 -0
- package/dist/desktop/runtime.d.ts.map +1 -0
- package/dist/desktop/types.d.ts +76 -0
- package/dist/desktop/types.d.ts.map +1 -0
- package/dist/extension-extractor.d.ts +6 -0
- package/dist/extension-extractor.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1103 -467
- package/dist/index.js.map +1 -1
- package/dist/integrations/figma/assets.d.ts +13 -0
- package/dist/integrations/figma/assets.d.ts.map +1 -0
- package/dist/integrations/figma/auth.d.ts +3 -0
- package/dist/integrations/figma/auth.d.ts.map +1 -0
- package/dist/integrations/figma/client.d.ts +42 -0
- package/dist/integrations/figma/client.d.ts.map +1 -0
- package/dist/integrations/figma/mappers.d.ts +23 -0
- package/dist/integrations/figma/mappers.d.ts.map +1 -0
- package/dist/integrations/figma/normalize.d.ts +99 -0
- package/dist/integrations/figma/normalize.d.ts.map +1 -0
- package/dist/integrations/figma/url.d.ts +17 -0
- package/dist/integrations/figma/url.d.ts.map +1 -0
- package/dist/integrations/figma/variables.d.ts +21 -0
- package/dist/integrations/figma/variables.d.ts.map +1 -0
- package/dist/macros/execute-runtime.d.ts +19 -0
- package/dist/macros/execute-runtime.d.ts.map +1 -0
- package/dist/macros/execute.d.ts +3 -1
- package/dist/macros/execute.d.ts.map +1 -1
- package/dist/opendevbrowser.d.ts.map +1 -1
- package/dist/opendevbrowser.js +1103 -467
- package/dist/opendevbrowser.js.map +1 -1
- package/dist/providers/blocker.d.ts.map +1 -1
- package/dist/providers/browser-fallback.d.ts +30 -0
- package/dist/providers/browser-fallback.d.ts.map +1 -0
- package/dist/providers/constraint.d.ts +45 -0
- package/dist/providers/constraint.d.ts.map +1 -0
- package/dist/providers/index.d.ts +11 -2
- package/dist/providers/index.d.ts.map +1 -1
- package/dist/providers/policy.d.ts.map +1 -1
- package/dist/providers/product-video-compiler.d.ts +92 -0
- package/dist/providers/product-video-compiler.d.ts.map +1 -0
- package/dist/providers/registry.d.ts +37 -1
- package/dist/providers/registry.d.ts.map +1 -1
- package/dist/providers/renderer.d.ts.map +1 -1
- package/dist/providers/research-compiler.d.ts +64 -0
- package/dist/providers/research-compiler.d.ts.map +1 -0
- package/dist/providers/research-executor.d.ts +27 -0
- package/dist/providers/research-executor.d.ts.map +1 -0
- package/dist/providers/runtime-bundle.d.ts +26 -0
- package/dist/providers/runtime-bundle.d.ts.map +1 -0
- package/dist/providers/runtime-factory.d.ts +6 -1
- package/dist/providers/runtime-factory.d.ts.map +1 -1
- package/dist/providers/runtime-policy.d.ts +24 -0
- package/dist/providers/runtime-policy.d.ts.map +1 -0
- package/dist/providers/shared/anti-bot-policy.d.ts +3 -2
- package/dist/providers/shared/anti-bot-policy.d.ts.map +1 -1
- package/dist/providers/shopping/index.d.ts +11 -1
- package/dist/providers/shopping/index.d.ts.map +1 -1
- package/dist/providers/shopping-compiler.d.ts +51 -0
- package/dist/providers/shopping-compiler.d.ts.map +1 -0
- package/dist/providers/shopping-executor.d.ts +18 -0
- package/dist/providers/shopping-executor.d.ts.map +1 -0
- package/dist/providers/shopping-postprocess.d.ts +46 -0
- package/dist/providers/shopping-postprocess.d.ts.map +1 -0
- package/dist/providers/shopping-workflow.d.ts +33 -0
- package/dist/providers/shopping-workflow.d.ts.map +1 -0
- package/dist/providers/social/platform.d.ts +2 -1
- package/dist/providers/social/platform.d.ts.map +1 -1
- package/dist/providers/social/search-quality.d.ts +16 -0
- package/dist/providers/social/search-quality.d.ts.map +1 -0
- package/dist/providers/social/youtube-resolver.d.ts +2 -1
- package/dist/providers/social/youtube-resolver.d.ts.map +1 -1
- package/dist/providers/social/youtube.d.ts.map +1 -1
- package/dist/providers/types.d.ts +116 -4
- package/dist/providers/types.d.ts.map +1 -1
- package/dist/providers/web/crawl-worker.d.ts.map +1 -1
- package/dist/providers/web/extract.d.ts +16 -0
- package/dist/providers/web/extract.d.ts.map +1 -1
- package/dist/providers/web/index.d.ts.map +1 -1
- package/dist/providers/workflow-contracts.d.ts +53 -0
- package/dist/providers/workflow-contracts.d.ts.map +1 -0
- package/dist/providers/workflows.d.ts +30 -6
- package/dist/providers/workflows.d.ts.map +1 -1
- package/dist/{providers-G3LRHQXX.js → providers-G36AM3Z2.js} +2 -2
- package/dist/public-surface/generated-manifest.d.ts +1168 -0
- package/dist/public-surface/generated-manifest.d.ts.map +1 -0
- package/dist/public-surface/source.d.ts +437 -0
- package/dist/public-surface/source.d.ts.map +1 -0
- package/dist/relay/protocol.d.ts +25 -3
- package/dist/relay/protocol.d.ts.map +1 -1
- package/dist/relay/relay-endpoints.d.ts +21 -0
- package/dist/relay/relay-endpoints.d.ts.map +1 -1
- package/dist/relay/relay-server.d.ts +18 -0
- package/dist/relay/relay-server.d.ts.map +1 -1
- package/dist/skills/bundled-skill-directories.d.ts +8 -0
- package/dist/skills/bundled-skill-directories.d.ts.map +1 -0
- package/dist/skills/skill-loader.d.ts +9 -1
- package/dist/skills/skill-loader.d.ts.map +1 -1
- package/dist/skills/skill-loader.js +7 -0
- package/dist/skills/skill-nudge.d.ts.map +1 -1
- package/dist/skills/types.d.ts +31 -0
- package/dist/skills/types.d.ts.map +1 -1
- package/dist/snapshot/ops-snapshot.d.ts +1 -1
- package/dist/snapshot/ops-snapshot.d.ts.map +1 -1
- package/dist/snapshot/refs.d.ts +6 -1
- package/dist/snapshot/refs.d.ts.map +1 -1
- package/dist/snapshot/snapshotter.d.ts.map +1 -1
- package/dist/tools/connect.d.ts.map +1 -1
- package/dist/tools/deps.d.ts +4 -0
- package/dist/tools/deps.d.ts.map +1 -1
- package/dist/tools/desktop-shared.d.ts +6 -0
- package/dist/tools/desktop-shared.d.ts.map +1 -0
- package/dist/tools/desktop_accessibility_snapshot.d.ts +4 -0
- package/dist/tools/desktop_accessibility_snapshot.d.ts.map +1 -0
- package/dist/tools/desktop_active_window.d.ts +4 -0
- package/dist/tools/desktop_active_window.d.ts.map +1 -0
- package/dist/tools/desktop_capture_desktop.d.ts +4 -0
- package/dist/tools/desktop_capture_desktop.d.ts.map +1 -0
- package/dist/tools/desktop_capture_window.d.ts +4 -0
- package/dist/tools/desktop_capture_window.d.ts.map +1 -0
- package/dist/tools/desktop_status.d.ts +4 -0
- package/dist/tools/desktop_status.d.ts.map +1 -0
- package/dist/tools/desktop_windows.d.ts +4 -0
- package/dist/tools/desktop_windows.d.ts.map +1 -0
- package/dist/tools/dialog.d.ts +4 -0
- package/dist/tools/dialog.d.ts.map +1 -0
- package/dist/tools/index.d.ts +3 -0
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/launch.d.ts.map +1 -1
- package/dist/tools/macro_resolve.d.ts.map +1 -1
- package/dist/tools/pointer_down.d.ts +4 -0
- package/dist/tools/pointer_down.d.ts.map +1 -0
- package/dist/tools/pointer_drag.d.ts +4 -0
- package/dist/tools/pointer_drag.d.ts.map +1 -0
- package/dist/tools/pointer_move.d.ts +4 -0
- package/dist/tools/pointer_move.d.ts.map +1 -0
- package/dist/tools/pointer_up.d.ts +4 -0
- package/dist/tools/pointer_up.d.ts.map +1 -0
- package/dist/tools/product_video_run.d.ts.map +1 -1
- package/dist/tools/prompting_guide.d.ts.map +1 -1
- package/dist/tools/research_run.d.ts.map +1 -1
- package/dist/tools/review.d.ts +4 -0
- package/dist/tools/review.d.ts.map +1 -0
- package/dist/tools/screencast_start.d.ts +4 -0
- package/dist/tools/screencast_start.d.ts.map +1 -0
- package/dist/tools/screencast_stop.d.ts +4 -0
- package/dist/tools/screencast_stop.d.ts.map +1 -0
- package/dist/tools/screenshot.d.ts.map +1 -1
- package/dist/tools/session_inspector.d.ts +4 -0
- package/dist/tools/session_inspector.d.ts.map +1 -0
- package/dist/tools/shopping_run.d.ts.map +1 -1
- package/dist/tools/skill_list.d.ts.map +1 -1
- package/dist/tools/skill_load.d.ts.map +1 -1
- package/dist/tools/upload.d.ts +4 -0
- package/dist/tools/upload.d.ts.map +1 -0
- package/dist/tools/workflow-runtime.d.ts +4 -1
- package/dist/tools/workflow-runtime.d.ts.map +1 -1
- package/dist/utils/package-assets.d.ts +4 -0
- package/dist/utils/package-assets.d.ts.map +1 -0
- package/extension/canvas.html +379 -9
- package/extension/dist/annotate-content.js +62 -32
- package/extension/dist/annotation-payload.js +57 -21
- package/extension/dist/background.js +406 -61
- package/extension/dist/canvas/canvas-runtime.js +481 -52
- package/extension/dist/canvas/model.js +129 -1
- package/extension/dist/canvas-page.js +1882 -74
- package/extension/dist/ops/dom-bridge.js +139 -0
- package/extension/dist/ops/ops-runtime.js +2854 -295
- package/extension/dist/ops/ops-session-store.js +83 -5
- package/extension/dist/ops/snapshot-builder.js +2 -2
- package/extension/dist/ops/snapshot-shared.js +2 -2
- package/extension/dist/ops/target-session-coordinator.js +5 -3
- package/extension/dist/popup.js +50 -15
- package/extension/dist/services/CDPRouter.js +1567 -63
- package/extension/dist/services/ConnectionManager.js +436 -78
- package/extension/dist/services/RelayClient.js +70 -30
- package/extension/dist/services/TabManager.js +83 -10
- package/extension/dist/services/TargetSessionMap.js +127 -3
- package/extension/dist/services/attach-errors.js +20 -0
- package/extension/dist/services/cdp-router-commands.js +135 -8
- package/extension/dist/services/url-restrictions.js +9 -13
- package/extension/manifest.json +2 -2
- package/extension/popup.html +7 -6
- package/package.json +15 -7
- package/skills/AGENTS.md +9 -8
- package/skills/opendevbrowser-best-practices/SKILL.md +118 -9
- package/skills/opendevbrowser-best-practices/artifacts/browser-agent-known-issues-matrix.md +1 -0
- package/skills/opendevbrowser-best-practices/artifacts/command-channel-reference.md +26 -12
- package/skills/opendevbrowser-best-practices/artifacts/parity-gates.md +9 -2
- package/skills/opendevbrowser-best-practices/artifacts/provider-workflows.md +6 -0
- package/skills/opendevbrowser-best-practices/artifacts/skill-runtime-surface-matrix.md +58 -0
- package/skills/opendevbrowser-best-practices/assets/templates/skill-runtime-pack-matrix.json +674 -0
- package/skills/opendevbrowser-best-practices/assets/templates/surface-audit-checklist.json +9 -4
- package/skills/opendevbrowser-best-practices/scripts/odb-workflow.sh +89 -20
- package/skills/opendevbrowser-best-practices/scripts/resolve-odb-cli.sh +100 -0
- package/skills/opendevbrowser-best-practices/scripts/run-robustness-audit.sh +1 -0
- package/skills/opendevbrowser-best-practices/scripts/validate-skill-assets.sh +256 -116
- package/skills/opendevbrowser-best-practices/scripts/validator-fixture-cli.sh +208 -0
- package/skills/opendevbrowser-continuity-ledger/SKILL.md +14 -1
- package/skills/opendevbrowser-continuity-ledger/scripts/validate-skill-assets.sh +61 -0
- package/skills/opendevbrowser-data-extraction/SKILL.md +6 -0
- package/skills/opendevbrowser-data-extraction/scripts/validate-skill-assets.sh +112 -0
- package/skills/opendevbrowser-design-agent/SKILL.md +275 -0
- package/skills/opendevbrowser-design-agent/artifacts/app-shell-and-state-wiring.md +84 -0
- package/skills/opendevbrowser-design-agent/artifacts/async-search-state-ownership.md +58 -0
- package/skills/opendevbrowser-design-agent/artifacts/component-pattern-index.md +130 -0
- package/skills/opendevbrowser-design-agent/artifacts/design-contract-playbook.md +157 -0
- package/skills/opendevbrowser-design-agent/artifacts/design-release-gate.md +40 -0
- package/skills/opendevbrowser-design-agent/artifacts/design-workflows.md +153 -0
- package/skills/opendevbrowser-design-agent/artifacts/existing-surface-adaptation.md +56 -0
- package/skills/opendevbrowser-design-agent/artifacts/external-pattern-synthesis.md +103 -0
- package/skills/opendevbrowser-design-agent/artifacts/frontend-evaluation-rubric.md +61 -0
- package/skills/opendevbrowser-design-agent/artifacts/implementation-anti-patterns.md +163 -0
- package/skills/opendevbrowser-design-agent/artifacts/isolated-preview-validation.md +68 -0
- package/skills/opendevbrowser-design-agent/artifacts/loading-and-feedback-surfaces.md +56 -0
- package/skills/opendevbrowser-design-agent/artifacts/opendevbrowser-ui-example-map.md +44 -0
- package/skills/opendevbrowser-design-agent/artifacts/performance-audit-playbook.md +70 -0
- package/skills/opendevbrowser-design-agent/artifacts/research-harvest-workflow.md +81 -0
- package/skills/opendevbrowser-design-agent/artifacts/scroll-reveal-surface-planning.md +64 -0
- package/skills/opendevbrowser-design-agent/artifacts/state-ownership-matrix.md +36 -0
- package/skills/opendevbrowser-design-agent/artifacts/theming-and-token-ownership.md +43 -0
- package/skills/opendevbrowser-design-agent/assets/templates/canvas-generation-plan.design.v1.json +58 -0
- package/skills/opendevbrowser-design-agent/assets/templates/design-audit-report.v1.md +34 -0
- package/skills/opendevbrowser-design-agent/assets/templates/design-brief.v1.md +40 -0
- package/skills/opendevbrowser-design-agent/assets/templates/design-contract.v1.json +226 -0
- package/skills/opendevbrowser-design-agent/assets/templates/design-release-gate.v1.json +35 -0
- package/skills/opendevbrowser-design-agent/assets/templates/design-review-checklist.json +57 -0
- package/skills/opendevbrowser-design-agent/assets/templates/real-surface-design-matrix.json +32 -0
- package/skills/opendevbrowser-design-agent/assets/templates/reference-pattern-board.v1.json +31 -0
- package/skills/opendevbrowser-design-agent/scripts/design-workflow.sh +171 -0
- package/skills/opendevbrowser-design-agent/scripts/extract-canvas-plan.sh +56 -0
- package/skills/opendevbrowser-design-agent/scripts/validate-skill-assets.sh +223 -0
- package/skills/opendevbrowser-form-testing/SKILL.md +19 -3
- package/skills/opendevbrowser-form-testing/artifacts/form-workflows.md +5 -4
- package/skills/opendevbrowser-form-testing/assets/templates/challenge-decision-tree.json +2 -0
- package/skills/opendevbrowser-form-testing/scripts/validate-skill-assets.sh +109 -0
- package/skills/opendevbrowser-login-automation/SKILL.md +21 -3
- package/skills/opendevbrowser-login-automation/artifacts/login-workflows.md +5 -4
- package/skills/opendevbrowser-login-automation/assets/templates/auth-signals.json +5 -0
- package/skills/opendevbrowser-login-automation/assets/templates/login-scenario-matrix.json +3 -2
- package/skills/opendevbrowser-login-automation/scripts/run-login-workflow.sh +17 -1
- package/skills/opendevbrowser-login-automation/scripts/validate-skill-assets.sh +133 -0
- package/skills/opendevbrowser-product-presentation-asset/SKILL.md +23 -11
- package/skills/opendevbrowser-product-presentation-asset/artifacts/asset-pack-assembly.md +5 -3
- package/skills/opendevbrowser-product-presentation-asset/assets/templates/shot-list.md +2 -0
- package/skills/opendevbrowser-product-presentation-asset/assets/templates/video-assembly.md +3 -2
- package/skills/opendevbrowser-product-presentation-asset/scripts/capture-screenshots.sh +5 -1
- package/skills/opendevbrowser-product-presentation-asset/scripts/collect-product.sh +6 -2
- package/skills/opendevbrowser-product-presentation-asset/scripts/download-images.sh +5 -1
- package/skills/opendevbrowser-product-presentation-asset/scripts/render-video-brief.sh +20 -7
- package/skills/opendevbrowser-product-presentation-asset/scripts/validate-skill-assets.sh +39 -0
- package/skills/opendevbrowser-product-presentation-asset/scripts/write-manifest.sh +5 -1
- package/skills/opendevbrowser-research/SKILL.md +14 -6
- package/skills/opendevbrowser-research/scripts/render-output.sh +5 -1
- package/skills/opendevbrowser-research/scripts/run-research.sh +5 -1
- package/skills/opendevbrowser-research/scripts/validate-skill-assets.sh +45 -0
- package/skills/opendevbrowser-research/scripts/write-artifacts.sh +5 -1
- package/skills/opendevbrowser-shopping/SKILL.md +20 -1
- package/skills/opendevbrowser-shopping/scripts/normalize-offers.sh +6 -2
- package/skills/opendevbrowser-shopping/scripts/run-deal-hunt.sh +5 -1
- package/skills/opendevbrowser-shopping/scripts/run-shopping.sh +5 -1
- package/skills/opendevbrowser-shopping/scripts/validate-skill-assets.sh +54 -0
- package/dist/chunk-5J3IFL3X.js +0 -16706
- package/dist/chunk-5J3IFL3X.js.map +0 -1
- package/dist/chunk-D633UO34.js +0 -8149
- package/dist/chunk-D633UO34.js.map +0 -1
- package/dist/chunk-V7KUDHDG.js +0 -276
- package/dist/chunk-V7KUDHDG.js.map +0 -1
- package/dist/runtime-factory-BICHDPE7.js +0 -13
- /package/dist/{providers-G3LRHQXX.js.map → providers-G36AM3Z2.js.map} +0 -0
- /package/dist/{runtime-factory-BICHDPE7.js.map → skills/skill-loader.js.map} +0 -0
|
@@ -1,15 +1,30 @@
|
|
|
1
1
|
import { TabManager } from "./TabManager.js";
|
|
2
2
|
import { TargetSessionMap } from "./TargetSessionMap.js";
|
|
3
3
|
import { logError } from "../logging.js";
|
|
4
|
+
import { getRestrictionMessage } from "./url-restrictions.js";
|
|
5
|
+
import { isAttachBlockedError } from "./attach-errors.js";
|
|
4
6
|
import { handleSetDiscoverTargets, handleSetAutoAttach, handleCreateTarget, handleCloseTarget, handleActivateTarget, handleAttachToTarget, handleRoutedCommand } from "./cdp-router-commands.js";
|
|
5
7
|
const FLAT_SESSION_ERROR = "Chrome 125+ required for extension relay (flat sessions).";
|
|
6
8
|
const DEPRECATED_SEND_MESSAGE = "Target.sendMessageToTarget is deprecated in flat session mode. Use sessionId routing.";
|
|
7
9
|
const DEFAULT_BROWSER_CONTEXT_ID = "default";
|
|
10
|
+
const DEFAULT_BROWSER_TARGET_ID = "browser";
|
|
11
|
+
const STALE_TAB_ERROR_MARKERS = [
|
|
12
|
+
"No tab with given id",
|
|
13
|
+
"Debugger is not attached",
|
|
14
|
+
"Detached while handling command"
|
|
15
|
+
];
|
|
8
16
|
export class CDPRouter {
|
|
9
17
|
debuggees = new Map();
|
|
18
|
+
rootTargetTabIds = new Map();
|
|
10
19
|
sessions = new TargetSessionMap();
|
|
11
20
|
tabManager = new TabManager();
|
|
12
21
|
rootAttachedSessions = new Set();
|
|
22
|
+
pendingTargetTabIds = new Map();
|
|
23
|
+
childAttachDiagnostics = new Map();
|
|
24
|
+
rootAttachDiagnostics = new Map();
|
|
25
|
+
rootRefreshDiagnostics = new Map();
|
|
26
|
+
expectedRootDetachDeadlines = new Map();
|
|
27
|
+
eventListeners = new Set();
|
|
13
28
|
callbacks = null;
|
|
14
29
|
autoAttachOptions = { autoAttach: false, waitForDebuggerOnStart: false, flatten: true };
|
|
15
30
|
discoverTargets = false;
|
|
@@ -22,6 +37,7 @@ export class CDPRouter {
|
|
|
22
37
|
churnTracker = new Map();
|
|
23
38
|
churnWindowMs = 5000;
|
|
24
39
|
churnThreshold = 3;
|
|
40
|
+
clientResetPending = false;
|
|
25
41
|
handleEventBound = (source, method, params) => {
|
|
26
42
|
this.handleEvent(source, method, params);
|
|
27
43
|
};
|
|
@@ -31,38 +47,364 @@ export class CDPRouter {
|
|
|
31
47
|
setCallbacks(callbacks) {
|
|
32
48
|
this.callbacks = callbacks;
|
|
33
49
|
}
|
|
50
|
+
addEventListener(listener) {
|
|
51
|
+
this.eventListeners.add(listener);
|
|
52
|
+
}
|
|
53
|
+
removeEventListener(listener) {
|
|
54
|
+
this.eventListeners.delete(listener);
|
|
55
|
+
}
|
|
56
|
+
async setDiscoverTargetsEnabled(discover) {
|
|
57
|
+
await this.prepareForNextClientIfNeeded();
|
|
58
|
+
const shouldEmit = discover && !this.discoverTargets;
|
|
59
|
+
this.discoverTargets = discover;
|
|
60
|
+
for (const debuggee of this.debuggees.values()) {
|
|
61
|
+
await this.applyDiscoverTargets(debuggee, discover);
|
|
62
|
+
}
|
|
63
|
+
if (!shouldEmit) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
for (const targetInfo of this.sessions.listTargetInfos()) {
|
|
67
|
+
const tabId = this.sessions.getByTargetId(targetInfo.targetId)?.tabId
|
|
68
|
+
?? this.rootTargetTabIds.get(targetInfo.targetId)
|
|
69
|
+
?? this.primaryTabId;
|
|
70
|
+
if (typeof tabId === "number") {
|
|
71
|
+
this.emitTargetCreated(tabId, targetInfo);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
async configureAutoAttach(options) {
|
|
76
|
+
await this.prepareForNextClientIfNeeded();
|
|
77
|
+
if (options.flatten === false) {
|
|
78
|
+
throw new Error(FLAT_SESSION_ERROR);
|
|
79
|
+
}
|
|
80
|
+
this.autoAttachOptions = { ...options, flatten: true };
|
|
81
|
+
if (this.autoAttachOptions.autoAttach) {
|
|
82
|
+
this.resetRootAttached();
|
|
83
|
+
}
|
|
84
|
+
for (const debuggee of this.debuggees.values()) {
|
|
85
|
+
await this.applyAutoAttach(debuggee);
|
|
86
|
+
}
|
|
87
|
+
if (!this.autoAttachOptions.autoAttach) {
|
|
88
|
+
this.emitRootDetached();
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
for (const tabId of this.sessions.listTabIds()) {
|
|
92
|
+
await this.refreshRootTargetInfo(tabId);
|
|
93
|
+
}
|
|
94
|
+
for (const targetInfo of this.sessions.listTargetInfos()) {
|
|
95
|
+
this.emitRootAttached(targetInfo);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
34
98
|
async attach(tabId) {
|
|
99
|
+
await this.prepareForNextClientIfNeeded(tabId);
|
|
35
100
|
await this.attachInternal(tabId, true);
|
|
36
101
|
}
|
|
102
|
+
async refreshTabAttachment(tabId) {
|
|
103
|
+
const preparedTabId = await this.prepareForNextClientIfNeeded(tabId);
|
|
104
|
+
const resetPreparedSameTabRoot = preparedTabId === tabId && this.debuggees.has(tabId);
|
|
105
|
+
const path = this.debuggees.has(tabId)
|
|
106
|
+
? "reattach_root_debuggee"
|
|
107
|
+
: "attach_internal";
|
|
108
|
+
try {
|
|
109
|
+
if (resetPreparedSameTabRoot) {
|
|
110
|
+
// Reset preflight already rebuilt this root; probing it is enough.
|
|
111
|
+
}
|
|
112
|
+
else if (path === "reattach_root_debuggee") {
|
|
113
|
+
await this.reattachRootDebuggee(tabId);
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
await this.attachInternal(tabId, false);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
catch (error) {
|
|
120
|
+
await this.captureRootRefreshDiagnostic(tabId, path, false, error);
|
|
121
|
+
throw error;
|
|
122
|
+
}
|
|
123
|
+
await this.captureRootRefreshDiagnostic(tabId, path, true);
|
|
124
|
+
}
|
|
125
|
+
async primeAttachedRootSession(tabId) {
|
|
126
|
+
await this.prepareForNextClientIfNeeded(tabId);
|
|
127
|
+
if (this.sessions.getAttachedRootSession(tabId)) {
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
await this.ensureAttachedRootSession(tabId);
|
|
131
|
+
}
|
|
132
|
+
async resolveTabTargetId(tabId) {
|
|
133
|
+
await this.prepareForNextClientIfNeeded(tabId);
|
|
134
|
+
return (await this.readDebuggerTargetInfo(tabId))?.id ?? null;
|
|
135
|
+
}
|
|
136
|
+
async resolveTabOpenerTargetId(tabId) {
|
|
137
|
+
await this.prepareForNextClientIfNeeded();
|
|
138
|
+
const { tab, pageTargets } = await this.readDebuggerPageTargets(tabId);
|
|
139
|
+
if (pageTargets.length === 0) {
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
const preferredTarget = this.selectPreferredDebuggerTargetInfo(tab, pageTargets);
|
|
143
|
+
const candidates = preferredTarget
|
|
144
|
+
? [preferredTarget, ...pageTargets.filter((target) => target !== preferredTarget)]
|
|
145
|
+
: pageTargets;
|
|
146
|
+
for (const candidate of candidates) {
|
|
147
|
+
const targetInfo = this.resolveTargetInfo(candidate.id);
|
|
148
|
+
const openerTabId = this.pendingTargetTabIds.get(candidate.id)
|
|
149
|
+
?? this.resolveLinkedTargetTabId(candidate.openerId)
|
|
150
|
+
?? this.resolveLinkedTargetTabId(targetInfo?.openerId)
|
|
151
|
+
?? null;
|
|
152
|
+
if (openerTabId !== null) {
|
|
153
|
+
return `tab-${openerTabId}`;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
async attachChildTarget(tabId, targetId) {
|
|
159
|
+
await this.prepareForNextClientIfNeeded(tabId);
|
|
160
|
+
let rootDebuggee;
|
|
161
|
+
try {
|
|
162
|
+
rootDebuggee = await this.resolveRootSessionDebuggee(tabId);
|
|
163
|
+
}
|
|
164
|
+
catch (error) {
|
|
165
|
+
this.recordChildAttachDiagnostic(tabId, targetId, {
|
|
166
|
+
stage: "raw_attach_failed",
|
|
167
|
+
reason: getErrorMessage(error)
|
|
168
|
+
});
|
|
169
|
+
throw error;
|
|
170
|
+
}
|
|
171
|
+
let initialStage;
|
|
172
|
+
let directError = null;
|
|
173
|
+
let rootTargetRetryStage;
|
|
174
|
+
const captureRootRecordState = () => {
|
|
175
|
+
const record = this.sessions.getByTabId(tabId);
|
|
176
|
+
return {
|
|
177
|
+
present: Boolean(record),
|
|
178
|
+
rootSessionId: record?.rootSessionId ?? null,
|
|
179
|
+
targetId: record?.targetInfo.targetId ?? null,
|
|
180
|
+
attachTargetId: record?.attachTargetId ?? null
|
|
181
|
+
};
|
|
182
|
+
};
|
|
183
|
+
try {
|
|
184
|
+
const directSessionId = await this.attachChildTargetWithDebuggee(rootDebuggee, targetId);
|
|
185
|
+
if (directSessionId) {
|
|
186
|
+
this.clearChildAttachDiagnostic(tabId, targetId);
|
|
187
|
+
return directSessionId;
|
|
188
|
+
}
|
|
189
|
+
const directTargetRetry = await this.attachChildTargetWithRootTargetId(rootDebuggee, targetId);
|
|
190
|
+
if (directTargetRetry.sessionId) {
|
|
191
|
+
this.clearChildAttachDiagnostic(tabId, targetId);
|
|
192
|
+
return directTargetRetry.sessionId;
|
|
193
|
+
}
|
|
194
|
+
if (directTargetRetry.stage !== "attached") {
|
|
195
|
+
rootTargetRetryStage = directTargetRetry.stage;
|
|
196
|
+
}
|
|
197
|
+
initialStage = "raw_attach_null";
|
|
198
|
+
}
|
|
199
|
+
catch (error) {
|
|
200
|
+
const attachBlocked = isAttachBlockedError(error);
|
|
201
|
+
const staleRootDebuggee = this.isStaleTabError(error);
|
|
202
|
+
if (!attachBlocked && !staleRootDebuggee) {
|
|
203
|
+
this.recordChildAttachDiagnostic(tabId, targetId, {
|
|
204
|
+
stage: "raw_attach_failed",
|
|
205
|
+
reason: getErrorMessage(error)
|
|
206
|
+
});
|
|
207
|
+
throw error;
|
|
208
|
+
}
|
|
209
|
+
if (staleRootDebuggee) {
|
|
210
|
+
directError = error;
|
|
211
|
+
}
|
|
212
|
+
if (attachBlocked || staleRootDebuggee) {
|
|
213
|
+
let directTargetRetry;
|
|
214
|
+
try {
|
|
215
|
+
directTargetRetry = await this.attachChildTargetWithRootTargetId(rootDebuggee, targetId, error);
|
|
216
|
+
}
|
|
217
|
+
catch (fallbackError) {
|
|
218
|
+
this.recordChildAttachDiagnostic(tabId, targetId, {
|
|
219
|
+
stage: "raw_attach_failed",
|
|
220
|
+
reason: getErrorMessage(fallbackError)
|
|
221
|
+
});
|
|
222
|
+
throw fallbackError;
|
|
223
|
+
}
|
|
224
|
+
if (directTargetRetry.sessionId) {
|
|
225
|
+
this.clearChildAttachDiagnostic(tabId, targetId);
|
|
226
|
+
return directTargetRetry.sessionId;
|
|
227
|
+
}
|
|
228
|
+
if (directTargetRetry.stage !== "attached") {
|
|
229
|
+
rootTargetRetryStage = directTargetRetry.stage;
|
|
230
|
+
}
|
|
231
|
+
if (attachBlocked) {
|
|
232
|
+
initialStage = "raw_attach_blocked";
|
|
233
|
+
directError = error;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
let attachedRootRecovery = await this.ensureAttachedRootSessionWithDiagnostic(tabId);
|
|
238
|
+
let attachedRootRecoveryRetriedAfterRegisterRoot = false;
|
|
239
|
+
let attachedRootRecoveryRegisterRootChanged;
|
|
240
|
+
let attachedRootRecoveryRegisterRootAttachTargetChanged;
|
|
241
|
+
if (!attachedRootRecovery.debuggerSession) {
|
|
242
|
+
const beforeRegisterRoot = captureRootRecordState();
|
|
243
|
+
await this.registerRootTab(tabId);
|
|
244
|
+
const afterRegisterRoot = captureRootRecordState();
|
|
245
|
+
attachedRootRecoveryRetriedAfterRegisterRoot = true;
|
|
246
|
+
attachedRootRecoveryRegisterRootChanged = beforeRegisterRoot.present !== afterRegisterRoot.present
|
|
247
|
+
|| beforeRegisterRoot.rootSessionId !== afterRegisterRoot.rootSessionId
|
|
248
|
+
|| beforeRegisterRoot.targetId !== afterRegisterRoot.targetId
|
|
249
|
+
|| beforeRegisterRoot.attachTargetId !== afterRegisterRoot.attachTargetId;
|
|
250
|
+
attachedRootRecoveryRegisterRootAttachTargetChanged = beforeRegisterRoot.attachTargetId !== afterRegisterRoot.attachTargetId;
|
|
251
|
+
attachedRootRecovery = await this.ensureAttachedRootSessionWithDiagnostic(tabId);
|
|
252
|
+
}
|
|
253
|
+
if (!attachedRootRecovery.debuggerSession) {
|
|
254
|
+
const reattachedChild = await this.reattachRootAndAttachChildTarget(tabId, targetId);
|
|
255
|
+
if (reattachedChild.sessionId) {
|
|
256
|
+
this.clearChildAttachDiagnostic(tabId, targetId);
|
|
257
|
+
return reattachedChild.sessionId;
|
|
258
|
+
}
|
|
259
|
+
const terminalBranch = reattachedChild.terminalBranch
|
|
260
|
+
?? (attachedRootRecoveryRetriedAfterRegisterRoot
|
|
261
|
+
? "post_register_root_recovery"
|
|
262
|
+
: "initial_attached_root_recovery");
|
|
263
|
+
this.recordChildAttachDiagnostic(tabId, targetId, {
|
|
264
|
+
stage: "attached_root_unavailable",
|
|
265
|
+
...(initialStage ? { initialStage } : {}),
|
|
266
|
+
...(rootTargetRetryStage ? { rootTargetRetryStage } : {}),
|
|
267
|
+
...(attachedRootRecovery.stage !== "attached"
|
|
268
|
+
? { attachedRootRecoveryStage: attachedRootRecovery.stage }
|
|
269
|
+
: {}),
|
|
270
|
+
...(attachedRootRecovery.attachTargetSource
|
|
271
|
+
? { attachedRootRecoverySource: attachedRootRecovery.attachTargetSource }
|
|
272
|
+
: {}),
|
|
273
|
+
...(attachedRootRecovery.attachTargetId
|
|
274
|
+
? { attachedRootRecoveryAttachTargetId: attachedRootRecovery.attachTargetId }
|
|
275
|
+
: {}),
|
|
276
|
+
...(attachedRootRecoveryRetriedAfterRegisterRoot
|
|
277
|
+
? { attachedRootRecoveryRetriedAfterRegisterRoot: true }
|
|
278
|
+
: {}),
|
|
279
|
+
...(typeof attachedRootRecoveryRegisterRootChanged === "boolean"
|
|
280
|
+
? { attachedRootRecoveryRegisterRootChanged }
|
|
281
|
+
: {}),
|
|
282
|
+
...(typeof attachedRootRecoveryRegisterRootAttachTargetChanged === "boolean"
|
|
283
|
+
? { attachedRootRecoveryRegisterRootAttachTargetChanged }
|
|
284
|
+
: {}),
|
|
285
|
+
...(typeof attachedRootRecovery.registerAttachedRootSessionCalled === "boolean"
|
|
286
|
+
? { attachedRootRecoveryRegisterAttachedRootSessionCalled: attachedRootRecovery.registerAttachedRootSessionCalled }
|
|
287
|
+
: {}),
|
|
288
|
+
attachedRootUnavailableTerminalBranch: terminalBranch,
|
|
289
|
+
...(reattachedChild.stage ? { reattachRecoveryStage: reattachedChild.stage } : {}),
|
|
290
|
+
...(reattachedChild.reason ? { reattachRecoveryReason: reattachedChild.reason } : {}),
|
|
291
|
+
...(attachedRootRecovery.reason
|
|
292
|
+
? { attachedRootRecoveryReason: attachedRootRecovery.reason }
|
|
293
|
+
: {}),
|
|
294
|
+
...((directError || attachedRootRecovery.reason || reattachedChild.reason)
|
|
295
|
+
? {
|
|
296
|
+
reason: directError
|
|
297
|
+
? getErrorMessage(directError)
|
|
298
|
+
: (attachedRootRecovery.reason ?? reattachedChild.reason)
|
|
299
|
+
}
|
|
300
|
+
: {})
|
|
301
|
+
});
|
|
302
|
+
if (directError) {
|
|
303
|
+
throw directError;
|
|
304
|
+
}
|
|
305
|
+
return null;
|
|
306
|
+
}
|
|
307
|
+
try {
|
|
308
|
+
const attachedRootSessionId = await this.attachChildTargetWithDebuggee(attachedRootRecovery.debuggerSession, targetId);
|
|
309
|
+
if (attachedRootSessionId) {
|
|
310
|
+
this.clearChildAttachDiagnostic(tabId, targetId);
|
|
311
|
+
return attachedRootSessionId;
|
|
312
|
+
}
|
|
313
|
+
await this.restoreRootAfterChildAttachFailure(tabId);
|
|
314
|
+
this.recordChildAttachDiagnostic(tabId, targetId, {
|
|
315
|
+
stage: "attached_root_attach_null",
|
|
316
|
+
...(initialStage ? { initialStage } : {}),
|
|
317
|
+
...(rootTargetRetryStage ? { rootTargetRetryStage } : {}),
|
|
318
|
+
...(attachedRootRecovery.attachTargetSource
|
|
319
|
+
? { attachedRootRecoverySource: attachedRootRecovery.attachTargetSource }
|
|
320
|
+
: {}),
|
|
321
|
+
...(attachedRootRecovery.attachTargetId
|
|
322
|
+
? { attachedRootRecoveryAttachTargetId: attachedRootRecovery.attachTargetId }
|
|
323
|
+
: {}),
|
|
324
|
+
...(typeof attachedRootRecovery.registerAttachedRootSessionCalled === "boolean"
|
|
325
|
+
? { attachedRootRecoveryRegisterAttachedRootSessionCalled: attachedRootRecovery.registerAttachedRootSessionCalled }
|
|
326
|
+
: {})
|
|
327
|
+
});
|
|
328
|
+
return null;
|
|
329
|
+
}
|
|
330
|
+
catch (error) {
|
|
331
|
+
await this.restoreRootAfterChildAttachFailure(tabId);
|
|
332
|
+
this.recordChildAttachDiagnostic(tabId, targetId, {
|
|
333
|
+
stage: "attached_root_attach_failed",
|
|
334
|
+
...(initialStage ? { initialStage } : {}),
|
|
335
|
+
...(rootTargetRetryStage ? { rootTargetRetryStage } : {}),
|
|
336
|
+
...(attachedRootRecovery.attachTargetSource
|
|
337
|
+
? { attachedRootRecoverySource: attachedRootRecovery.attachTargetSource }
|
|
338
|
+
: {}),
|
|
339
|
+
...(attachedRootRecovery.attachTargetId
|
|
340
|
+
? { attachedRootRecoveryAttachTargetId: attachedRootRecovery.attachTargetId }
|
|
341
|
+
: {}),
|
|
342
|
+
...(typeof attachedRootRecovery.registerAttachedRootSessionCalled === "boolean"
|
|
343
|
+
? { attachedRootRecoveryRegisterAttachedRootSessionCalled: attachedRootRecovery.registerAttachedRootSessionCalled }
|
|
344
|
+
: {}),
|
|
345
|
+
reason: getErrorMessage(error)
|
|
346
|
+
});
|
|
347
|
+
throw error;
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
getLastChildAttachDiagnostic(tabId, targetId) {
|
|
351
|
+
return this.childAttachDiagnostics.get(this.childAttachDiagnosticKey(tabId, targetId)) ?? null;
|
|
352
|
+
}
|
|
353
|
+
getLastRootRefreshDiagnostic(tabId) {
|
|
354
|
+
return this.rootRefreshDiagnostics.get(tabId) ?? null;
|
|
355
|
+
}
|
|
356
|
+
getLastRootAttachDiagnostic(tabId) {
|
|
357
|
+
return this.rootAttachDiagnostics.get(tabId) ?? null;
|
|
358
|
+
}
|
|
359
|
+
hasDebuggerSession(sessionId) {
|
|
360
|
+
return this.sessions.hasSession(sessionId);
|
|
361
|
+
}
|
|
362
|
+
registerChildSession(tabId, targetInfo, sessionId) {
|
|
363
|
+
this.sessions.registerChildSession(tabId, targetInfo, sessionId);
|
|
364
|
+
}
|
|
37
365
|
async attachInternal(tabId, allowRetry) {
|
|
38
366
|
if (this.debuggees.has(tabId)) {
|
|
367
|
+
this.clearRootAttachDiagnostic(tabId);
|
|
39
368
|
this.updatePrimaryTab(tabId);
|
|
369
|
+
await this.pruneRootDebuggees(tabId);
|
|
40
370
|
return;
|
|
41
371
|
}
|
|
42
|
-
const debuggee =
|
|
372
|
+
const debuggee = await this.resolveRootDebuggee(tabId);
|
|
373
|
+
let attachedDebuggee = debuggee;
|
|
374
|
+
const displacedRoots = await this.detachConflictingRootDebuggees(tabId);
|
|
43
375
|
this.debuggees.set(tabId, debuggee);
|
|
44
376
|
this.ensureListeners();
|
|
45
377
|
try {
|
|
46
|
-
await this.
|
|
47
|
-
chrome.debugger.attach(debuggee, "1.3", done);
|
|
48
|
-
});
|
|
49
|
-
await this.ensureFlatSessionSupport(debuggee);
|
|
378
|
+
attachedDebuggee = await this.attachRootDebuggeeWithFallback(tabId, debuggee);
|
|
50
379
|
const targetInfo = await this.registerRootTab(tabId);
|
|
51
380
|
if (this.discoverTargets) {
|
|
52
|
-
this.
|
|
381
|
+
await this.applyDiscoverTargets(attachedDebuggee, true);
|
|
382
|
+
this.emitTargetCreated(tabId, targetInfo);
|
|
53
383
|
}
|
|
54
384
|
if (this.autoAttachOptions.autoAttach) {
|
|
55
|
-
await this.applyAutoAttach(
|
|
385
|
+
await this.applyAutoAttach(attachedDebuggee);
|
|
56
386
|
this.emitRootAttached(targetInfo);
|
|
57
387
|
}
|
|
58
388
|
this.updatePrimaryTab(tabId);
|
|
389
|
+
this.commitDetachedRootDebuggees(displacedRoots);
|
|
390
|
+
await this.pruneRootDebuggees(tabId);
|
|
391
|
+
this.clearRootAttachDiagnostic(tabId);
|
|
59
392
|
}
|
|
60
393
|
catch (error) {
|
|
394
|
+
if (isAttachBlockedError(error) && await this.reuseAlreadyAttachedRootDebuggee(tabId)) {
|
|
395
|
+
this.commitDetachedRootDebuggees(displacedRoots);
|
|
396
|
+
await this.pruneRootDebuggees(tabId);
|
|
397
|
+
this.clearRootAttachDiagnostic(tabId);
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
61
400
|
this.debuggees.delete(tabId);
|
|
401
|
+
if (typeof attachedDebuggee.targetId === "string") {
|
|
402
|
+
this.rootTargetTabIds.delete(attachedDebuggee.targetId);
|
|
403
|
+
}
|
|
62
404
|
if (this.debuggees.size === 0) {
|
|
63
405
|
this.removeListeners();
|
|
64
406
|
}
|
|
65
|
-
await this.safeDetach(
|
|
407
|
+
await this.safeDetach(attachedDebuggee);
|
|
66
408
|
if (allowRetry && this.isStaleTabError(error)) {
|
|
67
409
|
const attemptedTabIds = new Set([tabId]);
|
|
68
410
|
let lastStaleError = error;
|
|
@@ -70,7 +412,9 @@ export class CDPRouter {
|
|
|
70
412
|
if (activeTabId && !attemptedTabIds.has(activeTabId)) {
|
|
71
413
|
attemptedTabIds.add(activeTabId);
|
|
72
414
|
try {
|
|
73
|
-
|
|
415
|
+
await this.attachInternal(activeTabId, false);
|
|
416
|
+
this.commitDetachedRootDebuggees(displacedRoots);
|
|
417
|
+
return;
|
|
74
418
|
}
|
|
75
419
|
catch (candidateError) {
|
|
76
420
|
if (!this.isStaleTabError(candidateError)) {
|
|
@@ -83,7 +427,9 @@ export class CDPRouter {
|
|
|
83
427
|
if (fallbackTabId && !attemptedTabIds.has(fallbackTabId)) {
|
|
84
428
|
attemptedTabIds.add(fallbackTabId);
|
|
85
429
|
try {
|
|
86
|
-
|
|
430
|
+
await this.attachInternal(fallbackTabId, false);
|
|
431
|
+
this.commitDetachedRootDebuggees(displacedRoots);
|
|
432
|
+
return;
|
|
87
433
|
}
|
|
88
434
|
catch (candidateError) {
|
|
89
435
|
if (!this.isStaleTabError(candidateError)) {
|
|
@@ -95,7 +441,9 @@ export class CDPRouter {
|
|
|
95
441
|
try {
|
|
96
442
|
const createdTab = await this.tabManager.createTab("about:blank", true);
|
|
97
443
|
if (typeof createdTab.id === "number" && !attemptedTabIds.has(createdTab.id)) {
|
|
98
|
-
|
|
444
|
+
await this.attachInternal(createdTab.id, false);
|
|
445
|
+
this.commitDetachedRootDebuggees(displacedRoots);
|
|
446
|
+
return;
|
|
99
447
|
}
|
|
100
448
|
}
|
|
101
449
|
catch (candidateError) {
|
|
@@ -104,11 +452,122 @@ export class CDPRouter {
|
|
|
104
452
|
}
|
|
105
453
|
lastStaleError = candidateError;
|
|
106
454
|
}
|
|
455
|
+
await this.restoreDetachedRootDebuggees(displacedRoots);
|
|
107
456
|
throw lastStaleError;
|
|
108
457
|
}
|
|
458
|
+
await this.restoreDetachedRootDebuggees(displacedRoots);
|
|
459
|
+
throw error;
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
async reuseAlreadyAttachedRootDebuggee(tabId) {
|
|
463
|
+
const targetInfo = await this.readDebuggerTargetInfo(tabId);
|
|
464
|
+
if (!targetInfo?.attached) {
|
|
465
|
+
return false;
|
|
466
|
+
}
|
|
467
|
+
const reusedDebuggee = {
|
|
468
|
+
tabId,
|
|
469
|
+
targetId: targetInfo.id,
|
|
470
|
+
attachBy: "targetId"
|
|
471
|
+
};
|
|
472
|
+
this.debuggees.set(tabId, reusedDebuggee);
|
|
473
|
+
this.ensureListeners();
|
|
474
|
+
try {
|
|
475
|
+
await this.ensureFlatSessionSupport(reusedDebuggee);
|
|
476
|
+
const registeredTarget = await this.registerRootTab(tabId);
|
|
477
|
+
if (this.discoverTargets) {
|
|
478
|
+
await this.applyDiscoverTargets(reusedDebuggee, true);
|
|
479
|
+
this.emitTargetCreated(tabId, registeredTarget);
|
|
480
|
+
}
|
|
481
|
+
if (this.autoAttachOptions.autoAttach) {
|
|
482
|
+
await this.applyAutoAttach(reusedDebuggee);
|
|
483
|
+
this.emitRootAttached(registeredTarget);
|
|
484
|
+
}
|
|
485
|
+
this.updatePrimaryTab(tabId);
|
|
486
|
+
return true;
|
|
487
|
+
}
|
|
488
|
+
catch {
|
|
489
|
+
this.debuggees.delete(tabId);
|
|
490
|
+
this.rootTargetTabIds.delete(targetInfo.id);
|
|
491
|
+
if (this.debuggees.size === 0) {
|
|
492
|
+
this.removeListeners();
|
|
493
|
+
}
|
|
494
|
+
return false;
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
async attachRootDebuggeeWithFallback(tabId, debuggee) {
|
|
498
|
+
await this.attachRootDebuggee(debuggee);
|
|
499
|
+
try {
|
|
500
|
+
await this.ensureFlatSessionSupport(debuggee);
|
|
501
|
+
return debuggee;
|
|
502
|
+
}
|
|
503
|
+
catch (error) {
|
|
504
|
+
this.recordRootAttachDiagnostic(tabId, {
|
|
505
|
+
origin: "flat_session_bootstrap",
|
|
506
|
+
stage: "flat_session_probe_failed",
|
|
507
|
+
attachBy: this.resolveRootAttachBy(debuggee),
|
|
508
|
+
probeMethod: "Target.setAutoAttach",
|
|
509
|
+
reason: getErrorMessage(error)
|
|
510
|
+
});
|
|
511
|
+
const targetAttachDebuggee = this.createTargetAttachRootDebuggee(tabId, debuggee, error);
|
|
512
|
+
if (!targetAttachDebuggee) {
|
|
513
|
+
throw error;
|
|
514
|
+
}
|
|
515
|
+
this.markExpectedRootDetach(tabId);
|
|
516
|
+
await this.safeDetach(debuggee);
|
|
517
|
+
this.debuggees.set(tabId, targetAttachDebuggee);
|
|
518
|
+
await this.attachRootDebuggee(targetAttachDebuggee);
|
|
519
|
+
try {
|
|
520
|
+
await this.ensureFlatSessionSupport(targetAttachDebuggee);
|
|
521
|
+
}
|
|
522
|
+
catch (fallbackError) {
|
|
523
|
+
this.recordRootAttachDiagnostic(tabId, {
|
|
524
|
+
origin: "flat_session_bootstrap",
|
|
525
|
+
stage: "fallback_flat_session_probe_failed",
|
|
526
|
+
attachBy: this.resolveRootAttachBy(targetAttachDebuggee),
|
|
527
|
+
probeMethod: "Target.setAutoAttach",
|
|
528
|
+
reason: getErrorMessage(fallbackError)
|
|
529
|
+
});
|
|
530
|
+
throw fallbackError;
|
|
531
|
+
}
|
|
532
|
+
return targetAttachDebuggee;
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
async attachRootDebuggee(debuggee) {
|
|
536
|
+
try {
|
|
537
|
+
await this.runDebuggerAction((done) => {
|
|
538
|
+
chrome.debugger.attach(this.toChromeDebuggee(debuggee), "1.3", done);
|
|
539
|
+
});
|
|
540
|
+
}
|
|
541
|
+
catch (error) {
|
|
542
|
+
if (typeof debuggee.tabId === "number") {
|
|
543
|
+
this.recordRootAttachDiagnostic(debuggee.tabId, {
|
|
544
|
+
origin: "root_attach",
|
|
545
|
+
stage: debuggee.attachBy === "targetId"
|
|
546
|
+
? "fallback_root_debugger_attach_failed"
|
|
547
|
+
: "root_debugger_attach_failed",
|
|
548
|
+
attachBy: this.resolveRootAttachBy(debuggee),
|
|
549
|
+
reason: getErrorMessage(error)
|
|
550
|
+
});
|
|
551
|
+
}
|
|
109
552
|
throw error;
|
|
110
553
|
}
|
|
111
554
|
}
|
|
555
|
+
createTargetAttachRootDebuggee(tabId, debuggee, error) {
|
|
556
|
+
if (!isAttachBlockedError(error)) {
|
|
557
|
+
return null;
|
|
558
|
+
}
|
|
559
|
+
const targetId = typeof debuggee.targetId === "string" && debuggee.targetId.length > 0
|
|
560
|
+
? debuggee.targetId
|
|
561
|
+
: null;
|
|
562
|
+
if (!targetId || debuggee.attachBy === "targetId") {
|
|
563
|
+
return null;
|
|
564
|
+
}
|
|
565
|
+
return {
|
|
566
|
+
tabId,
|
|
567
|
+
targetId,
|
|
568
|
+
attachBy: "targetId"
|
|
569
|
+
};
|
|
570
|
+
}
|
|
112
571
|
async detachAll() {
|
|
113
572
|
const entries = Array.from(this.debuggees.entries());
|
|
114
573
|
this.debuggees.clear();
|
|
@@ -145,7 +604,22 @@ export class CDPRouter {
|
|
|
145
604
|
getAttachedTabIds() {
|
|
146
605
|
return Array.from(this.debuggees.keys());
|
|
147
606
|
}
|
|
607
|
+
isTabAttached(tabId) {
|
|
608
|
+
return this.debuggees.has(tabId);
|
|
609
|
+
}
|
|
610
|
+
getTabDebuggee(tabId) {
|
|
611
|
+
return this.sessions.getAttachedRootSession(tabId)?.debuggerSession
|
|
612
|
+
?? this.debuggees.get(tabId)
|
|
613
|
+
?? (() => {
|
|
614
|
+
const rootRecord = this.sessions.getByTabId(tabId);
|
|
615
|
+
if (!rootRecord) {
|
|
616
|
+
return null;
|
|
617
|
+
}
|
|
618
|
+
return this.sessions.getBySessionId(rootRecord.rootSessionId)?.debuggerSession ?? null;
|
|
619
|
+
})();
|
|
620
|
+
}
|
|
148
621
|
async handleCommand(command) {
|
|
622
|
+
await this.prepareForNextClientIfNeeded();
|
|
149
623
|
if (!this.callbacks)
|
|
150
624
|
return;
|
|
151
625
|
if (this.debuggees.size === 0) {
|
|
@@ -179,7 +653,8 @@ export class CDPRouter {
|
|
|
179
653
|
this.respondError(command.id, "No tab attached");
|
|
180
654
|
return;
|
|
181
655
|
}
|
|
182
|
-
this.
|
|
656
|
+
const browserSessionId = await this.ensureBrowserSession(rootSession.tabId);
|
|
657
|
+
this.respond(command.id, { sessionId: browserSessionId ?? rootSession.sessionId });
|
|
183
658
|
return;
|
|
184
659
|
}
|
|
185
660
|
case "Target.sendMessageToTarget":
|
|
@@ -193,9 +668,7 @@ export class CDPRouter {
|
|
|
193
668
|
return;
|
|
194
669
|
case "Target.getTargetInfo": {
|
|
195
670
|
const targetId = typeof commandParams.targetId === "string" ? commandParams.targetId : "";
|
|
196
|
-
const
|
|
197
|
-
const targetInfo = record?.targetInfo
|
|
198
|
-
?? (record?.kind === "root" ? this.sessions.getByTabId(record.tabId)?.targetInfo ?? null : null);
|
|
671
|
+
const targetInfo = this.resolveTargetInfo(targetId, sessionId);
|
|
199
672
|
this.respond(command.id, { targetInfo });
|
|
200
673
|
return;
|
|
201
674
|
}
|
|
@@ -218,6 +691,9 @@ export class CDPRouter {
|
|
|
218
691
|
await handleRoutedCommand(ctx, command.id, method, commandParams, sessionId);
|
|
219
692
|
}
|
|
220
693
|
}
|
|
694
|
+
markClientClosed() {
|
|
695
|
+
this.clientResetPending = true;
|
|
696
|
+
}
|
|
221
697
|
buildCommandContext() {
|
|
222
698
|
return {
|
|
223
699
|
debuggees: this.debuggees,
|
|
@@ -232,9 +708,25 @@ export class CDPRouter {
|
|
|
232
708
|
setDiscoverTargets: (value) => {
|
|
233
709
|
this.discoverTargets = value;
|
|
234
710
|
},
|
|
711
|
+
applyDiscoverTargets: this.applyDiscoverTargets.bind(this),
|
|
235
712
|
respond: this.respond.bind(this),
|
|
236
713
|
respondError: this.respondError.bind(this),
|
|
237
|
-
|
|
714
|
+
emitEvent: (method, params, sessionId) => {
|
|
715
|
+
const tabId = sessionId
|
|
716
|
+
? this.sessions.getBySessionId(sessionId)?.tabId ?? this.primaryTabId
|
|
717
|
+
: this.primaryTabId;
|
|
718
|
+
if (typeof tabId === "number") {
|
|
719
|
+
this.emitEvent(tabId, method, params, sessionId);
|
|
720
|
+
}
|
|
721
|
+
},
|
|
722
|
+
emitTargetCreated: (targetInfo) => {
|
|
723
|
+
const tabId = this.sessions.getByTargetId(targetInfo.targetId)?.tabId
|
|
724
|
+
?? this.rootTargetTabIds.get(targetInfo.targetId)
|
|
725
|
+
?? this.primaryTabId;
|
|
726
|
+
if (typeof tabId === "number") {
|
|
727
|
+
this.emitTargetCreated(tabId, targetInfo);
|
|
728
|
+
}
|
|
729
|
+
},
|
|
238
730
|
emitRootAttached: this.emitRootAttached.bind(this),
|
|
239
731
|
emitRootDetached: this.emitRootDetached.bind(this),
|
|
240
732
|
resetRootAttached: this.resetRootAttached.bind(this),
|
|
@@ -243,18 +735,137 @@ export class CDPRouter {
|
|
|
243
735
|
safeDetach: this.safeDetach.bind(this),
|
|
244
736
|
attach: this.attach.bind(this),
|
|
245
737
|
registerRootTab: this.registerRootTab.bind(this),
|
|
738
|
+
refreshRootTargetInfo: this.refreshRootTargetInfo.bind(this),
|
|
246
739
|
applyAutoAttach: this.applyAutoAttach.bind(this),
|
|
247
740
|
sendCommand: this.sendCommand.bind(this),
|
|
248
|
-
getPrimaryDebuggee: this.getPrimaryDebuggee.bind(this)
|
|
741
|
+
getPrimaryDebuggee: this.getPrimaryDebuggee.bind(this),
|
|
742
|
+
resolveCommandDebuggee: this.resolveCommandDebuggee.bind(this)
|
|
249
743
|
};
|
|
250
744
|
}
|
|
251
745
|
async registerRootTab(tabId) {
|
|
252
746
|
const existing = this.sessions.getByTabId(tabId);
|
|
253
747
|
const sessionId = existing?.rootSessionId ?? this.createRootSessionId();
|
|
254
748
|
const targetInfo = await this.buildTargetInfo(tabId);
|
|
255
|
-
this.
|
|
749
|
+
const debuggerSession = await this.resolveRootSessionDebuggee(tabId);
|
|
750
|
+
this.sessions.registerRootTab(tabId, targetInfo, sessionId, debuggerSession.targetId, debuggerSession);
|
|
256
751
|
return targetInfo;
|
|
257
752
|
}
|
|
753
|
+
async refreshRootTargetInfo(tabId) {
|
|
754
|
+
const existing = this.sessions.getByTabId(tabId);
|
|
755
|
+
const sessionId = existing?.rootSessionId ?? this.createRootSessionId();
|
|
756
|
+
const targetInfo = await this.buildTargetInfo(tabId);
|
|
757
|
+
const debuggerSession = await this.resolveRootSessionDebuggee(tabId);
|
|
758
|
+
const rootFrame = await this.readRootFrameInfo(tabId);
|
|
759
|
+
const refreshed = rootFrame
|
|
760
|
+
? {
|
|
761
|
+
...targetInfo,
|
|
762
|
+
targetId: rootFrame.id,
|
|
763
|
+
...(rootFrame.url ? { url: rootFrame.url } : {})
|
|
764
|
+
}
|
|
765
|
+
: targetInfo;
|
|
766
|
+
this.sessions.registerRootTab(tabId, refreshed, sessionId, debuggerSession.targetId, debuggerSession);
|
|
767
|
+
return refreshed;
|
|
768
|
+
}
|
|
769
|
+
async prepareForNextClientIfNeeded(preferredTabIdHint) {
|
|
770
|
+
if (!this.clientResetPending) {
|
|
771
|
+
return null;
|
|
772
|
+
}
|
|
773
|
+
const preferredTabId = await this.resolvePreferredResetTabId(preferredTabIdHint);
|
|
774
|
+
const retainedPreferredRootTargetId = preferredTabId !== null
|
|
775
|
+
? this.resolveRetainedRootTargetId(preferredTabId)
|
|
776
|
+
: null;
|
|
777
|
+
this.clientResetPending = false;
|
|
778
|
+
this.autoAttachOptions = { autoAttach: false, waitForDebuggerOnStart: false, flatten: true };
|
|
779
|
+
this.discoverTargets = false;
|
|
780
|
+
this.rootAttachedSessions.clear();
|
|
781
|
+
this.pendingTargetTabIds.clear();
|
|
782
|
+
this.quarantinedSessions.clear();
|
|
783
|
+
this.churnTracker.clear();
|
|
784
|
+
this.sessions.reset();
|
|
785
|
+
for (const [tabId, debuggee] of Array.from(this.debuggees.entries())) {
|
|
786
|
+
if (preferredTabId !== null && tabId === preferredTabId) {
|
|
787
|
+
continue;
|
|
788
|
+
}
|
|
789
|
+
this.debuggees.delete(tabId);
|
|
790
|
+
await this.safeDetach(debuggee);
|
|
791
|
+
}
|
|
792
|
+
if (preferredTabId === null) {
|
|
793
|
+
this.primaryTabId = null;
|
|
794
|
+
this.lastActiveTabId = null;
|
|
795
|
+
if (this.debuggees.size === 0) {
|
|
796
|
+
this.removeListeners();
|
|
797
|
+
}
|
|
798
|
+
return null;
|
|
799
|
+
}
|
|
800
|
+
const attachedPrimary = this.debuggees.get(preferredTabId);
|
|
801
|
+
if (attachedPrimary) {
|
|
802
|
+
this.updatePrimaryTab(preferredTabId);
|
|
803
|
+
// After a client reset, a preserved root tab is only a candidate anchor.
|
|
804
|
+
// Rebuild the real root attachment before any same-tab reuse is considered healthy.
|
|
805
|
+
await this.reattachRootDebuggee(preferredTabId, true);
|
|
806
|
+
const refreshedRoot = this.sessions.getByTabId(preferredTabId);
|
|
807
|
+
if (retainedPreferredRootTargetId && !refreshedRoot?.attachTargetId) {
|
|
808
|
+
this.sessions.setRootAttachTargetId(preferredTabId, retainedPreferredRootTargetId);
|
|
809
|
+
const refreshedDebuggee = this.debuggees.get(preferredTabId);
|
|
810
|
+
if (refreshedDebuggee && !refreshedDebuggee.targetId) {
|
|
811
|
+
refreshedDebuggee.targetId = retainedPreferredRootTargetId;
|
|
812
|
+
}
|
|
813
|
+
const refreshedRootSession = refreshedRoot
|
|
814
|
+
? this.sessions.getBySessionId(refreshedRoot.rootSessionId)
|
|
815
|
+
: null;
|
|
816
|
+
if (refreshedRootSession?.debuggerSession && !refreshedRootSession.debuggerSession.targetId) {
|
|
817
|
+
refreshedRootSession.debuggerSession.targetId = retainedPreferredRootTargetId;
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
return preferredTabId;
|
|
821
|
+
}
|
|
822
|
+
await this.attachInternal(preferredTabId, true);
|
|
823
|
+
return preferredTabId;
|
|
824
|
+
}
|
|
825
|
+
async resolvePreferredResetTabId(preferredTabIdHint) {
|
|
826
|
+
const candidateTabIds = [];
|
|
827
|
+
const pushCandidate = (tabId) => {
|
|
828
|
+
if (typeof tabId === "number" && !candidateTabIds.includes(tabId)) {
|
|
829
|
+
candidateTabIds.push(tabId);
|
|
830
|
+
}
|
|
831
|
+
};
|
|
832
|
+
pushCandidate(preferredTabIdHint ?? null);
|
|
833
|
+
pushCandidate(await this.tabManager.getActiveTabId());
|
|
834
|
+
pushCandidate(this.lastActiveTabId);
|
|
835
|
+
pushCandidate(this.primaryTabId);
|
|
836
|
+
for (const tabId of candidateTabIds) {
|
|
837
|
+
if (await this.isUsableResetTab(tabId)) {
|
|
838
|
+
return tabId;
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
const firstHttpTabId = await this.tabManager.getFirstHttpTabId();
|
|
842
|
+
if (firstHttpTabId !== null) {
|
|
843
|
+
return firstHttpTabId;
|
|
844
|
+
}
|
|
845
|
+
for (const tabId of candidateTabIds) {
|
|
846
|
+
if (this.debuggees.has(tabId)) {
|
|
847
|
+
return tabId;
|
|
848
|
+
}
|
|
849
|
+
const tab = await this.tabManager.getTab(tabId);
|
|
850
|
+
if (tab) {
|
|
851
|
+
return tabId;
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
const [firstAttachedTabId] = this.debuggees.keys();
|
|
855
|
+
return typeof firstAttachedTabId === "number" ? firstAttachedTabId : null;
|
|
856
|
+
}
|
|
857
|
+
async isUsableResetTab(tabId) {
|
|
858
|
+
const tab = await this.tabManager.getTab(tabId);
|
|
859
|
+
if (!tab?.url) {
|
|
860
|
+
return false;
|
|
861
|
+
}
|
|
862
|
+
try {
|
|
863
|
+
return getRestrictionMessage(new URL(tab.url)) === null;
|
|
864
|
+
}
|
|
865
|
+
catch {
|
|
866
|
+
return false;
|
|
867
|
+
}
|
|
868
|
+
}
|
|
258
869
|
updatePrimaryTab(tabId) {
|
|
259
870
|
if (tabId === this.primaryTabId)
|
|
260
871
|
return;
|
|
@@ -264,6 +875,50 @@ export class CDPRouter {
|
|
|
264
875
|
}
|
|
265
876
|
this.callbacks?.onPrimaryTabChange?.(tabId);
|
|
266
877
|
}
|
|
878
|
+
async pruneRootDebuggees(primaryTabId) {
|
|
879
|
+
const displacedRoots = await this.detachConflictingRootDebuggees(primaryTabId);
|
|
880
|
+
this.commitDetachedRootDebuggees(displacedRoots);
|
|
881
|
+
}
|
|
882
|
+
async detachConflictingRootDebuggees(nextTabId) {
|
|
883
|
+
const staleTabIds = Array.from(this.debuggees.keys()).filter((tabId) => tabId !== nextTabId);
|
|
884
|
+
const displacedRoots = [];
|
|
885
|
+
for (const staleTabId of staleTabIds) {
|
|
886
|
+
const debuggee = this.debuggees.get(staleTabId);
|
|
887
|
+
if (!debuggee) {
|
|
888
|
+
continue;
|
|
889
|
+
}
|
|
890
|
+
this.debuggees.delete(staleTabId);
|
|
891
|
+
this.markExpectedRootDetach(staleTabId);
|
|
892
|
+
await this.safeDetach(debuggee);
|
|
893
|
+
displacedRoots.push({ tabId: staleTabId });
|
|
894
|
+
}
|
|
895
|
+
return displacedRoots;
|
|
896
|
+
}
|
|
897
|
+
commitDetachedRootDebuggees(detachedRoots) {
|
|
898
|
+
for (const { tabId } of detachedRoots) {
|
|
899
|
+
if (this.debuggees.has(tabId)) {
|
|
900
|
+
continue;
|
|
901
|
+
}
|
|
902
|
+
this.detachTabState(tabId);
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
async restoreDetachedRootDebuggees(detachedRoots) {
|
|
906
|
+
for (const { tabId } of detachedRoots) {
|
|
907
|
+
if (this.debuggees.has(tabId)) {
|
|
908
|
+
return;
|
|
909
|
+
}
|
|
910
|
+
try {
|
|
911
|
+
await this.attachInternal(tabId, false);
|
|
912
|
+
return;
|
|
913
|
+
}
|
|
914
|
+
catch (error) {
|
|
915
|
+
logError("cdp.restore_root_attach", error, {
|
|
916
|
+
code: "restore_root_attach_failed",
|
|
917
|
+
extra: { tabId }
|
|
918
|
+
});
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
}
|
|
267
922
|
selectFallbackPrimary() {
|
|
268
923
|
if (this.lastActiveTabId && this.debuggees.has(this.lastActiveTabId)) {
|
|
269
924
|
return this.lastActiveTabId;
|
|
@@ -272,27 +927,467 @@ export class CDPRouter {
|
|
|
272
927
|
return first ?? null;
|
|
273
928
|
}
|
|
274
929
|
getPrimaryDebuggee() {
|
|
275
|
-
if (this.primaryTabId !== null
|
|
276
|
-
|
|
930
|
+
if (this.primaryTabId !== null) {
|
|
931
|
+
const primary = this.debuggees.get(this.primaryTabId);
|
|
932
|
+
if (primary) {
|
|
933
|
+
return primary;
|
|
934
|
+
}
|
|
277
935
|
}
|
|
278
|
-
const [first] = this.debuggees.
|
|
279
|
-
return
|
|
936
|
+
const [first] = this.debuggees.values();
|
|
937
|
+
return first ?? null;
|
|
938
|
+
}
|
|
939
|
+
async resolveCommandDebuggee(sessionId) {
|
|
940
|
+
if (!sessionId) {
|
|
941
|
+
return this.getPrimaryDebuggee();
|
|
942
|
+
}
|
|
943
|
+
const session = this.sessions.getBySessionId(sessionId);
|
|
944
|
+
if (!session) {
|
|
945
|
+
return null;
|
|
946
|
+
}
|
|
947
|
+
if (session.kind !== "root") {
|
|
948
|
+
return session.debuggerSession;
|
|
949
|
+
}
|
|
950
|
+
if (typeof session.debuggerSession.targetId === "string" && session.debuggerSession.targetId.length > 0) {
|
|
951
|
+
return session.debuggerSession;
|
|
952
|
+
}
|
|
953
|
+
const attached = await this.ensureAttachedRootSession(session.tabId);
|
|
954
|
+
return attached ?? session.debuggerSession;
|
|
280
955
|
}
|
|
281
956
|
async ensureRootSessionForPrimary() {
|
|
282
|
-
const
|
|
283
|
-
if (
|
|
957
|
+
const tabId = this.primaryTabId ?? this.resolveSourceTabId(this.getPrimaryDebuggee() ?? {});
|
|
958
|
+
if (typeof tabId !== "number") {
|
|
284
959
|
return null;
|
|
285
960
|
}
|
|
286
|
-
const existing = this.sessions.getByTabId(
|
|
961
|
+
const existing = this.sessions.getByTabId(tabId);
|
|
287
962
|
if (existing) {
|
|
288
|
-
return { sessionId: existing.rootSessionId, targetInfo: existing.targetInfo };
|
|
963
|
+
return { tabId, sessionId: existing.rootSessionId, targetInfo: existing.targetInfo };
|
|
289
964
|
}
|
|
290
|
-
const targetInfo = await this.registerRootTab(
|
|
291
|
-
const refreshed = this.sessions.getByTabId(
|
|
965
|
+
const targetInfo = await this.registerRootTab(tabId);
|
|
966
|
+
const refreshed = this.sessions.getByTabId(tabId);
|
|
292
967
|
if (!refreshed) {
|
|
293
968
|
return null;
|
|
294
969
|
}
|
|
295
|
-
return { sessionId: refreshed.rootSessionId, targetInfo: targetInfo ?? refreshed.targetInfo };
|
|
970
|
+
return { tabId, sessionId: refreshed.rootSessionId, targetInfo: targetInfo ?? refreshed.targetInfo };
|
|
971
|
+
}
|
|
972
|
+
async ensureAttachedRootSession(tabId) {
|
|
973
|
+
return (await this.ensureAttachedRootSessionWithDiagnostic(tabId)).debuggerSession;
|
|
974
|
+
}
|
|
975
|
+
async ensureAttachedRootSessionWithDiagnostic(tabId) {
|
|
976
|
+
const existing = this.sessions.getAttachedRootSession(tabId);
|
|
977
|
+
if (existing) {
|
|
978
|
+
return {
|
|
979
|
+
debuggerSession: existing.debuggerSession,
|
|
980
|
+
stage: "attached",
|
|
981
|
+
registerAttachedRootSessionCalled: false
|
|
982
|
+
};
|
|
983
|
+
}
|
|
984
|
+
const record = this.sessions.getByTabId(tabId);
|
|
985
|
+
if (!record) {
|
|
986
|
+
return {
|
|
987
|
+
debuggerSession: null,
|
|
988
|
+
stage: "record_missing",
|
|
989
|
+
registerAttachedRootSessionCalled: false
|
|
990
|
+
};
|
|
991
|
+
}
|
|
992
|
+
const recordAttachTargetId = typeof record.attachTargetId === "string" && record.attachTargetId.length > 0
|
|
993
|
+
? record.attachTargetId
|
|
994
|
+
: null;
|
|
995
|
+
const retainedAttachTargetId = recordAttachTargetId ?? this.resolveRetainedRootTargetId(tabId);
|
|
996
|
+
const liveAttachTargetId = await this.readDebuggerTargetId(tabId);
|
|
997
|
+
const attachTargetId = recordAttachTargetId ?? liveAttachTargetId ?? retainedAttachTargetId;
|
|
998
|
+
const attachTargetSource = recordAttachTargetId
|
|
999
|
+
? "record"
|
|
1000
|
+
: liveAttachTargetId
|
|
1001
|
+
? "debugger"
|
|
1002
|
+
: retainedAttachTargetId
|
|
1003
|
+
? "debuggee"
|
|
1004
|
+
: undefined;
|
|
1005
|
+
if (!attachTargetId) {
|
|
1006
|
+
return {
|
|
1007
|
+
debuggerSession: null,
|
|
1008
|
+
stage: "session_missing",
|
|
1009
|
+
registerAttachedRootSessionCalled: false,
|
|
1010
|
+
reason: "attach_target_id_unavailable"
|
|
1011
|
+
};
|
|
1012
|
+
}
|
|
1013
|
+
if (recordAttachTargetId !== attachTargetId) {
|
|
1014
|
+
this.sessions.setRootAttachTargetId(tabId, attachTargetId);
|
|
1015
|
+
}
|
|
1016
|
+
const attachRootSession = async (debuggee) => {
|
|
1017
|
+
try {
|
|
1018
|
+
const attached = await this.sendCommandOnce(debuggee, "Target.attachToTarget", {
|
|
1019
|
+
targetId: attachTargetId,
|
|
1020
|
+
flatten: true
|
|
1021
|
+
});
|
|
1022
|
+
const sessionRecord = isRecord(attached) ? attached : {};
|
|
1023
|
+
return {
|
|
1024
|
+
sessionId: typeof sessionRecord.sessionId === "string" ? sessionRecord.sessionId : null
|
|
1025
|
+
};
|
|
1026
|
+
}
|
|
1027
|
+
catch (error) {
|
|
1028
|
+
return {
|
|
1029
|
+
sessionId: null,
|
|
1030
|
+
error
|
|
1031
|
+
};
|
|
1032
|
+
}
|
|
1033
|
+
};
|
|
1034
|
+
const initialAttachDebuggee = liveAttachTargetId
|
|
1035
|
+
? { tabId }
|
|
1036
|
+
: { targetId: attachTargetId, attachBy: "targetId" };
|
|
1037
|
+
let attachAttempt = await attachRootSession(initialAttachDebuggee);
|
|
1038
|
+
if (typeof initialAttachDebuggee.tabId === "number"
|
|
1039
|
+
&& !attachAttempt.sessionId
|
|
1040
|
+
&& (!attachAttempt.error
|
|
1041
|
+
|| isAttachBlockedError(attachAttempt.error)
|
|
1042
|
+
|| this.isStaleTabError(attachAttempt.error))) {
|
|
1043
|
+
const initialFailure = attachAttempt;
|
|
1044
|
+
const retriedAttachAttempt = await attachRootSession({ targetId: attachTargetId, attachBy: "targetId" });
|
|
1045
|
+
attachAttempt = retriedAttachAttempt.sessionId
|
|
1046
|
+
|| retriedAttachAttempt.error
|
|
1047
|
+
|| !initialFailure.error
|
|
1048
|
+
? retriedAttachAttempt
|
|
1049
|
+
: initialFailure;
|
|
1050
|
+
}
|
|
1051
|
+
try {
|
|
1052
|
+
const attachedSessionId = attachAttempt.sessionId;
|
|
1053
|
+
if (!attachedSessionId) {
|
|
1054
|
+
if (attachAttempt.error) {
|
|
1055
|
+
throw attachAttempt.error;
|
|
1056
|
+
}
|
|
1057
|
+
return {
|
|
1058
|
+
debuggerSession: null,
|
|
1059
|
+
stage: "attach_null",
|
|
1060
|
+
...(attachTargetSource ? { attachTargetSource } : {}),
|
|
1061
|
+
attachTargetId,
|
|
1062
|
+
registerAttachedRootSessionCalled: false
|
|
1063
|
+
};
|
|
1064
|
+
}
|
|
1065
|
+
const attachedRecord = this.sessions.registerAttachedRootSession(tabId, attachedSessionId);
|
|
1066
|
+
if (attachedRecord?.debuggerSession) {
|
|
1067
|
+
attachedRecord.debuggerSession.targetId = attachTargetId;
|
|
1068
|
+
}
|
|
1069
|
+
return {
|
|
1070
|
+
debuggerSession: attachedRecord?.debuggerSession ?? {
|
|
1071
|
+
tabId,
|
|
1072
|
+
sessionId: attachedSessionId,
|
|
1073
|
+
targetId: attachTargetId
|
|
1074
|
+
},
|
|
1075
|
+
stage: "attached",
|
|
1076
|
+
...(attachTargetSource ? { attachTargetSource } : {}),
|
|
1077
|
+
attachTargetId,
|
|
1078
|
+
registerAttachedRootSessionCalled: true
|
|
1079
|
+
};
|
|
1080
|
+
}
|
|
1081
|
+
catch (error) {
|
|
1082
|
+
return {
|
|
1083
|
+
debuggerSession: null,
|
|
1084
|
+
stage: "attach_failed",
|
|
1085
|
+
...(attachTargetSource ? { attachTargetSource } : {}),
|
|
1086
|
+
attachTargetId,
|
|
1087
|
+
registerAttachedRootSessionCalled: false,
|
|
1088
|
+
reason: getErrorMessage(error)
|
|
1089
|
+
};
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
async resolveRootSessionDebuggee(tabId) {
|
|
1093
|
+
await this.syncLiveRootTargetId(tabId);
|
|
1094
|
+
const attachedDebuggee = this.debuggees.get(tabId);
|
|
1095
|
+
if (attachedDebuggee?.targetId) {
|
|
1096
|
+
return attachedDebuggee;
|
|
1097
|
+
}
|
|
1098
|
+
const attachedRootSession = this.sessions.getAttachedRootSession(tabId);
|
|
1099
|
+
if (attachedRootSession?.debuggerSession) {
|
|
1100
|
+
return attachedRootSession.debuggerSession;
|
|
1101
|
+
}
|
|
1102
|
+
const existing = this.sessions.getByTabId(tabId);
|
|
1103
|
+
const existingSession = existing ? this.sessions.getBySessionId(existing.rootSessionId) : null;
|
|
1104
|
+
if (existingSession?.debuggerSession?.targetId) {
|
|
1105
|
+
return existingSession.debuggerSession;
|
|
1106
|
+
}
|
|
1107
|
+
return await this.resolveRootDebuggee(tabId);
|
|
1108
|
+
}
|
|
1109
|
+
async syncLiveRootTargetId(tabId) {
|
|
1110
|
+
const liveTargetId = await this.readDebuggerTargetId(tabId);
|
|
1111
|
+
if (!liveTargetId) {
|
|
1112
|
+
return;
|
|
1113
|
+
}
|
|
1114
|
+
const staleTargetIds = new Set();
|
|
1115
|
+
const attachedDebuggee = this.debuggees.get(tabId);
|
|
1116
|
+
if (typeof attachedDebuggee?.targetId === "string" && attachedDebuggee.targetId.length > 0) {
|
|
1117
|
+
staleTargetIds.add(attachedDebuggee.targetId);
|
|
1118
|
+
}
|
|
1119
|
+
const rootRecord = this.sessions.getByTabId(tabId);
|
|
1120
|
+
if (typeof rootRecord?.targetInfo.targetId === "string" && rootRecord.targetInfo.targetId.length > 0) {
|
|
1121
|
+
staleTargetIds.add(rootRecord.targetInfo.targetId);
|
|
1122
|
+
}
|
|
1123
|
+
if (typeof rootRecord?.attachTargetId === "string" && rootRecord.attachTargetId.length > 0) {
|
|
1124
|
+
staleTargetIds.add(rootRecord.attachTargetId);
|
|
1125
|
+
}
|
|
1126
|
+
for (const targetId of staleTargetIds) {
|
|
1127
|
+
if (targetId !== liveTargetId && this.rootTargetTabIds.get(targetId) === tabId) {
|
|
1128
|
+
this.rootTargetTabIds.delete(targetId);
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1131
|
+
this.rootTargetTabIds.set(liveTargetId, tabId);
|
|
1132
|
+
this.sessions.setRootAttachTargetId(tabId, liveTargetId);
|
|
1133
|
+
if (attachedDebuggee) {
|
|
1134
|
+
attachedDebuggee.targetId = liveTargetId;
|
|
1135
|
+
}
|
|
1136
|
+
const rootSession = rootRecord
|
|
1137
|
+
? this.sessions.getBySessionId(rootRecord.rootSessionId)
|
|
1138
|
+
: null;
|
|
1139
|
+
if (rootSession?.debuggerSession) {
|
|
1140
|
+
rootSession.debuggerSession.targetId = liveTargetId;
|
|
1141
|
+
}
|
|
1142
|
+
const attachedRootSession = this.sessions.getAttachedRootSession(tabId);
|
|
1143
|
+
if (attachedRootSession?.debuggerSession) {
|
|
1144
|
+
attachedRootSession.debuggerSession.targetId = liveTargetId;
|
|
1145
|
+
}
|
|
1146
|
+
}
|
|
1147
|
+
async resolveRootDebuggee(tabId) {
|
|
1148
|
+
const attachTargetId = await this.readDebuggerTargetId(tabId);
|
|
1149
|
+
if (attachTargetId) {
|
|
1150
|
+
this.rootTargetTabIds.set(attachTargetId, tabId);
|
|
1151
|
+
return { tabId, targetId: attachTargetId };
|
|
1152
|
+
}
|
|
1153
|
+
return { tabId };
|
|
1154
|
+
}
|
|
1155
|
+
async attachChildTargetWithDebuggee(debuggee, targetId) {
|
|
1156
|
+
const result = await this.sendCommandOnce(debuggee, "Target.attachToTarget", { targetId, flatten: true });
|
|
1157
|
+
const record = isRecord(result) ? result : {};
|
|
1158
|
+
const childSessionId = typeof record.sessionId === "string" ? record.sessionId : null;
|
|
1159
|
+
if (!childSessionId || typeof debuggee.tabId !== "number") {
|
|
1160
|
+
return childSessionId;
|
|
1161
|
+
}
|
|
1162
|
+
const targetInfo = this.resolveTargetInfo(targetId) ?? {
|
|
1163
|
+
targetId,
|
|
1164
|
+
type: "page",
|
|
1165
|
+
browserContextId: DEFAULT_BROWSER_CONTEXT_ID
|
|
1166
|
+
};
|
|
1167
|
+
this.sessions.registerChildSession(debuggee.tabId, targetInfo, childSessionId);
|
|
1168
|
+
return childSessionId;
|
|
1169
|
+
}
|
|
1170
|
+
async attachChildTargetWithRootTargetId(debuggee, targetId, priorError) {
|
|
1171
|
+
if (typeof debuggee.sessionId === "string" || typeof debuggee.tabId !== "number") {
|
|
1172
|
+
return {
|
|
1173
|
+
sessionId: null,
|
|
1174
|
+
stage: "missing_root_target_id"
|
|
1175
|
+
};
|
|
1176
|
+
}
|
|
1177
|
+
const rootTargetId = typeof debuggee.targetId === "string" && debuggee.targetId.length > 0
|
|
1178
|
+
? debuggee.targetId
|
|
1179
|
+
: null;
|
|
1180
|
+
if (!rootTargetId) {
|
|
1181
|
+
return {
|
|
1182
|
+
sessionId: null,
|
|
1183
|
+
stage: "missing_root_target_id"
|
|
1184
|
+
};
|
|
1185
|
+
}
|
|
1186
|
+
try {
|
|
1187
|
+
const result = await this.sendCommandOnce({ targetId: rootTargetId }, "Target.attachToTarget", {
|
|
1188
|
+
targetId,
|
|
1189
|
+
flatten: true
|
|
1190
|
+
});
|
|
1191
|
+
const record = isRecord(result) ? result : {};
|
|
1192
|
+
const childSessionId = typeof record.sessionId === "string" ? record.sessionId : null;
|
|
1193
|
+
if (!childSessionId) {
|
|
1194
|
+
return {
|
|
1195
|
+
sessionId: null,
|
|
1196
|
+
stage: "attach_null"
|
|
1197
|
+
};
|
|
1198
|
+
}
|
|
1199
|
+
const targetInfo = this.resolveTargetInfo(targetId) ?? {
|
|
1200
|
+
targetId,
|
|
1201
|
+
type: "page",
|
|
1202
|
+
browserContextId: DEFAULT_BROWSER_CONTEXT_ID
|
|
1203
|
+
};
|
|
1204
|
+
this.sessions.registerChildSession(debuggee.tabId, targetInfo, childSessionId);
|
|
1205
|
+
return {
|
|
1206
|
+
sessionId: childSessionId,
|
|
1207
|
+
stage: "attached"
|
|
1208
|
+
};
|
|
1209
|
+
}
|
|
1210
|
+
catch (error) {
|
|
1211
|
+
if (priorError && isAttachBlockedError(priorError) && isAttachBlockedError(error)) {
|
|
1212
|
+
return {
|
|
1213
|
+
sessionId: null,
|
|
1214
|
+
stage: "attach_blocked",
|
|
1215
|
+
reason: getErrorMessage(error)
|
|
1216
|
+
};
|
|
1217
|
+
}
|
|
1218
|
+
if (priorError && this.isStaleTabError(priorError) && this.isStaleTabError(error)) {
|
|
1219
|
+
return {
|
|
1220
|
+
sessionId: null,
|
|
1221
|
+
stage: "attach_blocked",
|
|
1222
|
+
reason: getErrorMessage(error)
|
|
1223
|
+
};
|
|
1224
|
+
}
|
|
1225
|
+
throw error;
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
async reattachRootAndAttachChildTarget(tabId, targetId) {
|
|
1229
|
+
let result = { sessionId: null };
|
|
1230
|
+
try {
|
|
1231
|
+
let tabScopedRootDebuggee;
|
|
1232
|
+
try {
|
|
1233
|
+
tabScopedRootDebuggee = await this.reattachTabScopedRootDebuggeeForPopup(tabId);
|
|
1234
|
+
}
|
|
1235
|
+
catch (error) {
|
|
1236
|
+
result = {
|
|
1237
|
+
sessionId: null,
|
|
1238
|
+
terminalBranch: "tab_scoped_root_reattach",
|
|
1239
|
+
stage: "tab_scoped_root_reattach_failed",
|
|
1240
|
+
reason: getErrorMessage(error)
|
|
1241
|
+
};
|
|
1242
|
+
return result;
|
|
1243
|
+
}
|
|
1244
|
+
try {
|
|
1245
|
+
const tabScopedSessionId = await this.attachChildTargetWithDebuggee(tabScopedRootDebuggee, targetId);
|
|
1246
|
+
if (tabScopedSessionId) {
|
|
1247
|
+
result = { sessionId: tabScopedSessionId };
|
|
1248
|
+
return result;
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1251
|
+
catch (tabScopedError) {
|
|
1252
|
+
if (!isAttachBlockedError(tabScopedError) && !this.isStaleTabError(tabScopedError)) {
|
|
1253
|
+
result = {
|
|
1254
|
+
sessionId: null,
|
|
1255
|
+
terminalBranch: "tab_scoped_root_reattach",
|
|
1256
|
+
stage: "tab_scoped_attach_failed",
|
|
1257
|
+
reason: getErrorMessage(tabScopedError)
|
|
1258
|
+
};
|
|
1259
|
+
return result;
|
|
1260
|
+
}
|
|
1261
|
+
}
|
|
1262
|
+
try {
|
|
1263
|
+
await this.reattachRootDebuggee(tabId);
|
|
1264
|
+
const rootDebuggee = await this.resolveRootSessionDebuggee(tabId);
|
|
1265
|
+
const rootSessionId = await this.attachChildTargetWithDebuggee(rootDebuggee, targetId);
|
|
1266
|
+
result = rootSessionId
|
|
1267
|
+
? { sessionId: rootSessionId }
|
|
1268
|
+
: {
|
|
1269
|
+
sessionId: null,
|
|
1270
|
+
terminalBranch: "root_debuggee_reattach",
|
|
1271
|
+
stage: "root_debuggee_attach_null"
|
|
1272
|
+
};
|
|
1273
|
+
}
|
|
1274
|
+
catch (error) {
|
|
1275
|
+
const blocked = isAttachBlockedError(error) || this.isStaleTabError(error);
|
|
1276
|
+
result = {
|
|
1277
|
+
sessionId: null,
|
|
1278
|
+
terminalBranch: "root_debuggee_reattach",
|
|
1279
|
+
stage: blocked ? "root_debuggee_attach_blocked" : "root_debuggee_attach_failed",
|
|
1280
|
+
reason: getErrorMessage(error)
|
|
1281
|
+
};
|
|
1282
|
+
}
|
|
1283
|
+
return result;
|
|
1284
|
+
}
|
|
1285
|
+
catch (error) {
|
|
1286
|
+
result = {
|
|
1287
|
+
sessionId: null,
|
|
1288
|
+
terminalBranch: "root_debuggee_reattach",
|
|
1289
|
+
stage: "root_debuggee_reattach_failed",
|
|
1290
|
+
reason: getErrorMessage(error)
|
|
1291
|
+
};
|
|
1292
|
+
return result;
|
|
1293
|
+
}
|
|
1294
|
+
finally {
|
|
1295
|
+
if (!result.sessionId) {
|
|
1296
|
+
await this.restoreRootAfterChildAttachFailure(tabId);
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1299
|
+
}
|
|
1300
|
+
async reattachTabScopedRootDebuggeeForPopup(tabId) {
|
|
1301
|
+
const existing = this.debuggees.get(tabId);
|
|
1302
|
+
this.debuggees.delete(tabId);
|
|
1303
|
+
this.detachTabState(tabId);
|
|
1304
|
+
if (existing) {
|
|
1305
|
+
this.markExpectedRootDetach(tabId);
|
|
1306
|
+
await this.safeDetach(existing);
|
|
1307
|
+
}
|
|
1308
|
+
this.ensureListeners();
|
|
1309
|
+
const resolvedRootDebuggee = await this.resolveRootDebuggee(tabId);
|
|
1310
|
+
const tabScopedDebuggee = typeof resolvedRootDebuggee.targetId === "string" && resolvedRootDebuggee.targetId.length > 0
|
|
1311
|
+
? { tabId, targetId: resolvedRootDebuggee.targetId }
|
|
1312
|
+
: { tabId };
|
|
1313
|
+
await this.attachRootDebuggee(tabScopedDebuggee);
|
|
1314
|
+
this.debuggees.set(tabId, tabScopedDebuggee);
|
|
1315
|
+
await this.registerRootTab(tabId);
|
|
1316
|
+
this.updatePrimaryTab(tabId);
|
|
1317
|
+
return await this.resolveRootSessionDebuggee(tabId);
|
|
1318
|
+
}
|
|
1319
|
+
async restoreRootAfterChildAttachFailure(tabId) {
|
|
1320
|
+
try {
|
|
1321
|
+
await this.refreshTabAttachment(tabId);
|
|
1322
|
+
}
|
|
1323
|
+
catch {
|
|
1324
|
+
// Best-effort root restoration only. The original popup attach error remains authoritative.
|
|
1325
|
+
}
|
|
1326
|
+
}
|
|
1327
|
+
async reattachRootDebuggee(tabId, allowRetry = false) {
|
|
1328
|
+
const existing = this.debuggees.get(tabId);
|
|
1329
|
+
this.debuggees.delete(tabId);
|
|
1330
|
+
this.detachTabState(tabId);
|
|
1331
|
+
if (existing) {
|
|
1332
|
+
this.markExpectedRootDetach(tabId);
|
|
1333
|
+
await this.safeDetach(existing);
|
|
1334
|
+
}
|
|
1335
|
+
await this.attachInternal(tabId, allowRetry);
|
|
1336
|
+
}
|
|
1337
|
+
async readDebuggerPageTargets(tabId) {
|
|
1338
|
+
const tab = await this.tabManager.getTab(tabId);
|
|
1339
|
+
const targets = await new Promise((resolve) => {
|
|
1340
|
+
chrome.debugger.getTargets((records) => {
|
|
1341
|
+
const lastError = chrome.runtime.lastError;
|
|
1342
|
+
if (lastError || !Array.isArray(records)) {
|
|
1343
|
+
resolve([]);
|
|
1344
|
+
return;
|
|
1345
|
+
}
|
|
1346
|
+
resolve(records);
|
|
1347
|
+
});
|
|
1348
|
+
});
|
|
1349
|
+
const pageTargets = targets.filter((target) => target.tabId === tabId && target.type === "page");
|
|
1350
|
+
return { tab: tab ?? null, pageTargets };
|
|
1351
|
+
}
|
|
1352
|
+
selectPreferredDebuggerTargetInfo(tab, pageTargets) {
|
|
1353
|
+
if (pageTargets.length === 0) {
|
|
1354
|
+
return null;
|
|
1355
|
+
}
|
|
1356
|
+
const liveTargets = pageTargets.some((target) => target.attached)
|
|
1357
|
+
? pageTargets.filter((target) => target.attached)
|
|
1358
|
+
: pageTargets;
|
|
1359
|
+
const preferredByUrl = typeof tab?.url === "string"
|
|
1360
|
+
? liveTargets.find((target) => target.url === tab.url)
|
|
1361
|
+
: null;
|
|
1362
|
+
const preferredByTitle = typeof tab?.title === "string"
|
|
1363
|
+
? liveTargets.find((target) => target.title === tab.title)
|
|
1364
|
+
: null;
|
|
1365
|
+
return preferredByUrl ?? preferredByTitle ?? liveTargets[0] ?? null;
|
|
1366
|
+
}
|
|
1367
|
+
async readDebuggerTargetInfo(tabId) {
|
|
1368
|
+
const { tab, pageTargets } = await this.readDebuggerPageTargets(tabId);
|
|
1369
|
+
return this.selectPreferredDebuggerTargetInfo(tab, pageTargets);
|
|
1370
|
+
}
|
|
1371
|
+
async readDebuggerTargetId(tabId) {
|
|
1372
|
+
return (await this.readDebuggerTargetInfo(tabId))?.id ?? null;
|
|
1373
|
+
}
|
|
1374
|
+
resolveTargetInfo(targetId, sessionId) {
|
|
1375
|
+
if (targetId) {
|
|
1376
|
+
const record = this.sessions.getByTargetId(targetId);
|
|
1377
|
+
return record?.targetInfo
|
|
1378
|
+
?? (record?.kind === "root" ? this.sessions.getByTabId(record.tabId)?.targetInfo ?? null : null);
|
|
1379
|
+
}
|
|
1380
|
+
if (sessionId) {
|
|
1381
|
+
const session = this.sessions.getBySessionId(sessionId);
|
|
1382
|
+
return session?.targetInfo
|
|
1383
|
+
?? (session?.kind === "root" ? this.sessions.getByTabId(session.tabId)?.targetInfo ?? null : null);
|
|
1384
|
+
}
|
|
1385
|
+
return {
|
|
1386
|
+
targetId: DEFAULT_BROWSER_TARGET_ID,
|
|
1387
|
+
type: "browser",
|
|
1388
|
+
title: "OpenDevBrowser Relay",
|
|
1389
|
+
url: ""
|
|
1390
|
+
};
|
|
296
1391
|
}
|
|
297
1392
|
ensureListeners() {
|
|
298
1393
|
if (this.listenersActive)
|
|
@@ -316,7 +1411,7 @@ export class CDPRouter {
|
|
|
316
1411
|
autoAttach: false,
|
|
317
1412
|
waitForDebuggerOnStart: false,
|
|
318
1413
|
flatten: true
|
|
319
|
-
});
|
|
1414
|
+
}, { preserveTab: true, refreshPreparedDebuggee: false });
|
|
320
1415
|
this.flatSessionValidated = true;
|
|
321
1416
|
}
|
|
322
1417
|
catch (error) {
|
|
@@ -325,7 +1420,12 @@ export class CDPRouter {
|
|
|
325
1420
|
throw new Error(`${FLAT_SESSION_ERROR} (${detail})`);
|
|
326
1421
|
}
|
|
327
1422
|
}
|
|
1423
|
+
async applyDiscoverTargets(debuggee, discover) {
|
|
1424
|
+
const rootTrackingDebuggee = this.resolveRootTrackingDebuggee(debuggee);
|
|
1425
|
+
await this.sendCommand(rootTrackingDebuggee, "Target.setDiscoverTargets", { discover }, { preserveTab: true, refreshPreparedDebuggee: false });
|
|
1426
|
+
}
|
|
328
1427
|
async applyAutoAttach(debuggee) {
|
|
1428
|
+
const rootTrackingDebuggee = this.resolveRootTrackingDebuggee(debuggee);
|
|
329
1429
|
const params = {
|
|
330
1430
|
autoAttach: this.autoAttachOptions.autoAttach,
|
|
331
1431
|
waitForDebuggerOnStart: this.autoAttachOptions.waitForDebuggerOnStart,
|
|
@@ -335,7 +1435,7 @@ export class CDPRouter {
|
|
|
335
1435
|
params.filter = this.autoAttachOptions.filter;
|
|
336
1436
|
}
|
|
337
1437
|
try {
|
|
338
|
-
await this.sendCommand(
|
|
1438
|
+
await this.sendCommand(rootTrackingDebuggee, "Target.setAutoAttach", params, { preserveTab: true, refreshPreparedDebuggee: false });
|
|
339
1439
|
}
|
|
340
1440
|
catch (error) {
|
|
341
1441
|
const detail = getErrorMessage(error);
|
|
@@ -343,6 +1443,24 @@ export class CDPRouter {
|
|
|
343
1443
|
throw new Error(`${FLAT_SESSION_ERROR} (${detail})`);
|
|
344
1444
|
}
|
|
345
1445
|
}
|
|
1446
|
+
resolveRootTrackingDebuggee(debuggee) {
|
|
1447
|
+
const rootDebuggee = typeof debuggee.tabId === "number"
|
|
1448
|
+
? this.debuggees.get(debuggee.tabId) ?? debuggee
|
|
1449
|
+
: debuggee;
|
|
1450
|
+
if (rootDebuggee.attachBy === "targetId"
|
|
1451
|
+
&& typeof rootDebuggee.targetId === "string"
|
|
1452
|
+
&& rootDebuggee.targetId.length > 0) {
|
|
1453
|
+
return {
|
|
1454
|
+
...(typeof rootDebuggee.tabId === "number" ? { tabId: rootDebuggee.tabId } : {}),
|
|
1455
|
+
targetId: rootDebuggee.targetId,
|
|
1456
|
+
attachBy: "targetId"
|
|
1457
|
+
};
|
|
1458
|
+
}
|
|
1459
|
+
if (typeof rootDebuggee.sessionId === "string" && typeof rootDebuggee.tabId === "number") {
|
|
1460
|
+
return { tabId: rootDebuggee.tabId };
|
|
1461
|
+
}
|
|
1462
|
+
return rootDebuggee;
|
|
1463
|
+
}
|
|
346
1464
|
async applyAutoAttachToChild(tabId, sessionId) {
|
|
347
1465
|
if (!this.autoAttachOptions.autoAttach)
|
|
348
1466
|
return;
|
|
@@ -403,16 +1521,29 @@ export class CDPRouter {
|
|
|
403
1521
|
handleEvent(source, method, params) {
|
|
404
1522
|
if (!this.callbacks)
|
|
405
1523
|
return;
|
|
406
|
-
const tabId =
|
|
1524
|
+
const tabId = this.resolveEventTabId(source, params);
|
|
407
1525
|
if (tabId === null || !this.debuggees.has(tabId))
|
|
408
1526
|
return;
|
|
409
1527
|
if (method === "Target.receivedMessageFromTarget")
|
|
410
1528
|
return;
|
|
1529
|
+
if (method === "Target.targetCreated" && params && isRecord(params)) {
|
|
1530
|
+
const targetInfo = isTargetInfo(params.targetInfo) ? params.targetInfo : null;
|
|
1531
|
+
if (targetInfo) {
|
|
1532
|
+
this.pendingTargetTabIds.set(targetInfo.targetId, tabId);
|
|
1533
|
+
}
|
|
1534
|
+
}
|
|
411
1535
|
if (method === "Target.attachedToTarget" && params && isRecord(params)) {
|
|
412
1536
|
const sessionId = typeof params.sessionId === "string" ? params.sessionId : null;
|
|
413
1537
|
const targetInfo = isTargetInfo(params.targetInfo) ? params.targetInfo : null;
|
|
414
1538
|
if (sessionId && targetInfo) {
|
|
415
|
-
this.
|
|
1539
|
+
this.pendingTargetTabIds.delete(targetInfo.targetId);
|
|
1540
|
+
if (this.isAttachedRootTarget(tabId, targetInfo)) {
|
|
1541
|
+
this.sessions.setRootAttachTargetId(tabId, targetInfo.targetId);
|
|
1542
|
+
this.sessions.registerAttachedRootSession(tabId, sessionId);
|
|
1543
|
+
}
|
|
1544
|
+
else {
|
|
1545
|
+
this.sessions.registerChildSession(tabId, targetInfo, sessionId);
|
|
1546
|
+
}
|
|
416
1547
|
this.quarantinedSessions.delete(sessionId);
|
|
417
1548
|
this.applyAutoAttachToChild(tabId, sessionId).catch((error) => {
|
|
418
1549
|
logError("cdp.apply_auto_attach_child", error, { code: "auto_attach_failed" });
|
|
@@ -424,6 +1555,10 @@ export class CDPRouter {
|
|
|
424
1555
|
}
|
|
425
1556
|
if (method === "Target.detachedFromTarget" && params && isRecord(params)) {
|
|
426
1557
|
const detachedSessionId = typeof params.sessionId === "string" ? params.sessionId : null;
|
|
1558
|
+
const detachedTargetId = typeof params.targetId === "string" ? params.targetId : null;
|
|
1559
|
+
if (detachedTargetId) {
|
|
1560
|
+
this.pendingTargetTabIds.delete(detachedTargetId);
|
|
1561
|
+
}
|
|
427
1562
|
if (detachedSessionId) {
|
|
428
1563
|
const removed = this.sessions.removeBySessionId(detachedSessionId);
|
|
429
1564
|
if (!removed) {
|
|
@@ -433,16 +1568,26 @@ export class CDPRouter {
|
|
|
433
1568
|
}
|
|
434
1569
|
}
|
|
435
1570
|
}
|
|
1571
|
+
if (method === "Target.targetDestroyed" && params && isRecord(params)) {
|
|
1572
|
+
const targetId = typeof params.targetId === "string" ? params.targetId : null;
|
|
1573
|
+
if (targetId) {
|
|
1574
|
+
this.pendingTargetTabIds.delete(targetId);
|
|
1575
|
+
}
|
|
1576
|
+
}
|
|
436
1577
|
const sourceSessionId = source.sessionId;
|
|
437
|
-
if (typeof sourceSessionId === "string"
|
|
1578
|
+
if (typeof sourceSessionId === "string"
|
|
1579
|
+
&& !this.sessions.hasSession(sourceSessionId)
|
|
1580
|
+
&& !this.shouldAllowUnknownSourceSession(method, source, tabId)) {
|
|
438
1581
|
this.quarantineUnknownSession(tabId, sourceSessionId, method);
|
|
439
1582
|
return;
|
|
440
1583
|
}
|
|
441
1584
|
const forwardSessionId = this.resolveForwardSessionId(method, source);
|
|
442
|
-
this.emitEvent(method, params, forwardSessionId);
|
|
1585
|
+
this.emitEvent(tabId, method, params, forwardSessionId);
|
|
443
1586
|
}
|
|
444
1587
|
handleDetach(source, reason) {
|
|
445
|
-
|
|
1588
|
+
if (this.consumeExpectedRootDetach(source))
|
|
1589
|
+
return;
|
|
1590
|
+
const tabId = this.resolveSourceTabId(source);
|
|
446
1591
|
if (tabId === null || !this.debuggees.has(tabId))
|
|
447
1592
|
return;
|
|
448
1593
|
this.debuggees.delete(tabId);
|
|
@@ -453,14 +1598,29 @@ export class CDPRouter {
|
|
|
453
1598
|
}
|
|
454
1599
|
}
|
|
455
1600
|
detachTabState(tabId) {
|
|
1601
|
+
this.expectedRootDetachDeadlines.delete(tabId);
|
|
1602
|
+
this.clearRootAttachDiagnostic(tabId);
|
|
456
1603
|
const record = this.sessions.removeByTabId(tabId);
|
|
1604
|
+
for (const [key, diagnostic] of this.childAttachDiagnostics.entries()) {
|
|
1605
|
+
if (diagnostic.tabId === tabId) {
|
|
1606
|
+
this.childAttachDiagnostics.delete(key);
|
|
1607
|
+
}
|
|
1608
|
+
}
|
|
1609
|
+
for (const [targetId, mappedTabId] of this.pendingTargetTabIds.entries()) {
|
|
1610
|
+
if (mappedTabId === tabId) {
|
|
1611
|
+
this.pendingTargetTabIds.delete(targetId);
|
|
1612
|
+
}
|
|
1613
|
+
}
|
|
457
1614
|
if (record) {
|
|
1615
|
+
if (record.attachTargetId) {
|
|
1616
|
+
this.rootTargetTabIds.delete(record.attachTargetId);
|
|
1617
|
+
}
|
|
458
1618
|
this.rootAttachedSessions.delete(record.rootSessionId);
|
|
459
1619
|
if (this.autoAttachOptions.autoAttach) {
|
|
460
|
-
this.emitTargetDetached(record.rootSessionId, record.targetInfo.targetId);
|
|
1620
|
+
this.emitTargetDetached(record.tabId, record.rootSessionId, record.targetInfo.targetId);
|
|
461
1621
|
}
|
|
462
1622
|
if (this.discoverTargets) {
|
|
463
|
-
this.emitTargetDestroyed(record.targetInfo.targetId);
|
|
1623
|
+
this.emitTargetDestroyed(record.tabId, record.targetInfo.targetId);
|
|
464
1624
|
}
|
|
465
1625
|
}
|
|
466
1626
|
if (tabId === this.primaryTabId) {
|
|
@@ -476,14 +1636,186 @@ export class CDPRouter {
|
|
|
476
1636
|
if (typeof sessionId === "string") {
|
|
477
1637
|
return this.sessions.getBySessionId(sessionId) ? sessionId : undefined;
|
|
478
1638
|
}
|
|
479
|
-
const tabId =
|
|
1639
|
+
const tabId = this.resolveSourceTabId(source);
|
|
480
1640
|
if (tabId === null)
|
|
481
1641
|
return undefined;
|
|
482
1642
|
const record = this.sessions.getByTabId(tabId);
|
|
483
1643
|
if (!record)
|
|
484
1644
|
return undefined;
|
|
1645
|
+
const browserSession = this.sessions.getBrowserSession(tabId);
|
|
1646
|
+
if (browserSession) {
|
|
1647
|
+
return browserSession.sessionId;
|
|
1648
|
+
}
|
|
485
1649
|
return this.rootAttachedSessions.has(record.rootSessionId) ? record.rootSessionId : undefined;
|
|
486
1650
|
}
|
|
1651
|
+
resolveEventTabId(source, params) {
|
|
1652
|
+
const sourceTabId = this.resolveSourceTabId(source);
|
|
1653
|
+
if (sourceTabId !== null) {
|
|
1654
|
+
return sourceTabId;
|
|
1655
|
+
}
|
|
1656
|
+
if (!params || !isRecord(params)) {
|
|
1657
|
+
return null;
|
|
1658
|
+
}
|
|
1659
|
+
const targetInfo = isTargetInfo(params.targetInfo) ? params.targetInfo : null;
|
|
1660
|
+
const openerTabId = this.resolveLinkedTargetTabId(targetInfo?.openerId);
|
|
1661
|
+
if (openerTabId !== null) {
|
|
1662
|
+
if (targetInfo) {
|
|
1663
|
+
this.pendingTargetTabIds.set(targetInfo.targetId, openerTabId);
|
|
1664
|
+
}
|
|
1665
|
+
return openerTabId;
|
|
1666
|
+
}
|
|
1667
|
+
if (targetInfo) {
|
|
1668
|
+
const targetTabId = this.resolveLinkedTargetTabId(targetInfo.targetId);
|
|
1669
|
+
if (targetTabId !== null) {
|
|
1670
|
+
return targetTabId;
|
|
1671
|
+
}
|
|
1672
|
+
}
|
|
1673
|
+
const targetId = typeof params.targetId === "string" ? params.targetId : null;
|
|
1674
|
+
if (targetId) {
|
|
1675
|
+
return this.resolveLinkedTargetTabId(targetId);
|
|
1676
|
+
}
|
|
1677
|
+
const sessionId = typeof params.sessionId === "string" ? params.sessionId : null;
|
|
1678
|
+
if (sessionId) {
|
|
1679
|
+
return this.sessions.getBySessionId(sessionId)?.tabId ?? null;
|
|
1680
|
+
}
|
|
1681
|
+
return null;
|
|
1682
|
+
}
|
|
1683
|
+
resolveSourceTabId(source) {
|
|
1684
|
+
if (typeof source.tabId === "number") {
|
|
1685
|
+
return source.tabId;
|
|
1686
|
+
}
|
|
1687
|
+
const sourceSessionId = source.sessionId;
|
|
1688
|
+
if (typeof sourceSessionId === "string") {
|
|
1689
|
+
const knownTabId = this.sessions.getBySessionId(sourceSessionId)?.tabId
|
|
1690
|
+
?? this.quarantinedSessions.get(sourceSessionId)?.tabId
|
|
1691
|
+
?? null;
|
|
1692
|
+
if (typeof knownTabId === "number") {
|
|
1693
|
+
return knownTabId;
|
|
1694
|
+
}
|
|
1695
|
+
if (this.debuggees.size === 1) {
|
|
1696
|
+
const nextAttachedTab = this.debuggees.keys().next();
|
|
1697
|
+
return nextAttachedTab.done ? null : nextAttachedTab.value;
|
|
1698
|
+
}
|
|
1699
|
+
return null;
|
|
1700
|
+
}
|
|
1701
|
+
if (typeof source.targetId === "string") {
|
|
1702
|
+
return this.resolveLinkedTargetTabId(source.targetId);
|
|
1703
|
+
}
|
|
1704
|
+
return null;
|
|
1705
|
+
}
|
|
1706
|
+
shouldAllowUnknownSourceSession(method, source, tabId) {
|
|
1707
|
+
if (method !== "Page.javascriptDialogOpening"
|
|
1708
|
+
&& method !== "Page.javascriptDialogClosed"
|
|
1709
|
+
&& method !== "Page.fileChooserOpened") {
|
|
1710
|
+
return false;
|
|
1711
|
+
}
|
|
1712
|
+
if (typeof source.tabId === "number") {
|
|
1713
|
+
return source.tabId === tabId;
|
|
1714
|
+
}
|
|
1715
|
+
if (typeof source.targetId === "string") {
|
|
1716
|
+
return this.resolveLinkedTargetTabId(source.targetId) === tabId;
|
|
1717
|
+
}
|
|
1718
|
+
if (typeof source.sessionId === "string") {
|
|
1719
|
+
return this.resolveSourceTabId(source) === tabId;
|
|
1720
|
+
}
|
|
1721
|
+
return false;
|
|
1722
|
+
}
|
|
1723
|
+
resolveLinkedTargetTabId(targetId) {
|
|
1724
|
+
if (typeof targetId !== "string" || targetId.length === 0) {
|
|
1725
|
+
return null;
|
|
1726
|
+
}
|
|
1727
|
+
return parseTabTargetAlias(targetId)
|
|
1728
|
+
?? this.rootTargetTabIds.get(targetId)
|
|
1729
|
+
?? this.sessions.getByTargetId(targetId)?.tabId
|
|
1730
|
+
?? this.sessions.getTabIdByTargetAlias(targetId)
|
|
1731
|
+
?? this.pendingTargetTabIds.get(targetId)
|
|
1732
|
+
?? null;
|
|
1733
|
+
}
|
|
1734
|
+
isAttachedRootTarget(tabId, targetInfo) {
|
|
1735
|
+
if (targetInfo.type !== "page") {
|
|
1736
|
+
return false;
|
|
1737
|
+
}
|
|
1738
|
+
const record = this.sessions.getByTabId(tabId);
|
|
1739
|
+
if (!record) {
|
|
1740
|
+
return false;
|
|
1741
|
+
}
|
|
1742
|
+
if (record.attachTargetId && targetInfo.targetId === record.attachTargetId) {
|
|
1743
|
+
return true;
|
|
1744
|
+
}
|
|
1745
|
+
if (targetInfo.targetId === record.targetInfo.targetId) {
|
|
1746
|
+
return true;
|
|
1747
|
+
}
|
|
1748
|
+
if (record.targetInfo.url && targetInfo.url === record.targetInfo.url) {
|
|
1749
|
+
return true;
|
|
1750
|
+
}
|
|
1751
|
+
if (record.targetInfo.title && targetInfo.title === record.targetInfo.title) {
|
|
1752
|
+
return true;
|
|
1753
|
+
}
|
|
1754
|
+
return false;
|
|
1755
|
+
}
|
|
1756
|
+
childAttachDiagnosticKey(tabId, targetId) {
|
|
1757
|
+
return `${tabId}:${targetId}`;
|
|
1758
|
+
}
|
|
1759
|
+
resolveRootAttachBy(debuggee) {
|
|
1760
|
+
return debuggee.attachBy === "targetId" ? "targetId" : "tabId";
|
|
1761
|
+
}
|
|
1762
|
+
clearRootAttachDiagnostic(tabId) {
|
|
1763
|
+
this.rootAttachDiagnostics.delete(tabId);
|
|
1764
|
+
}
|
|
1765
|
+
recordRootAttachDiagnostic(tabId, diagnostic) {
|
|
1766
|
+
this.rootAttachDiagnostics.set(tabId, {
|
|
1767
|
+
tabId,
|
|
1768
|
+
at: Date.now(),
|
|
1769
|
+
...diagnostic
|
|
1770
|
+
});
|
|
1771
|
+
}
|
|
1772
|
+
clearChildAttachDiagnostic(tabId, targetId) {
|
|
1773
|
+
this.childAttachDiagnostics.delete(this.childAttachDiagnosticKey(tabId, targetId));
|
|
1774
|
+
}
|
|
1775
|
+
recordChildAttachDiagnostic(tabId, targetId, diagnostic) {
|
|
1776
|
+
this.childAttachDiagnostics.set(this.childAttachDiagnosticKey(tabId, targetId), {
|
|
1777
|
+
tabId,
|
|
1778
|
+
targetId,
|
|
1779
|
+
at: Date.now(),
|
|
1780
|
+
...diagnostic
|
|
1781
|
+
});
|
|
1782
|
+
}
|
|
1783
|
+
async captureRootRefreshDiagnostic(tabId, path, refreshCompleted, error) {
|
|
1784
|
+
const attachedDebuggee = this.debuggees.get(tabId) ?? null;
|
|
1785
|
+
const rootRecord = this.sessions.getByTabId(tabId);
|
|
1786
|
+
const rootSession = rootRecord
|
|
1787
|
+
? this.sessions.getBySessionId(rootRecord.rootSessionId)
|
|
1788
|
+
: null;
|
|
1789
|
+
const debuggee = attachedDebuggee ?? rootSession?.debuggerSession ?? null;
|
|
1790
|
+
const rootTargetIdAfterRefresh = typeof debuggee?.targetId === "string" && debuggee.targetId.length > 0
|
|
1791
|
+
? debuggee.targetId
|
|
1792
|
+
: undefined;
|
|
1793
|
+
let probeStage = refreshCompleted ? "missing_debuggee" : "skipped";
|
|
1794
|
+
let probeReason;
|
|
1795
|
+
if (refreshCompleted && debuggee) {
|
|
1796
|
+
try {
|
|
1797
|
+
await this.sendCommandOnce(debuggee, "Target.getTargets", {});
|
|
1798
|
+
probeStage = "succeeded";
|
|
1799
|
+
}
|
|
1800
|
+
catch (probeError) {
|
|
1801
|
+
probeStage = "failed";
|
|
1802
|
+
probeReason = getErrorMessage(probeError);
|
|
1803
|
+
}
|
|
1804
|
+
}
|
|
1805
|
+
this.rootRefreshDiagnostics.set(tabId, {
|
|
1806
|
+
tabId,
|
|
1807
|
+
path,
|
|
1808
|
+
refreshCompleted,
|
|
1809
|
+
debuggeePresentAfterRefresh: attachedDebuggee !== null,
|
|
1810
|
+
rootSessionPresentAfterRefresh: rootSession !== null,
|
|
1811
|
+
...(rootTargetIdAfterRefresh ? { rootTargetIdAfterRefresh } : {}),
|
|
1812
|
+
probeMethod: "Target.getTargets",
|
|
1813
|
+
probeStage,
|
|
1814
|
+
...(probeReason ? { probeReason } : {}),
|
|
1815
|
+
...(error ? { reason: getErrorMessage(error) } : {}),
|
|
1816
|
+
at: Date.now()
|
|
1817
|
+
});
|
|
1818
|
+
}
|
|
487
1819
|
async buildTargetInfo(tabId) {
|
|
488
1820
|
const tab = await this.tabManager.getTab(tabId);
|
|
489
1821
|
return {
|
|
@@ -494,14 +1826,32 @@ export class CDPRouter {
|
|
|
494
1826
|
url: tab?.url ?? undefined
|
|
495
1827
|
};
|
|
496
1828
|
}
|
|
497
|
-
|
|
498
|
-
|
|
1829
|
+
async readRootFrameInfo(tabId) {
|
|
1830
|
+
try {
|
|
1831
|
+
const result = await Promise.race([
|
|
1832
|
+
this.sendCommand({ tabId }, "Page.getFrameTree", {}, { preserveTab: true }),
|
|
1833
|
+
new Promise((resolve) => {
|
|
1834
|
+
setTimeout(() => resolve(null), 750);
|
|
1835
|
+
})
|
|
1836
|
+
]);
|
|
1837
|
+
const rootFrame = readRootFrame(result);
|
|
1838
|
+
if (!rootFrame) {
|
|
1839
|
+
return null;
|
|
1840
|
+
}
|
|
1841
|
+
return rootFrame;
|
|
1842
|
+
}
|
|
1843
|
+
catch {
|
|
1844
|
+
return null;
|
|
1845
|
+
}
|
|
1846
|
+
}
|
|
1847
|
+
emitTargetCreated(tabId, targetInfo) {
|
|
1848
|
+
this.emitEvent(tabId, "Target.targetCreated", { targetInfo });
|
|
499
1849
|
}
|
|
500
|
-
emitTargetDestroyed(targetId) {
|
|
501
|
-
this.emitEvent("Target.targetDestroyed", { targetId });
|
|
1850
|
+
emitTargetDestroyed(tabId, targetId) {
|
|
1851
|
+
this.emitEvent(tabId, "Target.targetDestroyed", { targetId });
|
|
502
1852
|
}
|
|
503
|
-
emitTargetDetached(sessionId, targetId) {
|
|
504
|
-
this.emitEvent("Target.detachedFromTarget", { sessionId, targetId });
|
|
1853
|
+
emitTargetDetached(tabId, sessionId, targetId) {
|
|
1854
|
+
this.emitEvent(tabId, "Target.detachedFromTarget", { sessionId, targetId });
|
|
505
1855
|
}
|
|
506
1856
|
emitRootAttached(targetInfo) {
|
|
507
1857
|
const record = this.sessions.getByTargetId(targetInfo.targetId);
|
|
@@ -510,7 +1860,7 @@ export class CDPRouter {
|
|
|
510
1860
|
if (this.rootAttachedSessions.has(record.sessionId))
|
|
511
1861
|
return;
|
|
512
1862
|
this.rootAttachedSessions.add(record.sessionId);
|
|
513
|
-
this.emitEvent("Target.attachedToTarget", {
|
|
1863
|
+
this.emitEvent(record.tabId, "Target.attachedToTarget", {
|
|
514
1864
|
sessionId: record.sessionId,
|
|
515
1865
|
targetInfo,
|
|
516
1866
|
waitingForDebugger: false
|
|
@@ -524,7 +1874,7 @@ export class CDPRouter {
|
|
|
524
1874
|
if (!this.rootAttachedSessions.has(record.sessionId))
|
|
525
1875
|
continue;
|
|
526
1876
|
this.rootAttachedSessions.delete(record.sessionId);
|
|
527
|
-
this.emitTargetDetached(record.sessionId, targetInfo.targetId);
|
|
1877
|
+
this.emitTargetDetached(record.tabId, record.sessionId, targetInfo.targetId);
|
|
528
1878
|
}
|
|
529
1879
|
}
|
|
530
1880
|
resetRootAttached() {
|
|
@@ -535,25 +1885,76 @@ export class CDPRouter {
|
|
|
535
1885
|
this.sessionCounter += 1;
|
|
536
1886
|
return sessionId;
|
|
537
1887
|
}
|
|
538
|
-
|
|
1888
|
+
createBrowserSessionId() {
|
|
1889
|
+
const sessionId = `pw-browser-${this.sessionCounter}`;
|
|
1890
|
+
this.sessionCounter += 1;
|
|
1891
|
+
return sessionId;
|
|
1892
|
+
}
|
|
1893
|
+
async ensureBrowserSession(tabId) {
|
|
1894
|
+
const existing = this.sessions.getBrowserSession(tabId);
|
|
1895
|
+
if (existing) {
|
|
1896
|
+
return existing.sessionId;
|
|
1897
|
+
}
|
|
1898
|
+
const browserSessionId = this.createBrowserSessionId();
|
|
1899
|
+
return this.sessions.registerBrowserSession(tabId, browserSessionId)?.sessionId ?? null;
|
|
1900
|
+
}
|
|
1901
|
+
async sendCommand(debuggee, method, params, options = {}) {
|
|
1902
|
+
const preferredTabId = this.resolveSourceTabId(debuggee);
|
|
1903
|
+
const refreshCommandDebuggee = options.refreshPreparedDebuggee !== false
|
|
1904
|
+
&& this.shouldRefreshPreparedCommandDebuggee(debuggee, preferredTabId);
|
|
1905
|
+
await this.prepareForNextClientIfNeeded(preferredTabId);
|
|
1906
|
+
const commandDebuggee = refreshCommandDebuggee && preferredTabId !== null
|
|
1907
|
+
? (this.getTabDebuggee(preferredTabId) ?? debuggee)
|
|
1908
|
+
: debuggee;
|
|
539
1909
|
try {
|
|
540
|
-
return await this.sendCommandOnce(
|
|
1910
|
+
return await this.sendCommandOnce(commandDebuggee, method, params);
|
|
541
1911
|
}
|
|
542
1912
|
catch (error) {
|
|
543
|
-
const hasChildSession = typeof
|
|
1913
|
+
const hasChildSession = typeof commandDebuggee.sessionId === "string";
|
|
544
1914
|
if (!this.isStaleTabError(error) || hasChildSession) {
|
|
545
1915
|
throw error;
|
|
546
1916
|
}
|
|
547
|
-
const
|
|
1917
|
+
const retainedRootDebuggee = this.resolveRetainedRootTargetDebuggee(commandDebuggee);
|
|
1918
|
+
if (retainedRootDebuggee) {
|
|
1919
|
+
try {
|
|
1920
|
+
return await this.sendCommandOnce(retainedRootDebuggee, method, params);
|
|
1921
|
+
}
|
|
1922
|
+
catch (retainedError) {
|
|
1923
|
+
if (!this.isStaleTabError(retainedError)) {
|
|
1924
|
+
throw retainedError;
|
|
1925
|
+
}
|
|
1926
|
+
error = retainedError;
|
|
1927
|
+
}
|
|
1928
|
+
}
|
|
1929
|
+
const recovered = await this.recoverFromStaleTab(commandDebuggee, options.preserveTab === true);
|
|
548
1930
|
if (!recovered) {
|
|
549
1931
|
throw error;
|
|
550
1932
|
}
|
|
551
1933
|
return await this.sendCommandOnce(recovered, method, params);
|
|
552
1934
|
}
|
|
553
1935
|
}
|
|
1936
|
+
shouldRefreshPreparedCommandDebuggee(debuggee, preferredTabId) {
|
|
1937
|
+
if (preferredTabId === null) {
|
|
1938
|
+
return false;
|
|
1939
|
+
}
|
|
1940
|
+
if (typeof debuggee.sessionId !== "string") {
|
|
1941
|
+
return true;
|
|
1942
|
+
}
|
|
1943
|
+
const sessionRecord = this.sessions.getBySessionId(debuggee.sessionId);
|
|
1944
|
+
const rootRecord = this.sessions.getByTabId(preferredTabId);
|
|
1945
|
+
return Boolean(sessionRecord
|
|
1946
|
+
&& rootRecord
|
|
1947
|
+
&& sessionRecord.tabId === preferredTabId
|
|
1948
|
+
&& sessionRecord.targetId === rootRecord.targetInfo.targetId);
|
|
1949
|
+
}
|
|
554
1950
|
async sendCommandOnce(debuggee, method, params) {
|
|
1951
|
+
const chromeDebuggee = this.toChromeDebuggee(debuggee);
|
|
1952
|
+
const sendCommandFn = chrome.debugger.sendCommand;
|
|
1953
|
+
if (!("mock" in sendCommandFn) || chrome.debugger.sendCommand.length < 4) {
|
|
1954
|
+
return await chrome.debugger.sendCommand(chromeDebuggee, method, params);
|
|
1955
|
+
}
|
|
555
1956
|
return await new Promise((resolve, reject) => {
|
|
556
|
-
chrome.debugger.sendCommand(
|
|
1957
|
+
chrome.debugger.sendCommand(chromeDebuggee, method, params, (result) => {
|
|
557
1958
|
const lastError = chrome.runtime.lastError;
|
|
558
1959
|
if (lastError) {
|
|
559
1960
|
reject(new Error(lastError.message));
|
|
@@ -563,25 +1964,96 @@ export class CDPRouter {
|
|
|
563
1964
|
});
|
|
564
1965
|
});
|
|
565
1966
|
}
|
|
566
|
-
|
|
567
|
-
|
|
1967
|
+
resolveRetainedRootTargetDebuggee(debuggee) {
|
|
1968
|
+
if (typeof debuggee.sessionId === "string") {
|
|
1969
|
+
return null;
|
|
1970
|
+
}
|
|
1971
|
+
const staleTabId = typeof debuggee.tabId === "number"
|
|
1972
|
+
? debuggee.tabId
|
|
1973
|
+
: (typeof debuggee.targetId === "string" ? this.rootTargetTabIds.get(debuggee.targetId) ?? null : null);
|
|
1974
|
+
if (staleTabId === null) {
|
|
1975
|
+
return null;
|
|
1976
|
+
}
|
|
1977
|
+
const targetId = this.resolveRetainedRootTargetId(staleTabId);
|
|
1978
|
+
if (!targetId) {
|
|
1979
|
+
return null;
|
|
1980
|
+
}
|
|
1981
|
+
if (typeof debuggee.targetId === "string" && debuggee.targetId === targetId && typeof debuggee.tabId !== "number") {
|
|
1982
|
+
return null;
|
|
1983
|
+
}
|
|
1984
|
+
return { targetId };
|
|
1985
|
+
}
|
|
1986
|
+
resolveRetainedRootTargetId(tabId) {
|
|
1987
|
+
const attachedDebuggee = this.debuggees.get(tabId);
|
|
1988
|
+
if (typeof attachedDebuggee?.targetId === "string" && attachedDebuggee.targetId.length > 0) {
|
|
1989
|
+
return attachedDebuggee.targetId;
|
|
1990
|
+
}
|
|
1991
|
+
const rootRecord = this.sessions.getByTabId(tabId);
|
|
1992
|
+
const rootSession = rootRecord
|
|
1993
|
+
? this.sessions.getBySessionId(rootRecord.rootSessionId)
|
|
1994
|
+
: null;
|
|
1995
|
+
if (typeof rootSession?.debuggerSession?.targetId === "string" && rootSession.debuggerSession.targetId.length > 0) {
|
|
1996
|
+
return rootSession.debuggerSession.targetId;
|
|
1997
|
+
}
|
|
1998
|
+
if (typeof rootRecord?.attachTargetId === "string" && rootRecord.attachTargetId.length > 0) {
|
|
1999
|
+
return rootRecord.attachTargetId;
|
|
2000
|
+
}
|
|
2001
|
+
return null;
|
|
2002
|
+
}
|
|
2003
|
+
async recoverFromStaleTab(debuggee, preserveTab) {
|
|
2004
|
+
const staleTabId = typeof debuggee.tabId === "number"
|
|
2005
|
+
? debuggee.tabId
|
|
2006
|
+
: (typeof debuggee.targetId === "string" ? this.rootTargetTabIds.get(debuggee.targetId) ?? null : null);
|
|
568
2007
|
if (staleTabId === null) {
|
|
569
2008
|
return null;
|
|
570
2009
|
}
|
|
571
|
-
this.debuggees.delete(staleTabId);
|
|
572
|
-
this.detachTabState(staleTabId);
|
|
573
|
-
await this.safeDetach({ tabId: staleTabId });
|
|
574
2010
|
try {
|
|
575
|
-
await this.
|
|
2011
|
+
await this.reattachRootDebuggee(staleTabId, !preserveTab);
|
|
576
2012
|
}
|
|
577
2013
|
catch {
|
|
578
2014
|
return null;
|
|
579
2015
|
}
|
|
580
|
-
return
|
|
2016
|
+
return preserveTab
|
|
2017
|
+
? this.debuggees.get(staleTabId) ?? null
|
|
2018
|
+
: this.debuggees.get(staleTabId) ?? this.getPrimaryDebuggee();
|
|
581
2019
|
}
|
|
582
2020
|
isStaleTabError(error) {
|
|
583
2021
|
const message = error instanceof Error ? error.message : String(error);
|
|
584
|
-
return message.includes(
|
|
2022
|
+
return STALE_TAB_ERROR_MARKERS.some((marker) => message.includes(marker));
|
|
2023
|
+
}
|
|
2024
|
+
markExpectedRootDetach(tabId) {
|
|
2025
|
+
this.expectedRootDetachDeadlines.set(tabId, Date.now() + 1000);
|
|
2026
|
+
}
|
|
2027
|
+
consumeExpectedRootDetach(source) {
|
|
2028
|
+
const tabId = this.resolveSourceTabId(source);
|
|
2029
|
+
if (tabId === null) {
|
|
2030
|
+
return false;
|
|
2031
|
+
}
|
|
2032
|
+
const deadline = this.expectedRootDetachDeadlines.get(tabId);
|
|
2033
|
+
if (typeof deadline !== "number") {
|
|
2034
|
+
return false;
|
|
2035
|
+
}
|
|
2036
|
+
const sourceSessionId = source.sessionId;
|
|
2037
|
+
if (typeof sourceSessionId === "string") {
|
|
2038
|
+
return false;
|
|
2039
|
+
}
|
|
2040
|
+
this.expectedRootDetachDeadlines.delete(tabId);
|
|
2041
|
+
return deadline >= Date.now();
|
|
2042
|
+
}
|
|
2043
|
+
toChromeDebuggee(debuggee) {
|
|
2044
|
+
if (typeof debuggee.sessionId === "string") {
|
|
2045
|
+
if (typeof debuggee.targetId === "string" && debuggee.targetId.length > 0) {
|
|
2046
|
+
return { targetId: debuggee.targetId, sessionId: debuggee.sessionId };
|
|
2047
|
+
}
|
|
2048
|
+
return { tabId: debuggee.tabId, sessionId: debuggee.sessionId };
|
|
2049
|
+
}
|
|
2050
|
+
if (debuggee.attachBy === "targetId" && typeof debuggee.targetId === "string" && debuggee.targetId.length > 0) {
|
|
2051
|
+
return { targetId: debuggee.targetId };
|
|
2052
|
+
}
|
|
2053
|
+
if (typeof debuggee.tabId === "number") {
|
|
2054
|
+
return { tabId: debuggee.tabId };
|
|
2055
|
+
}
|
|
2056
|
+
return { targetId: debuggee.targetId };
|
|
585
2057
|
}
|
|
586
2058
|
async runDebuggerAction(action) {
|
|
587
2059
|
return new Promise((resolve, reject) => {
|
|
@@ -598,7 +2070,7 @@ export class CDPRouter {
|
|
|
598
2070
|
async safeDetach(debuggee) {
|
|
599
2071
|
try {
|
|
600
2072
|
await this.runDebuggerAction((done) => {
|
|
601
|
-
chrome.debugger.detach(debuggee, done);
|
|
2073
|
+
chrome.debugger.detach(this.toChromeDebuggee(debuggee), done);
|
|
602
2074
|
});
|
|
603
2075
|
}
|
|
604
2076
|
catch (error) {
|
|
@@ -615,10 +2087,14 @@ export class CDPRouter {
|
|
|
615
2087
|
return;
|
|
616
2088
|
this.callbacks.onResponse({ id, error: { message }, ...(sessionId ? { sessionId } : {}) });
|
|
617
2089
|
}
|
|
618
|
-
emitEvent(method, params, sessionId) {
|
|
2090
|
+
emitEvent(tabId, method, params, sessionId) {
|
|
2091
|
+
const event = { tabId, method, ...(typeof params !== "undefined" ? { params } : {}), ...(sessionId ? { sessionId } : {}) };
|
|
2092
|
+
for (const listener of this.eventListeners) {
|
|
2093
|
+
listener(event);
|
|
2094
|
+
}
|
|
619
2095
|
if (!this.callbacks)
|
|
620
2096
|
return;
|
|
621
|
-
const payload = { method, params };
|
|
2097
|
+
const payload = { method, ...(typeof params !== "undefined" ? { params } : {}) };
|
|
622
2098
|
if (sessionId) {
|
|
623
2099
|
payload.sessionId = sessionId;
|
|
624
2100
|
}
|
|
@@ -628,6 +2104,17 @@ export class CDPRouter {
|
|
|
628
2104
|
const isTargetInfo = (value) => {
|
|
629
2105
|
return isRecord(value) && typeof value.targetId === "string" && typeof value.type === "string";
|
|
630
2106
|
};
|
|
2107
|
+
const parseTabTargetAlias = (targetId) => {
|
|
2108
|
+
if (typeof targetId !== "string") {
|
|
2109
|
+
return null;
|
|
2110
|
+
}
|
|
2111
|
+
const match = /^tab-(\d+)$/.exec(targetId);
|
|
2112
|
+
if (!match) {
|
|
2113
|
+
return null;
|
|
2114
|
+
}
|
|
2115
|
+
const parsed = Number.parseInt(match[1] ?? "", 10);
|
|
2116
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
2117
|
+
};
|
|
631
2118
|
const getErrorMessage = (error) => {
|
|
632
2119
|
if (error instanceof Error) {
|
|
633
2120
|
return error.message;
|
|
@@ -637,3 +2124,20 @@ const getErrorMessage = (error) => {
|
|
|
637
2124
|
const isRecord = (value) => {
|
|
638
2125
|
return typeof value === "object" && value !== null;
|
|
639
2126
|
};
|
|
2127
|
+
const readRootFrame = (value) => {
|
|
2128
|
+
if (!isRecord(value)) {
|
|
2129
|
+
return null;
|
|
2130
|
+
}
|
|
2131
|
+
const frameTree = value.frameTree;
|
|
2132
|
+
if (!isRecord(frameTree)) {
|
|
2133
|
+
return null;
|
|
2134
|
+
}
|
|
2135
|
+
const frame = frameTree.frame;
|
|
2136
|
+
if (!isRecord(frame) || typeof frame.id !== "string") {
|
|
2137
|
+
return null;
|
|
2138
|
+
}
|
|
2139
|
+
return {
|
|
2140
|
+
id: frame.id,
|
|
2141
|
+
...(typeof frame.url === "string" ? { url: frame.url } : {})
|
|
2142
|
+
};
|
|
2143
|
+
};
|