@rangojs/router 0.17.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/README.md +3 -2
- package/dist/types/browser/cookie-name.d.ts +6 -0
- package/dist/types/browser/event-controller.d.ts +3 -3
- package/dist/types/browser/history-state.d.ts +18 -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 +48 -2
- package/dist/types/cache/cache-policy.d.ts +18 -1
- package/dist/types/cache/cache-runtime.d.ts +7 -0
- package/dist/types/cache/cache-scope.d.ts +192 -26
- package/dist/types/cache/cache-tag.d.ts +116 -11
- package/dist/types/cache/cf/cf-base64.d.ts +6 -0
- package/dist/types/cache/cf/cf-cache-constants.d.ts +11 -0
- package/dist/types/cache/cf/cf-cache-store.d.ts +224 -72
- package/dist/types/cache/cf/cf-cache-types.d.ts +31 -4
- package/dist/types/cache/cf/cf-shell-frame.d.ts +95 -0
- package/dist/types/cache/cf/cf-tag-marker-memo.d.ts +19 -0
- package/dist/types/cache/document-cache.d.ts +10 -0
- package/dist/types/cache/handle-snapshot.d.ts +41 -8
- package/dist/types/cache/index.d.ts +1 -0
- package/dist/types/cache/invalidation-order.d.ts +23 -0
- package/dist/types/cache/isolate-tag-memo.d.ts +149 -0
- package/dist/types/cache/request-tag-mask.d.ts +54 -0
- package/dist/types/cache/shell-memo.d.ts +178 -0
- package/dist/types/cache/shell-snapshot.d.ts +141 -105
- package/dist/types/cache/tag-invalidation.d.ts +54 -3
- package/dist/types/cache/types.d.ts +267 -96
- package/dist/types/cache/vercel/vercel-cache-store.d.ts +123 -18
- 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/prerender/build-shell-capture.d.ts +11 -4
- 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/instrument.d.ts +8 -0
- 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/middleware-types.d.ts +6 -1
- package/dist/types/router/router-options.d.ts +4 -1
- package/dist/types/router/segment-resolution/loader-cache.d.ts +58 -12
- package/dist/types/router/segment-resolution/loader-mask.d.ts +3 -4
- package/dist/types/router/segment-resolution/loader-snapshot.d.ts +33 -48
- package/dist/types/router/segment-resolution/mask-nested.d.ts +73 -24
- 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 +21 -0
- package/dist/types/rsc/handler.d.ts +1 -1
- package/dist/types/rsc/response-cache-serve.d.ts +15 -12
- package/dist/types/rsc/shell-build-manifest.d.ts +12 -3
- package/dist/types/rsc/shell-capture-constants.d.ts +116 -12
- package/dist/types/rsc/shell-capture.d.ts +202 -74
- package/dist/types/rsc/shell-serve.d.ts +144 -50
- package/dist/types/rsc/types.d.ts +9 -0
- package/dist/types/segment-system.d.ts +7 -0
- package/dist/types/server/context.d.ts +155 -33
- package/dist/types/server/cookie-store.d.ts +33 -0
- package/dist/types/server/handle-store.d.ts +52 -1
- package/dist/types/server/request-context.d.ts +210 -63
- package/dist/types/server/request-headers.d.ts +44 -0
- package/dist/types/server.d.ts +1 -0
- package/dist/types/ssr/index.d.ts +9 -0
- package/dist/types/ssr/ssr-root.d.ts +9 -8
- package/dist/types/testing/e2e/index.d.ts +1 -1
- package/dist/types/testing/flight.entry.d.ts +7 -0
- 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-loader.d.ts +18 -3
- package/dist/types/testing/run-transition-when.d.ts +44 -69
- package/dist/types/testing/serve-shell-request.d.ts +133 -0
- package/dist/types/testing/shell-status.d.ts +44 -19
- package/dist/types/transition-when-ref.d.ts +79 -0
- package/dist/types/types/cache-types.d.ts +15 -3
- package/dist/types/types/handler-context.d.ts +14 -1
- 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 +21 -18
- package/dist/types/vite/plugins/transition-when-hoist.d.ts +45 -0
- package/dist/types/vite/router-discovery.d.ts +29 -2
- package/dist/vite/index.js +1005 -105
- package/package.json +1 -1
- package/skills/breadcrumbs/SKILL.md +17 -7
- package/skills/cache-guide/SKILL.md +175 -76
- package/skills/caching/SKILL.md +361 -33
- package/skills/catalog.json +1 -1
- package/skills/client-urls/SKILL.md +12 -7
- package/skills/cloudflare/SKILL.md +15 -0
- package/skills/comparison/references/framework-comparison.md +52 -37
- package/skills/defer-hydration/SKILL.md +50 -30
- package/skills/deployment-caching/SKILL.md +5 -2
- package/skills/document-cache/SKILL.md +32 -2
- package/skills/handler-use/SKILL.md +2 -0
- package/skills/hooks/SKILL.md +3 -1
- package/skills/hooks/handle-and-actions.md +3 -1
- package/skills/hooks/navigation.md +23 -2
- package/skills/hooks/state.md +101 -7
- package/skills/intercept/SKILL.md +29 -12
- package/skills/loader/SKILL.md +197 -44
- package/skills/middleware/SKILL.md +34 -9
- package/skills/migrate-nextjs/SKILL.md +68 -37
- package/skills/migrate-react-router/SKILL.md +2 -1
- package/skills/migrate-react-router/component-migration.md +3 -1
- package/skills/migrate-react-router/data-and-actions.md +3 -1
- package/skills/migrate-react-router/route-mapping.md +7 -4
- package/skills/observability/SKILL.md +65 -0
- package/skills/parallel/SKILL.md +13 -8
- package/skills/ppr/SKILL.md +715 -371
- package/skills/prerender/SKILL.md +30 -17
- package/skills/rango/SKILL.md +72 -34
- package/skills/route/SKILL.md +14 -7
- package/skills/router-setup/SKILL.md +4 -2
- package/skills/scripts/SKILL.md +8 -1
- package/skills/server-actions/SKILL.md +11 -0
- package/skills/shell-manifest/SKILL.md +21 -12
- package/skills/testing/SKILL.md +49 -43
- package/skills/testing/cache-prerender.md +15 -14
- package/skills/testing/client-components.md +45 -3
- package/skills/testing/loader.md +19 -1
- 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 +202 -0
- package/skills/testing/server-actions.md +9 -3
- package/skills/theme/SKILL.md +56 -4
- package/skills/typesafety/env-and-bindings.md +18 -2
- package/skills/use-cache/SKILL.md +91 -23
- package/skills/vercel/SKILL.md +14 -2
- package/skills/view-transitions/SKILL.md +150 -29
- package/src/__augment-tests__/augmented.check.ts +23 -0
- package/src/browser/cookie-name.ts +23 -0
- package/src/browser/event-controller.ts +4 -4
- package/src/browser/history-state.ts +75 -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 +9 -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 +62 -2
- package/src/cache/cache-policy.ts +31 -4
- package/src/cache/cache-runtime.ts +209 -129
- package/src/cache/cache-scope.ts +573 -69
- package/src/cache/cache-tag.ts +475 -19
- package/src/cache/cf/cf-base64.ts +36 -4
- package/src/cache/cf/cf-cache-constants.ts +12 -0
- package/src/cache/cf/cf-cache-store.ts +1094 -376
- package/src/cache/cf/cf-cache-types.ts +32 -4
- package/src/cache/cf/cf-shell-frame.ts +258 -0
- package/src/cache/cf/cf-tag-marker-memo.ts +55 -40
- package/src/cache/document-cache.ts +53 -7
- package/src/cache/handle-snapshot.ts +53 -9
- package/src/cache/index.ts +2 -0
- package/src/cache/invalidation-order.ts +84 -0
- package/src/cache/isolate-tag-memo.ts +308 -0
- package/src/cache/request-tag-mask.ts +147 -0
- package/src/cache/shell-memo.ts +341 -0
- package/src/cache/shell-snapshot.ts +249 -277
- package/src/cache/tag-invalidation.ts +109 -18
- package/src/cache/types.ts +274 -102
- package/src/cache/vercel/vercel-cache-store.ts +561 -74
- 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 +173 -110
- package/src/route-definition/dsl-helpers.ts +6 -3
- 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 +42 -5
- package/src/router/instrument.ts +54 -2
- package/src/router/intercept-resolution.ts +30 -8
- package/src/router/loader-resolution.ts +89 -33
- package/src/router/logging.ts +5 -3
- package/src/router/match-api.ts +89 -42
- package/src/router/match-context.ts +5 -0
- package/src/router/match-handlers.ts +14 -29
- package/src/router/match-middleware/background-revalidation.ts +3 -5
- package/src/router/match-middleware/cache-lookup.ts +52 -19
- package/src/router/match-middleware/cache-store.ts +36 -10
- package/src/router/match-result.ts +1 -0
- package/src/router/middleware-types.ts +6 -1
- package/src/router/middleware.ts +20 -4
- package/src/router/navigation-snapshot.ts +6 -5
- package/src/router/prerender-match.ts +10 -0
- package/src/router/request-classification.ts +7 -4
- package/src/router/router-options.ts +4 -1
- package/src/router/segment-resolution/fresh.ts +18 -13
- package/src/router/segment-resolution/helpers.ts +4 -2
- package/src/router/segment-resolution/loader-cache.ts +366 -70
- package/src/router/segment-resolution/loader-mask.ts +3 -4
- package/src/router/segment-resolution/loader-snapshot.ts +215 -126
- package/src/router/segment-resolution/mask-nested.ts +161 -42
- package/src/router/segment-resolution/revalidation.ts +27 -13
- 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 +47 -3
- package/src/rsc/handler.ts +24 -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 +10 -32
- package/src/rsc/response-cache-serve.ts +69 -78
- package/src/rsc/response-route-handler.ts +2 -2
- package/src/rsc/rsc-rendering.ts +712 -338
- package/src/rsc/server-action.ts +8 -20
- package/src/rsc/shell-build-manifest.ts +49 -29
- package/src/rsc/shell-capture-constants.ts +182 -12
- package/src/rsc/shell-capture.ts +1126 -612
- package/src/rsc/shell-serve.ts +331 -85
- package/src/rsc/ssr-setup.ts +3 -2
- package/src/rsc/types.ts +9 -0
- package/src/segment-system.tsx +40 -7
- package/src/server/context.ts +328 -72
- package/src/server/cookie-store.ts +184 -133
- package/src/server/handle-store.ts +245 -27
- package/src/server/request-context.ts +364 -100
- package/src/server/request-headers.ts +134 -0
- package/src/server.ts +4 -0
- package/src/ssr/index.tsx +96 -37
- package/src/ssr/ssr-root.tsx +9 -8
- package/src/testing/dispatch.ts +4 -7
- package/src/testing/e2e/index.ts +1 -0
- package/src/testing/flight.entry.ts +14 -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 +67 -5
- package/src/testing/run-transition-when.ts +109 -172
- package/src/testing/serve-shell-request.ts +381 -0
- package/src/testing/shell-status.ts +73 -47
- package/src/theme/ThemeProvider.tsx +7 -6
- package/src/transition-when-ref.ts +220 -0
- package/src/types/cache-types.ts +15 -3
- package/src/types/handler-context.ts +14 -1
- 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 +21 -18
- package/src/vite/discovery/discover-routers.ts +3 -0
- package/src/vite/discovery/shell-prerender-phase.ts +9 -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 +89 -9
- package/dist/types/rsc/transition-gate.d.ts +0 -23
- package/src/rsc/transition-gate.ts +0 -86
|
@@ -6,28 +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
|
-
import {
|
|
19
|
-
import { type RequestContext } from "../server/request-context.js";
|
|
21
|
+
import { type MatchResult } from "../types.js";
|
|
22
|
+
import { type RequestContext, type RouteRecordWindow } from "../server/request-context.js";
|
|
20
23
|
import { type HandleStore } from "../server/handle-store.js";
|
|
21
24
|
import type { SegmentCacheStore } from "../cache/types.js";
|
|
22
25
|
import type { HandlerContext } from "./handler-context.js";
|
|
23
26
|
import type { SSRModule } from "./types.js";
|
|
24
|
-
/**
|
|
25
|
-
* Default capture budget. Canonical value, raise rationale, and ceiling math
|
|
26
|
-
* live on the leaf module (shell-capture-constants.ts, importable from the ssr
|
|
27
|
-
* graph too). Re-exported here so shell-build-manifest.ts's envelope math
|
|
28
|
-
* keeps its existing import site and cannot drift from the capture.
|
|
29
|
-
*/
|
|
30
|
-
export { SHELL_CAPTURE_MAX_WAIT_MS };
|
|
31
27
|
/**
|
|
32
28
|
* Delay before the in-place retry of a capture that produced no usable shell.
|
|
33
29
|
*
|
|
@@ -79,6 +75,7 @@ declare const REFUSED_CAPTURE_MAX_MS = 60000;
|
|
|
79
75
|
* docs/design/ppr-shell-resume.md ("Refused-capture backoff").
|
|
80
76
|
*/
|
|
81
77
|
declare const REFUSED_CAPTURE_DEV_MAX_MS = 2000;
|
|
78
|
+
/** True iff `key` is still inside its (exponential) backoff window. */
|
|
82
79
|
declare function isCaptureBackedOff(key: string): boolean;
|
|
83
80
|
/**
|
|
84
81
|
* Record a refused/failed capture, escalating the backoff window exponentially up
|
|
@@ -91,6 +88,13 @@ declare function isCaptureBackedOff(key: string): boolean;
|
|
|
91
88
|
declare function markCaptureBackoff(key: string): void;
|
|
92
89
|
/** Clear any backoff for a key that just captured successfully. */
|
|
93
90
|
declare function clearCaptureBackoff(key: string): void;
|
|
91
|
+
/**
|
|
92
|
+
* Default limit (bytes) on a whole stored shell entry — prelude, postponed
|
|
93
|
+
* state, and snapshot — when the store declares none
|
|
94
|
+
* (SegmentCacheStore.maxShellEntryBytes). Cloudflare KV's 25 MiB value limit:
|
|
95
|
+
* the tightest common store tier a shell entry lands in.
|
|
96
|
+
*/
|
|
97
|
+
export declare const DEFAULT_SHELL_ENTRY_MAX_BYTES: number;
|
|
94
98
|
/**
|
|
95
99
|
* Default cap (serialized UTF-8 bytes) on the capture data snapshot riding
|
|
96
100
|
* inside a shell entry, when the route's `ppr` option does not set
|
|
@@ -100,8 +104,9 @@ declare function clearCaptureBackoff(key: string): void;
|
|
|
100
104
|
* while still fitting any sane pinned-ring payload. Applied ONLY in
|
|
101
105
|
* captureAndStoreShell (the single defaulting site — resolvePprConfig passes
|
|
102
106
|
* the option through undefaulted), so every producer and direct caller gets
|
|
103
|
-
* the same policy.
|
|
104
|
-
*
|
|
107
|
+
* the same policy. The doc record is exempt; over the cap the other records
|
|
108
|
+
* are dropped (shell still stored and replayed; the pins' loaders read the
|
|
109
|
+
* live store — see PartialPrerenderProps.maxSnapshotBytes).
|
|
105
110
|
*/
|
|
106
111
|
export declare const DEFAULT_PPR_MAX_SNAPSHOT_BYTES: number;
|
|
107
112
|
/**
|
|
@@ -116,10 +121,13 @@ export interface ShellCaptureDebugEvent {
|
|
|
116
121
|
key: string;
|
|
117
122
|
/**
|
|
118
123
|
* What happened:
|
|
119
|
-
* - stored / redirect / no-shell / refused: one capture
|
|
120
|
-
* (see CaptureAttemptOutcome for the semantics of each)
|
|
124
|
+
* - stored / redirect / no-shell / refused / expired: one capture
|
|
125
|
+
* ATTEMPT's outcome (see CaptureAttemptOutcome for the semantics of each)
|
|
121
126
|
* - error: the capture task failed with a genuine error (also routed through
|
|
122
127
|
* reportCacheError; the key is backed off)
|
|
128
|
+
* - skip-stored: a capture for the key stored after the scheduling request
|
|
129
|
+
* read the store and missed (ShellCaptureDescriptor.storedSeqAtRead), so
|
|
130
|
+
* the shell that request missed exists now
|
|
123
131
|
* - skip-in-flight: scheduleShellCapture found a capture already running for
|
|
124
132
|
* the key (stampede guard) and scheduled nothing
|
|
125
133
|
* - skip-backoff: the key is inside its refused-capture backoff window and
|
|
@@ -137,7 +145,7 @@ export interface ShellCaptureDebugEvent {
|
|
|
137
145
|
* - backoff: the key entered (or escalated) backoff after a terminal
|
|
138
146
|
* no-shell — carries the new backoff state
|
|
139
147
|
*/
|
|
140
|
-
outcome: "stored" | "redirect" | "no-shell" | "refused" | "error" | "skip-in-flight" | "skip-backoff" | "skip-capacity" | "skip-inert-store" | "skip-queue-timeout" | "backoff";
|
|
148
|
+
outcome: "stored" | "redirect" | "no-shell" | "refused" | "expired" | "error" | "skip-in-flight" | "skip-stored" | "skip-backoff" | "skip-capacity" | "skip-inert-store" | "skip-queue-timeout" | "backoff";
|
|
141
149
|
/** Attempt number (1 = first, 2 = in-place retry). Absent on skips. */
|
|
142
150
|
attempt?: number;
|
|
143
151
|
/** Wall-clock ms of the whole attempt (barrier + render + drain + put). */
|
|
@@ -176,14 +184,13 @@ export interface ShellCaptureDebugEvent {
|
|
|
176
184
|
*/
|
|
177
185
|
queueAhead?: number;
|
|
178
186
|
/**
|
|
179
|
-
*
|
|
180
|
-
*
|
|
181
|
-
*
|
|
182
|
-
* (the hole doctrine: top-level promises bake), but it recurs on EVERY
|
|
183
|
-
* capture of the route and occupies the serialized queue; this field makes
|
|
184
|
-
* it attributable. Absent when nothing held the gate.
|
|
187
|
+
* How long the capture waited for its doc record: the handler layer's
|
|
188
|
+
* promises, async server components and handle pushes settling, then the
|
|
189
|
+
* record's encode (settleCaptureRecord). Part of the one capture deadline.
|
|
185
190
|
*/
|
|
186
|
-
|
|
191
|
+
recordSettleMs?: number;
|
|
192
|
+
/** Bytes of the stored entry: prelude, postponed state, and snapshot. */
|
|
193
|
+
entryBytes?: number;
|
|
187
194
|
}
|
|
188
195
|
/**
|
|
189
196
|
* Debug sink for the capture pipeline, mirroring {@link CFCacheDebug}: `true`
|
|
@@ -245,19 +252,12 @@ export interface FlightCaptureGate {
|
|
|
245
252
|
* closing (no holes) fires quiesce immediately for the DATA variant — the
|
|
246
253
|
* TransformStream then closes the readable, so fizz completes with postponed null.
|
|
247
254
|
*
|
|
248
|
-
*
|
|
249
|
-
*
|
|
250
|
-
*
|
|
251
|
-
*
|
|
252
|
-
* out — the handles row would never reach fizz and the prelude would come back
|
|
253
|
-
* trivial. While `holdUntil` is pending, byte-quiet detection keeps running but the
|
|
254
|
-
* gate neither fires nor freezes; once it resolves, the quiet counter restarts so a
|
|
255
|
-
* burst of rows unblocked by it (the resolved handles row) is still captured. It
|
|
256
|
-
* never delays a HOLE from postponing: holes are pending promises that emit no
|
|
257
|
-
* bytes, so holding the gate open longer only ever admits shell rows. Bounded by
|
|
258
|
-
* 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.
|
|
259
259
|
*/
|
|
260
|
-
export declare function gateFlightForCapture(source: ReadableStream<Uint8Array
|
|
260
|
+
export declare function gateFlightForCapture(source: ReadableStream<Uint8Array>): FlightCaptureGate;
|
|
261
261
|
/**
|
|
262
262
|
* The background shell-capture descriptor: everything the capture task needs to
|
|
263
263
|
* store the shell. Built by the integrated PPR serve path (rsc-rendering.ts) from
|
|
@@ -304,16 +304,13 @@ export interface ShellCaptureDescriptor {
|
|
|
304
304
|
tags?: string[];
|
|
305
305
|
/**
|
|
306
306
|
* Per-route capture settle budget in ms (`ppr.captureTimeout`, resolved by
|
|
307
|
-
* resolvePprConfig)
|
|
308
|
-
*
|
|
309
|
-
*
|
|
310
|
-
*
|
|
311
|
-
* 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).
|
|
312
311
|
*/
|
|
313
312
|
captureTimeout?: number;
|
|
314
313
|
store?: SegmentCacheStore<any>;
|
|
315
|
-
/** Gates the concise per-attempt capture breadcrumbs (INTERNAL_RANGO_DEBUG). */
|
|
316
|
-
debug?: boolean;
|
|
317
314
|
/**
|
|
318
315
|
* Cap (serialized UTF-8 bytes) on the entry's capture data snapshot; over it
|
|
319
316
|
* the snapshot is skipped and the shell stored without it (reported once per
|
|
@@ -330,7 +327,17 @@ export interface ShellCaptureDescriptor {
|
|
|
330
327
|
debugSink?: (event: ShellCaptureDebugEvent) => void;
|
|
331
328
|
/** Store the snapshot for navigation replay, never the captured HTML prelude. */
|
|
332
329
|
navigationOnly?: true;
|
|
330
|
+
/**
|
|
331
|
+
* lastStoredCaptureSeq(key) when a document request read the store and
|
|
332
|
+
* missed. The request schedules its capture only after rendering the MISS,
|
|
333
|
+
* so a capture another request started can store in between; a later
|
|
334
|
+
* sequence number then skips the redundant one (`skip-stored`), which would
|
|
335
|
+
* re-render the page and drop the isolate's memo of the shell just stored.
|
|
336
|
+
*/
|
|
337
|
+
storedSeqAtRead?: number;
|
|
333
338
|
}
|
|
339
|
+
/** The latest stored capture's sequence number for `key` in this isolate, or 0. */
|
|
340
|
+
export declare function lastStoredCaptureSeq(key: string): number;
|
|
334
341
|
/**
|
|
335
342
|
* Schedule the background shell capture for a served document. Stampede-guarded:
|
|
336
343
|
* one capture per key per isolate. Runs via runBackground (waitUntil on workerd,
|
|
@@ -343,6 +350,26 @@ export interface ShellCaptureDescriptor {
|
|
|
343
350
|
* capture enters the guarded background queue, never on response latency.
|
|
344
351
|
*/
|
|
345
352
|
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;
|
|
353
|
+
/**
|
|
354
|
+
* The ttl/swr a shell is stored with: the route's ppr policy, capped by the
|
|
355
|
+
* route cache() records the capture replayed or wrote
|
|
356
|
+
* (RequestContext._routeRecordWindow). A HIT replays the capture's handler
|
|
357
|
+
* output, while a client navigation reads the route's cache() tier first, so
|
|
358
|
+
* a shell that outlived its record would show a document request other
|
|
359
|
+
* handler output than a navigation of the same URL. Freshness and total
|
|
360
|
+
* lifetime are capped separately, like the record's own SWR: the shell is
|
|
361
|
+
* fresh while the record is (at most `ttl`), and servable while the record
|
|
362
|
+
* is (at most `ttl + swr`), so a record already inside its swr window yields
|
|
363
|
+
* a shell that is stale from the start and serves while it recaptures.
|
|
364
|
+
*
|
|
365
|
+
* Whole seconds, rounded up (the SegmentCacheStore.putShell contract), so the
|
|
366
|
+
* shell may outlast the record by under a second. Null when the record's
|
|
367
|
+
* total lifetime has run out: the shell would be dead on arrival.
|
|
368
|
+
*/
|
|
369
|
+
export declare function capShellWindow(ttl: number, swr: number, record: Pick<RouteRecordWindow, "freshUntil" | "staleUntil">, now: number): {
|
|
370
|
+
ttl: number;
|
|
371
|
+
swr: number;
|
|
372
|
+
} | null;
|
|
346
373
|
/**
|
|
347
374
|
* The outcome of one capture attempt.
|
|
348
375
|
* - `stored`: a usable shell was captured (and a putShell was attempted; a store
|
|
@@ -350,18 +377,49 @@ export declare function scheduleShellCapture(ctx: HandlerContext<any>, request:
|
|
|
350
377
|
* the capture itself worked).
|
|
351
378
|
* - `redirect`: the matched route redirects, so there is no shell to capture.
|
|
352
379
|
* - `no-shell`: captureShellHTML returned null because the prelude was unusable
|
|
353
|
-
* or its private capture abort landed before the shell completed
|
|
354
|
-
*
|
|
380
|
+
* or its private capture abort landed before the shell completed, or the
|
|
381
|
+
* capture ran out of ppr.captureTimeout. Retried once in place, when no
|
|
382
|
+
* deadline ran out (CaptureAttemptStats.noShellCause).
|
|
383
|
+
* - `expired`: the route cache() record the capture read (not wrote) ran out
|
|
384
|
+
* before the store (capShellWindow null): it was near its end (its age,
|
|
385
|
+
* queue wait). Retried once in place, where a fresh match reads or renders
|
|
386
|
+
* a newer record; an `expired` retry, or no hard-cap budget left for the
|
|
387
|
+
* retry, is terminal `no-shell` (backoff, warned once per route).
|
|
388
|
+
*/
|
|
389
|
+
type CaptureAttemptOutcome = "stored" | "redirect" | "no-shell" | "refused" | "expired";
|
|
390
|
+
/**
|
|
391
|
+
* What a capture task ends with (runShellCapture): a refusal and a terminal
|
|
392
|
+
* `expired` are `no-shell`, which the scheduler backs off.
|
|
355
393
|
*/
|
|
356
|
-
type
|
|
394
|
+
type CaptureTaskOutcome = "stored" | "redirect" | "no-shell";
|
|
357
395
|
/**
|
|
358
|
-
*
|
|
359
|
-
* attemptCapture, the rest in captureAndStoreShell)
|
|
360
|
-
*
|
|
361
|
-
*
|
|
362
|
-
*
|
|
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.
|
|
363
402
|
*/
|
|
364
|
-
type CaptureAttemptStats = Pick<ShellCaptureDebugEvent, "barrierWaitMs" | "writeSettleMs" | "preludeBytes" | "snapshotBytes" | "snapshotSkipped" | "untaggedBake" | "storeWrite" | "
|
|
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
|
+
};
|
|
365
423
|
/**
|
|
366
424
|
* Run the shell capture with a single in-place retry, then store the result.
|
|
367
425
|
*
|
|
@@ -373,26 +431,84 @@ type CaptureAttemptStats = Pick<ShellCaptureDebugEvent, "barrierWaitMs" | "write
|
|
|
373
431
|
* when we froze the shell; the attempt itself warmed the module graph, so a second
|
|
374
432
|
* attempt a short beat later usually completes the shell in the SAME background
|
|
375
433
|
* task. That kills the old multi-request warmup where the caller had to re-issue
|
|
376
|
-
* several HTTP requests before a capture stuck. We retry ONLY on `no-shell
|
|
377
|
-
*
|
|
378
|
-
*
|
|
434
|
+
* several HTTP requests before a capture stuck. We retry ONLY on `no-shell`
|
|
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.
|
|
379
438
|
*
|
|
380
|
-
* `
|
|
381
|
-
*
|
|
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.
|
|
443
|
+
*/
|
|
444
|
+
declare function runShellCapture(ctx: HandlerContext<any>, request: Request, env: any, url: URL, reqCtx: RequestContext<any>, ssrModule: SSRModule, descriptor: ShellCaptureDescriptor, retryDelayMs?: number): Promise<CaptureTaskOutcome>;
|
|
445
|
+
/**
|
|
446
|
+
* What the record-first step produced ({@link settleCaptureRecord}):
|
|
447
|
+
* - `record`: the doc record settled; `match` carries its fragments in place
|
|
448
|
+
* of the handler layer's elements, so the capture's Flight payload is the
|
|
449
|
+
* bytes every HIT replays.
|
|
450
|
+
* - `prerender`: the prerender store supplied the handler layer (a
|
|
451
|
+
* Prerender route); its HIT tail replays the same build-time segments, so
|
|
452
|
+
* the capture renders the match as is.
|
|
453
|
+
* - `timeout`: handler output did not settle within the capture budget.
|
|
454
|
+
* - `refused`: a deterministic refusal (a capture guard tripped, the route
|
|
455
|
+
* opted out, or the handler output failed); the warning already fired.
|
|
382
456
|
*/
|
|
383
|
-
|
|
457
|
+
export type CaptureRecordOutcome = {
|
|
458
|
+
kind: "record" | "prerender";
|
|
459
|
+
match: MatchResult;
|
|
460
|
+
} | {
|
|
461
|
+
kind: "timeout";
|
|
462
|
+
reason: string;
|
|
463
|
+
} | {
|
|
464
|
+
kind: "refused";
|
|
465
|
+
};
|
|
466
|
+
/**
|
|
467
|
+
* Record-first capture: the doc record is both the settle signal and the
|
|
468
|
+
* parity source.
|
|
469
|
+
*
|
|
470
|
+
* Writing the record Flight-serializes every non-loader segment
|
|
471
|
+
* (serializeSegments), which runs each handler's async server components and
|
|
472
|
+
* waits for every promise the handler output carries — the capture's "is the
|
|
473
|
+
* handler layer done" signal. Live-lane loader data is not in the record
|
|
474
|
+
* (loader segments are excluded and their masked promises never settle), so
|
|
475
|
+
* the wait never depends on a hole.
|
|
476
|
+
*
|
|
477
|
+
* The capture then renders its OWN Flight payload from the record's
|
|
478
|
+
* fragments (fragmentSegments, the function a HIT tail uses) instead of from
|
|
479
|
+
* the elements the match produced. Server components therefore render once
|
|
480
|
+
* per capture, inside the record's encode: before this, the capture's Flight
|
|
481
|
+
* render and the record's encode each ran them, so an uncached async
|
|
482
|
+
* component showed one value in the prelude and another on every HIT.
|
|
483
|
+
*
|
|
484
|
+
* Order, all bounded by the one capture deadline (`ppr.captureTimeout`):
|
|
485
|
+
* top-level handle promises, the handler pushes' nested promises, and the
|
|
486
|
+
* bake-lane loader containers settle first (the record encodes the handles
|
|
487
|
+
* a HIT restores, and its handle encode has its own 5s timeout that must
|
|
488
|
+
* never be the one that fires); then the capture's onResponse callbacks fire
|
|
489
|
+
* with a synthetic 200 (the implicit doc scope's cacheRoute, an explicit
|
|
490
|
+
* scope's own write), and the deferred writes settle.
|
|
491
|
+
*/
|
|
492
|
+
export declare function settleCaptureRecord(match: MatchResult, derivation: CaptureContextDerivation, capture: Pick<ShellCaptureDescriptor, "key">, deadline: number): Promise<CaptureRecordOutcome>;
|
|
384
493
|
/**
|
|
385
494
|
* The derived capture context and its fresh (mask-funneled) handle store,
|
|
386
495
|
* shared by BOTH shell producers: the runtime background capture
|
|
387
496
|
* (attemptCapture, producer A) and the build-time prerender shell capture
|
|
388
497
|
* (prerender/build-shell-capture.ts, producer B — issue #699). One
|
|
389
|
-
* implementation so the capture semantics — the
|
|
390
|
-
*
|
|
391
|
-
* scope — cannot drift between producers.
|
|
498
|
+
* implementation so the capture semantics — the handle push funnel (handler
|
|
499
|
+
* pushes settled, loader pushes masked), the capture guards, snapshot
|
|
500
|
+
* recording, the implicit doc-cache scope — cannot drift between producers.
|
|
392
501
|
*/
|
|
393
502
|
export interface CaptureContextDerivation {
|
|
394
503
|
derivedCtx: RequestContext;
|
|
395
504
|
freshHandleStore: HandleStore;
|
|
505
|
+
/**
|
|
506
|
+
* Resolves once every handler handle push has settled at any depth of
|
|
507
|
+
* plain objects and arrays (top-level promise, then the promises nested
|
|
508
|
+
* in what it resolved to). The record-first step awaits it before the doc
|
|
509
|
+
* record encodes its handles, so that encode never races a pending value.
|
|
510
|
+
*/
|
|
511
|
+
handlerPushesSettled: () => Promise<void>;
|
|
396
512
|
}
|
|
397
513
|
/**
|
|
398
514
|
* Derive the capture request context from a base context. Producer A passes
|
|
@@ -407,19 +523,31 @@ export declare function deriveShellCaptureContext(reqCtx: RequestContext<any>, d
|
|
|
407
523
|
url: URL;
|
|
408
524
|
}): CaptureContextDerivation;
|
|
409
525
|
/**
|
|
410
|
-
*
|
|
411
|
-
* captureShellHTML, and store the result.
|
|
412
|
-
*
|
|
413
|
-
*
|
|
414
|
-
*
|
|
415
|
-
*
|
|
416
|
-
*
|
|
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).
|
|
417
537
|
*
|
|
418
538
|
* A `no-shell` result from captureShellHTML is the only retryable outcome. Every
|
|
419
539
|
* captureShellHTML error propagates to reportCacheError and is NOT retried. The
|
|
420
540
|
* capture handler converts only its own private abort sentinel to null before this
|
|
421
541
|
* layer sees it.
|
|
422
542
|
*/
|
|
423
|
-
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">>;
|
|
424
544
|
export { runShellCapture, captureAndStoreShell, delay, SHELL_CAPTURE_RETRY_DELAY_MS, };
|
|
425
545
|
export { isCaptureBackedOff, markCaptureBackoff, clearCaptureBackoff, REFUSED_CAPTURE_BASE_MS, REFUSED_CAPTURE_MAX_MS, REFUSED_CAPTURE_DEV_MAX_MS, };
|
|
546
|
+
/**
|
|
547
|
+
* @internal Reset this module's per-isolate state: the capture stampede
|
|
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.
|
|
552
|
+
*/
|
|
553
|
+
export declare function resetShellCaptureStateForTests(): void;
|