bakit 1.0.0-beta.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 ADDED
@@ -0,0 +1,1020 @@
1
+ // src/BakitClient.ts
2
+ import {
3
+ Client,
4
+ codeBlock,
5
+ Events
6
+ } from "discord.js";
7
+
8
+ // src/command/CommandRegistry.ts
9
+ import {
10
+ Collection as Collection2,
11
+ SlashCommandBuilder,
12
+ SlashCommandSubcommandBuilder,
13
+ SlashCommandSubcommandGroupBuilder
14
+ } from "discord.js";
15
+ import glob from "tiny-glob";
16
+ import { pathToFileURL } from "url";
17
+
18
+ // src/command/CommandEntry.ts
19
+ import { Collection } from "discord.js";
20
+
21
+ // src/command/argument/Argument.ts
22
+ var ArgumentType = /* @__PURE__ */ ((ArgumentType2) => {
23
+ ArgumentType2["String"] = "string";
24
+ ArgumentType2["Integer"] = "integer";
25
+ ArgumentType2["Number"] = "number";
26
+ ArgumentType2["User"] = "user";
27
+ ArgumentType2["Member"] = "member";
28
+ return ArgumentType2;
29
+ })(ArgumentType || {});
30
+
31
+ // src/command/argument/Arg.ts
32
+ var ARGS_KEY = Symbol("args");
33
+ var Arg = class _Arg {
34
+ static cache = /* @__PURE__ */ new WeakMap();
35
+ static string = _Arg.createArgument("string" /* String */);
36
+ static integer = _Arg.createArgument("integer" /* Integer */);
37
+ static number = _Arg.createArgument("number" /* Number */);
38
+ static user = _Arg.createArgument("user" /* User */);
39
+ static member = _Arg.createArgument("member" /* Member */);
40
+ static getMethodArguments(method, init = false) {
41
+ let args = this.cache.get(method) ?? Reflect.getMetadata(ARGS_KEY, method);
42
+ if (!args) {
43
+ args = [];
44
+ if (init) {
45
+ Reflect.defineMetadata(ARGS_KEY, args, method);
46
+ this.cache.set(method, args);
47
+ }
48
+ }
49
+ return init ? args : Object.freeze([...args]);
50
+ }
51
+ static format(arg) {
52
+ const { name, required, tuple } = arg;
53
+ const opening = required ? "<" : "[";
54
+ const closing = required ? ">" : "]";
55
+ const prefix = tuple ? "..." : "";
56
+ return `${opening}${prefix}${name}: ${this.describeArgumentExpectation(arg)}${closing}`;
57
+ }
58
+ static describeArgumentExpectation(arg) {
59
+ const parts = [arg.type];
60
+ switch (arg.type) {
61
+ case "string" /* String */: {
62
+ if (arg.minLength && !arg.maxLength) {
63
+ parts.push(`\u2265 ${String(arg.minLength)}`);
64
+ }
65
+ if (!arg.minLength && arg.maxLength) {
66
+ parts.push(`\u2264 ${String(arg.maxLength)}`);
67
+ }
68
+ if (arg.minLength && arg.maxLength) {
69
+ parts.push(`${String(arg.minLength)} - ${String(arg.maxLength)}`);
70
+ }
71
+ break;
72
+ }
73
+ case "number" /* Number */:
74
+ case "integer" /* Integer */: {
75
+ if (arg.minValue !== void 0 && arg.maxValue === void 0) {
76
+ parts.push(`\u2265 ${String(arg.minValue)}`);
77
+ }
78
+ if (arg.minValue === void 0 && arg.maxValue !== void 0) {
79
+ parts.push(`\u2264 ${String(arg.maxValue)}`);
80
+ }
81
+ if (arg.minValue !== void 0 && arg.maxValue !== void 0) {
82
+ parts.push(`${String(arg.minValue)} - ${String(arg.maxValue)}`);
83
+ }
84
+ break;
85
+ }
86
+ case "user" /* User */:
87
+ case "member" /* Member */: {
88
+ break;
89
+ }
90
+ }
91
+ return parts.join(", ");
92
+ }
93
+ static createArgument(type) {
94
+ return function(options) {
95
+ const objOptions = typeof options === "string" ? { name: options } : options;
96
+ const fullOptions = { ...objOptions, type };
97
+ if (!fullOptions.description) {
98
+ fullOptions.description = fullOptions.name;
99
+ }
100
+ if (!("required" in fullOptions)) {
101
+ fullOptions.required = true;
102
+ }
103
+ return function(target, key, _index) {
104
+ const method = Object.getOwnPropertyDescriptor(target, key)?.value;
105
+ if (!method) {
106
+ throw new Error("No method found");
107
+ }
108
+ const args = _Arg.getMethodArguments(method, true);
109
+ args.unshift(fullOptions);
110
+ };
111
+ };
112
+ }
113
+ };
114
+
115
+ // src/command/CommandEntry.ts
116
+ var HookExecutionState = /* @__PURE__ */ ((HookExecutionState2) => {
117
+ HookExecutionState2["Main"] = "main";
118
+ HookExecutionState2["Pre"] = "pre";
119
+ HookExecutionState2["Post"] = "post";
120
+ HookExecutionState2["Error"] = "error";
121
+ return HookExecutionState2;
122
+ })(HookExecutionState || {});
123
+ var HOOKS_KEY = Symbol("hooks");
124
+ var BaseCommandEntry = class _BaseCommandEntry {
125
+ constructor(options) {
126
+ this.options = options;
127
+ }
128
+ static cache = /* @__PURE__ */ new WeakMap();
129
+ main = _BaseCommandEntry.createMainHookDecorator("main" /* Main */, this);
130
+ pre = _BaseCommandEntry.createMainHookDecorator("pre" /* Pre */, this);
131
+ post = _BaseCommandEntry.createMainHookDecorator("post" /* Post */, this);
132
+ error = _BaseCommandEntry.createErrorHookDecorator("error" /* Error */, this);
133
+ static getHooks(constructor, init = false) {
134
+ let hooks = this.cache.get(constructor) ?? Reflect.getMetadata(HOOKS_KEY, constructor);
135
+ if (!hooks) {
136
+ hooks = [];
137
+ if (init) {
138
+ Reflect.defineMetadata(HOOKS_KEY, hooks, constructor);
139
+ this.cache.set(constructor, hooks);
140
+ }
141
+ }
142
+ return init ? hooks : Object.freeze([...hooks]);
143
+ }
144
+ static createMainHookDecorator(state, entry) {
145
+ return (target, _key, descriptor) => {
146
+ this.addHook(target, state, descriptor.value, entry);
147
+ };
148
+ }
149
+ static createErrorHookDecorator(state, entry) {
150
+ return (target, _key, descriptor) => {
151
+ this.addHook(target, state, descriptor.value, entry);
152
+ };
153
+ }
154
+ static addHook(target, state, method, entry) {
155
+ const { constructor } = target;
156
+ const hooks = _BaseCommandEntry.getHooks(constructor, true);
157
+ if (typeof method !== "function") {
158
+ throw new Error("CommandEntry decorator must be used with a class method.");
159
+ }
160
+ if (hooks.some((hook) => hook.state === state && hook.entry === entry)) {
161
+ throw new Error(`Hook "${state}" is already defined for entry "${entry.options.name}".`);
162
+ }
163
+ if ("parent" in entry) {
164
+ const parentHook = hooks.find(
165
+ (hook) => hook.entry === entry.parent && hook.state === "main" /* Main */
166
+ );
167
+ if (parentHook) {
168
+ const parentArgs = Arg.getMethodArguments(parentHook.method);
169
+ if (parentArgs.at(-1)?.tuple) {
170
+ throw new Error(
171
+ `Cannot add hook "${state}" to entry "${entry.options.name}" because its parent "${entry.parent.options.name}" has a tuple argument.`
172
+ );
173
+ }
174
+ }
175
+ }
176
+ hooks.push({
177
+ state,
178
+ entry,
179
+ method
180
+ });
181
+ }
182
+ };
183
+ var BaseCommandGroupEntry = class extends BaseCommandEntry {
184
+ children = new Collection();
185
+ subcommand(options) {
186
+ if (typeof options === "string") {
187
+ options = { name: options };
188
+ }
189
+ if (!options.description) {
190
+ options.description = options.name;
191
+ }
192
+ if (this.children.has(options.name)) {
193
+ throw new Error(`Entry with name "${options.name}" already exists.`);
194
+ }
195
+ if (!(this instanceof CommandGroupEntry) && !(this instanceof RootCommandEntry)) {
196
+ throw new Error(`Invalid parent "${this.constructor.name}"`);
197
+ }
198
+ const entry = new SubcommandEntry(options, this);
199
+ this.children.set(entry.options.name, entry);
200
+ return entry;
201
+ }
202
+ };
203
+ var CommandGroupEntry = class extends BaseCommandGroupEntry {
204
+ constructor(options, parent) {
205
+ super(options);
206
+ this.options = options;
207
+ this.parent = parent;
208
+ }
209
+ };
210
+ var RootCommandEntry = class extends BaseCommandGroupEntry {
211
+ constructor(options) {
212
+ super(options);
213
+ this.options = options;
214
+ }
215
+ group(options) {
216
+ if (typeof options === "string") {
217
+ options = { name: options };
218
+ }
219
+ if (!options.description) {
220
+ options.description = options.name;
221
+ }
222
+ if (this.children.has(options.name)) {
223
+ throw new Error(`Entry with name "${options.name}" already exists.`);
224
+ }
225
+ const entry = new CommandGroupEntry(options, this);
226
+ this.children.set(entry.options.name, entry);
227
+ return entry;
228
+ }
229
+ };
230
+ var SubcommandEntry = class extends BaseCommandEntry {
231
+ constructor(options, parent) {
232
+ super(options);
233
+ this.options = options;
234
+ this.parent = parent;
235
+ }
236
+ };
237
+
238
+ // src/command/Command.ts
239
+ var ROOT_KEY = Symbol("root");
240
+ var Command = class {
241
+ static create(options) {
242
+ if (typeof options === "string") {
243
+ options = { name: options };
244
+ }
245
+ if (!options.description) {
246
+ options.description = options.name;
247
+ }
248
+ return new RootCommandEntry(options);
249
+ }
250
+ static use(command) {
251
+ return (target) => {
252
+ Reflect.defineMetadata(ROOT_KEY, command, target);
253
+ };
254
+ }
255
+ static getRoot(constructor) {
256
+ return Reflect.getMetadata(ROOT_KEY, constructor);
257
+ }
258
+ };
259
+
260
+ // src/command/CommandRegistry.ts
261
+ var CommandRegistry = class _CommandRegistry {
262
+ static constructors = new Collection2();
263
+ static instances = new Collection2();
264
+ static add(constructor) {
265
+ const root = Command.getRoot(constructor);
266
+ if (!root) {
267
+ throw new Error(`No root found for "${constructor.name}"`);
268
+ }
269
+ const { options } = root;
270
+ this.constructors.set(options.name, constructor);
271
+ this.instances.set(options.name, new constructor());
272
+ }
273
+ static buildSlashCommand(constructor) {
274
+ const builder = new SlashCommandBuilder();
275
+ const root = Command.getRoot(constructor);
276
+ if (!root) {
277
+ throw new Error(`No root found for "${constructor.name}"`);
278
+ }
279
+ const { options } = root;
280
+ builder.setName(options.name);
281
+ builder.setDescription(options.description || "");
282
+ builder.setNSFW(Boolean(options.nsfw));
283
+ this.buildSlashCommandOptions(builder, constructor);
284
+ return builder.toJSON();
285
+ }
286
+ static async loadDirectory(pattern, parallel = true) {
287
+ const files = await glob(pattern);
288
+ const loaders = files.map(async (file) => {
289
+ const fileURL = pathToFileURL(file).toString();
290
+ const { default: constructor } = await import(fileURL);
291
+ _CommandRegistry.add(constructor);
292
+ return constructor;
293
+ });
294
+ if (parallel) {
295
+ return await Promise.all(loaders);
296
+ }
297
+ const result = [];
298
+ for (const loader of loaders) {
299
+ result.push(await loader);
300
+ }
301
+ return result;
302
+ }
303
+ static buildSlashCommandOptions(builder, constructor) {
304
+ const root = Command.getRoot(constructor);
305
+ if (!root) {
306
+ throw new Error(`No root found for "${constructor.name}"`);
307
+ }
308
+ const hooks = new Collection2(
309
+ BaseCommandEntry.getHooks(constructor).filter((hook) => hook.state === "main" /* Main */).map((hook) => [hook.entry, hook])
310
+ );
311
+ const rootHook = hooks.get(root);
312
+ if (!root.children.size && hooks.size) {
313
+ if (!rootHook) {
314
+ return;
315
+ }
316
+ for (const arg of Arg.getMethodArguments(rootHook.method)) {
317
+ this.buildSlashCommandOption(builder, arg);
318
+ }
319
+ return;
320
+ }
321
+ for (const child of root.children.values()) {
322
+ const hook = hooks.get(child);
323
+ const inheritedArgs = [];
324
+ if (rootHook) {
325
+ inheritedArgs.push(...Arg.getMethodArguments(rootHook.method));
326
+ }
327
+ if (child instanceof SubcommandEntry) {
328
+ this.buildSubcommand(builder, child, hook, inheritedArgs);
329
+ } else if (child instanceof CommandGroupEntry) {
330
+ if (hook) {
331
+ inheritedArgs.push(...Arg.getMethodArguments(hook.method));
332
+ }
333
+ const { options } = child;
334
+ const group = new SlashCommandSubcommandGroupBuilder().setName(options.name).setDescription(options.description);
335
+ for (const subChild of child.children.values()) {
336
+ this.buildSubcommand(group, subChild, hooks.get(subChild), inheritedArgs);
337
+ }
338
+ builder.addSubcommandGroup(group);
339
+ }
340
+ }
341
+ }
342
+ static buildSubcommand(parent, entry, hook, inheritedArgs) {
343
+ const { options } = entry;
344
+ const subcommand = new SlashCommandSubcommandBuilder().setName(options.name).setDescription(options.description);
345
+ const args = [...inheritedArgs];
346
+ if (hook) {
347
+ args.push(...Arg.getMethodArguments(hook.method));
348
+ }
349
+ for (const arg of args) {
350
+ this.buildSlashCommandOption(subcommand, arg);
351
+ }
352
+ parent.addSubcommand(subcommand);
353
+ }
354
+ static buildSlashCommandOption(builder, arg) {
355
+ const setupOption = (option) => {
356
+ return option.setName(arg.name).setDescription(arg.description || arg.name).setRequired(Boolean(arg.required));
357
+ };
358
+ switch (arg.type) {
359
+ case "string" /* String */: {
360
+ builder.addStringOption((option) => setupOption(option));
361
+ break;
362
+ }
363
+ case "integer" /* Integer */: {
364
+ builder.addIntegerOption((option) => setupOption(option));
365
+ break;
366
+ }
367
+ case "number" /* Number */: {
368
+ builder.addNumberOption((option) => setupOption(option));
369
+ break;
370
+ }
371
+ case "user" /* User */:
372
+ case "member" /* Member */: {
373
+ builder.addUserOption((option) => setupOption(option));
374
+ break;
375
+ }
376
+ }
377
+ }
378
+ };
379
+
380
+ // src/command/index.ts
381
+ import "reflect-metadata";
382
+
383
+ // src/command/Context.ts
384
+ import {
385
+ ChatInputCommandInteraction,
386
+ Message
387
+ } from "discord.js";
388
+ var BaseContext = class {
389
+ constructor(source) {
390
+ this.source = source;
391
+ }
392
+ get client() {
393
+ return this.source.client;
394
+ }
395
+ get channel() {
396
+ return this.source.channel;
397
+ }
398
+ get channelId() {
399
+ return this.source.channelId;
400
+ }
401
+ get guild() {
402
+ return this.source.guild;
403
+ }
404
+ get guildId() {
405
+ return this.source.guildId;
406
+ }
407
+ inGuild() {
408
+ return Boolean(this.guildId);
409
+ }
410
+ inCachedGuild() {
411
+ if (this.isChatInput()) {
412
+ return this.source.inCachedGuild();
413
+ } else if (this.isMessage()) {
414
+ return this.source.inGuild();
415
+ } else {
416
+ throw new Error("Invalid source");
417
+ }
418
+ }
419
+ get author() {
420
+ if (this.isChatInput()) {
421
+ return this.source.user;
422
+ } else if (this.isMessage()) {
423
+ return this.source.author;
424
+ } else {
425
+ throw new Error("Invalid source");
426
+ }
427
+ }
428
+ isChatInput() {
429
+ return this.source instanceof ChatInputCommandInteraction;
430
+ }
431
+ isMessage() {
432
+ return this.source instanceof Message;
433
+ }
434
+ };
435
+ var ChatInputContext = class extends BaseContext {
436
+ async send(options) {
437
+ if (typeof options === "string") {
438
+ options = { content: options };
439
+ }
440
+ const sendOptions = {
441
+ ...options,
442
+ withResponse: true
443
+ };
444
+ if (this.source.deferred || this.source.replied) {
445
+ return await this.source.followUp(sendOptions);
446
+ }
447
+ const response = await this.source.reply(sendOptions);
448
+ return response.resource?.message;
449
+ }
450
+ };
451
+ var MessageContext = class extends BaseContext {
452
+ async send(options) {
453
+ const { channel } = this;
454
+ if (!channel?.isSendable()) {
455
+ throw new Error("Invalid channel or channel is not sendable");
456
+ }
457
+ return await channel.send(options);
458
+ }
459
+ };
460
+
461
+ // src/utils/user.ts
462
+ function extractId(value) {
463
+ const idMatch = value.match(/^<@!?(\d+)>$/);
464
+ if (idMatch) {
465
+ return idMatch[1];
466
+ }
467
+ const numericMatch = value.match(/^(\d{17,19})$/);
468
+ if (numericMatch) {
469
+ return numericMatch[1];
470
+ }
471
+ return null;
472
+ }
473
+
474
+ // src/errors/CommandSyntaxError.ts
475
+ var CommandSyntaxErrorType = /* @__PURE__ */ ((CommandSyntaxErrorType2) => {
476
+ CommandSyntaxErrorType2["MissingRequireArgument"] = "MISSING_REQUIRE_ARGUMENT";
477
+ CommandSyntaxErrorType2["InvalidArgument"] = "INVALID_ARGUMENT";
478
+ CommandSyntaxErrorType2["InvalidVariadicArgumentValue"] = "INVALID_VARIADIC_ARGUMENT_VALUE";
479
+ return CommandSyntaxErrorType2;
480
+ })(CommandSyntaxErrorType || {});
481
+ var CommandSyntaxError = class extends Error {
482
+ arg;
483
+ type;
484
+ expected;
485
+ received;
486
+ constructor(options) {
487
+ let message;
488
+ const { arg, type, received } = options;
489
+ const expected = Arg.describeArgumentExpectation(arg);
490
+ switch (type) {
491
+ case "MISSING_REQUIRE_ARGUMENT" /* MissingRequireArgument */: {
492
+ message = [`Missing required argument "${arg.name}"`, `> Expected: ${expected}`].join("\n");
493
+ break;
494
+ }
495
+ case "INVALID_ARGUMENT" /* InvalidArgument */: {
496
+ message = [
497
+ `Invalid value received for argument "${arg.name}"`,
498
+ `> Expected: ${expected}`,
499
+ `> Received: ${String(received)}`
500
+ ].join("\n");
501
+ break;
502
+ }
503
+ case "INVALID_VARIADIC_ARGUMENT_VALUE" /* InvalidVariadicArgumentValue */: {
504
+ message = [
505
+ `Invalid value received for variadic argument "${arg.name}"`,
506
+ `> Expected: ${expected}`,
507
+ `> Received: ${String(received)}`
508
+ ].join("\n");
509
+ break;
510
+ }
511
+ default: {
512
+ message = "Unknown error";
513
+ break;
514
+ }
515
+ }
516
+ super(message);
517
+ this.arg = arg;
518
+ this.type = type;
519
+ this.expected = expected;
520
+ this.received = received;
521
+ Error.captureStackTrace(this, this.constructor);
522
+ }
523
+ get name() {
524
+ return `CommandSyntaxError[${this.type}]`;
525
+ }
526
+ };
527
+
528
+ // src/command/argument/ArgumentResolver.ts
529
+ var ArgumentResolver = class _ArgumentResolver {
530
+ constructor(options) {
531
+ this.options = options;
532
+ }
533
+ parsedValues = [];
534
+ /**
535
+ * Get the first value as the command trigger.
536
+ */
537
+ get trigger() {
538
+ return this.options.values[0];
539
+ }
540
+ /**
541
+ * Get amount of specified argument values.
542
+ */
543
+ get specifiedAmount() {
544
+ return this.options.values.length - this.options.startAt;
545
+ }
546
+ /**
547
+ * Get parsed raw values from content.
548
+ */
549
+ get values() {
550
+ return [...this.options.values];
551
+ }
552
+ get client() {
553
+ return this.options.message.client;
554
+ }
555
+ static create(message) {
556
+ const client = message.client;
557
+ const { enableMentionPrefix } = client.options;
558
+ const prefixes = [
559
+ // Custom prefixes specified in options
560
+ ...client.options.prefixes ?? [],
561
+ // Use bot mention as prefix if enabled
562
+ ...enableMentionPrefix ? [client.user.toString()] : []
563
+ ];
564
+ const prefix = prefixes.find((p) => message.content.startsWith(p)) ?? null;
565
+ if (!prefix) {
566
+ return;
567
+ }
568
+ const values = message.content.slice(prefix.length).trim().split(/\s+/);
569
+ return new _ArgumentResolver({
570
+ message,
571
+ startAt: 1,
572
+ // Skip the command trigger
573
+ values,
574
+ args: [],
575
+ prefix
576
+ });
577
+ }
578
+ async resolve(args) {
579
+ const child = new _ArgumentResolver({
580
+ prefix: this.options.prefix,
581
+ message: this.options.message,
582
+ values: this.options.values,
583
+ args,
584
+ startAt: this.options.startAt
585
+ });
586
+ child.parsedValues = [...this.parsedValues];
587
+ if (!child.options.args.length) {
588
+ return child;
589
+ }
590
+ if (this.specifiedAmount >= child.options.args.length) {
591
+ await child.absoluteParse();
592
+ } else {
593
+ await child.dynamicParse();
594
+ }
595
+ return child;
596
+ }
597
+ async absoluteParse() {
598
+ const { args, values, startAt } = this.options;
599
+ let valueIndex = startAt;
600
+ let argIndex = 0;
601
+ while (valueIndex < values.length && argIndex < args.length) {
602
+ const value = values[valueIndex];
603
+ const arg = args[argIndex];
604
+ if (arg.tuple) {
605
+ this.parsedValues.push(...await this.resolveTuple(arg, valueIndex, argIndex));
606
+ break;
607
+ }
608
+ const matchedValue = await this.matchValue(arg, value);
609
+ if (matchedValue === null) {
610
+ throw new CommandSyntaxError({
611
+ arg,
612
+ type: "INVALID_ARGUMENT" /* InvalidArgument */,
613
+ received: value
614
+ });
615
+ }
616
+ this.parsedValues.push(matchedValue);
617
+ valueIndex++;
618
+ argIndex++;
619
+ }
620
+ }
621
+ async dynamicParse() {
622
+ const { args, values } = this.options;
623
+ let argIndex = 0;
624
+ let valueIndex = this.options.startAt + 1;
625
+ while (valueIndex < values.length && argIndex < args.length) {
626
+ const value = values[valueIndex];
627
+ const arg = args[argIndex];
628
+ if (arg.tuple) {
629
+ this.parsedValues.push(...await this.resolveTuple(arg, valueIndex, argIndex));
630
+ break;
631
+ }
632
+ const matchedValue = await this.matchValue(arg, value);
633
+ if (matchedValue !== null) {
634
+ this.parsedValues.push(matchedValue);
635
+ valueIndex++;
636
+ } else if (arg.required) {
637
+ throw new CommandSyntaxError({
638
+ arg,
639
+ type: "MISSING_REQUIRE_ARGUMENT" /* MissingRequireArgument */,
640
+ received: value
641
+ });
642
+ }
643
+ argIndex++;
644
+ }
645
+ while (argIndex < args.length) {
646
+ const arg = args[argIndex];
647
+ if (arg.required) {
648
+ throw new CommandSyntaxError({
649
+ arg,
650
+ type: "MISSING_REQUIRE_ARGUMENT" /* MissingRequireArgument */,
651
+ received: "nothing"
652
+ });
653
+ }
654
+ argIndex++;
655
+ }
656
+ }
657
+ async resolveTuple(arg, startIndex, argIndex) {
658
+ const { args } = this.options;
659
+ if (argIndex !== args.length - 1) {
660
+ throw new SyntaxError("Tuple argument must be the last argument");
661
+ }
662
+ const values = [];
663
+ for (const rest of this.values.slice(startIndex)) {
664
+ const matchedValue = await this.matchValue(arg, rest);
665
+ if (matchedValue === null) {
666
+ throw new CommandSyntaxError({
667
+ arg,
668
+ type: "INVALID_VARIADIC_ARGUMENT_VALUE" /* InvalidVariadicArgumentValue */,
669
+ received: rest
670
+ });
671
+ }
672
+ values.push(matchedValue);
673
+ }
674
+ if (values.length === 0 && arg.required) {
675
+ throw new CommandSyntaxError({
676
+ arg,
677
+ type: "MISSING_REQUIRE_ARGUMENT" /* MissingRequireArgument */,
678
+ received: "nothing"
679
+ });
680
+ }
681
+ return values;
682
+ }
683
+ async matchValue(arg, value) {
684
+ switch (arg.type) {
685
+ case "user" /* User */:
686
+ return await this.matchUserValue(arg, value);
687
+ case "integer" /* Integer */:
688
+ return this.matchIntegerValue(arg, value);
689
+ case "number" /* Number */:
690
+ return this.matchNumberValue(arg, value);
691
+ case "string" /* String */:
692
+ return this.matchStringValue(arg, value);
693
+ default:
694
+ return null;
695
+ }
696
+ }
697
+ async matchUserValue(arg, value) {
698
+ const userId = extractId(value);
699
+ if (!userId) {
700
+ return null;
701
+ }
702
+ const user = await this.client.users.fetch(userId).catch(() => null);
703
+ if (!user) {
704
+ return null;
705
+ }
706
+ return user;
707
+ }
708
+ matchIntegerValue(arg, value) {
709
+ const intVal = parseInt(value, 10);
710
+ if (isNaN(intVal)) {
711
+ return null;
712
+ }
713
+ if (arg.minValue !== void 0 && intVal < arg.minValue) {
714
+ return null;
715
+ }
716
+ if (arg.maxValue !== void 0 && intVal > arg.maxValue) {
717
+ return null;
718
+ }
719
+ return intVal;
720
+ }
721
+ matchNumberValue(arg, value) {
722
+ const numVal = parseFloat(value);
723
+ if (isNaN(numVal)) {
724
+ return null;
725
+ }
726
+ if (arg.minValue !== void 0 && numVal < arg.minValue) {
727
+ return null;
728
+ }
729
+ if (arg.maxValue !== void 0 && numVal > arg.maxValue) {
730
+ return null;
731
+ }
732
+ return numVal;
733
+ }
734
+ matchStringValue(arg, value) {
735
+ if (arg.minLength !== void 0 && value.length < arg.minLength) {
736
+ return null;
737
+ }
738
+ if (arg.maxLength !== void 0 && value.length > arg.maxLength) {
739
+ return null;
740
+ }
741
+ return value;
742
+ }
743
+ static resolveChatInput(interaction, arg) {
744
+ switch (arg.type) {
745
+ case "string" /* String */:
746
+ return interaction.options.getString(arg.name, arg.required);
747
+ case "integer" /* Integer */:
748
+ return interaction.options.getInteger(arg.name, arg.required);
749
+ case "number" /* Number */:
750
+ return interaction.options.getNumber(arg.name, arg.required);
751
+ case "user" /* User */:
752
+ return interaction.options.getUser(arg.name, arg.required);
753
+ case "member" /* Member */:
754
+ return interaction.options.getMember(arg.name);
755
+ default:
756
+ return null;
757
+ }
758
+ }
759
+ };
760
+
761
+ // src/libs/StateBox.ts
762
+ import { AsyncLocalStorage } from "async_hooks";
763
+ var StateBox = class _StateBox {
764
+ static STATES_KEY = Symbol("states");
765
+ static storage = new AsyncLocalStorage();
766
+ static getState() {
767
+ const state = this.storage.getStore();
768
+ if (!state) {
769
+ throw new Error("No active context, did you forget to wrap it with StateBox.wrap()?");
770
+ }
771
+ return state;
772
+ }
773
+ static run(fn, store = {}) {
774
+ return this.storage.run(store, fn);
775
+ }
776
+ static wrap(fn) {
777
+ const currentStore = this.storage.getStore();
778
+ if (!currentStore) {
779
+ throw new Error("No active context, cannot wrap function outside a StateBox.run()");
780
+ }
781
+ return () => this.run(fn, currentStore);
782
+ }
783
+ static use(defaultValue) {
784
+ return (target, key) => {
785
+ Object.defineProperty(target, key, {
786
+ get() {
787
+ const states = _StateBox.getState();
788
+ if (!(key in states)) {
789
+ states[key] = defaultValue;
790
+ }
791
+ return states[key];
792
+ },
793
+ set(value) {
794
+ const states = _StateBox.getState();
795
+ states[key] = value;
796
+ },
797
+ enumerable: true,
798
+ configurable: true
799
+ });
800
+ };
801
+ }
802
+ };
803
+
804
+ // src/BakitClient.ts
805
+ var BakitClient = class _BakitClient extends Client {
806
+ constructor(options) {
807
+ if (options.getSyntaxErrorMessage === void 0) {
808
+ options.getSyntaxErrorMessage = _BakitClient.getSyntaxErrorMessage;
809
+ }
810
+ super(options);
811
+ this.once(
812
+ Events.ClientReady,
813
+ (client) => void this.registerApplicationCommands(client)
814
+ );
815
+ this.on(Events.InteractionCreate, (interaction) => void this.handleInteraction(interaction));
816
+ this.on(Events.MessageCreate, (message) => void this.handleMessage(message));
817
+ }
818
+ static getSyntaxErrorMessage = (command, error, context, args, prefix) => {
819
+ const requiredSyntax = args.map((x) => Arg.format(x)).join(" ");
820
+ const root = Command.getRoot(command.constructor);
821
+ if (!root) {
822
+ return;
823
+ }
824
+ const content = [
825
+ codeBlock(error.message),
826
+ "Required Syntax:",
827
+ codeBlock(`${prefix}${root.options.name} ${requiredSyntax}`)
828
+ ].join("\n");
829
+ return {
830
+ content
831
+ };
832
+ };
833
+ async registerApplicationCommands(client) {
834
+ const commands = CommandRegistry.constructors.map((c) => CommandRegistry.buildSlashCommand(c));
835
+ await client.application.commands.set(commands);
836
+ }
837
+ async handleMessage(message) {
838
+ if (message.author.bot) {
839
+ return;
840
+ }
841
+ const resolver = ArgumentResolver.create(message);
842
+ if (!resolver) {
843
+ return;
844
+ }
845
+ const { trigger } = resolver;
846
+ const command = CommandRegistry.instances.get(trigger);
847
+ if (!command) {
848
+ return;
849
+ }
850
+ const hooks = BaseCommandEntry.getHooks(command.constructor);
851
+ const context = new MessageContext(message);
852
+ await StateBox.run(() => this.handleMessageHooks(context, hooks, command, resolver));
853
+ }
854
+ async handleInteraction(interaction) {
855
+ if (!interaction.isChatInputCommand()) {
856
+ return;
857
+ }
858
+ const { commandName } = interaction;
859
+ const command = CommandRegistry.instances.get(commandName);
860
+ if (!command) {
861
+ return;
862
+ }
863
+ const hooks = BaseCommandEntry.getHooks(command.constructor);
864
+ const context = new ChatInputContext(interaction);
865
+ await StateBox.run(() => this.handleChatInputHooks(context, hooks, command));
866
+ }
867
+ async handleChatInputHooks(context, hooks, instance) {
868
+ const targetHooks = this.getChatInputTargetHooks(context.source, hooks);
869
+ let inheritedArgs = [];
870
+ for (const record of [targetHooks.root, targetHooks.group, targetHooks.subcommand]) {
871
+ const newArgs = await this.runChatInputHooks(context, instance, record, inheritedArgs);
872
+ if (newArgs) {
873
+ inheritedArgs = newArgs;
874
+ }
875
+ }
876
+ }
877
+ async handleMessageHooks(context, hooks, instance, resolver) {
878
+ if (!resolver) {
879
+ return;
880
+ }
881
+ const rootEntry = Command.getRoot(instance.constructor);
882
+ if (!rootEntry) return;
883
+ const rootRecord = this.createHookRecord(hooks.filter((hook) => hook.entry === rootEntry));
884
+ resolver = await this.runMessageHooks(context, instance, rootRecord, resolver);
885
+ if (!resolver) {
886
+ return;
887
+ }
888
+ const usedValues = resolver.parsedValues.length;
889
+ const nextTrigger = resolver.values[usedValues + 1];
890
+ const nextHook = hooks.find((hook) => hook.entry.options.name === nextTrigger);
891
+ const nextRecord = this.createHookRecord(nextHook ? [nextHook] : []);
892
+ resolver = await this.runMessageHooks(context, instance, nextRecord, resolver);
893
+ if (!resolver) {
894
+ return;
895
+ }
896
+ if (nextRecord.main?.entry instanceof CommandGroupEntry) {
897
+ const groupEntry = nextRecord.main.entry;
898
+ const subTrigger = resolver.values[usedValues + 2];
899
+ const subHook = hooks.find(
900
+ (h) => h.entry instanceof SubcommandEntry && h.entry.options.name === subTrigger && h.entry.parent === groupEntry
901
+ );
902
+ const subRecord = this.createHookRecord(subHook ? [subHook] : []);
903
+ resolver = await this.runMessageHooks(context, instance, subRecord, resolver);
904
+ }
905
+ }
906
+ async runMessageHooks(context, instance, record, resolver) {
907
+ if (!record.main) {
908
+ return resolver;
909
+ }
910
+ const args = Arg.getMethodArguments(record.main.method);
911
+ try {
912
+ resolver = await resolver.resolve(args);
913
+ } catch (error) {
914
+ if (error instanceof CommandSyntaxError) {
915
+ const errorContent = await this.options.getSyntaxErrorMessage?.(
916
+ instance,
917
+ error,
918
+ context,
919
+ args,
920
+ resolver.options.prefix
921
+ );
922
+ if (errorContent) {
923
+ await context.send(errorContent);
924
+ }
925
+ return null;
926
+ }
927
+ throw error;
928
+ }
929
+ try {
930
+ await record.pre?.method.call(instance, context, ...resolver.parsedValues);
931
+ await record.main.method.call(instance, context, ...resolver.parsedValues);
932
+ await record.post?.method.call(instance, context, ...resolver.parsedValues);
933
+ } catch (error) {
934
+ if (record.error) {
935
+ await record.error.method.call(instance, context, error, ...resolver.parsedValues);
936
+ } else {
937
+ throw error;
938
+ }
939
+ }
940
+ return resolver;
941
+ }
942
+ async runChatInputHooks(context, instance, record, inheritedArgs) {
943
+ if (!record.main) {
944
+ return;
945
+ }
946
+ const newArgs = Arg.getMethodArguments(record.main.method).map(
947
+ (arg) => ArgumentResolver.resolveChatInput(context.source, arg)
948
+ );
949
+ const argValues = [...inheritedArgs, ...newArgs];
950
+ try {
951
+ await record.pre?.method.call(instance, context, ...argValues);
952
+ await record.main.method.call(instance, context, ...argValues);
953
+ await record.post?.method.call(instance, context, ...argValues);
954
+ } catch (error) {
955
+ if (record.error) {
956
+ await record.error.method.call(instance, context, error, ...argValues);
957
+ } else {
958
+ throw error;
959
+ }
960
+ }
961
+ return argValues;
962
+ }
963
+ getChatInputTargetHooks(interaction, hooks) {
964
+ const subcommand = interaction.options.getSubcommand(false);
965
+ const subcommandGroup = interaction.options.getSubcommandGroup(false);
966
+ const root = this.createHookRecord(
967
+ hooks.filter((hook) => hook.entry instanceof RootCommandEntry)
968
+ );
969
+ const group = this.createHookRecord(
970
+ hooks.filter(({ entry }) => {
971
+ return entry instanceof CommandGroupEntry && entry.options.name === subcommandGroup;
972
+ })
973
+ );
974
+ const sub = this.createHookRecord(
975
+ hooks.filter(({ entry }) => {
976
+ if (!(entry instanceof SubcommandEntry) || !(entry.options.name === subcommand)) {
977
+ return false;
978
+ }
979
+ if (subcommandGroup) {
980
+ const { parent } = entry;
981
+ if (!(parent instanceof CommandGroupEntry) || parent.options.name !== subcommandGroup) {
982
+ return false;
983
+ }
984
+ }
985
+ return true;
986
+ })
987
+ );
988
+ return { root, group, subcommand: sub };
989
+ }
990
+ createHookRecord(hooks) {
991
+ return Object.values(HookExecutionState).reduce(
992
+ (acc, state) => {
993
+ acc[state] = hooks.find((h) => h.state === state);
994
+ return acc;
995
+ },
996
+ {}
997
+ );
998
+ }
999
+ };
1000
+ export {
1001
+ Arg,
1002
+ ArgumentType,
1003
+ BakitClient,
1004
+ BaseCommandEntry,
1005
+ BaseCommandGroupEntry,
1006
+ BaseContext,
1007
+ ChatInputContext,
1008
+ Command,
1009
+ CommandGroupEntry,
1010
+ CommandRegistry,
1011
+ CommandSyntaxError,
1012
+ CommandSyntaxErrorType,
1013
+ HOOKS_KEY,
1014
+ HookExecutionState,
1015
+ MessageContext,
1016
+ RootCommandEntry,
1017
+ StateBox,
1018
+ SubcommandEntry,
1019
+ extractId
1020
+ };