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

plug-api-gateway

v0.1.0

Published

A configuration-first, production-ready API gateway for Node.js

Readme

plug-api-gateway

A plug-and-play Node.js gateway built around validated YAML configuration. Install it as a CLI product or embed it in a Fastify application. It provides versioned streaming proxy routes, OIDC/JWKS authentication, Redis-backed distributed rate limits, health probes, and structured operational logs.

Install and start

Requires Node.js 22 or newer and Redis.

npm install plug-api-gateway
npx plug-api-gateway init gateway.yaml
npx plug-api-gateway validate --config gateway.yaml
npx plug-api-gateway start --config gateway.yaml

Edit the generated gateway.yaml to point at your identity provider, Redis, and upstream services. The gateway listens on port 3000 by default.

For a global installation:

npm install --global plug-api-gateway
plug-api-gateway start --config /etc/plug-api-gateway/gateway.yaml

init refuses to replace an existing file unless --force is supplied. GATEWAY_CONFIG_FILE can provide the default file for start and validate.

Embed in Node.js

The package has no import-time network, signal, or process side effects:

import { createGateway } from 'plug-api-gateway';

const gateway = await createGateway({ config: './gateway.yaml' });
await gateway.start();

process.once('SIGTERM', () => {
  void gateway.close();
});

createGateway owns its Redis connection and closes it with the Fastify server. Advanced consumers can inject ApplicationDependencies or use buildApplication directly for custom rate-limit, health, and token-verification integrations. Public TypeScript types and the validated gatewayConfigSchema are exported from the package root.

Develop locally

npm install
cp config/gateway.example.yaml config/gateway.yaml
npm run dev

Set GATEWAY_CONFIG_FILE to load a different YAML file. Configuration values support ${NAME} and ${NAME:-default} interpolation. Startup fails when a required variable is absent or the resulting configuration is invalid.

Versioned routes

Each route declares a version and resource prefix separately:

- id: users
  version: v1
  prefix: /users
  upstream: http://users-service:8080
  allowedMethods: [GET, POST]

This route is exposed at /api/v1/users. Versions use v1, v2, and so on. Prefixes are normalized by validation: they begin with /, have no trailing or repeated slash, and reject traversal and encoded separator forms. Duplicate route IDs and duplicate versioned prefixes are rejected at startup. Nested prefixes are allowed; lookup chooses the longest match on a complete path-segment boundary.

Deprecated routes may declare deprecatedAt, sunsetAt, and successorUrl. The gateway then emits Deprecation, Sunset, and Link: <...>; rel="successor-version" headers. Both dates use ISO 8601 in YAML, sunset must follow deprecation, and all three values are required together.

The current runnable endpoints are:

  • GET /health/live
  • GET /health/ready

Proxy behavior

Matched requests are streamed to their configured upstream with query strings intact. stripPrefix defaults to true, so /api/v1/users/42 reaches the upstream as /42; set it to false to preserve the complete public path. allowedMethods is enforced before forwarding.

server.upstreamTimeoutMs sets the default upstream timeout and timeoutMs overrides it for one route. server.bodyLimitBytes caps request bodies. The gateway removes hop-by-hop headers, replaces forwarding headers using Fastify's trusted-proxy interpretation, and propagates or generates X-Request-ID. Only enable trustProxy for known proxy addresses or CIDR ranges.

Errors use one shape:

{"code":"ROUTE_NOT_FOUND","message":"No route matches this request","requestId":"req-1"}

Routing failures return 404 or 405, oversized bodies return 413, upstream connection failures return 502, and upstream timeouts return 504.

Authentication and scopes

OIDC configuration pins the issuer, one or more accepted audiences, the JWKS URL, and an explicit asymmetric algorithm allowlist. Symmetric HS* algorithms and unsecured tokens are rejected by configuration. Remote keys are cached by jose and refreshed when signing keys rotate.

Routes choose one authorization mode:

  • public accepts requests without a token.
  • authenticated requires a valid bearer JWT.
  • scoped also requires every entry in requiredScopes.

Bearer syntax is strict. Verification covers signature, key/algorithm compatibility, issuer, audience, expiration, and not-before claims. Configure scopeRepresentation as space-delimited-string for claims such as "users:read users:write", or string-array for claims such as ["users:read", "users:write"]. A mismatched claim type is denied rather than coerced.

Authentication failures return 401 with WWW-Authenticate; valid tokens lacking scopes return 403. Responses and logs do not expose token validation details.

Rate limits and health

Redis provides a distributed fixed-window counter. The global rateLimit policy applies unless a route supplies an override. Keys combine route ID with authenticated sub, falling back to Fastify's trusted client IP when no subject exists. Responses include X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset; rejected requests also include Retry-After.

Rate limiting fails closed with 503 if Redis cannot check a counter. Redis availability does not prevent process startup: /health/live remains 200, while /health/ready returns 503 until Redis responds and automatically recovers to 200 afterward.

Logs are Pino JSON at logging.level. Authorization, cookies, proxy authorization, set-cookie, and configured sensitive headers are redacted. Request summaries include request ID, route ID, method, status, latency, and authenticated subject. SIGTERM and SIGINT stop new traffic, drain Fastify requests, then close Redis.

Docker demo

The Compose environment builds the production image and starts Redis, a local JWKS/token fixture, mock upstream endpoints, and the gateway:

docker compose up --build --wait --detach
sh tools/compose-smoke.sh
docker compose down --volumes

The smoke test checks liveness, readiness, public versioned proxying, a scoped request with a freshly signed demo token, rate limiting, and graceful gateway stop. The fixture key and tokens are ephemeral and only suitable for local demonstrations.

The smoke script prefers the docker compose plugin and falls back to the standalone docker-compose command. Set COMPOSE_COMMAND to exactly docker compose or docker-compose to select one explicitly. On older installations, substitute docker-compose for each Compose command shown above.

If host port 3000 is occupied, choose another host port while keeping the container port unchanged, then point the smoke script at it:

GATEWAY_PORT=3100 docker-compose up --build --detach
GATEWAY_URL=http://localhost:3100 COMPOSE_COMMAND=docker-compose sh tools/compose-smoke.sh

Operations and security

  • Terminate TLS at a trusted ingress and configure trustProxy only for known addresses or CIDR ranges.
  • Keep upstream targets and the JWKS URI under deployment control; clients cannot choose proxy destinations.
  • Use rediss:// and authenticated Redis in production. A Redis outage makes readiness fail and proxy requests fail closed.
  • Monitor readiness, 5xx responses, rate-limit rejections, upstream latency, and JWKS retrieval failures.
  • Roll out successor API versions before publishing deprecation and sunset dates.
  • The container runs as the unprivileged node user and exposes only port 3000.

Quality checks

npm run check
npm run pack:check

These run ESLint, Vitest, the strict TypeScript build, and an npm package-content preview. Before publishing, run npm pack, install the generated tarball into a clean temporary project, and verify the CLI there.

Publish a release

The working package name is plug-api-gateway; it was unregistered when selected, but npm availability must be checked again immediately before the first release. Complete the repository, author, support, and homepage fields once permanent project URLs exist.

npm login
npm view plug-api-gateway
npm run check
npm run pack:check
npm publish --provenance

Publishing requires an npm account with two-factor authentication. prepublishOnly runs the complete quality suite automatically. Use semantic versions and publish from a clean, tagged Git commit once the repository is established.

Container validation, when Docker is available:

docker compose config --quiet
docker compose build
docker compose up --wait --detach
sh tools/compose-smoke.sh
docker compose down --volumes

A CI system should run those commands after npm ci and npm run check. No workflow is included because this workspace is not currently a Git repository and its eventual repository root is unknown.

docker-compose config --quiet, image build, and the full runtime smoke test have been verified in the current workspace. The runtime check used GATEWAY_PORT=3100 with GATEWAY_URL=http://localhost:3100 and covered liveness, readiness, public versioned proxying, scoped JWT access, Redis rate limiting, graceful gateway stop, and volume cleanup.

Design direction

Configuration loading, token verification, route lookup, rate limiting, and dependency health use narrow interfaces. Comments are reserved for security rules or intent that names and types cannot express.