A batteries-included Express.js v5 wrapper that provides an opinionated HTTP/HTTPS server with WebSocket support, session management, authorization parsing, and more.
yarn add @gibme/webserver
# or
npm install @gibme/webserver
import WebServer, { Logger } from '@gibme/webserver';
const app = WebServer({ port: 8080 });
app.get('/', (_request, response) => {
return response.json({ success: true });
});
app.ws('/wss', (socket) => {
socket.on('message', msg => socket.send(msg));
});
await app.start();
Logger.info('Listening on: %s', app.url);
.ws() routesX-Request-ID)X-Response-Time):id?)All options are optional with sensible defaults:
const app = WebServer({
host: '0.0.0.0',
port: 8080,
ssl: false, // or { certificate, privateKey }
backlog: 511,
bodyLimit: 2, // MB
compression: true,
corsOrigin: '*',
helmet: false, // or HelmetOptions
sessions: false, // or true or SessionOptions
logging: false, // or true, 'full', or callback
cookieSecret: ['insecure'],
autoHandle404: true,
autoHandleOptions: true,
autoParseJSON: true,
autoParseURLEncoded: true,
autoParseRaw: true,
autoParseText: true,
autoParseXML: true,
autoRecommendedHeaders: false,
autoContentSecurityPolicyHeaders: false,
autoStartCloudflared: false,
suppressProcessErrors: true,
xml: {}, // parser and validator options
wsOptions: {} // ws.ServerOptions
});
The Authorization header is automatically parsed and available on every request:
// Basic Auth: Authorization: Basic base64(user:pass)
request.authorization?.basic?.username
request.authorization?.basic?.password
// Bearer Token: Authorization: Bearer <token>
request.authorization?.bearer?.token
// JWT: If the bearer token is a valid JWT structure
request.authorization?.jwt?.header // { alg, typ }
request.authorization?.jwt?.payload // decoded claims
request.authorization?.jwt?.signature
Use ProtectedRouter() to build a mountable Express Router whose every route is gated by a pluggable authentication provider. The provider is consulted on each request, so calling setAuthenticationProvider after registering routes updates auth for all of them:
import WebServer, { ProtectedRouter } from '@gibme/webserver';
const app = WebServer();
const adminRouter = ProtectedRouter();
adminRouter.setAuthenticationProvider(async (request) => {
return request.authorization?.bearer?.token === 'secret';
// return true to allow, false to deny (401)
// or return { statusCode: 403, message: 'Forbidden' }
});
adminRouter.get('/admin', (_request, response) => {
return response.json({ admin: true });
});
app.use(adminRouter); // mount at root
// or: app.use('/api', adminRouter); // mount at a prefix
Because ProtectedRouter() returns a real express.Router, all router methods are available (get, post, put, patch, delete, head, options, route, use, etc.) and instances can be nested or reused across apps.
Register WebSocket handlers with Express-style routing:
app.ws('/chat', (socket, request, next) => {
socket.on('message', msg => socket.send(msg));
});
// With route parameters
app.ws('/room/:id', (socket, request) => {
const { id } = request.params;
socket.send(`Joined room ${id}`);
});
WebSocket support can also be added to routers:
import WebServer, { Router } from '@gibme/webserver';
const router = Router();
app.wsApplyTo(router, '/api');
router.ws('/events', (socket) => { /* ... */ });
app.use('/api', router);
Enable in-memory sessions backed by node-cache:
const app = WebServer({ sessions: true });
app.post('/login', (request, response) => {
request.session.user = request.body;
return response.status(200).send();
});
app.get('/profile', (request, response) => {
return response.json(request.session.user ?? {});
});
Pass express-session options for fine-grained control:
const app = WebServer({
sessions: {
secret: 'your-secret',
cookie: { secure: true, maxAge: 86400000 }
}
});
Routes with optional parameters (:id?) are automatically expanded into two registered routes:
app.get('/users/:id?', handler);
// Registers both /users and /users/:id
This works on all routing methods and on Router() instances.
Spin up a Cloudflare Tunnel for development and testing:
const app = WebServer({ autoStartCloudflared: true });
await app.start();
Logger.info('Public URL: %s', app.tunnel.url);
Or manage the tunnel manually:
await app.tunnel.install();
await app.tunnel.start();
console.log(app.tunnel.url); // https://xxxxx.trycloudflare.com
console.log(app.tunnel.connections);
await app.tunnel.stop();
app.static('/assets', './public');
// Basic request logging
const app = WebServer({ logging: true });
// Full logging (includes headers and body)
const app = WebServer({ logging: 'full' });
// Custom callback
const app = WebServer({
logging: async (entry) => {
await saveToDatabase(entry);
}
});
Every request is automatically augmented with:
| Property | Type | Description |
|---|---|---|
request.id |
string | Unique request UUID |
request.remoteIp |
string | Client IP (resolved through proxies/Cloudflare) |
request.time_elapsed |
number | Response time in milliseconds |
request.authorization |
object | Parsed authorization header |
request.cookies |
object | Parsed cookies |
request.signedCookies |
object | Verified signed cookies |
const app = WebServer({
ssl: {
certificate: '/path/to/cert.pem',
privateKey: '/path/to/key.pem'
}
});
Both file paths (strings) and Buffers are accepted.
import WebServer, { Logger, Router, multer } from '@gibme/webserver';
import type { Request, Response } from '@gibme/webserver';
https://gibme-npm.github.io/webserver/
MIT