{"version":3,"sources":["../../../../src/server/app-render/vary-params.ts"],"sourcesContent":["import type { Params } from '../request/params'\nimport type { SearchParams } from '../request/search-params'\nimport { workUnitAsyncStorage } from './work-unit-async-storage.external'\nimport type {\n  VaryParamsThenable,\n  VaryParams,\n} from '../../shared/lib/segment-cache/vary-params-decoding'\n\n/**\n * Accumulates vary params for a single segment (or for metadata/rootParams).\n *\n * VaryParamsAccumulator is also a thenable that can be serialized by React\n * Flight. The accumulator starts as 'pending' and accumulates param accesses\n * during render. Call `finishTrackingVaryParams()` after rendering to resolve\n * all accumulators.\n *\n * The `status` and `value` fields follow the React Flight thenable protocol:\n * when `status === 'fulfilled'`, Flight can read `value` synchronously without\n * scheduling a microtask via `.then()`.\n */\nexport type VaryParamsAccumulator = {\n  // Mutable during render - accumulates param access\n  varyParams: VaryParams\n\n  // React thenable protocol fields\n  status: 'pending' | 'fulfilled'\n  value: VaryParams\n  then(\n    onfulfilled?: ((value: Set<string>) => unknown) | null,\n    onrejected?: ((reason: unknown) => unknown) | null\n  ): void\n\n  // Internal - callbacks waiting for resolution\n  resolvers: Array<(value: Set<string>) => void>\n}\n\n/**\n * A mutable data structure for accumulating per-segment vary params for an\n * entire server response. It's only used during prerenders. It describes\n * metadata about the response itself.\n */\nexport type ResponseVaryParamsAccumulator = {\n  /** Vary params accumulator for metadata/viewport (the \"head\" segment) */\n  head: VaryParamsAccumulator\n  /** Vary params accumulator for root params access */\n  rootParams: VaryParamsAccumulator\n  /** Vary params accumulators for each route segment */\n  segments: Set<VaryParamsAccumulator>\n}\n\nfunction createSegmentVaryParamsAccumulator(): VaryParamsAccumulator {\n  const accumulator: VaryParamsAccumulator = {\n    varyParams: new Set(),\n    status: 'pending',\n    value: new Set(),\n    then(onfulfilled: ((value: Set<string>) => unknown) | null | undefined) {\n      if (onfulfilled) {\n        if (accumulator.status === 'pending') {\n          accumulator.resolvers.push(onfulfilled)\n        } else {\n          onfulfilled(accumulator.value)\n        }\n      }\n    },\n    resolvers: [],\n  }\n  return accumulator\n}\n\n/**\n * A singleton accumulator that's already resolved to an empty Set. Use this for\n * segments where we know upfront that no params will be accessed, such as\n * client components or segments without user code.\n *\n * Benefits:\n * - No need to accumulate or resolve later\n * - Resilient: resolves correctly even if other tracking fails\n * - Memory efficient: reuses the same object\n */\nconst emptySet: VaryParams = new Set()\nexport const emptyVaryParamsAccumulator: VaryParamsAccumulator = {\n  varyParams: emptySet,\n  status: 'fulfilled',\n  value: emptySet,\n  then(onfulfilled: ((value: Set<string>) => unknown) | null | undefined) {\n    if (onfulfilled) {\n      onfulfilled(emptySet)\n    }\n  },\n  resolvers: [],\n}\n\nexport function createResponseVaryParamsAccumulator(): ResponseVaryParamsAccumulator {\n  // Create the head and rootParams accumulators as top-level fields.\n  // Segment accumulators are added to the segments set as they are created.\n  const head = createSegmentVaryParamsAccumulator()\n  const rootParams = createSegmentVaryParamsAccumulator()\n  const segments = new Set<VaryParamsAccumulator>()\n\n  return {\n    head,\n    rootParams,\n    segments,\n  }\n}\n\n/**\n * Allocates a new VaryParamsAccumulator and adds it to the response accumulator\n * associated with the current WorkUnitStore.\n *\n * Returns a thenable that resolves to the segment's vary params once rendering\n * is complete. The thenable can be passed directly to React Flight for\n * serialization.\n */\nexport function createVaryParamsAccumulator(): VaryParamsAccumulator | null {\n  const workUnitStore = workUnitAsyncStorage.getStore()\n  if (workUnitStore) {\n    switch (workUnitStore.type) {\n      case 'prerender':\n      case 'prerender-runtime': {\n        const responseAccumulator = workUnitStore.varyParamsAccumulator\n        if (responseAccumulator !== null) {\n          const accumulator = createSegmentVaryParamsAccumulator()\n          responseAccumulator.segments.add(accumulator)\n          return accumulator\n        }\n        return null\n      }\n      case 'prerender-ppr':\n      case 'prerender-legacy':\n      case 'request':\n      case 'cache':\n      case 'private-cache':\n      case 'prerender-client':\n      case 'validation-client':\n      case 'unstable-cache':\n      case 'generate-static-params':\n        break\n      default:\n        workUnitStore satisfies never\n    }\n  }\n  return null\n}\n\nexport function getMetadataVaryParamsAccumulator(): VaryParamsAccumulator | null {\n  const workUnitStore = workUnitAsyncStorage.getStore()\n  if (workUnitStore) {\n    switch (workUnitStore.type) {\n      case 'prerender':\n      case 'prerender-runtime': {\n        const responseAccumulator = workUnitStore.varyParamsAccumulator\n        if (responseAccumulator !== null) {\n          return responseAccumulator.head\n        }\n        return null\n      }\n      case 'prerender-ppr':\n      case 'prerender-legacy':\n      case 'request':\n      case 'cache':\n      case 'private-cache':\n      case 'prerender-client':\n      case 'validation-client':\n      case 'unstable-cache':\n      case 'generate-static-params':\n        return null\n      default:\n        workUnitStore satisfies never\n    }\n  }\n  return null\n}\n\nexport function getVaryParamsThenable(\n  accumulator: VaryParamsAccumulator\n): VaryParamsThenable | null {\n  return accumulator as unknown as VaryParamsThenable | null\n}\n\nexport function getMetadataVaryParamsThenable(): VaryParamsThenable | null {\n  const accumulator = getMetadataVaryParamsAccumulator()\n  if (accumulator !== null) {\n    return getVaryParamsThenable(accumulator)\n  }\n  return null\n}\n\n// The metadata and viewport are always delivered in a single payload, so they\n// don't need to be tracked separately. This may change in the future, but for\n// now this is just an alias.\nexport const getViewportVaryParamsAccumulator = getMetadataVaryParamsAccumulator\n\nexport function getRootParamsVaryParamsAccumulator(): VaryParamsAccumulator | null {\n  const workUnitStore = workUnitAsyncStorage.getStore()\n  if (workUnitStore) {\n    switch (workUnitStore.type) {\n      case 'prerender':\n      case 'prerender-runtime': {\n        const responseAccumulator = workUnitStore.varyParamsAccumulator\n        if (responseAccumulator !== null) {\n          return responseAccumulator.rootParams\n        }\n        return null\n      }\n      case 'prerender-ppr':\n      case 'prerender-legacy':\n      case 'request':\n      case 'cache':\n      case 'private-cache':\n      case 'prerender-client':\n      case 'validation-client':\n      case 'unstable-cache':\n      case 'generate-static-params':\n        return null\n      default:\n        workUnitStore satisfies never\n    }\n  }\n  return null\n}\n\n/**\n * Records that a param was accessed. Adds the param name to the accumulator's\n * varyParams set.\n */\nexport function accumulateVaryParam(\n  accumulator: VaryParamsAccumulator,\n  paramName: string\n): void {\n  accumulator.varyParams.add(paramName)\n}\n\n/**\n * Records a root param access.\n */\nexport function accumulateRootVaryParam(paramName: string): void {\n  const rootParamsAccumulator = getRootParamsVaryParamsAccumulator()\n  if (rootParamsAccumulator !== null) {\n    accumulateVaryParam(rootParamsAccumulator, paramName)\n  }\n}\n\nexport function createVaryingParams(\n  accumulator: VaryParamsAccumulator,\n  originalParamsObject: Params,\n  optionalCatchAllParamName: string | null\n): Params {\n  if (optionalCatchAllParamName !== null) {\n    // When there's an optional catch-all param with no value (e.g.,\n    // [[...slug]] at /), the param doesn't exist as a property on the params\n    // object. Use a Proxy to track all param access — both existing params\n    // and the missing optional param — including enumeration patterns like\n    // Object.keys(), spread, for...in, and `in` checks.\n    return new Proxy(originalParamsObject, {\n      get(target, prop, receiver) {\n        if (typeof prop === 'string') {\n          if (\n            prop === optionalCatchAllParamName ||\n            Object.prototype.hasOwnProperty.call(target, prop)\n          ) {\n            accumulateVaryParam(accumulator, prop)\n          }\n        }\n        return Reflect.get(target, prop, receiver)\n      },\n      has(target, prop) {\n        if (prop === optionalCatchAllParamName) {\n          accumulateVaryParam(accumulator, optionalCatchAllParamName)\n        }\n        return Reflect.has(target, prop)\n      },\n      ownKeys(target) {\n        // Enumerating the params object means the user's code may depend on\n        // which params are present, so conservatively track the optional\n        // param as accessed.\n        accumulateVaryParam(accumulator, optionalCatchAllParamName)\n        return Reflect.ownKeys(target)\n      },\n    })\n  }\n\n  // When there's no optional catch-all, all params exist as properties on the\n  // object, so we can use defineProperty getters instead of a Proxy. This is\n  // faster because the engine can optimize property access on regular objects\n  // more aggressively than Proxy trap calls.\n  const underlyingParamsWithVarying: Params = {}\n  for (const paramName in originalParamsObject) {\n    Object.defineProperty(underlyingParamsWithVarying, paramName, {\n      get() {\n        accumulateVaryParam(accumulator, paramName)\n        return originalParamsObject[paramName]\n      },\n      enumerable: true,\n    })\n  }\n  return underlyingParamsWithVarying\n}\n\nexport function createVaryingSearchParams(\n  accumulator: VaryParamsAccumulator,\n  originalSearchParamsObject: SearchParams\n): SearchParams {\n  const underlyingSearchParamsWithVarying: SearchParams = {}\n  for (const searchParamName in originalSearchParamsObject) {\n    Object.defineProperty(underlyingSearchParamsWithVarying, searchParamName, {\n      get() {\n        // TODO: Unlike path params, we don't vary track each search param\n        // individually. The entire search string is treated as a single param.\n        // This may change in the future.\n        accumulateVaryParam(accumulator, '?')\n        return originalSearchParamsObject[searchParamName]\n      },\n      enumerable: true,\n    })\n  }\n  return underlyingSearchParamsWithVarying\n}\n\n/**\n * Resolves all segment accumulators in a ResponseVaryParamsAccumulator with\n * their final vary params. Call this after rendering is complete.\n *\n * Each segment's thenable is resolved with its vary params merged with the\n * root params. If we can't track vary params (e.g., legacy prerender), simply\n * don't call this function - the client treats unresolved thenables as\n * \"unknown\" vary params.\n */\nexport async function finishAccumulatingVaryParams(\n  responseAccumulator: ResponseVaryParamsAccumulator\n): Promise<void> {\n  const rootVaryParams = responseAccumulator.rootParams.varyParams\n\n  // Resolve head\n  finishSegmentAccumulator(responseAccumulator.head, rootVaryParams)\n\n  // Resolve each segment\n  for (const segmentAccumulator of responseAccumulator.segments) {\n    finishSegmentAccumulator(segmentAccumulator, rootVaryParams)\n  }\n\n  // Now that the thenables are resolved, Flight should be able to flush the\n  // vary params into the response stream. This work gets scheduled internally\n  // by Flight using a microtask as soon as we notify the thenable listeners.\n  //\n  // We need to ensure that Flight's pending queues are emptied before this\n  // function returns; the caller will abort the prerender immediately after.\n  // We can't use a macrotask, because that would allow dynamic IO to sneak\n  // into the response. So we use microtasks instead.\n  //\n  // The exact number of awaits here isn't important (indeed, one seems to be\n  // sufficient, at the time of writing), as long as we wait enough ticks for\n  // Flight to finish writing the response.\n  //\n  // Anything that remains in Flight's internal queue after these awaits must\n  // be actual dynamic IO, not caused by pending vary params tasks. In other\n  // words, failing to do this would cause us to treat a fully static prerender\n  // as if it were partially dynamic.\n  await Promise.resolve()\n  await Promise.resolve()\n  await Promise.resolve()\n}\n\nfunction finishSegmentAccumulator(\n  accumulator: VaryParamsAccumulator,\n  rootVaryParams: VaryParams\n): void {\n  if (accumulator.status !== 'pending') {\n    return\n  }\n  const merged = new Set<string>(accumulator.varyParams)\n  for (const param of rootVaryParams) {\n    merged.add(param)\n  }\n  accumulator.value = merged\n  accumulator.status = 'fulfilled'\n  for (const resolver of accumulator.resolvers) {\n    resolver(merged)\n  }\n  accumulator.resolvers = []\n}\n"],"names":["workUnitAsyncStorage","createSegmentVaryParamsAccumulator","accumulator","varyParams","Set","status","value","then","onfulfilled","resolvers","push","emptySet","emptyVaryParamsAccumulator","createResponseVaryParamsAccumulator","head","rootParams","segments","createVaryParamsAccumulator","workUnitStore","getStore","type","responseAccumulator","varyParamsAccumulator","add","getMetadataVaryParamsAccumulator","getVaryParamsThenable","getMetadataVaryParamsThenable","getViewportVaryParamsAccumulator","getRootParamsVaryParamsAccumulator","accumulateVaryParam","paramName","accumulateRootVaryParam","rootParamsAccumulator","createVaryingParams","originalParamsObject","optionalCatchAllParamName","Proxy","get","target","prop","receiver","Object","prototype","hasOwnProperty","call","Reflect","has","ownKeys","underlyingParamsWithVarying","defineProperty","enumerable","createVaryingSearchParams","originalSearchParamsObject","underlyingSearchParamsWithVarying","searchParamName","finishAccumulatingVaryParams","rootVaryParams","finishSegmentAccumulator","segmentAccumulator","Promise","resolve","merged","param","resolver"],"mappings":"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","ignoreList":[0]}