Spaces:
Sleeping
Sleeping
| import { PAGE_SEGMENT_KEY } from '../shared/lib/segment'; | |
| // TODO: We should only have to export `normalizeFlightData`, however because the initial flight data | |
| // that gets passed to `createInitialRouterState` doesn't conform to the `FlightDataPath` type (it's missing the root segment) | |
| // we're currently exporting it so we can use it directly. This should be fixed as part of the unification of | |
| // the different ways we express `FlightSegmentPath`. | |
| export function getFlightDataPartsFromPath(flightDataPath) { | |
| // Pick the last 4 items from the `FlightDataPath` to get the [tree, seedData, viewport, isHeadPartial]. | |
| const flightDataPathLength = 4; | |
| // tree, seedData, and head are *always* the last three items in the `FlightDataPath`. | |
| const [tree, seedData, head, isHeadPartial] = flightDataPath.slice(-flightDataPathLength); | |
| // The `FlightSegmentPath` is everything except the last three items. For a root render, it won't be present. | |
| const segmentPath = flightDataPath.slice(0, -flightDataPathLength); | |
| var _segmentPath_; | |
| return { | |
| // TODO: Unify these two segment path helpers. We are inconsistently pushing an empty segment ("") | |
| // to the start of the segment path in some places which makes it hard to use solely the segment path. | |
| // Look for "// TODO-APP: remove ''" in the codebase. | |
| pathToSegment: segmentPath.slice(0, -1), | |
| segmentPath, | |
| // if the `FlightDataPath` corresponds with the root, there'll be no segment path, | |
| // in which case we default to ''. | |
| segment: (_segmentPath_ = segmentPath[segmentPath.length - 1]) != null ? _segmentPath_ : '', | |
| tree, | |
| seedData, | |
| head, | |
| isHeadPartial, | |
| isRootRender: flightDataPath.length === flightDataPathLength | |
| }; | |
| } | |
| export function getNextFlightSegmentPath(flightSegmentPath) { | |
| // Since `FlightSegmentPath` is a repeated tuple of `Segment` and `ParallelRouteKey`, we slice off two items | |
| // to get the next segment path. | |
| return flightSegmentPath.slice(2); | |
| } | |
| export function normalizeFlightData(flightData) { | |
| // FlightData can be a string when the server didn't respond with a proper flight response, | |
| // or when a redirect happens, to signal to the client that it needs to perform an MPA navigation. | |
| if (typeof flightData === 'string') { | |
| return flightData; | |
| } | |
| return flightData.map((flightDataPath)=>getFlightDataPartsFromPath(flightDataPath)); | |
| } | |
| /** | |
| * This function is used to prepare the flight router state for the request. | |
| * It removes markers that are not needed by the server, and are purely used | |
| * for stashing state on the client. | |
| * @param flightRouterState - The flight router state to prepare. | |
| * @param isHmrRefresh - Whether this is an HMR refresh request. | |
| * @returns The prepared flight router state. | |
| */ export function prepareFlightRouterStateForRequest(flightRouterState, isHmrRefresh) { | |
| // HMR requests need the complete, unmodified state for proper functionality | |
| if (isHmrRefresh) { | |
| return encodeURIComponent(JSON.stringify(flightRouterState)); | |
| } | |
| return encodeURIComponent(JSON.stringify(stripClientOnlyDataFromFlightRouterState(flightRouterState))); | |
| } | |
| /** | |
| * Recursively strips client-only data from FlightRouterState while preserving | |
| * server-needed information for proper rendering decisions. | |
| */ function stripClientOnlyDataFromFlightRouterState(flightRouterState) { | |
| const [segment, parallelRoutes, _url, refreshMarker, isRootLayout, hasLoadingBoundary] = flightRouterState; | |
| // __PAGE__ segments are always fetched from the server, so there's | |
| // no need to send them up | |
| const cleanedSegment = stripSearchParamsFromPageSegment(segment); | |
| // Recursively process parallel routes | |
| const cleanedParallelRoutes = {}; | |
| for (const [key, childState] of Object.entries(parallelRoutes)){ | |
| cleanedParallelRoutes[key] = stripClientOnlyDataFromFlightRouterState(childState); | |
| } | |
| const result = [ | |
| cleanedSegment, | |
| cleanedParallelRoutes, | |
| null, | |
| shouldPreserveRefreshMarker(refreshMarker) ? refreshMarker : null | |
| ]; | |
| // Append optional fields if present | |
| if (isRootLayout !== undefined) { | |
| result[4] = isRootLayout; | |
| } | |
| if (hasLoadingBoundary !== undefined) { | |
| result[5] = hasLoadingBoundary; | |
| } | |
| return result; | |
| } | |
| /** | |
| * Strips search parameters from __PAGE__ segments to prevent sensitive | |
| * client-side data from being sent to the server. | |
| */ function stripSearchParamsFromPageSegment(segment) { | |
| if (typeof segment === 'string' && segment.startsWith(PAGE_SEGMENT_KEY + '?')) { | |
| return PAGE_SEGMENT_KEY; | |
| } | |
| return segment; | |
| } | |
| /** | |
| * Determines whether the refresh marker should be sent to the server | |
| * Client-only markers like 'refresh' are stripped, while server-needed markers | |
| * like 'refetch' and 'inside-shared-layout' are preserved. | |
| */ function shouldPreserveRefreshMarker(refreshMarker) { | |
| return Boolean(refreshMarker && refreshMarker !== 'refresh'); | |
| } | |
| //# sourceMappingURL=flight-data-helpers.js.map |