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

@zakhomuth/llm-gateway

v0.2.2

Published

Configurable LLM gateway: paused/dry-run/replay modes, Anthropic/Bedrock/Ollama/OpenAI-compatible providers, response cache, spend ledger and daily USD cap.

Readme

@zakhomuth/llm-gateway

import { createGatewayFromEnv } from '@zakhomuth/llm-gateway';

const gateway = createGatewayFromEnv('APP', process.env);
const result = await gateway.complete({ operation: 'summarize', prompt: 'Summarize this.', maxTokens: 512 });

Environment

| Variable | Meaning | Default | |---|---|---| | <P>_LLM | paused, dry-run, bedrock, anthropic, ollama, or openai-compatible | paused | | <P>_LLM_MODEL | Provider model identifier (required for openai-compatible; bedrock uses <P>_BEDROCK_MODEL_ARN) | claude-sonnet-5-5 (anthropic), llama3 (ollama) | | <P>_BEDROCK_MODEL_ARN | Bedrock inference profile ARN | required for Bedrock | | <P>_LLM_BASE_URL | OpenAI-compatible base URL; Ollama base URL | required for openai-compatible; Ollama default http://localhost:11434 | | <P>_LLM_API_KEY | OpenAI-compatible bearer token; Anthropic key | required for openai-compatible; Anthropic falls back to ANTHROPIC_API_KEY | | <P>_LLM_CACHE | on, off, or replay-only | on | | <P>_LLM_DAILY_USD | Daily USD cap | 10 | | <P>_LLM_PRICE_PER_MTOK | <input>/<output> USD per million tokens, e.g. 3/15; overrides the built-in table | built-in Claude table; ollama, paused and dry-run cost 0 | | <P>_LLM_REFRESH | 1 bypasses cache reads | unset | | <P>_LLM_NO_BATCH | 1 disables batching | unset |

Cache mode on reads and writes entries. off uses a null store. replay-only serves hits and rejects misses. Provider modes select the corresponding adapter; paused rejects calls and dry-run reads operation-named fixtures.

Cross-process ledger adoption

FileInflightLedger markers are readable by any process pointed at the same store root, which makes them cross-process by construction — Gateway adopts an existing marker before opening a new one: a marker with a batchId is handed to the injected adoptBatch(batchId, key) callback (never resubmitted as a new batch); a sync marker whose holder pid is dead is taken over immediately, and a live holder is polled for up to holderWaitMs (default 15 minutes) before giving up and issuing a fresh call. A batch adoption that raises (the batch is stalled past its own polling cap) marks the key direct-only for the remainder of that Gateway instance's completeMany batching decisions, so it never loops into another orphaned batch. InflightLedger is a plain interface, so a DynamoDB-backed implementation can be added later without touching Gateway.

autoTool?: boolean on LlmRequest selects Anthropic's tool_choice: auto for structured (schema) calls instead of the default forced tool choice — some models reject a forced tool_choice. It is folded into the cache key and supported by both the direct Anthropic provider and AnthropicBatchBroker.

images?: LlmAttachment[] supplies image or document attachments. Attachments are placed before the text block of the first user message, whether the request uses prompt or messages. An attachment with mediaType: "application/pdf" becomes an Anthropic document content block in the Anthropic and Bedrock drivers; Ollama and OpenAI-compatible drivers throw a clear unsupported error.

Structured-output schema values may have a non-object root, such as z.array(...). Anthropic tool input schemas are automatically wrapped in { result: ... } and their responses are transparently unwrapped, so result.parsed continues to validate against the original schema.

validationRetries?: number on LlmRequest defaults to 0. When schema validation fails, the gateway can reissue the request with the invalid response and a correction instruction for up to that many extra attempts. Every attempt is cost-recorded, and only a valid result is cached.

Store schemas

The file store writes <root>/<key>.txt and <root>/<key>.json; the sidecar contains prompt, meta, and createdAt.

CREATE TABLE IF NOT EXISTS llm_cache (key TEXT PRIMARY KEY, text TEXT NOT NULL, prompt TEXT NOT NULL, meta TEXT NOT NULL, created_at TEXT NOT NULL);
CREATE TABLE IF NOT EXISTS llm_spend (date TEXT, operation TEXT, tenant_id TEXT, provider TEXT, model TEXT, input_tokens INTEGER, output_tokens INTEGER, cost_usd REAL);

The DynamoDB cache table uses partition key key (string). Cache items contain text, prompt, JSON-string meta, and createdAt. Spend items use key = date#operation#uuid; daily totals currently use a scan.

Cost

Spend is computed from provider-reported token usage. Claude models are priced from a built-in table (PRICE_TABLE, base per-million-token rates) that matches Claude API IDs, dated IDs and Bedrock IDs/ARNs by model family. A model the table does not know is costed at the highest listed rate and logs a warning once, so the daily cap errs on the safe side; set <P>_LLM_PRICE_PER_MTOK for openai-compatible or custom models.