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.8.0

Published

Node.js 服务端通用工具库 - 提供零依赖微信小程序 SDK、DEDS 签名防重放守卫、统一响应封装、Token 服务、通用 HTTP 客户端、常用工具方法等

Readme

公共服务 SDK (public-sdk)

npm version license

版本: 2.7.0 | Node.js: >= 18.0.0

Node.js 服务端工具库,提供零依赖微信与抖音小程序 SDK、DEDS 动态接口签名守卫、统一响应封装、Token 登录态管理服务、原生 Http 客户端及常用通用工具方法。

特性

  • 零外部依赖:基于 Node.js 18+ 原生驱动实现 Http 客户端,无第三方运行时依赖。
  • 双端小程序 SDK:提供微信(WX)与抖音(DY)小程序 OpenAPI 完整封装,支持凭证自愈重试、多环境自适应与实例级超时配置。
  • 接口签名与防重放:提供 DEDS 动态接口签名守卫与恒定时间安全比对(timingSafeEqualSign),支持动态密钥派生、魔数过滤与基于 Redis 的防重放中间件。
  • 密码学安全:基于 Node.js crypto 模块实现安全的随机数、UUID 与 Token 签名。
  • 测试覆盖:包含异步单元测试套件,覆盖核心模块与极端边界场景。
  • 模块支持:支持 ES Module 与 CommonJS 双规范导出。

交流讨论

QQ群:666713758

前后端协同机制

本项目与前端 SDK public-client-sdk 提供对应的接口设计与协同机制:

| 能力维度 | 服务端 (public-sdk) | 客户端 (public-client-sdk) | 机制说明 | | :--- | :--- | :--- | :--- | | 接口防篡改与防重放 | SignatureGuard (Express 中间件) | DEDSSigner (加签发生器) | 动态时间片 KDF、参数排序混淆、4 字节魔数初筛与 Redis 单次消费防重放 | | 统一数据响应与解包 | Send.success / Send.fail | UniRequestClient / Fetch / Axios | 统一响应结构与状态码,客户端自动解包 body.data 并处理登录失效拦截 | | 跨端排他路由锁 | - | UniversalRouter (小程序/Web/App) | 排他锁控制,防止跳转未完成时的并发连点与页面栈异常 | | 统一多端持久化缓存 | - | UniversalStorage (多端统一 Storage) | 统一多端本地存储接口,支持指定秒级/毫秒级过期时间(TTL) | | 实时长连接消息推送 | ws-service / Redis PubSub | SocketClient (WebSocket 客户端) | 心跳探活、指数退避重连与离线消息缓冲队列 | | 时间漂移校准 | /common/timestamp | setServerTimeOffset | 服务端时间戳校准,消除客户端设备时钟漂移 |


安装

npm install public-sdk

快速开始

微信小程序 SDK

import { WX } from "public-sdk";

const wx = new WX({
  appid: "your-appid",
  secret: "your-secret",
  botOpenid: "your-bot-openid", // 可选:保活机器人 openid,非小程序端调用安全接口时用于兜底
  env_version: "develop",       // develop | trial | release(默认 release);与 wechatEnv 等价
});

// 获取 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,
});

// 1. 文本内容安全识别 (微信 msg_sec_check 2.0)
// 支持小程序端传入 openid,或在 Web/APP 端省略 openid(自动使用机器人兜底)
const secResult = await wx.checkSensitiveWords("待检测文本内容", {
  scene: 2, // 1资料, 2评论(默认), 3论坛, 4社交日志
  nickname: "用户昵称",
});
// secResult: { bool: false, message: '未包含敏感词', suggest: 'pass' }

// 也可显式传入 openid(若用户长期未活跃触发 61010,底层将自动借用机器人重试):
// await wx.checkSensitiveWords("待检测文本内容", userOpenid, { scene: 2 });

// 2. 异步多媒体内容安全识别 (微信 media_check_async 2.0,支持图片/音频)
const mediaResult = await wx.checkMediaAsync({
  media_url: "https://example.com/sample.jpg",
  media_type: 2, // 1 音频, 2 图片
  scene: 1,      // 1 资料, 2 评论, 3 论坛, 4 社交日志
  // openid,     // 可选,未传或用户未活跃时自动走 botOpenid 兜底
});
// mediaResult: { success: true, trace_id: 'xxxx', errcode: 0, errmsg: 'ok' }

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

发送订阅消息(2.5.0+)

import { WX } from "public-sdk";

const wx = new WX({ appid: "xxx", secret: "xxx", env_version: "release" });

// 自动截断超长 thing* 字段,并根据配置注入 miniprogram_state
const result = await wx.sendSubscribeMessage({
  touser: "openid_xxx",
  templateId: "TEMPLATE_ID",
  data: {
    thing2: { value: "今日学习提醒" },      // 超长内容自动截断至 20 字符
    thing6: { value: "请及时完成今日任务" },
    time3: { value: "2026-07-21 09:00" },
  },
  page: "pages/index/index",
  // miniprogramState: "formal",  // 可选,覆盖默认配置
});

if (result.success) {
  console.log("发送成功");
} else {
  console.error("失败:", result.errmsg);
}

抖音小程序 SDK(2.7.0+)

零外部依赖对接抖音开放平台 OpenAPI(官方服务端根域名 https://open.douyin.com),支持凭证自动缓存、40001/40002/40014 自愈重试与实例级超时配置:

import { DY } from "public-sdk";

const dy = new DY({
  appid: "your-client-key",
  secret: "your-client-secret",
  env_version: "release", // develop | trial | release(与 douyinEnv 等价)
  timeout: 8000,          // 可选:自定义请求超时时长(默认 8000ms)
});

// 1. 获取 access_token(自动缓存至过期前 5 分钟)
const accessToken = await dy.getAccessToken();

// 2. 登录凭证校验 (code2session)
const session = await dy.code2Session("login_code_xxx");
// session: { openid: 'xxx', session_key: 'xxx', unionid: 'xxx', anonymous_openid: 'xxx' }

// 3. 生成小程序码 (createQRCode)
const qrBuffer = await dy.createQRCode({
  path: "pages/index/index",
  width: 430,
});

// 4. 内容安全文本反垃圾检测 (checkSensitiveWords)
const secResult = await dy.checkSensitiveWords("待检测文本内容");
// secResult: { bool: false, message: '未包含敏感词' }

// 5. 获取手机号 (getPhoneNumber)
const phoneInfo = await dy.getPhoneNumber("phone_code_xxx");

// 6. 发送订阅消息 (sendSubscribeMessage)
const msgResult = await dy.sendSubscribeMessage({
  to_user_id: "openid_xxx",
  template_id: "TEMPLATE_ID",
  data: {
    thing1: "系统通知", // 自动截断超长字段
    time2: "2026-09-18 15:00",
  },
  page: "pages/index/index",
});

DEDS 接口签名与防重放守卫(2.6.0+)

基于动态密钥派生、参数排序签名、魔数过滤与 Redis 防重放机制,为 Express 服务端提供接口安全校验中间件:

import express from 'express'
import { SignatureGuard } from 'public-sdk'
import redis from './utils/redis'

const app = express()

// 1. 初始化签名守卫实例
const signGuard = new SignatureGuard({
  kernelSeed: 0x5f3759df, // 项目专属掩码种子
  redis,                  // Redis 实例 (用于单次消费防重放)
  timeWindowMs: 300000,   // 5 分钟有效容差窗口
  whitelist: ['/pay/wx/notify', '/health', '/common/timestamp']
})

// 2. 挂载中间件
app.use('/api', signGuard.middleware())

原生 Http 客户端(2.6.0+)

基于 Node.js 原生驱动封装,无第三方依赖,提供简洁的请求接口与拦截器机制:

import { Http } from 'public-sdk'

// 1. 快捷请求
const res = await Http.get('https://api.example.com/users')
console.log(res.data)

// 2. 实例模式
const client = Http.create({
  baseURL: 'https://api.weixin.qq.com',
  timeout: 5000,
  headers: { 'X-Custom-Header': 'value' }
})

// 3. 拦截器支持
client.interceptors.request.use((config) => {
  config.headers['Authorization'] = 'Bearer token'
  return config
})

const result = await client.post('/cgi-bin/stable_token', { appid: 'xxx', secret: 'xxx' })

静态工具:截断微信 thing 字段

WX.truncateThing("很长的内容...");  // 截断到 20 字符内

响应数据统一封装

import { Send } from "public-sdk";

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

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

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

// 格式化错误信息
Send.formatError(error); // { code: 500, message: '服务器错误', timestamp: 1694524800000 }

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

工具类 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)

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

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

特性:

  • 支持多级嵌套解析
  • 自动跳过重复 ID 的项并输出警告
  • 兼容父级 ID 为 null/undefined 的根节点判定
  • 自动维护 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)

从 HTTP 请求对象中获取客户端真实 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 本地回环 (::1) 规范化为 127.0.0.1
  • 支持逗号分隔的多 IP 解析
  • 兼容数组类型的 HTTP header
  • 空请求对象返回空字符串

典型应用配置:

// Nginx 代理配置示例:
// proxy_set_header X-Real-IP $remote_address;
// proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

app.use((req, res, next) => {
  req.clientIp = Utils.clientIp(req);
  next();
});

字符串截断(2.5.0+)

通用字符串长度截断工具,适用于微信 thing 字段等长度受限场景。

Utils.truncate("很长的内容...", 20);          // 截断到 20 字符,超长添加 '...'
Utils.truncate("很长的内容...", 10, '…');      // 自定义省略符
Utils.truncate(null);                          // 返回空字符串(安全不抛错)

Token 服务(2.5.0+)

通用的 Token 登录态管理服务,支持单设备互斥、多端登录与滑动续期。

import { TokenService } from "public-sdk";

// 注入 Redis 客户端(兼容 ioredis / node-redis / 任意实现 get/set/del/expire 的对象)
const token = new TokenService(redis, {
  prefix: "my-app",       // 键名前缀,默认 'token'
  expire: 86400,          // 过期时间(秒),默认 24 小时
  singleDevice: true,     // 单设备互斥,默认 true
});

// 保存登录态
const t = await token.save(userId, { userId, role: "user" });

// 校验 Token(验证失败抛出 Error,statusCode = 401)
const info = await token.verify(t);

// 滑动续期
await token.refresh(t);

// 注销
await token.revoke(t);

// 强制下线(按 userId 维度)
await token.revokeByUserId(userId);

特性:

  • 采用三键映射设计(token-account / account-token / account-info),保障快速校验
  • 单设备互斥模式:新 Token 自动使旧 Token 失效
  • 多设备模式(singleDevice: false):按 Token 维度隔离存储用户信息
  • 兼容多种 Redis 客户端(ioredis、node-redis 或 Mock 对象)
  • 鉴权异常附带 statusCode = 401,便于中间件统一捕获

测试

运行测试套件:

npm test
# 或
node test.js

测试覆盖:

  • UUID 生成(3 个用例)
  • 账号格式化方法(4 个用例)
  • 密码格式化方法(3 个用例)
  • 随机字符串(6 个用例)
  • 邮箱校验(3 个用例)
  • 手机号校验(5 个用例)
  • URL 校验(3 个用例)
  • 列表转树形结构(7 个用例)
  • 路由匹配(5 个用例)
  • 客户端 IP 获取(8 个用例)
  • 字符串截断(5 个用例)
  • WX 静态工具(3 个用例)
  • WX 构造与 wechatEnv(6 个用例)
  • TokenService(6 个用例)
  • Http 客户端(2 个用例)
  • DEDS 签名与防重放守卫(3 个用例)
  • DY 抖音小程序 SDK(6 个用例)
  • 深度优化与健壮性专项(8 个用例)

总计:86 个测试用例全部通过


更新日志

[2.7.0] - 2026-09-18

新增

  • DY 抖音小程序 SDK:新增 DY 模块(./utils/applet/dy),提供凭证获取(含自动重试与缓存)、登录校验(code2Session)、小程序码生成、文本内容安全检测、手机号解密与订阅消息推送等完整能力。
  • 实例级超时配置:WX 与 DY 构造函数新增 timeout 参数,支持为各 SDK 实例独立配置 HTTP 请求超时时长。
  • 恒定时间签名比对:导出 timingSafeEqualSign 工具函数,防范针对 API 签名的时序侧信道攻击(Timing Attack)。

修复与增强

  • Send.formatError 循环引用防御:增强错误格式化鲁棒性,针对包含循环引用的复杂对象增加安全序列化保护,杜绝二次崩溃。
  • list2tree 拓扑死循环防御:新增多节点相互循环引用拓扑检测,遇脏数据环路时自动阻断挂载并降级为根节点,避免内存溢出与 JSON 序列化崩溃。
  • truncate 边界截取防护:修复在 max <= suffix.length 极端场景下截断后字符串长度超出上限的问题。
  • TokenService 多设备全量清理:多设备登录模式下维护 Redis 活跃 Token 集合,支持通过 revokeByUserId 一键注销该用户全量在线设备。
  • 测试框架异步调度升级:重构 test.js 为支持 async/await 的异步队列调度执行器,消除异步断言提前通过隐患。
  • 环境要求规范:修正 Node.js 运行引擎要求为 >=18.0.0,与底层原生 fetch 与 crypto 原生特性对齐。

[2.6.0] - 2026-08-21

新增

  • Http 客户端:基于 Node.js 原生驱动实现,支持拦截器、实例创建(Http.create)、超时中断与 Buffer 数据接收。
  • DEDS 接口签名守卫 (SignatureGuard):实现基于动态密钥派生、魔数初筛与 Redis 单次防重放的 Express 中间件。

优化

  • 零依赖改造:清空 package.json 中的 dependencies 依赖项,改用内置模块实现。
  • 微信 SDK 驱动重构:WX 模块切换至原生 Http 驱动,并完善 Buffer 处理机制。
  • 配置规范统一:移除历史环境变量 WECHAT_MINIPROGRAM_STATE,统一支持构造函数传参(env_version / wechatEnv)。
  • 测试用例补充:测试用例扩充至 72 个。

[2.5.1] - 2026-08-05

修复

  • WX.getAccessToken 改用稳定版接口 /cgi-bin/stable_token:采用稳定版接口替代旧接口,默认 force_refresh=false,消除多进程/多实例并发刷新相互挤掉 token (40001) 的问题。
  • 新增 _withToken 凭证失效自动重试:微信接口返回 40001/42001(access_token 失效)时,自动以 force_refresh=true 刷新并重试一次。
  • 修复 getUnlimitedQRCode 错误响应识别:增加对 Node 环境下返回 Buffer 的判定与解析,异常时提取 errcode/errmsg 抛出。
  • 提升 checkSensitiveWords 容错:增加 errcode 状态校验与空详情数组兜底。

优化

  • 缓存字段语义调整:expires_in 调整为绝对时间戳 expiresAt,过期判定采用 Date.now() >= expiresAt。
  • 文档与类型声明同步更新。

重要说明

  • 本版本保持向后兼容,API 接口无破坏性变更。
  • 多进程或集群部署推荐保持默认 force_refresh=false。

[2.5.0] - 2026-07-21

新增

  • WX.sendSubscribeMessage():支持发送订阅消息,自动处理字段长度限制与环境参数。
  • TokenService:通用 Token 管理服务,支持单设备互斥、多设备登录与滑动续期。
  • Utils.truncate():通用字符串截断工具。
  • WX.truncateThing():微信 thing 字段专用截断方法。

修复

  • 修复多设备登录场景下 account-info 覆盖问题(非单设备模式下按 Token 维度隔离)。

优化

  • package.json 新增 ./utils/Token 导出路径。
  • 完善订阅消息与 TokenService 文档示例。
  • 测试用例扩充至 65 个。

[2.4.0] - 2026-05-28

新增

  • 随机数生成改用 Node.js crypto 模块。
  • randomStr() 支持 charset 自定义字符集。
  • isPhone() 支持 strict 宽松模式校验国际号码。

修复

  • 修复 uuid() 进制转换问题。
  • 修复 list2tree() 重复 ID 节点重复添加问题。
  • 修复 isInRoutes() 传入 null 时的空指针异常。

优化

  • 优化邮箱与手机号校验正则。
  • URL 校验改用原生 URL 构造函数。
  • 完善 list2tree() 边界处理。
  • Send 统一响应格式补充 timestamp 字段。

测试

  • 新增单元测试套件,覆盖核心公共方法。

[2.3.0] - 2025-12

文档

  • 重写 README.md,补充 API 接口与使用示例。

配置

  • 完善 package.json 元数据配置与 LICENSE 声明。

新增

  • isPhone() 支持国际号码格式校验。

修复

  • 修复 uuid() 算法缺陷。
  • 修复 list2tree() 树形转换重复节点问题。
  • 修复 isInRoutes() 边界解构异常。

优化

  • 优化参数校验与异常处理机制。

[1.0.1] - 2025-09

  • 初始版本发布。

许可证

ISC

参与贡献

欢迎提交 Issue 与 Pull Request。

问题反馈

如遇问题或有功能建议,请提交至 Issue 列表。