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

@tansr/api-client

v0.2.0

Published

Thin zero-dependency TypeScript client for the Tansr gateway: OpenAI/Anthropic/Responses-shaped data plane, models catalog & usage, SSE streaming (public, MIT).

Readme

@tansr/api-client

Tansr 网关薄客户端:用平台 key 直连 Tansr 数据面(OpenAI / Anthropic / OpenAI Responses 三协议形)与账面(模型目录 / 用量)。零依赖——只用运行时全局 fetch 与 Web Streams,不引 openai/anthropic SDK。

  • 运行环境:Node ≥ 20.3(内建 fetch),或任何具备 fetch/ReadableStream 的 现代浏览器 / 边缘运行时;
  • 请求体 passthrough:网关不做协议转换,字段语义与各上游协议一致,本包类型 只钉常用字段、其余原样放行。

获取 key

登录 Tansr 门户,在 /console → API Keys 创建 PAT(tansr_sk_ 前缀;scope 可选 datadata control——/v1/usage 需要 control)。登录态 access JWT 同样可用,两者均走 Authorization: Bearer

三行起步

import { Tansr } from '@tansr/api-client';

const client = new Tansr({ apiKey: process.env.TANSR_API_KEY }); // 省略 apiKey 时自动读 env TANSR_API_KEY
const r = await client.chat.completions.create({
  model: 'kimi-k3',
  messages: [{ role: 'user', content: '你好' }],
});
console.log(r.choices?.[0]?.message?.content);
console.log(r.meta); // { requestId, cost, balance } —— 消费 x-tansr-* 响应头

自建/私有部署传 baseUrl(含 /v1):new Tansr({ apiKey, baseUrl: 'http://127.0.0.1:8787/v1' })

流式(SSE)

const stream = client.chat.completions.stream({ model: 'kimi-k3', messages });
for await (const chunk of stream) {
  process.stdout.write(chunk.choices?.[0]?.delta?.content ?? '');
}
console.log(stream.meta); // 迭代完成后可取;流式无 x-tansr-cost(成本流末才可知),cost 恒 null
  • OpenAI 系(chat / responses):data: [DONE] 哨兵终止;
  • Anthropic(messages):event: 行语义已归一到帧对象的 type 字段,流体自然 结束即止;
  • 提前 break 会取消上游读,网关按断链结算,不留悬挂请求;
  • 流对象单次可迭代。

三协议同型 API 面

| 径 | 非流式 | 流式 | |----|--------|------| | OpenAI chat | client.chat.completions.create(params) | client.chat.completions.stream(params) | | Anthropic messages | client.messages.create(params) | client.messages.stream(params) | | OpenAI Responses | client.responses.create(params) | client.responses.stream(params) |

目录与账面:

const models = await client.models.list();
const usage = await client.usage.get({ window: '7d', groupBy: 'model' }); // 需 control scope

错误处理

import { TansrApiError, TansrConnectionError } from '@tansr/api-client';

try {
  await client.chat.completions.create({ model, messages });
} catch (err) {
  if (err instanceof TansrApiError) {
    // 网关错误信封 { error: { code, message, requestId, detail? } } 的映射
    console.error(err.status, err.code, err.requestId, err.detail);
    if (err.status === 402) {/* 余额不足:detail 携 balance / estimatedCost */}
    if (err.status === 429) {/* 限流:err.retryAfterMs 由 Retry-After 头换算(服务端原值,毫秒) */}
  } else if (err instanceof TansrConnectionError) {
    // 网络故障 / 超时(cause 保真底层错误)
  }
}

上游 4xx/5xx 由网关原样透传,本包尽力从透传体提取 code/message,兜底 http_<status>。错误对象永不携带 api key。

取消与超时

const ac = new AbortController();
const p = client.messages.create(params, { signal: ac.signal, timeoutMs: 30_000 });
ac.abort(); // 用户取消:原样抛调用方的 AbortError,不做包装

timeoutMs(构造器缺省 600_000)是一次调用的总预算:以调用起点计,覆盖整个 请求生命周期(含流式全程),也含幂等 GET 的 429 重试等待与后续尝试——重试不会 重新起算。预算耗尽抛 TansrConnectionError(timed out after <timeoutMs>ms)。

重试纪律

  • 幂等 GET(models.list / usage.get)的 429 自动重试:尊重 Retry-After (秒、小数秒或 HTTP-date;缺失 / 不可解析时回落 1 s、2 s 退避),上限 2 次;

  • 单次等待钳 30 s 上限(Retry-After 来自对端,不让远端决定客户端悬挂时长);

  • 等待与重试都在 timeoutMs 总预算之内:剩余预算盖不住(钳制后的)等待时不再等待、 不再重试,直接抛出该 429 的 TansrApiError——status === 429,retryAfterMs 携服务端原值(不受 30 s 钳制影响),调用方可据此自行排程:

    try {
      await client.models.list({ timeoutMs: 5_000 });
    } catch (err) {
      if (err instanceof TansrApiError && err.status === 429 && err.retryAfterMs !== null) {
        // 预算内放弃重试:按服务端建议自行排程,而不是让本次调用悬挂
        scheduleRetry(err.retryAfterMs);
      }
    }
  • POST 数据面一律不自动重试:网关按请求预扣与结算(计费面),盲重试会 重复计费——失败原样抛出,由调用方决策。

meta 挂载说明

非流式返回值的 meta不可枚举属性:JSON.stringify(响应) 不含 meta, 持久化原始响应体不被污染;注意 { ...res } 展开会丢弃它,先取后展开。

License

MIT