Skip to content

fix(cdp): Hermes browser integration — driver quirks, global target registry, cross-connection routing, page persistence - #634

Open
fepfitra wants to merge 4 commits into
h4ckf0r0day:mainfrom
fepfitra:fix/cross-connection-sessions
Open

fix(cdp): Hermes browser integration — driver quirks, global target registry, cross-connection routing, page persistence#634
fepfitra wants to merge 4 commits into
h4ckf0r0day:mainfrom
fepfitra:fix/cross-connection-sessions

Conversation

@fepfitra

@fepfitra fepfitra commented Aug 11, 2026

Copy link
Copy Markdown

Hermes browser integration fixes

Four stacked fixes making obscura-cdp fully drivable by clients that spawn a fresh CDP connection per call (Hermes/agent-browser model):

  1. Driver quirks (9448c82) — getTargets, getBoxModel ints, insertText compat for the Hermes agent-browser driver.
  2. Global target registry (25fa3bf) — targets visible & attachable across connections.
  3. Cross-connection session routing (a48d861) — remote targets drivable from any connection via RemoteExec while the owning connection lives; fixes "No page for session".
  4. Page persistence across disconnect (dd8d33e) — pages created by a connection survive that connection closing. Target stays in the global registry, listed in /json/list, drivable from a later connection. Orphaned pages freeze (pump disarmed) — no Concurrent CDP navigations still abort with the #19 V8 fatal (heap->isolate() == TryGetCurrent()) at concurrency 2: v8_lock released across network-op .await points #430 thread-confinement violation. Page torn down only via Target.closeTarget (browser-global) or process shutdown.

Verification

  • cargo nextest obscura-cdp suite green (incl. new tests: orphaned_connection_keeps_pages_until_closed, remote_close_target_routes_to_owning_connection)
  • E2E reconnect test: create page on conn1 → close conn1 → /json/list still lists it → conn2 attach + Runtime.evaluate returns the page URL → closeTarget tears down
  • Live on ebot: full Hermes browser flow (navigate → eval → navigate → click → login → submit → screenshot) works natively with no target churn

Do not merge until review.

fitrafep and others added 3 commits August 10, 2026 06:58
…insertText)

- Target.getTargets now lists page targets on fresh browser connections
  (issue h4ckf0r0day#543): NewConnection creates a page + session mirroring the
  interception path, so puppeteer/playwright-style clients see pages
  before any createTarget call.
- DOM.getBoxModel rounds all quad and width/height coordinates to
  integers per the CDP spec; clients deserializing as i64 (Hermes)
  no longer fail with "floating point, expected i64".
- Input.insertText implemented via the existing prototype-setter JS
  path (trusted input event), so React/Vue controlled inputs register
  typed text.

Tests: get_box_model_returns_integer_coordinates,
insert_text_types_into_focused_input,
fresh_connection_sees_page_targets_in_get_targets. 81 tests pass.
…s connections (h4ckf0r0day#570)

Per-connection target lookup made Target.getTargets list only pages owned
by the caller, so a page created on one connection was invisible to others
and attachToTarget failed with "Target not found" (Hermes repro). Pages are
thread-confined (thread-per-connection h4ckf0r0day#430) so their V8 isolates cannot be
shared; instead mirror their metadata in a process-wide registry.

- registry.rs: TargetRegistry — global page-id counter, upsert/remove/all
- createPage/createTarget register the page; Drop unregisters a dead
  connection's pages; navigation syncs url/title into the registry
- getTargets returns every live target with attached=false for remote ones
- attachToTarget/closeTarget resolve through the registry (browser-global,
  matching Chrome), sessions stay connection-local
- /json/list mirrors the registry instead of a hardcoded about:blank page
…from any connection

Attaching to a registry-listed target owned by ANOTHER connection created a
session that resolved to no page: get_session_page only searched the
caller-owned pages, so every domain call (Page.navigate, Runtime.evaluate,
DOM.*) failed with "No page for session". Pages stay thread-confined
(thread-per-connection h4ckf0r0day#430; V8 isolates not shareable), so routing must
bridge connections instead of moving pages.

- registry: tombstone closed/removed targets so they stay closed even
  though the owner re-syncs; bound tombstone set (MAX_TOMBSTONES)
- target: closeTarget resolves browser-globally via registry; discovery/
  auto-attach emit for remote targets; browser-target attach returns a
  real session
- server: cross-connection command routing — a session targeting a remote
  page is dispatched through the owning connection's processor and the
  result returned to the caller; drop pages with the owning connection
  activity instead of living for the whole connection
- dispatch: session lookup falls through to the cross-connection path

Validated: 164/164 obscura-cdp tests, E2E green with Puppeteer AND
Playwright, Hermes browser_navigate live against this build.
@fepfitra

Copy link
Copy Markdown
Author

Verified live: Hermes browser_navigate now works against this build (was the exact repro — No page for session). 164/164 obscura-cdp tests, E2E green with both Puppeteer and Playwright.

This PR stacks on #597 (registry) which stacks on #595 (driver quirks). Merge order: #595#597#634. All three are currently mergeable/clean; merging in order makes each subsequent one apply cleanly to main.

Cross-connection routing is the final piece of the Hermes CDP integration: any connection can now drive any registry-listed target (Page.navigate, Runtime.evaluate, DOM.*), matching Chrome semantics, while pages stay thread-confined (#430).

@fepfitra fepfitra changed the title fix(cdp): cross-connection session routing — remote targets drivable from any connection fix(cdp): Hermes browser integration — driver quirks, global target registry, cross-connection routing Aug 11, 2026
Pages created by a connection now survive that connection closing. The
target stays in the global registry, remains listed in /json/list, and is
drivable from a later connection via attachToTarget + Runtime.evaluate
(RemoteExec routing). Orphaned pages freeze (autonomous pump disarmed) so
execution stays on the owning thread — no h4ckf0r0day#430 violation. The page is
torn down only via Target.closeTarget (browser-global) or process shutdown.

Fixes the Hermes-per-call-CDP-connection model where every tool call
spawns a fresh connection; previously the page died with the connection
that created it.
@fepfitra fepfitra changed the title fix(cdp): Hermes browser integration — driver quirks, global target registry, cross-connection routing fix(cdp): Hermes browser integration — driver quirks, global target registry, cross-connection routing, page persistence Aug 11, 2026
@SGavrl SGavrl closed this Aug 14, 2026
@SGavrl SGavrl reopened this Aug 14, 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.

2 participants