@moneko/utils
v0.3.5
Published
[npm-url]: https://npmjs.org/package/@moneko/utils [install-tag]: https://nodei.co/npm/@moneko/utils.png [version-tag]: https://img.shields.io/npm/v/@moneko/utils/latest.svg?logo=npm [size-tag]: https://packagephobia.com/badge?p=%40moneko%2Futils@latest [
Readme
@moneko/utils
🐾 🐾 🐾 🐾
简介
@moneko/utils 是一个功能丰富的跨平台工具库,提供文件操作、格式转换、证书生成、终端输出、网络工具等多种实用功能。由 Rust 编写,通过 NAPI-RS 暴露给 JavaScript,性能卓越。
安装
npm install @moneko/utils或使用 pnpm/yarn:
pnpm add @moneko/utils
yarn add @moneko/utils功能模块
📁 文件操作
基础读写
loadFile(filepath: string): Promise<string>- 异步读取文件loadFileSync(filepath: string): string | null- 同步读取文件saveFile(filepath: string, data: string): Promise<boolean>- 异步写入文件saveFileSync(filepath: string, data: string): boolean- 同步写入文件loadFileRaw(filepath: string): Promise<Array<number>>- 异步读取二进制文件saveFileRaw(filepath: string, data: Array<number>): Promise<boolean>- 异步保存二进制数据
文件追加与更新
appendToFile(filepath: string, data: string): Promise<boolean>- 异步追加内容到文件末尾appendToFileSync(filepath: string, data: string): boolean- 同步追加内容到文件末尾updateFile(filepath: string, data: string): Promise<boolean>- 异步更新文件内容updateFileSync(filepath: string, data: string): boolean- 同步更新文件内容
文件复制与删除
copyFile(source: string, destination: string): Promise<boolean>- 异步复制文件copyFileSync(src: string, dest: string): Promise<boolean>- 同步复制文件removeFile(path: string): boolean- 删除文件fileExists(filepath: string): boolean- 检查文件是否存在
目录操作
createDir(dirPath: string): boolean- 创建文件夹(包含必要的父级文件夹)removeDir(path: string): boolean- 删除目录及其所有内容(谨慎使用!)- ⚠️ 此函数不遵循符号链接,它只会删除符号链接本身
deleteEmptyDirs(dirpath: string): void- 递归删除空目录directoryExists(dirPath: string): boolean- 检查文件夹是否存在scanFolderSync(folderpath: string, condition?: Array<string>): Array<string>- 扫描文件夹renameFiles(dirpath: string, patterns: [string, string]): boolean- 重命名文件夹下的所有文件
文件操作示例:
import {
loadFile,
saveFile,
copyFile,
removeFile,
createDir,
scanFolderSync,
renameFiles,
appendToFile,
updateFile,
fileExists,
directoryExists
} from '@moneko/utils';
// 读取文件
const content = await loadFile('path/to/file.txt');
console.log(content);
// 保存文件
await saveFile('path/to/output.txt', 'Hello World');
// 同步读写
const syncContent = loadFileSync('config.json');
saveFileSync('backup.json', syncContent);
// 读取二进制文件
const buffer = await loadFileRaw('image.png');
// 复制文件
await copyFile('source.txt', 'destination.txt');
copyFileSync('src/file.js', 'dist/file.js');
// 追加内容
await appendToFile('log.txt', 'New log entry\n');
appendToFileSync('output.txt', 'appended text');
// 更新文件
await updateFile('config.json', '{"updated": true}');
// 检查文件/目录
if (fileExists('file.txt')) {
console.log('File exists');
}
if (!directoryExists('output')) {
createDir('output');
createDir('path/to/nested/directory');
}
// 删除文件和目录
removeFile('temp.txt');
removeDir('path/to/directory'); // 删除目录及其所有内容
// 递归删除空目录
deleteEmptyDirs('lib');
// 扫描文件夹
const files = scanFolderSync('lib', ['.*\\.js$', '.*\\.ts$']);
console.log(files); // ['file1.js', 'file2.ts', ...]
// 重命名文件夹下的所有文件
renameFiles('lib', ['\\.js$', '.mjs']);
// 将所有 .js 文件重命名为 .mjs🔄 格式转换
YAML 转换
parseYaml(filepath: string): Promise<string | null>- 解析 YAML 文件为 JSON 字符串parseYamlSync(filepath: string): string | null- 同步解析 YAML 文件parseYamlString(yamlString: string): Promise<string | null>- 解析 YAML 字符串parseYamlStringSync(yamlString: string): string | null- 同步解析 YAML 字符串jsonToYaml(jsonString: string): Promise<string | null>- 将 JSON 转换为 YAMLjsonToYamlSync(jsonString: string): string | null- 同步将 JSON 转换为 YAML
YAML 示例:
import { parseYaml, parseYamlString, jsonToYaml, jsonToYamlSync } from '@moneko/utils';
// 读取并解析 YAML 文件
const config = await parseYaml('config.yml');
const obj = JSON.parse(config);
// 解析 YAML 字符串
const yaml = `
name: example
version: 1.0.0
items:
- id: 1
name: item1
`;
const parsed = await parseYamlString(yaml);
console.log(JSON.parse(parsed)); // { name: 'example', version: 1, items: [...] }
// JSON 转 YAML
const json = { name: 'test', version: '1.0.0', tags: ['a', 'b'] };
const yamlOutput = await jsonToYaml(JSON.stringify(json));
console.log(yamlOutput);
// name: test
// version: 1.0.0
// tags:
// - a
// - b
// 同步转换
const yamlSync = jsonToYamlSync(JSON.stringify(json));Plist 转换(iOS/macOS)
parsePlist(filepath: string): Promise<string>- 解析 Plist 文件为 JSON 字符串parsePlistString(value: string): Promise<string>- 解析 Plist 字符串为 JSONbuildPlist(data: string): Promise<string>- 构建 JSON 字符串为 Plist 格式
Plist 示例:
import { parsePlist, parsePlistString, buildPlist } from '@moneko/utils';
// 解析 Info.plist 文件
const infoPlist = await parsePlist('Info.plist');
const config = JSON.parse(infoPlist);
console.log(config.CFBundleIdentifier);
// 解析 Plist 字符串
const plistStr = `<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "...">
<plist version="1.0">
<dict>
<key>Name</key>
<string>Test</string>
</dict>
</plist>`;
const parsed = await parsePlistString(plistStr);
console.log(JSON.parse(parsed)); // { Name: 'Test' }
// 构建 Plist
const data = JSON.stringify({ Name: 'App', Version: '1.0' });
const plistOutput = await buildPlist(data);
console.log(plistOutput); // XML 格式的 PlistXML 转换
parseXml(filePath: string): string- 将 XML 文件转换为 JSON 字符串parseXmlToJson(xmlContent: string): string- 将 XML 字符串转换为 JSON 字符串buildXml(jsonContent: string): string- 将 JSON 字符串转换为 XML
XML 示例:
import { parseXml, parseXmlToJson, buildXml } from '@moneko/utils';
// 解析 XML 文件
const xmlData = parseXml('data.xml');
const obj = JSON.parse(xmlData);
console.log(obj);
// 解析 XML 字符串
const xml = `<?xml version="1.0"?>
<root>
<user id="1">
<name>John</name>
<email>[email protected]</email>
</user>
</root>`;
const json = parseXmlToJson(xml);
console.log(JSON.parse(json));
// {
// root: {
// user: {
// '@id': '1',
// name: 'John',
// email: '[email protected]'
// }
// }
// }
// JSON 转 XML
const data = { root: { item: 'value', count: 1 } };
const xmlOutput = buildXml(JSON.stringify(data));
console.log(xmlOutput);
// <?xml version="1.0"?>
// <root>
// <item>value</item>
// <count>1</count>
// </root>🗜️ 压缩与编码
compression(source: Array<number>, algo?: string, level?: number): Array<number>- 压缩数据(Gzip/Brotli)algo: 压缩算法,默认gzip,可选brotlilevel: 压缩级别,默认使用各算法默认级别
compressionByFilepath(filePath: string, algo?: string, level?: number): Array<number>- 按文件路径压缩文件compressImage(imagePath: string, sizeFactor: number, quality: number): void- 压缩图片
压缩示例:
import { compression, compressionByFilepath, compressImage, saveFileRaw } from '@moneko/utils';
// 压缩数据
const data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const compressed = compression(data, 'gzip', 6);
console.log(`原始大小: ${data.length}, 压缩后: ${compressed.length}`);
// 使用 Brotli 压缩
const brotliCompressed = compression(data, 'brotli', 11);
// 按文件路径压缩
const result = compressionByFilepath('large-file.bin', 'gzip', 9);
saveFileRaw('large-file.bin.gz', result);
// 压缩图片
compressImage('photo.jpg', 0.8, 80);
// sizeFactor: 缩放比例 (0-1),1.0 = 原始大小
// quality: 图片质量 (0-100)🖨️ 终端输出
彩色文本
ink(text: string, color: string, options?: InkOptions): string- 为终端输出创建彩色文本- 支持基础颜色:
red,green,blue,yellow,cyan,magenta,white,black - 支持 RGB 格式:
"255,0,0" - 支持 ANSI256:
"123"
- 支持基础颜色:
interface InkOptions {
bg?: string; // 背景色
bold?: boolean; // 粗体
intense?: boolean; // 高亮
italic?: boolean; // 斜体
underline?: boolean; // 下划线
}输出函数
print(text: string, clear?: boolean): void- 输出文本到控制台println(text: string, clear?: boolean): void- 输出文本到控制台并换行termClear(mode?: number): boolean- 清除终端输出mode=0: 从光标位置到屏幕末尾(默认)mode=1: 从屏幕开始到光标位置mode=2: 整个屏幕mode=3: 整个屏幕和滚动缓冲区
进度条与完成信息
progressBar(current: number, max: number, options?: ProgressBarOptions): void- 显示进度条completedInfo(duration: number, output: string): void- 显示完成信息
interface ProgressBarOptions {
name?: string; // 进度条名称
msg?: string; // 显示的消息
nameColor?: string; // 名称颜色
msgColor?: string; // 消息颜色
barColor?: string; // 进度条颜色
barBgColor?: string; // 进度条背景颜色
}终端输出示例:
import { ink, print, println, termClear, progressBar, completedInfo } from '@moneko/utils';
// 彩色输出
console.log(`${ink("错误", "red")} 连接失败`);
console.log(`${ink("成功", "green")} 数据已保存`);
console.log(`${ink("警告", "255,165,0")} 操作需要审批`); // 橙色 RGB
console.log(ink("提示", "39")); // ANSI256 深蓝色
// 高级样式
console.log(ink("粗体", "blue", { bold: true }));
console.log(ink("下划线", "cyan", { underline: true }));
console.log(ink("红底白字", "white", { bg: "red", bold: true }));
// 普通输出
print("你好"); // 输出但不换行
println("操作完成"); // 输出并换行
print("加载中...", true); // 清行后输出(适用于进度条)
// 进度条
for (let i = 0; i <= 100; i++) {
progressBar(i, 100, {
name: '下载',
nameColor: 'cyan',
barColor: 'green'
});
}
// 显示完成信息
const startTime = Date.now();
// ... 执行操作 ...
const duration = Date.now() - startTime;
completedInfo(duration, 'build');
// 清除终端
termClear(0); // 从光标清到末尾
termClear(2); // 清除整个屏幕
termClear(3); // 清除屏幕和历史📊 数据分析与转换
analyzeBundleSize(filepath: string, condition?: Array<string>): void- 分析文件体积convert(num: number): string- 大小转换(字节转人类可读格式)
数据分析示例:
import { analyzeBundleSize, convert } from '@moneko/utils';
// 分析打包体积
analyzeBundleSize('dist', ['.*\\.js$', '.*\\.css$']);
// 输出:
// dist/index.js: 1.2 MB
// dist/style.css: 150 KB
// 总大小: 1.35 MB
// 字节转换
console.log(convert(1024)); // "1.0 KB"
console.log(convert(1048576)); // "1.0 MB"
console.log(convert(1073741824)); // "1.0 GB"
console.log(convert(512)); // "512 B"🌐 网络与 Hosts
getHostsPath(): string- 获取 hosts 文件路径(跨平台)- macOS/Linux:
/etc/hosts - Windows:
C:\Windows\System32\drivers\etc\hosts
- macOS/Linux:
checkHost(ip: string, domain: string): boolean- 检查 hosts 文件中是否存在指定映射addHost(ip: string, domain: string): boolean- 追加 IP 和域名的映射到 hosts 文件
Hosts 示例:
import { getHostsPath, checkHost, addHost } from '@moneko/utils';
const hostsPath = getHostsPath();
console.log(`Hosts 文件路径: ${hostsPath}`);
// 检查是否已存在映射
if (!checkHost('127.0.0.1', 'local.example.com')) {
// 如果不存在,添加映射
const success = addHost('127.0.0.1', 'local.example.com');
if (success) {
console.log('Hosts 映射添加成功');
}
}
// 检查其他映射
if (checkHost('192.168.1.1', 'router.local')) {
console.log('路由器映射已存在');
}🔐 证书管理
接口定义
interface GenerateCertificateParams {
// 证书绑定的主域名(支持通配符域名)
// @example ["local.example.com", "localhost", "127.0.0.1"]
subjectAltNames?: Array<string>;
// 国家代码(两位大写字母,遵循 ISO 3166 标准)
// @example "CN" // 中国
countryName?: string;
// 州/省名称(全称,不包含缩写)
// @example "Shanghai"
stateOrProvinceName?: string;
// 城市/地区名称(需为完整行政区划名称)
// @example "Beijing"
localityName?: string;
// 组织机构全称(需为合法注册的实体名称)
// @example "Acme Corporation"
organizationName?: string;
// 组织机构部门名称(具体业务部门名称)
// @example "IT Department"
organizationUnitName?: string;
// 通用名称(通常显示在证书详情中的主体标识)
// 对于 SSL 证书通常与域名一致
// @example "local.example.com"
commonName?: string;
}
interface CertificateResult {
cert: string; // 证书内容(PEM 格式)
key: string; // 私钥内容(PEM 格式)
}
interface Certificates {
cert?: string; // 签名证书
key?: string; // 签名证书私钥
rootCa: string; // 根证书(PEM 格式)
rootKey: string; // 根证书私钥(PEM 格式)
}证书生成函数
generateRootCertificateAuthority(option: GenerateCertificateParams): CertificateResult- 生成根证书generateCertificate(params: GenerateCertificateParams): Certificates- 生成完整证书(包含根证书和签名证书)generateCert(issuer: string, issuerKey: string, subjectAltNames: Array<string>): CertificateResult- 根据颁发者证书生成签名证书normalCertificateAuthority(): CertificateResult- 获取默认的预设根证书
证书示例:
import {
generateRootCertificateAuthority,
generateCertificate,
generateCert,
normalCertificateAuthority,
saveFileSync
} from '@moneko/utils';
// 方式1: 一步生成完整证书
const certs = generateCertificate({
subjectAltNames: ['localhost', '127.0.0.1', '*.example.com'],
countryName: 'CN',
stateOrProvinceName: 'Shanghai',
localityName: 'Shanghai',
organizationName: 'My Company',
organizationUnitName: 'IT Department',
commonName: 'local.example.com'
});
saveFileSync('./certs/root.pem', certs.rootCa);
saveFileSync('./certs/root-key.pem', certs.rootKey);
saveFileSync('./certs/server.pem', certs.cert);
saveFileSync('./certs/server-key.pem', certs.key);
// 方式2: 分步生成(先生成根证书,再生成签名证书)
const rootCA = generateRootCertificateAuthority({
countryName: 'CN',
stateOrProvinceName: 'Beijing',
localityName: 'Beijing',
organizationName: 'My Root CA',
commonName: 'My Root CA'
});
saveFileSync('./certs/ca.pem', rootCA.cert);
saveFileSync('./certs/ca-key.pem', rootCA.key);
// 使用根证书签名服务器证书
const serverCert = generateCert(
rootCA.cert,
rootCA.key,
['localhost', '127.0.0.1', 'api.example.com']
);
saveFileSync('./certs/server.pem', serverCert.cert);
saveFileSync('./certs/server-key.pem', serverCert.key);
// 方式3: 使用预设根证书
const presetCA = normalCertificateAuthority();
const clientCert = generateCert(
presetCA.cert,
presetCA.key,
['client.example.com']
);
// 用于 Express/Node.js HTTPS 服务器
const https = require('https');
const fs = require('fs');
const options = {
key: fs.readFileSync('./certs/server-key.pem'),
cert: fs.readFileSync('./certs/server.pem')
};
https.createServer(options, (req, res) => {
res.writeHead(200);
res.end('Hello HTTPS World!');
}).listen(443);🍎 iOS/macOS 特有功能
bundleIpa(bundleDir: string, outputBundleDir: string, ipaType: string): void- 打包 IPA 文件bundleDir: 要打包的文件夹的目录路径outputBundleDir: 输出 IPA 文件的保存路径ipaType: 打包类型(如app-store,ad-hoc,development)
iOS 打包示例:
import { bundleIpa } from '@moneko/utils';
// 打包生成的 .app 文件为 IPA
bundleIpa(
'./build/Release-iphoneos',
'./output',
'app-store'
);
// 其他打包类型
bundleIpa('./build/Release-iphoneos', './output', 'ad-hoc');
bundleIpa('./build/Release-iphoneos', './output', 'development');⚙️ Promise 工具
awaitPromise(p: Promise<boolean>): Promise<boolean>- 等待 Promise 执行
import { awaitPromise } from '@moneko/utils';
async function example() {
const result = await awaitPromise(someAsyncOperation());
console.log(result);
}完整示例
示例1:文件处理流程
import {
fileExists,
directoryExists,
createDir,
saveFile,
loadFile,
scanFolderSync,
ink,
println
} from '@moneko/utils';
async function processFiles() {
const sourceDir = './source';
const outputDir = './processed';
// 创建输出目录
if (!directoryExists(outputDir)) {
createDir(outputDir);
println(`${ink('✓', 'green')} 创建目录成功`);
}
// 扫描源文件
const files = scanFolderSync(sourceDir, ['.*\\.txt$']);
println(`${ink(`找到 ${files.length} 个文件`, 'cyan')}`);
// 处理每个文件
for (const file of files) {
try {
const content = await loadFile(`${sourceDir}/${file}`);
const processed = content.toUpperCase();
const outputFile = `${outputDir}/${file}`;
await saveFile(outputFile, processed);
println(`${ink('✓', 'green')} 处理完成: ${outputFile}`);
} catch (error) {
println(`${ink('✗', 'red')} 处理失败: ${file} - ${error.message}`);
}
}
println(`${ink('完成!', 'green', { bold: true })}`);
}
processFiles();示例2:Web 服务器 SSL 证书生成与使用
import {
generateRootCertificateAuthority,
generateCert,
saveFileSync,
fileExists,
createDir,
directoryExists
} from '@moneko/utils';
import https from 'https';
import fs from 'fs';
import express from 'express';
async function setupSSLServer() {
const certDir = './certs';
// 确保证书目录存在
if (!directoryExists(certDir)) {
createDir(certDir);
}
const rootCertPath = `${certDir}/root.pem`;
const rootKeyPath = `${certDir}/root-key.pem`;
const serverCertPath = `${certDir}/server.pem`;
const serverKeyPath = `${certDir}/server-key.pem`;
let rootCA;
// 检查根证书是否存在
if (fileExists(rootCertPath)) {
console.log('使用现有的根证书');
rootCA = {
cert: fs.readFileSync(rootCertPath, 'utf-8'),
key: fs.readFileSync(rootKeyPath, 'utf-8')
};
} else {
// 生成新的根证书
console.log('生成新的根证书...');
rootCA = generateRootCertificateAuthority({
countryName: 'CN',
stateOrProvinceName: 'Shanghai',
localityName: 'Shanghai',
organizationName: 'Example Corp',
organizationUnitName: 'IT',
commonName: 'Example Root CA'
});
saveFileSync(rootCertPath, rootCA.cert);
saveFileSync(rootKeyPath, rootCA.key);
}
// 生成服务器证书
console.log('生成服务器证书...');
const serverCert = generateCert(
rootCA.cert,
rootCA.key,
['localhost', '127.0.0.1', '*.example.local']
);
saveFileSync(serverCertPath, serverCert.cert);
saveFileSync(serverKeyPath, serverCert.key);
// 创建 HTTPS 服务器
const app = express();
app.get('/', (req, res) => {
res.send('Hello HTTPS World!');
});
const httpsOptions = {
key: fs.readFileSync(serverKeyPath),
cert: fs.readFileSync(serverCertPath)
};
https.createServer(httpsOptions, app).listen(443, () => {
console.log('HTTPS 服务器运行在 https://localhost');
});
}
setupSSLServer();示例3:批量处理和格式转换
import {
scanFolderSync,
loadFile,
saveFile,
parseXml,
buildXml,
jsonToYaml,
progressBar,
ink,
println
} from '@moneko/utils';
async function convertXmlFiles() {
const inputDir = './data/xml';
const outputDir = './data/json';
// 扫描所有 XML 文件
const xmlFiles = scanFolderSync(inputDir, ['.*\\.xml$']);
println(`${ink(`开始转换 ${xmlFiles.length} 个 XML 文件`, 'cyan')}`);
for (let i = 0; i < xmlFiles.length; i++) {
const xmlFile = xmlFiles[i];
try {
// 读取 XML 文件
const xmlContent = await loadFile(`${inputDir}/${xmlFile}`);
// 转换为 JSON
const jsonContent = parseXml(`${inputDir}/${xmlFile}`);
// 保存 JSON
const jsonFileName = xmlFile.replace('.xml', '.json');
await saveFile(`${outputDir}/${jsonFileName}`, jsonContent);
// 转换为 YAML
const yamlContent = await jsonToYaml(jsonContent);
const yamlFileName = xmlFile.replace('.xml', '.yaml');
await saveFile(`${outputDir}/${yamlFileName}`, yamlContent);
// 显示进度
progressBar(i + 1, xmlFiles.length, {
name: '转换',
nameColor: 'cyan',
barColor: 'green'
});
} catch (error) {
println(`${ink(`✗ 转换失败: ${xmlFile}`, 'red')}`);
}
}
println(`${ink('转换完成!', 'green', { bold: true })}`);
}
convertXmlFiles();示例4:项目构建和文件整理
import {
scanFolderSync,
analyzeBundleSize,
convert,
renameFiles,
progressBar,
completedInfo,
ink
} from '@moneko/utils';
async function buildProject() {
const startTime = Date.now();
console.log(ink('开始构建项目...', 'cyan', { bold: true }));
// 扫描输出目录
const jsFiles = scanFolderSync('dist', ['.*\\.js$']);
const cssFiles = scanFolderSync('dist', ['.*\\.css$']);
console.log(`${ink('✓', 'green')} 找到 ${jsFiles.length} 个 JS 文件和 ${cssFiles.length} 个 CSS 文件`);
// 分析打包体积
console.log('\n分析打包体积:');
analyzeBundleSize('dist', ['.*\\.(js|css|json)$']);
// 重命名文件为 .mjs
console.log(`\n${ink('重命名文件...', 'cyan')}`);
renameFiles('dist', ['\\.js$', '.mjs']);
// 显示完成信息
const duration = Date.now() - startTime;
completedInfo(duration, '构建');
}
buildProject();API 速查表
| 功能 | 函数名 | 同步版本 | 异步版本 | |------|--------|---------|---------| | 读取文件 | loadFile | ✅ | ✅ | | 写入文件 | saveFile | ✅ | ✅ | | 追加内容 | appendToFile | ✅ | ✅ | | 更新内容 | updateFile | ✅ | ✅ | | 复制文件 | copyFile | ✅ | ✅ | | 删除文件 | removeFile | ✅ | ✗ | | 创建目录 | createDir | ✅ | ✗ | | 删除目录 | removeDir | ✅ | ✗ | | 扫描目录 | scanFolderSync | ✅ | ✗ | | 解析 YAML | parseYaml | ✅ | ✅ | | 解析 XML | parseXml | ✅ | ✗ | | 解析 Plist | parsePlist | ✗ | ✅ | | 生成证书 | generateCertificate | ✅ | ✗ | | 彩色输出 | ink | ✅ | ✗ | | 进度条 | progressBar | ✅ | ✗ |
性能说明
- 所有文件操作都是通过 Rust 实现,性能远优于 Node.js 原生 API
- 大文件操作(>100MB)建议使用二进制接口(loadFileRaw, saveFileRaw)
- 递归操作(如 removeDir, deleteEmptyDirs)在处理大目录时性能最优
浏览器兼容性
本库为 Node.js 专用,不支持浏览器环境。
常见问题
Q: 如何在 Windows 上修改 hosts 文件?
A: 需要以管理员身份运行 Node.js 进程。
// Windows 上需要管理员权限
import { addHost } from '@moneko/utils';
addHost('127.0.0.1', 'example.local'); // 需要管理员Q: 证书生成后如何在浏览器中信任?
A:
- macOS: 打开钥匙串访问,导入根证书,设置为信任
- Linux: 将根证书复制到
/usr/local/share/ca-certificates/, 运行update-ca-certificates - Windows: 运行
certmgr.msc,导入根证书到"受信任的根证书颁发机构"
Q: 如何处理大文件?
A: 对于大文件(>100MB),建议使用二进制接口:
const buffer = await loadFileRaw('large-file.bin');
// 处理数据
await saveFileRaw('output.bin', buffer);许可证
MIT

