@yumerijs/core 1.2.0 → 1.3.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/dist/command.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @time: 2025/03/25 23:53
2
+ * @time: 2025/08/14 09:48
3
3
  * @author: FireGuo
4
4
  * WindyPear-Team All right reserved
5
5
  **/
package/dist/command.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /**
3
- * @time: 2025/03/25 23:53
3
+ * @time: 2025/08/14 09:48
4
4
  * @author: FireGuo
5
5
  * WindyPear-Team All right reserved
6
6
  **/
package/dist/context.d.ts CHANGED
@@ -1,8 +1,25 @@
1
+ /**
2
+ * @time: 2025/08/14 19:10
3
+ * @author: FireGuo
4
+ * WindyPear-Team All right reserved
5
+ **/
1
6
  import { Core } from './core';
2
- import { Command } from './command';
3
7
  import { Route } from './route';
8
+ import { HookHandler } from './hook';
9
+ /**
10
+ * 插件上下文对象
11
+ * 每个插件一个 Context,用于管理插件注册的命令、路由、事件、组件和中间件
12
+ */
4
13
  export declare class Context {
5
14
  private core;
15
+ private routes;
16
+ private eventlisteners;
17
+ private components;
18
+ private middlewares;
19
+ private hooks;
20
+ /**
21
+ * 插件名称
22
+ */
6
23
  pluginname: string;
7
24
  /**
8
25
  * 创建 Context 实例
@@ -10,14 +27,10 @@ export declare class Context {
10
27
  * @param pluginname 插件名称
11
28
  */
12
29
  constructor(core: Core, pluginname: string);
13
- /**
14
- * @deprecated Use route() instead.
15
- */
16
- command(name: string): Command;
17
30
  /**
18
31
  * 注册路由
19
32
  * @param path 路由路径
20
- * @returns Route
33
+ * @returns Route 实例
21
34
  */
22
35
  route(path: string): Route;
23
36
  /**
@@ -33,8 +46,23 @@ export declare class Context {
33
46
  */
34
47
  use(name: string, callback: Function): void;
35
48
  /**
36
- * Unless nessesary, do not use core directly
37
- */
49
+ * 注册 Hook 钩子
50
+ * @param name Hook 点名称
51
+ * @param hookname 钩子名称
52
+ * @param callback 钩子回调函数
53
+ */
54
+ hook(name: string, hookname: string, callback: HookHandler): void;
55
+ /**
56
+ * 执行 Hook 钩子
57
+ * @param name Hook 点名称
58
+ * @param args Hook 参数
59
+ * @returns Promise<any[]>
60
+ */
61
+ executeHook(name: string, ...args: any[]): Promise<any[]>;
62
+ /**
63
+ * 获取 Core 实例
64
+ * @returns Core
65
+ */
38
66
  getCore(): Core;
39
67
  /**
40
68
  * 触发事件
@@ -45,7 +73,7 @@ export declare class Context {
45
73
  emit(event: string, ...args: any[]): Promise<void>;
46
74
  /**
47
75
  * 获取组件实例
48
- * @param name 组件名称
76
+ * @param name 组件名称
49
77
  * @returns 组件实例
50
78
  */
51
79
  getComponent(name: string): any;
@@ -53,7 +81,11 @@ export declare class Context {
53
81
  * 注册组件
54
82
  * @param name 组件名称
55
83
  * @param component 组件实例
56
- * @returns void
57
84
  */
58
85
  registerComponent(name: string, component: any): void;
86
+ /**
87
+ * 卸载插件时清理注册的所有资源
88
+ * 包括组件、路由、中间件和事件监听器
89
+ */
90
+ dispose(): void;
59
91
  }
package/dist/context.js CHANGED
@@ -1,9 +1,21 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Context = void 0;
4
- const command_1 = require("./command");
4
+ const route_1 = require("./route");
5
+ /**
6
+ * 插件上下文对象
7
+ * 每个插件一个 Context,用于管理插件注册的命令、路由、事件、组件和中间件
8
+ */
5
9
  class Context {
6
10
  core;
11
+ routes = [];
12
+ eventlisteners = [];
13
+ components = [];
14
+ middlewares = [];
15
+ hooks = {};
16
+ /**
17
+ * 插件名称
18
+ */
7
19
  pluginname;
8
20
  /**
9
21
  * 创建 Context 实例
@@ -14,33 +26,18 @@ class Context {
14
26
  this.core = core;
15
27
  this.pluginname = pluginname;
16
28
  }
17
- /**
18
- * @deprecated Use route() instead.
19
- */
20
- command(name) {
21
- if (this.core.commands[name]) {
22
- this.core.logger.warn(`Plugin "${this.pluginname}" attempt to register command "${name}", but it has been registered by plugin "${this.core.cmdtoplu[name]}."`);
23
- return new command_1.Command(this.core, name);
24
- }
25
- else {
26
- this.core.cmdtoplu[name] = this.pluginname;
27
- return this.core.command(name);
28
- }
29
- }
30
29
  /**
31
30
  * 注册路由
32
31
  * @param path 路由路径
33
- * @returns Route
32
+ * @returns Route 实例
34
33
  */
35
34
  route(path) {
36
35
  if (this.core.routes[path]) {
37
- this.core.logger.warn(`Plugin "${this.pluginname}" attempt to register route "${path}", but it has been registered by plugin "${this.core.routetoplu[path]}."`);
38
- return this.core.routes[path];
39
- }
40
- else {
41
- this.core.routetoplu[path] = this.pluginname;
42
- return this.core.route(path);
36
+ this.core.logger.warn(`Plugin "${this.pluginname}" attempt to register route "${path}", but it has already been registered.`);
37
+ return new route_1.Route(path);
43
38
  }
39
+ this.routes.push(path);
40
+ return this.core.route(path);
44
41
  }
45
42
  /**
46
43
  * 注册事件
@@ -48,14 +45,9 @@ class Context {
48
45
  * @param listener 事件监听器
49
46
  */
50
47
  on(name, listener) {
51
- // 存储该插件监听的事件,需要注意的是一个事件可由多个插件监听
52
- if (!this.core.evttoplu[name]) {
53
- this.core.evttoplu[name] = {};
54
- }
55
- if (!this.core.evttoplu[name][this.pluginname]) {
56
- this.core.evttoplu[name][this.pluginname] = [];
57
- }
58
- this.core.evttoplu[name][this.pluginname].push(listener);
48
+ // 记录插件自己的事件监听器
49
+ this.eventlisteners.push({ name, listener });
50
+ // 注册到 core 的全局事件监听器中
59
51
  this.core.on(name, listener);
60
52
  }
61
53
  /**
@@ -64,14 +56,32 @@ class Context {
64
56
  * @param callback 中间件回调函数
65
57
  */
66
58
  use(name, callback) {
67
- this.core.mdwtoplu[name] = this.pluginname;
68
- this.core.use(name, async (...args) => {
69
- return callback(...args);
70
- });
59
+ this.middlewares.push(name);
60
+ this.core.use(name, async (...args) => callback(...args));
61
+ }
62
+ /**
63
+ * 注册 Hook 钩子
64
+ * @param name Hook 点名称
65
+ * @param hookname 钩子名称
66
+ * @param callback 钩子回调函数
67
+ */
68
+ hook(name, hookname, callback) {
69
+ this.core.hook(name, hookname, callback);
70
+ this.hooks[name].push(hookname);
71
71
  }
72
72
  /**
73
- * Unless nessesary, do not use core directly
74
- */
73
+ * 执行 Hook 钩子
74
+ * @param name Hook 点名称
75
+ * @param args Hook 参数
76
+ * @returns Promise<any[]>
77
+ */
78
+ async executeHook(name, ...args) {
79
+ return await this.core.hookExecute(name, ...args);
80
+ }
81
+ /**
82
+ * 获取 Core 实例
83
+ * @returns Core
84
+ */
75
85
  getCore() {
76
86
  return this.core;
77
87
  }
@@ -86,7 +96,7 @@ class Context {
86
96
  }
87
97
  /**
88
98
  * 获取组件实例
89
- * @param name 组件名称
99
+ * @param name 组件名称
90
100
  * @returns 组件实例
91
101
  */
92
102
  getComponent(name) {
@@ -96,16 +106,50 @@ class Context {
96
106
  * 注册组件
97
107
  * @param name 组件名称
98
108
  * @param component 组件实例
99
- * @returns void
100
109
  */
101
110
  registerComponent(name, component) {
102
111
  if (this.core.components[name]) {
103
- this.core.logger.warn(`Plugin "${this.pluginname}" attempt to register component "${name}", but it has been registered by plugin "${this.core.comtoplu[name]}."`);
112
+ this.core.logger.warn(`Plugin "${this.pluginname}" attempt to register component "${name}", but it has already been registered.`);
104
113
  return;
105
114
  }
106
- this.core.comtoplu[name] = this.pluginname;
107
115
  this.core.components[name] = component;
108
- return;
116
+ this.components.push(name);
117
+ }
118
+ /**
119
+ * 卸载插件时清理注册的所有资源
120
+ * 包括组件、路由、中间件和事件监听器
121
+ */
122
+ dispose() {
123
+ // 删除组件
124
+ this.components.forEach((name) => {
125
+ delete this.core.components[name];
126
+ });
127
+ // 删除路由
128
+ this.routes.forEach((route) => {
129
+ delete this.core.routes[route];
130
+ });
131
+ // 删除中间件
132
+ this.middlewares.forEach((middleware) => {
133
+ delete this.core.globalMiddlewares[middleware];
134
+ });
135
+ // 删除事件监听器
136
+ this.eventlisteners.forEach(({ name, listener }) => {
137
+ if (this.core.eventListeners?.[name]) {
138
+ this.core.eventListeners[name] =
139
+ this.core.eventListeners[name].filter((l) => l !== listener);
140
+ }
141
+ });
142
+ // 删除钩子
143
+ for (const hook in this.hooks) {
144
+ this.hooks.hook.forEach((hookname) => {
145
+ this.core.unhook(hook, hookname);
146
+ });
147
+ }
148
+ // 清空 Context 内部记录,避免内存泄漏
149
+ this.components = [];
150
+ this.routes = [];
151
+ this.middlewares = [];
152
+ this.eventlisteners = [];
109
153
  }
110
154
  }
111
155
  exports.Context = Context;
package/dist/core.d.ts CHANGED
@@ -1,11 +1,11 @@
1
1
  import { Config } from './config';
2
2
  import { Logger } from './logger';
3
- import { Command } from './command';
4
3
  import { Session } from './session';
5
- import { Platform } from './platform';
6
4
  import { Middleware } from './middleware';
7
5
  import { Route } from './route';
8
6
  import { Context } from './context';
7
+ import { HookHandler, Hook } from './hook';
8
+ import { Server as CoreServer } from './server';
9
9
  interface Plugin {
10
10
  apply: (ctx: Context, config: Config) => Promise<void>;
11
11
  disable: (ctx: Context) => Promise<void>;
@@ -19,6 +19,13 @@ interface PluginLoader {
19
19
  installPluginDependencies(pluginName: string): Promise<void>;
20
20
  logger: Logger;
21
21
  }
22
+ interface CoreOptions {
23
+ port: number;
24
+ host: string;
25
+ staticDir: string;
26
+ enableCors: boolean;
27
+ enableWs: boolean;
28
+ }
22
29
  /**
23
30
  * 定义插件状态枚举
24
31
  */
@@ -35,60 +42,49 @@ export declare class Core {
35
42
  };
36
43
  };
37
44
  config: any;
38
- platforms: Platform[];
39
- private eventListeners;
45
+ eventListeners: {
46
+ [event: string]: ((...args: any[]) => Promise<void>)[];
47
+ };
40
48
  components: {
41
49
  [name: string]: any;
42
50
  };
43
- commands: Record<string, Command>;
44
51
  routes: Record<string, Route>;
45
52
  pluginLoader: PluginLoader;
46
53
  logger: Logger;
47
54
  providedComponents: {
48
55
  [name: string]: string;
49
56
  };
57
+ globalMiddlewares: Record<string, Middleware>;
58
+ pluginStatus: Record<string, PluginStatus>;
59
+ hooks: Record<string, Hook>;
60
+ coreConfig: CoreOptions;
61
+ server: CoreServer;
62
+ private pluginWatchers;
50
63
  private pluginModules;
51
64
  private configPath;
52
- private globalMiddlewares;
53
65
  /**
54
- * @deprecated 命令与插件对应关系
66
+ * 插件名 -> Context 映射
55
67
  */
56
- cmdtoplu: Record<string, string>;
68
+ private pluginContexts;
69
+ constructor(pluginLoader?: PluginLoader, coreConfig?: CoreOptions);
57
70
  /**
58
- * 路由与插件对应关系
71
+ * 获取或创建插件对应 Context
59
72
  */
60
- routetoplu: Record<string, string>;
73
+ getContext(pluginName: string): Context;
61
74
  /**
62
- * 组件与插件对应关系
63
- */
64
- comtoplu: Record<string, string>;
65
- /**
66
- * 事件监听器与插件对应关系
67
- */
68
- evttoplu: Record<string, Record<string, ((...args: any[]) => Promise<void>)[]>>;
69
- /**
70
- * 中间件与插件对应关系
71
- */
72
- mdwtoplu: Record<string, string>;
73
- plftoplu: Record<string, string>;
74
- /**
75
- * 插件状态
76
- */
77
- pluginStatus: Record<string, PluginStatus>;
78
- /**
79
- * 插件监听器
80
- */
81
- private pluginWatchers;
82
- /**
83
- * 初始化核心
84
- * @param pluginLoader 插件加载器
75
+ * 清理指定插件注册的所有内容
85
76
  */
86
- constructor(pluginLoader: PluginLoader);
77
+ unregall(pluginName: string): void;
87
78
  /**
88
79
  * 加载配置文件
89
80
  * @param configPath 配置文件的路径
90
81
  */
91
82
  loadConfig(configPath: string): Promise<void>;
83
+ /**
84
+ * 启动应用
85
+ * @returns Promise<void>
86
+ */
87
+ runCore(): Promise<void>;
92
88
  /**
93
89
  * 监听配置文件变化,实现热重载
94
90
  * @param configPath 配置文件的路径
@@ -175,10 +171,6 @@ export declare class Core {
175
171
  * @returns Core 实例
176
172
  */
177
173
  use(name: string, middleware: Middleware): Core;
178
- /**
179
- * @deprecated 已更改为路由
180
- */
181
- command(name: string): Command;
182
174
  /**
183
175
  * 注册路由
184
176
  * @param path 路由路径
@@ -186,10 +178,23 @@ export declare class Core {
186
178
  */
187
179
  route(path: string): Route;
188
180
  /**
189
- * 执行命令
190
- * @deprecated
181
+ * 注册 Hook 钩子
182
+ * @param name Hook 点名称
183
+ * @param hookname 钩子名称
184
+ * @param callback 钩子函数
185
+ */
186
+ hook(name: string, hookname: string, callback: HookHandler): any;
187
+ /**
188
+ * 消除 Hook 钩子
189
+ */
190
+ unhook(name: string, hookname: string): any;
191
+ /**
192
+ * 执行 Hook 钩子
193
+ * @param name Hook 点名称
194
+ * @param args 参数
195
+ * @return Promise<any[]>
191
196
  */
192
- executeCommand(name: string, session: any, ...args: any[]): Promise<Session | null>;
197
+ hookExecute(name: string, ...args: any[]): Promise<any[]>;
193
198
  /**
194
199
  * 执行路由
195
200
  * @param pathname 需要匹配的URL
@@ -198,23 +203,6 @@ export declare class Core {
198
203
  * @returns 是否匹配成功
199
204
  */
200
205
  executeRoute(pathname: string, session: Session, queryParams: URLSearchParams): Promise<boolean>;
201
- /**
202
- * 注册平台
203
- * @param platform 平台实例
204
- * @returns 平台启动结果
205
- */
206
- registerPlatform(platform: Platform): any;
207
- /**
208
- * 清理指定插件注册的所有内容
209
- * @param pluginname 插件名称
210
- */
211
- unregall(pluginname: string): void;
212
- /**
213
- * 获取命令
214
- * @param name 命令名称
215
- * @returns Command 实例或 null
216
- */
217
- getCommand(name: string): Command | null;
218
206
  /**
219
207
  * 获取路由
220
208
  * @param path 匹配路径
package/dist/core.js CHANGED
@@ -35,8 +35,8 @@ var __importStar = (this && this.__importStar) || (function () {
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.Core = void 0;
37
37
  /**
38
- * @time: 2025/07/12 18:14
39
- * @author: FireGuo & Manus
38
+ * @time: 2025/08/14 09:48
39
+ * @author: FireGuo
40
40
  * WindyPear-Team All right reserved
41
41
  **/
42
42
  const yaml = __importStar(require("js-yaml"));
@@ -44,59 +44,54 @@ const fs = __importStar(require("fs"));
44
44
  const path = __importStar(require("path"));
45
45
  const config_1 = require("./config");
46
46
  const logger_1 = require("./logger");
47
- const command_1 = require("./command");
48
47
  const chokidar = __importStar(require("chokidar"));
49
48
  const route_1 = require("./route");
50
49
  const context_1 = require("./context");
50
+ const hook_1 = require("./hook");
51
+ const server_1 = require("./server");
51
52
  class Core {
52
53
  plugins = {};
53
54
  config = null;
54
- platforms = [];
55
55
  eventListeners = {};
56
56
  components = {};
57
- commands = {};
58
57
  routes = {};
59
58
  pluginLoader;
60
59
  logger = new logger_1.Logger('core');
61
60
  providedComponents = {};
61
+ globalMiddlewares = {};
62
+ pluginStatus = {};
63
+ hooks = {};
64
+ coreConfig;
65
+ server;
66
+ pluginWatchers = {};
62
67
  pluginModules = {};
63
68
  configPath = '';
64
- globalMiddlewares = {};
65
- /**
66
- * @deprecated 命令与插件对应关系
67
- */
68
- cmdtoplu = {};
69
- /**
70
- * 路由与插件对应关系
71
- */
72
- routetoplu = {};
73
69
  /**
74
- * 组件与插件对应关系
70
+ * 插件名 -> Context 映射
75
71
  */
76
- comtoplu = {};
77
- /**
78
- * 事件监听器与插件对应关系
79
- */
80
- evttoplu = {};
81
- /**
82
- * 中间件与插件对应关系
83
- */
84
- mdwtoplu = {};
85
- plftoplu = {};
86
- /**
87
- * 插件状态
88
- */
89
- pluginStatus = {};
72
+ pluginContexts = {};
73
+ constructor(pluginLoader, coreConfig) {
74
+ this.coreConfig = coreConfig;
75
+ this.pluginLoader = pluginLoader;
76
+ }
90
77
  /**
91
- * 插件监听器
78
+ * 获取或创建插件对应 Context
92
79
  */
93
- pluginWatchers = {};
80
+ getContext(pluginName) {
81
+ if (!this.pluginContexts[pluginName]) {
82
+ this.pluginContexts[pluginName] = new context_1.Context(this, pluginName);
83
+ }
84
+ return this.pluginContexts[pluginName];
85
+ }
94
86
  /**
95
- * 初始化核心
96
- * @param pluginLoader 插件加载器
87
+ * 清理指定插件注册的所有内容
97
88
  */
98
- constructor(pluginLoader) {
99
- this.pluginLoader = pluginLoader;
89
+ unregall(pluginName) {
90
+ const ctx = this.pluginContexts[pluginName];
91
+ if (ctx) {
92
+ ctx.dispose();
93
+ delete this.pluginContexts[pluginName];
94
+ }
100
95
  }
101
96
  /**
102
97
  * 加载配置文件
@@ -111,12 +106,28 @@ class Core {
111
106
  if (process.env.NODE_ENV === 'development') {
112
107
  this.watchConfig(configPath);
113
108
  }
109
+ this.coreConfig = this.config.core || {};
114
110
  }
115
111
  catch (e) {
116
112
  this.logger.error('Failed to load config:', e);
117
113
  throw e;
118
114
  }
119
115
  }
116
+ /**
117
+ * 启动应用
118
+ * @returns Promise<void>
119
+ */
120
+ async runCore() {
121
+ this.server = new server_1.Server(this, {
122
+ port: this.coreConfig.port || 14510,
123
+ host: this.coreConfig.host || '0.0.0.0',
124
+ enableCors: this.coreConfig.enableCors || false,
125
+ enableWs: this.coreConfig.enableWs || false,
126
+ staticDir: this.coreConfig.staticDir || 'public',
127
+ });
128
+ await this.server.start();
129
+ this.logger.info(`Yumeri server started at ${this.coreConfig.host}:${this.coreConfig.port}`);
130
+ }
120
131
  /**
121
132
  * 监听配置文件变化,实现热重载
122
133
  * @param configPath 配置文件的路径
@@ -255,7 +266,7 @@ class Core {
255
266
  this.plugins[pluginName] = pluginInstance;
256
267
  if (pluginInstance.apply) {
257
268
  this.pluginLoader.logger.info(`Apply plugin "${pluginName}"`);
258
- await pluginInstance.apply(new context_1.Context(this, pluginName), await this.getPluginConfig(pluginName));
269
+ await pluginInstance.apply(this.getContext(pluginName), await this.getPluginConfig(pluginName));
259
270
  }
260
271
  // 注册提供的组件
261
272
  if (pluginInstance.provide) {
@@ -365,9 +376,8 @@ class Core {
365
376
  this.logger.info(`Unloading plugin "${pluginName}"...`);
366
377
  try {
367
378
  const plugin = this.plugins[pluginName];
368
- if (plugin && plugin.disable) {
369
- await plugin.disable(new context_1.Context(this, pluginName));
370
- }
379
+ if (plugin && plugin.disable)
380
+ await plugin.disable(this.getContext(pluginName));
371
381
  await this.pluginLoader.unloadPlugin(pluginName);
372
382
  this.unregall(pluginName); // 清理该插件注册的所有内容
373
383
  delete this.plugins[pluginName];
@@ -465,7 +475,6 @@ class Core {
465
475
  unregisterComponent(name) {
466
476
  delete this.components[name];
467
477
  delete this.providedComponents[name];
468
- delete this.comtoplu[name];
469
478
  }
470
479
  /**
471
480
  * 注册事件监听器
@@ -505,14 +514,6 @@ class Core {
505
514
  this.globalMiddlewares[name] = middleware;
506
515
  return this;
507
516
  }
508
- /**
509
- * @deprecated 已更改为路由
510
- */
511
- command(name) {
512
- const command = new command_1.Command(this, name);
513
- this.commands[name] = command;
514
- return command;
515
- }
516
517
  /**
517
518
  * 注册路由
518
519
  * @param path 路由路径
@@ -524,29 +525,36 @@ class Core {
524
525
  return route;
525
526
  }
526
527
  /**
527
- * 执行命令
528
- * @deprecated
528
+ * 注册 Hook 钩子
529
+ * @param name Hook 点名称
530
+ * @param hookname 钩子名称
531
+ * @param callback 钩子函数
529
532
  */
530
- async executeCommand(name, session, ...args) {
531
- const command = this.commands[name];
532
- if (command) {
533
- const globalMiddlewareList = Object.values(this.globalMiddlewares || {});
534
- const commandMiddlewareList = command.middlewares || [];
535
- const middlewares = [...globalMiddlewareList, ...commandMiddlewareList];
536
- let index = 0;
537
- const runner = async () => {
538
- if (index < middlewares.length) {
539
- const middleware = middlewares[index++];
540
- await middleware(session, runner);
541
- }
542
- else {
543
- await command.executeHandler(session, ...args);
544
- }
545
- };
546
- await runner();
547
- return session;
533
+ hook(name, hookname, callback) {
534
+ if (!this.hooks[name]) {
535
+ this.hooks[name] = new hook_1.Hook(name);
536
+ }
537
+ this.hooks[name].add(hookname, callback);
538
+ }
539
+ /**
540
+ * 消除 Hook 钩子
541
+ */
542
+ unhook(name, hookname) {
543
+ if (this.hooks[name]) {
544
+ this.hooks[name].remove(hookname);
545
+ }
546
+ }
547
+ /**
548
+ * 执行 Hook 钩子
549
+ * @param name Hook 点名称
550
+ * @param args 参数
551
+ * @return Promise<any[]>
552
+ */
553
+ async hookExecute(name, ...args) {
554
+ if (this.hooks[name]) {
555
+ return await this.hooks[name].trigger(...args);
548
556
  }
549
- return null;
557
+ return [];
550
558
  }
551
559
  /**
552
560
  * 执行路由
@@ -560,18 +568,13 @@ class Core {
560
568
  const route = this.routes[routePath];
561
569
  const result = route.match(pathname);
562
570
  if (result) {
563
- const globalMiddlewareList = Object.values(this.globalMiddlewares || {});
564
- const routeMiddlewareList = route.middlewares || [];
565
- const middlewares = [...globalMiddlewareList, ...routeMiddlewareList];
571
+ const middlewares = [...Object.values(this.globalMiddlewares), ...(route.middlewares || [])];
566
572
  let index = 0;
567
573
  const runner = async () => {
568
- if (index < middlewares.length) {
569
- const middleware = middlewares[index++];
570
- await middleware(session, runner);
571
- }
572
- else {
574
+ if (index < middlewares.length)
575
+ await middlewares[index++](session, runner);
576
+ else
573
577
  await route.executeHandler(session, queryParams, result.pathParams);
574
- }
575
578
  };
576
579
  await runner();
577
580
  return true;
@@ -579,74 +582,6 @@ class Core {
579
582
  }
580
583
  return false;
581
584
  }
582
- /**
583
- * 注册平台
584
- * @param platform 平台实例
585
- * @returns 平台启动结果
586
- */
587
- registerPlatform(platform) {
588
- this.platforms.push(platform);
589
- return platform.startPlatform(this);
590
- }
591
- /**
592
- * 清理指定插件注册的所有内容
593
- * @param pluginname 插件名称
594
- */
595
- unregall(pluginname) {
596
- // 清理 commands
597
- Object.keys(this.cmdtoplu)
598
- .filter(cmd => this.cmdtoplu[cmd] === pluginname)
599
- .forEach(cmd => {
600
- delete this.cmdtoplu[cmd];
601
- delete this.commands[cmd];
602
- });
603
- // 清理 routes
604
- Object.keys(this.routetoplu)
605
- .filter(path => this.routetoplu[path] === pluginname)
606
- .forEach(path => {
607
- delete this.routetoplu[path];
608
- delete this.routes[path];
609
- });
610
- // 清理 components 和 providedComponents
611
- Object.keys(this.comtoplu)
612
- .filter(comp => this.comtoplu[comp] === pluginname)
613
- .forEach(comp => {
614
- delete this.comtoplu[comp];
615
- delete this.components[comp];
616
- delete this.providedComponents[comp];
617
- });
618
- // 清理由 provide 声明的组件提供关系
619
- Object.keys(this.providedComponents)
620
- .filter(prov => this.providedComponents[prov] === pluginname)
621
- .forEach(prov => {
622
- delete this.providedComponents[prov];
623
- });
624
- // 清理 event listeners
625
- for (const evt in this.evttoplu) {
626
- if (this.evttoplu[evt][pluginname]) {
627
- const pluginListeners = this.evttoplu[evt][pluginname] || [];
628
- if (this.eventListeners[evt]) {
629
- this.eventListeners[evt] = this.eventListeners[evt].filter(l => !pluginListeners.includes(l));
630
- }
631
- delete this.evttoplu[evt][pluginname];
632
- }
633
- }
634
- // 清理 middlewares
635
- Object.keys(this.mdwtoplu)
636
- .filter(mdw => this.mdwtoplu[mdw] === pluginname)
637
- .forEach(mdw => {
638
- delete this.mdwtoplu[mdw];
639
- delete this.globalMiddlewares[mdw];
640
- });
641
- }
642
- /**
643
- * 获取命令
644
- * @param name 命令名称
645
- * @returns Command 实例或 null
646
- */
647
- getCommand(name) {
648
- return this.commands[name] || null;
649
- }
650
585
  /**
651
586
  * 获取路由
652
587
  * @param path 匹配路径
package/dist/hook.d.ts ADDED
@@ -0,0 +1,39 @@
1
+ /**
2
+ * @time: 2025/08/14 18:33
3
+ * @author: FireGuo
4
+ * WindyPear-Team All right reserved
5
+ **/
6
+ /**
7
+ * Hook 处理器
8
+ */
9
+ export type HookHandler = (...args: any[]) => Promise<any>;
10
+ /**
11
+ * Hook 类
12
+ */
13
+ export declare class Hook {
14
+ name: string;
15
+ handlers: Record<string, HookHandler>;
16
+ /**
17
+ * 创建 Hook 实例
18
+ * @param name Hook 名称
19
+ */
20
+ constructor(name: string);
21
+ /**
22
+ * 添加 Hook 函数
23
+ * @param name Hook 函数名称
24
+ * @param handler Hook 函数
25
+ */
26
+ add(name: string, handler: HookHandler): void;
27
+ /**
28
+ * 删除 Hook 函数
29
+ * @param name Hook 函数名称
30
+ */
31
+ remove(name: string): void;
32
+ /**
33
+ * 触发 Hook 函数
34
+ * @param session 会话
35
+ * @param args 参数
36
+ * @returns 执行结果
37
+ */
38
+ trigger(...args: any[]): Promise<any[]>;
39
+ }
package/dist/hook.js ADDED
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ /**
3
+ * @time: 2025/08/14 18:33
4
+ * @author: FireGuo
5
+ * WindyPear-Team All right reserved
6
+ **/
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.Hook = void 0;
9
+ /**
10
+ * Hook 类
11
+ */
12
+ class Hook {
13
+ name;
14
+ handlers = {};
15
+ /**
16
+ * 创建 Hook 实例
17
+ * @param name Hook 名称
18
+ */
19
+ constructor(name) {
20
+ this.name = name;
21
+ }
22
+ /**
23
+ * 添加 Hook 函数
24
+ * @param name Hook 函数名称
25
+ * @param handler Hook 函数
26
+ */
27
+ add(name, handler) {
28
+ this.handlers[name] = handler;
29
+ }
30
+ /**
31
+ * 删除 Hook 函数
32
+ * @param name Hook 函数名称
33
+ */
34
+ remove(name) {
35
+ delete this.handlers[name];
36
+ }
37
+ /**
38
+ * 触发 Hook 函数
39
+ * @param session 会话
40
+ * @param args 参数
41
+ * @returns 执行结果
42
+ */
43
+ async trigger(...args) {
44
+ let result;
45
+ for (const handler of Object.values(this.handlers)) {
46
+ result.push(handler(...args));
47
+ }
48
+ return result;
49
+ }
50
+ }
51
+ exports.Hook = Hook;
package/dist/index.d.ts CHANGED
@@ -1,13 +1,12 @@
1
1
  /**
2
- * @time: 2025/03/24 12:26
2
+ * @time: 2025/08/14 09:48
3
3
  * @author: FireGuo
4
4
  * WindyPear-Team All right reserved
5
5
  **/
6
6
  export * from './core';
7
7
  export * from './session';
8
- export * from './command';
9
8
  export * from './route';
10
9
  export * from './config';
11
10
  export * from './logger';
12
- export * from './platform';
13
11
  export * from './context';
12
+ export * from './hook';
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /**
3
- * @time: 2025/03/24 12:26
3
+ * @time: 2025/08/14 09:48
4
4
  * @author: FireGuo
5
5
  * WindyPear-Team All right reserved
6
6
  **/
@@ -21,9 +21,8 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
21
21
  Object.defineProperty(exports, "__esModule", { value: true });
22
22
  __exportStar(require("./core"), exports);
23
23
  __exportStar(require("./session"), exports);
24
- __exportStar(require("./command"), exports);
25
24
  __exportStar(require("./route"), exports);
26
25
  __exportStar(require("./config"), exports);
27
26
  __exportStar(require("./logger"), exports);
28
- __exportStar(require("./platform"), exports);
29
27
  __exportStar(require("./context"), exports);
28
+ __exportStar(require("./hook"), exports);
package/dist/logger.d.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  /**
2
- * @time: 2025/03/25 18:01
2
+ * @time: 2025/08/14 09:48
3
3
  * @author: FireGuo
4
4
  * WindyPear-Team All right reserved
5
- */
5
+ **/
6
6
  import { Core } from './core';
7
7
  export declare class Logger {
8
8
  private title;
package/dist/logger.js CHANGED
@@ -1,15 +1,15 @@
1
1
  "use strict";
2
2
  /**
3
- * @time: 2025/03/25 18:01
3
+ * @time: 2025/08/14 09:48
4
4
  * @author: FireGuo
5
5
  * WindyPear-Team All right reserved
6
- */
6
+ **/
7
7
  var __importDefault = (this && this.__importDefault) || function (mod) {
8
8
  return (mod && mod.__esModule) ? mod : { "default": mod };
9
9
  };
10
10
  Object.defineProperty(exports, "__esModule", { value: true });
11
11
  exports.Logger = void 0;
12
- const picocolors_1 = __importDefault(require("picocolors")); // 轻量颜色库
12
+ const picocolors_1 = __importDefault(require("picocolors"));
13
13
  class Logger {
14
14
  title;
15
15
  titleColor;
@@ -1,2 +1,7 @@
1
+ /**
2
+ * @time: 2025/08/14 09:48
3
+ * @author: FireGuo
4
+ * WindyPear-Team All right reserved
5
+ **/
1
6
  import { Session } from './session';
2
7
  export type Middleware = (session: Session, next: () => Promise<void>) => Promise<void>;
@@ -1,3 +1,8 @@
1
+ /**
2
+ * @time: 2025/08/14 09:48
3
+ * @author: FireGuo
4
+ * WindyPear-Team All right reserved
5
+ **/
1
6
  import { Session } from './session';
2
7
  import { Core } from './core';
3
8
  import { ConfigSchema } from './config';
package/dist/platform.js CHANGED
@@ -1,6 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Platform = void 0;
4
+ /**
5
+ * @time: 2025/08/14 09:48
6
+ * @author: FireGuo
7
+ * WindyPear-Team All right reserved
8
+ **/
4
9
  const session_1 = require("./session");
5
10
  /**
6
11
  * Platform 基类
package/dist/route.d.ts CHANGED
@@ -1,3 +1,8 @@
1
+ /**
2
+ * @time: 2025/08/14 09:48
3
+ * @author: FireGuo
4
+ * WindyPear-Team All right reserved
5
+ **/
1
6
  import { Session } from './session';
2
7
  import { Middleware } from './middleware';
3
8
  export type RouteHandler = (session: Session, queryParams: URLSearchParams, ...pathParams: string[]) => Promise<void> | void;
@@ -0,0 +1,26 @@
1
+ import { Core } from './core';
2
+ export interface ServerConfig {
3
+ port: number;
4
+ host: string;
5
+ enableCors: boolean;
6
+ staticDir: string;
7
+ enableWs: boolean;
8
+ }
9
+ export declare class Server {
10
+ private core;
11
+ private port;
12
+ private host;
13
+ private enableCors;
14
+ private staticDir;
15
+ private enableWs;
16
+ private httpServer;
17
+ private wsServer;
18
+ constructor(core: Core, config?: Partial<ServerConfig>);
19
+ private createSession;
20
+ private parseCookies;
21
+ private getClientIP;
22
+ private parseRequestBody;
23
+ private serveStaticFile;
24
+ start(): Promise<void>;
25
+ stop(): void;
26
+ }
package/dist/server.js ADDED
@@ -0,0 +1,231 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.Server = void 0;
40
+ const logger_1 = require("./logger");
41
+ const session_1 = require("./session");
42
+ const http_1 = __importDefault(require("http"));
43
+ const fs = __importStar(require("fs"));
44
+ const path = __importStar(require("path"));
45
+ const url_1 = require("url");
46
+ const ws_1 = __importDefault(require("ws"));
47
+ const formidable = __importStar(require("formidable"));
48
+ const mime = __importStar(require("mime-types"));
49
+ const logger = new logger_1.Logger('server');
50
+ class Server {
51
+ core;
52
+ port;
53
+ host;
54
+ enableCors;
55
+ staticDir;
56
+ enableWs;
57
+ httpServer = null;
58
+ wsServer = null;
59
+ constructor(core, config = {}) {
60
+ this.core = core;
61
+ this.port = config.port ?? 14510;
62
+ this.host = config.host ?? '0.0.0.0';
63
+ this.enableCors = config.enableCors ?? true;
64
+ this.staticDir = config.staticDir ?? 'static';
65
+ this.enableWs = config.enableWs ?? true;
66
+ }
67
+ createSession(ip, cookies, res, req, extra = {}) {
68
+ const session = new session_1.Session(ip, cookies, this, req, res);
69
+ Object.assign(session.properties, extra);
70
+ session.protocol = extra.protocol ?? 'http';
71
+ return session;
72
+ }
73
+ parseCookies(req) {
74
+ const cookieHeader = req.headers.cookie;
75
+ if (!cookieHeader)
76
+ return {};
77
+ const cookies = {};
78
+ cookieHeader.split(';').forEach(c => {
79
+ const [k, ...v] = c.split('=');
80
+ cookies[k.trim()] = v.join('=').trim();
81
+ });
82
+ return cookies;
83
+ }
84
+ getClientIP(req) {
85
+ const xff = req.headers['x-forwarded-for'];
86
+ return xff ? xff.split(',')[0].trim() : req.socket.remoteAddress || '127.0.0.1';
87
+ }
88
+ async parseRequestBody(req) {
89
+ return new Promise((resolve, reject) => {
90
+ const contentType = (req.headers['content-type'] || '').toLowerCase();
91
+ if (contentType.includes('application/json') || contentType.includes('application/x-www-form-urlencoded')) {
92
+ let body = '';
93
+ req.on('data', chunk => body += chunk.toString());
94
+ req.on('end', () => {
95
+ try {
96
+ if (contentType.includes('application/json'))
97
+ resolve(JSON.parse(body));
98
+ else {
99
+ const params = new URLSearchParams(body);
100
+ const parsed = {};
101
+ params.forEach((v, k) => parsed[k] = v);
102
+ resolve(parsed);
103
+ }
104
+ }
105
+ catch (e) {
106
+ reject(e);
107
+ }
108
+ });
109
+ }
110
+ else if (contentType.includes('multipart/form-data')) {
111
+ const form = formidable.formidable({});
112
+ form.parse(req, (err, fields) => {
113
+ if (err)
114
+ return reject(err);
115
+ const parsed = {};
116
+ Object.keys(fields).forEach(k => {
117
+ const val = fields[k];
118
+ parsed[k] = Array.isArray(val) && val.length === 1 ? val[0] : val;
119
+ });
120
+ resolve(parsed);
121
+ });
122
+ }
123
+ else
124
+ resolve({});
125
+ req.on('error', reject);
126
+ });
127
+ }
128
+ serveStaticFile(pathname, res) {
129
+ const fullPath = path.join(process.cwd(), this.staticDir, pathname);
130
+ fs.readFile(fullPath, (err, data) => {
131
+ if (err) {
132
+ res.writeHead(404, { 'Content-Type': 'text/html' });
133
+ res.end(`<html><body><h1>404 Not Found</h1></body></html>`);
134
+ }
135
+ else {
136
+ res.writeHead(200, { 'Content-Type': mime.lookup(fullPath) || 'text/plain' });
137
+ res.end(data);
138
+ }
139
+ });
140
+ }
141
+ async start() {
142
+ this.httpServer = http_1.default.createServer(async (req, res) => {
143
+ if (req.method === 'OPTIONS' && this.enableCors) {
144
+ res.writeHead(204, {
145
+ 'Access-Control-Allow-Origin': '*',
146
+ 'Access-Control-Allow-Methods': 'GET,POST,PUT,DELETE,PATCH,HEAD,OPTIONS',
147
+ 'Access-Control-Allow-Headers': 'Content-Type',
148
+ });
149
+ res.end();
150
+ return;
151
+ }
152
+ const url = new url_1.URL(req.url || '/', `http://${req.headers.host}`);
153
+ const pathname = url.pathname;
154
+ const queryParams = url.searchParams;
155
+ const ip = this.getClientIP(req);
156
+ const cookies = this.parseCookies(req);
157
+ const session = this.createSession(ip, cookies, res, req, { protocol: 'http', header: req.headers });
158
+ if (req.method?.toLowerCase() === 'post') {
159
+ try {
160
+ const body = await this.parseRequestBody(req);
161
+ Object.entries(body).forEach(([k, v]) => {
162
+ if (typeof v === 'string')
163
+ queryParams.set(k, v);
164
+ else if (Array.isArray(v))
165
+ v.forEach(val => queryParams.append(k, val));
166
+ });
167
+ }
168
+ catch (err) {
169
+ res.writeHead(400, { 'Content-Type': 'text/plain' });
170
+ res.end('Invalid request body');
171
+ logger.error('Request body parse error:', err);
172
+ return;
173
+ }
174
+ }
175
+ const route = this.core.getRoute(pathname);
176
+ if (route && route.allowedMethods.includes(req.method ?? 'GET')) {
177
+ const matched = await this.core.executeRoute(pathname, session, queryParams);
178
+ if (!matched) {
179
+ this.serveStaticFile(pathname, res);
180
+ }
181
+ else {
182
+ let head = session.head;
183
+ head['Set-Cookie'] = Object.entries(session.newCookie).map(([k, v]) => `${k}=${v}`);
184
+ if (this.enableCors) {
185
+ head['Access-Control-Allow-Origin'] = '*';
186
+ }
187
+ res.writeHead(session.status ?? 200, head);
188
+ res.end(session.body);
189
+ }
190
+ }
191
+ else {
192
+ this.serveStaticFile(pathname, res);
193
+ }
194
+ });
195
+ if (this.enableWs) {
196
+ this.wsServer = new ws_1.default.Server({ server: this.httpServer });
197
+ this.wsServer.on('connection', (ws, req) => {
198
+ const url = new url_1.URL(req.url || '/', `http://${req.headers.host}`);
199
+ const pathname = url.pathname;
200
+ const queryParams = url.searchParams;
201
+ const ip = this.getClientIP(req);
202
+ const cookies = this.parseCookies(req);
203
+ const session = this.createSession(ip, cookies, undefined, req, { ws, protocol: 'ws' });
204
+ ws.on('message', async (msg) => {
205
+ try {
206
+ const data = JSON.parse(msg.toString());
207
+ Object.entries(data).forEach(([k, v]) => queryParams.set(k, v));
208
+ }
209
+ catch {
210
+ queryParams.set('message', msg.toString());
211
+ }
212
+ await this.core.executeRoute(pathname, session, queryParams);
213
+ });
214
+ this.core.executeRoute(pathname, session, queryParams).catch(err => {
215
+ logger.error(`WS initial route error for ${pathname}:`, err);
216
+ ws.close(1011, 'Internal error');
217
+ });
218
+ });
219
+ }
220
+ this.httpServer.listen(this.port, this.host, () => {
221
+ logger.info(`Server listening on ${this.host}:${this.port}`);
222
+ });
223
+ }
224
+ stop() {
225
+ if (this.wsServer)
226
+ this.wsServer.close();
227
+ if (this.httpServer)
228
+ this.httpServer.close(() => logger.info('Server stopped'));
229
+ }
230
+ }
231
+ exports.Server = Server;
package/dist/session.d.ts CHANGED
@@ -3,7 +3,8 @@
3
3
  * @author: FireGuo
4
4
  * WindyPear-Team All right reserved
5
5
  **/
6
- import { Platform } from './platform';
6
+ import { Server } from './server';
7
+ import { IncomingMessage, ServerResponse } from 'http';
7
8
  export declare class Session {
8
9
  ip: string;
9
10
  cookie: Record<string, string>;
@@ -14,9 +15,12 @@ export declare class Session {
14
15
  head: Record<string, any>;
15
16
  status: number;
16
17
  body: any;
17
- platform: Platform;
18
18
  properties?: Record<string, any>;
19
- constructor(ip: string, cookie: Record<string, string>, platform: Platform, query?: Record<string, string>);
19
+ res: any;
20
+ req: any;
21
+ server: Server;
22
+ protocol: string;
23
+ constructor(ip: string, cookie: Record<string, string>, server: Server, req?: IncomingMessage, res?: ServerResponse, query?: Record<string, string>);
20
24
  private generateId;
21
25
  private md5;
22
26
  setData(key: string, value: any): void;
package/dist/session.js CHANGED
@@ -20,18 +20,23 @@ class Session {
20
20
  head = {};
21
21
  status = 200;
22
22
  body;
23
- platform;
24
23
  properties = {};
24
+ res = null;
25
+ req = null;
26
+ server;
27
+ protocol = 'http';
25
28
  /*
26
29
  * @ip: string,用户IP
27
30
  * @cookie: string,会话cookie
28
31
  * @query: string,请求字符串
29
32
  */
30
- constructor(ip, cookie, platform, query) {
33
+ constructor(ip, cookie, server, req, res, query) {
31
34
  this.ip = ip;
32
35
  this.cookie = cookie;
33
36
  this.query = query;
34
- this.platform = platform;
37
+ this.server = server;
38
+ this.req = req;
39
+ this.res = res;
35
40
  this.head['Content-Type'] = 'text/plain';
36
41
  if (cookie.sessionid) {
37
42
  this.sessionid = cookie.sessionid;
@@ -102,10 +107,10 @@ class Session {
102
107
  }
103
108
  }
104
109
  send(data) {
105
- return this.platform.sendMessage(this, data);
110
+ return this.res.send(data);
106
111
  }
107
112
  endsession(message) {
108
- return this.platform.terminationSession(this, message);
113
+ return this.res.end(message);
109
114
  }
110
115
  }
111
116
  exports.Session = Session;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yumerijs/core",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "description": "Core module for yumeri",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -33,7 +33,6 @@
33
33
  "dependencies": {
34
34
  "@yumerijs/loader": "^1.2.0",
35
35
  "chokidar": "^4.0.3",
36
- "js-sha256": "^0.11.0",
37
36
  "js-yaml": "^4.1.0",
38
37
  "picocolors": "^1.1.1"
39
38
  },