UNPKG

next

Version:

The React Framework

189 lines (188 loc) • 9.28 kB
import type { RenderOpts, PreloadCallbacks } from './types'; import type { ActionResult, DynamicParamTypesShort, DynamicSegmentTuple, FlightRouterState, CacheNodeSeedData } from '../../shared/lib/app-router-types'; import { type WorkStore } from '../app-render/work-async-storage.external'; import type { RequestStore } from '../app-render/work-unit-async-storage.external'; import type { NextParsedUrlQuery } from '../request-meta'; import type { LoaderTree } from '../lib/app-dir-module'; import type { AppPageModule } from '../route-modules/app-page/module'; import type { BaseNextRequest, BaseNextResponse } from '../base-http'; import RenderResult, { type AppPageRenderResultMetadata } from '../render-result'; import type { AnyStream } from './stream-ops'; import { type DevValidationWorkerMessage } from './dev-validation-worker-globals'; import { type ImplicitTags } from '../lib/implicit-tags'; import { parseRelativeUrl } from '../../shared/lib/router/utils/parse-relative-url'; import type { ServerComponentsHmrCache } from '../response-cache'; import { type OpaqueFallbackRouteParams } from '../request/fallback-params'; import type { Params } from '../request/params'; import type { StageEndTimes } from './instant-validation/instant-validation'; export type GetDynamicParamFromSegment = (loaderTree: LoaderTree) => DynamicParam | null; export type DynamicParam = { param: string; value: string | string[] | null; treeSegment: DynamicSegmentTuple; type: DynamicParamTypesShort; }; export type GenerateFlight = typeof generateDynamicFlightRenderResult; export type AppSharedContext = { buildId: string; deploymentId: string; clientAssetToken: string; }; export type AppRenderContext = { sharedContext: AppSharedContext; workStore: WorkStore; url: ReturnType<typeof parseRelativeUrl>; componentMod: AppPageModule; renderOpts: RenderOpts; parsedRequestHeaders: ParsedRequestHeaders; getDynamicParamFromSegment: GetDynamicParamFromSegment; interpolatedParams: Params; /** * The request's fallback route params (the same ones * `getDynamicParamFromSegment` closes over). Kept on the context so the dev * validation worker can rebuild an identical `getDynamicParamFromSegment`; * the depth-loop segment keys are derived from it, so it must match what * produced the seed render's Flight, not the separate fallback set validation * uses to mark params unknown in its stores. */ fallbackRouteParams: OpaqueFallbackRouteParams | null; query: NextParsedUrlQuery; isPrefetch: boolean; isPossibleServerAction: boolean; requestTimestamp: number; appUsingSizeAdjustment: boolean; flightRouterState?: FlightRouterState; requestId: string; htmlRequestId: string; pagePath: string; assetPrefix: string; isNotFoundPath: boolean; nonce: string | undefined; res: BaseNextResponse; /** * For now, the implicit tags are common for the whole route. If we ever start * rendering/revalidating segments independently, they need to move to the * work unit store. */ implicitTags: ImplicitTags; }; interface ParsedRequestHeaders { /** * Router state provided from the client-side router. Used to handle rendering * from the common layout down. This value will be undefined if the request is * not a client-side navigation request, or if the request is a prefetch * request. */ readonly flightRouterState: FlightRouterState | undefined; readonly isPrefetchRequest: boolean; readonly isRuntimePrefetchRequest: boolean; /** * App Shell prefetch: a runtime prefetch that the server renders with * params omitted (any `await params` hangs forever). Produces the * param-independent shell of the route. Implies isRuntimePrefetchRequest. */ readonly isAppShellPrefetchRequest: boolean; readonly isRouteTreePrefetchRequest: boolean; readonly isHmrRefresh: boolean; readonly isRSCRequest: boolean; readonly nonce: string | undefined; readonly previouslyRevalidatedTags: string[]; readonly requestId: string | undefined; readonly htmlRequestId: string | undefined; } /** * Produces a RenderResult containing the Flight data for the given request. See * `generateDynamicRSCPayload` for information on the contents of the render result. */ declare function generateDynamicFlightRenderResult(req: BaseNextRequest, ctx: AppRenderContext, requestStore: RequestStore, options?: { actionResult: ActionResult; skipPageRendering: boolean; componentTree?: CacheNodeSeedData; preloadCallbacks?: PreloadCallbacks; temporaryReferences?: WeakMap<any, string>; waitUntil?: Promise<unknown>; }): Promise<RenderResult>; export type BinaryStreamOf<T> = AnyStream; export type AppPageRender = (req: BaseNextRequest, res: BaseNextResponse, pagePath: string, query: NextParsedUrlQuery, fallbackRouteParams: OpaqueFallbackRouteParams | null, renderOpts: RenderOpts, serverComponentsHmrCache: ServerComponentsHmrCache | undefined, sharedContext: AppSharedContext) => Promise<RenderResult<AppPageRenderResultMetadata>>; export declare const renderToHTMLOrFlight: AppPageRender; /** * A staged dev render interrupted by sync IO. It has no artifacts that could be * used as validation inputs, only the reason it was interrupted. */ interface SyncInterruptedStagedDevRender { readonly syncInterruptReason: Error; } /** * The chunks and per-stage timings a staged dev render accumulates once its * stream finishes. A render only produces them when it runs to the end without * a sync-IO interrupt, so they back both a render's uninterrupted outcome and * the validation inputs. */ interface StagedDevRenderArtifacts { readonly accumulatedChunks: AccumulatedStreamChunks; readonly startTime: number; readonly stageEndTimes: StageEndTimes; } /** * What `runValidationInDev` consumes: an uninterrupted render's artifacts plus * the request store and the debug channel. Carries no `syncInterruptReason`: * the resolution step has already surfaced and bailed on any sync interrupt. */ export interface ResolvedValidationInputs extends StagedDevRenderArtifacts { readonly requestStore: RequestStore; readonly debugChannelClient: AnyStream | undefined; } /** * The inputs produced for validation, before resolution: either an * uninterrupted render's artifacts (`ResolvedValidationInputs`) or, for a * render interrupted by sync IO, only the interrupt reason. An interrupted * render is never validated, so it carries nothing else: its debug channel is * dropped at construction. Discriminate with `'syncInterruptReason' in x`; the * resolution step surfaces and bails on the interrupted case, so the depth loop * only ever sees `ResolvedValidationInputs`. */ export type DevValidationInputs = ResolvedValidationInputs | SyncInterruptedStagedDevRender; export declare enum PrefetchingMode { LegacySpeculative = 1, Partial = 2 } interface AccumulatedStreamChunks { readonly shellStaticChunks: Array<Uint8Array>; readonly staticChunks: Array<Uint8Array>; readonly shellRuntimeChunks: Array<Uint8Array>; readonly runtimeChunks: Array<Uint8Array>; readonly dynamicChunks: Array<Uint8Array>; } /** * The slice of the render context the dev/build validation passes read. Both * the in-process callers and the validation worker build one of these, so it * names exactly what validation depends on and nothing else: no live * request/response objects that can't be rebuilt off the main thread. * `isDebugChannelEnabled` is the derived flag validation uses in place of the * main render's `setReactDebugChannel` callback (validation only ever read that * callback's presence as a boolean). */ export type ValidationRenderContext = Pick<AppRenderContext, 'componentMod' | 'getDynamicParamFromSegment' | 'query' | 'implicitTags' | 'nonce' | 'workStore'> & { renderOpts: Pick<RenderOpts, 'images' | 'allowEmptyStaticShell'>; isDebugChannelEnabled: boolean; }; /** * Projects a full app render context down to the slice validation reads. The * in-process dev and build callers hold an `AppRenderContext` and use this to * hand validation exactly what it needs; the worker builds the same shape from * its snapshot instead. */ export declare function toValidationRenderContext(ctx: AppRenderContext): ValidationRenderContext; /** * Worker entry point for Cached Components dev validation, reached from the * validation worker via `ComponentMod.routeModule.runValidationInDev`. The * worker reloads the route's compiled module and calls this so the entire * validation (Flight re-encodes and the client prerenders) runs inside the * app-page bundle's single React instance, alongside the user's client * components. It rebuilds the render context, work store, and request store * from the transported snapshot (the live objects can't cross a thread) and * returns the validation errors for the worker to serialize and the main thread * to deliver. */ export declare function runValidationInDevFromSnapshot(message: DevValidationWorkerMessage, componentMod: AppPageModule, abortSignal: AbortSignal): Promise<Array<unknown> | undefined>; export {};