befly 3.5.7 → 3.6.0
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/lib/addon.ts +77 -0
- package/lib/logger.ts +6 -15
- package/lifecycle/checker.ts +20 -49
- package/lifecycle/lifecycle.ts +7 -5
- package/lifecycle/loader.ts +5 -5
- package/main.ts +10 -1
- package/package.json +2 -9
- package/paths.ts +5 -54
- package/util.ts +1 -83
- package/apis/admin/del.ts +0 -35
- package/apis/admin/info.ts +0 -50
- package/apis/admin/ins.ts +0 -61
- package/apis/admin/list.ts +0 -20
- package/apis/admin/roleDetail.ts +0 -35
- package/apis/admin/roleSave.ts +0 -40
- package/apis/admin/upd.ts +0 -51
- package/apis/api/all.ts +0 -37
- package/apis/auth/login.ts +0 -78
- package/apis/auth/logout.ts +0 -23
- package/apis/auth/register.ts +0 -50
- package/apis/auth/sendSmsCode.ts +0 -36
- package/apis/cache/refresh.ts +0 -34
- package/apis/dashboard/addonList.ts +0 -47
- package/apis/dashboard/changelog.ts +0 -37
- package/apis/dashboard/configStatus.ts +0 -54
- package/apis/dashboard/environmentInfo.ts +0 -46
- package/apis/dashboard/performanceMetrics.ts +0 -23
- package/apis/dashboard/permissionStats.ts +0 -31
- package/apis/dashboard/serviceStatus.ts +0 -82
- package/apis/dashboard/systemInfo.ts +0 -26
- package/apis/dashboard/systemOverview.ts +0 -32
- package/apis/dashboard/systemResources.ts +0 -119
- package/apis/dict/all.ts +0 -25
- package/apis/dict/del.ts +0 -19
- package/apis/dict/detail.ts +0 -21
- package/apis/dict/ins.ts +0 -27
- package/apis/dict/list.ts +0 -18
- package/apis/dict/upd.ts +0 -31
- package/apis/menu/all.ts +0 -68
- package/apis/menu/del.ts +0 -37
- package/apis/menu/ins.ts +0 -20
- package/apis/menu/list.ts +0 -21
- package/apis/menu/upd.ts +0 -29
- package/apis/role/apiDetail.ts +0 -30
- package/apis/role/apiSave.ts +0 -41
- package/apis/role/del.ts +0 -44
- package/apis/role/detail.ts +0 -24
- package/apis/role/ins.ts +0 -39
- package/apis/role/list.ts +0 -14
- package/apis/role/menuDetail.ts +0 -30
- package/apis/role/menuSave.ts +0 -38
- package/apis/role/save.ts +0 -44
- package/apis/role/upd.ts +0 -40
- package/bin/index.ts +0 -34
- package/checks/conflict.ts +0 -351
- package/checks/table.ts +0 -250
- package/commands/index.ts +0 -73
- package/commands/sync.ts +0 -88
- package/commands/syncApi.ts +0 -316
- package/commands/syncDb/apply.ts +0 -171
- package/commands/syncDb/constants.ts +0 -77
- package/commands/syncDb/ddl.ts +0 -191
- package/commands/syncDb/helpers.ts +0 -173
- package/commands/syncDb/index.ts +0 -217
- package/commands/syncDb/schema.ts +0 -199
- package/commands/syncDb/sqlite.ts +0 -50
- package/commands/syncDb/state.ts +0 -112
- package/commands/syncDb/table.ts +0 -214
- package/commands/syncDb/tableCreate.ts +0 -149
- package/commands/syncDb/types.ts +0 -92
- package/commands/syncDb/version.ts +0 -73
- package/commands/syncDb.ts +0 -34
- package/commands/syncDev.ts +0 -237
- package/commands/syncMenu.ts +0 -349
- package/commands/util.ts +0 -58
- package/tables/admin.json +0 -14
- package/tables/api.json +0 -8
- package/tables/dict.json +0 -8
- package/tables/menu.json +0 -8
- package/tables/role.json +0 -8
package/lib/addon.ts
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
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/lib/logger.ts
CHANGED
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
|
|
6
6
|
import { join } from 'pathe';
|
|
7
7
|
import { appendFile, stat } from 'node:fs/promises';
|
|
8
|
-
import chalk from 'chalk';
|
|
9
8
|
import { Env } from '../env.js';
|
|
10
9
|
import type { LogLevel } from '../types/common.js';
|
|
11
10
|
|
|
@@ -54,12 +53,6 @@ export class Logger {
|
|
|
54
53
|
|
|
55
54
|
// 格式化消息
|
|
56
55
|
const timestamp = formatDate();
|
|
57
|
-
const colorMap = {
|
|
58
|
-
info: chalk.greenBright,
|
|
59
|
-
debug: chalk.cyanBright,
|
|
60
|
-
warn: chalk.yellowBright,
|
|
61
|
-
error: chalk.redBright
|
|
62
|
-
};
|
|
63
56
|
|
|
64
57
|
// 处理消息内容
|
|
65
58
|
let content = '';
|
|
@@ -69,19 +62,17 @@ export class Logger {
|
|
|
69
62
|
content = String(message);
|
|
70
63
|
}
|
|
71
64
|
|
|
72
|
-
//
|
|
73
|
-
const
|
|
74
|
-
const
|
|
65
|
+
// 格式化日志消息
|
|
66
|
+
const levelStr = level.toUpperCase().padStart(5);
|
|
67
|
+
const logMessage = `[${timestamp}] ${levelStr} - ${content}`;
|
|
75
68
|
|
|
76
69
|
// 控制台输出
|
|
77
70
|
if (this.config.toConsole) {
|
|
78
|
-
console.log(
|
|
71
|
+
console.log(logMessage);
|
|
79
72
|
}
|
|
80
73
|
|
|
81
|
-
//
|
|
82
|
-
|
|
83
|
-
const plainMessage = `[${timestamp}] ${plainLevelStr} - ${content}`;
|
|
84
|
-
await this.writeToFile(plainMessage, level);
|
|
74
|
+
// 文件输出
|
|
75
|
+
await this.writeToFile(logMessage, level);
|
|
85
76
|
}
|
|
86
77
|
|
|
87
78
|
/**
|
package/lifecycle/checker.ts
CHANGED
|
@@ -6,8 +6,9 @@
|
|
|
6
6
|
import { join, basename } from 'pathe';
|
|
7
7
|
import { Logger } from '../lib/logger.js';
|
|
8
8
|
import { calcPerfTime } from '../util.js';
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
9
|
+
import { projectCheckDir } from '../paths.js';
|
|
10
|
+
import { checkDefault } from '../check.js';
|
|
11
|
+
import { Addon } from '../lib/addon.js';
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* 系统检查器类
|
|
@@ -20,6 +21,9 @@ export class Checker {
|
|
|
20
21
|
try {
|
|
21
22
|
const checkStartTime = Bun.nanoseconds();
|
|
22
23
|
|
|
24
|
+
// 先执行默认检查(有异常会自动抛出)
|
|
25
|
+
await checkDefault();
|
|
26
|
+
|
|
23
27
|
const glob = new Bun.Glob('*.{ts}');
|
|
24
28
|
|
|
25
29
|
// 统计信息
|
|
@@ -29,50 +33,19 @@ export class Checker {
|
|
|
29
33
|
failedChecks: 0
|
|
30
34
|
};
|
|
31
35
|
|
|
32
|
-
//
|
|
33
|
-
|
|
34
|
-
const conflictCheckPath = join(coreCheckDir, 'conflict.ts');
|
|
35
|
-
const conflictCheckFile = Bun.file(conflictCheckPath);
|
|
36
|
-
|
|
37
|
-
if (await conflictCheckFile.exists()) {
|
|
38
|
-
stats.totalChecks++;
|
|
39
|
-
const conflictCheckStart = Bun.nanoseconds();
|
|
36
|
+
// 检查目录列表:先项目,后 addons
|
|
37
|
+
const checkDirs: Array<{ path: string; type: 'app' | 'addon'; addonName?: string }> = [];
|
|
40
38
|
|
|
41
|
-
|
|
42
|
-
|
|
39
|
+
// 添加项目 checks 目录
|
|
40
|
+
checkDirs.push({ path: projectCheckDir, type: 'app' });
|
|
43
41
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
const conflictCheckTime = calcPerfTime(conflictCheckStart);
|
|
47
|
-
|
|
48
|
-
if (typeof conflictResult !== 'boolean') {
|
|
49
|
-
Logger.warn(`核心检查 conflict.ts 返回值必须为 true 或 false,当前为 ${typeof conflictResult}`);
|
|
50
|
-
stats.failedChecks++;
|
|
51
|
-
} else if (conflictResult === true) {
|
|
52
|
-
stats.passedChecks++;
|
|
53
|
-
} else {
|
|
54
|
-
Logger.warn(`核心检查未通过: conflict.ts`);
|
|
55
|
-
stats.failedChecks++;
|
|
56
|
-
// 资源冲突检测失败,立即终止
|
|
57
|
-
Logger.warn('资源冲突检测失败,无法继续启动');
|
|
58
|
-
process.exit(1);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
} catch (error: any) {
|
|
63
|
-
Logger.error('执行资源冲突检测时出错:', error);
|
|
64
|
-
stats.failedChecks++;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// 2. 检查目录列表:先核心,后项目,最后 addons
|
|
68
|
-
// 检查所有 checks 目录
|
|
69
|
-
const checkDirs = [{ path: coreCheckDir, type: 'core' as const }]; // 添加所有 addon 的 checks 目录
|
|
70
|
-
const addons = scanAddons();
|
|
42
|
+
// 添加所有 addon 的 checks 目录
|
|
43
|
+
const addons = Addon.scan();
|
|
71
44
|
for (const addon of addons) {
|
|
72
|
-
if (
|
|
45
|
+
if (Addon.dirExists(addon, 'checks')) {
|
|
73
46
|
checkDirs.push({
|
|
74
|
-
path:
|
|
75
|
-
type: 'addon'
|
|
47
|
+
path: Addon.getDir(addon, 'checks'),
|
|
48
|
+
type: 'addon',
|
|
76
49
|
addonName: addon
|
|
77
50
|
});
|
|
78
51
|
}
|
|
@@ -80,9 +53,10 @@ export class Checker {
|
|
|
80
53
|
|
|
81
54
|
// 按顺序扫描并执行检查函数
|
|
82
55
|
for (const checkConfig of checkDirs) {
|
|
83
|
-
const { path: checkDir, type } = checkConfig;
|
|
56
|
+
const { path: checkDir, type: type } = checkConfig;
|
|
84
57
|
const addonName = 'addonName' in checkConfig ? checkConfig.addonName : undefined;
|
|
85
|
-
const checkTypeLabel = type === '
|
|
58
|
+
const checkTypeLabel = type === 'app' ? '项目' : `组件${addonName}`;
|
|
59
|
+
|
|
86
60
|
for await (const file of glob.scan({
|
|
87
61
|
cwd: checkDir,
|
|
88
62
|
onlyFiles: true,
|
|
@@ -91,9 +65,6 @@ export class Checker {
|
|
|
91
65
|
const fileName = basename(file);
|
|
92
66
|
if (fileName.startsWith('_')) continue; // 跳过以下划线开头的文件
|
|
93
67
|
|
|
94
|
-
// 跳过已经执行过的 conflict.ts
|
|
95
|
-
if (type === 'core' && fileName === 'conflict.ts') continue;
|
|
96
|
-
|
|
97
68
|
try {
|
|
98
69
|
stats.totalChecks++;
|
|
99
70
|
const singleCheckStart = Bun.nanoseconds();
|
|
@@ -135,10 +106,10 @@ export class Checker {
|
|
|
135
106
|
|
|
136
107
|
// 输出检查结果统计
|
|
137
108
|
if (stats.failedChecks > 0) {
|
|
138
|
-
Logger.error(
|
|
109
|
+
Logger.error(`系统检查失败: ${stats.failedChecks}/${stats.totalChecks},耗时: ${totalCheckTime}`);
|
|
139
110
|
process.exit(1);
|
|
140
111
|
} else if (stats.totalChecks > 0) {
|
|
141
|
-
Logger.info(
|
|
112
|
+
Logger.info(`系统检查通过: ${stats.passedChecks}/${stats.totalChecks},耗时: ${totalCheckTime}`);
|
|
142
113
|
}
|
|
143
114
|
} catch (error: any) {
|
|
144
115
|
Logger.error('执行系统检查时发生错误', error);
|
package/lifecycle/lifecycle.ts
CHANGED
|
@@ -4,10 +4,12 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { Logger } from '../lib/logger.js';
|
|
7
|
-
import {
|
|
8
|
-
import { scanAddons, addonDirExists } from '../util.js';
|
|
9
|
-
import { Checker } from './checker.js';
|
|
7
|
+
import { Database } from '../lib/database.js';
|
|
10
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';
|
|
11
13
|
import { Bootstrap } from './bootstrap.js';
|
|
12
14
|
|
|
13
15
|
import type { Server } from 'bun';
|
|
@@ -78,10 +80,10 @@ export class Lifecycle {
|
|
|
78
80
|
}
|
|
79
81
|
|
|
80
82
|
// 2. 加载 addon APIs
|
|
81
|
-
const addons =
|
|
83
|
+
const addons = Addon.scan();
|
|
82
84
|
|
|
83
85
|
for (const addon of addons) {
|
|
84
|
-
const hasApis =
|
|
86
|
+
const hasApis = Addon.dirExists(addon, 'apis');
|
|
85
87
|
if (hasApis) {
|
|
86
88
|
try {
|
|
87
89
|
await Loader.loadApis(addon, this.apiRoutes, { where: 'addon', addonName: addon });
|
package/lifecycle/loader.ts
CHANGED
|
@@ -9,7 +9,7 @@ import { isPlainObject } from 'es-toolkit/compat';
|
|
|
9
9
|
import { Logger } from '../lib/logger.js';
|
|
10
10
|
import { calcPerfTime } from '../util.js';
|
|
11
11
|
import { corePluginDir, projectPluginDir, coreApiDir, projectApiDir } from '../paths.js';
|
|
12
|
-
import {
|
|
12
|
+
import { Addon } from '../lib/addon.js';
|
|
13
13
|
import type { Plugin } from '../types/plugin.js';
|
|
14
14
|
import type { ApiRoute } from '../types/api.js';
|
|
15
15
|
import type { BeflyContext } from '../types/befly.js';
|
|
@@ -148,13 +148,13 @@ export class Loader {
|
|
|
148
148
|
Logger.info(`✓ 核心插件加载完成: ${corePlugins.length} 个,耗时: ${corePluginsScanTime}`);
|
|
149
149
|
|
|
150
150
|
// 扫描 addon 插件目录
|
|
151
|
-
const addons =
|
|
151
|
+
const addons = Addon.scan();
|
|
152
152
|
if (addons.length > 0) {
|
|
153
153
|
const addonPluginsScanStart = Bun.nanoseconds();
|
|
154
154
|
for (const addon of addons) {
|
|
155
|
-
if (!
|
|
155
|
+
if (!Addon.dirExists(addon, 'plugins')) continue;
|
|
156
156
|
|
|
157
|
-
const addonPluginsDir =
|
|
157
|
+
const addonPluginsDir = Addon.getDir(addon, 'plugins');
|
|
158
158
|
for await (const file of glob.scan({
|
|
159
159
|
cwd: addonPluginsDir,
|
|
160
160
|
onlyFiles: true,
|
|
@@ -325,7 +325,7 @@ export class Loader {
|
|
|
325
325
|
if (where === 'core') {
|
|
326
326
|
apiDir = coreApiDir;
|
|
327
327
|
} else if (where === 'addon') {
|
|
328
|
-
apiDir =
|
|
328
|
+
apiDir = Addon.getDir(addonName, 'apis');
|
|
329
329
|
} else {
|
|
330
330
|
apiDir = projectApiDir;
|
|
331
331
|
}
|
package/main.ts
CHANGED
|
@@ -10,6 +10,10 @@ import { Cipher } from './lib/cipher.js';
|
|
|
10
10
|
import { Jwt } from './lib/jwt.js';
|
|
11
11
|
import { Database } from './lib/database.js';
|
|
12
12
|
import { Lifecycle } from './lifecycle/lifecycle.js';
|
|
13
|
+
import { coreDir } from './paths.js';
|
|
14
|
+
import { DbHelper } from './lib/dbHelper.js';
|
|
15
|
+
import { RedisHelper } from './lib/redisHelper.js';
|
|
16
|
+
import { Addon } from './lib/addon.js';
|
|
13
17
|
|
|
14
18
|
import type { Server } from 'bun';
|
|
15
19
|
import type { BeflyContext, BeflyOptions } from './types/befly.js';
|
|
@@ -71,5 +75,10 @@ export {
|
|
|
71
75
|
Cipher,
|
|
72
76
|
Jwt,
|
|
73
77
|
Yes,
|
|
74
|
-
No
|
|
78
|
+
No,
|
|
79
|
+
coreDir,
|
|
80
|
+
Database,
|
|
81
|
+
DbHelper,
|
|
82
|
+
RedisHelper,
|
|
83
|
+
Addon
|
|
75
84
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "befly",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.6.0",
|
|
4
4
|
"description": "Befly - 为 Bun 专属打造的 TypeScript API 接口框架核心引擎",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": false,
|
|
@@ -10,9 +10,6 @@
|
|
|
10
10
|
},
|
|
11
11
|
"main": "main.ts",
|
|
12
12
|
"types": "./types/index.d.ts",
|
|
13
|
-
"bin": {
|
|
14
|
-
"befly": "./bin/index.ts"
|
|
15
|
-
},
|
|
16
13
|
"exports": {
|
|
17
14
|
".": {
|
|
18
15
|
"default": "./main.ts"
|
|
@@ -30,7 +27,6 @@
|
|
|
30
27
|
"api",
|
|
31
28
|
"framework",
|
|
32
29
|
"core",
|
|
33
|
-
"cli",
|
|
34
30
|
"typescript",
|
|
35
31
|
"javascript",
|
|
36
32
|
"backend",
|
|
@@ -42,10 +38,8 @@
|
|
|
42
38
|
"homepage": "https://chensuiyi.me",
|
|
43
39
|
"license": "Apache-2.0",
|
|
44
40
|
"files": [
|
|
45
|
-
"bin/",
|
|
46
41
|
"apis/",
|
|
47
42
|
"checks/",
|
|
48
|
-
"commands/",
|
|
49
43
|
"config/",
|
|
50
44
|
"lib/",
|
|
51
45
|
"lifecycle/",
|
|
@@ -76,9 +70,8 @@
|
|
|
76
70
|
"bun": ">=1.3.0"
|
|
77
71
|
},
|
|
78
72
|
"dependencies": {
|
|
79
|
-
"chalk": "^5.6.2",
|
|
80
73
|
"es-toolkit": "^1.41.0",
|
|
81
74
|
"pathe": "^2.0.3"
|
|
82
75
|
},
|
|
83
|
-
"gitHead": "
|
|
76
|
+
"gitHead": "e6d6cd5dd4098fc9b4cf537b0dcdc7e781c0e80e"
|
|
84
77
|
}
|
package/paths.ts
CHANGED
|
@@ -8,24 +8,6 @@
|
|
|
8
8
|
* - root* 系列:Core 框架内部路径(packages/core/*)
|
|
9
9
|
* - project* 系列:用户项目路径(process.cwd()/*)
|
|
10
10
|
*
|
|
11
|
-
* 目录结构:
|
|
12
|
-
* ```
|
|
13
|
-
* packages/core/ (coreDir)
|
|
14
|
-
* ├── scripts/ (coreScriptDir)
|
|
15
|
-
* ├── config/ (coreConfigDir)
|
|
16
|
-
* ├── checks/ (coreCheckDir)
|
|
17
|
-
* ├── plugins/ (corePluginDir)
|
|
18
|
-
* ├── apis/ (coreApiDir)
|
|
19
|
-
* └── tables/ (coreTableDir)
|
|
20
|
-
*
|
|
21
|
-
* project/ (projectDir)
|
|
22
|
-
* ├── scripts/ (projectScriptDir)
|
|
23
|
-
* ├── config/ (projectConfigDir)
|
|
24
|
-
* ├── checks/ (projectCheckDir)
|
|
25
|
-
* ├── plugins/ (projectPluginDir)
|
|
26
|
-
* ├── apis/ (projectApiDir)
|
|
27
|
-
* └── tables/ (projectTableDir)
|
|
28
|
-
* ```
|
|
29
11
|
*/
|
|
30
12
|
|
|
31
13
|
import { fileURLToPath } from 'node:url';
|
|
@@ -35,9 +17,6 @@ import { dirname, join } from 'pathe';
|
|
|
35
17
|
const __filename = fileURLToPath(import.meta.url);
|
|
36
18
|
const __dirname = dirname(__filename);
|
|
37
19
|
|
|
38
|
-
// 项目根目录(befly 框架的使用方项目)
|
|
39
|
-
const projectRoot = process.cwd();
|
|
40
|
-
|
|
41
20
|
// ==================== Core 框架路径 ====================
|
|
42
21
|
|
|
43
22
|
/**
|
|
@@ -46,20 +25,6 @@ const projectRoot = process.cwd();
|
|
|
46
25
|
*/
|
|
47
26
|
export const coreDir = __dirname;
|
|
48
27
|
|
|
49
|
-
/**
|
|
50
|
-
* Core 框架脚本目录
|
|
51
|
-
* @description packages/core/scripts/
|
|
52
|
-
* @usage 存放框架级别的脚本工具
|
|
53
|
-
*/
|
|
54
|
-
export const coreScriptDir = join(__dirname, 'scripts');
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Core 框架配置目录
|
|
58
|
-
* @description packages/core/config/
|
|
59
|
-
* @usage 存放框架默认配置(env.ts, fields.ts 等)
|
|
60
|
-
*/
|
|
61
|
-
export const coreConfigDir = join(__dirname, 'config');
|
|
62
|
-
|
|
63
28
|
/**
|
|
64
29
|
* Core 框架检查目录
|
|
65
30
|
* @description packages/core/checks/
|
|
@@ -95,46 +60,32 @@ export const coreTableDir = join(__dirname, 'tables');
|
|
|
95
60
|
* @description process.cwd()
|
|
96
61
|
* @usage 用户项目的根目录
|
|
97
62
|
*/
|
|
98
|
-
export const projectDir =
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* 项目脚本目录
|
|
102
|
-
* @description {projectDir}/scripts/
|
|
103
|
-
* @usage 存放用户自定义脚本工具
|
|
104
|
-
*/
|
|
105
|
-
export const projectScriptDir = join(projectRoot, 'scripts');
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* 项目配置目录
|
|
109
|
-
* @description {projectDir}/config/
|
|
110
|
-
* @usage 存放用户项目配置(覆盖框架默认配置)
|
|
111
|
-
*/
|
|
112
|
-
export const projectConfigDir = join(projectRoot, 'config');
|
|
63
|
+
export const projectDir = process.cwd();
|
|
113
64
|
|
|
114
65
|
/**
|
|
115
66
|
* 项目检查目录
|
|
116
67
|
* @description {projectDir}/checks/
|
|
117
68
|
* @usage 存放用户自定义启动检查模块
|
|
118
69
|
*/
|
|
119
|
-
export const projectCheckDir = join(
|
|
70
|
+
export const projectCheckDir = join(projectDir, 'checks');
|
|
120
71
|
|
|
121
72
|
/**
|
|
122
73
|
* 项目插件目录
|
|
123
74
|
* @description {projectDir}/plugins/
|
|
124
75
|
* @usage 存放用户自定义插件
|
|
125
76
|
*/
|
|
126
|
-
export const projectPluginDir = join(
|
|
77
|
+
export const projectPluginDir = join(projectDir, 'plugins');
|
|
127
78
|
|
|
128
79
|
/**
|
|
129
80
|
* 项目 API 目录
|
|
130
81
|
* @description {projectDir}/apis/
|
|
131
82
|
* @usage 存放用户业务 API 接口
|
|
132
83
|
*/
|
|
133
|
-
export const projectApiDir = join(
|
|
84
|
+
export const projectApiDir = join(projectDir, 'apis');
|
|
134
85
|
|
|
135
86
|
/**
|
|
136
87
|
* 项目表定义目录
|
|
137
88
|
* @description {projectDir}/tables/
|
|
138
89
|
* @usage 存放用户业务表定义(JSON 格式)
|
|
139
90
|
*/
|
|
140
|
-
export const projectTableDir = join(
|
|
91
|
+
export const projectTableDir = join(projectDir, 'tables');
|
package/util.ts
CHANGED
|
@@ -1,21 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
* Befly 核心工具函数集合
|
|
3
|
-
*
|
|
4
|
-
* 本文件整合了框架核心工具函数:
|
|
5
|
-
* - API 响应工具(Yes, No)
|
|
6
|
-
* - 对象操作(pickFields, fieldClear)
|
|
7
|
-
* - 日期时间(calcPerfTime)
|
|
8
|
-
* - 表定义工具(parseRule)
|
|
9
|
-
* - Addon 管理(scanAddons, getAddonDir 等)
|
|
10
|
-
*
|
|
11
|
-
* 注意:
|
|
12
|
-
* - JWT 工具位于 lib/jwt.ts
|
|
13
|
-
* - Logger 位于 lib/logger.ts
|
|
14
|
-
* - Validator 位于 lib/validator.ts
|
|
15
|
-
* - Database 管理位于 lib/database.ts
|
|
16
|
-
*/
|
|
17
|
-
|
|
18
|
-
import fs from 'node:fs';
|
|
1
|
+
import fs from 'node:fs';
|
|
19
2
|
import { join } from 'pathe';
|
|
20
3
|
import { readdirSync, statSync, readFileSync, existsSync } from 'node:fs';
|
|
21
4
|
import { isEmpty, isPlainObject } from 'es-toolkit/compat';
|
|
@@ -232,68 +215,3 @@ export const parseRule = (rule: string): ParsedFieldRule => {
|
|
|
232
215
|
regex: fieldRegx !== 'null' ? fieldRegx : null
|
|
233
216
|
};
|
|
234
217
|
};
|
|
235
|
-
|
|
236
|
-
// ========================================
|
|
237
|
-
// Addon 管理工具
|
|
238
|
-
// ========================================
|
|
239
|
-
|
|
240
|
-
/**
|
|
241
|
-
* 扫描所有可用的 addon
|
|
242
|
-
*/
|
|
243
|
-
export const scanAddons = (): string[] => {
|
|
244
|
-
const beflyDir = join(projectDir, 'node_modules', '@befly-addon');
|
|
245
|
-
|
|
246
|
-
if (!existsSync(beflyDir)) {
|
|
247
|
-
return [];
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
try {
|
|
251
|
-
return fs
|
|
252
|
-
.readdirSync(beflyDir)
|
|
253
|
-
.filter((name) => {
|
|
254
|
-
// addon 名称格式:admin, demo 等(不带 addon- 前缀)
|
|
255
|
-
const fullPath = join(beflyDir, name);
|
|
256
|
-
try {
|
|
257
|
-
const stat = statSync(fullPath);
|
|
258
|
-
return stat.isDirectory();
|
|
259
|
-
} catch {
|
|
260
|
-
return false;
|
|
261
|
-
}
|
|
262
|
-
})
|
|
263
|
-
.sort();
|
|
264
|
-
} catch {
|
|
265
|
-
return [];
|
|
266
|
-
}
|
|
267
|
-
};
|
|
268
|
-
|
|
269
|
-
/**
|
|
270
|
-
* 获取 addon 的指定子目录路径
|
|
271
|
-
*/
|
|
272
|
-
export const getAddonDir = (addonName: string, subDir: string): string => {
|
|
273
|
-
return join(projectDir, 'node_modules', '@befly-addon', addonName, subDir);
|
|
274
|
-
};
|
|
275
|
-
|
|
276
|
-
/**
|
|
277
|
-
* 检查 addon 子目录是否存在
|
|
278
|
-
*/
|
|
279
|
-
export const addonDirExists = (addonName: string, subDir: string): boolean => {
|
|
280
|
-
const dir = getAddonDir(addonName, subDir);
|
|
281
|
-
return existsSync(dir) && statSync(dir).isDirectory();
|
|
282
|
-
};
|
|
283
|
-
|
|
284
|
-
/**
|
|
285
|
-
* 获取插件目录列表
|
|
286
|
-
* @param addonsDir - addons 根目录路径
|
|
287
|
-
* @returns 插件名称数组
|
|
288
|
-
*/
|
|
289
|
-
export function getAddonDirs(addonsDir: string): string[] {
|
|
290
|
-
// try {
|
|
291
|
-
return readdirSync(addonsDir).filter((name) => {
|
|
292
|
-
const addonPath = path.join(addonsDir, name);
|
|
293
|
-
return statSync(addonPath).isDirectory() && !name.startsWith('_');
|
|
294
|
-
});
|
|
295
|
-
// } catch (error: any) {
|
|
296
|
-
// Logger.error(`读取插件目录失败: ${addonsDir}`, error.message);
|
|
297
|
-
// return [];
|
|
298
|
-
// }
|
|
299
|
-
}
|
package/apis/admin/del.ts
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 删除管理员
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { Yes, No } from '../../util.js';
|
|
6
|
-
|
|
7
|
-
export default {
|
|
8
|
-
name: '删除管理员',
|
|
9
|
-
fields: {},
|
|
10
|
-
required: ['id'],
|
|
11
|
-
handler: async (befly, ctx) => {
|
|
12
|
-
// 检查管理员是否存在
|
|
13
|
-
const admin = await befly.db.getOne({
|
|
14
|
-
table: 'core_admin',
|
|
15
|
-
where: { id: ctx.body.id }
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
if (!admin) {
|
|
19
|
-
return No('管理员不存在');
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
// 不能删除 dev 角色的管理员
|
|
23
|
-
if (admin.roleCode === 'dev') {
|
|
24
|
-
return No('不能删除开发者账号');
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// 删除管理员
|
|
28
|
-
await befly.db.delData({
|
|
29
|
-
table: 'core_admin',
|
|
30
|
-
where: { id: ctx.body.id }
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
return Yes('删除成功');
|
|
34
|
-
}
|
|
35
|
-
};
|
package/apis/admin/info.ts
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 获取用户信息接口
|
|
3
|
-
*
|
|
4
|
-
* @returns 返回 admin 表的字段(不含 password)以及关联的角色信息(小驼峰格式):
|
|
5
|
-
* - id, name, email, phone, roleId, roleCode, state
|
|
6
|
-
* - lastLoginTime, lastLoginIp
|
|
7
|
-
* - createdAt, updatedAt
|
|
8
|
-
* - role: 角色完整信息(包含 menus 和 apis 权限)
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import { Yes, No } from '../../util.js';
|
|
12
|
-
|
|
13
|
-
export default {
|
|
14
|
-
name: '获取用户信息',
|
|
15
|
-
handler: async (befly, ctx) => {
|
|
16
|
-
// 从 JWT token 中获取用户ID
|
|
17
|
-
const userId = ctx.user?.id;
|
|
18
|
-
|
|
19
|
-
if (!userId) {
|
|
20
|
-
return No('未授权');
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
// 查询用户信息(框架自动转换为小驼峰)
|
|
24
|
-
const admin = await befly.db.getOne({
|
|
25
|
-
table: 'core_admin',
|
|
26
|
-
where: { id: userId }
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
if (!admin) {
|
|
30
|
-
return No('用户不存在');
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// 查询角色信息(使用 roleCode 而非 roleId,框架自动转换为小驼峰)
|
|
34
|
-
let roleInfo = null;
|
|
35
|
-
if (admin.roleCode) {
|
|
36
|
-
roleInfo = await befly.db.getOne({
|
|
37
|
-
table: 'core_role',
|
|
38
|
-
where: { code: admin.roleCode }
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// 返回用户信息(不包含密码,字段已是小驼峰格式)
|
|
43
|
-
const { password: _, ...userWithoutPassword } = admin;
|
|
44
|
-
|
|
45
|
-
return Yes('获取成功', {
|
|
46
|
-
...userWithoutPassword,
|
|
47
|
-
role: roleInfo
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
|
-
};
|