-
Notifications
You must be signed in to change notification settings - Fork 0
Middleware
NextRush middleware follows the Koa-style async pattern. Every middleware is an async (ctx, next) => void function.
import type { Middleware } from 'nextrush';
const requestLogger: Middleware = async (ctx, next) => {
const start = Date.now();
await next();
const ms = Date.now() - start;
console.log(`${ctx.method} ${ctx.path} ${ctx.status} — ${ms}ms`);
};
app.use(requestLogger);Return without calling next() to stop the chain:
const requireAuth: Middleware = async (ctx, next) => {
if (!ctx.get('authorization')) {
ctx.status = 401;
ctx.json({ error: 'Unauthorized' });
return; // chain stops here
}
await next();
};const tenantMiddleware: Middleware = async (ctx, next) => {
ctx.state.tenantId = ctx.get('x-tenant-id') ?? 'default';
await next();
};All middleware is installed separately from the core.
Parse incoming request bodies.
pnpm add @nextrush/body-parserimport { json, urlencoded, text, raw, bodyParser } from '@nextrush/body-parser';
// Combined parser (recommended)
app.use(bodyParser());
// Individual parsers
app.use(json({ limit: '10mb', strict: true }));
app.use(urlencoded({ extended: true, depth: 5 }));
app.use(text({ type: ['text/plain', 'text/html'] }));
app.use(raw({ type: 'application/octet-stream' }));OWASP-compliant CORS middleware with null-origin and wildcard-credential protection.
pnpm add @nextrush/corsimport { cors, strictCors, devCors, simpleCors } from '@nextrush/cors';
// Custom configuration
app.use(cors({
origin: ['https://app.example.com'],
credentials: true,
allowedHeaders: ['Content-Type', 'Authorization'],
}));
// Built-in presets
app.use(strictCors()); // production — strict origin matching
app.use(devCors()); // development — permissive
app.use(simpleCors(['https://app.example.com']));Security headers following OWASP recommendations.
pnpm add @nextrush/helmetimport { helmet, apiHelmet } from '@nextrush/helmet';
app.use(helmet()); // all defaults
app.use(apiHelmet()); // preset for JSON APIs
app.use(helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "'nonce-abc123'"],
},
},
hsts: { maxAge: 31536000, includeSubDomains: true, preload: true },
}));CSRF protection using the Signed Double-Submit Cookie pattern (OWASP recommended).
pnpm add @nextrush/csrfimport { csrf } from '@nextrush/csrf';
app.use(csrf({
secret: process.env.CSRF_SECRET!,
// Token is read from: X-CSRF-Token header, csrf body field, or _csrf query param
}));Rate limiting with Token Bucket (default), Sliding Window, and Fixed Window algorithms.
pnpm add @nextrush/rate-limitimport { rateLimit } from '@nextrush/rate-limit';
// Zero-config: 100 req/min per IP
app.use(rateLimit());
// Custom limits
app.use(rateLimit({ max: 1000, window: '15m' }));
// Choose algorithm
app.use(rateLimit({ algorithm: 'sliding-window', max: 100, window: '1m' }));Cookie parsing and serialization.
pnpm add @nextrush/cookiesimport { cookies } from '@nextrush/cookies';
app.use(cookies());
// In a handler:
ctx.state.cookies.set('session', 'abc123', {
httpOnly: true,
secure: true,
maxAge: 86400,
});
const session = ctx.state.cookies.get('session');
ctx.state.cookies.delete('session');Response compression with Gzip, Deflate, and Brotli. Uses the Web Compression Streams API for multi-runtime compatibility.
pnpm add @nextrush/compressionimport { compression } from '@nextrush/compression';
app.use(compression());
app.use(compression({
level: 9, // 1-9 compression level
threshold: 512, // skip responses smaller than 512 bytes
}));Multipart form-data parsing with memory and disk storage strategies.
pnpm add @nextrush/multipartimport { multipart, MemoryStorage, DiskStorage } from '@nextrush/multipart';
// Memory storage (default)
app.use(multipart({ storage: new MemoryStorage({ maxFileSize: 5 * 1024 * 1024 }) }));
// Disk storage
app.use(multipart({ storage: new DiskStorage({ dest: './uploads' }) }));
// In handler:
const files = ctx.state.files;
const fields = ctx.state.fields;Attach a unique request ID to every request for distributed tracing.
pnpm add @nextrush/request-idimport { requestId } from '@nextrush/request-id';
app.use(requestId());
// Each request gets ctx.state.requestId = crypto.randomUUID()
// Also sets X-Request-ID response headerMeasure and expose request duration via response headers.
pnpm add @nextrush/timerimport { timer } from '@nextrush/timer';
app.use(timer());
// Sets X-Response-Time header on every responseOrder matters. Register middleware in this sequence:
// 1. Request ID (first — so all middleware can use it)
app.use(requestId());
// 2. Security headers
app.use(helmet());
// 3. CORS (before auth)
app.use(cors());
// 4. Timing
app.use(timer());
// 5. Body parsing
app.use(json());
// 6. Rate limiting
app.use(rateLimit());
// 7. Auth middleware
app.use(requireAuth);
// 8. Routes
app.route('/api', router);import { errorHandler, notFoundHandler } from 'nextrush';
// Register as the first middleware to catch all errors from the chain
app.setErrorHandler(async (error, ctx) => {
// handled internally
});
// Or use the built-in error handler middleware
app.use(errorHandler());
// 404 for unmatched routes — register after all routes
app.use(notFoundHandler());NextRush · MIT License · Docs · Issues