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.
- package/check.ts +165 -92
- package/env.ts +3 -3
- package/lib/cacheHelper.ts +81 -0
- package/lib/database.ts +1 -1
- package/loader/loadApis.ts +172 -0
- package/{lifecycle → loader}/loadPlugins.ts +10 -10
- package/main.ts +108 -12
- package/package.json +4 -4
- package/paths.ts +7 -0
- package/util.ts +85 -1
- package/lib/addon.ts +0 -77
- package/lifecycle/bootstrap.ts +0 -49
- package/lifecycle/checker.ts +0 -122
- package/lifecycle/lifecycle.ts +0 -61
- package/lifecycle/loadApis.ts +0 -164
- package/menu.json +0 -55
- package/plugins/cache.ts +0 -22
- package/plugins/db.ts +0 -59
- package/plugins/logger.ts +0 -27
- package/plugins/redis.ts +0 -41
package/lifecycle/checker.ts
DELETED
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 系统检查管理器
|
|
3
|
-
* 负责在框架启动前执行系统检查
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { join, basename } from 'pathe';
|
|
7
|
-
import { existsSync, statSync } from 'node:fs';
|
|
8
|
-
import { Logger } from '../lib/logger.js';
|
|
9
|
-
import { calcPerfTime } from '../util.js';
|
|
10
|
-
import { projectCheckDir } from '../paths.js';
|
|
11
|
-
import { checkDefault } from '../check.js';
|
|
12
|
-
import { Addon } from '../lib/addon.js';
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* 系统检查器类
|
|
16
|
-
*/
|
|
17
|
-
export class Checker {
|
|
18
|
-
/**
|
|
19
|
-
* 执行所有系统检查
|
|
20
|
-
*/
|
|
21
|
-
static async run(): Promise<void> {
|
|
22
|
-
try {
|
|
23
|
-
const checkStartTime = Bun.nanoseconds();
|
|
24
|
-
|
|
25
|
-
// 先执行默认检查(有异常会自动抛出)
|
|
26
|
-
await checkDefault();
|
|
27
|
-
|
|
28
|
-
const glob = new Bun.Glob('*.{ts}');
|
|
29
|
-
|
|
30
|
-
// 统计信息
|
|
31
|
-
const stats = {
|
|
32
|
-
totalChecks: 0,
|
|
33
|
-
passedChecks: 0,
|
|
34
|
-
failedChecks: 0
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
// 检查目录列表:先项目,后 addons
|
|
38
|
-
const checkDirs: Array<{ path: string; type: 'app' | 'addon'; addonName?: string }> = [];
|
|
39
|
-
|
|
40
|
-
// 添加项目 checks 目录(如果存在)
|
|
41
|
-
if (existsSync(projectCheckDir) && statSync(projectCheckDir).isDirectory()) {
|
|
42
|
-
checkDirs.push({ path: projectCheckDir, type: 'app' });
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// 添加所有 addon 的 checks 目录
|
|
46
|
-
const addons = Addon.scan();
|
|
47
|
-
for (const addon of addons) {
|
|
48
|
-
if (Addon.dirExists(addon, 'checks')) {
|
|
49
|
-
checkDirs.push({
|
|
50
|
-
path: Addon.getDir(addon, 'checks'),
|
|
51
|
-
type: 'addon',
|
|
52
|
-
addonName: addon
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// 按顺序扫描并执行检查函数
|
|
58
|
-
for (const checkConfig of checkDirs) {
|
|
59
|
-
const { path: checkDir, type: type } = checkConfig;
|
|
60
|
-
const addonName = 'addonName' in checkConfig ? checkConfig.addonName : undefined;
|
|
61
|
-
const checkTypeLabel = type === 'app' ? '项目' : `组件${addonName}`;
|
|
62
|
-
|
|
63
|
-
for await (const file of glob.scan({
|
|
64
|
-
cwd: checkDir,
|
|
65
|
-
onlyFiles: true,
|
|
66
|
-
absolute: true
|
|
67
|
-
})) {
|
|
68
|
-
const fileName = basename(file);
|
|
69
|
-
if (fileName.startsWith('_')) continue; // 跳过以下划线开头的文件
|
|
70
|
-
|
|
71
|
-
try {
|
|
72
|
-
stats.totalChecks++;
|
|
73
|
-
const singleCheckStart = Bun.nanoseconds();
|
|
74
|
-
|
|
75
|
-
// 导入检查模块
|
|
76
|
-
const checkModule = await import(file);
|
|
77
|
-
|
|
78
|
-
// 获取 default 导出的检查函数
|
|
79
|
-
const checkFn = checkModule.default;
|
|
80
|
-
|
|
81
|
-
// 执行检查函数
|
|
82
|
-
if (typeof checkFn === 'function') {
|
|
83
|
-
const checkResult = await checkFn();
|
|
84
|
-
const singleCheckTime = calcPerfTime(singleCheckStart);
|
|
85
|
-
|
|
86
|
-
// 检查返回值是否为 boolean
|
|
87
|
-
if (typeof checkResult !== 'boolean') {
|
|
88
|
-
Logger.warn(`${checkTypeLabel}检查 ${fileName} 返回值必须为 true 或 false,当前为 ${typeof checkResult}`);
|
|
89
|
-
stats.failedChecks++;
|
|
90
|
-
} else if (checkResult === true) {
|
|
91
|
-
stats.passedChecks++;
|
|
92
|
-
} else {
|
|
93
|
-
Logger.warn(`${checkTypeLabel}检查未通过: ${fileName}`);
|
|
94
|
-
stats.failedChecks++;
|
|
95
|
-
}
|
|
96
|
-
} else {
|
|
97
|
-
Logger.warn(`${checkTypeLabel}检查文件 ${fileName} 未找到 default 导出的检查函数`);
|
|
98
|
-
stats.failedChecks++;
|
|
99
|
-
}
|
|
100
|
-
} catch (error: any) {
|
|
101
|
-
const singleCheckTime = calcPerfTime(Bun.nanoseconds());
|
|
102
|
-
Logger.error(`${checkTypeLabel}检查失败 ${fileName},耗时: ${singleCheckTime}`, error);
|
|
103
|
-
stats.failedChecks++;
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
const totalCheckTime = calcPerfTime(checkStartTime);
|
|
109
|
-
|
|
110
|
-
// 输出检查结果统计
|
|
111
|
-
if (stats.failedChecks > 0) {
|
|
112
|
-
Logger.error(`系统检查失败: ${stats.failedChecks}/${stats.totalChecks},耗时: ${totalCheckTime}`);
|
|
113
|
-
process.exit(1);
|
|
114
|
-
} else if (stats.totalChecks > 0) {
|
|
115
|
-
Logger.info(`系统检查通过: ${stats.passedChecks}/${stats.totalChecks},耗时: ${totalCheckTime}`);
|
|
116
|
-
}
|
|
117
|
-
} catch (error: any) {
|
|
118
|
-
Logger.error('执行系统检查时发生错误', error);
|
|
119
|
-
process.exit(1);
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
}
|
package/lifecycle/lifecycle.ts
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 生命周期管理器
|
|
3
|
-
* 统一管理框架的启动流程:检查、加载插件、加载API、启动服务器
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { Logger } from '../lib/logger.js';
|
|
7
|
-
import { Database } from '../lib/database.js';
|
|
8
|
-
import { loadPlugins } from './loadPlugins.js';
|
|
9
|
-
import { loadApis } from './loadApis.js';
|
|
10
|
-
import { Checker } from './checker.js';
|
|
11
|
-
import { Env } from '../env.js';
|
|
12
|
-
import { calcPerfTime } from '../util.js';
|
|
13
|
-
import { Addon } from '../lib/addon.js';
|
|
14
|
-
import { Bootstrap } from './bootstrap.js';
|
|
15
|
-
|
|
16
|
-
import type { Server } from 'bun';
|
|
17
|
-
import type { Plugin } from '../types/plugin.js';
|
|
18
|
-
import type { ApiRoute } from '../types/api.js';
|
|
19
|
-
import type { BeflyContext } from '../types/befly.js';
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* 生命周期管理类
|
|
23
|
-
*/
|
|
24
|
-
export class Lifecycle {
|
|
25
|
-
/** API 路由映射表 */
|
|
26
|
-
private apiRoutes: Map<string, ApiRoute> = new Map();
|
|
27
|
-
|
|
28
|
-
/** 插件列表 */
|
|
29
|
-
private pluginLists: Plugin[] = [];
|
|
30
|
-
|
|
31
|
-
constructor() {}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* 启动完整的生命周期流程
|
|
35
|
-
* @param appContext - 应用上下文
|
|
36
|
-
*/
|
|
37
|
-
async start(appContext: BeflyContext): Promise<Server> {
|
|
38
|
-
const serverStartTime = Bun.nanoseconds();
|
|
39
|
-
|
|
40
|
-
// 1. 执行系统检查
|
|
41
|
-
await Checker.run();
|
|
42
|
-
|
|
43
|
-
// 2. 加载插件
|
|
44
|
-
await loadPlugins({
|
|
45
|
-
pluginLists: this.pluginLists,
|
|
46
|
-
appContext: appContext
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
// // 3. 加载所有 API
|
|
50
|
-
await loadApis(this.apiRoutes);
|
|
51
|
-
|
|
52
|
-
// 4. 启动 HTTP 服务器
|
|
53
|
-
const totalStartupTime = calcPerfTime(serverStartTime);
|
|
54
|
-
|
|
55
|
-
return await Bootstrap.start({
|
|
56
|
-
apiRoutes: this.apiRoutes,
|
|
57
|
-
pluginLists: this.pluginLists,
|
|
58
|
-
appContext: appContext
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
}
|
package/lifecycle/loadApis.ts
DELETED
|
@@ -1,164 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* API 加载器
|
|
3
|
-
* 负责扫描和加载所有 API 路由(核心、组件、用户)
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { relative, basename } 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 { coreApiDir, projectApiDir } from '../paths.js';
|
|
12
|
-
import { Addon } from '../lib/addon.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
|
-
* @param apiDir - API 目录路径
|
|
56
|
-
* @param apiRoutes - API 路由映射表
|
|
57
|
-
* @param routePrefix - 路由前缀(如 'core', 'addon/admin', '')
|
|
58
|
-
* @param displayName - 显示名称(用于日志)
|
|
59
|
-
*/
|
|
60
|
-
async function scanApisFromDir(apiDir: string, apiRoutes: Map<string, ApiRoute>, routePrefix: string, displayName: string): Promise<void> {
|
|
61
|
-
if (!existsSync(apiDir)) {
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const glob = new Bun.Glob('**/*.ts');
|
|
66
|
-
|
|
67
|
-
for await (const file of glob.scan({
|
|
68
|
-
cwd: apiDir,
|
|
69
|
-
onlyFiles: true,
|
|
70
|
-
absolute: true
|
|
71
|
-
})) {
|
|
72
|
-
const fileName = basename(file).replace(/\.ts$/, '');
|
|
73
|
-
const apiPath = relative(apiDir, file).replace(/\.ts$/, '');
|
|
74
|
-
if (apiPath.indexOf('_') !== -1) continue;
|
|
75
|
-
|
|
76
|
-
try {
|
|
77
|
-
const apiImport = await import(file);
|
|
78
|
-
const api = apiImport.default;
|
|
79
|
-
// 验证必填属性:name 和 handler
|
|
80
|
-
if (typeof api.name !== 'string' || api.name.trim() === '') {
|
|
81
|
-
throw new Error(`接口 ${apiPath} 的 name 属性必须是非空字符串`);
|
|
82
|
-
}
|
|
83
|
-
if (typeof api.handler !== 'function') {
|
|
84
|
-
throw new Error(`接口 ${apiPath} 的 handler 属性必须是函数`);
|
|
85
|
-
}
|
|
86
|
-
// 设置默认值
|
|
87
|
-
api.method = api.method || 'POST';
|
|
88
|
-
api.auth = api.auth !== undefined ? api.auth : true;
|
|
89
|
-
// 合并默认字段:先设置自定义字段,再用默认字段覆盖(默认字段优先级更高)
|
|
90
|
-
api.fields = { ...(api.fields || {}), ...DEFAULT_API_FIELDS };
|
|
91
|
-
api.required = api.required || [];
|
|
92
|
-
// 验证可选属性的类型(如果提供了)
|
|
93
|
-
if (api.method && !['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS'].includes(api.method.toUpperCase())) {
|
|
94
|
-
throw new Error(`接口 ${apiPath} 的 method 属性必须是有效的 HTTP 方法`);
|
|
95
|
-
}
|
|
96
|
-
if (api.auth !== undefined && typeof api.auth !== 'boolean') {
|
|
97
|
-
throw new Error(`接口 ${apiPath} 的 auth 属性必须是布尔值 (true=需登录, false=公开)`);
|
|
98
|
-
}
|
|
99
|
-
if (api.fields && !isPlainObject(api.fields)) {
|
|
100
|
-
throw new Error(`接口 ${apiPath} 的 fields 属性必须是对象`);
|
|
101
|
-
}
|
|
102
|
-
if (api.required && !Array.isArray(api.required)) {
|
|
103
|
-
throw new Error(`接口 ${apiPath} 的 required 属性必须是数组`);
|
|
104
|
-
}
|
|
105
|
-
if (api.required && api.required.some((item: any) => typeof item !== 'string')) {
|
|
106
|
-
throw new Error(`接口 ${apiPath} 的 required 属性必须是字符串数组`);
|
|
107
|
-
}
|
|
108
|
-
// 构建路由
|
|
109
|
-
api.route = `${api.method.toUpperCase()}/api/${routePrefix ? routePrefix + '/' : ''}${apiPath}`;
|
|
110
|
-
apiRoutes.set(api.route, api);
|
|
111
|
-
} catch (error: any) {
|
|
112
|
-
Logger.error(`[${displayName}] 接口 ${apiPath} 加载失败`, error);
|
|
113
|
-
process.exit(1);
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* 扫描核心 APIs
|
|
120
|
-
*/
|
|
121
|
-
async function scanCoreApis(apiRoutes: Map<string, ApiRoute>): Promise<void> {
|
|
122
|
-
await scanApisFromDir(coreApiDir, apiRoutes, 'core', '核心');
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* 扫描组件 APIs
|
|
127
|
-
*/
|
|
128
|
-
async function scanAddonApis(apiRoutes: Map<string, ApiRoute>): Promise<void> {
|
|
129
|
-
const addons = Addon.scan();
|
|
130
|
-
|
|
131
|
-
for (const addon of addons) {
|
|
132
|
-
if (!Addon.dirExists(addon, 'apis')) continue;
|
|
133
|
-
|
|
134
|
-
const addonApiDir = Addon.getDir(addon, 'apis');
|
|
135
|
-
await scanApisFromDir(addonApiDir, apiRoutes, `addon/${addon}`, `组件${addon}`);
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* 扫描用户 APIs
|
|
141
|
-
*/
|
|
142
|
-
async function scanUserApis(apiRoutes: Map<string, ApiRoute>): Promise<void> {
|
|
143
|
-
await scanApisFromDir(projectApiDir, apiRoutes, '', '用户');
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* 加载所有 API 路由
|
|
148
|
-
* @param apiRoutes - API 路由映射表
|
|
149
|
-
*/
|
|
150
|
-
export async function loadApis(apiRoutes: Map<string, ApiRoute>): Promise<void> {
|
|
151
|
-
try {
|
|
152
|
-
const loadStartTime = Bun.nanoseconds();
|
|
153
|
-
|
|
154
|
-
// 扫描所有 APIs
|
|
155
|
-
await scanCoreApis(apiRoutes);
|
|
156
|
-
await scanAddonApis(apiRoutes);
|
|
157
|
-
await scanUserApis(apiRoutes);
|
|
158
|
-
|
|
159
|
-
const totalLoadTime = calcPerfTime(loadStartTime);
|
|
160
|
-
} catch (error: any) {
|
|
161
|
-
Logger.error('加载 API 时发生错误', error);
|
|
162
|
-
process.exit(1);
|
|
163
|
-
}
|
|
164
|
-
}
|
package/menu.json
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
[
|
|
2
|
-
{
|
|
3
|
-
"name": "首页",
|
|
4
|
-
"path": "/internal/index",
|
|
5
|
-
"icon": "",
|
|
6
|
-
"sort": 1,
|
|
7
|
-
"type": 1
|
|
8
|
-
},
|
|
9
|
-
{
|
|
10
|
-
"name": "人员管理",
|
|
11
|
-
"path": "_people",
|
|
12
|
-
"icon": "",
|
|
13
|
-
"sort": 2,
|
|
14
|
-
"type": 1,
|
|
15
|
-
"children": [
|
|
16
|
-
{
|
|
17
|
-
"name": "管理员管理",
|
|
18
|
-
"path": "/internal/admin",
|
|
19
|
-
"icon": "",
|
|
20
|
-
"sort": 2,
|
|
21
|
-
"type": 1
|
|
22
|
-
}
|
|
23
|
-
]
|
|
24
|
-
},
|
|
25
|
-
{
|
|
26
|
-
"name": "权限设置",
|
|
27
|
-
"path": "_permission",
|
|
28
|
-
"icon": "",
|
|
29
|
-
"sort": 3,
|
|
30
|
-
"type": 1,
|
|
31
|
-
"children": [
|
|
32
|
-
{
|
|
33
|
-
"name": "菜单管理",
|
|
34
|
-
"path": "/internal/menu",
|
|
35
|
-
"icon": "",
|
|
36
|
-
"sort": 4,
|
|
37
|
-
"type": 1
|
|
38
|
-
},
|
|
39
|
-
{
|
|
40
|
-
"name": "角色管理",
|
|
41
|
-
"path": "/internal/role",
|
|
42
|
-
"icon": "",
|
|
43
|
-
"sort": 5,
|
|
44
|
-
"type": 1
|
|
45
|
-
}
|
|
46
|
-
]
|
|
47
|
-
},
|
|
48
|
-
{
|
|
49
|
-
"name": "字典管理",
|
|
50
|
-
"path": "/internal/dict",
|
|
51
|
-
"icon": "",
|
|
52
|
-
"sort": 6,
|
|
53
|
-
"type": 1
|
|
54
|
-
}
|
|
55
|
-
]
|
package/plugins/cache.ts
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 缓存插件 - TypeScript 版本
|
|
3
|
-
* 负责在服务器启动时缓存接口、菜单和角色权限到 Redis
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { CacheHelper } from '../lib/cacheHelper.js';
|
|
7
|
-
import type { Plugin } from '../types/plugin.js';
|
|
8
|
-
import type { BeflyContext } from '../types/befly.js';
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* 缓存插件
|
|
12
|
-
*/
|
|
13
|
-
const cachePlugin: Plugin = {
|
|
14
|
-
name: '_cache',
|
|
15
|
-
after: ['_db', '_redis'],
|
|
16
|
-
|
|
17
|
-
async onInit(befly: BeflyContext): Promise<CacheHelper> {
|
|
18
|
-
return new CacheHelper(befly);
|
|
19
|
-
}
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
export default cachePlugin;
|
package/plugins/db.ts
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 数据库插件 - TypeScript 版本
|
|
3
|
-
* 初始化数据库连接和 SQL 管理器
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { Env } from '../env.js';
|
|
7
|
-
import { Logger } from '../lib/logger.js';
|
|
8
|
-
import { Database } from '../lib/database.js';
|
|
9
|
-
import { DbHelper } from '../lib/dbHelper.js';
|
|
10
|
-
import type { Plugin } from '../types/plugin.js';
|
|
11
|
-
import type { BeflyContext } from '../types/befly.js';
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* 数据库插件
|
|
15
|
-
*/
|
|
16
|
-
const dbPlugin: Plugin = {
|
|
17
|
-
name: '_db',
|
|
18
|
-
after: ['_redis'],
|
|
19
|
-
|
|
20
|
-
async onInit(befly: BeflyContext): Promise<DbHelper | Record<string, never>> {
|
|
21
|
-
let sql: any = null;
|
|
22
|
-
|
|
23
|
-
try {
|
|
24
|
-
if (Env.DB_ENABLE === 1) {
|
|
25
|
-
// 创建 Bun SQL 客户端(内置连接池),并确保连接验证成功后再继续
|
|
26
|
-
// 从环境变量读取连接超时配置
|
|
27
|
-
const connectionTimeout = Env.DB_CONNECTION_TIMEOUT ? parseInt(Env.DB_CONNECTION_TIMEOUT) : 30000;
|
|
28
|
-
|
|
29
|
-
sql = await Database.connectSql({
|
|
30
|
-
connectionTimeout
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
// 创建数据库管理器实例,直接传入 sql 对象
|
|
34
|
-
const dbManager = new DbHelper(befly, sql);
|
|
35
|
-
|
|
36
|
-
return dbManager;
|
|
37
|
-
} else {
|
|
38
|
-
Logger.warn('数据库未启用(DB_ENABLE≠1),跳过初始化');
|
|
39
|
-
return {};
|
|
40
|
-
}
|
|
41
|
-
} catch (error: any) {
|
|
42
|
-
Logger.error('数据库初始化失败', error);
|
|
43
|
-
|
|
44
|
-
// 清理资源
|
|
45
|
-
if (sql) {
|
|
46
|
-
try {
|
|
47
|
-
await sql.close();
|
|
48
|
-
} catch (cleanupError: any) {
|
|
49
|
-
Logger.error('清理连接池失败:', cleanupError);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// 插件内禁止直接退出进程,抛出异常交由主流程统一处理
|
|
54
|
-
throw error;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
export default dbPlugin;
|
package/plugins/logger.ts
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 日志插件 - TypeScript 版本
|
|
3
|
-
* 提供全局日志功能
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { Logger } from '../lib/logger.js';
|
|
7
|
-
import type { Plugin } from '../types/plugin.js';
|
|
8
|
-
import type { BeflyContext } from '../types/befly.js';
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* 日志插件
|
|
12
|
-
*/
|
|
13
|
-
const loggerPlugin: Plugin = {
|
|
14
|
-
name: '_logger',
|
|
15
|
-
after: [],
|
|
16
|
-
|
|
17
|
-
async onInit(befly: BeflyContext): Promise<typeof Logger> {
|
|
18
|
-
try {
|
|
19
|
-
return Logger;
|
|
20
|
-
} catch (error: any) {
|
|
21
|
-
// 插件内禁止直接退出进程,抛出异常交由主流程统一处理
|
|
22
|
-
throw error;
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
export default loggerPlugin;
|
package/plugins/redis.ts
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Redis 插件 - TypeScript 版本
|
|
3
|
-
* 初始化 Redis 连接和助手工具
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { Env } from '../env.js';
|
|
7
|
-
import { Logger } from '../lib/logger.js';
|
|
8
|
-
import { RedisHelper } from '../lib/redisHelper.js';
|
|
9
|
-
import { Database } from '../lib/database.js';
|
|
10
|
-
import type { Plugin } from '../types/plugin.js';
|
|
11
|
-
import type { BeflyContext } from '../types/befly.js';
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Redis 插件
|
|
15
|
-
*/
|
|
16
|
-
const redisPlugin: Plugin = {
|
|
17
|
-
name: '_redis',
|
|
18
|
-
after: ['_logger'],
|
|
19
|
-
|
|
20
|
-
async onInit(befly: BeflyContext): Promise<typeof RedisHelper | Record<string, never>> {
|
|
21
|
-
try {
|
|
22
|
-
if (Env.REDIS_ENABLE === 1) {
|
|
23
|
-
// 初始化 Redis 客户端(统一使用 database.ts 的连接管理)
|
|
24
|
-
await Database.connectRedis();
|
|
25
|
-
|
|
26
|
-
// 返回工具对象,向下游以相同 API 暴露
|
|
27
|
-
return RedisHelper;
|
|
28
|
-
} else {
|
|
29
|
-
Logger.warn('Redis 未启用,跳过初始化');
|
|
30
|
-
return {};
|
|
31
|
-
}
|
|
32
|
-
} catch (error: any) {
|
|
33
|
-
Logger.error('Redis 初始化失败', error);
|
|
34
|
-
|
|
35
|
-
// 插件内禁止直接退出进程,抛出异常交由主流程统一处理
|
|
36
|
-
throw error;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
export default redisPlugin;
|