@rangojs/router 0.23.0 → 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 +4 -3
- package/dist/types/browser/merge-segment-loaders.d.ts +5 -2
- package/dist/types/browser/partial-update.d.ts +6 -4
- package/dist/types/browser/react/NavigationProvider.d.ts +11 -7
- package/dist/types/browser/react/context.d.ts +3 -2
- package/dist/types/browser/types.d.ts +5 -1
- package/dist/types/build/route-types/scan-filter.d.ts +7 -1
- package/dist/types/cache/document-cache-policy.d.ts +24 -0
- package/dist/types/cache/document-cache.d.ts +2 -10
- package/dist/types/context-var.d.ts +12 -0
- package/dist/types/errors.d.ts +10 -0
- package/dist/types/handles/pushed-by.d.ts +8 -0
- package/dist/types/index.d.ts +4 -0
- package/dist/types/index.rsc.d.ts +2 -0
- package/dist/types/response-utils.d.ts +7 -0
- package/dist/types/reverse.d.ts +8 -8
- 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/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/mask-nested.d.ts +4 -2
- package/dist/types/router/segment-resolution/prefetch-deferral.d.ts +36 -13
- 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/request-context.d.ts +39 -2
- package/dist/types/server/rewrite-trail.d.ts +49 -0
- package/dist/types/server/slot-accessors.d.ts +29 -0
- package/dist/types/testing/index.d.ts +1 -1
- package/dist/types/testing/render-route.d.ts +8 -0
- package/dist/types/testing/run-middleware.d.ts +20 -0
- package/dist/types/testing/serve-shell-request.d.ts +2 -1
- package/dist/types/thenable-status.d.ts +6 -0
- package/dist/types/types/request-scope.d.ts +7 -0
- package/dist/types/vite/discovery/state.d.ts +12 -9
- package/dist/vite/index.js +164 -103
- package/package.json +1 -1
- package/skills/caching/SKILL.md +12 -0
- package/skills/catalog.json +1 -1
- package/skills/client-urls/SKILL.md +84 -0
- package/skills/hooks/SKILL.md +11 -6
- package/skills/hooks/data.md +3 -1
- package/skills/loader/SKILL.md +7 -1
- package/skills/middleware/SKILL.md +183 -2
- package/skills/ppr/SKILL.md +9 -0
- package/skills/rango/SKILL.md +1 -1
- package/skills/server-actions/SKILL.md +27 -0
- package/skills/testing/client-components.md +1 -0
- package/skills/testing/middleware.md +31 -10
- package/skills/testing/response-routes.md +1 -0
- package/skills/testing/serve-shell-request.md +19 -1
- package/skills/use-cache/SKILL.md +4 -2
- package/src/__augment-tests__/augmented.check.ts +20 -0
- package/src/browser/event-controller.ts +3 -0
- package/src/browser/merge-segment-loaders.ts +31 -18
- package/src/browser/navigation-bridge.ts +19 -3
- package/src/browser/partial-update.ts +27 -12
- package/src/browser/react/Link.tsx +7 -9
- package/src/browser/react/NavigationProvider.tsx +46 -26
- package/src/browser/react/context.ts +3 -2
- package/src/browser/react/use-router.ts +2 -4
- package/src/browser/server-action-bridge.ts +6 -0
- package/src/browser/types.ts +5 -1
- package/src/build/route-types/scan-filter.ts +11 -4
- package/src/cache/document-cache-policy.ts +131 -0
- package/src/cache/document-cache.ts +12 -119
- package/src/context-var.ts +32 -2
- package/src/errors.ts +19 -0
- package/src/handles/pushed-by.ts +26 -0
- package/src/index.rsc.ts +8 -0
- package/src/index.ts +7 -0
- package/src/response-utils.ts +19 -0
- package/src/reverse.ts +17 -14
- 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 +29 -12
- package/src/router/internal-params.ts +16 -0
- package/src/router/loader-resolution.ts +2 -0
- package/src/router/match-middleware/background-revalidation.ts +11 -9
- package/src/router/match-middleware/cache-lookup.ts +20 -15
- package/src/router/match-middleware/cache-store.ts +9 -11
- package/src/router/match-middleware/intercept-resolution.ts +4 -2
- package/src/router/middleware-types.ts +16 -0
- package/src/router/middleware.ts +127 -49
- package/src/router/revalidation.ts +1 -1
- package/src/router/route-trie-builder.ts +28 -1
- 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 +57 -17
- package/src/router/segment-resolution/revalidation.ts +57 -33
- 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 +4 -2
- package/src/rsc/ssr-setup.ts +11 -5
- package/src/server/cookie-parse.ts +36 -12
- package/src/server/cookie-store.ts +7 -3
- package/src/server/handle-store.ts +48 -17
- package/src/server/request-context.ts +154 -63
- 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/ssr/index.tsx +118 -16
- package/src/testing/dispatch.ts +138 -67
- package/src/testing/index.ts +1 -0
- package/src/testing/render-route.tsx +16 -3
- package/src/testing/run-loader.ts +2 -0
- package/src/testing/run-middleware.ts +56 -11
- package/src/testing/serve-shell-request.ts +15 -2
- package/src/thenable-status.ts +11 -0
- package/src/types/request-scope.ts +8 -0
- package/src/vite/discovery/state.ts +21 -13
- package/src/vite/plugins/expose-internal-ids.ts +2 -3
- package/src/vite/router-discovery.ts +29 -27
|
@@ -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;
|
|
@@ -600,6 +600,13 @@ export interface RequestContext<TEnv = DefaultEnv, TParams = Record<string, stri
|
|
|
600
600
|
* (segment-resolution/prefetch-deferral.ts requestKind).
|
|
601
601
|
*/
|
|
602
602
|
_requestKind?: "prefetch" | "fill";
|
|
603
|
+
/**
|
|
604
|
+
* @internal Set when a render shows the visitor's URL of a rewritten
|
|
605
|
+
* request: the payload or SSR seed (renderedLocation, rsc/full-payload.ts)
|
|
606
|
+
* or a `ctx.rewrittenFrom` read (server/rewrite-trail.ts). The document
|
|
607
|
+
* cache does not store that response: it is keyed by the target.
|
|
608
|
+
*/
|
|
609
|
+
_payloadVisitorLocation?: boolean;
|
|
603
610
|
/**
|
|
604
611
|
* Attach location state entries to the current response.
|
|
605
612
|
*
|
|
@@ -816,7 +823,7 @@ export interface RouteRecordWindow {
|
|
|
816
823
|
* This is the type exported to library consumers. Internal code should
|
|
817
824
|
* use the full RequestContext interface directly.
|
|
818
825
|
*/
|
|
819
|
-
export type PublicRequestContext<TEnv = DefaultEnv, TParams = Record<string, string>> = Omit<RequestContext<TEnv, TParams>, "cookie" | "cookies" | "_readCookie" | "_readCookies" | "setCookie" | "deleteCookie" | "_handleStore" | "_transitionWhenRefs" | "_pprReplayPostMatchReason" | "_cacheStore" | "_prerender" | "_onDemandProducer" | "_searchParamsFilter" | "_shellCaptureRun" | "_shellImplicitCache" | "_shellLoaderSeed" | "_shellCaptureLoaderRecords" | "_shellCaptureUnrecordedLoaderPush" | "_shellCaptureLoaderLanes" | "_resolvedCacheKeys" | "_shellKey" | "_shellForcedMiss" | "_prerenderWarm" | "_runAtRequestEntry" | "_routeRecordWindow" | "_shellFragmentPayload" | "_shellCaptureGuardTripped" | "_shellCaptureGuardTrippedLoaderId" | "_explicitTaggedStores" | "_requestTags" | "_recordTagOwners" | "_recordLoaderTags" | "_cacheProfiles" | "_onResponseCallbacks" | "_pendingBackgroundTasks" | "_themeConfig" | "_readTheme" | "_documentCacheRender" | "_payloadVisitorTheme" | "_payloadDeferred" | "_requestKind" | "_locationState" | "_routeName" | "_prevRouteKey" | "_inActionRevalidation" | "_reportedErrors" | "_renderErrors" | "_recoveredHandlerErrors" | "_renderBarrier" | "_resolveRenderBarrier" | "_renderBarrierSegmentOrder" | "_treeHasStreaming" | "_renderBarrierWaiters" | "_handlerLoaderDeps" | "_awaitBeforeFlushLoaderIds" | "_renderBarrierHandleSnapshot" | "_renderBarrierGuardClosed" | "_reportBackgroundError" | "_debugPerformance" | "_metricsStore" | "_renderForeground" | "_activeRoutine" | "_renderDiagnosticsEnabled" | "_handlerStart" | "_tracing" | "_basename" | "_routerId" | "_versions" | "_setStatus" | "_rotateStateCookie" | "_setKeepCacheDirective" | "_freshReads" | "_setFreshReadsCookie" | "_requestRoot" | "_requestStart" | "_responseSent" | "_variables" | "_classifiedRoute" | "_requestMode" | "_cacheSignal" | "_dynamic" | "res">;
|
|
826
|
+
export type PublicRequestContext<TEnv = DefaultEnv, TParams = Record<string, string>> = Omit<RequestContext<TEnv, TParams>, "cookie" | "cookies" | "_readCookie" | "_readCookies" | "setCookie" | "deleteCookie" | "_handleStore" | "_transitionWhenRefs" | "_pprReplayPostMatchReason" | "_cacheStore" | "_prerender" | "_onDemandProducer" | "_searchParamsFilter" | "_shellCaptureRun" | "_shellImplicitCache" | "_shellLoaderSeed" | "_shellCaptureLoaderRecords" | "_shellCaptureUnrecordedLoaderPush" | "_shellCaptureLoaderLanes" | "_resolvedCacheKeys" | "_shellKey" | "_shellForcedMiss" | "_prerenderWarm" | "_runAtRequestEntry" | "_routeRecordWindow" | "_shellFragmentPayload" | "_shellCaptureGuardTripped" | "_shellCaptureGuardTrippedLoaderId" | "_explicitTaggedStores" | "_requestTags" | "_recordTagOwners" | "_recordLoaderTags" | "_cacheProfiles" | "_onResponseCallbacks" | "_pendingBackgroundTasks" | "_themeConfig" | "_readTheme" | "_documentCacheRender" | "_payloadVisitorTheme" | "_payloadDeferred" | "_requestKind" | "_payloadVisitorLocation" | "_locationState" | "_routeName" | "_prevRouteKey" | "_inActionRevalidation" | "_reportedErrors" | "_renderErrors" | "_recoveredHandlerErrors" | "_renderBarrier" | "_resolveRenderBarrier" | "_renderBarrierSegmentOrder" | "_treeHasStreaming" | "_renderBarrierWaiters" | "_handlerLoaderDeps" | "_awaitBeforeFlushLoaderIds" | "_renderBarrierHandleSnapshot" | "_renderBarrierGuardClosed" | "_reportBackgroundError" | "_debugPerformance" | "_metricsStore" | "_renderForeground" | "_activeRoutine" | "_renderDiagnosticsEnabled" | "_handlerStart" | "_tracing" | "_basename" | "_routerId" | "_versions" | "_setStatus" | "_rotateStateCookie" | "_setKeepCacheDirective" | "_freshReads" | "_setFreshReadsCookie" | "_requestRoot" | "_requestStart" | "_responseSent" | "_variables" | "_classifiedRoute" | "_requestMode" | "_cacheSignal" | "_dynamic" | "res">;
|
|
820
827
|
/**
|
|
821
828
|
* Marker for a waitUntil-scheduled fn whose task promise must NOT enter
|
|
822
829
|
* _pendingBackgroundTasks. Used by the PPR shell capture for its own task:
|
|
@@ -825,6 +832,13 @@ export type PublicRequestContext<TEnv = DefaultEnv, TParams = Record<string, str
|
|
|
825
832
|
* @internal
|
|
826
833
|
*/
|
|
827
834
|
export declare const UNTRACKED_BACKGROUND_TASK: unique symbol;
|
|
835
|
+
/**
|
|
836
|
+
* Define `ctx.res` as an own accessor that reads `get`. Assigning it throws
|
|
837
|
+
* the read-only error. A context derived from another (Object.create) gets
|
|
838
|
+
* its own response this way; copying the descriptor would read the
|
|
839
|
+
* prototype's slot.
|
|
840
|
+
*/
|
|
841
|
+
export declare function bindRes(ctx: RequestContext<any, any>, get: () => Response): void;
|
|
828
842
|
/**
|
|
829
843
|
* Capture the current async context (RequestContext._runAtRequestEntry), taken
|
|
830
844
|
* on handler entry before any router scope, so a nested dispatch (a
|
|
@@ -924,6 +938,26 @@ export interface CreateRequestContextOptions<TEnv> {
|
|
|
924
938
|
* - Passed to handlers as ctx
|
|
925
939
|
*/
|
|
926
940
|
export declare function createRequestContext<TEnv>(options: CreateRequestContextOptions<TEnv>): RequestContext<TEnv>;
|
|
941
|
+
/**
|
|
942
|
+
* Move a request context to a rewrite target for the next pass of the
|
|
943
|
+
* request (rsc/rewrite-passes.ts, `throw rewrite()`). The context object
|
|
944
|
+
* stays the same, so what the visitor's pass set is still there: variables
|
|
945
|
+
* (the rewrite trail among them), the response stub (status, headers,
|
|
946
|
+
* cookies), location state, theme, `dynamic()`, metrics, request tags,
|
|
947
|
+
* onResponse callbacks, the handle store.
|
|
948
|
+
*
|
|
949
|
+
* Moved to the target: the request (`rawUrl`, the visitor's `_rsc*` params
|
|
950
|
+
* included), url, originalUrl, pathname, searchParams and the request kind.
|
|
951
|
+
* Cleared for the target's match: params, route name, reverse, the
|
|
952
|
+
* classified route, the request mode, and the document cache's render mark
|
|
953
|
+
* (its middleware runs again for the target). The loader memo behind
|
|
954
|
+
* `getRequestContext().use()` is new: a loader that middleware started in
|
|
955
|
+
* the visitor's pass read the visitor's URL. A pass never renders before it
|
|
956
|
+
* rewrites: router/middleware.ts refuses a rewrite thrown after a next()
|
|
957
|
+
* unless that next() rejected with a Rewrite (a downstream middleware
|
|
958
|
+
* rewrote before its own next()), so there is no render state to reset.
|
|
959
|
+
*/
|
|
960
|
+
export declare function rebaseRequestContext(ctx: RequestContext<any>, request: Request, rawUrl: URL): void;
|
|
927
961
|
/**
|
|
928
962
|
* Wire a fresh render barrier onto `ctx`, closure-bound to THIS ctx and THIS
|
|
929
963
|
* handle store. Called by createRequestContext for every fresh context, and by
|
|
@@ -940,8 +974,11 @@ export declare function createRequestContext<TEnv>(options: CreateRequestContext
|
|
|
940
974
|
* read the foreground's handle snapshot; the capture's fresh `_handleStore`
|
|
941
975
|
* was invisible, so foreground per-request handle data could bake into the
|
|
942
976
|
* shared shell.
|
|
977
|
+
*
|
|
978
|
+
* A derived context's `_renderBarrier` is non-enumerable (the default
|
|
979
|
+
* descriptor); a fresh context's is enumerable like its other fields.
|
|
943
980
|
*/
|
|
944
|
-
export declare function wireRenderBarrier(ctx: RequestContext<any, any>, handleStore: HandleStore): void;
|
|
981
|
+
export declare function wireRenderBarrier(ctx: RequestContext<any, any>, handleStore: HandleStore, descriptor?: PropertyDescriptor): void;
|
|
945
982
|
export { parseCookiesFromHeader };
|
|
946
983
|
export declare function serializeCookieValue(name: string, value: string, options?: CookieOptions): string;
|
|
947
984
|
/**
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The URLs a rewritten request moved through (`throw rewrite()`), and what
|
|
3
|
+
* each context sees of them.
|
|
4
|
+
*
|
|
5
|
+
* One source: the trail lives in the request's variables under a token no
|
|
6
|
+
* user code can reach, so a middleware cannot reset the loop count. The
|
|
7
|
+
* visitor's URL is its first entry (`ctx.rewrittenFrom`); the hops are its
|
|
8
|
+
* length minus one.
|
|
9
|
+
*/
|
|
10
|
+
import type { RequestContext } from "./request-context.js";
|
|
11
|
+
/** Most rewrites one request may take; the next one is a RewriteLoopError. */
|
|
12
|
+
export declare const MAX_REWRITE_HOPS = 5;
|
|
13
|
+
type TrailContext = Pick<RequestContext<any>, "_variables">;
|
|
14
|
+
/** The trail of a rewritten request; undefined when nothing rewrote. */
|
|
15
|
+
export declare function rewriteTrail(reqCtx: TrailContext | undefined): readonly string[] | undefined;
|
|
16
|
+
/**
|
|
17
|
+
* Count one hop from `from` to `to` (clean URLs) and return its number.
|
|
18
|
+
* Throws RewriteLoopError past {@link MAX_REWRITE_HOPS}, or when `to` is the
|
|
19
|
+
* URL the request is on (pathname and search).
|
|
20
|
+
*/
|
|
21
|
+
export declare function recordRewriteHop(reqCtx: TrailContext, from: URL, to: URL): number;
|
|
22
|
+
type AudienceContext = Pick<RequestContext<any>, "_shellCaptureRun" | "_documentCacheRender" | "res">;
|
|
23
|
+
/**
|
|
24
|
+
* A render other visitors may be served: a PPR shell capture, or a render
|
|
25
|
+
* the document cache stores (its response opted in before next()). It shows
|
|
26
|
+
* what a direct visit to its URL shows: no visitor theme, no visitor URL.
|
|
27
|
+
*/
|
|
28
|
+
export declare function rendersForSharedAudience(reqCtx: AudienceContext): boolean;
|
|
29
|
+
/**
|
|
30
|
+
* The URL the visitor is on: the first URL of a rewritten request, else
|
|
31
|
+
* `url` with the internal `_rsc*` params stripped. A reload the router asks
|
|
32
|
+
* the browser for points here.
|
|
33
|
+
*/
|
|
34
|
+
export declare function visitorUrl(reqCtx: TrailContext | undefined, url: URL): URL;
|
|
35
|
+
/**
|
|
36
|
+
* Who reads `rewrittenFrom`: "render" for the contexts a render reads
|
|
37
|
+
* (handler, loader, response route, getRequestContext()), "middleware" for a
|
|
38
|
+
* middleware ctx, which runs once per request and is never stored.
|
|
39
|
+
*/
|
|
40
|
+
export type RewrittenFromReader = "render" | "middleware";
|
|
41
|
+
/**
|
|
42
|
+
* Define `ctx.rewrittenFrom` on a handler, loader, response-route or
|
|
43
|
+
* middleware ctx, read through `source` (the request context it belongs
|
|
44
|
+
* to). Each ctx gets its own copy of the URL.
|
|
45
|
+
*/
|
|
46
|
+
export declare function defineRewrittenFrom(ctx: object, source: RequestContext<any> | undefined, reader?: RewrittenFromReader): void;
|
|
47
|
+
/** Define `rewrittenFrom` on a request context, read through itself. */
|
|
48
|
+
export declare function defineRequestRewrittenFrom(ctx: RequestContext<any>): void;
|
|
49
|
+
export {};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Property definitions for per-request objects that keep V8 fast properties
|
|
3
|
+
* (#1109): the request context, the middleware ctx, the handle store and a
|
|
4
|
+
* guarded request.
|
|
5
|
+
*
|
|
6
|
+
* V8 puts an object in dictionary mode, where every property read is a hash
|
|
7
|
+
* lookup for the object's whole lifetime, when an object literal declares a
|
|
8
|
+
* get/set member, when a data property is redefined as an accessor after
|
|
9
|
+
* creation, or when an accessor is defined with a function its shape
|
|
10
|
+
* transition has not recorded: a closure created per request is a new
|
|
11
|
+
* function every time. So an accessor on a per-request object is a
|
|
12
|
+
* module-level descriptor, and one that needs per-object state reads a
|
|
13
|
+
* per-object closure from a non-enumerable symbol slot (slotAccessor +
|
|
14
|
+
* defineSlot). A derived object (Object.create(obj)) reads the slot through
|
|
15
|
+
* its prototype; the descriptor copied onto another object reads that
|
|
16
|
+
* object's slot instead. context-fast-properties.test.ts pins all of it.
|
|
17
|
+
*
|
|
18
|
+
* Dependency-free leaf: handle-store.ts is imported by request-context.ts,
|
|
19
|
+
* so these cannot live in either.
|
|
20
|
+
*/
|
|
21
|
+
/**
|
|
22
|
+
* An accessor descriptor whose getter calls the receiver's `slot` closure.
|
|
23
|
+
* Call it once at module level and share the result.
|
|
24
|
+
*/
|
|
25
|
+
export declare function slotAccessor(slot: symbol, enumerable: boolean): PropertyDescriptor;
|
|
26
|
+
/** Define `slot` on `target` as a non-enumerable, read-only data property. */
|
|
27
|
+
export declare function defineSlot(target: object, slot: symbol, value: unknown): void;
|
|
28
|
+
/** Define `key` on `target` as a non-enumerable, writable data property. */
|
|
29
|
+
export declare function defineHidden(target: object, key: PropertyKey, value: unknown): void;
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
* - RSC: see @rangojs/router/testing/flight
|
|
35
35
|
*/
|
|
36
36
|
export { runMiddleware } from "./run-middleware.js";
|
|
37
|
-
export type { RunMiddlewareOptions, RunMiddlewareResult, } from "./run-middleware.js";
|
|
37
|
+
export type { RunMiddlewareOptions, RunMiddlewareResult, RunMiddlewareRewrite, } from "./run-middleware.js";
|
|
38
38
|
export { runLoader, runLoaderResult } from "./run-loader.js";
|
|
39
39
|
export type { RunLoaderOptions, RunLoaderResult, UseResolver, TestLoaderContext, } from "./run-loader.js";
|
|
40
40
|
export { runTransitionWhen } from "./run-transition-when.js";
|
|
@@ -300,6 +300,14 @@ export interface RenderRouteOptions {
|
|
|
300
300
|
* - Needs @testing-library/react >= 16.2.0; throws on older versions.
|
|
301
301
|
*/
|
|
302
302
|
hydrate?: boolean;
|
|
303
|
+
/**
|
|
304
|
+
* The path middleware rewrote `request` to (`throw rewrite()`): the leaf
|
|
305
|
+
* route is matched against it for params, while the location stays
|
|
306
|
+
* `request`, as on a rewritten document. The server pass and hydration
|
|
307
|
+
* both see `request` (`usePathname()`, `useSearchParams()`), as production
|
|
308
|
+
* renders a rewritten page with the visitor's URL (`/middleware` skill).
|
|
309
|
+
*/
|
|
310
|
+
rewrite?: string;
|
|
303
311
|
}
|
|
304
312
|
/**
|
|
305
313
|
* Imperative handle returned alongside the RTL result.
|
|
@@ -13,6 +13,10 @@
|
|
|
13
13
|
*
|
|
14
14
|
* `nextCalled` counts how many times the terminal `next()` (the finalHandler)
|
|
15
15
|
* ran: 0 when the chain short-circuited, 1 when it ran to completion.
|
|
16
|
+
*
|
|
17
|
+
* A `throw rewrite(target)` is reported as `result.rewrite` (the resolved
|
|
18
|
+
* target) instead of failing the run: production re-dispatches the request
|
|
19
|
+
* there, which this primitive does not do.
|
|
16
20
|
*/
|
|
17
21
|
import { type RequestContext } from "../server/request-context.js";
|
|
18
22
|
import type { MiddlewareFn } from "../router/middleware-types.js";
|
|
@@ -79,6 +83,12 @@ export interface RunMiddlewareOptions<TEnv = any> {
|
|
|
79
83
|
*/
|
|
80
84
|
stateCookie?: StateCookieSeed;
|
|
81
85
|
}
|
|
86
|
+
/** A rewrite the chain threw (RunMiddlewareResult.rewrite). */
|
|
87
|
+
export interface RunMiddlewareRewrite {
|
|
88
|
+
pathname: string;
|
|
89
|
+
search: string;
|
|
90
|
+
routeName?: string;
|
|
91
|
+
}
|
|
82
92
|
/**
|
|
83
93
|
* Result of runMiddleware.
|
|
84
94
|
*/
|
|
@@ -94,6 +104,16 @@ export interface RunMiddlewareResult<TEnv = any> {
|
|
|
94
104
|
ctx: RequestContext<TEnv>;
|
|
95
105
|
/** Number of times the terminal handler ran (0 = short-circuited, 1 = passed through). */
|
|
96
106
|
nextCalled: number;
|
|
107
|
+
/**
|
|
108
|
+
* The target of a `throw rewrite(...)` from the chain, resolved as
|
|
109
|
+
* production resolves it (a path basename-prefixed, a route name through
|
|
110
|
+
* `routeMap`): `pathname` and `search` of the URL the request would render,
|
|
111
|
+
* and `routeName` when the rewrite named a route. `undefined` when the chain
|
|
112
|
+
* did not rewrite. On a rewrite, `response` carries what the chain set
|
|
113
|
+
* before the throw (status, headers, cookies), which production keeps for
|
|
114
|
+
* the target's response.
|
|
115
|
+
*/
|
|
116
|
+
rewrite?: RunMiddlewareRewrite;
|
|
97
117
|
/**
|
|
98
118
|
* Whether the chain called `ctx.dynamic()` (the PPR shell opt-out). The public
|
|
99
119
|
* way to assert the opt-out without reading the `@internal` `ctx._dynamic`.
|
|
@@ -29,7 +29,8 @@
|
|
|
29
29
|
*
|
|
30
30
|
* A `Prerender` route serves its handler layer from the artifact
|
|
31
31
|
* `router.matchForPrerender` bakes for the URL (on its first request, kept
|
|
32
|
-
* until resetShellTestState), through the production prerender store
|
|
32
|
+
* until resetShellTestState), through the production prerender store; an
|
|
33
|
+
* intercept of it serves from the intercept variant the bake keeps. Its
|
|
33
34
|
* first `ppr` request is a MISS with a runtime capture, as a URL without a
|
|
34
35
|
* build-time shell is in production; build-time shells are e2e-only. An
|
|
35
36
|
* on-demand route (`Prerender(..., { onDemand })`) bakes nothing here: it
|
|
@@ -13,3 +13,9 @@ export declare function unwrapsSynchronously(stream: Promise<unknown>): boolean;
|
|
|
13
13
|
* listing a 0 ms promise on every reader that calls it.
|
|
14
14
|
*/
|
|
15
15
|
export declare const SETTLED_THENABLE: Promise<undefined>;
|
|
16
|
+
/**
|
|
17
|
+
* The value React reads from `value` without suspending: `value` itself when
|
|
18
|
+
* it is not a promise, a promise's `value` once it carries React's or Flight's
|
|
19
|
+
* `status: "fulfilled"`. Undefined while it is pending or rejected.
|
|
20
|
+
*/
|
|
21
|
+
export declare function settledValue<T>(value: T | Promise<T>): T | undefined;
|
|
@@ -48,6 +48,13 @@ export interface RequestScope<TEnv = DefaultEnv> {
|
|
|
48
48
|
* cache keying.
|
|
49
49
|
*/
|
|
50
50
|
originalUrl: URL;
|
|
51
|
+
/**
|
|
52
|
+
* The visitor's URL (the address bar, search included) when middleware
|
|
53
|
+
* rewrote this request with `throw rewrite()`; `undefined` otherwise. `url`,
|
|
54
|
+
* `pathname` and `searchParams` are the rewrite target's. After several
|
|
55
|
+
* rewrites this is still the first URL. Each context gets its own copy.
|
|
56
|
+
*/
|
|
57
|
+
rewrittenFrom?: URL;
|
|
51
58
|
/** URL pathname (same as `url.pathname`). */
|
|
52
59
|
pathname: string;
|
|
53
60
|
/**
|
|
@@ -188,21 +188,24 @@ export interface DiscoveryState {
|
|
|
188
188
|
/** Cleanup function for build-time env resources (e.g., miniflare). */
|
|
189
189
|
buildEnvDispose?: (() => Promise<void> | void) | null;
|
|
190
190
|
/**
|
|
191
|
-
* Set when the most recent discovery
|
|
192
|
-
* cold
|
|
193
|
-
* discovery. While set, the route-file
|
|
194
|
-
* change as a rediscovery trigger
|
|
191
|
+
* Set when the most recent dev discovery failed: an HMR re-discovery, or the
|
|
192
|
+
* cold discovery on the Node RSC runner or the Cloudflare temp runner.
|
|
193
|
+
* Cleared on the next successful discovery. While set, the route-file
|
|
194
|
+
* watcher treats any in-scan source change as a rediscovery trigger
|
|
195
|
+
* (recovery mode).
|
|
195
196
|
*/
|
|
196
197
|
lastDiscoveryError?: {
|
|
197
198
|
message: string;
|
|
198
199
|
at: number;
|
|
199
200
|
} | null;
|
|
200
201
|
}
|
|
202
|
+
/** Record a failed dev discovery (lastDiscoveryError): recovery mode. */
|
|
203
|
+
export declare function recordDiscoveryFailure(state: Pick<DiscoveryState, "lastDiscoveryError">, err: unknown): void;
|
|
201
204
|
/**
|
|
202
|
-
* Whether the route-file watcher can re-run runtime discovery
|
|
203
|
-
* manifest
|
|
204
|
-
*
|
|
205
|
-
* the
|
|
205
|
+
* Whether the route-file watcher can re-run runtime discovery: a committed
|
|
206
|
+
* manifest, or a recorded failure. A failed cold discovery commits none, and
|
|
207
|
+
* without its recorded failure the dev server stayed broken until a restart,
|
|
208
|
+
* on the Node runner and on Cloudflare alike.
|
|
206
209
|
*/
|
|
207
|
-
export declare function canRefreshRuntimeDiscovery(state: Pick<DiscoveryState, "perRouterManifests" | "lastDiscoveryError"
|
|
210
|
+
export declare function canRefreshRuntimeDiscovery(state: Pick<DiscoveryState, "perRouterManifests" | "lastDiscoveryError">): boolean;
|
|
208
211
|
export declare function createDiscoveryState(entryPath: string | undefined, opts: PluginOptions | undefined): DiscoveryState & ClientUrlDiscoveryState;
|