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

velora-express

v1.2.0

Published

Fast Express utilities and a reliability HTTP client with HTTP/3 transport support, caching, retries, observability, and resilient APIs.

Readme

velora-express

Fast, dependency-light Express utilities for production APIs. velora-express gives you the pieces most teams keep rebuilding: async route handling, RFC problem details, request context, validation adapters, security headers, in-memory cache, ETags, idempotency, rate limits, deadlines, circuit breakers, metrics, safe JSON, stable hashing, and response helpers.

Runtime dependencies: zero. Express is a peer dependency.

Version 1.1.0 also includes an AM92-style compatibility layer: CustomError, ResponseBody, configureApp, configureRouter, asyncWrapper, httpContext, apiLogging, extractHeaders, routeSanity, handleResponse, handleError, decryptCryptoKey, decryptPayload, and encryptPayload.

Install

npm install velora-express express

Quick Start

import express from 'express';
import {
  asyncHandler,
  problemDetails,
  requestContext,
  securityHeaders,
  smartJson
} from 'velora-express';

const app = express();

app.use(express.json());
app.use(requestContext());
app.use(securityHeaders());
app.use(smartJson());

app.get('/health', asyncHandler(async (_req, res) => {
  res.ok({ status: 'up' });
}));

app.use(problemDetails());
app.listen(3000);

What Is Included

| Feature | Export | Purpose | | --- | --- | --- | | Async routes | asyncHandler | Catches rejected promises and forwards them to Express error handling. | | Typed API errors | ApiError | Adds status, code, exposed details, headers, and RFC problem conversion. | | Problem details | problemDetails, makeProblem | Sends application/problem+json compatible errors. | | Request context | requestContext, getRequestContext, contextValue | Per-request storage powered by AsyncLocalStorage. | | Validation | validate, validateRequest | Works with Zod-like safeParse, parser objects, or plain functions. | | Security headers | securityHeaders | Applies strict default browser security headers. | | Rate limits | rateLimit, createMemoryRateLimitStore | Fast fixed-window limiter with pluggable storage. | | Idempotency | idempotency | Replays successful mutation responses by idempotency key. | | HTTP cache | httpCache, LruTtlStore | In-memory GET/HEAD response cache with TTL and LRU eviction. | | ETags | etag | Generates weak or strong ETags and handles If-None-Match. | | Deadlines | deadline, withTimeout | Fails slow HTTP or internal async work with timeout errors. | | Resilience | createCircuitBreaker | Opens after repeated failures and recovers after a reset window. | | Route builder | createRoute | Composes validation, rate limits, cache, and async handling. | | Response helpers | smartJson | Adds res.ok, res.created, res.accepted, res.noContent, and res.problem. | | Metrics | metrics | Emits request timing, status, route, and request id to your sink. | | Utilities | safeJson, stableHash, constantTimeEqual, clientIp | Production-safe primitives for logs, signatures, and networking. | | Reliability HTTP client | createHttpClient, createHttp3Transport | Retries, queueing, cache, dedupe, failover, hooks, metrics, and HTTP/3 adapter support. |

AM92-Style Stable Response Flow

Use this when you want every route to return the same envelope shape:

import express from 'express';
import {
  ResponseBody,
  CustomError,
  configureRouter,
  configureApp
} from 'velora-express';

const app = express();
const router = express.Router();

configureRouter(router, {
  routerName: 'users',
  enabled: true,
  disableCrypto: true,
  routesConfig: {
    listUsers: {
      method: 'get',
      path: '/users',
      enabled: true,
      cache: { ttlMs: 10_000 },
      pipeline: [
        async (_req, res) => {
          res.body = new ResponseBody(200, 'Success', [{ id: 1 }]);
        }
      ]
    },
    createUser: {
      method: 'post',
      path: '/users',
      enabled: true,
      pipeline: [
        async (req, res) => {
          if (!req.body.email) {
            throw new CustomError(new Error('Email required'), {
              statusCode: 422,
              errorCode: 'USER_EMAIL_REQUIRED'
            });
          }

          res.body = new ResponseBody(201, 'Created', { id: 1 });
        }
      ]
    }
  }
});

configureApp(app, [{ path: '/api', router }]);

All responses keep this structure:

{
  "statusCode": 200,
  "status": "OK",
  "message": "Success",
  "data": {},
  "error": null,
  "errorCode": null
}

Errors use the same structure, so clients do not need a separate parser for failures.

AM92-Compatible Exports

  • ResponseBody: stable response envelope.
  • CustomError: app error wrapper with statusCode, errorCode, data, and original error.
  • configureApp: installs request context, header extraction, security, logging, default routes, final response handling, and error handling.
  • configureRouter: builds routes from config with pre, main, post, crypto, cache, rate-limit, and validation pipelines.
  • asyncWrapper / asyncHandler: forwards async errors to Express.
  • httpContext: request-scoped storage with helpers for request id, session id, client id, and encryption keys.
  • apiLogging and logManager: structured request/response logging with body redaction and body-log opt out.
  • extractHeaders: stores lowercase request headers and generates missing request/session ids.
  • routeSanity: marks matched routes so unmatched routes return a stable 404 envelope.
  • handleResponse: sends ResponseBody or redirects for 3xx bodies.
  • handleError: wraps all errors into CustomError and returns a stable ResponseBody.
  • decryptCryptoKey, decryptPayload, encryptPayload: optional crypto hooks with pluggable crypto providers.

Reliability HTTP Client

velora-express also ships a backend HTTP client for resilient service-to-service calls:

import {
  createHttpClient,
  createHttp3Transport,
  pluginLogger,
  pluginRetry
} from 'velora-express';

const api = createHttpClient({
  baseURL: ['https://primary.example.com', 'https://backup.example.com'],
  timeout: 5000,
  retry: {
    attempts: 3,
    delay: 250,
    strategy: 'exponential',
    jitter: true
  },
  queue: { concurrency: 5 },
  rateLimit: { requests: 100, per: 60_000 },
  cache: { ttl: '5m' },
  circuitBreaker: { failureThreshold: 5, resetAfterMs: 30_000 },
  token: process.env.API_TOKEN,
  plugins: [
    pluginRetry({ attempts: 3 }),
    pluginLogger(console)
  ]
});

const users = await api.get('/users', {
  priority: 'high',
  dedupe: true,
  fallback: []
});

console.log(users.data, users.meta);

Included client features:

  • intelligent retries with linear, exponential, random, fibonacci, jitter, and Retry-After support
  • timeout and AbortController
  • request queue with priority
  • client-side rate limiting
  • in-memory LRU/TTL cache
  • in-flight request deduplication
  • failover base URLs
  • circuit breaker and fallback responses
  • bearer token, API key, basic auth, idempotency key generation
  • request/response hooks and plugin system
  • batch requests and pagination helper
  • response validation
  • production diagnostics metadata: duration, retries, cache status, HTTP version, response size, request id, trace id, attempts
  • metrics snapshot with totals, retries, cache hit/miss, p50, p95, and p99

HTTP/3 Support

Node.js does not currently expose a stable built-in HTTP/3 client API. Velora supports HTTP/3 through an adapter so you can plug in a native QUIC binding, infrastructure SDK, or future Node transport without changing your application code.

const http3Transport = createHttp3Transport(async (request) => {
  // Use your HTTP/3 implementation here.
  // Return either a fetch-like Response or { status, headers, data, url }.
  return myHttp3Client.request({
    url: request.url,
    method: request.method,
    headers: Object.fromEntries(request.headers),
    body: request.body,
    signal: request.signal
  });
});

const api = createHttpClient({
  baseURL: 'https://api.example.com',
  httpVersion: '3',
  http3Transport
});

await api.get('/users');

Strict HTTP/3 mode:

const api = createHttpClient({
  baseURL: 'https://api.example.com',
  httpVersion: '3',
  allowHttp3Fallback: false,
  http3Transport
});

If httpVersion: '3' is requested without a transport, Velora falls back to fetch by default. Set allowHttp3Fallback: false to throw a rich HttpClientError instead.

Middleware Order

Recommended order:

app.use(express.json());
app.use(requestContext());
app.use(securityHeaders());
app.use(metrics({ sink: console.log }));
app.use(smartJson());

// routes

app.use(problemDetails());

problemDetails() should be registered after routes because it is an Express error middleware.

Validation

validateRequest() intentionally supports multiple validator styles instead of locking you into one dependency.

const createUser = {
  safeParse(value) {
    if (typeof value.email === 'string') return { success: true, data: value };
    return { success: false, error: { issues: [{ path: ['email'], message: 'Required' }] } };
  }
};

app.post('/users', validateRequest({ body: createUser }), asyncHandler(async (req, res) => {
  res.created({ user: req.body });
}));

Rate Limiting

app.use('/api', rateLimit({
  windowMs: 60_000,
  limit: 120,
  key: (req) => req.user?.id || req.ip
}));

For distributed systems, pass a custom store implementing hit(key).

Route-Level Response Caching

configureRouter() supports cache config per route:

configureRouter(router, {
  enabled: true,
  disableCrypto: true,
  routesConfig: {
    catalog: {
      method: 'get',
      path: '/catalog',
      enabled: true,
      cache: {
        ttlMs: 30_000,
        key: (req) => `catalog:${req.headers['accept-language'] || 'en'}`
      },
      pipeline: [
        async (_req, res) => {
          res.body = new ResponseBody(200, 'Success', await loadCatalog());
        }
      ]
    }
  }
});

For lower-level Express handlers, use responseCache() or httpCache(). Both use LruTtlStore by default and accept a custom store.

Optional Payload Crypto

Velora does not force a crypto dependency. You can provide your own provider:

import { initialize } from 'velora-express';

await initialize({
  validateClient: async (clientId) => Boolean(clientId),
  crypto: {
    async decryptKey(clientId, encryptedKey) {
      return unwrapClientKey(clientId, encryptedKey);
    },
    encryptData(value, key) {
      return encrypt(value, key);
    },
    decryptData(payload, key) {
      return decrypt(payload, key);
    }
  }
});

If no provider is supplied, createPayloadCrypto() gives you a small AES-256-GCM helper suitable for internal services and tests.

Idempotency

app.post('/payments', idempotency(), asyncHandler(async (_req, res) => {
  res.created({ paymentId: 'pay_123' });
}));

Clients send:

Idempotency-Key: unique-client-token

Successful POST, PATCH, and PUT responses are cached and replayed with idempotency-replayed: true.

Caching And ETags

app.get('/catalog', etag(), httpCache({ ttlMs: 15_000 }), asyncHandler(async (_req, res) => {
  res.json(await loadCatalog());
}));

Use LruTtlStore directly when you need a tiny in-process cache:

const store = new LruTtlStore({ max: 500, ttlMs: 30_000 });
store.set('feature-flags', flags);

Deadlines And Circuit Breakers

const billingBreaker = createCircuitBreaker({ failureThreshold: 3, resetAfterMs: 10_000 });

app.get('/invoice/:id', deadline({ timeoutMs: 2500 }), asyncHandler(async (req, res) => {
  const invoice = await billingBreaker.exec(() =>
    withTimeout(() => billing.getInvoice(req.params.id), 2000)
  );

  res.ok(invoice);
}));

Request Context

app.use(requestContext({ header: 'x-request-id' }));

app.use((req, _res, next) => {
  contextValue('userId', req.user?.id);
  next();
});

logger.info({
  requestId: getRequestContext()?.requestId,
  userId: contextValue('userId')
});

Response Helpers

smartJson() adds helpers without hiding Express:

res.ok(data, meta);       // 200 { ok: true, data, meta }
res.created(data);        // 201
res.accepted(data);       // 202
res.noContent();          // 204
res.problem(409, 'Duplicate email', { code: 'EMAIL_EXISTS' });

TypeScript

The package ships TypeScript declarations. To type the smartJson() response helpers globally, add this in your app:

declare global {
  namespace Express {
    interface Response {
      ok(data: unknown, meta?: unknown): this;
      created(data: unknown, meta?: unknown): this;
      accepted(data: unknown, meta?: unknown): this;
      noContent(): this;
      problem(status: number, title: string, extras?: unknown): this;
    }
  }
}

Performance Notes

  • No required runtime dependencies.
  • Middleware is allocation-conscious and avoids global mutation.
  • Caches use Map insertion order for O(1) LRU-style eviction.
  • Request context uses Node's native AsyncLocalStorage.
  • Hashing and constant-time comparison use Node core crypto primitives.
  • Logging redacts sensitive keys by default.
  • Route configuration composes only the middleware a route enables.

Publishing Checklist

npm test
npm run build
npm pack --dry-run
npm publish --access public

You must be logged in with npm login before publishing.

License

MIT