@zhin.js/core 1.0.0 → 1.0.1
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/CHANGELOG.md +9 -0
- package/LICENSE +21 -0
- package/README.md +295 -74
- package/lib/adapter.d.ts +39 -0
- package/lib/adapter.d.ts.map +1 -0
- package/{dist → lib}/adapter.js +20 -2
- package/lib/adapter.js.map +1 -0
- package/lib/app.d.ts +115 -0
- package/lib/app.d.ts.map +1 -0
- package/{dist → lib}/app.js +148 -78
- package/lib/app.js.map +1 -0
- package/lib/bot.d.ts +31 -0
- package/lib/bot.d.ts.map +1 -0
- package/lib/command.d.ts +32 -0
- package/lib/command.d.ts.map +1 -0
- package/lib/command.js +46 -0
- package/lib/command.js.map +1 -0
- package/lib/component.d.ts +107 -0
- package/lib/component.d.ts.map +1 -0
- package/lib/component.js +273 -0
- package/lib/component.js.map +1 -0
- package/{dist → lib}/config.d.ts.map +1 -1
- package/{dist → lib}/config.js +6 -9
- package/lib/config.js.map +1 -0
- package/lib/cron.d.ts +81 -0
- package/lib/cron.d.ts.map +1 -0
- package/lib/cron.js +159 -0
- package/lib/cron.js.map +1 -0
- package/lib/errors.d.ts +165 -0
- package/lib/errors.d.ts.map +1 -0
- package/lib/errors.js +306 -0
- package/lib/errors.js.map +1 -0
- package/lib/index.d.ts +15 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +17 -0
- package/lib/index.js.map +1 -0
- package/lib/message.d.ts +44 -0
- package/lib/message.d.ts.map +1 -0
- package/lib/message.js +11 -0
- package/lib/message.js.map +1 -0
- package/lib/plugin.d.ts +50 -0
- package/lib/plugin.d.ts.map +1 -0
- package/lib/plugin.js +170 -0
- package/lib/plugin.js.map +1 -0
- package/lib/prompt.d.ts +116 -0
- package/lib/prompt.d.ts.map +1 -0
- package/lib/prompt.js +240 -0
- package/lib/prompt.js.map +1 -0
- package/lib/schema.d.ts +83 -0
- package/lib/schema.d.ts.map +1 -0
- package/lib/schema.js +245 -0
- package/lib/schema.js.map +1 -0
- package/{dist → lib}/types-generator.d.ts.map +1 -1
- package/{dist → lib}/types-generator.js +6 -3
- package/lib/types-generator.js.map +1 -0
- package/lib/types.d.ts +119 -0
- package/lib/types.d.ts.map +1 -0
- package/lib/utils.d.ts +52 -0
- package/lib/utils.d.ts.map +1 -0
- package/lib/utils.js +338 -0
- package/lib/utils.js.map +1 -0
- package/package.json +15 -9
- package/src/adapter.ts +25 -9
- package/src/app.ts +363 -258
- package/src/bot.ts +29 -8
- package/src/command.ts +50 -0
- package/src/component.ts +318 -0
- package/src/config.ts +9 -12
- package/src/cron.ts +176 -0
- package/src/errors.ts +365 -0
- package/src/index.ts +16 -13
- package/src/message.ts +44 -0
- package/src/plugin.ts +148 -66
- package/src/prompt.ts +290 -0
- package/src/schema.ts +273 -0
- package/src/types-generator.ts +7 -3
- package/src/types.ts +77 -30
- package/src/utils.ts +312 -0
- package/tests/adapter.test.ts +36 -22
- package/tests/app.test.ts +30 -0
- package/tests/command.test.ts +545 -0
- package/tests/component.test.ts +656 -0
- package/tests/config.test.ts +1 -1
- package/tests/errors.test.ts +311 -0
- package/tests/message.test.ts +402 -0
- package/tests/plugin.test.ts +275 -143
- package/tests/utils.test.ts +80 -0
- package/tsconfig.json +3 -4
- package/dist/adapter.d.ts +0 -22
- package/dist/adapter.d.ts.map +0 -1
- package/dist/adapter.js.map +0 -1
- package/dist/app.d.ts +0 -69
- package/dist/app.d.ts.map +0 -1
- package/dist/app.js.map +0 -1
- package/dist/bot.d.ts +0 -9
- package/dist/bot.d.ts.map +0 -1
- package/dist/config.js.map +0 -1
- package/dist/index.d.ts +0 -9
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -12
- package/dist/index.js.map +0 -1
- package/dist/logger.d.ts +0 -3
- package/dist/logger.d.ts.map +0 -1
- package/dist/logger.js +0 -3
- package/dist/logger.js.map +0 -1
- package/dist/plugin.d.ts +0 -41
- package/dist/plugin.d.ts.map +0 -1
- package/dist/plugin.js +0 -95
- package/dist/plugin.js.map +0 -1
- package/dist/types-generator.js.map +0 -1
- package/dist/types.d.ts +0 -69
- package/dist/types.d.ts.map +0 -1
- package/src/logger.ts +0 -3
- package/tests/logger.test.ts +0 -170
- package/tsconfig.tsbuildinfo +0 -1
- /package/{dist → lib}/bot.js +0 -0
- /package/{dist → lib}/bot.js.map +0 -0
- /package/{dist → lib}/config.d.ts +0 -0
- /package/{dist → lib}/types-generator.d.ts +0 -0
- /package/{dist → lib}/types.js +0 -0
- /package/{dist → lib}/types.js.map +0 -0
package/src/app.ts
CHANGED
|
@@ -1,170 +1,248 @@
|
|
|
1
|
-
import path from
|
|
2
|
-
import
|
|
3
|
-
import {SideEffect, GlobalContext} from '@zhin.js/types'
|
|
4
|
-
import { HMR, Context, Logger, ConsoleLogger,getCallerFile, getCallerFiles } from '@zhin.js/hmr';
|
|
1
|
+
import path from "path";
|
|
2
|
+
import { SideEffect, GlobalContext, Models } from "@zhin.js/types";
|
|
5
3
|
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
import {
|
|
13
|
-
|
|
14
|
-
|
|
4
|
+
HMR,
|
|
5
|
+
Context,
|
|
6
|
+
Logger,
|
|
7
|
+
getCallerFile,
|
|
8
|
+
getCallerFiles,
|
|
9
|
+
} from "@zhin.js/hmr";
|
|
10
|
+
import {
|
|
11
|
+
AdapterMessage,
|
|
12
|
+
AppConfig,
|
|
13
|
+
BeforeSendHandler,
|
|
14
|
+
RegisteredAdapter,
|
|
15
|
+
SendOptions,
|
|
16
|
+
} from "./types.js";
|
|
17
|
+
import { Message } from "./message.js";
|
|
18
|
+
import { fileURLToPath } from "url";
|
|
19
|
+
import { generateEnvTypes } from "./types-generator.js";
|
|
20
|
+
import logger, { setName } from "@zhin.js/logger";
|
|
21
|
+
import { sleep } from "./utils.js";
|
|
22
|
+
|
|
23
|
+
// 创建静态logger用于配置加载等静态操作
|
|
24
|
+
setName("Zhin");
|
|
25
|
+
import { MessageMiddleware, Plugin } from "./plugin.js";
|
|
26
|
+
import { Adapter } from "./adapter";
|
|
27
|
+
import { MessageCommand } from "./command";
|
|
28
|
+
import { Component } from "./component";
|
|
29
|
+
import { RelatedDatabase,DocumentDatabase,KeyValueDatabase,Schema,Registry} from "@zhin.js/database";
|
|
15
30
|
|
|
16
31
|
// ============================================================================
|
|
17
|
-
// App
|
|
32
|
+
// App 类(Zhin.js 应用主入口,负责插件热重载、配置管理、消息分发等)
|
|
18
33
|
// ============================================================================
|
|
19
34
|
/**
|
|
20
|
-
* App
|
|
35
|
+
* App类:Zhin.js 应用主入口,负责插件热重载、配置管理、消息分发等。
|
|
36
|
+
* 继承自 HMR,支持插件生命周期、适配器管理、数据库集成等。
|
|
21
37
|
*/
|
|
22
38
|
export class App extends HMR<Plugin> {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// 调用父类构造函数
|
|
46
|
-
super('Zhin',{
|
|
47
|
-
logger: new ConsoleLogger('[Zhin]'),
|
|
48
|
-
dirs: finalConfig.plugin_dirs || [],
|
|
49
|
-
extensions: new Set(['.js', '.ts']),
|
|
50
|
-
debug: finalConfig.debug
|
|
39
|
+
static currentPlugin: Plugin;
|
|
40
|
+
private config: AppConfig;
|
|
41
|
+
adapters: string[] = [];
|
|
42
|
+
database?: RelatedDatabase<any,Models>|DocumentDatabase<any,Models>|KeyValueDatabase<any,Models>;
|
|
43
|
+
/**
|
|
44
|
+
* 构造函数:初始化应用,加载配置,注册全局异常处理
|
|
45
|
+
* @param config 可选的应用配置,若为空则自动查找配置文件
|
|
46
|
+
*/
|
|
47
|
+
constructor(config?: Partial<AppConfig>) {
|
|
48
|
+
// 如果没有传入配置或配置为空对象,尝试自动加载配置文件
|
|
49
|
+
let finalConfig: AppConfig;
|
|
50
|
+
if (!config || Object.keys(config).length === 0) {
|
|
51
|
+
try {
|
|
52
|
+
// 异步加载配置,这里需要改为同步初始化
|
|
53
|
+
logger.info("🔍 正在查找配置文件...");
|
|
54
|
+
finalConfig = App.loadConfigSync();
|
|
55
|
+
logger.info("✅ 配置文件加载成功");
|
|
56
|
+
} catch (error) {
|
|
57
|
+
logger.warn("⚠️ 配置文件加载失败,使用默认配置", {
|
|
58
|
+
error: error instanceof Error ? error.message : String(error),
|
|
51
59
|
});
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
plugin_dirs: ['./plugins'],
|
|
58
|
-
plugins: [],
|
|
59
|
-
bots: [],
|
|
60
|
-
debug: false,
|
|
61
|
-
};
|
|
62
|
-
async sendMessage(options:SendOptions){
|
|
63
|
-
const adapter=this.getContext<Adapter>(options.context)
|
|
64
|
-
if(!adapter) throw new Error(`can't find adapter for name ${options.context}`)
|
|
65
|
-
const bot=adapter.bots.get(options.bot)
|
|
66
|
-
if(!bot) throw new Error(`can't find bot ${options.bot} for adapter ${options.bot}`)
|
|
67
|
-
return bot.sendMessage(options)
|
|
68
|
-
}
|
|
69
|
-
/** 同步加载配置文件 */
|
|
70
|
-
static loadConfigSync(): AppConfig {
|
|
71
|
-
// 由于loadConfig是异步的,我们需要创建一个同步版本
|
|
72
|
-
// 或者在这里简化处理,让用户使用异步创建方法
|
|
73
|
-
throw new Error('同步加载配置暂不支持,请使用 App.createAsync() 方法');
|
|
60
|
+
finalConfig = Object.assign({}, App.defaultConfig);
|
|
61
|
+
}
|
|
62
|
+
} else {
|
|
63
|
+
// 合并默认配置和传入的配置
|
|
64
|
+
finalConfig = Object.assign({}, App.defaultConfig, config);
|
|
74
65
|
}
|
|
75
66
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
67
|
+
// 调用父类构造函数
|
|
68
|
+
super("Zhin", {
|
|
69
|
+
logger,
|
|
70
|
+
dirs: finalConfig.plugin_dirs || [],
|
|
71
|
+
extensions: new Set([".js", ".ts"]),
|
|
72
|
+
debug: finalConfig.debug,
|
|
73
|
+
});
|
|
74
|
+
this.on("message.send", this.sendMessage.bind(this));
|
|
75
|
+
process.on("uncaughtException", (e) => {
|
|
76
|
+
this.logger.error(e);
|
|
77
|
+
});
|
|
78
|
+
process.on("unhandledRejection", (e) => {
|
|
79
|
+
this.logger.error(e);
|
|
80
|
+
});
|
|
81
|
+
this.config = finalConfig;
|
|
82
|
+
}
|
|
83
|
+
/** 默认配置 */
|
|
84
|
+
/**
|
|
85
|
+
* 默认配置
|
|
86
|
+
* - plugin_dirs: 插件目录
|
|
87
|
+
* - plugins: 启用插件
|
|
88
|
+
* - bots: 机器人配置
|
|
89
|
+
* - debug: 是否调试模式
|
|
90
|
+
*/
|
|
91
|
+
static defaultConfig: AppConfig = {
|
|
92
|
+
plugin_dirs: ["./plugins"],
|
|
93
|
+
plugins: [],
|
|
94
|
+
bots: [],
|
|
95
|
+
debug: false,
|
|
96
|
+
};
|
|
97
|
+
/**
|
|
98
|
+
* 发送消息到指定适配器和机器人
|
|
99
|
+
* @param options 消息发送参数(包含 context、bot、内容等)
|
|
100
|
+
* @throws 找不到适配器或机器人时抛出异常
|
|
101
|
+
*/
|
|
102
|
+
async sendMessage(options: SendOptions) {
|
|
103
|
+
const adapter = this.getContext<Adapter>(options.context);
|
|
104
|
+
if (!adapter)
|
|
105
|
+
throw new Error(`can't find adapter for name ${options.context}`);
|
|
106
|
+
const bot = adapter.bots.get(options.bot);
|
|
107
|
+
if (!bot)
|
|
108
|
+
throw new Error(
|
|
109
|
+
`can't find bot ${options.bot} for adapter ${options.context}`
|
|
110
|
+
);
|
|
111
|
+
return bot.$sendMessage(options);
|
|
112
|
+
}
|
|
113
|
+
/** 同步加载配置文件 */
|
|
114
|
+
/**
|
|
115
|
+
* 同步加载配置文件(暂不支持,建议使用异步创建)
|
|
116
|
+
* @throws 始终抛出异常,提示使用异步方法
|
|
117
|
+
*/
|
|
118
|
+
static loadConfigSync(): AppConfig {
|
|
119
|
+
// 由于loadConfig是异步的,我们需要创建一个同步版本
|
|
120
|
+
// 或者在这里简化处理,让用户使用异步创建方法
|
|
121
|
+
throw new Error("同步加载配置暂不支持,请使用 App.createAsync() 方法");
|
|
122
|
+
}
|
|
80
123
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
124
|
+
/** 创建插件依赖 */
|
|
125
|
+
/**
|
|
126
|
+
* 创建插件依赖
|
|
127
|
+
* @param name 插件名
|
|
128
|
+
* @param filePath 插件文件路径
|
|
129
|
+
*/
|
|
130
|
+
createDependency(name: string, filePath: string): Plugin {
|
|
131
|
+
return new Plugin(this, name, filePath);
|
|
132
|
+
}
|
|
85
133
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
const currentDirs = this.getWatchDirs();
|
|
94
|
-
const newDirs = config.plugin_dirs;
|
|
95
|
-
|
|
96
|
-
// 移除不再需要的目录
|
|
97
|
-
for (const dir of currentDirs) {
|
|
98
|
-
if (!newDirs.includes(dir)) {
|
|
99
|
-
this.removeWatchDir(dir);
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// 添加新的目录
|
|
104
|
-
for (const dir of newDirs) {
|
|
105
|
-
if (!currentDirs.includes(dir)) {
|
|
106
|
-
this.addWatchDir(dir);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
this.logger.info('App configuration updated', this.config);
|
|
112
|
-
}
|
|
134
|
+
/** 获取App配置 */
|
|
135
|
+
/**
|
|
136
|
+
* 获取App配置(只读)
|
|
137
|
+
*/
|
|
138
|
+
getConfig(): Readonly<AppConfig> {
|
|
139
|
+
return { ...this.config };
|
|
140
|
+
}
|
|
113
141
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
142
|
+
/** 更新App配置 */
|
|
143
|
+
/**
|
|
144
|
+
* 更新App配置
|
|
145
|
+
* @param config 部分配置项,将与现有配置合并
|
|
146
|
+
*/
|
|
147
|
+
updateConfig(config: Partial<AppConfig>): void {
|
|
148
|
+
this.config = { ...this.config, ...config };
|
|
149
|
+
|
|
150
|
+
// 更新HMR配置
|
|
151
|
+
if (config.plugin_dirs) {
|
|
152
|
+
// 动态更新监听目录
|
|
153
|
+
const currentDirs = this.getWatchDirs();
|
|
154
|
+
const newDirs = config.plugin_dirs;
|
|
118
155
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
for (const pluginName of this.config.plugins || []) {
|
|
124
|
-
this.use(pluginName);
|
|
156
|
+
// 移除不再需要的目录
|
|
157
|
+
for (const dir of currentDirs) {
|
|
158
|
+
if (!newDirs.includes(dir)) {
|
|
159
|
+
this.removeWatchDir(dir);
|
|
125
160
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// 添加新的目录
|
|
164
|
+
for (const dir of newDirs) {
|
|
165
|
+
if (!currentDirs.includes(dir)) {
|
|
166
|
+
this.addWatchDir(dir);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
129
169
|
}
|
|
130
170
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
171
|
+
this.logger.info("App configuration updated", this.config);
|
|
172
|
+
}
|
|
173
|
+
get schemas(){
|
|
174
|
+
return this.dependencyList.reduce((result, plugin) => {
|
|
175
|
+
plugin.schemas.forEach((schema, name) => {
|
|
176
|
+
result.set(name, schema);
|
|
177
|
+
});
|
|
178
|
+
return result;
|
|
179
|
+
}, new Map<string,Schema<any>>());
|
|
180
|
+
}
|
|
181
|
+
/** 使用插件 */
|
|
182
|
+
use(filePath: string): void {
|
|
183
|
+
this.emit("internal.add", filePath);
|
|
184
|
+
}
|
|
136
185
|
|
|
137
|
-
|
|
186
|
+
/** 启动App */
|
|
187
|
+
async start(mode: "dev" | "prod" = "prod"): Promise<void> {
|
|
188
|
+
await generateEnvTypes(process.cwd());
|
|
189
|
+
// 加载插件
|
|
190
|
+
for (const pluginName of this.config.plugins || []) {
|
|
191
|
+
this.use(pluginName);
|
|
138
192
|
}
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
const context = dep.contexts.get(name)!
|
|
144
|
-
// 如果上下文还没有挂载,等待挂载完成
|
|
145
|
-
if (!context.value) {
|
|
146
|
-
throw new Error(`Context ${name} is not mounted yet`)
|
|
147
|
-
}
|
|
148
|
-
return context.value
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
throw new Error(`can't find Context of ${name}`)
|
|
193
|
+
await sleep(200);
|
|
194
|
+
const schemas:Record<string,Schema>={};
|
|
195
|
+
for (const [name, schema] of this.schemas) {
|
|
196
|
+
schemas[name]=schema;
|
|
152
197
|
}
|
|
198
|
+
if (this.config.database) {
|
|
199
|
+
this.database=Registry.create((this.config.database as any).dialect,this.config.database,schemas);
|
|
200
|
+
await this.database?.start();
|
|
201
|
+
this.logger.info(`database init success`);
|
|
202
|
+
} else {
|
|
203
|
+
this.logger.info(`database not configured, skipping database init`);
|
|
204
|
+
}
|
|
205
|
+
this.dispatch("database.ready",this.database);
|
|
206
|
+
// 等待所有插件就绪
|
|
207
|
+
await this.waitForReady();
|
|
208
|
+
this.logger.info("started successfully");
|
|
209
|
+
this.dispatch("app.ready");
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/** 停止App */
|
|
213
|
+
async stop(): Promise<void> {
|
|
214
|
+
this.logger.info("Stopping app...");
|
|
215
|
+
// 销毁所有插件
|
|
216
|
+
this.dispose();
|
|
153
217
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
218
|
+
this.logger.info("App stopped");
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
getContext<T>(name: string): T {
|
|
222
|
+
for (const dep of this.dependencyList) {
|
|
223
|
+
if (dep.contexts.has(name)) {
|
|
224
|
+
const context = dep.contexts.get(name)!;
|
|
225
|
+
// 如果上下文还没有挂载,等待挂载完成
|
|
226
|
+
if (!context.value) {
|
|
227
|
+
throw new Error(`Context ${name} is not mounted yet`);
|
|
162
228
|
}
|
|
163
|
-
return
|
|
229
|
+
return context.value;
|
|
230
|
+
}
|
|
164
231
|
}
|
|
165
|
-
|
|
166
|
-
|
|
232
|
+
throw new Error(`can't find Context of ${name}`);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
async handleBeforeSend(options: SendOptions) {
|
|
236
|
+
const handlers = this.dependencyList.reduce((result, plugin) => {
|
|
237
|
+
result.push(...plugin.listeners("before-message.send"));
|
|
238
|
+
return result;
|
|
239
|
+
}, [] as Function[]);
|
|
240
|
+
for (const handler of handlers) {
|
|
241
|
+
const result = await handler(options);
|
|
242
|
+
if (result) options = result;
|
|
167
243
|
}
|
|
244
|
+
return options;
|
|
245
|
+
}
|
|
168
246
|
}
|
|
169
247
|
|
|
170
248
|
// ============================================================================
|
|
@@ -172,168 +250,195 @@ export class App extends HMR<Plugin> {
|
|
|
172
250
|
// ============================================================================
|
|
173
251
|
|
|
174
252
|
function getPlugin(hmr: HMR<Plugin>, filename: string): Plugin {
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
const envFiles=['.env',`.env.${process.env.NODE_ENV}`]
|
|
194
|
-
.filter(filename=>fs.existsSync(path.join(process.cwd(),filename)))
|
|
195
|
-
if (!config || Object.keys(config).length === 0) {
|
|
196
|
-
try {
|
|
197
|
-
logger.info('🔍 正在查找配置文件...');
|
|
198
|
-
[configPath,finalConfig] = await loadConfig();
|
|
199
|
-
logger.info('✅ 配置文件加载成功');
|
|
200
|
-
} catch (error) {
|
|
201
|
-
logger.warn('⚠️ 配置文件加载失败,使用默认配置:', error instanceof Error ? error.message : error);
|
|
202
|
-
finalConfig = Object.assign({}, App.defaultConfig);
|
|
203
|
-
}
|
|
204
|
-
} else {
|
|
205
|
-
finalConfig = Object.assign({}, App.defaultConfig, config);
|
|
206
|
-
}
|
|
207
|
-
const app= new App(finalConfig);
|
|
208
|
-
app.watching(envFiles,()=>{
|
|
209
|
-
process.exit(51)
|
|
210
|
-
})
|
|
211
|
-
if(configPath){
|
|
212
|
-
app.watching(configPath,()=>{
|
|
213
|
-
process.exit(51);
|
|
214
|
-
})
|
|
215
|
-
}
|
|
216
|
-
return app
|
|
253
|
+
const name = path.basename(filename).replace(path.extname(filename), "");
|
|
254
|
+
|
|
255
|
+
// 尝试从当前依赖中查找插件
|
|
256
|
+
const childPlugin = hmr.findChild(filename);
|
|
257
|
+
if (childPlugin) {
|
|
258
|
+
return childPlugin;
|
|
259
|
+
}
|
|
260
|
+
const parent = hmr.findParent(
|
|
261
|
+
filename,
|
|
262
|
+
getCallerFiles(fileURLToPath(import.meta.url))
|
|
263
|
+
);
|
|
264
|
+
// 创建新的插件实例
|
|
265
|
+
const newPlugin = new Plugin(parent, name, filename);
|
|
266
|
+
|
|
267
|
+
// 添加到当前依赖的子依赖中
|
|
268
|
+
parent.dependencies.set(filename, newPlugin);
|
|
269
|
+
|
|
270
|
+
return newPlugin;
|
|
217
271
|
}
|
|
218
272
|
/** 获取App实例 */
|
|
219
273
|
export function useApp(): App {
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
274
|
+
const hmr = HMR.currentHMR;
|
|
275
|
+
if (!hmr) throw new Error("useApp must be called within a App Context");
|
|
276
|
+
return hmr as unknown as App;
|
|
277
|
+
}
|
|
278
|
+
export function defineModel<T extends Record<string, any>>(
|
|
279
|
+
name: string,
|
|
280
|
+
schema: Schema<T>,
|
|
281
|
+
) {
|
|
282
|
+
const plugin = usePlugin();
|
|
283
|
+
return plugin.defineModel(name, schema);
|
|
223
284
|
}
|
|
224
285
|
|
|
225
286
|
/** 获取当前插件实例 */
|
|
226
287
|
export function usePlugin(): Plugin {
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
}
|
|
238
|
-
throw error;
|
|
288
|
+
const hmr = HMR.currentHMR;
|
|
289
|
+
if (!hmr) throw new Error("usePlugin must be called within a App Context");
|
|
290
|
+
|
|
291
|
+
try {
|
|
292
|
+
const currentFile = getCallerFile(import.meta.url);
|
|
293
|
+
return getPlugin(hmr as unknown as HMR<Plugin>, currentFile);
|
|
294
|
+
} catch (error) {
|
|
295
|
+
// 如果无法获取当前文件,尝试从当前依赖获取
|
|
296
|
+
if (HMR.currentDependency) {
|
|
297
|
+
return HMR.currentDependency as unknown as Plugin;
|
|
239
298
|
}
|
|
299
|
+
throw error;
|
|
300
|
+
}
|
|
240
301
|
}
|
|
241
|
-
export function beforeSend(handler:BeforeSendHandler){
|
|
242
|
-
|
|
243
|
-
|
|
302
|
+
export function beforeSend(handler: BeforeSendHandler) {
|
|
303
|
+
const plugin = usePlugin();
|
|
304
|
+
return plugin.beforeSend(handler);
|
|
244
305
|
}
|
|
245
306
|
/** 创建Context */
|
|
246
|
-
export function register<T>(context: Context<T,Plugin>): Context<T,Plugin> {
|
|
247
|
-
|
|
248
|
-
|
|
307
|
+
export function register<T>(context: Context<T, Plugin>): Context<T, Plugin> {
|
|
308
|
+
const plugin = usePlugin();
|
|
309
|
+
return plugin.register(context);
|
|
249
310
|
}
|
|
250
|
-
export function registerAdapter<T extends Adapter>(adapter:T){
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
311
|
+
export function registerAdapter<T extends Adapter>(adapter: T) {
|
|
312
|
+
const plugin = usePlugin();
|
|
313
|
+
plugin.app.adapters.push(adapter.name);
|
|
314
|
+
plugin.register({
|
|
315
|
+
name: adapter.name,
|
|
316
|
+
description: `adapter for ${adapter.name}`,
|
|
317
|
+
async mounted(plugin) {
|
|
318
|
+
await adapter.start(plugin);
|
|
319
|
+
return adapter;
|
|
320
|
+
},
|
|
321
|
+
dispose() {
|
|
322
|
+
return adapter.stop(plugin);
|
|
323
|
+
},
|
|
324
|
+
});
|
|
262
325
|
}
|
|
263
326
|
|
|
264
|
-
export function use<T extends keyof GlobalContext>(name: T): GlobalContext[T]
|
|
265
|
-
export function use<T>(name: string): T
|
|
266
|
-
export function use(name: string){
|
|
267
|
-
const plugin = usePlugin();
|
|
268
|
-
return plugin.use(name);
|
|
269
|
-
}
|
|
270
327
|
|
|
271
328
|
/** 标记必需的Context */
|
|
272
|
-
export function useContext<T extends (keyof GlobalContext)[]>(
|
|
273
|
-
|
|
274
|
-
|
|
329
|
+
export function useContext<T extends (keyof GlobalContext)[]>(
|
|
330
|
+
...args: [...T, sideEffect: SideEffect<T>]
|
|
331
|
+
): void {
|
|
332
|
+
const plugin = usePlugin();
|
|
333
|
+
plugin.useContext(...(args as any));
|
|
275
334
|
}
|
|
276
335
|
|
|
277
336
|
/** 添加中间件 */
|
|
278
337
|
export function addMiddleware(middleware: MessageMiddleware): void {
|
|
279
|
-
|
|
280
|
-
|
|
338
|
+
const plugin = usePlugin();
|
|
339
|
+
plugin.addMiddleware(middleware);
|
|
340
|
+
}
|
|
341
|
+
export function onDatabaseReady(callback: (database: RelatedDatabase<any,Models>|DocumentDatabase<any,Models>|KeyValueDatabase<any,Models>) => PromiseLike<void>) {
|
|
342
|
+
const plugin = usePlugin();
|
|
343
|
+
if (plugin.app.database?.isStarted) callback(plugin.app.database);
|
|
344
|
+
plugin.on("database.ready", callback);
|
|
345
|
+
}
|
|
346
|
+
export function useDatabase() {
|
|
347
|
+
const plugin = usePlugin();
|
|
348
|
+
return plugin.app.database;
|
|
349
|
+
}
|
|
350
|
+
export function onAppReady(callback: () => PromiseLike<void>) {
|
|
351
|
+
const plugin = usePlugin();
|
|
352
|
+
if (plugin.app.isReady) callback();
|
|
353
|
+
plugin.on("app.ready", callback);
|
|
354
|
+
}
|
|
355
|
+
/** 添加指令 */
|
|
356
|
+
export function addCommand(command: MessageCommand): void {
|
|
357
|
+
const plugin = usePlugin();
|
|
358
|
+
plugin.addCommand(command);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/** 添加组件 */
|
|
362
|
+
export function addComponent<T = {}, D = {}, P = Component.Props<T>>(
|
|
363
|
+
component: Component<T, D, P>
|
|
364
|
+
): void {
|
|
365
|
+
const plugin = usePlugin();
|
|
366
|
+
plugin.addComponent(component);
|
|
281
367
|
}
|
|
282
368
|
|
|
283
369
|
/** 监听事件 */
|
|
284
|
-
export function onEvent
|
|
285
|
-
|
|
286
|
-
|
|
370
|
+
export function onEvent(
|
|
371
|
+
event: string,
|
|
372
|
+
listener: (...args: any[]) => any
|
|
373
|
+
): void {
|
|
374
|
+
const plugin = usePlugin();
|
|
375
|
+
plugin.on(event, listener);
|
|
287
376
|
}
|
|
288
377
|
|
|
289
378
|
/** 监听群组消息 */
|
|
290
|
-
export function onGroupMessage(
|
|
291
|
-
|
|
379
|
+
export function onGroupMessage(
|
|
380
|
+
handler: (message: Message) => void | Promise<void>
|
|
381
|
+
): void {
|
|
382
|
+
onEvent("message.group.receive", handler);
|
|
292
383
|
}
|
|
293
384
|
|
|
294
385
|
/** 监听私聊消息 */
|
|
295
|
-
export function onPrivateMessage(
|
|
296
|
-
|
|
386
|
+
export function onPrivateMessage(
|
|
387
|
+
handler: (message: Message) => void | Promise<void>
|
|
388
|
+
): void {
|
|
389
|
+
onEvent("message.private.receive", handler);
|
|
297
390
|
}
|
|
298
391
|
|
|
299
392
|
/** 监听所有消息 */
|
|
300
|
-
export function onMessage
|
|
301
|
-
|
|
393
|
+
export function onMessage<T extends RegisteredAdapter>(
|
|
394
|
+
handler: (message: Message<AdapterMessage<T>>) => void | Promise<void>
|
|
395
|
+
): void {
|
|
396
|
+
onEvent("message.receive", handler);
|
|
397
|
+
}
|
|
398
|
+
/** 获取下一条消息 */
|
|
399
|
+
export function usePrompt<P extends RegisteredAdapter>(
|
|
400
|
+
message: Message<AdapterMessage<P>>
|
|
401
|
+
) {
|
|
402
|
+
const plugin = usePlugin();
|
|
403
|
+
return plugin.prompt<P>(message);
|
|
302
404
|
}
|
|
303
405
|
|
|
304
406
|
/** 监听插件挂载事件 */
|
|
305
|
-
export function onMounted(
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
407
|
+
export function onMounted(
|
|
408
|
+
hook: (plugin: Plugin) => Promise<void> | void
|
|
409
|
+
): void {
|
|
410
|
+
const plugin = usePlugin();
|
|
411
|
+
if (plugin.isReady) hook(plugin);
|
|
412
|
+
plugin.on("self.mounted", hook);
|
|
309
413
|
}
|
|
310
414
|
|
|
311
415
|
/** 监听插件销毁事件 */
|
|
312
416
|
export function onDispose(hook: () => void): void {
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
/** 添加定时任务 */
|
|
319
|
-
export function addCronJob(job: CronJob): void {
|
|
320
|
-
const plugin = usePlugin();
|
|
321
|
-
plugin.addCronJob(job);
|
|
417
|
+
const plugin = usePlugin();
|
|
418
|
+
if (plugin.isDispose) hook();
|
|
419
|
+
plugin.on("self.dispose", hook);
|
|
322
420
|
}
|
|
323
421
|
|
|
324
422
|
/** 发送消息 */
|
|
325
|
-
export async function sendMessage(options:SendOptions): Promise<void> {
|
|
326
|
-
|
|
327
|
-
|
|
423
|
+
export async function sendMessage(options: SendOptions): Promise<void> {
|
|
424
|
+
const app = useApp();
|
|
425
|
+
await app.sendMessage(options);
|
|
328
426
|
}
|
|
329
427
|
|
|
330
428
|
/** 获取App实例(用于高级操作) */
|
|
331
429
|
export function getAppInstance(): App {
|
|
332
|
-
|
|
430
|
+
return useApp();
|
|
333
431
|
}
|
|
334
432
|
|
|
335
433
|
/** 获取插件日志记录器 */
|
|
336
434
|
export function useLogger(): Logger {
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
}
|
|
435
|
+
const plugin = usePlugin();
|
|
436
|
+
return plugin.logger;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
/** 创建App实例的工厂函数 */
|
|
440
|
+
export async function createApp(config?: Partial<AppConfig>): Promise<App> {
|
|
441
|
+
const app = new App(config);
|
|
442
|
+
await app.start();
|
|
443
|
+
return app;
|
|
444
|
+
}
|