Skip to content

Release RC packages (rc) - #3921

Open
github-actions[bot] wants to merge 1 commit into
nextfrom
changeset-release/next
Open

github-actions[bot] wants to merge 1 commit into
nextfrom
changeset-release/next

Conversation

@github-actions

@github-actions github-actions Bot commented Oct 8, 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/babel-plugin@2.0.0-rc.15

Patch Changes

  • 617d195: Emit element claims after the element's initial attributes are applied (Client element claims fire before dynamic attributes are applied, and only href/action writes re-claim #3923), at parity across both compilers.

    A fully static a[href] / form[action] is claimed at the end of its creation statements (after static writes and refs). An element with dynamic bindings captures its owner at creation (var _o$ = _$getOwner()) and is claimed as the last statement of its binding effect's callback — _$claimElement(_el$, _o$) — in both the single-binding and the multi-binding shapes, so the claim observes the applied values on the first run whether that run is synchronous or lands from a held flush. An element carrying a spread emits no compiled claim: the spread runtime claims it after the first application.

  • 43570f8: Reapply a select's bound value when its options arrive after the value was written.

  • 22f942d: SSR: a router can mark links in server HTML (SSR: let the router mark links in server HTML (a guarded claim hole for anchors, with a per-render handler) #3878). Element claims never fire during SSR, so plain anchors arrived without aria-current="page" / data-active — late on hydrated pages, never on pages that do not hydrate. Both compilers now give every candidate <a href> in SSR output one hole after its attributes, ssrLinkClaim(attrs), where a render's link handler writes the anchor's link state and "" otherwise. A static anchor's hole is one eager call over a hoisted attributes object (no allocation per render); a dynamic anchor's joins the element's attribute group and reuses the raw value its href hole evaluated. Anchors the compiler can rule out — a static non-empty target, a download, a rel naming external, an author-written aria-current, an empty href or a non-HTTP scheme — get no hole at all. The hole creates no owner and takes no hydration id. A spread anchor's link attributes are collected by ssrElement from its winning sources (an anchor's trailing link attributes stay a source instead of baked tail markup).

    New server API (@experimental): setLinkClaim(handler) sets the handler of the render the caller belongs to — found through the owner chain like getHydrationWriter(), so concurrent renders never share one — and returns false outside a render; undefined clears it. The handler, (attrs) => string, receives the anchor's link-relevant attributes (href, target, rel, download, link, aria-current, raw values as written) and returns its attribute markup. An author-written aria-current always wins. Server components inline in the document render under the page's handler; a server component's own frame stream has none unless its render sets one.

    Trust marker: the first setLinkClaim of a render writes the links hydration record once (_$HY.r.links = 1, with the shell's hydration script on the document face, a data record on a frame stream). hasServerLinkState() (client; false on the server) reads it non-destructively, so a link consumer can tell "this page's anchors carry the server's link state" from "no handler ran" and trust the HTML at hydration instead of resolving every anchor's URL at claim. Without a handler the HTML and the hydration ids are byte-for-byte what they were.

@solidjs/compiler@2.0.0-rc.15

Patch Changes

  • 617d195: Emit element claims after the element's initial attributes are applied (Client element claims fire before dynamic attributes are applied, and only href/action writes re-claim #3923), at parity across both compilers.

    A fully static a[href] / form[action] is claimed at the end of its creation statements (after static writes and refs). An element with dynamic bindings captures its owner at creation (var _o$ = _$getOwner()) and is claimed as the last statement of its binding effect's callback — _$claimElement(_el$, _o$) — in both the single-binding and the multi-binding shapes, so the claim observes the applied values on the first run whether that run is synchronous or lands from a held flush. An element carrying a spread emits no compiled claim: the spread runtime claims it after the first application.

  • 43570f8: Reapply a select's bound value when its options arrive after the value was written.

  • 15e1228: The native compiler no longer drops a component ref whose value is wrapped in a TypeScript as cast, non-null ! or satisfies, such as ref={[setRef, props.ref] as any}; it classified the wrapper instead of the value inside and emitted no ref prop. The universal generate also keeps array refs on components and unwraps as and ! on element refs, so <view ref={myRef as any} /> assigns the element to myRef, as the Babel plugin does.

  • 0c4bff7: Add lazyModule() so a lazy module that is not a component can be preloaded and hydrated by module id.

  • 22f942d: SSR: a router can mark links in server HTML (SSR: let the router mark links in server HTML (a guarded claim hole for anchors, with a per-render handler) #3878). Element claims never fire during SSR, so plain anchors arrived without aria-current="page" / data-active — late on hydrated pages, never on pages that do not hydrate. Both compilers now give every candidate <a href> in SSR output one hole after its attributes, ssrLinkClaim(attrs), where a render's link handler writes the anchor's link state and "" otherwise. A static anchor's hole is one eager call over a hoisted attributes object (no allocation per render); a dynamic anchor's joins the element's attribute group and reuses the raw value its href hole evaluated. Anchors the compiler can rule out — a static non-empty target, a download, a rel naming external, an author-written aria-current, an empty href or a non-HTTP scheme — get no hole at all. The hole creates no owner and takes no hydration id. A spread anchor's link attributes are collected by ssrElement from its winning sources (an anchor's trailing link attributes stay a source instead of baked tail markup).

    New server API (@experimental): setLinkClaim(handler) sets the handler of the render the caller belongs to — found through the owner chain like getHydrationWriter(), so concurrent renders never share one — and returns false outside a render; undefined clears it. The handler, (attrs) => string, receives the anchor's link-relevant attributes (href, target, rel, download, link, aria-current, raw values as written) and returns its attribute markup. An author-written aria-current always wins. Server components inline in the document render under the page's handler; a server component's own frame stream has none unless its render sets one.

    Trust marker: the first setLinkClaim of a render writes the links hydration record once (_$HY.r.links = 1, with the shell's hydration script on the document face, a data record on a frame stream). hasServerLinkState() (client; false on the server) reads it non-destructively, so a link consumer can tell "this page's anchors carry the server's link state" from "no handler ran" and trust the HTML at hydration instead of resolving every anchor's URL at claim. Without a handler the HTML and the hydration ids are byte-for-byte what they were.

@solidjs/diagnostics@2.0.0-rc.15

Patch Changes

  • 84dada7: The browser bridge keeps shared references in the payload it transfers. toSerializable treated every object it had already written as a cycle and dropped it, so a LONG_HOLD diagnostic, whose data carries the hold's own blockers and acknowledgements arrays, left the hold record in attribution.holds without them, and expectNoSilentHolds threw a TypeError on any browser capture that recorded a long hold. The serializer now tracks only the ancestors of the value being written: an object reached twice is written twice, and only an object that contains itself is dropped.
  • Updated dependencies [ad973ed]
  • Updated dependencies [b2bec73]
  • Updated dependencies [617d195]
  • Updated dependencies [a497d4b]
  • Updated dependencies [4afc662]
  • Updated dependencies [b460640]
  • Updated dependencies [0c70907]
  • Updated dependencies [a14c18b]
  • Updated dependencies [5a26ebe]
  • Updated dependencies [c189013]
  • Updated dependencies [a963ec1]
  • Updated dependencies [39450e5]
  • Updated dependencies [0c70907]
  • Updated dependencies [469733e]
  • Updated dependencies [cbd66e5]
  • Updated dependencies [ad973ed]
  • Updated dependencies [43570f8]
  • Updated dependencies [b083833]
  • Updated dependencies [39051bf]
  • Updated dependencies [ef1c297]
  • Updated dependencies [abe12fc]
  • Updated dependencies [f64fcfe]
  • Updated dependencies [0c4bff7]
  • Updated dependencies [20db6a2]
  • Updated dependencies [3173a14]
  • Updated dependencies [5d75ed8]
  • Updated dependencies [1c14992]
  • Updated dependencies [86ac6da]
  • Updated dependencies [c2d4571]
  • Updated dependencies [e9d549f]
  • Updated dependencies [c689a9a]
  • Updated dependencies [49bed5c]
  • Updated dependencies [43570f8]
  • Updated dependencies [b749474]
  • Updated dependencies [234cfc9]
  • Updated dependencies [22f942d]
  • Updated dependencies [d966729]
  • Updated dependencies [a405039]
  • Updated dependencies [a2dff39]
  • Updated dependencies [234cfc9]
  • Updated dependencies [f6905dc]
  • Updated dependencies [e0a7548]
  • Updated dependencies [a24e911]
  • Updated dependencies [234cfc9]
    • @solidjs/signals@2.0.0-rc.15
    • @solidjs/web@2.0.0-rc.15
    • solid-js@2.0.0-rc.15

@solidjs/element@2.0.0-rc.15

Patch Changes

@solidjs/h@2.0.0-rc.15

Patch Changes

  • a497d4b: Remove state, noscroll, replace, and preload from core anchor JSX types. They are not standard <a> attributes; a routing integration declares them by augmenting AnchorHTMLAttributes. link stays — it is the shared explicit-links opt-in, and the SSR claim bag already copies that name. Media and webview preload attributes are unchanged. Types only.
  • Updated dependencies [617d195]
  • Updated dependencies [a497d4b]
  • Updated dependencies [4afc662]
  • Updated dependencies [a14c18b]
  • Updated dependencies [469733e]
  • Updated dependencies [43570f8]
  • Updated dependencies [abe12fc]
  • Updated dependencies [f64fcfe]
  • Updated dependencies [3173a14]
  • Updated dependencies [5d75ed8]
  • Updated dependencies [86ac6da]
  • Updated dependencies [c2d4571]
  • Updated dependencies [49bed5c]
  • Updated dependencies [43570f8]
  • Updated dependencies [b749474]
  • Updated dependencies [234cfc9]
  • Updated dependencies [22f942d]
  • Updated dependencies [234cfc9]
    • @solidjs/web@2.0.0-rc.15

@solidjs/html@2.0.0-rc.15

Patch Changes

@solidjs/signals@2.0.0-rc.15

Patch Changes

  • ad973ed: Async holds follow the reader, and are shorter:

    • A first load read by a render effect outside a <Loading> makes the change that mounted it wait (the async answer of a memo created under a hold lands with that hold); a <Loading> that has not shown content catches it instead and shows its fallback.
    • Creating a memo no longer pulls the whole tick into a hold: the render effect that reads it decides. A memo nobody renders holds nothing.
    • isPending or latest alone never holds a change; a plain read beside them still does.
    • isPending of a memo born held joins the hold with its reader instead of reporting a verdict.
    • An optimistic store row's server echo is judged as reconcile would (key order free, a self-referencing row is a correction) instead of by JSON.stringify.
    • An errored reader is not re-run when a transaction lands, so an errored derived store is not refetched by a row that also reads isPending ([2.0 rc.14 / next] Errored derived store re-fetches in an endless loop when a row binding also reads isPending() #3945, [next] After #3954, a reader re-queued by a derived store's rejection sees the errored store as settled #3962).
    • refresh()'s promise reads the truth beneath a guess the same way until() does ([2.0 next, regressed after rc.13] Awaited refresh returns the caller optimistic override #3895).
    • An optimistic signal (createOptimistic) judges its source's answer with its own equals, as signals do: a server's new array or object is a correction unless equals says it is the same. (next compared every optimistic answer with JSON.stringify.) Store rows follow reconcile: equal Date objects, or { t: undefined } against a missing key, are corrections.
  • b2bec73: A render effect that reads a memo born into a held change and, in the same pass, a fresh isPending no longer re-runs forever while the change is held ([2.0 next] Flush loop guard trips when a pending indicator component mounts during a refetch #3969). Under the dev server every component runs inside such a memo (hot reload), so a refetch that swapped a <Show> to a fallback containing <Spinner on={isPending(x)} /> tripped the "Potential Infinite Loop Detected" guard. A read of a node born held no longer counts as a staged read: there is no committed value to re-derive on.

  • 0c70907: The errored-store refetch guard lives on the store pull, so a bundle that never reads a store does not carry it

  • 5a26ebe: Fix an awaited refresh() never settling in production builds: the waiter is always created under a root, so it re-runs when the refetch lands instead of being released as an unobserved node. yield refresh(x) in an action now finishes, and the refetched value reaches the UI.

  • c189013: Derived-store landings finalize their attribution flight

  • a963ec1: Fix a derived store (createStore(fn)) whose re-fetch rejects never reaching Errored: a render effect outside the flight's flush kept showing the last value instead of throwing the derive's error, for sync-to-async and async-to-async derives alike. Memos were unaffected.

  • 0c70907: A row that reads an errored store field and isPending does not refetch the source

  • ad973ed: A createSignal(fn) or createMemo(fn) derivation that reads latest() or isPending() of a signal an in-flight async memo is holding receives its previous value as prev on every re-run under the hold. When its first pass under the hold was equal to the previous value, the next pass received an empty internal marker instead, so (prev = []) => [...prev] threw prev is not iterable and halted the reactive system.

  • 39051bf: Tracked store reads keep a data value that replaced an own getter

  • ef1c297: Fix affects(store) / affects(store, key) throwing TypeError: _.O is not a function in tree-shaken production and observe bundles ([2.0 next, regressed after rc.13] Production tree shaking removes store affects registration (production build) #3891). The store half of affects() was installed by a side-effect-only import that bundlers drop under "sideEffects": false; affects() now installs it on its first store-targeted call, and the store half reaches the store engine through hook slots instead of importing it — so a store app that never calls affects() carries none of it, and an app without stores never pulls in the store engine. Thanks to @nickshiro, whose fix(signals): retain store affects registration in production bundles #3912 proposed installing it from affects().

  • 20db6a2: A Loading boundary armed by latest() leaves its fallback once the shared source settles.

  • 1c14992: An async-generator action's until resolves when an external source echoes the optimistic row after await, instead of timing out on an acknowledgement the source already contains.

  • e9d549f: A createProjection whose re-run throws synchronously (for example, reading an entry that has since failed) now delivers the error to the readers of its fields, so the nearest <Errored> shows it instead of the screen keeping the last good value.

  • c689a9a: Awaited refresh of an optimistic accessor returns the source answer, not the caller's override.

  • a2dff39: A structural store write during hydration's snapshot capture (a row removed from an array from onSettled, by splice or reconcile) records the container's pre-write backing as its snapshot, the way a leaf write already does. Readers inside the snapshot scope, such as a hydrated <For>, are held on the server's list until the scope is released instead of re-running mid-claim against a snapshot length and live items, which rendered a row for undefined, threw, and halted reactivity ([2.0 rc.14 / next] A store write from onSettled during hydration makes a hydrated <For> render a phantom row and halts reactivity #3950). A record with more than 32 keys commits such a write to a copy of its backing, so the recorded snapshot keeps the pre-write key set for a scoped reader created after the flush.

  • f6905dc: isPending and latest on a superseded write do not depend on reads inside the parked computation.

  • e0a7548: until() through a derivation of an optimistic value resolves once the source confirms the guess (2.0.0-rc.14: until() through a synchronous memo misses optimistic confirmation #3943). A derivation's optimistic value counts as the truth when every guess it depends on has been confirmed (its source produced a value equal to the guess) and none of its other inputs has a write still held by the action; nothing is recomputed. A guess made again after a confirmation, an unconfirmed guess the derivation reads, or a held write it reads keeps until() waiting, as before.

  • a24e911: An untracked isPending or latest inside a computation is a snapshot: it no longer makes the computation re-run when one of its own dependencies goes pending. A router link claim that probes pending state while its anchor is created no longer rebuilds the <Show> around it on every refetch of its condition (fix(signals): an untracked isPending or latest does not re-derive its reader #3946). Event handlers are unchanged, and a throw from an unresolved source still reaches the computation through untrack.

solid-js@2.0.0-rc.15

Patch Changes

  • 4afc662: Move dynamicComponent into solid-js. @solidjs/web keeps dynamic and re-exports dynamicComponent.

  • b460640: A rejection contained by <Errored> is no longer reported as unhandled when the boundary shares a {props.children} slot with an async sibling during SSR ([2.0 rc.14 / next] SSR: a rejection contained by <Errored> is still an unhandled rejection when an async sibling shares its children slot (exits Node) #3973). While its holes were pending, the server boundary threw a combined promise that the slot retry could drop, so its rejection exited Node even though the fallback rendered. The combined promise is now marked handled where it is created; anything that awaits it still sees the rejection.

  • 39450e5: Keep an SSR Errored fallback's hydration ids when its children slot is retried.

  • cbd66e5: Preserve mounted context IDs during hot module evaluation, before another module can refresh a consumer. Previously a consumer refreshing before the context module's accept callback could throw ContextNotFoundError or read the context's default instead of the provided value. Unmounted context registrations retain fresh IDs for entry-module remounts.

  • b083833: Non-keyed Show judges staleness from the truthiness that selected the child, so a first mount of when={latest(x)} renders and a live update does not look stale

  • 0c4bff7: Add lazyModule() so a lazy module that is not a component can be preloaded and hydrated by module id.

  • b749474: Pin seroval and seroval-plugins to exactly 1.6.7: 1.6.8 changed the stream representation in a patch release and grew bundles. Stream detection now requires a real stream — the JSON decoder (server functions, frames) treats a value as a stream only when seroval's isStream holds and it has a callable .on, so decoded plain data that happens to carry a __SEROVAL_STREAM__ key stays data. The frames container-trace check, the client container-trace materializer and the render stream's channel guard also recognize seroval's untagged stream class, and the frames border walk tests for an async iterator first.

  • 234cfc9: The server-component half of hydration installs from @solidjs/web/frames' installServerComponents(), not from hydrate(): sharedConfig.holdBoundary (the client hold on adopted markup counted as a pending boundary), sharedConfig.hydrateWindow (the claim window an adopted occurrence re-enters hydration through), fragment ownership by rendering (the _$HY.fa term of the reveal policy) and the ledger's published answer _$HY.fr on the solid side; the declared claim roots (sharedConfig.claimRoots) and the frame-region exclusion of the root sweep on the DOM runtime's side. A hydrating page without server components carries none of it — −686 B minified / ≈ −205…−243 B brotli on the hydrating apps (this returns the bytes the frames A0 correctness pass added to every hydrating page); a server-component page pays the two installers' glue (≈ +220 B minified).

    Public surface (@internal): enableServerComponentHydration() on solid-js (runtime) and solid-js/internal (typed), a no-op on the server entry; installServerComponentHydration() on @solidjs/web, which installs both halves — the frames client calls it where it installs its reveal hook.

  • d966729: On the server, a render effect's retry and a projection's re-derive (createProjection, createStore(fn), createOptimisticStore(fn)) run under their own render's context once a pending source settles, as an async memo's retry already does ([2.0 rc.14 / next] SSR: async memo retries run under another concurrent render's context #3972). Under concurrent requests they ran under whichever render set the context last, so anything the pass created took the other request's hydration ids.

  • a405039: On the server, an async memo's retry (when its source settles) runs under its own render's context instead of whichever concurrent render set it last ([2.0 rc.14 / next] SSR: async memo retries run under another concurrent render's context #3972). Under concurrent requests, slot content created by the retry took the other request's hydration ids, which could leave the server spinning or fail hydration with "Hydration key miss".

  • 234cfc9: The store hydration adapters (createStore(fn) / createProjection / createOptimisticStore(fn) under hydration: snapshot adoption, the parked patch backlog, the hybrid handoff) move to their own source module, and solid-js/internal/container-trace — the frames traces tier's materializer, a lazy chunk — bundles its own copy of it instead of reading the eager slot enableHydration() fills through withStoreHydration. Reading the slot from the lazy chunk pinned every adapter into the entry chunk of a server-component page that never creates a client store (an app bundler keeps a module eager whenever an eager module imports it); the copy is inert by construction — the adapters declare no module-level state, and every piece of shared state is read back from the one solid-js instance. −2,550 B minified / ≈ −575 B brotli on the compiled server-component page; 0 on pages whose root pass creates a derived store (they keep the eager install); the lazy trace.js chunk grows ≈ 0.5 KB brotli.

    Public surface (@internal, stripped from the declarations): withStoreHydration is removed from the solid-js client and server entries (its only consumer was the trace entry); the client entry gains the runtime exports the adapter copy reads — readSerializedOrCompute, subFetch, readHydratedValue, wrapFirstYield, adoptedAnswerStream, withHydrationGate, onHydrationEnd, noHydrationId, markTopLevelSnapshotScope, hasLoadingWindow, isAsyncIterable, syncThenable, UNASKED — mirrored on the server entry as inert stubs for export parity.

  • Updated dependencies [ad973ed]

  • Updated dependencies [b2bec73]

  • Updated dependencies [0c70907]

  • Updated dependencies [5a26ebe]

  • Updated dependencies [c189013]

  • Updated dependencies [a963ec1]

  • Updated dependencies [0c70907]

  • Updated dependencies [ad973ed]

  • Updated dependencies [39051bf]

  • Updated dependencies [ef1c297]

  • Updated dependencies [20db6a2]

  • Updated dependencies [1c14992]

  • Updated dependencies [e9d549f]

  • Updated dependencies [c689a9a]

  • Updated dependencies [a2dff39]

  • Updated dependencies [f6905dc]

  • Updated dependencies [e0a7548]

  • Updated dependencies [a24e911]

    • @solidjs/signals@2.0.0-rc.15

@solidjs/universal@2.0.0-rc.15

Patch Changes

@solidjs/web@2.0.0-rc.15

Patch Changes

  • 617d195: Element claims fire after an element's initial attributes are applied, and the attributes whose writes re-claim are consumer-declared (Client element claims fire before dynamic attributes are applied, and only href/action writes re-claim #3923).

    A claim consumer (a router's link-state layer) is told about each a[href] / form[action] once per mount — with its dynamic href, target, rel, … already applied — instead of at creation before the binding effect's first run. Compiled output claims a static element at creation, an element with bindings at the tail of its binding effect's first run (under the owner captured at creation, since a held mount lands ownerless), and spread claims an a/form it applies after the first application (so dynamic("a") anchors are covered too). Writes before the mount claim never re-claim.

    Public API:

    • registerElementClaim(handler, options?) takes an options bag: { attributes?: readonly string[] } names the attributes whose compiler-owned writes (setAttribute, setAttributeNS, setProperty, the spread's property path) re-claim an already claimed element — plain names; prop:href and xlink:href map to href. The write sites consult the union of every registered consumer's set. Default stays ["href", "action"], so existing consumers keep today's behaviour. New exported type ElementClaimOptions.
    • claimElement(node, owner?) (compiler-emitted primitive, @internal) takes the optional reactive owner the handlers run under.

    Without a registered consumer every hook folds away: the three every-page size scenarios (app: CSR, app: compiled CSR, app: compiled hydrating) are byte-identical.

  • a497d4b: Remove state, noscroll, replace, and preload from core anchor JSX types. They are not standard <a> attributes; a routing integration declares them by augmenting AnchorHTMLAttributes. link stays — it is the shared explicit-links opt-in, and the SSR claim bag already copies that name. Media and webview preload attributes are unchanged. Types only.

  • 4afc662: Move dynamicComponent into solid-js. @solidjs/web keeps dynamic and re-exports dynamicComponent.

  • a14c18b: A 304 from a server function no longer stamps a body-format header onto the cache update, so a browser replaying a cached GET still decodes the stored value.

  • 469733e: Fix aborting a document that renders a live server component crashing Node: the document's sc:live channel now marks itself closed when the abort cancels it, so the render's own end (and any late hole op) no longer closes or writes the cancelled stream, which escaped as an unhandled ERR_INVALID_STATE rejection.

  • 43570f8: Reapply a select's bound value when its options arrive after the value was written.

  • abe12fc: Frames client: the adopt-time slot walk reads the server's tier announcement for the scan, not only the load — a page whose sc:tiers record names other tiers and not bind is never scanned for binding-slot markers (_s:*), and the bind tier is never loaded for it; an un-announced page keeps detection. collectSlots is one TreeWalker pass over comments (and elements only when markers may exist), testing a comment's data by prefix before any regex. Same slots found, in the same order; no public API change. Measured on the HN story page (652 occurrences, 17k comments): collectSlots 14.2 → 5.4 ms.

  • f64fcfe: Fix an unbounded request loop when a server component's re-asked flight fails the same way as the error it replaces. The server writes an escaped render failure as its message string, so two flights that fail alike carry equal payloads; a mount's content node told "already surfaced" from "the next flight's error" by the payload and re-asked on every flight instead of surfacing the error. It now keys a surfaced error by the response version that carried it: reset(), and a fresh mount over an errored address (e.g. after a hover preload that failed), make one request and the error reaches the nearest <Errored> again.

  • 3173a14: A server component factory mounted more than once keeps an independent hydrated client slot at each site. The first site still uses the function id; each later site gets its own frame scope so hydration keys, slot records, and adoption do not collide.

  • 5d75ed8: A nested server region keeps its own stream version, so a same-argument refetch no longer makes the next argument's region look stale.

  • 86ac6da: Frames (document adoption): gather an adopted boundary's hydration keys once per adoption, not once per occurrence. Each adopted occurrence's claim window used to select [_hk^="<prefix>"] over the whole hydration root — 37 ms on a 652-occurrence comment thread, more than the rest of its hydration. The boundary now indexes the _hk nodes under its element once (bucketed by occurrence prefix) and serves every window — the occurrence's and a streamed <Loading>'s resume inside it — from that index; a fragment revealed into the element later extends the index for the revealed parent, so late (post-done) claims still find their nodes. The page-level gather and the streamed boundary's resume path are unchanged.

  • c2d4571: A synchronous prepareRequest hook no longer defers the server-function request by a microtask, so reads adopted during hydration stay inside the hydration trace instead of refetching from the browser ([2.0 rc.14 / next] A synchronous prepareRequest hook makes every hydrated server-function read refetch in the browser #3959). An async hook is still awaited.

  • 49bed5c: respond() is typed as its value and its envelope is a real Response; direct calls unwrap it.

    • Direct calls unwrap envelopes. A server function called in-process during SSR that returned respond(value) handed its caller the ResponseEnvelope itself, while an HTTP caller decoded value — and a server component wrapped for its headers (respond(View, { headers })) reached the render as an object, so the frames policy never branded it and the hydration serializer failed on the envelope. The direct leg now resolves with the value (a thrown envelope rejects with it) before transformDirectResult runs. Of the metadata, Set-Cookie is appended to the render's response head; other headers describe the function's own address and the status is the page's, so neither is applied to the document.
    • The envelope is a Response. ResponseEnvelope now extends Response, carrying the given response's body, status and headers, so a consumer with no Solid knowledge (a fetch-style API dispatch) answers with it as-is instead of JSON-encoding the wrapper. new ResponseEnvelope(response, value) keeps its signature; response is the envelope itself, or undefined when constructed without one. Solid's own consumers still recognize it with isResponseEnvelope().
    • The helpers are typed by what they mean to the caller. respond<T>() returns T, and redirect()/reload() are <T = never>(…): T — control flow, not values, so they vanish from the returning function's inferred type, while an annotated return or a Response-typed request handler supplies T (a literal never would also mark code after a bare call unreachable). A bare "use server" function's own signature is therefore its callers' type, with no wrapper narrowing (NarrowResponse) needed. At runtime the helpers are unchanged.
  • 43570f8: Keep every bound value of a multi-select selected when its options arrive later.

  • b749474: Pin seroval and seroval-plugins to exactly 1.6.7: 1.6.8 changed the stream representation in a patch release and grew bundles. Stream detection now requires a real stream — the JSON decoder (server functions, frames) treats a value as a stream only when seroval's isStream holds and it has a callable .on, so decoded plain data that happens to carry a __SEROVAL_STREAM__ key stays data. The frames container-trace check, the client container-trace materializer and the render stream's channel guard also recognize seroval's untagged stream class, and the frames border walk tests for an async iterator first.

  • 234cfc9: The server-component half of hydration installs from @solidjs/web/frames' installServerComponents(), not from hydrate(): sharedConfig.holdBoundary (the client hold on adopted markup counted as a pending boundary), sharedConfig.hydrateWindow (the claim window an adopted occurrence re-enters hydration through), fragment ownership by rendering (the _$HY.fa term of the reveal policy) and the ledger's published answer _$HY.fr on the solid side; the declared claim roots (sharedConfig.claimRoots) and the frame-region exclusion of the root sweep on the DOM runtime's side. A hydrating page without server components carries none of it — −686 B minified / ≈ −205…−243 B brotli on the hydrating apps (this returns the bytes the frames A0 correctness pass added to every hydrating page); a server-component page pays the two installers' glue (≈ +220 B minified).

    Public surface (@internal): enableServerComponentHydration() on solid-js (runtime) and solid-js/internal (typed), a no-op on the server entry; installServerComponentHydration() on @solidjs/web, which installs both halves — the frames client calls it where it installs its reveal hook.

  • 22f942d: SSR: a router can mark links in server HTML (SSR: let the router mark links in server HTML (a guarded claim hole for anchors, with a per-render handler) #3878). Element claims never fire during SSR, so plain anchors arrived without aria-current="page" / data-active — late on hydrated pages, never on pages that do not hydrate. Both compilers now give every candidate <a href> in SSR output one hole after its attributes, ssrLinkClaim(attrs), where a render's link handler writes the anchor's link state and "" otherwise. A static anchor's hole is one eager call over a hoisted attributes object (no allocation per render); a dynamic anchor's joins the element's attribute group and reuses the raw value its href hole evaluated. Anchors the compiler can rule out — a static non-empty target, a download, a rel naming external, an author-written aria-current, an empty href or a non-HTTP scheme — get no hole at all. The hole creates no owner and takes no hydration id. A spread anchor's link attributes are collected by ssrElement from its winning sources (an anchor's trailing link attributes stay a source instead of baked tail markup).

    New server API (@experimental): setLinkClaim(handler) sets the handler of the render the caller belongs to — found through the owner chain like getHydrationWriter(), so concurrent renders never share one — and returns false outside a render; undefined clears it. The handler, (attrs) => string, receives the anchor's link-relevant attributes (href, target, rel, download, link, aria-current, raw values as written) and returns its attribute markup. An author-written aria-current always wins. Server components inline in the document render under the page's handler; a server component's own frame stream has none unless its render sets one.

    Trust marker: the first setLinkClaim of a render writes the links hydration record once (_$HY.r.links = 1, with the shell's hydration script on the document face, a data record on a frame stream). hasServerLinkState() (client; false on the server) reads it non-destructively, so a link consumer can tell "this page's anchors carry the server's link state" from "no handler ran" and trust the HTML at hydration instead of resolving every anchor's URL at claim. Without a handler the HTML and the hydration ids are byte-for-byte what they were.

  • 234cfc9: readShallow (the compiler's one-layer tracked read of an object-valued class/style) reads a proxy's keys with Reflect.ownKeys directly — what sourceKeys(value, SOURCE_PROXY) resolves to by definition — instead of through sourceKeys, whose runtime kind argument kept the merge/omit view walkers of @solidjs/signals in every compiled page with a dynamic class or style, reached by nothing. Identical behaviour; −1,165 B minified / ≈ −350 B brotli on the compiled server-component page (a page with an element spread keeps the walkers through spread()).

  • Updated dependencies [4afc662]

  • Updated dependencies [b460640]

  • Updated dependencies [39450e5]

  • Updated dependencies [cbd66e5]

  • Updated dependencies [b083833]

  • Updated dependencies [0c4bff7]

  • Updated dependencies [b749474]

  • Updated dependencies [234cfc9]

  • Updated dependencies [d966729]

  • Updated dependencies [a405039]

  • Updated dependencies [234cfc9]

    • solid-js@2.0.0-rc.15

todos-server-example@0.0.1-rc.3

Patch Changes

test-integration@2.0.0-rc.15

Patch Changes

  • Updated dependencies [ad973ed]
  • Updated dependencies [b2bec73]
  • Updated dependencies [617d195]
  • Updated dependencies [617d195]
  • Updated dependencies [a497d4b]
  • Updated dependencies [4afc662]
  • Updated dependencies [b460640]
  • Updated dependencies [0c70907]
  • Updated dependencies [a14c18b]
  • Updated dependencies [5a26ebe]
  • Updated dependencies [c189013]
  • Updated dependencies [a963ec1]
  • Updated dependencies [39450e5]
  • Updated dependencies [0c70907]
  • Updated dependencies [469733e]
  • Updated dependencies [cbd66e5]
  • Updated dependencies [ad973ed]
  • Updated dependencies [43570f8]
  • Updated dependencies [b083833]
  • Updated dependencies [39051bf]
  • Updated dependencies [ef1c297]
  • Updated dependencies [abe12fc]
  • Updated dependencies [f64fcfe]
  • Updated dependencies [0c4bff7]
  • Updated dependencies [20db6a2]
  • Updated dependencies [3173a14]
  • Updated dependencies [5d75ed8]
  • Updated dependencies [1c14992]
  • Updated dependencies [86ac6da]
  • Updated dependencies [c2d4571]
  • Updated dependencies [e9d549f]
  • Updated dependencies [c689a9a]
  • Updated dependencies [49bed5c]
  • Updated dependencies [43570f8]
  • Updated dependencies [b749474]
  • Updated dependencies [234cfc9]
  • Updated dependencies [22f942d]
  • Updated dependencies [d966729]
  • Updated dependencies [a405039]
  • Updated dependencies [a2dff39]
  • Updated dependencies [234cfc9]
  • Updated dependencies [f6905dc]
  • Updated dependencies [e0a7548]
  • Updated dependencies [a24e911]
  • Updated dependencies [234cfc9]
    • @solidjs/signals@2.0.0-rc.15
    • @solidjs/babel-plugin@2.0.0-rc.15
    • @solidjs/web@2.0.0-rc.15
    • @solidjs/h@2.0.0-rc.15
    • solid-js@2.0.0-rc.15
    • @solidjs/html@2.0.0-rc.15
    • @solidjs/universal@2.0.0-rc.15

@github-actions
github-actions Bot force-pushed the changeset-release/next branch 25 times, most recently from b9dba05 to b607632 Compare October 9, 2026 10:50
@github-actions
github-actions Bot force-pushed the changeset-release/next branch 4 times, most recently from 4ac10a8 to 471bd6c Compare October 9, 2026 17:45
@github-actions
github-actions Bot force-pushed the changeset-release/next branch 16 times, most recently from 02e03a5 to c0f6655 Compare October 12, 2026 16:41
@github-actions
github-actions Bot force-pushed the changeset-release/next branch from c0f6655 to 00dc934 Compare October 12, 2026 17:53
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.

0 participants