release: v0.15.0 — Firefox/BiDi engine + incognito clean session#3
Merged
Conversation
CDP is deprecated in Firefox, so add a second transport beside cdp.js over
the same `ws` dependency — no geckodriver, no new dep. Selectable with
connect({ engine: 'firefox' }), BAREBROWSE_ENGINE=firefox (MCP), or
`open --engine firefox` (CLI).
New modules (each stands alone):
- bidi.js — BiDi JSON-RPC transport (session.new, script.evaluate, …)
- firefox.js — find/launch Firefox, parse BiDi banner, temp profile, reap
- ax-snapshot.js — reconstruct a CDP-vocabulary AX tree in-page (BiDi has no
getFullAXTree): implicit roles, accessible-name computation,
aria-hidden/visibility filtering, shadow-DOM + slot walk
- firefox-page.js — page object over BiDi: goto/snapshot/click/type/press/
scroll/hover/select/drag/upload/back/forward/reload/
screenshot/pdf/tabs/switchTab/waitFor/readable/injectCookies
Reuses prune.js/aria.js/readable.js unchanged; readable.js refactored to share
EXTRACT_EXPRESSION + finalizeReadable across transports. Navigation guard
(assertNavigable) enforced on the Firefox goto() for parity. Fidelity validated
against real CDP snapshots; iframes, shadow DOM, CSP, SPA timing covered in
test/integration/firefox.test.js (13 tests).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AtfjYZuaUhrB7ovuWC2GRD
incognito gates every auth source so the session loads logged-out:
storageState loading is skipped (CDP) and injectCookies() is a no-op on both
engines (connect page, createTab, and Firefox/BiDi page), so even callers that
inject unconditionally (MCP goto, daemon) get no auth. Exposed as
connect({ incognito }) / browse({ incognito }), CLI --incognito, MCP per-request
`incognito` on `browse` + BAREBROWSE_INCOGNITO=1 for the persistent session.
Parity + able-to-fail controls in test/integration/incognito.test.js (4 tests).
Also makes the Firefox/BiDi modules typecheck-clean under `tsc --noEmit`:
- ax-snapshot.js: // @ts-nocheck (browser-context code — document/CSS/regex
literals run in-page via .toString(), never in Node)
- bidi.js: @type {Promise<void>} hint on the connect promise
- firefox.js: guard possibly-undefined process.pid in cleanupFirefox
- firefox-page.js / index.js: JSDoc @param for uploadDir, incognito, engine
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AtfjYZuaUhrB7ovuWC2GRD
Firefox support over WebDriver BiDi (connect({ engine: 'firefox' }), CLI
--engine firefox, MCP BAREBROWSE_ENGINE=firefox) and an incognito clean,
unauthenticated session that gates all auth injection. Docs: CHANGELOG 0.15.0,
README Firefox section + requirements, integration guide engine/incognito opts.
Pre-release review pass (/ship + /security + /diff-review under /verify-done)
found and fixed, each validated first:
- HIGH: startDaemon never forwarded --incognito to the detached daemon child,
so `barebrowse open <url> --incognito` silently ran a fully-authenticated
session. Extracted pure buildDaemonArgs() (unit-tested) with the forward.
- HIGH: Firefox injectCookies loaded the entire cookie jar (ignored the URL),
vs the CDP path's host scoping. Extracted shared scopedCookiesForUrl() used
by both engines so they cannot drift; Firefox now scopes to the target host.
- Firefox iframe splice leaked another tab's frame into the active snapshot
after switchTab() to a non-first tab (POC-proven). Scoped allContexts() to
the active tab via getTree({ root }); nested-frame handling was already
correct. Regression tests added (nested + multi-tab).
- Firefox page stubs the 5 CDP-only methods the daemon dispatches: downloads/
dialogLog return [], saveState/waitForNavigation/waitForNetworkIdle throw a
clear "not supported on Firefox/BiDi" error instead of a silent TypeError.
Tests: 193 pass, 0 fail; typecheck clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MZpPPhwXmSfN1n7uX7RAxT
Medium /code-review of the v0.15.0 branch surfaced 5 correctness issues in the new Firefox/BiDi engine; all validated (POC + regression tests) and fixed: - goto()/reload()/traverseHistory() ignored their timeout — a page that never fires load hung the call forever. Added withTimeout() around the navigate commands (goto now rejects at its timeout; POC: ~2s vs never). - daemon `eval` over BiDi returned the raw serialized result.value, so object/ array evals came back malformed vs the CDP returnByValue shape. Wrapped in an in-page JSON.stringify + JSON.parse (undefined → null), matching readable(). - A collapsed native <select> expanded every <option> into the tree. It now surfaces as a single combobox with its current value; multi/size listboxes still list options. - Bare text directly under <body> was dropped (root walk used .children, not .childNodes). Now kept as StaticText, matching walk()/CDP. - Firefox proxy setup ignored the URL scheme and wired everything as an HTTP proxy; a socks:// proxy now configures network.proxy.socks + version. Regression tests added to test/integration/firefox.test.js (select collapse, bare body text, goto timeout). Full suite: 196 pass, 0 fail; typecheck clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MZpPPhwXmSfN1n7uX7RAxT
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
v0.15.0 — Firefox/BiDi engine + incognito clean session
Two features, released together after a full pre-merge review pass.
Firefox support via WebDriver BiDi (
connect({ engine: 'firefox' }))Second transport (
src/bidi.js) over the samewsdep — no geckodriver, no new package. AX tree reconstructed in-page (src/ax-snapshot.js) since BiDi has nogetFullAXTree.prune.js/aria.js/readable.jsreused verbatim. CLI--engine firefox, MCPBAREBROWSE_ENGINE=firefox.Incognito clean session (
incognito: true)Skips all auth injection (cookies +
storageState) for a logged-out session. Gate enforced at the page-object level, so it holds even when a caller injects unconditionally (MCPgoto, daemon). Onbrowse(),connect(), both engines, MCP (browsearg +BAREBROWSE_INCOGNITO=1), CLI (--incognito).Review pass — found + fixed (each validated first)
startDaemonnever forwarded--incognitoto the daemon child →open --incognitosilently authenticated. Fixed via pure, unit-testedbuildDaemonArgs().injectCookiesloaded the whole cookie jar (ignored the URL). Fixed via sharedscopedCookiesForUrl()used by both engines so they can't drift.switchTab()(POC-proven). Fixed by scopingallContexts()to the active tab (getTree({ root })). Nested-frame handling was already correct. Regression tests added.TypeErrors.Verification
npm test— 193 pass, 0 failnpm run typecheck— clean/ship+/security+/diff-reviewgates run under/verify-doneKnown gaps (Firefox engine, documented)
Consent auto-dismiss, ad-block, stealth,
hybridmode,reload({ignoreCache}), console/network capture,saveState/waitForNavigation/waitForNetworkIdleare Chromium-only.🤖 Generated with Claude Code
https://claude.ai/code/session_01MZpPPhwXmSfN1n7uX7RAxT