import assert from 'node:assert/strict'; import http from 'node:http'; import url from 'node:url'; import configExports from 'next/dist/server/config.js'; import constants from 'next/constants.js'; import proxyExports from 'next/dist/server/lib/router-utils/proxy-request.js'; const loadConfig = configExports.default; const { PHASE_DEVELOPMENT_SERVER } = constants; const { proxyRequest } = proxyExports; // Exercise the installed Next proxy with the project's loaded config and real sockets. // A delayed structured failure must reach the caller beyond Next's default 30s. (async () => { const config = await loadConfig(PHASE_DEVELOPMENT_SERVER, process.cwd()); const pending = new Set(); const backend = http.createServer((request, response) => { request.resume(); const timer = setTimeout(() => { pending.delete(timer); response.writeHead(502, { 'content-type': 'application/json' }); response.end(JSON.stringify({ error: 'Backend timeout receipt', outcome: 'unknown' })); }, 31_000); pending.add(timer); }); const proxy = http.createServer((request, response) => { const target = url.parse(`http://127.0.0.1:${backend.address().port}${request.url}`, true); proxyRequest(request, response, target, undefined, undefined, config.experimental.proxyTimeout) .catch(() => { if (!response.headersSent) response.writeHead(500); response.end(); }); }); const listen = server => new Promise(resolve => server.listen(0, '127.0.0.1', resolve)); try { await listen(backend); await listen(proxy); const started = Date.now(); const response = await fetch(`http://127.0.0.1:${proxy.address().port}/api/uptime/speed-test`, { method: 'POST', body: '{}', headers: { 'content-type': 'application/json' }, signal: AbortSignal.timeout(60_000), }); assert.equal(response.status, 502, 'Next must preserve the backend failure receipt after 30s'); assert.deepEqual(await response.json(), { error: 'Backend timeout receipt', outcome: 'unknown' }); assert(Date.now() - started >= 31_000); console.log('Next proxy: delayed 502 JSON preserved beyond 30s'); } finally { for (const timer of pending) clearTimeout(timer); proxy.closeAllConnections(); backend.closeAllConnections(); await Promise.all([proxy, backend].map(server => new Promise(resolve => server.close(resolve)))); } })().catch(error => { console.error(error.message); process.exitCode = 1; });