@rangojs/router 0.25.0 → 0.26.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/rango.js +1 -1
- package/dist/types/cache/cf/cf-cache-store.d.ts +0 -2
- package/dist/types/cache/cf/cf-cache-types.d.ts +0 -16
- package/dist/types/cache/handle-snapshot.d.ts +2 -2
- package/dist/types/cache/shell-snapshot.d.ts +6 -4
- package/dist/types/cache/types.d.ts +8 -6
- package/dist/types/cache/vercel/vercel-cache-store.d.ts +1 -15
- package/dist/types/handles/deferred-resolution.d.ts +3 -2
- package/dist/types/handles/meta.d.ts +5 -0
- package/dist/types/prerender/build-shell-capture.d.ts +1 -2
- package/dist/types/prerender/writable-store.d.ts +2 -3
- package/dist/types/router/dev-reload-handoff.d.ts +26 -0
- package/dist/types/router/router-interfaces.d.ts +0 -5
- package/dist/types/router/router-options.d.ts +0 -20
- package/dist/types/router/segment-resolution/mask-nested.d.ts +5 -3
- package/dist/types/router-versions.d.ts +8 -6
- package/dist/types/rsc/shell-capture-constants.d.ts +10 -6
- package/dist/types/rsc/shell-capture.d.ts +25 -8
- package/dist/types/rsc/types.d.ts +0 -8
- package/dist/types/server/build-version-table.d.ts +10 -13
- package/dist/types/server/context.d.ts +26 -2
- package/dist/types/server/handle-store.d.ts +17 -6
- package/dist/types/server/request-context.d.ts +4 -3
- package/dist/types/testing/build-versions.d.ts +0 -3
- package/dist/types/testing/internal/seed-vars.d.ts +4 -4
- package/dist/types/testing/serve-shell-request.d.ts +1 -1
- package/dist/types/types/loader-types.d.ts +6 -1
- package/dist/types/urls/pattern-types.d.ts +7 -6
- package/dist/vite/index.js +3 -8
- package/package.json +1 -1
- package/skills/cache-guide/SKILL.md +4 -8
- package/skills/caching/SKILL.md +3 -5
- package/skills/comparison/references/framework-comparison.md +1 -1
- package/skills/hooks/handle-and-actions.md +6 -6
- package/skills/host-router/SKILL.md +1 -1
- package/skills/loader/SKILL.md +10 -9
- package/skills/ppr/SKILL.md +83 -60
- package/skills/prerender/SKILL.md +3 -3
- package/skills/router-setup/SKILL.md +0 -2
- package/skills/testing/render-handler.md +17 -17
- package/skills/testing/serve-shell-request.md +1 -1
- package/skills/testing/server-actions.md +16 -16
- package/skills/vercel/SKILL.md +1 -1
- package/src/cache/cf/cf-cache-store.ts +4 -7
- package/src/cache/cf/cf-cache-types.ts +0 -17
- package/src/cache/handle-snapshot.ts +2 -2
- package/src/cache/shell-snapshot.ts +7 -3
- package/src/cache/types.ts +8 -6
- package/src/cache/vercel/vercel-cache-store.ts +2 -18
- package/src/handles/deferred-resolution.ts +3 -2
- package/src/handles/meta.ts +5 -0
- package/src/prerender/build-shell-capture.ts +1 -2
- package/src/prerender/writable-store.ts +2 -3
- package/src/route-definition/dsl-helpers.ts +14 -14
- package/src/router/dev-reload-handoff.ts +73 -0
- package/src/router/manifest.ts +9 -2
- package/src/router/match-middleware/intercept-resolution.ts +2 -2
- package/src/router/router-interfaces.ts +0 -6
- package/src/router/router-options.ts +0 -21
- package/src/router/segment-resolution/loader-cache.ts +4 -3
- package/src/router/segment-resolution/mask-nested.ts +5 -3
- package/src/router-versions.ts +7 -7
- package/src/router.ts +19 -8
- package/src/rsc/handler.ts +3 -7
- package/src/rsc/rsc-rendering.ts +44 -12
- package/src/rsc/shell-capture-constants.ts +10 -6
- package/src/rsc/shell-capture.ts +163 -88
- package/src/rsc/types.ts +0 -9
- package/src/server/build-version-table.ts +12 -24
- package/src/server/context.ts +64 -2
- package/src/server/handle-store.ts +77 -10
- package/src/server/request-context.ts +4 -3
- package/src/testing/build-versions.ts +0 -3
- package/src/testing/dispatch.ts +1 -3
- package/src/testing/internal/seed-vars.ts +4 -4
- package/src/testing/serve-shell-request.ts +2 -5
- package/src/types/loader-types.ts +6 -1
- package/src/urls/pattern-types.ts +7 -6
- package/src/vite/discovery/shell-prerender-phase.ts +1 -5
package/dist/bin/rango.js
CHANGED
|
@@ -1644,7 +1644,7 @@ var init_package = __esm({
|
|
|
1644
1644
|
"package.json"() {
|
|
1645
1645
|
package_default = {
|
|
1646
1646
|
name: "@rangojs/router",
|
|
1647
|
-
version: "0.
|
|
1647
|
+
version: "0.26.1",
|
|
1648
1648
|
description: "Django-inspired RSC router with composable URL patterns",
|
|
1649
1649
|
keywords: [
|
|
1650
1650
|
"react",
|
|
@@ -21,8 +21,6 @@ export declare class CFCacheStore<TEnv = unknown> implements SegmentCacheStore<T
|
|
|
21
21
|
private readonly namespace?;
|
|
22
22
|
private readonly explicitBaseUrl?;
|
|
23
23
|
private readonly waitUntil?;
|
|
24
|
-
/** The `version` option: used for every versioned family when set. */
|
|
25
|
-
private readonly explicitVersion?;
|
|
26
24
|
private readonly edgeLookupTimeoutMs;
|
|
27
25
|
private readonly edgeReadTimeoutMs;
|
|
28
26
|
private readonly kvReadTimeoutMs;
|
|
@@ -278,22 +278,6 @@ export interface CFCacheStoreOptions<TEnv = unknown> {
|
|
|
278
278
|
* (safe to set large) rather than the invalidation-latency ceiling.
|
|
279
279
|
*/
|
|
280
280
|
tagCacheTtl?: number;
|
|
281
|
-
/**
|
|
282
|
-
* Cache version string override. When set, this exact value prefixes every
|
|
283
|
-
* versioned key the store writes (`v/{version}/...`), for cached data and
|
|
284
|
-
* stored HTML alike; changing it makes every earlier entry unreachable.
|
|
285
|
-
*
|
|
286
|
-
* Leave it unset for the default: the store keys with the versions of the
|
|
287
|
-
* router serving the request. Segment entries and `"use cache"` items use
|
|
288
|
-
* the router's data version; document responses and PPR shells use its
|
|
289
|
-
* document version (see `createRouter({ version })`). Those are computed
|
|
290
|
-
* from the router's built code, so a deploy that does not change the router
|
|
291
|
-
* keeps its entries.
|
|
292
|
-
*
|
|
293
|
-
* Tag invalidation markers are never versioned: an invalidation applies to
|
|
294
|
-
* the entries of every version, including one that comes back in a rollback.
|
|
295
|
-
*/
|
|
296
|
-
version?: string;
|
|
297
281
|
/**
|
|
298
282
|
* Latency budget (ms) for an L1 edge cache (CF Cache API) read. A `match`
|
|
299
283
|
* slower than this is abandoned and treated as a miss, so a degraded colo
|
|
@@ -73,8 +73,8 @@ export type OwnedPushDelivery = (loaderId: string) => RecordAuthority;
|
|
|
73
73
|
* says the record supplies that loader's value too ("pin", "copies"), and is
|
|
74
74
|
* a placeholder (pushPlaceholder) everywhere else: without `owned`, every
|
|
75
75
|
* owner. Neither claims its loader, so the loader's own cache() HIT still
|
|
76
|
-
* delivers (the
|
|
77
|
-
* pushes in a placeholder's place).
|
|
76
|
+
* delivers (the pushes holding a promise a restored copy lets through, or its
|
|
77
|
+
* entry's pushes in a placeholder's place).
|
|
78
78
|
*/
|
|
79
79
|
export declare function restoreHandles(handles: Record<string, SegmentHandleData>, handleStore: HandleStore, owners?: HandleOwners, owned?: OwnedPushDelivery): void;
|
|
80
80
|
/**
|
|
@@ -199,11 +199,13 @@ export interface ShellLoaderSeedEntry {
|
|
|
199
199
|
* by loader. A key that does not parse pins nothing.
|
|
200
200
|
*
|
|
201
201
|
* Deserializations run in parallel; a record that fails to decode is skipped
|
|
202
|
-
*
|
|
203
|
-
* HIT
|
|
204
|
-
*
|
|
202
|
+
* and reported to `onUndecodable`: its loader runs instead, which a document
|
|
203
|
+
* HIT has already committed a prelude against, so serveShellHit retires the
|
|
204
|
+
* entry (dc-t89). Returns undefined when the snapshot carries no loader
|
|
205
|
+
* records, without touching the Flight codec (kept lazy for cold paths and
|
|
206
|
+
* non-RSC configs).
|
|
205
207
|
*/
|
|
206
|
-
export declare function buildShellLoaderSeed(snapshot: ShellSnapshotRecord[]): Promise<Map<string, ShellLoaderSeedEntry> | undefined>;
|
|
208
|
+
export declare function buildShellLoaderSeed(snapshot: ShellSnapshotRecord[], onUndecodable?: (key: string) => void): Promise<Map<string, ShellLoaderSeedEntry> | undefined>;
|
|
207
209
|
/** The key of a snapshot's one `handles` record (ShellSnapshotHandlesValue). */
|
|
208
210
|
export declare const SHELL_HANDLES_RECORD_KEY = "handles";
|
|
209
211
|
/**
|
|
@@ -389,7 +389,7 @@ export interface ShellCacheEntry {
|
|
|
389
389
|
/** React.version captured at prerender time; the read-time invalidation gate. */
|
|
390
390
|
reactVersion: string;
|
|
391
391
|
/**
|
|
392
|
-
* Build version captured at prerender time: the RSC handler's
|
|
392
|
+
* Build version captured at prerender time: the RSC handler's version,
|
|
393
393
|
* which is the router's DOCUMENT version (router-versions.ts) — a hash of
|
|
394
394
|
* its server code and the client asset names by default, a stamp bumped on
|
|
395
395
|
* dev RSC-module edits. The second read-time gate: a persistent shared
|
|
@@ -625,11 +625,13 @@ export interface ShellSnapshotLoaderValue {
|
|
|
625
625
|
*/
|
|
626
626
|
holes: 0 | 1;
|
|
627
627
|
/**
|
|
628
|
-
* 1 when the capture saw a loader push it could not record (
|
|
629
|
-
*
|
|
630
|
-
* body): a HIT then still runs the loader
|
|
631
|
-
* (pin-first) so those pushes reach the page.
|
|
632
|
-
*
|
|
628
|
+
* 1 when the capture saw a loader push it could not record (one whose
|
|
629
|
+
* settled value holds masked nested promises, one a live-lane loader made,
|
|
630
|
+
* or one made outside any loader body): a HIT then still runs the loader
|
|
631
|
+
* body in the background (pin-first) so those pushes reach the page. A
|
|
632
|
+
* pushed promise that settles thenable-free is recorded (#1182).
|
|
633
|
+
* 0: a hole-free record is served from the pin alone and its body does not
|
|
634
|
+
* run on a HIT.
|
|
633
635
|
*
|
|
634
636
|
* Both bits are always written. A record stored before they existed (v0.17)
|
|
635
637
|
* reads each missing bit as 1 (buildShellLoaderSeed): its snapshot lacks
|
|
@@ -102,7 +102,7 @@ export interface VercelCacheStoreOptions<TEnv = unknown> {
|
|
|
102
102
|
*
|
|
103
103
|
* Vercel does not reconcile entries between deployments; the store does it
|
|
104
104
|
* through its keys, which carry the serving router's cache versions (see
|
|
105
|
-
* `
|
|
105
|
+
* `getCacheVersions`). So a deploy that changes a router's code stops reading that
|
|
106
106
|
* router's old entries, and a deploy that does not keeps them. A namespace
|
|
107
107
|
* that changes per deployment (`getCache({ namespace: VERCEL_DEPLOYMENT_ID })`)
|
|
108
108
|
* still works and clears the cache on every deploy, which is what you want
|
|
@@ -128,18 +128,6 @@ export interface VercelCacheStoreOptions<TEnv = unknown> {
|
|
|
128
128
|
* segmentation). Receives the request context and the default key.
|
|
129
129
|
*/
|
|
130
130
|
keyGenerator?: (ctx: RequestContext<TEnv>, defaultKey: string) => string | Promise<string>;
|
|
131
|
-
/**
|
|
132
|
-
* Version override, folded into every versioned key as `v/{version}/...`.
|
|
133
|
-
* When set, this exact value is used for cached data and stored HTML alike;
|
|
134
|
-
* changing it makes everything this store wrote before unreachable.
|
|
135
|
-
*
|
|
136
|
-
* Leave it unset for the default: the store keys with the versions of the
|
|
137
|
-
* router serving the request, as CFCacheStore does. Segments and `"use
|
|
138
|
-
* cache"` items use the router's data version; responses and PPR shells use
|
|
139
|
-
* its document version (see `createRouter({ version })`). Tag markers are
|
|
140
|
-
* never versioned, so an invalidation applies to every version.
|
|
141
|
-
*/
|
|
142
|
-
version?: string;
|
|
143
131
|
/**
|
|
144
132
|
* Max serialized entry size in bytes before a write is skipped. Defaults to
|
|
145
133
|
* VERCEL_MAX_ITEM_BYTES (2 MB - the platform's hard cap).
|
|
@@ -238,8 +226,6 @@ export declare class VercelCacheStore<TEnv = unknown> implements SegmentCacheSto
|
|
|
238
226
|
readonly keyGenerator?: (ctx: RequestContext<TEnv>, defaultKey: string) => string | Promise<string>;
|
|
239
227
|
private readonly cache;
|
|
240
228
|
private readonly waitUntil?;
|
|
241
|
-
/** The `version` option: used for every versioned family when set. */
|
|
242
|
-
private readonly explicitVersion?;
|
|
243
229
|
private readonly maxItemBytes;
|
|
244
230
|
private readonly memo;
|
|
245
231
|
private readonly handleMemos;
|
|
@@ -48,8 +48,9 @@ export declare function resolveDeferredHandleValues(data: HandleData): Promise<H
|
|
|
48
48
|
* so a push the record leaves out must not be in the prelude either: it
|
|
49
49
|
* rendered an element no HIT's hydration data matched (issue #1035). Which
|
|
50
50
|
* pushes a record keeps is the capture funnel's decision (shell-capture.ts
|
|
51
|
-
* deriveShellCaptureContext:
|
|
52
|
-
*
|
|
51
|
+
* deriveShellCaptureContext: it leaves out a loader push whose settled value
|
|
52
|
+
* holds a masked promise, and one a live-lane loader made), not this
|
|
53
|
+
* function's.
|
|
53
54
|
*/
|
|
54
55
|
export declare function resolvedHandleStream(handleStore: HandleStore, recordedOnly?: boolean): AsyncGenerator<HandleData, void, unknown>;
|
|
55
56
|
/**
|
|
@@ -39,5 +39,10 @@ import type { MetaDescriptor } from "../router/types.js";
|
|
|
39
39
|
* (resolve-by-default), so they participate in deduplication and `%s`
|
|
40
40
|
* title-templating identically to synchronous descriptors. A descriptor that
|
|
41
41
|
* resolves to `null`/`undefined` (or rejects) is dropped.
|
|
42
|
+
*
|
|
43
|
+
* On a ppr route, a descriptor a handler or an `ssr: false` loader pushes,
|
|
44
|
+
* promise or not, is in the shell's `<head>` on every HIT (#1182). One a
|
|
45
|
+
* loader without `ssr: false` pushes is live: on a HIT it arrives after
|
|
46
|
+
* hydration.
|
|
42
47
|
*/
|
|
43
48
|
export declare const Meta: Handle<MetaDescriptor, MetaDescriptor[]>;
|
|
@@ -68,8 +68,7 @@ export interface BuildShellCaptureOptions {
|
|
|
68
68
|
/** Build-time env bindings (rango plugin buildEnv), if configured. */
|
|
69
69
|
buildEnv?: unknown;
|
|
70
70
|
/**
|
|
71
|
-
* The versions the SHIPPED build serves this router with (the build table
|
|
72
|
-
* or the router's consumer-set version) — NOT the temp server's own
|
|
71
|
+
* The versions the SHIPPED build serves this router with (the build table) — NOT the temp server's own
|
|
73
72
|
* version-plugin stamp. The serve-side isValidShellHit gate compares
|
|
74
73
|
* entry.buildVersion against the running worker's ctx.version, which is the
|
|
75
74
|
* document version; stamping the temp server's would make every build entry
|
|
@@ -19,9 +19,8 @@ import type { PrerenderEntry } from "./store.js";
|
|
|
19
19
|
export interface PrerenderKey {
|
|
20
20
|
routerId: string;
|
|
21
21
|
/**
|
|
22
|
-
* The owning router's cache version (its data version
|
|
23
|
-
*
|
|
24
|
-
* store keys off it as given.
|
|
22
|
+
* The owning router's cache version (its data version). Opaque: never set
|
|
23
|
+
* or read by app code; a store keys off it as given.
|
|
25
24
|
*/
|
|
26
25
|
version: string;
|
|
27
26
|
routeName: string;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { RangoInternal } from "./router-interfaces.js";
|
|
2
|
+
/** The `import.meta.hot` subset this reads. */
|
|
3
|
+
interface RunnerReloadEvents {
|
|
4
|
+
on(event: "vite:beforeFullReload", listener: () => void): void;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Mark this module copy dropped on the runner's next full reload.
|
|
8
|
+
* @internal
|
|
9
|
+
*/
|
|
10
|
+
export declare function watchRunnerReloads(events: RunnerReloadEvents | undefined): void;
|
|
11
|
+
/**
|
|
12
|
+
* Whether a runner full reload dropped this module copy.
|
|
13
|
+
* @internal
|
|
14
|
+
*/
|
|
15
|
+
export declare function droppedByRunnerReload(): boolean;
|
|
16
|
+
/**
|
|
17
|
+
* The router the reload re-created for `routerId`, or undefined when none
|
|
18
|
+
* registered within DEV_RECREATED_ROUTER_WAIT_MS. Importing `sourceFile`
|
|
19
|
+
* evaluates it when nothing else is. While the reload's re-import is still
|
|
20
|
+
* evaluating it, the runner returns the unfinished module (it is in this
|
|
21
|
+
* copy's import call stack, `cachedRequest` in vite's module-runner), so this
|
|
22
|
+
* waits for the fresh registry to receive the router.
|
|
23
|
+
* @internal
|
|
24
|
+
*/
|
|
25
|
+
export declare function routerAfterRunnerReload(routerId: string, sourceFile: string | undefined): Promise<RangoInternal<any, any> | undefined>;
|
|
26
|
+
export {};
|
|
@@ -378,11 +378,6 @@ export interface RangoInternal<TEnv = any, TRoutes extends Record<string, unknow
|
|
|
378
378
|
* Nonce provider for CSP
|
|
379
379
|
*/
|
|
380
380
|
readonly nonce?: NonceProvider<TEnv>;
|
|
381
|
-
/**
|
|
382
|
-
* The consumer-set version (createRouter({ version })), used for both of the
|
|
383
|
-
* router's versions. Undefined when the router uses its build versions.
|
|
384
|
-
*/
|
|
385
|
-
readonly version?: string;
|
|
386
381
|
/**
|
|
387
382
|
* URL patterns reference for build-time manifest generation
|
|
388
383
|
*/
|
|
@@ -489,26 +489,6 @@ export interface RangoOptions<TEnv = any> {
|
|
|
489
489
|
* ```
|
|
490
490
|
*/
|
|
491
491
|
nonce?: NonceProvider<TEnv>;
|
|
492
|
-
/**
|
|
493
|
-
* Version override. When set, this exact value is used for both of the
|
|
494
|
-
* router's versions: it keys the router's cached data (segments, `"use
|
|
495
|
-
* cache"` values, loader data) and its stored HTML (PPR shells,
|
|
496
|
-
* document-cache responses), is sent in payload metadata, and is what the
|
|
497
|
-
* browser's `_rsc_v` is compared with (a mismatch reloads the tab).
|
|
498
|
-
*
|
|
499
|
-
* Leave it unset for the default: rango computes two versions per router at
|
|
500
|
-
* build time, a data version from the router's server code and a document
|
|
501
|
-
* version that also covers the client assets. The same code builds to the
|
|
502
|
-
* same versions, so a deploy that does not change this router keeps its
|
|
503
|
-
* cache. In dev both are a stamp bumped on every RSC module edit.
|
|
504
|
-
*
|
|
505
|
-
* Set it to clear this router's cache on demand (change the value), or to
|
|
506
|
-
* tie the cache to your own release id (a per-deploy value clears the cache
|
|
507
|
-
* on every deploy).
|
|
508
|
-
*
|
|
509
|
-
* @default the router's build versions
|
|
510
|
-
*/
|
|
511
|
-
version?: string;
|
|
512
492
|
/**
|
|
513
493
|
* TTL (in seconds) for the client-side in-memory prefetch cache.
|
|
514
494
|
*
|
|
@@ -59,9 +59,11 @@ export declare function settleNestedThenables(value: unknown): Promise<void>;
|
|
|
59
59
|
/**
|
|
60
60
|
* True when `value` is a thenable or holds one where the capture's loader
|
|
61
61
|
* push funnel masks it (maskNestedContainerThenables): through plain data
|
|
62
|
-
* objects, arrays and React element props.
|
|
63
|
-
* record and reaches a HIT only from a run of its
|
|
64
|
-
* keeps it; a push without one is the record's
|
|
62
|
+
* objects, arrays and React element props. A settled push that holds one
|
|
63
|
+
* stays out of a shell's record and reaches a HIT only from a run of its
|
|
64
|
+
* loader there, so a HIT keeps it; a push without one is the record's
|
|
65
|
+
* (HandleStore.pushRestored). A top-level thenable is judged by the value it
|
|
66
|
+
* settles to, on both sides (#1182).
|
|
65
67
|
*/
|
|
66
68
|
export declare function holdsThenable(value: unknown): boolean;
|
|
67
69
|
/**
|
|
@@ -27,13 +27,15 @@ export interface RouterVersions {
|
|
|
27
27
|
export type RouterVersionsTable = Readonly<Record<string, readonly [data: string, document: string]>>;
|
|
28
28
|
/** Table key of the whole-build versions. Not a legal `$$id` (8 hex chars). */
|
|
29
29
|
export declare const DEFAULT_ROUTER_VERSIONS_KEY = "*";
|
|
30
|
-
/**
|
|
30
|
+
/**
|
|
31
|
+
* One value for both versions: the dev stamp, the version a build-time shell
|
|
32
|
+
* capture is asked for, or a test's seed.
|
|
33
|
+
*/
|
|
31
34
|
export declare function uniformVersions(version: string): RouterVersions;
|
|
32
35
|
/**
|
|
33
|
-
* The versions a router serves with under `table`:
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
* tests) or it has neither entry. One function for the request handler and
|
|
36
|
+
* The versions a router serves with under `table`: the router's own entry,
|
|
37
|
+
* else the whole-build pair, for a router the table does not list.
|
|
38
|
+
* `undefined` when there is no table (dev, tests) or it has neither entry. One function for the request handler and
|
|
37
39
|
* the build's shell capture, which must stamp what the handler will check.
|
|
38
40
|
*/
|
|
39
|
-
export declare function resolveVersionsFrom(table: RouterVersionsTable | undefined, routerId: string | undefined
|
|
41
|
+
export declare function resolveVersionsFrom(table: RouterVersionsTable | undefined, routerId: string | undefined): RouterVersions | undefined;
|
|
@@ -148,13 +148,17 @@ export declare const SHELL_CAPTURE_TASK_HARD_CAP_MS = 25000;
|
|
|
148
148
|
* (ShellCaptureDebugEvent.refusal, `caches.refusal` on a `router.prerender()`
|
|
149
149
|
* result): `identity` (a request-scoped read: cookies(), headers(), the
|
|
150
150
|
* theme, a `{ cache: false }` variable), `dynamic` (`ctx.dynamic()`),
|
|
151
|
-
* `loader` (a `{ ssr: false }` loader rejected,
|
|
152
|
-
* redirect()/notFound()
|
|
153
|
-
*
|
|
151
|
+
* `loader` (a `{ ssr: false }` loader rejected, settled with
|
|
152
|
+
* redirect()/notFound(), or a promise it pushed rejected),
|
|
153
|
+
* `no-record` (no doc record: the route's cache() refused the write, or the
|
|
154
|
+
* handler output failed), `handles` (a pushed
|
|
154
155
|
* handle value did not finish encoding), `size` (over the store's value
|
|
155
|
-
* limit
|
|
156
|
-
*
|
|
157
|
-
*
|
|
156
|
+
* limit, or `ssr: false` loader pins over `ppr.maxSnapshotBytes`: a
|
|
157
|
+
* navigation-only entry was stored in place of the document shell),
|
|
158
|
+
* `record-expired` (the route cache() record
|
|
159
|
+
* the capture wrote ran out first), `invalidated` (a tag of the shell was
|
|
160
|
+
* invalidated after the capture started), `uncacheable` (the store cannot
|
|
161
|
+
* hold the entry).
|
|
158
162
|
*/
|
|
159
163
|
export type ShellCaptureRefusal = "identity" | "dynamic" | "loader" | "no-record" | "handles" | "size" | "record-expired" | "invalidated" | "uncacheable";
|
|
160
164
|
/**
|
|
@@ -105,9 +105,8 @@ export declare const DEFAULT_SHELL_ENTRY_MAX_BYTES: number;
|
|
|
105
105
|
* while still fitting any sane pinned-ring payload. Applied ONLY in
|
|
106
106
|
* captureAndStoreShell (the single defaulting site — resolvePprConfig passes
|
|
107
107
|
* the option through undefaulted), so every producer and direct caller gets
|
|
108
|
-
* the same policy. The doc record is exempt; over the cap the
|
|
109
|
-
*
|
|
110
|
-
* live store — see PartialPrerenderProps.maxSnapshotBytes).
|
|
108
|
+
* the same policy. The doc record is exempt; over the cap only the
|
|
109
|
+
* navigation half is stored (see PartialPrerenderProps.maxSnapshotBytes).
|
|
111
110
|
*/
|
|
112
111
|
export declare const DEFAULT_PPR_MAX_SNAPSHOT_BYTES: number;
|
|
113
112
|
/**
|
|
@@ -165,7 +164,11 @@ export interface ShellCaptureDebugEvent {
|
|
|
165
164
|
preludeBytes?: number;
|
|
166
165
|
/** Serialized snapshot size in UTF-8 bytes. Absent when nothing was recorded. */
|
|
167
166
|
snapshotBytes?: number;
|
|
168
|
-
/**
|
|
167
|
+
/**
|
|
168
|
+
* True when the loader pins exceeded maxSnapshotBytes: no document shell
|
|
169
|
+
* was stored, only a navigation-only entry (the doc record, or a tombstone
|
|
170
|
+
* for a prerender-served capture). The outcome is `refused`, refusal `size`.
|
|
171
|
+
*/
|
|
169
172
|
snapshotSkipped?: boolean;
|
|
170
173
|
/** A bake-lane loader settled into a shell that uses TTL/SWR-only invalidation. */
|
|
171
174
|
untaggedBake?: true;
|
|
@@ -315,8 +318,8 @@ export interface ShellCaptureDescriptor {
|
|
|
315
318
|
captureTimeout?: number;
|
|
316
319
|
store?: SegmentCacheStore<any>;
|
|
317
320
|
/**
|
|
318
|
-
* Cap (serialized UTF-8 bytes) on the entry's
|
|
319
|
-
*
|
|
321
|
+
* Cap (serialized UTF-8 bytes) on the entry's loader pins; over it only the
|
|
322
|
+
* navigation half is stored and the attempt refuses (reported once per
|
|
320
323
|
* key). Absent = DEFAULT_PPR_MAX_SNAPSHOT_BYTES, applied in
|
|
321
324
|
* captureAndStoreShell — the single defaulting site.
|
|
322
325
|
*/
|
|
@@ -502,8 +505,9 @@ export type CaptureRecordOutcome = {
|
|
|
502
505
|
* component showed one value in the prelude and another on every HIT.
|
|
503
506
|
*
|
|
504
507
|
* Order, all bounded by the one capture deadline (`ppr.captureTimeout`):
|
|
505
|
-
* top-level handle promises
|
|
506
|
-
*
|
|
508
|
+
* top-level handle promises (a bake-lane loader's pushed promises among
|
|
509
|
+
* them, #1182), the handler pushes' nested promises, and the bake-lane
|
|
510
|
+
* loader containers settle first (the record encodes the handles
|
|
507
511
|
* a HIT restores, and its handle encode has its own 5s timeout that must
|
|
508
512
|
* never be the one that fires); then the capture's onResponse callbacks fire
|
|
509
513
|
* with a synthetic 200 (the implicit doc scope's cacheRoute, an explicit
|
|
@@ -529,6 +533,19 @@ export interface CaptureContextDerivation {
|
|
|
529
533
|
* record encodes its handles, so that encode never races a pending value.
|
|
530
534
|
*/
|
|
531
535
|
handlerPushesSettled: () => Promise<void>;
|
|
536
|
+
/**
|
|
537
|
+
* Every promise a bake-lane loader body pushed (#1182), in push order.
|
|
538
|
+
* The record-first step waits for them (they are in the recorded cut) and
|
|
539
|
+
* names the loader and the handle of one that rejects or misses the
|
|
540
|
+
* deadline.
|
|
541
|
+
*/
|
|
542
|
+
loaderPromisePushes: readonly LoaderPromisePush[];
|
|
543
|
+
}
|
|
544
|
+
/** A promise a bake-lane loader pushed at capture, owned by that loader. */
|
|
545
|
+
export interface LoaderPromisePush {
|
|
546
|
+
loaderId: string;
|
|
547
|
+
handleName: string;
|
|
548
|
+
state: "pending" | "fulfilled" | "rejected";
|
|
532
549
|
}
|
|
533
550
|
/**
|
|
534
551
|
* Derive the capture request context from a base context. Producer A passes
|
|
@@ -333,14 +333,6 @@ export interface CreateRSCHandlerOptions<TEnv = unknown, TRoutes extends Record<
|
|
|
333
333
|
* ```
|
|
334
334
|
*/
|
|
335
335
|
cache?: HandlerCacheConfig | ((env: TEnv) => HandlerCacheConfig);
|
|
336
|
-
/**
|
|
337
|
-
* Version override for this handler. Same meaning as
|
|
338
|
-
* `createRouter({ version })`, which it takes precedence over: this exact
|
|
339
|
-
* value is used for both of the router's versions.
|
|
340
|
-
*
|
|
341
|
-
* @default createRouter({ version }), else the router's build versions
|
|
342
|
-
*/
|
|
343
|
-
version?: string;
|
|
344
336
|
/**
|
|
345
337
|
* Nonce provider for Content Security Policy (CSP).
|
|
346
338
|
*
|
|
@@ -2,21 +2,18 @@ import { type RouterVersions, type RouterVersionsTable } from "../router-version
|
|
|
2
2
|
/**
|
|
3
3
|
* The versions a router serves with, in order:
|
|
4
4
|
*
|
|
5
|
-
* 1.
|
|
6
|
-
*
|
|
7
|
-
* 2. The router's entry in the build table, else the whole-build entry.
|
|
8
|
-
* 3. `VERSION` for both: the dev stamp, bumped on every RSC module edit.
|
|
5
|
+
* 1. The router's entry in the build table, else the whole-build entry.
|
|
6
|
+
* 2. `VERSION` for both: the dev stamp, bumped on every RSC module edit.
|
|
9
7
|
*/
|
|
10
|
-
export declare function resolveRouterVersions(routerId: string | undefined
|
|
8
|
+
export declare function resolveRouterVersions(routerId: string | undefined): RouterVersions;
|
|
11
9
|
/**
|
|
12
10
|
* The version an on-demand prerender overlay key carries: the router's data
|
|
13
11
|
* version, because the overlay stores segment data, as the segment cache does
|
|
14
12
|
* (a client-only deploy keeps both). The write side (`router.prerender`,
|
|
15
|
-
* router.ts) and the read side (rsc/handler.ts) both call this
|
|
16
|
-
*
|
|
17
|
-
* cannot disagree; a `createRSCHandler({ version })` does not move it.
|
|
13
|
+
* router.ts) and the read side (rsc/handler.ts) both call this, so they
|
|
14
|
+
* cannot disagree.
|
|
18
15
|
*/
|
|
19
|
-
export declare function resolvePrerenderVersion(routerId: string | undefined
|
|
16
|
+
export declare function resolvePrerenderVersion(routerId: string | undefined): string;
|
|
20
17
|
/**
|
|
21
18
|
* The versions of the router serving the current request, for a cache store
|
|
22
19
|
* building a key. A store operation with no request context (a detached task
|
|
@@ -40,11 +37,11 @@ export declare function getCacheVersions(): RouterVersions;
|
|
|
40
37
|
export type KeyVersion = keyof RouterVersions | null;
|
|
41
38
|
/**
|
|
42
39
|
* The `v/{version}/` prefix of a persistent store key, or "" for an
|
|
43
|
-
* unversioned one.
|
|
44
|
-
*
|
|
45
|
-
*
|
|
40
|
+
* unversioned one. The version is the serving router's, read per operation
|
|
41
|
+
* because the cache factory builds the store before the request context
|
|
42
|
+
* exists.
|
|
46
43
|
*/
|
|
47
|
-
export declare function versionKeyPrefix(
|
|
44
|
+
export declare function versionKeyPrefix(kind: KeyVersion): string;
|
|
48
45
|
/**
|
|
49
46
|
* @internal Install a table, or restore the build's with `undefined`. A
|
|
50
47
|
* request handler resolves its router's versions once, when it is created, so
|
|
@@ -97,6 +97,11 @@ export type EntryPropRender = {
|
|
|
97
97
|
* on both DSL evaluations, whatever `ssr` did to `loading`.
|
|
98
98
|
*/
|
|
99
99
|
loadingPrefetch?: false;
|
|
100
|
+
/**
|
|
101
|
+
* loading(fallback, { ssr: false }), on both DSL evaluations; a document
|
|
102
|
+
* then sets `loading` to false (applyDocumentModeLoading).
|
|
103
|
+
*/
|
|
104
|
+
loadingSsr?: false;
|
|
100
105
|
transition?: TransitionConfig;
|
|
101
106
|
};
|
|
102
107
|
/**
|
|
@@ -117,7 +122,8 @@ export type LoaderEntry = {
|
|
|
117
122
|
* Resolved at DSL-evaluation time from ctx.isSSR — entries are cached
|
|
118
123
|
* per-isSSR (router/manifest.ts cache key), so the flag is already
|
|
119
124
|
* request-mode-correct when resolveLoaders (fresh.ts) reads it and never
|
|
120
|
-
* appears on navigation-lane entries.
|
|
125
|
+
* appears on navigation-lane entries. Set by documentModeLoader, which
|
|
126
|
+
* getDocumentModeEntry also applies to a lazy include's captured ancestors.
|
|
121
127
|
*/
|
|
122
128
|
awaitBeforeFlush?: true;
|
|
123
129
|
/**
|
|
@@ -325,7 +331,8 @@ interface HelperContext extends IncludeScopePosition {
|
|
|
325
331
|
* different routers don't clobber each other (route-map-builder.ts). */
|
|
326
332
|
routerId?: string;
|
|
327
333
|
metrics?: MetricsStore;
|
|
328
|
-
/** True when rendering for SSR (document requests)
|
|
334
|
+
/** True when rendering for SSR (document requests). DSL decisions on it
|
|
335
|
+
* go through the document-mode helpers (documentModeLoader). */
|
|
329
336
|
isSSR?: boolean;
|
|
330
337
|
/** URL patterns map for path() routes (route name -> pattern) */
|
|
331
338
|
patterns?: Map<string, string>;
|
|
@@ -479,6 +486,23 @@ export type { HelperContext };
|
|
|
479
486
|
* parent pointer, handler) stays shared, which is correct and cheap.
|
|
480
487
|
*/
|
|
481
488
|
export declare function getIsolatedLazyParent(captured: EntryData | null | undefined): EntryData | null;
|
|
489
|
+
/** loader(Def, { ssr: false }): a document awaits it before the first flush. */
|
|
490
|
+
export declare function documentModeLoader(entry: LoaderEntry): LoaderEntry;
|
|
491
|
+
/** loading(fallback, { ssr: false }): a document renders no fallback. */
|
|
492
|
+
export declare function applyDocumentModeLoading(entry: EntryPropRender): void;
|
|
493
|
+
/**
|
|
494
|
+
* `entry`, its ancestors, orphan layouts and parallels as a document (isSSR)
|
|
495
|
+
* DSL evaluation builds them, from an evaluation without isSSR.
|
|
496
|
+
*
|
|
497
|
+
* include() captures its parent chain on router.ts routes() or
|
|
498
|
+
* lazy-includes.ts runExpansion, neither of which has isSSR, and loadManifest
|
|
499
|
+
* reuses it for every request. Handed to a document as is, every ancestor
|
|
500
|
+
* outside the include kept its navigation-mode decisions (#1179). Intercepts
|
|
501
|
+
* stay as they are: a document never resolves one.
|
|
502
|
+
*
|
|
503
|
+
* Memoized per entry, so an ancestor several includes share maps to one copy.
|
|
504
|
+
*/
|
|
505
|
+
export declare function getDocumentModeEntry(entry: EntryData): EntryData;
|
|
482
506
|
export declare function getParallelEntries(parallels: ParallelEntries | EntryData[] | undefined): ParallelEntryData[];
|
|
483
507
|
export declare function getParallelSlotEntries(parallels: ParallelEntries | EntryData[] | undefined): Array<{
|
|
484
508
|
slot: `@${string}`;
|
|
@@ -123,12 +123,14 @@ export interface HandleStore {
|
|
|
123
123
|
*/
|
|
124
124
|
pushPlaceholder(handleName: string, segmentId: string, data: unknown, loaderId: string): void;
|
|
125
125
|
/**
|
|
126
|
-
* push() a record's copy of `loaderId`'s
|
|
127
|
-
*
|
|
128
|
-
*
|
|
129
|
-
*
|
|
130
|
-
*
|
|
131
|
-
*
|
|
126
|
+
* push() a record's copy of `loaderId`'s push that stands (restoreHandles):
|
|
127
|
+
* the record supplies the loader's value too. From then on this request
|
|
128
|
+
* drops every thenable-free push the loader makes (live, or replayed from
|
|
129
|
+
* a cache entry, anywhere inside its body), and keeps the ones holding a
|
|
130
|
+
* thenable (holdsThenable: what the record could not keep), placed among
|
|
131
|
+
* the restored copies in the loader's push order. A top-level promise is
|
|
132
|
+
* judged by its settled value, as the capture judged it (#1182): dropped
|
|
133
|
+
* when it settles thenable-free or rejects, else kept once it settles.
|
|
132
134
|
*/
|
|
133
135
|
pushRestored(handleName: string, segmentId: string, data: unknown, loaderId: string): void;
|
|
134
136
|
/**
|
|
@@ -140,6 +142,15 @@ export interface HandleStore {
|
|
|
140
142
|
* takes a push made inside a hole it awaited.
|
|
141
143
|
*/
|
|
142
144
|
setRecordAuthority(authority: (loaderId: string) => RecordAuthority): void;
|
|
145
|
+
/**
|
|
146
|
+
* Capture only (shell-capture.ts deriveShellCaptureContext): the slot
|
|
147
|
+
* holding `value` becomes a DSL-loader push without an owner, so the
|
|
148
|
+
* record and the prelude leave it out (getDataForSegment's
|
|
149
|
+
* `excludeLoaderPushes`). The capture owns a bake-lane loader's promise
|
|
150
|
+
* when it is pushed, and calls this once the promise settled to a value
|
|
151
|
+
* that holds one (#1182).
|
|
152
|
+
*/
|
|
153
|
+
unrecordPush(handleName: string, segmentId: string, value: unknown): void;
|
|
143
154
|
/**
|
|
144
155
|
* `loaderId`'s run in this request settled (resolved or rejected), its
|
|
145
156
|
* pushes made (loader-resolution.ts createLoaderExecutor). Its placeholders
|
|
@@ -264,9 +264,10 @@ export interface RequestContext<TEnv = DefaultEnv, TParams = Record<string, stri
|
|
|
264
264
|
_shellCaptureLoaderRecords?: Map<string, Promise<unknown>>;
|
|
265
265
|
/**
|
|
266
266
|
* @internal Set on a capture's derived context when a loader pushed a
|
|
267
|
-
* value the record cannot keep (
|
|
268
|
-
*
|
|
269
|
-
* `runs: 1`, so a HIT still
|
|
267
|
+
* value the record cannot keep (masked nested promises, a pushed promise
|
|
268
|
+
* that settled to one, a live-lane loader's push, or a push outside a
|
|
269
|
+
* loader body): the loader records then carry `runs: 1`, so a HIT still
|
|
270
|
+
* runs their bodies for those pushes.
|
|
270
271
|
*/
|
|
271
272
|
_shellCaptureUnrecordedLoaderPush?: true;
|
|
272
273
|
/**
|
|
@@ -15,9 +15,6 @@ export interface BuildVersions extends RouterVersions {
|
|
|
15
15
|
* Install the cache versions of a simulated build, or remove them with no
|
|
16
16
|
* argument (routers serve unversioned again, the default in tests).
|
|
17
17
|
*
|
|
18
|
-
* A router that sets `createRouter({ version })` keeps that value for both
|
|
19
|
-
* versions, exactly as in production.
|
|
20
|
-
*
|
|
21
18
|
* @example A deploy that changes the client only keeps cached data
|
|
22
19
|
* ```ts
|
|
23
20
|
* setBuildVersions({ data: "d1", document: "h1" });
|
|
@@ -21,10 +21,10 @@ export interface StateCookieSeed {
|
|
|
21
21
|
*/
|
|
22
22
|
routerId?: string;
|
|
23
23
|
/**
|
|
24
|
-
* The app's version
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
24
|
+
* The app's version: the rotated value's prefix (`{version}:{timestamp}`)
|
|
25
|
+
* and the request's cache versions, which a store keys with. Defaults to
|
|
26
|
+
* `"0"` for the prefix (resolved inside createRequestContext) and to the
|
|
27
|
+
* build versions for the store.
|
|
28
28
|
*/
|
|
29
29
|
version?: string;
|
|
30
30
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* serveShellRequest — one request through the production PPR serve path.
|
|
3
3
|
*
|
|
4
4
|
* Builds the router's request handler as `router.fetch` does
|
|
5
|
-
* (`createRSCHandler` with the router's `nonce
|
|
5
|
+
* (`createRSCHandler` with the router's `nonce` and `cache`
|
|
6
6
|
* config) and serves one GET through it, so middleware, the shell serve path
|
|
7
7
|
* and a MISS's background capture all run production code, on real Flight
|
|
8
8
|
* (the vendored react-server-dom serializer). The call settles every
|
|
@@ -164,7 +164,12 @@ export type LoaderFn<T, TParams = Record<string, string | undefined>, TEnv = Def
|
|
|
164
164
|
* deterministically precedes Response construction, where the streamed
|
|
165
165
|
* default only wins that race opportunistically). Under ppr it is also the
|
|
166
166
|
* BAKE lane: the loader executes at shell capture and its settled return is
|
|
167
|
-
* shell material (nested promises stay live holes)
|
|
167
|
+
* shell material (nested promises stay live holes), and so are its handle
|
|
168
|
+
* pushes, a pushed promise or `.defer()` included: the capture awaits it and
|
|
169
|
+
* every HIT serves the value it settled to (#1182). A pushed promise that
|
|
170
|
+
* rejects, or misses `ppr.captureTimeout`, keeps the route on MISS. A value
|
|
171
|
+
* that must stay per request belongs to a loader without `ssr: false` — see
|
|
172
|
+
* the ppr docs.
|
|
168
173
|
*
|
|
169
174
|
* Scoped per LOADER, not per segment: an `ssr: false` loader alongside a
|
|
170
175
|
* deliberately streaming sibling awaits only itself, and the sibling keeps
|