befly 3.8.19 → 3.8.21

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 (78) hide show
  1. package/README.md +7 -6
  2. package/bunfig.toml +1 -1
  3. package/checks/checkApi.ts +92 -0
  4. package/checks/checkApp.ts +31 -0
  5. package/{check.ts → checks/checkTable.ts} +28 -159
  6. package/config.ts +71 -0
  7. package/hooks/auth.ts +30 -0
  8. package/hooks/cors.ts +48 -0
  9. package/hooks/errorHandler.ts +23 -0
  10. package/hooks/parser.ts +67 -0
  11. package/hooks/permission.ts +54 -0
  12. package/hooks/rateLimit.ts +70 -0
  13. package/hooks/requestId.ts +24 -0
  14. package/hooks/requestLogger.ts +25 -0
  15. package/hooks/responseFormatter.ts +64 -0
  16. package/hooks/validator.ts +34 -0
  17. package/lib/database.ts +28 -25
  18. package/lib/dbHelper.ts +3 -3
  19. package/lib/jwt.ts +90 -99
  20. package/lib/logger.ts +44 -23
  21. package/lib/redisHelper.ts +19 -22
  22. package/loader/loadApis.ts +69 -114
  23. package/loader/loadHooks.ts +65 -0
  24. package/loader/loadPlugins.ts +50 -219
  25. package/main.ts +106 -133
  26. package/package.json +23 -14
  27. package/paths.ts +20 -0
  28. package/plugins/cache.ts +1 -3
  29. package/plugins/db.ts +8 -11
  30. package/plugins/logger.ts +5 -3
  31. package/plugins/redis.ts +10 -14
  32. package/router/api.ts +60 -106
  33. package/router/root.ts +15 -12
  34. package/router/static.ts +54 -58
  35. package/sync/syncAll.ts +58 -0
  36. package/sync/syncApi.ts +264 -0
  37. package/sync/syncDb/apply.ts +194 -0
  38. package/sync/syncDb/constants.ts +76 -0
  39. package/sync/syncDb/ddl.ts +194 -0
  40. package/sync/syncDb/helpers.ts +200 -0
  41. package/sync/syncDb/index.ts +164 -0
  42. package/sync/syncDb/schema.ts +201 -0
  43. package/sync/syncDb/sqlite.ts +50 -0
  44. package/sync/syncDb/table.ts +321 -0
  45. package/sync/syncDb/tableCreate.ts +146 -0
  46. package/sync/syncDb/version.ts +72 -0
  47. package/sync/syncDb.ts +19 -0
  48. package/sync/syncDev.ts +206 -0
  49. package/sync/syncMenu.ts +331 -0
  50. package/tests/cipher.test.ts +248 -0
  51. package/tests/dbHelper-advanced.test.ts +717 -0
  52. package/tests/dbHelper-columns.test.ts +266 -0
  53. package/tests/dbHelper-execute.test.ts +240 -0
  54. package/tests/fields-redis-cache.test.ts +123 -0
  55. package/tests/fields-validate.test.ts +99 -0
  56. package/tests/integration.test.ts +202 -0
  57. package/tests/jwt.test.ts +122 -0
  58. package/tests/logger.test.ts +94 -0
  59. package/tests/redisHelper.test.ts +231 -0
  60. package/tests/sqlBuilder-advanced.test.ts +593 -0
  61. package/tests/sqlBuilder.test.ts +184 -0
  62. package/tests/util.test.ts +95 -0
  63. package/tests/validator-advanced.test.ts +653 -0
  64. package/tests/validator.test.ts +148 -0
  65. package/tests/xml.test.ts +101 -0
  66. package/tsconfig.json +2 -4
  67. package/types/api.d.ts +6 -0
  68. package/types/befly.d.ts +152 -28
  69. package/types/context.d.ts +29 -3
  70. package/types/hook.d.ts +35 -0
  71. package/types/index.ts +14 -1
  72. package/types/plugin.d.ts +6 -7
  73. package/types/sync.d.ts +403 -0
  74. package/env.ts +0 -106
  75. package/lib/middleware.ts +0 -275
  76. package/types/env.ts +0 -65
  77. package/types/util.d.ts +0 -45
  78. package/util.ts +0 -257
@@ -1,18 +1,22 @@
1
1
  /**
2
2
  * API 加载器
3
- * 负责扫描和加载所有 API 路由(组件、用户)
3
+ * 负责扫描和加载所有 API 路由(组件、项目)
4
4
  */
5
5
 
6
- import { relative, basename, join } from 'pathe';
6
+ // 内部依赖
7
7
  import { existsSync } from 'node:fs';
8
+
9
+ // 外部依赖
10
+ import { relative, basename, join } from 'pathe';
8
11
  import { isPlainObject } from 'es-toolkit/compat';
12
+ import { calcPerfTime, scanFiles, scanAddons, getAddonDir, addonDirExists } from 'befly-util';
13
+
14
+ // 相对导入
9
15
  import { Logger } from '../lib/logger.js';
10
- import { calcPerfTime } from '../util.js';
11
16
  import { projectApiDir } from '../paths.js';
12
- import { scanAddons, getAddonDir, addonDirExists } from '../util.js';
13
- import type { ApiRoute } from '../types/api.js';
14
17
 
15
- const API_GLOB_PATTERN = '**/*.{ts,js}';
18
+ // 类型导入
19
+ import type { ApiRoute } from '../types/api.js';
16
20
 
17
21
  /**
18
22
  * API 默认字段定义
@@ -52,103 +56,6 @@ const DEFAULT_API_FIELDS = {
52
56
  }
53
57
  } as const;
54
58
 
55
- /**
56
- * 扫描用户 API 文件
57
- */
58
- async function scanUserApis(): Promise<Array<{ file: string; routePrefix: string; displayName: string }>> {
59
- const apis: Array<{ file: string; routePrefix: string; displayName: string }> = [];
60
-
61
- if (!existsSync(projectApiDir)) {
62
- return apis;
63
- }
64
-
65
- const glob = new Bun.Glob(API_GLOB_PATTERN);
66
-
67
- for await (const file of glob.scan({
68
- cwd: projectApiDir,
69
- onlyFiles: true,
70
- absolute: true
71
- })) {
72
- if (file.endsWith('.d.ts')) {
73
- continue;
74
- }
75
- const apiPath = relative(projectApiDir, file).replace(/\.(ts|js)$/, '');
76
- if (apiPath.indexOf('_') !== -1) continue;
77
-
78
- apis.push({
79
- file: file,
80
- routePrefix: '',
81
- displayName: '用户'
82
- });
83
- }
84
-
85
- return apis;
86
- }
87
-
88
- /**
89
- * 扫描组件 API 文件
90
- */
91
- async function scanAddonApis(): Promise<Array<{ file: string; routePrefix: string; displayName: string }>> {
92
- const apis: Array<{ file: string; routePrefix: string; displayName: string }> = [];
93
- const glob = new Bun.Glob(API_GLOB_PATTERN);
94
- const addons = scanAddons();
95
-
96
- for (const addon of addons) {
97
- if (!addonDirExists(addon, 'apis')) continue;
98
-
99
- const addonApiDir = getAddonDir(addon, 'apis');
100
- for await (const file of glob.scan({
101
- cwd: addonApiDir,
102
- onlyFiles: true,
103
- absolute: true
104
- })) {
105
- if (file.endsWith('.d.ts')) {
106
- continue;
107
- }
108
- const apiPath = relative(addonApiDir, file).replace(/\.(ts|js)$/, '');
109
- if (apiPath.indexOf('_') !== -1) continue;
110
-
111
- apis.push({
112
- file: file,
113
- routePrefix: `addon/${addon}`,
114
- displayName: `组件${addon}`
115
- });
116
- }
117
- }
118
-
119
- return apis;
120
- }
121
-
122
- /**
123
- * 初始化单个 API
124
- */
125
- async function initApi(apiRoutes: Map<string, ApiRoute>, apiInfo: { file: string; routePrefix: string; displayName: string }): Promise<void> {
126
- const { file, routePrefix, displayName } = apiInfo;
127
- const apiDir = routePrefix === '' ? projectApiDir : getAddonDir(routePrefix.replace('addon/', ''), 'apis');
128
- const apiPath = relative(apiDir, file).replace(/\.(ts|js)$/, '');
129
-
130
- try {
131
- // Windows 下路径需要转换为正斜杠格式
132
- const filePath = file.replace(/\\/g, '/');
133
- const apiImport = await import(filePath);
134
- const api = apiImport.default;
135
-
136
- // 设置默认值
137
- api.method = api.method || 'POST';
138
- api.auth = api.auth !== undefined ? api.auth : true;
139
- // 合并默认字段:默认字段作为基础,API 自定义字段优先级更高
140
- api.fields = { ...DEFAULT_API_FIELDS, ...(api.fields || {}) };
141
- api.required = api.required || [];
142
-
143
- // 构建路由
144
- api.route = `${api.method.toUpperCase()}/api/${routePrefix ? routePrefix + '/' : ''}${apiPath}`;
145
- apiRoutes.set(api.route, api);
146
- } catch (error: any) {
147
- Logger.error(`[${displayName}] 接口 ${apiPath} 加载失败`, error);
148
- process.exit(1);
149
- }
150
- }
151
-
152
59
  /**
153
60
  * 加载所有 API 路由
154
61
  * @param apiRoutes - API 路由映射表
@@ -157,19 +64,67 @@ export async function loadApis(apiRoutes: Map<string, ApiRoute>): Promise<void>
157
64
  try {
158
65
  const loadStartTime = Bun.nanoseconds();
159
66
 
160
- // 阶段1:扫描所有 API
161
- const userApis = await scanUserApis();
162
- const addonApis = await scanAddonApis();
163
-
164
- // 阶段2:初始化所有 API(用户 → 组件)
165
- // 2.1 初始化用户 APIs
166
- for (const apiInfo of userApis) {
167
- await initApi(apiRoutes, apiInfo);
67
+ // 1. 扫描项目 API
68
+ const projectApiFiles = await scanFiles(projectApiDir);
69
+ const projectApiList = projectApiFiles.map((file) => ({
70
+ filePath: file.filePath,
71
+ relativePath: file.relativePath,
72
+ type: 'project' as const,
73
+ routePrefix: '',
74
+ typeName: '项目'
75
+ }));
76
+
77
+ // 2. 扫描组件 API
78
+ const addonApiList: Array<{
79
+ filePath: string;
80
+ relativePath: string;
81
+ type: 'addon';
82
+ routePrefix: string;
83
+ typeName: string;
84
+ }> = [];
85
+ const addons = scanAddons();
86
+ for (const addon of addons) {
87
+ if (!addonDirExists(addon, 'apis')) continue;
88
+
89
+ const addonApiDir = getAddonDir(addon, 'apis');
90
+ const addonApiFiles = await scanFiles(addonApiDir);
91
+
92
+ for (const file of addonApiFiles) {
93
+ addonApiList.push({
94
+ filePath: file.filePath,
95
+ relativePath: file.relativePath,
96
+ type: 'addon' as const,
97
+ routePrefix: `addon/${addon}`,
98
+ typeName: `组件${addon}`
99
+ });
100
+ }
168
101
  }
169
102
 
170
- // 2.2 初始化组件 APIs
171
- for (const apiInfo of addonApis) {
172
- await initApi(apiRoutes, apiInfo);
103
+ // 3. 合并所有 API 文件
104
+ const allApiFiles = [...projectApiList, ...addonApiList];
105
+
106
+ // 4. 遍历处理所有 API 文件
107
+ for (const apiFile of allApiFiles) {
108
+ try {
109
+ // Windows 下路径需要转换为正斜杠格式
110
+ const normalizedFilePath = apiFile.filePath.replace(/\\/g, '/');
111
+ const apiImport = await import(normalizedFilePath);
112
+ const api = apiImport.default;
113
+
114
+ // 设置默认值
115
+ api.method = api.method || 'POST';
116
+ api.auth = api.auth !== undefined ? api.auth : true;
117
+ // 合并默认字段:默认字段作为基础,API 自定义字段优先级更高
118
+ api.fields = { ...DEFAULT_API_FIELDS, ...(api.fields || {}) };
119
+ api.required = api.required || [];
120
+
121
+ // 构建路由
122
+ api.route = `${api.method.toUpperCase()}/api/${apiFile.routePrefix ? apiFile.routePrefix + '/' : ''}${apiFile.relativePath}`;
123
+ apiRoutes.set(api.route, api);
124
+ } catch (error: any) {
125
+ Logger.error(`[${apiFile.typeName}] 接口 ${apiFile.relativePath} 加载失败`, error);
126
+ process.exit(1);
127
+ }
173
128
  }
174
129
 
175
130
  const totalLoadTime = calcPerfTime(loadStartTime);
@@ -0,0 +1,65 @@
1
+ /**
2
+ * 钩子加载器
3
+ * 负责扫描和初始化所有钩子(核心、组件、项目)
4
+ */
5
+
6
+ // 外部依赖
7
+ import { scanAddons, getAddonDir } from 'befly-util';
8
+
9
+ // 相对导入
10
+ import { Logger } from '../lib/logger.js';
11
+ import { coreHookDir, projectHookDir } from '../paths.js';
12
+ import { sortModules, scanModules } from '../util.js';
13
+
14
+ // 类型导入
15
+ import type { Hook } from '../types/hook.js';
16
+
17
+ export async function loadHooks(befly: {
18
+ //
19
+ hookLists: Hook[];
20
+ pluginsConfig?: Record<string, any>;
21
+ }): Promise<void> {
22
+ try {
23
+ const allHooks: Hook[] = [];
24
+
25
+ // 1. 扫描核心钩子
26
+ const coreHooks = await scanModules<Hook>(coreHookDir, 'core', '钩子', befly.pluginsConfig);
27
+
28
+ // 2. 扫描组件钩子
29
+ const addonHooks: Hook[] = [];
30
+ const addons = scanAddons();
31
+ for (const addon of addons) {
32
+ const dir = getAddonDir(addon, 'hooks');
33
+ const hooks = await scanModules<Hook>(dir, 'addon', '钩子', befly.pluginsConfig, addon);
34
+ addonHooks.push(...hooks);
35
+ }
36
+
37
+ // 3. 扫描项目钩子
38
+ const appHooks = await scanModules<Hook>(projectHookDir, 'app', '钩子', befly.pluginsConfig);
39
+
40
+ // 4. 合并所有钩子
41
+ allHooks.push(...coreHooks);
42
+ allHooks.push(...addonHooks);
43
+ allHooks.push(...appHooks);
44
+
45
+ // 5. 过滤禁用的钩子
46
+ const disableHooks = (befly as any).config?.disableHooks || [];
47
+ const enabledHooks = allHooks.filter((hook) => !disableHooks.includes(hook.name));
48
+
49
+ if (disableHooks.length > 0) {
50
+ Logger.info(`禁用钩子: ${disableHooks.join(', ')}`);
51
+ }
52
+
53
+ // 6. 排序
54
+ const sortedHooks = sortModules(enabledHooks);
55
+ if (sortedHooks === false) {
56
+ Logger.error('钩子依赖关系错误,请检查 after 属性');
57
+ process.exit(1);
58
+ }
59
+
60
+ befly.hookLists.push(...sortedHooks);
61
+ } catch (error: any) {
62
+ Logger.error('加载钩子时发生错误', error);
63
+ process.exit(1);
64
+ }
65
+ }
@@ -1,249 +1,80 @@
1
1
  /**
2
2
  * 插件加载器
3
- * 负责扫描和初始化所有插件(核心、组件、用户)
3
+ * 负责扫描和初始化所有插件(核心、组件、项目)
4
4
  */
5
5
 
6
- import { basename } from 'pathe';
7
- import { existsSync } from 'node:fs';
8
- import { camelCase } from 'es-toolkit/string';
6
+ import { scanAddons, getAddonDir } from 'befly-util';
7
+
9
8
  import { Logger } from '../lib/logger.js';
10
- import { calcPerfTime } from '../util.js';
11
9
  import { corePluginDir, projectPluginDir } from '../paths.js';
12
- import { scanAddons, getAddonDir, addonDirExists } from '../util.js';
10
+ import { sortModules, scanModules } from '../util.js';
11
+
13
12
  import type { Plugin } from '../types/plugin.js';
14
13
  import type { BeflyContext } from '../types/befly.js';
15
14
 
16
- /**
17
- * 排序插件(根据依赖关系)
18
- */
19
- function sortPlugins(plugins: Plugin[]): Plugin[] | false {
20
- const result: Plugin[] = [];
21
- const visited = new Set<string>();
22
- const visiting = new Set<string>();
23
- const pluginMap: Record<string, Plugin> = Object.fromEntries(plugins.map((p) => [p.pluginName || p.name, p]));
24
- let isPass = true;
25
-
26
- const visit = (name: string): void => {
27
- if (visited.has(name)) return;
28
- if (visiting.has(name)) {
29
- isPass = false;
30
- return;
31
- }
32
-
33
- const plugin = pluginMap[name];
34
- if (!plugin) return;
35
-
36
- visiting.add(name);
37
- (plugin.after || []).forEach(visit);
38
- visiting.delete(name);
39
- visited.add(name);
40
- result.push(plugin);
41
- };
42
-
43
- plugins.forEach((p) => visit(p.pluginName || p.name));
44
- return isPass ? result : false;
45
- }
46
-
47
- /**
48
- * 扫描核心插件
49
- */
50
- async function scanCorePlugins(loadedPluginNames: Set<string>): Promise<Plugin[]> {
51
- const plugins: Plugin[] = [];
52
- const glob = new Bun.Glob('*.{ts,js}');
53
-
54
- for await (const file of glob.scan({
55
- cwd: corePluginDir,
56
- onlyFiles: true,
57
- absolute: true
58
- })) {
59
- if (file.endsWith('.d.ts')) continue;
60
- const fileName = basename(file).replace(/\.(ts|js)$/, '');
61
- if (fileName.startsWith('_')) continue;
62
-
63
- try {
64
- const pluginImport = await import(file);
65
- const plugin = pluginImport.default;
66
- plugin.pluginName = fileName;
67
- plugins.push(plugin);
68
- loadedPluginNames.add(fileName);
69
- } catch (err: any) {
70
- Logger.error(`核心插件 ${fileName} 导入失败`, err);
71
- process.exit(1);
72
- }
73
- }
74
-
75
- return plugins;
76
- }
77
-
78
- /**
79
- * 扫描组件插件
80
- */
81
- async function scanAddonPlugins(loadedPluginNames: Set<string>): Promise<Plugin[]> {
82
- const plugins: Plugin[] = [];
83
- const glob = new Bun.Glob('*.{ts,js}');
84
- const addons = scanAddons();
85
-
86
- for (const addon of addons) {
87
- if (!addonDirExists(addon, 'plugins')) continue;
88
-
89
- const addonPluginsDir = getAddonDir(addon, 'plugins');
90
- for await (const file of glob.scan({
91
- cwd: addonPluginsDir,
92
- onlyFiles: true,
93
- absolute: true
94
- })) {
95
- if (file.endsWith('.d.ts')) continue;
96
- const fileName = basename(file).replace(/\.(ts|js)$/, '');
97
- if (fileName.startsWith('_')) continue;
98
-
99
- const addonCamelCase = camelCase(addon);
100
- const fileNameCamelCase = camelCase(fileName);
101
- const pluginFullName = `addon${addonCamelCase.charAt(0).toUpperCase() + addonCamelCase.slice(1)}_${fileNameCamelCase}`;
102
-
103
- if (loadedPluginNames.has(pluginFullName)) {
104
- continue;
105
- }
106
-
107
- try {
108
- const normalizedFilePath = file.replace(/\\/g, '/');
109
- const pluginImport = await import(normalizedFilePath);
110
- const plugin = pluginImport.default;
111
- plugin.pluginName = pluginFullName;
112
- plugins.push(plugin);
113
- loadedPluginNames.add(pluginFullName);
114
- } catch (err: any) {
115
- Logger.error(`组件${addon} ${fileName} 导入失败`, err);
116
- process.exit(1);
117
- }
118
- }
119
- }
120
-
121
- return plugins;
122
- }
123
-
124
- /**
125
- * 扫描用户插件
126
- */
127
- async function scanUserPlugins(loadedPluginNames: Set<string>): Promise<Plugin[]> {
128
- const plugins: Plugin[] = [];
129
-
130
- if (!existsSync(projectPluginDir)) {
131
- return plugins;
132
- }
133
-
134
- const glob = new Bun.Glob('*.{ts,js}');
135
- for await (const file of glob.scan({
136
- cwd: projectPluginDir,
137
- onlyFiles: true,
138
- absolute: true
139
- })) {
140
- if (file.endsWith('.d.ts')) continue;
141
- const fileName = basename(file).replace(/\.(ts|js)$/, '');
142
- if (fileName.startsWith('_')) continue;
143
-
144
- const fileNameCamelCase = camelCase(fileName);
145
- const pluginFullName = `app${fileNameCamelCase.charAt(0).toUpperCase() + fileNameCamelCase.slice(1)}`;
146
-
147
- if (loadedPluginNames.has(pluginFullName)) {
148
- continue;
149
- }
150
-
151
- try {
152
- const normalizedFilePath = file.replace(/\\/g, '/');
153
- const pluginImport = await import(normalizedFilePath);
154
- const plugin = pluginImport.default;
155
- plugin.pluginName = pluginFullName;
156
- plugins.push(plugin);
157
- loadedPluginNames.add(pluginFullName);
158
- } catch (err: any) {
159
- Logger.error(`用户插件 ${fileName} 导入失败`, err);
160
- process.exit(1);
15
+ export async function loadPlugins(befly: {
16
+ //
17
+ pluginLists: Plugin[];
18
+ appContext: BeflyContext;
19
+ pluginsConfig?: Record<string, any>;
20
+ }): Promise<void> {
21
+ try {
22
+ const allPlugins: Plugin[] = [];
23
+
24
+ // 1. 扫描核心插件
25
+ const corePlugins = await scanModules<Plugin>(corePluginDir, 'core', '插件', befly.pluginsConfig);
26
+
27
+ // 2. 扫描组件插件
28
+ const addonPlugins: Plugin[] = [];
29
+ const addons = scanAddons();
30
+ for (const addon of addons) {
31
+ const dir = getAddonDir(addon, 'plugins');
32
+ const plugins = await scanModules<Plugin>(dir, 'addon', '插件', befly.pluginsConfig, addon);
33
+ addonPlugins.push(...plugins);
161
34
  }
162
- }
163
-
164
- return plugins;
165
- }
166
-
167
- /**
168
- * 初始化单个插件
169
- */
170
- async function initPlugin(befly: { pluginLists: Plugin[]; appContext: BeflyContext }, plugin: Plugin): Promise<void> {
171
- befly.pluginLists.push(plugin);
172
-
173
- if (typeof plugin?.onInit === 'function') {
174
- befly.appContext[plugin.pluginName] = await plugin?.onInit(befly.appContext);
175
- } else {
176
- befly.appContext[plugin.pluginName] = {};
177
- }
178
- }
179
35
 
180
- /**
181
- * 加载所有插件
182
- * @param befly - Befly实例(需要访问 pluginLists 和 appContext)
183
- */
184
- export async function loadPlugins(befly: { pluginLists: Plugin[]; appContext: BeflyContext }): Promise<void> {
185
- try {
186
- const loadStartTime = Bun.nanoseconds();
187
- const loadedPluginNames = new Set<string>();
36
+ // 3. 扫描项目插件
37
+ const appPlugins = await scanModules<Plugin>(projectPluginDir, 'app', '插件', befly.pluginsConfig);
188
38
 
189
- // 阶段1:扫描所有插件
190
- const corePlugins = await scanCorePlugins(loadedPluginNames);
191
- const addonPlugins = await scanAddonPlugins(loadedPluginNames);
192
- const userPlugins = await scanUserPlugins(loadedPluginNames);
39
+ // 4. 合并所有插件
40
+ allPlugins.push(...corePlugins);
41
+ allPlugins.push(...addonPlugins);
42
+ allPlugins.push(...appPlugins);
193
43
 
194
- // 阶段2:分层排序插件
195
- const sortedCorePlugins = sortPlugins(corePlugins);
196
- if (sortedCorePlugins === false) {
197
- Logger.error('核心插件依赖关系错误,请检查插件的 after 属性');
198
- process.exit(1);
199
- }
44
+ // 5. 过滤禁用的插件
45
+ const disablePlugins = (befly as any).config?.disablePlugins || [];
46
+ const enabledPlugins = allPlugins.filter((plugin) => !disablePlugins.includes(plugin.name));
200
47
 
201
- const sortedAddonPlugins = sortPlugins(addonPlugins);
202
- if (sortedAddonPlugins === false) {
203
- Logger.error('组件插件依赖关系错误,请检查插件的 after 属性');
204
- process.exit(1);
48
+ if (disablePlugins.length > 0) {
49
+ Logger.info(`禁用插件: ${disablePlugins.join(', ')}`);
205
50
  }
206
51
 
207
- const sortedUserPlugins = sortPlugins(userPlugins);
208
- if (sortedUserPlugins === false) {
209
- Logger.error('用户插件依赖关系错误,请检查插件的 after 属性');
52
+ // 6. 排序与初始化
53
+ const sortedPlugins = sortModules(enabledPlugins);
54
+ if (sortedPlugins === false) {
55
+ Logger.error('插件依赖关系错误,请检查 after 属性');
210
56
  process.exit(1);
211
57
  }
212
58
 
213
- // 阶段3:分层初始化插件(核心 组件 用户)
214
- // 3.1 初始化核心插件
215
- for (const plugin of sortedCorePlugins) {
59
+ for (const plugin of sortedPlugins) {
216
60
  try {
217
- await initPlugin(befly, plugin);
218
- } catch (error: any) {
219
- Logger.error(`核心插件 ${plugin.pluginName} 初始化失败`, error);
220
- process.exit(1);
221
- }
222
- }
61
+ befly.pluginLists.push(plugin);
223
62
 
224
- // 3.2 初始化组件插件
225
- for (const plugin of sortedAddonPlugins) {
226
- try {
227
- await initPlugin(befly, plugin);
63
+ if (typeof plugin.handler === 'function') {
64
+ befly.appContext[plugin.name!] = await plugin.handler(befly.appContext);
65
+ } else {
66
+ befly.appContext[plugin.name!] = {};
67
+ }
228
68
  } catch (error: any) {
229
- Logger.error(`组件插件 ${plugin.pluginName} 初始化失败`, error);
69
+ Logger.error(`插件 ${plugin.name} 初始化失败`, error);
230
70
  process.exit(1);
231
71
  }
232
72
  }
233
-
234
- // 3.3 初始化用户插件
235
- for (const plugin of sortedUserPlugins) {
236
- try {
237
- await initPlugin(befly, plugin);
238
- } catch (error: any) {
239
- Logger.error(`用户插件 ${plugin.pluginName} 初始化失败`, error);
240
- process.exit(1);
241
- }
242
- }
243
-
244
- const totalLoadTime = calcPerfTime(loadStartTime);
245
73
  } catch (error: any) {
246
74
  Logger.error('加载插件时发生错误', error);
247
75
  process.exit(1);
248
76
  }
249
77
  }
78
+
79
+ // ==================== 钩子加载逻辑 ====================
80
+ // 已移动到 loadHooks.ts