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 🙏

© 2025 – Pkg Stats / Ryan Hefner

safetygate

v1.0.1

Published

A lightweight, high-performance rate limiting proxy that protects your APIs from abuse and overload

Readme

SafetyGate

A lightweight, high-performance rate limiting proxy that protects your APIs from abuse and overload.

SafetyGate sits between your clients and API server, automatically blocking excessive requests while allowing legitimate traffic through. No code changes required in your existing application.

✨ Features

  • 🛡️ Rate Limiting - Multiple algorithms: Token Bucket, Sliding Window, Fixed Window
  • ⚡ Zero-Config Setup - Works out of the box with smart defaults
  • 🔧 Highly Configurable - Customize limits per route, client, or globally
  • 📊 Real-time Metrics - Monitor rate limiting effectiveness
  • 🚀 Production Ready - Health checks, logging, and monitoring included
  • 💾 Scalable Storage - In-memory or Redis for distributed setups

🚀 Quick Start

Installation

npm install -g safetygate

Setup in Your Project

cd my-api-project
safetygate init
npm run start:safe

That's it! Your API is now protected.

📖 How It Works

Before: Client → Your API (port 3000)
After:  Client → SafetyGate (port 4000) → Your API (port 3000)

SafetyGate acts as a protective gateway:

  1. Receives all client requests
  2. Checks rate limits per IP/user
  3. Forwards allowed requests to your API
  4. Blocks excessive requests with 429 status

🛠️ Usage

Method 1: Automatic Setup (Recommended)

# In your existing project
safetygate init

# Starts both SafetyGate + your server
npm run start:safe

Method 2: Manual Configuration

# Start SafetyGate manually
safetygate start --target http://localhost:3000 --port 4000 --rate 100

# Or with config file
safetygate start --config ./safetygate.config.json

Method 3: Docker

docker run -d -p 4000:4000 \
  -e TARGET_URL=http://host.docker.internal:3000 \
  -e RATE_LIMIT=100 \
  safetygate/safetygate

⚙️ Configuration

SafetyGate auto-generates safetygate.config.json:

{
  "port": 4000,
  "target": "http://localhost:3000",
  "rateLimiting": {
    "enabled": true,
    "windowMs": 60000,
    "maxRequests": 60,
    "algorithm": "token-bucket",
    "storage": "memory"
  }
}

🧠 Rate Limiting Algorithms

SafetyGate offers three proven rate limiting algorithms. Choose based on your API's needs:

🪣 Token Bucket (Default - Recommended)

How it works: Like a bucket that holds tokens. Each request consumes a token. Tokens refill at a steady rate.

Perfect for:

  • APIs that can handle traffic bursts
  • Mobile apps (handles network reconnections)
  • APIs with variable request patterns

Example: 60 requests/minute

  • Start with 60 tokens
  • Each request = -1 token
  • Refill +1 token every second
  • Can burst 60 requests immediately, then 1/second
{
  "algorithm": "token-bucket",
  "maxRequests": 60,
  "windowMs": 60000
}

✅ Pros: Flexible, handles bursts naturally, smooth experience ❌ Cons: Slightly more memory usage


🪟 Sliding Window (Most Accurate)

How it works: Tracks exact timestamp of each request. Counts requests in a rolling time window.

Perfect for:

  • Strict rate enforcement needed
  • Billing/payment APIs
  • APIs where precision matters

Example: 60 requests/minute

  • Tracks last 60 seconds exactly
  • If 60 requests in any 60-second period → block
  • Very precise, no "edge case" bursts
{
  "algorithm": "sliding-window", 
  "maxRequests": 60,
  "windowMs": 60000
}

✅ Pros: Most accurate, fair distribution ❌ Cons: Higher memory usage, slightly slower


⏰ Fixed Window (Simplest)

How it works: Resets counter every fixed period (e.g., every minute at :00 seconds).

Perfect for:

  • Simple use cases
  • Memory-constrained environments
  • APIs with predictable traffic

Example: 60 requests/minute

  • 12:00:00 - 12:00:59 → 60 requests allowed
  • 12:01:00 → Counter resets to 0
  • Can get 120 requests at boundary (60 at 12:00:59, 60 at 12:01:00)
{
  "algorithm": "fixed-window",
  "maxRequests": 60, 
  "windowMs": 60000
}

✅ Pros: Lowest memory, fastest, simple ❌ Cons: "Boundary burst" possible


🎯 Algorithm Comparison

| Aspect | Token Bucket | Sliding Window | Fixed Window | |--------|--------------|----------------|--------------| | Accuracy | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | | Performance | ⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | | Memory Usage | ⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | | Burst Handling | ⭐⭐⭐⭐⭐ | ⭐⭐ | ⭐⭐ | | Fairness | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ |

🔧 Algorithm Selection Guide

Choose Token Bucket if:

  • ✅ Your API can handle traffic bursts
  • ✅ You want smooth user experience
  • ✅ Mobile/web apps (network reconnections)
  • ✅ General purpose APIs

Choose Sliding Window if:

  • ✅ You need precise rate limiting
  • ✅ Billing/payment/critical APIs
  • ✅ Strict compliance requirements
  • ✅ Absolute fairness is important

Choose Fixed Window if:

  • ✅ Simple rate limiting is enough
  • ✅ Memory is very limited
  • ✅ High performance is critical
  • ✅ Boundary bursts are acceptable

📊 Real-World Examples

E-commerce API

{
  "algorithm": "token-bucket",
  "routes": [
    { "path": "/api/products", "maxRequests": 200 },
    { "path": "/api/checkout", "maxRequests": 10 },
    { "path": "/api/search", "maxRequests": 100 }
  ]
}

Payment API

{
  "algorithm": "sliding-window",
  "maxRequests": 5,
  "windowMs": 60000
}

Public API

{
  "algorithm": "fixed-window", 
  "maxRequests": 1000,
  "windowMs": 3600000
}

Advanced Configuration

{
  "port": 4000,
  "target": "http://localhost:3000",
  "rateLimiting": {
    "enabled": true,
    "windowMs": 60000,
    "maxRequests": 100,
    "algorithm": "token-bucket",
    "storage": "redis",
    "redis": {
      "host": "localhost",
      "port": 6379
    },
    "routes": [
      {
        "path": "/api/public/*",
        "maxRequests": 200,
        "windowMs": 60000
      },
      {
        "path": "/api/private/*",
        "maxRequests": 20,
        "windowMs": 60000
      }
    ]
  }
}

📡 API Endpoints

Once running, SafetyGate provides:

  • GET /health - Health check endpoint
  • GET /metrics - Rate limiting statistics
  • * - All other requests are proxied to your API

Rate Limit Headers

SafetyGate adds standard headers to all responses:

X-RateLimit-Limit: 60
X-RateLimit-Remaining: 45
X-RateLimit-Reset: 1640995200
Retry-After: 30

📊 Monitoring

View Metrics

curl http://localhost:4000/metrics
{
  "totalRequests": 1250,
  "blockedRequests": 45,
  "allowedRequests": 1205,
  "successRate": "96.4%"
}

Health Check

curl http://localhost:4000/health

🔧 CLI Commands

# Initialize in project
safetygate init [options]

# Start proxy server
safetygate start [options]

# View configuration
safetygate config

# Show help
safetygate --help

CLI Options

safetygate init
  --port <port>         Proxy port (default: auto-detect)
  --target <url>        Target server URL
  --rate <number>       Requests per minute (default: 60)
  --force              Overwrite existing config

safetygate start
  --config <path>       Config file path
  --target <url>        Target server URL
  --port <port>         Proxy port
  --rate <number>       Rate limit
  --daemon             Run in background

🐳 Docker Deployment

Docker Compose

version: '3.8'
services:
  api:
    build: .
    ports:
      - "3000:3000"
  
  safetygate:
    image: safetygate/safetygate
    ports:
      - "4000:4000"
    environment:
      TARGET_URL: http://api:3000
      RATE_LIMIT: 100
    depends_on:
      - api

Kubernetes

apiVersion: apps/v1
kind: Deployment
metadata:
  name: safetygate
spec:
  replicas: 3
  selector:
    matchLabels:
      app: safetygate
  template:
    spec:
      containers:
      - name: safetygate
        image: safetygate/safetygate
        env:
        - name: TARGET_URL
          value: "http://api-service:3000"
        - name: REDIS_HOST
          value: "redis-service"

🚀 Production Setup

With PM2

pm2 start safetygate -- start --config production.json
pm2 startup
pm2 save

With SystemD

sudo safetygate install
sudo systemctl enable safetygate
sudo systemctl start safetygate

Behind Load Balancer

Internet → Load Balancer → SafetyGate Cluster → API Servers
                              ↓
                          Redis Cluster

🧪 Testing

Test rate limiting with curl:

# Single request
curl http://localhost:4000/

# Burst test (will trigger rate limit)
for i in {1..70}; do curl http://localhost:4000/; done

# Check headers
curl -I http://localhost:4000/

🤝 Integration Examples

Express.js

// No changes needed in your Express app!
app.listen(3000, () => {
  console.log('API running on port 3000');
});

// SafetyGate runs separately on port 4000
// Clients connect to 4000, SafetyGate forwards to 3000

Next.js

{
  "scripts": {
    "dev": "concurrently \"next dev\" \"safetygate start\"",
    "start": "next start",
    "start:safe": "safetygate start & npm start"
  }
}

🔒 Security Features

  • DDoS Protection - Automatic request limiting
  • IP-based Limiting - Track clients by IP address
  • Custom Headers - Rate limit by API key or JWT
  • Route-specific Limits - Different limits per endpoint
  • Redis Support - Distributed rate limiting across servers

📈 Performance

  • < 1ms latency overhead per request
  • 10,000+ concurrent connections supported
  • < 50MB memory footprint
  • 99.99% uptime capability

🔗 Environment Variables

SAFETYGATE_PORT=4000
SAFETYGATE_TARGET=http://localhost:3000
SAFETYGATE_RATE_LIMIT=100
SAFETYGATE_REDIS_HOST=localhost
SAFETYGATE_LOG_LEVEL=info

📚 Comparison

| Solution | Setup Time | Rate Limiting | Memory Usage | Flexibility | |----------|------------|---------------|--------------|-------------| | SafetyGate | 30 seconds | Advanced | Low | High | | nginx | 30 minutes | Basic | Medium | Medium | | HAProxy | 45 minutes | Basic | Low | Low | | Traefik | 15 minutes | Plugin | Medium | Medium |

🆘 Troubleshooting

Common Issues

Port already in use:

lsof -i :4000  # Check what's using the port
safetygate init --port 5000  # Use different port

Rate limiting not working:

safetygate config  # Check configuration
curl localhost:4000/metrics  # Check if proxy is running

Can't reach target server:

curl localhost:3000  # Test direct connection
safetygate start --target http://localhost:8080  # Use correct port

📄 License

MIT - see LICENSE file.

🤝 Contributing

  1. Fork the repository
  2. Create your feature branch
  3. Commit your changes
  4. Push to the branch
  5. Create a Pull Request

🔗 Links


⭐ Star this repo if SafetyGate helps protect your APIs!