befly 3.13.9 → 3.14.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/dist/befly.js +149 -146
- package/dist/befly.min.js +11 -11
- package/dist/checks/checkApi.js +12 -12
- package/dist/index.js +4 -5
- package/dist/loader/loadApis.js +3 -4
- package/dist/router/api.js +1 -1
- package/dist/sync/syncApi.js +54 -31
- package/dist/sync/syncDev.js +88 -97
- package/dist/types/sync.d.ts +2 -1
- package/dist/utils/processAtSymbol.d.ts +1 -1
- package/dist/utils/processAtSymbol.js +2 -2
- package/dist/utils/scanFiles.js +5 -1
- package/package.json +2 -2
package/dist/checks/checkApi.js
CHANGED
|
@@ -14,28 +14,28 @@ export async function checkApi(apis) {
|
|
|
14
14
|
hasError = true;
|
|
15
15
|
continue;
|
|
16
16
|
}
|
|
17
|
-
//
|
|
18
|
-
if (typeof api?.
|
|
19
|
-
Logger.warn(Object.assign({}, omit(api, ["handler"]), { msg: "接口的
|
|
17
|
+
// path / routePrefix 由 scanFiles 系统生成:必须是严格的 pathname
|
|
18
|
+
if (typeof api?.path !== "string" || api.path.trim() === "") {
|
|
19
|
+
Logger.warn(Object.assign({}, omit(api, ["handler"]), { msg: "接口的 path 属性必须是非空字符串(由系统生成)" }));
|
|
20
20
|
hasError = true;
|
|
21
21
|
}
|
|
22
22
|
else {
|
|
23
|
-
const
|
|
23
|
+
const path = api.path.trim();
|
|
24
24
|
// 不允许出现 "POST/api/..." 等 method 前缀
|
|
25
|
-
if (/^(GET|POST|PUT|PATCH|DELETE|OPTIONS|HEAD)\b/i.test(
|
|
26
|
-
Logger.warn(Object.assign({}, omit(api, ["handler"]), { msg: "接口的
|
|
25
|
+
if (/^(GET|POST|PUT|PATCH|DELETE|OPTIONS|HEAD)\b/i.test(path)) {
|
|
26
|
+
Logger.warn(Object.assign({}, omit(api, ["handler"]), { msg: "接口的 path 不允许包含 method 前缀,应为 url.pathname(例如 /api/app/xxx)" }));
|
|
27
27
|
hasError = true;
|
|
28
28
|
}
|
|
29
|
-
if (!
|
|
30
|
-
Logger.warn(Object.assign({}, omit(api, ["handler"]), { msg: "接口的
|
|
29
|
+
if (!path.startsWith("/api/")) {
|
|
30
|
+
Logger.warn(Object.assign({}, omit(api, ["handler"]), { msg: "接口的 path 必须以 /api/ 开头" }));
|
|
31
31
|
hasError = true;
|
|
32
32
|
}
|
|
33
|
-
if (
|
|
34
|
-
Logger.warn(Object.assign({}, omit(api, ["handler"]), { msg: "接口的
|
|
33
|
+
if (path.includes(" ")) {
|
|
34
|
+
Logger.warn(Object.assign({}, omit(api, ["handler"]), { msg: "接口的 path 不允许包含空格" }));
|
|
35
35
|
hasError = true;
|
|
36
36
|
}
|
|
37
|
-
if (
|
|
38
|
-
Logger.warn(Object.assign({}, omit(api, ["handler"]), { msg: "接口的
|
|
37
|
+
if (path.includes("/api//")) {
|
|
38
|
+
Logger.warn(Object.assign({}, omit(api, ["handler"]), { msg: "接口的 path 不允许出现 /api//(重复斜杠)" }));
|
|
39
39
|
hasError = true;
|
|
40
40
|
}
|
|
41
41
|
}
|
package/dist/index.js
CHANGED
|
@@ -48,16 +48,15 @@ export class Befly {
|
|
|
48
48
|
* 启动完整的生命周期流程
|
|
49
49
|
* @returns HTTP 服务器实例
|
|
50
50
|
*/
|
|
51
|
-
async start(env) {
|
|
51
|
+
async start(env = {}) {
|
|
52
52
|
try {
|
|
53
53
|
const serverStartTime = Bun.nanoseconds();
|
|
54
|
-
const runtimeEnv = env || {};
|
|
55
54
|
// 0. 加载配置
|
|
56
|
-
this.config = await loadBeflyConfig(
|
|
55
|
+
this.config = await loadBeflyConfig(env.NODE_ENV || "development");
|
|
57
56
|
// 将配置注入到 ctx,供插件/Hook/sync 等按需读取
|
|
58
57
|
this.context.config = this.config;
|
|
59
58
|
// 给插件/Hook/sync 一个统一读取 env 的入口(只从 start 入参注入)
|
|
60
|
-
this.context.env =
|
|
59
|
+
this.context.env = env;
|
|
61
60
|
const { apis, tables, plugins, hooks, addons } = await scanSources();
|
|
62
61
|
// 让后续 syncMenu 能拿到 addon 的 views 路径等信息
|
|
63
62
|
this.context.addons = addons;
|
|
@@ -131,7 +130,7 @@ export class Befly {
|
|
|
131
130
|
}
|
|
132
131
|
});
|
|
133
132
|
const finalStartupTime = calcPerfTime(serverStartTime);
|
|
134
|
-
const processRole = getProcessRole(
|
|
133
|
+
const processRole = getProcessRole(env);
|
|
135
134
|
const roleLabel = processRole.role === "primary" ? "主进程" : `工作进程 #${processRole.instanceId}`;
|
|
136
135
|
const envLabel = processRole.env === "standalone" ? "" : ` [${processRole.env}]`;
|
|
137
136
|
Logger.info(`${this.config.appName} 启动成功! (${roleLabel}${envLabel})`);
|
package/dist/loader/loadApis.js
CHANGED
|
@@ -12,17 +12,16 @@ import { processAtSymbol } from "../utils/processAtSymbol";
|
|
|
12
12
|
export async function loadApis(apis) {
|
|
13
13
|
const apisMap = new Map();
|
|
14
14
|
for (const api of apis) {
|
|
15
|
-
const apiType = api.type;
|
|
16
15
|
// 兼容:scanFiles 的结果或测试构造数据可能缺少 type 字段;缺少时默认按 API 处理。
|
|
17
16
|
// 仅在 type 显式存在且不等于 "api" 时跳过,避免错误过滤。
|
|
18
|
-
if (
|
|
17
|
+
if (api.type !== "api") {
|
|
19
18
|
continue;
|
|
20
19
|
}
|
|
21
20
|
try {
|
|
22
21
|
const apiRoute = api;
|
|
23
22
|
// 处理字段定义,将 @ 引用替换为实际字段定义
|
|
24
|
-
apiRoute.fields = processAtSymbol(apiRoute.fields || {}, apiRoute.name, apiRoute.
|
|
25
|
-
apisMap.set(apiRoute.
|
|
23
|
+
apiRoute.fields = processAtSymbol(apiRoute.fields || {}, apiRoute.name, apiRoute.path);
|
|
24
|
+
apisMap.set(apiRoute.path, apiRoute);
|
|
26
25
|
}
|
|
27
26
|
catch (error) {
|
|
28
27
|
Logger.error({ err: error, api: api.relativePath, file: api.filePath, msg: "接口加载失败" });
|
package/dist/router/api.js
CHANGED
|
@@ -21,7 +21,7 @@ export function apiHandler(apis, hooks, context) {
|
|
|
21
21
|
// 2. 创建请求上下文
|
|
22
22
|
const url = new URL(req.url);
|
|
23
23
|
// 只用接口路径做存在性判断与匹配:不要把 method 拼进 key
|
|
24
|
-
// 说明:apisMap 的 key 来源于 scanFiles/loadApis 生成的
|
|
24
|
+
// 说明:apisMap 的 key 来源于 scanFiles/loadApis 生成的 path(例如 /api/core/xxx)
|
|
25
25
|
const apiPath = url.pathname || "/";
|
|
26
26
|
const clientIp = getClientIp(req, server);
|
|
27
27
|
const now = Date.now();
|
package/dist/sync/syncApi.js
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
import { Logger } from "../lib/logger";
|
|
2
2
|
import { keyBy } from "../utils/util";
|
|
3
|
+
const getApiParentPath = (apiPath) => {
|
|
4
|
+
const segments = apiPath
|
|
5
|
+
.split("/")
|
|
6
|
+
.map((s) => s.trim())
|
|
7
|
+
.filter((s) => s.length > 0);
|
|
8
|
+
// segments 示例:
|
|
9
|
+
// - /api/addon/admin/sysConfig/list -> ["api","addon","admin","sysConfig","list"]
|
|
10
|
+
// - /api/app/test/hi -> ["api","app","test","hi"]
|
|
11
|
+
const seg2 = segments[1] || "";
|
|
12
|
+
const take = seg2 === "addon" ? 4 : 3;
|
|
13
|
+
const parentSegments = segments.slice(0, Math.min(take, segments.length));
|
|
14
|
+
if (parentSegments.length === 0)
|
|
15
|
+
return "";
|
|
16
|
+
return `/${parentSegments.join("/")}`;
|
|
17
|
+
};
|
|
3
18
|
export async function syncApi(ctx, apis) {
|
|
4
19
|
const tableName = "addon_admin_api";
|
|
5
20
|
if (!ctx.db) {
|
|
@@ -14,61 +29,68 @@ export async function syncApi(ctx, apis) {
|
|
|
14
29
|
}
|
|
15
30
|
const allDbApis = await ctx.db.getAll({
|
|
16
31
|
table: tableName,
|
|
17
|
-
fields: ["id", "
|
|
32
|
+
fields: ["id", "path", "parentPath", "name", "addonName", "auth", "state"],
|
|
18
33
|
where: { state$gte: 0 }
|
|
19
34
|
});
|
|
20
35
|
const dbLists = allDbApis.data.lists || [];
|
|
21
|
-
const allDbApiMap = keyBy(dbLists, (item) => item.
|
|
36
|
+
const allDbApiMap = keyBy(dbLists, (item) => item.path);
|
|
22
37
|
const insData = [];
|
|
23
38
|
const updData = [];
|
|
24
39
|
const delData = [];
|
|
25
|
-
// 1) 先构建当前扫描到的
|
|
40
|
+
// 1) 先构建当前扫描到的 path 集合(用于删除差集)
|
|
26
41
|
const apiRouteKeys = new Set();
|
|
27
|
-
// 2) 插入 / 更新(存在不一定更新:仅当 name/
|
|
42
|
+
// 2) 插入 / 更新(存在不一定更新:仅当 name/path/addonName/auth 任一不匹配时更新)
|
|
28
43
|
for (const api of apis) {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
// 因此仅当 type **显式存在** 且不为 "api" 时才跳过,避免误把真实 API 条目过滤掉。
|
|
32
|
-
if (apiType && apiType !== "api") {
|
|
44
|
+
// 仅当 type **显式存在** 且不为 "api" 时才跳过,避免误把真实 API 条目过滤掉。
|
|
45
|
+
if (api.type !== "api") {
|
|
33
46
|
continue;
|
|
34
47
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
};
|
|
42
|
-
const routePath = normalizedApi.routePath;
|
|
43
|
-
apiRouteKeys.add(routePath);
|
|
44
|
-
const item = allDbApiMap[routePath];
|
|
48
|
+
// auth:运行时 API 定义使用 boolean;DB 字段使用 0/1。
|
|
49
|
+
// 统一在 syncApi 写库前做归一化,避免类型不一致导致每次启动都触发更新。
|
|
50
|
+
const auth = api.auth === false || api.auth === 0 ? 0 : 1;
|
|
51
|
+
const parentPath = getApiParentPath(api.path);
|
|
52
|
+
apiRouteKeys.add(api.path);
|
|
53
|
+
const item = allDbApiMap[api.path];
|
|
45
54
|
if (item) {
|
|
46
|
-
const
|
|
47
|
-
const shouldUpdate = normalizedApi.name !== item.name || normalizedApi.routePath !== item.routePath || normalizedApi.addonName !== item.addonName || normalizedAuth !== dbAuth;
|
|
55
|
+
const shouldUpdate = api.name !== item.name || api.path !== item.path || api.addonName !== item.addonName || parentPath !== item.parentPath || auth !== item.auth;
|
|
48
56
|
if (shouldUpdate) {
|
|
49
|
-
updData.push({
|
|
57
|
+
updData.push({
|
|
58
|
+
id: item.id,
|
|
59
|
+
name: api.name,
|
|
60
|
+
path: api.path,
|
|
61
|
+
parentPath: parentPath,
|
|
62
|
+
addonName: api.addonName,
|
|
63
|
+
auth: auth
|
|
64
|
+
});
|
|
50
65
|
}
|
|
51
66
|
}
|
|
52
67
|
else {
|
|
53
|
-
insData.push(
|
|
68
|
+
insData.push({
|
|
69
|
+
name: api.name,
|
|
70
|
+
path: api.path,
|
|
71
|
+
parentPath: parentPath,
|
|
72
|
+
addonName: api.addonName,
|
|
73
|
+
auth: auth
|
|
74
|
+
});
|
|
54
75
|
}
|
|
55
76
|
}
|
|
56
77
|
// 3) 删除:用差集(DB - 当前扫描)得到要删除的 id
|
|
57
78
|
for (const record of dbLists) {
|
|
58
|
-
if (!apiRouteKeys.has(record.
|
|
79
|
+
if (!apiRouteKeys.has(record.path)) {
|
|
59
80
|
delData.push(record.id);
|
|
60
81
|
}
|
|
61
82
|
}
|
|
62
83
|
if (updData.length > 0) {
|
|
63
84
|
try {
|
|
64
|
-
await ctx.db.updBatch(tableName, updData.map((
|
|
85
|
+
await ctx.db.updBatch(tableName, updData.map((api) => {
|
|
65
86
|
return {
|
|
66
|
-
id:
|
|
87
|
+
id: api.id,
|
|
67
88
|
data: {
|
|
68
|
-
name:
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
89
|
+
name: api.name,
|
|
90
|
+
path: api.path,
|
|
91
|
+
parentPath: api.parentPath,
|
|
92
|
+
addonName: api.addonName,
|
|
93
|
+
auth: api.auth
|
|
72
94
|
}
|
|
73
95
|
};
|
|
74
96
|
}));
|
|
@@ -82,9 +104,10 @@ export async function syncApi(ctx, apis) {
|
|
|
82
104
|
await ctx.db.insBatch(tableName, insData.map((api) => {
|
|
83
105
|
return {
|
|
84
106
|
name: api.name,
|
|
85
|
-
|
|
107
|
+
path: api.path,
|
|
108
|
+
parentPath: api.parentPath,
|
|
86
109
|
addonName: api.addonName,
|
|
87
|
-
auth: api.auth
|
|
110
|
+
auth: api.auth
|
|
88
111
|
};
|
|
89
112
|
}));
|
|
90
113
|
}
|
package/dist/sync/syncDev.js
CHANGED
|
@@ -4,7 +4,6 @@ export async function syncDev(ctx, config = {}) {
|
|
|
4
4
|
if (!config.devPassword) {
|
|
5
5
|
return;
|
|
6
6
|
}
|
|
7
|
-
const devEmail = typeof config.devEmail === "string" && config.devEmail.length > 0 ? config.devEmail : "dev@qq.com";
|
|
8
7
|
if (!ctx.db) {
|
|
9
8
|
throw new Error("syncDev: ctx.db 未初始化(Db 插件未加载或注入失败)");
|
|
10
9
|
}
|
|
@@ -23,140 +22,132 @@ export async function syncDev(ctx, config = {}) {
|
|
|
23
22
|
Logger.debug(`addon_admin_menu 表不存在`);
|
|
24
23
|
return;
|
|
25
24
|
}
|
|
25
|
+
if (!(await ctx.db.tableExists("addon_admin_api")).data) {
|
|
26
|
+
Logger.debug(`addon_admin_api 表不存在`);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
26
29
|
const allMenus = await ctx.db.getAll({
|
|
27
30
|
table: "addon_admin_menu",
|
|
28
31
|
fields: ["path"],
|
|
29
32
|
where: { state$gte: 0 },
|
|
30
33
|
orderBy: ["id#ASC"]
|
|
31
34
|
});
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
35
|
+
const allApis = await ctx.db.getAll({
|
|
36
|
+
table: "addon_admin_api",
|
|
37
|
+
fields: ["path"],
|
|
38
|
+
where: { state$gte: 0 },
|
|
39
|
+
orderBy: ["id#ASC"]
|
|
40
|
+
});
|
|
41
|
+
const devRole = await ctx.db.getOne({
|
|
42
|
+
table: "addon_admin_role",
|
|
43
|
+
where: { code: "dev" }
|
|
44
|
+
});
|
|
45
|
+
const devRoleData = {
|
|
46
|
+
code: "dev",
|
|
47
|
+
name: "开发者角色",
|
|
48
|
+
description: "拥有所有菜单和接口权限的开发者角色",
|
|
49
|
+
menus: allMenus.data.lists.map((item) => item.path).filter((v) => v),
|
|
50
|
+
apis: allApis.data.lists.map((item) => item.path).filter((v) => v),
|
|
51
|
+
sort: 0
|
|
52
|
+
};
|
|
53
|
+
if (devRole.data) {
|
|
54
|
+
await ctx.db.updData({
|
|
55
|
+
table: "addon_admin_role",
|
|
56
|
+
where: { code: "dev" },
|
|
57
|
+
data: {
|
|
58
|
+
name: devRoleData.name,
|
|
59
|
+
description: devRoleData.description,
|
|
60
|
+
menus: devRoleData.menus,
|
|
61
|
+
apis: devRoleData.apis,
|
|
62
|
+
sort: devRoleData.sort
|
|
49
63
|
}
|
|
50
|
-
|
|
51
|
-
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
await ctx.db.insData({
|
|
68
|
+
table: "addon_admin_role",
|
|
69
|
+
data: devRoleData
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
const devAdminData = {
|
|
73
|
+
nickname: "开发者",
|
|
74
|
+
email: config.devEmail || "dev@qq.com",
|
|
75
|
+
username: "dev",
|
|
76
|
+
password: await Cipher.hashPassword(Cipher.sha256(config.devPassword + "befly")),
|
|
77
|
+
roleCode: "dev",
|
|
78
|
+
roleType: "admin"
|
|
79
|
+
};
|
|
80
|
+
const devAdmin = await ctx.db.getOne({
|
|
81
|
+
table: "addon_admin_admin",
|
|
82
|
+
where: { username: "dev" }
|
|
83
|
+
});
|
|
84
|
+
if (devAdmin.data) {
|
|
85
|
+
await ctx.db.updData({
|
|
86
|
+
table: "addon_admin_admin",
|
|
87
|
+
where: { username: "dev" },
|
|
88
|
+
data: {
|
|
89
|
+
nickname: devAdminData.nickname,
|
|
90
|
+
email: devAdminData.email,
|
|
91
|
+
username: devAdminData.username,
|
|
92
|
+
password: devAdminData.password,
|
|
93
|
+
roleCode: devAdminData.roleCode,
|
|
94
|
+
roleType: devAdminData.roleType
|
|
52
95
|
}
|
|
53
|
-
|
|
54
|
-
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
await ctx.db.insData({
|
|
100
|
+
table: "addon_admin_admin",
|
|
101
|
+
data: devAdminData
|
|
102
|
+
});
|
|
55
103
|
}
|
|
56
104
|
const roles = [
|
|
57
|
-
{
|
|
58
|
-
code: "dev",
|
|
59
|
-
name: "开发者角色",
|
|
60
|
-
description: "拥有所有菜单和接口权限的开发者角色",
|
|
61
|
-
menus: menuPaths,
|
|
62
|
-
apis: apiPaths,
|
|
63
|
-
sort: 0
|
|
64
|
-
},
|
|
65
105
|
{
|
|
66
106
|
code: "user",
|
|
67
107
|
name: "用户角色",
|
|
68
108
|
description: "普通用户角色",
|
|
69
|
-
menus: [],
|
|
70
|
-
apis: [],
|
|
71
109
|
sort: 1
|
|
72
110
|
},
|
|
73
111
|
{
|
|
74
112
|
code: "admin",
|
|
75
113
|
name: "管理员角色",
|
|
76
114
|
description: "管理员角色",
|
|
77
|
-
menus: [],
|
|
78
|
-
apis: [],
|
|
79
115
|
sort: 2
|
|
80
116
|
},
|
|
81
117
|
{
|
|
82
118
|
code: "guest",
|
|
83
119
|
name: "访客角色",
|
|
84
120
|
description: "访客角色",
|
|
85
|
-
menus: [],
|
|
86
|
-
apis: [],
|
|
87
121
|
sort: 3
|
|
88
122
|
}
|
|
89
123
|
];
|
|
90
|
-
let devRole = null;
|
|
91
124
|
for (const roleConfig of roles) {
|
|
92
125
|
const existingRole = await ctx.db.getOne({
|
|
93
126
|
table: "addon_admin_role",
|
|
94
127
|
where: { code: roleConfig.code }
|
|
95
128
|
});
|
|
96
|
-
if (existingRole.data) {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
where: { code: roleConfig.code },
|
|
108
|
-
data: {
|
|
109
|
-
name: roleConfig.name,
|
|
110
|
-
description: roleConfig.description,
|
|
111
|
-
menus: roleConfig.menus,
|
|
112
|
-
apis: roleConfig.apis,
|
|
113
|
-
sort: roleConfig.sort
|
|
114
|
-
}
|
|
115
|
-
});
|
|
116
|
-
}
|
|
117
|
-
if (roleConfig.code === "dev") {
|
|
118
|
-
devRole = existingRole.data;
|
|
119
|
-
}
|
|
129
|
+
if (existingRole.data?.id) {
|
|
130
|
+
// 角色存在则强制更新(不做差异判断)
|
|
131
|
+
await ctx.db.updData({
|
|
132
|
+
table: "addon_admin_role",
|
|
133
|
+
where: { code: roleConfig.code },
|
|
134
|
+
data: {
|
|
135
|
+
name: roleConfig.name,
|
|
136
|
+
description: roleConfig.description,
|
|
137
|
+
sort: roleConfig.sort
|
|
138
|
+
}
|
|
139
|
+
});
|
|
120
140
|
}
|
|
121
141
|
else {
|
|
122
|
-
|
|
142
|
+
await ctx.db.insData({
|
|
123
143
|
table: "addon_admin_role",
|
|
124
|
-
data:
|
|
144
|
+
data: {
|
|
145
|
+
code: roleConfig.code,
|
|
146
|
+
name: roleConfig.name,
|
|
147
|
+
description: roleConfig.description,
|
|
148
|
+
sort: roleConfig.sort
|
|
149
|
+
}
|
|
125
150
|
});
|
|
126
|
-
if (roleConfig.code === "dev") {
|
|
127
|
-
devRole = { id: roleId.data };
|
|
128
|
-
}
|
|
129
151
|
}
|
|
130
152
|
}
|
|
131
|
-
if (!devRole) {
|
|
132
|
-
Logger.error("dev 角色不存在,无法创建开发者账号");
|
|
133
|
-
return;
|
|
134
|
-
}
|
|
135
|
-
const sha256Hashed = Cipher.sha256(config.devPassword + "befly");
|
|
136
|
-
const hashed = await Cipher.hashPassword(sha256Hashed);
|
|
137
|
-
const devData = {
|
|
138
|
-
nickname: "开发者",
|
|
139
|
-
email: devEmail,
|
|
140
|
-
username: "dev",
|
|
141
|
-
password: hashed,
|
|
142
|
-
roleCode: "dev",
|
|
143
|
-
roleType: "admin"
|
|
144
|
-
};
|
|
145
|
-
const existing = await ctx.db.getOne({
|
|
146
|
-
table: "addon_admin_admin",
|
|
147
|
-
where: { email: devEmail }
|
|
148
|
-
});
|
|
149
|
-
if (existing.data) {
|
|
150
|
-
await ctx.db.updData({
|
|
151
|
-
table: "addon_admin_admin",
|
|
152
|
-
where: { email: devEmail },
|
|
153
|
-
data: devData
|
|
154
|
-
});
|
|
155
|
-
}
|
|
156
|
-
else {
|
|
157
|
-
await ctx.db.insData({
|
|
158
|
-
table: "addon_admin_admin",
|
|
159
|
-
data: devData
|
|
160
|
-
});
|
|
161
|
-
}
|
|
162
153
|
}
|
package/dist/types/sync.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 处理字段定义:将 @ 符号引用替换为实际字段定义
|
|
3
3
|
*/
|
|
4
|
-
export declare function processAtSymbol(fields: Record<string, any>, apiName: string,
|
|
4
|
+
export declare function processAtSymbol(fields: Record<string, any>, apiName: string, path: string): Record<string, any>;
|
|
@@ -2,7 +2,7 @@ import { presetFields } from "../configs/presetFields";
|
|
|
2
2
|
/**
|
|
3
3
|
* 处理字段定义:将 @ 符号引用替换为实际字段定义
|
|
4
4
|
*/
|
|
5
|
-
export function processAtSymbol(fields, apiName,
|
|
5
|
+
export function processAtSymbol(fields, apiName, path) {
|
|
6
6
|
if (!fields || typeof fields !== "object")
|
|
7
7
|
return fields;
|
|
8
8
|
const processed = {};
|
|
@@ -13,7 +13,7 @@ export function processAtSymbol(fields, apiName, routePath) {
|
|
|
13
13
|
continue;
|
|
14
14
|
}
|
|
15
15
|
const validKeys = Object.keys(presetFields).join(", ");
|
|
16
|
-
throw new Error(`API [${apiName}] (${
|
|
16
|
+
throw new Error(`API [${apiName}] (${path}) 字段 [${key}] 引用了未定义的预设字段 "${value}"。可用的预设字段有: ${validKeys}`);
|
|
17
17
|
}
|
|
18
18
|
processed[key] = value;
|
|
19
19
|
}
|
package/dist/utils/scanFiles.js
CHANGED
|
@@ -102,6 +102,10 @@ export async function scanFiles(dir, source, type, pattern) {
|
|
|
102
102
|
continue;
|
|
103
103
|
}
|
|
104
104
|
if (type === "api") {
|
|
105
|
+
// 运行时 auth 必须是 boolean:
|
|
106
|
+
// - checkApi 会校验 auth 类型
|
|
107
|
+
// - permission hook 以 ctx.api.auth === false 判断公开接口
|
|
108
|
+
// DB 存储的 0/1 由 syncApi 负责转换写入。
|
|
105
109
|
base.auth = true;
|
|
106
110
|
base.rawBody = false;
|
|
107
111
|
base.method = "POST";
|
|
@@ -118,7 +122,7 @@ export async function scanFiles(dir, source, type, pattern) {
|
|
|
118
122
|
});
|
|
119
123
|
if (type === "api") {
|
|
120
124
|
base.routePrefix = source === "app" ? "/app" : `/addon/${addonName}`;
|
|
121
|
-
base.
|
|
125
|
+
base.path = `/api${base.routePrefix}/${relativePath}`;
|
|
122
126
|
}
|
|
123
127
|
results.push(base);
|
|
124
128
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "befly",
|
|
3
|
-
"version": "3.
|
|
4
|
-
"gitHead": "
|
|
3
|
+
"version": "3.14.0",
|
|
4
|
+
"gitHead": "0d60e323a83a1fc53822147de877af19cdb972c0",
|
|
5
5
|
"private": false,
|
|
6
6
|
"description": "Befly - 为 Bun 专属打造的 TypeScript API 接口框架核心引擎",
|
|
7
7
|
"keywords": [
|