Prunes hidden subtrees from the accessibility tree and implements
accessible name resolution via labels. Adds the `labels` property
to labellable HTML elements.
We've seen this sort of thing before - an assumption we make about the state of
the DOM through a transition is broken by CustomElement callbacks.
Here we see replaceChild which (a) inserts the new nodes and (b) removes the
old one. As part of removing, our page.removeNode has an assertion that the
child belongs to the parent. This is a guarantee that the Page is asking the
caller (Node.replaceChild in this case) to make. But, if the node being inserted
is a custom element, it can have a callback so step (a) can cause changes to
the document, including removing/moving the node being replaced.
TL;DR - CustomElement callbacks means that we have to check that the child to
be replaced is still a child of the parent after our insert.
Was originally just a []const u8, but now allows for Blob, BufferArray (and
related) and Stream.
I saw this being used on http://www.github.com/ (homepage). Unfortunately its
using the data for webgl stuff that we don't support, but it does move the
processing a step further.
Tweak ergonomics (public functions log internally and are infallible). Use
readFileAlloc directly. Fix possible memory leak with cookie arena - I don't
think you can make a copy of the arena, and then dupe with the original.
The point of this change is that v8 might call these finalizers after we've
cleared things (e.g. because it's already queued it). We need to make the
FC.Identity self-contained and not rely on any external state (like the
finalizer_callback lookup) which might have new entries.
Split the single --cookies-file flag into two flags following curl's
convention as requested by @krichprollsch:
- --cookie (read-only): loads cookies at startup for fetch, mcp, and
serve/CDP commands
- --cookie-jar (write-only): saves cookies on exit for fetch and mcp
only (CDP cookie-jar deferred per maintainer guidance)
Add cookie integration to MCP server (load in init, save in deinit)
and CDP session creation (load only). The serve command now rejects
--cookie-jar with a clear error message.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Escape braces in help text format string to avoid std.debug.print
interpreting them as format specifiers
- Use writer.interface for std.Io.Writer methods (writeAll, stringify)
instead of calling them directly on fs.File.Writer
- Replace writer.flush() with writer.end() per codebase convention
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
std.io.bufferedWriter doesn't exist in Zig 0.15.2. Use the
file.writer(&buf) pattern that matches the rest of the codebase.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add a --cookies-file CLI option that loads cookies from a JSON file
at startup and saves them back on exit. This enables AI agents to
maintain login sessions across multiple Lightpanda invocations.
The cookie format matches CDP Network.Cookie (compatible with
Puppeteer's page.cookies() export):
[{"name":"sid","value":"abc","domain":".example.com","path":"/",
"expires":1234567890,"secure":true,"httpOnly":true}]
Closes#335
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2 small changes:
1 - Ensure that isolated world identity is always reset. Not clear how we can
have identity without a context, but very little harm in doing it this way.
2 - Clear finalizer_callback map _before_ finalizing an instance. Finalizing
an instance could (a) release an arena (they almost all do) and (b) create an
object with the newly released arena. I don't think anything does that now, but
they could. That object could even be passed into v8 during finalization. In
which case, we'd temporarily have 2 "live" instances (one being finalized, one
jsut created) at the same address. Don't think we have any code that does this,
but switching the order (remove from map, then finalize) protects against this
address re-use.
1 big change:
Not really big, but more likely to actually fix things. A finalizer can still
be called _after_ we've cleared the finalizer callback. This can happen if
v8 has queued the finalizer prior to us clearing it. We do see some evidence
that this might be an issue, as many extra releaseRefs are happening in
the message loop or microtasks. This makes that scenario safer. First, it moves
the finalizer identity to a dedicated MemoryPool that can outlive the page.
Second, it uses the finalizer_callback map itself to tell whether or not
anything has to happen.
This is an attempt to fix reference counting issues. When Session.replacePage
is called, isolated worlds survive. This appears to be the correct behavior, but
it means that their identity outlives the page reset, which can result in a
use-after-free. The idea is that, on reset, IsolatedWorld persist, but their
identity is cleared.
It should be impossible for a internal cache get to have an incorrect # of
internal fields. But we're seeing this exact scenario in production.
https://github.com/lightpanda-io/browser/pull/1991 was meant to help with this,
but you can do some pretty weird things in JavaScript and it's possible there's
some combination of JavaScript which still allows calling these methods on a
different receiver.
1. Double buffer to_load list so that load callback which register more loadable
elements don't invalid the list while we're iterating
2. Switch to debug-only assertion for opaque origin. Not clear how this
assertion is failing, but isn't worth failing release builds for it.
3. on worker terminate, don't remove worker from page tracking. This results in
a leaking context, which causes numerous problems.
4. On page.init error, cleanly shutdown context
Fetch is owned by response.arena (a) we need to clear the flag before freeing
the arena and (b) there's no point in clearing the flag at all, since the
memory is freed.