@rangojs/router 0.34.0 → 0.35.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.
- package/README.md +1 -1
- package/dist/bin/{chunk-4HHFQSDC.js → chunk-3CQXDX3A.js} +5 -5
- package/dist/bin/{client-urls-projection-4Q5EQDAL.js → client-urls-projection-2GBDM5YK.js} +1 -1
- package/dist/bin/rango.js +1 -1
- package/dist/bin/{runtime-discovery-2ZTYRZ3V.js → runtime-discovery-PA3V3IFQ.js} +2 -2
- package/dist/bin/{temp-rsc-server-EUNKRFJD.js → temp-rsc-server-WDXEHDY7.js} +2 -2
- package/dist/types/cache/shell-snapshot.d.ts +1 -1
- package/dist/types/cache/types.d.ts +1 -1
- package/dist/types/client-urls/server-projection.d.ts +1 -1
- package/dist/types/client-urls/types.d.ts +6 -6
- package/dist/types/decode-loader-results.d.ts +1 -1
- package/dist/types/errors.d.ts +3 -3
- package/dist/types/handles/meta.d.ts +2 -2
- package/dist/types/loader-store.d.ts +20 -8
- package/dist/types/outlet-context.d.ts +1 -1
- package/dist/types/route-definition/helpers-types.d.ts +5 -5
- package/dist/types/router/loader-resolution.d.ts +1 -1
- package/dist/types/router/match-context.d.ts +12 -0
- package/dist/types/router/navigation-snapshot.d.ts +17 -0
- package/dist/types/router/segment-resolution/loader-cache.d.ts +7 -7
- package/dist/types/router/types.d.ts +1 -1
- package/dist/types/rsc/shell-capture-constants.d.ts +2 -2
- package/dist/types/server/context.d.ts +3 -3
- package/dist/types/server/request-context.d.ts +1 -1
- package/dist/types/ssr/index.d.ts +1 -1
- package/dist/types/ssr/ssr-root.d.ts +1 -1
- package/dist/types/ssr-suspension-warning.d.ts +1 -1
- package/dist/types/types/loader-types.d.ts +19 -19
- package/dist/types/types/segments.d.ts +2 -2
- package/dist/types/urls/path-helper-types.d.ts +4 -4
- package/dist/types/urls/pattern-types.d.ts +1 -1
- package/dist/types/vite/plugin-types.d.ts +1 -1
- package/dist/vite/index.js +7 -7
- package/package.json +1 -1
- package/skills/app-structure/e-commerce.md +1 -1
- package/skills/breadcrumbs/SKILL.md +5 -5
- package/skills/cache-guide/SKILL.md +4 -4
- package/skills/caching/SKILL.md +1 -1
- package/skills/catalog.json +2 -2
- package/skills/client-urls/SKILL.md +20 -20
- package/skills/comparison/references/framework-comparison.md +6 -6
- package/skills/defer-hydration/SKILL.md +2 -2
- package/skills/handler-use/SKILL.md +5 -5
- package/skills/hooks/data.md +5 -2
- package/skills/hooks/handle-and-actions.md +9 -9
- package/skills/loader/SKILL.md +52 -47
- package/skills/middleware/SKILL.md +2 -2
- package/skills/migrate-nextjs/SKILL.md +10 -10
- package/skills/migrate-react-router/SKILL.md +1 -1
- package/skills/migrate-react-router/component-migration.md +2 -2
- package/skills/migrate-react-router/data-and-actions.md +2 -2
- package/skills/migrate-react-router/route-mapping.md +2 -2
- package/skills/parallel/SKILL.md +2 -2
- package/skills/ppr/SKILL.md +91 -92
- package/skills/prerender/SKILL.md +5 -5
- package/skills/rango/SKILL.md +7 -7
- package/skills/route/SKILL.md +1 -1
- package/skills/router-setup/SKILL.md +2 -2
- package/skills/scripts/SKILL.md +3 -3
- package/skills/shell-manifest/SKILL.md +3 -3
- package/skills/testing/serve-shell-request.md +1 -1
- package/skills/theme/SKILL.md +2 -2
- package/skills/typesafety/env-and-bindings.md +2 -2
- package/skills/use-cache/SKILL.md +1 -1
- package/skills/ux-architecture/SKILL.md +7 -7
- package/src/cache/shell-snapshot.ts +1 -1
- package/src/cache/types.ts +1 -1
- package/src/client-urls/client-urls.ts +16 -9
- package/src/client-urls/server-projection.ts +4 -4
- package/src/client-urls/types.ts +6 -6
- package/src/decode-loader-results.ts +1 -1
- package/src/errors.ts +9 -9
- package/src/handles/meta.ts +2 -2
- package/src/loader-store.ts +29 -13
- package/src/outlet-context.ts +1 -1
- package/src/route-definition/dsl-helpers.ts +4 -8
- package/src/route-definition/helpers-types.ts +5 -5
- package/src/router/loader-resolution.ts +4 -4
- package/src/router/match-api.ts +2 -0
- package/src/router/match-context.ts +22 -1
- package/src/router/match-middleware/cache-lookup.ts +17 -8
- package/src/router/match-middleware/intercept-resolution.ts +3 -3
- package/src/router/navigation-snapshot.ts +39 -8
- package/src/router/segment-resolution/loader-cache.ts +8 -8
- package/src/router/segment-resolution/prefetch-deferral.ts +1 -1
- package/src/router/segment-resolution/revalidation.ts +3 -3
- package/src/router/types.ts +1 -1
- package/src/rsc/shell-capture-constants.ts +3 -3
- package/src/rsc/shell-capture.ts +12 -12
- package/src/segment-system.tsx +3 -3
- package/src/server/context.ts +5 -5
- package/src/server/cookie-store.ts +1 -1
- package/src/server/request-context.ts +1 -1
- package/src/ssr/index.tsx +6 -6
- package/src/ssr/ssr-root.tsx +1 -1
- package/src/ssr-suspension-warning.ts +4 -4
- package/src/types/loader-types.ts +19 -19
- package/src/types/segments.ts +2 -2
- package/src/urls/path-helper-types.ts +4 -4
- package/src/urls/pattern-types.ts +1 -1
- package/src/use-loader.tsx +5 -3
- package/src/vite/discovery/shell-prerender-phase.ts +1 -1
- package/src/vite/plugin-types.ts +1 -1
package/README.md
CHANGED
|
@@ -304,7 +304,7 @@ Loaders run in parallel with the handler and stream their results.
|
|
|
304
304
|
into it. Without `loading()`, the segment has no skeleton, and the HTML
|
|
305
305
|
normally arrives with the data already in place. To guarantee that a
|
|
306
306
|
loader's data, head tags, or a real 404 are in the first HTML flush, register
|
|
307
|
-
it with `loader(StockLoader, { ssr:
|
|
307
|
+
it with `loader(StockLoader, { ssr: "await" })`.
|
|
308
308
|
|
|
309
309
|
When a loader's data changes, every component that reads it updates too.
|
|
310
310
|
Calling `load()` from `useLoader()` refetches it on the client, and
|
|
@@ -23,7 +23,7 @@ import * as React4 from "react";
|
|
|
23
23
|
import { AsyncLocalStorage as AsyncLocalStorage2 } from "node:async_hooks";
|
|
24
24
|
|
|
25
25
|
// src/rsc/shell-capture-constants.ts
|
|
26
|
-
var PPR_LANE_HINT = 'Lane rule: only loader(Def, { ssr:
|
|
26
|
+
var PPR_LANE_HINT = 'Lane rule: only loader(Def, { ssr: "await" }) executes at capture and bakes its non-promise data; every other loader is live (masked at capture, fresh per request) and needs loading() or an inline <Suspense> above its reader. See the /ppr skill, "The loader lane rule" (node_modules/@rangojs/router/skills/ppr/SKILL.md).';
|
|
27
27
|
|
|
28
28
|
// src/cache/cache-exec-scope.ts
|
|
29
29
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
@@ -52,8 +52,8 @@ var LOADER_BODY_SCOPE_KEY = /* @__PURE__ */ Symbol.for("rangojs-router:loader-bo
|
|
|
52
52
|
var loaderBodyScopeALS = globalThis[LOADER_BODY_SCOPE_KEY] ??= new AsyncLocalStorage2();
|
|
53
53
|
function requestReadCaptureFix(what) {
|
|
54
54
|
return {
|
|
55
|
-
capture: `The captured shell is served to every user of this URL, so request-scoped data read here would leak one user's ${what} to others. Read it inside a loader without ssr:
|
|
56
|
-
warning:
|
|
55
|
+
capture: `The captured shell is served to every user of this URL, so request-scoped data read here would leak one user's ${what} to others. Read it inside a loader without ssr: "await" and consume it with useLoader, e.g. createLoader(async () => getUser(cookies().get("session")?.value)). ${PPR_LANE_HINT}`,
|
|
56
|
+
warning: 'Read it in a loader without ssr: "await" and consume it with useLoader under loading() or an inline <Suspense> (a live hole). A promise the handler passes or pushes does not help: the capture waits for it.'
|
|
57
57
|
};
|
|
58
58
|
}
|
|
59
59
|
var NON_CACHEABLE_READ = {
|
|
@@ -1149,7 +1149,7 @@ var RAW_COOKIES_READ = {
|
|
|
1149
1149
|
verb: "called",
|
|
1150
1150
|
fix: COOKIES_READ.fix
|
|
1151
1151
|
};
|
|
1152
|
-
var THEME_READ_FIX =
|
|
1152
|
+
var THEME_READ_FIX = 'On ppr and cache() routes, read the theme with useTheme() in a client component, or in a live loader (no ssr: "await") with cookies().get(<storageKey>). The <html> theme class needs neither: the theme script sets it before paint. See the /theme skill (node_modules/@rangojs/router/skills/theme/SKILL.md).';
|
|
1153
1153
|
var THEME_READ = {
|
|
1154
1154
|
verb: "read",
|
|
1155
1155
|
fix: {
|
|
@@ -1348,7 +1348,7 @@ function serializeRoute(route2, options, ordinals) {
|
|
|
1348
1348
|
});
|
|
1349
1349
|
const awaitedLoaderIndices = indicesWhere(
|
|
1350
1350
|
route2.loaders,
|
|
1351
|
-
({ ssr }) => ssr ===
|
|
1351
|
+
({ ssr }) => ssr === "await"
|
|
1352
1352
|
);
|
|
1353
1353
|
const transition3 = serializeTransition(route2);
|
|
1354
1354
|
return Object.freeze({
|
package/dist/bin/rango.js
CHANGED
|
@@ -229,7 +229,7 @@ ${formatNestedRouterConflictError(nestedRouterConflict, "[rango]")}
|
|
|
229
229
|
}
|
|
230
230
|
let discoverAndWriteRouteTypes;
|
|
231
231
|
try {
|
|
232
|
-
const mod = await import("./runtime-discovery-
|
|
232
|
+
const mod = await import("./runtime-discovery-PA3V3IFQ.js");
|
|
233
233
|
discoverAndWriteRouteTypes = mod.discoverAndWriteRouteTypes;
|
|
234
234
|
} catch (err) {
|
|
235
235
|
if (err.code === "ERR_MODULE_NOT_FOUND" || err.code === "MODULE_NOT_FOUND") {
|
|
@@ -163,9 +163,9 @@ async function discoverAndWriteRouteTypes(opts) {
|
|
|
163
163
|
"Runtime discovery requires '@vitejs/plugin-rsc'. Install it with: pnpm add -D @vitejs/plugin-rsc"
|
|
164
164
|
);
|
|
165
165
|
}
|
|
166
|
-
const { createTempRscServer } = await import("./temp-rsc-server-
|
|
166
|
+
const { createTempRscServer } = await import("./temp-rsc-server-WDXEHDY7.js");
|
|
167
167
|
const { createDiscoveryState } = await import("./state-ACD2MGKJ.js");
|
|
168
|
-
const { discoverClientUrlProjections } = await import("./client-urls-projection-
|
|
168
|
+
const { discoverClientUrlProjections } = await import("./client-urls-projection-2GBDM5YK.js");
|
|
169
169
|
const {
|
|
170
170
|
isFrameworkPlugin,
|
|
171
171
|
pickForwardedRunnerConfig,
|
|
@@ -27,7 +27,7 @@ import {
|
|
|
27
27
|
propertyKeyIs,
|
|
28
28
|
recordClientUrlsModule,
|
|
29
29
|
unwrapExpression
|
|
30
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-3CQXDX3A.js";
|
|
31
31
|
import "./chunk-MWOHBDPM.js";
|
|
32
32
|
import {
|
|
33
33
|
codeMatchIndices,
|
|
@@ -47,7 +47,7 @@ var DEFAULT_ROUTER_VERSIONS_KEY = "*";
|
|
|
47
47
|
// package.json
|
|
48
48
|
var package_default = {
|
|
49
49
|
name: "@rangojs/router",
|
|
50
|
-
version: "0.
|
|
50
|
+
version: "0.35.0",
|
|
51
51
|
description: "Django-inspired RSC router with composable URL patterns",
|
|
52
52
|
keywords: [
|
|
53
53
|
"react",
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* that must agree with them byte for byte. The handler layer's part of that
|
|
6
6
|
* payload is the capture's own doc segment record: the capture writes it
|
|
7
7
|
* first, renders its prelude from it, and every HIT replays it (no handler
|
|
8
|
-
* runs on a HIT). The loader layer's part is the bake-lane (`ssr:
|
|
8
|
+
* runs on a HIT). The loader layer's part is the bake-lane (`ssr: "await"`)
|
|
9
9
|
* loader pins: a promise-free bake-lane loader is served from its pin and
|
|
10
10
|
* does not run; one whose return carries promises (`holes`), or whose pushes
|
|
11
11
|
* the record could not keep (`runs`), runs on the HIT. See
|
|
@@ -770,7 +770,7 @@ export type SegmentHandleData = Record<string, unknown[]>;
|
|
|
770
770
|
/**
|
|
771
771
|
* segmentId -> handleName -> the owning loader id of each recorded value, by
|
|
772
772
|
* index (null: not owned). Only a PPR shell capture writes owners: the
|
|
773
|
-
* settled pushes of the loader bodies it ran (an `ssr:
|
|
773
|
+
* settled pushes of the loader bodies it ran (an `ssr: "await"` loader's own,
|
|
774
774
|
* the loaders it awaits, and its own cache() replays), which the record keeps
|
|
775
775
|
* because the prelude rendered them. A restore of the record
|
|
776
776
|
* (handle-snapshot.ts restoreHandles) keeps an owner's value where the
|
|
@@ -28,7 +28,7 @@ export interface ClientUrlProjectionRoute {
|
|
|
28
28
|
readonly options: ClientUrlProjectionOptions;
|
|
29
29
|
readonly loaderIds: readonly string[];
|
|
30
30
|
readonly hasLoading: boolean;
|
|
31
|
-
/** Indices into loaderIds of loaders declared loader(Def, { ssr:
|
|
31
|
+
/** Indices into loaderIds of loaders declared loader(Def, { ssr: "await" });
|
|
32
32
|
* materialization passes the option through to the server loader() so
|
|
33
33
|
* document renders await them before first flush. Absent (= none) in
|
|
34
34
|
* projections serialized before the option existed. */
|
|
@@ -42,12 +42,12 @@ export interface ClientUrlLoaderRecord {
|
|
|
42
42
|
*/
|
|
43
43
|
readonly revalidate: readonly (ShouldRevalidateFn<any, DefaultEnv> | HoistedRevalidateRef | boolean)[];
|
|
44
44
|
/**
|
|
45
|
-
* loader(Def, { ssr:
|
|
45
|
+
* loader(Def, { ssr: "await" }): document renders await this loader before
|
|
46
46
|
* first flush (see {@link LoaderOptions}). Projected into the server tree,
|
|
47
47
|
* where the per-isSSR entry stamping applies — client navigations stream
|
|
48
48
|
* regardless.
|
|
49
49
|
*/
|
|
50
|
-
readonly ssr?:
|
|
50
|
+
readonly ssr?: "await";
|
|
51
51
|
/**
|
|
52
52
|
* loader(Def, { prefetch: false | "intent" }): a prefetch of the route, or
|
|
53
53
|
* of an intercept's target from its source, defers this loader and the
|
|
@@ -109,10 +109,10 @@ export interface ClientUrlHelpers {
|
|
|
109
109
|
* Attach a projected loader. The optional use callback may contain
|
|
110
110
|
* revalidate() only: a per-loader predicate the server runs, as in urls().
|
|
111
111
|
*
|
|
112
|
-
* Pass `{ ssr:
|
|
113
|
-
*
|
|
114
|
-
*
|
|
115
|
-
*
|
|
112
|
+
* Pass `{ ssr: "await" }` to await this loader before first flush on
|
|
113
|
+
* DOCUMENT requests (see {@link LoaderOptions}): the opt-in for loaders
|
|
114
|
+
* whose data, handle pushes, or thrown notFound()/redirect() must be in the
|
|
115
|
+
* SSR'd HTML.
|
|
116
116
|
* Per-loader: a streaming sibling keeps streaming. Under a `ppr` group
|
|
117
117
|
* route the flag BAKES: the loader executes at shell capture and its
|
|
118
118
|
* settled return freezes into the shell (nested promises stay live
|
|
@@ -18,7 +18,7 @@ import { type ErrorInfo, type ResolvedSegment } from "./types.js";
|
|
|
18
18
|
* decodeLoaderResults runs during the tree build on settled results, where a
|
|
19
19
|
* throw would collapse the whole payload — it routes signals through the
|
|
20
20
|
* errorFallback slot instead (same visual: the slot replaces the children
|
|
21
|
-
* under OutletProvider). The document lane's `{ ssr:
|
|
21
|
+
* under OutletProvider). The document lane's `{ ssr: "await" }` results take
|
|
22
22
|
* this route (segment-system buildLoaderStreams): they are settled before the
|
|
23
23
|
* tree is built, and the read-site throw would land in the Fizz shell with no
|
|
24
24
|
* boundary to absorb it.
|
package/dist/types/errors.d.ts
CHANGED
|
@@ -243,10 +243,10 @@ export declare class InvalidHandlerError extends Error {
|
|
|
243
243
|
*/
|
|
244
244
|
export declare function invariant(condition: any, message: string): asserts condition;
|
|
245
245
|
/**
|
|
246
|
-
* Rejects a
|
|
247
|
-
* passes)
|
|
246
|
+
* Rejects a loader `ssr` option other than `"stream"` or `"await"`
|
|
247
|
+
* (undefined passes). clientUrls() inlines the same checks.
|
|
248
248
|
*/
|
|
249
|
-
export declare function
|
|
249
|
+
export declare function assertLoaderSsrOption(value: unknown, helper: string): void;
|
|
250
250
|
/**
|
|
251
251
|
* Rejects a `prefetch` DSL option that is neither a boolean nor `"intent"`
|
|
252
252
|
* (undefined passes), as an invariant.
|
|
@@ -40,9 +40,9 @@ import type { MetaDescriptor } from "../router/types.js";
|
|
|
40
40
|
* title-templating identically to synchronous descriptors. A descriptor that
|
|
41
41
|
* resolves to `null`/`undefined` (or rejects) is dropped.
|
|
42
42
|
*
|
|
43
|
-
* On a ppr route, a descriptor a handler or an `ssr:
|
|
43
|
+
* On a ppr route, a descriptor a handler or an `ssr: "await"` loader pushes,
|
|
44
44
|
* promise or not, is in the shell's `<head>` on every HIT (#1182). One a
|
|
45
|
-
* loader without `ssr:
|
|
45
|
+
* loader without `ssr: "await"` pushes is live: on a HIT it arrives after
|
|
46
46
|
* hydration.
|
|
47
47
|
*/
|
|
48
48
|
export declare const Meta: Handle<MetaDescriptor, MetaDescriptor[]>;
|
|
@@ -28,6 +28,10 @@
|
|
|
28
28
|
* cancelled on resubscribe so a StrictMode / transition remount does not
|
|
29
29
|
* reclaim a bucket that is about to be reused, and is held until any
|
|
30
30
|
* in-flight load settles.
|
|
31
|
+
* - Owned buckets (one reader's private refresh-group bucket,
|
|
32
|
+
* `useLoader(L, { refreshGroup })` without a key) are sticky while that
|
|
33
|
+
* reader is mounted and dropped like an ephemeral bucket once it leaves:
|
|
34
|
+
* no other reader names the bucket, and a remount takes a new one.
|
|
31
35
|
*
|
|
32
36
|
* Each router's NavigationStore owns one (navigation-store.ts), and hooks reach
|
|
33
37
|
* it through NavigationStoreContext: the router store is the single source of
|
|
@@ -79,6 +83,13 @@ export interface SubscribeOptions {
|
|
|
79
83
|
* subscriber attaches, and from then on resets via `clearFamily`.
|
|
80
84
|
*/
|
|
81
85
|
ephemeral?: boolean;
|
|
86
|
+
/**
|
|
87
|
+
* When true, the bucket belongs to this subscriber alone (a private
|
|
88
|
+
* refresh-group bucket, which no other reader names): it is reset by
|
|
89
|
+
* `clearFamily` while subscribed, and dropped after the subscriber leaves
|
|
90
|
+
* even when sticky. Read at unsubscribe, so pass it on every subscribe.
|
|
91
|
+
*/
|
|
92
|
+
owned?: boolean;
|
|
82
93
|
/**
|
|
83
94
|
* Cross-loader refresh group name(s). Tags this bucket so `refreshGroups(name)`
|
|
84
95
|
* can refresh it alongside buckets of other loaders. A bucket may be tagged
|
|
@@ -130,8 +141,8 @@ export declare class LoaderStore {
|
|
|
130
141
|
* Subscribe to entry changes for `bucketKey`.
|
|
131
142
|
* Returns an unsubscribe function. A sticky bucket's entry is kept around even
|
|
132
143
|
* after the last subscriber leaves so that an in-flight `load()` can still
|
|
133
|
-
* commit if the consumer remounts. An ephemeral bucket is dropped
|
|
134
|
-
* last subscriber leaves (deferred, see maybeScheduleRefcountClear).
|
|
144
|
+
* commit if the consumer remounts. An ephemeral or owned bucket is dropped
|
|
145
|
+
* once its last subscriber leaves (deferred, see maybeScheduleRefcountClear).
|
|
135
146
|
*/
|
|
136
147
|
subscribe(bucketKey: string, cb: () => void, options?: SubscribeOptions): () => void;
|
|
137
148
|
private addToGroup;
|
|
@@ -149,14 +160,14 @@ export declare class LoaderStore {
|
|
|
149
160
|
*/
|
|
150
161
|
refreshGroups(groups: string | string[]): Promise<void>;
|
|
151
162
|
/**
|
|
152
|
-
* Schedule a deferred drop for an ad-hoc (never-sticky)
|
|
153
|
-
* subscriber just left. Deferred to a microtask so a StrictMode /
|
|
154
|
-
* remount that resubscribes in the same tick cancels it.
|
|
163
|
+
* Schedule a deferred drop for an ad-hoc (never-sticky) or owned bucket
|
|
164
|
+
* whose last subscriber just left. Deferred to a microtask so a StrictMode /
|
|
165
|
+
* transition remount that resubscribes in the same tick cancels it.
|
|
155
166
|
*/
|
|
156
167
|
private maybeScheduleRefcountClear;
|
|
157
168
|
/** Remove a bucket entry entirely and prune it from its family/group indexes. */
|
|
158
169
|
private dropBucket;
|
|
159
|
-
/** Drop an ephemeral bucket that settled with no subscribers left. */
|
|
170
|
+
/** Drop an ephemeral or owned bucket that settled with no subscribers left. */
|
|
160
171
|
private dropIfSettled;
|
|
161
172
|
/**
|
|
162
173
|
* Returns the current snapshot for `bucketKey`. Stable reference between
|
|
@@ -205,7 +216,8 @@ export declare class LoaderStore {
|
|
|
205
216
|
* Reset a single bucket entry. Bumps `latestRequestId` so any in-flight
|
|
206
217
|
* `load()` whose promise is still pending will fail its gate when it resolves
|
|
207
218
|
* and be dropped — prevents pre-navigation loads from clobbering the new
|
|
208
|
-
* route's context. The entry itself is kept (sticky-bucket semantics)
|
|
219
|
+
* route's context. The entry itself is kept (sticky-bucket semantics),
|
|
220
|
+
* unless it was only waiting for that request to be dropped.
|
|
209
221
|
*/
|
|
210
222
|
clear(bucketKey: string): void;
|
|
211
223
|
/**
|
|
@@ -221,7 +233,7 @@ export declare class LoaderStore {
|
|
|
221
233
|
/**
|
|
222
234
|
* Register a still-streaming per-loader result for `loaderId`. No-op for a
|
|
223
235
|
* settled Flight chunk (unwrapsSynchronously / "rejected"): the forceAwait
|
|
224
|
-
* and action lanes commit settled chunks, and a { ssr:
|
|
236
|
+
* and action lanes commit settled chunks, and a { ssr: "await" } loader is
|
|
225
237
|
* awaited before flush. Released as the stream settles, either way.
|
|
226
238
|
*/
|
|
227
239
|
trackPendingStream(loaderId: string, stream: Promise<unknown>): void;
|
|
@@ -19,7 +19,7 @@ export interface OutletContextValue {
|
|
|
19
19
|
loaderStreams?: Record<string, unknown>;
|
|
20
20
|
/**
|
|
21
21
|
* Loader $$ids on this segment that the render awaited before first flush
|
|
22
|
-
* (loader(Def, { ssr:
|
|
22
|
+
* (loader(Def, { ssr: "await" })). Dev-diagnostic input only: useLoader uses
|
|
23
23
|
* it to warn when a read still suspends during SSR on a render that awaited
|
|
24
24
|
* flagged loaders (ssr-suspension-warning.ts). Present only where a
|
|
25
25
|
* segment carries flagged loaders (document and shell-capture renders, and
|
|
@@ -221,14 +221,14 @@ export type RouteHelpers<T extends RouteDefinition, TEnv> = {
|
|
|
221
221
|
* return <div>{data.name}</div>;
|
|
222
222
|
* }
|
|
223
223
|
* ```
|
|
224
|
-
* Pass `{ ssr:
|
|
225
|
-
*
|
|
226
|
-
*
|
|
227
|
-
*
|
|
224
|
+
* Pass `{ ssr: "await" }` to await this loader before first flush on
|
|
225
|
+
* DOCUMENT requests (see {@link LoaderOptions}): the opt-in for loaders
|
|
226
|
+
* whose data, handle pushes, or thrown notFound()/redirect() must be in the
|
|
227
|
+
* SSR'd HTML.
|
|
228
228
|
* Per-loader: a streaming sibling in the same segment keeps streaming.
|
|
229
229
|
*
|
|
230
230
|
* ```typescript
|
|
231
|
-
* loader(ProductLoader, { ssr:
|
|
231
|
+
* loader(ProductLoader, { ssr: "await" }, () => [cache()]),
|
|
232
232
|
* loader(RecommendationsLoader), // still streams behind loading()
|
|
233
233
|
* ```
|
|
234
234
|
*
|
|
@@ -44,7 +44,7 @@ export type LoaderErrorCallback = (error: unknown, context: {
|
|
|
44
44
|
* This has a simplified signature for internal use - the caller (typically
|
|
45
45
|
* wrapLoaderPromise in router.ts) is responsible for bridging to the full
|
|
46
46
|
* OnErrorCallback with complete request context (request, url, env, etc.).
|
|
47
|
-
* @param useDefaultErrorBoundary - An `ssr:
|
|
47
|
+
* @param useDefaultErrorBoundary - An `ssr: "await"` loader on a document or
|
|
48
48
|
* capture render: an error with no declared boundary gets
|
|
49
49
|
* `DefaultErrorFallback` (it would otherwise reject the tree), and every
|
|
50
50
|
* error answers 500.
|
|
@@ -112,6 +112,7 @@ import type { CacheScope } from "../cache/cache-scope.js";
|
|
|
112
112
|
import type { EntryData, InterceptSelectorContext, MetricsStore } from "../server/context.js";
|
|
113
113
|
import type { HandlerContext, ResolvedSegment } from "../types.js";
|
|
114
114
|
import type { RouteMatchResult } from "./pattern-matching.js";
|
|
115
|
+
import type { PrevPage } from "./navigation-snapshot.js";
|
|
115
116
|
import type { InterceptResult } from "./router-context.js";
|
|
116
117
|
import type { ResolutionPassInput } from "./segment-resolution/resolution-pass.js";
|
|
117
118
|
import type { ActionContext } from "./types.js";
|
|
@@ -130,7 +131,10 @@ export interface MatchContext<TEnv = any> {
|
|
|
130
131
|
heldBoundary?: string;
|
|
131
132
|
prevUrl: URL;
|
|
132
133
|
prevParams: Record<string, string>;
|
|
134
|
+
/** The match of the page left: the intercept's URL while one is open. */
|
|
133
135
|
prevMatch: RouteMatchResult | null;
|
|
136
|
+
/** The page an open intercept's slot was rendered for. */
|
|
137
|
+
interceptPrev: PrevPage;
|
|
134
138
|
matched: RouteMatchResult;
|
|
135
139
|
manifestEntry: EntryData;
|
|
136
140
|
entries: EntryData[];
|
|
@@ -169,6 +173,14 @@ export interface MatchContext<TEnv = any> {
|
|
|
169
173
|
export declare function rendersLive(ctx: Pick<MatchContext, "isAction" | "stale">): boolean;
|
|
170
174
|
/** This match as the input of a revalidating resolution pass (resolution-pass.ts). */
|
|
171
175
|
export declare function resolutionPassInput<TEnv>(ctx: MatchContext<TEnv>): ResolutionPassInput<TEnv>;
|
|
176
|
+
/**
|
|
177
|
+
* This match as the input of the pass that resolves its intercept's slot: its
|
|
178
|
+
* held segments compare with the intercept's own URL (`interceptPrev`), not
|
|
179
|
+
* with the source page under it. From /item/2 over /list/1, a link to /item/1
|
|
180
|
+
* compared with the source's params would read as param-equal and keep item
|
|
181
|
+
* 2's slot.
|
|
182
|
+
*/
|
|
183
|
+
export declare function interceptPassInput<TEnv>(ctx: MatchContext<TEnv>): ResolutionPassInput<TEnv>;
|
|
172
184
|
/**
|
|
173
185
|
* Mutable state that flows through the pipeline
|
|
174
186
|
*/
|
|
@@ -1,10 +1,27 @@
|
|
|
1
1
|
import type { RouteMatchResult } from "./pattern-matching.js";
|
|
2
|
+
/** A page held segments were rendered for: what their revalidation compares with. */
|
|
3
|
+
export interface PrevPage {
|
|
4
|
+
url: URL;
|
|
5
|
+
params: Record<string, string>;
|
|
6
|
+
}
|
|
2
7
|
export interface NavigationSnapshot {
|
|
8
|
+
/**
|
|
9
|
+
* `prevUrl` and `prevParams`: the page the held page segments were rendered
|
|
10
|
+
* for. That is the page left, or the source page while an intercept is open
|
|
11
|
+
* (`hasInterceptSource`).
|
|
12
|
+
*/
|
|
3
13
|
prevUrl: URL;
|
|
4
14
|
/** The visitor's URL of the page left, when `prevUrl` is its rewrite target. */
|
|
5
15
|
prevVisitorUrl: URL | null;
|
|
6
16
|
prevParams: Record<string, string>;
|
|
17
|
+
/** The match of the page left: the intercept's URL while one is open. */
|
|
7
18
|
prevMatch: RouteMatchResult | null;
|
|
19
|
+
/**
|
|
20
|
+
* The page an open intercept's slot was rendered for: the intercept's own
|
|
21
|
+
* URL (match-context.ts interceptPassInput). Equals `prevUrl`/`prevParams`
|
|
22
|
+
* when the request names no intercept source.
|
|
23
|
+
*/
|
|
24
|
+
interceptPrev: PrevPage;
|
|
8
25
|
interceptContextUrl: URL;
|
|
9
26
|
interceptContextMatch: RouteMatchResult | null;
|
|
10
27
|
clientSegmentIds: string[];
|
|
@@ -56,14 +56,14 @@ import { type RequestContext } from "../../server/request-context.js";
|
|
|
56
56
|
export declare function bindsLoaderCache(entries: readonly EntryData[]): boolean;
|
|
57
57
|
/**
|
|
58
58
|
* The lane of each loader the matched chain `entries` registers: "live" (no
|
|
59
|
-
* `ssr:
|
|
59
|
+
* `ssr: "await"`) or "bake". A loader registered on both is "live". A PPR
|
|
60
60
|
* capture credits a push to the first registered loader around it when that
|
|
61
61
|
* one is live (shell-capture.ts deriveShellCaptureContext).
|
|
62
62
|
*/
|
|
63
63
|
export declare function routeLoaderLanes(entries: readonly EntryData[]): ReadonlyMap<string, "live" | "bake">;
|
|
64
64
|
/**
|
|
65
65
|
* This request serves `loaderEntry` from a pin (servedPins), so its body does
|
|
66
|
-
* not decide the value: resolveLoaderData serves a pin to an `ssr:
|
|
66
|
+
* not decide the value: resolveLoaderData serves a pin to an `ssr: "await"`
|
|
67
67
|
* registration only. A prefetch does not defer such a loader
|
|
68
68
|
* (prefetch-deferral.ts defersLoader): nothing would run, and the pin is the
|
|
69
69
|
* value the document shows.
|
|
@@ -77,14 +77,14 @@ export declare function servesLoaderPin(loaderEntry: LoaderEntry, reqCtx?: Reque
|
|
|
77
77
|
* only and the store asks while loader bodies run.
|
|
78
78
|
*
|
|
79
79
|
* Each side applies its own lane to the pin. The value is per registration
|
|
80
|
-
* (resolveLoaderData: an `ssr:
|
|
81
|
-
* pushes are per loader: one the route also registers without `ssr:
|
|
80
|
+
* (resolveLoaderData: an `ssr: "await"` registration is served its pin). The
|
|
81
|
+
* pushes are per loader: one the route also registers without `ssr: "await"`
|
|
82
82
|
* is a hole whatever its other registration's pin says, because the capture
|
|
83
83
|
* credited its pushes to the live registration's run (routeLoaderLanes).
|
|
84
84
|
*
|
|
85
85
|
* A dependency the route does not register has no pin of its own, and the
|
|
86
86
|
* record does not name the loader that ran it at capture: its copies stand
|
|
87
|
-
* only while every `ssr:
|
|
87
|
+
* only while every `ssr: "await"` loader is pinned (exact when the pins are
|
|
88
88
|
* all there or all gone).
|
|
89
89
|
*/
|
|
90
90
|
export declare function loaderPins(entries: readonly EntryData[], reqCtx: RequestContext<any> | undefined): OwnedPushDelivery;
|
|
@@ -108,7 +108,7 @@ export declare function loaderPins(entries: readonly EntryData[], reqCtx: Reques
|
|
|
108
108
|
* never run under a shell capture), so the lane is decided here, per LOADER,
|
|
109
109
|
* never by the entry's loading():
|
|
110
110
|
*
|
|
111
|
-
* - BAKE lane: `loader(Def, { ssr:
|
|
111
|
+
* - BAKE lane: `loader(Def, { ssr: "await" })` (LoaderEntry `bake`: the
|
|
112
112
|
* caller passes a `bakeSegmentKey` for it on document and navigation
|
|
113
113
|
* evaluations alike; a capture, a document evaluation, also has
|
|
114
114
|
* awaitBeforeFlush). The loader EXECUTES at capture (the
|
|
@@ -130,7 +130,7 @@ export declare function loaderPins(entries: readonly EntryData[], reqCtx: Reques
|
|
|
130
130
|
* (loader-mask.ts) and postpones at the reader's boundary — loading() or an
|
|
131
131
|
* inline Suspense — then streams fresh per request. A masked read with NO
|
|
132
132
|
* boundary above it root-postpones and the <body> sanity gate refuses the
|
|
133
|
-
* shell (eternal-MISS warning). A route whose loaders are ALL `ssr:
|
|
133
|
+
* shell (eternal-MISS warning). A route whose loaders are ALL `ssr: "await"`
|
|
134
134
|
* needs no loading(): nothing masks.
|
|
135
135
|
*/
|
|
136
136
|
export declare function resolveLoaderData<TEnv>(loaderEntry: LoaderEntry, ctx: HandlerContext<any, TEnv>, pathname: string, bakeSegmentKey?: string | null): Promise<any>;
|
|
@@ -35,7 +35,7 @@ export interface SegmentResolutionDeps<TEnv = any> {
|
|
|
35
35
|
env?: TEnv;
|
|
36
36
|
isPartial?: boolean;
|
|
37
37
|
},
|
|
38
|
-
/** An `ssr:
|
|
38
|
+
/** An `ssr: "await"` loader on a document or capture render. */
|
|
39
39
|
useDefaultErrorBoundary?: boolean) => Promise<LoaderDataResult<T>>;
|
|
40
40
|
trackHandler: <T>(promise: Promise<T>, errorContext?: {
|
|
41
41
|
segmentId?: string;
|
|
@@ -148,12 +148,12 @@ export declare const SHELL_CAPTURE_TASK_HARD_CAP_MS = 25000;
|
|
|
148
148
|
* (ShellCaptureDebugEvent.refusal, `caches.refusal` on a `router.prerender()`
|
|
149
149
|
* result): `identity` (a request-scoped read: cookies(), headers(), the
|
|
150
150
|
* theme, a `{ cache: false }` variable), `dynamic` (`ctx.dynamic()`),
|
|
151
|
-
* `loader` (a `{ ssr:
|
|
151
|
+
* `loader` (a `{ ssr: "await" }` loader rejected, settled with
|
|
152
152
|
* redirect()/notFound(), or a promise it pushed rejected),
|
|
153
153
|
* `no-record` (no doc record: the route's cache() refused the write, or the
|
|
154
154
|
* handler output failed), `handles` (a pushed
|
|
155
155
|
* handle value did not finish encoding), `size` (over the store's value
|
|
156
|
-
* limit, or `ssr:
|
|
156
|
+
* limit, or `ssr: "await"` loader pins over `ppr.maxSnapshotBytes`: a
|
|
157
157
|
* navigation-only entry was stored in place of the document shell),
|
|
158
158
|
* `record-expired` (the route cache() record
|
|
159
159
|
* the capture wrote ran out first), `invalidated` (a tag of the shell was
|
|
@@ -119,7 +119,7 @@ export type LoaderEntry = {
|
|
|
119
119
|
cache?: EntryCacheConfig;
|
|
120
120
|
/**
|
|
121
121
|
* Document renders await this loader before segment resolution returns
|
|
122
|
-
* (loader(Def, { ssr:
|
|
122
|
+
* (loader(Def, { ssr: "await" })), so its data, handle pushes, and
|
|
123
123
|
* thrown notFound()/redirect() deterministically precede first flush.
|
|
124
124
|
* Resolved at DSL-evaluation time from ctx.isSSR — entries are cached
|
|
125
125
|
* per-isSSR (router/manifest.ts cache key), so the flag is already
|
|
@@ -129,7 +129,7 @@ export type LoaderEntry = {
|
|
|
129
129
|
*/
|
|
130
130
|
awaitBeforeFlush?: true;
|
|
131
131
|
/**
|
|
132
|
-
* loader(Def, { ssr:
|
|
132
|
+
* loader(Def, { ssr: "await" }) on every DSL evaluation, document and
|
|
133
133
|
* navigation: the loader's PPR bake lane (loader-cache.ts
|
|
134
134
|
* resolveLoaderData). The bake/seed key rides on it, so a client
|
|
135
135
|
* navigation's shell replay pins exactly the loaders a document HIT pins,
|
|
@@ -491,7 +491,7 @@ export type { HelperContext };
|
|
|
491
491
|
* parent pointer, handler) stays shared, which is correct and cheap.
|
|
492
492
|
*/
|
|
493
493
|
export declare function getIsolatedLazyParent(captured: EntryData | null | undefined): EntryData | null;
|
|
494
|
-
/** loader(Def, { ssr:
|
|
494
|
+
/** loader(Def, { ssr: "await" }): a document awaits it before the first flush. */
|
|
495
495
|
export declare function documentModeLoader(entry: LoaderEntry): LoaderEntry;
|
|
496
496
|
/** loading(fallback, { ssr: false }): a document renders no fallback. */
|
|
497
497
|
export declare function applyDocumentModeLoading(entry: EntryPropRender): void;
|
|
@@ -710,7 +710,7 @@ export interface RequestContext<TEnv = DefaultEnv, TParams = Record<string, stri
|
|
|
710
710
|
_handlerLoaderDeps?: Set<string>;
|
|
711
711
|
/**
|
|
712
712
|
* @internal Loader IDs ($$id) whose entries carry `awaitBeforeFlush`
|
|
713
|
-
* (loader(Def, { ssr:
|
|
713
|
+
* (loader(Def, { ssr: "await" })): segment resolution awaits these
|
|
714
714
|
* before returning, so the render barrier cannot resolve until they settle.
|
|
715
715
|
* rendered() checks this set to fail fast — a flagged loader awaiting the
|
|
716
716
|
* barrier is a guaranteed cycle, not a race. Registered by resolveOwnerLoaders
|
|
@@ -171,7 +171,7 @@ export interface SSRDependencies<TEnv = unknown> {
|
|
|
171
171
|
*
|
|
172
172
|
* When UNSET, createSSRHandler and createShellCaptureHandler auto-raise to
|
|
173
173
|
* Number.MAX_SAFE_INTEGER for document renders and shell captures whose
|
|
174
|
-
* matched chain has a `loader(Def, { ssr:
|
|
174
|
+
* matched chain has a `loader(Def, { ssr: "await" })` entry (payload segments
|
|
175
175
|
* carry `awaitBeforeFlush`): the loader was awaited before first flush
|
|
176
176
|
* precisely so its content ships in-place, and React 19.2's Fizz would
|
|
177
177
|
* otherwise move any completed boundary over ~500 bytes to an end-of-stream
|
|
@@ -30,7 +30,7 @@ export interface RscPayload {
|
|
|
30
30
|
* Deserialize the Flight stream branch into the payload SsrRoot renders,
|
|
31
31
|
* fragment expansion included. Factored out of SsrRoot so createSSRHandler and
|
|
32
32
|
* createShellCaptureHandler can create the promise BEFORE fizz starts and read
|
|
33
|
-
* metadata that must influence the fizz call itself (the ssr:
|
|
33
|
+
* metadata that must influence the fizz call itself (the ssr: "await"
|
|
34
34
|
* progressiveChunkSize auto-raise) — awaiting it there is latency-neutral
|
|
35
35
|
* because fizz cannot emit even <html> until this same promise settles.
|
|
36
36
|
*/
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Dev-only diagnostic for the { ssr:
|
|
2
|
+
* Dev-only diagnostic for the { ssr: "await" } SSR-completeness opt-in.
|
|
3
3
|
*
|
|
4
4
|
* A document render that awaits flagged loaders before first flush is usually
|
|
5
5
|
* expected to produce an SSR-complete boundary — but the await is scoped per
|
|
@@ -63,7 +63,7 @@ export type LoaderContext<TParams = Record<string, string | undefined>, TEnv = D
|
|
|
63
63
|
* later ones stream to the client and apply post-hydration (document lane)
|
|
64
64
|
* or progressively (navigation/action lanes). To guarantee a loader's
|
|
65
65
|
* handles are in the SSR'd document, register it as
|
|
66
|
-
* `loader(Def, { ssr:
|
|
66
|
+
* `loader(Def, { ssr: "await" })` so the document render awaits it
|
|
67
67
|
* (see {@link LoaderOptions}).
|
|
68
68
|
*
|
|
69
69
|
* @example
|
|
@@ -150,29 +150,29 @@ export type LoaderFn<T, TParams = Record<string, string | undefined>, TEnv = Def
|
|
|
150
150
|
/**
|
|
151
151
|
* SSR delivery for a DSL-registered loader: `loader(Def, { ssr })`.
|
|
152
152
|
*
|
|
153
|
-
* Default (omitted / `
|
|
154
|
-
* its `ctx.use(Handle)` pushes, and any `notFound()`/`redirect()` it
|
|
155
|
-
* may land AFTER the document Response is constructed, so none of
|
|
156
|
-
* guaranteed to be in the SSR'd HTML.
|
|
153
|
+
* Default (omitted / `"stream"`): the loader streams on every render. Its
|
|
154
|
+
* data, its `ctx.use(Handle)` pushes, and any `notFound()`/`redirect()` it
|
|
155
|
+
* throws may land AFTER the document Response is constructed, so none of
|
|
156
|
+
* them are guaranteed to be in the SSR'd HTML.
|
|
157
157
|
*
|
|
158
|
-
* `ssr:
|
|
159
|
-
*
|
|
160
|
-
*
|
|
161
|
-
*
|
|
162
|
-
*
|
|
163
|
-
* it
|
|
164
|
-
*
|
|
165
|
-
*
|
|
166
|
-
*
|
|
167
|
-
* BAKE lane: the loader executes at shell capture and its settled return is
|
|
158
|
+
* `ssr: "await"` makes the server renders that produce HTML await this
|
|
159
|
+
* loader: on a DOCUMENT request the loader is awaited before first flush, so
|
|
160
|
+
* no fallback paints for it (`useLoader` still suspends, but on an
|
|
161
|
+
* already-settled promise); a ppr shell capture, at runtime or at build time
|
|
162
|
+
* for a Prerender + ppr route, awaits it too. Client navigations keep
|
|
163
|
+
* streaming it. This is the SSR-completeness opt-in. Choose it when the
|
|
164
|
+
* loader feeds something that must exist in the document: `<head>` meta via
|
|
165
|
+
* a handle, or a real 404 status (an awaited `notFound()` deterministically
|
|
166
|
+
* precedes Response construction, where the streamed default only wins
|
|
167
|
+
* that race opportunistically). Under ppr it is also the BAKE lane: the loader executes at shell capture and its settled return is
|
|
168
168
|
* shell material (nested promises stay live holes), and so are its handle
|
|
169
169
|
* pushes, a pushed promise or `.defer()` included: the capture awaits it and
|
|
170
170
|
* every HIT serves the value it settled to (#1182). A pushed promise that
|
|
171
171
|
* rejects, or misses `ppr.captureTimeout`, keeps the route on MISS. A value
|
|
172
|
-
* that must stay per request belongs to a loader without `ssr:
|
|
172
|
+
* that must stay per request belongs to a loader without `ssr: "await"` — see
|
|
173
173
|
* the ppr docs.
|
|
174
174
|
*
|
|
175
|
-
* Scoped per LOADER, not per segment: an `ssr:
|
|
175
|
+
* Scoped per LOADER, not per segment: an `ssr: "await"` loader alongside a
|
|
176
176
|
* deliberately streaming sibling awaits only itself, and the sibling keeps
|
|
177
177
|
* streaming behind its `loading()`/Suspense boundary. Watch the scoping when
|
|
178
178
|
* the boundary must be SSR-complete: ONE unflagged read under it still
|
|
@@ -181,7 +181,7 @@ export type LoaderFn<T, TParams = Record<string, string | undefined>, TEnv = Def
|
|
|
181
181
|
* site naming the unflagged loader (ssr-suspension-warning.ts).
|
|
182
182
|
*/
|
|
183
183
|
export type LoaderOptions = {
|
|
184
|
-
ssr?:
|
|
184
|
+
ssr?: "stream" | "await";
|
|
185
185
|
/**
|
|
186
186
|
* `prefetch: false` keeps this loader out of every `<Link>` prefetch: a
|
|
187
187
|
* prefetch (a partial request with `X-Rango-Prefetch`) does not execute
|
|
@@ -211,7 +211,7 @@ export type LoaderOptions = {
|
|
|
211
211
|
* Limits: a handler that awaits the loader with `ctx.use()` makes it run in
|
|
212
212
|
* the prefetch anyway; the loader cannot call `ctx.rendered()` (it throws
|
|
213
213
|
* on every request); on a `ppr` route the flag is ignored for an
|
|
214
|
-
* `ssr:
|
|
214
|
+
* `ssr: "await"` loader (the bake lane), with a dev warning. In the fill
|
|
215
215
|
* request only deferred work and middleware run, so values a held handler
|
|
216
216
|
* would have set with `ctx.set()` are not visible.
|
|
217
217
|
*/
|
|
@@ -150,7 +150,7 @@ export interface ResolvedSegment {
|
|
|
150
150
|
loaderData?: any;
|
|
151
151
|
/**
|
|
152
152
|
* True when this loader was awaited before first flush
|
|
153
|
-
* (loader(Def, { ssr:
|
|
153
|
+
* (loader(Def, { ssr: "await" })). Stamped by resolveOwnerLoaders on
|
|
154
154
|
* document AND shell-capture renders — capture bakes flagged loaders and
|
|
155
155
|
* awaits the same lane. Feeds segment-system's settled-value delivery and
|
|
156
156
|
* the dev SSR suspension warning (ssr-suspension-warning.ts).
|
|
@@ -170,7 +170,7 @@ export interface ResolvedSegment {
|
|
|
170
170
|
loaderIds?: string[];
|
|
171
171
|
/**
|
|
172
172
|
* Per-loader UNDECODED results for a layout/route stream map.
|
|
173
|
-
* Flagged (ssr:
|
|
173
|
+
* Flagged (ssr: "await") entries are settled values; unflagged siblings
|
|
174
174
|
* stay promises. Parallel slots do not use this channel — they pin
|
|
175
175
|
* loading() / live-lane holes via use(loaderDataPromise).
|
|
176
176
|
*/
|