befly 3.9.38 → 3.9.39
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 +37 -38
- package/befly.config.ts +62 -40
- package/checks/checkApi.ts +16 -16
- package/checks/checkApp.ts +19 -25
- package/checks/checkTable.ts +42 -42
- package/docs/README.md +42 -35
- package/docs/{api.md → api/api.md} +223 -231
- package/docs/cipher.md +71 -69
- package/docs/database.md +143 -141
- package/docs/{examples.md → guide/examples.md} +181 -181
- package/docs/guide/quickstart.md +331 -0
- package/docs/hooks/auth.md +38 -0
- package/docs/hooks/cors.md +28 -0
- package/docs/{hook.md → hooks/hook.md} +140 -57
- package/docs/hooks/parser.md +19 -0
- package/docs/hooks/rateLimit.md +47 -0
- package/docs/{redis.md → infra/redis.md} +84 -93
- package/docs/plugins/cipher.md +61 -0
- package/docs/plugins/database.md +128 -0
- package/docs/{plugin.md → plugins/plugin.md} +83 -81
- package/docs/quickstart.md +26 -26
- package/docs/{addon.md → reference/addon.md} +46 -46
- package/docs/{config.md → reference/config.md} +32 -80
- package/docs/{logger.md → reference/logger.md} +52 -52
- package/docs/{sync.md → reference/sync.md} +32 -35
- package/docs/{table.md → reference/table.md} +1 -1
- package/docs/{validator.md → reference/validator.md} +57 -57
- package/hooks/auth.ts +8 -4
- package/hooks/cors.ts +13 -13
- package/hooks/parser.ts +37 -17
- package/hooks/permission.ts +26 -14
- package/hooks/rateLimit.ts +276 -0
- package/hooks/validator.ts +7 -7
- package/lib/asyncContext.ts +43 -0
- package/lib/cacheHelper.ts +212 -77
- package/lib/cacheKeys.ts +38 -0
- package/lib/cipher.ts +30 -30
- package/lib/connect.ts +28 -28
- package/lib/dbHelper.ts +183 -102
- package/lib/jwt.ts +16 -16
- package/lib/logger.ts +610 -19
- package/lib/redisHelper.ts +185 -44
- package/lib/sqlBuilder.ts +90 -91
- package/lib/validator.ts +59 -39
- package/loader/loadApis.ts +48 -44
- package/loader/loadHooks.ts +40 -14
- package/loader/loadPlugins.ts +16 -17
- package/main.ts +57 -47
- package/package.json +47 -45
- package/paths.ts +15 -14
- package/plugins/cache.ts +5 -4
- package/plugins/cipher.ts +3 -3
- package/plugins/config.ts +2 -2
- package/plugins/db.ts +9 -9
- package/plugins/jwt.ts +3 -3
- package/plugins/logger.ts +8 -12
- package/plugins/redis.ts +8 -8
- package/plugins/tool.ts +6 -6
- package/router/api.ts +85 -56
- package/router/static.ts +12 -12
- package/sync/syncAll.ts +12 -12
- package/sync/syncApi.ts +55 -52
- package/sync/syncDb/apply.ts +20 -19
- package/sync/syncDb/constants.ts +25 -23
- package/sync/syncDb/ddl.ts +35 -36
- package/sync/syncDb/helpers.ts +6 -9
- package/sync/syncDb/schema.ts +10 -9
- package/sync/syncDb/sqlite.ts +7 -8
- package/sync/syncDb/table.ts +37 -35
- package/sync/syncDb/tableCreate.ts +21 -20
- package/sync/syncDb/types.ts +23 -20
- package/sync/syncDb/version.ts +10 -10
- package/sync/syncDb.ts +43 -36
- package/sync/syncDev.ts +74 -65
- package/sync/syncMenu.ts +190 -55
- package/tests/api-integration-array-number.test.ts +282 -0
- package/tests/befly-config-env.test.ts +78 -0
- package/tests/cacheHelper.test.ts +135 -104
- package/tests/cacheKeys.test.ts +41 -0
- package/tests/cipher.test.ts +90 -89
- package/tests/dbHelper-advanced.test.ts +140 -134
- package/tests/dbHelper-all-array-types.test.ts +316 -0
- package/tests/dbHelper-array-serialization.test.ts +258 -0
- package/tests/dbHelper-columns.test.ts +56 -55
- package/tests/dbHelper-execute.test.ts +45 -44
- package/tests/dbHelper-joins.test.ts +124 -119
- package/tests/fields-redis-cache.test.ts +29 -27
- package/tests/fields-validate.test.ts +38 -38
- package/tests/getClientIp.test.ts +54 -0
- package/tests/integration.test.ts +69 -67
- package/tests/jwt.test.ts +27 -26
- package/tests/logger.test.ts +267 -34
- package/tests/rateLimit-hook.test.ts +477 -0
- package/tests/redisHelper.test.ts +187 -188
- package/tests/redisKeys.test.ts +6 -73
- package/tests/scanConfig.test.ts +144 -0
- package/tests/sqlBuilder-advanced.test.ts +217 -215
- package/tests/sqlBuilder.test.ts +92 -91
- package/tests/sync-connection.test.ts +29 -29
- package/tests/syncDb-apply.test.ts +97 -96
- package/tests/syncDb-array-number.test.ts +160 -0
- package/tests/syncDb-constants.test.ts +48 -47
- package/tests/syncDb-ddl.test.ts +99 -98
- package/tests/syncDb-helpers.test.ts +29 -28
- package/tests/syncDb-schema.test.ts +61 -60
- package/tests/syncDb-types.test.ts +60 -59
- package/tests/syncMenu-paths.test.ts +68 -0
- package/tests/util.test.ts +42 -41
- package/tests/validator-array-number.test.ts +310 -0
- package/tests/validator-default.test.ts +373 -0
- package/tests/validator.test.ts +271 -266
- package/tsconfig.json +4 -5
- package/types/api.d.ts +7 -12
- package/types/befly.d.ts +60 -13
- package/types/cache.d.ts +8 -4
- package/types/common.d.ts +17 -9
- package/types/context.d.ts +2 -2
- package/types/crypto.d.ts +23 -0
- package/types/database.d.ts +19 -19
- package/types/hook.d.ts +2 -2
- package/types/jwt.d.ts +118 -0
- package/types/logger.d.ts +30 -0
- package/types/plugin.d.ts +4 -4
- package/types/redis.d.ts +7 -3
- package/types/roleApisCache.ts +23 -0
- package/types/sync.d.ts +10 -10
- package/types/table.d.ts +50 -9
- package/types/validate.d.ts +69 -0
- package/utils/addonHelper.ts +90 -0
- package/utils/arrayKeysToCamel.ts +18 -0
- package/utils/calcPerfTime.ts +13 -0
- package/utils/configTypes.ts +3 -0
- package/utils/cors.ts +19 -0
- package/utils/fieldClear.ts +75 -0
- package/utils/genShortId.ts +12 -0
- package/utils/getClientIp.ts +45 -0
- package/utils/keysToCamel.ts +22 -0
- package/utils/keysToSnake.ts +22 -0
- package/utils/modules.ts +98 -0
- package/utils/pickFields.ts +19 -0
- package/utils/process.ts +56 -0
- package/utils/regex.ts +225 -0
- package/utils/response.ts +115 -0
- package/utils/route.ts +23 -0
- package/utils/scanConfig.ts +142 -0
- package/utils/scanFiles.ts +48 -0
- package/.prettierignore +0 -2
- package/.prettierrc +0 -12
- package/docs/1-/345/237/272/346/234/254/344/273/213/347/273/215.md +0 -35
- package/docs/2-/345/210/235/346/255/245/344/275/223/351/252/214.md +0 -64
- package/docs/3-/347/254/254/344/270/200/344/270/252/346/216/245/345/217/243.md +0 -46
- package/docs/4-/346/223/215/344/275/234/346/225/260/346/215/256/345/272/223.md +0 -172
- package/hooks/requestLogger.ts +0 -84
- package/types/index.ts +0 -24
- package/util.ts +0 -283
package/README.md
CHANGED
|
@@ -37,10 +37,10 @@ bunx befly init
|
|
|
37
37
|
|
|
38
38
|
```typescript
|
|
39
39
|
// main.ts
|
|
40
|
-
import { Befly } from
|
|
40
|
+
import { Befly } from "befly";
|
|
41
41
|
|
|
42
42
|
const app = new Befly({
|
|
43
|
-
appName:
|
|
43
|
+
appName: "My API",
|
|
44
44
|
appPort: 3000
|
|
45
45
|
});
|
|
46
46
|
|
|
@@ -57,15 +57,15 @@ bun run main.ts
|
|
|
57
57
|
|
|
58
58
|
```typescript
|
|
59
59
|
// apis/user/hello.ts
|
|
60
|
-
import type { ApiRoute } from
|
|
60
|
+
import type { ApiRoute } from "befly/types/api";
|
|
61
61
|
|
|
62
62
|
export default {
|
|
63
|
-
name:
|
|
63
|
+
name: "问候接口",
|
|
64
64
|
auth: false, // 公开接口
|
|
65
65
|
fields: {},
|
|
66
66
|
handler: async (befly, ctx) => {
|
|
67
67
|
return {
|
|
68
|
-
msg:
|
|
68
|
+
msg: "Hello, Befly!",
|
|
69
69
|
data: {
|
|
70
70
|
timestamp: Date.now()
|
|
71
71
|
}
|
|
@@ -81,26 +81,27 @@ export default {
|
|
|
81
81
|
### TypeScript 全面支持
|
|
82
82
|
|
|
83
83
|
```typescript
|
|
84
|
-
import type { ApiRoute
|
|
85
|
-
import type {
|
|
84
|
+
import type { ApiRoute } from "befly/types/api";
|
|
85
|
+
import type { BeflyContext } from "befly/types/befly";
|
|
86
|
+
import type { User } from "./types/models";
|
|
86
87
|
|
|
87
88
|
export default {
|
|
88
|
-
name:
|
|
89
|
+
name: "获取用户",
|
|
89
90
|
auth: true,
|
|
90
91
|
fields: {
|
|
91
|
-
id:
|
|
92
|
+
id: "用户ID|number|1|999999|null|1|null"
|
|
92
93
|
},
|
|
93
|
-
required: [
|
|
94
|
+
required: ["id"],
|
|
94
95
|
handler: async (befly: BeflyContext, ctx) => {
|
|
95
96
|
const { id } = ctx.body;
|
|
96
97
|
|
|
97
98
|
// 类型安全的数据库查询
|
|
98
99
|
const user = await befly.db.getOne<User>({
|
|
99
|
-
table:
|
|
100
|
+
table: "user",
|
|
100
101
|
where: { id }
|
|
101
102
|
});
|
|
102
103
|
|
|
103
|
-
return { msg:
|
|
104
|
+
return { msg: "查询成功", data: user };
|
|
104
105
|
}
|
|
105
106
|
} as ApiRoute;
|
|
106
107
|
```
|
|
@@ -110,40 +111,40 @@ export default {
|
|
|
110
111
|
```typescript
|
|
111
112
|
// 查询单条
|
|
112
113
|
const user = await befly.db.getOne<User>({
|
|
113
|
-
table:
|
|
114
|
+
table: "user",
|
|
114
115
|
where: { id: 1 }
|
|
115
116
|
});
|
|
116
117
|
|
|
117
118
|
// 分页列表
|
|
118
119
|
const result = await befly.db.getList<Product>({
|
|
119
|
-
table:
|
|
120
|
-
where: { category:
|
|
120
|
+
table: "product",
|
|
121
|
+
where: { category: "electronics" },
|
|
121
122
|
page: 1,
|
|
122
123
|
limit: 10,
|
|
123
|
-
orderBy: [
|
|
124
|
+
orderBy: ["createdAt#DESC"]
|
|
124
125
|
});
|
|
125
126
|
|
|
126
127
|
// 插入数据
|
|
127
128
|
await befly.db.insData({
|
|
128
|
-
table:
|
|
129
|
+
table: "user",
|
|
129
130
|
data: {
|
|
130
|
-
username:
|
|
131
|
-
email:
|
|
131
|
+
username: "john",
|
|
132
|
+
email: "john@example.com"
|
|
132
133
|
}
|
|
133
134
|
});
|
|
134
135
|
|
|
135
136
|
// 更新数据
|
|
136
137
|
await befly.db.updData({
|
|
137
|
-
table:
|
|
138
|
+
table: "user",
|
|
138
139
|
where: { id: 1 },
|
|
139
140
|
data: {
|
|
140
|
-
nickname:
|
|
141
|
+
nickname: "John Doe"
|
|
141
142
|
}
|
|
142
143
|
});
|
|
143
144
|
|
|
144
145
|
// 删除数据
|
|
145
146
|
await befly.db.delData({
|
|
146
|
-
table:
|
|
147
|
+
table: "user",
|
|
147
148
|
where: { id: 1 }
|
|
148
149
|
});
|
|
149
150
|
```
|
|
@@ -164,9 +165,7 @@ await befly.db.delData({
|
|
|
164
165
|
|
|
165
166
|
同步到数据库:
|
|
166
167
|
|
|
167
|
-
|
|
168
|
-
bun run scripts/syncDb.ts
|
|
169
|
-
```
|
|
168
|
+
请参考:`docs/reference/sync.md`(`syncDb` / `syncAll` 等同步流程说明)。
|
|
170
169
|
|
|
171
170
|
## 🗄️ 数据库配置
|
|
172
171
|
|
|
@@ -203,37 +202,37 @@ Befly 使用 `befly.config.ts` 作为统一配置文件:
|
|
|
203
202
|
```typescript
|
|
204
203
|
// befly.config.ts
|
|
205
204
|
export const beflyConfig = {
|
|
206
|
-
appName:
|
|
205
|
+
appName: "我的应用",
|
|
207
206
|
appPort: 3000,
|
|
208
|
-
appHost:
|
|
207
|
+
appHost: "0.0.0.0",
|
|
209
208
|
|
|
210
209
|
// 数据库配置(优先使用环境变量)
|
|
211
210
|
db: {
|
|
212
|
-
type:
|
|
213
|
-
host:
|
|
211
|
+
type: "mysql",
|
|
212
|
+
host: "127.0.0.1",
|
|
214
213
|
port: 3306,
|
|
215
|
-
username:
|
|
216
|
-
password:
|
|
217
|
-
database:
|
|
214
|
+
username: "root",
|
|
215
|
+
password: "password",
|
|
216
|
+
database: "my_database"
|
|
218
217
|
},
|
|
219
218
|
|
|
220
219
|
// Redis 配置
|
|
221
220
|
redis: {
|
|
222
|
-
host:
|
|
221
|
+
host: "127.0.0.1",
|
|
223
222
|
port: 6379,
|
|
224
|
-
prefix:
|
|
223
|
+
prefix: "befly:"
|
|
225
224
|
},
|
|
226
225
|
|
|
227
226
|
// CORS 跨域配置
|
|
228
227
|
cors: {
|
|
229
|
-
origin: [
|
|
230
|
-
methods: [
|
|
228
|
+
origin: ["http://localhost:5173"],
|
|
229
|
+
methods: ["GET", "POST", "PUT", "DELETE"]
|
|
231
230
|
},
|
|
232
231
|
|
|
233
232
|
// Addon 插件配置
|
|
234
233
|
addons: {
|
|
235
234
|
admin: {
|
|
236
|
-
email: { host:
|
|
235
|
+
email: { host: "smtp.qq.com" }
|
|
237
236
|
}
|
|
238
237
|
}
|
|
239
238
|
};
|
|
@@ -244,7 +243,7 @@ export const beflyConfig = {
|
|
|
244
243
|
框架会自动从 `beflyConfig` 获取配置并建立连接,无需手动传参:
|
|
245
244
|
|
|
246
245
|
```typescript
|
|
247
|
-
import { Connect } from
|
|
246
|
+
import { Connect } from "befly/lib/connect";
|
|
248
247
|
|
|
249
248
|
// 连接 SQL 数据库(配置自动从 beflyConfig.db 获取)
|
|
250
249
|
await Connect.connectSql();
|
package/befly.config.ts
CHANGED
|
@@ -1,69 +1,80 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Befly 配置模块
|
|
3
3
|
* 自动加载 configs 目录下的配置文件并与默认配置合并
|
|
4
|
-
* 支持环境分离:befly.common.json + befly.
|
|
4
|
+
* 支持环境分离:befly.common.json + befly.development/production.json
|
|
5
5
|
*/
|
|
6
|
-
import {
|
|
6
|
+
import type { BeflyOptions } from "./types/befly.js";
|
|
7
7
|
|
|
8
|
-
import
|
|
8
|
+
import { scanConfig } from "./utils/scanConfig.js";
|
|
9
9
|
|
|
10
10
|
/** 默认配置 */
|
|
11
11
|
const defaultOptions: BeflyOptions = {
|
|
12
12
|
// ========== 核心参数 ==========
|
|
13
|
-
nodeEnv:
|
|
14
|
-
appName:
|
|
13
|
+
nodeEnv: "development",
|
|
14
|
+
appName: "野蜂飞舞",
|
|
15
15
|
appPort: 3000,
|
|
16
|
-
appHost:
|
|
17
|
-
devEmail:
|
|
18
|
-
devPassword:
|
|
16
|
+
appHost: "127.0.0.1",
|
|
17
|
+
devEmail: "dev@qq.com",
|
|
18
|
+
devPassword: "beflydev123456",
|
|
19
19
|
bodyLimit: 1048576, // 1MB
|
|
20
|
-
tz:
|
|
20
|
+
tz: "Asia/Shanghai",
|
|
21
21
|
|
|
22
22
|
// ========== 日志配置 ==========
|
|
23
23
|
logger: {
|
|
24
24
|
debug: 1,
|
|
25
|
-
excludeFields:
|
|
26
|
-
dir:
|
|
25
|
+
excludeFields: ["password", "token", "secret"],
|
|
26
|
+
dir: "./logs",
|
|
27
27
|
console: 1,
|
|
28
28
|
maxSize: 10485760 // 10MB
|
|
29
29
|
},
|
|
30
30
|
|
|
31
31
|
// ========== 数据库配置 ==========
|
|
32
32
|
db: {
|
|
33
|
-
type:
|
|
34
|
-
host:
|
|
33
|
+
type: "mysql",
|
|
34
|
+
host: "127.0.0.1",
|
|
35
35
|
port: 3306,
|
|
36
|
-
username:
|
|
37
|
-
password:
|
|
38
|
-
database:
|
|
36
|
+
username: "root",
|
|
37
|
+
password: "root",
|
|
38
|
+
database: "befly_demo",
|
|
39
39
|
poolMax: 10
|
|
40
40
|
},
|
|
41
41
|
|
|
42
42
|
// ========== Redis 配置 ==========
|
|
43
43
|
redis: {
|
|
44
|
-
host:
|
|
44
|
+
host: "127.0.0.1",
|
|
45
45
|
port: 6379,
|
|
46
|
-
username:
|
|
47
|
-
password:
|
|
46
|
+
username: "",
|
|
47
|
+
password: "",
|
|
48
48
|
db: 0,
|
|
49
|
-
prefix:
|
|
49
|
+
prefix: "befly_demo:"
|
|
50
50
|
},
|
|
51
51
|
|
|
52
52
|
// ========== 认证配置 ==========
|
|
53
53
|
auth: {
|
|
54
|
-
secret:
|
|
55
|
-
expiresIn:
|
|
56
|
-
algorithm:
|
|
54
|
+
secret: "befly-secret",
|
|
55
|
+
expiresIn: "7d",
|
|
56
|
+
algorithm: "HS256"
|
|
57
57
|
},
|
|
58
58
|
|
|
59
59
|
// ========== CORS 配置 ==========
|
|
60
60
|
cors: {
|
|
61
|
-
origin:
|
|
62
|
-
methods:
|
|
63
|
-
allowedHeaders:
|
|
64
|
-
exposedHeaders:
|
|
61
|
+
origin: "*",
|
|
62
|
+
methods: "GET,HEAD,PUT,PATCH,POST,DELETE",
|
|
63
|
+
allowedHeaders: "Content-Type,Authorization",
|
|
64
|
+
exposedHeaders: "",
|
|
65
65
|
maxAge: 86400,
|
|
66
|
-
credentials:
|
|
66
|
+
credentials: "true"
|
|
67
|
+
},
|
|
68
|
+
|
|
69
|
+
// ========== Hook:全局限流 ==========
|
|
70
|
+
rateLimit: {
|
|
71
|
+
enable: 1,
|
|
72
|
+
// 默认兜底规则:所有接口按 IP 限流(如需更细粒度请配置 rules)
|
|
73
|
+
defaultLimit: 1000,
|
|
74
|
+
defaultWindow: 60,
|
|
75
|
+
key: "ip",
|
|
76
|
+
skipRoutes: [],
|
|
77
|
+
rules: []
|
|
67
78
|
},
|
|
68
79
|
|
|
69
80
|
// ========== 禁用配置 ==========
|
|
@@ -75,16 +86,27 @@ const defaultOptions: BeflyOptions = {
|
|
|
75
86
|
addons: {}
|
|
76
87
|
};
|
|
77
88
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
89
|
+
export type LoadBeflyConfigOptions = {
|
|
90
|
+
cwd?: string;
|
|
91
|
+
nodeEnv?: string;
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
export async function loadBeflyConfig(options: LoadBeflyConfigOptions = {}): Promise<BeflyOptions> {
|
|
95
|
+
const nodeEnv = options.nodeEnv || process.env.NODE_ENV || "development";
|
|
96
|
+
const envSuffix = nodeEnv === "production" ? "production" : "development";
|
|
97
|
+
|
|
98
|
+
// 使用 scanConfig 一次性加载并合并所有配置文件
|
|
99
|
+
// 合并顺序:defaultOptions ← befly.common.json ← befly.development/production.json
|
|
100
|
+
const config = await scanConfig({
|
|
101
|
+
cwd: options.cwd,
|
|
102
|
+
dirs: ["configs"],
|
|
103
|
+
files: ["befly.common", `befly.${envSuffix}`],
|
|
104
|
+
extensions: [".json"],
|
|
105
|
+
mode: "merge",
|
|
106
|
+
defaults: defaultOptions
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
return config as BeflyOptions;
|
|
110
|
+
}
|
|
81
111
|
|
|
82
|
-
|
|
83
|
-
// 合并顺序:defaultOptions ← befly.common.json ← befly.dev/prod.json ← befly.local.json
|
|
84
|
-
export const beflyConfig = (await scanConfig({
|
|
85
|
-
dirs: ['configs'],
|
|
86
|
-
files: ['befly.common', `befly.${envSuffix}`, 'befly.local'],
|
|
87
|
-
extensions: ['.json'],
|
|
88
|
-
mode: 'merge',
|
|
89
|
-
defaults: defaultOptions
|
|
90
|
-
})) as BeflyOptions;
|
|
112
|
+
export const beflyConfig = await loadBeflyConfig();
|
package/checks/checkApi.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
// 内部依赖
|
|
2
|
-
import { existsSync } from
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
3
|
|
|
4
4
|
// 外部依赖
|
|
5
|
-
import { isPlainObject } from
|
|
6
|
-
import { scanFiles } from 'befly-shared/scanFiles';
|
|
7
|
-
import { scanAddons, getAddonDir, addonDirExists } from 'befly-shared/addonHelper';
|
|
5
|
+
import { isPlainObject } from "es-toolkit/compat";
|
|
8
6
|
|
|
7
|
+
import { Logger } from "../lib/logger.js";
|
|
8
|
+
import { projectApiDir } from "../paths.js";
|
|
9
|
+
import { scanAddons, getAddonDir, addonDirExists } from "../utils/addonHelper.js";
|
|
9
10
|
// 相对导入
|
|
10
|
-
import {
|
|
11
|
-
import { projectApiDir } from '../paths.js';
|
|
11
|
+
import { scanFiles } from "../utils/scanFiles.js";
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* 检查所有 API 定义
|
|
@@ -24,7 +24,7 @@ export async function checkApi(): Promise<void> {
|
|
|
24
24
|
for (const { filePath, relativePath } of files) {
|
|
25
25
|
allApiFiles.push({
|
|
26
26
|
file: filePath,
|
|
27
|
-
displayName:
|
|
27
|
+
displayName: "用户",
|
|
28
28
|
apiPath: relativePath
|
|
29
29
|
});
|
|
30
30
|
}
|
|
@@ -33,8 +33,8 @@ export async function checkApi(): Promise<void> {
|
|
|
33
33
|
// 收集组件 API 文件
|
|
34
34
|
const addons = scanAddons();
|
|
35
35
|
for (const addon of addons) {
|
|
36
|
-
if (!addonDirExists(addon,
|
|
37
|
-
const addonApiDir = getAddonDir(addon,
|
|
36
|
+
if (!addonDirExists(addon, "apis")) continue;
|
|
37
|
+
const addonApiDir = getAddonDir(addon, "apis");
|
|
38
38
|
|
|
39
39
|
const files = await scanFiles(addonApiDir);
|
|
40
40
|
for (const { filePath, relativePath } of files) {
|
|
@@ -52,26 +52,26 @@ export async function checkApi(): Promise<void> {
|
|
|
52
52
|
|
|
53
53
|
try {
|
|
54
54
|
// Windows 下路径需要转换为正斜杠格式
|
|
55
|
-
const filePath = item.file.replace(/\\/g,
|
|
55
|
+
const filePath = item.file.replace(/\\/g, "/");
|
|
56
56
|
const apiImport = await import(filePath);
|
|
57
57
|
const api = apiImport.default;
|
|
58
58
|
|
|
59
59
|
// 验证必填属性:name 和 handler
|
|
60
|
-
if (typeof api.name !==
|
|
60
|
+
if (typeof api.name !== "string" || api.name.trim() === "") {
|
|
61
61
|
Logger.warn(`[${item.displayName}] 接口 ${apiPath} 的 name 属性必须是非空字符串`);
|
|
62
62
|
continue;
|
|
63
63
|
}
|
|
64
|
-
if (typeof api.handler !==
|
|
64
|
+
if (typeof api.handler !== "function") {
|
|
65
65
|
Logger.warn(`[${item.displayName}] 接口 ${apiPath} 的 handler 属性必须是函数`);
|
|
66
66
|
continue;
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
// 验证可选属性的类型(如果提供了)
|
|
70
|
-
const validMethods = [
|
|
70
|
+
const validMethods = ["GET", "POST", "GET,POST", "POST,GET"];
|
|
71
71
|
if (api.method && !validMethods.includes(api.method.toUpperCase())) {
|
|
72
72
|
Logger.warn(`[${item.displayName}] 接口 ${apiPath} 的 method 属性必须是有效的 HTTP 方法 (GET, POST, GET,POST, POST,GET)`);
|
|
73
73
|
}
|
|
74
|
-
if (api.auth !== undefined && typeof api.auth !==
|
|
74
|
+
if (api.auth !== undefined && typeof api.auth !== "boolean") {
|
|
75
75
|
Logger.warn(`[${item.displayName}] 接口 ${apiPath} 的 auth 属性必须是布尔值 (true=需登录, false=公开)`);
|
|
76
76
|
}
|
|
77
77
|
if (api.fields && !isPlainObject(api.fields)) {
|
|
@@ -80,7 +80,7 @@ export async function checkApi(): Promise<void> {
|
|
|
80
80
|
if (api.required && !Array.isArray(api.required)) {
|
|
81
81
|
Logger.warn(`[${item.displayName}] 接口 ${apiPath} 的 required 属性必须是数组`);
|
|
82
82
|
}
|
|
83
|
-
if (api.required && api.required.some((item: any) => typeof item !==
|
|
83
|
+
if (api.required && api.required.some((item: any) => typeof item !== "string")) {
|
|
84
84
|
Logger.warn(`[${item.displayName}] 接口 ${apiPath} 的 required 属性必须是字符串数组`);
|
|
85
85
|
}
|
|
86
86
|
} catch (error: any) {
|
|
@@ -88,7 +88,7 @@ export async function checkApi(): Promise<void> {
|
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
90
|
} catch (error: any) {
|
|
91
|
-
Logger.error(
|
|
91
|
+
Logger.error("API 定义检查过程中出错", error);
|
|
92
92
|
throw error;
|
|
93
93
|
}
|
|
94
94
|
}
|
package/checks/checkApp.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
1
2
|
// 内部依赖
|
|
2
|
-
import { join } from
|
|
3
|
-
import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import { join } from "node:path";
|
|
4
4
|
|
|
5
5
|
// 相对导入
|
|
6
|
-
import { Logger } from
|
|
7
|
-
import { projectApiDir, projectDir } from
|
|
6
|
+
import { Logger } from "../lib/logger.js";
|
|
7
|
+
import { projectApiDir, projectDir } from "../paths.js";
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* 检查项目结构
|
|
@@ -13,49 +13,43 @@ export async function checkApp(): Promise<void> {
|
|
|
13
13
|
try {
|
|
14
14
|
// 检查项目 apis 目录下是否存在名为 addon 的目录
|
|
15
15
|
if (existsSync(projectApiDir)) {
|
|
16
|
-
const addonDir = join(projectApiDir,
|
|
16
|
+
const addonDir = join(projectApiDir, "addon");
|
|
17
17
|
if (existsSync(addonDir)) {
|
|
18
|
-
throw new Error(
|
|
18
|
+
throw new Error("项目 apis 目录下不能存在名为 addon 的目录,addon 是保留名称,用于组件接口路由");
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
// 检查并创建 logs 目录
|
|
23
|
-
const logsDir = join(projectDir,
|
|
23
|
+
const logsDir = join(projectDir, "logs");
|
|
24
24
|
if (!existsSync(logsDir)) {
|
|
25
25
|
mkdirSync(logsDir, { recursive: true });
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
// 检查并创建 configs 目录和配置文件
|
|
29
|
-
const configsDir = join(projectDir,
|
|
29
|
+
const configsDir = join(projectDir, "configs");
|
|
30
30
|
if (!existsSync(configsDir)) {
|
|
31
31
|
mkdirSync(configsDir, { recursive: true });
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
// 检查并创建 befly.common.json
|
|
35
|
-
const beflyJsonPath = join(configsDir,
|
|
35
|
+
const beflyJsonPath = join(configsDir, "befly.common.json");
|
|
36
36
|
if (!existsSync(beflyJsonPath)) {
|
|
37
|
-
writeFileSync(beflyJsonPath,
|
|
37
|
+
writeFileSync(beflyJsonPath, "{}", "utf-8");
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
// 检查并创建 befly.
|
|
41
|
-
const
|
|
42
|
-
if (!existsSync(
|
|
43
|
-
writeFileSync(
|
|
40
|
+
// 检查并创建 befly.development.json
|
|
41
|
+
const beflyDevelopmentJsonPath = join(configsDir, "befly.development.json");
|
|
42
|
+
if (!existsSync(beflyDevelopmentJsonPath)) {
|
|
43
|
+
writeFileSync(beflyDevelopmentJsonPath, "{}", "utf-8");
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
// 检查并创建 befly.
|
|
47
|
-
const
|
|
48
|
-
if (!existsSync(
|
|
49
|
-
writeFileSync(
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// 检查并创建 befly.local.json
|
|
53
|
-
const beflyLocalJsonPath = join(configsDir, 'befly.local.json');
|
|
54
|
-
if (!existsSync(beflyLocalJsonPath)) {
|
|
55
|
-
writeFileSync(beflyLocalJsonPath, '{}', 'utf-8');
|
|
46
|
+
// 检查并创建 befly.production.json
|
|
47
|
+
const beflyProductionJsonPath = join(configsDir, "befly.production.json");
|
|
48
|
+
if (!existsSync(beflyProductionJsonPath)) {
|
|
49
|
+
writeFileSync(beflyProductionJsonPath, "{}", "utf-8");
|
|
56
50
|
}
|
|
57
51
|
} catch (error: any) {
|
|
58
|
-
Logger.error(
|
|
52
|
+
Logger.error("项目结构检查过程中出错", error);
|
|
59
53
|
throw error;
|
|
60
54
|
}
|
|
61
55
|
}
|