only be loaded in Node environments.
 */

import type { Tracer } from '@opentelemetry/api'
import {
  type WorkUnitStore,
  workUnitAsyncStorage,
} from '../../app-render/work-unit-async-storage.external'
import { InvariantError } from '../../../shared/lib/invariant-error'
import { isUseCacheFunction } from '../../../lib/client-and-server-references'

export function afterRegistration(): void {
  if (process.env.NEXT_RUNTIME === 'edge') {
    throw new InvariantError(
      'Node.js instrumentation extensio

ight load instrumentation before nextConfig is available
// and so gating it on the config might lead to skipping this extension even when it is necessary.
// When cacheComponents is disabled this extension should be a no-op so we enable it universally.
//

ns should not be loaded in the Edge runtime.'
    )
  }

  extendTracerProviderForCacheComponents()
}

// In theory we only want to enable this extension when cacheComponents is enabled
// however there are certain servers that m


m '../../request-meta'

import url from 'url'
import { stringifyQuery } from '../../server-route-utils'
import { Duplex } from 'stream'
import { DetachedPromise } from '../../../lib/detached-promise'

export async function proxyRequest(
  req: IncomingMessage,
  res: ServerResponse | Duplex,
  parsedUrl: NextUrlWithParsedQuery,
  upgradeHead?: Buffer,
  reqBody?: any,
  proxyTimeout?: number | null
) {
  const { query } = parsedUrl
  delete (parsedUrl as any).query
  parsedUrl.search = stringifyQuery(req as

: true,
    ignorePath: true,
    ws: true,
    // we limit proxy requests to 30s by default, in development
    // we don't time out WebSocket requests to allow proxying
    proxyTimeout: proxyTimeout === null ? undefined : proxyTimeout || 30_000,
    hea

 any, query)

  const target = url.format(parsedUrl)
  const HttpProxy =
    require('next/dist/compiled/http-proxy') as typeof import('next/dist/compiled/http-proxy')

  const proxy = new HttpProxy({
    target,
    changeOrigin


s'
import { formatHostname } from '../format-hostname'
import { toNodeOutgoingHttpHeaders } from '../../web/utils'
import { isAbortError } from '../../pipe-readable'
import { getHostname } from '../../../shared/lib/get-hostname'
import {
  getRedirectStatus,
  allowedStatusCodes,
} from '../../../lib/redirect-status'
import { normalizeRepeatedSlashes } from '../../../shared/lib/utils'
import { getRelativeURL } from '../../../shared/lib/router/utils/relativize-url'
import { addPathPrefix } from '../../../sha

./../shared/lib/i18n/detect-domain-locale'
import { normalizeLocalePath } from '../../../shared/lib/i18n/normalize-locale-path'
import { removePathPrefix } from '../../../shared/lib/router/utils/remove-path-prefix'
import { NextDataPathnameNormalizer } fro

red/lib/router/utils/add-path-prefix'
import { pathHasPrefix } from '../../../shared/lib/router/utils/path-has-prefix'
import { parseUrl } from '../../../shared/lib/router/utils/parse-url'
import { detectDomainLocale } from '../.


lib/try-to-parse-path'
import {
  extractInterceptionRouteInformation,
  isInterceptionRouteAppPath,
} from '../../../shared/lib/router/utils/interception-routes'
import {
  UNDERSCORE_GLOBAL_ERROR_ROUTE,
  UNDERSCORE_NOT_FOUND_ROUTE,
} from '../../../shared/lib/entry-constants'
import { normalizePathSep } from '../../../shared/lib/page-path/normalize-path-sep'
import type { RouteInfo, SlotInfo } from '../../../build/file-classifier'
import type {
  RootParamInfo,
  RootParamValueType,
} from './root-params

, ManifestRouteInfo>
  pageRoutes: Record<string, ManifestRouteInfo>
  layoutRoutes: Record<string, ManifestRouteInfo & { slots: string[] }>
  appRouteHandlerRoutes: Record<string, ManifestRouteInfo>
  /** Map of redirect source => ManifestRouteInfo */
  r

-type-utils'

// Internal route info with extracted params for the manifest
interface ManifestRouteInfo {
  path: string
  groups: { [groupName: string]: Group }
}

export interface RouteTypesManifest {
  appRoutes: Record<string


Routes = never\n'
  }

  // Generate RedirectRoutes union type
  if (redirectRoutes.length > 0) {
    result += `type RedirectRoutes = ${redirectRoutes
      .map((route) => JSON.stringify(route))
      .join(' | ')}\n`
  } else {
    result += 'type RedirectRoutes = never\n'
  }

  // Generate RewriteRoutes union type
  if (rewriteRoutes.length > 0) {
    result += `type RewriteRoutes = ${rewriteRoutes
      .map((route) => JSON.stringify(route))
      .join(' | ')}\n`
  } else {
    result += 'type Rewrit

iteRoutes',
  ]
  if (hasAppRouteHandlers) {
    routeUnionParts.push('AppRouteHandlerRoutes')
  }

  result += `type Routes = ${routeUnionParts.join(' | ')}\n`

  return result
}

function generateParamTypes(routesManifest: RouteTypesManifest): string {

eRoutes = never\n'
  }

  // Only include AppRouteHandlerRoutes in Routes union if there are actual route handlers
  const routeUnionParts = [
    'AppRoutes',
    'PageRoutes',
    'LayoutRoutes',
    'RedirectRoutes',
    'Rewr


an names defined here.
 **/

// eslint typescript has a bug with TS enums

enum BaseServerSpan {
  handleRequest = 'BaseServer.handleRequest',
  run = 'BaseServer.run',
  pipe = 'BaseServer.pipe',
  getStaticHTML = 'BaseServer.getStaticHTML',
  render = 'BaseServer.render',
  renderToResponseWithComponents = 'BaseServer.renderToResponseWithComponents',
  renderToResponse = 'BaseServer.renderToResponse',
  renderToHTML = 'BaseServer.renderToHTML',
  renderError = 'BaseServer.renderError',
  renderErrorToResp

mponents',
  loadComponents = 'LoadComponents.loadComponents',
}

enum NextServerSpan {
  getRequestHandler = 'NextServer.getRequestHandler',
  getRequestHandlerWithMetadata = 'NextServer.getRequestHandlerWithMetadata',
  getServer = 'NextServer.getServer'

onse = 'BaseServer.renderErrorToResponse',
  renderErrorToHTML = 'BaseServer.renderErrorToHTML',
  render404 = 'BaseServer.render404',
}

enum LoadComponentsSpan {
  loadDefaultErrorComponents = 'LoadComponents.loadDefaultErrorCo


h warming up an entry that's
 * likely going to get evicted before we get to use it anyway. However, we also
 * don't want to reuse a stale entry for too long so stale entries should be
 * considered expired/missing in such cache handlers.
 */

import { LRUCache } from '../lru-cache'
import type { CacheEntry, CacheHandler } from './types'
import {
  areTagsExpired,
  areTagsStale,
  tagsManifest,
  type TagManifestEntry,
} from '../incremental-cache/tags-manifest.external'

type PrivateCacheEntry = {
  entr

ree times so that we retry hitting origin (MISS)
  // and then if it still fails to set after the third we
  // return the errored content and use expiration of
  // Math.min(30, entry.expiration)
  isErrored: boolean
  errorRetryCount: number

  // comput

y: CacheEntry

  // For the default cache we store errored cache
  // entries and allow them to be used up to 3 times
  // after that we want to dispose it and try for fresh

  // If an entry is errored we return no entry
  // th


xt,
  type SetIncrementalResponseCacheContext,
} from '../../response-cache'

import type { LRUCache } from '../lru-cache'
import path from '../../../shared/lib/isomorphic/path'
import {
  NEXT_CACHE_TAGS_HEADER,
  NEXT_DATA_SUFFIX,
  NEXT_META_SUFFIX,
  RSC_SEGMENT_SUFFIX,
  RSC_SEGMENTS_DIR_SUFFIX,
  RSC_SUFFIX,
} from '../../../lib/constants'
import { areTagsExpired, tagsManifest } from './tags-manifest.external'
import { MultiFileWriter } from '../../../lib/multi-file-writer'
import { getMemoryCache } f

ivate fs: FileSystemCacheContext['fs']
  private flushToDisk?: FileSystemCacheContext['flushToDisk']
  private serverDistDir: FileSystemCacheContext['serverDistDir']
  private revalidatedTags: string[]
  private static debug: boolean = !!process.env.NEXT_P

rom './memory-cache.external'

type FileSystemCacheContext = Omit<
  CacheHandlerContext,
  'fs' | 'serverDistDir'
> & {
  fs: CacheFs
  serverDistDir: string
}

export default class FileSystemCache implements CacheHandler {
  pr


CHE_TAGS_HEADER,
  PRERENDER_REVALIDATE_HEADER,
} from '../../../lib/constants'
import { toRoute } from '../to-route'
import { SharedCacheControls } from './shared-cache-controls.external'
import {
  getResumeDataCache,
  workUnitAsyncStorage,
} from '../../app-render/work-unit-async-storage.external'
import { InvariantError } from '../../../shared/lib/invariant-error'
import type { Revalidate } from '../cache-control'
import { getPreviouslyRevalidatedTags } from '../../server-utils'
import { workAsyncStora

t {
  fs?: CacheFs
  dev?: boolean
  flushToDisk?: boolean
  serverDistDir?: string
  maxMemoryCacheSize?: number
  fetchCacheKeyPrefix?: string
  prerenderManifest?: PrerenderManifest
  revalidatedTags: string[]
  _requestHeaders: IncrementalCache['reques

ge } from '../../app-render/work-async-storage.external'
import { DetachedPromise } from '../../../lib/detached-promise'
import { areTagsExpired, areTagsStale } from './tags-manifest.external'

export interface CacheHandlerContex


ild'
import type { DeepReadonly } from '../../../shared/lib/deep-readonly'
import type { CacheControl } from '../cache-control'

/**
 * A shared cache of cache controls for routes. This cache is used so we don't
 * have to modify the prerender manifest when we want to update the cache
 * control for a route.
 */
export class SharedCacheControls {
  /**
   * The in-memory cache of cache lives for routes. This cache is populated when
   * the cache is updated with new cache lives.
   */
  private static reado

     Pick<PrerenderManifest, 'routes' | 'dynamicRoutes'>
    >
  ) {}

  /**
   * Try to get the cache control value for a route. This will first try to get
   * the value from the in-memory cache. If the value is not present in the
   * in-memory cache, i

nly cacheControls = new Map<string, CacheControl>()

  constructor(
    /**
     * The prerender manifest that contains the initial cache controls for
     * routes.
     */
    private readonly prerenderManifest: DeepReadonly<


./../../lib/is-error'
import { INSTRUMENTATION_HOOK_FILENAME } from '../../../lib/constants'
import type {
  InstrumentationModule,
  InstrumentationOnRequestError,
} from '../../instrumentation/types'
import { interopDefault } from '../../../lib/interop-default'
import { afterRegistration as extendInstrumentationAfterRegistration } from './instrumentation-node-extensions'

let cachedInstrumentationModule: InstrumentationModule

export async function getInstrumentationModule(
  projectDir: string,
  distDir

.join(
          projectDir,
          distDir,
          'server',
          `${INSTRUMENTATION_HOOK_FILENAME}.js`
        )
      )
    )
    return cachedInstrumentationModule
  } catch (err: unknown) {
    if (
      isError(err) &&
      err.code !==

: string
): Promise<InstrumentationModule | undefined> {
  if (cachedInstrumentationModule) {
    return cachedInstrumentationModule
  }

  try {
    cachedInstrumentationModule = interopDefault(
      await require(
        path


../base-http/node'
import type { WebNextRequest } from '../../../base-http/web'
import type { Writable } from 'node:stream'

import { getRequestMeta } from '../../../request-meta'
import { fromNodeOutgoingHttpHeaders } from '../../utils'
import { NextRequest } from '../request'
import { isNodeNextRequest, isWebNextRequest } from '../../../base-http/helpers'

export const ResponseAbortedName = 'ResponseAborted'
export class ResponseAborted extends Error {
  public readonly name = ResponseAbortedName
}

/**

eateAbortController(response: Writable): AbortController {
  const controller = new AbortController()

  // If `finish` fires first, then `res.end()` has been called and the close is
  // just us finishing the stream on our side. If `close` fires first, th

* Creates an AbortController tied to the closing of a ServerResponse (or other
 * appropriate Writable).
 *
 * If the `close` event is fired before the `finish` event, then we'll send the
 * `abort` signal.
 */
export function cr


esAdapter,
  MutableRequestCookiesAdapter,
} from './request-cookies'

describe('RequestCookiesAdapter', () => {
  it('should be able to create a new instance from a RequestCookies', () => {
    const headers = new Headers({ cookie: 'foo=bar; bar=foo' })
    const cookies = new RequestCookies(headers)

    const sealed = RequestCookiesAdapter.seal(cookies)
    expect(sealed).toBeInstanceOf(RequestCookies)

    expect(sealed.get('foo')).toEqual({ name: 'foo', value: 'bar' })
    expect(sealed.get('bar')).toE

any).delete('foo')).toThrow(
      ReadonlyRequestCookiesError
    )
    expect(() => (sealed as any).clear()).toThrow(ReadonlyRequestCookiesError)

    // Ensure nothing was actually changed.
    expect(sealed.get('foo')).toEqual({ name: 'foo', value: 'ba

qual({ name: 'bar', value: 'foo' })

    // These methods are not available on the sealed instance
    expect(() => (sealed as any).set('foo', 'bar2')).toThrow(
      ReadonlyRequestCookiesError
    )
    expect(() => (sealed as


e.external'
import type { RequestStore } from '../../../app-render/work-unit-async-storage.external'
import { ActionDidRevalidateStaticAndDynamic } from '../../../../shared/lib/action-revalidation-kind'

/**
 * @internal
 */
export class ReadonlyRequestCookiesError extends Error {
  constructor() {
    super(
      'Cookies can only be modified in a Server Action or Route Handler. Read more: https://nextjs.org/docs/app/api-reference/functions/cookies#options'
    )
  }

  public static callable() {
    thro

methods,
// we want to return the request cookie if it exists. For mutative methods like `.set()`,
// we want to return the response cookie.
export type ReadonlyRequestCookies = Omit<
  RequestCookies,
  'set' | 'clear' | 'delete'
> &
  Pick<ResponseCookie

w new ReadonlyRequestCookiesError()
  }
}

// We use this to type some APIs but we don't construct instances directly
export type { ResponseCookies }

// The `cookies()` API is a mix of request and response cookies. For `.get()`


 { validateURL } from '../utils'

jest.mock('../utils', () => ({
  ...jest.requireActual('../utils'),
  validateURL: jest.fn(jest.requireActual('../utils').validateURL),
}))

const mockedValidateURL = jest.mocked(validateURL)

describe('Next.js sandbox Request constructor', () => {
  let moduleContext: any

  beforeEach(async () => {
    mockedValidateURL.mockClear()
    moduleContext = await getModuleContext({
      moduleName: 'test-module',
      onError: () => {},
      onWarning: () => {},
      useCac

const { Request: NextRequest } = moduleContext.runtime.context

    const originalRequest = new NextRequest('https://example.com', {
      method: 'POST',
    })
    expect(originalRequest.method).toBe('POST')

    const copiedRequest = new NextRequest(ori

he: false,
      distDir: '/tmp',
      edgeFunctionEntry: {
        assets: [],
        wasm: [],
        env: {},
      },
    })
  })

  it('should preserve Request method when copying Request in Next.js context', () => {


mplementation from 'node:assert'
import UtilImplementation from 'node:util'
import AsyncHooksImplementation from 'node:async_hooks'
import { intervalsManager, timeoutsManager } from './resource-managers'
import { createLocalRequestContext } from '../../after/builtin-request-context'
import {
  patchErrorInspectEdgeLite,
  patchErrorInspectNodeJS,
} from '../../patch-error-inspect'

interface ModuleContext {
  runtime: EdgeRuntime
  paths: Map<string, string>
  warnedEvals: Set<string>
}

let getServerError:

equire('../../dev/node-stack-frames') as typeof import('../../dev/node-stack-frames') as typeof import('../../dev/node-stack-frames')
  ).getServerError
  decorateServerError = (
    require('../../../shared/lib/error-source') as typeof import('../../../sh

 typeof import('../../dev/node-stack-frames').getServerError
let decorateServerError: typeof import('../../../shared/lib/error-source').decorateServerError

if (process.env.NODE_ENV === 'development') {
  getServerError = (
    r


{ EdgeFunctionDefinition } from '../../../build/webpack/plugins/middleware-plugin'
import { createReadStream, promises as fs } from 'fs'
import { requestToBodyStream } from '../../body-streams'
import { resolve } from 'path'

/**
 * Short-circuits the `fetch` function
 * to return a stream for a given asset, if a user used `new URL("file", import.meta.url)`.
 * This allows to embed assets in Edge Runtime.
 */
export async function fetchInlineAsset(options: {
  input: RequestInfo | URL
  distDir: string
  as

'blob:')) {
    return
  }

  const name = inputString.replace('blob:', '')
  const asset = options.assets
    ? options.assets.find((x) => x.name === name)
    : {
        name,
        filePath: name,
      }
  if (!asset) {
    return
  }

  const fileP

sets: EdgeFunctionDefinition['assets']
  context: { Response: typeof Response; ReadableStream: typeof ReadableStream }
}): Promise<Response | undefined> {
  const inputString = String(options.input)
  if (!inputString.startsWith(


 resources: T[] = []

  abstract create(resourceArgs: Args): T
  abstract destroy(resource: T): void

  add(resourceArgs: Args) {
    const resource = this.create(resourceArgs)
    this.resources.push(resource)
    return resource
  }

  remove(resource: T) {
    this.resources = this.resources.filter((r) => r !== resource)
    this.destroy(resource)
  }

  removeAll() {
    this.resources.forEach(this.destroy)
    this.resources = []
  }
}

class IntervalsManager extends ResourceManager<
  number,
  Parame

rInterval(interval)
  }
}

class TimeoutsManager extends ResourceManager<
  number,
  Parameters<typeof setTimeout>
> {
  create(args: Parameters<typeof setTimeout>) {
    // TODO: use the edge runtime provided `setTimeout` instead
    return webSetTimeout

ters<typeof setInterval>
> {
  create(args: Parameters<typeof setInterval>) {
    // TODO: use the edge runtime provided `setInterval` instead
    return webSetIntervalPolyfill(...args)
  }

  destroy(interval: number) {
    clea


st/compiled/edge-runtime'
import {
  getModuleContext,
  requestStore,
  edgeSandboxNextRequestContext,
} from './context'
import { requestToBodyStream } from '../../body-streams'
import type { ServerComponentsHmrCache } from '../../response-cache'
import {
  getBuiltinRequestContext,
  type BuiltinRequestContextValue,
} from '../../after/builtin-request-context'
import {
  RouterServerContextSymbol,
  routerServerGlobal,
} from '../../lib/router-utils/router-server-context'
import type { EdgeHandler } from

) => void
  onWarning?: (warn: Error) => void
  paths: string[]
  request: NodejsRequestData
  useCache: boolean
  edgeFunctionEntry: Pick<EdgeFunctionDefinition, 'assets' | 'wasm' | 'env'>
  distDir: string
  incrementalCache?: any
  serverComponentsHmrCa

 '../adapter'

export const ErrorSource = Symbol('SandboxError')

const FORBIDDEN_HEADERS = [
  'content-length',
  'content-encoding',
  'transfer-encoding',
]

interface RunnerFnParams {
  name: string
  onError?: (err: unknown


 const NEXT_TS_ERRORS = {
  INVALID_SERVER_API: 71001,
  INVALID_ENTRY_EXPORT: 71002,
  INVALID_OPTION_VALUE: 71003,
  MISPLACED_ENTRY_DIRECTIVE: 71004,
  INVALID_PAGE_PROP: 71005,
  INVALID_CONFIG_OPTION: 71006,
  INVALID_CLIENT_ENTRY_PROP: 71007,
  INVALID_METADATA_EXPORT: 71008,
  INVALID_ERROR_COMPONENT: 71009,
  INVALID_ENTRY_DIRECTIVE: 71010,
  INVALID_SERVER_ENTRY_RETURN: 71011,
}

export const ALLOWED_EXPORTS = [
  'config',
  'generateStaticParams',
  'metadata',
  'generateMetadata',
  'viewport',

erativeHandle',
  'useInsertionEffect',
  'useReducer',
  'useRef',
  'useSyncExternalStore',
  'useTransition',
  'Component',
  'PureComponent',
  'createContext',
  'createFactory',
  'experimental_useOptimistic',
  'useOptimistic',
  'useActionState',

  'generateViewport',
]

export const LEGACY_CONFIG_EXPORT = 'config'

export const DISALLOWED_SERVER_REACT_APIS: string[] = [
  'useState',
  'useEffect',
  'useEffectEvent',
  'useLayoutEffect',
  'useDeferredValue',
  'useImp


port,
  isPositionInsideNode,
  getSource,
  isInsideApp,
} from './utils'
import { NEXT_TS_ERRORS } from './constant'

import entryConfig from './rules/config'
import serverLayer from './rules/server'
import entryDefault from './rules/entry'
import clientBoundary from './rules/client-boundary'
import serverBoundary from './rules/server-boundary'
import metadata from './rules/metadata'
import errorEntry from './rules/error'
import type tsModule from 'typescript/lib/tsserverlibrary'

export const createTSPlu

/ e.g. { "plugins": [{ "name": "next", "enabled": true }] }
    // config will be { "name": "next", "enabled": true }
    // The default user config is { "name": "next" }
    const isPluginEnabled = info.config.enabled ?? true

    if (!isPluginEnabled) {

gin: tsModule.server.PluginModuleFactory = ({
  typescript: ts,
}) => {
  function create(info: tsModule.server.PluginCreateInfo) {
    // Get plugin options
    // config is the plugin options from the user's tsconfig.json
    /


typeof import('typescript/lib/tsserverlibrary')

let ts: TypeScript
let info: tsModule.server.PluginCreateInfo
let appDirRegExp: RegExp

export function log(message: string) {
  info.project.projectService.logger.info('[next] ' + message)
}

// This function has to be called initially.
export function init(opts: {
  ts: TypeScript
  info: tsModule.server.PluginCreateInfo
}) {
  const projectDir = opts.info.project.getCurrentDirectory()
  ts = opts.ts
  info = opts.info
  appDirRegExp = new RegExp(
    '^' +

getTypeChecker() {
  const program = info.languageService.getProgram()
  if (!program) {
    log('Failed to get program while while running getTypeChecker.')
    return
  }
  const typeChecker = program.getTypeChecker()
  if (!typeChecker) {
    log('Faile

 (projectDir + '(/src)?/app').replace(/[\\/]/g, '[\\/]')
  )

  log('Initialized Next.js TypeScript plugin: ' + projectDir)
}

export function getTs() {
  return ts
}

export function getInfo() {
  return info
}

export function


 { NEXT_TS_ERRORS } from '../constant'
import { getTs, getTypeChecker } from '../utils'
import type tsModule from 'typescript/lib/tsserverlibrary'

const clientBoundary = {
  getSemanticDiagnosticsForExportVariableStatement(
    source: tsModule.SourceFile,
    node: tsModule.VariableStatement
  ) {
    const ts = getTs()

    const diagnostics: tsModule.Diagnostic[] = []

    if (ts.isVariableDeclarationList(node.declarationList)) {
      for (const declaration of node.declarationList.declarations) {

              initializer
            )
          )
        }
      }
    }

    return diagnostics
  },

  getSemanticDiagnosticsForFunctionExport(
    source: tsModule.SourceFile,
    node: tsModule.FunctionDeclaration | tsModule.ArrowFunction
  ) {

   const initializer = declaration.initializer
        if (initializer && ts.isArrowFunction(initializer)) {
          diagnostics.push(
            ...clientBoundary.getSemanticDiagnosticsForFunctionExport(
              source,


   "Heuristic to cache as much as possible but doesn't prevent any component to opt-in to dynamic behavior.",
      '"force-dynamic"':
        'This disables all caching of fetches and always revalidates. (This is equivalent to `getServerSideProps`.)',
      '"error"':
        'This errors if any dynamic Hooks or fetches are used. (This is equivalent to `getStaticProps`.)',
      '"force-static"':
        'This forces caching of all fetches and returns empty values from `cookies`, `headers` and `useSearchPa

etchCache` option controls how Next.js statically caches fetches. By default it statically caches fetches reachable before any dynamic Hooks are used, and it doesn't cache fetches that are discovered after that.",
    options: {
      '"force-no-store"':

rams`.',
    } satisfies DocsOptionsObject<FullAppSegmentConfig['dynamic']>,
    link: 'https://nextjs.org/docs/app/api-reference/file-conventions/route-segment-config#dynamic',
  },
  fetchCache: {
    description:
      "The `f


'

import type tsModule from 'typescript/lib/tsserverlibrary'

const entry = {
  // Give auto completion for the component's props
  getCompletionsAtPosition(
    fileName: string,
    node: tsModule.FunctionDeclaration,
    position: number
  ) {
    const ts = getTs()
    const entries: tsModule.CompletionEntry[] = []

    // Default export function might not accept parameters
    const paramNode = node.parameters?.[0] as
      | tsModule.ParameterDeclaration
      | undefined

    if (paramNode && isPosi

f (isPageFile(fileName)) {
          // For page entries (page.js), it can only have `params` and `searchParams`
          // as the prop names.
          validProps = ALLOWED_PAGE_PROPS
          validPropsWithType = ALLOWED_PAGE_PROPS
          type = 'p

tionInsideNode(position, paramNode)) {
      const props = paramNode?.name
      if (props && ts.isObjectBindingPattern(props)) {
        let validProps = []
        let validPropsWithType = []
        let type: string

        i


s module provides intellisense for all components that has the `"use client"` directive.

import { NEXT_TS_ERRORS } from '../constant'
import { getTs } from '../utils'
import type tsModule from 'typescript/lib/tsserverlibrary'

const errorEntry = {
  getSemanticDiagnostics(
    source: tsModule.SourceFile,
    isClientEntry: boolean
  ): tsModule.Diagnostic[] {
    const isErrorFile = /[\\/]error\.tsx?$/.test(source.fileName)
    const isGlobalErrorFile = /[\\/]global-error\.tsx?$/.test(source.fileName)

agnosticCategory.Error,
          code: NEXT_TS_ERRORS.INVALID_ERROR_COMPONENT,
          messageText: `Error Components must be Client Components, please add the "use client" directive: https://nextjs.org/docs/app/api-reference/file-conventions/error`,

  if (!isErrorFile && !isGlobalErrorFile) return []

    const ts = getTs()

    if (!isClientEntry) {
      // Error components must be Client Components
      return [
        {
          file: source,
          category: ts.Di


leName)
      const ts = getTs()

      // It is not allowed to export `metadata` or `generateMetadata` in client entry
      if (ts.isFunctionDeclaration(node)) {
        if (node.name?.getText() === 'generateMetadata') {
          return [
            {
              file: source,
              category: ts.DiagnosticCategory.Error,
              code: NEXT_TS_ERRORS.INVALID_METADATA_EXPORT,
              messageText: `The Next.js 'generateMetadata' API is not allowed in a Client Component.`,

ion.name.getText()
          if (name === 'metadata') {
            return [
              {
                file: source,
                category: ts.DiagnosticCategory.Error,
                code: NEXT_TS_ERRORS.INVALID_METADATA_EXPORT,

  start: node.name.getStart(),
              length: node.name.getWidth(),
            },
          ]
        }
      } else {
        for (const declaration of node.declarationList.declarations) {
          const name = declarat


ERRORS } from '../constant'
import { getTs, getTypeChecker } from '../utils'
import type tsModule from 'typescript/lib/tsserverlibrary'

// Check if the type is `Promise<T>`.
function isPromiseType(type: tsModule.Type, typeChecker: tsModule.TypeChecker) {
  const typeReferenceType = type as tsModule.TypeReference
  if (!typeReferenceType.target) return false

  // target should be Promise or Promise<...>
  if (
    !/^Promise(<.+>)?$/.test(typeChecker.typeToString(typeReferenceType.target))
  ) {
    return

hecker.getSignaturesOfType(
    type,
    ts.SignatureKind.Call
  )

  let isPromise = true
  if (signatures.length) {
    for (const signature of signatures) {
      const returnType = signature.getReturnType()
      if (returnType.isUnion()) {
        fo

 false
  }

  return true
}

function isFunctionReturningPromise(
  node: tsModule.Node,
  typeChecker: tsModule.TypeChecker,
  ts: typeof tsModule
) {
  const type = typeChecker.getTypeAtLocation(node)
  const signatures = typeC


odeOutgoingHttpHeaders } from './utils'

describe('toNodeHeaders', () => {
  it('should handle multiple set-cookie headers correctly', () => {
    const headers = new Headers()

    headers.append('set-cookie', 'foo=bar')
    headers.append('set-cookie', 'bar=foo')

    expect(toNodeOutgoingHttpHeaders(headers)).toEqual({
      'set-cookie': ['foo=bar', 'bar=foo'],
    })
  })

  it('should handle a single set-cookie header correctly', () => {
    const headers = new Headers()

    headers.append('set-cooki

 Headers()

    headers.append('set-cookie', 'foo=bar, bar=foo')

    expect(toNodeOutgoingHttpHeaders(headers)).toEqual({
      'set-cookie': ['foo=bar', 'bar=foo'],
    })

    headers.append('set-cookie', 'baz=qux')

    expect(toNodeOutgoingHttpHeaders

e', 'foo=bar')

    expect(toNodeOutgoingHttpHeaders(headers)).toEqual({
      'set-cookie': 'foo=bar',
    })
  })

  it('should handle a single set-cookie header with multiple cookies correctly', () => {
    const headers = new


b-on-close'

describe('trackStreamConsumed', () => {
  it('calls onEnd when the stream finishes', async () => {
    const endPromise = new DetachedPromise<void>()
    const onEnd = jest.fn(endPromise.resolve)

    const { stream: inputStream, controller } =
      readableStreamWithController<string>()
    const trackedStream = trackStreamConsumed(inputStream, onEnd)

    const reader = trackedStream.getReader()
    controller.enqueue('one')
    controller.enqueue('two')
    await reader.read()
    await rea

veBeenCalledTimes(1)
  })

  it('calls onEnd when the stream errors', async () => {
    const endPromise = new DetachedPromise<void>()
    const onEnd = jest.fn(endPromise.resolve)

    const { stream: inputStream, controller } =
      readableStreamWithCo

der.read()
    expect(onEnd).not.toHaveBeenCalled()

    controller.close()

    await expect(reader.read()).resolves.toEqual({
      done: true,
      value: undefined,
    })

    await endPromise.promise
    expect(onEnd).toHa


-request-context'
import { PageSignatureError } from '../error'
import type { NextRequest } from './request'

const responseSymbol = Symbol('response')
const passThroughSymbol = Symbol('passThrough')
const waitUntilSymbol = Symbol('waitUntil')

class FetchEvent {
  // TODO(after): get rid of the 'internal' variant and always use an external waitUntil
  // (this means removing `FetchEventResult.waitUntil` which also requires a builder change)
  readonly [waitUntilSymbol]:
    | { kind: 'internal'; promises:

ntil
      ? { kind: 'external', function: waitUntil }
      : { kind: 'internal', promises: [] }
  }

  // TODO: is this dead code? NextFetchEvent never lets this get called
  respondWith(response: Response | Promise<Response>): void {
    if (!this[respo

Promise<any>[] }
    | { kind: 'external'; function: WaitUntil };

  [responseSymbol]?: Promise<Response>;
  [passThroughSymbol] = false

  constructor(_request: Request, waitUntil?: WaitUntil) {
    this[waitUntilSymbol] = waitU


/../config-shared'
import { NextURL } from '../next-url'
import { toNodeOutgoingHttpHeaders, validateURL } from '../utils'
import { ReflectAdapter } from './adapters/reflect'

import { ResponseCookies } from './cookies'

const INTERNALS = Symbol('internal response')
const REDIRECTS = new Set([301, 302, 303, 307, 308])

function handleMiddlewareField(
  init: MiddlewareResponseInit | undefined,
  headers: Headers
) {
  if (init?.request?.headers) {
    if (!(init.request.headers instanceof Headers)) {

}

    headers.set('x-middleware-override-headers', keys.join(','))
  }
}

/**
 * This class extends the [Web `Response` API](https://developer.mozilla.org/docs/Web/API/Response) with additional convenience methods.
 *
 * Read more: [Next.js Docs: `NextRes

throw new Error('request.headers must be an instance of Headers')
    }

    const keys = []
    for (const [key, value] of init.request.headers) {
      headers.set('x-middleware-request-' + key, value)
      keys.push(key)


app-render/work-unit-async-storage.external'
import {
  CachedRouteKind,
  IncrementalCacheKind,
  type CachedFetchData,
} from '../../response-cache'
import type {
  UnstableCacheStore,
  WorkUnitStore,
} from '../../app-render/work-unit-async-storage.external'

type Callback = (...args: any[]) => Promise<any>

let noStoreFetchIdx = 0

async function cacheNewResult<T>(
  result: T,
  incrementalCache: IncrementalCache,
  cacheKey: string,
  tags: string[],
  revalidate: number | false | undefined,
  fetchI

SON.stringify(result),
        status: 200,
        url: '',
      } satisfies CachedFetchData,
      revalidate:
        typeof revalidate !== 'number' ? CACHE_ONE_YEAR_SECONDS : revalidate,
    },
    { fetchCache: true, tags, fetchIdx, fetchUrl }
  )

dx: number,
  fetchUrl: string
): Promise<unknown> {
  await incrementalCache.set(
    cacheKey,
    {
      kind: CachedRouteKind.FETCH,
      data: {
        headers: {},
        // TODO: handle non-JSON values?
        body: J


 parseua from 'next/dist/compiled/ua-parser-js'

interface UserAgent {
  isBot: boolean
  ua: string
  browser: {
    name?: string
    version?: string
    major?: string
  }
  device: {
    model?: string
    type?: string
    vendor?: string
  }
  engine: {
    name?: string
    version?: string
  }
  os: {
    name?: string
    version?: string
  }
  cpu: {
    architecture?: string
  }
}

export function isBot(input: string): boolean {
  return /Googlebot|Mediapartners-Google|AdsBot-Google|googleweblig

lebot|redditbot|Slackbot|Discordbot|WhatsApp|SkypeUriPreview|ia_archiver|GPTBot/i.test(
    input
  )
}

export function userAgentFromString(input: string | undefined): UserAgent {
  return {
    ...parseua(input),
    isBot: input === undefined ? false :


oBeInstanceOf(HeadersAdapter)
    expect(adapter.get('content-type')).toBe('application/json')
    expect(adapter.get('x-custom-header')).toBe('custom')
  })

  it('should be able to create a new instance from a Headers', () => {
    const headers = new Headers({
      'content-type': 'application/json',
      'x-custom-header': 'custom',
    })
    const adapter = HeadersAdapter.from(headers)
    expect(adapter).toBeInstanceOf(Headers)
    expect(adapter.get('content-type')).toBe('application/json')
    ex

ustom-header': 'custom',
    })
    const adapter = HeadersAdapter.from(headers)
    expect(adapter).toBeInstanceOf(HeadersAdapter)
    expect(adapter.get('content-type')).toBe('application/json')
    expect(adapter.get('x-custom-header')).toBe('custom')

pect(adapter.get('x-custom-header')).toBe('custom')
  })

  it('should be able to create a new instance from a HeadersAdapter', () => {
    const headers = new HeadersAdapter({
      'content-type': 'application/json',
      'x-c


t path from 'path'
import type { RouteTypesManifest } from './route-types-utils'

export type RootParamValueType = 'string' | 'string[]' | 'undefined'

export type RootParamInfo = Set<RootParamValueType>

const ROOT_PARAM_VALUE_TYPES: RootParamValueType[] = [
  'string',
  'string[]',
  'undefined',
]

/**
 * Generates TypeScript type definitions for root params.
 * Creates a `declare module 'next/root-params'` block with async getter functions
 * for each root parameter.
 */
export function generateRootPar

amName}(): ${getRootParamReturnType(info)}`
    )

  return `// Type definitions for Next.js root params (next/root-params)

declare module 'next/root-params' {
${exports.join('\n')}
}
`
}

function getRootParamReturnType(valueTypes: RootParamInfo): string

amsTypes(
  rootParams: Map<string, RootParamInfo>
): string {
  const exports = Array.from(rootParams.entries())
    .sort(([a], [b]) => a.localeCompare(b))
    .map(
      ([paramName, info]) =>
        `  export function ${par


apPropagator,
} from '@opentelemetry/api'
import {
  ROOT_CONTEXT,
  context,
  createContextKey,
  propagation,
  trace,
} from '@opentelemetry/api'

import { getTracer } from './tracer'

const customContextKey = createContextKey('next.tracer.test.custom-context')

const getter: TextMapGetter<Record<string, string | undefined>> = {
  keys: (carrier) => Object.keys(carrier),
  get: (carrier, key) => carrier[key],
}

class TestContextManager implements ContextManager {
  private currentContext: Context = ROO

: ReturnType<F> {
    const previousContext = this.currentContext
    this.currentContext = newContext
    try {
      return fn.apply(thisArg, args)
    } finally {
      this.currentContext = previousContext
    }
  }

  bind<T>(bindContext: Context, tar

T_CONTEXT

  active(): Context {
    return this.currentContext
  }

  with<A extends unknown[], F extends (...args: A) => ReturnType<F>>(
    newContext: Context,
    fn: F,
    thisArg?: ThisParameterType<F>,
    ...args: A
  )


e epoch
 */
export type Timestamp = number

export interface CacheEntry {
  /**
   * The ReadableStream can error and only have partial data so any cache
   * handlers need to handle this case and decide to keep the partial cache
   * around or not.
   */
  value: ReadableStream<Uint8Array>

  /**
   * The tags configured for the entry excluding soft tags
   */
  tags: string[]

  /**
   * This is for the client, not used to calculate cache entry expiration
   * [duration in seconds]
   */
  stale: number

e: number

  /**
   * How long until the entry should be revalidated [duration in seconds]
   */
  revalidate: number
}

export interface CacheHandler {
  /**
   * Retrieve a cache entry for the given cache key, if available. Will return
   * undefined if

  /**
   * When the cache entry was created [timestamp in milliseconds]
   */
  timestamp: Timestamp

  /**
   * How long the entry is allowed to be used (should be longer than revalidate)
   * [duration in seconds]
   */
  expir


t { RenderingMode } from '../../../build/rendering-mode'
import { SharedCacheControls } from './shared-cache-controls.external'

describe('SharedCacheControls', () => {
  let sharedCacheControls: SharedCacheControls
  let prerenderManifest

  beforeEach(() => {
    prerenderManifest = {
      routes: {
        '/route1': {
          initialRevalidateSeconds: 10,
          initialExpireSeconds: undefined,
          dataRoute: null,
          srcRoute: null,
          prefetchDataRoute: null,
          experi

ds: 40,
          dataRoute: null,
          srcRoute: null,
          prefetchDataRoute: null,
          experimentalPPR: undefined,
          renderingMode: RenderingMode.STATIC,
          allowHeader: [],
        } satisfies PrerenderManifestRoute,

mentalPPR: undefined,
          renderingMode: RenderingMode.STATIC,
          allowHeader: [],
        } satisfies PrerenderManifestRoute,
        '/route2': {
          initialRevalidateSeconds: 20,
          initialExpireSecon


 type { Timestamp } from '../cache-handlers/types'

export interface TagManifestEntry {
  stale?: number
  expired?: number
}

// We share the tags manifest between the "use cache" handlers and the previous
// file-system cache.
export const tagsManifest = new Map<string, TagManifestEntry>()

export const areTagsExpired = (tags: string[], timestamp: Timestamp) => {
  for (const tag of tags) {
    const entry = tagsManifest.get(tag)
    const expiredAt = entry?.expired

    if (typeof expiredAt === 'number')

)
      const isImmediatelyExpired = expiredAt <= now && expiredAt > timestamp

      if (isImmediatelyExpired) {
        return true
      }
    }
  }

  return false
}

export const areTagsStale = (tags: string[], timestamp: Timestamp) => {
  for (const

 {
      const now = Date.now()
      // For immediate expiration (expiredAt <= now) and tag was invalidated after entry was created
      // OR for future expiration that has now passed (expiredAt > timestamp && expiredAt <= now


Headers = [
  'accept-encoding',
  'keepalive',
  'keep-alive',
  'content-encoding',
  'transfer-encoding',
  // https://github.com/nodejs/undici/issues/1470
  'connection',
  // marked as unsupported by undici: https://github.com/nodejs/undici/blob/c83b084879fa0bb8e0469d31ec61428ac68160d5/lib/core/request.js#L354
  'expect',
]

export const actionsForbiddenHeaders = [
  ...ipcForbiddenHeaders,
  'content-length',
  'set-cookie',
]

export const filterReqHeaders = (
  headers: Record<string, undefined | st

content-length'] && headers['content-length'] === '0') {
    delete headers['content-length']
  }

  for (const [key, value] of Object.entries(headers)) {
    if (
      forbiddenHeaders.includes(key) ||
      !(Array.isArray(value) || typeof value === 'st

ring | number | string[]>,
  forbiddenHeaders: string[]
) => {
  // Some browsers are not matching spec and sending Content-Length: 0. This causes issues in undici
  // https://github.com/nodejs/undici/issues/2046
  if (headers['


expose the "waitUntil" API to Edge SSR and Edge Route Handler functions.
// This is highly experimental and subject to change.

// We still need a global key to bypass Webpack's layering of modules.
const GLOBAL_KEY = Symbol.for('__next_internal_waitUntil__')

const state: {
  waitUntilCounter: number
  waitUntilResolve: () => void
  waitUntilPromise: Promise<void> | null
} =
  // @ts-ignore
  globalThis[GLOBAL_KEY] ||
  // @ts-ignore
  (globalThis[GLOBAL_KEY] = {
    waitUntilCounter: 0,
    waitUntilResol

ction resolveOnePromise() {
  state.waitUntilCounter--
  if (state.waitUntilCounter === 0) {
    state.waitUntilResolve()
    state.waitUntilPromise = null
  }
}

export function internal_getCurrentFunctionWaitUntil() {
  return state.waitUntilPromise
}

e

ve: undefined,
    waitUntilPromise: null,
  })

// No matter how many concurrent requests are being handled, we want to make sure
// that the final promise is only resolved once all of the waitUntil promises have
// settled.
fun


 '../config-shared'
import type { NextRequest } from './spec-extension/request'
import type { NextFetchEvent } from './spec-extension/fetch-event'
import type { NextResponse } from './spec-extension/response'
import type { CloneableBody } from '../body-streams'
import type { OutgoingHttpHeaders } from 'http'
import type { FetchMetrics } from '../base-http'
import type { RequestMeta } from '../request-meta'

/**
 * @deprecated Use `ProxyConfig` instead. Middleware has been renamed to Proxy.
 */
export type {

ort interface RequestData {
  headers: OutgoingHttpHeaders
  method: string
  nextConfig?: {
    basePath?: string
    i18n?: I18NConfig | null
    trailingSlash?: boolean
    experimental?: Pick<
      ExperimentalConfig,
      'cacheLife' | 'authInterrup

 MiddlewareConfigInput as MiddlewareConfig } from '../../build/segment-config/middleware/middleware-config'

export type { MiddlewareConfigInput as ProxyConfig } from '../../build/segment-config/middleware/middleware-config'

exp


umer finishes reading the response body.
that's as close as we can get to `res.on('close')` using web APIs.
*/
export function trackBodyConsumed(
  body: string | ReadableStream,
  onEnd: () => void
): BodyInit {
  if (typeof body === 'string') {
    const generator = async function* generate() {
      const encoder = new TextEncoder()
      yield encoder.encode(body)
      onEnd()
    }
    // @ts-expect-error BodyInit typings doesn't seem to include AsyncIterables even though it's supported in practice

ction must handle `stream` being aborted or cancelled,
  // so it can't just be this:
  //
  //   return stream.pipeThrough(new TransformStream({ flush() { onEnd() } }))
  //
  // because that doesn't handle cancellations.
  // (and cancellation handling v

  return generator()
  } else {
    return trackStreamConsumed(body, onEnd)
  }
}

export function trackStreamConsumed<TChunk>(
  stream: ReadableStream<TChunk>,
  onEnd: () => void
): ReadableStream<TChunk> {
  // NOTE: This fun


om '../../app-render/work-unit-async-storage.external'
import { DynamicServerError } from '../../../client/components/hooks-server-context'
import { InvariantError } from '../../../shared/lib/invariant-error'
import {
  ActionDidRevalidateDynamicOnly,
  ActionDidRevalidateStaticAndDynamic as ActionDidRevalidate,
} from '../../../shared/lib/action-revalidation-kind'
import { removeTrailingSlash } from '../../../shared/lib/router/utils/remove-trailing-slash'
import { encodeCacheTag } from '../../lib/encode-ca

gument specifies a [`cacheLife`](https://nextjs.org/docs/app/api-reference/functions/cacheLife#reference) profile
 * (e.g. `"max"`), or a `{ expire }` object. For immediate expiration in Server Actions, use
 * [`updateTag`](https://nextjs.org/docs/app/api-

che-tag'

type CacheLifeConfig = {
  expire?: number
}

/**
 * This function allows you to purge [cached data](https://nextjs.org/docs/app/building-your-application/caching) on-demand for a specific cache tag.
 *
 * The second ar


work-async-storage.external'
import { workUnitAsyncStorage } from '../../app-render/work-unit-async-storage.external'
import { markCurrentScopeAsDynamic } from '../../app-render/dynamic-rendering'

/**
 * This function can be used to declaratively opt out of static rendering and indicate a particular component should not be cached.
 *
 * It marks the current scope as dynamic.
 *
 * - In [non-PPR](https://nextjs.org/docs/app/api-reference/next-config-js/partial-prerendering) cases this will make a static ren

er and will error otherwise.
 *
 * Read more: [Next.js Docs: `unstable_noStore`](https://nextjs.org/docs/app/api-reference/functions/unstable_noStore)
 */
export function unstable_noStore() {
  const callingExpression = 'unstable_noStore()'
  const store =

der
 * halt and mark the page as dynamic.
 * - In PPR cases this will postpone the render at this location.
 *
 * If we are inside a cache scope then this function does nothing.
 *
 * @note It expects to be called within App Rout


m 'node:http'
import type { NextConfigRuntime } from '../../config-shared'
import type { UrlWithParsedQuery } from 'node:url'
import type { ServerCacheStatus } from '../../../next-devtools/dev-overlay/cache-indicator'
import type { AnyStream } from '../../app-render/stream-ops'

export type RevalidateFn = (config: {
  urlPath: string
  headers: { [key: string]: string | string[] }
  opts: { unstable_onlyGenerated?: boolean }
}) => Promise<void>

// The RouterServerContext contains instance specific
// infor

erContext = Record<
  string,
  {
    // hostname the server is started with
    hostname?: string
    // revalidate function to bypass going through network
    // to invoke revalidate request (uses mocked req/res)
    revalidate?: RevalidateFn
    // fun

mation that isn't available/relevant when
// deployed in serverless environments, the key is
// the relative project dir this allows separate contexts
// when running multiple next instances in same process
export type RouterServ


gex'
import { buildDataRoute } from './build-data-route'
import { getRouteMatcher } from '../../../shared/lib/router/utils/route-matcher'
import { normalizePathSep } from '../../../shared/lib/page-path/normalize-path-sep'
import { createClientRouterFilter } from '../../../lib/create-client-router-filter'
import { absolutePathToPage } from '../../../shared/lib/page-path/absolute-path-to-page'
import { generateInterceptionRoutesRewrites } from '../../../lib/generate-interception-routes-rewrites'

import {
  C

tants'

import { getMiddlewareRouteMatcher } from '../../../shared/lib/router/utils/middleware-route-matcher'

import {
  isMiddlewareFile,
  NestedMiddlewareError,
  isInstrumentationHookFile,
  getPossibleMiddlewareFilenames,
  getPossibleInstrumentation

LIENT_STATIC_FILES_PATH,
  DEV_CLIENT_PAGES_MANIFEST,
  DEV_CLIENT_MIDDLEWARE_MANIFEST,
  PHASE_DEVELOPMENT_SERVER,
  TURBOPACK_CLIENT_MIDDLEWARE_MANIFEST,
  ROUTES_MANIFEST,
  PRERENDER_MANIFEST,
} from '../../../shared/lib/cons


 type { LoadedEnvFiles } from '@next/env'
import { join } from 'node:path'
import { writeFile } from 'node:fs/promises'

export async function createEnvDefinitions({
  distDir,
  loadedEnvFiles,
}: {
  distDir: string
  loadedEnvFiles: LoadedEnvFiles
}) {
  const envLines = []
  const seenKeys = new Set()
  // env files are in order of priority
  for (const { path, env } of loadedEnvFiles) {
    for (const key in env) {
      if (!seenKeys.has(key)) {
        envLines.push(`      /** Loaded from \`${path}\`

{
  namespace NodeJS {
    interface ProcessEnv {
${envStr}
    }
  }
}
export {}`

  if (process.env.NODE_ENV === 'test') {
    return definitionStr
  }

  try {
    // we expect the types directory to already exist
    const envDtsPath = join(distDir, 't

 */`)
        envLines.push(`      ${key}?: string`)
        seenKeys.add(key)
      }
    }
  }
  const envStr = envLines.join('\n')

  const definitionStr = `// Type definitions for Next.js environment variables
declare global


er'
import {
  IncrementalCache,
  type CacheHandler as IncrementalCacheHandler,
} from '../lib/incremental-cache'
import type { CacheHandler } from '../lib/cache-handlers/types'
import { initializeCacheHandlers, setCacheHandler } from '../use-cache/handlers'
import { RouteMatcher } from '../route-matchers/route-matcher'
import type { NextFetchEvent } from './spec-extension/fetch-event'
import { internal_getCurrentFunctionWaitUntil } from './internal-edge-wait-until'
import { getServerUtils } from '../serve

rt { WebNextRequest } from '../../server/base-http/web'

export interface WrapOptions {
  page: string
  cacheHandlers?: Record<string, CacheHandler>
  incrementalCacheHandler?: typeof IncrementalCacheHandler
}

/**
 * EdgeRouteModuleWrapper is a wrapper a

r-utils'
import { searchParamsToUrlQuery } from '../../shared/lib/router/utils/querystring'
import { CloseController, trackStreamConsumed } from './web-on-close'
import { getEdgePreviewProps } from './get-edge-preview-props'
impo


 a Headers object. Any
 * headers with multiple values will be joined with a comma and space. Any
 * headers that have an undefined value will be ignored and others will be
 * coerced to strings.
 *
 * @param nodeHeaders the headers object to convert
 * @returns the converted headers object
 */
export function fromNodeOutgoingHttpHeaders(
  nodeHeaders: OutgoingHttpHeaders
): Headers {
  const headers = new Headers()
  for (let [key, value] of Object.entries(nodeHeaders)) {
    const values = Array.isArray(

  Set-Cookie header field-values are sometimes comma joined in one string. This splits them without choking on commas
  that are within a single set-cookie field-value, such as in the Expires portion.
  This is uncommon, but explicitly allowed - see https:

value) ? value : [value]
    for (let v of values) {
      if (typeof v === 'undefined') continue
      if (typeof v === 'number') {
        v = v.toString()
      }

      headers.append(key, v)
    }
  }
  return headers
}

/*


oNodeOutgoingHttpHeaders, validateURL } from '../utils'
import { RemovedUAError, RemovedPageError } from '../error'
import { RequestCookies } from './cookies'

export const INTERNALS = Symbol('internal request')

/**
 * This class extends the [Web `Request` API](https://developer.mozilla.org/docs/Web/API/Request) with additional convenience methods.
 *
 * Read more: [Next.js Docs: `NextRequest`](https://nextjs.org/docs/app/api-reference/functions/next-request)
 */
export class NextRequest extends Request {

in input ? input.url : String(input)

    validateURL(url)

    // node Request instance requires duplex option when a body
    // is present or it errors, we don't handle this for
    // Request being passed in since it would have already
    // errored i

  /** @internal */
  [INTERNALS]: {
    cookies: RequestCookies
    url: string
    nextUrl: NextURL
  }

  constructor(input: URL | RequestInfo, init: RequestInit = {}) {
    const url =
      typeof input !== 'string' && 'url'


./shared/lib/is-thenable'

const NEXT_OTEL_PERFORMANCE_PREFIX = process.env.NEXT_OTEL_PERFORMANCE_PREFIX

let api: typeof import('next/dist/compiled/@opentelemetry/api')

// we want to allow users to use their own version of @opentelemetry/api if they
// want to, so we try to require it first, and if it fails we fall back to the
// version that is bundled with Next.js
// this is because @opentelemetry/api has to be synced with the version of
// @opentelemetry/tracing that is used, and we don't want to force

se {
  try {
    api = require('@opentelemetry/api') as typeof import('@opentelemetry/api')
  } catch (err) {
    api =
      require('next/dist/compiled/@opentelemetry/api') as typeof import('next/dist/compiled/@opentelemetry/api')
  }
}

const { context,

 users to use
// the version that is bundled with Next.js.
// the API is ~stable, so this should be fine
if (process.env.NEXT_RUNTIME === 'edge') {
  api = require('@opentelemetry/api') as typeof import('@opentelemetry/api')
} el


ntal`, only those leaf pages that export
 * `experimental_ppr = true` will have partial prerendering enabled. If any
 * page exports this value as `false` or does not export it at all will not
 * have partial prerendering enabled. If set to a boolean, the options for
 * `experimental_ppr` will be ignored.
 */

export type ExperimentalPPRConfig = boolean | 'incremental'

/**
 * Returns true if partial prerendering is enabled for the application. It does
 * not tell you if a given route has PPR enabled, as th

ined
): boolean {
  // If the config is undefined, partial prerendering is disabled.
  if (typeof config === 'undefined') return false

  // If the config is a boolean, use it directly.
  if (typeof config === 'boolean') return config

  // If the config i

at requires analysis of
 * the route's configuration.
 *
 * @see {@link checkIsRoutePPREnabled} - for checking if a specific route has PPR enabled.
 */
export function checkIsAppPPREnabled(
  config: ExperimentalPPRConfig | undef


rValue } from '.'
import { CachedRouteKind } from '../../response-cache/types'
import { LRUCache } from '../lru-cache'

let memoryCache: LRUCache<CacheHandlerValue> | undefined

function getBufferSize(buffer: Buffer | undefined) {
  return buffer?.length || 0
}

function getSegmentDataSize(segmentData: Map<string, Buffer> | undefined) {
  if (!segmentData) {
    return 0
  }

  let size = 0

  for (const [segmentPath, buffer] of segmentData) {
    size += segmentPath.length + getBufferSize(buffer)
  }

  re

 (value.kind === CachedRouteKind.REDIRECT) {
        return JSON.stringify(value.props).length
      } else if (value.kind === CachedRouteKind.IMAGE) {
        throw new Error('invariant image should not be incremental-cache')
      } else if (value.kind =

turn size
}

export function getMemoryCache(maxMemoryCacheSize: number) {
  if (!memoryCache) {
    memoryCache = new LRUCache(maxMemoryCacheSize, function length({ value }) {
      if (!value) {
        return 25
      } else if


ers cannot be modified. Read more: https://nextjs.org/docs/app/api-reference/functions/headers'
    )
  }

  public static callable() {
    throw new ReadonlyHeadersError()
  }
}

export type ReadonlyHeaders = Headers & {
  /** @deprecated Method unavailable on `ReadonlyHeaders`. Read more: https://nextjs.org/docs/app/api-reference/functions/headers */
  append(...args: any[]): void
  /** @deprecated Method unavailable on `ReadonlyHeaders`. Read more: https://nextjs.org/docs/app/api-reference/functions/head

extends Headers {
  private readonly headers: IncomingHttpHeaders

  constructor(headers: IncomingHttpHeaders) {
    // We've already overridden the methods that would be called, so we're just
    // calling the super constructor to ensure that the instanc

ers */
  set(...args: any[]): void
  /** @deprecated Method unavailable on `ReadonlyHeaders`. Read more: https://nextjs.org/docs/app/api-reference/functions/headers */
  delete(...args: any[]): void
}
export class HeadersAdapter


ds
const DAY_IN_SECONDS = HOUR_IN_SECONDS * 24
const WEEK_IN_SECONDS = DAY_IN_SECONDS * 7
// Nevermind leap years, or you know, July
const MONTH_30_DAYS_IN_SECONDS = DAY_IN_SECONDS * 30

function formatTimespan(seconds: number): string {
  if (seconds > 0) {
    if (seconds === MONTH_30_DAYS_IN_SECONDS) {
      return '1 month'
    }
    if (seconds === WEEK_IN_SECONDS) {
      return '1 week'
    }
    if (seconds === DAY_IN_SECONDS) {
      return '1 day'
    }
    if (seconds === HOUR_IN_SECONDS) {

 18144000 === 0) {
      return seconds / 18144000 + ' months'
    }
    if (seconds % WEEK_IN_SECONDS === 0) {
      return seconds / WEEK_IN_SECONDS + ' weeks'
    }
    if (seconds % DAY_IN_SECONDS === 0) {
      return seconds / DAY_IN_SECONDS + ' days

 return '1 hour'
    }
    if (seconds === MINUTE_IN_SECONDS) {
      return '1 minute'
    }
    if (seconds % MONTH_30_DAYS_IN_SECONDS === 0) {
      return seconds / MONTH_30_DAYS_IN_SECONDS + ' months'
    }
    if (seconds %


ED_SERVER_REACT_DOM_APIS,
  NEXT_TS_ERRORS,
} from '../constant'
import { getTs } from '../utils'
import type tsModule from 'typescript/lib/tsserverlibrary'

const serverLayer = {
  // On the server layer we need to filter out some invalid completion results.
  filterCompletionsAtPosition(entries: tsModule.CompletionEntry[]) {
    return entries.filter((e: tsModule.CompletionEntry) => {
      // Remove disallowed React APIs.
      if (
        DISALLOWED_SERVER_REACT_APIS.includes(e.name) &&
        e.sourc

return definitions?.some(
      (d) =>
        DISALLOWED_SERVER_REACT_APIS.includes(d.name) &&
        d.containerName === 'React'
    )
  },

  // Give errors about disallowed imports such as `useState`.
  getSemanticDiagnosticsForImportDeclaration(

e === 'react'
      ) {
        return false
      }
      return true
    })
  },

  // Filter out quick info for some React APIs.
  hasDisallowedReactAPIDefinition(
    definitions: readonly tsModule.DefinitionInfo[]
  ) {


ort { workUnitAsyncStorage } from '../app-render/work-unit-async-storage.external'
import { validateTags } from '../lib/patch-fetch'

export function cacheTag(...tags: string[]): void {
  if (!process.env.__NEXT_USE_CACHE) {
    throw new Error(
      '`cacheTag()` is only available with the `cacheComponents` config.'
    )
  }

  const workUnitStore = workUnitAsyncStorage.getStore()

  switch (workUnitStore?.type) {
    case 'prerender':
    case 'prerender-client':
    case 'validation-client':
    case '

y be called inside a "use cache" function.'
      )
    case 'cache':
    case 'private-cache':
      break
    default:
      workUnitStore satisfies never
  }

  const validTags = validateTags(tags, '`cacheTag()`')

  if (!workUnitStore.tags) {
    workU

prerender-runtime':
    case 'prerender-ppr':
    case 'prerender-legacy':
    case 'request':
    case 'unstable-cache':
    case 'generate-static-params':
    case undefined:
      throw new Error(
        '`cacheTag()` can onl


 from '../lib/cache-handlers/types'

const debug = process.env.NEXT_PRIVATE_DEBUG_CACHE
  ? (message: string, ...args: any[]) => {
      console.log(`use-cache: ${message}`, ...args)
    }
  : undefined

const handlersSymbol = Symbol.for('@next/cache-handlers')
const handlersMapSymbol = Symbol.for('@next/cache-handlers-map')
const handlersSetSymbol = Symbol.for('@next/cache-handlers-set')

/**
 * The reference to the cache handlers. We store the cache handlers on the
 * global object so that we can access t

 [handlersMapSymbol]?: Map<string, CacheHandler>
  [handlersSetSymbol]?: Set<CacheHandler>
} = globalThis

/**
 * Initialize the cache handlers.
 * @param cacheMaxMemorySize - The maximum memory size of the cache in bytes, if
 *  not provided, the default

he same instance across different
 * boundaries (such as different copies of the same module).
 */
const reference: typeof globalThis & {
  [handlersSymbol]?: {
    RemoteCache?: CacheHandler
    DefaultCache?: CacheHandler
  }


seVersionInfo } from './parse-version-info'
import type { VersionInfo } from './parse-version-info'

describe('parse version info', () => {
  test.each<
    [
      installed: string,
      latest: string,
      canary: string,
      staleness: VersionInfo['staleness'],
    ]
  >([
    ['12.0.0', '13.1.1', '13.0.1-canary.0', 'stale-major'],
    ['13.0.0', '13.1.0', '13.1.1-canary.0', 'stale-minor'],
    ['13.1.1', '13.1.2', '13.1.3-canary.0', 'stale-patch'],
    ['13.0.1-canary.0', '13.0.0', '13.0.1-canary.


next/dist/compiled/semver'

export interface VersionInfo {
  installed: string
  staleness:
    | 'fresh'
    | 'stale-patch'
    | 'stale-minor'
    | 'stale-major'
    | 'stale-prerelease'
    | 'newer-than-npm'
    | 'unknown'
  expected?: string
}

export function parseVersionInfo(o: {
  installed: string
  latest: string
  canary: string
}): VersionInfo {
  const latest = semver.parse(o.latest)
  const canary = semver.parse(o.canary)
  const installedParsed = semver.parse(o.installed)
  const installed

   installedParsed.prerelease[0] === 'canary' &&
      semver.lt(installedParsed, canary)
    ) {
      // Matching major, but old canary
      return {
        staleness: 'stale-prerelease',
        expected: canary.raw,
        installed,
      }
    } e

 = o.installed
  if (installedParsed && latest && canary) {
    if (installedParsed.major < latest.major) {
      // Old major version
      return { staleness: 'stale-major', expected: latest.raw, installed }
    } else if (


ealpathSync } from '../../lib/realpath'
import { clearManifestCache } from '../load-manifest.external'

/**
 * Batch delete modules from require.cache with a single scan.
 *
 * When deleting N modules, this performs ONE scan of require.cache
 * instead of N scans, reducing complexity from O(N * C) to O(C + N)
 * where C = size of require.cache.
 */
function deleteFromRequireCache(filePaths: string[]): void {
  // Phase 1: Resolve all paths and collect modules to delete
  const resolvedPaths: string[] = []

re.cache[filePath]
    if (mod) {
      resolvedPaths.push(filePath)
      modsToDelete.add(mod)
    }
  }

  if (modsToDelete.size === 0) return

  // Phase 2: Single scan of require.cache to remove child references
  const modules = Object.values(require

 const modsToDelete = new Set<NodeModule>()

  for (let filePath of filePaths) {
    try {
      filePath = realpathSync(filePath)
    } catch (e) {
      if (isError(e) && e.code !== 'ENOENT') throw e
    }
    const mod = requi


NT_TO_BROWSER,
  type HmrMessageSentToBrowser,
} from './hot-reloader-types'
import type { AnyStream } from '../app-render/stream-ops'
import { streamToUint8Array } from '../stream-utils/node-web-streams-helper'

const errorsRscStreamsByHtmlRequestId = new Map<string, AnyStream>()

export function sendSerializedErrorsToClient(
  errorsRscStream: AnyStream,
  sendToClient: (message: HmrMessageSentToBrowser) => void
) {
  streamToUint8Array(errorsRscStream).then(
    (serializedErrors) => {
      sendToClient

nction sendSerializedErrorsToClientForHtmlRequest(
  htmlRequestId: string,
  sendToClient: (message: HmrMessageSentToBrowser) => void
) {
  const errorsRscStream = errorsRscStreamsByHtmlRequestId.get(htmlRequestId)

  if (!errorsRscStream) {
    return

({
        type: HMR_MESSAGE_SENT_TO_BROWSER.ERRORS_TO_SHOW_IN_BROWSER,
        serializedErrors,
      })
    },
    (err) => {
      console.error(new Error('Failed to serialize errors.', { cause: err }))
    }
  )
}

export fu


// Configure stringify with reasonable limits for action logging
const stringify = configure({
  maximumDepth: 2,
  maximumBreadth: 3,
})

/**
 * Format a single argument for display in server action logs.
 */
function formatArg(arg: unknown): string {
  try {
    return stringify(arg) ?? String(arg)
  } catch {
    // String(arg) can throw for temporary client references (e.g., class instances
    // passed from client to server) because accessing .toString() on them throws
    // "Cannot access toString o

 } catch {
      return '[unserializable]'
    }
  }
}

/**
 * Format arguments array to a string for display
 */
export function formatArgs(args: unknown[]): string {
  return args.map((a) => formatArg(a)).join(', ')
}

export interface ServerActionLogInf

n the server"
    try {
      return String(arg)


ule,
} from '../route-modules/app-route/module.compiled'

import '../require-hook'
import '../node-environment'

import { collectSegments } from '../../build/segment-config/app/app-segments'
import type { StaticPathsResult } from '../../build/static-paths/types'
import { loadComponents } from '../load-components'
import { setHttpClientAndAgentOptions } from '../setup-http-agent-env'
import type { IncrementalCache } from '../lib/incremental-cache'
import { isAppPageRouteModule } from '../route-modules/checks

g/app/collect-root-param-keys'
import { buildAppStaticPaths } from '../../build/static-paths/app'
import { buildPagesStaticPaths } from '../../build/static-paths/pages'
import { createIncrementalCache } from '../../export/helpers/create-incremental-cache'

'
import {
  checkIsRoutePPREnabled,
  type ExperimentalPPRConfig,
} from '../lib/experimental/ppr'
import { InvariantError } from '../../shared/lib/invariant-error'
import { collectRootParamKeys } from '../../build/segment-confi


e ws from 'next/dist/compiled/ws'
import { isMetadataRoute } from '../../lib/metadata/is-metadata-route'
import type { CustomRoutes } from '../../lib/load-custom-routes'
import {
  formatIssue,
  getIssueKey,
  isRelevantWarning,
  processIssues,
  renderStyledStringToErrorAnsi,
  type EntryIssuesMap,
  type TopLevelIssuesMap,
} from '../../shared/lib/turbopack/utils'
import { MIDDLEWARE_FILENAME, PROXY_FILENAME } from '../../lib/constants'

const onceErrorSet = new Set()
/**
 * Check if given issue is a wa

everity === 'warning' && title.value === 'Invalid page configuration') {
    if (onceErrorSet.has(issue)) {
      return false
    }
    onceErrorSet.add(issue)
  }
  if (
    severity === 'warning' &&
    stage === 'config' &&
    renderStyledStringToErro

rning to be display only once.
 * This mimics behavior of get-page-static-info's warnOnce.
 * @param issue
 * @returns
 */
function shouldEmitOnceWarning(issue: Issue): boolean {
  const { severity, title, stage } = issue
  if (s


ompiled/jest-worker'
import { setUseCacheProbe } from '../use-cache/use-cache-probe-globals'
import { onCacheInvalidation } from './require-cache'
import { getFormattedNodeOptionsWithoutInspect } from '../lib/utils'
import { needsExperimentalReact } from '../../lib/needs-experimental-react'

interface InstallOptions {
  distDir: string
  buildId: string
  deploymentId: string
  nextConfig: NextConfigComplete
}

type ProbePool = { [key: string]: any } & {
  probeUseCache: typeof probeUseCache
}

/**
 * Conve

 * path would handle Blobs via structured clone, but we need one shape that
 * works for both.
 */
async function toEncodedArgumentsForProbe(
  encoded: string | FormData
): Promise<EncodedArgumentsForProbe> {
  if (typeof encoded === 'string') {
    retu

rt the `encodedArguments` that `use-cache-wrapper.ts` already holds into
 * the worker-transport shape. Blob values are base64-encoded so the payload
 * survives the child-process JSON-only fallback transport — the worker_threads


import type { UseCacheProbeRequestSnapshot } from '../use-cache/use-cache-probe-globals'

import '../require-hook'
import '../node-environment'

import { AfterContext } from '../after/after-context'
import { loadComponents } from '../load-components'
import { setHttpClientAndAgentOptions } from '../setup-http-agent-env'
import { workAsyncStorage } from '../app-render/work-async-storage.external'
import { workUnitAsyncStorage } from '../app-render/work-unit-async-storage.external'
import { getServerModuleMap

s */
import {
  decodeReply,
  decodeReplyFromAsyncIterable,
  createTemporaryReferenceSet,
} from 'react-server-dom-webpack/server'
import type { CacheKeyParts } from '../use-cache/use-cache-wrapper'
/* eslint-enable import/no-extraneous-dependencies */

 } from '../app-render/manifests-singleton'
import { createSnapshot } from '../app-render/async-local-storage'
import { createRequestStore } from '../async-storage/request-store'
/* eslint-disable import/no-extraneous-dependencie


ger() // Reset singleton
    fileLogger = getFileLogger()
    fileLogger.initialize(tempDir, true) // Enable mcpServer for testing
  })

  afterEach(() => {
    // Clean up temporary directory
    if (fs.existsSync(tempDir)) {
      fs.rmSync(tempDir, { recursive: true, force: true })
    }
  })

  it('should create log file on first log', () => {
    // Log a message
    fileLogger.logBrowser('LOG', 'Test message')

    // Force flush to ensure the log is written
    fileLogger.forceFlush()

    // Check t

xpect(logFiles[0]).toBe('next-development.log')
  })

  it('should format log entries correctly', () => {
    fileLogger.logBrowser('LOG', 'Test message')
    fileLogger.logServer('ERROR', 'Server error')

    // Force flush to ensure logs are written

hat a log file was created in the logs directory
    const logsDir = path.join(tempDir, 'logs')
    expect(fs.existsSync(logsDir)).toBe(true)

    const logFiles = fs.readdirSync(logsDir)
    expect(logFiles.length).toBe(1)
    e


 'Server' | 'Browser'
  level: string
  message: string
}

// Logging server and browser logs to a file
export class FileLogger {
  private logFilePath: string = ''
  private isInitialized: boolean = false
  private logQueue: string[] = []
  private flushTimer: NodeJS.Timeout | null = null
  private mcpServerEnabled: boolean = false

  public initialize(distDir: string, mcpServerEnabled: boolean): void {
    this.logFilePath = path.join(distDir, 'logs', `next-development.log`)
    this.mcpServerEnabled = mc

n
      // ensure the directory exists
      fs.mkdirSync(path.dirname(this.logFilePath), { recursive: true })
      fs.writeFileSync(this.logFilePath, '')
      this.isInitialized = true
    } catch (error) {
      console.error(error)
    }
  }

  privat

pServerEnabled

    if (this.isInitialized) {
      return
    }

    // Only initialize if mcpServer is enabled
    if (!this.mcpServerEnabled) {
      return
    }

    try {
      // Clean up the log file on each initializatio


gs'

describe('stripFormatSpecifiers', () => {
  it('should only process when first arg is string containing %', () => {
    expect(stripFormatSpecifiers([])).toEqual([])
    expect(stripFormatSpecifiers([123])).toEqual([123])
    expect(stripFormatSpecifiers(['no percent'])).toEqual(['no percent'])
  })

  it('should replace format specifiers with their arguments', () => {
    expect(stripFormatSpecifiers(['%s', 'string'])).toEqual(['string'])
    expect(stripFormatSpecifiers(['Hello %s', 'world'])).toEqua

 expect(stripFormatSpecifiers(['%o', { a: 1 }])).toEqual(['{ a: 1 }'])
    expect(stripFormatSpecifiers(['%O', { a: 1 }])).toEqual(['{ a: 1 }'])
    expect(stripFormatSpecifiers(['%j', { a: 1 }])).toEqual(['{ a: 1 }'])
  })

  it('should strip CSS styling

l([
      'Hello world',
    ])

    expect(stripFormatSpecifiers(['%d', 42])).toEqual(['42'])
    expect(stripFormatSpecifiers(['%i', 123])).toEqual(['123'])
    expect(stripFormatSpecifiers(['%f', 3.14])).toEqual(['3.14'])


ray<LogMethod> = [
  'log',
  'info',
  'warn',
  'debug',
  'table',
  'error',
  'assert',
  'dir',
  'dirxml',
  'group',
  'groupCollapsed',
  'groupEnd',
]

const methodsToSkipInspect = new Set([
  'table',
  'dir',
  'dirxml',
  'group',
  'groupCollapsed',
  'groupEnd',
])

// we aren't overriding console, we're just making a (slightly convoluted) helper for replaying user console methods
const forwardConsole: typeof console = {
  ...console,
  ...Object.fromEntries(
    methods.map((method) => [

    ? arg
              : // we hardcode depth:Infinity to allow the true depth to be configured by the serialization done in the browser (which is controlled by user)
                util.inspect(arg, { depth: Infinity, colors: true })
          )

   method,
      (...args: Array<any>) =>
        (console[method] as any)(
          ...args.map((arg) =>
            methodsToSkipInspect.has(method) ||
            typeof arg !== 'object' ||
            arg === null


ype { Project } from '../../../build/swc/types'
import { dim } from '../../../lib/picocolors'
import { parseStack, type StackFrame } from '../../lib/parse-stack'
import path from 'path'
import { LRUCache } from '../../lib/lru-cache'

type WebpackMappingContext = {
  bundler: 'webpack'
  isServer: boolean
  isEdgeServer: boolean
  isAppDirectory: boolean
  clientStats: () => any
  serverStats: () => any
  edgeServerStats: () => any
  rootDirectory: string
}

type TurbopackMappingContext = {
  bundler: 'turbo

er error source mapping correctly
export async function mapFramesUsingBundler(
  frames: StackFrame[],
  ctx: MappingContext
) {
  switch (ctx.bundler) {
    case 'webpack': {
      const {
        isServer,
        isEdgeServer,
        isAppDirectory,

pack'
  isServer: boolean
  isEdgeServer: boolean
  isAppDirectory: boolean
  project: Project
  projectPath: string
}

export type MappingContext = WebpackMappingContext | TurbopackMappingContext

// TODO: handle server vs brows


ort type { ReadonlyRequestCookies } from '../web/spec-extension/adapters/request-cookies'
import type { ResponseCookies } from '../web/spec-extension/cookies'

import {
  COOKIE_NAME_PRERENDER_BYPASS,
  checkIsOnDemandRevalidate,
} from '../api-utils'
import type { __ApiPreviewProps } from '../api-utils'

export class DraftModeProvider {
  /**
   * @internal - this declaration is stripped via `tsc --stripInternal`
   */
  private _isEnabled: boolean

  /**
   * @internal - this declaration is stripped via `

tor(
    previewProps: __ApiPreviewProps | undefined,
    headers: Headers | IncomingHttpHeaders,
    cookies: ReadonlyRequestCookies,
    mutableCookies: ResponseCookies
  ) {
    // The logic for draftMode() is very similar to tryGetPreviewData()
    //

tsc --stripInternal`
   */
  private readonly _previewModeId: string | undefined

  /**
   * @internal - this declaration is stripped via `tsc --stripInternal`
   */
  private readonly _mutableCookies: ResponseCookies

  construc


/../client/components/app-router-headers'
import {
  HeadersAdapter,
  type ReadonlyHeaders,
} from '../web/spec-extension/adapters/headers'
import {
  MutableRequestCookiesAdapter,
  RequestCookiesAdapter,
  responseCookiesToRequestCookies,
  createCookiesWithMutableAccessCheck,
  type ReadonlyRequestCookies,
} from '../web/spec-extension/adapters/request-cookies'
import { ResponseCookies, RequestCookies } from '../web/spec-extension/cookies'
import { DraftModeProvider } from './draft-mode-provider'
import

arams'
import type { ImplicitTags } from '../lib/implicit-tags'
import type { OpaqueFallbackRouteParams } from '../request/fallback-params'

function getHeaders(headers: Headers | IncomingHttpHeaders): ReadonlyHeaders {
  const cleaned = HeadersAdapter.fro

 { splitCookiesString } from '../web/utils'
import type { ServerComponentsHmrCache } from '../response-cache'
import type { ResumeDataCache } from '../resume-data-cache/resume-data-cache'
import type { Params } from '../request/p


e { FetchMetric } from '../base-http'
import type { RequestLifecycleOpts } from '../base-server'
import type { AppSegmentConfig } from '../../build/segment-config/app/app-segment-config'
import type { CacheLife } from '../use-cache/cache-life'
import type { ValidationLevel } from '../config-shared'

import { AfterContext } from '../after/after-context'

import { normalizeAppPath } from '../../shared/lib/router/utils/app-paths'
import { createLazyResult, type LazyResult } from '../lib/lazy-result'
import { g

 page file.
   */
  page: string

  isPrefetchRequest?: boolean
  nonce?: string
  renderOpts: {
    cacheLifeProfiles?: { [profile: string]: CacheLife }
    staticPageGenerationTimeout: number
    incrementalCache?: IncrementalCache
    isOnDemandRevalida

etCacheHandlerEntries } from '../use-cache/handlers'
import { createSnapshot } from '../app-render/async-local-storage'

export type WorkStoreContext = {
  /**
   * The page that is being rendered. This relates to the path to the


{
  postponeWithTracking,
  throwToInterruptStaticGeneration,
  trackDynamicDataInDynamicRender,
} from '../app-render/dynamic-rendering'
import { StaticGenBailoutError } from '../../client/components/static-generation-bailout'
import {
  makeHangingPromise,
  makeDevtoolsIOAwarePromise,
} from '../dynamic-rendering-utils'
import { isRequestAPICallableInsideAfter } from './utils'
import { applyOwnerStack } from '../dynamic-rendering-utils'
import { RenderStage } from '../app-render/staged-rendering'
import

ng it resolves immediately.
 */
export function connection(): Promise<void> {
  const callingExpression = 'connection'
  const workStore = workAsyncStorage.getStore()
  const workUnitStore = workUnitAsyncStorage.getStore()

  if (workStore) {
    if (

{ InvariantError } from '../../shared/lib/invariant-error'

/**
 * This function allows you to indicate that you require an actual user Request before continuing.
 *
 * During prerendering it will never resolve and during renderi


  type RequestStore,
  isInEarlyRenderStage,
} from '../app-render/work-unit-async-storage.external'
import {
  postponeWithTracking,
  throwToInterruptStaticGeneration,
  trackDynamicDataInDynamicRender,
} from '../app-render/dynamic-rendering'
import { StaticGenBailoutError } from '../../client/components/static-generation-bailout'
import {
  delayUntilRuntimeStage,
  makeDevtoolsIOAwarePromise,
  makeHangingPromise,
} from '../dynamic-rendering-utils'
import { createDedupedByCallsiteServerErrorLoggerDev

nvariant-error'
import { RenderStage } from '../app-render/staged-rendering'

export function cookies(): Promise<ReadonlyRequestCookies> {
  const callingExpression = 'cookies'
  const workStore = workAsyncStorage.getStore()
  const workUnitStore = workUni

 } from '../create-deduped-by-callsite-server-error-logger'
import { isRequestAPICallableInsideAfter } from './utils'
import { applyOwnerStack } from '../dynamic-rendering-utils'
import { InvariantError } from '../../shared/lib/i


bortAndThrowOnSynchronousRequestDataAccess,
  postponeWithTracking,
  trackDynamicDataInDynamicRender,
} from '../app-render/dynamic-rendering'
import { createDedupedByCallsiteServerErrorLoggerDev } from '../create-deduped-by-callsite-server-error-logger'
import { StaticGenBailoutError } from '../../client/components/static-generation-bailout'
import { DynamicServerError } from '../../client/components/hooks-server-context'
import { InvariantError } from '../../shared/lib/invariant-error'
import { delayUnti

e> {
  const callingExpression = 'draftMode'
  const workStore = workAsyncStorage.getStore()
  const workUnitStore = workUnitAsyncStorage.getStore()

  if (!workStore || !workUnitStore) {
    throwForMissingRequestStore(callingExpression)
  }

  switch (wo

lRuntimeStage } from '../dynamic-rendering-utils'
import { ReflectAdapter } from '../web/spec-extension/adapters/reflect'
import { applyOwnerStack } from '../dynamic-rendering-utils'

export function draftMode(): Promise<DraftMod


allelRoutes
  return [segment, routes, {}, null]
}

/**
 * Creates a mock AppPageRouteModule for testing.
 */
function createMockRouteModule(loaderTree: LoaderTree): AppPageRouteModule {
  return {
    userland: {
      loaderTree,
    },
  } as AppPageRouteModule
}

describe('createOpaqueFallbackRouteParams', () => {
  describe('opaque object interface', () => {
    const fallbackParams: readonly FallbackRouteParam[] = [
      { paramName: 'slug', paramType: 'dynamic' },
      { paramName: 'modal', paramTy

      expect(result.has('nonexistent')).toBe(false)
      expect(result.has('')).toBe(false)
    })

    it('get method works correctly', () => {
      const result = createOpaqueFallbackRouteParams(fallbackParams)!

      expect(result.get('slug')?.[0]).t

pe: 'dynamic' },
    ]

    it('has method works correctly', () => {
      const result = createOpaqueFallbackRouteParams(fallbackParams)!

      expect(result.has('slug')).toBe(true)
      expect(result.has('modal')).toBe(true)


ed/lib/app-router-types'
import { dynamicParamTypes } from '../app-render/get-short-dynamic-param-type'
import type AppPageRouteModule from '../route-modules/app-page/module'
import { parseNormalizedAppRoute } from '../../shared/lib/router/routes/app'
import { extractPathnameRouteParamSegmentsFromLoaderTree } from '../../build/static-paths/app/extract-pathname-route-param-segments-from-loader-tree'
import { getParamProperties } from '../../shared/lib/router/utils/get-segment-param'

export type OpaqueFallba

c param type of the fallback route param. This is the type of
   * the dynamic param that will be used to replace the dynamic param in the
   * postponed state.
   */
  dynamicParamType: DynamicParamTypesShort,
]

/**
 * An opaque fallback route params obj

ckRouteParamValue = [
  /**
   * The search value of the fallback route param. This is the opaque key
   * that will be used to replace the dynamic param in the postponed state.
   */
  searchValue: string,

  /**
   * The dynami


eWithTracking,
  throwToInterruptStaticGeneration,
  trackDynamicDataInDynamicRender,
} from '../app-render/dynamic-rendering'
import { StaticGenBailoutError } from '../../client/components/static-generation-bailout'
import {
  delayUntilRuntimeStage,
  makeDevtoolsIOAwarePromise,
  makeHangingPromise,
} from '../dynamic-rendering-utils'
import { createDedupedByCallsiteServerErrorLoggerDev } from '../create-deduped-by-callsite-server-error-logger'
import { isRequestAPICallableInsideAfter } from './utils'
im

e HTTP incoming request headers in
 * [Server Components](https://nextjs.org/docs/app/building-your-application/rendering/server-components),
 * [Server Actions](https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions-and-mutatio

port { applyOwnerStack } from '../dynamic-rendering-utils'
import { InvariantError } from '../../shared/lib/invariant-error'
import { RenderStage } from '../app-render/staged-rendering'

/**
 * This function allows you to read th


rage } from '../app-render/work-unit-async-storage.external'
import {
  makeHangingPromise,
  makeDevtoolsIOAwarePromise,
} from '../dynamic-rendering-utils'
import { RenderStage } from '../app-render/staged-rendering'
import { throwPrerenderPPRRemovedError } from '../../shared/lib/ppr-removed-error'

// A fulfilled thenable that React can unwrap synchronously via `use()` without
// ever suspending. Reusing a single instance avoids allocating on every call.
const resolvedIOPromise: Promise<void> = Promise.r

rces such as `new Date()` or `Math.random()`.
 *
 * During prerendering it will prevent the prerender from continuing past this
 * point, creating a dynamic boundary. Inside `"use cache"` scopes or during
 * a real request it resolves immediately.
 *
 * Un

esolve(undefined)
;(resolvedIOPromise as any).status = 'fulfilled'
;(resolvedIOPromise as any).value = undefined

/**
 * This function allows you to indicate that the code following it performs
 * I/O or accesses dynamic data sou


rk-unit-async-storage.external'
import { InvariantError } from '../../shared/lib/invariant-error'
import {
  describeStringPropertyAccess,
  wellKnownProperties,
} from '../../shared/lib/utils/reflect-utils'
import {
  makeDevtoolsIOAwarePromise,
  makeHangingPromise,
} from '../dynamic-rendering-utils'
import { createDedupedByCallsiteServerErrorLoggerDev } from '../create-deduped-by-callsite-server-error-logger'
import { dynamicAccessAsyncStorage } from '../app-render/dynamic-access-async-storage.external'

s: Params
): Promise<Params> {
  const workStore = workAsyncStorage.getStore()
  if (!workStore) {
    throw new InvariantError('Expected workStore to be initialized')
  }
  const workUnitStore = workUnitAsyncStorage.getStore()
  if (workUnitStore) {
    s

import { RenderStage } from '../app-render/staged-rendering'

export type ParamValue = string | Array<string> | undefined
export type Params = Record<string, ParamValue>

export function createParamsFromClient(
  underlyingParam


ort {
  postponeWithTracking,
  type DynamicTrackingState,
} from '../app-render/dynamic-rendering'

import {
  throwInvariantForMissingStore,
  workUnitAsyncStorage,
  type PrerenderStoreLegacy,
  type PrerenderStoreModernServer,
  type PrerenderStorePPR,
} from '../app-render/work-unit-async-storage.external'
import {
  delayUntilRuntimeStage,
  makeHangingPromise,
} from '../dynamic-rendering-utils'
import { InvariantError } from '../../shared/lib/invariant-error'

export function createServerPathnameFor

UnitAsyncStorage.getStore()
  if (workUnitStore) {
    switch (workUnitStore.type) {
      case 'prerender':
      case 'prerender-ppr':
      case 'prerender-legacy': {
        return createPrerenderPathname(
          underlyingPathname,
          workSt

Metadata(
  underlyingPathname: string
): Promise<string> {
  const workStore = workAsyncStorage.getStore()
  if (!workStore) {
    throw new InvariantError('Expected workStore to be initialized')
  }
  const workUnitStore = work


  type WorkStore,
} from '../app-render/work-async-storage.external'
import {
  workUnitAsyncStorage,
  type PrerenderStoreLegacy,
  type PrerenderStoreModernServer,
  type PrerenderStorePPR,
} from '../app-render/work-unit-async-storage.external'
import { makeHangingPromise } from '../dynamic-rendering-utils'
import type { ParamValue } from './params'
import { describeStringPropertyAccess } from '../../shared/lib/utils/reflect-utils'
import { actionAsyncStorage } from '../app-render/action-async-storage.e

 {
  const apiName = `\`import('next/root-params').${paramName}()\``

  const workStore = workAsyncStorage.getStore()
  if (!workStore) {
    throw new InvariantError(`Missing workStore in ${apiName}`)
  }

  const workUnitStore = workUnitAsyncStorage.getS

xternal'
import { accumulateRootVaryParam } from '../app-render/vary-params'

/**
 * Used for the compiler-generated `next/root-params` module.
 * @internal
 */
export function getRootParam(paramName: string): Promise<ParamValue>


nvariantError } from '../../shared/lib/invariant-error'
import {
  makeDevtoolsIOAwarePromise,
  makeHangingPromise,
} from '../dynamic-rendering-utils'
import { createDedupedByCallsiteServerErrorLoggerDev } from '../create-deduped-by-callsite-server-error-logger'
import {
  describeStringPropertyAccess,
  describeHasCheckingStringProperty,
  wellKnownProperties,
} from '../../shared/lib/utils/reflect-utils'
import {
  throwWithStaticGenerationBailoutErrorWithDynamicError,
  throwForSearchParamsAccessInUseC

ams: SearchParams
): Promise<SearchParams> {
  const workStore = workAsyncStorage.getStore()
  if (!workStore) {
    throw new InvariantError('Expected workStore to be initialized')
  }
  const workUnitStore = workUnitAsyncStorage.getStore()
  if (workUnit

ache,
} from './utils'
import { RenderStage } from '../app-render/staged-rendering'

export type SearchParams = { [key: string]: string | string[] | undefined }

export function createSearchParamsFromClient(
  underlyingSearchPar


ticGenBailoutError } from '../../client/components/static-generation-bailout'
import { afterTaskAsyncStorage } from '../app-render/after-task-async-storage.external'
import type { WorkStore } from '../app-render/work-async-storage.external'

export function throwWithStaticGenerationBailoutErrorWithDynamicError(
  route: string,
  expression: string
): never {
  throw new StaticGenBailoutError(
    `Route ${route} with \`dynamic = "error"\` couldn't be rendered statically because it used ${expression}. See m

): never {
  const error = new Error(
    `Route ${workStore.route} used \`searchParams\` inside "use cache". Accessing dynamic request data inside a cache scope is not supported. If you need some search params inside a cached function await \`searchParams

ore info here: https://nextjs.org/docs/app/building-your-application/rendering/static-and-dynamic#dynamic-rendering`
  )
}

export function throwForSearchParamsAccessInUseCache(
  workStore: WorkStore,
  constructorOpt: Function


import { RouteKind } from '../route-kind'
import RenderResult from '../render-result'
import { HTML_CONTENT_TYPE_HEADER } from '../../lib/constants'

function mockIncrementalCache() {
  return {
    get: jest.fn().mockResolvedValue(null),
    set: jest.fn().mockResolvedValue(undefined),
  }
}

function makeCacheEntry(html: string): ResponseCacheEntry {
  return {
    value: {
      kind: CachedRouteKind.APP_PAGE,
      html: RenderResult.fromStatic(html, HTML_CONTENT_TYPE_HEADER),
      rscData: Buffer.fro

escribe('minimal mode LRU population for batched invocations', () => {
    it('should populate LRU for all batched invocationIDs, not just the winner', async () => {
      const cache = new ResponseCache(true)
      const incrementalCache = mockIncremental

m('rsc-payload'),
      postponed: undefined,
      status: 200,
      headers: undefined,
      segmentData: undefined,
    },
    cacheControl: { revalidate: 60, expire: undefined },
  }
}

describe('ResponseCache', () => {
  d


alCacheKind,
  toResponseCacheEntry,
} from './utils'
import type { RouteKind } from '../route-kind'

/**
 * Parses an environment variable as a positive integer, returning the fallback
 * if the value is missing, not a number, or not positive.
 */
function parsePositiveInt(
  envValue: string | undefined,
  fallback: number
): number {
  if (!envValue) return fallback
  const parsed = parseInt(envValue, 10)
  return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback
}

/**
 * Default TTL (in millise

cessive requests (e.g., page + data)
 * - Short enough to not serve stale data across unrelated requests
 *
 * Can be configured via `NEXT_PRIVATE_RESPONSE_CACHE_TTL` environment variable.
 */
const DEFAULT_TTL_MS = parsePositiveInt(
  process.env.NEXT_PRI

conds) for minimal mode response cache entries.
 * Used for cache hit validation as a fallback for providers that don't
 * send the x-invocation-id header yet.
 *
 * 10 seconds chosen because:
 * - Long enough to dedupe rapid suc


te-kind'

export interface ResponseCacheBase {
  get(
    key: string | null,
    responseGenerator: ResponseGenerator,
    context: {
      isOnDemandRevalidate?: boolean
      isPrefetch?: boolean
      incrementalCache: IncrementalCache
      /**
       * This is a hint to the cache to help it determine what kind of route
       * this is so it knows where to look up the cache entry from. If not
       * provided it will test the filesystem to check.
       */
      routeKind: RouteKind

      /**

 The server components HMR cache might store other data as well in the future,
// at which point this should be refactored to a discriminated union type.
export interface ServerComponentsHmrCache {
  get(key: string): CachedFetchData | undefined
  set(key:

 * True if this is a fallback request.
       */
      isFallback?: boolean

      /**
       * True if the route is enabled for PPR.
       */
      isRoutePPREnabled?: boolean
    }
  ): Promise<ResponseCacheEntry | null>
}

//


  type IncrementalResponseCacheEntry,
  type ResponseCacheEntry,
} from './types'

import RenderResult from '../render-result'
import { RouteKind } from '../route-kind'
import { HTML_CONTENT_TYPE_HEADER } from '../../lib/constants'

export async function fromResponseCacheEntry(
  cacheEntry: ResponseCacheEntry
): Promise<IncrementalResponseCacheEntry> {
  return {
    ...cacheEntry,
    value:
      cacheEntry.value?.kind === CachedRouteKind.PAGES
        ? {
            kind: CachedRouteKind.PAGES,

acheEntry.value?.kind === CachedRouteKind.APP_PAGE
          ? {
              kind: CachedRouteKind.APP_PAGE,
              html: await cacheEntry.value.html.toUnchunkedString(true),
              postponed: cacheEntry.value.postponed,
              rscDa

      html: await cacheEntry.value.html.toUnchunkedString(true),
            pageData: cacheEntry.value.pageData,
            headers: cacheEntry.value.headers,
            status: cacheEntry.value.status,
          }
        : c


-probe-globals'

const PROBE_THRESHOLD_MS = 10_000
const MIN_PROBE_BUDGET_MS = 3_000

interface CacheContextWithProbeFields {
  readonly functionId: string
  readonly handlerKind: string
}

interface SetupOptions {
  workStore: WorkStore
  outerRequestStore: RequestStore
  cacheContext: CacheContextWithProbeFields
  encodedArguments: string | FormData
  /**
   * Absolute monotonic deadline (in `performance.now()` units) at which the
   * outer cache fill will be aborted by the dev render-timeout timer. The

s through resets the idle timer;
   * the returned stream is the same data, transparently observed.
   */
  stream: ReadableStream<Uint8Array>
  /**
   * Aborts when the probe should stop watching: the cache fill bailed (timeout,
   * upstream cancel, dead

   * scheduler derives the up-front budget check, every reschedule budget check,
   * and each probe's internal timeout from this single value.
   */
  fillDeadlineAt: number
  /**
   * Cache stream to track. Each chunk that flow


port { LocaleRouteMatcher } from '../route-matchers/locale-route-matcher'
import { RouteMatcher } from '../route-matchers/route-matcher'
import { DefaultRouteMatcherManager } from './default-route-matcher-manager'
import type { MatchOptions } from './route-matcher-manager'

describe('DefaultRouteMatcherManager', () => {
  it('will throw an error when used before it has been reloaded', async () => {
    const manager = new DefaultRouteMatcherManager()
    await expect(manager.match('/some/not/real/path', {})

/some/not/real/path', {})).resolves.toEqual(
      null
    )
  })

  it('will not error and not match when no matchers are provided', async () => {
    const manager = new DefaultRouteMatcherManager()
    await manager.reload()
    await expect(manager.ma

).resolves.toEqual(
      null
    )
    manager.push({ matchers: jest.fn(async () => []) })
    await expect(manager.match('/some/not/real/path', {})).rejects.toThrow()
    await manager.reload()
    await expect(manager.match('


h'
import type { RouteDefinition } from '../route-definitions/route-definition'
import { DefaultRouteMatcherManager } from './default-route-matcher-manager'
import type { MatchOptions, RouteMatcherManager } from './route-matcher-manager'
import path from '../../shared/lib/isomorphic/path'
import * as Log from '../../build/output/log'
import { cyan } from '../../lib/picocolors'
import type { RouteMatcher } from '../route-matchers/route-matcher'

export interface RouteEnsurer {
  ensure(match: RouteMatch, pat

e readonly dir: string
  ) {
    super()
  }

  public async test(pathname: string, options: MatchOptions): Promise<boolean> {
    // Try to find a match within the developer routes.
    const match = await super.match(pathname, options)

    // Return if

hname: string): Promise<void>
}

export class DevRouteMatcherManager extends DefaultRouteMatcherManager {
  constructor(
    private readonly production: RouteMatcherManager,
    private readonly ensurer: RouteEnsurer,
    privat


oute-match'
import type { RouteMatcherProvider } from '../route-matcher-providers/route-matcher-provider'
import type { LocaleAnalysisResult } from '../lib/i18n-provider'

export type MatchOptions = {
  skipDynamic?: boolean

  /**
   * If defined, this indicates to the matcher that the request should be
   * treated as locale-aware. If this is undefined, it means that this
   * application was not configured for additional locales.
   */
  i18n?: LocaleAnalysisResult | undefined
}

export interface RouteMa

   * providers have been pushed, the manager must be reloaded.
   *
   * @param provider the provider for this manager to also manage
   */
  push(provider: RouteMatcherProvider): void

  /**
   * Reloads the matchers from the providers. This should be don

tcherManager {
  /**
   * Returns a promise that resolves when the matcher manager has finished
   * reloading.
   */
  waitTillReady(): Promise<void>

  /**
   * Pushes in a new matcher for this manager to manage. After all the


'
import url from 'url'
import type { RawSourceMap } from 'next/dist/compiled/source-map08'
import dataUriToBuffer from 'next/dist/compiled/data-uri-to-buffer'

function getSourceMapUrl(fileContents: string): string | null {
  const regex = /\/\/[#@] ?sourceMappingURL=([^\s'"]+)\s*$/gm
  let match = null
  for (;;) {
    let next = regex.exec(fileContents)
    if (next == null) {
      break
    }
    match = next
  }
  if (!(match && match[1])) {
    return null
  }
  return match[1].toString()
}

export a

ileContents = await fs.readFile(filename, 'utf-8')
  } catch (error) {
    throw new Error(`Failed to read file contents of ${filename}.`, {
      cause: error,
    })
  }

  const sourceUrl = getSourceMapUrl(fileContents)

  if (!sourceUrl) {
    return u

sync function getSourceMapFromFile(
  filename: string
): Promise<RawSourceMap | undefined> {
  filename = filename.startsWith('file://')
    ? url.fileURLToPath(filename)
    : filename

  let fileContents: string

  try {
    f


including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:

// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE W

,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
import type { webpack } from 'next/dist/compiled/webpack/webpack'
import type ws from 'next/dist/compiled/ws'
import type { Dev

ARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT


/shared/lib/router/utils/path-match'
import { parseVersionInfo, type VersionInfo } from './parse-version-info'

export const matchNextPageBundleRequest = getPathMatch(
  '/_next/static/chunks/pages/:path*.js(\\.map|)'
)
export async function getVersionInfo(): Promise<VersionInfo> {
  let installed = '0.0.0'

  try {
    installed = require('next/package.json').version

    let res

    try {
      // use NPM registry regardless user using Yarn
      res = await fetch('https://registry.npmjs.org/-/package/ne

rrors
    }

    if (!res || !res.ok) return { installed, staleness: 'unknown' }

    const { latest, canary } = await res.json()

    return parseVersionInfo({ installed, latest, canary })
  } catch (e: any) {
    console.error(e)
    return { installed,

xt/dist-tags')
    } catch {
      // ignore fetch e