@rangojs/router 0.16.0 → 0.18.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 +255 -89
- package/dist/testing/vitest.js +252 -0
- package/dist/types/browser/cookie-name.d.ts +6 -0
- package/dist/types/browser/history-state.d.ts +16 -0
- package/dist/types/browser/navigation-transaction.d.ts +6 -0
- package/dist/types/browser/partial-update.d.ts +11 -0
- package/dist/types/browser/react/ScrollRestoration.d.ts +6 -6
- package/dist/types/browser/rsc-router.d.ts +1 -1
- package/dist/types/browser/scroll-restoration.d.ts +7 -0
- package/dist/types/cache/cache-exec-scope.d.ts +18 -1
- package/dist/types/cache/cache-key-utils.d.ts +17 -2
- package/dist/types/cache/cache-policy.d.ts +17 -0
- package/dist/types/cache/cache-scope.d.ts +132 -19
- package/dist/types/cache/cache-tag.d.ts +92 -7
- package/dist/types/cache/cf/cf-base64.d.ts +6 -0
- package/dist/types/cache/cf/cf-cache-constants.d.ts +11 -0
- package/dist/types/cache/cf/cf-cache-store.d.ts +185 -44
- package/dist/types/cache/cf/cf-cache-types.d.ts +31 -4
- package/dist/types/cache/cf/cf-shell-frame.d.ts +95 -0
- package/dist/types/cache/cf/cf-tag-marker-memo.d.ts +34 -0
- package/dist/types/cache/handle-capture.d.ts +41 -3
- package/dist/types/cache/handle-snapshot.d.ts +54 -13
- package/dist/types/cache/index.d.ts +1 -0
- package/dist/types/cache/isolate-tag-memo.d.ts +149 -0
- package/dist/types/cache/segment-codec.d.ts +10 -3
- package/dist/types/cache/shell-memo.d.ts +178 -0
- package/dist/types/cache/shell-snapshot.d.ts +110 -21
- package/dist/types/cache/tag-invalidation.d.ts +30 -3
- package/dist/types/cache/taint.d.ts +1 -1
- package/dist/types/cache/types.d.ts +220 -44
- package/dist/types/cache/vercel/vercel-cache-store.d.ts +111 -13
- package/dist/types/client.d.ts +4 -4
- package/dist/types/client.rsc.d.ts +4 -5
- package/dist/types/components/DefaultDocument.d.ts +5 -2
- package/dist/types/context-var.d.ts +6 -5
- package/dist/types/escape-script.d.ts +1 -1
- package/dist/types/handles/MetaTags.d.ts +5 -4
- package/dist/types/handles/Scripts.d.ts +8 -7
- package/dist/types/handles/meta.d.ts +2 -2
- package/dist/types/handles/script.d.ts +17 -16
- package/dist/types/href-client.d.ts +1 -1
- package/dist/types/html.d.ts +12 -0
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.rsc.d.ts +3 -2
- package/dist/types/loader-store.d.ts +7 -4
- package/dist/types/prerender/build-shell-capture.d.ts +11 -4
- package/dist/types/reverse.d.ts +36 -4
- package/dist/types/route-definition/dsl-helpers.d.ts +3 -3
- package/dist/types/route-definition/helpers-types.d.ts +33 -9
- package/dist/types/route-definition/resolve-handler-use.d.ts +23 -1
- package/dist/types/route-types.d.ts +1 -1
- package/dist/types/router/debug-manifest.d.ts +3 -2
- package/dist/types/router/error-handling.d.ts +20 -0
- package/dist/types/router/handler-context.d.ts +6 -0
- package/dist/types/router/instrument.d.ts +8 -0
- package/dist/types/router/match-middleware/background-revalidation.d.ts +46 -5
- package/dist/types/router/middleware-types.d.ts +9 -3
- package/dist/types/router/router-context.d.ts +3 -1
- package/dist/types/router/router-interfaces.d.ts +24 -2
- package/dist/types/router/router-options.d.ts +8 -5
- package/dist/types/router/segment-resolution/fresh.d.ts +10 -0
- package/dist/types/router/segment-resolution/loader-cache.d.ts +66 -1
- package/dist/types/router/segment-resolution/loader-mask.d.ts +9 -19
- package/dist/types/router/segment-resolution/loader-snapshot.d.ts +23 -12
- package/dist/types/router/segment-resolution/mask-nested.d.ts +67 -26
- package/dist/types/router/segment-resolution/revalidation.d.ts +6 -2
- package/dist/types/router/segment-wrappers.d.ts +1 -1
- package/dist/types/rsc/full-payload.d.ts +14 -0
- package/dist/types/rsc/handler.d.ts +1 -1
- package/dist/types/rsc/response-route-handler.d.ts +1 -1
- package/dist/types/rsc/rsc-rendering.d.ts +1 -2
- package/dist/types/rsc/shell-build-manifest.d.ts +8 -0
- package/dist/types/rsc/shell-capture-constants.d.ts +61 -6
- package/dist/types/rsc/shell-capture.d.ts +151 -19
- package/dist/types/rsc/shell-serve.d.ts +140 -17
- package/dist/types/rsc/ssr-setup.d.ts +6 -6
- package/dist/types/rsc/types.d.ts +17 -0
- package/dist/types/server/context.d.ts +139 -15
- package/dist/types/server/cookie-store.d.ts +21 -0
- package/dist/types/server/handle-store.d.ts +26 -2
- package/dist/types/server/request-context.d.ts +182 -53
- package/dist/types/ssr/index.d.ts +24 -0
- package/dist/types/ssr/ssr-root.d.ts +9 -8
- package/dist/types/static-handler.d.ts +4 -1
- package/dist/types/testing/flight.entry.d.ts +7 -0
- package/dist/types/testing/generated-routes.d.ts +2 -2
- package/dist/types/testing/internal/context.d.ts +1 -1
- package/dist/types/testing/render-route.d.ts +32 -6
- package/dist/types/testing/run-loader.d.ts +18 -3
- package/dist/types/testing/serve-shell-request.d.ts +132 -0
- package/dist/types/testing/shell-status.d.ts +23 -10
- package/dist/types/testing/vitest-stubs/plugin-rsc.d.ts +28 -5
- package/dist/types/testing/vitest.d.ts +35 -1
- package/dist/types/theme/ThemeScript.d.ts +3 -3
- package/dist/types/types/cache-types.d.ts +14 -10
- package/dist/types/types/handler-context.d.ts +28 -1
- package/dist/types/types/loader-types.d.ts +8 -6
- package/dist/types/urls/pattern-types.d.ts +22 -18
- package/dist/types/urls/response-types.d.ts +3 -12
- package/dist/types/use-loader.d.ts +12 -3
- package/dist/types/vite/plugins/use-cache-transform.d.ts +33 -2
- package/dist/types/vite/rango.d.ts +1 -1
- package/dist/types/vite/router-discovery.d.ts +29 -2
- package/dist/vite/index.js +1420 -1348
- package/package.json +2 -2
- package/skills/api-client/SKILL.md +22 -10
- package/skills/breadcrumbs/SKILL.md +75 -22
- package/skills/bundle-analysis/SKILL.md +22 -22
- package/skills/cache-guide/SKILL.md +306 -124
- package/skills/caching/SKILL.md +530 -98
- package/skills/catalog.json +16 -16
- package/skills/client-urls/SKILL.md +65 -38
- package/skills/cloudflare/SKILL.md +87 -20
- package/skills/cloudflare/references/d1-and-local-dev.md +15 -2
- package/skills/cloudflare/references/streaming-and-deploy.md +10 -3
- package/skills/cloudflare/references/webhooks-and-crypto.md +9 -2
- package/skills/comparison/SKILL.md +5 -0
- package/skills/comparison/references/framework-comparison.md +75 -57
- package/skills/composability/SKILL.md +38 -29
- package/skills/css/SKILL.md +10 -13
- package/skills/debug-manifest/SKILL.md +74 -31
- package/skills/defer-hydration/SKILL.md +52 -31
- package/skills/deployment-caching/SKILL.md +11 -3
- package/skills/document-cache/SKILL.md +98 -28
- package/skills/fonts/SKILL.md +16 -8
- package/skills/handler-use/SKILL.md +55 -17
- package/skills/hooks/SKILL.md +28 -20
- package/skills/hooks/data.md +23 -3
- package/skills/hooks/handle-and-actions.md +34 -17
- package/skills/hooks/navigation.md +39 -10
- package/skills/hooks/outlets.md +13 -6
- package/skills/hooks/state.md +39 -15
- package/skills/hooks/urls.md +7 -5
- package/skills/host-router/SKILL.md +64 -12
- package/skills/i18n/SKILL.md +60 -34
- package/skills/intercept/SKILL.md +161 -26
- package/skills/layout/SKILL.md +106 -50
- package/skills/links/SKILL.md +51 -19
- package/skills/loader/SKILL.md +386 -128
- package/skills/middleware/SKILL.md +129 -26
- package/skills/migrate-nextjs/SKILL.md +156 -70
- package/skills/migrate-nextjs/backend-host-swap.md +5 -2
- package/skills/migrate-react-router/SKILL.md +51 -39
- package/skills/migrate-react-router/component-migration.md +28 -7
- package/skills/migrate-react-router/data-and-actions.md +21 -6
- package/skills/migrate-react-router/route-mapping.md +19 -10
- package/skills/mime-routes/SKILL.md +12 -7
- package/skills/observability/SKILL.md +92 -14
- package/skills/parallel/SKILL.md +88 -47
- package/skills/ppr/SKILL.md +866 -379
- package/skills/prerender/SKILL.md +210 -108
- package/skills/rango/SKILL.md +115 -65
- package/skills/react-compiler/SKILL.md +6 -5
- package/skills/response-routes/SKILL.md +133 -25
- package/skills/route/SKILL.md +170 -60
- package/skills/router-setup/SKILL.md +420 -240
- package/skills/scripts/SKILL.md +39 -21
- package/skills/server-actions/SKILL.md +231 -59
- package/skills/shell-manifest/SKILL.md +28 -14
- package/skills/streams-and-websockets/SKILL.md +32 -14
- package/skills/tailwind/SKILL.md +37 -33
- package/skills/testing/SKILL.md +73 -33
- package/skills/testing/cache-prerender.md +60 -33
- package/skills/testing/client-components.md +59 -6
- package/skills/testing/e2e-parity.md +12 -2
- package/skills/testing/flight.md +19 -11
- package/skills/testing/handles.md +8 -5
- package/skills/testing/loader.md +26 -6
- package/skills/testing/middleware.md +8 -3
- package/skills/testing/predicates.md +120 -0
- package/skills/testing/render-handler.md +70 -22
- package/skills/testing/response-routes.md +11 -4
- package/skills/testing/reverse-and-types.md +20 -14
- package/skills/testing/serve-shell-request.md +188 -0
- package/skills/testing/server-actions.md +12 -3
- package/skills/testing/server-tree.md +9 -0
- package/skills/testing/setup.md +9 -5
- package/skills/theme/SKILL.md +155 -30
- package/skills/typesafety/SKILL.md +20 -9
- package/skills/typesafety/env-and-bindings.md +137 -50
- package/skills/typesafety/generated-files-and-cli.md +26 -14
- package/skills/typesafety/params-and-search.md +44 -19
- package/skills/typesafety/route-types.md +50 -14
- package/skills/use-cache/SKILL.md +224 -83
- package/skills/vercel/SKILL.md +35 -13
- package/skills/view-transitions/SKILL.md +42 -21
- package/src/__augment-tests__/augmented.check.ts +26 -1
- package/src/browser/cookie-name.ts +23 -0
- package/src/browser/history-state.ts +23 -0
- package/src/browser/index.ts +2 -2
- package/src/browser/navigation-bridge.ts +3 -4
- package/src/browser/navigation-transaction.ts +22 -2
- package/src/browser/partial-update.ts +35 -25
- package/src/browser/react/ScrollRestoration.tsx +6 -6
- package/src/browser/rsc-router.tsx +6 -1
- package/src/browser/scroll-restoration.ts +53 -6
- package/src/cache/cache-exec-scope.ts +37 -4
- package/src/cache/cache-key-utils.ts +23 -8
- package/src/cache/cache-policy.ts +22 -0
- package/src/cache/cache-runtime.ts +264 -68
- package/src/cache/cache-scope.ts +419 -43
- package/src/cache/cache-tag.ts +375 -11
- package/src/cache/cf/cf-base64.ts +36 -4
- package/src/cache/cf/cf-cache-constants.ts +12 -0
- package/src/cache/cf/cf-cache-store.ts +990 -348
- package/src/cache/cf/cf-cache-types.ts +32 -4
- package/src/cache/cf/cf-shell-frame.ts +258 -0
- package/src/cache/cf/cf-tag-marker-memo.ts +143 -39
- package/src/cache/document-cache.ts +15 -0
- package/src/cache/handle-capture.ts +90 -10
- package/src/cache/handle-snapshot.ts +133 -28
- package/src/cache/index.ts +2 -0
- package/src/cache/isolate-tag-memo.ts +308 -0
- package/src/cache/segment-codec.ts +26 -7
- package/src/cache/shell-memo.ts +341 -0
- package/src/cache/shell-snapshot.ts +217 -27
- package/src/cache/tag-invalidation.ts +108 -22
- package/src/cache/taint.ts +1 -1
- package/src/cache/types.ts +225 -44
- package/src/cache/vercel/vercel-cache-store.ts +545 -61
- package/src/client.rsc.tsx +10 -9
- package/src/client.tsx +5 -4
- package/src/components/DefaultDocument.tsx +7 -2
- package/src/context-var.ts +6 -5
- package/src/escape-script.ts +1 -1
- package/src/handles/MetaTags.tsx +13 -11
- package/src/handles/Scripts.tsx +11 -10
- package/src/handles/meta.ts +2 -2
- package/src/handles/script.ts +17 -16
- package/src/href-client.ts +1 -1
- package/src/html.ts +12 -0
- package/src/index.rsc.ts +5 -0
- package/src/index.ts +1 -0
- package/src/loader-store.ts +7 -4
- package/src/prerender/build-shell-capture.ts +73 -22
- package/src/reverse.ts +44 -4
- package/src/route-definition/dsl-helpers.ts +121 -33
- package/src/route-definition/helpers-types.ts +33 -9
- package/src/route-definition/resolve-handler-use.ts +121 -6
- package/src/route-types.ts +0 -3
- package/src/router/debug-manifest.ts +10 -2
- package/src/router/error-handling.ts +51 -15
- package/src/router/handler-context.ts +71 -28
- package/src/router/instrument.ts +54 -2
- package/src/router/intercept-resolution.ts +141 -43
- package/src/router/loader-resolution.ts +115 -39
- package/src/router/match-api.ts +40 -26
- package/src/router/match-handlers.ts +5 -0
- package/src/router/match-middleware/background-revalidation.ts +161 -96
- package/src/router/match-middleware/cache-lookup.ts +110 -10
- package/src/router/match-middleware/cache-store.ts +48 -101
- package/src/router/middleware-types.ts +9 -6
- package/src/router/middleware.ts +75 -13
- package/src/router/prerender-match.ts +59 -19
- package/src/router/route-snapshot.ts +11 -1
- package/src/router/router-context.ts +2 -0
- package/src/router/router-interfaces.ts +25 -2
- package/src/router/router-options.ts +8 -5
- package/src/router/segment-resolution/fresh.ts +62 -21
- package/src/router/segment-resolution/helpers.ts +4 -2
- package/src/router/segment-resolution/loader-cache.ts +407 -76
- package/src/router/segment-resolution/loader-mask.ts +12 -22
- package/src/router/segment-resolution/loader-snapshot.ts +208 -56
- package/src/router/segment-resolution/mask-nested.ts +138 -44
- package/src/router/segment-resolution/revalidation.ts +61 -16
- package/src/router/segment-wrappers.ts +4 -0
- package/src/rsc/full-payload.ts +25 -1
- package/src/rsc/handler.ts +14 -2
- package/src/rsc/progressive-enhancement.ts +3 -2
- package/src/rsc/render-pipeline.ts +3 -0
- package/src/rsc/response-cache-serve.ts +9 -6
- package/src/rsc/response-route-handler.ts +11 -3
- package/src/rsc/rsc-rendering.ts +608 -225
- package/src/rsc/shell-build-manifest.ts +27 -9
- package/src/rsc/shell-capture-constants.ts +73 -6
- package/src/rsc/shell-capture.ts +1068 -296
- package/src/rsc/shell-serve.ts +316 -34
- package/src/rsc/ssr-setup.ts +14 -8
- package/src/rsc/types.ts +18 -0
- package/src/server/context.ts +300 -32
- package/src/server/cookie-store.ts +87 -61
- package/src/server/handle-store.ts +232 -7
- package/src/server/request-context.ts +297 -67
- package/src/ssr/index.tsx +136 -44
- package/src/ssr/ssr-root.tsx +9 -8
- package/src/static-handler.ts +4 -1
- package/src/testing/flight-runtime.d.ts +21 -0
- package/src/testing/flight.entry.ts +14 -0
- package/src/testing/generated-routes.ts +2 -2
- package/src/testing/internal/context.ts +1 -1
- package/src/testing/internal/flight-client-globals.ts +7 -5
- package/src/testing/render-route.tsx +85 -24
- package/src/testing/run-loader.ts +68 -6
- package/src/testing/serve-shell-request.ts +378 -0
- package/src/testing/shell-status.ts +34 -12
- package/src/testing/vitest-stubs/plugin-rsc.ts +123 -20
- package/src/testing/vitest.ts +62 -1
- package/src/theme/ThemeProvider.tsx +7 -6
- package/src/theme/ThemeScript.tsx +3 -3
- package/src/types/cache-types.ts +14 -10
- package/src/types/handler-context.ts +28 -1
- package/src/types/loader-types.ts +8 -6
- package/src/urls/pattern-types.ts +22 -18
- package/src/urls/response-types.ts +3 -23
- package/src/use-loader.tsx +12 -3
- package/src/vite/discovery/shell-prerender-phase.ts +9 -0
- package/src/vite/plugins/use-cache-transform.ts +118 -74
- package/src/vite/rango.ts +7 -3
- package/src/vite/router-discovery.ts +14 -4
|
@@ -45,7 +45,8 @@ import {
|
|
|
45
45
|
} from "./helpers.js";
|
|
46
46
|
import { applyViewTransitionDefault } from "./view-transition-default.js";
|
|
47
47
|
import { getRouterContext } from "../router-context.js";
|
|
48
|
-
import { observeEvent,
|
|
48
|
+
import { observeEvent, observeSegmentHandler } from "../instrument.js";
|
|
49
|
+
import { runInSegmentTagScope } from "../../cache/cache-tag.js";
|
|
49
50
|
import { observeStreamedHandler } from "./streamed-handler-telemetry.js";
|
|
50
51
|
import {
|
|
51
52
|
track,
|
|
@@ -215,13 +216,14 @@ export async function resolveLoadersWithRevalidation<TEnv>(
|
|
|
215
216
|
// onError/loader.error. isPartial flags the reporting phase accordingly.
|
|
216
217
|
const errorContext = { ...buildLoaderErrorContext(ctx), isPartial: true };
|
|
217
218
|
|
|
218
|
-
// PPR
|
|
219
|
-
//
|
|
220
|
-
//
|
|
221
|
-
//
|
|
222
|
-
//
|
|
219
|
+
// PPR bake/seed key, same as fresh.ts (lane rule: see resolveLoaderData,
|
|
220
|
+
// loader-cache.ts). The key must thread through EVERY resolveLoaderData
|
|
221
|
+
// funnel — omitting it here made a capture-active context
|
|
222
|
+
// whole-container-mask every loader on this path (a never-settling promise
|
|
223
|
+
// for a loader that should have executed).
|
|
223
224
|
// Outside capture the key only activates the _shellLoaderSeed overlay,
|
|
224
|
-
// which
|
|
225
|
+
// which serveShellHit seeds for a document HIT and the PPR partial replay
|
|
226
|
+
// (matchPartialWithPprReplay) seeds once its doc record hits.
|
|
225
227
|
const bakeLane = !entryLoadingMasksLoaders(entry.loading);
|
|
226
228
|
|
|
227
229
|
const loadersToRun = revalidationChecks.filter((c) => c.shouldRun);
|
|
@@ -240,9 +242,10 @@ export async function resolveLoadersWithRevalidation<TEnv>(
|
|
|
240
242
|
loaderEntry,
|
|
241
243
|
ctx,
|
|
242
244
|
ctx.pathname,
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
245
|
+
// `bake`, not awaitBeforeFlush: a navigation evaluation never
|
|
246
|
+
// carries awaitBeforeFlush, and an ssr: false loader must pin
|
|
247
|
+
// here exactly as on the document HIT.
|
|
248
|
+
bakeLane || loaderEntry.bake === true ? segmentId : null,
|
|
246
249
|
),
|
|
247
250
|
),
|
|
248
251
|
entry,
|
|
@@ -476,7 +479,9 @@ async function resolveParallelSlotComponent<TEnv>(args: {
|
|
|
476
479
|
handlerRan = true;
|
|
477
480
|
if (hasLoadingFallback) {
|
|
478
481
|
const result =
|
|
479
|
-
typeof handler === "function"
|
|
482
|
+
typeof handler === "function"
|
|
483
|
+
? runInSegmentTagScope(parallelId, handler, context)
|
|
484
|
+
: handler;
|
|
480
485
|
if (result instanceof Promise) {
|
|
481
486
|
warnOnStreamedResponse(result, parallelId);
|
|
482
487
|
const tracked = deps.trackHandler(result, {
|
|
@@ -497,7 +502,9 @@ async function resolveParallelSlotComponent<TEnv>(args: {
|
|
|
497
502
|
}
|
|
498
503
|
} else {
|
|
499
504
|
component =
|
|
500
|
-
typeof handler === "function"
|
|
505
|
+
typeof handler === "function"
|
|
506
|
+
? await runInSegmentTagScope(parallelId, handler, context)
|
|
507
|
+
: handler;
|
|
501
508
|
}
|
|
502
509
|
}
|
|
503
510
|
}
|
|
@@ -842,14 +849,19 @@ export async function resolveEntryHandlerWithRevalidation<TEnv>(
|
|
|
842
849
|
: routeEntry.handler;
|
|
843
850
|
if (!routeEntry.loading) {
|
|
844
851
|
const result = handleHandlerResult(
|
|
845
|
-
await
|
|
852
|
+
await observeSegmentHandler(
|
|
853
|
+
entry.shortCode,
|
|
854
|
+
entry.id,
|
|
855
|
+
handler,
|
|
856
|
+
context,
|
|
857
|
+
),
|
|
846
858
|
);
|
|
847
859
|
doneHandler();
|
|
848
860
|
return result;
|
|
849
861
|
}
|
|
850
862
|
if (!actionContext) {
|
|
851
863
|
const result = handleHandlerResult(
|
|
852
|
-
|
|
864
|
+
observeSegmentHandler(entry.shortCode, entry.id, handler, context),
|
|
853
865
|
);
|
|
854
866
|
if (result instanceof Promise) {
|
|
855
867
|
warnOnStreamedResponse(result, routeEntry.id);
|
|
@@ -875,7 +887,12 @@ export async function resolveEntryHandlerWithRevalidation<TEnv>(
|
|
|
875
887
|
entryId: entry.id,
|
|
876
888
|
});
|
|
877
889
|
const actionResult = handleHandlerResult(
|
|
878
|
-
await
|
|
890
|
+
await observeSegmentHandler(
|
|
891
|
+
entry.shortCode,
|
|
892
|
+
entry.id,
|
|
893
|
+
handler,
|
|
894
|
+
context,
|
|
895
|
+
),
|
|
879
896
|
);
|
|
880
897
|
doneHandler();
|
|
881
898
|
return {
|
|
@@ -934,6 +951,8 @@ export async function resolveSegmentWithRevalidation<TEnv>(
|
|
|
934
951
|
deps: SegmentResolutionDeps<TEnv>,
|
|
935
952
|
actionContext?: ActionContext,
|
|
936
953
|
stale?: boolean,
|
|
954
|
+
/** The matched route's full chain; see ResolveSegmentOptions.chain (fresh.ts). */
|
|
955
|
+
chain?: readonly EntryData[],
|
|
937
956
|
): Promise<SegmentRevalidationResult> {
|
|
938
957
|
const segments: ResolvedSegment[] = [];
|
|
939
958
|
const matchedIds: string[] = [];
|
|
@@ -1066,6 +1085,7 @@ export async function resolveSegmentWithRevalidation<TEnv>(
|
|
|
1066
1085
|
matchedIds.push(...parallelResult.matchedIds);
|
|
1067
1086
|
|
|
1068
1087
|
for (const orphan of entry.layout) {
|
|
1088
|
+
if (chain?.includes(orphan)) continue;
|
|
1069
1089
|
const orphanResult = await resolveOrphanLayoutWithRevalidation(
|
|
1070
1090
|
orphan,
|
|
1071
1091
|
params,
|
|
@@ -1274,6 +1294,27 @@ export async function resolveOrphanLayoutWithRevalidation<TEnv>(
|
|
|
1274
1294
|
segments.push(...parallelResult.segments);
|
|
1275
1295
|
matchedIds.push(...parallelResult.matchedIds);
|
|
1276
1296
|
|
|
1297
|
+
// Nested routeless entries; see resolveOrphanLayout (fresh.ts).
|
|
1298
|
+
for (const nested of orphan.layout) {
|
|
1299
|
+
const nestedResult = await resolveOrphanLayoutWithRevalidation(
|
|
1300
|
+
nested,
|
|
1301
|
+
params,
|
|
1302
|
+
context,
|
|
1303
|
+
clientSegmentIds,
|
|
1304
|
+
prevParams,
|
|
1305
|
+
request,
|
|
1306
|
+
prevUrl,
|
|
1307
|
+
nextUrl,
|
|
1308
|
+
routeKey,
|
|
1309
|
+
belongsToRoute,
|
|
1310
|
+
deps,
|
|
1311
|
+
actionContext,
|
|
1312
|
+
stale,
|
|
1313
|
+
);
|
|
1314
|
+
segments.push(...nestedResult.segments);
|
|
1315
|
+
matchedIds.push(...nestedResult.matchedIds);
|
|
1316
|
+
}
|
|
1317
|
+
|
|
1277
1318
|
return { segments, matchedIds };
|
|
1278
1319
|
}
|
|
1279
1320
|
|
|
@@ -1296,6 +1337,8 @@ export async function resolveAllSegmentsWithRevalidation<TEnv>(
|
|
|
1296
1337
|
pathname: string,
|
|
1297
1338
|
deps: SegmentResolutionDeps<TEnv>,
|
|
1298
1339
|
stale?: boolean,
|
|
1340
|
+
/** The matched route's full chain; see ResolveSegmentOptions.chain (fresh.ts). */
|
|
1341
|
+
chain: readonly EntryData[] = entries,
|
|
1299
1342
|
): Promise<{ segments: ResolvedSegment[]; matchedIds: string[] }> {
|
|
1300
1343
|
const allSegments: ResolvedSegment[] = [];
|
|
1301
1344
|
const matchedIds: string[] = [];
|
|
@@ -1325,7 +1368,8 @@ export async function resolveAllSegmentsWithRevalidation<TEnv>(
|
|
|
1325
1368
|
}
|
|
1326
1369
|
|
|
1327
1370
|
const nonParallelEntry = entry as Exclude<EntryData, { type: "parallel" }>;
|
|
1328
|
-
|
|
1371
|
+
// Same latch as resolveAllSegments (fresh.ts), route-level cache() included.
|
|
1372
|
+
if (entry.cache) {
|
|
1329
1373
|
const store = RangoContext.getStore();
|
|
1330
1374
|
if (store) store.insideCacheScope = true;
|
|
1331
1375
|
latchCachedHeaderScope("cache", routeKey);
|
|
@@ -1348,6 +1392,7 @@ export async function resolveAllSegmentsWithRevalidation<TEnv>(
|
|
|
1348
1392
|
deps,
|
|
1349
1393
|
actionContext,
|
|
1350
1394
|
stale,
|
|
1395
|
+
chain,
|
|
1351
1396
|
),
|
|
1352
1397
|
(seg) => ({ segments: [seg], matchedIds: [seg.id] }),
|
|
1353
1398
|
deps,
|
|
@@ -80,6 +80,8 @@ export interface SegmentWrappers<TEnv = any> {
|
|
|
80
80
|
interceptResult: { intercept: InterceptEntry; entry: EntryData } | null,
|
|
81
81
|
localRouteName: string,
|
|
82
82
|
pathname: string,
|
|
83
|
+
stale?: boolean,
|
|
84
|
+
chain?: readonly EntryData[],
|
|
83
85
|
) => Promise<{ segments: ResolvedSegment[]; matchedIds: string[] }>;
|
|
84
86
|
findInterceptForRoute: (
|
|
85
87
|
targetRouteKey: string,
|
|
@@ -205,6 +207,7 @@ export function createSegmentWrappers<TEnv = any>(
|
|
|
205
207
|
localRouteName: string,
|
|
206
208
|
pathname: string,
|
|
207
209
|
stale?: boolean,
|
|
210
|
+
chain?: readonly EntryData[],
|
|
208
211
|
): ReturnType<typeof _resolveAllSegmentsWithRevalidation> {
|
|
209
212
|
return _resolveAllSegmentsWithRevalidation(
|
|
210
213
|
entries,
|
|
@@ -222,6 +225,7 @@ export function createSegmentWrappers<TEnv = any>(
|
|
|
222
225
|
pathname,
|
|
223
226
|
segmentDeps,
|
|
224
227
|
stale,
|
|
228
|
+
chain,
|
|
225
229
|
);
|
|
226
230
|
}
|
|
227
231
|
|
package/src/rsc/full-payload.ts
CHANGED
|
@@ -13,6 +13,7 @@ import type { RscPayload } from "./types.js";
|
|
|
13
13
|
import type { HandlerContext } from "./handler-context.js";
|
|
14
14
|
import type { RequestContext } from "../server/request-context.js";
|
|
15
15
|
import type { HandleStore } from "../server/handle-store.js";
|
|
16
|
+
import type { Theme } from "../theme/types.js";
|
|
16
17
|
import { gateTransitions } from "./transition-gate.js";
|
|
17
18
|
import { resolvedHandleStream } from "../handles/deferred-resolution.js";
|
|
18
19
|
|
|
@@ -71,7 +72,30 @@ export function buildFullPayload(
|
|
|
71
72
|
// entry knows whether to wrap hydration in React.StrictMode. Partial
|
|
72
73
|
// (navigation) payloads omit it by design; StrictMode is decided once.
|
|
73
74
|
strictMode: ctx.router.strictMode,
|
|
74
|
-
initialTheme: reqCtx
|
|
75
|
+
initialTheme: payloadInitialTheme(reqCtx),
|
|
75
76
|
},
|
|
76
77
|
};
|
|
77
78
|
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* The theme a document payload carries as `metadata.initialTheme` (the
|
|
82
|
+
* ThemeProvider's first state), read with no identity guard: it is the
|
|
83
|
+
* router's own read, not handler code (#971).
|
|
84
|
+
*
|
|
85
|
+
* A shell capture carries the no-cookie default, not the capturing visitor's
|
|
86
|
+
* theme. The shell and its ShellCacheEntry.initialTheme serve every visitor,
|
|
87
|
+
* and ThemeProvider re-syncs only from an explicitly stored theme, so a
|
|
88
|
+
* visitor with none kept the capturer's `useTheme().theme` for the page's
|
|
89
|
+
* lifetime. A visitor with a stored theme gets it pre-paint (theme script)
|
|
90
|
+
* and in the provider after mount.
|
|
91
|
+
*/
|
|
92
|
+
export function payloadInitialTheme(
|
|
93
|
+
reqCtx: Pick<
|
|
94
|
+
RequestContext<any>,
|
|
95
|
+
"_themeConfig" | "_shellCaptureRun" | "_readTheme"
|
|
96
|
+
>,
|
|
97
|
+
): Theme | undefined {
|
|
98
|
+
const config = reqCtx._themeConfig;
|
|
99
|
+
if (!config) return undefined;
|
|
100
|
+
return reqCtx._shellCaptureRun ? config.defaultTheme : reqCtx._readTheme();
|
|
101
|
+
}
|
package/src/rsc/handler.ts
CHANGED
|
@@ -31,6 +31,7 @@ import {
|
|
|
31
31
|
} from "./helpers.js";
|
|
32
32
|
import { renderRscFlightStage, renderRscResponse } from "./render-pipeline.js";
|
|
33
33
|
import { guardOutgoingRedirect } from "./redirect-guard.js";
|
|
34
|
+
import { payloadInitialTheme } from "./full-payload.js";
|
|
34
35
|
import {
|
|
35
36
|
resolveSoftRedirectUrl,
|
|
36
37
|
resolveExternalRedirect,
|
|
@@ -85,6 +86,7 @@ import {
|
|
|
85
86
|
ORIGIN_CHECK_PHASE_BY_MODE,
|
|
86
87
|
} from "./origin-guard.js";
|
|
87
88
|
import { handleRscRendering } from "./rsc-rendering.js";
|
|
89
|
+
import { withoutShellMissMarker } from "./shell-serve.js";
|
|
88
90
|
import {
|
|
89
91
|
withTimeout,
|
|
90
92
|
isTimeoutEnabled,
|
|
@@ -436,10 +438,16 @@ export function createRSCHandler<
|
|
|
436
438
|
};
|
|
437
439
|
|
|
438
440
|
return async function handler(
|
|
439
|
-
|
|
441
|
+
incomingRequest: Request,
|
|
440
442
|
input: RouterRequestInput<TEnv> = {},
|
|
441
443
|
): Promise<Response> {
|
|
442
444
|
const handlerStart = performance.now();
|
|
445
|
+
// A degraded PPR HIT's reload carries the forced-MISS marker: keep only
|
|
446
|
+
// the flag (set on the request context below) and drop the marker before
|
|
447
|
+
// anything reads the request, so middleware, handlers, loaders, cache
|
|
448
|
+
// keys and the SSR search seed see the URL the visitor asked for.
|
|
449
|
+
const unmarkedRequest = withoutShellMissMarker(incomingRequest);
|
|
450
|
+
const request = unmarkedRequest ?? incomingRequest;
|
|
443
451
|
// Create the metrics store at handler start so handler:total has startTime=0
|
|
444
452
|
// and all metrics are relative to the request entry point.
|
|
445
453
|
const earlyMetricsStore = router.debugPerformance
|
|
@@ -566,6 +574,7 @@ export function createRSCHandler<
|
|
|
566
574
|
stateCookieName: router.resolvedStateCookieName,
|
|
567
575
|
version,
|
|
568
576
|
});
|
|
577
|
+
if (unmarkedRequest) requestContext._shellForcedMiss = true;
|
|
569
578
|
// Gate on the SAME enabled-semantics withTimeout uses (isTimeoutEnabled):
|
|
570
579
|
// a `renderStartMs: 0` / negative opt-out disables the timeout, so the
|
|
571
580
|
// driver's cursor bookkeeping (which only the timeout reads) must be off too.
|
|
@@ -662,6 +671,9 @@ export function createRSCHandler<
|
|
|
662
671
|
// the host; it never reads or wraps response.body. A downstream throw
|
|
663
672
|
// skips it entirely (no response exists to hand off).
|
|
664
673
|
return observePhase(PHASES.response, (responseSpan) => {
|
|
674
|
+
// Header and cookie writes from here on (a streaming loader or
|
|
675
|
+
// render) no longer reach the response.
|
|
676
|
+
requestContext._responseSent = true;
|
|
665
677
|
let response: Response;
|
|
666
678
|
if (hasMiddleware) {
|
|
667
679
|
if (
|
|
@@ -1355,7 +1367,7 @@ export function createRSCHandler<
|
|
|
1355
1367
|
themeConfig: router.themeConfig,
|
|
1356
1368
|
warmupEnabled: router.warmupEnabled,
|
|
1357
1369
|
strictMode: router.strictMode,
|
|
1358
|
-
initialTheme: getRequestContext()
|
|
1370
|
+
initialTheme: payloadInitialTheme(getRequestContext()),
|
|
1359
1371
|
},
|
|
1360
1372
|
};
|
|
1361
1373
|
|
|
@@ -15,6 +15,7 @@ import type { MiddlewareFn } from "../router/middleware.js";
|
|
|
15
15
|
import { executeMiddleware } from "../router/middleware.js";
|
|
16
16
|
import { observePhase, PHASES } from "../router/instrument.js";
|
|
17
17
|
import { gateTransitions } from "./transition-gate.js";
|
|
18
|
+
import { payloadInitialTheme } from "./full-payload.js";
|
|
18
19
|
import { resolvedHandleStream } from "../handles/deferred-resolution.js";
|
|
19
20
|
import type { RscPayload, ReactFormState } from "./types.js";
|
|
20
21
|
import {
|
|
@@ -444,7 +445,7 @@ function renderPeResponse<TEnv>(
|
|
|
444
445
|
themeConfig: ctx.router.themeConfig,
|
|
445
446
|
warmupEnabled: ctx.router.warmupEnabled,
|
|
446
447
|
strictMode: ctx.router.strictMode,
|
|
447
|
-
initialTheme: getRequestContext()
|
|
448
|
+
initialTheme: payloadInitialTheme(getRequestContext()),
|
|
448
449
|
},
|
|
449
450
|
};
|
|
450
451
|
|
|
@@ -646,7 +647,7 @@ function renderPeErrorResponse<TEnv>(
|
|
|
646
647
|
themeConfig: ctx.router.themeConfig,
|
|
647
648
|
warmupEnabled: ctx.router.warmupEnabled,
|
|
648
649
|
strictMode: ctx.router.strictMode,
|
|
649
|
-
initialTheme: getRequestContext()
|
|
650
|
+
initialTheme: payloadInitialTheme(getRequestContext()),
|
|
650
651
|
},
|
|
651
652
|
};
|
|
652
653
|
|
|
@@ -155,9 +155,12 @@ function createFlightStage<TEnv>(
|
|
|
155
155
|
if (input.ctx.devDiscoveryEpoch !== undefined && input.payload.metadata) {
|
|
156
156
|
input.payload.metadata.devDiscoveryEpoch = input.ctx.devDiscoveryEpoch;
|
|
157
157
|
}
|
|
158
|
+
// Read once here: onError can fire outside the ALS frame.
|
|
159
|
+
const renderErrors = _getRequestContext()?._renderErrors;
|
|
158
160
|
const stream = input.ctx.renderToReadableStream<RscPayload>(input.payload, {
|
|
159
161
|
temporaryReferences: input.temporaryReferences,
|
|
160
162
|
onError: (error: unknown) => {
|
|
163
|
+
renderErrors?.push(error);
|
|
161
164
|
input.ctx.callOnError(error, "rendering", {
|
|
162
165
|
request: input.request,
|
|
163
166
|
url: input.url,
|
|
@@ -105,7 +105,10 @@ export async function serveResponseRouteWithCache(
|
|
|
105
105
|
// the host-namespacing and search-normalization rules cannot drift.
|
|
106
106
|
let cacheKey = `response:${responseType}:${cacheKeyBase(url.host, url.pathname, url.searchParams, undefined, reqCtx._searchParamsFilter)}`;
|
|
107
107
|
|
|
108
|
-
// Priority 1: route-level key() (full override)
|
|
108
|
+
// Priority 1: route-level key() (full override): the key() results of every
|
|
109
|
+
// cache() enclosing the route, composed like the segment record key
|
|
110
|
+
// (CacheScope.resolveKeyFrom, #970), so a nested cache() never shares an
|
|
111
|
+
// entry across the enclosing partitions. Priority 2: store-level
|
|
109
112
|
// keyGenerator (modifies the default key).
|
|
110
113
|
//
|
|
111
114
|
// A CONFIGURED key()/keyGenerator that THROWS must DEGRADE TO A MISS, not fall
|
|
@@ -114,13 +117,13 @@ export async function serveResponseRouteWithCache(
|
|
|
114
117
|
// would cache PERSONALIZED output under it and serve it cross-user (cache
|
|
115
118
|
// poisoning). Mirrors the segment-cache behavior (cache-scope.ts lookupRoute):
|
|
116
119
|
// a throwing key degrades to a cache miss, never a collision onto the default
|
|
117
|
-
// slot
|
|
118
|
-
//
|
|
120
|
+
// slot, and so does a key() with no ambient request context to run in
|
|
121
|
+
// (resolveKeyFrom rejects). The no-key default path is left untouched (the
|
|
122
|
+
// broad key is correct when no key is configured).
|
|
119
123
|
let keyResolutionFailed = false;
|
|
120
|
-
if (cacheScope.
|
|
124
|
+
if (cacheScope.keyFns.length > 0) {
|
|
121
125
|
try {
|
|
122
|
-
|
|
123
|
-
cacheKey = `response:${customKey}`;
|
|
126
|
+
cacheKey = `response:${await cacheScope.resolveKeyFrom(cacheKey)}`;
|
|
124
127
|
} catch (error) {
|
|
125
128
|
keyResolutionFailed = true;
|
|
126
129
|
reportCacheError(
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
import { RouterError } from "../errors.js";
|
|
10
10
|
import { getRequestContext } from "../server/request-context.js";
|
|
11
|
-
import { contextGet } from "../context-var.js";
|
|
11
|
+
import { contextGet, isNonCacheable } from "../context-var.js";
|
|
12
12
|
import { NOCACHE_SYMBOL } from "../cache/taint.js";
|
|
13
13
|
import { RESPONSE_TYPE_MIME } from "../router/content-negotiation.js";
|
|
14
14
|
import { createCacheScope, resolveCacheTags } from "../cache/cache-scope.js";
|
|
@@ -19,7 +19,10 @@ import {
|
|
|
19
19
|
stripInternalParams,
|
|
20
20
|
} from "../router/handler-context.js";
|
|
21
21
|
import type { MiddlewareFn } from "../router/middleware.js";
|
|
22
|
-
import
|
|
22
|
+
import {
|
|
23
|
+
assertNonCacheableReadAllowed,
|
|
24
|
+
type EntryData,
|
|
25
|
+
} from "../server/context.js";
|
|
23
26
|
import type { HandlerContext } from "./handler-context.js";
|
|
24
27
|
import { createProblemDetails } from "./response-error.js";
|
|
25
28
|
import {
|
|
@@ -85,7 +88,12 @@ export async function handleResponseRoute<TEnv>(
|
|
|
85
88
|
originalUrl: reqCtx.originalUrl,
|
|
86
89
|
pathname: url.pathname,
|
|
87
90
|
reverse: createReverseFunction(handlerCtx.getRequiredRouteMap()),
|
|
88
|
-
get: ((keyOrVar: any) =>
|
|
91
|
+
get: ((keyOrVar: any) => {
|
|
92
|
+
if (isNonCacheable(variables, keyOrVar)) {
|
|
93
|
+
assertNonCacheableReadAllowed(keyOrVar);
|
|
94
|
+
}
|
|
95
|
+
return contextGet(variables, keyOrVar);
|
|
96
|
+
}) as any,
|
|
89
97
|
header: (name: string, value: string) => reqCtx.header(name, value),
|
|
90
98
|
waitUntil: reqCtx.waitUntil.bind(reqCtx),
|
|
91
99
|
executionContext: reqCtx.executionContext,
|