@real-router/solid 0.11.0 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/README.md +169 -14
  2. package/dist/cjs/index.d.ts +20 -1
  3. package/dist/cjs/index.js +0 -0
  4. package/dist/cjs/ssr.d.ts +163 -0
  5. package/dist/cjs/ssr.js +263 -0
  6. package/dist/esm/index.d.mts +20 -1
  7. package/dist/esm/index.mjs +0 -0
  8. package/dist/esm/ssr.d.mts +163 -0
  9. package/dist/esm/ssr.mjs +254 -0
  10. package/dist/types/RouterProvider.d.ts.map +1 -1
  11. package/dist/types/components/Await.d.ts +30 -0
  12. package/dist/types/components/Await.d.ts.map +1 -0
  13. package/dist/types/components/ClientOnly.d.ts +7 -0
  14. package/dist/types/components/ClientOnly.d.ts.map +1 -0
  15. package/dist/types/components/HttpStatusCode.d.ts +52 -0
  16. package/dist/types/components/HttpStatusCode.d.ts.map +1 -0
  17. package/dist/types/components/HttpStatusProvider.d.ts +9 -0
  18. package/dist/types/components/HttpStatusProvider.d.ts.map +1 -0
  19. package/dist/types/components/Link.d.ts.map +1 -1
  20. package/dist/types/components/RouteView/RouteView.d.ts.map +1 -1
  21. package/dist/types/components/RouteView/components.d.ts.map +1 -1
  22. package/dist/types/components/RouteView/helpers.d.ts.map +1 -1
  23. package/dist/types/components/ServerOnly.d.ts +7 -0
  24. package/dist/types/components/ServerOnly.d.ts.map +1 -0
  25. package/dist/types/components/Streamed.d.ts +18 -0
  26. package/dist/types/components/Streamed.d.ts.map +1 -0
  27. package/dist/types/constants.d.ts +20 -2
  28. package/dist/types/constants.d.ts.map +1 -1
  29. package/dist/types/context.d.ts +9 -0
  30. package/dist/types/context.d.ts.map +1 -1
  31. package/dist/types/createSignalFromSource.d.ts.map +1 -1
  32. package/dist/types/createStoreFromSource.d.ts +19 -0
  33. package/dist/types/createStoreFromSource.d.ts.map +1 -1
  34. package/dist/types/directives/link.d.ts.map +1 -1
  35. package/dist/types/dom-utils/__test-helpers/expected-fragment.d.ts +31 -0
  36. package/dist/types/dom-utils/__test-helpers/expected-fragment.d.ts.map +1 -0
  37. package/dist/types/dom-utils/__test-helpers/index.d.ts +9 -0
  38. package/dist/types/dom-utils/__test-helpers/index.d.ts.map +1 -0
  39. package/dist/types/dom-utils/link-utils.d.ts +23 -0
  40. package/dist/types/dom-utils/link-utils.d.ts.map +1 -1
  41. package/dist/types/dom-utils/route-announcer.d.ts.map +1 -1
  42. package/dist/types/dom-utils/scroll-restore.d.ts +38 -1
  43. package/dist/types/dom-utils/scroll-restore.d.ts.map +1 -1
  44. package/dist/types/hooks/useDeferred.d.ts +16 -0
  45. package/dist/types/hooks/useDeferred.d.ts.map +1 -0
  46. package/dist/types/hooks/useNavigator.d.ts.map +1 -1
  47. package/dist/types/hooks/useRouteUtils.d.ts.map +1 -1
  48. package/dist/types/hooks/useRouter.d.ts.map +1 -1
  49. package/dist/types/index.d.ts +1 -0
  50. package/dist/types/index.d.ts.map +1 -1
  51. package/dist/types/ssr.d.ts +16 -0
  52. package/dist/types/ssr.d.ts.map +1 -0
  53. package/dist/types/utils/createHttpStatusSink.d.ts +29 -0
  54. package/dist/types/utils/createHttpStatusSink.d.ts.map +1 -0
  55. package/dist/types/utils/createMountedSignal.d.ts +16 -0
  56. package/dist/types/utils/createMountedSignal.d.ts.map +1 -0
  57. package/package.json +20 -4
  58. package/src/RouterProvider.tsx +36 -30
  59. package/src/components/Await.tsx +56 -0
  60. package/src/components/ClientOnly.tsx +20 -0
  61. package/src/components/HttpStatusCode.tsx +65 -0
  62. package/src/components/HttpStatusProvider.tsx +21 -0
  63. package/src/components/Link.tsx +21 -15
  64. package/src/components/RouteView/RouteView.tsx +19 -18
  65. package/src/components/RouteView/components.tsx +34 -28
  66. package/src/components/RouteView/helpers.tsx +0 -0
  67. package/src/components/ServerOnly.tsx +20 -0
  68. package/src/components/Streamed.tsx +23 -0
  69. package/src/constants.ts +20 -2
  70. package/src/context.ts +21 -1
  71. package/src/createSignalFromSource.ts +48 -5
  72. package/src/createStoreFromSource.ts +49 -2
  73. package/src/directives/link.tsx +41 -16
  74. package/src/hooks/useDeferred.tsx +36 -0
  75. package/src/hooks/useNavigator.tsx +3 -12
  76. package/src/hooks/useRouteUtils.tsx +39 -1
  77. package/src/hooks/useRouter.tsx +3 -12
  78. package/src/index.tsx +2 -0
  79. package/src/ssr.tsx +39 -0
  80. package/src/utils/createHttpStatusSink.ts +31 -0
  81. package/src/utils/createMountedSignal.ts +26 -0
@@ -0,0 +1,263 @@
1
+ 'use strict';
2
+
3
+ var web = require('solid-js/web');
4
+ var solidJs = require('solid-js');
5
+
6
+ /**
7
+ * Returns a boolean accessor that is `false` during initial render (SSR
8
+ * and the first client paint) and flips to `true` once the component
9
+ * has mounted in the browser.
10
+ *
11
+ * Solid guarantees that `onMount` does NOT fire during `renderToString` /
12
+ * `renderToStream`, so the accessor stays `false` server-side — this is
13
+ * the building block for SSR boundary components (`<ClientOnly>` /
14
+ * `<ServerOnly>`).
15
+ *
16
+ * Consolidates the identical `createSignal(false) + onMount(setMounted)`
17
+ * pattern across the two boundary components (§8a Q15).
18
+ */
19
+ function createMountedSignal() {
20
+ const [mounted, setMounted] = solidJs.createSignal(false);
21
+ solidJs.onMount(() => {
22
+ setMounted(true);
23
+ });
24
+ return mounted;
25
+ }
26
+
27
+ function ClientOnly(props) {
28
+ const mounted = createMountedSignal();
29
+ return web.createComponent(solidJs.Show, {
30
+ get when() {
31
+ return mounted();
32
+ },
33
+ get fallback() {
34
+ return props.fallback;
35
+ },
36
+ get children() {
37
+ return props.children;
38
+ }
39
+ });
40
+ }
41
+
42
+ function ServerOnly(props) {
43
+ const mounted = createMountedSignal();
44
+ return web.createComponent(solidJs.Show, {
45
+ get when() {
46
+ return mounted();
47
+ },
48
+ get fallback() {
49
+ return props.children;
50
+ },
51
+ get children() {
52
+ return props.fallback;
53
+ }
54
+ });
55
+ }
56
+
57
+ solidJs.createContext(null);
58
+ const RouteContext = solidJs.createContext(null);
59
+
60
+ const useRoute = () => {
61
+ const routeSignal = solidJs.useContext(RouteContext);
62
+ if (!routeSignal) {
63
+ throw new Error("useRoute must be used within a RouterProvider");
64
+ }
65
+ if (!routeSignal().route) {
66
+ throw new Error("useRoute called with no active route. Did you forget to await router.start() before rendering, or is the router stopped/disposed?");
67
+ }
68
+ return routeSignal;
69
+ };
70
+
71
+ const NEVER_PROMISE = new Promise(() => {
72
+ // Intentionally never resolves — surfaces a forever-pending Suspense boundary
73
+ // when a key is requested that the loader never declared.
74
+ });
75
+
76
+ /**
77
+ * Read a deferred promise published by `defer({ deferred: { <key>: Promise } })`
78
+ * inside an SSR data loader.
79
+ *
80
+ * Returns a Solid `Accessor<Promise<T>>` so the value tracks the active route
81
+ * — re-reading on navigation picks up the new state's deferred map. Wrap with
82
+ * `<Await name="key">{(value) => …}</Await>` (this package), which builds on
83
+ * `createResource` + `<Suspense>` for native Solid streaming.
84
+ *
85
+ * Returns a forever-pending promise when the key is missing — surfaces
86
+ * loader/consumer key drift as a visible Suspense fallback rather than a
87
+ * silent runtime error.
88
+ */
89
+ function useDeferred(key) {
90
+ const routeAccessor = useRoute();
91
+ return () => {
92
+ const context = routeAccessor().route.context;
93
+ const deferred = context.ssrDataDeferred;
94
+ return deferred?.[key] ?? NEVER_PROMISE;
95
+ };
96
+ }
97
+
98
+ /**
99
+ * Reads `useDeferred(name)` and hands the resolved value to the render-prop.
100
+ * Wraps the deferred promise in `createResource` so Solid's reactivity tracks
101
+ * resolution and `<Suspense>` gets the standard suspend signal.
102
+ *
103
+ * ```tsx
104
+ * <Streamed fallback={<Spinner />}>
105
+ * <Await<Review[]> name="reviews">
106
+ * {(reviews) => <ReviewList items={reviews} />}
107
+ * </Await>
108
+ * </Streamed>
109
+ * ```
110
+ *
111
+ * Implementation: returns a Solid accessor (function child) that reads
112
+ * `resource()` — this both (a) triggers `<Suspense>` suspension while pending
113
+ * and (b) re-throws on `errored` for the nearest `<ErrorBoundary>` to catch.
114
+ * The render-prop is gated on `resource.state === "ready"` rather than on
115
+ * truthiness so falsy resolved values (`0`, `false`, `null`, `""`) still
116
+ * reach `props.children`.
117
+ */
118
+ function Await(props) {
119
+ const promiseAccessor = useDeferred(props.name);
120
+ const [resource] = solidJs.createResource(promiseAccessor, promise => promise);
121
+
122
+ // The double cast `as unknown as JSX.Element` (audit-2026-05-17 §8a) is
123
+ // load-bearing: this returns a Solid accessor *function*, not an element
124
+ // node. `JSX.Element` in Solid is a union that includes function-as-child
125
+ // for reactive bindings, but the type machinery can't narrow the bare
126
+ // arrow's signature to that union — going through `unknown` is the
127
+ // standard escape hatch used elsewhere in solid-router-style adapters.
128
+ // Removing either cast yields a "Type '() => unknown' is not assignable
129
+ // to type 'JSX.Element'" error.
130
+ return () => {
131
+ const value = resource();
132
+ if (resource.state !== "ready") {
133
+ return;
134
+ }
135
+ return props.children(value);
136
+ };
137
+ }
138
+
139
+ /**
140
+ * Cross-adapter alias for Solid's `<Suspense fallback={…}>`. Symmetric naming
141
+ * with the React/Preact/Svelte/Vue/Angular `<Streamed>` components — pick
142
+ * `<Streamed>` for cross-framework consistency, or use Solid's native
143
+ * `<Suspense>` directly when team conventions prefer that.
144
+ *
145
+ * Solid's `<Suspense>` is a built-in primitive; out-of-order resolution +
146
+ * splice scripts during `renderToStream` are part of the runtime. See
147
+ * Solid's SSR docs for the wire-format details.
148
+ */
149
+ function Streamed(props) {
150
+ return web.createComponent(solidJs.Suspense, {
151
+ get fallback() {
152
+ return props.fallback;
153
+ },
154
+ get children() {
155
+ return props.children;
156
+ }
157
+ });
158
+ }
159
+
160
+ const HttpStatusContext = solidJs.createContext(null);
161
+ function HttpStatusProvider(props) {
162
+ return web.createComponent(HttpStatusContext.Provider, {
163
+ get value() {
164
+ return props.sink;
165
+ },
166
+ get children() {
167
+ return props.children;
168
+ }
169
+ });
170
+ }
171
+
172
+ /**
173
+ * Render-time HTTP status declaration. Mount inside a route component (typical
174
+ * use case: a glob `*` route's NotFound page) when the status is decided by
175
+ * the rendered tree rather than a loader.
176
+ *
177
+ * Writes `code` to the nearest `<HttpStatusProvider>`'s sink during render and
178
+ * returns `null`. With no provider mounted (the standard client-side case)
179
+ * the component is a silent no-op — same component tree hydrates without
180
+ * touching the DOM or warning about mismatches.
181
+ *
182
+ * Loader-driven errors (`LoaderNotFound` → 404, `LoaderRedirect` → 30x) keep
183
+ * working as before; this component covers render-time decisions only.
184
+ *
185
+ * Last write wins when several `<HttpStatusCode />` instances mount in the
186
+ * same render pass — sink reflects the last component that ran.
187
+ *
188
+ * ```tsx
189
+ * // entry-server.tsx
190
+ * import { renderToString } from "solid-js/web";
191
+ * import { createHttpStatusSink, HttpStatusProvider } from "@real-router/solid/ssr";
192
+ *
193
+ * const sink = createHttpStatusSink();
194
+ * const html = renderToString(() => (
195
+ * <HttpStatusProvider sink={sink}>
196
+ * <RouterProvider router={router}>
197
+ * <App />
198
+ * </RouterProvider>
199
+ * </HttpStatusProvider>
200
+ * ));
201
+ * response.status(sink.code ?? 200).send(html);
202
+ * ```
203
+ *
204
+ * **Streaming SSR (`renderToStream`):** the response status MUST be sent
205
+ * before the first body byte flushes. If `<HttpStatusCode />` is mounted
206
+ * inside a late-resolving `<Suspense>` boundary, the sink write may happen
207
+ * AFTER the headers are already on the wire — the override is then lost.
208
+ * Mount the component in the shell (above every `<Suspense>` that could
209
+ * delay it), or use `renderToStringAsync` (single-shot, awaits all Suspense
210
+ * before returning HTML).
211
+ *
212
+ * **Valid `code` range:** Node's `res.end()` throws `Invalid status code` on
213
+ * `NaN`, `0`, negative values, or values `> 999` — this surfaces as a 5xx /
214
+ * dropped connection, not silent corruption. Pass a real HTTP status integer
215
+ * (commonly 4xx/5xx; 100-999 is what Node accepts).
216
+ */
217
+ function HttpStatusCode(props) {
218
+ const sink = solidJs.useContext(HttpStatusContext);
219
+ if (sink) {
220
+ sink.code = props.code;
221
+ }
222
+ return null;
223
+ }
224
+
225
+ /**
226
+ * Render-scoped HTTP status sink. Created per request on the server, passed to
227
+ * `<HttpStatusProvider sink={...}>`, and read after `renderToString` /
228
+ * `renderToStream` to apply the value to the HTTP response.
229
+ *
230
+ * Last write wins: if the rendered tree mounts more than one
231
+ * `<HttpStatusCode />`, the value reflects the last component that ran during
232
+ * the render pass.
233
+ *
234
+ * No-op on the client — `<HttpStatusCode />` reads the optional context and
235
+ * skips the write when no provider is mounted, so the same component tree can
236
+ * be hydrated without changing behaviour.
237
+ *
238
+ * Constraints:
239
+ * - **Per-request only.** Don't share a sink across requests; the rendered
240
+ * tree mutates `code` in place. Module-level singletons leak status
241
+ * between concurrent requests.
242
+ * - **Don't `Object.freeze` the sink.** The component writes to `.code`;
243
+ * freezing makes the assignment throw under ESM strict mode.
244
+ * - **Hydration symmetry:** mount `<HttpStatusProvider>` on both server and
245
+ * client (with a throwaway client sink). Solid emits `data-hk` markers
246
+ * per component boundary; an extra provider on one side desyncs the
247
+ * counter and breaks the hydration walker.
248
+ */
249
+
250
+ function createHttpStatusSink() {
251
+ return {
252
+ code: undefined
253
+ };
254
+ }
255
+
256
+ exports.Await = Await;
257
+ exports.ClientOnly = ClientOnly;
258
+ exports.HttpStatusCode = HttpStatusCode;
259
+ exports.HttpStatusProvider = HttpStatusProvider;
260
+ exports.ServerOnly = ServerOnly;
261
+ exports.Streamed = Streamed;
262
+ exports.createHttpStatusSink = createHttpStatusSink;
263
+ exports.useDeferred = useDeferred;
@@ -319,7 +319,26 @@ declare const RouteContext: solid_js.Context<Accessor<RouteState<_real_router_co
319
319
 
320
320
  declare function createSignalFromSource<T>(source: RouterSource<T>): Accessor<T>;
321
321
 
322
+ /**
323
+ * Bridges a `RouterSource<T>` into a Solid store (`createStore` + `reconcile`).
324
+ *
325
+ * Unlike `createSignalFromSource` (whole-value replacement via `===`), this
326
+ * bridge uses `reconcile` on every emit so **unchanged nested paths retain
327
+ * their object identity**. Components that read only `state.route.name` will
328
+ * not re-run when `state.route.params` changes — granular reactivity without
329
+ * manual memoisation.
330
+ *
331
+ * **Ownership**: calls `onCleanup` — must be called inside a reactive owner
332
+ * (component body or `createRoot`). Same contract as `createSignalFromSource`.
333
+ *
334
+ * **Lazy-source re-sync**: after `source.subscribe()`, a cached lazy source
335
+ * may reconcile its snapshot in `onFirstSubscribe`. The listener is not
336
+ * notified for that internal update, so we re-read immediately after
337
+ * subscribing (`setState(reconcile(source.getSnapshot()))`) — mirrors the
338
+ * same pattern in `createSignalFromSource`. `reconcile` is a no-op when the
339
+ * snapshot is structurally unchanged, so there is no spurious reactivity cost.
340
+ */
322
341
  declare function createStoreFromSource<T extends object>(source: RouterSource<T>): T;
323
342
 
324
343
  export { Link, RouteContext, RouteView, RouterContext, RouterErrorBoundary, RouterProvider, createSignalFromSource, createStoreFromSource, link, useNavigator, useRoute, useRouteEnter, useRouteExit, useRouteNode, useRouteNodeStore, useRouteStore, useRouteUtils, useRouter, useRouterTransition };
325
- export type { LinkDirectiveOptions, LinkProps, RouteEnterContext, RouteEnterHandler, RouteExitContext, RouteExitHandler, RouteState, MatchProps as RouteViewMatchProps, NotFoundProps as RouteViewNotFoundProps, RouteViewProps, SelfProps as RouteViewSelfProps, RouterErrorBoundaryProps, UseRouteEnterOptions, UseRouteExitOptions };
344
+ export type { LinkDirectiveOptions, LinkProps, RouteEnterContext, RouteEnterHandler, RouteExitContext, RouteExitHandler, RouteState, MatchProps as RouteViewMatchProps, NotFoundProps as RouteViewNotFoundProps, RouteViewProps, SelfProps as RouteViewSelfProps, RouterContextValue, RouterErrorBoundaryProps, UseRouteEnterOptions, UseRouteExitOptions };
Binary file
@@ -0,0 +1,163 @@
1
+ import { JSX, Accessor } from 'solid-js';
2
+
3
+ interface ClientOnlyProps {
4
+ readonly children: JSX.Element;
5
+ readonly fallback?: JSX.Element;
6
+ }
7
+ declare function ClientOnly(props: ClientOnlyProps): JSX.Element;
8
+
9
+ interface ServerOnlyProps {
10
+ readonly children: JSX.Element;
11
+ readonly fallback?: JSX.Element;
12
+ }
13
+ declare function ServerOnly(props: ServerOnlyProps): JSX.Element;
14
+
15
+ interface AwaitProps<T> {
16
+ /** Deferred key declared in the loader's `defer({ deferred: { <name>: ... } })`. */
17
+ readonly name: string;
18
+ /** Render the resolved value. Surrounding `<Suspense>` shows fallback while
19
+ * pending; rejection bubbles through Solid's `<ErrorBoundary>`. */
20
+ readonly children: (value: T) => JSX.Element;
21
+ }
22
+ /**
23
+ * Reads `useDeferred(name)` and hands the resolved value to the render-prop.
24
+ * Wraps the deferred promise in `createResource` so Solid's reactivity tracks
25
+ * resolution and `<Suspense>` gets the standard suspend signal.
26
+ *
27
+ * ```tsx
28
+ * <Streamed fallback={<Spinner />}>
29
+ * <Await<Review[]> name="reviews">
30
+ * {(reviews) => <ReviewList items={reviews} />}
31
+ * </Await>
32
+ * </Streamed>
33
+ * ```
34
+ *
35
+ * Implementation: returns a Solid accessor (function child) that reads
36
+ * `resource()` — this both (a) triggers `<Suspense>` suspension while pending
37
+ * and (b) re-throws on `errored` for the nearest `<ErrorBoundary>` to catch.
38
+ * The render-prop is gated on `resource.state === "ready"` rather than on
39
+ * truthiness so falsy resolved values (`0`, `false`, `null`, `""`) still
40
+ * reach `props.children`.
41
+ */
42
+ declare function Await<T = unknown>(props: AwaitProps<T>): JSX.Element;
43
+
44
+ interface StreamedProps {
45
+ /** Shown while any descendant `<Await>` / `createResource` suspends. */
46
+ readonly fallback: JSX.Element;
47
+ readonly children: JSX.Element;
48
+ }
49
+ /**
50
+ * Cross-adapter alias for Solid's `<Suspense fallback={…}>`. Symmetric naming
51
+ * with the React/Preact/Svelte/Vue/Angular `<Streamed>` components — pick
52
+ * `<Streamed>` for cross-framework consistency, or use Solid's native
53
+ * `<Suspense>` directly when team conventions prefer that.
54
+ *
55
+ * Solid's `<Suspense>` is a built-in primitive; out-of-order resolution +
56
+ * splice scripts during `renderToStream` are part of the runtime. See
57
+ * Solid's SSR docs for the wire-format details.
58
+ */
59
+ declare function Streamed(props: StreamedProps): JSX.Element;
60
+
61
+ interface HttpStatusCodeProps {
62
+ /** HTTP status to apply to the response. Common values: 404, 410, 451, 503. */
63
+ readonly code: number;
64
+ }
65
+ /**
66
+ * Render-time HTTP status declaration. Mount inside a route component (typical
67
+ * use case: a glob `*` route's NotFound page) when the status is decided by
68
+ * the rendered tree rather than a loader.
69
+ *
70
+ * Writes `code` to the nearest `<HttpStatusProvider>`'s sink during render and
71
+ * returns `null`. With no provider mounted (the standard client-side case)
72
+ * the component is a silent no-op — same component tree hydrates without
73
+ * touching the DOM or warning about mismatches.
74
+ *
75
+ * Loader-driven errors (`LoaderNotFound` → 404, `LoaderRedirect` → 30x) keep
76
+ * working as before; this component covers render-time decisions only.
77
+ *
78
+ * Last write wins when several `<HttpStatusCode />` instances mount in the
79
+ * same render pass — sink reflects the last component that ran.
80
+ *
81
+ * ```tsx
82
+ * // entry-server.tsx
83
+ * import { renderToString } from "solid-js/web";
84
+ * import { createHttpStatusSink, HttpStatusProvider } from "@real-router/solid/ssr";
85
+ *
86
+ * const sink = createHttpStatusSink();
87
+ * const html = renderToString(() => (
88
+ * <HttpStatusProvider sink={sink}>
89
+ * <RouterProvider router={router}>
90
+ * <App />
91
+ * </RouterProvider>
92
+ * </HttpStatusProvider>
93
+ * ));
94
+ * response.status(sink.code ?? 200).send(html);
95
+ * ```
96
+ *
97
+ * **Streaming SSR (`renderToStream`):** the response status MUST be sent
98
+ * before the first body byte flushes. If `<HttpStatusCode />` is mounted
99
+ * inside a late-resolving `<Suspense>` boundary, the sink write may happen
100
+ * AFTER the headers are already on the wire — the override is then lost.
101
+ * Mount the component in the shell (above every `<Suspense>` that could
102
+ * delay it), or use `renderToStringAsync` (single-shot, awaits all Suspense
103
+ * before returning HTML).
104
+ *
105
+ * **Valid `code` range:** Node's `res.end()` throws `Invalid status code` on
106
+ * `NaN`, `0`, negative values, or values `> 999` — this surfaces as a 5xx /
107
+ * dropped connection, not silent corruption. Pass a real HTTP status integer
108
+ * (commonly 4xx/5xx; 100-999 is what Node accepts).
109
+ */
110
+ declare function HttpStatusCode(props: HttpStatusCodeProps): JSX.Element;
111
+
112
+ /**
113
+ * Render-scoped HTTP status sink. Created per request on the server, passed to
114
+ * `<HttpStatusProvider sink={...}>`, and read after `renderToString` /
115
+ * `renderToStream` to apply the value to the HTTP response.
116
+ *
117
+ * Last write wins: if the rendered tree mounts more than one
118
+ * `<HttpStatusCode />`, the value reflects the last component that ran during
119
+ * the render pass.
120
+ *
121
+ * No-op on the client — `<HttpStatusCode />` reads the optional context and
122
+ * skips the write when no provider is mounted, so the same component tree can
123
+ * be hydrated without changing behaviour.
124
+ *
125
+ * Constraints:
126
+ * - **Per-request only.** Don't share a sink across requests; the rendered
127
+ * tree mutates `code` in place. Module-level singletons leak status
128
+ * between concurrent requests.
129
+ * - **Don't `Object.freeze` the sink.** The component writes to `.code`;
130
+ * freezing makes the assignment throw under ESM strict mode.
131
+ * - **Hydration symmetry:** mount `<HttpStatusProvider>` on both server and
132
+ * client (with a throwaway client sink). Solid emits `data-hk` markers
133
+ * per component boundary; an extra provider on one side desyncs the
134
+ * counter and breaks the hydration walker.
135
+ */
136
+ interface HttpStatusSink {
137
+ code: number | undefined;
138
+ }
139
+ declare function createHttpStatusSink(): HttpStatusSink;
140
+
141
+ interface HttpStatusProviderProps {
142
+ readonly sink: HttpStatusSink;
143
+ readonly children: JSX.Element;
144
+ }
145
+ declare function HttpStatusProvider(props: HttpStatusProviderProps): JSX.Element;
146
+
147
+ /**
148
+ * Read a deferred promise published by `defer({ deferred: { <key>: Promise } })`
149
+ * inside an SSR data loader.
150
+ *
151
+ * Returns a Solid `Accessor<Promise<T>>` so the value tracks the active route
152
+ * — re-reading on navigation picks up the new state's deferred map. Wrap with
153
+ * `<Await name="key">{(value) => …}</Await>` (this package), which builds on
154
+ * `createResource` + `<Suspense>` for native Solid streaming.
155
+ *
156
+ * Returns a forever-pending promise when the key is missing — surfaces
157
+ * loader/consumer key drift as a visible Suspense fallback rather than a
158
+ * silent runtime error.
159
+ */
160
+ declare function useDeferred<T = unknown>(key: string): Accessor<Promise<T>>;
161
+
162
+ export { Await, ClientOnly, HttpStatusCode, HttpStatusProvider, ServerOnly, Streamed, createHttpStatusSink, useDeferred };
163
+ export type { AwaitProps, ClientOnlyProps, HttpStatusCodeProps, HttpStatusProviderProps, HttpStatusSink, ServerOnlyProps, StreamedProps };