{"version":3,"sources":["../../../../src/server/response-cache/index.ts"],"sourcesContent":["import type {\n  ResponseCacheEntry,\n  ResponseGenerator,\n  ResponseCacheBase,\n  IncrementalResponseCacheEntry,\n  IncrementalResponseCache,\n} from './types'\n\nimport { Batcher } from '../../lib/batcher'\nimport { LRUCache } from '../lib/lru-cache'\nimport { warnOnce } from '../../build/output/log'\nimport { scheduleOnNextTick } from '../../lib/scheduler'\nimport {\n  fromResponseCacheEntry,\n  routeKindToIncrementalCacheKind,\n  toResponseCacheEntry,\n} from './utils'\nimport type { RouteKind } from '../route-kind'\n\n/**\n * Parses an environment variable as a positive integer, returning the fallback\n * if the value is missing, not a number, or not positive.\n */\nfunction parsePositiveInt(\n  envValue: string | undefined,\n  fallback: number\n): number {\n  if (!envValue) return fallback\n  const parsed = parseInt(envValue, 10)\n  return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback\n}\n\n/**\n * Default TTL (in milliseconds) for minimal mode response cache entries.\n * Used for cache hit validation as a fallback for providers that don't\n * send the x-invocation-id header yet.\n *\n * 10 seconds chosen because:\n * - Long enough to dedupe rapid successive requests (e.g., page + data)\n * - Short enough to not serve stale data across unrelated requests\n *\n * Can be configured via `NEXT_PRIVATE_RESPONSE_CACHE_TTL` environment variable.\n */\nconst DEFAULT_TTL_MS = parsePositiveInt(\n  process.env.NEXT_PRIVATE_RESPONSE_CACHE_TTL,\n  10_000\n)\n\n/**\n * Default maximum number of entries in the response cache.\n * Can be configured via `NEXT_PRIVATE_RESPONSE_CACHE_MAX_SIZE` environment variable.\n */\nconst DEFAULT_MAX_SIZE = parsePositiveInt(\n  process.env.NEXT_PRIVATE_RESPONSE_CACHE_MAX_SIZE,\n  150\n)\n\n/**\n * Separator used in compound cache keys to join pathname and invocationID.\n * Using null byte (\\0) since it cannot appear in valid URL paths or UUIDs.\n */\nconst KEY_SEPARATOR = '\\0'\n\n/**\n * Sentinel value used for TTL-based cache entries (when invocationID is undefined).\n * Chosen to be a clearly reserved marker for internal cache keys.\n */\nconst TTL_SENTINEL = '__ttl_sentinel__'\n\n/**\n * Entry stored in the LRU cache.\n */\ntype CacheEntry = {\n  entry: IncrementalResponseCacheEntry | null\n  /**\n   * TTL expiration timestamp in milliseconds. Used as a fallback for\n   * cache hit validation when providers don't send x-invocation-id.\n   * Memory pressure is managed by LRU eviction rather than timers.\n   */\n  expiresAt: number\n}\n\n/**\n * Creates a compound cache key from pathname and invocationID.\n */\nfunction createCacheKey(\n  pathname: string,\n  invocationID: string | undefined\n): string {\n  return `${pathname}${KEY_SEPARATOR}${invocationID ?? TTL_SENTINEL}`\n}\n\n/**\n * Extracts the invocationID from a compound cache key.\n * Returns undefined if the key used TTL_SENTINEL.\n */\nfunction extractInvocationID(compoundKey: string): string | undefined {\n  const separatorIndex = compoundKey.lastIndexOf(KEY_SEPARATOR)\n  if (separatorIndex === -1) return undefined\n\n  const invocationID = compoundKey.slice(separatorIndex + 1)\n  return invocationID === TTL_SENTINEL ? undefined : invocationID\n}\n\nexport * from './types'\n\nexport default class ResponseCache implements ResponseCacheBase {\n  private readonly getBatcher = Batcher.create<\n    { key: string; isOnDemandRevalidate: boolean },\n    IncrementalResponseCacheEntry | null,\n    string\n  >({\n    // Ensure on-demand revalidate doesn't block normal requests, it should be\n    // safe to run an on-demand revalidate for the same key as a normal request.\n    cacheKeyFn: ({ key, isOnDemandRevalidate }) =>\n      `${key}-${isOnDemandRevalidate ? '1' : '0'}`,\n    // We wait to do any async work until after we've added our promise to\n    // `pendingResponses` to ensure that any any other calls will reuse the\n    // same promise until we've fully finished our work.\n    schedulerFn: scheduleOnNextTick,\n  })\n\n  private readonly revalidateBatcher = Batcher.create<\n    string,\n    IncrementalResponseCacheEntry | null\n  >({\n    // We wait to do any async work until after we've added our promise to\n    // `pendingResponses` to ensure that any any other calls will reuse the\n    // same promise until we've fully finished our work.\n    schedulerFn: scheduleOnNextTick,\n  })\n\n  /**\n   * LRU cache for minimal mode using compound keys (pathname + invocationID).\n   * This allows multiple invocations to cache the same pathname without\n   * overwriting each other's entries.\n   */\n  private readonly cache: LRUCache<CacheEntry>\n\n  /**\n   * Set of invocation IDs that have had cache entries evicted.\n   * Used to detect when the cache size may be too small.\n   * Bounded to prevent memory growth.\n   */\n  private readonly evictedInvocationIDs: Set<string> = new Set()\n\n  /**\n   * The configured max size, stored for logging.\n   */\n  private readonly maxSize: number\n\n  /**\n   * The configured TTL for cache entries in milliseconds.\n   */\n  private readonly ttl: number\n\n  // we don't use minimal_mode name here as this.minimal_mode is\n  // statically replace for server runtimes but we need it to\n  // be dynamic here\n  private minimal_mode?: boolean\n\n  constructor(\n    minimal_mode: boolean,\n    maxSize: number = DEFAULT_MAX_SIZE,\n    ttl: number = DEFAULT_TTL_MS\n  ) {\n    this.minimal_mode = minimal_mode\n    this.maxSize = maxSize\n    this.ttl = ttl\n\n    // Create the LRU cache with eviction tracking\n    this.cache = new LRUCache(maxSize, undefined, (compoundKey) => {\n      const invocationID = extractInvocationID(compoundKey)\n      if (invocationID) {\n        // Bound to 100 entries to prevent unbounded memory growth.\n        // FIFO eviction is acceptable here because:\n        // 1. Invocations are short-lived (single request lifecycle), so older\n        //    invocations are unlikely to still be active after 100 newer ones\n        // 2. This warning mechanism is best-effort for developer guidance—\n        //    missing occasional eviction warnings doesn't affect correctness\n        // 3. If a long-running invocation is somehow evicted and then has\n        //    another cache entry evicted, it will simply be re-added\n        if (this.evictedInvocationIDs.size >= 100) {\n          const first = this.evictedInvocationIDs.values().next().value\n          if (first) this.evictedInvocationIDs.delete(first)\n        }\n        this.evictedInvocationIDs.add(invocationID)\n      }\n    })\n  }\n\n  /**\n   * Gets the response cache entry for the given key.\n   *\n   * @param key - The key to get the response cache entry for.\n   * @param responseGenerator - The response generator to use to generate the response cache entry.\n   * @param context - The context for the get request.\n   * @returns The response cache entry.\n   */\n  public async get(\n    key: string | null,\n    responseGenerator: ResponseGenerator,\n    context: {\n      routeKind: RouteKind\n      isOnDemandRevalidate?: boolean\n      isPrefetch?: boolean\n      incrementalCache: IncrementalResponseCache\n      isRoutePPREnabled?: boolean\n      isFallback?: boolean\n      waitUntil?: (prom: Promise<any>) => void\n\n      /**\n       * The invocation ID from the infrastructure. Used to scope the\n       * in-memory cache to a single revalidation request in minimal mode.\n       */\n      invocationID?: string\n    }\n  ): Promise<ResponseCacheEntry | null> {\n    // If there is no key for the cache, we can't possibly look this up in the\n    // cache so just return the result of the response generator.\n    if (!key) {\n      return responseGenerator({\n        hasResolved: false,\n        previousCacheEntry: null,\n      })\n    }\n\n    // Check minimal mode cache before doing any other work.\n    if (this.minimal_mode) {\n      const cacheKey = createCacheKey(key, context.invocationID)\n      const cachedItem = this.cache.get(cacheKey)\n\n      if (cachedItem) {\n        // With invocationID: exact match found - always a hit\n        // With TTL mode: must check expiration\n        if (context.invocationID !== undefined) {\n          return toResponseCacheEntry(cachedItem.entry)\n        }\n\n        // TTL mode: check expiration\n        const now = Date.now()\n        if (cachedItem.expiresAt > now) {\n          return toResponseCacheEntry(cachedItem.entry)\n        }\n\n        // TTL expired - clean up\n        this.cache.remove(cacheKey)\n      }\n\n      // Warn if this invocation had entries evicted - indicates cache may be too small.\n      if (\n        context.invocationID &&\n        this.evictedInvocationIDs.has(context.invocationID)\n      ) {\n        warnOnce(\n          `Response cache entry was evicted for invocation ${context.invocationID}. ` +\n            `Consider increasing NEXT_PRIVATE_RESPONSE_CACHE_MAX_SIZE (current: ${this.maxSize}).`\n        )\n      }\n    }\n\n    const {\n      incrementalCache,\n      isOnDemandRevalidate = false,\n      isFallback = false,\n      isRoutePPREnabled = false,\n      isPrefetch = false,\n      waitUntil,\n      routeKind,\n      invocationID,\n    } = context\n\n    const response = await this.getBatcher.batch(\n      { key, isOnDemandRevalidate },\n      ({ resolve }) => {\n        const promise = this.handleGet(\n          key,\n          responseGenerator,\n          {\n            incrementalCache,\n            isOnDemandRevalidate,\n            isFallback,\n            isRoutePPREnabled,\n            isPrefetch,\n            routeKind,\n            invocationID,\n          },\n          resolve\n        )\n\n        // We need to ensure background revalidates are passed to waitUntil.\n        if (waitUntil) waitUntil(promise)\n\n        return promise\n      }\n    )\n\n    return toResponseCacheEntry(response)\n  }\n\n  /**\n   * Handles the get request for the response cache.\n   *\n   * @param key - The key to get the response cache entry for.\n   * @param responseGenerator - The response generator to use to generate the response cache entry.\n   * @param context - The context for the get request.\n   * @param resolve - The resolve function to use to resolve the response cache entry.\n   * @returns The response cache entry.\n   */\n  private async handleGet(\n    key: string,\n    responseGenerator: ResponseGenerator,\n    context: {\n      incrementalCache: IncrementalResponseCache\n      isOnDemandRevalidate: boolean\n      isFallback: boolean\n      isRoutePPREnabled: boolean\n      isPrefetch: boolean\n      routeKind: RouteKind\n      invocationID: string | undefined\n    },\n    resolve: (value: IncrementalResponseCacheEntry | null) => void\n  ): Promise<IncrementalResponseCacheEntry | null> {\n    let previousIncrementalCacheEntry: IncrementalResponseCacheEntry | null =\n      null\n    let resolved = false\n\n    try {\n      // Get the previous cache entry if not in minimal mode\n      previousIncrementalCacheEntry = !this.minimal_mode\n        ? await context.incrementalCache.get(key, {\n            kind: routeKindToIncrementalCacheKind(context.routeKind),\n            isRoutePPREnabled: context.isRoutePPREnabled,\n            isFallback: context.isFallback,\n          })\n        : null\n\n      if (previousIncrementalCacheEntry && !context.isOnDemandRevalidate) {\n        resolve(previousIncrementalCacheEntry)\n        resolved = true\n\n        if (!previousIncrementalCacheEntry.isStale || context.isPrefetch) {\n          // The cached value is still valid, so we don't need to update it yet.\n          return previousIncrementalCacheEntry\n        }\n      }\n\n      // Revalidate the cache entry\n      const incrementalResponseCacheEntry = await this.revalidate(\n        key,\n        context.incrementalCache,\n        context.isRoutePPREnabled,\n        context.isFallback,\n        responseGenerator,\n        previousIncrementalCacheEntry,\n        previousIncrementalCacheEntry !== null && !context.isOnDemandRevalidate,\n        undefined,\n        context.invocationID\n      )\n\n      // Handle null response\n      if (!incrementalResponseCacheEntry) {\n        // Remove the cache item if it was set so we don't use it again.\n        if (this.minimal_mode) {\n          const cacheKey = createCacheKey(key, context.invocationID)\n          this.cache.remove(cacheKey)\n        }\n        return null\n      }\n\n      // Resolve for on-demand revalidation or if not already resolved\n      if (context.isOnDemandRevalidate && !resolved) {\n        return incrementalResponseCacheEntry\n      }\n\n      return incrementalResponseCacheEntry\n    } catch (err) {\n      // If we've already resolved the cache entry, we can't reject as we\n      // already resolved the cache entry so log the error here.\n      if (resolved) {\n        console.error(err)\n        return null\n      }\n\n      throw err\n    }\n  }\n\n  /**\n   * Revalidates the cache entry for the given key.\n   *\n   * @param key - The key to revalidate the cache entry for.\n   * @param incrementalCache - The incremental cache to use to revalidate the cache entry.\n   * @param isRoutePPREnabled - Whether the route is PPR enabled.\n   * @param isFallback - Whether the route is a fallback.\n   * @param responseGenerator - The response generator to use to generate the response cache entry.\n   * @param previousIncrementalCacheEntry - The previous cache entry to use to revalidate the cache entry.\n   * @param hasResolved - Whether the response has been resolved.\n   * @param waitUntil - Optional function to register background work.\n   * @param invocationID - The invocation ID for cache key scoping.\n   * @returns The revalidated cache entry.\n   */\n  public async revalidate(\n    key: string,\n    incrementalCache: IncrementalResponseCache,\n    isRoutePPREnabled: boolean,\n    isFallback: boolean,\n    responseGenerator: ResponseGenerator,\n    previousIncrementalCacheEntry: IncrementalResponseCacheEntry | null,\n    hasResolved: boolean,\n    waitUntil?: (prom: Promise<any>) => void,\n    invocationID?: string\n  ) {\n    return this.revalidateBatcher.batch(key, () => {\n      const promise = this.handleRevalidate(\n        key,\n        incrementalCache,\n        isRoutePPREnabled,\n        isFallback,\n        responseGenerator,\n        previousIncrementalCacheEntry,\n        hasResolved,\n        invocationID\n      )\n\n      // We need to ensure background revalidates are passed to waitUntil.\n      if (waitUntil) waitUntil(promise)\n\n      return promise\n    })\n  }\n\n  private async handleRevalidate(\n    key: string,\n    incrementalCache: IncrementalResponseCache,\n    isRoutePPREnabled: boolean,\n    isFallback: boolean,\n    responseGenerator: ResponseGenerator,\n    previousIncrementalCacheEntry: IncrementalResponseCacheEntry | null,\n    hasResolved: boolean,\n    invocationID: string | undefined\n  ) {\n    try {\n      // Generate the response cache entry using the response generator.\n      const responseCacheEntry = await responseGenerator({\n        hasResolved,\n        previousCacheEntry: previousIncrementalCacheEntry,\n        isRevalidating: true,\n      })\n      if (!responseCacheEntry) {\n        return null\n      }\n\n      // Convert the response cache entry to an incremental response cache entry.\n      const incrementalResponseCacheEntry = await fromResponseCacheEntry({\n        ...responseCacheEntry,\n        isMiss: !previousIncrementalCacheEntry,\n      })\n\n      // We want to persist the result only if it has a cache control value\n      // defined.\n      if (incrementalResponseCacheEntry.cacheControl) {\n        if (this.minimal_mode) {\n          // Set TTL expiration for cache hit validation. Entries are validated\n          // by invocationID when available, with TTL as a fallback for providers\n          // that don't send x-invocation-id. Memory is managed by LRU eviction.\n          const cacheKey = createCacheKey(key, invocationID)\n          this.cache.set(cacheKey, {\n            entry: incrementalResponseCacheEntry,\n            expiresAt: Date.now() + this.ttl,\n          })\n        } else {\n          await incrementalCache.set(key, incrementalResponseCacheEntry.value, {\n            cacheControl: incrementalResponseCacheEntry.cacheControl,\n            isRoutePPREnabled,\n            isFallback,\n          })\n        }\n      }\n\n      return incrementalResponseCacheEntry\n    } catch (err) {\n      // When a path is erroring we automatically re-set the existing cache\n      // with new revalidate and expire times to prevent non-stop retrying.\n      if (previousIncrementalCacheEntry?.cacheControl) {\n        const revalidate = Math.min(\n          Math.max(\n            previousIncrementalCacheEntry.cacheControl.revalidate || 3,\n            3\n          ),\n          30\n        )\n        const expire =\n          previousIncrementalCacheEntry.cacheControl.expire === undefined\n            ? undefined\n            : Math.max(\n                revalidate + 3,\n                previousIncrementalCacheEntry.cacheControl.expire\n              )\n\n        await incrementalCache.set(key, previousIncrementalCacheEntry.value, {\n          cacheControl: { revalidate: revalidate, expire: expire },\n          isRoutePPREnabled,\n          isFallback,\n        })\n      }\n\n      // We haven't resolved yet, so let's throw to indicate an error.\n      throw err\n    }\n  }\n}\n"],"names":["Batcher","LRUCache","warnOnce","scheduleOnNextTick","fromResponseCacheEntry","routeKindToIncrementalCacheKind","toResponseCacheEntry","parsePositiveInt","envValue","fallback","parsed","parseInt","Number","isFinite","DEFAULT_TTL_MS","process","env","NEXT_PRIVATE_RESPONSE_CACHE_TTL","DEFAULT_MAX_SIZE","NEXT_PRIVATE_RESPONSE_CACHE_MAX_SIZE","KEY_SEPARATOR","TTL_SENTINEL","createCacheKey","pathname","invocationID","extractInvocationID","compoundKey","separatorIndex","lastIndexOf","undefined","slice","ResponseCache","constructor","minimal_mode","maxSize","ttl","getBatcher","create","cacheKeyFn","key","isOnDemandRevalidate","schedulerFn","revalidateBatcher","evictedInvocationIDs","Set","cache","size","first","values","next","value","delete","add","get","responseGenerator","context","hasResolved","previousCacheEntry","cacheKey","cachedItem","entry","now","Date","expiresAt","remove","has","incrementalCache","isFallback","isRoutePPREnabled","isPrefetch","waitUntil","routeKind","response","batch","resolve","promise","handleGet","previousIncrementalCacheEntry","resolved","kind","isStale","incrementalResponseCacheEntry","revalidate","err","console","error","handleRevalidate","responseCacheEntry","isRevalidating","isMiss","cacheControl","set","Math","min","max","expire"],"mappings":"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","ignoreList":[0]}