befly 3.5.0 → 3.5.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.
- package/commands/index.ts +2 -57
- package/commands/syncApi.ts +14 -14
- package/commands/syncDev.ts +4 -4
- package/commands/syncMenu.ts +17 -17
- package/main.ts +0 -1
- package/package.json +2 -2
package/commands/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Build、Start、Sync、
|
|
2
|
+
* Build、Start、Sync、SyncApi、SyncMenu、SyncDev 命令实现
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { join } from 'pathe';
|
|
@@ -163,62 +163,7 @@ export async function syncCommand(options: SyncOptions) {
|
|
|
163
163
|
}
|
|
164
164
|
}
|
|
165
165
|
|
|
166
|
-
// ==========
|
|
167
|
-
export const addonCommand = {
|
|
168
|
-
async install(name: string, options: { source?: string }) {
|
|
169
|
-
Logger.info(`正在安装插件: ${name}`);
|
|
170
|
-
|
|
171
|
-
try {
|
|
172
|
-
// TODO: 实现插件安装逻辑
|
|
173
|
-
// 1. 从 source 或默认源下载插件
|
|
174
|
-
// 2. 解压到 addons 目录
|
|
175
|
-
// 3. 安装插件依赖
|
|
176
|
-
// 4. 执行插件安装脚本
|
|
177
|
-
|
|
178
|
-
Logger.success(`插件 ${name} 安装成功`);
|
|
179
|
-
} catch (error) {
|
|
180
|
-
Logger.error(`插件 ${name} 安装失败`);
|
|
181
|
-
throw error;
|
|
182
|
-
}
|
|
183
|
-
},
|
|
184
|
-
|
|
185
|
-
async uninstall(name: string, options: { keepData: boolean }) {
|
|
186
|
-
Logger.info(`正在卸载插件: ${name}`);
|
|
187
|
-
|
|
188
|
-
try {
|
|
189
|
-
// TODO: 实现插件卸载逻辑
|
|
190
|
-
// 1. 执行插件卸载脚本
|
|
191
|
-
// 2. 删除插件文件
|
|
192
|
-
// 3. 可选:删除插件数据
|
|
193
|
-
|
|
194
|
-
Logger.success(`插件 ${name} 卸载成功`);
|
|
195
|
-
} catch (error) {
|
|
196
|
-
Logger.error(`插件 ${name} 卸载失败`);
|
|
197
|
-
throw error;
|
|
198
|
-
}
|
|
199
|
-
},
|
|
200
|
-
|
|
201
|
-
async list() {
|
|
202
|
-
try {
|
|
203
|
-
const projectRoot = getProjectRoot();
|
|
204
|
-
const addonsDir = join(projectRoot, 'addons');
|
|
205
|
-
|
|
206
|
-
if (!existsSync(addonsDir)) {
|
|
207
|
-
Logger.info('未找到 addons 目录');
|
|
208
|
-
return;
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
// TODO: 读取已安装的插件列表
|
|
212
|
-
Logger.info('已安装的插件:\n');
|
|
213
|
-
Logger.info('(功能开发中)');
|
|
214
|
-
} catch (error) {
|
|
215
|
-
Logger.error('获取插件列表失败:');
|
|
216
|
-
console.error(error);
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
};
|
|
220
|
-
|
|
221
|
-
// ========== 导出新增的同步命令 ==========
|
|
166
|
+
// ========== 导出同步命令 ==========
|
|
222
167
|
export { syncApiCommand } from './syncApi.js';
|
|
223
168
|
export { syncMenuCommand } from './syncMenu.js';
|
|
224
169
|
export { syncDevCommand } from './syncDev.js';
|
package/commands/syncApi.ts
CHANGED
|
@@ -111,17 +111,17 @@ async function scanAllApis(projectRoot: string): Promise<ApiInfo[]> {
|
|
|
111
111
|
const apis: ApiInfo[] = [];
|
|
112
112
|
|
|
113
113
|
// 1. 扫描 Core 框架 API
|
|
114
|
-
Logger.
|
|
114
|
+
Logger.debug('=== 扫描 Core 框架 API (core/apis) ===');
|
|
115
115
|
const coreApisDir = join(dirname(projectRoot), 'core', 'apis');
|
|
116
116
|
try {
|
|
117
117
|
const coreApiFiles = scanTsFiles(coreApisDir);
|
|
118
|
-
Logger.
|
|
118
|
+
Logger.debug(` 找到 ${coreApiFiles.length} 个核心 API 文件`);
|
|
119
119
|
|
|
120
120
|
for (const filePath of coreApiFiles) {
|
|
121
121
|
const apiInfo = await extractApiInfo(filePath, coreApisDir, 'core', '', '核心接口');
|
|
122
122
|
if (apiInfo) {
|
|
123
123
|
apis.push(apiInfo);
|
|
124
|
-
Logger.
|
|
124
|
+
Logger.debug(` └ ${apiInfo.path} - ${apiInfo.name}`);
|
|
125
125
|
}
|
|
126
126
|
}
|
|
127
127
|
|
|
@@ -129,13 +129,13 @@ async function scanAllApis(projectRoot: string): Promise<ApiInfo[]> {
|
|
|
129
129
|
Logger.info('\n=== 扫描项目 API (apis) ===');
|
|
130
130
|
const projectApisDir = join(projectRoot, 'apis');
|
|
131
131
|
const projectApiFiles = scanTsFiles(projectApisDir);
|
|
132
|
-
Logger.
|
|
132
|
+
Logger.debug(` 找到 ${projectApiFiles.length} 个项目 API 文件`);
|
|
133
133
|
|
|
134
134
|
for (const filePath of projectApiFiles) {
|
|
135
135
|
const apiInfo = await extractApiInfo(filePath, projectApisDir, 'app', '', '项目接口');
|
|
136
136
|
if (apiInfo) {
|
|
137
137
|
apis.push(apiInfo);
|
|
138
|
-
Logger.
|
|
138
|
+
Logger.debug(` └ ${apiInfo.path} - ${apiInfo.name}`);
|
|
139
139
|
}
|
|
140
140
|
}
|
|
141
141
|
|
|
@@ -148,7 +148,7 @@ async function scanAllApis(projectRoot: string): Promise<ApiInfo[]> {
|
|
|
148
148
|
|
|
149
149
|
// 检查 apis 子目录是否存在
|
|
150
150
|
if (!addonDirExists(addonName, 'apis')) {
|
|
151
|
-
Logger.
|
|
151
|
+
Logger.debug(` [${addonName}] 无 apis 目录,跳过`);
|
|
152
152
|
continue;
|
|
153
153
|
}
|
|
154
154
|
|
|
@@ -166,13 +166,13 @@ async function scanAllApis(projectRoot: string): Promise<ApiInfo[]> {
|
|
|
166
166
|
}
|
|
167
167
|
|
|
168
168
|
const addonApiFiles = scanTsFiles(addonApisDir);
|
|
169
|
-
Logger.
|
|
169
|
+
Logger.debug(` [${addonName}] 找到 ${addonApiFiles.length} 个 API 文件`);
|
|
170
170
|
|
|
171
171
|
for (const filePath of addonApiFiles) {
|
|
172
172
|
const apiInfo = await extractApiInfo(filePath, addonApisDir, 'addon', addonName, addonTitle);
|
|
173
173
|
if (apiInfo) {
|
|
174
174
|
apis.push(apiInfo);
|
|
175
|
-
Logger.
|
|
175
|
+
Logger.debug(` └ ${apiInfo.path} - ${apiInfo.name}`);
|
|
176
176
|
}
|
|
177
177
|
}
|
|
178
178
|
}
|
|
@@ -209,7 +209,7 @@ async function syncApis(helper: any, apis: ApiInfo[]): Promise<{ created: number
|
|
|
209
209
|
}
|
|
210
210
|
});
|
|
211
211
|
stats.updated++;
|
|
212
|
-
Logger.
|
|
212
|
+
Logger.debug(` └ 更新接口: ${api.name} (ID: ${existing.id}, Path: ${api.path})`);
|
|
213
213
|
} else {
|
|
214
214
|
const id = await helper.insData({
|
|
215
215
|
table: 'core_api',
|
|
@@ -223,7 +223,7 @@ async function syncApis(helper: any, apis: ApiInfo[]): Promise<{ created: number
|
|
|
223
223
|
}
|
|
224
224
|
});
|
|
225
225
|
stats.created++;
|
|
226
|
-
Logger.
|
|
226
|
+
Logger.debug(` └ 新增接口: ${api.name} (ID: ${id}, Path: ${api.path})`);
|
|
227
227
|
}
|
|
228
228
|
} catch (error: any) {
|
|
229
229
|
Logger.error(`同步接口 "${api.name}" 失败:`, error);
|
|
@@ -253,7 +253,7 @@ async function deleteObsoleteRecords(helper: any, apiPaths: Set<string>): Promis
|
|
|
253
253
|
where: { id: record.id }
|
|
254
254
|
});
|
|
255
255
|
deletedCount++;
|
|
256
|
-
Logger.
|
|
256
|
+
Logger.debug(` └ 删除记录: ${record.name} (ID: ${record.id}, path: ${record.path})`);
|
|
257
257
|
}
|
|
258
258
|
}
|
|
259
259
|
|
|
@@ -289,7 +289,7 @@ export async function syncApiCommand(options: SyncApiOptions = {}) {
|
|
|
289
289
|
const helper = Database.getDbHelper();
|
|
290
290
|
|
|
291
291
|
// 1. 检查表是否存在
|
|
292
|
-
Logger.
|
|
292
|
+
Logger.debug('=== 检查数据表 ===');
|
|
293
293
|
const exists = await helper.tableExists('core_api');
|
|
294
294
|
|
|
295
295
|
if (!exists) {
|
|
@@ -300,13 +300,13 @@ export async function syncApiCommand(options: SyncApiOptions = {}) {
|
|
|
300
300
|
Logger.info(`✅ 表 core_api 存在\n`);
|
|
301
301
|
|
|
302
302
|
// 2. 扫描所有 API 文件
|
|
303
|
-
Logger.
|
|
303
|
+
Logger.debug('=== 步骤 2: 扫描 API 文件 ===');
|
|
304
304
|
const apis = await scanAllApis(projectRoot);
|
|
305
305
|
const apiPaths = new Set(apis.map((api) => api.path));
|
|
306
306
|
Logger.info(`\n✅ 共扫描到 ${apis.length} 个 API 接口\n`);
|
|
307
307
|
|
|
308
308
|
// 3. 同步 API 数据
|
|
309
|
-
Logger.
|
|
309
|
+
Logger.debug('=== 步骤 3: 同步 API 数据(新增/更新) ===');
|
|
310
310
|
const stats = await syncApis(helper, apis);
|
|
311
311
|
|
|
312
312
|
// 4. 删除文件中不存在的接口
|
package/commands/syncDev.ts
CHANGED
|
@@ -71,7 +71,7 @@ export async function syncDevCommand(options: SyncDevOptions = {}) {
|
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
const menuIds = allMenus.length > 0 ? allMenus.map((m: any) => m.id).join(',') : '';
|
|
74
|
-
Logger.
|
|
74
|
+
Logger.debug(`查询到 ${allMenus.length} 个菜单,ID 列表: ${menuIds || '(空)'}`);
|
|
75
75
|
|
|
76
76
|
// 查询所有接口 ID
|
|
77
77
|
const existApi = await helper.tableExists('core_api');
|
|
@@ -84,7 +84,7 @@ export async function syncDevCommand(options: SyncDevOptions = {}) {
|
|
|
84
84
|
|
|
85
85
|
if (allApis && Array.isArray(allApis) && allApis.length > 0) {
|
|
86
86
|
apiIds = allApis.map((a: any) => a.id).join(',');
|
|
87
|
-
Logger.
|
|
87
|
+
Logger.debug(`查询到 ${allApis.length} 个接口,ID 列表: ${apiIds}`);
|
|
88
88
|
} else {
|
|
89
89
|
Logger.info('未查询到接口数据');
|
|
90
90
|
}
|
|
@@ -212,8 +212,8 @@ export async function syncDevCommand(options: SyncDevOptions = {}) {
|
|
|
212
212
|
// 先删除旧数据
|
|
213
213
|
await redis.del(redisKey);
|
|
214
214
|
|
|
215
|
-
// 批量添加到 Set
|
|
216
|
-
const result = await redis.sadd(redisKey, roleApiPaths);
|
|
215
|
+
// 批量添加到 Set(使用扩展运算符展开数组)
|
|
216
|
+
const result = await redis.sadd(redisKey, ...roleApiPaths);
|
|
217
217
|
|
|
218
218
|
if (result > 0) {
|
|
219
219
|
cachedRoles++;
|
package/commands/syncMenu.ts
CHANGED
|
@@ -176,7 +176,7 @@ async function syncMenus(helper: any, menus: MenuConfig[]): Promise<{ created: n
|
|
|
176
176
|
});
|
|
177
177
|
parentId = existingParent.id;
|
|
178
178
|
stats.updated++;
|
|
179
|
-
Logger.
|
|
179
|
+
Logger.debug(` └ 更新父级菜单: ${menu.name} (ID: ${parentId}, Path: ${menu.path})`);
|
|
180
180
|
} else {
|
|
181
181
|
parentId = await helper.insData({
|
|
182
182
|
table: 'core_menu',
|
|
@@ -190,7 +190,7 @@ async function syncMenus(helper: any, menus: MenuConfig[]): Promise<{ created: n
|
|
|
190
190
|
}
|
|
191
191
|
});
|
|
192
192
|
stats.created++;
|
|
193
|
-
Logger.
|
|
193
|
+
Logger.debug(` └ 新增父级菜单: ${menu.name} (ID: ${parentId}, Path: ${menu.path})`);
|
|
194
194
|
}
|
|
195
195
|
|
|
196
196
|
// 2. 同步子级菜单(自动追加父级路径前缀)
|
|
@@ -217,7 +217,7 @@ async function syncMenus(helper: any, menus: MenuConfig[]): Promise<{ created: n
|
|
|
217
217
|
}
|
|
218
218
|
});
|
|
219
219
|
stats.updated++;
|
|
220
|
-
Logger.
|
|
220
|
+
Logger.debug(` └ 更新子级菜单: ${child.name} (ID: ${existingChild.id}, PID: ${parentId}, Path: ${childFullPath})`);
|
|
221
221
|
} else {
|
|
222
222
|
const childId = await helper.insData({
|
|
223
223
|
table: 'core_menu',
|
|
@@ -231,7 +231,7 @@ async function syncMenus(helper: any, menus: MenuConfig[]): Promise<{ created: n
|
|
|
231
231
|
}
|
|
232
232
|
});
|
|
233
233
|
stats.created++;
|
|
234
|
-
Logger.
|
|
234
|
+
Logger.debug(` └ 新增子级菜单: ${child.name} (ID: ${childId}, PID: ${parentId}, Path: ${childFullPath})`);
|
|
235
235
|
}
|
|
236
236
|
}
|
|
237
237
|
}
|
|
@@ -248,7 +248,7 @@ async function syncMenus(helper: any, menus: MenuConfig[]): Promise<{ created: n
|
|
|
248
248
|
* 删除配置中不存在的菜单(强制删除)
|
|
249
249
|
*/
|
|
250
250
|
async function deleteObsoleteRecords(helper: any, configPaths: Set<string>): Promise<number> {
|
|
251
|
-
Logger.
|
|
251
|
+
Logger.debug(`\n=== 删除配置中不存在的记录 ===`);
|
|
252
252
|
|
|
253
253
|
const allRecords = await helper.getAll({
|
|
254
254
|
table: 'core_menu',
|
|
@@ -264,12 +264,12 @@ async function deleteObsoleteRecords(helper: any, configPaths: Set<string>): Pro
|
|
|
264
264
|
where: { id: record.id }
|
|
265
265
|
});
|
|
266
266
|
deletedCount++;
|
|
267
|
-
Logger.
|
|
267
|
+
Logger.debug(` └ 删除记录: ${record.name} (ID: ${record.id}, path: ${record.path})`);
|
|
268
268
|
}
|
|
269
269
|
}
|
|
270
270
|
|
|
271
271
|
if (deletedCount === 0) {
|
|
272
|
-
Logger.
|
|
272
|
+
Logger.debug(' ✅ 无需删除的记录');
|
|
273
273
|
}
|
|
274
274
|
|
|
275
275
|
return deletedCount;
|
|
@@ -295,7 +295,7 @@ export async function syncMenuCommand(options: SyncMenuOptions = {}) {
|
|
|
295
295
|
Logger.info('开始同步菜单配置到数据库...\n');
|
|
296
296
|
|
|
297
297
|
// 1. 读取两个配置文件
|
|
298
|
-
Logger.
|
|
298
|
+
Logger.debug('=== 步骤 1: 读取菜单配置文件 ===');
|
|
299
299
|
const projectMenuPath = join(projectDir, 'menu.json');
|
|
300
300
|
const coreMenuPath = join(coreDir, 'menu.json');
|
|
301
301
|
|
|
@@ -316,7 +316,7 @@ export async function syncMenuCommand(options: SyncMenuOptions = {}) {
|
|
|
316
316
|
// 打印合并后的菜单结构
|
|
317
317
|
for (const menu of mergedMenus) {
|
|
318
318
|
const childCount = menu.children?.length || 0;
|
|
319
|
-
Logger.
|
|
319
|
+
Logger.debug(` └ ${menu.name} (${menu.path}) - ${childCount} 个子菜单`);
|
|
320
320
|
}
|
|
321
321
|
|
|
322
322
|
// 连接数据库(SQL + Redis)
|
|
@@ -325,7 +325,7 @@ export async function syncMenuCommand(options: SyncMenuOptions = {}) {
|
|
|
325
325
|
const helper = Database.getDbHelper();
|
|
326
326
|
|
|
327
327
|
// 3. 检查表是否存在
|
|
328
|
-
Logger.
|
|
328
|
+
Logger.debug('\n=== 步骤 3: 检查数据表 ===');
|
|
329
329
|
const exists = await helper.tableExists('core_menu');
|
|
330
330
|
|
|
331
331
|
if (!exists) {
|
|
@@ -333,22 +333,22 @@ export async function syncMenuCommand(options: SyncMenuOptions = {}) {
|
|
|
333
333
|
process.exit(1);
|
|
334
334
|
}
|
|
335
335
|
|
|
336
|
-
Logger.
|
|
336
|
+
Logger.debug(`✅ 表 core_menu 存在`);
|
|
337
337
|
|
|
338
338
|
// 4. 收集配置文件中所有菜单的 path
|
|
339
|
-
Logger.
|
|
339
|
+
Logger.debug('\n=== 步骤 4: 收集配置菜单路径 ===');
|
|
340
340
|
const configPaths = collectPaths(mergedMenus);
|
|
341
|
-
Logger.
|
|
341
|
+
Logger.debug(`✅ 配置文件中共有 ${configPaths.size} 个菜单路径`);
|
|
342
342
|
|
|
343
343
|
// 5. 同步菜单
|
|
344
|
-
Logger.
|
|
344
|
+
Logger.debug('\n=== 步骤 5: 同步菜单数据(新增/更新) ===');
|
|
345
345
|
const stats = await syncMenus(helper, mergedMenus);
|
|
346
346
|
|
|
347
347
|
// 6. 删除文件中不存在的菜单(强制删除)
|
|
348
348
|
const deletedCount = await deleteObsoleteRecords(helper, configPaths);
|
|
349
349
|
|
|
350
350
|
// 7. 构建树形结构预览
|
|
351
|
-
Logger.
|
|
351
|
+
Logger.debug('\n=== 步骤 7: 菜单结构预览 ===');
|
|
352
352
|
const allMenus = await helper.getAll({
|
|
353
353
|
table: 'core_menu',
|
|
354
354
|
fields: ['id', 'pid', 'name', 'path', 'type'],
|
|
@@ -358,9 +358,9 @@ export async function syncMenuCommand(options: SyncMenuOptions = {}) {
|
|
|
358
358
|
const parentMenus = allMenus.filter((m: any) => m.pid === 0);
|
|
359
359
|
for (const parent of parentMenus) {
|
|
360
360
|
const children = allMenus.filter((m: any) => m.pid === parent.id);
|
|
361
|
-
Logger.
|
|
361
|
+
Logger.debug(` └ ${parent.name} (${parent.path})`);
|
|
362
362
|
for (const child of children) {
|
|
363
|
-
Logger.
|
|
363
|
+
Logger.debug(` └ ${child.name} (${child.path})`);
|
|
364
364
|
}
|
|
365
365
|
}
|
|
366
366
|
|
package/main.ts
CHANGED
|
@@ -35,7 +35,6 @@ export class Befly {
|
|
|
35
35
|
*/
|
|
36
36
|
async listen(callback?: (server: Server) => void): Promise<Server> {
|
|
37
37
|
const server = await this.lifecycle.start(this.appContext, callback);
|
|
38
|
-
Logger.info('数据库======:' + Env.APP_NAME);
|
|
39
38
|
|
|
40
39
|
// 注册优雅关闭信号处理器
|
|
41
40
|
const gracefulShutdown = async (signal: string) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "befly",
|
|
3
|
-
"version": "3.5.
|
|
3
|
+
"version": "3.5.1",
|
|
4
4
|
"description": "Befly - 为 Bun 专属打造的 TypeScript API 接口框架核心引擎",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": false,
|
|
@@ -80,5 +80,5 @@
|
|
|
80
80
|
"inquirer": "^12.10.0",
|
|
81
81
|
"pathe": "^2.0.3"
|
|
82
82
|
},
|
|
83
|
-
"gitHead": "
|
|
83
|
+
"gitHead": "bb6847f91fb09704ec47fdae750b3296419d5085"
|
|
84
84
|
}
|