@rangojs/router 0.20.0 → 0.22.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/dist/bin/rango.js +39 -15
- package/dist/types/browser/event-controller.d.ts +49 -0
- package/dist/types/browser/history-state.d.ts +16 -4
- package/dist/types/browser/navigation-store.d.ts +9 -0
- package/dist/types/browser/navigation-transaction.d.ts +7 -0
- package/dist/types/browser/partial-update.d.ts +2 -1
- package/dist/types/browser/prefetch/default-strategy.d.ts +16 -20
- package/dist/types/browser/rango-state.d.ts +3 -1
- package/dist/types/browser/react/NavigationProvider.d.ts +14 -1
- package/dist/types/browser/react/context.d.ts +25 -0
- package/dist/types/browser/react/location-state-shared.d.ts +84 -10
- package/dist/types/browser/react/location-state.d.ts +7 -2
- package/dist/types/browser/rsc-router.d.ts +13 -2
- package/dist/types/browser/types.d.ts +10 -0
- package/dist/types/build/generate-manifest.d.ts +2 -0
- package/dist/types/cache/background-task.d.ts +22 -0
- package/dist/types/cache/cache-key-utils.d.ts +50 -5
- package/dist/types/cache/cache-policy.d.ts +17 -0
- package/dist/types/cache/cache-scope.d.ts +5 -6
- package/dist/types/cache/cf/cf-cache-store.d.ts +34 -7
- package/dist/types/cache/cf/cf-cache-types.d.ts +12 -4
- package/dist/types/cache/document-cache.d.ts +8 -5
- package/dist/types/cache/handle-snapshot.d.ts +59 -50
- package/dist/types/cache/index.d.ts +3 -1
- package/dist/types/cache/invalidation-order.d.ts +14 -0
- package/dist/types/cache/memory-segment-store.d.ts +33 -1
- package/dist/types/cache/shell-snapshot.d.ts +29 -4
- package/dist/types/cache/store-scope.d.ts +22 -0
- package/dist/types/cache/tag-invalidation.d.ts +7 -6
- package/dist/types/cache/types.d.ts +84 -24
- package/dist/types/cache/vercel/vercel-cache-store.d.ts +35 -17
- package/dist/types/client-urls/navigation.d.ts +7 -1
- package/dist/types/client-urls/optimistic-location.d.ts +10 -4
- package/dist/types/errors.d.ts +6 -0
- package/dist/types/handles/deferred-resolution.d.ts +18 -1
- package/dist/types/internal-suspense-audit.d.ts +1 -0
- package/dist/types/loader-store.d.ts +4 -8
- package/dist/types/outlet-provider.d.ts +2 -1
- package/dist/types/prerender/build-shell-capture.d.ts +8 -6
- package/dist/types/prerender/cloudflare.d.ts +49 -0
- package/dist/types/prerender/create-prerender-trigger.d.ts +121 -0
- package/dist/types/prerender/index.d.ts +12 -0
- package/dist/types/prerender/memory-prerender-store.d.ts +29 -0
- package/dist/types/prerender/on-demand.d.ts +272 -0
- package/dist/types/prerender/producer-guard.d.ts +33 -0
- package/dist/types/prerender/shell-manifest-key.d.ts +1 -18
- package/dist/types/prerender/warm-request.d.ts +65 -0
- package/dist/types/prerender/warm.d.ts +65 -0
- package/dist/types/prerender/writable-store.d.ts +170 -0
- package/dist/types/prerender.d.ts +27 -0
- package/dist/types/reverse.d.ts +1 -1
- package/dist/types/route-content-wrapper.d.ts +3 -1
- package/dist/types/router/error-handling.d.ts +2 -0
- package/dist/types/router/handler-context.d.ts +1 -1
- package/dist/types/router/match-middleware/cache-lookup.d.ts +15 -1
- package/dist/types/router/navigation-snapshot.d.ts +8 -1
- package/dist/types/router/pattern-matching.d.ts +2 -0
- package/dist/types/router/prefetch-default.d.ts +4 -4
- package/dist/types/router/prerender-match.d.ts +23 -1
- package/dist/types/router/route-trie-builder.d.ts +8 -1
- package/dist/types/router/router-context.d.ts +1 -0
- package/dist/types/router/router-interfaces.d.ts +32 -1
- package/dist/types/router/router-options.d.ts +39 -5
- package/dist/types/router/segment-resolution/fresh.d.ts +7 -0
- package/dist/types/router/segment-resolution/loader-cache.d.ts +23 -10
- package/dist/types/router/segment-resolution/revalidation.d.ts +5 -1
- package/dist/types/router/segment-resolution/streamed-handler-boundary.d.ts +43 -0
- package/dist/types/router/trie-matching.d.ts +2 -0
- package/dist/types/router-versions.d.ts +39 -0
- package/dist/types/rsc/handler-context.d.ts +5 -0
- package/dist/types/rsc/shell-build-manifest.d.ts +9 -6
- package/dist/types/rsc/shell-capture-constants.d.ts +20 -5
- package/dist/types/rsc/shell-capture.d.ts +14 -1
- package/dist/types/rsc/shell-serve.d.ts +2 -2
- package/dist/types/rsc/ssr-module-loader.d.ts +15 -0
- package/dist/types/rsc/types.d.ts +12 -6
- package/dist/types/segment-boundary-content.d.ts +17 -0
- package/dist/types/segment-loader-promise.d.ts +2 -6
- package/dist/types/server/build-version-table.d.ts +53 -0
- package/dist/types/server/context.d.ts +12 -4
- package/dist/types/server/handle-store.d.ts +89 -46
- package/dist/types/server/request-context.d.ts +84 -9
- package/dist/types/suspense-audit-react.d.ts +26 -0
- package/dist/types/suspense-audit.d.ts +157 -0
- package/dist/types/testing/action-form.d.ts +34 -0
- package/dist/types/testing/build-versions.d.ts +32 -0
- package/dist/types/testing/dom.entry.d.ts +1 -1
- package/dist/types/testing/flight.entry.d.ts +3 -1
- package/dist/types/testing/index.d.ts +6 -0
- package/dist/types/testing/internal/seed-vars.d.ts +7 -2
- package/dist/types/testing/internal/server-modules.d.ts +8 -0
- package/dist/types/testing/location-state-key.d.ts +5 -1
- package/dist/types/testing/render-route.d.ts +77 -6
- package/dist/types/testing/serve-shell-request.d.ts +55 -4
- package/dist/types/testing/shell-status.d.ts +14 -6
- package/dist/types/testing/vitest-stubs/plugin-rsc.d.ts +9 -6
- package/dist/types/testing/vitest-stubs/version.d.ts +1 -0
- package/dist/types/thenable-status.d.ts +6 -0
- package/dist/types/types/handler-context.d.ts +15 -5
- package/dist/types/types/route-entry.d.ts +5 -0
- package/dist/types/urls/path-helper.d.ts +18 -0
- package/dist/types/vite/discovery/build-versions.d.ts +393 -0
- package/dist/types/vite/discovery/installed-packages.d.ts +26 -0
- package/dist/types/vite/discovery/router-versions-phase.d.ts +52 -0
- package/dist/types/vite/discovery/shell-prerender-phase.d.ts +7 -17
- package/dist/types/vite/discovery/state.d.ts +25 -0
- package/dist/types/vite/encryption-key.d.ts +18 -0
- package/dist/types/vite/inject-client-debug.d.ts +6 -25
- package/dist/types/vite/plugin-types.d.ts +27 -0
- package/dist/types/vite/plugins/{version-injector.d.ts → entry-bootstrap-injector.d.ts} +4 -6
- package/dist/types/vite/plugins/expose-ids/export-analysis.d.ts +1 -0
- package/dist/types/vite/plugins/expose-ids/router-transform.d.ts +14 -0
- package/dist/types/vite/plugins/stable-rsc-output.d.ts +51 -0
- package/dist/types/vite/plugins/version-plugin.d.ts +9 -11
- package/dist/types/vite/plugins/virtual-entries.d.ts +18 -1
- package/dist/types/vite/router-discovery.d.ts +6 -0
- package/dist/types/vite/utils/bundle-analysis.d.ts +6 -2
- package/dist/types/vite/utils/client-chunks.d.ts +2 -0
- package/dist/types/vite/utils/compare-strings.d.ts +7 -0
- package/dist/types/vite/utils/package-resolution.d.ts +8 -0
- package/dist/types/vite/utils/prerender-utils.d.ts +2 -0
- package/dist/vite/index.js +1707 -931
- package/package.json +12 -3
- package/skills/cache-guide/SKILL.md +102 -37
- package/skills/caching/SKILL.md +56 -9
- package/skills/catalog.json +1 -1
- package/skills/client-urls/SKILL.md +16 -0
- package/skills/cloudflare/SKILL.md +133 -1
- package/skills/comparison/references/framework-comparison.md +17 -13
- package/skills/deployment-caching/SKILL.md +33 -12
- package/skills/document-cache/SKILL.md +16 -14
- package/skills/hooks/SKILL.md +25 -0
- package/skills/hooks/handle-and-actions.md +5 -0
- package/skills/hooks/navigation.md +38 -0
- package/skills/hooks/state.md +213 -11
- package/skills/hooks/urls.md +40 -1
- package/skills/host-router/SKILL.md +31 -0
- package/skills/intercept/SKILL.md +6 -0
- package/skills/loader/SKILL.md +25 -5
- package/skills/middleware/SKILL.md +2 -0
- package/skills/migrate-nextjs/SKILL.md +82 -9
- package/skills/ppr/SKILL.md +150 -48
- package/skills/prerender/SKILL.md +651 -10
- package/skills/rango/SKILL.md +9 -7
- package/skills/response-routes/SKILL.md +5 -5
- package/skills/route/SKILL.md +29 -0
- package/skills/router-setup/SKILL.md +15 -1
- package/skills/testing/SKILL.md +32 -27
- package/skills/testing/cache-prerender.md +18 -17
- package/skills/testing/client-components.md +193 -8
- package/skills/testing/handles.md +2 -0
- package/skills/testing/loader.md +1 -1
- package/skills/testing/middleware.md +1 -1
- package/skills/testing/render-handler.md +18 -18
- package/skills/testing/serve-shell-request.md +167 -22
- package/skills/testing/server-actions.md +17 -17
- package/skills/testing/server-tree.md +1 -1
- package/skills/typesafety/generated-files-and-cli.md +1 -1
- package/skills/use-cache/SKILL.md +25 -10
- package/skills/vercel/SKILL.md +5 -3
- package/skills/view-transitions/SKILL.md +9 -4
- package/src/bin/rango.ts +1 -1
- package/src/browser/event-controller.ts +119 -2
- package/src/browser/history-state.ts +39 -17
- package/src/browser/link-interceptor.ts +2 -2
- package/src/browser/navigation-bridge.ts +104 -41
- package/src/browser/navigation-store.ts +26 -0
- package/src/browser/navigation-transaction.ts +24 -12
- package/src/browser/network-error-handler.ts +2 -0
- package/src/browser/partial-update.ts +58 -14
- package/src/browser/prefetch/default-strategy.ts +22 -42
- package/src/browser/rango-state.ts +3 -1
- package/src/browser/react/Link.tsx +37 -43
- package/src/browser/react/NavigationProvider.tsx +85 -1
- package/src/browser/react/context.ts +30 -0
- package/src/browser/react/location-state-shared.ts +200 -34
- package/src/browser/react/location-state.ts +28 -77
- package/src/browser/react/use-action.ts +4 -1
- package/src/browser/react/use-handle.ts +3 -0
- package/src/browser/react/use-link-status.ts +4 -3
- package/src/browser/react/use-navigation.ts +4 -1
- package/src/browser/react/use-params.ts +4 -1
- package/src/browser/react/use-pathname.ts +4 -1
- package/src/browser/react/use-search-params.ts +5 -3
- package/src/browser/react/use-segments.ts +36 -54
- package/src/browser/rsc-router.tsx +93 -31
- package/src/browser/segment-reconciler.ts +3 -3
- package/src/browser/server-action-bridge.ts +43 -7
- package/src/browser/types.ts +11 -0
- package/src/build/generate-manifest.ts +17 -0
- package/src/build/merge-full-manifests.ts +5 -0
- package/src/build/route-trie.ts +1 -0
- package/src/cache/background-task.ts +61 -0
- package/src/cache/cache-key-utils.ts +91 -12
- package/src/cache/cache-policy.ts +11 -2
- package/src/cache/cache-runtime.ts +23 -23
- package/src/cache/cache-scope.ts +48 -36
- package/src/cache/cf/cf-cache-store.ts +91 -66
- package/src/cache/cf/cf-cache-types.ts +12 -4
- package/src/cache/document-cache.ts +35 -14
- package/src/cache/handle-snapshot.ts +118 -86
- package/src/cache/index.ts +5 -0
- package/src/cache/invalidation-order.ts +53 -0
- package/src/cache/memory-segment-store.ts +52 -1
- package/src/cache/shell-snapshot.ts +52 -5
- package/src/cache/store-scope.ts +36 -0
- package/src/cache/tag-invalidation.ts +7 -5
- package/src/cache/types.ts +90 -24
- package/src/cache/vercel/vercel-cache-store.ts +68 -26
- package/src/client-urls/client-root.tsx +1 -0
- package/src/client-urls/navigation.ts +10 -0
- package/src/client-urls/optimistic-location.ts +10 -4
- package/src/client.tsx +40 -3
- package/src/errors.ts +13 -6
- package/src/handles/deferred-resolution.ts +36 -0
- package/src/internal-suspense-audit.ts +12 -0
- package/src/loader-store.ts +4 -9
- package/src/outlet-provider.tsx +25 -1
- package/src/prerender/build-shell-capture.ts +11 -9
- package/src/prerender/cloudflare.ts +130 -0
- package/src/prerender/create-prerender-trigger.ts +780 -0
- package/src/prerender/index.ts +39 -0
- package/src/prerender/memory-prerender-store.ts +115 -0
- package/src/prerender/on-demand.ts +339 -0
- package/src/prerender/producer-guard.ts +66 -0
- package/src/prerender/shell-manifest-key.ts +12 -17
- package/src/prerender/warm-request.ts +154 -0
- package/src/prerender/warm.ts +193 -0
- package/src/prerender/writable-store.ts +278 -0
- package/src/prerender.ts +29 -0
- package/src/reverse.ts +1 -1
- package/src/route-content-wrapper.tsx +107 -13
- package/src/router/error-handling.ts +12 -12
- package/src/router/find-match.ts +1 -0
- package/src/router/handler-context.ts +2 -0
- package/src/router/intercept-resolution.ts +15 -8
- package/src/router/loader-resolution.ts +2 -10
- package/src/router/manifest.ts +2 -0
- package/src/router/match-middleware/background-revalidation.ts +2 -0
- package/src/router/match-middleware/cache-lookup.ts +239 -54
- package/src/router/navigation-snapshot.ts +25 -6
- package/src/router/pattern-matching.ts +14 -0
- package/src/router/prefetch-default.ts +4 -4
- package/src/router/prerender-match.ts +460 -352
- package/src/router/request-classification.ts +15 -12
- package/src/router/route-trie-builder.ts +9 -0
- package/src/router/router-context.ts +1 -0
- package/src/router/router-interfaces.ts +35 -1
- package/src/router/router-options.ts +45 -5
- package/src/router/segment-resolution/fresh.ts +20 -19
- package/src/router/segment-resolution/loader-cache.ts +110 -77
- package/src/router/segment-resolution/revalidation.ts +34 -24
- package/src/router/segment-resolution/streamed-handler-boundary.ts +133 -0
- package/src/router/trie-matching.ts +3 -0
- package/src/router-versions.ts +60 -0
- package/src/router.ts +107 -1
- package/src/rsc/full-payload.ts +6 -2
- package/src/rsc/handler-context.ts +5 -0
- package/src/rsc/handler.ts +64 -7
- package/src/rsc/progressive-enhancement.ts +5 -1
- package/src/rsc/response-cache-serve.ts +10 -4
- package/src/rsc/rsc-rendering.ts +65 -12
- package/src/rsc/shell-build-manifest.ts +17 -12
- package/src/rsc/shell-capture-constants.ts +39 -7
- package/src/rsc/shell-capture.ts +144 -45
- package/src/rsc/shell-serve.ts +12 -6
- package/src/rsc/ssr-module-loader.ts +26 -0
- package/src/rsc/types.ts +12 -6
- package/src/segment-boundary-content.ts +25 -0
- package/src/segment-loader-promise.ts +28 -38
- package/src/segment-system.tsx +117 -57
- package/src/server/build-version-table.ts +130 -0
- package/src/server/context.ts +40 -17
- package/src/server/cookie-store.ts +5 -0
- package/src/server/handle-store.ts +357 -127
- package/src/server/request-context.ts +149 -12
- package/src/ssr/ssr-root.tsx +32 -13
- package/src/suspense-audit-react.tsx +98 -0
- package/src/suspense-audit.ts +1030 -0
- package/src/testing/action-form.ts +66 -0
- package/src/testing/build-versions.ts +64 -0
- package/src/testing/dispatch.ts +6 -0
- package/src/testing/dom.entry.ts +1 -0
- package/src/testing/flight-runtime.d.ts +27 -0
- package/src/testing/flight.entry.ts +4 -0
- package/src/testing/index.ts +22 -0
- package/src/testing/internal/context.ts +2 -1
- package/src/testing/internal/seed-vars.ts +14 -2
- package/src/testing/internal/server-modules.ts +32 -0
- package/src/testing/location-state-key.ts +18 -8
- package/src/testing/render-handler.ts +2 -1
- package/src/testing/render-route.tsx +293 -46
- package/src/testing/serve-shell-request.ts +262 -37
- package/src/testing/shell-status.ts +17 -6
- package/src/testing/vitest-stubs/plugin-rsc.ts +37 -11
- package/src/testing/vitest-stubs/version.ts +4 -1
- package/src/thenable-status.ts +10 -0
- package/src/types/handler-context.ts +15 -5
- package/src/types/route-entry.ts +6 -0
- package/src/urls/path-helper.ts +69 -9
- package/src/use-loader.tsx +57 -30
- package/src/vite/discovery/build-versions.ts +1281 -0
- package/src/vite/discovery/bundle-postprocess.ts +4 -0
- package/src/vite/discovery/discover-routers.ts +15 -0
- package/src/vite/discovery/installed-packages.ts +159 -0
- package/src/vite/discovery/prerender-collection.ts +38 -1
- package/src/vite/discovery/router-versions-phase.ts +336 -0
- package/src/vite/discovery/shell-prerender-phase.ts +33 -43
- package/src/vite/discovery/state.ts +36 -1
- package/src/vite/discovery/virtual-module-codegen.ts +7 -2
- package/src/vite/encryption-key.ts +101 -9
- package/src/vite/inject-client-debug.ts +42 -20
- package/src/vite/plugin-types.ts +28 -0
- package/src/vite/plugins/{version-injector.ts → entry-bootstrap-injector.ts} +7 -22
- package/src/vite/plugins/expose-ids/export-analysis.ts +1 -1
- package/src/vite/plugins/expose-ids/router-transform.ts +36 -15
- package/src/vite/plugins/expose-internal-ids.ts +12 -3
- package/src/vite/plugins/stable-rsc-output.ts +147 -0
- package/src/vite/plugins/version-plugin.ts +19 -24
- package/src/vite/plugins/version.d.ts +17 -2
- package/src/vite/plugins/virtual-entries.ts +39 -6
- package/src/vite/rango.ts +28 -3
- package/src/vite/router-discovery.ts +96 -13
- package/src/vite/utils/bundle-analysis.ts +39 -7
- package/src/vite/utils/client-chunks.ts +5 -1
- package/src/vite/utils/compare-strings.ts +9 -0
- package/src/vite/utils/package-resolution.ts +9 -0
- package/src/vite/utils/prerender-utils.ts +4 -1
- package/src/vite/utils/shared-utils.ts +1 -1
- package/dist/types/segment-content-promise.d.ts +0 -13
- package/src/segment-content-promise.ts +0 -67
|
@@ -47,7 +47,7 @@ import { applyViewTransitionDefault } from "./view-transition-default.js";
|
|
|
47
47
|
import { getRouterContext } from "../router-context.js";
|
|
48
48
|
import { observeEvent, observeSegmentHandler } from "../instrument.js";
|
|
49
49
|
import { runInSegmentTagScope } from "../../cache/cache-tag.js";
|
|
50
|
-
import {
|
|
50
|
+
import { trackStreamedHandler } from "./streamed-handler-boundary.js";
|
|
51
51
|
import {
|
|
52
52
|
track,
|
|
53
53
|
RangoContext,
|
|
@@ -441,6 +441,8 @@ async function resolveParallelSlotComponent<TEnv>(args: {
|
|
|
441
441
|
deps: SegmentResolutionDeps<TEnv>;
|
|
442
442
|
routeKey: string;
|
|
443
443
|
params: Record<string, string>;
|
|
444
|
+
/** Matched chain entry (where the sync path catches), else the slot's owner. */
|
|
445
|
+
boundaryEntry: EntryData;
|
|
444
446
|
}): Promise<{ component: ReactNode | undefined; handlerRan: boolean }> {
|
|
445
447
|
const {
|
|
446
448
|
shouldResolve,
|
|
@@ -452,6 +454,7 @@ async function resolveParallelSlotComponent<TEnv>(args: {
|
|
|
452
454
|
deps,
|
|
453
455
|
routeKey,
|
|
454
456
|
params,
|
|
457
|
+
boundaryEntry,
|
|
455
458
|
} = args;
|
|
456
459
|
|
|
457
460
|
let component: ReactNode | undefined;
|
|
@@ -484,19 +487,15 @@ async function resolveParallelSlotComponent<TEnv>(args: {
|
|
|
484
487
|
: handler;
|
|
485
488
|
if (result instanceof Promise) {
|
|
486
489
|
warnOnStreamedResponse(result, parallelId);
|
|
487
|
-
|
|
490
|
+
component = trackStreamedHandler(deps, result, {
|
|
491
|
+
boundaryEntry,
|
|
488
492
|
segmentId: parallelId,
|
|
489
493
|
segmentType: "parallel",
|
|
490
|
-
|
|
491
|
-
observeStreamedHandler(
|
|
492
|
-
tracked,
|
|
493
|
-
parallelId,
|
|
494
|
-
"parallel",
|
|
495
|
-
context.pathname,
|
|
494
|
+
context,
|
|
496
495
|
routeKey,
|
|
497
496
|
params,
|
|
498
|
-
|
|
499
|
-
|
|
497
|
+
recover: true,
|
|
498
|
+
});
|
|
500
499
|
} else {
|
|
501
500
|
component = result as ReactNode;
|
|
502
501
|
}
|
|
@@ -547,6 +546,8 @@ export async function resolveParallelSegmentsWithRevalidation<TEnv>(
|
|
|
547
546
|
* to it: loader sub-ids are filtered out and slots are re-grouped by parent).
|
|
548
547
|
*/
|
|
549
548
|
loaderOrder?: "after" | "before";
|
|
549
|
+
/** Matched chain entry being resolved; see ResolveSegmentOptions.boundaryEntry. */
|
|
550
|
+
boundaryEntry?: EntryData;
|
|
550
551
|
},
|
|
551
552
|
): Promise<SegmentRevalidationResult> {
|
|
552
553
|
const segments: ResolvedSegment[] = [];
|
|
@@ -696,6 +697,7 @@ export async function resolveParallelSegmentsWithRevalidation<TEnv>(
|
|
|
696
697
|
deps,
|
|
697
698
|
routeKey,
|
|
698
699
|
params,
|
|
700
|
+
boundaryEntry: options?.boundaryEntry ?? entry,
|
|
699
701
|
});
|
|
700
702
|
|
|
701
703
|
segments.push({
|
|
@@ -865,19 +867,17 @@ export async function resolveEntryHandlerWithRevalidation<TEnv>(
|
|
|
865
867
|
if (result instanceof Promise) {
|
|
866
868
|
warnOnStreamedResponse(result, routeEntry.id);
|
|
867
869
|
result.finally(doneHandler).catch(() => {});
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
);
|
|
880
|
-
return { content: tracked };
|
|
870
|
+
return {
|
|
871
|
+
content: trackStreamedHandler(deps, result, {
|
|
872
|
+
boundaryEntry: entry,
|
|
873
|
+
segmentId: entry.shortCode,
|
|
874
|
+
segmentType: entry.type,
|
|
875
|
+
context,
|
|
876
|
+
routeKey,
|
|
877
|
+
params,
|
|
878
|
+
recover: true,
|
|
879
|
+
}),
|
|
880
|
+
};
|
|
881
881
|
}
|
|
882
882
|
doneHandler();
|
|
883
883
|
return { content: result };
|
|
@@ -1098,6 +1098,8 @@ export async function resolveSegmentWithRevalidation<TEnv>(
|
|
|
1098
1098
|
deps,
|
|
1099
1099
|
actionContext,
|
|
1100
1100
|
stale,
|
|
1101
|
+
undefined,
|
|
1102
|
+
entry,
|
|
1101
1103
|
);
|
|
1102
1104
|
segments.push(...orphanResult.segments);
|
|
1103
1105
|
matchedIds.push(...orphanResult.matchedIds);
|
|
@@ -1126,6 +1128,8 @@ export async function resolveOrphanLayoutWithRevalidation<TEnv>(
|
|
|
1126
1128
|
stale?: boolean,
|
|
1127
1129
|
/** Parent route entry — its loaders are inherited so parallel slots can access them. */
|
|
1128
1130
|
parentRouteEntry?: EntryData,
|
|
1131
|
+
/** Matched chain entry being resolved (see ResolveSegmentOptions.boundaryEntry); defaults to parentRouteEntry. */
|
|
1132
|
+
boundaryEntry: EntryData | undefined = parentRouteEntry,
|
|
1129
1133
|
): Promise<SegmentRevalidationResult> {
|
|
1130
1134
|
invariant(
|
|
1131
1135
|
orphan.type === "layout" || orphan.type === "cache",
|
|
@@ -1286,7 +1290,11 @@ export async function resolveOrphanLayoutWithRevalidation<TEnv>(
|
|
|
1286
1290
|
deps,
|
|
1287
1291
|
actionContext,
|
|
1288
1292
|
stale,
|
|
1289
|
-
{
|
|
1293
|
+
{
|
|
1294
|
+
parentChainDefault: "force-render",
|
|
1295
|
+
loaderOrder: "before",
|
|
1296
|
+
boundaryEntry,
|
|
1297
|
+
},
|
|
1290
1298
|
);
|
|
1291
1299
|
segments.push(...parallelResult.segments);
|
|
1292
1300
|
matchedIds.push(...parallelResult.matchedIds);
|
|
@@ -1307,6 +1315,8 @@ export async function resolveOrphanLayoutWithRevalidation<TEnv>(
|
|
|
1307
1315
|
deps,
|
|
1308
1316
|
actionContext,
|
|
1309
1317
|
stale,
|
|
1318
|
+
undefined,
|
|
1319
|
+
boundaryEntry,
|
|
1310
1320
|
);
|
|
1311
1321
|
segments.push(...nestedResult.segments);
|
|
1312
1322
|
matchedIds.push(...nestedResult.matchedIds);
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Streamed handlers (loading()): track, observe, and recover a rejection into
|
|
3
|
+
* the declared errorBoundary() / notFoundBoundary() fallback.
|
|
4
|
+
*
|
|
5
|
+
* Invariants:
|
|
6
|
+
* - No status write and no onError call: the status is committed at first
|
|
7
|
+
* flush, and trackHandler already reports each rejection once.
|
|
8
|
+
* - The recovered promise resolves, so Flight reports no error. The writers
|
|
9
|
+
* that refuse a failed render through Flight errors need the failure
|
|
10
|
+
* recorded here: `_renderErrors` for the document cache and a prerender
|
|
11
|
+
* warm, `_recoveredHandlerErrors` for cacheRoute (cache(), and the doc record
|
|
12
|
+
* a PPR capture needs). The shell capture and the SWR re-render own both,
|
|
13
|
+
* so a derived render never writes into (or reads) the foreground's.
|
|
14
|
+
* - Nothing to render to rethrows the original rejection: no boundary found, a
|
|
15
|
+
* thrown Response (redirect), a Skip, a throwing fallback.
|
|
16
|
+
* - No recovery when `recover` is false (prerender throwOnError, the intercept
|
|
17
|
+
* background re-render): those lanes must reject so nothing is baked/cached.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import type { ReactNode } from "react";
|
|
21
|
+
import { isDataNotFoundError } from "../../errors.js";
|
|
22
|
+
import {
|
|
23
|
+
createErrorInfo,
|
|
24
|
+
createNotFoundInfo,
|
|
25
|
+
renderErrorFallback,
|
|
26
|
+
renderNotFoundFallback,
|
|
27
|
+
resolveNotFoundFallback,
|
|
28
|
+
} from "../error-handling.js";
|
|
29
|
+
import { _getRequestContext } from "../../server/request-context.js";
|
|
30
|
+
import type { EntryData } from "../../server/context.js";
|
|
31
|
+
import type { ErrorInfo, HandlerContext } from "../../types/index.js";
|
|
32
|
+
import type { SegmentResolutionDeps } from "../types.js";
|
|
33
|
+
import { observeStreamedHandler } from "./streamed-handler-telemetry.js";
|
|
34
|
+
|
|
35
|
+
export interface StreamedHandlerOptions<TEnv> {
|
|
36
|
+
/**
|
|
37
|
+
* Entry to look boundaries up from: the matched chain entry being resolved
|
|
38
|
+
* (where the sync path catches, whatever routeless layout owns a slot), or
|
|
39
|
+
* the intercept's declaring entry.
|
|
40
|
+
*/
|
|
41
|
+
boundaryEntry: EntryData;
|
|
42
|
+
segmentId: string;
|
|
43
|
+
segmentType: ErrorInfo["segmentType"];
|
|
44
|
+
context: HandlerContext<any, TEnv>;
|
|
45
|
+
routeKey?: string;
|
|
46
|
+
params: Record<string, string>;
|
|
47
|
+
/** False where the rejection must reach the caller (prerender, intercept background re-render). */
|
|
48
|
+
recover: boolean;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const NOOP = (): void => {};
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Track a streamed handler promise and return the segment component: the
|
|
55
|
+
* tracked promise itself when there is nothing to recover to, else a promise
|
|
56
|
+
* that resolves to the declared fallback on rejection.
|
|
57
|
+
*/
|
|
58
|
+
export function trackStreamedHandler<TEnv>(
|
|
59
|
+
deps: SegmentResolutionDeps<TEnv>,
|
|
60
|
+
result: Promise<unknown>,
|
|
61
|
+
options: StreamedHandlerOptions<TEnv>,
|
|
62
|
+
): ReactNode {
|
|
63
|
+
const { segmentId, segmentType, context } = options;
|
|
64
|
+
const tracked = deps.trackHandler(result as Promise<ReactNode>, {
|
|
65
|
+
segmentId,
|
|
66
|
+
segmentType,
|
|
67
|
+
});
|
|
68
|
+
observeStreamedHandler(
|
|
69
|
+
tracked,
|
|
70
|
+
segmentId,
|
|
71
|
+
segmentType,
|
|
72
|
+
context.pathname,
|
|
73
|
+
options.routeKey,
|
|
74
|
+
options.params,
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
if (!options.recover) return tracked as ReactNode;
|
|
78
|
+
const { boundaryEntry } = options;
|
|
79
|
+
const hasBoundary =
|
|
80
|
+
deps.findNearestErrorBoundary(boundaryEntry) != null ||
|
|
81
|
+
deps.findNearestNotFoundBoundary(boundaryEntry) != null ||
|
|
82
|
+
deps.notFoundComponent !== undefined;
|
|
83
|
+
if (!hasBoundary) return tracked as ReactNode;
|
|
84
|
+
|
|
85
|
+
// Captured now: the rejection can settle outside the request's ALS frame.
|
|
86
|
+
const reqCtx = _getRequestContext();
|
|
87
|
+
const recovered = tracked.catch((error: unknown): ReactNode => {
|
|
88
|
+
const node = renderBoundary(error, deps, options, boundaryEntry);
|
|
89
|
+
if (node === undefined) throw error;
|
|
90
|
+
if (reqCtx)
|
|
91
|
+
(reqCtx._recoveredHandlerErrors ??= new Map()).set(segmentId, error);
|
|
92
|
+
reqCtx?._renderErrors?.push(error);
|
|
93
|
+
return node;
|
|
94
|
+
});
|
|
95
|
+
// A dropped segment (never rendered) must not become an unhandledRejection.
|
|
96
|
+
recovered.catch(NOOP);
|
|
97
|
+
return recovered as ReactNode;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function renderBoundary<TEnv>(
|
|
101
|
+
error: unknown,
|
|
102
|
+
deps: SegmentResolutionDeps<TEnv>,
|
|
103
|
+
options: StreamedHandlerOptions<TEnv>,
|
|
104
|
+
boundaryEntry: EntryData,
|
|
105
|
+
): ReactNode | undefined {
|
|
106
|
+
if (error instanceof Response) return undefined;
|
|
107
|
+
if ((error as { name?: string } | null)?.name === "Skip") return undefined;
|
|
108
|
+
const { segmentId, segmentType, context } = options;
|
|
109
|
+
try {
|
|
110
|
+
if (isDataNotFoundError(error)) {
|
|
111
|
+
const boundary = deps.findNearestNotFoundBoundary(boundaryEntry);
|
|
112
|
+
if (boundary == null && deps.notFoundComponent === undefined) {
|
|
113
|
+
return undefined;
|
|
114
|
+
}
|
|
115
|
+
return renderNotFoundFallback(
|
|
116
|
+
resolveNotFoundFallback(
|
|
117
|
+
boundary,
|
|
118
|
+
deps.notFoundComponent,
|
|
119
|
+
context.pathname,
|
|
120
|
+
),
|
|
121
|
+
createNotFoundInfo(error, segmentId, segmentType, context.pathname),
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
const fallback = deps.findNearestErrorBoundary(boundaryEntry);
|
|
125
|
+
if (fallback == null) return undefined;
|
|
126
|
+
return renderErrorFallback(
|
|
127
|
+
fallback,
|
|
128
|
+
createErrorInfo(error, segmentId, segmentType),
|
|
129
|
+
);
|
|
130
|
+
} catch {
|
|
131
|
+
return undefined;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
@@ -25,6 +25,8 @@ export interface TrieMatchResult {
|
|
|
25
25
|
pr?: true;
|
|
26
26
|
/** Passthrough: handler kept for live fallback on unknown params */
|
|
27
27
|
pt?: true;
|
|
28
|
+
/** On-demand prerender eligible (router.prerender() refreshable) */
|
|
29
|
+
od?: true;
|
|
28
30
|
/** Response type for non-RSC routes (json, text, image, any) */
|
|
29
31
|
responseType?: string;
|
|
30
32
|
/** Negotiate variants: response-type routes sharing this path */
|
|
@@ -343,6 +345,7 @@ function validateAndBuild(
|
|
|
343
345
|
if (redirectTo) result.redirectTo = redirectTo;
|
|
344
346
|
if (leaf.pr) result.pr = true;
|
|
345
347
|
if (leaf.pt) result.pt = true;
|
|
348
|
+
if (leaf.od) result.od = true;
|
|
346
349
|
if (leaf.rt) result.responseType = leaf.rt;
|
|
347
350
|
if (leaf.nv) result.negotiateVariants = leaf.nv;
|
|
348
351
|
if (leaf.rf) result.rscFirst = true;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-router cache versions: the shapes shared by the build (which computes
|
|
3
|
+
* them, vite/discovery/build-versions.ts) and the runtime (which reads them,
|
|
4
|
+
* server/build-version-table.ts). No imports, so the Vite plugin bundle can
|
|
5
|
+
* use it without resolving the `@rangojs/router:version` virtual module.
|
|
6
|
+
*
|
|
7
|
+
* Design: docs/design/per-app-cache-version.md.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* The two versions one `createRouter()` serves with.
|
|
12
|
+
*
|
|
13
|
+
* - `data` keys cached RSC data: segment entries, `"use cache"` values and
|
|
14
|
+
* loader data. It follows the router's server code only.
|
|
15
|
+
* - `document` keys stored HTML (PPR shells, document-cache responses), is the
|
|
16
|
+
* value the browser echoes as `_rsc_v`, and stamps `ShellCacheEntry.buildVersion`.
|
|
17
|
+
* It follows the server code and the client asset URLs.
|
|
18
|
+
*/
|
|
19
|
+
export interface RouterVersions {
|
|
20
|
+
readonly data: string;
|
|
21
|
+
readonly document: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* The build's table as the `@rangojs/router:version` module exports it:
|
|
26
|
+
* router id to `[data, document]`. {@link DEFAULT_ROUTER_VERSIONS_KEY} holds
|
|
27
|
+
* the whole-build pair, used for a router the build could not attribute.
|
|
28
|
+
*/
|
|
29
|
+
export type RouterVersionsTable = Readonly<
|
|
30
|
+
Record<string, readonly [data: string, document: string]>
|
|
31
|
+
>;
|
|
32
|
+
|
|
33
|
+
/** Table key of the whole-build versions. Not a legal `$$id` (8 hex chars). */
|
|
34
|
+
export const DEFAULT_ROUTER_VERSIONS_KEY = "*";
|
|
35
|
+
|
|
36
|
+
/** One value for both versions: a consumer-set `version`, or the dev stamp. */
|
|
37
|
+
export function uniformVersions(version: string): RouterVersions {
|
|
38
|
+
return { data: version, document: version };
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* The versions a router serves with under `table`: a consumer-set `version`
|
|
43
|
+
* for both; else the router's own entry; else the whole-build pair, for a
|
|
44
|
+
* router the table does not list. `undefined` when there is no table (dev,
|
|
45
|
+
* tests) or it has neither entry. One function for the request handler and
|
|
46
|
+
* the build's shell capture, which must stamp what the handler will check.
|
|
47
|
+
*/
|
|
48
|
+
export function resolveVersionsFrom(
|
|
49
|
+
table: RouterVersionsTable | undefined,
|
|
50
|
+
routerId: string | undefined,
|
|
51
|
+
override: string | undefined,
|
|
52
|
+
): RouterVersions | undefined {
|
|
53
|
+
if (override !== undefined) return uniformVersions(override);
|
|
54
|
+
if (!table) return undefined;
|
|
55
|
+
const pair =
|
|
56
|
+
(routerId !== undefined && Object.hasOwn(table, routerId)
|
|
57
|
+
? table[routerId]
|
|
58
|
+
: undefined) ?? table[DEFAULT_ROUTER_VERSIONS_KEY];
|
|
59
|
+
return pair ? { data: pair[0], document: pair[1] } : undefined;
|
|
60
|
+
}
|
package/src/router.ts
CHANGED
|
@@ -14,6 +14,14 @@ import {
|
|
|
14
14
|
isValidDevDiscoveryEpoch,
|
|
15
15
|
} from "./dev-discovery-protocol.js";
|
|
16
16
|
import { createReverse, type ReverseFunction } from "./reverse.js";
|
|
17
|
+
import {
|
|
18
|
+
resolvePrerenderVersion,
|
|
19
|
+
resolveRouterVersions,
|
|
20
|
+
} from "./server/build-version-table.js";
|
|
21
|
+
import { isDevEnvironment } from "./errors.js";
|
|
22
|
+
import { isViteDevServer } from "./cache/store-scope.js";
|
|
23
|
+
import { createPrerenderTrigger } from "./prerender/create-prerender-trigger.js";
|
|
24
|
+
import { createMemoryPrerenderStore } from "./prerender/memory-prerender-store.js";
|
|
17
25
|
import {
|
|
18
26
|
registerRouteMap,
|
|
19
27
|
getRouterManifest,
|
|
@@ -155,6 +163,7 @@ export function createRouter<TEnv = any>(
|
|
|
155
163
|
notFound,
|
|
156
164
|
onError,
|
|
157
165
|
cache,
|
|
166
|
+
prerender: prerenderConfigOption,
|
|
158
167
|
cacheProfiles: cacheProfilesOption,
|
|
159
168
|
theme: themeOption,
|
|
160
169
|
urls: urlsOption,
|
|
@@ -181,6 +190,16 @@ export function createRouter<TEnv = any>(
|
|
|
181
190
|
strictMode: strictModeOption = true,
|
|
182
191
|
} = options;
|
|
183
192
|
|
|
193
|
+
const defaultDevPrerenderStore = prerenderConfigOption
|
|
194
|
+
? undefined
|
|
195
|
+
: createMemoryPrerenderStore();
|
|
196
|
+
const effectivePrerenderConfigOption =
|
|
197
|
+
prerenderConfigOption ??
|
|
198
|
+
((() =>
|
|
199
|
+
isViteDevServer() && defaultDevPrerenderStore
|
|
200
|
+
? { store: defaultDevPrerenderStore }
|
|
201
|
+
: undefined) as RangoOptions<TEnv>["prerender"]);
|
|
202
|
+
|
|
184
203
|
// Debug cache signal gate (DEVELOPMENT/TEST ONLY). Enabled by the
|
|
185
204
|
// debugCacheSignal option OR the RANGO_TEST_SIGNALS=1 env flag. When off,
|
|
186
205
|
// no X-Rango-Cache header is emitted and output is byte-identical.
|
|
@@ -744,6 +763,77 @@ export function createRouter<TEnv = any>(
|
|
|
744
763
|
);
|
|
745
764
|
}
|
|
746
765
|
|
|
766
|
+
// Shared reverse function (also the value behind router.reverse).
|
|
767
|
+
const reverseFn = createReverse(mergedRouteMap);
|
|
768
|
+
const reverseLoose = reverseFn as unknown as (
|
|
769
|
+
name: string,
|
|
770
|
+
params?: Record<string, string>,
|
|
771
|
+
) => string;
|
|
772
|
+
|
|
773
|
+
// On-demand prerender binder (router.prerender({ env, ctx }) -> runner with .many / .markStale).
|
|
774
|
+
// Requestless: runProducer runs matchForPrerender with onDemand=true (arming
|
|
775
|
+
// the personalization guard); the store/config resolve per call from {env,ctx}.
|
|
776
|
+
// The key version is the router's data version, resolved by the same call the
|
|
777
|
+
// handler's overlay read makes (resolvePrerenderVersion), so the keys agree.
|
|
778
|
+
const prerenderTrigger = createPrerenderTrigger<TEnv, {}>({
|
|
779
|
+
routerId,
|
|
780
|
+
resolveVersion: () => resolvePrerenderVersion(routerId, version),
|
|
781
|
+
isDev: isDevEnvironment,
|
|
782
|
+
isViteDevServer,
|
|
783
|
+
ensureManifest: () => ensureRouterManifest(routerId),
|
|
784
|
+
resolveConfig: (env, ctx) => {
|
|
785
|
+
const opt = effectivePrerenderConfigOption;
|
|
786
|
+
if (!opt) return undefined;
|
|
787
|
+
return typeof opt === "function" ? opt(env, ctx) : opt;
|
|
788
|
+
},
|
|
789
|
+
reverse: (route, params) => {
|
|
790
|
+
try {
|
|
791
|
+
return reverseLoose(route, params);
|
|
792
|
+
} catch {
|
|
793
|
+
return undefined;
|
|
794
|
+
}
|
|
795
|
+
},
|
|
796
|
+
matchRoute: async (pathname) => {
|
|
797
|
+
const m = await findMatch(pathname);
|
|
798
|
+
if (!m) return null;
|
|
799
|
+
return {
|
|
800
|
+
routeName: m.routeKey,
|
|
801
|
+
params: m.params,
|
|
802
|
+
isOnDemand: m.od === true,
|
|
803
|
+
isPassthrough: m.pt === true,
|
|
804
|
+
};
|
|
805
|
+
},
|
|
806
|
+
runProducer: ({ pathname, isPassthrough, env, dev }) =>
|
|
807
|
+
_matchForPrerender<TEnv>(
|
|
808
|
+
pathname,
|
|
809
|
+
{},
|
|
810
|
+
{
|
|
811
|
+
...prerenderDeps,
|
|
812
|
+
versions: resolveRouterVersions(routerId, version),
|
|
813
|
+
},
|
|
814
|
+
undefined,
|
|
815
|
+
isPassthrough,
|
|
816
|
+
env,
|
|
817
|
+
dev,
|
|
818
|
+
true,
|
|
819
|
+
),
|
|
820
|
+
// A warm goes through router.fetch's handler: the one createRouter's own
|
|
821
|
+
// cache, nonce and version configure. An entry that passes them to
|
|
822
|
+
// createRSCHandler itself is not what a warm runs.
|
|
823
|
+
resolveCacheConfig: (env, ctx) =>
|
|
824
|
+
typeof cache === "function" ? cache(env, ctx) : cache,
|
|
825
|
+
// Called from inside a request, the warm leaves that request's scopes:
|
|
826
|
+
// it runs in the context the request entered the handler with
|
|
827
|
+
// (RequestContext._runAtRequestEntry).
|
|
828
|
+
fetch: (request, input) => {
|
|
829
|
+
const atRequestEntry = _getRequestContext()?._runAtRequestEntry;
|
|
830
|
+
return atRequestEntry
|
|
831
|
+
? atRequestEntry(() => router.fetch(request, input))
|
|
832
|
+
: router.fetch(request, input);
|
|
833
|
+
},
|
|
834
|
+
ambientOrigin: () => _getRequestContext()?.url.origin,
|
|
835
|
+
});
|
|
836
|
+
|
|
747
837
|
// Create match handler functions bound to router state
|
|
748
838
|
const matchHandlers = createMatchHandlers<TEnv>({
|
|
749
839
|
buildRouterContext,
|
|
@@ -866,6 +956,7 @@ export function createRouter<TEnv = any>(
|
|
|
866
956
|
// Collect route keys that have prerender handlers (for non-trie match path)
|
|
867
957
|
let prerenderRouteKeys: Set<string> | undefined;
|
|
868
958
|
let passthroughRouteKeys: Set<string> | undefined;
|
|
959
|
+
let onDemandRouteKeys: Set<string> | undefined;
|
|
869
960
|
for (const [name, entry] of manifest.entries()) {
|
|
870
961
|
if (entry.type === "route" && entry.isPrerender) {
|
|
871
962
|
if (!prerenderRouteKeys) prerenderRouteKeys = new Set();
|
|
@@ -874,6 +965,10 @@ export function createRouter<TEnv = any>(
|
|
|
874
965
|
if (!passthroughRouteKeys) passthroughRouteKeys = new Set();
|
|
875
966
|
passthroughRouteKeys.add(name);
|
|
876
967
|
}
|
|
968
|
+
if (entry.isOnDemand === true) {
|
|
969
|
+
if (!onDemandRouteKeys) onDemandRouteKeys = new Set();
|
|
970
|
+
onDemandRouteKeys.add(name);
|
|
971
|
+
}
|
|
877
972
|
}
|
|
878
973
|
}
|
|
879
974
|
|
|
@@ -900,6 +995,7 @@ export function createRouter<TEnv = any>(
|
|
|
900
995
|
cacheProfiles: resolvedCacheProfiles,
|
|
901
996
|
...(prerenderRouteKeys ? { prerenderRouteKeys } : {}),
|
|
902
997
|
...(passthroughRouteKeys ? { passthroughRouteKeys } : {}),
|
|
998
|
+
...(onDemandRouteKeys ? { onDemandRouteKeys } : {}),
|
|
903
999
|
});
|
|
904
1000
|
}
|
|
905
1001
|
} else {
|
|
@@ -920,6 +1016,7 @@ export function createRouter<TEnv = any>(
|
|
|
920
1016
|
cacheProfiles: resolvedCacheProfiles,
|
|
921
1017
|
...(prerenderRouteKeys ? { prerenderRouteKeys } : {}),
|
|
922
1018
|
...(passthroughRouteKeys ? { passthroughRouteKeys } : {}),
|
|
1019
|
+
...(onDemandRouteKeys ? { onDemandRouteKeys } : {}),
|
|
923
1020
|
});
|
|
924
1021
|
}
|
|
925
1022
|
|
|
@@ -1020,7 +1117,7 @@ export function createRouter<TEnv = any>(
|
|
|
1020
1117
|
// Type-safe URL builder using merged route map
|
|
1021
1118
|
// Types are tracked through the builder chain via TRoutes parameter
|
|
1022
1119
|
// Seeded with static route names from the generated file (injected by Vite)
|
|
1023
|
-
reverse:
|
|
1120
|
+
reverse: reverseFn,
|
|
1024
1121
|
|
|
1025
1122
|
// Expose accumulated route map for typeof extraction
|
|
1026
1123
|
// Returns {} initially, but builder chain accumulates specific route types
|
|
@@ -1037,6 +1134,15 @@ export function createRouter<TEnv = any>(
|
|
|
1037
1134
|
// Expose cache configuration for RSC handler
|
|
1038
1135
|
cache,
|
|
1039
1136
|
|
|
1137
|
+
// Expose the prerender store config (durable overlay) for the RSC handler to
|
|
1138
|
+
// resolve per request. Stored under _prerenderConfig because `prerender` on
|
|
1139
|
+
// the instance is the trigger method (router.prerender()).
|
|
1140
|
+
_prerenderConfig: effectivePrerenderConfigOption,
|
|
1141
|
+
|
|
1142
|
+
// On-demand prerender trigger: router.prerender({ env, ctx })(target),
|
|
1143
|
+
// plus .many() and .markStale() on the runner.
|
|
1144
|
+
prerender: prerenderTrigger,
|
|
1145
|
+
|
|
1040
1146
|
// Expose notFound component for RSC handler
|
|
1041
1147
|
notFound,
|
|
1042
1148
|
|
package/src/rsc/full-payload.ts
CHANGED
|
@@ -52,8 +52,12 @@ export function buildFullPayload(
|
|
|
52
52
|
rootLayout: ctx.router.rootLayout,
|
|
53
53
|
// Full render: resolve deferred handle values server-side so SSR markup and
|
|
54
54
|
// the first sync useHandle read see resolved values. Partial payloads
|
|
55
|
-
// (rsc-rendering.ts) keep streaming (handleStore.stream()).
|
|
56
|
-
|
|
55
|
+
// (rsc-rendering.ts) keep streaming (handleStore.stream()). A shell
|
|
56
|
+
// capture renders from what its record keeps (resolvedHandleStream).
|
|
57
|
+
handles: resolvedHandleStream(
|
|
58
|
+
handleStore,
|
|
59
|
+
reqCtx._shellCaptureRun === true,
|
|
60
|
+
),
|
|
57
61
|
// Post-handler-barrier pushes (streaming loader ctx.handle() writes)
|
|
58
62
|
// stream here; the client applies them after hydration. Instantly
|
|
59
63
|
// complete when the loader lane is idle — including PPR shell capture,
|
|
@@ -14,6 +14,11 @@ import type { SSRStreamMode } from "../router/router-options.js";
|
|
|
14
14
|
|
|
15
15
|
export interface HandlerContext<TEnv = unknown> {
|
|
16
16
|
router: RangoInternal<TEnv, any>;
|
|
17
|
+
/**
|
|
18
|
+
* The router's DOCUMENT version (router-versions.ts): payload metadata, the
|
|
19
|
+
* `_rsc_v` reload check, and PPR shell stamping and gating. The data version
|
|
20
|
+
* is not here; cache stores read it from the request context.
|
|
21
|
+
*/
|
|
17
22
|
version: string;
|
|
18
23
|
devDiscoveryEpoch?: number;
|
|
19
24
|
renderToReadableStream: RSCDependencies["renderToReadableStream"];
|