stoatx 0.7.7 → 1.0.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.mjs CHANGED
@@ -1,3 +1,35 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
+
4
+ // src/types.ts
5
+ import { User, BaseChannel, Role } from "@stoatx/client";
6
+ var PARAM_TYPE_MAP = /* @__PURE__ */ new Map([
7
+ [
8
+ String,
9
+ "string"
10
+ ],
11
+ [
12
+ Number,
13
+ "number"
14
+ ],
15
+ [
16
+ Boolean,
17
+ "boolean"
18
+ ],
19
+ [
20
+ User,
21
+ "user"
22
+ ],
23
+ [
24
+ BaseChannel,
25
+ "channel"
26
+ ],
27
+ [
28
+ Role,
29
+ "role"
30
+ ]
31
+ ]);
32
+
1
33
  // src/decorators/Stoat.ts
2
34
  import "reflect-metadata";
3
35
 
@@ -6,14 +38,22 @@ var METADATA_KEYS = {
6
38
  IS_STOAT_CLASS: /* @__PURE__ */ Symbol("stoatx:stoat:isClass"),
7
39
  SIMPLE_COMMANDS: /* @__PURE__ */ Symbol("stoatx:stoat:simpleCommands"),
8
40
  GUARDS: "stoatx:command:guards",
9
- EVENTS: /* @__PURE__ */ Symbol("stoatx:stoat:events")
41
+ EVENTS: /* @__PURE__ */ Symbol("stoatx:stoat:events"),
42
+ ARGS: /* @__PURE__ */ Symbol("stoatx:param:args"),
43
+ OPTIONS: /* @__PURE__ */ Symbol("stoatx:param:options"),
44
+ INJECTABLE: /* @__PURE__ */ Symbol("stoatx:injectable"),
45
+ SUBCOMMAND: /* @__PURE__ */ Symbol("stoatx:subcommand"),
46
+ COMMAND_GROUP: /* @__PURE__ */ Symbol("stoatx:commandGroup")
10
47
  };
11
48
 
12
49
  // src/decorators/store.ts
13
50
  var DecoratorStore = class _DecoratorStore {
51
+ static {
52
+ __name(this, "DecoratorStore");
53
+ }
14
54
  static instance;
15
55
  /** Stoat classes with their SimpleCommand methods */
16
- stoatClasses = /* @__PURE__ */ new Map();
56
+ stoatClasses = /* @__PURE__ */ new Set();
17
57
  /** Registered commands from @Stoat/@SimpleCommand decorators */
18
58
  commands = [];
19
59
  /** Whether the store has been initialized */
@@ -27,49 +67,46 @@ var DecoratorStore = class _DecoratorStore {
27
67
  return _DecoratorStore.instance;
28
68
  }
29
69
  /**
30
- * Register a @Stoat decorated class
31
- */
70
+ * Register a @Stoat decorated class
71
+ */
32
72
  registerStoatClass(classConstructor) {
33
- if (!this.stoatClasses.has(classConstructor)) {
34
- const instance = new classConstructor();
35
- this.stoatClasses.set(classConstructor, instance);
36
- }
73
+ this.stoatClasses.add(classConstructor);
37
74
  }
38
75
  /**
39
- * Get all registered Stoat classes with their instances
40
- */
76
+ * Get all registered Stoat classes with their instances
77
+ */
41
78
  getStoatClasses() {
42
79
  return this.stoatClasses;
43
80
  }
44
81
  /**
45
- * Add a registered command
46
- */
82
+ * Add a registered command
83
+ */
47
84
  addCommand(command) {
48
85
  this.commands.push(command);
49
86
  }
50
87
  /**
51
- * Get all registered commands
52
- */
88
+ * Get all registered commands
89
+ */
53
90
  getCommands() {
54
91
  return this.commands;
55
92
  }
56
93
  /**
57
- * Clear all registered classes (useful for testing)
58
- */
94
+ * Clear all registered classes (useful for testing)
95
+ */
59
96
  clear() {
60
97
  this.stoatClasses.clear();
61
98
  this.commands = [];
62
99
  this.initialized = false;
63
100
  }
64
101
  /**
65
- * Mark as initialized
66
- */
102
+ * Mark as initialized
103
+ */
67
104
  markInitialized() {
68
105
  this.initialized = true;
69
106
  }
70
107
  /**
71
- * Check if initialized
72
- */
108
+ * Check if initialized
109
+ */
73
110
  isInitialized() {
74
111
  return this.initialized;
75
112
  }
@@ -83,9 +120,11 @@ function Stoat() {
83
120
  decoratorStore.registerStoatClass(target);
84
121
  };
85
122
  }
123
+ __name(Stoat, "Stoat");
86
124
  function isStoatClass(target) {
87
125
  return Reflect.getMetadata(METADATA_KEYS.IS_STOAT_CLASS, target) === true;
88
126
  }
127
+ __name(isStoatClass, "isStoatClass");
89
128
 
90
129
  // src/decorators/SimpleCommand.ts
91
130
  import "reflect-metadata";
@@ -101,22 +140,35 @@ function SimpleCommand(options = {}) {
101
140
  return descriptor;
102
141
  };
103
142
  }
143
+ __name(SimpleCommand, "SimpleCommand");
104
144
  function getSimpleCommands(target) {
105
145
  return Reflect.getMetadata(METADATA_KEYS.SIMPLE_COMMANDS, target) || [];
106
146
  }
147
+ __name(getSimpleCommands, "getSimpleCommands");
107
148
 
108
149
  // src/decorators/Guard.ts
109
150
  import "reflect-metadata";
110
151
  function Guard(guardClass) {
111
- return (target) => {
112
- const existingGuards = Reflect.getMetadata(METADATA_KEYS.GUARDS, target) || [];
113
- existingGuards.push(guardClass);
114
- Reflect.defineMetadata(METADATA_KEYS.GUARDS, existingGuards, target);
152
+ return (target, propertyKey) => {
153
+ if (propertyKey) {
154
+ const existingGuards = Reflect.getMetadata(METADATA_KEYS.GUARDS, target, propertyKey) || [];
155
+ existingGuards.push(guardClass);
156
+ Reflect.defineMetadata(METADATA_KEYS.GUARDS, existingGuards, target, propertyKey);
157
+ } else {
158
+ const existingGuards = Reflect.getMetadata(METADATA_KEYS.GUARDS, target) || [];
159
+ existingGuards.push(guardClass);
160
+ Reflect.defineMetadata(METADATA_KEYS.GUARDS, existingGuards, target);
161
+ }
115
162
  };
116
163
  }
117
- function getGuards(target) {
164
+ __name(Guard, "Guard");
165
+ function getGuards(target, propertyKey) {
166
+ if (propertyKey) {
167
+ return Reflect.getMetadata(METADATA_KEYS.GUARDS, target.prototype, propertyKey) || [];
168
+ }
118
169
  return Reflect.getMetadata(METADATA_KEYS.GUARDS, target) || [];
119
170
  }
171
+ __name(getGuards, "getGuards");
120
172
 
121
173
  // src/decorators/Events.ts
122
174
  import "reflect-metadata";
@@ -133,18 +185,88 @@ function createEventDecorator(event, type) {
133
185
  return descriptor;
134
186
  };
135
187
  }
188
+ __name(createEventDecorator, "createEventDecorator");
136
189
  function On(event) {
137
190
  return createEventDecorator(event, "on");
138
191
  }
192
+ __name(On, "On");
139
193
  function Once(event) {
140
194
  return createEventDecorator(event, "once");
141
195
  }
196
+ __name(Once, "Once");
142
197
  function getEventsMetadata(target) {
143
198
  return Reflect.getMetadata(METADATA_KEYS.EVENTS, target) || [];
144
199
  }
200
+ __name(getEventsMetadata, "getEventsMetadata");
201
+
202
+ // src/decorators/Arg.ts
203
+ import "reflect-metadata";
204
+ function Arg(options = {}) {
205
+ return (target, propertyKey, parameterIndex) => {
206
+ const existing = Reflect.getMetadata(METADATA_KEYS.ARGS, target, propertyKey) || [];
207
+ existing.push({
208
+ ...options,
209
+ index: parameterIndex
210
+ });
211
+ Reflect.defineMetadata(METADATA_KEYS.ARGS, existing, target, propertyKey);
212
+ };
213
+ }
214
+ __name(Arg, "Arg");
215
+ function getArgs(target, propertyKey) {
216
+ return Reflect.getMetadata(METADATA_KEYS.ARGS, target, propertyKey) || [];
217
+ }
218
+ __name(getArgs, "getArgs");
219
+
220
+ // src/decorators/Option.ts
221
+ import "reflect-metadata";
222
+ function Option(options) {
223
+ return (target, propertyKey, parameterIndex) => {
224
+ const existing = Reflect.getMetadata(METADATA_KEYS.OPTIONS, target, propertyKey) || [];
225
+ existing.push({
226
+ ...options,
227
+ index: parameterIndex
228
+ });
229
+ Reflect.defineMetadata(METADATA_KEYS.OPTIONS, existing, target, propertyKey);
230
+ };
231
+ }
232
+ __name(Option, "Option");
233
+ function getOptions(target, propertyKey) {
234
+ return Reflect.getMetadata(METADATA_KEYS.OPTIONS, target, propertyKey) || [];
235
+ }
236
+ __name(getOptions, "getOptions");
237
+
238
+ // src/decorators/Injectable.ts
239
+ import "reflect-metadata";
240
+ function Injectable() {
241
+ return (target) => {
242
+ Reflect.defineMetadata(METADATA_KEYS.INJECTABLE, true, target);
243
+ };
244
+ }
245
+ __name(Injectable, "Injectable");
246
+
247
+ // src/decorators/CommandGroup.ts
248
+ import "reflect-metadata";
249
+ function CommandGroup(name) {
250
+ return (target) => {
251
+ Reflect.defineMetadata(METADATA_KEYS.COMMAND_GROUP, name, target);
252
+ };
253
+ }
254
+ __name(CommandGroup, "CommandGroup");
255
+
256
+ // src/decorators/SubCommand.ts
257
+ import "reflect-metadata";
258
+ function SubCommand(options) {
259
+ const opts = typeof options === "string" ? {
260
+ name: options
261
+ } : options;
262
+ return (target, propertyKey) => {
263
+ Reflect.defineMetadata(METADATA_KEYS.SUBCOMMAND, opts, target, propertyKey);
264
+ };
265
+ }
266
+ __name(SubCommand, "SubCommand");
145
267
 
146
268
  // src/decorators/utils.ts
147
- function buildSimpleCommandMetadata(options, methodName, category) {
269
+ function buildSimpleCommandMetadata(options, methodName, category, params) {
148
270
  return {
149
271
  name: options.name ?? methodName.toLowerCase(),
150
272
  description: options.description ?? "No description provided",
@@ -152,11 +274,30 @@ function buildSimpleCommandMetadata(options, methodName, category) {
152
274
  permissions: options.permissions ?? [],
153
275
  category: options.category ?? category ?? "uncategorized",
154
276
  cooldown: options.cooldown ?? 0,
155
- ...options.cooldownStorage !== void 0 ? { cooldownStorage: options.cooldownStorage } : {},
277
+ ...options.cooldownStorage !== void 0 ? {
278
+ cooldownStorage: options.cooldownStorage
279
+ } : {},
156
280
  nsfw: options.nsfw ?? false,
157
- ownerOnly: options.ownerOnly ?? false
281
+ ownerOnly: options.ownerOnly ?? false,
282
+ params
158
283
  };
159
284
  }
285
+ __name(buildSimpleCommandMetadata, "buildSimpleCommandMetadata");
286
+ function getSubCommands(target) {
287
+ const methods = Object.getOwnPropertyNames(target.prototype);
288
+ const subCommands = [];
289
+ for (const method of methods) {
290
+ const options = Reflect.getMetadata(METADATA_KEYS.SUBCOMMAND, target.prototype, method);
291
+ if (options) {
292
+ subCommands.push({
293
+ methodName: method,
294
+ options
295
+ });
296
+ }
297
+ }
298
+ return subCommands;
299
+ }
300
+ __name(getSubCommands, "getSubCommands");
160
301
 
161
302
  // src/registry.ts
162
303
  import * as path from "path";
@@ -164,6 +305,9 @@ import * as fs from "fs/promises";
164
305
  import { pathToFileURL } from "url";
165
306
  import { glob } from "tinyglobby";
166
307
  var CommandRegistry = class _CommandRegistry {
308
+ static {
309
+ __name(this, "CommandRegistry");
310
+ }
167
311
  static DEFAULT_AUTO_DISCOVERY_IGNORES = [
168
312
  "**/node_modules/**",
169
313
  "**/.git/**",
@@ -176,23 +320,27 @@ var CommandRegistry = class _CommandRegistry {
176
320
  registeredEvents = [];
177
321
  extensions;
178
322
  processedStoatClasses = /* @__PURE__ */ new Set();
179
- constructor(extensions = [".js", ".mjs", ".cjs"]) {
323
+ container;
324
+ constructor(container, extensions = [
325
+ ".js",
326
+ ".mjs",
327
+ ".cjs"
328
+ ]) {
329
+ this.container = container;
180
330
  this.extensions = extensions;
181
331
  }
182
- /**
183
- * Get the number of registered commands
184
- */
185
332
  get size() {
186
333
  return this.commands.size;
187
334
  }
188
- /**
189
- * Load commands from a directory using glob pattern matching
190
- */
191
335
  async loadFromDirectory(directory) {
192
336
  const patterns = this.extensions.map((ext) => path.join(directory, "**", `*${ext}`).replace(/\\/g, "/"));
193
337
  for (const pattern of patterns) {
194
338
  const files = await glob(pattern, {
195
- ignore: ["**/*.d.ts", "**/*.test.ts", "**/*.spec.ts"],
339
+ ignore: [
340
+ "**/*.d.ts",
341
+ "**/*.test.ts",
342
+ "**/*.spec.ts"
343
+ ],
196
344
  absolute: true
197
345
  });
198
346
  for (const file of files) {
@@ -201,26 +349,26 @@ var CommandRegistry = class _CommandRegistry {
201
349
  }
202
350
  console.log(`[Stoatx] Loaded ${this.commands.size} command(s) and ${this.registeredEvents.length} event(s)`);
203
351
  }
204
- /**
205
- * Auto-discover command files across one or more roots.
206
- */
207
352
  async autoDiscover(options = {}) {
208
- const roots = options.roots?.length ? options.roots : [process.cwd()];
353
+ const roots = options.roots?.length ? options.roots : [
354
+ process.cwd()
355
+ ];
209
356
  const includePatterns = options.include?.length ? options.include : this.getDefaultAutoDiscoveryPatterns();
210
- const patterns = roots.flatMap(
211
- (root) => includePatterns.map((pattern) => path.join(root, pattern).replace(/\\/g, "/"))
212
- );
357
+ const patterns = roots.flatMap((root) => includePatterns.map((pattern) => path.join(root, pattern).replace(/\\/g, "/")));
213
358
  const files = await glob(patterns, {
214
- ignore: [..._CommandRegistry.DEFAULT_AUTO_DISCOVERY_IGNORES, ...options.ignore ?? []],
359
+ ignore: [
360
+ ..._CommandRegistry.DEFAULT_AUTO_DISCOVERY_IGNORES,
361
+ ...options.ignore ?? []
362
+ ],
215
363
  absolute: true
216
364
  });
217
- const uniqueFiles = [...new Set(files)];
218
- let candidateFiles = 0;
365
+ const uniqueFiles = [
366
+ ...new Set(files)
367
+ ];
219
368
  for (const file of uniqueFiles) {
220
369
  if (!await this.isLikelyCommandModule(file)) {
221
370
  continue;
222
371
  }
223
- candidateFiles++;
224
372
  const baseDir = roots.find((root) => {
225
373
  const relative2 = path.relative(root, file);
226
374
  return relative2 && !relative2.startsWith("..") && !path.isAbsolute(relative2);
@@ -240,17 +388,22 @@ var CommandRegistry = class _CommandRegistry {
240
388
  return true;
241
389
  }
242
390
  }
243
- /**
244
- * Register a command instance
245
- */
246
391
  register(instance, metadata, classConstructor, methodName) {
247
- const name = metadata.name.toLowerCase();
392
+ const groupOptions = Reflect.getMetadata(METADATA_KEYS.COMMAND_GROUP, classConstructor);
393
+ const subCommandOptions = Reflect.getMetadata(METADATA_KEYS.SUBCOMMAND, instance, methodName);
394
+ const subCommandName = subCommandOptions?.name;
395
+ const name = groupOptions && subCommandName ? `${groupOptions.name}:${subCommandName}`.toLowerCase() : metadata.name.toLowerCase();
248
396
  if (this.commands.has(name)) {
249
397
  console.warn(`[Stoatx] Duplicate command name: ${name}. Skipping...`);
250
398
  return;
251
399
  }
252
400
  this.validateGuards(classConstructor, metadata.name);
253
- this.commands.set(name, { instance, metadata, methodName, classConstructor });
401
+ this.commands.set(name, {
402
+ instance,
403
+ metadata,
404
+ methodName,
405
+ classConstructor
406
+ });
254
407
  for (const alias of metadata.aliases) {
255
408
  const aliasLower = alias.toLowerCase();
256
409
  if (this.aliases.has(aliasLower) || this.commands.has(aliasLower)) {
@@ -260,42 +413,24 @@ var CommandRegistry = class _CommandRegistry {
260
413
  this.aliases.set(aliasLower, name);
261
414
  }
262
415
  }
263
- /**
264
- * Get a command by name or alias
265
- */
266
416
  get(name) {
267
417
  const lowerName = name.toLowerCase();
268
418
  const resolvedName = this.aliases.get(lowerName) ?? lowerName;
269
419
  return this.commands.get(resolvedName);
270
420
  }
271
- /**
272
- * Check if a command exists
273
- */
274
421
  has(name) {
275
422
  const lowerName = name.toLowerCase();
276
423
  return this.commands.has(lowerName) || this.aliases.has(lowerName);
277
424
  }
278
- /**
279
- * Get all registered commands
280
- */
281
425
  getAll() {
282
426
  return Array.from(this.commands.values());
283
427
  }
284
- /**
285
- * Get all command metadata
286
- */
287
428
  getAllMetadata() {
288
429
  return this.getAll().map((c) => c.metadata);
289
430
  }
290
- /**
291
- * Get all registered events
292
- */
293
431
  getEvents() {
294
432
  return this.registeredEvents;
295
433
  }
296
- /**
297
- * Get commands grouped by category
298
- */
299
434
  getByCategory() {
300
435
  const categories = /* @__PURE__ */ new Map();
301
436
  for (const cmd of this.commands.values()) {
@@ -306,95 +441,70 @@ var CommandRegistry = class _CommandRegistry {
306
441
  }
307
442
  return categories;
308
443
  }
309
- /**
310
- * Clear all commands
311
- */
312
444
  clear() {
313
445
  this.commands.clear();
314
446
  this.aliases.clear();
315
447
  this.registeredEvents.length = 0;
316
448
  this.processedStoatClasses.clear();
317
449
  }
318
- /**
319
- * Iterate over commands
320
- */
321
450
  [Symbol.iterator]() {
322
451
  return this.commands.entries();
323
452
  }
324
- /**
325
- * Iterate over command values
326
- */
327
453
  values() {
328
454
  return this.commands.values();
329
455
  }
330
- /**
331
- * Iterate over command names
332
- */
333
456
  keys() {
334
457
  return this.commands.keys();
335
458
  }
336
- /**
337
- * Validate that all guards on a command implement the required methods
338
- * @param commandClass
339
- * @param commandName
340
- * @private
341
- */
342
459
  validateGuards(commandClass, commandName) {
343
- const guards = Reflect.getMetadata("stoatx:command:guards", commandClass) || [];
460
+ const guards = Reflect.getMetadata(METADATA_KEYS.GUARDS, commandClass) || [];
344
461
  for (const GuardClass of guards) {
345
- const guardInstance = new GuardClass();
462
+ const guardInstance = this.container.resolve(GuardClass);
346
463
  if (typeof guardInstance.run !== "function") {
347
- console.error(
348
- `[Stoatx] FATAL: Guard "${GuardClass.name}" on command "${commandName}" does not have a run() method.`
349
- );
464
+ console.error(`[Stoatx] FATAL: Guard "${GuardClass.name}" on command "${commandName}" does not have a run() method.`);
350
465
  process.exit(1);
351
466
  }
352
467
  if (typeof guardInstance.guardFail !== "function") {
353
- console.error(
354
- `[Stoatx] FATAL: Guard "${GuardClass.name}" on command "${commandName}" does not have a guardFail() method.`
355
- );
356
- console.error(`[Stoatx] All guards must implement guardFail() to handle failed checks.`);
468
+ console.error(`[Stoatx] FATAL: Guard "${GuardClass.name}" on command "${commandName}" does not have a guardFail() method.`);
357
469
  process.exit(1);
358
470
  }
359
471
  }
360
472
  }
361
- /**
362
- * Load commands from a single file
363
- */
364
473
  async loadFile(filePath, baseDir) {
365
474
  try {
366
475
  const knownStoatClasses = new Set(decoratorStore.getStoatClasses().keys());
367
476
  const fileUrl = pathToFileURL(filePath).href;
368
477
  await import(fileUrl);
369
478
  const allStoatClasses = decoratorStore.getStoatClasses();
370
- for (const [stoatClass, stoatInstance] of allStoatClasses.entries()) {
479
+ for (const [stoatClass] of allStoatClasses.entries()) {
371
480
  if (knownStoatClasses.has(stoatClass) || this.processedStoatClasses.has(stoatClass)) {
372
481
  continue;
373
482
  }
374
- this.registerStoatClassCommands(stoatClass, stoatInstance, filePath, baseDir);
483
+ this.registerStoatClassCommands(stoatClass, filePath, baseDir);
375
484
  }
376
485
  } catch (error) {
377
486
  console.error(`[Stoatx] Failed to load command file: ${filePath}`, error);
378
487
  }
379
488
  }
380
- registerStoatClassCommands(stoatClass, instance, filePath, baseDir) {
489
+ registerStoatClassCommands(stoatClass, filePath, baseDir) {
490
+ const instance = this.container.resolve(stoatClass);
381
491
  const simpleCommands = getSimpleCommands(stoatClass);
492
+ const subCommands = getSubCommands(stoatClass);
382
493
  const events = getEventsMetadata(stoatClass);
383
494
  const category = this.getCategoryFromPath(filePath, baseDir);
384
- if (simpleCommands.length === 0 && events.length === 0) {
385
- console.warn(
386
- `[Stoatx] Class ${stoatClass.name} is decorated with @Stoat but has no @SimpleCommand, @On or @Once methods. Skipping...`
387
- );
495
+ const allCommands = [
496
+ ...simpleCommands,
497
+ ...subCommands
498
+ ];
499
+ if (allCommands.length === 0 && events.length === 0) {
388
500
  this.processedStoatClasses.add(stoatClass);
389
501
  return;
390
502
  }
391
- for (const cmdDef of simpleCommands) {
503
+ for (const cmdDef of allCommands) {
392
504
  const method = instance[cmdDef.methodName];
393
- if (typeof method !== "function") {
394
- console.warn(`[Stoatx] Method ${cmdDef.methodName} not found on ${stoatClass.name}. Skipping...`);
395
- continue;
396
- }
397
- const metadata = buildSimpleCommandMetadata(cmdDef.options, cmdDef.methodName, category);
505
+ if (typeof method !== "function") continue;
506
+ const params = this.buildParamSchema(stoatClass.prototype, cmdDef.methodName);
507
+ const metadata = buildSimpleCommandMetadata(cmdDef.options, cmdDef.methodName, category, params);
398
508
  this.register(instance, metadata, stoatClass, cmdDef.methodName);
399
509
  }
400
510
  for (const eventDef of events) {
@@ -413,21 +523,180 @@ var CommandRegistry = class _CommandRegistry {
413
523
  this.processedStoatClasses.add(stoatClass);
414
524
  }
415
525
  /**
416
- * Derive category from file path relative to base directory
417
- */
526
+ * Build the parameter schema for a command method by combining
527
+ * reflect-metadata param types with @Arg/@Option decorator metadata.
528
+ */
529
+ buildParamSchema(prototype, methodName) {
530
+ const paramTypes = Reflect.getMetadata("design:paramtypes", prototype, methodName) ?? [];
531
+ const argDefs = getArgs(prototype, methodName);
532
+ const optionDefs = getOptions(prototype, methodName);
533
+ const argByIndex = new Map(argDefs.map((a) => [
534
+ a.index,
535
+ a
536
+ ]));
537
+ const optionByIndex = new Map(optionDefs.map((o) => [
538
+ o.index,
539
+ o
540
+ ]));
541
+ const params = [];
542
+ for (let i = 0; i < paramTypes.length; i++) {
543
+ const reflectedType = paramTypes[i];
544
+ if (optionByIndex.has(i)) {
545
+ const optDef = optionByIndex.get(i);
546
+ const resolvedType = reflectedType ? PARAM_TYPE_MAP.get(reflectedType) ?? "string" : "string";
547
+ params.push({
548
+ index: i,
549
+ kind: "option",
550
+ resolvedType,
551
+ name: optDef.name,
552
+ required: optDef.required
553
+ });
554
+ continue;
555
+ }
556
+ if (argByIndex.has(i)) {
557
+ const argDef = argByIndex.get(i);
558
+ const resolvedType = reflectedType ? PARAM_TYPE_MAP.get(reflectedType) ?? "string" : "string";
559
+ params.push({
560
+ index: i,
561
+ kind: "arg",
562
+ resolvedType,
563
+ required: argDef.required,
564
+ fetch: argDef.fetch
565
+ });
566
+ continue;
567
+ }
568
+ params.push({
569
+ index: i,
570
+ kind: "ctx",
571
+ resolvedType: "ctx"
572
+ });
573
+ }
574
+ return params;
575
+ }
418
576
  getCategoryFromPath(filePath, baseDir) {
419
577
  const relative2 = path.relative(baseDir, filePath);
420
578
  const parts = relative2.split(path.sep);
421
- if (parts.length > 1) {
422
- return parts[0];
423
- }
424
- return void 0;
579
+ return parts.length > 1 ? parts[0] : void 0;
425
580
  }
426
581
  };
427
582
 
428
583
  // src/handler.ts
429
584
  import "reflect-metadata";
585
+
586
+ // src/error.ts
587
+ var StoatxError = class extends Error {
588
+ static {
589
+ __name(this, "StoatxError");
590
+ }
591
+ constructor(message) {
592
+ super(message);
593
+ this.name = "StoatxError";
594
+ }
595
+ };
596
+ var CommandValidationError = class extends StoatxError {
597
+ static {
598
+ __name(this, "CommandValidationError");
599
+ }
600
+ paramName;
601
+ paramKind;
602
+ constructor(paramName, paramKind, message) {
603
+ super(message), this.paramName = paramName, this.paramKind = paramKind;
604
+ this.name = "CommandValidationError";
605
+ }
606
+ };
607
+ var MissingArgumentError = class extends CommandValidationError {
608
+ static {
609
+ __name(this, "MissingArgumentError");
610
+ }
611
+ constructor(paramName) {
612
+ super(paramName, "arg", `Missing required argument: \`<${paramName}>\``);
613
+ this.name = "MissingArgumentError";
614
+ }
615
+ };
616
+ var MissingOptionError = class extends CommandValidationError {
617
+ static {
618
+ __name(this, "MissingOptionError");
619
+ }
620
+ constructor(paramName, flagPrefix) {
621
+ super(paramName, "option", `Missing required option: \`${flagPrefix.repeat(2)}${paramName}\``);
622
+ this.name = "MissingOptionError";
623
+ }
624
+ };
625
+ var InvalidTypeError = class extends CommandValidationError {
626
+ static {
627
+ __name(this, "InvalidTypeError");
628
+ }
629
+ expected;
630
+ received;
631
+ constructor(paramName, paramKind, expected, received) {
632
+ super(paramName, paramKind, `Invalid value for \`${paramName}\`. Expected ${expected}, got \`${received}\`.`), this.expected = expected, this.received = received;
633
+ this.name = "InvalidTypeError";
634
+ }
635
+ };
636
+ var InvalidMentionError = class extends CommandValidationError {
637
+ static {
638
+ __name(this, "InvalidMentionError");
639
+ }
640
+ mentionKind;
641
+ rawValue;
642
+ constructor(paramName, paramKind, mentionKind, rawValue) {
643
+ super(paramName, paramKind, `Invalid ${mentionKind} mention for \`${paramName}\`.`), this.mentionKind = mentionKind, this.rawValue = rawValue;
644
+ this.name = "InvalidMentionError";
645
+ }
646
+ };
647
+ var FetchFailedError = class extends CommandValidationError {
648
+ static {
649
+ __name(this, "FetchFailedError");
650
+ }
651
+ mentionKind;
652
+ resolvedId;
653
+ constructor(paramName, paramKind, mentionKind, resolvedId) {
654
+ super(paramName, paramKind, `Could not fetch ${mentionKind} \`${resolvedId}\` for \`${paramName}\`.`), this.mentionKind = mentionKind, this.resolvedId = resolvedId;
655
+ this.name = "FetchFailedError";
656
+ }
657
+ };
658
+ var NoServerContextError = class extends CommandValidationError {
659
+ static {
660
+ __name(this, "NoServerContextError");
661
+ }
662
+ constructor(paramName, paramKind) {
663
+ super(paramName, paramKind, `Cannot fetch role for \`${paramName}\` outside of a server.`);
664
+ this.name = "NoServerContextError";
665
+ }
666
+ };
667
+
668
+ // src/di/Container.ts
669
+ import "reflect-metadata";
670
+ var StoatxContainer = class {
671
+ static {
672
+ __name(this, "StoatxContainer");
673
+ }
674
+ instances = /* @__PURE__ */ new Map();
675
+ /**
676
+ * Resolves a class instance, injecting any required dependencies.
677
+ */
678
+ resolve(target) {
679
+ if (this.instances.has(target)) {
680
+ return this.instances.get(target);
681
+ }
682
+ const paramTypes = Reflect.getMetadata("design:paramtypes", target) || [];
683
+ const injections = paramTypes.map((param) => {
684
+ if (!param) {
685
+ throw new Error(`[Stoatx DI] Cannot resolve dependency for ${target.name}. Ensure all injected services are decorated with @Injectable().`);
686
+ }
687
+ return this.resolve(param);
688
+ });
689
+ const instance = new target(...injections);
690
+ this.instances.set(target, instance);
691
+ return instance;
692
+ }
693
+ };
694
+
695
+ // src/handler.ts
430
696
  var DefaultCooldownManager = class {
697
+ static {
698
+ __name(this, "DefaultCooldownManager");
699
+ }
431
700
  cooldowns = /* @__PURE__ */ new Map();
432
701
  check(ctx, metadata) {
433
702
  if (metadata.cooldown <= 0) return true;
@@ -460,27 +729,33 @@ var DefaultCooldownManager = class {
460
729
  }
461
730
  };
462
731
  var StoatxHandler = class {
732
+ static {
733
+ __name(this, "StoatxHandler");
734
+ }
463
735
  commandsDir;
464
736
  discoveryOptions;
737
+ // After
465
738
  prefixResolver;
466
739
  owners;
467
740
  registry;
468
741
  cooldownManager;
469
742
  disableMentionPrefix;
470
743
  client;
744
+ flagPrefix;
745
+ globalGuards;
746
+ container = new StoatxContainer();
471
747
  constructor(options) {
472
748
  this.client = options.client;
473
749
  this.commandsDir = options.commandsDir;
474
750
  this.discoveryOptions = options.discovery;
475
751
  this.prefixResolver = options.prefix;
476
752
  this.owners = new Set(options.owners ?? []);
477
- this.registry = new CommandRegistry(options.extensions);
753
+ this.registry = new CommandRegistry(this.container, options.extensions);
478
754
  this.disableMentionPrefix = options.disableMentionPrefix ?? false;
479
755
  this.cooldownManager = options.cooldownManager ?? new DefaultCooldownManager();
756
+ this.flagPrefix = options.flagPrefix || "-";
757
+ this.globalGuards = options.globalGuards ?? [];
480
758
  }
481
- /**
482
- * Initialize the handler - load all commands
483
- */
484
759
  async init() {
485
760
  if (this.commandsDir) {
486
761
  await this.registry.loadFromDirectory(this.commandsDir);
@@ -489,22 +764,16 @@ var StoatxHandler = class {
489
764
  }
490
765
  this.attachEvents();
491
766
  }
492
- /**
493
- * Attach registered events to the client
494
- */
495
767
  attachEvents() {
496
768
  const events = this.registry.getEvents();
497
769
  for (const eventDef of events) {
498
- const handler = async (...args) => {
770
+ const handler = /* @__PURE__ */ __name(async (...args) => {
499
771
  try {
500
772
  await eventDef.instance[eventDef.methodName](...args, this.client);
501
773
  } catch (error) {
502
- console.error(
503
- `[Stoatx] Event Handler Error in @${eventDef.type === "on" ? "On" : "Once"}('${eventDef.event}'):`,
504
- error
505
- );
774
+ console.error(`[Stoatx] Event Handler Error in @${eventDef.type === "on" ? "On" : "Once"}('${eventDef.event}'):`, error);
506
775
  }
507
- };
776
+ }, "handler");
508
777
  const eventName = eventDef.event;
509
778
  if (eventDef.type === "once") {
510
779
  this.client.once(eventName, handler);
@@ -513,73 +782,86 @@ var StoatxHandler = class {
513
782
  }
514
783
  }
515
784
  }
516
- /**
517
- * Parse a raw message into command context
518
- */
785
+ parseRawInput(rawArgs) {
786
+ const args = [];
787
+ const flags = {};
788
+ for (let i = 0; i < rawArgs.length; i++) {
789
+ const arg = rawArgs[i];
790
+ if (arg === void 0) continue;
791
+ if (arg.startsWith(this.flagPrefix)) {
792
+ let key = arg;
793
+ while (key.startsWith(this.flagPrefix)) {
794
+ key = key.slice(this.flagPrefix.length);
795
+ }
796
+ const nextArg = rawArgs[i + 1];
797
+ if (nextArg !== void 0 && !nextArg.startsWith(this.flagPrefix)) {
798
+ flags[key] = nextArg;
799
+ i++;
800
+ } else {
801
+ flags[key] = true;
802
+ }
803
+ } else {
804
+ args.push(arg);
805
+ }
806
+ }
807
+ return {
808
+ args,
809
+ flags
810
+ };
811
+ }
519
812
  async parseMessage(rawContent, message, meta) {
520
- const prefix = await this.resolvePrefix(meta.serverId);
521
- let usedPrefix = prefix;
813
+ const prefixes = await this.resolvePrefix(meta.serverId);
814
+ let usedPrefix = "";
522
815
  let withoutPrefix = "";
523
- if (rawContent.startsWith(prefix)) {
524
- withoutPrefix = rawContent.slice(prefix.length).trim();
525
- usedPrefix = prefix;
526
- } else if (!this.disableMentionPrefix && rawContent.match(/^<@!?[\w]+>/)) {
527
- const mentionMatch = rawContent.match(/^<@!?([\w]+)>\s*/);
816
+ const matchedPrefix = prefixes.find((p) => rawContent.startsWith(p));
817
+ if (matchedPrefix !== void 0) {
818
+ usedPrefix = matchedPrefix;
819
+ withoutPrefix = rawContent.slice(matchedPrefix.length).trim();
820
+ } else if (!this.disableMentionPrefix && rawContent.match(/^<@!?\w+>/)) {
821
+ const mentionMatch = rawContent.match(/^<@!?(\w+)>\s*/);
528
822
  if (mentionMatch) {
529
823
  const mentionedId = mentionMatch[1];
530
824
  const botId = this.client.user?.id;
531
825
  if (botId && mentionedId === botId) {
532
826
  usedPrefix = mentionMatch[0];
533
827
  withoutPrefix = rawContent.slice(mentionMatch[0].length).trim();
534
- } else {
535
828
  }
536
829
  }
537
830
  }
538
- if (!withoutPrefix) {
539
- return null;
540
- }
541
- const [commandName, ...args] = withoutPrefix.split(/\s+/);
542
- if (!commandName) {
543
- return null;
831
+ if (!withoutPrefix) return null;
832
+ const parts = withoutPrefix.split(/\s+/);
833
+ const part1 = parts[0];
834
+ const part2 = parts[1];
835
+ if (!part1) return null;
836
+ let commandKey = part1.toLowerCase();
837
+ let remainingParts = parts.slice(1);
838
+ if (part2 && this.registry.has(`${part1}:${part2}`)) {
839
+ commandKey = `${part1}:${part2}`.toLowerCase();
840
+ remainingParts = parts.slice(2);
544
841
  }
842
+ const { args, flags } = this.parseRawInput(remainingParts);
545
843
  return {
546
844
  client: this.client,
547
845
  content: rawContent,
548
846
  authorId: meta.authorId,
549
847
  channelId: meta.channelId,
550
848
  serverId: meta.serverId,
551
- args,
552
849
  prefix: usedPrefix,
553
- commandName: commandName.toLowerCase(),
850
+ commandName: commandKey,
554
851
  reply: meta.reply,
555
- message
852
+ message,
853
+ _rawArgs: args,
854
+ _rawFlags: flags
556
855
  };
557
856
  }
558
- /**
559
- * Handle a message object using the configured message adapter
560
- *
561
- * @example
562
- * ```ts
563
- * // With message adapter configured
564
- * client.on('messageCreate', (message) => {
565
- * handler.handle(message);
566
- * });
567
- * ```
568
- */
569
857
  async handle(message) {
570
- if (!message.channel || !message.author || !message.content) {
571
- return false;
572
- }
573
- if (message.author.bot) {
574
- return false;
575
- }
858
+ if (!message.channel || !message.author || !message.content) return false;
859
+ if (message.author.bot) return false;
576
860
  const rawContent = message.content;
577
861
  const authorId = message.author.id;
578
862
  const channelId = message.channel.id;
579
863
  const serverId = message.server?.id;
580
- const reply = async (content) => {
581
- return await message.channel.send(content);
582
- };
864
+ const reply = /* @__PURE__ */ __name(async (content) => await message.channel.send(content), "reply");
583
865
  await this.handleMessage(rawContent, message, {
584
866
  authorId,
585
867
  channelId,
@@ -588,43 +870,20 @@ var StoatxHandler = class {
588
870
  });
589
871
  return true;
590
872
  }
591
- /**
592
- * Handle a raw message string with metadata
593
- *
594
- * @example
595
- * ```ts
596
- * // Manual usage without message adapter
597
- * client.on('messageCreate', (message) => {
598
- * handler.handleMessage(message.content, message, {
599
- * authorId: message.author.id,
600
- * channelId: message.channel.id,
601
- * serverId: message.server?.id,
602
- * reply: (content) => message.channel.sendMessage(content),
603
- * });
604
- * });
605
- * ```
606
- */
607
873
  async handleMessage(rawContent, message, meta) {
608
874
  const ctx = await this.parseMessage(rawContent, message, meta);
609
- if (!ctx) {
610
- return;
611
- }
875
+ if (!ctx) return;
612
876
  await this.execute(ctx);
613
877
  }
614
- /**
615
- * Execute a command with the given context
616
- */
617
878
  async execute(ctx) {
618
879
  const registered = this.registry.get(ctx.commandName);
619
- if (!registered) {
620
- return false;
621
- }
880
+ if (!registered) return false;
622
881
  const { instance, metadata, methodName, classConstructor } = registered;
623
882
  if (metadata.ownerOnly && !this.owners.has(ctx.authorId)) {
624
883
  await ctx.reply("This command is owner-only.");
625
884
  return false;
626
885
  }
627
- if (metadata.permissions) {
886
+ if (metadata.permissions.length > 0) {
628
887
  const server = ctx.message.server;
629
888
  const member = server ? await server.members.fetch(ctx.authorId) : null;
630
889
  if (!member || !member.permissions.has(metadata.permissions)) {
@@ -637,9 +896,16 @@ var StoatxHandler = class {
637
896
  return false;
638
897
  }
639
898
  }
640
- const guards = Reflect.getMetadata("stoatx:command:guards", classConstructor) || [];
641
- for (const guardClass of guards) {
642
- const guardInstance = new guardClass();
899
+ const globalGuards = this.globalGuards;
900
+ const classGuards = Reflect.getMetadata(METADATA_KEYS.GUARDS, classConstructor) || [];
901
+ const methodGuards = Reflect.getMetadata(METADATA_KEYS.GUARDS, instance, methodName) || [];
902
+ const allGuards = [
903
+ ...globalGuards,
904
+ ...classGuards,
905
+ ...methodGuards
906
+ ];
907
+ for (const guardClass of allGuards) {
908
+ const guardInstance = this.container.resolve(guardClass);
643
909
  if (typeof guardInstance.run === "function") {
644
910
  const guardResult = await guardInstance.run(ctx);
645
911
  if (!guardResult) {
@@ -661,42 +927,152 @@ var StoatxHandler = class {
661
927
  }
662
928
  return false;
663
929
  }
930
+ const resolvedParams = await this.resolveParams(metadata.params, ctx, instance);
931
+ if (resolvedParams === null) return false;
664
932
  try {
665
933
  if (metadata.cooldown > 0) {
666
934
  await this.cooldownManager.set(ctx, metadata);
667
935
  }
668
- await instance[methodName](ctx);
936
+ await instance[methodName](...resolvedParams);
669
937
  return true;
670
938
  } catch (error) {
671
939
  if (typeof instance.onError === "function") {
672
940
  await instance.onError(ctx, error);
673
941
  } else {
674
942
  console.error(`[Stoatx] Error in command ${metadata.name}:`, error);
943
+ await ctx.reply("Something went wrong. Please try again later.");
675
944
  }
676
945
  return false;
677
946
  }
678
947
  }
679
948
  /**
680
- * Get the command registry
681
- */
949
+ * Report a validation error to the instance via onValidationError → onError → default reply
950
+ */
951
+ async reportValidationError(instance, ctx, error) {
952
+ if (typeof instance.onValidationError === "function") {
953
+ await instance.onValidationError(ctx, error);
954
+ } else if (typeof instance.onError === "function") {
955
+ await instance.onError(ctx, error);
956
+ } else {
957
+ await ctx.reply(error.message);
958
+ }
959
+ return null;
960
+ }
961
+ async resolveParams(params, ctx, instance) {
962
+ const resolved = new Array(params.length);
963
+ let argCursor = 0;
964
+ for (const param of params) {
965
+ if (param.kind === "ctx") {
966
+ resolved[param.index] = ctx;
967
+ continue;
968
+ }
969
+ if (param.kind === "arg") {
970
+ const rawValue = ctx._rawArgs[argCursor++];
971
+ if (rawValue === void 0) {
972
+ if (param.required) {
973
+ const paramName = param.name ?? `arg[${param.index}]`;
974
+ return this.reportValidationError(instance, ctx, new MissingArgumentError(paramName));
975
+ }
976
+ resolved[param.index] = void 0;
977
+ continue;
978
+ }
979
+ const value = await this.resolveValue(rawValue, param, ctx, instance, "arg");
980
+ if (value === null) return null;
981
+ resolved[param.index] = value;
982
+ continue;
983
+ }
984
+ if (param.kind === "option") {
985
+ const rawValue = ctx._rawFlags[param.name];
986
+ if (rawValue === void 0) {
987
+ if (param.required) {
988
+ return this.reportValidationError(instance, ctx, new MissingOptionError(param.name, this.flagPrefix));
989
+ }
990
+ resolved[param.index] = void 0;
991
+ continue;
992
+ }
993
+ const value = await this.resolveValue(String(rawValue), param, ctx, instance, "option");
994
+ if (value === null) return null;
995
+ resolved[param.index] = value;
996
+ }
997
+ }
998
+ return resolved;
999
+ }
1000
+ async resolveValue(rawValue, param, ctx, instance, kind) {
1001
+ const paramName = kind === "arg" ? param.name ?? `arg[${param.index}]` : param.name;
1002
+ switch (param.resolvedType) {
1003
+ case "string":
1004
+ return String(rawValue);
1005
+ case "number": {
1006
+ const num = Number(rawValue);
1007
+ if (isNaN(num)) {
1008
+ return this.reportValidationError(instance, ctx, new InvalidTypeError(paramName, kind, "a number", rawValue));
1009
+ }
1010
+ return num;
1011
+ }
1012
+ case "boolean":
1013
+ return rawValue === "false" ? false : Boolean(rawValue);
1014
+ case "user": {
1015
+ const match = rawValue.match(/^(?:<@!?)?([0-7][0-9A-HJKMNP-TV-Z]{25})>?$/i);
1016
+ if (!match) {
1017
+ return this.reportValidationError(instance, ctx, new InvalidMentionError(paramName, kind, "user", rawValue));
1018
+ }
1019
+ const userId = match[1];
1020
+ if (param.fetch) {
1021
+ try {
1022
+ return await this.client.users.fetch(userId);
1023
+ } catch {
1024
+ return this.reportValidationError(instance, ctx, new FetchFailedError(paramName, kind, "user", userId));
1025
+ }
1026
+ }
1027
+ return this.client.users.cache.get(userId) ?? userId;
1028
+ }
1029
+ case "channel": {
1030
+ const match = rawValue.match(/^(?:<#)?([0-7][0-9A-HJKMNP-TV-Z]{25})>?$/i);
1031
+ if (!match) {
1032
+ return this.reportValidationError(instance, ctx, new InvalidMentionError(paramName, kind, "channel", rawValue));
1033
+ }
1034
+ const channelId = match[1];
1035
+ if (param.fetch) {
1036
+ try {
1037
+ return await this.client.channels.fetch(channelId);
1038
+ } catch {
1039
+ return this.reportValidationError(instance, ctx, new FetchFailedError(paramName, kind, "channel", channelId));
1040
+ }
1041
+ }
1042
+ return this.client.channels.cache.get(channelId) ?? channelId;
1043
+ }
1044
+ case "role": {
1045
+ const match = rawValue.match(/^(?:<@&)?([0-7][0-9A-HJKMNP-TV-Z]{25})>?$/i);
1046
+ if (!match) {
1047
+ return this.reportValidationError(instance, ctx, new InvalidMentionError(paramName, kind, "role", rawValue));
1048
+ }
1049
+ const roleId = match[1];
1050
+ if (param.fetch) {
1051
+ const server = ctx.message.server;
1052
+ if (!server) {
1053
+ return this.reportValidationError(instance, ctx, new NoServerContextError(paramName, kind));
1054
+ }
1055
+ try {
1056
+ return await server.roles.fetch(roleId);
1057
+ } catch {
1058
+ return this.reportValidationError(instance, ctx, new FetchFailedError(paramName, kind, "role", roleId));
1059
+ }
1060
+ }
1061
+ return ctx.message.server?.roles.cache.get(roleId) ?? roleId;
1062
+ }
1063
+ default:
1064
+ return rawValue;
1065
+ }
1066
+ }
682
1067
  getRegistry() {
683
1068
  return this.registry;
684
1069
  }
685
- /**
686
- * Get a command by name or alias
687
- */
688
1070
  getCommand(name) {
689
1071
  return this.registry.get(name);
690
1072
  }
691
- /**
692
- * Get all commands
693
- */
694
1073
  getCommands() {
695
1074
  return this.registry.getAll();
696
1075
  }
697
- /**
698
- * Reload all commands
699
- */
700
1076
  async reload() {
701
1077
  this.registry.clear();
702
1078
  if (this.cooldownManager.clear) {
@@ -708,63 +1084,74 @@ var StoatxHandler = class {
708
1084
  }
709
1085
  await this.registry.autoDiscover(this.discoveryOptions);
710
1086
  }
711
- /**
712
- * Check if a user is an owner
713
- */
714
1087
  isOwner(userId) {
715
1088
  return this.owners.has(userId);
716
1089
  }
717
- /**
718
- * Add an owner
719
- */
720
1090
  addOwner(userId) {
721
1091
  this.owners.add(userId);
722
1092
  }
723
- /**
724
- * Remove an owner
725
- */
726
1093
  removeOwner(userId) {
727
1094
  this.owners.delete(userId);
728
1095
  }
729
- /**
730
- * Resolve the prefix for a context
731
- */
732
1096
  async resolvePrefix(serverId) {
733
- if (typeof this.prefixResolver === "function") {
734
- return this.prefixResolver({ serverId });
735
- }
736
- return this.prefixResolver;
1097
+ const result = typeof this.prefixResolver === "function" ? await this.prefixResolver({
1098
+ serverId
1099
+ }) : this.prefixResolver;
1100
+ return Array.isArray(result) ? result : [
1101
+ result
1102
+ ];
737
1103
  }
738
1104
  };
739
1105
 
740
1106
  // src/client.ts
741
1107
  import { Client as StoatClient } from "@stoatx/client";
742
1108
  var Client = class extends StoatClient {
1109
+ static {
1110
+ __name(this, "Client");
1111
+ }
743
1112
  handler;
744
1113
  constructor(options) {
745
- super();
746
- this.handler = new StoatxHandler({ ...options, client: this });
747
- this.on("messageCreate", async (message) => {
748
- await this.handler.handle(message);
1114
+ super(options);
1115
+ this.handler = new StoatxHandler({
1116
+ ...options,
1117
+ client: this
749
1118
  });
750
1119
  }
751
- async initCommands() {
1120
+ async login(token) {
752
1121
  await this.handler.init();
1122
+ return super.login(token);
1123
+ }
1124
+ async executeCommand(message) {
1125
+ await this.handler.handle(message);
753
1126
  }
754
1127
  };
755
1128
 
756
1129
  // src/index.ts
757
1130
  export * from "@stoatx/client";
758
1131
  export {
1132
+ Arg,
759
1133
  Client,
1134
+ CommandGroup,
760
1135
  CommandRegistry,
1136
+ CommandValidationError,
761
1137
  DefaultCooldownManager,
1138
+ FetchFailedError,
762
1139
  Guard,
1140
+ Injectable,
1141
+ InvalidMentionError,
1142
+ InvalidTypeError,
763
1143
  METADATA_KEYS,
1144
+ MissingArgumentError,
1145
+ MissingOptionError,
1146
+ NoServerContextError,
764
1147
  On,
765
1148
  Once,
1149
+ Option,
1150
+ PARAM_TYPE_MAP,
766
1151
  SimpleCommand,
767
1152
  Stoat,
1153
+ StoatxError,
1154
+ SubCommand,
768
1155
  buildSimpleCommandMetadata,
769
1156
  getEventsMetadata,
770
1157
  getGuards,