@kotori-bot/loader 1.2.0 → 1.4.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/README.md ADDED
@@ -0,0 +1,27 @@
1
+ # @kotori-bot/core
2
+
3
+ ```typescript
4
+ interface Context {
5
+ readonly baseDir: Runner['baseDir'];
6
+ readonly options: Runner['options'];
7
+ readonly [Symbols.modules]: Runner[typeof Symbols.modules];
8
+ loadAll(): void;
9
+ watcher(): void;
10
+ logger: Logger;
11
+ /* Service */
12
+ server: Server;
13
+ db: Database;
14
+ file: File;
15
+ }
16
+ ```
17
+
18
+ - Loader
19
+ - Runner
20
+ - Server
21
+ - Database
22
+ - File
23
+ - log
24
+
25
+ ## Reference
26
+
27
+ - [Kotori Docs](https://kotori.js.org/)
package/lib/consts.d.ts CHANGED
@@ -1,4 +1,8 @@
1
1
  export declare const DEV_FILE = ".ts";
2
2
  export declare const BUILD_FILE = ".js";
3
- export declare const DEV_IMPORT = "./src/index.ts";
4
3
  export declare const DEV_CODE_DIRS = "./src/";
4
+ export declare const DEV_IMPORT = "./src/index.ts";
5
+ export declare const BUILD_CONFIG_NAME = "kotori.yml";
6
+ export declare const DEV_CONFIG_NAME = "kotori.dev.yml";
7
+ export declare const SUPPORTS_VERSION: RegExp;
8
+ export declare const SUPPORTS_HALF_VERSION: RegExp;
package/lib/consts.js CHANGED
@@ -1,7 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DEV_CODE_DIRS = exports.DEV_IMPORT = exports.BUILD_FILE = exports.DEV_FILE = void 0;
3
+ exports.SUPPORTS_HALF_VERSION = exports.SUPPORTS_VERSION = exports.DEV_CONFIG_NAME = exports.BUILD_CONFIG_NAME = exports.DEV_IMPORT = exports.DEV_CODE_DIRS = exports.BUILD_FILE = exports.DEV_FILE = void 0;
4
4
  exports.DEV_FILE = '.ts';
5
5
  exports.BUILD_FILE = '.js';
6
- exports.DEV_IMPORT = './src/index.ts';
7
6
  exports.DEV_CODE_DIRS = './src/';
7
+ exports.DEV_IMPORT = `${exports.DEV_CODE_DIRS}index.ts`;
8
+ exports.BUILD_CONFIG_NAME = 'kotori.yml';
9
+ exports.DEV_CONFIG_NAME = 'kotori.dev.yml';
10
+ exports.SUPPORTS_VERSION = /(1\.1\.0)|(1\.2\.0)/;
11
+ exports.SUPPORTS_HALF_VERSION = /(x\.x\.(.*?))/;
package/lib/index.d.ts CHANGED
@@ -1,2 +1,3 @@
1
- import loader from './loader';
2
- export default loader;
1
+ export * from './loader';
2
+ export * from './consts';
3
+ export * from '@kotori-bot/logger';
package/lib/index.js CHANGED
@@ -1,14 +1,26 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
2
  /*
7
3
  * @Author: Hotaru biyuehuya@gmail.com
8
4
  * @Blog: https://hotaru.icu
9
5
  * @Date: 2023-10-29 16:20:51
10
6
  * @LastEditors: Hotaru biyuehuya@gmail.com
11
- * @LastEditTime: 2023-12-30 17:32:51
7
+ * @LastEditTime: 2024-02-20 20:20:54
12
8
  */
13
- const loader_1 = __importDefault(require("./loader"));
14
- exports.default = loader_1.default;
9
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ var desc = Object.getOwnPropertyDescriptor(m, k);
12
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
13
+ desc = { enumerable: true, get: function() { return m[k]; } };
14
+ }
15
+ Object.defineProperty(o, k2, desc);
16
+ }) : (function(o, m, k, k2) {
17
+ if (k2 === undefined) k2 = k;
18
+ o[k2] = m[k];
19
+ }));
20
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
21
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
22
+ };
23
+ Object.defineProperty(exports, "__esModule", { value: true });
24
+ __exportStar(require("./loader"), exports);
25
+ __exportStar(require("./consts"), exports);
26
+ __exportStar(require("@kotori-bot/logger"), exports);
package/lib/loader.d.ts CHANGED
@@ -1,13 +1,40 @@
1
- import { ContextInstance } from '@kotori-bot/core';
2
- declare class Main extends ContextInstance {
1
+ import { Container, Symbols } from '@kotori-bot/core';
2
+ import Logger from '@kotori-bot/logger';
3
+ import Runner from './runner';
4
+ import Server from './service/server';
5
+ import Database from './service/database';
6
+ import File from './service/file';
7
+ declare module '@kotori-bot/core' {
8
+ interface Context {
9
+ readonly baseDir: Runner['baseDir'];
10
+ readonly options: Runner['options'];
11
+ readonly [Symbols.modules]: Runner[typeof Symbols.modules];
12
+ loadAll(): void;
13
+ watcher(): void;
14
+ logger: Logger;
15
+ server: Server;
16
+ db: Database;
17
+ file: File;
18
+ }
19
+ interface GlobalConfig {
20
+ dirs: string[];
21
+ port: number;
22
+ }
23
+ }
24
+ export declare class Loader extends Container {
3
25
  private ctx;
4
- constructor();
26
+ private loadCount;
27
+ constructor(options?: {
28
+ dir?: string;
29
+ mode?: string;
30
+ });
5
31
  run(): void;
6
32
  private handleError;
7
33
  private catchError;
8
34
  private listenMessage;
9
- private loadAllModule;
35
+ private setPreService;
36
+ private loadAllModules;
10
37
  private loadAllAdapter;
11
38
  private checkUpdate;
12
39
  }
13
- export default Main;
40
+ export default Loader;
package/lib/loader.js CHANGED
@@ -1,130 +1,262 @@
1
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 (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
2
25
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
26
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
27
  };
5
28
  Object.defineProperty(exports, "__esModule", { value: true });
29
+ exports.Loader = void 0;
6
30
  /*
7
31
  * @Author: hotaru biyuehuya@gmail.com
8
32
  * @Blog: https://hotaru.icu
9
33
  * @Date: 2023-06-24 15:12:55
10
34
  * @LastEditors: Hotaru biyuehuya@gmail.com
11
- * @LastEditTime: 2023-12-30 19:12:43
35
+ * @LastEditTime: 2024-02-21 11:35:04
12
36
  */
13
37
  const core_1 = require("@kotori-bot/core");
14
- const modules_1 = __importDefault(require("./modules"));
15
- const global_1 = require("./global");
38
+ const path_1 = __importDefault(require("path"));
39
+ const fs_1 = __importDefault(require("fs"));
40
+ const logger_1 = __importDefault(require("@kotori-bot/logger"));
41
+ const runner_1 = __importStar(require("./runner"));
16
42
  const log_1 = __importDefault(require("./log"));
17
- const kotoriConfig = () => {
18
- let result = {};
19
- const baseDir = (0, global_1.getBaseDir)();
20
- result = {
21
- baseDir,
22
- config: (0, global_1.getGlobalConfig)(baseDir),
23
- options: {
24
- env: (0, global_1.isDev)() ? 'dev' : 'build',
25
- },
43
+ const consts_1 = require("./consts");
44
+ const server_1 = __importDefault(require("./service/server"));
45
+ const database_1 = __importDefault(require("./service/database"));
46
+ const file_1 = __importDefault(require("./service/file"));
47
+ function getRunnerConfig(file, dir) {
48
+ const handle = (root) => {
49
+ const baseDir = {
50
+ root,
51
+ modules: path_1.default.join(root, 'modules'),
52
+ data: path_1.default.join(root, 'data'),
53
+ logs: path_1.default.join(root, 'logs')
54
+ };
55
+ Object.values(baseDir).forEach((val) => {
56
+ if (!fs_1.default.existsSync(val))
57
+ fs_1.default.mkdirSync(val);
58
+ });
59
+ return baseDir;
26
60
  };
27
- return result;
28
- };
29
- class Main extends core_1.ContextInstance {
61
+ const options = {
62
+ mode: file === consts_1.DEV_CONFIG_NAME ? 'dev' : 'build'
63
+ };
64
+ if (dir)
65
+ return { baseDir: handle(path_1.default.resolve(dir)), options };
66
+ let root = path_1.default.resolve(__dirname, '..').replace('loader', 'kotori');
67
+ let count = 0;
68
+ while (!fs_1.default.existsSync(path_1.default.join(root, file))) {
69
+ if (count > 5) {
70
+ logger_1.default.fatal(`cannot find file ${file} `);
71
+ process.exit();
72
+ }
73
+ root = path_1.default.join(root, '..');
74
+ count += 1;
75
+ }
76
+ return { baseDir: handle(root), options };
77
+ }
78
+ /* eslint consistent-return: 0 */
79
+ function getCoreConfig(file, baseDir) {
80
+ try {
81
+ const result1 = core_1.Tsu.Object({
82
+ global: core_1.Tsu.Object({
83
+ dirs: core_1.Tsu.Array(core_1.Tsu.String()).default([]),
84
+ port: core_1.Tsu.Number().default(core_1.DEFAULT_PORT),
85
+ lang: runner_1.localeTypeSchema.default(core_1.DEFAULT_CORE_CONFIG.global.lang),
86
+ 'command-prefix': core_1.Tsu.String().default(core_1.DEFAULT_CORE_CONFIG.global['command-prefix'])
87
+ }),
88
+ plugin: core_1.Tsu.Object({})
89
+ .index(core_1.Tsu.Object({
90
+ filter: core_1.Tsu.Object({}).default({})
91
+ }).default({ filter: {} }))
92
+ .default(core_1.DEFAULT_CORE_CONFIG.plugin)
93
+ })
94
+ .default({ global: Object.assign(core_1.DEFAULT_CORE_CONFIG.global), plugin: core_1.DEFAULT_CORE_CONFIG.plugin })
95
+ .parse((0, core_1.loadConfig)(path_1.default.join(baseDir.root, file), 'yaml'));
96
+ return core_1.Tsu.Object({
97
+ adapter: core_1.Tsu.Object({})
98
+ .index(core_1.Tsu.Object({
99
+ extends: core_1.Tsu.String(),
100
+ master: core_1.Tsu.Union([core_1.Tsu.Number(), core_1.Tsu.String()]),
101
+ lang: runner_1.localeTypeSchema.default(result1.global.lang),
102
+ 'command-prefix': core_1.Tsu.String().default(result1.global['command-prefix'])
103
+ }))
104
+ .default(core_1.DEFAULT_CORE_CONFIG.adapter)
105
+ }).parse(result1);
106
+ }
107
+ catch (err) {
108
+ if (!(err instanceof core_1.TsuError))
109
+ throw err;
110
+ logger_1.default.fatal(`file ${file} format error: ${err.message}`);
111
+ process.exit();
112
+ }
113
+ }
114
+ class Loader extends core_1.Container {
30
115
  ctx;
31
- constructor() {
116
+ loadCount = 0;
117
+ constructor(options) {
32
118
  super();
33
- core_1.ContextInstance.setInstance(new modules_1.default(kotoriConfig()));
34
- this.ctx = core_1.ContextInstance.getInstance();
35
- // 静态类型继续居然她妈是隔离的
119
+ const file = options && options.mode === 'dev' ? consts_1.DEV_CONFIG_NAME : consts_1.BUILD_CONFIG_NAME;
120
+ const runnerConfig = getRunnerConfig(file, options?.dir);
121
+ const ctx = new core_1.Core(getCoreConfig(file, runnerConfig.baseDir));
122
+ ctx.provide('runner', new runner_1.default(ctx, runnerConfig));
123
+ ctx.mixin('runner', ['baseDir', 'options']);
124
+ core_1.Container.setInstance(ctx);
125
+ this.ctx = core_1.Container.getInstance();
36
126
  }
37
127
  run() {
38
- (0, log_1.default)(this.ctx.package, this.ctx);
128
+ (0, log_1.default)(this.ctx.pkg, this.ctx);
39
129
  this.catchError();
40
130
  this.listenMessage();
41
- this.loadAllModule();
131
+ this.setPreService();
132
+ this.loadAllModules();
42
133
  this.checkUpdate();
43
134
  }
44
135
  handleError(err, prefix) {
45
- const isKotoriError = err instanceof core_1.KotoriError;
46
- if (!isKotoriError) {
47
- this.ctx.logger.tag(prefix, 'default', prefix === 'UCE' ? 'cyanBG' : 'greenBG').error(err);
136
+ if (!(err instanceof core_1.KotoriError)) {
137
+ if (err instanceof Error) {
138
+ this.ctx.logger.label(prefix).error(err.message, err.stack);
139
+ }
140
+ else {
141
+ this.ctx.logger.label(prefix).error(err);
142
+ }
48
143
  return;
49
144
  }
50
- this.ctx.logger
51
- .tag(err.name.split('Error')[0].toUpperCase(), 'yellow', 'default')[err.level === 'normal' ? 'error' : err.level](err.message, err.stack);
52
- if (err.name !== 'CoreError')
53
- return;
54
- this.ctx.logger.tag('CORE', 'black', 'red').error(err.message);
55
- process.emit('SIGINT');
145
+ const list = {
146
+ ServiceError: () => this.ctx.logger.label('service').warn,
147
+ ModuleError: () => this.ctx.logger.label('module').error,
148
+ UnknownError: () => this.ctx.logger.error,
149
+ DevError: () => this.ctx.logger.label('error').debug
150
+ };
151
+ list[err.name]().bind(this.ctx.logger)(err.message, err.stack);
56
152
  }
57
153
  catchError() {
58
- process.on('uncaughtExceptionMonitor', err => this.handleError(err, 'UCE'));
59
- process.on('unhandledRejection', err => this.handleError(err, 'UHR'));
60
- process.on('SIGINT', () => {
61
- process.exit();
62
- });
63
- this.ctx.logger.debug('Run info: develop with debuing...');
154
+ process.on('uncaughtExceptionMonitor', (err) => this.handleError(err, 'sync'));
155
+ process.on('unhandledRejection', (err) => this.handleError(err, 'async'));
156
+ process.on('SIGINT', () => process.exit());
157
+ this.ctx.logger.debug('run info: develop with debuing...');
64
158
  }
65
159
  listenMessage() {
66
- const handleConnectInfo = (data) => {
67
- if (!data.info)
160
+ this.ctx.on('connect', (data) => {
161
+ const { type, mode, normal, address, adapter } = data;
162
+ let msg;
163
+ if (type === 'connect') {
164
+ switch (mode) {
165
+ case 'ws':
166
+ msg = `${normal ? 'Connect' : 'Reconnect'} server to ${address}`;
167
+ break;
168
+ case 'ws-reverse':
169
+ msg = `server ${normal ? 'start' : 'restart'} at ${address}`;
170
+ break;
171
+ default:
172
+ msg = `ready completed about ${address}`;
173
+ }
174
+ }
175
+ else {
176
+ switch (mode) {
177
+ case 'ws':
178
+ msg = `disconnect server from ${address}${normal ? '' : ' unexpectedly'}`;
179
+ break;
180
+ case 'ws-reverse':
181
+ msg = `server stop at ${address}${normal ? '' : ' unexpectedly'}`;
182
+ break;
183
+ default:
184
+ msg = `dispose completed about ${address}`;
185
+ }
186
+ }
187
+ adapter.ctx.logger[normal ? 'info' : 'warn'](msg);
188
+ });
189
+ this.ctx.on('status', (data) => {
190
+ const { status, adapter } = data;
191
+ adapter.ctx.logger.info(status);
192
+ });
193
+ this.ctx.on('ready_module', (data) => {
194
+ if (typeof data.instance !== 'object')
68
195
  return;
69
- this.ctx.logger[data.normal ? 'log' : 'warn'](`[${data.adapter.platform}]`, `${data.adapter.identity}:`, data.info);
70
- };
71
- this.ctx.on('connect', handleConnectInfo);
72
- this.ctx.on('disconnect', handleConnectInfo);
73
- this.ctx.on('load_module', data => {
74
- if (!data.module)
196
+ const pkg = data.instance.name
197
+ ? this.ctx.get('runner')[core_1.Symbols.modules].get(data.instance.name)
198
+ : undefined;
199
+ if (!pkg)
75
200
  return;
76
- const { name, version, author } = data.module.package;
77
- this.ctx.logger.info(`Loaded ${data.moduleType} ${name} Version: ${version} ${Array.isArray(author) ? `Authors: ${author.join(',')}` : `Author: ${author}`}`);
78
- });
79
- this.ctx.on('load_all_module', data => {
80
- const failed = data.expected - data.reality;
81
- this.ctx.logger.info(`Loaded ${data.reality} modules (plugins)${failed > 0 ? `, failed to load ${failed} modules` : ''}`);
82
- this.loadAllAdapter();
201
+ this.loadCount += 1;
202
+ const { name, version, author, peerDependencies } = pkg[0].pkg;
203
+ this.ctx.logger.info(`loaded module ${name} version: ${version} ${Array.isArray(author) ? `authors: ${author.join(',')}` : `author: ${author}`}`);
204
+ const requiredVersion = peerDependencies['kotori-bot'];
205
+ if (!requiredVersion.includes('workspace') &&
206
+ (!consts_1.SUPPORTS_VERSION.exec(requiredVersion) || requiredVersion !== this.ctx.pkg.version)) {
207
+ if (consts_1.SUPPORTS_HALF_VERSION.exec(requiredVersion)) {
208
+ this.ctx.logger.warn(`incomplete supported module version: ${requiredVersion}`);
209
+ }
210
+ else {
211
+ this.ctx.logger.error(`unsupported module version: ${requiredVersion}`);
212
+ }
213
+ }
83
214
  });
84
215
  }
85
- loadAllModule() {
86
- this.ctx.moduleAll();
87
- if ((0, global_1.isDev)())
88
- this.ctx.watchFile();
216
+ setPreService() {
217
+ this.ctx.service('server', new server_1.default(this.ctx.extends(), { port: this.ctx.config.global.port }));
218
+ this.ctx.service('db', new database_1.default(this.ctx.extends()));
219
+ this.ctx.service('file', new file_1.default(this.ctx.extends()));
220
+ }
221
+ loadAllModules() {
222
+ this.ctx.get('runner').loadAll();
223
+ const failLoadCount = this.ctx.get('runner')[core_1.Symbols.modules].size - this.loadCount;
224
+ this.ctx.logger.info(`loaded ${this.loadCount} modules successfully${failLoadCount > 0 ? `, failed to load ${failLoadCount} modules` : ''} `);
225
+ this.loadAllAdapter();
226
+ this.ctx.emit('ready');
89
227
  }
90
228
  loadAllAdapter() {
91
- const adapters = this.ctx.internal.getAdapters();
92
- Object.keys(this.ctx.config.adapter).forEach(botName => {
229
+ const adapters = this.ctx[core_1.Symbols.adapter];
230
+ Object.keys(this.ctx.config.adapter).forEach((botName) => {
93
231
  const botConfig = this.ctx.config.adapter[botName];
94
- if (!(botConfig.extends in adapters)) {
95
- this.ctx.logger.warn(`Cannot find adapter '${botConfig.extends}' for ${botName}`);
96
- return;
97
- }
98
- const array = adapters[botConfig.extends];
99
- const isSchema = array[1]?.parseSafe(botConfig);
100
- if (isSchema && !isSchema.value) {
232
+ const array = adapters.get(botConfig.extends);
233
+ if (!array) {
234
+ this.ctx.logger.warn(`cannot find adapter '${botConfig.extends}' for ${botName}`);
101
235
  return;
102
236
  }
103
- const bot = new array[0](this.ctx, isSchema ? isSchema.data : botConfig, botName);
104
- // if (!(botConfig.extend in Adapter)) Adapter.apis[botConfig.extend] = []; // I dont know whats this
105
- // this.ctx.botStack[botConfig.extend].push(bot.api);
106
- bot.start();
107
- }); /*
108
- const adapters: Adapter[] = [];
109
- Object.values(this.ctx.botStack).forEach(apis => {
110
- apis.forEach(api => adapters.push(api.adapter));
111
- }); */
112
- // this.ctx.emit({ type: 'adapters', adapters });
237
+ const result = array[1]?.parseSafe(botConfig);
238
+ if (result && !result.value)
239
+ throw new core_1.ModuleError(`Config format of adapter ${botName} is error: ${result.error.message}`);
240
+ const bot = new array[0](this.ctx.extends({}, `${botConfig.extends}/${botName}`), result ? result.data : botConfig, botName);
241
+ this.ctx.on('ready', () => bot.start());
242
+ this.ctx.on('dispose', () => bot.stop());
243
+ });
113
244
  }
114
245
  async checkUpdate() {
115
- const { version } = this.ctx.package;
246
+ const { version } = this.ctx.pkg;
116
247
  const res = await this.ctx.http
117
- .get('https://hotaru.icu/api/agent/?url=https://raw.githubusercontent.com/kotorijs/kotori/master/packages/kotori/package.json')
118
- .catch(() => this.ctx.logger.error('Get update failed, please check your network'));
248
+ .get("https://hotaru.icu/api/agent/?url=https://raw.githubusercontent.com/kotorijs/kotori/master/packages/kotori/package.json" /* GLOBAL.UPDATE */)
249
+ .catch(() => this.ctx.logger.error('get update failed, please check your network'));
119
250
  if (!res || !core_1.Tsu.Object({ version: core_1.Tsu.String() }).check(res)) {
120
- this.ctx.logger.error(`Detection update failed`);
251
+ this.ctx.logger.warn(`detection update failed`);
121
252
  }
122
253
  else if (version === res.version) {
123
- this.ctx.logger.log('Kotori is currently the latest version');
254
+ this.ctx.logger.info('kotori is currently the latest version');
124
255
  }
125
256
  else {
126
- this.ctx.logger.warn(`The current version of Kotori is ${version}, and the latest version is ${res.version}. Please go to ${"https://github.com/kotorijs/kotori" /* GLOBAL.REPO */} to update`);
257
+ this.ctx.logger.warn(`the current version of Kotori is ${version}, and the latest version is ${res.version}. please go to ${"https://github.com/kotorijs/kotori" /* GLOBAL.REPO */} to update`);
127
258
  }
128
259
  }
129
260
  }
130
- exports.default = Main;
261
+ exports.Loader = Loader;
262
+ exports.default = Loader;
package/lib/log.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- import type { Context, PackageInfo } from '@kotori-bot/core';
2
- export declare function loadInfo(info: PackageInfo, ctx: Context): void;
1
+ import type { Context } from '@kotori-bot/core';
2
+ export declare function loadInfo(info: Context['pkg'], ctx: Context): void;
3
3
  export default loadInfo;
package/lib/log.js CHANGED
@@ -2,18 +2,19 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.loadInfo = void 0;
4
4
  function loadInfo(info, ctx) {
5
- console.info('Kotori Bot is loading...');
6
- console.info(`
7
- ██╗ ██╗ ██████╗ ████████╗ ██████╗ ██████╗ ██╗
8
- ██║ ██╔╝██╔═══██╗╚══██╔══╝██╔═══██╗██╔══██╗██║
9
- █████╔╝ ██║ ██║ ██║ ██║ ██║██████╔╝██║
10
- ██╔═██╗ ██║ ██║ ██║ ██║ ██║██╔══██╗██║
11
- ██║ ██╗╚██████╔╝ ██║ ╚██████╔╝██║ ██║██║
12
- ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝╚═╝
5
+ process.stdout.write('Kotori Bot is loading...');
6
+ process.stdout.write(`
7
+ ██╗ ██╗ ██████╗ ████████╗ ██████╗ ██████╗ ██╗
8
+ ██║ ██╔╝██╔═══██╗╚══██╔══╝██╔═══██╗██╔══██╗██║
9
+ █████╔╝ ██║ ██║ ██║ ██║ ██║██████╔╝██║
10
+ ██╔═██╗ ██║ ██║ ██║ ██║ ██║██╔══██╗██║
11
+ ██║ ██╗╚██████╔╝ ██║ ╚██████╔╝██║ ██║██║
12
+ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝╚═╝
13
13
  `);
14
+ ctx.logger.info('loader base dir:', ctx.baseDir.root);
14
15
  ctx.logger.info(`Kotori Bot Version: ${info.version} License: ${info.license}`);
15
16
  ctx.logger.info(`Kotori Bot By ${info.author}`);
16
- ctx.logger.info(`Copyright © 2023 ${info.author} All rights reserved.`);
17
+ ctx.logger.info(`Copyright © 2023 - 2024 ${info.author} All rights reserved`);
17
18
  }
18
19
  exports.loadInfo = loadInfo;
19
20
  exports.default = loadInfo;
@@ -0,0 +1,55 @@
1
+ import { Context, LocaleType, ModuleConfig, Symbols } from '@kotori-bot/core';
2
+ interface BaseDir {
3
+ root: string;
4
+ modules: string;
5
+ data: string;
6
+ logs: string;
7
+ }
8
+ interface Options {
9
+ mode: 'dev' | 'build';
10
+ }
11
+ interface RunnerConfig {
12
+ baseDir: BaseDir;
13
+ options: Options;
14
+ }
15
+ interface ModulePackage {
16
+ name: string;
17
+ version: string;
18
+ description: string;
19
+ main: string;
20
+ keywords: string[];
21
+ license: 'GPL-3.0';
22
+ author: string | string[];
23
+ peerDependencies: {
24
+ 'kotori-bot': string;
25
+ [propName: string]: string;
26
+ };
27
+ kotori: {
28
+ enforce?: 'pre' | 'post';
29
+ meta: {
30
+ language: LocaleType[];
31
+ };
32
+ };
33
+ }
34
+ interface ModuleMeta {
35
+ pkg: ModulePackage;
36
+ files: string[];
37
+ main: string;
38
+ }
39
+ export declare const localeTypeSchema: import("@kotori-bot/core").UnionParser<[import("@kotori-bot/core").UnionParser<[import("@kotori-bot/core").LiteralParser<"en_US">, import("@kotori-bot/core").LiteralParser<"ja_JP">]>, import("@kotori-bot/core").UnionParser<[import("@kotori-bot/core").LiteralParser<"zh_TW">, import("@kotori-bot/core").AnyParser<any>]>]>;
40
+ export declare class Runner {
41
+ readonly baseDir: BaseDir;
42
+ readonly options: Options;
43
+ private ctx;
44
+ private isDev;
45
+ readonly [Symbols.modules]: Map<string, [ModuleMeta, ModuleConfig]>;
46
+ constructor(ctx: Context, config: RunnerConfig);
47
+ private getDirFiles;
48
+ private getModuleRootDir;
49
+ private getModuleList;
50
+ private loadEx;
51
+ private unloadEx;
52
+ loadAll(): void;
53
+ watcher(): void;
54
+ }
55
+ export default Runner;
package/lib/runner.js ADDED
@@ -0,0 +1,205 @@
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 (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __importDefault = (this && this.__importDefault) || function (mod) {
26
+ return (mod && mod.__esModule) ? mod : { "default": mod };
27
+ };
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ exports.Runner = exports.localeTypeSchema = void 0;
30
+ const fs_1 = __importStar(require("fs"));
31
+ const path_1 = __importDefault(require("path"));
32
+ const core_1 = require("@kotori-bot/core");
33
+ const logger_1 = require("@kotori-bot/logger");
34
+ const consts_1 = require("./consts");
35
+ const logger_2 = __importDefault(require("./utils/logger"));
36
+ exports.localeTypeSchema = core_1.Tsu.Union([
37
+ core_1.Tsu.Union([core_1.Tsu.Literal('en_US'), core_1.Tsu.Literal('ja_JP')]),
38
+ core_1.Tsu.Union([core_1.Tsu.Literal('zh_TW'), core_1.Tsu.Any()])
39
+ ]);
40
+ const modulePackageSchema = core_1.Tsu.Object({
41
+ name: core_1.Tsu.String().regexp(/kotori-plugin-[a-z]([a-z,0-9]{2,13})\b/),
42
+ version: core_1.Tsu.String(),
43
+ description: core_1.Tsu.String(),
44
+ main: core_1.Tsu.String(),
45
+ license: core_1.Tsu.Literal('GPL-3.0'),
46
+ keywords: core_1.Tsu.Custom((val) => Array.isArray(val) && val.includes('kotori') && val.includes('chatbot') && val.includes('kotori-plugin')),
47
+ author: core_1.Tsu.Union([core_1.Tsu.String(), core_1.Tsu.Array(core_1.Tsu.String())]),
48
+ peerDependencies: core_1.Tsu.Object({
49
+ 'kotori-bot': core_1.Tsu.String()
50
+ }),
51
+ kotori: core_1.Tsu.Object({
52
+ enforce: core_1.Tsu.Union([core_1.Tsu.Literal('pre'), core_1.Tsu.Literal('post')]).optional(),
53
+ meta: core_1.Tsu.Object({
54
+ language: core_1.Tsu.Array(exports.localeTypeSchema).default([])
55
+ }).default({ language: [] })
56
+ }).default({
57
+ enforce: undefined,
58
+ meta: { language: [] }
59
+ })
60
+ });
61
+ function moduleLoadOrder(pkg) {
62
+ if (pkg.name.includes(core_1.DATABASE_PREFIX))
63
+ return 1;
64
+ if (pkg.name.includes(core_1.ADAPTER_PREFIX))
65
+ return 2;
66
+ // if (CORE_MODULES.includes(pkg.name)) return 3;
67
+ if (pkg.kotori.enforce === 'pre')
68
+ return 4;
69
+ if (!pkg.kotori.enforce)
70
+ return 5;
71
+ return 6;
72
+ }
73
+ class Runner {
74
+ baseDir;
75
+ options;
76
+ ctx;
77
+ isDev;
78
+ [core_1.Symbols.modules] = new Map();
79
+ constructor(ctx, config) {
80
+ this.ctx = ctx;
81
+ /* handle config */
82
+ this.baseDir = config.baseDir;
83
+ this.options = config.options;
84
+ this.isDev = this.options.mode === 'dev';
85
+ const loggerOptions = {
86
+ level: this.isDev ? logger_1.LoggerLevel.TRACE : logger_1.LoggerLevel.INFO,
87
+ label: [],
88
+ transports: [
89
+ new logger_1.ConsoleTransport(),
90
+ new logger_1.FileTransport({ dir: this.baseDir.logs, filter: (data) => data.level >= logger_1.LoggerLevel.WARN })
91
+ ]
92
+ };
93
+ ctx.provide('logger', new logger_2.default(loggerOptions, this.ctx));
94
+ ctx.inject('logger');
95
+ }
96
+ getDirFiles(rootDir) {
97
+ const files = fs_1.default.readdirSync(rootDir);
98
+ const list = [];
99
+ files.forEach((fileName) => {
100
+ const file = path_1.default.join(rootDir, fileName);
101
+ if (fs_1.default.statSync(file).isDirectory()) {
102
+ list.push(...this.getDirFiles(file));
103
+ }
104
+ if (path_1.default.parse(file).ext !== (this.isDev ? consts_1.DEV_FILE : consts_1.BUILD_FILE))
105
+ return;
106
+ list.push(path_1.default.resolve(file));
107
+ });
108
+ return list;
109
+ }
110
+ getModuleRootDir() {
111
+ const moduleRootDir = [];
112
+ [
113
+ ...this.ctx.config.global.dirs.map((dir) => path_1.default.resolve(this.ctx.baseDir.root, dir)),
114
+ this.ctx.baseDir.modules
115
+ ].forEach((dir) => {
116
+ if (fs_1.default.existsSync(dir) && fs_1.default.statSync(dir).isDirectory())
117
+ moduleRootDir.push(dir);
118
+ });
119
+ return moduleRootDir;
120
+ }
121
+ getModuleList(rootDir) {
122
+ fs_1.default.readdirSync(rootDir).forEach(async (fileName) => {
123
+ const dir = path_1.default.join(rootDir, fileName);
124
+ if (!fs_1.default.statSync(dir).isDirectory())
125
+ return;
126
+ if (rootDir !== this.ctx.baseDir.modules && !fileName.startsWith(core_1.PLUGIN_PREFIX))
127
+ return;
128
+ const packagePath = path_1.default.join(dir, 'package.json');
129
+ let pkg;
130
+ if (!fs_1.default.existsSync(packagePath))
131
+ return;
132
+ try {
133
+ pkg = JSON.parse(fs_1.default.readFileSync(packagePath).toString());
134
+ }
135
+ catch {
136
+ throw new core_1.DevError(`illegal package.json ${packagePath}`);
137
+ }
138
+ const result = modulePackageSchema.parseSafe(pkg);
139
+ if (!result.value) {
140
+ if (rootDir !== this.ctx.baseDir.modules)
141
+ return;
142
+ throw new core_1.DevError(`package.json format error ${packagePath}: ${result.error.message}`);
143
+ }
144
+ pkg = result.data;
145
+ const devMode = this.isDev && (0, fs_1.existsSync)(path_1.default.resolve(dir, consts_1.DEV_IMPORT));
146
+ const main = path_1.default.resolve(dir, devMode ? consts_1.DEV_IMPORT : pkg.main);
147
+ if (!fs_1.default.existsSync(main))
148
+ throw new core_1.DevError(`cannot find ${main}`);
149
+ const dirs = path_1.default.join(dir, devMode ? consts_1.DEV_CODE_DIRS : path_1.default.dirname(pkg.main));
150
+ const files = fs_1.default.statSync(dirs).isDirectory() ? this.getDirFiles(dirs) : [];
151
+ this[core_1.Symbols.modules].set(pkg.name, [
152
+ { pkg, files, main },
153
+ this.ctx.config.plugin[(0, core_1.stringRightSplit)(pkg.name, core_1.PLUGIN_PREFIX)] || {}
154
+ ]);
155
+ });
156
+ }
157
+ loadEx(instance, config) {
158
+ const { main, pkg } = instance;
159
+ /* eslint-disable-next-line import/no-dynamic-require, global-require, @typescript-eslint/no-var-requires */
160
+ let obj = require(main);
161
+ let handle = config;
162
+ const adapterName = pkg.name.split(core_1.ADAPTER_PREFIX)[1];
163
+ if (core_1.Adapter.isPrototypeOf.call(core_1.Adapter, obj.default) &&
164
+ adapterName &&
165
+ (!obj.config || obj.config instanceof core_1.Parser)) {
166
+ this.ctx[core_1.Symbols.adapter].set(adapterName, [obj.default, obj.config]);
167
+ obj = {};
168
+ }
169
+ else if (core_1.Service.isPrototypeOf.call(core_1.Service, obj.default)) {
170
+ obj = {};
171
+ }
172
+ else if (obj.config instanceof core_1.Parser) {
173
+ const result = obj.config.parseSafe(handle);
174
+ if (!result.value)
175
+ throw new core_1.ModuleError(`Config format of module ${pkg.name} is error: ${result.error.message}`);
176
+ handle = result.data;
177
+ }
178
+ if (obj.lang)
179
+ this.ctx.i18n.use(Array.isArray(obj.lang) ? path_1.default.resolve(...obj.lang) : path_1.default.resolve(obj.lang));
180
+ this.ctx.load({ name: pkg.name, ...obj, config: handle });
181
+ }
182
+ unloadEx(instance) {
183
+ instance.files.forEach((file) => delete require.cache[require.resolve(file)]);
184
+ this.ctx.load({ name: instance.pkg.name });
185
+ }
186
+ loadAll() {
187
+ this.getModuleRootDir().forEach((dir) => this.getModuleList(dir));
188
+ const modules = [];
189
+ this[core_1.Symbols.modules].forEach((val) => modules.push(val));
190
+ modules
191
+ .sort((el1, el2) => moduleLoadOrder(el1[0].pkg) - moduleLoadOrder(el2[0].pkg))
192
+ .forEach((el) => this.loadEx(...el));
193
+ if (this.isDev)
194
+ this.watcher();
195
+ }
196
+ watcher() {
197
+ this[core_1.Symbols.modules].forEach((data) => data[0].files.forEach((file) => fs_1.default.watchFile(file, async () => {
198
+ this.ctx.logger.debug(`file happen changed, module ${data[0].pkg.name} is reloading...`);
199
+ this.unloadEx(data[0]);
200
+ this.loadEx(...data);
201
+ })));
202
+ }
203
+ }
204
+ exports.Runner = Runner;
205
+ exports.default = Runner;
@@ -0,0 +1,12 @@
1
+ import { Context, Service } from '@kotori-bot/core';
2
+ import knex from 'knex';
3
+ export declare class Database extends Service {
4
+ internal: ReturnType<typeof knex>;
5
+ select: ReturnType<typeof knex>['select'];
6
+ delete: ReturnType<typeof knex>['delete'];
7
+ update: ReturnType<typeof knex>['update'];
8
+ insert: ReturnType<typeof knex>['insert'];
9
+ schema: ReturnType<typeof knex>['schema'];
10
+ constructor(ctx: Context);
11
+ }
12
+ export default Database;
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.Database = void 0;
7
+ const core_1 = require("@kotori-bot/core");
8
+ const knex_1 = __importDefault(require("knex"));
9
+ const path_1 = require("path");
10
+ class Database extends core_1.Service {
11
+ internal;
12
+ select;
13
+ delete;
14
+ update;
15
+ insert;
16
+ schema;
17
+ constructor(ctx) {
18
+ super(ctx, {}, 'database');
19
+ this.internal = (0, knex_1.default)({
20
+ client: 'sqlite',
21
+ connection: {
22
+ filename: (0, path_1.resolve)(this.ctx.baseDir.root, 'kotori.db')
23
+ },
24
+ useNullAsDefault: true
25
+ } /* {
26
+ client: 'mysql',
27
+ connection: {
28
+ host: '127.0.0.1',
29
+ port: 3306,
30
+ user: 'kotori',
31
+ password: 'kotori',
32
+ database: 'kotori'
33
+ }
34
+ } */);
35
+ this.select = this.internal.select.bind(this.internal);
36
+ this.delete = this.internal.delete.bind(this.internal);
37
+ this.update = this.internal.update.bind(this.internal);
38
+ this.insert = this.internal.insert.bind(this.internal);
39
+ this.schema = this.internal.schema;
40
+ }
41
+ }
42
+ exports.Database = Database;
43
+ exports.default = Database;
@@ -0,0 +1,10 @@
1
+ import { Context, Service, createConfig, loadConfig, saveConfig } from '@kotori-bot/core';
2
+ export declare class File extends Service {
3
+ constructor(ctx: Context);
4
+ getDir(): string;
5
+ getFile(filename: string): string;
6
+ load(filename: string, type?: Parameters<typeof loadConfig>[1], init?: Parameters<typeof loadConfig>[2]): string | object | unknown[] | null;
7
+ save(filename: string, data: Parameters<typeof saveConfig>[1], type?: Parameters<typeof saveConfig>[2]): void;
8
+ create(filename: string, data?: Parameters<typeof createConfig>[1], type?: Parameters<typeof createConfig>[2]): void;
9
+ }
10
+ export default File;
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.File = void 0;
4
+ const core_1 = require("@kotori-bot/core");
5
+ const path_1 = require("path");
6
+ class File extends core_1.Service {
7
+ constructor(ctx) {
8
+ super(ctx, {}, 'file');
9
+ }
10
+ getDir() {
11
+ return (0, path_1.join)(this.ctx.baseDir.data, ...(this.ctx.identity ? this.ctx.identity.split('/') : []));
12
+ }
13
+ getFile(filename) {
14
+ return (0, path_1.join)(this.getDir(), filename);
15
+ }
16
+ load(filename, type, init) {
17
+ return (0, core_1.loadConfig)(this.getFile(filename), type, init);
18
+ }
19
+ save(filename, data, type) {
20
+ (0, core_1.saveConfig)(this.getFile(filename), data, type);
21
+ }
22
+ create(filename, data, type) {
23
+ (0, core_1.createConfig)(this.getFile(filename), data, type);
24
+ }
25
+ }
26
+ exports.File = File;
27
+ exports.default = File;
@@ -0,0 +1,26 @@
1
+ /// <reference types="body-parser" />
2
+ /// <reference types="connect" />
3
+ /// <reference types="serve-static" />
4
+ import { Context, Service } from '@kotori-bot/core';
5
+ import express from 'express';
6
+ interface ServerConfig {
7
+ port: number;
8
+ }
9
+ export declare class Server extends Service<ServerConfig> {
10
+ private app;
11
+ private server?;
12
+ constructor(ctx: Context, config: ServerConfig);
13
+ start(): void;
14
+ stop(): void;
15
+ get: Server['app']['get'];
16
+ post: Server['app']['post'];
17
+ patch: Server['app']['patch'];
18
+ put: Server['app']['put'];
19
+ delete: Server['app']['delete'];
20
+ all: Server['app']['all'];
21
+ use: Server['app']['use'];
22
+ router: typeof express.Router;
23
+ json: (options?: import("body-parser").OptionsJson | undefined) => import("connect").NextHandleFunction;
24
+ static: import("serve-static").RequestHandlerConstructor<express.Response<any, Record<string, any>>>;
25
+ }
26
+ export default Server;
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.Server = void 0;
7
+ const core_1 = require("@kotori-bot/core");
8
+ const express_1 = __importDefault(require("express"));
9
+ class Server extends core_1.Service {
10
+ app;
11
+ server;
12
+ constructor(ctx, config) {
13
+ super(ctx, config, 'server');
14
+ this.app = (0, express_1.default)();
15
+ this.app.use('/', (_, res, next) => {
16
+ let isWebui = false;
17
+ ctx[core_1.Symbols.modules].forEach((module) => {
18
+ if (isWebui)
19
+ return;
20
+ if (module[0].pkg.name === '@kotori-bot/kotori-plugin-webui')
21
+ isWebui = true;
22
+ });
23
+ if (!isWebui) {
24
+ res.setHeader('Content-type', 'text/html');
25
+ res.send(/* html */ `<h1>Welcome to kotori!</h1>`);
26
+ }
27
+ next();
28
+ });
29
+ this.get = this.app.get.bind(this.app);
30
+ this.post = this.app.post.bind(this.app);
31
+ this.patch = this.app.patch.bind(this.app);
32
+ this.put = this.app.put.bind(this.app);
33
+ this.delete = this.app.delete.bind(this.app);
34
+ this.use = this.app.use.bind(this.app);
35
+ this.all = this.app.all.bind(this.app);
36
+ }
37
+ start() {
38
+ if (this.server)
39
+ return;
40
+ this.server = this.app.listen(this.config.port);
41
+ this.ctx.logger.label('server').info(`server start at http://127.0.0.1:${this.config.port}`);
42
+ }
43
+ stop() {
44
+ if (!this.server)
45
+ return;
46
+ this.server.close();
47
+ }
48
+ get;
49
+ post;
50
+ patch;
51
+ put;
52
+ delete;
53
+ all;
54
+ use;
55
+ router = express_1.default.Router;
56
+ json = express_1.default.json;
57
+ static = express_1.default.static;
58
+ }
59
+ exports.Server = Server;
60
+ exports.default = Server;
@@ -0,0 +1,15 @@
1
+ import type { Context } from '@kotori-bot/core';
2
+ import { Logger } from '@kotori-bot/logger';
3
+ export declare class KotoriLogger extends Logger {
4
+ private optionsSelf;
5
+ private ctx;
6
+ constructor(optionsSelf: Logger['options'], ctx: Context);
7
+ private setLabel;
8
+ fatal(...args: unknown[]): void;
9
+ error(...args: unknown[]): void;
10
+ warn(...args: unknown[]): void;
11
+ info(...args: unknown[]): void;
12
+ debug(...args: unknown[]): void;
13
+ trace(...args: unknown[]): void;
14
+ }
15
+ export default KotoriLogger;
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.KotoriLogger = void 0;
4
+ const logger_1 = require("@kotori-bot/logger");
5
+ class KotoriLogger extends logger_1.Logger {
6
+ optionsSelf;
7
+ ctx;
8
+ constructor(optionsSelf, ctx) {
9
+ super(optionsSelf);
10
+ this.optionsSelf = optionsSelf;
11
+ this.ctx = ctx;
12
+ }
13
+ setLabel() {
14
+ const origin = Object.create(this.optionsSelf.label);
15
+ const label = this.ctx.identity ? [this.ctx.identity, ...this.optionsSelf.label] : this.optionsSelf.label;
16
+ this[(() => 'options')()].label = label;
17
+ return () => {
18
+ this[(() => 'options')()].label = origin;
19
+ };
20
+ }
21
+ fatal(...args) {
22
+ const dispose = this.setLabel();
23
+ super.fatal(...args);
24
+ dispose();
25
+ }
26
+ error(...args) {
27
+ const dispose = this.setLabel();
28
+ super.error(...args);
29
+ dispose();
30
+ }
31
+ warn(...args) {
32
+ const dispose = this.setLabel();
33
+ super.warn(...args);
34
+ dispose();
35
+ }
36
+ info(...args) {
37
+ const dispose = this.setLabel();
38
+ super.info(...args);
39
+ dispose();
40
+ }
41
+ debug(...args) {
42
+ const dispose = this.setLabel();
43
+ super.debug(...args);
44
+ dispose();
45
+ }
46
+ trace(...args) {
47
+ const dispose = this.setLabel();
48
+ super.trace(...args);
49
+ dispose();
50
+ }
51
+ }
52
+ exports.KotoriLogger = KotoriLogger;
53
+ exports.default = KotoriLogger;
package/package.json CHANGED
@@ -1,18 +1,40 @@
1
1
  {
2
2
  "name": "@kotori-bot/loader",
3
- "version": "v1.2.0",
3
+ "version": "1.4.0",
4
4
  "description": "Loader For KotoriBot",
5
5
  "license": "GPL-3.0",
6
6
  "main": "lib/index.js",
7
7
  "author": "Hotaru <biyuehuya@gmail.com>",
8
- "dependencies": {
9
- "@kotori-bot/core": "^v1.1.0"
10
- },
8
+ "keywords": [
9
+ "kotori",
10
+ "chatbot",
11
+ "loader"
12
+ ],
11
13
  "files": [
12
- "lib"
14
+ "lib",
15
+ "LICENSE",
16
+ "README.md"
13
17
  ],
18
+ "bugs": {
19
+ "url": "https://github.com/kotorijs/kotori/issues"
20
+ },
21
+ "repository": {
22
+ "type": "git",
23
+ "url": "git+https://github.com/kotorijs/kotori.git"
24
+ },
25
+ "homepage": "https://kotori.js.org",
26
+ "dependencies": {
27
+ "express": "^4.18.2",
28
+ "knex": "^3.1.0",
29
+ "sqlite3": "^5.1.7",
30
+ "@kotori-bot/logger": "^1.1.1",
31
+ "@kotori-bot/core": "^1.3.0"
32
+ },
14
33
  "devDependencies": {
15
- "ts-node": "^10.9.2",
16
- "typescript": "^5.1.3"
34
+ "@types/body-parser": "^1.19.5",
35
+ "@types/connect": "^3.4.38",
36
+ "@types/express": "^4.17.21",
37
+ "@types/express-serve-static-core": "^4.17.43",
38
+ "@types/serve-static": "^1.15.5"
17
39
  }
18
40
  }
package/lib/global.d.ts DELETED
@@ -1,25 +0,0 @@
1
- import { BaseDir } from '@kotori-bot/core';
2
- export declare const isDev: () => boolean;
3
- export declare const CONFIG_FILE: () => "kotori.dev.yml" | "kotori.yml";
4
- export declare const getBaseDir: () => {
5
- root: any;
6
- modules: string;
7
- };
8
- export declare const getGlobalConfig: (baseDir: BaseDir) => import("@kotori-bot/core").ObjectParserInfer<{
9
- global: import("@kotori-bot/core").IntersectionParser<[import("@kotori-bot/core").ObjectParser<{
10
- dirs: import("@kotori-bot/core").ArrayParser<import("@kotori-bot/core").StringParser>;
11
- }>, import("@kotori-bot/core").ObjectParser<{
12
- lang: import("@kotori-bot/core").UnionParser<[import("@kotori-bot/core").UnionParser<[import("@kotori-bot/core").LiteralParser<"en_US">, import("@kotori-bot/core").LiteralParser<"ja_JP">]>, import("@kotori-bot/core").UnionParser<[import("@kotori-bot/core").LiteralParser<"zh_CN">, import("@kotori-bot/core").LiteralParser<"zh_TW">]>]>;
13
- 'command-prefix': import("@kotori-bot/core").StringParser;
14
- }>]>;
15
- adapter: import("@kotori-bot/core").Parser<import("@kotori-bot/core").IndexObject<import("@kotori-bot/core").ObjectParserInfer<{
16
- extends: import("@kotori-bot/core").StringParser;
17
- master: import("@kotori-bot/core").UnionParser<[import("@kotori-bot/core").NumberParser, import("@kotori-bot/core").StringParser]>;
18
- }> & import("@kotori-bot/core").ObjectParserInfer<{
19
- lang: import("@kotori-bot/core").UnionParser<[import("@kotori-bot/core").UnionParser<[import("@kotori-bot/core").LiteralParser<"en_US">, import("@kotori-bot/core").LiteralParser<"ja_JP">]>, import("@kotori-bot/core").UnionParser<[import("@kotori-bot/core").LiteralParser<"zh_CN">, import("@kotori-bot/core").LiteralParser<"zh_TW">]>]>;
20
- 'command-prefix': import("@kotori-bot/core").StringParser;
21
- }>>>;
22
- plugin: import("@kotori-bot/core").Parser<import("@kotori-bot/core").IndexObject<import("@kotori-bot/core").ObjectParserInfer<{
23
- priority: import("@kotori-bot/core").NumberParser;
24
- }>>>;
25
- }>;
package/lib/global.js DELETED
@@ -1,53 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.getGlobalConfig = exports.getBaseDir = exports.CONFIG_FILE = exports.isDev = void 0;
7
- const fs_1 = __importDefault(require("fs"));
8
- const path_1 = __importDefault(require("path"));
9
- const core_1 = require("@kotori-bot/core");
10
- const isDev = () => globalThis.env_mode === 'dev';
11
- exports.isDev = isDev;
12
- const CONFIG_FILE = () => ((0, exports.isDev)() ? 'kotori.dev.yml' : 'kotori.yml');
13
- exports.CONFIG_FILE = CONFIG_FILE;
14
- const getBaseDir = () => {
15
- const { env_dir: envDir } = globalThis;
16
- if (envDir) {
17
- return {
18
- root: envDir,
19
- modules: path_1.default.join(envDir, 'modules'),
20
- };
21
- }
22
- let root = path_1.default.resolve(__dirname, '..').replace('loader', 'kotori');
23
- let count = 0;
24
- while (!fs_1.default.existsSync(path_1.default.join(root, (0, exports.CONFIG_FILE)()))) {
25
- if (count > 5)
26
- throw new core_1.CoreError(`cannot find kotori-bot global ${exports.CONFIG_FILE}`);
27
- root = path_1.default.join(root, '..');
28
- count += 1;
29
- }
30
- return {
31
- root,
32
- modules: path_1.default.join(root, 'modules'),
33
- };
34
- };
35
- exports.getBaseDir = getBaseDir;
36
- const getGlobalConfig = (baseDir) => {
37
- const data = (0, core_1.loadConfig)(path_1.default.join(baseDir.root, (0, exports.CONFIG_FILE)()), 'yaml');
38
- const isExistsGlobal = data && typeof data === 'object' && data.global && typeof data.global === 'object';
39
- try {
40
- if (!isExistsGlobal)
41
- throw new core_1.TsuError('en_US', 'array_error');
42
- const lang = data.global.lang ? core_1.localeTypeSchema.parse(data.global.lang) : undefined;
43
- const commandPrefix = data.global['command-prefix'] ? data.global['command-prefix'] : undefined;
44
- return (0, core_1.globalConfigSchemaController)(lang, commandPrefix).parse(data);
45
- }
46
- catch (err) {
47
- if (!(err instanceof core_1.TsuError))
48
- throw err;
49
- // process.exit(1);
50
- throw new core_1.CoreError(`kotori-bot global ${exports.CONFIG_FILE} format error: ${err.message}`);
51
- }
52
- };
53
- exports.getGlobalConfig = getGlobalConfig;
package/lib/modules.d.ts DELETED
@@ -1,18 +0,0 @@
1
- import { Context } from '@kotori-bot/core';
2
- declare module '@kotori-bot/core' {
3
- interface Context {
4
- readonly moduleAll?: () => void;
5
- readonly watchFile?: () => void;
6
- }
7
- }
8
- export declare class Modules extends Context {
9
- private isDev;
10
- private readonly moduleRootDir;
11
- private getDirFiles;
12
- private getModuleRootDir;
13
- private getModuleList;
14
- private moduleQuick;
15
- readonly moduleAll: () => Promise<void>;
16
- readonly watchFile: () => Promise<void>;
17
- }
18
- export default Modules;
package/lib/modules.js DELETED
@@ -1,84 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.Modules = void 0;
7
- const fs_1 = __importDefault(require("fs"));
8
- const path_1 = __importDefault(require("path"));
9
- const core_1 = require("@kotori-bot/core");
10
- const consts_1 = require("./consts");
11
- class Modules extends core_1.Context {
12
- isDev = this.options.env === 'dev';
13
- moduleRootDir = [];
14
- getDirFiles(rootDir) {
15
- const files = fs_1.default.readdirSync(rootDir);
16
- const list = [];
17
- files.forEach(fileName => {
18
- const file = path_1.default.join(rootDir, fileName);
19
- if (fs_1.default.statSync(file).isDirectory()) {
20
- list.push(...this.getDirFiles(file));
21
- }
22
- if (path_1.default.parse(file).ext !== (this.isDev ? consts_1.DEV_FILE : consts_1.BUILD_FILE))
23
- return;
24
- list.push(path_1.default.resolve(file));
25
- });
26
- return list;
27
- }
28
- getModuleRootDir() {
29
- Object.assign(this.config.global.dirs, [this.baseDir.modules]).forEach(dir => {
30
- if (fs_1.default.existsSync(dir) && fs_1.default.statSync(dir).isDirectory())
31
- this.moduleRootDir.push(dir);
32
- });
33
- }
34
- getModuleList(rootDir) {
35
- const files = fs_1.default.readdirSync(rootDir);
36
- files.forEach(fileName => {
37
- const dir = path_1.default.join(rootDir, fileName);
38
- if (!fs_1.default.statSync(dir).isDirectory())
39
- return;
40
- if (rootDir !== this.baseDir.modules && fileName.startsWith(core_1.PLUGIN_PREFIX))
41
- return;
42
- const packagePath = path_1.default.join(dir, 'package.json');
43
- let packageJson;
44
- if (!fs_1.default.existsSync(packagePath))
45
- return;
46
- try {
47
- packageJson = JSON.parse(fs_1.default.readFileSync(packagePath).toString());
48
- }
49
- catch {
50
- throw new core_1.DevError(`illegal package.json ${packagePath}`);
51
- }
52
- const result = core_1.ModulePackageSchema.parseSafe(packageJson);
53
- if (!result.value && rootDir === this.baseDir.modules) {
54
- throw new core_1.DevError(`package.json format error ${packagePath}: ${result.error.message}`);
55
- }
56
- const mainPath = path_1.default.join(dir, this.isDev ? consts_1.DEV_IMPORT : packageJson.main);
57
- if (!fs_1.default.existsSync(mainPath))
58
- throw new core_1.DevError(`cannot find ${mainPath}`);
59
- const codeDirs = path_1.default.join(dir, this.isDev ? consts_1.DEV_CODE_DIRS : path_1.default.dirname(packageJson.main));
60
- this.moduleStack.push({
61
- package: packageJson,
62
- fileList: fs_1.default.statSync(codeDirs).isDirectory() ? this.getDirFiles(codeDirs) : [],
63
- mainPath: path_1.default.resolve(mainPath),
64
- });
65
- });
66
- }
67
- moduleQuick(moduleData) {
68
- return this.use(moduleData, this, this.config.plugin[(0, core_1.stringRightSplit)(moduleData.package.name, core_1.PLUGIN_PREFIX)] ?? {});
69
- }
70
- moduleAll = async () => {
71
- this.getModuleRootDir();
72
- this.moduleRootDir.forEach(dir => {
73
- this.getModuleList(dir);
74
- });
75
- const array = this.moduleStack.filter(data => data.package.name.startsWith(core_1.OFFICIAL_MODULES_SCOPE));
76
- array.push(...this.moduleStack.filter(data => !array.includes(data)));
77
- array.forEach(moduleData => this.moduleQuick(moduleData));
78
- };
79
- watchFile = async () => {
80
- this.moduleStack.forEach(moduleData => moduleData.fileList.forEach(file => fs_1.default.watchFile(file, () => this.dispose(moduleData) && this.moduleQuick(moduleData))));
81
- };
82
- }
83
- exports.Modules = Modules;
84
- exports.default = Modules;