MCP mode unconditionally set log.opts.format = .logfmt after the
--log_format flag had already been applied, so `--log_format pretty`
was silently ignored. It also ran after the "starting server" line,
which came out in the pre-override format in debug builds.
Move it into Config.logFormat() as a mode-aware default, mirroring
what logLevel() does for agent mode: null -> logfmt for mcp, and an
explicit flag wins.
clientX/clientY, screenX/screenY, pageX/pageY, layerX/layerY and the x/y
aliases returned the MouseEventInit double verbatim, so a synthetic event
built with clientX: 47.5 read back 47.5. Chrome floors these getters on
MouseEvent and its non-pointer subclasses (DragEvent, WheelEvent) and
exposes fractional coordinates on PointerEvent only; page code and
automation tooling written against Chrome assume integer mouse
coordinates. The getters now floor unless the event's _type tag says
pointer_event, so the inherited PointerEvent accessors keep the
fractional double.
Closes#3258
Reading el.draggable returned undefined for every element, and assigning
it created a plain JS own property with no reflection onto the content
attribute. Implement the reflected property per the HTML spec: the
"true"/"false" keywords are matched ASCII case-insensitively, the auto
state defaults to true for <img> and for <a> with an href (matching
Chrome), and the setter writes the literal "true"/"false" onto the
content attribute.
Closes#3255
Depends on https://github.com/lightpanda-io/wpt/pull/77
Track click count so that we can correctly fire a double click. On click, if
the mousedown and mouseup targets differe, find the nearest common inclusive
ancestor. Our `dispatchMouse` now sets the correct buttons value.
Also, HTMLElement.click() should be a PointerEvent (not a MouseEvent)
Improves various /uievents/ WPT cases.
Mirror the zenai provider pattern: the enum's declaration order is the
single source of truth for the .auto cascade, asserted at comptime against
api_engines (auto first, one table entry per API engine in tag order,
duckduckgo last with no entry). The enum reorders brave before tavily to
match the table's actual preference — persisted settings are unaffected
(ZON stores tag names).
Each table entry now carries a .keyless field; the hardcoded keenable
keyless rung, searchEngineKeyless, and searchExplicit's comptime gate all
derive from it, engineIndex collapses to arithmetic, and apiSearch takes a
typed ?[]const u8 key instead of anytype.
- build.zig.zon points at lightpanda-io/zenai's merge commit of zenai#9
(same tree, so the hash is unchanged)
- the keyless rung is no longer skipped when KEENABLE_API_KEY is set:
the public endpoint has its own rate-limit regime, so it is worth
trying after a failed keyed attempt — which the search tool
description already promised
- keenable retries are disabled: the fallback cascade is the retry
mechanism, and honoring the public endpoint's 60s Retry-After would
stall the search tool short of the DDG rung
- stale SearchEngine/searchExplicit doc comments updated for keyless
`has` add support for optional value (matches name AND value)
`delete` preserve entry order
`sort` compares by UTF-16
`forEach` iterates by index since the callback can mutate the list
Minor improvement to a handful of WPT tests, e.g.
/url/urlsearchparams-delete.any.html (first of a handful of /url/ WPT
improvements)
zenai's review round made keyless explicit in the client's type
(init takes ?[]const u8; null selects the public endpoint) and removed
the always-empty description field from results:
- the .auto keyless rung and searchExplicit pass null instead of "";
the null-key call is comptime-gated to keyless-capable engines and
apiSearch's key parameter is anytype to admit both shapes
- a set-but-empty KEENABLE_API_KEY is now keyed and fails loudly
instead of silently switching to the keyless rate-limit regime
- formatKeenableMarkdown reads snippet only (description no longer
exists to fall back to)
- build.zig.zon repinned to the reviewed zenai commit
Adds keenable to the search tool's engines (KEENABLE_API_KEY, tried
after brave/tavily/exa in .auto). Unlike the other engines it also
answers without any key: its client routes an empty key to the public
endpoint (rate-limited per client IP), so .auto now tries that as the
last rung before the DuckDuckGo scrape, and an explicit
/searchEngine keenable works keyless instead of erroring. Engine table
entries gain init_options so the Keenable client can carry the
lightpanda attribution header.
Needs the zenai Keenable search client (lightpanda-io/zenai PR #9); the
zon pin points at that branch until it lands.
No clue why this happens, but if the error mattered, a test would fail. A lot
of tests can be "harsh" on the server (e.g. a frame that navigates its parent
away while some resource load), so a WriteFailed error isn't exactly surprising
FormData is now encoded based on the Page's encoding on form submission, or
UTF8 for a JS-created FormData. Newlines are also normalized as needed (sole
\r and \n become \r\n in most cases).
The value for a hidden _charset input is now set to the encoding of the FormData
(who knew this was a thing?).
Added a setter to File.input
findFramebyName ignores a disconnected frame.
Most of these were driven by the WPT /FileAPI/ category, but the changes impacts
a handful of cases throughout (e.g. various cases in /html/semantics/forms/ are
also improved).
HttpClient guarantees that only one of done/error/shtudown callback will be
called. But that guarantee had a hole when a done/error callback would trigger
JS that caused an HttpClient.abort (e.g. by scheduling a navigation).
So far, this isn't a problem. fetch/XHR guard against this themselves, and
ScriptManager doesn't care of it happens.
But https://github.com/lightpanda-io/browser/pull/3230 doesn't guard against it
and would crash if it happens: its doneCallback frees `self` but can re-enter
shutdown which needs `self`. While 3230 could fix this issue, I'd prefer to
bake this contract into the HttpClient. Transfers now have an
`_outcome_delivered: bool` which guarantees that only one of done/error/shutdown
is called.
Network is less cohesive than https://github.com/lightpanda-io/browser/pull/3242
would indicate. It has two distinct and _completely_ separate responsibilities.
1 - It acts as the base for each HttpClient, providing a shared connection pool
(for http and ws) and access to the process wide Cache, RobotStore,
WebBothAuth, certificates, ...
2 - It accepts, polls and reads from CDP connection
There is zero relationship between these, and it's a particularly bad place for
this duality to exist because both parts are, in their own way, the main
multi-threaded junction in the system.
This commit is purely mechanical it:
1 - Keeps network as the base for each HttpClient.
2 - Extract the CDP interaction into the existing Server.zig
3 - Gives mcp's HttpServer its own accept loop
Network has accumulated a bit of bagged. It knows a lot about certificates, it
knows a lot of the cache. I have plans to expand Network, and wanted to clean it
up.
1 - certificate logic moved to dedicated Certificates.zig
2 - Removed CurlDebugAllocator
- this makes setup easier, to Updater can just init libcurl directly
3 - Change Updater to be a single function
4 - Cache initialization is don in the Cache
5 - ?Cache => Cache{.kind = .noop}