Skip to content

Add AutoSessionRouter which takes care of all CDP command routing + Mod.getTopology to expose unified Session+Target+Frame+DomRoot+ExecutionContext tree that it uses to route#8

Open
pirate wants to merge 1 commit into
split/server-upstream-transportfrom
split/mod-topology-router
Open

Add AutoSessionRouter which takes care of all CDP command routing + Mod.getTopology to expose unified Session+Target+Frame+DomRoot+ExecutionContext tree that it uses to route#8
pirate wants to merge 1 commit into
split/server-upstream-transportfrom
split/mod-topology-router

Conversation

@pirate
Copy link
Copy Markdown
Member

@pirate pirate commented May 26, 2026

Summary

CDP clients repeatedly have to keep several browser-owned identifiers in sync before they can send a command to the right place:

  • targetId: the browser target for a page, iframe/OOPIF, worker, or extension context.
  • sessionId: the flattened CDP session id used by loopback CDP after Target.attachToTarget. In chrome.debugger mode the parent page route is sessionless, while child sessions from Target.attachedToTarget are still observed and mapped when Chrome emits them.
  • frameId: the Page domain frame id. Same-process frames share their target; OOPIFs appear as iframe targets and have to be stitched back into the frame tree through parentFrameId.
  • executionContextId: the Runtime context id used for evaluation. It is only meaningful inside its target/session route and changes on navigation or context teardown. The router records the native id, optional uniqueId, owning targetId, optional sessionId, frameId, and semantic world (main, piercer, or isolated-world name).
  • backendNodeId: the DOM boundary ids needed to cross document, iframe, and shadow-root boundaries. The topology exposes only the boundary ids that matter: frame owner <iframe> ids, document <html> ids, shadow host ids, and shadow-root ids.
  • objectId: live Runtime remote-object handles for document and shadow roots. These are returned as the keys of topology.roots and are scoped to the returned objectGroup, so callers can use them immediately with Runtime/DOM commands and release the group when done.

This PR adds an AutoSessionRouter layer that owns the generic routing state and uses it consistently for server-side CDP dispatch. The router subscribes to typed upstream CDP events (Target.*, Runtime.*, and Page.*) from the selected ServerUpstreamTransport, records target/session/context mappings as they change, invalidates context records on navigation, frame detach, context clear/destroy, target detach, and target destroy, and routes standard CDP commands through the active upstream without leaking loopback-vs-chrome.debugger logic into callers.

The PR also adds Mod.getTopology, which exposes the router's current view plus a fresh topology build in one command. It starts from the selected root page target, enables Page/DOM/Runtime/flattened auto-attach for each relevant target, walks same-process frame trees and OOPIF iframe targets, resolves frame owner backend node ids, creates or reuses a dedicated __modcdp_piercer__ isolated world for each frame, resolves each document root, and walks DOM.getDocument({ depth: -1, pierce: true }) to include open and closed shadow roots. Topology work runs through a small breadth-style queue with up to 8 concurrent frame/target tasks so pages with many frames do not require serial per-frame traversal.

Mod.getTopology returns flat id-keyed maps:

  • rootFrameId: the root Page frame id for the chosen target.
  • frames: frameId -> { targetId, url, parentFrameId, outerBackendNodeId }.
  • targets: targetId -> TargetInfo + optional sessionId.
  • contexts: router context key -> Runtime execution context metadata, including route and world.
  • roots: Runtime objectId -> { kind: "document" | "shadow", frameId, outerBackendNodeId, innerBackendNodeId, mode, executionContextId, uniqueContextId }.
  • objectGroup: the Runtime object group used for the returned root handles.

This keeps ModCDP generic. It does not add locator, XPath, DOM-summary, Stagehand, or Understudy logic to ModCDP. Higher layers can consume the topology to build cross-OOPIF DOM summaries, deep selectors that pierce closed shadow roots and frame boundaries, or other browser-graph-aware features without reimplementing target/session/context/frame traversal themselves.

Validation

  • pnpm exec tsc -p tsconfig.json --noEmit
  • pnpm run build
  • pnpm exec vitest run js/test/test.ServerUpstreamTransport.ts js/test/test.ModCDPClientRoutedDefaultOverrides.ts --fileParallelism=false --maxWorkers=1
  • pnpm exec prek run --all-files

@pirate pirate marked this pull request as ready for review May 26, 2026 17:49
@pirate pirate changed the title Add Mod topology routing Add Mod.getTopology to get unified Session+Target+Frame+DomRoot+ExecutionContext tree May 26, 2026
@pirate pirate changed the title Add Mod.getTopology to get unified Session+Target+Frame+DomRoot+ExecutionContext tree Add AutoSessionRouter which takes care of all CDP command routing + Mod.getTopology to expose unified Session+Target+Frame+DomRoot+ExecutionContext tree that it uses May 26, 2026
@pirate pirate changed the title Add AutoSessionRouter which takes care of all CDP command routing + Mod.getTopology to expose unified Session+Target+Frame+DomRoot+ExecutionContext tree that it uses Add AutoSessionRouter which takes care of all CDP command routing + Mod.getTopology to expose unified Session+Target+Frame+DomRoot+ExecutionContext tree that it uses to route May 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant