befly 3.8.2 → 3.8.4

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.
@@ -0,0 +1,172 @@
1
+ /**
2
+ * API 加载器
3
+ * 负责扫描和加载所有 API 路由(组件、用户)
4
+ */
5
+
6
+ import { relative, basename, join } from 'pathe';
7
+ import { existsSync } from 'node:fs';
8
+ import { isPlainObject } from 'es-toolkit/compat';
9
+ import { Logger } from '../lib/logger.js';
10
+ import { calcPerfTime } from '../util.js';
11
+ import { projectApiDir } from '../paths.js';
12
+ import { scanAddons, getAddonDir, addonDirExists } from '../util.js';
13
+ import type { ApiRoute } from '../types/api.js';
14
+
15
+ /**
16
+ * API 默认字段定义
17
+ * 这些字段会自动合并到所有 API 的 fields 中
18
+ * API 自定义的同名字段可以覆盖这些默认值
19
+ */
20
+ const DEFAULT_API_FIELDS = {
21
+ id: {
22
+ name: 'ID',
23
+ type: 'number',
24
+ min: 1,
25
+ max: null
26
+ },
27
+ page: {
28
+ name: '页码',
29
+ type: 'number',
30
+ min: 1,
31
+ max: 9999
32
+ },
33
+ limit: {
34
+ name: '每页数量',
35
+ type: 'number',
36
+ min: 1,
37
+ max: 100
38
+ },
39
+ keyword: {
40
+ name: '关键词',
41
+ type: 'string',
42
+ min: 1,
43
+ max: 50
44
+ },
45
+ state: {
46
+ name: '状态',
47
+ type: 'number',
48
+ min: 0,
49
+ max: 2
50
+ }
51
+ } as const;
52
+
53
+ /**
54
+ * 扫描用户 API 文件
55
+ */
56
+ async function scanUserApis(): Promise<Array<{ file: string; routePrefix: string; displayName: string }>> {
57
+ const apis: Array<{ file: string; routePrefix: string; displayName: string }> = [];
58
+
59
+ if (!existsSync(projectApiDir)) {
60
+ return apis;
61
+ }
62
+
63
+ const glob = new Bun.Glob('**/*.ts');
64
+
65
+ for await (const file of glob.scan({
66
+ cwd: projectApiDir,
67
+ onlyFiles: true,
68
+ absolute: true
69
+ })) {
70
+ const apiPath = relative(projectApiDir, file).replace(/\.ts$/, '');
71
+ if (apiPath.indexOf('_') !== -1) continue;
72
+
73
+ apis.push({
74
+ file: file,
75
+ routePrefix: '',
76
+ displayName: '用户'
77
+ });
78
+ }
79
+
80
+ return apis;
81
+ }
82
+
83
+ /**
84
+ * 扫描组件 API 文件
85
+ */
86
+ async function scanAddonApis(): Promise<Array<{ file: string; routePrefix: string; displayName: string }>> {
87
+ const apis: Array<{ file: string; routePrefix: string; displayName: string }> = [];
88
+ const glob = new Bun.Glob('**/*.ts');
89
+ const addons = scanAddons();
90
+
91
+ for (const addon of addons) {
92
+ if (!addonDirExists(addon, 'apis')) continue;
93
+
94
+ const addonApiDir = getAddonDir(addon, 'apis');
95
+ for await (const file of glob.scan({
96
+ cwd: addonApiDir,
97
+ onlyFiles: true,
98
+ absolute: true
99
+ })) {
100
+ const apiPath = relative(addonApiDir, file).replace(/\.ts$/, '');
101
+ if (apiPath.indexOf('_') !== -1) continue;
102
+
103
+ apis.push({
104
+ file: file,
105
+ routePrefix: `addon/${addon}`,
106
+ displayName: `组件${addon}`
107
+ });
108
+ }
109
+ }
110
+
111
+ return apis;
112
+ }
113
+
114
+ /**
115
+ * 初始化单个 API
116
+ */
117
+ async function initApi(apiRoutes: Map<string, ApiRoute>, apiInfo: { file: string; routePrefix: string; displayName: string }): Promise<void> {
118
+ const { file, routePrefix, displayName } = apiInfo;
119
+ const apiDir = routePrefix === '' ? projectApiDir : getAddonDir(routePrefix.replace('addon/', ''), 'apis');
120
+ const apiPath = relative(apiDir, file).replace(/\.ts$/, '');
121
+
122
+ try {
123
+ // Windows 下路径需要转换为正斜杠格式
124
+ const filePath = file.replace(/\\/g, '/');
125
+ const apiImport = await import(filePath);
126
+ const api = apiImport.default;
127
+
128
+ // 设置默认值
129
+ api.method = api.method || 'POST';
130
+ api.auth = api.auth !== undefined ? api.auth : true;
131
+ // 合并默认字段:先设置自定义字段,再用默认字段覆盖(默认字段优先级更高)
132
+ api.fields = { ...(api.fields || {}), ...DEFAULT_API_FIELDS };
133
+ api.required = api.required || [];
134
+
135
+ // 构建路由
136
+ api.route = `${api.method.toUpperCase()}/api/${routePrefix ? routePrefix + '/' : ''}${apiPath}`;
137
+ apiRoutes.set(api.route, api);
138
+ } catch (error: any) {
139
+ Logger.error(`[${displayName}] 接口 ${apiPath} 加载失败`, error);
140
+ process.exit(1);
141
+ }
142
+ }
143
+
144
+ /**
145
+ * 加载所有 API 路由
146
+ * @param apiRoutes - API 路由映射表
147
+ */
148
+ export async function loadApis(apiRoutes: Map<string, ApiRoute>): Promise<void> {
149
+ try {
150
+ const loadStartTime = Bun.nanoseconds();
151
+
152
+ // 阶段1:扫描所有 API
153
+ const userApis = await scanUserApis();
154
+ const addonApis = await scanAddonApis();
155
+
156
+ // 阶段2:初始化所有 API(用户 → 组件)
157
+ // 2.1 初始化用户 APIs
158
+ for (const apiInfo of userApis) {
159
+ await initApi(apiRoutes, apiInfo);
160
+ }
161
+
162
+ // 2.2 初始化组件 APIs
163
+ for (const apiInfo of addonApis) {
164
+ await initApi(apiRoutes, apiInfo);
165
+ }
166
+
167
+ const totalLoadTime = calcPerfTime(loadStartTime);
168
+ } catch (error: any) {
169
+ Logger.error('加载 API 时发生错误', error);
170
+ process.exit(1);
171
+ }
172
+ }
@@ -9,7 +9,7 @@ import { camelCase } from 'es-toolkit/string';
9
9
  import { Logger } from '../lib/logger.js';
10
10
  import { calcPerfTime } from '../util.js';
11
11
  import { corePluginDir, projectPluginDir } from '../paths.js';
12
- import { Addon } from '../lib/addon.js';
12
+ import { scanAddons, getAddonDir, addonDirExists } from '../util.js';
13
13
  import type { Plugin } from '../types/plugin.js';
14
14
  import type { BeflyContext } from '../types/befly.js';
15
15
 
@@ -80,12 +80,12 @@ async function scanCorePlugins(loadedPluginNames: Set<string>): Promise<Plugin[]
80
80
  async function scanAddonPlugins(loadedPluginNames: Set<string>): Promise<Plugin[]> {
81
81
  const plugins: Plugin[] = [];
82
82
  const glob = new Bun.Glob('*.ts');
83
- const addons = Addon.scan();
83
+ const addons = scanAddons();
84
84
 
85
85
  for (const addon of addons) {
86
- if (!Addon.dirExists(addon, 'plugins')) continue;
86
+ if (!addonDirExists(addon, 'plugins')) continue;
87
87
 
88
- const addonPluginsDir = Addon.getDir(addon, 'plugins');
88
+ const addonPluginsDir = getAddonDir(addon, 'plugins');
89
89
  for await (const file of glob.scan({
90
90
  cwd: addonPluginsDir,
91
91
  onlyFiles: true,
@@ -103,9 +103,9 @@ async function scanAddonPlugins(loadedPluginNames: Set<string>): Promise<Plugin[
103
103
  }
104
104
 
105
105
  try {
106
- const plugin = require(file);
107
- const pluginInstance = plugin.default;
108
- pluginInstance.pluginName = pluginFullName;
106
+ const pluginImport = await import(file);
107
+ const plugin = pluginImport.default;
108
+ plugin.pluginName = pluginFullName;
109
109
  plugins.push(pluginInstance);
110
110
  loadedPluginNames.add(pluginFullName);
111
111
  } catch (err: any) {
@@ -145,9 +145,9 @@ async function scanUserPlugins(loadedPluginNames: Set<string>): Promise<Plugin[]
145
145
  }
146
146
 
147
147
  try {
148
- const plugin = require(file);
149
- const pluginInstance = plugin.default;
150
- pluginInstance.pluginName = pluginFullName;
148
+ const pluginImport = await import(file);
149
+ const plugin = pluginImport.default;
150
+ plugin.pluginName = pluginFullName;
151
151
  plugins.push(pluginInstance);
152
152
  loadedPluginNames.add(pluginFullName);
153
153
  } catch (err: any) {
package/main.ts CHANGED
@@ -1,44 +1,136 @@
1
1
  /**
2
2
  * Befly 框架主入口文件
3
- * 提供简洁的框架接口,核心逻辑已提取到 lifecycle
3
+ * 提供简洁的框架接口,核心逻辑已提取到 loader
4
4
  */
5
5
 
6
6
  import { Env } from './env.js';
7
- import { Yes, No, keysToSnake, keysToCamel, arrayKeysToCamel, pickFields, fieldClear, calcPerfTime } from './util.js';
7
+
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
11
  import { Database } from './lib/database.js';
12
- import { Lifecycle } from './lifecycle/lifecycle.js';
12
+ import { loadPlugins } from './loader/loadPlugins.js';
13
+ import { loadApis } from './loader/loadApis.js';
14
+ import { rootHandler } from './router/root.js';
15
+ import { apiHandler } from './router/api.js';
16
+ import { staticHandler } from './router/static.js';
13
17
  import { coreDir } from './paths.js';
14
18
  import { DbHelper } from './lib/dbHelper.js';
15
19
  import { RedisHelper } from './lib/redisHelper.js';
16
- import { Addon } from './lib/addon.js';
17
- import { checkDefault } from './check.js';
20
+ import { checkTable, checkApi, checkApp } from './check.js';
21
+ import {
22
+ //
23
+ Yes,
24
+ No,
25
+ keysToSnake,
26
+ keysToCamel,
27
+ arrayKeysToCamel,
28
+ pickFields,
29
+ fieldClear,
30
+ calcPerfTime,
31
+ scanAddons,
32
+ getAddonDir,
33
+ addonDirExists
34
+ } from './util.js';
18
35
 
19
36
  import type { Server } from 'bun';
20
37
  import type { BeflyContext } from './types/befly.js';
38
+ import type { Plugin } from './types/plugin.js';
39
+ import type { ApiRoute } from './types/api.js';
21
40
  /**
22
41
  * Befly 框架核心类
23
42
  * 职责:管理应用上下文和生命周期
24
43
  */
25
44
  export class Befly {
26
- /** 生命周期管理器 */
27
- private lifecycle: Lifecycle;
45
+ /** API 路由映射表 */
46
+ private apiRoutes: Map<string, ApiRoute> = new Map();
47
+
48
+ /** 插件列表 */
49
+ private pluginLists: Plugin[] = [];
28
50
 
29
51
  /** 应用上下文 */
30
52
  public appContext: BeflyContext;
31
53
 
32
54
  constructor() {
33
- this.lifecycle = new Lifecycle();
34
55
  this.appContext = {};
35
56
  }
36
57
 
58
+ /**
59
+ * 启动完整的生命周期流程
60
+ * @returns HTTP 服务器实例
61
+ */
62
+ private async start(): Promise<Server> {
63
+ const serverStartTime = Bun.nanoseconds();
64
+
65
+ // 1. 加载所有 API(动态导入必须在最前面,避免 Bun 1.3.2 的崩溃 bug)
66
+ await loadApis(this.apiRoutes);
67
+
68
+ // 2. 执行项目结构检查
69
+ const appCheckResult = await checkApp();
70
+ if (!appCheckResult) {
71
+ Logger.error('项目结构检查失败,程序退出');
72
+ process.exit(1);
73
+ }
74
+
75
+ // 3. 执行表定义检查
76
+ const tableCheckResult = await checkTable();
77
+ if (!tableCheckResult) {
78
+ Logger.error('表定义检查失败,程序退出');
79
+ process.exit(1);
80
+ }
81
+
82
+ // 4. 执行 API 定义检查
83
+ const apiCheckResult = await checkApi();
84
+ if (!apiCheckResult) {
85
+ Logger.error('API 定义检查失败,程序退出');
86
+ process.exit(1);
87
+ }
88
+
89
+ // 5. 加载插件
90
+ await loadPlugins({
91
+ pluginLists: this.pluginLists,
92
+ appContext: this.appContext
93
+ });
94
+
95
+ // 4. 启动 HTTP 服务器
96
+ const totalStartupTime = calcPerfTime(serverStartTime);
97
+
98
+ return await this.startServer();
99
+ }
100
+
101
+ /**
102
+ * 启动 HTTP 服务器
103
+ * @returns HTTP 服务器实例
104
+ */
105
+ private async startServer(): Promise<Server> {
106
+ const startTime = Bun.nanoseconds();
107
+
108
+ const server = Bun.serve({
109
+ port: Env.APP_PORT,
110
+ hostname: Env.APP_HOST,
111
+ routes: {
112
+ '/': rootHandler,
113
+ '/api/*': apiHandler(this.apiRoutes, this.pluginLists, this.appContext),
114
+ '/*': staticHandler
115
+ },
116
+ error: (error: Error) => {
117
+ Logger.error('服务启动时发生错误', error);
118
+ return Response.json({ code: 1, msg: '内部服务器错误' });
119
+ }
120
+ });
121
+
122
+ const finalStartupTime = calcPerfTime(startTime);
123
+ Logger.info(`${Env.APP_NAME} 服务器启动成功! 服务器启动耗时: ${finalStartupTime}`);
124
+ Logger.info(`服务器监听地址: http://${Env.APP_HOST}:${Env.APP_PORT}`);
125
+
126
+ return server;
127
+ }
128
+
37
129
  /**
38
130
  * 启动服务器并注册优雅关闭处理
39
131
  */
40
132
  async listen(): Promise<Server> {
41
- const server = await this.lifecycle.start(this.appContext);
133
+ const server = await this.start();
42
134
 
43
135
  const gracefulShutdown = async (signal: string) => {
44
136
  // 1. 停止接收新请求
@@ -76,9 +168,10 @@ export {
76
168
  Database,
77
169
  DbHelper,
78
170
  RedisHelper,
79
- Addon,
80
171
  coreDir,
81
- checkDefault
172
+ checkTable,
173
+ checkApi,
174
+ checkApp
82
175
  };
83
176
 
84
177
  // 工具函数命名空间导出
@@ -88,5 +181,8 @@ export const utils = {
88
181
  arrayKeysToCamel: arrayKeysToCamel,
89
182
  pickFields: pickFields,
90
183
  fieldClear: fieldClear,
91
- calcPerfTime: calcPerfTime
184
+ calcPerfTime: calcPerfTime,
185
+ scanAddons: scanAddons,
186
+ getAddonDir: getAddonDir,
187
+ addonDirExists: addonDirExists
92
188
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "befly",
3
- "version": "3.8.2",
3
+ "version": "3.8.4",
4
4
  "description": "Befly - 为 Bun 专属打造的 TypeScript API 接口框架核心引擎",
5
5
  "type": "module",
6
6
  "private": false,
@@ -39,8 +39,8 @@
39
39
  "license": "Apache-2.0",
40
40
  "files": [
41
41
  "lib/",
42
- "lifecycle/",
43
- "plugins/",
42
+ "loader/",
43
+ "middleware/",
44
44
  "router/",
45
45
  "types/",
46
46
  ".gitignore",
@@ -69,5 +69,5 @@
69
69
  "es-toolkit": "^1.41.0",
70
70
  "pathe": "^2.0.3"
71
71
  },
72
- "gitHead": "c0844203f8fee734d2a8742f3b77b67bf0874681"
72
+ "gitHead": "40b4c3e6591454ff060416a6275142792e7de66c"
73
73
  }
package/paths.ts CHANGED
@@ -89,3 +89,10 @@ export const projectApiDir = join(projectDir, 'apis');
89
89
  * @usage 存放用户业务表定义(JSON 格式)
90
90
  */
91
91
  export const projectTableDir = join(projectDir, 'tables');
92
+
93
+ /**
94
+ * 项目组件目录
95
+ * @description {projectDir}/addons/
96
+ * @usage 存放本地组件(优先级高于 node_modules 中的组件)
97
+ */
98
+ export const projectAddonsDir = join(projectDir, 'addons');
package/util.ts CHANGED
@@ -5,7 +5,7 @@ import { isEmpty, isPlainObject } from 'es-toolkit/compat';
5
5
  import { snakeCase, camelCase, kebabCase } from 'es-toolkit/string';
6
6
  import { Env } from './env.js';
7
7
  import { Logger } from './lib/logger.js';
8
- import { projectDir } from './paths.js';
8
+ import { projectDir, projectAddonsDir } from './paths.js';
9
9
  import type { KeyValue } from './types/common.js';
10
10
  import type { JwtPayload, JwtSignOptions, JwtVerifyOptions } from './types/jwt';
11
11
  import type { Plugin } from './types/plugin.js';
@@ -171,3 +171,87 @@ export const calcPerfTime = (startTime: number, endTime: number = Bun.nanosecond
171
171
  return `${elapsedSeconds.toFixed(2)} 秒`;
172
172
  }
173
173
  };
174
+
175
+ // ========================================
176
+ // Addon 工具函数
177
+ // ========================================
178
+
179
+ /**
180
+ * 扫描所有可用的 addon
181
+ * 优先从本地 addons/ 目录加载,其次从 node_modules/@befly-addon/ 加载
182
+ * @returns addon 名称数组
183
+ */
184
+ export const scanAddons = (): string[] => {
185
+ const addons = new Set<string>();
186
+
187
+ // 1. 扫描本地 addons 目录(优先级高)
188
+ // if (existsSync(projectAddonsDir)) {
189
+ // try {
190
+ // const localAddons = fs.readdirSync(projectAddonsDir).filter((name) => {
191
+ // const fullPath = join(projectAddonsDir, name);
192
+ // try {
193
+ // const stat = statSync(fullPath);
194
+ // return stat.isDirectory() && !name.startsWith('_');
195
+ // } catch {
196
+ // return false;
197
+ // }
198
+ // });
199
+ // localAddons.forEach((name) => addons.add(name));
200
+ // } catch (err) {
201
+ // // 忽略本地目录读取错误
202
+ // }
203
+ // }
204
+
205
+ // 2. 扫描 node_modules/@befly-addon 目录
206
+ const beflyDir = join(projectDir, 'node_modules', '@befly-addon');
207
+ if (existsSync(beflyDir)) {
208
+ try {
209
+ const npmAddons = fs.readdirSync(beflyDir).filter((name) => {
210
+ // 如果本地已存在,跳过 npm 包版本
211
+ if (addons.has(name)) return false;
212
+
213
+ const fullPath = join(beflyDir, name);
214
+ try {
215
+ const stat = statSync(fullPath);
216
+ return stat.isDirectory();
217
+ } catch {
218
+ return false;
219
+ }
220
+ });
221
+ npmAddons.forEach((name) => addons.add(name));
222
+ } catch {
223
+ // 忽略 npm 目录读取错误
224
+ }
225
+ }
226
+
227
+ return Array.from(addons).sort();
228
+ };
229
+
230
+ /**
231
+ * 获取 addon 的指定子目录路径
232
+ * 优先返回本地 addons 目录,其次返回 node_modules 目录
233
+ * @param name - addon 名称
234
+ * @param subDir - 子目录名称
235
+ * @returns 完整路径
236
+ */
237
+ export const getAddonDir = (name: string, subDir: string): string => {
238
+ // 优先使用本地 addons 目录
239
+ // const localPath = join(projectAddonsDir, name, subDir);
240
+ // if (existsSync(localPath)) {
241
+ // return localPath;
242
+ // }
243
+
244
+ // 降级使用 node_modules 目录
245
+ return join(projectDir, 'node_modules', '@befly-addon', name, subDir);
246
+ };
247
+
248
+ /**
249
+ * 检查 addon 子目录是否存在
250
+ * @param name - addon 名称
251
+ * @param subDir - 子目录名称
252
+ * @returns 是否存在
253
+ */
254
+ export const addonDirExists = (name: string, subDir: string): boolean => {
255
+ const dir = getAddonDir(name, subDir);
256
+ return existsSync(dir) && statSync(dir).isDirectory();
257
+ };
package/lib/addon.ts DELETED
@@ -1,77 +0,0 @@
1
- /**
2
- * Addon 管理工具类
3
- * 提供 addon 的扫描、路径获取等功能
4
- */
5
-
6
- import fs from 'node:fs';
7
- import { join } from 'pathe';
8
- import { existsSync, statSync, readdirSync } from 'node:fs';
9
- import { projectDir } from '../paths.js';
10
-
11
- /**
12
- * Addon 管理类
13
- */
14
- export class Addon {
15
- /**
16
- * 扫描所有可用的 addon
17
- * @returns addon 名称数组
18
- */
19
- static scan(): string[] {
20
- const beflyDir = join(projectDir, 'node_modules', '@befly-addon');
21
-
22
- if (!existsSync(beflyDir)) {
23
- return [];
24
- }
25
-
26
- try {
27
- return fs
28
- .readdirSync(beflyDir)
29
- .filter((name) => {
30
- // addon 名称格式:admin, demo 等(不带 addon- 前缀)
31
- const fullPath = join(beflyDir, name);
32
- try {
33
- const stat = statSync(fullPath);
34
- return stat.isDirectory();
35
- } catch {
36
- return false;
37
- }
38
- })
39
- .sort();
40
- } catch {
41
- return [];
42
- }
43
- }
44
-
45
- /**
46
- * 获取 addon 的指定子目录路径
47
- * @param name - addon 名称
48
- * @param subDir - 子目录名称
49
- * @returns 完整路径
50
- */
51
- static getDir(name: string, subDir: string): string {
52
- return join(projectDir, 'node_modules', '@befly-addon', name, subDir);
53
- }
54
-
55
- /**
56
- * 检查 addon 子目录是否存在
57
- * @param name - addon 名称
58
- * @param subDir - 子目录名称
59
- * @returns 是否存在
60
- */
61
- static dirExists(name: string, subDir: string): boolean {
62
- const dir = this.getDir(name, subDir);
63
- return existsSync(dir) && statSync(dir).isDirectory();
64
- }
65
-
66
- /**
67
- * 获取插件目录列表
68
- * @param addonsDir - addons 根目录路径
69
- * @returns 插件名称数组
70
- */
71
- static getDirs(addonsDir: string): string[] {
72
- return readdirSync(addonsDir).filter((name) => {
73
- const addonPath = join(addonsDir, name);
74
- return statSync(addonPath).isDirectory() && !name.startsWith('_');
75
- });
76
- }
77
- }
@@ -1,49 +0,0 @@
1
- /**
2
- * 服务启动引导器
3
- * 负责组装和启动Bun HTTP服务器
4
- */
5
-
6
- import { Logger } from '../lib/logger.js';
7
- import { calcPerfTime } from '../util.js';
8
- import { Env } from '../env.js';
9
- import { rootHandler } from '../router/root.js';
10
- import { apiHandler } from '../router/api.js';
11
- import { staticHandler } from '../router/static.js';
12
-
13
- import type { Server } from 'bun';
14
- import type { BeflyContext } from '../types/befly.js';
15
- import type { ApiRoute } from '../types/api.js';
16
- import type { Plugin } from '../types/plugin.js';
17
-
18
- /**
19
- * 引导器类
20
- */
21
- export class Bootstrap {
22
- /**
23
- * 启动HTTP服务器
24
- * @param befly - Befly实例(需要访问 apiRoutes, pluginLists, appContext)
25
- */
26
- static async start(befly: { apiRoutes: Map<string, ApiRoute>; pluginLists: Plugin[]; appContext: BeflyContext }): Promise<Server> {
27
- const startTime = Bun.nanoseconds();
28
-
29
- const server = Bun.serve({
30
- port: Env.APP_PORT,
31
- hostname: Env.APP_HOST,
32
- routes: {
33
- '/': rootHandler,
34
- '/api/*': apiHandler(befly.apiRoutes, befly.pluginLists, befly.appContext),
35
- '/*': staticHandler
36
- },
37
- error: (error: Error) => {
38
- Logger.error('服务启动时发生错误', error);
39
- return Response.json({ code: 1, msg: '内部服务器错误' });
40
- }
41
- });
42
-
43
- const finalStartupTime = calcPerfTime(startTime);
44
- Logger.info(`${Env.APP_NAME} 服务器启动成功! 服务器启动耗时: ${finalStartupTime}`);
45
- Logger.info(`服务器监听地址: http://${Env.APP_HOST}:${Env.APP_PORT}`);
46
-
47
- return server;
48
- }
49
- }