Repository: vercel/next.js
Pull request: Pages API handler interface follow-ups

Applies some clean-up/follow-ups from review on https://github.com/vercel/next.js/pull/78166

Changed files:
filename: packages/next/src/build/templates/pages-api.ts
patch: @@ -1,34 +1,34 @@
 import type { NextApiResponse } from '../../types'
 import type { IncomingMessage, ServerResponse } from 'node:http'
+import type { PrerenderManifest } from '..'
+import type { DevRoutesManifest } from '../../server/lib/router-utils/setup-dev-bundler'
+import type { InstrumentationOnRequestError } from '../../server/instrumentation/types'
 
 import { parse } from 'node:url'
-import { RouteKind } from '../../server/route-kind'
 import { sendError } from '../../server/api-utils'
+import { RouteKind } from '../../server/route-kind'
+import type { Span } from '../../server/lib/trace/tracer'
 import { PagesAPIRouteModule } from '../../server/route-modules/pages-api/module.compiled'
 
 import { hoist } from './helpers'
 
 // Import the userland code.
 import * as userland from 'VAR_USERLAND'
 import { getTracer, SpanKind } from '../../server/lib/trace/tracer'
-import type { Span } from '../../server/lib/trace/tracer'
 import { BaseServerSpan } from '../../server/lib/trace/constants'
 import {
   ensureInstrumentationRegistered,
   instrumentationOnRequestError,
 } from '../../server/lib/router-utils/instrumentation-globals.external'
-import type { InstrumentationOnRequestError } from '../../server/instrumentation/types'
 import { getUtils } from '../../server/server-utils'
 import { PRERENDER_MANIFEST, ROUTES_MANIFEST } from '../../api/constants'
 import { isDynamicRoute } from '../../shared/lib/router/utils'
-import type { BaseNextRequest } from '../../server/base-http'
 import {
   RouterServerContextSymbol,
   routerServerGlobal,
 } from '../../server/lib/router-utils/router-server-context'
 import { removePathPrefix } from '../../shared/lib/router/utils/remove-path-prefix'
 import { normalizeLocalePath } from '../../shared/lib/i18n/normalize-locale-path'
-import type { PrerenderManifest, RoutesManifest } from '..'
 import { loadManifestFromRelativePath } from '../../server/load-manifest.external'
 
 // Re-export the handler (should be the default export).
@@ -62,17 +62,18 @@ export async function handler(
   const distDir = process.env.__NEXT_RELATIVE_DIST_DIR || ''
   const isDev = process.env.NODE_ENV === 'development'
 
-  const routesManifest = await loadManifestFromRelativePath<RoutesManifest>(
-    projectDir,
-    distDir,
-    ROUTES_MANIFEST
-  )
-  const prerenderManifest =
-    await loadManifestFromRelativePath<PrerenderManifest>(
+  const [routesManifest, prerenderManifest] = await Promise.all([
+    loadManifestFromRelativePath<DevRoutesManifest>(
+      projectDir,
+      distDir,
+      ROUTES_MANIFEST
+    ),
+    loadManifestFromRelativePath<PrerenderManifest>(
       projectDir,
       distDir,
       PRERENDER_MANIFEST
-    )
+    ),
+  ])
   let srcPage = 'VAR_DEFINITION_PAGE'
 
   // turbopack doesn't normalize `/index` in the page name
@@ -114,9 +115,9 @@ export async function handler(
     caseSensitive: Boolean(routesManifest.caseSensitive),
   })
   const rewriteParamKeys = Object.keys(
-    serverUtils.handleRewrites(req as any as BaseNextRequest, parsedUrl)
+    serverUtils.handleRewrites(req, parsedUrl)
   )
-  serverUtils.normalizeCdnUrl(req as any as BaseNextRequest, [
+  serverUtils.normalizeCdnUrl(req, [
     ...rewriteParamKeys,
     ...Object.keys(serverUtils.defaultRouteRegex?.groups || {}),
   ])
@@ -150,8 +151,8 @@ export async function handler(
 
     const activeSpan = tracer.getActiveScopeSpan()
 
-    const invokeRouteModule = async (span?: Span) => {
-      await routeModule
+    const invokeRouteModule = async (span?: Span) =>
+      routeModule
         .render(req, res, {
           query,
           params,
@@ -210,7 +211,6 @@ export async function handler(
             span.updateName(`${method} ${req.url}`)
           }
         })
-    }
 
     // TODO: activeSpan code path is for when wrapped by
     // next-server can be removed when this is no longer used

filename: packages/next/src/server/lib/router-utils/setup-dev-bundler.ts
patch: @@ -101,6 +101,17 @@ export type SetupOpts = {
   resetFetch: () => void
 }
 
+export interface DevRoutesManifest {
+  version: number
+  caseSensitive: RoutesManifest['caseSensitive']
+  basePath: RoutesManifest['basePath']
+  rewrites: RoutesManifest['rewrites']
+  redirects: RoutesManifest['redirects']
+  headers: RoutesManifest['headers']
+  i18n: RoutesManifest['i18n']
+  skipMiddlewareUrlNormalize: RoutesManifest['skipMiddlewareUrlNormalize']
+}
+
 export type ServerFields = {
   actualMiddlewareFile?: string | undefined
   actualInstrumentationHookFile?: string | undefined
@@ -200,14 +211,13 @@ async function startWatcher(opts: SetupOpts) {
   // have to write this after starting hot-reloader since that
   // cleans the dist dir
   const routesManifestPath = path.join(distDir, ROUTES_MANIFEST)
-  const routesManifest: Partial<RoutesManifest> = {
+  const routesManifest: DevRoutesManifest = {
     version: 3,
     caseSensitive: !!nextConfig.experimental.caseSensitiveRoutes,
     basePath: nextConfig.basePath,
     rewrites: opts.fsChecker.rewrites,
     redirects: opts.fsChecker.redirects,
     headers: opts.fsChecker.headers,
-    dataRoutes: [],
     i18n: nextConfig.i18n || undefined,
     skipMiddlewareUrlNormalize: nextConfig.skipMiddlewareUrlNormalize,
   }

filename: packages/next/src/server/server-utils.ts
patch: @@ -23,12 +23,12 @@ import {
   NEXT_QUERY_PARAM_PREFIX,
 } from '../lib/constants'
 import { normalizeNextQueryParam } from './web/utils'
-import type { IncomingHttpHeaders } from 'http'
+import type { IncomingHttpHeaders, IncomingMessage } from 'http'
 import { decodeQueryPathParameter } from './lib/decode-query-path-parameter'
 import type { DeepReadonly } from '../shared/lib/deep-readonly'
 
 export function normalizeCdnUrl(
-  req: BaseNextRequest,
+  req: BaseNextRequest | IncomingMessage,
   paramKeys: string[],
   defaultRouteRegex: ReturnType<typeof getNamedRouteRegex> | undefined
 ) {
@@ -198,7 +198,10 @@ export function getUtils({
     defaultRouteMatches = dynamicRouteMatcher(page) as ParsedUrlQuery
   }
 
-  function handleRewrites(req: BaseNextRequest, parsedUrl: UrlWithParsedQuery) {
+  function handleRewrites(
+    req: BaseNextRequest | IncomingMessage,
+    parsedUrl: UrlWithParsedQuery
+  ) {
     const rewriteParams = {}
     let fsPathname = parsedUrl.pathname
 
@@ -416,8 +419,10 @@ export function getUtils({
         ignoreMissingOptional
       )
     },
-    normalizeCdnUrl: (req: BaseNextRequest, paramKeys: string[]) =>
-      normalizeCdnUrl(req, paramKeys, defaultRouteRegex),
+    normalizeCdnUrl: (
+      req: BaseNextRequest | IncomingMessage,
+      paramKeys: string[]
+    ) => normalizeCdnUrl(req, paramKeys, defaultRouteRegex),
     interpolateDynamicPath: (
       pathname: string,
       params: Record<string, undefined | string | string[]>