{"version":3,"sources":["../../../src/client/flight-data-helpers.ts"],"sourcesContent":["import type {\n  CacheNodeSeedData,\n  FlightData,\n  FlightDataPath,\n  FlightRouterState,\n  FlightSegmentPath,\n  Segment,\n  HeadData,\n  InitialRSCPayload,\n} from '../shared/lib/app-router-types'\nimport { PAGE_SEGMENT_KEY } from '../shared/lib/segment'\nimport type { NormalizedSearch } from './components/segment-cache/cache-key'\nimport {\n  getCacheKeyForDynamicParam,\n  parseDynamicParamFromURLPart,\n  doesStaticSegmentAppearInURL,\n  getRenderedPathname,\n  getRenderedSearch,\n} from './route-params'\nimport { createHrefFromUrl } from './components/router-reducer/create-href-from-url'\n\nexport type NormalizedFlightData = {\n  /**\n   * The full `FlightSegmentPath` inclusive of the final `Segment`\n   */\n  segmentPath: FlightSegmentPath\n  /**\n   * The `FlightSegmentPath` exclusive of the final `Segment`\n   */\n  pathToSegment: FlightSegmentPath\n  segment: Segment\n  tree: FlightRouterState\n  seedData: CacheNodeSeedData | null\n  head: HeadData\n  isHeadPartial: boolean\n  isRootRender: boolean\n}\n\n// TODO: We should only have to export `normalizeFlightData`, however because the initial flight data\n// that gets passed to `createInitialRouterState` doesn't conform to the `FlightDataPath` type (it's missing the root segment)\n// we're currently exporting it so we can use it directly. This should be fixed as part of the unification of\n// the different ways we express `FlightSegmentPath`.\nexport function getFlightDataPartsFromPath(\n  flightDataPath: FlightDataPath\n): NormalizedFlightData {\n  // Pick the last 4 items from the `FlightDataPath` to get the [tree, seedData, viewport, isHeadPartial].\n  const flightDataPathLength = 4\n  // tree, seedData, and head are *always* the last three items in the `FlightDataPath`.\n  const [tree, seedData, head, isHeadPartial] =\n    flightDataPath.slice(-flightDataPathLength)\n  // The `FlightSegmentPath` is everything except the last three items. For a root render, it won't be present.\n  const segmentPath = flightDataPath.slice(0, -flightDataPathLength)\n\n  return {\n    // TODO: Unify these two segment path helpers. We are inconsistently pushing an empty segment (\"\")\n    // to the start of the segment path in some places which makes it hard to use solely the segment path.\n    // Look for \"// TODO-APP: remove ''\" in the codebase.\n    pathToSegment: segmentPath.slice(0, -1),\n    segmentPath,\n    // if the `FlightDataPath` corresponds with the root, there'll be no segment path,\n    // in which case we default to ''.\n    segment: segmentPath[segmentPath.length - 1] ?? '',\n    tree,\n    seedData,\n    head,\n    isHeadPartial,\n    isRootRender: flightDataPath.length === flightDataPathLength,\n  }\n}\n\nexport function createInitialRSCPayloadFromFallbackPrerender(\n  response: Response,\n  fallbackInitialRSCPayload: InitialRSCPayload\n): InitialRSCPayload {\n  // This is a static fallback page. In order to hydrate the page, we need to\n  // parse the client params from the URL, but to account for the possibility\n  // that the page was rewritten, we need to check the response headers\n  // for x-nextjs-rewritten-path or x-nextjs-rewritten-query headers. Since\n  // we can't access the headers of the initial document response, the client\n  // performs a fetch request to the current location. Since it's possible that\n  // the fetch request will be dynamically rewritten to a different path than\n  // the initial document, this fetch request delivers _all_ the hydration data\n  // for the page; it was not inlined into the document, like it normally\n  // would be.\n  //\n  // TODO: Consider treating the case where fetch is rewritten to a different\n  // path from the document as a special deopt case. We should optimistically\n  // assume this won't happen, inline the data into the document, and perform\n  // a minimal request (like a HEAD or range request) to verify that the\n  // response matches. Tricky to get right because we need to account for\n  // all the different deployment environments we support, like output:\n  // \"export\" mode, where we currently don't assume that custom response\n  // headers are present.\n\n  // Patch the Flight data sent by the server with the correct params parsed\n  // from the URL + response object.\n  const renderedPathname = getRenderedPathname(response)\n  const renderedSearch = getRenderedSearch(response)\n  const canonicalUrl = createHrefFromUrl(new URL(location.href))\n  const originalFlightDataPath = fallbackInitialRSCPayload.f[0]\n  const originalFlightRouterState = originalFlightDataPath[0]\n  const payload: InitialRSCPayload = {\n    c: canonicalUrl.split('/'),\n    q: renderedSearch,\n    i: fallbackInitialRSCPayload.i,\n    f: [\n      [\n        fillInFallbackFlightRouterState(\n          originalFlightRouterState,\n          renderedPathname,\n          renderedSearch as NormalizedSearch\n        ),\n        originalFlightDataPath[1],\n        originalFlightDataPath[2],\n        originalFlightDataPath[2],\n      ],\n    ],\n    m: fallbackInitialRSCPayload.m,\n    G: fallbackInitialRSCPayload.G,\n    S: fallbackInitialRSCPayload.S,\n    h: fallbackInitialRSCPayload.h,\n  }\n  if (fallbackInitialRSCPayload.b) {\n    payload.b = fallbackInitialRSCPayload.b\n  }\n  return payload\n}\n\nfunction fillInFallbackFlightRouterState(\n  flightRouterState: FlightRouterState,\n  renderedPathname: string,\n  renderedSearch: NormalizedSearch\n): FlightRouterState {\n  const pathnameParts = renderedPathname.split('/').filter((p) => p !== '')\n  const index = 0\n  return fillInFallbackFlightRouterStateImpl(\n    flightRouterState,\n    renderedSearch,\n    pathnameParts,\n    index\n  )\n}\n\nfunction fillInFallbackFlightRouterStateImpl(\n  flightRouterState: FlightRouterState,\n  renderedSearch: NormalizedSearch,\n  pathnameParts: Array<string>,\n  pathnamePartsIndex: number\n): FlightRouterState {\n  const originalSegment = flightRouterState[0]\n  let newSegment: Segment\n  let doesAppearInURL: boolean\n  if (typeof originalSegment === 'string') {\n    newSegment = originalSegment\n    doesAppearInURL = doesStaticSegmentAppearInURL(originalSegment)\n  } else {\n    const paramName = originalSegment[0]\n    const paramType = originalSegment[2]\n    const staticSiblings = originalSegment[3]\n    const paramValue = parseDynamicParamFromURLPart(\n      paramType,\n      pathnameParts,\n      pathnamePartsIndex\n    )\n    const cacheKey = getCacheKeyForDynamicParam(paramValue, renderedSearch)\n    newSegment = [paramName, cacheKey, paramType, staticSiblings]\n    doesAppearInURL = true\n  }\n\n  // Only increment the index if the segment appears in the URL. If it's a\n  // \"virtual\" segment, like a route group, it remains the same.\n  const childPathnamePartsIndex = doesAppearInURL\n    ? pathnamePartsIndex + 1\n    : pathnamePartsIndex\n\n  const children = flightRouterState[1]\n  const newChildren: { [key: string]: FlightRouterState } = {}\n  for (let key in children) {\n    const childFlightRouterState = children[key]\n    newChildren[key] = fillInFallbackFlightRouterStateImpl(\n      childFlightRouterState,\n      renderedSearch,\n      pathnameParts,\n      childPathnamePartsIndex\n    )\n  }\n\n  const newState: FlightRouterState = [\n    newSegment,\n    newChildren,\n    null,\n    flightRouterState[3],\n    flightRouterState[4],\n  ]\n  return newState\n}\n\nexport function getNextFlightSegmentPath(\n  flightSegmentPath: FlightSegmentPath\n): FlightSegmentPath {\n  // Since `FlightSegmentPath` is a repeated tuple of `Segment` and `ParallelRouteKey`, we slice off two items\n  // to get the next segment path.\n  return flightSegmentPath.slice(2)\n}\n\nexport function normalizeFlightData(\n  flightData: FlightData\n): NormalizedFlightData[] | string {\n  // FlightData can be a string when the server didn't respond with a proper flight response,\n  // or when a redirect happens, to signal to the client that it needs to perform an MPA navigation.\n  if (typeof flightData === 'string') {\n    return flightData\n  }\n\n  return flightData.map((flightDataPath) =>\n    getFlightDataPartsFromPath(flightDataPath)\n  )\n}\n\n/**\n * This function is used to prepare the flight router state for the request.\n * It removes markers that are not needed by the server, and are purely used\n * for stashing state on the client.\n * @param flightRouterState - The flight router state to prepare.\n * @param isHmrRefresh - Whether this is an HMR refresh request.\n * @returns The prepared flight router state.\n */\nexport function prepareFlightRouterStateForRequest(\n  flightRouterState: FlightRouterState,\n  isHmrRefresh?: boolean\n): string {\n  // HMR requests need the complete, unmodified state for proper functionality\n  if (isHmrRefresh) {\n    return encodeURIComponent(JSON.stringify(flightRouterState))\n  }\n\n  return encodeURIComponent(\n    JSON.stringify(stripClientOnlyDataFromFlightRouterState(flightRouterState))\n  )\n}\n\n/**\n * Recursively strips client-only data from FlightRouterState while preserving\n * server-needed information for proper rendering decisions.\n */\nfunction stripClientOnlyDataFromFlightRouterState(\n  flightRouterState: FlightRouterState\n): FlightRouterState {\n  const [\n    segment,\n    parallelRoutes,\n    _refreshState, // Intentionally unused - URLs are client-only\n    refreshMarker,\n    prefetchHints,\n  ] = flightRouterState\n\n  // Strip client-only data from the segment\n  const cleanedSegment = stripClientOnlyDataFromSegment(segment)\n\n  // Recursively process parallel routes\n  const cleanedParallelRoutes: { [key: string]: FlightRouterState } = {}\n  for (const [key, childState] of Object.entries(parallelRoutes)) {\n    cleanedParallelRoutes[key] =\n      stripClientOnlyDataFromFlightRouterState(childState)\n  }\n\n  const result: FlightRouterState = [cleanedSegment, cleanedParallelRoutes]\n  if (refreshMarker) {\n    result[2] = null // null slightly more compact than undefined\n    result[3] = refreshMarker\n  }\n\n  // Append optional fields if present\n  if (prefetchHints !== undefined) {\n    result[4] = prefetchHints\n  }\n\n  // Everything else is used only by the client and is not needed for requests.\n  return result\n}\n\n/**\n * Strips client-only data from segments:\n * - Search parameters from __PAGE__ segments\n * - staticSiblings from dynamic segment tuples (only needed for client-side\n *   prefetch reuse decisions)\n */\nfunction stripClientOnlyDataFromSegment(segment: Segment): Segment {\n  if (typeof segment === 'string') {\n    // Strip search params from __PAGE__ segments\n    if (segment.startsWith(PAGE_SEGMENT_KEY + '?')) {\n      return PAGE_SEGMENT_KEY\n    }\n    return segment\n  }\n  // Dynamic segment tuple: [paramName, paramCacheKey, paramType, staticSiblings]\n  // Strip staticSiblings (4th element) since server doesn't need it\n  const [paramName, paramCacheKey, paramType] = segment\n  return [paramName, paramCacheKey, paramType, null]\n}\n"],"names":["PAGE_SEGMENT_KEY","getCacheKeyForDynamicParam","parseDynamicParamFromURLPart","doesStaticSegmentAppearInURL","getRenderedPathname","getRenderedSearch","createHrefFromUrl","getFlightDataPartsFromPath","flightDataPath","flightDataPathLength","tree","seedData","head","isHeadPartial","slice","segmentPath","pathToSegment","segment","length","isRootRender","createInitialRSCPayloadFromFallbackPrerender","response","fallbackInitialRSCPayload","renderedPathname","renderedSearch","canonicalUrl","URL","location","href","originalFlightDataPath","f","originalFlightRouterState","payload","c","split","q","i","fillInFallbackFlightRouterState","m","G","S","h","b","flightRouterState","pathnameParts","filter","p","index","fillInFallbackFlightRouterStateImpl","pathnamePartsIndex","originalSegment","newSegment","doesAppearInURL","paramName","paramType","staticSiblings","paramValue","cacheKey","childPathnamePartsIndex","children","newChildren","key","childFlightRouterState","newState","getNextFlightSegmentPath","flightSegmentPath","normalizeFlightData","flightData","map","prepareFlightRouterStateForRequest","isHmrRefresh","encodeURIComponent","JSON","stringify","stripClientOnlyDataFromFlightRouterState","parallelRoutes","_refreshState","refreshMarker","prefetchHints","cleanedSegment","stripClientOnlyDataFromSegment","cleanedParallelRoutes","childState","Object","entries","result","undefined","startsWith","paramCacheKey"],"mappings":"AAUA,SAASA,gBAAgB,QAAQ,wBAAuB;AAExD,SACEC,0BAA0B,EAC1BC,4BAA4B,EAC5BC,4BAA4B,EAC5BC,mBAAmB,EACnBC,iBAAiB,QACZ,iBAAgB;AACvB,SAASC,iBAAiB,QAAQ,mDAAkD;AAmBpF,qGAAqG;AACrG,8HAA8H;AAC9H,6GAA6G;AAC7G,qDAAqD;AACrD,OAAO,SAASC,2BACdC,cAA8B;IAE9B,wGAAwG;IACxG,MAAMC,uBAAuB;IAC7B,sFAAsF;IACtF,MAAM,CAACC,MAAMC,UAAUC,MAAMC,cAAc,GACzCL,eAAeM,KAAK,CAAC,CAACL;IACxB,6GAA6G;IAC7G,MAAMM,cAAcP,eAAeM,KAAK,CAAC,GAAG,CAACL;IAE7C,OAAO;QACL,kGAAkG;QAClG,sGAAsG;QACtG,qDAAqD;QACrDO,eAAeD,YAAYD,KAAK,CAAC,GAAG,CAAC;QACrCC;QACA,kFAAkF;QAClF,kCAAkC;QAClCE,SAASF,WAAW,CAACA,YAAYG,MAAM,GAAG,EAAE,IAAI;QAChDR;QACAC;QACAC;QACAC;QACAM,cAAcX,eAAeU,MAAM,KAAKT;IAC1C;AACF;AAEA,OAAO,SAASW,6CACdC,QAAkB,EAClBC,yBAA4C;IAE5C,2EAA2E;IAC3E,2EAA2E;IAC3E,qEAAqE;IACrE,yEAAyE;IACzE,2EAA2E;IAC3E,6EAA6E;IAC7E,2EAA2E;IAC3E,6EAA6E;IAC7E,uEAAuE;IACvE,YAAY;IACZ,EAAE;IACF,2EAA2E;IAC3E,2EAA2E;IAC3E,2EAA2E;IAC3E,sEAAsE;IACtE,uEAAuE;IACvE,qEAAqE;IACrE,sEAAsE;IACtE,uBAAuB;IAEvB,0EAA0E;IAC1E,kCAAkC;IAClC,MAAMC,mBAAmBnB,oBAAoBiB;IAC7C,MAAMG,iBAAiBnB,kBAAkBgB;IACzC,MAAMI,eAAenB,kBAAkB,IAAIoB,IAAIC,SAASC,IAAI;IAC5D,MAAMC,yBAAyBP,0BAA0BQ,CAAC,CAAC,EAAE;IAC7D,MAAMC,4BAA4BF,sBAAsB,CAAC,EAAE;IAC3D,MAAMG,UAA6B;QACjCC,GAAGR,aAAaS,KAAK,CAAC;QACtBC,GAAGX;QACHY,GAAGd,0BAA0Bc,CAAC;QAC9BN,GAAG;YACD;gBACEO,gCACEN,2BACAR,kBACAC;gBAEFK,sBAAsB,CAAC,EAAE;gBACzBA,sBAAsB,CAAC,EAAE;gBACzBA,sBAAsB,CAAC,EAAE;aAC1B;SACF;QACDS,GAAGhB,0BAA0BgB,CAAC;QAC9BC,GAAGjB,0BAA0BiB,CAAC;QAC9BC,GAAGlB,0BAA0BkB,CAAC;QAC9BC,GAAGnB,0BAA0BmB,CAAC;IAChC;IACA,IAAInB,0BAA0BoB,CAAC,EAAE;QAC/BV,QAAQU,CAAC,GAAGpB,0BAA0BoB,CAAC;IACzC;IACA,OAAOV;AACT;AAEA,SAASK,gCACPM,iBAAoC,EACpCpB,gBAAwB,EACxBC,cAAgC;IAEhC,MAAMoB,gBAAgBrB,iBAAiBW,KAAK,CAAC,KAAKW,MAAM,CAAC,CAACC,IAAMA,MAAM;IACtE,MAAMC,QAAQ;IACd,OAAOC,oCACLL,mBACAnB,gBACAoB,eACAG;AAEJ;AAEA,SAASC,oCACPL,iBAAoC,EACpCnB,cAAgC,EAChCoB,aAA4B,EAC5BK,kBAA0B;IAE1B,MAAMC,kBAAkBP,iBAAiB,CAAC,EAAE;IAC5C,IAAIQ;IACJ,IAAIC;IACJ,IAAI,OAAOF,oBAAoB,UAAU;QACvCC,aAAaD;QACbE,kBAAkBjD,6BAA6B+C;IACjD,OAAO;QACL,MAAMG,YAAYH,eAAe,CAAC,EAAE;QACpC,MAAMI,YAAYJ,eAAe,CAAC,EAAE;QACpC,MAAMK,iBAAiBL,eAAe,CAAC,EAAE;QACzC,MAAMM,aAAatD,6BACjBoD,WACAV,eACAK;QAEF,MAAMQ,WAAWxD,2BAA2BuD,YAAYhC;QACxD2B,aAAa;YAACE;YAAWI;YAAUH;YAAWC;SAAe;QAC7DH,kBAAkB;IACpB;IAEA,wEAAwE;IACxE,8DAA8D;IAC9D,MAAMM,0BAA0BN,kBAC5BH,qBAAqB,IACrBA;IAEJ,MAAMU,WAAWhB,iBAAiB,CAAC,EAAE;IACrC,MAAMiB,cAAoD,CAAC;IAC3D,IAAK,IAAIC,OAAOF,SAAU;QACxB,MAAMG,yBAAyBH,QAAQ,CAACE,IAAI;QAC5CD,WAAW,CAACC,IAAI,GAAGb,oCACjBc,wBACAtC,gBACAoB,eACAc;IAEJ;IAEA,MAAMK,WAA8B;QAClCZ;QACAS;QACA;QACAjB,iBAAiB,CAAC,EAAE;QACpBA,iBAAiB,CAAC,EAAE;KACrB;IACD,OAAOoB;AACT;AAEA,OAAO,SAASC,yBACdC,iBAAoC;IAEpC,4GAA4G;IAC5G,gCAAgC;IAChC,OAAOA,kBAAkBnD,KAAK,CAAC;AACjC;AAEA,OAAO,SAASoD,oBACdC,UAAsB;IAEtB,2FAA2F;IAC3F,kGAAkG;IAClG,IAAI,OAAOA,eAAe,UAAU;QAClC,OAAOA;IACT;IAEA,OAAOA,WAAWC,GAAG,CAAC,CAAC5D,iBACrBD,2BAA2BC;AAE/B;AAEA;;;;;;;CAOC,GACD,OAAO,SAAS6D,mCACd1B,iBAAoC,EACpC2B,YAAsB;IAEtB,4EAA4E;IAC5E,IAAIA,cAAc;QAChB,OAAOC,mBAAmBC,KAAKC,SAAS,CAAC9B;IAC3C;IAEA,OAAO4B,mBACLC,KAAKC,SAAS,CAACC,yCAAyC/B;AAE5D;AAEA;;;CAGC,GACD,SAAS+B,yCACP/B,iBAAoC;IAEpC,MAAM,CACJ1B,SACA0D,gBACAC,eACAC,eACAC,cACD,GAAGnC;IAEJ,0CAA0C;IAC1C,MAAMoC,iBAAiBC,+BAA+B/D;IAEtD,sCAAsC;IACtC,MAAMgE,wBAA8D,CAAC;IACrE,KAAK,MAAM,CAACpB,KAAKqB,WAAW,IAAIC,OAAOC,OAAO,CAACT,gBAAiB;QAC9DM,qBAAqB,CAACpB,IAAI,GACxBa,yCAAyCQ;IAC7C;IAEA,MAAMG,SAA4B;QAACN;QAAgBE;KAAsB;IACzE,IAAIJ,eAAe;QACjBQ,MAAM,CAAC,EAAE,GAAG,KAAK,4CAA4C;;QAC7DA,MAAM,CAAC,EAAE,GAAGR;IACd;IAEA,oCAAoC;IACpC,IAAIC,kBAAkBQ,WAAW;QAC/BD,MAAM,CAAC,EAAE,GAAGP;IACd;IAEA,6EAA6E;IAC7E,OAAOO;AACT;AAEA;;;;;CAKC,GACD,SAASL,+BAA+B/D,OAAgB;IACtD,IAAI,OAAOA,YAAY,UAAU;QAC/B,6CAA6C;QAC7C,IAAIA,QAAQsE,UAAU,CAACvF,mBAAmB,MAAM;YAC9C,OAAOA;QACT;QACA,OAAOiB;IACT;IACA,+EAA+E;IAC/E,kEAAkE;IAClE,MAAM,CAACoC,WAAWmC,eAAelC,UAAU,GAAGrC;IAC9C,OAAO;QAACoC;QAAWmC;QAAelC;QAAW;KAAK;AACpD","ignoreList":[0]}