befly 3.9.37 → 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 +38 -39
- 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} +225 -235
- package/docs/cipher.md +71 -69
- package/docs/database.md +155 -153
- 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} +7 -7
- 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 +15 -7
- package/lib/asyncContext.ts +43 -0
- package/lib/cacheHelper.ts +212 -81
- package/lib/cacheKeys.ts +38 -0
- package/lib/cipher.ts +30 -30
- package/lib/connect.ts +28 -28
- package/lib/dbHelper.ts +211 -109
- 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 +53 -47
- 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 -54
- 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 -66
- package/sync/syncMenu.ts +190 -57
- 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
|
@@ -68,11 +68,11 @@ Befly 插件系统是框架的核心扩展机制,允许开发者封装和复
|
|
|
68
68
|
### 基础结构
|
|
69
69
|
|
|
70
70
|
```typescript
|
|
71
|
-
import type { Plugin } from
|
|
71
|
+
import type { Plugin } from "befly/types/plugin";
|
|
72
72
|
|
|
73
73
|
const plugin: Plugin = {
|
|
74
74
|
// 依赖的插件列表(可选)
|
|
75
|
-
after: [
|
|
75
|
+
after: ["logger", "db"],
|
|
76
76
|
|
|
77
77
|
// 初始化函数(必填)
|
|
78
78
|
handler: (befly) => {
|
|
@@ -176,7 +176,7 @@ interface Plugin {
|
|
|
176
176
|
```typescript
|
|
177
177
|
// redis.ts - 依赖 logger
|
|
178
178
|
const plugin: Plugin = {
|
|
179
|
-
after: [
|
|
179
|
+
after: ["logger"], // 在 logger 插件之后初始化
|
|
180
180
|
handler: () => {
|
|
181
181
|
/* ... */
|
|
182
182
|
}
|
|
@@ -212,10 +212,10 @@ const loggerPlugin: Plugin = {
|
|
|
212
212
|
**使用方式**:
|
|
213
213
|
|
|
214
214
|
```typescript
|
|
215
|
-
befly.logger.info(
|
|
216
|
-
befly.logger.warn(
|
|
217
|
-
befly.logger.error({ err: error },
|
|
218
|
-
befly.logger.debug(
|
|
215
|
+
befly.logger.info("信息日志");
|
|
216
|
+
befly.logger.warn("警告日志");
|
|
217
|
+
befly.logger.error({ err: error }, "错误日志");
|
|
218
|
+
befly.logger.debug("调试日志");
|
|
219
219
|
```
|
|
220
220
|
|
|
221
221
|
---
|
|
@@ -250,7 +250,7 @@ const redisConfig = befly.config.redis;
|
|
|
250
250
|
```typescript
|
|
251
251
|
// 插件源码
|
|
252
252
|
const dbPlugin: Plugin = {
|
|
253
|
-
after: [
|
|
253
|
+
after: ["logger"],
|
|
254
254
|
async handler(befly: BeflyContext): Promise<DbHelper> {
|
|
255
255
|
const sql = await Connect.connectSql();
|
|
256
256
|
return new DbHelper(befly, sql);
|
|
@@ -262,16 +262,16 @@ const dbPlugin: Plugin = {
|
|
|
262
262
|
|
|
263
263
|
```typescript
|
|
264
264
|
// 查询
|
|
265
|
-
const user = await befly.db.getOne({ table:
|
|
265
|
+
const user = await befly.db.getOne({ table: "user", where: { id: 1 } });
|
|
266
266
|
|
|
267
267
|
// 插入
|
|
268
|
-
const id = await befly.db.insData({ table:
|
|
268
|
+
const id = await befly.db.insData({ table: "user", data: { name: "张三" } });
|
|
269
269
|
|
|
270
270
|
// 更新
|
|
271
|
-
await befly.db.updData({ table:
|
|
271
|
+
await befly.db.updData({ table: "user", data: { name: "李四" }, where: { id: 1 } });
|
|
272
272
|
|
|
273
273
|
// 删除
|
|
274
|
-
await befly.db.delData({ table:
|
|
274
|
+
await befly.db.delData({ table: "user", where: { id: 1 } });
|
|
275
275
|
```
|
|
276
276
|
|
|
277
277
|
> 详细用法请参考 [database.md](./database.md)
|
|
@@ -285,7 +285,7 @@ await befly.db.delData({ table: 'user', where: { id: 1 } });
|
|
|
285
285
|
```typescript
|
|
286
286
|
// 插件源码
|
|
287
287
|
const redisPlugin: Plugin = {
|
|
288
|
-
after: [
|
|
288
|
+
after: ["logger"],
|
|
289
289
|
async handler(): Promise<RedisHelper | Record<string, never>> {
|
|
290
290
|
await Connect.connectRedis();
|
|
291
291
|
return new RedisHelper(redisConfig.prefix);
|
|
@@ -297,19 +297,19 @@ const redisPlugin: Plugin = {
|
|
|
297
297
|
|
|
298
298
|
```typescript
|
|
299
299
|
// 字符串操作
|
|
300
|
-
await befly.redis.setString(
|
|
301
|
-
const value = await befly.redis.getString(
|
|
300
|
+
await befly.redis.setString("key", "value", 3600);
|
|
301
|
+
const value = await befly.redis.getString("key");
|
|
302
302
|
|
|
303
303
|
// 对象操作
|
|
304
|
-
await befly.redis.setObject(
|
|
305
|
-
const user = await befly.redis.getObject(
|
|
304
|
+
await befly.redis.setObject("user:1", { name: "张三" });
|
|
305
|
+
const user = await befly.redis.getObject("user:1");
|
|
306
306
|
|
|
307
307
|
// 集合操作
|
|
308
|
-
await befly.redis.sadd(
|
|
309
|
-
const isMember = await befly.redis.sismember(
|
|
308
|
+
await befly.redis.sadd("set:key", "member1", "member2");
|
|
309
|
+
const isMember = await befly.redis.sismember("set:key", "member1");
|
|
310
310
|
```
|
|
311
311
|
|
|
312
|
-
> 详细用法请参考 [redis.md](
|
|
312
|
+
> 详细用法请参考 [redis.md](../infra/redis.md)
|
|
313
313
|
|
|
314
314
|
---
|
|
315
315
|
|
|
@@ -335,7 +335,7 @@ const token = await befly.jwt.sign(
|
|
|
335
335
|
id: user.id,
|
|
336
336
|
roleCode: user.roleCode
|
|
337
337
|
},
|
|
338
|
-
{ expiresIn:
|
|
338
|
+
{ expiresIn: "7d" }
|
|
339
339
|
);
|
|
340
340
|
|
|
341
341
|
// 验证 Token
|
|
@@ -361,18 +361,20 @@ const plugin: Plugin = {
|
|
|
361
361
|
|
|
362
362
|
```typescript
|
|
363
363
|
// 密码哈希
|
|
364
|
-
const hashedPassword = await befly.cipher.hashPassword(
|
|
364
|
+
const hashedPassword = await befly.cipher.hashPassword("123456");
|
|
365
365
|
|
|
366
366
|
// 密码验证
|
|
367
|
-
const isValid = await befly.cipher.verifyPassword(
|
|
367
|
+
const isValid = await befly.cipher.verifyPassword("123456", hashedPassword);
|
|
368
368
|
|
|
369
369
|
// AES 加密
|
|
370
|
-
const encrypted = befly.cipher.encrypt(
|
|
370
|
+
const encrypted = befly.cipher.encrypt("敏感数据");
|
|
371
371
|
|
|
372
372
|
// AES 解密
|
|
373
373
|
const decrypted = befly.cipher.decrypt(encrypted);
|
|
374
374
|
```
|
|
375
375
|
|
|
376
|
+
> 详细用法请参考 [cipher.md](./cipher.md)
|
|
377
|
+
|
|
376
378
|
---
|
|
377
379
|
|
|
378
380
|
### cache - 缓存插件
|
|
@@ -393,7 +395,7 @@ const cachePlugin: Plugin = {
|
|
|
393
395
|
|
|
394
396
|
```typescript
|
|
395
397
|
// 刷新角色权限缓存
|
|
396
|
-
await befly.cache.refreshRoleApis(
|
|
398
|
+
await befly.cache.refreshRoleApis("admin");
|
|
397
399
|
|
|
398
400
|
// 获取菜单缓存
|
|
399
401
|
const menus = await befly.cache.getMenus();
|
|
@@ -424,11 +426,11 @@ const plugin: Plugin = {
|
|
|
424
426
|
|
|
425
427
|
```typescript
|
|
426
428
|
// 成功响应
|
|
427
|
-
return befly.tool.Yes(
|
|
429
|
+
return befly.tool.Yes("操作成功", { id: 1 });
|
|
428
430
|
// 返回: { code: 0, msg: '操作成功', data: { id: 1 } }
|
|
429
431
|
|
|
430
432
|
// 失败响应
|
|
431
|
-
return befly.tool.No(
|
|
433
|
+
return befly.tool.No("操作失败");
|
|
432
434
|
// 返回: { code: 1, msg: '操作失败', data: null }
|
|
433
435
|
```
|
|
434
436
|
|
|
@@ -440,7 +442,7 @@ return befly.tool.No('操作失败');
|
|
|
440
442
|
|
|
441
443
|
```typescript
|
|
442
444
|
// plugins/hello.ts
|
|
443
|
-
import type { Plugin } from
|
|
445
|
+
import type { Plugin } from "befly/types/plugin";
|
|
444
446
|
|
|
445
447
|
const plugin: Plugin = {
|
|
446
448
|
handler: () => {
|
|
@@ -457,7 +459,7 @@ export default plugin;
|
|
|
457
459
|
|
|
458
460
|
```typescript
|
|
459
461
|
// 项目插件名为 app_hello
|
|
460
|
-
const greeting = befly.app_hello.sayHello(
|
|
462
|
+
const greeting = befly.app_hello.sayHello("World");
|
|
461
463
|
// 返回: "Hello, World!"
|
|
462
464
|
```
|
|
463
465
|
|
|
@@ -467,11 +469,11 @@ const greeting = befly.app_hello.sayHello('World');
|
|
|
467
469
|
|
|
468
470
|
```typescript
|
|
469
471
|
// plugins/userService.ts
|
|
470
|
-
import type { Plugin } from
|
|
471
|
-
import type { BeflyContext } from
|
|
472
|
+
import type { Plugin } from "befly/types/plugin";
|
|
473
|
+
import type { BeflyContext } from "befly/types/befly";
|
|
472
474
|
|
|
473
475
|
const plugin: Plugin = {
|
|
474
|
-
after: [
|
|
476
|
+
after: ["db", "redis"], // 依赖数据库和 Redis
|
|
475
477
|
handler: (befly: BeflyContext) => {
|
|
476
478
|
return {
|
|
477
479
|
async getUser(id: number) {
|
|
@@ -482,7 +484,7 @@ const plugin: Plugin = {
|
|
|
482
484
|
if (!user) {
|
|
483
485
|
// 缓存不存在,从数据库查询
|
|
484
486
|
user = await befly.db.getOne({
|
|
485
|
-
table:
|
|
487
|
+
table: "user",
|
|
486
488
|
where: { id: id }
|
|
487
489
|
});
|
|
488
490
|
|
|
@@ -507,25 +509,25 @@ export default plugin;
|
|
|
507
509
|
|
|
508
510
|
```typescript
|
|
509
511
|
// plugins/elastic.ts
|
|
510
|
-
import type { Plugin } from
|
|
511
|
-
import { Client } from
|
|
512
|
+
import type { Plugin } from "befly/types/plugin";
|
|
513
|
+
import { Client } from "@elastic/elasticsearch";
|
|
512
514
|
|
|
513
515
|
const plugin: Plugin = {
|
|
514
|
-
after: [
|
|
516
|
+
after: ["logger", "config"],
|
|
515
517
|
async handler(befly) {
|
|
516
518
|
const config = befly.config.elasticsearch || {};
|
|
517
519
|
|
|
518
520
|
const client = new Client({
|
|
519
|
-
node: config.node ||
|
|
521
|
+
node: config.node || "http://localhost:9200",
|
|
520
522
|
auth: config.auth
|
|
521
523
|
});
|
|
522
524
|
|
|
523
525
|
// 测试连接
|
|
524
526
|
try {
|
|
525
527
|
await client.ping();
|
|
526
|
-
befly.logger.info(
|
|
528
|
+
befly.logger.info("Elasticsearch 连接成功");
|
|
527
529
|
} catch (error) {
|
|
528
|
-
befly.logger.error({ err: error },
|
|
530
|
+
befly.logger.error({ err: error }, "Elasticsearch 连接失败");
|
|
529
531
|
throw error;
|
|
530
532
|
}
|
|
531
533
|
|
|
@@ -550,8 +552,8 @@ export default plugin;
|
|
|
550
552
|
|
|
551
553
|
```typescript
|
|
552
554
|
// plugins/sms.ts
|
|
553
|
-
import type { Plugin } from
|
|
554
|
-
import type { BeflyContext } from
|
|
555
|
+
import type { Plugin } from "befly/types/plugin";
|
|
556
|
+
import type { BeflyContext } from "befly/types/befly";
|
|
555
557
|
|
|
556
558
|
interface SmsConfig {
|
|
557
559
|
accessKeyId: string;
|
|
@@ -571,14 +573,14 @@ class SmsHelper {
|
|
|
571
573
|
|
|
572
574
|
async send(phone: string, params: Record<string, string>) {
|
|
573
575
|
// 实现短信发送逻辑
|
|
574
|
-
this.befly.logger.info({ phone: phone },
|
|
576
|
+
this.befly.logger.info({ phone: phone }, "发送短信");
|
|
575
577
|
// ...
|
|
576
578
|
return { success: true };
|
|
577
579
|
}
|
|
578
580
|
}
|
|
579
581
|
|
|
580
582
|
const plugin: Plugin = {
|
|
581
|
-
after: [
|
|
583
|
+
after: ["logger", "config"],
|
|
582
584
|
handler: (befly: BeflyContext) => {
|
|
583
585
|
const smsConfig = befly.config.sms || {};
|
|
584
586
|
return new SmsHelper(befly, smsConfig);
|
|
@@ -596,10 +598,10 @@ export default plugin;
|
|
|
596
598
|
|
|
597
599
|
```typescript
|
|
598
600
|
// addonAdmin/plugins/email.ts
|
|
599
|
-
import nodemailer from
|
|
600
|
-
import type { Transporter } from
|
|
601
|
-
import type { Plugin } from
|
|
602
|
-
import type { BeflyContext } from
|
|
601
|
+
import nodemailer from "nodemailer";
|
|
602
|
+
import type { Transporter } from "nodemailer";
|
|
603
|
+
import type { Plugin } from "befly/types/plugin";
|
|
604
|
+
import type { BeflyContext } from "befly/types/befly";
|
|
603
605
|
|
|
604
606
|
/** 邮件配置 */
|
|
605
607
|
interface EmailConfig {
|
|
@@ -653,7 +655,7 @@ class EmailHelper {
|
|
|
653
655
|
|
|
654
656
|
async send(options: SendEmailOptions): Promise<SendEmailResult> {
|
|
655
657
|
if (!this.transporter) {
|
|
656
|
-
return { success: false, error:
|
|
658
|
+
return { success: false, error: "邮件服务未配置" };
|
|
657
659
|
}
|
|
658
660
|
|
|
659
661
|
try {
|
|
@@ -686,7 +688,7 @@ class EmailHelper {
|
|
|
686
688
|
* 邮件插件
|
|
687
689
|
*/
|
|
688
690
|
const emailPlugin: Plugin = {
|
|
689
|
-
after: [
|
|
691
|
+
after: ["db", "logger", "config"],
|
|
690
692
|
async handler(befly: BeflyContext): Promise<EmailHelper> {
|
|
691
693
|
const emailConfig = befly.config?.addons?.admin?.email || {};
|
|
692
694
|
return new EmailHelper(befly, emailConfig);
|
|
@@ -701,15 +703,15 @@ export default emailPlugin;
|
|
|
701
703
|
```typescript
|
|
702
704
|
// Addon 插件名为 addon_addonAdmin_email
|
|
703
705
|
const result = await befly.addon_addonAdmin_email.send({
|
|
704
|
-
to:
|
|
705
|
-
subject:
|
|
706
|
-
html:
|
|
706
|
+
to: "user@example.com",
|
|
707
|
+
subject: "验证码",
|
|
708
|
+
html: "<p>您的验证码是:123456</p>"
|
|
707
709
|
});
|
|
708
710
|
|
|
709
711
|
if (result.success) {
|
|
710
|
-
return befly.tool.Yes(
|
|
712
|
+
return befly.tool.Yes("邮件发送成功");
|
|
711
713
|
} else {
|
|
712
|
-
return befly.tool.No(result.error ||
|
|
714
|
+
return befly.tool.No(result.error || "邮件发送失败");
|
|
713
715
|
}
|
|
714
716
|
```
|
|
715
717
|
|
|
@@ -722,22 +724,22 @@ if (result.success) {
|
|
|
722
724
|
```typescript
|
|
723
725
|
// 在 API handler 中
|
|
724
726
|
export default {
|
|
725
|
-
name:
|
|
727
|
+
name: "示例接口",
|
|
726
728
|
handler: async (befly, ctx) => {
|
|
727
729
|
// 访问内置插件
|
|
728
|
-
const user = await befly.db.getOne({ table:
|
|
729
|
-
befly.logger.info({ user: user },
|
|
730
|
+
const user = await befly.db.getOne({ table: "user", where: { id: 1 } });
|
|
731
|
+
befly.logger.info({ user: user }, "查询用户");
|
|
730
732
|
|
|
731
733
|
// 访问项目插件
|
|
732
|
-
const result = await befly.app_sms.send(
|
|
734
|
+
const result = await befly.app_sms.send("13800138000", { code: "123456" });
|
|
733
735
|
|
|
734
736
|
// 访问 Addon 插件
|
|
735
737
|
await befly.addon_addonAdmin_email.send({
|
|
736
|
-
to:
|
|
737
|
-
subject:
|
|
738
|
+
to: "admin@example.com",
|
|
739
|
+
subject: "通知"
|
|
738
740
|
});
|
|
739
741
|
|
|
740
|
-
return befly.tool.Yes(
|
|
742
|
+
return befly.tool.Yes("成功");
|
|
741
743
|
}
|
|
742
744
|
};
|
|
743
745
|
```
|
|
@@ -749,7 +751,7 @@ export default {
|
|
|
749
751
|
在配置文件中设置 `disablePlugins` 数组:
|
|
750
752
|
|
|
751
753
|
```json
|
|
752
|
-
// befly.
|
|
754
|
+
// befly.development.json
|
|
753
755
|
{
|
|
754
756
|
"disablePlugins": ["redis", "app_sms"]
|
|
755
757
|
}
|
|
@@ -767,8 +769,8 @@ Addon 插件是组件包中的扩展功能,用于为 Addon 提供特定的服
|
|
|
767
769
|
|
|
768
770
|
```typescript
|
|
769
771
|
// packages/addonPay/plugins/wechat.ts
|
|
770
|
-
import type { Plugin } from
|
|
771
|
-
import type { BeflyContext } from
|
|
772
|
+
import type { Plugin } from "befly/types/plugin";
|
|
773
|
+
import type { BeflyContext } from "befly/types/befly";
|
|
772
774
|
|
|
773
775
|
class WechatPayHelper {
|
|
774
776
|
private befly: BeflyContext;
|
|
@@ -782,24 +784,24 @@ class WechatPayHelper {
|
|
|
782
784
|
async createOrder(params: { orderId: string; amount: number; description: string }) {
|
|
783
785
|
// 调用微信支付 API 创建订单
|
|
784
786
|
// ...
|
|
785
|
-
return { prepayId:
|
|
787
|
+
return { prepayId: "xxx", nonceStr: "xxx" };
|
|
786
788
|
}
|
|
787
789
|
|
|
788
790
|
async queryOrder(orderId: string) {
|
|
789
791
|
// 查询订单状态
|
|
790
792
|
// ...
|
|
791
|
-
return { status:
|
|
793
|
+
return { status: "SUCCESS" };
|
|
792
794
|
}
|
|
793
795
|
|
|
794
796
|
async refund(orderId: string, amount: number) {
|
|
795
797
|
// 申请退款
|
|
796
798
|
// ...
|
|
797
|
-
return { refundId:
|
|
799
|
+
return { refundId: "xxx" };
|
|
798
800
|
}
|
|
799
801
|
}
|
|
800
802
|
|
|
801
803
|
const plugin: Plugin = {
|
|
802
|
-
after: [
|
|
804
|
+
after: ["logger", "config"],
|
|
803
805
|
handler: (befly: BeflyContext) => {
|
|
804
806
|
return new WechatPayHelper(befly);
|
|
805
807
|
}
|
|
@@ -813,9 +815,9 @@ export default plugin;
|
|
|
813
815
|
```typescript
|
|
814
816
|
// 插件名:addon_addonPay_wechat
|
|
815
817
|
const order = await befly.addon_addonPay_wechat.createOrder({
|
|
816
|
-
orderId:
|
|
818
|
+
orderId: "202312010001",
|
|
817
819
|
amount: 100,
|
|
818
|
-
description:
|
|
820
|
+
description: "商品购买"
|
|
819
821
|
});
|
|
820
822
|
```
|
|
821
823
|
|
|
@@ -849,7 +851,7 @@ const plugin: Plugin = {
|
|
|
849
851
|
```typescript
|
|
850
852
|
// ✅ 推荐:明确声明所有依赖
|
|
851
853
|
const plugin: Plugin = {
|
|
852
|
-
after: [
|
|
854
|
+
after: ["logger", "db", "redis"], // 声明所有使用的插件
|
|
853
855
|
handler: (befly) => {
|
|
854
856
|
/* ... */
|
|
855
857
|
}
|
|
@@ -875,7 +877,7 @@ const plugin: Plugin = {
|
|
|
875
877
|
const client = await connectToService();
|
|
876
878
|
return client;
|
|
877
879
|
} catch (error) {
|
|
878
|
-
befly.logger.error({ err: error },
|
|
880
|
+
befly.logger.error({ err: error }, "服务连接失败");
|
|
879
881
|
throw error; // 抛出错误会终止应用启动
|
|
880
882
|
}
|
|
881
883
|
}
|
|
@@ -891,7 +893,7 @@ const plugin: Plugin = {
|
|
|
891
893
|
const config = befly.config.myService;
|
|
892
894
|
|
|
893
895
|
if (!config?.apiKey) {
|
|
894
|
-
throw new Error(
|
|
896
|
+
throw new Error("myService.apiKey 配置缺失");
|
|
895
897
|
}
|
|
896
898
|
|
|
897
899
|
return new MyService(config);
|
|
@@ -936,11 +938,11 @@ class DatabasePool {
|
|
|
936
938
|
|
|
937
939
|
```typescript
|
|
938
940
|
const plugin: Plugin = {
|
|
939
|
-
after: [
|
|
941
|
+
after: ["db"], // 声明依赖
|
|
940
942
|
handler: (befly) => {
|
|
941
943
|
return {
|
|
942
944
|
async getUser(id: number) {
|
|
943
|
-
return befly.db.getOne({ table:
|
|
945
|
+
return befly.db.getOne({ table: "user", where: { id: id } });
|
|
944
946
|
}
|
|
945
947
|
};
|
|
946
948
|
}
|
|
@@ -959,20 +961,20 @@ const plugin: Plugin = {
|
|
|
959
961
|
|
|
960
962
|
```typescript
|
|
961
963
|
// tests/myPlugin.test.ts
|
|
962
|
-
import { describe, test, expect } from
|
|
964
|
+
import { describe, test, expect } from "bun:test";
|
|
963
965
|
|
|
964
|
-
describe(
|
|
965
|
-
test(
|
|
966
|
+
describe("MyPlugin", () => {
|
|
967
|
+
test("应该正确初始化", async () => {
|
|
966
968
|
const mockBefly = {
|
|
967
|
-
config: { myService: { apiKey:
|
|
969
|
+
config: { myService: { apiKey: "test" } },
|
|
968
970
|
logger: { info: () => {}, error: () => {} }
|
|
969
971
|
};
|
|
970
972
|
|
|
971
|
-
const plugin = (await import(
|
|
973
|
+
const plugin = (await import("../plugins/myPlugin.ts")).default;
|
|
972
974
|
const instance = await plugin.handler(mockBefly);
|
|
973
975
|
|
|
974
976
|
expect(instance).toBeDefined();
|
|
975
|
-
expect(typeof instance.doSomething).toBe(
|
|
977
|
+
expect(typeof instance.doSomething).toBe("function");
|
|
976
978
|
});
|
|
977
979
|
});
|
|
978
980
|
```
|
package/docs/quickstart.md
CHANGED
|
@@ -59,8 +59,8 @@ my-api/
|
|
|
59
59
|
│ └── user.json # 用户表定义
|
|
60
60
|
├── configs/ # 配置文件目录
|
|
61
61
|
│ ├── befly.common.json # 公共配置
|
|
62
|
-
│ ├── befly.
|
|
63
|
-
│ └── befly.
|
|
62
|
+
│ ├── befly.development.json # 开发环境配置
|
|
63
|
+
│ └── befly.production.json # 生产环境配置
|
|
64
64
|
├── main.ts # 入口文件
|
|
65
65
|
└── package.json
|
|
66
66
|
```
|
|
@@ -74,39 +74,39 @@ my-api/
|
|
|
74
74
|
在 `apis/user/` 目录下创建 `login.ts`:
|
|
75
75
|
|
|
76
76
|
```typescript
|
|
77
|
-
import type { ApiRoute } from
|
|
77
|
+
import type { ApiRoute } from "befly/types/api";
|
|
78
78
|
|
|
79
79
|
export default {
|
|
80
|
-
name:
|
|
81
|
-
method:
|
|
80
|
+
name: "用户登录",
|
|
81
|
+
method: "POST",
|
|
82
82
|
auth: false, // 不需要登录
|
|
83
83
|
fields: {
|
|
84
|
-
email: { name:
|
|
85
|
-
password: { name:
|
|
84
|
+
email: { name: "邮箱", type: "string", min: 5, max: 100, regexp: "@email" },
|
|
85
|
+
password: { name: "密码", type: "string", min: 6, max: 100 }
|
|
86
86
|
},
|
|
87
|
-
required: [
|
|
87
|
+
required: ["email", "password"],
|
|
88
88
|
handler: async (befly, ctx) => {
|
|
89
89
|
// 查询用户
|
|
90
90
|
const user = await befly.db.getDetail({
|
|
91
|
-
table:
|
|
92
|
-
columns: [
|
|
91
|
+
table: "user",
|
|
92
|
+
columns: ["id", "email", "password", "nickname"],
|
|
93
93
|
where: { email: ctx.body.email }
|
|
94
94
|
});
|
|
95
95
|
|
|
96
96
|
if (!user?.id) {
|
|
97
|
-
return No(
|
|
97
|
+
return No("用户不存在");
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
// 验证密码
|
|
101
101
|
const isValid = await befly.cipher.verifyPassword(ctx.body.password, user.password);
|
|
102
102
|
if (!isValid) {
|
|
103
|
-
return No(
|
|
103
|
+
return No("密码错误");
|
|
104
104
|
}
|
|
105
105
|
|
|
106
106
|
// 签发令牌
|
|
107
107
|
const token = befly.jwt.sign({ userId: user.id });
|
|
108
108
|
|
|
109
|
-
return Yes(
|
|
109
|
+
return Yes("登录成功", { token: token, user: { id: user.id, nickname: user.nickname } });
|
|
110
110
|
}
|
|
111
111
|
} as ApiRoute;
|
|
112
112
|
```
|
|
@@ -127,7 +127,7 @@ export default {
|
|
|
127
127
|
|
|
128
128
|
### 编辑配置文件
|
|
129
129
|
|
|
130
|
-
修改 `configs/befly.
|
|
130
|
+
修改 `configs/befly.development.json`:
|
|
131
131
|
|
|
132
132
|
```json
|
|
133
133
|
{
|
|
@@ -281,18 +281,18 @@ curl -X POST http://localhost:3000/api/user/login \
|
|
|
281
281
|
|
|
282
282
|
### 学习更多
|
|
283
283
|
|
|
284
|
-
| 主题 | 文档
|
|
285
|
-
| ---------- |
|
|
286
|
-
| API 开发 | [api.md](./api.md)
|
|
287
|
-
| 表结构 | [table.md](./table.md)
|
|
288
|
-
| 数据库操作 | [database.md](./database.md)
|
|
289
|
-
| 配置系统 | [config.md](./config.md)
|
|
290
|
-
| 插件开发 | [plugin.md](./plugin.md)
|
|
291
|
-
| Hook 开发 | [hook.md](./hook.md) | 请求处理钩子 |
|
|
292
|
-
| 验证系统 | [validator.md](./validator.md)
|
|
293
|
-
| 日志系统 | [logger.md](./logger.md)
|
|
294
|
-
| 加密工具 | [cipher.md](./cipher.md)
|
|
295
|
-
| 同步命令 | [sync.md](./sync.md)
|
|
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
296
|
|
|
297
297
|
### 常用命令
|
|
298
298
|
|