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.
Files changed (144) hide show
  1. package/README.md +47 -19
  2. package/befly.config.ts +19 -2
  3. package/checks/checkApi.ts +79 -77
  4. package/checks/checkHook.ts +48 -0
  5. package/checks/checkMenu.ts +168 -0
  6. package/checks/checkPlugin.ts +48 -0
  7. package/checks/checkTable.ts +137 -183
  8. package/docs/README.md +17 -11
  9. package/docs/api/api.md +16 -2
  10. package/docs/guide/quickstart.md +31 -10
  11. package/docs/hooks/hook.md +2 -2
  12. package/docs/hooks/rateLimit.md +1 -1
  13. package/docs/infra/redis.md +26 -14
  14. package/docs/plugins/plugin.md +23 -21
  15. package/docs/quickstart.md +5 -328
  16. package/docs/reference/addon.md +0 -4
  17. package/docs/reference/config.md +14 -31
  18. package/docs/reference/logger.md +3 -3
  19. package/docs/reference/sync.md +132 -237
  20. package/docs/reference/table.md +28 -30
  21. package/hooks/auth.ts +3 -4
  22. package/hooks/cors.ts +4 -6
  23. package/hooks/parser.ts +3 -4
  24. package/hooks/permission.ts +3 -4
  25. package/hooks/validator.ts +3 -4
  26. package/lib/cacheHelper.ts +89 -153
  27. package/lib/cacheKeys.ts +1 -1
  28. package/lib/connect.ts +9 -13
  29. package/lib/dbDialect.ts +285 -0
  30. package/lib/dbHelper.ts +179 -507
  31. package/lib/dbUtils.ts +450 -0
  32. package/lib/logger.ts +41 -5
  33. package/lib/redisHelper.ts +1 -0
  34. package/lib/sqlBuilder.ts +358 -58
  35. package/lib/sqlCheck.ts +136 -0
  36. package/lib/validator.ts +1 -1
  37. package/loader/loadApis.ts +23 -126
  38. package/loader/loadHooks.ts +31 -46
  39. package/loader/loadPlugins.ts +37 -52
  40. package/main.ts +58 -19
  41. package/package.json +24 -25
  42. package/paths.ts +14 -14
  43. package/plugins/cache.ts +12 -6
  44. package/plugins/cipher.ts +2 -2
  45. package/plugins/config.ts +6 -8
  46. package/plugins/db.ts +14 -19
  47. package/plugins/jwt.ts +6 -7
  48. package/plugins/logger.ts +7 -9
  49. package/plugins/redis.ts +8 -10
  50. package/plugins/tool.ts +3 -4
  51. package/router/api.ts +3 -2
  52. package/router/static.ts +7 -5
  53. package/sync/syncApi.ts +80 -235
  54. package/sync/syncCache.ts +16 -0
  55. package/sync/syncDev.ts +167 -202
  56. package/sync/syncMenu.ts +230 -444
  57. package/sync/syncTable.ts +1247 -0
  58. package/tests/_mocks/mockSqliteDb.ts +204 -0
  59. package/tests/addonHelper-cache.test.ts +32 -0
  60. package/tests/apiHandler-routePath-only.test.ts +32 -0
  61. package/tests/cacheHelper.test.ts +16 -51
  62. package/tests/checkApi-routePath-strict.test.ts +166 -0
  63. package/tests/checkMenu.test.ts +346 -0
  64. package/tests/checkTable-smoke.test.ts +157 -0
  65. package/tests/dbDialect-cache.test.ts +23 -0
  66. package/tests/dbDialect.test.ts +46 -0
  67. package/tests/dbHelper-advanced.test.ts +1 -1
  68. package/tests/dbHelper-all-array-types.test.ts +15 -15
  69. package/tests/dbHelper-batch-write.test.ts +90 -0
  70. package/tests/dbHelper-columns.test.ts +36 -54
  71. package/tests/dbHelper-execute.test.ts +26 -26
  72. package/tests/dbHelper-joins.test.ts +85 -176
  73. package/tests/fixtures/scanFilesAddon/node_modules/@befly-addon/demo/apis/sub/b.ts +3 -0
  74. package/tests/fixtures/scanFilesApis/a.ts +3 -0
  75. package/tests/fixtures/scanFilesApis/sub/b.ts +3 -0
  76. package/tests/loadPlugins-order-smoke.test.ts +75 -0
  77. package/tests/logger.test.ts +6 -6
  78. package/tests/redisHelper.test.ts +6 -1
  79. package/tests/scanFiles-routePath.test.ts +46 -0
  80. package/tests/smoke-sql.test.ts +24 -0
  81. package/tests/sqlBuilder-advanced.test.ts +18 -5
  82. package/tests/sqlBuilder.test.ts +24 -0
  83. package/tests/sync-init-guard.test.ts +105 -0
  84. package/tests/syncApi-insBatch-fields-consistent.test.ts +61 -0
  85. package/tests/syncApi-obsolete-records.test.ts +69 -0
  86. package/tests/syncApi-type-compat.test.ts +72 -0
  87. package/tests/syncDev-permissions.test.ts +81 -0
  88. package/tests/syncMenu-disableMenus-hard-delete.test.ts +88 -0
  89. package/tests/syncMenu-duplicate-path.test.ts +122 -0
  90. package/tests/syncMenu-obsolete-records.test.ts +161 -0
  91. package/tests/syncMenu-parentPath-from-tree.test.ts +75 -0
  92. package/tests/syncMenu-paths.test.ts +0 -9
  93. package/tests/{syncDb-apply.test.ts → syncTable-apply.test.ts} +14 -24
  94. package/tests/{syncDb-array-number.test.ts → syncTable-array-number.test.ts} +31 -31
  95. package/tests/syncTable-constants.test.ts +101 -0
  96. package/tests/syncTable-db-integration.test.ts +237 -0
  97. package/tests/{syncDb-ddl.test.ts → syncTable-ddl.test.ts} +67 -53
  98. package/tests/{syncDb-helpers.test.ts → syncTable-helpers.test.ts} +12 -26
  99. package/tests/syncTable-schema.test.ts +99 -0
  100. package/tests/syncTable-testkit.test.ts +25 -0
  101. package/tests/syncTable-types.test.ts +122 -0
  102. package/tests/tableRef-and-deserialize.test.ts +67 -0
  103. package/tsconfig.json +1 -1
  104. package/types/api.d.ts +1 -1
  105. package/types/befly.d.ts +13 -12
  106. package/types/cache.d.ts +2 -2
  107. package/types/context.d.ts +1 -1
  108. package/types/database.d.ts +0 -5
  109. package/types/hook.d.ts +1 -10
  110. package/types/plugin.d.ts +2 -96
  111. package/types/sync.d.ts +19 -25
  112. package/utils/convertBigIntFields.ts +38 -0
  113. package/utils/disableMenusGlob.ts +85 -0
  114. package/utils/importDefault.ts +21 -0
  115. package/utils/isDirentDirectory.ts +23 -0
  116. package/utils/loadMenuConfigs.ts +145 -0
  117. package/utils/processFields.ts +25 -0
  118. package/utils/scanAddons.ts +72 -0
  119. package/utils/scanFiles.ts +129 -21
  120. package/utils/scanSources.ts +64 -0
  121. package/utils/sortModules.ts +137 -0
  122. package/checks/checkApp.ts +0 -55
  123. package/docs/cipher.md +0 -582
  124. package/docs/database.md +0 -1176
  125. package/hooks/rateLimit.ts +0 -276
  126. package/sync/syncAll.ts +0 -35
  127. package/sync/syncDb/apply.ts +0 -192
  128. package/sync/syncDb/constants.ts +0 -119
  129. package/sync/syncDb/ddl.ts +0 -251
  130. package/sync/syncDb/helpers.ts +0 -84
  131. package/sync/syncDb/schema.ts +0 -202
  132. package/sync/syncDb/sqlite.ts +0 -48
  133. package/sync/syncDb/table.ts +0 -207
  134. package/sync/syncDb/tableCreate.ts +0 -163
  135. package/sync/syncDb/types.ts +0 -132
  136. package/sync/syncDb/version.ts +0 -69
  137. package/sync/syncDb.ts +0 -168
  138. package/tests/rateLimit-hook.test.ts +0 -477
  139. package/tests/syncDb-constants.test.ts +0 -130
  140. package/tests/syncDb-schema.test.ts +0 -179
  141. package/tests/syncDb-types.test.ts +0 -139
  142. package/utils/addonHelper.ts +0 -90
  143. package/utils/modules.ts +0 -98
  144. package/utils/route.ts +0 -23
@@ -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: "role:admin:apis", members: ["GET/api/user", "POST/api/user"] },
225
- { key: "role:editor:apis", members: ["GET/api/article", "POST/api/article"] }
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: "role:admin:apis", member: "GET/api/user" },
235
- { key: "role:admin:apis", member: "DELETE/api/user" }
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 key = CacheKeys.apisAll(); // 'befly:apis:all'
289
- const key = CacheKeys.menusAll(); // 'befly:menus:all'
290
- const key = CacheKeys.roleInfo("admin"); // 'befly:role:info:admin'
291
- const key = CacheKeys.roleApis("admin"); // 'befly:role:apis:admin'
292
- const key = CacheKeys.tableColumns("user"); // 'befly:table:columns:user'
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
- 所有键会自动添加前缀:`myapp:user:1`
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, "POST/api/user/add");
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
- // 返回: ['GET/api/user/list', 'POST/api/user/add', ...]
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", "POST/api/user/add");
495
+ const hasPermission = await befly.cache.checkRolePermission("admin", "/api/user/add");
484
496
  // 返回: true 或 false
485
497
  ```
486
498
 
@@ -72,7 +72,7 @@ import type { Plugin } from "befly/types/plugin";
72
72
 
73
73
  const plugin: Plugin = {
74
74
  // 依赖的插件列表(可选)
75
- after: ["logger", "db"],
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
- after?: string[];
99
+ deps: string[];
100
100
 
101
101
  /** 插件初始化函数 */
102
- handler?: (context: BeflyContext) => any | Promise<any>;
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
- 使用 `after` 属性声明依赖关系:
174
+ 使用 `deps` 属性声明依赖关系:
175
175
 
176
176
  ```typescript
177
177
  // redis.ts - 依赖 logger
178
178
  const plugin: Plugin = {
179
- after: ["logger"], // 在 logger 插件之后初始化
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
- after: [],
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
- after: ["logger"],
253
+ deps: ["logger", "redis"],
254
254
  async handler(befly: BeflyContext): Promise<DbHelper> {
255
- const sql = await Connect.connectSql();
256
- return new DbHelper(befly, sql);
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
- after: ["logger"],
289
+ deps: ["logger"],
289
290
  async handler(): Promise<RedisHelper | Record<string, never>> {
290
- await Connect.connectRedis();
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
- after: [],
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
- after: ["db", "redis"], // 依赖数据库和 Redis
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
- after: ["logger", "config"],
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
- after: ["logger", "config"],
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
- after: ["db", "logger", "config"],
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
- after: ["logger", "config"],
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
- after: ["logger", "db", "redis"], // 声明所有使用的插件
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. 同一类型内根据 `after` 依赖关系排序
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
- after: ["db"], // 声明依赖
943
+ deps: ["db"], // 声明依赖
942
944
  handler: (befly) => {
943
945
  return {
944
946
  async getUser(id: number) {
@@ -1,331 +1,8 @@
1
- # Quickstart 快速入门
1
+ # Quickstart 快速入门(已迁移)
2
2
 
3
- > 5 分钟搭建你的第一个 Befly API 服务
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 规则等都以当前实现为准)。
@@ -465,10 +465,6 @@ A: 在配置文件中设置:
465
465
  }
466
466
  ```
467
467
 
468
- ### Q: Addon 的表如何迁移?
469
-
470
- A: 使用 `befly sync:db` 命令,会自动同步所有 Addon 的表定义。
471
-
472
468
  ### Q: 如何在 Addon 中访问项目配置?
473
469
 
474
470
  A: 通过 `befly.config` 访问:
@@ -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'` | 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 前缀 |
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 = beflyConfig.appPort;
472
- const dbConfig = beflyConfig.db;
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
  ## 最佳实践