@rangojs/router 0.27.0 → 0.28.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 +1 -1
- package/dist/types/__internal.d.ts +7 -1
- package/dist/types/browser/event-controller.d.ts +2 -1
- package/dist/types/browser/history-state.d.ts +3 -9
- package/dist/types/browser/navigation-store.d.ts +8 -6
- package/dist/types/browser/react/filter-segment-order.d.ts +2 -2
- package/dist/types/browser/segment-reconciler.d.ts +6 -4
- package/dist/types/browser/types.d.ts +2 -1
- package/dist/types/browser/wire-protocol.d.ts +25 -0
- package/dist/types/cache/cache-key-utils.d.ts +11 -5
- package/dist/types/cache/cache-scope.d.ts +34 -22
- package/dist/types/cache/cf/cf-cache-constants.d.ts +2 -2
- package/dist/types/cache/cf/cf-cache-store.d.ts +47 -65
- package/dist/types/cache/cf/cf-kv-utils.d.ts +1 -1
- package/dist/types/cache/handle-snapshot.d.ts +9 -4
- package/dist/types/cache/segment-codec.d.ts +14 -0
- package/dist/types/cache/shell-snapshot.d.ts +1 -1
- package/dist/types/cache/tag-invalidation.d.ts +10 -0
- package/dist/types/cache/taint.d.ts +5 -3
- package/dist/types/cache/types.d.ts +7 -3
- package/dist/types/cache/vercel/vercel-cache-store.d.ts +8 -6
- package/dist/types/prefetch-markers.d.ts +5 -14
- package/dist/types/prerender/store.d.ts +31 -0
- package/dist/types/prerender/warm-request.d.ts +3 -3
- package/dist/types/prerender.d.ts +2 -2
- package/dist/types/route-name.d.ts +5 -0
- package/dist/types/router/error-handling.d.ts +4 -4
- package/dist/types/router/instrument.d.ts +4 -3
- package/dist/types/router/intercept-resolution.d.ts +25 -9
- package/dist/types/router/match-context.d.ts +4 -11
- package/dist/types/router/match-handlers.d.ts +2 -6
- package/dist/types/router/match-middleware/background-revalidation.d.ts +10 -20
- package/dist/types/router/match-middleware/cache-lookup.d.ts +34 -86
- package/dist/types/router/match-middleware/segment-resolution.d.ts +8 -6
- package/dist/types/router/prerender-match.d.ts +21 -6
- package/dist/types/router/preview-match.d.ts +2 -7
- package/dist/types/router/request-classification.d.ts +5 -0
- package/dist/types/router/router-context.d.ts +7 -46
- package/dist/types/router/router-interfaces.d.ts +8 -14
- package/dist/types/router/segment-resolution/loader-cache.d.ts +3 -3
- package/dist/types/router/segment-resolution/loader-mask.d.ts +4 -4
- package/dist/types/router/segment-resolution/prefetch-deferral.d.ts +20 -18
- package/dist/types/router/segment-resolution/resolution-pass.d.ts +93 -0
- package/dist/types/router/segment-resolution/revalidation.d.ts +82 -31
- package/dist/types/router/segment-resolution.d.ts +1 -2
- package/dist/types/router/segment-wrappers.d.ts +11 -48
- package/dist/types/router/telemetry.d.ts +2 -0
- package/dist/types/router/types.d.ts +10 -0
- package/dist/types/rsc/full-payload.d.ts +2 -2
- package/dist/types/rsc/handler-context.d.ts +6 -6
- package/dist/types/rsc/json-route-result.d.ts +5 -9
- package/dist/types/rsc/request-stages.d.ts +203 -0
- package/dist/types/rsc/response-cache-serve.d.ts +7 -12
- package/dist/types/rsc/response-route-handler.d.ts +2 -2
- package/dist/types/rsc/routine-plan.d.ts +1 -1
- package/dist/types/rsc/server-action.d.ts +2 -2
- package/dist/types/rsc/shell-capture-constants.d.ts +1 -1
- package/dist/types/rsc/shell-capture.d.ts +132 -15
- package/dist/types/rsc/shell-serve.d.ts +37 -12
- package/dist/types/server/context.d.ts +9 -8
- package/dist/types/server/handle-store.d.ts +16 -0
- package/dist/types/server/render-pass.d.ts +72 -0
- package/dist/types/server/request-context.d.ts +24 -104
- package/dist/types/server/rewrite-trail.d.ts +2 -2
- package/dist/types/testing/dispatch.d.ts +35 -18
- package/dist/types/types/cache-types.d.ts +6 -3
- package/dist/types/types/error-types.d.ts +9 -1
- package/dist/types/types/handler-context.d.ts +9 -1
- package/dist/types/types/segments.d.ts +1 -1
- package/dist/types/vite/discovery/build-discovery-phase.d.ts +40 -0
- package/dist/types/vite/discovery/build-env.d.ts +22 -0
- package/dist/types/vite/discovery/bundle-scan-phase.d.ts +12 -0
- package/dist/types/vite/discovery/dev-prerender-cache.d.ts +3 -2
- package/dist/types/vite/discovery/dev-server-phase.d.ts +26 -0
- package/dist/types/vite/discovery/discovery-errors.d.ts +1 -1
- package/dist/types/vite/discovery/state.d.ts +12 -0
- package/dist/types/vite/plugins/version-plugin.d.ts +1 -1
- package/dist/types/vite/plugins/virtual-entries.d.ts +1 -1
- package/dist/types/vite/router-discovery.d.ts +8 -47
- package/dist/types/vite/temp-rsc-server.d.ts +39 -0
- package/dist/types/vite/utils/prerender-utils.d.ts +9 -0
- package/dist/types/wire-params.d.ts +34 -0
- package/dist/vite/index.js +3809 -3710
- package/package.json +1 -1
- package/skills/cache-guide/SKILL.md +8 -5
- package/skills/caching/SKILL.md +37 -18
- package/skills/document-cache/SKILL.md +13 -1
- package/skills/handler-use/SKILL.md +1 -1
- package/skills/intercept/SKILL.md +17 -7
- package/skills/middleware/SKILL.md +18 -0
- package/skills/ppr/SKILL.md +18 -3
- package/skills/prerender/SKILL.md +39 -15
- package/skills/rango/SKILL.md +5 -1
- package/skills/server-actions/SKILL.md +8 -1
- package/skills/testing/response-routes.md +6 -4
- package/skills/use-cache/SKILL.md +46 -8
- package/src/__internal.ts +7 -1
- package/src/browser/connection-warmup.ts +3 -1
- package/src/browser/event-controller.ts +5 -3
- package/src/browser/history-state.ts +6 -12
- package/src/browser/navigation-bridge.ts +14 -13
- package/src/browser/navigation-client.ts +18 -25
- package/src/browser/navigation-store.ts +25 -27
- package/src/browser/navigation-transaction.ts +4 -1
- package/src/browser/prefetch/cache.ts +2 -1
- package/src/browser/prefetch/fetch.ts +8 -16
- package/src/browser/prefetch/queue.ts +4 -4
- package/src/browser/react/NavigationProvider.tsx +2 -1
- package/src/browser/react/filter-segment-order.ts +2 -2
- package/src/browser/rsc-router.tsx +1 -0
- package/src/browser/segment-reconciler.ts +66 -53
- package/src/browser/server-action-bridge.ts +50 -57
- package/src/browser/types.ts +2 -1
- package/src/browser/wire-protocol.ts +41 -0
- package/src/cache/cache-key-utils.ts +11 -5
- package/src/cache/cache-runtime.ts +110 -50
- package/src/cache/cache-scope.ts +110 -64
- package/src/cache/cf/cf-cache-constants.ts +2 -2
- package/src/cache/cf/cf-cache-store.ts +486 -874
- package/src/cache/cf/cf-kv-utils.ts +1 -1
- package/src/cache/document-cache.ts +34 -13
- package/src/cache/handle-snapshot.ts +19 -7
- package/src/cache/segment-codec.ts +55 -0
- package/src/cache/shell-snapshot.ts +2 -2
- package/src/cache/tag-invalidation.ts +21 -2
- package/src/cache/taint.ts +5 -3
- package/src/cache/types.ts +7 -3
- package/src/cache/vercel/vercel-cache-store.ts +243 -310
- package/src/handles/pushed-by.ts +1 -1
- package/src/prefetch-markers.ts +5 -16
- package/src/prerender/store.ts +76 -0
- package/src/prerender/warm-request.ts +8 -4
- package/src/prerender.ts +2 -2
- package/src/route-name.ts +8 -0
- package/src/router/error-handling.ts +4 -4
- package/src/router/instrument.ts +4 -3
- package/src/router/intercept-resolution.ts +77 -75
- package/src/router/loader-resolution.ts +5 -4
- package/src/router/match-api.ts +4 -5
- package/src/router/match-context.ts +20 -12
- package/src/router/match-handlers.ts +8 -20
- package/src/router/match-middleware/background-revalidation.ts +41 -53
- package/src/router/match-middleware/cache-lookup.ts +675 -726
- package/src/router/match-middleware/cache-store.ts +4 -8
- package/src/router/match-middleware/intercept-resolution.ts +3 -23
- package/src/router/match-middleware/segment-resolution.ts +34 -61
- package/src/router/middleware.ts +69 -11
- package/src/router/navigation-snapshot.ts +4 -4
- package/src/router/prerender-match.ts +100 -44
- package/src/router/preview-match.ts +6 -41
- package/src/router/request-classification.ts +13 -7
- package/src/router/route-snapshot.ts +2 -5
- package/src/router/router-context.ts +10 -95
- package/src/router/router-interfaces.ts +8 -14
- package/src/router/segment-resolution/loader-cache.ts +14 -9
- package/src/router/segment-resolution/loader-mask.ts +5 -5
- package/src/router/segment-resolution/prefetch-deferral.ts +30 -27
- package/src/router/segment-resolution/resolution-pass.ts +137 -0
- package/src/router/segment-resolution/revalidation.ts +897 -776
- package/src/router/segment-resolution.ts +4 -13
- package/src/router/segment-wrappers.ts +51 -269
- package/src/router/telemetry.ts +5 -0
- package/src/router/types.ts +10 -0
- package/src/router.ts +12 -13
- package/src/rsc/full-payload.ts +6 -5
- package/src/rsc/handler-context.ts +8 -14
- package/src/rsc/handler.ts +126 -507
- package/src/rsc/json-route-result.ts +5 -9
- package/src/rsc/loader-fetch.ts +6 -5
- package/src/rsc/progressive-enhancement.ts +5 -0
- package/src/rsc/request-stages.ts +757 -0
- package/src/rsc/response-cache-serve.ts +10 -14
- package/src/rsc/response-route-handler.ts +13 -5
- package/src/rsc/rewrite-passes.ts +2 -1
- package/src/rsc/routine-plan.ts +1 -1
- package/src/rsc/rsc-rendering.ts +164 -349
- package/src/rsc/server-action.ts +87 -113
- package/src/rsc/shell-capture-constants.ts +1 -1
- package/src/rsc/shell-capture.ts +212 -169
- package/src/rsc/shell-serve.ts +121 -18
- package/src/rsc/ssr-setup.ts +5 -4
- package/src/segment-system.tsx +3 -3
- package/src/server/context.ts +22 -25
- package/src/server/handle-store.ts +55 -0
- package/src/server/render-pass.ts +291 -0
- package/src/server/request-context.ts +26 -115
- package/src/server/rewrite-trail.ts +6 -4
- package/src/ssr/index.tsx +1 -1
- package/src/testing/dispatch.ts +223 -710
- package/src/testing/e2e/page-helpers.ts +2 -2
- package/src/testing/serve-shell-request.ts +23 -36
- package/src/types/cache-types.ts +6 -3
- package/src/types/error-types.ts +9 -1
- package/src/types/handler-context.ts +12 -1
- package/src/types/segments.ts +1 -1
- package/src/vite/discovery/build-discovery-phase.ts +204 -0
- package/src/vite/discovery/build-env.ts +148 -0
- package/src/vite/discovery/bundle-scan-phase.ts +128 -0
- package/src/vite/discovery/dev-prerender-cache.ts +8 -3
- package/src/vite/discovery/dev-server-phase.ts +1776 -0
- package/src/vite/discovery/discover-routers.ts +1 -1
- package/src/vite/discovery/discovery-errors.ts +1 -1
- package/src/vite/discovery/prerender-collection.ts +24 -39
- package/src/vite/discovery/state.ts +15 -0
- package/src/vite/plugins/version-plugin.ts +1 -1
- package/src/vite/plugins/virtual-entries.ts +1 -1
- package/src/vite/router-discovery.ts +29 -2428
- package/src/vite/temp-rsc-server.ts +223 -0
- package/src/vite/utils/prerender-utils.ts +47 -0
- package/src/wire-params.ts +35 -0
- package/dist/types/router/segment-resolution/fresh.d.ts +0 -72
- package/src/router/segment-resolution/fresh.ts +0 -945
|
@@ -1,51 +1,14 @@
|
|
|
1
|
-
import type { EntryData, InterceptEntry } from "../server/context";
|
|
2
|
-
import type { HandlerContext, ResolvedSegment, ShouldRevalidateFn } from "../types";
|
|
3
1
|
import type { SegmentResolutionDeps } from "./types.js";
|
|
4
|
-
import type {
|
|
5
|
-
import
|
|
6
|
-
|
|
7
|
-
export
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
actionId?: string;
|
|
12
|
-
actionUrl?: URL;
|
|
13
|
-
actionResult?: any;
|
|
14
|
-
formData?: FormData;
|
|
15
|
-
}, stale?: boolean) => Promise<{
|
|
16
|
-
segments: ResolvedSegment[];
|
|
17
|
-
matchedIds: string[];
|
|
18
|
-
}>;
|
|
19
|
-
buildEntryRevalidateMap: (entries: EntryData[]) => Map<string, {
|
|
20
|
-
entry: EntryData;
|
|
21
|
-
revalidate: ShouldRevalidateFn<any, any>[];
|
|
22
|
-
}>;
|
|
23
|
-
resolveAllSegmentsWithRevalidation: (entries: EntryData[], routeKey: string, params: Record<string, string>, context: HandlerContext<any, TEnv>, clientSegmentSet: Set<string>, prevParams: Record<string, string>, request: Request, prevUrl: URL, nextUrl: URL, actionContext: {
|
|
24
|
-
actionId?: string;
|
|
25
|
-
actionUrl?: URL;
|
|
26
|
-
actionResult?: any;
|
|
27
|
-
formData?: FormData;
|
|
28
|
-
} | undefined, interceptResult: {
|
|
29
|
-
intercept: InterceptEntry;
|
|
30
|
-
entry: EntryData;
|
|
31
|
-
} | null, localRouteName: string, pathname: string, stale?: boolean, chain?: readonly EntryData[]) => Promise<{
|
|
32
|
-
segments: ResolvedSegment[];
|
|
33
|
-
matchedIds: string[];
|
|
34
|
-
}>;
|
|
35
|
-
findInterceptForRoute: (targetRouteKey: string, fromEntry: EntryData | null, selectorContext?: InterceptSelectorContext | null, isAction?: boolean) => {
|
|
36
|
-
intercept: InterceptEntry;
|
|
37
|
-
entry: EntryData;
|
|
38
|
-
} | null;
|
|
39
|
-
resolveInterceptEntry: (interceptEntry: InterceptEntry, parentEntry: EntryData, params: Record<string, string>, context: HandlerContext<any, TEnv>, belongsToRoute?: boolean, revalidationContext?: any, options?: {
|
|
40
|
-
background?: boolean;
|
|
41
|
-
}) => Promise<ResolvedSegment[]>;
|
|
42
|
-
resolveInterceptLoadersOnly: (interceptEntry: InterceptEntry, parentEntry: EntryData, context: HandlerContext<any, TEnv>, belongsToRoute: boolean, revalidationContext: RevalidationContext) => Promise<ResolvedSegment[]>;
|
|
43
|
-
}
|
|
2
|
+
import type { RouterContext } from "./router-context.js";
|
|
3
|
+
import { findInterceptForRoute as _findInterceptForRoute } from "./intercept-resolution.js";
|
|
4
|
+
/** The resolvers RouterContext exposes, with the router's deps bound. */
|
|
5
|
+
export type SegmentWrappers<TEnv = any> = Pick<RouterContext<TEnv>, "resolveAllSegments" | "resolveInterceptEntry"> & Required<Pick<RouterContext<TEnv>, "resolveLoadersOnly" | "buildEntryRevalidateMap" | "resolveInterceptLoadersOnly">> & {
|
|
6
|
+
/** Its own signature: a null selector context, isAction defaulting to false. */
|
|
7
|
+
findInterceptForRoute: typeof _findInterceptForRoute;
|
|
8
|
+
};
|
|
44
9
|
/**
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
* These maintain the same signatures as the original inline functions
|
|
49
|
-
* so that RouterContext and call sites don't need to change.
|
|
10
|
+
* Bind the router's segment deps into the extracted segment and intercept
|
|
11
|
+
* resolvers. Each gets a ResolutionPass: the caller's request-side input with
|
|
12
|
+
* the deps added here, once per call.
|
|
50
13
|
*/
|
|
51
|
-
export declare function createSegmentWrappers<TEnv = any>(
|
|
14
|
+
export declare function createSegmentWrappers<TEnv = any>(deps: SegmentResolutionDeps<TEnv>): SegmentWrappers<TEnv>;
|
|
@@ -208,6 +208,8 @@ export declare function safeEmit(sink: TelemetrySink, event: TelemetryEvent): vo
|
|
|
208
208
|
* Generated IDs use format "t-{base36}" to distinguish from header values.
|
|
209
209
|
*/
|
|
210
210
|
export declare function getRequestId(request: Request): string;
|
|
211
|
+
/** Make `id` the id getRequestId returns for `request`. */
|
|
212
|
+
export declare function setRequestId(request: Request, id: string): void;
|
|
211
213
|
/**
|
|
212
214
|
* Built-in console sink that logs events in a structured format.
|
|
213
215
|
* Designed as the default sink for development / debugging.
|
|
@@ -15,6 +15,16 @@ export type ActionContext = {
|
|
|
15
15
|
actionUrl?: URL;
|
|
16
16
|
actionResult?: any;
|
|
17
17
|
formData?: FormData;
|
|
18
|
+
/**
|
|
19
|
+
* A thrown action's error segment (matchError), set on the action's
|
|
20
|
+
* revalidation (rsc/server-action.ts matchBoundaryRevalidation). The walk
|
|
21
|
+
* (resolveAllSegments) resolves every entry above the segment's outlet as on
|
|
22
|
+
* a success, emits the segment in the outlet's place and stops, so nothing
|
|
23
|
+
* at or below the outlet runs. The pass skips the prerender store
|
|
24
|
+
* (cache-lookup.ts): the evicted handler is under the cut. No revalidate()
|
|
25
|
+
* predicate sees it.
|
|
26
|
+
*/
|
|
27
|
+
boundary?: ResolvedSegment;
|
|
18
28
|
};
|
|
19
29
|
export interface SegmentResolutionDeps<TEnv = any> {
|
|
20
30
|
wrapLoaderPromise: <T>(promise: Promise<T>, entry: EntryData, segmentId: string, pathname: string, errorContext?: {
|
|
@@ -32,7 +32,7 @@ export declare function buildFullPayload(m: MatchResult, ctx: HandlerContext<any
|
|
|
32
32
|
* visitor's URL. Any other render that shows the visitor's URL marks
|
|
33
33
|
* `_payloadVisitorLocation`, and the document cache does not store it.
|
|
34
34
|
*/
|
|
35
|
-
export declare function renderedLocation(reqCtx: Pick<RequestContext<any>, "_variables" | "
|
|
35
|
+
export declare function renderedLocation(reqCtx: Pick<RequestContext<any>, "_variables" | "_shellCaptureState" | "_documentCacheRender" | "_payloadVisitorLocation" | "res"> | undefined, url: URL): URL;
|
|
36
36
|
/**
|
|
37
37
|
* A payload's `pathname` (renderedLocation) and, when middleware rewrote the
|
|
38
38
|
* request, `rewriteTarget`: the path and search the route rendered (the
|
|
@@ -63,4 +63,4 @@ export declare function payloadLocation(reqCtx: Parameters<typeof renderedLocati
|
|
|
63
63
|
* default it marks `_payloadVisitorTheme`, and the document cache does not
|
|
64
64
|
* store the response.
|
|
65
65
|
*/
|
|
66
|
-
export declare function payloadInitialTheme(reqCtx: Pick<RequestContext<any>, "_themeConfig" | "
|
|
66
|
+
export declare function payloadInitialTheme(reqCtx: Pick<RequestContext<any>, "_themeConfig" | "_shellCaptureState" | "_readTheme" | "_documentCacheRender" | "_payloadVisitorTheme" | "res">): Theme | undefined;
|
|
@@ -6,11 +6,14 @@
|
|
|
6
6
|
* RSC rendering) so they can be standalone modules without closure coupling.
|
|
7
7
|
*/
|
|
8
8
|
import type { RangoInternal } from "../router/router-interfaces.js";
|
|
9
|
-
import type { ErrorPhase } from "../types.js";
|
|
10
|
-
import type { InvokeOnErrorContext } from "../router/error-handling.js";
|
|
11
9
|
import type { RSCDependencies, LoadSSRModule } from "./types.js";
|
|
12
10
|
import type { SSRStreamMode } from "../router/router-options.js";
|
|
13
|
-
|
|
11
|
+
import type { RequestStageContext } from "./request-stages.js";
|
|
12
|
+
/**
|
|
13
|
+
* Extends what the request stages (rsc/request-stages.ts) call back into, so
|
|
14
|
+
* the handler hands this one bundle to them as well.
|
|
15
|
+
*/
|
|
16
|
+
export interface HandlerContext<TEnv = unknown> extends RequestStageContext<TEnv> {
|
|
14
17
|
router: RangoInternal<TEnv, any>;
|
|
15
18
|
/**
|
|
16
19
|
* The router's DOCUMENT version (router-versions.ts): payload metadata, the
|
|
@@ -26,9 +29,6 @@ export interface HandlerContext<TEnv = unknown> {
|
|
|
26
29
|
decodeAction: RSCDependencies["decodeAction"];
|
|
27
30
|
decodeFormState: RSCDependencies["decodeFormState"];
|
|
28
31
|
loadSSRModule: LoadSSRModule;
|
|
29
|
-
callOnError: (error: unknown, phase: ErrorPhase, context: InvokeOnErrorContext<TEnv>) => void;
|
|
30
|
-
getRequiredRouteMap: () => Record<string, string>;
|
|
31
|
-
createRedirectFlightResponse: (redirectUrl: string, locationState?: Record<string, unknown>, external?: boolean) => Response;
|
|
32
32
|
/**
|
|
33
33
|
* Resolve the SSR stream mode for a given request.
|
|
34
34
|
* Returns "stream" when no resolveStreaming callback is configured.
|
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* Kept in its own lightweight module (depends only on `errors.js`) so the
|
|
5
|
-
* `dispatch()` testing primitive can import it WITHOUT dragging in
|
|
6
|
-
* `response-route-handler.ts`'s heavy runtime graph, which transitively reaches
|
|
7
|
-
* a Vite virtual module and breaks a plain (non-Vite) vitest import.
|
|
2
|
+
* Serialization for `json()` response-route results (depends only on
|
|
3
|
+
* `errors.js`).
|
|
8
4
|
*/
|
|
9
5
|
/**
|
|
10
6
|
* Serialize a `json()` response-route result, rejecting a nested unresolved
|
|
@@ -13,8 +9,8 @@
|
|
|
13
9
|
* the RSC pipeline awaits nested promises but this path does not. Throwing
|
|
14
10
|
* `RESPONSE_NOT_SERIALIZABLE` makes the failure loud.
|
|
15
11
|
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
12
|
+
* The `dispatch()` testing primitive runs the same response-route handler, so
|
|
13
|
+
* a `dispatch` json test of a forgotten await fails exactly where production
|
|
14
|
+
* 500s, instead of going green.
|
|
19
15
|
*/
|
|
20
16
|
export declare function stringifyJsonRouteResult(result: unknown): string;
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Request stages
|
|
3
|
+
*
|
|
4
|
+
* The stages a request runs through before and after rendering: classify,
|
|
5
|
+
* guard, the global middleware passes, the response route, and the
|
|
6
|
+
* response's finalization. The RSC handler (rsc/handler.ts createRSCHandler)
|
|
7
|
+
* runs them all around its Flight executor. The dispatch testing primitive
|
|
8
|
+
* (testing/dispatch.ts) runs classify, the terminal plans, the passes, the
|
|
9
|
+
* response route and the finalization, and throws where a plan would render
|
|
10
|
+
* a component. Sharing them keeps dispatch's responses identical to
|
|
11
|
+
* production's; a hand-kept mirror drifted once (#1128).
|
|
12
|
+
*
|
|
13
|
+
* No import of @vitejs/plugin-rsc on this graph: dispatch loads it in a
|
|
14
|
+
* plain Vitest project, where plugin-rsc's entries cannot load (they import
|
|
15
|
+
* Vite virtuals). testing/__tests__/testing-module-graph.test.ts pins it.
|
|
16
|
+
*/
|
|
17
|
+
import type { MiddlewareEntry } from "../router/middleware-types.js";
|
|
18
|
+
import { type RequestContext } from "../server/request-context.js";
|
|
19
|
+
import { type RewritePassesOptions, type RewritePassesResult } from "./rewrite-passes.js";
|
|
20
|
+
import { type ResponseRouteMatch } from "./response-route-handler.js";
|
|
21
|
+
import type { ErrorPhase } from "../types.js";
|
|
22
|
+
import type { OnErrorCallback } from "../types/error-types.js";
|
|
23
|
+
import { type InvokeOnErrorContext } from "../router/error-handling.js";
|
|
24
|
+
import type { OriginCheckPhase } from "./origin-guard.js";
|
|
25
|
+
import { type OnTimeoutCallback, type ResolvedTimeouts, type TimeoutPhase } from "../router/timeout.js";
|
|
26
|
+
import { type TelemetrySink } from "../router/telemetry.js";
|
|
27
|
+
import { type ClassifyRequestDeps, type ExecutableRequestPlan, type RequestPlan, type ResponseRoutePlan } from "../router/request-classification.js";
|
|
28
|
+
/**
|
|
29
|
+
* The router members the stages read. The handler's `RangoInternal` carries
|
|
30
|
+
* them; dispatch reads them off the router a test passes.
|
|
31
|
+
*/
|
|
32
|
+
export interface StageRouter<TEnv = unknown> {
|
|
33
|
+
readonly basename: string | undefined;
|
|
34
|
+
readonly middleware: MiddlewareEntry<TEnv>[];
|
|
35
|
+
readonly onError?: OnErrorCallback<TEnv>;
|
|
36
|
+
readonly telemetry?: TelemetrySink;
|
|
37
|
+
readonly timeouts?: ResolvedTimeouts;
|
|
38
|
+
readonly onTimeout?: OnTimeoutCallback<TEnv>;
|
|
39
|
+
}
|
|
40
|
+
/** Report an error through the router's onError. */
|
|
41
|
+
export type ReportError<TEnv = unknown> = (error: unknown, phase: ErrorPhase, context: InvokeOnErrorContext<TEnv>) => void;
|
|
42
|
+
/**
|
|
43
|
+
* What the stages call back into. The handler's context bundle
|
|
44
|
+
* (rsc/handler-context.ts HandlerContext) extends it.
|
|
45
|
+
*/
|
|
46
|
+
export interface RequestStageContext<TEnv = unknown> {
|
|
47
|
+
router: StageRouter<TEnv>;
|
|
48
|
+
callOnError: ReportError<TEnv>;
|
|
49
|
+
getRequiredRouteMap: () => Record<string, string>;
|
|
50
|
+
/**
|
|
51
|
+
* The redirect a partial or action request receives: a Flight payload in
|
|
52
|
+
* the handler (fetch() would follow a raw 3xx to HTML). dispatch has no
|
|
53
|
+
* Flight runtime and answers 204 + X-RSC-Redirect.
|
|
54
|
+
*/
|
|
55
|
+
createRedirectFlightResponse: (redirectUrl: string, locationState?: Record<string, unknown>, external?: boolean) => Response;
|
|
56
|
+
/**
|
|
57
|
+
* Reports a response-route handler's own throw; absent, it goes to
|
|
58
|
+
* callOnError with phase "handler". dispatch passes a no-op: it does not
|
|
59
|
+
* report that throw (its documented boundary, testing/dispatch.ts).
|
|
60
|
+
*/
|
|
61
|
+
reportResponseRouteError?: (error: unknown, context: InvokeOnErrorContext<TEnv>) => void;
|
|
62
|
+
}
|
|
63
|
+
/** What classify and the terminal plans read beyond the stage context. */
|
|
64
|
+
export interface ClassifyContext<TEnv = unknown> {
|
|
65
|
+
router: {
|
|
66
|
+
readonly id: string;
|
|
67
|
+
readonly findMatch: ClassifyRequestDeps<TEnv>["findMatch"];
|
|
68
|
+
};
|
|
69
|
+
/** The router's DOCUMENT version: the `_rsc_v` reload check. */
|
|
70
|
+
version: string;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Per-request error reporter that deduplicates via the ALS request context.
|
|
74
|
+
*
|
|
75
|
+
* Uses the same _reportedErrors WeakSet as the router layer so errors
|
|
76
|
+
* that propagate across layers are only reported once per request.
|
|
77
|
+
*/
|
|
78
|
+
export declare function createErrorReporter<TEnv>(router: {
|
|
79
|
+
readonly onError?: OnErrorCallback<TEnv>;
|
|
80
|
+
}): ReportError<TEnv>;
|
|
81
|
+
/**
|
|
82
|
+
* Wire background error reporting so "use cache" and other subsystems can
|
|
83
|
+
* surface non-fatal errors through the router's onError callback.
|
|
84
|
+
*/
|
|
85
|
+
export declare function reportBackgroundErrors<TEnv>(reqCtx: RequestContext<TEnv>, request: Request, url: URL, callOnError: ReportError<TEnv>): void;
|
|
86
|
+
/**
|
|
87
|
+
* Classify a request into its plan. classifyRequest throws
|
|
88
|
+
* RouteNotFoundError for an unknown route; that falls through to a
|
|
89
|
+
* full-render plan with no matched route, so the render path renders the
|
|
90
|
+
* 404 page (match()/matchPartial() re-throw and the render's catch renders
|
|
91
|
+
* it).
|
|
92
|
+
*/
|
|
93
|
+
export declare function classify<TEnv>(request: Request, url: URL, ctx: ClassifyContext<TEnv>): Promise<RequestPlan<TEnv>>;
|
|
94
|
+
/** The plan classify answers an unknown route with (the render path's 404). */
|
|
95
|
+
export declare function isUnmatchedPlan(plan: RequestPlan<any>): boolean;
|
|
96
|
+
/**
|
|
97
|
+
* Record a plan's route on the request context: its params and name, and the
|
|
98
|
+
* classified snapshot match()/matchPartial() reuse instead of resolving the
|
|
99
|
+
* route again. Runs inside the global chain, so global middleware sees the
|
|
100
|
+
* route after next(). A redirect has none.
|
|
101
|
+
*/
|
|
102
|
+
export declare function recordPlanRoute<TEnv>(plan: ExecutableRequestPlan<TEnv>): void;
|
|
103
|
+
/**
|
|
104
|
+
* The checks between classification and execution that need no await.
|
|
105
|
+
* Returns the response of a terminal plan (a partial request's redirect, a
|
|
106
|
+
* version or app-switch reload), null to go on. Throws for a rewritten
|
|
107
|
+
* action whose target is not a page route.
|
|
108
|
+
*
|
|
109
|
+
* Synchronous, and the origin guard is a separate step: the caller awaits
|
|
110
|
+
* checkRequestOrigin only for the modes ORIGIN_CHECK_PHASE_BY_MODE gates, so
|
|
111
|
+
* a full, partial or response plan reaches execution without an added
|
|
112
|
+
* microtask (rsc/__tests__/request-microtasks.rsc-test.tsx).
|
|
113
|
+
*/
|
|
114
|
+
export declare function terminalPlanResponse<TEnv>(plan: RequestPlan<TEnv>, url: URL, ctx: RequestStageContext<TEnv> & ClassifyContext<TEnv>): Response | null;
|
|
115
|
+
/**
|
|
116
|
+
* The origin guard's rejection: reports it through onError and telemetry,
|
|
117
|
+
* and returns the response checkRequestOrigin rejected the request with. The
|
|
118
|
+
* caller awaits checkRequestOrigin itself, for the modes
|
|
119
|
+
* ORIGIN_CHECK_PHASE_BY_MODE gates (action, loader, PE form), so the guard
|
|
120
|
+
* adds no microtask over that await.
|
|
121
|
+
*/
|
|
122
|
+
export declare function originRejectedResponse<TEnv>(rejection: Response, phase: OriginCheckPhase, request: Request, env: TEnv, url: URL, ctx: RequestStageContext<TEnv>): Response;
|
|
123
|
+
export interface RequestPassesOptions<TEnv> {
|
|
124
|
+
ctx: RequestStageContext<TEnv>;
|
|
125
|
+
reqCtx: RequestContext<TEnv>;
|
|
126
|
+
/** The visitor's request and raw URL: the first pass. */
|
|
127
|
+
request: Request;
|
|
128
|
+
url: URL;
|
|
129
|
+
env: TEnv;
|
|
130
|
+
variables: Record<string, any>;
|
|
131
|
+
/** The visitor's global middleware, when the caller matched it already. */
|
|
132
|
+
firstPassMiddleware?: Array<{
|
|
133
|
+
entry: MiddlewareEntry<TEnv>;
|
|
134
|
+
params: Record<string, string>;
|
|
135
|
+
}>;
|
|
136
|
+
/** Runs before a pass's global chain; dispatch matches the pass there. */
|
|
137
|
+
beforePass?: (request: Request, url: URL, index: number) => Promise<void>;
|
|
138
|
+
/** The core handler a pass's global chain wraps. */
|
|
139
|
+
core: (request: Request, url: URL) => Promise<Response>;
|
|
140
|
+
onHop?: RewritePassesOptions["onHop"];
|
|
141
|
+
refuse?: RewritePassesOptions["refuse"];
|
|
142
|
+
}
|
|
143
|
+
export interface RequestPassesResult extends RewritePassesResult {
|
|
144
|
+
/** Whether the last pass ran a global middleware chain. */
|
|
145
|
+
hasMiddleware: boolean;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* One pass per URL: the global middleware chain matched on the pass's path,
|
|
149
|
+
* wrapping the core handler. A `throw rewrite()` from global or route
|
|
150
|
+
* middleware unwinds the pass, and the next one runs the same request as
|
|
151
|
+
* the target from the top, as a direct visit would (rsc/rewrite-passes.ts).
|
|
152
|
+
*/
|
|
153
|
+
export declare function runRequestPasses<TEnv>(opts: RequestPassesOptions<TEnv>): Promise<RequestPassesResult>;
|
|
154
|
+
/**
|
|
155
|
+
* The flat match handleResponseRoute takes, with params at the top level,
|
|
156
|
+
* built from a response-route plan.
|
|
157
|
+
*/
|
|
158
|
+
export declare function responseRouteMatch(plan: ResponseRoutePlan<any>): ResponseRouteMatch;
|
|
159
|
+
export interface ServeResponseRouteOptions<TEnv> {
|
|
160
|
+
match: ResponseRouteMatch;
|
|
161
|
+
/** The matched route's key, for the timeout report. */
|
|
162
|
+
routeKey: string | undefined;
|
|
163
|
+
/** The pass's request, raw URL and env. */
|
|
164
|
+
request: Request;
|
|
165
|
+
url: URL;
|
|
166
|
+
env: TEnv;
|
|
167
|
+
variables: Record<string, any>;
|
|
168
|
+
/**
|
|
169
|
+
* Receives the handler's work when the deadline wins. The handler leaves
|
|
170
|
+
* it running; dispatch cancels its body.
|
|
171
|
+
*/
|
|
172
|
+
abandon?: (work: Promise<Response>) => void;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* A response route: its handler (rsc/response-route-handler.ts) under the
|
|
176
|
+
* renderStartMs deadline, which starts here, inside the global chain, so
|
|
177
|
+
* global middleware time never counts toward it.
|
|
178
|
+
*/
|
|
179
|
+
export declare function serveResponseRoute<TEnv>(ctx: RequestStageContext<TEnv>, opts: ServeResponseRouteOptions<TEnv>): Promise<Response>;
|
|
180
|
+
/**
|
|
181
|
+
* Handle a timeout by reporting the error, emitting telemetry,
|
|
182
|
+
* and returning either the custom onTimeout response or a default 504.
|
|
183
|
+
*/
|
|
184
|
+
export declare function timeoutResponse<TEnv>(ctx: RequestStageContext<TEnv>, request: Request, env: TEnv, url: URL, phase: TimeoutPhase, durationMs: number, routeKey?: string, actionId?: string): Promise<Response>;
|
|
185
|
+
export interface FinalizeRequestOptions<TEnv> {
|
|
186
|
+
ctx: RequestStageContext<TEnv>;
|
|
187
|
+
reqCtx: RequestContext<TEnv>;
|
|
188
|
+
/** The visitor's request, raw URL and env. */
|
|
189
|
+
request: Request;
|
|
190
|
+
url: URL;
|
|
191
|
+
env: TEnv;
|
|
192
|
+
/** runRequestPasses' result. */
|
|
193
|
+
hasMiddleware: boolean;
|
|
194
|
+
rewrittenTo?: string;
|
|
195
|
+
/** Runs on the response before the open-redirect guard. */
|
|
196
|
+
beforeGuard?: (response: Response) => void;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* The response the global chain returned, made ready to leave: a partial or
|
|
200
|
+
* action request's redirect converted, onResponse callbacks drained, the
|
|
201
|
+
* rewrite header, the open-redirect guard and the stream-idle watchdog.
|
|
202
|
+
*/
|
|
203
|
+
export declare function finalizeRequestResponse<TEnv>(downstream: Response, opts: FinalizeRequestOptions<TEnv>): Response;
|
|
@@ -5,23 +5,18 @@
|
|
|
5
5
|
* matched entry tree, condition eval, key resolution (route key() > store
|
|
6
6
|
* keyGenerator > default, CacheScope.resolveKeyFrom), tag resolution,
|
|
7
7
|
* pre-handler-callback timing, and the fresh-hit / SWR-revalidate /
|
|
8
|
-
* miss-write branches — for
|
|
9
|
-
*
|
|
10
|
-
*
|
|
8
|
+
* miss-write branches — for the response-route handler
|
|
9
|
+
* (rsc/response-route-handler.ts), which the production handler and the
|
|
10
|
+
* dispatch testing primitive both run (rsc/request-stages.ts
|
|
11
|
+
* serveResponseRoute), so the two can never drift.
|
|
11
12
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* testing barrel's EAGER graph (dispatch imports it). So `createCacheScope` is
|
|
15
|
-
* NOT imported here at runtime — it is INJECTED by the caller (production
|
|
16
|
-
* imports it statically; dispatch lazy-imports it only once a response route
|
|
17
|
-
* matches). The only runtime imports here are plugin-rsc-free
|
|
18
|
-
* (helpers' isCacheableStatus/finalizeResponse, traverseBack); cache-scope is a
|
|
19
|
-
* type-only import (erased at build).
|
|
13
|
+
* `createCacheScope` is injected by the caller: the response-route handler
|
|
14
|
+
* passes the real one, unit tests a stub.
|
|
20
15
|
*/
|
|
21
16
|
import type { CacheScope } from "../cache/cache-scope.js";
|
|
22
17
|
import { type RequestContext } from "../server/request-context.js";
|
|
23
18
|
import type { EntryCacheConfig, EntryData } from "../server/context.js";
|
|
24
|
-
/** Injected cache-scope builder
|
|
19
|
+
/** Injected cache-scope builder. */
|
|
25
20
|
export interface CacheScopeDeps {
|
|
26
21
|
createCacheScope: (config: EntryCacheConfig | undefined, parent?: CacheScope | null) => CacheScope | null;
|
|
27
22
|
}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import type { MiddlewareFn } from "../router/middleware.js";
|
|
9
9
|
import { type EntryData } from "../server/context.js";
|
|
10
|
-
import type {
|
|
10
|
+
import type { RequestStageContext } from "./request-stages.js";
|
|
11
11
|
export interface ResponseRouteMatch {
|
|
12
12
|
responseType: string;
|
|
13
13
|
handler: Function;
|
|
@@ -26,4 +26,4 @@ export interface ResponseRouteMatch {
|
|
|
26
26
|
* For partial (client-side navigation) requests, returns X-RSC-Reload
|
|
27
27
|
* so the browser triggers a hard navigation to the response route URL.
|
|
28
28
|
*/
|
|
29
|
-
export declare function handleResponseRoute<TEnv>(handlerCtx:
|
|
29
|
+
export declare function handleResponseRoute<TEnv>(handlerCtx: Pick<RequestStageContext<TEnv>, "callOnError" | "getRequiredRouteMap" | "reportResponseRouteError">, preview: ResponseRouteMatch, request: Request, env: TEnv, url: URL, variables: Record<string, any>): Promise<Response>;
|
|
@@ -62,7 +62,7 @@ export declare function step<T>(name: string, execute: () => T | Promise<T>): Ro
|
|
|
62
62
|
*
|
|
63
63
|
* Settlement tracking follows the RETURNED value: a returned promise is
|
|
64
64
|
* observed until it settles; a scheduler that fires-and-forgets internally
|
|
65
|
-
* (e.g.
|
|
65
|
+
* (e.g. planShellCapture via runBackground) returns void, so its trace
|
|
66
66
|
* entry settles at the scheduling call, not at background completion. That is
|
|
67
67
|
* deliberate — the plan's contract ends at the handoff.
|
|
68
68
|
*/
|
|
@@ -27,8 +27,8 @@ import type { MatchResult } from "../types.js";
|
|
|
27
27
|
* the revalidation phase so it runs INSIDE the same route-middleware wrapper as
|
|
28
28
|
* a successful revalidation — route middleware (context vars, headers, cookies)
|
|
29
29
|
* must apply to the error render too, matching the module doc's "identical to a
|
|
30
|
-
* normal render".
|
|
31
|
-
* boundary
|
|
30
|
+
* normal render". That render is the action's revalidation, cut at the
|
|
31
|
+
* boundary (ActionContext.boundary).
|
|
32
32
|
*/
|
|
33
33
|
export interface ActionContinuation {
|
|
34
34
|
returnValue: {
|
|
@@ -139,7 +139,7 @@ export declare const POST_QUIESCE_TASK_HOPS = 16;
|
|
|
139
139
|
* short is an acceptable loss — every terminal path backs the key off anyway),
|
|
140
140
|
* and below workerd's ~30s waitUntil grace so the cap timer still fires in a
|
|
141
141
|
* live context. When workerd kills the context BEFORE the cap fires, the timer
|
|
142
|
-
* dies with it — that stranding is healed by
|
|
142
|
+
* dies with it — that stranding is healed by planShellCapture's staleness
|
|
143
143
|
* check on the stampede guard, keyed off the same constant.
|
|
144
144
|
*/
|
|
145
145
|
export declare const SHELL_CAPTURE_TASK_HARD_CAP_MS = 25000;
|