npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@nifrajs/middleware

v3.1.0

Published

Composable middleware for nifra - auth, CSRF, JWT/JWKS, IP restriction, CORS, body limits, response cache, timing, and operational helpers.

Readme

@nifrajs/middleware

Composable, dependency-light middleware for nifra - CORS, security headers, body limits, auth, CSRF, JWT/JWKS, IP restriction, response caching, timing, and ops helpers - applied with app.use().

bun add @nifrajs/middleware
import { server } from "@nifrajs/core/server"
import {
  bodyLimit,
  cors,
  MemoryStore,
  problemDetails,
  rateLimit,
  securityHeaders,
  timing,
} from "@nifrajs/middleware"

const app = server()
  .use(securityHeaders())
  .use(problemDetails())
  .use(cors({ origin: ["https://app.example.com"], credentials: true }))
  .use(bodyLimit({ maxBytes: 1_000_000 }))
  .use(rateLimit({
    store: new MemoryStore(),
    max: 100,
    windowMs: 60_000,
    key: (req) => req.headers.get("x-user-id") ?? "anonymous",
  }))
  .use(timing())
  .get("/", () => ({ ok: true }))
  • bodyLimit({ maxBytes }) - fail-closed Content-Length gate before routing. Lengthless bodies are rejected with 411 by default; use route-level c.boundedBody() / schema validation for intentionally streamed endpoints.
  • basicAuth(options) - Basic Auth plugin with constant-time static credential comparison or a custom verifier.
  • bearer(options) / apiKey(options) - token auth plugins with typed principals.
  • csrf({ secret }) - signed double-submit CSRF protection plus Origin/Referer checking.
  • jwt(options) + verifyJwt() / tryVerifyJwt() + jwk() / jwks() - JWT auth with explicit algorithm allowlists, required expiration by default, issuer/audience checks, direct JWK, HTTPS JWKS, and an additive no-throw Result helper for manual verification.
  • ipRestriction(options) - allow/deny IPv4/IPv6 exact and CIDR matches. Fails closed unless you provide clientIp, trusted proxy extraction, or a trusted single-IP header.
  • cors(options) - preflight handling + headers on every response (errors and 404s included). Origin as "*" / exact / list / predicate. Throws if credentials: true is paired with origin: "*" (the browser rejects it).
  • securityHeaders(options) - X-Content-Type-Options, X-Frame-Options, Referrer-Policy by default; opt-in HSTS and CSP. Every value is fixed, so they are declared (see below) rather than written by a hook - the app keeps its fused/native lanes.
  • rateLimit(options) - 429 + Retry-After + RateLimit-* headers, with a pluggable RateLimitStore. Configure a trusted key, trusted single-IP header, or trustedProxies; a missing key source fails closed instead of silently sharing one bucket. The bundled MemoryStore refuses to run in production (a per-instance limiter is unsafe across instances) - provide a shared store (Redis, etc.) there.
  • cache({ store, ttlMs }) / responseCache(...) - full response cache with a pluggable store, Vary-aware keys, Age, byte caps, and Cache-Control / Set-Cookie safety defaults. MemoryResponseCache is dev/single-instance only unless explicitly allowed in production.
  • timing() - Server-Timing plus typed c.timing.metric/mark/measure controls.
  • problemDetails() - opt-in RFC 9457 application/problem+json responses for framework errors. The default { ok: false, error } envelope remains unchanged unless installed; validation issues are preserved, and includeInstance includes only the request pathname.
  • rangeResponse() / parseByteRange() - bounded byte-range responses with 206/416, If-Range, multipart ranges, and conditional validators.
  • conditionalResponse() - reusable ETag/Last-Modified handling that emits a bodyless 304.
  • negotiateContentType() - RFC-style Accept matching with q-values, wildcards, and q=0.
  • multipartResponse() - cancellable streaming multipart output without buffering all parts.
  • prettyJson() - capped, JSON-only pretty printing for debugging and developer-facing APIs.
  • methodOverride() - header/query method tunneling for clients that can only send POST. Header override is on by default; query override is opt-in.
  • trimTrailingSlash() / appendTrailingSlash() - redirect or rewrite URL canonicalization.
  • poweredBy() - opt-in product/framework header; Nifra emits no powered-by header by default.
  • language() / pickLanguage() - Accept-Language negotiation with typed c.language.
  • combine() / namedCombine() - reusable runtime bundles for middleware/plugins.
  • requestId() / logger() / etag() / compression() / cacheControl() / idempotency() / healthcheck() / openapi() - additional operational middleware for APIs.

Header middleware: declared headers and onResponseHeaders

A bundle whose headers are FIXED at construction should declare them (responseHeaders) rather than write them from a hook: declared headers register no hook at all, so they fold into response construction and the app keeps the fused/native lanes a response hook closes (measured +11% on a bare Bun GET, byte-identical on the wire). They are defaults - anything the request produced wins. securityHeaders and the default poweredBy ship this way.

A middleware whose response hook only reads/writes headers but needs the request should use the portable onResponseHeaders hook - enable the observer surface with app.use(responseObserver()) from @nifrajs/core/response-observer before registering a custom hook. It remains one implementation, fast on every runtime: it mutates the response's own Headers on Bun/Deno and the outcome record on Node's direct socket writer, never materializing Web Request/Response objects. cors (origin reflection), static cacheControl, language, and poweredBy({ respectExisting: false }) are built on it. Stateful middleware (rateLimit with the built-in key derivation, logger) pairs full native twins (onNodeRequest/onNodeResponse) instead. Body-transforming middleware has its own portable tier, onResponseBody - the hook receives the final framework-serialized bytes on every runtime with no stream drained (raw handler Responses are skipped by contract); full-response capture and stream wrapping keep the onResponse contract. timing stays Web-only for now. See the plugins guide for the contracts.

Request timeouts are configured at the core server boundary so they can abort c.signal and race the whole lifecycle:

const app = server({ requestTimeoutMs: 5_000 })

@nifrajs/core is a peer dependency. ESM-only. MIT.

For AI agents

Start with LLM.md - this package's contract card (the exports you call + its footguns), one cheap read instead of the whole corpus. For the wider framework: the repo's AGENTS.md is the copy-paste quick reference, and llms-full.txt is the full machine-readable corpus. Run nifra check as the done-gate, or nifra mcp to give the agent live project tools.