{"version":3,"sources":["../../../../src/client/components/router-reducer/refetch-inactive-parallel-segments.ts"],"sourcesContent":["import type { FlightRouterState } from '../../../server/app-render/types'\nimport type { CacheNode } from '../../../shared/lib/app-router-context.shared-runtime'\nimport type { AppRouterState } from './router-reducer-types'\nimport { applyFlightData } from './apply-flight-data'\nimport { fetchServerResponse } from './fetch-server-response'\nimport { PAGE_SEGMENT_KEY } from '../../../shared/lib/segment'\n\ninterface RefreshInactiveParallelSegments {\n  navigatedAt: number\n  state: AppRouterState\n  updatedTree: FlightRouterState\n  updatedCache: CacheNode\n  includeNextUrl: boolean\n  canonicalUrl: string\n}\n\n/**\n * Refreshes inactive segments that are still in the current FlightRouterState.\n * A segment is considered \"inactive\" when the server response indicates it didn't match to a page component.\n * This happens during a soft-navigation, where the server will want to patch in the segment\n * with the \"default\" component, but we explicitly ignore the server in this case\n * and keep the existing state for that segment. New data for inactive segments are inherently\n * not part of the server response when we patch the tree, because they were associated with a response\n * from an earlier navigation/request. For each segment, once it becomes \"active\", we encode the URL that provided\n * the data for it. This function traverses parallel routes looking for these markers so that it can re-fetch\n * and patch the new data into the tree.\n */\nexport async function refreshInactiveParallelSegments(\n  options: RefreshInactiveParallelSegments\n) {\n  const fetchedSegments = new Set<string>()\n  await refreshInactiveParallelSegmentsImpl({\n    ...options,\n    rootTree: options.updatedTree,\n    fetchedSegments,\n  })\n}\n\nasync function refreshInactiveParallelSegmentsImpl({\n  navigatedAt,\n  state,\n  updatedTree,\n  updatedCache,\n  includeNextUrl,\n  fetchedSegments,\n  rootTree = updatedTree,\n  canonicalUrl,\n}: RefreshInactiveParallelSegments & {\n  fetchedSegments: Set<string>\n  rootTree: FlightRouterState\n}) {\n  const [, parallelRoutes, refetchPath, refetchMarker] = updatedTree\n  const fetchPromises = []\n\n  if (\n    refetchPath &&\n    refetchPath !== canonicalUrl &&\n    refetchMarker === 'refresh' &&\n    // it's possible for the tree to contain multiple segments that contain data at the same URL\n    // we keep track of them so we can dedupe the requests\n    !fetchedSegments.has(refetchPath)\n  ) {\n    fetchedSegments.add(refetchPath) // Mark this URL as fetched\n\n    // Eagerly kick off the fetch for the refetch path & the parallel routes. This should be fine to do as they each operate\n    // independently on their own cache nodes, and `applyFlightData` will copy anything it doesn't care about from the existing cache.\n    const fetchPromise = fetchServerResponse(\n      new URL(refetchPath, location.origin),\n      {\n        // refetch from the root of the updated tree, otherwise it will be scoped to the current segment\n        // and might not contain the data we need to patch in interception route data (such as dynamic params from a previous segment)\n        flightRouterState: [rootTree[0], rootTree[1], rootTree[2], 'refetch'],\n        nextUrl: includeNextUrl ? state.nextUrl : null,\n      }\n    ).then(({ flightData }) => {\n      if (typeof flightData !== 'string') {\n        for (const flightDataPath of flightData) {\n          // we only pass the new cache as this function is called after clearing the router cache\n          // and filling in the new page data from the server. Meaning the existing cache is actually the cache that's\n          // just been created & has been written to, but hasn't been \"committed\" yet.\n          applyFlightData(\n            navigatedAt,\n            updatedCache,\n            updatedCache,\n            flightDataPath\n          )\n        }\n      } else {\n        // When flightData is a string, it suggests that the server response should have triggered an MPA navigation\n        // I'm not 100% sure of this decision, but it seems unlikely that we'd want to introduce a redirect side effect\n        // when refreshing on-screen data, so handling this has been ommitted.\n      }\n    })\n\n    fetchPromises.push(fetchPromise)\n  }\n\n  for (const key in parallelRoutes) {\n    const parallelFetchPromise = refreshInactiveParallelSegmentsImpl({\n      navigatedAt,\n      state,\n      updatedTree: parallelRoutes[key],\n      updatedCache,\n      includeNextUrl,\n      fetchedSegments,\n      rootTree,\n      canonicalUrl,\n    })\n\n    fetchPromises.push(parallelFetchPromise)\n  }\n\n  await Promise.all(fetchPromises)\n}\n\n/**\n * Walks the current parallel segments to determine if they are \"active\".\n * An active parallel route will have a `__PAGE__` segment in the FlightRouterState.\n * As opposed to a `__DEFAULT__` segment, which means there was no match for that parallel route.\n * We add a special marker here so that we know how to refresh its data when the router is revalidated.\n */\nexport function addRefreshMarkerToActiveParallelSegments(\n  tree: FlightRouterState,\n  path: string\n) {\n  const [segment, parallelRoutes, , refetchMarker] = tree\n  // a page segment might also contain concatenated search params, so we do a partial match on the key\n  if (segment.includes(PAGE_SEGMENT_KEY) && refetchMarker !== 'refresh') {\n    tree[2] = path\n    tree[3] = 'refresh'\n  }\n\n  for (const key in parallelRoutes) {\n    addRefreshMarkerToActiveParallelSegments(parallelRoutes[key], path)\n  }\n}\n"],"names":["applyFlightData","fetchServerResponse","PAGE_SEGMENT_KEY","refreshInactiveParallelSegments","options","fetchedSegments","Set","refreshInactiveParallelSegmentsImpl","rootTree","updatedTree","navigatedAt","state","updatedCache","includeNextUrl","canonicalUrl","parallelRoutes","refetchPath","refetchMarker","fetchPromises","has","add","fetchPromise","URL","location","origin","flightRouterState","nextUrl","then","flightData","flightDataPath","push","key","parallelFetchPromise","Promise","all","addRefreshMarkerToActiveParallelSegments","tree","path","segment","includes"],"mappings":"AAGA,SAASA,eAAe,QAAQ,sBAAqB;AACrD,SAASC,mBAAmB,QAAQ,0BAAyB;AAC7D,SAASC,gBAAgB,QAAQ,8BAA6B;AAW9D;;;;;;;;;;CAUC,GACD,OAAO,eAAeC,gCACpBC,OAAwC;IAExC,MAAMC,kBAAkB,IAAIC;IAC5B,MAAMC,oCAAoC;QACxC,GAAGH,OAAO;QACVI,UAAUJ,QAAQK,WAAW;QAC7BJ;IACF;AACF;AAEA,eAAeE,oCAAoC,KAYlD;IAZkD,IAAA,EACjDG,WAAW,EACXC,KAAK,EACLF,WAAW,EACXG,YAAY,EACZC,cAAc,EACdR,eAAe,EACfG,WAAWC,WAAW,EACtBK,YAAY,EAIb,GAZkD;IAajD,MAAM,GAAGC,gBAAgBC,aAAaC,cAAc,GAAGR;IACvD,MAAMS,gBAAgB,EAAE;IAExB,IACEF,eACAA,gBAAgBF,gBAChBG,kBAAkB,aAClB,4FAA4F;IAC5F,sDAAsD;IACtD,CAACZ,gBAAgBc,GAAG,CAACH,cACrB;QACAX,gBAAgBe,GAAG,CAACJ,aAAa,2BAA2B;;QAE5D,wHAAwH;QACxH,kIAAkI;QAClI,MAAMK,eAAepB,oBACnB,IAAIqB,IAAIN,aAAaO,SAASC,MAAM,GACpC;YACE,gGAAgG;YAChG,8HAA8H;YAC9HC,mBAAmB;gBAACjB,QAAQ,CAAC,EAAE;gBAAEA,QAAQ,CAAC,EAAE;gBAAEA,QAAQ,CAAC,EAAE;gBAAE;aAAU;YACrEkB,SAASb,iBAAiBF,MAAMe,OAAO,GAAG;QAC5C,GACAC,IAAI,CAAC;gBAAC,EAAEC,UAAU,EAAE;YACpB,IAAI,OAAOA,eAAe,UAAU;gBAClC,KAAK,MAAMC,kBAAkBD,WAAY;oBACvC,wFAAwF;oBACxF,4GAA4G;oBAC5G,4EAA4E;oBAC5E5B,gBACEU,aACAE,cACAA,cACAiB;gBAEJ;YACF,OAAO;YACL,4GAA4G;YAC5G,+GAA+G;YAC/G,sEAAsE;YACxE;QACF;QAEAX,cAAcY,IAAI,CAACT;IACrB;IAEA,IAAK,MAAMU,OAAOhB,eAAgB;QAChC,MAAMiB,uBAAuBzB,oCAAoC;YAC/DG;YACAC;YACAF,aAAaM,cAAc,CAACgB,IAAI;YAChCnB;YACAC;YACAR;YACAG;YACAM;QACF;QAEAI,cAAcY,IAAI,CAACE;IACrB;IAEA,MAAMC,QAAQC,GAAG,CAAChB;AACpB;AAEA;;;;;CAKC,GACD,OAAO,SAASiB,yCACdC,IAAuB,EACvBC,IAAY;IAEZ,MAAM,CAACC,SAASvB,kBAAkBE,cAAc,GAAGmB;IACnD,oGAAoG;IACpG,IAAIE,QAAQC,QAAQ,CAACrC,qBAAqBe,kBAAkB,WAAW;QACrEmB,IAAI,CAAC,EAAE,GAAGC;QACVD,IAAI,CAAC,EAAE,GAAG;IACZ;IAEA,IAAK,MAAML,OAAOhB,eAAgB;QAChCoB,yCAAyCpB,cAAc,CAACgB,IAAI,EAAEM;IAChE;AACF","ignoreList":[0]}