@rangojs/router 0.18.0 → 0.19.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/types/browser/event-controller.d.ts +3 -3
- package/dist/types/browser/history-state.d.ts +2 -0
- package/dist/types/browser/navigation-transaction.d.ts +20 -2
- package/dist/types/browser/partial-update.d.ts +16 -1
- package/dist/types/browser/prefetch/cache.d.ts +6 -6
- package/dist/types/browser/react/Link.d.ts +19 -9
- package/dist/types/browser/react/context.d.ts +2 -2
- package/dist/types/browser/react/location-state-shared.d.ts +95 -56
- package/dist/types/browser/react/location-state.d.ts +1 -1
- package/dist/types/browser/transition-when.d.ts +80 -0
- package/dist/types/browser/types.d.ts +104 -9
- package/dist/types/build/generate-manifest.d.ts +8 -0
- package/dist/types/cache/background-task.d.ts +24 -2
- package/dist/types/cache/cache-exec-scope.d.ts +31 -0
- package/dist/types/cache/cache-key-utils.d.ts +44 -13
- package/dist/types/cache/cache-policy.d.ts +1 -1
- package/dist/types/cache/cache-runtime.d.ts +7 -0
- package/dist/types/cache/cache-scope.d.ts +117 -35
- package/dist/types/cache/cache-tag.d.ts +24 -4
- package/dist/types/cache/cf/cf-cache-store.d.ts +55 -44
- package/dist/types/cache/cf/cf-shell-frame.d.ts +1 -1
- package/dist/types/cache/cf/cf-tag-marker-memo.d.ts +0 -15
- package/dist/types/cache/document-cache.d.ts +10 -0
- package/dist/types/cache/handle-snapshot.d.ts +40 -8
- package/dist/types/cache/invalidation-order.d.ts +23 -0
- package/dist/types/cache/request-tag-mask.d.ts +54 -0
- package/dist/types/cache/shell-snapshot.d.ts +88 -141
- package/dist/types/cache/tag-invalidation.d.ts +38 -14
- package/dist/types/cache/types.d.ts +68 -61
- package/dist/types/cache/vercel/vercel-cache-store.d.ts +23 -16
- package/dist/types/client-urls/navigation.d.ts +28 -2
- package/dist/types/client-urls/server-projection.d.ts +5 -2
- package/dist/types/client-urls/types.d.ts +5 -5
- package/dist/types/client.d.ts +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.rsc.d.ts +1 -1
- package/dist/types/route-definition/helpers-types.d.ts +11 -11
- package/dist/types/route-name.d.ts +7 -0
- package/dist/types/router/error-handling.d.ts +1 -1
- package/dist/types/router/intercept-resolution.d.ts +2 -0
- package/dist/types/router/match-context.d.ts +5 -0
- package/dist/types/router/match-middleware/background-revalidation.d.ts +0 -4
- package/dist/types/router/router-options.d.ts +4 -1
- package/dist/types/router/segment-resolution/loader-cache.d.ts +18 -1
- package/dist/types/router/segment-resolution/loader-mask.d.ts +3 -4
- package/dist/types/router/segment-resolution/loader-snapshot.d.ts +14 -40
- package/dist/types/router/segment-resolution/mask-nested.d.ts +11 -3
- package/dist/types/router/segment-resolution/view-transition-default.d.ts +7 -5
- package/dist/types/router/transition-when.d.ts +24 -10
- package/dist/types/rsc/attach-transition-when.d.ts +18 -0
- package/dist/types/rsc/full-payload.d.ts +14 -7
- package/dist/types/rsc/response-cache-serve.d.ts +15 -12
- package/dist/types/rsc/shell-build-manifest.d.ts +4 -3
- package/dist/types/rsc/shell-capture-constants.d.ts +77 -20
- package/dist/types/rsc/shell-capture.d.ts +78 -81
- package/dist/types/rsc/shell-serve.d.ts +19 -48
- package/dist/types/rsc/types.d.ts +2 -0
- package/dist/types/segment-system.d.ts +7 -0
- package/dist/types/server/context.d.ts +89 -61
- package/dist/types/server/cookie-store.d.ts +30 -18
- package/dist/types/server/handle-store.d.ts +52 -1
- package/dist/types/server/request-context.d.ts +66 -45
- package/dist/types/server/request-headers.d.ts +44 -0
- package/dist/types/server.d.ts +1 -0
- package/dist/types/testing/e2e/index.d.ts +1 -1
- package/dist/types/testing/index.d.ts +3 -2
- package/dist/types/testing/internal/action-id.d.ts +7 -0
- package/dist/types/testing/location-state-key.d.ts +24 -0
- package/dist/types/testing/render-route.d.ts +17 -1
- package/dist/types/testing/run-transition-when.d.ts +44 -69
- package/dist/types/testing/serve-shell-request.d.ts +7 -6
- package/dist/types/testing/shell-status.d.ts +34 -22
- package/dist/types/transition-when-ref.d.ts +79 -0
- package/dist/types/types/cache-types.d.ts +15 -3
- package/dist/types/types/index.d.ts +1 -1
- package/dist/types/types/segments.d.ts +86 -71
- package/dist/types/urls/path-helper-types.d.ts +3 -4
- package/dist/types/urls/pattern-types.d.ts +3 -4
- package/dist/types/vite/plugins/transition-when-hoist.d.ts +45 -0
- package/dist/vite/index.js +960 -97
- package/package.json +1 -1
- package/skills/cache-guide/SKILL.md +76 -49
- package/skills/caching/SKILL.md +167 -69
- package/skills/client-urls/SKILL.md +1 -1
- package/skills/comparison/references/framework-comparison.md +8 -5
- package/skills/document-cache/SKILL.md +24 -0
- package/skills/hooks/SKILL.md +3 -1
- package/skills/hooks/navigation.md +23 -2
- package/skills/hooks/state.md +98 -6
- package/skills/intercept/SKILL.md +29 -12
- package/skills/loader/SKILL.md +52 -21
- package/skills/middleware/SKILL.md +18 -0
- package/skills/migrate-nextjs/SKILL.md +3 -3
- package/skills/observability/SKILL.md +6 -5
- package/skills/parallel/SKILL.md +1 -1
- package/skills/ppr/SKILL.md +129 -77
- package/skills/prerender/SKILL.md +3 -3
- package/skills/rango/SKILL.md +25 -6
- package/skills/route/SKILL.md +2 -0
- package/skills/testing/SKILL.md +27 -25
- package/skills/testing/cache-prerender.md +9 -9
- package/skills/testing/client-components.md +45 -3
- package/skills/testing/loader.md +3 -2
- package/skills/testing/middleware.md +1 -0
- package/skills/testing/predicates.md +49 -49
- package/skills/testing/render-handler.md +1 -0
- package/skills/testing/serve-shell-request.md +14 -0
- package/skills/testing/server-actions.md +9 -3
- package/skills/theme/SKILL.md +8 -4
- package/skills/typesafety/env-and-bindings.md +8 -0
- package/skills/use-cache/SKILL.md +64 -19
- package/skills/view-transitions/SKILL.md +150 -29
- package/src/__augment-tests__/augmented.check.ts +23 -0
- package/src/browser/event-controller.ts +4 -4
- package/src/browser/history-state.ts +52 -1
- package/src/browser/link-interceptor.ts +4 -0
- package/src/browser/navigation-bridge.ts +77 -18
- package/src/browser/navigation-client.ts +4 -3
- package/src/browser/navigation-store.ts +43 -1
- package/src/browser/navigation-transaction.ts +31 -11
- package/src/browser/partial-update.ts +146 -35
- package/src/browser/prefetch/cache.ts +6 -6
- package/src/browser/prefetch/fetch.ts +2 -2
- package/src/browser/react/Link.tsx +38 -33
- package/src/browser/react/NavigationProvider.tsx +2 -2
- package/src/browser/react/context.ts +2 -2
- package/src/browser/react/location-state-shared.ts +241 -49
- package/src/browser/react/location-state.ts +5 -2
- package/src/browser/rsc-router.tsx +4 -0
- package/src/browser/server-action-bridge.ts +84 -15
- package/src/browser/transition-when.ts +205 -0
- package/src/browser/types.ts +124 -10
- package/src/build/generate-manifest.ts +77 -1
- package/src/cache/background-task.ts +55 -2
- package/src/cache/cache-exec-scope.ts +48 -1
- package/src/cache/cache-key-utils.ts +56 -16
- package/src/cache/cache-policy.ts +9 -4
- package/src/cache/cache-runtime.ts +197 -144
- package/src/cache/cache-scope.ts +304 -112
- package/src/cache/cache-tag.ts +105 -13
- package/src/cache/cf/cf-cache-store.ts +152 -76
- package/src/cache/cf/cf-shell-frame.ts +2 -2
- package/src/cache/cf/cf-tag-marker-memo.ts +11 -100
- package/src/cache/document-cache.ts +53 -7
- package/src/cache/handle-snapshot.ts +52 -9
- package/src/cache/invalidation-order.ts +84 -0
- package/src/cache/request-tag-mask.ts +147 -0
- package/src/cache/shell-snapshot.ts +130 -348
- package/src/cache/tag-invalidation.ts +57 -51
- package/src/cache/types.ts +71 -67
- package/src/cache/vercel/vercel-cache-store.ts +61 -58
- package/src/client-urls/client-root.tsx +8 -4
- package/src/client-urls/client-urls.ts +8 -6
- package/src/client-urls/navigation.ts +55 -4
- package/src/client-urls/server-projection.ts +31 -10
- package/src/client-urls/types.ts +12 -5
- package/src/client.tsx +2 -0
- package/src/host/cookie-handler.ts +2 -1
- package/src/index.rsc.ts +3 -0
- package/src/index.ts +3 -0
- package/src/loader-redirect.tsx +7 -3
- package/src/prerender/build-shell-capture.ts +155 -146
- package/src/route-definition/dsl-helpers.ts +2 -0
- package/src/route-definition/helpers-types.ts +11 -11
- package/src/route-name.ts +12 -0
- package/src/router/content-negotiation.ts +4 -1
- package/src/router/error-handling.ts +5 -2
- package/src/router/handler-context.ts +10 -7
- package/src/router/intercept-resolution.ts +11 -1
- package/src/router/loader-resolution.ts +28 -3
- package/src/router/logging.ts +5 -3
- package/src/router/match-api.ts +62 -34
- package/src/router/match-context.ts +5 -0
- package/src/router/match-handlers.ts +9 -29
- package/src/router/match-middleware/background-revalidation.ts +3 -5
- package/src/router/match-middleware/cache-lookup.ts +35 -19
- package/src/router/match-middleware/cache-store.ts +15 -9
- package/src/router/match-result.ts +1 -0
- package/src/router/middleware.ts +2 -5
- package/src/router/navigation-snapshot.ts +6 -5
- package/src/router/prerender-match.ts +4 -0
- package/src/router/request-classification.ts +7 -4
- package/src/router/router-options.ts +4 -1
- package/src/router/segment-resolution/fresh.ts +0 -4
- package/src/router/segment-resolution/loader-cache.ts +150 -25
- package/src/router/segment-resolution/loader-mask.ts +3 -4
- package/src/router/segment-resolution/loader-snapshot.ts +15 -78
- package/src/router/segment-resolution/mask-nested.ts +47 -22
- package/src/router/segment-resolution/revalidation.ts +0 -3
- package/src/router/segment-resolution/view-transition-default.ts +6 -21
- package/src/router/telemetry.ts +6 -3
- package/src/router/transition-when.ts +34 -52
- package/src/router.ts +2 -1
- package/src/rsc/attach-transition-when.ts +47 -0
- package/src/rsc/full-payload.ts +30 -10
- package/src/rsc/handler.ts +12 -10
- package/src/rsc/loader-fetch.ts +2 -1
- package/src/rsc/manifest-init.ts +4 -0
- package/src/rsc/origin-guard.ts +8 -5
- package/src/rsc/progressive-enhancement.ts +7 -30
- package/src/rsc/response-cache-serve.ts +68 -80
- package/src/rsc/response-route-handler.ts +2 -2
- package/src/rsc/rsc-rendering.ts +206 -252
- package/src/rsc/server-action.ts +8 -20
- package/src/rsc/shell-build-manifest.ts +22 -20
- package/src/rsc/shell-capture-constants.ts +136 -20
- package/src/rsc/shell-capture.ts +352 -589
- package/src/rsc/shell-serve.ts +73 -109
- package/src/rsc/ssr-setup.ts +3 -2
- package/src/rsc/types.ts +2 -0
- package/src/segment-system.tsx +40 -7
- package/src/server/context.ts +189 -124
- package/src/server/cookie-store.ts +153 -127
- package/src/server/handle-store.ts +245 -27
- package/src/server/request-context.ts +123 -84
- package/src/server/request-headers.ts +134 -0
- package/src/server.ts +4 -0
- package/src/testing/dispatch.ts +4 -7
- package/src/testing/e2e/index.ts +1 -0
- package/src/testing/index.ts +5 -0
- package/src/testing/internal/action-id.ts +25 -0
- package/src/testing/internal/context.ts +1 -1
- package/src/testing/location-state-key.ts +45 -0
- package/src/testing/render-handler.ts +1 -1
- package/src/testing/render-route.tsx +109 -16
- package/src/testing/run-client-revalidate.ts +3 -19
- package/src/testing/run-loader.ts +5 -1
- package/src/testing/run-transition-when.ts +109 -172
- package/src/testing/serve-shell-request.ts +10 -7
- package/src/testing/shell-status.ts +60 -56
- package/src/transition-when-ref.ts +220 -0
- package/src/types/cache-types.ts +15 -3
- package/src/types/index.ts +3 -0
- package/src/types/segments.ts +94 -91
- package/src/urls/path-helper-types.ts +3 -4
- package/src/urls/pattern-types.ts +3 -4
- package/src/vite/discovery/discover-routers.ts +3 -0
- package/src/vite/discovery/shell-prerender-phase.ts +0 -2
- package/src/vite/discovery/virtual-module-codegen.ts +16 -6
- package/src/vite/plugins/transition-when-hoist.ts +1064 -0
- package/src/vite/rango.ts +2 -0
- package/src/vite/router-discovery.ts +75 -5
- package/dist/types/rsc/transition-gate.d.ts +0 -23
- package/src/rsc/transition-gate.ts +0 -86
package/src/router/logging.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { requestHeaders } from "../server/request-headers.js";
|
|
1
2
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
3
|
import { INTERNAL_RANGO_DEBUG } from "../internal-debug.js";
|
|
3
4
|
|
|
@@ -61,10 +62,11 @@ function nextId(prefix: string, counter: number): string {
|
|
|
61
62
|
}
|
|
62
63
|
|
|
63
64
|
function getHeaderRequestId(request: Request): string | null {
|
|
65
|
+
const headers = requestHeaders(request);
|
|
64
66
|
const candidate =
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
67
|
+
headers.get("x-rsc-router-request-id") ??
|
|
68
|
+
headers.get("x-request-id") ??
|
|
69
|
+
headers.get("cf-ray");
|
|
68
70
|
if (!candidate) return null;
|
|
69
71
|
const trimmed = candidate.trim();
|
|
70
72
|
return trimmed.length > 0 ? trimmed : null;
|
package/src/router/match-api.ts
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
|
+
import { requestHeaders } from "../server/request-headers.js";
|
|
1
2
|
import {
|
|
2
3
|
CacheScope,
|
|
3
4
|
createCacheScope,
|
|
4
5
|
resolveShellImplicitCacheScope,
|
|
5
6
|
} from "../cache/cache-scope.js";
|
|
6
7
|
import { armLoaderTagSets, armRecordTagOwners } from "../cache/cache-tag.js";
|
|
7
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
bindsLoaderCache,
|
|
10
|
+
routeLoaderLanes,
|
|
11
|
+
} from "./segment-resolution/loader-cache.js";
|
|
8
12
|
import { RouteNotFoundError } from "../errors";
|
|
9
13
|
import {
|
|
10
14
|
createErrorInfo,
|
|
@@ -37,8 +41,7 @@ import {
|
|
|
37
41
|
_getRequestContext,
|
|
38
42
|
setRequestContextPrevRouteKey,
|
|
39
43
|
} from "../server/request-context.js";
|
|
40
|
-
import {
|
|
41
|
-
import type { DefaultRouteName } from "../types/global-namespace.js";
|
|
44
|
+
import { publicRouteName } from "../route-name.js";
|
|
42
45
|
import { debugLog, debugWarn } from "./logging.js";
|
|
43
46
|
import {
|
|
44
47
|
resolveRoute,
|
|
@@ -62,7 +65,7 @@ export async function createMatchContextForFull<TEnv>(
|
|
|
62
65
|
|
|
63
66
|
const metricsStore = deps.getMetricsStore();
|
|
64
67
|
|
|
65
|
-
const isHmr = !!request.
|
|
68
|
+
const isHmr = !!requestHeaders(request).get("X-RSC-HMR");
|
|
66
69
|
// HMR: clear the manifest cache so stale handler references are discarded.
|
|
67
70
|
if (isHmr) {
|
|
68
71
|
clearManifestCache();
|
|
@@ -165,6 +168,12 @@ export async function createMatchContextForFull<TEnv>(
|
|
|
165
168
|
armRecordTagOwners();
|
|
166
169
|
}
|
|
167
170
|
if (bindsLoaderCache(snapshot.entries)) armLoaderTagSets();
|
|
171
|
+
// A shell capture credits a push under a live-lane loader's body to that
|
|
172
|
+
// loader (shell-capture.ts deriveShellCaptureContext). The lanes are set
|
|
173
|
+
// before any loader runs: a bake-lane loader can start a later one.
|
|
174
|
+
if (reqCtx?._shellCaptureRun) {
|
|
175
|
+
reqCtx._shellCaptureLoaderLanes = routeLoaderLanes(snapshot.entries);
|
|
176
|
+
}
|
|
168
177
|
|
|
169
178
|
return {
|
|
170
179
|
request,
|
|
@@ -188,18 +197,20 @@ export async function createMatchContextForFull<TEnv>(
|
|
|
188
197
|
metricsStore,
|
|
189
198
|
Store,
|
|
190
199
|
interceptContextMatch: null,
|
|
191
|
-
interceptSelectorContext: {
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
200
|
+
interceptSelectorContext: (() => {
|
|
201
|
+
const here = {
|
|
202
|
+
url: cleanUrl,
|
|
203
|
+
params: matched.params,
|
|
204
|
+
routeName: publicRouteName(matched.routeKey),
|
|
205
|
+
};
|
|
206
|
+
return {
|
|
207
|
+
from: here,
|
|
208
|
+
to: here,
|
|
209
|
+
request,
|
|
210
|
+
env,
|
|
211
|
+
segments: { path: [], ids: [] },
|
|
212
|
+
};
|
|
213
|
+
})(),
|
|
203
214
|
isSameRouteNavigation: false,
|
|
204
215
|
interceptResult: null,
|
|
205
216
|
cacheScope,
|
|
@@ -231,7 +242,7 @@ export async function createMatchContextForPartial<TEnv>(
|
|
|
231
242
|
|
|
232
243
|
const metricsStore = deps.getMetricsStore();
|
|
233
244
|
|
|
234
|
-
const isHmr = !!request.
|
|
245
|
+
const isHmr = !!requestHeaders(request).get("X-RSC-HMR");
|
|
235
246
|
|
|
236
247
|
// HMR: clear manifest cache so stale handler references are discarded
|
|
237
248
|
if (isHmr) {
|
|
@@ -349,31 +360,27 @@ export async function createMatchContextForPartial<TEnv>(
|
|
|
349
360
|
});
|
|
350
361
|
}
|
|
351
362
|
|
|
352
|
-
setRequestContextPrevRouteKey(
|
|
353
|
-
nav.effectiveFromMatch?.routeKey,
|
|
354
|
-
nav.effectiveFromUrl,
|
|
355
|
-
nav.effectiveFromMatch?.params ?? nav.prevParams,
|
|
356
|
-
);
|
|
363
|
+
setRequestContextPrevRouteKey(nav.effectiveFromMatch?.routeKey);
|
|
357
364
|
|
|
358
365
|
const interceptSelectorContext: InterceptSelectorContext = {
|
|
359
|
-
from
|
|
360
|
-
|
|
361
|
-
|
|
366
|
+
// The source's params come from matching its URL (the intercept source
|
|
367
|
+
// while one is open), like its route name.
|
|
368
|
+
from: {
|
|
369
|
+
url: nav.effectiveFromUrl,
|
|
370
|
+
params: nav.effectiveFromMatch?.params ?? {},
|
|
371
|
+
routeName: publicRouteName(nav.effectiveFromMatch?.routeKey),
|
|
372
|
+
},
|
|
373
|
+
to: {
|
|
374
|
+
url: cleanUrl,
|
|
375
|
+
params: matched.params,
|
|
376
|
+
routeName: publicRouteName(matched.routeKey),
|
|
377
|
+
},
|
|
362
378
|
request,
|
|
363
379
|
env,
|
|
364
380
|
segments: {
|
|
365
381
|
path: nav.effectiveFromUrl.pathname.split("/").filter(Boolean),
|
|
366
382
|
ids: nav.filteredSegmentIds,
|
|
367
383
|
},
|
|
368
|
-
fromRouteName:
|
|
369
|
-
nav.effectiveFromMatch?.routeKey &&
|
|
370
|
-
!isAutoGeneratedRouteName(nav.effectiveFromMatch.routeKey)
|
|
371
|
-
? (nav.effectiveFromMatch.routeKey as DefaultRouteName)
|
|
372
|
-
: undefined,
|
|
373
|
-
toRouteName:
|
|
374
|
-
matched.routeKey && !isAutoGeneratedRouteName(matched.routeKey)
|
|
375
|
-
? (matched.routeKey as DefaultRouteName)
|
|
376
|
-
: undefined,
|
|
377
384
|
};
|
|
378
385
|
const isAction = !!actionContext;
|
|
379
386
|
|
|
@@ -414,6 +421,26 @@ export async function createMatchContextForPartial<TEnv>(
|
|
|
414
421
|
clientSegmentSet.delete(snapshot.manifestEntry.shortCode);
|
|
415
422
|
}
|
|
416
423
|
|
|
424
|
+
// Whether an intercept targets this route at all: the same walk as above
|
|
425
|
+
// with isAction=true, which skips when(). If one does, the response depends
|
|
426
|
+
// on the source even when none applied (a when() that rejected it, a
|
|
427
|
+
// same-route navigation), so it must not share the source-agnostic prefetch
|
|
428
|
+
// slot (#1007). The walk is over the TARGET's chain, so a route no
|
|
429
|
+
// intercept targets never depends on the source this way.
|
|
430
|
+
const targetsIntercept = (routeKey: string): boolean =>
|
|
431
|
+
findInterceptForRoute(
|
|
432
|
+
routeKey,
|
|
433
|
+
snapshot.manifestEntry.parent,
|
|
434
|
+
null,
|
|
435
|
+
true,
|
|
436
|
+
) !== null;
|
|
437
|
+
const interceptTargeted =
|
|
438
|
+
!!interceptResult ||
|
|
439
|
+
(!skipInterceptForAction &&
|
|
440
|
+
(targetsIntercept(matched.routeKey) ||
|
|
441
|
+
(snapshot.localRouteName !== matched.routeKey &&
|
|
442
|
+
targetsIntercept(snapshot.localRouteName))));
|
|
443
|
+
|
|
417
444
|
const isIntercept = !!interceptResult;
|
|
418
445
|
// A normal-route navigation may replay a PPR shell's canonical segment
|
|
419
446
|
// snapshot. Intercepts remain source-dependent and always use their normal
|
|
@@ -451,6 +478,7 @@ export async function createMatchContextForPartial<TEnv>(
|
|
|
451
478
|
interceptSelectorContext,
|
|
452
479
|
isSameRouteNavigation: nav.isSameRouteNavigation,
|
|
453
480
|
interceptResult,
|
|
481
|
+
interceptTargeted,
|
|
454
482
|
cacheScope,
|
|
455
483
|
isIntercept,
|
|
456
484
|
actionContext,
|
|
@@ -176,6 +176,11 @@ export interface MatchContext<TEnv = any> {
|
|
|
176
176
|
interceptSelectorContext: InterceptSelectorContext;
|
|
177
177
|
isSameRouteNavigation: boolean;
|
|
178
178
|
interceptResult: InterceptResult | null;
|
|
179
|
+
/**
|
|
180
|
+
* An intercept targets this route, matched or not (a same-route navigation
|
|
181
|
+
* skips it), so the response depends on the source. Partial matches only.
|
|
182
|
+
*/
|
|
183
|
+
interceptTargeted?: boolean;
|
|
179
184
|
|
|
180
185
|
// Cache
|
|
181
186
|
cacheScope: CacheScope | null;
|
|
@@ -9,7 +9,6 @@ import type {
|
|
|
9
9
|
NotFoundBoundaryHandler,
|
|
10
10
|
} from "../types";
|
|
11
11
|
import {
|
|
12
|
-
isPprEntry,
|
|
13
12
|
type EntryData,
|
|
14
13
|
type InterceptEntry,
|
|
15
14
|
type InterceptSelectorContext,
|
|
@@ -48,7 +47,7 @@ import {
|
|
|
48
47
|
} from "./telemetry.js";
|
|
49
48
|
import { _getRequestContext } from "../server/request-context.js";
|
|
50
49
|
import { ShellRecordUnavailableError } from "../cache/shell-snapshot.js";
|
|
51
|
-
import {
|
|
50
|
+
import { recordTransitionWhenRefs } from "./transition-when.js";
|
|
52
51
|
|
|
53
52
|
/**
|
|
54
53
|
* Per-call telemetry lifecycle emitter for match()/matchPartial(). Each method
|
|
@@ -235,33 +234,14 @@ export function createMatchHandlers<TEnv = any>(
|
|
|
235
234
|
if (reqCtx) reqCtx._cacheSignal = segments;
|
|
236
235
|
};
|
|
237
236
|
|
|
238
|
-
const
|
|
239
|
-
ctx: MatchContext<TEnv>,
|
|
240
|
-
isPartial: boolean,
|
|
241
|
-
): void => {
|
|
237
|
+
const recordTransitionWhenRefsForMatch = (ctx: MatchContext<TEnv>): void => {
|
|
242
238
|
const reqCtx = _getRequestContext();
|
|
243
239
|
if (!reqCtx) return;
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
reqCtx,
|
|
250
|
-
{
|
|
251
|
-
params: ctx.matched.params,
|
|
252
|
-
routeName: ctx.interceptSelectorContext.toRouteName,
|
|
253
|
-
},
|
|
254
|
-
(error, segmentId) =>
|
|
255
|
-
callOnError(error, "rendering", {
|
|
256
|
-
request: ctx.request,
|
|
257
|
-
url: ctx.url,
|
|
258
|
-
env: ctx.env,
|
|
259
|
-
params: ctx.matched.params,
|
|
260
|
-
segmentId,
|
|
261
|
-
isPartial,
|
|
262
|
-
handledByBoundary: false,
|
|
263
|
-
}),
|
|
264
|
-
);
|
|
240
|
+
const entry = ctx.manifestEntry;
|
|
241
|
+
recordTransitionWhenRefs(ctx.entries, reqCtx, {
|
|
242
|
+
routeName: ctx.routeKey,
|
|
243
|
+
pattern: entry?.type === "route" ? entry.pattern : undefined,
|
|
244
|
+
});
|
|
265
245
|
};
|
|
266
246
|
|
|
267
247
|
async function createMatchContextForFull(
|
|
@@ -350,7 +330,7 @@ export function createMatchHandlers<TEnv = any>(
|
|
|
350
330
|
}
|
|
351
331
|
|
|
352
332
|
const ctx = result as MatchContext<TEnv>;
|
|
353
|
-
|
|
333
|
+
recordTransitionWhenRefsForMatch(ctx);
|
|
354
334
|
|
|
355
335
|
try {
|
|
356
336
|
const state = createPipelineState();
|
|
@@ -466,7 +446,7 @@ export function createMatchHandlers<TEnv = any>(
|
|
|
466
446
|
emitter.end(0, false);
|
|
467
447
|
return null;
|
|
468
448
|
}
|
|
469
|
-
|
|
449
|
+
recordTransitionWhenRefsForMatch(ctx);
|
|
470
450
|
|
|
471
451
|
if (isRouterDebugEnabled()) {
|
|
472
452
|
startRevalidationTrace({
|
|
@@ -107,6 +107,7 @@ import type { GeneratorMiddleware } from "./cache-lookup.js";
|
|
|
107
107
|
import { debugLog, debugWarn, getOrCreateRequestId } from "../logging.js";
|
|
108
108
|
import { INTERNAL_RANGO_DEBUG } from "../../internal-debug.js";
|
|
109
109
|
import { getContext } from "../../server/context.js";
|
|
110
|
+
import { executionStart } from "../../cache/tag-invalidation.js";
|
|
110
111
|
import {
|
|
111
112
|
createRequestContext,
|
|
112
113
|
runWithRequestContext,
|
|
@@ -134,10 +135,6 @@ import {
|
|
|
134
135
|
* cache-scope.ts), so a swap sent live pushes into this render.
|
|
135
136
|
* setupLoaderAccess binds the store at setup, so it runs inside the
|
|
136
137
|
* derived context too.
|
|
137
|
-
* - _transitionWhen: fresh resolution appends transition({ when })
|
|
138
|
-
* predicates; the foreground's gateTransitions reads the array after the
|
|
139
|
-
* match, and a stale HIT (which replays the stored transition) must not
|
|
140
|
-
* evaluate this render's predicates.
|
|
141
138
|
* - _metricsStore: undefined, and the DSL store below has `metrics` unset
|
|
142
139
|
* (track() reads that one), so nothing lands on the foreground's perf
|
|
143
140
|
* timeline. ctx.Store.run closes over ctx.Store, so the derived store
|
|
@@ -156,6 +153,7 @@ export async function rerenderAndCacheRoute<TEnv>(
|
|
|
156
153
|
cacheScope: CacheScope,
|
|
157
154
|
routerCtx: RouterContext<TEnv>,
|
|
158
155
|
): Promise<number> {
|
|
156
|
+
const start = executionStart();
|
|
159
157
|
const handleStore = routerCtx.createHandleStore();
|
|
160
158
|
// Response writes land in a throwaway context nothing merges or drains. Its
|
|
161
159
|
// mutators are closures over its own stub, and they keep the same guards.
|
|
@@ -172,7 +170,6 @@ export async function rerenderAndCacheRoute<TEnv>(
|
|
|
172
170
|
}),
|
|
173
171
|
{
|
|
174
172
|
_handleStore: handleStore,
|
|
175
|
-
_transitionWhen: [],
|
|
176
173
|
_metricsStore: undefined,
|
|
177
174
|
_onResponseCallbacks: [],
|
|
178
175
|
header: sink.header,
|
|
@@ -253,6 +250,7 @@ export async function rerenderAndCacheRoute<TEnv>(
|
|
|
253
250
|
ctx.matched.params,
|
|
254
251
|
segments,
|
|
255
252
|
ctx.isIntercept,
|
|
253
|
+
start,
|
|
256
254
|
);
|
|
257
255
|
return segments.length;
|
|
258
256
|
});
|
|
@@ -92,12 +92,14 @@
|
|
|
92
92
|
* - Action context (if POST)
|
|
93
93
|
*/
|
|
94
94
|
import type { InternalHandlerContext, ResolvedSegment } from "../../types.js";
|
|
95
|
+
import type { OwnedPushDelivery } from "../../cache/handle-snapshot.js";
|
|
95
96
|
import type { EntryData } from "../../server/context.js";
|
|
96
97
|
import type { MatchContext, MatchPipelineState } from "../match-context.js";
|
|
97
98
|
import { getRouterContext, type RouterContext } from "../router-context.js";
|
|
98
99
|
import { observeEvent } from "../instrument.js";
|
|
99
100
|
import { pushRevalidationTraceEntry, isTraceActive } from "../logging.js";
|
|
100
101
|
import { treeHasStreaming } from "./segment-resolution.js";
|
|
102
|
+
import { liveLaneLoaderIds } from "../segment-resolution/loader-cache.js";
|
|
101
103
|
import type { PrerenderStore, PrerenderEntry } from "../../prerender/store.js";
|
|
102
104
|
import {
|
|
103
105
|
_getRequestContext,
|
|
@@ -297,8 +299,7 @@ async function* yieldFromStore<TEnv>(
|
|
|
297
299
|
!paramsChanged &&
|
|
298
300
|
ctx.clientSegmentSet.has(segment.id)
|
|
299
301
|
) {
|
|
300
|
-
segment
|
|
301
|
-
segment.loading = undefined;
|
|
302
|
+
keepClientSegment(segment);
|
|
302
303
|
}
|
|
303
304
|
yield segment;
|
|
304
305
|
}
|
|
@@ -405,6 +406,21 @@ async function* tryPrerenderLookup<TEnv>(
|
|
|
405
406
|
return true;
|
|
406
407
|
}
|
|
407
408
|
|
|
409
|
+
/**
|
|
410
|
+
* Keep the client's copy of a stored (runtime cache, prerender, or shell
|
|
411
|
+
* replay) segment this navigation does not re-render. collectMatchResult
|
|
412
|
+
* (match-result.ts) omits a null-component segment the client holds, as the
|
|
413
|
+
* live partial path omits a segment whose revalidation said no
|
|
414
|
+
* (segment-resolution/revalidation.ts).
|
|
415
|
+
*
|
|
416
|
+
* A transition({ when }) is no exception: it is decided in the browser for
|
|
417
|
+
* kept segments too, so no segment is re-sent to carry a decision (#986).
|
|
418
|
+
*/
|
|
419
|
+
function keepClientSegment(segment: ResolvedSegment): void {
|
|
420
|
+
segment.component = null;
|
|
421
|
+
segment.loading = undefined;
|
|
422
|
+
}
|
|
423
|
+
|
|
408
424
|
/**
|
|
409
425
|
* Async generator middleware type
|
|
410
426
|
*/
|
|
@@ -531,14 +547,24 @@ export function withCacheLookup<TEnv>(
|
|
|
531
547
|
}
|
|
532
548
|
|
|
533
549
|
// A record's loader-owned handle values claim their loader, so its own
|
|
534
|
-
// cache() HIT does not replay them again (restoreHandles).
|
|
535
|
-
|
|
536
|
-
|
|
550
|
+
// cache() HIT does not replay them again (restoreHandles). A document
|
|
551
|
+
// HIT tail restores a bake-lane owner's values as the prelude's, unclaimed:
|
|
552
|
+
// they stand against any later push of that loader
|
|
553
|
+
// (HandleStore.pushRestored). An owner the route runs on the live lane is
|
|
554
|
+
// a hole, so its live run still replaces them, even inside a restored
|
|
555
|
+
// loader's body.
|
|
556
|
+
const ownedPushes: OwnedPushDelivery = {
|
|
557
|
+
claim: (ctx.handlerContext as InternalHandlerContext)._claimLoaderPushes,
|
|
558
|
+
};
|
|
559
|
+
if (tailMarker) {
|
|
560
|
+
ownedPushes.liveLane = liveLaneLoaderIds(ctx.entries);
|
|
561
|
+
ownedPushes.restore = tailMarker.docTail === true;
|
|
562
|
+
}
|
|
537
563
|
const explicitLookup = await ctx.cacheScope.lookupRouteDetailed(
|
|
538
564
|
ctx.pathname,
|
|
539
565
|
ctx.matched.params,
|
|
540
566
|
ctx.isIntercept,
|
|
541
|
-
|
|
567
|
+
ownedPushes,
|
|
542
568
|
);
|
|
543
569
|
let cacheResult =
|
|
544
570
|
explicitLookup.status === "hit" ? explicitLookup.result : null;
|
|
@@ -582,7 +608,7 @@ export function withCacheLookup<TEnv>(
|
|
|
582
608
|
ctx.pathname,
|
|
583
609
|
ctx.matched.params,
|
|
584
610
|
ctx.isIntercept,
|
|
585
|
-
|
|
611
|
+
ownedPushes,
|
|
586
612
|
);
|
|
587
613
|
} else if (explicitLookup.status === "bypass") {
|
|
588
614
|
// condition() refused at lookup time (the gate only pre-decides the
|
|
@@ -675,7 +701,6 @@ export function withCacheLookup<TEnv>(
|
|
|
675
701
|
...liveMatchedIds,
|
|
676
702
|
...cacheResult.segments.map((s) => s.id),
|
|
677
703
|
];
|
|
678
|
-
const pprTransitionDecisions = pipelineReqCtx?._pprTransitionDecisions;
|
|
679
704
|
|
|
680
705
|
const canCheckSegmentRevalidation =
|
|
681
706
|
!ctx.isFullMatch &&
|
|
@@ -751,13 +776,7 @@ export function withCacheLookup<TEnv>(
|
|
|
751
776
|
reason: "cached-no-rules",
|
|
752
777
|
});
|
|
753
778
|
}
|
|
754
|
-
|
|
755
|
-
// segment otherwise needs no update. Keep its replayed component so the
|
|
756
|
-
// partial result retains the segment for gateTransitions().
|
|
757
|
-
if (!pprTransitionDecisions?.has(segment.id)) {
|
|
758
|
-
segment.component = null;
|
|
759
|
-
segment.loading = undefined;
|
|
760
|
-
}
|
|
779
|
+
keepClientSegment(segment);
|
|
761
780
|
yield segment;
|
|
762
781
|
continue;
|
|
763
782
|
}
|
|
@@ -789,10 +808,7 @@ export function withCacheLookup<TEnv>(
|
|
|
789
808
|
shouldRevalidate,
|
|
790
809
|
});
|
|
791
810
|
|
|
792
|
-
if (!shouldRevalidate
|
|
793
|
-
segment.component = null;
|
|
794
|
-
segment.loading = undefined;
|
|
795
|
-
}
|
|
811
|
+
if (!shouldRevalidate) keepClientSegment(segment);
|
|
796
812
|
|
|
797
813
|
yield segment;
|
|
798
814
|
}
|
|
@@ -106,11 +106,9 @@ import {
|
|
|
106
106
|
type RequestContext,
|
|
107
107
|
} from "../../server/request-context.js";
|
|
108
108
|
import type { MatchContext, MatchPipelineState } from "../match-context.js";
|
|
109
|
-
import {
|
|
110
|
-
createShellImplicitDocScope,
|
|
111
|
-
resolveCacheTags,
|
|
112
|
-
} from "../../cache/cache-scope.js";
|
|
109
|
+
import { createShellImplicitDocScope } from "../../cache/cache-scope.js";
|
|
113
110
|
import { recordSegmentTags } from "../../cache/cache-tag.js";
|
|
111
|
+
import { executionStart } from "../../cache/tag-invalidation.js";
|
|
114
112
|
import { getRouterContext } from "../router-context.js";
|
|
115
113
|
import { debugLog, debugWarn, getOrCreateRequestId } from "../logging.js";
|
|
116
114
|
import { INTERNAL_RANGO_DEBUG } from "../../internal-debug.js";
|
|
@@ -131,6 +129,9 @@ export function withCacheStore<TEnv>(
|
|
|
131
129
|
source: AsyncGenerator<ResolvedSegment>,
|
|
132
130
|
): AsyncGenerator<ResolvedSegment> {
|
|
133
131
|
const ms = ctx.metricsStore;
|
|
132
|
+
// Before the lookup and the handlers below it run: the record's write
|
|
133
|
+
// gate (#977, CacheScope.cacheRoute).
|
|
134
|
+
const renderStart = executionStart();
|
|
134
135
|
|
|
135
136
|
const allSegments: ResolvedSegment[] = [];
|
|
136
137
|
for await (const segment of source) {
|
|
@@ -266,6 +267,10 @@ export function withCacheStore<TEnv>(
|
|
|
266
267
|
ctx.matched.params,
|
|
267
268
|
allSegmentsToCache,
|
|
268
269
|
ctx.isIntercept,
|
|
270
|
+
// A capture's doc record lives only in the shell entry, which
|
|
271
|
+
// putShell gates by the capture start; skipping it here would
|
|
272
|
+
// read as a render that produced no record.
|
|
273
|
+
cacheScope.isShellImplicitDocScope ? undefined : renderStart,
|
|
269
274
|
);
|
|
270
275
|
if (INTERNAL_RANGO_DEBUG) {
|
|
271
276
|
const dur = performance.now() - start;
|
|
@@ -341,13 +346,14 @@ function recordShellCaptureDocRecord<TEnv>(
|
|
|
341
346
|
if (!scope.allowsCache("write")) return;
|
|
342
347
|
|
|
343
348
|
const docScope = createShellImplicitDocScope(marker);
|
|
344
|
-
// The route scope's cache({ tags })
|
|
345
|
-
// HIT they arrive with the replayed
|
|
346
|
-
// lookupRouteDetailed); on a fresh render they
|
|
347
|
-
// doc record, and the shell taking its tags,
|
|
349
|
+
// The route scope's cache({ tags }), and its enclosing scopes' (#974),
|
|
350
|
+
// describe these segments too: on its HIT they arrive with the replayed
|
|
351
|
+
// record (recordSegmentTags in lookupRouteDetailed); on a fresh render they
|
|
352
|
+
// are recorded here, so the doc record, and the shell taking its tags,
|
|
353
|
+
// carries them either way.
|
|
348
354
|
recordSegmentTags(
|
|
349
355
|
segments.map((s) => s.id),
|
|
350
|
-
|
|
356
|
+
scope.resolveTags(requestCtx),
|
|
351
357
|
requestCtx,
|
|
352
358
|
);
|
|
353
359
|
// Through onResponse, like the implicit scope's own write: the capture
|
|
@@ -281,6 +281,7 @@ export function buildMatchResult<TEnv>(
|
|
|
281
281
|
routeName: ctx.routeKey,
|
|
282
282
|
slots: Object.keys(state.slots).length > 0 ? state.slots : undefined,
|
|
283
283
|
...(interceptTargets.length > 0 ? { interceptTargets } : {}),
|
|
284
|
+
...(ctx.interceptTargeted ? { interceptTargeted: true } : {}),
|
|
284
285
|
routeMiddleware:
|
|
285
286
|
ctx.routeMiddleware.length > 0 ? ctx.routeMiddleware : undefined,
|
|
286
287
|
};
|
package/src/router/middleware.ts
CHANGED
|
@@ -31,7 +31,7 @@ import {
|
|
|
31
31
|
} from "../cache/taint.js";
|
|
32
32
|
import { getCacheExecScope } from "../cache/cache-exec-scope.js";
|
|
33
33
|
import { assertNonCacheableReadAllowed } from "../server/context.js";
|
|
34
|
-
import {
|
|
34
|
+
import { readGuardedTheme } from "../server/cookie-store.js";
|
|
35
35
|
import type { Theme } from "../theme/types.js";
|
|
36
36
|
|
|
37
37
|
// Re-export types consumed through this module's path.
|
|
@@ -52,10 +52,7 @@ export type {
|
|
|
52
52
|
*/
|
|
53
53
|
const MIDDLEWARE_THEME_DESCRIPTOR: PropertyDescriptor = {
|
|
54
54
|
get(): Theme | undefined {
|
|
55
|
-
|
|
56
|
-
if (!reqCtx?._themeConfig) return undefined;
|
|
57
|
-
assertThemeReadAllowed(reqCtx, "ctx.theme");
|
|
58
|
-
return reqCtx._readTheme();
|
|
55
|
+
return readGuardedTheme(_getRequestContext(), "ctx.theme");
|
|
59
56
|
},
|
|
60
57
|
enumerable: false,
|
|
61
58
|
configurable: true,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { requestHeaders } from "../server/request-headers.js";
|
|
1
2
|
import type { RouteMatchResult } from "./pattern-matching.js";
|
|
2
3
|
|
|
3
4
|
export interface NavigationSnapshot {
|
|
@@ -40,8 +41,8 @@ export interface ResolveNavigationDeps {
|
|
|
40
41
|
*/
|
|
41
42
|
export function getNavigationContextHeader(request: Request): string | null {
|
|
42
43
|
return (
|
|
43
|
-
request.
|
|
44
|
-
request.
|
|
44
|
+
requestHeaders(request).get("X-RSC-Router-Client-Path") ||
|
|
45
|
+
requestHeaders(request).get("Referer")
|
|
45
46
|
);
|
|
46
47
|
}
|
|
47
48
|
|
|
@@ -59,7 +60,7 @@ export function prerenderStoreShortCircuits(
|
|
|
59
60
|
pr: true | undefined,
|
|
60
61
|
request: Request,
|
|
61
62
|
): boolean {
|
|
62
|
-
return pr === true && !request.
|
|
63
|
+
return pr === true && !requestHeaders(request).get("X-RSC-HMR");
|
|
63
64
|
}
|
|
64
65
|
|
|
65
66
|
/**
|
|
@@ -71,7 +72,7 @@ export function prerenderStoreShortCircuits(
|
|
|
71
72
|
* request would report `prerender-store` for an artifact that cannot serve.
|
|
72
73
|
*/
|
|
73
74
|
export function getInterceptSourceHeader(request: Request): string | null {
|
|
74
|
-
return request.
|
|
75
|
+
return requestHeaders(request).get("X-RSC-Router-Intercept-Source");
|
|
75
76
|
}
|
|
76
77
|
|
|
77
78
|
export async function resolveNavigation(
|
|
@@ -85,7 +86,7 @@ export async function resolveNavigation(
|
|
|
85
86
|
const stale = url.searchParams.get("_rsc_stale") === "true";
|
|
86
87
|
const previousUrl = getNavigationContextHeader(request);
|
|
87
88
|
const interceptSourceUrl = getInterceptSourceHeader(request);
|
|
88
|
-
const isHmr = !!request.
|
|
89
|
+
const isHmr = !!requestHeaders(request).get("X-RSC-HMR");
|
|
89
90
|
|
|
90
91
|
if (!previousUrl) {
|
|
91
92
|
return null;
|
|
@@ -223,6 +223,8 @@ export async function matchForPrerender<TEnv = any>(
|
|
|
223
223
|
res: stubRes,
|
|
224
224
|
cookie: () => undefined,
|
|
225
225
|
cookies: () => ({}),
|
|
226
|
+
_readCookie: () => undefined,
|
|
227
|
+
_readCookies: () => ({}),
|
|
226
228
|
setCookie: () => {},
|
|
227
229
|
deleteCookie: () => {},
|
|
228
230
|
header: () => {},
|
|
@@ -526,6 +528,8 @@ export async function renderStaticSegment<TEnv = any>(
|
|
|
526
528
|
res: stubRes,
|
|
527
529
|
cookie: () => undefined,
|
|
528
530
|
cookies: () => ({}),
|
|
531
|
+
_readCookie: () => undefined,
|
|
532
|
+
_readCookies: () => ({}),
|
|
529
533
|
setCookie: () => {},
|
|
530
534
|
deleteCookie: () => {},
|
|
531
535
|
header: () => {},
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
* Builds on RouteSnapshot from route-snapshot.ts.
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
+
import { requestHeaders } from "../server/request-headers.js";
|
|
18
19
|
import { RouteNotFoundError } from "../errors.js";
|
|
19
20
|
import type { EntryData } from "../server/context.js";
|
|
20
21
|
import type { CollectedMiddleware } from "./middleware-types.js";
|
|
@@ -149,10 +150,11 @@ export async function classifyRequest<TEnv = any>(
|
|
|
149
150
|
): Promise<RequestPlan<TEnv>> {
|
|
150
151
|
const pathname = url.pathname;
|
|
151
152
|
const isAction =
|
|
152
|
-
request.
|
|
153
|
+
requestHeaders(request).has("rsc-action") ||
|
|
154
|
+
url.searchParams.has("_rsc_action");
|
|
153
155
|
const isLoaderFetch = url.searchParams.has("_rsc_loader");
|
|
154
156
|
const isPartialReq = url.searchParams.has("_rsc_partial");
|
|
155
|
-
const contentType = request.
|
|
157
|
+
const contentType = requestHeaders(request).get("content-type") || "";
|
|
156
158
|
const isFormSubmission =
|
|
157
159
|
contentType.includes("multipart/form-data") ||
|
|
158
160
|
contentType.includes("application/x-www-form-urlencoded");
|
|
@@ -176,7 +178,7 @@ export async function classifyRequest<TEnv = any>(
|
|
|
176
178
|
) {
|
|
177
179
|
let reloadUrl = stripInternalParams(url).toString();
|
|
178
180
|
if (isAction) {
|
|
179
|
-
const referer = request.
|
|
181
|
+
const referer = requestHeaders(request).get("referer");
|
|
180
182
|
if (referer) {
|
|
181
183
|
try {
|
|
182
184
|
const refererUrl = new URL(referer);
|
|
@@ -248,7 +250,8 @@ export async function classifyRequest<TEnv = any>(
|
|
|
248
250
|
}
|
|
249
251
|
|
|
250
252
|
const actionId =
|
|
251
|
-
request.
|
|
253
|
+
requestHeaders(request).get("rsc-action") ||
|
|
254
|
+
url.searchParams.get("_rsc_action");
|
|
252
255
|
|
|
253
256
|
const hasVariants =
|
|
254
257
|
snapshot.matched.negotiateVariants &&
|
|
@@ -518,7 +518,10 @@ export interface RangoOptions<TEnv = any> {
|
|
|
518
518
|
*
|
|
519
519
|
* Controls how long prefetch responses are kept in the client-side
|
|
520
520
|
* in-memory cache and sets `Cache-Control: private, max-age=<ttl>`
|
|
521
|
-
* on
|
|
521
|
+
* on prefetch responses, so the browser's HTTP cache may reuse them
|
|
522
|
+
* (`private`: shared caches such as a CDN do not store them). A route an
|
|
523
|
+
* intercept targets gets no prefetch `Cache-Control`: whether its
|
|
524
|
+
* response is the modal or the full page depends on the source page.
|
|
522
525
|
*
|
|
523
526
|
* The cache is automatically invalidated on server actions regardless
|
|
524
527
|
* of TTL, so this is primarily a staleness safety net.
|
|
@@ -324,7 +324,6 @@ export async function resolveSegment<TEnv>(
|
|
|
324
324
|
transition: applyViewTransitionDefault(
|
|
325
325
|
entry.transition,
|
|
326
326
|
deps.viewTransitionDefault,
|
|
327
|
-
entry.shortCode,
|
|
328
327
|
),
|
|
329
328
|
params,
|
|
330
329
|
belongsToRoute: false,
|
|
@@ -474,7 +473,6 @@ export async function resolveSegment<TEnv>(
|
|
|
474
473
|
transition: applyViewTransitionDefault(
|
|
475
474
|
entry.transition,
|
|
476
475
|
deps.viewTransitionDefault,
|
|
477
|
-
entry.shortCode,
|
|
478
476
|
),
|
|
479
477
|
params,
|
|
480
478
|
belongsToRoute: true,
|
|
@@ -563,7 +561,6 @@ export async function resolveOrphanLayout<TEnv>(
|
|
|
563
561
|
transition: applyViewTransitionDefault(
|
|
564
562
|
orphan.transition,
|
|
565
563
|
deps.viewTransitionDefault,
|
|
566
|
-
orphan.shortCode,
|
|
567
564
|
),
|
|
568
565
|
...(orphan.mountPath ? { mountPath: orphan.mountPath } : {}),
|
|
569
566
|
});
|
|
@@ -723,7 +720,6 @@ export async function resolveParallelEntry<TEnv>(
|
|
|
723
720
|
transition: applyViewTransitionDefault(
|
|
724
721
|
parallelEntry.transition,
|
|
725
722
|
deps.viewTransitionDefault,
|
|
726
|
-
`${parentShortCode}.${slot}`,
|
|
727
723
|
),
|
|
728
724
|
params,
|
|
729
725
|
slot,
|