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

public-sdk

v2.3.1

Published

Node.js 服务端通用工具库 - 提供微信小程序 SDK、统一响应封装、常用工具方法等

Readme

公共服务 SDK

npm version license

版本: 2.3.0 | Node.js: >= 14.0.0

Node.js 服务端通用工具库,提供微信小程序 SDK、统一响应封装、常用工具方法等。

✨ 特性

  • 🔐 安全可靠:使用 Node.js crypto 模块生成安全的随机数和 UUID
  • 🛡️ 类型安全:完善的参数验证和类型检查
  • 🧪 测试覆盖:47+ 单元测试用例,100% 方法覆盖率
  • 📦 零依赖:除 axios 外无其他第三方依赖
  • 🚀 即插即用:ES Module 支持,Tree-shaking 友好

📦 安装

npm install public-sdk

🚀 快速开始

微信小程序 SDK

import { WX } from "public-sdk";

const wx = new WX({
  appid: "your-appid",
  secret: "your-secret",
  env_version: "develop", // develop | trial | release
});

// 获取 access_token
const token = await wx.getAccessToken();

// 获取微信 openid
const openid = await wx.getOpenid(code);

// 获取小程序码
const qrBuffer = await wx.getUnlimitedQRCode({
  page: "pages/index/index",
  scene: "user=123",
  width: 430,
});

// 敏感词检测
const result = await wx.checkSensitiveWords(text, openid);

// 获取手机号
const phoneInfo = await wx.getPhoneNumber(code);

响应数据统一封装

import { Send } from "public-sdk";

// 自定义成功响应 code(默认为 0)
Send.successCode = 200;

// 成功响应
Send.success(data); // { code: 0, data, message: 'success' }

// 错误响应
Send.fail("操作失败", 400); // { code: 400, message: '操作失败', data: null }

// 格式化错误信息
Send.formatError(error);

// 操作过于频繁响应
Send.tooManyRequests(); // { code: 429, message: '请求过于频繁' }

🔧 工具类 Utils

import { Utils } from "public-sdk";

UUID 生成

使用 crypto.randomUUID() 生成符合 RFC 4122 标准的 UUID v4。

const uuid = Utils.uuid();
// 示例输出: "550e8400-e29b-41d4-a716-446655440000"

特性:

  • 使用加密安全的随机数生成器
  • 保证唯一性
  • 标准 UUID 格式(36 字符)

格式化方法

formatAccount(account)

格式化账号:转小写 + 去除首尾空格

Utils.formatAccount("  [email protected]  ");
// 返回: "[email protected]"

Utils.formatAccount(null);      // 返回: ""
Utils.formatAccount(undefined); // 返回: ""
Utils.formatAccount(12345);     // 返回: "12345"

formatPassword(password)

格式化密码:去除首尾空格

Utils.formatPassword("  myPassword123  ");
// 返回: "myPassword123"

Utils.formatPassword(null);      // 返回: ""
Utils.formatPassword(undefined); // 返回: ""

随机字符串生成

randomStr(len?, prefix?, charset?)

生成加密安全的随机字符串。

参数:

| 参数 | 类型 | 默认值 | 说明 | |------|------|--------|------| | len | number | 8 | 生成的字符串长度 | | prefix | string | '' | 前缀 | | charset | string | 'alphanumeric' | 字符集类型 |

字符集选项:

| 值 | 说明 | 包含字符 | |----|------|----------| | 'alphanumeric' | 字母数字混合(默认) | a-z, A-Z, 0-9 | | 'alpha' | 纯字母 | a-z, A-Z | | 'numeric' | 纯数字 | 0-9 |

示例:

// 默认:8 位字母数字混合
Utils.randomStr();
// 示例: "aB3xK9mP"

// 自定义长度
Utils.randomStr(16);
// 示例: "qR7tY2wE8pL1kO3j"

// 带前缀
Utils.randomStr(8, "token_");
// 示例: "token_xKmPqR"

// 纯字母
Utils.randomStr(20, "", "alpha");
// 示例: "aBcDeFgHiJkLmNoPqRsT"

// 纯数字
Utils.randomStr(6, "", "numeric");
// 示例: "385921"

特性:

  • 使用 crypto.randomBytes() 生成密码学安全的随机数
  • 支持自定义字符集
  • 可用于生成 token、验证码、临时密码等场景

校验方法

isEmail(email)

校验邮箱格式是否符合 RFC 标准。

Utils.isEmail("[email protected]");           // true
Utils.isEmail("[email protected]"); // true
Utils.isEmail("invalid-email");              // false
Utils.isEmail(null);                         // false
Utils.isEmail("");                           // false

支持的邮箱格式:


isPhone(phone, strict?)

校验手机号格式。

参数:

| 参数 | 类型 | 默认值 | 说明 | |------|------|--------|------| | phone | string \| number | - | 手机号 | | strict | boolean | true | 是否使用严格模式 |

严格模式(默认):

  • 仅支持中国大陆手机号
  • 格式:11 位数字,1 开头,第二位为 3-9
Utils.isPhone("13812345678");    // true
Utils.isPhone("19900001111");    // true
Utils.isPhone("12345678901");    // false (号段无效)
Utils.isPhone("1381234567");     // false (位数不足)
Utils.isPhone(13812345678);      // true (支持数字类型)

宽松模式:

  • 支持国际手机号格式
  • 格式:可选 + 前缀,7-15 位数字
Utils.isPhone("+8613812345678", false); // true
Utils.isPhone("+11234567890", false);   // true
Utils.isPhone("8613812345678", false);   // true

isUrl(url)

校验 URL 格式是否有效。

Utils.isUrl("https://www.example.com");        // true
Utils.isUrl("http://test.org/path?query=1");   // true
Utils.isUrl("ftp://files.server.com");         // true
Utils.isUrl("not-a-url");                      // false
Utils.isUrl("http://");                        // false
Utils.isUrl(null);                             // false

特性:

  • 使用原生 URL 构造函数进行验证
  • 支持 http、https、ftp 等协议
  • 自动处理各种 URL 格式

数据转换

list2tree(items, prop?)

将扁平列表转换为树形结构(支持多级嵌套)。

参数:

| 参数 | 类型 | 默认值 | 说明 | |------|------|--------|------| | items | Array | - | 扁平数据列表 | | prop | Object | {} | 属性名配置 |

默认配置:

{
  id: 'id',           // ID 字段名
  parent_id: 'parent_id', // 父级 ID 字段名
  children: 'children',   // 子节点字段名
  label: 'label',         // 显示文本字段名
  value: 'value'          // 值字段名
}

基本用法:

const items = [
  { id: 1, name: "根节点1", parent_id: 0 },
  { id: 2, name: "子节点1-1", parent_id: 1 },
  { id: 3, name: "子节点1-2", parent_id: 1 },
  { id: 4, name: "根节点2", parent_id: 0 },
  { id: 5, name: "子节点2-1", parent_id: 4 },
];

const tree = Utils.list2tree(items, { label: "name" });

// 输出:
[
  {
    id: 1,
    name: "根节点1",
    label: "根节点1",
    value: 1,
    children: [
      {
        id: 2,
        name: "子节点1-1",
        label: "子节点1-1",
        value: 2,
        parent_name: "根节点1",
        children: []
      },
      // ...
    ]
  },
  // ...
]

自定义属性名:

const items = [
  { itemId: 1, title: "根节点", parentId: null },
  { itemId: 2, title: "子节点", parentId: 1 },
];

const tree = Utils.list2tree(items, {
  id: "itemId",
  label: "title",
  value: "itemId",
  parent_id: "parentId"
});

Sequelize 兼容性:

自动识别 Sequelize 模型实例,提取 dataValues

const sequelizeItems = await Model.findAll();

const tree = Utils.list2tree(sequelizeItems);
// 自动处理 Sequelize 实例

特性:

  • ✅ 支持多级嵌套
  • ✅ 自动跳过重复 ID 的项(控制台警告)
  • ✅ 处理 null/undefined 的父级 ID(视为根节点)
  • ✅ 自动添加 parent_name 字段
  • ✅ 空数组/非数组输入返回空数组

路由匹配

isInRoutes(route, routes)

检查 API 路由是否在匹配列表中(支持路径参数)。

参数:

| 参数 | 类型 | 说明 | |------|------|------| | route | { method: string, path: string } | 待匹配的路由 | | routes | Array<{ method: string, path: string }> | 路由匹配列表 |

示例:

const routes = [
  { method: "GET", path: "/api/users" },
  { method: "GET", path: "/api/users/:id" },
  { method: "POST", path: "/api/users" },
];

// 精确匹配
Utils.isInRoutes({ method: "GET", path: "/api/users" }, routes);
// true

// 路径参数匹配
Utils.isInRoutes({ method: "GET", path: "/api/users/123" }, routes);
// true

// HTTP 方法不区分大小写
Utils.isInRoutes({ method: "get", path: "/api/users" }, routes);
// true

// 不匹配
Utils.isInRoutes({ method: "POST", path: "/api/posts" }, routes);
// false

特性:

  • ✅ 支持路径参数(如 /users/:id
  • ✅ HTTP 方法不区分大小写
  • ✅ 路径不区分大小写
  • ✅ 安全的 null 输入处理

IP 地址获取

clientIp(req)

从请求对象中获取客户端真实 IP 地址。

参数:

| 参数 | 类型 | 说明 | |------|------|------| | req | Object | Express/Koa 等 HTTP 请求对象 |

IP 获取优先级:

  1. X-Forwarded-For 头(取第一个 IP)
  2. X-Real-IP
  3. req.ip
  4. req.connection.remoteAddress
  5. req.socket.remoteAddress

示例:

// Express 路由中使用
app.get("/api/data", (req, res) => {
  const ip = Utils.clientIp(req);
  console.log(ip); // "192.168.1.1"
});

特性:

  • ✅ 处理代理服务器的多级转发
  • ✅ 自动移除 IPv6 映射前缀 (::ffff:)
  • ✅ 将 IPv6 localhost (::1) 转换为 127.0.0.1
  • ✅ 处理逗号分隔的多个 IP
  • ✅ 支持数组类型的 header
  • ✅ 空 req 对象返回空字符串

典型应用场景:

// Nginx 反向代理配置
// nginx.conf: proxy_set_header X-Real-IP $remote_address;
//             proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

app.use((req, res, next) => {
  const clientIp = Utils.clientIp(req);
  req.clientIp = clientIp; // 挂载到 req 上
  next();
});

🧪 测试

运行测试套件:

npm test
# 或
node test.js

测试覆盖:

  • ✅ UUID 生成(3 个用例)
  • ✅ 格式化方法(7 个用例)
  • ✅ 随机字符串(6 个用例)
  • ✅ 邮箱校验(3 个用例)
  • ✅ 手机号校验(5 个用例)
  • ✅ URL 校验(3 个用例)
  • ✅ 列表转树形结构(7 个用例)
  • ✅ 路由匹配(5 个用例)
  • ✅ 客户端 IP 获取(8 个用例)

总计:47 个测试用例,全部通过 ✅


📝 更新日志

[2.3.0] - 2026-04-30

✨ 新功能

  • 🔐 使用 crypto 模块替代 Math.random() 提升安全性
  • 🎲 randomStr() 新增 charset 参数支持自定义字符集
  • 📱 isPhone() 新增 strict 参数支持国际号码格式

🐛 Bug 修复

  • ✅ 修复 uuid() 生成算法错误(toString(32) → toString(16))
  • ✅ 修复 list2tree() 重复 ID 导致节点重复添加的问题
  • ✅ 修复 isInRoutes() 传入 null 时解构错误

💎 优化改进

  • 📧 优化邮箱正则表达式,支持更多 RFC 标准格式
  • 📱 优化手机号正则表达式,支持最新号段
  • 🌐 使用原生 URL 构造函数替代正则校验 URL
  • 🌳 增强 list2tree() 健壮性(空值处理、重复检测)
  • 🛡️ 完善所有方法的类型安全检查和参数验证
  • 🖥️ 增强 clientIp() 对各种代理场景的支持

🧪 测试

  • 🆕 新增完整测试套件(47 个测试用例)
  • ✅ 100% 公共方法覆盖率
  • ✅ 包含正向/负向测试、边界情况测试

[1.0.1] - 2025-09

  • 初始版本发布

📄 许可证

ISC

🤝 贡献

欢迎提交 Issue 和 Pull Request!


📞 支持

如有问题或建议,请提交 Issue