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/core

v1.3.4

Published

Dependency Inversion Network Library with Type-Safe Injection.

Downloads

457

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))
)

🔗 中间件组合

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

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

推荐的中间件顺序

在组合中间件时,建议遵循以下顺序(从前到后):

  1. 自定义拦截中间件(日志、鉴权等)
  2. idempotent() - 幂等处理
  3. cache() - 缓存
  4. retry() - 重试
  5. 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 次
  ]
})

🎯 便捷组合方法

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

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:自定义中间件

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,
    cache({ duration: 5000 })
  ]
})

🔧 高级用法

自定义中间件

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

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]
})

💡 提示:如果你的自定义中间件需要拦截所有请求(如日志记录、鉴权检查等),建议将其放在中间件数组的最前面。否则,被前置中间件(如 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 上联系我们!