@rangojs/router 0.2.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -1
- package/dist/types/browser/event-controller.d.ts +4 -0
- package/dist/types/browser/link-interceptor.d.ts +17 -7
- package/dist/types/browser/navigation-bridge.d.ts +13 -1
- package/dist/types/browser/notify-listeners.d.ts +2 -0
- package/dist/types/browser/prefetch/cache.d.ts +1 -1
- package/dist/types/browser/prefetch/default-strategy.d.ts +31 -0
- package/dist/types/browser/prefetch/invalidation.d.ts +6 -0
- package/dist/types/browser/prefetch/loader.d.ts +3 -1
- package/dist/types/browser/prefetch/observer.d.ts +3 -6
- package/dist/types/browser/prefetch/runtime.d.ts +0 -1
- package/dist/types/browser/rango-state.d.ts +4 -0
- package/dist/types/browser/react/Link.d.ts +11 -19
- package/dist/types/browser/react/context.d.ts +3 -0
- package/dist/types/browser/rsc-router.d.ts +7 -2
- package/dist/types/browser/types.d.ts +6 -0
- package/dist/types/cache/cache-key-utils.d.ts +11 -3
- package/dist/types/cache/cache-scope.d.ts +82 -3
- package/dist/types/cache/cf/cf-cache-store.d.ts +2 -2
- package/dist/types/cache/index.d.ts +3 -1
- package/dist/types/cache/search-params-filter.d.ts +64 -0
- package/dist/types/cache/shell-snapshot.d.ts +4 -4
- package/dist/types/cache/types.d.ts +36 -2
- package/dist/types/cache/vercel/vercel-cache-store.d.ts +2 -2
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.rsc.d.ts +1 -0
- package/dist/types/router/match-middleware/cache-lookup.d.ts +13 -0
- package/dist/types/router/navigation-snapshot.d.ts +29 -0
- package/dist/types/router/prefetch-default.d.ts +28 -0
- package/dist/types/router/router-interfaces.d.ts +7 -0
- package/dist/types/router/router-options.d.ts +54 -0
- package/dist/types/rsc/capture-queue.d.ts +6 -0
- package/dist/types/rsc/shell-build-manifest.d.ts +7 -1
- package/dist/types/rsc/shell-capture.d.ts +15 -7
- package/dist/types/rsc/shell-serve.d.ts +11 -4
- package/dist/types/rsc/types.d.ts +19 -0
- package/dist/types/server/request-context.d.ts +57 -4
- package/dist/types/testing/e2e/index.d.ts +2 -2
- package/dist/types/testing/e2e/page-helpers.d.ts +24 -0
- package/dist/types/testing/render-route.d.ts +10 -1
- package/dist/types/testing/shell-status.d.ts +6 -3
- package/dist/types/vite/plugin-types.d.ts +1 -1
- package/dist/vite/index.js +9 -6
- package/package.json +23 -22
- package/skills/caching/SKILL.md +39 -0
- package/skills/comparison/references/framework-comparison.md +9 -2
- package/skills/links/SKILL.md +24 -0
- package/skills/ppr/SKILL.md +80 -16
- package/skills/router-setup/SKILL.md +9 -0
- package/skills/testing/client-components.md +15 -14
- package/skills/vercel/SKILL.md +1 -1
- package/src/browser/event-controller.ts +110 -11
- package/src/browser/link-interceptor.ts +469 -20
- package/src/browser/navigation-bridge.ts +71 -2
- package/src/browser/navigation-store.ts +24 -1
- package/src/browser/notify-listeners.ts +22 -0
- package/src/browser/prefetch/cache.ts +4 -2
- package/src/browser/prefetch/default-strategy.ts +74 -0
- package/src/browser/prefetch/invalidation.ts +30 -0
- package/src/browser/prefetch/loader.ts +18 -17
- package/src/browser/prefetch/observer.ts +50 -22
- package/src/browser/prefetch/runtime.ts +0 -1
- package/src/browser/rango-state.ts +21 -0
- package/src/browser/react/Link.tsx +111 -101
- package/src/browser/react/NavigationProvider.tsx +1 -0
- package/src/browser/react/context.ts +4 -0
- package/src/browser/rsc-router.tsx +30 -9
- package/src/browser/types.ts +6 -0
- package/src/cache/cache-key-utils.ts +18 -4
- package/src/cache/cache-runtime.ts +7 -2
- package/src/cache/cache-scope.ts +152 -23
- package/src/cache/cf/cf-cache-store.ts +55 -16
- package/src/cache/document-cache.ts +7 -1
- package/src/cache/index.ts +7 -0
- package/src/cache/search-params-filter.ts +118 -0
- package/src/cache/shell-snapshot.ts +8 -4
- package/src/cache/types.ts +39 -2
- package/src/cache/vercel/vercel-cache-store.ts +22 -3
- package/src/index.rsc.ts +4 -0
- package/src/index.ts +6 -0
- package/src/router/match-middleware/cache-lookup.ts +146 -33
- package/src/router/match-middleware/cache-store.ts +70 -0
- package/src/router/navigation-snapshot.ts +46 -6
- package/src/router/prefetch-default.ts +59 -0
- package/src/router/router-interfaces.ts +8 -0
- package/src/router/router-options.ts +59 -1
- package/src/router.ts +7 -0
- package/src/rsc/capture-queue.ts +24 -1
- package/src/rsc/full-payload.ts +1 -0
- package/src/rsc/handler.ts +10 -0
- package/src/rsc/response-cache-serve.ts +1 -1
- package/src/rsc/rsc-rendering.ts +367 -40
- package/src/rsc/shell-build-manifest.ts +8 -1
- package/src/rsc/shell-capture.ts +99 -50
- package/src/rsc/shell-serve.ts +14 -6
- package/src/rsc/types.ts +19 -0
- package/src/server/request-context.ts +62 -3
- package/src/testing/dispatch.ts +21 -3
- package/src/testing/e2e/index.ts +6 -0
- package/src/testing/e2e/page-helpers.ts +47 -0
- package/src/testing/e2e/parity.ts +13 -0
- package/src/testing/render-route.tsx +86 -17
- package/src/testing/shell-status.ts +20 -3
- package/src/vite/plugin-types.ts +1 -1
- package/src/vite/plugins/vercel-output.ts +2 -2
|
@@ -10,6 +10,19 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import type { ResolvedSegment } from "../types.js";
|
|
12
12
|
import type { RequestContext } from "../server/request-context.js";
|
|
13
|
+
/**
|
|
14
|
+
* Sentinel a `SegmentCacheStore.get` MAY return instead of `null` when the
|
|
15
|
+
* read FAILED (backend error) rather than genuinely missing. For the render
|
|
16
|
+
* outcome the two are identical — render fresh, re-cache — so hit/miss-only
|
|
17
|
+
* consumers can treat it as a miss. The PPR replay composition needs the
|
|
18
|
+
* distinction: an errored explicit-tier read must render uncached
|
|
19
|
+
* (`lookupRouteDetailed` classifies it `error`), never be substituted by the
|
|
20
|
+
* seeded doc record — the built-in stores swallow backend errors internally,
|
|
21
|
+
* so without this signal their failures read as replayable misses. Third-party
|
|
22
|
+
* stores returning plain `null` on error keep the miss classification.
|
|
23
|
+
*/
|
|
24
|
+
export declare const CACHE_READ_ERROR: unique symbol;
|
|
25
|
+
export type CacheReadError = typeof CACHE_READ_ERROR;
|
|
13
26
|
/**
|
|
14
27
|
* Result from cache get() including data and revalidation status
|
|
15
28
|
*/
|
|
@@ -81,9 +94,10 @@ export interface SegmentCacheStore<TEnv = unknown> {
|
|
|
81
94
|
readonly keyGenerator?: (ctx: RequestContext<TEnv>, defaultKey: string) => string | Promise<string>;
|
|
82
95
|
/**
|
|
83
96
|
* Get cached entry data by key
|
|
84
|
-
* @returns Cache result with data and staleness,
|
|
97
|
+
* @returns Cache result with data and staleness, null if not found/expired,
|
|
98
|
+
* or CACHE_READ_ERROR when the read failed (optional — see the sentinel).
|
|
85
99
|
*/
|
|
86
|
-
get(key: string): Promise<CacheGetResult | null>;
|
|
100
|
+
get(key: string): Promise<CacheGetResult | null | CacheReadError>;
|
|
87
101
|
/**
|
|
88
102
|
* Store entry data with TTL
|
|
89
103
|
* @param key - Cache key
|
|
@@ -265,6 +279,26 @@ export interface ShellCacheEntry {
|
|
|
265
279
|
* heals it. See docs/design/ppr-shell-resume.md ("the capture data snapshot").
|
|
266
280
|
*/
|
|
267
281
|
snapshot?: ShellSnapshotRecord[];
|
|
282
|
+
/**
|
|
283
|
+
* The key of the CANONICAL document segment record inside `snapshot` — the
|
|
284
|
+
* one navigation replay can actually consume (resolved under the implicit
|
|
285
|
+
* doc namespace at capture; see CacheScope.cacheRoute). Replay eligibility
|
|
286
|
+
* requires this exact record: the snapshot also carries incidentally
|
|
287
|
+
* recorded explicit-tier records (RecordingShellStore passthroughs) whose
|
|
288
|
+
* keys a partial lookup can never resolve, and counting those declared
|
|
289
|
+
* entries "replayable" that always missed (`snapshot-miss` flip-flop).
|
|
290
|
+
* Absent on entries captured before the field existed OR when the capture
|
|
291
|
+
* recorded no doc record (cache(false)/condition-false routes, prerender
|
|
292
|
+
* short-circuit) — both read as `no-segment-snapshot`; recapture heals the
|
|
293
|
+
* former.
|
|
294
|
+
*/
|
|
295
|
+
docKey?: string;
|
|
296
|
+
/**
|
|
297
|
+
* The entry was captured from a partial request only to produce an eligible
|
|
298
|
+
* segment snapshot. Document serving must treat its HTML prelude as a miss;
|
|
299
|
+
* the partial request's headers and middleware state are not document state.
|
|
300
|
+
*/
|
|
301
|
+
navigationOnly?: true;
|
|
268
302
|
/**
|
|
269
303
|
* True when the capture's HANDLER layer declared per-request liveness: a
|
|
270
304
|
* handle pushed OUTSIDE a DSL loader scope carried a nested thenable (the
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
* `getCache(...)` result, which satisfies the shape structurally. That keeps the
|
|
31
31
|
* router free of a hard Vercel dependency.
|
|
32
32
|
*/
|
|
33
|
-
import type { SegmentCacheStore, CachedEntryData, CacheDefaults, CacheGetResult, CacheItemResult, CacheItemOptions, ShellCacheEntry } from "../types.js";
|
|
33
|
+
import type { SegmentCacheStore, CachedEntryData, CacheDefaults, CacheGetResult, CacheItemResult, CacheItemOptions, ShellCacheEntry, CacheReadError } from "../types.js";
|
|
34
34
|
import type { RequestContext } from "../../server/request-context.js";
|
|
35
35
|
/**
|
|
36
36
|
* Minimal structural shape of the Vercel Runtime Cache returned by `getCache()`
|
|
@@ -194,7 +194,7 @@ export declare class VercelCacheStore<TEnv = unknown> implements SegmentCacheSto
|
|
|
194
194
|
private readonly name?;
|
|
195
195
|
private readonly debug?;
|
|
196
196
|
constructor(options: VercelCacheStoreOptions<TEnv>);
|
|
197
|
-
get(key: string): Promise<CacheGetResult | null>;
|
|
197
|
+
get(key: string): Promise<CacheGetResult | null | CacheReadError>;
|
|
198
198
|
set(key: string, data: CachedEntryData, ttl: number, swr?: number): Promise<void>;
|
|
199
199
|
delete(key: string): Promise<boolean>;
|
|
200
200
|
getResponse(key: string): Promise<{
|
package/dist/types/index.d.ts
CHANGED
|
@@ -13,6 +13,7 @@ export { RouteNotFoundError, DataNotFoundError, notFound, MiddlewareError, Handl
|
|
|
13
13
|
export type { DocumentProps, DefaultEnv, RouteDefinition, RouteConfig, RouteDefinitionOptions, TrailingSlashMode, Handler, // Supports params object, path pattern, or route name
|
|
14
14
|
HandlerContext, ExtractParams, GenericParams, Middleware, RevalidateParams, Revalidate, ActionRef, RouteKeys, LoaderDefinition, LoaderFn, LoaderContext, FetchableLoaderOptions, LoadOptions, ErrorInfo, ErrorBoundaryFallbackProps, ErrorBoundaryHandler, ClientErrorBoundaryFallbackProps, NotFoundInfo, NotFoundBoundaryFallbackProps, NotFoundBoundaryHandler, ErrorPhase, OnErrorContext, OnErrorCallback, } from "./types.js";
|
|
15
15
|
export type { SearchSchema, SearchSchemaValue, ResolveSearchSchema, RouteSearchParams, RouteParams, } from "./search-params.js";
|
|
16
|
+
export { TRACKING_SEARCH_PARAMS, type CacheSearchParams, } from "./cache/search-params-filter.js";
|
|
16
17
|
export { createLoader } from "./loader.js";
|
|
17
18
|
export type { RouteHelpers, RouteHandlers } from "./route-definition.js";
|
|
18
19
|
export type { TransitionConfig, TransitionWhenFn, TransitionWhenContext, ViewTransitionClass, } from "./types.js";
|
|
@@ -24,6 +24,7 @@ export { Static, type StaticHandlerDefinition, type StaticHandlerOptions, } from
|
|
|
24
24
|
export { urls, type PathHelpers, type PathOptions, type PartialPrerenderProps, type UrlPatterns, type IncludeOptions, type IncludeItem, type RouteResponse, type ProblemDetails, type ResponseHandler, type ResponseHandlerContext, type JsonResponseHandler, type TextResponseHandler, type JsonValue, type ResponsePathFn, type JsonResponsePathFn, type TextResponsePathFn, } from "./urls.js";
|
|
25
25
|
export { createRouter, type Rango, type RootLayoutProps, type RouterRequestInput, } from "./router.js";
|
|
26
26
|
export type { HandlerCacheConfig } from "./rsc/types.js";
|
|
27
|
+
export { TRACKING_SEARCH_PARAMS, type CacheSearchParams, } from "./cache/search-params-filter.js";
|
|
27
28
|
export { Meta } from "./handles/meta.js";
|
|
28
29
|
export { Script, type ScriptConfig, type ScriptAttributes, } from "./handles/script.js";
|
|
29
30
|
export { Breadcrumbs, type BreadcrumbItem } from "./handles/breadcrumbs.js";
|
|
@@ -92,7 +92,20 @@
|
|
|
92
92
|
* - Action context (if POST)
|
|
93
93
|
*/
|
|
94
94
|
import type { ResolvedSegment } from "../../types.js";
|
|
95
|
+
import type { EntryData } from "../../server/context.js";
|
|
95
96
|
import type { MatchContext, MatchPipelineState } from "../match-context.js";
|
|
97
|
+
/**
|
|
98
|
+
* Whether the prerender store holds a baked entry for this route + params.
|
|
99
|
+
* Consulted by the PPR replay gate (matchPartialWithPprReplay), which must
|
|
100
|
+
* only report `prerender-store` when the short-circuit below will actually
|
|
101
|
+
* serve: a Passthrough(Prerender()) route with an unbaked/passthrough param
|
|
102
|
+
* misses the store and renders live, and replay — including its heal
|
|
103
|
+
* capture — must stay available for it (withCacheStore records the doc
|
|
104
|
+
* record on that path; state.cacheSource is not "prerender"). The store
|
|
105
|
+
* memoizes per routeKey/paramHash, so this probe and tryPrerenderLookup's
|
|
106
|
+
* subsequent get() share one underlying load.
|
|
107
|
+
*/
|
|
108
|
+
export declare function prerenderEntryExists(routeKey: string | undefined, params: Record<string, string>, pathname: string, entries: EntryData[]): Promise<boolean>;
|
|
96
109
|
/**
|
|
97
110
|
* Async generator middleware type
|
|
98
111
|
*/
|
|
@@ -18,5 +18,34 @@ export interface NavigationSnapshot {
|
|
|
18
18
|
export interface ResolveNavigationDeps {
|
|
19
19
|
findMatch: (pathname: string) => RouteMatchResult | null | Promise<RouteMatchResult | null>;
|
|
20
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* The raw navigation-context header for a partial request, or null when the
|
|
23
|
+
* request carries none. Single source of truth shared by resolveNavigation and
|
|
24
|
+
* the PPR replay gate (matchPartialWithPprReplay): a context-less partial can
|
|
25
|
+
* never produce a partial match, so the replay path must decide
|
|
26
|
+
* `no-navigation-context` BEFORE spending shell-store reads — the two
|
|
27
|
+
* predicates drifting apart would misattribute the bypass again.
|
|
28
|
+
*/
|
|
29
|
+
export declare function getNavigationContextHeader(request: Request): string | null;
|
|
30
|
+
/**
|
|
31
|
+
* Whether withCacheLookup's prerender short-circuit will serve this partial
|
|
32
|
+
* from the build-time prerender store: a Prerender() match (`matched.pr`)
|
|
33
|
+
* outside dev HMR — the short-circuit is disabled on X-RSC-HMR so HMR
|
|
34
|
+
* navigations pick up edited modules. Shared by withCacheLookup and the PPR
|
|
35
|
+
* replay gate (matchPartialWithPprReplay) for the same drift reason as
|
|
36
|
+
* getNavigationContextHeader: the gate's `prerender-store` bypass must decide
|
|
37
|
+
* exactly what the middleware will actually do. (Both callers additionally
|
|
38
|
+
* exclude actions on their own paths — the gate via its GET-only check.)
|
|
39
|
+
*/
|
|
40
|
+
export declare function prerenderStoreShortCircuits(pr: true | undefined, request: Request): boolean;
|
|
41
|
+
/**
|
|
42
|
+
* The intercept-source header for a partial request, or null when the request
|
|
43
|
+
* carries none. Shared by resolveNavigation and the PPR replay gate's
|
|
44
|
+
* prerender probe: intercept navigations consult the intercept-specific
|
|
45
|
+
* prerender artifact (`paramHash + "/i"`), so the probe must check the same
|
|
46
|
+
* variant the middleware will — probing the bare hash for an intercept
|
|
47
|
+
* request would report `prerender-store` for an artifact that cannot serve.
|
|
48
|
+
*/
|
|
49
|
+
export declare function getInterceptSourceHeader(request: Request): string | null;
|
|
21
50
|
export declare function resolveNavigation(request: Request, url: URL, currentRouteKey: string, deps: ResolveNavigationDeps): Promise<NavigationSnapshot | null>;
|
|
22
51
|
export declare function createNavigationSnapshot(overrides?: Partial<NavigationSnapshot>): NavigationSnapshot;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve the router-wide default Link prefetch strategy once, at router init.
|
|
3
|
+
* The resolved value ships to the client in payload metadata; the browser
|
|
4
|
+
* entry applies it via `setDefaultPrefetchStrategy` (browser/prefetch/
|
|
5
|
+
* default-strategy.ts) and every `<Link>` without an explicit `prefetch` prop
|
|
6
|
+
* falls back to it.
|
|
7
|
+
*
|
|
8
|
+
* The type lives HERE (not in browser/react/Link.tsx) because both seats need
|
|
9
|
+
* it: this server-side resolver and the client Link/default-strategy modules.
|
|
10
|
+
* Link.tsx re-exports it so the public `PrefetchStrategy` export path is
|
|
11
|
+
* unchanged.
|
|
12
|
+
*
|
|
13
|
+
* Policy note: automatic prefetch stays quiet in development, matching the
|
|
14
|
+
* production-only default used by Next.js. Explicit router and per-Link
|
|
15
|
+
* strategies still work in every mode. Invalid untyped inputs fall back to the
|
|
16
|
+
* current environment's default.
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* Prefetch strategy for the Link component
|
|
20
|
+
* - "hover": Prefetch on mouse enter (direct, no queue)
|
|
21
|
+
* - "viewport": Prefetch when link enters viewport (queued, waits for idle)
|
|
22
|
+
* - "render": Prefetch on component mount regardless of visibility (queued, waits for idle)
|
|
23
|
+
* - "adaptive": Hover on pointer devices, viewport on touch devices
|
|
24
|
+
* - "none": No prefetching
|
|
25
|
+
*/
|
|
26
|
+
export type PrefetchStrategy = "hover" | "viewport" | "render" | "adaptive" | "none";
|
|
27
|
+
export declare const DEFAULT_PREFETCH_STRATEGY: PrefetchStrategy;
|
|
28
|
+
export declare function resolveDefaultPrefetch(raw: PrefetchStrategy | undefined, nodeEnv?: string | undefined): PrefetchStrategy;
|
|
@@ -249,6 +249,13 @@ export interface RangoInternal<TEnv = any, TRoutes extends Record<string, unknow
|
|
|
249
249
|
* prefetchConcurrency.
|
|
250
250
|
*/
|
|
251
251
|
readonly prefetchConcurrency: number;
|
|
252
|
+
/**
|
|
253
|
+
* Router-wide default Link prefetch strategy for Links without an explicit
|
|
254
|
+
* `prefetch` prop. Shipped to the client in payload metadata. Derived from
|
|
255
|
+
* the `defaultPrefetch` option (default "none" in development and
|
|
256
|
+
* "viewport" in production).
|
|
257
|
+
*/
|
|
258
|
+
readonly defaultPrefetch: import("./prefetch-default.js").PrefetchStrategy;
|
|
252
259
|
/**
|
|
253
260
|
* Resolved rango state cookie name (`{prefix}_{routerId}`), composed once at
|
|
254
261
|
* router init and shipped to the client in payload metadata. The server-side
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ComponentType, ReactNode } from "react";
|
|
2
2
|
import type { SegmentCacheStore } from "../cache/types.js";
|
|
3
|
+
import type { CacheSearchParams } from "../cache/search-params-filter.js";
|
|
3
4
|
import type { ErrorBoundaryHandler, NotFoundBoundaryHandler, OnErrorCallback } from "../types";
|
|
4
5
|
import type { NonceProvider } from "../rsc/types.js";
|
|
5
6
|
import type { ShellCaptureDebug } from "../rsc/shell-capture.js";
|
|
@@ -7,6 +8,7 @@ import type { ExecutionContext } from "../server/request-context.js";
|
|
|
7
8
|
import type { UrlPatterns } from "../urls.js";
|
|
8
9
|
import type { UrlBuilder } from "../urls/pattern-types.js";
|
|
9
10
|
import type { NamedRouteEntry } from "./content-negotiation.js";
|
|
11
|
+
import type { PrefetchStrategy } from "./prefetch-default.js";
|
|
10
12
|
import type { TelemetrySink } from "./telemetry.js";
|
|
11
13
|
import type { RouterTracingConfig } from "./tracing.js";
|
|
12
14
|
import type { RouterTimeouts, OnTimeoutCallback } from "./timeout.js";
|
|
@@ -282,13 +284,32 @@ export interface RangoOptions<TEnv = any> {
|
|
|
282
284
|
* }),
|
|
283
285
|
* });
|
|
284
286
|
* ```
|
|
287
|
+
*
|
|
288
|
+
* `searchParams` controls which query params key the cache (default:
|
|
289
|
+
* `"all"`). Cache keys only -- handlers still see the full query string.
|
|
290
|
+
* Excluding a param is a promise that rendered output does not depend on
|
|
291
|
+
* it; if it does, the first variant is cached and served to everyone.
|
|
292
|
+
*
|
|
293
|
+
* @example Ignore tracking params for cache keys
|
|
294
|
+
* ```typescript
|
|
295
|
+
* import { TRACKING_SEARCH_PARAMS } from "@rangojs/router";
|
|
296
|
+
*
|
|
297
|
+
* const router = createRouter({
|
|
298
|
+
* cache: {
|
|
299
|
+
* store: cacheStore,
|
|
300
|
+
* searchParams: { exclude: TRACKING_SEARCH_PARAMS },
|
|
301
|
+
* },
|
|
302
|
+
* });
|
|
303
|
+
* ```
|
|
285
304
|
*/
|
|
286
305
|
cache?: {
|
|
287
306
|
store: SegmentCacheStore;
|
|
288
307
|
enabled?: boolean;
|
|
308
|
+
searchParams?: CacheSearchParams;
|
|
289
309
|
} | ((env: TEnv, ctx?: ExecutionContext) => {
|
|
290
310
|
store: SegmentCacheStore;
|
|
291
311
|
enabled?: boolean;
|
|
312
|
+
searchParams?: CacheSearchParams;
|
|
292
313
|
});
|
|
293
314
|
/**
|
|
294
315
|
* Named cache profiles for "use cache" directive.
|
|
@@ -495,6 +516,39 @@ export interface RangoOptions<TEnv = any> {
|
|
|
495
516
|
* @default 2
|
|
496
517
|
*/
|
|
497
518
|
prefetchConcurrency?: number;
|
|
519
|
+
/**
|
|
520
|
+
* Default prefetch strategy for every `<Link>` that does not set its own
|
|
521
|
+
* `prefetch` prop and every eligible intercepted plain anchor. Plain anchors
|
|
522
|
+
* can opt out with `data-prefetch="false"` or `data-prefetch="none"`. Common
|
|
523
|
+
* static-resource suffixes are excluded unless `data-prefetch="true"` marks
|
|
524
|
+
* the URL as an application route. Mark side-effectful GET links such as
|
|
525
|
+
* `/logout` with an opt-out because the router cannot infer endpoint safety.
|
|
526
|
+
* A per-Link `prefetch` prop always wins in both directions (a Link can opt
|
|
527
|
+
* out with `prefetch="none"`, or opt in under `defaultPrefetch: "none"`).
|
|
528
|
+
*
|
|
529
|
+
* - `"viewport"` (production default): prefetch when the link enters the viewport —
|
|
530
|
+
* idle-gated and queued (see `prefetchConcurrency`), so prefetches never
|
|
531
|
+
* compete with hydration or an active navigation.
|
|
532
|
+
* - `"hover"`: prefetch on mouse enter only. Much lighter on the server —
|
|
533
|
+
* only links the pointer approaches are fetched — at the cost of the
|
|
534
|
+
* ~100-300ms head start viewport prefetch gives.
|
|
535
|
+
* - `"adaptive"`: `"hover"` on pointer devices, `"viewport"` on touch
|
|
536
|
+
* devices (no hover to wait for).
|
|
537
|
+
* - `"render"`: prefetch on mount regardless of visibility.
|
|
538
|
+
* - `"none"`: manual mode — nothing prefetches unless a Link opts in.
|
|
539
|
+
*
|
|
540
|
+
* Automatic prefetch defaults to `"none"` in development and `"viewport"`
|
|
541
|
+
* in production. With the production default, every visible Link triggers an
|
|
542
|
+
* RSC render (loaders included) on the server. Routes served from cache/PPR
|
|
543
|
+
* absorb this cheaply; per-user dynamic routes pay full price per viewport
|
|
544
|
+
* entry. Set `"hover"`, `"adaptive"`, or `"none"` when that cost matters.
|
|
545
|
+
*
|
|
546
|
+
* To disable the prefetch subsystem entirely (including per-Link opt-ins
|
|
547
|
+
* and `useRouter().prefetch()`), set `prefetchCacheTTL: false` instead.
|
|
548
|
+
*
|
|
549
|
+
* @default "none" in development; "viewport" in production
|
|
550
|
+
*/
|
|
551
|
+
defaultPrefetch?: PrefetchStrategy;
|
|
498
552
|
/**
|
|
499
553
|
* Prefix for the rango state cookie name. The resolved name is
|
|
500
554
|
* `{prefix}_{routerId}`; the prefix is sanitized to cookie-name-safe
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/** Bound queued/running capture closures retained by one isolate. */
|
|
2
|
+
export declare const MAX_ADMITTED_CAPTURES: number;
|
|
3
|
+
/** The caller may drop this best-effort capture and retry on a later request. */
|
|
4
|
+
export declare class CaptureQueueFullError extends Error {
|
|
5
|
+
constructor();
|
|
6
|
+
}
|
|
1
7
|
/**
|
|
2
8
|
* Run `task` after every previously enqueued capture has settled. Returns a
|
|
3
9
|
* promise for THIS task's completion (rejections propagate to the caller —
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
* markers say whether it is still current.
|
|
26
26
|
*/
|
|
27
27
|
import type { SegmentCacheStore, ShellCacheEntry } from "../cache/types.js";
|
|
28
|
+
import type { SearchParamsFilter } from "../cache/search-params-filter.js";
|
|
28
29
|
/** One baked manifest record (the __ps asset module's default export). */
|
|
29
30
|
export interface BuildShellEntry {
|
|
30
31
|
entry: ShellCacheEntry;
|
|
@@ -79,6 +80,11 @@ export interface DevShellLookup {
|
|
|
79
80
|
* version validity, payload integrity, and tag-invalidation markers. Returns
|
|
80
81
|
* null on any gate failure — the caller degrades to the ordinary MISS path
|
|
81
82
|
* (axis 1 + runtime capture), never a broken serve.
|
|
83
|
+
*
|
|
84
|
+
* "Search-less" is evaluated AFTER the request's `cache.searchParams` filter:
|
|
85
|
+
* a URL whose only params are excluded ones (`?fbclid=…` under a tracking
|
|
86
|
+
* exclusion) matches the baked shell — ad-click traffic is exactly the
|
|
87
|
+
* traffic the shell was prerendered for.
|
|
82
88
|
*/
|
|
83
|
-
export declare function lookupBuildShell(url: URL, buildVersion: string, store: SegmentCacheStore, dev?: DevShellLookup): Promise<BuildShellHit | null>;
|
|
89
|
+
export declare function lookupBuildShell(url: URL, buildVersion: string, store: SegmentCacheStore, dev?: DevShellLookup, filter?: SearchParamsFilter): Promise<BuildShellHit | null>;
|
|
84
90
|
export {};
|
|
@@ -124,10 +124,11 @@ export interface ShellCaptureDebugEvent {
|
|
|
124
124
|
* the key (stampede guard) and scheduled nothing
|
|
125
125
|
* - skip-backoff: the key is inside its refused-capture backoff window and
|
|
126
126
|
* the capture was not attempted
|
|
127
|
+
* - skip-capacity: the isolate capture queue is full; a later request may retry
|
|
127
128
|
* - backoff: the key entered (or escalated) backoff after a terminal
|
|
128
129
|
* no-shell — carries the new backoff state
|
|
129
130
|
*/
|
|
130
|
-
outcome: "stored" | "redirect" | "no-shell" | "refused" | "error" | "skip-in-flight" | "skip-backoff" | "backoff";
|
|
131
|
+
outcome: "stored" | "redirect" | "no-shell" | "refused" | "error" | "skip-in-flight" | "skip-backoff" | "skip-capacity" | "backoff";
|
|
131
132
|
/** Attempt number (1 = first, 2 = in-place retry). Absent on skips. */
|
|
132
133
|
attempt?: number;
|
|
133
134
|
/** Wall-clock ms of the whole attempt (barrier + render + drain + put). */
|
|
@@ -148,6 +149,8 @@ export interface ShellCaptureDebugEvent {
|
|
|
148
149
|
snapshotBytes?: number;
|
|
149
150
|
/** True when the snapshot exceeded maxSnapshotBytes and was dropped. */
|
|
150
151
|
snapshotSkipped?: boolean;
|
|
152
|
+
/** A bake-lane loader settled into a shell that uses TTL/SWR-only invalidation. */
|
|
153
|
+
untaggedBake?: true;
|
|
151
154
|
/** Outcome reported by a store that supports shell-write acknowledgements. */
|
|
152
155
|
storeWrite?: "stored" | "invalidated";
|
|
153
156
|
/** Consecutive failure count in the key's backoff entry, when one exists. */
|
|
@@ -280,6 +283,8 @@ export interface ShellCaptureDescriptor {
|
|
|
280
283
|
* {@link ShellCaptureDebugEvent} per attempt/skip.
|
|
281
284
|
*/
|
|
282
285
|
debugSink?: (event: ShellCaptureDebugEvent) => void;
|
|
286
|
+
/** Store the snapshot for navigation replay, never the captured HTML prelude. */
|
|
287
|
+
navigationOnly?: true;
|
|
283
288
|
}
|
|
284
289
|
/**
|
|
285
290
|
* Schedule the background shell capture for a served document. Stampede-guarded:
|
|
@@ -288,11 +293,11 @@ export interface ShellCaptureDescriptor {
|
|
|
288
293
|
* error is routed through reportCacheError — capture is best-effort; a failure just
|
|
289
294
|
* means the next request recaptures.
|
|
290
295
|
*
|
|
291
|
-
* Eligibility (nonce/
|
|
292
|
-
*
|
|
293
|
-
*
|
|
296
|
+
* Eligibility (nonce/partial/status/strategy) is decided by the caller. An SSR
|
|
297
|
+
* module loader may be passed for cold partial requests; it runs only after the
|
|
298
|
+
* capture enters the guarded background queue, never on response latency.
|
|
294
299
|
*/
|
|
295
|
-
export declare function scheduleShellCapture(ctx: HandlerContext<any>, request: Request, env: any, url: URL, reqCtx: RequestContext<any>, ssrModule: SSRModule, descriptor: ShellCaptureDescriptor): void;
|
|
300
|
+
export declare function scheduleShellCapture(ctx: HandlerContext<any>, request: Request, env: any, url: URL, reqCtx: RequestContext<any>, ssrModule: SSRModule | ((request: Request, url: URL) => Promise<SSRModule | null>), descriptor: ShellCaptureDescriptor): void;
|
|
296
301
|
/**
|
|
297
302
|
* The outcome of one capture attempt.
|
|
298
303
|
* - `stored`: a usable shell was captured (and a putShell was attempted; a store
|
|
@@ -310,7 +315,7 @@ type CaptureAttemptOutcome = "stored" | "redirect" | "no-shell" | "refused";
|
|
|
310
315
|
* bag, not a return value: captureAndStoreShell's outcome type stays a string
|
|
311
316
|
* union its existing callers (producer B, tests) consume unchanged.
|
|
312
317
|
*/
|
|
313
|
-
type CaptureAttemptStats = Pick<ShellCaptureDebugEvent, "barrierWaitMs" | "writeSettleMs" | "preludeBytes" | "snapshotBytes" | "snapshotSkipped" | "storeWrite">;
|
|
318
|
+
type CaptureAttemptStats = Pick<ShellCaptureDebugEvent, "barrierWaitMs" | "writeSettleMs" | "preludeBytes" | "snapshotBytes" | "snapshotSkipped" | "untaggedBake" | "storeWrite">;
|
|
314
319
|
/**
|
|
315
320
|
* Run the shell capture with a single in-place retry, then store the result.
|
|
316
321
|
*
|
|
@@ -351,7 +356,10 @@ export interface CaptureContextDerivation {
|
|
|
351
356
|
* createRequestContext over the build env, with a fresh MemorySegmentCacheStore
|
|
352
357
|
* as `_cacheStore` so the recording/snapshot machinery arms identically.
|
|
353
358
|
*/
|
|
354
|
-
export declare function deriveShellCaptureContext(reqCtx: RequestContext<any>, descriptor: Pick<ShellCaptureDescriptor, "ttl" | "swr"
|
|
359
|
+
export declare function deriveShellCaptureContext(reqCtx: RequestContext<any>, descriptor: Pick<ShellCaptureDescriptor, "ttl" | "swr">, identity?: {
|
|
360
|
+
request: Request;
|
|
361
|
+
url: URL;
|
|
362
|
+
}): CaptureContextDerivation;
|
|
355
363
|
/**
|
|
356
364
|
* Seal handles, derive the quiesce signal, prerender + abort via the SSR module's
|
|
357
365
|
* captureShellHTML, and store the result. Returns the attempt outcome (the caller
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
* intent cannot be honored — unlike an undeclared route, which is silent).
|
|
17
17
|
*/
|
|
18
18
|
import { type EntryData } from "../server/context.js";
|
|
19
|
+
import type { SearchParamsFilter } from "../cache/search-params-filter.js";
|
|
19
20
|
import type { ShellCacheEntry, SegmentCacheStore } from "../cache/types.js";
|
|
20
21
|
/** Debug/status header the browser (and e2e assertions) can read: HIT | MISS. */
|
|
21
22
|
export declare const SHELL_STATUS_HEADER = "x-rango-shell";
|
|
@@ -53,9 +54,10 @@ export interface ResolvedPprConfig {
|
|
|
53
54
|
captureTimeout?: number;
|
|
54
55
|
}
|
|
55
56
|
/**
|
|
56
|
-
* Validate the raw `ppr.captureTimeout` option: a finite number >= 1ms
|
|
57
|
-
*
|
|
58
|
-
* resolves to undefined, which means "use
|
|
57
|
+
* Validate the raw `ppr.captureTimeout` option: a finite number >= 1ms is
|
|
58
|
+
* clamped to the default ceiling; anything else (including
|
|
59
|
+
* 0/negative/NaN/Infinity/non-number) resolves to undefined, which means "use
|
|
60
|
+
* the capture default" downstream.
|
|
59
61
|
* Mirrors the prefetch-limit option policy: invalid values silently fall back
|
|
60
62
|
* to the default rather than throwing at request time. Also the boundary
|
|
61
63
|
* re-normalizer for the dev /__rsc_shell endpoint (vite/router-discovery.ts),
|
|
@@ -85,8 +87,13 @@ export declare function resolvePprConfig(entry: EntryData | undefined | null): R
|
|
|
85
87
|
* The key includes the request HOST: in a multi-tenant host-router deployment
|
|
86
88
|
* (one worker, one shared KV/runtime-cache store) a host-less key would serve
|
|
87
89
|
* tenant A's captured shell to tenant B's users.
|
|
90
|
+
*
|
|
91
|
+
* `filter` is the request's compiled `cache.searchParams` config
|
|
92
|
+
* (ctx._searchParamsFilter): excluded params collapse onto one shell slot.
|
|
93
|
+
* Callers on the serve/capture path MUST pass it -- key drift between capture
|
|
94
|
+
* and lookup makes every shell request a permanent miss.
|
|
88
95
|
*/
|
|
89
|
-
export declare function buildShellKey(url: URL): string;
|
|
96
|
+
export declare function buildShellKey(url: URL, filter?: SearchParamsFilter): string;
|
|
90
97
|
/**
|
|
91
98
|
* Version gates for a stored shell: reactVersion AND buildVersion must both
|
|
92
99
|
* match the running server. The postponed blob encodes hole positions against
|
|
@@ -49,6 +49,8 @@ export interface RscPayload {
|
|
|
49
49
|
prefetchCacheSize?: number;
|
|
50
50
|
/** Max concurrent speculative prefetch requests on the client */
|
|
51
51
|
prefetchConcurrency?: number;
|
|
52
|
+
/** Router-wide default prefetch strategy for Links without a `prefetch` prop */
|
|
53
|
+
defaultPrefetch?: import("../router/prefetch-default.js").PrefetchStrategy;
|
|
52
54
|
/** Server-resolved rango state cookie name; the client reads it verbatim. */
|
|
53
55
|
stateCookieName?: string;
|
|
54
56
|
/** Theme configuration for FOUC prevention */
|
|
@@ -192,6 +194,23 @@ export interface HandlerCacheConfig {
|
|
|
192
194
|
store: import("../cache/types.js").SegmentCacheStore;
|
|
193
195
|
/** Enable/disable caching (default: true) */
|
|
194
196
|
enabled?: boolean;
|
|
197
|
+
/**
|
|
198
|
+
* Which query params key the cache (default: `"all"`). Affects cache keys
|
|
199
|
+
* ONLY -- handlers and loaders still see the full query string. Global by
|
|
200
|
+
* design: the per-route case is already reachable through `cache({ key })`.
|
|
201
|
+
*
|
|
202
|
+
* Excluding a param is a promise that rendered output does not depend on
|
|
203
|
+
* it; if it does, the first variant is cached and served to everyone.
|
|
204
|
+
*
|
|
205
|
+
* @example
|
|
206
|
+
* ```typescript
|
|
207
|
+
* cache: {
|
|
208
|
+
* store: cacheStore,
|
|
209
|
+
* searchParams: { exclude: TRACKING_SEARCH_PARAMS },
|
|
210
|
+
* }
|
|
211
|
+
* ```
|
|
212
|
+
*/
|
|
213
|
+
searchParams?: import("../cache/search-params-filter.js").CacheSearchParams;
|
|
195
214
|
}
|
|
196
215
|
/**
|
|
197
216
|
* Nonce provider function type.
|
|
@@ -143,8 +143,24 @@ export interface RequestContext<TEnv = DefaultEnv, TParams = Record<string, stri
|
|
|
143
143
|
}>;
|
|
144
144
|
/** @internal PPR transition decisions evaluated before cache lookup/handlers. */
|
|
145
145
|
_pprTransitionDecisions?: Map<string, boolean>;
|
|
146
|
+
/**
|
|
147
|
+
* @internal Post-match serve-source truth for the PPR replay reporter.
|
|
148
|
+
* Stamped from the match context as `intercept`, then overwritten as
|
|
149
|
+
* `prerender-store` if that lookup actually serves. The latter wins because
|
|
150
|
+
* it identifies the response source. matchPartialWithPprReplay reads this
|
|
151
|
+
* AFTER matching to reclassify its pre-match guess and suppress pointless
|
|
152
|
+
* heal captures.
|
|
153
|
+
*/
|
|
154
|
+
_pprReplayPostMatchReason?: "prerender-store" | "intercept";
|
|
146
155
|
/** @internal Cache store for segment caching (optional, used by CacheScope) */
|
|
147
156
|
_cacheStore?: SegmentCacheStore;
|
|
157
|
+
/**
|
|
158
|
+
* @internal Compiled `cache.searchParams` filter for default cache-key
|
|
159
|
+
* generation (undefined = "all", the byte-stable unfiltered format). Set
|
|
160
|
+
* once per request by handler.ts; every URL-keyed tier (segment, document,
|
|
161
|
+
* response, shell, "use cache") reads it so the tiers cannot drift.
|
|
162
|
+
*/
|
|
163
|
+
_searchParamsFilter?: import("../cache/search-params-filter.js").SearchParamsFilter;
|
|
148
164
|
/**
|
|
149
165
|
* @internal PPR shell-capture ACTIVE marker. True ONLY inside the background
|
|
150
166
|
* capture task's derived request context (built by shell-capture.ts). This is
|
|
@@ -190,9 +206,13 @@ export interface RequestContext<TEnv = DefaultEnv, TParams = Record<string, stri
|
|
|
190
206
|
* (b) a HIT tail's seeded context, and (c) an eligible normal-route partial
|
|
191
207
|
* replay, where `store` is a request-local segment overlay. Handler-live holes
|
|
192
208
|
* and conditional transitions decline replay.
|
|
193
|
-
* Routes with their own cache() config
|
|
194
|
-
*
|
|
195
|
-
*
|
|
209
|
+
* Routes with their own cache() config are never overridden — their scope's
|
|
210
|
+
* store/key/ttl/swr/condition semantics stay authoritative. On the
|
|
211
|
+
* navigation-replay serve path (`onExplicitHit` set) the marker COMPOSES with
|
|
212
|
+
* such a scope instead of being ignored: the seeded doc record supplies the match
|
|
213
|
+
* only when the explicit tier misses (withCacheLookup). cache(false) and a
|
|
214
|
+
* false condition() stay absolute opt-outs — replay bypasses before any
|
|
215
|
+
* shell read (`cache-disabled`).
|
|
196
216
|
*/
|
|
197
217
|
_shellImplicitCache?: {
|
|
198
218
|
ttl?: number;
|
|
@@ -206,6 +226,34 @@ export interface RequestContext<TEnv = DefaultEnv, TParams = Record<string, stri
|
|
|
206
226
|
keyPrefix?: "doc";
|
|
207
227
|
/** @internal Called only after the implicit cache hit decodes successfully. */
|
|
208
228
|
onHit?: () => void;
|
|
229
|
+
/**
|
|
230
|
+
* @internal The resolved key of the canonical document segment record.
|
|
231
|
+
* Written during a CAPTURE render by CacheScope.cacheRoute when a
|
|
232
|
+
* doc-namespaced scope records the matched segments; captureAndStoreShell
|
|
233
|
+
* stamps it onto the ShellCacheEntry (`docKey`) so replay eligibility can
|
|
234
|
+
* require the exact consumable record instead of "any segment record".
|
|
235
|
+
*/
|
|
236
|
+
docKey?: string;
|
|
237
|
+
/**
|
|
238
|
+
* @internal Set ONLY by matchPartialWithPprReplay on the navigation-replay
|
|
239
|
+
* serve path. Its presence arms the explicit-scope composition in
|
|
240
|
+
* withCacheLookup: a route-derived cache() scope stays authoritative, and
|
|
241
|
+
* only when its lookup MISSes does the seeded doc record supply the match.
|
|
242
|
+
* A capture render must never set this (its match must re-run handlers so
|
|
243
|
+
* SWR recapture stays fresh), which is why the fallback keys off this
|
|
244
|
+
* field and not off the marker itself. Fired when the route-derived
|
|
245
|
+
* scope's own lookup supplied the match — the header then reports
|
|
246
|
+
* `BYPASS; reason=explicit-cache-hit`, never a false replay HIT.
|
|
247
|
+
*/
|
|
248
|
+
onExplicitHit?: () => void;
|
|
249
|
+
/**
|
|
250
|
+
* @internal Companion to onExplicitHit, same lifecycle: fired when the
|
|
251
|
+
* route-derived scope's lookup REFUSED the read (`bypass` outcome — a
|
|
252
|
+
* false condition() or no store). The gate only pre-decides the static
|
|
253
|
+
* cache(false) case; a predicate refusal is known only at lookup time and
|
|
254
|
+
* reports `BYPASS; reason=cache-disabled` post-match.
|
|
255
|
+
*/
|
|
256
|
+
onExplicitBypass?: () => void;
|
|
209
257
|
};
|
|
210
258
|
/**
|
|
211
259
|
* @internal Shell-HIT tail marker: cache/prerender-store hits during THIS
|
|
@@ -518,7 +566,7 @@ export interface RequestContext<TEnv = DefaultEnv, TParams = Record<string, stri
|
|
|
518
566
|
* This is the type exported to library consumers. Internal code should
|
|
519
567
|
* use the full RequestContext interface directly.
|
|
520
568
|
*/
|
|
521
|
-
export type PublicRequestContext<TEnv = DefaultEnv, TParams = Record<string, string>> = Omit<RequestContext<TEnv, TParams>, "cookie" | "cookies" | "setCookie" | "deleteCookie" | "_handleStore" | "_transitionWhen" | "_pprTransitionDecisions" | "_cacheStore" | "_shellCaptureRun" | "_shellImplicitCache" | "_shellLoaderSeed" | "_shellCaptureLoaderRecords" | "_shellCaptureHandleLiveness" | "_shellCaptureLoaderHandleValues" | "_shellFragmentPayload" | "_shellCaptureGuardTripped" | "_shellCaptureGuardTrippedLoaderId" | "_explicitTaggedStores" | "_requestTags" | "_cacheProfiles" | "_onResponseCallbacks" | "_pendingBackgroundTasks" | "_themeConfig" | "_locationState" | "_routeName" | "_prevRouteKey" | "_gateCurrentUrl" | "_gateCurrentParams" | "_gateActionId" | "_gateActionUrl" | "_gateActionResult" | "_gateFormData" | "_inActionRevalidation" | "_reportedErrors" | "_renderBarrier" | "_resolveRenderBarrier" | "_renderBarrierSegmentOrder" | "_treeHasStreaming" | "_renderBarrierWaiters" | "_handlerLoaderDeps" | "_renderBarrierHandleSnapshot" | "_renderBarrierGuardClosed" | "_reportBackgroundError" | "_debugPerformance" | "_metricsStore" | "_renderForeground" | "_renderDiagnosticsEnabled" | "_handlerStart" | "_tracing" | "_basename" | "_routerId" | "_setStatus" | "_rotateStateCookie" | "_setKeepCacheDirective" | "_variables" | "_classifiedRoute" | "_cacheSignal" | "_dynamic" | "res">;
|
|
569
|
+
export type PublicRequestContext<TEnv = DefaultEnv, TParams = Record<string, string>> = Omit<RequestContext<TEnv, TParams>, "cookie" | "cookies" | "setCookie" | "deleteCookie" | "_handleStore" | "_transitionWhen" | "_pprTransitionDecisions" | "_pprReplayPostMatchReason" | "_cacheStore" | "_searchParamsFilter" | "_shellCaptureRun" | "_shellImplicitCache" | "_shellLoaderSeed" | "_shellCaptureLoaderRecords" | "_shellCaptureHandleLiveness" | "_shellCaptureLoaderHandleValues" | "_shellFragmentPayload" | "_shellCaptureGuardTripped" | "_shellCaptureGuardTrippedLoaderId" | "_explicitTaggedStores" | "_requestTags" | "_cacheProfiles" | "_onResponseCallbacks" | "_pendingBackgroundTasks" | "_themeConfig" | "_locationState" | "_routeName" | "_prevRouteKey" | "_gateCurrentUrl" | "_gateCurrentParams" | "_gateActionId" | "_gateActionUrl" | "_gateActionResult" | "_gateFormData" | "_inActionRevalidation" | "_reportedErrors" | "_renderBarrier" | "_resolveRenderBarrier" | "_renderBarrierSegmentOrder" | "_treeHasStreaming" | "_renderBarrierWaiters" | "_handlerLoaderDeps" | "_renderBarrierHandleSnapshot" | "_renderBarrierGuardClosed" | "_reportBackgroundError" | "_debugPerformance" | "_metricsStore" | "_renderForeground" | "_renderDiagnosticsEnabled" | "_handlerStart" | "_tracing" | "_basename" | "_routerId" | "_setStatus" | "_rotateStateCookie" | "_setKeepCacheDirective" | "_variables" | "_classifiedRoute" | "_cacheSignal" | "_dynamic" | "res">;
|
|
522
570
|
/**
|
|
523
571
|
* Marker for a waitUntil-scheduled fn whose task promise must NOT enter
|
|
524
572
|
* _pendingBackgroundTasks. Used by the PPR shell capture for its own task:
|
|
@@ -574,6 +622,11 @@ export interface CreateRequestContextOptions<TEnv> {
|
|
|
574
622
|
initialResponse?: Response;
|
|
575
623
|
/** Optional cache store for segment caching (used by CacheScope) */
|
|
576
624
|
cacheStore?: SegmentCacheStore;
|
|
625
|
+
/**
|
|
626
|
+
* Compiled `cache.searchParams` filter from the resolved handler cache
|
|
627
|
+
* config (handler.ts). Stored as _searchParamsFilter.
|
|
628
|
+
*/
|
|
629
|
+
searchParamsFilter?: import("../cache/search-params-filter.js").SearchParamsFilter;
|
|
577
630
|
/**
|
|
578
631
|
* Handler-owned registry of explicit per-scope stores for cross-store tag
|
|
579
632
|
* invalidation. Created once per handler, reused across requests.
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { Expect, TestType } from "@playwright/test";
|
|
2
2
|
import { createUseFixture, type Fixture, type FixtureOptions } from "./fixture.js";
|
|
3
|
-
import { createPageHelpers, createStopwatch, getHistoryState, getNumericContent, goBack, goForward, isVisibleInViewport, measureTime, type PageHelpers, parseNumber, type Stopwatch, testId, waitForElement, waitForHydration, waitForNavigation } from "./page-helpers.js";
|
|
3
|
+
import { blockPrefetch, unblockPrefetch, createPageHelpers, createStopwatch, getHistoryState, getNumericContent, goBack, goForward, isPrefetchRequest, isVisibleInViewport, measureTime, type PageHelpers, parseNumber, type Stopwatch, testId, waitForElement, waitForHydration, waitForNavigation } from "./page-helpers.js";
|
|
4
4
|
import { createParity, type ExpectParityOptions, type Parity, type ParityDescribeOptions, type ParityIntent } from "./parity.js";
|
|
5
5
|
import { createRangoMatchers, type RangoMatchers } from "./matchers.js";
|
|
6
6
|
export { assertCacheStatus, assertCacheDecision, parseCacheHeader, createCacheSink, filterCacheDecisions, type CacheSink, type ExpectedCacheStatus, type CacheStatusTarget, } from "../cache-status.js";
|
|
7
7
|
export { assertPprReplayStatus, assertShellStatus, parsePprReplayStatus, parseShellStatus, PPR_REPLAY_STATUS_HEADER, shellCacheKey, SHELL_STATUS_HEADER, type PprReplayBypassReason, type PprReplayStatus, type ShellStatus, type ShellStatusTarget, } from "../shell-status.js";
|
|
8
|
-
export { testId, waitForHydration, waitForNavigation, goBack, goForward, getHistoryState, waitForElement, isVisibleInViewport, parseNumber, getNumericContent, createStopwatch, measureTime, createPageHelpers, createUseFixture, createParity, createRangoMatchers, };
|
|
8
|
+
export { testId, waitForHydration, waitForNavigation, goBack, goForward, getHistoryState, waitForElement, isVisibleInViewport, isPrefetchRequest, blockPrefetch, unblockPrefetch, parseNumber, getNumericContent, createStopwatch, measureTime, createPageHelpers, createUseFixture, createParity, createRangoMatchers, };
|
|
9
9
|
export type { Fixture, FixtureOptions, PageHelpers, Stopwatch, Parity, ParityIntent, ParityDescribeOptions, ExpectParityOptions, RangoMatchers, };
|
|
10
10
|
export interface RangoE2E extends PageHelpers, Parity {
|
|
11
11
|
useFixture: (options: FixtureOptions) => Fixture;
|
|
@@ -43,6 +43,30 @@ export declare function measureTime<T>(fn: () => Promise<T>): Promise<{
|
|
|
43
43
|
elapsed: number;
|
|
44
44
|
result: T;
|
|
45
45
|
}>;
|
|
46
|
+
/**
|
|
47
|
+
* True when the request is a speculative prefetch (Link viewport/hover/render
|
|
48
|
+
* strategies or `useRouter().prefetch()`). Every prefetch fetch carries the
|
|
49
|
+
* `X-Rango-Prefetch` header. Links prefetch by default in production unless
|
|
50
|
+
* the router opts out, so tests that track `_rsc_partial` requests to pin
|
|
51
|
+
* NAVIGATION behavior must skip these — a request-count or first-request
|
|
52
|
+
* assertion otherwise races background prefetch traffic.
|
|
53
|
+
*/
|
|
54
|
+
export declare function isPrefetchRequest(req: {
|
|
55
|
+
headers: () => Record<string, string>;
|
|
56
|
+
}): boolean;
|
|
57
|
+
/**
|
|
58
|
+
* Abort every speculative prefetch request on this page. Install BEFORE
|
|
59
|
+
* `page.goto` so no prefetch can complete first. For tests whose semantics
|
|
60
|
+
* need a virgin prefetch cache: a click on a Link whose target was already
|
|
61
|
+
* prefetched ADOPTS the warmed entry and issues no navigation fetch at all —
|
|
62
|
+
* a `page.route` override, a request waiter, or a Set-Cookie assertion aimed
|
|
63
|
+
* at the navigation request then sees nothing (or sees the prefetch's side
|
|
64
|
+
* effects instead). Aborted prefetches are benign by design (evicted, never
|
|
65
|
+
* adopted, no page error), so the click's real fetch is guaranteed live.
|
|
66
|
+
*/
|
|
67
|
+
export declare function blockPrefetch(page: Page): Promise<void>;
|
|
68
|
+
/** Remove a `blockPrefetch` guard, restoring normal prefetch traffic. */
|
|
69
|
+
export declare function unblockPrefetch(page: Page): Promise<void>;
|
|
46
70
|
export interface PageHelpers {
|
|
47
71
|
/** Assert that no full page reload occurred between scope entry and exit. */
|
|
48
72
|
expectNoReload: (page: Page) => AsyncDisposable;
|