{"version":3,"sources":["../../../../src/client/components/segment-cache/bfcache.ts"],"sourcesContent":["import { DYNAMIC_STALETIME_MS } from '../router-reducer/reducers/navigate-reducer'\nimport type { SegmentVaryPath } from './vary-path'\n\n/**\n * Sentinel value indicating that no per-page dynamic stale time was provided.\n * When this is the dynamicStaleTime, the default DYNAMIC_STALETIME_MS is used.\n */\nexport const UnknownDynamicStaleTime = -1\n\n/**\n * Converts a dynamic stale time (in seconds, as sent by the server in the `d`\n * field of the Flight response) to an absolute staleAt timestamp. When the\n * value is unknown, falls back to the global DYNAMIC_STALETIME_MS.\n */\nexport function computeDynamicStaleAt(\n  now: number,\n  dynamicStaleTimeSeconds: number\n): number {\n  return dynamicStaleTimeSeconds !== UnknownDynamicStaleTime\n    ? now + dynamicStaleTimeSeconds * 1000\n    : now + DYNAMIC_STALETIME_MS\n}\nimport {\n  setInCacheMap,\n  getFromCacheMap,\n  EntryStatus,\n  type UnknownMapEntry,\n  type CacheMap,\n  createCacheMap,\n} from './cache-map'\n\nexport type BFCacheEntry = {\n  rsc: React.ReactNode | null\n  prefetchRsc: React.ReactNode | null\n  head: React.ReactNode | null\n  prefetchHead: React.ReactNode | null\n\n  // The bfcacheId of the CacheNode that wrote this entry. Restored on\n  // history-traversal navigations so that `useRouter().bfcacheId` is stable\n  // across back/forward, even without `cacheComponents` Activity preservation.\n  bfcacheId: number\n\n  ref: UnknownMapEntry | null\n  size: number\n  // The time at which this data was received. Used to compute the stale time\n  // for dynamic prefetches (which use STATIC_STALETIME_MS instead of\n  // DYNAMIC_STALETIME_MS). Stored explicitly because staleAt may be\n  // overridden by a per-page unstable_dynamicStaleTime, which would break\n  // any reverse calculation from staleAt.\n  navigatedAt: number\n  staleAt: number\n  version: number\n  // A BFCacheEntry always represents a completed navigation, so the status is\n  // always Fulfilled. The field exists so that BFCacheEntry conforms to the\n  // MapValue protocol.\n  status: EntryStatus.Fulfilled\n}\n\nconst bfcacheMap: CacheMap<BFCacheEntry> = createCacheMap()\n\nlet currentBfCacheVersion = 0\n\nexport function invalidateBfCache(): void {\n  if (typeof window === 'undefined') {\n    return\n  }\n  currentBfCacheVersion++\n}\n\nexport function writeToBFCache(\n  now: number,\n  varyPath: SegmentVaryPath,\n  rsc: React.ReactNode,\n  prefetchRsc: React.ReactNode,\n  head: React.ReactNode,\n  prefetchHead: React.ReactNode,\n  dynamicStaleAt: number,\n  bfcacheId: number\n): void {\n  if (typeof window === 'undefined') {\n    return\n  }\n\n  const entry: BFCacheEntry = {\n    rsc,\n    prefetchRsc,\n\n    // TODO: These fields will be removed from both BFCacheEntry and\n    // SegmentCacheEntry. The head has its own separate cache entry.\n    head,\n    prefetchHead,\n\n    bfcacheId,\n\n    ref: null,\n    // TODO: This is just a heuristic. Getting the actual size of the segment\n    // isn't feasible because it's part of a larger streaming response. The\n    // LRU will still evict it, we just won't have a fully accurate total\n    // LRU size. However, we'll probably remove the size tracking from the LRU\n    // entirely and use memory pressure events instead.\n    size: 100,\n\n    navigatedAt: now,\n\n    // A back/forward navigation will disregard the stale time. This field is\n    // only relevant when staleTimes.dynamic is enabled or unstable_dynamicStaleTime\n    // is exported by a page.\n    staleAt: dynamicStaleAt,\n    version: currentBfCacheVersion,\n    status: EntryStatus.Fulfilled,\n  }\n  const isRevalidation = false\n  setInCacheMap(bfcacheMap, varyPath, entry, isRevalidation)\n}\n\nexport function writeHeadToBFCache(\n  now: number,\n  varyPath: SegmentVaryPath,\n  head: React.ReactNode,\n  prefetchHead: React.ReactNode,\n  dynamicStaleAt: number,\n  bfcacheId: number\n): void {\n  // Read the special \"segment\" that represents the head data.\n  writeToBFCache(\n    now,\n    varyPath,\n    head,\n    prefetchHead,\n    null,\n    null,\n    dynamicStaleAt,\n    bfcacheId\n  )\n}\n\n/**\n * Update the staleAt of an existing BFCache entry. Used after a dynamic\n * response arrives with a per-page stale time from `unstable_dynamicStaleTime`.\n * The per-page value is authoritative — it overrides whatever staleAt was set\n * by the default DYNAMIC_STALETIME_MS.\n */\nexport function updateBFCacheEntryStaleAt(\n  varyPath: SegmentVaryPath,\n  newStaleAt: number\n): void {\n  if (typeof window === 'undefined') {\n    return\n  }\n  const isRevalidation = false\n  // Read with staleness bypass (-1) so we can update even stale entries\n  const entry = getFromCacheMap(\n    -1,\n    currentBfCacheVersion,\n    bfcacheMap,\n    varyPath,\n    isRevalidation,\n    false\n  )\n  if (entry !== null) {\n    entry.staleAt = newStaleAt\n  }\n}\n\nexport function readFromBFCache(\n  varyPath: SegmentVaryPath\n): BFCacheEntry | null {\n  if (typeof window === 'undefined') {\n    return null\n  }\n  const isRevalidation = false\n  return getFromCacheMap(\n    // During a back/forward navigation, it doesn't matter how stale the data\n    // might be. Pass -1 instead of the actual current time to bypass\n    // staleness checks.\n    -1,\n    currentBfCacheVersion,\n    bfcacheMap,\n    varyPath,\n    isRevalidation,\n    false\n  )\n}\n\nexport function readFromBFCacheDuringRegularNavigation(\n  now: number,\n  varyPath: SegmentVaryPath\n): BFCacheEntry | null {\n  if (typeof window === 'undefined') {\n    return null\n  }\n  const isRevalidation = false\n  return getFromCacheMap(\n    now,\n    currentBfCacheVersion,\n    bfcacheMap,\n    varyPath,\n    isRevalidation,\n    false\n  )\n}\n"],"names":["UnknownDynamicStaleTime","computeDynamicStaleAt","invalidateBfCache","readFromBFCache","readFromBFCacheDuringRegularNavigation","updateBFCacheEntryStaleAt","writeHeadToBFCache","writeToBFCache","now","dynamicStaleTimeSeconds","DYNAMIC_STALETIME_MS","bfcacheMap","createCacheMap","currentBfCacheVersion","window","varyPath","rsc","prefetchRsc","head","prefetchHead","dynamicStaleAt","bfcacheId","entry","ref","size","navigatedAt","staleAt","version","status","EntryStatus","Fulfilled","isRevalidation","setInCacheMap","newStaleAt","getFromCacheMap"],"mappings":";;;;;;;;;;;;;;;;;;;;;IAOaA,uBAAuB;eAAvBA;;IAOGC,qBAAqB;eAArBA;;IAgDAC,iBAAiB;eAAjBA;;IAsGAC,eAAe;eAAfA;;IAoBAC,sCAAsC;eAAtCA;;IA1CAC,yBAAyB;eAAzBA;;IA3BAC,kBAAkB;eAAlBA;;IA9CAC,cAAc;eAAdA;;;iCArEqB;0BA6B9B;AAtBA,MAAMP,0BAA0B,CAAC;AAOjC,SAASC,sBACdO,GAAW,EACXC,uBAA+B;IAE/B,OAAOA,4BAA4BT,0BAC/BQ,MAAMC,0BAA0B,OAChCD,MAAME,qCAAoB;AAChC;AAqCA,MAAMC,aAAqCC,IAAAA,wBAAc;AAEzD,IAAIC,wBAAwB;AAErB,SAASX;IACd,IAAI,OAAOY,WAAW,aAAa;QACjC;IACF;IACAD;AACF;AAEO,SAASN,eACdC,GAAW,EACXO,QAAyB,EACzBC,GAAoB,EACpBC,WAA4B,EAC5BC,IAAqB,EACrBC,YAA6B,EAC7BC,cAAsB,EACtBC,SAAiB;IAEjB,IAAI,OAAOP,WAAW,aAAa;QACjC;IACF;IAEA,MAAMQ,QAAsB;QAC1BN;QACAC;QAEA,gEAAgE;QAChE,gEAAgE;QAChEC;QACAC;QAEAE;QAEAE,KAAK;QACL,yEAAyE;QACzE,uEAAuE;QACvE,qEAAqE;QACrE,0EAA0E;QAC1E,mDAAmD;QACnDC,MAAM;QAENC,aAAajB;QAEb,yEAAyE;QACzE,gFAAgF;QAChF,yBAAyB;QACzBkB,SAASN;QACTO,SAASd;QACTe,QAAQC,qBAAW,CAACC,SAAS;IAC/B;IACA,MAAMC,iBAAiB;IACvBC,IAAAA,uBAAa,EAACrB,YAAYI,UAAUO,OAAOS;AAC7C;AAEO,SAASzB,mBACdE,GAAW,EACXO,QAAyB,EACzBG,IAAqB,EACrBC,YAA6B,EAC7BC,cAAsB,EACtBC,SAAiB;IAEjB,4DAA4D;IAC5Dd,eACEC,KACAO,UACAG,MACAC,cACA,MACA,MACAC,gBACAC;AAEJ;AAQO,SAAShB,0BACdU,QAAyB,EACzBkB,UAAkB;IAElB,IAAI,OAAOnB,WAAW,aAAa;QACjC;IACF;IACA,MAAMiB,iBAAiB;IACvB,sEAAsE;IACtE,MAAMT,QAAQY,IAAAA,yBAAe,EAC3B,CAAC,GACDrB,uBACAF,YACAI,UACAgB,gBACA;IAEF,IAAIT,UAAU,MAAM;QAClBA,MAAMI,OAAO,GAAGO;IAClB;AACF;AAEO,SAAS9B,gBACdY,QAAyB;IAEzB,IAAI,OAAOD,WAAW,aAAa;QACjC,OAAO;IACT;IACA,MAAMiB,iBAAiB;IACvB,OAAOG,IAAAA,yBAAe,EACpB,yEAAyE;IACzE,iEAAiE;IACjE,oBAAoB;IACpB,CAAC,GACDrB,uBACAF,YACAI,UACAgB,gBACA;AAEJ;AAEO,SAAS3B,uCACdI,GAAW,EACXO,QAAyB;IAEzB,IAAI,OAAOD,WAAW,aAAa;QACjC,OAAO;IACT;IACA,MAAMiB,iBAAiB;IACvB,OAAOG,IAAAA,yBAAe,EACpB1B,KACAK,uBACAF,YACAI,UACAgB,gBACA;AAEJ","ignoreList":[0]}