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

utils-ok

v2.0.0

Published

useful utils

Readme

utils-ok

一站式 Node.js 工具库 —— 字符串处理、文件操作、异步工具、云存储、数据库、AI 对话、自动化测试,开箱即用。

特性

  • 跨平台 —— macOS / Windows / Linux 全兼容
  • 按需引用 —— 每个模块独立导出,tree-shaking 友好
  • 内置日志 —— 自带 wLogger,零配置即可输出结构化日志
  • 云原生 —— 集成阿里云 OSS / MinIO / MySQL / OpenAI / 钉钉机器人
  • 工程化 —— 内置 ESLint / blacklint 检查、Git 工具、Hosts 管理等 CLI 辅助

安装

pnpm add utils-ok
# 或
npm install utils-ok
# 或
yarn add utils-ok

快速开始

import { strUtil, fileUtil, asyncUtil, baseUtil } from 'utils-ok';

// 字符串处理
strUtil.md5('hello');           // MD5 哈希
strUtil.random(16);             // 随机字符串
strUtil.md2html('# 标题');       // Markdown → HTML

// 文件操作
fileUtil.delete('/tmp/a.txt');  // 删除文件
fileUtil.tmpFile('.json');      // 获取临时文件路径
fileUtil.getJSON('/path/to/config.json');

// 异步工具
await asyncUtil.sleep(1000);    // 延时 1 秒

// 加密 & 工具
baseUtil.encrypt('data', 'key'); // DES 加密
baseUtil.uuid();                 // UUID v7
baseUtil.retry(fn, 3, 1000);     // 重试 3 次,间隔 1 秒

API 参考

📦 数据处理

strUtil — 字符串工具

| 方法 | 说明 | |------|------| | parseDBUri(uri) | 解析数据库 URI,提取 host/port/user/pass/db | | isJsonStr(str) | 判断是否为合法 JSON 字符串 | | safeIntNumber(val) | 安全转整数 | | safeBoolean(val) | 安全转布尔值 | | md5(str) | MD5 哈希 | | hasUnicode(str) | 检测是否含 Unicode 字符 | | isSimilar(str1, str2, opts) | 字符串相似度比较 | | isSimilarCn(str1, str2) | 中文相似度比较 | | md2html(markdown) | Markdown 转 HTML(带样式) | | sqlStr(str) | 转义 SQL 字符串中的单引号 | | regExp(str) | 字符串 → RegExp 对象 | | random(len, prefix) | 生成随机字母数字字符串 | | randomCn(len) | 生成中文数字字符串 | | uid(n) | 生成唯一 ID | | cutStrByLength(str, len) | 按长度切割字符串 | | cutStrTail(length, str) | 截断尾部字符串 | | cleanColor(str) | 清除 ANSI 颜色码 |

arrUtil — 数组工具

| 方法 | 说明 | |------|------| | sum(arr) | 数字数组求和 | | getMostSimilar(target, list) | 从列表中找最相似项 | | getUniq(list) | 字符串数组去重 | | getUniqByKey(list, key) | 对象数组按 key 去重 | | getUniqBySimilar(list, rate) | 按相似度去重 |

objUtil — 对象工具

| 方法 | 说明 | |------|------| | search(obj, key) | 递归搜索对象中的匹配项 | | isRegExp(str) | 判断是否为合法正则 | | clean(obj, keepEmptyStr) | 清除 null/undefined 键 | | cleanKey(obj, key) | 递归删除指定键 | | isObj(val) | 判断是否为普通对象 | | isAsyncFunc(fn) | 判断是否为异步函数 |

numUtil — 数字工具

| 方法 | 说明 | |------|------| | randomInt(len) | 生成指定长度随机整数 |

dateUtil — 日期工具

| 方法 | 说明 | |------|------| | mm | moment 实例(中文 locale) | | getTime(hours, sec) | 获取时间戳,可选偏移 | | humanizeDuration(begin, end) | 人性化时长显示 | | isWorkDay(date) | 是否工作日 | | isFriday(date) | 是否周五 | | isMonthEnd(date) | 是否月末 |

📁 文件 & Shell

fileUtil — 文件操作

| 方法 | 说明 | |------|------| | cp(from, to) | 拷贝文件或文件夹 | | mockFile(target, sizeMb) | 生成指定大小的文件 | | delete(file) | 删除文件或文件夹 | | tmpFile(ext) | 获取临时文件路径 | | tmpdir() | 系统临时目录路径 | | getSizeKb(target) | 文件/文件夹大小 (KB) | | checkPath(target) | 路径合法性检查 | | clean(file) | 清空文件内容 | | deleteOldFiles(dir, opts) | 按时间删除旧文件 | | rename(old, new) | 重命名文件 | | genEmptyFile(opts) | 创建空白文件 | | cleanDir(dir) | 清空文件夹 | | saveTempFile(urlOrStr) | 下载 URL 或保存字符串为临时文件 | | saveTempFileSync(url) | 同步下载文件 | | saveFileStr(str, dest) | 保存字符串到文件(异步) | | saveFileStrSync(str, dest) | 保存字符串到文件(同步) | | saveFileUrl(url, dest, name) | 通过 URL 保存文件 | | getFileStr(target) | 读取文件字符串 | | getFileRowCount(target) | 获取文件行数 | | getMd5(file) | 计算文件 MD5(异步) | | getMd5ByShell(file) | 计算文件 MD5(同步) | | getFileBufferByUrl(url) | 通过 HTTP 获取文件 Buffer | | getJsonByUrl(url) | 通过 HTTP 获取 JSON 数据 | | getFirstLine(target) | 读取文件第一行 | | getLines(target, limit) | 读取文件行数组 | | getTailLinesStr(target, lines) | 读取末尾几行 | | getHeadLinesStr(target, lines) | 读取开头几行 | | createFile(target, data) | 创建文件并写入初始数据 | | getJSON(target) | 读取 JSON 文件 | | img2base64(target) | 图片转 base64 | | dirWalker(dir) | 递归遍历文件夹 | | lineOfCode(opts) | 代码行数统计(依赖 cloc) | | savePressFileAndDeploy(url, dest) | 下载压缩包并自动解压 |

shUtil — Shell 工具

| 方法 | 说明 | |------|------| | processExist(name) | 进程是否存在(跨平台) | | pidExist(pid) | 指定 PID 是否存在 | | safeKill(pid) | 安全终止进程树 | | cmdExist(cmd) | 命令是否存在(跨平台) | | timeOut(cmd, sec) | 命令超时执行 | | findFilesByText(opts) | 按内容搜索文件(跨平台) | | getMacSysRunTimeInfo() | macOS 系统运行信息¹ | | getMacAvailStorage() | macOS 剩余存储空间¹ | | isHdpiDisplay() | 检测 Retina / 4K 显示器¹ | | nohup(cmd, sec) | 后台运行命令(仅 Unix) | | log(cmd, logname) | 命令输出重定向到日志 |

¹ 仅 macOS 可用,Windows/Linux 调用时返回 undefined 并输出 warning。

hostUtil — Hosts 管理

| 方法 | 说明 | |------|------| | getHosts(format) | 获取 hosts 文件内容 | | bak(bakFile) | 备份 hosts 文件 | | restoreBak(bakFile) | 从备份恢复 | | check(ip, host) | 检查 hosts 映射 | | upsert(ip, host) | 插入或更新映射 | | remove(host, ip) | 删除映射 | | setHosts(hosts) | 批量设置映射 | | cleanHosts(hosts) | 批量清理映射 | | removeHosts(hosts) | 批量删除映射 |

⚡ 异步 & 基础工具

asyncUtil — 异步工具

| 方法 | 说明 | |------|------| | sleep(ms, tick) | 异步延时,可选每秒打印进度 |

baseUtil — 基础工具

| 方法 | 说明 | |------|------| | sleep(ms) | 异步延时(re-export) | | deeplog(obj, depth) | 深度打印对象内容 | | getEnv(key) | 获取环境变量 | | getProcessBar(total) | 创建命令行进度条 | | store(key, value) | 本地 KV 文件缓存读写 | | encrypt(str, key, iv) | DES 加密 | | decrypt(encrypted, key, iv) | DES 解密 | | genRsaKeyPairByNodeRsa() | 生成 RSA 密钥对 | | rsaEncrypt(pubKey, raw) | RSA 公钥加密 | | rsaDecrypt(priKey, data) | RSA 私钥解密 | | uuid() | 生成 UUID v7 | | getLocalIP() | 获取本机局域网 IP | | waitUntil(fn, waitMs, intervalMs) | 等待直到条件满足 | | warpPromise(promise, timeout) | Promise 超时 + 中断 | | retry(fn, count, interval) | 异步重试 | | safeRequire(file) | 清除缓存后加载模块 | | getCallerData() | 获取调用堆栈信息 | | getDepsPkgVersion(path, name) | 获取依赖包版本号 | | logRes(resp) | 格式化打印响应数据 |

resUtil — 响应构建

| 方法 | 说明 | |------|------| | success(data) | 成功响应 { code: 200 } | | error(message) | 服务器错误 { code: 500 } | | authError(message) | 认证错误 { code: 401 } | | paramError(message) | 参数错误 { code: 400 } | | formatRes(data, code, msg) | 自定义响应构建 |

🌐 网络 & 客户端

OssClient — 阿里云 OSS

import { OssClient } from 'utils-ok';

const oss = new OssClient({
  region: 'oss-cn-hangzhou',
  bucket: 'my-bucket',
  accessKeyId: 'AK',
  accessKeySecret: 'SK',
});

await oss.put('./local.txt', 'remote.txt');     // 上传
await oss.get('remote.txt', './download.txt');   // 下载
await oss.putTxt('hello', 'hello.txt');          // 上传字符串
await oss.putJSON({ key: 'value' }, 'data.json');// 上传 JSON
const content = await oss.getFileStr('file.txt');// 读取内容
await oss.postDir('./dist', 'oss-dist/');        // 上传整个目录

| 方法 | 说明 | |------|------| | put(localFile, ossFile) | 上传本地文件 | | putUrl(url, ossFile) | URL 转存 | | putTxt(str, ossFile) | 上传字符串 | | putJSON(obj, ossFile) | 上传 JSON 对象 | | store(key, obj, merge) | 存储/更新 JSON 对象(支持合并) | | get(ossFile, localFile) | 下载文件 | | getFilesByPath(ossDir, destDir) | 下载文件夹 | | getFileStr(ossFile) | 读取为字符串 | | getJSON(ossFile) | 读取并解析 JSON | | deleteFile(ossFile) | 删除文件 | | deleteFolder(ossPath) | 递归清空文件夹 | | exist(ossFile) | 检查是否存在 | | getFiles(ossPath) | 获取文件列表 | | getFolders(ossPath) | 获取子文件夹列表 | | postDir(localPath, ossFile) | 递归上传目录 | | postDirZip(localPath, ossFile) | 压缩为 ZIP 上传 | | postDirTarGz(localPath, ossFile) | 压缩为 tar.gz 上传 | | setLifeCycle(days) | 设置生命周期规则 | | getLifeCycle() | 查询生命周期规则 | | delLifeCycle() | 删除生命周期规则 |

MinioClient — MinIO 对象存储

API 与 OssClient 类似,额外支持:

| 方法 | 说明 | |------|------| | getTmpUrl(ossFile, expires) | 获取临时下载链接(默认 1h) | | uploadFile(localFile, ossFile) | 上传本地文件 | | uploadDir(localPath, ossDir) | 递归上传目录 | | downloadDir(ossDir, destDir) | 下载目录 | | downloadFile(ossFile, localFile) | 下载文件 | | getStr(ossFile) | 读取为字符串 | | uploadDirZip(localPath, ossFile) | 压缩为 ZIP 上传 | | uploadDirTarGz(localPath, ossFile) | 压缩为 tar.gz 上传 | | setBucketPolicyGetFree(bktName) | 设置 bucket 为公开读取 | | ossExist(ossFile) | 检查文件或目录是否存在 |

MysqlClient / DBClient — MySQL 数据库

import { DBClient } from 'utils-ok';

const db = new DBClient({ uri: 'mysql://user:pass@host:3306/dbname' });
// 内部基于 Sequelize,支持 Model 定义
await db.close();

DingClient — 钉钉机器人

import { DingClient } from 'utils-ok';

const ding = new DingClient('your-access-token', 'secret-key');
await ding.send('Hello, 钉钉!');
await ding.sendMd('通知标题', '## 正文内容');

| 方法 | 说明 | |------|------| | send(msg, atMobiles, atUserIds) | 发送文本消息,支持 @ 用户 | | sendMd(title, msg, atMobiles, atUserIds) | 发送 Markdown 消息 |

OpenAiClient — OpenAI 对话

import { OpenAiClient } from 'utils-ok';

const ai = new OpenAiClient({ apiKey: 'sk-xxx' });
const reply = await ai.chatCn('你好');

| 方法 | 说明 | |------|------| | chat(prompt) | 简单对话 | | chatCn(prompt) | 中文系统提示对话 | | chatEn(prompt) | 英文系统提示对话 | | createChatCompletion(messages, opts) | 创建聊天补全 | | createCompletion(prompt, opts) | 创建补全请求 |

PopClient — 阿里云 POP SDK

封装阿里云 POP 通用调用客户端。

SlsClient — 阿里云 SLS 日志服务

封装阿里云 SLS 日志服务客户端。

YuqueClient — 语雀 API

封装语雀知识库 API 客户端。

🛠️ 工程辅助

gitUtil — Git 工具

| 方法 | 说明 | |------|------| | safeCheckout(opts) | 安全检出分支/commit(带超时重试) | | getGitDir() | 获取 Git 仓库根目录 | | getBranchName() | 获取当前分支名 | | getBranchDiffFiles(opts) | 获取工作分支 diff 文件列表 | | getBranchSourceCommit() | 获取当前分支起点 commit | | getLastCommit(opts) | 获取最后一次 commit 详情 | | formatGitHttpUrl(remote) | Git SSH URL → HTTP URL 转换 | | getPRList(branch) | 查询分支上的 PR 列表 |

lintUtil — Lint 工具

| 方法 | 说明 | |------|------| | lintProj(opts) | 全量 lint(eslint + blacklint + tsc + 用例规范) | | lintFixProj() | 自动修复 lint 问题 + 清除 .only() 标记 | | eslint() | 单独执行 eslint 检查 | | tscLint() | 单独执行 tsc 类型检查 | | blackLint(dirs) | 单独执行 blacklint 检查 | | testDirLint(testDir) | 用例命名规范检查 |

ProjUtil — 项目路径工具

import { ProjUtil } from 'utils-ok';

const proj = new ProjUtil(__dirname);
proj.getPkgVersion();     // 获取版本号
proj.getResourcePath();   // 获取 resource 目录
proj.bin('eslint', true); // 执行 node_modules/.bin 下的命令

| 方法 | 说明 | |------|------| | getPkgVersion() | 获取 package.json 版本号 | | getPkg() | 读取 package.json | | getProjPath() | 获取项目路径 | | getRootProjPath() | 获取项目根路径 | | getResourcePath() | 获取 resource 目录 | | getModulesPath() | 获取 node_modules 路径 | | bin(cmd, async, silent) | 执行 .bin 下的命令 |

ffmpegUtil — 视频处理

| 方法 | 说明 | |------|------| | mov2mp4(fileMov, fileMp4) | MOV → MP4 转码 | | addPoster(srcMp4, pngFile) | 插入封面首帧 | | getVideoLastImg(srcMp4, destPng) | 提取视频最后一帧 | | setVideoLastImgAsPoster(srcMp4) | 设置视频最后一帧为封面 |

🤖 浏览器自动化

WebDriver — Playwright 浏览器驱动

import { WebDriver } from 'utils-ok';

const driver = new WebDriver({ headless: true });
await driver.init();
await driver.goto('https://example.com');
await driver.clickOn('#submit');
await driver.checkText('提交成功');
await driver.stop();

| 方法 | 说明 | |------|------| | init() | 初始化浏览器 | | stop() | 关闭浏览器 | | goto(url) | 导航到 URL | | clickOn(selector) | 点击元素 | | input(text, selector) | 输入文本 | | check(selector) | 检查元素存在 | | checkText(text) | 检查页面包含文本 | | checkMulti(selectors) | 并行检查多个选择器 | | checkNotExists(selector) | 检查元素不存在 | | getText(selector) | 获取元素文本 | | waitForElement(selector, timeout) | 等待元素出现 | | waitForAny(selectors, opts) | 等待任意选择器出现 | | waitForFocusByCSS(css) | 等待元素获得焦点 | | getElement(selector, opts) | 查找单个元素 | | getElementsCount(selector) | 获取匹配元素数量 | | hover(selector) | 鼠标悬停 | | pressKeys(key, ...more) | 键盘按键 | | mouse(action, ...args) | 鼠标操作 | | keyboard(action, ...args) | 键盘操作 | | dragAndDrop(source, target, ...) | 拖拽元素 | | elementScreenShot(opts) | 元素截图 | | redirect(url) | JS 重定向 | | curl(clean) | 获取当前 URL | | execute(script, args) | 执行页面 JS | | coverage(opts) | 代码覆盖率收集 | | webFetch(opts) | 前端注入执行 fetch | | mixin(api) | 混入自定义方法 |

RemoteLoginClient — 远程登录

import { RemoteLoginClient } from 'utils-ok';

const client = new RemoteLoginClient({
  ip: '192.168.1.100',
  username: 'root',
  password: 'pass',
});
await client.ssh('ls -la');  // SSH 远程执行命令
await client.vnc();          // macOS 打开 VNC 连接

| 方法 | 说明 | |------|------| | ssh(cmd) | SSH 远程执行命令 | | vnc() | 打开 VNC 连接(macOS) |

📋 日志

项目内置 wLogger(基于 winston),支持多级别日志输出:

import { wLogger } from 'utils-ok';

const logger = wLogger();
logger.info('应用启动');
logger.debug('调试信息', { data: [1, 2, 3] });
logger.error('出错了', error);

跨平台支持

| 模块 | macOS | Windows | Linux | |------|:-----:|:-------:|:-----:| | 数据处理 (strUtil/arrUtil/...) | ✅ | ✅ | ✅ | | 文件操作 (fileUtil) | ✅ | ✅ | ✅ | | Shell 工具 (shUtil) | ✅ | ✅¹ | ✅ | | Hosts 管理 (hostUtil) | ✅ | ✅ | ✅ | | Git 工具 (gitUtil) | ✅ | ✅² | ✅ | | 云存储 (OssClient/MinioClient) | ✅ | ✅ | ✅ | | 数据库 (DBClient) | ✅ | ✅ | ✅ | | 浏览器自动化 (WebDriver) | ✅ | ✅ | ✅ | | AI 对话 (OpenAiClient) | ✅ | ✅ | ✅ | | 钉钉机器人 (DingClient) | ✅ | ✅ | ✅ |

¹ getMacSysRunTimeInfoisHdpiDisplaynohup 为 Unix/macOS 专属功能。 ² Windows 需要安装 Git for Windows。

版本历史

| 版本 | 说明 | |------|------| | 2.0.0 | 全面跨平台重构,支持 Windows/macOS/Linux | | 1.x | 初始版本,仅 macOS/Linux |

License

MIT