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

llm-provider-registry

v1.0.0

Published

Map any LLM model name (glm-4.6, deepseek-chat, kimi-k2, grok-4, claude-…, gpt-…) to its API base URL + key env var. Curated for 16 providers — incl. the Chinese ones the big frameworks don't ship. Zero deps.

Readme

llm-provider-registry

Give it a model name, get back where to send the request and which key to use.

"glm-4.6"            → https://open.bigmodel.cn/api/paas/v4   · ZHIPU_API_KEY    · OpenAI-compatible
"deepseek-chat"      → https://api.deepseek.com/v1            · DEEPSEEK_API_KEY · OpenAI-compatible
"kimi-k2"            → https://api.moonshot.cn/v1             · MOONSHOT_API_KEY · OpenAI-compatible
"claude-sonnet-4-6"  → https://api.anthropic.com              · ANTHROPIC_API_KEY· Anthropic SDK
"gpt-5"              → https://api.openai.com/v1              · OPENAI_API_KEY   · OpenAI SDK

A tiny, zero-dependency lookup table + resolver. It knows 16 providers — including the Chinese ones (Zhipu/GLM, DeepSeek, Moonshot/Kimi, Qwen, Doubao, MiniMax, Baichuan, Yi, Stepfun, Hunyuan) that the big frameworks make you wire up by hand.

The problem it solves

You want to let users pick any model — gpt-5, deepseek-chat, glm-4.6, qwen3-max, claude-… — and Just Work. Every one of those is reachable through the OpenAI chat-completions API, so in principle you only need one SDK. The catch is the plumbing: each provider has its own base URL and its own API-key env var, and nobody ships a maintained table of them — the OpenAI SDK obviously doesn't, and the big frameworks skip most of the Chinese providers.

So everyone ends up hand-copying base URLs off docs pages into a switch statement. This is that switch statement, curated and tested, as a 2 kB import.

import OpenAI from "openai";
import { resolveModel } from "llm-provider-registry";

function clientFor(model) {
  const p = resolveModel(model);
  if (!p) throw new Error(`Unknown model: ${model}`);
  if (!p.openaiCompatible) throw new Error(`${p.provider} needs its own SDK, not OpenAI's`);
  return new OpenAI({ baseURL: p.baseURL, apiKey: p.apiKey });
}

// One line, any provider:
const res = await clientFor("glm-4.6").chat.completions.create({
  model: "glm-4.6",
  messages: [{ role: "user", content: "hi" }],
});

Install

npm install llm-provider-registry

Node ≥ 18. ESM. Ships its own TypeScript types.

API

resolveModel(model, env?) → ResolvedModel | null

Returns null if the model isn't recognized, otherwise:

{
  provider: string;          // "Zhipu (GLM)", "DeepSeek", "Anthropic", …
  kind: "anthropic" | "openai" | "gemini" | "openai-compatible";
  baseURL: string;           // point your client here
  apiKeyEnv: string;         // e.g. "ZHIPU_API_KEY"
  apiKey: string | undefined;// that var's value, read from `env` (default process.env)
  openaiCompatible: boolean; // true → use the OpenAI SDK against baseURL
}

env defaults to process.env; pass your own object to resolve keys from somewhere else (tests, a config store, per-request overrides).

openaiCompatible is the branch that matters. It's true for everything except Anthropic (claude-*), which speaks a different wire protocol — send those to @anthropic-ai/sdk. OpenAI, Gemini (via its OpenAI-compat endpoint), and all 13 presets are true.

hasCredentials(model, env?) → boolean

true only when the model is recognized and its API-key env var is set. Handy for filtering a model menu down to the ones the user can actually call:

const usable = ALL_MODELS.filter((m) => hasCredentials(m));

PRESETS

The raw table of OpenAI-compatible third-party providers, if you'd rather iterate it yourself:

{ name: string; modelPrefixes: string[]; baseURL: string; apiKeyEnv: string }[]

Providers covered

| Provider | Example model prefixes | Base URL | API-key env | |---|---|---|---| | Anthropic | claude- | api.anthropic.com | ANTHROPIC_API_KEY | | OpenAI | gpt-, o1, o3, o4, chatgpt- | api.openai.com/v1 | OPENAI_API_KEY | | Google Gemini | gemini- | …/v1beta/openai/ | GEMINI_API_KEY | | DeepSeek | deepseek- | api.deepseek.com/v1 | DEEPSEEK_API_KEY | | Mistral AI | mistral-, codestral-, magistral-, ministral-, pixtral- | api.mistral.ai/v1 | MISTRAL_API_KEY | | Perplexity (Sonar) | sonar, sonar- | api.perplexity.ai | PERPLEXITY_API_KEY | | xAI Grok | grok- | api.x.ai/v1 | XAI_API_KEY | | Volcengine Ark (Doubao) | doubao-, ep- | ark.cn-beijing.volces.com/api/v3 | ARK_API_KEY | | Aliyun DashScope (Qwen) | qwen-, qwen2, qwen3 | dashscope.aliyuncs.com/compatible-mode/v1 | DASHSCOPE_API_KEY | | Moonshot (Kimi) | moonshot-, kimi- | api.moonshot.cn/v1 | MOONSHOT_API_KEY | | Zhipu (GLM) | glm-, chatglm- | open.bigmodel.cn/api/paas/v4 | ZHIPU_API_KEY | | Stepfun (Step) | step- | api.stepfun.com/v1 | STEPFUN_API_KEY | | 01.AI (Yi) | yi- | api.lingyiwanwu.com/v1 | LINGYI_API_KEY | | Baichuan | baichuan-, baichuan2/3/4 | api.baichuan-ai.com/v1 | BAICHUAN_API_KEY | | MiniMax | abab, minimax- | api.minimax.io/v1 | MINIMAX_API_KEY | | Tencent Hunyuan | hunyuan- | api.hunyuan.cloud.tencent.com/v1 | HUNYUAN_API_KEY |

Matching is by case-insensitive prefix, so glm-4.6, glm-4-flash, and GLM-4.6 all resolve to Zhipu — new model releases usually keep the family prefix and Just Work without a library bump.

What it deliberately isn't

  • Not an API client. It hands you a baseURL + key; you bring your own SDK. That's the point — it stays 2 kB and never breaks when a provider tweaks a response field.
  • Not a param translator. It doesn't reshape requests between the Anthropic and OpenAI schemas. It only tells you which family a model belongs to (kind) so you know which SDK to reach for.
  • Not exhaustive on models. It matches families by prefix, not an ever-changing list of exact model IDs.

License

MIT © 2026 oratis