Repository navigation
Release RC packages (rc) - #4037
Open
github-actions[bot] wants to merge 1 commit into
Open
github-actions[bot] wants to merge 1 commit into
github-actions[bot] wants to merge 1 commit into
Conversation
github-actions
Bot
force-pushed
the
changeset-release/next
branch
30 times, most recently
from
October 15, 2026 04:26
cf6c72a to
df829de
Compare
github-actions
Bot
force-pushed
the
changeset-release/next
branch
15 times, most recently
from
October 16, 2026 04:14
b6f48c6 to
6f94f06
Compare
github-actions
Bot
force-pushed
the
changeset-release/next
branch
from
October 16, 2026 09:49
6f94f06 to
0ce27ac
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR was opened by the Changesets release GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to next, this PR will be updated.
nextis currently in pre mode so this branch has prereleases rather than normal releases. If you want to exit prereleases, runchangeset pre exitonnext.Releases
@solidjs/babel-plugin@2.0.0-rc.16
Patch Changes
sourceNamesgains alocationskind (and the plugin arootoption): component and binding labels carry afile:line:colfor diagnostics.createComponent(Home, props, "Home", "src/App.tsx:12:5")points at the<Homeopening element (DOM and SSR output); a binding's options gainlocaftername— the attribute's start for an attribute effect (a merged effect points at the first attribute it lists), the hole's{for an insert — and a spread passes it after the tag (spread(el, props, false, undefined, "div", "src/App.tsx:20:12")). The path is relative toroot(default: the working directory) with/separators; line and column are 1-based, so a dev server links the location straight to the source. Like the other kinds,locationsfollowsdevwhen unset,trueturns every kind on, and the object form picks; a location is only emitted beside its label, and never when Babel has nofilenamefor the module.refexpression beside a spread, as it already does without one, so a ref factory's owned setup (ref={tooltip()}) runs on the server too and the hydration ids after it line up. The ref itself is still never called on the server ([2.0 rc.15 / next] SSR never evaluates arefon an element that has a spread, so a directive factory's setup misaligns hydration ids #4081). UnderserverComponentsthe same holds outside a server component's render, where a ref expression was never evaluated on either path; inside one the claim evaluates it, once.@solidjs/compiler@2.0.0-rc.16
Patch Changes
4a99c84:
sourceNamesgains alocationskind andtransform()arootoption: component and binding labels carry afile:line:colfor diagnostics, printed the same as@solidjs/babel-plugin's.createComponent(Home, props, "Home", "src/App.tsx:12:5")points at the<Homeopening element (DOM and SSR output); a binding's options gainlocaftername— the attribute's start for an attribute effect (a merged effect points at the first attribute it lists; a property split out ofstyle={{…}}/class={{…}}at that attribute), the hole's{for an insert — and a spread passes it after the tag (spread(el, props, false, undefined, "div", "src/App.tsx:20:12")). The path is relative toroot(default: the working directory) with/separators; line and column are 1-based, so a dev server links the location straight to the source. Like the other kinds,locationsfollowsdevwhen unset,trueturns every kind on, and the object form picks; a location is only emitted beside its label, and never without afilename.transformSourceNamesgainslocations(defaulttrue) androot: it writeslocbesidenamein every options literal it writes or completes —createSignal(0, { name: "count", loc: "src/store.ts:3:22" }), the call's start — keeping an explicitname(and still addingloc) and never overriding an explicitloc.d0ba31c: SSR evaluates a
refexpression beside a spread, as it already does without one, so a ref factory's owned setup (ref={tooltip()}) runs on the server too and the hydration ids after it line up. The ref itself is still never called on the server ([2.0 rc.15 / next] SSR never evaluates arefon an element that has a spread, so a directive factory's setup misaligns hydration ids #4081). UnderserverComponentsthe same holds outside a server component's render, where a ref expression was never evaluated on either path; inside one the claim evaluates it, once.@solidjs/diagnostics@2.0.0-rc.16
Patch Changes
holdsandfeedbackentries fromDiagnosticsMethods(and so fromDiagnosticsMethod,DiagnosticsRequest,DiagnosticsResponse) in@solidjs/diagnostics/protocol. The/__solid/diagnosticsdev-server endpoint never served them; it answersbegin,end,active,whyDidRunandcosts, and the holds and feedback tables arrive in theendpayload (attribution.holds,attribution.feedback). The in-page bridge'sholds()/feedback()queries are unchanged. The agent-loops skill's endpoint example no longer lists afeedbackcall.loc(the source location the runtime resolved,file:line:col) as a plain event field through artifacts and the JSONL form; assertion failures print it with the rest of the offending event.solid-2.0skill, emitCHEATSHEET.mdas thesolid-2.0-cheatsheetskill on build, give every shipped skill thename/descriptionfrontmatter the Agent Skills format requires, and add thetanstack-intentkeyword so skill registries discover them innode_modules.@solidjs/element@2.0.0-rc.16
Patch Changes
@solidjs/h@2.0.0-rc.16
Patch Changes
data-*attributes type-check in props objects (ComponentProps<"div">,JSX.HTMLAttributes<T>), not only in JSX: a template-literal index signature onElementAttributes([2.0 rc.15 / next] Types:data-*attributes are rejected in props objects typed withComponentProps/JSX.HTMLAttributes#4082).@solidjs/html@2.0.0-rc.16
Patch Changes
@solidjs/signals@2.0.0-rc.16
Patch Changes
3d8a8a9: Point JSDoc
@descriptionlinks at the 2.0 reference docs (v2.solidjs.com), documentisPending, point the console footer, diagnostics guide and cheatsheet links at thenextbranch, and replace the staleonMountadvice in the server-side client-only API error.a7fe050: A Loading boundary mounted by a pass that joined a hold appears at that hold's commit, its fallback never shown (D-13, U-3). Before, the boundary's content was caught as a fresh mount and the fallback published at once (or, for a
<Show>that opens when a flight lands, flashed at the landing before the content). A first pass born into the flush's hold is now the hold's, not the boundary's: the content reads with the hold and the whole mount appears at its commit. A mount made by a verdict reader (latestin a<Show>) is still mainline and shows the fallback while the hold is up.52008d9: An effect or memo that catches the
NotReadyErrorfrom reading an async derived store (createStore(async fn, seed),createProjection) now re-runs when the store's flight lands, as it does for an async memo (rc.14: an effect that catches NotReadyError from an async store is never re-run when the store settles #4070).0b6765f: A signal write from an
onCleanupthat a transition's landing runs no longer leaves the landed transaction as the next flush's: later transitions commit again instead of parking forever (signals rc.14+: a write from onCleanup during land() resurrects the landed transaction, and later transitions never commit #4089).b8617ec:
createDeferred(fn, options?): an async memo that may lag, but never leads. Before its first answer it is an ordinary async memo (readers suspend to<Loading>, orloadingValueshows). After it, a refetch holds nothing: readers keep the previous answer until the new one lands, the rest of the screen moves on, andisPendingreports the refetch on the node and on everything derived from it, store keys included. A refetch that read a held value lands with that hold. A rejection errors like any memo.refresh(d)is a quiet re-ask, andawait refresh(d)anduntilwait for the landing. It iscreateMemoon the server and hydrates like one.The rules: F-1 and F-2 are amended for declared lag, and D-40 / S-41 are new. The
affects()mark core moved to its own module (affects-marks.ts), whichcreateDeferredshares. A mark on the source of a derived store now covers that store's keys.3643c5e: A
createRootdispose function no longer keeps the root'sinitfunction (and everything it closes over) alive while it is held (createRoot's dispose function keepsfnalive, so<For>/<Index>rows retain removed list items #4095).4a99c84: Diagnostics carry a source location.
NodeOptions.locandStoreOptions.loc(file:line:col, root-relative — written by the compiler'ssourceNameslocationskind, not by hand) land in a_locslot beside_nameon the observe/dev node literals; store property nodes carry their store's.DiagnosticEvent.locis the innermost located node on the subject's chain (its ownloc, else the first up the owners — a signal through its registering owner), found inemitDiagnosticthe wayownerPathis; a host event that sets it keeps it.reportDiagnosticprints it as anatline after theinline —at src/App.tsx:18:3, or in a browserat http://localhost:5173/src/App.tsx:18:3, which the devtools link to the Sources panel.DEV.guideUrl(code)now returns the code's page on the docs site (https://v2.solidjs.com/reference/solid-js/diagnostics/<slug>).61c4436: An async memo created inside a fresh Loading boundary over a held value no longer lands its first answer before the hold commits (D-12, U-1). The boundary still catches it and shows its fallback, and the hold still does not wait for it: its answer is staged with the hold and appears no earlier than the hold's commit. A boundary re-armed by
onkeeps owning what it collects outright.a39acdd:
GRAPH_GROWTHno longer reports long-lived state that the page just left also read. What outlived a navigation was the set of nodes reachable as that one navigation opened, and the walk reaches a module-level source (solid-refresh's per-component registry signal in dev, a global store) only through a page that reads it. So arriving at a route from pages sharing more and more of its components, or of its global state, read as growth with nothing leaked. The nodes met as navigations open now go into one set kept for the session, so such a source counts the same at every settle once met, and only what keeps accumulating climbs. Leaked roots, ownerless effects and per-visit subscriptions still report as before. Fixes [2.0 rc.15 / next] GRAPH_GROWTH counts solid-refresh's per-component registry signals as having outlived a navigation #4101.0bda987: An error is an answer: it ends the wait like a value, and it shows when a value would (D-41). A rejection or throw on a node a transaction holds is staged and published with the frame that carries it: until then the screen, an untracked read,
createEffect's error arm and<Errored>keep the previous frame,isPendingistrue,latestthrows the proposed error, andresolve/until/refreshreject at the landing. A held recovery keeps the shown error until its own commit, and a recovery equal to the last good value now reaches effects, held or not (it was swallowed by the equality gate). Replaces the separate staged-error publish path. From fix(signals): publish value and error outcomes consistently #3886's audit (GabbeV).ccd9948: Smaller floor bundles: the optional engines (lanes, verdicts, boundaries, stores, affects, external sources) install their scheduler hooks as module variables, so an app that never loads them no longer retains their paths in
recompute,readand the settle step; client-onlyrenderno longer retains hydration text adoption, and the delegated dispatcher drops dead guards. The JSX hello world goes from 10.35 KB to 9.75 KB brotli.dbc5d00:
SSR_BOUNDARY_WATERFALLnow judges a wait by when its work started, the same origin rule the client'sASYNC_WATERFALLuses. A nested route meets its levels one render pass at a time, but the router starts every matched level'slazy()import and preload together. Before, the first request to a cold server warned about a data waterfall that wasn't there. A wait whose work had all started before the previous wait landed is now left out of the count (data.parallelWaits).lazy()andlazyModule()stamp their imports. The start stamps move from the attribution engine to the core'sOBSERVE.attribution(markFlight,flightOrigin), so a router or cache can stamp what it hands out without loading the engine.attribution.markFlightwrites to the same place.347f242: New dev check
SSR_LIVE_HOLE_LATCHED(A live hole silently stops re-emitting when its markup has a conditional on a property ({m.usage && …}) #4023): a live markup hole that shipped its markers and then stopped updating, because re-running it would create reactive scopes (most often a compiler condition memo for{m.usage && …}), is now named on the console, located by its component, instead of going quiet. Behavior is unchanged; hoisting the property into a local keeps the hole live.c12c420: An outer
on-reset Loading boundary no longer waits for a flight its nestedon-reset boundary catches (D-14, U-4). A pending reader forwarded through both boundaries while neither was collecting was recorded in both, so when one tick re-armed both the outer kept its fallback until the inner's flight landed. A reader a nested collecting boundary holds is now that boundary's alone: the outer's content shows beside the inner's fallback as soon as the outer's own work lands.4bc7969: fix(signals): a later mainline store setter that does not write a held key publishes on the mainline tick — a setter's written keys are its own set, so its notify visits only the keys it wrote (D-8, U-8, Solid 2: reconcile repeats unchanged presence and holds unrelated updates #3743)
d3cddff: Attribution:
createProjectionrecords the owner in scope ascreateStoredoes, so a projection's property nodes carry an owner path ([2.0 rc.15 / next] GRAPH_GROWTH reports a keyed cache filling with new keys as a leak, and a cache has no way to say what it is #4035). TheGRAPH_GROWTHmessage and its skill section now name a cache that never evicts as a source of the same growth.c2513e3: A Loading boundary re-armed by
onowns the content under it that reads a hold another change made (D-14, D-16, U-9). Before, that content joined the hold, so no fallback showed and the boundary reported pending, and a held tree under a re-armed boundary could redraw forever. Now the fallback shows with the re-arming change and the content reveals at the hold's commit, which no longer waits for it. A re-arm whose own change joins that hold still shows no fallback (the frame waits on the same data), andLOADING_ON_OUTSIDE_HOLDis reported only for a flight the change itself started.dfb31ed: Derived stores no longer need a seed (Proposal: make derived store APIs type-safe and ergonomic #3194).
createStore(fn),createProjection(fn)andcreateOptimisticStore(fn)accept a derive that takes no draft and answers a complete value — sync, a promise, or an async iterable whose every yield is a complete snapshot. The root is a plain object (an array keeps its[]seed); passundefinedfor the seed to reach the options, e.g.createStore(fetchUser, undefined, { key: "email" }). Until the first answer lands the store is unreadable, as with any seed (A25);seedLoadingValueneeds a seed and is not offered on the seedless form.With the seedless form available, a seed is a complete
Tagain (fix(signals): require complete store seeds #3258's requirement, reverted then because async stores that needed the options slot had to invent one). A{}seed on a return-form derive is now a type error: drop it. A mutating derive that builds its object from an empty seed needs{} as T.3fc5551:
until()andrefresh()no longer retain the optimistic lane engine in apps that don't use optimism (−4.8 KB minified). Anuntil()predicate reading a memo derived from an unconfirmed optimistic guess now waits for the guess to be confirmed or corrected, instead of seeing the value from before the guess.42c2568: A memo that reads a verdict memo (
isPending/latest) shows the verdict now, beside a held value it also reads (F-6, U-10, [2.0 rc.15 + next] Held navigation never publishes delayed pending feedback #4050). Before, it re-entered the hold with that value and the verdict waited for the landing: a Provider's children memo over a router shell[<Feedback/>, outlet]never showed delayed pending feedback during a held navigation. It now behaves as the same probe read inline, or a render effect reading both, already did.solid-js@2.0.0-rc.16
Patch Changes
3d8a8a9: Point JSDoc
@descriptionlinks at the 2.0 reference docs (v2.solidjs.com), documentisPending, point the console footer, diagnostics guide and cheatsheet links at thenextbranch, and replace the staleonMountadvice in the server-side client-only API error.b8617ec:
createDeferred(fn, options?): an async memo that may lag, but never leads. Before its first answer it is an ordinary async memo (readers suspend to<Loading>, orloadingValueshows). After it, a refetch holds nothing: readers keep the previous answer until the new one lands, the rest of the screen moves on, andisPendingreports the refetch on the node and on everything derived from it, store keys included. A refetch that read a held value lands with that hold. A rejection errors like any memo.refresh(d)is a quiet re-ask, andawait refresh(d)anduntilwait for the landing. It iscreateMemoon the server and hydrates like one.The rules: F-1 and F-2 are amended for declared lag, and D-40 / S-41 are new. The
affects()mark core moved to its own module (affects-marks.ts), whichcreateDeferredshares. A mark on the source of a derived store now covers that store's keys.4a99c84:
createComponent(Comp, props, name?, loc?)takes the JSX site the compiler emits beside the tag ("src/App.tsx:12:5"); the dev and observe component owner carries it on both the client and the server, so a finding raised inside a component reportsat src/App.tsx:12:5(andevent.loc) when nothing closer was located. The console footer is now two lines: the code's docs page for a human (what it means and how to fix it: https://v2.solidjs.com/reference/solid-js/diagnostics/<slug>), then the repair skill for an agent (installed path and GitHub URL, anchored to the code's section).diagnostics.jsonlinks each code to its docs page, and thereactivity-diagnosticsskill documents theatline.467ac97: Hydration: a streamed
<Loading>fragment that is the first to carry alazy()module's assets now loads them before its resume claims the revealed content, instead of rendering nothing while they load and clearing the parent's revealed nodes ([2.0 rc.15 / next] Hydration: a streamed <Loading> fragment that first brings a lazy() module's assets clears its revealed content #4087).dbc5d00:
SSR_BOUNDARY_WATERFALLnow judges a wait by when its work started, the same origin rule the client'sASYNC_WATERFALLuses. A nested route meets its levels one render pass at a time, but the router starts every matched level'slazy()import and preload together. Before, the first request to a cold server warned about a data waterfall that wasn't there. A wait whose work had all started before the previous wait landed is now left out of the count (data.parallelWaits).lazy()andlazyModule()stamp their imports. The start stamps move from the attribution engine to the core'sOBSERVE.attribution(markFlight,flightOrigin), so a router or cache can stamp what it hands out without loading the engine.attribution.markFlightwrites to the same place.7c36f2b: Server
Forin a live hole: a row that read an async memo or projection besides its item, or whose item was edited in place, now renders again on each sweep instead of reusing stale markup.0a49dd8: Live holes: on a live response, a sweep that changed some rows of a
<For>sends just those rows (replace, append, truncate by index), and the frames client morphs only their ranges. A client whose range doesn't show what the rows were taken against resumes its live connection, which sends the hole whole.51d005a: Server
<For>keeps its rows across live-hole sweeps (Server components: a markup hole that re-emits re-renders every row of its list on every sweep #4056). A markup hole that re-emits (a live server component, a standing source) re-evaluated every row of a list on every write. During a sweep, a row whose item at the same index is unchanged (the same reference, or a shallow-equal object, as a live source's fresh snapshot usually is) now reuses the row it rendered on the previous sweep. Plain SSR and a server component's first render are unchanged. A row is a function of its item: an item mutated in place keeps its old row, and a row that reads outside data keeps the value it rendered with.eb4e019: Hydration no longer hydrates a streamed
<Loading>fallback when the fragment was already revealed but its_frrecord hasn't settled yet (an async entry running between the two scripts). The boundary renders nothing and adopts the revealed content once the record settles ([2.0 rc.15 / next] Streaming hydration: a <Loading> fragment revealed before its "_fr" record settles hydrates the removed fallback (Hydration key miss) #4074).dfb31ed: Derived stores no longer need a seed (Proposal: make derived store APIs type-safe and ergonomic #3194).
createStore(fn),createProjection(fn)andcreateOptimisticStore(fn)accept a derive that takes no draft and answers a complete value — sync, a promise, or an async iterable whose every yield is a complete snapshot. The root is a plain object (an array keeps its[]seed); passundefinedfor the seed to reach the options, e.g.createStore(fetchUser, undefined, { key: "email" }). Until the first answer lands the store is unreadable, as with any seed (A25);seedLoadingValueneeds a seed and is not offered on the seedless form.With the seedless form available, a seed is a complete
Tagain (fix(signals): require complete store seeds #3258's requirement, reverted then because async stores that needed the options slot had to invent one). A{}seed on a return-form derive is now a type error: drop it. A mutating derive that builds its object from an empty seed needs{} as T.a61c929: A server component in a document marks its live holes only once the render has served something a later commit can replace: an async iterable it pumps, or a loading value or seed shown ahead of its landing. Until then a hole that resolves synchronously ships without
lhmarkers,data-lhaaddresses or a ledger binding, because no channel op can ever address it. On a request/response page that is every hole: the 1,406-comment hackernews thread drops from 948 KB to 787 KB and renders in about half the server time.3d8a8a9: Ship the Solid 2.0 primer for coding agents as the
solid-2.0skill, emitCHEATSHEET.mdas thesolid-2.0-cheatsheetskill on build, give every shipped skill thename/descriptionfrontmatter the Agent Skills format requires, and add thetanstack-intentkeyword so skill registries discover them innode_modules.3d8a8a9:
solid-jsnow shipsdiagnostics.jsonnext toCHEATSHEET.md: the machine-readable catalog of every dev diagnostic code —code,kind,severity,category,trigger,repair(the first sentence of the code's section in thereactivity-diagnosticsskill) andguideUrl(that section on GitHub). It is generated from theDiagnosticCodeunion, the RFC's quick-reference table and the skill bypnpm diagnostics:json, and a test fails when any of the three (or the committed file) names a different set of codes. The quick-reference table gains its missingPRIMITIVE_IN_EFFECT_CALLBACKrow.Updated dependencies [3d8a8a9]
Updated dependencies [a7fe050]
Updated dependencies [52008d9]
Updated dependencies [0b6765f]
Updated dependencies [b8617ec]
Updated dependencies [3643c5e]
Updated dependencies [4a99c84]
Updated dependencies [61c4436]
Updated dependencies [a39acdd]
Updated dependencies [0bda987]
Updated dependencies [ccd9948]
Updated dependencies [dbc5d00]
Updated dependencies [347f242]
Updated dependencies [c12c420]
Updated dependencies [4bc7969]
Updated dependencies [d3cddff]
Updated dependencies [c2513e3]
Updated dependencies [dfb31ed]
Updated dependencies [3fc5551]
Updated dependencies [42c2568]
@solidjs/universal@2.0.0-rc.16
Patch Changes
@solidjs/web@2.0.0-rc.16
Patch Changes
3d8a8a9: Point JSDoc
@descriptionlinks at the 2.0 reference docs (v2.solidjs.com), documentisPending, point the console footer, diagnostics guide and cheatsheet links at thenextbranch, and replace the staleonMountadvice in the server-side client-only API error.86cf504:
data-*attributes type-check in props objects (ComponentProps<"div">,JSX.HTMLAttributes<T>), not only in JSX: a template-literal index signature onElementAttributes([2.0 rc.15 / next] Types:data-*attributes are rejected in props objects typed withComponentProps/JSX.HTMLAttributes#4082).f048691: A server component's hole that waits on async data keeps its handler-position markers (
_s:on:click) when a boundary outside the component resumes it. The retry renders under the component's claims arming instead of the resuming boundary's context, so the markup the client adopts carries the marker. Before, the chat example's Copy buttons shipped without it and were only bound after the end-of-response sweep re-sent the whole message list.4a99c84:
effectandinserttakelocbesidenamein their options, andspreada trailinglocafter its tag — the source site the compiler emits undersourceNameslocations— so a diagnostic about a compiled binding reportsat src/App.tsx:14:7and carriesevent.loc. Dev and observe builds keep it on the node; production ignores it.96b615d: Remove the internal
scriptNonce/styleNonceexports from the server build. They stayed exported after fix(web): single-script surfaces take a CSPNonce; scriptNonce/styleNonce become internal #4016 only because@solidjs/vite-plugin≤ 3.0.0-next.49 imported them. 3.0.0-next.50 projects the nonce itself (fix(ssr): project the CSP nonce locally instead of importing scriptNonce/styleNonce solid-vite-plugin#409). Apps must use@solidjs/vite-plugin3.0.0-next.50 or later with this release.a0991b3: perf(frames): while the bind tier is announced or loading, the slot walk visits comments only and holds the frame, so
_s:*attributes are scanned once, after the tier installs, instead of twice8092282: fix(frames): a link inside nested slot regions is claimed once per adoption instead of once per enclosing region, and a streaming document whose server components mint no tier writes an empty
sc:tiersrecord so the client skips its per-element slot-marker scan8163bc3: Send data server functions called during hydration on a page with server components (With serverFunctions.components on, data server functions called during hydration never reach the network (frames intercept waits forever) #4033). The frames client holds a server-function call while the document may still deliver a boundary for it, and a data function never has one. A wait created under a hydration trace cached the trace's never-settling
Promisestub, so every later call for that function hung; and a call made after the page's last reveal (a hydration-end recompute) was released only by a reveal that never came. Waits made under a trace are no longer kept, and outstanding waits are released when hydration ends as well as on reveals.10b3f55: Frames client: a live stream's writes no longer re-walk the whole frame. After every write, the slot sync used to walk all of the frame's content and re-parse every binding marker, and each live-hole apply searched the frame for its marker. Both costs grew with everything the frame showed, which was most of the per-write client time once a chat thread had history. Now only a root morph, a reveal, or an empty write ("re-walk what you hold") walks the whole frame. Any other write reuses the last walk's result and walks only the ranges its live holes morphed. That reuse runs in the lazy bind tier; without the tier, the walk sees only comments. Live-hole markers are cached between applies. When reuse can't be exact (a reveal whose content landed after its flush, an attr patch on a consumer, a hole whose parent element is a consumer), the full walk runs as before.
1f3b5b4: fix(frames): a frame rendered off the live address marks only the holes that can change within its response (the document face's gate), so synchronous holes ship without
lhmarkers,data-lhaaddresses or hole digests; the live address keeps every marker for its reconnect have-listccd9948: Smaller floor bundles: the optional engines (lanes, verdicts, boundaries, stores, affects, external sources) install their scheduler hooks as module variables, so an app that never loads them no longer retains their paths in
recompute,readand the settle step; client-onlyrenderno longer retains hydration text adoption, and the delegated dispatcher drops dead guards. The JSX hello world goes from 10.35 KB to 9.75 KB brotli.0e0c043: Write one
data-lhaaddress on an element whose attribute was still pending inside a<Loading>in a live server component (Live holes: a pending attribute inside a Loading boundary writes data-lha twice, and the element's later attr updates are dropped #4032). When the in-tag hole escalated, the attribute capture was dropped but the address it had spliced into the tag stayed, and the boundary's resume minted a second one in front of it. The stale address rode every later attr op for the element, so the first op moved the element off its bound address and every op after it was dropped. The address now goes with the dropped capture.0a49dd8: Live holes: on a live response, a sweep that changed some rows of a
<For>sends just those rows (replace, append, truncate by index), and the frames client morphs only their ranges. A client whose range doesn't show what the rows were taken against resumes its live connection, which sends the hole whole.347f242: New dev check
SSR_LIVE_HOLE_LATCHED(A live hole silently stops re-emitting when its markup has a conditional on a property ({m.usage && …}) #4023): a live markup hole that shipped its markers and then stopped updating, because re-running it would create reactive scopes (most often a compiler condition memo for{m.usage && …}), is now named on the console, located by its component, instead of going quiet. Behavior is unchanged; hoisting the property into a local keeps the hole live.b972757: Live holes keep updating when their markup creates reactive scopes (a nested
<For>, a compiler condition memo such as{m.usage && …}, a component). Each re-render runs in a throwaway scope disposed once its markup is out; only a scope still waiting on async work closes the hole (A live hole silently stops re-emitting when its markup has a conditional on a property ({m.usage && …}) #4023).8e2590e: Hydrating a
<Loading>whoselazy()module lands after hydration starts no longer moves its server-rendered nodes when the boundary has a sibling in the same fragment ([2.0 rc.15 + next] Hydration reverses static and lazy children in Loading after a sibling #4049). A sibling before the boundary used to swap the boundary's static and lazy children (A/C/B instead of A/B/C), and a sibling after it detached and re-attached the boundary's content, restarting CSS animations and blurring a focused input. The late claim now leaves server nodes in place when they already sit in the region, in order, around the nodes the insert was tracking.8fbadfd: Frames morph: when a text hole empties, the reconcile drops the stale text node instead of relocating the next element in front of it, so the elements after an emptied text hole stay put instead of being re-inserted.
e1bf2af: Frames morph skips an identical subtree with one native
isEqualNodecompare instead of walking it.8e2590e:
respond(value, init)accepts every value a plain return does ([2.0 rc.15 + next]respond()encodes its value withJSON.stringifyup front, so abigintresult that a plain return carries fine throws #4060). Its passthrough JSON body — read only by consumers without the client runtime — is now encoded when read instead of when the envelope is built, so abigintno longer throws insiderespond()and fails both the direct call and the HTTP call. Unscripted HTTP callers get the carried JSON body only when JSON carries the value faithfully; otherwise the value is encoded the same way as a plain return.8bd7a5b: Bind each server-component site to its own frame when the server minted the sites in a different order than the client mounts them ([2.0 rc.15] Server-component sites reached in a different order on the client bind to the wrong frame #4042). Document adoption took sites of one server function by ordinal (
id,id~2, …), so a site behind async setup, rendered after its neighbours on the server but mounted first on the client, adopted a neighbour's element, and its first update landed in the wrong frame. A document frame for a call with arguments now carries the call's argument hash (data-fa), and a mount takes the unclaimed site showing its own arguments, falling back to the first unclaimed site when none does. Argless calls render byte-identical markup.3e94215: Server functions: arguments never decode
ResponseorRequestvalues. The handler decodes client → server argument payloads with the configured plugin list minus theResponse/Requestplugins, so a call carrying one — top level, nested, or inside a promise or stream — is refused with400before the function runs.enableRichArguments()rejects such a call before sending. Results and hydration keep the full plugin set.Server-function responses now default to
X-Content-Type-Options: nosniff; a value the function sets itself is kept.a61c929: A server component in a document marks its live holes only once the render has served something a later commit can replace: an async iterable it pumps, or a loading value or seed shown ahead of its landing. Until then a hole that resolves synchronously ships without
lhmarkers,data-lhaaddresses or a ledger binding, because no channel op can ever address it. On a request/response page that is every hole: the 1,406-comment hackernews thread drops from 948 KB to 787 KB and renders in about half the server time.36039e2: The shell-end marker is spliced in before
</body>instead of being appended after</html>when the shell is a whole document (Shell-end marker is written after </html> in fully assembled documents (rc.15, #4002) #4030). Async render mode and a stream with nothing pending now end with</html>again; a shell without</body>(an embedded render) still gets the marker appended.3d8a8a9: Ship the Solid 2.0 primer for coding agents as the
solid-2.0skill, emitCHEATSHEET.mdas thesolid-2.0-cheatsheetskill on build, give every shipped skill thename/descriptionfrontmatter the Agent Skills format requires, and add thetanstack-intentkeyword so skill registries discover them innode_modules.8d4a285: A cleanup that throws while a stream is torn down no longer crashes the server (renderToStream: an onCleanup that throws during signal abort crashes the server process #4029). Aborting
renderToStream'ssignaldisposes the render inside theabortlistener, where a throw became an uncaught exception; the teardown now reports it throughonErroras a failed render (handling: "failed") and finishes.Updated dependencies [3d8a8a9]
Updated dependencies [b8617ec]
Updated dependencies [4a99c84]
Updated dependencies [467ac97]
Updated dependencies [dbc5d00]
Updated dependencies [7c36f2b]
Updated dependencies [0a49dd8]
Updated dependencies [51d005a]
Updated dependencies [eb4e019]
Updated dependencies [dfb31ed]
Updated dependencies [a61c929]
Updated dependencies [3d8a8a9]
Updated dependencies [3d8a8a9]
board-example@0.0.1-rc.1
Patch Changes
server-dbmon-example@0.0.1-rc.0
Patch Changes
todos-server-example@0.0.1-rc.4
Patch Changes
test-integration@2.0.0-rc.16
Patch Changes