befly 1.2.1 → 1.2.3
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/apis/health/info.js +32 -23
- package/apis/tool/tokenCheck.js +22 -0
- package/main.js +14 -2
- package/package.json +2 -2
- package/utils/jwt.js +0 -65
package/apis/health/info.js
CHANGED
|
@@ -3,31 +3,40 @@ import { Api } from '../../utils/api.js';
|
|
|
3
3
|
import { RYes, RNo } from '../../utils/util.js';
|
|
4
4
|
|
|
5
5
|
export default Api.POST('健康检查', false, {}, [], async (befly, ctx) => {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
if (
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
6
|
+
try {
|
|
7
|
+
const info = {
|
|
8
|
+
status: 'ok',
|
|
9
|
+
timestamp: new Date().toISOString(),
|
|
10
|
+
uptime: process.uptime(),
|
|
11
|
+
memory: process.memoryUsage(),
|
|
12
|
+
runtime: 'Bun',
|
|
13
|
+
version: Bun.version,
|
|
14
|
+
platform: process.platform,
|
|
15
|
+
arch: process.arch
|
|
16
|
+
};
|
|
17
|
+
// 检查 Redis 连接状态
|
|
18
|
+
if (Env.REDIS_ENABLE === 1) {
|
|
19
|
+
if (befly.redis) {
|
|
20
|
+
try {
|
|
21
|
+
await befly.redis.ping();
|
|
22
|
+
info.redis = '已连接';
|
|
23
|
+
} catch (error) {
|
|
24
|
+
info.redis = '未连接';
|
|
25
|
+
info.redisError = error.message;
|
|
26
|
+
}
|
|
27
|
+
} else {
|
|
28
|
+
info.redis = '未开启';
|
|
25
29
|
}
|
|
26
30
|
} else {
|
|
27
|
-
info.redis = '
|
|
31
|
+
info.redis = '禁用';
|
|
28
32
|
}
|
|
29
|
-
|
|
30
|
-
|
|
33
|
+
return RYes('健康检查成功', info);
|
|
34
|
+
} catch (error) {
|
|
35
|
+
befly.logger.error({
|
|
36
|
+
msg: '健康检查失败',
|
|
37
|
+
error: error.message,
|
|
38
|
+
stack: error.stack
|
|
39
|
+
});
|
|
40
|
+
return RNo('健康检查失败');
|
|
31
41
|
}
|
|
32
|
-
return RYes('健康检查成功', info);
|
|
33
42
|
});
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Env } from '../../config/env.js';
|
|
2
|
+
import { Api } from '../../utils/api.js';
|
|
3
|
+
import { RYes, RNo } from '../../utils/util.js';
|
|
4
|
+
import { Jwt } from '../../utils/jwt.js';
|
|
5
|
+
|
|
6
|
+
export default Api.POST('令牌检测', false, {}, [], async (befly, ctx) => {
|
|
7
|
+
try {
|
|
8
|
+
const token = ctx.headers?.authorization?.split(' ')[1] || '';
|
|
9
|
+
if (!token) {
|
|
10
|
+
return RNo('令牌不能为空');
|
|
11
|
+
}
|
|
12
|
+
const jwtData = await Jwt.verify(token);
|
|
13
|
+
return RYes('令牌有效');
|
|
14
|
+
} catch (error) {
|
|
15
|
+
befly.logger.error({
|
|
16
|
+
msg: '令牌检测失败',
|
|
17
|
+
error: error.message,
|
|
18
|
+
stack: error.stack
|
|
19
|
+
});
|
|
20
|
+
return RNo('令牌检测失败');
|
|
21
|
+
}
|
|
22
|
+
});
|
package/main.js
CHANGED
|
@@ -319,6 +319,7 @@ class Befly {
|
|
|
319
319
|
hostname: Env.APP_HOST,
|
|
320
320
|
routes: {
|
|
321
321
|
'/': async (req) => {
|
|
322
|
+
const corsOptions = setCorsOptions(req);
|
|
322
323
|
return Response.json(
|
|
323
324
|
{
|
|
324
325
|
code: 0,
|
|
@@ -335,6 +336,7 @@ class Befly {
|
|
|
335
336
|
'/api/*': async (req) => {
|
|
336
337
|
try {
|
|
337
338
|
const corsOptions = setCorsOptions(req);
|
|
339
|
+
|
|
338
340
|
// 直接返回options请求
|
|
339
341
|
if (req.method === 'OPTIONS') {
|
|
340
342
|
return new Response(null, {
|
|
@@ -342,6 +344,7 @@ class Befly {
|
|
|
342
344
|
headers: corsOptions.headers
|
|
343
345
|
});
|
|
344
346
|
}
|
|
347
|
+
|
|
345
348
|
// 初始化请求数据存储
|
|
346
349
|
const ctx = {
|
|
347
350
|
headers: Object.fromEntries(req.headers.entries()),
|
|
@@ -489,6 +492,15 @@ class Befly {
|
|
|
489
492
|
},
|
|
490
493
|
'/*': async (req) => {
|
|
491
494
|
const corsOptions = setCorsOptions(req);
|
|
495
|
+
|
|
496
|
+
// 直接返回options请求
|
|
497
|
+
if (req.method === 'OPTIONS') {
|
|
498
|
+
return new Response(null, {
|
|
499
|
+
status: 204,
|
|
500
|
+
headers: corsOptions.headers
|
|
501
|
+
});
|
|
502
|
+
}
|
|
503
|
+
|
|
492
504
|
const url = new URL(req.url);
|
|
493
505
|
const filePath = path.join(process.cwd(), 'public', url.pathname);
|
|
494
506
|
|
|
@@ -525,8 +537,8 @@ class Befly {
|
|
|
525
537
|
});
|
|
526
538
|
|
|
527
539
|
const finalStartupTime = (Bun.nanoseconds() - serverStartTime) / 1_000_000;
|
|
528
|
-
Logger.info(
|
|
529
|
-
Logger.info(
|
|
540
|
+
Logger.info(`Befly 服务器启动成功! 完整启动耗时: ${finalStartupTime.toFixed(2)}ms`);
|
|
541
|
+
Logger.info(`服务器监听地址: http://${Env.APP_HOST}:${Env.APP_PORT}`);
|
|
530
542
|
|
|
531
543
|
if (callback && typeof callback === 'function') {
|
|
532
544
|
callback(server);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "befly",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.3",
|
|
4
4
|
"description": "Buma - 为 Bun 专属打造的 API 接口框架核心引擎",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": false,
|
|
@@ -49,5 +49,5 @@
|
|
|
49
49
|
"README.md",
|
|
50
50
|
"vitest.config.js"
|
|
51
51
|
],
|
|
52
|
-
"gitHead": "
|
|
52
|
+
"gitHead": "092063519e02232d1f60ccf7aa83978f96b940f7"
|
|
53
53
|
}
|
package/utils/jwt.js
CHANGED
|
@@ -50,35 +50,6 @@ export class Jwt {
|
|
|
50
50
|
return this.verifier(token);
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
/**
|
|
54
|
-
* 创建自定义签名器
|
|
55
|
-
* @param {object} options - 签名选项
|
|
56
|
-
* @returns {Promise<Function>} 签名器函数
|
|
57
|
-
*/
|
|
58
|
-
static async createSigner(options = {}) {
|
|
59
|
-
const { createSigner } = await import('fast-jwt');
|
|
60
|
-
return createSigner({
|
|
61
|
-
key: options.key || Env.JWT_SECRET,
|
|
62
|
-
expiresIn: options.expiresIn || Env.JWT_EXPIRES_IN || '7d',
|
|
63
|
-
algorithm: options.algorithm || Env.JWT_ALGORITHM || 'HS256',
|
|
64
|
-
...options
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* 创建自定义验证器
|
|
70
|
-
* @param {object} options - 验证选项
|
|
71
|
-
* @returns {Promise<Function>} 验证器函数
|
|
72
|
-
*/
|
|
73
|
-
static async createVerifier(options = {}) {
|
|
74
|
-
const { createVerifier } = await import('fast-jwt');
|
|
75
|
-
return createVerifier({
|
|
76
|
-
key: options.key || Env.JWT_SECRET,
|
|
77
|
-
algorithms: options.algorithms || [Env.JWT_ALGORITHM || 'HS256'],
|
|
78
|
-
...options
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
|
|
82
53
|
/**
|
|
83
54
|
* 解码 JWT token (不验证签名)
|
|
84
55
|
* @param {string} token - JWT token
|
|
@@ -100,21 +71,6 @@ export class Jwt {
|
|
|
100
71
|
}
|
|
101
72
|
}
|
|
102
73
|
|
|
103
|
-
/**
|
|
104
|
-
* 检查 token 是否过期
|
|
105
|
-
* @param {string} token - JWT token
|
|
106
|
-
* @returns {boolean} 是否过期
|
|
107
|
-
*/
|
|
108
|
-
static isExpired(token) {
|
|
109
|
-
try {
|
|
110
|
-
const { payload } = this.decode(token);
|
|
111
|
-
if (!payload.exp) return false;
|
|
112
|
-
return Date.now() >= payload.exp * 1000;
|
|
113
|
-
} catch {
|
|
114
|
-
return true;
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
74
|
/**
|
|
119
75
|
* 获取 token 剩余有效时间 (秒)
|
|
120
76
|
* @param {string} token - JWT token
|
|
@@ -130,25 +86,4 @@ export class Jwt {
|
|
|
130
86
|
return -1;
|
|
131
87
|
}
|
|
132
88
|
}
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* 刷新 token (重新签名相同载荷)
|
|
136
|
-
* @param {string} token - 旧的 JWT token
|
|
137
|
-
* @returns {Promise<string>} 新的 JWT token
|
|
138
|
-
*/
|
|
139
|
-
static async refresh(token) {
|
|
140
|
-
const { payload } = this.decode(token);
|
|
141
|
-
// 移除时间相关的声明,让新 token 重新生成
|
|
142
|
-
delete payload.iat;
|
|
143
|
-
delete payload.exp;
|
|
144
|
-
delete payload.nbf;
|
|
145
|
-
return this.sign(payload);
|
|
146
|
-
}
|
|
147
89
|
}
|
|
148
|
-
|
|
149
|
-
// 使用示例:
|
|
150
|
-
// const token = await JWT.sign({ userId: 123, role: 'user' });
|
|
151
|
-
// const payload = await JWT.verify(token);
|
|
152
|
-
// const isExpired = JWT.isExpired(token);
|
|
153
|
-
// const remaining = JWT.getTimeToExpiry(token);
|
|
154
|
-
// const newToken = await JWT.refresh(token);
|