120 lines
5.7 KiB
TypeScript
120 lines
5.7 KiB
TypeScript
import type { InitialRSCPayload, Segment } from '../../../shared/lib/app-router-types';
|
|
import { RenderStage } from '../staged-rendering';
|
|
import type { ValidationBoundaryTracking } from './boundary-tracking';
|
|
import { type LoaderTree } from '../../lib/app-dir-module';
|
|
import type { GetDynamicParamFromSegment } from '../app-render';
|
|
import type { Instant } from '../../../build/segment-config/app/app-segment-config';
|
|
import { Readable } from 'node:stream';
|
|
import type { NextParsedUrlQuery } from '../../request-meta';
|
|
type ClientReferenceManifest = Record<string, any>;
|
|
/** Used to identify a segment. Conceptually similar to request keys in the Client Segment Cache. */
|
|
export type SegmentPath = string & {
|
|
_tag: 'SegmentPath';
|
|
};
|
|
/**
|
|
* Isomorphic to a FlightRouterState, but with extra data attached.
|
|
* Carries the segment path for each segment so we can easily get it from the cache.
|
|
* */
|
|
export type RouteTree = {
|
|
path: SegmentPath;
|
|
segment: Segment;
|
|
module: null | {
|
|
type: 'layout' | 'page';
|
|
instantConfig: Instant | null;
|
|
conventionPath: string;
|
|
createInstantStack: (() => Error) | null;
|
|
};
|
|
slots: {
|
|
[parallelRouteKey: string]: RouteTree;
|
|
} | null;
|
|
};
|
|
export type SegmentStage = RenderStage.Static | RenderStage.Runtime | RenderStage.Dynamic;
|
|
export type StageChunks = Record<SegmentStage, Uint8Array[]>;
|
|
export type StageEndTimes = {
|
|
[RenderStage.Static]: number;
|
|
[RenderStage.Runtime]: number;
|
|
};
|
|
/**
|
|
* Splits an existing staged stream (represented as arrays of chunks)
|
|
* into separate staged streams (also in arrays-of-chunks form), one for each segment.
|
|
* */
|
|
export declare function collectStagedSegmentData(fullPageChunks: StageChunks, fullPageDebugChunks: Uint8Array[] | null, startTime: number, hasRuntimePrefetch: boolean, clientReferenceManifest: ClientReferenceManifest): Promise<{
|
|
cache: SegmentCache;
|
|
payload: InitialRSCPayload;
|
|
stageEndTimes: StageEndTimes;
|
|
}>;
|
|
/**
|
|
* Creates a late-release stream for a given payload.
|
|
* When `renderSignal` is triggered, the stream will release late chunks
|
|
* to provide extra debug info.
|
|
* */
|
|
export declare function createCombinedPayloadStream(payload: InitialRSCPayload, extraChunksAbortController: AbortController, renderSignal: AbortSignal, clientReferenceManifest: ClientReferenceManifest, startTime: number, isDebugChannelEnabled: boolean): Promise<{
|
|
stream: Readable;
|
|
debugStream: Readable | null;
|
|
}>;
|
|
export type SegmentCache = {
|
|
head: SegmentCacheItem | null;
|
|
segments: Map<SegmentPath, SegmentCacheItem>;
|
|
};
|
|
type SegmentCacheItem = {
|
|
chunks: StageChunks;
|
|
debugChunks: Uint8Array[] | null;
|
|
};
|
|
/**
|
|
* Walks the LoaderTree to discover validation depth bounds.
|
|
*
|
|
* Each route group between URL segments represents a potential
|
|
* shared/new boundary in a client navigation. When a user navigates
|
|
* between sibling routes that share a route group layout, that
|
|
* layout is already mounted — its Suspense boundaries are revealed
|
|
* and don't cover new content below. By tracking the max group
|
|
* depth at each URL depth, we can iterate all possible group
|
|
* boundaries and validate that blocking code is always covered by
|
|
* Suspense in the new tree. This is conservative: some boundaries
|
|
* may not correspond to real navigations (e.g. a route group with
|
|
* no siblings), but it ensures we don't miss real violations.
|
|
*
|
|
* The max is taken across all parallel slots. When slots have
|
|
* different numbers of groups, the deepest slot determines the
|
|
* iteration range. Shallower slots simply stay entirely shared
|
|
* at group depths beyond their own group count — they run out
|
|
* of groups before reaching the boundary, so their content
|
|
* remains in the Dynamic stage.
|
|
*
|
|
* Returns an array where:
|
|
* - length = max URL depth (number of URL-consuming segments)
|
|
* - array[i] = max group depth at URL depth i (number of route group
|
|
* segments between this URL depth and the next)
|
|
*
|
|
* For example, a tree like:
|
|
* '' / (outer) / (inner) / dashboard / page
|
|
* returns [2, 0] — URL depth 0 (root) has 2 group layers before
|
|
* the next URL segment (dashboard), and URL depth 1 (dashboard) has
|
|
* 0 group layers before the leaf.
|
|
*/
|
|
export declare function discoverValidationDepths(loaderTree: LoaderTree): number[];
|
|
/**
|
|
* Builds a combined RSC payload for validation at a given URL depth.
|
|
*
|
|
* Walks the LoaderTree directly, loading modules and counting
|
|
* URL-contributing layouts. When `depth` URL segments have been
|
|
* consumed, the boundary flips from shared (dynamic stage) to new
|
|
* (static/runtime stage). As the new subtree is built, we check for
|
|
* instant configs. If none are found, returns null — no validation
|
|
* needed at this depth or deeper.
|
|
*
|
|
* This combines module loading, tree walking, config discovery, and
|
|
* payload construction into a single pass.
|
|
*/
|
|
export type ValidationPayloadResult = {
|
|
payload: InitialRSCPayload;
|
|
/** Whether errors from this payload could be ambiguous between runtime
|
|
* API access (cookies, headers) and uncached IO (connection, fetch).
|
|
* True when some segments used Static stage. False when all segments
|
|
* used Runtime stage and errors are definitively from uncached IO. */
|
|
hasAmbiguousErrors: boolean;
|
|
createInstantStack: (() => Error) | null;
|
|
};
|
|
export declare function createCombinedPayloadAtDepth(initialRSCPayload: InitialRSCPayload, cache: SegmentCache, initialLoaderTree: LoaderTree, getDynamicParamFromSegment: GetDynamicParamFromSegment, query: NextParsedUrlQuery | null, depth: number, groupDepth: number, releaseSignal: AbortSignal, boundaryState: ValidationBoundaryTracking, clientReferenceManifest: ClientReferenceManifest, stageEndTimes: StageEndTimes, useRuntimeStageForPartialSegments: boolean): Promise<ValidationPayloadResult | null>;
|
|
export {};
|