befly 3.8.1 → 3.8.3
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/check.ts +201 -95
- package/env.ts +3 -3
- package/{plugins/cache.ts → lib/cacheHelper.ts} +99 -35
- package/lib/redisHelper.ts +49 -65
- package/lib/validator.ts +29 -32
- package/loader/loadApis.ts +172 -0
- package/loader/loadPlugins.ts +244 -0
- package/main.ts +116 -23
- package/menu.json +14 -14
- package/package.json +4 -4
- package/paths.ts +7 -0
- package/types/common.d.ts +28 -7
- package/util.ts +76 -36
- package/lib/addon.ts +0 -77
- package/lifecycle/bootstrap.ts +0 -63
- package/lifecycle/checker.ts +0 -122
- package/lifecycle/lifecycle.ts +0 -104
- package/lifecycle/loader.ts +0 -427
- package/plugins/db.ts +0 -59
- package/plugins/logger.ts +0 -27
- package/plugins/redis.ts +0 -41
package/util.ts
CHANGED
|
@@ -5,11 +5,10 @@ import { isEmpty, isPlainObject } from 'es-toolkit/compat';
|
|
|
5
5
|
import { snakeCase, camelCase, kebabCase } from 'es-toolkit/string';
|
|
6
6
|
import { Env } from './env.js';
|
|
7
7
|
import { Logger } from './lib/logger.js';
|
|
8
|
-
import { projectDir } from './paths.js';
|
|
8
|
+
import { projectDir, projectAddonsDir } from './paths.js';
|
|
9
9
|
import type { KeyValue } from './types/common.js';
|
|
10
10
|
import type { JwtPayload, JwtSignOptions, JwtVerifyOptions } from './types/jwt';
|
|
11
11
|
import type { Plugin } from './types/plugin.js';
|
|
12
|
-
import type { ParsedFieldRule } from './types/common.js';
|
|
13
12
|
|
|
14
13
|
// ========================================
|
|
15
14
|
// API 响应工具
|
|
@@ -39,6 +38,10 @@ export const No = <T = any>(msg: string = '', data: T | {} = {}, other: KeyValue
|
|
|
39
38
|
};
|
|
40
39
|
};
|
|
41
40
|
|
|
41
|
+
// ========================================
|
|
42
|
+
// 动态导入工具
|
|
43
|
+
// ========================================
|
|
44
|
+
|
|
42
45
|
// ========================================
|
|
43
46
|
// 字段转换工具(重新导出 lib/convert.ts)
|
|
44
47
|
// ========================================
|
|
@@ -170,48 +173,85 @@ export const calcPerfTime = (startTime: number, endTime: number = Bun.nanosecond
|
|
|
170
173
|
};
|
|
171
174
|
|
|
172
175
|
// ========================================
|
|
173
|
-
//
|
|
176
|
+
// Addon 工具函数
|
|
174
177
|
// ========================================
|
|
175
178
|
|
|
176
179
|
/**
|
|
177
|
-
*
|
|
178
|
-
*
|
|
179
|
-
*
|
|
180
|
+
* 扫描所有可用的 addon
|
|
181
|
+
* 优先从本地 addons/ 目录加载,其次从 node_modules/@befly-addon/ 加载
|
|
182
|
+
* @returns addon 名称数组
|
|
180
183
|
*/
|
|
181
|
-
export const
|
|
182
|
-
const
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
184
|
+
export const scanAddons = (): string[] => {
|
|
185
|
+
const addons = new Set<string>();
|
|
186
|
+
|
|
187
|
+
// 1. 扫描本地 addons 目录(优先级高)
|
|
188
|
+
// if (existsSync(projectAddonsDir)) {
|
|
189
|
+
// try {
|
|
190
|
+
// const localAddons = fs.readdirSync(projectAddonsDir).filter((name) => {
|
|
191
|
+
// const fullPath = join(projectAddonsDir, name);
|
|
192
|
+
// try {
|
|
193
|
+
// const stat = statSync(fullPath);
|
|
194
|
+
// return stat.isDirectory() && !name.startsWith('_');
|
|
195
|
+
// } catch {
|
|
196
|
+
// return false;
|
|
197
|
+
// }
|
|
198
|
+
// });
|
|
199
|
+
// localAddons.forEach((name) => addons.add(name));
|
|
200
|
+
// } catch (err) {
|
|
201
|
+
// // 忽略本地目录读取错误
|
|
202
|
+
// }
|
|
203
|
+
// }
|
|
204
|
+
|
|
205
|
+
// 2. 扫描 node_modules/@befly-addon 目录
|
|
206
|
+
const beflyDir = join(projectDir, 'node_modules', '@befly-addon');
|
|
207
|
+
if (existsSync(beflyDir)) {
|
|
208
|
+
try {
|
|
209
|
+
const npmAddons = fs.readdirSync(beflyDir).filter((name) => {
|
|
210
|
+
// 如果本地已存在,跳过 npm 包版本
|
|
211
|
+
if (addons.has(name)) return false;
|
|
212
|
+
|
|
213
|
+
const fullPath = join(beflyDir, name);
|
|
214
|
+
try {
|
|
215
|
+
const stat = statSync(fullPath);
|
|
216
|
+
return stat.isDirectory();
|
|
217
|
+
} catch {
|
|
218
|
+
return false;
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
npmAddons.forEach((name) => addons.add(name));
|
|
222
|
+
} catch {
|
|
223
|
+
// 忽略 npm 目录读取错误
|
|
193
224
|
}
|
|
194
225
|
}
|
|
195
|
-
parts.push(currentPart);
|
|
196
226
|
|
|
197
|
-
|
|
227
|
+
return Array.from(addons).sort();
|
|
228
|
+
};
|
|
198
229
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
230
|
+
/**
|
|
231
|
+
* 获取 addon 的指定子目录路径
|
|
232
|
+
* 优先返回本地 addons 目录,其次返回 node_modules 目录
|
|
233
|
+
* @param name - addon 名称
|
|
234
|
+
* @param subDir - 子目录名称
|
|
235
|
+
* @returns 完整路径
|
|
236
|
+
*/
|
|
237
|
+
export const getAddonDir = (name: string, subDir: string): string => {
|
|
238
|
+
// 优先使用本地 addons 目录
|
|
239
|
+
// const localPath = join(projectAddonsDir, name, subDir);
|
|
240
|
+
// if (existsSync(localPath)) {
|
|
241
|
+
// return localPath;
|
|
242
|
+
// }
|
|
202
243
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
}
|
|
244
|
+
// 降级使用 node_modules 目录
|
|
245
|
+
return join(projectDir, 'node_modules', '@befly-addon', name, subDir);
|
|
246
|
+
};
|
|
207
247
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
248
|
+
/**
|
|
249
|
+
* 检查 addon 子目录是否存在
|
|
250
|
+
* @param name - addon 名称
|
|
251
|
+
* @param subDir - 子目录名称
|
|
252
|
+
* @returns 是否存在
|
|
253
|
+
*/
|
|
254
|
+
export const addonDirExists = (name: string, subDir: string): boolean => {
|
|
255
|
+
const dir = getAddonDir(name, subDir);
|
|
256
|
+
return existsSync(dir) && statSync(dir).isDirectory();
|
|
217
257
|
};
|
package/lib/addon.ts
DELETED
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Addon 管理工具类
|
|
3
|
-
* 提供 addon 的扫描、路径获取等功能
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import fs from 'node:fs';
|
|
7
|
-
import { join } from 'pathe';
|
|
8
|
-
import { existsSync, statSync, readdirSync } from 'node:fs';
|
|
9
|
-
import { projectDir } from '../paths.js';
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Addon 管理类
|
|
13
|
-
*/
|
|
14
|
-
export class Addon {
|
|
15
|
-
/**
|
|
16
|
-
* 扫描所有可用的 addon
|
|
17
|
-
* @returns addon 名称数组
|
|
18
|
-
*/
|
|
19
|
-
static scan(): string[] {
|
|
20
|
-
const beflyDir = join(projectDir, 'node_modules', '@befly-addon');
|
|
21
|
-
|
|
22
|
-
if (!existsSync(beflyDir)) {
|
|
23
|
-
return [];
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
try {
|
|
27
|
-
return fs
|
|
28
|
-
.readdirSync(beflyDir)
|
|
29
|
-
.filter((name) => {
|
|
30
|
-
// addon 名称格式:admin, demo 等(不带 addon- 前缀)
|
|
31
|
-
const fullPath = join(beflyDir, name);
|
|
32
|
-
try {
|
|
33
|
-
const stat = statSync(fullPath);
|
|
34
|
-
return stat.isDirectory();
|
|
35
|
-
} catch {
|
|
36
|
-
return false;
|
|
37
|
-
}
|
|
38
|
-
})
|
|
39
|
-
.sort();
|
|
40
|
-
} catch {
|
|
41
|
-
return [];
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* 获取 addon 的指定子目录路径
|
|
47
|
-
* @param name - addon 名称
|
|
48
|
-
* @param subDir - 子目录名称
|
|
49
|
-
* @returns 完整路径
|
|
50
|
-
*/
|
|
51
|
-
static getDir(name: string, subDir: string): string {
|
|
52
|
-
return join(projectDir, 'node_modules', '@befly-addon', name, subDir);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* 检查 addon 子目录是否存在
|
|
57
|
-
* @param name - addon 名称
|
|
58
|
-
* @param subDir - 子目录名称
|
|
59
|
-
* @returns 是否存在
|
|
60
|
-
*/
|
|
61
|
-
static dirExists(name: string, subDir: string): boolean {
|
|
62
|
-
const dir = this.getDir(name, subDir);
|
|
63
|
-
return existsSync(dir) && statSync(dir).isDirectory();
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* 获取插件目录列表
|
|
68
|
-
* @param addonsDir - addons 根目录路径
|
|
69
|
-
* @returns 插件名称数组
|
|
70
|
-
*/
|
|
71
|
-
static getDirs(addonsDir: string): string[] {
|
|
72
|
-
return readdirSync(addonsDir).filter((name) => {
|
|
73
|
-
const addonPath = join(addonsDir, name);
|
|
74
|
-
return statSync(addonPath).isDirectory() && !name.startsWith('_');
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
|
-
}
|
package/lifecycle/bootstrap.ts
DELETED
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 服务启动引导器
|
|
3
|
-
* 负责组装和启动Bun HTTP服务器
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { Logger } from '../lib/logger.js';
|
|
7
|
-
import { calcPerfTime, No } from '../util.js';
|
|
8
|
-
import { Env } from '../env.js';
|
|
9
|
-
import { rootHandler } from '../router/root.js';
|
|
10
|
-
import { apiHandler } from '../router/api.js';
|
|
11
|
-
import { staticHandler } from '../router/static.js';
|
|
12
|
-
|
|
13
|
-
import type { Server } from 'bun';
|
|
14
|
-
import type { BeflyContext } from '../types/befly.js';
|
|
15
|
-
import type { ApiRoute } from '../types/api.js';
|
|
16
|
-
import type { Plugin } from '../types/plugin.js';
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* 引导器类
|
|
20
|
-
*/
|
|
21
|
-
export class Bootstrap {
|
|
22
|
-
/**
|
|
23
|
-
* 启动HTTP服务器
|
|
24
|
-
* @param befly - Befly实例(需要访问 apiRoutes, pluginLists, appContext, appOptions)
|
|
25
|
-
* @param callback - 启动后的回调函数
|
|
26
|
-
*/
|
|
27
|
-
static async start(
|
|
28
|
-
befly: {
|
|
29
|
-
apiRoutes: Map<string, ApiRoute>;
|
|
30
|
-
pluginLists: Plugin[];
|
|
31
|
-
appContext: BeflyContext;
|
|
32
|
-
appOptions: any;
|
|
33
|
-
},
|
|
34
|
-
callback?: (server: Server) => void
|
|
35
|
-
): Promise<Server> {
|
|
36
|
-
const startTime = Bun.nanoseconds();
|
|
37
|
-
|
|
38
|
-
const server = Bun.serve({
|
|
39
|
-
port: Env.APP_PORT,
|
|
40
|
-
hostname: Env.APP_HOST,
|
|
41
|
-
routes: {
|
|
42
|
-
'/': rootHandler,
|
|
43
|
-
'/api/*': apiHandler(befly.apiRoutes, befly.pluginLists, befly.appContext),
|
|
44
|
-
'/*': staticHandler,
|
|
45
|
-
...(befly.appOptions.routes || {})
|
|
46
|
-
},
|
|
47
|
-
error: (error: Error) => {
|
|
48
|
-
Logger.error('服务启动时发生错误', error);
|
|
49
|
-
return Response.json(No('内部服务器错误'));
|
|
50
|
-
}
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
const finalStartupTime = calcPerfTime(startTime);
|
|
54
|
-
Logger.info(`${Env.APP_NAME} 服务器启动成功! 服务器启动耗时: ${finalStartupTime}`);
|
|
55
|
-
Logger.info(`服务器监听地址: http://${Env.APP_HOST}:${Env.APP_PORT}`);
|
|
56
|
-
|
|
57
|
-
if (callback && typeof callback === 'function') {
|
|
58
|
-
callback(server);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
return server;
|
|
62
|
-
}
|
|
63
|
-
}
|
package/lifecycle/checker.ts
DELETED
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 系统检查管理器
|
|
3
|
-
* 负责在框架启动前执行系统检查
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { join, basename } from 'pathe';
|
|
7
|
-
import { existsSync, statSync } from 'node:fs';
|
|
8
|
-
import { Logger } from '../lib/logger.js';
|
|
9
|
-
import { calcPerfTime } from '../util.js';
|
|
10
|
-
import { projectCheckDir } from '../paths.js';
|
|
11
|
-
import { checkDefault } from '../check.js';
|
|
12
|
-
import { Addon } from '../lib/addon.js';
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* 系统检查器类
|
|
16
|
-
*/
|
|
17
|
-
export class Checker {
|
|
18
|
-
/**
|
|
19
|
-
* 执行所有系统检查
|
|
20
|
-
*/
|
|
21
|
-
static async run(): Promise<void> {
|
|
22
|
-
try {
|
|
23
|
-
const checkStartTime = Bun.nanoseconds();
|
|
24
|
-
|
|
25
|
-
// 先执行默认检查(有异常会自动抛出)
|
|
26
|
-
await checkDefault();
|
|
27
|
-
|
|
28
|
-
const glob = new Bun.Glob('*.{ts}');
|
|
29
|
-
|
|
30
|
-
// 统计信息
|
|
31
|
-
const stats = {
|
|
32
|
-
totalChecks: 0,
|
|
33
|
-
passedChecks: 0,
|
|
34
|
-
failedChecks: 0
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
// 检查目录列表:先项目,后 addons
|
|
38
|
-
const checkDirs: Array<{ path: string; type: 'app' | 'addon'; addonName?: string }> = [];
|
|
39
|
-
|
|
40
|
-
// 添加项目 checks 目录(如果存在)
|
|
41
|
-
if (existsSync(projectCheckDir) && statSync(projectCheckDir).isDirectory()) {
|
|
42
|
-
checkDirs.push({ path: projectCheckDir, type: 'app' });
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// 添加所有 addon 的 checks 目录
|
|
46
|
-
const addons = Addon.scan();
|
|
47
|
-
for (const addon of addons) {
|
|
48
|
-
if (Addon.dirExists(addon, 'checks')) {
|
|
49
|
-
checkDirs.push({
|
|
50
|
-
path: Addon.getDir(addon, 'checks'),
|
|
51
|
-
type: 'addon',
|
|
52
|
-
addonName: addon
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// 按顺序扫描并执行检查函数
|
|
58
|
-
for (const checkConfig of checkDirs) {
|
|
59
|
-
const { path: checkDir, type: type } = checkConfig;
|
|
60
|
-
const addonName = 'addonName' in checkConfig ? checkConfig.addonName : undefined;
|
|
61
|
-
const checkTypeLabel = type === 'app' ? '项目' : `组件${addonName}`;
|
|
62
|
-
|
|
63
|
-
for await (const file of glob.scan({
|
|
64
|
-
cwd: checkDir,
|
|
65
|
-
onlyFiles: true,
|
|
66
|
-
absolute: true
|
|
67
|
-
})) {
|
|
68
|
-
const fileName = basename(file);
|
|
69
|
-
if (fileName.startsWith('_')) continue; // 跳过以下划线开头的文件
|
|
70
|
-
|
|
71
|
-
try {
|
|
72
|
-
stats.totalChecks++;
|
|
73
|
-
const singleCheckStart = Bun.nanoseconds();
|
|
74
|
-
|
|
75
|
-
// 导入检查模块
|
|
76
|
-
const checkModule = await import(file);
|
|
77
|
-
|
|
78
|
-
// 获取 default 导出的检查函数
|
|
79
|
-
const checkFn = checkModule.default;
|
|
80
|
-
|
|
81
|
-
// 执行检查函数
|
|
82
|
-
if (typeof checkFn === 'function') {
|
|
83
|
-
const checkResult = await checkFn();
|
|
84
|
-
const singleCheckTime = calcPerfTime(singleCheckStart);
|
|
85
|
-
|
|
86
|
-
// 检查返回值是否为 boolean
|
|
87
|
-
if (typeof checkResult !== 'boolean') {
|
|
88
|
-
Logger.warn(`${checkTypeLabel}检查 ${fileName} 返回值必须为 true 或 false,当前为 ${typeof checkResult}`);
|
|
89
|
-
stats.failedChecks++;
|
|
90
|
-
} else if (checkResult === true) {
|
|
91
|
-
stats.passedChecks++;
|
|
92
|
-
} else {
|
|
93
|
-
Logger.warn(`${checkTypeLabel}检查未通过: ${fileName}`);
|
|
94
|
-
stats.failedChecks++;
|
|
95
|
-
}
|
|
96
|
-
} else {
|
|
97
|
-
Logger.warn(`${checkTypeLabel}检查文件 ${fileName} 未找到 default 导出的检查函数`);
|
|
98
|
-
stats.failedChecks++;
|
|
99
|
-
}
|
|
100
|
-
} catch (error: any) {
|
|
101
|
-
const singleCheckTime = calcPerfTime(Bun.nanoseconds());
|
|
102
|
-
Logger.error(`${checkTypeLabel}检查失败 ${fileName},耗时: ${singleCheckTime}`, error);
|
|
103
|
-
stats.failedChecks++;
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
const totalCheckTime = calcPerfTime(checkStartTime);
|
|
109
|
-
|
|
110
|
-
// 输出检查结果统计
|
|
111
|
-
if (stats.failedChecks > 0) {
|
|
112
|
-
Logger.error(`系统检查失败: ${stats.failedChecks}/${stats.totalChecks},耗时: ${totalCheckTime}`);
|
|
113
|
-
process.exit(1);
|
|
114
|
-
} else if (stats.totalChecks > 0) {
|
|
115
|
-
Logger.info(`系统检查通过: ${stats.passedChecks}/${stats.totalChecks},耗时: ${totalCheckTime}`);
|
|
116
|
-
}
|
|
117
|
-
} catch (error: any) {
|
|
118
|
-
Logger.error('执行系统检查时发生错误', error);
|
|
119
|
-
process.exit(1);
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
}
|
package/lifecycle/lifecycle.ts
DELETED
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 生命周期管理器
|
|
3
|
-
* 统一管理框架的启动流程:检查、加载插件、加载API、启动服务器
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { Logger } from '../lib/logger.js';
|
|
7
|
-
import { Database } from '../lib/database.js';
|
|
8
|
-
import { Loader } from './loader.js';
|
|
9
|
-
import { Checker } from './checker.js';
|
|
10
|
-
import { Env } from '../env.js';
|
|
11
|
-
import { calcPerfTime } from '../util.js';
|
|
12
|
-
import { Addon } from '../lib/addon.js';
|
|
13
|
-
import { Bootstrap } from './bootstrap.js';
|
|
14
|
-
|
|
15
|
-
import type { Server } from 'bun';
|
|
16
|
-
import type { Plugin } from '../types/plugin.js';
|
|
17
|
-
import type { ApiRoute } from '../types/api.js';
|
|
18
|
-
import type { BeflyContext, BeflyOptions } from '../types/befly.js';
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* 生命周期管理类
|
|
22
|
-
*/
|
|
23
|
-
export class Lifecycle {
|
|
24
|
-
/** API 路由映射表 */
|
|
25
|
-
private apiRoutes: Map<string, ApiRoute> = new Map();
|
|
26
|
-
|
|
27
|
-
/** 插件列表 */
|
|
28
|
-
private pluginLists: Plugin[] = [];
|
|
29
|
-
|
|
30
|
-
/** 应用配置选项 */
|
|
31
|
-
private options: BeflyOptions;
|
|
32
|
-
|
|
33
|
-
constructor(options: BeflyOptions = {}) {
|
|
34
|
-
this.options = options;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* 启动完整的生命周期流程
|
|
39
|
-
* @param appContext - 应用上下文
|
|
40
|
-
* @param callback - 启动完成后的回调函数
|
|
41
|
-
*/
|
|
42
|
-
async start(appContext: BeflyContext, callback?: (server: Server) => void): Promise<Server> {
|
|
43
|
-
const serverStartTime = Bun.nanoseconds();
|
|
44
|
-
|
|
45
|
-
// 1. 执行系统检查
|
|
46
|
-
await Checker.run();
|
|
47
|
-
|
|
48
|
-
// 2. 加载插件
|
|
49
|
-
await Loader.loadPlugins({ pluginLists: this.pluginLists, appContext });
|
|
50
|
-
|
|
51
|
-
// 3. 加载所有 API(addon + app)
|
|
52
|
-
await this.loadAllApis();
|
|
53
|
-
|
|
54
|
-
// 4. 启动 HTTP 服务器
|
|
55
|
-
const totalStartupTime = calcPerfTime(serverStartTime);
|
|
56
|
-
|
|
57
|
-
return await Bootstrap.start(
|
|
58
|
-
{
|
|
59
|
-
apiRoutes: this.apiRoutes,
|
|
60
|
-
pluginLists: this.pluginLists,
|
|
61
|
-
appContext,
|
|
62
|
-
appOptions: this.options
|
|
63
|
-
},
|
|
64
|
-
callback
|
|
65
|
-
);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* 加载所有 API 路由
|
|
70
|
-
* 包括 core APIs、addon APIs 和 app APIs
|
|
71
|
-
*/
|
|
72
|
-
private async loadAllApis(): Promise<void> {
|
|
73
|
-
// 1. 加载 Core APIs
|
|
74
|
-
try {
|
|
75
|
-
await Loader.loadApis('core', this.apiRoutes, { where: 'core' });
|
|
76
|
-
} catch (error: any) {
|
|
77
|
-
Logger.error(`核心 APIs 加载失败`, error);
|
|
78
|
-
throw error;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// 2. 加载 addon APIs
|
|
82
|
-
const addons = Addon.scan();
|
|
83
|
-
|
|
84
|
-
for (const addon of addons) {
|
|
85
|
-
const hasApis = Addon.dirExists(addon, 'apis');
|
|
86
|
-
if (hasApis) {
|
|
87
|
-
try {
|
|
88
|
-
await Loader.loadApis(addon, this.apiRoutes, { where: 'addon', addonName: addon });
|
|
89
|
-
} catch (error: any) {
|
|
90
|
-
Logger.error(`[组件 ${addon}] APIs 加载失败`, error);
|
|
91
|
-
throw error;
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// 3. 加载用户 APIs
|
|
97
|
-
try {
|
|
98
|
-
await Loader.loadApis('app', this.apiRoutes, { where: 'app' });
|
|
99
|
-
} catch (error: any) {
|
|
100
|
-
Logger.error(`用户 APIs 加载失败`, error);
|
|
101
|
-
throw error;
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
}
|