Production hardening

Ingenium ships native primitives an API team actually needs in prod, all opt-in. This page walks through what each one buys you and how to wire them all together.

The hardening surface

ConcernSurfaceWhy it matters
Per-request timeout ceilingingenium({ requestTimeoutMs: 30_000 })IngeniumTimeoutError (503)A handler that never resolves leaks the context, socket, and pool slot forever.
Hard request-body capingenium({ maxRequestBytes: 2_000_000 }) enforced at the transport layerDefault-100KB per-call check doesn't help if the handler reads via ctx.body.stream(). Cap is enforced before any consumer touches a byte.
Header injection guardctx.set(name, value) rejects \r\n immediately → IngeniumHeaderInjectionErrorCatches CRLF injection at the call site instead of deep inside Node's wire path.
ctx.json() safety on circular refs / BigIntThrows IngeniumUnserializableError (500) with the structural reasonNo more useless TypeError: Converting circular... bubbling up as a generic 500. safeJsonStringify(value) exported for lenient mode.
Idempotency-Key - skip caching 5xxingenium.idempotency({ cacheable: (s) => s < 500 }) (default)A transient 500 no longer gets replayed for the entire TTL.
Compat shim - fail-loud on broken middlewareexpressCompat(bodyParser.json()) throws TypeError at registrationSilent failures of express-session, multer, body-parser, compression now point at the native equivalent. Opt out via { allowKnownBroken: true }.
Asymmetric JWT (RS/PS/ES + JWKS)ingenium.jwt({ algorithms: ['RS256'], jwksUrl: '...' })Required for any IdP with a JWKS endpoint (Auth0, Okta, Cognito, Clerk, Supabase). Algorithm-confusion attacks blocked at the allowlist. 'none' rejected unconditionally.
Late-write protection_epoch counter on IngeniumContext - orphaned-handler writes after a timeout are detected and discardedStops cross-request response corruption when the pool recycles the context.

Full production wiring

Wire all of these together in production:

import {
  ingenium, sessionMiddleware, gracefulShutdown,
  IdempotencyMemoryStore,
} from 'ingenium'

const app = ingenium({
  trustProxy: 'loopback',                  // behind nginx / Caddy / etc.
  requestTimeoutMs: 30_000,                // hung-handler protection
  maxRequestBytes: 2 * 1024 * 1024,        // 2 MiB body ceiling
  poolSize: 4096,
})

app.use(ingenium.cors({ origin: 'https://app.example.com', credentials: true }))
app.use(ingenium.csrf({ secret: process.env.CSRF_SECRET! }))
app.use(sessionMiddleware({ secret: [process.env.SESSION_SECRET!] }))
app.use(ingenium.rateLimit({ windowMs: 60_000, limit: 100 }))
app.use(ingenium.idempotency({ store: new IdempotencyMemoryStore() }))   // swap for RedisStore for multi-instance
app.use(ingenium.problemDetails({ typeBaseUrl: 'https://api.example.com/errors/' }))
app.use(ingenium.jwt({
  algorithms: ['RS256'],
  jwksUrl: 'https://example.auth0.com/.well-known/jwks.json',
  issuer: 'https://example.auth0.com/',
  audience: 'https://api.example.com',
}))

const server = await app.listen(cfg.PORT, '0.0.0.0')
gracefulShutdown(server, { gracefulTimeoutMs: 10_000, onShutdown: () => db.close() })

Still NOT production-ready for multi-instance deploys: the in-memory stores for sessions, idempotency, and rate-limit don't share state across pods. Redis-backed adapters are the next P0. See the roadmap.

Where to next?