Skip to content

Commit dd271a2

Browse files
docs: sync reference to rc.13; internalized boundary primitives; public hydration API
Regenerate the reference against solidjs/solid 8950bb7b7 (rc.13). Internalized (#3709, fb4e637): createErrorBoundary, createLoadingBoundary and createRevealOrder are typed only through solid-js/internal now, so their pages go and Boundaries' "Primitive forms" says so, composing Errored + Loading for a custom boundary instead. sharedConfig and $DEVCOMP stay hidden. The REACTIVITY_HALTED message points at <Errored> alone. New public hydration API (#3718): isHydrating / isHydratable pages under Manual hydration, a getHydrationWriter / takeHydrationValue page under Rendering & SSR with HydrationWriter / HydrationValue folded in. Rendering and SSR's "Controlling hydration" introduces the four; SSR-safe code uses isHydrating() to seed a browser-measured value correctly on a client-side navigation. Observe tier (#3705, #3708, fe1eb68): the "request" record, the shared CallLive, the bodies opt-in, OBSERVE.include, and the router's initial / interaction declarations in the two observability guides and the debugging guide; CallRequestEvent, CallRequestListener, RecordSubscribeOptions and RenderRoute fold into the OBSERVE page. Server-component binding-slot exports (SLOT_*, isSlotValue) are hidden as renderer ABI. Extractor: member types go through cleanTypeText, so an interface member no longer leaks SolidElement or an inline JSDoc blob; GlobalAbortSignal renders as AbortSignal. Router: defineFileRoute's config is optional (solid-router#622). Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 37e9191 commit dd271a2

22 files changed

Lines changed: 180 additions & 329 deletions

File tree

‎scripts/extract-solid-ref.mjs‎

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -266,18 +266,6 @@ const ADVANCED_ROUTES = {
266266
"Advanced / Store Advanced",
267267
],
268268

269-
createErrorBoundary: [
270-
"advanced/jsx-component-primitives/create-error-boundary.mdx",
271-
"Advanced / JSX Component Primitives",
272-
],
273-
createLoadingBoundary: [
274-
"advanced/jsx-component-primitives/create-loading-boundary.mdx",
275-
"Advanced / JSX Component Primitives",
276-
],
277-
createRevealOrder: [
278-
"advanced/jsx-component-primitives/create-reveal-order.mdx",
279-
"Advanced / JSX Component Primitives",
280-
],
281269
mapArray: [
282270
"advanced/jsx-component-primitives/map-array.mdx",
283271
"Advanced / JSX Component Primitives",
@@ -632,6 +620,11 @@ const HIDDEN_EXPORTS = new Set([
632620
"SLOT_FACE_MARKUP",
633621
"isSlotValue",
634622
"$DEVCOMP",
623+
// Runtime exports typed only through solid-js/internal (#3709): the
624+
// primitives behind Errored, Loading, and Reveal, for renderers.
625+
"createErrorBoundary",
626+
"createLoadingBoundary",
627+
"createRevealOrder",
635628
"$PROXY",
636629
"$REFRESH",
637630
"$TRACK",
@@ -1056,6 +1049,8 @@ const VALUE_IMPORTS = new Set(["storePath"]);
10561049
// from the implementation.
10571050
const PREFERRED_SOURCE_PATHS = {
10581051
getHydrationWriter: "packages/web/src/server.ts",
1052+
HydrationWriter: "packages/web/src/server.ts",
1053+
HydrationValue: "packages/web/src/server.ts",
10591054
getRequestEvent: "packages/web/src/server.ts",
10601055
getTraceContext: "packages/web/src/server.ts",
10611056
configureServerErrors: "packages/web/src/server.ts",
@@ -2510,6 +2505,31 @@ const ENTRY_LEARN = {
25102505
parseCookieHeader: [
25112506
["Sessions and auth", "/building-apps/sessions-and-auth"],
25122507
],
2508+
isHydrating: [
2509+
["Browser APIs", "/guides/ssr-safe-code#browser-apis"],
2510+
[
2511+
"Controlling hydration",
2512+
"/concepts/rendering-and-ssr#controlling-hydration",
2513+
],
2514+
],
2515+
isHydratable: [
2516+
[
2517+
"Controlling hydration",
2518+
"/concepts/rendering-and-ssr#controlling-hydration",
2519+
],
2520+
],
2521+
getHydrationWriter: [
2522+
[
2523+
"Controlling hydration",
2524+
"/concepts/rendering-and-ssr#controlling-hydration",
2525+
],
2526+
],
2527+
takeHydrationValue: [
2528+
[
2529+
"Controlling hydration",
2530+
"/concepts/rendering-and-ssr#controlling-hydration",
2531+
],
2532+
],
25132533
};
25142534
const CATEGORY_LEARN = {
25152535
Reactivity: [
@@ -2588,6 +2608,9 @@ const TYPE_TEXT_REWRITES = [
25882608
// The core `Element` type is imported as `SolidElement` inside the
25892609
// package; app code knows it as `JSX.Element`.
25902610
[/\bSolidElement\b/g, "JSX.Element"],
2611+
// `until`'s abort option: the global type when a lib declares one, a
2612+
// minimal abort surface otherwise. App code knows it as `AbortSignal`.
2613+
[/\bGlobalAbortSignal\b/g, "AbortSignal"],
25912614
// Underscore-prefixed parameter names in server-side stubs.
25922615
[/([(,]\s*)_+([a-z]\w*\??:)/g, "$1$2"],
25932616
];
@@ -3732,7 +3755,7 @@ function getMemberDocs(declarations) {
37323755
if (!member.name) return null;
37333756
const name = member.name.getText();
37343757
const type = member.type
3735-
? member.type.getText(member.getSourceFile())
3758+
? cleanTypeText(member.type.getText(member.getSourceFile()))
37363759
: "";
37373760
const text = (member.jsDoc ?? [])
37383761
.map((doc) => normalizeMarkdown(renderComment(doc.comment)))

‎src/routes/(2)concepts/(4)boundaries.mdx‎

Lines changed: 16 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -216,36 +216,30 @@ Wrapping a descendant in another loading boundary does not let it escape an oute
216216

217217
## Primitive forms
218218

219-
The components above are built from three primitives.
220-
Application code does not need them; they exist for custom boundary components and renderer integrations.
221-
222-
- [`createLoadingBoundary(fn, fallback, options?)`](/reference/solid-js/advanced/jsx-component-primitives/create-loading-boundary) returns an accessor that switches between the tracked `fn` and the fallback.
223-
Its `on` option takes an accessor, because the primitive does not receive JSX props.
224-
- [`createErrorBoundary(fn, fallback)`](/reference/solid-js/advanced/jsx-component-primitives/create-error-boundary) returns an accessor and passes the fallback an error accessor and a reset function.
225-
- [`createRevealOrder(fn, options?)`](/reference/solid-js/advanced/jsx-component-primitives/create-reveal-order) runs `fn` under a reveal controller; its `order` and `collapsed` options are accessors.
219+
The components above are built from three primitives, `createLoadingBoundary`, `createErrorBoundary`, and `createRevealOrder`.
220+
They stay runtime exports of `solid-js`, but their types live in `solid-js/internal`, which carries no semver guarantee: they exist for renderer integrations, not for application code.
221+
A custom boundary component composes `Loading`, `Errored`, and `Reveal` instead:
226222

227223
```tsx
228-
import { createErrorBoundary, createLoadingBoundary } from "solid-js";
224+
import { Errored, Loading } from "solid-js";
225+
import type { JSX } from "@solidjs/web";
229226

230227
function StatusBoundary(props: {
231228
children: JSX.Element;
232229
loading: JSX.Element;
233230
}) {
234-
const output = createErrorBoundary(
235-
() =>
236-
createLoadingBoundary(
237-
() => props.children,
238-
() => props.loading
239-
)(),
240-
(error, reset) => (
241-
<section>
242-
<p>{String(error())}</p>
243-
<button onClick={reset}>Retry</button>
244-
</section>
245-
)
231+
return (
232+
<Errored
233+
fallback={(error, reset) => (
234+
<section>
235+
<p>{String(error())}</p>
236+
<button onClick={reset}>Retry</button>
237+
</section>
238+
)}
239+
>
240+
<Loading fallback={props.loading}>{props.children}</Loading>
241+
</Errored>
246242
);
247-
248-
return output() as JSX.Element;
249243
}
250244
```
251245

‎src/routes/(2)concepts/(6)rendering-and-ssr.mdx‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,13 @@ const accountRoot = document.getElementById("account")!;
289289
hydrate(() => <Account />, accountRoot, { renderId: "account" });
290290
```
291291

292+
Two functions answer questions about the hydration in progress.
293+
[`isHydrating()`](/reference/solid-js/advanced/manual-hydration/is-hydrating) is `true` while the running code is claiming server-rendered DOM, during the root pass of `hydrate()` or while a streamed boundary resumes, and `false` on the server, in client-only renders, and afterwards; a component reads it to seed a browser-measured value with what the server rendered only when the server rendered anything, as [SSR-safe code](/guides/ssr-safe-code#browser-apis) shows.
294+
[`isHydratable()`](/reference/solid-js/advanced/manual-hydration/is-hydratable) is `true` when the calling owner sits where hydration applies, so `false` under `NoHydration` and `true` again inside a nested `Hydration`.
295+
296+
Those two, with [`getHydrationWriter`](/reference/solid-web/rendering-ssr/get-hydration-writer) and [`takeHydrationValue`](/reference/solid-web/rendering-ssr/take-hydration-value) from `@solidjs/web`, are the surface a data library uses to carry its own values from the server render to the hydrating client: the server side writes a value under a namespaced key when `isHydratable()` allows it, and the client side takes it back by key, as a resolved value, a rejection, or a promise still streaming in.
297+
Application code does not need them; Solid moves its own state this way already.
298+
292299
## Common problems
293300

294301
### `window is not defined` or `document is not defined`

‎src/routes/(5)guides/(10)debugging-reactivity.mdx‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@ Acknowledged holds under those thresholds still count in the feedback tables: `f
285285

286286
A router can name the holds its navigations cause by the route pattern that matched, `/products/:id` rather than `/products/mug`, so occurrences fold together in these tables.
287287
It does so by wrapping its location write in `OBSERVE.attribution.withOrigin({ kind: "navigation", name, to, params }, write)`, which is router-agnostic; nothing else in attribution knows about routing.
288-
The [attribution reference](/reference/solid-js/advanced/diagnostics-dev-hooks/attribution#navigationref) describes the `NavigationRef` fields, including how a router whose match is not final at write time fills them in later.
288+
The [attribution reference](/reference/solid-js/advanced/diagnostics-dev-hooks/attribution#navigationref) describes the `NavigationRef` fields, including how a router whose match is not final at write time fills them in later, how it declares the route the document arrived on with `initial`, and how one that awaits before writing hands the click back as `interaction`.
289289
:::
290290

291291
## The test sees the old DOM
@@ -345,7 +345,7 @@ An error thrown inside a computation that no boundary catches halts the reactive
345345

346346
```text
347347
[REACTIVITY_HALTED] An uncaught error halted the reactive system. No further updates will be processed.
348-
Handle errors with createErrorBoundary/<Errored> or treat this as a crash.
348+
Handle errors with <Errored> or treat this as a crash.
349349
```
350350

351351
Nothing on the page updates after this until a reload.

‎src/routes/(5)guides/(15)observability.mdx‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ The fields it returns replace the runtime's derivation; its `entries` merge by n
180180
| `"render"` | server | A `renderToString` or `renderToStream` render: how long the shell took and how many boundaries it waited on. |
181181
| `"boundary"` | server | A `Loading` boundary that waited during a render; one that rendered on its first pass emits nothing. |
182182
| `"invocation"` | server | A server-function execution, from HTTP dispatch or an in-process call. |
183+
| `"request"` | client | A server-function request the page sent, delivered at the send, so a call still in flight has a row. |
183184
| `"call"` | client | A server-function call the page made, as the caller awaited it. |
184185
| `"frame"` | both | A frame stream produced (server) or applied (client). |
185186
| `"recovery"` | client | A `Loading` boundary the server gave up on, re-rendered as fresh DOM on the client; joins its `"boundary"` by id. |
@@ -204,6 +205,8 @@ Render `/orders` with a slow database and the line reads `<Loading> at <App> ›
204205
A record is data: ids, names, an outcome, `at` on the `performance.now()` clock, durations, counts.
205206
Anything live — the request, the response, the arguments, the error as thrown — travels in a second argument to the listener, never on the record, so a record can leave the process as it is.
206207
A client `"call"` and the server `"invocation"` it caused share an `id`; the difference between their durations is the wire.
208+
The `"request"` and `"call"` records of one call share their `live` object by identity, filled in as the call proceeds, so a listener holding it from the send reads the outcome off it at settle.
209+
Request and response bodies are taken only for a listener that asked, `subscribe("call", fn, { bodies: true })`; a listener that reads ids, statuses, and timings never pays for them.
207210
An invocation made during a boundary's render pass names that boundary, so a wait can be read as the calls it consisted of.
208211

209212
Listeners run synchronously inside the runtime, the moment the record is complete.
@@ -235,7 +238,7 @@ OBSERVE?.records.subscribe("interaction", (event) => {
235238
Click "Place order" and the line reads `click on button#place-order "Place order" took 840ms to settle: ["placeOrder held 812ms"]`.
236239
An interaction record carries the handler's own time, the writes it made, the re-runs and creations they caused, when the last effect that traces back to it ran (`settledMs`), and the holds and navigations it performed, each settled before the interaction is.
237240
A hold names what blocked the write, how long, and whether the screen acknowledged the wait with `isPending`, `latest`, or an optimistic value; `silent` is `true` on a hold nothing acknowledged, which is what the shopper experiences as a dead click, and `long` on one whose wait ran past the point a fallback should have taken over.
238-
A router that wraps its location write in `OBSERVE.attribution.withOrigin` gives its navigations the matched route pattern as their name, so `/orders/:id` folds together across shoppers.
241+
A router that wraps its location write in `OBSERVE.attribution.withOrigin` gives its navigations the matched route pattern as their name, so `/orders/:id` folds together across shoppers; the route the document arrived on is declared the same way, so the first navigation has a name too, and a server `"render"` record carries it as `route`.
239242

240243
`enable()` takes a hold on the engine and returns its release.
241244
The engine is shared by every tool on the page — an adapter, the Performance panel tracks, a diagnostics capture — so each takes its own hold, options combine by the most demanding request per key, and the engine stays on until the last release; `attribution.disable()` tears everything down regardless.
@@ -279,6 +282,8 @@ createRoot(() => {
279282
});
280283
```
281284

285+
A tool that renders the app inside its own shell, `<DevToolbar><App /></DevToolbar>`, excludes the shell and re-admits the app with `OBSERVE.include(owner)` at the app's root; each owner answers by its nearest marked ancestor.
286+
282287
## Common problems
283288

284289
### `OBSERVE` is `undefined` in production

‎src/routes/(5)guides/(16)observability-adapters.mdx‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ The contract that shapes a span builder:
6060
- Server records are delivered during the request, so a Node SDK whose active span is the request's parents them without anything passing a parent around.
6161
- A client `"call"` and the server `"invocation"` it caused share `id`.
6262
An invocation made during a boundary's render pass carries `boundary`, the `id` of that boundary's record.
63+
- A `"request"` record leaves at the send, before the transport's `fetch`, for a call the `"call"` record cannot show yet: one still in flight, or one that never settles.
64+
The two share one `live` object by identity.
65+
- Bodies cost the call a copy, so they are taken only under `subscribe(type, fn, { bodies: true })`; without it `live.request` is absent and `live.response` is the transport's own, already consumed.
6366

6467
```ts
6568
import { OBSERVE } from "solid-js";
@@ -117,6 +120,7 @@ Keep a `WeakMap` from origin to span and a call finds its parent without a clock
117120
The stamp is read at dispatch: a call made synchronously in the handler carries it even when the response lands after the interaction settled, which is the usual shape of `onClick={async () => set(await call())}`; a call made after an `await` in the handler carries nothing, the same escape a write there has.
118121

119122
Routers declare their navigations to the engine with `OBSERVE.attribution.withOrigin`, so navigation records carry the matched route pattern as `name`; an adapter needs no router code.
123+
The route the document arrived on is declared with the same call around the router's initial match, so the first `"navigation"` record names it with `initial: true`, timed from the document's navigation start, and the server `"render"` record carries the matched route as `route`; a router that resolves guards or loaders before it writes the location hands the interaction it captured back as `interaction`, and the write joins the click as if it had been synchronous.
120124

121125
## Trace context: answer once, the runtime carries it
122126

@@ -168,6 +172,7 @@ createRoot(() => {
168172
```
169173

170174
Under an excluded owner, diagnostics about the subtree are neither delivered nor reported, and the engine records no runs for its computations.
175+
An adapter that renders the app inside its own shell excludes the shell and calls `OBSERVE.include(owner)` at the app's root to re-admit it; the verdict comes from the nearest marked ancestor, and a mark belongs at the owner's creation.
171176
The signals and stores created under it stay excluded wherever their writes come from, so the writes need no `runWithOwner` and must not use one: a write under an owner is a write in an owned scope, which the dev build flags.
172177

173178
## Test against the observe build

‎src/routes/(5)guides/(8)ssr-safe-code.mdx‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,23 @@ In the `Prefer` version the server renders `class="drawer"`, the browser hydrate
122122
Resizing the window updates it again through the listener, and the returned cleanup removes the listener when the drawer is disposed.
123123
[Custom primitives](/guides/custom-primitives#clean-up-what-you-start) turns this into a reusable `createMediaQuery`.
124124

125+
The `false` seed is right while the browser is claiming server HTML, and wrong when the drawer is created later by a client-side navigation: there is no server markup to agree with, and the class still flips one frame after it appears.
126+
[`isHydrating`](/reference/solid-js/advanced/manual-hydration/is-hydrating) tells the two apart, so the seed can ask the browser whenever the answer will not be checked against the server:
127+
128+
```tsx
129+
import { createSignal, isHydrating, onSettled } from "solid-js";
130+
import { isServer } from "@solidjs/web";
131+
132+
const [compact, setCompact] = createSignal(
133+
isServer || isHydrating()
134+
? false
135+
: window.matchMedia("(max-width: 40rem)").matches
136+
);
137+
```
138+
139+
`isHydrating()` is `true` during the root pass of `hydrate()` and while a streamed boundary resumes, and `false` on the server, in client-only renders, and after hydration; it is not reactive, so read it where the signal is created.
140+
The `onSettled` callback stays: it is still what updates the value after a hydrated first paint.
141+
125142
Some helpers are called from places that have no owner, such as a formatting function shared with server code.
126143
For those, [`isServer`](/reference/solid-web/rendering-ssr/is-server) from `@solidjs/web` is a build-time constant, `true` in the server build and `false` in the browser build, so the bundler drops the branch that cannot run:
127144

‎src/routes/reference/(1)solid-js/(0)index.mdx‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,13 @@ Built-in components for conditions, lists, and boundaries.
6969

7070
## Advanced
7171

72-
Owner introspection, specialized effects, store internals, boundary primitives, manual hydration, interop, and development hooks.
72+
Owner introspection, specialized effects, store internals, list primitives, manual hydration, interop, and development hooks.
7373
These pages support libraries and tooling; application code rarely needs them.
7474

7575
- [`createRoot`](/reference/solid-js/advanced/owner-introspection/create-root), [`getOwner`](/reference/solid-js/advanced/owner-introspection/get-owner), and [`runWithOwner`](/reference/solid-js/advanced/owner-introspection/run-with-owner) manage reactive scopes by hand.
7676
- [`createRenderEffect`](/reference/solid-js/advanced/specialized-reactivity/create-render-effect) and [`onCleanup`](/reference/solid-js/advanced/specialized-reactivity/on-cleanup) serve renderers and custom primitives.
77-
- [`createLoadingBoundary`](/reference/solid-js/advanced/jsx-component-primitives/create-loading-boundary) and [`createErrorBoundary`](/reference/solid-js/advanced/jsx-component-primitives/create-error-boundary) back the flow components.
77+
- [`mapArray`](/reference/solid-js/advanced/jsx-component-primitives/map-array) and [`repeat`](/reference/solid-js/advanced/jsx-component-primitives/repeat) are the list primitives behind `For` and `Repeat`.
78+
- [`isHydrating`](/reference/solid-js/advanced/manual-hydration/is-hydrating) says whether the running code is claiming server-rendered DOM; [`isHydratable`](/reference/solid-js/advanced/manual-hydration/is-hydratable) whether the owner sits where hydration applies.
7879
- [`DEV`](/reference/solid-js/advanced/diagnostics-dev-hooks/dev) exposes the development diagnostics that [Debugging reactivity](/guides/debugging-reactivity) reads.
7980

8081
## Types

‎src/routes/reference/(1)solid-js/(5)components-jsx/reveal.mdx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,4 +136,4 @@ type RevealProps = {
136136

137137
#### `children`
138138

139-
- **Type:** `SolidElement`
139+
- **Type:** `JSX.Element`

0 commit comments

Comments
 (0)