Repository: vercel/next.js
Pull request: [devtools] Add a very minimal API for restarting the dev server

Example:

```
curl -v --request POST --header "Content-Type: application/json" --data '{}' http://localhost:3000/__nextjs_restart_dev
```

Closes PACK-4647

Changed files:
filename: packages/next/src/client/components/react-dev-overlay/server/restart-dev-server-middleware.ts
patch: @@ -0,0 +1,35 @@
+import type { ServerResponse, IncomingMessage } from 'http'
+import type { Telemetry } from '../../../../telemetry/storage'
+import { RESTART_EXIT_CODE } from '../../../../server/lib/utils'
+import { middlewareResponse } from './middleware-response'
+
+const EVENT_DEV_OVERLAY_RESTART_SERVER = 'DEV_OVERLAY_RESTART_SERVER'
+
+export function getRestartDevServerMiddleware(telemetry: Telemetry) {
+  return async function (
+    req: IncomingMessage,
+    res: ServerResponse,
+    next: () => void
+  ): Promise<void> {
+    const { pathname } = new URL(`http://n${req.url}`)
+    if (pathname !== '/__nextjs_restart_dev' || req.method !== 'POST') {
+      return next()
+    }
+
+    telemetry.record({
+      eventName: EVENT_DEV_OVERLAY_RESTART_SERVER,
+      payload: {},
+    })
+
+    // TODO: Use flushDetached
+    await telemetry.flush()
+
+    // do this async to try to give the response a chance to send
+    // it's not really important if it doesn't though
+    setTimeout(() => {
+      process.exit(RESTART_EXIT_CODE)
+    }, 0)
+
+    return middlewareResponse.noContent(res)
+  }
+}

filename: packages/next/src/server/dev/hot-reloader-turbopack.ts
patch: @@ -97,6 +97,7 @@ import {
 import { getDevOverlayFontMiddleware } from '../../client/components/react-dev-overlay/font/get-dev-overlay-font-middleware'
 import { devIndicatorServerState } from './dev-indicator-server-state'
 import { getDisableDevIndicatorMiddleware } from './dev-indicator-middleware'
+import { getRestartDevServerMiddleware } from '../../client/components/react-dev-overlay/server/restart-dev-server-middleware'
 // import { getSupportedBrowsers } from '../../build/utils'
 
 const wsServer = new ws.Server({ noServer: true })
@@ -649,6 +650,7 @@ export async function createHotReloaderTurbopack(
     getNextErrorFeedbackMiddleware(opts.telemetry),
     getDevOverlayFontMiddleware(),
     getDisableDevIndicatorMiddleware(),
+    getRestartDevServerMiddleware(opts.telemetry),
   ]
 
   const versionInfoPromise = getVersionInfo()

filename: packages/next/src/server/dev/hot-reloader-webpack.ts
patch: @@ -87,6 +87,7 @@ import { getNextErrorFeedbackMiddleware } from '../../client/components/react-de
 import { getDevOverlayFontMiddleware } from '../../client/components/react-dev-overlay/font/get-dev-overlay-font-middleware'
 import { getDisableDevIndicatorMiddleware } from './dev-indicator-middleware'
 import getWebpackBundler from '../../shared/lib/get-webpack-bundler'
+import { getRestartDevServerMiddleware } from '../../client/components/react-dev-overlay/server/restart-dev-server-middleware'
 
 const MILLISECONDS_IN_NANOSECOND = BigInt(1_000_000)
 
@@ -1569,6 +1570,7 @@ export default class HotReloaderWebpack implements NextJsHotReloaderInterface {
       getNextErrorFeedbackMiddleware(this.telemetry),
       getDevOverlayFontMiddleware(),
       getDisableDevIndicatorMiddleware(),
+      getRestartDevServerMiddleware(this.telemetry),
     ]
   }