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
package/docs/infra/redis.md
CHANGED
|
@@ -220,9 +220,11 @@ const count = await befly.redis.expireBatch([
|
|
|
220
220
|
### saddBatch - 批量添加 Set 成员
|
|
221
221
|
|
|
222
222
|
```typescript
|
|
223
|
+
import { CacheKeys } from "befly/lib/cacheKeys";
|
|
224
|
+
|
|
223
225
|
const count = await befly.redis.saddBatch([
|
|
224
|
-
{ key: "
|
|
225
|
-
{ key: "
|
|
226
|
+
{ key: CacheKeys.roleApis("admin"), members: ["/api/user"] },
|
|
227
|
+
{ key: CacheKeys.roleApis("editor"), members: ["/api/article"] }
|
|
226
228
|
]);
|
|
227
229
|
// 返回: 成功添加的总成员数量
|
|
228
230
|
```
|
|
@@ -230,9 +232,11 @@ const count = await befly.redis.saddBatch([
|
|
|
230
232
|
### sismemberBatch - 批量检查 Set 成员
|
|
231
233
|
|
|
232
234
|
```typescript
|
|
235
|
+
import { CacheKeys } from "befly/lib/cacheKeys";
|
|
236
|
+
|
|
233
237
|
const results = await befly.redis.sismemberBatch([
|
|
234
|
-
{ key: "
|
|
235
|
-
{ key: "
|
|
238
|
+
{ key: CacheKeys.roleApis("admin"), member: "/api/user" },
|
|
239
|
+
{ key: CacheKeys.roleApis("admin"), member: "/api/user/delete" }
|
|
236
240
|
]);
|
|
237
241
|
// 返回: [true, false]
|
|
238
242
|
```
|
|
@@ -285,11 +289,11 @@ const id = await befly.db.insData({
|
|
|
285
289
|
import { CacheKeys } from "befly/lib/cacheKeys";
|
|
286
290
|
|
|
287
291
|
// 获取键名
|
|
288
|
-
const
|
|
289
|
-
const
|
|
290
|
-
const
|
|
291
|
-
const
|
|
292
|
-
const
|
|
292
|
+
const apisAllKey = CacheKeys.apisAll(); // 'befly:apis:all'
|
|
293
|
+
const menusAllKey = CacheKeys.menusAll(); // 'befly:menus:all'
|
|
294
|
+
const adminRoleInfoKey = CacheKeys.roleInfo("admin"); // 'befly:role:info:admin'
|
|
295
|
+
const adminRoleApisKey = CacheKeys.roleApis("admin"); // 'befly:role:apis:admin'
|
|
296
|
+
const userTableColumnsKey = CacheKeys.tableColumns("user"); // 'befly:table:columns:user'
|
|
293
297
|
```
|
|
294
298
|
|
|
295
299
|
### 键名前缀
|
|
@@ -304,7 +308,12 @@ Redis 插件支持配置全局前缀,避免键名冲突:
|
|
|
304
308
|
}
|
|
305
309
|
```
|
|
306
310
|
|
|
307
|
-
|
|
311
|
+
所有键会自动添加前缀,最终写入 Redis 的 key 形如:`myapp:<key>`。
|
|
312
|
+
|
|
313
|
+
- 例如:你调用 `befly.redis.getString("user:1")`,实际访问的是 `myapp:user:1`
|
|
314
|
+
- 例如:你调用 `befly.redis.sismember(CacheKeys.roleApis("admin"), "/api/user")`,实际访问的是 `myapp:befly:role:apis:admin`
|
|
315
|
+
|
|
316
|
+
> 注意:`redis.prefix` **不允许包含** `:`,因为 RedisHelper 会自动拼接分隔符 `:`。
|
|
308
317
|
|
|
309
318
|
---
|
|
310
319
|
|
|
@@ -313,6 +322,8 @@ Redis 插件支持配置全局前缀,避免键名冲突:
|
|
|
313
322
|
### 场景1:表结构缓存
|
|
314
323
|
|
|
315
324
|
DbHelper 自动缓存表字段信息,避免重复查询数据库。
|
|
325
|
+
|
|
326
|
+
```typescript
|
|
316
327
|
// 计数 + 过期:常用于限流/风控
|
|
317
328
|
// 更推荐:直接使用 Befly Core 内置的 rateLimit hook(通过 configs 配置即可)
|
|
318
329
|
|
|
@@ -323,8 +334,9 @@ const key = `ratelimit:${ctx.ip}:${ctx.route}`;
|
|
|
323
334
|
const count = await befly.redis.incrWithExpire(key, windowSeconds);
|
|
324
335
|
|
|
325
336
|
if (count > limit) {
|
|
326
|
-
return befly.tool.No("请求过于频繁");
|
|
337
|
+
return befly.tool.No("请求过于频繁");
|
|
327
338
|
}
|
|
339
|
+
```
|
|
328
340
|
|
|
329
341
|
### 场景2:接口权限缓存
|
|
330
342
|
|
|
@@ -333,7 +345,7 @@ return befly.tool.No("请求过于频繁");
|
|
|
333
345
|
```typescript
|
|
334
346
|
// 极简方案:每个角色一个 Set
|
|
335
347
|
const roleApisKey = CacheKeys.roleApis("admin");
|
|
336
|
-
const hasPermission = await befly.redis.sismember(roleApisKey, "
|
|
348
|
+
const hasPermission = await befly.redis.sismember(roleApisKey, "/api/user/add");
|
|
337
349
|
// 返回: true
|
|
338
350
|
```
|
|
339
351
|
|
|
@@ -473,14 +485,14 @@ const menus = await befly.cache.getMenus();
|
|
|
473
485
|
|
|
474
486
|
// 获取角色权限
|
|
475
487
|
const permissions = await befly.cache.getRolePermissions("admin");
|
|
476
|
-
// 返回: ['
|
|
488
|
+
// 返回: ['/api/user/list', '/api/user/add', ...]
|
|
477
489
|
```
|
|
478
490
|
|
|
479
491
|
### 权限检查
|
|
480
492
|
|
|
481
493
|
```typescript
|
|
482
494
|
// 检查角色是否有指定接口权限
|
|
483
|
-
const hasPermission = await befly.cache.checkRolePermission("admin", "
|
|
495
|
+
const hasPermission = await befly.cache.checkRolePermission("admin", "/api/user/add");
|
|
484
496
|
// 返回: true 或 false
|
|
485
497
|
```
|
|
486
498
|
|
package/docs/plugins/plugin.md
CHANGED
|
@@ -72,7 +72,7 @@ import type { Plugin } from "befly/types/plugin";
|
|
|
72
72
|
|
|
73
73
|
const plugin: Plugin = {
|
|
74
74
|
// 依赖的插件列表(可选)
|
|
75
|
-
|
|
75
|
+
deps: ["logger", "db"],
|
|
76
76
|
|
|
77
77
|
// 初始化函数(必填)
|
|
78
78
|
handler: (befly) => {
|
|
@@ -96,10 +96,10 @@ interface Plugin {
|
|
|
96
96
|
name?: string;
|
|
97
97
|
|
|
98
98
|
/** 依赖的插件列表(在这些插件之后执行) */
|
|
99
|
-
|
|
99
|
+
deps: string[];
|
|
100
100
|
|
|
101
101
|
/** 插件初始化函数 */
|
|
102
|
-
handler
|
|
102
|
+
handler: (context: BeflyContext) => any | Promise<any>;
|
|
103
103
|
|
|
104
104
|
/** 插件描述(可选) */
|
|
105
105
|
description?: string;
|
|
@@ -171,12 +171,12 @@ interface Plugin {
|
|
|
171
171
|
|
|
172
172
|
### 依赖排序
|
|
173
173
|
|
|
174
|
-
使用 `
|
|
174
|
+
使用 `deps` 属性声明依赖关系:
|
|
175
175
|
|
|
176
176
|
```typescript
|
|
177
177
|
// redis.ts - 依赖 logger
|
|
178
178
|
const plugin: Plugin = {
|
|
179
|
-
|
|
179
|
+
deps: ["logger"], // 在 logger 插件之后初始化
|
|
180
180
|
handler: () => {
|
|
181
181
|
/* ... */
|
|
182
182
|
}
|
|
@@ -199,7 +199,7 @@ const plugin: Plugin = {
|
|
|
199
199
|
```typescript
|
|
200
200
|
// 插件源码
|
|
201
201
|
const loggerPlugin: Plugin = {
|
|
202
|
-
|
|
202
|
+
deps: [],
|
|
203
203
|
async handler(): Promise<typeof Logger> {
|
|
204
204
|
if (beflyConfig.logger) {
|
|
205
205
|
Logger.configure(beflyConfig.logger);
|
|
@@ -250,10 +250,11 @@ const redisConfig = befly.config.redis;
|
|
|
250
250
|
```typescript
|
|
251
251
|
// 插件源码
|
|
252
252
|
const dbPlugin: Plugin = {
|
|
253
|
-
|
|
253
|
+
deps: ["logger", "redis"],
|
|
254
254
|
async handler(befly: BeflyContext): Promise<DbHelper> {
|
|
255
|
-
|
|
256
|
-
|
|
255
|
+
// 连接由启动期统一完成;插件仅消费已连接实例
|
|
256
|
+
const sql = Connect.getSql();
|
|
257
|
+
return new DbHelper({ redis: befly.redis, sql: sql, dialect: new MySqlDialect() });
|
|
257
258
|
}
|
|
258
259
|
};
|
|
259
260
|
```
|
|
@@ -285,9 +286,10 @@ await befly.db.delData({ table: "user", where: { id: 1 } });
|
|
|
285
286
|
```typescript
|
|
286
287
|
// 插件源码
|
|
287
288
|
const redisPlugin: Plugin = {
|
|
288
|
-
|
|
289
|
+
deps: ["logger"],
|
|
289
290
|
async handler(): Promise<RedisHelper | Record<string, never>> {
|
|
290
|
-
|
|
291
|
+
// 连接由启动期统一完成;插件仅校验连接存在
|
|
292
|
+
Connect.getRedis();
|
|
291
293
|
return new RedisHelper(redisConfig.prefix);
|
|
292
294
|
}
|
|
293
295
|
};
|
|
@@ -384,9 +386,9 @@ const decrypted = befly.cipher.decrypt(encrypted);
|
|
|
384
386
|
```typescript
|
|
385
387
|
// 插件源码
|
|
386
388
|
const cachePlugin: Plugin = {
|
|
387
|
-
|
|
389
|
+
deps: ["logger", "redis", "db"],
|
|
388
390
|
async handler(befly: BeflyContext): Promise<CacheHelper> {
|
|
389
|
-
return new CacheHelper(befly);
|
|
391
|
+
return new CacheHelper({ db: befly.db, redis: befly.redis });
|
|
390
392
|
}
|
|
391
393
|
};
|
|
392
394
|
```
|
|
@@ -473,7 +475,7 @@ import type { Plugin } from "befly/types/plugin";
|
|
|
473
475
|
import type { BeflyContext } from "befly/types/befly";
|
|
474
476
|
|
|
475
477
|
const plugin: Plugin = {
|
|
476
|
-
|
|
478
|
+
deps: ["db", "redis"], // 依赖数据库和 Redis
|
|
477
479
|
handler: (befly: BeflyContext) => {
|
|
478
480
|
return {
|
|
479
481
|
async getUser(id: number) {
|
|
@@ -513,7 +515,7 @@ import type { Plugin } from "befly/types/plugin";
|
|
|
513
515
|
import { Client } from "@elastic/elasticsearch";
|
|
514
516
|
|
|
515
517
|
const plugin: Plugin = {
|
|
516
|
-
|
|
518
|
+
deps: ["logger", "config"],
|
|
517
519
|
async handler(befly) {
|
|
518
520
|
const config = befly.config.elasticsearch || {};
|
|
519
521
|
|
|
@@ -580,7 +582,7 @@ class SmsHelper {
|
|
|
580
582
|
}
|
|
581
583
|
|
|
582
584
|
const plugin: Plugin = {
|
|
583
|
-
|
|
585
|
+
deps: ["logger", "config"],
|
|
584
586
|
handler: (befly: BeflyContext) => {
|
|
585
587
|
const smsConfig = befly.config.sms || {};
|
|
586
588
|
return new SmsHelper(befly, smsConfig);
|
|
@@ -688,7 +690,7 @@ class EmailHelper {
|
|
|
688
690
|
* 邮件插件
|
|
689
691
|
*/
|
|
690
692
|
const emailPlugin: Plugin = {
|
|
691
|
-
|
|
693
|
+
deps: ["db", "logger", "config"],
|
|
692
694
|
async handler(befly: BeflyContext): Promise<EmailHelper> {
|
|
693
695
|
const emailConfig = befly.config?.addons?.admin?.email || {};
|
|
694
696
|
return new EmailHelper(befly, emailConfig);
|
|
@@ -801,7 +803,7 @@ class WechatPayHelper {
|
|
|
801
803
|
}
|
|
802
804
|
|
|
803
805
|
const plugin: Plugin = {
|
|
804
|
-
|
|
806
|
+
deps: ["logger", "config"],
|
|
805
807
|
handler: (befly: BeflyContext) => {
|
|
806
808
|
return new WechatPayHelper(befly);
|
|
807
809
|
}
|
|
@@ -851,7 +853,7 @@ const plugin: Plugin = {
|
|
|
851
853
|
```typescript
|
|
852
854
|
// ✅ 推荐:明确声明所有依赖
|
|
853
855
|
const plugin: Plugin = {
|
|
854
|
-
|
|
856
|
+
deps: ["logger", "db", "redis"], // 声明所有使用的插件
|
|
855
857
|
handler: (befly) => {
|
|
856
858
|
/* ... */
|
|
857
859
|
}
|
|
@@ -929,7 +931,7 @@ class DatabasePool {
|
|
|
929
931
|
插件按以下顺序加载:
|
|
930
932
|
|
|
931
933
|
1. 核心插件 → Addon 插件 → 项目插件
|
|
932
|
-
2. 同一类型内根据 `
|
|
934
|
+
2. 同一类型内根据 `deps` 依赖关系排序
|
|
933
935
|
3. 无依赖的插件按文件名字母顺序
|
|
934
936
|
|
|
935
937
|
### Q2: 如何在插件中访问其他插件?
|
|
@@ -938,7 +940,7 @@ class DatabasePool {
|
|
|
938
940
|
|
|
939
941
|
```typescript
|
|
940
942
|
const plugin: Plugin = {
|
|
941
|
-
|
|
943
|
+
deps: ["db"], // 声明依赖
|
|
942
944
|
handler: (befly) => {
|
|
943
945
|
return {
|
|
944
946
|
async getUser(id: number) {
|
package/docs/quickstart.md
CHANGED
|
@@ -1,331 +1,8 @@
|
|
|
1
|
-
# Quickstart
|
|
1
|
+
# Quickstart 快速入门(已迁移)
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
为避免重复内容长期漂移,本 Quickstart 已迁移到权威入口:
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
- `packages/core/docs/guide/quickstart.md`
|
|
6
|
+
- 在线阅读:[`./guide/quickstart.md`](./guide/quickstart.md)
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
- [项目结构](#项目结构)
|
|
9
|
-
- [第一个 API](#第一个-api)
|
|
10
|
-
- [配置数据库](#配置数据库)
|
|
11
|
-
- [定义表结构](#定义表结构)
|
|
12
|
-
- [同步数据库](#同步数据库)
|
|
13
|
-
- [启动服务](#启动服务)
|
|
14
|
-
- [下一步](#下一步)
|
|
15
|
-
|
|
16
|
-
---
|
|
17
|
-
|
|
18
|
-
## 环境准备
|
|
19
|
-
|
|
20
|
-
### 必需软件
|
|
21
|
-
|
|
22
|
-
| 软件 | 版本要求 | 说明 |
|
|
23
|
-
| ----- | -------- | ----------------- |
|
|
24
|
-
| Bun | >= 1.0 | JavaScript 运行时 |
|
|
25
|
-
| MySQL | >= 8.0 | 数据库 |
|
|
26
|
-
| Redis | >= 6.0 | 缓存(可选) |
|
|
27
|
-
|
|
28
|
-
### 安装 Bun
|
|
29
|
-
|
|
30
|
-
```bash
|
|
31
|
-
# Windows (PowerShell)
|
|
32
|
-
powershell -c "irm bun.sh/install.ps1 | iex"
|
|
33
|
-
|
|
34
|
-
# macOS / Linux
|
|
35
|
-
curl -fsSL https://bun.sh/install | bash
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
### 创建项目
|
|
39
|
-
|
|
40
|
-
```bash
|
|
41
|
-
# 克隆模板项目
|
|
42
|
-
git clone https://github.com/chenbimo/befly-tpl.git my-api
|
|
43
|
-
cd my-api
|
|
44
|
-
|
|
45
|
-
# 安装依赖
|
|
46
|
-
bun install
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
---
|
|
50
|
-
|
|
51
|
-
## 项目结构
|
|
52
|
-
|
|
53
|
-
```
|
|
54
|
-
my-api/
|
|
55
|
-
├── apis/ # API 接口目录
|
|
56
|
-
│ └── user/
|
|
57
|
-
│ └── login.ts # 用户登录接口
|
|
58
|
-
├── tables/ # 表定义目录
|
|
59
|
-
│ └── user.json # 用户表定义
|
|
60
|
-
├── configs/ # 配置文件目录
|
|
61
|
-
│ ├── befly.common.json # 公共配置
|
|
62
|
-
│ ├── befly.development.json # 开发环境配置
|
|
63
|
-
│ └── befly.production.json # 生产环境配置
|
|
64
|
-
├── main.ts # 入口文件
|
|
65
|
-
└── package.json
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
---
|
|
69
|
-
|
|
70
|
-
## 第一个 API
|
|
71
|
-
|
|
72
|
-
### 创建 API 文件
|
|
73
|
-
|
|
74
|
-
在 `apis/user/` 目录下创建 `login.ts`:
|
|
75
|
-
|
|
76
|
-
```typescript
|
|
77
|
-
import type { ApiRoute } from "befly/types/api";
|
|
78
|
-
|
|
79
|
-
export default {
|
|
80
|
-
name: "用户登录",
|
|
81
|
-
method: "POST",
|
|
82
|
-
auth: false, // 不需要登录
|
|
83
|
-
fields: {
|
|
84
|
-
email: { name: "邮箱", type: "string", min: 5, max: 100, regexp: "@email" },
|
|
85
|
-
password: { name: "密码", type: "string", min: 6, max: 100 }
|
|
86
|
-
},
|
|
87
|
-
required: ["email", "password"],
|
|
88
|
-
handler: async (befly, ctx) => {
|
|
89
|
-
// 查询用户
|
|
90
|
-
const user = await befly.db.getDetail({
|
|
91
|
-
table: "user",
|
|
92
|
-
columns: ["id", "email", "password", "nickname"],
|
|
93
|
-
where: { email: ctx.body.email }
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
if (!user?.id) {
|
|
97
|
-
return No("用户不存在");
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
// 验证密码
|
|
101
|
-
const isValid = await befly.cipher.verifyPassword(ctx.body.password, user.password);
|
|
102
|
-
if (!isValid) {
|
|
103
|
-
return No("密码错误");
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
// 签发令牌
|
|
107
|
-
const token = befly.jwt.sign({ userId: user.id });
|
|
108
|
-
|
|
109
|
-
return Yes("登录成功", { token: token, user: { id: user.id, nickname: user.nickname } });
|
|
110
|
-
}
|
|
111
|
-
} as ApiRoute;
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
### API 路由规则
|
|
115
|
-
|
|
116
|
-
文件路径自动转换为路由:
|
|
117
|
-
|
|
118
|
-
| 文件路径 | 路由路径 |
|
|
119
|
-
| ----------------------- | ------------------------- |
|
|
120
|
-
| `apis/user/login.ts` | `POST /api/user/login` |
|
|
121
|
-
| `apis/user/register.ts` | `POST /api/user/register` |
|
|
122
|
-
| `apis/article/list.ts` | `POST /api/article/list` |
|
|
123
|
-
|
|
124
|
-
---
|
|
125
|
-
|
|
126
|
-
## 配置数据库
|
|
127
|
-
|
|
128
|
-
### 编辑配置文件
|
|
129
|
-
|
|
130
|
-
修改 `configs/befly.development.json`:
|
|
131
|
-
|
|
132
|
-
```json
|
|
133
|
-
{
|
|
134
|
-
"db": {
|
|
135
|
-
"type": "mysql",
|
|
136
|
-
"host": "127.0.0.1",
|
|
137
|
-
"port": 3306,
|
|
138
|
-
"user": "root",
|
|
139
|
-
"password": "your_password",
|
|
140
|
-
"database": "my_api"
|
|
141
|
-
},
|
|
142
|
-
"redis": {
|
|
143
|
-
"host": "127.0.0.1",
|
|
144
|
-
"port": 6379,
|
|
145
|
-
"password": ""
|
|
146
|
-
},
|
|
147
|
-
"auth": {
|
|
148
|
-
"secret": "your-jwt-secret-change-in-production",
|
|
149
|
-
"expiresIn": "7d"
|
|
150
|
-
},
|
|
151
|
-
"logger": {
|
|
152
|
-
"debug": 1,
|
|
153
|
-
"console": 1
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
### 创建数据库
|
|
159
|
-
|
|
160
|
-
```sql
|
|
161
|
-
CREATE DATABASE my_api CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
---
|
|
165
|
-
|
|
166
|
-
## 定义表结构
|
|
167
|
-
|
|
168
|
-
### 创建表定义文件
|
|
169
|
-
|
|
170
|
-
在 `tables/` 目录下创建 `user.json`:
|
|
171
|
-
|
|
172
|
-
```json
|
|
173
|
-
{
|
|
174
|
-
"email": "邮箱|string|5|100||true|^[\\w.-]+@[\\w.-]+\\.[a-zA-Z]{2,}$",
|
|
175
|
-
"password": "密码|string|6|100||true",
|
|
176
|
-
"nickname": "昵称|string|2|50|用户",
|
|
177
|
-
"avatar": "头像|string|0|500",
|
|
178
|
-
"phone": "手机号|string|0|20"
|
|
179
|
-
}
|
|
180
|
-
```
|
|
181
|
-
|
|
182
|
-
### 字段定义格式
|
|
183
|
-
|
|
184
|
-
格式:`"字段标签|类型|最小|最大|默认|必填|正则"`
|
|
185
|
-
|
|
186
|
-
| 位置 | 说明 | 示例 |
|
|
187
|
-
| ---- | ----------- | --------------------- |
|
|
188
|
-
| 1 | 字段标签 | `邮箱` |
|
|
189
|
-
| 2 | 数据类型 | `string` / `number` |
|
|
190
|
-
| 3 | 最小值/长度 | `5` |
|
|
191
|
-
| 4 | 最大值/长度 | `100` |
|
|
192
|
-
| 5 | 默认值 | `用户` |
|
|
193
|
-
| 6 | 是否必填 | `true` / `false` |
|
|
194
|
-
| 7 | 正则验证 | `@email` 或自定义正则 |
|
|
195
|
-
|
|
196
|
-
### 自动字段
|
|
197
|
-
|
|
198
|
-
每个表自动添加:
|
|
199
|
-
|
|
200
|
-
| 字段 | 类型 | 说明 |
|
|
201
|
-
| ------------ | ------- | ------------------------------- |
|
|
202
|
-
| `id` | BIGINT | 主键,自增 |
|
|
203
|
-
| `created_at` | BIGINT | 创建时间戳 |
|
|
204
|
-
| `updated_at` | BIGINT | 更新时间戳 |
|
|
205
|
-
| `state` | TINYINT | 状态(1=正常,0=禁用,-1=删除) |
|
|
206
|
-
|
|
207
|
-
---
|
|
208
|
-
|
|
209
|
-
## 同步数据库
|
|
210
|
-
|
|
211
|
-
### 运行同步命令
|
|
212
|
-
|
|
213
|
-
```bash
|
|
214
|
-
# 全量同步(表结构 + API + 菜单 + 开发账户)
|
|
215
|
-
bun befly sync
|
|
216
|
-
|
|
217
|
-
# 或单独同步
|
|
218
|
-
bun befly sync:db # 只同步表结构
|
|
219
|
-
bun befly sync:api # 只同步 API 路由
|
|
220
|
-
```
|
|
221
|
-
|
|
222
|
-
### 验证同步结果
|
|
223
|
-
|
|
224
|
-
```bash
|
|
225
|
-
# 查看数据库
|
|
226
|
-
mysql -u root -p my_api -e "SHOW TABLES;"
|
|
227
|
-
|
|
228
|
-
# 应该看到:
|
|
229
|
-
# +------------------+
|
|
230
|
-
# | Tables_in_my_api |
|
|
231
|
-
# +------------------+
|
|
232
|
-
# | user |
|
|
233
|
-
# +------------------+
|
|
234
|
-
```
|
|
235
|
-
|
|
236
|
-
---
|
|
237
|
-
|
|
238
|
-
## 启动服务
|
|
239
|
-
|
|
240
|
-
### 开发模式
|
|
241
|
-
|
|
242
|
-
```bash
|
|
243
|
-
bun run dev
|
|
244
|
-
```
|
|
245
|
-
|
|
246
|
-
服务启动后:
|
|
247
|
-
|
|
248
|
-
```
|
|
249
|
-
🚀 Befly 服务已启动
|
|
250
|
-
📍 http://localhost:3000
|
|
251
|
-
```
|
|
252
|
-
|
|
253
|
-
### 测试 API
|
|
254
|
-
|
|
255
|
-
```bash
|
|
256
|
-
# 测试登录接口
|
|
257
|
-
curl -X POST http://localhost:3000/api/user/login \
|
|
258
|
-
-H "Content-Type: application/json" \
|
|
259
|
-
-d '{"email":"test@example.com","password":"123456"}'
|
|
260
|
-
```
|
|
261
|
-
|
|
262
|
-
响应示例:
|
|
263
|
-
|
|
264
|
-
```json
|
|
265
|
-
{
|
|
266
|
-
"code": 0,
|
|
267
|
-
"msg": "登录成功",
|
|
268
|
-
"data": {
|
|
269
|
-
"token": "eyJhbGciOiJIUzI1NiIs...",
|
|
270
|
-
"user": {
|
|
271
|
-
"id": 1,
|
|
272
|
-
"nickname": "用户"
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
```
|
|
277
|
-
|
|
278
|
-
---
|
|
279
|
-
|
|
280
|
-
## 下一步
|
|
281
|
-
|
|
282
|
-
### 学习更多
|
|
283
|
-
|
|
284
|
-
| 主题 | 文档 | 说明 |
|
|
285
|
-
| ---------- | ------------------------------------ | -------------------- |
|
|
286
|
-
| API 开发 | [api.md](./api/api.md) | API 定义、字段、权限 |
|
|
287
|
-
| 表结构 | [table.md](./table.md) | 表定义格式详解 |
|
|
288
|
-
| 数据库操作 | [database.md](./plugins/database.md) | CRUD 操作 |
|
|
289
|
-
| 配置系统 | [config.md](./config.md) | 配置文件说明 |
|
|
290
|
-
| 插件开发 | [plugin.md](./plugins/plugin.md) | 自定义插件 |
|
|
291
|
-
| Hook 开发 | [hook.md](./hooks/hook.md) | 请求处理钩子 |
|
|
292
|
-
| 验证系统 | [validator.md](./validator.md) | 参数验证 |
|
|
293
|
-
| 日志系统 | [logger.md](./logger.md) | 日志配置 |
|
|
294
|
-
| 加密工具 | [cipher.md](./plugins/cipher.md) | 加密与 JWT |
|
|
295
|
-
| 同步命令 | [sync.md](./sync.md) | 数据库同步 |
|
|
296
|
-
|
|
297
|
-
### 常用命令
|
|
298
|
-
|
|
299
|
-
```bash
|
|
300
|
-
# 开发
|
|
301
|
-
bun run dev # 启动开发服务
|
|
302
|
-
bun befly sync # 同步数据库
|
|
303
|
-
bun befly sync:db # 只同步表结构
|
|
304
|
-
|
|
305
|
-
# 生产
|
|
306
|
-
bun run build # 构建
|
|
307
|
-
bun run start # 启动生产服务
|
|
308
|
-
```
|
|
309
|
-
|
|
310
|
-
### 项目示例
|
|
311
|
-
|
|
312
|
-
```
|
|
313
|
-
apis/
|
|
314
|
-
├── user/
|
|
315
|
-
│ ├── login.ts # 登录
|
|
316
|
-
│ ├── register.ts # 注册
|
|
317
|
-
│ ├── info.ts # 获取信息
|
|
318
|
-
│ └── update.ts # 更新信息
|
|
319
|
-
├── article/
|
|
320
|
-
│ ├── list.ts # 文章列表
|
|
321
|
-
│ ├── detail.ts # 文章详情
|
|
322
|
-
│ ├── create.ts # 创建文章
|
|
323
|
-
│ └── delete.ts # 删除文章
|
|
324
|
-
└── common/
|
|
325
|
-
└── upload.ts # 文件上传
|
|
326
|
-
|
|
327
|
-
tables/
|
|
328
|
-
├── user.json # 用户表
|
|
329
|
-
├── article.json # 文章表
|
|
330
|
-
└── category.json # 分类表
|
|
331
|
-
```
|
|
8
|
+
如你从旧链接跳转到这里,请以 `guide/quickstart.md` 的内容为准(配置字段、同步流程、权限 pathname 规则等都以当前实现为准)。
|
package/docs/reference/addon.md
CHANGED
package/docs/reference/config.md
CHANGED
|
@@ -207,14 +207,14 @@ befly.development.json 或 befly.production.json(环境配置)
|
|
|
207
207
|
|
|
208
208
|
### Redis 配置 (redis)
|
|
209
209
|
|
|
210
|
-
| 配置项 | 类型 | 默认值
|
|
211
|
-
| ---------- | ------ |
|
|
212
|
-
| `host` | string | `'127.0.0.1'`
|
|
213
|
-
| `port` | number | `6379`
|
|
214
|
-
| `username` | string | `''`
|
|
215
|
-
| `password` | string | `''`
|
|
216
|
-
| `db` | number | `0`
|
|
217
|
-
| `prefix` | string | `'befly_demo
|
|
210
|
+
| 配置项 | 类型 | 默认值 | 说明 |
|
|
211
|
+
| ---------- | ------ | -------------- | ------------------------------------------------------ |
|
|
212
|
+
| `host` | string | `'127.0.0.1'` | Redis 主机 |
|
|
213
|
+
| `port` | number | `6379` | Redis 端口 |
|
|
214
|
+
| `username` | string | `''` | Redis 用户名 |
|
|
215
|
+
| `password` | string | `''` | Redis 密码 |
|
|
216
|
+
| `db` | number | `0` | Redis 数据库索引 |
|
|
217
|
+
| `prefix` | string | `'befly_demo'` | Redis Key 前缀(不允许包含 `:`,分隔符由系统自动拼接) |
|
|
218
218
|
|
|
219
219
|
```json
|
|
220
220
|
{
|
|
@@ -223,7 +223,7 @@ befly.development.json 或 befly.production.json(环境配置)
|
|
|
223
223
|
"port": 6379,
|
|
224
224
|
"password": "redis_password",
|
|
225
225
|
"db": 1,
|
|
226
|
-
"prefix": "myapp
|
|
226
|
+
"prefix": "myapp"
|
|
227
227
|
}
|
|
228
228
|
}
|
|
229
229
|
```
|
|
@@ -295,13 +295,11 @@ befly.development.json 或 befly.production.json(环境配置)
|
|
|
295
295
|
| ---------------- | -------- | ------ | -------------- |
|
|
296
296
|
| `disableHooks` | string[] | `[]` | 禁用的钩子列表 |
|
|
297
297
|
| `disablePlugins` | string[] | `[]` | 禁用的插件列表 |
|
|
298
|
-
| `hiddenMenus` | string[] | `[]` | 隐藏的菜单路径 |
|
|
299
298
|
|
|
300
299
|
```json
|
|
301
300
|
{
|
|
302
301
|
"disableHooks": ["requestLogger"],
|
|
303
|
-
"disablePlugins": ["redis"]
|
|
304
|
-
"hiddenMenus": ["/admin/debug", "/admin/test"]
|
|
302
|
+
"disablePlugins": ["redis"]
|
|
305
303
|
}
|
|
306
304
|
```
|
|
307
305
|
|
|
@@ -381,7 +379,7 @@ NODE_ENV=production bun run start
|
|
|
381
379
|
},
|
|
382
380
|
|
|
383
381
|
"redis": {
|
|
384
|
-
"prefix": "myapp
|
|
382
|
+
"prefix": "myapp"
|
|
385
383
|
},
|
|
386
384
|
|
|
387
385
|
"cors": {
|
|
@@ -464,30 +462,15 @@ export default {
|
|
|
464
462
|
### 在插件中访问
|
|
465
463
|
|
|
466
464
|
```typescript
|
|
467
|
-
import { beflyConfig } from "../befly.config.js";
|
|
468
|
-
|
|
469
465
|
const plugin: Plugin = {
|
|
470
|
-
handler: () => {
|
|
471
|
-
const port =
|
|
472
|
-
const dbConfig =
|
|
466
|
+
handler: (context) => {
|
|
467
|
+
const port = context.config.appPort;
|
|
468
|
+
const dbConfig = context.config.db;
|
|
473
469
|
// ...
|
|
474
470
|
}
|
|
475
471
|
};
|
|
476
472
|
```
|
|
477
473
|
|
|
478
|
-
### 直接导入(仅 Befly 源码/单仓内)
|
|
479
|
-
|
|
480
|
-
> 说明:`befly` 包的 `exports` 仅暴露 `befly`、`befly/lib/*`、`befly/utils/*`、`befly/types/*`。
|
|
481
|
-
> 因此不支持 `befly/befly.config` 这种子路径导入。
|
|
482
|
-
|
|
483
|
-
如果你在 Befly 源码/单仓内开发(例如编写内置插件/命令),可以使用相对路径导入:
|
|
484
|
-
|
|
485
|
-
```typescript
|
|
486
|
-
import { beflyConfig } from "../befly.config.js";
|
|
487
|
-
|
|
488
|
-
console.log(beflyConfig.appName);
|
|
489
|
-
```
|
|
490
|
-
|
|
491
474
|
---
|
|
492
475
|
|
|
493
476
|
## 最佳实践
|