ph-utils 0.20.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/node.d.ts ADDED
@@ -0,0 +1,115 @@
1
+ import { SpawnOptionsWithoutStdio } from "node:child_process";
2
+ //#region src/crypto_node.d.ts
3
+ type HashAlgorithmName = "md5" | SHAHashAlgorithmName;
4
+ type SHAHashAlgorithmName = "sha1" | "sha256" | "sha512";
5
+ type AESAlgorithmName = "aes-128-cbc" | "aes-192-cbc" | "aes-256-cbc";
6
+ interface HashOptions {
7
+ algorithm?: HashAlgorithmName;
8
+ upper?: boolean;
9
+ }
10
+ interface HmacOptions {
11
+ algorithm?: SHAHashAlgorithmName;
12
+ upper?: boolean;
13
+ }
14
+ interface AESEncryptOptions {
15
+ algorithm?: AESAlgorithmName;
16
+ upper?: boolean;
17
+ }
18
+ interface AESDecryptOptions {
19
+ algorithm?: AESAlgorithmName;
20
+ encoding?: "hex" | "base64";
21
+ }
22
+ interface KeyPairOptions {
23
+ modulusLength?: 2048 | 3072 | 4096;
24
+ }
25
+ /**
26
+ * 计算数据的哈希摘要
27
+ * @example
28
+ * hash("hello world")
29
+ * // "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9"
30
+ */
31
+ declare function hash(data: string, options?: HashOptions): string;
32
+ /**
33
+ * @deprecated 请直接使用 hash 函数
34
+ */
35
+ declare function hashDigest(data: string, options?: HashOptions): string;
36
+ /**
37
+ * 使用 HMAC 算法对消息进行哈希处理
38
+ */
39
+ declare function hmacHash(message: string, key: string, options?: HmacOptions): string;
40
+ /**
41
+ * 生成 RSA 密钥对
42
+ */
43
+ declare function generateRSAKeyPair(options?: KeyPairOptions): Promise<[string, string]>;
44
+ declare function aesEncrypt(key: string, input: string, options?: AESEncryptOptions): [string, string];
45
+ declare function aesDecrypt(input: string, key: string | Buffer, iv?: string | Buffer, options?: AESDecryptOptions): string;
46
+ declare function rsaEncrypt(input: string, publicKey: string, encoding?: BufferEncoding): string;
47
+ declare function rsaDecrypt(encryptedData: string, privateKey: string, encoding?: BufferEncoding): string;
48
+ declare function generateAESKey(bits?: 128 | 192 | 256): string;
49
+ declare function generateIV(): string;
50
+ //#endregion
51
+ //#region src/file.d.ts
52
+ /**
53
+ * 读取文件内容
54
+ * @example <caption>1. 读取JSON文件, 内容为字符串列表</caption>
55
+ * read<string[]>('a.json', []);
56
+ * @example <caption>2. 读取JSON文件, 内容为对象</caption>
57
+ * read<{ name: string }>('b.json', {});
58
+ * @param filepath 文件路径
59
+ * @param defaultValue 文件不存在时默认值, 不传则抛异常, 如果传递的是对象形式则会将结果转换为 JSON
60
+ * @returns 文件内容
61
+ */
62
+ declare function read<T>(filepath: string, defaultValue?: T): Promise<T>;
63
+ /**
64
+ * 写入 JSON 格式的数据到文件
65
+ * @param file 待写入的文件
66
+ * @param data 待写入的数据
67
+ * @param opts 写入配置
68
+ * @property opts.json 是否写入 JSON 格式的数据,写入数据时对数据进行 JSON 格式化,默认为:true
69
+ * @property opts.format 是否在写入 json 数据时,将 JSON 数据格式化2个空格写入, 默认为 true
70
+ */
71
+ declare function write(file: string, data: any, opts?: {
72
+ json: boolean;
73
+ format: boolean;
74
+ }): Promise<void>;
75
+ /**
76
+ * 根据文件的 stat 获取文件的 etag
77
+ * @param filePath 文件地址
78
+ * @returns file stat etag
79
+ */
80
+ declare function statTag(filePath: string): Promise<string>;
81
+ //#endregion
82
+ //#region src/server.d.ts
83
+ /**
84
+ * 执行命令
85
+ * @param command 待执行的命令
86
+ * @param args 命令参数
87
+ */
88
+ declare function exec(command: string, args?: string[]): Promise<{
89
+ stdout: string;
90
+ stderr: string;
91
+ }>;
92
+ declare function exec(command: string, options?: SpawnOptions): Promise<{
93
+ stdout: string;
94
+ stderr: string;
95
+ }>;
96
+ declare function exec(command: string, args?: string[], options?: SpawnOptions): Promise<{
97
+ stdout: string;
98
+ stderr: string;
99
+ }>;
100
+ type SpawnOptions = SpawnOptionsWithoutStdio & {
101
+ shell?: "powershell";
102
+ };
103
+ /**
104
+ * 执行命令并返回执行结果的Promise
105
+ * @param command 要执行的命令
106
+ * @param args 命令参数数组
107
+ * @param options 执行选项,支持指定shell类型
108
+ * @returns Promise对象,成功时resolve包含stdout和stderr的对象,失败时reject包含错误信息
109
+ */
110
+ declare function spawn(command: string, args?: string[], options?: SpawnOptions): Promise<{
111
+ stdout: string;
112
+ stderr: string;
113
+ }>;
114
+ //#endregion
115
+ export { AESAlgorithmName, AESDecryptOptions, AESEncryptOptions, HashAlgorithmName, HashOptions, HmacOptions, KeyPairOptions, SHAHashAlgorithmName, aesDecrypt, aesEncrypt, exec, generateAESKey, generateIV, generateRSAKeyPair, hash, hashDigest, hmacHash, read, rsaDecrypt, rsaEncrypt, spawn, statTag, write };
package/lib/node.js ADDED
@@ -0,0 +1,213 @@
1
+ import { constants, createCipheriv, createDecipheriv, createHash, createHmac, generateKeyPair, privateDecrypt, publicEncrypt, randomBytes } from "node:crypto";
2
+ import path from "node:path";
3
+ import fs from "node:fs/promises";
4
+ import { execFile, spawn as spawn$1 } from "node:child_process";
5
+ import { promisify } from "node:util";
6
+ //#region src/crypto_node.ts
7
+ const DEFAULT_HASH_ALGORITHM = "sha256";
8
+ const DEFAULT_AES_ALGORITHM = "aes-256-cbc";
9
+ const DEFAULT_ENCODING = "hex";
10
+ const IV_LENGTH = 16;
11
+ const RSA_MODULUS_LENGTH = 2048;
12
+ /**
13
+ * 计算数据的哈希摘要
14
+ * @example
15
+ * hash("hello world")
16
+ * // "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9"
17
+ */
18
+ function hash(data, options = {}) {
19
+ const { algorithm = DEFAULT_HASH_ALGORITHM, upper = false } = options;
20
+ const hashed = createHash(algorithm).update(data).digest("hex");
21
+ return upper ? hashed.toUpperCase() : hashed;
22
+ }
23
+ /**
24
+ * @deprecated 请直接使用 hash 函数
25
+ */
26
+ function hashDigest(data, options = {}) {
27
+ return hash(data, options);
28
+ }
29
+ /**
30
+ * 使用 HMAC 算法对消息进行哈希处理
31
+ */
32
+ function hmacHash(message, key, options = {}) {
33
+ const { algorithm = DEFAULT_HASH_ALGORITHM, upper = false } = options;
34
+ const hashed = createHmac(algorithm, key).update(message).digest("hex");
35
+ return upper ? hashed.toUpperCase() : hashed;
36
+ }
37
+ /**
38
+ * 生成 RSA 密钥对
39
+ */
40
+ async function generateRSAKeyPair(options = {}) {
41
+ const { modulusLength = RSA_MODULUS_LENGTH } = options;
42
+ return new Promise((resolve, reject) => {
43
+ generateKeyPair("rsa", {
44
+ modulusLength,
45
+ publicKeyEncoding: {
46
+ type: "spki",
47
+ format: "pem"
48
+ },
49
+ privateKeyEncoding: {
50
+ type: "pkcs8",
51
+ format: "pem"
52
+ }
53
+ }, (err, publicKey, privateKey) => {
54
+ if (err) reject(err);
55
+ else resolve([publicKey, privateKey]);
56
+ });
57
+ });
58
+ }
59
+ function aesEncrypt(key, input, options = {}) {
60
+ const { algorithm = DEFAULT_AES_ALGORITHM, upper = false } = options;
61
+ const requiredKeyLength = parseInt(algorithm.split("-")[1]) / 8;
62
+ const keyBuffer = Buffer.from(key, "hex");
63
+ if (keyBuffer.length !== requiredKeyLength) throw new Error(`Invalid key length for ${algorithm}: expected ${requiredKeyLength} bytes, got ${keyBuffer.length} bytes`);
64
+ const iv = randomBytes(IV_LENGTH);
65
+ const cipher = createCipheriv(algorithm, keyBuffer, iv);
66
+ let encryptedData = cipher.update(input, "utf-8", "hex");
67
+ encryptedData += cipher.final("hex");
68
+ return [upper ? encryptedData.toUpperCase() : encryptedData, iv.toString("hex")];
69
+ }
70
+ function aesDecrypt(input, key, iv, options = {}) {
71
+ const { algorithm = DEFAULT_AES_ALGORITHM, encoding = DEFAULT_ENCODING } = options;
72
+ const keyBuffer = Buffer.isBuffer(key) ? key : Buffer.from(key, "hex");
73
+ const requiredKeyLength = parseInt(algorithm.split("-")[1]) / 8;
74
+ if (keyBuffer.length !== requiredKeyLength) throw new Error(`Invalid key length for ${algorithm}: expected ${requiredKeyLength} bytes, got ${keyBuffer.length} bytes`);
75
+ const ivBuffer = iv ? Buffer.isBuffer(iv) ? iv : Buffer.from(iv, "hex") : Buffer.alloc(IV_LENGTH, 0);
76
+ const decipher = createDecipheriv(algorithm, keyBuffer, ivBuffer);
77
+ let decryptedData = decipher.update(input, encoding, "utf-8");
78
+ decryptedData += decipher.final("utf-8");
79
+ return decryptedData;
80
+ }
81
+ function rsaEncrypt(input, publicKey, encoding = "base64") {
82
+ return publicEncrypt({
83
+ key: publicKey,
84
+ oaepHash: "sha256",
85
+ padding: constants.RSA_PKCS1_OAEP_PADDING
86
+ }, Buffer.from(input, "utf-8")).toString(encoding);
87
+ }
88
+ function rsaDecrypt(encryptedData, privateKey, encoding = "base64") {
89
+ return privateDecrypt({
90
+ key: privateKey,
91
+ oaepHash: "sha256",
92
+ padding: constants.RSA_PKCS1_OAEP_PADDING
93
+ }, Buffer.from(encryptedData, encoding)).toString("utf-8");
94
+ }
95
+ function generateAESKey(bits = 256) {
96
+ return randomBytes(bits / 8).toString("hex");
97
+ }
98
+ function generateIV() {
99
+ return randomBytes(IV_LENGTH).toString("hex");
100
+ }
101
+ //#endregion
102
+ //#region src/file.ts
103
+ /** nodejs 文件操作工具类 */
104
+ /**
105
+ * 读取文件内容
106
+ * @example <caption>1. 读取JSON文件, 内容为字符串列表</caption>
107
+ * read<string[]>('a.json', []);
108
+ * @example <caption>2. 读取JSON文件, 内容为对象</caption>
109
+ * read<{ name: string }>('b.json', {});
110
+ * @param filepath 文件路径
111
+ * @param defaultValue 文件不存在时默认值, 不传则抛异常, 如果传递的是对象形式则会将结果转换为 JSON
112
+ * @returns 文件内容
113
+ */
114
+ async function read(filepath, defaultValue) {
115
+ let content;
116
+ try {
117
+ content = await fs.readFile(filepath, "utf8");
118
+ if (defaultValue != null && typeof defaultValue === "object") return JSON.parse(content);
119
+ return content;
120
+ } catch (error) {
121
+ if (defaultValue === void 0) throw error;
122
+ return defaultValue;
123
+ }
124
+ }
125
+ /**
126
+ * 写入 JSON 格式的数据到文件
127
+ * @param file 待写入的文件
128
+ * @param data 待写入的数据
129
+ * @param opts 写入配置
130
+ * @property opts.json 是否写入 JSON 格式的数据,写入数据时对数据进行 JSON 格式化,默认为:true
131
+ * @property opts.format 是否在写入 json 数据时,将 JSON 数据格式化2个空格写入, 默认为 true
132
+ */
133
+ async function write(file, data, opts) {
134
+ let writeData = data.toString();
135
+ opts = {
136
+ json: true,
137
+ format: true,
138
+ ...opts
139
+ };
140
+ if (opts.json === true && typeof data === "object") writeData = JSON.stringify(data, null, opts.format === true ? 2 : 0);
141
+ await fs.writeFile(path.resolve(file), writeData);
142
+ }
143
+ /**
144
+ * 根据文件的 stat 获取文件的 etag
145
+ * @param filePath 文件地址
146
+ * @returns file stat etag
147
+ */
148
+ async function statTag(filePath) {
149
+ let stat = await fs.stat(filePath);
150
+ return `${stat.size.toString(16)}-${stat.mtimeMs.toString(16)}`;
151
+ }
152
+ //#endregion
153
+ //#region src/server.ts
154
+ const execFilePromise = promisify(execFile);
155
+ /**
156
+ * 执行命令
157
+ * @param cmd 执行的命令
158
+ * @returns
159
+ */
160
+ function exec(command, ...params) {
161
+ let argvs = [];
162
+ const commandItems = command.split(" ");
163
+ const cmd = commandItems.shift();
164
+ if (commandItems.length > 0) argvs = commandItems;
165
+ let opts = { shell: true };
166
+ if (params[0] != null) {
167
+ if (params[0] instanceof Array) {
168
+ argvs.push(...params[0]);
169
+ if (params[1] != null) opts = params[1];
170
+ } else opts = params[0];
171
+ }
172
+ return execFilePromise(cmd, argvs, opts);
173
+ }
174
+ /**
175
+ * 执行命令并返回执行结果的Promise
176
+ * @param command 要执行的命令
177
+ * @param args 命令参数数组
178
+ * @param options 执行选项,支持指定shell类型
179
+ * @returns Promise对象,成功时resolve包含stdout和stderr的对象,失败时reject包含错误信息
180
+ */
181
+ function spawn(command, args, options = {}) {
182
+ return new Promise((resolve, reject) => {
183
+ let execArgs = [];
184
+ let cmd;
185
+ if (options.shell === "powershell") {
186
+ cmd = "powershell.exe";
187
+ execArgs = [
188
+ "-NoProfile",
189
+ "-Command",
190
+ command,
191
+ ...args || []
192
+ ];
193
+ } else {
194
+ cmd = command;
195
+ execArgs = args || [];
196
+ }
197
+ delete options.shell;
198
+ const child = spawn$1(cmd, execArgs, options);
199
+ let stdout = "", stderr = "";
200
+ child.stdout.on("data", (d) => stdout += d);
201
+ child.stderr.on("data", (d) => stderr += d);
202
+ child.on("close", (code) => {
203
+ if (code === 0) resolve({
204
+ stdout,
205
+ stderr
206
+ });
207
+ else reject(/* @__PURE__ */ new Error(`spawn failed (${code}): ${stderr}`));
208
+ });
209
+ child.on("error", reject);
210
+ });
211
+ }
212
+ //#endregion
213
+ export { aesDecrypt, aesEncrypt, exec, generateAESKey, generateIV, generateRSAKeyPair, hash, hashDigest, hmacHash, read, rsaDecrypt, rsaEncrypt, spawn, statTag, write };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ph-utils",
3
- "version": "0.20.0",
3
+ "version": "1.0.0",
4
4
  "description": "js 开发工具集,前后端都可以使用(commonjs和es module)",
5
5
  "keywords": [
6
6
  "date",
@@ -25,75 +25,21 @@
25
25
  "lib"
26
26
  ],
27
27
  "type": "module",
28
- "main": "lib/index.js",
29
- "module": "lib/index.js",
28
+ "sideEffects": false,
30
29
  "browser": "lib/index.js",
31
30
  "types": "lib/index.d.ts",
32
31
  "exports": {
33
- ".": {
34
- "types": "./lib/index.d.ts",
35
- "import": "./lib/index.js"
36
- },
37
- "./file": {
38
- "types": "./lib/file.d.ts",
39
- "import": "./lib/file.js"
40
- },
41
- "./date": {
42
- "types": "./lib/date.d.ts",
43
- "import": "./lib/date.js"
44
- },
45
- "./server": {
46
- "types": "./lib/server.d.ts",
47
- "import": "./lib/server.js"
48
- },
49
- "./validator": {
50
- "types": "./lib/validator.d.ts",
51
- "import": "./lib/validator.js"
52
- },
53
- "./crypto": {
54
- "types": "./lib/crypto.d.ts",
55
- "import": "./lib/crypto.js"
56
- },
57
- "./crypto_node": {
58
- "types": "./lib/crypto_node.d.ts",
59
- "import": "./lib/crypto_node.js"
60
- },
61
- "./web": {
62
- "types": "./lib/web.d.ts",
63
- "import": "./lib/web.js"
64
- },
65
- "./dom": {
66
- "types": "./lib/dom.d.ts",
67
- "import": "./lib/dom.js"
68
- },
69
- "./copy": {
70
- "types": "./lib/copy.d.ts",
71
- "import": "./lib/copy.js"
72
- },
73
- "./storage": {
74
- "types": "./lib/storage.d.ts",
75
- "import": "./lib/storage.js"
76
- },
77
- "./color": {
78
- "types": "./lib/color.d.ts",
79
- "import": "./lib/color.js"
80
- },
81
- "./logger": {
82
- "types": "./lib/logger.d.ts",
83
- "import": "./lib/logger.js"
84
- },
85
- "./array": {
86
- "types": "./lib/array.d.ts",
87
- "import": "./lib/array.js"
88
- },
89
- "./theme": {
90
- "types": "./lib/theme.d.ts",
91
- "import": "./lib/theme.js"
92
- },
93
- "./*": "./lib/*"
32
+ ".": "./lib/index.js",
33
+ "./browser": "./lib/browser.js",
34
+ "./node": "./lib/node.js",
35
+ "./package.json": "./package.json"
36
+ },
37
+ "scripts": {
38
+ "build": "tsdown"
94
39
  },
95
40
  "devDependencies": {
96
41
  "@types/node": "^22.8.2",
42
+ "tsdown": "^0.22.14",
97
43
  "typescript": "^5.6.3"
98
44
  }
99
45
  }
package/lib/array.d.ts DELETED
@@ -1,79 +0,0 @@
1
- /**
2
- * 数组排序
3
- * @param arr 待排序数组
4
- * @param order 排序信息, asc - 升序, desc - 倒序
5
- * @param orderKey 如果是个对象数组,按哪个字段排序
6
- * @returns
7
- */
8
- export declare function order<T>(arr: T[], order?: "asc" | "desc", orderKey?: string | null): T[];
9
- /**
10
- * 返回一个所有集合交集的新集合
11
- *
12
- * 如果集合本身支持 intersection, 则调用原生 intersection 函数
13
- *
14
- * @param arrs
15
- *
16
- * @returns 新集合中的元素在传入的所有集合中同时存在
17
- */
18
- export declare function intersection<T>(...arrs: Set<T>[]): Set<T>;
19
- /**
20
- * 返回一个所有列表交集的新列表
21
- *
22
- * @param arrs
23
- *
24
- * @returns 新列表中的元素在传入的所有列表中同时存在
25
- */
26
- export declare function intersection<T>(...arrs: T[][]): T[];
27
- /**
28
- * 返回一个包含第一个集合中的元素但不包含后续给定集合中元素的新集合
29
- *
30
- * 如果集合本身支持 difference 方法,则调用原生 difference 方法
31
- *
32
- * @param arrs 集合列表
33
- *
34
- * @returns
35
- */
36
- export declare function difference<T>(...arrs: Set<T>[]): Set<T>;
37
- /**
38
- * 返回一个包含第一个列表中的元素但不包含后续给定列表中元素的新列表
39
- *
40
- * @param arrs 二维列表
41
- *
42
- * @returns
43
- */
44
- export declare function difference<T>(...arrs: T[][]): T[];
45
- /**
46
- * 返回多个集合的并集, 如果支持 union,则调用原生 union
47
- *
48
- * @param arrs
49
- *
50
- * @returns 一个包含所有给定集合的所有元素的新集合
51
- */
52
- export declare function union<T>(...arrs: Set<T>[]): Set<T>;
53
- export declare function union<T>(...arrs: T[][]): T[];
54
- export declare function symmetricDifference<T>(...arrs: Set<T>[]): Set<T>;
55
- export declare function symmetricDifference<T>(...arrs: T[][]): T[];
56
- /**
57
- * 返回一个布尔值,指示此集合中的所有元素是否都在给定的集合中。
58
- * @param a1
59
- * @param a2
60
- * @returns
61
- */
62
- export declare function isSubsetOf<T>(a1: T[] | Set<T>, a2: T[] | Set<T>): boolean;
63
- /**
64
- * 返回一个布尔值,指示给定集合中的所有元素是否都在此集合中。
65
- * @param arr1
66
- * @param arr2
67
- * @returns
68
- */
69
- export declare function isSupersetOf<T>(arr1: T[] | Set<T>, arr2: T[] | Set<T>): boolean;
70
- /**
71
- * 返回一个布尔值,指示此集合是否与给定集合没有公共元素。
72
- *
73
- * 判断两个集合是否有交集, 也可以通过 intersection(arr1, arr2).length 判断
74
- *
75
- * @param arr1
76
- * @param arr2
77
- * @returns
78
- */
79
- export declare function isDisjointFrom<T>(arr1: T[] | Set<T>, arr2: T[] | Set<T>): boolean;