befly 3.3.4 → 3.4.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/apis/admin/del.ts +35 -0
- package/apis/admin/info.ts +50 -0
- package/apis/admin/ins.ts +61 -0
- package/apis/admin/list.ts +20 -0
- package/apis/admin/roleDetail.ts +35 -0
- package/apis/admin/roleSave.ts +40 -0
- package/apis/admin/upd.ts +51 -0
- package/apis/api/all.ts +37 -0
- package/apis/auth/login.ts +78 -0
- package/apis/auth/logout.ts +23 -0
- package/apis/auth/register.ts +50 -0
- package/apis/auth/sendSmsCode.ts +35 -0
- package/apis/cache/refresh.ts +34 -0
- package/apis/dashboard/addonList.ts +47 -0
- package/apis/dashboard/changelog.ts +37 -0
- package/apis/dashboard/configStatus.ts +54 -0
- package/apis/dashboard/environmentInfo.ts +46 -0
- package/apis/dashboard/performanceMetrics.ts +23 -0
- package/apis/dashboard/permissionStats.ts +31 -0
- package/apis/dashboard/serviceStatus.ts +82 -0
- package/apis/dashboard/systemInfo.ts +25 -0
- package/apis/dashboard/systemOverview.ts +32 -0
- package/apis/dashboard/systemResources.ts +119 -0
- package/apis/dict/all.ts +25 -0
- package/apis/dict/del.ts +19 -0
- package/apis/dict/detail.ts +21 -0
- package/apis/dict/ins.ts +27 -0
- package/apis/dict/list.ts +18 -0
- package/apis/dict/upd.ts +31 -0
- package/apis/menu/all.ts +68 -0
- package/apis/menu/del.ts +37 -0
- package/apis/menu/ins.ts +20 -0
- package/apis/menu/list.ts +21 -0
- package/apis/menu/upd.ts +29 -0
- package/apis/role/apiDetail.ts +30 -0
- package/apis/role/apiSave.ts +41 -0
- package/apis/role/del.ts +44 -0
- package/apis/role/detail.ts +24 -0
- package/apis/role/ins.ts +39 -0
- package/apis/role/list.ts +14 -0
- package/apis/role/menuDetail.ts +30 -0
- package/apis/role/menuSave.ts +38 -0
- package/apis/role/save.ts +44 -0
- package/apis/role/upd.ts +40 -0
- package/checks/conflict.ts +6 -6
- package/checks/table.ts +2 -2
- package/commands/build.ts +8 -4
- package/commands/dev.ts +19 -30
- package/commands/start.ts +24 -8
- package/commands/syncDb/index.ts +3 -3
- package/commands/syncDb/table.ts +1 -1
- package/commands/syncMenu.ts +40 -28
- package/config/env.ts +1 -17
- package/lifecycle/checker.ts +3 -3
- package/lifecycle/cluster-worker.ts +49 -0
- package/lifecycle/cluster.ts +31 -18
- package/lifecycle/lifecycle.ts +2 -2
- package/lifecycle/loader.ts +5 -5
- package/main.ts +2 -2
- package/package.json +3 -2
- package/paths.ts +125 -19
- package/router/static.ts +2 -2
- package/util.ts +3 -3
- package/config/menu.json +0 -67
package/apis/menu/ins.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Yes, No } from '../../util.js';
|
|
2
|
+
import adminMenuTable from '../../tables/menu.json';
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
name: '创建菜单',
|
|
6
|
+
fields: adminMenuTable,
|
|
7
|
+
handler: async (befly, ctx) => {
|
|
8
|
+
try {
|
|
9
|
+
const menuId = await befly.db.insData({
|
|
10
|
+
table: 'core_menu',
|
|
11
|
+
data: ctx.body
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
return Yes('操作成功', { id: menuId });
|
|
15
|
+
} catch (error) {
|
|
16
|
+
befly.logger.error('创建菜单失败:', error);
|
|
17
|
+
return No('操作失败');
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Yes, No } from '../../util.js';
|
|
2
|
+
export default {
|
|
3
|
+
name: '获取菜单列表',
|
|
4
|
+
handler: async (befly, ctx) => {
|
|
5
|
+
try {
|
|
6
|
+
const menus = await befly.db.getAll({
|
|
7
|
+
table: 'core_menu',
|
|
8
|
+
fields: ['id', 'name', 'path', 'icon', 'sort', 'pid', 'type', 'state', 'created_at', 'updated_at'],
|
|
9
|
+
orderBy: [
|
|
10
|
+
{ field: 'sort', direction: 'ASC' },
|
|
11
|
+
{ field: 'id', direction: 'ASC' }
|
|
12
|
+
]
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
return Yes('操作成功', menus);
|
|
16
|
+
} catch (error) {
|
|
17
|
+
befly.logger.error('获取菜单列表失败:', error);
|
|
18
|
+
return No('操作失败');
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
};
|
package/apis/menu/upd.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Yes, No } from '../../util.js';
|
|
2
|
+
import adminMenuTable from '../../tables/menu.json';
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
name: '更新菜单',
|
|
6
|
+
fields: adminMenuTable,
|
|
7
|
+
handler: async (befly, ctx) => {
|
|
8
|
+
try {
|
|
9
|
+
await befly.db.updData({
|
|
10
|
+
table: 'core_menu',
|
|
11
|
+
where: { id: ctx.body.id },
|
|
12
|
+
data: {
|
|
13
|
+
name: ctx.body.name,
|
|
14
|
+
path: ctx.body.path,
|
|
15
|
+
icon: ctx.body.icon,
|
|
16
|
+
sort: ctx.body.sort,
|
|
17
|
+
pid: ctx.body.pid,
|
|
18
|
+
type: ctx.body.type
|
|
19
|
+
// state 字段不在此处更新,需要禁用/启用时单独处理
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
return Yes('操作成功');
|
|
24
|
+
} catch (error) {
|
|
25
|
+
befly.logger.error('更新菜单失败:', error);
|
|
26
|
+
return No('操作失败');
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 获取角色的接口权限
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { Yes, No } from '../../util.js';
|
|
6
|
+
|
|
7
|
+
export default {
|
|
8
|
+
name: '获取角色接口权限',
|
|
9
|
+
handler: async (befly, ctx) => {
|
|
10
|
+
// 查询角色信息
|
|
11
|
+
const role = await befly.db.getOne({
|
|
12
|
+
table: 'core_role',
|
|
13
|
+
where: { id: ctx.body.roleId }
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
if (!role) {
|
|
17
|
+
return No('角色不存在');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// 解析接口ID列表(逗号分隔的字符串转为数组)
|
|
21
|
+
const apiIds = role.apis
|
|
22
|
+
? role.apis
|
|
23
|
+
.split(',')
|
|
24
|
+
.map((id: string) => parseInt(id.trim()))
|
|
25
|
+
.filter((id: number) => !isNaN(id))
|
|
26
|
+
: [];
|
|
27
|
+
|
|
28
|
+
return Yes('操作成功', { apiIds });
|
|
29
|
+
}
|
|
30
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 保存角色的接口权限
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { Yes, No } from '../../util.js';
|
|
6
|
+
import adminRoleTable from '../../tables/role.json';
|
|
7
|
+
|
|
8
|
+
export default {
|
|
9
|
+
name: '保存角色接口权限',
|
|
10
|
+
fields: {
|
|
11
|
+
apiIds: adminRoleTable.apis
|
|
12
|
+
},
|
|
13
|
+
handler: async (befly, ctx) => {
|
|
14
|
+
// 查询角色是否存在
|
|
15
|
+
const role = await befly.db.getOne({
|
|
16
|
+
table: 'core_role',
|
|
17
|
+
where: { id: ctx.body.roleId }
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
if (!role) {
|
|
21
|
+
return No('角色不存在');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// 将数组转为逗号分隔的字符串存储
|
|
25
|
+
const apiIdsStr = Array.isArray(ctx.body.apiIds) ? ctx.body.apiIds.join(',') : '';
|
|
26
|
+
|
|
27
|
+
// 更新角色的接口权限
|
|
28
|
+
await befly.db.updData({
|
|
29
|
+
table: 'core_role',
|
|
30
|
+
where: { id: ctx.body.roleId },
|
|
31
|
+
data: {
|
|
32
|
+
apis: apiIdsStr
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
// 增量更新 Redis 缓存
|
|
37
|
+
await befly.cache.cacheRolePermissions(befly, role.code, apiIdsStr);
|
|
38
|
+
|
|
39
|
+
return Yes('操作成功');
|
|
40
|
+
}
|
|
41
|
+
};
|
package/apis/role/del.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 删除角色
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { Yes, No } from '../../util.js';
|
|
6
|
+
|
|
7
|
+
export default {
|
|
8
|
+
name: '删除角色',
|
|
9
|
+
handler: async (befly, ctx) => {
|
|
10
|
+
try {
|
|
11
|
+
// 检查是否有用户使用此角色(使用 getList 代替 getAll)
|
|
12
|
+
const adminList = await befly.db.getList({
|
|
13
|
+
table: 'core_admin',
|
|
14
|
+
where: { roleId: ctx.body.id }
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
if (adminList.total > 0) {
|
|
18
|
+
return No('该角色已分配给用户,无法删除');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// 获取角色信息(用于删除缓存)
|
|
22
|
+
const role = await befly.db.getDetail({
|
|
23
|
+
table: 'core_role',
|
|
24
|
+
where: { id: ctx.body.id }
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
// 删除角色
|
|
28
|
+
await befly.db.delData({
|
|
29
|
+
table: 'core_role',
|
|
30
|
+
where: { id: ctx.body.id }
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// 删除角色权限缓存
|
|
34
|
+
if (role?.code) {
|
|
35
|
+
await befly.cache.deleteRolePermissions(befly, role.code);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return Yes('操作成功');
|
|
39
|
+
} catch (error) {
|
|
40
|
+
befly.logger.error('删除角色失败:', error);
|
|
41
|
+
return No('操作失败');
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 获取用户的角色(单角色模式)
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { Yes, No } from '../../util.js';
|
|
6
|
+
|
|
7
|
+
export default {
|
|
8
|
+
name: '获取用户角色',
|
|
9
|
+
handler: async (befly, ctx) => {
|
|
10
|
+
let roleInfo = null;
|
|
11
|
+
if (ctx.body.id && ctx.user.roleType === 'admin') {
|
|
12
|
+
roleInfo = await befly.db.getOne({
|
|
13
|
+
table: 'core_role',
|
|
14
|
+
where: { code: ctx.body.id }
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return Yes('操作成功', {
|
|
19
|
+
roleId: ctx.body.id,
|
|
20
|
+
roleCode: ctx.body.id,
|
|
21
|
+
role: roleInfo
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
};
|
package/apis/role/ins.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Yes, No } from '../../util.js';
|
|
2
|
+
import adminRoleTable from '../../tables/role.json';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* 创建角色
|
|
6
|
+
*/
|
|
7
|
+
export default {
|
|
8
|
+
name: '创建角色',
|
|
9
|
+
fields: adminRoleTable,
|
|
10
|
+
handler: async (befly, ctx) => {
|
|
11
|
+
// 检查角色代码是否已存在
|
|
12
|
+
const existing = await befly.db.getOne({
|
|
13
|
+
table: 'core_role',
|
|
14
|
+
where: { code: ctx.body.code }
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
if (existing) {
|
|
18
|
+
return No('角色代码已存在');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const roleId = await befly.db.insData({
|
|
22
|
+
table: 'core_role',
|
|
23
|
+
data: {
|
|
24
|
+
name: ctx.body.name,
|
|
25
|
+
code: ctx.body.code,
|
|
26
|
+
description: ctx.body.description,
|
|
27
|
+
menus: ctx.body.menus || '',
|
|
28
|
+
apis: ctx.body.apis || '',
|
|
29
|
+
sort: ctx.body.sort
|
|
30
|
+
// state 由框架自动设置为 1
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
// 增量缓存角色权限到 Redis Set
|
|
35
|
+
await befly.cache.cacheRolePermissions(befly, ctx.body.code, ctx.body.apis || '');
|
|
36
|
+
|
|
37
|
+
return Yes('操作成功', { id: roleId });
|
|
38
|
+
}
|
|
39
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Yes } from '../../util.js';
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
name: '获取角色列表',
|
|
5
|
+
handler: async (befly, ctx) => {
|
|
6
|
+
const roles = await befly.db.getList({
|
|
7
|
+
limit: 30,
|
|
8
|
+
table: 'core_role',
|
|
9
|
+
orderBy: ['sort#ASC', 'id#ASC']
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
return Yes('操作成功', roles);
|
|
13
|
+
}
|
|
14
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 获取角色的菜单权限
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { Yes, No } from '../../util.js';
|
|
6
|
+
|
|
7
|
+
export default {
|
|
8
|
+
name: '获取角色菜单权限',
|
|
9
|
+
handler: async (befly, ctx) => {
|
|
10
|
+
// 查询角色信息
|
|
11
|
+
const role = await befly.db.getOne({
|
|
12
|
+
table: 'core_role',
|
|
13
|
+
where: { id: ctx.body.roleId }
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
if (!role) {
|
|
17
|
+
return No('角色不存在');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// 解析菜单ID列表(逗号分隔的字符串转为数组)
|
|
21
|
+
const menuIds = role.menus
|
|
22
|
+
? role.menus
|
|
23
|
+
.split(',')
|
|
24
|
+
.map((id: string) => parseInt(id.trim()))
|
|
25
|
+
.filter((id: number) => !isNaN(id))
|
|
26
|
+
: [];
|
|
27
|
+
|
|
28
|
+
return Yes('操作成功', menuIds);
|
|
29
|
+
}
|
|
30
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 保存角色的菜单权限
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { Yes, No } from '../../util.js';
|
|
6
|
+
import adminRoleTable from '../../tables/role.json';
|
|
7
|
+
|
|
8
|
+
export default {
|
|
9
|
+
name: '保存角色菜单权限',
|
|
10
|
+
fields: {
|
|
11
|
+
menuIds: adminRoleTable.menus
|
|
12
|
+
},
|
|
13
|
+
handler: async (befly, ctx) => {
|
|
14
|
+
// 查询角色是否存在
|
|
15
|
+
const role = await befly.db.getOne({
|
|
16
|
+
table: 'core_role',
|
|
17
|
+
where: { id: ctx.body.roleId }
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
if (!role) {
|
|
21
|
+
return No('角色不存在');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// 将数组转为逗号分隔的字符串存储
|
|
25
|
+
const menuIdsStr = Array.isArray(ctx.body.menuIds) ? ctx.body.menuIds.join(',') : '';
|
|
26
|
+
|
|
27
|
+
// 更新角色的菜单权限
|
|
28
|
+
await befly.db.updData({
|
|
29
|
+
table: 'core_role',
|
|
30
|
+
where: { id: ctx.body.roleId },
|
|
31
|
+
data: {
|
|
32
|
+
menus: menuIdsStr
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
return Yes('操作成功');
|
|
37
|
+
}
|
|
38
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 保存用户的角色(单角色模式)
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { Yes, No } from '../../util.js';
|
|
6
|
+
|
|
7
|
+
export default {
|
|
8
|
+
name: '保存用户角色',
|
|
9
|
+
fields: {
|
|
10
|
+
roleCode: '角色编码|string|2|50|null|1|^[a-zA-Z0-9_]+$'
|
|
11
|
+
},
|
|
12
|
+
handler: async (befly, ctx) => {
|
|
13
|
+
try {
|
|
14
|
+
// 查询角色是否存在(使用 roleCode 而非 roleId)
|
|
15
|
+
const role = await befly.db.getOne({
|
|
16
|
+
table: 'core_role',
|
|
17
|
+
where: { code: ctx.body.roleCode }
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
if (!role) {
|
|
21
|
+
return No('角色不存在');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// 根据角色编码判断角色类型(硬编码规则)
|
|
25
|
+
const roleType = role.code === 'dev' || role.code === 'admin' ? 'admin' : 'user';
|
|
26
|
+
|
|
27
|
+
// 更新管理员的角色ID、角色编码和角色类型
|
|
28
|
+
await befly.db.updData({
|
|
29
|
+
table: 'core_admin',
|
|
30
|
+
where: { id: ctx.body.adminId },
|
|
31
|
+
data: {
|
|
32
|
+
roleId: role.id,
|
|
33
|
+
roleCode: role.code,
|
|
34
|
+
roleType: roleType
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
return Yes('操作成功');
|
|
39
|
+
} catch (error) {
|
|
40
|
+
befly.logger.error('保存用户角色失败:', error);
|
|
41
|
+
return No('操作失败');
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
};
|
package/apis/role/upd.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Yes, No } from '../../util.js';
|
|
2
|
+
import adminRoleTable from '../../tables/role.json';
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
name: '更新角色',
|
|
6
|
+
fields: adminRoleTable,
|
|
7
|
+
handler: async (befly, ctx) => {
|
|
8
|
+
// 检查角色代码是否被其他角色占用
|
|
9
|
+
const existing = await befly.db.getList({
|
|
10
|
+
table: 'core_role',
|
|
11
|
+
where: {
|
|
12
|
+
code: ctx.body.code,
|
|
13
|
+
id$ne: ctx.body.id
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
if (existing.total > 0) {
|
|
18
|
+
return No('角色代码已被其他角色使用');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
await befly.db.updData({
|
|
22
|
+
table: 'core_role',
|
|
23
|
+
where: { id: ctx.body.id },
|
|
24
|
+
data: {
|
|
25
|
+
name: ctx.body.name,
|
|
26
|
+
code: ctx.body.code,
|
|
27
|
+
description: ctx.body.description,
|
|
28
|
+
menus: ctx.body.menus || '',
|
|
29
|
+
apis: ctx.body.apis || '',
|
|
30
|
+
sort: ctx.body.sort
|
|
31
|
+
// state 字段不在此处更新,需要禁用/启用时单独处理
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
// 增量更新角色权限缓存(先删除再重建)
|
|
36
|
+
await befly.cache.cacheRolePermissions(befly, ctx.body.code, ctx.body.apis || '');
|
|
37
|
+
|
|
38
|
+
return Yes('操作成功');
|
|
39
|
+
}
|
|
40
|
+
};
|
package/checks/conflict.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
import { relative, basename } from 'pathe';
|
|
7
7
|
import { Logger } from '../lib/logger.js';
|
|
8
|
-
import {
|
|
8
|
+
import { projectPluginDir, coreTableDir, projectTableDir, projectApiDir } from '../paths.js';
|
|
9
9
|
import { scanAddons, getAddonDir, addonDirExists } from '../util.js';
|
|
10
10
|
|
|
11
11
|
/**
|
|
@@ -41,7 +41,7 @@ async function collectCorePlugins(registry: ResourceRegistry): Promise<void> {
|
|
|
41
41
|
try {
|
|
42
42
|
const glob = new Bun.Glob('*.ts');
|
|
43
43
|
for await (const file of glob.scan({
|
|
44
|
-
cwd:
|
|
44
|
+
cwd: projectPluginDir,
|
|
45
45
|
onlyFiles: true,
|
|
46
46
|
absolute: true
|
|
47
47
|
})) {
|
|
@@ -77,7 +77,7 @@ async function collectAddonResources(addonName: string, registry: ResourceRegist
|
|
|
77
77
|
const glob = new Bun.Glob('*.json');
|
|
78
78
|
|
|
79
79
|
for await (const file of glob.scan({
|
|
80
|
-
cwd:
|
|
80
|
+
cwd: addonTablesDir,
|
|
81
81
|
onlyFiles: true,
|
|
82
82
|
absolute: true
|
|
83
83
|
})) {
|
|
@@ -183,7 +183,7 @@ async function collectUserResources(registry: ResourceRegistry): Promise<string[
|
|
|
183
183
|
const conflicts: string[] = [];
|
|
184
184
|
|
|
185
185
|
// 收集用户表定义
|
|
186
|
-
const userTablesDir =
|
|
186
|
+
const userTablesDir = projectTableDir;
|
|
187
187
|
try {
|
|
188
188
|
const glob = new Bun.Glob('*.json');
|
|
189
189
|
for await (const file of glob.scan({
|
|
@@ -219,7 +219,7 @@ async function collectUserResources(registry: ResourceRegistry): Promise<string[
|
|
|
219
219
|
}
|
|
220
220
|
|
|
221
221
|
// 收集用户 API 路由
|
|
222
|
-
const userApisDir =
|
|
222
|
+
const userApisDir = projectApiDir;
|
|
223
223
|
try {
|
|
224
224
|
const glob = new Bun.Glob('**/*.ts');
|
|
225
225
|
for await (const file of glob.scan({
|
|
@@ -255,7 +255,7 @@ async function collectUserResources(registry: ResourceRegistry): Promise<string[
|
|
|
255
255
|
}
|
|
256
256
|
|
|
257
257
|
// 收集用户插件
|
|
258
|
-
const userPluginsDir =
|
|
258
|
+
const userPluginsDir = projectPluginDir;
|
|
259
259
|
try {
|
|
260
260
|
const glob = new Bun.Glob('*.ts');
|
|
261
261
|
for await (const file of glob.scan({
|
package/checks/table.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
import { basename } from 'pathe';
|
|
7
7
|
import { Logger } from '../lib/logger.js';
|
|
8
8
|
import { parseRule } from '../util.js';
|
|
9
|
-
import {
|
|
9
|
+
import { projectTableDir } from '../paths.js';
|
|
10
10
|
import { scanAddons, getAddonDir } from '../util.js';
|
|
11
11
|
|
|
12
12
|
/**
|
|
@@ -69,7 +69,7 @@ export default async function (): Promise<boolean> {
|
|
|
69
69
|
|
|
70
70
|
// 收集项目表字段定义文件
|
|
71
71
|
for await (const file of tablesGlob.scan({
|
|
72
|
-
cwd:
|
|
72
|
+
cwd: projectTableDir,
|
|
73
73
|
absolute: true,
|
|
74
74
|
onlyFiles: true
|
|
75
75
|
})) {
|
package/commands/build.ts
CHANGED
|
@@ -28,20 +28,24 @@ interface BuildOptions {
|
|
|
28
28
|
export async function buildCommand(options: BuildOptions) {
|
|
29
29
|
try {
|
|
30
30
|
const projectRoot = getProjectRoot();
|
|
31
|
-
const mainFile = join(projectRoot, 'main.ts');
|
|
32
31
|
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
// 验证是否在项目目录下
|
|
33
|
+
const packageJsonPath = join(projectRoot, 'package.json');
|
|
34
|
+
if (!existsSync(packageJsonPath)) {
|
|
35
|
+
Logger.error('未找到 package.json 文件,请确保在项目目录下');
|
|
35
36
|
process.exit(1);
|
|
36
37
|
}
|
|
37
38
|
|
|
39
|
+
// 使用内置默认入口文件
|
|
40
|
+
const entryFile = join(import.meta.dir, '..', 'entry.ts');
|
|
41
|
+
|
|
38
42
|
const spinner = ora({
|
|
39
43
|
text: '正在构建项目...',
|
|
40
44
|
color: 'cyan',
|
|
41
45
|
spinner: 'dots'
|
|
42
46
|
}).start();
|
|
43
47
|
|
|
44
|
-
const args = ['build',
|
|
48
|
+
const args = ['build', entryFile, '--outdir', options.outdir, '--target', 'bun'];
|
|
45
49
|
|
|
46
50
|
if (options.minify) {
|
|
47
51
|
args.push('--minify');
|
package/commands/dev.ts
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import { join } from 'pathe';
|
|
6
6
|
import { existsSync } from 'node:fs';
|
|
7
7
|
import { Logger } from '../lib/logger.js';
|
|
8
|
+
import { Befly } from '../main.js';
|
|
8
9
|
|
|
9
10
|
interface DevOptions {
|
|
10
11
|
port: string;
|
|
@@ -27,10 +28,11 @@ function getProjectRoot(): string {
|
|
|
27
28
|
export async function devCommand(options: DevOptions) {
|
|
28
29
|
try {
|
|
29
30
|
const projectRoot = getProjectRoot();
|
|
30
|
-
const mainFile = join(projectRoot, 'main.ts');
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
// 验证是否在 Befly 项目目录下
|
|
33
|
+
const packageJsonPath = join(projectRoot, 'package.json');
|
|
34
|
+
if (!existsSync(packageJsonPath)) {
|
|
35
|
+
Logger.error('未找到 package.json 文件,请确保在项目目录下');
|
|
34
36
|
process.exit(1);
|
|
35
37
|
}
|
|
36
38
|
|
|
@@ -54,38 +56,25 @@ export async function devCommand(options: DevOptions) {
|
|
|
54
56
|
Logger.info(`环境变量文件: .env.development\n`);
|
|
55
57
|
}
|
|
56
58
|
|
|
57
|
-
//
|
|
59
|
+
// 直接启动 Befly 实例
|
|
60
|
+
const app = new Befly();
|
|
61
|
+
const server = await app.listen();
|
|
58
62
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
stdout: 'inherit',
|
|
62
|
-
stderr: 'inherit',
|
|
63
|
-
stdin: 'inherit',
|
|
64
|
-
env: {
|
|
65
|
-
// ...process.env,
|
|
66
|
-
// NODE_ENV: 'development',
|
|
67
|
-
// APP_PORT: options.port,
|
|
68
|
-
// APP_HOST: options.host,
|
|
69
|
-
// LOG_DEBUG: options.verbose ? '1' : process.env.LOG_DEBUG,
|
|
70
|
-
// FORCE_COLOR: '1'
|
|
71
|
-
}
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
// 添加信号处理,确保优雅关闭
|
|
75
|
-
const signals: NodeJS.Signals[] = ['SIGTERM', 'SIGINT', 'SIGHUP'];
|
|
63
|
+
// 设置信号处理,确保优雅关闭
|
|
64
|
+
const signals: NodeJS.Signals[] = ['SIGTERM', 'SIGINT'];
|
|
76
65
|
signals.forEach((signal) => {
|
|
77
|
-
process.on(signal, () => {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
66
|
+
process.on(signal, async () => {
|
|
67
|
+
Logger.info(`\n收到 ${signal} 信号,正在关闭开发服务器...`);
|
|
68
|
+
try {
|
|
69
|
+
server.stop(true);
|
|
70
|
+
Logger.info('开发服务器已关闭');
|
|
71
|
+
process.exit(0);
|
|
72
|
+
} catch (error) {
|
|
73
|
+
Logger.error('关闭开发服务器失败:', error);
|
|
82
74
|
process.exit(1);
|
|
83
|
-
}
|
|
75
|
+
}
|
|
84
76
|
});
|
|
85
77
|
});
|
|
86
|
-
|
|
87
|
-
const exitCode = await proc.exited;
|
|
88
|
-
process.exit(exitCode || 0);
|
|
89
78
|
} catch (error) {
|
|
90
79
|
Logger.error('启动开发服务器失败:');
|
|
91
80
|
console.error(error);
|
package/commands/start.ts
CHANGED
|
@@ -6,6 +6,7 @@ import { join } from 'pathe';
|
|
|
6
6
|
import { existsSync } from 'node:fs';
|
|
7
7
|
import { Logger } from '../lib/logger.js';
|
|
8
8
|
import { ClusterManager } from '../lifecycle/cluster.js';
|
|
9
|
+
import { Befly } from '../main.js';
|
|
9
10
|
|
|
10
11
|
function getProjectRoot(): string {
|
|
11
12
|
let current = process.cwd();
|
|
@@ -28,10 +29,11 @@ interface StartOptions {
|
|
|
28
29
|
export async function startCommand(options: StartOptions) {
|
|
29
30
|
try {
|
|
30
31
|
const projectRoot = getProjectRoot();
|
|
31
|
-
const mainFile = join(projectRoot, 'main.ts');
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
// 验证是否在项目目录下
|
|
34
|
+
const packageJsonPath = join(projectRoot, 'package.json');
|
|
35
|
+
if (!existsSync(packageJsonPath)) {
|
|
36
|
+
Logger.error('未找到 package.json 文件,请确保在项目目录下');
|
|
35
37
|
process.exit(1);
|
|
36
38
|
}
|
|
37
39
|
|
|
@@ -49,8 +51,7 @@ export async function startCommand(options: StartOptions) {
|
|
|
49
51
|
instances,
|
|
50
52
|
startPort: parseInt(options.port),
|
|
51
53
|
host: options.host,
|
|
52
|
-
projectRoot
|
|
53
|
-
mainFile
|
|
54
|
+
projectRoot
|
|
54
55
|
});
|
|
55
56
|
|
|
56
57
|
await clusterManager.start();
|
|
@@ -67,10 +68,25 @@ export async function startCommand(options: StartOptions) {
|
|
|
67
68
|
Logger.info(`环境变量文件: .env.production\n`);
|
|
68
69
|
}
|
|
69
70
|
|
|
70
|
-
//
|
|
71
|
-
|
|
71
|
+
// 直接启动 Befly 实例
|
|
72
|
+
const app = new Befly();
|
|
73
|
+
const server = await app.listen();
|
|
72
74
|
|
|
73
|
-
//
|
|
75
|
+
// 设置信号处理,确保优雅关闭
|
|
76
|
+
const signals: NodeJS.Signals[] = ['SIGTERM', 'SIGINT'];
|
|
77
|
+
signals.forEach((signal) => {
|
|
78
|
+
process.on(signal, async () => {
|
|
79
|
+
Logger.info(`\n收到 ${signal} 信号,正在关闭生产服务器...`);
|
|
80
|
+
try {
|
|
81
|
+
server.stop(true);
|
|
82
|
+
Logger.info('生产服务器已关闭');
|
|
83
|
+
process.exit(0);
|
|
84
|
+
} catch (error) {
|
|
85
|
+
Logger.error('关闭生产服务器失败:', error);
|
|
86
|
+
process.exit(1);
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
});
|
|
74
90
|
}
|
|
75
91
|
} catch (error) {
|
|
76
92
|
Logger.error('启动失败:');
|