Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 20 additions & 5 deletions packages/next/src/server/next-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1687,11 +1687,26 @@ export default class NextNodeServer extends BaseServer<
const adapterFn: typeof import('./web/adapter').adapter =
middlewareModule.default || middlewareModule

result = await adapterFn({
handler: middlewareModule.middleware || middlewareModule,
request: requestData,
page: 'middleware',
})
const hasRequestBody =
!['HEAD', 'GET'].includes(params.request.method) &&
Boolean(requestData.body)

try {
result = await adapterFn({
handler: middlewareModule.middleware || middlewareModule,
request: {
...requestData,
body: hasRequestBody
? requestData.body.cloneBodyStream()
: undefined,
},
page: 'middleware',
})
} finally {
if (hasRequestBody) {
requestData.body.finalize()
}
}
} else {
const { run } = require('./web/sandbox') as typeof import('./web/sandbox')

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
process.env.TEST_NODE_MIDDLEWARE = 'true'

require('./app-action-form-state.test')
8 changes: 7 additions & 1 deletion test/e2e/app-dir/actions/app-action-form-state.test.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
/* eslint-disable jest/no-standalone-expect */
import { nextTestSetup } from 'e2e-utils'
import { FileRef, nextTestSetup } from 'e2e-utils'
import { check } from 'next-test-utils'
import { join } from 'path'

describe('app-dir action useActionState', () => {
const { next } = nextTestSetup({
files: __dirname,
overrideFiles: process.env.TEST_NODE_MIDDLEWARE
? {
'middleware.js': new FileRef(join(__dirname, 'middleware-node.js')),
}
: {},
dependencies: {
nanoid: '4.0.1',
},
Expand Down
3 changes: 3 additions & 0 deletions test/e2e/app-dir/actions/app-action-node-middleware.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
process.env.TEST_NODE_MIDDLEWARE = 'true'

require('./app-action.test')
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
process.env.TEST_NODE_MIDDLEWARE = 'true'

require('./app-action-size-limit-invalid.test')
Comment on lines +1 to +3
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Restore TEST_NODE_MIDDLEWARE after the suite to avoid env leakage.

Since this sets a global env var at module scope, it can bleed into subsequent test files in the same worker. Consider saving the previous value and restoring it in afterAll.

🔧 Suggested patch
-process.env.TEST_NODE_MIDDLEWARE = 'true'
-
-require('./app-action-size-limit-invalid.test')
+const previousValue = process.env.TEST_NODE_MIDDLEWARE
+process.env.TEST_NODE_MIDDLEWARE = 'true'
+
+require('./app-action-size-limit-invalid.test')
+
+afterAll(() => {
+  if (previousValue === undefined) {
+    delete process.env.TEST_NODE_MIDDLEWARE
+  } else {
+    process.env.TEST_NODE_MIDDLEWARE = previousValue
+  }
+})
🤖 Prompt for AI Agents
In
`@test/e2e/app-dir/actions/app-action-size-limit-invalid-node-middleware.test.ts`
around lines 1 - 3, This file sets process.env.TEST_NODE_MIDDLEWARE at module
scope which can leak into other tests; capture the current value before
overwriting (e.g., const prev = process.env.TEST_NODE_MIDDLEWARE), set
process.env.TEST_NODE_MIDDLEWARE = 'true' as it currently does, and register an
afterAll cleanup that restores the original value
(process.env.TEST_NODE_MIDDLEWARE = prev or delete it if prev is undefined) so
the environment is not mutated for other tests; reference the module-level
assignment of process.env.TEST_NODE_MIDDLEWARE and add an afterAll hook to
restore the previous value.

17 changes: 13 additions & 4 deletions test/e2e/app-dir/actions/app-action-size-limit-invalid.test.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
import { NextInstance, nextTestSetup } from 'e2e-utils'
import { FileRef, NextInstance, nextTestSetup } from 'e2e-utils'
import { retry } from 'next-test-utils'
import { createRequestTracker } from 'e2e-utils/request-tracker'
import stripAnsi from 'strip-ansi'
import { accountForOverhead } from './account-for-overhead'
import { join } from 'path'

const CONFIG_ERROR =
'Server Actions Size Limit must be a valid number or filesize format larger than 1MB'

describe('app-dir action size limit invalid config', () => {
const { next, isNextStart, isNextDeploy, skipped } = nextTestSetup({
files: __dirname,
overrideFiles: process.env.TEST_NODE_MIDDLEWARE
? {
'middleware.js': new FileRef(join(__dirname, 'middleware-node.js')),
}
: {},
skipStart: true,
dependencies: {
nanoid: '4.0.1',
Expand Down Expand Up @@ -43,7 +49,8 @@ describe('app-dir action size limit invalid config', () => {
`
module.exports = {
experimental: {
serverActions: { bodySizeLimit: -3000 }
serverActions: { bodySizeLimit: -3000 },
nodeMiddleware: true
},
}
`
Expand All @@ -61,7 +68,8 @@ describe('app-dir action size limit invalid config', () => {
`
module.exports = {
experimental: {
serverActions: { bodySizeLimit: 'testmb' }
serverActions: { bodySizeLimit: 'testmb' },
nodeMiddleware: true
},
}
`
Expand All @@ -79,7 +87,8 @@ describe('app-dir action size limit invalid config', () => {
`
module.exports = {
experimental: {
serverActions: { bodySizeLimit: '-3000mb' }
serverActions: { bodySizeLimit: '-3000mb' },
nodeMiddleware: true
},
}
`
Expand Down
7 changes: 6 additions & 1 deletion test/e2e/app-dir/actions/app-action.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* eslint-disable jest/no-standalone-expect */
import { nextTestSetup } from 'e2e-utils'
import { FileRef, nextTestSetup } from 'e2e-utils'
import {
assertHasRedbox,
retry,
Expand All @@ -20,6 +20,11 @@ describe('app-dir action handling', () => {
const { next, isNextDev, isNextStart, isNextDeploy, isTurbopack } =
nextTestSetup({
files: __dirname,
overrideFiles: process.env.TEST_NODE_MIDDLEWARE
? {
'middleware.js': new FileRef(join(__dirname, 'middleware-node.js')),
}
: {},
dependencies: {
nanoid: '4.0.1',
'server-only': 'latest',
Expand Down
18 changes: 18 additions & 0 deletions test/e2e/app-dir/actions/middleware-node.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Ensure that https://github.com/vercel/next.js/issues/56286 is fixed.
import { NextResponse } from 'next/server'

export async function middleware(req) {
if (req.nextUrl.pathname.includes('rewrite-to-static-first')) {
req.nextUrl.pathname = '/static/first'
return NextResponse.rewrite(req.nextUrl)
}

return NextResponse.next()
}

/**
* @type {import('next/server').MiddlewareConfig}
*/
export const config = {
runtime: 'nodejs',
}
Comment on lines +13 to +18
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, let's understand the repository structure and find Next.js type definitions
git ls-files | grep -E "(middleware|server)" | head -20

Repository: Signal65/next.js-CodeRabbit

Length of output: 1103


🏁 Script executed:

# Search for MiddlewareConfig type definition in the codebase
rg -n "type MiddlewareConfig|interface MiddlewareConfig" --type=ts -A 10

Repository: Signal65/next.js-CodeRabbit

Length of output: 4557


🏁 Script executed:

# Also search for middleware config exports to understand the type structure
rg -n "export.*MiddlewareConfig" --type=ts

Repository: Signal65/next.js-CodeRabbit

Length of output: 1073


🏁 Script executed:

# Check if runtime property is used in middleware configs anywhere
rg -n "runtime.*nodejs" --type=ts -C 3

Repository: Signal65/next.js-CodeRabbit

Length of output: 25948


🏁 Script executed:

# Let's check the MiddlewareConfigInputSchema to see all supported properties
sed -n '95,150p' packages/next/src/build/segment-config/middleware/middleware-config.ts

Repository: Signal65/next.js-CodeRabbit

Length of output: 1417


🏁 Script executed:

# Let's check the actual file under review to see what it contains
cat -n test/e2e/app-dir/actions/middleware-node.js

Repository: Signal65/next.js-CodeRabbit

Length of output: 648


🏁 Script executed:

# Also check if there's a separate type definition for runtime in middleware context
rg -n "runtime.*nodejs" packages/next/src/build/segment-config/middleware/ -A 2 -B 2

Repository: Signal65/next.js-CodeRabbit

Length of output: 53


🏁 Script executed:

# Search for where runtime is parsed/validated in middleware config
rg -n "runtime" packages/next/src/build/segment-config/middleware/middleware-config.ts -A 2 -B 2

Repository: Signal65/next.js-CodeRabbit

Length of output: 53


🏁 Script executed:

# Check the types exported from next/server to understand what types are available
cat packages/next/src/server/web/types.ts

Repository: Signal65/next.js-CodeRabbit

Length of output: 1931


🏁 Script executed:

# Let's look at what types are available in next/server.d.ts
cat packages/next/server.d.ts | head -30

Repository: Signal65/next.js-CodeRabbit

Length of output: 1286


🏁 Script executed:

# Search for all type definitions that include runtime in middleware context
rg -n "type.*Middleware.*Config|interface.*Middleware.*Config" packages/next/src --type=ts -A 5

Repository: Signal65/next.js-CodeRabbit

Length of output: 8896


Update JSDoc type annotation to include the runtime property or use a more specific type.

The MiddlewareConfig type exported from next/server does not include the runtime property, which is set to 'nodejs' in this config. Consider either:

  • Removing the JSDoc type annotation and relying on type inference
  • Using a more specific type that includes all properties: { runtime: 'nodejs'; matcher?: ... }
  • Or filing a feature request to add runtime to the official MiddlewareConfig type definition
Relevant code snippet
/**
 * `@type` {import('next/server').MiddlewareConfig}
 */
export const config = {
  runtime: 'nodejs',
}
🤖 Prompt for AI Agents
In `@test/e2e/app-dir/actions/middleware-node.js` around lines 13 - 18, Update the
JSDoc for the exported config so the annotated type matches the included runtime
property: either remove the JSDoc annotation entirely from the exported symbol
config to let inference handle the shape, or replace
import('next/server').MiddlewareConfig with a more specific inline type that
includes runtime: 'nodejs' (and optional matcher if needed) so the runtime
property is allowed; ensure the modification targets the exported const named
config and the JSDoc comment referencing MiddlewareConfig.

9 changes: 0 additions & 9 deletions test/e2e/app-dir/actions/middleware.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,3 @@ export async function middleware(req) {

return NextResponse.next()
}

/**
* @type {import('next/server').MiddlewareConfig}
*/
export const config = {
// Ensure that middleware doesn't interfere with the request body parsing for
// this test fixture.
matcher: ['/((?!decode-req-body).*)'],
}
1 change: 1 addition & 0 deletions test/e2e/app-dir/actions/next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ module.exports = {
fetches: {},
},
experimental: {
nodeMiddleware: true,
serverActions: { bodySizeLimit: '2mb' },
},
}