Commit Graph

6274 Commits

Author SHA1 Message Date
Navid EMAD
fd0700a572 dockerfile: fix curl|sh pipefail; trim builder stage
- Download rustup to a file then execute, so a failed curl is not
  masked by sh's exit code under /bin/sh (no pipefail).
- Add --no-install-recommends and apt-list cleanup to both apt stages
  (stage 0 drops from 156 to 116 packages, 1144 MB to 605 MB).
- Add --retry 3 --retry-delay 2 to all 4 external downloads.
- Use git clone --depth 1 (28 MB to 9.6 MB working tree).
- Drop -v from tar for minisign and zig extractions (log noise only).

Final shipped image is unchanged; the wins live in the builder stage
and build-cache footprint.
2026-05-15 23:45:06 +02:00
Pierre Tachoire
4f33d64c5c Merge pull request #2433 from lightpanda-io/webmcp
Implement webMCP API and webMCP cdp domain
2026-05-15 16:13:12 +02:00
Pierre Tachoire
60e3d48dbd webmcp: update comments 2026-05-15 15:12:27 +02:00
Pierre Tachoire
f00c0ab276 webmcp: implement abortSignal with _dependent 2026-05-15 13:11:59 +02:00
Pierre Tachoire
3803a1f8c6 webmcp: use value.jsonStringify for JSON write 2026-05-15 11:17:53 +02:00
Pierre Tachoire
dbb9b31061 webmcp: fix invoke callback with correct ModelContextClient param 2026-05-15 11:00:56 +02:00
Karl Seguin
64c5843e9e Merge pull request #2466 from lightpanda-io/pending_queue_pump
Clear pending destroy on createPage (a known safepoint).
2026-05-15 16:42:15 +08:00
Pierre Tachoire
7c5a3b211f cdp: cancel inflight webmcp invocation on bc deinit 2026-05-15 08:50:48 +02:00
Pierre Tachoire
19fd9a6e35 cdp: adjust inv_id address usage 2026-05-15 08:50:47 +02:00
Pierre Tachoire
5e0901aaf7 cdp: fix invalid arena usage in webmcp 2026-05-15 08:50:47 +02:00
Pierre Tachoire
3ef6e57d58 cdp: adjust invocation id usage for webmcp 2026-05-15 08:50:47 +02:00
Pierre Tachoire
c23d0f4f35 cdp: implement webMCP domain 2026-05-15 08:50:46 +02:00
Pierre Tachoire
0023bd7d19 Add WebMCP navigator.modelContext
Implements the page-side surface of the W3C WebMCP spec
(https://webmachinelearning.github.io/webmcp/): exposes
`navigator.modelContext.registerTool(...)` for declaring MCP tools to a
browser agent, with full name/description validation, AbortSignal-based
unregistration, and a `ModelContextClient` whose `requestUserInteraction`
invokes its callback directly (closest faithful behavior in a headless
browser).
2026-05-15 08:50:38 +02:00
Karl Seguin
4205cd905b Clear pending destroy on createPage (a known safepoint).
This allows pending destroys that have been accumulated to be cleaned up. In
normal operations, this likely isn't going to happen. But we see a some unit
tests create _many_ pages that never have the change to be cleaned up. The
result is that the next "normal" unit test, which actually runs enough through
Runner to trigger the cleanup, pays a huge cleanup price.

Arguably, for a test-only solution, we could create a session per test, or
have explicit cleanup in the test. But having 1 long-lasting session is useful
as it can show us these potential pitfalls AND, it isn't impossible that a
real-world case runs into similar issues.
2026-05-15 11:31:53 +08:00
Karl Seguin
cb8c2bc4d8 Merge pull request #2456 from lightpanda-io/cdp-proper-cache-disable
properly disable cache on `Network.setCacheDisabled`
2026-05-15 09:11:12 +08:00
Karl Seguin
632f3ea7d6 Merge pull request #2457 from lightpanda-io/fetch_dump_navigate_fix
Dump using the latest Frame to prevent segfault during on frame change
2026-05-15 07:38:19 +08:00
Karl Seguin
94f0d94192 Merge pull request #2461 from staylor/fix/2459-surface-at-rules-via-insertrule
Surface at-rules through insertRule and replaceSync (fixes #2459 partial)
2026-05-15 07:35:59 +08:00
Karl Seguin
b7a0ca2bca fallback unknown rule to new unknown type 2026-05-15 06:59:21 +08:00
Scott Taylor
6d1740b40f Surface at-rules through insertRule and replaceSync (fixes #2459)
CSSStyleSheet.insertRule previously detected at-rules in the parser
(has_skipped_at_rule) and returned the requested index without inserting
anything. The original change (PR #1972) did this to keep at-rule input
from killing module evaluation in apps like Expo Web -- correct, but the
silent-success contract has a second-order effect: CSS-in-JS libraries
(emotion, styled-components, Stitches, Mantine, Linaria) that round-trip
through cssRules to deduplicate their stylesheets see the rule as missing
after insertion, conclude the stylesheet is empty, and fall back to direct
<style> element injection per render. The result is unbounded <style>
accumulation on long-lived sessions doing repeated DOM interaction. See
issue #2459 for measurements (Allbirds-style PDPs accumulating thousands
of <style> elements over a render loop).

Changes:

* Parser.RulesIterator now returns a Rule union of {.style, .at_rule}
  instead of skipping at-rules and setting has_skipped_at_rule. The
  at-rule variant carries the keyword (without `@`) and the full source
  span so callers can construct an opaque placeholder rule.

* CSSRule gains a `_text` field and an `initAtRule` constructor for
  storing the at-rule source. CSSRule.getCssText returns the stored
  text (CSSStyleRule's overridden getCssText still wins for `.style`
  rules via the bridge dispatch on the most-derived class).

* CSSStyleSheet.insertRule and replaceSync handle both Rule variants:
  regular rules become CSSStyleRule as before, at-rules become opaque
  CSSRule placeholders with the matching CSSRule.Type variant
  (vendor-prefixed keyframes are normalized; unrecognized at-rule
  keywords fall back to .media). The CSS engine still doesn't apply
  these rules -- that's intentional and outside the scope of this
  change -- but they now surface via cssRules so library dedup paths
  work correctly.

* StyleManager.addRawRules switches on the Rule kind and skips
  at-rules (it only filters on display/visibility/opacity at the top
  level, no semantic change).

* The CSSRule spec constants (STYLE_RULE, KEYFRAMES_RULE, MEDIA_RULE,
  ...) were declared as plain Zig consts inside JsApi but never wrapped
  with bridge.property, so they came back as `undefined` from JS. Fixed
  while writing the regression tests since the tests need to compare
  rule.type against the spec constants.

Tests:

* Parser unit tests: cover statement at-rules (`@import url(...);`),
  block at-rules (`@media`), and vendor-prefixed at-rules
  (`@-webkit-keyframes`).

* HTML runner tests: cover insertRule for @keyframes, @media,
  @supports, @font-face, vendor-prefixed at-rules, mixed style + at-rule
  insertion, replaceSync at-rule preservation, and the dedup-via-cssRules
  pattern that's the actual library code path the bug breaks.

A/B verification with the synthetic CSS-in-JS dedup pattern (50 calls to
inject the same @keyframes through a library that falls back to <style>
element injection when insertRule appears empty):

  baseline (1.0.0-nightly.6240): styles=51 rules=0
  patched (this branch):         styles=1  rules=50

The leak collapses: instead of 50 <style> fallbacks stacking up, the
single persistent stylesheet receives all 50 insertions and dedup works.

Note on partial coverage of #2459: the original Allbirds reproducer
involves a Vue.js + Yotpo widget that injects <style> elements via
direct document.head.appendChild rather than insertRule. That code
path is unaffected by this change; it appears to be a separate
mechanism (possibly related to Vue's vue-style-loader closure-based
dedup or web-component lifecycle on Lightpanda) and is worth filing
separately. This PR fixes the specific insertRule contract issue
described in #2459 and unblocks the major CSS-in-JS libraries.
2026-05-14 16:19:36 -04:00
Muki Kiboigo
940976b6a7 properly disable cache on Network.setCacheDisabled 2026-05-14 09:03:51 -07:00
Karl Seguin
a59ddeb360 Dump using the latest Frame to prevent segfault during on frame change
Fixes: https://github.com/lightpanda-io/browser/issues/2446
2026-05-14 20:00:20 +08:00
Karl Seguin
2f3a426fb0 Merge pull request #2453 from lightpanda-io/cdp-network-serve-from-cache
Adds `Network.requestServedFromCache`
2026-05-14 17:34:46 +08:00
Karl Seguin
b96c24d377 Merge pull request #2455 from lightpanda-io/cdp-response-fromdiskcache
Add `fromDiskCache` field to `Network.Response`
2026-05-14 16:01:04 +08:00
Karl Seguin
0624a05205 Merge pull request #2454 from lightpanda-io/cdp-network-cache-clear
add `Network.clearBrowserCache` and `Network.canClearBrowserCache`
2026-05-14 15:56:29 +08:00
Karl Seguin
143bffdfec Merge pull request #2450 from navidemad/fix-bug7-form-idl
forms: add enctype + 5 submitter form-* IDL accessors
2026-05-14 13:44:57 +08:00
Karl Seguin
80a09fc0fd zig fmt 2026-05-14 13:19:17 +08:00
Muki Kiboigo
f2f328cffd add fromDiskCache field to Network.Response CDP type 2026-05-13 21:57:22 -07:00
Muki Kiboigo
07e7c3d687 add Network.clearBrowserCache and Network.canClearBrowserCache 2026-05-13 21:52:10 -07:00
Muki Kiboigo
ac863c7e2b add Network.requestServedFromCache 2026-05-13 21:47:47 -07:00
Karl Seguin
14b4449628 use format to write String value 2026-05-14 11:03:12 +08:00
Karl Seguin
373916873f Merge pull request #2442 from lightpanda-io/worker_message_buffer
CI fixes, callback timing correctness
2026-05-14 08:56:36 +08:00
Karl Seguin
96ac9a49ea Update src/browser/webapi/Worker.zig
Co-authored-by: Navid EMAD <navid.emad@yespark.fr>
2026-05-14 08:33:32 +08:00
Karl Seguin
1580ab197f Merge pull request #2452 from lightpanda-io/event_worker
make Event worker-safe
2026-05-14 07:39:37 +08:00
Karl Seguin
bcafa175cb make Event worker-safe 2026-05-14 07:11:33 +08:00
Navid EMAD
f0cce42757 forms: route Frame.submitForm through Form.normalizeMethod/normalizeEnctype
The submitForm encoding path was the last duplicate of the "limited to
only known values" canonicalization the previous commit consolidated for
the IDL getters. Now it consumes the same Form.normalizeMethod /
Form.normalizeEnctype helpers, so a single function owns the canonical
mapping (`""` / unknown -> spec default, recognized values pass through
unchanged).

Side effect of routing through the helper: the
`log.warn(.not_implemented, "FormData.encoding", ...)` branch falls out.
After commit 4b693db4 added `text/plain`, the only attribute values that
still reach the urlencoded fallback are spec-invalid ones, which per
HTML §4.10.21.5 silently canonicalize to
`application/x-www-form-urlencoded`. The warning was firing for valid
spec behavior — Chrome doesn't log either.

Behavior-preserving on all observable surfaces: full suite 639/639 green;
existing form-submission integration tests (multipart, urlencoded,
text/plain, GET-ignores-enctype) all pass unchanged.
2026-05-13 18:14:10 +02:00
Navid EMAD
4b693db480 forms: support enctype=text/plain in form submission
Closing the divergence introduced by the new IDL accessors: `submitter.formEnctype`
(and `form.enctype`) now return "text/plain" for that attribute value per WHATWG
HTML §4.10.21.5, but `Frame.submitForm` previously fell back to urlencoded with
a `.not_implemented` log when it saw the same value on the submission path.

Implement the spec's text/plain encoding algorithm (HTML §4.10.21.8):

  - FormData.EncType gains a `.plaintext` variant.
  - FormData.plaintextEncode writes "name=value CRLF" per entry, no URL-encoding,
    no escaping — the spec accepts that text/plain is a lossy, human-readable
    encoding (values containing "=" or CRLF produce an ambiguous wire format
    by design).
  - Frame.submitForm recognizes "text/plain" before the urlencoded fallback and
    sets the Content-Type header to "text/plain; charset=<form-charset>", per
    spec step 21.4.

Two new Zig unit tests cover encoding output (`FormData: plaintext write`,
`FormData: plaintext empty body`). Full suite 639/639 green.

This is bundled with the IDL accessor commits because returning "text/plain"
from the IDL while the submission silently re-encodes as urlencoded is a
spec-internal inconsistency the IDL change itself introduces. Reviewers who'd
prefer to land just the read-only accessors first should feel free to ask for
a split — this commit is self-contained and reverts cleanly.
2026-05-13 18:08:54 +02:00
Navid EMAD
cedfdba0d7 forms: extract normalizeMethod / normalizeEnctype helpers
The "limited to only known values" canonicalization (per WHATWG HTML
§2.2.2) was duplicated five times: Form.getMethod + Form.getEnctype +
{Button,Input}.{getFormMethod,getFormEnctype}. Each callsite differed
only in the missing-value default ("" for submitter overrides, "get" /
"application/x-www-form-urlencoded" for the form-side).

Extract into two pub helpers on Form.zig taking the attribute slice +
the missing-value default. The five callers collapse to one-liners.

Behavior-preserving: existing form.html / button.html / input-attrs.html
fixtures all pass unchanged; full suite 637/637 green.

Net: -36 LOC.
2026-05-13 17:58:55 +02:00
Navid EMAD
2fdc82aa05 forms: add enctype + 5 submitter form-* IDL accessors
Six form-submission IDL accessors were missing from the JsApi blocks of
HTMLFormElement, HTMLButtonElement, and HTMLInputElement, so reads
produced undefined instead of the spec-mandated string/boolean. The
content-attribute path (clicking a submit button honoring formaction /
formmethod / formenctype) was wired up in #2279; this commit adds the
matching IDL-property accessors per WHATWG HTML §4.10.18.6 and §4.10.21.5.

- Form.enctype: limited to known values, missing+invalid both default to
  application/x-www-form-urlencoded (mirrors getMethod's shape).
- Button/Input formAction: returns frame.url when missing/empty, else the
  resolved URL (mirrors Form.getAction).
- Button/Input formEnctype, formMethod: limited to known values with no
  missing-value default ("" when missing, canonical invalid-value default
  application/x-www-form-urlencoded / get when invalid).
- Button/Input formTarget: plain reflection, defaults to "".
- Button/Input formNoValidate: boolean reflection of formnovalidate.

Closes #2449
2026-05-13 17:49:19 +02:00
Karl Seguin
5595f7d298 Merge pull request #2448 from lightpanda-io/script_load_error_handling
Don't process scripts that failed to load
2026-05-13 23:19:40 +08:00
Pierre Tachoire
198c4e5a0f Merge pull request #2444 from lightpanda-io/useless-code
cdp: remove dead code
0.3.0
2026-05-13 15:36:16 +02:00
Pierre Tachoire
ffc2baa733 Merge pull request #2431 from lightpanda-io/cdp-double-frame-navigated-event
fix(cdp): remove duplicate Page.frameNavigated and fix context regist…
2026-05-13 15:17:27 +02:00
Karl Seguin
7750bc94f6 Apply suggestions from code review
Remove no-longer needed setTimeouts in test now that messages are queued. 

Runner also checks ready_queue when determining doneness.

Co-authored-by: Navid EMAD <design.navid@gmail.com>
2026-05-13 20:57:59 +08:00
Karl Seguin
2326071036 Don't [try] to process scripts that failed to load
At some point recently, we started to process scripts that fail to load (e.g.
404). This stops such scripts from [trying] to be evaluated, and executes the
onerror handler in all script loading paths.
2026-05-13 20:48:08 +08:00
Pierre Tachoire
12971a2420 Merge pull request #2445 from lightpanda-io/reset-bc-arena
cdp: reset browser context arena when bc is removed
2026-05-13 14:35:38 +02:00
Pierre Tachoire
5d73d82bf6 cdp: call context created w/ correct is_default_context value
Co-authored-by: Navid EMAD <navid.emad@yespark.fr>
2026-05-13 14:11:53 +02:00
Pierre Tachoire
8432cfbfba cdp: return error in case of missing event's frame
Instead of using the root_frame
2026-05-13 12:29:11 +02:00
Karl Seguin
e895ce81e3 Merge pull request #2437 from lightpanda-io/window_frameElement
Add window.frameElement
2026-05-13 18:00:08 +08:00
Karl Seguin
3e31fde66c Merge pull request #2443 from lightpanda-io/url_fixes
Fix URLSearchParams constructor
2026-05-13 17:59:50 +08:00
Karl Seguin
625e240f5a Pump the http_client queue after perform, not just before
Client.tick drains self.queue (assigning conns to queued transfers) only
at the start. When perform / processMessages releases a batch of conns
back to the pool, those conns sit idle until the next tick — a queued
transfer that could have run this tick waits one Runner iteration
(~20 ms in the test runner) for no reason. Adds a second drainQueue
call after perform so newly-freed conns get picked up immediately.

In practice this matters whenever httpMaxHostOpen / httpMaxConcurrent
is exceeded — pages with N > limit subresources had each "wave" of
queue overflow paying one extra tick of latency.
2026-05-13 17:58:49 +08:00
Karl Seguin
c79dd2bf1f Make runner aware of http_client.queue
When connections are queued, the processing cannot be considered done.
2026-05-13 17:55:39 +08:00