Roadmap
Ingenium is alpha (v0.0.1). The API is mostly settled but still subject to change before 0.1.0. This page tracks what's shipped, what's known-broken, and what's planned. Authoritative changelog lives in the source repo.
Shipped in v0.0.1
Core surface:
riftex()app factory with lazy-composed middleware pipeline andapp.compose()pre-warm.Router()with prefix mounting, nested routers, and deterministic precedence (static > param > wildcard).- IngeniumContext with params, query, headers,
state, status/header setters, and terminal writers (json/text/html/send/redirect/stream). - Lazy body parsers -
json(with optional Zod-like schema +maxBytes),text,urlencoded,buffer,stream. - Handler return-value reflection (object → JSON, string → text/html,
Buffer→ octet-stream,Readable→ stream,undefined→ 204). - Error class hierarchy (
RiftexErrorand friends) with default JSON error boundary;app.onErroroverride + re-throw delegation. - Express compatibility shim (
expressCompat) for pure-function middleware (cors, helmet, etc.) + detect-and-throw guard for known-broken middleware (multer,express-session,compression,body-parser). - Plugin system -
app.register(plugin, opts?)with lifecycle hooks (onRoute,onCompose,onRequest,onResponse,onError) and per-request decorators.
Transports:
- Node HTTP adapter with
app.listen(port, host?)returning{ port, close }. - HTTP/2 and HTTP/2 cleartext (h2c) transports.
- WebSocket and SSE transports sharing the same dispatch entry.
- Bun adapter (
riftexpress-bun) forBun.serve()with a Web-Streams ↔node:streambridge.
Production primitives:
- Static file middleware - ETag,
If-None-Match, range requests, MIME detection, HEAD support,index/extensions/dotfiles/maxAgeoptions. - Rate limiting - sliding-window middleware with pluggable store (in-memory ships in core).
- Sessions - cookie + server-side stores.
- CSRF protection - native
riftex.csrf(opts)middleware, double-submit cookie or session-synchronizer pattern, HMAC-SHA-256 signed, timing-safe verification. - CORS - origin allowlist, preflight caching, credentials handling.
- Trust proxy -
X-Forwarded-*andForwardedparsing with explicit-hop counting. - Body parsing - schema-validated JSON with hard
maxRequestBytescap enforced at the transport layer (default 2 MiB). - Per-request timeout (
requestTimeoutMs) withRiftexTimeoutError(503) and late-write protection via per-context_epochcounter. - Graceful shutdown - drain in-flight requests, refuse new ones.
Auth + integrations:
- JWT middleware - HS256/384/512, RS256/384/512, PS256/384/512, ES256/384/512, plus JWKS support with in-flight request coalescing.
'none'rejected unconditionally. - API-key middleware.
- Idempotency-Key middleware - skip-caching 5xx by default via
IdempotencyOptions.cacheable. - OpenAPI generation, RFC 7807
application/problem+jsonerrors, content negotiation, reverse-proxy helpers, cron + background jobs primitives.
Hardening:
- Header injection guard -
\r/\nin header names or values throwsRiftexHeaderInjectionError(500, codeHEADER_INJECTION). ctx.json()safety - circular refs,BigInt, and unserializable values throwRiftexUnserializableError(500, codeUNSERIALIZABLE_RESPONSE) instead of bubbling a genericJSON.stringifyTypeError.safeJsonStringifyhelper exported for lenient mode.
Tooling:
- CLI scaffolder -
riftex new <name> [--bun|--minimal]. - ADR docs covering load-bearing decisions (radix-trie router, lazy composition with dirty bit, return-value reflection, context pool, compat shim scope).
Known issues
- Compat shim long-tail beyond the known-broken list - middleware that own
res.endoutside the four detected ones (multer,express-session,compression,body-parser) silently misbehave. Workaround: use the native equivalents listed above. See Express compatibility shim. - No
ctx.query.parse(schema)yet - only body validation has the schema affordance. See Schema validation. ExtractParamsdoesn't narrow constrained params -:id(\\d+)staysstring. The router doesn't yet honor inline constraints at runtime; types and runtime have to land together.- Static middleware doesn't honor
If-Modified-Since- onlyIf-None-Match. See Static files.
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.
Deferred to next session
- Native rate-limit, session, and idempotency Redis stores.
- Plugin scoping (Fastify-style sub-app affinity) - today plugin hooks/decorators apply app-wide.
- Standard Schema integration - first-class support so
ctx.body.json(schema)accepts TypeBox / Valibot / ArkType natively, not just the{ parse(input): T }duck-type that already covers Zod. - Native multipart / file upload (
ctx.body.multipart()) somulter-shaped use cases stop needing a hand-rolled parser. - Full benchmark matrix on CI - pinned versions, isolated CPU pinning, Bun in the same matrix, multi-payload scenarios, RSS tracking.
Open questions
- Lazy compose dirty-bit cost under heavy mutation. Apps that register routes per-request will recompose on every request. Cap it, warn after N recomposes per minute, or expose a
freeze()toggle for production? - Compat shim long-tail strategy. Aim for "covers the top 20 middleware on npm" with documented gaps, or stay minimal and route everyone to native ports?
- Standard Schema vs
{ parse }duck-type. Promote the schema arg toStandardSchemaV1(more ergonomic) or keep it duck-typed (keeps the core dep-free)?
Where to next?
- Production hardening - what's shippable today.
- Express compatibility shim - the long-tail status.
- Schema validation - current validator support.
- Introduction - back to the top.