Commit Graph

8347 Commits

Author SHA1 Message Date
Halil Durak
be8628f235 update: add help command entry for update 2026-07-08 13:00:29 +03:00
Halil Durak
94239e123b Updater: finalize inform 2026-07-08 13:00:29 +03:00
Halil Durak
32fefeaa7a update: remove nightly channel check 2026-07-08 13:00:29 +03:00
Halil Durak
4c62337cfa Updater: prefer JSON structures specific to update channel 2026-07-08 13:00:29 +03:00
Halil Durak
6acb58eff4 Updater: continue on implementing Updater.inform 2026-07-08 13:00:28 +03:00
Halil Durak
bbd53e4d83 Updater: prefer arbitrary JSON union for parsing versions.json 2026-07-08 13:00:28 +03:00
Halil Durak
7bea3319e8 Updater: update versions.json URL 2026-07-08 13:00:28 +03:00
Halil Durak
6919400c42 add update command and make it runnable in main 2026-07-08 13:00:28 +03:00
Halil Durak
a716279e30 Updater: introduce Updater
Updater is a simple interface that does web requests for version comparison without needing `App` instance.
2026-07-08 13:00:27 +03:00
Halil Durak
03c51052b0 Config: add update command 2026-07-08 13:00:27 +03:00
Halil Durak
b97ca18dcb Network: mark globalInit and globalDeinit as pub 2026-07-08 13:00:24 +03:00
Karl Seguin
2a7b399d90 refactor: Rework how v8::Globals are managed
We typically persist a v8::Value by calling persist() or temp() on our v8
wrappers. Both persist() and temp() create a v8::Global, but persist() tracks
it in the page's globals ArrayList while temp() tracks it in the page's temps
HashMap.

Globals are only freed when the page is torn down, hence a simple ArrayList is
all we need. Temps can be freed at any point, hence HashMap is used. (Temps are
also freed on teardown, but they can be freed before that too).

This commit removes Temp (js.Value.Temp, js.Promise.Temp, js.Function.Temp)
and all the mechinery around them (e.g. pseudo Global generic). There are now
only Globals and any global can be freed at any time (while still being tracked
in the page in order to be able to free any un-freed on page teardown).

Many files were touched because .Temp -> .Global and .temp() -> .persist().

This commit is based off the indexeddb branch because indexeddb introduced
"bare" globals (globals which aren't tracked by the Page). Building this new
model to include "Bare" globals avoids a messy merge later.
2026-07-08 10:48:18 +08:00
Karl Seguin
958bea53de cleanup rebase 2026-07-08 10:38:04 +08:00
Karl Seguin
15d6b16268 Revert "refactor: Rework how v8::Globals are managed"
This reverts commit 61cc7bb949.
2026-07-08 10:24:57 +08:00
Karl Seguin
65ae4a8bc0 refactor: Rework how v8::Globals are managed
We typically persist a v8::Value by calling persist() or temp() on our v8
wrappers. Both persist() and temp() create a v8::Global, but persist() tracks
it in the page's globals ArrayList while temp() tracks it in the page's temps
HashMap.

Globals are only freed when the page is torn down, hence a simple ArrayList is
all we need. Temps can be freed at any point, hence HashMap is used. (Temps are
also freed on teardown, but they can be freed before that too).

This commit removes Temp (js.Value.Temp, js.Promise.Temp, js.Function.Temp)
and all the mechinery around them (e.g. pseudo Global generic). There are now
only Globals and any global can be freed at any time (while still being tracked
in the page in order to be able to free any un-freed on page teardown).

Many files were touched because .Temp -> .Global and .temp() -> .persist().

This commit is based off the indexeddb branch because indexeddb introduced
"bare" globals (globals which aren't tracked by the Page). Building this new
model to include "Bare" globals avoids a messy merge later.
2026-07-08 10:24:21 +08:00
Karl Seguin
6b3ee7f65d idb: on abort, rollback created stores/indexes
Also, better query key validation
2026-07-08 10:23:09 +08:00
Karl Seguin
2961264052 idb: add compound keys 2026-07-08 10:23:07 +08:00
Karl Seguin
b1453f12a3 idb: expose request.source, and improve cursor state check 2026-07-08 10:22:53 +08:00
Karl Seguin
28c36a8d0b idb: reject operations on deleted datastore 2026-07-08 10:22:32 +08:00
Karl Seguin
300d783b4d idb: abort transaction on callback exception 2026-07-08 10:22:11 +08:00
Karl Seguin
22f2b15842 idb: handle reentrant upgradeneeded callbacks
Add handling for upgradeneeded callbacks enqueuing more work.
2026-07-08 10:21:49 +08:00
Karl Seguin
0bb6291ad0 idb: improve indexeddb memory model
Rather than having everything tied to the page's memory (arena, factory), most
things are now tied to an IDBTransaction and its arena. The IDBTransaction is
reference counted and finalized with v8. The lifecycle is relatively complicated
compared to anything else we have, which is a concern, but using the page arena
seems like a dealbreaker to me.

Any "child" created for the transaction (e.g. IDBRequest) has its v8 acquireRef
and releaseRef forwarded to the Transaction. This should make v8's usage safe.
However, in addition to this, Zig itself must take a RC whenever a drain is
scheduled AND whenever the transaction is parked in the engine. And these
things, especially on cleanup, can be a little messy.

The _awful_ cursor allocations have been improved by a local re-used ArrayLists
for the key/primary key/value. So rather than accumulating _every_ allocation
we now only capture the peak.

One final memory-related area this commit addresses is the lifetime difference
between Transactions (Page) and Engine (Session). This is problematic because
the Engine can reference the Transaction. On js.Context deinit, the engine is
notified and all related Transactions are canceled/removed. This is...unusual
in our design. We have other similar cases that use a list on the frame/GWS to
track resources to cleanup. But, the Engine already _has_ to have this list so
rather than book-keeping in Engine AND Frame AND WGS, only Engine has a list at
the cost of js.Context having to notify it on teardown.
2026-07-08 10:21:49 +08:00
Karl Seguin
73b5386d26 idb: allow re-entrant and interleaved transactions
Because of the single-connection nature of our Engine (in-memory SQLite), the
IDB Engine now keeps a list of "gated" transactions, processing one at time.
When one transaction completes, waiting transactions are signaled so that they
can processes their queue.

This also adds a double-queue so that any requests that comes in while
processing requests goes into a new queue and is only drained on the next tick.

Note: this introduces a UAF, where Engine lives on Session and referneces
IDBTransactions which are tied to the page. The next bit work on IDB is the
memory re-work, so I'm punting that there.
2026-07-08 10:21:49 +08:00
Karl Seguin
ba74450d1b fix broken zig fmt 2026-07-08 10:21:47 +08:00
Karl Seguin
cb8d6d9270 idb: handle requeue index order and abort in settle 2026-07-08 10:21:29 +08:00
Karl Seguin
fb39792f2d idb: add IDBRecord 2026-07-08 10:21:25 +08:00
Karl Seguin
1dcd0dc6fb idb: rework transaction model
Previously, every operation would run synchronously, and resolve the value
on the next drain (schedule task run on the next tick).

With 1 connection per DB, this doesn't work with SQLite: you cannot have nested
transactions. Imagine:

add
  begin
    insert into
    JS callback (success)
      add
        begin <-- nested
          insert

This approach captures the requested operation and does all necessary validation
(since most validation errors are returned synchronously), but only executes
operations on drain. Hence, rather than IDBTransaction._requests being a
queue of result values to emit on drain, it is now a queue of operations to
execute and then emit.

This will also potentially make it easier to address serious memory
issues by better scoping the lifetime of things (particularly requests).
2026-07-08 10:21:04 +08:00
Karl Seguin
b0bccbb4bc make indexedb in-memory only (for now) 2026-07-08 10:21:02 +08:00
Karl Seguin
91901ca007 Add object store name support + DOMStringList 2026-07-08 10:20:23 +08:00
Karl Seguin
437dac68ef add IDBIndex 2026-07-08 10:19:38 +08:00
Karl Seguin
edbd24bbac webapi, idb: Add IDBCursor and IDBCursorWithValue 2026-07-08 10:18:42 +08:00
Karl Seguin
6b7d0c6391 webapi, idb: add IDBKeyRange
Including support for IDBKeyRange based operations
2026-07-08 10:17:22 +08:00
Karl Seguin
47d540a69a webapi: IndexedDB base
Initial WIP on IndexedDB WebAPI. Uses sqlite and a new `--indexdb_dir` config.
Defaults to :memory:.

The main things missing are the IDBCursor, IDBIndex and IDBKeyRange, along with
a bunch of smaller apis.

Also, every object is currently tied to the Page arena / factory. It's possible
that's how it will have to be, but, once more of the API lands, I will check
if we can scope these better.
2026-07-08 10:16:17 +08:00
Karl Seguin
cc7d319ea5 Merge pull request #2874 from lightpanda-io/agent-regression
Add agent regression suite to CI (consumed from lightpanda-io/demo)
2026-07-08 09:19:00 +08:00
Karl Seguin
789929ba1e Merge pull request #2895 from lightpanda-io/lazy_loading_iframes
perf: Iframes with loading=lazy don't delay parent's "load" event
2026-07-08 08:51:21 +08:00
Karl Seguin
62edeb506a Merge pull request #2897 from lightpanda-io/v8_max_memory
v8, mem: Add v8 configuration option + heap limit protection
2026-07-08 08:33:07 +08:00
Adrià Arrufat
f3f731ffb1 fix: setChecked double-toggled checkables via click activation
actions.setChecked set the input state and then dispatched a trusted
click, but the click's activation behavior (EventManager's
ActivationState) toggles a checkbox on every click dispatch — undoing
the state just set — and its commit path fires input/change, which
setChecked then fired a second time. Checkboxes always landed in the
opposite of the requested state with doubled events; radios only
appeared to work because radio activation always checks. It survived
because existing tests asserted the tool's report string, never the
resulting DOM state.

setChecked is now a no-op when the state already matches, otherwise it
performs the click (reusing actions.click) and verifies the state
landed — erroring before the click for radio+false (a click can never
uncheck a radio, and the click has observable page side effects) and
after it when a listener preventDefault()ed the toggle.

Caught by the checked.js golden in the demo agent regression suite.
The Runtime test now asserts DOM state and idempotency instead of
trusting the report string.
2026-07-07 15:43:28 +02:00
Karl Seguin
4253bd852d update v8 dep 2026-07-07 20:41:12 +08:00
Adrià Arrufat
52a8779f2a Merge branch 'main' into agent-regression 2026-07-07 11:43:12 +02:00
Karl Seguin
7184c45ee6 improve variables/comments 2026-07-07 17:14:48 +08:00
Karl Seguin
03f542006d v8, mem: Add v8 configuration option + heap limit protection
The main addition in this commit is that we hook into the Isolate's
AddNearHeapLimitCallback callback and try to force the isolate to shutdown
rather than letting v8 hit an OOM which would take down the entire process.

In support of this, we now support a `--v8-max-heap-mb` command line option to
set an explicit heap limit. As a simple way to test this feature, load a
relatively heavy JS page with `--v8-max-heap-mb 1`.

There's also a `--v8-flags-unsafe` which is a mechanism to pass arbitrary
flags to v8 via its `SetFlagsFromString`. The parameter is called `unsafe`
because some [of the many] configurable flags could conflict with how the
snapshot is built and result in crashes. The snapshot creator also gains a
`--v8-flags-unsafe` flag, so advance users COULD create their snapshot and
run lightpanda with the same set of flags.
2026-07-07 12:40:23 +08:00
Karl Seguin
032cbc3846 perf: Iframes with loading=lazy don't delay parent's "load" event
When an iframe has "loading=lazy" it no longer delays the parent's "load" event.
It's still loaded (subject to `--disable-subframes` parameter).

Many sites use loading=lazy for non-critical content (e.g. ads). On Chrome/
Firefox, these are only loaded when they're in the viewport, so sites usually
can't depend/rely on them being loaded.
2026-07-07 11:17:36 +08:00
Karl Seguin
c1dfb09f04 Merge pull request #2883 from lightpanda-io/response-static
webapi: Add static Response.json, Response.error and Response.redirect
2026-07-07 07:19:19 +08:00
Karl Seguin
2b1f7f78ad Merge pull request #2881 from lightpanda-io/DOMPoint
webapi: Add DOMPoint and DOMPointReadOnly
2026-07-07 07:17:23 +08:00
Karl Seguin
9621f5edf7 Merge pull request #2890 from lightpanda-io/domexception
minor: remove DOMException WebAPI flag (make it always on).
2026-07-07 07:17:09 +08:00
Karl Seguin
4a31784901 Merge pull request #2893 from lightpanda-io/replaceable
webapi: more (and better) replaceable proeprties.
2026-07-07 07:16:52 +08:00
Pierre Tachoire
6982ff95f0 Merge pull request #2894 from lightpanda-io/nested_timer_protection
perf, mem, uaf: Enforce minimum timer delay on nested timers
2026-07-06 16:52:28 +02:00
Pierre Tachoire
b1458da04c Merge pull request #2892 from lightpanda-io/getComputedStyle-width-height
fix, render: CSS getPropertyValue special width/height handling
2026-07-06 16:49:26 +02:00
Karl Seguin
0067fe8996 Merge pull request #2884 from lightpanda-io/goto_error_path_isolate
script: reject failed goto starts outside the browser isolate
2026-07-06 22:31:57 +08:00
Karl Seguin
fd8ee52e1f perf, mem, uaf: Enforce minimum timer delay on nested timers
Per spec, nested timers eventually (5-level deeps) enforce a minimum timeout
(4ms).

This commit also fixes 2 UAFs in module loading where a map entry would become
invalid through nested mutations.

All issues were encountered on https://111skin.com/.
2026-07-06 22:05:12 +08:00