data'

describe('NextDataPathnameNormalizer', () => {
  describe('constructor', () => {
    it('should error when no buildID is provided', () => {
      expect(() => {
        new NextDataPathnameNormalizer('')
      }).toThrowErrorMatchingInlineSnapshot(`"Invariant: buildID is required"`)
    })
  })

  describe('match', () => {
    it('should return false if the pathname does not start with the prefix', () => {
      const normalizer = new NextDataPathnameNormalizer('build-id')
      const pathnames = ['/

nst normalizer = new NextDataPathnameNormalizer('build-id')
      const pathnames = ['/foo.json', '/foo/bar.json', '/fooo/bar.json']
      for (const pathname of pathnames) {
        expect(normalizer.match(pathname)).toBe(false)
      }
    })

    it('sh

foo', '/foo/bar', '/fooo/bar']
      for (const pathname of pathnames) {
        expect(normalizer.match(pathname)).toBe(false)
      }
    })

    it('should return false if the pathname only ends with `.json`', () => {
      co


ort type { PathnameNormalizer } from './pathname-normalizer'

import { denormalizePagePath } from '../../../shared/lib/page-path/denormalize-page-path'
import { PrefixPathnameNormalizer } from './prefix'
import { SuffixPathnameNormalizer } from './suffix'

export class NextDataPathnameNormalizer implements PathnameNormalizer {
  private readonly prefix: PrefixPathnameNormalizer
  private readonly suffix = new SuffixPathnameNormalizer('.json')
  constructor(buildID: string) {
    if (!buildID) {
      throw

ame)
  }

  public normalize(pathname: string, matched?: boolean): string {
    // If we're not matched and we don't match, we don't need to normalize.
    if (!matched && !this.match(pathname)) return pathname

    pathname = this.prefix.normalize(pathnam

new Error('Invariant: buildID is required')
    }

    this.prefix = new PrefixPathnameNormalizer(`/_next/data/${buildID}`)
  }

  public match(pathname: string) {
    return this.prefix.match(pathname) && this.suffix.match(pathn


rmalizer } from './prefix'

describe('PrefixPathnameNormalizer', () => {
  describe('match', () => {
    it('should return false if the pathname does not start with the prefix', () => {
      const normalizer = new PrefixPathnameNormalizer('/foo')
      const pathnames = ['/bar', '/bar/foo', '/fooo/bar']
      for (const pathname of pathnames) {
        expect(normalizer.match(pathname)).toBe(false)
      }
    })

    it('should return true if the pathname starts with the prefix', () => {
      const norma

should throw if the prefix ends with a slash', () => {
    expect(() => new PrefixPathnameNormalizer('/foo/')).toThrow()
    expect(() => new PrefixPathnameNormalizer('/')).toThrow()
  })

  describe('normalize', () => {
    it('should return the same path

lizer = new PrefixPathnameNormalizer('/foo')
      const pathnames = ['/foo', '/foo/bar', '/foo/bar/baz']
      for (const pathname of pathnames) {
        expect(normalizer.match(pathname)).toBe(true)
      }
    })
  })

  it('


export class PrefixPathnameNormalizer implements Normalizer {
  constructor(private readonly prefix: string) {
    if (prefix.endsWith('/')) {
      throw new Error(
        `PrefixPathnameNormalizer: prefix "${prefix}" should not end with a slash`
      )
    }
  }

  public match(pathname: string) {
    // If the pathname doesn't start with the prefix, we don't match.
    if (pathname !== this.prefix && !pathname.startsWith(this.prefix + '/')) {
      return false
    }

    return true
  }

  public no

 {
    // If we're not matched and we don't match, we don't need to normalize.
    if (!matched && !this.match(pathname)) return pathname

    if (pathname.length === this.prefix.length) {
      return '/'
    }

    return pathname.substring(this.prefix.l

rmalize(pathname: string, matched?: boolean): string


mentPrefixRSCPathnameNormalizer } from './segment-prefix-rsc'

describe('SegmentPrefixRSCPathnameNormalizer', () => {
  it('should match and extract the original pathname and segment path', () => {
    const normalizer = new SegmentPrefixRSCPathnameNormalizer()
    const result = normalizer.extract('/hello/hello.segments/_tree.segment.rsc')
    expect(result).toEqual({
      originalPathname: '/hello/hello',
      segmentPath: '/_tree',
    })
  })

  it('should extract segment prefetch paths for catch-all

(result).toEqual({
      originalPathname: '/catch/[...segments]',
      segmentPath: '/catch/$c$segments/__PAGE__',
    })
  })

  it('should still extract segment prefetch paths for other catch-all param names', () => {
    const normalizer = new Segment

params named segments', () => {
    const normalizer = new SegmentPrefixRSCPathnameNormalizer()
    const result = normalizer.extract(
      '/catch/[...segments].segments/catch/$c$segments/__PAGE__.segment.rsc'
    )

    expect


hnameNormalizer } from './pathname-normalizer'

import {
  RSC_SEGMENT_SUFFIX,
  RSC_SEGMENTS_DIR_SUFFIX,
} from '../../../lib/constants'
import { escapeStringRegexp } from '../../../shared/lib/escape-regexp'

const PATTERN = new RegExp(
  `^(/.*)${escapeStringRegexp(RSC_SEGMENTS_DIR_SUFFIX)}(/.*)${escapeStringRegexp(RSC_SEGMENT_SUFFIX)}$`
)

export class SegmentPrefixRSCPathnameNormalizer implements PathnameNormalizer {
  public match(pathname: string): boolean {
    return PATTERN.test(pathname)
  }

  pu

athname.match(PATTERN)
    if (!match) return null

    return { originalPathname: match[1], segmentPath: match[2] }
  }

  public normalize(pathname: string): string {
    const match = this.extract(pathname)
    if (!match) return pathname

    return ma

blic extract(pathname: string) {
    const match = p


rmalizer } from './suffix'

describe('SuffixPathnameNormalizer', () => {
  describe('match', () => {
    it('should return false if the pathname does not end with `.rsc`', () => {
      const normalizer = new SuffixPathnameNormalizer('.rsc')
      const pathnames = ['/foo', '/foo/bar', '/fooo/bar']
      for (const pathname of pathnames) {
        expect(normalizer.match(pathname)).toBe(false)
      }
    })

    it('should return true if it matches', () => {
      const normalizer = new SuffixPathnameNorma

> {
    it('should return the same pathname if we are not matched and the pathname does not end with `.rsc`', () => {
      const normalizer = new SuffixPathnameNormalizer('.rsc')
      const pathnames = ['/foo', '/foo/bar', '/fooo/bar']
      for (const p

lizer('.rsc')
      const pathnames = ['/foo.rsc', '/foo/bar.rsc', '/fooo/bar.rsc']
      for (const pathname of pathnames) {
        expect(normalizer.match(pathname)).toBe(true)
      }
    })
  })

  describe('normalize', () =


| ErrorReport
  | OutputReport
  | SerializableDataReport

type ConsoleCallReport = {
  type: 'console-call'
  method: string
  input: string
}

type ErrorReport = { type: 'error'; message: string }
type OutputReport = { type: 'output'; message: string }
type SerializableDataReport = {
  type: 'serialized'
  key: string
  data: string | number | boolean
}

declare global {
  function reportResult(result: ReportableResult): void
}

import { Worker } from 'node:worker_threads'

type WorkerResult = {
  exitCod

urn new Promise((resolve, reject) => {
    const script = `
      const { parentPort } = require('node:worker_threads');
      (async () => {
        const { AsyncLocalStorage } = require('node:async_hooks');
        // We need to put this on the global be

e: number
  stderr: string
  consoleCalls: Array<{ method: string; input: string }>
  data: Record<string, unknown>
  messages: Array<ReportableResult>
}

export function runWorkerCode(fn: Function): Promise<WorkerResult> {
  ret


used-vars -- we may use later and want parity with the HIDDEN_STYLE value
const DIMMED_STYLE = 'dimmed'
const HIDDEN_STYLE = 'hidden'

type LogStyle = typeof DIMMED_STYLE | typeof HIDDEN_STYLE

let currentAbortedLogsStyle: LogStyle = 'dimmed'
export function setAbortedLogsStyle(style: LogStyle) {
  currentAbortedLogsStyle = style
}

type InterceptableConsoleMethod =
  | 'error'
  | 'assert'
  | 'debug'
  | 'dir'
  | 'dirxml'
  | 'group'
  | 'groupCollapsed'
  | 'groupEnd'
  | 'info'
  | 'log'
  | 'table'

nction dimmedConsoleArgs(...inputArgs: any[]): any[] {
  if (!isColorSupported) {
    return inputArgs
  }

  const newArgs = inputArgs.slice(0)
  let template = ''
  let argumentsPointer = 0
  if (typeof inputArgs[0] === 'string') {
    const originalTemp

| 'trace'
  | 'warn'

const isColorSupported = dim('test') !== 'test'

// 50% opacity for dimmed text
const dimStyle = 'color: color(from currentColor xyz x y z / 0.5);'
const reactBadgeFormat = '\x1b[0m\x1b[7m%c%s\x1b[0m%c '

fu


portableResult): void
}

import type { WorkUnitStore } from '../app-render/work-unit-async-storage.external'
import { Worker } from 'node:worker_threads'

type WorkerResult = {
  exitCode: number
  stderr: string
  consoleCalls: Array<{ method: string; input: string }>
  data: Record<string, unknown>
  messages: Array<ReportableResult>
}

export function runWorkerCode(fn: Function): Promise<WorkerResult> {
  return new Promise((resolve, reject) => {
    const script = `
      const { parentPort } = require(

ompatible with edge runtimes.
        globalThis.AsyncLocalStorage = AsyncLocalStorage;

        global.reportResult = (value) => {
          parentPort?.postMessage(value);
        };

        const fn = (${fn.toString()});
        try {
          const o

'node:worker_threads');
      (async () => {
        const { AsyncLocalStorage } = require('node:async_hooks');
        // We need to put this on the global because Next.js does not import it
        // from node directly to be c


AsyncStorage so that inside the host implementation
 * sync IO can be called. This is relevant for example with runtimes that patch console methods to
 * prepend a timestamp to the log output.
 *
 * Note that this will only exit for already installed patched console methods. If you further patch
 * the console method after this and add any sync IO there it will trigger sync IO warnings while prerendering.
 *
 * This is a pragmatic concession because layering the patches if you install your own log implement

on patchConsoleMethod(methodName: ConsoleMethodName): void {
  const descriptor = Object.getOwnPropertyDescriptor(console, methodName)
  if (
    descriptor &&
    (descriptor.configurable || descriptor.writable) &&
    typeof descriptor.value === 'functio

ation
 * after they are installed is very tricky to do correctly because the order matters
 */

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

type ConsoleMethodName = keyof Console

functi


console-async-storage.external'
import { getFileLogger } from '../dev/browser-logs/file-logger'
import { formatConsoleArgs } from '../../client/lib/console'

type InterceptableConsoleMethod =
  | 'error'
  | 'assert'
  | 'debug'
  | 'dir'
  | 'dirxml'
  | 'group'
  | 'groupCollapsed'
  | 'groupEnd'
  | 'info'
  | 'log'
  | 'table'
  | 'trace'
  | 'warn'

// Based on https://github.com/facebook/react/blob/28dc0776be2e1370fe217549d32aee2519f0cf05/packages/react-server/src/ReactFlightServer.js#L248
function pa

peof descriptor.value === 'function'
  ) {
    const originalMethod = descriptor.value
    const originalName = Object.getOwnPropertyDescriptor(originalMethod, 'name')
    const wrapperMethod = function (this: typeof console, ...args: any[]) {
      const

tchConsoleMethodDEV(methodName: InterceptableConsoleMethod): void {
  const descriptor = Object.getOwnPropertyDescriptor(console, methodName)
  if (
    descriptor &&
    (descriptor.configurable || descriptor.writable) &&
    ty


es to ensure that prerenders don't observe the clock as a source of IO
 * When cacheComponents is enabled. The current time is a form of IO even though it resolves synchronously. When cacheComponents is
 * enabled we need to ensure that clock time is excluded from prerenders unless it is cached.
 *
 * There is tension here because time is used for both output and introspection. While arbitrary we intend to reserve
 * `Date` for output use cases and `performance` for introspection use cases. If you want to m

ted and thus should be transparent to callers.
 */
import { io } from './io-utils'

function createNow(originalNow: typeof Date.now) {
  return {
    now: function now() {
      io('`Date.now()`', 'time')
      return originalNow()
    },
  }['now'.slice()

easure
 * how long something takes use `performance.timeOrigin` and `performance.now()` rather than `Date.now()` for instance.
 *
 * The extensions here never error nor alter the underlying Date objects, strings, and numbers crea


> {
      log('timeout 1 -> immediate 2')
    })
    process.nextTick(() => {
      log('timeout 1 -> nextTick 1')
      queueMicrotask(() => {
        log('timeout 1 -> nextTick 1 -> microtask 1')
      })
      queueMicrotask(() => {
        process.nextTick(() => {
          log('timeout 1 -> nextTick 1 -> microtask 2 -> nextTick')
        })
      })
      process.nextTick(() => {
        log('timeout 1 -> nextTick 1 -> nextTick 1')
      })
    })
  })

  setTimeout(() => {
    DANGEROUSLY_runPendingIm

() => {
    log('timeout 3')
    try {
      expectNoPendingImmediates()
      done.resolve()
    } catch (err) {
      done.reject(err)
    }
  })

  await done.promise

  expect(logs).toEqual([
    // ===================================
    'timeout 1',

mediatesAfterCurrentTask()

    log('timeout 2')
    setImmediate(() => {
      log('timeout 2 -> immediate 1')
      setImmediate(() => {
        log('timeout 2 -> immediate 1 -> immediate 1')
      })
    })
  })

  setTimeout(


 setImmediate: globalThis.setImmediate,
    clearImmediate: globalThis.clearImmediate,
    nextTick: process.nextTick,
  })) as FastSetImmediateOriginals

let wasEnabledAtLeastOnce = false

let pendingNextTicks = 0
let currentExecution: Execution | null = null

const originalSetImmediate = originals.setImmediate
const originalClearImmediate = originals.clearImmediate
const originalNextTick = originals.nextTick
const originalSetImmediatePromisify: (typeof setImmediate)['__promisify__'] =
  typeof originalSet

on't ever enable the patch, so this can be a dummy value
      undefined!

function install() {
  if (process.env.NEXT_RUNTIME === 'edge') {
    // Nothing to patch. The exported functions all error if used in the edge runtime,
    // so we're not going to

Immediate === 'function'
    ? // @ts-expect-error: the types for `promisify.custom` are strange
      originalSetImmediate[promisify.custom]
    : // if setImmediate is not defined, we must be in the edge runtime,
      // and w


*
 * Unlike most files in the node-environment-extensions folder this one is not
 * an extension itself but it exposes a function to install config based global
 * behaviors that should be loaded whenever a Node Server or Node Worker are created.
 */
import { InvariantError } from '../../shared/lib/invariant-error'

import { setAbortedLogsStyle } from './console-dim.external'

export function installGlobalBehaviors(config: {
  experimental?: { hideLogsAfterAbort?: boolean }
}) {
  if (process.env.NEXT_RUNTI

 {
    throw new InvariantError(
      'Expected not to install Node.js global behaviors in the edge runtime.'
    )
  }

  if (config.experimental?.hideLogsAfterAbort === true) {
    setAbortedLogsStyle('hidden')
  } else {
    setAbortedLogsStyle('dimmed


rage } from '../app-render/work-unit-async-storage.external'
import { abortOnSynchronousPlatformIOAccess } from '../app-render/dynamic-rendering'
import { RenderStage } from '../app-render/staged-rendering'
import { applyOwnerStack } from '../dynamic-rendering-utils'
import {
  createSyncIOClientError,
  createSyncIOError,
  createSyncIORuntimeError,
  type SyncIOApiType,
} from '../app-render/sync-io-messages'

export function io(expression: string, type: SyncIOApiType) {
  const workUnitStore = workUnitAs

derSignal = workUnitStore.controller.signal

      if (prerenderSignal.aborted === false) {
        // If the prerender signal is already aborted we don't need to construct
        // any stacks because something else actually terminated the prerender.

yncStorage.getStore()
  const workStore = workAsyncStorage.getStore()

  if (!workUnitStore || !workStore) {
    return
  }

  switch (workUnitStore.type) {
    case 'prerender':
    case 'prerender-runtime': {
      const preren


synchronously. When cacheComponents is
 * enabled we need to ensure that random bytes are excluded from prerenders unless they are cached.
 *
 *
 * The extensions here never error nor alter the underlying return values and thus should be transparent to callers.
 */

import { io } from './io-utils'

if (process.env.NEXT_RUNTIME === 'edge') {
  // nothing to patch
} else {
  const nodeCrypto = require('node:crypto') as typeof import('node:crypto')

  // require('node:crypto').getRandomValues is an alias for

t _randomUUID = nodeCrypto.randomUUID
    nodeCrypto.randomUUID = function randomUUID() {
      io(randomUUIDExpression, 'random')
      return _randomUUID.apply(this, arguments as any)
    }
  } catch {
    console.error(
      `Failed to install ${random

 // crypto.getRandomValues which is extended in web-crypto.tsx

  // require('node:crypto').randomUUID is not an alias for crypto.randomUUID

  const randomUUIDExpression = "`require('node:crypto').randomUUID()`"
  try {
    cons


lThis & {
  nextInitializedProcessErrorHandlers?: boolean
}

export function installProcessErrorHandlers(
  shouldRemoveUncaughtErrorAndRejectionListeners: boolean
) {
  if (_global.nextInitializedProcessErrorHandlers) return
  _global.nextInitializedProcessErrorHandlers = true
  // The conventional wisdom of Node.js and other runtimes is to treat
  // unhandled errors as fatal and exit the process.
  //
  // But Next.js is not a generic JS runtime — it's a specialized runtime for
  // React Server Componen

 // without blocking unncessarily on the result. These can end up
  // triggering an "unhandledRejection" if it later turns out that the
  // data is not needed to render the page. Example:
  //
  //     const promise = fetchData()
  //     const shouldSho

ts.
  //
  // Many unhandled rejections are due to the late-awaiting pattern for
  // prefetching data. In Next.js it's OK to call an async function without
  // immediately awaiting it, to start the request as soon as possible


 * We extend Math.random() during builds and revalidates to ensure that prerenders don't observe randomness
 * When cacheComponents is enabled. randomness is a form of IO even though it resolves synchronously. When cacheComponents is
 * enabled we need to ensure that randomness is excluded from prerenders.
 *
 * The extensions here never error nor alter the random generation itself and thus should be transparent to callers.
 */

import { io } from './io-utils'

const expression = '`Math.random()`'
try {

toString`.
    // eslint-disable-next-line no-extra-bind
  }.bind(null)
  Object.defineProperty(Math.random, 'name', { value: 'random' })
} catch {
  console.error(
    `Failed to install ${expression} extension. When using \`cacheComponents\` calling this

const _random = Math.random
  Math.random = function random() {
    io(expression, 'random')
    return _random.apply(null, arguments as any)

    // We bind here to alter the `toString` printing to match `Math.random`'s native `


/route-definitions/app-route-route-definition'
import { RouteKind } from '../../route-kind'
import { DevAppRouteRouteMatcherProvider } from './dev-app-route-route-matcher-provider'
import type { FileReader } from './helpers/file-reader/file-reader'

describe.each(['webpack', 'turbopack'])(
  'DevAppRouteRouteMatcher %s',
  (bundler) => {
    const isTurbopack = bundler === 'turbopack'
    const dir = '<root>'
    const extensions = ['ts', 'tsx', 'js', 'jsx']

    it('returns no routes with an empty filesyst

atchers = await matcher.matchers()
      expect(matchers).toHaveLength(0)
      expect(reader.read).toHaveBeenCalledWith(dir)
    })

    describe('filename matching', () => {
      it.each<{
        files: ReadonlyArray<string>
        route: AppRouteRout

em', async () => {
      const reader: FileReader = { read: jest.fn(() => []) }
      const matcher = new DevAppRouteRouteMatcherProvider(
        dir,
        extensions,
        reader,
        isTurbopack
      )
      const m


Definition } from '../../route-definitions/pages-api-route-definition'
import { RouteKind } from '../../route-kind'
import { DevPagesAPIRouteMatcherProvider } from './dev-pages-api-route-matcher-provider'
import type { FileReader } from './helpers/file-reader/file-reader'

const normalizeSlashes = (p: string) => p.replace(/\//g, path.sep)

describe('DevPagesAPIRouteMatcherProvider', () => {
  const dir = '<root>'
  const extensions = ['ts', 'tsx', 'js', 'jsx']

  it('returns no routes with an empty filesyst

aveLength(0)
    expect(reader.read).toHaveBeenCalledWith(dir)
  })

  describe('filename matching', () => {
    it.each<{
      files: ReadonlyArray<string>
      route: PagesAPIRouteDefinition
    }>([
      {
        files: [normalizeSlashes(`${dir}/api

em', async () => {
    const reader: FileReader = { read: jest.fn(() => []) }
    const matcher = new DevPagesAPIRouteMatcherProvider(dir, extensions, reader)
    const matchers = await matcher.matchers()
    expect(matchers).toH


inition } from '../../route-definitions/pages-route-definition'
import { RouteKind } from '../../route-kind'
import { DevPagesRouteMatcherProvider } from './dev-pages-route-matcher-provider'
import type { FileReader } from './helpers/file-reader/file-reader'

const normalizeSlashes = (p: string) => p.replace(/\//g, path.sep)

describe('DevPagesRouteMatcherProvider', () => {
  const dir = '<root>'
  const extensions = ['ts', 'tsx', 'js', 'jsx']

  it('returns no routes with an empty filesystem', async () =>

ect(reader.read).toHaveBeenCalledWith(dir)
  })

  describe('filename matching', () => {
    it.each<{
      files: ReadonlyArray<string>
      route: PagesRouteDefinition
    }>([
      {
        files: [normalizeSlashes(`${dir}/index.ts`)],
        route

{
    const reader: FileReader = { read: jest.fn(() => []) }
    const matcher = new DevPagesRouteMatcherProvider(dir, extensions, reader)
    const matchers = await matcher.matchers()
    expect(matchers).toHaveLength(0)
    exp


matchers/route-matcher'
import { CachedRouteMatcherProvider } from '../helpers/cached-route-matcher-provider'
import type { FileReader } from './helpers/file-reader/file-reader'

/**
 * This will memoize the matchers when the file contents are the same.
 */
export abstract class FileCacheRouteMatcherProvider<
  M extends RouteMatcher = RouteMatcher,
> extends CachedRouteMatcherProvider<M, ReadonlyArray<string>> {
  constructor(dir: string, reader: FileReader) {
    super({
      load: async () => reader.rea

 (left.length !== right.length) return false

        // Assuming the file traversal order is deterministic...
        for (let i = 0; i < left.length; i++) {
          if (left[i] !== right[i]) return false
        }

        return true
      },
    })

d(dir),
      compare: (left, right) => {
        if


r } from './batched-file-reader'
import type { FileReader } from './file-reader'

describe('CachedFileReader', () => {
  it('will only scan the filesystem a minimal amount of times', async () => {
    const pages = ['1', '2', '3']
    const app = ['4', '5', '6']

    const reader: FileReader = {
      read: jest.fn(async (directory: string) => {
        switch (directory) {
          case '<root>/pages':
            return pages
          case '<root>/app':
            return app
          default:

hed.read('<root>/app'),
      cached.read('<root>/app'),
    ])

    expect(reader.read).toHaveBeenCalledTimes(2)
    expect(results).toHaveLength(4)
    expect(results[0]).toBe(pages)
    expect(results[1]).toBe(pages)
    expect(results[2]).toBe(app)

    throw new Error('unexpected')
        }
      }),
    }
    const cached = new BatchedFileReader(reader)

    const results = await Promise.all([
      cached.read('<root>/pages'),
      cached.read('<root>/pages'),
      cac


../shared/lib/invariant-error'
import { isThenable } from '../../shared/lib/is-thenable'
import { workAsyncStorage } from '../app-render/work-async-storage.external'
import { withExecuteRevalidates } from '../revalidation-utils'
import { bindSnapshot } from '../app-render/async-local-storage'
import {
  workUnitAsyncStorage,
  type WorkUnitStore,
} from '../app-render/work-unit-async-storage.external'
import { afterTaskAsyncStorage } from '../app-render/after-task-async-storage.external'

export type AfterC

tUntil: RequestLifecycleOpts['waitUntil'] | undefined
  private onClose: RequestLifecycleOpts['onClose']
  private onTaskError: RequestLifecycleOpts['onAfterTaskError'] | undefined

  private runCallbacksOnClosePromise: Promise<void> | undefined
  private

ontextOpts = {
  waitUntil: RequestLifecycleOpts['waitUntil'] | undefined
  onClose: RequestLifecycleOpts['onClose']
  onTaskError: RequestLifecycleOpts['onAfterTaskError'] | undefined
}

export class AfterContext {
  private wai


t { isThenable } from '../../../shared/lib/is-thenable'

/**
 * Tracks all in-flight async imports and chunk loads.
 * Initialized lazily, because we don't want this to error in case it gets pulled into an edge runtime module.
 */
let _moduleLoadingSignal: CacheSignal | null
function getModuleLoadingSignal() {
  if (!_moduleLoadingSignal) {
    _moduleLoadingSignal = new CacheSignal()
  }
  return _moduleLoadingSignal
}

export function trackPendingChunkLoad(promise: Promise<unknown>) {
  const moduleLoadin

 returns a promise.
  // if it's sync, there's nothing to track.
  if (isThenable(exportsOrPromise)) {
    // A client reference proxy might look like a promise, but we can only call `.then()` on it, not e.g. `.finally()`.
    // Turn it into a real promis

gSignal = getModuleLoadingSignal()
  moduleLoadingSignal.trackRead(promise)
}

export function trackPendingImport(exportsOrPromise: unknown) {
  const moduleLoadingSignal = getModuleLoadingSignal()

  // requiring an async module


*

Files in the rsc directory are meant to be packaged as part of the RSC graph using next-app-loader.

*/

import * as React from 'react'

type Reference = object
type TaintableUniqueValue = string | bigint | ArrayBufferView

function notImplemented() {
  throw new Error('Taint can only be used with the taint flag.')
}

export const taintObjectReference: (
  message: string | undefined,
  object: Reference
) => void = process.env.__NEXT_EXPERIMENTAL_REACT
  ? // @ts-ignore
    React.experimental_taintObjec

 notImplemented
export const taintUniqueValue: (
  message: string | undefined,
  lifetime: Reference,
  value: TaintableUniqueValue
) => void = process.env.__NEXT_EXPERIMENTAL_REACT
  ? // @ts-ignore
    React.experimental_taintUniqueValue
  : notImplemen


tream'

import { SYMBOL_CLEARED_COOKIES } from '../api-utils'
import type { NextApiRequestCookies } from '../api-utils'

import { NEXT_REQUEST_META } from '../request-meta'
import type { RequestMeta } from '../request-meta'

import { BaseNextRequest, BaseNextResponse, type FetchMetric } from './index'
import type { OutgoingHttpHeaders } from 'node:http'

type Req = IncomingMessage & {
  [NEXT_REQUEST_META]?: RequestMeta
  cookies?: NextApiRequestCookies
  fetchMetrics?: FetchMetric[]
}

export class NodeNex

}

  constructor(private _req: Req) {
    super(_req.method!.toUpperCase(), _req.url!, _req)
  }

  get originalRequest() {
    // Need to mimic these changes to the original req object for places where we use it:
    // render.tsx, api/ssg requests
    th

tRequest extends BaseNextRequest<Readable> {
  public headers = this._req.headers
  public fetchMetrics: FetchMetric[] | undefined = this._req?.fetchMetrics;

  [NEXT_REQUEST_META]: RequestMeta = this._req[NEXT_REQUEST_META] || {


NextResponse } from './web'

describe('WebNextResponse onClose', () => {
  it('stream body', async () => {
    const cb = jest.fn()
    const ts = new TransformStream({
      transform(chunk, controller) {
        controller.enqueue(chunk)
      },
    })

    const webNextResponse = new WebNextResponse(ts)
    webNextResponse.onClose(cb)
    webNextResponse.send()
    expect(cb).toHaveBeenCalledTimes(0)
    const response = await webNextResponse.toResponse()
    expect(cb).toHaveBeenCalledTimes(0)
    cons

st text = await t
    expect(cb).toHaveBeenCalledTimes(1)
    expect(text).toBe('abcdef')
  })

  it('string body', async () => {
    const cb = jest.fn()
    const webNextResponse = new WebNextResponse(undefined).body('abcdef')
    webNextResponse.onClose

t t = response.text()

    const encoder = new TextEncoder()
    const writer = ts.writable.getWriter()
    await writer.write(encoder.encode('abc'))
    await writer.write(encoder.encode('def'))
    await writer.close()

    con


ge-route'

import { APP_PATHS_MANIFEST } from '../../shared/lib/constants'
import { AppNormalizers } from '../normalizers/built/app'
import { RouteKind } from '../route-kind'
import { AppPageRouteMatcher } from '../route-matchers/app-page-route-matcher'
import type {
  Manifest,
  ManifestLoader,
} from './helpers/manifest-loaders/manifest-loader'
import { ManifestRouteMatcherProvider } from './manifest-route-matcher-provider'

export class AppPageRouteMatcherProvider extends ManifestRouteMatcherProvider<Ap

r)
  }

  protected async transform(
    manifest: Manifest
  ): Promise<ReadonlyArray<AppPageRouteMatcher>> {
    // This matcher only matches app pages.
    const pages = Object.keys(manifest).filter((page) => isAppPageRoute(page))

    // Collect all th

pPageRouteMatcher> {
  private readonly normalizers: AppNormalizers

  constructor(distDir: string, manifestLoader: ManifestLoader) {
    super(APP_PATHS_MANIFEST, manifestLoader)

    this.normalizers = new AppNormalizers(distDi


} from '../../lib/is-app-route-route'
import { APP_PATHS_MANIFEST } from '../../shared/lib/constants'
import { RouteKind } from '../route-kind'
import { AppRouteRouteMatcher } from '../route-matchers/app-route-route-matcher'
import type {
  Manifest,
  ManifestLoader,
} from './helpers/manifest-loaders/manifest-loader'
import { ManifestRouteMatcherProvider } from './manifest-route-matcher-provider'
import { AppNormalizers } from '../normalizers/built/app'

export class AppRouteRouteMatcherProvider extends M

ers = new AppNormalizers(distDir)
  }

  protected async transform(
    manifest: Manifest
  ): Promise<ReadonlyArray<AppRouteRouteMatcher>> {
    // This matcher only matches app routes.
    const pages = Object.keys(manifest).filter((page) => isAppRouteR

anifestRouteMatcherProvider<AppRouteRouteMatcher> {
  private readonly normalizers: AppNormalizers

  constructor(distDir: string, manifestLoader: ManifestLoader) {
    super(APP_PATHS_MANIFEST, manifestLoader)

    this.normaliz


./../shared/lib/constants'
import type { PagesAPIRouteDefinition } from '../route-definitions/pages-api-route-definition'
import { RouteKind } from '../route-kind'
import type { ManifestLoader } from './helpers/manifest-loaders/manifest-loader'
import { PagesAPIRouteMatcherProvider } from './pages-api-route-matcher-provider'

describe('PagesAPIRouteMatcherProvider', () => {
  it('returns no routes with an empty manifest', async () => {
    const loader: ManifestLoader = { load: jest.fn(() => ({})) }
    con

each<{
      manifest: Record<string, string>
      route: PagesAPIRouteDefinition
    }>([
      {
        manifest: { '/api/users/[id]': 'pages/api/users/[id].js' },
        route: {
          kind: RouteKind.PAGES_API,
          pathname: '/api/users/[i

st provider = new PagesAPIRouteMatcherProvider('<root>', loader)
    expect(await provider.matchers()).toEqual([])
    expect(loader.load).toHaveBeenCalledWith(PAGES_MANIFEST)
  })

  describe('manifest matching', () => {
    it.


e-definition'
import { RouteKind } from '../route-kind'
import type { ManifestLoader } from './helpers/manifest-loaders/manifest-loader'
import { PagesRouteMatcherProvider } from './pages-route-matcher-provider'

describe('PagesRouteMatcherProvider', () => {
  it('returns no routes with an empty manifest', async () => {
    const loader: ManifestLoader = { load: jest.fn(() => ({})) }
    const provider = new PagesRouteMatcherProvider('<root>', loader)
    expect(await provider.matchers()).toEqual([])
    ex

: Array<string>; defaultLocale: string }
    }>([
      {
        manifest: {
          '/_app': 'pages/_app.js',
          '/_error': 'pages/_error.js',
          '/_document': 'pages/_document.js',
          '/blog/[slug]': 'pages/blog/[slug].js',

pect(loader.load).toHaveBeenCalledWith(PAGES_MANIFEST)
  })

  describe('locale matching', () => {
    describe.each<{
      manifest: Record<string, string>
      routes: ReadonlyArray<PagesRouteDefinition>
      i18n: { locales


m '../../route-matchers/app-page-route-matcher'
import { RouteKind } from '../../route-kind'
import { FileCacheRouteMatcherProvider } from './file-cache-route-matcher-provider'

import { DevAppNormalizers } from '../../normalizers/built/app'
import { normalizeCatchAllRoutes } from '../../../build/normalize-catchall-routes'
import { compareAppPaths } from '../../../shared/lib/router/utils/app-paths'

export class DevAppPageRouteMatcherProvider extends FileCacheRouteMatcherProvider<AppPageRouteMatcher> {
  pr

Turbopack: boolean
  ) {
    super(appDir, reader)

    this.normalizers = new DevAppNormalizers(appDir, extensions, isTurbopack)

    // Match any page file that ends with `/page.${extension}` or `/default.${extension}` under the app
    // directory.

ivate readonly expression: RegExp
  private readonly normalizers: DevAppNormalizers
  private readonly isTurbopack: boolean

  constructor(
    appDir: string,
    extensions: ReadonlyArray<string>,
    reader: FileReader,
    is


der/file-reader'
import {
  PagesAPILocaleRouteMatcher,
  PagesAPIRouteMatcher,
} from '../../route-matchers/pages-api-route-matcher'
import { RouteKind } from '../../route-kind'
import path from 'path'
import type { LocaleRouteNormalizer } from '../../normalizers/locale-route-normalizer'
import { FileCacheRouteMatcherProvider } from './file-cache-route-matcher-provider'
import { DevPagesNormalizers } from '../../normalizers/built/pages'

export class DevPagesAPIRouteMatcherProvider extends FileCacheRouteMa

<string>,
    reader: FileReader,
    private readonly localeNormalizer?: LocaleRouteNormalizer
  ) {
    super(pagesDir, reader)

    // Match any route file that ends with `/${filename}.${extension}` under the
    // pages directory.
    this.expression

tcherProvider<PagesAPIRouteMatcher> {
  private readonly expression: RegExp
  private readonly normalizers: DevPagesNormalizers

  constructor(
    private readonly pagesDir: string,
    private readonly extensions: ReadonlyArray


der/file-reader'
import {
  PagesRouteMatcher,
  PagesLocaleRouteMatcher,
} from '../../route-matchers/pages-route-matcher'
import { RouteKind } from '../../route-kind'
import path from 'path'
import type { LocaleRouteNormalizer } from '../../normalizers/locale-route-normalizer'
import { FileCacheRouteMatcherProvider } from './file-cache-route-matcher-provider'
import { DevPagesNormalizers } from '../../normalizers/built/pages'

export class DevPagesRouteMatcherProvider extends FileCacheRouteMatcherProvider

ader: FileReader,
    private readonly localeNormalizer?: LocaleRouteNormalizer
  ) {
    super(pagesDir, reader)

    // Match any route file that ends with `/${filename}.${extension}` under the
    // pages directory.
    this.expression = new RegExp(`\\

<PagesRouteMatcher> {
  private readonly expression: RegExp
  private readonly normalizers: DevPagesNormalizers

  constructor(
    private readonly pagesDir: string,
    private readonly extensions: ReadonlyArray<string>,
    re


` on `globalThis` at import time,
  // so we have to do some contortions here to set it up before running anything else
  type WASMod = typeof import('../app-render/work-async-storage.external')
  type WSMod = typeof import('../app-render/work-unit-async-storage.external')
  type AfterMod = typeof import('./after')
  type AfterContextMod = typeof import('./after-context')

  let workAsyncStorage: WASMod['workAsyncStorage']
  let workUnitAsyncStorage: WSMod['workUnitAsyncStorage']
  let AfterContext: AfterCo

ternal')
    workAsyncStorage = WASMod.workAsyncStorage

    const WSMod = await import('../app-render/work-unit-async-storage.external')
    workUnitAsyncStorage = WSMod.workUnitAsyncStorage

    const AfterContextMod = await import('./after-context')

ntextMod['AfterContext']
  let after: AfterMod['after']

  beforeAll(async () => {
    // @ts-expect-error
    globalThis.AsyncLocalStorage = AsyncLocalStorage

    const WASMod = await import('../app-render/work-async-storage.ex


rom './'
import type { NodeNextRequest, NodeNextResponse } from './node'
import type { WebNextRequest, WebNextResponse } from './web'

/**
 * This file provides some helpers that should be used in conjunction with
 * explicit environment checks. When combined with the environment checks, it
 * will ensure that the correct typings are used as well as enable code
 * elimination.
 */

/**
 * Type guard to determine if a request is a WebNextRequest. This does not
 * actually check the type of the request, but r

t =>
  process.env.NEXT_RUNTIME === 'edge'

/**
 * Type guard to determine if a response is a WebNextResponse. This does not
 * actually check the type of the response, but rather the runtime environment.
 * It's expected that when the runtime environment

ather the runtime environment.
 * It's expected that when the runtime environment is the edge runtime, that any
 * base request is a WebNextRequest.
 */
export const isWebNextRequest = (req: BaseNextRequest): req is WebNextReques


 './index'

import { toNodeOutgoingHttpHeaders } from '../web/utils'
import { BaseNextRequest, BaseNextResponse } from './index'
import { DetachedPromise } from '../../lib/detached-promise'
import type { NextRequestHint } from '../web/adapter'
import { CloseController, trackBodyConsumed } from '../web/web-on-close'
import { InvariantError } from '../../shared/lib/invariant-error'

export class WebNextRequest extends BaseNextRequest<ReadableStream | null> {
  public request: Request
  public headers: Incomin

.clone().body
    )
    this.request = request
    this.fetchMetrics = request.fetchMetrics

    this.headers = {}
    for (const [name, value] of request.headers.entries()) {
      this.headers[name] = value
    }
  }

  async parseBody(_limit: string | n

gHttpHeaders
  public fetchMetrics: FetchMetrics | undefined

  constructor(request: NextRequestHint) {
    const url = new URL(request.url)

    super(
      request.method,
      url.href.slice(url.origin.length),
      request


constants'
import type { AppRouteRouteDefinition } from '../route-definitions/app-route-route-definition'
import { RouteKind } from '../route-kind'
import { AppRouteRouteMatcherProvider } from './app-route-route-matcher-provider'
import type { ManifestLoader } from './helpers/manifest-loaders/manifest-loader'

describe('AppRouteRouteMatcherProvider', () => {
  it('returns no routes with an empty manifest', async () => {
    const loader: ManifestLoader = { load: jest.fn(() => ({})) }
    const provider = ne

ition
    }>([
      {
        manifest: {
          '/route': 'app/route.js',
        },
        route: {
          kind: RouteKind.APP_ROUTE,
          pathname: '/',
          filename: `<root>/${SERVER_DIRECTORY}/app/route.js`,
          page: '/route'

w AppRouteRouteMatcherProvider('<root>', loader)
    expect(await provider.matchers()).toEqual([])
  })

  describe('manifest matching', () => {
    it.each<{
      manifest: Record<string, string>
      route: AppRouteRouteDefin


import { PAGES_MANIFEST } from '../../shared/lib/constants'
import { RouteKind } from '../route-kind'
import {
  PagesAPILocaleRouteMatcher,
  PagesAPIRouteMatcher,
} from '../route-matchers/pages-api-route-matcher'
import type {
  Manifest,
  ManifestLoader,
} from './helpers/manifest-loaders/manifest-loader'
import { ManifestRouteMatcherProvider } from './manifest-route-matcher-provider'
import type { I18NProvider } from '../lib/i18n-provider'
import { PagesNormalizers } from '../normalizers/built/pages'

  private readonly i18nProvider?: I18NProvider
  ) {
    super(PAGES_MANIFEST, manifestLoader)

    this.normalizers = new PagesNormalizers(distDir)
  }

  protected async transform(
    manifest: Manifest
  ): Promise<ReadonlyArray<PagesAPIRouteMatcher>>

export class PagesAPIRouteMatcherProvider extends ManifestRouteMatcherProvider<PagesAPIRouteMatcher> {
  private readonly normalizers: PagesNormalizers

  constructor(
    distDir: string,
    manifestLoader: ManifestLoader,


./../normalizers/normalizer'
import { AppRouteRouteMatcher } from '../../route-matchers/app-route-route-matcher'
import { RouteKind } from '../../route-kind'
import { FileCacheRouteMatcherProvider } from './file-cache-route-matcher-provider'
import { isAppRouteRoute } from '../../../lib/is-app-route-route'
import { DevAppNormalizers } from '../../normalizers/built/app'
import {
  isMetadataRouteFile,
  isStaticMetadataRoute,
  isStaticMetadataFile,
} from '../../../lib/metadata/is-metadata-route'
import { n

eMatcher> {
  private readonly normalizers: {
    page: Normalizer
    pathname: Normalizer
    bundlePath: Normalizer
  }
  private readonly appDir: string
  private readonly isTurbopack: boolean

  constructor(
    appDir: string,
    extensions: Readonl

ormalizeMetadataPageToRoute } from '../../../lib/metadata/get-metadata-route'
import path from '../../../shared/lib/isomorphic/path'

export class DevAppRouteRouteMatcherProvider extends FileCacheRouteMatcherProvider<AppRouteRout


} from './file-reader'
import type { RecursiveReadDirOptions } from '../../../../../lib/recursive-readdir'
import { recursiveReadDir } from '../../../../../lib/recursive-readdir'

export type DefaultFileReaderOptions = Pick<
  RecursiveReadDirOptions,
  'pathnameFilter' | 'ignorePartFilter'
>

/**
 * Reads all the files in the directory and its subdirectories following any
 * symbolic links.
 */
export class DefaultFileReader implements FileReader {
  /**
   * Filter to ignore files with absolute pathnames.

 false to ignore
   * @param ignoreFilter filter to ignore files and directories with absolute pathnames, false to ignore
   * @param ignorePartFilter filter to ignore files and directories with the pathname part, false to ignore
   */
  constructor(option

 If undefined, no files are
   * ignored.
   */
  private readonly options: Readonly<DefaultFileReaderOptions>

  /**
   * Creates a new file reader.
   *
   * @param pathnameFilter filter to ignore files with absolute pathnames,


ers } from 'http'
import type { I18NConfig } from '../config-shared'

import { RedirectStatusCode } from '../../client/components/redirect-status-code'
import type { NextApiRequestCookies } from '../api-utils'
import { getCookieParser } from '../api-utils/get-cookie-parser'

export interface BaseNextRequestConfig {
  basePath: string | undefined
  i18n?: I18NConfig
  trailingSlash?: boolean | undefined
}

export type FetchMetric = {
  url: string
  idx: number
  end: number
  start: number
  method: string

ies: NextApiRequestCookies | undefined
  public abstract headers: IncomingHttpHeaders
  public abstract fetchMetrics: FetchMetric[] | undefined

  constructor(
    public method: string,
    public url: string,
    public body: Body
  ) {}

  // Utils impl

  status: number
  cacheReason: string
  cacheStatus: 'hit' | 'miss' | 'skip' | 'hmr'
  cacheWarning?: string
}

export type FetchMetrics = Array<FetchMetric>

export abstract class BaseNextRequest<Body = any> {
  protected _cook


import { BLOCKED_PAGES, PAGES_MANIFEST } from '../../shared/lib/constants'
import { RouteKind } from '../route-kind'
import {
  PagesLocaleRouteMatcher,
  PagesRouteMatcher,
} from '../route-matchers/pages-route-matcher'
import type {
  Manifest,
  ManifestLoader,
} from './helpers/manifest-loaders/manifest-loader'
import { ManifestRouteMatcherProvider } from './manifest-route-matcher-provider'
import type { I18NProvider } from '../lib/i18n-provider'
import { PagesNormalizers } from '../normalizers/built/p

 private readonly i18nProvider?: I18NProvider
  ) {
    super(PAGES_MANIFEST, manifestLoader)

    this.normalizers = new PagesNormalizers(distDir)
  }

  protected async transform(
    manifest: Manifest
  ): Promise<ReadonlyArray<PagesRouteMatcher>> {

ages'

export class PagesRouteMatcherProvider extends ManifestRouteMatcherProvider<PagesRouteMatcher> {
  private readonly normalizers: PagesNormalizers

  constructor(
    distDir: string,
    manifestLoader: ManifestLoader,


rectories: Array<string>
  callbacks: Array<{
    resolve: (value: ReadonlyArray<string>) => void
    reject: (err: any) => void
  }>
}

/**
 * CachedFileReader will deduplicate requests made to the same folder structure
 * to scan for files.
 */
export class BatchedFileReader implements FileReader {
  private batch?: FileReaderBatch

  constructor(private readonly reader: FileReader) {}

  // This allows us to schedule the batches after all the promises associated
  // with loading files.
  private schedul

  }

  private getOrCreateBatch(): FileReaderBatch {
    // If there is an existing batch and it's not completed, then reuse it.
    if (this.batch && !this.batch.completed) {
      return this.batch
    }

    const batch: FileReaderBatch = {
      compl

ePromise?: Promise<void>
  private schedule(callback: Function) {
    if (!this.schedulePromise) {
      this.schedulePromise = Promise.resolve()
    }
    this.schedulePromise.then(() => {
      process.nextTick(callback)
    })


rom '../route-definitions/app-page-route-definition'
import { RouteKind } from '../route-kind'
import { AppPageRouteMatcherProvider } from './app-page-route-matcher-provider'
import type { ManifestLoader } from './helpers/manifest-loaders/manifest-loader'

describe('AppPageRouteMatcherProvider', () => {
  it('returns no routes with an empty manifest', async () => {
    const loader: ManifestLoader = { load: jest.fn(() => ({})) }
    const matcher = new AppPageRouteMatcherProvider('<root>', loader)
    await

  '/page': 'app/page.js',
        },
        route: {
          kind: RouteKind.APP_PAGE,
          pathname: '/',
          filename: `<root>/${SERVER_DIRECTORY}/app/page.js`,
          page: '/page',
          bundlePath: 'app/page',
          appPaths:

 expect(matcher.matchers()).resolves.toEqual([])
  })

  describe('manifest matching', () => {
    it.each<{
      manifest: Record<string, string>
      route: AppPageRouteDefinition
    }>([
      {
        manifest: {


les in the rsc directory are meant to be packaged as part of the RSC graph using next-app-loader.

*/

import ReactDOM from 'react-dom'

export function preloadStyle(
  href: string,
  crossOrigin: string | undefined,
  nonce: string | undefined
) {
  const opts: any = { as: 'style' }
  if (typeof crossOrigin === 'string') {
    opts.crossOrigin = crossOrigin
  }
  if (typeof nonce === 'string') {
    opts.nonce = nonce
  }
  ReactDOM.preload(href, opts)
}

export function preloadFont(
  href: string,
  typ

') {
    opts.nonce = nonce
  }
  ReactDOM.preload(href, opts)
}

export function preconnect(
  href: string,
  crossOrigin: string | undefined,
  nonce: string | undefined
) {
  const opts: any = {}
  if (typeof crossOrigin === 'string') {
    opts.crossO

e: string,
  crossOrigin: string | undefined,
  nonce: string | undefined
) {
  const opts: any = { as: 'font', type }
  if (typeof crossOrigin === 'string') {
    opts.crossOrigin = crossOrigin
  }
  if (typeof nonce === 'string


import { spawn } from 'child_process'
import { getProjectDir } from '../lib/get-project-dir'
import { getNpxCommand } from '../lib/helpers/get-npx-command'

interface NextUpgradeOptions {
  revision: string
  verbose: boolean
}

export function spawnNextUpgrade(
  directory: string | undefined,
  options: NextUpgradeOptions
) {
  const baseDir = getProjectDir(directory)
  const [upgradeProcessCommand, ...upgradeProcessDefaultArgs] =
    getNpxCommand(baseDir).split(' ')

  const upgradeProcessCommandArgs =

.push('--verbose')
  }

  const upgradeProcess = spawn(
    upgradeProcessCommand,
    upgradeProcessCommandArgs,
    {
      stdio: 'inherit',
      cwd: baseDir,
    }
  )

  upgradeProcess.on('close', (code) => {
    process.exitCode = code ?? 0
  })
}

[
    ...upgradeProcessDefaultArgs,
    // Needs to be bleeding edge (canary) to pick up latest codemods.
    '@next/codemod@canary',
    'upgrade',
    options.revision,
  ]
  if (options.verbose) {
    upgradeProcessCommandArgs


ib/head-manager-context.shared-runtime'
import { onRecoverableError } from './react-client-callbacks/on-recoverable-error'
import {
  onCaughtError,
  onUncaughtError,
} from './react-client-callbacks/error-boundary-callbacks'
import { callServer } from './app-call-server'
import { findSourceMapURL } from './app-find-source-map-url'
import {
  type AppRouterActionQueue,
  createMutableActionQueue,
} from './components/app-router-instance'
import AppRouter from './components/app-router'
import type { Initial

time'
import type { StaticIndicatorState } from './dev/hot-reloader/app/hot-reloader-app'
import { createInitialRSCPayloadFromFallbackPrerender } from './flight-data-helpers'
import { getDeploymentId } from '../shared/lib/deployment-id'
import { setNavigat

RSCPayload } from '../shared/lib/app-router-types'
import { createInitialRouterState } from './components/router-reducer/create-initial-router-state'
import { MissingSlotContext } from '../shared/lib/app-router-context.shared-run


  if (process.env.NODE_ENV !== 'production') {
    const callback = (mutationList: MutationRecord[]) => {
      for (const mutation of mutationList) {
        if (mutation.type === 'childList') {
          for (const node of mutation.addedNodes) {
            if (
              'tagName' in node &&
              (node as HTMLLinkElement).tagName === 'LINK'
            ) {
              const link = node as HTMLLinkElement
              if (link.dataset.precedence?.startsWith('next')) {
                cons

                   const allLinks = [
                      ...document.querySelectorAll(
                        'link[href^="' + resource + '"]'
                      ),
                      // It's possible that the resource is a full URL or only pathn

t href = link.getAttribute('href')
                if (href) {
                  const [resource, version] = href.split('?v=', 2)
                  if (version) {
                    const currentOrigin = window.location.origin


P: hydration warning

import './app-webpack'

import { renderAppDevOverlay } from 'next/dist/compiled/next-devtools'
import { appBootstrap } from './app-bootstrap'
import { getOwnerStack } from '../next-devtools/userspace/app/errors/stitched-error'
import { isRecoverableError } from './react-client-callbacks/on-recoverable-error'

// eslint-disable-next-line @next/internal/typechecked-require
const instrumentationHooks = require('../lib/require-instrumentation-client')

appBootstrap((assetPrefix) => {
  con

Indicator = process.env.__NEXT_CACHE_COMPONENTS

  const { hydrate } = require('./app-index') as typeof import('./app-index')
  try {
    hydrate(instrumentationHooks, assetPrefix)
  } finally {
    renderAppDevOverlay(getOwnerStack, isRecoverableError, en


ort './register-deployment-id-global'
import { appBootstrap } from './app-bootstrap'
import { isRecoverableError } from './react-client-callbacks/on-recoverable-error'

window.next.turbopack = true
;(self as any).__webpack_hash__ = ''

// eslint-disable-next-line @next/internal/typechecked-require
const instrumentationHooks = require('../lib/require-instrumentation-client')

appBootstrap((assetPrefix) => {
  const { hydrate } = require('./app-index') as typeof import('./app-index')
  try {
    hydrate(instr

ce/app/errors/stitched-error') as typeof import('../next-devtools/userspace/app/errors/stitched-error')
      const { renderAppDevOverlay } =
        require('next/dist/compiled/next-devtools') as typeof import('next/dist/compiled/next-devtools')
      ren

umentationHooks, assetPrefix)
  } finally {
    if (process.env.__NEXT_DEV_SERVER) {
      const enableCacheIndicator = process.env.__NEXT_CACHE_COMPONENTS
      const { getOwnerStack } =
        require('../next-devtools/userspa


st go first because it needs to patch webpack chunk loading
// before React patches chunk loading.
import './app-webpack'
import { appBootstrap } from './app-bootstrap'

const instrumentationHooks =
  // eslint-disable-next-line @next/internal/typechecked-require -- not a module
  require('../lib/require-instrumentation-client')

appBootstrap((assetPrefix) => {
  const { hydrate } = require('./app-index') as typeof import('./app-index')
  // Include app-router and layout-router in the main chunk
  // eslint

e -- Why not relative imports?
  require('next/dist/client/components/app-router')
  // eslint-disable-next-line @next/internal/typechecked-require -- Why not relative imports?
  require('next/dist/client/components/layout-router')
  hydrate(instrumentatio


ping in the webpack runtime
// https://github.com/webpack/webpack/blob/2738eebc7880835d88c727d364ad37f3ec557593/lib/RuntimeGlobals.js#L204

import './register-deployment-id-global'
import { getAssetToken, getAssetTokenQuery } from '../shared/lib/deployment-id'
import { encodeURIPath } from '../shared/lib/encode-uri-path'

declare const __webpack_require__: any

// If we have a deployment ID, we need to append it to the webpack chunk names
// I am keeping the process check explicit so this can be statically

rver matches against and encoded
    // filename path.
    encodeURIPath(getChunkScriptFilename(...args)) + suffix

  const getChunkCssFilename = __webpack_require__.k
  __webpack_require__.k = (...args: any[]) =>
    getChunkCssFilename(...args) + suffix

optimized
if (getAssetToken()) {
  const suffix = getAssetTokenQuery()
  const getChunkScriptFilename = __webpack_require__.u
  __webpack_require__.u = (...args: any[]) =>
    // We encode the chunk filename because our static se


ectly assign location to URL
 *
 * The method will add basePath, and will also correctly add location (including if it is a relative path)
 * @param location Location that should be added to the url
 * @param url Base URL to which the location should be assigned
 */
export function assignLocation(location: string, url: URL): URL {
  if (location.startsWith('.')) {
    const urlBase = url.origin + url.pathname
    return new URL(
      // In order for a relative path to be added to the current url correctly,

URL('./relative', 'https://example.com/subdir').href -> 'https://example.com/relative'
      // new URL('./relative', 'https://example.com/subdir/').href -> 'https://example.com/subdir/relative'
      (urlBase.endsWith('/') ? urlBase : urlBase + '/') + loc

 the current url must end with a slash
      // new


?{"sensitive":"data"}',
        {},
        ['/some/url', ''],
        'refetch',
        PrefetchHint.IsRootLayout | 1,
      ]

      const result = prepareFlightRouterStateForRequest(flightRouterState, true)
      const decoded = JSON.parse(decodeURIComponent(result))

      expect(decoded).toEqual(flightRouterState)
    })
  })

  describe('__PAGE__ segment handling', () => {
    it('should strip search params from __PAGE__ segments', () => {
      const flightRouterState: FlightRouterState = [

('__PAGE__')
    })

    it('should preserve non-page segments', () => {
      const flightRouterState: FlightRouterState = ['regular-segment', {}]

      const result = prepareFlightRouterStateForRequest(flightRouterState)
      const decoded = JSON.parse

'__PAGE__?{"param":"value","foo":"bar"}',
        {},
      ]

      const result = prepareFlightRouterStateForRequest(flightRouterState)
      const decoded = JSON.parse(decodeURIComponent(result))

      expect(decoded[0]).toBe


cSegmentAppearInURL,
  getRenderedPathname,
  getRenderedSearch,
} from './route-params'
import { createHrefFromUrl } from './components/router-reducer/create-href-from-url'

export type NormalizedFlightData = {
  /**
   * The full `FlightSegmentPath` inclusive of the final `Segment`
   */
  segmentPath: FlightSegmentPath
  /**
   * The `FlightSegmentPath` exclusive of the final `Segment`
   */
  pathToSegment: FlightSegmentPath
  segment: Segment
  tree: FlightRouterState
  seedData: CacheNodeSeedData | nu

't conform to the `FlightDataPath` type (it's missing the root segment)
// we're currently exporting it so we can use it directly. This should be fixed as part of the unification of
// the different ways we express `FlightSegmentPath`.
export function getF

ll
  head: HeadData
  isHeadPartial: boolean
  isRootRender: boolean
}

// TODO: We should only have to export `normalizeFlightData`, however because the initial flight data
// that gets passed to `createInitialRouterState` doesn


SALLOWED_FORM_PROPS)[number]

type InternalFormProps = {
  /**
   * `action` can be either a `string` or a function.
   * - If `action` is a string, it will be interpreted as a path or URL to navigate to when the form is submitted.
   *   The path will be prefetched when the form becomes visible.
   * - If `action` is a function, it will be called when the form is submitted. See the [React docs](https://react.dev/reference/react-dom/components/form#props) for more.
   */
  action: NonNullable<HTMLFormProps[

alse}`. Prefetching is only enabled in production.
   *
   * Options:
   * - "auto", null, undefined (default): For statically generated pages, this will prefetch the full React Server Component data. For dynamic pages, this will prefetch up to the nearest

'action']>
  /**
   * Controls how the route specified by `action` is prefetched.
   * Any `<Form />` that is in the viewport (initially or through scroll) will be prefetched.
   * Prefetch can be disabled by passing `prefetch={f


ort type { NextRouter } from './router'
import {
  checkFormActionUrl,
  createFormSubmitDestinationUrl,
  DISALLOWED_FORM_PROPS,
  hasReactClientActionAttributes,
  hasUnsupportedSubmitterAttributes,
  type FormProps,
} from './form-shared'

export type { FormProps }

const Form = forwardRef<HTMLFormElement, FormProps>(function FormComponent(
  { replace, scroll, prefetch: prefetchProp, ...props },
  ref
) {
  const router = useContext(RouterContext)

  const actionProp = props.action
  const isNavigatingF

cess.env.NODE_ENV === 'development') {
    if (prefetchProp !== undefined) {
      console.error(
        'Passing `prefetch` to a <Form> has no effect in the pages directory.'
      )
    }
  }

  // Validate `scroll` and `replace`
  if (process.env.NODE_

orm = typeof actionProp === 'string'

  // Validate `action`
  if (process.env.NODE_ENV === 'development') {
    if (isNavigatingForm) {
      checkFormActionUrl(actionProp, 'action')
    }
  }

  // Validate `prefetch`
  if (pro


{ DomainLocale } from '../server/config'
import type { normalizeLocalePath as NormalizeFn } from './normalize-locale-path'
import type { detectDomainLocale as DetectFn } from './detect-domain-locale'
import { normalizePathTrailingSlash } from './normalize-trailing-slash'

const basePath = (process.env.__NEXT_ROUTER_BASEPATH as string) || ''

export function getDomainLocale(
  path: string,
  locale?: string | false,
  locales?: readonly string[],
  domainLocales?: readonly DomainLocale[]
) {
  if (process.e

etectFn = (
      require('./detect-domain-locale') as typeof import('./detect-domain-locale')
    ).detectDomainLocale

    const target = locale || normalizeLocalePath(path, locales).detectedLocale
    const domain = detectDomainLocale(domainLocales, und

nv.__NEXT_I18N_SUPPORT) {
    const normalizeLocalePath: typeof NormalizeFn = (
      require('./normalize-locale-path') as typeof import('./normalize-locale-path')
    ).normalizeLocalePath
    const detectDomainLocale: typeof D


function reactElementToDOM({ type, props }: JSX.Element): HTMLElement {
  const el: HTMLElement = document.createElement(type)
  setAttributesFromProps(el, props)

  const { children, dangerouslySetInnerHTML } = props
  if (dangerouslySetInnerHTML) {
    el.innerHTML = dangerouslySetInnerHTML.__html || ''
  } else if (children) {
    el.textContent =
      typeof children === 'string'
        ? children
        : Array.isArray(children)
          ? children.join('')
          : ''
  }
  return el
}

/**

 that have nonces, `Element,isEqualNode()` will return false if one
 * of those elements gets added to the document. Although the `element.nonce` property will be the
 * same for both elements, the one that was added to the document will return an empty st

* When a `nonce` is present on an element, browsers such as Chrome and Firefox strip it out of the
 * actual HTML attributes for security reasons *when the element is added to the document*. Thus,
 * given two equivalent elements


type {
  ImageConfigComplete,
  ImageLoaderProps,
} from '../shared/lib/image-config'
import { imageConfigDefault } from '../shared/lib/image-config'
import { ImageConfigContext } from '../shared/lib/image-config-context.shared-runtime'
import { warnOnce } from '../shared/lib/utils/warn-once'
import { RouterContext } from '../shared/lib/router-context.shared-runtime'

// This is replaced by webpack alias
import defaultLoader from 'next/dist/shared/lib/image-loader'
import { useMergedRef } from './use-merged

 type { ImageLoaderProps }
export type ImageLoader = (p: ImageLoaderProps) => string

type ImgElementWithDataProp = HTMLImageElement & {
  'data-loaded-src'?: string | undefined
}

type ImageElementProps = ImgProps & {
  unoptimized: boolean
  placeholder:

-ref'

// This is replaced by webpack define plugin
const configEnv = process.env.__NEXT_IMAGE_OPTS as any as ImageConfigComplete

if (typeof window === 'undefined') {
  ;(globalThis as any).__NEXT_IMAGE_IMPORTED = true
}

export


archParams,
  assign,
} from '../shared/lib/router/utils/querystring'
import { getURL, loadGetInitialProps, ST } from '../shared/lib/utils'
import type { NextWebVitalsMetric, NEXT_DATA } from '../shared/lib/utils'
import { Portal } from './portal'
import initHeadManager from './head-manager'
import PageLoader from './page-loader'
import type { StyleSheetTuple } from './page-loader'
import { RouteAnnouncer } from './route-announcer'
import { createRouter, makePublicRouterInstance } from './router'
import { g

/remove-base-path'
import { hasBasePath } from './has-base-path'
import { AppRouterContext } from '../shared/lib/app-router-context.shared-runtime'
import {
  adaptForAppRouterInstance,
  adaptForPathParams,
  adaptForSearchParams,
  PathnameContextProvide

etProperError } from '../lib/is-error'
import { ImageConfigContext } from '../shared/lib/image-config-context.shared-runtime'
import type { ImageConfigComplete } from '../shared/lib/image-config'
import { removeBasePath } from '.


seMergedRef } from './use-merged-ref'
import { errorOnce } from '../shared/lib/utils/error-once'

type Url = string | UrlObject
type RequiredKeys<T> = {
  [K in keyof T]-?: {} extends Pick<T, K> ? never : K
}[keyof T]
type OptionalKeys<T> = {
  [K in keyof T]-?: {} extends Pick<T, K> ? K : never
}[keyof T]

type OnNavigateEventHandler = (event: { preventDefault: () => void }) => void

type InternalLinkProps = {
  /**
   * The path or URL to navigate to. It can also be an object.
   *
   * @example https://n

ious docs](https://github.com/vercel/next.js/blob/v9.5.2/docs/api-reference/next/link.md#dynamic-routes) to see how it worked. Note: when this path differs from the one provided in `href` the previous `href`/`as` behavior is used as shown in the [previous

extjs.org/docs/api-reference/next/link#with-url-object
   */
  href: Url
  /**
   * Optional decorator for the path that will be shown in the browser URL bar. Before Next.js 9.5.3 this was used for dynamic routes, check our [prev


s gets assigned as a side-effect during app initialization. Because it
// represents the build used to create the JS bundle, it should never change
// after being set, so we store it in a global variable.
//
// When performing RSC requests, if the incoming data has a different build ID,
// we perform an MPA navigation/refresh to load the updated build and ensure
// that the client and server in sync.
//
// Starts as an empty string. In practice, because setNavigationBuildId is called during initialization
/

uld fail and trigger an MPA navigation.
//
// Note that this can also be initialized with the deployment id instead (if available). So it's not
// the same as "the build id", but we are running out of alternative names for "build id or
// deployment id".
l

/ before hydration starts, this will always get reassigned to the actual ID before it's ever needed
// by a navigation. If for some reasons it didn't, due to a bug or race condition, then on
// navigation the build comparision wo


 polyfill from `@next/polyfill-module` after build.
import '../build/polyfills/polyfill-module'

// Only set up devtools for the dev server.
if (process.env.__NEXT_DEV_SERVER) {
  require('../next-devtools/userspace/app/app-dev-overlay-setup') as typeof import('../next-devtools/userspace/app/app-dev-overlay-setup')
}

// Start listening for the instant navigation test cookie. The test framework
// (e.g. Playwright) sets/clears this cookie to control the navigation lock.
// Browser-only.
if (process.env.__NE

ING_API && typeof window !== 'undefined') {
  const { startListeningForInstantNavigationCookie } =
    require('./components/segment-cache/navigation-testing-lock') as typeof import('./components/segment-cache/navigation-testing-lock')
  startListeningForI


out time-based windows
 *
 * This ensures we suppress noisy prerender-related rejections while preserving
 * normal error logging for genuine unhandled rejections.
 */

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

const MODE:
  | 'enabled'
  | 'debug'
  | 'silent'
  | 'true'
  | 'false'
  | '1'
  | '0'
  | ''
  | string
  | undefined = process.env.NEXT_UNHANDLED_REJECTION_FILTER

let ENABLE_UHR_FILTER = true
let UHR_FILTER_LOG_LEVEL: 'debug' | 'warn' | 'silent' = 'w

eak
  case '':
  case undefined:
  case 'enabled':
  case 'true':
  case '1':
    break
  default:
    if (typeof MODE === 'string') {
      console.error(
        `NEXT_UNHANDLED_REJECTION_FILTER has an unrecognized value: ${JSON.stringify(MODE)}. Use "en

arn'

switch (MODE) {
  case 'silent':
    UHR_FILTER_LOG_LEVEL = 'silent'
    break
  case 'debug':
    UHR_FILTER_LOG_LEVEL = 'debug'
    break
  case 'false':
  case 'disabled':
  case '0':
    ENABLE_UHR_FILTER = false
    br


to APIs during builds and revalidates to ensure that prerenders don't observe random bytes
 * When cacheComponents is enabled. Random bytes are a form of IO even if they resolve synchronously. When cacheComponents is
 * enabled we need to ensure that random bytes are excluded from prerenders unless they are cached.
 *
 *
 * The extensions here never error nor alter the underlying return values and thus should be transparent to callers.
 */

import { io } from './io-utils'

let webCrypto: typeof crypto
if (p

pto'))
      .webcrypto
  } else {
    webCrypto = crypto
  }
}

const getRandomValuesExpression = '`crypto.getRandomValues()`'
try {
  const _getRandomValues = webCrypto.getRandomValues
  webCrypto.getRandomValues = function getRandomValues() {
    io(get

rocess.env.NEXT_RUNTIME === 'edge') {
  webCrypto = crypto
} else {
  if (typeof crypto === 'undefined') {
    // @ts-expect-error -- TODO: Is this actually safe?
    webCrypto = (require('node:crypto') as typeof import('node:cry


teSelfSignedCertificate } from '../lib/mkcert'
import type { SelfSignedCertificate } from '../lib/mkcert'
import uploadTrace from '../trace/upload-trace'
import { initialEnv } from '@next/env'
import { fork } from 'child_process'
import type { ChildProcess } from 'child_process'
import {
  getReservedPortExplanation,
  isPortIsReserved,
} from '../lib/helpers/get-reserved-port'
import { getCacheDirectory } from '../lib/helpers/get-cache-directory'
import { getGitBranch } from '../lib/helpers/git'
import os

 { Bundler, parseBundlerArgs } from '../lib/bundler'

export type NextDevOptions = {
  disableSourceMaps: boolean
  // Commander is not putting `--inspect` through the arg parser
  inspect?: DebugAddress | true
  turbo?: boolean
  turbopack?: boolean
  web

from 'os'
import fs from 'node:fs'
import { once } from 'node:events'
import { clearTimeout } from 'timers'
import { trace, initializeTraceState, exportTraceState } from '../trace'
import { traceId } from '../trace/shared'
import


nv node

import { existsSync } from 'fs'
import path from 'path'
import loadConfig from '../server/config'
import { PHASE_PRODUCTION_BUILD } from '../shared/lib/constants'
import { getProjectDir } from '../lib/get-project-dir'
import { printAndExit } from '../server/lib/utils'
import { loadBindings } from '../build/swc'

export type NextPostBuildOptions = {}

const nextPostBuild = async (
  _options: NextPostBuildOptions,
  directory?: string
) => {
  const dir = getProjectDir(directory)

  if (!existsSync(

orBuild || false

  if (!persistentCaching) {
    console.log('Persistent caching for build is not enabled. Nothing to do.')
    return
  }

  const distDir = path.join(dir, config.distDir)
  const cachePath = path.join(distDir, 'cache', 'turbopack')

  if

dir)) {
    printAndExit(`> No such directory exists as the project root: ${dir}`)
  }

  const config = await loadConfig(PHASE_PRODUCTION_BUILD, dir)
  const persistentCaching =
    config.experimental?.turbopackFileSystemCacheF


nv node

import { bold, cyan, green, red, yellow } from '../lib/picocolors'
import { Telemetry } from '../telemetry/storage'

export type NextTelemetryOptions = {
  enable?: boolean
  disable?: boolean
}

const telemetry = new Telemetry({ distDir: process.cwd() })
let isEnabled = telemetry.isEnabled

const nextTelemetry = (options: NextTelemetryOptions, arg: string) => {
  if (options.enable || arg === 'enable') {
    telemetry.setEnabled(true)
    isEnabled = true

    console.log(cyan('Success!'))
  } els

      console.log(yellow(`Next.js' telemetry collection is already disabled.`))
    }

    isEnabled = false
  } else {
    console.log(bold('Next.js Telemetry'))
  }

  console.log(
    `\nStatus: ${isEnabled ? bold(green('Enabled')) : bold(red('Disabled'

e if (options.disable || arg === 'disable') {
    const path = telemetry.setEnabled(false)

    if (isEnabled) {
      console.log(
        cyan(`Your preference has been saved${path ? ` to ${path}` : ''}.`)
      )
    } else {


} from 'fs/promises'

import loadConfig from '../server/config'
import { printAndExit } from '../server/lib/utils'
import { PHASE_PRODUCTION_BUILD } from '../shared/lib/constants'
import { getProjectDir } from '../lib/get-project-dir'
import { findPagesDir } from '../lib/find-pages-dir'
import { verifyAndRunTypeScript } from '../lib/verify-typescript-setup'
import { discoverRoutes } from '../build/route-discovery'

import {
  createRouteTypesManifest,
  writeRouteTypesManifest,
  writeValidatorFile,
} from

 { installBindings } from '../build/swc/install-bindings'

export type NextTypegenOptions = {
  dir?: string
}

const nextTypegen = async (
  _options: NextTypegenOptions,
  directory?: string
) => {
  const baseDir = getProjectDir(directory)

  // Check i

'../server/lib/router-utils/route-types-utils'
import { writeCacheLifeTypes } from '../server/lib/router-utils/cache-life-type-utils'
import { writeRootParamsTypes } from '../server/lib/router-utils/root-params-type-utils'
import


ort { encodeURIPath } from '../shared/lib/encode-uri-path'
import type { DeepReadonly } from '../shared/lib/deep-readonly'
import { getTracer } from '../server/lib/trace/tracer'
import { getTracedMetadata } from '../server/lib/trace/utils'

export type { DocumentContext, DocumentInitialProps, DocumentProps }

export type OriginProps = {
  nonce?: string
  crossOrigin?: 'anonymous' | 'use-credentials' | '' | undefined
  children?: React.ReactNode
}

type DocumentFiles = {
  sharedFiles: readonly string[]
  p

es that have triggered a large data warning on production mode. */
const largePageDataWarnings = new Set<string>()

function getDocumentFiles(
  buildManifest: BuildManifest,
  pathname: string
): DocumentFiles {
  const sharedFiles: readonly string[] = ge

ageFiles: readonly string[]
  allFiles: readonly string[]
}

type HeadHTMLProps = React.DetailedHTMLProps<
  React.HTMLAttributes<HTMLHeadElement>,
  HTMLHeadElement
>

type HeadProps = OriginProps & HeadHTMLProps

/** Set of pag


../shared/lib/utils'

const statusCodes: { [code: number]: string } = {
  400: 'Bad Request',
  404: 'This page could not be found',
  405: 'Method Not Allowed',
  500: 'Internal Server Error',
}

export type ErrorProps = {
  statusCode: number
  hostname?: string
  title?: string
  withDarkMode?: boolean
}

function _getInitialProps({
  req,
  res,
  err,
}: NextPageContext): Promise<ErrorProps> | ErrorProps {
  const statusCode =
    res && res.statusCode ? res.statusCode : err ? err.statusCode! : 404

   const initUrl = getRequestMeta(req, 'initURL')
    if (initUrl) {
      const url = new URL(initUrl)
      hostname = url.hostname
    }
  }

  return { statusCode, hostname }
}

const styles: Record<string, React.CSSProperties> = {
  error: {
    // ht

let hostname

  if (typeof window !== 'undefined') {
    hostname = window.location.hostname
  } else if (req) {
    const { getRequestMeta } =
      require('../server/request-meta') as typeof import('../server/request-meta')


er-headers'
import type {
  NormalizedPathname,
  NormalizedSearch,
} from './components/segment-cache/cache-key'
import type { RSCResponse } from './components/router-reducer/fetch-server-response'
import type { ParsedUrlQuery } from 'querystring'

export type RouteParamValue = string | Array<string> | null

export function getRenderedSearch(
  response: RSCResponse<unknown> | Response
): NormalizedSearch {
  // If the server performed a rewrite, the search params used to render the
  // page will be diffe

 !== null) {
    return (
      rewrittenQuery === '' ? '' : '?' + rewrittenQuery
    ) as NormalizedSearch
  }
  // If the header is not present, there was no rewrite, so we use the search
  // query of the response URL.
  return urlToUrlWithoutFlightMark

rent from the params in the request URL. In this case,
  // the response will include a header that gives the rewritten search query.
  const rewrittenQuery = response.headers.get(NEXT_REWRITTEN_QUERY_HEADER)
  if (rewrittenQuery


uter-context.shared-runtime'
import isError from '../lib/is-error'

type SingletonRouterBase = {
  router: Router | null
  readyCallbacks: Array<() => any>
  ready(cb: () => any): void
}

export { Router }

export type { NextRouter }

export type SingletonRouter = SingletonRouterBase & NextRouter

const singletonRouter: SingletonRouterBase = {
  router: null, // holds the actual router instance
  readyCallbacks: [],
  ready(callback: () => void) {
    if (this.router) return callback()
    if (typeof window

 'components',
  'isFallback',
  'basePath',
  'locale',
  'locales',
  'defaultLocale',
  'isReady',
  'isPreview',
  'isLocaleDomain',
  'domainLocales',
] as const
const routerEvents = [
  'routeChangeStart',
  'beforeHistoryChange',
  'routeChangeCompl

 !== 'undefined') {
      this.readyCallbacks.push(callback)
    }
  },
}

// Create public properties and methods of the router in the singletonRouter
const urlPropertyFields = [
  'pathname',
  'route',
  'query',
  'asPath',


String } from '../shared/lib/htmlescape'

const ScriptCache = new Map()
const LoadCache = new Set()

export interface ScriptProps extends ScriptHTMLAttributes<HTMLScriptElement> {
  strategy?: 'afterInteractive' | 'lazyOnload' | 'beforeInteractive' | 'worker'
  id?: string
  onLoad?: (e: any) => void
  onReady?: () => void | null
  onError?: (e: any) => void
  children?: React.ReactNode
  stylesheets?: string[]
}

/**
 * @deprecated Use `ScriptProps` instead.
 */
export type Props = ScriptProps

const inser

esheets might have already been loaded if initialized with Script component
  // Re-inject styles here to handle scripts loaded via handleClientScriptLoad
  // ReactDOM.preinit handles dedup and ensures the styles are loaded only once
  if (ReactDOM.preini

tStylesheets = (stylesheets: string[]) => {
  // Case 1: Styles for afterInteractive/lazyOnload with appDir injected via handleClientScriptLoad
  //
  // Using ReactDOM.preinit to feature detect appDir and inject styles
  // Styl


Record<string, string> = {
  acceptCharset: 'accept-charset',
  className: 'class',
  htmlFor: 'for',
  httpEquiv: 'http-equiv',
  noModule: 'noModule',
}

const ignoreProps = [
  'onLoad',
  'onReady',
  'dangerouslySetInnerHTML',
  'children',
  'onError',
  'strategy',
  'stylesheets',
]

function isBooleanScriptAttribute(
  attr: string
): attr is 'async' | 'defer' | 'noModule' {
  return ['async', 'defer', 'noModule'].includes(attr)
}

export function setAttributesFromProps(el: HTMLElement, props: obje

  continue
    }

    const attr = DOMAttributeNames[p] || p.toLowerCase()

    if (el.tagName === 'SCRIPT' && isBooleanScriptAttribute(attr)) {
      // Correctly assign boolean script attributes
      // https://github.com/vercel/next.js/pull/20748

ct) {
  for (const [p, value] of Object.entries(props)) {
    if (!props.hasOwnProperty(p)) continue
    if (ignoreProps.includes(p)) continue

    // we don't render undefined props to the DOM
    if (value === undefined) {


s the Trusted Types Policy. Starts as undefined and can be set to null
 * if Trusted Types is not supported in the browser.
 */
let policy: TrustedTypePolicy | null | undefined

/**
 * Getter for the Trusted Types Policy. If it is undefined, it is instantiated
 * here or set to null if Trusted Types is not supported in the browser.
 */
function getPolicy() {
  if (typeof policy === 'undefined' && typeof window !== 'undefined') {
    policy =
      window.trustedTypes?.createPolicy('nextjs', {
        create

* when Trusted Types are not available.
 * This is a security-sensitive function; any use of this function
 * must go through security review. In particular, it must be assured that the
 * provided string will never cause an XSS vulnerability if used in a

HTML: (input) => input,
        createScript: (input) => input,
        createScriptURL: (input) => input,
      }) || null
  }

  return policy
}

/**
 * Unsafely promote a string to a TrustedScriptURL, falling back to strings


celIdleCallback,
} from './request-idle-callback'

type UseIntersectionObserverInit = Pick<
  IntersectionObserverInit,
  'rootMargin' | 'root'
>

type UseIntersection = { disabled?: boolean } & UseIntersectionObserverInit & {
    rootRef?: React.RefObject<HTMLElement | null> | null
  }
type ObserveCallback = (isVisible: boolean) => void
type Identifier = {
  root: Element | Document | null
  margin: string
}
type Observer = {
  id: Identifier
  observer: IntersectionObserver
  elements: Map<Element, Observ

Init): Observer {
  const id = {
    root: options.root || null,
    margin: options.rootMargin || '',
  }
  const existing = idList.find(
    (obj) => obj.root === id.root && obj.margin === id.margin
  )
  let instance: Observer | undefined

  if (existin

eCallback>
}

const hasIntersectionObserver = typeof IntersectionObserver === 'function'

const observers = new Map<Identifier, Observer>()
const idList: Identifier[] = []

function createObserver(options: UseIntersectionObserver


t'

// This is a compatibility hook to support React 18 and 19 refs.
// In 19, a cleanup function from refs may be returned.
// In 18, returning a cleanup function creates a warning.
// Since we take userspace refs, we don't know ahead of time if a cleanup function will be returned.
// This implements cleanup functions with the old behavior in 18.
// We know refs are always called alternating with `null` and then `T`.
// So a call with `null` means we need to call the previous cleanup functions.
export func

d skip the wrapping if only one of the refs is non-null.
  // (this happens often if the user doesn't pass a ref to Link/Form/Image)
  // But this can cause us to leak a cleanup-ref into user code (previously via `<Link legacyBehavior>`),
  // and the user

tion useMergedRef<TElement>(
  refA: Ref<TElement>,
  refB: Ref<TElement>
): Ref<TElement> {
  const cleanupA = useRef<(() => void) | null>(null)
  const cleanupB = useRef<(() => void) | null>(null)

  // NOTE: In theory, we coul


 PHASE_DEVELOPMENT_SERVER } from '../../shared/lib/constants'
import type { TraceEvent } from '../types'
import type { Reporter } from './types'

// Batch events as zipkin allows for multiple events to be sent in one go
export function batcher(reportEvents: (evts: TraceEvent[]) => Promise<void>) {
  const events: TraceEvent[] = []
  // Promise queue to ensure events are always sent on flushAll
  const queue = new Set()
  return {
    flushAll: async () => {
      await Promise.all(queue)
      if (events.le

vents.length = 0
        const report = reportEvents(evts)
        queue.add(report)
        report.then(() => queue.delete(report))
      }
    },
  }
}

const writeStreamOptions = {
  flags: 'a',
  encoding: 'utf8' as const,
}
class RotatingWriteStream {

ngth > 0) {
        await reportEvents(events)
        events.length = 0
      }
    },
    report: (event: TraceEvent) => {
      events.push(event)

      if (events.length > 100) {
        const evts = events.slice()
        e


t
  | OutputReport
  | ErrorLogReport
  | SerializableDataReport
type ErrorReport = { type: 'error'; message: string }
type OutputReport = { type: 'output'; message: string }
type CountReport = {
  type: 'count'
  count: number
}
type UHRReport = {
  type: 'uhr'
  reason: string
}
type ErrorLogReport = {
  type: 'error-log'
  message: string
}
type SerializableDataReport = {
  type: 'serialized'
  key: string
  data: string
}

declare global {
  function reportResult(result: ReportableResult): void
}

impor

eport>
  errorLog: Array<string>
  data: Record<string, unknown>
  messages: Array<ReportableResult>
}

export function runWorkerCode(fn: Function): Promise<WorkerResult> {
  return new Promise((resolve, reject) => {
    const script = `
      const { pare

t type { WorkUnitStore } from '../app-render/work-unit-async-storage.external'

import { Worker } from 'node:worker_threads'

type WorkerResult = {
  exitCode: number
  stderr: string
  uhr: Array<UHRReport>
  count: Array<CountR


nv node

import '../server/lib/cpu-profile'
import { saveCpuProfile } from '../server/lib/cpu-profile'
import { existsSync } from 'fs'
import { italic } from '../lib/picocolors'
import analyze from '../build/analyze'
import { warn } from '../build/output/log'
import { printAndExit } from '../server/lib/utils'
import { getProjectDir } from '../lib/get-project-dir'

export type NextAnalyzeOptions = {
  experimentalAnalyze?: boolean
  profile?: boolean
  mangling: boolean
  port: number
  output: boolean
  exp

eCpuProfile()
    process.exit(130)
  })

  const { profile, mangling, experimentalAppOnly, output, port } = options

  if (!mangling) {
    warn(
      `Mangling is disabled. ${italic('Note: This may affect performance and should only be used for debuggin

erimentalAppOnly?: boolean
}

const nextAnalyze = async (options: NextAnalyzeOptions, directory?: string) => {
  process.on('SIGTERM', () => {
    saveCpuProfile()
    process.exit(143)
  })
  process.on('SIGINT', () => {
    sav


IME is set for accurate "Ready in" timing.
// This should already be set by bin/next.ts, but we set it here as a fallback
// in case the module is loaded through a different code path.
if (!process.env.NEXT_PRIVATE_START_TIME) {
  process.env.NEXT_PRIVATE_START_TIME = Date.now().toString()
}

import '../server/lib/cpu-profile'
import { saveCpuProfile } from '../server/lib/cpu-profile'
import { startServer } from '../server/lib/start-server'
import {
  getParsedDebugAddress,
  formatDebugAddress,
  printAndE

om '../build/output/log'

export type NextStartOptions = {
  port: number
  hostname?: string
  // Commander is not putting `--inspect` through the arg parser
  inspect?: DebugAddress | true
  keepAliveTimeout?: number
  experimentalNextConfigStripTypes?:

xit,
  type DebugAddress,
} from '../server/lib/utils'
import { getProjectDir } from '../lib/get-project-dir'
import {
  getReservedPortExplanation,
  isPortIsReserved,
} from '../lib/helpers/get-reserved-port'
import * as Log fr


RPC `tools/call` request and prints the response to stdout.
 * Use --json for machine-readable JSON output (default: markdown).
 *
 * Usage: next internal query-trace [options]
 */

const DEFAULT_MCP_PORT = 5748 // Keep in sync with turbo-trace-server.ts

interface QueryTraceOptions {
  port: number | undefined
  parent: string | undefined
  aggregated: boolean | undefined
  sort: string | undefined
  search: string | undefined
  page: number | undefined
  json: boolean | undefined
}

export async function

ptions.parent !== undefined) args.parent = options.parent
  if (options.aggregated !== undefined) args.aggregated = options.aggregated
  if (options.sort !== undefined) args.sort = options.sort
  if (options.search !== undefined) args.search = options.sear

queryTraceCli(options: QueryTraceOptions): Promise<void> {
  const port = options.port ?? DEFAULT_MCP_PORT

  // Build arguments — only include values explicitly set by the user.
  const args: Record<string, unknown> = {}
  if (o


t/dist/compiled/@modelcontextprotocol/sdk/server/streamableHttp') as typeof import('next/dist/compiled/@modelcontextprotocol/sdk/server/streamableHttp')

const DEFAULT_WS_PORT = 5747

/** 100 internal ticks = 1 µs */
const TICKS_PER_US = 100
const TICKS_PER_MS = TICKS_PER_US * 1000
const TICKS_PER_S = TICKS_PER_MS * 1000

function formatDuration(ticks: number): string {
  if (ticks < TICKS_PER_MS) {
    const us = ticks / TICKS_PER_US
    return `${us.toFixed(0)}µs`
  }
  if (ticks < TICKS_PER_S) {
    cons

 the parent reference point
  const prefix = ticks < 0 ? '-' : ''
  return prefix + formatDuration(Math.abs(ticks))
}

function formatBytes(bytes: number): string {
  const KB = 1024
  const MB = KB * 1024
  const GB = MB * 1024
  if (bytes >= GB) return `

t ms = ticks / TICKS_PER_MS
    return `${ms.toFixed(2)}ms`
  }
  const s = ticks / TICKS_PER_S
  return `${s.toFixed(3)}s`
}

function formatRelative(ticks: number): string {
  // ticks may be negative if the child starts before


 React from 'react'

import type {
  AppContextType,
  AppInitialProps,
  AppPropsType,
  NextWebVitalsMetric,
  AppType,
} from '../shared/lib/utils'
import type { Router } from '../client/router'

import { loadGetInitialProps } from '../shared/lib/utils'

export type { AppInitialProps, AppType }

export type { NextWebVitalsMetric }

export type AppContext = AppContextType<Router>

export type AppProps<P = any> = AppPropsType<Router, P>

/**
 * `App` component is used for initialize of pages. It allows for

Context): Promise<AppInitialProps> {
  const pageProps = await loadGetInitialProps(Component, ctx)
  return { pageProps }
}

export default class App<P = any, CP = {}, S = {}> extends React.Component<
  P & AppProps<CP>,
  S
> {
  static origGetInitialProp

 overwriting and full control of the `page` initialization.
 * This allows for keeping state between navigation, custom error handling, injecting additional data.
 */
async function appGetInitialProps({
  Component,
  ctx,
}: App


lient-side entry point for Turbopack builds. Includes logic to load chunks,
// but does not include development-time features like hot module reloading.

import './register-deployment-id-global'
import '../lib/require-instrumentation-client'

// TODO: Remove use of `any` type.
import { initialize, version, router, emitter, hydrate } from './'

window.next = {
  version,
  turbopack: true,
  // router is initialized later so it has to be live-binded
  get router() {
    return router
  },
  emitter,
}
;(self

ck_load_page_chunks__ = (
      page: string,
      chunksData: any
    ) => {
      const chunkPromises = chunksData.map((c: unknown) =>
        __turbopack_load__(c)
      )

      Promise.all(chunkPromises).catch((err) =>
        console.error('failed t

 as any).__next_set_public_path__ = () => {}
;(self as any).__webpack_hash__ = ''

// for the page loader
declare let __turbopack_load__: any

initialize({})
  .then(() => {
    // for the page loader
    ;(self as any).__turbopa


connectHMR,
  addMessageListener,
} from './dev/hot-reloader/pages/websocket'
import {
  assign,
  urlQueryToSearchParams,
} from '../shared/lib/router/utils/querystring'
import { HMR_MESSAGE_SENT_TO_BROWSER } from '../server/dev/hot-reloader-types'
import { RuntimeErrorHandler } from './dev/runtime-error-handler'
import { REACT_REFRESH_FULL_RELOAD_FROM_ERROR } from './dev/hot-reloader/shared'
import { performFullReload } from './dev/hot-reloader/pages/hot-reloader-pages'
import { dispatcher } from 'next/di

t reloading = false

    addMessageListener((message) => {
      if (reloading) return

      switch (message.type) {
        case HMR_MESSAGE_SENT_TO_BROWSER.SERVER_ERROR: {
          const errorObject = JSON.parse(message.errorJSON)
          const error

st/compiled/next-devtools'

export function pageBootstrap(assetPrefix: string) {
  connectHMR({ assetPrefix, path: '/_next/hmr' })

  return hydrate({ beforeRender: displayContent }).then(() => {
    initOnDemandEntries()

    le


ase-path'
import { interpolateAs } from '../shared/lib/router/utils/interpolate-as'
import getAssetPathFromRoute from '../shared/lib/router/utils/get-asset-path-from-route'
import { addLocale } from './add-locale'
import { isDynamicRoute } from '../shared/lib/router/utils/is-dynamic'
import { parseRelativeUrl } from '../shared/lib/router/utils/parse-relative-url'
import { removeTrailingSlash } from '../shared/lib/router/utils/remove-trailing-slash'
import {
  createRouteLoader,
  getClientBuildManifest,
  m

ce Window {
    __DEV_MIDDLEWARE_MATCHERS?: ProxyMatcher[]
    __DEV_PAGES_MANIFEST?: { pages: string[] }
    __SSG_MANIFEST_CB?: () => void
    __SSG_MANIFEST?: Set<string>
  }
}

export type StyleSheetTuple = { href: string; text: string }
export type Go

arkAssetError,
} from './route-loader'
import {
  DEV_CLIENT_PAGES_MANIFEST,
  DEV_CLIENT_MIDDLEWARE_MANIFEST,
} from '../shared/lib/constants'
import { resolvePromiseWithTimeout } from './lib/promise'

declare global {
  interfa


etTokenQuery } from '../shared/lib/deployment-id'
import { encodeURIPath } from '../shared/lib/encode-uri-path'
import { resolvePromiseWithTimeout } from './lib/promise'

declare global {
  interface Window {
    __BUILD_MANIFEST?: Record<string, string[]>
    __BUILD_MANIFEST_CB?: Function
    __SERVER_FILES_MANIFEST?: RequiredServerFilesManifest
    __MIDDLEWARE_MATCHERS?: ProxyMatcher[]
    __MIDDLEWARE_MATCHERS_CB?: Function
    __REACT_LOADABLE_MANIFEST?: any
    __DYNAMIC_CSS_MANIFEST?: any
    __RSC_

: ComponentType
  exports: any
}
interface LoadedEntrypointFailure {
  error: unknown
}
type RouteEntrypoint = LoadedEntrypointSuccess | LoadedEntrypointFailure

interface RouteStyleSheet {
  href: string
  content: string
}

interface LoadedRouteSuccess e

MANIFEST?: any
    __RSC_SERVER_MANIFEST?: any
    __NEXT_FONT_MANIFEST?: any
    __SUBRESOURCE_INTEGRITY_MANIFEST?: string
    __INTERCEPTION_ROUTE_REWRITE_MANIFEST?: string
  }
}

interface LoadedEntrypointSuccess {
  component


ort { tmpdir } from 'os'
import { join } from 'path'
import { setGlobal } from '../trace/shared'
import {
  recordFrameworkVersion,
  updateBuildDiagnostics,
} from './build-diagnostics'

async function readBuildDiagnostics(dir: string) {
  return JSON.parse(
    await readFile(join(dir, 'diagnostics', 'build-diagnostics.json'), 'utf8')
  )
}

describe('build-diagnostics', () => {
  it('records framework version to framework.json correctly', async () => {
    const tmpDir = await mkdtemp(join(tmpdir(), 'bui

'diagnostics', 'framework.json'), 'utf8')
    )
    expect(diagnostics.version).toEqual('14.2.3')
  })

  it('records build diagnostics to a file correctly', async () => {
    const tmpDir = await mkdtemp(join(tmpdir(), 'build-diagnostics'))
    setGlobal(

ld-diagnostics'))
    setGlobal('distDir', tmpDir)

    // Record the initial diagnostics and make sure it's correct.
    await recordFrameworkVersion('14.2.3')
    let diagnostics = JSON.parse(
      await readFile(join(tmpDir,


rom 'fs'
import path from 'path'
import { getGitBranch, getGitCommit } from '../lib/helpers/git'

const COMMON_ALLOWED_EVENTS = ['memory-usage']

// Predefined set of the event names to be included in the trace.
// If the trace span's name matches to one of the event names in the set,
// it'll up uploaded to the trace server.
const DEV_ALLOWED_EVENTS = new Set([
  ...COMMON_ALLOWED_EVENTS,
  'client-hmr-latency',
  'render-path',
  'hot-reloader',
  'webpack-invalid-client',
  'webpack-invalidated-server',

rbopack',
  'webpack-compilation',
  'run-webpack-compiler',
  'create-entrypoints',
  'worker-main-edge-server',
  'worker-main-client',
  'worker-main-server',
  'server',
  'make',
  'seal',
  'chunk-graph',
  'optimize-modules',
  'optimize-chunks',

  'navigation-to-hydration',
  'start-dev-server',
  'compile-path',
  'memory-usage',
  'server-restart-close-to-memory-threshold',
])

const BUILD_ALLOWED_EVENTS = new Set([
  ...COMMON_ALLOWED_EVENTS,
  'next-build',
  'run-tu


et count = 0
const getId = () => {
  count++
  return count
}
let defaultParentSpanId: SpanId | undefined
let shouldSaveTraceEvents: boolean | undefined
let savedTraceEvents: TraceEvent[] = []

const RECORD_SPAN_THRESHOLD_MS = parseInt(
  process.env.NEXT_TRACE_SPAN_THRESHOLD_MS ?? '-1'
)

// eslint typescript has a bug with TS enums
export enum SpanStatus {
  Started = 'started',
  Stopped = 'stopped',
}

interface Attributes {
  [key: string]: unknown
}

export class Span {
  private name: string
  privat

    parentId,
    attrs,
    startTime,
  }: {
    name: string
    parentId?: SpanId
    startTime?: bigint
    attrs?: Attributes
  }) {
    this.name = name
    this.parentId = parentId ?? defaultParentSpanId
    this.attrs = attrs ? { ...attrs } : {}

e id: SpanId
  private parentId?: SpanId
  private attrs: { [key: string]: unknown }
  private status: SpanStatus
  private now: number

  // Number of nanoseconds since epoch.
  private _start: bigint

  constructor({
    name,


e } from 'fs/promises'
import { reporter } from '.'
import { setGlobal } from '../shared'
import { join } from 'path'
import { tmpdir } from 'os'

const TRACE_EVENT = {
  name: 'test-span',
  duration: 321,
  timestamp: Date.now(),
  id: 127,
  startTime: Date.now(),
}
const WEBPACK_INVALIDATED_EVENT = {
  name: 'webpack-invalidated',
  duration: 100,
  timestamp: Date.now(),
  id: 112,
  startTime: Date.now(),
}

describe('Trace Reporter', () => {
  describe('JSON reporter', () => {
    it('should write th

t reporter.flushAll()
      const traceFilename = join(tmpDir, 'trace')
      const traces = JSON.parse(await readFile(traceFilename, 'utf-8'))
      expect(traces.length).toEqual(1)
      expect(traces[0].name).toEqual('test-span')
      expect(traces[0].

e trace events to JSON file', async () => {
      const tmpDir = await mkdtemp(join(tmpdir(), 'json-reporter'))
      setGlobal('distDir', tmpDir)
      setGlobal('phase', 'anything')
      reporter.report(TRACE_EVENT)
      awai


iring any module, we need to make
 * sure the following scripts are executed in the correct order:
 * - Polyfills
 * - next/script with `beforeInteractive` strategy
 */

import { getAssetPrefix } from './asset-prefix'
import { setAttributesFromProps } from './set-attributes-from-props'

const version = process.env.__NEXT_VERSION

window.next = {
  version,
  appDir: true,
}

function loadScriptsInSequence(
  scripts: [src: string, props: { [prop: string]: any }][],
  hydrate: () => void
) {
  if (!scripts |

teElement('script')

          if (props) {
            setAttributesFromProps(el, props)
          }

          if (src) {
            el.src = src
            el.onload = () => resolve()
            el.onerror = reject
          } else if (props) {

| !scripts.length) {
    return hydrate()
  }

  return scripts
    .reduce((promise, [src, props]) => {
      return promise.then(() => {
        return new Promise<void>((resolve, reject) => {
          const el = document.crea


from 'fs'
import { italic } from '../lib/picocolors'
import build from '../build'
import { warn } from '../build/output/log'
import { printAndExit } from '../server/lib/utils'
import isError from '../lib/is-error'
import { getProjectDir } from '../lib/get-project-dir'
import { enableMemoryDebuggingMode } from '../lib/memory/startup'
import { disableMemoryDebuggingMode } from '../lib/memory/shutdown'
import { Bundler, parseBundlerArgs } from '../lib/bundler'
import {
  resolveBuildPaths,
  parseBuildPathsInp

n
  webpack?: boolean
  experimentalDebugMemoryUsage: boolean
  experimentalAppOnly?: boolean
  experimentalTurbo?: boolean
  experimentalBuildMode: 'default' | 'compile' | 'generate' | 'generate-env'
  experimentalUploadTrace?: string
  experimentalNextCo

ut,
} from '../lib/resolve-build-paths'

export type NextBuildOptions = {
  experimentalAnalyze?: boolean
  debug?: boolean
  debugPrerender?: boolean
  profile?: boolean
  mangling: boolean
  turbo?: boolean
  turbopack?: boolea


TION_BUILD } from '../shared/lib/constants'
import {
  hasNecessaryDependencies,
  type MissingDependency,
} from '../lib/has-necessary-dependencies'
import { installDependencies } from '../lib/install-dependencies'
import type { NextConfigComplete } from '../server/config-shared'
import findUp from 'next/dist/compiled/find-up'
import { findPagesDir } from '../lib/find-pages-dir'
import { verifyAndRunTypeScript } from '../lib/verify-typescript-setup'
import path from 'path'
import spawn from 'next/dist/comp

nst requiredPackagesByTestRunner: {
  [k in SupportedTestRunners]: MissingDependency[]
} = {
  playwright: [
    { file: 'playwright', pkg: '@playwright/test', exportsRestrict: false },
  ],
}

export async function nextTest(
  directory?: string,
  testRu

iled/cross-spawn'

export interface NextTestOptions {
  testRunner?: string
}

export const SUPPORTED_TEST_RUNNERS_LIST = ['playwright'] as const
export type SupportedTestRunners = (typeof SUPPORTED_TEST_RUNNERS_LIST)[number]

co