Next.js hydration references FileList as a global for feature detection.
Register a minimal stub (length=0, item()→null) so the type exists in
the global scope and the reference check doesn't throw.
Custom element callbacks aren't allowed to call document.open/close/write while
parsing.
Fixes WPT crash:
/custom-elements/throw-on-dynamic-markup-insertion-counter-reactions.html
On BSD, a listening socket isn't considered connected, so this error is
expected. Maybe we shouldn't call shutdown at all, but I guess it's safer this
way.
The bridge.finalizer resolves Page through its own module graph, which
can differ from Range.zig's import in release builds. Store a pointer
to the live_ranges list directly on AbstractRange so deinit can remove
without accessing Page fields.
Add a weak finalizer to Range that removes its linked list node from
Page._live_ranges when V8 garbage-collects the JS Range object. This
prevents the list from growing unboundedly and avoids iterating over
stale entries during mutation updates.
Move the per-range update logic from Page into AbstractRange methods
(updateForCharacterDataReplace, updateForSplitText, updateForNodeInsertion,
updateForNodeRemoval). Page now just iterates the list and delegates.
Remove redundant start_container == end_container check in insertNode —
collapsed already implies same container.
When calculating accessible names for elements without explicit labels, multiple descendant text nodes were previously concatenated directly together. This adds a space between distinct text node contents to prevent words from sticking together.
Previously, semantic_tree_text hardcoded prune = false, which bypassed the structural node filters and allowed empty none nodes to pollute the root of the text dump.
This prevents token bloat in JSON/text dumps and ensures that StaticText leaf nodes are not incorrectly pruned when structural containers (like none, table) hoist their text.
This fixes a bug where only the first text node was being returned, causing fragmented text nodes (e.g. <span>Sub</span><span>mit</span>) to be missing their trailing text.
The introduction of frames means that data is no longer tied to a specific Page
or Context. 255b9a91cc introduced Origins for
v8 values shared across frames of the same origin. The commit highlighted the
lifetime mismatched that we now have with data that can outlive 1 frame. A
specific issue with that commit was the finalizers were still Context-owned.
But like any other piece of data, that isn't right; aside from modules, nothing
should be context-owned.
This commit continues where the last left off and moves finalizers from Context
to Origin. This is done in a separate commit because it introduces significant
changes. Currently, finalizers take a *Page, but that's no longer correct. A
value created in one Page, can outlive the Page. We need another container. I
original thought to use Origin, but that isn't know to CDP/MCP. Instead, I
decide to enhance the Session.
Session is now the owner of the page.arena, the page.factory and the
page.arena_pool. Finalizers are given a *Session which they can use to release
their arena.
Depends on: https://github.com/lightpanda-io/zig-v8-fork/pull/153
In some ways this is an extension of
https://github.com/lightpanda-io/browser/pull/1635 but it has more implications
with respect to correctness.
A js.Context wraps a v8::Context. One of the important thing it adds is the
identity_map so that, given a Zig instance we always return the same v8::Object.
But imagine code running in a frame. This frame has its own Context, and thus
its own identity_map. What happens when that frame does:
```js
window.top.frame_loaded = true;
```
From Zig's point of view, `Window.getTop` will return the correct Zig instance.
It will return the *Window references by the "root" page. When that instance is
passed to the bridge, we'll look for the v8::Object in the Context's
`identity_map` but wont' find it. The mapping exists in the root context
`identity_map`, but not within this frame. So we create a new v8::Object and now
our 1 zig instance has N v8::Objects for every page/frame that tries to access
it.
This breaks cross-frame scripting which should work, at least to some degree,
even when frames are on the same origin.
This commit adds a `js.Origin` which contains the `identity_map`, along with our
other `v8::Global` storage. The `Env` now contains a `*js.Origin` lookup,
mapping an origin string (e.g. lightpanda.io:443) to an *Origin. When a Page's
URL is changed, we call `self.js.setOrigin(new_url)` which will then either get
or create an origin from the Env's origin lookup map.
js.Origin is reference counted so that it remains valid so long as at least 1
frame references them.
There's some special handling for null-origins (i.e. about:blank). At the root,
null origins get a distinct/isolated Origin. For a frame, the parent's origin
is used.
Above, we talked about `identity_map`, but a `js.Context` has 8 other fields
to track v8 values, e.g. `global_objects`, `global_functions`,
`global_values_temp`, etc. These all must be shared by frames on the same
origin. So all of these have also been moved to js.Origin. They've also been
merged so that we now have 3 fields: `identity_map`, `globals` and `temps`.
Finally, when the origin of a context is changed, we set the v8::Context's
SecurityToken (to that origin). This is a key part of how v8 allows cross-
context access.
Per DOM spec, appendData(data) is defined as replaceData(length, 0, data).
While the range update would be a no-op (offset=length, count=0), routing
through replaceData ensures consistent code path and spec compliance.
Per DOM spec, all live ranges must have their boundary offsets updated
when CharacterData content changes (insertData, deleteData, replaceData,
splitText) or when nodes are inserted/removed from the tree.
Track live ranges via an intrusive linked list on Page. After each
mutation, iterate and adjust start/end offsets per the spec algorithms.
Also fix Range.deleteContents loop that read _end_offset on each
iteration (now decremented by the range update), and Range.insertNode
that double-incremented _end_offset for non-collapsed ranges.
Route textContent, nodeValue, and data setters through replaceData
so range updates fire consistently.
Fixes 9 WPT test files (all now 100%): Range-mutations-insertData,
deleteData, replaceData, splitText, appendChild, insertBefore,
removeChild, appendData, dataChange (~1330 new passing subtests).