befly 3.9.40 → 3.10.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/README.md +47 -19
- package/befly.config.ts +19 -2
- package/checks/checkApi.ts +79 -77
- package/checks/checkHook.ts +48 -0
- package/checks/checkMenu.ts +168 -0
- package/checks/checkPlugin.ts +48 -0
- package/checks/checkTable.ts +137 -183
- package/docs/README.md +17 -11
- package/docs/api/api.md +16 -2
- package/docs/guide/quickstart.md +31 -10
- package/docs/hooks/hook.md +2 -2
- package/docs/hooks/rateLimit.md +1 -1
- package/docs/infra/redis.md +26 -14
- package/docs/plugins/plugin.md +23 -21
- package/docs/quickstart.md +5 -328
- package/docs/reference/addon.md +0 -4
- package/docs/reference/config.md +14 -31
- package/docs/reference/logger.md +3 -3
- package/docs/reference/sync.md +132 -237
- package/docs/reference/table.md +28 -30
- package/hooks/auth.ts +3 -4
- package/hooks/cors.ts +4 -6
- package/hooks/parser.ts +3 -4
- package/hooks/permission.ts +3 -4
- package/hooks/validator.ts +3 -4
- package/lib/cacheHelper.ts +89 -153
- package/lib/cacheKeys.ts +1 -1
- package/lib/connect.ts +9 -13
- package/lib/dbDialect.ts +285 -0
- package/lib/dbHelper.ts +179 -507
- package/lib/dbUtils.ts +450 -0
- package/lib/logger.ts +41 -5
- package/lib/redisHelper.ts +1 -0
- package/lib/sqlBuilder.ts +358 -58
- package/lib/sqlCheck.ts +136 -0
- package/lib/validator.ts +1 -1
- package/loader/loadApis.ts +23 -126
- package/loader/loadHooks.ts +31 -46
- package/loader/loadPlugins.ts +37 -52
- package/main.ts +58 -19
- package/package.json +24 -25
- package/paths.ts +14 -14
- package/plugins/cache.ts +12 -6
- package/plugins/cipher.ts +2 -2
- package/plugins/config.ts +6 -8
- package/plugins/db.ts +14 -19
- package/plugins/jwt.ts +6 -7
- package/plugins/logger.ts +7 -9
- package/plugins/redis.ts +8 -10
- package/plugins/tool.ts +3 -4
- package/router/api.ts +3 -2
- package/router/static.ts +7 -5
- package/sync/syncApi.ts +80 -235
- package/sync/syncCache.ts +16 -0
- package/sync/syncDev.ts +167 -202
- package/sync/syncMenu.ts +230 -444
- package/sync/syncTable.ts +1247 -0
- package/tests/_mocks/mockSqliteDb.ts +204 -0
- package/tests/addonHelper-cache.test.ts +32 -0
- package/tests/apiHandler-routePath-only.test.ts +32 -0
- package/tests/cacheHelper.test.ts +16 -51
- package/tests/checkApi-routePath-strict.test.ts +166 -0
- package/tests/checkMenu.test.ts +346 -0
- package/tests/checkTable-smoke.test.ts +157 -0
- package/tests/dbDialect-cache.test.ts +23 -0
- package/tests/dbDialect.test.ts +46 -0
- package/tests/dbHelper-advanced.test.ts +1 -1
- package/tests/dbHelper-all-array-types.test.ts +15 -15
- package/tests/dbHelper-batch-write.test.ts +90 -0
- package/tests/dbHelper-columns.test.ts +36 -54
- package/tests/dbHelper-execute.test.ts +26 -26
- package/tests/dbHelper-joins.test.ts +85 -176
- package/tests/fixtures/scanFilesAddon/node_modules/@befly-addon/demo/apis/sub/b.ts +3 -0
- package/tests/fixtures/scanFilesApis/a.ts +3 -0
- package/tests/fixtures/scanFilesApis/sub/b.ts +3 -0
- package/tests/loadPlugins-order-smoke.test.ts +75 -0
- package/tests/logger.test.ts +6 -6
- package/tests/redisHelper.test.ts +6 -1
- package/tests/scanFiles-routePath.test.ts +46 -0
- package/tests/smoke-sql.test.ts +24 -0
- package/tests/sqlBuilder-advanced.test.ts +18 -5
- package/tests/sqlBuilder.test.ts +24 -0
- package/tests/sync-init-guard.test.ts +105 -0
- package/tests/syncApi-insBatch-fields-consistent.test.ts +61 -0
- package/tests/syncApi-obsolete-records.test.ts +69 -0
- package/tests/syncApi-type-compat.test.ts +72 -0
- package/tests/syncDev-permissions.test.ts +81 -0
- package/tests/syncMenu-disableMenus-hard-delete.test.ts +88 -0
- package/tests/syncMenu-duplicate-path.test.ts +122 -0
- package/tests/syncMenu-obsolete-records.test.ts +161 -0
- package/tests/syncMenu-parentPath-from-tree.test.ts +75 -0
- package/tests/syncMenu-paths.test.ts +0 -9
- package/tests/{syncDb-apply.test.ts → syncTable-apply.test.ts} +14 -24
- package/tests/{syncDb-array-number.test.ts → syncTable-array-number.test.ts} +31 -31
- package/tests/syncTable-constants.test.ts +101 -0
- package/tests/syncTable-db-integration.test.ts +237 -0
- package/tests/{syncDb-ddl.test.ts → syncTable-ddl.test.ts} +67 -53
- package/tests/{syncDb-helpers.test.ts → syncTable-helpers.test.ts} +12 -26
- package/tests/syncTable-schema.test.ts +99 -0
- package/tests/syncTable-testkit.test.ts +25 -0
- package/tests/syncTable-types.test.ts +122 -0
- package/tests/tableRef-and-deserialize.test.ts +67 -0
- package/tsconfig.json +1 -1
- package/types/api.d.ts +1 -1
- package/types/befly.d.ts +13 -12
- package/types/cache.d.ts +2 -2
- package/types/context.d.ts +1 -1
- package/types/database.d.ts +0 -5
- package/types/hook.d.ts +1 -10
- package/types/plugin.d.ts +2 -96
- package/types/sync.d.ts +19 -25
- package/utils/convertBigIntFields.ts +38 -0
- package/utils/disableMenusGlob.ts +85 -0
- package/utils/importDefault.ts +21 -0
- package/utils/isDirentDirectory.ts +23 -0
- package/utils/loadMenuConfigs.ts +145 -0
- package/utils/processFields.ts +25 -0
- package/utils/scanAddons.ts +72 -0
- package/utils/scanFiles.ts +129 -21
- package/utils/scanSources.ts +64 -0
- package/utils/sortModules.ts +137 -0
- package/checks/checkApp.ts +0 -55
- package/docs/cipher.md +0 -582
- package/docs/database.md +0 -1176
- package/hooks/rateLimit.ts +0 -276
- package/sync/syncAll.ts +0 -35
- package/sync/syncDb/apply.ts +0 -192
- package/sync/syncDb/constants.ts +0 -119
- package/sync/syncDb/ddl.ts +0 -251
- package/sync/syncDb/helpers.ts +0 -84
- package/sync/syncDb/schema.ts +0 -202
- package/sync/syncDb/sqlite.ts +0 -48
- package/sync/syncDb/table.ts +0 -207
- package/sync/syncDb/tableCreate.ts +0 -163
- package/sync/syncDb/types.ts +0 -132
- package/sync/syncDb/version.ts +0 -69
- package/sync/syncDb.ts +0 -168
- package/tests/rateLimit-hook.test.ts +0 -477
- package/tests/syncDb-constants.test.ts +0 -130
- package/tests/syncDb-schema.test.ts +0 -179
- package/tests/syncDb-types.test.ts +0 -139
- package/utils/addonHelper.ts +0 -90
- package/utils/modules.ts +0 -98
- package/utils/route.ts +0 -23
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { camelCase } from "es-toolkit/string";
|
|
2
|
+
|
|
3
|
+
import { Logger } from "../lib/logger.js";
|
|
4
|
+
|
|
5
|
+
export type SortModulesByDepsOptions<T> = {
|
|
6
|
+
/**
|
|
7
|
+
* 用于日志的模块标签(如:"插件"、"钩子")
|
|
8
|
+
*/
|
|
9
|
+
moduleLabel?: string;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* 生成模块名(用于 deps 解析与排序 key)。
|
|
13
|
+
* 默认:camelCase(item.fileName)
|
|
14
|
+
*/
|
|
15
|
+
getName?: (item: T) => string;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* 获取 deps。
|
|
19
|
+
* 默认:item.deps
|
|
20
|
+
*/
|
|
21
|
+
getDeps?: (item: T) => string[];
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* 按 deps 拓扑排序 scanSources 扫描得到的插件/钩子。
|
|
26
|
+
*
|
|
27
|
+
* 说明:
|
|
28
|
+
* - 输入为 scanSources/scanFiles 的条目数组:每个条目包含 fileName 与 deps。
|
|
29
|
+
* - deps 里的字符串会与 getName(item) 的结果匹配。
|
|
30
|
+
* - 若出现:重复 name、缺失依赖、循环依赖,则返回 false。
|
|
31
|
+
*/
|
|
32
|
+
export function sortModules<T extends { fileName: string; deps?: any }>(items: T[], options: SortModulesByDepsOptions<T> = {}): T[] | false {
|
|
33
|
+
const moduleLabel = options.moduleLabel || "模块";
|
|
34
|
+
const getName =
|
|
35
|
+
options.getName ||
|
|
36
|
+
((item: T) => {
|
|
37
|
+
const moduleName = (item as any).moduleName;
|
|
38
|
+
if (typeof moduleName === "string" && moduleName.trim() !== "") {
|
|
39
|
+
return moduleName;
|
|
40
|
+
}
|
|
41
|
+
return camelCase(item.fileName);
|
|
42
|
+
});
|
|
43
|
+
const getDeps = options.getDeps || ((item: T) => (item as any).deps);
|
|
44
|
+
|
|
45
|
+
const result: T[] = [];
|
|
46
|
+
const visited = new Set<string>();
|
|
47
|
+
const visiting = new Set<string>();
|
|
48
|
+
|
|
49
|
+
const nameToItem: Record<string, T> = {};
|
|
50
|
+
let isPass = true;
|
|
51
|
+
|
|
52
|
+
// 1) 建表 + 重名检查
|
|
53
|
+
for (const item of items) {
|
|
54
|
+
const name = getName(item);
|
|
55
|
+
|
|
56
|
+
if (typeof name !== "string" || name.trim() === "") {
|
|
57
|
+
Logger.error({ item: item }, `${moduleLabel} 名称解析失败(getName 返回空字符串)`);
|
|
58
|
+
isPass = false;
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (nameToItem[name]) {
|
|
63
|
+
Logger.error(
|
|
64
|
+
{
|
|
65
|
+
name: name,
|
|
66
|
+
first: nameToItem[name],
|
|
67
|
+
second: item
|
|
68
|
+
},
|
|
69
|
+
`${moduleLabel} 名称重复,无法根据 deps 唯一定位`
|
|
70
|
+
);
|
|
71
|
+
isPass = false;
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
nameToItem[name] = item;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (!isPass) return false;
|
|
79
|
+
|
|
80
|
+
// 2) 依赖存在性检查 + deps 类型检查
|
|
81
|
+
for (const item of items) {
|
|
82
|
+
const name = getName(item);
|
|
83
|
+
const deps = getDeps(item);
|
|
84
|
+
|
|
85
|
+
if (!Array.isArray(deps)) {
|
|
86
|
+
Logger.error({ module: name, item: item }, `${moduleLabel} 的 deps 必须是数组`);
|
|
87
|
+
isPass = false;
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
for (const dep of deps) {
|
|
92
|
+
if (typeof dep !== "string") {
|
|
93
|
+
Logger.error({ module: name, dependency: dep, item: item }, `${moduleLabel} 的 deps 必须是字符串数组`);
|
|
94
|
+
isPass = false;
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (!nameToItem[dep]) {
|
|
99
|
+
Logger.error({ module: name, dependency: dep }, `${moduleLabel} 依赖未找到`);
|
|
100
|
+
isPass = false;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (!isPass) return false;
|
|
106
|
+
|
|
107
|
+
// 3) 拓扑排序(DFS)
|
|
108
|
+
const visit = (name: string): void => {
|
|
109
|
+
if (visited.has(name)) return;
|
|
110
|
+
if (visiting.has(name)) {
|
|
111
|
+
Logger.error({ module: name }, `${moduleLabel} 循环依赖`);
|
|
112
|
+
isPass = false;
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const item = nameToItem[name];
|
|
117
|
+
if (!item) return;
|
|
118
|
+
|
|
119
|
+
const deps = getDeps(item) as string[];
|
|
120
|
+
|
|
121
|
+
visiting.add(name);
|
|
122
|
+
for (const dep of deps) {
|
|
123
|
+
visit(dep);
|
|
124
|
+
}
|
|
125
|
+
visiting.delete(name);
|
|
126
|
+
|
|
127
|
+
visited.add(name);
|
|
128
|
+
result.push(item);
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
for (const item of items) {
|
|
132
|
+
const name = getName(item);
|
|
133
|
+
visit(name);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return isPass ? result : false;
|
|
137
|
+
}
|
package/checks/checkApp.ts
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
2
|
-
// 内部依赖
|
|
3
|
-
import { join } from "node:path";
|
|
4
|
-
|
|
5
|
-
// 相对导入
|
|
6
|
-
import { Logger } from "../lib/logger.js";
|
|
7
|
-
import { projectApiDir, projectDir } from "../paths.js";
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* 检查项目结构
|
|
11
|
-
*/
|
|
12
|
-
export async function checkApp(): Promise<void> {
|
|
13
|
-
try {
|
|
14
|
-
// 检查项目 apis 目录下是否存在名为 addon 的目录
|
|
15
|
-
if (existsSync(projectApiDir)) {
|
|
16
|
-
const addonDir = join(projectApiDir, "addon");
|
|
17
|
-
if (existsSync(addonDir)) {
|
|
18
|
-
throw new Error("项目 apis 目录下不能存在名为 addon 的目录,addon 是保留名称,用于组件接口路由");
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
// 检查并创建 logs 目录
|
|
23
|
-
const logsDir = join(projectDir, "logs");
|
|
24
|
-
if (!existsSync(logsDir)) {
|
|
25
|
-
mkdirSync(logsDir, { recursive: true });
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
// 检查并创建 configs 目录和配置文件
|
|
29
|
-
const configsDir = join(projectDir, "configs");
|
|
30
|
-
if (!existsSync(configsDir)) {
|
|
31
|
-
mkdirSync(configsDir, { recursive: true });
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// 检查并创建 befly.common.json
|
|
35
|
-
const beflyJsonPath = join(configsDir, "befly.common.json");
|
|
36
|
-
if (!existsSync(beflyJsonPath)) {
|
|
37
|
-
writeFileSync(beflyJsonPath, "{}", "utf-8");
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// 检查并创建 befly.development.json
|
|
41
|
-
const beflyDevelopmentJsonPath = join(configsDir, "befly.development.json");
|
|
42
|
-
if (!existsSync(beflyDevelopmentJsonPath)) {
|
|
43
|
-
writeFileSync(beflyDevelopmentJsonPath, "{}", "utf-8");
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// 检查并创建 befly.production.json
|
|
47
|
-
const beflyProductionJsonPath = join(configsDir, "befly.production.json");
|
|
48
|
-
if (!existsSync(beflyProductionJsonPath)) {
|
|
49
|
-
writeFileSync(beflyProductionJsonPath, "{}", "utf-8");
|
|
50
|
-
}
|
|
51
|
-
} catch (error: any) {
|
|
52
|
-
Logger.error("项目结构检查过程中出错", error);
|
|
53
|
-
throw error;
|
|
54
|
-
}
|
|
55
|
-
}
|