@chubbyts/chubbyts-undici-server-node
v1.3.0
Published
Use @chubbyts/chubbyts-undici-server on node.js
Readme
chubbyts-undici-server-node
Description
Use @chubbyts/chubbyts-undici-server on node.js.
Requirements
- node: 22
- @chubbyts/chubbyts-undici-server: ^1.2.0
Installation
Through NPM as @chubbyts/chubbyts-undici-server-node.
npm i @chubbyts/chubbyts-undici-server-node@^1.3.0Usage
import { STATUS_CODES } from 'node:http';
import type { Server } from 'node:http';
import { createServer } from 'node:http';
import type { Handler, ServerRequest } from '@chubbyts/chubbyts-undici-server/dist/server';
import { Response } from '@chubbyts/chubbyts-undici-server/dist/server';
import {
createNodeRequestToUndiciRequestFactory,
createUndiciResponseToNodeResponseEmitter,
} from '@chubbyts/chubbyts-undici-server-node/dist/node';
const serverHost = process.env.SERVER_HOST as string;
const serverPort = parseInt(process.env.SERVER_PORT as string);
const shutdownServer = (server: Server) => {
server.close((err) => {
if (err) {
console.warn(`Shutdown server with error: ${err}`);
process.exit(1);
}
console.log('Shutdown server');
process.exit(0);
});
};
// second argument (optional): the request body must be fully received within 30s
const nodeRequestToUndiciRequestFactory = createNodeRequestToUndiciRequestFactory('https://example.com', 30_000);
// for example @chubbyts/chubbyts-framework app (which implements Handler)
const handler: Handler = async (serverRequest: ServerRequest<{name: string}>): Promise<Response> => {
return new Response(`Hello, ${serverRequest.attributes.name}`, {
status: 200,
statusText: STATUS_CODES[200],
headers: {'content-type': 'text/plain'}
});
};
// argument (optional): the response must be fully sent within 60s
const undiciResponseToNodeResponseEmitter = createUndiciResponseToNodeResponseEmitter(60_000);
const server = createServer(async (req, res) => {
try {
const serverRequest = nodeRequestToUndiciRequestFactory(req);
const response = await handler(serverRequest);
undiciResponseToNodeResponseEmitter(response, res);
} catch (error) {
console.error(`Failed to handle request: ${error}`);
// once headers are sent the response cannot be turned into a 500 anymore:
// destroying the socket is the only way to signal the failure to the client
if (res.headersSent) {
res.destroy(error instanceof Error ? error : new Error(String(error)));
return;
}
res.writeHead(500, { 'content-type': 'text/plain' }).end('Internal Server Error');
}
});
server.listen(serverPort, serverHost, () => {
console.log(`Listening to ${serverHost}:${serverPort}`);
});
process.on('SIGINT', () => shutdownServer(server));
process.on('SIGTERM', () => shutdownServer(server));Timeouts
Slow clients (slowloris) can otherwise tie up sockets indefinitely:
createNodeRequestToUndiciRequestFactory(baseUrl, requestBodyTimeoutMs): if the request body has not been fully received within the given time, the request gets destroyed and the error surfaces to the handler through the request body stream.createUndiciResponseToNodeResponseEmitter(responseSendTimeoutMs): if the response has not been fully sent within the given time (slow reading client or stalling response body stream), the response gets destroyed.
Both timeouts are optional and disabled by default. They only cover the body phases handled by this adapter,
so make sure the node server level timeouts are configured as well: server.headersTimeout (slow header
senders), server.requestTimeout and server.keepAliveTimeout.
Copyright
2026 Dominik Zogg
