@jayfong/x-utils 3.3.0 → 3.4.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/ai.d.mts +103 -0
- package/lib/ai.mjs +75 -0
- package/lib/cache.d.mts +464 -0
- package/lib/cache.mjs +531 -0
- package/lib/captcha.d.mts +259 -0
- package/lib/captcha.mjs +174 -0
- package/lib/chinese.d.mts +19 -1
- package/lib/chinese.mjs +28 -1
- package/lib/cli.d.mts +25 -37
- package/lib/cli.mjs +25 -22
- package/lib/crawler.d.mts +1 -1
- package/lib/crawler.mjs +1 -1
- package/lib/crypto.d.mts +158 -0
- package/lib/crypto.mjs +213 -0
- package/lib/data_set.mjs +3 -3
- package/lib/db_value.d.mts +213 -0
- package/lib/db_value.mjs +208 -0
- package/lib/dispose.d.mts +98 -0
- package/lib/dispose.mjs +107 -0
- package/lib/file_store.d.mts +167 -0
- package/lib/file_store.mjs +120 -0
- package/lib/fs.d.mts +64 -2
- package/lib/fs.mjs +65 -3
- package/lib/html.d.mts +103 -0
- package/lib/html.mjs +112 -0
- package/lib/jwt.d.mts +128 -0
- package/lib/jwt.mjs +104 -0
- package/lib/mail.d.mts +125 -0
- package/lib/mail.mjs +108 -0
- package/lib/pay.d.mts +394 -0
- package/lib/pay.mjs +343 -0
- package/lib/puppeteer.mjs +3 -3
- package/lib/random.d.mts +71 -0
- package/lib/random.mjs +92 -0
- package/lib/redis.d.mts +32 -0
- package/lib/redis.mjs +24 -0
- package/lib/runner.d.mts +52 -24
- package/lib/runner.mjs +31 -15
- package/lib/sensitive_words.d.mts +82 -0
- package/lib/sensitive_words.mjs +73 -0
- package/lib/sms.d.mts +133 -0
- package/lib/sms.mjs +100 -0
- package/lib/task.d.mts +1 -1
- package/lib/task.mjs +4 -4
- package/package.json +35 -3
package/lib/crypto.d.mts
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 常用加解密与摘要工具。
|
|
3
|
+
*
|
|
4
|
+
* 提供 Base64 / Base64URL 编解码、常见哈希摘要(MD5、SHA-1、
|
|
5
|
+
* SHA-256、SHA-512),以及 AES-128-ECB 对称加解密能力,所有方法
|
|
6
|
+
* 均为静态方法,可直接通过 `XCrypto.xxx()` 调用。
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* XCrypto.md5('123456') // 'e10adc3949ba59abbe56e057f20f883e'
|
|
10
|
+
* XCrypto.base64UrlEncode('{"userId":"doit"}') // 'eyJ1c2VySWQiOiJkb2l0In0'
|
|
11
|
+
*
|
|
12
|
+
* @remarks
|
|
13
|
+
* - MD5 与 SHA-1 已被视为不安全算法,仅建议用于校验等非安全场景;
|
|
14
|
+
* - AES 采用 ECB 模式,相同明文加密结果固定,不适用于需要语义安全的
|
|
15
|
+
* 场景(建议改用 CBC / GCM 等带随机 IV 的模式);
|
|
16
|
+
* - 加解密密钥会自动规范化为 16 字节(不足补零、超出截断)。
|
|
17
|
+
*/
|
|
18
|
+
export declare class XCrypto {
|
|
19
|
+
/**
|
|
20
|
+
* 将文本编码为 Base64 字符串。
|
|
21
|
+
*
|
|
22
|
+
* @param text 需要编码的原始文本。
|
|
23
|
+
* @returns Base64 编码后的字符串。
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* XCrypto.base64Encode('{"userId":"doit"}') // 'eyJ1c2VySWQiOiJkb2l0In0='
|
|
27
|
+
* XCrypto.base64Encode('🐲') // '8J+Qsg=='
|
|
28
|
+
*/
|
|
29
|
+
static base64Encode(text: string): string;
|
|
30
|
+
/**
|
|
31
|
+
* 将 Base64 字符串解码为 UTF-8 文本。
|
|
32
|
+
*
|
|
33
|
+
* @param text Base64 编码的字符串。
|
|
34
|
+
* @returns 解码后的 UTF-8 文本。
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* XCrypto.base64Decode('eyJ1c2VySWQiOiJkb2l0In0=') // '{"userId":"doit"}'
|
|
38
|
+
* XCrypto.base64Decode('8J+Qsg==') // '🐲'
|
|
39
|
+
*/
|
|
40
|
+
static base64Decode(text: string): string;
|
|
41
|
+
/**
|
|
42
|
+
* 将文本编码为 URL 安全的 Base64(Base64URL)字符串。
|
|
43
|
+
*
|
|
44
|
+
* 与标准 Base64 的区别:`+` 替换为 `-`、`/` 替换为 `_`,并去除
|
|
45
|
+
* 末尾的 `=` 填充,使其可直接用于 URL 查询参数等场景。
|
|
46
|
+
*
|
|
47
|
+
* @param text 需要编码的原始文本。
|
|
48
|
+
* @returns Base64URL 编码后的字符串。
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* XCrypto.base64UrlEncode('{"userId":"doit"}') // 'eyJ1c2VySWQiOiJkb2l0In0'
|
|
52
|
+
* XCrypto.base64UrlEncode('🐲') // '8J-Qsg'
|
|
53
|
+
*/
|
|
54
|
+
static base64UrlEncode(text: string): string;
|
|
55
|
+
/**
|
|
56
|
+
* 将 Base64URL 字符串解码为 UTF-8 文本。
|
|
57
|
+
*
|
|
58
|
+
* @param text Base64URL 编码的字符串。
|
|
59
|
+
* @returns 解码后的 UTF-8 文本。
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* XCrypto.base64UrlDecode('eyJ1c2VySWQiOiJkb2l0In0') // '{"userId":"doit"}'
|
|
63
|
+
* XCrypto.base64UrlDecode('8J-Qsg') // '🐲'
|
|
64
|
+
*/
|
|
65
|
+
static base64UrlDecode(text: string): string;
|
|
66
|
+
/**
|
|
67
|
+
* 计算文本的 MD5 摘要。
|
|
68
|
+
*
|
|
69
|
+
* @param text 待摘要的文本。
|
|
70
|
+
* @returns 32 位小写十六进制字符串。
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* XCrypto.md5('123456') // 'e10adc3949ba59abbe56e057f20f883e'
|
|
74
|
+
*/
|
|
75
|
+
static md5(text: string): string;
|
|
76
|
+
/**
|
|
77
|
+
* 计算文本的 SHA-1 摘要。
|
|
78
|
+
*
|
|
79
|
+
* @param text 待摘要的文本。
|
|
80
|
+
* @returns 40 位小写十六进制字符串。
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* XCrypto.sha1('123456') // '7c4a8d09ca3762af61e59520943dc26494f8941b'
|
|
84
|
+
*/
|
|
85
|
+
static sha1(text: string): string;
|
|
86
|
+
/**
|
|
87
|
+
* 计算文本的 SHA-256 摘要。
|
|
88
|
+
*
|
|
89
|
+
* @param text 待摘要的文本。
|
|
90
|
+
* @returns 64 位小写十六进制字符串。
|
|
91
|
+
*
|
|
92
|
+
* @example
|
|
93
|
+
* XCrypto.sha256('123456') // '8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92'
|
|
94
|
+
*/
|
|
95
|
+
static sha256(text: string): string;
|
|
96
|
+
/**
|
|
97
|
+
* 计算文本的 SHA-512 摘要。
|
|
98
|
+
*
|
|
99
|
+
* @param text 待摘要的文本。
|
|
100
|
+
* @returns 128 位小写十六进制字符串。
|
|
101
|
+
*
|
|
102
|
+
* @example
|
|
103
|
+
* XCrypto.sha512('123456') // 'ba3253876aed6bc22d4a6ff53d8406c6ad864195ed144ab5c87621b6c233b548baeae6956df346ec8c17f5ea10f35ee3cbc514797ed7ddd3145464e2a0bab413'
|
|
104
|
+
*/
|
|
105
|
+
static sha512(text: string): string;
|
|
106
|
+
/**
|
|
107
|
+
* 使用 AES-128-ECB(PKCS7 填充)对文本进行加密。
|
|
108
|
+
*
|
|
109
|
+
* @param text 需要加密的文本。
|
|
110
|
+
* @param key 加密密钥,会自动规范化为 16 字节(不足补零、超出截断)。
|
|
111
|
+
* @returns Base64 编码的密文。
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
* XCrypto.aesEncrypt('{"userId":"doit"}', 'hj7Wer8V3epukzV7')
|
|
115
|
+
* // 'fCH/NJMbVFVDjL73irkG40HP19muCpVcrrUrx22GuEc='
|
|
116
|
+
*/
|
|
117
|
+
static aesEncrypt(text: string, key: string): string;
|
|
118
|
+
/**
|
|
119
|
+
* 使用 AES-128-ECB(PKCS7 填充)对文本进行解密。
|
|
120
|
+
*
|
|
121
|
+
* @param text Base64 编码的密文。
|
|
122
|
+
* @param key 解密密钥,需与加密时使用的密钥一致,会自动规范化为 16 字节。
|
|
123
|
+
* @returns 解密后的 UTF-8 文本。
|
|
124
|
+
*
|
|
125
|
+
* @example
|
|
126
|
+
* XCrypto.aesDecrypt('fCH/NJMbVFVDjL73irkG40HP19muCpVcrrUrx22GuEc=', 'hj7Wer8V3epukzV7')
|
|
127
|
+
* // '{"userId":"doit"}'
|
|
128
|
+
*/
|
|
129
|
+
static aesDecrypt(text: string, key: string): string;
|
|
130
|
+
/**
|
|
131
|
+
* 将对象序列化为 JSON 后使用 AES 加密。
|
|
132
|
+
*
|
|
133
|
+
* 适用于传输或存储敏感结构化数据前的加密处理。
|
|
134
|
+
*
|
|
135
|
+
* @param payload 需要加密的任意数据,内部会先 `JSON.stringify` 序列化。
|
|
136
|
+
* @param key 加密密钥,会自动规范化为 16 字节(不足补零、超出截断)。
|
|
137
|
+
* @returns Base64 编码的密文。
|
|
138
|
+
*
|
|
139
|
+
* @example
|
|
140
|
+
* XCrypto.aesEncryptJson({ userId: 'doit' }, 'hj7Wer8V3epukzV7')
|
|
141
|
+
* // 'fCH/NJMbVFVDjL73irkG40HP19muCpVcrrUrx22GuEc='
|
|
142
|
+
*/
|
|
143
|
+
static aesEncryptJson(payload: unknown, key: string): string;
|
|
144
|
+
/**
|
|
145
|
+
* 解密文本并将结果解析为 JSON 对象。
|
|
146
|
+
*
|
|
147
|
+
* @param text Base64 编码的密文。
|
|
148
|
+
* @param key 解密密钥,需与加密时使用的密钥一致。
|
|
149
|
+
* @returns 解密并解析后的 JSON 对象,类型由泛型 `T` 指定。
|
|
150
|
+
*
|
|
151
|
+
* @example
|
|
152
|
+
* XCrypto.aesDecryptJson<{ userId: string }>(
|
|
153
|
+
* 'fCH/NJMbVFVDjL73irkG40HP19muCpVcrrUrx22GuEc=',
|
|
154
|
+
* 'hj7Wer8V3epukzV7',
|
|
155
|
+
* ) // { userId: 'doit' }
|
|
156
|
+
*/
|
|
157
|
+
static aesDecryptJson<T>(text: string, key: string): T;
|
|
158
|
+
}
|
package/lib/crypto.mjs
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import crypto from "node:crypto";
|
|
2
|
+
// src/crypto.ts
|
|
3
|
+
/**
|
|
4
|
+
* 将任意长度的密钥规范化为 AES-128 所需的 16 字节密钥。
|
|
5
|
+
*
|
|
6
|
+
* 规则:密钥先按 UTF-8 编码为字节序列;不足 16 字节时在右侧补 0,
|
|
7
|
+
* 超过 16 字节时截取前 16 字节。
|
|
8
|
+
*
|
|
9
|
+
* 对于纯 ASCII 密钥,结果与 `key.substring(0, 16)` 完全一致;
|
|
10
|
+
* 同时修复了原实现按字符截取导致多字节字符密钥字节数超长而抛错的问题。
|
|
11
|
+
*/
|
|
12
|
+
function resolveAesKey(key) {
|
|
13
|
+
return Buffer.concat([Buffer.from(key, "utf8"), Buffer.alloc(16)]).subarray(0, 16);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* 计算文本的十六进制摘要。
|
|
17
|
+
*
|
|
18
|
+
* @param text 待摘要的文本。
|
|
19
|
+
* @param algorithm 摘要算法名称(如 md5、sha1、sha256、sha512)。
|
|
20
|
+
* @returns 小写十六进制形式的摘要字符串。
|
|
21
|
+
*/
|
|
22
|
+
function digest(text, algorithm) {
|
|
23
|
+
return crypto.createHash(algorithm).update(text, "utf8").digest("hex");
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* 常用加解密与摘要工具。
|
|
27
|
+
*
|
|
28
|
+
* 提供 Base64 / Base64URL 编解码、常见哈希摘要(MD5、SHA-1、
|
|
29
|
+
* SHA-256、SHA-512),以及 AES-128-ECB 对称加解密能力,所有方法
|
|
30
|
+
* 均为静态方法,可直接通过 `XCrypto.xxx()` 调用。
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* XCrypto.md5('123456') // 'e10adc3949ba59abbe56e057f20f883e'
|
|
34
|
+
* XCrypto.base64UrlEncode('{"userId":"doit"}') // 'eyJ1c2VySWQiOiJkb2l0In0'
|
|
35
|
+
*
|
|
36
|
+
* @remarks
|
|
37
|
+
* - MD5 与 SHA-1 已被视为不安全算法,仅建议用于校验等非安全场景;
|
|
38
|
+
* - AES 采用 ECB 模式,相同明文加密结果固定,不适用于需要语义安全的
|
|
39
|
+
* 场景(建议改用 CBC / GCM 等带随机 IV 的模式);
|
|
40
|
+
* - 加解密密钥会自动规范化为 16 字节(不足补零、超出截断)。
|
|
41
|
+
*/
|
|
42
|
+
var XCrypto = class XCrypto {
|
|
43
|
+
/**
|
|
44
|
+
* 将文本编码为 Base64 字符串。
|
|
45
|
+
*
|
|
46
|
+
* @param text 需要编码的原始文本。
|
|
47
|
+
* @returns Base64 编码后的字符串。
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* XCrypto.base64Encode('{"userId":"doit"}') // 'eyJ1c2VySWQiOiJkb2l0In0='
|
|
51
|
+
* XCrypto.base64Encode('🐲') // '8J+Qsg=='
|
|
52
|
+
*/
|
|
53
|
+
static base64Encode(text) {
|
|
54
|
+
return Buffer.from(text, "utf8").toString("base64");
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* 将 Base64 字符串解码为 UTF-8 文本。
|
|
58
|
+
*
|
|
59
|
+
* @param text Base64 编码的字符串。
|
|
60
|
+
* @returns 解码后的 UTF-8 文本。
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* XCrypto.base64Decode('eyJ1c2VySWQiOiJkb2l0In0=') // '{"userId":"doit"}'
|
|
64
|
+
* XCrypto.base64Decode('8J+Qsg==') // '🐲'
|
|
65
|
+
*/
|
|
66
|
+
static base64Decode(text) {
|
|
67
|
+
return Buffer.from(text, "base64").toString("utf8");
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* 将文本编码为 URL 安全的 Base64(Base64URL)字符串。
|
|
71
|
+
*
|
|
72
|
+
* 与标准 Base64 的区别:`+` 替换为 `-`、`/` 替换为 `_`,并去除
|
|
73
|
+
* 末尾的 `=` 填充,使其可直接用于 URL 查询参数等场景。
|
|
74
|
+
*
|
|
75
|
+
* @param text 需要编码的原始文本。
|
|
76
|
+
* @returns Base64URL 编码后的字符串。
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* XCrypto.base64UrlEncode('{"userId":"doit"}') // 'eyJ1c2VySWQiOiJkb2l0In0'
|
|
80
|
+
* XCrypto.base64UrlEncode('🐲') // '8J-Qsg'
|
|
81
|
+
*/
|
|
82
|
+
static base64UrlEncode(text) {
|
|
83
|
+
return Buffer.from(text, "utf8").toString("base64url");
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* 将 Base64URL 字符串解码为 UTF-8 文本。
|
|
87
|
+
*
|
|
88
|
+
* @param text Base64URL 编码的字符串。
|
|
89
|
+
* @returns 解码后的 UTF-8 文本。
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* XCrypto.base64UrlDecode('eyJ1c2VySWQiOiJkb2l0In0') // '{"userId":"doit"}'
|
|
93
|
+
* XCrypto.base64UrlDecode('8J-Qsg') // '🐲'
|
|
94
|
+
*/
|
|
95
|
+
static base64UrlDecode(text) {
|
|
96
|
+
return Buffer.from(text, "base64url").toString("utf8");
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* 计算文本的 MD5 摘要。
|
|
100
|
+
*
|
|
101
|
+
* @param text 待摘要的文本。
|
|
102
|
+
* @returns 32 位小写十六进制字符串。
|
|
103
|
+
*
|
|
104
|
+
* @example
|
|
105
|
+
* XCrypto.md5('123456') // 'e10adc3949ba59abbe56e057f20f883e'
|
|
106
|
+
*/
|
|
107
|
+
static md5(text) {
|
|
108
|
+
return digest(text, "md5");
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* 计算文本的 SHA-1 摘要。
|
|
112
|
+
*
|
|
113
|
+
* @param text 待摘要的文本。
|
|
114
|
+
* @returns 40 位小写十六进制字符串。
|
|
115
|
+
*
|
|
116
|
+
* @example
|
|
117
|
+
* XCrypto.sha1('123456') // '7c4a8d09ca3762af61e59520943dc26494f8941b'
|
|
118
|
+
*/
|
|
119
|
+
static sha1(text) {
|
|
120
|
+
return digest(text, "sha1");
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* 计算文本的 SHA-256 摘要。
|
|
124
|
+
*
|
|
125
|
+
* @param text 待摘要的文本。
|
|
126
|
+
* @returns 64 位小写十六进制字符串。
|
|
127
|
+
*
|
|
128
|
+
* @example
|
|
129
|
+
* XCrypto.sha256('123456') // '8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92'
|
|
130
|
+
*/
|
|
131
|
+
static sha256(text) {
|
|
132
|
+
return digest(text, "sha256");
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* 计算文本的 SHA-512 摘要。
|
|
136
|
+
*
|
|
137
|
+
* @param text 待摘要的文本。
|
|
138
|
+
* @returns 128 位小写十六进制字符串。
|
|
139
|
+
*
|
|
140
|
+
* @example
|
|
141
|
+
* XCrypto.sha512('123456') // 'ba3253876aed6bc22d4a6ff53d8406c6ad864195ed144ab5c87621b6c233b548baeae6956df346ec8c17f5ea10f35ee3cbc514797ed7ddd3145464e2a0bab413'
|
|
142
|
+
*/
|
|
143
|
+
static sha512(text) {
|
|
144
|
+
return digest(text, "sha512");
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* 使用 AES-128-ECB(PKCS7 填充)对文本进行加密。
|
|
148
|
+
*
|
|
149
|
+
* @param text 需要加密的文本。
|
|
150
|
+
* @param key 加密密钥,会自动规范化为 16 字节(不足补零、超出截断)。
|
|
151
|
+
* @returns Base64 编码的密文。
|
|
152
|
+
*
|
|
153
|
+
* @example
|
|
154
|
+
* XCrypto.aesEncrypt('{"userId":"doit"}', 'hj7Wer8V3epukzV7')
|
|
155
|
+
* // 'fCH/NJMbVFVDjL73irkG40HP19muCpVcrrUrx22GuEc='
|
|
156
|
+
*/
|
|
157
|
+
static aesEncrypt(text, key) {
|
|
158
|
+
const cipher = crypto.createCipheriv("aes-128-ecb", resolveAesKey(key), null);
|
|
159
|
+
let encrypted = cipher.update(text, "utf8", "base64");
|
|
160
|
+
encrypted += cipher.final("base64");
|
|
161
|
+
return encrypted;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* 使用 AES-128-ECB(PKCS7 填充)对文本进行解密。
|
|
165
|
+
*
|
|
166
|
+
* @param text Base64 编码的密文。
|
|
167
|
+
* @param key 解密密钥,需与加密时使用的密钥一致,会自动规范化为 16 字节。
|
|
168
|
+
* @returns 解密后的 UTF-8 文本。
|
|
169
|
+
*
|
|
170
|
+
* @example
|
|
171
|
+
* XCrypto.aesDecrypt('fCH/NJMbVFVDjL73irkG40HP19muCpVcrrUrx22GuEc=', 'hj7Wer8V3epukzV7')
|
|
172
|
+
* // '{"userId":"doit"}'
|
|
173
|
+
*/
|
|
174
|
+
static aesDecrypt(text, key) {
|
|
175
|
+
const decipher = crypto.createDecipheriv("aes-128-ecb", resolveAesKey(key), null);
|
|
176
|
+
let decrypted = decipher.update(text, "base64", "utf8");
|
|
177
|
+
decrypted += decipher.final("utf8");
|
|
178
|
+
return decrypted;
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* 将对象序列化为 JSON 后使用 AES 加密。
|
|
182
|
+
*
|
|
183
|
+
* 适用于传输或存储敏感结构化数据前的加密处理。
|
|
184
|
+
*
|
|
185
|
+
* @param payload 需要加密的任意数据,内部会先 `JSON.stringify` 序列化。
|
|
186
|
+
* @param key 加密密钥,会自动规范化为 16 字节(不足补零、超出截断)。
|
|
187
|
+
* @returns Base64 编码的密文。
|
|
188
|
+
*
|
|
189
|
+
* @example
|
|
190
|
+
* XCrypto.aesEncryptJson({ userId: 'doit' }, 'hj7Wer8V3epukzV7')
|
|
191
|
+
* // 'fCH/NJMbVFVDjL73irkG40HP19muCpVcrrUrx22GuEc='
|
|
192
|
+
*/
|
|
193
|
+
static aesEncryptJson(payload, key) {
|
|
194
|
+
return XCrypto.aesEncrypt(JSON.stringify(payload), key);
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* 解密文本并将结果解析为 JSON 对象。
|
|
198
|
+
*
|
|
199
|
+
* @param text Base64 编码的密文。
|
|
200
|
+
* @param key 解密密钥,需与加密时使用的密钥一致。
|
|
201
|
+
* @returns 解密并解析后的 JSON 对象,类型由泛型 `T` 指定。
|
|
202
|
+
*
|
|
203
|
+
* @example
|
|
204
|
+
* XCrypto.aesDecryptJson<{ userId: string }>(
|
|
205
|
+
* 'fCH/NJMbVFVDjL73irkG40HP19muCpVcrrUrx22GuEc=',
|
|
206
|
+
* 'hj7Wer8V3epukzV7',
|
|
207
|
+
* ) // { userId: 'doit' }
|
|
208
|
+
*/
|
|
209
|
+
static aesDecryptJson(text, key) {
|
|
210
|
+
return JSON.parse(XCrypto.aesDecrypt(text, key));
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
export { XCrypto };
|
package/lib/data_set.mjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { XCsv } from "./csv.mjs";
|
|
2
|
+
import { XDispose } from "./dispose.mjs";
|
|
2
3
|
import { XJson } from "./json.mjs";
|
|
3
4
|
import { XYaml } from "./yaml.mjs";
|
|
4
5
|
import { keyBy, keysStrict, pickStrict } from "vtils";
|
|
5
6
|
import { v } from "vtils/vae";
|
|
6
|
-
import { asyncExitHook } from "exit-hook";
|
|
7
7
|
import * as path from "node:path";
|
|
8
8
|
import fs from "fs-extra";
|
|
9
9
|
// src/data_set.ts
|
|
@@ -64,10 +64,10 @@ var XDataSet = class {
|
|
|
64
64
|
const timer = setInterval(() => {
|
|
65
65
|
this.write();
|
|
66
66
|
}, options.autoWriteInterval || 5e3);
|
|
67
|
-
|
|
67
|
+
XDispose.exit.add(async () => {
|
|
68
68
|
clearInterval(timer);
|
|
69
69
|
await this.write();
|
|
70
|
-
}
|
|
70
|
+
});
|
|
71
71
|
}
|
|
72
72
|
}
|
|
73
73
|
/**
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `XDbValue.SimpleArray` 的配置项。
|
|
3
|
+
*/
|
|
4
|
+
export interface XDbValueSimpleArrayOptions {
|
|
5
|
+
/**
|
|
6
|
+
* 元素之间的分隔符。
|
|
7
|
+
*
|
|
8
|
+
* @default ','
|
|
9
|
+
*/
|
|
10
|
+
separator?: string;
|
|
11
|
+
/**
|
|
12
|
+
* 存储值的统一前后缀(成对包裹在序列化结果两侧)。
|
|
13
|
+
*
|
|
14
|
+
* 例如传入 `"` 后,`['a', 'b']` 会被写为 `"a,b"`。
|
|
15
|
+
* 读取时仅当值同时以该前后缀开头和结尾时才会被剥离,否则按原始文本解析,
|
|
16
|
+
* 避免误伤没有前后缀的历史数据。
|
|
17
|
+
*
|
|
18
|
+
* @default ''
|
|
19
|
+
*/
|
|
20
|
+
affix?: string;
|
|
21
|
+
/**
|
|
22
|
+
* 是否将数组元素转换为数字。
|
|
23
|
+
*
|
|
24
|
+
* @default false
|
|
25
|
+
*/
|
|
26
|
+
number?: boolean;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* `XDbValue.JsonObject` 的转换钩子配置。
|
|
30
|
+
*
|
|
31
|
+
* @template T 对象值的类型。
|
|
32
|
+
*/
|
|
33
|
+
export interface XDbValueJsonObjectOptions<T> {
|
|
34
|
+
/**
|
|
35
|
+
* 可选的转换钩子,分别在写入(add)、读取(get)、更新(update)时对值做预处理。
|
|
36
|
+
*/
|
|
37
|
+
transform?: {
|
|
38
|
+
/** 写入(add)前对值做转换。 */
|
|
39
|
+
add?: (value: T) => T;
|
|
40
|
+
/** 读取(get)后对值做转换。 */
|
|
41
|
+
get?: (value: T) => T;
|
|
42
|
+
/** 更新(update)前对值做转换。 */
|
|
43
|
+
update?: (value: T) => T;
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* 数据库字段值的序列化与反序列化工具。
|
|
48
|
+
*
|
|
49
|
+
* 适用于把数组或对象以字符串形式存储到数据库字段(如 VARCHAR / TEXT)的场景,
|
|
50
|
+
* 内置三种存储格式:
|
|
51
|
+
* - {@link XDbValue.SimpleArray}:以分隔符连接的数组,支持前后缀与数字模式;
|
|
52
|
+
* - {@link XDbValue.JsonArray}:JSON 数组;
|
|
53
|
+
* - {@link XDbValue.JsonObject}:JSON 对象,支持读写转换钩子。
|
|
54
|
+
*
|
|
55
|
+
* 每种格式都提供 `add`(写入)、`get`(读取)、`update`(更新)三个方法:
|
|
56
|
+
* - `add` 返回序列化后的字符串,入参非法时使用默认值兜底;
|
|
57
|
+
* - `get` 将存储字符串反序列化为目标类型,空值返回空数组或空对象;
|
|
58
|
+
* - `update` 返回用于更新的字符串,入参非法时返回 `undefined`,便于调用方跳过该字段。
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* const sa = new XDbValue.SimpleArray();
|
|
62
|
+
* sa.add(['a', 'b']);
|
|
63
|
+
* // 'a,b'
|
|
64
|
+
* sa.get('a,b');
|
|
65
|
+
* // ['a', 'b']
|
|
66
|
+
*/
|
|
67
|
+
export declare class XDbValue {
|
|
68
|
+
/**
|
|
69
|
+
* 分隔符数组格式:`'a,b'` ↔ `['a', 'b']`。
|
|
70
|
+
*
|
|
71
|
+
* @template T 数组元素类型,仅支持 `string` 或 `number`。
|
|
72
|
+
*/
|
|
73
|
+
static SimpleArray: {
|
|
74
|
+
new <T extends string | number = string>(options?: XDbValueSimpleArrayOptions): {
|
|
75
|
+
/** 元素之间的分隔符。 */
|
|
76
|
+
separator: string;
|
|
77
|
+
/** 存储值的统一前后缀,空字符串表示不包裹。 */
|
|
78
|
+
affix: string;
|
|
79
|
+
/** 是否将数组元素转换为数字。 */
|
|
80
|
+
number: boolean;
|
|
81
|
+
/**
|
|
82
|
+
* 将数组序列化为适合存储的字符串。
|
|
83
|
+
*
|
|
84
|
+
* - `value` 不是数组时,使用 `defaultValue` 兜底;
|
|
85
|
+
* - 过滤掉 `null`、`undefined` 与空字符串元素;
|
|
86
|
+
* - 结果非空且设置了 `affix` 时在首尾包裹前后缀;结果为空时返回空字符串(不包裹)。
|
|
87
|
+
*
|
|
88
|
+
* @param value 要序列化的数组。
|
|
89
|
+
* @param defaultValue `value` 非法时使用的兜底数组。
|
|
90
|
+
* @returns 序列化后的字符串。
|
|
91
|
+
*
|
|
92
|
+
* @example
|
|
93
|
+
* const sa = new XDbValue.SimpleArray();
|
|
94
|
+
* sa.add(['a', 'b']);
|
|
95
|
+
* // 'a,b'
|
|
96
|
+
*/
|
|
97
|
+
add: (value?: T[], defaultValue?: T[]) => string;
|
|
98
|
+
/**
|
|
99
|
+
* 将存储字符串反序列化为数组。
|
|
100
|
+
*
|
|
101
|
+
* - 值为空时返回空数组;
|
|
102
|
+
* - 设置了 `affix` 时,仅当值同时以该前后缀开头和结尾才会剥离,否则按原始文本解析;
|
|
103
|
+
* - 按 `separator` 分割并过滤掉空字符串;
|
|
104
|
+
* - `number` 为 `true` 时,将每个元素转换为数字。
|
|
105
|
+
*
|
|
106
|
+
* @param value 存储字符串。
|
|
107
|
+
* @returns 反序列化后的数组。
|
|
108
|
+
*
|
|
109
|
+
* @example
|
|
110
|
+
* const sa = new XDbValue.SimpleArray();
|
|
111
|
+
* sa.get('a,b');
|
|
112
|
+
* // ['a', 'b']
|
|
113
|
+
*/
|
|
114
|
+
get: (value?: string) => T[];
|
|
115
|
+
/**
|
|
116
|
+
* 将数组序列化为用于更新的字符串。
|
|
117
|
+
*
|
|
118
|
+
* 与 {@link add} 的区别在于:`value` 不是数组时返回 `undefined`,
|
|
119
|
+
* 便于调用方在更新数据库时跳过该字段;`value` 是数组但过滤后为空时返回空字符串。
|
|
120
|
+
*
|
|
121
|
+
* @param value 要序列化的数组。
|
|
122
|
+
* @returns 序列化后的字符串;`value` 不是数组时返回 `undefined`。
|
|
123
|
+
*/
|
|
124
|
+
update: (value?: T[]) => string | undefined;
|
|
125
|
+
};
|
|
126
|
+
};
|
|
127
|
+
/**
|
|
128
|
+
* JSON 数组格式:`'[{"a":1}]'` ↔ `[{ a: 1 }]`。
|
|
129
|
+
*
|
|
130
|
+
* @template T 数组元素类型。
|
|
131
|
+
*/
|
|
132
|
+
static JsonArray: {
|
|
133
|
+
new <T = string>(): {
|
|
134
|
+
/**
|
|
135
|
+
* 将数组序列化为 JSON 字符串。
|
|
136
|
+
*
|
|
137
|
+
* @param value 要序列化的数组。
|
|
138
|
+
* @param defaultValue `value` 非法时使用的兜底数组。
|
|
139
|
+
* @returns JSON 字符串。
|
|
140
|
+
*/
|
|
141
|
+
add: (value?: T[], defaultValue?: T[]) => string;
|
|
142
|
+
/**
|
|
143
|
+
* 将 JSON 字符串反序列化为数组。
|
|
144
|
+
*
|
|
145
|
+
* - 值为空时返回空数组;
|
|
146
|
+
* - 值不是合法 JSON 时抛出 `SyntaxError`。
|
|
147
|
+
*
|
|
148
|
+
* @param value JSON 字符串。
|
|
149
|
+
* @returns 反序列化后的数组。
|
|
150
|
+
*/
|
|
151
|
+
get: (value?: string) => T[];
|
|
152
|
+
/**
|
|
153
|
+
* 将数组序列化为用于更新的 JSON 字符串。
|
|
154
|
+
*
|
|
155
|
+
* @param value 要序列化的数组。
|
|
156
|
+
* @returns JSON 字符串;`value` 不是数组时返回 `undefined`。
|
|
157
|
+
*/
|
|
158
|
+
update: (value?: T[]) => string | undefined;
|
|
159
|
+
};
|
|
160
|
+
};
|
|
161
|
+
/**
|
|
162
|
+
* JSON 对象格式:`'{"name":"x"}'` ↔ `{ name: 'x' }`。
|
|
163
|
+
*
|
|
164
|
+
* 相比 {@link XDbValue.JsonArray},额外支持 {@link XDbValueJsonObjectOptions.transform}
|
|
165
|
+
* 转换钩子,适合在读写时统一处理日期、默认值等字段。
|
|
166
|
+
*
|
|
167
|
+
* @template T 对象值的类型。
|
|
168
|
+
*/
|
|
169
|
+
static JsonObject: {
|
|
170
|
+
new <T>(options?: XDbValueJsonObjectOptions<T>): {
|
|
171
|
+
/** 构造时传入的转换钩子配置。 */
|
|
172
|
+
options?: XDbValueJsonObjectOptions<T>;
|
|
173
|
+
/** 是否配置了 add 转换钩子。 */
|
|
174
|
+
hasTransformAdd: boolean;
|
|
175
|
+
/** 是否配置了 get 转换钩子。 */
|
|
176
|
+
hasTransformGet: boolean;
|
|
177
|
+
/** 是否配置了 update 转换钩子。 */
|
|
178
|
+
hasTransformUpdate: boolean;
|
|
179
|
+
/**
|
|
180
|
+
* 将对象序列化为 JSON 字符串。
|
|
181
|
+
*
|
|
182
|
+
* - 配置 `transform.add` 时,先对值做转换;
|
|
183
|
+
* - `value` 不是普通对象时,使用 `defaultValue` 兜底。
|
|
184
|
+
*
|
|
185
|
+
* @param value 要序列化的对象。
|
|
186
|
+
* @param defaultValue `value` 非法时使用的兜底对象。
|
|
187
|
+
* @returns JSON 字符串。
|
|
188
|
+
*/
|
|
189
|
+
add: (value?: T, defaultValue?: T) => string;
|
|
190
|
+
/**
|
|
191
|
+
* 将 JSON 字符串反序列化为对象。
|
|
192
|
+
*
|
|
193
|
+
* - 值为空时返回空对象 `{}`;
|
|
194
|
+
* - 值不是合法 JSON 时抛出 `SyntaxError`;
|
|
195
|
+
* - 配置 `transform.get` 时对结果做转换,空值解析出的 `{}` 同样会经过该钩子。
|
|
196
|
+
*
|
|
197
|
+
* @param value JSON 字符串。
|
|
198
|
+
* @returns 反序列化后的对象。
|
|
199
|
+
*/
|
|
200
|
+
get: (value?: string) => T;
|
|
201
|
+
/**
|
|
202
|
+
* 将对象序列化为用于更新的 JSON 字符串。
|
|
203
|
+
*
|
|
204
|
+
* - 配置 `transform.update` 时,先对值做转换;
|
|
205
|
+
* - `value` 不是普通对象时返回 `undefined`。
|
|
206
|
+
*
|
|
207
|
+
* @param value 要序列化的对象。
|
|
208
|
+
* @returns JSON 字符串;`value` 不是普通对象时返回 `undefined`。
|
|
209
|
+
*/
|
|
210
|
+
update: (value?: T) => string | undefined;
|
|
211
|
+
};
|
|
212
|
+
};
|
|
213
|
+
}
|