Patch Changes
-
4f8daa2: A derived store row first read during a held adoption is paired with its old row the way the adoption pairs rows (by the family's key), so reading a field the adoption left unchanged (
cards.find(...)?.id) no longer holds an independent write for the action's lifetime (#3712). A changed field still holds. -
ad973ed: Async holds follow the reader, and are shorter:
- A first load read by a render effect outside a
<Loading>makes the change that mounted it wait (the async answer of a memo created under a hold lands with that hold); a<Loading>that has not shown content catches it instead and shows its fallback. - Creating a memo no longer pulls the whole tick into a hold: the render effect that reads it decides. A memo nobody renders holds nothing.
isPendingorlatestalone never holds a change; a plain read beside them still does.isPendingof a memo born held joins the hold with its reader instead of reporting a verdict.- An optimistic store row's server echo is judged as reconcile would (key order free, a self-referencing row is a correction) instead of by
JSON.stringify. - An errored reader is not re-run when a transaction lands, so an errored derived store is not refetched by a row that also reads
isPending(#3945, #3962). refresh()'s promise reads the truth beneath a guess the same wayuntil()does (#3895).- An optimistic signal (
createOptimistic) judges its source's answer with its ownequals, as signals do: a server's new array or object is a correction unlessequalssays it is the same. (nextcompared every optimistic answer withJSON.stringify.) Store rows follow reconcile: equalDateobjects, or{ t: undefined }against a missing key, are corrections.
- A first load read by a render effect outside a
-
b2bec73: A render effect that reads a memo born into a held change and, in the same pass, a fresh
isPendingno longer re-runs forever while the change is held (#3969). Under the dev server every component runs inside such a memo (hot reload), so a refetch that swapped a<Show>to a fallback containing<Spinner on={isPending(x)} />tripped the "Potential Infinite Loop Detected" guard. A read of a node born held no longer counts as a staged read: there is no committed value to re-derive on. -
49a765c: A boundary's fallback is instantiated once per show. An
<Errored>whose content reads a failing async memo through a<Show>rendered its fallback twice for one failure and rebuilt it when areset()retry failed again, losing focus on the Retry button (#3991). The fallback is now built in a scope of its own beside the boundary's output and kept while it shows; a later error reaches it through the error accessor. The same holds for a<Loading>fallback across the boundary's re-derives. -
0c70907: The errored-store refetch guard lives on the store pull, so a bundle that never reads a store does not carry it
-
5a26ebe: Fix an awaited
refresh()never settling in production builds: the waiter is always created under a root, so it re-runs when the refetch lands instead of being released as an unobserved node.yield refresh(x)in an action now finishes, and the refetched value reaches the UI. -
c189013: Derived-store landings finalize their attribution flight
-
a963ec1: Fix a derived store (
createStore(fn)) whose re-fetch rejects never reachingErrored: a render effect outside the flight's flush kept showing the last value instead of throwing the derive's error, for sync-to-async and async-to-async derives alike. Memos were unaffected. -
0c70907: A row that reads an errored store field and isPending does not refetch the source
-
ad973ed: A
createSignal(fn)orcreateMemo(fn)derivation that readslatest()orisPending()of a signal an in-flight async memo is holding receives its previous value asprevon every re-run under the hold. When its first pass under the hold was equal to the previous value, the next pass received an empty internal marker instead, so(prev = []) => [...prev]threwprev is not iterableand halted the reactive system. -
39051bf: Tracked store reads keep a data value that replaced an own getter
-
ef1c297: Fix
affects(store)/affects(store, key)throwingTypeError: _.O is not a functionin tree-shaken production and observe bundles (#3891). The store half ofaffects()was installed by a side-effect-only import that bundlers drop under"sideEffects": false;affects()now installs it on its first store-targeted call, and the store half reaches the store engine through hook slots instead of importing it — so a store app that never callsaffects()carries none of it, and an app without stores never pulls in the store engine. Thanks to @nickshiro, whose #3912 proposed installing it fromaffects(). -
ade4c46: Attribution:
GRAPH_GROWTHno longer counts the previous route's computations when a navigation settles through a held transition (#3989). The navigation record still settles in the landing, but its graph walk waits for that drain's end, after the landing's commits dispose the page left — the same instant a one-drain navigation is counted. Observe tier only; no production bytes. -
eae6e03:
GRAPH_GROWTHno longer reports a route whose correctly owned content is bigger on each visit (/rows/1,/rows/3,/rows/5) when leaving it disposes everything. While the check is on, each non-initial navigation also counts what outlived it — the nodes alive when it opened that are still alive at its settle — and a series reports only when it climbs both in the totals, as before, and in that count. A navigation that stays on the route pattern (only params or query change) continues the visit and is not compared. The finding'sdatagainssurvivedbesidehistory, and its message shows both (owners 3 → 5 → 7 (of 6 → 10 → 14)). Fixes #4007. -
c9027a9: A branch a held write mounts reads the value that mounted it on every pass. A binding in the new branch of a non-keyed
<Show>that ran again before the landing — because it probesisPendingon data the same write started loading, or because a live write reached it — was served the committed screen, where the condition is stillnull, and threw into<Errored>(where an unchanged landing then left the error up). Members of the frame a held pass built are now flagged at the park seam and read their transaction's world whichever flush runs them; a verdict reader among them waits on the transaction's flight with its frame instead of being served the committed value (#4010). -
20db6a2: A Loading boundary armed by latest() leaves its fallback once the shared source settles.
-
1c14992: An async-generator action's
untilresolves when an external source echoes the optimistic row afterawait, instead of timing out on an acknowledgement the source already contains. -
d8ba741: An effect reading every row of an optimistic store no longer spins
flushforever when the source's answer moves the optimistically written row to an earlier index (#4014). The lane seam re-enqueued the leaked effect as a mainline re-derivation, so its first held read joined the parked transaction and was served the staging, and its later read of the written value re-entered the lane and leaked again, every round. A leaked effect is now re-seated in its lane, as a computed already is by its override, and reads the held slots as committed. -
e9d549f: A
createProjectionwhose re-run throws synchronously (for example, reading an entry that has since failed) now delivers the error to the readers of its fields, so the nearest<Errored>shows it instead of the screen keeping the last good value. -
c689a9a: Awaited refresh of an optimistic accessor returns the source answer, not the caller's override.
-
a2dff39: A structural store write during hydration's snapshot capture (a row removed from an array from
onSettled, byspliceorreconcile) records the container's pre-write backing as its snapshot, the way a leaf write already does. Readers inside the snapshot scope, such as a hydrated<For>, are held on the server's list until the scope is released instead of re-running mid-claim against a snapshotlengthand live items, which rendered a row forundefined, threw, and halted reactivity (#3950). A record with more than 32 keys commits such a write to a copy of its backing, so the recorded snapshot keeps the pre-write key set for a scoped reader created after the flush. -
f6905dc: isPending and latest on a superseded write do not depend on reads inside the parked computation.
-
e0a7548:
until()through a derivation of an optimistic value resolves once the source confirms the guess (#3943). A derivation's optimistic value counts as the truth when every guess it depends on has been confirmed (its source produced a value equal to the guess) and none of its other inputs has a write still held by the action; nothing is recomputed. A guess made again after a confirmation, an unconfirmed guess the derivation reads, or a held write it reads keepsuntil()waiting, as before. -
a24e911: An untracked
isPendingorlatestinside a computation is a snapshot: it no longer makes the computation re-run when one of its own dependencies goes pending. A router link claim that probes pending state while its anchor is created no longer rebuilds the<Show>around it on every refetch of its condition (#3946). Event handlers are unchanged, and a throw from an unresolved source still reaches the computation throughuntrack.