befly 3.5.0 → 3.5.2
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/bin/index.ts +17 -130
- package/checks/table.ts +5 -7
- package/commands/index.ts +2 -153
- package/commands/sync.ts +60 -28
- package/commands/syncApi.ts +22 -52
- package/commands/syncDb/index.ts +31 -31
- package/commands/syncDb.ts +5 -5
- package/commands/syncDev.ts +37 -35
- package/commands/syncMenu.ts +25 -76
- package/lib/database.ts +0 -9
- package/lib/logger.ts +7 -5
- package/lifecycle/checker.ts +8 -25
- package/lifecycle/lifecycle.ts +5 -34
- package/lifecycle/loader.ts +10 -100
- package/main.ts +0 -1
- package/package.json +2 -4
- package/commands/build.ts +0 -62
package/commands/syncMenu.ts
CHANGED
|
@@ -34,6 +34,15 @@ interface MenuConfig {
|
|
|
34
34
|
children?: MenuConfig[];
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
+
export interface SyncMenuStats {
|
|
38
|
+
totalMenus: number;
|
|
39
|
+
parentMenus: number;
|
|
40
|
+
childMenus: number;
|
|
41
|
+
created: number;
|
|
42
|
+
updated: number;
|
|
43
|
+
deleted: number;
|
|
44
|
+
}
|
|
45
|
+
|
|
37
46
|
/**
|
|
38
47
|
* 读取菜单配置文件
|
|
39
48
|
* 如果文件不存在或不是数组格式,返回空数组
|
|
@@ -41,7 +50,6 @@ interface MenuConfig {
|
|
|
41
50
|
async function readMenuConfig(filePath: string): Promise<MenuConfig[]> {
|
|
42
51
|
try {
|
|
43
52
|
if (!existsSync(filePath)) {
|
|
44
|
-
Logger.warn(`菜单配置文件不存在: ${filePath},使用空数组`);
|
|
45
53
|
return [];
|
|
46
54
|
}
|
|
47
55
|
|
|
@@ -50,13 +58,11 @@ async function readMenuConfig(filePath: string): Promise<MenuConfig[]> {
|
|
|
50
58
|
|
|
51
59
|
// 验证是否为数组
|
|
52
60
|
if (!Array.isArray(content)) {
|
|
53
|
-
Logger.warn(`菜单配置文件格式错误(非数组): ${filePath},使用空数组`);
|
|
54
61
|
return [];
|
|
55
62
|
}
|
|
56
63
|
|
|
57
64
|
return content;
|
|
58
65
|
} catch (error: any) {
|
|
59
|
-
Logger.warn(`读取菜单配置失败: ${filePath},使用空数组`, error.message);
|
|
60
66
|
return [];
|
|
61
67
|
}
|
|
62
68
|
}
|
|
@@ -176,7 +182,6 @@ async function syncMenus(helper: any, menus: MenuConfig[]): Promise<{ created: n
|
|
|
176
182
|
});
|
|
177
183
|
parentId = existingParent.id;
|
|
178
184
|
stats.updated++;
|
|
179
|
-
Logger.info(` └ 更新父级菜单: ${menu.name} (ID: ${parentId}, Path: ${menu.path})`);
|
|
180
185
|
} else {
|
|
181
186
|
parentId = await helper.insData({
|
|
182
187
|
table: 'core_menu',
|
|
@@ -190,7 +195,6 @@ async function syncMenus(helper: any, menus: MenuConfig[]): Promise<{ created: n
|
|
|
190
195
|
}
|
|
191
196
|
});
|
|
192
197
|
stats.created++;
|
|
193
|
-
Logger.info(` └ 新增父级菜单: ${menu.name} (ID: ${parentId}, Path: ${menu.path})`);
|
|
194
198
|
}
|
|
195
199
|
|
|
196
200
|
// 2. 同步子级菜单(自动追加父级路径前缀)
|
|
@@ -217,9 +221,8 @@ async function syncMenus(helper: any, menus: MenuConfig[]): Promise<{ created: n
|
|
|
217
221
|
}
|
|
218
222
|
});
|
|
219
223
|
stats.updated++;
|
|
220
|
-
Logger.info(` └ 更新子级菜单: ${child.name} (ID: ${existingChild.id}, PID: ${parentId}, Path: ${childFullPath})`);
|
|
221
224
|
} else {
|
|
222
|
-
|
|
225
|
+
await helper.insData({
|
|
223
226
|
table: 'core_menu',
|
|
224
227
|
data: {
|
|
225
228
|
pid: parentId,
|
|
@@ -231,7 +234,6 @@ async function syncMenus(helper: any, menus: MenuConfig[]): Promise<{ created: n
|
|
|
231
234
|
}
|
|
232
235
|
});
|
|
233
236
|
stats.created++;
|
|
234
|
-
Logger.info(` └ 新增子级菜单: ${child.name} (ID: ${childId}, PID: ${parentId}, Path: ${childFullPath})`);
|
|
235
237
|
}
|
|
236
238
|
}
|
|
237
239
|
}
|
|
@@ -248,8 +250,6 @@ async function syncMenus(helper: any, menus: MenuConfig[]): Promise<{ created: n
|
|
|
248
250
|
* 删除配置中不存在的菜单(强制删除)
|
|
249
251
|
*/
|
|
250
252
|
async function deleteObsoleteRecords(helper: any, configPaths: Set<string>): Promise<number> {
|
|
251
|
-
Logger.info(`\n=== 删除配置中不存在的记录 ===`);
|
|
252
|
-
|
|
253
253
|
const allRecords = await helper.getAll({
|
|
254
254
|
table: 'core_menu',
|
|
255
255
|
fields: ['id', 'path', 'name'],
|
|
@@ -264,60 +264,31 @@ async function deleteObsoleteRecords(helper: any, configPaths: Set<string>): Pro
|
|
|
264
264
|
where: { id: record.id }
|
|
265
265
|
});
|
|
266
266
|
deletedCount++;
|
|
267
|
-
Logger.info(` └ 删除记录: ${record.name} (ID: ${record.id}, path: ${record.path})`);
|
|
268
267
|
}
|
|
269
268
|
}
|
|
270
269
|
|
|
271
|
-
if (deletedCount === 0) {
|
|
272
|
-
Logger.info(' ✅ 无需删除的记录');
|
|
273
|
-
}
|
|
274
|
-
|
|
275
270
|
return deletedCount;
|
|
276
271
|
}
|
|
277
272
|
|
|
278
273
|
/**
|
|
279
274
|
* SyncMenu 命令主函数
|
|
280
275
|
*/
|
|
281
|
-
export async function syncMenuCommand(options: SyncMenuOptions = {}) {
|
|
276
|
+
export async function syncMenuCommand(options: SyncMenuOptions = {}): Promise<SyncMenuStats> {
|
|
282
277
|
try {
|
|
283
278
|
if (options.plan) {
|
|
284
279
|
Logger.info('[计划] 同步菜单配置到数据库(plan 模式不执行)');
|
|
285
|
-
|
|
286
|
-
Logger.info('[计划] 2. 合并菜单配置(core 优先覆盖项目)');
|
|
287
|
-
Logger.info('[计划] 3. 子级菜单自动追加父级路径前缀');
|
|
288
|
-
Logger.info('[计划] 4. 根据 path 检查菜单是否存在');
|
|
289
|
-
Logger.info('[计划] 5. 存在则更新,不存在则新增');
|
|
290
|
-
Logger.info('[计划] 6. 强制删除配置中不存在的菜单');
|
|
291
|
-
Logger.info('[计划] 7. 显示菜单结构预览');
|
|
292
|
-
return;
|
|
280
|
+
return { totalMenus: 0, parentMenus: 0, childMenus: 0, created: 0, updated: 0, deleted: 0 };
|
|
293
281
|
}
|
|
294
282
|
|
|
295
|
-
Logger.info('开始同步菜单配置到数据库...\n');
|
|
296
|
-
|
|
297
283
|
// 1. 读取两个配置文件
|
|
298
|
-
Logger.info('=== 步骤 1: 读取菜单配置文件 ===');
|
|
299
284
|
const projectMenuPath = join(projectDir, 'menu.json');
|
|
300
285
|
const coreMenuPath = join(coreDir, 'menu.json');
|
|
301
286
|
|
|
302
|
-
Logger.info(` 项目路径: ${projectMenuPath}`);
|
|
303
|
-
Logger.info(` core 路径: ${coreMenuPath}`);
|
|
304
|
-
|
|
305
287
|
const projectMenus = await readMenuConfig(projectMenuPath);
|
|
306
288
|
const coreMenus = await readMenuConfig(coreMenuPath);
|
|
307
289
|
|
|
308
|
-
Logger.info(`✅ 项目配置: ${projectMenus.length} 个父级菜单`);
|
|
309
|
-
Logger.info(`✅ core 配置: ${coreMenus.length} 个父级菜单`);
|
|
310
|
-
|
|
311
290
|
// 2. 合并菜单配置
|
|
312
|
-
Logger.info('\n=== 步骤 2: 合并菜单配置(core 优先覆盖项目) ===');
|
|
313
291
|
const mergedMenus = mergeMenuConfigs(projectMenus, coreMenus);
|
|
314
|
-
Logger.info(`✅ 合并后共有 ${mergedMenus.length} 个父级菜单`);
|
|
315
|
-
|
|
316
|
-
// 打印合并后的菜单结构
|
|
317
|
-
for (const menu of mergedMenus) {
|
|
318
|
-
const childCount = menu.children?.length || 0;
|
|
319
|
-
Logger.info(` └ ${menu.name} (${menu.path}) - ${childCount} 个子菜单`);
|
|
320
|
-
}
|
|
321
292
|
|
|
322
293
|
// 连接数据库(SQL + Redis)
|
|
323
294
|
await Database.connect();
|
|
@@ -325,7 +296,6 @@ export async function syncMenuCommand(options: SyncMenuOptions = {}) {
|
|
|
325
296
|
const helper = Database.getDbHelper();
|
|
326
297
|
|
|
327
298
|
// 3. 检查表是否存在
|
|
328
|
-
Logger.info('\n=== 步骤 3: 检查数据表 ===');
|
|
329
299
|
const exists = await helper.tableExists('core_menu');
|
|
330
300
|
|
|
331
301
|
if (!exists) {
|
|
@@ -333,47 +303,23 @@ export async function syncMenuCommand(options: SyncMenuOptions = {}) {
|
|
|
333
303
|
process.exit(1);
|
|
334
304
|
}
|
|
335
305
|
|
|
336
|
-
Logger.info(`✅ 表 core_menu 存在`);
|
|
337
|
-
|
|
338
306
|
// 4. 收集配置文件中所有菜单的 path
|
|
339
|
-
Logger.info('\n=== 步骤 4: 收集配置菜单路径 ===');
|
|
340
307
|
const configPaths = collectPaths(mergedMenus);
|
|
341
|
-
Logger.info(`✅ 配置文件中共有 ${configPaths.size} 个菜单路径`);
|
|
342
308
|
|
|
343
309
|
// 5. 同步菜单
|
|
344
|
-
Logger.info('\n=== 步骤 5: 同步菜单数据(新增/更新) ===');
|
|
345
310
|
const stats = await syncMenus(helper, mergedMenus);
|
|
346
311
|
|
|
347
312
|
// 6. 删除文件中不存在的菜单(强制删除)
|
|
348
313
|
const deletedCount = await deleteObsoleteRecords(helper, configPaths);
|
|
349
314
|
|
|
350
|
-
// 7.
|
|
351
|
-
Logger.info('\n=== 步骤 7: 菜单结构预览 ===');
|
|
315
|
+
// 7. 获取最终菜单数据
|
|
352
316
|
const allMenus = await helper.getAll({
|
|
353
317
|
table: 'core_menu',
|
|
354
318
|
fields: ['id', 'pid', 'name', 'path', 'type'],
|
|
355
319
|
orderBy: ['pid#ASC', 'sort#ASC', 'id#ASC']
|
|
356
320
|
});
|
|
357
321
|
|
|
358
|
-
|
|
359
|
-
for (const parent of parentMenus) {
|
|
360
|
-
const children = allMenus.filter((m: any) => m.pid === parent.id);
|
|
361
|
-
Logger.info(` └ ${parent.name} (${parent.path})`);
|
|
362
|
-
for (const child of children) {
|
|
363
|
-
Logger.info(` └ ${child.name} (${child.path})`);
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
// 8. 输出统计信息
|
|
368
|
-
Logger.info(`\n=== 菜单同步完成 ===`);
|
|
369
|
-
Logger.info(`新增菜单: ${stats.created} 个`);
|
|
370
|
-
Logger.info(`更新菜单: ${stats.updated} 个`);
|
|
371
|
-
Logger.info(`删除菜单: ${deletedCount} 个`);
|
|
372
|
-
Logger.info(`当前父级菜单: ${allMenus.filter((m: any) => m.pid === 0).length} 个`);
|
|
373
|
-
Logger.info(`当前子级菜单: ${allMenus.filter((m: any) => m.pid !== 0).length} 个`);
|
|
374
|
-
|
|
375
|
-
// 9. 缓存菜单数据到 Redis
|
|
376
|
-
Logger.info('\n=== 步骤 8: 缓存菜单数据到 Redis ===');
|
|
322
|
+
// 8. 缓存菜单数据到 Redis
|
|
377
323
|
try {
|
|
378
324
|
const menus = await helper.getAll({
|
|
379
325
|
table: 'core_menu',
|
|
@@ -381,16 +327,19 @@ export async function syncMenuCommand(options: SyncMenuOptions = {}) {
|
|
|
381
327
|
orderBy: ['sort#ASC', 'id#ASC']
|
|
382
328
|
});
|
|
383
329
|
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
if (result === null) {
|
|
387
|
-
Logger.warn('⚠️ 菜单缓存失败');
|
|
388
|
-
} else {
|
|
389
|
-
Logger.info(`✅ 已缓存 ${menus.length} 个菜单到 Redis (Key: menus:all)`);
|
|
390
|
-
}
|
|
330
|
+
await RedisHelper.setObject('menus:all', menus);
|
|
391
331
|
} catch (error: any) {
|
|
392
|
-
|
|
332
|
+
// 忽略缓存错误
|
|
393
333
|
}
|
|
334
|
+
|
|
335
|
+
return {
|
|
336
|
+
totalMenus: allMenus.length,
|
|
337
|
+
parentMenus: allMenus.filter((m: any) => m.pid === 0).length,
|
|
338
|
+
childMenus: allMenus.filter((m: any) => m.pid !== 0).length,
|
|
339
|
+
created: stats.created,
|
|
340
|
+
updated: stats.updated,
|
|
341
|
+
deleted: deletedCount
|
|
342
|
+
};
|
|
394
343
|
} catch (error: any) {
|
|
395
344
|
Logger.error('菜单同步失败:', error);
|
|
396
345
|
process.exit(1);
|
package/lib/database.ts
CHANGED
|
@@ -87,8 +87,6 @@ export class Database {
|
|
|
87
87
|
|
|
88
88
|
const version = await Promise.race([healthCheckPromise, timeoutPromise]);
|
|
89
89
|
|
|
90
|
-
Logger.info(`数据库连接成功,version: ${version}`);
|
|
91
|
-
|
|
92
90
|
this.sqlClient = sql;
|
|
93
91
|
return sql;
|
|
94
92
|
} catch (error: any) {
|
|
@@ -110,7 +108,6 @@ export class Database {
|
|
|
110
108
|
if (this.sqlClient) {
|
|
111
109
|
try {
|
|
112
110
|
await this.sqlClient.close();
|
|
113
|
-
Logger.info('SQL 连接已关闭');
|
|
114
111
|
} catch (error: any) {
|
|
115
112
|
Logger.warn('关闭 SQL 连接时出错:', error.message);
|
|
116
113
|
}
|
|
@@ -186,7 +183,6 @@ export class Database {
|
|
|
186
183
|
});
|
|
187
184
|
|
|
188
185
|
await redis.ping();
|
|
189
|
-
Logger.info('Redis 连接成功');
|
|
190
186
|
|
|
191
187
|
this.redisClient = redis;
|
|
192
188
|
return redis;
|
|
@@ -203,7 +199,6 @@ export class Database {
|
|
|
203
199
|
if (this.redisClient) {
|
|
204
200
|
try {
|
|
205
201
|
this.redisClient.close();
|
|
206
|
-
Logger.info('Redis 连接已关闭');
|
|
207
202
|
} catch (error: any) {
|
|
208
203
|
Logger.warn('关闭 Redis 连接时出错:', error);
|
|
209
204
|
}
|
|
@@ -233,16 +228,12 @@ export class Database {
|
|
|
233
228
|
static async connect(options?: { sql?: SqlClientOptions; redis?: boolean }): Promise<void> {
|
|
234
229
|
try {
|
|
235
230
|
if (options?.sql !== false) {
|
|
236
|
-
Logger.info('正在初始化 SQL 连接...');
|
|
237
231
|
await this.connectSql(options?.sql);
|
|
238
232
|
}
|
|
239
233
|
|
|
240
234
|
if (options?.redis !== false) {
|
|
241
|
-
Logger.info('正在初始化 Redis 连接...');
|
|
242
235
|
await this.connectRedis();
|
|
243
236
|
}
|
|
244
|
-
|
|
245
|
-
Logger.info('数据库连接初始化完成');
|
|
246
237
|
} catch (error: any) {
|
|
247
238
|
Logger.error('数据库初始化失败', error);
|
|
248
239
|
await this.disconnect();
|
package/lib/logger.ts
CHANGED
|
@@ -217,10 +217,12 @@ export class Logger {
|
|
|
217
217
|
* 用于命令开始时提示用户当前环境
|
|
218
218
|
*/
|
|
219
219
|
static printEnv(): void {
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
console.log(
|
|
223
|
-
console.log(
|
|
224
|
-
console.log(
|
|
220
|
+
console.log('========================================');
|
|
221
|
+
console.log('开始执行完整同步流程');
|
|
222
|
+
console.log(`当前环境: ${process.env.NODE_ENV || 'development'}`);
|
|
223
|
+
console.log(`项目名称: ${Env.APP_NAME}`);
|
|
224
|
+
console.log(`数据库地址: ${Env.DB_HOST}`);
|
|
225
|
+
console.log(`数据库名称: ${Env.DB_NAME}`);
|
|
226
|
+
console.log('========================================\n');
|
|
225
227
|
}
|
|
226
228
|
}
|
package/lifecycle/checker.ts
CHANGED
|
@@ -46,20 +46,15 @@ export class Checker {
|
|
|
46
46
|
const conflictCheckTime = calcPerfTime(conflictCheckStart);
|
|
47
47
|
|
|
48
48
|
if (typeof conflictResult !== 'boolean') {
|
|
49
|
-
Logger.warn(`核心检查 conflict.ts 返回值必须为 true 或 false,当前为 ${typeof conflictResult}
|
|
49
|
+
Logger.warn(`核心检查 conflict.ts 返回值必须为 true 或 false,当前为 ${typeof conflictResult}`);
|
|
50
50
|
stats.failedChecks++;
|
|
51
51
|
} else if (conflictResult === true) {
|
|
52
52
|
stats.passedChecks++;
|
|
53
|
-
Logger.info(`核心检查 conflict.ts 通过,耗时: ${conflictCheckTime}`);
|
|
54
53
|
} else {
|
|
55
|
-
Logger.warn(`核心检查未通过: conflict.ts
|
|
54
|
+
Logger.warn(`核心检查未通过: conflict.ts`);
|
|
56
55
|
stats.failedChecks++;
|
|
57
56
|
// 资源冲突检测失败,立即终止
|
|
58
|
-
Logger.warn('资源冲突检测失败,无法继续启动'
|
|
59
|
-
totalChecks: stats.totalChecks,
|
|
60
|
-
passedChecks: stats.passedChecks,
|
|
61
|
-
failedChecks: stats.failedChecks
|
|
62
|
-
});
|
|
57
|
+
Logger.warn('资源冲突检测失败,无法继续启动');
|
|
63
58
|
process.exit(1);
|
|
64
59
|
}
|
|
65
60
|
}
|
|
@@ -88,8 +83,6 @@ export class Checker {
|
|
|
88
83
|
const { path: checkDir, type } = checkConfig;
|
|
89
84
|
const addonName = 'addonName' in checkConfig ? checkConfig.addonName : undefined;
|
|
90
85
|
const checkTypeLabel = type === 'core' ? '核心' : type === 'project' ? '项目' : `组件${addonName}`;
|
|
91
|
-
Logger.info(`开始执行${checkTypeLabel}检查,目录: ${checkDir}`);
|
|
92
|
-
|
|
93
86
|
for await (const file of glob.scan({
|
|
94
87
|
cwd: checkDir,
|
|
95
88
|
onlyFiles: true,
|
|
@@ -118,18 +111,16 @@ export class Checker {
|
|
|
118
111
|
|
|
119
112
|
// 检查返回值是否为 boolean
|
|
120
113
|
if (typeof checkResult !== 'boolean') {
|
|
121
|
-
Logger.warn(`${checkTypeLabel}检查 ${fileName} 返回值必须为 true 或 false,当前为 ${typeof checkResult}
|
|
114
|
+
Logger.warn(`${checkTypeLabel}检查 ${fileName} 返回值必须为 true 或 false,当前为 ${typeof checkResult}`);
|
|
122
115
|
stats.failedChecks++;
|
|
123
116
|
} else if (checkResult === true) {
|
|
124
117
|
stats.passedChecks++;
|
|
125
|
-
Logger.info(`${checkTypeLabel}检查 ${fileName} 通过,耗时: ${singleCheckTime}`);
|
|
126
118
|
} else {
|
|
127
|
-
Logger.warn(`${checkTypeLabel}检查未通过: ${fileName}
|
|
119
|
+
Logger.warn(`${checkTypeLabel}检查未通过: ${fileName}`);
|
|
128
120
|
stats.failedChecks++;
|
|
129
121
|
}
|
|
130
122
|
} else {
|
|
131
|
-
|
|
132
|
-
Logger.warn(`${checkTypeLabel}检查文件 ${fileName} 未找到 default 导出的检查函数,耗时: ${singleCheckTime}`);
|
|
123
|
+
Logger.warn(`${checkTypeLabel}检查文件 ${fileName} 未找到 default 导出的检查函数`);
|
|
133
124
|
stats.failedChecks++;
|
|
134
125
|
}
|
|
135
126
|
} catch (error: any) {
|
|
@@ -143,19 +134,11 @@ export class Checker {
|
|
|
143
134
|
const totalCheckTime = calcPerfTime(checkStartTime);
|
|
144
135
|
|
|
145
136
|
// 输出检查结果统计
|
|
146
|
-
Logger.info(`系统检查完成! 总耗时: ${totalCheckTime},总检查数: ${stats.totalChecks}, 通过: ${stats.passedChecks}, 失败: ${stats.failedChecks}`);
|
|
147
|
-
|
|
148
137
|
if (stats.failedChecks > 0) {
|
|
149
|
-
Logger.error(
|
|
150
|
-
totalChecks: stats.totalChecks,
|
|
151
|
-
passedChecks: stats.passedChecks,
|
|
152
|
-
failedChecks: stats.failedChecks
|
|
153
|
-
});
|
|
138
|
+
Logger.error(`✗ 系统检查失败: ${stats.failedChecks}/${stats.totalChecks},耗时: ${totalCheckTime}`);
|
|
154
139
|
process.exit(1);
|
|
155
140
|
} else if (stats.totalChecks > 0) {
|
|
156
|
-
Logger.info(
|
|
157
|
-
} else {
|
|
158
|
-
Logger.info(`未执行任何检查`);
|
|
141
|
+
Logger.info(`✓ 系统检查通过: ${stats.passedChecks}/${stats.totalChecks},耗时: ${totalCheckTime}`);
|
|
159
142
|
}
|
|
160
143
|
} catch (error: any) {
|
|
161
144
|
Logger.error('执行系统检查时发生错误', error);
|
package/lifecycle/lifecycle.ts
CHANGED
|
@@ -39,7 +39,6 @@ export class Lifecycle {
|
|
|
39
39
|
*/
|
|
40
40
|
async start(appContext: BeflyContext, callback?: (server: Server) => void): Promise<Server> {
|
|
41
41
|
const serverStartTime = Bun.nanoseconds();
|
|
42
|
-
Logger.info('开始启动 Befly 服务器...');
|
|
43
42
|
|
|
44
43
|
// 1. 执行系统检查
|
|
45
44
|
await Checker.run();
|
|
@@ -52,7 +51,7 @@ export class Lifecycle {
|
|
|
52
51
|
|
|
53
52
|
// 4. 启动 HTTP 服务器
|
|
54
53
|
const totalStartupTime = calcPerfTime(serverStartTime);
|
|
55
|
-
Logger.info(
|
|
54
|
+
Logger.info(`✓ 服务器启动准备完成,总耗时: ${totalStartupTime}`);
|
|
56
55
|
|
|
57
56
|
return await Bootstrap.start(
|
|
58
57
|
{
|
|
@@ -70,63 +69,35 @@ export class Lifecycle {
|
|
|
70
69
|
* 包括 core APIs、addon APIs 和 app APIs
|
|
71
70
|
*/
|
|
72
71
|
private async loadAllApis(): Promise<void> {
|
|
73
|
-
Logger.info('========== 开始加载所有 API 路由 ==========');
|
|
74
|
-
const totalLoadStart = Bun.nanoseconds();
|
|
75
|
-
|
|
76
72
|
// 1. 加载 Core APIs
|
|
77
|
-
Logger.info('========== 开始加载核心 APIs ==========');
|
|
78
|
-
const coreApiLoadStart = Bun.nanoseconds();
|
|
79
73
|
try {
|
|
80
74
|
await Loader.loadApis('core', this.apiRoutes, { where: 'core' });
|
|
81
|
-
const coreApiLoadTime = calcPerfTime(coreApiLoadStart);
|
|
82
|
-
Logger.info(`========== 核心 APIs 加载完成,耗时: ${coreApiLoadTime} ==========`);
|
|
83
75
|
} catch (error: any) {
|
|
84
|
-
|
|
85
|
-
Logger.error(`核心 APIs 加载失败,耗时: ${coreApiLoadTime}`, error);
|
|
76
|
+
Logger.error(`核心 APIs 加载失败`, error);
|
|
86
77
|
throw error;
|
|
87
78
|
}
|
|
88
79
|
|
|
89
80
|
// 2. 加载 addon APIs
|
|
90
81
|
const addons = scanAddons();
|
|
91
|
-
Logger.info(`扫描到 ${addons.length} 个 addon: ${addons.join(', ')}`);
|
|
92
82
|
|
|
93
83
|
for (const addon of addons) {
|
|
94
|
-
const addonLoadStart = Bun.nanoseconds();
|
|
95
84
|
const hasApis = addonDirExists(addon, 'apis');
|
|
96
|
-
Logger.info(`[组件 ${addon}] APIs 目录存在: ${hasApis}`);
|
|
97
|
-
|
|
98
85
|
if (hasApis) {
|
|
99
|
-
Logger.info(`[组件 ${addon}] ===== 开始加载 APIs =====`);
|
|
100
86
|
try {
|
|
101
87
|
await Loader.loadApis(addon, this.apiRoutes, { where: 'addon', addonName: addon });
|
|
102
|
-
const addonLoadTime = calcPerfTime(addonLoadStart);
|
|
103
|
-
Logger.info(`[组件 ${addon}] ===== APIs 加载完成,耗时: ${addonLoadTime} =====`);
|
|
104
88
|
} catch (error: any) {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
throw error; // 重新抛出错误,让上层处理
|
|
89
|
+
Logger.error(`[组件 ${addon}] APIs 加载失败`, error);
|
|
90
|
+
throw error;
|
|
108
91
|
}
|
|
109
92
|
}
|
|
110
93
|
}
|
|
111
94
|
|
|
112
|
-
Logger.info('========== 组件 APIs 全部加载完成 ==========');
|
|
113
|
-
|
|
114
95
|
// 3. 加载用户 APIs
|
|
115
|
-
Logger.info('========== 开始加载用户 APIs ==========');
|
|
116
|
-
|
|
117
|
-
const userApiLoadStart = Bun.nanoseconds();
|
|
118
96
|
try {
|
|
119
|
-
// 加载 app APIs
|
|
120
97
|
await Loader.loadApis('app', this.apiRoutes, { where: 'app' });
|
|
121
|
-
const userApiLoadTime = calcPerfTime(userApiLoadStart);
|
|
122
|
-
Logger.info(`========== 用户 APIs 加载完成,耗时: ${userApiLoadTime} ==========`);
|
|
123
98
|
} catch (error: any) {
|
|
124
|
-
|
|
125
|
-
Logger.error(`用户 APIs 加载失败,耗时: ${userApiLoadTime}`, error);
|
|
99
|
+
Logger.error(`用户 APIs 加载失败`, error);
|
|
126
100
|
throw error;
|
|
127
101
|
}
|
|
128
|
-
|
|
129
|
-
const totalLoadTime = calcPerfTime(totalLoadStart);
|
|
130
|
-
Logger.info(`========== 所有 API 路由加载完成!总耗时: ${totalLoadTime} ==========`);
|
|
131
102
|
}
|
|
132
103
|
}
|