Release RC packages (rc) - #3067
Merged
Merged
Conversation
github-actions
Bot
force-pushed
the
changeset-release/next
branch
13 times, most recently
from
August 27, 2026 06:54
9d91a53 to
d6ee6c7
Compare
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
github-actions
Bot
force-pushed
the
changeset-release/next
branch
16 times, most recently
from
August 28, 2026 16:28
697dce2 to
a4e72d0
Compare
github-actions
Bot
force-pushed
the
changeset-release/next
branch
2 times, most recently
from
August 28, 2026 17:31
5ccc24c to
51b8316
Compare
github-actions
Bot
force-pushed
the
changeset-release/next
branch
from
August 28, 2026 18:38
51b8316 to
6da89e8
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR was opened by the Changesets release GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to next, this PR will be updated.
nextis currently in pre mode so this branch has prereleases rather than normal releases. If you want to exit prereleases, runchangeset pre exitonnext.Releases
@solidjs/compiler@2.0.0-rc.4
Minor Changes
styled(...), an HOC, a tagged template — was never registered, and once a registered sibling made the module self-accept,hot.accept()disabled the very module invalidation its staleness relied on: the export went permanently stale, silently. Two compile-time admission gates fix this. A call-shaped top-level binding rendered as a JSX tag in its own module is proven a component and registers automatically (resolution is scope-aware — shadowing locals don't count). For export-only shapes with no in-module usage, the per-binding@refresh componentpragma asserts it:export const Badge = /* @refresh component */ styled.span\...``. Registered call bindings get the full treatment — location, granular signature, and dependencies, with same-module registered components excluded from the dependency set (edits propagate through the proxy chain; counting them would remount the consumer on every edit of the module). This is a deliberate native-first divergence from the frozen Babel-plugin reference.Patch Changes
patchDriveroption and normalizes the boolean opt-in: the Rust core supports the option (dormant by default), butvalidateOptions' whitelist rejected it, and the napi wrapper mapping collapsestrueintoWrapper::Default— whichpatch_driveruniquely treats as disabled. The loader now whitelists the option and mapstrueto the default"patchDriver"import name so an explicit opt-in through@solidjs/vite-pluginreaches the native core.compiler.node) over the installed@solidjs/compiler-*platform package when loading the native binding. The published package ships no local binary, so a local build can only mean development — but the loader tried the platform package first, which made the monorepo's own tests (locally and in CI) silently run against the last published release instead of the code under test. A present-but-unloadable local build now fails loudly instead of degrading to the published binary.export const getUser = withValidation(schema, fn)applies the wrapper to HTTP dispatch and in-process SSR calls alike, and patterns likewithDelay(fn, 400)work for server mocks. The client build always emits bare references, so wrappers, schemas, and helpers stay server-only by construction. The compiler never inspects the initializer's shape;registerServerReferencenow throws at module eval when handed a non-function, turning stray non-function exports into loud boot errors instead of dead references. Anonymous default expressions (export default withDelay(...),export default async () => ...) get a synthesized binding and register too — previously they were silently dropped from both builds. Supersedes the unreleased wrapped-export compile error.patchDriverregistrations unbind with their owner (entries no longer leak past unmount); merged transitions move their held-patch stash so no patch strands; the optimistic drain shares the normal drain's per-entry error isolation and boundary routing; accessor-bearing records are excluded at admission (scan-before-trust) and records that acquire accessors demote their patches to tracked effect fallbacks; writable projection arrays emit setter row ops at their fold-commit visibility moment; row-ops/slot registrations resolve chained backings to the ultimate owner; duplicate keys match occurrence-aware instead of first-wins; the production dev-token typo (_DX_DEV_) is fixed;patchDriver: truenormalizes identically in Babel and the native loader, the option is typed inTransformOptions, and adom-patchparity tier ratchets patch-mode output across both compilers (currently byte-identical on all fixtures).<main>{() => <App/>}</main>, including via thechildrenattribute) is a deferred hole at runtime, but it never classified asdynamic, so neither generate reserved an id scope for it — its owner ids drifted across async retry passes on the server and desynced from the client (the 2.0.0-beta.19: SSR: async retry paths re-run computes without resetting owner child state — hydration id drift (4 sites) #2900 hydration-id-parity class). Both compilers now treat syntactic function expressions as scope-eligible alongside dynamic values, emitting_$scope(...)in the ssr generate and around the matching insert accessor in the dom generate. The native compiler also unwraps TS casts in the allocate-ids predicate, matching Babel (fixes a scope-emission desync for{call() as any}children).@solidjs/signals@2.0.0-rc.4
Minor Changes
DEV.diagnostics.setConsoleFooter(fn)registers a footer printed once per diagnostic code after that code's first console report. solid-js registers a footer in dev pointing at its shipped repair skill (node_modules/solid-js/skills/reactivity-diagnostics/SKILL.md), so anyone — human or agent — hitting a diagnostic warning learns where the prescribed fix lives without prior knowledge of the skill system.<For>over a store array is offered to theruntime's row-ops driver (create/bind at op-apply, LIS moves, node removal —
no mapArray, no per-row owners, no DOM-side reconcile).
Forcarries$llmetadata on a lazy classic accessor so unaware renderers and declined lists
(non-store subject, impure rows proven by a bind-time owner probe, fallback
or index usage) fall through to today's mapArray path unchanged. Array
identity swaps keep keyed semantics by raw-identity matching. Adds
ownerIsBlank(signals) for the purity probe anddriveList(web, rxcoreseam) for the runtime.
channel structural mutation (push/splice/index assignment/permutation) now
emits identity-keyed row ops at the fold — a driven list stays DOM-correct
for stores mutated without reconcile — and empty-initial lists engage
TENTATIVELY, deferring the purity probe to the first created row, with a
late decline handing the region to the classic mapArray path through the
runtime's re-entry thunk
prototype to channel semantics (key-aligned value-replaced slots only —
structure rides row ops — queued at effect phase under the registration
owner), and the list driver collects a shallow row's compiled bodies at bind
(rows are raw; nothing to register on) and dispatches them from the array's
slot channel, rebasing indices with structural ops. Adds storeIsShallow;
kind-changing subject swaps (shallow <-> deep) hand off to classic.
Patch Changes
8d249c7: External-audit fixes on the patch-list driver surface: family (projection/optimistic) arrays now decline the driver — their structural changes emit no row/slot ops and the proxy identity is stable, so an engaged list would freeze on optimistic or projection structure (classic mapArray handles them correctly, including on identity-swap handoff). Shallow slot-patch registration is now multi-consumer — two driven lists over one shallow array previously overwrote each other's channel. Adds
storeHasFamily(with server stub) and regression tests for both.8d249c7: Group the write-side patch-channel fields (
wk,p,ro,sp) into one lazily-allocatedpcextension on store targets and delete the dead prototype binding registry (b). Array proxy targets carry their fields as named properties on a real array, and V8 normalizes arrays to dictionary properties as the named count grows — at 24 fields every trap read had become a hash lookup (~15% uibench, tree-heavy scenarios worst). The target is capped at 20 named fields with the shape rule documented; future patch-channel state goes insidepc.505c73d: Fix
isPendingmemos reading inconsistently during an action-held transition (2.0.0-rc.3 | didn't get the memo (isPendingmemo reads inconsistently in a transition) #3078)Two defects stacked in the report:
read()tore the node down inline (unobserved) and the next read revived it with a full recompute in the ambient transition/lane context, so consecutive reads could answerfalse → true → falsewith no write in between. Reads now queue the node for a re-validating dormancy sweep at the top of the next flush — reads are idempotent within a tick, the leak protection is preserved (reclamation within one microtask; the enqueue armsschedule()), and a same-tick dirtying is reclaimed instead of recomputed, matching the old compute counts across flushes.isPending(() => latest(x))is inconsistent across node shapes #2831/2.0.0-rc.1 isPending in Show when not working outside topmost Loading #3028) suppressed the pending verdict for any compute that saw a staged plain write while an action still held the transition, makingcreateMemo(() => isPending(x))reportfalsewhile a directisPending(x)probe reportedtruefor the whole action window. A plain signal's staged write is an input to a computation still in flight, not a landed answer awaiting reveal:heldAwaitingAsyncnow treats an unsettled action as "still computing" for input-staged (non-computed) nodes, while a computed's landed async answer keeps the pairing rule even inside an open action.de9e3cb: Fix projection stores leaking unsettled writes to effect-phase readers (2.0.0-rc.3 | ready or not here I come - reading a store key in transition returns uncommitted value unlike signal #3082)
A derived (projection) store's pending backing is authoritative-elect and served to context-free readers, but that clause also caught CHILDREN_FORBIDDEN execution scopes (
onSettled/createTrackedEffectcallbacks), sosetStore(...)followed by a read inside the callback returned the staged draft while a signal write in the same scope correctly read committed. Projection reads in those scopes now get committed visibility, restoring the 2.0.0-rc.0 | royal flush - inconsistent read/write in onSettled #3006 contract (a callback never observes its own unsettled write) and store/signal parity.0e37f90: Fix projection transition isolation and
latest()parity (2.0.0-rc.3 | projection leaks after flush while in transition #3074, 2.0.0-rc.3 |latest()does not work on projected valuecreateProjection()#3075). A projection recompute deriving from transition-held sources committed its output through the eager adoption channel, so untracked readers saw the uncommitted value afterflush()while reads of the source signal correctly stayed committed. Adoption under a live hold now stages a held view: committed-visibility readers keep the pre-hold backing until the transition commits (speculative readers — drafts, owner-context computeds,latest()— see the adopted backing). Andlatest()now works through projections: store traps never reach coreread()without an observer, so the get trap pulls the projection computed up to date under the latest window and serves the in-flight derivation — signal/memo parity.8d249c7: Fix shallow slot-patch emission racing row creation: appended positions past a fully-aligned prefix (vacuously aligned when the previous list was empty) emitted slot value-ticks for rows that do not exist yet — the slot queue applies before the row ops that create them, crashing the list driver on clear-then-refill and pure appends. Slots now dispatch only for indices with a previous slot; appends are structure-only. Found by the driver/classic equivalence matrix.
b96d7ce: Fix store folds silently stranding while any transition is in flight (Projection/derived-store recomputes are lane-captured by unrelated in-flight transitions (committed rail serves torn state) #3089). The fold queue armed a drain only when it was empty, assuming every drain clears it — but a held re-queue or an incomplete-transition flush (which skips
commitPendingNodesentirely) leaves entries behind afterscheduledis consumed, and every later fold was then queued without ever scheduling a drain: the committed backing froze at stale state (a derived store's seed) while its nodes committed, and readers on different rails saw torn state —length0,Object.keys["0"], the element intact.queueFoldnow always arms the scheduler, and folds carry a write-time transition stamp so drafts written under a still-running transition — including unobserved keys, which have no pending node for the drain's held check to see — defer to that transition's settle instead of landing in whichever flush drains next.8d249c7: Optimistic family arrays are drivable by the patch-mode list driver, completing the family channel: structural optimism (push/splice/reorder/replace in optimistic drafts) emits identity-diffed row ops at lane timing from the override channel — visible in flight, bypassing the transition stash like optimistic record patches — and reverts emit an identity RESYNC the driver resolves against the live post-revert view. The driver binds optimistic lists from the optimistic view (classic reads the same view through the proxy), and the identity-swap matcher is shared between swaps and resyncs. Equivalence matrix extended with async optimistic scenarios (mounted → in-flight → settled, revert and land, element-level and parent-key structural writes).
8d249c7: Patch channel is pay-for-use: the list driver and
patchDrivermoved out of the always-retained web runtime intopatch-driver.ts, arming the insert seam lazily fromrowProof/patchDriver(which only compiled patch-mode output imports); the store's emitters ride hooks installed at first registration (patch-hooks.ts) instead of static imports. Apps without patch-mode output retain only a ~100 B insert hook; the store write-path seams cost ~490 B on the store floor. Before this, every client app carried the full driver (~2.4 KB brotli).8d249c7: Stage 2 (PR-A): the patch channel. Compiled per-record patch consumers
(
registerPatch, undocumented compiler-contract export) dispatched by storevisibility transitions at all four sites: adoption walk and setter notify
(plain stores, with ancestor bubbling for targeted nested writes), fold
commit (projections — held folds hold their patches), and the override
lifecycle (application emits the visible draft; consumption and engine
reverts force-reapply from the live view). Application timing: per-flush
apply queue at render-effect phase; transition-stamped emissions release
when THEIR batch commits (reverted transactions drop by GC); optimistic
emissions drain at lane-effect timing so in-flight visibility works while
actions stash the regular queues. Unpatched stores pay a null check and the
module tree-shakes out of non-store bundles. Gauntlet: effect-phase timing,
reconcile prev pairing, nested-write bubbling, unbind/multi-consumer,
transition hold, optimistic in-flight + DOM revert, projection refetch,
disposed-owner drop.
8d249c7: Second re-audit hardening of the patch channel: adoption seams demote accessor-bearing adoptees to tracked effects in development, with a loud diagnostic (production emits directly — per-adoption accessor scans cost ~12% of dbmon's tick, and getter-bearing adoptees on patched records are a development-caught shape); setter-returned root replacements and chained-store swaps emit their patches and row ops at fold commit; the list driver's ops application builds every new row before any destructive step (a throwing row factory leaves DOM and bookkeeping atomically unchanged); patch errors route to the nearest computed ancestor so
Errored.reset()can recompute it (reset also skips non-computed sources), and unhandled patch errors halt like unhandled effect errors; key equality is SameValueZero and occurrence-aware everywhere keys compare — NaN keys stay retained and duplicate keys adopt per occurrence on both channels; same-batch duplicate patch emissions coalesce (one application per batch, effect parity).8d249c7: Third re-audit hardening of the patch channel: same-batch coalescing updates the queued entry in place (latest
nextwins — adoption replaces the captured object, so dropping later emissions applied stale state) and the drain clears the channel stamps (no batch retention on quiet records); the adoption remainder window builds from the misalignment point so prefix-consumed rows are never re-offered to duplicate keys; optimistic tentative matching gains SameValueZero + occurrence-aware parity with the plain channel; a failed row-ops application forces an identity resync on the next update (the store committed the failed topology while DOM kept the old one — positional ops would mis-index) and suppresses slot ticks until the baseline is restored; a throwing row factory also severs its own partial registrations.8d249c7: Fifth-round hardening of the patch channel: no-op adoptions (A→B→A in one batch) clear the adopted flag so later setter row ops never freeze a driven list; transition merges retarget the moved entries' coalescing stamps (post-merge emissions coalesce instead of double-applying at commit); multi-consumer patch dispatch snapshots the registration list (a callback unbinding a sibling no longer skips consumers); the list driver's initial construction severs partial registrations on throw like update-time builds (one failed initial render no longer elevates patchCount globally); a failed apply actively resyncs from the next slot tick instead of waiting for a structural update; and identity swaps register the new subject's channels before applying so a throwing swap stays recoverable.
8d249c7: Patch-channel contract hardening from the stage-2 re-audit: ordinary
patchDriverregistrations unbind with their owner (entries no longer leak past unmount); merged transitions move their held-patch stash so no patch strands; the optimistic drain shares the normal drain's per-entry error isolation and boundary routing; accessor-bearing records are excluded at admission (scan-before-trust) and records that acquire accessors demote their patches to tracked effect fallbacks; writable projection arrays emit setter row ops at their fold-commit visibility moment; row-ops/slot registrations resolve chained backings to the ultimate owner; duplicate keys match occurrence-aware instead of first-wins; the production dev-token typo (_DX_DEV_) is fixed;patchDriver: truenormalizes identically in Babel and the native loader, the option is typed inTransformOptions, and adom-patchparity tier ratchets patch-mode output across both compilers (currently byte-identical on all fixtures).8d249c7: Stage 2 (PR-B): row ops. The keyed adoption walk emits structural list ops
(
registerRowOps: prefix, sources, removed) through the same apply queue asrecord patches — aligned value ticks emit nothing; consumers apply minimal
DOM moves via one LIS over data ops instead of re-deriving moves from DOM
node arrays. Measured on dbmon: sort 10.7 → 4.5ms, remount 25.7 → 9.3ms
(octane 4.0/8.5), while ticks stay ahead (3.0/0.9 vs 3.2/1.3).
8d249c7: Patch-channel semantics completion: a throwing patch now routes through its
registering owner's queue chain to the enclosing error boundary (render-
effect parity; sibling isolation preserved, unhandled errors still rethrow),
and the dual-driver effect fallback splits phases with the same compiled
body — a next===prev read pass tracks in compute, the force apply writes in
the effect phase where transitions and batching expect DOM writes
8d249c7: Patch-channel held emissions stash directly on their transition object
instead of a WeakMap — the every-flush commit-hook check becomes one
property read, and reverted transitions drop their stash with the object
8d249c7: Patch-channel arming is two-tier so the default-on cost stays proportional:
patchDriverno longer retains the list driver (onlyrowProof— the compiled marker of a patch-mode list — arms the insert seam), and the store emitters split into value hooks (armed byregisterPatch) and row hooks (armed by list registrations), so non-list patch templates never retain row binding, LIS, or reconcile's diff builders. Flip-preview size scenarios pin both tiers.8d249c7: Projection (non-optimistic) family arrays are drivable by the patch-mode list driver: their recomputes walk reconcile, whose row/slot emissions were never family-gated and ride the transition-stamped apply queue. The blanket family decline narrows to optimistic families only (
storeHasOptimisticFamily), whose user writes ride node overrides and emit no structural ops. Fixes chained-backing patch registration: a projection wrapper's backing is another store's proxy, soregisterPatch/patchableRawnow resolve through the chain to the ultimate owner target — patches registered on wrapped projection rows previously never fired (value transitions fold on the source). Equivalence matrix extended with 13 projection scenarios including recompute-driven structure and retention topology.8d249c7: The reconcile walk's patch-emission guards short-circuit on the installed-hooks binding before touching target fields, so stores without any patch consumer pay no per-record loads in the adoption walk (CodSpeed caught −7.7% on the 12k-path listened-paths bench).
8d249c7: Patch-mode list admission moves entirely to compile time: driveList engages only for row functions carrying the compiler's
rowProofstamp (exported from @solidjs/web), and the runtime purity probe is deleted — no speculative execution of user row code, no probeMark/probeGate seams, no ownerIsBlank, no tentative empty-list engagement with late decline. Unstamped rows take the classic mapArray path before any DOM work;lateClassicremains only for engaged lists whose subject later leaves the contract (identity swap to a derived array, shallow/deep kind switch).8d249c7: The shallow branch's slot-alignment prefix compares keys with SameValueZero: strict equality broke alignment on NaN keys, suppressing the slot's value ticks while the ops builder retained the row — a permanently stale DOM row (found by a full-surface self-sweep of every key-comparison site).
ba6c0b6: Effects dispatch status through one shared notifier instead of storing it per node:
effect()stored the module-levelnotifyEffectStatuson every effect throughext(), allocating the full 19-fieldNodeExtensionat every effect creation — +127 B/node and +23% effect creation time, shipped unnoticed with the stage-3 cold-field split. Status walks now resolve the notifier viastatusNotifierOf(an own_xchannel — boundaries — wins; effect nodes fall back to the shared one), which preserves the walks' display-consumer membership semantics exactly. Effect nodes drop to 488 B (below even the pre-stage-3 528) and creation recovers to ~1.07 ms/10k from 1.26.solid-js@2.0.0-rc.4
Minor Changes
DEV.diagnostics.setConsoleFooter(fn)registers a footer printed once per diagnostic code after that code's first console report. solid-js registers a footer in dev pointing at its shipped repair skill (node_modules/solid-js/skills/reactivity-diagnostics/SKILL.md), so anyone — human or agent — hitting a diagnostic warning learns where the prescribed fix lives without prior knowledge of the skill system.<For>over a store array is offered to theruntime's row-ops driver (create/bind at op-apply, LIS moves, node removal —
no mapArray, no per-row owners, no DOM-side reconcile).
Forcarries$llmetadata on a lazy classic accessor so unaware renderers and declined lists
(non-store subject, impure rows proven by a bind-time owner probe, fallback
or index usage) fall through to today's mapArray path unchanged. Array
identity swaps keep keyed semantics by raw-identity matching. Adds
ownerIsBlank(signals) for the purity probe anddriveList(web, rxcoreseam) for the runtime.
Patch Changes
storeHasFamily(with server stub) and regression tests for both.ssrSourcepaths; hybrid's sync/promise adopt-and-latch semantics are unchanged.createProjection/createStore(asyncFn)store (2.0.0-rc.3 |createProjectionSSR flush-loop hang — reading a property of a pending projection proxy re-allocates the projection every pass #3068). An async projection can never be ready at creation-scope read time, so the read threw NotReadyError and the retry re-ran the scope — butcreateProjectionallocated a fresh generator, deferred, and serialized promise on every pass, so the read could never succeed and the flush loop spun forever. Server projections now keep by-slot flight memory (the NodeJS OOM crashes with Solid V2 when ssr: true #3003 memo mechanism): a re-created projection at a known slot returns the same in-flight proxy — one generator run, one trace, one serialized channel — and post-settle passes read through it synchronously.mapArrayexactly, where the driver previously patched them in place (a default-on compiler mode must never change observable DOM identity).Forforwards itskeyedprop on the list metadata; explicitkeyed={fn}lists decline the driver until the accessor-row binding contract lands.storeHasOptimisticFamily), whose user writes ride node overrides and emit no structural ops. Fixes chained-backing patch registration: a projection wrapper's backing is another store's proxy, soregisterPatch/patchableRawnow resolve through the chain to the ultimate owner target — patches registered on wrapped projection rows previously never fired (value transitions fold on the source). Equivalence matrix extended with 13 projection scenarios including recompute-driven structure and retention topology.rowProofstamp (exported from @solidjs/web), and the runtime purity probe is deleted — no speculative execution of user row code, no probeMark/probeGate seams, no ownerIsBlank, no tentative empty-list engagement with late decline. Unstamped rows take the classic mapArray path before any DOM work;lateClassicremains only for engaged lists whose subject later leaves the contract (identity swap to a derived array, shallow/deep kind switch).@solidjs/web@2.0.0-rc.4
Minor Changes
invoke(fn, options, ...args)— the per-call server function invocator (RFC 10 follow-up: support per-call server function cancellation #3057). Applies one call with invocation-scoped options:signal(aborting rejects the call and cancels the request; ends a live source's iteration across reconnects),keepalive, andpriority. Longer-lived concerns are refused with a redirect to their home (prepareRequest,withMeta/GET, the data layer viasignal) — never aRequestInitpassthrough. Dispatch rides a registered-symbol invocation channel (SERVER_FUNCTION_INVOKE) that wrappers forward like declaration metadata, soinvokecomposes throughGET,live, and integration wrappers that adapt it. On the server the call runs in-process:signalrejects the caller, transport hints are no-ops.server row positionally through the row's own
_hkkey (a row-scopedexplicit-id owner makes the compiled template's getNextElement resolve it),
and patchDriver skips the initial force-apply while hydrating — server HTML
stays the truth until the first transition. All driver-side
eachreads andthe probe are id-isolated (throwaway/private explicit-id owners), so lazily
minted prop-getter memos can no longer shift the ambient hydration id chain
on either the engage or decline path.
<For>over a store array is offered to theruntime's row-ops driver (create/bind at op-apply, LIS moves, node removal —
no mapArray, no per-row owners, no DOM-side reconcile).
Forcarries$llmetadata on a lazy classic accessor so unaware renderers and declined lists
(non-store subject, impure rows proven by a bind-time owner probe, fallback
or index usage) fall through to today's mapArray path unchanged. Array
identity swaps keep keyed semantics by raw-identity matching. Adds
ownerIsBlank(signals) for the purity probe anddriveList(web, rxcoreseam) for the runtime.
channel structural mutation (push/splice/index assignment/permutation) now
emits identity-keyed row ops at the fold — a driven list stays DOM-correct
for stores mutated without reconcile — and empty-initial lists engage
TENTATIVELY, deferring the purity probe to the first created row, with a
late decline handing the region to the classic mapArray path through the
runtime's re-entry thunk
prototype to channel semantics (key-aligned value-replaced slots only —
structure rides row ops — queued at effect phase under the registration
owner), and the list driver collects a shallow row's compiled bodies at bind
(rows are raw; nothing to register on) and dispatches them from the array's
slot channel, rebasing indices with structural ops. Adds storeIsShallow;
kind-changing subject swaps (shallow <-> deep) hand off to classic.
Patch Changes
8d249c7: External-audit fixes on the patch-list driver surface: family (projection/optimistic) arrays now decline the driver — their structural changes emit no row/slot ops and the proxy identity is stable, so an engaged list would freeze on optimistic or projection structure (classic mapArray handles them correctly, including on identity-swap handoff). Shallow slot-patch registration is now multi-consumer — two driven lists over one shallow array previously overwrote each other's channel. Adds
storeHasFamily(with server stub) and regression tests for both.54506e0: Clarify invoke's wrapper contract: declaration wrappers (GET, live) forward the invocation channel mechanically (1:1 call mapping); wrappers that share calls (deduping caches, multicast channels) opt in deliberately or decline, and invoke's error now directs callers to the underlying reference or the wrapper's own idioms.
0043643: Document two boundaries of the client
fetchoption's contract: a retrying wrapper may re-send a request that got no response but must never replay one whose response ended (mid-body death may have executed a mutation; live-source reconnection is the runtime's job), and the call-to-request mapping is delivery detail, not contract.c9b4f2a: SSR
<select value>resolution now handles empty-string bound values (SSR emits<select value="…">as an attribute and never marks an optionselected— the server markup shows the wrong option #3013 follow-up). Empty attribute values serialize as bare attributes (<select value>,<option value>), which the flush-time pass didn't recognize — a bound''never marked thevalue=""placeholder optionselected, so the pre-hydration page showed the first option while app state said''. The pass now reads the bare form as the empty string on both the select and its options, matching React's SSR output for the single-select placeholder pattern.8c48a2e: Fix whole-document hydration dying when
useHeadcoexists with shell-authored<head>children (useHead+ shell-authored<head>children: SSR order breaks whole-document hydration #3081). A charset/base registration is spliced as a prelude immediately after the<head>open tag — a deliberate byte-placement constraint — landing it ahead of every head child the shell authored itself. The compiled head traversal is positional (rawfirstChild/nextSiblingchains in production), so the prepended tag shifted every read by one and hydration for the whole document died on a null read.hydrate()now moves the registry-inserted leading run (data-dhwithout thedata-dhfin-place-rewrite stash) to the end of head before any claiming: the parser already consumed the byte-placement guarantees, the moved metas are inert in an unrendered element, and the walk sees exactly the shell's authored children. The in-place rewritten static<title>keeps its stash, its position, and its claim.8d249c7: The list driver's identity matching unwraps store proxies on both sides — draft-authored permutations store row proxies verbatim, and matching them against raw records rebuilt every surviving row (caught by the JFB keyed-reorder identity gate).
2f01f23: Module-level "use server" exports now register by value: the server build registers each export's evaluated terminal initializer whole, so server-side wrappers compose onto every call path —
export const getUser = withValidation(schema, fn)applies the wrapper to HTTP dispatch and in-process SSR calls alike, and patterns likewithDelay(fn, 400)work for server mocks. The client build always emits bare references, so wrappers, schemas, and helpers stay server-only by construction. The compiler never inspects the initializer's shape;registerServerReferencenow throws at module eval when handed a non-function, turning stray non-function exports into loud boot errors instead of dead references. Anonymous default expressions (export default withDelay(...),export default async () => ...) get a synthesized binding and register too — previously they were silently dropped from both builds. Supersedes the unreleased wrapped-export compile error.8d249c7: Optimistic family arrays are drivable by the patch-mode list driver, completing the family channel: structural optimism (push/splice/reorder/replace in optimistic drafts) emits identity-diffed row ops at lane timing from the override channel — visible in flight, bypassing the transition stash like optimistic record patches — and reverts emit an identity RESYNC the driver resolves against the live post-revert view. The driver binds optimistic lists from the optimistic view (classic reads the same view through the proxy), and the identity-swap matcher is shared between swaps and resyncs. Equivalence matrix extended with async optimistic scenarios (mounted → in-flight → settled, revert and land, element-level and parent-key structural writes).
8d249c7: Patch channel is pay-for-use: the list driver and
patchDrivermoved out of the always-retained web runtime intopatch-driver.ts, arming the insert seam lazily fromrowProof/patchDriver(which only compiled patch-mode output imports); the store's emitters ride hooks installed at first registration (patch-hooks.ts) instead of static imports. Apps without patch-mode output retain only a ~100 B insert hook; the store write-path seams cost ~490 B on the store floor. Before this, every client app carried the full driver (~2.4 KB brotli).8d249c7: Second re-audit hardening of the patch channel: adoption seams demote accessor-bearing adoptees to tracked effects in development, with a loud diagnostic (production emits directly — per-adoption accessor scans cost ~12% of dbmon's tick, and getter-bearing adoptees on patched records are a development-caught shape); setter-returned root replacements and chained-store swaps emit their patches and row ops at fold commit; the list driver's ops application builds every new row before any destructive step (a throwing row factory leaves DOM and bookkeeping atomically unchanged); patch errors route to the nearest computed ancestor so
Errored.reset()can recompute it (reset also skips non-computed sources), and unhandled patch errors halt like unhandled effect errors; key equality is SameValueZero and occurrence-aware everywhere keys compare — NaN keys stay retained and duplicate keys adopt per occurrence on both channels; same-batch duplicate patch emissions coalesce (one application per batch, effect parity).8d249c7: Third re-audit hardening of the patch channel: same-batch coalescing updates the queued entry in place (latest
nextwins — adoption replaces the captured object, so dropping later emissions applied stale state) and the drain clears the channel stamps (no batch retention on quiet records); the adoption remainder window builds from the misalignment point so prefix-consumed rows are never re-offered to duplicate keys; optimistic tentative matching gains SameValueZero + occurrence-aware parity with the plain channel; a failed row-ops application forces an identity resync on the next update (the store committed the failed topology while DOM kept the old one — positional ops would mis-index) and suppresses slot ticks until the baseline is restored; a throwing row factory also severs its own partial registrations.8d249c7: Fifth-round hardening of the patch channel: no-op adoptions (A→B→A in one batch) clear the adopted flag so later setter row ops never freeze a driven list; transition merges retarget the moved entries' coalescing stamps (post-merge emissions coalesce instead of double-applying at commit); multi-consumer patch dispatch snapshots the registration list (a callback unbinding a sibling no longer skips consumers); the list driver's initial construction severs partial registrations on throw like update-time builds (one failed initial render no longer elevates patchCount globally); a failed apply actively resyncs from the next slot tick instead of waiting for a structural update; and identity swaps register the new subject's channels before applying so a throwing swap stays recoverable.
8d249c7: Patch-channel contract hardening from the stage-2 re-audit: ordinary
patchDriverregistrations unbind with their owner (entries no longer leak past unmount); merged transitions move their held-patch stash so no patch strands; the optimistic drain shares the normal drain's per-entry error isolation and boundary routing; accessor-bearing records are excluded at admission (scan-before-trust) and records that acquire accessors demote their patches to tracked effect fallbacks; writable projection arrays emit setter row ops at their fold-commit visibility moment; row-ops/slot registrations resolve chained backings to the ultimate owner; duplicate keys match occurrence-aware instead of first-wins; the production dev-token typo (_DX_DEV_) is fixed;patchDriver: truenormalizes identically in Babel and the native loader, the option is typed inTransformOptions, and adom-patchparity tier ratchets patch-mode output across both compilers (currently byte-identical on all fixtures).8d249c7: Patch-channel semantics completion: a throwing patch now routes through its
registering owner's queue chain to the enclosing error boundary (render-
effect parity; sibling isolation preserved, unhandled errors still rethrow),
and the dual-driver effect fallback splits phases with the same compiled
body — a next===prev read pass tracks in compute, the force apply writes in
the effect phase where transitions and batching expect DOM writes
8d249c7: Patch-mode lists now implement the identity semantics the view declares instead of the reconcile key's. Deep lists are unaffected (adoption preserves proxy identity, so key ops and reference semantics coincide). Shallow reference-keyed lists rebuild rows whose records were replaced — matching classic
mapArrayexactly, where the driver previously patched them in place (a default-on compiler mode must never change observable DOM identity).Forforwards itskeyedprop on the list metadata; explicitkeyed={fn}lists decline the driver until the accessor-row binding contract lands.8d249c7: Patch-channel arming is two-tier so the default-on cost stays proportional:
patchDriverno longer retains the list driver (onlyrowProof— the compiled marker of a patch-mode list — arms the insert seam), and the store emitters split into value hooks (armed byregisterPatch) and row hooks (armed by list registrations), so non-list patch templates never retain row binding, LIS, or reconcile's diff builders. Flip-preview size scenarios pin both tiers.8d249c7: Patch-mode lists retain per-row unbind handles: a record the app keeps beyond its row's life no longer holds a live patch registration updating detached DOM — registrations are severed on row removal, contract-leave handoffs, and list disposal. Dev builds also warn when a stamped row's build attaches computations or cleanups to the shared list owner (owned work in handler/attribute value position is unsupported in patch-mode rows).
8d249c7: Projection (non-optimistic) family arrays are drivable by the patch-mode list driver: their recomputes walk reconcile, whose row/slot emissions were never family-gated and ride the transition-stamped apply queue. The blanket family decline narrows to optimistic families only (
storeHasOptimisticFamily), whose user writes ride node overrides and emit no structural ops. Fixes chained-backing patch registration: a projection wrapper's backing is another store's proxy, soregisterPatch/patchableRawnow resolve through the chain to the ultimate owner target — patches registered on wrapped projection rows previously never fired (value transitions fold on the source). Equivalence matrix extended with 13 projection scenarios including recompute-driven structure and retention topology.8d249c7: Patch-mode list admission moves entirely to compile time: driveList engages only for row functions carrying the compiler's
rowProofstamp (exported from @solidjs/web), and the runtime purity probe is deleted — no speculative execution of user row code, no probeMark/probeGate seams, no ownerIsBlank, no tentative empty-list engagement with late decline. Unstamped rows take the classic mapArray path before any DOM work;lateClassicremains only for engaged lists whose subject later leaves the contract (identity swap to a derived array, shallow/deep kind switch).258c76a: Harden the server function handler's HTTP layer. The method gate is now an allowlist: POST always dispatches, GET and HEAD dispatch only to
GET-declared functions, and every other verb answers 405 — previously a HEAD (or PUT/DELETE/PATCH) request bypassed the GET gate entirely and executed any registered function with attacker-chosen query arguments (HEAD requests bypass the server function method gate and execute any registered function #3069). HEAD runs the function like GET and strips the body per spec. Responses now default toCache-Control: no-storeunless the function set its own cache policy, and GET/HEAD requests toGET-declared functions skip the CSRF origin gate so their responses no longer carry theVary: Sec-Fetch-Site, Origin, Refererthat fragmented shared-cache entries — declared reads are protected by same-origin policy, and caching becomes opt-in on the wire instead of just in prose (Server function responses ship no Cache-Control, and a CSRF Vary that defeats GET caching #3071).79b96cf: Address server function calls by path:
<endpoint>/<id>, with arguments staying in the query.The id travelled in
X-Server-Function-Id, with?id=as the fallback for requests the client runtime did not make. Both are gone; it moves into the path — what per-function edge rules, cache policies andhttp.routelabels key on — leaving one place in the request that carries it, so a cache in front of the app cannot be made to store one function's response under another's key (X-Server-Function-Id overrides the id in the URL, making it an unkeyed input to a cacheable response #3070). POST addresses move too, andendpointnow gates dispatch on both halves: a request whose path does not start with it is not a call.serverFunctionUrl(id, boundArgs?)andparseServerFunctionUrl(url)ship on both entries for integrations composing action urls. A GET call whose url would exceed 2000 characters dispatches over POST instead, marked as a read — a cache miss rather than a 414.A read whose query is not an argument encoding hands that query to the function as a lone
URLSearchParams, the read-side mirror of a no-JS form post decoding to a loneFormData, so amethod="get"submit reaches the function it addresses. Which reading applies is decided by the url alone, never by a header;argsstays reserved on the query, and a value under it that is not an argument array answers 400.82b4e14: Add
fetchtoconfigureServerFunctionsClient: the function the transport sends every server-function request with, typed and called as(address, init)— the address relative to the document, as the global one receives it — so an ordinary fetch wrapper drops in, a hand-written one needs no casts, andparseServerFunctionUrlreads the id back out for telemetry.nullrestores the global.An app-shaped url is what makes it worth a seam: the handler takes a web
Request, so a route that rewrites into the canonical address dispatches like any other call, and nothing downstream — the router's action-url interception, the plugin's dev middleware, the generated dispatch gate — has to learn a second address format. A wrapper forwardsinit— the call'ssignalrides on it — keeps the call same-origin, and hands back what the peer answered, unread. The seam is the client transport's exit only: a server-side call runs in process and never reaches a fetch.Also tidies the
endpointdocumentation on both entries, which the path-addressing change left saying the same thing twice.c07edcb: Fail a server function call on a response the runtime did not write, instead of resolving it to
undefined(A response the runtime did not produce resolves the call to undefined instead of failing #3087).Only the protocol's error header and a 5xx counted as failure, so every other non-2xx was decoded as a result — and decoding a login page, or an empty 405, yields nothing. A response at 400 or above carrying no body format now fails the call with the status on the error, undecoded, and before the passthrough control flow uses: a refusal can carry a
Locationof its own, and the passthrough would have handed it back as control flow. Redirects are left alone —fetchfollows them, so an interstitial arrives as its page at 200, and a 3xx only reaches the transport where something opted out of following one.BodyFormat.Voidmarks the one response the runtime encodes without a format to carry — a function that returned nothing — sorespond(undefined, { status: 400 })stays a result alongsidenew Response(null, { status: 404 })andrespond(value, { status: 400 }). A client that predates the tag decodes it the same way; a client that has it, talking to a server that does not, reads an untagged void 4xx as a refusal.A 2xx is not judged at all: a login page served at 200 is indistinguishable from a void result by header alone. One runtime-produced shape is caught with the foreign ones — a verbatim
X-Content-Rawresponse at a non-2xx status, which an integration'sresponseHandlerclaims before the check.Updated dependencies [8d249c7]
Updated dependencies [f0c3692]
Updated dependencies [f3da41e]
Updated dependencies [a10cf1a]
Updated dependencies [8d249c7]
Updated dependencies [8d249c7]
Updated dependencies [8d249c7]
Updated dependencies [8d249c7]
@solidjs/babel-plugin@2.0.0-rc.4
Patch Changes
patchDriverregistrations unbind with their owner (entries no longer leak past unmount); merged transitions move their held-patch stash so no patch strands; the optimistic drain shares the normal drain's per-entry error isolation and boundary routing; accessor-bearing records are excluded at admission (scan-before-trust) and records that acquire accessors demote their patches to tracked effect fallbacks; writable projection arrays emit setter row ops at their fold-commit visibility moment; row-ops/slot registrations resolve chained backings to the ultimate owner; duplicate keys match occurrence-aware instead of first-wins; the production dev-token typo (_DX_DEV_) is fixed;patchDriver: truenormalizes identically in Babel and the native loader, the option is typed inTransformOptions, and adom-patchparity tier ratchets patch-mode output across both compilers (currently byte-identical on all fixtures).<main>{() => <App/>}</main>, including via thechildrenattribute) is a deferred hole at runtime, but it never classified asdynamic, so neither generate reserved an id scope for it — its owner ids drifted across async retry passes on the server and desynced from the client (the 2.0.0-beta.19: SSR: async retry paths re-run computes without resetting owner child state — hydration id drift (4 sites) #2900 hydration-id-parity class). Both compilers now treat syntactic function expressions as scope-eligible alongside dynamic values, emitting_$scope(...)in the ssr generate and around the matching insert accessor in the dom generate. The native compiler also unwraps TS casts in the allocate-ids predicate, matching Babel (fixes a scope-emission desync for{call() as any}children).@solidjs/diagnostics@2.0.0-rc.4
Patch Changes
@solidjs/element@2.0.0-rc.4
Patch Changes
@solidjs/h@2.0.0-rc.4
Patch Changes
@solidjs/html@2.0.0-rc.4
Patch Changes
@solidjs/universal@2.0.0-rc.4
Patch Changes
test-integration@2.0.0-rc.4
Patch Changes