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

@andy-toolforge/llm-gateway

v0.1.1

Published

LLM API gateway — multi-provider routing, failover, rate limiting, key rotation, cost tracking, caching

Readme

@andy-toolforge/llm-gateway

npm License

LLM API Gateway — multi-provider routing, failover, rate limiting, auth, caching, circuit breaker, key rotation, cost tracking. Pipeline-of-Stages architecture.

Request → [Auth → RateLimit → Cache → Router → Fallback → CircuitBreaker → Provider → CostLogger] → Response

Installation

npm install @andy-toolforge/llm-gateway

Quick Start

const { createGateway } = require('@andy-toolforge/llm-gateway');

const gw = createGateway({
  apiKey: 'sk-your-key',
  keys: { 'sk-your-key': { tenant: 'my-app' } },
  models: {
    'gemini-pro': { provider: 'gemini', adapter: 'GenAIAdapter' },
    'gpt-4': { provider: 'openai', adapter: 'OpenAIAdapter' },
  },
});

// Sync
const result = await gw.chat({
  model: 'gemini-pro',
  messages: [{ role: 'user', content: 'Hello!' }],
});
console.log(result.content);

// Streaming
for await (const chunk of gw.chatStream({
  model: 'gemini-pro',
  messages: [{ role: 'user', content: 'Tell me a story' }],
})) {
  process.stdout.write(chunk.content);
}

Features

| Feature | Stage | Config | |---------|-------|--------| | API Key Auth | AuthStage | keys: { 'sk-xxx': { tenant } } | | Rate Limiting | RateLimitStage | rateLimits: { tenant: { capacity, refillRate } } | | Response Caching | CacheStage | cache: { ttlMs } | | Model Routing | RouterStage | models: { name: { provider, adapter } } | | Failover | FallbackChain | Defined in model config | | Circuit Breaker | CircuitBreakerStage | circuitBreaker: { threshold, cooldownMs } | | Key Rotation | KeyRotatorStage | keyRotator: { keys: [...], rotationIntervalMs } | | Cost Logging | CostLoggerStage | Automatic per-request cost | | Provider Adapter | ProviderStage | createAdapter(provider, model) factory |

Architecture

Pipeline-of-Stages

Every request flows through a chain of stages, each with a single responsibility. Stage order is fixed:

Request
  │
  ├─ ① AuthStage        — validate API key, extract tenant
  ├─ ② RateLimitStage   — enforce per-tenant token bucket
  ├─ ③ CacheStage       — return cached response if available
  ├─ ④ RouterStage      — resolve model → provider + adapter; activate fallback chain
  ├─ ⑤ FallbackChain    — try primary provider, fall through to alternatives on failure
  ├─ ⑥ CircuitBreakerStage — track failures; open circuit if threshold exceeded
  ├─ ⑦ ProviderStage    — call the LLM provider (sync or streaming)
  └─ ⑧ CostLoggerStage  — log usage + compute cost
  │
Response

Request / Response Object

Each stage transforms a shared request object and/or the response:

Request: { model, messages, stream?, requestId, tenant?, signal? }
Response: { content, usage: { promptTokens, completionTokens, costUsd }, cached? }

Stages before ProviderStage (Auth → Cache) operate on the request object. ProviderStage calls the actual LLM and produces the response. Stages after (CostLogger) decorate the response. The next() call passes control to the next stage; a stage can short-circuit (Cache hit, Circuit open, Rate limited) and return early.

Streaming Path

When request.stream = true, ProviderStage returns an AsyncIterable<{ content, done, usage? }>. CacheStage bypasses caching for streaming requests (unless the entire response is buffered). The HTTP server delivers streaming via SSE (Server-Sent Events).

Gateway Class

The Gateway class assembles the pipeline from config and exposes three methods:

| Method | Description | |--------|-------------| | gateway.chat(req) | Sync completion — returns Response | | gateway.chatStream(req) | Streaming — returns AsyncIterable | | gateway.health() | Pipeline status — returns { status, models, stages } |

HTTP Server

# CLI
npx llm-gateway --port 4000 --api-key sk-admin

# Or programmatically
const { HTTPServer, createGateway } = require('@andy-toolforge/llm-gateway');
const server = new HTTPServer(gateway, { port: 4000 });
await server.start();

Routes

| Method | Path | Description | |--------|------|-------------| | GET | /health | Pipeline status + model list | | GET | /v1/models | Available models | | POST | /v1/chat/completions | Chat completion (OpenAI-compatible) | | POST | /v1/chat/completions | With stream: true → SSE streaming |

Adapters

Create custom adapters for any provider:

const gw = createGateway({
  models: { 'custom-model': { provider: 'custom', adapter: 'MyAdapter' } },
  createAdapter: (provider, model) => {
    if (provider === 'custom') return {
      chat: async (messages, opts) => ({
        content: 'response text',
        usage: { promptTokens: 5, completionTokens: 10, costUsd: 0.0001 },
      }),
    };
  },
});

Configuration Reference

Gateway Options

| Option | Type | Required | Description | |--------|------|----------|-------------| | apiKey | string | yes | Admin API key | | keys | object | yes | { key: { tenant } } — API key → tenant mapping | | models | object | yes | { name: { provider, adapter } } — model definitions | | rateLimits | object | no | { tenant: { capacity, refillRate } } | | cache | object | no | { ttlMs } — cache TTL | | circuitBreaker | object | no | { threshold, cooldownMs, halfOpenMaxRequests } | | keyRotator | object | no | { keys: [...], rotationIntervalMs } | | createAdapter | function | no | Factory (provider, model) => adapter | | costConfig | object | no | { perMillionTokens: { input, output } } |

HTTP Server Options

| Option | Type | Default | Description | |--------|------|---------|-------------| | port | number | 3000 | Listen port (0 = random) | | host | string | 'localhost' | Bind address |

Related