@zhin.js/core 1.0.6 → 1.0.8

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 (66) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/lib/adapter.d.ts +8 -6
  3. package/lib/adapter.d.ts.map +1 -1
  4. package/lib/adapter.js +13 -7
  5. package/lib/adapter.js.map +1 -1
  6. package/lib/app.d.ts +72 -14
  7. package/lib/app.d.ts.map +1 -1
  8. package/lib/app.js +241 -83
  9. package/lib/app.js.map +1 -1
  10. package/lib/bot.d.ts +10 -8
  11. package/lib/bot.d.ts.map +1 -1
  12. package/lib/config.d.ts +44 -14
  13. package/lib/config.d.ts.map +1 -1
  14. package/lib/config.js +275 -208
  15. package/lib/config.js.map +1 -1
  16. package/lib/index.d.ts +1 -1
  17. package/lib/index.d.ts.map +1 -1
  18. package/lib/index.js +1 -1
  19. package/lib/index.js.map +1 -1
  20. package/lib/log-transport.js +1 -1
  21. package/lib/log-transport.js.map +1 -1
  22. package/lib/models/system-log.d.ts +2 -2
  23. package/lib/models/system-log.d.ts.map +1 -1
  24. package/lib/models/system-log.js +1 -1
  25. package/lib/models/system-log.js.map +1 -1
  26. package/lib/models/user.d.ts +2 -2
  27. package/lib/models/user.d.ts.map +1 -1
  28. package/lib/models/user.js +1 -1
  29. package/lib/models/user.js.map +1 -1
  30. package/lib/plugin.d.ts +7 -3
  31. package/lib/plugin.d.ts.map +1 -1
  32. package/lib/plugin.js +16 -5
  33. package/lib/plugin.js.map +1 -1
  34. package/lib/prompt.d.ts +1 -1
  35. package/lib/prompt.d.ts.map +1 -1
  36. package/lib/prompt.js +9 -7
  37. package/lib/prompt.js.map +1 -1
  38. package/lib/types.d.ts +6 -5
  39. package/lib/types.d.ts.map +1 -1
  40. package/package.json +4 -4
  41. package/src/adapter.ts +18 -11
  42. package/src/app.ts +358 -105
  43. package/src/bot.ts +27 -25
  44. package/src/config.ts +352 -230
  45. package/src/index.ts +1 -1
  46. package/src/log-transport.ts +1 -1
  47. package/src/models/system-log.ts +2 -2
  48. package/src/models/user.ts +2 -2
  49. package/src/plugin.ts +19 -6
  50. package/src/prompt.ts +10 -9
  51. package/src/types.ts +8 -5
  52. package/tests/adapter.test.ts +5 -200
  53. package/tests/app.test.ts +208 -181
  54. package/tests/command.test.ts +2 -2
  55. package/tests/config.test.ts +5 -326
  56. package/tests/cron.test.ts +277 -0
  57. package/tests/jsx.test.ts +300 -0
  58. package/tests/permissions.test.ts +358 -0
  59. package/tests/plugin.test.ts +40 -177
  60. package/tests/prompt.test.ts +223 -0
  61. package/tests/schema.test.ts +248 -0
  62. package/lib/schema.d.ts +0 -83
  63. package/lib/schema.d.ts.map +0 -1
  64. package/lib/schema.js +0 -245
  65. package/lib/schema.js.map +0 -1
  66. package/src/schema.ts +0 -273
package/src/app.ts CHANGED
@@ -1,11 +1,13 @@
1
1
  import path from "path";
2
2
  import { SideEffect, GlobalContext, Models } from "@zhin.js/types";
3
+ import { Schema } from '@zhin.js/hmr';
3
4
  import {
4
5
  HMR,
5
6
  Context,
6
7
  Logger,
7
8
  getCallerFile,
8
9
  getCallerFiles,
10
+ mergeConfig,
9
11
  } from "@zhin.js/hmr";
10
12
  import {
11
13
  AdapterMessage,
@@ -15,6 +17,7 @@ import {
15
17
  SendOptions,
16
18
  MessageMiddleware,
17
19
  } from "./types.js";
20
+ import { Config } from "./config.js";
18
21
  import { Message } from "./message.js";
19
22
  import { fileURLToPath } from "url";
20
23
  import { generateEnvTypes } from "./types-generator.js";
@@ -27,15 +30,21 @@ import { Plugin } from "./plugin.js";
27
30
  import { Adapter } from "./adapter";
28
31
  import { MessageCommand } from "./command";
29
32
  import { Component } from "./component";
30
- import { RelatedDatabase, DocumentDatabase, KeyValueDatabase, Schema, Registry } from "@zhin.js/database";
33
+ import {
34
+ RelatedDatabase,
35
+ DocumentDatabase,
36
+ KeyValueDatabase,
37
+ Definition,
38
+ Registry,
39
+ } from "@zhin.js/database";
31
40
  import { DatabaseLogTransport } from "./log-transport.js";
32
- import { SystemLog, SystemLogSchema } from "./models/system-log.js";
33
- import { User, UserSchema } from './models/user.js'
41
+ import { SystemLog, SystemLogDefinition } from "./models/system-log.js";
42
+ import { User, UserDefinition } from "./models/user.js";
34
43
  import { addTransport, removeTransport } from "@zhin.js/logger";
35
44
  declare module "@zhin.js/types" {
36
45
  interface Models {
37
46
  SystemLog: SystemLog;
38
- User: User
47
+ User: User;
39
48
  }
40
49
  }
41
50
 
@@ -48,45 +57,47 @@ declare module "@zhin.js/types" {
48
57
  */
49
58
  export class App extends HMR<Plugin> {
50
59
  static currentPlugin: Plugin;
51
- private config: AppConfig;
52
60
  middlewares: MessageMiddleware[] = [];
53
61
  adapters: string[] = [];
54
- database?: RelatedDatabase<any, Models> | DocumentDatabase<any, Models> | KeyValueDatabase<any, Models>;
62
+ #config: Config<AppConfig>;
63
+ database?:
64
+ | RelatedDatabase<any, Models>
65
+ | DocumentDatabase<any, Models>
66
+ | KeyValueDatabase<any, Models>;
55
67
  permissions: Permissions = new Permissions(this);
56
68
  private logTransport?: DatabaseLogTransport;
69
+ /** 配置变更处理锁 */
70
+ private configChangeLock: Promise<void> | null = null;
57
71
  /**
58
72
  * 构造函数:初始化应用,加载配置,注册全局异常处理
59
- * @param config 可选的应用配置,若为空则自动查找配置文件
73
+ * @param config 可选,应用配置,若为空则自动查找配置文件
60
74
  */
61
- constructor(config?: Partial<AppConfig>) {
62
- // 如果没有传入配置或配置为空对象,尝试自动加载配置文件
63
- let finalConfig: AppConfig;
64
- if (!config || Object.keys(config).length === 0) {
65
- try {
66
- // 异步加载配置,这里需要改为同步初始化
67
- logger.info("🔍 正在查找配置文件...");
68
- finalConfig = App.loadConfigSync();
69
- logger.info(" 配置文件加载成功");
70
- } catch (error) {
71
- logger.warn("⚠️ 配置文件加载失败,使用默认配置", {
72
- error: error instanceof Error ? error.message : String(error),
73
- });
74
- finalConfig = Object.assign({}, App.defaultConfig);
75
- }
76
- } else {
77
- // 合并默认配置和传入的配置
78
- finalConfig = Object.assign({}, App.defaultConfig, config);
79
- }
80
-
75
+ constructor(config: AppConfig);
76
+ /**
77
+ * 构造函数:初始化应用,加载配置,注册全局异常处理
78
+ * @param config_file 可选,配置文件路径,默认为 'zhin.config.yml'
79
+ */
80
+ constructor(config_file?: string);
81
+ constructor(config_param: string | AppConfig = "zhin.config.yml") {
82
+ const config_file =
83
+ typeof config_param === "string" ? config_param : "zhin.config.yml";
84
+ const config_obj =
85
+ typeof config_param === "object" ? config_param : App.defaultConfig;
86
+ const config = new Config<AppConfig>(
87
+ config_file,
88
+ App.schema,
89
+ mergeConfig(App.defaultConfig, config_obj)
90
+ );
81
91
  // 调用父类构造函数
82
- super("Zhin", {
92
+ super({
83
93
  logger,
84
- dirs: finalConfig.plugin_dirs || [],
94
+ dirs: config.get("plugin_dirs") || [],
85
95
  extensions: new Set([".js", ".ts", ".jsx", ".tsx"]),
86
- debug: finalConfig.debug,
96
+ debug: config.get("debug"),
87
97
  });
98
+ this.watching(config.filepath,()=>config.reload());
88
99
  this.on("message.send", this.sendMessage.bind(this));
89
- this.on('message.receive',this.receiveMessage.bind(this))
100
+ this.on("message.receive", this.receiveMessage.bind(this));
90
101
  process.on("uncaughtException", (e) => {
91
102
  const args = e instanceof Error ? [e.message, { stack: e.stack }] : [e];
92
103
  this.logger.error(...args);
@@ -95,17 +106,175 @@ export class App extends HMR<Plugin> {
95
106
  const args = e instanceof Error ? [e.message, { stack: e.stack }] : [e];
96
107
  this.logger.error(...args);
97
108
  });
98
- this.config = finalConfig;
99
- setLevel(finalConfig.log_level);
100
- this.middleware(this.messageMiddleware.bind(this))
109
+ this.#config = config;
110
+ // 监听配置变更
111
+ config.on("change", (before, after) => {
112
+ this.handleConfigChange(before, after);
113
+ this.broadcast("config.change", before, after);
114
+ });
115
+ this.defineSchema(App.schema);
116
+ setLevel(config.get("log_level") || LogLevel.INFO);
117
+ this.middleware(this.messageMiddleware.bind(this));
101
118
  }
102
- async receiveMessage<P extends RegisteredAdapter>(message: Message<AdapterMessage<P>>) {
103
- const middlewares=this.dependencyList.reduce((result, plugin) => {
104
- result.push(...plugin.middlewares as MessageMiddleware<P>[]);
105
- return result;
106
- }, [...this.middlewares] as MessageMiddleware<P>[]);
107
- const handle=compose(middlewares)
108
- await handle(message)
119
+
120
+ /**
121
+ * 处理配置变更
122
+ * 如果上一次变更未完成,等待其完成后再处理新的变更
123
+ */
124
+ private async handleConfigChange(
125
+ before: AppConfig,
126
+ after: AppConfig
127
+ ): Promise<void> {
128
+ this.logger.info("configuration changed");
129
+ // 等待上一次配置变更处理完成
130
+ if (this.configChangeLock) {
131
+ this.logger.info("Waiting for previous config change to complete...");
132
+ await this.configChangeLock;
133
+ }
134
+
135
+ // 创建新的锁
136
+ this.configChangeLock = this.applyConfigChanges(before, after);
137
+
138
+ try {
139
+ await this.configChangeLock;
140
+ } finally {
141
+ this.configChangeLock = null;
142
+ }
143
+ }
144
+
145
+ /**
146
+ * 应用配置变更
147
+ */
148
+ private async applyConfigChanges(
149
+ before: AppConfig,
150
+ after: AppConfig
151
+ ): Promise<void> {
152
+ try {
153
+ // 1. 更新日志级别
154
+ if (after.log_level !== before.log_level) {
155
+ setLevel(after.log_level || LogLevel.INFO);
156
+ }
157
+
158
+ // 2. 更新监听目录
159
+ await this.updateWatchDirs(
160
+ before.plugin_dirs || [],
161
+ after.plugin_dirs || []
162
+ );
163
+
164
+ // 3. 更新插件加载
165
+ await this.updatePlugins(before.plugins || [], after.plugins || []);
166
+ } catch (error) {
167
+ this.logger.error("Failed to apply configuration changes:", error);
168
+ throw error;
169
+ }
170
+ // 4. 更新数据库连接
171
+ if (JSON.stringify(before.database) !== JSON.stringify(after.database)) {
172
+ this.database?.stop();
173
+ if (after.database) {
174
+ this.database = Registry.create(
175
+ (this.config.database as any).dialect,
176
+ this.config.database,
177
+ Object.fromEntries(this.definitions)
178
+ );
179
+ await this.database!.start();
180
+ }
181
+ }
182
+ }
183
+
184
+ /**
185
+ * 更新监听目录
186
+ */
187
+ private async updateWatchDirs(
188
+ oldDirs: string[],
189
+ newDirs: string[]
190
+ ): Promise<void> {
191
+ const oldResolved = oldDirs.map((dir) => path.resolve(process.cwd(), dir));
192
+ const newResolved = newDirs.map((dir) => path.resolve(process.cwd(), dir));
193
+
194
+ // 找出需要移除的目录
195
+ const dirsToRemove = oldResolved.filter(
196
+ (dir) => !newResolved.includes(dir)
197
+ );
198
+ // 找出需要添加的目录
199
+ const dirsToAdd = newResolved.filter((dir) => !oldResolved.includes(dir));
200
+
201
+ // 移除过时的监听目录
202
+ for (const dir of dirsToRemove) {
203
+ this.removeWatchDir(dir);
204
+ }
205
+
206
+ // 添加新的监听目录
207
+ for (const dir of dirsToAdd) {
208
+ this.addWatchDir(dir);
209
+ }
210
+ }
211
+
212
+ /**
213
+ * 更新插件加载
214
+ */
215
+ private async updatePlugins(
216
+ oldPlugins: string[],
217
+ newPlugins: string[]
218
+ ): Promise<void> {
219
+ // 找出需要卸载的插件
220
+ const pluginsToUnload = oldPlugins.filter(
221
+ (plugin) => !newPlugins.includes(plugin)
222
+ );
223
+ // 找出需要加载的插件
224
+ const pluginsToLoad = newPlugins.filter(
225
+ (plugin) => !oldPlugins.includes(plugin)
226
+ );
227
+
228
+ // 卸载不再需要的插件
229
+ for (const pluginName of pluginsToUnload) {
230
+ await this.unloadPlugin(pluginName);
231
+ }
232
+
233
+ // 加载新插件
234
+ for (const pluginName of pluginsToLoad) {
235
+ this.use(pluginName);
236
+ }
237
+
238
+ // 等待新插件加载完成
239
+ if (pluginsToLoad.length > 0) {
240
+ await sleep(200);
241
+ await this.waitForReady();
242
+ }
243
+ }
244
+
245
+ /**
246
+ * 卸载插件
247
+ */
248
+ private async unloadPlugin(pluginName: string): Promise<void> {
249
+ // 尝试找到插件 (使用 HMR 提供的方法)
250
+ const plugin = this.findPluginByName<Plugin>(pluginName);
251
+ if (plugin) {
252
+ // 找到插件的文件路径
253
+ const filePath = plugin.filename;
254
+
255
+ // 销毁插件
256
+ plugin.dispose();
257
+
258
+ // 从依赖映射中移除
259
+ this.dependencies.delete(filePath);
260
+
261
+ this.logger.info(`Plugin ${pluginName} unloaded successfully`);
262
+ } else {
263
+ this.logger.warn(`Plugin ${pluginName} not found, skipping unload`);
264
+ }
265
+ }
266
+ async receiveMessage<P extends RegisteredAdapter>(
267
+ message: Message<AdapterMessage<P>>
268
+ ) {
269
+ const middlewares = this.dependencyList.reduce(
270
+ (result, plugin) => {
271
+ result.push(...(plugin.middlewares as MessageMiddleware<P>[]));
272
+ return result;
273
+ },
274
+ [...this.middlewares] as MessageMiddleware<P>[]
275
+ );
276
+ const handle = compose(middlewares);
277
+ await handle(message);
109
278
  }
110
279
  async messageMiddleware(message: Message, next: () => Promise<void>) {
111
280
  for (const command of this.commands) {
@@ -130,13 +299,13 @@ export class App extends HMR<Plugin> {
130
299
  */
131
300
  static defaultConfig: AppConfig = {
132
301
  log_level: LogLevel.INFO,
133
- plugin_dirs: ["./plugins"],
302
+ plugin_dirs: [],
134
303
  plugins: [],
135
304
  bots: [],
136
305
  debug: false,
137
306
  };
138
307
  middleware(middleware: MessageMiddleware) {
139
- this.middlewares.push(middleware)
308
+ this.middlewares.push(middleware);
140
309
  }
141
310
  /**
142
311
  * 发送消息到指定适配器和机器人
@@ -181,33 +350,54 @@ export class App extends HMR<Plugin> {
181
350
  * @param filePath 插件文件路径
182
351
  */
183
352
  createDependency(name: string, filePath: string): Plugin {
184
- const plugin = new Plugin(this, name, filePath);
185
- // 将插件添加到依赖列表中
186
- this.dependencies.set(name, plugin);
187
- return plugin;
353
+ return new Plugin(this, name, filePath);
188
354
  }
189
355
 
190
356
  /** 获取App配置 */
191
357
  /**
192
358
  * 获取App配置(只读)
193
359
  */
194
- getConfig(): Readonly<AppConfig> {
195
- return { ...this.config };
360
+ getConfig(): Readonly<AppConfig>;
361
+ getConfig<T extends Config.Paths<AppConfig>>(
362
+ key: T
363
+ ): Readonly<Config.Value<AppConfig, T>>;
364
+ getConfig<T extends Config.Paths<AppConfig>>(key?: T) {
365
+ if (key === undefined) {
366
+ return this.#config.config;
367
+ }
368
+ return this.#config.get(key);
196
369
  }
197
-
198
- /** 更新App配置 */
199
- /**
200
- * 更新App配置
201
- * @param config 部分配置项,将与现有配置合并
202
- */
203
- updateConfig(config: Partial<AppConfig>): void {
204
- this.config = { ...this.config, ...config };
205
-
206
- // 更新HMR配置
207
- if (config.plugin_dirs) {
370
+ setConfig(value: AppConfig): void;
371
+ setConfig<T extends Config.Paths<AppConfig>>(
372
+ key: T,
373
+ value: Config.Value<AppConfig, T>
374
+ ): void;
375
+ setConfig<T extends Config.Paths<AppConfig>>(
376
+ key: T | AppConfig,
377
+ value?: Config.Value<AppConfig, T>
378
+ ): void {
379
+ if (typeof key === "object") {
380
+ this.#config.config = key;
381
+ } else if (value !== undefined) {
382
+ this.#config.set(key, value);
383
+ }
384
+ }
385
+ changeSchema(key: string, value: Schema) {
386
+ if (!App.schema.options.object) {
387
+ App.schema.options.object = {};
388
+ }
389
+ App.schema.options.object[key] = value;
390
+ this.#config.reload();
391
+ }
392
+ get config() {
393
+ return this.#config.config;
394
+ }
395
+ set config(newConfig: AppConfig) {
396
+ this.#config.config = newConfig;
397
+ if (newConfig.plugin_dirs) {
208
398
  // 动态更新监听目录
209
399
  const currentDirs = this.getWatchDirs();
210
- const newDirs = config.plugin_dirs;
400
+ const newDirs = newConfig.plugin_dirs;
211
401
 
212
402
  // 移除不再需要的目录
213
403
  for (const dir of currentDirs) {
@@ -223,52 +413,61 @@ export class App extends HMR<Plugin> {
223
413
  }
224
414
  }
225
415
  }
226
-
227
416
  this.logger.info("App configuration updated", this.config);
228
417
  }
229
- get schemas() {
230
- return this.dependencyList.reduce((result, plugin) => {
231
- plugin.schemas.forEach((schema, name) => {
232
- result.set(name, schema);
233
- });
234
- return result;
235
- }, new Map<string, Schema<any>>([
236
- ['SystemLog', SystemLogSchema],
237
- ['User', UserSchema]
238
- ]));
418
+ get definitions() {
419
+ return this.dependencyList.reduce(
420
+ (result, plugin) => {
421
+ plugin.definitions.forEach((definition, name) => {
422
+ result.set(name, definition);
423
+ });
424
+ return result;
425
+ },
426
+ new Map<string, Definition<any>>([
427
+ ["SystemLog", SystemLogDefinition],
428
+ ["User", UserDefinition],
429
+ ])
430
+ );
239
431
  }
240
432
  /** 使用插件 */
241
433
  use(filePath: string): void {
242
434
  this.emit("internal.add", filePath);
243
435
  }
244
-
245
- /** 启动App */
246
- async start(mode: "dev" | "prod" = "prod"): Promise<void> {
247
- await generateEnvTypes(process.cwd());
248
- // 加载插件
249
- for (const pluginName of this.config.plugins || []) {
250
- this.use(pluginName);
251
- }
252
- await sleep(200);
253
- const schemas: Record<string, Schema> = {};
254
- for (const [name, schema] of this.schemas) {
255
- schemas[name] = schema;
436
+ async #init() {
437
+ // 首次初始化时,执行配置应用逻辑
438
+ await this.handleConfigChange(App.defaultConfig, this.config);
439
+
440
+ // 初始化数据库
441
+ const definitions: Record<string, Definition> = {};
442
+ for (const [name, schema] of this.definitions) {
443
+ definitions[name] = schema;
256
444
  }
257
445
  if (this.config.database) {
258
- this.database = Registry.create((this.config.database as any).dialect, this.config.database, schemas);
446
+ this.database = Registry.create(
447
+ (this.config.database as any).dialect,
448
+ this.config.database,
449
+ definitions
450
+ );
451
+ this.logger.info(`database init...`);
259
452
  await this.database?.start();
260
453
  this.logger.info(`database init success`);
261
-
262
- // 初始化日志传输器
263
- this.logTransport = new DatabaseLogTransport(this);
264
- addTransport(this.logTransport);
265
- this.logger.info(`database log transport registered`);
454
+ this.dispatch("database.ready", this.database);
266
455
  } else {
267
456
  this.logger.info(`database not configured, skipping database init`);
268
457
  }
269
- this.dispatch("database.ready", this.database);
270
458
  // 等待所有插件就绪
271
459
  await this.waitForReady();
460
+ }
461
+ /** 启动App */
462
+ async start(mode: "dev" | "prod" = "prod"): Promise<void> {
463
+ await generateEnvTypes(process.cwd());
464
+ await this.#init();
465
+ if (this.database) {
466
+ // 初始化日志传输器
467
+ this.logTransport = new DatabaseLogTransport(this);
468
+ addTransport(this.logTransport);
469
+ this.logger.info(`database log transport registered`);
470
+ }
272
471
  this.logger.info("started successfully");
273
472
  this.dispatch("app.ready");
274
473
  }
@@ -316,6 +515,50 @@ export class App extends HMR<Plugin> {
316
515
  return options;
317
516
  }
318
517
  }
518
+ export namespace App {
519
+ export const schema = Schema.object({
520
+ database: Schema.any().description("数据库配置"),
521
+ bots: Schema.list(Schema.any()).default([]).description("机器人配置列表"),
522
+ log_level: Schema.number()
523
+ .default(LogLevel.INFO)
524
+ .description("日志级别 (0=DEBUG, 1=INFO, 2=WARN, 3=ERROR, 4=SILENT)")
525
+ .min(0)
526
+ .max(4),
527
+ log: Schema.object({
528
+ maxDays: Schema.number().default(7).description("日志最大保存天数"),
529
+ maxRecords: Schema.number().default(10000).description("日志最大记录数"),
530
+ cleanupInterval: Schema.number()
531
+ .default(24)
532
+ .description("日志清理间隔(小时)"),
533
+ })
534
+ .description("日志配置")
535
+ .default({
536
+ maxDays: 7,
537
+ maxRecords: 10000,
538
+ cleanupInterval: 24,
539
+ }),
540
+ plugin_dirs: Schema.list(Schema.string())
541
+ .default(["node_modules"])
542
+ .description("插件目录列表"),
543
+
544
+ plugins: Schema.list(Schema.string())
545
+ .default([])
546
+ .description("需要加载的插件列表"),
547
+ debug: Schema.boolean()
548
+ .default(false)
549
+ .description("是否启用调试模式"),
550
+ }).default({
551
+ log_level: LogLevel.INFO,
552
+ log: {
553
+ maxDays: 7,
554
+ maxRecords: 10000,
555
+ cleanupInterval: 24,
556
+ },
557
+ plugin_dirs: ["node_modules"],
558
+ plugins: [],
559
+ debug: false,
560
+ });
561
+ }
319
562
 
320
563
  // ============================================================================
321
564
  // Hooks API
@@ -350,14 +593,17 @@ export function useApp(): App {
350
593
  }
351
594
  export function defineModel<T extends Record<string, any>>(
352
595
  name: string,
353
- schema: Schema<T>,
596
+ schema: Definition<T>
354
597
  ) {
355
598
  const plugin = usePlugin();
356
599
  return plugin.defineModel(name, schema);
357
600
  }
358
- export function addPermit<T extends RegisteredAdapter>(name: string | RegExp, checker: PermissionChecker<T>) {
359
- const plugin = usePlugin()
360
- return plugin.addPermit(name, checker)
601
+ export function addPermit<T extends RegisteredAdapter>(
602
+ name: string | RegExp,
603
+ checker: PermissionChecker<T>
604
+ ) {
605
+ const plugin = usePlugin();
606
+ return plugin.addPermit(name, checker);
361
607
  }
362
608
  /** 获取当前插件实例 */
363
609
  export function usePlugin(): Plugin {
@@ -391,16 +637,15 @@ export function registerAdapter<T extends Adapter>(adapter: T) {
391
637
  name: adapter.name,
392
638
  description: `adapter for ${adapter.name}`,
393
639
  async mounted(plugin) {
394
- await adapter.start(plugin);
640
+ await adapter.mounted(plugin);
395
641
  return adapter;
396
642
  },
397
643
  dispose() {
398
- return adapter.stop(plugin);
644
+ return adapter.dispose(plugin);
399
645
  },
400
646
  });
401
647
  }
402
648
 
403
-
404
649
  /** 标记必需的Context */
405
650
  export function useContext<T extends (keyof GlobalContext)[]>(
406
651
  ...args: [...T, sideEffect: SideEffect<T>]
@@ -414,7 +659,14 @@ export function addMiddleware(middleware: MessageMiddleware): void {
414
659
  const plugin = usePlugin();
415
660
  plugin.addMiddleware(middleware);
416
661
  }
417
- export function onDatabaseReady(callback: (database: RelatedDatabase<any, Models> | DocumentDatabase<any, Models> | KeyValueDatabase<any, Models>) => PromiseLike<void>) {
662
+ export function onDatabaseReady(
663
+ callback: (
664
+ database:
665
+ | RelatedDatabase<any, Models>
666
+ | DocumentDatabase<any, Models>
667
+ | KeyValueDatabase<any, Models>
668
+ ) => PromiseLike<void>
669
+ ) {
418
670
  const plugin = usePlugin();
419
671
  if (plugin.app.database?.isStarted) callback(plugin.app.database);
420
672
  plugin.on("database.ready", callback);
@@ -435,9 +687,7 @@ export function addCommand(command: MessageCommand): void {
435
687
  }
436
688
 
437
689
  /** 添加组件 */
438
- export function addComponent<P = any>(
439
- component: Component<P>
440
- ): void {
690
+ export function addComponent<P = any>(component: Component<P>): void {
441
691
  const plugin = usePlugin();
442
692
  plugin.addComponent(component);
443
693
  }
@@ -500,7 +750,10 @@ export async function sendMessage(options: SendOptions): Promise<void> {
500
750
  const app = useApp();
501
751
  await app.sendMessage(options);
502
752
  }
503
-
753
+ export function defineSchema<S extends Schema>(rules: S): S {
754
+ const plugin = usePlugin();
755
+ return plugin.defineSchema(rules);
756
+ }
504
757
  /** 获取App实例(用于高级操作) */
505
758
  export function getAppInstance(): App {
506
759
  return useApp();
@@ -513,8 +766,8 @@ export function useLogger(): Logger {
513
766
  }
514
767
 
515
768
  /** 创建App实例的工厂函数 */
516
- export async function createApp(config?: Partial<AppConfig>): Promise<App> {
517
- const app = new App(config);
769
+ export async function createApp(config_file?: string): Promise<App> {
770
+ const app = new App(config_file);
518
771
  await app.start();
519
772
  return app;
520
773
  }
package/src/bot.ts CHANGED
@@ -1,32 +1,34 @@
1
- import type { SendOptions} from "./types.js";
2
- import {Message} from "./message.js";
1
+ import type { SendOptions } from "./types.js";
2
+ import { Message } from "./message.js";
3
3
  /**
4
4
  * Bot接口:所有平台机器人需实现的统一接口。
5
5
  * 负责消息格式化、连接、断开、消息发送等。
6
6
  * @template M 消息类型
7
7
  * @template T 配置类型
8
8
  */
9
- export interface Bot<M extends object={},T extends BotConfig=BotConfig> {
10
- /** 机器人配置 */
11
- $config: T;
12
- /** 是否已连接 */
13
- $connected?: boolean;
14
- /** 格式化平台消息为标准Message结构 */
15
- $formatMessage(message:M):Message<M>
16
- /** 连接机器人 */
17
- $connect():Promise<void>
18
- /** 断开机器人 */
19
- $disconnect():Promise<void>
20
- /** 撤回消息 */
21
- $recallMessage(id:string):Promise<void>
22
- /** 发送消息返回消息id */
23
- $sendMessage(options: SendOptions): Promise<string>
9
+ export interface Bot<M extends object = {}, T extends Bot.Config = Bot.Config> {
10
+ /** 机器人配置 */
11
+ $config: T;
12
+ /** 是否已连接 */
13
+ $connected?: boolean;
14
+ /** 格式化平台消息为标准Message结构 */
15
+ $formatMessage(message: M): Message<M>;
16
+ /** 连接机器人 */
17
+ $connect(): Promise<void>;
18
+ /** 断开机器人 */
19
+ $disconnect(): Promise<void>;
20
+ /** 撤回消息 */
21
+ $recallMessage(id: string): Promise<void>;
22
+ /** 发送消息返回消息id */
23
+ $sendMessage(options: SendOptions): Promise<string>;
24
+ }
25
+ export namespace Bot {
26
+ /**
27
+ * Bot配置类型,所有平台机器人通用
28
+ */
29
+ export interface Config {
30
+ context: string;
31
+ name: string;
32
+ [key: string]: any;
33
+ }
24
34
  }
25
- /**
26
- * Bot配置类型,所有平台机器人通用
27
- */
28
- export interface BotConfig{
29
- context:string
30
- name:string
31
- [key:string]:any
32
- }