@rangojs/router 0.22.1 → 0.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/rango.js +10 -4
- package/dist/testing/vitest.js +31 -1
- package/dist/types/browser/defer.d.ts +48 -0
- package/dist/types/browser/document-revealed.d.ts +17 -0
- package/dist/types/browser/event-controller.d.ts +7 -1
- package/dist/types/browser/merge-segment-loaders.d.ts +5 -2
- package/dist/types/browser/navigation-transaction.d.ts +21 -7
- package/dist/types/browser/partial-update.d.ts +39 -8
- package/dist/types/browser/react/NavigationProvider.d.ts +19 -5
- package/dist/types/browser/react/context.d.ts +3 -2
- package/dist/types/browser/react/filter-segment-order.d.ts +7 -0
- package/dist/types/browser/response-adapter.d.ts +7 -0
- package/dist/types/browser/types.d.ts +24 -10
- package/dist/types/browser/validate-redirect-origin.d.ts +11 -0
- package/dist/types/build/generate-route-types.d.ts +1 -1
- package/dist/types/build/route-types/router-processing.d.ts +1 -1
- package/dist/types/build/route-types/scan-filter.d.ts +22 -2
- package/dist/types/cache/cf/cf-cache-store.d.ts +16 -1
- package/dist/types/cache/cf/cf-cache-types.d.ts +23 -2
- package/dist/types/cache/document-cache-policy.d.ts +24 -0
- package/dist/types/cache/document-cache.d.ts +2 -10
- package/dist/types/client-urls/client-urls.d.ts +1 -1
- package/dist/types/client-urls/hoisted-revalidate.d.ts +13 -0
- package/dist/types/client-urls/navigation.d.ts +0 -37
- package/dist/types/client-urls/revalidate-registry.d.ts +4 -0
- package/dist/types/client-urls/server-projection.d.ts +29 -1
- package/dist/types/client-urls/types.d.ts +34 -69
- package/dist/types/client.d.ts +0 -1
- package/dist/types/context-var.d.ts +12 -0
- package/dist/types/errors.d.ts +15 -0
- package/dist/types/handles/deferred-resolution.d.ts +2 -1
- package/dist/types/handles/pushed-by.d.ts +31 -0
- package/dist/types/index.d.ts +4 -0
- package/dist/types/index.rsc.d.ts +2 -0
- package/dist/types/loader-store.d.ts +8 -0
- package/dist/types/prefetch-markers.d.ts +11 -0
- package/dist/types/response-utils.d.ts +7 -0
- package/dist/types/reverse.d.ts +8 -8
- package/dist/types/route-definition/helpers-types.d.ts +27 -0
- package/dist/types/route-definition/rewrite.d.ts +56 -0
- package/dist/types/route-map-builder.d.ts +7 -2
- package/dist/types/router/basename.d.ts +7 -0
- package/dist/types/router/handler-context.d.ts +1 -5
- package/dist/types/router/internal-params.d.ts +8 -0
- package/dist/types/router/is-action.d.ts +2 -1
- package/dist/types/router/middleware-types.d.ts +15 -0
- package/dist/types/router/revalidation.d.ts +1 -2
- package/dist/types/router/route-trie-builder.d.ts +10 -0
- package/dist/types/router/segment-resolution/loader-mask.d.ts +3 -2
- package/dist/types/router/segment-resolution/mask-nested.d.ts +4 -2
- package/dist/types/router/segment-resolution/prefetch-deferral.d.ts +264 -0
- package/dist/types/rsc/full-payload.d.ts +11 -0
- package/dist/types/rsc/handler.d.ts +33 -0
- package/dist/types/rsc/helpers.d.ts +8 -0
- package/dist/types/rsc/loader-fetch.d.ts +16 -0
- package/dist/types/rsc/rewrite-passes.d.ts +74 -0
- package/dist/types/rsc/ssr-setup.d.ts +3 -1
- package/dist/types/server/context.d.ts +21 -1
- package/dist/types/server/handle-store.d.ts +9 -1
- package/dist/types/server/request-context.d.ts +52 -2
- package/dist/types/server/rewrite-trail.d.ts +49 -0
- package/dist/types/server/slot-accessors.d.ts +29 -0
- package/dist/types/server.d.ts +1 -0
- package/dist/types/testing/flight.entry.d.ts +1 -1
- package/dist/types/testing/index.d.ts +4 -4
- package/dist/types/testing/internal/action-id.d.ts +10 -1
- package/dist/types/testing/internal/client-urls-projection.d.ts +16 -0
- package/dist/types/testing/internal/test-action.d.ts +8 -0
- package/dist/types/testing/render-route.d.ts +8 -0
- package/dist/types/testing/run-loader.d.ts +2 -1
- package/dist/types/testing/run-middleware.d.ts +20 -0
- package/dist/types/testing/run-revalidate.d.ts +74 -0
- package/dist/types/testing/run-transition-when.d.ts +2 -3
- package/dist/types/testing/serve-shell-request.d.ts +40 -1
- package/dist/types/testing/vitest.d.ts +11 -0
- package/dist/types/thenable-status.d.ts +6 -0
- package/dist/types/types/boundaries.d.ts +9 -0
- package/dist/types/types/handler-context.d.ts +14 -0
- package/dist/types/types/loader-types.d.ts +30 -0
- package/dist/types/types/request-scope.d.ts +7 -0
- package/dist/types/types/segments.d.ts +21 -4
- package/dist/types/urls/path-helper-types.d.ts +25 -4
- package/dist/types/urls/type-extraction.d.ts +6 -2
- package/dist/types/vite/discovery/discover-routers.d.ts +9 -0
- package/dist/types/vite/discovery/state.d.ts +14 -4
- package/dist/types/vite/plugins/client-urls-revalidate-hoist.d.ts +54 -0
- package/dist/types/vite/plugins/hoist/literal.d.ts +83 -0
- package/dist/types/vite/plugins/hoist/scope.d.ts +40 -0
- package/dist/types/vite/plugins/hoist/source.d.ts +41 -0
- package/dist/types/vite/plugins/transition-when-hoist.d.ts +8 -11
- package/dist/types/vite/router-discovery.d.ts +10 -0
- package/dist/vite/index.js +974 -379
- package/package.json +1 -1
- package/skills/caching/SKILL.md +54 -5
- package/skills/catalog.json +3 -3
- package/skills/client-urls/SKILL.md +197 -24
- package/skills/cloudflare/SKILL.md +14 -9
- package/skills/hooks/SKILL.md +16 -3
- package/skills/hooks/data.md +3 -1
- package/skills/links/SKILL.md +24 -0
- package/skills/loader/SKILL.md +199 -2
- package/skills/middleware/SKILL.md +183 -2
- package/skills/migrate-nextjs/SKILL.md +2 -2
- package/skills/migrate-react-router/SKILL.md +10 -7
- package/skills/migrate-react-router/data-and-actions.md +1 -1
- package/skills/ppr/SKILL.md +22 -0
- package/skills/prerender/SKILL.md +22 -8
- package/skills/rango/SKILL.md +13 -7
- package/skills/route/SKILL.md +139 -0
- package/skills/server-actions/SKILL.md +27 -0
- package/skills/testing/SKILL.md +3 -2
- package/skills/testing/client-components.md +2 -1
- package/skills/testing/middleware.md +31 -10
- package/skills/testing/predicates.md +67 -32
- package/skills/testing/response-routes.md +1 -0
- package/skills/testing/serve-shell-request.md +107 -19
- package/skills/testing/setup.md +2 -2
- package/skills/typesafety/route-types.md +2 -2
- package/skills/use-cache/SKILL.md +4 -2
- package/skills/view-transitions/SKILL.md +26 -0
- package/src/__augment-tests__/augmented.check.ts +20 -0
- package/src/browser/defer.ts +82 -0
- package/src/browser/document-revealed.ts +52 -0
- package/src/browser/event-controller.ts +46 -32
- package/src/browser/merge-segment-loaders.ts +31 -18
- package/src/browser/navigation-bridge.ts +82 -16
- package/src/browser/navigation-client.ts +48 -36
- package/src/browser/navigation-store.ts +13 -0
- package/src/browser/navigation-transaction.ts +25 -8
- package/src/browser/partial-update.ts +554 -146
- package/src/browser/prefetch/fetch.ts +2 -1
- package/src/browser/react/Link.tsx +7 -9
- package/src/browser/react/NavigationProvider.tsx +88 -49
- package/src/browser/react/context.ts +3 -2
- package/src/browser/react/filter-segment-order.ts +13 -2
- package/src/browser/react/use-router.ts +2 -4
- package/src/browser/response-adapter.ts +20 -0
- package/src/browser/rsc-router.tsx +17 -45
- package/src/browser/server-action-bridge.ts +25 -63
- package/src/browser/types.ts +24 -10
- package/src/browser/validate-redirect-origin.ts +16 -0
- package/src/build/generate-route-types.ts +1 -0
- package/src/build/route-types/router-processing.ts +3 -6
- package/src/build/route-types/scan-filter.ts +45 -11
- package/src/cache/cf/cf-cache-store.ts +59 -21
- package/src/cache/cf/cf-cache-types.ts +24 -2
- package/src/cache/document-cache-policy.ts +131 -0
- package/src/cache/document-cache.ts +21 -107
- package/src/client-urls/client-urls.ts +22 -6
- package/src/client-urls/hoisted-revalidate.ts +25 -0
- package/src/client-urls/navigation.ts +0 -96
- package/src/client-urls/revalidate-registry.ts +30 -0
- package/src/client-urls/server-projection.ts +151 -65
- package/src/client-urls/types.ts +39 -71
- package/src/client.tsx +9 -5
- package/src/context-var.ts +32 -2
- package/src/errors.ts +34 -0
- package/src/handles/deferred-resolution.ts +28 -5
- package/src/handles/pushed-by.ts +148 -0
- package/src/index.rsc.ts +8 -0
- package/src/index.ts +7 -0
- package/src/loader-store.ts +18 -7
- package/src/prefetch-markers.ts +13 -0
- package/src/response-utils.ts +19 -0
- package/src/reverse.ts +17 -14
- package/src/route-content-wrapper.tsx +18 -4
- package/src/route-definition/dsl-helpers.ts +27 -4
- package/src/route-definition/helpers-types.ts +27 -1
- package/src/route-definition/redirect.ts +2 -15
- package/src/route-definition/rewrite.ts +146 -0
- package/src/route-map-builder.ts +14 -11
- package/src/router/basename.ts +20 -0
- package/src/router/handler-context.ts +3 -13
- package/src/router/intercept-resolution.ts +35 -16
- package/src/router/internal-params.ts +16 -0
- package/src/router/is-action.ts +2 -1
- package/src/router/loader-resolution.ts +85 -4
- package/src/router/match-api.ts +36 -1
- package/src/router/match-middleware/background-revalidation.ts +16 -4
- package/src/router/match-middleware/cache-lookup.ts +35 -7
- package/src/router/match-middleware/cache-store.ts +15 -1
- package/src/router/match-middleware/intercept-resolution.ts +4 -2
- package/src/router/match-result.ts +14 -2
- package/src/router/middleware-types.ts +16 -0
- package/src/router/middleware.ts +127 -49
- package/src/router/navigation-snapshot.ts +2 -1
- package/src/router/revalidation.ts +1 -1
- package/src/router/route-trie-builder.ts +28 -1
- package/src/router/segment-resolution/fresh.ts +22 -18
- package/src/router/segment-resolution/loader-cache.ts +2 -1
- package/src/router/segment-resolution/loader-mask.ts +5 -3
- package/src/router/segment-resolution/loader-snapshot.ts +18 -4
- package/src/router/segment-resolution/mask-nested.ts +8 -4
- package/src/router/segment-resolution/prefetch-deferral.ts +583 -0
- package/src/router/segment-resolution/revalidation.ts +215 -82
- package/src/rsc/full-payload.ts +37 -5
- package/src/rsc/handler.ts +82 -55
- package/src/rsc/helpers.ts +24 -0
- package/src/rsc/loader-fetch.ts +79 -24
- package/src/rsc/response-cache-serve.ts +18 -2
- package/src/rsc/response-route-handler.ts +4 -7
- package/src/rsc/rewrite-passes.ts +203 -0
- package/src/rsc/rsc-rendering.ts +54 -9
- package/src/rsc/shell-capture.ts +2 -1
- package/src/rsc/ssr-setup.ts +11 -5
- package/src/segment-loader-promise.ts +23 -20
- package/src/segment-system.tsx +60 -26
- package/src/server/context.ts +39 -5
- package/src/server/cookie-parse.ts +36 -12
- package/src/server/cookie-store.ts +7 -3
- package/src/server/handle-store.ts +152 -25
- package/src/server/request-context.ts +175 -64
- package/src/server/request-headers.ts +4 -14
- package/src/server/rewrite-trail.ts +190 -0
- package/src/server/slot-accessors.ts +57 -0
- package/src/server.ts +4 -0
- package/src/ssr/index.tsx +118 -16
- package/src/testing/action-form.ts +2 -11
- package/src/testing/dispatch.ts +138 -67
- package/src/testing/e2e/page-helpers.ts +3 -1
- package/src/testing/flight.entry.ts +1 -0
- package/src/testing/index.ts +7 -3
- package/src/testing/internal/action-id.ts +16 -1
- package/src/testing/internal/client-urls-projection.ts +70 -0
- package/src/testing/internal/test-action.ts +25 -0
- package/src/testing/render-route.tsx +16 -3
- package/src/testing/run-loader.ts +4 -1
- package/src/testing/run-middleware.ts +56 -11
- package/src/testing/run-revalidate.ts +142 -0
- package/src/testing/run-transition-when.ts +7 -8
- package/src/testing/serve-shell-request.ts +131 -8
- package/src/testing/vitest.ts +67 -1
- package/src/thenable-status.ts +11 -0
- package/src/types/boundaries.ts +12 -0
- package/src/types/handler-context.ts +14 -0
- package/src/types/loader-types.ts +30 -0
- package/src/types/request-scope.ts +8 -0
- package/src/types/segments.ts +26 -4
- package/src/urls/path-helper-types.ts +27 -5
- package/src/urls/type-extraction.ts +30 -10
- package/src/use-loader.tsx +18 -13
- package/src/vite/discovery/client-urls-projection.ts +20 -21
- package/src/vite/discovery/discover-routers.ts +94 -26
- package/src/vite/discovery/state.ts +28 -4
- package/src/vite/discovery/virtual-module-codegen.ts +22 -17
- package/src/vite/plugins/client-urls-revalidate-hoist.ts +564 -0
- package/src/vite/plugins/expose-internal-ids.ts +2 -3
- package/src/vite/plugins/hoist/literal.ts +417 -0
- package/src/vite/plugins/hoist/scope.ts +370 -0
- package/src/vite/plugins/hoist/source.ts +84 -0
- package/src/vite/plugins/transition-when-hoist.ts +113 -779
- package/src/vite/rango.ts +2 -0
- package/src/vite/router-discovery.ts +116 -53
- package/dist/types/client-urls/revalidate-chain.d.ts +0 -33
- package/dist/types/client-urls/revalidation-protocol.d.ts +0 -25
- package/dist/types/testing/run-client-revalidate.d.ts +0 -43
- package/src/client-urls/revalidate-chain.ts +0 -83
- package/src/client-urls/revalidation-protocol.ts +0 -56
- package/src/testing/run-client-revalidate.ts +0 -92
|
@@ -10,11 +10,7 @@ import type { InternalHandlerContext } from "../types";
|
|
|
10
10
|
* (createMiddlewareContext).
|
|
11
11
|
*/
|
|
12
12
|
export declare function guardHeaderWrites(headers: Headers, assertWrite: (method: string | symbol) => void): Headers;
|
|
13
|
-
|
|
14
|
-
* Strip internal _rsc* query params from a URL.
|
|
15
|
-
* Returns a new URL with only user-facing params.
|
|
16
|
-
*/
|
|
17
|
-
export declare function stripInternalParams(url: URL): URL;
|
|
13
|
+
export { stripInternalParams } from "./internal-params.js";
|
|
18
14
|
/**
|
|
19
15
|
* Create a reverse function for URL generation from route names.
|
|
20
16
|
* Used by both HandlerContext and MiddlewareContext.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Strip internal _rsc* query params from a URL.
|
|
3
|
+
* Returns a new URL with only user-facing params.
|
|
4
|
+
*
|
|
5
|
+
* A leaf, so request-scoped modules (server/rewrite-trail.ts) can strip
|
|
6
|
+
* without importing the handler context's graph.
|
|
7
|
+
*/
|
|
8
|
+
export declare function stripInternalParams(url: URL): URL;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Shared `isAction()` matcher for revalidate predicates (server
|
|
2
|
+
* Shared `isAction()` matcher for revalidate() predicates (server) and
|
|
3
|
+
* transition({ when }) (browser).
|
|
3
4
|
*
|
|
4
5
|
* Action identity is `actionId`. The helper resolves an imported reference the
|
|
5
6
|
* same way the action boundary derives that id (`$id ?? $$id`), so a
|
|
@@ -4,6 +4,7 @@ import type { GlobalReverseFunction } from "../reverse.js";
|
|
|
4
4
|
import type { Theme } from "../theme/types.js";
|
|
5
5
|
import type { LocationStateEntry } from "../browser/react/location-state-shared.js";
|
|
6
6
|
import type { RequestScope } from "../types/request-scope.js";
|
|
7
|
+
import type { Rewrite } from "../route-definition/rewrite.js";
|
|
7
8
|
type GetVariableFn = {
|
|
8
9
|
<T>(contextVar: ContextVar<T>): T | undefined;
|
|
9
10
|
<K extends keyof DefaultVars>(key: K): DefaultVars[K];
|
|
@@ -58,6 +59,20 @@ export interface MiddlewareContext<TEnv = any, TParams = Record<string, string |
|
|
|
58
59
|
setLocationState(entries: LocationStateEntry | LocationStateEntry[]): void;
|
|
59
60
|
/** Global route names only; see {@link GlobalReverseFunction}. */
|
|
60
61
|
reverse: GlobalReverseFunction<DefaultReverseRouteMap>;
|
|
62
|
+
/**
|
|
63
|
+
* Whether `value` is a `rewrite()` thrown downstream. A middleware that
|
|
64
|
+
* wraps `next()` in try/catch rethrows it, so the request re-dispatches:
|
|
65
|
+
*
|
|
66
|
+
* ```ts
|
|
67
|
+
* try {
|
|
68
|
+
* return await next();
|
|
69
|
+
* } catch (error) {
|
|
70
|
+
* if (ctx.isRewrite(error)) throw error;
|
|
71
|
+
* return new Response("Error", { status: 500 });
|
|
72
|
+
* }
|
|
73
|
+
* ```
|
|
74
|
+
*/
|
|
75
|
+
isRewrite(value: unknown): value is Rewrite;
|
|
61
76
|
}
|
|
62
77
|
export type MiddlewareFn<TEnv = any, TParams = Record<string, string | undefined>> = (ctx: MiddlewareContext<TEnv, TParams>, next: () => Promise<Response>) => Response | void | Promise<Response | void>;
|
|
63
78
|
export interface MiddlewareEntry<TEnv = any> {
|
|
@@ -9,7 +9,7 @@ import type { RevalidationTraceEntry } from "./logging.js";
|
|
|
9
9
|
/**
|
|
10
10
|
* Options for revalidation evaluation
|
|
11
11
|
*/
|
|
12
|
-
interface EvaluateRevalidationOptions<TEnv> {
|
|
12
|
+
export interface EvaluateRevalidationOptions<TEnv> {
|
|
13
13
|
/** Current segment to evaluate */
|
|
14
14
|
segment: ResolvedSegment;
|
|
15
15
|
/** Previous route params (from route match, not segment) */
|
|
@@ -61,4 +61,3 @@ interface EvaluateRevalidationOptions<TEnv> {
|
|
|
61
61
|
* Optimized to use prevParams directly and avoid building previous segments
|
|
62
62
|
*/
|
|
63
63
|
export declare function evaluateRevalidation<TEnv>(options: EvaluateRevalidationOptions<TEnv>): Promise<boolean>;
|
|
64
|
-
export {};
|
|
@@ -82,3 +82,13 @@ export interface TrieNode {
|
|
|
82
82
|
* @param onDemandRouteNames - Optional set of on-demand-eligible route names (sets leaf.od)
|
|
83
83
|
*/
|
|
84
84
|
export declare function buildRouteTrie(routeManifest: Record<string, string>, routeToStaticPrefix: Record<string, string>, routeTrailingSlash?: Record<string, string>, prerenderRouteNames?: Set<string>, passthroughRouteNames?: Set<string>, responseTypeRoutes?: Record<string, string>, onDemandRouteNames?: Set<string>): TrieNode;
|
|
85
|
+
/**
|
|
86
|
+
* Give every static-children map in the trie a null prototype, in place, and
|
|
87
|
+
* return the trie (#1109). The walker indexes `node.s` with raw URL segments,
|
|
88
|
+
* so a map with Object.prototype would answer `/constructor` or `/__proto__`
|
|
89
|
+
* with an inherited member. The builder creates null-prototype maps; a trie
|
|
90
|
+
* that arrives as JSON (the build manifest) or across the dev runner boundary
|
|
91
|
+
* gets them here. Object.setPrototypeOf keeps a JSON-parsed map's fast
|
|
92
|
+
* properties, where Object.create(null) starts in dictionary mode.
|
|
93
|
+
*/
|
|
94
|
+
export declare function nullPrototypeStaticChildren(node: TrieNode): TrieNode;
|
|
@@ -24,8 +24,9 @@ import { type RequestContext } from "../../server/request-context.js";
|
|
|
24
24
|
export declare function isShellCaptureActive(reqCtx?: RequestContext<any> | undefined): boolean;
|
|
25
25
|
export { createMaskedLoaderPromise } from "./mask-nested.js";
|
|
26
26
|
/**
|
|
27
|
-
* True when the entry's loading() is renderable (
|
|
28
|
-
* isRenderableLoading
|
|
27
|
+
* True when the entry's loading() is renderable (the shared
|
|
28
|
+
* isRenderableLoading, types/boundaries.ts, that segment-system gates on).
|
|
29
|
+
* Not the lane decision (lane rule: see
|
|
29
30
|
* resolveLoaderData, loader-cache.ts): callers only use it to decide whether
|
|
30
31
|
* an unflagged loader's segment key rides as the bake/seed key, which is inert
|
|
31
32
|
* at capture.
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
*
|
|
9
9
|
* Deliberately a LEAF module: loader-mask (the other natural home) imports
|
|
10
10
|
* request-context, so any funnel importing the mask from there inherits that
|
|
11
|
-
* graph. This module imports only is-thenable and
|
|
11
|
+
* graph. This module imports only react and two leaves, is-thenable and
|
|
12
|
+
* context-var.
|
|
12
13
|
*/
|
|
13
14
|
import { type ReactElement } from "react";
|
|
14
15
|
/**
|
|
@@ -36,7 +37,8 @@ export declare function isPlainDataObject(value: unknown): value is Record<strin
|
|
|
36
37
|
* keyless child of a static children list (validated at creation) would warn
|
|
37
38
|
* "Each child in a list should have a unique key" once cloned. Pass only the
|
|
38
39
|
* props that change: cloneElement re-parents the element (owner) when its
|
|
39
|
-
* config carries `ref`.
|
|
40
|
+
* config carries `ref`. cloneElement copies props by assignment, so a prop
|
|
41
|
+
* key named `__proto__` can't survive a clone; prop copies don't use assignOwn.
|
|
40
42
|
*/
|
|
41
43
|
export declare function cloneElementWithProps(element: ReactElement, props: Record<string, unknown>): ReactElement;
|
|
42
44
|
/**
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `prefetch: false`: what a prefetch request defers and what its fill request
|
|
3
|
+
* runs (docs/design/prefetch-false.md).
|
|
4
|
+
*
|
|
5
|
+
* Two layers. The SCOPE is static per matched chain: which loader
|
|
6
|
+
* registrations are deferrable and which entries can be a handler unit. The
|
|
7
|
+
* PLAN is per match and rides the handler context
|
|
8
|
+
* (InternalHandlerContext._prefetchDeferral): the request's mode and where the
|
|
9
|
+
* chain's stored handler output starts. A request context cannot carry it: a
|
|
10
|
+
* shell capture derives its context from the request that scheduled it and
|
|
11
|
+
* would inherit a prefetch's mode.
|
|
12
|
+
*
|
|
13
|
+
* The decisions themselves are made in revalidation.ts, by asking this module.
|
|
14
|
+
*
|
|
15
|
+
* One rule runs through every decision: the flag applies only to a segment
|
|
16
|
+
* the client does not have yet. A segment the client holds is never deferred,
|
|
17
|
+
* whether or not it re-renders, and nothing is deferred because of it. A
|
|
18
|
+
* placeholder over content that is on screen would replace it with a fallback,
|
|
19
|
+
* or make the click wait where a plain navigation would not.
|
|
20
|
+
*
|
|
21
|
+
* "Holds" is what the request listed in `_rsc_segments` (PrefetchDeferral.held),
|
|
22
|
+
* the set buildMatchResult (match-result.ts) filters the response with. Not
|
|
23
|
+
* the set resolution works on: the match deletes a route's id from that one to
|
|
24
|
+
* force a same-route render from an intercept source (match-api.ts), and a
|
|
25
|
+
* unit deferred on that ground would be dropped from the response as held.
|
|
26
|
+
*/
|
|
27
|
+
import { type EntryData, type LoaderEntry } from "../../server/context.js";
|
|
28
|
+
import type { HandlerContext } from "../../types.js";
|
|
29
|
+
import type { CacheScope } from "../../cache/cache-scope.js";
|
|
30
|
+
/**
|
|
31
|
+
* What a request says it is, read once when its context is created
|
|
32
|
+
* (RequestContext._requestKind). A fill is marked on the raw URL and wins
|
|
33
|
+
* over the prefetch header. Whether a prefetch defers anything is decided per
|
|
34
|
+
* match, by partialDeferralMode: a shell capture inherits the context of the
|
|
35
|
+
* request that scheduled it and is never a prefetch.
|
|
36
|
+
*/
|
|
37
|
+
export declare function requestKind(request: Request, rawUrl: URL): "prefetch" | "fill" | undefined;
|
|
38
|
+
/** Static, per matched chain. */
|
|
39
|
+
interface DeferralScope {
|
|
40
|
+
/**
|
|
41
|
+
* Loader registrations a prefetch can defer, each with what makes it so:
|
|
42
|
+
* `true` for its own flag, else the segment ids of the flagged entries whose
|
|
43
|
+
* fallback covers it. A covered loader is deferred only while one of those
|
|
44
|
+
* segments is new to the client.
|
|
45
|
+
*/
|
|
46
|
+
readonly loaders: ReadonlyMap<LoaderEntry, true | readonly string[]>;
|
|
47
|
+
/** `$$id`s of `loaders`: the loaders that cannot call ctx.rendered(). */
|
|
48
|
+
readonly loaderIds: ReadonlySet<string>;
|
|
49
|
+
/**
|
|
50
|
+
* Entries whose handler a prefetch can skip (a flagged loading() with a
|
|
51
|
+
* fallback to show). `index` is the chain index that owns the entry: its
|
|
52
|
+
* own for a chain entry, its parent's for a parallel entry. `ids` are its
|
|
53
|
+
* segment ids: the entry's for a chain entry, one per slot for a parallel
|
|
54
|
+
* entry.
|
|
55
|
+
*/
|
|
56
|
+
readonly units: ReadonlyMap<EntryData, DeferralUnit>;
|
|
57
|
+
}
|
|
58
|
+
interface DeferralUnit {
|
|
59
|
+
readonly index: number;
|
|
60
|
+
readonly ids: readonly string[];
|
|
61
|
+
}
|
|
62
|
+
/** Per match: InternalHandlerContext._prefetchDeferral. */
|
|
63
|
+
export interface PrefetchDeferral {
|
|
64
|
+
readonly scope: DeferralScope;
|
|
65
|
+
/**
|
|
66
|
+
* "prefetch": deferral replaces execution. "fill": the request that follows
|
|
67
|
+
* an adopted prefetch; a held segment is skipped outright. Unset on every
|
|
68
|
+
* other request, where the plan only feeds the ctx.rendered() guards.
|
|
69
|
+
*/
|
|
70
|
+
readonly mode?: "prefetch" | "fill";
|
|
71
|
+
/**
|
|
72
|
+
* First chain index whose handler output is stored or about to be (a
|
|
73
|
+
* cache() boundary, a ppr or Prerender route): no unit at or below it.
|
|
74
|
+
*/
|
|
75
|
+
readonly storedFrom: number;
|
|
76
|
+
/** The segment ids the request listed as held (`_rsc_segments`). */
|
|
77
|
+
readonly held: ReadonlySet<string>;
|
|
78
|
+
/**
|
|
79
|
+
* Segment ids of the handler units this prefetch skips: every unit that is
|
|
80
|
+
* not stored and not held. Empty outside a prefetch.
|
|
81
|
+
*/
|
|
82
|
+
readonly skipped: ReadonlySet<string>;
|
|
83
|
+
/** How this request may use the route's cache() record (recordUse). */
|
|
84
|
+
readonly record: RecordUse;
|
|
85
|
+
/** Segment id of the handler unit this prefetch skipped. */
|
|
86
|
+
deferredUnit?: string;
|
|
87
|
+
/**
|
|
88
|
+
* The walk is below a chain unit it skipped (resolution is in chain order,
|
|
89
|
+
* a route's orphan layouts and slots after its handler): every handler it
|
|
90
|
+
* reaches from here on is skipped too, and sends a placeholder with what
|
|
91
|
+
* the entry declares. The browser builds the page's tree once, from those
|
|
92
|
+
* (browser/partial-update.ts armHoles), so they have to list every segment
|
|
93
|
+
* a navigation to the page lists.
|
|
94
|
+
*/
|
|
95
|
+
below?: true;
|
|
96
|
+
/**
|
|
97
|
+
* The loaders this prefetch deferred, by `$$id` (registerDeferredLoader).
|
|
98
|
+
* A deferred loader runs only if something reads it: a handler's or another
|
|
99
|
+
* loader's ctx.use() starts it through its registration
|
|
100
|
+
* (startDeferredLoader), and revalidation.ts deliverStartedLoaders delivers
|
|
101
|
+
* what was started by the end of resolution.
|
|
102
|
+
*/
|
|
103
|
+
deferredLoaders?: Map<string, DeferredLoader>;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* How a request may use the route's cache() record, decided once per match
|
|
107
|
+
* (planPrefetchDeferral) for the cache middleware.
|
|
108
|
+
*/
|
|
109
|
+
export interface RecordUse {
|
|
110
|
+
/**
|
|
111
|
+
* withCacheLookup reads it. False when this prefetch skips a chain unit
|
|
112
|
+
* (PrefetchDeferral.skipped): the unit takes everything below it, so the
|
|
113
|
+
* read would replay the record's handle pushes for segments the response
|
|
114
|
+
* does not carry. Decided from what the client holds, never per tree: a
|
|
115
|
+
* prefetch that holds the flagged layout reads and writes the record like
|
|
116
|
+
* any other request.
|
|
117
|
+
*/
|
|
118
|
+
readonly read: boolean;
|
|
119
|
+
/** withCacheStore writes it. False where `read` is: the record would be incomplete. */
|
|
120
|
+
readonly write: boolean;
|
|
121
|
+
/**
|
|
122
|
+
* A background re-render of the whole route may write it: the stale-hit
|
|
123
|
+
* refresh (withBackgroundRevalidation) and the proactive write a partial
|
|
124
|
+
* response needs (withCacheStore). False for a fill: the re-render runs
|
|
125
|
+
* the handlers of segments the client holds, which a fill does not run.
|
|
126
|
+
*/
|
|
127
|
+
readonly refresh: boolean;
|
|
128
|
+
}
|
|
129
|
+
/** A loader this prefetch deferred: PrefetchDeferral.deferredLoaders. */
|
|
130
|
+
export interface DeferredLoader {
|
|
131
|
+
/**
|
|
132
|
+
* The segment that registers it. Its run files its handle pushes there,
|
|
133
|
+
* where a navigation's run of it files them, not under the reader
|
|
134
|
+
* (loaderOwner).
|
|
135
|
+
*/
|
|
136
|
+
readonly owner: string;
|
|
137
|
+
/**
|
|
138
|
+
* Starts it as resolution would have: resolveLoaderData with its cache()
|
|
139
|
+
* binding, so the reader and the delivered segment share one value.
|
|
140
|
+
*/
|
|
141
|
+
readonly start: () => Promise<unknown>;
|
|
142
|
+
/** A reader started it. */
|
|
143
|
+
started?: true;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* The deferral scope of a matched chain, memoized on its leaf entry (entries
|
|
147
|
+
* are per-isSSR manifest objects, replaced on HMR). EMPTY_SCOPE when nothing
|
|
148
|
+
* in the tree declares `prefetch: false`.
|
|
149
|
+
*/
|
|
150
|
+
export declare function resolveDeferralScope(entries: readonly EntryData[]): DeferralScope;
|
|
151
|
+
/**
|
|
152
|
+
* Which half of the feature a partial request is, if either (`fill` and
|
|
153
|
+
* `prefetch` are requestKind's answer). Both halves are GETs: a request of
|
|
154
|
+
* another method that carries either marker is a normal request. A prefetch
|
|
155
|
+
* defers only on a plain GET navigation: an action re-renders what it
|
|
156
|
+
* changed, an intercept resolves its loaders outside the shared funnel, and a
|
|
157
|
+
* shell capture is never a prefetch whatever the request that scheduled it
|
|
158
|
+
* sent. The four conditions overlap today (an action is a POST, a capture
|
|
159
|
+
* runs the full match): each one states its own reason.
|
|
160
|
+
*/
|
|
161
|
+
export declare function partialDeferralMode(request: {
|
|
162
|
+
fill: boolean;
|
|
163
|
+
prefetch: boolean;
|
|
164
|
+
method: string;
|
|
165
|
+
isAction: boolean;
|
|
166
|
+
isIntercept: boolean;
|
|
167
|
+
isShellCapture: boolean;
|
|
168
|
+
}): PrefetchDeferral["mode"];
|
|
169
|
+
/**
|
|
170
|
+
* The plan for one match, or undefined when the tree declares no flag and the
|
|
171
|
+
* request is not a fill (the common case: nothing to carry). `held` is the
|
|
172
|
+
* client's segment ids as the request listed them.
|
|
173
|
+
*/
|
|
174
|
+
export declare function planPrefetchDeferral(entries: readonly EntryData[], mode: PrefetchDeferral["mode"], matched: {
|
|
175
|
+
pr?: boolean;
|
|
176
|
+
od?: boolean;
|
|
177
|
+
}, cacheScope: CacheScope | null | undefined, held?: ReadonlySet<string>): PrefetchDeferral | undefined;
|
|
178
|
+
export declare function getPrefetchDeferral(ctx: HandlerContext<any, any> | undefined): PrefetchDeferral | undefined;
|
|
179
|
+
/** The request is a fill: a held segment is skipped without consulting anything. */
|
|
180
|
+
export declare function isFillRequest(ctx: HandlerContext<any, any>): boolean;
|
|
181
|
+
/**
|
|
182
|
+
* A fill's whole revalidation rule (R5): send a segment the client does not
|
|
183
|
+
* hold, keep one it holds, and consult nothing else (no revalidate()
|
|
184
|
+
* predicate, no params or search comparison, no trace entry). Undefined on
|
|
185
|
+
* any other request, where revalidation decides. `held` is the set the
|
|
186
|
+
* deciding site resolves with.
|
|
187
|
+
*/
|
|
188
|
+
export declare function fillSends(ctx: HandlerContext<any, any>, segmentId: string, held: ReadonlySet<string>): boolean | undefined;
|
|
189
|
+
/** PrefetchDeferral.record, or all of it open when the match has no plan. */
|
|
190
|
+
export declare function recordUse(ctx: HandlerContext<any, any> | undefined): RecordUse;
|
|
191
|
+
/**
|
|
192
|
+
* Register a loader this prefetch deferred, with the segment that registers
|
|
193
|
+
* it and how to start it there (PrefetchDeferral.deferredLoaders). The first
|
|
194
|
+
* registration wins, as the loader's one run per request does.
|
|
195
|
+
*/
|
|
196
|
+
export declare function registerDeferredLoader(ctx: HandlerContext<any, any>, loaderId: string, owner: string, start: () => Promise<unknown>): void;
|
|
197
|
+
/**
|
|
198
|
+
* A reader asks for a loader this prefetch deferred and nothing has started:
|
|
199
|
+
* start it through its registration and return the run, or undefined when
|
|
200
|
+
* the read takes the ordinary path. Without this the reader ran the loader
|
|
201
|
+
* bare, without its cache() binding, and the segment delivered afterwards
|
|
202
|
+
* read the binding: two values on one page and an extra run on a HIT.
|
|
203
|
+
*
|
|
204
|
+
* A started cache() binding of the loader (`_loaderCacheOverrides`) is never
|
|
205
|
+
* redirected here: the read is that binding's own MISS execution, and
|
|
206
|
+
* starting the registration would hand the binding its own pending value.
|
|
207
|
+
*/
|
|
208
|
+
export declare function startDeferredLoader(ctx: HandlerContext<any, any>, loaderId: string): Promise<unknown> | undefined;
|
|
209
|
+
/**
|
|
210
|
+
* The segment a run of `loaderId` files its handle pushes under: the one
|
|
211
|
+
* that registers it when this prefetch deferred it, else the segment being
|
|
212
|
+
* resolved.
|
|
213
|
+
*/
|
|
214
|
+
export declare function loaderOwner(ctx: HandlerContext<any, any>, loaderId: string): string | undefined;
|
|
215
|
+
/**
|
|
216
|
+
* This prefetch defers `loaderEntry`, whose segment is `segmentId`: the client
|
|
217
|
+
* does not hold that segment, and the loader is flagged itself or sits behind
|
|
218
|
+
* the fallback of a flagged entry the client does not hold either. Under a
|
|
219
|
+
* flagged layout the client holds, a new route's loaders run.
|
|
220
|
+
*/
|
|
221
|
+
export declare function defersLoader(ctx: HandlerContext<any, any>, loaderEntry: LoaderEntry, segmentId: string): boolean;
|
|
222
|
+
/**
|
|
223
|
+
* This prefetch skips the handler of the entry whose segment is `segmentId`:
|
|
224
|
+
* a unit the client does not hold, or anything the client does not hold
|
|
225
|
+
* below one (belowDeferredUnit). A held segment that re-renders is rendered
|
|
226
|
+
* by the prefetch, as by a navigation.
|
|
227
|
+
*/
|
|
228
|
+
export declare function defersUnit(ctx: HandlerContext<any, any>, segmentId: string): boolean;
|
|
229
|
+
/**
|
|
230
|
+
* `segmentId` is new to the client and the walk is below a chain unit this
|
|
231
|
+
* prefetch skipped (PrefetchDeferral.below). Nothing of such a segment runs
|
|
232
|
+
* in the prefetch, a slot's revalidate() predicates included: on a new
|
|
233
|
+
* segment they cannot change the outcome, and what they would read from
|
|
234
|
+
* context was set by handlers that did not run.
|
|
235
|
+
*/
|
|
236
|
+
export declare function belowDeferredUnit(ctx: HandlerContext<any, any>, segmentId: string): boolean;
|
|
237
|
+
/**
|
|
238
|
+
* A unit candidate that is not stored: a prefetch of this tree can skip a
|
|
239
|
+
* handler. Returns its entry (the first in chain order), for the
|
|
240
|
+
* ctx.rendered() guards (loader-resolution.ts).
|
|
241
|
+
*/
|
|
242
|
+
export declare function firstUnitCandidate(plan: PrefetchDeferral): EntryData | undefined;
|
|
243
|
+
/**
|
|
244
|
+
* Record the handler unit this prefetch skipped. A `chain` entry takes what
|
|
245
|
+
* the walk reaches after it (PrefetchDeferral.below); a slot is skipped
|
|
246
|
+
* alone.
|
|
247
|
+
*/
|
|
248
|
+
export declare function markUnitDeferred(ctx: HandlerContext<any, any>, segmentId: string, chain?: boolean): void;
|
|
249
|
+
/**
|
|
250
|
+
* Whether this prefetch skips the handler of the unit whose segment is
|
|
251
|
+
* `segmentId`, recorded: the flag the segment carries
|
|
252
|
+
* (ResolvedSegment.deferred), or undefined when the handler runs.
|
|
253
|
+
* - `chain`: a chain entry, its own unit or below one (defersUnit). The walk
|
|
254
|
+
* takes what it reaches after it (markUnitDeferred).
|
|
255
|
+
* - `slot`: a slot that is its own unit, skipped alone.
|
|
256
|
+
* - `below`: what the walk reaches below a chain unit it skipped
|
|
257
|
+
* (belowDeferredUnit): a slot, before its predicates run, and an orphan
|
|
258
|
+
* layout, which is never a unit of its own (resolveDeferralScope). The unit
|
|
259
|
+
* above is recorded already.
|
|
260
|
+
*/
|
|
261
|
+
export declare function deferUnit(ctx: HandlerContext<any, any>, segmentId: string, kind: "chain" | "slot" | "below"): {
|
|
262
|
+
readonly deferred: true;
|
|
263
|
+
} | undefined;
|
|
264
|
+
export {};
|
|
@@ -21,6 +21,17 @@ import type { Theme } from "../theme/types.js";
|
|
|
21
21
|
* derived-context store.
|
|
22
22
|
*/
|
|
23
23
|
export declare function buildFullPayload(m: MatchResult, ctx: HandlerContext<any>, url: URL, reqCtx: RequestContext<any>, handleStore: HandleStore): RscPayload;
|
|
24
|
+
/**
|
|
25
|
+
* The URL a render shows as the page's location (payload `pathname`, the SSR
|
|
26
|
+
* search and origin seed). For a request middleware rewrote, the visitor's
|
|
27
|
+
* URL, so the server markup and the hydrating client (which reads the address
|
|
28
|
+
* bar) agree on `usePathname()` and `useSearchParams()`. A render other
|
|
29
|
+
* visitors may be served shows `url`, the target, as a direct visit does: a
|
|
30
|
+
* shell capture, and a render the document cache stores (its key is the
|
|
31
|
+
* target). A render that shows the visitor's URL marks
|
|
32
|
+
* `_payloadVisitorLocation`, and the document cache does not store it.
|
|
33
|
+
*/
|
|
34
|
+
export declare function renderedLocation(reqCtx: Pick<RequestContext<any>, "_variables" | "_shellCaptureRun" | "_documentCacheRender" | "_payloadVisitorLocation" | "res"> | undefined, url: URL): URL;
|
|
24
35
|
/**
|
|
25
36
|
* The theme a document payload carries as `metadata.initialTheme` (the
|
|
26
37
|
* ThemeProvider's first state), read with no identity guard: it is the
|
|
@@ -6,4 +6,37 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import type { CreateRSCHandlerOptions } from "./types.js";
|
|
8
8
|
import type { RouterRequestInput } from "../router/router-interfaces.js";
|
|
9
|
+
/**
|
|
10
|
+
* Create an RSC request handler.
|
|
11
|
+
*
|
|
12
|
+
* **Recommended:** Use `router.createHandler()` instead for simpler setup:
|
|
13
|
+
* ```tsx
|
|
14
|
+
* const router = createRouter({ document, urls, nonce: () => true });
|
|
15
|
+
* export const fetch = router.createHandler();
|
|
16
|
+
* ```
|
|
17
|
+
*
|
|
18
|
+
* This function is still useful for advanced cases like per-request cache
|
|
19
|
+
* configuration (e.g., Cloudflare Workers with ExecutionContext).
|
|
20
|
+
*
|
|
21
|
+
* @example Basic usage (deps and loadSSRModule have sensible defaults)
|
|
22
|
+
* ```tsx
|
|
23
|
+
* import { createRSCHandler } from "@rangojs/router/rsc";
|
|
24
|
+
* import { router } from "./router.js";
|
|
25
|
+
*
|
|
26
|
+
* export default createRSCHandler({ router });
|
|
27
|
+
* ```
|
|
28
|
+
*
|
|
29
|
+
* @example With custom deps (advanced)
|
|
30
|
+
* ```tsx
|
|
31
|
+
* import { createRSCHandler } from "@rangojs/router/rsc";
|
|
32
|
+
* import * as rsc from "@vitejs/plugin-rsc/rsc/server";
|
|
33
|
+
* import { router } from "./router.js";
|
|
34
|
+
*
|
|
35
|
+
* export default createRSCHandler({
|
|
36
|
+
* router,
|
|
37
|
+
* deps: rsc,
|
|
38
|
+
* loadSSRModule: () => import.meta.viteRsc.loadModule("ssr", "index"),
|
|
39
|
+
* });
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
9
42
|
export declare function createRSCHandler<TEnv = unknown, TRoutes extends Record<string, string> = Record<string, string>>(options: CreateRSCHandlerOptions<TEnv, TRoutes>): (incomingRequest: Request, input?: RouterRequestInput<TEnv>) => Promise<Response>;
|
|
@@ -31,6 +31,14 @@ export declare function hasBodyContent(body: FormData | string): boolean;
|
|
|
31
31
|
* Also triggers any registered onResponse callbacks.
|
|
32
32
|
*/
|
|
33
33
|
export declare function createResponseWithMergedHeaders(body: BodyInit | null, init: ResponseInit): Response;
|
|
34
|
+
/**
|
|
35
|
+
* An empty 200 carrying X-RSC-Reload: the client turns it into a document
|
|
36
|
+
* navigation (window.location.href). It points at the visitor's URL: the
|
|
37
|
+
* first URL of a rewritten request (server/rewrite-trail.ts visitorUrl),
|
|
38
|
+
* else `url` with the internal `_rsc*` params stripped, or `url` as given
|
|
39
|
+
* when it is a string the caller resolved (an action's referer).
|
|
40
|
+
*/
|
|
41
|
+
export declare function createReloadResponse(reqCtx: RequestContext<any> | undefined, url: URL | string): Response;
|
|
34
42
|
/**
|
|
35
43
|
* Rebuild a Response returned or thrown by a response-route handler so request
|
|
36
44
|
* effects merge consistently in production and the public dispatch primitive.
|
|
@@ -11,4 +11,20 @@
|
|
|
11
11
|
* has already extracted params from it.
|
|
12
12
|
*/
|
|
13
13
|
import type { HandlerContext } from "./handler-context.js";
|
|
14
|
+
export interface LoaderErrorMeta<TEnv> {
|
|
15
|
+
request: Request;
|
|
16
|
+
url: URL;
|
|
17
|
+
env: TEnv;
|
|
18
|
+
loaderId: string;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* A text/x-component Response carrying `{ loaderResult: null, loaderError }`,
|
|
22
|
+
* the payload `load()` turns into a rejection with `loaderError.message`. A
|
|
23
|
+
* plain-text body would reject with React's opaque "Connection closed.".
|
|
24
|
+
* Render failures report through onError("rendering").
|
|
25
|
+
*/
|
|
26
|
+
export declare function renderLoaderError<TEnv>(ctx: HandlerContext<TEnv>, loaderError: {
|
|
27
|
+
message: string;
|
|
28
|
+
name: string;
|
|
29
|
+
}, status: number, meta: LoaderErrorMeta<TEnv>): Response;
|
|
14
30
|
export declare function handleLoaderFetch<TEnv>(ctx: HandlerContext<TEnv>, request: Request, env: TEnv, url: URL, variables: Record<string, any>, routeParams?: Record<string, string>): Promise<Response>;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The pass loop that honors `throw rewrite()` (route-definition/rewrite.ts):
|
|
3
|
+
* one catch around the global middleware chain moves the same request
|
|
4
|
+
* context to the target (server/request-context.ts rebaseRequestContext) and
|
|
5
|
+
* runs the request again from the top, as a direct visit to the target
|
|
6
|
+
* would run it. Shared by the request handler (rsc/handler.ts) and the
|
|
7
|
+
* dispatch testing primitive, so the two cannot drift.
|
|
8
|
+
*/
|
|
9
|
+
import { type Rewrite } from "../route-definition/rewrite.js";
|
|
10
|
+
import { type RequestContext } from "../server/request-context.js";
|
|
11
|
+
/** Response header naming the route path a rewritten request rendered. */
|
|
12
|
+
export declare const REWRITE_HEADER = "x-rango-rewrite";
|
|
13
|
+
/**
|
|
14
|
+
* Resolve a rewrite's target against the router's route map (global names,
|
|
15
|
+
* no param auto-fill, as middleware `ctx.reverse`) and the request origin.
|
|
16
|
+
* A path is basename-prefixed like `redirect()` and must stay under the
|
|
17
|
+
* basename once normalized (`/../admin` cannot step out of it). The
|
|
18
|
+
* target's own `_rsc*` params are dropped: only the visitor's transport
|
|
19
|
+
* params carry over. Throws for an unknown name, a missing param, another
|
|
20
|
+
* origin or a path outside the basename.
|
|
21
|
+
*/
|
|
22
|
+
export declare function resolveRewriteTarget(rewrite: Rewrite, routeMap: Record<string, string>, base: URL, basename?: string): URL;
|
|
23
|
+
/** The next pass of a rewritten request. */
|
|
24
|
+
export interface RewritePass {
|
|
25
|
+
request: Request;
|
|
26
|
+
/** The pass's raw URL, `_rsc*` params included. */
|
|
27
|
+
url: URL;
|
|
28
|
+
/** The target's clean URL. */
|
|
29
|
+
target: URL;
|
|
30
|
+
hops: number;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Move the request context to `rewrite`'s target for the next pass: check
|
|
34
|
+
* that this request can be rewritten, resolve the target, count the hop,
|
|
35
|
+
* then rebase the context. Throws the site error for a mutation or a loader
|
|
36
|
+
* fetch, a resolution error, and RewriteLoopError.
|
|
37
|
+
*/
|
|
38
|
+
export declare function applyRewrite(rewrite: Rewrite, passRequest: Request, reqCtx: RequestContext<any>, routeMap: Record<string, string>, basename: string | undefined): RewritePass;
|
|
39
|
+
/** The response to a rewrite loop. */
|
|
40
|
+
export declare function loopDetectedResponse(): Response;
|
|
41
|
+
export interface RewritePassesOptions {
|
|
42
|
+
reqCtx: RequestContext<any>;
|
|
43
|
+
/** The visitor's request and raw URL: the first pass. */
|
|
44
|
+
request: Request;
|
|
45
|
+
url: URL;
|
|
46
|
+
routeMap: () => Record<string, string>;
|
|
47
|
+
basename: string | undefined;
|
|
48
|
+
/** One pass: the global chain matched on `url`'s path around the core handler. */
|
|
49
|
+
runPass: (request: Request, url: URL) => Promise<Response>;
|
|
50
|
+
/** After a hop moved the context to its target. */
|
|
51
|
+
onHop?: (pass: RewritePass) => void;
|
|
52
|
+
/** Report a rewrite the request cannot take (onError, phase "routing"). */
|
|
53
|
+
report: (error: unknown, at: {
|
|
54
|
+
request: Request;
|
|
55
|
+
url: URL;
|
|
56
|
+
}) => void;
|
|
57
|
+
/**
|
|
58
|
+
* The response for a refused rewrite other than a loop (a loader fetch's
|
|
59
|
+
* error response); undefined rethrows the error.
|
|
60
|
+
*/
|
|
61
|
+
refuse?: (error: unknown, rewrite: Rewrite) => Response | undefined;
|
|
62
|
+
}
|
|
63
|
+
export interface RewritePassesResult {
|
|
64
|
+
response: Response;
|
|
65
|
+
/** The pathname the final pass rendered, when a rewrite took the request there. */
|
|
66
|
+
rewrittenTo?: string;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Run the request pass by pass until one produces a response. A `Rewrite`
|
|
70
|
+
* that unwinds a pass moves the context to its target and runs the next;
|
|
71
|
+
* a loop answers 508; a rewrite the request cannot take is reported and
|
|
72
|
+
* becomes `refuse`'s response, or is thrown.
|
|
73
|
+
*/
|
|
74
|
+
export declare function runRewritePasses(opts: RewritePassesOptions): Promise<RewritePassesResult>;
|
|
@@ -23,8 +23,10 @@ export declare const SSR_SETUP_VAR = "__ssrSetup";
|
|
|
23
23
|
* lazily so stores created after kickoff are still captured). Without a
|
|
24
24
|
* getter the promises run bare — no `.then()` microtasks, no
|
|
25
25
|
* `performance.now()` calls — keeping the non-debug hot path lean.
|
|
26
|
+
* `ssrModule` reuses a load already started (a rewritten request's earlier
|
|
27
|
+
* pass).
|
|
26
28
|
*/
|
|
27
|
-
export declare function startSSRSetup<TEnv>(ctx: HandlerContext<TEnv>, request: Request, env: TEnv, url: URL, getMetricsStore?: () => MetricsStore | undefined): Promise<SSRSetup>;
|
|
29
|
+
export declare function startSSRSetup<TEnv>(ctx: HandlerContext<TEnv>, request: Request, env: TEnv, url: URL, getMetricsStore?: () => MetricsStore | undefined, ssrModule?: Promise<SSRModule>): Promise<SSRSetup>;
|
|
28
30
|
export interface SsrHtmlStageOptions<TEnv> {
|
|
29
31
|
ctx: HandlerContext<TEnv>;
|
|
30
32
|
request: Request;
|
|
@@ -84,6 +84,13 @@ export type EntryPropDatas = {
|
|
|
84
84
|
*/
|
|
85
85
|
export type EntryPropRender = {
|
|
86
86
|
loading?: ReactNode | false;
|
|
87
|
+
/**
|
|
88
|
+
* loading(fallback, { prefetch: false }) with a renderable fallback: a
|
|
89
|
+
* prefetch defers what the fallback covers while the entry's segment is
|
|
90
|
+
* new to the client (router/segment-resolution/prefetch-deferral.ts). Set
|
|
91
|
+
* on both DSL evaluations, whatever `ssr` did to `loading`.
|
|
92
|
+
*/
|
|
93
|
+
loadingPrefetch?: false;
|
|
87
94
|
transition?: TransitionConfig;
|
|
88
95
|
};
|
|
89
96
|
/**
|
|
@@ -116,6 +123,12 @@ export type LoaderEntry = {
|
|
|
116
123
|
* navigation evaluation never has it.
|
|
117
124
|
*/
|
|
118
125
|
bake?: true;
|
|
126
|
+
/**
|
|
127
|
+
* loader(Def, { prefetch: false }): a prefetch defers this registration
|
|
128
|
+
* while its segment is new to the client
|
|
129
|
+
* (router/segment-resolution/prefetch-deferral.ts).
|
|
130
|
+
*/
|
|
131
|
+
prefetch?: false;
|
|
119
132
|
};
|
|
120
133
|
/**
|
|
121
134
|
* Segments state for intercept context
|
|
@@ -668,7 +681,14 @@ export declare function assertCachedHeaderWriteAllowed(surface: string, surfaceP
|
|
|
668
681
|
* are bypassed because loaders are always fresh (never cached) and
|
|
669
682
|
* their side effects (setCookie, header, etc.) are safe.
|
|
670
683
|
*/
|
|
671
|
-
export declare function runInsideLoaderScope<T>(fn: () => T): T;
|
|
684
|
+
export declare function runInsideLoaderScope<T>(fn: () => T, loaderId?: string): T;
|
|
685
|
+
/**
|
|
686
|
+
* The loader whose run a handle push here belongs to, for the browser's
|
|
687
|
+
* merge of a partial response (handles/pushed-by.ts): the DSL loader
|
|
688
|
+
* this scope resolves, else the outermost loader body around the push (a
|
|
689
|
+
* loader a handler reads with ctx.use). Undefined for a handler's own push.
|
|
690
|
+
*/
|
|
691
|
+
export declare function getHandlePushOwner(): string | undefined;
|
|
672
692
|
/**
|
|
673
693
|
* Run `fn` inside a loader BODY scope. Marks loader-function execution for the
|
|
674
694
|
* cache() purity guard only (isInsideCacheScope), WITHOUT affecting
|
|
@@ -186,7 +186,8 @@ export interface HandleStore {
|
|
|
186
186
|
* nav/action payloads, whose consumer applies each yield progressively) or
|
|
187
187
|
* "settled" (the document lane, whose consumers drain to completion in
|
|
188
188
|
* blocking positions and must not wait on loader bodies).
|
|
189
|
-
* Each yield contains the full accumulated state (not just the delta)
|
|
189
|
+
* Each yield contains the full accumulated state (not just the delta),
|
|
190
|
+
* with the pushedBy records of its buckets (handles/pushed-by.ts).
|
|
190
191
|
* Safe for concurrent consumers (per-consumer version cursor).
|
|
191
192
|
* The "settled" lane of a frozen store (freezeDocumentSnapshot) yields the
|
|
192
193
|
* frozen state once, at once, and ends. That yield is the store's own
|
|
@@ -212,6 +213,13 @@ export interface HandleStore {
|
|
|
212
213
|
* time (see push); see captureHandles.
|
|
213
214
|
*/
|
|
214
215
|
getDataForSegment(segmentId: string, excludeLoaderPushes?: boolean): Record<string, unknown[]>;
|
|
216
|
+
/**
|
|
217
|
+
* The loader whose run pushed each value in getDataForSegment(segmentId,
|
|
218
|
+
* excludeLoaderPushes), index-aligned per handle (null: the handler's).
|
|
219
|
+
* Handles without such a value are omitted; undefined when none has one.
|
|
220
|
+
* The browser's pushedBy record (handles/pushed-by.ts).
|
|
221
|
+
*/
|
|
222
|
+
getPushedBy(segmentId: string, excludeLoaderPushes?: boolean): Record<string, (string | null)[]> | undefined;
|
|
215
223
|
/**
|
|
216
224
|
* The push `owner` of each value in getDataForSegment(segmentId, true),
|
|
217
225
|
* index-aligned per handle (null: no owner). Handles without an owned
|