befly 3.3.0 → 3.3.2

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 CHANGED
@@ -1,3 +1,246 @@
1
- # Befly - 蜜蜂飞舞
1
+ # Befly - 野蜂飞舞
2
2
 
3
- 道生一,一生二,二生三,三生万物,v3 版本发布后可才是公测版本。
3
+ ![野蜂飞舞](https://static.yicode.tech/befly.svg)
4
+
5
+ > 道生一,一生二,二生三,三生万物
6
+
7
+ **Befly 3.0 - TypeScript 重构版本已发布!**
8
+
9
+ ## 🎯 简介
10
+
11
+ Befly 是专为 Bun 运行时设计的现代化 API 框架,提供:
12
+
13
+ - ⚡ **原生 TypeScript 支持** - 完整的类型定义和智能提示
14
+ - 🚀 **高性能** - 基于 Bun 运行时,超快的启动和执行速度
15
+ - 🔌 **插件化架构** - 灵活的插件系统,轻松扩展功能
16
+ - 🗄️ **多数据库支持** - MySQL、PostgreSQL、SQLite 统一接口
17
+ - 📝 **自动化表管理** - 基于 JSON 的表定义,自动同步数据库结构
18
+ - 🔐 **内置身份验证** - JWT 认证,角色权限管理
19
+ - 📊 **完整日志系统** - 结构化日志,敏感字段过滤
20
+
21
+ ## 📦 快速开始
22
+
23
+ ### 安装
24
+
25
+ ```bash
26
+ # 创建新项目
27
+ mkdir my-api && cd my-api
28
+
29
+ # 安装 Befly
30
+ bun add befly
31
+
32
+ # 初始化项目(即将支持)
33
+ bunx befly init
34
+ ```
35
+
36
+ ### 最简示例
37
+
38
+ ```typescript
39
+ // main.ts
40
+ import { Server } from 'befly';
41
+
42
+ await Server({
43
+ name: 'My API',
44
+ port: 3000
45
+ });
46
+ ```
47
+
48
+ 运行项目:
49
+
50
+ ```bash
51
+ bun run main.ts
52
+ ```
53
+
54
+ ### 创建第一个接口
55
+
56
+ ```typescript
57
+ // apis/user/hello.ts
58
+ import { Yes } from 'befly';
59
+ import type { ApiRoute } from 'befly';
60
+
61
+ export default {
62
+ name: '问候接口',
63
+ auth: false, // 公开接口
64
+ fields: {},
65
+ handler: async (befly, ctx) => {
66
+ return Yes('Hello, Befly!', {
67
+ timestamp: Date.now()
68
+ });
69
+ }
70
+ } as ApiRoute;
71
+ ```
72
+
73
+ 访问:`http://localhost:3000/api/user/hello`
74
+
75
+ ## 🔥 新版本特性(3.0)
76
+
77
+ ### TypeScript 全面支持
78
+
79
+ ```typescript
80
+ import { Yes } from 'befly';
81
+ import type { ApiRoute, BeflyContext } from 'befly';
82
+ import type { User } from './types/models';
83
+
84
+ export default {
85
+ name: '获取用户',
86
+ auth: true,
87
+ fields: {
88
+ id: '用户ID|number|1|999999|null|1|null'
89
+ },
90
+ required: ['id'],
91
+ handler: async (befly: BeflyContext, ctx) => {
92
+ const { id } = ctx.body;
93
+
94
+ // 类型安全的数据库查询
95
+ const user = await befly.db.getOne<User>({
96
+ table: 'user',
97
+ where: { id }
98
+ });
99
+
100
+ return Yes('查询成功', user);
101
+ }
102
+ } as ApiRoute;
103
+ ```
104
+
105
+ ### 增强的数据库操作
106
+
107
+ ```typescript
108
+ // 查询单条
109
+ const user = await befly.db.getOne<User>({
110
+ table: 'user',
111
+ where: { id: 1 }
112
+ });
113
+
114
+ // 分页列表
115
+ const result = await befly.db.getList<Product>({
116
+ table: 'product',
117
+ where: { category: 'electronics' },
118
+ page: 1,
119
+ limit: 10,
120
+ orderBy: ['createdAt#DESC']
121
+ });
122
+
123
+ // 插入数据
124
+ await befly.db.insData({
125
+ table: 'user',
126
+ data: {
127
+ username: 'john',
128
+ email: 'john@example.com'
129
+ }
130
+ });
131
+
132
+ // 更新数据
133
+ await befly.db.updData({
134
+ table: 'user',
135
+ where: { id: 1 },
136
+ data: {
137
+ nickname: 'John Doe'
138
+ }
139
+ });
140
+
141
+ // 删除数据
142
+ await befly.db.delData({
143
+ table: 'user',
144
+ where: { id: 1 }
145
+ });
146
+ ```
147
+
148
+ ### 智能表定义
149
+
150
+ ```json
151
+ {
152
+ "username": "用户名|string|3|50|null|1|^[a-zA-Z0-9_]+$",
153
+ "email": "邮箱|string|5|100|null|1|^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$",
154
+ "age": "年龄|number|0|150|18|0|null",
155
+ "tags": "标签|array_string|0|10|null|0|null",
156
+ "bio": "简介|text|0|5000|null|0|null"
157
+ }
158
+ ```
159
+
160
+ 字段定义格式:`"字段名|类型|最小值|最大值|默认值|是否索引|正则约束"`
161
+
162
+ 同步到数据库:
163
+
164
+ ```bash
165
+ bun run scripts/syncDb.ts
166
+ ```
167
+
168
+ ## 🗄️ 数据库配置
169
+
170
+ 统一使用环境变量配置,支持三种数据库:
171
+
172
+ ```bash
173
+ # MySQL
174
+ DB_TYPE=mysql
175
+ DB_HOST=127.0.0.1
176
+ DB_PORT=3306
177
+ DB_USER=root
178
+ DB_PASS=password
179
+ DB_NAME=my_database
180
+
181
+ # PostgreSQL
182
+ DB_TYPE=postgresql
183
+ DB_HOST=localhost
184
+ DB_PORT=5432
185
+ DB_USER=postgres
186
+ DB_PASS=password
187
+ DB_NAME=my_database
188
+
189
+ # SQLite
190
+ DB_TYPE=sqlite
191
+ DB_NAME=/path/to/database.sqlite
192
+ # 或使用内存数据库
193
+ DB_NAME=:memory:
194
+ ```
195
+
196
+ ## 📖 文档
197
+
198
+ 完整文档请访问 [`/docs` 目录](./docs/):
199
+
200
+ - [快速开始](./docs/02-快速上手/01-10分钟体验.md)
201
+ - [核心概念](./docs/03-核心概念/)
202
+ - [API 开发](./docs/04-API开发/)
203
+ - [数据库操作](./docs/05-数据库/)
204
+ - [TypeScript 支持](./docs/10-TypeScript/01-TypeScript支持.md)
205
+
206
+ ### 目录说明
207
+
208
+ - **`packages/core`** - Befly 核心框架包(发布到 npm)
209
+ - **`packages/tpl`** - API 项目模板示例
210
+ - **`packages/admin`** - 后台管理系统(Vue3 + TinyVue + 自动导入)
211
+
212
+ ## 🚀 快速启动
213
+
214
+ ### 启动 API 服务
215
+
216
+ ```bash
217
+ bun run dev
218
+ # 访问: http://localhost:3000
219
+ ```
220
+
221
+ ### 启动后台管理
222
+
223
+ ```bash
224
+ bun run dev:admin
225
+ # 访问: http://localhost:5173
226
+ ```
227
+
228
+ ## 🎓 示例项目
229
+
230
+ 查看 `/tpl` 目录获取完整的示例项目。
231
+
232
+ ## 🤝 贡献
233
+
234
+ 欢迎提交 Issue 和 Pull Request!
235
+
236
+ ## 📄 许可
237
+
238
+ MIT License
239
+
240
+ ## 🌟 致谢
241
+
242
+ 感谢所有为 Befly 做出贡献的开发者!
243
+
244
+ ---
245
+
246
+ **Befly 3.0 - 让 API 开发更简单、更高效!** 🚀
@@ -105,27 +105,22 @@ function scanCliScripts(): Array<{ scriptName: string; scriptPath: string }> {
105
105
  }
106
106
 
107
107
  /**
108
- * 扫描 node_modules/@befly/addon-* 下的 scripts
108
+ * 扫描 node_modules/@befly-addon/* 下的 scripts
109
109
  */
110
110
  function scanAddonScripts(projectRoot: string): Array<{ addonName: string; scriptName: string; scriptPath: string }> {
111
111
  const results: Array<{ addonName: string; scriptName: string; scriptPath: string }> = [];
112
112
 
113
113
  try {
114
- const beflyAddonsDir = join(projectRoot, 'node_modules', '@befly');
114
+ const beflyAddonsDir = join(projectRoot, 'node_modules', '@befly-addon');
115
115
 
116
116
  if (!existsSync(beflyAddonsDir)) {
117
117
  return results;
118
118
  }
119
119
 
120
- // 读取 @befly 目录下的所有 addon
120
+ // 读取 @befly-addon 目录下的所有 addon
121
121
  const addonDirs = readdirSync(beflyAddonsDir);
122
122
 
123
123
  for (const addonDir of addonDirs) {
124
- // 只处理 addon-* 开头的目录
125
- if (!addonDir.startsWith('addon-')) {
126
- continue;
127
- }
128
-
129
124
  const scriptsDir = join(beflyAddonsDir, addonDir, 'scripts');
130
125
 
131
126
  if (!existsSync(scriptsDir)) {
@@ -5,7 +5,7 @@
5
5
  * 流程:
6
6
  * 1. 扫描 core/apis 目录下所有 Core API 文件
7
7
  * 2. 扫描项目 apis 目录下所有项目 API 文件
8
- * 3. 扫描 node_modules/@befly/addon-* 目录下所有组件 API 文件
8
+ * 3. 扫描 node_modules/@befly-addon/* 目录下所有组件 API 文件
9
9
  * 4. 提取每个 API 的 name、method、auth 等信息
10
10
  * 5. 根据接口路径检查是否存在
11
11
  * 6. 存在则更新,不存在则新增
@@ -138,24 +138,23 @@ async function scanAllApis(projectRoot: string): Promise<ApiInfo[]> {
138
138
  }
139
139
  }
140
140
 
141
- // 3. 扫描组件 API (node_modules/@befly/addon-*)
142
- Logger.info('\n=== 扫描组件 API (node_modules/@befly/addon-*) ===');
141
+ // 3. 扫描组件 API (node_modules/@befly-addon/*)
142
+ Logger.info('\n=== 扫描组件 API (node_modules/@befly-addon/*) ===');
143
143
  const addonNames = scanAddons();
144
144
 
145
- for (const fullAddonName of addonNames) {
146
- // fullAddonName 格式: addon-admin, addon-demo 等
147
- const addonName = fullAddonName.replace('addon-', ''); // 移除 addon- 前缀
145
+ for (const addonName of addonNames) {
146
+ // addonName 格式: admin, demo 等
148
147
 
149
148
  // 检查 apis 子目录是否存在
150
- if (!addonDirExists(fullAddonName, 'apis')) {
149
+ if (!addonDirExists(addonName, 'apis')) {
151
150
  Logger.info(` [${addonName}] 无 apis 目录,跳过`);
152
151
  continue;
153
152
  }
154
153
 
155
- const addonApisDir = getAddonDir(fullAddonName, 'apis');
154
+ const addonApisDir = getAddonDir(addonName, 'apis');
156
155
 
157
156
  // 读取 addon 配置
158
- const addonConfigPath = getAddonDir(fullAddonName, 'addon.config.json');
157
+ const addonConfigPath = getAddonDir(addonName, 'addon.config.json');
159
158
  let addonTitle = addonName;
160
159
  try {
161
160
  const configFile = Bun.file(addonConfigPath);
@@ -139,8 +139,8 @@ export const SyncDb = async (): Promise<void> => {
139
139
  // 确定表名:
140
140
  // - core 表:core_{表名}
141
141
  // 例如:user.json → core_user
142
- // - addon 表:addon_{转换后的addonName}_{表名}
143
- // 例如:addon-admin 的 user.json → core_user
142
+ // - addon 表:{addonName}_{表名}
143
+ // 例如:admin addon 的 user.json → admin_user
144
144
  // - 项目表:{表名}
145
145
  // 例如:user.json → user
146
146
  let tableName = snakeCase(fileName);
@@ -148,8 +148,8 @@ export const SyncDb = async (): Promise<void> => {
148
148
  // core 框架表,添加 core_ 前缀
149
149
  tableName = `core_${tableName}`;
150
150
  } else if (type === 'addon') {
151
- // addon 表,添加 addon_{name}_ 前缀
152
- // 使用 snakeCase 统一转换(addon-admin → addon_admin
151
+ // addon 表,添加 {addonName}_ 前缀
152
+ // 使用 snakeCase 统一转换(admin → admin
153
153
  const addonNameSnake = snakeCase(addonName!);
154
154
  tableName = `${addonNameSnake}_${tableName}`;
155
155
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "befly",
3
- "version": "3.3.0",
3
+ "version": "3.3.2",
4
4
  "description": "Befly - 为 Bun 专属打造的 TypeScript API 接口框架核心引擎",
5
5
  "type": "module",
6
6
  "private": false,
@@ -50,6 +50,7 @@
50
50
  "lifecycle/",
51
51
  "plugins/",
52
52
  "router/",
53
+ "tables/",
53
54
  "types/",
54
55
  ".gitignore",
55
56
  ".npmignore",
@@ -78,5 +79,5 @@
78
79
  "ora": "^9.0.0",
79
80
  "pathe": "^2.0.3"
80
81
  },
81
- "gitHead": "24b35d0ef83d78db3dea67784e052516d4a83fc5"
82
+ "gitHead": "031b4a753e40d888648335a9ff4e085ba42010ad"
82
83
  }
@@ -0,0 +1,14 @@
1
+ {
2
+ "name": "姓名|string|2|50|null|0|null",
3
+ "nickname": "昵称|string|2|50|null|0|null",
4
+ "email": "邮箱|string|5|100|null|1|^[\\w.-]+@[\\w.-]+\\.\\w+$",
5
+ "phone": "手机号|string|11|11|null|0|^1[3-9]\\d{9}$",
6
+ "username": "用户名|string|3|30|null|0|^[a-zA-Z0-9_]+$",
7
+ "password": "密码|string|6|500|null|0|null",
8
+ "avatar": "头像|string|0|500|null|0|null",
9
+ "roleId": "角色ID|number|1|999999999999999|null|1|null",
10
+ "roleCode": "角色编码|string|2|50|null|0|^[a-zA-Z0-9_]+$",
11
+ "roleType": "角色类型|string|4|5|user|1|^(admin|user)$",
12
+ "lastLoginTime": "最后登录时间|number|0|null|0|0|null",
13
+ "lastLoginIp": "最后登录IP|string|0|50|null|0|null"
14
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "name": "接口名称|string|2|100|null|1|null",
3
+ "path": "接口路径|string|1|200|null|1|null",
4
+ "method": "请求方法|string|3|10|POST|1|^(GET|POST|PUT|DELETE|PATCH)$",
5
+ "description": "接口描述|string|0|500|null|0|null",
6
+ "addonName": "所属插件|string|0|50|null|0|null",
7
+ "addonTitle": "插件标题|string|0|100|null|0|null"
8
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "name": "字典名称|string|2|50|null|1|null",
3
+ "code": "字典代码|string|2|50|null|1|^[a-zA-Z0-9_]+$",
4
+ "value": "字典值|string|0|200|null|1|null",
5
+ "sort": "排序|number|0|9999|0|0|null",
6
+ "pid": "父级ID|number|0|999999999999999|0|1|null",
7
+ "description": "描述|string|0|200|null|0|null"
8
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "name": "菜单名称|string|2|50|null|1|null",
3
+ "path": "路由路径|string|1|200|null|1|null",
4
+ "icon": "图标名称|string|0|50|null|0|null",
5
+ "sort": "排序|number|0|9999|0|0|null",
6
+ "pid": "父级ID|number|0|999999999999999|0|1|null",
7
+ "type": "菜单类型|number|1|2|1|1|^(1|2)$"
8
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "name": "角色名称|string|2|50|null|1|null",
3
+ "code": "角色编码|string|2|50|null|1|^[a-zA-Z0-9_]+$",
4
+ "description": "角色描述|string|0|200|null|0|null",
5
+ "menus": "菜单权限|array_text|null|null|null|0|null",
6
+ "apis": "接口权限|array_text|null|null|null|0|null",
7
+ "sort": "排序|number|0|9999|0|0|null"
8
+ }
package/util.ts CHANGED
@@ -241,7 +241,7 @@ export const parseRule = (rule: string): ParsedFieldRule => {
241
241
  * 扫描所有可用的 addon
242
242
  */
243
243
  export const scanAddons = (): string[] => {
244
- const beflyDir = join(paths.projectDir, 'node_modules', '@befly');
244
+ const beflyDir = join(paths.projectDir, 'node_modules', '@befly-addon');
245
245
 
246
246
  if (!existsSync(beflyDir)) {
247
247
  return [];
@@ -251,9 +251,7 @@ export const scanAddons = (): string[] => {
251
251
  return fs
252
252
  .readdirSync(beflyDir)
253
253
  .filter((name) => {
254
- // 先转为 kebab-case 格式再判断
255
- const kebabName = kebabCase(name);
256
- if (!kebabName.startsWith('addon-')) return false;
254
+ // addon 名称格式:admin, demo 等(不带 addon- 前缀)
257
255
  const fullPath = join(beflyDir, name);
258
256
  try {
259
257
  const stat = statSync(fullPath);
@@ -272,7 +270,7 @@ export const scanAddons = (): string[] => {
272
270
  * 获取 addon 的指定子目录路径
273
271
  */
274
272
  export const getAddonDir = (addonName: string, subDir: string): string => {
275
- return join(paths.projectDir, 'node_modules', '@befly', addonName, subDir);
273
+ return join(paths.projectDir, 'node_modules', '@befly-addon', addonName, subDir);
276
274
  };
277
275
 
278
276
  /**