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

net-vert

v1.0.0

Published

Dependency Inversion Network Library with Type-Safe Injection.

Readme

@net-vert/core

轻量级依赖倒置网络请求库,专为扩展和易用而设计。

npm version license

GitHub 开源仓库 👉 https://github.com/yvygyyth/net-vert


✨ 核心特性

依赖倒置设计 - 解耦网络层,按需注入 axios、fetch 或自定义请求器
中间件扩展 - 内置缓存、幂等、重试、并发控制、同步模式等强大中间件
类型安全 - TypeScript 全类型提示,开发体验丝滑
零配置上手 - API 极简,开箱即用
灵活组合 - 多种中间件自由组合,满足复杂业务场景
Tree-Shaking - 支持按需引入,打包体积更小


📦 安装

npm install @net-vert/core

或者使用其他包管理器:

pnpm add @net-vert/core
# 或
yarn add @net-vert/core

🚀 快速上手

1️⃣ 注入请求器

首先,将你的请求函数注入到 @net-vert/core。这个函数接收请求配置,返回一个 Promise:

import { inject } from '@net-vert/core'

// 创建一个简单的请求函数
const myRequestor = (config) => {
  // 返回一个 Promise
  return new Promise((resolve, reject) => {
    // 这里可以是任何异步请求实现
    // 例如:fetch、axios、小程序的 wx.request 等
    fetch(config.url, {
      method: config.method,
      headers: config.headers,
      body: config.data ? JSON.stringify(config.data) : undefined
    })
      .then(res => res.json())
      .then(data => resolve(data))
      .catch(err => reject(err))
  })
}

// 注入到 net-vert
inject(myRequestor)

提示:你可以注入任何符合请求器签名 (config) => Promise 的函数,包括 axios、fetch 或自定义请求实现。

2️⃣ 发起请求

注入完成后,使用 useRequestorcreateRequestor 创建请求器:

基础用法

import { useRequestor } from '@net-vert/core'

const requestor = useRequestor()

// GET 请求
requestor.get('/user/info', { params: { id: 1 } }).then(console.log)

// POST 请求
requestor.post('/user/create', { name: 'Alice' }).then(console.log)

// PUT 请求
requestor.put('/user/update', { id: 1, name: 'Bob' })

// DELETE 请求
requestor.delete('/user/delete', { params: { id: 1 } })

🛠 中间件系统

@net-vert/core 的强大之处在于其中间件系统。你可以通过 createRequestor 结合各种中间件来扩展请求能力。

核心 API:createRequestor

import { createRequestor, cache, idempotent } from '@net-vert/core'

const requestor = createRequestor({
  extensions: [
    idempotent(),              // 防止并发重复请求
    cache({ duration: 5000 })  // 缓存 5 秒
  ]
})

// 使用增强后的请求器
requestor.get('/api/data')

📚 内置中间件

1. 缓存中间件 (cache)

为请求结果添加缓存能力,避免重复请求相同数据。

基础用法

import { createRequestor, cache } from '@net-vert/core'

const requestor = createRequestor({
  extensions: [
    cache({ 
      duration: 5000  // 缓存 5 秒
    })
  ]
})

// 首次请求会发起网络请求
await requestor.get('/api/users')

// 5 秒内的相同请求会直接返回缓存
await requestor.get('/api/users')  // 使用缓存

配置选项

interface CacheOptions<D = any, R = any> {
  /**
   * 缓存 key 生成函数
   * 默认:基于 method + url + params 生成哈希
   */
  key?: (ctx: { config: RequestConfig<D> }) => string

  /**
   * 缓存有效期(毫秒)
   * - number: 固定时长
   * - function: 动态计算(可根据响应内容决定缓存时长)
   */
  duration?: number | ((ctx: { 
    key: string
    config: RequestConfig<D>
    response: R 
  }) => number)

  /**
   * 是否持久化到 IndexedDB 或 localStorage
   * 默认:false(仅内存缓存)
   */
  persist?: boolean

  /**
   * 缓存有效性校验函数
   * 返回 false 则忽略缓存,重新请求
   */
  isValid?: (ctx: {
    key: string
    config: RequestConfig<D>
    cachedData?: ExpirableValue<R>
  }) => boolean | Promise<boolean>
}

高级示例

自定义缓存 key

const requestor = createRequestor({
  extensions: [
    cache({
      duration: 5000,
      // 只根据 URL 生成 key,忽略参数差异
      key: ({ config }) => `custom_${config.url}`
    })
  ]
})

// 这两个请求会共享缓存(因为 URL 相同)
await requestor.get('/api/users', { params: { id: 1 } })
await requestor.get('/api/users', { params: { id: 2 } })  // 使用缓存

动态缓存时长

const requestor = createRequestor({
  extensions: [
    cache({
      // 根据响应内容决定缓存时长
      duration: ({ response }) => {
        // 如果数据标记为"静态",缓存 1 小时
        if (response.isStatic) {
          return 60 * 60 * 1000
        }
        // 否则缓存 5 秒
        return 5000
      }
    })
  ]
})

自定义缓存有效性校验

let userLoggedOut = false

const requestor = createRequestor({
  extensions: [
    cache({
      duration: 10000,
      // 用户登出后使所有缓存失效
      isValid: ({ cachedData }) => {
        if (userLoggedOut) return false
        return true
      }
    })
  ]
})

持久化缓存

const requestor = createRequestor({
  extensions: [
    cache({
      duration: 24 * 60 * 60 * 1000,  // 缓存 24 小时
      persist: true  // 持久化到 IndexedDB/localStorage
    })
  ]
})

手动操作缓存

缓存中间件暴露了 storage 属性,允许你手动操作缓存:

const cacheMiddleware = cache({ duration: 5000 })

const requestor = createRequestor({
  extensions: [cacheMiddleware]
})

// 清空所有缓存
cacheMiddleware.storage.clear()

// 获取缓存项
const cached = cacheMiddleware.storage.getItem('/api/users')

// 删除特定缓存
cacheMiddleware.storage.removeItem('/api/users')

// 手动设置缓存
cacheMiddleware.storage.set('/api/users', { data: [...] })

2. 幂等中间件 (idempotent)

防止相同的请求并发执行,确保在前一个请求完成前,后续相同请求返回同一个 Promise。

基础用法

import { createRequestor, idempotent } from '@net-vert/core'

const requestor = createRequestor({
  extensions: [idempotent()]
})

// 并发发起两个相同请求
const promise1 = requestor.get('/api/users')
const promise2 = requestor.get('/api/users')

// promise1 和 promise2 是同一个 Promise 实例
console.log(promise1 === promise2)  // true

// 只会发起一次网络请求
const [result1, result2] = await Promise.all([promise1, promise2])

配置选项

interface IdempotencyOptions<D = any> {
  /**
   * 自定义请求唯一标识生成函数
   * 默认:基于 method + url + params 生成哈希
   */
  genKey?: (config: RequestConfig<D>) => string
}

高级示例

const requestor = createRequestor({
  extensions: [
    idempotent({
      // 自定义 key 生成逻辑
      genKey: (config) => `${config.method}:${config.url}`
    })
  ]
})

与缓存组合使用

幂等中间件通常与缓存中间件配合使用,实现"短期防重复 + 长期缓存":

const requestor = createRequestor({
  extensions: [
    idempotent(),              // 防止并发重复(短期)
    cache({ duration: 5000 })  // 缓存结果(长期)
  ]
})

3. 重试中间件 (retry)

当请求失败时自动重试,支持固定延迟、指数退避等策略。

基础用法

import { createRequestor, retry } from '@net-vert/core'

const requestor = createRequestor({
  extensions: [
    retry({ 
      retries: 3,    // 最多重试 3 次
      delay: 1000    // 每次重试延迟 1 秒
    })
  ]
})

// 失败后会自动重试最多 3 次
await requestor.get('/api/unstable-endpoint')

配置选项

interface RetryOptions<D = any> {
  /**
   * 最大重试次数
   * 默认:3
   */
  retries?: number

  /**
   * 重试延迟(毫秒)
   * - number: 固定延迟
   * - function: 动态延迟(实现指数退避等策略)
   * 默认:0
   */
  delay?: number | ((ctx: {
    config: RequestConfig<D>
    lastResponse: any
    attempt: number
  }) => number)

  /**
   * 重试条件判断函数
   * 返回 true 则重试,false 则直接抛出错误
   * 默认:所有错误都重试
   */
  retryCondition?: (ctx: {
    config: RequestConfig<D>
    lastResponse: any
    attempt: number
  }) => boolean
}

高级示例

指数退避重试

const requestor = createRequestor({
  extensions: [
    retry({
      retries: 5,
      // 指数退避:第 n 次重试延迟 2^n * 100ms
      delay: ({ attempt }) => Math.pow(2, attempt) * 100
    })
  ]
})

条件重试(仅 5xx 错误)

const requestor = createRequestor({
  extensions: [
    retry({
      retries: 3,
      delay: 1000,
      // 只在服务器错误时重试
      retryCondition: ({ lastResponse }) => {
        const status = lastResponse?.response?.status
        return status >= 500 && status < 600
      }
    })
  ]
})

4. 并发控制中间件 (concurrent)

限制同时发起的请求数量,适用于批量请求场景。

基础用法

import { createRequestor, concurrent } from '@net-vert/core'

const requestor = createRequestor({
  extensions: [
    concurrent({ 
      parallelCount: 3  // 最多同时 3 个请求
    })
  ]
})

// 发起 10 个请求,但同时只会执行 3 个
const promises = []
for (let i = 0; i < 10; i++) {
  promises.push(requestor.get(`/api/data/${i}`))
}
await Promise.all(promises)

配置选项

interface ConcurrentOptions<D = any> {
  /**
   * 最大并行请求数
   * 默认:4
   */
  parallelCount?: number

  /**
   * 任务唯一标识生成函数
   * 默认:基于时间戳 + 随机数
   */
  createId?: (config: RequestConfig<D>) => string | number
}

高级示例

const requestor = createRequestor({
  extensions: [
    concurrent({
      parallelCount: 5,
      // 使用请求 URL 作为任务 ID
      createId: ({ config }) => config.url
    })
  ]
})

与重试组合使用

const requestor = createRequestor({
  extensions: [
    concurrent({ parallelCount: 3 }),  // 限制并发数
    retry({ retries: 2, delay: 500 })   // 失败重试
  ]
})

// 批量请求,每个请求都有重试保护
const results = await Promise.all(
  urls.map(url => requestor.get(url))
)

5. 同步模式中间件 (sync)

让异步请求支持"Suspense 风格"的同步调用,适用于 React Suspense 等场景。

⚠️ 重要sync 中间件必须放在中间件数组的第一位,否则会导致功能异常。详见 中间件顺序规则

基础用法(Suspense 模式)

import { createRequestor, sync } from '@net-vert/core'

const requestor = createRequestor({
  extensions: [sync()]
})

// 首次调用会抛出 Promise(触发 Suspense)
try {
  const data = requestor.get('/api/users')
} catch (promise) {
  await promise  // 等待数据加载
}

// 再次调用会同步返回缓存数据
const data = requestor.get('/api/users')  // 同步返回,不再抛出
console.log(data)  // 直接获取数据

React Suspense 集成

import { createRequestor, sync } from '@net-vert/core'

const requestor = createRequestor({
  extensions: [sync()]
})

function UserProfile({ userId }) {
  // 首次渲染会抛出 Promise,触发 Suspense
  // 数据加载完成后重新渲染,此时同步返回数据
  const user = requestor.get(`/api/users/${userId}`)
  
  return <div>{user.name}</div>
}

function App() {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <UserProfile userId={1} />
    </Suspense>
  )
}

配置选项

interface SyncOptions<D = any, R = any> {
  /**
   * 缓存 key 生成函数
   * 默认:基于 method + url + params 生成
   */
  key?: (ctx: { config: RequestConfig<D> }) => string

  /**
   * 是否启用 Suspense 模式(抛出 Promise)
   * - true: 首次调用抛出 Promise(默认)
   * - false: 首次调用返回 Promise
   */
  suspense?: boolean

  /**
   * 自定义 Promise 包装函数
   * 可用于添加元数据或修改返回结构
   */
  wrapSuspense?: (params: {
    key: string
    config: RequestConfig<D>
    p: Promise<R>
  }) => Promise<R>

  /**
   * 缓存有效期(毫秒)
   * 默认:永久缓存
   */
  duration?: number

  /**
   * 是否持久化
   * 默认:false
   */
  persist?: boolean
}

高级示例

非 Suspense 模式

const requestor = createRequestor({
  extensions: [
    sync({ suspense: false })  // 关闭 Suspense 模式
  ]
})

// 首次调用返回 Promise
const promise = requestor.get('/api/users')
await promise

// 再次调用同步返回缓存
const data = requestor.get('/api/users')  // 同步返回

自定义 Promise 包装

const requestor = createRequestor({
  extensions: [
    sync({
      wrapSuspense: ({ p, key }) => {
        // 给 Promise 添加元数据
        return p.then(data => ({
          ...data,
          __cacheKey: key,
          __timestamp: Date.now()
        }))
      }
    })
  ]
})

🔗 中间件组合

多个中间件可以自由组合,执行顺序遵循数组顺序:

const requestor = createRequestor({
  extensions: [
    idempotent(),                      // 1. 防止并发重复
    cache({ duration: 5000 }),         // 2. 缓存结果
    retry({ retries: 3, delay: 1000 }), // 3. 失败重试
    concurrent({ parallelCount: 3 })   // 4. 限制并发
  ]
})

⚠️ 重要:中间件顺序规则

在组合中间件时,需要注意以下强制性规则,否则会导致功能异常:

  1. 同步模式中间件(sync)必须放在第一位

    // ✅ 正确
    const requestor = createRequestor({
      extensions: [
        sync(),                        // 必须第一个
        idempotent(),
        cache({ duration: 5000 })
      ]
    })
       
    // ❌ 错误 - 某些情况下 sync 不在第一位会导致同步调用失败,幂等缓存的promise会被sync模块直接改变,导致幂等缓存失效.重试也会因为同步模块抛错误耗尽失败次数,同步模块的同步能力也可能因为部分中间件的异步特性而失效
    const requestor = createRequestor({
      extensions: [
        retry() | idempotent(),
        sync()                        // 错误位置!
      ]
    })
  2. 自定义中间件如果需要拦截所有请求,必须前置

    自定义中间件的位置决定了它在中间件链中的执行时机:

    • 前置:可以拦截和修改所有请求(包括被其他中间件处理的请求)
    • 后置:只能处理未被前面中间件拦截的请求(如缓存命中的请求不会到达后置中间件)
    const loggerMiddleware: Middleware = async ({ config, next }) => {
      console.log('Request:', config.url)
      return await next()
    }
       
    // ✅ 正确 - logger 在最前面,可以记录所有请求
    const requestor = createRequestor({
      extensions: [
        loggerMiddleware,              // 第一个执行
        cache({ duration: 5000 }),
        retry({ retries: 3 })
      ]
    })
       
    // ⚠️ 注意 - logger 在 cache 之后,缓存命中的请求不会被记录
    const requestor = createRequestor({
      extensions: [
        cache({ duration: 5000 }),
        loggerMiddleware,              // 缓存命中时不会执行
        retry({ retries: 3 })
      ]
    })
  3. 推荐的中间件顺序(从前到后):

    • sync() - 同步模式(如果使用)
    • 自定义拦截中间件(日志、鉴权等)
    • idempotent() - 幂等处理
    • cache() - 缓存
    • retry() - 重试
    • concurrent() - 并发控制

常见组合模式

1. 数据查询场景(幂等 + 缓存)

const requestor = createRequestor({
  extensions: [
    idempotent(),              // 防止并发重复请求
    cache({ duration: 5000 })  // 缓存 5 秒
  ]
})

2. 批量请求场景(并发控制 + 重试)

const requestor = createRequestor({
  extensions: [
    concurrent({ parallelCount: 5 }),  // 最多同时 5 个请求
    retry({ retries: 3, delay: 500 })   // 失败重试 3 次
  ]
})

3. 全能组合(适用于复杂场景)

const requestor = createRequestor({
  extensions: [
    idempotent(),                         // 1. 防止并发重复
    cache({ 
      duration: 10000, 
      persist: true                       // 2. 持久化缓存 10 秒
    }),
    retry({ 
      retries: 3, 
      delay: ({ attempt }) => Math.pow(2, attempt) * 100  // 3. 指数退避重试
    }),
    concurrent({ parallelCount: 3 })      // 4. 限制并发数
  ]
})

🎯 便捷组合方法

为常见场景提供了预设组合:

createCachedIdempotentRequestor

创建带缓存和幂等的请求器,适用于数据查询接口。

import { createCachedIdempotentRequestor } from '@net-vert/core'

const requestor = createCachedIdempotentRequestor({
  duration: 5000,  // 缓存 5 秒
  persist: false,  // 不持久化
  // 支持所有 cache 和 idempotent 的配置项
})

// 等价于:
// createRequestor({
//   extensions: [
//     idempotent(),
//     cache({ duration: 5000, persist: false })
//   ]
// })

createConcurrentRetryRequestor

创建带并发控制和重试的请求器,适用于批量请求场景。

import { createConcurrentRetryRequestor } from '@net-vert/core'

const requestor = createConcurrentRetryRequestor({
  parallelCount: 5,  // 最多 5 个并发
  retries: 3,        // 重试 3 次
  delay: 1000        // 每次延迟 1 秒
})

// 等价于:
// createRequestor({
//   extensions: [
//     concurrent({ parallelCount: 5 }),
//     retry({ retries: 3, delay: 1000 })
//   ]
// })

🔑 多实例管理

支持注入和管理多个请求器实例:

import { inject, createRequestor } from '@net-vert/core'

// 注入主实例(默认)
inject(axiosAdapter)

// 注入备用实例
inject(fetchAdapter, 'backup')

// 使用默认实例
const requestor1 = createRequestor()

// 使用备用实例
const requestor2 = createRequestor({ instanceKey: 'backup' })

📘 API 参考

核心 API

inject(requestor, instanceKey?)

注入请求器到全局容器。

  • requestor: (config: RequestConfig) => Promise<any> - 请求器函数
  • instanceKey: string | symbol - 实例标识(可选,默认为 'default'

useRequestor(instanceKey?)

获取已注入的请求器。

  • instanceKey: string | symbol - 实例标识(可选)
  • 返回: Requestor - 请求器对象

createRequestor(config?)

创建带中间件的请求器。

  • config.extensions: Middleware[] - 中间件数组
  • config.instanceKey: string | symbol - 使用的请求器实例标识
  • 返回: Requestor - 增强后的请求器

Requestor 接口

interface Requestor {
  request<R = any, D = any>(config: RequestConfig<D>): Promise<R>
  get<R = any, D = any>(url: string, config?: Omit<RequestConfig<D>, 'method' | 'url'>): Promise<R>
  post<R = any, D = any>(url: string, data?: D, config?: Omit<RequestConfig<D>, 'method' | 'url'>): Promise<R>
  put<R = any, D = any>(url: string, data?: D, config?: Omit<RequestConfig<D>, 'method' | 'url'>): Promise<R>
  delete<R = any, D = any>(url: string, config?: Omit<RequestConfig<D>, 'method' | 'url'>): Promise<R>
}

🎨 完整示例

示例 1:典型的前端应用配置

import axios from 'axios'
import { inject, createRequestor, idempotent, cache, retry } from '@net-vert/core'

// 1. 创建并注入 axios 实例
const instance = axios.create({
  baseURL: 'https://api.example.com',
  timeout: 10000
})
inject(config => instance.request(config))

// 2. 创建数据查询请求器(带缓存和幂等)
export const queryRequestor = createRequestor({
  extensions: [
    idempotent(),
    cache({ 
      duration: 30000,    // 缓存 30 秒
      persist: true       // 持久化
    })
  ]
})

// 3. 创建数据变更请求器(带重试)
export const mutationRequestor = createRequestor({
  extensions: [
    retry({ 
      retries: 3, 
      delay: ({ attempt }) => Math.pow(2, attempt) * 200,
      retryCondition: ({ lastResponse }) => {
        // 只在网络错误或 5xx 时重试
        const status = lastResponse?.response?.status
        return !status || (status >= 500 && status < 600)
      }
    })
  ]
})

// 4. 使用
async function fetchUserProfile(userId: number) {
  return queryRequestor.get(`/users/${userId}`)
}

async function updateUserProfile(userId: number, data: any) {
  return mutationRequestor.put(`/users/${userId}`, data)
}

示例 2:批量文件上传

import { createRequestor, concurrent, retry } from '@net-vert/core'

const uploadRequestor = createRequestor({
  extensions: [
    concurrent({ parallelCount: 3 }),  // 同时最多 3 个上传
    retry({ retries: 2, delay: 1000 }) // 失败重试 2 次
  ]
})

async function uploadFiles(files: File[]) {
  const tasks = files.map(file => {
    const formData = new FormData()
    formData.append('file', file)
    return uploadRequestor.post('/upload', formData)
  })
  
  return Promise.all(tasks)
}

示例 3:React Suspense 集成

import { inject, createRequestor, sync } from '@net-vert/core'
import { Suspense } from 'react'

// 注入请求器
inject(config => fetch(config.url).then(res => res.json()))

// 创建 Suspense 风格的请求器
const suspenseRequestor = createRequestor({
  extensions: [sync()]
})

// API 封装
const api = {
  getUser: (id: number) => suspenseRequestor.get(`/api/users/${id}`),
  getPosts: () => suspenseRequestor.get('/api/posts')
}

// 组件
function UserProfile({ userId }: { userId: number }) {
  const user = api.getUser(userId)  // 首次会触发 Suspense
  return <div>{user.name}</div>
}

function App() {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <UserProfile userId={1} />
    </Suspense>
  )
}

🔧 高级用法

自定义中间件

你可以编写自己的中间件来扩展功能:

import { createRequestor, type Middleware } from '@net-vert/core'

// 自定义日志中间件
const loggerMiddleware: Middleware = async ({ config, next }) => {
  console.log('Request:', config.method, config.url)
  const startTime = Date.now()
  
  try {
    const result = await next()
    console.log('Success:', Date.now() - startTime, 'ms')
    return result
  } catch (error) {
    console.error('Error:', error)
    throw error
  }
}

// 使用自定义中间件
const requestor = createRequestor({
  extensions: [loggerMiddleware]
})

⚠️ 重要提示:如果你的自定义中间件需要拦截所有请求(如日志记录、鉴权检查等),必须将其放在中间件数组的最前面sync 除外)。否则,被前置中间件(如 cache)拦截的请求不会经过你的自定义中间件。详见 中间件顺序规则

动态切换请求器

import { inject, useRequestor } from '@net-vert/core'

// 注入多个请求器
inject(axiosAdapter, 'axios')
inject(fetchAdapter, 'fetch')

// 动态选择
function getRequestor(type: 'axios' | 'fetch') {
  return useRequestor(type)
}

// 使用
const requestor = getRequestor('axios')
requestor.get('/api/data')

🧪 测试支持

轻松进行单元测试:

import { inject, createRequestor, cache } from '@net-vert/core'
import { vi } from 'vitest'

describe('API Tests', () => {
  it('should cache requests', async () => {
    // 创建 mock 请求器
    const mockRequestor = vi.fn(async (config) => ({
      code: 200,
      data: { url: config.url }
    }))
    
    inject(mockRequestor)
    
    const requestor = createRequestor({
      extensions: [cache({ duration: 5000 })]
    })
    
    // 发起两次相同请求
    await requestor.get('/api/test')
    await requestor.get('/api/test')
    
    // 验证只调用了一次
    expect(mockRequestor).toHaveBeenCalledTimes(1)
  })
})

📤 项目信息


💡 设计理念

  1. 依赖倒置 - 网络层完全解耦,未来可自由切换底层实现
  2. 组合优于继承 - 通过中间件组合实现复杂功能
  3. 渐进式增强 - 零配置可用,按需添加能力
  4. 类型安全 - 完整的 TypeScript 支持
  5. 轻量纯粹 - 核心代码极简,扩展独立管理

🤝 贡献

欢迎提交 Issue 和 Pull Request!


📝 更新日志

v1.0.0 (2024-11)

  • 🎉 正式版本发布
  • ✨ 完整的中间件系统
  • ✨ 支持缓存、幂等、重试、并发控制、同步模式
  • ✨ 完整的 TypeScript 类型支持
  • ✨ 支持多实例管理
  • 📚 完善的文档和示例

如有任何问题或建议,欢迎在 GitHub 上联系我们!