next
Version:
The React Framework
195 lines (194 loc) • 7.26 kB
TypeScript
/**
* App Router types - Client-safe types for the Next.js App Router
*
* This file contains type definitions that can be safely imported
* by both client-side and server-side code without circular dependencies.
*/
import type React from 'react';
export type LoadingModuleData = [React.JSX.Element, React.ReactNode, React.ReactNode] | null;
/** viewport metadata node */
export type HeadData = React.ReactNode;
export type ChildSegmentMap = Map<string, CacheNode>;
/**
* Cache node used in app-router / layout-router.
*/
export type CacheNode = {
/**
* When rsc is not null, it represents the RSC data for the
* corresponding segment.
*
* `null` is a valid React Node but because segment data is always a
* <LayoutRouter> component, we can use `null` to represent empty. When it is
* null, it represents missing data, and rendering should suspend.
*/
rsc: React.ReactNode;
/**
* Represents a static version of the segment that can be shown immediately,
* and may or may not contain dynamic holes. It's prefetched before a
* navigation occurs.
*
* During rendering, we will choose whether to render `rsc` or `prefetchRsc`
* with `useDeferredValue`. As with the `rsc` field, a value of `null` means
* no value was provided. In this case, the LayoutRouter will go straight to
* rendering the `rsc` value; if that one is also missing, it will suspend and
* trigger a lazy fetch.
*/
prefetchRsc: React.ReactNode;
prefetchHead: HeadData | null;
head: HeadData;
loading: LoadingModuleData | Promise<LoadingModuleData>;
parallelRoutes: Map<string, ChildSegmentMap>;
/**
* The timestamp of the navigation that last updated the CacheNode's data. If
* a CacheNode is reused from a previous navigation, this value is not
* updated. Used to track the staleness of the data.
*/
navigatedAt: number;
};
export type DynamicParamTypes = 'catchall' | 'catchall-intercepted-(..)(..)' | 'catchall-intercepted-(.)' | 'catchall-intercepted-(..)' | 'catchall-intercepted-(...)' | 'optional-catchall' | 'dynamic' | 'dynamic-intercepted-(..)(..)' | 'dynamic-intercepted-(.)' | 'dynamic-intercepted-(..)' | 'dynamic-intercepted-(...)';
export type DynamicParamTypesShort = 'c' | 'ci(..)(..)' | 'ci(.)' | 'ci(..)' | 'ci(...)' | 'oc' | 'd' | 'di(..)(..)' | 'di(.)' | 'di(..)' | 'di(...)';
export type Segment = string | [
paramName: string,
paramCacheKey: string,
dynamicParamType: DynamicParamTypesShort
];
/**
* Router state
*/
export type FlightRouterState = [
segment: Segment,
parallelRoutes: {
[parallelRouterKey: string]: FlightRouterState;
},
url?: string | null,
/**
* "refresh" and "refetch", despite being similarly named, have different
* semantics:
* - "refetch" is used during a request to inform the server where rendering
* should start from.
*
* - "refresh" is used by the client to mark that a segment should re-fetch the
* data from the server for the current segment. It uses the "url" property
* above to determine where to fetch from.
*
* - "inside-shared-layout" is used during a prefetch request to inform the
* server that even if the segment matches, it should be treated as if it's
* within the "new" part of a navigation — inside the shared layout. If
* the segment doesn't match, then it has no effect, since it would be
* treated as new regardless. If it does match, though, the server does not
* need to render it, because the client already has it.
*
* - "metadata-only" instructs the server to skip rendering the segments and
* only send the head data.
*
* A bit confusing, but that's because it has only one extremely narrow use
* case — during a non-PPR prefetch, the server uses it to find the first
* loading boundary beneath a shared layout.
*
* TODO: We should rethink the protocol for dynamic requests. It might not
* make sense for the client to send a FlightRouterState, since this type is
* overloaded with concerns.
*/
refresh?: 'refetch' | 'refresh' | 'inside-shared-layout' | 'metadata-only' | null,
isRootLayout?: boolean,
/**
* Only present when responding to a tree prefetch request. Indicates whether
* there is a loading boundary somewhere in the tree. The client cache uses
* this to determine if it can skip the data prefetch request.
*/
hasLoadingBoundary?: HasLoadingBoundary
];
export declare const enum HasLoadingBoundary {
SegmentHasLoadingBoundary = 1,
SubtreeHasLoadingBoundary = 2,
SubtreeHasNoLoadingBoundary = 3
}
/**
* Individual Flight response path
*/
export type FlightSegmentPath = any[] | [
segment: Segment,
parallelRouterKey: string,
segment: Segment,
parallelRouterKey: string,
segment: Segment,
parallelRouterKey: string
];
/**
* Represents a tree of segments and the Flight data (i.e. React nodes) that
* correspond to each one. The tree is isomorphic to the FlightRouterState;
* however in the future we want to be able to fetch arbitrary partial segments
* without having to fetch all its children. So this response format will
* likely change.
*/
export type CacheNodeSeedData = [
node: React.ReactNode | null,
parallelRoutes: {
[parallelRouterKey: string]: CacheNodeSeedData | null;
},
loading: LoadingModuleData | Promise<LoadingModuleData>,
isPartial: boolean,
/** TODO: this doesn't feel like it belongs here, because it's only used during build, in `collectSegmentData` */
hasRuntimePrefetch: boolean
];
export type FlightDataSegment = [
Segment,
FlightRouterState,
CacheNodeSeedData | null,
HeadData,
boolean
];
export type FlightDataPath = any[] | [
...FlightSegmentPath[],
...FlightDataSegment
];
/**
* The Flight response data
*/
export type FlightData = Array<FlightDataPath> | string;
export type ActionResult = Promise<any>;
export type InitialRSCPayload = {
/** buildId */
b: string;
/** initialCanonicalUrlParts */
c: string[];
/** initialRenderedSearch */
q: string;
/** couldBeIntercepted */
i: boolean;
/** initialFlightData */
f: FlightDataPath[];
/** missingSlots */
m: Set<string> | undefined;
/** GlobalError */
G: [React.ComponentType<any>, React.ReactNode | undefined];
/** prerendered */
S: boolean;
};
export type NavigationFlightResponse = {
/** buildId */
b: string;
/** flightData */
f: FlightData;
/** prerendered */
S: boolean;
/** renderedSearch */
q: string;
/** couldBeIntercepted */
i: boolean;
/** runtimePrefetch - [isPartial, staleTime]. Only present in runtime prefetch responses. */
rp?: [boolean, number];
};
export type ActionFlightResponse = {
/** actionResult */
a: ActionResult;
/** buildId */
b: string;
/** flightData */
f: FlightData;
/** renderedSearch */
q: string;
/** couldBeIntercepted */
i: boolean;
};
export type RSCPayload = InitialRSCPayload | NavigationFlightResponse | ActionFlightResponse;