@rangojs/router 0.27.0 → 0.29.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/action-fence.d.ts +2 -1
- package/dist/types/browser/event-controller.d.ts +8 -2
- package/dist/types/browser/history-state.d.ts +3 -9
- package/dist/types/browser/navigation-store.d.ts +8 -6
- package/dist/types/browser/partial-update.d.ts +11 -0
- package/dist/types/browser/react/filter-segment-order.d.ts +2 -2
- package/dist/types/browser/react/use-action.d.ts +7 -2
- package/dist/types/browser/react/use-handle.d.ts +19 -16
- package/dist/types/browser/react/use-link-status.d.ts +5 -2
- package/dist/types/browser/segment-reconciler.d.ts +32 -4
- package/dist/types/browser/types.d.ts +24 -5
- package/dist/types/browser/wire-protocol.d.ts +26 -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/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 +11 -5
- 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 +6 -11
- package/dist/types/router/match-handlers.d.ts +2 -6
- package/dist/types/router/match-middleware/background-revalidation.d.ts +13 -22
- 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/navigation-snapshot.d.ts +7 -0
- 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/helpers.d.ts +19 -3
- 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 +95 -0
- package/dist/types/router/segment-resolution/revalidation.d.ts +82 -31
- package/dist/types/router/segment-resolution/streamed-handler-boundary.d.ts +2 -0
- 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 +11 -1
- 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 +53 -104
- package/dist/types/server/rewrite-trail.d.ts +2 -2
- package/dist/types/testing/dispatch.d.ts +35 -18
- package/dist/types/testing/render-route.d.ts +43 -8
- package/dist/types/testing/serve-shell-request.d.ts +8 -1
- package/dist/types/types/cache-types.d.ts +6 -3
- package/dist/types/types/error-types.d.ts +30 -3
- 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 +39 -0
- package/dist/vite/index.js +3822 -3727
- package/package.json +1 -1
- package/skills/cache-guide/SKILL.md +8 -5
- package/skills/caching/SKILL.md +37 -18
- package/skills/client-urls/SKILL.md +4 -2
- package/skills/document-cache/SKILL.md +13 -1
- package/skills/handler-use/SKILL.md +1 -1
- package/skills/hooks/SKILL.md +1 -1
- package/skills/hooks/data.md +8 -1
- package/skills/hooks/handle-and-actions.md +33 -2
- package/skills/hooks/navigation.md +121 -15
- package/skills/hooks/state.md +6 -4
- package/skills/hooks/urls.md +16 -5
- package/skills/intercept/SKILL.md +23 -7
- package/skills/middleware/SKILL.md +18 -0
- package/skills/observability/SKILL.md +30 -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 +15 -1
- package/skills/testing/client-components.md +25 -18
- package/skills/testing/response-routes.md +6 -4
- package/skills/testing/serve-shell-request.md +7 -7
- package/skills/use-cache/SKILL.md +46 -8
- package/skills/view-transitions/SKILL.md +1 -1
- package/src/__internal.ts +7 -1
- package/src/browser/action-fence.ts +2 -1
- package/src/browser/connection-warmup.ts +3 -1
- package/src/browser/event-controller.ts +37 -13
- package/src/browser/history-state.ts +6 -12
- package/src/browser/navigation-bridge.ts +59 -26
- package/src/browser/navigation-client.ts +20 -25
- package/src/browser/navigation-store.ts +25 -27
- package/src/browser/navigation-transaction.ts +4 -1
- package/src/browser/network-error-handler.ts +4 -0
- package/src/browser/partial-update.ts +33 -6
- 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/react/use-action.ts +24 -48
- package/src/browser/react/use-handle.ts +22 -18
- package/src/browser/react/use-link-status.ts +48 -60
- package/src/browser/react/use-navigation.ts +92 -41
- package/src/browser/rsc-router.tsx +1 -0
- package/src/browser/segment-reconciler.ts +109 -53
- package/src/browser/server-action-bridge.ts +81 -61
- package/src/browser/types.ts +25 -5
- package/src/browser/wire-protocol.ts +43 -0
- package/src/cache/cache-key-utils.ts +11 -5
- package/src/cache/cache-runtime.ts +132 -75
- 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 +64 -46
- package/src/cache/handle-snapshot.ts +19 -7
- package/src/cache/read-through-swr.ts +20 -18
- package/src/cache/segment-codec.ts +55 -0
- package/src/cache/shell-snapshot.ts +2 -2
- package/src/cache/tag-invalidation.ts +6 -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 +22 -10
- package/src/router/instrument.ts +4 -3
- package/src/router/intercept-resolution.ts +82 -75
- package/src/router/loader-resolution.ts +5 -4
- package/src/router/match-api.ts +5 -5
- package/src/router/match-context.ts +23 -12
- package/src/router/match-handlers.ts +8 -20
- package/src/router/match-middleware/background-revalidation.ts +46 -57
- package/src/router/match-middleware/cache-lookup.ts +677 -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 +14 -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/helpers.ts +49 -13
- package/src/router/segment-resolution/loader-cache.ts +15 -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 +139 -0
- package/src/router/segment-resolution/revalidation.ts +939 -789
- package/src/router/segment-resolution/streamed-handler-boundary.ts +3 -0
- 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 +11 -1
- package/src/router.ts +19 -17
- 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 +759 -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 +275 -227
- 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 +75 -115
- package/src/server/rewrite-trail.ts +6 -4
- package/src/ssr/index.tsx +1 -1
- package/src/testing/dispatch.ts +226 -710
- package/src/testing/e2e/page-helpers.ts +2 -2
- package/src/testing/render-route.tsx +199 -13
- package/src/testing/serve-shell-request.ts +36 -40
- package/src/types/cache-types.ts +6 -3
- package/src/types/error-types.ts +30 -3
- 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 +40 -0
- package/dist/types/router/segment-resolution/fresh.d.ts +0 -72
- package/src/router/segment-resolution/fresh.ts +0 -945
|
@@ -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;
|
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
* Capture does NOT flow through the HTTP middleware pipeline. The integrated PPR
|
|
5
5
|
* serve path (rsc-rendering.ts + shell-serve.ts) builds a ShellCaptureDescriptor
|
|
6
6
|
* from the route's `ppr` path option after the served response is built and calls
|
|
7
|
-
*
|
|
7
|
+
* planShellCapture with it (ShellCaptureInput). The capture then runs as a background task that re-derives
|
|
8
8
|
* the page via `ctx.router.match()` under its OWN derived request context — fresh
|
|
9
|
-
* handle store, `
|
|
9
|
+
* handle store, `_shellCaptureState.run` so live-lane loaders mask (loader-mask.ts)
|
|
10
10
|
* and postpone at their loading() or inline <Suspense> boundary. The match is
|
|
11
11
|
* MIXED-CHAIN: cache()'d segments replay from ring 3, uncached segments execute
|
|
12
12
|
* their handlers. The record-first step (settleCaptureRecord) waits for the
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
*/
|
|
21
21
|
import { type MatchResult } from "../types.js";
|
|
22
22
|
import { type ShellCaptureRefusal } from "./shell-capture-constants.js";
|
|
23
|
-
import { type RequestContext
|
|
23
|
+
import { type RequestContext } from "../server/request-context.js";
|
|
24
24
|
import { type HandleStore } from "../server/handle-store.js";
|
|
25
25
|
import type { SegmentCacheStore } from "../cache/types.js";
|
|
26
26
|
import type { HandlerContext } from "./handler-context.js";
|
|
@@ -128,7 +128,7 @@ export interface ShellCaptureDebugEvent {
|
|
|
128
128
|
* - skip-stored: a capture for the key stored after the scheduling request
|
|
129
129
|
* read the store and missed (ShellCaptureDescriptor.storedSeqAtRead), so
|
|
130
130
|
* the shell that request missed exists now
|
|
131
|
-
* - skip-in-flight:
|
|
131
|
+
* - skip-in-flight: planShellCapture found a capture already running for
|
|
132
132
|
* the key (stampede guard) and scheduled nothing
|
|
133
133
|
* - skip-backoff: the key is inside its refused-capture backoff window and
|
|
134
134
|
* the capture was not attempted
|
|
@@ -268,7 +268,7 @@ export declare function gateFlightForCapture(source: ReadableStream<Uint8Array>)
|
|
|
268
268
|
* The background shell-capture descriptor: everything the capture task needs to
|
|
269
269
|
* store the shell. Built by the integrated PPR serve path (rsc-rendering.ts) from
|
|
270
270
|
* the route's `ppr` path option (`PartialPrerenderProps`) and the app-level cache
|
|
271
|
-
* store, and passed to
|
|
271
|
+
* store, and passed to planShellCapture in its input — it is NOT threaded through
|
|
272
272
|
* the request context. `tags` carries the route's OPERATIONAL `ppr.tags`; the
|
|
273
273
|
* capture UNIONS them with the shell's own auto-collected (non-loader) request
|
|
274
274
|
* tags from its derived render (the collected set stays authoritative). That
|
|
@@ -336,7 +336,7 @@ export interface ShellCaptureDescriptor {
|
|
|
336
336
|
/**
|
|
337
337
|
* Set for a shell keyed by the visitor's URL (`rewrite(...).shell("visitor")`,
|
|
338
338
|
* visitorShellKey): the capture renders the visitor's location
|
|
339
|
-
* (`
|
|
339
|
+
* (`ShellCaptureState.forVisitor`) and stores it as
|
|
340
340
|
* ShellCacheEntry.pathname.
|
|
341
341
|
*/
|
|
342
342
|
pathname?: string;
|
|
@@ -351,7 +351,7 @@ export interface ShellCaptureDescriptor {
|
|
|
351
351
|
/**
|
|
352
352
|
* A `router.prerender()` warm's capture (rsc-rendering.ts shellServePlan):
|
|
353
353
|
* one explicit call that must store, so the guards that shed a herd of
|
|
354
|
-
* visitors do not apply to it.
|
|
354
|
+
* visitors do not apply to it. planShellCapture skips the in-flight
|
|
355
355
|
* dedup and the refused-capture backoff, and attemptCapture waits longer on
|
|
356
356
|
* the write barrier. Every correctness guard, the inert-store skip and the
|
|
357
357
|
* queue limits still decide.
|
|
@@ -360,6 +360,21 @@ export interface ShellCaptureDescriptor {
|
|
|
360
360
|
}
|
|
361
361
|
/** The latest stored capture's sequence number for `key` in this isolate, or 0. */
|
|
362
362
|
export declare function lastStoredCaptureSeq(key: string): number;
|
|
363
|
+
/** One shell capture: the request it re-renders and what it stores. */
|
|
364
|
+
export interface ShellCaptureInput {
|
|
365
|
+
ctx: HandlerContext<any>;
|
|
366
|
+
request: Request;
|
|
367
|
+
env: any;
|
|
368
|
+
url: URL;
|
|
369
|
+
reqCtx: RequestContext<any>;
|
|
370
|
+
/**
|
|
371
|
+
* The SSR module for the capture's own request and URL, called once the
|
|
372
|
+
* capture leaves the queue. A document passes the module it already
|
|
373
|
+
* resolved, returned as is, so the capture awaits only a pending one.
|
|
374
|
+
*/
|
|
375
|
+
ssr: (request: Request, url: URL) => SSRModule | null | Promise<SSRModule | null>;
|
|
376
|
+
descriptor: ShellCaptureDescriptor;
|
|
377
|
+
}
|
|
363
378
|
/**
|
|
364
379
|
* Schedule the background shell capture for a served document. Stampede-guarded:
|
|
365
380
|
* one capture per key per isolate. Runs via runBackground (waitUntil on workerd,
|
|
@@ -367,15 +382,13 @@ export declare function lastStoredCaptureSeq(key: string): number;
|
|
|
367
382
|
* error is routed through reportCacheError — capture is best-effort; a failure just
|
|
368
383
|
* means the next request recaptures.
|
|
369
384
|
*
|
|
370
|
-
* Eligibility (nonce/partial/status/strategy) is decided by the caller.
|
|
371
|
-
* module loader may be passed for cold partial requests; it runs only after the
|
|
372
|
-
* capture enters the guarded background queue, never on response latency.
|
|
385
|
+
* Eligibility (nonce/partial/status/strategy) is decided by the caller.
|
|
373
386
|
*/
|
|
374
|
-
export declare function
|
|
387
|
+
export declare function planShellCapture(input: ShellCaptureInput): void;
|
|
375
388
|
/**
|
|
376
389
|
* The ttl/swr a shell is stored with: the route's ppr policy, capped by the
|
|
377
390
|
* route cache() records the capture replayed or wrote
|
|
378
|
-
* (
|
|
391
|
+
* (ShellCaptureState.routeRecordWindow). A HIT replays the capture's handler
|
|
379
392
|
* output, while a client navigation reads the route's cache() tier first, so
|
|
380
393
|
* a shell that outlived its record would show a document request other
|
|
381
394
|
* handler output than a navigation of the same URL. Freshness and total
|
|
@@ -456,9 +469,9 @@ type CaptureAttemptStats = Pick<ShellCaptureDebugEvent, "barrierWaitMs" | "write
|
|
|
456
469
|
* several HTTP requests before a capture stuck. We retry ONLY on `no-shell`
|
|
457
470
|
* that did not run out of ppr.captureTimeout (CaptureAttemptStats.noShellCause),
|
|
458
471
|
* and on `expired`; a genuine render error is NOT retried — it propagates to
|
|
459
|
-
*
|
|
472
|
+
* planShellCapture's reportCacheError. See docs/design/ppr-shell-resume.md.
|
|
460
473
|
*
|
|
461
|
-
* `request` and `url` are the capture's own identity (
|
|
474
|
+
* `request` and `url` are the capture's own identity (planShellCapture
|
|
462
475
|
* strips a navigation-only capture's transport parameters). `retryDelayMs` is
|
|
463
476
|
* a parameter (defaulting to the module const) so unit tests can drive the
|
|
464
477
|
* retry without a real 400ms wall-clock wait.
|
|
@@ -511,9 +524,113 @@ export type CaptureRecordOutcome = {
|
|
|
511
524
|
* a HIT restores, and its handle encode has its own 5s timeout that must
|
|
512
525
|
* never be the one that fires); then the capture's onResponse callbacks fire
|
|
513
526
|
* with a synthetic 200 (the implicit doc scope's cacheRoute, an explicit
|
|
514
|
-
* scope's own write), and the deferred writes settle.
|
|
527
|
+
* scope's own write), and the deferred writes settle. A match holding an
|
|
528
|
+
* error or notFound boundary throws before the callbacks fire.
|
|
515
529
|
*/
|
|
516
530
|
export declare function settleCaptureRecord(match: MatchResult, derivation: CaptureContextDerivation, capture: Pick<ShellCaptureDescriptor, "key">, deadline: number): Promise<CaptureRecordOutcome>;
|
|
531
|
+
/**
|
|
532
|
+
* @internal The freshness window of a route cache() record, as ms
|
|
533
|
+
* timestamps: fresh until `freshUntil` (its `expiresAt`), stale until
|
|
534
|
+
* `staleUntil` (plus its scope's swr). `ttl`, `swr` and `written` describe
|
|
535
|
+
* the record that sets `staleUntil`: its cache() config, and whether this
|
|
536
|
+
* capture wrote it (cacheRoute) rather than read it.
|
|
537
|
+
*/
|
|
538
|
+
export interface RouteRecordWindow {
|
|
539
|
+
freshUntil: number;
|
|
540
|
+
staleUntil: number;
|
|
541
|
+
ttl: number;
|
|
542
|
+
swr: number;
|
|
543
|
+
written: boolean;
|
|
544
|
+
}
|
|
545
|
+
/**
|
|
546
|
+
* @internal What a shell capture's render records about itself, on its
|
|
547
|
+
* derived request context as `_shellCaptureState`.
|
|
548
|
+
* RENDER_PASS_FIELDS["shell-capture"] (server/render-pass.ts) creates it with
|
|
549
|
+
* every field present, so it keeps one shape while the capture writes it. A
|
|
550
|
+
* background re-render the capture starts has none: it writes a route
|
|
551
|
+
* record, under cache() rules (RENDER_PASS_FIELDS["background-revalidation"]).
|
|
552
|
+
*/
|
|
553
|
+
export interface ShellCaptureState {
|
|
554
|
+
/**
|
|
555
|
+
* @internal PPR shell-capture ACTIVE marker. True ONLY inside the background
|
|
556
|
+
* capture task's derived request context (built by shell-capture.ts). This is
|
|
557
|
+
* the switch every capture-specific behavior reads: loader masking
|
|
558
|
+
* (loader-mask.ts isShellCaptureActive / resolveOwnerLoaders) and the
|
|
559
|
+
* identity-read capture guard (server/context.ts guardIdentityRead). The
|
|
560
|
+
* foreground render never sets it, so the
|
|
561
|
+
* served response is byte-identical to axis 1. The capture descriptor itself
|
|
562
|
+
* (key/ttl/swr/tags/store) is NOT threaded through the request context — the
|
|
563
|
+
* integrated PPR serve path (rsc/shell-serve.ts + rsc-rendering.ts) builds it
|
|
564
|
+
* locally and passes it to planShellCapture in its input.
|
|
565
|
+
*/
|
|
566
|
+
readonly run: true;
|
|
567
|
+
/**
|
|
568
|
+
* @internal Set beside `run` when the shell is keyed by the
|
|
569
|
+
* visitor's URL (`rewrite(...).shell("visitor")`): the capture renders the
|
|
570
|
+
* visitor's location and `ctx.rewrittenFrom`; the theme stays the default.
|
|
571
|
+
*/
|
|
572
|
+
forVisitor: boolean | undefined;
|
|
573
|
+
/**
|
|
574
|
+
* @internal Bake-lane loader containers collected DURING a shell capture:
|
|
575
|
+
* segment-key -> the loader's (pre-wrap) result promise. Populated by
|
|
576
|
+
* resolveLoaderData for bake-lane loaders (lane rule: see its JSDoc in
|
|
577
|
+
* loader-cache.ts). Drained by captureAndStoreShell after the shell
|
|
578
|
+
* quiesces: settled containers are promise-elided, Flight-serialized, and
|
|
579
|
+
* pinned into the snapshot's loader family; a REJECTED container refuses
|
|
580
|
+
* the capture (error UI must never bake into the shared shell).
|
|
581
|
+
*/
|
|
582
|
+
loaderRecords: Map<string, Promise<unknown>>;
|
|
583
|
+
/**
|
|
584
|
+
* @internal Set when a loader pushed a
|
|
585
|
+
* value the record cannot keep (masked nested promises, a pushed promise
|
|
586
|
+
* that settled to one, a live-lane loader's push, or a push outside a
|
|
587
|
+
* loader body): the loader records then carry `runs: 1`, so a HIT still
|
|
588
|
+
* runs their bodies for those pushes.
|
|
589
|
+
*/
|
|
590
|
+
unrecordedLoaderPush: true | undefined;
|
|
591
|
+
/**
|
|
592
|
+
* @internal The lane of each loader the capture's matched route registers
|
|
593
|
+
* (loader-cache.ts routeLoaderLanes), set by createMatchContextForFull
|
|
594
|
+
* before any loader runs. The capture's push funnel credits a push made
|
|
595
|
+
* under a live-lane loader's body, at any depth, to that loader
|
|
596
|
+
* (shell-capture.ts deriveShellCaptureContext).
|
|
597
|
+
*/
|
|
598
|
+
loaderLanes: ReadonlyMap<string, "live" | "bake"> | undefined;
|
|
599
|
+
/**
|
|
600
|
+
* @internal Set by the capture guard (server/context.ts
|
|
601
|
+
* guardIdentityRead) when it throws DURING a capture render: the read
|
|
602
|
+
* ("cookies()", "headers()", `ctx.get() for a non-cacheable variable`,
|
|
603
|
+
* "ctx.theme") and the fix the
|
|
604
|
+
* refusal warning gives for it. Load-bearing for the
|
|
605
|
+
* bake lane: a guard throw inside an executing loader is swallowed by
|
|
606
|
+
* wrapLoaderPromise into per-loader error UI, which would otherwise bake
|
|
607
|
+
* silently into the shared shell — the capture checks this flag after the
|
|
608
|
+
* render and refuses instead. Deterministic, so the capture does not retry.
|
|
609
|
+
*/
|
|
610
|
+
guardTripped: {
|
|
611
|
+
surface: string;
|
|
612
|
+
fix: string;
|
|
613
|
+
} | undefined;
|
|
614
|
+
/**
|
|
615
|
+
* @internal The loader $$id whose BODY was executing when the capture guard
|
|
616
|
+
* tripped (read off the loader-body ALS scope at trip time), or undefined
|
|
617
|
+
* when the read came from handler/render code. Only used to make the
|
|
618
|
+
* once-per-key refusal warning name the real source — the old text
|
|
619
|
+
* hardcoded "a bake-lane loader", which misattributed handler-land reads
|
|
620
|
+
* and sent users debugging the wrong lane (issue #672, secondary).
|
|
621
|
+
*/
|
|
622
|
+
guardTrippedLoaderId: string | undefined;
|
|
623
|
+
/**
|
|
624
|
+
* @internal The freshness window of the route cache() records this
|
|
625
|
+
* capture read or wrote (cache-scope.ts noteRouteRecordWindow), as ms
|
|
626
|
+
* timestamps: `freshUntil` is the record's `expiresAt`, `staleUntil` adds
|
|
627
|
+
* its scope's swr. The narrowest record wins. A shell capture caps its
|
|
628
|
+
* entry's ttl and ttl+swr to it (shell-capture.ts capShellWindow), so a
|
|
629
|
+
* shell is never fresher, or served longer, than the route cache() entry
|
|
630
|
+
* it replayed or wrote.
|
|
631
|
+
*/
|
|
632
|
+
routeRecordWindow: RouteRecordWindow | undefined;
|
|
633
|
+
}
|
|
517
634
|
/**
|
|
518
635
|
* The derived capture context and its fresh (mask-funneled) handle store,
|
|
519
636
|
* shared by BOTH shell producers: the runtime background capture
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
*/
|
|
18
18
|
import { type EntryData } from "../server/context.js";
|
|
19
19
|
import type { DocumentShellCacheEntry, ShellCacheEntry, ShellDocumentRead, ShellEntryHead, ShellReadStats, ShellSnapshotFailure, ShellSnapshotRecord, SegmentCacheStore } from "../cache/types.js";
|
|
20
|
+
import type { MetricsStore } from "../server/context.js";
|
|
20
21
|
export { PPR_REPLAY_STATUS_HEADER, SHELL_STATUS_HEADER, buildShellKey, navigationShellKey, partitionShellKey, shellSearchSeed, } from "./shell-capture-constants.js";
|
|
21
22
|
/**
|
|
22
23
|
* Default shell ttl (seconds) for `ppr: true` and for a PartialPrerenderProps
|
|
@@ -76,18 +77,13 @@ export declare function normalizeCaptureTimeout(value: unknown): number | undefi
|
|
|
76
77
|
*/
|
|
77
78
|
export declare function resolvePprConfig(entry: EntryData | undefined | null): ResolvedPprConfig | null;
|
|
78
79
|
/**
|
|
79
|
-
* The forced-MISS
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
* the
|
|
84
|
-
*
|
|
85
|
-
|
|
86
|
-
export declare const SHELL_MISS_PARAM: string;
|
|
87
|
-
/**
|
|
88
|
-
* The request without the forced-MISS marker, or undefined when it carries
|
|
89
|
-
* none. The handler calls it before anything reads the request: left in, the
|
|
90
|
-
* marker reached `ctx.request.url`, `originalUrl`, middleware, and the SSR
|
|
80
|
+
* The request without the forced-MISS marker (`WIRE.shellMiss`), or
|
|
81
|
+
* undefined when it carries none. A document HIT that cannot finish its tail
|
|
82
|
+
* reloads the page with the marker (shellReloadScript); the serve gate
|
|
83
|
+
* renders a request carrying it on axis 1, with no shell read and no
|
|
84
|
+
* capture, so the reload can never be a HIT that degrades again. The handler
|
|
85
|
+
* calls this on entry, before anything reads the request, and keeps only the
|
|
86
|
+
* flag (RequestContext._shellForcedMiss): left in, the marker reached `ctx.request.url`, `originalUrl`, middleware, and the SSR
|
|
91
87
|
* search seed (so `useSearchParams` rendered it), and a `"use cache"` key
|
|
92
88
|
* built from the request URL was never read again. GET and HEAD only: the
|
|
93
89
|
* reload is a navigation, and a request with a body cannot be re-created
|
|
@@ -165,6 +161,35 @@ export interface ShellDocument {
|
|
|
165
161
|
*/
|
|
166
162
|
export declare function openShellDocument(entry: ShellCacheEntry): ShellDocument | null;
|
|
167
163
|
export declare function openShellDocument(entry: ShellEntryHead, read: Pick<ShellDocumentRead, "prelude" | "snapshot" | "snapshotFailure" | "stats">): ShellDocument | null;
|
|
164
|
+
/**
|
|
165
|
+
* A document serve's store read: a getShell entry, or a prelude-first read
|
|
166
|
+
* (readShellDocument) whose entry is the head and whose snapshot arrives on
|
|
167
|
+
* its own promise.
|
|
168
|
+
*/
|
|
169
|
+
export type ShellRead = {
|
|
170
|
+
entry: ShellCacheEntry;
|
|
171
|
+
shouldRevalidate?: boolean;
|
|
172
|
+
read?: undefined;
|
|
173
|
+
} | {
|
|
174
|
+
entry: ShellEntryHead;
|
|
175
|
+
shouldRevalidate?: boolean;
|
|
176
|
+
read: ShellDocumentRead;
|
|
177
|
+
};
|
|
178
|
+
/**
|
|
179
|
+
* The document serve's shell read from `source`, the app cache store, that
|
|
180
|
+
* degrades to null on failure (axis 1 MISS, never a 500) and records the raw
|
|
181
|
+
* `ppr:shell-read` outcome (pre-validity-gates, so a version-mismatch
|
|
182
|
+
* lifecycle miss stays distinguishable from a store miss). A store with a
|
|
183
|
+
* prelude-first read (readShellDocument) resolves before the snapshot is
|
|
184
|
+
* read, so the HIT commits without waiting for it. A build shell is read by
|
|
185
|
+
* shell-build-manifest.ts lookupBuildShell, which imports this module.
|
|
186
|
+
*/
|
|
187
|
+
export declare function readShell(source: SegmentCacheStore & {
|
|
188
|
+
getShell: NonNullable<SegmentCacheStore["getShell"]>;
|
|
189
|
+
}, key: string, opts: {
|
|
190
|
+
tagHints?: readonly string[];
|
|
191
|
+
metrics?: MetricsStore;
|
|
192
|
+
}): Promise<ShellRead | null>;
|
|
168
193
|
/**
|
|
169
194
|
* Prelude enqueue granularity. A streaming compressor in front of the worker
|
|
170
195
|
* emits its first byte only after compressing the whole write it was handed:
|
|
@@ -121,7 +121,7 @@ export type LoaderEntry = {
|
|
|
121
121
|
* thrown notFound()/redirect() deterministically precede first flush.
|
|
122
122
|
* Resolved at DSL-evaluation time from ctx.isSSR — entries are cached
|
|
123
123
|
* per-isSSR (router/manifest.ts cache key), so the flag is already
|
|
124
|
-
* request-mode-correct when
|
|
124
|
+
* request-mode-correct when resolveOwnerLoaders reads it and never
|
|
125
125
|
* appears on navigation-lane entries. Set by documentModeLoader, which
|
|
126
126
|
* getDocumentModeEntry also applies to a lazy include's captured ancestors.
|
|
127
127
|
*/
|
|
@@ -566,7 +566,7 @@ export interface IdentityReadWording {
|
|
|
566
566
|
* only observed; it is never rendered. A cached body, loader body or
|
|
567
567
|
* funnel they start is guarded again.
|
|
568
568
|
* 1. A PPR shell capture (`ctx` is the capture's derived context,
|
|
569
|
-
* `
|
|
569
|
+
* `_shellCaptureState`) trips first: the capture context is flagged (so a
|
|
570
570
|
* caught throw still refuses the capture) and the read throws. The shell is
|
|
571
571
|
* shared per host+URL, and every HIT replays what the capture read. There
|
|
572
572
|
* is no loader-body exemption here: a bake-lane loader and a loader a
|
|
@@ -737,12 +737,13 @@ export declare function latchPprHeaderScopeForEntries(entries: EntryData[], rout
|
|
|
737
737
|
* ONLY the ppr (shell) axis is dropped — dynamic() does NOT opt off the CACHE
|
|
738
738
|
* axis. Two cases:
|
|
739
739
|
* - Pure ppr funnel (no cache() boundary): clear the latch → writes re-permit.
|
|
740
|
-
* - ppr route nested under a cache() boundary:
|
|
741
|
-
* funnel top (first-wins), which MASKS the positional
|
|
742
|
-
* handler still runs inside the cache scope
|
|
743
|
-
* HIT skips that handler, so the write is
|
|
744
|
-
* "cache" instead of clearing, so the
|
|
745
|
-
* wording). This is why the check keys
|
|
740
|
+
* - ppr route nested under a cache() boundary: resolveAllSegments
|
|
741
|
+
* latches "ppr" at the funnel top (first-wins), which MASKS the positional
|
|
742
|
+
* cache() latch, but the handler still runs inside the cache scope
|
|
743
|
+
* (`insideCacheScope`). A cache() HIT skips that handler, so the write is
|
|
744
|
+
* still non-deterministic — UNMASK to "cache" instead of clearing, so the
|
|
745
|
+
* guard keeps throwing (accurate cache() wording). This is why the check keys
|
|
746
|
+
* off `insideCacheScope`, not just kind.
|
|
746
747
|
*
|
|
747
748
|
* A subsequent cache() entered AFTER dynamic() on a pure-ppr funnel re-latches
|
|
748
749
|
* "cache" via latchCachedHeaderScope's `!store.cachedHeaderScope` guard (the
|
|
@@ -169,6 +169,22 @@ export interface HandleStore {
|
|
|
169
169
|
* array, in order. Without placeholders it is a plain replay.
|
|
170
170
|
*/
|
|
171
171
|
replacePlaceholders(loaderIds: readonly string[], deliver: () => void): void;
|
|
172
|
+
/**
|
|
173
|
+
* A cache() or Prerender() HIT restored its stored values into
|
|
174
|
+
* `segmentIds` (cache-lookup.ts serveStoredSegments). The MISS ran each
|
|
175
|
+
* segment's handler after it started the segment's loaders, so a push into
|
|
176
|
+
* a restored array goes in front of the stored values until
|
|
177
|
+
* releaseRecordedValues: a loader's push lands where the same loader timing
|
|
178
|
+
* puts it on the MISS.
|
|
179
|
+
*/
|
|
180
|
+
holdRecordedValues(segmentIds: readonly string[]): void;
|
|
181
|
+
/**
|
|
182
|
+
* The HIT's loader walk reached the place where the MISS ran
|
|
183
|
+
* `segmentId`'s handler (revalidation.ts resolveLoadersOnly,
|
|
184
|
+
* intercept-resolution.ts resolveInterceptLoadersOnly): later pushes
|
|
185
|
+
* follow the record's values.
|
|
186
|
+
*/
|
|
187
|
+
releaseRecordedValues(segmentId: string): void;
|
|
172
188
|
/**
|
|
173
189
|
* Get all collected handle data after all handlers have settled.
|
|
174
190
|
* Waits for `settled` (handler lane), then returns the data at that point.
|