When writing a value, we used to store js.Value.Global in the transaction's
queue and then serialize it at write-time. We're supposed to capture the value
at call-time. The result is that, if JS code alters the value, we can end up
storing the wrong value. We now serialize the value at call time, so that any
subsequent changes to the value are not captured by the operation.
Also improve how we map large integers. Because JavaScript can't represent the
full u64/i64, we need to treat large numbers as floats and truncate. This is
done both from JS -> Zig and from Zig -> JS.
https://github.com/lightpanda-io/browser/issues/3348
When set to 1.1, libcurl is configured to only offer HTTP 1.1. By default, or
when set to "auto", it's up to libcurl to decide how to connect. This maps to
libcurl's CURL_HTTP_VERSION_1_1 and CURL_HTTP_VERSION_NONE.
LP.configureCDP now takes an `httpVersion` field which can be "1.1" or "auto"
to control that specific browser session. Ideally this is called prior to any
navigation.
MediaError.init had no caller and MediaError has no JS constructor
exposed (new MediaError() is not valid JS), so the helper was
unreachable dead code. It also had a latent bug: it passed a struct
VALUE to std.mem.Allocator.create, which expects a TYPE. That bug
never surfaced because Zig lazily skips analyzing unreferenced
function bodies.
Remove init per maintainer review, along with its now-unused Frame
import. HTMLMediaElement.error still returns null today, so this
does not change runtime behavior.
Verified: zig fmt --check clean, scoped build+test green (1 of 1,
the remaining constants test).
resolveTargetFrame returned null for _blank, so every caller carried the
meaning of that null. It now returns a tagged union and callsites switch
on it. <form target=_blank> takes the same path as links: the popup is
opened only once the submission is going ahead, so validation or
preventDefault can't leave a stray window. The opener rule (withheld
unless rel=opener) lives in one Frame.openBlankTarget helper.
awaitQueuedNavigation took a frame id, but Runner waits are keyed by
Page root, so a followed popup's id resolved to FrameNotFound and every
navigation from inside a popup failed. It now takes the Frame and waits
on its Page root, read before processing since a synthetic root
navigation frees the Page in place.
Meant to improve https://github.com/lightpanda-io/browser/issues/3251
There's a script on taobao and tmall which tries to tile the visible porition
or the root element. Well, the root element's fake height is 100,000,000 so the
page stalls.
This changes is so that the body's clientHeight/Width returns the viewport
dimensions.
actions.click() previously dispatched a single untrusted-shaped "click"
MouseEvent directly on the target node, skipping pointerdown, mousedown,
pointerup, and mouseup entirely. Many real-world widgets — custom
autocomplete/combobox components in particular — open or otherwise react
on mousedown, not click alone, so this made them unreachable through the
click tool even though the element was correctly focused and targeted.
WebDriver.zig's own click() already implements the correct sequence
(pointerdown, mousedown, pointerup, mouseup, click) for testdriver's
click, with a comment explicitly contrasting it against a lone untrusted
click event. This change ports that same sequence into actions.click()
so the MCP/CDP "click" action produces the same event sequence a real
user click would.
Adds a mousedown assertion to the existing MCP Actions test
(mcp_actions.html + tools.zig) to catch a regression here; confirmed the
new assertion fails against the old implementation and passes against
this one. Full test suite (1339 tests) and zig fmt --check both pass.
Reproduced against a real, previously-untested production site
(a Wix-built autocomplete branch-selector widget) where click could
focus the input but never open its option list; a minimal local
reproduction (a mousedown-only widget) confirms the fix.
ReadableStream's assumed collectBodyBytes was being called on the same context
that it was created, so that in a cross-context call, the expected LocalScope
was null. This creates an explicit local scope.
Fixes crash on WPT /service-workers/service-worker/fetch-event.https.h2.html
Commented it out for now, but plan on remove the code at some point in the
future. This was useful when sites would break because of an unimplemented
API, but (a) those are rare now and (b) AI is good at finding issues without
this. As-is, it just makes --log-level debug useless in Debug builds. The
logging could never tell between an site-specific global and a real API, and
sites have _a lot_ of globals, so it's a lot of noise.
https://github.com/lightpanda-io/browser/pull/3320 made Mime.zig aware of
`application/octet-stream`, but Mime is still lossy, e.g.
"text/html; charset=utf-8" -> "text/html".
This commit dupes the response's content-type in the XHR's arena and use that
value as-is.
.unknown can map to either an Svg.Unknown or Html.Unknown. The dump was assuming
HTML when doing a void-tag check, but we can skip the entire issue here since
only HTML has void tags.
Emulation.setLocaleOverride, setTimezoneOverride, setScriptExecutionDisabled,
setDefaultBackgroundColorOverride, Page.setBypassCSP, bringToFront,
setInterceptFileChooserDialog, Network.emulateNetworkConditions and
setBypassServiceWorker returned UnknownMethod. The ones that already hold
(no CSP, one page, no service workers, no file chooser, no background)
are plain no-ops; locale and timezone are accepted with a warning;
disabling script execution and offline emulation return a clear error.
The bare orelse gave text-content names to roled elements the AX tree
leaves unnamed (select, textarea, details). Scope the fallback to
listener/tabindex-only elements, where AccName gives nothing and the
text is the agent's only handle.
padding, border and margin were zeroed. Playwright reads `border` for
boundingBox(), so every element reported {0,0,0,0}. Without padding,
border or margin in the layout, the four boxes coincide with content.
Children of a `display: flex`/`grid` container are separate boxes however
inline their tags are, so `Title<b>Aug 04 2026</b>` inside a flex `<a>` ran
together as `Title**Aug 04 2026**`. StyleManager now keeps the display kind
(none/flex/grid/other) instead of a display:none bool, and the dumper puts a
space between the rendered items of such a container, skipping the
whitespace between them like layout does.
Every data command went through printAssistant, so /markdown was styled by
accident while /tree, /getUrl and /evaluate strings had `*`/`_` eaten as
emphasis, and /markdown lost table alignment past Stream's 16 KiB buffer.
- printData renders only markdown as markdown; JSON is re-indented and the
rest prints verbatim.
- render iterates the source directly and aligns tables from the slice;
Fence holds the fence state shared with Stream.
- Links are OSC 8 hyperlinks around the label only, with the label
inline-rendered; `` drops the `!`; escapes follow CommonMark
so what the page dumper escapes is unescaped.
Clicking a target=_blank link was logged and dropped. It now opens a
popup Frame, the same top-level context window.open creates; the opener
is withheld unless rel=opener, per spec.
A popup is invisible to the tool layer, which acts on the root frame, so
finalizeAction snapshots the popup count before the action and, when one
appears, waits for it to load and makes it the session's current frame.
The action result says so. Once the popup is gone, tools fall back to
the root.
The whitelist rejected methods the V8 inspector already implements,
notably releaseObjectGroup, which Puppeteer sends on handle disposal.
Bookkeeping methods that cannot observe or change the page's global
skip the main_world_touched mark.
Unknown domains and methods returned our private -31998 with the Zig
error name. Drivers feature-detect on Chrome's -32601 "'X' wasn't
found", so return that; other dispatch errors keep -31998.