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

@lovrabet/fetch

v1.0.2

Published

Lovrabet fetch sdk

Readme

fetch

云兔前端请求库 - 基于现代标准构建的轻量级 HTTP 客户端

特性

  • 🚀 轻量级,零依赖
  • 📦 完整的 TypeScript 支持
  • 📊 内置表格数据类型支持
  • 🎯 简洁的 API 设计

安装

pnpm add @lovrabet/fetch

快速开始

import { LovrabetFetch } from "@lovrabet/fetch";

// 创建实例
const fetcher = new LovrabetFetch();

// 发送 POST 请求
const result = await fetcher.post("/api/getList", {
  currentPage: 1,
  pageSize: 20,
});

// 发送 GET 请求
const data = await fetcher.get("/api/getOne", { id: 1 });

语言 Header(x-hng)

get/post 会自动尝试携带 x-hng 请求头:

x-hng: lang=zh-CN&domain=a.lovrabet.com

优先级如下:

  1. 调用请求时显式传入的 x-hng
  2. init.reqHeaders 中的 x-hng
  3. 浏览器环境自动生成(语言 + 当前域名)

浏览器自动生成时,语言来源优先级:

  1. 通过 setYTFetchLangProvider 设置的 provider

可以通过导出的 API 设置 provider:

import { setYTFetchLangProvider } from "@lovrabet/fetch";

setYTFetchLangProvider(() => "zh-CN");

在外部需要直接复用 x-hng header 时,可使用:

import { getXHngHeader } from "@lovrabet/fetch";

// 返回 { "x-hng": "lang=zh-CN&domain=a.lovrabet.com" } 或 {}
const headers = {
  ...getXHngHeader(),
  "Content-Type": "application/json",
};

Rabetbase 配置解析(.rabetbase.json)

构建脚本(如 vite.config.ts)常需要从 .rabetbase.json 读取应用与地区信息。本库提供一组纯函数,不读取文件,只解析传入的配置对象:

import {
  loadRabetbaseConfig,
  getRabetbaseAppCode,
  getRabetbaseRegion,
  getCdnBase,
  getRabetbaseCdnBase,
  REGION_BASE_DOMAINS,
} from "@lovrabet/fetch";

// Node / Bun 环境可直接读取当前项目配置:
// 从 cwd 逐级向上查找 .rabetbase.json,未显式配置 region 时从全局 ~/.rabetbase.json 继承
const config = await loadRabetbaseConfig();

// 解析 App Code:defaultApp 指向的 profile 的 appcode;
// 单 profile 时可省略 defaultApp,自动选中
const appCode = getRabetbaseAppCode(config);

// 解析 region(缺省 cn),非法值抛错
const region = getRabetbaseRegion(config); // "cn" | "id"

// region 对应的 CDN 公开访问 origin
getCdnBase(region); // https://g.lovrabet.com 或 https://g.lovrabet.id
getRabetbaseCdnBase(config); // 同上,直接从配置解析

loadRabetbaseConfig 依赖文件系统,只能在 Node / Bun 环境使用;浏览器环境请显式传入配置对象。所有 get* 函数均为纯函数,不读取文件。

REGION_BASE_DOMAINS 提供 region 到站点根域名的映射(cn → lovrabet.comid → lovrabet.id)。

CDN 产物上传(仅 Node / Bun)

lovrabetCdnUpload 将本地构建产物上传到 Lovrabet CDN(pan 发布服务):遍历目录 → 校验 app/<appcode>/assets/<version>/<path> 发布 key → 分批请求预签名地址 → 并发直传对象存储。

import { lovrabetCdnUpload } from "@lovrabet/fetch";

const { uploaded, urls } = await lovrabetCdnUpload({
  dir: "dist", // 默认 dist
  region: "cn", // 缺省 cn,决定 pan 服务与 CDN 地址
  apiKey: "<publish-api-key>", // 缺省不携带鉴权头
});

| 选项 | 默认值 | 说明 | |-|-|-| | dir | "dist" | 待上传的本地产物目录 | | region | "cn" | cn / id,pan 服务地址按此推导 | | apiKey | 无 | 发布 API Key,缺省不携带鉴权头 | | batchSize | 500 | 每批预签名文件数 | | workers | 8 | 并发上传数 | | log | true | 是否打印进度日志 |

该函数依赖文件系统与网络直传,只能在 Node / Bun 环境使用;浏览器环境调用会抛出错误。所有配置通过参数显式传入,不读取环境变量。

安装后也可直接使用命令行工具(支持 --dir/--region/--api-key/--no-log):

lovrabet-cdn-upload
lovrabet-cdn-upload --dir dist --region cn

子路径按需引入

构建产物提供多个入口,支持 exports 子路径解析(moduleResolution: bundler / node16+)的环境可按需引入,避免拉入不需要的模块:

// 全量入口
import { LovrabetFetch, lovrabetCdnUpload } from "@lovrabet/fetch";
// 仅 CDN 上传(Node / Bun)
import { lovrabetCdnUpload } from "@lovrabet/fetch/cdn-upload";
// 仅 .rabetbase.json 配置解析
import { loadRabetbaseConfig } from "@lovrabet/fetch/rabetbase-config";

moduleResolution: node(node10)的环境请继续使用根入口 @lovrabet/fetch

API 文档

构造函数选项

interface LovrabetFetchOptions {
  // baseURL 已根据 lovrabet.com 不同环境的域名自动适配,正常不需要再传递
  baseURL?: string;
  // 实例级 credentials 配置
  credentials?: RequestCredentials;
}

credentials 的优先级:单次请求传入 > 实例配置 > 默认行为(已知站点域名 lovrabet.com / lovrabet.id 强制 "include",其余域名不设置)。

// 实例级:该实例所有请求使用 same-origin
const fetcher = new LovrabetFetch({ credentials: "same-origin" });

// 请求级:覆盖实例配置与已知域名的默认 include
await fetcher.get("/api/getOne", { id: 1 }, { credentials: "omit" });

请求方法

  • get(url, params?) - GET 请求
  • post(url, data?) - POST 请求

类型定义

基础响应类型

import type { IResponse } from "@lovrabet/fetch";

interface IResponse<T = any> {
  data: T;
  code: number;
  message: string;
}

表格响应类型

import type { ITableResponse } from "@lovrabet/fetch";

interface ITableResponse<ListItem = any> {
  tableData: ListItem[];
  paging: {
    /**
     * 当前页码
     */
    currentPage: number;

    /**
     * 总页数
     */
    totalCount: number;

    /**
     * 每页条数
     */
    pageSize: number;
  };
  tableColumns: Record<string, unknown>[];
}

使用示例

处理表格数据

import type { ITableResponse } from "@lovrabet/fetch";

interface User {
  id: number;
  name: string;
  email: string;
}

const data = await fetcher.post<ITableResponse<User>>("api/users", {
  currentPage: 1,
  pageSize: 10,
});

console.log(data.tableData); // User[]
console.log(data.paging.totalCount); // number

错误处理

try {
  const data = await fetcher.get("/api/data");
  console.log(data);
} catch (error) {
  console.error("请求失败:", error);
}

开发

安装依赖

bun install

运行示例

bun run index.ts

构建

bun run build

测试

bun test

路线图

  • [ ] 内置埋点功能
  • [ ] 缓存机制
  • [ ] 重试机制
  • [ ] 取消请求功能