Introduces an incremental markdown renderer (`md_term.Stream`) to
format streamed assistant responses in real time. Buffers lines,
maintains code fence state across chunks, and temporarily withholds
tables to render them with proper column alignment once complete.
Introduces a stack-threaded `Style` chain to track and re-apply
parent styles upon nested resets. This fixes styling loss in
deeply nested markdown spans.
- Use a 256-ramp gray for `ansi.dim` to improve readability.
- Track and re-apply active styles in nested markdown spans.
- Collapse extra spaces after list markers.
CDP clients (Playwright/Puppeteer) never saw same-document navigations —
history.pushState / replaceState changed frame.url but fired no CDP event,
so frame.url() went stale and waitForNavigation missed SPA route changes.
Add a frame_navigated_within_document notification, dispatched from
History.pushState/replaceState, and emit Page.navigatedWithinDocument from
the Page domain with frameId, url, and navigationType. Unlike frameNavigated,
this deliberately does NOT send Runtime.executionContextsCleared or
DOM.documentUpdated — the document and its execution context are unchanged,
and clearing them would invalidate the client's live context ids and break
frame.evaluate(). Adds a cdp.frame test.
Scoped to the History-API path; fragment and Navigation-API paths are left
for follow-ups.
Same review pattern as the getNames enumerators: the bridge can inject
*Frame directly, so the manual switch on exec.js.global is unnecessary.
getIndexes was the one enumerator the earlier suggestions missed.
Co-Authored-By: Karl Seguin <karlseguin@users.noreply.github.com>
Review follow-up on #2944: the injected `frame` parameter of a bridged
function is the frame of the executing JS context - the caller's realm -
not the frame owning the element. The window-reflecting body/frameset
event handlers (onblur, onerror, onfocus, onload, onresize, onscroll)
used it directly, so a same-origin script reaching into another frame,
e.g. the parent doing
iframe.contentDocument.body.onblur = cb;
stored the handler on the parent's window instead of the iframe's. Per
the HTML spec these handlers alias the Window of the element's node
document, whichever realm performs the access.
All Body/FrameSet getters and setters now resolve that Window through
the existing Node.ownerFrame (element -> ownerDocument -> frame, falling
back to the caller's frame for detached/frameless documents), via a
shared reflectedWindow helper. The Build hooks (parse-complete,
attributeChange, attributeRemove) do the same, and additionally pass the
owner frame to setWindowReflectingHandlerFromAttribute so attribute
handler bodies are compiled in the element's document's realm.
Unit test added: tests/frames/window_reflecting_handlers.html covers the
IDL property path and the content-attribute path (parse-time and
runtime) across realms, asserting the handler lands on the iframe's
window while the parent's window stays untouched. It fails without this
fix.
Co-Authored-By: Karl Seguin <karlseguin@users.noreply.github.com>
Fixes 1 failing test in WPT /dom/events/Event-constructors.any.html
(and its .worker variant): "Event constructors 2", which does
`new Event({ toString: function() { throw test_error; } })` and expects
the exact test_error object to propagate.
When a JS value's conversion runs user code that throws (here, ToString
invoking a throwing toString method), the conversion fails with
error.JsException while the user's exception is pending in the isolate.
The argument-conversion catch folded that into error.InvalidArgument,
and handleError then threw a brand new "TypeError: invalid argument"
over the pending exception, so the script observed the wrong error.
error.JsException is now passed through the argument-conversion catch,
and handleError leaves the isolate untouched for it (like the existing
TryCatchRethrow case), letting the original exception surface.
Coverage: /dom/events/Event-constructors.any.html 13/14 -> 14/14,
/dom/events/Event-constructors.any.worker.html 13/14 -> 14/14.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Fixes 24 failing tests in WPT /dom/events/Body-FrameSet-Event-
Handlers.html (24/48 -> 48/48).
Per the HTML spec, the onblur, onerror, onfocus, onload, onresize and
onscroll event handlers of body and frameset elements are aliases for
the Window's handlers (the "window-reflecting body element event
handler set"), and setting the corresponding content attribute on those
elements must activate the Window's handler too. Two groups of
failures:
- "Set ...": assigning a non-callable (e.g. "") to the IDL attribute
threw "invalid argument" instead of storing null, because the setters
took ?js.Function.Global. Per [LegacyTreatNonObjectAsNull], the
Body/FrameSet setters now use Window.FunctionSetter (function or
anything-else-means-null), like the existing Window handler setters.
- "Forward ... to Window": only body.onload was forwarded. Window now
stores onblur/onfocus/onresize/onscroll handlers too (and exposes the
matching accessors, which it lacked entirely), and Body/FrameSet
implement getters/setters forwarding all six handlers to the Window
of the current frame. Setting or removing one of the six content
attributes (at parse time via Build.complete or at runtime via the
attributeChange/attributeRemove build hooks) compiles the handler
body and stores it on the Window, so window.onX === element.onX.
Coverage: /dom/events/Body-FrameSet-Event-Handlers.html 24/48 -> 48/48.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Fixes 2 failing tests in WPT /dom/events/AddEventListenerOptions-
signal.any.html (and its .worker variant): "Passing null as the signal
should throw" (with a valid and with a null listener).
The AddEventListenerOptions dictionary declares `signal` as a
non-nullable AbortSignal, so per Web IDL an explicit null (or any
non-AbortSignal value) must be rejected with a TypeError during the
dictionary conversion — even when the listener argument is null. The
bridge collapsed both a missing member and an explicit null into a Zig
null, silently ignoring the signal.
EventTarget.addEventListener now receives the signal member as a raw
js.Value: an absent or undefined member means "no signal", anything
else is converted to an AbortSignal (throwing a TypeError when it
isn't one), and the conversion runs before the null-callback early
return to match the spec's argument-conversion ordering.
Coverage: /dom/events/AddEventListenerOptions-signal.any.html
9/11 -> 11/11, /dom/events/AddEventListenerOptions-signal.any.worker.html
9/11 -> 11/11.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The applied review suggestions switched the getNames/getIndexes
enumerator callbacks of HTMLCollection, NamedNodeMap and DOMStringMap
from *const js.Execution to the injected *Frame, but only partially:
signatures and bodies disagreed and the build broke. Complete the
conversion — the bridge resolves *Frame from the context, so the manual
exec.js.global switch goes away, and the arenas/JS locals are reached
through the frame.
Co-Authored-By: Karl Seguin <karlseguin@users.noreply.github.com>
The Caller.deleteIndex and Caller.deleteNamedIndex helpers are invoked
by the bridge for definer interceptors too, since definers share the
deleter's (self, index/name) -> bool calling shape. Rename them (and
their private counterparts) to deleteOrDefineIndex and
deleteOrDefineNamedIndex so the name reflects both uses.
No behavior change.
Co-Authored-By: Karl Seguin <karlseguin@users.noreply.github.com>
This piggybacks on the HttpClient rework (1) and makes incoming WebSocket
messages get delivered in a similar fashion. Namely, WebSocket events (connect,
data, close) are queued and only delivered at safe points. The goal is to make
sure JS is never run during a libcurl callback. This has historically caused
issues and currently requires the HttpClient to have various guards (e.g.
performing flag, dirty queue, etc..).
This change removes the last cases where JS could be executed within a libcurl
callback. Consequently, HttpClient is simplified. It no longer has a perfoming
flag nor a dirty queue nor ready queue.
(1) https://github.com/lightpanda-io/browser/pull/2889
HTMLAreaElement only implemented the URL/HTMLHyperlinkElementUtils mixin
(href, origin, protocol, host, ...). The area-specific reflected IDL
attributes were missing, so alt, coords, shape, target, download, rel,
referrerPolicy and relList all read back as undefined.
Reflect them the same way HTMLAnchorElement and HTMLLinkElement do:
plain string reflection for alt/coords/shape/target/download/rel,
enumerated reflection for referrerPolicy, and the shared DOMTokenList
helper for relList (guarded to html/svg namespaces). ping is left out to
match the current HTMLAnchorElement precedent. Adds an area.html test.
The EventSource API only requires a simple line-based parser. It's pretty
straightforward. It's RC'd by v8 and itself, but also by scheduled tasks (e.g.
to reconnect).
The bigger change is to the HttpClient to support streaming requests. This
changes to things:
1 - A transfer doesn't only deliver() once
2 - A transfer can be in the multi while delivering
Neither of these are surprising, but they both add complexity.
There's 1 WPT test that returns a 8GB value content-length (testing failures)
and the u32 limit fails to parse it and makes it as though no content-length
header exists.