@rangojs/router 0.17.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 +3 -2
- package/dist/types/browser/cookie-name.d.ts +6 -0
- package/dist/types/browser/history-state.d.ts +16 -0
- 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 +98 -14
- 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-snapshot.d.ts +4 -3
- package/dist/types/cache/index.d.ts +1 -0
- package/dist/types/cache/isolate-tag-memo.d.ts +149 -0
- 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/types.d.ts +207 -43
- package/dist/types/cache/vercel/vercel-cache-store.d.ts +111 -13
- package/dist/types/prerender/build-shell-capture.d.ts +11 -4
- package/dist/types/router/instrument.d.ts +8 -0
- package/dist/types/router/middleware-types.d.ts +6 -1
- package/dist/types/router/segment-resolution/loader-cache.d.ts +40 -11
- package/dist/types/router/segment-resolution/loader-snapshot.d.ts +21 -10
- package/dist/types/router/segment-resolution/mask-nested.d.ts +65 -24
- package/dist/types/rsc/full-payload.d.ts +14 -0
- package/dist/types/rsc/handler.d.ts +1 -1
- package/dist/types/rsc/shell-build-manifest.d.ts +8 -0
- package/dist/types/rsc/shell-capture-constants.d.ts +53 -6
- package/dist/types/rsc/shell-capture.d.ts +146 -15
- package/dist/types/rsc/shell-serve.d.ts +140 -17
- package/dist/types/rsc/types.d.ts +7 -0
- package/dist/types/server/context.d.ts +109 -15
- package/dist/types/server/cookie-store.d.ts +21 -0
- package/dist/types/server/request-context.d.ts +159 -33
- package/dist/types/ssr/index.d.ts +9 -0
- package/dist/types/ssr/ssr-root.d.ts +9 -8
- package/dist/types/testing/flight.entry.d.ts +7 -0
- 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/types/handler-context.d.ts +14 -1
- package/dist/types/urls/pattern-types.d.ts +22 -18
- package/dist/types/vite/router-discovery.d.ts +29 -2
- package/dist/vite/index.js +46 -9
- package/package.json +1 -1
- package/skills/breadcrumbs/SKILL.md +17 -7
- package/skills/cache-guide/SKILL.md +123 -51
- package/skills/caching/SKILL.md +253 -23
- package/skills/catalog.json +1 -1
- package/skills/client-urls/SKILL.md +11 -6
- package/skills/cloudflare/SKILL.md +15 -0
- package/skills/comparison/references/framework-comparison.md +44 -32
- package/skills/defer-hydration/SKILL.md +50 -30
- package/skills/deployment-caching/SKILL.md +5 -2
- package/skills/document-cache/SKILL.md +8 -2
- package/skills/handler-use/SKILL.md +2 -0
- package/skills/hooks/handle-and-actions.md +3 -1
- package/skills/hooks/state.md +3 -1
- package/skills/loader/SKILL.md +161 -39
- package/skills/middleware/SKILL.md +16 -9
- package/skills/migrate-nextjs/SKILL.md +67 -36
- package/skills/migrate-react-router/SKILL.md +2 -1
- package/skills/migrate-react-router/component-migration.md +3 -1
- package/skills/migrate-react-router/data-and-actions.md +3 -1
- package/skills/migrate-react-router/route-mapping.md +7 -4
- package/skills/observability/SKILL.md +64 -0
- package/skills/parallel/SKILL.md +13 -8
- package/skills/ppr/SKILL.md +655 -363
- package/skills/prerender/SKILL.md +27 -14
- package/skills/rango/SKILL.md +52 -33
- package/skills/route/SKILL.md +12 -7
- package/skills/router-setup/SKILL.md +4 -2
- package/skills/scripts/SKILL.md +8 -1
- package/skills/server-actions/SKILL.md +11 -0
- package/skills/shell-manifest/SKILL.md +21 -12
- package/skills/testing/SKILL.md +25 -21
- package/skills/testing/cache-prerender.md +15 -14
- package/skills/testing/loader.md +18 -1
- package/skills/testing/serve-shell-request.md +188 -0
- package/skills/theme/SKILL.md +52 -4
- package/skills/typesafety/env-and-bindings.md +10 -2
- package/skills/use-cache/SKILL.md +39 -16
- package/skills/vercel/SKILL.md +14 -2
- package/skills/view-transitions/SKILL.md +1 -1
- package/src/browser/cookie-name.ts +23 -0
- package/src/browser/history-state.ts +23 -0
- package/src/browser/rsc-router.tsx +5 -0
- package/src/cache/cache-key-utils.ts +22 -2
- package/src/cache/cache-policy.ts +22 -0
- package/src/cache/cache-runtime.ts +34 -7
- package/src/cache/cache-scope.ts +345 -33
- 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/handle-snapshot.ts +4 -3
- package/src/cache/index.ts +2 -0
- package/src/cache/isolate-tag-memo.ts +308 -0
- package/src/cache/shell-memo.ts +341 -0
- package/src/cache/shell-snapshot.ts +217 -27
- package/src/cache/tag-invalidation.ts +104 -19
- package/src/cache/types.ts +211 -43
- package/src/cache/vercel/vercel-cache-store.ts +545 -61
- package/src/prerender/build-shell-capture.ts +65 -11
- package/src/route-definition/dsl-helpers.ts +4 -3
- package/src/router/handler-context.ts +38 -4
- package/src/router/instrument.ts +54 -2
- package/src/router/intercept-resolution.ts +19 -7
- package/src/router/loader-resolution.ts +63 -32
- package/src/router/match-api.ts +28 -9
- package/src/router/match-handlers.ts +5 -0
- package/src/router/match-middleware/cache-lookup.ts +17 -0
- package/src/router/match-middleware/cache-store.ts +31 -11
- package/src/router/middleware-types.ts +6 -1
- package/src/router/middleware.ts +23 -4
- package/src/router/prerender-match.ts +6 -0
- package/src/router/segment-resolution/fresh.ts +18 -9
- package/src/router/segment-resolution/helpers.ts +4 -2
- package/src/router/segment-resolution/loader-cache.ts +227 -56
- package/src/router/segment-resolution/loader-snapshot.ts +203 -51
- package/src/router/segment-resolution/mask-nested.ts +136 -42
- package/src/router/segment-resolution/revalidation.ts +27 -10
- 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/response-cache-serve.ts +9 -6
- package/src/rsc/rsc-rendering.ts +601 -181
- package/src/rsc/shell-build-manifest.ts +27 -9
- package/src/rsc/shell-capture-constants.ts +60 -6
- package/src/rsc/shell-capture.ts +1001 -250
- package/src/rsc/shell-serve.ts +316 -34
- package/src/rsc/types.ts +7 -0
- package/src/server/context.ts +219 -28
- package/src/server/cookie-store.ts +87 -62
- package/src/server/request-context.ts +263 -38
- package/src/ssr/index.tsx +96 -37
- package/src/ssr/ssr-root.tsx +9 -8
- package/src/testing/flight.entry.ts +14 -0
- package/src/testing/run-loader.ts +63 -5
- package/src/testing/serve-shell-request.ts +378 -0
- package/src/testing/shell-status.ts +34 -12
- package/src/theme/ThemeProvider.tsx +7 -6
- package/src/types/handler-context.ts +14 -1
- package/src/urls/pattern-types.ts +22 -18
- package/src/vite/discovery/shell-prerender-phase.ts +9 -0
- package/src/vite/router-discovery.ts +14 -4
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
|
|
|
@@ -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(
|