Skip to content

Release RC packages (rc) - #3067

Merged
ryansolid merged 1 commit into
nextfrom
changeset-release/next
Aug 28, 2026
Merged

Release RC packages (rc)#3067
ryansolid merged 1 commit into
nextfrom
changeset-release/next

Conversation

@github-actions

@github-actions github-actions Bot commented Aug 26, 2026

Copy link
Copy Markdown

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.

⚠️⚠️⚠️⚠️⚠️⚠️

next is currently in pre mode so this branch has prereleases rather than normal releases. If you want to exit prereleases, run changeset pre exit on next.

⚠️⚠️⚠️⚠️⚠️⚠️

Releases

@solidjs/compiler@2.0.0-rc.4

Minor Changes

  • 5455320: Register call-shaped component bindings in the refresh (HMR) pass ([compiler] transformRefresh: factory-created component exports go permanently stale in self-accepting modules #3090). A component produced by a factory call — 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 component pragma 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

  • 3a2d214: The native compiler's JS loader accepts the patchDriver option and normalizes the boolean opt-in: the Rust core supports the option (dormant by default), but validateOptions' whitelist rejected it, and the napi wrapper mapping collapses true into Wrapper::Default — which patch_driver uniquely treats as disabled. The loader now whitelists the option and maps true to the default "patchDriver" import name so an explicit opt-in through @solidjs/vite-plugin reaches the native core.
  • bfc834e: Prefer a local development build (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.
  • 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 like withDelay(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; registerServerReference now 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: Patch-channel contract hardening from the stage-2 re-audit: ordinary patchDriver registrations 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: true normalizes identically in Babel and the native loader, the option is typed in TransformOptions, and a dom-patch parity tier ratchets patch-mode output across both compilers (currently byte-identical on all fixtures).
  • b534733: Scope-wrap bare function children in hydratable mode. A function child (<main>{() => <App/>}</main>, including via the children attribute) is a deferred hole at runtime, but it never classified as dynamic, 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

  • f0c3692: Point-of-pain discovery for diagnostics: 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.
  • 8d249c7: Patch-mode list driver: keyed <For> over a store array is offered to the
    runtime's row-ops driver (create/bind at op-apply, LIS moves, node removal —
    no mapArray, no per-row owners, no DOM-side reconcile). For carries $ll
    metadata 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 and driveList (web, rxcore
    seam) for the runtime.
  • 8d249c7: Close two list-driver coverage gaps found by the JFB store scenario: setter-
    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
  • 8d249c7: Shallow store lists through the compiled driver: slot patches graduate from
    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-allocated pc extension 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 inside pc.

  • 505c73d: Fix isPending memos reading inconsistently during an action-held transition (2.0.0-rc.3 | didn't get the memo (isPending memo reads inconsistently in a transition) #3078)

    Two defects stacked in the report:

    • Untracked top-level reads of subscriber-less auto-dispose memos were destructive: 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 answer false → true → false with 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 arms schedule()), and a same-tick dirtying is reclaimed instead of recomputed, matching the old compute counts across flushes.
    • The fresh-read pairing rule (2.0.0-beta.15: 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, making createMemo(() => isPending(x)) report false while a direct isPending(x) probe reported true for 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: heldAwaitingAsync now 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 / createTrackedEffect callbacks), so setStore(...) 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 value createProjection() #3075). A projection recompute deriving from transition-held sources committed its output through the eager adoption channel, so untracked readers saw the uncommitted value after flush() 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). And latest() now works through projections: store traps never reach core read() 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 commitPendingNodes entirely) leaves entries behind after scheduled is 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 — length 0, Object.keys ["0"], the element intact. queueFold now 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 patchDriver moved out of the always-retained web runtime into patch-driver.ts, arming the insert seam lazily from rowProof/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 store
    visibility 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 next wins — 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 patchDriver registrations 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: true normalizes identically in Babel and the native loader, the option is typed in TransformOptions, and a dom-patch parity 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 as
    record 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: patchDriver no longer retains the list driver (only rowProof — the compiled marker of a patch-mode list — arms the insert seam), and the store emitters split into value hooks (armed by registerPatch) 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, so registerPatch/patchableRaw now 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 rowProof stamp (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; lateClassic remains 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-level notifyEffectStatus on every effect through ext(), allocating the full 19-field NodeExtension at 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 via statusNotifierOf (an own _x channel — 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

  • f0c3692: Point-of-pain discovery for diagnostics: 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.
  • 8d249c7: Patch-mode list driver: keyed <For> over a store array is offered to the
    runtime's row-ops driver (create/bind at op-apply, LIS moves, node removal —
    no mapArray, no per-row owners, no DOM-side reconcile). For carries $ll
    metadata 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 and driveList (web, rxcore
    seam) for the runtime.

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.
  • f3da41e: Fix mid-stream dependency changes being silently lost by hydration-latched computations. A node adopting its serialized server value re-serves it on every recompute while the stream is open (orphaning protection) — but that recompute left the node clean, so a dependency that changed during the hydration window never re-ran the compute afterwards: the change was lost, not deferred. Re-entry into the serialized-adoption path now arms the hydration-end takeover gate (the same mechanism live-branded sources use), re-running exactly the diverged nodes against their live sources once hydration completes. Applies to the default/"server" ssrSource paths; hybrid's sync/promise adopt-and-latch semantics are unchanged.
  • a10cf1a: Fix streaming SSR hanging permanently (0 bytes, 100% CPU) when a component body reads a property of a pending createProjection/createStore(asyncFn) store (2.0.0-rc.3 | createProjection SSR 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 — but createProjection allocated 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.
  • 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 mapArray exactly, where the driver previously patched them in place (a default-on compiler mode must never change observable DOM identity). For forwards its keyed prop on the list metadata; explicit keyed={fn} lists decline the driver until the accessor-row binding contract lands.
  • 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, so registerPatch/patchableRaw now 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 rowProof stamp (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; lateClassic remains only for engaged lists whose subject later leaves the contract (identity swap to a derived array, shallow/deep kind switch).
  • Updated dependencies [8d249c7]
  • Updated dependencies [f0c3692]
  • Updated dependencies [8d249c7]
  • Updated dependencies [505c73d]
  • Updated dependencies [de9e3cb]
  • Updated dependencies [0e37f90]
  • Updated dependencies [8d249c7]
  • Updated dependencies [b96d7ce]
  • Updated dependencies [8d249c7]
  • Updated dependencies [8d249c7]
  • Updated dependencies [8d249c7]
  • Updated dependencies [8d249c7]
  • Updated dependencies [8d249c7]
  • Updated dependencies [8d249c7]
  • Updated dependencies [8d249c7]
  • Updated dependencies [8d249c7]
  • Updated dependencies [8d249c7]
  • Updated dependencies [8d249c7]
  • Updated dependencies [8d249c7]
  • Updated dependencies [8d249c7]
  • Updated dependencies [8d249c7]
  • Updated dependencies [8d249c7]
  • Updated dependencies [8d249c7]
  • Updated dependencies [8d249c7]
  • Updated dependencies [8d249c7]
  • Updated dependencies [8d249c7]
  • Updated dependencies [ba6c0b6]
    • @solidjs/signals@2.0.0-rc.4

@solidjs/web@2.0.0-rc.4

Minor Changes

  • 475744c: Add 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, and priority. Longer-lived concerns are refused with a redirect to their home (prepareRequest, withMeta/GET, the data layer via signal) — never a RequestInit passthrough. Dispatch rides a registered-symbol invocation channel (SERVER_FUNCTION_INVOKE) that wrappers forward like declaration metadata, so invoke composes through GET, live, and integration wrappers that adapt it. On the server the call runs in-process: signal rejects the caller, transport hints are no-ops.
  • 8d249c7: Patch-mode list hydration: claim + register only. The list driver claims each
    server row positionally through the row's own _hk key (a row-scoped
    explicit-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 each reads and
    the 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.
  • 8d249c7: Patch-mode list driver: keyed <For> over a store array is offered to the
    runtime's row-ops driver (create/bind at op-apply, LIS moves, node removal —
    no mapArray, no per-row owners, no DOM-side reconcile). For carries $ll
    metadata 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 and driveList (web, rxcore
    seam) for the runtime.
  • 8d249c7: Close two list-driver coverage gaps found by the JFB store scenario: setter-
    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
  • 8d249c7: Shallow store lists through the compiled driver: slot patches graduate from
    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 fetch option'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 option selected — 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 the value="" placeholder option selected, 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 useHead coexists 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 (raw firstChild/nextSibling chains 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-dh without the data-dhf in-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 like withDelay(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; registerServerReference now 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 patchDriver moved out of the always-retained web runtime into patch-driver.ts, arming the insert seam lazily from rowProof/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 next wins — 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 patchDriver registrations 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: true normalizes identically in Babel and the native loader, the option is typed in TransformOptions, and a dom-patch parity 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 mapArray exactly, where the driver previously patched them in place (a default-on compiler mode must never change observable DOM identity). For forwards its keyed prop on the list metadata; explicit keyed={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: patchDriver no longer retains the list driver (only rowProof — the compiled marker of a patch-mode list — arms the insert seam), and the store emitters split into value hooks (armed by registerPatch) 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, so registerPatch/patchableRaw now 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 rowProof stamp (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; lateClassic remains 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 to Cache-Control: no-store unless the function set its own cache policy, and GET/HEAD requests to GET-declared functions skip the CSRF origin gate so their responses no longer carry the Vary: Sec-Fetch-Site, Origin, Referer that 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 and http.route labels 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, and endpoint now gates dispatch on both halves: a request whose path does not start with it is not a call.

    serverFunctionUrl(id, boundArgs?) and parseServerFunctionUrl(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 lone FormData, so a method="get" submit reaches the function it addresses. Which reading applies is decided by the url alone, never by a header; args stays reserved on the query, and a value under it that is not an argument array answers 400.

  • 82b4e14: Add fetch to configureServerFunctionsClient: 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, and parseServerFunctionUrl reads the id back out for telemetry. null restores 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 forwards init — the call's signal rides 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 endpoint documentation 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 Location of its own, and the passthrough would have handed it back as control flow. Redirects are left alone — fetch follows 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.Void marks the one response the runtime encodes without a format to carry — a function that returned nothing — so respond(undefined, { status: 400 }) stays a result alongside new Response(null, { status: 404 }) and respond(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-Raw response at a non-2xx status, which an integration's responseHandler claims 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]

    • solid-js@2.0.0-rc.4

@solidjs/babel-plugin@2.0.0-rc.4

Patch Changes

  • 8d249c7: Patch-channel contract hardening from the stage-2 re-audit: ordinary patchDriver registrations 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: true normalizes identically in Babel and the native loader, the option is typed in TransformOptions, and a dom-patch parity tier ratchets patch-mode output across both compilers (currently byte-identical on all fixtures).
  • b534733: Scope-wrap bare function children in hydratable mode. A function child (<main>{() => <App/>}</main>, including via the children attribute) is a deferred hole at runtime, but it never classified as dynamic, 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

  • Updated dependencies [475744c]
  • Updated dependencies [8d249c7]
  • Updated dependencies [54506e0]
  • Updated dependencies [f0c3692]
  • Updated dependencies [0043643]
  • Updated dependencies [8d249c7]
  • Updated dependencies [f3da41e]
  • Updated dependencies [505c73d]
  • Updated dependencies [a10cf1a]
  • Updated dependencies [de9e3cb]
  • Updated dependencies [0e37f90]
  • Updated dependencies [c9b4f2a]
  • Updated dependencies [8d249c7]
  • Updated dependencies [b96d7ce]
  • Updated dependencies [8c48a2e]
  • Updated dependencies [8d249c7]
  • Updated dependencies [2f01f23]
  • Updated dependencies [8d249c7]
  • Updated dependencies [8d249c7]
  • Updated dependencies [8d249c7]
  • Updated dependencies [8d249c7]
  • Updated dependencies [8d249c7]
  • Updated dependencies [8d249c7]
  • Updated dependencies [8d249c7]
  • Updated dependencies [8d249c7]
  • Updated dependencies [8d249c7]
  • Updated dependencies [8d249c7]
  • Updated dependencies [8d249c7]
  • Updated dependencies [8d249c7]
  • Updated dependencies [8d249c7]
  • Updated dependencies [8d249c7]
  • Updated dependencies [8d249c7]
  • Updated dependencies [8d249c7]
  • Updated dependencies [8d249c7]
  • Updated dependencies [8d249c7]
  • Updated dependencies [b534733]
  • Updated dependencies [258c76a]
  • Updated dependencies [79b96cf]
  • Updated dependencies [82b4e14]
  • Updated dependencies [8d249c7]
  • Updated dependencies [8d249c7]
  • Updated dependencies [8d249c7]
  • Updated dependencies [ba6c0b6]
  • Updated dependencies [c07edcb]
    • @solidjs/web@2.0.0-rc.4
    • @solidjs/signals@2.0.0-rc.4
    • solid-js@2.0.0-rc.4
    • @solidjs/babel-plugin@2.0.0-rc.4
    • @solidjs/h@2.0.0-rc.4
    • @solidjs/html@2.0.0-rc.4
    • @solidjs/universal@2.0.0-rc.4

@github-actions
github-actions Bot force-pushed the changeset-release/next branch 13 times, most recently from 9d91a53 to d6ee6c7 Compare August 27, 2026 06:54
@socket-security

socket-security Bot commented Aug 27, 2026

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addednpm/​@​solidjs/​compiler-darwin-arm64@​2.0.0-rc.4N/AN/AN/AN/AN/A
Addednpm/​@​solidjs/​compiler-darwin-x64@​2.0.0-rc.4N/AN/AN/AN/AN/A
Addednpm/​@​solidjs/​compiler-linux-arm64-gnu@​2.0.0-rc.4N/AN/AN/AN/AN/A
Addednpm/​@​solidjs/​compiler-linux-x64-gnu@​2.0.0-rc.4N/AN/AN/AN/AN/A
Addednpm/​@​solidjs/​compiler-wasm32-wasi@​2.0.0-rc.4N/AN/AN/AN/AN/A
Addednpm/​@​solidjs/​compiler-win32-x64-msvc@​2.0.0-rc.4N/AN/AN/AN/AN/A

View full report

@github-actions
github-actions Bot force-pushed the changeset-release/next branch 16 times, most recently from 697dce2 to a4e72d0 Compare August 28, 2026 16:28
@github-actions
github-actions Bot force-pushed the changeset-release/next branch 2 times, most recently from 5ccc24c to 51b8316 Compare August 28, 2026 17:31
@github-actions
github-actions Bot force-pushed the changeset-release/next branch from 51b8316 to 6da89e8 Compare August 28, 2026 18:38
@ryansolid
ryansolid merged commit c0b998e into next Aug 28, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant