befly 1.0.3 → 1.1.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.
Files changed (3) hide show
  1. package/README.md +1 -1
  2. package/main.js +133 -38
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -1,3 +1,3 @@
1
- # BunPii
1
+ # Befly
2
2
 
3
3
  自用框架,请勿使用。
package/main.js CHANGED
@@ -10,7 +10,7 @@ import { Crypto2 } from './utils/crypto.js';
10
10
  import { XMLParser } from './libs/xml/XMLParser.js';
11
11
  import { isEmptyObject, isType, pickFields, sortPlugins, RYes, RNo, filename2, dirname2 } from './utils/util.js';
12
12
 
13
- class BunPii {
13
+ class Befly {
14
14
  constructor(options = {}) {
15
15
  this.apiRoutes = new Map();
16
16
  this.pluginLists = [];
@@ -20,6 +20,9 @@ class BunPii {
20
20
 
21
21
  async initCheck() {
22
22
  try {
23
+ const checkStartTime = Bun.nanoseconds();
24
+ Logger.info('开始执行系统检查...');
25
+
23
26
  const checksDir = path.join(dirname2(import.meta.url), 'checks');
24
27
  const glob = new Bun.Glob('*.js');
25
28
 
@@ -39,6 +42,7 @@ class BunPii {
39
42
 
40
43
  try {
41
44
  totalChecks++;
45
+ const singleCheckStart = Bun.nanoseconds();
42
46
 
43
47
  // 导入检查模块
44
48
  const check = await import(file);
@@ -46,19 +50,24 @@ class BunPii {
46
50
  // 执行默认导出的函数
47
51
  if (typeof check.default === 'function') {
48
52
  const checkResult = await check.default(this.appContext);
53
+ const singleCheckTime = (Bun.nanoseconds() - singleCheckStart) / 1_000_000;
54
+
49
55
  if (checkResult === true) {
50
56
  passedChecks++;
57
+ Logger.info(`检查 ${fileName} 通过,耗时: ${singleCheckTime.toFixed(2)}ms`);
51
58
  } else {
52
- Logger.error(`检查未通过: ${fileName}`);
59
+ Logger.error(`检查未通过: ${fileName},耗时: ${singleCheckTime.toFixed(2)}ms`);
53
60
  failedChecks++;
54
61
  }
55
62
  } else {
56
- Logger.warn(`文件 ${fileName} 未导出默认函数`);
63
+ const singleCheckTime = (Bun.nanoseconds() - singleCheckStart) / 1_000_000;
64
+ Logger.warn(`文件 ${fileName} 未导出默认函数,耗时: ${singleCheckTime.toFixed(2)}ms`);
57
65
  failedChecks++;
58
66
  }
59
67
  } catch (error) {
68
+ const singleCheckTime = (Bun.nanoseconds() - singleCheckStart) / 1_000_000;
60
69
  Logger.error({
61
- msg: `检查失败 ${fileName}`,
70
+ msg: `检查失败 ${fileName},耗时: ${singleCheckTime.toFixed(2)}ms`,
62
71
  error: error.message,
63
72
  stack: error.stack
64
73
  });
@@ -66,8 +75,10 @@ class BunPii {
66
75
  }
67
76
  }
68
77
 
78
+ const totalCheckTime = (Bun.nanoseconds() - checkStartTime) / 1_000_000;
79
+
69
80
  // 输出检查结果统计
70
- Logger.info(`总检查数: ${totalChecks}, 通过: ${passedChecks}, 失败: ${failedChecks}`);
81
+ Logger.info(`系统检查完成! 总耗时: ${totalCheckTime.toFixed(2)}ms,总检查数: ${totalChecks}, 通过: ${passedChecks}, 失败: ${failedChecks}`);
71
82
 
72
83
  if (failedChecks > 0) {
73
84
  process.exit();
@@ -78,7 +89,7 @@ class BunPii {
78
89
  }
79
90
  } catch (error) {
80
91
  Logger.error({
81
- msg: '加载接口时发生错误',
92
+ msg: '执行系统检查时发生错误',
82
93
  error: error.message,
83
94
  stack: error.stack
84
95
  });
@@ -88,12 +99,17 @@ class BunPii {
88
99
 
89
100
  async loadPlugins() {
90
101
  try {
102
+ const loadStartTime = Bun.nanoseconds();
103
+ Logger.info('开始加载插件...');
104
+
91
105
  const glob = new Bun.Glob('*.js');
92
106
  const corePlugins = [];
93
107
  const userPlugins = [];
94
108
  const loadedPluginNames = new Set(); // 用于跟踪已加载的插件名称
95
109
 
96
- // 扫描指定目录
110
+ // 扫描核心插件目录
111
+ Logger.info('正在扫描核心插件...');
112
+ const corePluginsScanStart = Bun.nanoseconds();
97
113
  for await (const file of glob.scan({
98
114
  cwd: path.join(dirname2(import.meta.url), 'plugins'),
99
115
  onlyFiles: true,
@@ -101,12 +117,20 @@ class BunPii {
101
117
  })) {
102
118
  const fileName = path.basename(file, '.js');
103
119
  if (fileName.startsWith('_')) continue;
120
+
121
+ const importStart = Bun.nanoseconds();
104
122
  const plugin = await import(file);
123
+ const importTime = (Bun.nanoseconds() - importStart) / 1_000_000; // 转换为毫秒
124
+
105
125
  const pluginInstance = plugin.default;
106
126
  pluginInstance.pluginName = fileName;
107
127
  corePlugins.push(pluginInstance);
108
128
  loadedPluginNames.add(fileName); // 记录已加载的核心插件名称
129
+
130
+ Logger.info(`核心插件 ${fileName} 导入耗时: ${importTime.toFixed(2)}ms`);
109
131
  }
132
+ const corePluginsScanTime = (Bun.nanoseconds() - corePluginsScanStart) / 1_000_000;
133
+ Logger.info(`核心插件扫描完成,耗时: ${corePluginsScanTime.toFixed(2)}ms,共找到 ${corePlugins.length} 个插件`);
110
134
 
111
135
  const sortedCorePlugins = sortPlugins(corePlugins);
112
136
  if (sortedCorePlugins === false) {
@@ -114,16 +138,26 @@ class BunPii {
114
138
  process.exit();
115
139
  }
116
140
 
141
+ // 初始化核心插件
142
+ Logger.info('正在初始化核心插件...');
143
+ const corePluginsInitStart = Bun.nanoseconds();
117
144
  for (const plugin of sortedCorePlugins) {
118
145
  try {
146
+ const initStart = Bun.nanoseconds();
119
147
  this.pluginLists.push(plugin);
120
148
  this.appContext[plugin.pluginName] = typeof plugin?.onInit === 'function' ? await plugin?.onInit(this.appContext) : {};
149
+ const initTime = (Bun.nanoseconds() - initStart) / 1_000_000;
150
+ Logger.info(`核心插件 ${plugin.pluginName} 初始化耗时: ${initTime.toFixed(2)}ms`);
121
151
  } catch (error) {
122
152
  Logger.warn(`插件 ${plugin.pluginName} 初始化失败:`, error.message);
123
153
  }
124
154
  }
155
+ const corePluginsInitTime = (Bun.nanoseconds() - corePluginsInitStart) / 1_000_000;
156
+ Logger.info(`核心插件初始化完成,耗时: ${corePluginsInitTime.toFixed(2)}ms`);
125
157
 
126
- // 扫描指定目录
158
+ // 扫描用户插件目录
159
+ Logger.info('正在扫描用户插件...');
160
+ const userPluginsScanStart = Bun.nanoseconds();
127
161
  for await (const file of glob.scan({
128
162
  cwd: path.join(process.cwd(), 'plugins'),
129
163
  onlyFiles: true,
@@ -138,11 +172,18 @@ class BunPii {
138
172
  continue;
139
173
  }
140
174
 
175
+ const importStart = Bun.nanoseconds();
141
176
  const plugin = await import(file);
177
+ const importTime = (Bun.nanoseconds() - importStart) / 1_000_000; // 转换为毫秒
178
+
142
179
  const pluginInstance = plugin.default;
143
180
  pluginInstance.pluginName = fileName;
144
181
  userPlugins.push(pluginInstance);
182
+
183
+ Logger.info(`用户插件 ${fileName} 导入耗时: ${importTime.toFixed(2)}ms`);
145
184
  }
185
+ const userPluginsScanTime = (Bun.nanoseconds() - userPluginsScanStart) / 1_000_000;
186
+ Logger.info(`用户插件扫描完成,耗时: ${userPluginsScanTime.toFixed(2)}ms,共找到 ${userPlugins.length} 个插件`);
146
187
 
147
188
  const sortedUserPlugins = sortPlugins(userPlugins);
148
189
  if (sortedUserPlugins === false) {
@@ -150,14 +191,28 @@ class BunPii {
150
191
  process.exit();
151
192
  }
152
193
 
153
- for (const plugin of sortedUserPlugins) {
154
- try {
155
- this.pluginLists.push(plugin);
156
- this.appContext[plugin.pluginName] = typeof plugin?.onInit === 'function' ? await plugin?.onInit(this.appContext) : {};
157
- } catch (error) {
158
- Logger.warn(`插件 ${plugin.pluginName} 初始化失败:`, error.message);
194
+ // 初始化用户插件
195
+ if (userPlugins.length > 0) {
196
+ Logger.info('正在初始化用户插件...');
197
+ const userPluginsInitStart = Bun.nanoseconds();
198
+ for (const plugin of sortedUserPlugins) {
199
+ try {
200
+ const initStart = Bun.nanoseconds();
201
+ this.pluginLists.push(plugin);
202
+ this.appContext[plugin.pluginName] = typeof plugin?.onInit === 'function' ? await plugin?.onInit(this.appContext) : {};
203
+ const initTime = (Bun.nanoseconds() - initStart) / 1_000_000;
204
+ Logger.info(`用户插件 ${plugin.pluginName} 初始化耗时: ${initTime.toFixed(2)}ms`);
205
+ } catch (error) {
206
+ Logger.warn(`插件 ${plugin.pluginName} 初始化失败:`, error.message);
207
+ }
159
208
  }
209
+ const userPluginsInitTime = (Bun.nanoseconds() - userPluginsInitStart) / 1_000_000;
210
+ Logger.info(`用户插件初始化完成,耗时: ${userPluginsInitTime.toFixed(2)}ms`);
160
211
  }
212
+
213
+ const totalLoadTime = (Bun.nanoseconds() - loadStartTime) / 1_000_000;
214
+ const totalPluginCount = sortedCorePlugins.length + sortedUserPlugins.length;
215
+ Logger.info(`插件加载完成! 总耗时: ${totalLoadTime.toFixed(2)}ms,共加载 ${totalPluginCount} 个插件`);
161
216
  } catch (error) {
162
217
  Logger.error({
163
218
  msg: '加载插件时发生错误',
@@ -168,10 +223,19 @@ class BunPii {
168
223
  }
169
224
  async loadApis(dirName) {
170
225
  try {
226
+ const loadStartTime = Bun.nanoseconds();
227
+ const dirDisplayName = dirName === 'core' ? '核心' : '用户';
228
+ Logger.info(`开始加载${dirDisplayName}接口...`);
229
+
171
230
  const coreApisDir = path.join(dirname2(import.meta.url), 'apis');
172
231
  const userApisDir = path.join(process.cwd(), 'apis');
173
232
  const glob = new Bun.Glob('**/*.js');
174
233
  const apiDir = dirName === 'core' ? coreApisDir : userApisDir;
234
+
235
+ let totalApis = 0;
236
+ let loadedApis = 0;
237
+ let failedApis = 0;
238
+
175
239
  // 扫描指定目录
176
240
  for await (const file of glob.scan({
177
241
  cwd: apiDir,
@@ -181,29 +245,50 @@ class BunPii {
181
245
  const fileName = path.basename(file, '.js');
182
246
  const apiPath = path.relative(apiDir, file).replace(/\.js$/, '').replace(/\\/g, '/');
183
247
  if (apiPath.indexOf('_') !== -1) continue;
184
- const api = (await import(file)).default;
185
- if (isType(api.name, 'string') === false || api.name.trim() === '') {
186
- throw new Error(`接口 ${apiPath} 的 name 属性必须是非空字符串`);
187
- }
188
- if (api.auth !== false && api.auth !== true && Array.isArray(api.auth) === false) {
189
- throw new Error(`接口 ${apiPath} 的 auth 属性必须是布尔值或字符串数组`);
190
- }
191
- if (isType(api.fields, 'object') === false) {
192
- throw new Error(`接口 ${apiPath} 的 fields 属性必须是对象`);
193
- }
194
- if (isType(api.required, 'array') === false) {
195
- throw new Error(`接口 ${apiPath} 的 required 属性必须是数组`);
196
- }
197
- // 数组的每一项都必须是字符串
198
- if (api.required.some((item) => isType(item, 'string') === false)) {
199
- throw new Error(`接口 ${apiPath} required 属性必须是字符串数组`);
200
- }
201
- if (isType(api.handler, 'function') === false) {
202
- throw new Error(`接口 ${apiPath} 的 handler 属性必须是函数`);
248
+
249
+ totalApis++;
250
+ const singleApiStart = Bun.nanoseconds();
251
+
252
+ try {
253
+ const api = (await import(file)).default;
254
+ if (isType(api.name, 'string') === false || api.name.trim() === '') {
255
+ throw new Error(`接口 ${apiPath} name 属性必须是非空字符串`);
256
+ }
257
+ if (api.auth !== false && api.auth !== true && Array.isArray(api.auth) === false) {
258
+ throw new Error(`接口 ${apiPath} auth 属性必须是布尔值或字符串数组`);
259
+ }
260
+ if (isType(api.fields, 'object') === false) {
261
+ throw new Error(`接口 ${apiPath} 的 fields 属性必须是对象`);
262
+ }
263
+ if (isType(api.required, 'array') === false) {
264
+ throw new Error(`接口 ${apiPath} 的 required 属性必须是数组`);
265
+ }
266
+ // 数组的每一项都必须是字符串
267
+ if (api.required.some((item) => isType(item, 'string') === false)) {
268
+ throw new Error(`接口 ${apiPath} 的 required 属性必须是字符串数组`);
269
+ }
270
+ if (isType(api.handler, 'function') === false) {
271
+ throw new Error(`接口 ${apiPath} 的 handler 属性必须是函数`);
272
+ }
273
+ api.route = `${api.method.toUpperCase()}/api/${dirName}/${apiPath}`;
274
+ this.apiRoutes.set(api.route, api);
275
+
276
+ const singleApiTime = (Bun.nanoseconds() - singleApiStart) / 1_000_000;
277
+ loadedApis++;
278
+ // Logger.info(`${dirDisplayName}接口 ${apiPath} 加载成功,耗时: ${singleApiTime.toFixed(2)}ms`);
279
+ } catch (error) {
280
+ const singleApiTime = (Bun.nanoseconds() - singleApiStart) / 1_000_000;
281
+ failedApis++;
282
+ Logger.error({
283
+ msg: `${dirDisplayName}接口 ${apiPath} 加载失败,耗时: ${singleApiTime.toFixed(2)}ms`,
284
+ error: error.message,
285
+ stack: error.stack
286
+ });
203
287
  }
204
- api.route = `${api.method.toUpperCase()}/api/${dirName}/${apiPath}`;
205
- this.apiRoutes.set(api.route, api);
206
288
  }
289
+
290
+ const totalLoadTime = (Bun.nanoseconds() - loadStartTime) / 1_000_000;
291
+ Logger.info(`${dirDisplayName}接口加载完成! 总耗时: ${totalLoadTime.toFixed(2)}ms,总数: ${totalApis}, 成功: ${loadedApis}, 失败: ${failedApis}`);
207
292
  } catch (error) {
208
293
  Logger.error({
209
294
  msg: '加载接口时发生错误',
@@ -217,11 +302,17 @@ class BunPii {
217
302
  * 启动服务器
218
303
  */
219
304
  async listen(callback) {
305
+ const serverStartTime = Bun.nanoseconds();
306
+ Logger.info('开始启动 Befly 服务器...');
307
+
220
308
  await this.initCheck();
221
309
  await this.loadPlugins();
222
310
  await this.loadApis('core');
223
311
  await this.loadApis('app');
224
312
 
313
+ const totalStartupTime = (Bun.nanoseconds() - serverStartTime) / 1_000_000;
314
+ Logger.info(`服务器启动准备完成,总耗时: ${totalStartupTime.toFixed(2)}ms`);
315
+
225
316
  const server = Bun.serve({
226
317
  port: Env.APP_PORT,
227
318
  hostname: Env.APP_HOST,
@@ -229,7 +320,7 @@ class BunPii {
229
320
  '/': async (req) => {
230
321
  return Response.json({
231
322
  code: 0,
232
- msg: 'BunPii 接口服务已启动',
323
+ msg: 'Befly 接口服务已启动',
233
324
  data: {
234
325
  mode: Env.NODE_ENV
235
326
  }
@@ -327,7 +418,7 @@ class BunPii {
327
418
  }
328
419
 
329
420
  // 请求记录
330
- Logger.debug({
421
+ Logger.info({
331
422
  msg: '通用接口日志',
332
423
  请求路径: apiPath,
333
424
  请求方法: req.method,
@@ -400,10 +491,14 @@ class BunPii {
400
491
  }
401
492
  });
402
493
 
494
+ const finalStartupTime = (Bun.nanoseconds() - serverStartTime) / 1_000_000;
495
+ Logger.info(`🚀 Befly 服务器启动成功! 完整启动耗时: ${finalStartupTime.toFixed(2)}ms`);
496
+ Logger.info(`📡 服务器监听地址: http://${Env.APP_HOST}:${Env.APP_PORT}`);
497
+
403
498
  if (callback && typeof callback === 'function') {
404
499
  callback(server);
405
500
  }
406
501
  }
407
502
  }
408
503
 
409
- export { BunPii, Env, Api, Jwt, Crypto2, Logger, RYes, RNo };
504
+ export { Befly, Env, Api, Jwt, Crypto2, Logger, RYes, RNo };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "befly",
3
- "version": "1.0.3",
3
+ "version": "1.1.0",
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": "3bd2e1f01b94f2b576467db1b63a016b6717dbbe"
52
+ "gitHead": "c86df1d32fd5321912fed97a1bf7c1348ce9c730"
53
53
  }