@zhin.js/core 1.0.7 → 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 (65) hide show
  1. package/CHANGELOG.md +9 -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 +240 -79
  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 -102
  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/prompt.test.ts +223 -0
  60. package/tests/schema.test.ts +248 -0
  61. package/lib/schema.d.ts +0 -83
  62. package/lib/schema.d.ts.map +0 -1
  63. package/lib/schema.js +0 -245
  64. package/lib/schema.js.map +0 -1
  65. 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,30 +350,54 @@ export class App extends HMR<Plugin> {
181
350
  * @param filePath 插件文件路径
182
351
  */
183
352
  createDependency(name: string, filePath: string): Plugin {
184
- return new Plugin(this, name, filePath)
353
+ return new Plugin(this, name, filePath);
185
354
  }
186
355
 
187
356
  /** 获取App配置 */
188
357
  /**
189
358
  * 获取App配置(只读)
190
359
  */
191
- getConfig(): Readonly<AppConfig> {
192
- 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);
193
369
  }
194
-
195
- /** 更新App配置 */
196
- /**
197
- * 更新App配置
198
- * @param config 部分配置项,将与现有配置合并
199
- */
200
- updateConfig(config: Partial<AppConfig>): void {
201
- this.config = { ...this.config, ...config };
202
-
203
- // 更新HMR配置
204
- 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) {
205
398
  // 动态更新监听目录
206
399
  const currentDirs = this.getWatchDirs();
207
- const newDirs = config.plugin_dirs;
400
+ const newDirs = newConfig.plugin_dirs;
208
401
 
209
402
  // 移除不再需要的目录
210
403
  for (const dir of currentDirs) {
@@ -220,52 +413,61 @@ export class App extends HMR<Plugin> {
220
413
  }
221
414
  }
222
415
  }
223
-
224
416
  this.logger.info("App configuration updated", this.config);
225
417
  }
226
- get schemas() {
227
- return this.dependencyList.reduce((result, plugin) => {
228
- plugin.schemas.forEach((schema, name) => {
229
- result.set(name, schema);
230
- });
231
- return result;
232
- }, new Map<string, Schema<any>>([
233
- ['SystemLog', SystemLogSchema],
234
- ['User', UserSchema]
235
- ]));
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
+ );
236
431
  }
237
432
  /** 使用插件 */
238
433
  use(filePath: string): void {
239
434
  this.emit("internal.add", filePath);
240
435
  }
241
-
242
- /** 启动App */
243
- async start(mode: "dev" | "prod" = "prod"): Promise<void> {
244
- await generateEnvTypes(process.cwd());
245
- // 加载插件
246
- for (const pluginName of this.config.plugins || []) {
247
- this.use(pluginName);
248
- }
249
- await sleep(200);
250
- const schemas: Record<string, Schema> = {};
251
- for (const [name, schema] of this.schemas) {
252
- 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;
253
444
  }
254
445
  if (this.config.database) {
255
- 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...`);
256
452
  await this.database?.start();
257
453
  this.logger.info(`database init success`);
258
-
259
- // 初始化日志传输器
260
- this.logTransport = new DatabaseLogTransport(this);
261
- addTransport(this.logTransport);
262
- this.logger.info(`database log transport registered`);
454
+ this.dispatch("database.ready", this.database);
263
455
  } else {
264
456
  this.logger.info(`database not configured, skipping database init`);
265
457
  }
266
- this.dispatch("database.ready", this.database);
267
458
  // 等待所有插件就绪
268
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
+ }
269
471
  this.logger.info("started successfully");
270
472
  this.dispatch("app.ready");
271
473
  }
@@ -313,6 +515,50 @@ export class App extends HMR<Plugin> {
313
515
  return options;
314
516
  }
315
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
+ }
316
562
 
317
563
  // ============================================================================
318
564
  // Hooks API
@@ -347,14 +593,17 @@ export function useApp(): App {
347
593
  }
348
594
  export function defineModel<T extends Record<string, any>>(
349
595
  name: string,
350
- schema: Schema<T>,
596
+ schema: Definition<T>
351
597
  ) {
352
598
  const plugin = usePlugin();
353
599
  return plugin.defineModel(name, schema);
354
600
  }
355
- export function addPermit<T extends RegisteredAdapter>(name: string | RegExp, checker: PermissionChecker<T>) {
356
- const plugin = usePlugin()
357
- 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);
358
607
  }
359
608
  /** 获取当前插件实例 */
360
609
  export function usePlugin(): Plugin {
@@ -388,16 +637,15 @@ export function registerAdapter<T extends Adapter>(adapter: T) {
388
637
  name: adapter.name,
389
638
  description: `adapter for ${adapter.name}`,
390
639
  async mounted(plugin) {
391
- await adapter.start(plugin);
640
+ await adapter.mounted(plugin);
392
641
  return adapter;
393
642
  },
394
643
  dispose() {
395
- return adapter.stop(plugin);
644
+ return adapter.dispose(plugin);
396
645
  },
397
646
  });
398
647
  }
399
648
 
400
-
401
649
  /** 标记必需的Context */
402
650
  export function useContext<T extends (keyof GlobalContext)[]>(
403
651
  ...args: [...T, sideEffect: SideEffect<T>]
@@ -411,7 +659,14 @@ export function addMiddleware(middleware: MessageMiddleware): void {
411
659
  const plugin = usePlugin();
412
660
  plugin.addMiddleware(middleware);
413
661
  }
414
- 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
+ ) {
415
670
  const plugin = usePlugin();
416
671
  if (plugin.app.database?.isStarted) callback(plugin.app.database);
417
672
  plugin.on("database.ready", callback);
@@ -432,9 +687,7 @@ export function addCommand(command: MessageCommand): void {
432
687
  }
433
688
 
434
689
  /** 添加组件 */
435
- export function addComponent<P = any>(
436
- component: Component<P>
437
- ): void {
690
+ export function addComponent<P = any>(component: Component<P>): void {
438
691
  const plugin = usePlugin();
439
692
  plugin.addComponent(component);
440
693
  }
@@ -497,7 +750,10 @@ export async function sendMessage(options: SendOptions): Promise<void> {
497
750
  const app = useApp();
498
751
  await app.sendMessage(options);
499
752
  }
500
-
753
+ export function defineSchema<S extends Schema>(rules: S): S {
754
+ const plugin = usePlugin();
755
+ return plugin.defineSchema(rules);
756
+ }
501
757
  /** 获取App实例(用于高级操作) */
502
758
  export function getAppInstance(): App {
503
759
  return useApp();
@@ -510,8 +766,8 @@ export function useLogger(): Logger {
510
766
  }
511
767
 
512
768
  /** 创建App实例的工厂函数 */
513
- export async function createApp(config?: Partial<AppConfig>): Promise<App> {
514
- const app = new App(config);
769
+ export async function createApp(config_file?: string): Promise<App> {
770
+ const app = new App(config_file);
515
771
  await app.start();
516
772
  return app;
517
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
- }