@rangojs/router 0.18.0 → 0.19.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/types/browser/event-controller.d.ts +3 -3
- package/dist/types/browser/history-state.d.ts +2 -0
- package/dist/types/browser/navigation-transaction.d.ts +20 -2
- package/dist/types/browser/partial-update.d.ts +16 -1
- package/dist/types/browser/prefetch/cache.d.ts +6 -6
- package/dist/types/browser/react/Link.d.ts +19 -9
- package/dist/types/browser/react/context.d.ts +2 -2
- package/dist/types/browser/react/location-state-shared.d.ts +95 -56
- package/dist/types/browser/react/location-state.d.ts +1 -1
- package/dist/types/browser/transition-when.d.ts +80 -0
- package/dist/types/browser/types.d.ts +104 -9
- package/dist/types/build/generate-manifest.d.ts +8 -0
- package/dist/types/cache/background-task.d.ts +24 -2
- package/dist/types/cache/cache-exec-scope.d.ts +31 -0
- package/dist/types/cache/cache-key-utils.d.ts +44 -13
- package/dist/types/cache/cache-policy.d.ts +1 -1
- package/dist/types/cache/cache-runtime.d.ts +7 -0
- package/dist/types/cache/cache-scope.d.ts +117 -35
- package/dist/types/cache/cache-tag.d.ts +24 -4
- package/dist/types/cache/cf/cf-cache-store.d.ts +55 -44
- package/dist/types/cache/cf/cf-shell-frame.d.ts +1 -1
- package/dist/types/cache/cf/cf-tag-marker-memo.d.ts +0 -15
- package/dist/types/cache/document-cache.d.ts +10 -0
- package/dist/types/cache/handle-snapshot.d.ts +40 -8
- package/dist/types/cache/invalidation-order.d.ts +23 -0
- package/dist/types/cache/request-tag-mask.d.ts +54 -0
- package/dist/types/cache/shell-snapshot.d.ts +88 -141
- package/dist/types/cache/tag-invalidation.d.ts +38 -14
- package/dist/types/cache/types.d.ts +68 -61
- package/dist/types/cache/vercel/vercel-cache-store.d.ts +23 -16
- package/dist/types/client-urls/navigation.d.ts +28 -2
- package/dist/types/client-urls/server-projection.d.ts +5 -2
- package/dist/types/client-urls/types.d.ts +5 -5
- package/dist/types/client.d.ts +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.rsc.d.ts +1 -1
- package/dist/types/route-definition/helpers-types.d.ts +11 -11
- package/dist/types/route-name.d.ts +7 -0
- package/dist/types/router/error-handling.d.ts +1 -1
- package/dist/types/router/intercept-resolution.d.ts +2 -0
- package/dist/types/router/match-context.d.ts +5 -0
- package/dist/types/router/match-middleware/background-revalidation.d.ts +0 -4
- package/dist/types/router/router-options.d.ts +4 -1
- package/dist/types/router/segment-resolution/loader-cache.d.ts +18 -1
- package/dist/types/router/segment-resolution/loader-mask.d.ts +3 -4
- package/dist/types/router/segment-resolution/loader-snapshot.d.ts +14 -40
- package/dist/types/router/segment-resolution/mask-nested.d.ts +11 -3
- package/dist/types/router/segment-resolution/view-transition-default.d.ts +7 -5
- package/dist/types/router/transition-when.d.ts +24 -10
- package/dist/types/rsc/attach-transition-when.d.ts +18 -0
- package/dist/types/rsc/full-payload.d.ts +14 -7
- package/dist/types/rsc/response-cache-serve.d.ts +15 -12
- package/dist/types/rsc/shell-build-manifest.d.ts +4 -3
- package/dist/types/rsc/shell-capture-constants.d.ts +77 -20
- package/dist/types/rsc/shell-capture.d.ts +78 -81
- package/dist/types/rsc/shell-serve.d.ts +19 -48
- package/dist/types/rsc/types.d.ts +2 -0
- package/dist/types/segment-system.d.ts +7 -0
- package/dist/types/server/context.d.ts +89 -61
- package/dist/types/server/cookie-store.d.ts +30 -18
- package/dist/types/server/handle-store.d.ts +52 -1
- package/dist/types/server/request-context.d.ts +66 -45
- package/dist/types/server/request-headers.d.ts +44 -0
- package/dist/types/server.d.ts +1 -0
- package/dist/types/testing/e2e/index.d.ts +1 -1
- package/dist/types/testing/index.d.ts +3 -2
- package/dist/types/testing/internal/action-id.d.ts +7 -0
- package/dist/types/testing/location-state-key.d.ts +24 -0
- package/dist/types/testing/render-route.d.ts +17 -1
- package/dist/types/testing/run-transition-when.d.ts +44 -69
- package/dist/types/testing/serve-shell-request.d.ts +7 -6
- package/dist/types/testing/shell-status.d.ts +34 -22
- package/dist/types/transition-when-ref.d.ts +79 -0
- package/dist/types/types/cache-types.d.ts +15 -3
- package/dist/types/types/index.d.ts +1 -1
- package/dist/types/types/segments.d.ts +86 -71
- package/dist/types/urls/path-helper-types.d.ts +3 -4
- package/dist/types/urls/pattern-types.d.ts +3 -4
- package/dist/types/vite/plugins/transition-when-hoist.d.ts +45 -0
- package/dist/vite/index.js +960 -97
- package/package.json +1 -1
- package/skills/cache-guide/SKILL.md +76 -49
- package/skills/caching/SKILL.md +167 -69
- package/skills/client-urls/SKILL.md +1 -1
- package/skills/comparison/references/framework-comparison.md +8 -5
- package/skills/document-cache/SKILL.md +24 -0
- package/skills/hooks/SKILL.md +3 -1
- package/skills/hooks/navigation.md +23 -2
- package/skills/hooks/state.md +98 -6
- package/skills/intercept/SKILL.md +29 -12
- package/skills/loader/SKILL.md +52 -21
- package/skills/middleware/SKILL.md +18 -0
- package/skills/migrate-nextjs/SKILL.md +3 -3
- package/skills/observability/SKILL.md +6 -5
- package/skills/parallel/SKILL.md +1 -1
- package/skills/ppr/SKILL.md +129 -77
- package/skills/prerender/SKILL.md +3 -3
- package/skills/rango/SKILL.md +25 -6
- package/skills/route/SKILL.md +2 -0
- package/skills/testing/SKILL.md +27 -25
- package/skills/testing/cache-prerender.md +9 -9
- package/skills/testing/client-components.md +45 -3
- package/skills/testing/loader.md +3 -2
- package/skills/testing/middleware.md +1 -0
- package/skills/testing/predicates.md +49 -49
- package/skills/testing/render-handler.md +1 -0
- package/skills/testing/serve-shell-request.md +14 -0
- package/skills/testing/server-actions.md +9 -3
- package/skills/theme/SKILL.md +8 -4
- package/skills/typesafety/env-and-bindings.md +8 -0
- package/skills/use-cache/SKILL.md +64 -19
- package/skills/view-transitions/SKILL.md +150 -29
- package/src/__augment-tests__/augmented.check.ts +23 -0
- package/src/browser/event-controller.ts +4 -4
- package/src/browser/history-state.ts +52 -1
- package/src/browser/link-interceptor.ts +4 -0
- package/src/browser/navigation-bridge.ts +77 -18
- package/src/browser/navigation-client.ts +4 -3
- package/src/browser/navigation-store.ts +43 -1
- package/src/browser/navigation-transaction.ts +31 -11
- package/src/browser/partial-update.ts +146 -35
- package/src/browser/prefetch/cache.ts +6 -6
- package/src/browser/prefetch/fetch.ts +2 -2
- package/src/browser/react/Link.tsx +38 -33
- package/src/browser/react/NavigationProvider.tsx +2 -2
- package/src/browser/react/context.ts +2 -2
- package/src/browser/react/location-state-shared.ts +241 -49
- package/src/browser/react/location-state.ts +5 -2
- package/src/browser/rsc-router.tsx +4 -0
- package/src/browser/server-action-bridge.ts +84 -15
- package/src/browser/transition-when.ts +205 -0
- package/src/browser/types.ts +124 -10
- package/src/build/generate-manifest.ts +77 -1
- package/src/cache/background-task.ts +55 -2
- package/src/cache/cache-exec-scope.ts +48 -1
- package/src/cache/cache-key-utils.ts +56 -16
- package/src/cache/cache-policy.ts +9 -4
- package/src/cache/cache-runtime.ts +197 -144
- package/src/cache/cache-scope.ts +304 -112
- package/src/cache/cache-tag.ts +105 -13
- package/src/cache/cf/cf-cache-store.ts +152 -76
- package/src/cache/cf/cf-shell-frame.ts +2 -2
- package/src/cache/cf/cf-tag-marker-memo.ts +11 -100
- package/src/cache/document-cache.ts +53 -7
- package/src/cache/handle-snapshot.ts +52 -9
- package/src/cache/invalidation-order.ts +84 -0
- package/src/cache/request-tag-mask.ts +147 -0
- package/src/cache/shell-snapshot.ts +130 -348
- package/src/cache/tag-invalidation.ts +57 -51
- package/src/cache/types.ts +71 -67
- package/src/cache/vercel/vercel-cache-store.ts +61 -58
- package/src/client-urls/client-root.tsx +8 -4
- package/src/client-urls/client-urls.ts +8 -6
- package/src/client-urls/navigation.ts +55 -4
- package/src/client-urls/server-projection.ts +31 -10
- package/src/client-urls/types.ts +12 -5
- package/src/client.tsx +2 -0
- package/src/host/cookie-handler.ts +2 -1
- package/src/index.rsc.ts +3 -0
- package/src/index.ts +3 -0
- package/src/loader-redirect.tsx +7 -3
- package/src/prerender/build-shell-capture.ts +155 -146
- package/src/route-definition/dsl-helpers.ts +2 -0
- package/src/route-definition/helpers-types.ts +11 -11
- package/src/route-name.ts +12 -0
- package/src/router/content-negotiation.ts +4 -1
- package/src/router/error-handling.ts +5 -2
- package/src/router/handler-context.ts +10 -7
- package/src/router/intercept-resolution.ts +11 -1
- package/src/router/loader-resolution.ts +28 -3
- package/src/router/logging.ts +5 -3
- package/src/router/match-api.ts +62 -34
- package/src/router/match-context.ts +5 -0
- package/src/router/match-handlers.ts +9 -29
- package/src/router/match-middleware/background-revalidation.ts +3 -5
- package/src/router/match-middleware/cache-lookup.ts +35 -19
- package/src/router/match-middleware/cache-store.ts +15 -9
- package/src/router/match-result.ts +1 -0
- package/src/router/middleware.ts +2 -5
- package/src/router/navigation-snapshot.ts +6 -5
- package/src/router/prerender-match.ts +4 -0
- package/src/router/request-classification.ts +7 -4
- package/src/router/router-options.ts +4 -1
- package/src/router/segment-resolution/fresh.ts +0 -4
- package/src/router/segment-resolution/loader-cache.ts +150 -25
- package/src/router/segment-resolution/loader-mask.ts +3 -4
- package/src/router/segment-resolution/loader-snapshot.ts +15 -78
- package/src/router/segment-resolution/mask-nested.ts +47 -22
- package/src/router/segment-resolution/revalidation.ts +0 -3
- package/src/router/segment-resolution/view-transition-default.ts +6 -21
- package/src/router/telemetry.ts +6 -3
- package/src/router/transition-when.ts +34 -52
- package/src/router.ts +2 -1
- package/src/rsc/attach-transition-when.ts +47 -0
- package/src/rsc/full-payload.ts +30 -10
- package/src/rsc/handler.ts +12 -10
- package/src/rsc/loader-fetch.ts +2 -1
- package/src/rsc/manifest-init.ts +4 -0
- package/src/rsc/origin-guard.ts +8 -5
- package/src/rsc/progressive-enhancement.ts +7 -30
- package/src/rsc/response-cache-serve.ts +68 -80
- package/src/rsc/response-route-handler.ts +2 -2
- package/src/rsc/rsc-rendering.ts +206 -252
- package/src/rsc/server-action.ts +8 -20
- package/src/rsc/shell-build-manifest.ts +22 -20
- package/src/rsc/shell-capture-constants.ts +136 -20
- package/src/rsc/shell-capture.ts +352 -589
- package/src/rsc/shell-serve.ts +73 -109
- package/src/rsc/ssr-setup.ts +3 -2
- package/src/rsc/types.ts +2 -0
- package/src/segment-system.tsx +40 -7
- package/src/server/context.ts +189 -124
- package/src/server/cookie-store.ts +153 -127
- package/src/server/handle-store.ts +245 -27
- package/src/server/request-context.ts +123 -84
- package/src/server/request-headers.ts +134 -0
- package/src/server.ts +4 -0
- package/src/testing/dispatch.ts +4 -7
- package/src/testing/e2e/index.ts +1 -0
- package/src/testing/index.ts +5 -0
- package/src/testing/internal/action-id.ts +25 -0
- package/src/testing/internal/context.ts +1 -1
- package/src/testing/location-state-key.ts +45 -0
- package/src/testing/render-handler.ts +1 -1
- package/src/testing/render-route.tsx +109 -16
- package/src/testing/run-client-revalidate.ts +3 -19
- package/src/testing/run-loader.ts +5 -1
- package/src/testing/run-transition-when.ts +109 -172
- package/src/testing/serve-shell-request.ts +10 -7
- package/src/testing/shell-status.ts +60 -56
- package/src/transition-when-ref.ts +220 -0
- package/src/types/cache-types.ts +15 -3
- package/src/types/index.ts +3 -0
- package/src/types/segments.ts +94 -91
- package/src/urls/path-helper-types.ts +3 -4
- package/src/urls/pattern-types.ts +3 -4
- package/src/vite/discovery/discover-routers.ts +3 -0
- package/src/vite/discovery/shell-prerender-phase.ts +0 -2
- package/src/vite/discovery/virtual-module-codegen.ts +16 -6
- package/src/vite/plugins/transition-when-hoist.ts +1064 -0
- package/src/vite/rango.ts +2 -0
- package/src/vite/router-discovery.ts +75 -5
- package/dist/types/rsc/transition-gate.d.ts +0 -23
- package/src/rsc/transition-gate.ts +0 -86
|
@@ -3,28 +3,27 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Owns the single response-cache contract — cache-scope resolution from the
|
|
5
5
|
* matched entry tree, condition eval, key resolution (route key() > store
|
|
6
|
-
* keyGenerator > default), tag resolution,
|
|
7
|
-
* fresh-hit / SWR-revalidate /
|
|
6
|
+
* keyGenerator > default, CacheScope.resolveKeyFrom), tag resolution,
|
|
7
|
+
* pre-handler-callback timing, and the fresh-hit / SWR-revalidate /
|
|
8
|
+
* miss-write branches — for BOTH the production
|
|
8
9
|
* response-route handler (rsc/response-route-handler.ts) and the dispatch testing
|
|
9
10
|
* primitive (testing/dispatch.ts), so the two can never drift.
|
|
10
11
|
*
|
|
11
12
|
* Plugin-rsc hazard: cache-scope.ts pulls @vitejs/plugin-rsc (via segment-codec),
|
|
12
13
|
* which the non-Vite unit-test runner cannot resolve, and this module is on the
|
|
13
|
-
* testing barrel's EAGER graph (dispatch imports it). So `createCacheScope`
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
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
|
|
17
18
|
* (helpers' isCacheableStatus/finalizeResponse, traverseBack); cache-scope is a
|
|
18
19
|
* type-only import (erased at build).
|
|
19
20
|
*/
|
|
20
21
|
import type { CacheScope } from "../cache/cache-scope.js";
|
|
21
|
-
import type
|
|
22
|
-
import type { RequestContext } from "../server/request-context.js";
|
|
22
|
+
import { type RequestContext } from "../server/request-context.js";
|
|
23
23
|
import type { EntryCacheConfig, EntryData } from "../server/context.js";
|
|
24
|
-
/** Injected cache-scope
|
|
24
|
+
/** Injected cache-scope builder (kept off this module's runtime import graph). */
|
|
25
25
|
export interface CacheScopeDeps {
|
|
26
26
|
createCacheScope: (config: EntryCacheConfig | undefined, parent?: CacheScope | null) => CacheScope | null;
|
|
27
|
-
resolveCacheTags: (config: PartialCacheOptions | false, ctx: RequestContext | undefined) => string[] | undefined;
|
|
28
27
|
}
|
|
29
28
|
export interface ServeResponseRouteWithCacheArgs {
|
|
30
29
|
reqCtx: RequestContext;
|
|
@@ -40,7 +39,11 @@ export interface ServeResponseRouteWithCacheArgs {
|
|
|
40
39
|
* applies (no scope, disabled, condition false, or store lacks get/putResponse)
|
|
41
40
|
* so the caller falls through to a plain `executeHandler()` run.
|
|
42
41
|
*
|
|
43
|
-
* Must run inside runWithRequestContext (reads the ambient
|
|
44
|
-
* the helpers and reqCtx.waitUntil for background writes).
|
|
42
|
+
* Must run inside runWithRequestContext for `reqCtx` (reads the ambient
|
|
43
|
+
* request context via the helpers and reqCtx.waitUntil for background writes).
|
|
44
|
+
* Outside it, the route runs uncached: the scope resolves `key()`, a store
|
|
45
|
+
* keyGenerator and `condition()` against the ambient context, and without
|
|
46
|
+
* it a keyGenerator was skipped and the entry landed on the broad default
|
|
47
|
+
* key.
|
|
45
48
|
*/
|
|
46
49
|
export declare function serveResponseRouteWithCache(args: ServeResponseRouteWithCacheArgs): Promise<Response | undefined>;
|
|
@@ -31,10 +31,8 @@ export interface BuildShellEntry {
|
|
|
31
31
|
entry: ShellCacheEntry;
|
|
32
32
|
/** Resolved ppr ttl (seconds) — drives staleness/recapture, never expiry. */
|
|
33
33
|
ttl: number;
|
|
34
|
-
swr?: number;
|
|
35
34
|
/** The putShell-barrier tag union baked at build (static + recorded). */
|
|
36
35
|
tags?: string[];
|
|
37
|
-
routeName: string;
|
|
38
36
|
}
|
|
39
37
|
interface ShellManifestModule {
|
|
40
38
|
/** Manifest key (pathname — see shell-manifest-key.ts) -> asset specifier. */
|
|
@@ -46,7 +44,10 @@ interface ShellManifestModule {
|
|
|
46
44
|
declare global {
|
|
47
45
|
var __loadShellManifestModule: (() => Promise<ShellManifestModule>) | undefined;
|
|
48
46
|
}
|
|
49
|
-
/**
|
|
47
|
+
/**
|
|
48
|
+
* Reset the memoized manifest (unit tests swap the global loader) and the
|
|
49
|
+
* shell path's once-per-key warnings, the tag-check one included.
|
|
50
|
+
*/
|
|
50
51
|
export declare function resetBuildShellManifestForTests(): void;
|
|
51
52
|
export interface BuildShellHit {
|
|
52
53
|
entry: DocumentShellCacheEntry;
|
|
@@ -1,37 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* React-free leaf of the PPR shell path: its constants, the shell key
|
|
3
|
+
* builders, the status header names and bypass reasons, and the once-per-key
|
|
4
|
+
* warning registry. The ssr graph (ssr/index.tsx), the testing barrels
|
|
5
|
+
* (testing/shell-status.ts) and cookie-store.ts import from here without
|
|
6
|
+
* pulling the capture orchestration module or shell-serve.ts (React).
|
|
7
|
+
*/
|
|
8
|
+
import type { SearchParamsFilter } from "../cache/search-params-filter.js";
|
|
1
9
|
/**
|
|
2
10
|
* Default upper bound on the capture prerender wait before forcing the abort
|
|
3
11
|
* that freezes the shell — the ONLY wall-clock on the capture path, and a
|
|
4
12
|
* pathological guard: it should never fire once the caller's `quiesce` is a
|
|
5
13
|
* task-quantized, frozen-byte signal (the capture gate in shell-capture.ts).
|
|
6
|
-
*
|
|
7
|
-
* Leaf module on purpose (imports nothing): shell-capture.ts re-exports it
|
|
8
|
-
* (single import site for the rsc graph — shell-build-manifest.ts sizes the
|
|
9
|
-
* dev fetch envelope from that re-export) and ssr/index.tsx uses it as
|
|
10
|
-
* captureShellHTML's own fallback; the ssr graph must not pull the capture
|
|
11
|
-
* orchestration module for one number.
|
|
14
|
+
* ssr/index.tsx uses it as captureShellHTML's own fallback.
|
|
12
15
|
*
|
|
13
16
|
* 15s, raised from 5s: captures are background work (waitUntil), so the budget
|
|
14
17
|
* costs latency-to-HIT only — never a served response — and 5s spuriously
|
|
15
18
|
* refused legitimately-slow deferred shell material (a real storefront's meta
|
|
16
19
|
* chains settle at ~7s). Ceiling math: workerd's waitUntil lifetime is ~30s
|
|
17
20
|
* past response completion. An attempt that consumed the whole budget is not
|
|
18
|
-
* retried in place (shell-capture.ts
|
|
19
|
-
* budget plus store I/O; the retry follows only an
|
|
20
|
-
* (a cold-module abort). Past the ceiling the
|
|
21
|
-
* existing best-effort contract (the key stays
|
|
22
|
-
* re-captures).
|
|
21
|
+
* retried in place (shell-capture.ts CaptureAttemptStats.noShellCause), so
|
|
22
|
+
* the envelope is one budget plus store I/O; the retry follows only an
|
|
23
|
+
* attempt that ended early (a cold-module abort). Past the ceiling the
|
|
24
|
+
* platform kill degrades to the existing best-effort contract (the key stays
|
|
25
|
+
* MISS; a later request re-captures).
|
|
23
26
|
* Node/dev and build-time captures have no waitUntil ceiling. The per-route
|
|
24
27
|
* `ppr.captureTimeout` knob remains for tightening below the default. See
|
|
25
28
|
* docs/design/ppr-shell-resume.md (Cost model).
|
|
26
29
|
*/
|
|
27
30
|
export declare const SHELL_CAPTURE_MAX_WAIT_MS = 15000;
|
|
31
|
+
/** Debug/status header on a ppr document response: `HIT` | `MISS`. */
|
|
32
|
+
export declare const SHELL_STATUS_HEADER: string;
|
|
33
|
+
/**
|
|
34
|
+
* Partial-navigation replay status header, set only after the captured
|
|
35
|
+
* segment record was consumed (`HIT`) or with the reason it was not.
|
|
36
|
+
*/
|
|
37
|
+
export declare const PPR_REPLAY_STATUS_HEADER: string;
|
|
38
|
+
/**
|
|
39
|
+
* Bounded reasons a partial request to a ppr route falls open to the ordinary
|
|
40
|
+
* match (`x-rango-ppr-replay: BYPASS; reason=<reason>`). One list for the
|
|
41
|
+
* producer (rsc-rendering.ts) and the parser (testing/shell-status.ts): a
|
|
42
|
+
* reason the parser does not list parses as null.
|
|
43
|
+
*/
|
|
44
|
+
export declare const PPR_REPLAY_BYPASS_REASONS: readonly ["method", "dynamic", "nonce", "store-unavailable", "passive-read-unsupported", "no-navigation-context", "prerender-store", "intercept", "cache-disabled", "read-error", "no-entry", "invalid-version", "corrupt-entry", "no-segment-snapshot", "snapshot-miss", "explicit-cache-hit"];
|
|
45
|
+
/** One of {@link PPR_REPLAY_BYPASS_REASONS}. */
|
|
46
|
+
export type PprReplayBypassReason = (typeof PPR_REPLAY_BYPASS_REASONS)[number];
|
|
47
|
+
/**
|
|
48
|
+
* The shell key's search portion (`?`-prefixed sorted search with the
|
|
49
|
+
* cache.searchParams filter applied, or "") — ALSO the string the capture and
|
|
50
|
+
* resume SSR renders seed their store location with (SSRRenderOptions.search
|
|
51
|
+
* / ShellCaptureOptions.search / ShellResumeOptions.search). Search is part
|
|
52
|
+
* of shell identity, so static-part `useSearchParams` reads render exactly
|
|
53
|
+
* what the key names; deriving seed and key from this one helper is what
|
|
54
|
+
* keeps capture, resume, and lookup byte-agreed (drift = replay mismatch or
|
|
55
|
+
* permanent MISS).
|
|
56
|
+
*/
|
|
57
|
+
export declare function shellSearchSeed(url: URL, filter?: SearchParamsFilter): string;
|
|
58
|
+
/**
|
|
59
|
+
* Shell cache key: host + pathname + sorted search + a `:shell` namespace suffix
|
|
60
|
+
* (so it can never collide with a document-cache key; the store further isolates
|
|
61
|
+
* the shell family internally).
|
|
62
|
+
*
|
|
63
|
+
* The key includes the request HOST: in a multi-tenant host-router deployment
|
|
64
|
+
* (one worker, one shared KV/runtime-cache store) a host-less key would serve
|
|
65
|
+
* tenant A's captured shell to tenant B's users.
|
|
66
|
+
*
|
|
67
|
+
* `filter` is the request's compiled `cache.searchParams` config
|
|
68
|
+
* (ctx._searchParamsFilter): excluded params collapse onto one shell slot.
|
|
69
|
+
* Callers on the serve/capture path MUST pass it -- key drift between capture
|
|
70
|
+
* and lookup makes every shell request a permanent miss. The testing helper
|
|
71
|
+
* `shellCacheKey` (testing/shell-status.ts) builds its key with it too.
|
|
72
|
+
*/
|
|
73
|
+
export declare function buildShellKey(url: URL, filter?: SearchParamsFilter): string;
|
|
28
74
|
/**
|
|
29
75
|
* The shell key for one request partition (cache-scope.ts
|
|
30
76
|
* resolveShellPartition): the route cache() `key()` or store keyGenerator
|
|
31
77
|
* result that partitions the route's record partitions its shell too, so
|
|
32
|
-
* each partition captures and serves its own.
|
|
33
|
-
* the testing helper `shellCacheKey` (testing/shell-status.ts) calls it
|
|
34
|
-
* without pulling shell-serve.ts.
|
|
78
|
+
* each partition captures and serves its own.
|
|
35
79
|
*
|
|
36
80
|
* The partition is URI-encoded: it is request-derived, and raw it could end
|
|
37
81
|
* in a suffix another key is built with (navigationShellKey), so a partition
|
|
@@ -53,12 +97,12 @@ export declare function navigationShellKey(key: string): string;
|
|
|
53
97
|
* (ssr/index.tsx) and by the testing SSR stub (testing/serve-shell-request.ts),
|
|
54
98
|
* so the stub freezes the same Flight the real capture would.
|
|
55
99
|
*
|
|
56
|
-
* Why 16 and not the
|
|
57
|
-
* (
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
100
|
+
* Why 16 and not 2: the capture's Flight input is the doc record's stored
|
|
101
|
+
* fragments (settleCaptureRecord, shell-capture.ts), already serialized, so the
|
|
102
|
+
* render emits the whole shell payload in the first tick and the gate declares
|
|
103
|
+
* quiesce within a few ms, before fizz has rendered the shell to <body>. When
|
|
104
|
+
* the capture Flight dribbled out as handlers ran, Flight-quiet meant "the shell
|
|
105
|
+
* has rendered" and 2 hops sufficed.
|
|
62
106
|
*
|
|
63
107
|
* Hops alone are NOT render-readiness: fizz cannot emit even <html> until the
|
|
64
108
|
* payload root settles, nor complete a shell whose client components are
|
|
@@ -97,3 +141,16 @@ export declare const SHELL_CAPTURE_TASK_HARD_CAP_MS = 25000;
|
|
|
97
141
|
* rule: resolveLoaderData (router/segment-resolution/loader-cache.ts).
|
|
98
142
|
*/
|
|
99
143
|
export declare const PPR_LANE_HINT: string;
|
|
144
|
+
/** Whether {@link warnOnce} already warned for `scope` and `key`. */
|
|
145
|
+
export declare function hasWarnedOnce(scope: string, key: string): boolean;
|
|
146
|
+
/**
|
|
147
|
+
* `console.warn(message())` once per `scope` and `key`; `message` is built only
|
|
148
|
+
* when it prints. Returns true when it warned.
|
|
149
|
+
*/
|
|
150
|
+
export declare function warnOnce(scope: string, key: string, message: () => string): boolean;
|
|
151
|
+
/**
|
|
152
|
+
* @internal Forget every once-per-key shell warning. Tests only: the capture,
|
|
153
|
+
* serve and build-shell resets (testing/serve-shell-request.ts
|
|
154
|
+
* resetShellTestState) call it.
|
|
155
|
+
*/
|
|
156
|
+
export declare function resetShellWarningsForTests(): void;
|
|
@@ -6,29 +6,24 @@
|
|
|
6
6
|
* from the route's `ppr` path option after the served response is built and calls
|
|
7
7
|
* scheduleShellCapture. 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, `_shellCaptureRun: true` so loaders mask (loader-mask.ts)
|
|
10
|
-
* loading()
|
|
11
|
-
* from ring 3, uncached segments execute
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
9
|
+
* handle store, `_shellCaptureRun: true` so live-lane loaders mask (loader-mask.ts)
|
|
10
|
+
* and postpone at their loading() or inline <Suspense> boundary. The match is
|
|
11
|
+
* MIXED-CHAIN: cache()'d segments replay from ring 3, uncached segments execute
|
|
12
|
+
* their handlers. The record-first step (settleCaptureRecord) waits for the
|
|
13
|
+
* handler layer, writes the doc record every HIT replays, and renders the
|
|
14
|
+
* capture's Flight payload from it; the static prerender runs to a quiescent
|
|
15
|
+
* shell, aborts to freeze the prelude + postponed state, and putShell stores the
|
|
16
|
+
* pair with the snapshot. Because it uses match() rather than the HTTP pipeline,
|
|
17
|
+
* the middleware chain (auth, logging) never re-runs — it already ran for the
|
|
18
|
+
* triggering request, and the derived context inherits its post-middleware state
|
|
19
|
+
* (variables, cache store). Guarding is serve-time.
|
|
17
20
|
*/
|
|
18
21
|
import { type MatchResult } from "../types.js";
|
|
19
|
-
import { SHELL_CAPTURE_MAX_WAIT_MS } from "./shell-capture-constants.js";
|
|
20
22
|
import { type RequestContext, type RouteRecordWindow } from "../server/request-context.js";
|
|
21
23
|
import { type HandleStore } from "../server/handle-store.js";
|
|
22
24
|
import type { SegmentCacheStore } from "../cache/types.js";
|
|
23
25
|
import type { HandlerContext } from "./handler-context.js";
|
|
24
26
|
import type { SSRModule } from "./types.js";
|
|
25
|
-
/**
|
|
26
|
-
* Default capture budget. Canonical value, raise rationale, and ceiling math
|
|
27
|
-
* live on the leaf module (shell-capture-constants.ts, importable from the ssr
|
|
28
|
-
* graph too). Re-exported here so shell-build-manifest.ts's envelope math
|
|
29
|
-
* keeps its existing import site and cannot drift from the capture.
|
|
30
|
-
*/
|
|
31
|
-
export { SHELL_CAPTURE_MAX_WAIT_MS };
|
|
32
27
|
/**
|
|
33
28
|
* Delay before the in-place retry of a capture that produced no usable shell.
|
|
34
29
|
*
|
|
@@ -80,6 +75,7 @@ declare const REFUSED_CAPTURE_MAX_MS = 60000;
|
|
|
80
75
|
* docs/design/ppr-shell-resume.md ("Refused-capture backoff").
|
|
81
76
|
*/
|
|
82
77
|
declare const REFUSED_CAPTURE_DEV_MAX_MS = 2000;
|
|
78
|
+
/** True iff `key` is still inside its (exponential) backoff window. */
|
|
83
79
|
declare function isCaptureBackedOff(key: string): boolean;
|
|
84
80
|
/**
|
|
85
81
|
* Record a refused/failed capture, escalating the backoff window exponentially up
|
|
@@ -187,15 +183,6 @@ export interface ShellCaptureDebugEvent {
|
|
|
187
183
|
* same-or-higher priority. 0 = this capture starts immediately.
|
|
188
184
|
*/
|
|
189
185
|
queueAhead?: number;
|
|
190
|
-
/**
|
|
191
|
-
* Ms the capture gate was HELD waiting for the slowest bake source — a
|
|
192
|
-
* top-level pushed handle promise or a bake-lane loader container — to
|
|
193
|
-
* settle, measured from capture start. Bake time is by-design shell latency
|
|
194
|
-
* (the hole doctrine: top-level promises bake), but it recurs on EVERY
|
|
195
|
-
* capture of the route and occupies the serialized queue; this field makes
|
|
196
|
-
* it attributable. Absent when nothing held the gate.
|
|
197
|
-
*/
|
|
198
|
-
bakeWaitMs?: number;
|
|
199
186
|
/**
|
|
200
187
|
* How long the capture waited for its doc record: the handler layer's
|
|
201
188
|
* promises, async server components and handle pushes settling, then the
|
|
@@ -265,19 +252,12 @@ export interface FlightCaptureGate {
|
|
|
265
252
|
* closing (no holes) fires quiesce immediately for the DATA variant — the
|
|
266
253
|
* TransformStream then closes the readable, so fizz completes with postponed null.
|
|
267
254
|
*
|
|
268
|
-
*
|
|
269
|
-
*
|
|
270
|
-
*
|
|
271
|
-
*
|
|
272
|
-
* out — the handles row would never reach fizz and the prelude would come back
|
|
273
|
-
* trivial. While `holdUntil` is pending, byte-quiet detection keeps running but the
|
|
274
|
-
* gate neither fires nor freezes; once it resolves, the quiet counter restarts so a
|
|
275
|
-
* burst of rows unblocked by it (the resolved handles row) is still captured. It
|
|
276
|
-
* never delays a HOLE from postponing: holes are pending promises that emit no
|
|
277
|
-
* bytes, so holding the gate open longer only ever admits shell rows. Bounded by
|
|
278
|
-
* captureShellHTML's maxWaitMs like every other quiesce input.
|
|
255
|
+
* Nothing the shell bakes can still be pending here: settleCaptureRecord already
|
|
256
|
+
* waited for the top-level handle promises and the bake-lane loader containers
|
|
257
|
+
* before the capture's Flight render began, so the handles row and the baked
|
|
258
|
+
* loader rows emit at once and only the holes stay silent.
|
|
279
259
|
*/
|
|
280
|
-
export declare function gateFlightForCapture(source: ReadableStream<Uint8Array
|
|
260
|
+
export declare function gateFlightForCapture(source: ReadableStream<Uint8Array>): FlightCaptureGate;
|
|
281
261
|
/**
|
|
282
262
|
* The background shell-capture descriptor: everything the capture task needs to
|
|
283
263
|
* store the shell. Built by the integrated PPR serve path (rsc-rendering.ts) from
|
|
@@ -324,16 +304,13 @@ export interface ShellCaptureDescriptor {
|
|
|
324
304
|
tags?: string[];
|
|
325
305
|
/**
|
|
326
306
|
* Per-route capture settle budget in ms (`ppr.captureTimeout`, resolved by
|
|
327
|
-
* resolvePprConfig)
|
|
328
|
-
*
|
|
329
|
-
*
|
|
330
|
-
*
|
|
331
|
-
* pending). Undefined = SHELL_CAPTURE_MAX_WAIT_MS (15_000).
|
|
307
|
+
* resolvePprConfig): the ONE deadline bounding the whole capture — the match,
|
|
308
|
+
* the record-first settle (settleCaptureRecord), then the fizz prerender with
|
|
309
|
+
* what is left (captureShellHTML's maxWaitMs). Undefined =
|
|
310
|
+
* SHELL_CAPTURE_MAX_WAIT_MS (15_000).
|
|
332
311
|
*/
|
|
333
312
|
captureTimeout?: number;
|
|
334
313
|
store?: SegmentCacheStore<any>;
|
|
335
|
-
/** Gates the concise per-attempt capture breadcrumbs (INTERNAL_RANGO_DEBUG). */
|
|
336
|
-
debug?: boolean;
|
|
337
314
|
/**
|
|
338
315
|
* Cap (serialized UTF-8 bytes) on the entry's capture data snapshot; over it
|
|
339
316
|
* the snapshot is skipped and the shell stored without it (reported once per
|
|
@@ -402,22 +379,47 @@ export declare function capShellWindow(ttl: number, swr: number, record: Pick<Ro
|
|
|
402
379
|
* - `no-shell`: captureShellHTML returned null because the prelude was unusable
|
|
403
380
|
* or its private capture abort landed before the shell completed, or the
|
|
404
381
|
* capture ran out of ppr.captureTimeout. Retried once in place, when no
|
|
405
|
-
* deadline ran out (
|
|
382
|
+
* deadline ran out (CaptureAttemptStats.noShellCause).
|
|
406
383
|
* - `expired`: the route cache() record the capture read (not wrote) ran out
|
|
407
384
|
* before the store (capShellWindow null): it was near its end (its age,
|
|
408
385
|
* queue wait). Retried once in place, where a fresh match reads or renders
|
|
409
|
-
* a newer record;
|
|
386
|
+
* a newer record; an `expired` retry, or no hard-cap budget left for the
|
|
410
387
|
* retry, is terminal `no-shell` (backoff, warned once per route).
|
|
411
388
|
*/
|
|
412
389
|
type CaptureAttemptOutcome = "stored" | "redirect" | "no-shell" | "refused" | "expired";
|
|
413
390
|
/**
|
|
414
|
-
*
|
|
415
|
-
*
|
|
416
|
-
* attempt's {@link ShellCaptureDebugEvent} by runShellCapture. A plain mutable
|
|
417
|
-
* bag, not a return value: captureAndStoreShell's outcome type stays a string
|
|
418
|
-
* union its existing callers (producer B, tests) consume unchanged.
|
|
391
|
+
* What a capture task ends with (runShellCapture): a refusal and a terminal
|
|
392
|
+
* `expired` are `no-shell`, which the scheduler backs off.
|
|
419
393
|
*/
|
|
420
|
-
type
|
|
394
|
+
type CaptureTaskOutcome = "stored" | "redirect" | "no-shell";
|
|
395
|
+
/**
|
|
396
|
+
* One attempt's record, filled along the capture path (barrier and deadline
|
|
397
|
+
* causes in attemptCapture, the rest in captureAndStoreShell). runShellCapture
|
|
398
|
+
* folds the observability fields into the attempt's
|
|
399
|
+
* {@link ShellCaptureDebugEvent} and reads the rest to decide the retry and
|
|
400
|
+
* the warning. A plain mutable bag, not a return value: captureAndStoreShell's
|
|
401
|
+
* outcome type stays a string union producer B consumes unchanged.
|
|
402
|
+
*/
|
|
403
|
+
type CaptureAttemptStats = Pick<ShellCaptureDebugEvent, "barrierWaitMs" | "writeSettleMs" | "preludeBytes" | "snapshotBytes" | "snapshotSkipped" | "untaggedBake" | "storeWrite" | "recordSettleMs" | "entryBytes"> & {
|
|
404
|
+
/**
|
|
405
|
+
* Why a no-shell attempt ran out of ppr.captureTimeout (the match, the
|
|
406
|
+
* handler output, or the prerender after them). A set cause skips the
|
|
407
|
+
* in-place retry: the attempt's match may still be running.
|
|
408
|
+
*/
|
|
409
|
+
noShellCause?: string;
|
|
410
|
+
/**
|
|
411
|
+
* Dev only: component stacks of the tasks still pending at a no-shell
|
|
412
|
+
* attempt's abort, reported through prerender's onError (captureShellHTML's
|
|
413
|
+
* onAbortedTask).
|
|
414
|
+
*/
|
|
415
|
+
pendingStacks?: string[];
|
|
416
|
+
/** The route cache() record an `expired` attempt ran out on. */
|
|
417
|
+
expired?: {
|
|
418
|
+
route: string;
|
|
419
|
+
record: RouteRecordWindow;
|
|
420
|
+
captureMs: number;
|
|
421
|
+
};
|
|
422
|
+
};
|
|
421
423
|
/**
|
|
422
424
|
* Run the shell capture with a single in-place retry, then store the result.
|
|
423
425
|
*
|
|
@@ -430,14 +432,16 @@ type CaptureAttemptStats = Pick<ShellCaptureDebugEvent, "barrierWaitMs" | "write
|
|
|
430
432
|
* attempt a short beat later usually completes the shell in the SAME background
|
|
431
433
|
* task. That kills the old multi-request warmup where the caller had to re-issue
|
|
432
434
|
* several HTTP requests before a capture stuck. We retry ONLY on `no-shell`
|
|
433
|
-
* that did not run out of ppr.captureTimeout (
|
|
434
|
-
* error is NOT retried — it propagates to
|
|
435
|
-
* reportCacheError. See docs/design/ppr-shell-resume.md.
|
|
435
|
+
* that did not run out of ppr.captureTimeout (CaptureAttemptStats.noShellCause),
|
|
436
|
+
* and on `expired`; a genuine render error is NOT retried — it propagates to
|
|
437
|
+
* scheduleShellCapture's reportCacheError. See docs/design/ppr-shell-resume.md.
|
|
436
438
|
*
|
|
437
|
-
* `
|
|
438
|
-
*
|
|
439
|
+
* `request` and `url` are the capture's own identity (scheduleShellCapture
|
|
440
|
+
* strips a navigation-only capture's transport parameters). `retryDelayMs` is
|
|
441
|
+
* a parameter (defaulting to the module const) so unit tests can drive the
|
|
442
|
+
* retry without a real 400ms wall-clock wait.
|
|
439
443
|
*/
|
|
440
|
-
declare function runShellCapture(ctx: HandlerContext<any>, request: Request, env: any, url: URL, reqCtx: RequestContext<any>, ssrModule: SSRModule, descriptor: ShellCaptureDescriptor, retryDelayMs?: number): Promise<
|
|
444
|
+
declare function runShellCapture(ctx: HandlerContext<any>, request: Request, env: any, url: URL, reqCtx: RequestContext<any>, ssrModule: SSRModule, descriptor: ShellCaptureDescriptor, retryDelayMs?: number): Promise<CaptureTaskOutcome>;
|
|
441
445
|
/**
|
|
442
446
|
* What the record-first step produced ({@link settleCaptureRecord}):
|
|
443
447
|
* - `record`: the doc record settled; `match` carries its fragments in place
|
|
@@ -486,17 +490,6 @@ export type CaptureRecordOutcome = {
|
|
|
486
490
|
* scope's own write), and the deferred writes settle.
|
|
487
491
|
*/
|
|
488
492
|
export declare function settleCaptureRecord(match: MatchResult, derivation: CaptureContextDerivation, capture: Pick<ShellCaptureDescriptor, "key">, deadline: number): Promise<CaptureRecordOutcome>;
|
|
489
|
-
/**
|
|
490
|
-
* Race `work` against an absolute deadline, keeping its value. The losing
|
|
491
|
-
* work is not cancelled (a router match has no abort signal); callers that
|
|
492
|
-
* lose do not start it again (runShellCapture skips its in-place retry).
|
|
493
|
-
*/
|
|
494
|
-
export declare function withinDeadline<T>(work: Promise<T>, deadline: number): Promise<{
|
|
495
|
-
done: true;
|
|
496
|
-
value: T;
|
|
497
|
-
} | {
|
|
498
|
-
done: false;
|
|
499
|
-
}>;
|
|
500
493
|
/**
|
|
501
494
|
* The derived capture context and its fresh (mask-funneled) handle store,
|
|
502
495
|
* shared by BOTH shell producers: the runtime background capture
|
|
@@ -530,27 +523,31 @@ export declare function deriveShellCaptureContext(reqCtx: RequestContext<any>, d
|
|
|
530
523
|
url: URL;
|
|
531
524
|
}): CaptureContextDerivation;
|
|
532
525
|
/**
|
|
533
|
-
*
|
|
534
|
-
* captureShellHTML, and store the result.
|
|
535
|
-
*
|
|
536
|
-
*
|
|
537
|
-
*
|
|
538
|
-
*
|
|
539
|
-
*
|
|
526
|
+
* Derive the quiesce signal, prerender + abort via the SSR module's
|
|
527
|
+
* captureShellHTML, and store the result. Runs after settleCaptureRecord (both
|
|
528
|
+
* producers), which sealed the capture's handle store (`reqCtx._handleStore`)
|
|
529
|
+
* and waited for everything the shell bakes. Returns the attempt outcome (the
|
|
530
|
+
* caller owns retry/warn decisions). Never throws out of the store write: a
|
|
531
|
+
* failed putShell is routed through reportCacheError so the background task
|
|
532
|
+
* stays best-effort, and the attempt still counts as `stored` (the capture
|
|
533
|
+
* worked; only the store I/O failed). `ssrModule.captureShellHTML` MUST be
|
|
534
|
+
* present (eligibility is checked before scheduling). `captureStartedAt` is the
|
|
535
|
+
* capture generation's start, stamped before the match (ShellCacheEntry
|
|
536
|
+
* .createdAt).
|
|
540
537
|
*
|
|
541
538
|
* A `no-shell` result from captureShellHTML is the only retryable outcome. Every
|
|
542
539
|
* captureShellHTML error propagates to reportCacheError and is NOT retried. The
|
|
543
540
|
* capture handler converts only its own private abort sentinel to null before this
|
|
544
541
|
* layer sees it.
|
|
545
542
|
*/
|
|
546
|
-
declare function captureAndStoreShell(ssrModule: SSRModule, rscStream: ReadableStream<Uint8Array>,
|
|
543
|
+
declare function captureAndStoreShell(ssrModule: SSRModule, rscStream: ReadableStream<Uint8Array>, reqCtx: RequestContext<any>, capture: ShellCaptureDescriptor, captureStartedAt: number, stats?: CaptureAttemptStats): Promise<Exclude<CaptureAttemptOutcome, "redirect">>;
|
|
547
544
|
export { runShellCapture, captureAndStoreShell, delay, SHELL_CAPTURE_RETRY_DELAY_MS, };
|
|
548
545
|
export { isCaptureBackedOff, markCaptureBackoff, clearCaptureBackoff, REFUSED_CAPTURE_BASE_MS, REFUSED_CAPTURE_MAX_MS, REFUSED_CAPTURE_DEV_MAX_MS, };
|
|
549
546
|
/**
|
|
550
547
|
* @internal Reset this module's per-isolate state: the capture stampede
|
|
551
|
-
* guard, the refused-capture backoff, the
|
|
552
|
-
*
|
|
553
|
-
*
|
|
554
|
-
*
|
|
548
|
+
* guard, the refused-capture backoff, the once-per-key warnings (the shell
|
|
549
|
+
* path's one registry), the stored-capture sequence and the buffered debug
|
|
550
|
+
* events. Tests only (testing/serve-shell-request.ts resetShellTestState),
|
|
551
|
+
* between requests, never while a capture runs.
|
|
555
552
|
*/
|
|
556
553
|
export declare function resetShellCaptureStateForTests(): void;
|
|
@@ -16,12 +16,8 @@
|
|
|
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 {
|
|
20
|
-
|
|
21
|
-
/** Debug/status header the browser (and e2e assertions) can read: HIT | MISS. */
|
|
22
|
-
export declare const SHELL_STATUS_HEADER = "x-rango-shell";
|
|
23
|
-
/** Partial-navigation status header set only after captured PPR segments are consumed. */
|
|
24
|
-
export declare const PPR_REPLAY_STATUS_HEADER = "x-rango-ppr-replay";
|
|
19
|
+
import type { DocumentShellCacheEntry, ShellCacheEntry, ShellDocumentRead, ShellEntryHead, ShellReadStats, ShellSnapshotFailure, ShellSnapshotRecord, SegmentCacheStore } from "../cache/types.js";
|
|
20
|
+
export { PPR_REPLAY_STATUS_HEADER, SHELL_STATUS_HEADER, buildShellKey, navigationShellKey, partitionShellKey, shellSearchSeed, } from "./shell-capture-constants.js";
|
|
25
21
|
/**
|
|
26
22
|
* Default shell ttl (seconds) for `ppr: true` and for a PartialPrerenderProps
|
|
27
23
|
* that omits `ttl`.
|
|
@@ -79,22 +75,6 @@ export declare function normalizeCaptureTimeout(value: unknown): number | undefi
|
|
|
79
75
|
* inheritance (declaring it on a layout is not supported — a follow-up).
|
|
80
76
|
*/
|
|
81
77
|
export declare function resolvePprConfig(entry: EntryData | undefined | null): ResolvedPprConfig | null;
|
|
82
|
-
/**
|
|
83
|
-
* Shell cache key: host + pathname + sorted search + a `:shell` namespace suffix
|
|
84
|
-
* (so it can never collide with a document-cache key; the store further isolates
|
|
85
|
-
* the shell family internally).
|
|
86
|
-
*
|
|
87
|
-
* The key includes the request HOST: in a multi-tenant host-router deployment
|
|
88
|
-
* (one worker, one shared KV/runtime-cache store) a host-less key would serve
|
|
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.
|
|
95
|
-
*/
|
|
96
|
-
export declare function buildShellKey(url: URL, filter?: SearchParamsFilter): string;
|
|
97
|
-
export { navigationShellKey, partitionShellKey, } from "./shell-capture-constants.js";
|
|
98
78
|
/**
|
|
99
79
|
* The forced-MISS query marker. A document HIT that cannot finish its tail
|
|
100
80
|
* reloads the page with it (shellReloadScript); the serve gate renders a
|
|
@@ -122,35 +102,24 @@ export declare function withoutShellMissMarker(request: Request): Request | unde
|
|
|
122
102
|
* did (a server that ignores the marker) it would return without touching
|
|
123
103
|
* the page. window.stop() runs only when it reloads: it keeps the half-sent
|
|
124
104
|
* Flight stream from being closed by DOMContentLoaded, which would throw
|
|
125
|
-
* React's "Connection closed" (#412) before the reload lands.
|
|
126
|
-
* request's CSP nonce; a ppr route with an active nonce is axis 1
|
|
127
|
-
* (rsc-rendering.ts shellServePlan), so on a HIT it is normally absent.
|
|
105
|
+
* React's "Connection closed" (#412) before the reload lands.
|
|
128
106
|
*/
|
|
129
|
-
export declare function shellReloadScript(
|
|
130
|
-
/** An inline script a shell HIT's tail appends, carrying the CSP nonce if any. */
|
|
131
|
-
export declare function inlineShellScript(body: string, nonce?: string): string;
|
|
107
|
+
export declare function shellReloadScript(): string;
|
|
132
108
|
/**
|
|
133
|
-
*
|
|
134
|
-
*
|
|
135
|
-
*
|
|
136
|
-
* / ShellCaptureOptions.search / ShellResumeOptions.search). Search is part
|
|
137
|
-
* of shell identity, so static-part `useSearchParams` reads render exactly
|
|
138
|
-
* what the key names; deriving seed and key from this one helper is what
|
|
139
|
-
* keeps capture, resume, and lookup byte-agreed (drift = replay mismatch or
|
|
140
|
-
* permanent MISS).
|
|
109
|
+
* An inline script a shell HIT's tail appends. It carries no CSP nonce: a
|
|
110
|
+
* request with an active per-request nonce never reaches a HIT
|
|
111
|
+
* (rsc-rendering.ts shellServePlan serves it on axis 1).
|
|
141
112
|
*/
|
|
142
|
-
export declare function
|
|
113
|
+
export declare function inlineShellScript(body: string): string;
|
|
143
114
|
/**
|
|
144
115
|
* Version gates for a stored shell: reactVersion AND buildVersion must both
|
|
145
116
|
* match the running server. The postponed blob encodes hole positions against
|
|
146
117
|
* one exact tree, so resuming it under a different React OR a different app
|
|
147
118
|
* build tree-mismatches inside resume() — after the 200 + prelude committed,
|
|
148
119
|
* with no recovery. Either mismatch is a miss: the recapture overwrites the
|
|
149
|
-
* same key (self-healing) and the entry otherwise ages out via TTL.
|
|
150
|
-
* with no buildVersion (stored before the field existed) is a miss for the
|
|
151
|
-
* same reason — its build is unknown, so it cannot be proven resumable.
|
|
120
|
+
* same key (self-healing) and the entry otherwise ages out via TTL.
|
|
152
121
|
*/
|
|
153
|
-
export declare function isValidShellHit(entry: ShellCacheEntry, buildVersion: string): boolean;
|
|
122
|
+
export declare function isValidShellHit(entry: Pick<ShellCacheEntry, "reactVersion" | "buildVersion">, buildVersion: string): boolean;
|
|
154
123
|
/**
|
|
155
124
|
* DOCUMENT-half structural gate and type narrowing, without decoding the
|
|
156
125
|
* prelude: the prelude is a string and the postponed blob parses. Partial
|
|
@@ -167,7 +136,7 @@ export declare function isValidShellHit(entry: ShellCacheEntry, buildVersion: st
|
|
|
167
136
|
export declare function hasIntactShellPayload(entry: ShellCacheEntry): entry is DocumentShellCacheEntry;
|
|
168
137
|
/** A document shell ready to serve: its prelude decoded exactly once. */
|
|
169
138
|
export interface ShellDocument {
|
|
170
|
-
entry:
|
|
139
|
+
entry: ShellEntryHead;
|
|
171
140
|
prelude: Uint8Array;
|
|
172
141
|
/** React's postponed state, parse-checked (null = DATA variant). */
|
|
173
142
|
postponed: string | null;
|
|
@@ -176,7 +145,7 @@ export interface ShellDocument {
|
|
|
176
145
|
* after a prelude-first read (SegmentCacheStore.readShellDocument), which
|
|
177
146
|
* only the tail awaits.
|
|
178
147
|
*/
|
|
179
|
-
snapshot: ShellSnapshotRecord[] |
|
|
148
|
+
snapshot: ShellSnapshotRecord[] | Promise<ShellSnapshotRecord[] | undefined>;
|
|
180
149
|
/** Why a prelude-first read's snapshot is missing (ShellDocumentRead). */
|
|
181
150
|
snapshotFailure?: Promise<ShellSnapshotFailure | undefined>;
|
|
182
151
|
/** The prelude-first read's stats, when perf metrics are on. */
|
|
@@ -194,7 +163,8 @@ export interface ShellDocument {
|
|
|
194
163
|
* A prelude-first `read` (SegmentCacheStore.readShellDocument) already carries
|
|
195
164
|
* the raw bytes and a pending snapshot, so only its postponed blob is checked.
|
|
196
165
|
*/
|
|
197
|
-
export declare function openShellDocument(entry: ShellCacheEntry
|
|
166
|
+
export declare function openShellDocument(entry: ShellCacheEntry): ShellDocument | null;
|
|
167
|
+
export declare function openShellDocument(entry: ShellEntryHead, read: Pick<ShellDocumentRead, "prelude" | "snapshot" | "snapshotFailure" | "stats">): ShellDocument | null;
|
|
198
168
|
/**
|
|
199
169
|
* Prelude enqueue granularity. A streaming compressor in front of the worker
|
|
200
170
|
* emits its first byte only after compressing the whole write it was handed:
|
|
@@ -228,7 +198,7 @@ export interface ShellTailTiming {
|
|
|
228
198
|
snapshotReadMs?: number;
|
|
229
199
|
/** Snapshot JSON.parse CPU (reads 0 on a deployed worker: see bytes). */
|
|
230
200
|
snapshotParseMs?: number;
|
|
231
|
-
/** Snapshot records by family, e.g. `segment:1/
|
|
201
|
+
/** Snapshot records by family, e.g. `segment:1/loader:2` (no commas: it rides a Server-Timing desc). */
|
|
232
202
|
snapshotRecords?: string;
|
|
233
203
|
/** Records the capture pruned from the snapshot, same format (ShellCacheEntry.prunedRecords). */
|
|
234
204
|
snapshotPruned?: string;
|
|
@@ -251,7 +221,7 @@ export interface ShellTailTiming {
|
|
|
251
221
|
}
|
|
252
222
|
/**
|
|
253
223
|
* Compact single-line form for the console log and the Server-Timing mirror's
|
|
254
|
-
* `desc`: alphanumerics and `=`, `-`, `:`, `/` only (records=segment:1 pruned=
|
|
224
|
+
* `desc`: alphanumerics and `=`, `-`, `:`, `/` only (records=segment:1/loader:2 pruned=loader:1),
|
|
255
225
|
* so no quoted-string escaping is needed. Offsets are from the commit; the
|
|
256
226
|
* `-cpu` fields are CPU-only durations.
|
|
257
227
|
*/
|
|
@@ -317,7 +287,8 @@ export declare function partitionBuildShellCheckDone(pathname: string, routeName
|
|
|
317
287
|
*/
|
|
318
288
|
export declare function notePartitionBuildShellCheck(pathname: string, routeName: string | undefined, found: boolean): void;
|
|
319
289
|
/**
|
|
320
|
-
* @internal Reset the serve path's once-per-key warnings
|
|
321
|
-
*
|
|
290
|
+
* @internal Reset the serve path's once-per-key warnings (the shell path's
|
|
291
|
+
* one registry), its build-shell probe memo and buffered tail timings. Tests
|
|
292
|
+
* only (testing/serve-shell-request.ts resetShellTestState).
|
|
322
293
|
*/
|
|
323
294
|
export declare function resetShellServeStateForTests(): void;
|
|
@@ -32,6 +32,8 @@ export interface RscPayload {
|
|
|
32
32
|
resolvedIds?: string[];
|
|
33
33
|
/** Merged route params from the matched route */
|
|
34
34
|
params?: Record<string, string>;
|
|
35
|
+
/** Matched route name, when named (transition({ when }) route names). */
|
|
36
|
+
routeName?: string;
|
|
35
37
|
slots?: Record<string, SlotState>;
|
|
36
38
|
/**
|
|
37
39
|
* Intercept TARGET route names reachable from this location as a
|
|
@@ -19,6 +19,13 @@ export interface RenderSegmentsOptions {
|
|
|
19
19
|
forceAwait?: boolean;
|
|
20
20
|
/** Seeded descendant client-route pending state for testing. */
|
|
21
21
|
outletPending?: boolean;
|
|
22
|
+
/**
|
|
23
|
+
* This commit's transition({ when }) decision was false
|
|
24
|
+
* (browser/transition-when.ts): the navigation is urgent, so no segment
|
|
25
|
+
* animates. Every router <ViewTransition> stays in the tree with each class
|
|
26
|
+
* "none", so the element type never changes; keys never read this (#995).
|
|
27
|
+
*/
|
|
28
|
+
transitionGatedOff?: boolean;
|
|
22
29
|
/**
|
|
23
30
|
* Intercept segments to inject into the tree.
|
|
24
31
|
* These are parallel segments from intercept routes that need to be
|