zorvix
v1.8.9
Published
A static http/https file server
Maintainers
Readme
Zorvix
A fast zero-dependency Node.js typed http/1.1 server supporting CLI with TLS, in-built clustering, caching, and an API that adds REST routing and Express style middleware support.
Full Benchmarks against Express and 0http
CLI
npx zorvix <port> [options]
nix run github:DanielLMcGuire/Zorvix -- -- <port> [options]| Flag | Description |
|---|---|
| <port> | Port to listen on (required) |
| -r, --root <dir> | Directory to serve (default: cwd) |
| -l, --log | Enable request logging |
| --dev | Single process, no cache, exit on uncaught exception |
| -dt, --devtools | Enable Chrome DevTools workspace |
| --key / --cert | PEM key and cert files to enable HTTPS |
npx zorvix 8080 # Serve current directory
npx zorvix 3000 --root ./dist -l # Serve ./dist with logging
npx zorvix 443 --key ./key.pem --cert ./cert.pem # HTTPS
npx zorvix 8080 --dev --devtools -l # Dev mode + DevToolsFull zorvix(1) documentation
Examples
# Serve the current directory on port 8080
npx zorvix 8080
# Serve a specific directory with request logging
npx zorvix 3000 --root ./dist -l
# HTTPS
npx zorvix 443 --key ./key.pem --cert ./cert.pem
# Dev mode with DevTools workspace
npx zorvix 8080 --dev --devtools -lAPI
createServer(options)
Creates and returns a ServerInstance. Use this for single-process servers, tests, and any case where you don't need workers`.
import { createServer } from 'zorvix';
const server = createServer({
port: 3000,
root: './public',
logging: true,
});
server.get('/hello', (req, res) => res.end('Hello, world!'));
await server.start();
await server.stop();serve(options, setup)
Use serve instead of createServer when workers: true. Any code that must run inside a worker (connections, setup, route registration, etc) belongs INSIDE the callback.
I will be updating this soon to allow the worker entry to be a path to a js file
import { serve } from 'zorvix';
// All dependencies must be initialized inside (use import(), not import!), not in the outer scope!
serve({
port: 3000,
root: './public',
logging: true,
workers: true,
key: './server.key',
cert: './server.crt',
}, async (server) => {
// Only runs in worker processes
await db.connect();
server.use('/api', authMiddleware);
server.get('/users/:id', async (req, res) => {
res.json(await db.findUser(req.params.id));
});
server.post('/users', async (req, res) => {
res.json(await db.createUser(req.body), 201);
});
await server.start();
});Routes and middleware
Both createServer and serve return/provide a ServerInstance with the same API:
server.use((req, res, next) => { next(); });
server.use('/api', authMiddleware);
server.get('/users/:id', (req, res) => res.end(req.params.id));
server.post('/users', handler);
server.put('/users/:id', handler);
server.patch('/users/:id', handler);
server.delete('/users/:id', handler);
server.head('/users/:id', handler);
server.options('/users', handler);
await server.start();
await server.stop();Full zorvix(3) documentation
Features
- Caching -
ETag(SHA-1 for cached files, mtime-based for streamed) andLast-Modifiedheaders;304 Not ModifiedforIf-None-Match/If-Modified-Since - Range requests -
Accept-Ranges: bytesadvertised;RangeandIf-Rangesupported; multi-range (multipart/byteranges) supported - Gzip - compressible MIME types are compressed when the client sends
Accept-Encoding: gzip - Content-Disposition - binary/archive types are served with
attachmentso browsers download rather than render - TLS - pass
key/certas file paths or pre-loadedBuffers to switch tohttps.createServer - Clustering -
serve()guarantees user code never runs in the primary; primary supervises a worker and restarts it after 500 ms on unexpected exit; clean signal exits are not restarted - Graceful shutdown - idle connections closed immediately; active connections given a 5 s grace period before forced termination
- DevTools - serves
/.well-known/appspecific/com.chrome.devtools.jsonwith a per-process UUID to register the root as a Chrome DevTools workspace - WebSocket-friendly -
server.serverexposes the underlyinghttp.Server/https.Serverfor attaching WebSocket libraries - Query params -
req.querypopulated on every request; repeated keys collapse tostring[], single-occurrence keys remainstring - Body parsing - opt-in
createBodyParser()middleware; supportsapplication/jsonandapplication/x-www-form-urlencoded; configurable byte limit (default 1 MiB); populatesreq.body - Response helpers -
res.json(data, status?)andres.html(markup, status?)set correctContent-TypeandContent-Lengthautomatically - TypeScript - typings generated and bundled
- npm - no runtime npm dependencies; requires Node.js 22+
- Security - path traversal →
400; URLs > 2048 bytes →414; > 50 headers →431; unmatched non-GET/HEAD →405with accurateAllowheader
