{"version":3,"sources":["../../../src/server/app-render/walk-tree-with-flight-router-state.tsx"],"sourcesContent":["import type {\n  FlightDataPath,\n  FlightDataSegment,\n  FlightRouterState,\n  PreloadCallbacks,\n  Segment,\n} from './types'\nimport { matchSegment } from '../../client/components/match-segments'\nimport type { LoaderTree } from '../lib/app-dir-module'\nimport { getLinkAndScriptTags } from './get-css-inlined-link-tags'\nimport { getPreloadableFonts } from './get-preloadable-fonts'\nimport {\n  createFlightRouterStateFromLoaderTree,\n  createRouteTreePrefetch,\n} from './create-flight-router-state-from-loader-tree'\nimport type { AppRenderContext } from './app-render'\nimport { hasLoadingComponentInTree } from './has-loading-component-in-tree'\nimport {\n  DEFAULT_SEGMENT_KEY,\n  addSearchParamsIfPageSegment,\n} from '../../shared/lib/segment'\nimport { createComponentTree } from './create-component-tree'\nimport type { HeadData } from '../../shared/lib/app-router-context.shared-runtime'\nimport { getSegmentParam } from './get-segment-param'\n\n/**\n * Use router state to decide at what common layout to render the page.\n * This can either be the common layout between two pages or a specific place to start rendering from using the \"refetch\" marker in the tree.\n */\nexport async function walkTreeWithFlightRouterState({\n  loaderTreeToFilter,\n  parentParams,\n  flightRouterState,\n  parentIsInsideSharedLayout,\n  rscHead,\n  injectedCSS,\n  injectedJS,\n  injectedFontPreloadTags,\n  rootLayoutIncluded,\n  getViewportReady,\n  getMetadataReady,\n  ctx,\n  preloadCallbacks,\n  StreamingMetadataOutlet,\n}: {\n  loaderTreeToFilter: LoaderTree\n  parentParams: { [key: string]: string | string[] }\n  flightRouterState?: FlightRouterState\n  rscHead: HeadData\n  parentIsInsideSharedLayout?: boolean\n  injectedCSS: Set<string>\n  injectedJS: Set<string>\n  injectedFontPreloadTags: Set<string>\n  rootLayoutIncluded: boolean\n  getMetadataReady: () => Promise<void>\n  getViewportReady: () => Promise<void>\n  ctx: AppRenderContext\n  preloadCallbacks: PreloadCallbacks\n  StreamingMetadataOutlet: React.ComponentType | null\n}): Promise<FlightDataPath[]> {\n  const {\n    renderOpts: { nextFontManifest, experimental },\n    query,\n    isPrefetch,\n    getDynamicParamFromSegment,\n    parsedRequestHeaders,\n  } = ctx\n\n  const [segment, parallelRoutes, modules] = loaderTreeToFilter\n\n  const parallelRoutesKeys = Object.keys(parallelRoutes)\n\n  const { layout } = modules\n  const isLayout = typeof layout !== 'undefined'\n\n  /**\n   * Checks if the current segment is a root layout.\n   */\n  const rootLayoutAtThisLevel = isLayout && !rootLayoutIncluded\n  /**\n   * Checks if the current segment or any level above it has a root layout.\n   */\n  const rootLayoutIncludedAtThisLevelOrAbove =\n    rootLayoutIncluded || rootLayoutAtThisLevel\n\n  // Because this function walks to a deeper point in the tree to start rendering we have to track the dynamic parameters up to the point where rendering starts\n  const segmentParam = getDynamicParamFromSegment(segment)\n  const currentParams =\n    // Handle null case where dynamic param is optional\n    segmentParam && segmentParam.value !== null\n      ? {\n          ...parentParams,\n          [segmentParam.param]: segmentParam.value,\n        }\n      : parentParams\n  const actualSegment: Segment = addSearchParamsIfPageSegment(\n    segmentParam ? segmentParam.treeSegment : segment,\n    query\n  )\n\n  /**\n   * Decide if the current segment is where rendering has to start.\n   */\n  const renderComponentsOnThisLevel =\n    // No further router state available\n    !flightRouterState ||\n    // Segment in router state does not match current segment\n    !matchSegment(actualSegment, flightRouterState[0]) ||\n    // Last item in the tree\n    parallelRoutesKeys.length === 0 ||\n    // Explicit refresh\n    flightRouterState[3] === 'refetch'\n\n  // Pre-PPR, the `loading` component signals to the router how deep to render the component tree\n  // to ensure prefetches are quick and inexpensive. If there's no `loading` component anywhere in the tree being rendered,\n  // the prefetch will be short-circuited to avoid requesting a potentially very expensive subtree. If there's a `loading`\n  // somewhere in the tree, we'll recursively render the component tree up until we encounter that loading component, and then stop.\n\n  // Check if we're inside the \"new\" part of the navigation — inside the\n  // shared layout. In the case of a prefetch, this can be true even if the\n  // segment matches, because the client might send a matching segment to\n  // indicate that it already has the data in its cache. But in order to find\n  // the correct loading boundary, we still need to track where the shared\n  // layout begins.\n  //\n  // TODO: We should rethink the protocol for dynamic requests. It might not\n  // make sense for the client to send a FlightRouterState, since that type is\n  // overloaded with other concerns.\n  const isInsideSharedLayout =\n    renderComponentsOnThisLevel ||\n    parentIsInsideSharedLayout ||\n    flightRouterState[3] === 'inside-shared-layout'\n\n  if (\n    isInsideSharedLayout &&\n    !experimental.isRoutePPREnabled &&\n    // If PPR is disabled, and this is a request for the route tree, then we\n    // never render any components. Only send the router state.\n    (parsedRequestHeaders.isRouteTreePrefetchRequest ||\n      // Otherwise, check for the presence of a `loading` component.\n      (isPrefetch &&\n        !Boolean(modules.loading) &&\n        !hasLoadingComponentInTree(loaderTreeToFilter)))\n  ) {\n    // Send only the router state.\n    // TODO: Even for a dynamic route, we should cache these responses,\n    // because they do not contain any render data (neither segment data nor\n    // the head). They can be made even more cacheable once we move the route\n    // params into a separate data structure.\n    const overriddenSegment =\n      flightRouterState &&\n      // TODO: Why does canSegmentBeOverridden exist? Why don't we always just\n      // use `actualSegment`? Is it to avoid overwriting some state that's\n      // tracked by the client? Dig deeper to see if we can simplify this.\n      canSegmentBeOverridden(actualSegment, flightRouterState[0])\n        ? flightRouterState[0]\n        : actualSegment\n\n    const routerState = parsedRequestHeaders.isRouteTreePrefetchRequest\n      ? // Route tree prefetch requests contain some extra information\n        createRouteTreePrefetch(loaderTreeToFilter, getDynamicParamFromSegment)\n      : createFlightRouterStateFromLoaderTree(\n          loaderTreeToFilter,\n          getDynamicParamFromSegment,\n          query\n        )\n\n    return [\n      [\n        overriddenSegment,\n        routerState,\n        null,\n        [null, null],\n        true,\n      ] satisfies FlightDataSegment,\n    ]\n  }\n\n  // Similar to the previous branch. This flag is sent by the client to request\n  // only the metadata for a page. No segment data.\n  if (flightRouterState && flightRouterState[3] === 'metadata-only') {\n    const overriddenSegment =\n      flightRouterState &&\n      canSegmentBeOverridden(actualSegment, flightRouterState[0])\n        ? flightRouterState[0]\n        : actualSegment\n    const routerState = parsedRequestHeaders.isRouteTreePrefetchRequest\n      ? createRouteTreePrefetch(loaderTreeToFilter, getDynamicParamFromSegment)\n      : createFlightRouterStateFromLoaderTree(\n          loaderTreeToFilter,\n          getDynamicParamFromSegment,\n          query\n        )\n    return [\n      [\n        overriddenSegment,\n        routerState,\n        null,\n        rscHead,\n        false,\n      ] satisfies FlightDataSegment,\n    ]\n  }\n\n  if (renderComponentsOnThisLevel) {\n    const overriddenSegment =\n      flightRouterState &&\n      // TODO: Why does canSegmentBeOverridden exist? Why don't we always just\n      // use `actualSegment`? Is it to avoid overwriting some state that's\n      // tracked by the client? Dig deeper to see if we can simplify this.\n      canSegmentBeOverridden(actualSegment, flightRouterState[0])\n        ? flightRouterState[0]\n        : actualSegment\n\n    const routerState = createFlightRouterStateFromLoaderTree(\n      // Create router state using the slice of the loaderTree\n      loaderTreeToFilter,\n      getDynamicParamFromSegment,\n      query\n    )\n    // Create component tree using the slice of the loaderTree\n    const seedData = await createComponentTree(\n      // This ensures flightRouterPath is valid and filters down the tree\n      {\n        ctx,\n        loaderTree: loaderTreeToFilter,\n        parentParams: currentParams,\n        injectedCSS,\n        injectedJS,\n        injectedFontPreloadTags,\n        // This is intentionally not \"rootLayoutIncludedAtThisLevelOrAbove\" as createComponentTree starts at the current level and does a check for \"rootLayoutAtThisLevel\" too.\n        rootLayoutIncluded,\n        getViewportReady,\n        getMetadataReady,\n        preloadCallbacks,\n        authInterrupts: experimental.authInterrupts,\n        StreamingMetadataOutlet,\n      }\n    )\n\n    return [\n      [\n        overriddenSegment,\n        routerState,\n        seedData,\n        rscHead,\n        false,\n      ] satisfies FlightDataSegment,\n    ]\n  }\n\n  // If we are not rendering on this level we need to check if the current\n  // segment has a layout. If so, we need to track all the used CSS to make\n  // the result consistent.\n  const layoutPath = layout?.[1]\n  const injectedCSSWithCurrentLayout = new Set(injectedCSS)\n  const injectedJSWithCurrentLayout = new Set(injectedJS)\n  const injectedFontPreloadTagsWithCurrentLayout = new Set(\n    injectedFontPreloadTags\n  )\n  if (layoutPath) {\n    getLinkAndScriptTags(\n      ctx.clientReferenceManifest,\n      layoutPath,\n      injectedCSSWithCurrentLayout,\n      injectedJSWithCurrentLayout,\n      true\n    )\n    getPreloadableFonts(\n      nextFontManifest,\n      layoutPath,\n      injectedFontPreloadTagsWithCurrentLayout\n    )\n  }\n\n  const paths: FlightDataPath[] = []\n\n  // Walk through all parallel routes.\n  for (const parallelRouteKey of parallelRoutesKeys) {\n    const parallelRoute = parallelRoutes[parallelRouteKey]\n\n    const subPaths = await walkTreeWithFlightRouterState({\n      ctx,\n      loaderTreeToFilter: parallelRoute,\n      parentParams: currentParams,\n      flightRouterState:\n        flightRouterState && flightRouterState[1][parallelRouteKey],\n      parentIsInsideSharedLayout: isInsideSharedLayout,\n      rscHead,\n      injectedCSS: injectedCSSWithCurrentLayout,\n      injectedJS: injectedJSWithCurrentLayout,\n      injectedFontPreloadTags: injectedFontPreloadTagsWithCurrentLayout,\n      rootLayoutIncluded: rootLayoutIncludedAtThisLevelOrAbove,\n      getViewportReady,\n      getMetadataReady,\n      preloadCallbacks,\n      StreamingMetadataOutlet,\n    })\n\n    for (const subPath of subPaths) {\n      // we don't need to send over default routes in the flight data\n      // because they are always ignored by the client, unless it's a refetch\n      if (\n        subPath[0] === DEFAULT_SEGMENT_KEY &&\n        flightRouterState &&\n        !!flightRouterState[1][parallelRouteKey][0] &&\n        flightRouterState[1][parallelRouteKey][3] !== 'refetch'\n      ) {\n        continue\n      }\n\n      paths.push([actualSegment, parallelRouteKey, ...subPath])\n    }\n  }\n\n  return paths\n}\n\n/*\n * This function is used to determine if an existing segment can be overridden\n * by the incoming segment.\n */\nconst canSegmentBeOverridden = (\n  existingSegment: Segment,\n  segment: Segment\n): boolean => {\n  if (Array.isArray(existingSegment) || !Array.isArray(segment)) {\n    return false\n  }\n\n  return getSegmentParam(existingSegment)?.param === segment[0]\n}\n"],"names":["matchSegment","getLinkAndScriptTags","getPreloadableFonts","createFlightRouterStateFromLoaderTree","createRouteTreePrefetch","hasLoadingComponentInTree","DEFAULT_SEGMENT_KEY","addSearchParamsIfPageSegment","createComponentTree","getSegmentParam","walkTreeWithFlightRouterState","loaderTreeToFilter","parentParams","flightRouterState","parentIsInsideSharedLayout","rscHead","injectedCSS","injectedJS","injectedFontPreloadTags","rootLayoutIncluded","getViewportReady","getMetadataReady","ctx","preloadCallbacks","StreamingMetadataOutlet","renderOpts","nextFontManifest","experimental","query","isPrefetch","getDynamicParamFromSegment","parsedRequestHeaders","segment","parallelRoutes","modules","parallelRoutesKeys","Object","keys","layout","isLayout","rootLayoutAtThisLevel","rootLayoutIncludedAtThisLevelOrAbove","segmentParam","currentParams","value","param","actualSegment","treeSegment","renderComponentsOnThisLevel","length","isInsideSharedLayout","isRoutePPREnabled","isRouteTreePrefetchRequest","Boolean","loading","overriddenSegment","canSegmentBeOverridden","routerState","seedData","loaderTree","authInterrupts","layoutPath","injectedCSSWithCurrentLayout","Set","injectedJSWithCurrentLayout","injectedFontPreloadTagsWithCurrentLayout","clientReferenceManifest","paths","parallelRouteKey","parallelRoute","subPaths","subPath","push","existingSegment","Array","isArray"],"mappings":"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","ignoreList":[0]}