@rangojs/router 0.17.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/README.md +3 -2
- package/dist/types/browser/cookie-name.d.ts +6 -0
- package/dist/types/browser/event-controller.d.ts +3 -3
- package/dist/types/browser/history-state.d.ts +18 -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 +48 -2
- package/dist/types/cache/cache-policy.d.ts +18 -1
- package/dist/types/cache/cache-runtime.d.ts +7 -0
- package/dist/types/cache/cache-scope.d.ts +192 -26
- package/dist/types/cache/cache-tag.d.ts +116 -11
- 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 +224 -72
- 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 +19 -0
- package/dist/types/cache/document-cache.d.ts +10 -0
- package/dist/types/cache/handle-snapshot.d.ts +41 -8
- package/dist/types/cache/index.d.ts +1 -0
- package/dist/types/cache/invalidation-order.d.ts +23 -0
- package/dist/types/cache/isolate-tag-memo.d.ts +149 -0
- package/dist/types/cache/request-tag-mask.d.ts +54 -0
- package/dist/types/cache/shell-memo.d.ts +178 -0
- package/dist/types/cache/shell-snapshot.d.ts +141 -105
- package/dist/types/cache/tag-invalidation.d.ts +54 -3
- package/dist/types/cache/types.d.ts +267 -96
- package/dist/types/cache/vercel/vercel-cache-store.d.ts +123 -18
- 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/prerender/build-shell-capture.d.ts +11 -4
- 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/instrument.d.ts +8 -0
- 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/middleware-types.d.ts +6 -1
- package/dist/types/router/router-options.d.ts +4 -1
- package/dist/types/router/segment-resolution/loader-cache.d.ts +58 -12
- package/dist/types/router/segment-resolution/loader-mask.d.ts +3 -4
- package/dist/types/router/segment-resolution/loader-snapshot.d.ts +33 -48
- package/dist/types/router/segment-resolution/mask-nested.d.ts +73 -24
- 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 +21 -0
- package/dist/types/rsc/handler.d.ts +1 -1
- package/dist/types/rsc/response-cache-serve.d.ts +15 -12
- package/dist/types/rsc/shell-build-manifest.d.ts +12 -3
- package/dist/types/rsc/shell-capture-constants.d.ts +116 -12
- package/dist/types/rsc/shell-capture.d.ts +202 -74
- package/dist/types/rsc/shell-serve.d.ts +144 -50
- package/dist/types/rsc/types.d.ts +9 -0
- package/dist/types/segment-system.d.ts +7 -0
- package/dist/types/server/context.d.ts +155 -33
- package/dist/types/server/cookie-store.d.ts +33 -0
- package/dist/types/server/handle-store.d.ts +52 -1
- package/dist/types/server/request-context.d.ts +210 -63
- package/dist/types/server/request-headers.d.ts +44 -0
- package/dist/types/server.d.ts +1 -0
- package/dist/types/ssr/index.d.ts +9 -0
- package/dist/types/ssr/ssr-root.d.ts +9 -8
- package/dist/types/testing/e2e/index.d.ts +1 -1
- package/dist/types/testing/flight.entry.d.ts +7 -0
- 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-loader.d.ts +18 -3
- package/dist/types/testing/run-transition-when.d.ts +44 -69
- package/dist/types/testing/serve-shell-request.d.ts +133 -0
- package/dist/types/testing/shell-status.d.ts +44 -19
- package/dist/types/transition-when-ref.d.ts +79 -0
- package/dist/types/types/cache-types.d.ts +15 -3
- package/dist/types/types/handler-context.d.ts +14 -1
- 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 +21 -18
- package/dist/types/vite/plugins/transition-when-hoist.d.ts +45 -0
- package/dist/types/vite/router-discovery.d.ts +29 -2
- package/dist/vite/index.js +1005 -105
- package/package.json +1 -1
- package/skills/breadcrumbs/SKILL.md +17 -7
- package/skills/cache-guide/SKILL.md +175 -76
- package/skills/caching/SKILL.md +361 -33
- package/skills/catalog.json +1 -1
- package/skills/client-urls/SKILL.md +12 -7
- package/skills/cloudflare/SKILL.md +15 -0
- package/skills/comparison/references/framework-comparison.md +52 -37
- package/skills/defer-hydration/SKILL.md +50 -30
- package/skills/deployment-caching/SKILL.md +5 -2
- package/skills/document-cache/SKILL.md +32 -2
- package/skills/handler-use/SKILL.md +2 -0
- package/skills/hooks/SKILL.md +3 -1
- package/skills/hooks/handle-and-actions.md +3 -1
- package/skills/hooks/navigation.md +23 -2
- package/skills/hooks/state.md +101 -7
- package/skills/intercept/SKILL.md +29 -12
- package/skills/loader/SKILL.md +197 -44
- package/skills/middleware/SKILL.md +34 -9
- package/skills/migrate-nextjs/SKILL.md +68 -37
- 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 +65 -0
- package/skills/parallel/SKILL.md +13 -8
- package/skills/ppr/SKILL.md +715 -371
- package/skills/prerender/SKILL.md +30 -17
- package/skills/rango/SKILL.md +72 -34
- package/skills/route/SKILL.md +14 -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 +49 -43
- package/skills/testing/cache-prerender.md +15 -14
- package/skills/testing/client-components.md +45 -3
- package/skills/testing/loader.md +19 -1
- 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 +202 -0
- package/skills/testing/server-actions.md +9 -3
- package/skills/theme/SKILL.md +56 -4
- package/skills/typesafety/env-and-bindings.md +18 -2
- package/skills/use-cache/SKILL.md +91 -23
- package/skills/vercel/SKILL.md +14 -2
- package/skills/view-transitions/SKILL.md +150 -29
- package/src/__augment-tests__/augmented.check.ts +23 -0
- package/src/browser/cookie-name.ts +23 -0
- package/src/browser/event-controller.ts +4 -4
- package/src/browser/history-state.ts +75 -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 +9 -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 +62 -2
- package/src/cache/cache-policy.ts +31 -4
- package/src/cache/cache-runtime.ts +209 -129
- package/src/cache/cache-scope.ts +573 -69
- package/src/cache/cache-tag.ts +475 -19
- 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 +1094 -376
- 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 +55 -40
- package/src/cache/document-cache.ts +53 -7
- package/src/cache/handle-snapshot.ts +53 -9
- package/src/cache/index.ts +2 -0
- package/src/cache/invalidation-order.ts +84 -0
- package/src/cache/isolate-tag-memo.ts +308 -0
- package/src/cache/request-tag-mask.ts +147 -0
- package/src/cache/shell-memo.ts +341 -0
- package/src/cache/shell-snapshot.ts +249 -277
- package/src/cache/tag-invalidation.ts +109 -18
- package/src/cache/types.ts +274 -102
- package/src/cache/vercel/vercel-cache-store.ts +561 -74
- 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 +173 -110
- package/src/route-definition/dsl-helpers.ts +6 -3
- 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 +42 -5
- package/src/router/instrument.ts +54 -2
- package/src/router/intercept-resolution.ts +30 -8
- package/src/router/loader-resolution.ts +89 -33
- package/src/router/logging.ts +5 -3
- package/src/router/match-api.ts +89 -42
- package/src/router/match-context.ts +5 -0
- package/src/router/match-handlers.ts +14 -29
- package/src/router/match-middleware/background-revalidation.ts +3 -5
- package/src/router/match-middleware/cache-lookup.ts +52 -19
- package/src/router/match-middleware/cache-store.ts +36 -10
- package/src/router/match-result.ts +1 -0
- package/src/router/middleware-types.ts +6 -1
- package/src/router/middleware.ts +20 -4
- package/src/router/navigation-snapshot.ts +6 -5
- package/src/router/prerender-match.ts +10 -0
- package/src/router/request-classification.ts +7 -4
- package/src/router/router-options.ts +4 -1
- package/src/router/segment-resolution/fresh.ts +18 -13
- package/src/router/segment-resolution/helpers.ts +4 -2
- package/src/router/segment-resolution/loader-cache.ts +366 -70
- package/src/router/segment-resolution/loader-mask.ts +3 -4
- package/src/router/segment-resolution/loader-snapshot.ts +215 -126
- package/src/router/segment-resolution/mask-nested.ts +161 -42
- package/src/router/segment-resolution/revalidation.ts +27 -13
- 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 +47 -3
- package/src/rsc/handler.ts +24 -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 +10 -32
- package/src/rsc/response-cache-serve.ts +69 -78
- package/src/rsc/response-route-handler.ts +2 -2
- package/src/rsc/rsc-rendering.ts +712 -338
- package/src/rsc/server-action.ts +8 -20
- package/src/rsc/shell-build-manifest.ts +49 -29
- package/src/rsc/shell-capture-constants.ts +182 -12
- package/src/rsc/shell-capture.ts +1126 -612
- package/src/rsc/shell-serve.ts +331 -85
- package/src/rsc/ssr-setup.ts +3 -2
- package/src/rsc/types.ts +9 -0
- package/src/segment-system.tsx +40 -7
- package/src/server/context.ts +328 -72
- package/src/server/cookie-store.ts +184 -133
- package/src/server/handle-store.ts +245 -27
- package/src/server/request-context.ts +364 -100
- package/src/server/request-headers.ts +134 -0
- package/src/server.ts +4 -0
- package/src/ssr/index.tsx +96 -37
- package/src/ssr/ssr-root.tsx +9 -8
- package/src/testing/dispatch.ts +4 -7
- package/src/testing/e2e/index.ts +1 -0
- package/src/testing/flight.entry.ts +14 -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 +67 -5
- package/src/testing/run-transition-when.ts +109 -172
- package/src/testing/serve-shell-request.ts +381 -0
- package/src/testing/shell-status.ts +73 -47
- package/src/theme/ThemeProvider.tsx +7 -6
- package/src/transition-when-ref.ts +220 -0
- package/src/types/cache-types.ts +15 -3
- package/src/types/handler-context.ts +14 -1
- 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 +21 -18
- package/src/vite/discovery/discover-routers.ts +3 -0
- package/src/vite/discovery/shell-prerender-phase.ts +9 -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 +89 -9
- package/dist/types/rsc/transition-gate.d.ts +0 -23
- package/src/rsc/transition-gate.ts +0 -86
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* transition({ when }) references: what a route definition may carry as a
|
|
3
|
+
* `when`, how definitions are validated, and how the browser turns the carried
|
|
4
|
+
* value back into a callable predicate.
|
|
5
|
+
*
|
|
6
|
+
* `when` is a BROWSER predicate. The server never calls it; it only carries it
|
|
7
|
+
* to the browser inside the segment's transition config, as one of:
|
|
8
|
+
*
|
|
9
|
+
* - a React client reference: a function exported from a `"use client"`
|
|
10
|
+
* module and imported into a server `urls()` file, or an inline literal the
|
|
11
|
+
* build hoisted into one (vite/plugins/transition-when-hoist.ts). Flight
|
|
12
|
+
* serializes it as a module reference and the browser resolves it to the
|
|
13
|
+
* real function;
|
|
14
|
+
* - a clientUrls() when reference, synthesized by the projection materializer
|
|
15
|
+
* (client-urls/server-projection.ts): the group's definition client
|
|
16
|
+
* reference plus the route id. The browser resolves it to the `when` the
|
|
17
|
+
* route declared in its `"use client"` module.
|
|
18
|
+
*
|
|
19
|
+
* A plain function (a server function) cannot cross Flight, and a
|
|
20
|
+
* non-function is never callable. Both are LOUD errors: route discovery
|
|
21
|
+
* (generateManifestFull `validateTransitionWhen`) fails dev startup, the
|
|
22
|
+
* build and HMR re-discovery, and attachTransitionWhen (rsc/) throws the same
|
|
23
|
+
* error at render time for a route discovery did not see.
|
|
24
|
+
*
|
|
25
|
+
* Telling a client reference apart from a server function needs the
|
|
26
|
+
* react-server module graph, where a `"use client"` import IS a client
|
|
27
|
+
* reference. Outside it (a node/DOM unit-test project that aliases the router
|
|
28
|
+
* entry) the import is the plain function, so strict validation is enabled
|
|
29
|
+
* only by the Vite plugin: discovery passes the option, and the generated
|
|
30
|
+
* routes-manifest module calls enableTransitionWhenValidation() in the app's
|
|
31
|
+
* RSC realm (vite/discovery/virtual-module-codegen.ts).
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
import { isAutoGeneratedRouteName } from "./route-name.js";
|
|
35
|
+
import type { TransitionWhenFn } from "./types/segments.js";
|
|
36
|
+
|
|
37
|
+
const CLIENT_REFERENCE = Symbol.for("react.client.reference");
|
|
38
|
+
|
|
39
|
+
/** String key, so the marker survives Flight (symbol keys are not serialized). */
|
|
40
|
+
const CLIENT_URLS_WHEN_KEY = "__rangoClientUrlsWhen";
|
|
41
|
+
|
|
42
|
+
interface ClientUrlsWhenRef {
|
|
43
|
+
readonly __rangoClientUrlsWhen: 1;
|
|
44
|
+
/** The clientUrls() definition: a client reference on the server, the definition object in the browser. */
|
|
45
|
+
readonly definition: unknown;
|
|
46
|
+
readonly routeId: string;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function isClientReference(value: unknown): boolean {
|
|
50
|
+
if (typeof value !== "function" && (typeof value !== "object" || !value)) {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
return (value as { $$typeof?: unknown }).$$typeof === CLIENT_REFERENCE;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function isClientUrlsWhenRef(value: unknown): value is ClientUrlsWhenRef {
|
|
57
|
+
return (
|
|
58
|
+
typeof value === "object" &&
|
|
59
|
+
value !== null &&
|
|
60
|
+
(value as Record<string, unknown>)[CLIENT_URLS_WHEN_KEY] === 1
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function createClientUrlsWhenRef(
|
|
65
|
+
definition: unknown,
|
|
66
|
+
routeId: string,
|
|
67
|
+
): TransitionWhenFn {
|
|
68
|
+
const ref: ClientUrlsWhenRef = {
|
|
69
|
+
__rangoClientUrlsWhen: 1,
|
|
70
|
+
definition,
|
|
71
|
+
routeId,
|
|
72
|
+
};
|
|
73
|
+
return ref as unknown as TransitionWhenFn;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
let strictValidation = false;
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Turn on server-function rejection for this realm. Called by the Vite
|
|
80
|
+
* plugin's generated routes-manifest module, never by tests: see the module
|
|
81
|
+
* comment for why it cannot be on by default.
|
|
82
|
+
*/
|
|
83
|
+
export function enableTransitionWhenValidation(): void {
|
|
84
|
+
strictValidation = true;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function isTransitionWhenValidationEnabled(): boolean {
|
|
88
|
+
return strictValidation;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** @internal Reset for unit tests. */
|
|
92
|
+
export function resetTransitionWhenValidation(): void {
|
|
93
|
+
strictValidation = false;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** Thrown for an invalid transition({ when }); recognized by the dev HMR overlay. */
|
|
97
|
+
export class TransitionWhenError extends Error {
|
|
98
|
+
override readonly name: string = "TransitionWhenError";
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* The TransitionWhenError in an error's cause chain, matched by name: discovery
|
|
103
|
+
* throws it from the module runner's copy of this module (another class
|
|
104
|
+
* object), and include resolution wraps it (build/generate-manifest.ts).
|
|
105
|
+
*/
|
|
106
|
+
export function findTransitionWhenError(error: unknown): Error | undefined {
|
|
107
|
+
const seen = new Set<unknown>();
|
|
108
|
+
let current: unknown = error;
|
|
109
|
+
while (
|
|
110
|
+
typeof current === "object" &&
|
|
111
|
+
current !== null &&
|
|
112
|
+
!seen.has(current)
|
|
113
|
+
) {
|
|
114
|
+
seen.add(current);
|
|
115
|
+
if ((current as Error).name === "TransitionWhenError") {
|
|
116
|
+
return current as Error;
|
|
117
|
+
}
|
|
118
|
+
current = (current as { cause?: unknown }).cause;
|
|
119
|
+
}
|
|
120
|
+
return undefined;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/** Where an invalid `when` was declared, for the error message. */
|
|
124
|
+
export interface TransitionWhenSite {
|
|
125
|
+
/** The route the entry belongs to (the matched or enumerated route). */
|
|
126
|
+
readonly routeName?: string;
|
|
127
|
+
readonly pattern?: string;
|
|
128
|
+
/** The declaring entry's type when it is not the route itself. */
|
|
129
|
+
readonly entryType?: string;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function describeSite(site: TransitionWhenSite): string {
|
|
133
|
+
const named =
|
|
134
|
+
site.routeName && !isAutoGeneratedRouteName(site.routeName)
|
|
135
|
+
? `route "${site.routeName}"${site.pattern ? ` (${site.pattern})` : ""}`
|
|
136
|
+
: site.pattern
|
|
137
|
+
? `route ${site.pattern}`
|
|
138
|
+
: "a route";
|
|
139
|
+
if (!site.entryType || site.entryType === "route") return named;
|
|
140
|
+
return `a ${site.entryType} of ${named}`;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function describeValue(value: unknown): string {
|
|
144
|
+
if (value === null) return "null";
|
|
145
|
+
if (Array.isArray(value)) return "an array";
|
|
146
|
+
return typeof value;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* The problem with a `when` value, or null when it is valid. Non-functions
|
|
151
|
+
* are always invalid; a plain function is invalid only under strict
|
|
152
|
+
* validation (see the module comment).
|
|
153
|
+
*/
|
|
154
|
+
export function transitionWhenProblem(
|
|
155
|
+
when: unknown,
|
|
156
|
+
strict: boolean,
|
|
157
|
+
): "not-a-function" | "server-function" | null {
|
|
158
|
+
if (when === undefined || isClientUrlsWhenRef(when)) return null;
|
|
159
|
+
if (typeof when !== "function") return "not-a-function";
|
|
160
|
+
if (strict && !isClientReference(when)) return "server-function";
|
|
161
|
+
return null;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export function createTransitionWhenError(
|
|
165
|
+
when: unknown,
|
|
166
|
+
problem: "not-a-function" | "server-function",
|
|
167
|
+
site: TransitionWhenSite,
|
|
168
|
+
): TransitionWhenError {
|
|
169
|
+
const where = `transition({ when }) on ${describeSite(site)}`;
|
|
170
|
+
const head =
|
|
171
|
+
problem === "not-a-function"
|
|
172
|
+
? `${where} must be a function, got ${describeValue(when)}.`
|
|
173
|
+
: `${where} is not a client function.`;
|
|
174
|
+
return new TransitionWhenError(
|
|
175
|
+
`[rango] ${head} ` +
|
|
176
|
+
"`when` runs in the browser: write it inline in the transition() call " +
|
|
177
|
+
"(transition({ when: (ctx) => ... }), where transition is the urls() helper " +
|
|
178
|
+
'or imported from "@rangojs/router"; the build hoists that literal into a ' +
|
|
179
|
+
'client module) or export it from a "use client" module and import it ' +
|
|
180
|
+
"into your urls() file. It receives { kind, from, to, isAction, action }: " +
|
|
181
|
+
"URLs, params, route names, history state and action data; get(), env " +
|
|
182
|
+
'and handler state do not exist there. See skills/view-transitions "Conditional transitions".',
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Definition-time shape check (the DSL's transition()). Runs in every
|
|
188
|
+
* environment, so it rejects only what is invalid everywhere: a non-function.
|
|
189
|
+
*/
|
|
190
|
+
export function assertTransitionWhenShape(when: unknown): void {
|
|
191
|
+
if (transitionWhenProblem(when, false) === "not-a-function") {
|
|
192
|
+
throw new TypeError(
|
|
193
|
+
createTransitionWhenError(when, "not-a-function", {}).message,
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Browser: turn a transition config's `when` into the predicate to call.
|
|
200
|
+
* Undefined when there is none (or a clientUrls route no longer declares it).
|
|
201
|
+
*/
|
|
202
|
+
export function resolveTransitionWhen(
|
|
203
|
+
when: unknown,
|
|
204
|
+
): TransitionWhenFn | undefined {
|
|
205
|
+
if (typeof when === "function") return when as TransitionWhenFn;
|
|
206
|
+
if (!isClientUrlsWhenRef(when)) return undefined;
|
|
207
|
+
const definition = when.definition as
|
|
208
|
+
| {
|
|
209
|
+
routes?: ReadonlyArray<{
|
|
210
|
+
id: string;
|
|
211
|
+
transition?: { when?: unknown };
|
|
212
|
+
}>;
|
|
213
|
+
}
|
|
214
|
+
| undefined;
|
|
215
|
+
const record = definition?.routes?.find(
|
|
216
|
+
(candidate) => candidate.id === when.routeId,
|
|
217
|
+
);
|
|
218
|
+
const fn = record?.transition?.when;
|
|
219
|
+
return typeof fn === "function" ? (fn as TransitionWhenFn) : undefined;
|
|
220
|
+
}
|
package/src/types/cache-types.ts
CHANGED
|
@@ -72,7 +72,13 @@ export interface CacheOptions<TEnv = unknown> {
|
|
|
72
72
|
/**
|
|
73
73
|
* Override the cache store for this boundary.
|
|
74
74
|
* When specified, this boundary and its children use this store
|
|
75
|
-
* instead of the app-level store from handler config.
|
|
75
|
+
* instead of the app-level store from handler config. The records of a
|
|
76
|
+
* boundary with a store here are partitioned by the `keyGenerator` of each
|
|
77
|
+
* enclosing cache() without a `key` whose store differs, the app-level
|
|
78
|
+
* store included: under `cache(() => [...])` on an app store with a
|
|
79
|
+
* `keyGenerator`, `cache({ store })` records are split by its result too.
|
|
80
|
+
* Likewise, without a `key` of its own, this store's `keyGenerator`
|
|
81
|
+
* partitions a nested cache() on another store.
|
|
76
82
|
*
|
|
77
83
|
* Useful for:
|
|
78
84
|
* - Different backends per route section (memory vs KV vs Redis)
|
|
@@ -108,6 +114,8 @@ export interface CacheOptions<TEnv = unknown> {
|
|
|
108
114
|
/**
|
|
109
115
|
* Conditional cache read function.
|
|
110
116
|
* Return false to skip cache for this request (always fetch fresh).
|
|
117
|
+
* It gates every cache() nested under this one too: a nested boundary
|
|
118
|
+
* caches only when every enclosing condition allows it.
|
|
111
119
|
*
|
|
112
120
|
* Has access to full RequestContext including env, request, params, cookies, etc.
|
|
113
121
|
* Runs after global and route middleware on RSC routes; on response routes,
|
|
@@ -130,7 +138,10 @@ export interface CacheOptions<TEnv = unknown> {
|
|
|
130
138
|
|
|
131
139
|
/**
|
|
132
140
|
* Custom cache key function - FULL OVERRIDE.
|
|
133
|
-
* Bypasses default key generation AND store's keyGenerator.
|
|
141
|
+
* Bypasses default key generation AND store's keyGenerator. The result is
|
|
142
|
+
* stored namespaced (`key:` plus its URI encoding), so no value it returns
|
|
143
|
+
* names another route's record; a nested cache() keys its records within
|
|
144
|
+
* this partition.
|
|
134
145
|
*
|
|
135
146
|
* Has access to full RequestContext including env, request, params, cookies, etc.
|
|
136
147
|
* Runs after global and route middleware on RSC routes; on response routes,
|
|
@@ -154,7 +165,8 @@ export interface CacheOptions<TEnv = unknown> {
|
|
|
154
165
|
|
|
155
166
|
/**
|
|
156
167
|
* Tags for cache invalidation.
|
|
157
|
-
* Can be a static array or a function that returns tags.
|
|
168
|
+
* Can be a static array or a function that returns tags. They tag the
|
|
169
|
+
* records of every cache() nested under this one too.
|
|
158
170
|
*
|
|
159
171
|
* The built-in `MemorySegmentCacheStore`, `CFCacheStore`, and
|
|
160
172
|
* `VercelCacheStore` index by tag.
|
|
@@ -342,6 +342,12 @@ export type HandlerContext<
|
|
|
342
342
|
* Current theme (from cookie or default).
|
|
343
343
|
* Only available when theme is enabled in router config.
|
|
344
344
|
*
|
|
345
|
+
* The visitor's cookie, so it is guarded like `cookies()`: reading it on a
|
|
346
|
+
* `ppr` route refuses the shell capture, and inside a `cache()` boundary or
|
|
347
|
+
* a `"use cache"` function it throws (#971). Read it with `useTheme()` in a
|
|
348
|
+
* client component, or in a live loader, on those routes. A read-only,
|
|
349
|
+
* non-enumerable getter: `{ ...ctx }` does not carry it.
|
|
350
|
+
*
|
|
345
351
|
* @example
|
|
346
352
|
* ```typescript
|
|
347
353
|
* route("settings", (ctx) => {
|
|
@@ -350,7 +356,7 @@ export type HandlerContext<
|
|
|
350
356
|
* });
|
|
351
357
|
* ```
|
|
352
358
|
*/
|
|
353
|
-
theme?: Theme;
|
|
359
|
+
readonly theme?: Theme;
|
|
354
360
|
/**
|
|
355
361
|
* Set the theme (only available when theme is enabled in router config).
|
|
356
362
|
* Sets a cookie with the new theme value.
|
|
@@ -469,6 +475,13 @@ export type InternalHandlerContext<
|
|
|
469
475
|
* from the page. See setupLoaderAccess.
|
|
470
476
|
*/
|
|
471
477
|
_runLoaderIsolated?: (loader: any) => Promise<any>;
|
|
478
|
+
/**
|
|
479
|
+
* @internal A loader's cache() binding started with these cache() tags: an
|
|
480
|
+
* execution of that loader outside the binding (a reader started it first,
|
|
481
|
+
* or a stale refresh runs it) answers for them too (#964). See
|
|
482
|
+
* setupLoaderAccess.
|
|
483
|
+
*/
|
|
484
|
+
_bindLoaderCacheTags?: (loaderId: string, tags: Set<string>) => void;
|
|
472
485
|
};
|
|
473
486
|
|
|
474
487
|
/**
|
package/src/types/index.ts
CHANGED
package/src/types/segments.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { ReactNode } from "react";
|
|
2
2
|
import type { ErrorInfo, NotFoundInfo } from "./boundaries.js";
|
|
3
|
-
import type {
|
|
3
|
+
import type { IsActionFn } from "./handler-context.js";
|
|
4
|
+
import type { DefaultRouteName } from "./global-namespace.js";
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* CSS class(es) for a ViewTransition phase.
|
|
@@ -10,96 +11,97 @@ import type { RevalidateParams, HandlerContext } from "./handler-context.js";
|
|
|
10
11
|
export type ViewTransitionClass = Record<string, string> | string;
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
* error-boundary re-render exposes `actionUrl` only when `actionId` resolved.
|
|
38
|
-
* Malformed form bodies that fail before action detection expose no action
|
|
39
|
-
* fields. Treat `actionId` as "the action, if known", not as "was this an
|
|
40
|
-
* action".
|
|
41
|
-
*
|
|
42
|
-
* PREFETCH / CACHE CAVEAT (read this before gating on the source): the gate runs
|
|
43
|
-
* server-side during resolution. A PREFETCHED navigation renders at prefetch
|
|
44
|
-
* time, so `currentUrl`/`currentParams`/`fromRouteName` reflect the page the
|
|
45
|
-
* prefetch fired from, NOT necessarily the page the user actually navigates from
|
|
46
|
-
* — the decision is baked into the stored Flight payload and replayed verbatim.
|
|
47
|
-
* A non-PPR `cache()`/prerender hit replays the stored transition with the
|
|
48
|
-
* predicate NOT re-run. A `ppr` route instead evaluates the predicate before
|
|
49
|
-
* handlers on every match, including cache, prerender, and PPR replay. Prefetch
|
|
50
|
-
* still freezes the server decision into its Flight payload. If the gate must
|
|
51
|
-
* reflect the exact click-time source, source-scope the prefetch
|
|
52
|
-
* (`<Link prefetchKey=":source">`).
|
|
14
|
+
* One side of a navigation as the browser knows it when a
|
|
15
|
+
* `transition({ when })` predicate runs.
|
|
16
|
+
*/
|
|
17
|
+
export interface RouteLocation {
|
|
18
|
+
readonly url: URL;
|
|
19
|
+
/** Merged route params of the location. */
|
|
20
|
+
readonly params: Readonly<Record<string, string>>;
|
|
21
|
+
/**
|
|
22
|
+
* The matched route's name (include prefixes applied), typed from the
|
|
23
|
+
* generated route map; undefined for an unnamed route or when unknown.
|
|
24
|
+
* Internal names never appear here.
|
|
25
|
+
*/
|
|
26
|
+
readonly routeName: DefaultRouteName | undefined;
|
|
27
|
+
/**
|
|
28
|
+
* `history.state` of this entry at decision time. Read a typed slot with
|
|
29
|
+
* `Def.read(location)` (a `createLocationState()` definition).
|
|
30
|
+
*/
|
|
31
|
+
readonly state: unknown;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* A navigation side as the server sees it, for intercept's `when` selector:
|
|
36
|
+
* a {@link RouteLocation} without `state` (history state never reaches the
|
|
37
|
+
* server).
|
|
53
38
|
*/
|
|
54
|
-
export type
|
|
55
|
-
TParams = Record<string, string>,
|
|
56
|
-
TEnv = unknown,
|
|
57
|
-
> = Partial<
|
|
58
|
-
Pick<
|
|
59
|
-
RevalidateParams<TParams, TEnv>,
|
|
60
|
-
"currentUrl" | "currentParams" | "fromRouteName"
|
|
61
|
-
>
|
|
62
|
-
> &
|
|
63
|
-
Pick<
|
|
64
|
-
RevalidateParams<TParams, TEnv>,
|
|
65
|
-
| "nextUrl"
|
|
66
|
-
| "nextParams"
|
|
67
|
-
| "toRouteName"
|
|
68
|
-
| "actionId"
|
|
69
|
-
| "actionUrl"
|
|
70
|
-
| "actionResult"
|
|
71
|
-
| "formData"
|
|
72
|
-
| "method"
|
|
73
|
-
> &
|
|
74
|
-
Pick<HandlerContext<any, TEnv>, "get" | "env">;
|
|
39
|
+
export type ServerRouteLocation = Omit<RouteLocation, "state">;
|
|
75
40
|
|
|
76
41
|
/**
|
|
77
|
-
*
|
|
42
|
+
* How the navigation being decided was started.
|
|
78
43
|
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
|
|
88
|
-
|
|
44
|
+
* - `"push"` / `"replace"`: a Link click, `router.push()` / `router.replace()`
|
|
45
|
+
* or `navigate()`.
|
|
46
|
+
* - `"pop"`: browser back/forward (restored from the history cache or
|
|
47
|
+
* refetched).
|
|
48
|
+
* - `"action"`: the commit that applies a server action's revalidation,
|
|
49
|
+
* including the error-boundary commit of a failed action.
|
|
50
|
+
* - `"revalidate"`: a re-render of the current URL: `router.refresh()`,
|
|
51
|
+
* cross-tab invalidation, or the background revalidation of a stale entry.
|
|
52
|
+
*/
|
|
53
|
+
export type TransitionWhenKind =
|
|
54
|
+
| "push"
|
|
55
|
+
| "replace"
|
|
56
|
+
| "pop"
|
|
57
|
+
| "action"
|
|
58
|
+
| "revalidate";
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* The context a `transition({ when })` predicate receives. The predicate runs
|
|
62
|
+
* in the BROWSER, once per navigation, at the first commit that presents the
|
|
63
|
+
* destination. The server never calls it.
|
|
89
64
|
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
65
|
+
* - `from`: the committed location being left.
|
|
66
|
+
* - `to`: the destination. The same object as `from` for `"action"` and
|
|
67
|
+
* `"revalidate"`.
|
|
68
|
+
* - `isAction`: the matcher `revalidate()` predicates get; `false` off an
|
|
69
|
+
* action.
|
|
70
|
+
* - `action`: present only for `kind: "action"`.
|
|
71
|
+
*/
|
|
72
|
+
export interface TransitionWhenContext {
|
|
73
|
+
readonly kind: TransitionWhenKind;
|
|
74
|
+
readonly from: RouteLocation;
|
|
75
|
+
readonly to: RouteLocation;
|
|
76
|
+
readonly isAction: IsActionFn;
|
|
77
|
+
/** Present only for `kind: "action"`. */
|
|
78
|
+
readonly action?: {
|
|
79
|
+
/** The action's hashed `$$id` in the browser; match with `isAction(fn)` instead. */
|
|
80
|
+
readonly id: string | undefined;
|
|
81
|
+
/** The FormData argument the action received (the 2nd argument under `useActionState`). */
|
|
82
|
+
readonly formData: FormData | undefined;
|
|
83
|
+
/** The action's return value on success. */
|
|
84
|
+
readonly result: unknown;
|
|
85
|
+
/** What a failed action threw (its error-boundary commit); `result` is undefined then. */
|
|
86
|
+
readonly error: unknown;
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Browser-run predicate that gates whether a navigation holds and animates.
|
|
92
92
|
*
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
*
|
|
93
|
+
* In `urls()` write it inline (`transition({ when: (ctx) => ... })`, which
|
|
94
|
+
* the build hoists into a client module; it may reference only its own
|
|
95
|
+
* bindings, globals and client-safe imports) or export it from a
|
|
96
|
+
* `"use client"` module and import it; in `clientUrls()` it is an inline
|
|
97
|
+
* function. Anything else (a server function, a non-function) fails route
|
|
98
|
+
* discovery.
|
|
98
99
|
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
*
|
|
102
|
-
*
|
|
100
|
+
* `false` makes the navigation an urgent commit: no hold, no view transition,
|
|
101
|
+
* and a same-route navigation streams its `loading()` fallback. The segment
|
|
102
|
+
* keeps its key and its `<ViewTransition>` element (every class "none"), so
|
|
103
|
+
* nothing remounts. One predicate returning false decides for the whole
|
|
104
|
+
* navigation. A throw is logged with `console.error` and counts as `false`.
|
|
103
105
|
*/
|
|
104
106
|
export type TransitionWhenFn = (ctx: TransitionWhenContext) => boolean;
|
|
105
107
|
|
|
@@ -132,13 +134,8 @@ export interface TransitionConfig {
|
|
|
132
134
|
*/
|
|
133
135
|
viewTransition?: "auto" | false;
|
|
134
136
|
/**
|
|
135
|
-
* Optional
|
|
136
|
-
*
|
|
137
|
-
* the request, so the navigation streams its loading fallback instead of
|
|
138
|
-
* holding. PPR routes evaluate it before route handlers and on every replay;
|
|
139
|
-
* other routes evaluate it after handlers on fresh resolution. The predicate
|
|
140
|
-
* is server-only and never serialized to the client; only its resolved effect
|
|
141
|
-
* crosses. See {@link TransitionWhenFn}.
|
|
137
|
+
* Optional browser-run predicate that gates this transition per
|
|
138
|
+
* navigation. See {@link TransitionWhenFn}.
|
|
142
139
|
*/
|
|
143
140
|
when?: TransitionWhenFn;
|
|
144
141
|
}
|
|
@@ -285,6 +282,12 @@ export interface MatchResult {
|
|
|
285
282
|
* decline its optimistic presentation for targets an intercept would claim.
|
|
286
283
|
*/
|
|
287
284
|
interceptTargets?: string[];
|
|
285
|
+
/**
|
|
286
|
+
* Set on a partial match when an intercept targets the matched route,
|
|
287
|
+
* whether or not it applied from this source. The response depends on the
|
|
288
|
+
* source, so the RSC handler scopes its prefetch entry to it (#1007).
|
|
289
|
+
*/
|
|
290
|
+
interceptTargeted?: true;
|
|
288
291
|
/**
|
|
289
292
|
* Redirect URL for trailing slash normalization.
|
|
290
293
|
* When set, the RSC handler should return a 308 redirect to this URL
|
|
@@ -417,10 +417,9 @@ export type PathHelpers<TEnv> = {
|
|
|
417
417
|
* transition cannot fire without a startTransition. See
|
|
418
418
|
* skills/view-transitions for the startTransition x ViewTransition matrix.
|
|
419
419
|
*
|
|
420
|
-
* Pass `when
|
|
421
|
-
*
|
|
422
|
-
*
|
|
423
|
-
* not handler-set values.
|
|
420
|
+
* Pass `when` (inline, hoisted into a client module by the build, or a
|
|
421
|
+
* "use client" export) to gate the navigation's hold and view transition in
|
|
422
|
+
* the browser (never on the server); see TransitionWhenFn.
|
|
424
423
|
*/
|
|
425
424
|
transition: {
|
|
426
425
|
(): TransitionItem;
|
|
@@ -59,30 +59,33 @@ export interface PartialPrerenderProps {
|
|
|
59
59
|
/**
|
|
60
60
|
* Operational tags attached to the captured shell entry for
|
|
61
61
|
* `updateTag()`/`revalidateTag()`-driven eviction. UNIONED with the tags the
|
|
62
|
-
* capture
|
|
62
|
+
* capture collects: its doc record's tags (what the handler layer and the
|
|
63
|
+
* server components it rendered recorded) and its bake-lane loaders'.
|
|
63
64
|
*/
|
|
64
65
|
tags?: string[];
|
|
65
66
|
/**
|
|
66
|
-
* Upper bound (serialized UTF-8 bytes) on the
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
67
|
+
* Upper bound (serialized UTF-8 bytes) on the loader pins in the capture
|
|
68
|
+
* data snapshot: the bake-lane loader records. The doc record (the handler
|
|
69
|
+
* layer every HIT replays) is exempt. Over the cap the pins are dropped: the
|
|
70
|
+
* shell is still stored and every HIT still replays the handler layer, but the
|
|
71
|
+
* pinned loaders read the live store, so drifted cached content can
|
|
72
|
+
* hydration-mismatch and be repaired client-side. Reported once per key.
|
|
73
|
+
* Defaults to 8 MiB. The whole entry is bounded separately by the store's
|
|
74
|
+
* value limit (Cloudflare KV: 25 MiB); an entry over it is refused.
|
|
74
75
|
*/
|
|
75
76
|
maxSnapshotBytes?: number;
|
|
76
77
|
/**
|
|
77
|
-
* Capture settle budget in MILLISECONDS (default 15000).
|
|
78
|
-
* background capture: the
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
78
|
+
* Capture settle budget in MILLISECONDS (default 15000). One deadline for
|
|
79
|
+
* the whole background capture: the match (the handlers, and the loaders
|
|
80
|
+
* they await), the wait for handler output (handle pushes and the promises
|
|
81
|
+
* nested in them, bake-lane loaders, and the doc record's encode, which
|
|
82
|
+
* awaits handler promises and async server components), AND the fizz
|
|
83
|
+
* prerender. Everything a handler produces is
|
|
84
|
+
* awaited and baked into the stored shell. Declare it to tighten the
|
|
85
|
+
* budget below the default or when a route's shell material takes longer
|
|
86
|
+
* than 15s to settle. A budget that expires before the doc record is
|
|
87
|
+
* written REFUSES the capture (the route stays MISS with the once-per-key
|
|
88
|
+
* warning): a shell with missing handler output is never stored. Capture is background work
|
|
86
89
|
* (waitUntil), so a longer budget costs latency-to-HIT only, never a served
|
|
87
90
|
* response; the platform waitUntil lifetime (workerd: ~30s past response
|
|
88
91
|
* completion) is the physical ceiling — the default's derivation lives in
|
|
@@ -211,6 +211,9 @@ export async function discoverRouters(
|
|
|
211
211
|
routerId: id,
|
|
212
212
|
...(router.__basename ? { urlPrefix: router.__basename } : {}),
|
|
213
213
|
...(collectClientFallbackRef ? { collectClientFallbackRef } : {}),
|
|
214
|
+
// Discovery evaluates the tree in the react-server graph, where a
|
|
215
|
+
// "use client" import is a client reference: reject server `when`s.
|
|
216
|
+
validateTransitionWhen: true,
|
|
214
217
|
}),
|
|
215
218
|
);
|
|
216
219
|
routerMountIndex++;
|
|
@@ -64,6 +64,14 @@ export async function runShellPrerenderPhase(
|
|
|
64
64
|
const startTotal = performance.now();
|
|
65
65
|
console.log(`[rango] Shell-prerendering ${candidates.length} URL(s)...`);
|
|
66
66
|
|
|
67
|
+
// Hold the process open for the phase. The capture's waits are unref'd
|
|
68
|
+
// timers (retry delay, Flight quiesce hops) so a runtime capture never keeps
|
|
69
|
+
// Node alive; every bundle is already written and the build temp server has
|
|
70
|
+
// no file watcher (#947). Its only remaining handle is the HMR WebSocket on
|
|
71
|
+
// 24678, which fails to bind silently when another Vite server holds the
|
|
72
|
+
// port; `vite build` then exited 0 mid-phase without writing
|
|
73
|
+
// __shell-manifest.js.
|
|
74
|
+
const keepAlive = setInterval(() => {}, 60_000);
|
|
67
75
|
let restoreClientRequire: (() => void) | undefined;
|
|
68
76
|
try {
|
|
69
77
|
// Runner access needs the RunnableDevEnvironment surface; the environments
|
|
@@ -282,9 +290,7 @@ export async function runShellPrerenderPhase(
|
|
|
282
290
|
const value: BuildShellEntry = {
|
|
283
291
|
entry: res.entry,
|
|
284
292
|
ttl: policy.ttl,
|
|
285
|
-
swr: policy.swr,
|
|
286
293
|
tags: res.tags,
|
|
287
|
-
routeName: cand.routeName,
|
|
288
294
|
};
|
|
289
295
|
staged.push({
|
|
290
296
|
key: buildShellManifestKey(cand.urlPath),
|
|
@@ -343,6 +349,7 @@ export async function runShellPrerenderPhase(
|
|
|
343
349
|
// buildApp post hook's finally on success, buildEnd on an aborted build.
|
|
344
350
|
delete (globalThis as any).__loadPrerenderManifestModule;
|
|
345
351
|
restoreClientRequire?.();
|
|
352
|
+
clearInterval(keepAlive);
|
|
346
353
|
}
|
|
347
354
|
}
|
|
348
355
|
|