befly 3.4.15 → 3.5.0
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/commands/build.ts +3 -8
- package/commands/index.ts +12 -29
- package/commands/syncDb.ts +0 -1
- package/config/env.ts +12 -12
- package/lib/middleware.ts +6 -34
- package/main.ts +2 -1
- package/package.json +2 -3
- package/router/api.ts +1 -31
package/commands/build.ts
CHANGED
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
|
|
5
5
|
import { join } from 'pathe';
|
|
6
6
|
import { existsSync } from 'node:fs';
|
|
7
|
-
import ora from 'ora';
|
|
8
7
|
import { Logger } from '../lib/logger.js';
|
|
9
8
|
import { getProjectRoot } from './util.js';
|
|
10
9
|
|
|
@@ -28,11 +27,7 @@ export async function buildCommand(options: BuildOptions) {
|
|
|
28
27
|
// 使用内置默认入口文件
|
|
29
28
|
const entryFile = join(import.meta.dir, '..', 'entry.ts');
|
|
30
29
|
|
|
31
|
-
|
|
32
|
-
text: '正在构建项目...',
|
|
33
|
-
color: 'cyan',
|
|
34
|
-
spinner: 'dots'
|
|
35
|
-
}).start();
|
|
30
|
+
Logger.info('正在构建项目...');
|
|
36
31
|
|
|
37
32
|
const args = ['build', entryFile, '--outdir', options.outdir, '--target', 'bun'];
|
|
38
33
|
|
|
@@ -53,10 +48,10 @@ export async function buildCommand(options: BuildOptions) {
|
|
|
53
48
|
await proc.exited;
|
|
54
49
|
|
|
55
50
|
if (proc.exitCode === 0) {
|
|
56
|
-
|
|
51
|
+
Logger.success('项目构建完成');
|
|
57
52
|
Logger.success(`输出目录: ${options.outdir}`);
|
|
58
53
|
} else {
|
|
59
|
-
|
|
54
|
+
Logger.error('项目构建失败');
|
|
60
55
|
process.exit(1);
|
|
61
56
|
}
|
|
62
57
|
} catch (error) {
|
package/commands/index.ts
CHANGED
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
|
|
5
5
|
import { join } from 'pathe';
|
|
6
6
|
import { existsSync } from 'node:fs';
|
|
7
|
-
import ora from 'ora';
|
|
8
7
|
import { Logger } from '../lib/logger.js';
|
|
9
8
|
import { getProjectRoot } from './util.js';
|
|
10
9
|
|
|
@@ -25,11 +24,7 @@ export async function buildCommand(options: BuildOptions) {
|
|
|
25
24
|
process.exit(1);
|
|
26
25
|
}
|
|
27
26
|
|
|
28
|
-
|
|
29
|
-
text: '正在构建项目...',
|
|
30
|
-
color: 'cyan',
|
|
31
|
-
spinner: 'dots'
|
|
32
|
-
}).start();
|
|
27
|
+
Logger.info('正在构建项目...');
|
|
33
28
|
|
|
34
29
|
const args = ['build', mainFile, '--outdir', options.outdir, '--target', 'bun'];
|
|
35
30
|
|
|
@@ -50,10 +45,10 @@ export async function buildCommand(options: BuildOptions) {
|
|
|
50
45
|
await proc.exited;
|
|
51
46
|
|
|
52
47
|
if (proc.exitCode === 0) {
|
|
53
|
-
|
|
48
|
+
Logger.success('项目构建完成');
|
|
54
49
|
Logger.success(`输出目录: ${options.outdir}`);
|
|
55
50
|
} else {
|
|
56
|
-
|
|
51
|
+
Logger.error('项目构建失败');
|
|
57
52
|
process.exit(1);
|
|
58
53
|
}
|
|
59
54
|
} catch (error) {
|
|
@@ -126,11 +121,7 @@ export async function syncCommand(options: SyncOptions) {
|
|
|
126
121
|
process.exit(1);
|
|
127
122
|
}
|
|
128
123
|
|
|
129
|
-
|
|
130
|
-
text: '正在同步数据库表...',
|
|
131
|
-
color: 'cyan',
|
|
132
|
-
spinner: 'dots'
|
|
133
|
-
}).start();
|
|
124
|
+
Logger.info('正在同步数据库表...');
|
|
134
125
|
|
|
135
126
|
const args = ['run', syncScript];
|
|
136
127
|
|
|
@@ -160,9 +151,9 @@ export async function syncCommand(options: SyncOptions) {
|
|
|
160
151
|
await proc.exited;
|
|
161
152
|
|
|
162
153
|
if (proc.exitCode === 0) {
|
|
163
|
-
|
|
154
|
+
Logger.success('数据库同步完成');
|
|
164
155
|
} else {
|
|
165
|
-
|
|
156
|
+
Logger.error('数据库同步失败');
|
|
166
157
|
process.exit(1);
|
|
167
158
|
}
|
|
168
159
|
} catch (error) {
|
|
@@ -175,11 +166,7 @@ export async function syncCommand(options: SyncOptions) {
|
|
|
175
166
|
// ========== Addon 命令 ==========
|
|
176
167
|
export const addonCommand = {
|
|
177
168
|
async install(name: string, options: { source?: string }) {
|
|
178
|
-
|
|
179
|
-
text: `正在安装插件: ${name}`,
|
|
180
|
-
color: 'cyan',
|
|
181
|
-
spinner: 'dots'
|
|
182
|
-
}).start();
|
|
169
|
+
Logger.info(`正在安装插件: ${name}`);
|
|
183
170
|
|
|
184
171
|
try {
|
|
185
172
|
// TODO: 实现插件安装逻辑
|
|
@@ -188,19 +175,15 @@ export const addonCommand = {
|
|
|
188
175
|
// 3. 安装插件依赖
|
|
189
176
|
// 4. 执行插件安装脚本
|
|
190
177
|
|
|
191
|
-
|
|
178
|
+
Logger.success(`插件 ${name} 安装成功`);
|
|
192
179
|
} catch (error) {
|
|
193
|
-
|
|
180
|
+
Logger.error(`插件 ${name} 安装失败`);
|
|
194
181
|
throw error;
|
|
195
182
|
}
|
|
196
183
|
},
|
|
197
184
|
|
|
198
185
|
async uninstall(name: string, options: { keepData: boolean }) {
|
|
199
|
-
|
|
200
|
-
text: `正在卸载插件: ${name}`,
|
|
201
|
-
color: 'cyan',
|
|
202
|
-
spinner: 'dots'
|
|
203
|
-
}).start();
|
|
186
|
+
Logger.info(`正在卸载插件: ${name}`);
|
|
204
187
|
|
|
205
188
|
try {
|
|
206
189
|
// TODO: 实现插件卸载逻辑
|
|
@@ -208,9 +191,9 @@ export const addonCommand = {
|
|
|
208
191
|
// 2. 删除插件文件
|
|
209
192
|
// 3. 可选:删除插件数据
|
|
210
193
|
|
|
211
|
-
|
|
194
|
+
Logger.success(`插件 ${name} 卸载成功`);
|
|
212
195
|
} catch (error) {
|
|
213
|
-
|
|
196
|
+
Logger.error(`插件 ${name} 卸载失败`);
|
|
214
197
|
throw error;
|
|
215
198
|
}
|
|
216
199
|
},
|
package/commands/syncDb.ts
CHANGED
package/config/env.ts
CHANGED
|
@@ -87,17 +87,17 @@ export interface EnvConfig {
|
|
|
87
87
|
|
|
88
88
|
// ========== CORS 配置 ==========
|
|
89
89
|
/** 允许的来源 */
|
|
90
|
-
|
|
90
|
+
CORS_ALLOWED_ORIGIN: string;
|
|
91
91
|
/** 允许的方法 */
|
|
92
|
-
|
|
92
|
+
CORS_ALLOWED_METHODS: string;
|
|
93
93
|
/** 允许的头部 */
|
|
94
|
-
|
|
94
|
+
CORS_ALLOWED_HEADERS: string;
|
|
95
95
|
/** 暴露的头部 */
|
|
96
|
-
|
|
96
|
+
CORS_EXPOSE_HEADERS: string;
|
|
97
97
|
/** 预检请求缓存时间(秒) */
|
|
98
|
-
|
|
98
|
+
CORS_MAX_AGE: number;
|
|
99
99
|
/** 是否允许凭证 */
|
|
100
|
-
|
|
100
|
+
CORS_ALLOW_CREDENTIALS: string;
|
|
101
101
|
|
|
102
102
|
// ========== 邮件配置 ==========
|
|
103
103
|
/** 邮件服务器主机 */
|
|
@@ -183,12 +183,12 @@ export const Env: EnvConfig = {
|
|
|
183
183
|
JWT_ALGORITHM: getEnv('JWT_ALGORITHM', 'HS256'),
|
|
184
184
|
|
|
185
185
|
// ========== CORS 配置 ==========
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
186
|
+
CORS_ALLOWED_ORIGIN: getEnv('CORS_ALLOWED_ORIGIN', '*'),
|
|
187
|
+
CORS_ALLOWED_METHODS: getEnv('CORS_ALLOWED_METHODS', 'GET, POST, PUT, DELETE, OPTIONS'),
|
|
188
|
+
CORS_ALLOWED_HEADERS: getEnv('CORS_ALLOWED_HEADERS', 'Content-Type, Authorization, authorization, token'),
|
|
189
|
+
CORS_EXPOSE_HEADERS: getEnv('CORS_EXPOSE_HEADERS', 'Content-Range, X-Content-Range, Authorization, authorization, token'),
|
|
190
|
+
CORS_MAX_AGE: getEnvNumber('CORS_MAX_AGE', 86400),
|
|
191
|
+
CORS_ALLOW_CREDENTIALS: getEnv('CORS_ALLOW_CREDENTIALS', 'true'),
|
|
192
192
|
|
|
193
193
|
// ========== 邮件配置 ==========
|
|
194
194
|
MAIL_HOST: getEnv('MAIL_HOST', ''),
|
package/lib/middleware.ts
CHANGED
|
@@ -58,42 +58,14 @@ export interface CorsResult {
|
|
|
58
58
|
* @returns CORS 配置对象
|
|
59
59
|
*/
|
|
60
60
|
export const setCorsOptions = (req: Request): CorsResult => {
|
|
61
|
-
const requestOrigin = req.headers.get('origin');
|
|
62
|
-
let allowedOrigin = '*';
|
|
63
|
-
|
|
64
|
-
// 如果配置了 ALLOWED_ORIGIN
|
|
65
|
-
if (Env.ALLOWED_ORIGIN) {
|
|
66
|
-
// 如果配置为 *,使用请求的 origin(而不是返回 *)
|
|
67
|
-
if (Env.ALLOWED_ORIGIN === '*') {
|
|
68
|
-
allowedOrigin = requestOrigin || '*';
|
|
69
|
-
} else {
|
|
70
|
-
// 支持多个源,用逗号分隔
|
|
71
|
-
const allowedOrigins = Env.ALLOWED_ORIGIN.split(',').map((origin) => origin.trim());
|
|
72
|
-
|
|
73
|
-
// 如果请求的 origin 在允许列表中,返回该 origin
|
|
74
|
-
if (requestOrigin && allowedOrigins.includes(requestOrigin)) {
|
|
75
|
-
allowedOrigin = requestOrigin;
|
|
76
|
-
} else if (allowedOrigins.length === 1) {
|
|
77
|
-
// 如果只配置了一个源,直接使用
|
|
78
|
-
allowedOrigin = allowedOrigins[0];
|
|
79
|
-
} else {
|
|
80
|
-
// 多个源但请求源不在列表中,不允许跨域
|
|
81
|
-
allowedOrigin = 'null';
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
} else if (requestOrigin) {
|
|
85
|
-
// 没有配置 ALLOWED_ORIGIN,使用请求的 origin
|
|
86
|
-
allowedOrigin = requestOrigin;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
61
|
return {
|
|
90
62
|
headers: {
|
|
91
|
-
'Access-Control-Allow-Origin':
|
|
92
|
-
'Access-Control-Allow-Methods': Env.
|
|
93
|
-
'Access-Control-Allow-Headers': Env.
|
|
94
|
-
'Access-Control-Expose-Headers': Env.
|
|
95
|
-
'Access-Control-Max-Age': Env.
|
|
96
|
-
'Access-Control-Allow-Credentials': Env.
|
|
63
|
+
'Access-Control-Allow-Origin': Env.CORS_ALLOWED_ORIGIN === '*' ? req.headers.get('origin') : Env.CORS_ALLOWED_ORIGIN,
|
|
64
|
+
'Access-Control-Allow-Methods': Env.CORS_ALLOWED_METHODS,
|
|
65
|
+
'Access-Control-Allow-Headers': Env.CORS_ALLOWED_HEADERS,
|
|
66
|
+
'Access-Control-Expose-Headers': Env.CORS_EXPOSE_HEADERS,
|
|
67
|
+
'Access-Control-Max-Age': Env.CORS_MAX_AGE || 86400,
|
|
68
|
+
'Access-Control-Allow-Credentials': Env.CORS_ALLOW_CREDENTIALS || 'true'
|
|
97
69
|
}
|
|
98
70
|
};
|
|
99
71
|
};
|
package/main.ts
CHANGED
|
@@ -8,6 +8,7 @@ import { Yes, No } from './util.js';
|
|
|
8
8
|
import { Logger } from './lib/logger.js';
|
|
9
9
|
import { Cipher } from './lib/cipher.js';
|
|
10
10
|
import { Jwt } from './lib/jwt.js';
|
|
11
|
+
import { Database } from './lib/database.js';
|
|
11
12
|
import { Lifecycle } from './lifecycle/lifecycle.js';
|
|
12
13
|
|
|
13
14
|
import type { Server } from 'bun';
|
|
@@ -34,6 +35,7 @@ export class Befly {
|
|
|
34
35
|
*/
|
|
35
36
|
async listen(callback?: (server: Server) => void): Promise<Server> {
|
|
36
37
|
const server = await this.lifecycle.start(this.appContext, callback);
|
|
38
|
+
Logger.info('数据库======:' + Env.APP_NAME);
|
|
37
39
|
|
|
38
40
|
// 注册优雅关闭信号处理器
|
|
39
41
|
const gracefulShutdown = async (signal: string) => {
|
|
@@ -45,7 +47,6 @@ export class Befly {
|
|
|
45
47
|
|
|
46
48
|
// 2. 关闭数据库连接
|
|
47
49
|
try {
|
|
48
|
-
const { Database } = await import('./lib/database.js');
|
|
49
50
|
await Database.disconnect();
|
|
50
51
|
Logger.info('✅ 数据库连接已关闭');
|
|
51
52
|
} catch (error: any) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "befly",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.5.0",
|
|
4
4
|
"description": "Befly - 为 Bun 专属打造的 TypeScript API 接口框架核心引擎",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": false,
|
|
@@ -78,8 +78,7 @@
|
|
|
78
78
|
"commander": "^14.0.2",
|
|
79
79
|
"es-toolkit": "^1.41.0",
|
|
80
80
|
"inquirer": "^12.10.0",
|
|
81
|
-
"ora": "^9.0.0",
|
|
82
81
|
"pathe": "^2.0.3"
|
|
83
82
|
},
|
|
84
|
-
"gitHead": "
|
|
83
|
+
"gitHead": "6d065b50bd57e1330a81d5a62423b204a2a49205"
|
|
85
84
|
}
|
package/router/api.ts
CHANGED
|
@@ -117,37 +117,7 @@ export function apiHandler(apiRoutes: Map<string, ApiRoute>, pluginLists: Plugin
|
|
|
117
117
|
// 记录详细的错误日志
|
|
118
118
|
Logger.warn(api ? `接口 [${api.name}] 执行失败` : '处理接口请求时发生错误', error);
|
|
119
119
|
|
|
120
|
-
|
|
121
|
-
let errorMessage = '内部服务器错误';
|
|
122
|
-
let errorDetail = {};
|
|
123
|
-
|
|
124
|
-
// 数据库错误
|
|
125
|
-
if (error.message?.includes('ECONNREFUSED') || error.message?.includes('database')) {
|
|
126
|
-
errorMessage = '数据库连接失败';
|
|
127
|
-
}
|
|
128
|
-
// Redis错误
|
|
129
|
-
else if (error.message?.includes('Redis') || error.message?.includes('redis')) {
|
|
130
|
-
errorMessage = 'Redis服务异常';
|
|
131
|
-
}
|
|
132
|
-
// 权限错误
|
|
133
|
-
else if (error.message?.includes('permission') || error.message?.includes('权限')) {
|
|
134
|
-
errorMessage = '权限不足';
|
|
135
|
-
}
|
|
136
|
-
// 认证错误
|
|
137
|
-
else if (error.message?.includes('token') || error.message?.includes('认证')) {
|
|
138
|
-
errorMessage = '认证失败';
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
// 开发环境返回详细错误信息
|
|
142
|
-
if (Env.NODE_ENV === 'development') {
|
|
143
|
-
errorDetail = {
|
|
144
|
-
type: error.constructor?.name || 'Error',
|
|
145
|
-
message: error.message,
|
|
146
|
-
stack: error.stack
|
|
147
|
-
};
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
return Response.json(No(errorMessage, errorDetail), {
|
|
120
|
+
return Response.json(No('内部服务器错误'), {
|
|
151
121
|
headers: corsOptions.headers
|
|
152
122
|
});
|
|
153
123
|
}
|