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 {};
