rt type getBaseWebpackConfig from '../../build/webpack-config'
import type { RouteDefinition } from '../route-definitions/route-definition'
import type { Project, Update as TurbopackUpdate } from '../../build/swc/types'
import type { VersionInfo } from './parse-version-info'
import type { DebugInfo } from '../../next-devtools/shared/types'
import type { DevIndicatorServerState } from './dev-indicator-server-state'
import type {
  CacheIndicatorState,
  ServerCacheStatus,
} from '../../next-devtools/dev-over

t const enum HMR_MESSAGE_SENT_TO_BROWSER {
  // JSON messages:
  ADDED_PAGE = 'addedPage',
  REMOVED_PAGE = 'removedPage',
  RELOAD_PAGE = 'reloadPage',
  SERVER_COMPONENT_CHANGES = 'serverComponentChanges',
  MIDDLEWARE_CHANGES = 'middlewareChanges',
  CL

lay/cache-indicator'
import type { DevToolsConfig } from '../../next-devtools/dev-overlay/shared'
import type { ReactDebugChannelForBrowser } from './debug-channel'
import type { AnyStream } from '../app-render/stream-ops'

expor


_REACT_REFRESH,
  COMPILER_NAMES,
  RSC_MODULE_TYPES,
} from '../../shared/lib/constants'
import type { __ApiPreviewProps } from '../api-utils'
import { findPageFile } from '../lib/find-page-file'
import {
  BUILDING,
  getEntries,
  EntryTypes,
  getInvalidator,
  onDemandEntryHandler,
} from './on-demand-entry-handler'
import { denormalizePagePath } from '../../shared/lib/page-path/denormalize-page-path'
import { normalizePathSep } from '../../shared/lib/page-path/normalize-path-sep'
import getRouteFromEn

 type Span, trace } from '../../trace'
import { getProperError } from '../../lib/is-error'
import ws from 'next/dist/compiled/ws'
import { existsSync, promises as fs } from 'fs'
import type { UnwrapPromise } from '../../lib/coalesced-function'
import type

trypoint from '../get-route-from-entrypoint'
import {
  difference,
  isInstrumentationHookFile,
  isMiddlewareFile,
  isMiddlewareFilename,
} from '../../build/utils'
import { DecodeError } from '../../shared/lib/utils'
import {


UnionQuery } from '../../lib/url'
import type { FetchMetric } from '../base-http'
import type { NodeNextRequest, NodeNextResponse } from '../base-http/node'
import type { LoggingConfig } from '../config-shared'
import { getRequestMeta, removeRequestMeta } from '../request-meta'
import { formatArgs } from './server-action-logger'

/**
 * Returns true if the incoming request should be ignored for logging.
 */
export function ignoreLoggingIncomingRequests(
  request: NodeNextRequest,
  loggingConfig: LoggingCo

ill not ignore the request.
  const ignore = loggingConfig?.incomingRequests?.ignore

  // If ignore is not set, don't ignore anything
  if (!ignore) {
    return false
  }

  // If array of RegExp, ignore if any pattern matches
  return ignore.some((patte

nfig | undefined
): boolean {
  // If it's boolean use the boolean value
  if (typeof loggingConfig?.incomingRequests === 'boolean') {
    return !loggingConfig.incomingRequests
  }

  // Any of the value on the chain is falsy, w


/next-devtools/server/middleware-response'
import path from 'path'
import { openFileInEditor } from '../../next-devtools/server/launch-editor'
import {
  SourceMapConsumer,
  type NullableMappedPosition,
} from 'next/dist/compiled/source-map08'
import type { Project, TurbopackStackFrame } from '../../build/swc/types'
import {
  type ModernSourceMapPayload,
  devirtualizeReactServerURL,
  findApplicableSourceMapPayload,
} from '../lib/source-maps'
import { findSourceMap, type SourceMap } from 'node:module'
i

hen Next.js is symlinked e.g. in the Next.js monorepo
    modulePath.includes('next/dist') ||
    modulePath.startsWith('node:')
  )
}

const currentSourcesByFile: Map<string, Promise<string | null>> = new Map()
/**
 * @returns 1-based lines and 1-based co

mport { fileURLToPath, pathToFileURL } from 'node:url'
import { inspect } from 'node:util'

function shouldIgnorePath(modulePath: string): boolean {
  return (
    modulePath.includes('node_modules') ||
    // Only relevant for w


-devtools/server/shared'
import { middlewareResponse } from '../../next-devtools/server/middleware-response'

import type { IncomingMessage, ServerResponse } from 'http'
import type webpack from 'webpack'
import type {
  NullableMappedPosition,
  RawSourceMap,
} from 'next/dist/compiled/source-map08'
import { formatStackFrameFile } from '../../next-devtools/shared/webpack-module-path'
import type { MappedPosition } from 'source-map'
import { inspect } from 'util'

function shouldIgnoreSource(sourceURL: stri

ype IgnoredSources = Array<{ url: string; ignored: boolean }>

type SourceAttributes = {
  sourcePosition: NullableMappedPosition
  sourceContent: string | null
}

type Source =
  | {
      type: 'file'
      sourceMap: BasicSourceMapPayload
      ignoredS

ng): boolean {
  return (
    sourceURL.includes('node_modules') ||
    // Only relevant for when Next.js is symlinked e.g. in the Next.js monorepo
    sourceURL.includes('next/dist') ||
    sourceURL.startsWith('node:')
  )
}

t


sage } from 'http'

import { parse } from 'next/dist/compiled/content-type'
import isError from '../../../lib/is-error'
import type { SizeLimit } from '../../../types'
import { ApiError } from '../index'

/**
 * Parse `JSON` and handles invalid `JSON` strings
 * @param str `JSON` string
 */
function parseJson(str: string): object {
  if (str.length === 0) {
    // special-case empty json body, as it's a common client-side mistake
    return {}
  }

  try {
    return JSON.parse(str)
  } catch (e) {
    thro

 let contentType
  try {
    contentType = parse(req.headers['content-type'] || 'text/plain')
  } catch {
    contentType = parse('text/plain')
  }
  const { type, parameters } = contentType
  const encoding = parameters.charset || 'utf-8'

  let buffer

w new ApiError(400, 'Invalid JSON')
  }
}

/**
 * Parse incoming message like `json` or `urlencoded`
 * @param req request object
 */
export async function parseBody(
  req: IncomingMessage,
  limit: SizeLimit
): Promise<any> {


./../shared/lib/utils'
import { checkIsOnDemandRevalidate } from '../.'
import type { __ApiPreviewProps } from '../.'
import type { BaseNextRequest, BaseNextResponse } from '../../base-http'
import type { PreviewData } from '../../../types'

import {
  clearPreviewData,
  COOKIE_NAME_PRERENDER_BYPASS,
  COOKIE_NAME_PRERENDER_DATA,
  SYMBOL_PREVIEW_DATA,
} from '../index'
import { RequestCookies } from '../../web/spec-extension/cookies'
import { HeadersAdapter } from '../../web/spec-extension/adapters/header

d revalidation is being done preview mode
  // is disabled
  if (
    options &&
    checkIsOnDemandRevalidate(req.headers, options).isOnDemandRevalidate
  ) {
    return false
  }

  // Read cached preview data if present
  // TODO: use request metadata i

s'

export function tryGetPreviewData(
  req: IncomingMessage | BaseNextRequest | Request,
  res: ServerResponse | BaseNextResponse,
  options: __ApiPreviewProps,
  multiZoneDraftMode: boolean
): PreviewData {
  // if an On-Deman


-async-storage.external'

export type CacheLife = {
  // How long the client can cache a value without checking with the server.
  stale?: number
  // How frequently you want the cache to refresh on the server.
  // Stale values may be served while revalidating.
  revalidate?: number
  // In the worst case scenario, where you haven't had traffic in a while,
  // how stale can a value be until you prefer deopting to dynamic.
  // Must be longer than revalidate.
  expire?: number
}
// The equivalent header is

hes - not private caches.

// The default revalidates relatively frequently but doesn't expire to ensure it's always
// able to serve fast results but by default doesn't hang.

// This gets overridden by the next-types-plugin
type CacheLifeProfiles =
  | '

 kind of like:
// Cache-Control: max-age=[stale],s-max-age=[revalidate],stale-while-revalidate=[expire-revalidate],stale-if-error=[expire-revalidate]
// Except that stale-while-revalidate/stale-if-error only applies to shared cac


 UseCacheTimeoutError extends Error {
  constructor() {
    super(
      'Filling a cache during prerender timed out, likely because request-specific arguments such as params, searchParams, cookies() or dynamic data were used inside "use cache".'
    )
  }
}

export class UseCacheDeadlockError extends Error {
  constructor() {
    super(
      'Filling a "use cache" entry appears to be stuck on shared state from the outer render scope. The same function completed when run in isolation, which usually means a

e server instance — so the surrounding dedupe layer is both unnecessary and the likely cause. Remove it and rely on "use cache" alone for deduping.'
    )
  }
}

/**
 * Used purely as `cause` for the nested-dynamic cache error: its captured stack
 * points

module-scoped value (for example a top-level Map used to dedupe fetches) is joining a promise created outside the cache. "use cache" already dedupes calls with the same arguments — within a request and across requests on the sam


 Cross-module handoff for the `'use cache'` hang-detection probe. A symbol on
// `globalThis` decouples the dev-server entry point (which installs the
// jest-worker pool) from the read site inside `use-cache-wrapper.ts` — avoiding
// a direct import of dev-only code from the use-cache module. In any process
// where the symbol is not set (prod, edge, unit tests, the probe worker itself)
// `getUseCacheProbe()` returns undefined, which doubles as the recursion guard
// against a probe spawning another probe

hat read `cookies()`, `headers()`, or `draftMode()` behave the
 * same as in a real fill — without it, those reads would diverge from
 * production behaviour and could mask the actual deadlock.
 */
export type UseCacheProbeRequestSnapshot = {
  headers: [s

.
const SYMBOL: unique symbol = Symbol.for('next.dev.useCacheProbe')

/**
 * Serializable view of the outer `RequestStore` forwarded to the probe
 * worker. The worker rebuilds a real `RequestStore` from this so cache
 * bodies t


r'
import type { MatchOptions, RouteMatcherManager } from './route-matcher-manager'
import { getSortedRoutes } from '../../shared/lib/router/utils'
import { LocaleRouteMatcher } from '../route-matchers/locale-route-matcher'
import { ensureLeadingSlash } from '../../shared/lib/page-path/ensure-leading-slash'
import { DetachedPromise } from '../../lib/detached-promise'

interface RouteMatchers {
  static: ReadonlyArray<RouteMatcher>
  dynamic: ReadonlyArray<RouteMatcher>
  duplicates: Record<string, ReadonlyA

ynamic: [],
    duplicates: {},
  }
  private lastCompilationID = this.compilationID

  /**
   * When this value changes, it indicates that a change has been introduced
   * that requires recompilation.
   */
  private get compilationID() {
    return this

rray<RouteMatcher>>
}

export class DefaultRouteMatcherManager implements RouteMatcherManager {
  private readonly providers: Array<RouteMatcherProvider> = []
  protected readonly matchers: RouteMatchers = {
    static: [],
    d


etag'
import { sendEtagResponse } from '../../send-payload'
import { Stream } from 'stream'
import isError from '../../../lib/is-error'
import { isResSent } from '../../../shared/lib/utils'
import { interopDefault } from '../../../lib/interop-default'
import {
  setLazyProp,
  sendStatusCode,
  redirect,
  clearPreviewData,
  sendError,
  ApiError,
  COOKIE_NAME_PRERENDER_BYPASS,
  COOKIE_NAME_PRERENDER_DATA,
  RESPONSE_LIMIT_DEFAULT,
} from './../index'
import { getCookieParser } from './../get-cookie-pars

 from './parse-body'
import type { RevalidateFn } from '../../lib/router-utils/router-server-context'
import type { InstrumentationOnRequestError } from '../../instrumentation/types'

type ApiContext = __ApiPreviewProps & {
  trustHostHeader?: boolean
  al

er'
import {
  JSON_CONTENT_TYPE_HEADER,
  PRERENDER_REVALIDATE_HEADER,
  PRERENDER_REVALIDATE_ONLY_GENERATED_HEADER,
} from '../../../lib/constants'
import { tryGetPreviewData } from './try-get-preview-data'
import { parseBody }


entry-handler'
import type { __ApiPreviewProps } from '../api-utils'
import type { RouteDefinition } from '../route-definitions/route-definition'
import type { MultiCompiler } from 'webpack'
import { COMPILER_NAMES } from '../../shared/lib/constants'

/**
 * Rspack Persistent Cache Strategy for Next.js Development
 *
 * Rspack's persistent caching differs from Webpack in how it manages module graphs.
 * While Webpack incrementally updates modules, Rspack operates on complete module
 * graph snapshots for ca

er page requests find no cached module information, preventing cache reuse
 *
 * Solution:
 * - Track successfully built page entries after each compilation
 * - Restore these entries on dev server restart to maintain module graph continuity
 * - This ensu

che restoration.
 *
 * Problem:
 * - Next.js dev server starts with no page modules in the initial entry points
 * - When Rspack restores from persistent cache, it finds no modules and purges
 *   the entire module graph
 * - Lat


omingRequests } from './log-requests'
import type { NodeNextRequest } from '../base-http/node'
import type { LoggingConfig } from '../config-shared'

describe('ignoreLoggingIncomingRequests', () => {
  const createMockRequest = (url: string): NodeNextRequest => {
    return { url } as NodeNextRequest
  }

  it('should respect boolean config', () => {
    const req = createMockRequest('/test')

    expect(
      ignoreLoggingIncomingRequests(req, { incomingRequests: false })
    ).toBe(true)
    expect(ignor

omingRequests(req, {})).toBe(false)
    expect(ignoreLoggingIncomingRequests(req, undefined)).toBe(false)
  })

  it('should handle array of RegExp ignore patterns', () => {
    const config: LoggingConfig = {
      incomingRequests: {
        ignore: [/^\

eLoggingIncomingRequests(req, { incomingRequests: true })).toBe(
      false
    )
  })

  it('should not ignore when no ignore patterns configured', () => {
    const req = createMockRequest('/test')

    expect(ignoreLoggingInc


e-parser'
import type { StackFrame } from 'next/dist/compiled/stacktrace-parser'
import {
  decorateServerError,
  type ErrorSourceType,
} from '../../shared/lib/error-source'

function getFilesystemFrame(frame: StackFrame): StackFrame {
  const f: StackFrame = { ...frame }

  if (typeof f.file === 'string') {
    if (
      // Posix:
      f.file.startsWith('/') ||
      // Win32:
      /^[a-z]:\\/i.test(f.file) ||
      // Win32 UNC:
      f.file.startsWith('\\\\')
    ) {
      f.file = `file://${f.file}

ails
    // to the user. These are written to a log file instead.
    const turbopackInternalError = new Error(
      'An unexpected Turbopack error occurred. Please see the output of `next dev` for more details.'
    )
    decorateServerError(turbopackInt

`
    }
  }

  return f
}

export function getServerError(error: Error, type: ErrorSourceType): Error {
  if (error.name === 'TurbopackInternalError') {
    // If this is an internal Turbopack error we shouldn't show internal det


EST,
  COMPILER_NAMES,
  PRERENDER_MANIFEST,
} from '../../shared/lib/constants'
import Server, { WrappedBuildError } from '../next-server'
import { normalizePagePath } from '../../shared/lib/page-path/normalize-page-path'
import { pathHasPrefix } from '../../shared/lib/router/utils/path-has-prefix'
import { removePathPrefix } from '../../shared/lib/router/utils/remove-path-prefix'
import { Telemetry } from '../../telemetry/storage'
import {
  type Span,
  hrtimeToEpochNanoseconds,
  setGlobal,
  trace,
} f

/../lib/coalesced-function'
import {
  loadDefaultErrorComponents,
  type ErrorModule,
} from '../load-default-error-components'
import { DecodeError, MiddlewareNotFoundError } from '../../shared/lib/utils'
import * as Log from '../../build/output/log'
imp

rom '../../trace'
import { traceGlobals } from '../../trace/shared'
import { findPageFile } from '../lib/find-page-file'
import { getFormattedNodeOptionsWithoutInspect } from '../lib/utils'
import { withCoalescedInvoke } from '..


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

function toWebReadableStream(stream: AnyStream): ReadableStream<Uint8Array> {
  if (stream instanceof ReadableStream) {
    return stream
  }
  const { Readable: ReadableClass } =
    require('node:stream') as typeof import('node:stream')
  return ReadableClass.toWeb(st

xport function connectReactDebugChannel(
  requestId: string,
  debugChannel: ReactDebugChannelForBrowser,
  sendToClient: (message: HmrMessageSentToBrowser) => void
) {
  const reader = toWebReadableStream(debugChannel.readable)
    .pipeThrough(
      //

ream as Readable) as ReadableStream<Uint8Array>
}

export interface ReactDebugChannelForBrowser {
  readonly readable: AnyStream
}

const reactDebugChannelsByHtmlRequestId = new Map<
  string,
  ReactDebugChannelForBrowser
>()

e


nderStoreModernRuntime
  readonly skipPropagation: boolean
  readonly outerOwnerStack: string | undefined
  /** The `'use cache'` function's server reference id (second arg of `cache()`). */
  readonly functionId: string
  /** The cache handler kind (first arg of `cache()`, e.g. 'default'). */
  readonly handlerKind: string
}

interface PublicCacheContext {
  readonly kind: 'public'
  // TODO: We should probably forbid nesting "use cache" inside unstable_cache.
  readonly outerWorkUnitStore: Exclude<
    Wo

he()`). */
  readonly functionId: string
  /** The cache handler kind (first arg of `cache()`, e.g. 'default'). */
  readonly handlerKind: string
  /**
   * Eagerly captured at `cache()` entry, pointing at this invocation's call
   * site. Only set when th

rkUnitStore,
    PrerenderStoreModernClient | ValidationStoreClient
  >
  readonly skipPropagation: boolean
  readonly outerOwnerStack: string | undefined
  /** The `'use cache'` function's server reference id (second arg of `cac


etDevOverlayFontMiddleware } from '../../next-devtools/server/font/get-dev-overlay-font-middleware'
import { devIndicatorServerState } from './dev-indicator-server-state'
import { getDisableDevIndicatorMiddleware } from '../../next-devtools/server/dev-indicator-middleware'
import { getRestartDevServerMiddleware } from '../../next-devtools/server/restart-dev-server-middleware'
import { backgroundLogCompilationEvents } from '../../shared/lib/turbopack/compilation-events'
import { getSupportedBrowsers } from '

th'
import {
  devToolsConfigMiddleware,
  getDevToolsConfig,
} from '../../next-devtools/server/devtools-config-middleware'
import { getAttachNodejsDebuggerMiddleware } from '../../next-devtools/server/attach-nodejs-debugger-middleware'
import {
  connect

../../build/get-supported-browsers'
import { printBuildErrors } from '../../build/print-build-errors'
import { receiveBrowserLogsTurbopack } from './browser-logs/receive-logs'
import { normalizePath } from '../../lib/normalize-pa


hared/lib/segment'
import {
  HMR_MESSAGE_SENT_TO_BROWSER,
  HMR_MESSAGE_SENT_TO_SERVER,
  type NextJsHotReloaderInterface,
} from './hot-reloader-types'
import { isAppPageRouteDefinition } from '../route-definitions/app-page-route-definition'
import { scheduleOnNextTick } from '../../lib/scheduler'
import { Batcher } from '../../lib/batcher'
import { normalizeAppPath } from '../../shared/lib/router/utils/app-paths'
import { PAGE_TYPES } from '../../lib/page-types'
import { getNextFlightSegmentPath } from '

dler')

/**
 * Returns object keys with type inferred from the object key
 */
const keys = Object.keys as <T>(o: T) => Extract<keyof T, string>[]

const COMPILER_KEYS = keys(COMPILER_INDEXES)

function treePathToEntrypoint(
  segmentPath: FlightSegmentPath

../../client/flight-data-helpers'
import { handleErrorStateResponse } from '../mcp/tools/get-errors'
import { handlePageMetadataResponse } from '../mcp/tools/get-page-metadata'

const debug = createDebug('next:on-demand-entry-han


 from '../../shared/lib/invariant-error'
import {
  HMR_MESSAGE_SENT_TO_BROWSER,
  type BinaryHmrMessageSentToBrowser,
} from './hot-reloader-types'

export const FAST_REFRESH_RUNTIME_RELOAD =
  'Fast Refresh had to perform a full reload due to a runtime error.'

const textEncoder = new TextEncoder()

export function createBinaryHmrMessageData(
  message: BinaryHmrMessageSentToBrowser
): Uint8Array {
  switch (message.type) {
    case HMR_MESSAGE_SENT_TO_BROWSER.ERRORS_TO_SHOW_IN_BROWSER: {
      const { se

RS_TO_SHOW_IN_BROWSER)
      data.set(serializedErrors, 1)

      return data
    }
    case HMR_MESSAGE_SENT_TO_BROWSER.REACT_DEBUG_CHUNK: {
      const { requestId, chunk } = message
      const requestIdBytes = textEncoder.encode(requestId)
      const

rializedErrors } = message
      const totalLength = 1 + serializedErrors.length
      const data = new Uint8Array(totalLength)
      const view = new DataView(data.buffer)

      view.setUint8(0, HMR_MESSAGE_SENT_TO_BROWSER.ERRO


rt { HeadersAdapter } from '../web/spec-extension/adapters/headers'
import {
  PRERENDER_REVALIDATE_HEADER,
  PRERENDER_REVALIDATE_ONLY_GENERATED_HEADER,
} from '../../lib/constants'
import { getTracer } from '../lib/trace/tracer'
import { NodeSpan } from '../lib/trace/constants'

export type NextApiRequestCookies = Partial<{ [key: string]: string }>
export type NextApiRequestQuery = Partial<{ [key: string]: string | string[] }>

export type __ApiPreviewProps = {
  previewModeId: string
  previewModeEncrypt

page)
    // Call API route method
    return getTracer().trace(
      NodeSpan.runHandler,
      {
        spanName: `executing api route (pages) ${page}`,
      },
      () => handler(...args)
    )
  }) as T
}

/**
 *
 * @param res response object
 * @p

ionKey: string
  previewModeSigningKey: string
}

export function wrapApiHandler<T extends (...args: any[]) => any>(
  page: string,
  handler: T
): T {
  return ((...args) => {
    getTracer().setRootSpanAttribute('next.route',


'../lib/trace/tracer'

import { isAbortError } from '../pipe-readable'
import { isBailoutToCSRError } from '../../shared/lib/lazy-dynamic/bailout-to-csr'
import { isDynamicServerError } from '../../client/components/hooks-server-context'
import { isNextRouterError } from '../../client/components/is-next-router-error'
import { isPrerenderInterruptedError } from './dynamic-rendering'
import { getProperError } from '../../lib/is-error'
import { createDigestWithErrorCode } from '../../lib/error-telemetry-utils'

=> void)
}

type RSCErrorHandler = (err: unknown) => string | undefined
type SSRErrorHandler = (
  err: unknown,
  errorInfo?: ErrorInfo
) => string | undefined

export type DigestedError = Error & { digest: string; environmentName?: string }

/**
 * Retur

import { isReactLargeShellError } from './react-large-shell-error'
import { isInstantValidationError } from './instant-validation/instant-validation-error'

declare global {
  var __next_log_error__: undefined | ((err: unknown)


xport function getScriptNonceFromHeader(
  cspHeaderValue: string
): string | undefined {
  const directives = cspHeaderValue
    // Directives are split by ';'.
    .split(';')
    .map((directive) => directive.trim())

  // First try to find the directive for the 'script-src', otherwise try to
  // fallback to the 'default-src'.
  const directive =
    directives.find((dir) => dir.startsWith('script-src')) ||
    directives.find((dir) => dir.startsWith('default-src'))

  // If no directive could be found,

  // Extract the first valid nonce from the directive. Malformed nonces are
  // ignored so the request can continue without a nonce instead of failing.
  for (const source of directive.split(/\s+/).slice(1)) {
    const match = source.trim().match(CSP_N

 then we're done.
  if (!directive) {
    return
  }


act, { type JSX } from 'react'
import { isHTTPAccessFallbackError } from '../../client/components/http-access-fallback/http-access-fallback'
import {
  getURLFromRedirectError,
  getRedirectStatusCodeFromError,
} from '../../client/components/redirect'
import { isRedirectError } from '../../client/components/redirect-error'
import { RedirectStatusCode } from '../../client/components/redirect-status-code'
import { addPathPrefix } from '../../shared/lib/router/utils/add-path-prefix'
import type { ClientTraceD

verCapturedErrors,
  tracingMetadata,
  basePath,
}: {
  polyfills: JSX.IntrinsicElements['script'][]
  renderServerInsertedHTML: () => React.ReactNode
  tracingMetadata: ClientTraceDataEntry[] | undefined
  serverCapturedErrors: Array<unknown>
  basePath:

ataEntry } from '../lib/trace/tracer'
import {
  renderToNodeFizzStream,
  renderToWebFizzStream,
  streamToString,
} from './stream-ops'

export function makeGetServerInsertedHTML({
  polyfills,
  renderServerInsertedHTML,
  ser


athHasPrefix } from '../../shared/lib/router/utils/path-has-prefix'
import { removePathPrefix } from '../../shared/lib/router/utils/remove-path-prefix'
import { workAsyncStorage } from './work-async-storage.external'

export interface ServerModuleMap {
  readonly [name: string]: {
    readonly id: string | number
    readonly name: string
    readonly chunks: Readonly<Array<string>> // currently not used
    readonly async?: boolean
  }
}

// This is a global singleton that is, among other things, also used

ingleton {
  readonly clientReferenceManifestsPerRoute: Map<
    string,
    DeepReadonly<ClientReferenceManifest>
  >
  readonly proxiedClientReferenceManifest: DeepReadonly<ClientReferenceManifest>
  serverActionsManifest: DeepReadonly<ActionManifest>

 to
// encode/decode bound args of server function closures. This can't be using a
// AsyncLocalStorage as it might happen at the module level.
const MANIFESTS_SINGLETON = Symbol.for('next.server.manifests')

interface ManifestsS


{ FlightRouterState } from '../../shared/lib/app-router-types'
import { flightRouterStateSchema } from './types'
import { assert } from 'next/dist/compiled/superstruct'

export function parseAndValidateFlightRouterState(
  stateHeader: string | string[]
): FlightRouterState
export function parseAndValidateFlightRouterState(
  stateHeader: undefined
): undefined
export function parseAndValidateFlightRouterState(
  stateHeader: string | string[] | undefined
): FlightRouterState | undefined
export function par

w Error(
      'Multiple router state headers were sent. This is not allowed.'
    )
  }

  // We limit the size of the router state header to ~40kb. This is to prevent
  // a malicious user from sending a very large header and slowing down the
  // resolv

seAndValidateFlightRouterState(
  stateHeader: string | string[] | undefined
): FlightRouterState | undefined {
  if (typeof stateHeader === 'undefined') {
    return undefined
  }
  if (Array.isArray(stateHeader)) {
    throw ne


ate,
  getDynamicDataPostponedState,
  getDynamicHTMLPostponedState,
  parsePostponedState,
  DynamicHTMLPreludeState,
} from './postponed-state'
import type {
  OpaqueFallbackRouteParams,
  OpaqueFallbackRouteParamValue,
} from '../request/fallback-params'

export function createMockOpaqueFallbackRouteParams(
  params: Record<string, OpaqueFallbackRouteParamValue>
): OpaqueFallbackRouteParams {
  return new Map(Object.entries(params))
}

const isCacheComponentsEnabled = process.env.__NEXT_CACHE_COMPONENTS

ueFallbackRouteParams({
      slug: [key, 'd'],
    })
    const prerenderResumeDataCache = createPrerenderResumeDataCache()

    prerenderResumeDataCache.cache.set(
      '1',
      Promise.resolve({
        entry: {
          value: streamFromString('hel

=== 'true'

describe('getDynamicHTMLPostponedState', () => {
  it('serializes a HTML postponed state with fallback params', async () => {
    const key = '%%drp:slug:e9615126684e5%%'
    const fallbackRouteParams = createMockOpaq


'
import type { Params } from '../request/params'
import {
  createPrerenderResumeDataCache,
  createRenderResumeDataCache,
  type PrerenderResumeDataCache,
  type RenderResumeDataCache,
} from '../resume-data-cache/resume-data-cache'
import { stringifyResumeDataCache } from '../resume-data-cache/resume-data-cache'

export enum DynamicState {
  /**
   * The dynamic access occurred during the RSC render phase.
   */
  DATA = 1,

  /**
   * The dynamic access occurred during the HTML shell render phase.
   */

.
   */
  readonly renderResumeDataCache: RenderResumeDataCache
}

/**
 * The postponed state for dynamic HTML.
 */
export type DynamicHTMLPostponedState = {
  /**
   * The type of dynamic state.
   */
  readonly type: DynamicState.HTML

  /**
   * The pos

  HTML = 2,
}

/**
 * The postponed state for dynamic data.
 */
export type DynamicDataPostponedState = {
  /**
   * The type of dynamic state.
   */
  readonly type: DynamicState.DATA

  /**
   * The immutable resume data cache


e-error-handler'
import { isReactLargeShellError } from './react-large-shell-error'

export enum Phase {
  ProspectiveRender = 'the prospective render',
  SegmentCollection = 'segment collection',
  InstantValidation = 'instant validation',
}

export function printDebugThrownValueForProspectiveRender(
  thrownValue: unknown,
  route: string,
  phase: Phase
) {
  // We don't need to print well-known Next.js errors.
  if (getDigestForWellKnownError(thrownValue)) {
    return
  }

  if (isReactLargeShellError(

s any).message === 'string'
  ) {
    message = (thrownValue as any).message
    if (typeof (thrownValue as any).stack === 'string') {
      const originalErrorStack: string = (thrownValue as any).stack
      const stackStart = originalErrorStack.indexOf('

thrownValue)) {
    // TODO: Aggregate
    console.error(thrownValue)
    return undefined
  }

  let message: undefined | string
  if (
    typeof thrownValue === 'object' &&
    thrownValue !== null &&
    typeof (thrownValue a


ck/plugins/flight-manifest-plugin'
import { encodeURIPath } from '../../shared/lib/encode-uri-path'
import type { AppRenderContext } from './app-render'
import { getAssetQueryString } from './get-asset-query-string'
import type { PreloadCallbacks } from './types'

/**
 * Abstracts the rendering of CSS files based on whether they are inlined or not.
 * For inlined CSS, renders a <style> tag with the CSS content directly embedded.
 * For external CSS files, renders a <link> tag pointing to the CSS file.
 */
e

de[] = []
  let index = 0
  for (const entryCssFile of entryCssFiles) {
    // `Precedence` is an opt-in signal for React to handle resource
    // loading and deduplication, etc. It's also used as the key to sort
    // resources so they will be injected

xport function renderCssResource(
  entryCssFiles: Iterable<CssResource>,
  ctx: AppRenderContext,
  preloadCallbacks?: PreloadCallbacks
) {
  const {
    componentMod: { createElement },
  } = ctx
  const elements: React.ReactNo


ode-uri-path'
import type { BuildManifest } from '../get-page-files'

import ReactDOM from 'react-dom'

export function getRequiredScripts(
  buildManifest: BuildManifest,
  assetPrefix: string,
  crossOrigin: undefined | '' | 'anonymous' | 'use-credentials',
  SRIManifest: undefined | Record<string, string>,
  qs: string,
  nonce: string | undefined,
  pagePath: string
): [
  () => void,
  { src: string; integrity?: string; crossOrigin?: string | undefined },
] {
  let preinitScripts: () => void
  let prei

ree?.[pagePath] || buildManifest.rootMainFiles
  ).map(encodeURIPath)
  if (files.length === 0) {
    throw new Error(
      'Invariant: missing bootstrap script. This is a bug in Next.js'
    )
  }
  if (SRIManifest) {
    bootstrapScript.src = `${assetPr

nitScriptCommands: string[] = []
  const bootstrapScript: {
    src: string
    integrity?: string
    crossOrigin?: string | undefined
  } = {
    src: '',
    crossOrigin,
  }

  const files = (
    buildManifest.rootMainFilesT


__'

const nextInternalPrefixRegex =
  /^(.*[\\/])?next[\\/]dist[\\/]client[\\/]components[\\/]builtin[\\/]/

/**
 * Normalize a file path to be relative to the project directory.
 * Handles Turbopack [project] prefix and monorepo setups.
 */
export function normalizeFilePath(
  projectDir: string,
  filePath: string | undefined
): string {
  // Turbopack project path is formed as: "<project root>/<cwd>".
  // When project root is not the working directory, we can extract the relative project root path.
  /

th = (filePath || '')
    // remove turbopack [project] prefix
    .replace(/^\[project\][\\/]?/, '')
    // remove the project root from the path (absolute)
    .replace(projectDir, '')
    // remove cwd prefix (absolute)
    .replace(cwd, '')
    // norm

/ This is mostly used for running Next.js inside a monorepo.
  const cwd = process.env.NEXT_RUNTIME === 'edge' ? '' : process.cwd()
  const relativeProjectRoot = projectDir.replace(cwd, '').replace(/^[\\/]/, '')

  let relativePa


eslint-disable @next/internal/no-ambiguous-jsx -- whole module is used in React Client */
// Provider for the `useServerInsertedHTML` API to register callbacks to insert
// elements into the HTML stream.

import type { JSX, ReactNode } from 'react'
import * as ReactClient from 'react'
import { ServerInsertedHTMLContext } from '../../shared/lib/server-inserted-html.shared-runtime'

export function createServerInsertedHTML() {
  const serverInsertedHTMLCallbacks: (() => ReactNode)[] = []
  const addInsertedHt

er value={addInsertedHtml}>
          {children}
        </ServerInsertedHTMLContext.Provider>
      )
    },
    renderServerInsertedHTML() {
      return serverInsertedHTMLCallbacks.map((callback, index) => (
        <ReactClient.Fragment key={'__next_se

ml = (handler: () => ReactNode) => {
    serverInsertedHTMLCallbacks.push(handler)
  }

  return {
    ServerInsertedHTMLProvider({ children }: { children: JSX.Element }) {
      return (
        <ServerInsertedHTMLContext.Provid


 | RenderStage.Dynamic

export class StagedRenderingController {
  currentStage: RenderStage = RenderStage.Before

  syncInterruptReason: Error | null = null
  staticStageEndTime: number = Infinity
  runtimeStageEndTime: number = Infinity

  private staticStageListeners: Array<() => void> = []
  private earlyRuntimeStageListeners: Array<() => void> = []
  private runtimeStageListeners: Array<() => void> = []
  private dynamicStageListeners: Array<() => void> = []

  private staticStagePromise = createPromis

  constructor(
    private abortSignal: AbortSignal | null,
    private abandonController: AbortController | null,
    private shouldTrackSyncIO: boolean
  ) {
    if (abortSignal) {
      abortSignal.addEventListener(
        'abort',
        () => {

eWithResolvers<void>()
  private earlyRuntimeStagePromise = createPromiseWithResolvers<void>()
  private runtimeStagePromise = createPromiseWithResolvers<void>()
  private dynamicStagePromise = createPromiseWithResolvers<void>()


shared'
import { INFINITE_CACHE } from '../../lib/constants'

/**
 * An AsyncIterable<number> that yields staleTime values. Each call to
 * `update()` yields the new value. When `close()` is called, the iteration
 * ends.
 *
 * This is included in the RSC payload so Flight serializes each yielded value
 * into the stream immediately. If the prerender is aborted by sync IO, the last
 * yielded value is already in the stream, allowing the prerender to be aborted
 * synchronously.
 */
export class StaleTimeIte

ate(value: number): void {
    if (this._done) return
    this.currentValue = value
    if (this._resolve) {
      this._resolve({ value, done: false })
      this._resolve = null
    } else {
      this._buffer.push(value)
    }
  }

  close(): void {

rable {
  private _resolve: ((result: IteratorResult<number>) => void) | null = null
  private _done = false
  private _buffer: number[] = []

  /** The last value passed to `update()`. */
  public currentValue: number = 0

  upd


er as webContinueDynamicPrerender,
  continueStaticFallbackPrerender as webContinueStaticFallbackPrerender,
  continueDynamicHTMLResume as webContinueDynamicHTMLResume,
  streamToBuffer as webStreamToBuffer,
  streamToString as webStreamToString,
  createDocumentClosingStream as webCreateDocumentClosingStream,
  createRuntimePrefetchTransformStream,
  CLOSE_TAG,
} from '../stream-utils/node-web-streams-helper'
import { indexOfUint8Array } from '../stream-utils/uint8array-helpers'
import { ENCODED_TAGS } fro

dDataReadableStream } from './use-flight-response'
import type { AnyStream as AnyStreamType } from './app-render-prerender-utils'
import { DetachedPromise } from '../../lib/detached-promise'
import { getTracer } from '../lib/trace/tracer'
import { AppRende

m '../stream-utils/encoded-tags'
import { MISSING_ROOT_TAGS_ERROR } from '../../shared/lib/errors/constants'
import {
  htmlEscapeAttributeString,
  htmlEscapeJsonString,
} from '../../shared/lib/htmlescape'
import { createInline


 *
 * When __NEXT_USE_NODE_STREAMS is true, uses Node.js pipeable stream APIs.
 * Otherwise, uses web ReadableStream APIs.
 *
 * Both modules export AnyStream = AnyStreamType so their type surfaces are
 * structurally identical — no `as unknown as` cast is needed.
 */
export type {
  AnyStream,
  ContinueFizzStreamOptions,
  ContinueStaticPrerenderOptions,
  ContinueStreamSharedOptions,
  ContinueDynamicHTMLResumeOptions,
  FlightComponentMod,
  ServerPrerenderComponentMod,
  FlightPayload,
  FlightClientM

f import('./stream-ops.node')
} else {
  _m = require('./stream-ops.web') as typeof import('./stream-ops.web')
}

export const continueFizzStream = _m.continueFizzStream
export const continueStaticPrerender = _m.continueStaticPrerender
export const continu

odules,
  FlightRenderOptions,
  FizzStreamResult,
} from './stream-ops.web'

type WebMod = typeof import('./stream-ops.web')

let _m: WebMod
if (process.env.__NEXT_USE_NODE_STREAMS) {
  _m = require('./stream-ops.node') as typeo


ream-ops.node.ts,
 * allowing the switcher to assign either module without `as unknown as`.
 */

import type { PostponedState, PrerenderOptions } from 'react-dom/static'
import { resume, renderToReadableStream } from 'react-dom/server'
import { prerender } from 'react-dom/static'

import {
  renderToInitialFizzStream,
  streamToString as webStreamToString,
  createRuntimePrefetchTransformStream,
  continueFizzStream as webContinueFizzStream,
  continueStaticPrerender as webContinueStaticPrerender,
  continu

nStreams as webChainStreams,
  createDocumentClosingStream as webCreateDocumentClosingStream,
} from '../stream-utils/node-web-streams-helper'
import { createInlinedDataReadableStream } from './use-flight-response'
import { processPrelude as webProcessPrel

eDynamicPrerender as webContinueDynamicPrerender,
  continueStaticFallbackPrerender as webContinueStaticFallbackPrerender,
  continueDynamicHTMLResume as webContinueDynamicHTMLResume,
  streamToBuffer as webStreamToBuffer,
  chai


ypto'

const SYNC_IO_DOCS: Record<SyncIOApiType, string> = {
  time: 'https://nextjs.org/docs/messages/next-prerender-current-time',
  random: 'https://nextjs.org/docs/messages/next-prerender-random',
  crypto: 'https://nextjs.org/docs/messages/next-prerender-crypto',
}

const SYNC_IO_CLIENT_DOCS: Record<SyncIOApiType, string> = {
  time: 'https://nextjs.org/docs/messages/next-prerender-current-time-client',
  random: 'https://nextjs.org/docs/messages/next-prerender-random-client',
  crypto: 'https://nextjs

/messages/next-prerender-runtime-random',
  crypto: 'https://nextjs.org/docs/messages/next-prerender-runtime-crypto',
}

function elapsedTimeBullet(type: SyncIOApiType): string {
  return type === 'time'
    ? `  - If the value is for telemetry, use a timi

.org/docs/messages/next-prerender-crypto-client',
}

const SYNC_IO_RUNTIME_DOCS: Record<SyncIOApiType, string> = {
  time: 'https://nextjs.org/docs/messages/next-prerender-runtime-current-time',
  random: 'https://nextjs.org/docs


eSchema } from './types'
import { assert } from 'next/dist/compiled/superstruct'

const validFixtures = [
  [
    ['a', 'b', 'c', null],
    {
      a: [['a', 'b', 'c', null], {}],
      b: [['a', 'b', 'c', null], {}],
    },
  ],
  [
    ['a', 'b', 'c', ['sibling1', 'sibling2']],
    {
      a: [['a', 'b', 'c', null], {}],
      b: [['a', 'b', 'c', []], {}],
    },
    null,
    null,
    0b10000, // PrefetchHint.IsRootLayout
  ],
  [
    ['a', 'b', 'c', null],
    {
      a: [['a', 'b', 'c', null], {}],

 4th element)
  [['a', 'b', 'foo', null], {}],
  // invalid staticSiblings (not an array)
  [['a', 'b', 'c', 'not-an-array'], {}],
  // invalid staticSiblings (array with non-strings)
  [['a', 'b', 'c', [1, 2]], {}],
  // invalid url
  [
    ['a', 'b', 'c'

     b: [['a', 'b', 'c', null], {}],
    },
    null,
    'refetch',
  ],
]

const invalidFixtures = [
  // plain wrong
  ['1', 'b', 'c'],
  // invalid enum (missing 4th element)
  [['a', 'b', 'foo'], {}],
  // invalid enum (with


onfig,
  ValidationLevel,
} from '../../server/config-shared'
import type { NextFontManifest } from '../../build/webpack/plugins/next-font-manifest-plugin'
import type { ParsedUrlQuery } from 'querystring'
import type { AppPageModule } from '../route-modules/app-page/module'
import type { DeepReadonly } from '../../shared/lib/deep-readonly'
import type { ImageConfigComplete } from '../../shared/lib/image-config'
import type { __ApiPreviewProps } from '../api-utils'

import s from 'next/dist/compiled/superst

from '../base-http'
import type { IncomingMessage } from 'http'
import type { RenderResumeDataCache } from '../resume-data-cache/resume-data-cache'
import type { ServerCacheStatus } from '../../next-devtools/dev-overlay/cache-indicator'
import type { Prefe

ruct'
import type { RequestLifecycleOpts } from '../base-server'
import type { InstrumentationOnRequestError } from '../instrumentation/types'
import type { NextRequestHint } from '../web/adapter'
import type { BaseNextRequest }


workUnitAsyncStorage } from './work-unit-async-storage.external'
import { InvariantError } from '../../shared/lib/invariant-error'
import { getClientReferenceManifest } from './manifests-singleton'

const isEdgeRuntime = process.env.NEXT_RUNTIME === 'edge'

const INLINE_FLIGHT_PAYLOAD_BOOTSTRAP = 0
const INLINE_FLIGHT_PAYLOAD_DATA = 1
const INLINE_FLIGHT_PAYLOAD_FORM_STATE = 2
const INLINE_FLIGHT_PAYLOAD_BINARY = 3

const flightResponses = new WeakMap<
  Readable | BinaryStreamOf<any>,
  Promise<any>
>()
co

ender Flight stream.
 * This is only used for renderToHTML, the Flight response does not need additional wrappers.
 */
export function getFlightStream<T>(
  flightStream: Readable | BinaryStreamOf<T>,
  debugStream: Readable | ReadableStream<Uint8Array> |

nst encoder = new TextEncoder()

const findSourceMapURL =
  process.env.NODE_ENV !== 'production'
    ? (require('../lib/source-maps') as typeof import('../lib/source-maps'))
        .findSourceMapURLDEV
    : undefined

/**
 * R


lso a thenable that can be serialized by React
 * Flight. The accumulator starts as 'pending' and accumulates param accesses
 * during render. Call `finishTrackingVaryParams()` after rendering to resolve
 * all accumulators.
 *
 * The `status` and `value` fields follow the React Flight thenable protocol:
 * when `status === 'fulfilled'`, Flight can read `value` synchronously without
 * scheduling a microtask via `.then()`.
 */
export type VaryParamsAccumulator = {
  // Mutable during render - accumulates pa

) => unknown) | null
  ): void

  // Internal - callbacks waiting for resolution
  resolvers: Array<(value: Set<string>) => void>
}

/**
 * A mutable data structure for accumulating per-segment vary params for an
 * entire server response. It's only used d

ram access
  varyParams: VaryParams

  // React thenable protocol fields
  status: 'pending' | 'fulfilled'
  value: VaryParams
  then(
    onfulfilled?: ((value: Set<string>) => unknown) | null,
    onrejected?: ((reason: unknown


tPreloadableFonts } from './get-preloadable-fonts'
import {
  createFlightRouterStateFromLoaderTree,
  createRouteTreePrefetch,
} from './create-flight-router-state-from-loader-tree'
import type { AppRenderContext } from './app-render'
import { hasLoadingComponentInTree } from './has-loading-component-in-tree'
import { addSearchParamsIfPageSegment } from '../../shared/lib/segment'
import { createComponentTree } from './create-component-tree'
import { getSegmentParam } from '../../shared/lib/router/utils/get

tree.
 */
export async function walkTreeWithFlightRouterState({
  loaderTreeToFilter,
  parentParams,
  flightRouterState,
  parentIsInsideSharedLayout,
  rscHead,
  injectedCSS,
  injectedJS,
  injectedFontPreloadTags,
  rootLayoutIncluded,
  ctx,
  prelo

-segment-param'

/**
 * Use router state to decide at what common layout to render the page.
 * This can either be the common layout between two pages or a specific place to start rendering from using the "refetch" marker in the


/../shared/lib/deep-readonly'
import type { AppSegmentConfig } from '../../build/segment-config/app/app-segment-config'
import type { AfterContext } from '../after/after-context'
import type { CacheLife } from '../use-cache/cache-life'
import type { SharedCacheResult } from '../use-cache/use-cache-wrapper'
import type { ValidationLevel } from '../config-shared'

// Share the instance module in the next-shared layer
import { workAsyncStorageInstance } from './work-async-storage-instance' with { 'turbopack-tr

export interface WorkStore {
  readonly isStaticGeneration: boolean

  /**
   * The page that is being rendered. This relates to the path to the page file.
   */
  readonly page: string

  /**
   * The route that is being rendered. This is the page propert

ansition': 'next-shared' }
import type { LazyResult } from '../lib/lazy-result'
import type { DigestedError } from './create-error-handler'
import type { ActionRevalidationKind } from '../../shared/lib/action-revalidation-kind'


type { ServerComponentsHmrCache } from '../response-cache'
import type {
  PrerenderResumeDataCache,
  ResumeDataCache,
} from '../resume-data-cache/resume-data-cache'
import type { Params } from '../request/params'
import type { ImplicitTags } from '../lib/implicit-tags'
import type { WorkStore } from './work-async-storage.external'
import { NEXT_HMR_REFRESH_HASH_COOKIE } from '../../client/components/app-router-headers'
import { InvariantError } from '../../shared/lib/invariant-error'
import type { Staged

ng } from './instant-validation/instant-samples'

export type WorkUnitPhase = 'action' | 'render' | 'after'

export interface CommonWorkUnitStore {
  /** NOTE: Will be mutated as phases change */
  phase: WorkUnitPhase
  readonly implicitTags: ImplicitTags

RenderingController } from './staged-rendering'
import { RenderStage } from './staged-rendering'
import type { ValidationBoundaryTracking } from './instant-validation/boundary-tracking'
import type { InstantValidationSampleTracki


ective here. Import this module via the shim in
// `packages/next/src/client/components/instant-validation/boundary.tsx` instead.
// 'use client'

import { createContext, type ReactNode } from 'react'
import { INSTANT_VALIDATION_BOUNDARY_NAME } from './boundary-constants'
import { InvariantError } from '../../../shared/lib/invariant-error'
import type { ValidationBoundaryTracking } from './boundary-tracking'
import { workUnitAsyncStorage } from '../work-unit-async-storage.external'

if (typeof window !== 'u

ncStorage.getStore()
  if (!store) return null
  switch (store.type) {
    case 'validation-client':
      return store.boundaryState
    case 'prerender':
    case 'prerender-client':
    case 'prerender-ppr':
    case 'prerender-legacy':
    case 'preren

ndefined') {
  throw new InvariantError(
    'Instant validation boundaries should never appear in browser bundles.'
  )
}

function getValidationBoundaryTracking(): ValidationBoundaryTracking | null {
  const store = workUnitAsy


port type ValidationBoundaryTracking = {
  /**
   * Map from boundary id (the SegmentPath where a validation boundary is
   * placed) to the file paths of modules inside that boundary's subtree.
   * When the boundary spans multiple parallel slots, each slot contributes
   * its own first-found module path so all unrendered segments can be
   * reported together.
   */
  requiredIds: Map<string, string[]>
  renderedIds: Set<string>
}

export function createValidationBoundaryTracking(): ValidationBoundaryTra

enderedIds: new Set(),
  }
}

export function allRequiredBoundariesRendered(
  state: ValidationBoundaryTracking
): boolean {
  for (const id of state.requiredIds.keys()) {
    if (!state.renderedIds.has(id)) {
      return false
    }
  }
  return true
}

cking {
  return {
    requiredIds: new Map(),
    r


ants'
import type { Segment } from '../../../shared/lib/app-router-types'
import type {
  AppSegmentConfig,
  InstantSample,
} from '../../../build/segment-config/app/app-segment-config'
import {
  workAsyncStorage,
  type WorkStore,
} from '../work-async-storage.external'
import { InvariantError } from '../../../shared/lib/invariant-error'

/**
 * True when an unconfigured segment should be treated as implicitly
 * validated under a non-manual default validation level. Only page and
 * default segments qua

    key.startsWith(PAGE_SEGMENT_KEY) ||
    key === DEFAULT_SEGMENT_KEY
  )
}

/**
 * Routes for the framework-synthesized error and not-found entries. They
 * have no user-configurable escape hatch (the framework supplies the page
 * when the user hasn't

lify — layouts do not validate on their own.
 */
export function isImplicitValidationSegment(segment: Segment): boolean {
  const key = typeof segment === 'string' ? segment : segment[0]
  return (
    key === PAGE_SEGMENT_KEY ||


/../client/components/readonly-url-search-params'
import { workUnitAsyncStorage } from '../work-unit-async-storage.external'
import { workAsyncStorage } from '../work-async-storage.external'
import {
  createExhaustiveParamsProxy,
  createExhaustiveURLSearchParamsProxy,
  trackMissingSampleErrorAndThrow,
} from './instant-samples'
import { InstantValidationError } from './instant-validation-error'

export function instrumentParamsForClientValidation<TPArams extends Params>(
  underlyingParams: TPArams
): TP

orkUnitStore.validationSamples) {
          const declaredKeys = new Set(
            Object.keys(workUnitStore.validationSamples.params ?? {})
          )
          return createExhaustiveParamsProxy(
            underlyingParams,
            declaredKeys

Arams {
  const workStore = workAsyncStorage.getStore()
  const workUnitStore = workUnitAsyncStorage.getStore()
  if (workStore && workUnitStore) {
    switch (workUnitStore.type) {
      case 'validation-client': {
        if (w


/../shared/lib/router/utils/parse-relative-url'
import { InvariantError } from '../../../shared/lib/invariant-error'
import { InstantValidationError } from './instant-validation-error'
import { workUnitAsyncStorage } from '../work-unit-async-storage.external'
import { wellKnownProperties } from '../../../shared/lib/utils/reflect-utils'
import type { WorkStore } from '../work-async-storage.external'

export type InstantValidationSampleTracking = {
  // TODO(instant-validation-build): track which samples conf

ectedSampleTracking(): InstantValidationSampleTracking {
  let validationSampleTracking: InstantValidationSampleTracking | null = null
  const workUnitStore = workUnitAsyncStorage.getStore()
  if (workUnitStore) {
    switch (workUnitStore.type) {
      ca

ig we used and attribute errors
  missingSampleErrors: InstantValidationError[]
}

export function createValidationSampleTracking(): InstantValidationSampleTracking {
  return {
    missingSampleErrors: [],
  }
}

function getExp


 type { FlightComponentMod } from '../stream-ops'

// eslint-disable-next-line import/no-extraneous-dependencies
import { createFromNodeStream } from 'react-server-dom-webpack/client'
import {
  addSearchParamsIfPageSegment,
  isGroupSegment,
  PAGE_SEGMENT_KEY,
  DEFAULT_SEGMENT_KEY,
  NOT_FOUND_SEGMENT_KEY,
} from '../../../shared/lib/segment'
import {
  isFrameworkErrorRoute,
  isImplicitValidationSegment,
} from './instant-config'
import type { NextParsedUrlQuery } from '../../request-meta'

const filte

ODE_ENV !== 'production'
    ? (
        require('../../lib/source-maps') as typeof import('../../lib/source-maps')
      ).findSourceMapURLDEV
    : undefined

// FIXME: this causes typescript errors related to 'flight-client-entry-plugin.d.ts'
// type Cl

rStackFrame =
  process.env.NODE_ENV !== 'production'
    ? (
        require('../../lib/source-maps') as typeof import('../../lib/source-maps')
      ).filterStackFrameDEV
    : undefined
const findSourceMapURL =
  process.env.N


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

/**
 * When we abort a staged render, we can still provide react with more chunks from later phases
 * to use for their debug info. This will not cause more contents to be rendered.
 */
export function createNodeStreamWithLateRelease(
  partialChunks: Array<Uint8Array>,
  allChunks: Array<Uint8Array>,
  releaseSignal: AbortSignal
): Readable {
  if (process.env.NEXT_RUNTIME === 'edge') {
    throw new InvariantError(
      'createNodeStreamWithL

ile (nextIndex < partialChunks.length) {
          this.push(partialChunks[nextIndex])
          nextIndex++
        }
      },
    })

    releaseSignal.addEventListener(
      'abort',
      () => {
        // Flush any remaining chunks from the original

ateRelease cannot be used in the edge runtime'
    )
  } else {
    const { Readable } = require('node:stream') as typeof import('node:stream')

    let nextIndex = 0

    const readable = new Readable({
      read() {
        wh


/invariant-error'
import { isThenable } from '../../../shared/lib/is-thenable'
import { trackPendingImport } from './track-module-loading.external'

/**
 * in CacheComponents, `import(...)` will be transformed into `trackDynamicImport(import(...))`.
 * A dynamic import is essentially a cached async function, except it's cached by the module system.
 *
 * The promises are tracked globally regardless of if the `import()` happens inside a render or outside of it.
 * When rendering, we can make the `cacheSignal

== 'edge') {
    throw new InvariantError(
      "Dynamic imports should not be instrumented in the edge runtime, because `cacheComponents` doesn't support it"
    )
  }

  if (!isThenable(modulePromise)) {
    // We're expecting `import()` to always retur

` wait for all pending promises via `trackPendingModules`.
 * */
export function trackDynamicImport<TExports extends Record<string, any>>(
  modulePromise: Promise<TExports>
): Promise<TExports> {
  if (process.env.NEXT_RUNTIME =


mSegment } from './app-render'
import { addSearchParamsIfPageSegment } from '../../shared/lib/segment'
import type { AppSegmentConfig } from '../../build/segment-config/app/app-segment-config'

async function createFlightRouterStateFromLoaderTreeImpl(
  loaderTree: LoaderTree,
  hintTree: PrefetchHints | null,
  prefetchInliningEnabled: boolean,
  cacheComponents: boolean,
  isStaticGeneration: boolean,
  isBuildTimePrerendering: boolean,
  getDynamicParamFromSegment: GetDynamicParamFromSegment,
  searchPar

dynamicParam ? dynamicParam.treeSegment : segment

  const segmentTree: FlightRouterState = [
    addSearchParamsIfPageSegment(treeSegment, searchParams),
    {},
  ]

  // Load the layout or page module to check for unstable_instant/unstable_prefetch conf

ams: any,
  didFindRootLayout: boolean
): Promise<FlightRouterState> {
  const [segment, parallelRoutes, { layout, loading, page }] = loaderTree
  const dynamicParam = getDynamicParamFromSegment(loaderTree)
  const treeSegment =


 it cannot be used here since the code path that calls this function
// can be run from edge. This is a simple implementation that safely achieves the required functionality.
// the goal is to match the functionality for remotePatterns as defined here -
// https://nextjs.org/docs/app/api-reference/components/image#remotepatterns
// TODO - retrofit micromatch to work in edge and use that instead
function matchWildcardDomain(domain: string, pattern: string) {
  // DNS names are case-insensitive per RFC 1035

 = normalizedDomain.split('.')
  const patternParts = normalizedPattern.split('.')

  if (patternParts.length < 1) {
    // pattern is empty and therefore invalid to match against
    return false
  }

  if (domainParts.length < patternParts.length) {

 // Use ASCII-only toLowerCase to avoid unicode issues
  const normalizedDomain = domain.replace(/[A-Z]/g, (c) => c.toLowerCase())
  const normalizedPattern = pattern.replace(/[A-Z]/g, (c) => c.toLowerCase())

  const domainParts


ebug channel implementation.
 * Loaded by debug-channel-server.ts.
 */

import type { AnyStream } from './app-render-prerender-utils'

export type DebugChannelPair = {
  serverSide: DebugChannelServer
  clientSide: DebugChannelClient
}

export type DebugChannelServer = any

type DebugChannelClient = {
  readable: AnyStream
}

/**
 * Creates a debug channel using web WritableStream/ReadableStream.
 * Use with renderToWebFlightStream (React's renderToReadableStream),
 * which expects debugChannel = { writable

ntroller) {
      readableController = controller
    },
  })

  return {
    serverSide: {
      writable: new WritableStream<Uint8Array>({
        write(chunk) {
          readableController?.enqueue(chunk)
        },
        close() {
          readable

: WritableStream }.
 */
export function createWebDebugChannel(): DebugChannelPair {
  let readableController: ReadableStreamDefaultController | undefined

  const clientSideReadable = new ReadableStream<Uint8Array>({
    start(co


rn,
  ValidationStoreClient,
} from '../app-render/work-unit-async-storage.external'

// Once postpone is in stable we should switch to importing the postpone export directly
import React from 'react'

import { DynamicServerError } from '../../client/components/hooks-server-context'
import { StaticGenBailoutError } from '../../client/components/static-generation-bailout'
import {
  throwForMissingRequestStore,
  workUnitAsyncStorage,
} from './work-unit-async-storage.external'
import { workAsyncStorage } fr

UNDARY_NAME,
} from '../../lib/framework/boundary-constants'
import { scheduleOnNextTick } from '../../lib/scheduler'
import { BailoutToCSRError } from '../../shared/lib/lazy-dynamic/bailout-to-csr'
import {
  createRuntimeBodyError,
  createDynamicBodyErr

om '../app-render/work-async-storage.external'
import { makeHangingPromise, getRuntimeStage } from '../dynamic-rendering-utils'
import {
  METADATA_BOUNDARY_NAME,
  VIEWPORT_BOUNDARY_NAME,
  OUTLET_BOUNDARY_NAME,
  ROOT_LAYOUT_BO


import {
  arrayBufferToString,
  decrypt,
  encrypt,
  getActionEncryptionKey,
  stringToUint8Array,
} from './encryption-utils'
import {
  getClientReferenceManifest,
  getServerModuleMap,
} from './manifests-singleton'
import {
  getCacheSignal,
  getResumeDataCache,
  workUnitAsyncStorage,
} from './work-unit-async-storage.external'
import { createHangingInputAbortSignal } from './dynamic-rendering'
import React from 'react'

const isEdgeRuntime = process.env.NEXT_RUNTIME === 'edge'

const textEncoder =

    : undefined
const findSourceMapURL =
  process.env.NODE_ENV !== 'production'
    ? (require('../lib/source-maps') as typeof import('../lib/source-maps'))
        .findSourceMapURLDEV
    : undefined

/**
 * Decrypt the serialized string with the action

 new TextEncoder()
const textDecoder = new TextDecoder()

const filterStackFrame =
  process.env.NODE_ENV !== 'production'
    ? (require('../lib/source-maps') as typeof import('../lib/source-maps'))
        .filterStackFrameDEV


 from '../../shared/lib/invariant-error'
import { getServerActionsManifest } from './manifests-singleton'

let __next_loaded_action_key: CryptoKey

export function arrayBufferToString(
  buffer: ArrayBuffer | Uint8Array<ArrayBufferLike>
) {
  const bytes = new Uint8Array(buffer)
  const len = bytes.byteLength

  // @anonrig: V8 has a limit of 65535 arguments in a function.
  // For len < 65535, this is faster.
  // https://github.com/vercel/next.js/pull/56377#pullrequestreview-1656181623
  if (len < 65535)

rray(binary: string) {
  const len = binary.length
  const arr = new Uint8Array(len)

  for (let i = 0; i < len; i++) {
    arr[i] = binary.charCodeAt(i)
  }

  return arr
}

export function encrypt(
  key: CryptoKey,
  iv: Uint8Array<ArrayBuffer>,
  data:

{
    return String.fromCharCode.apply(null, bytes as unknown as number[])
  }

  let binary = ''
  for (let i = 0; i < len; i++) {
    binary += String.fromCharCode(bytes[i])
  }
  return binary
}

export function stringToUint8A


{ CssResource } from '../../build/webpack/plugins/flight-manifest-plugin'
import { getClientReferenceManifest } from './manifests-singleton'

/**
 * Get external stylesheet link hrefs based on server CSS manifest.
 */
export function getLinkAndScriptTags(
  filePath: string,
  injectedCSS: Set<string>,
  injectedScripts: Set<string>,
  collectNewImports?: boolean
): { styles: ReadonlySet<CssResource>; scripts: ReadonlySet<string> } {
  const filePathWithoutExt = filePath.replace(/\.[^.]+$/, '')
  const cssC

PathWithoutExt]

  if (cssFiles) {
    for (const css of cssFiles) {
      if (!injectedCSS.has(css.path)) {
        if (collectNewImports) {
          injectedCSS.add(css.path)
        }
        cssChunks.add(css)
      }
    }
  }

  if (jsFiles) {
    f

hunks = new Set<CssResource>()
  const jsChunks = new Set<string>()
  const { entryCSSFiles, entryJSFiles } = getClientReferenceManifest()
  const cssFiles = entryCSSFiles[filePathWithoutExt]
  const jsFiles = entryJSFiles?.[file


tNonceFromHeader } from './get-script-nonce-from-header'

describe('getScriptNonceFromHeader', () => {
  it('returns the first valid nonce from the script-src directive', () => {
    expect(
      getScriptNonceFromHeader(
        `default-src 'nonce-other'; script-src 'nonce-cmFuZG9tCg=='`
      )
    ).toBe('cmFuZG9tCg==')
  })

  it('ignores malformed nonce values', () => {
    expect(
      getScriptNonceFromHeader(`script-src 'nonce-"><script></script>"'`)
    ).toBeUndefined()
    expect(
      getScr

rt(1)'`)
    ).toBeUndefined()
  })

  it('skips malformed nonce values and keeps looking for a valid one', () => {
    expect(
      getScriptNonceFromHeader(
        `script-src 'nonce-" onerror="alert(1)' 'nonce-cmFuZG9tCg=='`
      )
    ).toBe('cmFuZG


eGenerator } from './types'

/**
 * In the web server, there is currently no incremental cache provided and we
 * always SSR the page.
 */
export default class WebResponseCache {
  pendingResponses: Map<string, Promise<ResponseCacheEntry | null>>
  previousCacheItem?: {
    key: string
    entry: ResponseCacheEntry | null
    expiresAt: number
  }
  minimalMode?: boolean

  constructor(minimalMode: boolean) {
    this.pendingResponses = new Map()
    // this is a hack to avoid Webpack knowing this is equal

xt: {
      isOnDemandRevalidate?: boolean
      isPrefetch?: boolean
      incrementalCache: any
    }
  ): Promise<ResponseCacheEntry | null> {
    // ensure on-demand revalidate doesn't block normal requests
    const pendingResponseKey = key
      ? `$

to this.minimalMode
    // because we replace this.minimalMode to true in production bundles.
    Object.assign(this, { minimalMode })
  }

  public get(
    key: string | null,
    responseGenerator: ResponseGenerator,
    conte


describe('parseHostHeader', () => {
  it('should return correct host', () => {
    expect(parseHostHeader({})).toBe(undefined)

    expect(
      parseHostHeader({
        host: 'www.foo.com',
      })
    ).toEqual({ type: 'host', value: 'www.foo.com' })

    expect(
      parseHostHeader({
        host: undefined,
        'x-forwarded-host': 'www.foo.com',
      })
    ).toEqual({ type: 'x-forwarded-host', value: 'www.foo.com' })

    expect(
      parseHostHeader({
        host: 'www.foo.com',
        '

       'x-forwarded-host': 'www.bar.com',
      })
    ).toEqual({ type: 'x-forwarded-host', value: 'www.bar.com' })
  })

  it('should return correct x-forwarded-host when provided in array', () => {
    expect(
      parseHostHeader({
        host: 'www.

x-forwarded-host': undefined,
      })
    ).toEqual({ type: 'host', value: 'www.foo.com' })
  })

  it('should return x-forwarded-host over host header', () => {
    expect(
      parseHostHeader({
        host: 'www.foo.com',


 './get-preloadable-fonts'
import type { AppRenderContext } from './app-render'
import { getAssetQueryString } from './get-asset-query-string'
import { encodeURIPath } from '../../shared/lib/encode-uri-path'
import type { PreloadCallbacks } from './types'
import { renderCssResource } from './render-css-resource'
const EMPTY_SET: ReadonlySet<never> = new Set()

export function getLayerAssets({
  ctx,
  layoutOrPagePath,
  injectedCSS: injectedCSSWithCurrentLayout,
  injectedJS: injectedJSWithCurrentLayout,

: AppRenderContext
  preloadCallbacks: PreloadCallbacks
}): React.ReactNode {
  const {
    componentMod: { createElement },
  } = ctx
  const { styles: styleTags, scripts: scriptTags } = layoutOrPagePath
    ? getLinkAndScriptTags(
        layoutOrPagePat

 injectedFontPreloadTags: injectedFontPreloadTagsWithCurrentLayout,
  preloadCallbacks,
}: {
  layoutOrPagePath: string | undefined
  injectedCSS: Set<string>
  injectedJS: Set<string>
  injectedFontPreloadTags: Set<string>
  ctx


der`. If the connection
// closes then whatever hanging chunks exist will be errored. This is because prerender (an experimental feature)
// has not yet implemented a concept of resume. For now we will simulate a paused connection by wrapping the stream
// in one that doesn't close even when the underlying is complete.
export class ReactServerResult {
  private _stream: null | AnyStream
  private _replayable: ReplayableNodeStream | null

  constructor(stream: AnyStream) {
    if (process.env.__NEXT_USE_NODE

eam {
    if (this._replayable) {
      return this._replayable.createReplayStream()
    }

    if (this._stream === null) {
      throw new Error(
        'Cannot tee a ReactServerResult that has already been consumed'
      )
    }
    if (isWebStream(th

_STREAMS && !isWebStream(stream)) {
      this._stream = null
      this._replayable = new ReplayableNodeStream(stream as Readable)
    } else {
      this._stream = stream
      this._replayable = null
    }
  }

  tee(): AnyStr


ound             |
==========================

Node.js does not guarantee that two timers scheduled back to back will run
on the same iteration of the event loop:

```ts
setTimeout(one, 0)
setTimeout(two, 0)
```

Internally, each timer is assigned a `_idleStart` property that holds
an internal libuv timestamp in millisecond resolution.
This will be used to determine if the timer is already "expired" and should be executed.
However, even in sync code, it's possible for two timers to get different `_idleStart

rnal/timers.js#L556-L564).
and can be debugged by running node with `NODE_DEBUG=timer`.

The easiest way to observe it is to run this program in a loop until it exits with status 1:

```
// test.js

let immediateRan = false
const t1 = setTimeout(() => {

` values.
This can cause one of the timers to be executed, and the other to be delayed until the next timer phase.

The delaying happens [here](https://github.com/nodejs/node/blob/c208ffc66bb9418ff026c4e3fa82e5b4387bd147/lib/inte


torage } from 'async_hooks'

const sharedAsyncLocalStorageNotAvailableError = new Error(
  'Invariant: AsyncLocalStorage accessed in runtime where it is not available'
)

class FakeAsyncLocalStorage<Store extends {}>
  implements AsyncLocalStorage<Store>
{
  disable(): void {
    throw sharedAsyncLocalStorageNotAvailableError
  }

  getStore(): Store | undefined {
    // This fake implementation of AsyncLocalStorage always returns `undefined`.
    return undefined
  }

  run<R>(): R {
    throw sharedAsyncL

 }
}

const maybeGlobalAsyncLocalStorage =
  typeof globalThis !== 'undefined' && (globalThis as any).AsyncLocalStorage

export function createAsyncLocalStorage<
  Store extends {},
>(): AsyncLocalStorage<Store> {
  if (maybeGlobalAsyncLocalStorage) {

ocalStorageNotAvailableError
  }

  exit<R>(): R {
    throw sharedAsyncLocalStorageNotAvailableError
  }

  enterWith(): void {
    throw sharedAsyncLocalStorageNotAvailableError
  }

  static bind<T>(fn: T): T {
    return fn


\n` +
      `  - Provide a placeholder with \`<Suspense fallback={...}>\` around the data access\n` +
      `  - If the runtime data is \`params\` and they're known, prerender them with \`generateStaticParams\`\n` +
      `  - Set \`export const instant = false\` to allow a blocking route\n\n` +
      `Learn more: https://nextjs.org/docs/messages/blocking-route`
  )
}

export function createDynamicBodyError(route: string): Error {
  return new Error(
    `Route "${route}": Next.js encountered uncached data

s to fix this:\n` +
      `  - Cache the data access with \`"use cache"\`\n` +
      `  - Provide a placeholder with \`<Suspense fallback={...}>\` around the data access\n` +
      `  - Set \`export const instant = false\` to allow a blocking route\n\n` +

during prerendering.\n\n` +
      `\`fetch(...)\` or \`connection()\` accessed outside of \`<Suspense>\` prevents the route from being prerendered, blocking the page load and leading to a slower user experience.\n\n` +
      `Way


?: string
  tree: TreePrefetch
  staleTime: number
}

export type TreePrefetchParam = {
  type: DynamicParamTypesShort
  // When cacheComponents is enabled, this field is always null.
  // Instead we parse the param on the client, allowing us to omit it from
  // the prefetch response and increase its cacheability.
  key: string | null
  // Static sibling segments at the same URL level. Used by the client
  // router to determine if a prefetch can be reused when navigating to
  // a static sibling of a dyna

 | null
}

export type TreePrefetch = {
  name: string
  // Only present for parameterized (dynamic) segments.
  param: TreePrefetchParam | null

  // Child segments.
  slots: null | {
    [parallelRouteKey: string]: TreePrefetch
  }

  /** Bitmask of Pref

mic route. For example, if the route is
  // /products/[id] and there's also /products/sale, then siblings
  // would be ['sale']. null means the siblings are unknown (e.g. in
  // webpack dev mode).
  siblings: readonly string[]


'should return true when allowedOrigins contains originDomain', () => {
    expect(isCsrfOriginAllowed('vercel.com', ['vercel.com'])).toBe(true)
    expect(isCsrfOriginAllowed('www.vercel.com', ['www.vercel.com'])).toBe(true)
  })

  it('should return true when allowedOrigins contains originDomain with matching pattern', () => {
    expect(isCsrfOriginAllowed('asdf.vercel.com', ['*.vercel.com'])).toBe(true)
    expect(isCsrfOriginAllowed('asdf.vercel.com', ['**.vercel.com'])).toBe(true)
    expect(isCsrfOri

ed('subdomain.localhost', ['*.localhost'])).toBe(
      true
    )
    expect(isCsrfOriginAllowed('localhost', ['*.localhost'])).toBe(false)

    // Multi-level wildcard
    expect(isCsrfOriginAllowed('subdomain.localhost', ['**.localhost'])).toBe(
      t

ginAllowed('asdf.jkl.vercel.com', ['**.vercel.com'])).toBe(
      true
    )
  })

  it("should correctly handle origins that don't have a TLD (eg for localhost)", () => {
    // Single level wildcard
    expect(isCsrfOriginAllow


 * Node debug channel implementation.
 * Loaded by debug-channel-server.ts when __NEXT_USE_NODE_STREAMS is enabled.
 */

import { PassThrough, Writable } from 'node:stream'
import type { DebugChannelPair } from './debug-channel-server.web'

export { createWebDebugChannel } from './debug-channel-server.web'

/**
 * Creates a debug channel using Node.js streams.
 * Use with renderToNodeFlightStream (React's renderToPipeableStream),
 * which expects debugChannel to be a Node.js stream with a .write() method.

 the debugChannel and
  // enters bidirectional mode, reading its own output back as commands.
  const writable = new Writable({
    write(chunk, _encoding, callback) {
      readable.push(chunk)
      callback()
    },
    final(callback) {
      readable

 */
export function createNodeDebugChannel(): DebugChannelPair {
  const readable = new PassThrough()

  // Use a plain Writable instead of exposing the PassThrough directly.
  // React's renderToPipeableStream detects .read() on


  renderToReadableStream,
  decodeReply,
  decodeAction,
  decodeFormState,
} from 'react-server-dom-webpack/server'

// eslint-disable-next-line import/no-extraneous-dependencies
export { prerender } from 'react-server-dom-webpack/static'

// Node.js-specific Flight APIs, needed by stream-ops.node.ts via ComponentMod.
// These must be exported from entry-base (react-server layer) because direct
// imports from react-server-dom-webpack/* fail outside this layer.
type FlightRenderToPipeableStream = (...args:

.Readable
}>

/* eslint-disable import/no-extraneous-dependencies */
export let renderToPipeableStream: FlightRenderToPipeableStream | undefined
export let prerenderToNodeStream: FlightPrerenderToNodeStream | undefined
if (process.env.__NEXT_USE_NODE_STREA

 any[]) => {
  pipe<Writable extends NodeJS.WritableStream>(destination: Writable): Writable
  abort: (reason?: unknown) => void
}

type FlightPrerenderToNodeStream = (...args: any[]) => Promise<{
  prelude: import('node:stream')


{ NextFontManifest } from '../../build/webpack/plugins/next-font-manifest-plugin'
import type { DeepReadonly } from '../../shared/lib/deep-readonly'

/**
 * Get hrefs for fonts to preload
 * Returns null if there are no fonts at all.
 * Returns string[] if there are fonts to preload (font paths)
 * Returns empty string[] if there are fonts but none to preload and no other fonts have been preloaded
 * Returns null if there are fonts but none to preload and at least some were previously preloaded
 */
export f

return null
  }
  const filepathWithoutExtension = filePath.replace(/\.[^.]+$/, '')
  const fontFiles = new Set<string>()
  let foundFontUsage = false

  const preloadedFontFiles = nextFontManifest.app[filepathWithoutExtension]
  if (preloadedFontFiles) {

unction getPreloadableFonts(
  nextFontManifest: DeepReadonly<NextFontManifest> | undefined,
  filePath: string | undefined,
  injectedFontPreloadTags: Set<string>
): string[] | null {
  if (!nextFontManifest || !filePath) {


AG_TOKEN_HEADER,
} from '../../lib/constants'
import { getServerActionRequestMetadata } from '../lib/server-action-request-meta'
import { isCsrfOriginAllowed } from './csrf-protection'
import { warn } from '../../build/output/log'
import { RequestCookies, ResponseCookies } from '../web/spec-extension/cookies'
import { HeadersAdapter } from '../web/spec-extension/adapters/headers'
import { fromNodeOutgoingHttpHeaders } from '../web/utils'
import {
  selectWorkerForForwarding,
  type ServerModuleMap,
  getSer

romServerReferenceId } from '../../shared/lib/server-reference-info'
import type { ServerActionLogInfo } from '../dev/server-action-logger'
import { RedirectStatusCode } from '../../client/components/redirect-status-code'
import { synchronizeMutableCookies

verActionsManifest,
  getServerModuleMap,
} from './manifests-singleton'
import { isNodeNextRequest, isWebNextRequest } from '../base-http/helpers'
import { normalizeFilePath } from './segment-explorer-path'
import { extractInfoF


'error', reject)
  })
}

function tick(): Promise<void> {
  return new Promise((resolve) => setImmediate(resolve))
}

describe('ReplayableNodeStream', () => {
  describe('construction and buffering', () => {
    it('buffers Uint8Array chunks from the source', async () => {
      const source = new PassThrough()
      const replayable = new ReplayableNodeStream(source)

      source.write(new Uint8Array([1, 2, 3]))
      source.write(new Uint8Array([4, 5, 6]))

      const ended = new Promise<void>((r) => so

'converts Buffer chunks to Uint8Array before buffering', async () => {
      const source = new PassThrough()
      const replayable = new ReplayableNodeStream(source)

      source.write(Buffer.from([10, 20, 30]))

      const ended = new Promise<void>((r

urce.on('end', r))
      source.end()
      await ended

      const collected = await collectBytes(replayable.createReplayStream())
      expect(collected).toEqual([
        [1, 2, 3],
        [4, 5, 6],
      ])
    })

    it(


  readonly flightRouterState: FlightRouterState | undefined
  readonly isPrefetchRequest: boolean
  readonly isRuntimePrefetchRequest: boolean
  /**
   * App Shell prefetch: a runtime prefetch that the server renders with
   * params omitted (any `await params` hangs forever). Produces the
   * param-independent shell of the route. Implies isRuntimePrefetchRequest.
   */
  readonly isAppShellPrefetchRequest: boolean
  readonly isRouteTreePrefetchRequest: boolean
  readonly isHmrRefresh: boolean
  readonly

aders: IncomingHttpHeaders,
  options: ParseRequestHeadersOptions
): ParsedRequestHeaders {
  // runtime prefetch requests are *not* treated as prefetch requests
  // (TODO: this is confusing, we should refactor this to express this better)
  const isPrefe

isRSCRequest: boolean
  readonly nonce: string | undefined
  readonly previouslyRevalidatedTags: string[]
  readonly requestId: string | undefined
  readonly htmlRequestId: string | undefined
}

function parseRequestHeaders(
  he


eropDefault } from './interop-default'
import { getLinkAndScriptTags } from './get-css-inlined-link-tags'
import type { AppRenderContext } from './app-render'
import { getAssetQueryString } from './get-asset-query-string'
import { encodeURIPath } from '../../shared/lib/encode-uri-path'
import { renderCssResource } from './render-css-resource'

export async function createComponentStylesAndScripts({
  filePath,
  getComponent,
  injectedCSS,
  injectedJS,
  ctx,
}: {
  filePath: string
  getComponent: () =>

s: entryCssFiles, scripts: jsHrefs } = getLinkAndScriptTags(
    filePath,
    injectedCSS,
    injectedJS
  )

  const styles = renderCssResource(entryCssFiles, ctx)

  const scripts: React.ReactNode[] = []
  let scriptIndex = 0
  for (const href of jsHre

any
  injectedCSS: Set<string>
  injectedJS: Set<string>
  ctx: AppRenderContext
}): Promise<[React.ComponentType<any>, React.ReactNode, React.ReactNode]> {
  const {
    componentMod: { createElement },
  } = ctx
  const { style


BOUNDARY_SUFFIX,
  BUILTIN_PREFIX,
  getConventionPathByType,
  isNextjsBuiltinFilePath,
} from './segment-explorer-path'
import type { AppSegmentConfig } from '../../build/segment-config/app/app-segment-config'
import { RenderStage, type StagedRenderingController } from './staged-rendering'

/**
 * Use the provided loader tree to create the React Component tree.
 */
// TODO convert these arguments to non-object form. the entrypoint doesn't need most of them
export function createComponentTree(props: {
  lo

oadTags: Set<string>
  ctx: AppRenderContext
  missingSlots?: Set<string>
  preloadCallbacks: PreloadCallbacks
  authInterrupts: boolean
  MetadataOutlet: ComponentType
}): Promise<CacheNodeSeedData> {
  return getTracer().trace(
    NextNodeServerSpan.cre

aderTree: LoaderTree
  parentParams: Params
  parentOptionalCatchAllParamName: string | null
  parentRuntimePrefetchable: false
  rootLayoutIncluded: boolean
  injectedCSS: Set<string>
  injectedJS: Set<string>
  injectedFontPrel


 server.
import path from 'path'
import fs from 'fs'
import { getStorageDirectory } from '../cache-dir'
import { arrayBufferToString } from './encryption-utils'

// Keep the key in memory as it should never change during the lifetime of the server in
// both development and production.
let __next_encryption_key_generation_promise: Promise<string> | null = null
const CONFIG_FILE = '.rscinfo'
const ENCRYPTION_KEY = 'encryption.key'
const ENCRYPTION_EXPIRE_AT = 'encryption.expire_at'
const EXPIRATION = 1000 *

FILE)
  if (!fs.existsSync(cacheBaseDir)) {
    await fs.promises.mkdir(cacheBaseDir, { recursive: true })
  }
  await fs.promises.writeFile(
    configPath,
    JSON.stringify({
      [ENCRYPTION_KEY]: configValue,
      [ENCRYPTION_EXPIRE_AT]: Date.now()

60 * 60 * 24 * 14 // 14 days

async function writeCache(distDir: string, configValue: string) {
  const cacheBaseDir = getStorageDirectory(distDir)
  if (!cacheBaseDir) return

  const configPath = path.join(cacheBaseDir, CONFIG_


vercel/og')

function importModule(): Promise<
  typeof import('next/dist/compiled/@vercel/og')
> {
  return import(
    process.env.NEXT_RUNTIME === 'edge'
      ? 'next/dist/compiled/@vercel/og/index.edge.js'
      : 'next/dist/compiled/@vercel/og/index.node.js'
  )
}

/**
 * The ImageResponse class allows you to generate dynamic images using JSX and CSS.
 * This is useful for generating social media images such as Open Graph images, Twitter cards, and more.
 *
 * Read more: [Next.js Docs: `ImageResponse`

ponse']>) {
    const readable = new ReadableStream({
      async start(controller) {
        const OGImageResponse: typeof import('next/dist/compiled/@vercel/og').ImageResponse =
          // So far we have to manually determine which build to use,

](https://nextjs.org/docs/app/api-reference/functions/image-response)
 */
export class ImageResponse extends Response {
  public static displayName = 'ImageResponse'
  constructor(...args: ConstructorParameters<OgModule['ImageRes


variant-error'
import { createAtomicTimerGroup } from './app-render-scheduling'
import {
  DANGEROUSLY_runPendingImmediatesAfterCurrentTask,
  expectNoPendingImmediates,
} from '../node-environment-extensions/fast-set-immediate.external'
import { isThenable } from '../../shared/lib/is-thenable'

function noop() {}

/**
 * This is a utility function to make scheduling sequential tasks that run back to back easier.
 * We schedule on the same queue (setTimeout) at the same time to ensure no other events can sn

 () => R,
  ...rest: Array<() => void>
): Promise<Awaited<R>> {
  if (process.env.NEXT_RUNTIME === 'edge') {
    throw new InvariantError(
      '`runInSequentialTasks` should not be called in edge runtime.'
    )
  } else {
    return new Promise((resolve

eak in between.
 *
 * The first function runs in the first task. Each subsequent function runs in its own task.
 * The returned promise resolves after the last task completes.
 */
export function runInSequentialTasks<R>(
  first:


 Compile-time switcher for debug channel operations.
 *
 * When __NEXT_USE_NODE_STREAMS is true, uses a Node PassThrough-based channel.
 * Otherwise, uses web WritableStream APIs.
 */
export type {
  DebugChannelPair,
  DebugChannelServer,
} from './debug-channel-server.web'
import type { DebugChannelPair } from './debug-channel-server.web'

type DebugChannelMod = {
  createWebDebugChannel: typeof import('./debug-channel-server.web').createWebDebugChannel
  createNodeDebugChannel: typeof import('./debug-cha

require('./debug-channel-server.web') as typeof import('./debug-channel-server.web')
}

export function createWebDebugChannel(): DebugChannelPair | undefined {
  if (process.env.NODE_ENV === 'production') {
    return undefined
  }

  return _m.createWebDe

nnel-server.web').createNodeDebugChannel
}

let _m: DebugChannelMod
if (process.env.__NEXT_USE_NODE_STREAMS) {
  _m =
    require('./debug-channel-server.node') as typeof import('./debug-channel-server.node')
} else {
  _m =


 page. This feature is really only useful when the cacheComponents flag is on
 * and should only be used in codepaths gated with this feature.
 */

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

export class CacheSignal {
  private count = 0
  private earlyListeners: Array<() => void> = []
  private listeners: Array<() => void> = []
  private tickPending = false
  private pendingTimeoutCleanup: (() => void) | null = null

  private subscribedSignals: Set<CacheSignal> | null = null

  con

cacheComponents` does not support it.'
      )
    }
  }

  private noMorePendingCaches() {
    if (!this.tickPending) {
      this.tickPending = true
      queueMicrotask(() =>
        process.nextTick(() => {
          this.tickPending = false

structor() {
    if (process.env.NEXT_RUNTIME === 'edge') {
      // we rely on `process.nextTick`, which is not supported in edge
      throw new InvariantError(
        'CacheSignal cannot be used in the edge runtime, because `


{ AppRenderContext } from './app-render'

const isDev = process.env.NODE_ENV === 'development'
const isTurbopack = !!process.env.TURBOPACK

export function getAssetQueryString(
  ctx: AppRenderContext,
  addTimestamp: boolean
) {
  let qs = ''

  // In development we add the request timestamp to allow react to
  // reload assets when a new RSC response is received.
  // Turbopack handles HMR of assets itself and react doesn't need to reload them
  // so this approach is not needed for Turbopack.
  const sho

= isDev && !isTurbopack && addTimestamp
  if (shouldAddVersion) {
    qs += `?v=${ctx.requestTimestamp}`
  }

  if (ctx.sharedContext.clientAssetToken) {
    qs += `${shouldAddVersion ? '&' : '?'}dpl=${ctx.sharedContext.clientAssetToken}`
  }
  return qs
}


ort type { RouteMatcherProvider } from '../route-matcher-provider'
import type { RouteMatcher } from '../../route-matchers/route-matcher'

interface LoaderComparable<D> {
  load(): Promise<D>
  compare(left: D, right: D): boolean
}

/**
 * This will memoize the matchers if the loaded data is comparable.
 */
export abstract class CachedRouteMatcherProvider<
  M extends RouteMatcher = RouteMatcher,
  D = any,
> implements RouteMatcherProvider<M>
{
  private data?: D
  private cached: ReadonlyArray<M> = []

 (!data) return []

    // Return the cached matchers if the data has not changed.
    if (this.data && this.loader.compare(this.data, data)) return this.cached
    this.data = data

    // Transform the manifest into matchers.
    const matchers = await t

constructor(private readonly loader: LoaderComparable<D>) {}

  protected abstract transform(data: D): Promise<ReadonlyArray<M>>

  public async matchers(): Promise<readonly M[]> {
    const data = await this.loader.load()
    if


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

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

    it('returns no routes with an empty filesystem', async () => {
      const reader: FileReader = { re

s).toHaveLength(0)
      expect(reader.read).toHaveBeenCalledWith(dir)
    })

    describe('filename matching', () => {
      it.each<{
        files: ReadonlyArray<string>
        route: AppPageRouteDefinition
      }>([
        {
          files: [`${di

ad: jest.fn(() => []) }
      const provider = new DevAppPageRouteMatcherProvider(
        dir,
        extensions,
        reader,
        isTurbopack
      )
      const matchers = await provider.matchers()
      expect(matcher


variant-error'
import { AwaiterMulti, AwaiterOnce } from './awaiter'

describe('AwaiterOnce/AwaiterMulti', () => {
  describe.each([
    { name: 'AwaiterMulti', impl: AwaiterMulti },
    { name: 'AwaiterOnce', impl: AwaiterOnce },
  ])('$name', ({ impl: AwaiterImpl }) => {
    it('awaits promises added by other promises', async () => {
      const awaiter = new AwaiterImpl()

      const MAX_DEPTH = 5
      const promises: TrackedPromise<unknown>[] = []

      const waitUntil = (promise: Promise<unknown>) =

t sleep(100)
        waitUntil(makeNestedPromise())
      }

      waitUntil(makeNestedPromise())

      await awaiter.awaiting()

      for (const promise of promises) {
        expect(promise.isSettled).toBe(true)
      }
    })

    it('calls onError fo

> {
        promises.push(trackPromiseSettled(promise))
        awaiter.waitUntil(promise)
      }

      const makeNestedPromise = async () => {
        if (promises.length >= MAX_DEPTH) {
          return
        }
        awai


variant-error'

/**
 * Provides a `waitUntil` implementation which gathers promises to be awaited later (via {@link AwaiterMulti.awaiting}).
 * Unlike a simple `Promise.all`, {@link AwaiterMulti} works recursively --
 * if a promise passed to {@link AwaiterMulti.waitUntil} calls `waitUntil` again,
 * that second promise will also be awaited.
 */
export class AwaiterMulti {
  private promises: Set<Promise<unknown>> = new Set()
  private onError: (error: unknown) => void

  constructor({ onError }: { onError?

 them indefinitely could result in a memory leak.
    const cleanup = () => {
      this.promises.delete(promise)
    }

    promise.then(cleanup, (err) => {
      cleanup()
      this.onError(err)
    })

    this.promises.add(promise)
  }

  public async

: (error: unknown) => void } = {}) {
    this.onError = onError ?? console.error
  }

  public waitUntil = (promise: Promise<unknown>): void => {
    // if a promise settles before we await it, we should drop it --
    // storing


ateAsyncLocalStorage } from '../app-render/async-local-storage'

export function getBuiltinRequestContext():
  | BuiltinRequestContextValue
  | undefined {
  const _globalThis = globalThis as GlobalThisWithRequestContext
  const ctx = _globalThis[NEXT_REQUEST_CONTEXT_SYMBOL]
  return ctx?.get()
}

const NEXT_REQUEST_CONTEXT_SYMBOL = Symbol.for('@next/request-context')

type GlobalThisWithRequestContext = typeof globalThis & {
  [NEXT_REQUEST_CONTEXT_SYMBOL]?: BuiltinRequestContext
}

/** A request context p

, callback: () => T): T
}

export type BuiltinRequestContextValue = {
  waitUntil?: WaitUntil
}
export type WaitUntil = (promise: Promise<any>) => void

/** "@next/request-context" has a different signature from AsyncLocalStorage,
 * matching [AsyncContext

rovided by the platform. */
export type BuiltinRequestContext = {
  get(): BuiltinRequestContextValue | undefined
}

export type RunnableBuiltinRequestContext = BuiltinRequestContext & {
  run<T>(value: BuiltinRequestContextValue


 { DetachedPromise } from '../../lib/detached-promise'
import { CloseController } from '../web/web-on-close'
import type { AfterContextOpts } from './after-context'
import { AwaiterOnce } from './awaiter'

type Ctx = {
  waitUntil: NonNullable<AfterContextOpts['waitUntil']>
  onClose: NonNullable<AfterContextOpts['onClose']>
  onTaskError: NonNullable<AfterContextOpts['onTaskError']>
}

export class AfterRunner {
  private awaiter = new AwaiterOnce()
  private closeController = new CloseController()
  priva

(error) => this.finishedWithoutErrors.reject(error),
  }

  public async executeAfter() {
    this.closeController.dispatchClose()
    await this.awaiter.awaiting()

    // if we got an error while running the callbacks,
    // thenthis is a noop, because

te finishedWithoutErrors = new DetachedPromise<void>()

  readonly context: Ctx = {
    waitUntil: this.awaiter.waitUntil.bind(this.awaiter),
    onClose: this.closeController.onClose.bind(this.closeController),
    onTaskError:


enameNormalizer } from './absolute-filename-normalizer'

describe('AbsoluteFilenameNormalizer', () => {
  it.each([
    {
      name: PAGE_TYPES.APP,
      pathname: '<root>/app/basic/(grouped)/endpoint/nested/route.ts',
      expected: '/basic/(grouped)/endpoint/nested/route',
    },
    {
      name: PAGE_TYPES.PAGES,
      pathname: '<root>/pages/basic/endpoint/nested.ts',
      expected: '/basic/endpoint/nested',
    },
    {
      name: PAGE_TYPES.PAGES,
      pathname: '<root>/pages/basic/endpoint/ind

])(
    "normalizes '$pathname' to '$expected'",
    ({ pathname, expected, name }) => {
      const normalizer = new AbsoluteFilenameNormalizer(
        `<root>/${name}`,
        ['ts', 'tsx', 'js', 'jsx'],
        name as PAGE_TYPES
      )

      expect

ex.ts',
      expected: '/basic/endpoint',
    },


import type { PAGE_TYPES } from '../../lib/page-types'
import { absolutePathToPage } from '../../shared/lib/page-path/absolute-path-to-page'
import type { Normalizer } from './normalizer'

/**
 * Normalizes a given filename so that it's relative to the provided directory.
 * It will also strip the extension (if provided) and the trailing `/index`.
 */
export class AbsoluteFilenameNormalizer implements Normalizer {
  /**
   *
   * @param dir the directory for which the files should be made relative to
   * @

ring>,
    private readonly pagesType: PAGE_TYPES
  ) {}

  public normalize(filename: string): string {
    return absolutePathToPage(filename, {
      extensions: this.extensions,
      keepIndex: false,
      dir: this.dir,
      pagesType: this.pagesTy

param extensions the extensions the file could have
   * @param keepIndex when `true` the trailing `/index` is _not_ removed
   */
  constructor(
    private readonly dir: string,
    private readonly extensions: ReadonlyArray<st


ort { Normalizers } from '../../normalizers'
import type { Normalizer } from '../../normalizer'
import { PrefixingNormalizer } from '../../prefixing-normalizer'
import { normalizePagePath } from '../../../../shared/lib/page-path/normalize-page-path'
import { UnderscoreNormalizer } from '../../underscore-normalizer'

export class AppBundlePathNormalizer extends PrefixingNormalizer {
  constructor() {
    super('app')
  }

  public normalize(page: string): string {
    return super.normalize(normalizePagePath

 pageNormalizer,
      // Normalize the app page to a pathname.
      new AppBundlePathNormalizer(),
    ]

    // %5F to _ replacement should only happen with Turbopack.
    if (isTurbopack) {
      normalizers.unshift(new UnderscoreNormalizer())
    }

(page))
  }
}

export class DevAppBundlePathNormalizer extends Normalizers {
  constructor(pageNormalizer: Normalizer, isTurbopack: boolean) {
    const normalizers = [
      // This should normalize the filename to a page.


E_TYPES } from '../../../../lib/page-types'
import { AbsoluteFilenameNormalizer } from '../../absolute-filename-normalizer'
import { Normalizers } from '../../normalizers'

/**
 * DevAppPageNormalizer is a normalizer that is used to normalize a pathname
 * to a page in the `app` directory.
 */
class DevAppPageNormalizerInternal extends AbsoluteFilenameNormalizer {
  constructor(appDir: string, extensions: ReadonlyArray<string>) {
    super(appDir, extensions, PAGE_TYPES.APP)
  }
}

export class DevAppPageNo

 // %5F to _ replacement should only happen with Turbopack.
      // TODO: enable when page matcher `/_` check is moved: https://github.com/vercel/next.js/blob/8eda00bf5999e43e8f0211bd72c981d5ce292e8b/packages/next/src/server/route-matcher-providers/dev/de

rmalizer extends Normalizers {
  constructor(
    appDir: string,
    extensions: ReadonlyArray<string>,
    _isTurbopack: boolean
  ) {
    const normalizer = new DevAppPageNormalizerInternal(appDir, extensions)
    super(


 { normalizeAppPath } from '../../../../shared/lib/router/utils/app-paths'
import { Normalizers } from '../../normalizers'
import { wrapNormalizerFn } from '../../wrap-normalizer-fn'
import { UnderscoreNormalizer } from '../../underscore-normalizer'
import type { Normalizer } from '../../normalizer'

export class AppPathnameNormalizer extends Normalizers {
  constructor() {
    super([
      // The pathname to match should have the trailing `/page` and other route
      // group information stripped from it

r.normalize(page)
  }
}

export class DevAppPathnameNormalizer extends Normalizers {
  constructor(pageNormalizer: Normalizer) {
    super([
      // This should normalize the filename to a page.
      pageNormalizer,
      // Normalize the app page to a p

.
      wrapNormalizerFn(normalizeAppPath),
      // The page should have the `%5F` characters replaced with `_` characters.
      new UnderscoreNormalizer(),
    ])
  }

  public normalize(page: string): string {
    return supe


 {
  AppBundlePathNormalizer,
  DevAppBundlePathNormalizer,
} from './app-bundle-path-normalizer'
import { AppFilenameNormalizer } from './app-filename-normalizer'
import { DevAppPageNormalizer } from './app-page-normalizer'
import {
  AppPathnameNormalizer,
  DevAppPathnameNormalizer,
} from './app-pathname-normalizer'

export class AppNormalizers {
  public readonly filename: AppFilenameNormalizer
  public readonly pathname: AppPathnameNormalizer
  public readonly bundlePath: AppBundlePathNormalizer

  co

lic readonly page: DevAppPageNormalizer
  public readonly pathname: DevAppPathnameNormalizer
  public readonly bundlePath: DevAppBundlePathNormalizer

  constructor(
    appDir: string,
    extensions: ReadonlyArray<string>,
    isTurbopack: boolean
  ) {

nstructor(distDir: string) {
    this.filename = new AppFilenameNormalizer(distDir)
    this.pathname = new AppPathnameNormalizer()
    this.bundlePath = new AppBundlePathNormalizer()
  }
}

export class DevAppNormalizers {
  pub


evPagesBundlePathNormalizer,
  PagesBundlePathNormalizer,
} from './pages-bundle-path-normalizer'
import { PagesFilenameNormalizer } from './pages-filename-normalizer'
import { DevPagesPageNormalizer } from './pages-page-normalizer'
import { DevPagesPathnameNormalizer } from './pages-pathname-normalizer'

export class PagesNormalizers {
  public readonly filename: PagesFilenameNormalizer
  public readonly bundlePath: PagesBundlePathNormalizer

  constructor(distDir: string) {
    this.filename = new PagesFi

o
    // analyze the page path to determine the locale prefix and it's locale.
  }
}

export class DevPagesNormalizers {
  public readonly page: DevPagesPageNormalizer
  public readonly pathname: DevPagesPathnameNormalizer
  public readonly bundlePath: Dev

lenameNormalizer(distDir)
    this.bundlePath = new PagesBundlePathNormalizer()

    // You'd think that we'd require a `pathname` normalizer here, but for
    // `/pages` we have to handle i18n routes, which means that we need t


ort { normalizePagePath } from '../../../../shared/lib/page-path/normalize-page-path'
import type { Normalizer } from '../../normalizer'
import { Normalizers } from '../../normalizers'
import { PrefixingNormalizer } from '../../prefixing-normalizer'
import { wrapNormalizerFn } from '../../wrap-normalizer-fn'

export class PagesBundlePathNormalizer extends Normalizers {
  constructor() {
    super([
      // The bundle path should have the trailing `/index` stripped from
      // it.
      wrapNormalizerFn(n

ePathNormalizer extends Normalizers {
  constructor(pagesNormalizer: Normalizer) {
    super([
      // This should normalize the filename to a page.
      pagesNormalizer,
      // Normalize the app page to a pathname.
      new PagesBundlePathNormalizer(

ormalizePagePath),
      // The page should prefixed with `pages/`.
      new PrefixingNormalizer('pages'),
    ])
  }

  public normalize(page: string): string {
    return super.normalize(page)
  }
}

export class DevPagesBundl