Commit Graph
7136 Commits
Author SHA1 Message Date
Ilya Bogin 56e5daed54 search: track zenai review changes for the keenable engine
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
2026-08-24 10:44:38 +03:00
Ilya Bogin 6cbe30b088 search: add Keenable engine with a keyless rung above the DDG scrape
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.
2026-08-23 15:42:06 +03:00
Karl Seguin 318ba730b5 webapi: FormData encoding
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).
2026-08-22 14:28:02 +08:00
Karl Seguin 23528f0cc4 Merge pull request #3246 from lightpanda-io/better-poll
chore: Remove Server component from Network
2026-08-22 11:15:11 +08:00
Karl Seguin 2d32e78838 chore: Remove Server component from Network
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
2026-08-22 10:11:30 +08:00
Karl Seguin 3e4b02a258 Merge pull request #3247 from lightpanda-io/canvas-png
add canvas toDataURL and toBlob returning 1x1 png
2026-08-22 10:01:43 +08:00
Karl Seguin 46d53792b8 chore: Network cleanup
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}
2026-08-22 09:21:18 +08:00
Karl Seguin a13c5fbc7b Apply same blank png logic to OffscreenCanvas
Move all of the blank png logic to OffscreenCanvas and apply it to the existing
convertToBlob. I agree it doesn't really make that much sense here, but Canvas
already references OffscreenCanvas, so given its current usage, it's the most
ergonomic place to put it.

Canvas's ToBlobCallback now runs microtask after executing the callback and
lazily creates the Blob for simpler blob lifecycle.
2026-08-22 09:14:41 +08:00
Karl Seguin e01baa1139 Merge pull request #3242 from lightpanda-io/network-cleanup
chore: Network cleanup
2026-08-22 08:21:27 +08:00
Karl Seguin 1b305cdec0 Merge pull request #3225 from lightpanda-io/agent-exa
browser: add exa search engine support
2026-08-22 07:06:27 +08:00
Karl Seguin 57bcdfed10 chore: Simplify Network and HttpClient init
Remove app field from Network
2026-08-22 07:05:05 +08:00
Karl Seguin decedca6e7 chore: Network cleanup
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}
2026-08-22 07:04:58 +08:00
Karl Seguin 9f4b39d723 Merge pull request #3239 from lightpanda-io/ratelimiter
http: Add optional rate limit
2026-08-22 06:58:52 +08:00
Pierre Tachoire 342eaf1036 add canvas toDataURL and toBlob returning 1x1 png 2026-08-21 19:53:42 +02:00
Pierre Tachoire d6d6248f34 Merge pull request #3244 from lightpanda-io/media-query-device
add device-width / device-height media features
2026-08-21 17:34:05 +02:00
Pierre Tachoire bc5289778a add device-width / device-height media features
matchMedia("(min-device-width: …)") always returned false, so scripts
scanning for the first matching bound never terminated.

device-* resolves against the viewport, like window.screen.width/height.
2026-08-21 16:07:23 +02:00
Halil Durak cfe885c319 Geolocation: order PositionOptions fields lexicographically 2026-08-21 15:17:03 +03:00
Karl Seguin be101e188c Merge pull request #3238 from lightpanda-io/fileapi-blob-spec
webapi: Blob / File conformance
2026-08-21 18:49:05 +08:00
Karl Seguin 467e372fd8 Merge pull request #3237 from lightpanda-io/domparser-realm
webapi: DOMParser capture owning frame for correct URL
2026-08-21 18:48:32 +08:00
Karl Seguin c80b3f1e03 Merge pull request #3241 from lightpanda-io/arena_leak
mem: Cleanup arena leak on page shutdown with live animations
2026-08-21 18:25:40 +08:00
Karl Seguin accb34eaa4 Merge pull request #3233 from rohitsux/feat/geolocation-emulation
feat: navigator.geolocation + Emulation.setGeolocationOverride
2026-08-21 14:47:38 +08:00
Karl Seguin ede211e5a0 WebApi: Improve Geolocation API
Add missing toJSON, use Arena + Finalizers for delivery / GeolocationPosition
and coordinates. Return permission denied if permission isn't set, regardless of
override. Split structs into their own files.
2026-08-21 11:24:01 +08:00
Karl Seguin 1adc8a3b70 mem: Cleanup arena leak on page shutdown with live animations 2026-08-21 09:30:28 +08:00
Karl Seguin 4a001f932c Merge pull request #3229 from lightpanda-io/element-left-position
webapi: improve "rendering" of an element's left position
2026-08-21 07:31:11 +08:00
Karl Seguin 09edfd3ce5 http: Add optional rate limit
Add an optional per-host rate limit. This currently only applies to the top-
level navigation. This makes it simpler to implement and simpler to reason
about. The full load of a page is only ever delayed at its head, not
sporadically through the page loading.

The use-case where a RateLimiter is most useful is when the browser is crawling
multiple pages of the same site, and in that case, the top-level rate limit
still applies some degree of limit to any linked resources (e.g. a JS on a
different host).

`--http-nav-delay` is the delay, in milliseconds, to apply to top level
navigates per host. Currently defaults to 0 (disabled).

`--http-nav-burst` is the burst allowed per host. Defaults to 1 (has no impact
when `--http-nav-delay` is disabled).
2026-08-20 16:03:42 +08:00
Karl Seguin b70f7a325e webapi: Blob / File conformance
1-
Per spec, dictionary objects should be loaded in lexicographical order (a). So
the following always pushes `endings` before `type`

```js
  new Blob([], {
    get type()    { order.push('type'); return ''; },
    get endings() { order.push('endings'); return 'transparent'; },
  });
```

This requirement is now enforced by a comptime check. So, a lot of files were
updated to satisfy this requirement.

2-
Blob parts now work with the @@iterator protocol. This is done more generically
(via `value.iterator())` but is currently only used by Blob (and File). Other
types that need this (e.g. URLSearchParams) can be done in a follow up.

3-
Add support for Blob.textStream

4-
Reject XHR/Fetch requests on blob URLs if the method isn't GET

5-
Strip #hash from blob URL when doing lookup

All of this fixes ~175 FileAPI WPT cases, though it's possible #1 (the
dictionary ordering) helps with a few others.

(a) https://webidl.spec.whatwg.org/#js-dictionary
2026-08-20 13:57:51 +08:00
Karl Seguin 28c5778fde webapi: DOMParser capture owning frame for correct URL
The URL assigned to a document parsed via DOMParser should come from the Frame
which created the DOMParser.
2026-08-20 12:39:16 +08:00
Rohit 3901858977 fix(cdp): advertise geolocation override methods in protocol + test denied path 2026-08-19 20:50:05 +05:30
Rohit a67bfbb74d feat(webapi): resolve navigator.geolocation from the emulation override 2026-08-19 20:33:02 +05:30
Rohit 0e875e2b03 feat(webapi): add navigator.geolocation with async error delivery
Adds the Geolocation and GeolocationPositionError interfaces plus a
navigator.geolocation accessor. getCurrentPosition schedules delivery
on the frame's js.Scheduler so callbacks always fire off the calling
stack, and covers the no-override path where no
Browser.geolocation_override is set: the error callback receives a
GeolocationPositionError with code POSITION_UNAVAILABLE (2), or
PERMISSION_DENIED (1) if the geolocation permission was denied via
CDP. Reading an override into a successful GeolocationPosition and
watchPosition/clearWatch are left for later work.
2026-08-19 20:16:21 +05:30
Adrià Arrufat 9a57a34b46 tools: cap exa search highlights to 3 sentences 2026-08-19 16:42:43 +02:00
Rohit 56ef7b95ee feat(cdp): store Emulation.setGeolocationOverride on the browser 2026-08-19 19:53:16 +05:30
Karl Seguin d40f68ba56 webapi: improve "rendering" of an element's left position
1. The horizontal position of an element is now calculated based on the
horizontal position of it's siblings (up the tree). Rather than merely the
count * default width.

2. translateX is parsed on inline styles and applies to the horizontal position

1 & 2 fix the https://lseo.com/ issue, but they add overhead to APIs that can be
used a lot. So:

3. Most element dimensions api relied on getElementDimensions which calculated
   both the height and width dimensions, even though they only needed once
   (e.g. getClientHeight only needs the height). These methods now only get
   the axis that they care about

4. Because we do more style sheet lookups, and thus more lookups in
   Frame._element_styles, Element.flags now has an has_inline_style which
   helps avoid the lookup.
2026-08-19 18:28:28 +08:00
Karl Seguin 46de01944e Merge pull request #3228 from lightpanda-io/js-promise-reject-bad-receiver
webapi: promise-returning operations reject, don't throw, on bad receiver
2026-08-19 15:38:14 +08:00
Karl Seguin 6f53c42df9 Merge pull request #3227 from lightpanda-io/xml-parse-fidelity
webapi: xml parsing reject documetns that are not well formed
2026-08-19 15:38:03 +08:00
Karl Seguin 9c609d056d Merge pull request #3218 from pasmud/gaz/lightpanda-io-browser-aboutblank-global
fix: replace bootstrap about:blank global on first navigation (#3215)
2026-08-19 13:24:30 +08:00
Karl Seguin 5f96fc1c3c Add condition to full page reload on about:blank from CDP
The unconditional full load incurs a performance hit in the common case where
the about:blank is safe to use. This commit restores the fast-path only when
(a) the page is waiting for its initial navigate (same as before) and (b)
no Runtime.* methods were executed (i.e. no driver-driven JS was executed on
about:blank)
2026-08-19 12:48:21 +08:00
Karl Seguin 289620fbf8 webapi: promise-returning operations reject, don't throw, on bad receiver
We currently implement a v8 signature check on the receiver. This throws on
failure. However, for a promise-returning function, it should reject the
promise instead. This skips the (v8) signature check for promise-returning so
that it flows through the normal code which does rejection.

Fixes a few WPT cases (in fetch and FileAPI, but probably others too).

This reject, don't throw, is an ongoing thing that we're fixing, e.g.
https://github.com/lightpanda-io/browser/pull/3095
2026-08-19 12:00:14 +08:00
Karl Seguin 25aa46a6ca webapi: xml parsing reject documetns that are not well formed
Hooks into the xml5ever parse_error callback to capture parse errors and reject
malformed XML. Because of this stricter error handling, we need to do some
input pre-processing for edge cases (thank you WPT). We need to strip out
<!DOCTYPE svg [ <!ENTITY ...> ]> which comes form Illustrator SVG export since
that now causes errors (but should be ignored).

Finally, by default xml5ever closes any opened tags at the end of the stream.
Per WPT, these should be invalid.

The rust work was all Claude-driven.
2026-08-19 08:52:15 +08:00
Karl Seguin 1ed8d4a35d trim comments 2026-08-19 08:25:57 +08:00
Karl Seguin f2b4043171 Merge pull request #3222 from lightpanda-io/style-attr-resync
webapi: Re-parse element.style when style attribute changes
2026-08-19 07:45:36 +08:00
Karl Seguin 4b06c248e7 use element.ownerFrame to access StyleManager 2026-08-19 07:33:38 +08:00
Karl Seguin 20293bca9d Merge pull request #3220 from lightpanda-io/fileapi-filereader-async
webapi: make FileReader asynchronously + proper text decoding
2026-08-19 06:55:13 +08:00
Adrià Arrufat d76ead300a browser: add exa search engine support 2026-08-18 21:10:45 +02:00
Pierre Tachoire 067709bb58 cdp: add obeyRobots to lp.configureCDP 2026-08-18 17:07:18 +02:00
Karl Seguin d3c26f589e Merge pull request #3219 from lightpanda-io/sec-ch-ua-full-version
send Sec-Ch-Ua-Full-Version-List header
2026-08-18 20:00:44 +08:00
Pierre Tachoire 0a0164c972 remove useless null terminated version_z 2026-08-18 12:28:21 +02:00
Pierre Tachoire 9ff1ad8306 fix header key case for Sec-Ch-Ua* 2026-08-18 12:25:40 +02:00
Pierre Tachoire d91a5b1abd update getHighEntropyValues 2026-08-18 12:25:11 +02:00
Karl Seguin 34ca271b33 Merge pull request #3221 from lightpanda-io/option-multiple
undocument comma separated list option
2026-08-18 17:03:29 +08:00