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

xby-fronted-api-client

v0.2.0

Published

可配置的统一后端请求客户端:微服务网关路由、业务信封解码、鉴权注入、取消管理与平台适配钩子

Readme

xby-fronted-api-client

基于 ky 的统一后端请求客户端。把「网关前缀路由、code/data/msg 信封解码、Token 注入、在途请求取消、成功/失败提示」做成可配置内核,把「弹窗、跳登录、Tauri fetch、文件保存」等平台细节留给调用方通过回调注入。

安装

bun add xby-fronted-api-client ky
# 本地联调(同级目录)
bun add xby-fronted-api-client@link:../snowy-api-client

快速开始

import { createApiClient } from 'xby-fronted-api-client';

export const client = createApiClient({
	baseUrl: () => import.meta.env.PUBLIC_API_URL,
	gateway: {
		routes: { '/sys': '/api/webapp', '/biz': '/api/bizapp' },
		bypassPrefix: '/custom',
	},
	getToken: () => store.get(tokenAtom),
	defaults: { cacheBust: true },
	onMessage: ({ level, message }) => toast[level](message),
	onUnauthorized: ({ source }) => (source === 'http' ? redirectToLogin() : showReloginModal()),
	saveFile: (blob, name) => downloadBlob(blob, name),
});

const user = await client.get<User>('/sys/user/detail', { id: 1 });
await client.post('/biz/order', { sku: 'A' }, { showSuccessMessage: true });
await client.download('/biz/order/export', { month: '2026-09' }); // 文件名可从 Content-Disposition 推断

路由表完全由调用方提供(库不内置任何路由):/sys/... 按上表映射为 /api/webapp/sys/...;/custom/x 命中 bypassPrefix 后剥掉前缀直接请求 /x。不传 gateway 时地址原样使用。

配置项一览(ApiClientOptions)

| 分组 | 选项 | 说明 | | --- | --- | --- | | 地址 | baseUrl | 绝对 HTTP(S) 地址或返回地址的函数(每次请求重新读取) | | | gateway | { routes, bypassPrefix } 网关映射表,路由完全由调用方提供;省略即不改写地址 | | | resolveUrl(path, base) | 完全接管路径解析,优先于 gateway | | 传输 | fetch | 自定义 fetch(浏览器 / Tauri plugin-http / 测试桩) | | | transport | 透传给 ky.create 的选项:timeout、retry 等,单次可覆盖 | | | defaults | 所有请求的默认 CustomRequestOptions(headers、hooks、cacheBust、meta…) | | 鉴权 | getToken | 同步或异步取 Token | | | auth | { headerName, formatToken, allowedOrigins };默认头名 token,仅向 baseUrl 同源发送 | | | getHeaders(ctx) | 每次请求追加的动态头(租户、语言、traceId…) | | 协议 | decodeResponse | 响应解码器,见 createEnvelopeDecoder;false 返回原始 JSON | | | searchParams | { arrayFormat: 'comma' \| 'repeat' \| 'brackets' \| 'indices', skipNull, serialize } | | | form | { fileField, filesField, serialize } 上传表单字段名与序列化 | | | messages | 覆盖内置文案(businessFailed、networkFailed、parseFailed、httpFailed(status) 等) | | 会话 | unauthorized | { httpStatuses: [401], businessCodes: [401] } 定义失效判定;false 关闭 | | | onUnauthorized(ctx) | 失效处理;并发触发时合并为一次,ctx.source 区分 http / business | | | canRequest(ctx) | 返回 false 时以 abort 错误拒绝新请求(登出过渡期) | | | requestTracker | 传入共享的 createRequestTracker() 让多个实例一起 abortAll | | 反馈 | onMessage({ level, message }) | 成功/错误提示出口 | | | shouldNotify(ctx) | 全局静默开关 | | | onError(error, ctx) | 所有失败的兜底观察 | | | onRequest / onResponse | 发出前 / 收到后观察(日志、埋点、耗时) | | 文件 | saveFile(blob, name) | download() 的保存适配器 |

单次请求选项(CustomRequestOptions)

在 ky 选项之上增加:showSuccessMessage、showErrorMessage、responseType(data | envelope | response | blob | text | optional)、returnFullResponse、auth: false、cacheBust、decodeResponse、form、searchParamsOptions、meta。

网关映射

routes 是「路径前缀 → 网关前缀」的表,按最长前缀匹配;目标写成函数即可按运行时条件动态决定(返回空值表示不改写):

gateway: {
	routes: {
		'/sys': '/api/webapp',
		'/sys/legacy': '/api/v1',                        // 更具体的前缀优先
		'/tenant': ({ pathname }) => tenantGateway(pathname),
	},
	bypassPrefix: ['/custom', '/raw'],                 // 可给多个;false 关闭
}
  • 未命中路由表时地址原样返回;不传 gateway 则完全不做映射。
  • 地址已带网关前缀时保持幂等,重复调用不会二次追加。
  • 绝对地址(https://...)与协议相对地址(//...)不参与映射。

非请求场景(拼接 SSE 地址、给 <img> 拼 URL 等)可以单独取出解析函数,复用同一张表:

const resolveGateway = createGatewayResolver({ routes: { '/biz': '/api/bizapp' } });
const sseUrl = join(import.meta.env.PUBLIC_API_URL, resolveGateway('/biz/lab/sse'));

信封解码器

createEnvelopeDecoder({
	codeKey: 'status', dataKey: 'payload', messageKey: 'message', successCodes: ['OK'],
	// 或完全自定义
	isSuccess: (body) => body.success === true,
	getData: (body) => body.result.items,
	allowRawBody: false, // 缺少 code 字段即视为业务错误
});

错误模型

所有失败统一抛出 ApiError,kind 取值 business | http | parse | network | timeout | abort,附带 code、status、data(原始响应体)、response、msg(等于 message,兼容旧调用方)。

派生实例

const silent = client.extend({ shouldNotify: () => false });
const v2 = client.extend({ gateway: { routes: { '/sys': '/api/v2' } } });

开发

bun install
bun test
bun run build