befly 3.2.1 → 3.3.1

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.
Files changed (73) hide show
  1. package/bin/index.ts +138 -0
  2. package/checks/conflict.ts +35 -25
  3. package/checks/table.ts +6 -6
  4. package/commands/addon.ts +57 -0
  5. package/commands/build.ts +74 -0
  6. package/commands/dev.ts +94 -0
  7. package/commands/index.ts +252 -0
  8. package/commands/script.ts +303 -0
  9. package/commands/start.ts +80 -0
  10. package/commands/syncApi.ts +327 -0
  11. package/{scripts → commands}/syncDb/apply.ts +2 -2
  12. package/{scripts → commands}/syncDb/constants.ts +13 -7
  13. package/{scripts → commands}/syncDb/ddl.ts +7 -5
  14. package/{scripts → commands}/syncDb/helpers.ts +18 -18
  15. package/{scripts → commands}/syncDb/index.ts +37 -23
  16. package/{scripts → commands}/syncDb/sqlite.ts +1 -1
  17. package/{scripts → commands}/syncDb/state.ts +10 -4
  18. package/{scripts → commands}/syncDb/table.ts +7 -7
  19. package/{scripts → commands}/syncDb/tableCreate.ts +7 -6
  20. package/{scripts → commands}/syncDb/types.ts +5 -5
  21. package/{scripts → commands}/syncDb/version.ts +1 -1
  22. package/commands/syncDb.ts +35 -0
  23. package/commands/syncDev.ts +174 -0
  24. package/commands/syncMenu.ts +368 -0
  25. package/config/env.ts +4 -4
  26. package/config/menu.json +67 -0
  27. package/{utils/crypto.ts → lib/cipher.ts} +16 -67
  28. package/lib/database.ts +296 -0
  29. package/{utils → lib}/dbHelper.ts +102 -56
  30. package/{utils → lib}/jwt.ts +124 -151
  31. package/{utils → lib}/logger.ts +47 -24
  32. package/lib/middleware.ts +271 -0
  33. package/{utils → lib}/redisHelper.ts +4 -4
  34. package/{utils/validate.ts → lib/validator.ts} +101 -78
  35. package/lifecycle/bootstrap.ts +63 -0
  36. package/lifecycle/checker.ts +165 -0
  37. package/lifecycle/cluster.ts +241 -0
  38. package/lifecycle/lifecycle.ts +139 -0
  39. package/lifecycle/loader.ts +513 -0
  40. package/main.ts +14 -12
  41. package/package.json +21 -9
  42. package/paths.ts +34 -0
  43. package/plugins/cache.ts +187 -0
  44. package/plugins/db.ts +4 -4
  45. package/plugins/logger.ts +1 -1
  46. package/plugins/redis.ts +4 -4
  47. package/router/api.ts +155 -0
  48. package/router/root.ts +53 -0
  49. package/router/static.ts +76 -0
  50. package/types/api.d.ts +0 -36
  51. package/types/befly.d.ts +8 -6
  52. package/types/common.d.ts +1 -1
  53. package/types/context.d.ts +3 -3
  54. package/types/util.d.ts +45 -0
  55. package/util.ts +299 -0
  56. package/config/fields.ts +0 -55
  57. package/config/regexAliases.ts +0 -51
  58. package/config/reserved.ts +0 -96
  59. package/scripts/syncDb/tests/constants.test.ts +0 -105
  60. package/scripts/syncDb/tests/ddl.test.ts +0 -134
  61. package/scripts/syncDb/tests/helpers.test.ts +0 -70
  62. package/scripts/syncDb.ts +0 -10
  63. package/types/index.d.ts +0 -450
  64. package/types/index.ts +0 -438
  65. package/types/validator.ts +0 -43
  66. package/utils/colors.ts +0 -221
  67. package/utils/database.ts +0 -348
  68. package/utils/helper.ts +0 -812
  69. package/utils/index.ts +0 -33
  70. package/utils/requestContext.ts +0 -167
  71. /package/{scripts → commands}/syncDb/schema.ts +0 -0
  72. /package/{utils → lib}/sqlBuilder.ts +0 -0
  73. /package/{utils → lib}/xml.ts +0 -0
@@ -0,0 +1,165 @@
1
+ /**
2
+ * 系统检查管理器
3
+ * 负责在框架启动前执行系统检查
4
+ */
5
+
6
+ import { join, basename } from 'pathe';
7
+ import { Logger } from '../lib/logger.js';
8
+ import { calcPerfTime } from '../util.js';
9
+ import { paths } from '../paths.js';
10
+ import { scanAddons, getAddonDir, addonDirExists } from '../util.js';
11
+
12
+ /**
13
+ * 系统检查器类
14
+ */
15
+ export class Checker {
16
+ /**
17
+ * 执行所有系统检查
18
+ */
19
+ static async run(): Promise<void> {
20
+ try {
21
+ const checkStartTime = Bun.nanoseconds();
22
+
23
+ const glob = new Bun.Glob('*.{ts}');
24
+
25
+ // 统计信息
26
+ const stats = {
27
+ totalChecks: 0,
28
+ passedChecks: 0,
29
+ failedChecks: 0
30
+ };
31
+
32
+ // 1. 优先执行资源冲突检测(如果存在)
33
+ try {
34
+ const conflictCheckPath = join(paths.rootCheckDir, 'conflict.ts');
35
+ const conflictCheckFile = Bun.file(conflictCheckPath);
36
+
37
+ if (await conflictCheckFile.exists()) {
38
+ stats.totalChecks++;
39
+ const conflictCheckStart = Bun.nanoseconds();
40
+
41
+ const conflictModule = await import(conflictCheckPath);
42
+ const conflictCheckFn = conflictModule.default;
43
+
44
+ if (typeof conflictCheckFn === 'function') {
45
+ const conflictResult = await conflictCheckFn();
46
+ const conflictCheckTime = calcPerfTime(conflictCheckStart);
47
+
48
+ if (typeof conflictResult !== 'boolean') {
49
+ Logger.warn(`核心检查 conflict.ts 返回值必须为 true 或 false,当前为 ${typeof conflictResult},耗时: ${conflictCheckTime}`);
50
+ stats.failedChecks++;
51
+ } else if (conflictResult === true) {
52
+ stats.passedChecks++;
53
+ Logger.info(`核心检查 conflict.ts 通过,耗时: ${conflictCheckTime}`);
54
+ } else {
55
+ Logger.warn(`核心检查未通过: conflict.ts,耗时: ${conflictCheckTime}`);
56
+ stats.failedChecks++;
57
+ // 资源冲突检测失败,立即终止
58
+ Logger.warn('资源冲突检测失败,无法继续启动', {
59
+ totalChecks: stats.totalChecks,
60
+ passedChecks: stats.passedChecks,
61
+ failedChecks: stats.failedChecks
62
+ });
63
+ process.exit(1);
64
+ }
65
+ }
66
+ }
67
+ } catch (error: any) {
68
+ Logger.error('执行资源冲突检测时出错:', error);
69
+ stats.failedChecks++;
70
+ }
71
+
72
+ // 2. 检查目录列表:先核心,后项目,最后 addons
73
+ // 检查所有 checks 目录
74
+ const checkDirs = [{ path: paths.rootCheckDir, type: 'core' as const }]; // 添加所有 addon 的 checks 目录
75
+ const addons = scanAddons();
76
+ for (const addon of addons) {
77
+ if (addonDirExists(addon, 'checks')) {
78
+ checkDirs.push({
79
+ path: getAddonDir(addon, 'checks'),
80
+ type: 'addon' as const,
81
+ addonName: addon
82
+ });
83
+ }
84
+ }
85
+
86
+ // 按顺序扫描并执行检查函数
87
+ for (const checkConfig of checkDirs) {
88
+ const { path: checkDir, type } = checkConfig;
89
+ const addonName = 'addonName' in checkConfig ? checkConfig.addonName : undefined;
90
+ const checkTypeLabel = type === 'core' ? '核心' : type === 'project' ? '项目' : `组件${addonName}`;
91
+ Logger.info(`开始执行${checkTypeLabel}检查,目录: ${checkDir}`);
92
+
93
+ for await (const file of glob.scan({
94
+ cwd: checkDir,
95
+ onlyFiles: true,
96
+ absolute: true
97
+ })) {
98
+ const fileName = basename(file);
99
+ if (fileName.startsWith('_')) continue; // 跳过以下划线开头的文件
100
+
101
+ // 跳过已经执行过的 conflict.ts
102
+ if (type === 'core' && fileName === 'conflict.ts') continue;
103
+
104
+ try {
105
+ stats.totalChecks++;
106
+ const singleCheckStart = Bun.nanoseconds();
107
+
108
+ // 导入检查模块
109
+ const checkModule = await import(file);
110
+
111
+ // 获取 default 导出的检查函数
112
+ const checkFn = checkModule.default;
113
+
114
+ // 执行检查函数
115
+ if (typeof checkFn === 'function') {
116
+ const checkResult = await checkFn();
117
+ const singleCheckTime = calcPerfTime(singleCheckStart);
118
+
119
+ // 检查返回值是否为 boolean
120
+ if (typeof checkResult !== 'boolean') {
121
+ Logger.warn(`${checkTypeLabel}检查 ${fileName} 返回值必须为 true 或 false,当前为 ${typeof checkResult},耗时: ${singleCheckTime}`);
122
+ stats.failedChecks++;
123
+ } else if (checkResult === true) {
124
+ stats.passedChecks++;
125
+ Logger.info(`${checkTypeLabel}检查 ${fileName} 通过,耗时: ${singleCheckTime}`);
126
+ } else {
127
+ Logger.warn(`${checkTypeLabel}检查未通过: ${fileName},耗时: ${singleCheckTime}`);
128
+ stats.failedChecks++;
129
+ }
130
+ } else {
131
+ const singleCheckTime = calcPerfTime(singleCheckStart);
132
+ Logger.warn(`${checkTypeLabel}检查文件 ${fileName} 未找到 default 导出的检查函数,耗时: ${singleCheckTime}`);
133
+ stats.failedChecks++;
134
+ }
135
+ } catch (error: any) {
136
+ const singleCheckTime = calcPerfTime(Bun.nanoseconds());
137
+ Logger.error(`${checkTypeLabel}检查失败 ${fileName},耗时: ${singleCheckTime}`, error);
138
+ stats.failedChecks++;
139
+ }
140
+ }
141
+ }
142
+
143
+ const totalCheckTime = calcPerfTime(checkStartTime);
144
+
145
+ // 输出检查结果统计
146
+ Logger.info(`系统检查完成! 总耗时: ${totalCheckTime},总检查数: ${stats.totalChecks}, 通过: ${stats.passedChecks}, 失败: ${stats.failedChecks}`);
147
+
148
+ if (stats.failedChecks > 0) {
149
+ Logger.error('统检查失败,无法继续启动', {
150
+ totalChecks: stats.totalChecks,
151
+ passedChecks: stats.passedChecks,
152
+ failedChecks: stats.failedChecks
153
+ });
154
+ process.exit(1);
155
+ } else if (stats.totalChecks > 0) {
156
+ Logger.info(`所有系统检查通过!`);
157
+ } else {
158
+ Logger.info(`未执行任何检查`);
159
+ }
160
+ } catch (error: any) {
161
+ Logger.error('执行系统检查时发生错误', error);
162
+ process.exit(1);
163
+ }
164
+ }
165
+ }
@@ -0,0 +1,241 @@
1
+ /**
2
+ * Cluster Manager - 集群管理器
3
+ * 负责多进程启动、自动重启、优雅关闭
4
+ */
5
+
6
+ import { join } from 'pathe';
7
+ import type { Subprocess } from 'bun';
8
+ import { Logger } from '../lib/logger.js';
9
+
10
+ export interface ClusterOptions {
11
+ /** 实例数量(数字或 'max') */
12
+ instances: number | 'max';
13
+ /** 起始端口 */
14
+ startPort: number;
15
+ /** 主机地址 */
16
+ host: string;
17
+ /** 项目根目录 */
18
+ projectRoot: string;
19
+ /** main.ts 文件路径 */
20
+ mainFile: string;
21
+ /** 环境变量 */
22
+ env?: Record<string, string>;
23
+ }
24
+
25
+ interface WorkerInfo {
26
+ id: number;
27
+ port: number;
28
+ process: Subprocess;
29
+ restartCount: number;
30
+ lastRestartTime: number;
31
+ }
32
+
33
+ export class ClusterManager {
34
+ private workers: Map<number, WorkerInfo> = new Map();
35
+ private isShuttingDown = false;
36
+ private readonly MAX_RESTARTS = 10; // 最大重启次数
37
+ private readonly RESTART_DELAY = 1000; // 重启延迟(毫秒)
38
+ private readonly RESTART_WINDOW = 60000; // 重启计数窗口(1分钟)
39
+
40
+ constructor(private options: ClusterOptions) {}
41
+
42
+ /**
43
+ * 启动集群
44
+ */
45
+ async start(): Promise<void> {
46
+ const instances = this.getInstanceCount();
47
+ const { startPort, host } = this.options;
48
+
49
+ Logger.info(`启动集群模式: ${instances} 个实例\n`);
50
+ Logger.info(`端口范围: ${startPort} - ${startPort + instances - 1}`);
51
+ Logger.info(`主机地址: ${host}`);
52
+ Logger.info(`环境: production\n`);
53
+
54
+ // 启动所有 Worker
55
+ for (let i = 0; i < instances; i++) {
56
+ const port = startPort + i;
57
+ this.spawnWorker(i, port);
58
+ }
59
+
60
+ // 监听进程信号
61
+ this.setupSignalHandlers();
62
+
63
+ Logger.info(`集群启动成功!\n`);
64
+ this.printWorkerStatus();
65
+ }
66
+
67
+ /**
68
+ * 获取实例数量
69
+ */
70
+ private getInstanceCount(): number {
71
+ const { instances } = this.options;
72
+
73
+ if (instances === 'max') {
74
+ return navigator.hardwareConcurrency || 4;
75
+ }
76
+
77
+ const count = typeof instances === 'string' ? parseInt(instances) : instances;
78
+
79
+ if (isNaN(count) || count < 1) {
80
+ Logger.warn(`无效的实例数量 "${instances}",使用默认值 4`);
81
+ return 4;
82
+ }
83
+
84
+ return count;
85
+ }
86
+
87
+ /**
88
+ * 启动单个 Worker
89
+ */
90
+ private spawnWorker(id: number, port: number): void {
91
+ const { projectRoot, mainFile, host, env = {} } = this.options;
92
+
93
+ Logger.info(`启动 Worker ${id} (端口 ${port})...`);
94
+
95
+ // 检查环境变量文件
96
+ const envFile = join(projectRoot, '.env.production');
97
+
98
+ const proc = Bun.spawn(['bun', 'run', '--env-file=.env.production', mainFile], {
99
+ cwd: projectRoot,
100
+ stdout: 'inherit',
101
+ stderr: 'inherit',
102
+ stdin: 'inherit',
103
+ env: {
104
+ ...process.env,
105
+ ...env,
106
+ NODE_ENV: 'production',
107
+ APP_PORT: port.toString(),
108
+ APP_HOST: host,
109
+ CLUSTER_MODE: '1',
110
+ CLUSTER_WORKER_ID: id.toString(),
111
+ CLUSTER_INSTANCES: this.getInstanceCount().toString(),
112
+ FORCE_COLOR: '1'
113
+ }
114
+ });
115
+
116
+ // 保存 Worker 信息
117
+ this.workers.set(id, {
118
+ id,
119
+ port,
120
+ process: proc,
121
+ restartCount: 0,
122
+ lastRestartTime: 0
123
+ });
124
+
125
+ // 监听进程退出
126
+ this.watchWorker(id, port);
127
+ }
128
+
129
+ /**
130
+ * 监听 Worker 退出并自动重启
131
+ */
132
+ private async watchWorker(id: number, port: number): Promise<void> {
133
+ const worker = this.workers.get(id);
134
+ if (!worker) return;
135
+
136
+ const exitCode = await worker.process.exited;
137
+
138
+ // 如果正在关闭,不重启
139
+ if (this.isShuttingDown) {
140
+ Logger.info(`Worker ${id} (端口 ${port}) 已退出`);
141
+ return;
142
+ }
143
+
144
+ Logger.warn(`Worker ${id} (端口 ${port}) 异常退出,退出码: ${exitCode}`);
145
+
146
+ // 检查重启次数
147
+ if (!this.canRestart(worker)) {
148
+ Logger.error(`Worker ${id} 重启次数过多,停止重启`);
149
+ return;
150
+ }
151
+
152
+ // 延迟重启
153
+ Logger.info(`${this.RESTART_DELAY / 1000} 秒后重启 Worker ${id}...`);
154
+ await Bun.sleep(this.RESTART_DELAY);
155
+
156
+ // 更新重启计数
157
+ this.updateRestartCount(worker);
158
+
159
+ // 重新启动
160
+ this.spawnWorker(id, port);
161
+ }
162
+
163
+ /**
164
+ * 检查是否可以重启
165
+ */
166
+ private canRestart(worker: WorkerInfo): boolean {
167
+ const now = Date.now();
168
+ const timeSinceLastRestart = now - worker.lastRestartTime;
169
+
170
+ // 如果距离上次重启超过窗口期,重置计数
171
+ if (timeSinceLastRestart > this.RESTART_WINDOW) {
172
+ worker.restartCount = 0;
173
+ }
174
+
175
+ return worker.restartCount < this.MAX_RESTARTS;
176
+ }
177
+
178
+ /**
179
+ * 更新重启计数
180
+ */
181
+ private updateRestartCount(worker: WorkerInfo): void {
182
+ worker.restartCount++;
183
+ worker.lastRestartTime = Date.now();
184
+ }
185
+
186
+ /**
187
+ * 设置信号处理器
188
+ */
189
+ private setupSignalHandlers(): void {
190
+ const signals: NodeJS.Signals[] = ['SIGTERM', 'SIGINT', 'SIGHUP'];
191
+
192
+ signals.forEach((signal) => {
193
+ process.on(signal, () => {
194
+ this.gracefulShutdown(signal);
195
+ });
196
+ });
197
+ }
198
+
199
+ /**
200
+ * 优雅关闭
201
+ */
202
+ private async gracefulShutdown(signal: NodeJS.Signals): Promise<void> {
203
+ if (this.isShuttingDown) return;
204
+ this.isShuttingDown = true;
205
+
206
+ Logger.info(`\n收到 ${signal} 信号,正在关闭集群...`);
207
+
208
+ // 向所有 Worker 发送 SIGTERM
209
+ for (const [id, worker] of this.workers.entries()) {
210
+ Logger.info(`关闭 Worker ${id} (端口 ${worker.port})...`);
211
+ worker.process.kill('SIGTERM');
212
+ }
213
+
214
+ // 等待所有进程退出,最多 5 秒
215
+ const timeout = setTimeout(() => {
216
+ Logger.warn('等待超时,强制关闭所有 Worker');
217
+ for (const worker of this.workers.values()) {
218
+ worker.process.kill('SIGKILL');
219
+ }
220
+ process.exit(1);
221
+ }, 5000);
222
+
223
+ // 等待所有进程退出
224
+ await Promise.all(Array.from(this.workers.values()).map((w) => w.process.exited));
225
+
226
+ clearTimeout(timeout);
227
+ Logger.info('集群已安全关闭');
228
+ process.exit(0);
229
+ }
230
+
231
+ /**
232
+ * 打印 Worker 状态
233
+ */
234
+ private printWorkerStatus(): void {
235
+ Logger.info('Worker 列表:');
236
+ for (const worker of this.workers.values()) {
237
+ Logger.info(` - Worker ${worker.id}: http://${this.options.host}:${worker.port}`);
238
+ }
239
+ Logger.info('');
240
+ }
241
+ }
@@ -0,0 +1,139 @@
1
+ /**
2
+ * 生命周期管理器
3
+ * 统一管理框架的启动流程:检查、加载插件、加载API、启动服务器
4
+ */
5
+
6
+ import { Logger } from '../lib/logger.js';
7
+ import { calcPerfTime } from '../util.js';
8
+ import { scanAddons, addonDirExists } from '../util.js';
9
+ import { Checker } from './checker.js';
10
+ import { Loader } from './loader.js';
11
+ import { Bootstrap } from './bootstrap.js';
12
+
13
+ import type { Server } from 'bun';
14
+ import type { Plugin } from '../types/plugin.js';
15
+ import type { ApiRoute } from '../types/api.js';
16
+ import type { BeflyContext, BeflyOptions } from '../types/befly.js';
17
+
18
+ /**
19
+ * 生命周期管理类
20
+ */
21
+ export class Lifecycle {
22
+ /** API 路由映射表 */
23
+ private apiRoutes: Map<string, ApiRoute> = new Map();
24
+
25
+ /** 插件列表 */
26
+ private pluginLists: Plugin[] = [];
27
+
28
+ /** 应用配置选项 */
29
+ private options: BeflyOptions;
30
+
31
+ constructor(options: BeflyOptions = {}) {
32
+ this.options = options;
33
+ }
34
+
35
+ /**
36
+ * 启动完整的生命周期流程
37
+ * @param appContext - 应用上下文
38
+ * @param callback - 启动完成后的回调函数
39
+ */
40
+ async start(appContext: BeflyContext, callback?: (server: Server) => void): Promise<void> {
41
+ const serverStartTime = Bun.nanoseconds();
42
+ Logger.info('开始启动 Befly 服务器...');
43
+
44
+ // 1. 执行系统检查
45
+ await Checker.run();
46
+
47
+ // 2. 加载插件
48
+ await Loader.loadPlugins({ pluginLists: this.pluginLists, appContext });
49
+
50
+ // 3. 加载所有 API(addon + app)
51
+ await this.loadAllApis();
52
+
53
+ // 4. 缓存数据到 Redis(接口、菜单、角色权限)
54
+ if (appContext.cache && appContext.redis) {
55
+ await appContext.cache.cacheAll();
56
+ } else {
57
+ Logger.warn('⚠️ Redis 或 Cache 插件未启用,跳过数据缓存');
58
+ }
59
+
60
+ // 5. 启动 HTTP 服务器
61
+ const totalStartupTime = calcPerfTime(serverStartTime);
62
+ Logger.info(`服务器启动准备完成,总耗时: ${totalStartupTime}`);
63
+
64
+ await Bootstrap.start(
65
+ {
66
+ apiRoutes: this.apiRoutes,
67
+ pluginLists: this.pluginLists,
68
+ appContext,
69
+ appOptions: this.options
70
+ },
71
+ callback
72
+ );
73
+ }
74
+
75
+ /**
76
+ * 加载所有 API 路由
77
+ * 包括 core APIs、addon APIs 和 app APIs
78
+ */
79
+ private async loadAllApis(): Promise<void> {
80
+ Logger.info('========== 开始加载所有 API 路由 ==========');
81
+ const totalLoadStart = Bun.nanoseconds();
82
+
83
+ // 1. 加载 Core APIs
84
+ Logger.info('========== 开始加载核心 APIs ==========');
85
+ const coreApiLoadStart = Bun.nanoseconds();
86
+ try {
87
+ await Loader.loadApis('core', this.apiRoutes, { where: 'core' });
88
+ const coreApiLoadTime = calcPerfTime(coreApiLoadStart);
89
+ Logger.info(`========== 核心 APIs 加载完成,耗时: ${coreApiLoadTime} ==========`);
90
+ } catch (error: any) {
91
+ const coreApiLoadTime = calcPerfTime(coreApiLoadStart);
92
+ Logger.error(`核心 APIs 加载失败,耗时: ${coreApiLoadTime}`, error);
93
+ throw error;
94
+ }
95
+
96
+ // 2. 加载 addon APIs
97
+ const addons = scanAddons();
98
+ Logger.info(`扫描到 ${addons.length} 个 addon: ${addons.join(', ')}`);
99
+
100
+ for (const addon of addons) {
101
+ const addonLoadStart = Bun.nanoseconds();
102
+ const hasApis = addonDirExists(addon, 'apis');
103
+ Logger.info(`[组件 ${addon}] APIs 目录存在: ${hasApis}`);
104
+
105
+ if (hasApis) {
106
+ Logger.info(`[组件 ${addon}] ===== 开始加载 APIs =====`);
107
+ try {
108
+ await Loader.loadApis(addon, this.apiRoutes, { where: 'addon', addonName: addon });
109
+ const addonLoadTime = calcPerfTime(addonLoadStart);
110
+ Logger.info(`[组件 ${addon}] ===== APIs 加载完成,耗时: ${addonLoadTime} =====`);
111
+ } catch (error: any) {
112
+ const addonLoadTime = calcPerfTime(addonLoadStart);
113
+ Logger.error(`[组件 ${addon}] APIs 加载失败,耗时: ${addonLoadTime}`, error);
114
+ throw error; // 重新抛出错误,让上层处理
115
+ }
116
+ }
117
+ }
118
+
119
+ Logger.info('========== 组件 APIs 全部加载完成 ==========');
120
+
121
+ // 3. 加载用户 APIs
122
+ Logger.info('========== 开始加载用户 APIs ==========');
123
+
124
+ const userApiLoadStart = Bun.nanoseconds();
125
+ try {
126
+ // 加载 app APIs
127
+ await Loader.loadApis('app', this.apiRoutes, { where: 'app' });
128
+ const userApiLoadTime = calcPerfTime(userApiLoadStart);
129
+ Logger.info(`========== 用户 APIs 加载完成,耗时: ${userApiLoadTime} ==========`);
130
+ } catch (error: any) {
131
+ const userApiLoadTime = calcPerfTime(userApiLoadStart);
132
+ Logger.error(`用户 APIs 加载失败,耗时: ${userApiLoadTime}`, error);
133
+ throw error;
134
+ }
135
+
136
+ const totalLoadTime = calcPerfTime(totalLoadStart);
137
+ Logger.info(`========== 所有 API 路由加载完成!总耗时: ${totalLoadTime} ==========`);
138
+ }
139
+ }