bakit 1.0.0-beta.8 → 2.0.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,1209 +1,61 @@
1
- // src/index.ts
2
- import "reflect-metadata";
3
-
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 (target.constructor !== this.target) {
58
- throw new Error("Hook is used at unknown 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);
1
+ import { GatewayIntentBits, Client } from 'discord.js';
2
+ import { z } from 'zod';
3
+ import { pathToFileURL } from 'url';
4
+ import glob from 'tiny-glob';
5
+
6
+ // src/config.ts
7
+ var ProjectConfigSchema = z.object({
8
+ intents: z.union([z.literal("auto"), z.bigint(), z.array(z.enum(GatewayIntentBits))]).default("auto"),
9
+ clientOptions: z.custom().optional()
10
+ });
11
+ function defineConfig(config) {
12
+ return config;
140
13
  }
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();
250
- /**
251
- * Add a command to the registry.
252
- * @param constructor The command class you want to add.
253
- */
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
- }
263
- /**
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.
268
- */
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
- }
286
- /**
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.
290
- */
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
- }
390
- }
391
- };
392
-
393
- // src/command/Context.ts
394
- import {
395
- ChatInputCommandInteraction,
396
- Message
397
- } from "discord.js";
398
- var BaseContext = class {
399
- constructor(source) {
400
- this.source = source;
401
- }
402
- get client() {
403
- return this.source.client;
404
- }
405
- get channel() {
406
- return this.source.channel;
407
- }
408
- get channelId() {
409
- return this.source.channelId;
410
- }
411
- get guild() {
412
- return this.source.guild;
413
- }
414
- get guildId() {
415
- return this.source.guildId;
416
- }
417
- inGuild() {
418
- return Boolean(this.guildId);
419
- }
420
- inCachedGuild() {
421
- if (this.isChatInput()) {
422
- return this.source.inCachedGuild();
423
- } else if (this.isMessage()) {
424
- return this.source.inGuild();
425
- } else {
426
- throw new Error("Invalid source");
427
- }
428
- }
429
- get author() {
430
- if (this.isChatInput()) {
431
- return this.source.user;
432
- } else if (this.isMessage()) {
433
- return this.source.author;
434
- } else {
435
- throw new Error("Invalid source");
436
- }
437
- }
438
- isChatInput() {
439
- return this.source instanceof ChatInputCommandInteraction;
440
- }
441
- isMessage() {
442
- return this.source instanceof Message;
443
- }
444
- };
445
- var ChatInputContext = class extends BaseContext {
446
- async send(options) {
447
- if (typeof options === "string") {
448
- options = { content: options };
449
- }
450
- const sendOptions = {
451
- ...options,
452
- withResponse: true
453
- };
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;
459
- }
460
- };
461
- var MessageContext = class extends BaseContext {
462
- async send(options) {
463
- const { channel } = this;
464
- if (!channel?.isSendable()) {
465
- throw new Error("Invalid channel or channel is not sendable");
466
- }
467
- return await channel.send(options);
468
- }
469
- };
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];
480
- }
481
- return null;
14
+ var _config;
15
+ async function loadConfig(cwd = process.cwd()) {
16
+ if (_config)
17
+ return console.warn("loadConfig() was called more than once. This shouldn't happen."), _config;
18
+ let globPattern = `bakit.config.{${["ts", "js"].join(",")}}`, [configPath, other] = await glob(globPattern, {
19
+ cwd: cwd.replace(/\\/g, "/"),
20
+ // ensure the path uses `/` instead of `\` on Windows
21
+ absolute: true
22
+ });
23
+ if (!configPath)
24
+ throw new Error("Missing config file");
25
+ other && console.warn(`Multiple config files found in ${cwd}. Using ${configPath}.`);
26
+ let configFileURL = pathToFileURL(configPath).toString(), { default: config } = await import(configFileURL);
27
+ return _config = Object.freeze(await ProjectConfigSchema.parseAsync(config)), _config;
482
28
  }
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");
511
- 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");
519
- break;
520
- }
521
- default: {
522
- message = "Unknown error";
523
- break;
524
- }
525
- }
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
- }
536
- };
537
-
538
- // src/command/argument/ArgumentResolver.ts
539
- var ArgumentResolver = class _ArgumentResolver {
540
- 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];
549
- }
550
- /**
551
- * Get amount of specified argument values.
552
- */
553
- get specifiedAmount() {
554
- return this.options.values.length - this.options.startAt;
555
- }
556
- /**
557
- * Get parsed raw values from content.
558
- */
559
- get values() {
560
- return [...this.options.values];
561
- }
562
- get client() {
563
- return this.options.message.client;
564
- }
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
- });
587
- }
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;
717
- }
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;
730
- }
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;
743
- }
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;
752
- }
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
- }
768
- }
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;
782
- }
783
- static run(fn, store = {}) {
784
- return this.storage.run(store, fn);
785
- }
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);
792
- }
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
- };
811
- }
812
- };
813
-
814
- // src/listener/ListenerEntry.ts
815
- var ListenerEntry = class extends BaseEntry {
816
- constructor(options) {
817
- super();
818
- this.options = options;
819
- }
820
- };
821
-
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
- };
830
- }
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);
29
+ function getConfig() {
30
+ if (!_config)
31
+ throw new Error("Project config is not loaded.");
32
+ return _config;
840
33
  }
841
- var Listener = Object.assign(ListenerFactory, ListenerAPI);
842
-
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.");
865
- }
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
- });
876
- }
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;
896
- }
897
- const { name, emitter } = entry.options;
898
- emitter?.removeListener(name, executor);
899
- this.executors.delete(instance);
900
- return true;
901
- }
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;
914
- }
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;
921
- }
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
- }
936
- try {
937
- if (preHook) {
938
- await preHook.method.call(instance, ...args);
939
- }
940
- await mainHook.method.call(instance, ...args);
941
- if (postHook) {
942
- await postHook.method.call(instance, ...args);
943
- }
944
- } catch (error) {
945
- if (errorHook) {
946
- await errorHook.method.call(
947
- instance,
948
- error,
949
- ...args
950
- );
951
- } else {
952
- throw error;
953
- }
954
- }
955
- };
956
- }
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;
979
- }
980
- };
981
-
982
- // src/BakitClient.ts
983
- var BakitClient = class _BakitClient extends Client {
34
+ var BakitClient = class extends Client {
984
35
  constructor(options) {
985
- if (options.getSyntaxErrorMessage === void 0) {
986
- options.getSyntaxErrorMessage = _BakitClient.getSyntaxErrorMessage;
987
- }
988
36
  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
1010
- };
1011
- };
1012
- async registerApplicationCommands(client) {
1013
- const commands = CommandRegistry.constructors.map((c) => CommandRegistry.buildSlashCommand(c));
1014
- await client.application.commands.set(commands);
1015
- }
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));
1031
37
  }
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));
38
+ isReady() {
39
+ return super.isReady();
1043
40
  }
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
- }
41
+ on(event, listener) {
42
+ return super.on(event, listener);
1056
43
  }
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);
44
+ once(event, listener) {
45
+ return super.once(event, listener);
1070
46
  }
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
- }
47
+ off(event, listener) {
48
+ return super.off(event, listener);
1085
49
  }
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;
50
+ removeAllListeners(event) {
51
+ return super.removeAllListeners(event);
1112
52
  }
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;
53
+ removeListener(event, listener) {
54
+ return super.removeListener(event, listener);
1124
55
  }
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
- }
56
+ emit(event, ...args) {
57
+ return super.emit(event, ...args);
1154
58
  }
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
- };
1182
- }
1183
- };
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
1209
59
  };
60
+
61
+ export { BakitClient, defineConfig, getConfig, loadConfig };