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

fetch-sdk

v2.0.0

Published

A modular Fetch API client with streaming and resumable file transfers

Readme

Fetch SDK 2.0

Fetch SDK 2.0 是一个零运行时依赖的 Fetch API 客户端,提供统一请求配置、拦截器、超时/取消、流式响应、上传下载进度,以及可持久化的文件断点续传能力。

安装

npm install fetch-sdk

项目不会自动安装依赖、构建或启动服务。发布前可由使用者手动执行 npm run build

快速开始

import client from 'fetch-sdk';

const api = client.create({
  baseURL: 'https://api.example.com',
  timeout: 15000,
  headers: { Authorization: 'Bearer token' }
});

const users = await api.get('/users', { params: { page: 1, tag: ['new', 'vip'] } });
const created = await api.post('/users', { name: 'Ada' });
const updated = await api.patch('/users/1', { name: 'Grace' });
await api.delete('/users/1');

默认根据 Content-Type 解析 JSON 或文本。通过 responseType 可以显式指定 jsontextblobarrayBufferformDataresponsestream

const response = await api.get('/health', { responseType: 'response' });
const buffer = await api.get('/archive.zip', { responseType: 'arrayBuffer' });

请求配置

request(config)request(url, options) 都可用,client 本身也可以直接调用。

await api.request({
  url: '/search',
  method: 'POST',
  params: { q: 'fetch' },
  data: { limit: 20 },
  credentials: 'include',
  timeout: 5000
});

对象、数组会自动 JSON 序列化;FormDataBlobArrayBufferURLSearchParamsReadableStream 会原样作为请求体。使用 FormData 时不要手动设置 Content-Type,浏览器需要自行追加 boundary。

拦截器

const requestId = api.interceptors.request.use(config => {
  config.headers['X-Request-Id'] = crypto.randomUUID();
  return config;
});

api.interceptors.response.use(data => data, error => Promise.reject(error));
api.interceptors.request.eject(requestId);

也可以使用 addRequestInterceptoraddResponseInterceptor。拦截器返回 undefined 时保留当前值,返回 nullfalse 时会使用返回值。

超时与取消

SDK 使用原生 AbortSignal,同时兼容 CancelToken

const controller = new AbortController();
const task = api.get('/events', { signal: controller.signal });
controller.abort();

直接导入 CancelToken

import client, { CancelToken, isCancel } from 'fetch-sdk';

const { token, cancel } = CancelToken.source();
api.get('/slow', { cancelToken: token }).catch(error => {
  if (isCancel(error)) console.log(error.message);
});
cancel('superseded');

错误统一为 FetchError,包含 codeconfigresponsestatuscause。常见 code:ERR_BAD_RESPONSEETIMEDOUTERR_CANCELEDERR_ABORTED

流式请求

stream 返回原始 ReadableStream,适合自定义二进制或 SSE 处理;streamIterable 提供 for await...of 语法,并默认以 UTF-8 解码。

for await (const chunk of api.streamIterable('/ai/chat')) {
  process.stdout.write(chunk);
}

const stream = await api.stream('/download/large');
const reader = stream.getReader();

通过 decode: false 保留 Uint8Array,通过 parseChunk(chunk) 转换每个文本块。

文件传输

普通上传和下载

const form = new FormData();
form.append('avatar', file);
await api.post('/avatar', form);

await api.upload(file, '/files', { fieldName: 'file' });
const blob = await api.download('/files/report.pdf', { filename: 'report.pdf' });

断点续传

上传按分片发送 X-Upload-IdX-Chunk-IndexX-Total-ChunksContent-Range 请求头;服务端应按这些信息保存分片并在所有分片完成后合并。下载使用 HTTP RangeContent-Range,需要服务端支持 206 Partial Content

await api.uploadWithResume(file, '/uploads/chunk', {
  chunkSize: 8 * 1024 * 1024,
  onProgress: ({ uploaded, total, progress }) => console.log(uploaded, total, progress),
  retry: 3
});

const blob = await api.downloadWithResume('/files/large.zip', {
  filename: 'large.zip',
  onProgress: ({ downloaded, total, progress }) => console.log(downloaded, total, progress)
});

进度默认保存在 IndexedDB;不支持 IndexedDB 时降级为内存和 localStorage(二进制断点在页面刷新后无法由 localStorage 恢复)。可通过 transferStore 注入自定义存储实现,或通过 storageKey 隔离多个业务。

进度回调

onDownloadProgress 适用于普通响应流,参数为 { loaded, total, progress }。原生 Fetch 没有跨浏览器统一的上传进度事件;需要上传进度时建议使用 uploadWithResume 的分片 onProgress,它在每个分片成功后稳定回调。

兼容性与手动构建

  • 需要支持 Fetch、AbortController、ReadableStream、Blob、FormData 的运行环境。
  • 构建工具链要求 Node.js >=20.19.0;运行时若没有原生 Fetch,可通过 fetch 配置注入实现。
  • 构建配置位于 vite.config.mjs,可由使用者手动运行 npm run build 生成 CJS、ESM 和 UMD 包。
  • 迁移不会自动重建已有 dist,首次使用新构建产物前请手动执行构建命令。

完整类型声明位于 src/index.d.ts