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 CHANGED
@@ -1,147 +1,34 @@
1
1
  #!/usr/bin/env bun
2
2
  /**
3
3
  * Befly CLI - 命令行工具入口
4
- * Befly 框架提供项目管理和脚本执行功能
4
+ * 只提供 sync 命令,用于同步所有数据
5
+ *
6
+ * 使用方法:
7
+ * befly sync # 使用当前环境(默认 development)
5
8
  *
6
9
  * 环境变量加载:
7
- * 1. Bun 自动加载:根据 NODE_ENV 自动加载 .env.{NODE_ENV} 文件
8
- * 2. 手动指定:bun --env-file=.env.xxx befly <command>
9
- * 3. 默认环境:如未设置 NODE_ENV,Bun 加载 .env.development
10
+ * Bun 自动根据 NODE_ENV 加载对应的 .env 文件:
11
+ * - NODE_ENV=development → .env.development
12
+ * - NODE_ENV=production .env.production
13
+ * - NODE_ENV=test → .env.test
10
14
  */
11
15
 
12
- import { Command } from 'commander';
13
- import { buildCommand } from '../commands/build.js';
14
16
  import { syncCommand } from '../commands/sync.js';
15
- import { syncDbCommand } from '../commands/syncDb.js';
16
- import { syncApiCommand } from '../commands/syncApi.js';
17
- import { syncMenuCommand } from '../commands/syncMenu.js';
18
- import { syncDevCommand } from '../commands/syncDev.js';
19
17
  import { Logger } from '../lib/logger.js';
20
- import { join } from 'pathe';
21
- import { getPackageVersion } from '../commands/util.js';
22
-
23
- /**
24
- * 读取 package.json 版本号
25
- */
26
- function getVersion(): string {
27
- const coreDir = join(import.meta.dir, '..');
28
- return getPackageVersion(coreDir);
29
- }
30
-
31
- /**
32
- * Bun 版本要求
33
- */
34
- const REQUIRED_BUN_VERSION = '1.3.0';
35
18
 
36
19
  /**
37
- * 比较版本号
20
+ * 主函数
38
21
  */
39
- function compareVersions(v1: string, v2: string): number {
40
- const parts1 = v1.split('.').map(Number);
41
- const parts2 = v2.split('.').map(Number);
42
-
43
- for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) {
44
- const num1 = parts1[i] || 0;
45
- const num2 = parts2[i] || 0;
46
-
47
- if (num1 > num2) return 1;
48
- if (num1 < num2) return -1;
49
- }
50
-
51
- return 0;
52
- }
53
-
54
- /**
55
- * 获取 Bun 版本
56
- */
57
- function getBunVersion(): string | null {
22
+ async function main() {
23
+ // 执行 sync 命令
58
24
  try {
59
- if (typeof Bun !== 'undefined' && Bun.version) {
60
- return Bun.version;
61
- }
62
-
63
- const proc = Bun.spawnSync(['bun', '--version'], {
64
- stdout: 'pipe',
65
- stderr: 'pipe'
66
- });
67
-
68
- if (proc.exitCode === 0) {
69
- const version = proc.stdout.toString().trim();
70
- return version;
71
- }
72
-
73
- return null;
74
- } catch {
75
- return null;
76
- }
77
- }
78
-
79
- /**
80
- * 检查 Bun 版本
81
- */
82
- function checkBunVersion(): void {
83
- const currentVersion = getBunVersion();
84
-
85
- if (!currentVersion) {
86
- Logger.error('未检测到 Bun 运行时');
87
- Logger.info('\nBefly CLI 需要 Bun v1.3.0 或更高版本');
88
- Logger.info('请访问 https://bun.sh 安装 Bun\n');
89
- Logger.info('安装命令:');
90
- Logger.info(' Windows (PowerShell): powershell -c "irm bun.sh/install.ps1 | iex"');
91
- Logger.info(' macOS/Linux: curl -fsSL https://bun.sh/install | bash\n');
92
- process.exit(1);
93
- }
94
-
95
- const comparison = compareVersions(currentVersion, REQUIRED_BUN_VERSION);
96
-
97
- if (comparison < 0) {
98
- Logger.error(`Bun 版本过低: ${currentVersion}`);
99
- Logger.info(`\n需要 Bun v${REQUIRED_BUN_VERSION} 或更高版本`);
100
- Logger.info('请升级 Bun:\n');
101
- Logger.info(' bun upgrade\n');
25
+ await syncCommand();
26
+ Logger.printEnv();
27
+ } catch (error: any) {
28
+ Logger.error('命令执行失败:', error.message || error);
102
29
  process.exit(1);
103
30
  }
104
31
  }
105
32
 
106
- // 检查 Bun 版本
107
- checkBunVersion();
108
-
109
- const program = new Command();
110
-
111
- program.name('befly').description('Befly CLI - 为 Befly 框架提供命令行工具').version(getVersion());
112
-
113
- /**
114
- * 包装命令处理函数,在执行后打印环境
115
- */
116
- function wrapCommand<T extends (...args: any[]) => any>(fn: T): T {
117
- return (async (...args: any[]) => {
118
- const result = await fn(...args);
119
- Logger.printEnv();
120
- return result;
121
- }) as T;
122
- }
123
-
124
- // build 命令 - 构建项目
125
- program.command('build').description('构建项目').option('-o, --outdir <path>', '输出目录', 'dist').option('--minify', '压缩代码', false).option('--sourcemap', '生成 sourcemap', false).action(wrapCommand(buildCommand));
126
-
127
- // sync 命令 - 一次性执行所有同步
128
- program.command('sync').description('一次性执行所有同步操作(syncApi + syncMenu + syncDev)').option('--plan', '计划模式,只显示不执行', false).option('-e, --env <environment>', '指定环境 (development, production, test)').action(wrapCommand(syncCommand));
129
-
130
- // syncDb 命令 - 同步数据库
131
- program.command('syncDb').description('同步数据库表结构').option('-t, --table <name>', '指定表名').option('--dry-run', '预览模式,只显示不执行', false).option('-e, --env <environment>', '指定环境 (development, production, test)').action(wrapCommand(syncDbCommand));
132
-
133
- // syncApi 命令 - 同步 API 接口
134
- program.command('syncApi').description('同步 API 接口到数据库').option('--plan', '计划模式,只显示不执行', false).option('-e, --env <environment>', '指定环境 (development, production, test)').action(wrapCommand(syncApiCommand));
135
-
136
- // syncMenu 命令 - 同步菜单
137
- program.command('syncMenu').description('同步菜单配置到数据库').option('--plan', '计划模式,只显示不执行', false).option('-e, --env <environment>', '指定环境 (development, production, test)').action(wrapCommand(syncMenuCommand));
138
-
139
- // syncDev 命令 - 同步开发者账号
140
- program.command('syncDev').description('同步开发者管理员账号').option('--plan', '计划模式,只显示不执行', false).option('-e, --env <environment>', '指定环境 (development, production, test)').action(wrapCommand(syncDevCommand));
141
-
142
- // 显示建议和错误
143
- program.showSuggestionAfterError();
144
- program.showHelpAfterError();
145
-
146
- // 解析命令行参数
147
- program.parse();
33
+ // 运行主函数
34
+ main();
package/checks/table.ts CHANGED
@@ -221,7 +221,7 @@ export default async function (): Promise<boolean> {
221
221
 
222
222
  if (fileValid) {
223
223
  validFiles++;
224
- Logger.info(`${fileType}表 ${fileName} 验证通过(${fileRules} 个字段)`);
224
+ // Logger.info(`${fileType}表 ${fileName} 验证通过(${fileRules} 个字段)`);
225
225
  } else {
226
226
  invalidFiles++;
227
227
  }
@@ -232,17 +232,15 @@ export default async function (): Promise<boolean> {
232
232
  }
233
233
 
234
234
  // 输出统计信息
235
- Logger.info(`表定义检查完成:`);
236
- Logger.info(` 总文件数: ${totalFiles}`);
237
- Logger.info(` 总规则数: ${totalRules}`);
238
- Logger.info(` 通过文件: ${validFiles}`);
239
- Logger.info(` 失败文件: ${invalidFiles}`);
235
+ // Logger.info(` 总文件数: ${totalFiles}`);
236
+ // Logger.info(` 总规则数: ${totalRules}`);
237
+ // Logger.info(` 通过文件: ${validFiles}`);
238
+ // Logger.info(` 失败文件: ${invalidFiles}`);
240
239
 
241
240
  if (invalidFiles > 0) {
242
241
  Logger.warn(`表定义检查失败,请修复上述错误后重试`);
243
242
  return false;
244
243
  } else {
245
- Logger.info(`所有表定义检查通过 ✓`);
246
244
  return true;
247
245
  }
248
246
  } catch (error: any) {
package/commands/index.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Build、Start、Sync、Addon、SyncApi、SyncMenu、SyncDev 命令实现
2
+ * Sync 命令实现
3
3
  */
4
4
 
5
5
  import { join } from 'pathe';
@@ -7,102 +7,6 @@ import { existsSync } from 'node:fs';
7
7
  import { Logger } from '../lib/logger.js';
8
8
  import { getProjectRoot } from './util.js';
9
9
 
10
- // ========== Build 命令 ==========
11
- interface BuildOptions {
12
- outdir: string;
13
- minify: boolean;
14
- sourcemap: boolean;
15
- }
16
-
17
- export async function buildCommand(options: BuildOptions) {
18
- try {
19
- const projectRoot = getProjectRoot();
20
- const mainFile = join(projectRoot, 'main.ts');
21
-
22
- if (!existsSync(mainFile)) {
23
- Logger.error('未找到 main.ts 文件');
24
- process.exit(1);
25
- }
26
-
27
- Logger.info('正在构建项目...');
28
-
29
- const args = ['build', mainFile, '--outdir', options.outdir, '--target', 'bun'];
30
-
31
- if (options.minify) {
32
- args.push('--minify');
33
- }
34
-
35
- if (options.sourcemap) {
36
- args.push('--sourcemap');
37
- }
38
-
39
- const proc = Bun.spawn(['bun', ...args], {
40
- cwd: projectRoot,
41
- stdout: 'pipe',
42
- stderr: 'pipe'
43
- });
44
-
45
- await proc.exited;
46
-
47
- if (proc.exitCode === 0) {
48
- Logger.success('项目构建完成');
49
- Logger.success(`输出目录: ${options.outdir}`);
50
- } else {
51
- Logger.error('项目构建失败');
52
- process.exit(1);
53
- }
54
- } catch (error) {
55
- Logger.error('构建失败:');
56
- console.error(error);
57
- process.exit(1);
58
- }
59
- }
60
-
61
- // ========== Start 命令 ==========
62
- interface StartOptions {
63
- port: string;
64
- host: string;
65
- }
66
-
67
- export async function startCommand(options: StartOptions) {
68
- try {
69
- const projectRoot = getProjectRoot();
70
- const mainFile = join(projectRoot, 'main.ts');
71
-
72
- if (!existsSync(mainFile)) {
73
- Logger.error('未找到 main.ts 文件');
74
- process.exit(1);
75
- }
76
-
77
- process.env.NODE_ENV = 'production';
78
- process.env.APP_PORT = options.port;
79
- process.env.APP_HOST = options.host;
80
-
81
- Logger.info('正在启动生产服务器...\n');
82
- Logger.info(`端口: ${options.port}`);
83
- Logger.info(`主机: ${options.host}`);
84
- Logger.info(`环境: production\n`);
85
-
86
- const proc = Bun.spawn(['bun', 'run', mainFile], {
87
- cwd: projectRoot,
88
- stdout: 'inherit',
89
- stderr: 'inherit',
90
- stdin: 'inherit',
91
- env: {
92
- ...process.env,
93
- FORCE_COLOR: '1'
94
- }
95
- });
96
-
97
- await proc.exited;
98
- process.exit(proc.exitCode || 0);
99
- } catch (error) {
100
- Logger.error('启动失败:');
101
- console.error(error);
102
- process.exit(1);
103
- }
104
- }
105
-
106
10
  // ========== Sync 命令 ==========
107
11
  interface SyncOptions {
108
12
  table?: string;
@@ -163,62 +67,7 @@ export async function syncCommand(options: SyncOptions) {
163
67
  }
164
68
  }
165
69
 
166
- // ========== Addon 命令 ==========
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
- // ========== 导出新增的同步命令 ==========
70
+ // ========== 导出同步命令 ==========
222
71
  export { syncApiCommand } from './syncApi.js';
223
72
  export { syncMenuCommand } from './syncMenu.js';
224
73
  export { syncDevCommand } from './syncDev.js';
package/commands/sync.ts CHANGED
@@ -1,54 +1,86 @@
1
1
  /**
2
2
  * Sync 命令 - 一次性执行所有同步操作
3
- * 按顺序执行:syncApi → syncMenu → syncDev
3
+ * 按顺序执行:syncDb → syncApi → syncMenu → syncDev
4
4
  */
5
5
 
6
6
  import { Logger } from '../lib/logger.js';
7
- import { syncApiCommand } from './syncApi.js';
8
- import { syncMenuCommand } from './syncMenu.js';
9
- import { syncDevCommand } from './syncDev.js';
7
+ import { Env } from '../config/env.js';
8
+ import { syncDbCommand, type SyncDbStats } from './syncDb.js';
9
+ import { syncApiCommand, type SyncApiStats } from './syncApi.js';
10
+ import { syncMenuCommand, type SyncMenuStats } from './syncMenu.js';
11
+ import { syncDevCommand, type SyncDevStats } from './syncDev.js';
10
12
  import { existsSync, mkdirSync } from 'node:fs';
11
13
 
12
- interface SyncOptions {
13
- env?: string;
14
- plan?: boolean;
15
- }
14
+ interface SyncOptions {}
16
15
 
17
16
  export async function syncCommand(options: SyncOptions = {}) {
18
17
  try {
19
- Logger.info('========================================');
20
- Logger.info('开始执行完整同步流程');
21
- Logger.info('========================================\n');
22
-
23
18
  const startTime = Date.now();
24
19
 
25
20
  // 确保 logs 目录存在
26
21
  if (!existsSync('./logs')) {
27
22
  mkdirSync('./logs', { recursive: true });
28
- Logger.info('✅ 已创建 logs 目录\n');
29
23
  }
30
24
 
31
- // 1. 同步接口(并缓存)
32
- Logger.info('【步骤 1/3】同步接口数据\n');
33
- await syncApiCommand(options);
34
- Logger.info('\n✅ 接口同步完成\n');
25
+ // 1. 同步数据库表结构
26
+ const dbStats = await syncDbCommand({ dryRun: false });
35
27
 
36
- // 2. 同步菜单(并缓存)
37
- Logger.info('【步骤 2/3】同步菜单数据\n');
38
- await syncMenuCommand(options);
39
- Logger.info('\n✅ 菜单同步完成\n');
28
+ // 2. 同步接口(并缓存)
29
+ const apiStats = await syncApiCommand();
40
30
 
41
- // 3. 同步开发管理员(并缓存角色权限)
42
- Logger.info('【步骤 3/3】同步开发管理员\n');
43
- await syncDevCommand(options);
44
- Logger.info('\n✅ 开发管理员同步完成\n');
31
+ // 3. 同步菜单(并缓存)
32
+ const menuStats = await syncMenuCommand();
33
+
34
+ // 4. 同步开发管理员(并缓存角色权限)
35
+ const devStats = await syncDevCommand();
45
36
 
46
37
  // 输出总结
47
38
  const totalTime = ((Date.now() - startTime) / 1000).toFixed(2);
48
- Logger.info('========================================');
49
- Logger.info('🎉 所有同步操作已完成!');
50
39
  Logger.info(`总耗时: ${totalTime} 秒`);
51
- Logger.info('========================================');
40
+
41
+ console.log(
42
+ Bun.inspect.table([
43
+ { 项目: '处理表数', 数量: dbStats.processedTables },
44
+ { 项目: '创建表', 数量: dbStats.createdTables },
45
+ { 项目: '修改表', 数量: dbStats.modifiedTables },
46
+ { 项目: '新增字段', 数量: dbStats.addFields },
47
+ { 项目: '字段名称变更', 数量: dbStats.nameChanges },
48
+ { 项目: '字段类型变更', 数量: dbStats.typeChanges },
49
+ { 项目: '索引新增', 数量: dbStats.indexCreate },
50
+ { 项目: '索引删除', 数量: dbStats.indexDrop }
51
+ ])
52
+ );
53
+
54
+ Logger.info('\n📊 接口同步统计');
55
+ console.log(
56
+ Bun.inspect.table([
57
+ { 项目: '总接口数', 数量: apiStats.totalApis },
58
+ { 项目: '新增接口', 数量: apiStats.created },
59
+ { 项目: '更新接口', 数量: apiStats.updated },
60
+ { 项目: '删除接口', 数量: apiStats.deleted }
61
+ ])
62
+ );
63
+
64
+ Logger.info('\n📊 菜单同步统计');
65
+ console.log(
66
+ Bun.inspect.table([
67
+ { 项目: '总菜单数', 数量: menuStats.totalMenus },
68
+ { 项目: '父级菜单', 数量: menuStats.parentMenus },
69
+ { 项目: '子级菜单', 数量: menuStats.childMenus },
70
+ { 项目: '新增菜单', 数量: menuStats.created },
71
+ { 项目: '更新菜单', 数量: menuStats.updated },
72
+ { 项目: '删除菜单', 数量: menuStats.deleted }
73
+ ])
74
+ );
75
+
76
+ Logger.info('\n📊 开发账号同步统计');
77
+ console.log(
78
+ Bun.inspect.table([
79
+ { 项目: '管理员数量', 数量: devStats.adminCount },
80
+ { 项目: '角色数量', 数量: devStats.roleCount },
81
+ { 项目: '缓存角色数', 数量: devStats.cachedRoles }
82
+ ])
83
+ );
52
84
  } catch (error: any) {
53
85
  Logger.error('同步过程中发生错误:', error);
54
86
  process.exit(1);