bakit 1.0.0-beta.9 → 2.0.0-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,402 +1,73 @@
1
- // src/index.ts
2
- import "reflect-metadata";
1
+ import { GatewayIntentBits, Events, Client, Collection, ChatInputCommandInteraction, Message } from 'discord.js';
2
+ import z3, { z } from 'zod';
3
+ import { pathToFileURL } from 'url';
4
+ import glob from 'tiny-glob';
5
+ import { inspect } from 'util';
6
+ import { posix } from 'path';
3
7
 
4
- // src/BakitClient.ts
5
- import {
6
- Client,
7
- codeBlock,
8
- Events
9
- } from "discord.js";
10
-
11
- // src/command/CommandRegistry.ts
12
- import {
13
- Collection as Collection2,
14
- SlashCommandBuilder,
15
- SlashCommandSubcommandBuilder,
16
- SlashCommandSubcommandGroupBuilder
17
- } from "discord.js";
18
- import glob from "tiny-glob";
19
- import { pathToFileURL } from "url";
20
-
21
- // src/command/CommandEntry.ts
22
- import { Collection } from "discord.js";
23
-
24
- // src/base/BaseEntry.ts
25
- var BaseEntry = class {
26
- target;
27
- hooks = {
28
- ["MAIN" /* Main */]: void 0,
29
- ["ERROR" /* Error */]: void 0,
30
- ["POST" /* Post */]: void 0,
31
- ["PRE" /* Pre */]: void 0
32
- };
33
- main;
34
- pre;
35
- post;
36
- error;
37
- constructor() {
38
- this.main = this.createMainHookDecorator("MAIN" /* Main */);
39
- this.pre = this.createMainHookDecorator("PRE" /* Pre */);
40
- this.post = this.createMainHookDecorator("POST" /* Post */);
41
- this.error = this.createMainHookDecorator("ERROR" /* Error */);
42
- }
43
- setTarget(target) {
44
- this.target = target;
45
- }
46
- createMainHookDecorator(state) {
47
- return (target, _key, descriptor) => {
48
- this.addHook(state, target, descriptor);
49
- };
50
- }
51
- createErrorHookDecorator(state) {
52
- return (target, _key, descriptor) => {
53
- this.addHook(state, target, descriptor);
54
- };
55
- }
56
- addHook(state, target, descriptor) {
57
- if (this.target && this.target !== target.constructor) {
58
- throw new Error("Hook is used at wrong constructor.");
59
- }
60
- const { value: method } = descriptor;
61
- if (typeof method !== "function") {
62
- throw new Error("Invalid target method for hook.");
63
- }
64
- const hook = {
65
- state,
66
- method,
67
- entry: this
68
- };
69
- this.hooks[state] = hook;
70
- }
71
- };
72
-
73
- // src/command/CommandEntry.ts
74
- var BaseCommandEntry = class extends BaseEntry {
75
- constructor(options) {
76
- super();
77
- this.options = options;
78
- }
79
- };
80
- var BaseCommandGroupEntry = class extends BaseCommandEntry {
81
- children = new Collection();
82
- subcommand(options) {
83
- const fullOptions = typeof options === "string" ? { name: options, description: `${options} command` } : { description: `${options.name} command`, ...options };
84
- if (this.children.has(fullOptions.name)) {
85
- throw new Error(`Entry "${fullOptions.name}" is already existed.`);
86
- }
87
- const subcommand = new SubcommandEntry(fullOptions, this);
88
- this.children.set(fullOptions.name, subcommand);
89
- return subcommand;
90
- }
91
- };
92
- var RootCommandEntry = class extends BaseCommandGroupEntry {
93
- group(options) {
94
- const fullOptions = typeof options === "string" ? { name: options, description: `${options} command` } : { description: `${options.name} command`, ...options };
95
- if (this.children.has(fullOptions.name)) {
96
- throw new Error(`Entry "${fullOptions.name}" is already existed.`);
97
- }
98
- const group = new CommandGroupEntry(fullOptions, this);
99
- this.children.set(fullOptions.name, group);
100
- return group;
101
- }
102
- };
103
- var CommandGroupEntry = class extends BaseCommandGroupEntry {
104
- constructor(options, parent) {
105
- super(options);
106
- this.parent = parent;
107
- }
108
- };
109
- var SubcommandEntry = class extends BaseCommandEntry {
110
- constructor(options, parent) {
111
- super(options);
112
- this.parent = parent;
113
- }
114
- };
115
-
116
- // src/command/Command.ts
117
- var CommandAPI;
118
- ((CommandAPI2) => {
119
- const rootEntries = /* @__PURE__ */ new WeakMap();
120
- function use(root) {
121
- return (target) => {
122
- root.setTarget(target);
123
- rootEntries.set(target, root);
124
- };
125
- }
126
- CommandAPI2.use = use;
127
- function getRoot(constructor) {
128
- return rootEntries.get(constructor);
129
- }
130
- CommandAPI2.getRoot = getRoot;
131
- })(CommandAPI || (CommandAPI = {}));
132
- function CommandFactory(options) {
133
- if (typeof options === "string") {
134
- options = { name: options };
135
- }
136
- if (!options.description) {
137
- options.description = options.name;
138
- }
139
- return new RootCommandEntry(options);
140
- }
141
- var Command = Object.assign(CommandFactory, CommandAPI);
142
-
143
- // src/command/argument/Argument.ts
144
- var ArgumentType = /* @__PURE__ */ ((ArgumentType2) => {
145
- ArgumentType2["String"] = "string";
146
- ArgumentType2["Integer"] = "integer";
147
- ArgumentType2["Number"] = "number";
148
- ArgumentType2["User"] = "user";
149
- ArgumentType2["Member"] = "member";
150
- return ArgumentType2;
151
- })(ArgumentType || {});
152
-
153
- // src/command/argument/Arg.ts
154
- var ARGS_KEY = Symbol("args");
155
- var cache = /* @__PURE__ */ new WeakMap();
156
- function getMethodArguments(method, init = false) {
157
- let args = cache.get(method) ?? Reflect.getMetadata(ARGS_KEY, method);
158
- if (!args) {
159
- args = [];
160
- if (init) {
161
- Reflect.defineMetadata(ARGS_KEY, args, method);
162
- cache.set(method, args);
163
- }
164
- }
165
- return init ? args : Object.freeze([...args]);
166
- }
167
- function createArgument(type) {
168
- return function(options) {
169
- const objOptions = typeof options === "string" ? { name: options } : options;
170
- const fullOptions = { ...objOptions, type };
171
- if (!fullOptions.description) {
172
- fullOptions.description = fullOptions.name;
173
- }
174
- if (!("required" in fullOptions)) {
175
- fullOptions.required = true;
176
- }
177
- return function(target, key, _index) {
178
- const method = Object.getOwnPropertyDescriptor(target, key)?.value;
179
- if (!method) {
180
- throw new Error("No method found");
181
- }
182
- const args = getMethodArguments(method, true);
183
- args.unshift(fullOptions);
184
- };
185
- };
186
- }
187
- var string = createArgument("string" /* String */);
188
- var integer = createArgument("integer" /* Integer */);
189
- var number = createArgument("number" /* Number */);
190
- var user = createArgument("user" /* User */);
191
- var member = createArgument("member" /* Member */);
192
- function describeArgumentExpectation(arg) {
193
- const parts = [arg.type];
194
- switch (arg.type) {
195
- case "string" /* String */: {
196
- if (arg.minLength && !arg.maxLength) {
197
- parts.push(`\u2265 ${String(arg.minLength)}`);
198
- }
199
- if (!arg.minLength && arg.maxLength) {
200
- parts.push(`\u2264 ${String(arg.maxLength)}`);
201
- }
202
- if (arg.minLength && arg.maxLength) {
203
- parts.push(`${String(arg.minLength)} - ${String(arg.maxLength)}`);
204
- }
205
- break;
206
- }
207
- case "number" /* Number */:
208
- case "integer" /* Integer */: {
209
- if (arg.minValue !== void 0 && arg.maxValue === void 0) {
210
- parts.push(`\u2265 ${String(arg.minValue)}`);
211
- }
212
- if (arg.minValue === void 0 && arg.maxValue !== void 0) {
213
- parts.push(`\u2264 ${String(arg.maxValue)}`);
214
- }
215
- if (arg.minValue !== void 0 && arg.maxValue !== void 0) {
216
- parts.push(`${String(arg.minValue)} - ${String(arg.maxValue)}`);
217
- }
218
- break;
219
- }
220
- case "user" /* User */:
221
- case "member" /* Member */: {
222
- break;
223
- }
224
- }
225
- return parts.join(", ");
226
- }
227
- function format(arg) {
228
- const { name, required, tuple } = arg;
229
- const opening = required ? "<" : "[";
230
- const closing = required ? ">" : "]";
231
- const prefix = tuple ? "..." : "";
232
- return `${opening}${prefix}${name}: ${describeArgumentExpectation(arg)}${closing}`;
233
- }
234
- var Arg = {
235
- getMethodArguments,
236
- createArgument,
237
- describeArgumentExpectation,
238
- format,
239
- string,
240
- number,
241
- integer,
242
- user,
243
- member
244
- };
245
-
246
- // src/command/CommandRegistry.ts
247
- var CommandRegistry = class _CommandRegistry {
248
- static constructors = new Collection2();
249
- static instances = new Collection2();
8
+ // src/config.ts
9
+ var ProjectConfigSchema = z.object({
250
10
  /**
251
- * Add a command to the registry.
252
- * @param constructor The command class you want to add.
11
+ * The gateway intents to use for the Discord client.
12
+ *
13
+ * - `auto` — automatically determine the required intents.
14
+ * - bigint — a raw bitfield value representing the combined intents.
15
+ * - array — a list of individual intent flags from `GatewayIntentBits`.
16
+ *
17
+ * @defaultvalue `auto`
253
18
  */
254
- static add(constructor) {
255
- const root = Command.getRoot(constructor);
256
- if (!root) {
257
- throw new Error(`No root found for "${constructor.name}"`);
258
- }
259
- const { options } = root;
260
- this.constructors.set(options.name, constructor);
261
- this.instances.set(options.name, new constructor());
262
- }
19
+ intents: z.union([z.literal("auto"), z.bigint(), z.array(z.enum(GatewayIntentBits))]).default("auto"),
263
20
  /**
264
- * Load and add all commands which matched provided glob pattern to the registry.
265
- * @param pattern glob pattern to load.
266
- * @param parallel load all matched results in parallel, enabled by default.
267
- * @returns All loaded command constructors.
21
+ * Optional custom client options for Discord.js (excluding `intents`).
22
+ *
23
+ * These are passed directly to the `Client` constructor when initializing the bot.
24
+ *
25
+ * @see {@link https://discord.js.org/docs/packages/discord.js/main/ClientOptions:Interface}
268
26
  */
269
- static async load(pattern, parallel = true) {
270
- const files = await glob(pattern);
271
- const loaders = files.map(async (file) => {
272
- const fileURL = pathToFileURL(file).toString();
273
- const { default: constructor } = await import(fileURL);
274
- _CommandRegistry.add(constructor);
275
- return constructor;
276
- });
277
- if (parallel) {
278
- return await Promise.all(loaders);
279
- }
280
- const result = [];
281
- for (const loader of loaders) {
282
- result.push(await loader);
283
- }
284
- return result;
285
- }
27
+ clientOptions: z.custom().optional(),
286
28
  /**
287
- * Build a command into application command data.
288
- * @param constructor The command class you want to build.
289
- * @returns a REST JSON version of the application command data.
29
+ * The path to the main project source directory.
30
+ *
31
+ * @defaultvalue `src`
290
32
  */
291
- static buildSlashCommand(constructor) {
292
- const root = Command.getRoot(constructor);
293
- if (!root) {
294
- throw new Error(`No root found for "${constructor.name}"`);
295
- }
296
- const { options } = root;
297
- const builder = new SlashCommandBuilder().setName(options.name).setDescription(options.description).setNSFW(Boolean(options.nsfw));
298
- const args = this.getMainHookArguments(root);
299
- if (root.children.size) {
300
- this.buildSlashCommandSubcommands(builder, root, args);
301
- } else {
302
- this.buildSlashCommandOptions(builder, args);
303
- }
304
- return builder.toJSON();
305
- }
306
- static getMainHookArguments(entry) {
307
- const { hooks } = entry;
308
- const mainHook = hooks["MAIN" /* Main */];
309
- return mainHook ? Arg.getMethodArguments(mainHook.method) : [];
310
- }
311
- static buildSlashCommandSubcommands(parent, entry, inheritedArgs) {
312
- const { children } = entry;
313
- for (const child of children.values()) {
314
- if (child instanceof CommandGroupEntry && parent instanceof SlashCommandBuilder) {
315
- const { options } = child;
316
- const group = new SlashCommandSubcommandGroupBuilder().setName(options.name).setDescription(options.description);
317
- this.buildSlashCommandSubcommands(group, child, [
318
- ...inheritedArgs,
319
- ...this.getMainHookArguments(child)
320
- ]);
321
- parent.addSubcommandGroup(group);
322
- } else if (child instanceof SubcommandEntry) {
323
- const { options } = child;
324
- const subcommand = new SlashCommandSubcommandBuilder().setName(options.name).setDescription(options.description);
325
- this.buildSlashCommandOptions(subcommand, [
326
- ...inheritedArgs,
327
- ...this.getMainHookArguments(child)
328
- ]);
329
- parent.addSubcommand(subcommand);
330
- }
331
- }
332
- }
333
- static buildSlashCommandOptions(builder, args) {
334
- const argGroup = Object.groupBy(args, ({ required }) => required ? "required" : "optional");
335
- const orderedArgs = [...argGroup.required || [], ...argGroup.optional || []];
336
- for (const arg of orderedArgs) {
337
- this.attachSlashCommandOption(builder, arg);
338
- }
339
- }
340
- static attachSlashCommandOption(builder, arg) {
341
- const setupOption = (option) => {
342
- return option.setName(arg.name).setDescription(arg.description || arg.name).setRequired(Boolean(arg.required));
343
- };
344
- switch (arg.type) {
345
- case "string" /* String */: {
346
- builder.addStringOption((data) => {
347
- const option = setupOption(data);
348
- if (arg.maxLength) {
349
- option.setMaxLength(arg.maxLength);
350
- }
351
- if (arg.minLength) {
352
- option.setMinLength(arg.minLength);
353
- }
354
- return option;
355
- });
356
- break;
357
- }
358
- case "integer" /* Integer */: {
359
- builder.addIntegerOption((data) => {
360
- const option = setupOption(data);
361
- if (arg.maxValue) {
362
- option.setMaxValue(arg.maxValue);
363
- }
364
- if (arg.minValue) {
365
- option.setMinValue(arg.minValue);
366
- }
367
- return option;
368
- });
369
- break;
370
- }
371
- case "number" /* Number */: {
372
- builder.addNumberOption((data) => {
373
- const option = setupOption(data);
374
- if (arg.maxValue) {
375
- option.setMaxValue(arg.maxValue);
376
- }
377
- if (arg.minValue) {
378
- option.setMinValue(arg.minValue);
379
- }
380
- return option;
381
- });
382
- break;
383
- }
384
- case "user" /* User */:
385
- case "member" /* Member */: {
386
- builder.addUserOption((option) => setupOption(option));
387
- break;
388
- }
389
- }
33
+ entryDir: z.string().default("src")
34
+ });
35
+ function defineConfig(config) {
36
+ return config;
37
+ }
38
+ var _config;
39
+ async function loadConfig(cwd = process.cwd()) {
40
+ if (_config)
41
+ return console.warn("loadConfig() was called more than once. This shouldn't happen."), _config;
42
+ let globPattern = `bakit.config.{${["ts", "js"].join(",")}}`, [configPath, other] = await glob(globPattern, {
43
+ cwd: cwd.replace(/\\/g, "/"),
44
+ // ensure the path uses `/` instead of `\` on Windows
45
+ absolute: true
46
+ });
47
+ if (!configPath)
48
+ throw new Error("Missing config file");
49
+ other && console.warn(`Multiple config files found in ${cwd}. Using ${configPath}.`);
50
+ let configFileURL = pathToFileURL(configPath).toString(), { default: config } = await import(configFileURL);
51
+ return _config = Object.freeze(await ProjectConfigSchema.parseAsync(config)), _config;
52
+ }
53
+ function getConfig() {
54
+ if (!_config)
55
+ throw new Error("Project config is not loaded.");
56
+ return _config;
57
+ }
58
+
59
+ // src/base/lifecycle/Context.ts
60
+ var Context = class {
61
+ canceled = false;
62
+ cancel() {
63
+ this.canceled = true;
390
64
  }
391
65
  };
392
66
 
393
- // src/command/Context.ts
394
- import {
395
- ChatInputCommandInteraction,
396
- Message
397
- } from "discord.js";
398
- var BaseContext = class {
67
+ // src/command/CommandContext.ts
68
+ var BaseCommandContext = class extends Context {
399
69
  constructor(source) {
70
+ super();
400
71
  this.source = source;
401
72
  }
402
73
  get client() {
@@ -414,26 +85,25 @@ var BaseContext = class {
414
85
  get guildId() {
415
86
  return this.source.guildId;
416
87
  }
88
+ get member() {
89
+ return this.source.member;
90
+ }
417
91
  inGuild() {
418
- return Boolean(this.guildId);
92
+ return !!this.guildId;
419
93
  }
420
94
  inCachedGuild() {
421
- if (this.isChatInput()) {
95
+ if (this.isChatInput())
422
96
  return this.source.inCachedGuild();
423
- } else if (this.isMessage()) {
97
+ if (this.isMessage())
424
98
  return this.source.inGuild();
425
- } else {
426
- throw new Error("Invalid source");
427
- }
99
+ throw new Error("Invalid source");
428
100
  }
429
- get author() {
430
- if (this.isChatInput()) {
101
+ get user() {
102
+ if (this.isChatInput())
431
103
  return this.source.user;
432
- } else if (this.isMessage()) {
104
+ if (this.isMessage())
433
105
  return this.source.author;
434
- } else {
435
- throw new Error("Invalid source");
436
- }
106
+ throw new Error("Invalid source");
437
107
  }
438
108
  isChatInput() {
439
109
  return this.source instanceof ChatInputCommandInteraction;
@@ -441,769 +111,357 @@ var BaseContext = class {
441
111
  isMessage() {
442
112
  return this.source instanceof Message;
443
113
  }
444
- };
445
- var ChatInputContext = class extends BaseContext {
114
+ }, ChatInputContext = class extends BaseCommandContext {
446
115
  async send(options) {
447
- if (typeof options === "string") {
448
- options = { content: options };
449
- }
450
- const sendOptions = {
116
+ typeof options == "string" && (options = { content: options });
117
+ let sendOptions = {
451
118
  ...options,
452
119
  withResponse: true
453
120
  };
454
- if (this.source.deferred || this.source.replied) {
455
- return await this.source.followUp(sendOptions);
456
- }
457
- const response = await this.source.reply(sendOptions);
458
- return response.resource?.message;
121
+ return this.source.deferred || this.source.replied ? await this.source.followUp(sendOptions) : (await this.source.reply(sendOptions)).resource?.message;
459
122
  }
460
- };
461
- var MessageContext = class extends BaseContext {
123
+ }, MessageContext = class extends BaseCommandContext {
462
124
  async send(options) {
463
- const { channel } = this;
464
- if (!channel?.isSendable()) {
125
+ let { channel } = this;
126
+ if (!channel?.isSendable())
465
127
  throw new Error("Invalid channel or channel is not sendable");
466
- }
467
128
  return await channel.send(options);
468
129
  }
469
130
  };
470
-
471
- // src/utils/user.ts
472
- function extractId(value) {
473
- const idMatch = value.match(/^<@!?(\d+)>$/);
474
- if (idMatch) {
475
- return idMatch[1];
476
- }
477
- const numericMatch = value.match(/^(\d{17,19})$/);
478
- if (numericMatch) {
479
- return numericMatch[1];
131
+ var LifecycleManager = class {
132
+ constructor(id) {
133
+ this.id = id;
480
134
  }
481
- return null;
482
- }
483
-
484
- // src/errors/CommandSyntaxError.ts
485
- var CommandSyntaxErrorType = /* @__PURE__ */ ((CommandSyntaxErrorType2) => {
486
- CommandSyntaxErrorType2["MissingRequireArgument"] = "MISSING_REQUIRE_ARGUMENT";
487
- CommandSyntaxErrorType2["InvalidArgument"] = "INVALID_ARGUMENT";
488
- CommandSyntaxErrorType2["InvalidVariadicArgumentValue"] = "INVALID_VARIADIC_ARGUMENT_VALUE";
489
- return CommandSyntaxErrorType2;
490
- })(CommandSyntaxErrorType || {});
491
- var CommandSyntaxError = class extends Error {
492
- arg;
493
- type;
494
- expected;
495
- received;
496
- constructor(options) {
497
- let message;
498
- const { arg, type, received } = options;
499
- const expected = Arg.describeArgumentExpectation(arg);
500
- switch (type) {
501
- case "MISSING_REQUIRE_ARGUMENT" /* MissingRequireArgument */: {
502
- message = [`Missing required argument "${arg.name}"`, `> Expected: ${expected}`].join("\n");
503
- break;
504
- }
505
- case "INVALID_ARGUMENT" /* InvalidArgument */: {
506
- message = [
507
- `Invalid value received for argument "${arg.name}"`,
508
- `> Expected: ${expected}`,
509
- `> Received: ${String(received)}`
510
- ].join("\n");
135
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
136
+ hooks = {
137
+ MAIN: new Collection(),
138
+ PRE: new Collection(),
139
+ POST: new Collection(),
140
+ ERROR: new Collection()
141
+ };
142
+ getName(name) {
143
+ return `${this.id}:${name}`;
144
+ }
145
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
146
+ setHook(name, state, callback, order = 1 /* Last */) {
147
+ let currentHooks = this.hooks[state], key = this.getName(name);
148
+ if (currentHooks.has(key) && console.warn(`Overriding duplicate hook '${key}' for state '${state}'`), order === 1 /* Last */)
149
+ currentHooks.set(key, callback);
150
+ else {
151
+ let existingEntries = [...currentHooks.entries()].filter(([k]) => k !== key);
152
+ currentHooks.clear(), currentHooks.set(key, callback);
153
+ for (let [k, v] of existingEntries)
154
+ currentHooks.set(k, v);
155
+ }
156
+ return this;
157
+ }
158
+ main(callback) {
159
+ return this.setHook("main", "MAIN" /* Main */, callback);
160
+ }
161
+ pre(callback) {
162
+ return this.setHook("pre", "PRE" /* Pre */, callback);
163
+ }
164
+ post(callback) {
165
+ return this.setHook("post", "POST" /* Post */, callback);
166
+ }
167
+ error(callback) {
168
+ return this.setHook("error", "ERROR" /* Error */, callback);
169
+ }
170
+ async execute(context, ...args) {
171
+ let pipeline = [
172
+ ...this.hooks.PRE.values(),
173
+ ...this.hooks.MAIN.values(),
174
+ ...this.hooks.POST.values()
175
+ ], error;
176
+ for (let hook of pipeline) {
177
+ if (context.canceled)
511
178
  break;
512
- }
513
- case "INVALID_VARIADIC_ARGUMENT_VALUE" /* InvalidVariadicArgumentValue */: {
514
- message = [
515
- `Invalid value received for variadic argument "${arg.name}"`,
516
- `> Expected: ${expected}`,
517
- `> Received: ${String(received)}`
518
- ].join("\n");
179
+ try {
180
+ await hook(context, ...args);
181
+ } catch (e) {
182
+ error = e;
519
183
  break;
520
184
  }
521
- default: {
522
- message = "Unknown error";
185
+ }
186
+ if (!error)
187
+ return;
188
+ if (!this.hooks.ERROR.size)
189
+ throw error;
190
+ for (let [key, callback] of this.hooks.ERROR.entries()) {
191
+ if (context.canceled)
523
192
  break;
193
+ try {
194
+ await callback(context, error, ...args);
195
+ } catch (innerError) {
196
+ console.error(`[Lifecycle] Error handler for '${key}' failed:`, innerError);
524
197
  }
525
198
  }
526
- super(message);
527
- this.arg = arg;
528
- this.type = type;
529
- this.expected = expected;
530
- this.received = received;
531
- Error.captureStackTrace(this, this.constructor);
532
- }
533
- get name() {
534
- return `CommandSyntaxError[${this.type}]`;
535
199
  }
536
200
  };
537
201
 
538
- // src/command/argument/ArgumentResolver.ts
539
- var ArgumentResolver = class _ArgumentResolver {
202
+ // src/command/param/Param.ts
203
+ var BaseParam = class {
204
+ options;
540
205
  constructor(options) {
541
- this.options = options;
542
- }
543
- parsedValues = [];
544
- /**
545
- * Get the first value as the command trigger.
546
- */
547
- get trigger() {
548
- return this.options.values[0];
206
+ this.options = { ...options, required: options.required ?? true };
549
207
  }
550
- /**
551
- * Get amount of specified argument values.
552
- */
553
- get specifiedAmount() {
554
- return this.options.values.length - this.options.startAt;
208
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
209
+ setOption(key, value) {
210
+ return value === null ? delete this.options[key] : this.options[key] = value, this;
555
211
  }
556
- /**
557
- * Get parsed raw values from content.
558
- */
559
- get values() {
560
- return [...this.options.values];
212
+ name(value) {
213
+ return this.setOption("name", value);
561
214
  }
562
- get client() {
563
- return this.options.message.client;
215
+ description(value) {
216
+ return this.setOption("description", value);
564
217
  }
565
- static create(message) {
566
- const client = message.client;
567
- const { enableMentionPrefix } = client.options;
568
- const prefixes = [
569
- // Custom prefixes specified in options
570
- ...client.options.prefixes ?? [],
571
- // Use bot mention as prefix if enabled
572
- ...enableMentionPrefix ? [client.user.toString()] : []
573
- ];
574
- const prefix = prefixes.find((p) => message.content.startsWith(p)) ?? null;
575
- if (!prefix) {
576
- return;
577
- }
578
- const values = message.content.slice(prefix.length).trim().split(/\s+/);
579
- return new _ArgumentResolver({
580
- message,
581
- startAt: 1,
582
- // Skip the command trigger
583
- values,
584
- args: [],
585
- prefix
586
- });
218
+ required(value) {
219
+ return this.setOption("required", value);
587
220
  }
588
- async resolve(args) {
589
- const child = new _ArgumentResolver({
590
- prefix: this.options.prefix,
591
- message: this.options.message,
592
- values: this.options.values,
593
- args,
594
- startAt: this.options.startAt
595
- });
596
- child.parsedValues = [...this.parsedValues];
597
- if (!child.options.args.length) {
598
- return child;
599
- }
600
- if (this.specifiedAmount >= child.options.args.length) {
601
- await child.absoluteParse();
602
- } else {
603
- await child.dynamicParse();
604
- }
605
- return child;
606
- }
607
- async absoluteParse() {
608
- const { args, values, startAt } = this.options;
609
- let valueIndex = startAt;
610
- let argIndex = 0;
611
- while (valueIndex < values.length && argIndex < args.length) {
612
- const value = values[valueIndex];
613
- const arg = args[argIndex];
614
- if (arg.tuple) {
615
- this.parsedValues.push(...await this.resolveTuple(arg, valueIndex, argIndex));
616
- break;
617
- }
618
- const matchedValue = await this.matchValue(arg, value);
619
- if (matchedValue === null) {
620
- throw new CommandSyntaxError({
621
- arg,
622
- type: "INVALID_ARGUMENT" /* InvalidArgument */,
623
- received: value
624
- });
625
- }
626
- this.parsedValues.push(matchedValue);
627
- valueIndex++;
628
- argIndex++;
629
- }
630
- }
631
- async dynamicParse() {
632
- const { args, values } = this.options;
633
- let argIndex = 0;
634
- let valueIndex = this.options.startAt + 1;
635
- while (valueIndex < values.length && argIndex < args.length) {
636
- const value = values[valueIndex];
637
- const arg = args[argIndex];
638
- if (arg.tuple) {
639
- this.parsedValues.push(...await this.resolveTuple(arg, valueIndex, argIndex));
640
- break;
641
- }
642
- const matchedValue = await this.matchValue(arg, value);
643
- if (matchedValue !== null) {
644
- this.parsedValues.push(matchedValue);
645
- valueIndex++;
646
- } else if (arg.required) {
647
- throw new CommandSyntaxError({
648
- arg,
649
- type: "MISSING_REQUIRE_ARGUMENT" /* MissingRequireArgument */,
650
- received: value
651
- });
652
- }
653
- argIndex++;
654
- }
655
- while (argIndex < args.length) {
656
- const arg = args[argIndex];
657
- if (arg.required) {
658
- throw new CommandSyntaxError({
659
- arg,
660
- type: "MISSING_REQUIRE_ARGUMENT" /* MissingRequireArgument */,
661
- received: "nothing"
662
- });
663
- }
664
- argIndex++;
665
- }
666
- }
667
- async resolveTuple(arg, startIndex, argIndex) {
668
- const { args } = this.options;
669
- if (argIndex !== args.length - 1) {
670
- throw new SyntaxError("Tuple argument must be the last argument");
671
- }
672
- const values = [];
673
- for (const rest of this.values.slice(startIndex)) {
674
- const matchedValue = await this.matchValue(arg, rest);
675
- if (matchedValue === null) {
676
- throw new CommandSyntaxError({
677
- arg,
678
- type: "INVALID_VARIADIC_ARGUMENT_VALUE" /* InvalidVariadicArgumentValue */,
679
- received: rest
680
- });
681
- }
682
- values.push(matchedValue);
683
- }
684
- if (values.length === 0 && arg.required) {
685
- throw new CommandSyntaxError({
686
- arg,
687
- type: "MISSING_REQUIRE_ARGUMENT" /* MissingRequireArgument */,
688
- received: "nothing"
689
- });
690
- }
691
- return values;
692
- }
693
- async matchValue(arg, value) {
694
- switch (arg.type) {
695
- case "user" /* User */:
696
- return await this.matchUserValue(arg, value);
697
- case "integer" /* Integer */:
698
- return this.matchIntegerValue(arg, value);
699
- case "number" /* Number */:
700
- return this.matchNumberValue(arg, value);
701
- case "string" /* String */:
702
- return this.matchStringValue(arg, value);
703
- default:
704
- return null;
705
- }
706
- }
707
- async matchUserValue(arg, value) {
708
- const userId = extractId(value);
709
- if (!userId) {
710
- return null;
711
- }
712
- const user2 = await this.client.users.fetch(userId).catch(() => null);
713
- if (!user2) {
714
- return null;
715
- }
716
- return user2;
221
+ /**
222
+ * Helper to normalize string inputs into an options object.
223
+ */
224
+ static getOptions(options) {
225
+ return typeof options == "string" ? { name: options } : options;
717
226
  }
718
- matchIntegerValue(arg, value) {
719
- const intVal = parseInt(value, 10);
720
- if (isNaN(intVal)) {
721
- return null;
722
- }
723
- if (arg.minValue !== void 0 && intVal < arg.minValue) {
724
- return null;
725
- }
726
- if (arg.maxValue !== void 0 && intVal > arg.maxValue) {
727
- return null;
728
- }
729
- return intVal;
227
+ }, StringParam = class extends BaseParam {
228
+ constructor(options) {
229
+ super(BaseParam.getOptions(options));
730
230
  }
731
- matchNumberValue(arg, value) {
732
- const numVal = parseFloat(value);
733
- if (isNaN(numVal)) {
734
- return null;
735
- }
736
- if (arg.minValue !== void 0 && numVal < arg.minValue) {
737
- return null;
738
- }
739
- if (arg.maxValue !== void 0 && numVal > arg.maxValue) {
740
- return null;
741
- }
742
- return numVal;
231
+ required(value) {
232
+ return super.required(value);
743
233
  }
744
- matchStringValue(arg, value) {
745
- if (arg.minLength !== void 0 && value.length < arg.minLength) {
746
- return null;
747
- }
748
- if (arg.maxLength !== void 0 && value.length > arg.maxLength) {
749
- return null;
750
- }
751
- return value;
234
+ /**
235
+ * Sets the minimum allowed length for this string.
236
+ * Pass `null` to remove this constraint.
237
+ */
238
+ min(length) {
239
+ return this.setOption("minLength", length);
752
240
  }
753
- static resolveChatInput(interaction, arg) {
754
- switch (arg.type) {
755
- case "string" /* String */:
756
- return interaction.options.getString(arg.name, arg.required);
757
- case "integer" /* Integer */:
758
- return interaction.options.getInteger(arg.name, arg.required);
759
- case "number" /* Number */:
760
- return interaction.options.getNumber(arg.name, arg.required);
761
- case "user" /* User */:
762
- return interaction.options.getUser(arg.name, arg.required);
763
- case "member" /* Member */:
764
- return interaction.options.getMember(arg.name);
765
- default:
766
- return null;
767
- }
241
+ /**
242
+ * Sets the maximum allowed length for this string.
243
+ * Pass `null` to remove this constraint.
244
+ */
245
+ max(length) {
246
+ return this.setOption("maxLength", length);
768
247
  }
769
- };
770
-
771
- // src/libs/StateBox.ts
772
- import { AsyncLocalStorage } from "async_hooks";
773
- var StateBox = class _StateBox {
774
- static STATES_KEY = Symbol("states");
775
- static storage = new AsyncLocalStorage();
776
- static getState() {
777
- const state = this.storage.getStore();
778
- if (!state) {
779
- throw new Error("No active context, did you forget to wrap it with StateBox.wrap()?");
780
- }
781
- return state;
248
+ }, NumberParam = class extends BaseParam {
249
+ constructor(options) {
250
+ super(BaseParam.getOptions(options));
782
251
  }
783
- static run(fn, store = {}) {
784
- return this.storage.run(store, fn);
252
+ required(value) {
253
+ return super.required(value);
785
254
  }
786
- static wrap(fn) {
787
- const currentStore = this.storage.getStore();
788
- if (!currentStore) {
789
- throw new Error("No active context, cannot wrap function outside a StateBox.run()");
790
- }
791
- return () => this.run(fn, currentStore);
255
+ /**
256
+ * Sets the minimum allowed value for this number.
257
+ * Pass `null` to remove this constraint.
258
+ */
259
+ min(value) {
260
+ return this.setOption("minValue", value);
792
261
  }
793
- static use(defaultValue) {
794
- return (target, key) => {
795
- Object.defineProperty(target, key, {
796
- get() {
797
- const states = _StateBox.getState();
798
- if (!(key in states)) {
799
- states[key] = defaultValue;
800
- }
801
- return states[key];
802
- },
803
- set(value) {
804
- const states = _StateBox.getState();
805
- states[key] = value;
806
- },
807
- enumerable: true,
808
- configurable: true
809
- });
810
- };
262
+ /**
263
+ * Sets the maximum allowed value for this number.
264
+ * Pass `null` to remove this constraint.
265
+ */
266
+ max(value) {
267
+ return this.setOption("maxValue", value);
811
268
  }
812
269
  };
813
270
 
814
- // src/listener/ListenerEntry.ts
815
- var ListenerEntry = class extends BaseEntry {
271
+ // src/command/Command.ts
272
+ var CommandOptionsSchema = z.object({
273
+ name: z.string(),
274
+ description: z.string().min(1).max(100).optional(),
275
+ params: z.array(z.instanceof(BaseParam)).default([])
276
+ }).transform((data) => ({
277
+ ...data,
278
+ description: data.description ?? `Command ${data.name}`
279
+ })), Command = class extends LifecycleManager {
816
280
  constructor(options) {
817
- super();
818
- this.options = options;
281
+ let _options = CommandOptionsSchema.parse(typeof options == "string" ? { name: options } : options);
282
+ super(`command:${_options.name}`), this.options = _options;
819
283
  }
820
284
  };
285
+ function defineCommand(options) {
286
+ return new Command(options);
287
+ }
821
288
 
822
- // src/listener/Listener.ts
823
- var ListenerAPI;
824
- ((ListenerAPI2) => {
825
- ListenerAPI2.ENTRY_KEY = Symbol("entry");
826
- function use(entry) {
827
- return (target) => {
828
- Reflect.defineMetadata(ListenerAPI2.ENTRY_KEY, entry, target);
829
- };
289
+ // src/base/BaseClientManager.ts
290
+ var BaseClientManager = class {
291
+ constructor(client) {
292
+ this.client = client;
830
293
  }
831
- ListenerAPI2.use = use;
832
- function getEntry(target) {
833
- return Reflect.getMetadata(ListenerAPI2.ENTRY_KEY, target);
834
- }
835
- ListenerAPI2.getEntry = getEntry;
836
- })(ListenerAPI || (ListenerAPI = {}));
837
- function ListenerFactory(options) {
838
- const fullOptions = typeof options !== "object" ? { name: options, once: false } : { once: false, ...options };
839
- return new ListenerEntry(fullOptions);
840
- }
841
- var Listener = Object.assign(ListenerFactory, ListenerAPI);
294
+ };
842
295
 
843
- // src/listener/ListenerRegistry.ts
844
- import glob2 from "tiny-glob";
845
- import { pathToFileURL as pathToFileURL2 } from "url";
846
- var ListenerRegistry = class {
847
- static client;
848
- static constructors = /* @__PURE__ */ new Set();
849
- static instances = /* @__PURE__ */ new WeakMap();
850
- static executors = /* @__PURE__ */ new WeakMap();
851
- /**
852
- * Add and register a listener to the registry.
853
- * If `options.emitter` is not provided, the registry will use the base `client` by default.
854
- * @param constructor The listener class you want to add.
855
- */
856
- static add(constructor) {
857
- const entry = Listener.getEntry(constructor);
858
- if (!entry) {
859
- throw new Error(`No entry found for "${constructor.name}"`);
860
- }
861
- const { options } = entry;
862
- if (!options.emitter) {
863
- if (!this.client) {
864
- throw new Error("Client is not ready.");
296
+ // src/command/CommandManager.ts
297
+ var CommandManager = class extends BaseClientManager {
298
+ commands = new Collection();
299
+ async loadModules() {
300
+ let entryDir = posix.resolve(getConfig().entryDir), pattern = posix.join(entryDir, "commands", "**/*.{ts,js}"), loads = (await glob(pattern, {
301
+ cwd: process.cwd()
302
+ })).map(async (file) => {
303
+ try {
304
+ let { default: command } = await import(pathToFileURL(file).toString());
305
+ if (!command) {
306
+ console.warn(`[Loader] File has no default export: ${file}`);
307
+ return;
308
+ }
309
+ if (!(command instanceof Command)) {
310
+ console.warn(`[Loader] Default export is not a Command: ${file}`);
311
+ return;
312
+ }
313
+ return this.add(command), command;
314
+ } catch (error) {
315
+ console.error(`An error occurred while trying to add command for '${file}':`, error);
865
316
  }
866
- options.emitter = this.client;
867
- }
868
- const instance = new constructor();
869
- const executor = this.createExecutor(constructor, instance);
870
- this.constructors.add(constructor);
871
- this.instances.set(constructor, instance);
872
- this.executors.set(instance, executor);
873
- options.emitter[options.once ? "once" : "on"](options.name, (...args) => {
874
- void executor(...args);
875
- });
317
+ }), loaded = (await Promise.all(loads)).filter((x) => x !== void 0);
318
+ return console.log(`Loaded ${loaded.length} command(s).`), loaded;
876
319
  }
877
- /**
878
- * Remove and unregister a listener from the registry.
879
- * @param constructor The listener class you want to remove.
880
- * @returns `boolean`, returns `true` if the listener is removed successfully.
881
- */
882
- static remove(constructor) {
883
- const entry = Listener.getEntry(constructor);
884
- if (!entry) {
885
- return false;
886
- }
887
- this.constructors.delete(constructor);
888
- const instance = this.instances.get(constructor);
889
- if (!instance) {
890
- return false;
891
- }
892
- this.instances.delete(constructor);
893
- const executor = this.executors.get(instance);
894
- if (!executor) {
895
- return false;
320
+ add(command) {
321
+ if (!(command instanceof Command))
322
+ throw new Error("Invalid command provided");
323
+ let { name } = command.options;
324
+ if (this.commands.has(name)) {
325
+ console.warn(`[Loader] Duplicate command registered: '${name}'`);
326
+ return;
896
327
  }
897
- const { name, emitter } = entry.options;
898
- emitter?.removeListener(name, executor);
899
- this.executors.delete(instance);
900
- return true;
328
+ this.commands.set(name, command);
901
329
  }
902
- /**
903
- * Remove and unregister all listeners from the registry.
904
- * @returns Amount of removed listeners.
905
- */
906
- static removeAll() {
907
- let removedAmount = 0;
908
- for (const constructor of this.constructors) {
909
- if (this.remove(constructor)) {
910
- removedAmount++;
911
- }
912
- }
913
- return removedAmount;
330
+ remove(target) {
331
+ let name = typeof target == "string" ? target : target.options.name, existing = this.commands.get(name);
332
+ if (existing)
333
+ return this.commands.delete(name), existing;
914
334
  }
915
- /**
916
- * Set base client for the registry to fallback as default emitter. This should be used only by BakitClient and stay untouched.
917
- * @param newClient base client to set for the registry.
918
- */
919
- static setClient(newClient) {
920
- this.client = newClient;
335
+ get(name) {
336
+ return this.commands.get(name);
921
337
  }
922
- static createExecutor(constructor, instance) {
923
- const entry = Listener.getEntry(constructor);
924
- if (!entry) {
925
- throw new Error("Missing listener entry");
926
- }
927
- const { hooks } = entry;
928
- return async function(...args) {
929
- const mainHook = hooks["MAIN" /* Main */];
930
- const preHook = hooks["PRE" /* Pre */];
931
- const postHook = hooks["POST" /* Post */];
932
- const errorHook = hooks["ERROR" /* Error */];
933
- if (!mainHook) {
934
- return;
935
- }
338
+ };
339
+ var ListenerOptionsSchema = z3.object({
340
+ name: z3.enum(Events),
341
+ once: z3.boolean().default(false)
342
+ }), Listener = class extends LifecycleManager {
343
+ options;
344
+ constructor(options) {
345
+ let _options = ListenerOptionsSchema.parse(typeof options == "string" ? { name: options } : options);
346
+ super(`listener:${_options.name}`), this.options = options;
347
+ }
348
+ };
349
+ function defineListener(options) {
350
+ return new Listener(options);
351
+ }
352
+
353
+ // src/listener/ListenerManager.ts
354
+ var ListenerManager = class extends BaseClientManager {
355
+ listeners = [];
356
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
357
+ executors = /* @__PURE__ */ new WeakMap();
358
+ async loadModules() {
359
+ let entryDir = posix.resolve(getConfig().entryDir), pattern = posix.join(entryDir, "listeners", "**/*.{ts,js}"), loads = (await glob(pattern, {
360
+ cwd: process.cwd()
361
+ })).map(async (file) => {
936
362
  try {
937
- if (preHook) {
938
- await preHook.method.call(instance, ...args);
363
+ let { default: listener } = await import(pathToFileURL(file).toString());
364
+ if (!listener) {
365
+ console.warn(`[Loader] File has no default export: ${file}`);
366
+ return;
939
367
  }
940
- await mainHook.method.call(instance, ...args);
941
- if (postHook) {
942
- await postHook.method.call(instance, ...args);
368
+ if (!(listener instanceof Listener)) {
369
+ console.warn(`[Loader] Default export is not a Listener: ${file}`);
370
+ return;
943
371
  }
372
+ return this.add(listener), listener;
944
373
  } catch (error) {
945
- if (errorHook) {
946
- await errorHook.method.call(
947
- instance,
948
- error,
949
- ...args
950
- );
951
- } else {
952
- throw error;
953
- }
374
+ console.error(`An error occurred while trying to add listener for '${file}':`, error);
954
375
  }
955
- };
376
+ }), loaded = (await Promise.all(loads)).filter((x) => x !== void 0);
377
+ return console.log(`Loaded ${loaded.length} listener(s).`), loaded;
956
378
  }
957
- /**
958
- * Load and add all listeners which matched provided glob pattern to the registry.
959
- * @param pattern glob pattern to load.
960
- * @param parallel load all matched results in parallel, enabled by default.
961
- * @returns All loaded listener constructors.
962
- */
963
- static async load(pattern, parallel = true) {
964
- const files = await glob2(pattern);
965
- const loaders = files.map(async (file) => {
966
- const fileURL = pathToFileURL2(file).toString();
967
- const { default: constructor } = await import(fileURL);
968
- this.add(constructor);
969
- return constructor;
970
- });
971
- if (parallel) {
972
- return Promise.all(loaders);
973
- }
974
- const result = [];
975
- for (const loader of loaders) {
976
- result.push(await loader);
977
- }
978
- return result;
379
+ add(listener) {
380
+ if (!(listener instanceof Listener))
381
+ throw new Error("Invalid listener provided");
382
+ let execute = (...args) => {
383
+ listener.execute(new Context(), ...args);
384
+ };
385
+ this.listeners.push(listener), this.executors.set(listener, execute);
386
+ let { once, name } = listener.options;
387
+ this.client[once ? "once" : "on"](name, execute);
388
+ }
389
+ remove(target) {
390
+ let isMatched = (listener) => typeof target == "string" ? listener.options.name === target : listener === target, removed = [];
391
+ return this.listeners = this.listeners.filter((listener) => {
392
+ if (!isMatched(listener))
393
+ return true;
394
+ removed.push(listener);
395
+ let execute = this.executors.get(listener);
396
+ return execute && (this.client.removeListener(listener.options.name, execute), this.executors.delete(listener)), false;
397
+ }), removed;
979
398
  }
980
399
  };
981
400
 
982
401
  // src/BakitClient.ts
983
- var BakitClient = class _BakitClient extends Client {
402
+ var BakitClient3 = class extends Client {
403
+ managers;
984
404
  constructor(options) {
985
- if (options.getSyntaxErrorMessage === void 0) {
986
- options.getSyntaxErrorMessage = _BakitClient.getSyntaxErrorMessage;
987
- }
988
- super(options);
989
- ListenerRegistry["setClient"](this);
990
- this.once(
991
- Events.ClientReady,
992
- (client) => void this.registerApplicationCommands(client)
993
- );
994
- this.on(Events.InteractionCreate, (interaction) => void this.handleInteraction(interaction));
995
- this.on(Events.MessageCreate, (message) => void this.handleMessage(message));
996
- }
997
- static getSyntaxErrorMessage = (command, error, context, args, prefix) => {
998
- const requiredSyntax = args.map((x) => Arg.format(x)).join(" ");
999
- const root = Command.getRoot(command.constructor);
1000
- if (!root) {
1001
- return;
1002
- }
1003
- const content = [
1004
- codeBlock(error.message),
1005
- "Required Syntax:",
1006
- codeBlock(`${prefix}${root.options.name} ${requiredSyntax}`)
1007
- ].join("\n");
1008
- return {
1009
- content
405
+ super(options), this.managers = {
406
+ commands: new CommandManager(this),
407
+ listeners: new ListenerManager(this)
1010
408
  };
1011
- };
1012
- async registerApplicationCommands(client) {
1013
- const commands = CommandRegistry.constructors.map((c) => CommandRegistry.buildSlashCommand(c));
1014
- await client.application.commands.set(commands);
1015
409
  }
1016
- async handleMessage(message) {
1017
- if (message.author.bot) {
1018
- return;
1019
- }
1020
- const context = new MessageContext(message);
1021
- const resolver = ArgumentResolver.create(message);
1022
- if (!resolver) {
1023
- return;
1024
- }
1025
- const { trigger } = resolver;
1026
- const command = CommandRegistry.instances.get(trigger);
1027
- if (!command) {
1028
- return;
1029
- }
1030
- await StateBox.run(() => this.handleMessageHooks(context, command, resolver));
410
+ async start(token) {
411
+ let { commands, listeners } = this.managers;
412
+ return await Promise.all([commands.loadModules(), listeners.loadModules()]), await this.login(token);
1031
413
  }
1032
- async handleInteraction(interaction) {
1033
- if (!interaction.isChatInputCommand()) {
1034
- return;
1035
- }
1036
- const { commandName } = interaction;
1037
- const command = CommandRegistry.instances.get(commandName);
1038
- if (!command) {
1039
- return;
1040
- }
1041
- const context = new ChatInputContext(interaction);
1042
- await StateBox.run(() => this.handleChatInputHooks(context, command));
414
+ /**
415
+ * Check if the client is connected to gateway successfully and finished initialization.
416
+ */
417
+ isReady() {
418
+ return super.isReady();
1043
419
  }
1044
- async handleChatInputHooks(context, instance) {
1045
- const targetHooks = this.getChatInputTargetHooks(context.source, instance);
1046
- let inheritedArgs = [];
1047
- for (const hooks of [targetHooks.root, targetHooks.group, targetHooks.subcommand]) {
1048
- if (!hooks) {
1049
- continue;
1050
- }
1051
- const newArgs = await this.runChatInputHooks(context, instance, hooks, inheritedArgs);
1052
- if (newArgs) {
1053
- inheritedArgs = newArgs;
1054
- }
1055
- }
420
+ on(event, listener) {
421
+ return super.on(event, listener);
1056
422
  }
1057
- async handleMessageHooks(context, instance, resolver) {
1058
- if (!resolver) {
1059
- return;
1060
- }
1061
- const root = Command.getRoot(instance.constructor);
1062
- if (!root) {
1063
- return;
1064
- }
1065
- resolver = await this.runMessageHooks(context, instance, root.hooks, resolver);
1066
- if (!resolver) {
1067
- return;
1068
- }
1069
- await this.handleChildMessageHooks(context, root, instance, resolver);
423
+ once(event, listener) {
424
+ return super.once(event, listener);
1070
425
  }
1071
- async handleChildMessageHooks(context, parent, instance, resolver, skip = 1) {
1072
- if (!resolver) {
1073
- return;
1074
- }
1075
- const usedValues = resolver.parsedValues.length;
1076
- const nextTrigger = resolver.values[usedValues + skip];
1077
- const child = parent.children.get(nextTrigger);
1078
- if (!child) {
1079
- return;
1080
- }
1081
- resolver = await this.runMessageHooks(context, instance, child.hooks, resolver);
1082
- if (child instanceof CommandGroupEntry) {
1083
- await this.handleChildMessageHooks(context, child, instance, resolver, skip + 1);
1084
- }
426
+ off(event, listener) {
427
+ return super.off(event, listener);
1085
428
  }
1086
- async runMessageHooks(context, instance, hooks, resolver) {
1087
- const mainHook = hooks["MAIN" /* Main */];
1088
- if (!mainHook) {
1089
- return resolver;
1090
- }
1091
- const args = Arg.getMethodArguments(mainHook.method);
1092
- try {
1093
- resolver = await resolver.resolve(args);
1094
- } catch (error) {
1095
- if (error instanceof CommandSyntaxError) {
1096
- const errorContent = await this.options.getSyntaxErrorMessage?.(
1097
- instance,
1098
- error,
1099
- context,
1100
- args,
1101
- resolver.options.prefix
1102
- );
1103
- if (errorContent) {
1104
- await context.send(errorContent);
1105
- }
1106
- return null;
1107
- }
1108
- throw error;
1109
- }
1110
- await this.runHooks(context, instance, hooks, resolver.parsedValues);
1111
- return resolver;
429
+ removeAllListeners(event) {
430
+ return super.removeAllListeners(event);
1112
431
  }
1113
- async runChatInputHooks(context, instance, hooks, inheritedArgs) {
1114
- const mainHook = hooks["MAIN" /* Main */];
1115
- if (!mainHook) {
1116
- return;
1117
- }
1118
- const newArgs = Arg.getMethodArguments(mainHook.method).map(
1119
- (arg) => ArgumentResolver.resolveChatInput(context.source, arg)
1120
- );
1121
- const argValues = [...inheritedArgs, ...newArgs];
1122
- await this.runHooks(context, instance, hooks, argValues);
1123
- return argValues;
432
+ removeListener(event, listener) {
433
+ return super.removeListener(event, listener);
1124
434
  }
1125
- async runHooks(context, instance, hooks, args) {
1126
- const mainHook = hooks["MAIN" /* Main */];
1127
- const preHook = hooks["PRE" /* Pre */];
1128
- const postHook = hooks["POST" /* Post */];
1129
- const errorHook = hooks["ERROR" /* Error */];
1130
- if (!mainHook) {
1131
- return;
1132
- }
1133
- const execute = async (hook, error) => {
1134
- if (!hook) {
1135
- return;
1136
- }
1137
- if (hook.state === "ERROR" /* Error */) {
1138
- await hook.method.call(instance, error, context, ...args);
1139
- } else {
1140
- await hook.method.call(instance, context, ...args);
1141
- }
1142
- };
1143
- try {
1144
- await execute(preHook);
1145
- await execute(mainHook);
1146
- await execute(postHook);
1147
- } catch (error) {
1148
- if (errorHook) {
1149
- await execute(errorHook, error);
1150
- } else {
1151
- throw error;
1152
- }
1153
- }
435
+ emit(event, ...args) {
436
+ return super.emit(event, ...args);
1154
437
  }
1155
- getChatInputTargetHooks(interaction, instance) {
1156
- const subcommandName = interaction.options.getSubcommand(false);
1157
- const groupName = interaction.options.getSubcommandGroup(false);
1158
- const root = Command.getRoot(instance.constructor);
1159
- if (!root) {
1160
- throw new Error("No root found.");
1161
- }
1162
- let group;
1163
- if (groupName) {
1164
- const child = root.children.get(groupName);
1165
- if (child instanceof CommandGroupEntry) {
1166
- group = child;
1167
- }
1168
- }
1169
- let subcommand;
1170
- if (subcommandName) {
1171
- const parent = group || root;
1172
- const child = parent.children.get(subcommandName);
1173
- if (child instanceof SubcommandEntry) {
1174
- subcommand = child;
1175
- }
1176
- }
1177
- return {
1178
- root: root.hooks,
1179
- group: group?.hooks,
1180
- subcommand: subcommand?.hooks
1181
- };
438
+ /**
439
+ * Override BakitClient output when using logger for security concern.
440
+ * @returns `BakitClient {}`
441
+ */
442
+ [inspect.custom]() {
443
+ return `${this.constructor.name} {}`;
1182
444
  }
1183
445
  };
1184
- export {
1185
- Arg,
1186
- ArgumentType,
1187
- BakitClient,
1188
- BaseCommandEntry,
1189
- BaseCommandGroupEntry,
1190
- BaseContext,
1191
- ChatInputContext,
1192
- Command,
1193
- CommandAPI,
1194
- CommandFactory,
1195
- CommandGroupEntry,
1196
- CommandRegistry,
1197
- CommandSyntaxError,
1198
- CommandSyntaxErrorType,
1199
- Listener,
1200
- ListenerAPI,
1201
- ListenerEntry,
1202
- ListenerFactory,
1203
- ListenerRegistry,
1204
- MessageContext,
1205
- RootCommandEntry,
1206
- StateBox,
1207
- SubcommandEntry,
1208
- extractId
446
+ var ParamUserType = /* @__PURE__ */ ((ParamUserType2) => (ParamUserType2.Bot = "bot", ParamUserType2.Normal = "normal", ParamUserType2.Any = "any", ParamUserType2))(ParamUserType || {}), BaseParamSchema = z.object({
447
+ name: z.string(),
448
+ description: z.string().optional(),
449
+ required: z.boolean().default(true)
450
+ }), StringParamSchema = BaseParamSchema.extend({
451
+ maxLength: z.number().min(1).optional(),
452
+ minLength: z.number().min(1).optional()
453
+ }), NumberParamSchema = BaseParamSchema.extend({
454
+ maxValue: z.number().optional(),
455
+ minValue: z.number().optional()
456
+ });
457
+
458
+ // src/command/param/Params.ts
459
+ function createFactory(ctor) {
460
+ return (...args) => new ctor(...args);
461
+ }
462
+ var Params = {
463
+ string: createFactory(StringParam),
464
+ number: createFactory(NumberParam)
1209
465
  };
466
+
467
+ export { BakitClient3 as BakitClient, BaseCommandContext, BaseParam, BaseParamSchema, ChatInputContext, Command, CommandManager, CommandOptionsSchema, Listener, ListenerManager, ListenerOptionsSchema, MessageContext, NumberParam, NumberParamSchema, ParamUserType, Params, ProjectConfigSchema, StringParam, StringParamSchema, defineCommand, defineConfig, defineListener, getConfig, loadConfig };