befly 2.3.3 → 3.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/apis/health/info.ts +64 -0
- package/apis/tool/tokenCheck.ts +51 -0
- package/bin/befly.ts +202 -0
- package/checks/conflict.ts +408 -0
- package/checks/{table.js → table.ts} +139 -61
- package/config/env.ts +218 -0
- package/config/reserved.ts +96 -0
- package/main.ts +101 -0
- package/package.json +44 -8
- package/plugins/{db.js → db.ts} +24 -11
- package/plugins/logger.ts +28 -0
- package/plugins/redis.ts +51 -0
- package/plugins/tool.ts +34 -0
- package/scripts/syncDb/apply.ts +171 -0
- package/scripts/syncDb/constants.ts +70 -0
- package/scripts/syncDb/ddl.ts +182 -0
- package/scripts/syncDb/helpers.ts +172 -0
- package/scripts/syncDb/index.ts +215 -0
- package/scripts/syncDb/schema.ts +199 -0
- package/scripts/syncDb/sqlite.ts +50 -0
- package/scripts/syncDb/state.ts +104 -0
- package/scripts/syncDb/table.ts +204 -0
- package/scripts/syncDb/tableCreate.ts +142 -0
- package/scripts/syncDb/tests/constants.test.ts +104 -0
- package/scripts/syncDb/tests/ddl.test.ts +134 -0
- package/scripts/syncDb/tests/helpers.test.ts +70 -0
- package/scripts/syncDb/types.ts +92 -0
- package/scripts/syncDb/version.ts +73 -0
- package/scripts/syncDb.ts +9 -0
- package/scripts/{syncDev.js → syncDev.ts} +41 -25
- package/system.ts +149 -0
- package/tables/_common.json +21 -0
- package/tables/admin.json +10 -0
- package/tsconfig.json +58 -0
- package/types/api.d.ts +246 -0
- package/types/befly.d.ts +234 -0
- package/types/common.d.ts +215 -0
- package/types/context.ts +167 -0
- package/types/crypto.d.ts +23 -0
- package/types/database.d.ts +278 -0
- package/types/index.d.ts +16 -0
- package/types/index.ts +459 -0
- package/types/jwt.d.ts +99 -0
- package/types/logger.d.ts +43 -0
- package/types/plugin.d.ts +109 -0
- package/types/redis.d.ts +44 -0
- package/types/tool.d.ts +67 -0
- package/types/validator.d.ts +45 -0
- package/utils/addonHelper.ts +60 -0
- package/utils/api.ts +23 -0
- package/utils/{colors.js → colors.ts} +79 -21
- package/utils/crypto.ts +308 -0
- package/utils/datetime.ts +51 -0
- package/utils/dbHelper.ts +142 -0
- package/utils/errorHandler.ts +68 -0
- package/utils/index.ts +46 -0
- package/utils/jwt.ts +493 -0
- package/utils/logger.ts +284 -0
- package/utils/objectHelper.ts +68 -0
- package/utils/pluginHelper.ts +62 -0
- package/utils/redisHelper.ts +338 -0
- package/utils/response.ts +38 -0
- package/utils/{sqlBuilder.js → sqlBuilder.ts} +233 -97
- package/utils/sqlHelper.ts +447 -0
- package/utils/tableHelper.ts +167 -0
- package/utils/tool.ts +230 -0
- package/utils/typeHelper.ts +101 -0
- package/utils/validate.ts +451 -0
- package/utils/{xml.js → xml.ts} +100 -74
- package/.npmrc +0 -3
- package/.prettierignore +0 -2
- package/.prettierrc +0 -11
- package/apis/health/info.js +0 -49
- package/apis/tool/tokenCheck.js +0 -29
- package/bin/befly.js +0 -109
- package/config/env.js +0 -64
- package/main.js +0 -579
- package/plugins/logger.js +0 -14
- package/plugins/redis.js +0 -32
- package/plugins/tool.js +0 -8
- package/scripts/syncDb.js +0 -752
- package/system.js +0 -118
- package/tables/common.json +0 -16
- package/tables/tool.json +0 -6
- package/utils/api.js +0 -27
- package/utils/crypto.js +0 -260
- package/utils/index.js +0 -334
- package/utils/jwt.js +0 -387
- package/utils/logger.js +0 -143
- package/utils/redisHelper.js +0 -74
- package/utils/sqlManager.js +0 -471
- package/utils/tool.js +0 -31
- package/utils/validate.js +0 -226
package/utils/{xml.js → xml.ts}
RENAMED
|
@@ -1,39 +1,66 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* XML 解析器
|
|
2
|
+
* XML 解析器 - TypeScript 版本
|
|
3
3
|
* 将 XML 字符串解析为 JSON 对象
|
|
4
4
|
*/
|
|
5
|
-
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* XML 解析选项
|
|
8
|
+
*/
|
|
9
|
+
interface XmlParseOptions {
|
|
10
|
+
/** 是否忽略属性 */
|
|
11
|
+
ignoreAttributes?: boolean;
|
|
12
|
+
/** 属性前缀 */
|
|
13
|
+
attributePrefix?: string;
|
|
14
|
+
/** 文本内容的键名 */
|
|
15
|
+
textKey?: string;
|
|
16
|
+
/** 是否去除首尾空格 */
|
|
17
|
+
trimValues?: boolean;
|
|
18
|
+
/** 是否解析布尔值 */
|
|
19
|
+
parseBooleans?: boolean;
|
|
20
|
+
/** 是否解析数字 */
|
|
21
|
+
parseNumbers?: boolean;
|
|
22
|
+
/** 是否使用自定义解析器 */
|
|
23
|
+
customParser?: boolean;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* 解析结果接口(内部使用)
|
|
28
|
+
*/
|
|
29
|
+
interface ParseResult {
|
|
30
|
+
value: Record<string, any>;
|
|
31
|
+
end: number;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* XML 解析器类
|
|
36
|
+
*/
|
|
37
|
+
export class Xml {
|
|
38
|
+
private options: Required<XmlParseOptions>;
|
|
39
|
+
|
|
6
40
|
/**
|
|
7
41
|
* 构造函数
|
|
8
|
-
* @param
|
|
42
|
+
* @param options - 解析选项
|
|
9
43
|
*/
|
|
10
|
-
constructor(options = {}) {
|
|
44
|
+
constructor(options: XmlParseOptions = {}) {
|
|
11
45
|
// 默认配置
|
|
12
46
|
this.options = {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
parseBooleans: true, // 是否解析布尔值
|
|
21
|
-
parseNumbers: true, // 是否解析数字
|
|
22
|
-
|
|
23
|
-
// 高级配置
|
|
24
|
-
customParser: true, // 是否使用自定义解析器
|
|
25
|
-
|
|
26
|
-
// 合并用户选项
|
|
47
|
+
ignoreAttributes: false,
|
|
48
|
+
attributePrefix: '@',
|
|
49
|
+
textKey: '#text',
|
|
50
|
+
trimValues: true,
|
|
51
|
+
parseBooleans: true,
|
|
52
|
+
parseNumbers: true,
|
|
53
|
+
customParser: true,
|
|
27
54
|
...options
|
|
28
55
|
};
|
|
29
56
|
}
|
|
30
57
|
|
|
31
58
|
/**
|
|
32
59
|
* 解析 XML 字符串为 JSON 对象
|
|
33
|
-
* @param
|
|
34
|
-
* @returns
|
|
60
|
+
* @param xmlData - XML 字符串
|
|
61
|
+
* @returns 解析后的 JSON 对象
|
|
35
62
|
*/
|
|
36
|
-
parse(xmlData) {
|
|
63
|
+
parse(xmlData: string): Record<string, any> {
|
|
37
64
|
if (typeof xmlData !== 'string') {
|
|
38
65
|
throw new Error('无效的 XML 数据');
|
|
39
66
|
}
|
|
@@ -54,20 +81,22 @@ class Xml {
|
|
|
54
81
|
|
|
55
82
|
// 自定义解析
|
|
56
83
|
if (this.options.customParser) {
|
|
57
|
-
return this
|
|
84
|
+
return this.customParse(xmlData);
|
|
58
85
|
}
|
|
86
|
+
|
|
87
|
+
return {};
|
|
59
88
|
}
|
|
60
89
|
|
|
61
90
|
/**
|
|
62
91
|
* 解析属性字符串
|
|
63
|
-
* @param
|
|
64
|
-
* @param
|
|
92
|
+
* @param attributesStr - 属性字符串
|
|
93
|
+
* @param element - 元素对象
|
|
65
94
|
*/
|
|
66
|
-
|
|
95
|
+
private parseAttributes(attributesStr: string, element: Record<string, any>): void {
|
|
67
96
|
// 移除标签名,只保留属性部分
|
|
68
97
|
const attrPart = attributesStr.replace(/^\w+\s*/, '');
|
|
69
98
|
const attrRegex = /(\w+)=["']([^"']*)["']/g;
|
|
70
|
-
let match;
|
|
99
|
+
let match: RegExpExecArray | null;
|
|
71
100
|
|
|
72
101
|
while ((match = attrRegex.exec(attrPart)) !== null) {
|
|
73
102
|
const attrName = this.options.attributePrefix + match[1];
|
|
@@ -78,18 +107,18 @@ class Xml {
|
|
|
78
107
|
element[attrName] = attrValue;
|
|
79
108
|
} else {
|
|
80
109
|
// 其他属性进行类型解析
|
|
81
|
-
element[attrName] = this
|
|
110
|
+
element[attrName] = this.parseValue(attrValue);
|
|
82
111
|
}
|
|
83
112
|
}
|
|
84
113
|
}
|
|
85
114
|
|
|
86
115
|
/**
|
|
87
116
|
* 自定义解析方法
|
|
88
|
-
* @param
|
|
89
|
-
* @returns
|
|
117
|
+
* @param xmlData - XML 数据
|
|
118
|
+
* @returns 解析结果
|
|
90
119
|
*/
|
|
91
|
-
|
|
92
|
-
const result = this
|
|
120
|
+
private customParse(xmlData: string): Record<string, any> {
|
|
121
|
+
const result = this.parseXmlElement(xmlData, 0).value;
|
|
93
122
|
|
|
94
123
|
// 如果结果只有一个根元素,返回该元素的内容
|
|
95
124
|
const keys = Object.keys(result);
|
|
@@ -101,11 +130,11 @@ class Xml {
|
|
|
101
130
|
|
|
102
131
|
/**
|
|
103
132
|
* 解析 XML 元素
|
|
104
|
-
* @param
|
|
105
|
-
* @param
|
|
106
|
-
* @returns
|
|
133
|
+
* @param xml - XML 字符串
|
|
134
|
+
* @param start - 开始位置
|
|
135
|
+
* @returns 包含解析结果和结束位置的对象
|
|
107
136
|
*/
|
|
108
|
-
|
|
137
|
+
private parseXmlElement(xml: string, start: number): ParseResult {
|
|
109
138
|
const tagStart = xml.indexOf('<', start);
|
|
110
139
|
if (tagStart === -1) {
|
|
111
140
|
return { value: {}, end: xml.length };
|
|
@@ -117,13 +146,13 @@ class Xml {
|
|
|
117
146
|
}
|
|
118
147
|
|
|
119
148
|
const fullTag = xml.slice(tagStart + 1, tagEnd);
|
|
120
|
-
const element = {};
|
|
149
|
+
const element: Record<string, any> = {};
|
|
121
150
|
|
|
122
151
|
// 自闭合标签
|
|
123
152
|
if (fullTag.endsWith('/')) {
|
|
124
153
|
const tagName = fullTag.slice(0, -1).split(/\s+/)[0];
|
|
125
154
|
if (!this.options.ignoreAttributes && fullTag.includes(' ')) {
|
|
126
|
-
this
|
|
155
|
+
this.parseAttributes(fullTag.slice(0, -1), element);
|
|
127
156
|
}
|
|
128
157
|
return { value: { [tagName]: Object.keys(element).length > 0 ? element : '' }, end: tagEnd + 1 };
|
|
129
158
|
}
|
|
@@ -134,7 +163,7 @@ class Xml {
|
|
|
134
163
|
if (commentEnd === -1) {
|
|
135
164
|
throw new Error('格式错误:未找到注释结束符');
|
|
136
165
|
}
|
|
137
|
-
return this
|
|
166
|
+
return this.parseXmlElement(xml, commentEnd + 3);
|
|
138
167
|
}
|
|
139
168
|
|
|
140
169
|
// CDATA
|
|
@@ -143,15 +172,14 @@ class Xml {
|
|
|
143
172
|
if (cdataEnd === -1) {
|
|
144
173
|
throw new Error('格式错误:未找到 CDATA 结束符');
|
|
145
174
|
}
|
|
146
|
-
|
|
147
|
-
return this.#parseXmlElement(xml, cdataEnd + 3);
|
|
175
|
+
return this.parseXmlElement(xml, cdataEnd + 3);
|
|
148
176
|
}
|
|
149
177
|
|
|
150
178
|
const tagName = fullTag.split(/\s+/)[0];
|
|
151
179
|
|
|
152
180
|
// 解析属性
|
|
153
181
|
if (!this.options.ignoreAttributes && fullTag.includes(' ')) {
|
|
154
|
-
this
|
|
182
|
+
this.parseAttributes(fullTag, element);
|
|
155
183
|
}
|
|
156
184
|
|
|
157
185
|
// 查找结束标签
|
|
@@ -171,7 +199,7 @@ class Xml {
|
|
|
171
199
|
|
|
172
200
|
// 如果没有子标签,直接解析文本
|
|
173
201
|
if (!content.includes('<')) {
|
|
174
|
-
const textValue = this
|
|
202
|
+
const textValue = this.parseValue(content);
|
|
175
203
|
if (Object.keys(element).length === 0) {
|
|
176
204
|
return { value: { [tagName]: textValue }, end: endTagStart + endTag.length };
|
|
177
205
|
} else {
|
|
@@ -181,7 +209,7 @@ class Xml {
|
|
|
181
209
|
} else {
|
|
182
210
|
// 解析子元素和混合内容
|
|
183
211
|
let pos = 0;
|
|
184
|
-
const texts = [];
|
|
212
|
+
const texts: string[] = [];
|
|
185
213
|
|
|
186
214
|
while (pos < content.length) {
|
|
187
215
|
const nextTag = content.indexOf('<', pos);
|
|
@@ -200,12 +228,12 @@ class Xml {
|
|
|
200
228
|
}
|
|
201
229
|
|
|
202
230
|
// 解析子元素
|
|
203
|
-
const childResult = this
|
|
231
|
+
const childResult = this.parseXmlElement(content, nextTag);
|
|
204
232
|
const childObj = childResult.value;
|
|
205
233
|
|
|
206
234
|
// 合并子元素到当前元素
|
|
207
235
|
for (const [key, value] of Object.entries(childObj)) {
|
|
208
|
-
this
|
|
236
|
+
this.addElement(element, key, value);
|
|
209
237
|
}
|
|
210
238
|
|
|
211
239
|
pos = childResult.end;
|
|
@@ -215,9 +243,9 @@ class Xml {
|
|
|
215
243
|
if (texts.length > 0) {
|
|
216
244
|
const combinedText = texts.join(' ');
|
|
217
245
|
if (Object.keys(element).length === 0) {
|
|
218
|
-
return { value: { [tagName]: this
|
|
246
|
+
return { value: { [tagName]: this.parseValue(combinedText) }, end: endTagStart + endTag.length };
|
|
219
247
|
} else {
|
|
220
|
-
element[this.options.textKey] = this
|
|
248
|
+
element[this.options.textKey] = this.parseValue(combinedText);
|
|
221
249
|
}
|
|
222
250
|
}
|
|
223
251
|
|
|
@@ -227,11 +255,11 @@ class Xml {
|
|
|
227
255
|
|
|
228
256
|
/**
|
|
229
257
|
* 添加元素到对象
|
|
230
|
-
* @param
|
|
231
|
-
* @param
|
|
232
|
-
* @param
|
|
258
|
+
* @param parent - 父对象
|
|
259
|
+
* @param name - 元素名
|
|
260
|
+
* @param value - 元素值
|
|
233
261
|
*/
|
|
234
|
-
|
|
262
|
+
private addElement(parent: Record<string, any>, name: string, value: any): void {
|
|
235
263
|
if (parent[name] === undefined) {
|
|
236
264
|
parent[name] = value;
|
|
237
265
|
} else if (Array.isArray(parent[name])) {
|
|
@@ -243,10 +271,10 @@ class Xml {
|
|
|
243
271
|
|
|
244
272
|
/**
|
|
245
273
|
* 解析值的类型
|
|
246
|
-
* @param
|
|
247
|
-
* @returns
|
|
274
|
+
* @param value - 原始值
|
|
275
|
+
* @returns 解析后的值
|
|
248
276
|
*/
|
|
249
|
-
|
|
277
|
+
private parseValue(value: string): string | number | boolean {
|
|
250
278
|
if (!value || typeof value !== 'string') {
|
|
251
279
|
return value;
|
|
252
280
|
}
|
|
@@ -288,16 +316,16 @@ class Xml {
|
|
|
288
316
|
}
|
|
289
317
|
|
|
290
318
|
// 处理 XML 实体
|
|
291
|
-
return this
|
|
319
|
+
return this.decodeEntities(value);
|
|
292
320
|
}
|
|
293
321
|
|
|
294
322
|
/**
|
|
295
323
|
* 解码 XML 实体
|
|
296
|
-
* @param
|
|
297
|
-
* @returns
|
|
324
|
+
* @param value - 包含实体的字符串
|
|
325
|
+
* @returns 解码后的字符串
|
|
298
326
|
*/
|
|
299
|
-
|
|
300
|
-
const entities = {
|
|
327
|
+
private decodeEntities(value: string): string {
|
|
328
|
+
const entities: Record<string, string> = {
|
|
301
329
|
'&': '&',
|
|
302
330
|
'<': '<',
|
|
303
331
|
'>': '>',
|
|
@@ -312,39 +340,39 @@ class Xml {
|
|
|
312
340
|
|
|
313
341
|
/**
|
|
314
342
|
* 静态方法:快速解析 XML
|
|
315
|
-
* @param
|
|
316
|
-
* @param
|
|
317
|
-
* @returns
|
|
343
|
+
* @param xmlData - XML 数据
|
|
344
|
+
* @param options - 解析选项
|
|
345
|
+
* @returns 解析后的 JSON 对象
|
|
318
346
|
*/
|
|
319
|
-
static parse(xmlData, options = {}) {
|
|
347
|
+
static parse(xmlData: string, options: XmlParseOptions = {}): Record<string, any> {
|
|
320
348
|
const parser = new Xml(options);
|
|
321
349
|
return parser.parse(xmlData);
|
|
322
350
|
}
|
|
323
351
|
|
|
324
352
|
/**
|
|
325
353
|
* 静态方法:解析 XML 并保留属性
|
|
326
|
-
* @param
|
|
327
|
-
* @returns
|
|
354
|
+
* @param xmlData - XML 数据
|
|
355
|
+
* @returns 解析后的 JSON 对象
|
|
328
356
|
*/
|
|
329
|
-
static parseWithAttributes(xmlData) {
|
|
357
|
+
static parseWithAttributes(xmlData: string): Record<string, any> {
|
|
330
358
|
return Xml.parse(xmlData, { ignoreAttributes: false });
|
|
331
359
|
}
|
|
332
360
|
|
|
333
361
|
/**
|
|
334
362
|
* 静态方法:解析 XML 并忽略属性
|
|
335
|
-
* @param
|
|
336
|
-
* @returns
|
|
363
|
+
* @param xmlData - XML 数据
|
|
364
|
+
* @returns 解析后的 JSON 对象
|
|
337
365
|
*/
|
|
338
|
-
static parseIgnoreAttributes(xmlData) {
|
|
366
|
+
static parseIgnoreAttributes(xmlData: string): Record<string, any> {
|
|
339
367
|
return Xml.parse(xmlData, { ignoreAttributes: true });
|
|
340
368
|
}
|
|
341
369
|
|
|
342
370
|
/**
|
|
343
371
|
* 静态方法:验证 XML 格式
|
|
344
|
-
* @param
|
|
345
|
-
* @returns
|
|
372
|
+
* @param xmlData - XML 数据
|
|
373
|
+
* @returns 是否有效
|
|
346
374
|
*/
|
|
347
|
-
static validate(xmlData) {
|
|
375
|
+
static validate(xmlData: string): boolean {
|
|
348
376
|
try {
|
|
349
377
|
Xml.parse(xmlData);
|
|
350
378
|
return true;
|
|
@@ -353,5 +381,3 @@ class Xml {
|
|
|
353
381
|
}
|
|
354
382
|
}
|
|
355
383
|
}
|
|
356
|
-
|
|
357
|
-
export { Xml };
|
package/.npmrc
DELETED
package/.prettierignore
DELETED
package/.prettierrc
DELETED
package/apis/health/info.js
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import { Env } from '../../config/env.js';
|
|
2
|
-
import { Api } from '../../utils/api.js';
|
|
3
|
-
import { RYes, RNo } from '../../utils/index.js';
|
|
4
|
-
|
|
5
|
-
export default Api.POST(
|
|
6
|
-
//
|
|
7
|
-
'健康检查',
|
|
8
|
-
false,
|
|
9
|
-
{},
|
|
10
|
-
[],
|
|
11
|
-
async (befly, ctx) => {
|
|
12
|
-
try {
|
|
13
|
-
const info = {
|
|
14
|
-
status: 'ok',
|
|
15
|
-
timestamp: new Date().toISOString(),
|
|
16
|
-
uptime: process.uptime(),
|
|
17
|
-
memory: process.memoryUsage(),
|
|
18
|
-
runtime: 'Bun',
|
|
19
|
-
version: Bun.version,
|
|
20
|
-
platform: process.platform,
|
|
21
|
-
arch: process.arch
|
|
22
|
-
};
|
|
23
|
-
// 检查 Redis 连接状态
|
|
24
|
-
if (Env.REDIS_ENABLE === 1) {
|
|
25
|
-
if (befly.redis) {
|
|
26
|
-
try {
|
|
27
|
-
await befly.redis.ping();
|
|
28
|
-
info.redis = '已连接';
|
|
29
|
-
} catch (error) {
|
|
30
|
-
info.redis = '未连接';
|
|
31
|
-
info.redisError = error.message;
|
|
32
|
-
}
|
|
33
|
-
} else {
|
|
34
|
-
info.redis = '未开启';
|
|
35
|
-
}
|
|
36
|
-
} else {
|
|
37
|
-
info.redis = '禁用';
|
|
38
|
-
}
|
|
39
|
-
return RYes('健康检查成功', info);
|
|
40
|
-
} catch (error) {
|
|
41
|
-
befly.logger.error({
|
|
42
|
-
msg: '健康检查失败',
|
|
43
|
-
error: error.message,
|
|
44
|
-
stack: error.stack
|
|
45
|
-
});
|
|
46
|
-
return RNo('健康检查失败');
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
);
|
package/apis/tool/tokenCheck.js
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { Env } from '../../config/env.js';
|
|
2
|
-
import { Api } from '../../utils/api.js';
|
|
3
|
-
import { RYes, RNo } from '../../utils/index.js';
|
|
4
|
-
import { Jwt } from '../../utils/jwt.js';
|
|
5
|
-
|
|
6
|
-
export default Api.POST(
|
|
7
|
-
//
|
|
8
|
-
'令牌检测',
|
|
9
|
-
false,
|
|
10
|
-
{},
|
|
11
|
-
[],
|
|
12
|
-
async (befly, ctx) => {
|
|
13
|
-
try {
|
|
14
|
-
const token = ctx.headers?.authorization?.split(' ')[1] || '';
|
|
15
|
-
if (!token) {
|
|
16
|
-
return RNo('令牌不能为空');
|
|
17
|
-
}
|
|
18
|
-
const jwtData = await Jwt.verify(token);
|
|
19
|
-
return RYes('令牌有效');
|
|
20
|
-
} catch (error) {
|
|
21
|
-
befly.logger.error({
|
|
22
|
-
msg: '令牌检测失败',
|
|
23
|
-
error: error.message,
|
|
24
|
-
stack: error.stack
|
|
25
|
-
});
|
|
26
|
-
return RNo('令牌检测失败');
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
);
|
package/bin/befly.js
DELETED
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env -S bun run
|
|
2
|
-
// Befly CLI (Bun): 列出并执行 core/scripts 与 tpl/scripts 下的脚本
|
|
3
|
-
|
|
4
|
-
import path from 'node:path';
|
|
5
|
-
import { Glob } from 'bun';
|
|
6
|
-
import { __dirscript as coreScriptsDir, getProjectDir } from '../system.js';
|
|
7
|
-
|
|
8
|
-
// 解析目录(来自 system.js)
|
|
9
|
-
// 核心脚本目录:core/scripts
|
|
10
|
-
// 用户项目(如 tpl)的脚本目录:始终基于当前工作目录
|
|
11
|
-
const tplScriptsDir = getProjectDir('scripts');
|
|
12
|
-
|
|
13
|
-
function safeList(dir) {
|
|
14
|
-
try {
|
|
15
|
-
// 使用 Bun.Glob 查找当前目录下的所有 .js 文件(不递归)
|
|
16
|
-
const glob = new Glob('*.js');
|
|
17
|
-
const files = Array.from(glob.scanSync({ cwd: dir, absolute: false, onlyFiles: true, dot: false }));
|
|
18
|
-
return files.map((f) => path.basename(f, '.js')).sort();
|
|
19
|
-
} catch {
|
|
20
|
-
return [];
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function buildScriptItems() {
|
|
25
|
-
const coreList = safeList(coreScriptsDir);
|
|
26
|
-
const tplList = safeList(tplScriptsDir);
|
|
27
|
-
const coreSet = new Set(coreList);
|
|
28
|
-
|
|
29
|
-
const items = [];
|
|
30
|
-
for (const name of coreList) {
|
|
31
|
-
items.push({
|
|
32
|
-
name: name,
|
|
33
|
-
source: 'core',
|
|
34
|
-
duplicate: tplList.includes(name),
|
|
35
|
-
path: path.resolve(coreScriptsDir, `${name}.js`)
|
|
36
|
-
});
|
|
37
|
-
}
|
|
38
|
-
for (const name of tplList) {
|
|
39
|
-
items.push({
|
|
40
|
-
name: name,
|
|
41
|
-
source: 'tpl',
|
|
42
|
-
duplicate: coreSet.has(name),
|
|
43
|
-
path: path.resolve(tplScriptsDir, `${name}.js`)
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
|
-
// 排序:名称字典序,core 在前
|
|
47
|
-
items.sort((a, b) => (a.name === b.name ? (a.source === b.source ? 0 : a.source === 'core' ? -1 : 1) : a.name.localeCompare(b.name)));
|
|
48
|
-
return items;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
function printAllScripts() {
|
|
52
|
-
const items = buildScriptItems();
|
|
53
|
-
if (items.length === 0) {
|
|
54
|
-
console.log(' • <无>');
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
for (const it of items) {
|
|
58
|
-
if (it.source === 'tpl' && it.duplicate) console.log(` • ${it.name}(重复)`);
|
|
59
|
-
else console.log(` • ${it.name}`);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
async function resolveScriptPath(name) {
|
|
64
|
-
const base = name.endsWith('.js') ? name.slice(0, -3) : name;
|
|
65
|
-
const filename = `${base}.js`;
|
|
66
|
-
const corePath = path.resolve(coreScriptsDir, filename);
|
|
67
|
-
const tplPath = path.resolve(tplScriptsDir, filename);
|
|
68
|
-
if (await Bun.file(corePath).exists()) return corePath;
|
|
69
|
-
if (await Bun.file(tplPath).exists()) return tplPath;
|
|
70
|
-
// 回退到列表匹配(防止极端路径或大小写差异)
|
|
71
|
-
const items = buildScriptItems();
|
|
72
|
-
const hit = items.find((it) => it.name.toLowerCase() === base.toLowerCase() && it.source === 'core') || items.find((it) => it.name.toLowerCase() === base.toLowerCase());
|
|
73
|
-
return hit ? hit.path : null;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
async function runScriptAtPath(targetPath, label, args = []) {
|
|
77
|
-
const bunExe = process.execPath || 'bun';
|
|
78
|
-
const child = Bun.spawn({
|
|
79
|
-
cmd: [bunExe, targetPath, ...args],
|
|
80
|
-
stdio: ['inherit', 'inherit', 'inherit'],
|
|
81
|
-
cwd: process.cwd(),
|
|
82
|
-
env: { ...process.env, LOG_TO_CONSOLE: '1' }
|
|
83
|
-
});
|
|
84
|
-
const code = await child.exited;
|
|
85
|
-
return code ?? 0;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
async function main() {
|
|
89
|
-
const [, , cmd, ...args] = process.argv;
|
|
90
|
-
// 无参数:打印所有脚本
|
|
91
|
-
if (!cmd) {
|
|
92
|
-
printAllScripts();
|
|
93
|
-
process.exit(0);
|
|
94
|
-
}
|
|
95
|
-
// 按名称执行(将剩余参数透传给脚本)
|
|
96
|
-
const target = await resolveScriptPath(cmd);
|
|
97
|
-
if (!target) {
|
|
98
|
-
console.error(`未找到脚本: ${cmd}`);
|
|
99
|
-
printAllScripts();
|
|
100
|
-
process.exit(1);
|
|
101
|
-
}
|
|
102
|
-
const code = await runScriptAtPath(target, cmd, args);
|
|
103
|
-
process.exit(code ?? 0);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
main().catch((e) => {
|
|
107
|
-
console.error('Befly CLI 执行失败:', e);
|
|
108
|
-
process.exit(1);
|
|
109
|
-
});
|
package/config/env.js
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
export const Env = {
|
|
2
|
-
// 项目模式
|
|
3
|
-
NODE_ENV: process.env.NODE_ENV,
|
|
4
|
-
// 应用名称
|
|
5
|
-
APP_NAME: process.env.APP_NAME,
|
|
6
|
-
// 加密盐
|
|
7
|
-
MD5_SALT: process.env.MD5_SALT,
|
|
8
|
-
// 监听端口
|
|
9
|
-
APP_PORT: Number(process.env.APP_PORT),
|
|
10
|
-
// 监听主机
|
|
11
|
-
APP_HOST: process.env.APP_HOST,
|
|
12
|
-
// 超级管理员密码
|
|
13
|
-
DEV_PASSWORD: process.env.DEV_PASSWORD,
|
|
14
|
-
// 请求体大小 10M
|
|
15
|
-
BODY_LIMIT: Number(process.env.BODY_LIMIT),
|
|
16
|
-
// 是否进行参数验证
|
|
17
|
-
PARAMS_CHECK: process.env.PARAMS_CHECK,
|
|
18
|
-
// 日志等级
|
|
19
|
-
LOG_LEVEL: process.env.LOG_LEVEL,
|
|
20
|
-
LOG_EXCLUDE_FIELDS: process.env.LOG_EXCLUDE_FIELDS,
|
|
21
|
-
LOG_DIR: process.env.LOG_DIR,
|
|
22
|
-
LOG_TO_CONSOLE: Number(process.env.LOG_TO_CONSOLE),
|
|
23
|
-
LOG_MAX_SIZE: Number(process.env.LOG_MAX_SIZE),
|
|
24
|
-
// 时区
|
|
25
|
-
TZ: process.env.TZ,
|
|
26
|
-
// 数据库配置
|
|
27
|
-
DB_ENABLE: Number(process.env.DB_ENABLE),
|
|
28
|
-
// 通用数据库连接参数
|
|
29
|
-
DB_TYPE: process.env.DB_TYPE, // sqlite | mysql | postgresql
|
|
30
|
-
DB_HOST: process.env.DB_HOST,
|
|
31
|
-
DB_PORT: Number(process.env.DB_PORT),
|
|
32
|
-
DB_USER: process.env.DB_USER,
|
|
33
|
-
DB_PASS: process.env.DB_PASS,
|
|
34
|
-
DB_NAME: process.env.DB_NAME,
|
|
35
|
-
DB_DEBUG: Number(process.env.DB_DEBUG),
|
|
36
|
-
DB_POOL_MAX: Number(process.env.DB_POOL_MAX),
|
|
37
|
-
// Redis配置
|
|
38
|
-
REDIS_URL: process.env.REDIS_URL,
|
|
39
|
-
REDIS_ENABLE: Number(process.env.REDIS_ENABLE),
|
|
40
|
-
REDIS_HOST: process.env.REDIS_HOST,
|
|
41
|
-
REDIS_PORT: Number(process.env.REDIS_PORT),
|
|
42
|
-
REDIS_USERNAME: process.env.REDIS_USERNAME,
|
|
43
|
-
REDIS_PASSWORD: process.env.REDIS_PASSWORD,
|
|
44
|
-
REDIS_DB: Number(process.env.REDIS_DB),
|
|
45
|
-
REDIS_KEY_PREFIX: process.env.REDIS_KEY_PREFIX,
|
|
46
|
-
// JWT配置
|
|
47
|
-
JWT_SECRET: process.env.JWT_SECRET,
|
|
48
|
-
JWT_EXPIRES_IN: process.env.JWT_EXPIRES_IN,
|
|
49
|
-
JWT_ALGORITHM: process.env.JWT_ALGORITHM,
|
|
50
|
-
// 邮件配置
|
|
51
|
-
MAIL_HOST: process.env.MAIL_HOST,
|
|
52
|
-
MAIL_PORT: Number(process.env.MAIL_PORT),
|
|
53
|
-
MAIL_POOL: process.env.MAIL_POOL,
|
|
54
|
-
MAIL_SECURE: process.env.MAIL_SECURE,
|
|
55
|
-
MAIL_USER: process.env.MAIL_USER,
|
|
56
|
-
MAIL_PASS: process.env.MAIL_PASS,
|
|
57
|
-
MAIL_SENDER: process.env.MAIL_SENDER,
|
|
58
|
-
MAIL_ADDRESS: process.env.MAIL_ADDRESS,
|
|
59
|
-
// 同步脚本开关(用于 core/scripts/syncDb.js)
|
|
60
|
-
SYNC_MERGE_ALTER: process.env.SYNC_MERGE_ALTER,
|
|
61
|
-
SYNC_ONLINE_INDEX: process.env.SYNC_ONLINE_INDEX,
|
|
62
|
-
SYNC_DISALLOW_SHRINK: process.env.SYNC_DISALLOW_SHRINK,
|
|
63
|
-
SYNC_ALLOW_TYPE_CHANGE: process.env.SYNC_ALLOW_TYPE_CHANGE
|
|
64
|
-
};
|